]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branch 'samsung/for-next'
authorStephen Rothwell <sfr@canb.auug.org.au>
Fri, 17 Aug 2012 04:27:29 +0000 (14:27 +1000)
committerStephen Rothwell <sfr@canb.auug.org.au>
Fri, 17 Aug 2012 04:27:29 +0000 (14:27 +1000)
2865 files changed:
Documentation/ABI/testing/sysfs-driver-wacom
Documentation/DocBook/filesystems.tmpl
Documentation/DocBook/media/dvb/audio.xml
Documentation/DocBook/media/dvb/ca.xml
Documentation/DocBook/media/dvb/demux.xml
Documentation/DocBook/media/dvb/dvbapi.xml
Documentation/DocBook/media/dvb/dvbproperty.xml
Documentation/DocBook/media/dvb/frontend.xml
Documentation/DocBook/media/dvb/net.xml
Documentation/DocBook/media/dvb/video.xml
Documentation/DocBook/media/v4l/compat.xml
Documentation/DocBook/media/v4l/v4l2.xml
Documentation/DocBook/media/v4l/vidioc-g-tuner.xml
Documentation/DocBook/media_api.tmpl
Documentation/DocBook/mtdnand.tmpl
Documentation/RCU/trace.txt
Documentation/arm/Marvell/README [new file with mode: 0644]
Documentation/arm/memory.txt
Documentation/block/00-INDEX
Documentation/block/cfq-iosched.txt
Documentation/block/queue-sysfs.txt
Documentation/cpuidle/sysfs.txt
Documentation/devicetree/bindings/arm/mrvl/tauros2.txt [new file with mode: 0644]
Documentation/devicetree/bindings/arm/pmu.txt
Documentation/devicetree/bindings/mmc/atmel-hsmci.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/pxa-mmc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/sdhci-dove.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/atmel-nand.txt
Documentation/devicetree/bindings/mtd/gpmi-nand.txt
Documentation/devicetree/bindings/mtd/lpc32xx-mlc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/lpc32xx-slc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/cpsw.txt [new file with mode: 0644]
Documentation/devicetree/bindings/net/davinci-mdio.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pinctrl/fsl,imx35-pinctrl.txt [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/tps6586x.txt
Documentation/devicetree/bindings/rtc/pxa-rtc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/cs4270.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/omap-abe-twl6040.txt [new file with mode: 0644]
Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/tty/serial/nxp-lpc32xx-hsuart.txt [new file with mode: 0644]
Documentation/devicetree/bindings/tty/serial/of-serial.txt
Documentation/devicetree/bindings/usb/platform-uhci.txt [new file with mode: 0644]
Documentation/devicetree/bindings/usb/pxa-usb.txt [new file with mode: 0644]
Documentation/devicetree/bindings/usb/vt8500-ehci.txt [new file with mode: 0644]
Documentation/devicetree/bindings/w1/w1-gpio.txt [new file with mode: 0644]
Documentation/filesystems/Locking
Documentation/filesystems/porting
Documentation/filesystems/vfs.txt
Documentation/hwmon/adt7410 [new file with mode: 0644]
Documentation/kernel-parameters.txt
Documentation/laptops/laptop-mode.txt
Documentation/networking/netconsole.txt
Documentation/pinctrl.txt
Documentation/scsi/ChangeLog.megaraid_sas
Documentation/security/Yama.txt
Documentation/serial/00-INDEX
Documentation/serial/computone.txt [deleted file]
Documentation/sound/alsa/HD-Audio-Models.txt
Documentation/sysctl/vm.txt
Documentation/thermal/sysfs-api.txt
Documentation/usb/persist.txt
Documentation/virtual/kvm/api.txt
Documentation/virtual/kvm/hypercalls.txt [new file with mode: 0644]
Documentation/virtual/kvm/ppc-pv.txt
Documentation/w1/slaves/w1_therm
Documentation/watchdog/src/watchdog-test.c
MAINTAINERS
Makefile
arch/Kconfig
arch/alpha/Kconfig
arch/alpha/include/asm/module.h
arch/alpha/kernel/srmcons.c
arch/arm/Kconfig
arch/arm/arm-soc-for-next-contents.txt [new file with mode: 0644]
arch/arm/boot/dts/am33xx.dtsi
arch/arm/boot/dts/imx23.dtsi
arch/arm/boot/dts/imx27-3ds.dts
arch/arm/boot/dts/imx27.dtsi
arch/arm/boot/dts/imx28.dtsi
arch/arm/boot/dts/imx51-babbage.dts
arch/arm/boot/dts/imx51.dtsi
arch/arm/boot/dts/imx53-ard.dts
arch/arm/boot/dts/imx53.dtsi
arch/arm/boot/dts/imx6q-sabrelite.dts
arch/arm/boot/dts/imx6q.dtsi
arch/arm/boot/dts/kirkwood-iconnect.dts
arch/arm/boot/dts/mmp2.dtsi
arch/arm/boot/dts/pxa27x.dtsi [new file with mode: 0644]
arch/arm/boot/dts/pxa2xx.dtsi [new file with mode: 0644]
arch/arm/boot/dts/pxa3xx.dtsi [new file with mode: 0644]
arch/arm/boot/dts/pxa910.dtsi
arch/arm/boot/dts/twl6030.dtsi
arch/arm/configs/afeb9260_defconfig
arch/arm/configs/at91rm9200_defconfig
arch/arm/configs/at91sam9261_defconfig
arch/arm/configs/at91sam9263_defconfig
arch/arm/configs/at91sam9g20_defconfig
arch/arm/configs/at91sam9rl_defconfig
arch/arm/configs/cpu9260_defconfig
arch/arm/configs/cpu9g20_defconfig
arch/arm/configs/imx_v6_v7_defconfig
arch/arm/configs/mxs_defconfig
arch/arm/configs/qil-a9260_defconfig
arch/arm/configs/sam9_l9260_defconfig
arch/arm/configs/stamp9g20_defconfig
arch/arm/configs/tct_hammer_defconfig
arch/arm/configs/usb-a9260_defconfig
arch/arm/include/asm/hardware/cache-tauros2.h
arch/arm/include/asm/hardware/iop3xx.h
arch/arm/include/asm/io.h
arch/arm/include/asm/leds.h [deleted file]
arch/arm/include/asm/mach/map.h
arch/arm/include/asm/mach/pci.h
arch/arm/include/asm/module.h
arch/arm/include/asm/perf_event.h
arch/arm/include/asm/pgtable.h
arch/arm/include/asm/pmu.h
arch/arm/include/asm/sched_clock.h
arch/arm/kernel/Makefile
arch/arm/kernel/bios32.c
arch/arm/kernel/hw_breakpoint.c
arch/arm/kernel/leds.c [deleted file]
arch/arm/kernel/perf_event.c
arch/arm/kernel/perf_event_cpu.c [new file with mode: 0644]
arch/arm/kernel/perf_event_v6.c
arch/arm/kernel/perf_event_v7.c
arch/arm/kernel/perf_event_xscale.c
arch/arm/kernel/pmu.c [deleted file]
arch/arm/kernel/process.c
arch/arm/kernel/sched_clock.c
arch/arm/kernel/time.c
arch/arm/kernel/topology.c
arch/arm/lib/Makefile
arch/arm/lib/io-readsw-armv3.S [new file with mode: 0644]
arch/arm/lib/io-writesw-armv3.S [new file with mode: 0644]
arch/arm/lib/uaccess.S [new file with mode: 0644]
arch/arm/mach-at91/at91rm9200_devices.c
arch/arm/mach-at91/at91sam9260_devices.c
arch/arm/mach-at91/at91sam9261_devices.c
arch/arm/mach-at91/at91sam9263.c
arch/arm/mach-at91/at91sam9263_devices.c
arch/arm/mach-at91/at91sam9rl_devices.c
arch/arm/mach-at91/board-afeb-9260v1.c
arch/arm/mach-at91/board-carmeva.c
arch/arm/mach-at91/board-cpu9krea.c
arch/arm/mach-at91/board-cpuat91.c
arch/arm/mach-at91/board-csb337.c
arch/arm/mach-at91/board-eb9200.c
arch/arm/mach-at91/board-ecbat91.c
arch/arm/mach-at91/board-eco920.c
arch/arm/mach-at91/board-flexibity.c
arch/arm/mach-at91/board-foxg20.c
arch/arm/mach-at91/board-kafa.c
arch/arm/mach-at91/board-kb9202.c
arch/arm/mach-at91/board-neocore926.c
arch/arm/mach-at91/board-picotux200.c
arch/arm/mach-at91/board-qil-a9260.c
arch/arm/mach-at91/board-rm9200dk.c
arch/arm/mach-at91/board-rm9200ek.c
arch/arm/mach-at91/board-rsi-ews.c
arch/arm/mach-at91/board-sam9-l9260.c
arch/arm/mach-at91/board-sam9260ek.c
arch/arm/mach-at91/board-sam9261ek.c
arch/arm/mach-at91/board-sam9263ek.c
arch/arm/mach-at91/board-sam9g20ek.c
arch/arm/mach-at91/board-sam9rlek.c
arch/arm/mach-at91/board-stamp9g20.c
arch/arm/mach-at91/board-usb-a926x.c
arch/arm/mach-at91/board-yl-9200.c
arch/arm/mach-at91/include/mach/board.h
arch/arm/mach-at91/leds.c
arch/arm/mach-bcmring/arch.c
arch/arm/mach-bcmring/core.c
arch/arm/mach-bcmring/csp/chipc/chipcHw.c
arch/arm/mach-bcmring/csp/chipc/chipcHw_init.c
arch/arm/mach-bcmring/csp/chipc/chipcHw_reset.c
arch/arm/mach-bcmring/csp/dmac/dmacHw.c
arch/arm/mach-bcmring/csp/dmac/dmacHw_extra.c
arch/arm/mach-bcmring/csp/tmr/tmrHw.c
arch/arm/mach-bcmring/include/cfg_global.h [deleted file]
arch/arm/mach-bcmring/include/csp/cache.h [deleted file]
arch/arm/mach-bcmring/include/csp/delay.h [deleted file]
arch/arm/mach-bcmring/include/csp/errno.h [deleted file]
arch/arm/mach-bcmring/include/csp/intcHw.h [deleted file]
arch/arm/mach-bcmring/include/csp/module.h [deleted file]
arch/arm/mach-bcmring/include/csp/secHw.h [deleted file]
arch/arm/mach-bcmring/include/csp/stdint.h [deleted file]
arch/arm/mach-bcmring/include/csp/string.h [deleted file]
arch/arm/mach-bcmring/include/mach/cfg_global.h [moved from arch/arm/mach-bcmring/include/cfg_global_defines.h with 74% similarity]
arch/arm/mach-bcmring/include/mach/csp/cap_inline.h
arch/arm/mach-bcmring/include/mach/csp/chipcHw_def.h
arch/arm/mach-bcmring/include/mach/csp/chipcHw_inline.h
arch/arm/mach-bcmring/include/mach/csp/chipcHw_reg.h
arch/arm/mach-bcmring/include/mach/csp/ddrcReg.h
arch/arm/mach-bcmring/include/mach/csp/dmacHw.h [moved from arch/arm/mach-bcmring/include/csp/dmacHw.h with 99% similarity]
arch/arm/mach-bcmring/include/mach/csp/dmacHw_priv.h
arch/arm/mach-bcmring/include/mach/csp/dmacHw_reg.h
arch/arm/mach-bcmring/include/mach/csp/hw_cfg.h
arch/arm/mach-bcmring/include/mach/csp/intcHw_reg.h
arch/arm/mach-bcmring/include/mach/csp/mm_addr.h
arch/arm/mach-bcmring/include/mach/csp/mm_io.h
arch/arm/mach-bcmring/include/mach/csp/reg.h [moved from arch/arm/mach-bcmring/include/csp/reg.h with 81% similarity]
arch/arm/mach-bcmring/include/mach/csp/secHw_inline.h
arch/arm/mach-bcmring/include/mach/csp/tmrHw.h [moved from arch/arm/mach-bcmring/include/csp/tmrHw.h with 99% similarity]
arch/arm/mach-bcmring/include/mach/dma.h
arch/arm/mach-bcmring/include/mach/hardware.h
arch/arm/mach-bcmring/include/mach/reg_nand.h
arch/arm/mach-bcmring/include/mach/reg_umi.h
arch/arm/mach-bcmring/mm.c
arch/arm/mach-bcmring/timer.c
arch/arm/mach-clps711x/Makefile
arch/arm/mach-clps711x/common.c
arch/arm/mach-clps711x/p720t-leds.c [deleted file]
arch/arm/mach-clps711x/p720t.c
arch/arm/mach-davinci/board-neuros-osd2.c
arch/arm/mach-dove/common.c
arch/arm/mach-dove/include/mach/dove.h
arch/arm/mach-dove/include/mach/io.h [deleted file]
arch/arm/mach-dove/pcie.c
arch/arm/mach-ebsa110/Makefile
arch/arm/mach-ebsa110/leds.c
arch/arm/mach-exynos/platsmp.c
arch/arm/mach-exynos/pm_domains.c
arch/arm/mach-footbridge/Makefile
arch/arm/mach-footbridge/common.c
arch/arm/mach-footbridge/dc21285.c
arch/arm/mach-footbridge/ebsa285-leds.c [deleted file]
arch/arm/mach-footbridge/ebsa285.c
arch/arm/mach-footbridge/include/mach/debug-macro.S
arch/arm/mach-footbridge/include/mach/io.h
arch/arm/mach-footbridge/netwinder-hw.c
arch/arm/mach-footbridge/netwinder-leds.c [deleted file]
arch/arm/mach-imx/clk-imx27.c
arch/arm/mach-imx/clk-imx31.c
arch/arm/mach-imx/clk-imx51-imx53.c
arch/arm/mach-imx/devices-imx27.h
arch/arm/mach-imx/mach-imx27_visstrim_m10.c
arch/arm/mach-integrator/Makefile
arch/arm/mach-integrator/core.c
arch/arm/mach-integrator/include/mach/cm.h
arch/arm/mach-integrator/include/mach/io.h [deleted file]
arch/arm/mach-integrator/include/mach/platform.h
arch/arm/mach-integrator/integrator_ap.c
arch/arm/mach-integrator/leds.c
arch/arm/mach-integrator/pci_v3.c
arch/arm/mach-iop13xx/include/mach/io.h [deleted file]
arch/arm/mach-iop13xx/include/mach/iop13xx.h
arch/arm/mach-iop13xx/io.c
arch/arm/mach-iop13xx/pci.c
arch/arm/mach-iop13xx/setup.c
arch/arm/mach-iop32x/include/mach/io.h [deleted file]
arch/arm/mach-iop33x/include/mach/io.h [deleted file]
arch/arm/mach-kirkwood/Makefile.boot
arch/arm/mach-kirkwood/common.c
arch/arm/mach-kirkwood/include/mach/io.h [deleted file]
arch/arm/mach-kirkwood/include/mach/kirkwood.h
arch/arm/mach-kirkwood/pcie.c
arch/arm/mach-ks8695/Makefile
arch/arm/mach-ks8695/devices.c
arch/arm/mach-ks8695/include/mach/devices.h
arch/arm/mach-ks8695/leds.c [deleted file]
arch/arm/mach-mmp/mmp2.c
arch/arm/mach-mmp/pxa910.c
arch/arm/mach-mmp/ttc_dkb.c
arch/arm/mach-mv78xx0/addr-map.c
arch/arm/mach-mv78xx0/common.c
arch/arm/mach-mv78xx0/include/mach/io.h [deleted file]
arch/arm/mach-mv78xx0/include/mach/mv78xx0.h
arch/arm/mach-mv78xx0/pcie.c
arch/arm/mach-mxs/Kconfig
arch/arm/mach-mxs/Makefile
arch/arm/mach-nomadik/board-nhk8815.c
arch/arm/mach-nomadik/cpu-8815.c
arch/arm/mach-omap1/Makefile
arch/arm/mach-omap1/board-h2.c
arch/arm/mach-omap1/board-h3.c
arch/arm/mach-omap1/board-osk.c
arch/arm/mach-omap1/leds-h2p2-debug.c [deleted file]
arch/arm/mach-omap1/leds-innovator.c [deleted file]
arch/arm/mach-omap1/leds-osk.c [deleted file]
arch/arm/mach-omap1/leds.c [deleted file]
arch/arm/mach-omap1/leds.h [deleted file]
arch/arm/mach-omap1/time.c
arch/arm/mach-omap1/timer32k.c
arch/arm/mach-omap2/Kconfig
arch/arm/mach-omap2/board-igep0020.c
arch/arm/mach-omap2/board-omap3evm.c
arch/arm/mach-omap2/common-board-devices.c
arch/arm/mach-omap2/common-board-devices.h
arch/arm/mach-omap2/devices.c
arch/arm/mach-omap2/mux.h
arch/arm/mach-omap2/opp4xxx_data.c
arch/arm/mach-omap2/pm34xx.c
arch/arm/mach-omap2/serial.c
arch/arm/mach-omap2/sleep44xx.S
arch/arm/mach-omap2/twl-common.c
arch/arm/mach-orion5x/common.c
arch/arm/mach-orion5x/include/mach/io.h [deleted file]
arch/arm/mach-orion5x/include/mach/orion5x.h
arch/arm/mach-orion5x/pci.c
arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
arch/arm/mach-orion5x/rd88f5182-setup.c
arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c
arch/arm/mach-pnx4008/time.c
arch/arm/mach-pxa/Kconfig
arch/arm/mach-pxa/Makefile
arch/arm/mach-pxa/clock-pxa3xx.c
arch/arm/mach-pxa/devices.c
arch/arm/mach-pxa/idp.c
arch/arm/mach-pxa/irq.c
arch/arm/mach-pxa/leds-idp.c [deleted file]
arch/arm/mach-pxa/leds-lubbock.c [deleted file]
arch/arm/mach-pxa/leds-mainstone.c [deleted file]
arch/arm/mach-pxa/leds.c [deleted file]
arch/arm/mach-pxa/leds.h [deleted file]
arch/arm/mach-pxa/lubbock.c
arch/arm/mach-pxa/mainstone.c
arch/arm/mach-pxa/pxa-dt.c [new file with mode: 0644]
arch/arm/mach-pxa/pxa3xx.c
arch/arm/mach-pxa/raumfeld.c
arch/arm/mach-realview/core.c
arch/arm/mach-realview/core.h
arch/arm/mach-realview/realview_eb.c
arch/arm/mach-realview/realview_pb1176.c
arch/arm/mach-realview/realview_pb11mp.c
arch/arm/mach-realview/realview_pba8.c
arch/arm/mach-realview/realview_pbx.c
arch/arm/mach-s3c24xx/Kconfig
arch/arm/mach-sa1100/Makefile
arch/arm/mach-sa1100/assabet.c
arch/arm/mach-sa1100/badge4.c
arch/arm/mach-sa1100/cerf.c
arch/arm/mach-sa1100/hackkit.c
arch/arm/mach-sa1100/lart.c
arch/arm/mach-sa1100/leds-assabet.c [deleted file]
arch/arm/mach-sa1100/leds-badge4.c [deleted file]
arch/arm/mach-sa1100/leds-cerf.c [deleted file]
arch/arm/mach-sa1100/leds-hackkit.c [deleted file]
arch/arm/mach-sa1100/leds-lart.c [deleted file]
arch/arm/mach-sa1100/leds.c [deleted file]
arch/arm/mach-sa1100/leds.h [deleted file]
arch/arm/mach-shark/Makefile
arch/arm/mach-shark/core.c
arch/arm/mach-shark/include/mach/debug-macro.S
arch/arm/mach-shark/include/mach/entry-macro.S
arch/arm/mach-shark/include/mach/io.h [deleted file]
arch/arm/mach-shark/leds.c
arch/arm/mach-shark/pci.c
arch/arm/mach-shmobile/Makefile
arch/arm/mach-shmobile/board-ap4evb.c
arch/arm/mach-shmobile/board-armadillo800eva.c
arch/arm/mach-shmobile/board-mackerel.c
arch/arm/mach-shmobile/common.c [deleted file]
arch/arm/mach-shmobile/cpuidle.c
arch/arm/mach-shmobile/include/mach/common.h
arch/arm/mach-shmobile/include/mach/pm-rmobile.h
arch/arm/mach-shmobile/include/mach/r8a7740.h
arch/arm/mach-shmobile/include/mach/r8a7779.h
arch/arm/mach-shmobile/include/mach/sh7372.h
arch/arm/mach-shmobile/pm-r8a7740.c
arch/arm/mach-shmobile/pm-r8a7779.c
arch/arm/mach-shmobile/pm-rmobile.c
arch/arm/mach-shmobile/pm-sh7372.c
arch/arm/mach-shmobile/setup-r8a7740.c
arch/arm/mach-shmobile/setup-r8a7779.c
arch/arm/mach-shmobile/setup-sh7372.c
arch/arm/mach-tegra/board-harmony-power.c
arch/arm/mach-tegra/devices.c
arch/arm/mach-tegra/include/mach/io.h [deleted file]
arch/arm/mach-tegra/include/mach/iomap.h
arch/arm/mach-tegra/pcie.c
arch/arm/mach-u300/Kconfig
arch/arm/mach-u300/Makefile
arch/arm/mach-u300/core.c
arch/arm/mach-u300/dma_channels.h [moved from arch/arm/mach-u300/include/mach/dma_channels.h with 88% similarity]
arch/arm/mach-u300/i2c.c
arch/arm/mach-u300/include/mach/clkdev.h [deleted file]
arch/arm/mach-u300/include/mach/irqs.h
arch/arm/mach-u300/include/mach/platform.h [deleted file]
arch/arm/mach-u300/include/mach/syscon.h
arch/arm/mach-u300/include/mach/u300-regs.h
arch/arm/mach-u300/spi.c
arch/arm/mach-u300/timer.c
arch/arm/mach-u300/timer.h [new file with mode: 0644]
arch/arm/mach-u300/u300-gpio.h
arch/arm/mach-u300/u300.c [deleted file]
arch/arm/mach-ux500/cache-l2x0.c
arch/arm/mach-ux500/cpu-db8500.c
arch/arm/mach-ux500/cpu.c
arch/arm/mach-ux500/include/mach/id.h
arch/arm/mach-ux500/platsmp.c
arch/arm/mach-versatile/core.c
arch/arm/mach-versatile/include/mach/hardware.h
arch/arm/mach-versatile/include/mach/io.h [deleted file]
arch/arm/mach-versatile/pci.c
arch/arm/mach-vexpress/ct-ca9x4.c
arch/arm/mach-vt8500/bv07.c
arch/arm/mach-vt8500/devices-vt8500.c
arch/arm/mach-vt8500/devices-wm8505.c
arch/arm/mach-vt8500/devices.c
arch/arm/mach-vt8500/devices.h
arch/arm/mach-vt8500/wm8505_7in.c
arch/arm/mm/cache-l2x0.c
arch/arm/mm/cache-tauros2.c
arch/arm/mm/dma-mapping.c
arch/arm/mm/flush.c
arch/arm/mm/init.c
arch/arm/mm/ioremap.c
arch/arm/mm/mmu.c
arch/arm/mm/tlb-v7.S
arch/arm/plat-iop/pci.c
arch/arm/plat-iop/pmu.c
arch/arm/plat-iop/setup.c
arch/arm/plat-mxc/devices/Kconfig
arch/arm/plat-mxc/devices/Makefile
arch/arm/plat-mxc/devices/platform-imx27-coda.c [new file with mode: 0644]
arch/arm/plat-mxc/devices/platform-mxc_nand.c
arch/arm/plat-mxc/include/mach/devices-common.h
arch/arm/plat-omap/Kconfig
arch/arm/plat-omap/debug-leds.c
arch/arm/plat-omap/dmtimer.c
arch/arm/plat-omap/include/plat/cpu.h
arch/arm/plat-omap/include/plat/multi.h
arch/arm/plat-omap/include/plat/omap-serial.h
arch/arm/plat-omap/include/plat/uncompress.h
arch/arm/plat-orion/common.c
arch/arm/plat-orion/include/plat/common.h
arch/arm/plat-samsung/Kconfig
arch/arm/plat-samsung/devs.c
arch/arm/plat-samsung/time.c
arch/arm/plat-versatile/Kconfig
arch/arm/plat-versatile/leds.c
arch/arm/vfp/vfpmodule.c
arch/avr32/Kconfig
arch/avr32/include/asm/module.h
arch/blackfin/Kconfig
arch/blackfin/include/asm/module.h
arch/blackfin/kernel/setup.c
arch/c6x/Kconfig
arch/c6x/include/asm/cache.h
arch/c6x/include/asm/module.h
arch/cris/Kconfig
arch/cris/arch-v32/drivers/axisflashmap.c
arch/cris/arch-v32/drivers/pci/bios.c
arch/cris/arch-v32/kernel/head.S
arch/cris/arch-v32/kernel/kgdb.c
arch/cris/arch-v32/mach-a3/Makefile
arch/cris/arch-v32/mach-a3/vcs_hook.c [deleted file]
arch/cris/arch-v32/mach-a3/vcs_hook.h [deleted file]
arch/cris/arch-v32/mach-fs/Makefile
arch/cris/arch-v32/mach-fs/vcs_hook.c [deleted file]
arch/cris/arch-v32/mach-fs/vcs_hook.h [deleted file]
arch/cris/arch-v32/mm/init.c
arch/cris/include/arch-v32/arch/page.h
arch/cris/include/arch-v32/arch/processor.h
arch/cris/include/arch-v32/mach-fs/mach/startup.inc
arch/cris/include/asm/Kbuild
arch/cris/include/asm/module.h [deleted file]
arch/cris/include/asm/pci.h
arch/frv/include/asm/module.h
arch/h8300/Kconfig
arch/h8300/include/asm/Kbuild
arch/h8300/include/asm/module.h [deleted file]
arch/hexagon/Kconfig
arch/ia64/Kconfig
arch/ia64/hp/sim/simserial.c
arch/ia64/include/asm/module.h
arch/ia64/kernel/acpi.c
arch/ia64/kvm/kvm-ia64.c
arch/m32r/Kconfig
arch/m32r/include/asm/Kbuild
arch/m32r/include/asm/module.h [deleted file]
arch/m32r/kernel/module.c
arch/m68k/Kconfig
arch/m68k/Kconfig.cpu
arch/m68k/apollo/config.c
arch/m68k/emu/nfcon.c
arch/m68k/include/asm/Kbuild
arch/m68k/include/asm/MC68332.h [deleted file]
arch/m68k/include/asm/apollodma.h [deleted file]
arch/m68k/include/asm/apollohw.h
arch/m68k/include/asm/bitsperlong.h [deleted file]
arch/m68k/include/asm/cputime.h [deleted file]
arch/m68k/include/asm/delay.h
arch/m68k/include/asm/device.h [deleted file]
arch/m68k/include/asm/emergency-restart.h [deleted file]
arch/m68k/include/asm/errno.h [deleted file]
arch/m68k/include/asm/futex.h [deleted file]
arch/m68k/include/asm/ioctl.h [deleted file]
arch/m68k/include/asm/ipcbuf.h [deleted file]
arch/m68k/include/asm/irq_regs.h [deleted file]
arch/m68k/include/asm/kdebug.h [deleted file]
arch/m68k/include/asm/kmap_types.h [deleted file]
arch/m68k/include/asm/kvm_para.h [deleted file]
arch/m68k/include/asm/local.h [deleted file]
arch/m68k/include/asm/local64.h [deleted file]
arch/m68k/include/asm/mac_mouse.h [deleted file]
arch/m68k/include/asm/mcfmbus.h [deleted file]
arch/m68k/include/asm/mman.h [deleted file]
arch/m68k/include/asm/module.h
arch/m68k/include/asm/mutex.h [deleted file]
arch/m68k/include/asm/percpu.h [deleted file]
arch/m68k/include/asm/resource.h [deleted file]
arch/m68k/include/asm/sbus.h [deleted file]
arch/m68k/include/asm/scatterlist.h [deleted file]
arch/m68k/include/asm/sections.h [deleted file]
arch/m68k/include/asm/shm.h [deleted file]
arch/m68k/include/asm/siginfo.h [deleted file]
arch/m68k/include/asm/statfs.h [deleted file]
arch/m68k/include/asm/topology.h [deleted file]
arch/m68k/include/asm/types.h [deleted file]
arch/m68k/include/asm/unaligned.h
arch/m68k/include/asm/xor.h [deleted file]
arch/m68k/kernel/setup_no.c
arch/m68k/kernel/sys_m68k.c
arch/m68k/kernel/vmlinux-nommu.lds
arch/m68k/kernel/vmlinux-std.lds
arch/m68k/kernel/vmlinux-sun3.lds
arch/m68k/lib/muldi3.c
arch/m68k/mm/init_mm.c
arch/m68k/mm/init_no.c
arch/m68k/platform/68328/head-de2.S
arch/m68k/platform/68328/head-pilot.S
arch/m68k/platform/68328/head-ram.S
arch/m68k/platform/68328/head-rom.S
arch/m68k/platform/68360/head-ram.S
arch/m68k/platform/68360/head-rom.S
arch/m68k/platform/coldfire/head.S
arch/m68k/sun3/prom/init.c
arch/microblaze/Kconfig
arch/microblaze/include/asm/sections.h
arch/microblaze/kernel/microblaze_ksyms.c
arch/microblaze/kernel/setup.c
arch/microblaze/kernel/vmlinux.lds.S
arch/mips/Kconfig
arch/mips/alchemy/board-mtx1.c
arch/mips/ath79/dev-usb.c
arch/mips/ath79/gpio.c
arch/mips/bcm63xx/dev-spi.c
arch/mips/cavium-octeon/octeon-irq.c
arch/mips/cavium-octeon/serial.c
arch/mips/include/asm/atomic.h
arch/mips/include/asm/cpu-features.h
arch/mips/include/asm/cpu.h
arch/mips/include/asm/elf.h
arch/mips/include/asm/mach-ath79/ar71xx_regs.h
arch/mips/include/asm/mach-ath79/cpu-feature-overrides.h
arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_spi.h
arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
arch/mips/include/asm/mach-cavium-octeon/irq.h
arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
arch/mips/include/asm/mipsregs.h
arch/mips/include/asm/module.h
arch/mips/include/asm/ptrace.h
arch/mips/include/asm/r4k-timer.h
arch/mips/include/asm/siginfo.h
arch/mips/include/asm/syscall.h [new file with mode: 0644]
arch/mips/include/asm/thread_info.h
arch/mips/include/asm/unistd.h
arch/mips/kernel/Makefile
arch/mips/kernel/cpu-probe.c
arch/mips/kernel/ftrace.c
arch/mips/kernel/kgdb.c
arch/mips/kernel/module.c
arch/mips/kernel/perf_event_mipsxx.c
arch/mips/kernel/ptrace.c
arch/mips/kernel/scall32-o32.S
arch/mips/kernel/scall64-64.S
arch/mips/kernel/scall64-n32.S
arch/mips/kernel/scall64-o32.S
arch/mips/kernel/smp.c
arch/mips/kernel/sync-r4k.c
arch/mips/kernel/vmlinux.lds.S
arch/mips/lantiq/xway/sysctrl.c
arch/mips/mm/init.c
arch/mips/pci/pci-lantiq.c
arch/mn10300/Kconfig
arch/mn10300/include/asm/module.h
arch/openrisc/Kconfig
arch/parisc/Kconfig
arch/parisc/include/asm/atomic.h
arch/parisc/include/asm/module.h
arch/parisc/kernel/pdc_cons.c
arch/parisc/kernel/process.c
arch/parisc/kernel/sys_parisc.c
arch/powerpc/Kconfig
arch/powerpc/boot/dts/fsl/e500mc_power_isa.dtsi [new file with mode: 0644]
arch/powerpc/boot/dts/fsl/e500v2_power_isa.dtsi [new file with mode: 0644]
arch/powerpc/boot/dts/fsl/e5500_power_isa.dtsi [new file with mode: 0644]
arch/powerpc/boot/dts/fsl/mpc8536si-pre.dtsi
arch/powerpc/boot/dts/fsl/mpc8544si-pre.dtsi
arch/powerpc/boot/dts/fsl/mpc8548si-pre.dtsi
arch/powerpc/boot/dts/fsl/mpc8568si-pre.dtsi
arch/powerpc/boot/dts/fsl/mpc8569si-pre.dtsi
arch/powerpc/boot/dts/fsl/mpc8572si-pre.dtsi
arch/powerpc/boot/dts/fsl/p1010si-pre.dtsi
arch/powerpc/boot/dts/fsl/p1020si-pre.dtsi
arch/powerpc/boot/dts/fsl/p1021si-pre.dtsi
arch/powerpc/boot/dts/fsl/p1022si-pre.dtsi
arch/powerpc/boot/dts/fsl/p1023si-pre.dtsi
arch/powerpc/boot/dts/fsl/p2020si-pre.dtsi
arch/powerpc/boot/dts/fsl/p2041si-pre.dtsi
arch/powerpc/boot/dts/fsl/p3041si-pre.dtsi
arch/powerpc/boot/dts/fsl/p4080si-post.dtsi
arch/powerpc/boot/dts/fsl/p4080si-pre.dtsi
arch/powerpc/boot/dts/fsl/p5020si-pre.dtsi
arch/powerpc/boot/dts/fsl/p5040si-post.dtsi [new file with mode: 0644]
arch/powerpc/boot/dts/fsl/p5040si-pre.dtsi [new file with mode: 0644]
arch/powerpc/boot/dts/fsl/qoriq-sec5.2-0.dtsi [new file with mode: 0644]
arch/powerpc/boot/dts/mpc8540ads.dts
arch/powerpc/boot/dts/mpc8541cds.dts
arch/powerpc/boot/dts/mpc8555cds.dts
arch/powerpc/boot/dts/mpc8560ads.dts
arch/powerpc/boot/dts/p1020rdb_camp_core0.dts [deleted file]
arch/powerpc/boot/dts/p1020rdb_camp_core1.dts [deleted file]
arch/powerpc/boot/dts/p1022rdk.dts [new file with mode: 0644]
arch/powerpc/boot/dts/p2020rdb_camp_core0.dts [deleted file]
arch/powerpc/boot/dts/p2020rdb_camp_core1.dts [deleted file]
arch/powerpc/boot/dts/p5040ds.dts [new file with mode: 0644]
arch/powerpc/configs/corenet32_smp_defconfig
arch/powerpc/configs/corenet64_smp_defconfig
arch/powerpc/configs/mpc85xx_defconfig
arch/powerpc/configs/mpc85xx_smp_defconfig
arch/powerpc/configs/ppc64_defconfig
arch/powerpc/configs/pseries_defconfig
arch/powerpc/include/asm/Kbuild
arch/powerpc/include/asm/cacheflush.h
arch/powerpc/include/asm/epapr_hcalls.h
arch/powerpc/include/asm/fsl_guts.h
arch/powerpc/include/asm/fsl_hcalls.h
arch/powerpc/include/asm/kvm.h
arch/powerpc/include/asm/kvm_host.h
arch/powerpc/include/asm/kvm_para.h
arch/powerpc/include/asm/kvm_ppc.h
arch/powerpc/include/asm/module.h
arch/powerpc/include/asm/mpic.h
arch/powerpc/include/asm/reg_booke.h
arch/powerpc/include/asm/smp.h
arch/powerpc/include/asm/swiotlb.h
arch/powerpc/kernel/cpu_setup_fsl_booke.S
arch/powerpc/kernel/cputable.c
arch/powerpc/kernel/dma-swiotlb.c
arch/powerpc/kernel/epapr_hcalls.S
arch/powerpc/kernel/epapr_paravirt.c
arch/powerpc/kernel/exceptions-64e.S
arch/powerpc/kernel/head_fsl_booke.S
arch/powerpc/kernel/kvm.c
arch/powerpc/kernel/ppc_ksyms.c
arch/powerpc/kernel/prom_init.c
arch/powerpc/kernel/smp.c
arch/powerpc/kvm/44x.c
arch/powerpc/kvm/44x_emulate.c
arch/powerpc/kvm/44x_tlb.c
arch/powerpc/kvm/Kconfig
arch/powerpc/kvm/book3s.c
arch/powerpc/kvm/book3s_32_mmu_host.c
arch/powerpc/kvm/book3s_64_mmu_host.c
arch/powerpc/kvm/book3s_64_mmu_hv.c
arch/powerpc/kvm/book3s_hv_builtin.c
arch/powerpc/kvm/book3s_hv_rm_mmu.c
arch/powerpc/kvm/book3s_hv_rmhandlers.S
arch/powerpc/kvm/book3s_mmu_hpte.c
arch/powerpc/kvm/book3s_pr.c
arch/powerpc/kvm/book3s_rmhandlers.S
arch/powerpc/kvm/booke.c
arch/powerpc/kvm/booke_emulate.c
arch/powerpc/kvm/e500.h
arch/powerpc/kvm/e500_tlb.c
arch/powerpc/kvm/powerpc.c
arch/powerpc/kvm/trace.h
arch/powerpc/mm/mem.c
arch/powerpc/platforms/44x/currituck.c
arch/powerpc/platforms/512x/Kconfig
arch/powerpc/platforms/512x/clock.c
arch/powerpc/platforms/512x/mpc512x_shared.c
arch/powerpc/platforms/83xx/suspend.c
arch/powerpc/platforms/85xx/Kconfig
arch/powerpc/platforms/85xx/Makefile
arch/powerpc/platforms/85xx/corenet_ds.c
arch/powerpc/platforms/85xx/mpc85xx_ds.c
arch/powerpc/platforms/85xx/p1022_rdk.c [new file with mode: 0644]
arch/powerpc/platforms/85xx/p5040_ds.c [new file with mode: 0644]
arch/powerpc/platforms/85xx/qemu_e500.c
arch/powerpc/platforms/85xx/smp.c
arch/powerpc/platforms/Kconfig
arch/powerpc/platforms/cell/celleb_pci.c
arch/powerpc/sysdev/Makefile
arch/powerpc/sysdev/fsl_85xx_l2ctlr.c
arch/powerpc/sysdev/fsl_mpic_err.c [new file with mode: 0644]
arch/powerpc/sysdev/fsl_msi.c
arch/powerpc/sysdev/fsl_pci.c
arch/powerpc/sysdev/fsl_soc.c
arch/powerpc/sysdev/mpic.c
arch/powerpc/sysdev/mpic.h
arch/s390/Kbuild
arch/s390/Kconfig
arch/s390/crypto/aes_s390.c
arch/s390/crypto/des_s390.c
arch/s390/crypto/ghash_s390.c
arch/s390/include/asm/module.h
arch/s390/include/asm/processor.h
arch/s390/include/asm/sparsemem.h
arch/s390/include/asm/syscall.h
arch/s390/kernel/compat_linux.c
arch/s390/kernel/compat_wrapper.S
arch/s390/kernel/dis.c
arch/s390/kernel/ptrace.c
arch/s390/kernel/sys_s390.c
arch/s390/kvm/Kconfig
arch/s390/kvm/diag.c
arch/s390/kvm/intercept.c
arch/s390/kvm/interrupt.c
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/priv.c
arch/s390/kvm/sigp.c
arch/s390/kvm/trace-s390.h [new file with mode: 0644]
arch/s390/kvm/trace.h [new file with mode: 0644]
arch/s390/net/Makefile [new file with mode: 0644]
arch/s390/net/bpf_jit.S [new file with mode: 0644]
arch/s390/net/bpf_jit_comp.c [new file with mode: 0644]
arch/score/Kconfig
arch/score/include/asm/module.h
arch/score/kernel/module.c
arch/sh/Kconfig
arch/sh/drivers/dma/dma-sh.c
arch/sh/include/asm/module.h
arch/sh/include/asm/sections.h
arch/sh/include/cpu-sh2a/cpu/sh7269.h
arch/sh/kernel/cpu/sh2a/pinmux-sh7269.c
arch/sh/kernel/setup.c
arch/sh/kernel/sh_ksyms_32.c
arch/sh/kernel/vmlinux.lds.S
arch/sh/lib/mcount.S
arch/sparc/Kconfig
arch/sparc/include/asm/Kbuild
arch/sparc/include/asm/module.h [deleted file]
arch/sparc/kernel/sys_sparc_64.c
arch/sparc/mm/init_64.c
arch/tile/Kconfig
arch/um/drivers/line.c
arch/um/drivers/mconsole_kern.c
arch/unicore32/Kconfig
arch/unicore32/include/asm/bug.h
arch/unicore32/include/asm/cmpxchg.h
arch/unicore32/kernel/setup.h
arch/unicore32/mm/fault.c
arch/x86/Kconfig
arch/x86/crypto/Makefile
arch/x86/crypto/aes_glue.c
arch/x86/crypto/aesni-intel_glue.c
arch/x86/crypto/blowfish_glue.c
arch/x86/crypto/camellia_glue.c
arch/x86/crypto/cast5-avx-x86_64-asm_64.S [new file with mode: 0644]
arch/x86/crypto/cast5_avx_glue.c [new file with mode: 0644]
arch/x86/crypto/cast6-avx-x86_64-asm_64.S [new file with mode: 0644]
arch/x86/crypto/cast6_avx_glue.c [new file with mode: 0644]
arch/x86/crypto/ghash-clmulni-intel_glue.c
arch/x86/crypto/salsa20_glue.c
arch/x86/crypto/serpent_avx_glue.c
arch/x86/crypto/serpent_sse2_glue.c
arch/x86/crypto/twofish_avx_glue.c
arch/x86/crypto/twofish_glue.c
arch/x86/crypto/twofish_glue_3way.c
arch/x86/include/asm/kvm_host.h
arch/x86/include/asm/kvm_para.h
arch/x86/include/asm/mce.h
arch/x86/include/asm/perf_event.h
arch/x86/include/asm/rcu.h [new file with mode: 0644]
arch/x86/include/asm/thread_info.h
arch/x86/kernel/acpi/sleep.c
arch/x86/kernel/acpi/sleep.h
arch/x86/kernel/acpi/wakeup_32.S
arch/x86/kernel/acpi/wakeup_64.S
arch/x86/kernel/alternative.c
arch/x86/kernel/apic/io_apic.c
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/intel.c
arch/x86/kernel/cpu/mcheck/mce-severity.c
arch/x86/kernel/cpu/mcheck/mce.c
arch/x86/kernel/cpu/perf_event.c
arch/x86/kernel/cpu/perf_event.h
arch/x86/kernel/cpu/perf_event_amd_ibs.c
arch/x86/kernel/cpu/perf_event_intel_ds.c
arch/x86/kernel/cpu/perf_event_intel_uncore.h
arch/x86/kernel/entry_64.S
arch/x86/kernel/irq.c
arch/x86/kernel/kdebugfs.c
arch/x86/kernel/kgdb.c
arch/x86/kernel/ptrace.c
arch/x86/kernel/signal.c
arch/x86/kernel/traps.c
arch/x86/kvm/Kconfig
arch/x86/kvm/Makefile
arch/x86/kvm/cpuid.c
arch/x86/kvm/emulate.c
arch/x86/kvm/i8254.c
arch/x86/kvm/i8254.h
arch/x86/kvm/i8259.c
arch/x86/kvm/irq.h
arch/x86/kvm/kvm_timer.h [deleted file]
arch/x86/kvm/lapic.c
arch/x86/kvm/lapic.h
arch/x86/kvm/mmu.c
arch/x86/kvm/mmu_audit.c
arch/x86/kvm/paging_tmpl.h
arch/x86/kvm/pmu.c
arch/x86/kvm/svm.c
arch/x86/kvm/timer.c [deleted file]
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/kvm/x86.h
arch/x86/mm/fault.c
arch/x86/mm/srat.c
arch/x86/syscalls/syscall_64.tbl
arch/x86/xen/enlighten.c
arch/x86/xen/p2m.c
arch/xtensa/Kconfig
arch/xtensa/include/asm/io.h
arch/xtensa/include/asm/module.h
arch/xtensa/kernel/Makefile
arch/xtensa/kernel/irq.c
arch/xtensa/kernel/pci.c
arch/xtensa/kernel/platform.c
arch/xtensa/platforms/iss/Makefile
arch/xtensa/platforms/iss/console.c
arch/xtensa/platforms/iss/setup.c
block/blk-lib.c
block/blk-merge.c
block/genhd.c
crypto/842.c [new file with mode: 0644]
crypto/Kconfig
crypto/Makefile
crypto/aes_generic.c
crypto/ansi_cprng.c
crypto/anubis.c
crypto/blowfish_generic.c
crypto/camellia_generic.c
crypto/cast5_generic.c [moved from crypto/cast5.c with 95% similarity]
crypto/cast6_generic.c [moved from crypto/cast6.c with 94% similarity]
crypto/crypto_null.c
crypto/deflate.c
crypto/des_generic.c
crypto/fcrypt.c
crypto/ghash-generic.c
crypto/khazad.c
crypto/krng.c
crypto/lzo.c
crypto/salsa20_generic.c
crypto/seed.c
crypto/serpent_generic.c
crypto/sha256_generic.c
crypto/sha512_generic.c
crypto/shash.c
crypto/tcrypt.c
crypto/tcrypt.h
crypto/tea.c
crypto/testmgr.c
crypto/testmgr.h
crypto/tgr192.c
crypto/twofish_generic.c
crypto/wp512.c
drivers/acpi/ac.c
drivers/acpi/acpica/achware.h
drivers/acpi/acpica/hwesleep.c
drivers/acpi/acpica/hwsleep.c
drivers/acpi/acpica/hwxfsleep.c
drivers/acpi/battery.c
drivers/acpi/button.c
drivers/acpi/fan.c
drivers/acpi/numa.c
drivers/acpi/pci_root.c
drivers/acpi/power.c
drivers/acpi/processor_driver.c
drivers/acpi/sbs.c
drivers/acpi/sleep.c
drivers/acpi/sysfs.c
drivers/acpi/thermal.c
drivers/ata/libata-core.c
drivers/ata/libata-eh.c
drivers/atm/iphase.c
drivers/base/core.c
drivers/base/platform.c
drivers/base/power/clock_ops.c
drivers/base/power/common.c
drivers/base/power/domain.c
drivers/base/power/main.c
drivers/base/power/power.h
drivers/base/power/runtime.c
drivers/base/power/wakeup.c
drivers/base/regmap/regmap-irq.c
drivers/base/regmap/regmap.c
drivers/bcma/driver_chipcommon_pmu.c
drivers/bcma/host_pci.c
drivers/bcma/host_soc.c
drivers/bcma/sprom.c
drivers/block/drbd/drbd_main.c
drivers/bluetooth/ath3k.c
drivers/bluetooth/bcm203x.c
drivers/bluetooth/bfusb.c
drivers/bluetooth/bluecard_cs.c
drivers/bluetooth/bpa10x.c
drivers/bluetooth/bt3c_cs.c
drivers/bluetooth/btmrvl_sdio.c
drivers/bluetooth/btsdio.c
drivers/bluetooth/btuart_cs.c
drivers/bluetooth/btusb.c
drivers/bluetooth/btwilink.c
drivers/bluetooth/dtl1_cs.c
drivers/bluetooth/hci_ath.c
drivers/char/agp/intel-agp.h
drivers/char/agp/intel-gtt.c
drivers/char/hw_random/omap-rng.c
drivers/char/mwave/mwavedd.c
drivers/char/nwflash.c
drivers/char/pcmcia/synclink_cs.c
drivers/char/tlclk.c
drivers/char/tpm/tpm_tis.c
drivers/char/ttyprintk.c
drivers/clocksource/sh_cmt.c
drivers/clocksource/sh_mtu2.c
drivers/clocksource/sh_tmu.c
drivers/cpufreq/cpufreq_conservative.c
drivers/cpufreq/omap-cpufreq.c
drivers/cpufreq/pcc-cpufreq.c
drivers/cpuidle/coupled.c
drivers/cpuidle/governors/ladder.c
drivers/crypto/Kconfig
drivers/crypto/atmel-aes.c
drivers/crypto/atmel-tdes.c
drivers/crypto/caam/caamalg.c
drivers/crypto/caam/caamhash.c
drivers/crypto/caam/caamrng.c
drivers/crypto/caam/jr.c
drivers/crypto/geode-aes.c
drivers/crypto/hifn_795x.c
drivers/crypto/nx/Kconfig [new file with mode: 0644]
drivers/crypto/nx/Makefile
drivers/crypto/nx/nx-842.c [new file with mode: 0644]
drivers/crypto/nx/nx-aes-cbc.c
drivers/crypto/nx/nx-aes-ccm.c
drivers/crypto/nx/nx-aes-ctr.c
drivers/crypto/nx/nx-aes-ecb.c
drivers/crypto/nx/nx-aes-gcm.c
drivers/crypto/omap-aes.c
drivers/crypto/padlock-aes.c
drivers/crypto/s5p-sss.c
drivers/crypto/tegra-aes.c
drivers/dma/dw_dmac.c
drivers/dma/dw_dmac_regs.h
drivers/dma/imx-dma.c
drivers/dma/tegra20-apb-dma.c
drivers/edac/edac_mc.c
drivers/extcon/extcon_gpio.c
drivers/gpio/gpio-em.c
drivers/gpio/gpio-langwell.c
drivers/gpio/gpio-ml-ioh.c
drivers/gpio/gpio-mpc8xxx.c
drivers/gpio/gpio-msic.c
drivers/gpio/gpio-mxc.c
drivers/gpio/gpio-omap.c
drivers/gpio/gpio-pch.c
drivers/gpio/gpio-pxa.c
drivers/gpio/gpio-samsung.c
drivers/gpio/gpio-sch.c
drivers/gpio/gpiolib-of.c
drivers/gpio/gpiolib.c
drivers/gpu/drm/drm_edid_load.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_gem_context.c
drivers/gpu/drm/i915/i915_gem_execbuffer.c
drivers/gpu/drm/i915/i915_gem_gtt.c
drivers/gpu/drm/i915/i915_sysfs.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_i2c.c
drivers/gpu/drm/i915/intel_panel.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/mgag200/mgag200_mode.c
drivers/gpu/drm/nouveau/nouveau_i2c.c
drivers/gpu/drm/nouveau/nouveau_state.c
drivers/gpu/drm/nouveau/nv84_fifo.c
drivers/gpu/drm/nouveau/nvc0_pm.c
drivers/gpu/drm/nouveau/nvd0_display.c
drivers/gpu/drm/nouveau/nve0_fifo.c
drivers/gpu/drm/radeon/atombios_crtc.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/r600.c
drivers/gpu/drm/radeon/r600_cs.c
drivers/gpu/drm/radeon/r600d.h
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_asic.h
drivers/gpu/drm/radeon/radeon_atombios.c
drivers/gpu/drm/radeon/radeon_combios.c
drivers/gpu/drm/radeon/radeon_cs.c
drivers/gpu/drm/radeon/radeon_cursor.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_gart.c
drivers/gpu/drm/radeon/radeon_gem.c
drivers/gpu/drm/radeon/radeon_kms.c
drivers/gpu/drm/radeon/radeon_legacy_crtc.c
drivers/gpu/drm/radeon/radeon_mode.h
drivers/gpu/drm/radeon/radeon_object.c
drivers/gpu/drm/radeon/rv515.c
drivers/gpu/drm/radeon/si.c
drivers/gpu/drm/radeon/sid.h
drivers/gpu/drm/udl/udl_gem.c
drivers/hid/Kconfig
drivers/hid/Makefile
drivers/hid/hid-core.c
drivers/hid/hid-ids.h
drivers/hid/hid-multitouch.c
drivers/hid/hid-picolcd.c [deleted file]
drivers/hid/hid-picolcd.h [new file with mode: 0644]
drivers/hid/hid-picolcd_backlight.c [new file with mode: 0644]
drivers/hid/hid-picolcd_cir.c [new file with mode: 0644]
drivers/hid/hid-picolcd_core.c [new file with mode: 0644]
drivers/hid/hid-picolcd_debugfs.c [new file with mode: 0644]
drivers/hid/hid-picolcd_fb.c [new file with mode: 0644]
drivers/hid/hid-picolcd_lcd.c [new file with mode: 0644]
drivers/hid/hid-picolcd_leds.c [new file with mode: 0644]
drivers/hid/hid-wacom.c
drivers/hid/hidraw.c
drivers/hid/usbhid/hid-quirks.c
drivers/hv/hv.c
drivers/hv/hyperv_vmbus.h
drivers/hv/vmbus_drv.c
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/abituguru.c
drivers/hwmon/abituguru3.c
drivers/hwmon/ad7314.c
drivers/hwmon/ad7414.c
drivers/hwmon/ad7418.c
drivers/hwmon/adcxx.c
drivers/hwmon/adm1029.c
drivers/hwmon/ads1015.c
drivers/hwmon/ads7828.c
drivers/hwmon/ads7871.c
drivers/hwmon/adt7410.c [new file with mode: 0644]
drivers/hwmon/adt7411.c
drivers/hwmon/adt7462.c
drivers/hwmon/adt7470.c
drivers/hwmon/amc6821.c
drivers/hwmon/asb100.c
drivers/hwmon/coretemp.c
drivers/hwmon/dme1737.c
drivers/hwmon/ds620.c
drivers/hwmon/emc1403.c
drivers/hwmon/emc2103.c
drivers/hwmon/f71882fg.c
drivers/hwmon/f75375s.c
drivers/hwmon/fam15h_power.c
drivers/hwmon/g760a.c
drivers/hwmon/jz4740-hwmon.c
drivers/hwmon/lm70.c
drivers/hwmon/lm95241.c
drivers/hwmon/lm95245.c
drivers/hwmon/ltc4151.c
drivers/hwmon/ltc4215.c
drivers/hwmon/ltc4245.c
drivers/hwmon/max1668.c
drivers/hwmon/mcp3021.c
drivers/hwmon/sch5627.c
drivers/hwmon/sch5636.c
drivers/hwmon/sch56xx-common.c
drivers/hwmon/sht15.c
drivers/hwmon/sht21.c
drivers/hwmon/via-cputemp.c
drivers/hwmon/vt8231.c
drivers/hwmon/w83l786ng.c
drivers/i2c/busses/Kconfig
drivers/i2c/busses/i2c-i801.c
drivers/i2c/busses/i2c-iop3xx.c
drivers/i2c/busses/i2c-mpc.c
drivers/i2c/busses/i2c-omap.c
drivers/i2c/i2c-core.c
drivers/i2c/i2c-mux.c
drivers/i2c/i2c-smbus.c
drivers/i2c/muxes/i2c-mux-gpio.c
drivers/i2c/muxes/i2c-mux-pca9541.c
drivers/i2c/muxes/i2c-mux-pca954x.c
drivers/i2c/muxes/i2c-mux-pinctrl.c
drivers/idle/intel_idle.c
drivers/iio/adc/at91_adc.c
drivers/iio/frequency/adf4350.c
drivers/iio/light/adjd_s311.c
drivers/iio/light/lm3533-als.c
drivers/infiniband/core/addr.c
drivers/infiniband/core/ucma.c
drivers/infiniband/hw/amso1100/c2_rnic.c
drivers/infiniband/hw/cxgb3/iwch_cm.c
drivers/infiniband/hw/mlx4/mad.c
drivers/infiniband/hw/mlx4/main.c
drivers/infiniband/hw/mlx4/qp.c
drivers/infiniband/hw/nes/nes_hw.c
drivers/infiniband/hw/nes/nes_nic.c
drivers/infiniband/hw/ocrdma/ocrdma_main.c
drivers/infiniband/hw/qib/qib_iba7322.c
drivers/infiniband/hw/qib/qib_sd7220.c
drivers/infiniband/ulp/ipoib/ipoib_cm.c
drivers/infiniband/ulp/ipoib/ipoib_main.c
drivers/infiniband/ulp/srp/ib_srp.c
drivers/infiniband/ulp/srpt/ib_srpt.c
drivers/input/apm-power.c
drivers/input/ff-core.c
drivers/input/ff-memless.c
drivers/input/joydev.c
drivers/input/keyboard/gpio_keys.c
drivers/input/misc/twl4030-pwrbutton.c
drivers/input/mousedev.c
drivers/input/sparse-keymap.c
drivers/input/touchscreen/eeti_ts.c
drivers/iommu/amd_iommu.c
drivers/iommu/amd_iommu_init.c
drivers/iommu/exynos-iommu.c
drivers/iommu/intel-iommu.c
drivers/iommu/intel_irq_remapping.c
drivers/iommu/tegra-smmu.c
drivers/isdn/capi/capi.c
drivers/isdn/gigaset/interface.c
drivers/isdn/i4l/isdn_tty.c
drivers/isdn/isdnloop/isdnloop.c
drivers/isdn/mISDN/layer2.c
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/led-class.c
drivers/leds/led-core.c
drivers/leds/leds-clevo-mail.c
drivers/leds/leds-lp8788.c
drivers/leds/leds-renesas-tpu.c
drivers/leds/leds-wm8350.c
drivers/leds/ledtrig-cpu.c [new file with mode: 0644]
drivers/macintosh/mediabay.c
drivers/md/linear.c
drivers/md/md.c
drivers/md/md.h
drivers/md/multipath.c
drivers/md/raid0.c
drivers/md/raid1.c
drivers/md/raid10.c
drivers/md/raid10.h
drivers/md/raid5.c
drivers/md/raid5.h
drivers/media/common/saa7146_core.c
drivers/media/common/saa7146_fops.c
drivers/media/common/tuners/qt1010.c
drivers/media/common/tuners/tda18212.c
drivers/media/common/tuners/tda18218.c
drivers/media/common/tuners/tuner-xc2028.c
drivers/media/common/tuners/xc5000.c
drivers/media/dvb/Kconfig
drivers/media/dvb/Makefile
drivers/media/dvb/dvb-core/dvb-usb-ids.h [moved from drivers/media/dvb/dvb-usb/dvb-usb-ids.h with 100% similarity]
drivers/media/dvb/dvb-core/dvb_frontend.c
drivers/media/dvb/dvb-core/dvbdev.h
drivers/media/dvb/dvb-usb-v2/Kconfig [new file with mode: 0644]
drivers/media/dvb/dvb-usb-v2/Makefile [new file with mode: 0644]
drivers/media/dvb/dvb-usb-v2/af9015.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb-v2/af9015.h [moved from drivers/media/dvb/dvb-usb/af9015.h with 72% similarity]
drivers/media/dvb/dvb-usb-v2/af9035.c [moved from drivers/media/dvb/dvb-usb/af9035.c with 62% similarity]
drivers/media/dvb/dvb-usb-v2/af9035.h [moved from drivers/media/dvb/dvb-usb/af9035.h with 96% similarity]
drivers/media/dvb/dvb-usb-v2/anysee.c [moved from drivers/media/dvb/dvb-usb/anysee.c with 70% similarity]
drivers/media/dvb/dvb-usb-v2/anysee.h [moved from drivers/media/dvb/dvb-usb/anysee.h with 95% similarity]
drivers/media/dvb/dvb-usb-v2/au6610.c [moved from drivers/media/dvb/dvb-usb/au6610.c with 64% similarity]
drivers/media/dvb/dvb-usb-v2/au6610.h [moved from drivers/media/dvb/dvb-usb/au6610.h with 80% similarity]
drivers/media/dvb/dvb-usb-v2/az6007.c [moved from drivers/media/dvb/dvb-usb/az6007.c with 63% similarity]
drivers/media/dvb/dvb-usb-v2/ce6230.c [moved from drivers/media/dvb/dvb-usb/ce6230.c with 59% similarity]
drivers/media/dvb/dvb-usb-v2/ce6230.h [moved from drivers/media/dvb/dvb-usb/ce6230.h with 60% similarity]
drivers/media/dvb/dvb-usb-v2/cypress_firmware.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb-v2/cypress_firmware.h [new file with mode: 0644]
drivers/media/dvb/dvb-usb-v2/dvb_usb.h [new file with mode: 0644]
drivers/media/dvb/dvb-usb-v2/dvb_usb_common.h [new file with mode: 0644]
drivers/media/dvb/dvb-usb-v2/dvb_usb_core.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb-v2/dvb_usb_urb.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb-v2/ec168.c [moved from drivers/media/dvb/dvb-usb/ec168.c with 58% similarity]
drivers/media/dvb/dvb-usb-v2/ec168.h [moved from drivers/media/dvb/dvb-usb/ec168.h with 65% similarity]
drivers/media/dvb/dvb-usb-v2/gl861.c [moved from drivers/media/dvb/dvb-usb/gl861.c with 54% similarity]
drivers/media/dvb/dvb-usb-v2/gl861.h [moved from drivers/media/dvb/dvb-usb/gl861.h with 59% similarity]
drivers/media/dvb/dvb-usb-v2/lmedm04.c [moved from drivers/media/dvb/dvb-usb/lmedm04.c with 69% similarity]
drivers/media/dvb/dvb-usb-v2/lmedm04.h [moved from drivers/media/dvb/dvb-usb/lmedm04.h with 100% similarity]
drivers/media/dvb/dvb-usb-v2/mxl111sf-demod.c [moved from drivers/media/dvb/dvb-usb/mxl111sf-demod.c with 100% similarity]
drivers/media/dvb/dvb-usb-v2/mxl111sf-demod.h [moved from drivers/media/dvb/dvb-usb/mxl111sf-demod.h with 100% similarity]
drivers/media/dvb/dvb-usb-v2/mxl111sf-gpio.c [moved from drivers/media/dvb/dvb-usb/mxl111sf-gpio.c with 100% similarity]
drivers/media/dvb/dvb-usb-v2/mxl111sf-gpio.h [moved from drivers/media/dvb/dvb-usb/mxl111sf-gpio.h with 100% similarity]
drivers/media/dvb/dvb-usb-v2/mxl111sf-i2c.c [moved from drivers/media/dvb/dvb-usb/mxl111sf-i2c.c with 100% similarity]
drivers/media/dvb/dvb-usb-v2/mxl111sf-i2c.h [moved from drivers/media/dvb/dvb-usb/mxl111sf-i2c.h with 100% similarity]
drivers/media/dvb/dvb-usb-v2/mxl111sf-phy.c [moved from drivers/media/dvb/dvb-usb/mxl111sf-phy.c with 100% similarity]
drivers/media/dvb/dvb-usb-v2/mxl111sf-phy.h [moved from drivers/media/dvb/dvb-usb/mxl111sf-phy.h with 100% similarity]
drivers/media/dvb/dvb-usb-v2/mxl111sf-reg.h [moved from drivers/media/dvb/dvb-usb/mxl111sf-reg.h with 100% similarity]
drivers/media/dvb/dvb-usb-v2/mxl111sf-tuner.c [moved from drivers/media/dvb/dvb-usb/mxl111sf-tuner.c with 99% similarity]
drivers/media/dvb/dvb-usb-v2/mxl111sf-tuner.h [moved from drivers/media/dvb/dvb-usb/mxl111sf-tuner.h with 100% similarity]
drivers/media/dvb/dvb-usb-v2/mxl111sf.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb-v2/mxl111sf.h [moved from drivers/media/dvb/dvb-usb/mxl111sf.h with 98% similarity]
drivers/media/dvb/dvb-usb-v2/usb_urb.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/Kconfig
drivers/media/dvb/dvb-usb/Makefile
drivers/media/dvb/dvb-usb/af9015.c [deleted file]
drivers/media/dvb/dvb-usb/dib0700_core.c
drivers/media/dvb/dvb-usb/dvb_usb_dvb.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/dvb_usb_remote.c [new file with mode: 0644]
drivers/media/dvb/dvb-usb/mxl111sf.c [deleted file]
drivers/media/dvb/frontends/au8522_common.c
drivers/media/dvb/frontends/au8522_decoder.c
drivers/media/dvb/frontends/au8522_dig.c
drivers/media/dvb/frontends/au8522_priv.h
drivers/media/dvb/frontends/dvb-pll.c
drivers/media/dvb/frontends/dvb-pll.h
drivers/media/dvb/frontends/m88rs2000.c
drivers/media/dvb/frontends/nxt200x.c
drivers/media/dvb/mantis/mantis_cards.c
drivers/media/dvb/mantis/mantis_core.c
drivers/media/dvb/mantis/mantis_dvb.c
drivers/media/dvb/ngene/ngene-cards.c
drivers/media/dvb/ttpci/budget.c
drivers/media/media-device.c
drivers/media/radio/radio-shark.c
drivers/media/radio/radio-shark2.c
drivers/media/radio/si470x/radio-si470x-common.c
drivers/media/radio/si470x/radio-si470x-i2c.c
drivers/media/radio/si470x/radio-si470x-usb.c
drivers/media/radio/wl128x/fmdrv_v4l2.c
drivers/media/rc/Kconfig
drivers/media/rc/ir-nec-decoder.c
drivers/media/video/Kconfig
drivers/media/video/Makefile
drivers/media/video/au0828/au0828-cards.c
drivers/media/video/au0828/au0828-core.c
drivers/media/video/au0828/au0828-dvb.c
drivers/media/video/au0828/au0828-i2c.c
drivers/media/video/au0828/au0828-reg.h
drivers/media/video/au0828/au0828-video.c
drivers/media/video/au0828/au0828.h
drivers/media/video/blackfin/bfin_capture.c
drivers/media/video/coda.c [new file with mode: 0644]
drivers/media/video/coda.h [new file with mode: 0644]
drivers/media/video/cpia2/cpia2_core.c
drivers/media/video/cpia2/cpia2_v4l.c
drivers/media/video/cx18/cx18-av-firmware.c
drivers/media/video/cx18/cx18-driver.c
drivers/media/video/cx18/cx18-dvb.c
drivers/media/video/cx18/cx18-firmware.c
drivers/media/video/cx231xx/Makefile
drivers/media/video/cx231xx/cx231xx-417.c
drivers/media/video/cx231xx/cx231xx-video.c
drivers/media/video/cx23885/cx23885-417.c
drivers/media/video/cx23885/cx23885-cards.c
drivers/media/video/cx23885/cx23885-input.c
drivers/media/video/cx25840/cx25840-firmware.c
drivers/media/video/davinci/vpbe_display.c
drivers/media/video/davinci/vpif_capture.c
drivers/media/video/davinci/vpif_display.c
drivers/media/video/em28xx/em28xx-audio.c
drivers/media/video/em28xx/em28xx-core.c
drivers/media/video/em28xx/em28xx-video.c
drivers/media/video/fsl-viu.c
drivers/media/video/ivtv/ivtv-fileops.c
drivers/media/video/ivtv/ivtv-firmware.c
drivers/media/video/ivtv/ivtv-streams.c
drivers/media/video/m2m-deinterlace.c [new file with mode: 0644]
drivers/media/video/mem2mem_testdev.c
drivers/media/video/mx2_emmaprp.c
drivers/media/video/omap3isp/cfa_coef_table.h
drivers/media/video/omap3isp/isp.c
drivers/media/video/omap3isp/isp.h
drivers/media/video/omap3isp/ispccdc.c
drivers/media/video/omap3isp/ispccdc.h
drivers/media/video/omap3isp/ispcsi2.c
drivers/media/video/omap3isp/isph3a_aewb.c
drivers/media/video/omap3isp/isph3a_af.c
drivers/media/video/omap3isp/isphist.c
drivers/media/video/omap3isp/isppreview.c
drivers/media/video/omap3isp/isppreview.h
drivers/media/video/omap3isp/ispqueue.c
drivers/media/video/omap3isp/ispresizer.c
drivers/media/video/omap3isp/ispvideo.c
drivers/media/video/omap3isp/ispvideo.h
drivers/media/video/pvrusb2/pvrusb2-devattr.c
drivers/media/video/s2255drv.c
drivers/media/video/s5k6aa.c
drivers/media/video/s5p-g2d/g2d.c
drivers/media/video/s5p-jpeg/jpeg-core.c
drivers/media/video/s5p-mfc/s5p_mfc.c
drivers/media/video/s5p-tv/mixer_video.c
drivers/media/video/saa7164/saa7164-api.c
drivers/media/video/saa7164/saa7164-core.c
drivers/media/video/saa7164/saa7164.h
drivers/media/video/sh_vou.c
drivers/media/video/soc_camera.c
drivers/media/video/stk1160/Kconfig [new file with mode: 0644]
drivers/media/video/stk1160/Makefile [new file with mode: 0644]
drivers/media/video/stk1160/stk1160-ac97.c [new file with mode: 0644]
drivers/media/video/stk1160/stk1160-core.c [new file with mode: 0644]
drivers/media/video/stk1160/stk1160-i2c.c [new file with mode: 0644]
drivers/media/video/stk1160/stk1160-reg.h [new file with mode: 0644]
drivers/media/video/stk1160/stk1160-v4l.c [new file with mode: 0644]
drivers/media/video/stk1160/stk1160-video.c [new file with mode: 0644]
drivers/media/video/stk1160/stk1160.h [new file with mode: 0644]
drivers/media/video/tm6000/tm6000-video.c
drivers/media/video/usbvision/usbvision-video.c
drivers/media/video/uvc/uvc_queue.c
drivers/media/video/v4l2-common.c
drivers/media/video/v4l2-dev.c
drivers/media/video/v4l2-ioctl.c
drivers/media/video/videobuf2-core.c
drivers/media/video/videobuf2-vmalloc.c
drivers/media/video/vivi.c
drivers/mfd/asic3.c
drivers/mfd/da9052-i2c.c
drivers/mfd/ezx-pcap.c
drivers/mfd/tps6586x.c
drivers/mfd/wm8994-irq.c
drivers/misc/bmp085-i2c.c
drivers/misc/carma/carma-fpga-program.c
drivers/misc/carma/carma-fpga.c
drivers/misc/ibmasm/uart.c
drivers/misc/mei/hw.h
drivers/misc/mei/init.c
drivers/misc/mei/interface.h
drivers/misc/mei/interrupt.c
drivers/misc/mei/iorw.c
drivers/misc/mei/main.c
drivers/misc/mei/mei_dev.h
drivers/misc/mei/wd.c
drivers/misc/pch_phub.c
drivers/misc/pti.c
drivers/misc/ti-st/st_core.c
drivers/misc/ti-st/st_kim.c
drivers/misc/ti-st/st_ll.c
drivers/mmc/card/sdio_uart.c
drivers/mmc/host/atmel-mci.c
drivers/mmc/host/bfin_sdh.c
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/omap_hsmmc.c
drivers/mmc/host/pxamci.c
drivers/mmc/host/sdhci-dove.c
drivers/mmc/host/sdhci-of-esdhc.c
drivers/mmc/host/sdhci-pxav2.c
drivers/mmc/host/sdhci-pxav3.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/vub300.c
drivers/mtd/chips/Kconfig
drivers/mtd/chips/cfi_cmdset_0002.c
drivers/mtd/devices/Kconfig
drivers/mtd/devices/m25p80.c
drivers/mtd/devices/spear_smi.c
drivers/mtd/maps/Kconfig
drivers/mtd/maps/Makefile
drivers/mtd/maps/uclinux.c
drivers/mtd/maps/wr_sbc82xx_flash.c [deleted file]
drivers/mtd/mtdcore.c
drivers/mtd/mtdoops.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/Makefile
drivers/mtd/nand/atmel_nand.c
drivers/mtd/nand/atmel_nand_ecc.h
drivers/mtd/nand/bcm_umi_bch.c
drivers/mtd/nand/bcm_umi_nand.c
drivers/mtd/nand/bf5xx_nand.c
drivers/mtd/nand/cafe_nand.c
drivers/mtd/nand/denali.c
drivers/mtd/nand/docg4.c
drivers/mtd/nand/fsl_elbc_nand.c
drivers/mtd/nand/fsl_ifc_nand.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/lpc32xx_mlc.c [new file with mode: 0644]
drivers/mtd/nand/lpc32xx_slc.c [new file with mode: 0644]
drivers/mtd/nand/mxc_nand.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/nand_bbt.c
drivers/mtd/nand/nand_bcm_umi.h
drivers/mtd/nand/nand_ids.c
drivers/mtd/nand/omap2.c
drivers/mtd/nand/pxa3xx_nand.c
drivers/mtd/nand/sh_flctl.c
drivers/mtd/tests/mtd_speedtest.c
drivers/mtd/tests/mtd_stresstest.c
drivers/mtd/ubi/Kconfig
drivers/mtd/ubi/build.c
drivers/mtd/ubi/misc.c
drivers/mtd/ubi/ubi.h
drivers/mtd/ubi/wl.c
drivers/net/appletalk/cops.c
drivers/net/appletalk/ltpc.c
drivers/net/bonding/bond_main.c
drivers/net/can/mscan/mpc5xxx_can.c
drivers/net/cris/eth_v10.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/freescale/fs_enet/mii-bitbang.c
drivers/net/ethernet/freescale/fs_enet/mii-fec.c
drivers/net/ethernet/intel/e1000e/82571.c
drivers/net/ethernet/intel/e1000e/netdev.c
drivers/net/ethernet/intel/igb/e1000_82575.c
drivers/net/ethernet/intel/igb/e1000_regs.h
drivers/net/ethernet/intel/igb/igb_ethtool.c
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c
drivers/net/ethernet/mellanox/mlx4/en_rx.c
drivers/net/ethernet/mellanox/mlx4/en_tx.c
drivers/net/ethernet/mellanox/mlx4/icm.c
drivers/net/ethernet/mellanox/mlx4/icm.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/mlx4_en.h
drivers/net/ethernet/mellanox/mlx4/mr.c
drivers/net/ethernet/mellanox/mlx4/profile.c
drivers/net/ethernet/mellanox/mlx4/sense.c
drivers/net/ethernet/nxp/lpc_eth.c
drivers/net/ethernet/sfc/efx.c
drivers/net/ethernet/sfc/efx.h
drivers/net/ethernet/sfc/ethtool.c
drivers/net/ethernet/sfc/tx.c
drivers/net/ethernet/sgi/ioc3-eth.c
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
drivers/net/ethernet/ti/Kconfig
drivers/net/ethernet/ti/cpsw.c
drivers/net/ethernet/ti/davinci_cpdma.c
drivers/net/ethernet/ti/davinci_mdio.c
drivers/net/ethernet/xscale/ixp4xx_eth.c
drivers/net/hyperv/netvsc.c
drivers/net/hyperv/netvsc_drv.c
drivers/net/hyperv/rndis_filter.c
drivers/net/irda/bfin_sir.c
drivers/net/irda/irtty-sir.c
drivers/net/loopback.c
drivers/net/macvtap.c
drivers/net/netconsole.c
drivers/net/phy/mdio-mux-gpio.c
drivers/net/ppp/ppp_generic.c
drivers/net/ppp/pptp.c
drivers/net/team/team.c
drivers/net/tun.c
drivers/net/usb/cdc-phonet.c
drivers/net/usb/cdc_ncm.c
drivers/net/usb/hso.c
drivers/net/usb/qmi_wwan.c
drivers/net/usb/sierra_net.c
drivers/net/veth.c
drivers/net/virtio_net.c
drivers/net/vmxnet3/vmxnet3_drv.c
drivers/net/wireless/at76c50x-usb.c
drivers/net/wireless/ath/ath5k/ath5k.h
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath5k/mac80211-ops.c
drivers/net/wireless/ath/ath5k/phy.c
drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/mac.c
drivers/net/wireless/ath/ath9k/mac.h
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/pci.c
drivers/net/wireless/ath/ath9k/rc.c
drivers/net/wireless/ath/ath9k/rc.h
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/carl9170/fw.c
drivers/net/wireless/ath/carl9170/mac.c
drivers/net/wireless/ath/carl9170/main.c
drivers/net/wireless/ath/carl9170/rx.c
drivers/net/wireless/b43/Makefile
drivers/net/wireless/b43/b43.h
drivers/net/wireless/b43/main.c
drivers/net/wireless/b43/phy_common.c
drivers/net/wireless/b43/phy_common.h
drivers/net/wireless/b43/phy_n.c
drivers/net/wireless/b43/phy_n.h
drivers/net/wireless/b43/radio_2057.c [new file with mode: 0644]
drivers/net/wireless/b43/radio_2057.h [new file with mode: 0644]
drivers/net/wireless/b43/tables_nphy.c
drivers/net/wireless/b43/tables_nphy.h
drivers/net/wireless/b43legacy/main.c
drivers/net/wireless/brcm80211/brcmsmac/channel.c
drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
drivers/net/wireless/brcm80211/brcmsmac/main.c
drivers/net/wireless/brcm80211/include/brcmu_wifi.h
drivers/net/wireless/ipw2x00/ipw2100.c
drivers/net/wireless/iwlegacy/common.c
drivers/net/wireless/iwlegacy/common.h
drivers/net/wireless/iwlwifi/dvm/rs.c
drivers/net/wireless/libertas/cfg.c
drivers/net/wireless/libertas/if_sdio.c
drivers/net/wireless/libertas/main.c
drivers/net/wireless/mwifiex/11n.c
drivers/net/wireless/mwifiex/11n.h
drivers/net/wireless/mwifiex/11n_aggr.c
drivers/net/wireless/mwifiex/11n_rxreorder.c
drivers/net/wireless/mwifiex/11n_rxreorder.h
drivers/net/wireless/mwifiex/Makefile
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/cmdevt.c
drivers/net/wireless/mwifiex/decl.h
drivers/net/wireless/mwifiex/fw.h
drivers/net/wireless/mwifiex/init.c
drivers/net/wireless/mwifiex/ioctl.h
drivers/net/wireless/mwifiex/main.c
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/scan.c
drivers/net/wireless/mwifiex/sta_cmd.c
drivers/net/wireless/mwifiex/sta_event.c
drivers/net/wireless/mwifiex/sta_ioctl.c
drivers/net/wireless/mwifiex/sta_rx.c
drivers/net/wireless/mwifiex/txrx.c
drivers/net/wireless/mwifiex/uap_cmd.c
drivers/net/wireless/mwifiex/uap_event.c [new file with mode: 0644]
drivers/net/wireless/mwifiex/uap_txrx.c [new file with mode: 0644]
drivers/net/wireless/mwifiex/wmm.c
drivers/net/wireless/p54/eeprom.c
drivers/net/wireless/p54/eeprom.h
drivers/net/wireless/p54/p54pci.c
drivers/net/wireless/p54/p54pci.h
drivers/net/wireless/rndis_wlan.c
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/net/wireless/rt2x00/rt2800pci.c
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/wireless/zd1211rw/zd_usb.c
drivers/net/xen-netfront.c
drivers/of/address.c
drivers/of/base.c
drivers/of/platform.c
drivers/pci/pci-acpi.c
drivers/pci/pci-driver.c
drivers/pci/pcie/aer/aerdrv_core.c
drivers/pci/setup-irq.c
drivers/pinctrl/Kconfig
drivers/pinctrl/Makefile
drivers/pinctrl/core.c
drivers/pinctrl/pinctrl-coh901.c
drivers/pinctrl/pinctrl-imx23.c
drivers/pinctrl/pinctrl-imx28.c
drivers/pinctrl/pinctrl-imx35.c [new file with mode: 0644]
drivers/pinctrl/pinctrl-imx51.c
drivers/pinctrl/pinctrl-imx53.c
drivers/pinctrl/pinctrl-nomadik-db8500.c
drivers/pinctrl/pinctrl-nomadik-db8540.c [new file with mode: 0644]
drivers/pinctrl/pinctrl-nomadik-stn8815.c [new file with mode: 0644]
drivers/pinctrl/pinctrl-nomadik.c
drivers/pinctrl/pinctrl-nomadik.h
drivers/pinctrl/pinctrl-sirf.c
drivers/pinctrl/pinctrl-u300.c
drivers/platform/x86/acerhdf.c
drivers/platform/x86/classmate-laptop.c
drivers/platform/x86/fujitsu-tablet.c
drivers/platform/x86/hdaps.c
drivers/platform/x86/hp_accel.c
drivers/platform/x86/intel_mid_thermal.c
drivers/platform/x86/msi-laptop.c
drivers/platform/x86/panasonic-laptop.c
drivers/platform/x86/sony-laptop.c
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/toshiba_acpi.c
drivers/platform/x86/toshiba_bluetooth.c
drivers/platform/x86/xo15-ebook.c
drivers/power/charger-manager.c
drivers/power/ds2760_battery.c
drivers/power/jz4740-battery.c
drivers/power/power_supply_core.c
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/ab3100.c
drivers/regulator/ab8500.c
drivers/regulator/anatop-regulator.c
drivers/regulator/core.c
drivers/regulator/da9052-regulator.c
drivers/regulator/dummy.c
drivers/regulator/gpio-regulator.c
drivers/regulator/isl6271a-regulator.c
drivers/regulator/lp872x.c
drivers/regulator/lp8788-buck.c
drivers/regulator/lp8788-ldo.c
drivers/regulator/max77686.c
drivers/regulator/max8907-regulator.c [new file with mode: 0644]
drivers/regulator/mc13783-regulator.c
drivers/regulator/mc13892-regulator.c
drivers/regulator/mc13xxx-regulator-core.c
drivers/regulator/mc13xxx.h
drivers/regulator/palmas-regulator.c
drivers/regulator/s2mps11.c
drivers/regulator/tps6524x-regulator.c
drivers/regulator/tps6586x-regulator.c
drivers/regulator/twl-regulator.c
drivers/regulator/wm831x-dcdc.c
drivers/regulator/wm831x-ldo.c
drivers/regulator/wm8400-regulator.c
drivers/rtc/interface.c
drivers/rtc/rtc-cmos.c
drivers/rtc/rtc-pxa.c
drivers/s390/char/con3215.c
drivers/s390/char/sclp_sdias.c
drivers/s390/char/sclp_tty.c
drivers/s390/char/sclp_vt220.c
drivers/s390/char/tty3270.c
drivers/scsi/ipr.c
drivers/scsi/ipr.h
drivers/scsi/isci/host.c
drivers/scsi/isci/host.h
drivers/scsi/isci/init.c
drivers/scsi/isci/phy.c
drivers/scsi/isci/probe_roms.c
drivers/scsi/isci/remote_node_context.h
drivers/scsi/libsas/sas_ata.c
drivers/scsi/libsas/sas_discover.c
drivers/scsi/libsas/sas_dump.c
drivers/scsi/libsas/sas_event.c
drivers/scsi/libsas/sas_init.c
drivers/scsi/libsas/sas_internal.h
drivers/scsi/libsas/sas_phy.c
drivers/scsi/libsas/sas_port.c
drivers/scsi/megaraid/megaraid_sas.h
drivers/scsi/megaraid/megaraid_sas_base.c
drivers/scsi/megaraid/megaraid_sas_fusion.c
drivers/scsi/mpt2sas/Kconfig
drivers/scsi/mpt2sas/mpi/mpi2.h
drivers/scsi/mpt2sas/mpi/mpi2_init.h
drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
drivers/scsi/mpt2sas/mpi/mpi2_raid.h
drivers/scsi/mpt2sas/mpt2sas_base.c
drivers/scsi/mpt2sas/mpt2sas_base.h
drivers/scsi/mpt2sas/mpt2sas_config.c
drivers/scsi/mpt2sas/mpt2sas_ctl.c
drivers/scsi/mpt2sas/mpt2sas_ctl.h
drivers/scsi/mpt2sas/mpt2sas_debug.h
drivers/scsi/mpt2sas/mpt2sas_scsih.c
drivers/scsi/mpt2sas/mpt2sas_transport.c
drivers/scsi/scsi_lib.c
drivers/sh/intc/core.c
drivers/spi/spi-altera.c
drivers/spi/spi-bcm63xx.c
drivers/spi/spi-imx.c
drivers/spi/spi-omap2-mcspi.c
drivers/spi/spi-orion.c
drivers/spi/spi-s3c64xx.c
drivers/spi/spi.c
drivers/ssb/driver_mipscore.c
drivers/staging/android/ashmem.c
drivers/staging/android/logger.c
drivers/staging/android/logger.h
drivers/staging/android/timed_gpio.c
drivers/staging/asus_oled/asus_oled.c
drivers/staging/bcm/CmHost.c
drivers/staging/bcm/Misc.c
drivers/staging/ccg/ccg.c
drivers/staging/comedi/Kconfig
drivers/staging/comedi/comedi_fops.c
drivers/staging/comedi/comedidev.h
drivers/staging/comedi/drivers.c
drivers/staging/comedi/drivers/Makefile
drivers/staging/comedi/drivers/adl_pci6208.c
drivers/staging/comedi/drivers/adl_pci7230.c [deleted file]
drivers/staging/comedi/drivers/adl_pci7296.c
drivers/staging/comedi/drivers/adl_pci7432.c [deleted file]
drivers/staging/comedi/drivers/adl_pci7x3x.c [new file with mode: 0644]
drivers/staging/comedi/drivers/adv_pci1710.c
drivers/staging/comedi/drivers/adv_pci1723.c
drivers/staging/comedi/drivers/adv_pci_dio.c
drivers/staging/comedi/drivers/amplc_dio200.c
drivers/staging/comedi/drivers/amplc_pc236.c
drivers/staging/comedi/drivers/amplc_pc263.c
drivers/staging/comedi/drivers/contec_pci_dio.c
drivers/staging/comedi/drivers/daqboard2000.c
drivers/staging/comedi/drivers/dt3000.c
drivers/staging/comedi/drivers/dyna_pci10xx.c
drivers/staging/comedi/drivers/rtd520.c
drivers/staging/comedi/drivers/ssv_dnp.c
drivers/staging/comedi/drivers/usbdux.c
drivers/staging/comedi/drivers/usbduxfast.c
drivers/staging/comedi/drivers/usbduxsigma.c
drivers/staging/comedi/range.c
drivers/staging/crystalhd/crystalhd_lnx.c
drivers/staging/csr/Kconfig
drivers/staging/csr/Makefile
drivers/staging/csr/bh.c
drivers/staging/csr/csr_formatted_io.c [deleted file]
drivers/staging/csr/csr_formatted_io.h [deleted file]
drivers/staging/csr/csr_panic.c
drivers/staging/csr/csr_time.c
drivers/staging/csr/csr_wifi_hip_card_sdio.c
drivers/staging/csr/csr_wifi_hip_send.c
drivers/staging/csr/csr_wifi_hip_udi.c
drivers/staging/csr/csr_wifi_hip_unifi.h
drivers/staging/csr/drv.c
drivers/staging/csr/firmware.c
drivers/staging/csr/io.c
drivers/staging/csr/monitor.c
drivers/staging/csr/netdev.c
drivers/staging/csr/sdio_mmc.c
drivers/staging/csr/sme_native.c
drivers/staging/csr/sme_sys.c
drivers/staging/csr/sme_wext.c
drivers/staging/csr/ul_int.c
drivers/staging/csr/unifi_pdu_processing.c
drivers/staging/csr/unifi_wext.h
drivers/staging/csr/wext_events.c
drivers/staging/ft1000/ft1000-usb/ft1000_hw.c
drivers/staging/ft1000/ft1000-usb/ft1000_usb.h
drivers/staging/gdm72xx/gdm_wimax.c
drivers/staging/iio/Documentation/generic_buffer.c
drivers/staging/iio/accel/adis16201_core.c
drivers/staging/iio/accel/adis16203_core.c
drivers/staging/iio/accel/adis16204_core.c
drivers/staging/iio/accel/adis16209_core.c
drivers/staging/iio/accel/adis16220_core.c
drivers/staging/iio/accel/adis16240_core.c
drivers/staging/iio/accel/kxsd9.c
drivers/staging/iio/accel/lis3l02dq_core.c
drivers/staging/iio/accel/sca3000_core.c
drivers/staging/iio/adc/Kconfig
drivers/staging/iio/adc/Makefile
drivers/staging/iio/adc/ad7192.c
drivers/staging/iio/adc/ad7298_core.c
drivers/staging/iio/adc/ad7298_ring.c
drivers/staging/iio/adc/ad7606.h
drivers/staging/iio/adc/ad7606_core.c
drivers/staging/iio/adc/ad7780.c
drivers/staging/iio/adc/ad7793.c
drivers/staging/iio/adc/lpc32xx_adc.c
drivers/staging/iio/adc/max1363.h
drivers/staging/iio/adc/max1363_core.c
drivers/staging/iio/adc/mxs-lradc.c [new file with mode: 0644]
drivers/staging/iio/adc/spear_adc.c
drivers/staging/iio/iio_hwmon.c
drivers/staging/iio/iio_simple_dummy.c
drivers/staging/iio/impedance-analyzer/ad5933.c
drivers/staging/iio/imu/adis16400_core.c
drivers/staging/iio/meter/ade7758.h
drivers/staging/iio/meter/ade7758_core.c
drivers/staging/iio/resolver/ad2s1210.c
drivers/staging/ipack/bridges/tpci200.c
drivers/staging/ipack/devices/ipoctal.c
drivers/staging/line6/pcm.c
drivers/staging/line6/variax.c
drivers/staging/media/Kconfig
drivers/staging/media/Makefile
drivers/staging/media/cxd2099/cxd2099.c
drivers/staging/media/dt3155v4l/dt3155v4l.c
drivers/staging/media/easycap/Kconfig [deleted file]
drivers/staging/media/easycap/Makefile [deleted file]
drivers/staging/media/easycap/README [deleted file]
drivers/staging/media/easycap/easycap.h [deleted file]
drivers/staging/media/easycap/easycap_ioctl.c [deleted file]
drivers/staging/media/easycap/easycap_low.c [deleted file]
drivers/staging/media/easycap/easycap_main.c [deleted file]
drivers/staging/media/easycap/easycap_settings.c [deleted file]
drivers/staging/media/easycap/easycap_sound.c [deleted file]
drivers/staging/media/easycap/easycap_testcard.c [deleted file]
drivers/staging/nvec/nvec.c
drivers/staging/omap-thermal/omap-thermal-common.c
drivers/staging/omapdrm/omap_crtc.c
drivers/staging/omapdrm/omap_dmm_tiler.c
drivers/staging/omapdrm/omap_dmm_tiler.h
drivers/staging/omapdrm/omap_drv.c
drivers/staging/omapdrm/omap_drv.h
drivers/staging/omapdrm/omap_fb.c
drivers/staging/omapdrm/omap_gem.c
drivers/staging/omapdrm/omap_plane.c
drivers/staging/ozwpan/ozhcd.c
drivers/staging/ozwpan/ozmain.c
drivers/staging/ozwpan/ozpd.c
drivers/staging/ozwpan/ozpd.h
drivers/staging/ozwpan/ozproto.c
drivers/staging/ozwpan/ozproto.h
drivers/staging/ozwpan/ozprotocol.h
drivers/staging/panel/panel.c
drivers/staging/rtl8187se/ieee80211/ieee80211.h
drivers/staging/rtl8187se/r8180_core.c
drivers/staging/rtl8187se/r8180_hw.h
drivers/staging/rtl8187se/r8185b_init.c
drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c
drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h
drivers/staging/rtl8192e/rtl8192e/rtl_core.c
drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
drivers/staging/rtl8192e/rtllib.h
drivers/staging/rtl8192e/rtllib_softmac.c
drivers/staging/rtl8192u/ieee80211/ieee80211.h
drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c
drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c
drivers/staging/rtl8192u/ieee80211/rtl819x_HT.h
drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c
drivers/staging/rtl8192u/r819xU_HTType.h
drivers/staging/rtl8192u/r819xU_phyreg.h
drivers/staging/rtl8712/rtl8712_recv.h
drivers/staging/rts5139/trace.h
drivers/staging/rts_pstor/trace.h
drivers/staging/serqt_usb2/serqt_usb2.c
drivers/staging/speakup/i18n.c
drivers/staging/tidspbridge/Documentation/error-codes
drivers/staging/tidspbridge/core/_tiomap.h
drivers/staging/tidspbridge/core/chnl_sm.c
drivers/staging/tidspbridge/core/io_sm.c
drivers/staging/tidspbridge/core/sync.c
drivers/staging/tidspbridge/core/tiomap3430.c
drivers/staging/tidspbridge/core/tiomap3430_pwr.c
drivers/staging/tidspbridge/dynload/tramp.c
drivers/staging/tidspbridge/gen/uuidutil.c
drivers/staging/tidspbridge/hw/hw_mmu.c
drivers/staging/tidspbridge/include/dspbridge/dspioctl.h
drivers/staging/tidspbridge/include/dspbridge/mbx_sh.h
drivers/staging/tidspbridge/include/dspbridge/node.h
drivers/staging/tidspbridge/include/dspbridge/ntfy.h
drivers/staging/tidspbridge/include/dspbridge/proc.h
drivers/staging/tidspbridge/include/dspbridge/strm.h
drivers/staging/tidspbridge/include/dspbridge/sync.h
drivers/staging/tidspbridge/include/dspbridge/uuidutil.h
drivers/staging/tidspbridge/rmgr/dbdcd.c
drivers/staging/tidspbridge/rmgr/drv_interface.c
drivers/staging/tidspbridge/rmgr/dspdrv.c
drivers/staging/tidspbridge/rmgr/mgr.c
drivers/staging/tidspbridge/rmgr/nldr.c
drivers/staging/tidspbridge/rmgr/node.c
drivers/staging/tidspbridge/rmgr/proc.c
drivers/staging/usbip/stub_rx.c
drivers/staging/usbip/vhci_hcd.c
drivers/staging/vme/devices/vme_user.c
drivers/staging/vt6655/ioctl.c
drivers/staging/vt6656/hostap.c
drivers/staging/vt6656/ioctl.c
drivers/staging/vt6656/rf.c
drivers/staging/vt6656/rxtx.c
drivers/staging/vt6656/wcmd.c
drivers/staging/vt6656/wmgr.c
drivers/staging/wlan-ng/p80211wep.c
drivers/staging/xgifb/XGI_main_26.c
drivers/staging/xgifb/vb_init.c
drivers/staging/zsmalloc/zsmalloc-main.c
drivers/staging/zsmalloc/zsmalloc_int.h [deleted file]
drivers/thermal/Kconfig
drivers/thermal/Makefile
drivers/thermal/rcar_thermal.c [new file with mode: 0644]
drivers/thermal/spear_thermal.c
drivers/thermal/thermal_sys.c
drivers/tty/Kconfig
drivers/tty/amiserial.c
drivers/tty/bfin_jtag_comm.c
drivers/tty/cyclades.c
drivers/tty/ehv_bytechan.c
drivers/tty/hvc/hvc_console.c
drivers/tty/hvc/hvcs.c
drivers/tty/hvc/hvsi.c
drivers/tty/hvc/hvsi_lib.c
drivers/tty/ipwireless/tty.c
drivers/tty/isicom.c
drivers/tty/moxa.c
drivers/tty/mxser.c
drivers/tty/n_gsm.c
drivers/tty/n_r3964.c
drivers/tty/n_tty.c
drivers/tty/nozomi.c
drivers/tty/pty.c
drivers/tty/rocket.c
drivers/tty/serial/68328serial.c
drivers/tty/serial/8250/8250.c
drivers/tty/serial/8250/8250.h
drivers/tty/serial/8250/8250_acorn.c
drivers/tty/serial/8250/8250_dw.c
drivers/tty/serial/8250/8250_gsc.c
drivers/tty/serial/8250/8250_hp300.c
drivers/tty/serial/8250/8250_pci.c
drivers/tty/serial/8250/8250_pnp.c
drivers/tty/serial/8250/serial_cs.c
drivers/tty/serial/Kconfig
drivers/tty/serial/Makefile
drivers/tty/serial/amba-pl011.c
drivers/tty/serial/bfin_uart.c
drivers/tty/serial/crisv10.c
drivers/tty/serial/ifx6x60.c
drivers/tty/serial/imx.c
drivers/tty/serial/ioc4_serial.c
drivers/tty/serial/jsm/jsm_tty.c
drivers/tty/serial/kgdboc.c
drivers/tty/serial/lpc32xx_hs.c [new file with mode: 0644]
drivers/tty/serial/max3107.c [deleted file]
drivers/tty/serial/max3107.h [deleted file]
drivers/tty/serial/max310x.c [new file with mode: 0644]
drivers/tty/serial/mpc52xx_uart.c
drivers/tty/serial/msm_smd_tty.c
drivers/tty/serial/mxs-auart.c
drivers/tty/serial/of_serial.c
drivers/tty/serial/omap-serial.c
drivers/tty/serial/pch_uart.c
drivers/tty/serial/pmac_zilog.c
drivers/tty/serial/pxa.c
drivers/tty/serial/samsung.c
drivers/tty/serial/sc26xx.c
drivers/tty/serial/serial_core.c
drivers/tty/synclink.c
drivers/tty/synclink_gt.c
drivers/tty/synclinkmp.c
drivers/tty/tty_io.c
drivers/tty/tty_ioctl.c
drivers/tty/tty_ldisc.c
drivers/tty/tty_mutex.c
drivers/tty/tty_port.c
drivers/tty/vt/keyboard.c
drivers/tty/vt/vt.c
drivers/usb/atm/ueagle-atm.c
drivers/usb/chipidea/Kconfig
drivers/usb/class/cdc-acm.c
drivers/usb/core/sysfs.c
drivers/usb/early/ehci-dbgp.c
drivers/usb/gadget/s3c-hsotg.c
drivers/usb/gadget/u_ether.c
drivers/usb/gadget/u_serial.c
drivers/usb/host/Kconfig
drivers/usb/host/ehci-atmel.c
drivers/usb/host/ehci-au1xxx.c
drivers/usb/host/ehci-cns3xxx.c
drivers/usb/host/ehci-grlib.c
drivers/usb/host/ehci-ixp4xx.c
drivers/usb/host/ehci-ls1x.c
drivers/usb/host/ehci-msm.c
drivers/usb/host/ehci-mv.c
drivers/usb/host/ehci-mxc.c
drivers/usb/host/ehci-omap.c
drivers/usb/host/ehci-platform.c
drivers/usb/host/ehci-ppc-of.c
drivers/usb/host/ehci-s5p.c
drivers/usb/host/ehci-sead3.c
drivers/usb/host/ehci-sh.c
drivers/usb/host/ehci-tegra.c
drivers/usb/host/ehci-vt8500.c
drivers/usb/host/ehci-xilinx-of.c
drivers/usb/host/isp1362-hcd.c
drivers/usb/host/ohci-omap.c
drivers/usb/host/ohci-platform.c
drivers/usb/host/ohci-pxa27x.c
drivers/usb/host/pci-quirks.c
drivers/usb/host/pci-quirks.h
drivers/usb/host/uhci-hcd.c
drivers/usb/host/uhci-platform.c [new file with mode: 0644]
drivers/usb/host/whci/hcd.c
drivers/usb/host/whci/qset.c
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h
drivers/usb/misc/legousbtower.c
drivers/usb/musb/Kconfig
drivers/usb/musb/musb_dsps.c
drivers/usb/renesas_usbhs/common.c
drivers/usb/renesas_usbhs/mod_host.c
drivers/usb/serial/ark3116.c
drivers/usb/serial/belkin_sa.c
drivers/usb/serial/bus.c
drivers/usb/serial/console.c
drivers/usb/serial/cp210x.c
drivers/usb/serial/cypress_m8.c
drivers/usb/serial/digi_acceleport.c
drivers/usb/serial/empeg.c
drivers/usb/serial/f81232.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/io_edgeport.c
drivers/usb/serial/io_ti.c
drivers/usb/serial/ipw.c
drivers/usb/serial/ir-usb.c
drivers/usb/serial/iuu_phoenix.c
drivers/usb/serial/keyspan.c
drivers/usb/serial/keyspan_pda.c
drivers/usb/serial/kl5kusb105.c
drivers/usb/serial/kobil_sct.c
drivers/usb/serial/mct_u232.c
drivers/usb/serial/metro-usb.c
drivers/usb/serial/mos7720.c
drivers/usb/serial/mos7840.c
drivers/usb/serial/option.c
drivers/usb/serial/oti6858.c
drivers/usb/serial/pl2303.c
drivers/usb/serial/qcserial.c
drivers/usb/serial/quatech2.c
drivers/usb/serial/sierra.c
drivers/usb/serial/spcp8x5.c
drivers/usb/serial/ssu100.c
drivers/usb/serial/ti_usb_3410_5052.c
drivers/usb/serial/usb-serial.c
drivers/usb/serial/usb-wwan.h
drivers/usb/serial/usb_wwan.c
drivers/usb/serial/whiteheat.c
drivers/usb/storage/ene_ub6250.c
drivers/usb/wusbcore/security.c
drivers/usb/wusbcore/wa-hc.c
drivers/vhost/Kconfig
drivers/vhost/Kconfig.tcm [new file with mode: 0644]
drivers/vhost/Makefile
drivers/vhost/tcm_vhost.c [new file with mode: 0644]
drivers/vhost/tcm_vhost.h [new file with mode: 0644]
drivers/video/backlight/88pm860x_bl.c
drivers/virt/Kconfig
drivers/w1/masters/Kconfig
drivers/w1/masters/omap_hdq.c
drivers/w1/masters/w1-gpio.c
drivers/w1/slaves/w1_therm.c
drivers/w1/w1_family.h
drivers/watchdog/mpc8xxx_wdt.c
drivers/xen/events.c
drivers/zorro/zorro.c
firmware/Makefile
firmware/cxgb3/t3fw-7.10.0.bin.ihex [deleted file]
firmware/intelliport2.bin.ihex [deleted file]
fs/afs/callback.c
fs/afs/server.c
fs/afs/vlocation.c
fs/autofs4/expire.c
fs/bio.c
fs/block_dev.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/ordered-data.c
fs/btrfs/super.c
fs/btrfs/volumes.c
fs/cifs/Kconfig
fs/cifs/Makefile
fs/cifs/cifsacl.c
fs/cifs/cifsencrypt.c
fs/cifs/cifsfs.c
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/dir.c
fs/cifs/file.c
fs/cifs/inode.c
fs/cifs/ioctl.c
fs/cifs/link.c
fs/cifs/misc.c
fs/cifs/netmisc.c
fs/cifs/readdir.c
fs/cifs/smb1ops.c
fs/cifs/smb2file.c [new file with mode: 0644]
fs/cifs/smb2glob.h
fs/cifs/smb2inode.c
fs/cifs/smb2maperror.c
fs/cifs/smb2misc.c
fs/cifs/smb2ops.c
fs/cifs/smb2pdu.c
fs/cifs/smb2pdu.h
fs/cifs/smb2proto.h
fs/cifs/smb2transport.c
fs/cifs/transport.c
fs/direct-io.c
fs/dlm/ast.c
fs/dlm/config.c
fs/dlm/config.h
fs/dlm/dlm_internal.h
fs/dlm/lockspace.c
fs/dlm/lowcomms.c
fs/dlm/lowcomms.h
fs/dlm/main.c
fs/dlm/member.c
fs/dlm/rcom.c
fs/dlm/recoverd.c
fs/dlm/recoverd.h
fs/exofs/inode.c
fs/exofs/ore.c
fs/exofs/super.c
fs/exofs/sys.c
fs/ext3/inode.c
fs/ext3/super.c
fs/ext4/inode.c
fs/ext4/super.c
fs/fuse/file.c
fs/fuse/fuse_i.h
fs/fuse/inode.c
fs/gfs2/aops.c
fs/gfs2/bmap.c
fs/gfs2/file.c
fs/gfs2/glock.c
fs/gfs2/incore.h
fs/gfs2/inode.c
fs/gfs2/meta_io.c
fs/gfs2/quota.c
fs/gfs2/rgrp.c
fs/gfs2/rgrp.h
fs/gfs2/super.c
fs/gfs2/trace_gfs2.h
fs/gfs2/trans.h
fs/gfs2/xattr.c
fs/hfs/mdb.c
fs/jbd/journal.c
fs/jbd2/journal.c
fs/logfs/dev_bdev.c
fs/logfs/inode.c
fs/logfs/journal.c
fs/logfs/readwrite.c
fs/logfs/segment.c
fs/nfs/Makefile
fs/nfs/client.c
fs/nfs/idmap.c
fs/nfs/nfs4_fs.h
fs/nfs/nfs4proc.c
fs/nfs/nfs4renewd.c
fs/nfs/nfs4super.c
fs/nfs/nfs4xdr.c
fs/nfs/objlayout/objio_osd.c
fs/nfs/pagelist.c
fs/nfs/pnfs.c
fs/nfs/pnfs.h
fs/nfs/super.c
fs/nfs/write.c
fs/nilfs2/super.c
fs/nilfs2/the_nilfs.h
fs/notify/dnotify/dnotify.c
fs/notify/fanotify/fanotify.c
fs/notify/fanotify/fanotify_user.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/ocfs2/cluster/heartbeat.c
fs/ocfs2/cluster/masklog.h
fs/ocfs2/dlm/dlmmaster.c
fs/ocfs2/dlm/dlmrecovery.c
fs/ocfs2/symlink.c
fs/open.c
fs/quota/dquot.c
fs/reiserfs/bitmap.c
fs/reiserfs/inode.c
fs/super.c
fs/ubifs/file.c
fs/ubifs/super.c
fs/udf/inode.c
fs/udf/super.c
fs/xfs/xfs_discard.c
fs/xfs/xfs_ialloc.c
fs/xfs/xfs_mount.h
fs/xfs/xfs_rtalloc.c
fs/xfs/xfs_trace.h
include/acpi/acpixf.h
include/acpi/actypes.h
include/asm-generic/module.h
include/asm-generic/vmlinux.lds.h
include/crypto/cast5.h [new file with mode: 0644]
include/crypto/cast6.h [new file with mode: 0644]
include/crypto/internal/hash.h
include/drm/drm_pciids.h
include/drm/radeon_drm.h
include/linux/Kbuild
include/linux/acpi.h
include/linux/atmel_tc.h
include/linux/backing-dev.h
include/linux/bcma/bcma_driver_chipcommon.h
include/linux/bcma/bcma_regs.h
include/linux/blkdev.h
include/linux/can.h
include/linux/cd1400.h [deleted file]
include/linux/cdk.h [deleted file]
include/linux/clockchips.h
include/linux/comstats.h [deleted file]
include/linux/device.h
include/linux/fs.h
include/linux/fsnotify_backend.h
include/linux/ftrace_event.h
include/linux/fuse.h
include/linux/generic_serial.h [deleted file]
include/linux/hardirq.h
include/linux/hash.h
include/linux/i2c-mux-gpio.h
include/linux/i2c-mux.h
include/linux/i2c/pca954x.h
include/linux/if_arp.h
include/linux/if_team.h
include/linux/if_tunnel.h
include/linux/iio/frequency/adf4350.h
include/linux/inetdevice.h
include/linux/input/eeti_ts.h
include/linux/iommu.h
include/linux/ip6_tunnel.h
include/linux/ipv6.h
include/linux/irq.h
include/linux/irqdesc.h
include/linux/istallion.h [deleted file]
include/linux/jiffies.h
include/linux/kbd_kern.h
include/linux/kdb.h
include/linux/kvm.h
include/linux/kvm_host.h
include/linux/leds.h
include/linux/libata.h
include/linux/mfd/ezx-pcap.h
include/linux/mfd/max77686.h
include/linux/mfd/tps6586x.h
include/linux/mmc/sdhci.h
include/linux/mod_devicetable.h
include/linux/moduleloader.h
include/linux/mtd/bbm.h
include/linux/mtd/mtd.h
include/linux/mtd/nand.h
include/linux/mtd/sh_flctl.h
include/linux/mv643xx_eth.h
include/linux/netdevice.h
include/linux/netpoll.h
include/linux/nfs_page.h
include/linux/nfs_xdr.h
include/linux/nx842.h [new file with mode: 0644]
include/linux/of_address.h
include/linux/omap3isp.h
include/linux/packet_diag.h [new file with mode: 0644]
include/linux/perf_event.h
include/linux/pinctrl/consumer.h
include/linux/platform_data/max310x.h [new file with mode: 0644]
include/linux/platform_data/pinctrl-coh901.h [moved from arch/arm/mach-u300/include/mach/gpio-u300.h with 72% similarity]
include/linux/pm.h
include/linux/pm_domain.h
include/linux/ptrace.h
include/linux/rcupdate.h
include/linux/regmap.h
include/linux/regulator/consumer.h
include/linux/regulator/driver.h
include/linux/sc26198.h [deleted file]
include/linux/sched.h
include/linux/security.h
include/linux/serial167.h [deleted file]
include/linux/serial_8250.h
include/linux/serial_core.h
include/linux/skbuff.h
include/linux/snmp.h
include/linux/ssb/ssb_driver_chipcommon.h
include/linux/stallion.h [deleted file]
include/linux/thermal.h
include/linux/ti_wilink_st.h
include/linux/timex.h
include/linux/topology.h
include/linux/tty.h
include/linux/tty_driver.h
include/linux/usb/ehci_pdriver.h
include/linux/usb/hcd.h
include/linux/usb/ohci_pdriver.h
include/linux/v4l2-common.h
include/linux/w1-gpio.h
include/linux/workqueue.h
include/linux/writeback.h
include/media/omap3isp.h
include/media/saa7146.h
include/media/v4l2-common.h
include/media/v4l2-dev.h
include/media/v4l2-subdev.h
include/net/arp.h
include/net/bluetooth/bluetooth.h
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
include/net/bluetooth/l2cap.h
include/net/bluetooth/mgmt.h
include/net/bluetooth/smp.h
include/net/cfg80211.h
include/net/codel.h
include/net/dst.h
include/net/inet_connection_sock.h
include/net/inet_sock.h
include/net/ip.h
include/net/ip6_tunnel.h
include/net/ipv6.h
include/net/irda/ircomm_tty.h
include/net/llc.h
include/net/ndisc.h
include/net/neighbour.h
include/net/net_namespace.h
include/net/netlink.h
include/net/netns/sctp.h [new file with mode: 0644]
include/net/sctp/sctp.h
include/net/sctp/sm.h
include/net/sctp/structs.h
include/net/snmp.h
include/net/sock.h
include/net/tcp.h
include/net/xfrm.h
include/scsi/libsas.h
include/scsi/sas_ata.h
include/sound/emu10k1.h
include/sound/initval.h
include/trace/events/sched.h
include/trace/ftrace.h
init/Kconfig
kernel/audit_tree.c
kernel/audit_watch.c
kernel/debug/kdb/kdb_debugger.c
kernel/debug/kdb/kdb_io.c
kernel/debug/kdb/kdb_main.c
kernel/events/callchain.c
kernel/events/core.c
kernel/events/internal.h
kernel/futex.c
kernel/irq/manage.c
kernel/jump_label.c
kernel/module.c
kernel/power/Kconfig
kernel/power/suspend.c
kernel/printk.c
kernel/ptrace.c
kernel/rcupdate.c
kernel/rcutiny.c
kernel/rcutorture.c
kernel/rcutree.c
kernel/rcutree.h
kernel/rcutree_plugin.h
kernel/rcutree_trace.c
kernel/sched/core.c
kernel/sched/cpupri.c
kernel/sched/fair.c
kernel/time/clockevents.c
kernel/time/jiffies.c
kernel/time/ntp.c
kernel/time/timekeeping.c
kernel/trace/trace_event_perf.c
kernel/trace/trace_kprobe.c
kernel/trace/trace_syscalls.c
kernel/trace/trace_uprobe.c
kernel/watchdog.c
kernel/workqueue.c
lib/Kconfig.debug
mm/backing-dev.c
mm/filemap.c
mm/frontswap.c
mm/kmemleak.c
mm/page-writeback.c
mm/slab.c
mm/slab_common.c
mm/slub.c
net/8021q/vlan_dev.c
net/atm/common.c
net/atm/pvc.c
net/batman-adv/gateway_client.c
net/batman-adv/translation-table.c
net/bluetooth/a2mp.c
net/bluetooth/af_bluetooth.c
net/bluetooth/bnep/sock.c
net/bluetooth/cmtp/sock.c
net/bluetooth/hci_conn.c
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/hci_sock.c
net/bluetooth/hidp/sock.c
net/bluetooth/l2cap_core.c
net/bluetooth/l2cap_sock.c
net/bluetooth/mgmt.c
net/bluetooth/rfcomm/sock.c
net/bluetooth/rfcomm/tty.c
net/bluetooth/sco.c
net/bluetooth/smp.c
net/bridge/br_device.c
net/bridge/br_fdb.c
net/bridge/br_forward.c
net/bridge/br_if.c
net/bridge/br_private.h
net/bridge/br_stp_timer.c
net/core/dev.c
net/core/dst.c
net/core/netpoll.c
net/core/netprio_cgroup.c
net/core/rtnetlink.c
net/core/scm.c
net/core/sock.c
net/dccp/ccid.h
net/dccp/ccids/ccid3.c
net/decnet/dn_route.c
net/ipv4/af_inet.c
net/ipv4/devinet.c
net/ipv4/fib_frontend.c
net/ipv4/fib_trie.c
net/ipv4/igmp.c
net/ipv4/ip_output.c
net/ipv4/ipmr.c
net/ipv4/netfilter/ipt_rpfilter.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/tcp_metrics.c
net/ipv4/tcp_minisocks.c
net/ipv4/tcp_output.c
net/ipv4/udp.c
net/ipv6/Kconfig
net/ipv6/Makefile
net/ipv6/addrconf.c
net/ipv6/ip6_gre.c [new file with mode: 0644]
net/ipv6/ip6_tunnel.c
net/ipv6/proc.c
net/ipv6/route.c
net/ipv6/tcp_ipv6.c
net/irda/ircomm/ircomm_param.c
net/irda/ircomm/ircomm_tty.c
net/irda/ircomm/ircomm_tty_attach.c
net/irda/ircomm/ircomm_tty_ioctl.c
net/key/af_key.c
net/l2tp/l2tp_ip6.c
net/llc/af_llc.c
net/llc/llc_input.c
net/llc/llc_station.c
net/mac80211/mesh.c
net/mac80211/mesh.h
net/mac80211/mesh_plink.c
net/mac80211/mlme.c
net/mac80211/scan.c
net/netfilter/ipvs/ip_vs_ctl.c
net/packet/Kconfig
net/packet/Makefile
net/packet/af_packet.c
net/packet/diag.c [new file with mode: 0644]
net/packet/internal.h [new file with mode: 0644]
net/rfkill/input.c
net/sched/act_gact.c
net/sched/act_ipt.c
net/sched/act_mirred.c
net/sched/act_pedit.c
net/sched/act_simple.c
net/sched/sch_generic.c
net/sched/sch_qfq.c
net/sctp/associola.c
net/sctp/auth.c
net/sctp/bind_addr.c
net/sctp/chunk.c
net/sctp/endpointola.c
net/sctp/input.c
net/sctp/ipv6.c
net/sctp/objcnt.c
net/sctp/output.c
net/sctp/outqueue.c
net/sctp/primitive.c
net/sctp/proc.c
net/sctp/protocol.c
net/sctp/sm_make_chunk.c
net/sctp/sm_sideeffect.c
net/sctp/sm_statefuns.c
net/sctp/sm_statetable.c
net/sctp/socket.c
net/sctp/sysctl.c
net/sctp/transport.c
net/sctp/ulpqueue.c
net/socket.c
net/wireless/core.c
net/wireless/core.h
net/wireless/reg.c
net/wireless/util.c
net/xfrm/xfrm_policy.c
net/xfrm/xfrm_state.c
net/xfrm/xfrm_user.c
samples/seccomp/bpf-helper.h
scripts/decodecode
scripts/kconfig/Makefile
scripts/kconfig/streamline_config.pl
security/yama/yama_lsm.c
sound/arm/pxa2xx-ac97.c
sound/atmel/abdac.c
sound/atmel/ac97c.c
sound/core/sgbuf.c
sound/drivers/aloop.c
sound/drivers/dummy.c
sound/drivers/pcsp/pcsp.c
sound/isa/gus/interwave.c
sound/isa/opti9xx/miro.c
sound/isa/opti9xx/opti92x-ad1848.c
sound/pci/ali5451/ali5451.c
sound/pci/als300.c
sound/pci/als4000.c
sound/pci/asihpi/asihpi.c
sound/pci/atiixp.c
sound/pci/atiixp_modem.c
sound/pci/azt3328.c
sound/pci/ca0106/ca0106.h
sound/pci/ca0106/ca0106_main.c
sound/pci/ca0106/ca0106_mixer.c
sound/pci/cmipci.c
sound/pci/cs4281.c
sound/pci/cs46xx/cs46xx.c
sound/pci/cs46xx/cs46xx.h
sound/pci/cs46xx/cs46xx_lib.c
sound/pci/cs46xx/cs46xx_lib.h
sound/pci/cs46xx/dsp_spos.c
sound/pci/cs46xx/dsp_spos_scb_lib.c
sound/pci/cs5535audio/Makefile
sound/pci/cs5535audio/cs5535audio.c
sound/pci/ctxfi/ctatc.c
sound/pci/ctxfi/ctatc.h
sound/pci/ctxfi/cthardware.h
sound/pci/ctxfi/cthw20k1.c
sound/pci/ctxfi/cthw20k2.c
sound/pci/ctxfi/ctmixer.c
sound/pci/ctxfi/ctmixer.h
sound/pci/ctxfi/ctpcm.c
sound/pci/ctxfi/xfi.c
sound/pci/echoaudio/echoaudio.c
sound/pci/echoaudio/echoaudio.h
sound/pci/emu10k1/emu10k1.c
sound/pci/emu10k1/emu10k1_main.c
sound/pci/emu10k1/emufx.c
sound/pci/emu10k1/memory.c
sound/pci/emu10k1/p16v.c
sound/pci/ens1370.c
sound/pci/es1938.c
sound/pci/es1968.c
sound/pci/fm801.c
sound/pci/hda/hda_auto_parser.c
sound/pci/hda/hda_beep.c
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_hwdep.c
sound/pci/hda/hda_intel.c
sound/pci/hda/hda_proc.c
sound/pci/hda/patch_analog.c
sound/pci/hda/patch_conexant.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/hda/patch_via.c
sound/pci/ice1712/aureon.c
sound/pci/ice1712/ice1712.h
sound/pci/ice1712/ice1724.c
sound/pci/ice1712/juli.c
sound/pci/ice1712/prodigy_hifi.c
sound/pci/intel8x0.c
sound/pci/intel8x0m.c
sound/pci/lx6464es/lx6464es.c
sound/pci/maestro3.c
sound/pci/nm256/nm256.c
sound/pci/oxygen/oxygen.c
sound/pci/oxygen/oxygen.h
sound/pci/oxygen/oxygen_lib.c
sound/pci/oxygen/virtuoso.c
sound/pci/riptide/riptide.c
sound/pci/sis7019.c
sound/pci/trident/trident.c
sound/pci/trident/trident_main.c
sound/pci/via82xx.c
sound/pci/via82xx_modem.c
sound/pci/vx222/vx222.c
sound/pci/ymfpci/ymfpci.c
sound/pci/ymfpci/ymfpci.h
sound/pci/ymfpci/ymfpci_main.c
sound/ppc/powermac.c
sound/soc/blackfin/bf6xx-sport.c
sound/soc/codecs/ab8500-codec.c
sound/soc/codecs/ad1980.c
sound/soc/codecs/adau1373.c
sound/soc/codecs/adau1701.c
sound/soc/codecs/ak4671.c
sound/soc/codecs/arizona.c
sound/soc/codecs/arizona.h
sound/soc/codecs/cs4270.c
sound/soc/codecs/cs42l51.c
sound/soc/codecs/cs42l52.c
sound/soc/codecs/isabelle.c
sound/soc/codecs/lm4857.c
sound/soc/codecs/max98088.c
sound/soc/codecs/max98095.c
sound/soc/codecs/max9850.c
sound/soc/codecs/max9877.c
sound/soc/codecs/mc13783.c
sound/soc/codecs/sgtl5000.c
sound/soc/codecs/sta32x.c
sound/soc/codecs/sta529.c
sound/soc/codecs/stac9766.c
sound/soc/codecs/tlv320aic32x4.c
sound/soc/codecs/tlv320aic3x.c
sound/soc/codecs/tlv320dac33.c
sound/soc/codecs/tpa6130a2.c
sound/soc/codecs/wm2000.c
sound/soc/codecs/wm2200.c
sound/soc/codecs/wm5102.c
sound/soc/codecs/wm5110.c
sound/soc/codecs/wm8903.c
sound/soc/codecs/wm8940.c
sound/soc/codecs/wm8955.c
sound/soc/codecs/wm8958-dsp2.c
sound/soc/codecs/wm8960.c
sound/soc/codecs/wm8961.c
sound/soc/codecs/wm8962.c
sound/soc/codecs/wm8971.c
sound/soc/codecs/wm8974.c
sound/soc/codecs/wm8978.c
sound/soc/codecs/wm8991.c
sound/soc/codecs/wm8994.c
sound/soc/codecs/wm8994.h
sound/soc/codecs/wm9090.c
sound/soc/codecs/wm9712.c
sound/soc/codecs/wm9713.c
sound/soc/codecs/wm_hubs.c
sound/soc/codecs/wm_hubs.h
sound/soc/davinci/davinci-evm.c
sound/soc/davinci/davinci-mcasp.c
sound/soc/davinci/davinci-mcasp.h
sound/soc/fsl/imx-ssi.c
sound/soc/mxs/Kconfig
sound/soc/mxs/mxs-saif.c
sound/soc/omap/mcbsp.c
sound/soc/omap/omap-abe-twl6040.c
sound/soc/omap/omap-mcbsp.c
sound/soc/omap/omap-mcpdm.c
sound/soc/omap/omap-pcm.c
sound/soc/samsung/Kconfig
sound/soc/samsung/Makefile
sound/soc/samsung/bells.c [new file with mode: 0644]
sound/soc/samsung/pcm.c
sound/soc/soc-core.c
sound/soc/soc-jack.c
sound/soc/tegra/tegra_alc5632.c
sound/soc/tegra/tegra_wm8903.c
sound/soc/ux500/ux500_msp_dai.c
sound/soc/ux500/ux500_msp_i2s.c
sound/soc/ux500/ux500_msp_i2s.h
sound/usb/6fire/firmware.c
sound/usb/endpoint.c
sound/usb/pcm.c
tools/kvm/.gitignore [new file with mode: 0644]
tools/kvm/CREDITS-Git [new file with mode: 0644]
tools/kvm/Documentation/kernel-debugging.txt [new file with mode: 0644]
tools/kvm/Documentation/kvm-balloon.txt [new file with mode: 0644]
tools/kvm/Documentation/kvm-debug.txt [new file with mode: 0644]
tools/kvm/Documentation/kvm-list.txt [new file with mode: 0644]
tools/kvm/Documentation/kvm-pause.txt [new file with mode: 0644]
tools/kvm/Documentation/kvm-resume.txt [new file with mode: 0644]
tools/kvm/Documentation/kvm-run.txt [new file with mode: 0644]
tools/kvm/Documentation/kvm-sandbox.txt [new file with mode: 0644]
tools/kvm/Documentation/kvm-setup.txt [new file with mode: 0644]
tools/kvm/Documentation/kvm-stat.txt [new file with mode: 0644]
tools/kvm/Documentation/kvm-stop.txt [new file with mode: 0644]
tools/kvm/Documentation/kvm-version.txt [new file with mode: 0644]
tools/kvm/Documentation/virtio-console.txt [new file with mode: 0644]
tools/kvm/Makefile [new file with mode: 0644]
tools/kvm/README [new file with mode: 0644]
tools/kvm/builtin-balloon.c [new file with mode: 0644]
tools/kvm/builtin-debug.c [new file with mode: 0644]
tools/kvm/builtin-help.c [new file with mode: 0644]
tools/kvm/builtin-list.c [new file with mode: 0644]
tools/kvm/builtin-pause.c [new file with mode: 0644]
tools/kvm/builtin-resume.c [new file with mode: 0644]
tools/kvm/builtin-run.c [new file with mode: 0644]
tools/kvm/builtin-sandbox.c [new file with mode: 0644]
tools/kvm/builtin-setup.c [new file with mode: 0644]
tools/kvm/builtin-stat.c [new file with mode: 0644]
tools/kvm/builtin-stop.c [new file with mode: 0644]
tools/kvm/builtin-version.c [new file with mode: 0644]
tools/kvm/code16gcc.h [new file with mode: 0644]
tools/kvm/command-list.txt [new file with mode: 0644]
tools/kvm/config/feature-tests.mak [new file with mode: 0644]
tools/kvm/config/utilities.mak [new file with mode: 0644]
tools/kvm/disk/blk.c [new file with mode: 0644]
tools/kvm/disk/core.c [new file with mode: 0644]
tools/kvm/disk/qcow.c [new file with mode: 0644]
tools/kvm/disk/raw.c [new file with mode: 0644]
tools/kvm/framebuffer.c [new file with mode: 0644]
tools/kvm/guest/init.c [new file with mode: 0644]
tools/kvm/guest/init_stage2.c [new file with mode: 0644]
tools/kvm/guest/passwd [new file with mode: 0644]
tools/kvm/guest_compat.c [new file with mode: 0644]
tools/kvm/hw/i8042.c [new file with mode: 0644]
tools/kvm/hw/pci-shmem.c [new file with mode: 0644]
tools/kvm/hw/rtc.c [new file with mode: 0644]
tools/kvm/hw/serial.c [new file with mode: 0644]
tools/kvm/hw/vesa.c [new file with mode: 0644]
tools/kvm/include/asm/hweight.h [new file with mode: 0644]
tools/kvm/include/bios/memcpy.h [new file with mode: 0644]
tools/kvm/include/kvm/8250-serial.h [new file with mode: 0644]
tools/kvm/include/kvm/apic.h [new file with mode: 0644]
tools/kvm/include/kvm/brlock.h [new file with mode: 0644]
tools/kvm/include/kvm/builtin-balloon.h [new file with mode: 0644]
tools/kvm/include/kvm/builtin-debug.h [new file with mode: 0644]
tools/kvm/include/kvm/builtin-help.h [new file with mode: 0644]
tools/kvm/include/kvm/builtin-list.h [new file with mode: 0644]
tools/kvm/include/kvm/builtin-pause.h [new file with mode: 0644]
tools/kvm/include/kvm/builtin-resume.h [new file with mode: 0644]
tools/kvm/include/kvm/builtin-run.h [new file with mode: 0644]
tools/kvm/include/kvm/builtin-sandbox.h [new file with mode: 0644]
tools/kvm/include/kvm/builtin-setup.h [new file with mode: 0644]
tools/kvm/include/kvm/builtin-stat.h [new file with mode: 0644]
tools/kvm/include/kvm/builtin-stop.h [new file with mode: 0644]
tools/kvm/include/kvm/builtin-version.h [new file with mode: 0644]
tools/kvm/include/kvm/compiler.h [new file with mode: 0644]
tools/kvm/include/kvm/disk-image.h [new file with mode: 0644]
tools/kvm/include/kvm/e820.h [new file with mode: 0644]
tools/kvm/include/kvm/framebuffer.h [new file with mode: 0644]
tools/kvm/include/kvm/guest_compat.h [new file with mode: 0644]
tools/kvm/include/kvm/i8042.h [new file with mode: 0644]
tools/kvm/include/kvm/ioeventfd.h [new file with mode: 0644]
tools/kvm/include/kvm/ioport.h [new file with mode: 0644]
tools/kvm/include/kvm/irq.h [new file with mode: 0644]
tools/kvm/include/kvm/kvm-cmd.h [new file with mode: 0644]
tools/kvm/include/kvm/kvm-cpu.h [new file with mode: 0644]
tools/kvm/include/kvm/kvm-ipc.h [new file with mode: 0644]
tools/kvm/include/kvm/kvm.h [new file with mode: 0644]
tools/kvm/include/kvm/msi.h [new file with mode: 0644]
tools/kvm/include/kvm/mutex.h [new file with mode: 0644]
tools/kvm/include/kvm/parse-options.h [new file with mode: 0644]
tools/kvm/include/kvm/pci-shmem.h [new file with mode: 0644]
tools/kvm/include/kvm/pci.h [new file with mode: 0644]
tools/kvm/include/kvm/qcow.h [new file with mode: 0644]
tools/kvm/include/kvm/rbtree-interval.h [new file with mode: 0644]
tools/kvm/include/kvm/read-write.h [new file with mode: 0644]
tools/kvm/include/kvm/rtc.h [new file with mode: 0644]
tools/kvm/include/kvm/rwsem.h [new file with mode: 0644]
tools/kvm/include/kvm/sdl.h [new file with mode: 0644]
tools/kvm/include/kvm/segment.h [new file with mode: 0644]
tools/kvm/include/kvm/strbuf.h [new file with mode: 0644]
tools/kvm/include/kvm/symbol.h [new file with mode: 0644]
tools/kvm/include/kvm/term.h [new file with mode: 0644]
tools/kvm/include/kvm/threadpool.h [new file with mode: 0644]
tools/kvm/include/kvm/types.h [new file with mode: 0644]
tools/kvm/include/kvm/uip.h [new file with mode: 0644]
tools/kvm/include/kvm/util.h [new file with mode: 0644]
tools/kvm/include/kvm/vesa.h [new file with mode: 0644]
tools/kvm/include/kvm/virtio-9p.h [new file with mode: 0644]
tools/kvm/include/kvm/virtio-balloon.h [new file with mode: 0644]
tools/kvm/include/kvm/virtio-blk.h [new file with mode: 0644]
tools/kvm/include/kvm/virtio-console.h [new file with mode: 0644]
tools/kvm/include/kvm/virtio-mmio.h [new file with mode: 0644]
tools/kvm/include/kvm/virtio-net.h [new file with mode: 0644]
tools/kvm/include/kvm/virtio-pci-dev.h [new file with mode: 0644]
tools/kvm/include/kvm/virtio-pci.h [new file with mode: 0644]
tools/kvm/include/kvm/virtio-rng.h [new file with mode: 0644]
tools/kvm/include/kvm/virtio.h [new file with mode: 0644]
tools/kvm/include/kvm/vnc.h [new file with mode: 0644]
tools/kvm/include/linux/bitops.h [new file with mode: 0644]
tools/kvm/include/linux/byteorder.h [new file with mode: 0644]
tools/kvm/include/linux/compiler.h [new file with mode: 0644]
tools/kvm/include/linux/kernel.h [new file with mode: 0644]
tools/kvm/include/linux/module.h [new file with mode: 0644]
tools/kvm/include/linux/prefetch.h [new file with mode: 0644]
tools/kvm/include/linux/stddef.h [new file with mode: 0644]
tools/kvm/include/linux/types.h [new file with mode: 0644]
tools/kvm/ioeventfd.c [new file with mode: 0644]
tools/kvm/ioport.c [new file with mode: 0644]
tools/kvm/kvm-cmd.c [new file with mode: 0644]
tools/kvm/kvm-cpu.c [new file with mode: 0644]
tools/kvm/kvm-ipc.c [new file with mode: 0644]
tools/kvm/kvm.c [new file with mode: 0644]
tools/kvm/main.c [new file with mode: 0644]
tools/kvm/mmio.c [new file with mode: 0644]
tools/kvm/net/uip/arp.c [new file with mode: 0644]
tools/kvm/net/uip/buf.c [new file with mode: 0644]
tools/kvm/net/uip/core.c [new file with mode: 0644]
tools/kvm/net/uip/csum.c [new file with mode: 0644]
tools/kvm/net/uip/dhcp.c [new file with mode: 0644]
tools/kvm/net/uip/icmp.c [new file with mode: 0644]
tools/kvm/net/uip/ipv4.c [new file with mode: 0644]
tools/kvm/net/uip/tcp.c [new file with mode: 0644]
tools/kvm/net/uip/udp.c [new file with mode: 0644]
tools/kvm/pci.c [new file with mode: 0644]
tools/kvm/powerpc/boot.c [new file with mode: 0644]
tools/kvm/powerpc/cpu_info.c [new file with mode: 0644]
tools/kvm/powerpc/cpu_info.h [new file with mode: 0644]
tools/kvm/powerpc/include/kvm/barrier.h [new file with mode: 0644]
tools/kvm/powerpc/include/kvm/kvm-arch.h [new file with mode: 0644]
tools/kvm/powerpc/include/kvm/kvm-cpu-arch.h [new file with mode: 0644]
tools/kvm/powerpc/ioport.c [new file with mode: 0644]
tools/kvm/powerpc/irq.c [new file with mode: 0644]
tools/kvm/powerpc/kvm-cpu.c [new file with mode: 0644]
tools/kvm/powerpc/kvm.c [new file with mode: 0644]
tools/kvm/powerpc/spapr.h [new file with mode: 0644]
tools/kvm/powerpc/spapr_hcall.c [new file with mode: 0644]
tools/kvm/powerpc/spapr_hvcons.c [new file with mode: 0644]
tools/kvm/powerpc/spapr_hvcons.h [new file with mode: 0644]
tools/kvm/powerpc/spapr_pci.c [new file with mode: 0644]
tools/kvm/powerpc/spapr_pci.h [new file with mode: 0644]
tools/kvm/powerpc/spapr_rtas.c [new file with mode: 0644]
tools/kvm/powerpc/xics.c [new file with mode: 0644]
tools/kvm/powerpc/xics.h [new file with mode: 0644]
tools/kvm/symbol.c [new file with mode: 0644]
tools/kvm/term.c [new file with mode: 0644]
tools/kvm/tests/Makefile [new file with mode: 0644]
tools/kvm/tests/boot/Makefile [new file with mode: 0644]
tools/kvm/tests/boot/init.c [new file with mode: 0644]
tools/kvm/tests/kernel/.gitignore [new file with mode: 0644]
tools/kvm/tests/kernel/Makefile [new file with mode: 0644]
tools/kvm/tests/kernel/README [new file with mode: 0644]
tools/kvm/tests/kernel/kernel.S [new file with mode: 0644]
tools/kvm/tests/pit/.gitignore [new file with mode: 0644]
tools/kvm/tests/pit/Makefile [new file with mode: 0644]
tools/kvm/tests/pit/README [new file with mode: 0644]
tools/kvm/tests/pit/tick.S [new file with mode: 0644]
tools/kvm/ui/sdl.c [new file with mode: 0644]
tools/kvm/ui/vnc.c [new file with mode: 0644]
tools/kvm/util/KVMTOOLS-VERSION-GEN [new file with mode: 0755]
tools/kvm/util/generate-cmdlist.sh [new file with mode: 0755]
tools/kvm/util/kvm-ifup-vbr0 [new file with mode: 0755]
tools/kvm/util/parse-options.c [new file with mode: 0644]
tools/kvm/util/rbtree-interval.c [new file with mode: 0644]
tools/kvm/util/read-write.c [new file with mode: 0644]
tools/kvm/util/set_private_br.sh [new file with mode: 0755]
tools/kvm/util/strbuf.c [new file with mode: 0644]
tools/kvm/util/threadpool.c [new file with mode: 0644]
tools/kvm/util/util.c [new file with mode: 0644]
tools/kvm/virtio/9p-pdu.c [new file with mode: 0644]
tools/kvm/virtio/9p.c [new file with mode: 0644]
tools/kvm/virtio/balloon.c [new file with mode: 0644]
tools/kvm/virtio/blk.c [new file with mode: 0644]
tools/kvm/virtio/console.c [new file with mode: 0644]
tools/kvm/virtio/core.c [new file with mode: 0644]
tools/kvm/virtio/mmio.c [new file with mode: 0644]
tools/kvm/virtio/net.c [new file with mode: 0644]
tools/kvm/virtio/pci.c [new file with mode: 0644]
tools/kvm/virtio/rng.c [new file with mode: 0644]
tools/kvm/x86/bios.c [new file with mode: 0644]
tools/kvm/x86/bios/.gitignore [new file with mode: 0644]
tools/kvm/x86/bios/bios-rom.S [new file with mode: 0644]
tools/kvm/x86/bios/e820.c [new file with mode: 0644]
tools/kvm/x86/bios/entry.S [new file with mode: 0644]
tools/kvm/x86/bios/gen-offsets.sh [new file with mode: 0644]
tools/kvm/x86/bios/int10.c [new file with mode: 0644]
tools/kvm/x86/bios/int15.c [new file with mode: 0644]
tools/kvm/x86/bios/local.S [new file with mode: 0644]
tools/kvm/x86/bios/macro.S [new file with mode: 0644]
tools/kvm/x86/bios/memcpy.c [new file with mode: 0644]
tools/kvm/x86/bios/rom.ld.S [new file with mode: 0644]
tools/kvm/x86/boot.c [new file with mode: 0644]
tools/kvm/x86/cpuid.c [new file with mode: 0644]
tools/kvm/x86/include/kvm/assembly.h [new file with mode: 0644]
tools/kvm/x86/include/kvm/barrier.h [new file with mode: 0644]
tools/kvm/x86/include/kvm/bios-export.h [new file with mode: 0644]
tools/kvm/x86/include/kvm/bios.h [new file with mode: 0644]
tools/kvm/x86/include/kvm/boot-protocol.h [new file with mode: 0644]
tools/kvm/x86/include/kvm/cpufeature.h [new file with mode: 0644]
tools/kvm/x86/include/kvm/interrupt.h [new file with mode: 0644]
tools/kvm/x86/include/kvm/kvm-arch.h [new file with mode: 0644]
tools/kvm/x86/include/kvm/kvm-cpu-arch.h [new file with mode: 0644]
tools/kvm/x86/include/kvm/mptable.h [new file with mode: 0644]
tools/kvm/x86/interrupt.c [new file with mode: 0644]
tools/kvm/x86/ioport.c [new file with mode: 0644]
tools/kvm/x86/irq.c [new file with mode: 0644]
tools/kvm/x86/kvm-cpu.c [new file with mode: 0644]
tools/kvm/x86/kvm.c [new file with mode: 0644]
tools/kvm/x86/mptable.c [new file with mode: 0644]
tools/perf/Makefile
tools/perf/builtin-record.c
tools/perf/builtin-report.c
tools/perf/builtin-test.c
tools/perf/builtin-top.c
tools/perf/util/event.h
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/intlist.c [new file with mode: 0644]
tools/perf/util/intlist.h [new file with mode: 0644]
tools/perf/util/parse-events-test.c
tools/perf/util/parse-options.c
tools/perf/util/python.c
tools/perf/util/rblist.c [new file with mode: 0644]
tools/perf/util/rblist.h [new file with mode: 0644]
tools/perf/util/session.c
tools/perf/util/session.h
tools/perf/util/strlist.c
tools/perf/util/strlist.h
tools/perf/util/symbol.c
tools/perf/util/target.c
virt/kvm/Kconfig
virt/kvm/async_pf.c
virt/kvm/iommu.c
virt/kvm/irq_comm.c
virt/kvm/kvm_main.c

index 8d55a83d6921d1b8779ba72430587be42856826c..7fc781048b799a2f32bed2775d2f1fc97e8534ec 100644 (file)
@@ -1,3 +1,16 @@
+WWhat:         /sys/class/hidraw/hidraw*/device/oled*_img
+Date:          June 2012
+Contact:       linux-bluetooth@vger.kernel.org
+Description:
+               The /sys/class/hidraw/hidraw*/device/oled*_img files control
+               OLED mocro displays on Intuos4 Wireless tablet. Accepted image
+               has to contain 256 bytes (64x32 px 1 bit colour). The format
+               is the same as PBM image 62x32px without header (64 bits per
+               horizontal line, 32 lines). An example of setting OLED No. 0:
+               dd bs=256 count=1 if=img_file of=[path to oled0_img]/oled0_img
+               The attribute is read only and no local copy of the image is
+               stored.
+
 What:          /sys/class/hidraw/hidraw*/device/speed
 Date:          April 2010
 Kernel Version:        2.6.35
index 3fca32c41927130dae636a93504d7d8aacdee90e..25b58efd955dd2bebf2d716aea851fe283f792c1 100644 (file)
@@ -224,8 +224,8 @@ all your transactions.
 </para>
 
 <para>
-Then at umount time , in your put_super() (2.4) or write_super() (2.5)
-you can then call journal_destroy() to clean up your in-core journal object.
+Then at umount time , in your put_super() you can then call journal_destroy()
+to clean up your in-core journal object.
 </para>
 
 <para>
index d64386237207a9f27867fd6e9bee02620ff4c8bb..a7ea56c71a27cc5cebcfd6ea91b8d17dfa9432c4 100644 (file)
@@ -1,12 +1,16 @@
 <title>DVB Audio Device</title>
 <para>The DVB audio device controls the MPEG2 audio decoder of the DVB hardware. It
 can be accessed through <emphasis role="tt">/dev/dvb/adapter0/audio0</emphasis>. Data types and and
-ioctl definitions can be accessed by including <emphasis role="tt">linux/dvb/video.h</emphasis> in your
+ioctl definitions can be accessed by including <emphasis role="tt">linux/dvb/audio.h</emphasis> in your
 application.
 </para>
 <para>Please note that some DVB cards don&#8217;t have their own MPEG decoder, which results in
 the omission of the audio and video device.
 </para>
+<para>
+These ioctls were also used by V4L2 to control MPEG decoders implemented in V4L2. The use
+of these ioctls for that purpose has been made obsolete and proper V4L2 ioctls or controls
+have been created to replace that functionality.</para>
 
 <section id="audio_data_types">
 <title>Audio Data Types</title>
@@ -558,6 +562,8 @@ role="subsection"><title>AUDIO_SELECT_SOURCE</title>
 role="subsection"><title>AUDIO_SET_MUTE</title>
 <para>DESCRIPTION
 </para>
+<para>This ioctl is for DVB devices only. To control a V4L2 decoder use the V4L2
+&VIDIOC-DECODER-CMD; with the <constant>V4L2_DEC_CMD_START_MUTE_AUDIO</constant> flag instead.</para>
 <informaltable><tgroup cols="1"><tbody><row><entry
  align="char">
 <para>This ioctl call asks the audio device to mute the stream that is currently being
@@ -730,6 +736,8 @@ role="subsection"><title>AUDIO_SET_BYPASS_MODE</title>
 role="subsection"><title>AUDIO_CHANNEL_SELECT</title>
 <para>DESCRIPTION
 </para>
+<para>This ioctl is for DVB devices only. To control a V4L2 decoder use the V4L2
+<constant>V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK</constant> control instead.</para>
 <informaltable><tgroup cols="1"><tbody><row><entry
  align="char">
 <para>This ioctl call asks the Audio Device to select the requested channel if possible.</para>
@@ -772,6 +780,109 @@ role="subsection"><title>AUDIO_CHANNEL_SELECT</title>
  </row></tbody></tgroup></informaltable>
 &return-value-dvb;
 
+</section><section id="AUDIO_BILINGUAL_CHANNEL_SELECT"
+role="subsection"><title>AUDIO_BILINGUAL_CHANNEL_SELECT</title>
+<para>DESCRIPTION
+</para>
+<para>This ioctl is obsolete. Do not use in new drivers. It has been replaced by
+the V4L2 <constant>V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK</constant> control
+for MPEG decoders controlled through V4L2.</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call asks the Audio Device to select the requested channel for bilingual streams if possible.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request =
+ AUDIO_BILINGUAL_CHANNEL_SELECT, audio_channel_select_t);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals AUDIO_BILINGUAL_CHANNEL_SELECT for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>audio_channel_select_t
+ch</para>
+</entry><entry
+ align="char">
+<para>Select the output format of the audio (mono left/right,
+ stereo).</para>
+</entry>
+ </row>
+</tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="AUDIO_GET_PTS"
+role="subsection"><title>AUDIO_GET_PTS</title>
+<para>DESCRIPTION
+</para>
+<para>This ioctl is obsolete. Do not use in new drivers. If you need this functionality,
+then please contact the linux-media mailing list (&v4l-ml;).</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call asks the Audio Device to return the current PTS timestamp.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request =
+ AUDIO_GET_PTS, __u64 *pts);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals AUDIO_GET_PTS for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>__u64 *pts
+</para>
+</entry><entry
+ align="char">
+<para>Returns the 33-bit timestamp as defined in ITU T-REC-H.222.0 / ISO/IEC 13818-1.
+</para>
+<para>
+The PTS should belong to the currently played
+frame if possible, but may also be a value close to it
+like the PTS of the last decoded frame or the last PTS
+extracted by the PES parser.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
 </section><section id="AUDIO_GET_STATUS"
 role="subsection"><title>AUDIO_GET_STATUS</title>
 <para>DESCRIPTION
index 5c4adb44b1c18a4207ac993132e823c83cac6624..85eaf4fe2931fc96cea50ba2d502a401d475c22c 100644 (file)
@@ -226,4 +226,357 @@ typedef struct ca_pid {
 </entry>
  </row></tbody></tgroup></informaltable>
  </section>
+
+<section id="CA_RESET"
+role="subsection"><title>CA_RESET</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = CA_RESET);
+</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals CA_RESET for this command.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="CA_GET_CAP"
+role="subsection"><title>CA_GET_CAP</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = CA_GET_CAP,
+ ca_caps_t *);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals CA_GET_CAP for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>ca_caps_t *
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="CA_GET_SLOT_INFO"
+role="subsection"><title>CA_GET_SLOT_INFO</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = CA_GET_SLOT_INFO,
+ ca_slot_info_t *);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals CA_GET_SLOT_INFO for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>ca_slot_info_t *
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="CA_GET_DESCR_INFO"
+role="subsection"><title>CA_GET_DESCR_INFO</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = CA_GET_DESCR_INFO,
+ ca_descr_info_t *);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals CA_GET_DESCR_INFO for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>ca_descr_info_t *
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="CA_GET_MSG"
+role="subsection"><title>CA_GET_MSG</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = CA_GET_MSG,
+ ca_msg_t *);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals CA_GET_MSG for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>ca_msg_t *
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="CA_SEND_MSG"
+role="subsection"><title>CA_SEND_MSG</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = CA_SEND_MSG,
+ ca_msg_t *);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals CA_SEND_MSG for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>ca_msg_t *
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="CA_SET_DESCR"
+role="subsection"><title>CA_SET_DESCR</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = CA_SET_DESCR,
+ ca_descr_t *);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals CA_SET_DESCR for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>ca_descr_t *
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="CA_SET_PID"
+role="subsection"><title>CA_SET_PID</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = CA_SET_PID,
+ ca_pid_t *);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals CA_SET_PID for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>ca_pid_t *
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
 </section>
index 37c17908aa400acd225881af1acb5383e6221442..86de89cfbd676cbeda054aba040432e25c4f68d3 100644 (file)
@@ -899,4 +899,232 @@ typedef enum {
 <para>Invalid stc number.</para>
 </entry>
  </row></tbody></tgroup></informaltable>
- </section></section>
+ </section>
+
+<section id="DMX_GET_PES_PIDS"
+role="subsection"><title>DMX_GET_PES_PIDS</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = DMX_GET_PES_PIDS,
+ __u16[5]);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals DMX_GET_PES_PIDS for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>__u16[5]
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="DMX_GET_CAPS"
+role="subsection"><title>DMX_GET_CAPS</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = DMX_GET_CAPS,
+ dmx_caps_t *);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals DMX_GET_CAPS for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>dmx_caps_t *
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="DMX_SET_SOURCE"
+role="subsection"><title>DMX_SET_SOURCE</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = DMX_SET_SOURCE,
+ dmx_source_t *);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals DMX_SET_SOURCE for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>dmx_source_t *
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="DMX_ADD_PID"
+role="subsection"><title>DMX_ADD_PID</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = DMX_ADD_PID,
+ __u16 *);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals DMX_ADD_PID for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>__u16 *
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="DMX_REMOVE_PID"
+role="subsection"><title>DMX_REMOVE_PID</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = DMX_REMOVE_PID,
+ __u16 *);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals DMX_REMOVE_PID for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>__u16 *
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+
+</section>
index 2ab6ddcfc4e095dada4e2e6eb8084003096c279a..d36f8f93c4ff0c01939b96b2d25631858099b0fe 100644 (file)
@@ -28,7 +28,7 @@
        <holder>Convergence GmbH</holder>
 </copyright>
 <copyright>
-       <year>2009-2011</year>
+       <year>2009-2012</year>
        <holder>Mauro Carvalho Chehab</holder>
 </copyright>
 
index e633c097a8d14b954975743e67816867f5b9fdaa..bb4777a2cd90b2f8897eb93f959a6893074b2e2e 100644 (file)
@@ -567,28 +567,33 @@ typedef enum fe_delivery_system {
                        <title><constant>DTV_ATSCMH_RS_FRAME_MODE</constant></title>
                        <para>RS frame mode.</para>
                        <para>Possible values are:</para>
+                 <section id="atscmh-rs-frame-mode">
 <programlisting>
 typedef enum atscmh_rs_frame_mode {
        ATSCMH_RSFRAME_PRI_ONLY  = 0,
        ATSCMH_RSFRAME_PRI_SEC   = 1,
 } atscmh_rs_frame_mode_t;
 </programlisting>
+                 </section>
                </section>
                <section id="DTV-ATSCMH-RS-FRAME-ENSEMBLE">
                        <title><constant>DTV_ATSCMH_RS_FRAME_ENSEMBLE</constant></title>
                        <para>RS frame ensemble.</para>
                        <para>Possible values are:</para>
+                 <section id="atscmh-rs-frame-ensemble">
 <programlisting>
 typedef enum atscmh_rs_frame_ensemble {
        ATSCMH_RSFRAME_ENS_PRI   = 0,
        ATSCMH_RSFRAME_ENS_SEC   = 1,
 } atscmh_rs_frame_ensemble_t;
 </programlisting>
+                 </section>
                </section>
                <section id="DTV-ATSCMH-RS-CODE-MODE-PRI">
                        <title><constant>DTV_ATSCMH_RS_CODE_MODE_PRI</constant></title>
                        <para>RS code mode (primary).</para>
                        <para>Possible values are:</para>
+                 <section id="atscmh-rs-code-mode">
 <programlisting>
 typedef enum atscmh_rs_code_mode {
        ATSCMH_RSCODE_211_187    = 0,
@@ -596,6 +601,7 @@ typedef enum atscmh_rs_code_mode {
        ATSCMH_RSCODE_235_187    = 2,
 } atscmh_rs_code_mode_t;
 </programlisting>
+                 </section>
                </section>
                <section id="DTV-ATSCMH-RS-CODE-MODE-SEC">
                        <title><constant>DTV_ATSCMH_RS_CODE_MODE_SEC</constant></title>
@@ -613,23 +619,27 @@ typedef enum atscmh_rs_code_mode {
                        <title><constant>DTV_ATSCMH_SCCC_BLOCK_MODE</constant></title>
                        <para>Series Concatenated Convolutional Code Block Mode.</para>
                        <para>Possible values are:</para>
+                 <section id="atscmh-sccc-block-mode">
 <programlisting>
 typedef enum atscmh_sccc_block_mode {
        ATSCMH_SCCC_BLK_SEP      = 0,
        ATSCMH_SCCC_BLK_COMB     = 1,
 } atscmh_sccc_block_mode_t;
 </programlisting>
+                 </section>
                </section>
                <section id="DTV-ATSCMH-SCCC-CODE-MODE-A">
                        <title><constant>DTV_ATSCMH_SCCC_CODE_MODE_A</constant></title>
                        <para>Series Concatenated Convolutional Code Rate.</para>
                        <para>Possible values are:</para>
+                 <section id="atscmh-sccc-code-mode">
 <programlisting>
 typedef enum atscmh_sccc_code_mode {
        ATSCMH_SCCC_CODE_HLF     = 0,
        ATSCMH_SCCC_CODE_QTR     = 1,
 } atscmh_sccc_code_mode_t;
 </programlisting>
+                 </section>
                </section>
                <section id="DTV-ATSCMH-SCCC-CODE-MODE-B">
                        <title><constant>DTV_ATSCMH_SCCC_CODE_MODE_B</constant></title>
@@ -784,7 +794,7 @@ typedef enum fe_hierarchy {
                        many data types via a single multiplex. The API will soon support this
                        at which point this section will be expanded.</para>
        </section>
-       <section id="DTV_ENUM_DELSYS">
+       <section id="DTV-ENUM-DELSYS">
                <title><constant>DTV_ENUM_DELSYS</constant></title>
                <para>A Multi standard frontend needs to advertise the delivery systems provided.
                        Applications need to enumerate the provided delivery systems, before using
@@ -925,13 +935,13 @@ typedef enum fe_hierarchy {
                                <listitem><para><link linkend="DTV-ATSCMH-PRC"><constant>DTV_ATSCMH_PRC</constant></link></para></listitem>
                                <listitem><para><link linkend="DTV-ATSCMH-RS-FRAME-MODE"><constant>DTV_ATSCMH_RS_FRAME_MODE</constant></link></para></listitem>
                                <listitem><para><link linkend="DTV-ATSCMH-RS-FRAME-ENSEMBLE"><constant>DTV_ATSCMH_RS_FRAME_ENSEMBLE</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-ATSCMH-CODE-MODE-PRI"><constant>DTV_ATSCMH_CODE_MODE_PRI</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-ATSCMH-CODE-MODE-SEC"><constant>DTV_ATSCMH_CODE_MODE_SEC</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-ATSCMH-RS-CODE-MODE-PRI"><constant>DTV_ATSCMH_RS_CODE_MODE_PRI</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-ATSCMH-RS-CODE-MODE-SEC"><constant>DTV_ATSCMH_RS_CODE_MODE_SEC</constant></link></para></listitem>
                                <listitem><para><link linkend="DTV-ATSCMH-SCCC-BLOCK-MODE"><constant>DTV_ATSCMH_SCCC_BLOCK_MODE</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE_MODE-A"><constant>DTV_ATSCMH_SCCC_CODE_MODE_A</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE_MODE-B"><constant>DTV_ATSCMH_SCCC_CODE_MODE_B</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE_MODE-C"><constant>DTV_ATSCMH_SCCC_CODE_MODE_C</constant></link></para></listitem>
-                               <listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE_MODE-D"><constant>DTV_ATSCMH_SCCC_CODE_MODE_D</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE-MODE-A"><constant>DTV_ATSCMH_SCCC_CODE_MODE_A</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE-MODE-B"><constant>DTV_ATSCMH_SCCC_CODE_MODE_B</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE-MODE-C"><constant>DTV_ATSCMH_SCCC_CODE_MODE_C</constant></link></para></listitem>
+                               <listitem><para><link linkend="DTV-ATSCMH-SCCC-CODE-MODE-D"><constant>DTV_ATSCMH_SCCC_CODE_MODE_D</constant></link></para></listitem>
                        </itemizedlist>
                </section>
        </section>
index aeaed59d0f1f5d3d9baeff4af53eb803a7b50355..81082fb84b1cbd7068b9395ce16081d102c6186b 100644 (file)
@@ -66,7 +66,7 @@ supported via the new <link linkend="FE_GET_SET_PROPERTY">FE_GET_PROPERTY/FE_GET
 
 <para>The usage of this field is deprecated, as it doesn't report all supported standards, and
 will provide an incomplete information for frontends that support multiple delivery systems.
-Please use <link linkend="DTV_ENUM_DELSYS">DTV_ENUM_DELSYS</link> instead.</para>
+Please use <link linkend="DTV-ENUM-DELSYS">DTV_ENUM_DELSYS</link> instead.</para>
 </section>
 
 <section id="fe-caps-t">
index 67d37e5ce5979c1a8ffb160bc0993b7f264fc8ec..a193e86941b55eb85ab45beb6850c90560d7c0a7 100644 (file)
@@ -26,4 +26,131 @@ struct dvb_net_if {
 <title>DVB net Function Calls</title>
 <para>To be written&#x2026;
 </para>
+
+<section id="NET_ADD_IF"
+role="subsection"><title>NET_ADD_IF</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = NET_ADD_IF,
+ struct dvb_net_if *if);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals NET_ADD_IF for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct dvb_net_if *if
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="NET_REMOVE_IF"
+role="subsection"><title>NET_REMOVE_IF</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = NET_REMOVE_IF);
+</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals NET_REMOVE_IF for this command.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
+
+<section id="NET_GET_IF"
+role="subsection"><title>NET_GET_IF</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl is undocumented. Documentation is welcome.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(fd, int request = NET_GET_IF,
+ struct dvb_net_if *if);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals NET_GET_IF for this command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct dvb_net_if *if
+</para>
+</entry><entry
+ align="char">
+<para>Undocumented.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+</section>
 </section>
index 25fb823226b42231f7333212c8256fd8d44a888b..3ea1ca7e785ef2b271c848442a54177b86b0245d 100644 (file)
@@ -15,6 +15,10 @@ the audio and video device as well as the video4linux device.
 <para>The ioctls that deal with SPUs (sub picture units) and navigation packets are only
 supported on some MPEG decoders made for DVD playback.
 </para>
+<para>
+These ioctls were also used by V4L2 to control MPEG decoders implemented in V4L2. The use
+of these ioctls for that purpose has been made obsolete and proper V4L2 ioctls or controls
+have been created to replace that functionality.</para>
 <section id="video_types">
 <title>Video Data Types</title>
 
@@ -55,7 +59,7 @@ typedef enum {
 </section>
 
 <section id="video-stream-source-t">
-<title>video stream source</title>
+<title>video_stream_source_t</title>
 <para>The video stream source is set through the VIDEO_SELECT_SOURCE call and can take
 the following values, depending on whether we are replaying from an internal (demuxer) or
 external (user write) source.
@@ -76,7 +80,7 @@ call.
 </section>
 
 <section id="video-play-state-t">
-<title>video play state</title>
+<title>video_play_state_t</title>
 <para>The following values can be returned by the VIDEO_GET_STATUS call representing the
 state of video playback.
 </para>
@@ -90,9 +94,9 @@ typedef enum {
 </section>
 
 <section id="video-command">
+<title>struct video_command</title>
 <para>The structure must be zeroed before use by the application
 This ensures it can be extended safely in the future.</para>
-<title>struct video-command</title>
 <programlisting>
 struct video_command {
        __u32 cmd;
@@ -121,7 +125,7 @@ struct video_command {
 </section>
 
 <section id="video-size-t">
-<title>struct video_size-t</title>
+<title>video_size_t</title>
 <programlisting>
 typedef struct {
        int w;
@@ -217,7 +221,7 @@ bits set according to the hardwares capabilities.
 </section>
 
 <section id="video-system">
-<title>video system</title>
+<title>video_system_t</title>
 <para>A call to VIDEO_SET_SYSTEM sets the desired video system for TV output. The
 following system types can be set:
 </para>
@@ -263,7 +267,7 @@ call expects the following format for that information:
 
 </section>
 <section id="video-spu">
-<title>video SPU</title>
+<title>struct video_spu</title>
 <para>Calling VIDEO_SET_SPU deactivates or activates SPU decoding, according to the
 following format:
 </para>
@@ -277,12 +281,12 @@ following format:
 
 </section>
 <section id="video-spu-palette">
-<title>video SPU palette</title>
+<title>struct video_spu_palette</title>
 <para>The following structure is used to set the SPU palette by calling VIDEO_SPU_PALETTE:
 </para>
 <programlisting>
  typedef
- struct video_spu_palette{
+ struct video_spu_palette {
         int length;
         uint8_t &#x22C6;palette;
  } video_spu_palette_t;
@@ -290,13 +294,13 @@ following format:
 
 </section>
 <section id="video-navi-pack">
-<title>video NAVI pack</title>
+<title>struct video_navi_pack</title>
 <para>In order to get the navigational data the following structure has to be passed to the ioctl
 VIDEO_GET_NAVI:
 </para>
 <programlisting>
  typedef
- struct video_navi_pack{
+ struct video_navi_pack {
         int length;         /&#x22C6; 0 ... 1024 &#x22C6;/
         uint8_t data[1024];
  } video_navi_pack_t;
@@ -305,7 +309,7 @@ VIDEO_GET_NAVI:
 
 
 <section id="video-attributes-t">
-<title>video attributes</title>
+<title>video_attributes_t</title>
 <para>The following attributes can be set by a call to VIDEO_SET_ATTRIBUTES:
 </para>
 <programlisting>
@@ -541,6 +545,8 @@ VIDEO_GET_NAVI:
 role="subsection"><title>VIDEO_STOP</title>
 <para>DESCRIPTION
 </para>
+<para>This ioctl is for DVB devices only. To control a V4L2 decoder use the V4L2
+&VIDIOC-DECODER-CMD; instead.</para>
 <informaltable><tgroup cols="1"><tbody><row><entry
  align="char">
 <para>This ioctl call asks the Video Device to stop playing the current stream.
@@ -598,6 +604,8 @@ role="subsection"><title>VIDEO_STOP</title>
 role="subsection"><title>VIDEO_PLAY</title>
 <para>DESCRIPTION
 </para>
+<para>This ioctl is for DVB devices only. To control a V4L2 decoder use the V4L2
+&VIDIOC-DECODER-CMD; instead.</para>
 <informaltable><tgroup cols="1"><tbody><row><entry
  align="char">
 <para>This ioctl call asks the Video Device to start playing a video stream from the
@@ -634,6 +642,8 @@ role="subsection"><title>VIDEO_PLAY</title>
 role="subsection"><title>VIDEO_FREEZE</title>
 <para>DESCRIPTION
 </para>
+<para>This ioctl is for DVB devices only. To control a V4L2 decoder use the V4L2
+&VIDIOC-DECODER-CMD; instead.</para>
 <informaltable><tgroup cols="1"><tbody><row><entry
  align="char">
 <para>This ioctl call suspends the live video stream being played. Decoding
@@ -674,6 +684,8 @@ role="subsection"><title>VIDEO_FREEZE</title>
 role="subsection"><title>VIDEO_CONTINUE</title>
 <para>DESCRIPTION
 </para>
+<para>This ioctl is for DVB devices only. To control a V4L2 decoder use the V4L2
+&VIDIOC-DECODER-CMD; instead.</para>
 <informaltable><tgroup cols="1"><tbody><row><entry
  align="char">
 <para>This ioctl call restarts decoding and playing processes of the video stream
@@ -710,6 +722,9 @@ role="subsection"><title>VIDEO_CONTINUE</title>
 role="subsection"><title>VIDEO_SELECT_SOURCE</title>
 <para>DESCRIPTION
 </para>
+<para>This ioctl is for DVB devices only. This ioctl was also supported by the
+V4L2 ivtv driver, but that has been replaced by the ivtv-specific
+<constant>IVTV_IOC_PASSTHROUGH_MODE</constant> ioctl.</para>
 <informaltable><tgroup cols="1"><tbody><row><entry
  align="char">
 <para>This ioctl call informs the video device which source shall be used for the input
@@ -845,10 +860,160 @@ role="subsection"><title>VIDEO_GET_STATUS</title>
  </row></tbody></tgroup></informaltable>
 &return-value-dvb;
 
+</section><section id="VIDEO_GET_FRAME_COUNT"
+role="subsection"><title>VIDEO_GET_FRAME_COUNT</title>
+<para>DESCRIPTION
+</para>
+<para>This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders this
+ioctl has been replaced by the <constant>V4L2_CID_MPEG_VIDEO_DEC_FRAME</constant> control.</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call asks the Video Device to return the number of displayed frames
+since the decoder was started.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request =
+ VIDEO_GET_FRAME_COUNT, __u64 *pts);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_GET_FRAME_COUNT for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>__u64 *pts
+</para>
+</entry><entry
+ align="char">
+<para>Returns the number of frames displayed since the decoder was started.
+</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="VIDEO_GET_PTS"
+role="subsection"><title>VIDEO_GET_PTS</title>
+<para>DESCRIPTION
+</para>
+<para>This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders this
+ioctl has been replaced by the <constant>V4L2_CID_MPEG_VIDEO_DEC_PTS</constant> control.</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call asks the Video Device to return the current PTS timestamp.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request =
+ VIDEO_GET_PTS, __u64 *pts);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_GET_PTS for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>__u64 *pts
+</para>
+</entry><entry
+ align="char">
+<para>Returns the 33-bit timestamp as defined in ITU T-REC-H.222.0 / ISO/IEC 13818-1.
+</para>
+<para>
+The PTS should belong to the currently played
+frame if possible, but may also be a value close to it
+like the PTS of the last decoded frame or the last PTS
+extracted by the PES parser.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="VIDEO_GET_FRAME_RATE"
+role="subsection"><title>VIDEO_GET_FRAME_RATE</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl call asks the Video Device to return the current framerate.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request =
+ VIDEO_GET_FRAME_RATE, unsigned int *rate);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_GET_FRAME_RATE for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>unsigned int *rate
+</para>
+</entry><entry
+ align="char">
+<para>Returns the framerate in number of frames per 1000 seconds.
+</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
 </section><section id="VIDEO_GET_EVENT"
 role="subsection"><title>VIDEO_GET_EVENT</title>
 <para>DESCRIPTION
 </para>
+<para>This ioctl is for DVB devices only. To get events from a V4L2 decoder use the V4L2
+&VIDIOC-DQEVENT; ioctl instead.</para>
 <informaltable><tgroup cols="1"><tbody><row><entry
  align="char">
 <para>This ioctl call returns an event of type video_event if available. If an event is
@@ -914,6 +1079,152 @@ role="subsection"><title>VIDEO_GET_EVENT</title>
 </entry>
  </row></tbody></tgroup></informaltable>
 
+</section><section id="VIDEO_COMMAND"
+role="subsection"><title>VIDEO_COMMAND</title>
+<para>DESCRIPTION
+</para>
+<para>This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders this
+ioctl has been replaced by the &VIDIOC-DECODER-CMD; ioctl.</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl commands the decoder. The <constant>video_command</constant> struct
+is a subset of the <constant>v4l2_decoder_cmd</constant> struct, so refer to the
+&VIDIOC-DECODER-CMD; documentation for more information.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request =
+ VIDEO_COMMAND, struct video_command *cmd);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_COMMAND for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct video_command *cmd
+</para>
+</entry><entry
+ align="char">
+<para>Commands the decoder.
+</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="VIDEO_TRY_COMMAND"
+role="subsection"><title>VIDEO_TRY_COMMAND</title>
+<para>DESCRIPTION
+</para>
+<para>This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders this
+ioctl has been replaced by the &VIDIOC-TRY-DECODER-CMD; ioctl.</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl tries a decoder command. The <constant>video_command</constant> struct
+is a subset of the <constant>v4l2_decoder_cmd</constant> struct, so refer to the
+&VIDIOC-TRY-DECODER-CMD; documentation for more information.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request =
+ VIDEO_TRY_COMMAND, struct video_command *cmd);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_TRY_COMMAND for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>struct video_command *cmd
+</para>
+</entry><entry
+ align="char">
+<para>Try a decoder command.
+</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
+</section><section id="VIDEO_GET_SIZE"
+role="subsection"><title>VIDEO_GET_SIZE</title>
+<para>DESCRIPTION
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>This ioctl returns the size and aspect ratio.</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>SYNOPSIS
+</para>
+<informaltable><tgroup cols="1"><tbody><row><entry
+ align="char">
+<para>int ioctl(int fd, int request =
+ VIDEO_GET_SIZE, video_size_t *size);</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+<para>PARAMETERS
+</para>
+<informaltable><tgroup cols="2"><tbody><row><entry
+ align="char">
+<para>int fd</para>
+</entry><entry
+ align="char">
+<para>File descriptor returned by a previous call to open().</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>int request</para>
+</entry><entry
+ align="char">
+<para>Equals VIDEO_GET_SIZE for this
+ command.</para>
+</entry>
+ </row><row><entry
+ align="char">
+<para>video_size_t *size
+</para>
+</entry><entry
+ align="char">
+<para>Returns the size and aspect ratio.
+</para>
+</entry>
+ </row></tbody></tgroup></informaltable>
+&return-value-dvb;
+
 </section><section id="VIDEO_SET_DISPLAY_FORMAT"
 role="subsection"><title>VIDEO_SET_DISPLAY_FORMAT</title>
 <para>DESCRIPTION
index faa0fd14666a54bc2688ca176c9dee531cc5eccf..98e8d088b3a5f77cc179e8bda8aaf1bdf623140b 100644 (file)
@@ -2468,21 +2468,9 @@ that used it. It was originally scheduled for removal in 2.6.35.
          <structfield>reserved2</structfield> and removed
          <constant>V4L2_BUF_FLAG_INPUT</constant>.</para>
        </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 3.6</title>
-      <orderedlist>
         <listitem>
          <para>Added V4L2_CAP_VIDEO_M2M and V4L2_CAP_VIDEO_M2M_MPLANE capabilities.</para>
         </listitem>
-      </orderedlist>
-    </section>
-
-    <section>
-      <title>V4L2 in Linux 3.6</title>
-      <orderedlist>
         <listitem>
          <para>Added support for frequency band enumerations: &VIDIOC-ENUM-FREQ-BANDS;.</para>
         </listitem>
@@ -2614,10 +2602,6 @@ ioctls.</para>
          <para>Sub-device selection API: &VIDIOC-SUBDEV-G-SELECTION;
          and &VIDIOC-SUBDEV-S-SELECTION; ioctls.</para>
         </listitem>
-        <listitem>
-         <para><link linkend="v4l2-auto-focus-area"><constant>
-         V4L2_CID_AUTO_FOCUS_AREA</constant></link> control.</para>
-        </listitem>
         <listitem>
          <para>Support for frequency band enumeration: &VIDIOC-ENUM-FREQ-BANDS; ioctl.</para>
         </listitem>
index eee6908c749fd3b6fb66e0e9ab84c9775c09509b..0292ed106887febe4db9bb84f0e04c5b3dd8185b 100644 (file)
@@ -145,9 +145,12 @@ applications. -->
        <authorinitials>hv</authorinitials>
        <revremark>Added VIDIOC_ENUM_FREQ_BANDS.
        </revremark>
+      </revision>
+
+      <revision>
        <revnumber>3.5</revnumber>
        <date>2012-05-07</date>
-       <authorinitials>sa, sn</authorinitials>
+       <authorinitials>sa, sn, hv</authorinitials>
        <revremark>Added V4L2_CTRL_TYPE_INTEGER_MENU and V4L2 subdev
            selections API. Improved the description of V4L2_CID_COLORFX
            control, added V4L2_CID_COLORFX_CBCR control.
@@ -158,11 +161,8 @@ applications. -->
            V4L2_CID_3A_LOCK, V4L2_CID_AUTO_FOCUS_START,
            V4L2_CID_AUTO_FOCUS_STOP, V4L2_CID_AUTO_FOCUS_STATUS
            and V4L2_CID_AUTO_FOCUS_RANGE.
-       </revremark>
-       <date>2012-05-01</date>
-       <authorinitials>hv</authorinitials>
-       <revremark>Added VIDIOC_ENUM_DV_TIMINGS, VIDIOC_QUERY_DV_TIMINGS and
-       VIDIOC_DV_TIMINGS_CAP.
+           Added VIDIOC_ENUM_DV_TIMINGS, VIDIOC_QUERY_DV_TIMINGS and
+           VIDIOC_DV_TIMINGS_CAP.
        </revremark>
       </revision>
 
@@ -472,7 +472,7 @@ and discussions on the V4L mailing list.</revremark>
 </partinfo>
 
 <title>Video for Linux Two API Specification</title>
- <subtitle>Revision 3.5</subtitle>
+ <subtitle>Revision 3.6</subtitle>
 
   <chapter id="common">
     &sub-common;
index 720395127904574b69db6dd2b042f46b3d14901b..701138f1209de10ae439aff4da056803fbb79713 100644 (file)
@@ -125,7 +125,7 @@ the structure refers to a radio tuner the
 <constant>V4L2_TUNER_CAP_NORM</constant> flags can't be used.</para>
 <para>If multiple frequency bands are supported, then
 <structfield>capability</structfield> is the union of all
-<structfield>capability></structfield> fields of each &v4l2-frequency-band;.
+<structfield>capability</structfield> fields of each &v4l2-frequency-band;.
 </para></entry>
          </row>
          <row>
index 4e8e8985cc1722a5594efdb61c2c0a5af1294929..f2413acfe24105b00b529feca5a0490d6a9b126d 100644 (file)
@@ -29,7 +29,7 @@
 <title>LINUX MEDIA INFRASTRUCTURE API</title>
 
 <copyright>
-       <year>2009-2011</year>
+       <year>2009-2012</year>
        <holder>LinuxTV Developers</holder>
 </copyright>
 
@@ -53,7 +53,7 @@ Foundation. A copy of the license is included in the chapter entitled
                video and radio straming devices, including video cameras,
                analog and digital TV receiver cards, AM/FM receiver cards,
                streaming capture devices.</para>
-       <para>It is divided into three parts.</para>
+       <para>It is divided into four parts.</para>
        <para>The first part covers radio, capture,
                cameras and analog TV devices.</para>
        <para>The second part covers the
@@ -62,7 +62,8 @@ Foundation. A copy of the license is included in the chapter entitled
                in fact it covers several different video standards including
                DVB-T, DVB-S, DVB-C and ATSC. The API is currently being updated
                to documment support also for DVB-S2, ISDB-T and ISDB-S.</para>
-       <para>The third part covers Remote Controller API</para>
+       <para>The third part covers the Remote Controller API.</para>
+       <para>The fourth part covers the Media Controller API.</para>
        <para>For additional information and for the latest development code,
                see: <ulink url="http://linuxtv.org">http://linuxtv.org</ulink>.</para>
        <para>For discussing improvements, reporting troubles, sending new drivers, etc, please mail to: <ulink url="http://vger.kernel.org/vger-lists.html#linux-media">Linux Media Mailing List (LMML).</ulink>.</para>
@@ -87,7 +88,7 @@ Foundation. A copy of the license is included in the chapter entitled
 </author>
 </authorgroup>
 <copyright>
-       <year>2009-2011</year>
+       <year>2009-2012</year>
        <holder>Mauro Carvalho Chehab</holder>
 </copyright>
 
index e0aedb7a782718c445d48f8f42ee9e14a3d5a33a..fe122d6e686f50e873d637d3f08929d042df4335 100644 (file)
@@ -1216,8 +1216,6 @@ in this page</entry>
 #define        NAND_BBT_LASTBLOCK      0x00000010
 /* The bbt is at the given page, else we must scan for the bbt */
 #define NAND_BBT_ABSPAGE       0x00000020
-/* The bbt is at the given page, else we must scan for the bbt */
-#define NAND_BBT_SEARCH                0x00000040
 /* bbt is stored per chip on multichip devices */
 #define NAND_BBT_PERCHIP       0x00000080
 /* bbt has a version counter at offset veroffs */
index f6f15ce399036e4c03b99d9d7bd77aab7480cd98..672d19083252499cfe8ca3034f2b59a1ce0557d8 100644 (file)
@@ -333,23 +333,23 @@ o Each element of the form "1/1 0:127 ^0" represents one struct
 The output of "cat rcu/rcu_pending" looks as follows:
 
 rcu_sched:
-  0 np=255892 qsp=53936 rpq=85 cbr=0 cng=14417 gpc=10033 gps=24320 nf=6445 nn=146741
-  1 np=261224 qsp=54638 rpq=33 cbr=0 cng=25723 gpc=16310 gps=2849 nf=5912 nn=155792
-  2 np=237496 qsp=49664 rpq=23 cbr=0 cng=2762 gpc=45478 gps=1762 nf=1201 nn=136629
-  3 np=236249 qsp=48766 rpq=98 cbr=0 cng=286 gpc=48049 gps=1218 nf=207 nn=137723
-  4 np=221310 qsp=46850 rpq=7 cbr=0 cng=26 gpc=43161 gps=4634 nf=3529 nn=123110
-  5 np=237332 qsp=48449 rpq=9 cbr=0 cng=54 gpc=47920 gps=3252 nf=201 nn=137456
-  6 np=219995 qsp=46718 rpq=12 cbr=0 cng=50 gpc=42098 gps=6093 nf=4202 nn=120834
-  7 np=249893 qsp=49390 rpq=42 cbr=0 cng=72 gpc=38400 gps=17102 nf=41 nn=144888
+  0 np=255892 qsp=53936 rpq=85 cbr=0 cng=14417 gpc=10033 gps=24320 nn=146741
+  1 np=261224 qsp=54638 rpq=33 cbr=0 cng=25723 gpc=16310 gps=2849 nn=155792
+  2 np=237496 qsp=49664 rpq=23 cbr=0 cng=2762 gpc=45478 gps=1762 nn=136629
+  3 np=236249 qsp=48766 rpq=98 cbr=0 cng=286 gpc=48049 gps=1218 nn=137723
+  4 np=221310 qsp=46850 rpq=7 cbr=0 cng=26 gpc=43161 gps=4634 nn=123110
+  5 np=237332 qsp=48449 rpq=9 cbr=0 cng=54 gpc=47920 gps=3252 nn=137456
+  6 np=219995 qsp=46718 rpq=12 cbr=0 cng=50 gpc=42098 gps=6093 nn=120834
+  7 np=249893 qsp=49390 rpq=42 cbr=0 cng=72 gpc=38400 gps=17102 nn=144888
 rcu_bh:
-  0 np=146741 qsp=1419 rpq=6 cbr=0 cng=6 gpc=0 gps=0 nf=2 nn=145314
-  1 np=155792 qsp=12597 rpq=3 cbr=0 cng=0 gpc=4 gps=8 nf=3 nn=143180
-  2 np=136629 qsp=18680 rpq=1 cbr=0 cng=0 gpc=7 gps=6 nf=0 nn=117936
-  3 np=137723 qsp=2843 rpq=0 cbr=0 cng=0 gpc=10 gps=7 nf=0 nn=134863
-  4 np=123110 qsp=12433 rpq=0 cbr=0 cng=0 gpc=4 gps=2 nf=0 nn=110671
-  5 np=137456 qsp=4210 rpq=1 cbr=0 cng=0 gpc=6 gps=5 nf=0 nn=133235
-  6 np=120834 qsp=9902 rpq=2 cbr=0 cng=0 gpc=6 gps=3 nf=2 nn=110921
-  7 np=144888 qsp=26336 rpq=0 cbr=0 cng=0 gpc=8 gps=2 nf=0 nn=118542
+  0 np=146741 qsp=1419 rpq=6 cbr=0 cng=6 gpc=0 gps=0 nn=145314
+  1 np=155792 qsp=12597 rpq=3 cbr=0 cng=0 gpc=4 gps=8 nn=143180
+  2 np=136629 qsp=18680 rpq=1 cbr=0 cng=0 gpc=7 gps=6 nn=117936
+  3 np=137723 qsp=2843 rpq=0 cbr=0 cng=0 gpc=10 gps=7 nn=134863
+  4 np=123110 qsp=12433 rpq=0 cbr=0 cng=0 gpc=4 gps=2 nn=110671
+  5 np=137456 qsp=4210 rpq=1 cbr=0 cng=0 gpc=6 gps=5 nn=133235
+  6 np=120834 qsp=9902 rpq=2 cbr=0 cng=0 gpc=6 gps=3 nn=110921
+  7 np=144888 qsp=26336 rpq=0 cbr=0 cng=0 gpc=8 gps=2 nn=118542
 
 As always, this is once again split into "rcu_sched" and "rcu_bh"
 portions, with CONFIG_TREE_PREEMPT_RCU kernels having an additional
@@ -377,17 +377,6 @@ o  "gpc" is the number of times that an old grace period had
 o      "gps" is the number of times that a new grace period had started,
        but this CPU was not yet aware of it.
 
-o      "nf" is the number of times that this CPU suspected that the
-       current grace period had run for too long, and thus needed to
-       be forced.
-
-       Please note that "forcing" consists of sending resched IPIs
-       to holdout CPUs.  If that CPU really still is in an old RCU
-       read-side critical section, then we really do have to wait for it.
-       The assumption behing "forcing" is that the CPU is not still in
-       an old RCU read-side critical section, but has not yet responded
-       for some other reason.
-
 o      "nn" is the number of times that this CPU needed nothing.  Alert
        readers will note that the rcu "nn" number for a given CPU very
        closely matches the rcu_bh "np" number for that same CPU.  This
diff --git a/Documentation/arm/Marvell/README b/Documentation/arm/Marvell/README
new file mode 100644 (file)
index 0000000..8f08a86
--- /dev/null
@@ -0,0 +1,232 @@
+ARM Marvell SoCs
+================
+
+This document lists all the ARM Marvell SoCs that are currently
+supported in mainline by the Linux kernel. As the Marvell families of
+SoCs are large and complex, it is hard to understand where the support
+for a particular SoC is available in the Linux kernel. This document
+tries to help in understanding where those SoCs are supported, and to
+match them with their corresponding public datasheet, when available.
+
+Orion family
+------------
+
+  Flavors:
+        88F5082
+        88F5181
+        88F5181L
+        88F5182
+               Datasheet               : http://www.embeddedarm.com/documentation/third-party/MV88F5182-datasheet.pdf
+               Programmer's User Guide : http://www.embeddedarm.com/documentation/third-party/MV88F5182-opensource-manual.pdf
+               User Manual             : http://www.embeddedarm.com/documentation/third-party/MV88F5182-usermanual.pdf
+        88F5281
+               Datasheet               : http://www.ocmodshop.com/images/reviews/networking/qnap_ts409u/marvel_88f5281_data_sheet.pdf
+        88F6183
+  Core: Feroceon ARMv5 compatible
+  Linux kernel mach directory: arch/arm/mach-orion5x
+  Linux kernel plat directory: arch/arm/plat-orion
+
+Kirkwood family
+---------------
+
+  Flavors:
+        88F6282 a.k.a Armada 300
+                Product Brief  : http://www.marvell.com/embedded-processors/armada-300/assets/armada_310.pdf
+        88F6283 a.k.a Armada 310
+                Product Brief  : http://www.marvell.com/embedded-processors/armada-300/assets/armada_310.pdf
+        88F6190
+                Product Brief  : http://www.marvell.com/embedded-processors/kirkwood/assets/88F6190-003_WEB.pdf
+                Hardware Spec  : http://www.marvell.com/embedded-processors/kirkwood/assets/HW_88F619x_OpenSource.pdf
+                Functional Spec: http://www.marvell.com/embedded-processors/kirkwood/assets/FS_88F6180_9x_6281_OpenSource.pdf
+        88F6192
+                Product Brief  : http://www.marvell.com/embedded-processors/kirkwood/assets/88F6192-003_ver1.pdf
+                Hardware Spec  : http://www.marvell.com/embedded-processors/kirkwood/assets/HW_88F619x_OpenSource.pdf
+                Functional Spec: http://www.marvell.com/embedded-processors/kirkwood/assets/FS_88F6180_9x_6281_OpenSource.pdf
+        88F6182
+        88F6180
+                Product Brief  : http://www.marvell.com/embedded-processors/kirkwood/assets/88F6180-003_ver1.pdf
+                Hardware Spec  : http://www.marvell.com/embedded-processors/kirkwood/assets/HW_88F6180_OpenSource.pdf
+                Functional Spec: http://www.marvell.com/embedded-processors/kirkwood/assets/FS_88F6180_9x_6281_OpenSource.pdf
+        88F6281
+                Product Brief  : http://www.marvell.com/embedded-processors/kirkwood/assets/88F6281-004_ver1.pdf
+                Hardware Spec  : http://www.marvell.com/embedded-processors/kirkwood/assets/HW_88F6281_OpenSource.pdf
+                Functional Spec: http://www.marvell.com/embedded-processors/kirkwood/assets/FS_88F6180_9x_6281_OpenSource.pdf
+  Homepage: http://www.marvell.com/embedded-processors/kirkwood/
+  Core: Feroceon ARMv5 compatible
+  Linux kernel mach directory: arch/arm/mach-kirkwood
+  Linux kernel plat directory: arch/arm/plat-orion
+
+Discovery family
+----------------
+
+  Flavors:
+        MV78100
+                Product Brief  : http://www.marvell.com/embedded-processors/discovery-innovation/assets/MV78100-003_WEB.pdf
+                Hardware Spec  : http://www.marvell.com/embedded-processors/discovery-innovation/assets/HW_MV78100_OpenSource.pdf
+                Functional Spec: http://www.marvell.com/embedded-processors/discovery-innovation/assets/FS_MV76100_78100_78200_OpenSource.pdf
+        MV78200
+                Product Brief  : http://www.marvell.com/embedded-processors/discovery-innovation/assets/MV78200-002_WEB.pdf
+                Hardware Spec  : http://www.marvell.com/embedded-processors/discovery-innovation/assets/HW_MV78200_OpenSource.pdf
+                Functional Spec: http://www.marvell.com/embedded-processors/discovery-innovation/assets/FS_MV76100_78100_78200_OpenSource.pdf
+        MV76100
+                Not supported by the Linux kernel.
+
+  Core: Feroceon ARMv5 compatible
+
+  Linux kernel mach directory: arch/arm/mach-mv78xx0
+  Linux kernel plat directory: arch/arm/plat-orion
+
+EBU Armada family
+-----------------
+
+  Armada 370 Flavors:
+        88F6710
+        88F6707
+        88F6W11
+
+  Armada XP Flavors:
+        MV78230
+        MV78260
+        MV78460
+
+  Product Brief: http://www.marvell.com/embedded-processors/armada-xp/assets/Marvell-ArmadaXP-SoC-product%20brief.pdf
+  No public datasheet available.
+
+  Core: Sheeva ARMv7 compatible
+
+  Linux kernel mach directory: arch/arm/mach-mvebu
+  Linux kernel plat directory: none
+
+Avanta family
+-------------
+
+  Flavors:
+       88F6510
+       88F6530P
+       88F6550
+       88F6560
+  Homepage     : http://www.marvell.com/broadband/
+  Product Brief: http://www.marvell.com/broadband/assets/Marvell_Avanta_88F6510_305_060-001_product_brief.pdf
+  No public datasheet available.
+
+  Core: ARMv5 compatible
+
+  Linux kernel mach directory: no code in mainline yet, planned for the future
+  Linux kernel plat directory: no code in mainline yet, planned for the future
+
+Dove family (application processor)
+-----------------------------------
+
+  Flavors:
+        88AP510 a.k.a Armada 510
+                Product Brief   : http://www.marvell.com/application-processors/armada-500/assets/Marvell_Armada510_SoC.pdf
+                Hardware Spec   : http://www.marvell.com/application-processors/armada-500/assets/Armada-510-Hardware-Spec.pdf
+                Functional Spec : http://www.marvell.com/application-processors/armada-500/assets/Armada-510-Functional-Spec.pdf
+  Homepage: http://www.marvell.com/application-processors/armada-500/
+  Core: ARMv7 compatible
+  Directory: arch/arm/mach-dove
+
+PXA 2xx/3xx/93x/95x family
+--------------------------
+
+  Flavors:
+        PXA21x, PXA25x, PXA26x
+             Application processor only
+             Core: ARMv5 XScale core
+        PXA270, PXA271, PXA272
+             Product Brief         : http://www.marvell.com/application-processors/pxa-family/assets/pxa_27x_pb.pdf
+             Design guide          : http://www.marvell.com/application-processors/pxa-family/assets/pxa_27x_design_guide.pdf
+             Developers manual     : http://www.marvell.com/application-processors/pxa-family/assets/pxa_27x_dev_man.pdf
+             Specification         : http://www.marvell.com/application-processors/pxa-family/assets/pxa_27x_emts.pdf
+             Specification update  : http://www.marvell.com/application-processors/pxa-family/assets/pxa_27x_spec_update.pdf
+             Application processor only
+             Core: ARMv5 XScale core
+        PXA300, PXA310, PXA320
+             PXA 300 Product Brief : http://www.marvell.com/application-processors/pxa-family/assets/PXA300_PB_R4.pdf
+             PXA 310 Product Brief : http://www.marvell.com/application-processors/pxa-family/assets/PXA310_PB_R4.pdf
+             PXA 320 Product Brief : http://www.marvell.com/application-processors/pxa-family/assets/PXA320_PB_R4.pdf
+             Design guide          : http://www.marvell.com/application-processors/pxa-family/assets/PXA3xx_Design_Guide.pdf
+             Developers manual     : http://www.marvell.com/application-processors/pxa-family/assets/PXA3xx_Developers_Manual.zip
+             Specifications        : http://www.marvell.com/application-processors/pxa-family/assets/PXA3xx_EMTS.pdf
+             Specification Update  : http://www.marvell.com/application-processors/pxa-family/assets/PXA3xx_Spec_Update.zip
+             Reference Manual      : http://www.marvell.com/application-processors/pxa-family/assets/PXA3xx_TavorP_BootROM_Ref_Manual.pdf
+             Application processor only
+             Core: ARMv5 XScale core
+        PXA930, PXA935
+             Application processor with Communication processor
+             Core: ARMv5 XScale core
+        PXA955
+             Application processor with Communication processor
+             Core: ARMv7 compatible Sheeva PJ4 core
+
+   Comments:
+
+    * This line of SoCs originates from the XScale family developed by
+      Intel and acquired by Marvell in ~2006. The PXA21x, PXA25x,
+      PXA26x, PXA27x, PXA3xx and PXA93x were developed by Intel, while
+      the later PXA95x were developed by Marvell.
+
+    * Due to their XScale origin, these SoCs have virtually nothing in
+      common with the other (Kirkwood, Dove, etc.) families of Marvell
+      SoCs, except with the MMP/MMP2 family of SoCs.
+
+   Linux kernel mach directory: arch/arm/mach-pxa
+   Linux kernel plat directory: arch/arm/plat-pxa
+
+MMP/MMP2 family (communication processor)
+-----------------------------------------
+
+   Flavors:
+        PXA168, a.k.a Armada 168
+             Homepage             : http://www.marvell.com/application-processors/armada-100/armada-168.jsp
+             Product brief        : http://www.marvell.com/application-processors/armada-100/assets/pxa_168_pb.pdf
+             Hardware manual      : http://www.marvell.com/application-processors/armada-100/assets/armada_16x_datasheet.pdf
+             Software manual      : http://www.marvell.com/application-processors/armada-100/assets/armada_16x_software_manual.pdf
+             Specification update : http://www.marvell.com/application-processors/armada-100/assets/ARMADA16x_Spec_update.pdf
+             Boot ROM manual      : http://www.marvell.com/application-processors/armada-100/assets/armada_16x_ref_manual.pdf
+             App node package     : http://www.marvell.com/application-processors/armada-100/assets/armada_16x_app_note_package.pdf
+             Application processor only
+             Core: ARMv5 compatible Marvell PJ1 (Mohawk)
+        PXA910
+             Homepage             : http://www.marvell.com/communication-processors/pxa910/
+             Product Brief        : http://www.marvell.com/communication-processors/pxa910/assets/Marvell_PXA910_Platform-001_PB_final.pdf
+             Application processor with Communication processor
+             Core: ARMv5 compatible Marvell PJ1 (Mohawk)
+        MMP2, a.k.a Armada 610
+             Product Brief        : http://www.marvell.com/application-processors/armada-600/assets/armada610_pb.pdf
+             Application processor only
+             Core: ARMv7 compatible Sheeva PJ4 core
+
+   Comments:
+
+    * This line of SoCs originates from the XScale family developed by
+      Intel and acquired by Marvell in ~2006. All the processors of
+      this MMP/MMP2 family were developed by Marvell.
+
+    * Due to their XScale origin, these SoCs have virtually nothing in
+      common with the other (Kirkwood, Dove, etc.) families of Marvell
+      SoCs, except with the PXA family of SoCs listed above.
+
+   Linux kernel mach directory: arch/arm/mach-mmp
+   Linux kernel plat directory: arch/arm/plat-pxa
+
+Long-term plans
+---------------
+
+ * Unify the mach-dove/, mach-mv78xx0/, mach-orion5x/ and
+   mach-kirkwood/ into the mach-mvebu/ to support all SoCs from the
+   Marvell EBU (Engineering Business Unit) in a single mach-<foo>
+   directory. The plat-orion/ would therefore disappear.
+
+ * Unify the mach-mmp/ and mach-pxa/ into the same mach-pxa
+   directory. The plat-pxa/ would therefore disappear.
+
+Credits
+-------
+
+ Maen Suleiman <maen@marvell.com>
+ Lior Amsalem <alior@marvell.com>
+ Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+ Andrew Lunn <andrew@lunn.ch>
+ Nicolas Pitre <nico@fluxnic.net>
+ Eric Miao <eric.y.miao@gmail.com>
index 208a2d465b922ec826049243abc8c6ac2a724813..4bfb9ffbdbc1d2b389025c9c0e5d9c5402a36a29 100644 (file)
@@ -51,6 +51,9 @@ ffc00000      ffefffff        DMA memory mapping region.  Memory returned
 ff000000       ffbfffff        Reserved for future expansion of DMA
                                mapping region.
 
+fee00000       feffffff        Mapping of PCI I/O space. This is a static
+                               mapping within the vmalloc space.
+
 VMALLOC_START  VMALLOC_END-1   vmalloc() / ioremap() space.
                                Memory returned by vmalloc/ioremap will
                                be dynamically placed in this region.
index d111e3b23db0bbc0bdf23d81c27e74158ccd9a66..d18ecd827c408d0fb42a8d8a7fc669ce88c95fc2 100644 (file)
@@ -3,15 +3,21 @@
 biodoc.txt
        - Notes on the Generic Block Layer Rewrite in Linux 2.5
 capability.txt
-       - Generic Block Device Capability (/sys/block/<disk>/capability)
+       - Generic Block Device Capability (/sys/block/<device>/capability)
+cfq-iosched.txt
+       - CFQ IO scheduler tunables
+data-integrity.txt
+       - Block data integrity
 deadline-iosched.txt
        - Deadline IO scheduler tunables
 ioprio.txt
        - Block io priorities (in CFQ scheduler)
+queue-sysfs.txt
+       - Queue's sysfs entries
 request.txt
        - The members of struct request (in include/linux/blkdev.h)
 stat.txt
-       - Block layer statistics in /sys/block/<dev>/stat
+       - Block layer statistics in /sys/block/<device>/stat
 switching-sched.txt
        - Switching I/O schedulers at runtime
 writeback_cache_control.txt
index 6d670f570451a14c1ce4f8c2eb1c69d52736ee01..d89b4fe724d75393a003b33c22bf531252c29672 100644 (file)
@@ -1,3 +1,14 @@
+CFQ (Complete Fairness Queueing)
+===============================
+
+The main aim of CFQ scheduler is to provide a fair allocation of the disk
+I/O bandwidth for all the processes which requests an I/O operation.
+
+CFQ maintains the per process queue for the processes which request I/O
+operation(syncronous requests). In case of asynchronous requests, all the
+requests from all the processes are batched together according to their
+process's I/O priority.
+
 CFQ ioscheduler tunables
 ========================
 
@@ -25,6 +36,72 @@ there are multiple spindles behind single LUN (Host based hardware RAID
 controller or for storage arrays), setting slice_idle=0 might end up in better
 throughput and acceptable latencies.
 
+back_seek_max
+-------------
+This specifies, given in Kbytes, the maximum "distance" for backward seeking.
+The distance is the amount of space from the current head location to the
+sectors that are backward in terms of distance.
+
+This parameter allows the scheduler to anticipate requests in the "backward"
+direction and consider them as being the "next" if they are within this
+distance from the current head location.
+
+back_seek_penalty
+-----------------
+This parameter is used to compute the cost of backward seeking. If the
+backward distance of request is just 1/back_seek_penalty from a "front"
+request, then the seeking cost of two requests is considered equivalent.
+
+So scheduler will not bias toward one or the other request (otherwise scheduler
+will bias toward front request). Default value of back_seek_penalty is 2.
+
+fifo_expire_async
+-----------------
+This parameter is used to set the timeout of asynchronous requests. Default
+value of this is 248ms.
+
+fifo_expire_sync
+----------------
+This parameter is used to set the timeout of synchronous requests. Default
+value of this is 124ms. In case to favor synchronous requests over asynchronous
+one, this value should be decreased relative to fifo_expire_async.
+
+slice_async
+-----------
+This parameter is same as of slice_sync but for asynchronous queue. The
+default value is 40ms.
+
+slice_async_rq
+--------------
+This parameter is used to limit the dispatching of asynchronous request to
+device request queue in queue's slice time. The maximum number of request that
+are allowed to be dispatched also depends upon the io priority. Default value
+for this is 2.
+
+slice_sync
+----------
+When a queue is selected for execution, the queues IO requests are only
+executed for a certain amount of time(time_slice) before switching to another
+queue. This parameter is used to calculate the time slice of synchronous
+queue.
+
+time_slice is computed using the below equation:-
+time_slice = slice_sync + (slice_sync/5 * (4 - prio)). To increase the
+time_slice of synchronous queue, increase the value of slice_sync. Default
+value is 100ms.
+
+quantum
+-------
+This specifies the number of request dispatched to the device queue. In a
+queue's time slice, a request will not be dispatched if the number of request
+in the device exceeds this parameter. This parameter is used for synchronous
+request.
+
+In case of storage with several disk, this setting can limit the parallel
+processing of request. Therefore, increasing the value can imporve the
+performace although this can cause the latency of some I/O to increase due
+to more number of requests.
+
 CFQ IOPS Mode for group scheduling
 ===================================
 Basic CFQ design is to provide priority based time slices. Higher priority
index 6518a55273e7094f62f84a5d83467fd96b26fd26..e54ac1d53403094c59e019b1f5e5397e8f4f637d 100644 (file)
@@ -9,20 +9,71 @@ These files are the ones found in the /sys/block/xxx/queue/ directory.
 Files denoted with a RO postfix are readonly and the RW postfix means
 read-write.
 
+add_random (RW)
+----------------
+This file allows to trun off the disk entropy contribution. Default
+value of this file is '1'(on).
+
+discard_granularity (RO)
+-----------------------
+This shows the size of internal allocation of the device in bytes, if
+reported by the device. A value of '0' means device does not support
+the discard functionality.
+
+discard_max_bytes (RO)
+----------------------
+Devices that support discard functionality may have internal limits on
+the number of bytes that can be trimmed or unmapped in a single operation.
+The discard_max_bytes parameter is set by the device driver to the maximum
+number of bytes that can be discarded in a single operation. Discard
+requests issued to the device must not exceed this limit. A discard_max_bytes
+value of 0 means that the device does not support discard functionality.
+
+discard_zeroes_data (RO)
+------------------------
+When read, this file will show if the discarded block are zeroed by the
+device or not. If its value is '1' the blocks are zeroed otherwise not.
+
 hw_sector_size (RO)
 -------------------
 This is the hardware sector size of the device, in bytes.
 
+iostats (RW)
+-------------
+This file is used to control (on/off) the iostats accounting of the
+disk.
+
+logical_block_size (RO)
+-----------------------
+This is the logcal block size of the device, in bytes.
+
 max_hw_sectors_kb (RO)
 ----------------------
 This is the maximum number of kilobytes supported in a single data transfer.
 
+max_integrity_segments (RO)
+---------------------------
+When read, this file shows the max limit of integrity segments as
+set by block layer which a hardware controller can handle.
+
 max_sectors_kb (RW)
 -------------------
 This is the maximum number of kilobytes that the block layer will allow
 for a filesystem request. Must be smaller than or equal to the maximum
 size allowed by the hardware.
 
+max_segments (RO)
+-----------------
+Maximum number of segments of the device.
+
+max_segment_size (RO)
+---------------------
+Maximum segment size of the device.
+
+minimum_io_size (RO)
+--------------------
+This is the smallest preferred io size reported by the device.
+
 nomerges (RW)
 -------------
 This enables the user to disable the lookup logic involved with IO
@@ -45,11 +96,24 @@ per-block-cgroup request pool.  IOW, if there are N block cgroups,
 each request queue may have upto N request pools, each independently
 regulated by nr_requests.
 
+optimal_io_size (RO)
+--------------------
+This is the optimal io size reported by the device.
+
+physical_block_size (RO)
+------------------------
+This is the physical block size of device, in bytes.
+
 read_ahead_kb (RW)
 ------------------
 Maximum number of kilobytes to read-ahead for filesystems on this block
 device.
 
+rotational (RW)
+---------------
+This file is used to stat if the device is of rotational type or
+non-rotational type.
+
 rq_affinity (RW)
 ----------------
 If this option is '1', the block layer will migrate request completions to the
index 9d28a3406e745589383021732fe7941ed9aad1cb..b6f44f490ed7839f0963acfc0c53ed2537fa35e2 100644 (file)
@@ -76,9 +76,17 @@ total 0
 
 
 * desc : Small description about the idle state (string)
-* disable : Option to disable this idle state (bool)
+* disable : Option to disable this idle state (bool) -> see note below
 * latency : Latency to exit out of this idle state (in microseconds)
 * name : Name of the idle state (string)
 * power : Power consumed while in this idle state (in milliwatts)
 * time : Total time spent in this idle state (in microseconds)
 * usage : Number of times this state was entered (count)
+
+Note:
+The behavior and the effect of the disable variable depends on the
+implementation of a particular governor. In the ladder governor, for
+example, it is not coherent, i.e. if one is disabling a light state,
+then all deeper states are disabled as well, but the disable variable
+does not reflect it. Likewise, if one enables a deep state but a lighter
+state still is disabled, then this has no effect.
diff --git a/Documentation/devicetree/bindings/arm/mrvl/tauros2.txt b/Documentation/devicetree/bindings/arm/mrvl/tauros2.txt
new file mode 100644 (file)
index 0000000..31af1cb
--- /dev/null
@@ -0,0 +1,17 @@
+* Marvell Tauros2 Cache
+
+Required properties:
+- compatible : Should be "marvell,tauros2-cache".
+- marvell,tauros2-cache-features : Specify the features supported for the
+  tauros2 cache.
+  The features including
+    CACHE_TAUROS2_PREFETCH_ON       (1 << 0)
+    CACHE_TAUROS2_LINEFILL_BURST8   (1 << 1)
+  The definition can be found at
+  arch/arm/include/asm/hardware/cache-tauros2.h
+
+Example:
+       L2: l2-cache {
+               compatible = "marvell,tauros2-cache";
+               marvell,tauros2-cache-features = <0x3>;
+       };
index 1c044eb320cc4fb6ed4f269ebaaa763794c485e7..343781b9f246773ce880f9427623ebbd12202f32 100644 (file)
@@ -7,8 +7,12 @@ representation in the device tree should be done as under:-
 Required properties:
 
 - compatible : should be one of
+       "arm,cortex-a15-pmu"
        "arm,cortex-a9-pmu"
        "arm,cortex-a8-pmu"
+       "arm,cortex-a7-pmu"
+       "arm,cortex-a5-pmu"
+       "arm,arm11mpcore-pmu"
        "arm,arm1176-pmu"
        "arm,arm1136-pmu"
 - interrupts : 1 combined interrupt or 1 per core.
diff --git a/Documentation/devicetree/bindings/mmc/atmel-hsmci.txt b/Documentation/devicetree/bindings/mmc/atmel-hsmci.txt
new file mode 100644 (file)
index 0000000..0a85c70
--- /dev/null
@@ -0,0 +1,68 @@
+* Atmel High Speed MultiMedia Card Interface
+
+This controller on atmel products provides an interface for MMC, SD and SDIO
+types of memory cards.
+
+This file documents differences between the core properties described
+by mmc.txt and the properties used by the atmel-mci driver.
+
+1) MCI node
+
+Required properties:
+- compatible: should be "atmel,hsmci"
+- #address-cells: should be one. The cell is the slot id.
+- #size-cells: should be zero.
+- at least one slot node
+
+The node contains child nodes for each slot that the platform uses
+
+Example MCI node:
+
+mmc0: mmc@f0008000 {
+       compatible = "atmel,hsmci";
+       reg = <0xf0008000 0x600>;
+       interrupts = <12 4>;
+       #address-cells = <1>;
+       #size-cells = <0>;
+
+       [ child node definitions...]
+};
+
+2) slot nodes
+
+Required properties:
+- reg: should contain the slot id.
+- bus-width: number of data lines connected to the controller
+
+Optional properties:
+- cd-gpios: specify GPIOs for card detection
+- cd-inverted: invert the value of external card detect gpio line
+- wp-gpios: specify GPIOs for write protection
+
+Example slot node:
+
+slot@0 {
+       reg = <0>;
+       bus-width = <4>;
+       cd-gpios = <&pioD 15 0>
+       cd-inverted;
+};
+
+Example full MCI node:
+mmc0: mmc@f0008000 {
+       compatible = "atmel,hsmci";
+       reg = <0xf0008000 0x600>;
+       interrupts = <12 4>;
+       #address-cells = <1>;
+       #size-cells = <0>;
+       slot@0 {
+               reg = <0>;
+               bus-width = <4>;
+               cd-gpios = <&pioD 15 0>
+               cd-inverted;
+       };
+       slot@1 {
+               reg = <1>;
+               bus-width = <4>;
+       };
+};
diff --git a/Documentation/devicetree/bindings/mmc/pxa-mmc.txt b/Documentation/devicetree/bindings/mmc/pxa-mmc.txt
new file mode 100644 (file)
index 0000000..b7025de
--- /dev/null
@@ -0,0 +1,25 @@
+* PXA MMC drivers
+
+Driver bindings for the PXA MCI (MMC/SDIO) interfaces
+
+Required properties:
+- compatible: Should be "marvell,pxa-mmc".
+- vmmc-supply: A regulator for VMMC
+
+Optional properties:
+- marvell,detect-delay-ms: sets the detection delay timeout in ms.
+- marvell,gpio-power: GPIO spec for the card power enable pin
+
+This file documents differences between the core properties in mmc.txt
+and the properties used by the pxa-mmc driver.
+
+Examples:
+
+mmc0: mmc@41100000 {
+       compatible = "marvell,pxa-mmc";
+       reg = <0x41100000 0x1000>;
+       interrupts = <23>;
+       cd-gpios = <&gpio 23 0>;
+       wp-gpios = <&gpio 24 0>;
+};
+
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-dove.txt b/Documentation/devicetree/bindings/mmc/sdhci-dove.txt
new file mode 100644 (file)
index 0000000..ae9aab9
--- /dev/null
@@ -0,0 +1,14 @@
+* Marvell sdhci-dove controller
+
+This file documents differences between the core properties in mmc.txt
+and the properties used by the sdhci-pxav2 and sdhci-pxav3 drivers.
+
+- compatible: Should be "marvell,dove-sdhci".
+
+Example:
+
+sdio0: sdio@92000 {
+       compatible = "marvell,dove-sdhci";
+       reg = <0x92000 0x100>;
+       interrupts = <35>;
+};
index a20069502f5aaeeb85c45978bcf13c67f598e962..d555421ea49f8237d5a8a0c1822facd379b60f1b 100644 (file)
@@ -3,7 +3,9 @@ Atmel NAND flash
 Required properties:
 - compatible : "atmel,at91rm9200-nand".
 - reg : should specify localbus address and size used for the chip,
-       and if availlable the ECC.
+       and hardware ECC controller if available.
+       If the hardware ECC is PMECC, it should contain address and size for
+       PMECC, PMECC Error Location controller and ROM which has lookup tables.
 - atmel,nand-addr-offset : offset for the address latch.
 - atmel,nand-cmd-offset : offset for the command latch.
 - #address-cells, #size-cells : Must be present if the device has sub-nodes
@@ -16,6 +18,15 @@ Optional properties:
 - nand-ecc-mode : String, operation mode of the NAND ecc mode, soft by default.
   Supported values are: "none", "soft", "hw", "hw_syndrome", "hw_oob_first",
   "soft_bch".
+- atmel,has-pmecc : boolean to enable Programmable Multibit ECC hardware.
+  Only supported by at91sam9x5 or later sam9 product.
+- atmel,pmecc-cap : error correct capability for Programmable Multibit ECC
+  Controller. Supported values are: 2, 4, 8, 12, 24.
+- atmel,pmecc-sector-size : sector size for ECC computation. Supported values
+  are: 512, 1024.
+- atmel,pmecc-lookup-table-offset : includes two offsets of lookup table in ROM
+  for different sector size. First one is for sector size 512, the next is for
+  sector size 1024.
 - nand-bus-width : 8 or 16 bus width if not present 8
 - nand-on-flash-bbt: boolean to enable on flash bbt option if not present false
 
@@ -39,3 +50,30 @@ nand0: nand@40000000,0 {
                ...
        };
 };
+
+/* for PMECC supported chips */
+nand0: nand@40000000 {
+       compatible = "atmel,at91rm9200-nand";
+       #address-cells = <1>;
+       #size-cells = <1>;
+       reg = < 0x40000000 0x10000000   /* bus addr & size */
+               0xffffe000 0x00000600   /* PMECC addr & size */
+               0xffffe600 0x00000200   /* PMECC ERRLOC addr & size */
+               0x00100000 0x00100000   /* ROM addr & size */
+               >;
+       atmel,nand-addr-offset = <21>;  /* ale */
+       atmel,nand-cmd-offset = <22>;   /* cle */
+       nand-on-flash-bbt;
+       nand-ecc-mode = "hw";
+       atmel,has-pmecc;        /* enable PMECC */
+       atmel,pmecc-cap = <2>;
+       atmel,pmecc-sector-size = <512>;
+       atmel,pmecc-lookup-table-offset = <0x8000 0x10000>;
+       gpios = <&pioD 5 0      /* rdy */
+                &pioD 4 0      /* nce */
+                0              /* cd */
+               >;
+       partition@0 {
+               ...
+       };
+};
index 1a5bbd346d223a4d3d0429b7abd57595b025763b..3fb3f9015365d0c15d1b4219838d6d16bef9cc53 100644 (file)
@@ -12,6 +12,10 @@ Required properties:
   - interrupt-names : The interrupt names "gpmi-dma", "bch";
   - fsl,gpmi-dma-channel : Should contain the dma channel it uses.
 
+Optional properties:
+  - nand-on-flash-bbt: boolean to enable on flash bbt option if not
+                       present false
+
 The device tree may optionally contain sub-nodes describing partitions of the
 address space. See partition.txt for more detail.
 
diff --git a/Documentation/devicetree/bindings/mtd/lpc32xx-mlc.txt b/Documentation/devicetree/bindings/mtd/lpc32xx-mlc.txt
new file mode 100644 (file)
index 0000000..d0a3725
--- /dev/null
@@ -0,0 +1,50 @@
+NXP LPC32xx SoC NAND MLC controller
+
+Required properties:
+- compatible: "nxp,lpc3220-mlc"
+- reg: Address and size of the controller
+- interrupts: The NAND interrupt specification
+- gpios: GPIO specification for NAND write protect
+
+The following required properties are very controller specific. See the LPC32xx
+User Manual 7.5.14 MLC NAND Timing Register (the values here are specified in
+Hz, to make them independent of actual clock speed and to provide for good
+accuracy:)
+- nxp,tcea_delay: TCEA_DELAY
+- nxp,busy_delay: BUSY_DELAY
+- nxp,nand_ta: NAND_TA
+- nxp,rd_high: RD_HIGH
+- nxp,rd_low: RD_LOW
+- nxp,wr_high: WR_HIGH
+- nxp,wr_low: WR_LOW
+
+Optional subnodes:
+- Partitions, see Documentation/devicetree/bindings/mtd/partition.txt
+
+Example:
+
+       mlc: flash@200A8000 {
+               compatible = "nxp,lpc3220-mlc";
+               reg = <0x200A8000 0x11000>;
+               interrupts = <11 0>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+
+               nxp,tcea-delay = <333333333>;
+               nxp,busy-delay = <10000000>;
+               nxp,nand-ta = <18181818>;
+               nxp,rd-high = <31250000>;
+               nxp,rd-low = <45454545>;
+               nxp,wr-high = <40000000>;
+               nxp,wr-low = <83333333>;
+               gpios = <&gpio 5 19 1>; /* GPO_P3 19, active low */
+
+               mtd0@00000000 {
+                       label = "boot";
+                       reg = <0x00000000 0x00064000>;
+                       read-only;
+               };
+
+               ...
+
+       };
diff --git a/Documentation/devicetree/bindings/mtd/lpc32xx-slc.txt b/Documentation/devicetree/bindings/mtd/lpc32xx-slc.txt
new file mode 100644 (file)
index 0000000..d94edc0
--- /dev/null
@@ -0,0 +1,52 @@
+NXP LPC32xx SoC NAND SLC controller
+
+Required properties:
+- compatible: "nxp,lpc3220-slc"
+- reg: Address and size of the controller
+- nand-on-flash-bbt: Use bad block table on flash
+- gpios: GPIO specification for NAND write protect
+
+The following required properties are very controller specific. See the LPC32xx
+User Manual:
+- nxp,wdr-clks: Delay before Ready signal is tested on write (W_RDY)
+- nxp,rdr-clks: Delay before Ready signal is tested on read (R_RDY)
+(The following values are specified in Hz, to make them independent of actual
+clock speed:)
+- nxp,wwidth: Write pulse width (W_WIDTH)
+- nxp,whold: Write hold time (W_HOLD)
+- nxp,wsetup: Write setup time (W_SETUP)
+- nxp,rwidth: Read pulse width (R_WIDTH)
+- nxp,rhold: Read hold time (R_HOLD)
+- nxp,rsetup: Read setup time (R_SETUP)
+
+Optional subnodes:
+- Partitions, see Documentation/devicetree/bindings/mtd/partition.txt
+
+Example:
+
+       slc: flash@20020000 {
+               compatible = "nxp,lpc3220-slc";
+               reg = <0x20020000 0x1000>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+
+               nxp,wdr-clks = <14>;
+               nxp,wwidth = <40000000>;
+               nxp,whold = <100000000>;
+               nxp,wsetup = <100000000>;
+               nxp,rdr-clks = <14>;
+               nxp,rwidth = <40000000>;
+               nxp,rhold = <66666666>;
+               nxp,rsetup = <100000000>;
+               nand-on-flash-bbt;
+               gpios = <&gpio 5 19 1>; /* GPO_P3 19, active low */
+
+               mtd0@00000000 {
+                       label = "phy3250-boot";
+                       reg = <0x00000000 0x00064000>;
+                       read-only;
+               };
+
+               ...
+
+       };
diff --git a/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt b/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt
new file mode 100644 (file)
index 0000000..f1421e2
--- /dev/null
@@ -0,0 +1,31 @@
+PXA3xx NAND DT bindings
+
+Required properties:
+
+ - compatible:         Should be "marvell,pxa3xx-nand"
+ - reg:                The register base for the controller
+ - interrupts:         The interrupt to map
+ - #address-cells:     Set to <1> if the node includes partitions
+
+Optional properties:
+
+ - marvell,nand-enable-arbiter:        Set to enable the bus arbiter
+ - marvell,nand-keep-config:   Set to keep the NAND controller config as set
+                               by the bootloader
+ - num-cs:                     Number of chipselect lines to usw
+
+Example:
+
+       nand0: nand@43100000 {
+               compatible = "marvell,pxa3xx-nand";
+               reg = <0x43100000 90>;
+               interrupts = <45>;
+               #address-cells = <1>;
+
+               marvell,nand-enable-arbiter;
+               marvell,nand-keep-config;
+               num-cs = <1>;
+
+               /* partitions (optional) */
+       };
+
diff --git a/Documentation/devicetree/bindings/net/cpsw.txt b/Documentation/devicetree/bindings/net/cpsw.txt
new file mode 100644 (file)
index 0000000..dcaabe9
--- /dev/null
@@ -0,0 +1,109 @@
+TI SoC Ethernet Switch Controller Device Tree Bindings
+------------------------------------------------------
+
+Required properties:
+- compatible           : Should be "ti,cpsw"
+- reg                  : physical base address and size of the cpsw
+                         registers map
+- interrupts           : property with a value describing the interrupt
+                         number
+- interrupt-parent     : The parent interrupt controller
+- cpdma_channels       : Specifies number of channels in CPDMA
+- host_port_no         : Specifies host port shift
+- cpdma_reg_ofs                : Specifies CPDMA submodule register offset
+- cpdma_sram_ofs       : Specifies CPDMA SRAM offset
+- ale_reg_ofs          : Specifies ALE submodule register offset
+- ale_entries          : Specifies No of entries ALE can hold
+- host_port_reg_ofs    : Specifies host port register offset
+- hw_stats_reg_ofs     : Specifies hardware statistics register offset
+- bd_ram_ofs           : Specifies internal desciptor RAM offset
+- bd_ram_size          : Specifies internal descriptor RAM size
+- rx_descs             : Specifies number of Rx descriptors
+- mac_control          : Specifies Default MAC control register content
+                         for the specific platform
+- slaves               : Specifies number for slaves
+- slave_reg_ofs                : Specifies slave register offset
+- sliver_reg_ofs       : Specifies slave sliver register offset
+- phy_id               : Specifies slave phy id
+- mac-address          : Specifies slave MAC address
+
+Optional properties:
+- ti,hwmods            : Must be "cpgmac0"
+- no_bd_ram            : Must be 0 or 1
+
+Note: "ti,hwmods" field is used to fetch the base address and irq
+resources from TI, omap hwmod data base during device registration.
+Future plan is to migrate hwmod data base contents into device tree
+blob so that, all the required data will be used from device tree dts
+file.
+
+Examples:
+
+       mac: ethernet@4A100000 {
+               compatible = "ti,cpsw";
+               reg = <0x4A100000 0x1000>;
+               interrupts = <55 0x4>;
+               interrupt-parent = <&intc>;
+               cpdma_channels = <8>;
+               host_port_no = <0>;
+               cpdma_reg_ofs = <0x800>;
+               cpdma_sram_ofs = <0xa00>;
+               ale_reg_ofs = <0xd00>;
+               ale_entries = <1024>;
+               host_port_reg_ofs = <0x108>;
+               hw_stats_reg_ofs = <0x900>;
+               bd_ram_ofs = <0x2000>;
+               bd_ram_size = <0x2000>;
+               no_bd_ram = <0>;
+               rx_descs = <64>;
+               mac_control = <0x20>;
+               slaves = <2>;
+               cpsw_emac0: slave@0 {
+                       slave_reg_ofs = <0x208>;
+                       sliver_reg_ofs = <0xd80>;
+                       phy_id = "davinci_mdio.16:00";
+                       /* Filled in by U-Boot */
+                       mac-address = [ 00 00 00 00 00 00 ];
+               };
+               cpsw_emac1: slave@1 {
+                       slave_reg_ofs = <0x308>;
+                       sliver_reg_ofs = <0xdc0>;
+                       phy_id = "davinci_mdio.16:01";
+                       /* Filled in by U-Boot */
+                       mac-address = [ 00 00 00 00 00 00 ];
+               };
+       };
+
+(or)
+       mac: ethernet@4A100000 {
+               compatible = "ti,cpsw";
+               ti,hwmods = "cpgmac0";
+               cpdma_channels = <8>;
+               host_port_no = <0>;
+               cpdma_reg_ofs = <0x800>;
+               cpdma_sram_ofs = <0xa00>;
+               ale_reg_ofs = <0xd00>;
+               ale_entries = <1024>;
+               host_port_reg_ofs = <0x108>;
+               hw_stats_reg_ofs = <0x900>;
+               bd_ram_ofs = <0x2000>;
+               bd_ram_size = <0x2000>;
+               no_bd_ram = <0>;
+               rx_descs = <64>;
+               mac_control = <0x20>;
+               slaves = <2>;
+               cpsw_emac0: slave@0 {
+                       slave_reg_ofs = <0x208>;
+                       sliver_reg_ofs = <0xd80>;
+                       phy_id = "davinci_mdio.16:00";
+                       /* Filled in by U-Boot */
+                       mac-address = [ 00 00 00 00 00 00 ];
+               };
+               cpsw_emac1: slave@1 {
+                       slave_reg_ofs = <0x308>;
+                       sliver_reg_ofs = <0xdc0>;
+                       phy_id = "davinci_mdio.16:01";
+                       /* Filled in by U-Boot */
+                       mac-address = [ 00 00 00 00 00 00 ];
+               };
+       };
diff --git a/Documentation/devicetree/bindings/net/davinci-mdio.txt b/Documentation/devicetree/bindings/net/davinci-mdio.txt
new file mode 100644 (file)
index 0000000..72efaaf
--- /dev/null
@@ -0,0 +1,33 @@
+TI SoC Davinci MDIO Controller Device Tree Bindings
+---------------------------------------------------
+
+Required properties:
+- compatible           : Should be "ti,davinci_mdio"
+- reg                  : physical base address and size of the davinci mdio
+                         registers map
+- bus_freq             : Mdio Bus frequency
+
+Optional properties:
+- ti,hwmods            : Must be "davinci_mdio"
+
+Note: "ti,hwmods" field is used to fetch the base address and irq
+resources from TI, omap hwmod data base during device registration.
+Future plan is to migrate hwmod data base contents into device tree
+blob so that, all the required data will be used from device tree dts
+file.
+
+Examples:
+
+       mdio: davinci_mdio@4A101000 {
+               compatible = "ti,cpsw";
+               reg = <0x4A101000 0x1000>;
+               bus_freq = <1000000>;
+       };
+
+(or)
+
+       mdio: davinci_mdio@4A101000 {
+               compatible = "ti,cpsw";
+               ti,hwmods = "davinci_mdio";
+               bus_freq = <1000000>;
+       };
diff --git a/Documentation/devicetree/bindings/pinctrl/fsl,imx35-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/fsl,imx35-pinctrl.txt
new file mode 100644 (file)
index 0000000..1183f1a
--- /dev/null
@@ -0,0 +1,984 @@
+* Freescale IMX35 IOMUX Controller
+
+Please refer to fsl,imx-pinctrl.txt in this directory for common binding part
+and usage.
+
+Required properties:
+- compatible: "fsl,imx35-iomuxc"
+- fsl,pins: two integers array, represents a group of pins mux and config
+  setting. The format is fsl,pins = <PIN_FUNC_ID CONFIG>, PIN_FUNC_ID is a
+  pin working on a specific function, CONFIG is the pad setting value like
+  pull-up for this pin. Please refer to imx35 datasheet for the valid pad
+  config settings.
+
+CONFIG bits definition:
+PAD_CTL_DRIVE_VOLAGAGE_18      (1 << 13)
+PAD_CTL_DRIVE_VOLAGAGE_33      (0 << 13)
+PAD_CTL_HYS                    (1 << 8)
+PAD_CTL_PKE                    (1 << 7)
+PAD_CTL_PUE                    (1 << 6)
+PAD_CTL_PUS_100K_DOWN          (0 << 4)
+PAD_CTL_PUS_47K_UP             (1 << 4)
+PAD_CTL_PUS_100K_UP            (2 << 4)
+PAD_CTL_PUS_22K_UP             (3 << 4)
+PAD_CTL_ODE_CMOS               (0 << 3)
+PAD_CTL_ODE_OPENDRAIN          (1 << 3)
+PAD_CTL_DSE_NOMINAL            (0 << 1)
+PAD_CTL_DSE_HIGH               (1 << 1)
+PAD_CTL_DSE_MAX                        (2 << 1)
+PAD_CTL_SRE_FAST               (1 << 0)
+PAD_CTL_SRE_SLOW               (0 << 0)
+
+See below for available PIN_FUNC_ID for imx35:
+0 MX35_PAD_CAPTURE__GPT_CAPIN1
+1 MX35_PAD_CAPTURE__GPT_CMPOUT2
+2 MX35_PAD_CAPTURE__CSPI2_SS1
+3 MX35_PAD_CAPTURE__EPIT1_EPITO
+4 MX35_PAD_CAPTURE__CCM_CLK32K
+5 MX35_PAD_CAPTURE__GPIO1_4
+6 MX35_PAD_COMPARE__GPT_CMPOUT1
+7 MX35_PAD_COMPARE__GPT_CAPIN2
+8 MX35_PAD_COMPARE__GPT_CMPOUT3
+9 MX35_PAD_COMPARE__EPIT2_EPITO
+10 MX35_PAD_COMPARE__GPIO1_5
+11 MX35_PAD_COMPARE__SDMA_EXTDMA_2
+12 MX35_PAD_WDOG_RST__WDOG_WDOG_B
+13 MX35_PAD_WDOG_RST__IPU_FLASH_STROBE
+14 MX35_PAD_WDOG_RST__GPIO1_6
+15 MX35_PAD_GPIO1_0__GPIO1_0
+16 MX35_PAD_GPIO1_0__CCM_PMIC_RDY
+17 MX35_PAD_GPIO1_0__OWIRE_LINE
+18 MX35_PAD_GPIO1_0__SDMA_EXTDMA_0
+19 MX35_PAD_GPIO1_1__GPIO1_1
+20 MX35_PAD_GPIO1_1__PWM_PWMO
+21 MX35_PAD_GPIO1_1__CSPI1_SS2
+22 MX35_PAD_GPIO1_1__SCC_TAMPER_DETECT
+23 MX35_PAD_GPIO1_1__SDMA_EXTDMA_1
+24 MX35_PAD_GPIO2_0__GPIO2_0
+25 MX35_PAD_GPIO2_0__USB_TOP_USBOTG_CLK
+26 MX35_PAD_GPIO3_0__GPIO3_0
+27 MX35_PAD_GPIO3_0__USB_TOP_USBH2_CLK
+28 MX35_PAD_RESET_IN_B__CCM_RESET_IN_B
+29 MX35_PAD_POR_B__CCM_POR_B
+30 MX35_PAD_CLKO__CCM_CLKO
+31 MX35_PAD_CLKO__GPIO1_8
+32 MX35_PAD_BOOT_MODE0__CCM_BOOT_MODE_0
+33 MX35_PAD_BOOT_MODE1__CCM_BOOT_MODE_1
+34 MX35_PAD_CLK_MODE0__CCM_CLK_MODE_0
+35 MX35_PAD_CLK_MODE1__CCM_CLK_MODE_1
+36 MX35_PAD_POWER_FAIL__CCM_DSM_WAKEUP_INT_26
+37 MX35_PAD_VSTBY__CCM_VSTBY
+38 MX35_PAD_VSTBY__GPIO1_7
+39 MX35_PAD_A0__EMI_EIM_DA_L_0
+40 MX35_PAD_A1__EMI_EIM_DA_L_1
+41 MX35_PAD_A2__EMI_EIM_DA_L_2
+42 MX35_PAD_A3__EMI_EIM_DA_L_3
+43 MX35_PAD_A4__EMI_EIM_DA_L_4
+44 MX35_PAD_A5__EMI_EIM_DA_L_5
+45 MX35_PAD_A6__EMI_EIM_DA_L_6
+46 MX35_PAD_A7__EMI_EIM_DA_L_7
+47 MX35_PAD_A8__EMI_EIM_DA_H_8
+48 MX35_PAD_A9__EMI_EIM_DA_H_9
+49 MX35_PAD_A10__EMI_EIM_DA_H_10
+50 MX35_PAD_MA10__EMI_MA10
+51 MX35_PAD_A11__EMI_EIM_DA_H_11
+52 MX35_PAD_A12__EMI_EIM_DA_H_12
+53 MX35_PAD_A13__EMI_EIM_DA_H_13
+54 MX35_PAD_A14__EMI_EIM_DA_H2_14
+55 MX35_PAD_A15__EMI_EIM_DA_H2_15
+56 MX35_PAD_A16__EMI_EIM_A_16
+57 MX35_PAD_A17__EMI_EIM_A_17
+58 MX35_PAD_A18__EMI_EIM_A_18
+59 MX35_PAD_A19__EMI_EIM_A_19
+60 MX35_PAD_A20__EMI_EIM_A_20
+61 MX35_PAD_A21__EMI_EIM_A_21
+62 MX35_PAD_A22__EMI_EIM_A_22
+63 MX35_PAD_A23__EMI_EIM_A_23
+64 MX35_PAD_A24__EMI_EIM_A_24
+65 MX35_PAD_A25__EMI_EIM_A_25
+66 MX35_PAD_SDBA1__EMI_EIM_SDBA1
+67 MX35_PAD_SDBA0__EMI_EIM_SDBA0
+68 MX35_PAD_SD0__EMI_DRAM_D_0
+69 MX35_PAD_SD1__EMI_DRAM_D_1
+70 MX35_PAD_SD2__EMI_DRAM_D_2
+71 MX35_PAD_SD3__EMI_DRAM_D_3
+72 MX35_PAD_SD4__EMI_DRAM_D_4
+73 MX35_PAD_SD5__EMI_DRAM_D_5
+74 MX35_PAD_SD6__EMI_DRAM_D_6
+75 MX35_PAD_SD7__EMI_DRAM_D_7
+76 MX35_PAD_SD8__EMI_DRAM_D_8
+77 MX35_PAD_SD9__EMI_DRAM_D_9
+78 MX35_PAD_SD10__EMI_DRAM_D_10
+79 MX35_PAD_SD11__EMI_DRAM_D_11
+80 MX35_PAD_SD12__EMI_DRAM_D_12
+81 MX35_PAD_SD13__EMI_DRAM_D_13
+82 MX35_PAD_SD14__EMI_DRAM_D_14
+83 MX35_PAD_SD15__EMI_DRAM_D_15
+84 MX35_PAD_SD16__EMI_DRAM_D_16
+85 MX35_PAD_SD17__EMI_DRAM_D_17
+86 MX35_PAD_SD18__EMI_DRAM_D_18
+87 MX35_PAD_SD19__EMI_DRAM_D_19
+88 MX35_PAD_SD20__EMI_DRAM_D_20
+89 MX35_PAD_SD21__EMI_DRAM_D_21
+90 MX35_PAD_SD22__EMI_DRAM_D_22
+91 MX35_PAD_SD23__EMI_DRAM_D_23
+92 MX35_PAD_SD24__EMI_DRAM_D_24
+93 MX35_PAD_SD25__EMI_DRAM_D_25
+94 MX35_PAD_SD26__EMI_DRAM_D_26
+95 MX35_PAD_SD27__EMI_DRAM_D_27
+96 MX35_PAD_SD28__EMI_DRAM_D_28
+97 MX35_PAD_SD29__EMI_DRAM_D_29
+98 MX35_PAD_SD30__EMI_DRAM_D_30
+99 MX35_PAD_SD31__EMI_DRAM_D_31
+100 MX35_PAD_DQM0__EMI_DRAM_DQM_0
+101 MX35_PAD_DQM1__EMI_DRAM_DQM_1
+102 MX35_PAD_DQM2__EMI_DRAM_DQM_2
+103 MX35_PAD_DQM3__EMI_DRAM_DQM_3
+104 MX35_PAD_EB0__EMI_EIM_EB0_B
+105 MX35_PAD_EB1__EMI_EIM_EB1_B
+106 MX35_PAD_OE__EMI_EIM_OE
+107 MX35_PAD_CS0__EMI_EIM_CS0
+108 MX35_PAD_CS1__EMI_EIM_CS1
+109 MX35_PAD_CS1__EMI_NANDF_CE3
+110 MX35_PAD_CS2__EMI_EIM_CS2
+111 MX35_PAD_CS3__EMI_EIM_CS3
+112 MX35_PAD_CS4__EMI_EIM_CS4
+113 MX35_PAD_CS4__EMI_DTACK_B
+114 MX35_PAD_CS4__EMI_NANDF_CE1
+115 MX35_PAD_CS4__GPIO1_20
+116 MX35_PAD_CS5__EMI_EIM_CS5
+117 MX35_PAD_CS5__CSPI2_SS2
+118 MX35_PAD_CS5__CSPI1_SS2
+119 MX35_PAD_CS5__EMI_NANDF_CE2
+120 MX35_PAD_CS5__GPIO1_21
+121 MX35_PAD_NF_CE0__EMI_NANDF_CE0
+122 MX35_PAD_NF_CE0__GPIO1_22
+123 MX35_PAD_ECB__EMI_EIM_ECB
+124 MX35_PAD_LBA__EMI_EIM_LBA
+125 MX35_PAD_BCLK__EMI_EIM_BCLK
+126 MX35_PAD_RW__EMI_EIM_RW
+127 MX35_PAD_RAS__EMI_DRAM_RAS
+128 MX35_PAD_CAS__EMI_DRAM_CAS
+129 MX35_PAD_SDWE__EMI_DRAM_SDWE
+130 MX35_PAD_SDCKE0__EMI_DRAM_SDCKE_0
+131 MX35_PAD_SDCKE1__EMI_DRAM_SDCKE_1
+132 MX35_PAD_SDCLK__EMI_DRAM_SDCLK
+133 MX35_PAD_SDQS0__EMI_DRAM_SDQS_0
+134 MX35_PAD_SDQS1__EMI_DRAM_SDQS_1
+135 MX35_PAD_SDQS2__EMI_DRAM_SDQS_2
+136 MX35_PAD_SDQS3__EMI_DRAM_SDQS_3
+137 MX35_PAD_NFWE_B__EMI_NANDF_WE_B
+138 MX35_PAD_NFWE_B__USB_TOP_USBH2_DATA_3
+139 MX35_PAD_NFWE_B__IPU_DISPB_D0_VSYNC
+140 MX35_PAD_NFWE_B__GPIO2_18
+141 MX35_PAD_NFWE_B__ARM11P_TOP_TRACE_0
+142 MX35_PAD_NFRE_B__EMI_NANDF_RE_B
+143 MX35_PAD_NFRE_B__USB_TOP_USBH2_DIR
+144 MX35_PAD_NFRE_B__IPU_DISPB_BCLK
+145 MX35_PAD_NFRE_B__GPIO2_19
+146 MX35_PAD_NFRE_B__ARM11P_TOP_TRACE_1
+147 MX35_PAD_NFALE__EMI_NANDF_ALE
+148 MX35_PAD_NFALE__USB_TOP_USBH2_STP
+149 MX35_PAD_NFALE__IPU_DISPB_CS0
+150 MX35_PAD_NFALE__GPIO2_20
+151 MX35_PAD_NFALE__ARM11P_TOP_TRACE_2
+152 MX35_PAD_NFCLE__EMI_NANDF_CLE
+153 MX35_PAD_NFCLE__USB_TOP_USBH2_NXT
+154 MX35_PAD_NFCLE__IPU_DISPB_PAR_RS
+155 MX35_PAD_NFCLE__GPIO2_21
+156 MX35_PAD_NFCLE__ARM11P_TOP_TRACE_3
+157 MX35_PAD_NFWP_B__EMI_NANDF_WP_B
+158 MX35_PAD_NFWP_B__USB_TOP_USBH2_DATA_7
+159 MX35_PAD_NFWP_B__IPU_DISPB_WR
+160 MX35_PAD_NFWP_B__GPIO2_22
+161 MX35_PAD_NFWP_B__ARM11P_TOP_TRCTL
+162 MX35_PAD_NFRB__EMI_NANDF_RB
+163 MX35_PAD_NFRB__IPU_DISPB_RD
+164 MX35_PAD_NFRB__GPIO2_23
+165 MX35_PAD_NFRB__ARM11P_TOP_TRCLK
+166 MX35_PAD_D15__EMI_EIM_D_15
+167 MX35_PAD_D14__EMI_EIM_D_14
+168 MX35_PAD_D13__EMI_EIM_D_13
+169 MX35_PAD_D12__EMI_EIM_D_12
+170 MX35_PAD_D11__EMI_EIM_D_11
+171 MX35_PAD_D10__EMI_EIM_D_10
+172 MX35_PAD_D9__EMI_EIM_D_9
+173 MX35_PAD_D8__EMI_EIM_D_8
+174 MX35_PAD_D7__EMI_EIM_D_7
+175 MX35_PAD_D6__EMI_EIM_D_6
+176 MX35_PAD_D5__EMI_EIM_D_5
+177 MX35_PAD_D4__EMI_EIM_D_4
+178 MX35_PAD_D3__EMI_EIM_D_3
+179 MX35_PAD_D2__EMI_EIM_D_2
+180 MX35_PAD_D1__EMI_EIM_D_1
+181 MX35_PAD_D0__EMI_EIM_D_0
+182 MX35_PAD_CSI_D8__IPU_CSI_D_8
+183 MX35_PAD_CSI_D8__KPP_COL_0
+184 MX35_PAD_CSI_D8__GPIO1_20
+185 MX35_PAD_CSI_D8__ARM11P_TOP_EVNTBUS_13
+186 MX35_PAD_CSI_D9__IPU_CSI_D_9
+187 MX35_PAD_CSI_D9__KPP_COL_1
+188 MX35_PAD_CSI_D9__GPIO1_21
+189 MX35_PAD_CSI_D9__ARM11P_TOP_EVNTBUS_14
+190 MX35_PAD_CSI_D10__IPU_CSI_D_10
+191 MX35_PAD_CSI_D10__KPP_COL_2
+192 MX35_PAD_CSI_D10__GPIO1_22
+193 MX35_PAD_CSI_D10__ARM11P_TOP_EVNTBUS_15
+194 MX35_PAD_CSI_D11__IPU_CSI_D_11
+195 MX35_PAD_CSI_D11__KPP_COL_3
+196 MX35_PAD_CSI_D11__GPIO1_23
+197 MX35_PAD_CSI_D12__IPU_CSI_D_12
+198 MX35_PAD_CSI_D12__KPP_ROW_0
+199 MX35_PAD_CSI_D12__GPIO1_24
+200 MX35_PAD_CSI_D13__IPU_CSI_D_13
+201 MX35_PAD_CSI_D13__KPP_ROW_1
+202 MX35_PAD_CSI_D13__GPIO1_25
+203 MX35_PAD_CSI_D14__IPU_CSI_D_14
+204 MX35_PAD_CSI_D14__KPP_ROW_2
+205 MX35_PAD_CSI_D14__GPIO1_26
+206 MX35_PAD_CSI_D15__IPU_CSI_D_15
+207 MX35_PAD_CSI_D15__KPP_ROW_3
+208 MX35_PAD_CSI_D15__GPIO1_27
+209 MX35_PAD_CSI_MCLK__IPU_CSI_MCLK
+210 MX35_PAD_CSI_MCLK__GPIO1_28
+211 MX35_PAD_CSI_VSYNC__IPU_CSI_VSYNC
+212 MX35_PAD_CSI_VSYNC__GPIO1_29
+213 MX35_PAD_CSI_HSYNC__IPU_CSI_HSYNC
+214 MX35_PAD_CSI_HSYNC__GPIO1_30
+215 MX35_PAD_CSI_PIXCLK__IPU_CSI_PIXCLK
+216 MX35_PAD_CSI_PIXCLK__GPIO1_31
+217 MX35_PAD_I2C1_CLK__I2C1_SCL
+218 MX35_PAD_I2C1_CLK__GPIO2_24
+219 MX35_PAD_I2C1_CLK__CCM_USB_BYP_CLK
+220 MX35_PAD_I2C1_DAT__I2C1_SDA
+221 MX35_PAD_I2C1_DAT__GPIO2_25
+222 MX35_PAD_I2C2_CLK__I2C2_SCL
+223 MX35_PAD_I2C2_CLK__CAN1_TXCAN
+224 MX35_PAD_I2C2_CLK__USB_TOP_USBH2_PWR
+225 MX35_PAD_I2C2_CLK__GPIO2_26
+226 MX35_PAD_I2C2_CLK__SDMA_DEBUG_BUS_DEVICE_2
+227 MX35_PAD_I2C2_DAT__I2C2_SDA
+228 MX35_PAD_I2C2_DAT__CAN1_RXCAN
+229 MX35_PAD_I2C2_DAT__USB_TOP_USBH2_OC
+230 MX35_PAD_I2C2_DAT__GPIO2_27
+231 MX35_PAD_I2C2_DAT__SDMA_DEBUG_BUS_DEVICE_3
+232 MX35_PAD_STXD4__AUDMUX_AUD4_TXD
+233 MX35_PAD_STXD4__GPIO2_28
+234 MX35_PAD_STXD4__ARM11P_TOP_ARM_COREASID0
+235 MX35_PAD_SRXD4__AUDMUX_AUD4_RXD
+236 MX35_PAD_SRXD4__GPIO2_29
+237 MX35_PAD_SRXD4__ARM11P_TOP_ARM_COREASID1
+238 MX35_PAD_SCK4__AUDMUX_AUD4_TXC
+239 MX35_PAD_SCK4__GPIO2_30
+240 MX35_PAD_SCK4__ARM11P_TOP_ARM_COREASID2
+241 MX35_PAD_STXFS4__AUDMUX_AUD4_TXFS
+242 MX35_PAD_STXFS4__GPIO2_31
+243 MX35_PAD_STXFS4__ARM11P_TOP_ARM_COREASID3
+244 MX35_PAD_STXD5__AUDMUX_AUD5_TXD
+245 MX35_PAD_STXD5__SPDIF_SPDIF_OUT1
+246 MX35_PAD_STXD5__CSPI2_MOSI
+247 MX35_PAD_STXD5__GPIO1_0
+248 MX35_PAD_STXD5__ARM11P_TOP_ARM_COREASID4
+249 MX35_PAD_SRXD5__AUDMUX_AUD5_RXD
+250 MX35_PAD_SRXD5__SPDIF_SPDIF_IN1
+251 MX35_PAD_SRXD5__CSPI2_MISO
+252 MX35_PAD_SRXD5__GPIO1_1
+253 MX35_PAD_SRXD5__ARM11P_TOP_ARM_COREASID5
+254 MX35_PAD_SCK5__AUDMUX_AUD5_TXC
+255 MX35_PAD_SCK5__SPDIF_SPDIF_EXTCLK
+256 MX35_PAD_SCK5__CSPI2_SCLK
+257 MX35_PAD_SCK5__GPIO1_2
+258 MX35_PAD_SCK5__ARM11P_TOP_ARM_COREASID6
+259 MX35_PAD_STXFS5__AUDMUX_AUD5_TXFS
+260 MX35_PAD_STXFS5__CSPI2_RDY
+261 MX35_PAD_STXFS5__GPIO1_3
+262 MX35_PAD_STXFS5__ARM11P_TOP_ARM_COREASID7
+263 MX35_PAD_SCKR__ESAI_SCKR
+264 MX35_PAD_SCKR__GPIO1_4
+265 MX35_PAD_SCKR__ARM11P_TOP_EVNTBUS_10
+266 MX35_PAD_FSR__ESAI_FSR
+267 MX35_PAD_FSR__GPIO1_5
+268 MX35_PAD_FSR__ARM11P_TOP_EVNTBUS_11
+269 MX35_PAD_HCKR__ESAI_HCKR
+270 MX35_PAD_HCKR__AUDMUX_AUD5_RXFS
+271 MX35_PAD_HCKR__CSPI2_SS0
+272 MX35_PAD_HCKR__IPU_FLASH_STROBE
+273 MX35_PAD_HCKR__GPIO1_6
+274 MX35_PAD_HCKR__ARM11P_TOP_EVNTBUS_12
+275 MX35_PAD_SCKT__ESAI_SCKT
+276 MX35_PAD_SCKT__GPIO1_7
+277 MX35_PAD_SCKT__IPU_CSI_D_0
+278 MX35_PAD_SCKT__KPP_ROW_2
+279 MX35_PAD_FST__ESAI_FST
+280 MX35_PAD_FST__GPIO1_8
+281 MX35_PAD_FST__IPU_CSI_D_1
+282 MX35_PAD_FST__KPP_ROW_3
+283 MX35_PAD_HCKT__ESAI_HCKT
+284 MX35_PAD_HCKT__AUDMUX_AUD5_RXC
+285 MX35_PAD_HCKT__GPIO1_9
+286 MX35_PAD_HCKT__IPU_CSI_D_2
+287 MX35_PAD_HCKT__KPP_COL_3
+288 MX35_PAD_TX5_RX0__ESAI_TX5_RX0
+289 MX35_PAD_TX5_RX0__AUDMUX_AUD4_RXC
+290 MX35_PAD_TX5_RX0__CSPI2_SS2
+291 MX35_PAD_TX5_RX0__CAN2_TXCAN
+292 MX35_PAD_TX5_RX0__UART2_DTR
+293 MX35_PAD_TX5_RX0__GPIO1_10
+294 MX35_PAD_TX5_RX0__EMI_M3IF_CHOSEN_MASTER_0
+295 MX35_PAD_TX4_RX1__ESAI_TX4_RX1
+296 MX35_PAD_TX4_RX1__AUDMUX_AUD4_RXFS
+297 MX35_PAD_TX4_RX1__CSPI2_SS3
+298 MX35_PAD_TX4_RX1__CAN2_RXCAN
+299 MX35_PAD_TX4_RX1__UART2_DSR
+300 MX35_PAD_TX4_RX1__GPIO1_11
+301 MX35_PAD_TX4_RX1__IPU_CSI_D_3
+302 MX35_PAD_TX4_RX1__KPP_ROW_0
+303 MX35_PAD_TX3_RX2__ESAI_TX3_RX2
+304 MX35_PAD_TX3_RX2__I2C3_SCL
+305 MX35_PAD_TX3_RX2__EMI_NANDF_CE1
+306 MX35_PAD_TX3_RX2__GPIO1_12
+307 MX35_PAD_TX3_RX2__IPU_CSI_D_4
+308 MX35_PAD_TX3_RX2__KPP_ROW_1
+309 MX35_PAD_TX2_RX3__ESAI_TX2_RX3
+310 MX35_PAD_TX2_RX3__I2C3_SDA
+311 MX35_PAD_TX2_RX3__EMI_NANDF_CE2
+312 MX35_PAD_TX2_RX3__GPIO1_13
+313 MX35_PAD_TX2_RX3__IPU_CSI_D_5
+314 MX35_PAD_TX2_RX3__KPP_COL_0
+315 MX35_PAD_TX1__ESAI_TX1
+316 MX35_PAD_TX1__CCM_PMIC_RDY
+317 MX35_PAD_TX1__CSPI1_SS2
+318 MX35_PAD_TX1__EMI_NANDF_CE3
+319 MX35_PAD_TX1__UART2_RI
+320 MX35_PAD_TX1__GPIO1_14
+321 MX35_PAD_TX1__IPU_CSI_D_6
+322 MX35_PAD_TX1__KPP_COL_1
+323 MX35_PAD_TX0__ESAI_TX0
+324 MX35_PAD_TX0__SPDIF_SPDIF_EXTCLK
+325 MX35_PAD_TX0__CSPI1_SS3
+326 MX35_PAD_TX0__EMI_DTACK_B
+327 MX35_PAD_TX0__UART2_DCD
+328 MX35_PAD_TX0__GPIO1_15
+329 MX35_PAD_TX0__IPU_CSI_D_7
+330 MX35_PAD_TX0__KPP_COL_2
+331 MX35_PAD_CSPI1_MOSI__CSPI1_MOSI
+332 MX35_PAD_CSPI1_MOSI__GPIO1_16
+333 MX35_PAD_CSPI1_MOSI__ECT_CTI_TRIG_OUT1_2
+334 MX35_PAD_CSPI1_MISO__CSPI1_MISO
+335 MX35_PAD_CSPI1_MISO__GPIO1_17
+336 MX35_PAD_CSPI1_MISO__ECT_CTI_TRIG_OUT1_3
+337 MX35_PAD_CSPI1_SS0__CSPI1_SS0
+338 MX35_PAD_CSPI1_SS0__OWIRE_LINE
+339 MX35_PAD_CSPI1_SS0__CSPI2_SS3
+340 MX35_PAD_CSPI1_SS0__GPIO1_18
+341 MX35_PAD_CSPI1_SS0__ECT_CTI_TRIG_OUT1_4
+342 MX35_PAD_CSPI1_SS1__CSPI1_SS1
+343 MX35_PAD_CSPI1_SS1__PWM_PWMO
+344 MX35_PAD_CSPI1_SS1__CCM_CLK32K
+345 MX35_PAD_CSPI1_SS1__GPIO1_19
+346 MX35_PAD_CSPI1_SS1__IPU_DIAGB_29
+347 MX35_PAD_CSPI1_SS1__ECT_CTI_TRIG_OUT1_5
+348 MX35_PAD_CSPI1_SCLK__CSPI1_SCLK
+349 MX35_PAD_CSPI1_SCLK__GPIO3_4
+350 MX35_PAD_CSPI1_SCLK__IPU_DIAGB_30
+351 MX35_PAD_CSPI1_SCLK__EMI_M3IF_CHOSEN_MASTER_1
+352 MX35_PAD_CSPI1_SPI_RDY__CSPI1_RDY
+353 MX35_PAD_CSPI1_SPI_RDY__GPIO3_5
+354 MX35_PAD_CSPI1_SPI_RDY__IPU_DIAGB_31
+355 MX35_PAD_CSPI1_SPI_RDY__EMI_M3IF_CHOSEN_MASTER_2
+356 MX35_PAD_RXD1__UART1_RXD_MUX
+357 MX35_PAD_RXD1__CSPI2_MOSI
+358 MX35_PAD_RXD1__KPP_COL_4
+359 MX35_PAD_RXD1__GPIO3_6
+360 MX35_PAD_RXD1__ARM11P_TOP_EVNTBUS_16
+361 MX35_PAD_TXD1__UART1_TXD_MUX
+362 MX35_PAD_TXD1__CSPI2_MISO
+363 MX35_PAD_TXD1__KPP_COL_5
+364 MX35_PAD_TXD1__GPIO3_7
+365 MX35_PAD_TXD1__ARM11P_TOP_EVNTBUS_17
+366 MX35_PAD_RTS1__UART1_RTS
+367 MX35_PAD_RTS1__CSPI2_SCLK
+368 MX35_PAD_RTS1__I2C3_SCL
+369 MX35_PAD_RTS1__IPU_CSI_D_0
+370 MX35_PAD_RTS1__KPP_COL_6
+371 MX35_PAD_RTS1__GPIO3_8
+372 MX35_PAD_RTS1__EMI_NANDF_CE1
+373 MX35_PAD_RTS1__ARM11P_TOP_EVNTBUS_18
+374 MX35_PAD_CTS1__UART1_CTS
+375 MX35_PAD_CTS1__CSPI2_RDY
+376 MX35_PAD_CTS1__I2C3_SDA
+377 MX35_PAD_CTS1__IPU_CSI_D_1
+378 MX35_PAD_CTS1__KPP_COL_7
+379 MX35_PAD_CTS1__GPIO3_9
+380 MX35_PAD_CTS1__EMI_NANDF_CE2
+381 MX35_PAD_CTS1__ARM11P_TOP_EVNTBUS_19
+382 MX35_PAD_RXD2__UART2_RXD_MUX
+383 MX35_PAD_RXD2__KPP_ROW_4
+384 MX35_PAD_RXD2__GPIO3_10
+385 MX35_PAD_TXD2__UART2_TXD_MUX
+386 MX35_PAD_TXD2__SPDIF_SPDIF_EXTCLK
+387 MX35_PAD_TXD2__KPP_ROW_5
+388 MX35_PAD_TXD2__GPIO3_11
+389 MX35_PAD_RTS2__UART2_RTS
+390 MX35_PAD_RTS2__SPDIF_SPDIF_IN1
+391 MX35_PAD_RTS2__CAN2_RXCAN
+392 MX35_PAD_RTS2__IPU_CSI_D_2
+393 MX35_PAD_RTS2__KPP_ROW_6
+394 MX35_PAD_RTS2__GPIO3_12
+395 MX35_PAD_RTS2__AUDMUX_AUD5_RXC
+396 MX35_PAD_RTS2__UART3_RXD_MUX
+397 MX35_PAD_CTS2__UART2_CTS
+398 MX35_PAD_CTS2__SPDIF_SPDIF_OUT1
+399 MX35_PAD_CTS2__CAN2_TXCAN
+400 MX35_PAD_CTS2__IPU_CSI_D_3
+401 MX35_PAD_CTS2__KPP_ROW_7
+402 MX35_PAD_CTS2__GPIO3_13
+403 MX35_PAD_CTS2__AUDMUX_AUD5_RXFS
+404 MX35_PAD_CTS2__UART3_TXD_MUX
+405 MX35_PAD_RTCK__ARM11P_TOP_RTCK
+406 MX35_PAD_TCK__SJC_TCK
+407 MX35_PAD_TMS__SJC_TMS
+408 MX35_PAD_TDI__SJC_TDI
+409 MX35_PAD_TDO__SJC_TDO
+410 MX35_PAD_TRSTB__SJC_TRSTB
+411 MX35_PAD_DE_B__SJC_DE_B
+412 MX35_PAD_SJC_MOD__SJC_MOD
+413 MX35_PAD_USBOTG_PWR__USB_TOP_USBOTG_PWR
+414 MX35_PAD_USBOTG_PWR__USB_TOP_USBH2_PWR
+415 MX35_PAD_USBOTG_PWR__GPIO3_14
+416 MX35_PAD_USBOTG_OC__USB_TOP_USBOTG_OC
+417 MX35_PAD_USBOTG_OC__USB_TOP_USBH2_OC
+418 MX35_PAD_USBOTG_OC__GPIO3_15
+419 MX35_PAD_LD0__IPU_DISPB_DAT_0
+420 MX35_PAD_LD0__GPIO2_0
+421 MX35_PAD_LD0__SDMA_SDMA_DEBUG_PC_0
+422 MX35_PAD_LD1__IPU_DISPB_DAT_1
+423 MX35_PAD_LD1__GPIO2_1
+424 MX35_PAD_LD1__SDMA_SDMA_DEBUG_PC_1
+425 MX35_PAD_LD2__IPU_DISPB_DAT_2
+426 MX35_PAD_LD2__GPIO2_2
+427 MX35_PAD_LD2__SDMA_SDMA_DEBUG_PC_2
+428 MX35_PAD_LD3__IPU_DISPB_DAT_3
+429 MX35_PAD_LD3__GPIO2_3
+430 MX35_PAD_LD3__SDMA_SDMA_DEBUG_PC_3
+431 MX35_PAD_LD4__IPU_DISPB_DAT_4
+432 MX35_PAD_LD4__GPIO2_4
+433 MX35_PAD_LD4__SDMA_SDMA_DEBUG_PC_4
+434 MX35_PAD_LD5__IPU_DISPB_DAT_5
+435 MX35_PAD_LD5__GPIO2_5
+436 MX35_PAD_LD5__SDMA_SDMA_DEBUG_PC_5
+437 MX35_PAD_LD6__IPU_DISPB_DAT_6
+438 MX35_PAD_LD6__GPIO2_6
+439 MX35_PAD_LD6__SDMA_SDMA_DEBUG_PC_6
+440 MX35_PAD_LD7__IPU_DISPB_DAT_7
+441 MX35_PAD_LD7__GPIO2_7
+442 MX35_PAD_LD7__SDMA_SDMA_DEBUG_PC_7
+443 MX35_PAD_LD8__IPU_DISPB_DAT_8
+444 MX35_PAD_LD8__GPIO2_8
+445 MX35_PAD_LD8__SDMA_SDMA_DEBUG_PC_8
+446 MX35_PAD_LD9__IPU_DISPB_DAT_9
+447 MX35_PAD_LD9__GPIO2_9
+448 MX35_PAD_LD9__SDMA_SDMA_DEBUG_PC_9
+449 MX35_PAD_LD10__IPU_DISPB_DAT_10
+450 MX35_PAD_LD10__GPIO2_10
+451 MX35_PAD_LD10__SDMA_SDMA_DEBUG_PC_10
+452 MX35_PAD_LD11__IPU_DISPB_DAT_11
+453 MX35_PAD_LD11__GPIO2_11
+454 MX35_PAD_LD11__SDMA_SDMA_DEBUG_PC_11
+455 MX35_PAD_LD11__ARM11P_TOP_TRACE_4
+456 MX35_PAD_LD12__IPU_DISPB_DAT_12
+457 MX35_PAD_LD12__GPIO2_12
+458 MX35_PAD_LD12__SDMA_SDMA_DEBUG_PC_12
+459 MX35_PAD_LD12__ARM11P_TOP_TRACE_5
+460 MX35_PAD_LD13__IPU_DISPB_DAT_13
+461 MX35_PAD_LD13__GPIO2_13
+462 MX35_PAD_LD13__SDMA_SDMA_DEBUG_PC_13
+463 MX35_PAD_LD13__ARM11P_TOP_TRACE_6
+464 MX35_PAD_LD14__IPU_DISPB_DAT_14
+465 MX35_PAD_LD14__GPIO2_14
+466 MX35_PAD_LD14__SDMA_SDMA_DEBUG_EVENT_CHANNEL_0
+467 MX35_PAD_LD14__ARM11P_TOP_TRACE_7
+468 MX35_PAD_LD15__IPU_DISPB_DAT_15
+469 MX35_PAD_LD15__GPIO2_15
+470 MX35_PAD_LD15__SDMA_SDMA_DEBUG_EVENT_CHANNEL_1
+471 MX35_PAD_LD15__ARM11P_TOP_TRACE_8
+472 MX35_PAD_LD16__IPU_DISPB_DAT_16
+473 MX35_PAD_LD16__IPU_DISPB_D12_VSYNC
+474 MX35_PAD_LD16__GPIO2_16
+475 MX35_PAD_LD16__SDMA_SDMA_DEBUG_EVENT_CHANNEL_2
+476 MX35_PAD_LD16__ARM11P_TOP_TRACE_9
+477 MX35_PAD_LD17__IPU_DISPB_DAT_17
+478 MX35_PAD_LD17__IPU_DISPB_CS2
+479 MX35_PAD_LD17__GPIO2_17
+480 MX35_PAD_LD17__SDMA_SDMA_DEBUG_EVENT_CHANNEL_3
+481 MX35_PAD_LD17__ARM11P_TOP_TRACE_10
+482 MX35_PAD_LD18__IPU_DISPB_DAT_18
+483 MX35_PAD_LD18__IPU_DISPB_D0_VSYNC
+484 MX35_PAD_LD18__IPU_DISPB_D12_VSYNC
+485 MX35_PAD_LD18__ESDHC3_CMD
+486 MX35_PAD_LD18__USB_TOP_USBOTG_DATA_3
+487 MX35_PAD_LD18__GPIO3_24
+488 MX35_PAD_LD18__SDMA_SDMA_DEBUG_EVENT_CHANNEL_4
+489 MX35_PAD_LD18__ARM11P_TOP_TRACE_11
+490 MX35_PAD_LD19__IPU_DISPB_DAT_19
+491 MX35_PAD_LD19__IPU_DISPB_BCLK
+492 MX35_PAD_LD19__IPU_DISPB_CS1
+493 MX35_PAD_LD19__ESDHC3_CLK
+494 MX35_PAD_LD19__USB_TOP_USBOTG_DIR
+495 MX35_PAD_LD19__GPIO3_25
+496 MX35_PAD_LD19__SDMA_SDMA_DEBUG_EVENT_CHANNEL_5
+497 MX35_PAD_LD19__ARM11P_TOP_TRACE_12
+498 MX35_PAD_LD20__IPU_DISPB_DAT_20
+499 MX35_PAD_LD20__IPU_DISPB_CS0
+500 MX35_PAD_LD20__IPU_DISPB_SD_CLK
+501 MX35_PAD_LD20__ESDHC3_DAT0
+502 MX35_PAD_LD20__GPIO3_26
+503 MX35_PAD_LD20__SDMA_SDMA_DEBUG_CORE_STATUS_3
+504 MX35_PAD_LD20__ARM11P_TOP_TRACE_13
+505 MX35_PAD_LD21__IPU_DISPB_DAT_21
+506 MX35_PAD_LD21__IPU_DISPB_PAR_RS
+507 MX35_PAD_LD21__IPU_DISPB_SER_RS
+508 MX35_PAD_LD21__ESDHC3_DAT1
+509 MX35_PAD_LD21__USB_TOP_USBOTG_STP
+510 MX35_PAD_LD21__GPIO3_27
+511 MX35_PAD_LD21__SDMA_DEBUG_EVENT_CHANNEL_SEL
+512 MX35_PAD_LD21__ARM11P_TOP_TRACE_14
+513 MX35_PAD_LD22__IPU_DISPB_DAT_22
+514 MX35_PAD_LD22__IPU_DISPB_WR
+515 MX35_PAD_LD22__IPU_DISPB_SD_D_I
+516 MX35_PAD_LD22__ESDHC3_DAT2
+517 MX35_PAD_LD22__USB_TOP_USBOTG_NXT
+518 MX35_PAD_LD22__GPIO3_28
+519 MX35_PAD_LD22__SDMA_DEBUG_BUS_ERROR
+520 MX35_PAD_LD22__ARM11P_TOP_TRCTL
+521 MX35_PAD_LD23__IPU_DISPB_DAT_23
+522 MX35_PAD_LD23__IPU_DISPB_RD
+523 MX35_PAD_LD23__IPU_DISPB_SD_D_IO
+524 MX35_PAD_LD23__ESDHC3_DAT3
+525 MX35_PAD_LD23__USB_TOP_USBOTG_DATA_7
+526 MX35_PAD_LD23__GPIO3_29
+527 MX35_PAD_LD23__SDMA_DEBUG_MATCHED_DMBUS
+528 MX35_PAD_LD23__ARM11P_TOP_TRCLK
+529 MX35_PAD_D3_HSYNC__IPU_DISPB_D3_HSYNC
+530 MX35_PAD_D3_HSYNC__IPU_DISPB_SD_D_IO
+531 MX35_PAD_D3_HSYNC__GPIO3_30
+532 MX35_PAD_D3_HSYNC__SDMA_DEBUG_RTBUFFER_WRITE
+533 MX35_PAD_D3_HSYNC__ARM11P_TOP_TRACE_15
+534 MX35_PAD_D3_FPSHIFT__IPU_DISPB_D3_CLK
+535 MX35_PAD_D3_FPSHIFT__IPU_DISPB_SD_CLK
+536 MX35_PAD_D3_FPSHIFT__GPIO3_31
+537 MX35_PAD_D3_FPSHIFT__SDMA_SDMA_DEBUG_CORE_STATUS_0
+538 MX35_PAD_D3_FPSHIFT__ARM11P_TOP_TRACE_16
+539 MX35_PAD_D3_DRDY__IPU_DISPB_D3_DRDY
+540 MX35_PAD_D3_DRDY__IPU_DISPB_SD_D_O
+541 MX35_PAD_D3_DRDY__GPIO1_0
+542 MX35_PAD_D3_DRDY__SDMA_SDMA_DEBUG_CORE_STATUS_1
+543 MX35_PAD_D3_DRDY__ARM11P_TOP_TRACE_17
+544 MX35_PAD_CONTRAST__IPU_DISPB_CONTR
+545 MX35_PAD_CONTRAST__GPIO1_1
+546 MX35_PAD_CONTRAST__SDMA_SDMA_DEBUG_CORE_STATUS_2
+547 MX35_PAD_CONTRAST__ARM11P_TOP_TRACE_18
+548 MX35_PAD_D3_VSYNC__IPU_DISPB_D3_VSYNC
+549 MX35_PAD_D3_VSYNC__IPU_DISPB_CS1
+550 MX35_PAD_D3_VSYNC__GPIO1_2
+551 MX35_PAD_D3_VSYNC__SDMA_DEBUG_YIELD
+552 MX35_PAD_D3_VSYNC__ARM11P_TOP_TRACE_19
+553 MX35_PAD_D3_REV__IPU_DISPB_D3_REV
+554 MX35_PAD_D3_REV__IPU_DISPB_SER_RS
+555 MX35_PAD_D3_REV__GPIO1_3
+556 MX35_PAD_D3_REV__SDMA_DEBUG_BUS_RWB
+557 MX35_PAD_D3_REV__ARM11P_TOP_TRACE_20
+558 MX35_PAD_D3_CLS__IPU_DISPB_D3_CLS
+559 MX35_PAD_D3_CLS__IPU_DISPB_CS2
+560 MX35_PAD_D3_CLS__GPIO1_4
+561 MX35_PAD_D3_CLS__SDMA_DEBUG_BUS_DEVICE_0
+562 MX35_PAD_D3_CLS__ARM11P_TOP_TRACE_21
+563 MX35_PAD_D3_SPL__IPU_DISPB_D3_SPL
+564 MX35_PAD_D3_SPL__IPU_DISPB_D12_VSYNC
+565 MX35_PAD_D3_SPL__GPIO1_5
+566 MX35_PAD_D3_SPL__SDMA_DEBUG_BUS_DEVICE_1
+567 MX35_PAD_D3_SPL__ARM11P_TOP_TRACE_22
+568 MX35_PAD_SD1_CMD__ESDHC1_CMD
+569 MX35_PAD_SD1_CMD__MSHC_SCLK
+570 MX35_PAD_SD1_CMD__IPU_DISPB_D0_VSYNC
+571 MX35_PAD_SD1_CMD__USB_TOP_USBOTG_DATA_4
+572 MX35_PAD_SD1_CMD__GPIO1_6
+573 MX35_PAD_SD1_CMD__ARM11P_TOP_TRCTL
+574 MX35_PAD_SD1_CLK__ESDHC1_CLK
+575 MX35_PAD_SD1_CLK__MSHC_BS
+576 MX35_PAD_SD1_CLK__IPU_DISPB_BCLK
+577 MX35_PAD_SD1_CLK__USB_TOP_USBOTG_DATA_5
+578 MX35_PAD_SD1_CLK__GPIO1_7
+579 MX35_PAD_SD1_CLK__ARM11P_TOP_TRCLK
+580 MX35_PAD_SD1_DATA0__ESDHC1_DAT0
+581 MX35_PAD_SD1_DATA0__MSHC_DATA_0
+582 MX35_PAD_SD1_DATA0__IPU_DISPB_CS0
+583 MX35_PAD_SD1_DATA0__USB_TOP_USBOTG_DATA_6
+584 MX35_PAD_SD1_DATA0__GPIO1_8
+585 MX35_PAD_SD1_DATA0__ARM11P_TOP_TRACE_23
+586 MX35_PAD_SD1_DATA1__ESDHC1_DAT1
+587 MX35_PAD_SD1_DATA1__MSHC_DATA_1
+588 MX35_PAD_SD1_DATA1__IPU_DISPB_PAR_RS
+589 MX35_PAD_SD1_DATA1__USB_TOP_USBOTG_DATA_0
+590 MX35_PAD_SD1_DATA1__GPIO1_9
+591 MX35_PAD_SD1_DATA1__ARM11P_TOP_TRACE_24
+592 MX35_PAD_SD1_DATA2__ESDHC1_DAT2
+593 MX35_PAD_SD1_DATA2__MSHC_DATA_2
+594 MX35_PAD_SD1_DATA2__IPU_DISPB_WR
+595 MX35_PAD_SD1_DATA2__USB_TOP_USBOTG_DATA_1
+596 MX35_PAD_SD1_DATA2__GPIO1_10
+597 MX35_PAD_SD1_DATA2__ARM11P_TOP_TRACE_25
+598 MX35_PAD_SD1_DATA3__ESDHC1_DAT3
+599 MX35_PAD_SD1_DATA3__MSHC_DATA_3
+600 MX35_PAD_SD1_DATA3__IPU_DISPB_RD
+601 MX35_PAD_SD1_DATA3__USB_TOP_USBOTG_DATA_2
+602 MX35_PAD_SD1_DATA3__GPIO1_11
+603 MX35_PAD_SD1_DATA3__ARM11P_TOP_TRACE_26
+604 MX35_PAD_SD2_CMD__ESDHC2_CMD
+605 MX35_PAD_SD2_CMD__I2C3_SCL
+606 MX35_PAD_SD2_CMD__ESDHC1_DAT4
+607 MX35_PAD_SD2_CMD__IPU_CSI_D_2
+608 MX35_PAD_SD2_CMD__USB_TOP_USBH2_DATA_4
+609 MX35_PAD_SD2_CMD__GPIO2_0
+610 MX35_PAD_SD2_CMD__SPDIF_SPDIF_OUT1
+611 MX35_PAD_SD2_CMD__IPU_DISPB_D12_VSYNC
+612 MX35_PAD_SD2_CLK__ESDHC2_CLK
+613 MX35_PAD_SD2_CLK__I2C3_SDA
+614 MX35_PAD_SD2_CLK__ESDHC1_DAT5
+615 MX35_PAD_SD2_CLK__IPU_CSI_D_3
+616 MX35_PAD_SD2_CLK__USB_TOP_USBH2_DATA_5
+617 MX35_PAD_SD2_CLK__GPIO2_1
+618 MX35_PAD_SD2_CLK__SPDIF_SPDIF_IN1
+619 MX35_PAD_SD2_CLK__IPU_DISPB_CS2
+620 MX35_PAD_SD2_DATA0__ESDHC2_DAT0
+621 MX35_PAD_SD2_DATA0__UART3_RXD_MUX
+622 MX35_PAD_SD2_DATA0__ESDHC1_DAT6
+623 MX35_PAD_SD2_DATA0__IPU_CSI_D_4
+624 MX35_PAD_SD2_DATA0__USB_TOP_USBH2_DATA_6
+625 MX35_PAD_SD2_DATA0__GPIO2_2
+626 MX35_PAD_SD2_DATA0__SPDIF_SPDIF_EXTCLK
+627 MX35_PAD_SD2_DATA1__ESDHC2_DAT1
+628 MX35_PAD_SD2_DATA1__UART3_TXD_MUX
+629 MX35_PAD_SD2_DATA1__ESDHC1_DAT7
+630 MX35_PAD_SD2_DATA1__IPU_CSI_D_5
+631 MX35_PAD_SD2_DATA1__USB_TOP_USBH2_DATA_0
+632 MX35_PAD_SD2_DATA1__GPIO2_3
+633 MX35_PAD_SD2_DATA2__ESDHC2_DAT2
+634 MX35_PAD_SD2_DATA2__UART3_RTS
+635 MX35_PAD_SD2_DATA2__CAN1_RXCAN
+636 MX35_PAD_SD2_DATA2__IPU_CSI_D_6
+637 MX35_PAD_SD2_DATA2__USB_TOP_USBH2_DATA_1
+638 MX35_PAD_SD2_DATA2__GPIO2_4
+639 MX35_PAD_SD2_DATA3__ESDHC2_DAT3
+640 MX35_PAD_SD2_DATA3__UART3_CTS
+641 MX35_PAD_SD2_DATA3__CAN1_TXCAN
+642 MX35_PAD_SD2_DATA3__IPU_CSI_D_7
+643 MX35_PAD_SD2_DATA3__USB_TOP_USBH2_DATA_2
+644 MX35_PAD_SD2_DATA3__GPIO2_5
+645 MX35_PAD_ATA_CS0__ATA_CS0
+646 MX35_PAD_ATA_CS0__CSPI1_SS3
+647 MX35_PAD_ATA_CS0__IPU_DISPB_CS1
+648 MX35_PAD_ATA_CS0__GPIO2_6
+649 MX35_PAD_ATA_CS0__IPU_DIAGB_0
+650 MX35_PAD_ATA_CS0__ARM11P_TOP_MAX1_HMASTER_0
+651 MX35_PAD_ATA_CS1__ATA_CS1
+652 MX35_PAD_ATA_CS1__IPU_DISPB_CS2
+653 MX35_PAD_ATA_CS1__CSPI2_SS0
+654 MX35_PAD_ATA_CS1__GPIO2_7
+655 MX35_PAD_ATA_CS1__IPU_DIAGB_1
+656 MX35_PAD_ATA_CS1__ARM11P_TOP_MAX1_HMASTER_1
+657 MX35_PAD_ATA_DIOR__ATA_DIOR
+658 MX35_PAD_ATA_DIOR__ESDHC3_DAT0
+659 MX35_PAD_ATA_DIOR__USB_TOP_USBOTG_DIR
+660 MX35_PAD_ATA_DIOR__IPU_DISPB_BE0
+661 MX35_PAD_ATA_DIOR__CSPI2_SS1
+662 MX35_PAD_ATA_DIOR__GPIO2_8
+663 MX35_PAD_ATA_DIOR__IPU_DIAGB_2
+664 MX35_PAD_ATA_DIOR__ARM11P_TOP_MAX1_HMASTER_2
+665 MX35_PAD_ATA_DIOW__ATA_DIOW
+666 MX35_PAD_ATA_DIOW__ESDHC3_DAT1
+667 MX35_PAD_ATA_DIOW__USB_TOP_USBOTG_STP
+668 MX35_PAD_ATA_DIOW__IPU_DISPB_BE1
+669 MX35_PAD_ATA_DIOW__CSPI2_MOSI
+670 MX35_PAD_ATA_DIOW__GPIO2_9
+671 MX35_PAD_ATA_DIOW__IPU_DIAGB_3
+672 MX35_PAD_ATA_DIOW__ARM11P_TOP_MAX1_HMASTER_3
+673 MX35_PAD_ATA_DMACK__ATA_DMACK
+674 MX35_PAD_ATA_DMACK__ESDHC3_DAT2
+675 MX35_PAD_ATA_DMACK__USB_TOP_USBOTG_NXT
+676 MX35_PAD_ATA_DMACK__CSPI2_MISO
+677 MX35_PAD_ATA_DMACK__GPIO2_10
+678 MX35_PAD_ATA_DMACK__IPU_DIAGB_4
+679 MX35_PAD_ATA_DMACK__ARM11P_TOP_MAX0_HMASTER_0
+680 MX35_PAD_ATA_RESET_B__ATA_RESET_B
+681 MX35_PAD_ATA_RESET_B__ESDHC3_DAT3
+682 MX35_PAD_ATA_RESET_B__USB_TOP_USBOTG_DATA_0
+683 MX35_PAD_ATA_RESET_B__IPU_DISPB_SD_D_O
+684 MX35_PAD_ATA_RESET_B__CSPI2_RDY
+685 MX35_PAD_ATA_RESET_B__GPIO2_11
+686 MX35_PAD_ATA_RESET_B__IPU_DIAGB_5
+687 MX35_PAD_ATA_RESET_B__ARM11P_TOP_MAX0_HMASTER_1
+688 MX35_PAD_ATA_IORDY__ATA_IORDY
+689 MX35_PAD_ATA_IORDY__ESDHC3_DAT4
+690 MX35_PAD_ATA_IORDY__USB_TOP_USBOTG_DATA_1
+691 MX35_PAD_ATA_IORDY__IPU_DISPB_SD_D_IO
+692 MX35_PAD_ATA_IORDY__ESDHC2_DAT4
+693 MX35_PAD_ATA_IORDY__GPIO2_12
+694 MX35_PAD_ATA_IORDY__IPU_DIAGB_6
+695 MX35_PAD_ATA_IORDY__ARM11P_TOP_MAX0_HMASTER_2
+696 MX35_PAD_ATA_DATA0__ATA_DATA_0
+697 MX35_PAD_ATA_DATA0__ESDHC3_DAT5
+698 MX35_PAD_ATA_DATA0__USB_TOP_USBOTG_DATA_2
+699 MX35_PAD_ATA_DATA0__IPU_DISPB_D12_VSYNC
+700 MX35_PAD_ATA_DATA0__ESDHC2_DAT5
+701 MX35_PAD_ATA_DATA0__GPIO2_13
+702 MX35_PAD_ATA_DATA0__IPU_DIAGB_7
+703 MX35_PAD_ATA_DATA0__ARM11P_TOP_MAX0_HMASTER_3
+704 MX35_PAD_ATA_DATA1__ATA_DATA_1
+705 MX35_PAD_ATA_DATA1__ESDHC3_DAT6
+706 MX35_PAD_ATA_DATA1__USB_TOP_USBOTG_DATA_3
+707 MX35_PAD_ATA_DATA1__IPU_DISPB_SD_CLK
+708 MX35_PAD_ATA_DATA1__ESDHC2_DAT6
+709 MX35_PAD_ATA_DATA1__GPIO2_14
+710 MX35_PAD_ATA_DATA1__IPU_DIAGB_8
+711 MX35_PAD_ATA_DATA1__ARM11P_TOP_TRACE_27
+712 MX35_PAD_ATA_DATA2__ATA_DATA_2
+713 MX35_PAD_ATA_DATA2__ESDHC3_DAT7
+714 MX35_PAD_ATA_DATA2__USB_TOP_USBOTG_DATA_4
+715 MX35_PAD_ATA_DATA2__IPU_DISPB_SER_RS
+716 MX35_PAD_ATA_DATA2__ESDHC2_DAT7
+717 MX35_PAD_ATA_DATA2__GPIO2_15
+718 MX35_PAD_ATA_DATA2__IPU_DIAGB_9
+719 MX35_PAD_ATA_DATA2__ARM11P_TOP_TRACE_28
+720 MX35_PAD_ATA_DATA3__ATA_DATA_3
+721 MX35_PAD_ATA_DATA3__ESDHC3_CLK
+722 MX35_PAD_ATA_DATA3__USB_TOP_USBOTG_DATA_5
+723 MX35_PAD_ATA_DATA3__CSPI2_SCLK
+724 MX35_PAD_ATA_DATA3__GPIO2_16
+725 MX35_PAD_ATA_DATA3__IPU_DIAGB_10
+726 MX35_PAD_ATA_DATA3__ARM11P_TOP_TRACE_29
+727 MX35_PAD_ATA_DATA4__ATA_DATA_4
+728 MX35_PAD_ATA_DATA4__ESDHC3_CMD
+729 MX35_PAD_ATA_DATA4__USB_TOP_USBOTG_DATA_6
+730 MX35_PAD_ATA_DATA4__GPIO2_17
+731 MX35_PAD_ATA_DATA4__IPU_DIAGB_11
+732 MX35_PAD_ATA_DATA4__ARM11P_TOP_TRACE_30
+733 MX35_PAD_ATA_DATA5__ATA_DATA_5
+734 MX35_PAD_ATA_DATA5__USB_TOP_USBOTG_DATA_7
+735 MX35_PAD_ATA_DATA5__GPIO2_18
+736 MX35_PAD_ATA_DATA5__IPU_DIAGB_12
+737 MX35_PAD_ATA_DATA5__ARM11P_TOP_TRACE_31
+738 MX35_PAD_ATA_DATA6__ATA_DATA_6
+739 MX35_PAD_ATA_DATA6__CAN1_TXCAN
+740 MX35_PAD_ATA_DATA6__UART1_DTR
+741 MX35_PAD_ATA_DATA6__AUDMUX_AUD6_TXD
+742 MX35_PAD_ATA_DATA6__GPIO2_19
+743 MX35_PAD_ATA_DATA6__IPU_DIAGB_13
+744 MX35_PAD_ATA_DATA7__ATA_DATA_7
+745 MX35_PAD_ATA_DATA7__CAN1_RXCAN
+746 MX35_PAD_ATA_DATA7__UART1_DSR
+747 MX35_PAD_ATA_DATA7__AUDMUX_AUD6_RXD
+748 MX35_PAD_ATA_DATA7__GPIO2_20
+749 MX35_PAD_ATA_DATA7__IPU_DIAGB_14
+750 MX35_PAD_ATA_DATA8__ATA_DATA_8
+751 MX35_PAD_ATA_DATA8__UART3_RTS
+752 MX35_PAD_ATA_DATA8__UART1_RI
+753 MX35_PAD_ATA_DATA8__AUDMUX_AUD6_TXC
+754 MX35_PAD_ATA_DATA8__GPIO2_21
+755 MX35_PAD_ATA_DATA8__IPU_DIAGB_15
+756 MX35_PAD_ATA_DATA9__ATA_DATA_9
+757 MX35_PAD_ATA_DATA9__UART3_CTS
+758 MX35_PAD_ATA_DATA9__UART1_DCD
+759 MX35_PAD_ATA_DATA9__AUDMUX_AUD6_TXFS
+760 MX35_PAD_ATA_DATA9__GPIO2_22
+761 MX35_PAD_ATA_DATA9__IPU_DIAGB_16
+762 MX35_PAD_ATA_DATA10__ATA_DATA_10
+763 MX35_PAD_ATA_DATA10__UART3_RXD_MUX
+764 MX35_PAD_ATA_DATA10__AUDMUX_AUD6_RXC
+765 MX35_PAD_ATA_DATA10__GPIO2_23
+766 MX35_PAD_ATA_DATA10__IPU_DIAGB_17
+767 MX35_PAD_ATA_DATA11__ATA_DATA_11
+768 MX35_PAD_ATA_DATA11__UART3_TXD_MUX
+769 MX35_PAD_ATA_DATA11__AUDMUX_AUD6_RXFS
+770 MX35_PAD_ATA_DATA11__GPIO2_24
+771 MX35_PAD_ATA_DATA11__IPU_DIAGB_18
+772 MX35_PAD_ATA_DATA12__ATA_DATA_12
+773 MX35_PAD_ATA_DATA12__I2C3_SCL
+774 MX35_PAD_ATA_DATA12__GPIO2_25
+775 MX35_PAD_ATA_DATA12__IPU_DIAGB_19
+776 MX35_PAD_ATA_DATA13__ATA_DATA_13
+777 MX35_PAD_ATA_DATA13__I2C3_SDA
+778 MX35_PAD_ATA_DATA13__GPIO2_26
+779 MX35_PAD_ATA_DATA13__IPU_DIAGB_20
+780 MX35_PAD_ATA_DATA14__ATA_DATA_14
+781 MX35_PAD_ATA_DATA14__IPU_CSI_D_0
+782 MX35_PAD_ATA_DATA14__KPP_ROW_0
+783 MX35_PAD_ATA_DATA14__GPIO2_27
+784 MX35_PAD_ATA_DATA14__IPU_DIAGB_21
+785 MX35_PAD_ATA_DATA15__ATA_DATA_15
+786 MX35_PAD_ATA_DATA15__IPU_CSI_D_1
+787 MX35_PAD_ATA_DATA15__KPP_ROW_1
+788 MX35_PAD_ATA_DATA15__GPIO2_28
+789 MX35_PAD_ATA_DATA15__IPU_DIAGB_22
+790 MX35_PAD_ATA_INTRQ__ATA_INTRQ
+791 MX35_PAD_ATA_INTRQ__IPU_CSI_D_2
+792 MX35_PAD_ATA_INTRQ__KPP_ROW_2
+793 MX35_PAD_ATA_INTRQ__GPIO2_29
+794 MX35_PAD_ATA_INTRQ__IPU_DIAGB_23
+795 MX35_PAD_ATA_BUFF_EN__ATA_BUFFER_EN
+796 MX35_PAD_ATA_BUFF_EN__IPU_CSI_D_3
+797 MX35_PAD_ATA_BUFF_EN__KPP_ROW_3
+798 MX35_PAD_ATA_BUFF_EN__GPIO2_30
+799 MX35_PAD_ATA_BUFF_EN__IPU_DIAGB_24
+800 MX35_PAD_ATA_DMARQ__ATA_DMARQ
+801 MX35_PAD_ATA_DMARQ__IPU_CSI_D_4
+802 MX35_PAD_ATA_DMARQ__KPP_COL_0
+803 MX35_PAD_ATA_DMARQ__GPIO2_31
+804 MX35_PAD_ATA_DMARQ__IPU_DIAGB_25
+805 MX35_PAD_ATA_DMARQ__ECT_CTI_TRIG_IN1_4
+806 MX35_PAD_ATA_DA0__ATA_DA_0
+807 MX35_PAD_ATA_DA0__IPU_CSI_D_5
+808 MX35_PAD_ATA_DA0__KPP_COL_1
+809 MX35_PAD_ATA_DA0__GPIO3_0
+810 MX35_PAD_ATA_DA0__IPU_DIAGB_26
+811 MX35_PAD_ATA_DA0__ECT_CTI_TRIG_IN1_5
+812 MX35_PAD_ATA_DA1__ATA_DA_1
+813 MX35_PAD_ATA_DA1__IPU_CSI_D_6
+814 MX35_PAD_ATA_DA1__KPP_COL_2
+815 MX35_PAD_ATA_DA1__GPIO3_1
+816 MX35_PAD_ATA_DA1__IPU_DIAGB_27
+817 MX35_PAD_ATA_DA1__ECT_CTI_TRIG_IN1_6
+818 MX35_PAD_ATA_DA2__ATA_DA_2
+819 MX35_PAD_ATA_DA2__IPU_CSI_D_7
+820 MX35_PAD_ATA_DA2__KPP_COL_3
+821 MX35_PAD_ATA_DA2__GPIO3_2
+822 MX35_PAD_ATA_DA2__IPU_DIAGB_28
+823 MX35_PAD_ATA_DA2__ECT_CTI_TRIG_IN1_7
+824 MX35_PAD_MLB_CLK__MLB_MLBCLK
+825 MX35_PAD_MLB_CLK__GPIO3_3
+826 MX35_PAD_MLB_DAT__MLB_MLBDAT
+827 MX35_PAD_MLB_DAT__GPIO3_4
+828 MX35_PAD_MLB_SIG__MLB_MLBSIG
+829 MX35_PAD_MLB_SIG__GPIO3_5
+830 MX35_PAD_FEC_TX_CLK__FEC_TX_CLK
+831 MX35_PAD_FEC_TX_CLK__ESDHC1_DAT4
+832 MX35_PAD_FEC_TX_CLK__UART3_RXD_MUX
+833 MX35_PAD_FEC_TX_CLK__USB_TOP_USBH2_DIR
+834 MX35_PAD_FEC_TX_CLK__CSPI2_MOSI
+835 MX35_PAD_FEC_TX_CLK__GPIO3_6
+836 MX35_PAD_FEC_TX_CLK__IPU_DISPB_D12_VSYNC
+837 MX35_PAD_FEC_TX_CLK__ARM11P_TOP_EVNTBUS_0
+838 MX35_PAD_FEC_RX_CLK__FEC_RX_CLK
+839 MX35_PAD_FEC_RX_CLK__ESDHC1_DAT5
+840 MX35_PAD_FEC_RX_CLK__UART3_TXD_MUX
+841 MX35_PAD_FEC_RX_CLK__USB_TOP_USBH2_STP
+842 MX35_PAD_FEC_RX_CLK__CSPI2_MISO
+843 MX35_PAD_FEC_RX_CLK__GPIO3_7
+844 MX35_PAD_FEC_RX_CLK__IPU_DISPB_SD_D_I
+845 MX35_PAD_FEC_RX_CLK__ARM11P_TOP_EVNTBUS_1
+846 MX35_PAD_FEC_RX_DV__FEC_RX_DV
+847 MX35_PAD_FEC_RX_DV__ESDHC1_DAT6
+848 MX35_PAD_FEC_RX_DV__UART3_RTS
+849 MX35_PAD_FEC_RX_DV__USB_TOP_USBH2_NXT
+850 MX35_PAD_FEC_RX_DV__CSPI2_SCLK
+851 MX35_PAD_FEC_RX_DV__GPIO3_8
+852 MX35_PAD_FEC_RX_DV__IPU_DISPB_SD_CLK
+853 MX35_PAD_FEC_RX_DV__ARM11P_TOP_EVNTBUS_2
+854 MX35_PAD_FEC_COL__FEC_COL
+855 MX35_PAD_FEC_COL__ESDHC1_DAT7
+856 MX35_PAD_FEC_COL__UART3_CTS
+857 MX35_PAD_FEC_COL__USB_TOP_USBH2_DATA_0
+858 MX35_PAD_FEC_COL__CSPI2_RDY
+859 MX35_PAD_FEC_COL__GPIO3_9
+860 MX35_PAD_FEC_COL__IPU_DISPB_SER_RS
+861 MX35_PAD_FEC_COL__ARM11P_TOP_EVNTBUS_3
+862 MX35_PAD_FEC_RDATA0__FEC_RDATA_0
+863 MX35_PAD_FEC_RDATA0__PWM_PWMO
+864 MX35_PAD_FEC_RDATA0__UART3_DTR
+865 MX35_PAD_FEC_RDATA0__USB_TOP_USBH2_DATA_1
+866 MX35_PAD_FEC_RDATA0__CSPI2_SS0
+867 MX35_PAD_FEC_RDATA0__GPIO3_10
+868 MX35_PAD_FEC_RDATA0__IPU_DISPB_CS1
+869 MX35_PAD_FEC_RDATA0__ARM11P_TOP_EVNTBUS_4
+870 MX35_PAD_FEC_TDATA0__FEC_TDATA_0
+871 MX35_PAD_FEC_TDATA0__SPDIF_SPDIF_OUT1
+872 MX35_PAD_FEC_TDATA0__UART3_DSR
+873 MX35_PAD_FEC_TDATA0__USB_TOP_USBH2_DATA_2
+874 MX35_PAD_FEC_TDATA0__CSPI2_SS1
+875 MX35_PAD_FEC_TDATA0__GPIO3_11
+876 MX35_PAD_FEC_TDATA0__IPU_DISPB_CS0
+877 MX35_PAD_FEC_TDATA0__ARM11P_TOP_EVNTBUS_5
+878 MX35_PAD_FEC_TX_EN__FEC_TX_EN
+879 MX35_PAD_FEC_TX_EN__SPDIF_SPDIF_IN1
+880 MX35_PAD_FEC_TX_EN__UART3_RI
+881 MX35_PAD_FEC_TX_EN__USB_TOP_USBH2_DATA_3
+882 MX35_PAD_FEC_TX_EN__GPIO3_12
+883 MX35_PAD_FEC_TX_EN__IPU_DISPB_PAR_RS
+884 MX35_PAD_FEC_TX_EN__ARM11P_TOP_EVNTBUS_6
+885 MX35_PAD_FEC_MDC__FEC_MDC
+886 MX35_PAD_FEC_MDC__CAN2_TXCAN
+887 MX35_PAD_FEC_MDC__UART3_DCD
+888 MX35_PAD_FEC_MDC__USB_TOP_USBH2_DATA_4
+889 MX35_PAD_FEC_MDC__GPIO3_13
+890 MX35_PAD_FEC_MDC__IPU_DISPB_WR
+891 MX35_PAD_FEC_MDC__ARM11P_TOP_EVNTBUS_7
+892 MX35_PAD_FEC_MDIO__FEC_MDIO
+893 MX35_PAD_FEC_MDIO__CAN2_RXCAN
+894 MX35_PAD_FEC_MDIO__USB_TOP_USBH2_DATA_5
+895 MX35_PAD_FEC_MDIO__GPIO3_14
+896 MX35_PAD_FEC_MDIO__IPU_DISPB_RD
+897 MX35_PAD_FEC_MDIO__ARM11P_TOP_EVNTBUS_8
+898 MX35_PAD_FEC_TX_ERR__FEC_TX_ERR
+899 MX35_PAD_FEC_TX_ERR__OWIRE_LINE
+900 MX35_PAD_FEC_TX_ERR__SPDIF_SPDIF_EXTCLK
+901 MX35_PAD_FEC_TX_ERR__USB_TOP_USBH2_DATA_6
+902 MX35_PAD_FEC_TX_ERR__GPIO3_15
+903 MX35_PAD_FEC_TX_ERR__IPU_DISPB_D0_VSYNC
+904 MX35_PAD_FEC_TX_ERR__ARM11P_TOP_EVNTBUS_9
+905 MX35_PAD_FEC_RX_ERR__FEC_RX_ERR
+906 MX35_PAD_FEC_RX_ERR__IPU_CSI_D_0
+907 MX35_PAD_FEC_RX_ERR__USB_TOP_USBH2_DATA_7
+908 MX35_PAD_FEC_RX_ERR__KPP_COL_4
+909 MX35_PAD_FEC_RX_ERR__GPIO3_16
+910 MX35_PAD_FEC_RX_ERR__IPU_DISPB_SD_D_IO
+911 MX35_PAD_FEC_CRS__FEC_CRS
+912 MX35_PAD_FEC_CRS__IPU_CSI_D_1
+913 MX35_PAD_FEC_CRS__USB_TOP_USBH2_PWR
+914 MX35_PAD_FEC_CRS__KPP_COL_5
+915 MX35_PAD_FEC_CRS__GPIO3_17
+916 MX35_PAD_FEC_CRS__IPU_FLASH_STROBE
+917 MX35_PAD_FEC_RDATA1__FEC_RDATA_1
+918 MX35_PAD_FEC_RDATA1__IPU_CSI_D_2
+919 MX35_PAD_FEC_RDATA1__AUDMUX_AUD6_RXC
+920 MX35_PAD_FEC_RDATA1__USB_TOP_USBH2_OC
+921 MX35_PAD_FEC_RDATA1__KPP_COL_6
+922 MX35_PAD_FEC_RDATA1__GPIO3_18
+923 MX35_PAD_FEC_RDATA1__IPU_DISPB_BE0
+924 MX35_PAD_FEC_TDATA1__FEC_TDATA_1
+925 MX35_PAD_FEC_TDATA1__IPU_CSI_D_3
+926 MX35_PAD_FEC_TDATA1__AUDMUX_AUD6_RXFS
+927 MX35_PAD_FEC_TDATA1__KPP_COL_7
+928 MX35_PAD_FEC_TDATA1__GPIO3_19
+929 MX35_PAD_FEC_TDATA1__IPU_DISPB_BE1
+930 MX35_PAD_FEC_RDATA2__FEC_RDATA_2
+931 MX35_PAD_FEC_RDATA2__IPU_CSI_D_4
+932 MX35_PAD_FEC_RDATA2__AUDMUX_AUD6_TXD
+933 MX35_PAD_FEC_RDATA2__KPP_ROW_4
+934 MX35_PAD_FEC_RDATA2__GPIO3_20
+935 MX35_PAD_FEC_TDATA2__FEC_TDATA_2
+936 MX35_PAD_FEC_TDATA2__IPU_CSI_D_5
+937 MX35_PAD_FEC_TDATA2__AUDMUX_AUD6_RXD
+938 MX35_PAD_FEC_TDATA2__KPP_ROW_5
+939 MX35_PAD_FEC_TDATA2__GPIO3_21
+940 MX35_PAD_FEC_RDATA3__FEC_RDATA_3
+941 MX35_PAD_FEC_RDATA3__IPU_CSI_D_6
+942 MX35_PAD_FEC_RDATA3__AUDMUX_AUD6_TXC
+943 MX35_PAD_FEC_RDATA3__KPP_ROW_6
+944 MX35_PAD_FEC_RDATA3__GPIO3_22
+945 MX35_PAD_FEC_TDATA3__FEC_TDATA_3
+946 MX35_PAD_FEC_TDATA3__IPU_CSI_D_7
+947 MX35_PAD_FEC_TDATA3__AUDMUX_AUD6_TXFS
+948 MX35_PAD_FEC_TDATA3__KPP_ROW_7
+949 MX35_PAD_FEC_TDATA3__GPIO3_23
+950 MX35_PAD_EXT_ARMCLK__CCM_EXT_ARMCLK
+951 MX35_PAD_TEST_MODE__TCU_TEST_MODE
index d156e1b5db1233c5ffdb2c0f54e1f5bd6234da34..4d1218f836a733ce8516b44e3b58885dc01d0c6e 100644 (file)
@@ -9,6 +9,10 @@ Required properties:
 - regulators: list of regulators provided by this controller, must have
   property "regulator-compatible" to match their hardware counterparts:
   sm[0-2], ldo[0-9] and ldo_rtc
+- vin-sm0-supply: The input supply for the SM0.
+- vin-sm1-supply: The input supply for the SM1.
+- vin-sm2-supply: The input supply for the SM2.
+- sys-supply: The input supply for SYS.
 - sm0-supply: The input supply for the SM0.
 - sm1-supply: The input supply for the SM1.
 - sm2-supply: The input supply for the SM2.
@@ -20,6 +24,9 @@ Required properties:
 
 Each regulator is defined using the standard binding for regulators.
 
+Note: LDO5 and LDO_RTC is supplied by SYS regulator internally and driver
+      take care of making proper parent child relationship.
+
 Example:
 
        pmu: tps6586x@34 {
@@ -30,9 +37,9 @@ Example:
                #gpio-cells = <2>;
                gpio-controller;
 
-               sm0-supply = <&some_reg>;
-               sm1-supply = <&some_reg>;
-               sm2-supply = <&some_reg>;
+               vin-sm0-supply = <&some_reg>;
+               vin-sm1-supply = <&some_reg>;
+               vin-sm2-supply = <&some_reg>;
                vinldo01-supply = <...>;
                vinldo23-supply = <...>;
                vinldo4-supply = <...>;
@@ -43,8 +50,16 @@ Example:
                        #address-cells = <1>;
                        #size-cells = <0>;
 
-                       sm0_reg: regulator@0 {
+                       sys_reg: regulator@0 {
                                reg = <0>;
+                               regulator-compatible = "sys";
+                               regulator-name = "vdd_sys";
+                               regulator-boot-on;
+                               regulator-always-on;
+                       };
+
+                       sm0_reg: regulator@1 {
+                               reg = <1>;
                                regulator-compatible = "sm0";
                                regulator-min-microvolt = < 725000>;
                                regulator-max-microvolt = <1500000>;
@@ -52,8 +67,8 @@ Example:
                                regulator-always-on;
                        };
 
-                       sm1_reg: regulator@1 {
-                               reg = <1>;
+                       sm1_reg: regulator@2 {
+                               reg = <2>;
                                regulator-compatible = "sm1";
                                regulator-min-microvolt = < 725000>;
                                regulator-max-microvolt = <1500000>;
@@ -61,8 +76,8 @@ Example:
                                regulator-always-on;
                        };
 
-                       sm2_reg: regulator@2 {
-                               reg = <2>;
+                       sm2_reg: regulator@3 {
+                               reg = <3>;
                                regulator-compatible = "sm2";
                                regulator-min-microvolt = <3000000>;
                                regulator-max-microvolt = <4550000>;
@@ -70,72 +85,72 @@ Example:
                                regulator-always-on;
                        };
 
-                       ldo0_reg: regulator@3 {
-                               reg = <3>;
+                       ldo0_reg: regulator@4 {
+                               reg = <4>;
                                regulator-compatible = "ldo0";
                                regulator-name = "PCIE CLK";
                                regulator-min-microvolt = <3300000>;
                                regulator-max-microvolt = <3300000>;
                        };
 
-                       ldo1_reg: regulator@4 {
-                               reg = <4>;
+                       ldo1_reg: regulator@5 {
+                               reg = <5>;
                                regulator-compatible = "ldo1";
                                regulator-min-microvolt = < 725000>;
                                regulator-max-microvolt = <1500000>;
                        };
 
-                       ldo2_reg: regulator@5 {
-                               reg = <5>;
+                       ldo2_reg: regulator@6 {
+                               reg = <6>;
                                regulator-compatible = "ldo2";
                                regulator-min-microvolt = < 725000>;
                                regulator-max-microvolt = <1500000>;
                        };
 
-                       ldo3_reg: regulator@6 {
-                               reg = <6>;
+                       ldo3_reg: regulator@7 {
+                               reg = <7>;
                                regulator-compatible = "ldo3";
                                regulator-min-microvolt = <1250000>;
                                regulator-max-microvolt = <3300000>;
                        };
 
-                       ldo4_reg: regulator@7 {
-                               reg = <7>;
+                       ldo4_reg: regulator@8 {
+                               reg = <8>;
                                regulator-compatible = "ldo4";
                                regulator-min-microvolt = <1700000>;
                                regulator-max-microvolt = <2475000>;
                        };
 
-                       ldo5_reg: regulator@8 {
-                               reg = <8>;
+                       ldo5_reg: regulator@9 {
+                               reg = <9>;
                                regulator-compatible = "ldo5";
                                regulator-min-microvolt = <1250000>;
                                regulator-max-microvolt = <3300000>;
                        };
 
-                       ldo6_reg: regulator@9 {
-                               reg = <9>;
+                       ldo6_reg: regulator@10 {
+                               reg = <10>;
                                regulator-compatible = "ldo6";
                                regulator-min-microvolt = <1250000>;
                                regulator-max-microvolt = <3300000>;
                        };
 
-                       ldo7_reg: regulator@10 {
-                               reg = <10>;
+                       ldo7_reg: regulator@11 {
+                               reg = <11>;
                                regulator-compatible = "ldo7";
                                regulator-min-microvolt = <1250000>;
                                regulator-max-microvolt = <3300000>;
                        };
 
-                       ldo8_reg: regulator@11 {
-                               reg = <11>;
+                       ldo8_reg: regulator@12 {
+                               reg = <12>;
                                regulator-compatible = "ldo8";
                                regulator-min-microvolt = <1250000>;
                                regulator-max-microvolt = <3300000>;
                        };
 
-                       ldo9_reg: regulator@12 {
-                               reg = <12>;
+                       ldo9_reg: regulator@13 {
+                               reg = <13>;
                                regulator-compatible = "ldo9";
                                regulator-min-microvolt = <1250000>;
                                regulator-max-microvolt = <3300000>;
diff --git a/Documentation/devicetree/bindings/rtc/pxa-rtc.txt b/Documentation/devicetree/bindings/rtc/pxa-rtc.txt
new file mode 100644 (file)
index 0000000..8c6672a
--- /dev/null
@@ -0,0 +1,14 @@
+* PXA RTC
+
+PXA specific RTC driver.
+
+Required properties:
+- compatible : Should be "marvell,pxa-rtc"
+
+Examples:
+
+rtc@40900000 {
+       compatible = "marvell,pxa-rtc";
+       reg = <0x40900000 0x3c>;
+       interrupts = <30 31>;
+};
diff --git a/Documentation/devicetree/bindings/sound/cs4270.txt b/Documentation/devicetree/bindings/sound/cs4270.txt
new file mode 100644 (file)
index 0000000..6b222f9
--- /dev/null
@@ -0,0 +1,21 @@
+CS4270 audio CODEC
+
+The driver for this device currently only supports I2C.
+
+Required properties:
+
+  - compatible : "cirrus,cs4270"
+
+  - reg : the I2C address of the device for I2C
+
+Optional properties:
+
+  - reset-gpio : a GPIO spec for the reset pin. If specified, it will be
+                deasserted before communication to the codec starts.
+
+Example:
+
+codec: cs4270@48 {
+       compatible = "cirrus,cs4270";
+       reg = <0x48>;
+};
diff --git a/Documentation/devicetree/bindings/sound/omap-abe-twl6040.txt b/Documentation/devicetree/bindings/sound/omap-abe-twl6040.txt
new file mode 100644 (file)
index 0000000..65dec87
--- /dev/null
@@ -0,0 +1,91 @@
+* Texas Instruments OMAP4+ and twl6040 based audio setups
+
+Required properties:
+- compatible: "ti,abe-twl6040"
+- ti,model: Name of the sound card ( for example "SDP4430")
+- ti,mclk-freq: MCLK frequency for HPPLL operation
+- ti,mcpdm: phandle for the McPDM node
+- ti,twl6040: phandle for the twl6040 core node
+- ti,audio-routing: List of connections between audio components.
+  Each entry is a pair of strings, the first being the connection's sink,
+  the second being the connection's source.
+
+Optional properties:
+- ti,dmic: phandle for the OMAP dmic node if the machine have it connected
+- ti,jack_detection: Need to be set to <1> if the board capable to detect jack
+  insertion, removal.
+
+Available audio endpoints for the audio-routing table:
+
+Board connectors:
+ * Headset Stereophone
+ * Earphone Spk
+ * Ext Spk
+ * Line Out
+ * Vibrator
+ * Headset Mic
+ * Main Handset Mic
+ * Sub Handset Mic
+ * Line In
+ * Digital Mic
+
+twl6040 pins:
+ * HSOL
+ * HSOR
+ * EP
+ * HFL
+ * HFR
+ * AUXL
+ * AUXR
+ * VIBRAL
+ * VIBRAR
+ * HSMIC
+ * MAINMIC
+ * SUBMIC
+ * AFML
+ * AFMR
+
+ * Headset Mic Bias
+ * Main Mic Bias
+ * Digital Mic1 Bias
+ * Digital Mic2 Bias
+
+Digital mic pins:
+ * DMic
+
+Example:
+
+sound {
+       compatible = "ti,abe-twl6040";
+       ti,model = "SDP4430";
+
+       ti,jack-detection = <1>;
+       ti,mclk-freq = <38400000>;
+
+       ti,mcpdm = <&mcpdm>;
+       ti,dmic = <&dmic>;
+
+       ti,twl6040 = <&twl6040>;
+
+       /* Audio routing */
+       ti,audio-routing =
+               "Headset Stereophone", "HSOL",
+               "Headset Stereophone", "HSOR",
+               "Earphone Spk", "EP",
+               "Ext Spk", "HFL",
+               "Ext Spk", "HFR",
+               "Line Out", "AUXL",
+               "Line Out", "AUXR",
+               "Vibrator", "VIBRAL",
+               "Vibrator", "VIBRAR",
+               "HSMIC", "Headset Mic",
+               "Headset Mic", "Headset Mic Bias",
+               "MAINMIC", "Main Handset Mic",
+               "Main Handset Mic", "Main Mic Bias",
+               "SUBMIC", "Sub Handset Mic",
+               "Sub Handset Mic", "Main Mic Bias",
+               "AFML", "Line In",
+               "AFMR", "Line In",
+               "DMic", "Digital Mic",
+               "Digital Mic", "Digital Mic1 Bias";
+};
diff --git a/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt b/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt
new file mode 100644 (file)
index 0000000..801d58c
--- /dev/null
@@ -0,0 +1,15 @@
+* Freescale i.MX28 LRADC device driver
+
+Required properties:
+- compatible: Should be "fsl,imx28-lradc"
+- reg: Address and length of the register set for the device
+- interrupts: Should contain the LRADC interrupts
+
+Examples:
+
+       lradc@80050000 {
+               compatible = "fsl,imx28-lradc";
+               reg = <0x80050000 0x2000>;
+               interrupts = <10 14 15 16 17 18 19
+                               20 21 22 23 24 25>;
+       };
diff --git a/Documentation/devicetree/bindings/tty/serial/nxp-lpc32xx-hsuart.txt b/Documentation/devicetree/bindings/tty/serial/nxp-lpc32xx-hsuart.txt
new file mode 100644 (file)
index 0000000..0d439df
--- /dev/null
@@ -0,0 +1,14 @@
+* NXP LPC32xx SoC High Speed UART
+
+Required properties:
+- compatible: Should be "nxp,lpc3220-hsuart"
+- reg: Should contain registers location and length
+- interrupts: Should contain interrupt
+
+Example:
+
+       uart1: serial@40014000 {
+               compatible = "nxp,lpc3220-hsuart";
+               reg = <0x40014000 0x1000>;
+               interrupts = <26 0>;
+       };
index 0847fdeee11a5b2961731b97c017df5bf4f4f9ca..ba385f2e0ddc5777daf3f7e9d667e6727ec4c26d 100644 (file)
@@ -25,6 +25,8 @@ Optional properties:
   accesses to the UART (e.g. TI davinci).
 - used-by-rtas : set to indicate that the port is in use by the OpenFirmware
   RTAS and should not be registered.
+- no-loopback-test: set to indicate that the port does not implements loopback
+  test mode
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/usb/platform-uhci.txt b/Documentation/devicetree/bindings/usb/platform-uhci.txt
new file mode 100644 (file)
index 0000000..91477d6
--- /dev/null
@@ -0,0 +1,12 @@
+Generic Platform UHCI controllers.
+
+Required properties:
+ - compatible: Should be "platform-uhci".
+ - reg: Address range of the uhci registers
+ - interrupts: Should contain the uhci interrupt.
+
+usb: uhci@D8007301 {
+       compatible = "platform-uhci", "usb-uhci";
+       reg = <0xD8007301 0x200>;
+       interrupts = <0>;
+};
diff --git a/Documentation/devicetree/bindings/usb/pxa-usb.txt b/Documentation/devicetree/bindings/usb/pxa-usb.txt
new file mode 100644 (file)
index 0000000..79729a9
--- /dev/null
@@ -0,0 +1,31 @@
+PXA USB controllers
+
+OHCI
+
+Required properties:
+ - compatible: Should be "marvell,pxa-ohci" for USB controllers
+   used in host mode.
+
+Optional properties:
+ - "marvell,enable-port1", "marvell,enable-port2", "marvell,enable-port3"
+   If present, enables the appropriate USB port of the controller.
+ - "marvell,port-mode" selects the mode of the ports:
+       1 = PMM_NPS_MODE
+       2 = PMM_GLOBAL_MODE
+       3 = PMM_PERPORT_MODE
+ - "marvell,power-sense-low" - power sense pin is low-active.
+ - "marvell,power-control-low" - power control pin is low-active.
+ - "marvell,no-oc-protection" - disable over-current protection.
+ - "marvell,oc-mode-perport" - enable per-port over-current protection.
+ - "marvell,power_on_delay" Power On to Power Good time - in ms.
+
+Example:
+
+       usb0: ohci@4c000000 {
+               compatible = "marvell,pxa-ohci", "usb-ohci";
+               reg = <0x4c000000 0x100000>;
+               interrupts = <18>;
+               marvell,enable-port1;
+               marvell,port-mode = <2>; /* PMM_GLOBAL_MODE */
+       };
+
diff --git a/Documentation/devicetree/bindings/usb/vt8500-ehci.txt b/Documentation/devicetree/bindings/usb/vt8500-ehci.txt
new file mode 100644 (file)
index 0000000..5fb8fd6
--- /dev/null
@@ -0,0 +1,12 @@
+VIA VT8500 and Wondermedia WM8xxx SoC USB controllers.
+
+Required properties:
+ - compatible: Should be "via,vt8500-ehci" or "wm,prizm-ehci".
+ - reg: Address range of the ehci registers. size should be 0x200
+ - interrupts: Should contain the ehci interrupt.
+
+usb: ehci@D8007100 {
+       compatible = "wm,prizm-ehci", "usb-ehci";
+       reg = <0xD8007100 0x200>;
+       interrupts = <1>;
+};
diff --git a/Documentation/devicetree/bindings/w1/w1-gpio.txt b/Documentation/devicetree/bindings/w1/w1-gpio.txt
new file mode 100644 (file)
index 0000000..6e09c35
--- /dev/null
@@ -0,0 +1,22 @@
+w1-gpio devicetree bindings
+
+Required properties:
+
+ - compatible: "w1-gpio"
+ - gpios: one or two GPIO specs:
+               - the first one is used as data I/O pin
+               - the second one is optional. If specified, it is used as
+                 enable pin for an external pin pullup.
+
+Optional properties:
+
+ - linux,open-drain: if specified, the data pin is considered in
+                    open-drain mode.
+
+Examples:
+
+       onewire@0 {
+               compatible = "w1-gpio";
+               gpios = <&gpio 126 0>, <&gpio 105 0>;
+       };
+
index 0f103e39b4f6a025cb486cbdfb21126c78992738..e540a24e5d069d4f6372adaabfa792ff11897ca9 100644 (file)
@@ -114,7 +114,6 @@ prototypes:
        int (*drop_inode) (struct inode *);
        void (*evict_inode) (struct inode *);
        void (*put_super) (struct super_block *);
-       void (*write_super) (struct super_block *);
        int (*sync_fs)(struct super_block *sb, int wait);
        int (*freeze_fs) (struct super_block *);
        int (*unfreeze_fs) (struct super_block *);
@@ -136,7 +135,6 @@ write_inode:
 drop_inode:                            !!!inode->i_lock!!!
 evict_inode:
 put_super:             write
-write_super:           read
 sync_fs:               read
 freeze_fs:             write
 unfreeze_fs:           write
index 2bef2b3843d1d4e09ead99fed121de4b2ab92db2..0742feebc6e221f9d79e400adab5feaba23098de 100644 (file)
@@ -94,9 +94,8 @@ protected.
 ---
 [mandatory]
 
-BKL is also moved from around sb operations.  ->write_super() Is now called 
-without BKL held.  BKL should have been shifted into individual fs sb_op
-functions.  If you don't need it, remove it.  
+BKL is also moved from around sb operations. BKL should have been shifted into
+individual fs sb_op functions.  If you don't need it, remove it.
 
 ---
 [informational]
index 065aa2dc083538dcf05a9e2863e8b14fddb9b514..2ee133e030c3f51521321afd62d5dd3b1d1650fb 100644 (file)
@@ -216,7 +216,6 @@ struct super_operations {
         void (*drop_inode) (struct inode *);
         void (*delete_inode) (struct inode *);
         void (*put_super) (struct super_block *);
-        void (*write_super) (struct super_block *);
         int (*sync_fs)(struct super_block *sb, int wait);
         int (*freeze_fs) (struct super_block *);
         int (*unfreeze_fs) (struct super_block *);
@@ -273,9 +272,6 @@ or bottom half).
   put_super: called when the VFS wishes to free the superblock
        (i.e. unmount). This is called with the superblock lock held
 
-  write_super: called when the VFS superblock needs to be written to
-       disc. This method is optional
-
   sync_fs: called when VFS is writing out all dirty data associated with
        a superblock. The second parameter indicates whether the method
        should wait until the write out has been completed. Optional.
diff --git a/Documentation/hwmon/adt7410 b/Documentation/hwmon/adt7410
new file mode 100644 (file)
index 0000000..9600400
--- /dev/null
@@ -0,0 +1,51 @@
+Kernel driver adt7410
+=====================
+
+Supported chips:
+  * Analog Devices ADT7410
+    Prefix: 'adt7410'
+    Addresses scanned: I2C 0x48 - 0x4B
+    Datasheet: Publicly available at the Analog Devices website
+               http://www.analog.com/static/imported-files/data_sheets/ADT7410.pdf
+
+Author: Hartmut Knaack <knaack.h@gmx.de>
+
+Description
+-----------
+
+The ADT7410 is a temperature sensor with rated temperature range of -55°C to
++150°C. It has a high accuracy of +/-0.5°C and can be operated at a resolution
+of 13 bits (0.0625°C) or 16 bits (0.0078°C). The sensor provides an INT pin to
+indicate that a minimum or maximum temperature set point has been exceeded, as
+well as a critical temperature (CT) pin to indicate that the critical
+temperature set point has been exceeded. Both pins can be set up with a common
+hysteresis of 0°C - 15°C and a fault queue, ranging from 1 to 4 events. Both
+pins can individually set to be active-low or active-high, while the whole
+device can either run in comparator mode or interrupt mode. The ADT7410
+supports continous temperature sampling, as well as sampling one temperature
+value per second or even justget one sample on demand for power saving.
+Besides, it can completely power down its ADC, if power management is
+required.
+
+Configuration Notes
+-------------------
+
+Since the device uses one hysteresis value, which is an offset to minimum,
+maximum and critical temperature, it can only be set for temp#_max_hyst.
+However, temp#_min_hyst and temp#_crit_hyst show their corresponding
+hysteresis.
+The device is set to 16 bit resolution and comparator mode.
+
+sysfs-Interface
+---------------
+
+temp#_input            - temperature input
+temp#_min              - temperature minimum setpoint
+temp#_max              - temperature maximum setpoint
+temp#_crit             - critical temperature setpoint
+temp#_min_hyst         - hysteresis for temperature minimum (read-only)
+temp#_max_hyst         - hysteresis for temperature maximum (read/write)
+temp#_crit_hyst                - hysteresis for critical temperature (read-only)
+temp#_min_alarm                - temperature minimum alarm flag
+temp#_max_alarm                - temperature maximum alarm flag
+temp#_crit_alarm       - critical temperature alarm flag
index ad7e2e5088c126ce48e0362d1f3296f3e8b55d2b..a3740ac03367cc925b2fa1b201244942148ac56c 100644 (file)
@@ -1350,6 +1350,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        * nohrst, nosrst, norst: suppress hard, soft
                           and both resets.
 
+                       * rstonce: only attempt one reset during
+                         hot-unplug link recovery
+
                        * dump_id: dump IDENTIFY data.
 
                        If there are multiple matching configurations changing
@@ -2385,6 +2388,17 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
        rcutree.rcu_cpu_stall_timeout= [KNL,BOOT]
                        Set timeout for RCU CPU stall warning messages.
 
+       rcutree.jiffies_till_first_fqs= [KNL,BOOT]
+                       Set delay from grace-period initialization to
+                       first attempt to force quiescent states.
+                       Units are jiffies, minimum value is zero,
+                       and maximum value is HZ.
+
+       rcutree.jiffies_till_next_fqs= [KNL,BOOT]
+                       Set delay between subsequent attempts to force
+                       quiescent states.  Units are jiffies, minimum
+                       value is one, and maximum value is HZ.
+
        rcutorture.fqs_duration= [KNL,BOOT]
                        Set duration of force_quiescent_state bursts.
 
index 0bf25eebce948b4a330fe8868db387e742108278..4ebbfc3f1c6ea803b1cb7b5b71c1e98c6d8e3f17 100644 (file)
@@ -262,9 +262,9 @@ MINIMUM_BATTERY_MINUTES=10
 
 #
 # Allowed dirty background ratio, in percent.  Once DIRTY_RATIO has been
-# exceeded, the kernel will wake pdflush which will then reduce the amount
-# of dirty memory to dirty_background_ratio.  Set this nice and low, so once
-# some writeout has commenced, we do a lot of it.
+# exceeded, the kernel will wake flusher threads which will then reduce the
+# amount of dirty memory to dirty_background_ratio.  Set this nice and low,
+# so once some writeout has commenced, we do a lot of it.
 #
 #DIRTY_BACKGROUND_RATIO=5
 
@@ -384,9 +384,9 @@ CPU_MAXFREQ=${CPU_MAXFREQ:-'slowest'}
 
 #
 # Allowed dirty background ratio, in percent.  Once DIRTY_RATIO has been
-# exceeded, the kernel will wake pdflush which will then reduce the amount
-# of dirty memory to dirty_background_ratio.  Set this nice and low, so once
-# some writeout has commenced, we do a lot of it.
+# exceeded, the kernel will wake flusher threads which will then reduce the
+# amount of dirty memory to dirty_background_ratio.  Set this nice and low,
+# so once some writeout has commenced, we do a lot of it.
 #
 DIRTY_BACKGROUND_RATIO=${DIRTY_BACKGROUND_RATIO:-'5'}
 
index 8d022073e3ef53933898c6756c3abf6d50104a79..2e9e0ae2cd453dc3ac0a605c1a40baf1096cf42f 100644 (file)
@@ -51,8 +51,23 @@ Built-in netconsole starts immediately after the TCP stack is
 initialized and attempts to bring up the supplied dev at the supplied
 address.
 
-The remote host can run either 'netcat -u -l -p <port>',
-'nc -l -u <port>' or syslogd.
+The remote host has several options to receive the kernel messages,
+for example:
+
+1) syslogd
+
+2) netcat
+
+   On distributions using a BSD-based netcat version (e.g. Fedora,
+   openSUSE and Ubuntu) the listening port must be specified without
+   the -p switch:
+
+   'nc -u -l -p <port>' / 'nc -u -l <port>' or
+   'netcat -u -l -p <port>' / 'netcat -u -l <port>'
+
+3) socat
+
+   'socat udp-recv:<port> -'
 
 Dynamic reconfiguration:
 ========================
index e40f4b4e1977c73d1f6984c705c1065878ad4ad4..1479aca2374441976c14668b7bc7e523fbb2211f 100644 (file)
@@ -840,9 +840,9 @@ static unsigned long i2c_pin_configs[] = {
 
 static struct pinctrl_map __initdata mapping[] = {
        PIN_MAP_MUX_GROUP("foo-i2c.0", PINCTRL_STATE_DEFAULT, "pinctrl-foo", "i2c0", "i2c0"),
-       PIN_MAP_MUX_CONFIGS_GROUP("foo-i2c.0", PINCTRL_STATE_DEFAULT, "pinctrl-foo", "i2c0", i2c_grp_configs),
-       PIN_MAP_MUX_CONFIGS_PIN("foo-i2c.0", PINCTRL_STATE_DEFAULT, "pinctrl-foo", "i2c0scl", i2c_pin_configs),
-       PIN_MAP_MUX_CONFIGS_PIN("foo-i2c.0", PINCTRL_STATE_DEFAULT, "pinctrl-foo", "i2c0sda", i2c_pin_configs),
+       PIN_MAP_CONFIGS_GROUP("foo-i2c.0", PINCTRL_STATE_DEFAULT, "pinctrl-foo", "i2c0", i2c_grp_configs),
+       PIN_MAP_CONFIGS_PIN("foo-i2c.0", PINCTRL_STATE_DEFAULT, "pinctrl-foo", "i2c0scl", i2c_pin_configs),
+       PIN_MAP_CONFIGS_PIN("foo-i2c.0", PINCTRL_STATE_DEFAULT, "pinctrl-foo", "i2c0sda", i2c_pin_configs),
 };
 
 Finally, some devices expect the mapping table to contain certain specific
index 80441ab608e4f04f530119db621ec9e7941545ac..3a3079411a3dc953c59cb75b8391906b2fb74df3 100644 (file)
@@ -1,3 +1,13 @@
+Release Date    : Tue. Jun 17, 2012 17:00:00 PST 2012 -
+                       (emaild-id:megaraidlinux@lsi.com)
+                       Adam Radford/Kashyap Desai
+Current Version : 00.00.06.18-rc1
+Old Version     : 00.00.06.15-rc1
+    1. Fix Copyright dates.
+    2. Add throttlequeuedepth module parameter.
+    3. Add resetwaittime module parameter.
+    4. Move poll_aen_lock initializer.
+-------------------------------------------------------------------------------
 Release Date    : Mon. Mar 19, 2012 17:00:00 PST 2012 -
                        (emaild-id:megaraidlinux@lsi.com)
                        Adam Radford
index e369de2d48cdf2f24c96a8373b8506d10800f28f..dd908cf64ecfcb7a809685a7eb2beb508cb30815 100644 (file)
@@ -46,14 +46,13 @@ restrictions, it can call prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, ...)
 so that any otherwise allowed process (even those in external pid namespaces)
 may attach.
 
-These restrictions do not change how ptrace via PTRACE_TRACEME operates.
-
-The sysctl settings are:
+The sysctl settings (writable only with CAP_SYS_PTRACE) are:
 
 0 - classic ptrace permissions: a process can PTRACE_ATTACH to any other
     process running under the same uid, as long as it is dumpable (i.e.
     did not transition uids, start privileged, or have called
-    prctl(PR_SET_DUMPABLE...) already).
+    prctl(PR_SET_DUMPABLE...) already). Similarly, PTRACE_TRACEME is
+    unchanged.
 
 1 - restricted ptrace: a process must have a predefined relationship
     with the inferior it wants to call PTRACE_ATTACH on. By default,
@@ -61,12 +60,13 @@ The sysctl settings are:
     classic criteria is also met. To change the relationship, an
     inferior can call prctl(PR_SET_PTRACER, debugger, ...) to declare
     an allowed debugger PID to call PTRACE_ATTACH on the inferior.
+    Using PTRACE_TRACEME is unchanged.
 
 2 - admin-only attach: only processes with CAP_SYS_PTRACE may use ptrace
-    with PTRACE_ATTACH.
+    with PTRACE_ATTACH, or through children calling PTRACE_TRACEME.
 
-3 - no attach: no processes may use ptrace with PTRACE_ATTACH. Once set,
-    this sysctl cannot be changed to a lower value.
+3 - no attach: no processes may use ptrace with PTRACE_ATTACH nor via
+    PTRACE_TRACEME. Once set, this sysctl value cannot be changed.
 
 The original children-only logic was based on the restrictions in grsecurity.
 
index e09468ad3cb16f97f4ef3075b5f743dd258fb01b..f7b0c7dc25ef283cc3fe689a4c6f4124c1114e70 100644 (file)
@@ -2,8 +2,6 @@
        - this file.
 README.cycladesZ
        - info on Cyclades-Z firmware loading.
-computone.txt
-       - info on Computone Intelliport II/Plus Multiport Serial Driver.
 digiepca.txt
        - info on Digi Intl. {PC,PCI,EISA}Xx and Xem series cards.
 hayes-esp.txt
diff --git a/Documentation/serial/computone.txt b/Documentation/serial/computone.txt
deleted file mode 100644 (file)
index a6a1158..0000000
+++ /dev/null
@@ -1,520 +0,0 @@
-NOTE: This is an unmaintained driver.  It is not guaranteed to work due to
-changes made in the tty layer in 2.6.  If you wish to take over maintenance of
-this driver, contact Michael Warfield <mhw@wittsend.com>.
-
-Changelog:
-----------
-11-01-2001:    Original Document
-
-10-29-2004:    Minor misspelling & format fix, update status of driver.
-               James Nelson <james4765@gmail.com>
-
-Computone Intelliport II/Plus Multiport Serial Driver
------------------------------------------------------
-
-Release Notes For Linux Kernel 2.2 and higher.
-These notes are for the drivers which have already been integrated into the
-kernel and have been tested on Linux kernels 2.0, 2.2, 2.3, and 2.4.
-
-Version: 1.2.14
-Date: 11/01/2001
-Historical Author: Andrew Manison <amanison@america.net>
-Primary Author: Doug McNash
-
-This file assumes that you are using the Computone drivers which are
-integrated into the kernel sources.  For updating the drivers or installing
-drivers into kernels which do not already have Computone drivers, please
-refer to the instructions in the README.computone file in the driver patch.
-
-
-1. INTRODUCTION
-
-This driver supports the entire family of Intelliport II/Plus controllers
-with the exception of the MicroChannel controllers.  It does not support
-products previous to the Intelliport II.
-
-This driver was developed on the v2.0.x Linux tree and has been tested up
-to v2.4.14; it will probably not work with earlier v1.X kernels,.
-
-
-2. QUICK INSTALLATION
-
-Hardware - If you have an ISA card, find a free interrupt and io port. 
-                  List those in use with `cat /proc/interrupts` and 
-                  `cat /proc/ioports`.  Set the card dip switches to a free 
-                  address.  You may need to configure your BIOS to reserve an
-                  irq for an ISA card.  PCI and EISA parameters are set
-                  automagically.  Insert card into computer with the power off 
-                  before or after drivers installation.
-
-       Note the hardware address from the Computone ISA cards installed into
-               the system.  These are required for editing ip2.c or editing
-               /etc/modprobe.d/*.conf, or for specification on the modprobe
-               command line.
-
-       Note that the /etc/modules.conf should be used for older (pre-2.6)
-               kernels.
-
-Software -
-
-Module installation:
-
-a) Determine free irq/address to use if any (configure BIOS if need be)
-b) Run "make config" or "make menuconfig" or "make xconfig"
-   Select (m) module for CONFIG_COMPUTONE under character
-   devices.  CONFIG_PCI and CONFIG_MODULES also may need to be set.
-c) Set address on ISA cards then:
-   edit /usr/src/linux/drivers/char/ip2.c if needed 
-       or
-   edit config file in  /etc/modprobe.d/ if needed (module).
-       or both to match this setting.
-d) Run "make modules"
-e) Run "make modules_install"
-f) Run "/sbin/depmod -a"
-g) install driver using `modprobe ip2 <options>` (options listed below)
-h) run ip2mkdev (either the script below or the binary version)
-
-
-Kernel installation:
-
-a) Determine free irq/address to use if any (configure BIOS if need be)
-b) Run "make config" or "make menuconfig" or "make xconfig"
-   Select (y) kernel for CONFIG_COMPUTONE under character
-   devices.  CONFIG_PCI may need to be set if you have PCI bus.
-c) Set address on ISA cards then:
-          edit /usr/src/linux/drivers/char/ip2.c  
-           (Optional - may be specified on kernel command line now)
-d) Run "make zImage" or whatever target you prefer.
-e) mv /usr/src/linux/arch/x86/boot/zImage to /boot.
-f) Add new config for this kernel into /etc/lilo.conf, run "lilo"
-       or copy to a floppy disk and boot from that floppy disk.
-g) Reboot using this kernel
-h) run ip2mkdev (either the script below or the binary version)
-
-Kernel command line options:
-
-When compiling the driver into the kernel, io and irq may be
-compiled into the driver by editing ip2.c and setting the values for
-io and irq in the appropriate array.  An alternative is to specify
-a command line parameter to the kernel at boot up.
-
-        ip2=io0,irq0,io1,irq1,io2,irq2,io3,irq3
-
-Note that this order is very different from the specifications for the
-modload parameters which have separate IRQ and IO specifiers.
-
-The io port also selects PCI (1) and EISA (2) boards.
-
-        io=0    No board
-        io=1    PCI board
-        io=2    EISA board
-        else    ISA board io address
-
-You only need to specify the boards which are present.
-
-        Examples:
-
-                2 PCI boards:
-
-                        ip2=1,0,1,0
-
-                1 ISA board at 0x310 irq 5:
-
-                        ip2=0x310,5
-
-This can be added to and "append" option in lilo.conf similar to this:
-
-        append="ip2=1,0,1,0"
-
-
-3. INSTALLATION
-
-Previously, the driver sources were packaged with a set of patch files
-to update the character drivers' makefile and configuration file, and other 
-kernel source files. A build script (ip2build) was included which applies 
-the patches if needed, and build any utilities needed.
-What you receive may be a single patch file in conventional kernel
-patch format build script. That form can also be applied by
-running patch -p1 < ThePatchFile.  Otherwise run ip2build.
-The driver can be installed as a module (recommended) or built into the 
-kernel. This is selected as for other drivers through the `make config`
-command from the root of the Linux source tree. If the driver is built 
-into the kernel you will need to edit the file ip2.c to match the boards 
-you are installing. See that file for instructions. If the driver is 
-installed as a module the configuration can also be specified on the
-modprobe command line as follows:
-
-       modprobe ip2 irq=irq1,irq2,irq3,irq4 io=addr1,addr2,addr3,addr4
-
-where irqnum is one of the valid Intelliport II interrupts (3,4,5,7,10,11,
-12,15) and addr1-4 are the base addresses for up to four controllers. If 
-the irqs are not specified the driver uses the default in ip2.c (which 
-selects polled mode). If no base addresses are specified the defaults in 
-ip2.c are used. If you are autoloading the driver module with kerneld or
-kmod the base addresses and interrupt number must also be set in ip2.c
-and recompile or just insert and options line in /etc/modprobe.d/*.conf or both.
-The options line is equivalent to the command line and takes precedence over
-what is in ip2.c. 
-
-config sample to put /etc/modprobe.d/*.conf:
-       options ip2 io=1,0x328 irq=1,10
-       alias char-major-71 ip2
-       alias char-major-72 ip2
-       alias char-major-73 ip2
-
-The equivalent in ip2.c:
-
-static int io[IP2_MAX_BOARDS]= { 1, 0x328, 0, 0 };
-static int irq[IP2_MAX_BOARDS] = { 1, 10, -1, -1 }; 
-
-The equivalent for the kernel command line (in lilo.conf):
-
-        append="ip2=1,1,0x328,10"
-
-
-Note:  Both io and irq should be updated to reflect YOUR system.  An "io"
-       address of 1 or 2 indicates a PCI or EISA card in the board table.
-       The PCI or EISA irq will be assigned automatically.
-
-Specifying an invalid or in-use irq will default the driver into
-running in polled mode for that card.  If all irq entries are 0 then
-all cards will operate in polled mode.
-
-If you select the driver as part of the kernel run :
-
-       make zlilo (or whatever you do to create a bootable kernel)
-
-If you selected a module run :
-
-       make modules && make modules_install
-
-The utility ip2mkdev (see 5 and 7 below) creates all the device nodes
-required by the driver.  For a device to be created it must be configured
-in the driver and the board must be installed. Only devices corresponding
-to real IntelliPort II ports are created. With multiple boards and expansion
-boxes this will leave gaps in the sequence of device names. ip2mkdev uses
-Linux tty naming conventions: ttyF0 - ttyF255 for normal devices, and
-cuf0 - cuf255 for callout devices.
-
-
-4. USING THE DRIVERS
-
-As noted above, the driver implements the ports in accordance with Linux
-conventions, and the devices should be interchangeable with the standard
-serial devices. (This is a key point for problem reporting: please make
-sure that what you are trying do works on the ttySx/cuax ports first; then 
-tell us what went wrong with the ip2 ports!)
-
-Higher speeds can be obtained using the setserial utility which remaps 
-38,400 bps (extb) to 57,600 bps, 115,200 bps, or a custom speed. 
-Intelliport II installations using the PowerPort expansion module can
-use the custom speed setting to select the highest speeds: 153,600 bps,
-230,400 bps, 307,200 bps, 460,800bps and 921,600 bps. The base for
-custom baud rate configuration is fixed at 921,600 for cards/expansion
-modules with ST654's and 115200 for those with Cirrus CD1400's.  This
-corresponds to the maximum bit rates those chips are capable.  
-For example if the baud base is 921600 and the baud divisor is 18 then
-the custom rate is 921600/18 = 51200 bps.  See the setserial man page for
-complete details. Of course if stty accepts the higher rates now you can
-use that as well as the standard ioctls().
-
-
-5. ip2mkdev and assorted utilities...
-
-Several utilities, including the source for a binary ip2mkdev utility are
-available under .../drivers/char/ip2.  These can be build by changing to
-that directory and typing "make" after the kernel has be built.  If you do
-not wish to compile the binary utilities, the shell script below can be
-cut out and run as "ip2mkdev" to create the necessary device files.  To
-use the ip2mkdev script, you must have procfs enabled and the proc file
-system mounted on /proc.
-
-
-6. NOTES
-
-This is a release version of the driver, but it is impossible to test it
-in all configurations of Linux. If there is any anomalous behaviour that 
-does not match the standard serial port's behaviour please let us know.
-
-
-7. ip2mkdev shell script
-
-Previously, this script was simply attached here.  It is now attached as a
-shar archive to make it easier to extract the script from the documentation.
-To create the ip2mkdev shell script change to a convenient directory (/tmp
-works just fine) and run the following command:
-
-       unshar Documentation/serial/computone.txt
-               (This file)
-
-You should now have a file ip2mkdev in your current working directory with
-permissions set to execute.  Running that script with then create the
-necessary devices for the Computone boards, interfaces, and ports which
-are present on you system at the time it is run.
-
-
-#!/bin/sh
-# This is a shell archive (produced by GNU sharutils 4.2.1).
-# To extract the files from this archive, save it to some FILE, remove
-# everything before the `!/bin/sh' line above, then type `sh FILE'.
-#
-# Made on 2001-10-29 10:32 EST by <mhw@alcove.wittsend.com>.
-# Source directory was `/home2/src/tmp'.
-#
-# Existing files will *not* be overwritten unless `-c' is specified.
-#
-# This shar contains:
-# length mode       name
-# ------ ---------- ------------------------------------------
-#   4251 -rwxr-xr-x ip2mkdev
-#
-save_IFS="${IFS}"
-IFS="${IFS}:"
-gettext_dir=FAILED
-locale_dir=FAILED
-first_param="$1"
-for dir in $PATH
-do
-  if test "$gettext_dir" = FAILED && test -f $dir/gettext \
-     && ($dir/gettext --version >/dev/null 2>&1)
-  then
-    set `$dir/gettext --version 2>&1`
-    if test "$3" = GNU
-    then
-      gettext_dir=$dir
-    fi
-  fi
-  if test "$locale_dir" = FAILED && test -f $dir/shar \
-     && ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
-  then
-    locale_dir=`$dir/shar --print-text-domain-dir`
-  fi
-done
-IFS="$save_IFS"
-if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED
-then
-  echo=echo
-else
-  TEXTDOMAINDIR=$locale_dir
-  export TEXTDOMAINDIR
-  TEXTDOMAIN=sharutils
-  export TEXTDOMAIN
-  echo="$gettext_dir/gettext -s"
-fi
-if touch -am -t 200112312359.59 $$.touch >/dev/null 2>&1 && test ! -f 200112312359.59 -a -f $$.touch; then
-  shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"'
-elif touch -am 123123592001.59 $$.touch >/dev/null 2>&1 && test ! -f 123123592001.59 -a ! -f 123123592001.5 -a -f $$.touch; then
-  shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"'
-elif touch -am 1231235901 $$.touch >/dev/null 2>&1 && test ! -f 1231235901 -a -f $$.touch; then
-  shar_touch='touch -am $3$4$5$6$2 "$8"'
-else
-  shar_touch=:
-  echo
-  $echo 'WARNING: not restoring timestamps.  Consider getting and'
-  $echo "installing GNU \`touch', distributed in GNU File Utilities..."
-  echo
-fi
-rm -f 200112312359.59 123123592001.59 123123592001.5 1231235901 $$.touch
-#
-if mkdir _sh17581; then
-  $echo 'x -' 'creating lock directory'
-else
-  $echo 'failed to create lock directory'
-  exit 1
-fi
-# ============= ip2mkdev ==============
-if test -f 'ip2mkdev' && test "$first_param" != -c; then
-  $echo 'x -' SKIPPING 'ip2mkdev' '(file already exists)'
-else
-  $echo 'x -' extracting 'ip2mkdev' '(text)'
-  sed 's/^X//' << 'SHAR_EOF' > 'ip2mkdev' &&
-#!/bin/sh -
-#
-#      ip2mkdev
-#
-#      Make or remove devices as needed for Computone Intelliport drivers
-#
-#      First rule!  If the dev file exists and you need it, don't mess
-#      with it.  That prevents us from screwing up open ttys, ownership
-#      and permissions on a running system!
-#
-#      This script will NOT remove devices that no longer exist if their
-#      board or interface box has been removed.  If you want to get rid
-#      of them, you can manually do an "rm -f /dev/ttyF* /dev/cuaf*"
-#      before running this script.  Running this script will then recreate
-#      all the valid devices.
-#
-#      Michael H. Warfield
-#      /\/\|=mhw=|\/\/
-#      mhw@wittsend.com
-#
-#      Updated 10/29/2000 for version 1.2.13 naming convention
-#              under devfs.    /\/\|=mhw=|\/\/
-#
-#      Updated 03/09/2000 for devfs support in ip2 drivers. /\/\|=mhw=|\/\/
-#
-X
-if test -d /dev/ip2 ; then
-#      This is devfs mode...  We don't do anything except create symlinks
-#      from the real devices to the old names!
-X      cd /dev
-X      echo "Creating symbolic links to devfs devices"
-X      for i in `ls ip2` ; do
-X              if test ! -L ip2$i ; then
-X                      # Remove it incase it wasn't a symlink (old device)
-X                      rm -f ip2$i
-X                      ln -s ip2/$i ip2$i
-X              fi
-X      done
-X      for i in `( cd tts ; ls F* )` ; do
-X              if test ! -L tty$i ; then
-X                      # Remove it incase it wasn't a symlink (old device)
-X                      rm -f tty$i
-X                      ln -s tts/$i tty$i
-X              fi
-X      done
-X      for i in `( cd cua ; ls F* )` ; do
-X              DEVNUMBER=`expr $i : 'F\(.*\)'`
-X              if test ! -L cuf$DEVNUMBER ; then
-X                      # Remove it incase it wasn't a symlink (old device)
-X                      rm -f cuf$DEVNUMBER
-X                      ln -s cua/$i cuf$DEVNUMBER
-X              fi
-X      done
-X      exit 0
-fi
-X
-if test ! -f /proc/tty/drivers
-then
-X      echo "\
-Unable to check driver status.
-Make sure proc file system is mounted."
-X
-X      exit 255
-fi
-X
-if test ! -f /proc/tty/driver/ip2
-then
-X      echo "\
-Unable to locate ip2 proc file.
-Attempting to load driver"
-X
-X      if /sbin/insmod ip2
-X      then
-X              if test ! -f /proc/tty/driver/ip2
-X              then
-X                      echo "\
-Unable to locate ip2 proc file after loading driver.
-Driver initialization failure or driver version error.
-"
-X              exit 255
-X              fi
-X      else
-X              echo "Unable to load ip2 driver."
-X              exit 255
-X      fi
-fi
-X
-# Ok...  So we got the driver loaded and we can locate the procfs files.
-# Next we need our major numbers.
-X
-TTYMAJOR=`sed -e '/^ip2/!d' -e '/\/dev\/tt/!d' -e 's/.*tt[^    ]*[     ]*\([0-9]*\)[   ]*.*/\1/' < /proc/tty/drivers`
-CUAMAJOR=`sed -e '/^ip2/!d' -e '/\/dev\/cu/!d' -e 's/.*cu[^    ]*[     ]*\([0-9]*\)[   ]*.*/\1/' < /proc/tty/drivers`
-BRDMAJOR=`sed -e '/^Driver: /!d' -e 's/.*IMajor=\([0-9]*\)[    ]*.*/\1/' < /proc/tty/driver/ip2`
-X
-echo "\
-TTYMAJOR = $TTYMAJOR
-CUAMAJOR = $CUAMAJOR
-BRDMAJOR = $BRDMAJOR
-"
-X
-# Ok...  Now we should know our major numbers, if appropriate...
-# Now we need our boards and start the device loops.
-X
-grep '^Board [0-9]:' /proc/tty/driver/ip2 | while read token number type alltherest
-do
-X      # The test for blank "type" will catch the stats lead-in lines
-X      # if they exist in the file
-X      if test "$type" = "vacant" -o "$type" = "Vacant" -o "$type" = ""
-X      then
-X              continue
-X      fi
-X
-X      BOARDNO=`expr "$number" : '\([0-9]\):'`
-X      PORTS=`expr "$alltherest" : '.*ports=\([0-9]*\)' | tr ',' ' '`
-X      MINORS=`expr "$alltherest" : '.*minors=\([0-9,]*\)' | tr ',' ' '`
-X
-X      if test "$BOARDNO" = "" -o "$PORTS" = ""
-X      then
-#      This may be a bug.  We should at least get this much information
-X              echo "Unable to process board line"
-X              continue
-X      fi
-X
-X      if test "$MINORS" = ""
-X      then
-#      Silently skip this one.  This board seems to have no boxes
-X              continue
-X      fi
-X
-X      echo "board $BOARDNO: $type ports = $PORTS; port numbers = $MINORS"
-X
-X      if test "$BRDMAJOR" != ""
-X      then
-X              BRDMINOR=`expr $BOARDNO \* 4`
-X              STSMINOR=`expr $BRDMINOR + 1`
-X              if test ! -c /dev/ip2ipl$BOARDNO ; then
-X                      mknod /dev/ip2ipl$BOARDNO c $BRDMAJOR $BRDMINOR
-X              fi
-X              if test ! -c /dev/ip2stat$BOARDNO ; then
-X                      mknod /dev/ip2stat$BOARDNO c $BRDMAJOR $STSMINOR
-X              fi
-X      fi
-X
-X      if test "$TTYMAJOR" != ""
-X      then
-X              PORTNO=$BOARDBASE
-X
-X              for PORTNO in $MINORS
-X              do
-X                      if test ! -c /dev/ttyF$PORTNO ; then
-X                              # We got the hardware but no device - make it
-X                              mknod /dev/ttyF$PORTNO c $TTYMAJOR $PORTNO
-X                      fi      
-X              done
-X      fi
-X
-X      if test "$CUAMAJOR" != ""
-X      then
-X              PORTNO=$BOARDBASE
-X
-X              for PORTNO in $MINORS
-X              do
-X                      if test ! -c /dev/cuf$PORTNO ; then
-X                              # We got the hardware but no device - make it
-X                              mknod /dev/cuf$PORTNO c $CUAMAJOR $PORTNO
-X                      fi      
-X              done
-X      fi
-done
-X
-Xexit 0
-SHAR_EOF
-  (set 20 01 10 29 10 32 01 'ip2mkdev'; eval "$shar_touch") &&
-  chmod 0755 'ip2mkdev' ||
-  $echo 'restore of' 'ip2mkdev' 'failed'
-  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
-  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
-    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
-    || $echo 'ip2mkdev:' 'MD5 check failed'
-cb5717134509f38bad9fde6b1f79b4a4  ip2mkdev
-SHAR_EOF
-  else
-    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'ip2mkdev'`"
-    test 4251 -eq "$shar_count" ||
-    $echo 'ip2mkdev:' 'original size' '4251,' 'current size' "$shar_count!"
-  fi
-fi
-rm -fr _sh17581
-exit 0
index a92bba8168435bc731ce8db34530d55639fa8def..16dfe57f173167c9df59bfdc6c1cefff9db2fa0f 100644 (file)
@@ -74,7 +74,8 @@ CMI9880
 
 AD1882 / AD1882A
 ================
-  3stack       3-stack mode (default)
+  3stack       3-stack mode
+  3stack-automute 3-stack with automute front HP (default)
   6stack       6-stack mode
 
 AD1884A / AD1883 / AD1984A / AD1984B
index dcc2a94ae34e7d4a976c8fd2f5613236c05968f3..078701fdbd4dd936dd485737abe7b5b60e554604 100644 (file)
@@ -76,8 +76,8 @@ huge pages although processes will also directly compact memory as required.
 
 dirty_background_bytes
 
-Contains the amount of dirty memory at which the pdflush background writeback
-daemon will start writeback.
+Contains the amount of dirty memory at which the background kernel
+flusher threads will start writeback.
 
 Note: dirty_background_bytes is the counterpart of dirty_background_ratio. Only
 one of them may be specified at a time. When one sysctl is written it is
@@ -89,7 +89,7 @@ other appears as 0 when read.
 dirty_background_ratio
 
 Contains, as a percentage of total system memory, the number of pages at which
-the pdflush background writeback daemon will start writing out dirty data.
+the background kernel flusher threads will start writing out dirty data.
 
 ==============================================================
 
@@ -112,9 +112,9 @@ retained.
 dirty_expire_centisecs
 
 This tunable is used to define when dirty data is old enough to be eligible
-for writeout by the pdflush daemons.  It is expressed in 100'ths of a second.
-Data which has been dirty in-memory for longer than this interval will be
-written out next time a pdflush daemon wakes up.
+for writeout by the kernel flusher threads.  It is expressed in 100'ths
+of a second.  Data which has been dirty in-memory for longer than this
+interval will be written out next time a flusher thread wakes up.
 
 ==============================================================
 
@@ -128,7 +128,7 @@ data.
 
 dirty_writeback_centisecs
 
-The pdflush writeback daemons will periodically wake up and write `old' data
+The kernel flusher threads will periodically wake up and write `old' data
 out to disk.  This tunable expresses the interval between those wakeups, in
 100'ths of a second.
 
index c087dbcf3535c2be5da5db5f8feeefaeaea9c88d..ca1a1a34970eae5dc8ddcc8d1d383e2d42be66ae 100644 (file)
@@ -84,7 +84,8 @@ temperature) and throttle appropriate devices.
 
 1.3 interface for binding a thermal zone device with a thermal cooling device
 1.3.1 int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
-               int trip, struct thermal_cooling_device *cdev);
+       int trip, struct thermal_cooling_device *cdev,
+       unsigned long upper, unsigned long lower);
 
     This interface function bind a thermal cooling device to the certain trip
     point of a thermal zone device.
@@ -93,6 +94,12 @@ temperature) and throttle appropriate devices.
     cdev: thermal cooling device
     trip: indicates which trip point the cooling devices is associated with
          in this thermal zone.
+    upper:the Maximum cooling state for this trip point.
+          THERMAL_NO_LIMIT means no upper limit,
+         and the cooling device can be in max_state.
+    lower:the Minimum cooling state can be used for this trip point.
+          THERMAL_NO_LIMIT means no lower limit,
+         and the cooling device can be in cooling state 0.
 
 1.3.2 int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
                int trip, struct thermal_cooling_device *cdev);
index 074b159b77c20344aaa0a4abf7becc8603a2a065..35d70eda9ad627bf0eff7c1193f91fb451126e5b 100644 (file)
@@ -155,6 +155,9 @@ If the kernel gets fooled in this way, it's almost certain to cause
 data corruption and to crash your system.  You'll have no one to blame
 but yourself.
 
+For those devices with avoid_reset_quirk attribute being set, persist
+maybe fail because they may morph after reset.
+
 YOU HAVE BEEN WARNED!  USE AT YOUR OWN RISK!
 
 That having been said, most of the time there shouldn't be any trouble
index bf33aaa4c59f8f2e507fdd3e9c32528b16e831d1..2c32651a74f187c0d98d080066ae623a730582fb 100644 (file)
@@ -1190,12 +1190,15 @@ struct kvm_ppc_pvinfo {
 This ioctl fetches PV specific information that need to be passed to the guest
 using the device tree or other means from vm context.
 
-For now the only implemented piece of information distributed here is an array
-of 4 instructions that make up a hypercall.
+The hcall array defines 4 instructions that make up a hypercall.
 
 If any additional field gets added to this structure later on, a bit for that
 additional piece of information will be set in the flags bitmap.
 
+The flags bitmap is defined as:
+
+   /* the host supports the ePAPR idle hcall
+   #define KVM_PPC_PVINFO_FLAGS_EV_IDLE   (1<<0)
 
 4.48 KVM_ASSIGN_PCI_DEVICE
 
@@ -1727,7 +1730,12 @@ registers, find a list below:
   Arch  |       Register        | Width (bits)
         |                       |
   PPC   | KVM_REG_PPC_HIOR      | 64
-
+  PPC   | KVM_REG_PPC_IAC1      | 64
+  PPC   | KVM_REG_PPC_IAC2      | 64
+  PPC   | KVM_REG_PPC_IAC3      | 64
+  PPC   | KVM_REG_PPC_IAC4      | 64
+  PPC   | KVM_REG_PPC_DAC1      | 64
+  PPC   | KVM_REG_PPC_DAC2      | 64
 
 4.69 KVM_GET_ONE_REG
 
@@ -1743,7 +1751,7 @@ kvm_one_reg struct passed in. On success, the register value can be found
 at the memory location pointed to by "addr".
 
 The list of registers accessible using this interface is identical to the
-list in 4.64.
+list in 4.68.
 
 
 4.70 KVM_KVMCLOCK_CTRL
diff --git a/Documentation/virtual/kvm/hypercalls.txt b/Documentation/virtual/kvm/hypercalls.txt
new file mode 100644 (file)
index 0000000..ea113b5
--- /dev/null
@@ -0,0 +1,66 @@
+Linux KVM Hypercall:
+===================
+X86:
+ KVM Hypercalls have a three-byte sequence of either the vmcall or the vmmcall
+ instruction. The hypervisor can replace it with instructions that are
+ guaranteed to be supported.
+
+ Up to four arguments may be passed in rbx, rcx, rdx, and rsi respectively.
+ The hypercall number should be placed in rax and the return value will be
+ placed in rax.  No other registers will be clobbered unless explicitly stated
+ by the particular hypercall.
+
+S390:
+  R2-R7 are used for parameters 1-6. In addition, R1 is used for hypercall
+  number. The return value is written to R2.
+
+  S390 uses diagnose instruction as hypercall (0x500) along with hypercall
+  number in R1.
+
+ PowerPC:
+  It uses R3-R10 and hypercall number in R11. R4-R11 are used as output registers.
+  Return value is placed in R3.
+
+  KVM hypercalls uses 4 byte opcode, that are patched with 'hypercall-instructions'
+  property inside the device tree's /hypervisor node.
+  For more information refer to Documentation/virtual/kvm/ppc-pv.txt
+
+KVM Hypercalls Documentation
+===========================
+The template for each hypercall is:
+1. Hypercall name.
+2. Architecture(s)
+3. Status (deprecated, obsolete, active)
+4. Purpose
+
+1. KVM_HC_VAPIC_POLL_IRQ
+------------------------
+Architecture: x86
+Status: active
+Purpose: Trigger guest exit so that the host can check for pending
+interrupts on reentry.
+
+2. KVM_HC_MMU_OP
+------------------------
+Architecture: x86
+Status: deprecated.
+Purpose: Support MMU operations such as writing to PTE,
+flushing TLB, release PT.
+
+3. KVM_HC_FEATURES
+------------------------
+Architecture: PPC
+Status: active
+Purpose: Expose hypercall availability to the guest. On x86 platforms, cpuid
+used to enumerate which hypercalls are available. On PPC, either device tree
+based lookup ( which is also what EPAPR dictates) OR KVM specific enumeration
+mechanism (which is this hypercall) can be used.
+
+4. KVM_HC_PPC_MAP_MAGIC_PAGE
+------------------------
+Architecture: PPC
+Status: active
+Purpose: To enable communication between the hypervisor and guest there is a
+shared page that contains parts of supervisor visible register state.
+The guest can map this shared page to access its supervisor register through
+memory using this hypercall.
index 4911cf95c67e51507118139a7d20897f67fbd888..4cd076febb0239452db01b8e127d6f810081efbb 100644 (file)
@@ -174,3 +174,25 @@ following:
 That way we can inject an arbitrary amount of code as replacement for a single
 instruction. This allows us to check for pending interrupts when setting EE=1
 for example.
+
+Hypercall ABIs in KVM on PowerPC
+=================================
+1) KVM hypercalls (ePAPR)
+
+These are ePAPR compliant hypercall implementation (mentioned above). Even
+generic hypercalls are implemented here, like the ePAPR idle hcall. These are
+available on all targets.
+
+2) PAPR hypercalls
+
+PAPR hypercalls are needed to run server PowerPC PAPR guests (-M pseries in QEMU).
+These are the same hypercalls that pHyp, the POWER hypervisor implements. Some of
+them are handled in the kernel, some are handled in user space. This is only
+available on book3s_64.
+
+3) OSI hypercalls
+
+Mac-on-Linux is another user of KVM on PowerPC, which has its own hypercall (long
+before KVM). This is supported to maintain compatibility. All these hypercalls get
+forwarded to user space. This is only useful on book3s_32, but can be used with
+book3s_64 as well.
index 0403aaaba878edd18473ef7a536b38cfac4784c5..874a8ca93feb95c9783d9a41b3f89136b7485516 100644 (file)
@@ -3,6 +3,7 @@ Kernel driver w1_therm
 
 Supported chips:
   * Maxim ds18*20 based temperature sensors.
+  * Maxim ds1825 based temperature sensors.
 
 Author: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
 
@@ -15,6 +16,7 @@ supported family codes:
 W1_THERM_DS18S20       0x10
 W1_THERM_DS1822                0x22
 W1_THERM_DS18B20       0x28
+W1_THERM_DS1825                0x3B
 
 Support is provided through the sysfs w1_slave file.  Each open and
 read sequence will initiate a temperature conversion then provide two
index 73ff5cc93e05db4c93321464cb8ae948571a18fe..3da822967ee0e13d1a2dbcd88d2d75f5a4aca370 100644 (file)
@@ -31,7 +31,7 @@ static void keep_alive(void)
  * or "-e" to enable the card.
  */
 
-void term(int sig)
+static void term(int sig)
 {
     close(fd);
     fprintf(stderr, "Stopping watchdog ticks...\n");
index 94b823f71e944d1f8805815c2b16b5bca437d3b7..fb8798993106ea239e576b8e6e4c6f91d668ed9d 100644 (file)
@@ -595,7 +595,6 @@ M:  Will Deacon <will.deacon@arm.com>
 S:     Maintained
 F:     arch/arm/kernel/perf_event*
 F:     arch/arm/oprofile/common.c
-F:     arch/arm/kernel/pmu.c
 F:     arch/arm/include/asm/pmu.h
 F:     arch/arm/kernel/hw_breakpoint.c
 F:     arch/arm/include/asm/hw_breakpoint.h
@@ -827,24 +826,24 @@ F:        arch/arm/mach-pxa/colibri-pxa270-income.c
 
 ARM/INTEL IOP32X ARM ARCHITECTURE
 M:     Lennert Buytenhek <kernel@wantstofly.org>
-M:     Dan Williams <dan.j.williams@intel.com>
+M:     Dan Williams <djbw@fb.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 
 ARM/INTEL IOP33X ARM ARCHITECTURE
-M:     Dan Williams <dan.j.williams@intel.com>
+M:     Dan Williams <djbw@fb.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 
 ARM/INTEL IOP13XX ARM ARCHITECTURE
 M:     Lennert Buytenhek <kernel@wantstofly.org>
-M:     Dan Williams <dan.j.williams@intel.com>
+M:     Dan Williams <djbw@fb.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 
 ARM/INTEL IQ81342EX MACHINE SUPPORT
 M:     Lennert Buytenhek <kernel@wantstofly.org>
-M:     Dan Williams <dan.j.williams@intel.com>
+M:     Dan Williams <djbw@fb.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 
@@ -869,7 +868,7 @@ F:  drivers/pcmcia/pxa2xx_stargate2.c
 
 ARM/INTEL XSC3 (MANZANO) ARM CORE
 M:     Lennert Buytenhek <kernel@wantstofly.org>
-M:     Dan Williams <dan.j.williams@intel.com>
+M:     Dan Williams <djbw@fb.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 
@@ -925,14 +924,14 @@ S:        Maintained
 
 ARM/NOMADIK ARCHITECTURE
 M:     Alessandro Rubini <rubini@unipv.it>
-M:     Linus Walleij <linus.walleij@stericsson.com>
+M:     Linus Walleij <linus.walleij@linaro.org>
 M:     STEricsson <STEricsson_nomadik_linux@list.st.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     arch/arm/mach-nomadik/
 F:     arch/arm/plat-nomadik/
 F:     drivers/i2c/busses/i2c-nomadik.c
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-stericsson.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-nomadik.git
 
 ARM/OPENMOKO NEO FREERUNNER (GTA02) MACHINE SUPPORT
 M:     Nelson Castillo <arhuaco@freaks-unidos.net>
@@ -1146,7 +1145,7 @@ F:        drivers/usb/host/ehci-w90x900.c
 F:     drivers/video/nuc900fb.c
 
 ARM/U300 MACHINE SUPPORT
-M:     Linus Walleij <linus.walleij@stericsson.com>
+M:     Linus Walleij <linus.walleij@linaro.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Supported
 F:     arch/arm/mach-u300/
@@ -1161,15 +1160,20 @@ T:      git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-stericsson.git
 
 ARM/Ux500 ARM ARCHITECTURE
 M:     Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
-M:     Linus Walleij <linus.walleij@stericsson.com>
+M:     Linus Walleij <linus.walleij@linaro.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     arch/arm/mach-ux500/
+F:     drivers/clocksource/clksrc-dbx500-prcmu.c
 F:     drivers/dma/ste_dma40*
+F:     drivers/hwspinlock/u8500_hsem.c
 F:     drivers/mfd/abx500*
 F:     drivers/mfd/ab8500*
-F:     drivers/mfd/stmpe*
+F:     drivers/mfd/dbx500*
+F:     drivers/mfd/db8500*
+F:     drivers/pinctrl/pinctrl-nomadik*
 F:     drivers/rtc/rtc-ab8500.c
+F:     drivers/rtc/rtc-pl031.c
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-stericsson.git
 
 ARM/VFP SUPPORT
@@ -1227,9 +1231,9 @@ S:        Maintained
 F:     drivers/hwmon/asb100.c
 
 ASYNCHRONOUS TRANSFERS/TRANSFORMS (IOAT) API
-M:     Dan Williams <dan.j.williams@intel.com>
+M:     Dan Williams <djbw@fb.com>
 W:     http://sourceforge.net/projects/xscaleiop
-S:     Supported
+S:     Maintained
 F:     Documentation/crypto/async-tx-api.txt
 F:     crypto/async_tx/
 F:     drivers/dma/
@@ -1513,7 +1517,7 @@ S:        Supported
 F:     drivers/rtc/rtc-bfin.c
 
 BLACKFIN SDH DRIVER
-M:     Cliff Cai <cliff.cai@analog.com>
+M:     Sonic Zhang <sonic.zhang@analog.com>
 L:     uclinux-dist-devel@blackfin.uclinux.org
 W:     http://blackfin.uclinux.org
 S:     Supported
@@ -2212,7 +2216,7 @@ S:        Maintained
 F:     drivers/scsi/tmscsim.*
 
 DC395x SCSI driver
-M:     Oliver Neukum <oliver@neukum.name>
+M:     Oliver Neukum <oliver@neukum.org>
 M:     Ali Akcaagac <aliakc@web.de>
 M:     Jamie Lenehan <lenehan@twibble.org>
 W:     http://twibble.org/dist/dc395x/
@@ -2359,7 +2363,7 @@ T:        git git://git.linaro.org/people/sumitsemwal/linux-dma-buf.git
 
 DMA GENERIC OFFLOAD ENGINE SUBSYSTEM
 M:     Vinod Koul <vinod.koul@intel.com>
-M:     Dan Williams <dan.j.williams@intel.com>
+M:     Dan Williams <djbw@fb.com>
 S:     Supported
 F:     drivers/dma/
 F:     include/linux/dma*
@@ -3094,7 +3098,7 @@ F:        include/linux/gigaset_dev.h
 
 GPIO SUBSYSTEM
 M:     Grant Likely <grant.likely@secretlab.ca>
-M:     Linus Walleij <linus.walleij@stericsson.com>
+M:     Linus Walleij <linus.walleij@linaro.org>
 S:     Maintained
 T:     git git://git.secretlab.ca/git/linux-2.6.git
 F:     Documentation/gpio.txt
@@ -3415,6 +3419,12 @@ T:       git git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux.git
 S:     Maintained
 F:     arch/ia64/
 
+IBM Power 842 compression accelerator
+M:     Robert Jennings <rcj@linux.vnet.ibm.com>
+S:     Supported
+F:     drivers/crypto/nx/nx-842.c
+F:     include/linux/nx842.h
+
 IBM Power Linux RAID adapter
 M:     Brian King <brking@us.ibm.com>
 S:     Supported
@@ -3547,7 +3557,6 @@ K:        \b(ABS|SYN)_MT_
 
 INTEL C600 SERIES SAS CONTROLLER DRIVER
 M:     Intel SCU Linux support <intel-linux-scu@intel.com>
-M:     Dan Williams <dan.j.williams@intel.com>
 M:     Dave Jiang <dave.jiang@intel.com>
 M:     Ed Nadolski <edmund.nadolski@intel.com>
 L:     linux-scsi@vger.kernel.org
@@ -3590,8 +3599,8 @@ F:        arch/x86/kernel/microcode_core.c
 F:     arch/x86/kernel/microcode_intel.c
 
 INTEL I/OAT DMA DRIVER
-M:     Dan Williams <dan.j.williams@intel.com>
-S:     Supported
+M:     Dan Williams <djbw@fb.com>
+S:     Maintained
 F:     drivers/dma/ioat*
 
 INTEL IOMMU (VT-d)
@@ -3603,8 +3612,8 @@ F:        drivers/iommu/intel-iommu.c
 F:     include/linux/intel-iommu.h
 
 INTEL IOP-ADMA DMA DRIVER
-M:     Dan Williams <dan.j.williams@intel.com>
-S:     Maintained
+M:     Dan Williams <djbw@fb.com>
+S:     Odd fixes
 F:     drivers/dma/iop-adma.c
 
 INTEL IXP4XX QMGR, NPE, ETHERNET and HSS SUPPORT
@@ -4533,7 +4542,7 @@ S:        Supported
 F:     arch/microblaze/
 
 MICROTEK X6 SCANNER
-M:     Oliver Neukum <oliver@neukum.name>
+M:     Oliver Neukum <oliver@neukum.org>
 S:     Maintained
 F:     drivers/usb/image/microtek.*
 
@@ -4639,6 +4648,14 @@ L:       alsa-devel@alsa-project.org
 W:     http://www.native-instruments.com
 F:     sound/usb/caiaq/
 
+NATIVE LINUX KVM TOOL
+M:     Pekka Enberg <penberg@kernel.org>
+M:     Sasha Levin <levinsasha928@gmail.com>
+M:     Asias He <asias.hejun@gmail.com>
+L:     kvm@vger.kernel.org
+S:     Maintained
+F:     tools/kvm/
+
 NCP FILESYSTEM
 M:     Petr Vandrovec <petr@vandrovec.name>
 S:     Odd Fixes
@@ -5316,6 +5333,12 @@ L:       linux-mtd@lists.infradead.org
 S:     Maintained
 F:     drivers/mtd/devices/phram.c
 
+PICOLCD HID DRIVER
+M:     Bruno Prémont <bonbons@linux-vserver.org>
+L:     linux-input@vger.kernel.org
+S:     Maintained
+F:     drivers/hid/hid-picolcd*
+
 PICOXCELL SUPPORT
 M:     Jamie Iles <jamie@jamieiles.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -5329,14 +5352,15 @@ PIN CONTROL SUBSYSTEM
 M:     Linus Walleij <linus.walleij@linaro.org>
 S:     Maintained
 F:     drivers/pinctrl/
+F:     include/linux/pinctrl/
 
 PIN CONTROLLER - ST SPEAR
-M:     Viresh Kumar <viresh.linux@gmail.com>
+M:     Viresh Kumar <viresh.linux@gmail.com>
 L:     spear-devel@list.st.com
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 W:     http://www.st.com/spear
 S:     Maintained
-F:     driver/pinctrl/spear/
+F:     drivers/pinctrl/spear/
 
 PKTCDVD DRIVER
 M:     Peter Osterlund <petero2@telia.com>
@@ -6793,6 +6817,8 @@ F:        drivers/char/tlclk.c
 
 TENSILICA XTENSA PORT (xtensa)
 M:     Chris Zankel <chris@zankel.net>
+M:     Max Filippov <jcmvbkbc@gmail.com>
+L:     linux-xtensa@linux-xtensa.org
 S:     Maintained
 F:     arch/xtensa/
 
@@ -7071,7 +7097,7 @@ F:        include/linux/mtd/ubi.h
 F:     include/mtd/ubi-user.h
 
 USB ACM DRIVER
-M:     Oliver Neukum <oliver@neukum.name>
+M:     Oliver Neukum <oliver@neukum.org>
 L:     linux-usb@vger.kernel.org
 S:     Maintained
 F:     Documentation/usb/acm.txt
@@ -7092,7 +7118,7 @@ S:        Supported
 F:     drivers/block/ub.c
 
 USB CDC ETHERNET DRIVER
-M:     Oliver Neukum <oliver@neukum.name>
+M:     Oliver Neukum <oliver@neukum.org>
 L:     linux-usb@vger.kernel.org
 S:     Maintained
 F:     drivers/net/usb/cdc_*.c
@@ -7165,7 +7191,7 @@ F:        drivers/usb/host/isp116x*
 F:     include/linux/usb/isp116x.h
 
 USB KAWASAKI LSI DRIVER
-M:     Oliver Neukum <oliver@neukum.name>
+M:     Oliver Neukum <oliver@neukum.org>
 L:     linux-usb@vger.kernel.org
 S:     Maintained
 F:     drivers/usb/serial/kl5kusb105.*
@@ -7665,23 +7691,28 @@ S:      Supported
 F:     Documentation/hwmon/wm83??
 F:     arch/arm/mach-s3c64xx/mach-crag6410*
 F:     drivers/clk/clk-wm83*.c
+F:     drivers/extcon/extcon-arizona.c
 F:     drivers/leds/leds-wm83*.c
 F:     drivers/gpio/gpio-*wm*.c
+F:     drivers/gpio/gpio-arizona.c
 F:     drivers/hwmon/wm83??-hwmon.c
 F:     drivers/input/misc/wm831x-on.c
 F:     drivers/input/touchscreen/wm831x-ts.c
 F:     drivers/input/touchscreen/wm97*.c
-F:     drivers/mfd/wm8*.c
+F:     drivers/mfd/arizona*
+F:     drivers/mfd/wm*.c
 F:     drivers/power/wm83*.c
 F:     drivers/rtc/rtc-wm83*.c
 F:     drivers/regulator/wm8*.c
 F:     drivers/video/backlight/wm83*_bl.c
 F:     drivers/watchdog/wm83*_wdt.c
+F:     include/linux/mfd/arizona/
 F:     include/linux/mfd/wm831x/
 F:     include/linux/mfd/wm8350/
 F:     include/linux/mfd/wm8400*
 F:     include/linux/wm97xx.h
 F:     include/sound/wm????.h
+F:     sound/soc/codecs/arizona.?
 F:     sound/soc/codecs/wm*
 
 WORKQUEUE
index ddf5be952e456904ba009fbbe0d1c8e0a42470b7..9cc77acfc88166ee9ce2b59bf4101d654188f73b 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 3
 PATCHLEVEL = 6
 SUBLEVEL = 0
-EXTRAVERSION = -rc1
+EXTRAVERSION = -rc2
 NAME = Saber-toothed Squirrel
 
 # *DOCUMENTATION*
index 72f2fa189cc5200bb98143c6b35de8ffc9e0aaee..0e26d74788f0116f346288e7c95ef8d1e109391e 100644 (file)
@@ -281,4 +281,33 @@ config SECCOMP_FILTER
 
          See Documentation/prctl/seccomp_filter.txt for details.
 
+config HAVE_MOD_ARCH_SPECIFIC
+       bool
+       help
+         The arch uses struct mod_arch_specific to store data.  Many arches
+         just need a simple module loader without arch specific data - those
+         should not enable this.
+
+config MODULES_USE_ELF_RELA
+       bool
+       help
+         Modules only use ELF RELA relocations.  Modules with ELF REL
+         relocations will give an error.
+
+config MODULES_USE_ELF_REL
+       bool
+       help
+         Modules only use ELF REL relocations.  Modules with ELF RELA
+         relocations will give an error.
+
+config HAVE_RCU_USER_QS
+       bool
+       help
+         Provide kernel entry/exit hooks necessary for userspace
+         RCU extended quiescent state. Syscalls need to be wrapped inside
+         rcu_user_exit()-rcu_user_enter() through the slow path using
+         TIF_NOHZ flag. Exceptions handlers must be wrapped as well. Irqs
+         are already protected inside rcu_irq_enter/rcu_irq_exit() but
+         preemption or signal handling on irq exit still need to be protected.
+
 source "kernel/gcov/Kconfig"
index d5b9b5e645cc7ad6ee66984d78434b306bc1aa13..e73a1a7d58969db46ae0b5b52c5420d8a201a4f2 100644 (file)
@@ -18,6 +18,8 @@ config ALPHA
        select ARCH_HAVE_NMI_SAFE_CMPXCHG
        select GENERIC_SMP_IDLE_THREAD
        select GENERIC_CMOS_UPDATE
+       select HAVE_MOD_ARCH_SPECIFIC
+       select MODULES_USE_ELF_RELA
        help
          The Alpha is a 64-bit general-purpose processor designed and
          marketed by the Digital Equipment Corporation of blessed memory,
index 7b63743c534a10c34a022c92c144558e425a38d9..9cd13b55155f2f4083f44a8fcec3a79b935570c9 100644 (file)
@@ -1,19 +1,13 @@
 #ifndef _ALPHA_MODULE_H
 #define _ALPHA_MODULE_H
 
+#include <asm-generic/module.h>
+
 struct mod_arch_specific
 {
        unsigned int gotsecindex;
 };
 
-#define Elf_Sym Elf64_Sym
-#define Elf_Shdr Elf64_Shdr
-#define Elf_Ehdr Elf64_Ehdr
-#define Elf_Phdr Elf64_Phdr
-#define Elf_Dyn Elf64_Dyn
-#define Elf_Rel Elf64_Rel
-#define Elf_Rela Elf64_Rela
-
 #define ARCH_SHF_SMALL SHF_ALPHA_GPREL
 
 #ifdef MODULE
index 3ea809430eda0f3ea018df2b540a75614846ce05..5d5865204a1d4739b0836bed605b5220192ad1b7 100644 (file)
@@ -223,6 +223,7 @@ srmcons_init(void)
                driver->subtype = SYSTEM_TYPE_SYSCONS;
                driver->init_termios = tty_std_termios;
                tty_set_operations(driver, &srmcons_ops);
+               tty_port_link_device(&srmcons_singleton.port, driver, 0);
                err = tty_register_driver(driver);
                if (err) {
                        put_tty_driver(driver);
index e91c7cdc6fe5c5ae370fa8be0f3a3c51a0b49beb..7a7b2e32a3b1ab5ddd6433ea12f69945fb42a007 100644 (file)
@@ -38,7 +38,6 @@ config ARM
        select HARDIRQS_SW_RESEND
        select GENERIC_IRQ_PROBE
        select GENERIC_IRQ_SHOW
-       select GENERIC_IRQ_PROBE
        select ARCH_WANT_IPC_PARSE_VERSION
        select HARDIRQS_SW_RESEND
        select CPU_PM if (SUSPEND || CPU_IDLE)
@@ -50,6 +49,8 @@ config ARM
        select GENERIC_STRNCPY_FROM_USER
        select GENERIC_STRNLEN_USER
        select DCACHE_WORD_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) && !CPU_BIG_ENDIAN
+       select HAVE_MOD_ARCH_SPECIFIC if ARM_UNWIND
+       select MODULES_USE_ELF_REL
        help
          The ARM series is a line of low-power-consumption RISC chip designs
          licensed by ARM Ltd and targeted at embedded applications and
@@ -126,11 +127,6 @@ config TRACE_IRQFLAGS_SUPPORT
        bool
        default y
 
-config GENERIC_LOCKBREAK
-       bool
-       default y
-       depends on SMP && PREEMPT
-
 config RWSEM_GENERIC_SPINLOCK
        bool
        default y
@@ -285,7 +281,6 @@ config ARCH_INTEGRATOR
        select GENERIC_CLOCKEVENTS
        select PLAT_VERSATILE
        select PLAT_VERSATILE_FPGA_IRQ
-       select NEED_MACH_IO_H
        select NEED_MACH_MEMORY_H
        select SPARSE_IRQ
        select MULTI_IRQ_HANDLER
@@ -318,7 +313,6 @@ config ARCH_VERSATILE
        select ICST
        select GENERIC_CLOCKEVENTS
        select ARCH_WANT_OPTIONAL_GPIOLIB
-       select NEED_MACH_IO_H if PCI
        select PLAT_VERSATILE
        select PLAT_VERSATILE_CLOCK
        select PLAT_VERSATILE_CLCD
@@ -462,7 +456,7 @@ config ARCH_FOOTBRIDGE
        select FOOTBRIDGE
        select GENERIC_CLOCKEVENTS
        select HAVE_IDE
-       select NEED_MACH_IO_H
+       select NEED_MACH_IO_H if !MMU
        select NEED_MACH_MEMORY_H
        help
          Support for systems based on the DC21285 companion chip
@@ -519,7 +513,6 @@ config ARCH_IOP13XX
        select PCI
        select ARCH_SUPPORTS_MSI
        select VMSPLIT_1G
-       select NEED_MACH_IO_H
        select NEED_MACH_MEMORY_H
        select NEED_RET_TO_USER
        help
@@ -529,7 +522,6 @@ config ARCH_IOP32X
        bool "IOP32x-based"
        depends on MMU
        select CPU_XSCALE
-       select NEED_MACH_IO_H
        select NEED_RET_TO_USER
        select PLAT_IOP
        select PCI
@@ -542,7 +534,6 @@ config ARCH_IOP33X
        bool "IOP33x-based"
        depends on MMU
        select CPU_XSCALE
-       select NEED_MACH_IO_H
        select NEED_RET_TO_USER
        select PLAT_IOP
        select PCI
@@ -582,7 +573,6 @@ config ARCH_DOVE
        select PCI
        select ARCH_REQUIRE_GPIOLIB
        select GENERIC_CLOCKEVENTS
-       select NEED_MACH_IO_H
        select PLAT_ORION
        help
          Support for the Marvell Dove SoC 88AP510
@@ -593,7 +583,6 @@ config ARCH_KIRKWOOD
        select PCI
        select ARCH_REQUIRE_GPIOLIB
        select GENERIC_CLOCKEVENTS
-       select NEED_MACH_IO_H
        select PLAT_ORION
        help
          Support for the following Marvell Kirkwood series SoCs:
@@ -620,7 +609,6 @@ config ARCH_MV78XX0
        select PCI
        select ARCH_REQUIRE_GPIOLIB
        select GENERIC_CLOCKEVENTS
-       select NEED_MACH_IO_H
        select PLAT_ORION
        help
          Support for the following Marvell MV78xx0 series SoCs:
@@ -633,7 +621,6 @@ config ARCH_ORION5X
        select PCI
        select ARCH_REQUIRE_GPIOLIB
        select GENERIC_CLOCKEVENTS
-       select NEED_MACH_IO_H
        select PLAT_ORION
        help
          Support for the following Marvell Orion 5x series SoCs:
@@ -689,7 +676,6 @@ config ARCH_TEGRA
        select HAVE_CLK
        select HAVE_SMP
        select MIGHT_HAVE_CACHE_L2X0
-       select NEED_MACH_IO_H if PCI
        select ARCH_HAS_CPUFREQ
        select USE_OF
        help
@@ -918,7 +904,6 @@ config ARCH_SHARK
        select PCI
        select ARCH_USES_GETTIMEOFFSET
        select NEED_MACH_MEMORY_H
-       select NEED_MACH_IO_H
        help
          Support for the StrongARM based Digital DNARD machine, also known
          as "Shark" (<http://www.shark-linux.de/shark.html>).
@@ -937,6 +922,7 @@ config ARCH_U300
        select COMMON_CLK
        select GENERIC_GPIO
        select ARCH_REQUIRE_GPIOLIB
+       select SPARSE_IRQ
        help
          Support for ST-Ericsson U300 series mobile platforms.
 
@@ -962,6 +948,7 @@ config ARCH_NOMADIK
        select COMMON_CLK
        select GENERIC_CLOCKEVENTS
        select PINCTRL
+       select PINCTRL_STN8815
        select MIGHT_HAVE_CACHE_L2X0
        select ARCH_REQUIRE_GPIOLIB
        help
@@ -1185,12 +1172,6 @@ config XSCALE_PMU
        depends on CPU_XSCALE
        default y
 
-config CPU_HAS_PMU
-       depends on (CPU_V6 || CPU_V6K || CPU_V7 || XSCALE_PMU) && \
-                  (!ARCH_OMAP3 || OMAP3_EMU)
-       default y
-       bool
-
 config MULTI_IRQ_HANDLER
        bool
        help
@@ -1763,7 +1744,7 @@ config HIGHPTE
 
 config HW_PERF_EVENTS
        bool "Enable hardware performance counter support for perf events"
-       depends on PERF_EVENTS && CPU_HAS_PMU
+       depends on PERF_EVENTS
        default y
        help
          Enable hardware performance counter support for perf events. If
@@ -1787,59 +1768,6 @@ config FORCE_MAX_ZONEORDER
          This config option is actually maximum order plus one. For example,
          a value of 11 means that the largest free memory block is 2^10 pages.
 
-config LEDS
-       bool "Timer and CPU usage LEDs"
-       depends on ARCH_CDB89712 || ARCH_EBSA110 || \
-                  ARCH_EBSA285 || ARCH_INTEGRATOR || \
-                  ARCH_LUBBOCK || MACH_MAINSTONE || ARCH_NETWINDER || \
-                  ARCH_OMAP || ARCH_P720T || ARCH_PXA_IDP || \
-                  ARCH_SA1100 || ARCH_SHARK || ARCH_VERSATILE || \
-                  ARCH_AT91 || ARCH_DAVINCI || \
-                  ARCH_KS8695 || MACH_RD88F5182 || ARCH_REALVIEW
-       help
-         If you say Y here, the LEDs on your machine will be used
-         to provide useful information about your current system status.
-
-         If you are compiling a kernel for a NetWinder or EBSA-285, you will
-         be able to select which LEDs are active using the options below. If
-         you are compiling a kernel for the EBSA-110 or the LART however, the
-         red LED will simply flash regularly to indicate that the system is
-         still functional. It is safe to say Y here if you have a CATS
-         system, but the driver will do nothing.
-
-config LEDS_TIMER
-       bool "Timer LED" if (!ARCH_CDB89712 && !ARCH_OMAP) || \
-                           OMAP_OSK_MISTRAL || MACH_OMAP_H2 \
-                           || MACH_OMAP_PERSEUS2
-       depends on LEDS
-       depends on !GENERIC_CLOCKEVENTS
-       default y if ARCH_EBSA110
-       help
-         If you say Y here, one of the system LEDs (the green one on the
-         NetWinder, the amber one on the EBSA285, or the red one on the LART)
-         will flash regularly to indicate that the system is still
-         operational. This is mainly useful to kernel hackers who are
-         debugging unstable kernels.
-
-         The LART uses the same LED for both Timer LED and CPU usage LED
-         functions. You may choose to use both, but the Timer LED function
-         will overrule the CPU usage LED.
-
-config LEDS_CPU
-       bool "CPU usage LED" if (!ARCH_CDB89712 && !ARCH_EBSA110 && \
-                       !ARCH_OMAP) \
-                       || OMAP_OSK_MISTRAL || MACH_OMAP_H2 \
-                       || MACH_OMAP_PERSEUS2
-       depends on LEDS
-       help
-         If you say Y here, the red LED will be used to give a good real
-         time indication of CPU usage, by lighting whenever the idle task
-         is not currently executing.
-
-         The LART uses the same LED for both Timer LED and CPU usage LED
-         functions. You may choose to use both, but the Timer LED function
-         will overrule the CPU usage LED.
-
 config ALIGNMENT_TRAP
        bool
        depends on CPU_CP15_MMU
diff --git a/arch/arm/arm-soc-for-next-contents.txt b/arch/arm/arm-soc-for-next-contents.txt
new file mode 100644 (file)
index 0000000..88031e7
--- /dev/null
@@ -0,0 +1,40 @@
+This file lists all branches that are pulled into the for-next branch
+of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc.git
+and their external dependencies.
+
+It also includes a couple of directly applied patches for build breaks with subject
+The next/* branches are kept in the order in which they get applied.
+
+fixes:
+
+next/fixes-non-critical:
+
+next/cleanup:
+cleanup/io-pci:   git://sources.calxeda.com/kernel/linux.git io-cleanup-pci-v2
+bcmring/cleanup:  patches from Arnd
+u300/cleanup     git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-stericsson.git u300-cleanup
+
+next/maintainers:
+
+next/soc:
+ux500/asic-id: git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-stericsson.git ux500-core
+
+next/dt:
+pxa/dt:                git://github.com/hzhuang1/linux.git dt
+
+next/defconfig:
+
+next/drivers:
+devel/led-driver       git://git.kernel.org/pub/scm/linux/kernel/git/cooloney/linux-leds.git for-arm-soc
+at91/mci       git://github.com/at91linux/linux-at91 at91-for-next-soc
+
+next/boards:
+pxa/board      git://github.com/hzhuang1/linux.git board
+
+next/docs:
+mvebu/docs:    git://github.com/MISL-EBU-System-SW/mainline-public.git marvell-doc
+
+
+
+
+
index 59509c48d7e5a5c2474f73ac028f73537e0a6659..bd0cff3f808c7c5be55ce79dd31b343d37e6297a 100644 (file)
                        #size-cells = <0>;
                        ti,hwmods = "i2c3";
                };
+
+               wdt2: wdt@44e35000 {
+                       compatible = "ti,omap3-wdt";
+                       ti,hwmods = "wd_timer2";
+               };
        };
 };
index a874dbfb5ae69da5d6771c75d9605ca3bbbcbcaa..e6138310e5ced961a269b903fadcfff6869c7be2 100644 (file)
 
                        dma-apbh@80004000 {
                                compatible = "fsl,imx23-dma-apbh";
-                               reg = <0x80004000 2000>;
+                               reg = <0x80004000 0x2000>;
                        };
 
                        ecc@80008000 {
-                               reg = <0x80008000 2000>;
+                               reg = <0x80008000 0x2000>;
                                status = "disabled";
                        };
 
@@ -63,7 +63,7 @@
                                compatible = "fsl,imx23-gpmi-nand";
                                #address-cells = <1>;
                                #size-cells = <1>;
-                               reg = <0x8000c000 2000>, <0x8000a000 2000>;
+                               reg = <0x8000c000 0x2000>, <0x8000a000 0x2000>;
                                reg-names = "gpmi-nand", "bch";
                                interrupts = <13>, <56>;
                                interrupt-names = "gpmi-dma", "bch";
                        };
 
                        ssp0: ssp@80010000 {
-                               reg = <0x80010000 2000>;
+                               reg = <0x80010000 0x2000>;
                                interrupts = <15 14>;
                                fsl,ssp-dma-channel = <1>;
                                status = "disabled";
                        };
 
                        etm@80014000 {
-                               reg = <0x80014000 2000>;
+                               reg = <0x80014000 0x2000>;
                                status = "disabled";
                        };
 
@@ -87,7 +87,7 @@
                                #address-cells = <1>;
                                #size-cells = <0>;
                                compatible = "fsl,imx23-pinctrl", "simple-bus";
-                               reg = <0x80018000 2000>;
+                               reg = <0x80018000 0x2000>;
 
                                gpio0: gpio@0 {
                                        compatible = "fsl,imx23-gpio", "fsl,mxs-gpio";
                        };
 
                        emi@80020000 {
-                               reg = <0x80020000 2000>;
+                               reg = <0x80020000 0x2000>;
                                status = "disabled";
                        };
 
                        dma-apbx@80024000 {
                                compatible = "fsl,imx23-dma-apbx";
-                               reg = <0x80024000 2000>;
+                               reg = <0x80024000 0x2000>;
                        };
 
                        dcp@80028000 {
-                               reg = <0x80028000 2000>;
+                               reg = <0x80028000 0x2000>;
                                status = "disabled";
                        };
 
                        pxp@8002a000 {
-                               reg = <0x8002a000 2000>;
+                               reg = <0x8002a000 0x2000>;
                                status = "disabled";
                        };
 
                        ocotp@8002c000 {
-                               reg = <0x8002c000 2000>;
+                               reg = <0x8002c000 0x2000>;
                                status = "disabled";
                        };
 
                        axi-ahb@8002e000 {
-                               reg = <0x8002e000 2000>;
+                               reg = <0x8002e000 0x2000>;
                                status = "disabled";
                        };
 
                        };
 
                        ssp1: ssp@80034000 {
-                               reg = <0x80034000 2000>;
+                               reg = <0x80034000 0x2000>;
                                interrupts = <2 20>;
                                fsl,ssp-dma-channel = <2>;
                                status = "disabled";
                        };
 
                        tvenc@80038000 {
-                               reg = <0x80038000 2000>;
+                               reg = <0x80038000 0x2000>;
                                status = "disabled";
                        };
                 };
                        ranges;
 
                        clkctl@80040000 {
-                               reg = <0x80040000 2000>;
+                               reg = <0x80040000 0x2000>;
                                status = "disabled";
                        };
 
                        saif0: saif@80042000 {
-                               reg = <0x80042000 2000>;
+                               reg = <0x80042000 0x2000>;
                                status = "disabled";
                        };
 
                        power@80044000 {
-                               reg = <0x80044000 2000>;
+                               reg = <0x80044000 0x2000>;
                                status = "disabled";
                        };
 
                        saif1: saif@80046000 {
-                               reg = <0x80046000 2000>;
+                               reg = <0x80046000 0x2000>;
                                status = "disabled";
                        };
 
                        audio-out@80048000 {
-                               reg = <0x80048000 2000>;
+                               reg = <0x80048000 0x2000>;
                                status = "disabled";
                        };
 
                        audio-in@8004c000 {
-                               reg = <0x8004c000 2000>;
+                               reg = <0x8004c000 0x2000>;
                                status = "disabled";
                        };
 
                        lradc@80050000 {
-                               reg = <0x80050000 2000>;
+                               reg = <0x80050000 0x2000>;
                                status = "disabled";
                        };
 
                        };
 
                        i2c@80058000 {
-                               reg = <0x80058000 2000>;
+                               reg = <0x80058000 0x2000>;
                                status = "disabled";
                        };
 
                        rtc@8005c000 {
                                compatible = "fsl,imx23-rtc", "fsl,stmp3xxx-rtc";
-                               reg = <0x8005c000 2000>;
+                               reg = <0x8005c000 0x2000>;
                                interrupts = <22>;
                        };
 
                        pwm: pwm@80064000 {
                                compatible = "fsl,imx23-pwm";
-                               reg = <0x80064000 2000>;
+                               reg = <0x80064000 0x2000>;
                                #pwm-cells = <2>;
                                fsl,pwm-number = <5>;
                                status = "disabled";
                        };
 
                        timrot@80068000 {
-                               reg = <0x80068000 2000>;
+                               reg = <0x80068000 0x2000>;
                                status = "disabled";
                        };
 
                ranges;
 
                usbctrl@80080000 {
-                       reg = <0x80080000 0x10000>;
+                       reg = <0x80080000 0x40000>;
                        status = "disabled";
                };
        };
index d3f8296e19e0828ea1bd94e88ef04a9467327e21..0a8978a40ecef73d826c12be5d7970b2120195da 100644 (file)
@@ -27,7 +27,7 @@
                                status = "okay";
                        };
 
-                       uart@1000a000 {
+                       uart1: serial@1000a000 {
                                fsl,uart-has-rtscts;
                                status = "okay";
                        };
index 00bae3aad5ab601f7a21adf4da8539aa48880781..5303ab680a3461614e324b27ed455f7da01b253d 100644 (file)
                serial3 = &uart4;
                serial4 = &uart5;
                serial5 = &uart6;
+               gpio0 = &gpio1;
+               gpio1 = &gpio2;
+               gpio2 = &gpio3;
+               gpio3 = &gpio4;
+               gpio4 = &gpio5;
+               gpio5 = &gpio6;
        };
 
        avic: avic-interrupt-controller@e0000000 {
index 787efac68da81b81f79318a0ac55817eb92c8879..3fa6d190fab4f9a2c1c4c47abc8904bce199b0da 100644 (file)
                        };
 
                        hsadc@80002000 {
-                               reg = <0x80002000 2000>;
+                               reg = <0x80002000 0x2000>;
                                interrupts = <13 87>;
                                status = "disabled";
                        };
 
                        dma-apbh@80004000 {
                                compatible = "fsl,imx28-dma-apbh";
-                               reg = <0x80004000 2000>;
+                               reg = <0x80004000 0x2000>;
                        };
 
                        perfmon@80006000 {
-                               reg = <0x80006000 800>;
+                               reg = <0x80006000 0x800>;
                                interrupts = <27>;
                                status = "disabled";
                        };
@@ -77,7 +77,7 @@
                                compatible = "fsl,imx28-gpmi-nand";
                                #address-cells = <1>;
                                #size-cells = <1>;
-                               reg = <0x8000c000 2000>, <0x8000a000 2000>;
+                               reg = <0x8000c000 0x2000>, <0x8000a000 0x2000>;
                                reg-names = "gpmi-nand", "bch";
                                interrupts = <88>, <41>;
                                interrupt-names = "gpmi-dma", "bch";
                        };
 
                        ssp0: ssp@80010000 {
-                               reg = <0x80010000 2000>;
+                               reg = <0x80010000 0x2000>;
                                interrupts = <96 82>;
                                fsl,ssp-dma-channel = <0>;
                                status = "disabled";
                        };
 
                        ssp1: ssp@80012000 {
-                               reg = <0x80012000 2000>;
+                               reg = <0x80012000 0x2000>;
                                interrupts = <97 83>;
                                fsl,ssp-dma-channel = <1>;
                                status = "disabled";
                        };
 
                        ssp2: ssp@80014000 {
-                               reg = <0x80014000 2000>;
+                               reg = <0x80014000 0x2000>;
                                interrupts = <98 84>;
                                fsl,ssp-dma-channel = <2>;
                                status = "disabled";
                        };
 
                        ssp3: ssp@80016000 {
-                               reg = <0x80016000 2000>;
+                               reg = <0x80016000 0x2000>;
                                interrupts = <99 85>;
                                fsl,ssp-dma-channel = <3>;
                                status = "disabled";
                                #address-cells = <1>;
                                #size-cells = <0>;
                                compatible = "fsl,imx28-pinctrl", "simple-bus";
-                               reg = <0x80018000 2000>;
+                               reg = <0x80018000 0x2000>;
 
                                gpio0: gpio@0 {
                                        compatible = "fsl,imx28-gpio", "fsl,mxs-gpio";
                        };
 
                        digctl@8001c000 {
-                               reg = <0x8001c000 2000>;
+                               reg = <0x8001c000 0x2000>;
                                interrupts = <89>;
                                status = "disabled";
                        };
 
                        etm@80022000 {
-                               reg = <0x80022000 2000>;
+                               reg = <0x80022000 0x2000>;
                                status = "disabled";
                        };
 
                        dma-apbx@80024000 {
                                compatible = "fsl,imx28-dma-apbx";
-                               reg = <0x80024000 2000>;
+                               reg = <0x80024000 0x2000>;
                        };
 
                        dcp@80028000 {
-                               reg = <0x80028000 2000>;
+                               reg = <0x80028000 0x2000>;
                                interrupts = <52 53 54>;
                                status = "disabled";
                        };
 
                        pxp@8002a000 {
-                               reg = <0x8002a000 2000>;
+                               reg = <0x8002a000 0x2000>;
                                interrupts = <39>;
                                status = "disabled";
                        };
 
                        ocotp@8002c000 {
-                               reg = <0x8002c000 2000>;
+                               reg = <0x8002c000 0x2000>;
                                status = "disabled";
                        };
 
                        axi-ahb@8002e000 {
-                               reg = <0x8002e000 2000>;
+                               reg = <0x8002e000 0x2000>;
                                status = "disabled";
                        };
 
                        lcdif@80030000 {
                                compatible = "fsl,imx28-lcdif";
-                               reg = <0x80030000 2000>;
+                               reg = <0x80030000 0x2000>;
                                interrupts = <38 86>;
                                status = "disabled";
                        };
 
                        can0: can@80032000 {
                                compatible = "fsl,imx28-flexcan", "fsl,p1010-flexcan";
-                               reg = <0x80032000 2000>;
+                               reg = <0x80032000 0x2000>;
                                interrupts = <8>;
                                status = "disabled";
                        };
 
                        can1: can@80034000 {
                                compatible = "fsl,imx28-flexcan", "fsl,p1010-flexcan";
-                               reg = <0x80034000 2000>;
+                               reg = <0x80034000 0x2000>;
                                interrupts = <9>;
                                status = "disabled";
                        };
 
                        simdbg@8003c000 {
-                               reg = <0x8003c000 200>;
+                               reg = <0x8003c000 0x200>;
                                status = "disabled";
                        };
 
                        simgpmisel@8003c200 {
-                               reg = <0x8003c200 100>;
+                               reg = <0x8003c200 0x100>;
                                status = "disabled";
                        };
 
                        simsspsel@8003c300 {
-                               reg = <0x8003c300 100>;
+                               reg = <0x8003c300 0x100>;
                                status = "disabled";
                        };
 
                        simmemsel@8003c400 {
-                               reg = <0x8003c400 100>;
+                               reg = <0x8003c400 0x100>;
                                status = "disabled";
                        };
 
                        gpiomon@8003c500 {
-                               reg = <0x8003c500 100>;
+                               reg = <0x8003c500 0x100>;
                                status = "disabled";
                        };
 
                        simenet@8003c700 {
-                               reg = <0x8003c700 100>;
+                               reg = <0x8003c700 0x100>;
                                status = "disabled";
                        };
 
                        armjtag@8003c800 {
-                               reg = <0x8003c800 100>;
+                               reg = <0x8003c800 0x100>;
                                status = "disabled";
                        };
                 };
                        ranges;
 
                        clkctl@80040000 {
-                               reg = <0x80040000 2000>;
+                               reg = <0x80040000 0x2000>;
                                status = "disabled";
                        };
 
                        saif0: saif@80042000 {
                                compatible = "fsl,imx28-saif";
-                               reg = <0x80042000 2000>;
+                               reg = <0x80042000 0x2000>;
                                interrupts = <59 80>;
                                fsl,saif-dma-channel = <4>;
                                status = "disabled";
                        };
 
                        power@80044000 {
-                               reg = <0x80044000 2000>;
+                               reg = <0x80044000 0x2000>;
                                status = "disabled";
                        };
 
                        saif1: saif@80046000 {
                                compatible = "fsl,imx28-saif";
-                               reg = <0x80046000 2000>;
+                               reg = <0x80046000 0x2000>;
                                interrupts = <58 81>;
                                fsl,saif-dma-channel = <5>;
                                status = "disabled";
                        };
 
                        lradc@80050000 {
-                               reg = <0x80050000 2000>;
+                               reg = <0x80050000 0x2000>;
                                status = "disabled";
                        };
 
                        spdif@80054000 {
-                               reg = <0x80054000 2000>;
+                               reg = <0x80054000 0x2000>;
                                interrupts = <45 66>;
                                status = "disabled";
                        };
 
                        rtc@80056000 {
                                compatible = "fsl,imx28-rtc", "fsl,stmp3xxx-rtc";
-                               reg = <0x80056000 2000>;
+                               reg = <0x80056000 0x2000>;
                                interrupts = <29>;
                        };
 
                                #address-cells = <1>;
                                #size-cells = <0>;
                                compatible = "fsl,imx28-i2c";
-                               reg = <0x80058000 2000>;
+                               reg = <0x80058000 0x2000>;
                                interrupts = <111 68>;
                                clock-frequency = <100000>;
                                status = "disabled";
                                #address-cells = <1>;
                                #size-cells = <0>;
                                compatible = "fsl,imx28-i2c";
-                               reg = <0x8005a000 2000>;
+                               reg = <0x8005a000 0x2000>;
                                interrupts = <110 69>;
                                clock-frequency = <100000>;
                                status = "disabled";
 
                        pwm: pwm@80064000 {
                                compatible = "fsl,imx28-pwm", "fsl,imx23-pwm";
-                               reg = <0x80064000 2000>;
+                               reg = <0x80064000 0x2000>;
                                #pwm-cells = <2>;
                                fsl,pwm-number = <8>;
                                status = "disabled";
                        };
 
                        timrot@80068000 {
-                               reg = <0x80068000 2000>;
+                               reg = <0x80068000 0x2000>;
                                status = "disabled";
                        };
 
index de065b5976e6cf0ed025c7e550198f4b079b817c..cd86177a3ea21aa1dbe3d0dcea633b50661e5552 100644 (file)
@@ -53,7 +53,7 @@
                                                spi-max-frequency = <6000000>;
                                                reg = <0>;
                                                interrupt-parent = <&gpio1>;
-                                               interrupts = <8>;
+                                               interrupts = <8 0x4>;
 
                                                regulators {
                                                        sw1_reg: sw1 {
index 53cbaa3d4f904cbe464116640824fd24a4015d81..aaa0c0a4ca8fa0e18dafecf4fac9308ed7330513 100644 (file)
                serial0 = &uart1;
                serial1 = &uart2;
                serial2 = &uart3;
+               gpio0 = &gpio1;
+               gpio1 = &gpio2;
+               gpio2 = &gpio3;
+               gpio3 = &gpio4;
        };
 
        tzic: tz-interrupt-controller@e0000000 {
                                status = "disabled";
                        };
 
+                       nand@83fdb000 {
+                               compatible = "fsl,imx51-nand";
+                               reg = <0x83fdb000 0x1000 0xcfff0000 0x10000>;
+                               interrupts = <8>;
+                               status = "disabled";
+                       };
+
                        ssi3: ssi@83fe8000 {
                                compatible = "fsl,imx51-ssi", "fsl,imx21-ssi";
                                reg = <0x83fe8000 0x4000>;
index 5b8eafcdbeec638009a894365b577df17256b3c0..da895e93a999113e0585905126dd980f3029e80b 100644 (file)
                        reg = <0xf4000000 0x2000000>;
                        phy-mode = "mii";
                        interrupt-parent = <&gpio2>;
-                       interrupts = <31>;
+                       interrupts = <31 0x8>;
                        reg-io-width = <4>;
+                       /*
+                        * VDD33A and VDDVARIO of LAN9220 are supplied by
+                        * SW4_3V3 of LTC3589.  Before the regulator driver
+                        * for this PMIC is available, we use a fixed dummy
+                        * 3V3 regulator to get LAN9220 driver probing work.
+                        */
+                       vdd33a-supply = <&reg_3p3v>;
+                       vddvario-supply = <&reg_3p3v>;
                        smsc,irq-push-pull;
                };
        };
 
+       regulators {
+               compatible = "simple-bus";
+
+               reg_3p3v: 3p3v {
+                       compatible = "regulator-fixed";
+                       regulator-name = "3P3V";
+                       regulator-min-microvolt = <3300000>;
+                       regulator-max-microvolt = <3300000>;
+                       regulator-always-on;
+               };
+       };
+
        gpio-keys {
                compatible = "gpio-keys";
 
index fc79cdc4b4e6a18d96138025bad146caabb04004..dc00c62acc8aefc5f52c7b96a3195ac3e4cf7394 100644 (file)
                serial2 = &uart3;
                serial3 = &uart4;
                serial4 = &uart5;
+               gpio0 = &gpio1;
+               gpio1 = &gpio2;
+               gpio2 = &gpio3;
+               gpio3 = &gpio4;
+               gpio4 = &gpio5;
+               gpio5 = &gpio6;
+               gpio6 = &gpio7;
        };
 
        tzic: tz-interrupt-controller@0fffc000 {
                                status = "disabled";
                        };
 
+                       nand@63fdb000 {
+                               compatible = "fsl,imx53-nand";
+                               reg = <0x63fdb000 0x1000 0xf7ff0000 0x10000>;
+                               interrupts = <8>;
+                               status = "disabled";
+                       };
+
                        ssi3: ssi@63fe8000 {
                                compatible = "fsl,imx53-ssi", "fsl,imx21-ssi";
                                reg = <0x63fe8000 0x4000>;
index d42e851ceb97e423fd785e3cd357ba6d70b23d8c..72f30f3e6171b4b737d122333c03a25a37189ddb 100644 (file)
@@ -53,6 +53,7 @@
                                                fsl,pins = <
                                                           144  0x80000000      /* MX6Q_PAD_EIM_D22__GPIO_3_22 */
                                                           121  0x80000000      /* MX6Q_PAD_EIM_D19__GPIO_3_19 */
+                                                          953  0x80000000      /* MX6Q_PAD_GPIO_0__CCM_CLKO */
                                                           >;
                                        };
                                };
index 3d3c64b014e61f9978072571343f6b84afb5f523..fd57079f71a95281d107da8df2328c37df8cc1d6 100644 (file)
                serial2 = &uart3;
                serial3 = &uart4;
                serial4 = &uart5;
+               gpio0 = &gpio1;
+               gpio1 = &gpio2;
+               gpio2 = &gpio3;
+               gpio3 = &gpio4;
+               gpio4 = &gpio5;
+               gpio5 = &gpio6;
+               gpio6 = &gpio7;
        };
 
        cpus {
index 52d9470451069f5445661c79ffa902a7cc49eee1..f8ca6fa88192a5d36edb0c484a7a13c7c11e6e7c 100644 (file)
                };
                power-blue {
                        label = "power:blue";
-                       gpios = <&gpio1 11 0>;
+                       gpios = <&gpio1 10 0>;
                        linux,default-trigger = "timer";
                };
+               power-red {
+                       label = "power:red";
+                       gpios = <&gpio1 11 0>;
+               };
                usb1 {
                        label = "usb1:blue";
                        gpios = <&gpio1 12 0>;
index 80f74e256408dcf7cf1f34dcfa9594b1d629f238..0514fb41627e1130a52d3c4ed56ff81ea23d68d0 100644 (file)
                interrupt-parent = <&intc>;
                ranges;
 
+               L2: l2-cache {
+                       compatible = "marvell,tauros2-cache";
+                       marvell,tauros2-cache-features = <0x3>;
+               };
+
                axi@d4200000 {  /* AXI */
                        compatible = "mrvl,axi-bus", "simple-bus";
                        #address-cells = <1>;
diff --git a/arch/arm/boot/dts/pxa27x.dtsi b/arch/arm/boot/dts/pxa27x.dtsi
new file mode 100644 (file)
index 0000000..d7c5d72
--- /dev/null
@@ -0,0 +1,14 @@
+/* The pxa3xx skeleton simply augments the 2xx version */
+/include/ "pxa2xx.dtsi"
+
+/ {
+       model = "Marvell PXA27x familiy SoC";
+       compatible = "marvell,pxa27x";
+
+       pxabus {
+               pxairq: interrupt-controller@40d00000 {
+                       marvell,intc-priority;
+                       marvell,intc-nr-irqs = <34>;
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/pxa2xx.dtsi b/arch/arm/boot/dts/pxa2xx.dtsi
new file mode 100644 (file)
index 0000000..f18aad3
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * pxa2xx.dtsi - Device Tree Include file for Marvell PXA2xx family SoC
+ *
+ * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+/include/ "skeleton.dtsi"
+
+/ {
+       model = "Marvell PXA2xx family SoC";
+       compatible = "marvell,pxa2xx";
+       interrupt-parent = <&pxairq>;
+
+       aliases {
+               serial0 = &ffuart;
+               serial1 = &btuart;
+               serial2 = &stuart;
+               serial3 = &hwuart;
+               i2c0 = &pwri2c;
+               i2c1 = &pxai2c1;
+       };
+
+       cpus {
+               cpu@0 {
+                       compatible = "arm,xscale";
+               };
+       };
+
+       pxabus {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               pxairq: interrupt-controller@40d00000 {
+                       #interrupt-cells = <1>;
+                       compatible = "marvell,pxa-intc";
+                       interrupt-controller;
+                       interrupt-parent;
+                       marvell,intc-nr-irqs = <32>;
+                       reg = <0x40d00000 0xd0>;
+               };
+
+               gpio: gpio@40e00000 {
+                       compatible = "mrvl,pxa-gpio";
+                       #address-cells = <0x1>;
+                       #size-cells = <0x1>;
+                       reg = <0x40e00000 0x10000>;
+                       gpio-controller;
+                       #gpio-cells = <0x2>;
+                       interrupts = <10>;
+                       interrupt-names = "gpio_mux";
+                       interrupt-controller;
+                       #interrupt-cells = <0x2>;
+                       ranges;
+
+                       gcb0: gpio@40e00000 {
+                               reg = <0x40e00000 0x4>;
+                       };
+
+                       gcb1: gpio@40e00004 {
+                               reg = <0x40e00004 0x4>;
+                       };
+
+                       gcb2: gpio@40e00008 {
+                               reg = <0x40e00008 0x4>;
+                       };
+                       gcb3: gpio@40e0000c {
+                               reg = <0x40e0000c 0x4>;
+                       };
+               };
+
+               ffuart: uart@40100000 {
+                       compatible = "mrvl,pxa-uart";
+                       reg = <0x40100000 0x30>;
+                       interrupts = <22>;
+                       status = "disabled";
+               };
+
+               btuart: uart@40200000 {
+                       compatible = "mrvl,pxa-uart";
+                       reg = <0x40200000 0x30>;
+                       interrupts = <21>;
+                       status = "disabled";
+               };
+
+               stuart: uart@40700000 {
+                       compatible = "mrvl,pxa-uart";
+                       reg = <0x40700000 0x30>;
+                       interrupts = <20>;
+                       status = "disabled";
+               };
+
+               hwuart: uart@41100000 {
+                       compatible = "mrvl,pxa-uart";
+                       reg = <0x41100000 0x30>;
+                       interrupts = <7>;
+                       status = "disabled";
+               };
+
+               pxai2c1: i2c@40301680 {
+                       compatible = "mrvl,pxa-i2c";
+                       reg = <0x40301680 0x30>;
+                       interrupts = <18>;
+                       #address-cells = <0x1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
+               usb0: ohci@4c000000 {
+                       compatible = "mrvl,pxa-ohci";
+                       reg = <0x4c000000 0x10000>;
+                       interrupts = <3>;
+                       status = "disabled";
+               };
+
+               mmc0: mmc@41100000 {
+                       compatible = "mrvl,pxa-mmc";
+                       reg = <0x41100000 0x1000>;
+                       interrupts = <23>;
+                       status = "disabled";
+               };
+
+               rtc@40900000 {
+                       compatible = "marvell,pxa-rtc";
+                       reg = <0x40900000 0x3c>;
+                       interrupts = <30 31>;
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/pxa3xx.dtsi b/arch/arm/boot/dts/pxa3xx.dtsi
new file mode 100644 (file)
index 0000000..f9d92da
--- /dev/null
@@ -0,0 +1,32 @@
+/* The pxa3xx skeleton simply augments the 2xx version */
+/include/ "pxa2xx.dtsi"
+
+/ {
+       model = "Marvell PXA3xx familiy SoC";
+       compatible = "marvell,pxa3xx";
+
+       pxabus {
+               pwri2c: i2c@40f500c0 {
+                       compatible = "mrvl,pwri2c";
+                       reg = <0x40f500c0 0x30>;
+                       interrupts = <6>;
+                       #address-cells = <0x1>;
+                       #size-cells = <0>;
+                       status = "disabled";
+               };
+
+               nand0: nand@43100000 {
+                       compatible = "marvell,pxa3xx-nand";
+                       reg = <0x43100000 90>;
+                       interrupts = <45>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;      
+                       status = "disabled";
+               };
+
+               pxairq: interrupt-controller@40d00000 {
+                       marvell,intc-priority;
+                       marvell,intc-nr-irqs = <56>;
+               };
+       };
+};
index aebf32de73b4ea31c44e2d18fd1c6f75c578488e..a3be44d86bcd5a3f9bd4938364bb76cedf85c5ac 100644 (file)
                interrupt-parent = <&intc>;
                ranges;
 
+               L2: l2-cache {
+                       compatible = "marvell,tauros2-cache";
+                       marvell,tauros2-cache-features = <0x3>;
+               };
+
                axi@d4200000 {  /* AXI */
                        compatible = "mrvl,axi-bus", "simple-bus";
                        #address-cells = <1>;
index 3b2f3510d7eb91ca5ce520692682ad26aca89d31..d351b27d7213f65c50680e50965d41cdfd4218f2 100644 (file)
@@ -66,6 +66,7 @@
 
        vcxio: regulator@8 {
                compatible = "ti,twl6030-vcxio";
+               regulator-always-on;
        };
 
        vusb: regulator@9 {
 
        v1v8: regulator@10 {
                compatible = "ti,twl6030-v1v8";
+               regulator-always-on;
        };
 
        v2v1: regulator@11 {
                compatible = "ti,twl6030-v2v1";
+               regulator-always-on;
        };
 
        clk32kg: regulator@12 {
index 2afdf67c2127184c335763aa845dd0fbb8a6558f..c285a9d777d933847a4ec3c9d8bf3e00ba2c18a5 100644 (file)
@@ -39,7 +39,6 @@ CONFIG_MTD_BLOCK=y
 CONFIG_MTD_DATAFLASH=y
 CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_ATMEL=y
-CONFIG_MTD_NAND_ATMEL_ECC_SOFT=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=8192
 CONFIG_ATMEL_SSC=y
index d54e2acd3ab16616814feaa1fcdbf9e712be5e9d..4ae57a34a582b704d9484bd41ec37fc49ac2f2e2 100644 (file)
@@ -232,7 +232,7 @@ CONFIG_USB_GADGET=y
 CONFIG_USB_ETH=m
 CONFIG_USB_MASS_STORAGE=m
 CONFIG_MMC=y
-CONFIG_MMC_AT91=y
+CONFIG_MMC_ATMELMCI=y
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_GPIO=y
index ade6b2f231164b00c1fc22ede4866e47d2aee485..1e8712ef062e42733552cd948810b4b984e2e5d1 100644 (file)
@@ -128,7 +128,7 @@ CONFIG_USB_GADGETFS=m
 CONFIG_USB_FILE_STORAGE=m
 CONFIG_USB_G_SERIAL=m
 CONFIG_MMC=y
-CONFIG_MMC_AT91=m
+CONFIG_MMC_ATMELMCI=m
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_GPIO=y
index 1cf96264cba1456ad4a7ae54daeb414479c3e684..d2050cada82d650334de0b44523efe6a5bcc1159 100644 (file)
@@ -61,7 +61,6 @@ CONFIG_MTD_DATAFLASH=y
 CONFIG_MTD_BLOCK2MTD=y
 CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_ATMEL=y
-CONFIG_MTD_NAND_ATMEL_ECC_SOFT=y
 CONFIG_MTD_UBI=y
 CONFIG_MTD_UBI_GLUEBI=y
 CONFIG_BLK_DEV_LOOP=y
@@ -138,7 +137,7 @@ CONFIG_USB_FILE_STORAGE=m
 CONFIG_USB_G_SERIAL=m
 CONFIG_MMC=y
 CONFIG_SDIO_UART=m
-CONFIG_MMC_AT91=m
+CONFIG_MMC_ATMELMCI=m
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_ATMEL_PWM=y
index 994d331b231956b0edd5d6e01a773beeda32fa60..e1b0e80b54a5693b792bfe2acaceb9be695c1c86 100644 (file)
@@ -99,7 +99,7 @@ CONFIG_USB_GADGETFS=m
 CONFIG_USB_FILE_STORAGE=m
 CONFIG_USB_G_SERIAL=m
 CONFIG_MMC=y
-CONFIG_MMC_AT91=m
+CONFIG_MMC_ATMELMCI=m
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_GPIO=y
index ad562ee64209cd08e57f9b31160c089b810d7c11..7cf87856d63ca2738112d59f336f615ec3ce36d5 100644 (file)
@@ -60,7 +60,7 @@ CONFIG_AT91SAM9X_WATCHDOG=y
 CONFIG_FB=y
 CONFIG_FB_ATMEL=y
 CONFIG_MMC=y
-CONFIG_MMC_AT91=m
+CONFIG_MMC_ATMELMCI=m
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_AT91SAM9=y
 CONFIG_EXT2_FS=y
index bbf729e2fb6f3f353588af389fffb929531d9aa8..921480c23b9813b8274d38cace24c6ea46961f05 100644 (file)
@@ -82,7 +82,7 @@ CONFIG_USB_STORAGE=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_ETH=m
 CONFIG_MMC=y
-CONFIG_MMC_AT91=m
+CONFIG_MMC_ATMELMCI=m
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_GPIO=y
index e7d7942927f388e4f794af9f61ee0539980dd8bc..ea116cbdffa1c7f9f60ac466fec45388094fc577 100644 (file)
@@ -82,7 +82,7 @@ CONFIG_USB_STORAGE=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_ETH=m
 CONFIG_MMC=y
-CONFIG_MMC_AT91=m
+CONFIG_MMC_ATMELMCI=m
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_GPIO=y
index f725b9637b3374a4079c17ca50823f064ea0bb6d..3c9f32f9b6b4dc6e5b77884deaa216c87684919c 100644 (file)
@@ -192,6 +192,7 @@ CONFIG_RTC_DRV_MC13XXX=y
 CONFIG_RTC_DRV_MXC=y
 CONFIG_DMADEVICES=y
 CONFIG_IMX_SDMA=y
+CONFIG_MXS_DMA=y
 CONFIG_COMMON_CLK_DEBUG=y
 # CONFIG_IOMMU_SUPPORT is not set
 CONFIG_EXT2_FS=y
index ccdb6357fb74065e017d44527a27e8c2c7a3f46d..4edcfb4e4deeea476d9b5007779153d2281643b8 100644 (file)
@@ -34,7 +34,6 @@ CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_PREEMPT_VOLUNTARY=y
 CONFIG_AEABI=y
-CONFIG_DEFAULT_MMAP_MIN_ADDR=65536
 CONFIG_AUTO_ZRELADDR=y
 CONFIG_FPE_NWFPE=y
 CONFIG_NET=y
index 9160f3b7751faab0478784d0669b85afe9bcdd98..42d5db1876ab5ec3f782b179c563718da1c92036 100644 (file)
@@ -50,7 +50,6 @@ CONFIG_MTD_BLOCK=y
 CONFIG_MTD_DATAFLASH=y
 CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_ATMEL=y
-CONFIG_MTD_NAND_ATMEL_ECC_SOFT=y
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_MISC_DEVICES is not set
 CONFIG_SCSI=y
@@ -87,7 +86,7 @@ CONFIG_USB_STORAGE=y
 CONFIG_USB_GADGET=y
 CONFIG_USB_ETH=m
 CONFIG_MMC=y
-CONFIG_MMC_AT91=m
+CONFIG_MMC_ATMELMCI=m
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
 CONFIG_LEDS_GPIO=y
index ecf2531523a11bbcf34c8fd1b48ca3d7be5041dc..da276f98ceb8d0bf28c2a8c5ead252342e1a0460 100644 (file)
@@ -39,7 +39,7 @@ CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_ATMEL=y
 CONFIG_MTD_NAND_PLATFORM=y
 CONFIG_MTD_UBI=y
-CONFIG_MTD_UBI_BEB_RESERVE=3
+CONFIG_MTD_UBI_BEB_LIMIT=3
 CONFIG_MTD_UBI_GLUEBI=y
 CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_RAM=y
index d5e260b8b16066314e645d1fb313b6e3f3cbac0d..52f1488591c7bb5724e848b8caa706973fa314d4 100644 (file)
@@ -100,7 +100,6 @@ CONFIG_USB_ETH=m
 CONFIG_USB_FILE_STORAGE=m
 CONFIG_USB_G_SERIAL=m
 CONFIG_MMC=y
-# CONFIG_MMC_AT91 is not set
 CONFIG_MMC_ATMELMCI=y
 CONFIG_NEW_LEDS=y
 CONFIG_LEDS_CLASS=y
index 1d24f8458befd49cd41b98e6fb1d6f22fcca8f94..71277a1591bad96d77036ad8eb2557af2a6d4c54 100644 (file)
@@ -7,7 +7,7 @@ CONFIG_SYSFS_DEPRECATED_V2=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_EXPERT=y
 # CONFIG_KALLSYMS is not set
-# CONFIG_BUG is not set
+# CONFIG_BUGVERBOSE is not set
 # CONFIG_ELF_CORE is not set
 # CONFIG_SHMEM is not set
 CONFIG_SLOB=y
index 2e39f38b9627197fc3b6cf6338ad665b7acc5ae6..a1501e1e1a90bcb1717475538ca8840b9d2aff26 100644 (file)
@@ -49,7 +49,6 @@ CONFIG_MTD_BLOCK=y
 CONFIG_MTD_DATAFLASH=y
 CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_ATMEL=y
-CONFIG_MTD_NAND_ATMEL_ECC_SOFT=y
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_MISC_DEVICES is not set
 CONFIG_SCSI=y
index 538f17ca905b1a7c9818496ee4ed50acd9f970a0..295e2e40151b12c0d2ad3ad2c3ced4f8de54e76a 100644 (file)
@@ -8,4 +8,7 @@
  * warranty of any kind, whether express or implied.
  */
 
-extern void __init tauros2_init(void);
+#define CACHE_TAUROS2_PREFETCH_ON      (1 << 0)
+#define CACHE_TAUROS2_LINEFILL_BURST8  (1 << 1)
+
+extern void __init tauros2_init(unsigned int features);
index 2ff2c75a46391344689893b3132b714ca96b8020..02fe2fbe2477078b4fa8da59c6f2a416fdb71913 100644 (file)
@@ -217,18 +217,8 @@ extern int iop3xx_get_init_atu(void);
 #define IOP3XX_PCI_LOWER_MEM_PA        0x80000000
 #define IOP3XX_PCI_MEM_WINDOW_SIZE     0x08000000
 
-#define IOP3XX_PCI_IO_WINDOW_SIZE      0x00010000
 #define IOP3XX_PCI_LOWER_IO_PA         0x90000000
-#define IOP3XX_PCI_LOWER_IO_VA         0xfe000000
-#define IOP3XX_PCI_LOWER_IO_BA         0x90000000
-#define IOP3XX_PCI_UPPER_IO_PA         (IOP3XX_PCI_LOWER_IO_PA +\
-                                       IOP3XX_PCI_IO_WINDOW_SIZE - 1)
-#define IOP3XX_PCI_UPPER_IO_VA         (IOP3XX_PCI_LOWER_IO_VA +\
-                                       IOP3XX_PCI_IO_WINDOW_SIZE - 1)
-#define IOP3XX_PCI_IO_PHYS_TO_VIRT(addr) (((u32) (addr) -\
-                                       IOP3XX_PCI_LOWER_IO_PA) +\
-                                       IOP3XX_PCI_LOWER_IO_VA)
-
+#define IOP3XX_PCI_LOWER_IO_BA         0x00000000
 
 #ifndef __ASSEMBLY__
 
index 815c669fec0a1f52665120604c774dbb6e9b2e41..8f4db67533e5a7bf937ce94396e6b7bd19367036 100644 (file)
@@ -113,11 +113,19 @@ static inline void __iomem *__typesafe_io(unsigned long addr)
 #define __iowmb()              do { } while (0)
 #endif
 
+/* PCI fixed i/o mapping */
+#define PCI_IO_VIRT_BASE       0xfee00000
+
+extern int pci_ioremap_io(unsigned int offset, phys_addr_t phys_addr);
+
 /*
  * Now, pick up the machine-defined IO definitions
  */
 #ifdef CONFIG_NEED_MACH_IO_H
 #include <mach/io.h>
+#elif defined(CONFIG_PCI)
+#define IO_SPACE_LIMIT ((resource_size_t)0xfffff)
+#define __io(a)                __typesafe_io(PCI_IO_VIRT_BASE + ((a) & IO_SPACE_LIMIT))
 #else
 #define __io(a)                __typesafe_io((a) & IO_SPACE_LIMIT)
 #endif
diff --git a/arch/arm/include/asm/leds.h b/arch/arm/include/asm/leds.h
deleted file mode 100644 (file)
index c545739..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- *  arch/arm/include/asm/leds.h
- *
- *  Copyright (C) 1998 Russell King
- *
- * 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.
- *
- *  Event-driven interface for LEDs on machines
- *  Added led_start and led_stop- Alex Holden, 28th Dec 1998.
- */
-#ifndef ASM_ARM_LEDS_H
-#define ASM_ARM_LEDS_H
-
-
-typedef enum {
-       led_idle_start,
-       led_idle_end,
-       led_timer,
-       led_start,
-       led_stop,
-       led_claim,              /* override idle & timer leds */
-       led_release,            /* restore idle & timer leds */
-       led_start_timer_mode,
-       led_stop_timer_mode,
-       led_green_on,
-       led_green_off,
-       led_amber_on,
-       led_amber_off,
-       led_red_on,
-       led_red_off,
-       led_blue_on,
-       led_blue_off,
-       /*
-        * I want this between led_timer and led_start, but
-        * someone has decided to export this to user space
-        */
-       led_halted
-} led_event_t;
-
-/* Use this routine to handle LEDs */
-
-#ifdef CONFIG_LEDS
-extern void (*leds_event)(led_event_t);
-#else
-#define leds_event(e)
-#endif
-
-#endif
index a6efcdd6fd25135803d906329675f989e3fdb8ea..195ac2f9d3d3b1eaaebca8a2b5260fb41f4e27e0 100644 (file)
@@ -9,6 +9,9 @@
  *
  *  Page table mapping constructs and function prototypes
  */
+#ifndef __ASM_MACH_MAP_H
+#define __ASM_MACH_MAP_H
+
 #include <asm/io.h>
 
 struct map_desc {
@@ -34,6 +37,8 @@ struct map_desc {
 
 #ifdef CONFIG_MMU
 extern void iotable_init(struct map_desc *, int);
+extern void vm_reserve_area_early(unsigned long addr, unsigned long size,
+                                 void *caller);
 
 struct mem_type;
 extern const struct mem_type *get_mem_type(unsigned int type);
@@ -44,4 +49,7 @@ extern int ioremap_page(unsigned long virt, unsigned long phys,
                        const struct mem_type *mtype);
 #else
 #define iotable_init(map,num)  do { } while (0)
+#define vm_reserve_area_early(a,s,c)   do { } while (0)
+#endif
+
 #endif
index 26c511fddf8fdc10ceea18e333de4e1320966e9e..db9fedb57f2c4284d2d456ee0eef29270580579c 100644 (file)
@@ -11,6 +11,8 @@
 #ifndef __ASM_MACH_PCI_H
 #define __ASM_MACH_PCI_H
 
+#include <linux/ioport.h>
+
 struct pci_sys_data;
 struct pci_ops;
 struct pci_bus;
@@ -42,6 +44,8 @@ struct pci_sys_data {
        unsigned long   io_offset;      /* bus->cpu IO mapping offset           */
        struct pci_bus  *bus;           /* PCI bus                              */
        struct list_head resources;     /* root bus resources (apertures)       */
+       struct resource io_res;
+       char            io_res_name[12];
                                        /* Bridge swizzling                     */
        u8              (*swizzle)(struct pci_dev *, u8 *);
                                        /* IRQ mapping                          */
@@ -54,6 +58,15 @@ struct pci_sys_data {
  */
 void pci_common_init(struct hw_pci *);
 
+/*
+ * Setup early fixed I/O mapping.
+ */
+#if defined(CONFIG_PCI)
+extern void pci_map_io_early(unsigned long pfn);
+#else
+static inline void pci_map_io_early(unsigned long pfn) {}
+#endif
+
 /*
  * PCI controllers
  */
index 6c6809f982f12557a6fa23a711f095c9a122fdb0..0d3a28dbc8e5db05823e6b83f85ccc5d04b807ac 100644 (file)
@@ -1,9 +1,7 @@
 #ifndef _ASM_ARM_MODULE_H
 #define _ASM_ARM_MODULE_H
 
-#define Elf_Shdr       Elf32_Shdr
-#define Elf_Sym                Elf32_Sym
-#define Elf_Ehdr       Elf32_Ehdr
+#include <asm-generic/module.h>
 
 struct unwind_table;
 
@@ -16,13 +14,11 @@ enum {
        ARM_SEC_DEVEXIT,
        ARM_SEC_MAX,
 };
-#endif
 
 struct mod_arch_specific {
-#ifdef CONFIG_ARM_UNWIND
        struct unwind_table *unwind[ARM_SEC_MAX];
-#endif
 };
+#endif
 
 /*
  * Add the ARM architecture version to the version magic string
index e074948d81431cec24598e088a696202d52f1615..625cd621a436db1d24d1d9ee53dffe0fe0ff70d8 100644 (file)
 #ifndef __ARM_PERF_EVENT_H__
 #define __ARM_PERF_EVENT_H__
 
-/* Nothing to see here... */
+/*
+ * The ARMv7 CPU PMU supports up to 32 event counters.
+ */
+#define ARMPMU_MAX_HWEVENTS            32
+
+#define HW_OP_UNSUPPORTED              0xFFFF
+#define C(_x)                          PERF_COUNT_HW_CACHE_##_x
+#define CACHE_OP_UNSUPPORTED           0xFFFF
 
 #endif /* __ARM_PERF_EVENT_H__ */
index f66626d71e7d1a304ad2c750fc4b00be9a436901..41dc31f834c3b68926a070036ac024b83f8e7b66 100644 (file)
@@ -195,6 +195,18 @@ static inline pte_t *pmd_page_vaddr(pmd_t pmd)
 
 #define pte_clear(mm,addr,ptep)        set_pte_ext(ptep, __pte(0), 0)
 
+#define pte_none(pte)          (!pte_val(pte))
+#define pte_present(pte)       (pte_val(pte) & L_PTE_PRESENT)
+#define pte_write(pte)         (!(pte_val(pte) & L_PTE_RDONLY))
+#define pte_dirty(pte)         (pte_val(pte) & L_PTE_DIRTY)
+#define pte_young(pte)         (pte_val(pte) & L_PTE_YOUNG)
+#define pte_exec(pte)          (!(pte_val(pte) & L_PTE_XN))
+#define pte_special(pte)       (0)
+
+#define pte_present_user(pte) \
+       ((pte_val(pte) & (L_PTE_PRESENT | L_PTE_USER)) == \
+        (L_PTE_PRESENT | L_PTE_USER))
+
 #if __LINUX_ARM_ARCH__ < 6
 static inline void __sync_icache_dcache(pte_t pteval)
 {
@@ -206,25 +218,15 @@ extern void __sync_icache_dcache(pte_t pteval);
 static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
                              pte_t *ptep, pte_t pteval)
 {
-       if (addr >= TASK_SIZE)
-               set_pte_ext(ptep, pteval, 0);
-       else {
+       unsigned long ext = 0;
+
+       if (addr < TASK_SIZE && pte_present_user(pteval)) {
                __sync_icache_dcache(pteval);
-               set_pte_ext(ptep, pteval, PTE_EXT_NG);
+               ext |= PTE_EXT_NG;
        }
-}
 
-#define pte_none(pte)          (!pte_val(pte))
-#define pte_present(pte)       (pte_val(pte) & L_PTE_PRESENT)
-#define pte_write(pte)         (!(pte_val(pte) & L_PTE_RDONLY))
-#define pte_dirty(pte)         (pte_val(pte) & L_PTE_DIRTY)
-#define pte_young(pte)         (pte_val(pte) & L_PTE_YOUNG)
-#define pte_exec(pte)          (!(pte_val(pte) & L_PTE_XN))
-#define pte_special(pte)       (0)
-
-#define pte_present_user(pte) \
-       ((pte_val(pte) & (L_PTE_PRESENT | L_PTE_USER)) == \
-        (L_PTE_PRESENT | L_PTE_USER))
+       set_pte_ext(ptep, pteval, ext);
+}
 
 #define PTE_BIT_FUNC(fn,op) \
 static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; }
@@ -251,13 +253,13 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
  *
  *   3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
  *   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
- *   <--------------- offset --------------------> <- type --> 0 0 0
+ *   <--------------- offset ----------------------> < type -> 0 0 0
  *
- * This gives us up to 63 swap files and 32GB per swap file.  Note that
+ * This gives us up to 31 swap files and 64GB per swap file.  Note that
  * the offset field is always non-zero.
  */
 #define __SWP_TYPE_SHIFT       3
-#define __SWP_TYPE_BITS                6
+#define __SWP_TYPE_BITS                5
 #define __SWP_TYPE_MASK                ((1 << __SWP_TYPE_BITS) - 1)
 #define __SWP_OFFSET_SHIFT     (__SWP_TYPE_BITS + __SWP_TYPE_SHIFT)
 
index 4432305f4a2aa1b2e89bf69beaf032929816f78d..a26170dce02e4b735ddab00a5ead32883e07b1b2 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/perf_event.h>
 
-/*
- * Types of PMUs that can be accessed directly and require mutual
- * exclusion between profiling tools.
- */
-enum arm_pmu_type {
-       ARM_PMU_DEVICE_CPU      = 0,
-       ARM_NUM_PMU_DEVICES,
-};
-
 /*
  * struct arm_pmu_platdata - ARM PMU platform data
  *
@@ -31,54 +22,24 @@ enum arm_pmu_type {
  *     interrupt and passed the address of the low level handler,
  *     and can be used to implement any platform specific handling
  *     before or after calling it.
- * @enable_irq: an optional handler which will be called after
- *     request_irq and be used to handle some platform specific
- *     irq enablement
- * @disable_irq: an optional handler which will be called before
- *     free_irq and be used to handle some platform specific
- *     irq disablement
+ * @runtime_resume: an optional handler which will be called by the
+ *     runtime PM framework following a call to pm_runtime_get().
+ *     Note that if pm_runtime_get() is called more than once in
+ *     succession this handler will only be called once.
+ * @runtime_suspend: an optional handler which will be called by the
+ *     runtime PM framework following a call to pm_runtime_put().
+ *     Note that if pm_runtime_get() is called more than once in
+ *     succession this handler will only be called following the
+ *     final call to pm_runtime_put() that actually disables the
+ *     hardware.
  */
 struct arm_pmu_platdata {
        irqreturn_t (*handle_irq)(int irq, void *dev,
                                  irq_handler_t pmu_handler);
-       void (*enable_irq)(int irq);
-       void (*disable_irq)(int irq);
+       int (*runtime_resume)(struct device *dev);
+       int (*runtime_suspend)(struct device *dev);
 };
 
-#ifdef CONFIG_CPU_HAS_PMU
-
-/**
- * reserve_pmu() - reserve the hardware performance counters
- *
- * Reserve the hardware performance counters in the system for exclusive use.
- * Returns 0 on success or -EBUSY if the lock is already held.
- */
-extern int
-reserve_pmu(enum arm_pmu_type type);
-
-/**
- * release_pmu() - Relinquish control of the performance counters
- *
- * Release the performance counters and allow someone else to use them.
- */
-extern void
-release_pmu(enum arm_pmu_type type);
-
-#else /* CONFIG_CPU_HAS_PMU */
-
-#include <linux/err.h>
-
-static inline int
-reserve_pmu(enum arm_pmu_type type)
-{
-       return -ENODEV;
-}
-
-static inline void
-release_pmu(enum arm_pmu_type type)    { }
-
-#endif /* CONFIG_CPU_HAS_PMU */
-
 #ifdef CONFIG_HW_PERF_EVENTS
 
 /* The events for a given PMU register set. */
@@ -103,7 +64,6 @@ struct pmu_hw_events {
 
 struct arm_pmu {
        struct pmu      pmu;
-       enum arm_pmu_type type;
        cpumask_t       active_irqs;
        char            *name;
        irqreturn_t     (*handle_irq)(int irq_num, void *dev);
@@ -118,6 +78,8 @@ struct arm_pmu {
        void            (*start)(void);
        void            (*stop)(void);
        void            (*reset)(void *);
+       int             (*request_irq)(irq_handler_t handler);
+       void            (*free_irq)(void);
        int             (*map_event)(struct perf_event *event);
        int             num_events;
        atomic_t        active_events;
@@ -129,7 +91,9 @@ struct arm_pmu {
 
 #define to_arm_pmu(p) (container_of(p, struct arm_pmu, pmu))
 
-int __init armpmu_register(struct arm_pmu *armpmu, char *name, int type);
+extern const struct dev_pm_ops armpmu_dev_pm_ops;
+
+int armpmu_register(struct arm_pmu *armpmu, char *name, int type);
 
 u64 armpmu_event_update(struct perf_event *event,
                        struct hw_perf_event *hwc,
@@ -139,6 +103,13 @@ int armpmu_event_set_period(struct perf_event *event,
                            struct hw_perf_event *hwc,
                            int idx);
 
+int armpmu_map_event(struct perf_event *event,
+                    const unsigned (*event_map)[PERF_COUNT_HW_MAX],
+                    const unsigned (*cache_map)[PERF_COUNT_HW_CACHE_MAX]
+                                               [PERF_COUNT_HW_CACHE_OP_MAX]
+                                               [PERF_COUNT_HW_CACHE_RESULT_MAX],
+                    u32 raw_event_mask);
+
 #endif /* CONFIG_HW_PERF_EVENTS */
 
 #endif /* __ARM_PMU_H__ */
index e3f7572634381bd28fbf3225eb375788431ee3fc..05b8e82ec9f5b66744305de1094df1115fc92798 100644 (file)
@@ -10,5 +10,7 @@
 
 extern void sched_clock_postinit(void);
 extern void setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate);
+extern void setup_sched_clock_needs_suspend(u32 (*read)(void), int bits,
+               unsigned long rate);
 
 #endif
index 7ad2d5cf700825892278c55920ded6f77e60558e..d81f3a6d9ad84df7917d2a1edefb68b0dcae6ac9 100644 (file)
@@ -21,7 +21,6 @@ obj-y         := elf.o entry-armv.o entry-common.o irq.o opcodes.o \
 
 obj-$(CONFIG_DEPRECATED_PARAM_STRUCT) += compat.o
 
-obj-$(CONFIG_LEDS)             += leds.o
 obj-$(CONFIG_OC_ETM)           += etm.o
 obj-$(CONFIG_CPU_IDLE)         += cpuidle.o
 obj-$(CONFIG_ISA_DMA_API)      += dma.o
@@ -69,8 +68,7 @@ obj-$(CONFIG_CPU_XSC3)                += xscale-cp0.o
 obj-$(CONFIG_CPU_MOHAWK)       += xscale-cp0.o
 obj-$(CONFIG_CPU_PJ4)          += pj4-cp0.o
 obj-$(CONFIG_IWMMXT)           += iwmmxt.o
-obj-$(CONFIG_CPU_HAS_PMU)      += pmu.o
-obj-$(CONFIG_HW_PERF_EVENTS)   += perf_event.o
+obj-$(CONFIG_HW_PERF_EVENTS)   += perf_event.o perf_event_cpu.o
 AFLAGS_iwmmxt.o                        := -Wa,-mcpu=iwmmxt
 obj-$(CONFIG_ARM_CPU_TOPOLOGY)  += topology.o
 
index 2b2f25e7fef5f07f545f8f5f0b9866a945a9026a..b244696de1a3da299d6bacfbadbde2433d71bcc7 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/io.h>
 
 #include <asm/mach-types.h>
+#include <asm/mach/map.h>
 #include <asm/mach/pci.h>
 
 static int debug_pci;
@@ -423,6 +424,38 @@ static int pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
        return irq;
 }
 
+static int __init pcibios_init_resources(int busnr, struct pci_sys_data *sys)
+{
+       int ret;
+       struct pci_host_bridge_window *window;
+
+       if (list_empty(&sys->resources)) {
+               pci_add_resource_offset(&sys->resources,
+                        &iomem_resource, sys->mem_offset);
+       }
+
+       list_for_each_entry(window, &sys->resources, list) {
+               if (resource_type(window->res) == IORESOURCE_IO)
+                       return 0;
+       }
+
+       sys->io_res.start = (busnr * SZ_64K) ?  : pcibios_min_io;
+       sys->io_res.end = (busnr + 1) * SZ_64K - 1;
+       sys->io_res.flags = IORESOURCE_IO;
+       sys->io_res.name = sys->io_res_name;
+       sprintf(sys->io_res_name, "PCI%d I/O", busnr);
+
+       ret = request_resource(&ioport_resource, &sys->io_res);
+       if (ret) {
+               pr_err("PCI: unable to allocate I/O port region (%d)\n", ret);
+               return ret;
+       }
+       pci_add_resource_offset(&sys->resources, &sys->io_res,
+                               sys->io_offset);
+
+       return 0;
+}
+
 static void __init pcibios_init_hw(struct hw_pci *hw, struct list_head *head)
 {
        struct pci_sys_data *sys = NULL;
@@ -445,11 +478,10 @@ static void __init pcibios_init_hw(struct hw_pci *hw, struct list_head *head)
                ret = hw->setup(nr, sys);
 
                if (ret > 0) {
-                       if (list_empty(&sys->resources)) {
-                               pci_add_resource_offset(&sys->resources,
-                                        &ioport_resource, sys->io_offset);
-                               pci_add_resource_offset(&sys->resources,
-                                        &iomem_resource, sys->mem_offset);
+                       ret = pcibios_init_resources(nr, sys);
+                       if (ret)  {
+                               kfree(sys);
+                               break;
                        }
 
                        if (hw->scan)
@@ -627,3 +659,15 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
 
        return 0;
 }
+
+void __init pci_map_io_early(unsigned long pfn)
+{
+       struct map_desc pci_io_desc = {
+               .virtual        = PCI_IO_VIRT_BASE,
+               .type           = MT_DEVICE,
+               .length         = SZ_64K,
+       };
+
+       pci_io_desc.pfn = pfn;
+       iotable_init(&pci_io_desc, 1);
+}
index ba386bd94107642d9819a7d8bafb7ba04e92b83f..4eedfde21f176fd263b100a6c9bd98632043e157 100644 (file)
@@ -159,6 +159,12 @@ static int debug_arch_supported(void)
                arch >= ARM_DEBUG_ARCH_V7_1;
 }
 
+/* Can we determine the watchpoint access type from the fsr? */
+static int debug_exception_updates_fsr(void)
+{
+       return 0;
+}
+
 /* Determine number of WRP registers available. */
 static int get_num_wrp_resources(void)
 {
@@ -604,13 +610,14 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
                /* Aligned */
                break;
        case 1:
-               /* Allow single byte watchpoint. */
-               if (info->ctrl.len == ARM_BREAKPOINT_LEN_1)
-                       break;
        case 2:
                /* Allow halfword watchpoints and breakpoints. */
                if (info->ctrl.len == ARM_BREAKPOINT_LEN_2)
                        break;
+       case 3:
+               /* Allow single byte watchpoint. */
+               if (info->ctrl.len == ARM_BREAKPOINT_LEN_1)
+                       break;
        default:
                ret = -EINVAL;
                goto out;
@@ -619,18 +626,34 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp)
        info->address &= ~alignment_mask;
        info->ctrl.len <<= offset;
 
-       /*
-        * Currently we rely on an overflow handler to take
-        * care of single-stepping the breakpoint when it fires.
-        * In the case of userspace breakpoints on a core with V7 debug,
-        * we can use the mismatch feature as a poor-man's hardware
-        * single-step, but this only works for per-task breakpoints.
-        */
-       if (!bp->overflow_handler && (arch_check_bp_in_kernelspace(bp) ||
-           !core_has_mismatch_brps() || !bp->hw.bp_target)) {
-               pr_warning("overflow handler required but none found\n");
-               ret = -EINVAL;
+       if (!bp->overflow_handler) {
+               /*
+                * Mismatch breakpoints are required for single-stepping
+                * breakpoints.
+                */
+               if (!core_has_mismatch_brps())
+                       return -EINVAL;
+
+               /* We don't allow mismatch breakpoints in kernel space. */
+               if (arch_check_bp_in_kernelspace(bp))
+                       return -EPERM;
+
+               /*
+                * Per-cpu breakpoints are not supported by our stepping
+                * mechanism. */
+               if (!bp->hw.bp_target)
+                       return -EINVAL;
+
+               /*
+                * We only support specific access types if the fsr
+                * reports them.
+                */
+               if (!debug_exception_updates_fsr() &&
+                   (info->ctrl.type == ARM_BREAKPOINT_LOAD ||
+                    info->ctrl.type == ARM_BREAKPOINT_STORE))
+                       return -EINVAL;
        }
+
 out:
        return ret;
 }
@@ -706,10 +729,12 @@ static void watchpoint_handler(unsigned long addr, unsigned int fsr,
                                goto unlock;
 
                        /* Check that the access type matches. */
-                       access = (fsr & ARM_FSR_ACCESS_MASK) ? HW_BREAKPOINT_W :
-                                HW_BREAKPOINT_R;
-                       if (!(access & hw_breakpoint_type(wp)))
-                               goto unlock;
+                       if (debug_exception_updates_fsr()) {
+                               access = (fsr & ARM_FSR_ACCESS_MASK) ?
+                                         HW_BREAKPOINT_W : HW_BREAKPOINT_R;
+                               if (!(access & hw_breakpoint_type(wp)))
+                                       goto unlock;
+                       }
 
                        /* We have a winner. */
                        info->trigger = addr;
diff --git a/arch/arm/kernel/leds.c b/arch/arm/kernel/leds.c
deleted file mode 100644 (file)
index 1911dae..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * LED support code, ripped out of arch/arm/kernel/time.c
- *
- *  Copyright (C) 1994-2001 Russell King
- *
- * 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/export.h>
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/syscore_ops.h>
-#include <linux/string.h>
-
-#include <asm/leds.h>
-
-static void dummy_leds_event(led_event_t evt)
-{
-}
-
-void (*leds_event)(led_event_t) = dummy_leds_event;
-
-struct leds_evt_name {
-       const char      name[8];
-       int             on;
-       int             off;
-};
-
-static const struct leds_evt_name evt_names[] = {
-       { "amber", led_amber_on, led_amber_off },
-       { "blue",  led_blue_on,  led_blue_off  },
-       { "green", led_green_on, led_green_off },
-       { "red",   led_red_on,   led_red_off   },
-};
-
-static ssize_t leds_store(struct device *dev,
-                       struct device_attribute *attr,
-                       const char *buf, size_t size)
-{
-       int ret = -EINVAL, len = strcspn(buf, " ");
-
-       if (len > 0 && buf[len] == '\0')
-               len--;
-
-       if (strncmp(buf, "claim", len) == 0) {
-               leds_event(led_claim);
-               ret = size;
-       } else if (strncmp(buf, "release", len) == 0) {
-               leds_event(led_release);
-               ret = size;
-       } else {
-               int i;
-
-               for (i = 0; i < ARRAY_SIZE(evt_names); i++) {
-                       if (strlen(evt_names[i].name) != len ||
-                           strncmp(buf, evt_names[i].name, len) != 0)
-                               continue;
-                       if (strncmp(buf+len, " on", 3) == 0) {
-                               leds_event(evt_names[i].on);
-                               ret = size;
-                       } else if (strncmp(buf+len, " off", 4) == 0) {
-                               leds_event(evt_names[i].off);
-                               ret = size;
-                       }
-                       break;
-               }
-       }
-       return ret;
-}
-
-static DEVICE_ATTR(event, 0200, NULL, leds_store);
-
-static struct bus_type leds_subsys = {
-       .name           = "leds",
-       .dev_name       = "leds",
-};
-
-static struct device leds_device = {
-       .id             = 0,
-       .bus            = &leds_subsys,
-};
-
-static int leds_suspend(void)
-{
-       leds_event(led_stop);
-       return 0;
-}
-
-static void leds_resume(void)
-{
-       leds_event(led_start);
-}
-
-static void leds_shutdown(void)
-{
-       leds_event(led_halted);
-}
-
-static struct syscore_ops leds_syscore_ops = {
-       .shutdown       = leds_shutdown,
-       .suspend        = leds_suspend,
-       .resume         = leds_resume,
-};
-
-static int __init leds_init(void)
-{
-       int ret;
-       ret = subsys_system_register(&leds_subsys, NULL);
-       if (ret == 0)
-               ret = device_register(&leds_device);
-       if (ret == 0)
-               ret = device_create_file(&leds_device, &dev_attr_event);
-       if (ret == 0)
-               register_syscore_ops(&leds_syscore_ops);
-       return ret;
-}
-
-device_initcall(leds_init);
-
-EXPORT_SYMBOL(leds_event);
index ab243b87118da54628c25b0069ecc52cc0d2f717..93971b1a4f0bb0d38eebd573f8618e994273b079 100644 (file)
  */
 #define pr_fmt(fmt) "hw perfevents: " fmt
 
-#include <linux/bitmap.h>
-#include <linux/interrupt.h>
 #include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/perf_event.h>
 #include <linux/platform_device.h>
-#include <linux/spinlock.h>
+#include <linux/pm_runtime.h>
 #include <linux/uaccess.h>
 
-#include <asm/cputype.h>
-#include <asm/irq.h>
 #include <asm/irq_regs.h>
 #include <asm/pmu.h>
 #include <asm/stacktrace.h>
 
-/*
- * ARMv6 supports a maximum of 3 events, starting from index 0. If we add
- * another platform that supports more, we need to increase this to be the
- * largest of all platforms.
- *
- * ARMv7 supports up to 32 events:
- *  cycle counter CCNT + 31 events counters CNT0..30.
- *  Cortex-A8 has 1+4 counters, Cortex-A9 has 1+6 counters.
- */
-#define ARMPMU_MAX_HWEVENTS            32
-
-static DEFINE_PER_CPU(struct perf_event * [ARMPMU_MAX_HWEVENTS], hw_events);
-static DEFINE_PER_CPU(unsigned long [BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)], used_mask);
-static DEFINE_PER_CPU(struct pmu_hw_events, cpu_hw_events);
-
-#define to_arm_pmu(p) (container_of(p, struct arm_pmu, pmu))
-
-/* Set at runtime when we know what CPU type we are. */
-static struct arm_pmu *cpu_pmu;
-
-const char *perf_pmu_name(void)
-{
-       if (!cpu_pmu)
-               return NULL;
-
-       return cpu_pmu->pmu.name;
-}
-EXPORT_SYMBOL_GPL(perf_pmu_name);
-
-int perf_num_counters(void)
-{
-       int max_events = 0;
-
-       if (cpu_pmu != NULL)
-               max_events = cpu_pmu->num_events;
-
-       return max_events;
-}
-EXPORT_SYMBOL_GPL(perf_num_counters);
-
-#define HW_OP_UNSUPPORTED              0xFFFF
-
-#define C(_x) \
-       PERF_COUNT_HW_CACHE_##_x
-
-#define CACHE_OP_UNSUPPORTED           0xFFFF
-
 static int
 armpmu_map_cache_event(const unsigned (*cache_map)
                                      [PERF_COUNT_HW_CACHE_MAX]
@@ -104,7 +51,7 @@ armpmu_map_cache_event(const unsigned (*cache_map)
 }
 
 static int
-armpmu_map_event(const unsigned (*event_map)[PERF_COUNT_HW_MAX], u64 config)
+armpmu_map_hw_event(const unsigned (*event_map)[PERF_COUNT_HW_MAX], u64 config)
 {
        int mapping = (*event_map)[config];
        return mapping == HW_OP_UNSUPPORTED ? -ENOENT : mapping;
@@ -116,19 +63,20 @@ armpmu_map_raw_event(u32 raw_event_mask, u64 config)
        return (int)(config & raw_event_mask);
 }
 
-static int map_cpu_event(struct perf_event *event,
-                        const unsigned (*event_map)[PERF_COUNT_HW_MAX],
-                        const unsigned (*cache_map)
-                                       [PERF_COUNT_HW_CACHE_MAX]
-                                       [PERF_COUNT_HW_CACHE_OP_MAX]
-                                       [PERF_COUNT_HW_CACHE_RESULT_MAX],
-                        u32 raw_event_mask)
+int
+armpmu_map_event(struct perf_event *event,
+                const unsigned (*event_map)[PERF_COUNT_HW_MAX],
+                const unsigned (*cache_map)
+                               [PERF_COUNT_HW_CACHE_MAX]
+                               [PERF_COUNT_HW_CACHE_OP_MAX]
+                               [PERF_COUNT_HW_CACHE_RESULT_MAX],
+                u32 raw_event_mask)
 {
        u64 config = event->attr.config;
 
        switch (event->attr.type) {
        case PERF_TYPE_HARDWARE:
-               return armpmu_map_event(event_map, config);
+               return armpmu_map_hw_event(event_map, config);
        case PERF_TYPE_HW_CACHE:
                return armpmu_map_cache_event(cache_map, config);
        case PERF_TYPE_RAW:
@@ -222,7 +170,6 @@ armpmu_stop(struct perf_event *event, int flags)
         */
        if (!(hwc->state & PERF_HES_STOPPED)) {
                armpmu->disable(hwc, hwc->idx);
-               barrier(); /* why? */
                armpmu_event_update(event, hwc, hwc->idx);
                hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
        }
@@ -350,99 +297,41 @@ validate_group(struct perf_event *event)
        return 0;
 }
 
-static irqreturn_t armpmu_platform_irq(int irq, void *dev)
+static irqreturn_t armpmu_dispatch_irq(int irq, void *dev)
 {
        struct arm_pmu *armpmu = (struct arm_pmu *) dev;
        struct platform_device *plat_device = armpmu->plat_device;
        struct arm_pmu_platdata *plat = dev_get_platdata(&plat_device->dev);
 
-       return plat->handle_irq(irq, dev, armpmu->handle_irq);
+       if (plat && plat->handle_irq)
+               return plat->handle_irq(irq, dev, armpmu->handle_irq);
+       else
+               return armpmu->handle_irq(irq, dev);
 }
 
 static void
 armpmu_release_hardware(struct arm_pmu *armpmu)
 {
-       int i, irq, irqs;
-       struct platform_device *pmu_device = armpmu->plat_device;
-       struct arm_pmu_platdata *plat =
-               dev_get_platdata(&pmu_device->dev);
-
-       irqs = min(pmu_device->num_resources, num_possible_cpus());
-
-       for (i = 0; i < irqs; ++i) {
-               if (!cpumask_test_and_clear_cpu(i, &armpmu->active_irqs))
-                       continue;
-               irq = platform_get_irq(pmu_device, i);
-               if (irq >= 0) {
-                       if (plat && plat->disable_irq)
-                               plat->disable_irq(irq);
-                       free_irq(irq, armpmu);
-               }
-       }
-
-       release_pmu(armpmu->type);
+       armpmu->free_irq();
+       pm_runtime_put_sync(&armpmu->plat_device->dev);
 }
 
 static int
 armpmu_reserve_hardware(struct arm_pmu *armpmu)
 {
-       struct arm_pmu_platdata *plat;
-       irq_handler_t handle_irq;
-       int i, err, irq, irqs;
+       int err;
        struct platform_device *pmu_device = armpmu->plat_device;
 
        if (!pmu_device)
                return -ENODEV;
 
-       err = reserve_pmu(armpmu->type);
+       pm_runtime_get_sync(&pmu_device->dev);
+       err = armpmu->request_irq(armpmu_dispatch_irq);
        if (err) {
-               pr_warning("unable to reserve pmu\n");
+               armpmu_release_hardware(armpmu);
                return err;
        }
 
-       plat = dev_get_platdata(&pmu_device->dev);
-       if (plat && plat->handle_irq)
-               handle_irq = armpmu_platform_irq;
-       else
-               handle_irq = armpmu->handle_irq;
-
-       irqs = min(pmu_device->num_resources, num_possible_cpus());
-       if (irqs < 1) {
-               pr_err("no irqs for PMUs defined\n");
-               return -ENODEV;
-       }
-
-       for (i = 0; i < irqs; ++i) {
-               err = 0;
-               irq = platform_get_irq(pmu_device, i);
-               if (irq < 0)
-                       continue;
-
-               /*
-                * If we have a single PMU interrupt that we can't shift,
-                * assume that we're running on a uniprocessor machine and
-                * continue. Otherwise, continue without this interrupt.
-                */
-               if (irq_set_affinity(irq, cpumask_of(i)) && irqs > 1) {
-                       pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n",
-                                   irq, i);
-                       continue;
-               }
-
-               err = request_irq(irq, handle_irq,
-                                 IRQF_DISABLED | IRQF_NOBALANCING,
-                                 "arm-pmu", armpmu);
-               if (err) {
-                       pr_err("unable to request IRQ%d for ARM PMU counters\n",
-                               irq);
-                       armpmu_release_hardware(armpmu);
-                       return err;
-               } else if (plat && plat->enable_irq)
-                       plat->enable_irq(irq);
-
-               cpumask_set_cpu(i, &armpmu->active_irqs);
-       }
-
        return 0;
 }
 
@@ -581,6 +470,32 @@ static void armpmu_disable(struct pmu *pmu)
        armpmu->stop();
 }
 
+#ifdef CONFIG_PM_RUNTIME
+static int armpmu_runtime_resume(struct device *dev)
+{
+       struct arm_pmu_platdata *plat = dev_get_platdata(dev);
+
+       if (plat && plat->runtime_resume)
+               return plat->runtime_resume(dev);
+
+       return 0;
+}
+
+static int armpmu_runtime_suspend(struct device *dev)
+{
+       struct arm_pmu_platdata *plat = dev_get_platdata(dev);
+
+       if (plat && plat->runtime_suspend)
+               return plat->runtime_suspend(dev);
+
+       return 0;
+}
+#endif
+
+const struct dev_pm_ops armpmu_dev_pm_ops = {
+       SET_RUNTIME_PM_OPS(armpmu_runtime_suspend, armpmu_runtime_resume, NULL)
+};
+
 static void __init armpmu_init(struct arm_pmu *armpmu)
 {
        atomic_set(&armpmu->active_events, 0);
@@ -598,174 +513,14 @@ static void __init armpmu_init(struct arm_pmu *armpmu)
        };
 }
 
-int __init armpmu_register(struct arm_pmu *armpmu, char *name, int type)
+int armpmu_register(struct arm_pmu *armpmu, char *name, int type)
 {
        armpmu_init(armpmu);
+       pr_info("enabled with %s PMU driver, %d counters available\n",
+                       armpmu->name, armpmu->num_events);
        return perf_pmu_register(&armpmu->pmu, name, type);
 }
 
-/* Include the PMU-specific implementations. */
-#include "perf_event_xscale.c"
-#include "perf_event_v6.c"
-#include "perf_event_v7.c"
-
-/*
- * Ensure the PMU has sane values out of reset.
- * This requires SMP to be available, so exists as a separate initcall.
- */
-static int __init
-cpu_pmu_reset(void)
-{
-       if (cpu_pmu && cpu_pmu->reset)
-               return on_each_cpu(cpu_pmu->reset, NULL, 1);
-       return 0;
-}
-arch_initcall(cpu_pmu_reset);
-
-/*
- * PMU platform driver and devicetree bindings.
- */
-static struct of_device_id armpmu_of_device_ids[] = {
-       {.compatible = "arm,cortex-a9-pmu"},
-       {.compatible = "arm,cortex-a8-pmu"},
-       {.compatible = "arm,arm1136-pmu"},
-       {.compatible = "arm,arm1176-pmu"},
-       {},
-};
-
-static struct platform_device_id armpmu_plat_device_ids[] = {
-       {.name = "arm-pmu"},
-       {},
-};
-
-static int __devinit armpmu_device_probe(struct platform_device *pdev)
-{
-       if (!cpu_pmu)
-               return -ENODEV;
-
-       cpu_pmu->plat_device = pdev;
-       return 0;
-}
-
-static struct platform_driver armpmu_driver = {
-       .driver         = {
-               .name   = "arm-pmu",
-               .of_match_table = armpmu_of_device_ids,
-       },
-       .probe          = armpmu_device_probe,
-       .id_table       = armpmu_plat_device_ids,
-};
-
-static int __init register_pmu_driver(void)
-{
-       return platform_driver_register(&armpmu_driver);
-}
-device_initcall(register_pmu_driver);
-
-static struct pmu_hw_events *armpmu_get_cpu_events(void)
-{
-       return &__get_cpu_var(cpu_hw_events);
-}
-
-static void __init cpu_pmu_init(struct arm_pmu *armpmu)
-{
-       int cpu;
-       for_each_possible_cpu(cpu) {
-               struct pmu_hw_events *events = &per_cpu(cpu_hw_events, cpu);
-               events->events = per_cpu(hw_events, cpu);
-               events->used_mask = per_cpu(used_mask, cpu);
-               raw_spin_lock_init(&events->pmu_lock);
-       }
-       armpmu->get_hw_events = armpmu_get_cpu_events;
-       armpmu->type = ARM_PMU_DEVICE_CPU;
-}
-
-/*
- * PMU hardware loses all context when a CPU goes offline.
- * When a CPU is hotplugged back in, since some hardware registers are
- * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading
- * junk values out of them.
- */
-static int __cpuinit pmu_cpu_notify(struct notifier_block *b,
-                                       unsigned long action, void *hcpu)
-{
-       if ((action & ~CPU_TASKS_FROZEN) != CPU_STARTING)
-               return NOTIFY_DONE;
-
-       if (cpu_pmu && cpu_pmu->reset)
-               cpu_pmu->reset(NULL);
-
-       return NOTIFY_OK;
-}
-
-static struct notifier_block __cpuinitdata pmu_cpu_notifier = {
-       .notifier_call = pmu_cpu_notify,
-};
-
-/*
- * CPU PMU identification and registration.
- */
-static int __init
-init_hw_perf_events(void)
-{
-       unsigned long cpuid = read_cpuid_id();
-       unsigned long implementor = (cpuid & 0xFF000000) >> 24;
-       unsigned long part_number = (cpuid & 0xFFF0);
-
-       /* ARM Ltd CPUs. */
-       if (0x41 == implementor) {
-               switch (part_number) {
-               case 0xB360:    /* ARM1136 */
-               case 0xB560:    /* ARM1156 */
-               case 0xB760:    /* ARM1176 */
-                       cpu_pmu = armv6pmu_init();
-                       break;
-               case 0xB020:    /* ARM11mpcore */
-                       cpu_pmu = armv6mpcore_pmu_init();
-                       break;
-               case 0xC080:    /* Cortex-A8 */
-                       cpu_pmu = armv7_a8_pmu_init();
-                       break;
-               case 0xC090:    /* Cortex-A9 */
-                       cpu_pmu = armv7_a9_pmu_init();
-                       break;
-               case 0xC050:    /* Cortex-A5 */
-                       cpu_pmu = armv7_a5_pmu_init();
-                       break;
-               case 0xC0F0:    /* Cortex-A15 */
-                       cpu_pmu = armv7_a15_pmu_init();
-                       break;
-               case 0xC070:    /* Cortex-A7 */
-                       cpu_pmu = armv7_a7_pmu_init();
-                       break;
-               }
-       /* Intel CPUs [xscale]. */
-       } else if (0x69 == implementor) {
-               part_number = (cpuid >> 13) & 0x7;
-               switch (part_number) {
-               case 1:
-                       cpu_pmu = xscale1pmu_init();
-                       break;
-               case 2:
-                       cpu_pmu = xscale2pmu_init();
-                       break;
-               }
-       }
-
-       if (cpu_pmu) {
-               pr_info("enabled with %s PMU driver, %d counters available\n",
-                       cpu_pmu->name, cpu_pmu->num_events);
-               cpu_pmu_init(cpu_pmu);
-               register_cpu_notifier(&pmu_cpu_notifier);
-               armpmu_register(cpu_pmu, cpu_pmu->name, PERF_TYPE_RAW);
-       } else {
-               pr_info("no hardware support available\n");
-       }
-
-       return 0;
-}
-early_initcall(init_hw_perf_events);
-
 /*
  * Callchain handling code.
  */
diff --git a/arch/arm/kernel/perf_event_cpu.c b/arch/arm/kernel/perf_event_cpu.c
new file mode 100644 (file)
index 0000000..8d7d8d4
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) 2012 ARM Limited
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ */
+#define pr_fmt(fmt) "CPU PMU: " fmt
+
+#include <linux/bitmap.h>
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+
+#include <asm/cputype.h>
+#include <asm/irq_regs.h>
+#include <asm/pmu.h>
+
+/* Set at runtime when we know what CPU type we are. */
+static struct arm_pmu *cpu_pmu;
+
+static DEFINE_PER_CPU(struct perf_event * [ARMPMU_MAX_HWEVENTS], hw_events);
+static DEFINE_PER_CPU(unsigned long [BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)], used_mask);
+static DEFINE_PER_CPU(struct pmu_hw_events, cpu_hw_events);
+
+/*
+ * Despite the names, these two functions are CPU-specific and are used
+ * by the OProfile/perf code.
+ */
+const char *perf_pmu_name(void)
+{
+       if (!cpu_pmu)
+               return NULL;
+
+       return cpu_pmu->pmu.name;
+}
+EXPORT_SYMBOL_GPL(perf_pmu_name);
+
+int perf_num_counters(void)
+{
+       int max_events = 0;
+
+       if (cpu_pmu != NULL)
+               max_events = cpu_pmu->num_events;
+
+       return max_events;
+}
+EXPORT_SYMBOL_GPL(perf_num_counters);
+
+/* Include the PMU-specific implementations. */
+#include "perf_event_xscale.c"
+#include "perf_event_v6.c"
+#include "perf_event_v7.c"
+
+static struct pmu_hw_events *cpu_pmu_get_cpu_events(void)
+{
+       return &__get_cpu_var(cpu_hw_events);
+}
+
+static void cpu_pmu_free_irq(void)
+{
+       int i, irq, irqs;
+       struct platform_device *pmu_device = cpu_pmu->plat_device;
+
+       irqs = min(pmu_device->num_resources, num_possible_cpus());
+
+       for (i = 0; i < irqs; ++i) {
+               if (!cpumask_test_and_clear_cpu(i, &cpu_pmu->active_irqs))
+                       continue;
+               irq = platform_get_irq(pmu_device, i);
+               if (irq >= 0)
+                       free_irq(irq, cpu_pmu);
+       }
+}
+
+static int cpu_pmu_request_irq(irq_handler_t handler)
+{
+       int i, err, irq, irqs;
+       struct platform_device *pmu_device = cpu_pmu->plat_device;
+
+       if (!pmu_device)
+               return -ENODEV;
+
+       irqs = min(pmu_device->num_resources, num_possible_cpus());
+       if (irqs < 1) {
+               pr_err("no irqs for PMUs defined\n");
+               return -ENODEV;
+       }
+
+       for (i = 0; i < irqs; ++i) {
+               err = 0;
+               irq = platform_get_irq(pmu_device, i);
+               if (irq < 0)
+                       continue;
+
+               /*
+                * If we have a single PMU interrupt that we can't shift,
+                * assume that we're running on a uniprocessor machine and
+                * continue. Otherwise, continue without this interrupt.
+                */
+               if (irq_set_affinity(irq, cpumask_of(i)) && irqs > 1) {
+                       pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n",
+                                   irq, i);
+                       continue;
+               }
+
+               err = request_irq(irq, handler, IRQF_NOBALANCING, "arm-pmu",
+                                 cpu_pmu);
+               if (err) {
+                       pr_err("unable to request IRQ%d for ARM PMU counters\n",
+                               irq);
+                       return err;
+               }
+
+               cpumask_set_cpu(i, &cpu_pmu->active_irqs);
+       }
+
+       return 0;
+}
+
+static void __devinit cpu_pmu_init(struct arm_pmu *cpu_pmu)
+{
+       int cpu;
+       for_each_possible_cpu(cpu) {
+               struct pmu_hw_events *events = &per_cpu(cpu_hw_events, cpu);
+               events->events = per_cpu(hw_events, cpu);
+               events->used_mask = per_cpu(used_mask, cpu);
+               raw_spin_lock_init(&events->pmu_lock);
+       }
+
+       cpu_pmu->get_hw_events  = cpu_pmu_get_cpu_events;
+       cpu_pmu->request_irq    = cpu_pmu_request_irq;
+       cpu_pmu->free_irq       = cpu_pmu_free_irq;
+
+       /* Ensure the PMU has sane values out of reset. */
+       if (cpu_pmu && cpu_pmu->reset)
+               on_each_cpu(cpu_pmu->reset, NULL, 1);
+}
+
+/*
+ * PMU hardware loses all context when a CPU goes offline.
+ * When a CPU is hotplugged back in, since some hardware registers are
+ * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading
+ * junk values out of them.
+ */
+static int __cpuinit cpu_pmu_notify(struct notifier_block *b,
+                                   unsigned long action, void *hcpu)
+{
+       if ((action & ~CPU_TASKS_FROZEN) != CPU_STARTING)
+               return NOTIFY_DONE;
+
+       if (cpu_pmu && cpu_pmu->reset)
+               cpu_pmu->reset(NULL);
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata cpu_pmu_hotplug_notifier = {
+       .notifier_call = cpu_pmu_notify,
+};
+
+/*
+ * PMU platform driver and devicetree bindings.
+ */
+static struct of_device_id __devinitdata 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},
+       {.compatible = "arm,cortex-a7-pmu",     .data = armv7_a7_pmu_init},
+       {.compatible = "arm,cortex-a5-pmu",     .data = armv7_a5_pmu_init},
+       {.compatible = "arm,arm11mpcore-pmu",   .data = armv6mpcore_pmu_init},
+       {.compatible = "arm,arm1176-pmu",       .data = armv6pmu_init},
+       {.compatible = "arm,arm1136-pmu",       .data = armv6pmu_init},
+       {},
+};
+
+static struct platform_device_id __devinitdata cpu_pmu_plat_device_ids[] = {
+       {.name = "arm-pmu"},
+       {},
+};
+
+/*
+ * CPU PMU identification and probing.
+ */
+static struct arm_pmu *__devinit probe_current_pmu(void)
+{
+       struct arm_pmu *pmu = NULL;
+       int cpu = get_cpu();
+       unsigned long cpuid = read_cpuid_id();
+       unsigned long implementor = (cpuid & 0xFF000000) >> 24;
+       unsigned long part_number = (cpuid & 0xFFF0);
+
+       pr_info("probing PMU on CPU %d\n", cpu);
+
+       /* ARM Ltd CPUs. */
+       if (0x41 == implementor) {
+               switch (part_number) {
+               case 0xB360:    /* ARM1136 */
+               case 0xB560:    /* ARM1156 */
+               case 0xB760:    /* ARM1176 */
+                       pmu = armv6pmu_init();
+                       break;
+               case 0xB020:    /* ARM11mpcore */
+                       pmu = armv6mpcore_pmu_init();
+                       break;
+               case 0xC080:    /* Cortex-A8 */
+                       pmu = armv7_a8_pmu_init();
+                       break;
+               case 0xC090:    /* Cortex-A9 */
+                       pmu = armv7_a9_pmu_init();
+                       break;
+               case 0xC050:    /* Cortex-A5 */
+                       pmu = armv7_a5_pmu_init();
+                       break;
+               case 0xC0F0:    /* Cortex-A15 */
+                       pmu = armv7_a15_pmu_init();
+                       break;
+               case 0xC070:    /* Cortex-A7 */
+                       pmu = armv7_a7_pmu_init();
+                       break;
+               }
+       /* Intel CPUs [xscale]. */
+       } else if (0x69 == implementor) {
+               part_number = (cpuid >> 13) & 0x7;
+               switch (part_number) {
+               case 1:
+                       pmu = xscale1pmu_init();
+                       break;
+               case 2:
+                       pmu = xscale2pmu_init();
+                       break;
+               }
+       }
+
+       put_cpu();
+       return pmu;
+}
+
+static int __devinit cpu_pmu_device_probe(struct platform_device *pdev)
+{
+       const struct of_device_id *of_id;
+       struct arm_pmu *(*init_fn)(void);
+       struct device_node *node = pdev->dev.of_node;
+
+       if (cpu_pmu) {
+               pr_info("attempt to register multiple PMU devices!");
+               return -ENOSPC;
+       }
+
+       if (node && (of_id = of_match_node(cpu_pmu_of_device_ids, pdev->dev.of_node))) {
+               init_fn = of_id->data;
+               cpu_pmu = init_fn();
+       } else {
+               cpu_pmu = probe_current_pmu();
+       }
+
+       if (!cpu_pmu)
+               return -ENODEV;
+
+       cpu_pmu->plat_device = pdev;
+       cpu_pmu_init(cpu_pmu);
+       register_cpu_notifier(&cpu_pmu_hotplug_notifier);
+       armpmu_register(cpu_pmu, cpu_pmu->name, PERF_TYPE_RAW);
+
+       return 0;
+}
+
+static struct platform_driver cpu_pmu_driver = {
+       .driver         = {
+               .name   = "arm-pmu",
+               .pm     = &armpmu_dev_pm_ops,
+               .of_match_table = cpu_pmu_of_device_ids,
+       },
+       .probe          = cpu_pmu_device_probe,
+       .id_table       = cpu_pmu_plat_device_ids,
+};
+
+static int __init register_pmu_driver(void)
+{
+       return platform_driver_register(&cpu_pmu_driver);
+}
+device_initcall(register_pmu_driver);
index c90fcb2b69676b1f462c5be0160de35d9b2f1b26..6ccc0797174555ebc805a1aabe0bd77941badef0 100644 (file)
@@ -645,7 +645,7 @@ armv6mpcore_pmu_disable_event(struct hw_perf_event *hwc,
 
 static int armv6_map_event(struct perf_event *event)
 {
-       return map_cpu_event(event, &armv6_perf_map,
+       return armpmu_map_event(event, &armv6_perf_map,
                                &armv6_perf_cache_map, 0xFF);
 }
 
@@ -664,7 +664,7 @@ static struct arm_pmu armv6pmu = {
        .max_period             = (1LLU << 32) - 1,
 };
 
-static struct arm_pmu *__init armv6pmu_init(void)
+static struct arm_pmu *__devinit armv6pmu_init(void)
 {
        return &armv6pmu;
 }
@@ -679,7 +679,7 @@ static struct arm_pmu *__init armv6pmu_init(void)
 
 static int armv6mpcore_map_event(struct perf_event *event)
 {
-       return map_cpu_event(event, &armv6mpcore_perf_map,
+       return armpmu_map_event(event, &armv6mpcore_perf_map,
                                &armv6mpcore_perf_cache_map, 0xFF);
 }
 
@@ -698,17 +698,17 @@ static struct arm_pmu armv6mpcore_pmu = {
        .max_period             = (1LLU << 32) - 1,
 };
 
-static struct arm_pmu *__init armv6mpcore_pmu_init(void)
+static struct arm_pmu *__devinit armv6mpcore_pmu_init(void)
 {
        return &armv6mpcore_pmu;
 }
 #else
-static struct arm_pmu *__init armv6pmu_init(void)
+static struct arm_pmu *__devinit armv6pmu_init(void)
 {
        return NULL;
 }
 
-static struct arm_pmu *__init armv6mpcore_pmu_init(void)
+static struct arm_pmu *__devinit armv6mpcore_pmu_init(void)
 {
        return NULL;
 }
index f04070bd21838dd9146d694066d756d2bb1e753a..bd4b090ebcfd8e2b6132a5d2e52a9eb890a34ea9 100644 (file)
@@ -1204,31 +1204,31 @@ static void armv7pmu_reset(void *info)
 
 static int armv7_a8_map_event(struct perf_event *event)
 {
-       return map_cpu_event(event, &armv7_a8_perf_map,
+       return armpmu_map_event(event, &armv7_a8_perf_map,
                                &armv7_a8_perf_cache_map, 0xFF);
 }
 
 static int armv7_a9_map_event(struct perf_event *event)
 {
-       return map_cpu_event(event, &armv7_a9_perf_map,
+       return armpmu_map_event(event, &armv7_a9_perf_map,
                                &armv7_a9_perf_cache_map, 0xFF);
 }
 
 static int armv7_a5_map_event(struct perf_event *event)
 {
-       return map_cpu_event(event, &armv7_a5_perf_map,
+       return armpmu_map_event(event, &armv7_a5_perf_map,
                                &armv7_a5_perf_cache_map, 0xFF);
 }
 
 static int armv7_a15_map_event(struct perf_event *event)
 {
-       return map_cpu_event(event, &armv7_a15_perf_map,
+       return armpmu_map_event(event, &armv7_a15_perf_map,
                                &armv7_a15_perf_cache_map, 0xFF);
 }
 
 static int armv7_a7_map_event(struct perf_event *event)
 {
-       return map_cpu_event(event, &armv7_a7_perf_map,
+       return armpmu_map_event(event, &armv7_a7_perf_map,
                                &armv7_a7_perf_cache_map, 0xFF);
 }
 
@@ -1245,7 +1245,7 @@ static struct arm_pmu armv7pmu = {
        .max_period             = (1LLU << 32) - 1,
 };
 
-static u32 __init armv7_read_num_pmnc_events(void)
+static u32 __devinit armv7_read_num_pmnc_events(void)
 {
        u32 nb_cnt;
 
@@ -1256,7 +1256,7 @@ static u32 __init armv7_read_num_pmnc_events(void)
        return nb_cnt + 1;
 }
 
-static struct arm_pmu *__init armv7_a8_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a8_pmu_init(void)
 {
        armv7pmu.name           = "ARMv7 Cortex-A8";
        armv7pmu.map_event      = armv7_a8_map_event;
@@ -1264,7 +1264,7 @@ static struct arm_pmu *__init armv7_a8_pmu_init(void)
        return &armv7pmu;
 }
 
-static struct arm_pmu *__init armv7_a9_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a9_pmu_init(void)
 {
        armv7pmu.name           = "ARMv7 Cortex-A9";
        armv7pmu.map_event      = armv7_a9_map_event;
@@ -1272,7 +1272,7 @@ static struct arm_pmu *__init armv7_a9_pmu_init(void)
        return &armv7pmu;
 }
 
-static struct arm_pmu *__init armv7_a5_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a5_pmu_init(void)
 {
        armv7pmu.name           = "ARMv7 Cortex-A5";
        armv7pmu.map_event      = armv7_a5_map_event;
@@ -1280,7 +1280,7 @@ static struct arm_pmu *__init armv7_a5_pmu_init(void)
        return &armv7pmu;
 }
 
-static struct arm_pmu *__init armv7_a15_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a15_pmu_init(void)
 {
        armv7pmu.name           = "ARMv7 Cortex-A15";
        armv7pmu.map_event      = armv7_a15_map_event;
@@ -1289,7 +1289,7 @@ static struct arm_pmu *__init armv7_a15_pmu_init(void)
        return &armv7pmu;
 }
 
-static struct arm_pmu *__init armv7_a7_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a7_pmu_init(void)
 {
        armv7pmu.name           = "ARMv7 Cortex-A7";
        armv7pmu.map_event      = armv7_a7_map_event;
@@ -1298,27 +1298,27 @@ static struct arm_pmu *__init armv7_a7_pmu_init(void)
        return &armv7pmu;
 }
 #else
-static struct arm_pmu *__init armv7_a8_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a8_pmu_init(void)
 {
        return NULL;
 }
 
-static struct arm_pmu *__init armv7_a9_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a9_pmu_init(void)
 {
        return NULL;
 }
 
-static struct arm_pmu *__init armv7_a5_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a5_pmu_init(void)
 {
        return NULL;
 }
 
-static struct arm_pmu *__init armv7_a15_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a15_pmu_init(void)
 {
        return NULL;
 }
 
-static struct arm_pmu *__init armv7_a7_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a7_pmu_init(void)
 {
        return NULL;
 }
index f759fe0bab632303b34484001ca2b6a9e91452f1..426e19f380a2f935b7b1c9706a6c50613ce4e272 100644 (file)
@@ -430,7 +430,7 @@ xscale1pmu_write_counter(int counter, u32 val)
 
 static int xscale_map_event(struct perf_event *event)
 {
-       return map_cpu_event(event, &xscale_perf_map,
+       return armpmu_map_event(event, &xscale_perf_map,
                                &xscale_perf_cache_map, 0xFF);
 }
 
@@ -449,7 +449,7 @@ static struct arm_pmu xscale1pmu = {
        .max_period     = (1LLU << 32) - 1,
 };
 
-static struct arm_pmu *__init xscale1pmu_init(void)
+static struct arm_pmu *__devinit xscale1pmu_init(void)
 {
        return &xscale1pmu;
 }
@@ -816,17 +816,17 @@ static struct arm_pmu xscale2pmu = {
        .max_period     = (1LLU << 32) - 1,
 };
 
-static struct arm_pmu *__init xscale2pmu_init(void)
+static struct arm_pmu *__devinit xscale2pmu_init(void)
 {
        return &xscale2pmu;
 }
 #else
-static struct arm_pmu *__init xscale1pmu_init(void)
+static struct arm_pmu *__devinit xscale1pmu_init(void)
 {
        return NULL;
 }
 
-static struct arm_pmu *__init xscale2pmu_init(void)
+static struct arm_pmu *__devinit xscale2pmu_init(void)
 {
        return NULL;
 }
diff --git a/arch/arm/kernel/pmu.c b/arch/arm/kernel/pmu.c
deleted file mode 100644 (file)
index 2334bf8..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- *  linux/arch/arm/kernel/pmu.c
- *
- *  Copyright (C) 2009 picoChip Designs Ltd, Jamie Iles
- *  Copyright (C) 2010 ARM Ltd, Will Deacon
- *
- * 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/err.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-
-#include <asm/pmu.h>
-
-/*
- * PMU locking to ensure mutual exclusion between different subsystems.
- */
-static unsigned long pmu_lock[BITS_TO_LONGS(ARM_NUM_PMU_DEVICES)];
-
-int
-reserve_pmu(enum arm_pmu_type type)
-{
-       return test_and_set_bit_lock(type, pmu_lock) ? -EBUSY : 0;
-}
-EXPORT_SYMBOL_GPL(reserve_pmu);
-
-void
-release_pmu(enum arm_pmu_type type)
-{
-       clear_bit_unlock(type, pmu_lock);
-}
-EXPORT_SYMBOL_GPL(release_pmu);
index 693b744fd572f163f053c9fef42d563e246e04d3..04eea22d7958637f17456c7e2f37ac7b71e8e182 100644 (file)
@@ -31,9 +31,9 @@
 #include <linux/random.h>
 #include <linux/hw_breakpoint.h>
 #include <linux/cpuidle.h>
+#include <linux/leds.h>
 
 #include <asm/cacheflush.h>
-#include <asm/leds.h>
 #include <asm/processor.h>
 #include <asm/thread_notify.h>
 #include <asm/stacktrace.h>
@@ -189,7 +189,7 @@ void cpu_idle(void)
        while (1) {
                tick_nohz_idle_enter();
                rcu_idle_enter();
-               leds_event(led_idle_start);
+               ledtrig_cpu(CPU_LED_IDLE_START);
                while (!need_resched()) {
 #ifdef CONFIG_HOTPLUG_CPU
                        if (cpu_is_offline(smp_processor_id()))
@@ -220,7 +220,7 @@ void cpu_idle(void)
                        } else
                                local_irq_enable();
                }
-               leds_event(led_idle_end);
+               ledtrig_cpu(CPU_LED_IDLE_END);
                rcu_idle_exit();
                tick_nohz_idle_exit();
                schedule_preempt_disabled();
index 27d186abbc06f8aa3aa6310faa5b67039d447f03..f4515393248dab76b97700f55ef17bba68e6cd0a 100644 (file)
@@ -21,6 +21,8 @@ struct clock_data {
        u32 epoch_cyc_copy;
        u32 mult;
        u32 shift;
+       bool suspended;
+       bool needs_suspend;
 };
 
 static void sched_clock_poll(unsigned long wrap_ticks);
@@ -49,6 +51,9 @@ static unsigned long long cyc_to_sched_clock(u32 cyc, u32 mask)
        u64 epoch_ns;
        u32 epoch_cyc;
 
+       if (cd.suspended)
+               return cd.epoch_ns;
+
        /*
         * Load the epoch_cyc and epoch_ns atomically.  We do this by
         * ensuring that we always write epoch_cyc, epoch_ns and
@@ -98,6 +103,13 @@ static void sched_clock_poll(unsigned long wrap_ticks)
        update_sched_clock();
 }
 
+void __init setup_sched_clock_needs_suspend(u32 (*read)(void), int bits,
+               unsigned long rate)
+{
+       setup_sched_clock(read, bits, rate);
+       cd.needs_suspend = true;
+}
+
 void __init setup_sched_clock(u32 (*read)(void), int bits, unsigned long rate)
 {
        unsigned long r, w;
@@ -169,11 +181,23 @@ void __init sched_clock_postinit(void)
 static int sched_clock_suspend(void)
 {
        sched_clock_poll(sched_clock_timer.data);
+       if (cd.needs_suspend)
+               cd.suspended = true;
        return 0;
 }
 
+static void sched_clock_resume(void)
+{
+       if (cd.needs_suspend) {
+               cd.epoch_cyc = read_sched_clock();
+               cd.epoch_cyc_copy = cd.epoch_cyc;
+               cd.suspended = false;
+       }
+}
+
 static struct syscore_ops sched_clock_ops = {
        .suspend = sched_clock_suspend,
+       .resume = sched_clock_resume,
 };
 
 static int __init sched_clock_syscore_init(void)
index af2afb019672afdb5d3654f12c799f69799a1dbc..09be0c3c906965822d206b4268a97fbe275bc5f8 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/timer.h>
 #include <linux/irq.h>
 
-#include <asm/leds.h>
 #include <asm/thread_info.h>
 #include <asm/sched_clock.h>
 #include <asm/stacktrace.h>
@@ -80,21 +79,6 @@ u32 arch_gettimeoffset(void)
 }
 #endif /* CONFIG_ARCH_USES_GETTIMEOFFSET */
 
-#ifdef CONFIG_LEDS_TIMER
-static inline void do_leds(void)
-{
-       static unsigned int count = HZ/2;
-
-       if (--count == 0) {
-               count = HZ/2;
-               leds_event(led_timer);
-       }
-}
-#else
-#define        do_leds()
-#endif
-
-
 #ifndef CONFIG_GENERIC_CLOCKEVENTS
 /*
  * Kernel system timer support.
@@ -102,7 +86,6 @@ static inline void do_leds(void)
 void timer_tick(void)
 {
        profile_tick(CPU_PROFILING);
-       do_leds();
        xtime_update(1);
 #ifndef CONFIG_SMP
        update_process_times(user_mode(get_irq_regs()));
index 198b08456e905e42d1c09819083c003d9a59e988..26c12c6440fcde02a3829f1ed3e1035f16ed6338 100644 (file)
@@ -321,7 +321,7 @@ void store_cpu_topology(unsigned int cpuid)
  * init_cpu_topology is called at boot when only one cpu is running
  * which prevent simultaneous write access to cpu_topology array
  */
-void init_cpu_topology(void)
+void __init init_cpu_topology(void)
 {
        unsigned int cpu;
 
index 2473fd1fd51cfa50ef02985e6e8d83c5f97119c8..af72969820b4951448c9d95135383ae9d8387cde 100644 (file)
@@ -16,13 +16,30 @@ lib-y               := backtrace.o changebit.o csumipv6.o csumpartial.o   \
                   call_with_stack.o
 
 mmu-y  := clear_user.o copy_page.o getuser.o putuser.o
-mmu-y  += copy_from_user.o copy_to_user.o
+
+# the code in uaccess.S is not preemption safe and
+# probably faster on ARMv3 only
+ifeq ($(CONFIG_PREEMPT),y)
+  mmu-y        += copy_from_user.o copy_to_user.o
+else
+ifneq ($(CONFIG_CPU_32v3),y)
+  mmu-y        += copy_from_user.o copy_to_user.o
+else
+  mmu-y        += uaccess.o
+endif
+endif
 
 # using lib_ here won't override already available weak symbols
 obj-$(CONFIG_UACCESS_WITH_MEMCPY) += uaccess_with_memcpy.o
 
-lib-$(CONFIG_MMU)              += $(mmu-y)
-lib-y                          += io-readsw-armv4.o io-writesw-armv4.o
+lib-$(CONFIG_MMU) += $(mmu-y)
+
+ifeq ($(CONFIG_CPU_32v3),y)
+  lib-y        += io-readsw-armv3.o io-writesw-armv3.o
+else
+  lib-y        += io-readsw-armv4.o io-writesw-armv4.o
+endif
+
 lib-$(CONFIG_ARCH_RPC)         += ecard.o io-acorn.o floppydma.o
 lib-$(CONFIG_ARCH_SHARK)       += io-shark.o
 
diff --git a/arch/arm/lib/io-readsw-armv3.S b/arch/arm/lib/io-readsw-armv3.S
new file mode 100644 (file)
index 0000000..88487c8
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ *  linux/arch/arm/lib/io-readsw-armv3.S
+ *
+ *  Copyright (C) 1995-2000 Russell King
+ *
+ * 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/linkage.h>
+#include <asm/assembler.h>
+
+.Linsw_bad_alignment:
+               adr     r0, .Linsw_bad_align_msg
+               mov     r2, lr
+               b       panic
+.Linsw_bad_align_msg:
+               .asciz  "insw: bad buffer alignment (0x%p, lr=0x%08lX)\n"
+               .align
+
+.Linsw_align:  tst     r1, #1
+               bne     .Linsw_bad_alignment
+
+               ldr     r3, [r0]
+               strb    r3, [r1], #1
+               mov     r3, r3, lsr #8
+               strb    r3, [r1], #1
+
+               subs    r2, r2, #1
+               moveq   pc, lr
+
+ENTRY(__raw_readsw)
+               teq     r2, #0          @ do we have to check for the zero len?
+               moveq   pc, lr
+               tst     r1, #3
+               bne     .Linsw_align
+
+.Linsw_aligned:        mov     ip, #0xff
+               orr     ip, ip, ip, lsl #8
+               stmfd   sp!, {r4, r5, r6, lr}
+
+               subs    r2, r2, #8
+               bmi     .Lno_insw_8
+
+.Linsw_8_lp:   ldr     r3, [r0]
+               and     r3, r3, ip
+               ldr     r4, [r0]
+               orr     r3, r3, r4, lsl #16
+
+               ldr     r4, [r0]
+               and     r4, r4, ip
+               ldr     r5, [r0]
+               orr     r4, r4, r5, lsl #16
+
+               ldr     r5, [r0]
+               and     r5, r5, ip
+               ldr     r6, [r0]
+               orr     r5, r5, r6, lsl #16
+
+               ldr     r6, [r0]
+               and     r6, r6, ip
+               ldr     lr, [r0]
+               orr     r6, r6, lr, lsl #16
+
+               stmia   r1!, {r3 - r6}
+
+               subs    r2, r2, #8
+               bpl     .Linsw_8_lp
+
+               tst     r2, #7
+               ldmeqfd sp!, {r4, r5, r6, pc}
+
+.Lno_insw_8:   tst     r2, #4
+               beq     .Lno_insw_4
+
+               ldr     r3, [r0]
+               and     r3, r3, ip
+               ldr     r4, [r0]
+               orr     r3, r3, r4, lsl #16
+
+               ldr     r4, [r0]
+               and     r4, r4, ip
+               ldr     r5, [r0]
+               orr     r4, r4, r5, lsl #16
+
+               stmia   r1!, {r3, r4}
+
+.Lno_insw_4:   tst     r2, #2
+               beq     .Lno_insw_2
+
+               ldr     r3, [r0]
+               and     r3, r3, ip
+               ldr     r4, [r0]
+               orr     r3, r3, r4, lsl #16
+
+               str     r3, [r1], #4
+
+.Lno_insw_2:   tst     r2, #1
+               ldrne   r3, [r0]
+               strneb  r3, [r1], #1
+               movne   r3, r3, lsr #8
+               strneb  r3, [r1]
+
+               ldmfd   sp!, {r4, r5, r6, pc}
+
+
diff --git a/arch/arm/lib/io-writesw-armv3.S b/arch/arm/lib/io-writesw-armv3.S
new file mode 100644 (file)
index 0000000..49b8004
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ *  linux/arch/arm/lib/io-writesw-armv3.S
+ *
+ *  Copyright (C) 1995-2000 Russell King
+ *
+ * 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/linkage.h>
+#include <asm/assembler.h>
+
+.Loutsw_bad_alignment:
+               adr     r0, .Loutsw_bad_align_msg
+               mov     r2, lr
+               b       panic
+.Loutsw_bad_align_msg:
+               .asciz  "outsw: bad buffer alignment (0x%p, lr=0x%08lX)\n"
+               .align
+
+.Loutsw_align: tst     r1, #1
+               bne     .Loutsw_bad_alignment
+
+               add     r1, r1, #2
+
+               ldr     r3, [r1, #-4]
+               mov     r3, r3, lsr #16
+               orr     r3, r3, r3, lsl #16
+               str     r3, [r0]
+               subs    r2, r2, #1
+               moveq   pc, lr
+
+ENTRY(__raw_writesw)
+               teq     r2, #0          @ do we have to check for the zero len?
+               moveq   pc, lr
+               tst     r1, #3
+               bne     .Loutsw_align
+
+               stmfd   sp!, {r4, r5, r6, lr}
+
+               subs    r2, r2, #8
+               bmi     .Lno_outsw_8
+
+.Loutsw_8_lp:  ldmia   r1!, {r3, r4, r5, r6}
+
+               mov     ip, r3, lsl #16
+               orr     ip, ip, ip, lsr #16
+               str     ip, [r0]
+
+               mov     ip, r3, lsr #16
+               orr     ip, ip, ip, lsl #16
+               str     ip, [r0]
+
+               mov     ip, r4, lsl #16
+               orr     ip, ip, ip, lsr #16
+               str     ip, [r0]
+
+               mov     ip, r4, lsr #16
+               orr     ip, ip, ip, lsl #16
+               str     ip, [r0]
+
+               mov     ip, r5, lsl #16
+               orr     ip, ip, ip, lsr #16
+               str     ip, [r0]
+
+               mov     ip, r5, lsr #16
+               orr     ip, ip, ip, lsl #16
+               str     ip, [r0]
+
+               mov     ip, r6, lsl #16
+               orr     ip, ip, ip, lsr #16
+               str     ip, [r0]
+
+               mov     ip, r6, lsr #16
+               orr     ip, ip, ip, lsl #16
+               str     ip, [r0]
+
+               subs    r2, r2, #8
+               bpl     .Loutsw_8_lp
+
+               tst     r2, #7
+               ldmeqfd sp!, {r4, r5, r6, pc}
+
+.Lno_outsw_8:  tst     r2, #4
+               beq     .Lno_outsw_4
+
+               ldmia   r1!, {r3, r4}
+
+               mov     ip, r3, lsl #16
+               orr     ip, ip, ip, lsr #16
+               str     ip, [r0]
+
+               mov     ip, r3, lsr #16
+               orr     ip, ip, ip, lsl #16
+               str     ip, [r0]
+
+               mov     ip, r4, lsl #16
+               orr     ip, ip, ip, lsr #16
+               str     ip, [r0]
+
+               mov     ip, r4, lsr #16
+               orr     ip, ip, ip, lsl #16
+               str     ip, [r0]
+
+.Lno_outsw_4:  tst     r2, #2
+               beq     .Lno_outsw_2
+
+               ldr     r3, [r1], #4
+
+               mov     ip, r3, lsl #16
+               orr     ip, ip, ip, lsr #16
+               str     ip, [r0]
+
+               mov     ip, r3, lsr #16
+               orr     ip, ip, ip, lsl #16
+               str     ip, [r0]
+
+.Lno_outsw_2:  tst     r2, #1
+
+               ldrne   r3, [r1]
+
+               movne   ip, r3, lsl #16
+               orrne   ip, ip, ip, lsr #16
+               strne   ip, [r0]
+
+               ldmfd   sp!, {r4, r5, r6, pc}
diff --git a/arch/arm/lib/uaccess.S b/arch/arm/lib/uaccess.S
new file mode 100644 (file)
index 0000000..5c908b1
--- /dev/null
@@ -0,0 +1,564 @@
+/*
+ *  linux/arch/arm/lib/uaccess.S
+ *
+ *  Copyright (C) 1995, 1996,1997,1998 Russell King
+ *
+ * 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.
+ *
+ *  Routines to block copy data to/from user memory
+ *   These are highly optimised both for the 4k page size
+ *   and for various alignments.
+ */
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/errno.h>
+#include <asm/domain.h>
+
+               .text
+
+#define PAGE_SHIFT 12
+
+/* Prototype: int __copy_to_user(void *to, const char *from, size_t n)
+ * Purpose  : copy a block to user memory from kernel memory
+ * Params   : to   - user memory
+ *          : from - kernel memory
+ *          : n    - number of bytes to copy
+ * Returns  : Number of bytes NOT copied.
+ */
+
+.Lc2u_dest_not_aligned:
+               rsb     ip, ip, #4
+               cmp     ip, #2
+               ldrb    r3, [r1], #1
+USER(  TUSER(  strb)   r3, [r0], #1)                   @ May fault
+               ldrgeb  r3, [r1], #1
+USER(  TUSER(  strgeb) r3, [r0], #1)                   @ May fault
+               ldrgtb  r3, [r1], #1
+USER(  TUSER(  strgtb) r3, [r0], #1)                   @ May fault
+               sub     r2, r2, ip
+               b       .Lc2u_dest_aligned
+
+ENTRY(__copy_to_user)
+               stmfd   sp!, {r2, r4 - r7, lr}
+               cmp     r2, #4
+               blt     .Lc2u_not_enough
+               ands    ip, r0, #3
+               bne     .Lc2u_dest_not_aligned
+.Lc2u_dest_aligned:
+
+               ands    ip, r1, #3
+               bne     .Lc2u_src_not_aligned
+/*
+ * Seeing as there has to be at least 8 bytes to copy, we can
+ * copy one word, and force a user-mode page fault...
+ */
+
+.Lc2u_0fupi:   subs    r2, r2, #4
+               addmi   ip, r2, #4
+               bmi     .Lc2u_0nowords
+               ldr     r3, [r1], #4
+USER(  TUSER(  str)    r3, [r0], #4)                   @ May fault
+               mov     ip, r0, lsl #32 - PAGE_SHIFT    @ On each page, use a ld/st??t instruction
+               rsb     ip, ip, #0
+               movs    ip, ip, lsr #32 - PAGE_SHIFT
+               beq     .Lc2u_0fupi
+/*
+ * ip = max no. of bytes to copy before needing another "strt" insn
+ */
+               cmp     r2, ip
+               movlt   ip, r2
+               sub     r2, r2, ip
+               subs    ip, ip, #32
+               blt     .Lc2u_0rem8lp
+
+.Lc2u_0cpy8lp: ldmia   r1!, {r3 - r6}
+               stmia   r0!, {r3 - r6}                  @ Shouldnt fault
+               ldmia   r1!, {r3 - r6}
+               subs    ip, ip, #32
+               stmia   r0!, {r3 - r6}                  @ Shouldnt fault
+               bpl     .Lc2u_0cpy8lp
+
+.Lc2u_0rem8lp: cmn     ip, #16
+               ldmgeia r1!, {r3 - r6}
+               stmgeia r0!, {r3 - r6}                  @ Shouldnt fault
+               tst     ip, #8
+               ldmneia r1!, {r3 - r4}
+               stmneia r0!, {r3 - r4}                  @ Shouldnt fault
+               tst     ip, #4
+               ldrne   r3, [r1], #4
+       TUSER(  strne) r3, [r0], #4                     @ Shouldnt fault
+               ands    ip, ip, #3
+               beq     .Lc2u_0fupi
+.Lc2u_0nowords:        teq     ip, #0
+               beq     .Lc2u_finished
+.Lc2u_nowords: cmp     ip, #2
+               ldrb    r3, [r1], #1
+USER(  TUSER(  strb)   r3, [r0], #1)                   @ May fault
+               ldrgeb  r3, [r1], #1
+USER(  TUSER(  strgeb) r3, [r0], #1)                   @ May fault
+               ldrgtb  r3, [r1], #1
+USER(  TUSER(  strgtb) r3, [r0], #1)                   @ May fault
+               b       .Lc2u_finished
+
+.Lc2u_not_enough:
+               movs    ip, r2
+               bne     .Lc2u_nowords
+.Lc2u_finished:        mov     r0, #0
+               ldmfd   sp!, {r2, r4 - r7, pc}
+
+.Lc2u_src_not_aligned:
+               bic     r1, r1, #3
+               ldr     r7, [r1], #4
+               cmp     ip, #2
+               bgt     .Lc2u_3fupi
+               beq     .Lc2u_2fupi
+.Lc2u_1fupi:   subs    r2, r2, #4
+               addmi   ip, r2, #4
+               bmi     .Lc2u_1nowords
+               mov     r3, r7, pull #8
+               ldr     r7, [r1], #4
+               orr     r3, r3, r7, push #24
+USER(  TUSER(  str)    r3, [r0], #4)                   @ May fault
+               mov     ip, r0, lsl #32 - PAGE_SHIFT
+               rsb     ip, ip, #0
+               movs    ip, ip, lsr #32 - PAGE_SHIFT
+               beq     .Lc2u_1fupi
+               cmp     r2, ip
+               movlt   ip, r2
+               sub     r2, r2, ip
+               subs    ip, ip, #16
+               blt     .Lc2u_1rem8lp
+
+.Lc2u_1cpy8lp: mov     r3, r7, pull #8
+               ldmia   r1!, {r4 - r7}
+               subs    ip, ip, #16
+               orr     r3, r3, r4, push #24
+               mov     r4, r4, pull #8
+               orr     r4, r4, r5, push #24
+               mov     r5, r5, pull #8
+               orr     r5, r5, r6, push #24
+               mov     r6, r6, pull #8
+               orr     r6, r6, r7, push #24
+               stmia   r0!, {r3 - r6}                  @ Shouldnt fault
+               bpl     .Lc2u_1cpy8lp
+
+.Lc2u_1rem8lp: tst     ip, #8
+               movne   r3, r7, pull #8
+               ldmneia r1!, {r4, r7}
+               orrne   r3, r3, r4, push #24
+               movne   r4, r4, pull #8
+               orrne   r4, r4, r7, push #24
+               stmneia r0!, {r3 - r4}                  @ Shouldnt fault
+               tst     ip, #4
+               movne   r3, r7, pull #8
+               ldrne   r7, [r1], #4
+               orrne   r3, r3, r7, push #24
+       TUSER(  strne) r3, [r0], #4                     @ Shouldnt fault
+               ands    ip, ip, #3
+               beq     .Lc2u_1fupi
+.Lc2u_1nowords:        mov     r3, r7, get_byte_1
+               teq     ip, #0
+               beq     .Lc2u_finished
+               cmp     ip, #2
+USER(  TUSER(  strb)   r3, [r0], #1)                   @ May fault
+               movge   r3, r7, get_byte_2
+USER(  TUSER(  strgeb) r3, [r0], #1)                   @ May fault
+               movgt   r3, r7, get_byte_3
+USER(  TUSER(  strgtb) r3, [r0], #1)                   @ May fault
+               b       .Lc2u_finished
+
+.Lc2u_2fupi:   subs    r2, r2, #4
+               addmi   ip, r2, #4
+               bmi     .Lc2u_2nowords
+               mov     r3, r7, pull #16
+               ldr     r7, [r1], #4
+               orr     r3, r3, r7, push #16
+USER(  TUSER(  str)    r3, [r0], #4)                   @ May fault
+               mov     ip, r0, lsl #32 - PAGE_SHIFT
+               rsb     ip, ip, #0
+               movs    ip, ip, lsr #32 - PAGE_SHIFT
+               beq     .Lc2u_2fupi
+               cmp     r2, ip
+               movlt   ip, r2
+               sub     r2, r2, ip
+               subs    ip, ip, #16
+               blt     .Lc2u_2rem8lp
+
+.Lc2u_2cpy8lp: mov     r3, r7, pull #16
+               ldmia   r1!, {r4 - r7}
+               subs    ip, ip, #16
+               orr     r3, r3, r4, push #16
+               mov     r4, r4, pull #16
+               orr     r4, r4, r5, push #16
+               mov     r5, r5, pull #16
+               orr     r5, r5, r6, push #16
+               mov     r6, r6, pull #16
+               orr     r6, r6, r7, push #16
+               stmia   r0!, {r3 - r6}                  @ Shouldnt fault
+               bpl     .Lc2u_2cpy8lp
+
+.Lc2u_2rem8lp: tst     ip, #8
+               movne   r3, r7, pull #16
+               ldmneia r1!, {r4, r7}
+               orrne   r3, r3, r4, push #16
+               movne   r4, r4, pull #16
+               orrne   r4, r4, r7, push #16
+               stmneia r0!, {r3 - r4}                  @ Shouldnt fault
+               tst     ip, #4
+               movne   r3, r7, pull #16
+               ldrne   r7, [r1], #4
+               orrne   r3, r3, r7, push #16
+       TUSER(  strne) r3, [r0], #4                     @ Shouldnt fault
+               ands    ip, ip, #3
+               beq     .Lc2u_2fupi
+.Lc2u_2nowords:        mov     r3, r7, get_byte_2
+               teq     ip, #0
+               beq     .Lc2u_finished
+               cmp     ip, #2
+USER(  TUSER(  strb)   r3, [r0], #1)                   @ May fault
+               movge   r3, r7, get_byte_3
+USER(  TUSER(  strgeb) r3, [r0], #1)                   @ May fault
+               ldrgtb  r3, [r1], #0
+USER(  TUSER(  strgtb) r3, [r0], #1)                   @ May fault
+               b       .Lc2u_finished
+
+.Lc2u_3fupi:   subs    r2, r2, #4
+               addmi   ip, r2, #4
+               bmi     .Lc2u_3nowords
+               mov     r3, r7, pull #24
+               ldr     r7, [r1], #4
+               orr     r3, r3, r7, push #8
+USER(  TUSER(  str)    r3, [r0], #4)                   @ May fault
+               mov     ip, r0, lsl #32 - PAGE_SHIFT
+               rsb     ip, ip, #0
+               movs    ip, ip, lsr #32 - PAGE_SHIFT
+               beq     .Lc2u_3fupi
+               cmp     r2, ip
+               movlt   ip, r2
+               sub     r2, r2, ip
+               subs    ip, ip, #16
+               blt     .Lc2u_3rem8lp
+
+.Lc2u_3cpy8lp: mov     r3, r7, pull #24
+               ldmia   r1!, {r4 - r7}
+               subs    ip, ip, #16
+               orr     r3, r3, r4, push #8
+               mov     r4, r4, pull #24
+               orr     r4, r4, r5, push #8
+               mov     r5, r5, pull #24
+               orr     r5, r5, r6, push #8
+               mov     r6, r6, pull #24
+               orr     r6, r6, r7, push #8
+               stmia   r0!, {r3 - r6}                  @ Shouldnt fault
+               bpl     .Lc2u_3cpy8lp
+
+.Lc2u_3rem8lp: tst     ip, #8
+               movne   r3, r7, pull #24
+               ldmneia r1!, {r4, r7}
+               orrne   r3, r3, r4, push #8
+               movne   r4, r4, pull #24
+               orrne   r4, r4, r7, push #8
+               stmneia r0!, {r3 - r4}                  @ Shouldnt fault
+               tst     ip, #4
+               movne   r3, r7, pull #24
+               ldrne   r7, [r1], #4
+               orrne   r3, r3, r7, push #8
+       TUSER(  strne) r3, [r0], #4                     @ Shouldnt fault
+               ands    ip, ip, #3
+               beq     .Lc2u_3fupi
+.Lc2u_3nowords:        mov     r3, r7, get_byte_3
+               teq     ip, #0
+               beq     .Lc2u_finished
+               cmp     ip, #2
+USER(  TUSER(  strb)   r3, [r0], #1)                   @ May fault
+               ldrgeb  r3, [r1], #1
+USER(  TUSER(  strgeb) r3, [r0], #1)                   @ May fault
+               ldrgtb  r3, [r1], #0
+USER(  TUSER(  strgtb) r3, [r0], #1)                   @ May fault
+               b       .Lc2u_finished
+ENDPROC(__copy_to_user)
+
+               .pushsection .fixup,"ax"
+               .align  0
+9001:          ldmfd   sp!, {r0, r4 - r7, pc}
+               .popsection
+
+/* Prototype: unsigned long __copy_from_user(void *to,const void *from,unsigned long n);
+ * Purpose  : copy a block from user memory to kernel memory
+ * Params   : to   - kernel memory
+ *          : from - user memory
+ *          : n    - number of bytes to copy
+ * Returns  : Number of bytes NOT copied.
+ */
+.Lcfu_dest_not_aligned:
+               rsb     ip, ip, #4
+               cmp     ip, #2
+USER(  TUSER(  ldrb)   r3, [r1], #1)                   @ May fault
+               strb    r3, [r0], #1
+USER(  TUSER(  ldrgeb) r3, [r1], #1)                   @ May fault
+               strgeb  r3, [r0], #1
+USER(  TUSER(  ldrgtb) r3, [r1], #1)                   @ May fault
+               strgtb  r3, [r0], #1
+               sub     r2, r2, ip
+               b       .Lcfu_dest_aligned
+
+ENTRY(__copy_from_user)
+               stmfd   sp!, {r0, r2, r4 - r7, lr}
+               cmp     r2, #4
+               blt     .Lcfu_not_enough
+               ands    ip, r0, #3
+               bne     .Lcfu_dest_not_aligned
+.Lcfu_dest_aligned:
+               ands    ip, r1, #3
+               bne     .Lcfu_src_not_aligned
+
+/*
+ * Seeing as there has to be at least 8 bytes to copy, we can
+ * copy one word, and force a user-mode page fault...
+ */
+
+.Lcfu_0fupi:   subs    r2, r2, #4
+               addmi   ip, r2, #4
+               bmi     .Lcfu_0nowords
+USER(  TUSER(  ldr)    r3, [r1], #4)
+               str     r3, [r0], #4
+               mov     ip, r1, lsl #32 - PAGE_SHIFT    @ On each page, use a ld/st??t instruction
+               rsb     ip, ip, #0
+               movs    ip, ip, lsr #32 - PAGE_SHIFT
+               beq     .Lcfu_0fupi
+/*
+ * ip = max no. of bytes to copy before needing another "strt" insn
+ */
+               cmp     r2, ip
+               movlt   ip, r2
+               sub     r2, r2, ip
+               subs    ip, ip, #32
+               blt     .Lcfu_0rem8lp
+
+.Lcfu_0cpy8lp: ldmia   r1!, {r3 - r6}                  @ Shouldnt fault
+               stmia   r0!, {r3 - r6}
+               ldmia   r1!, {r3 - r6}                  @ Shouldnt fault
+               subs    ip, ip, #32
+               stmia   r0!, {r3 - r6}
+               bpl     .Lcfu_0cpy8lp
+
+.Lcfu_0rem8lp: cmn     ip, #16
+               ldmgeia r1!, {r3 - r6}                  @ Shouldnt fault
+               stmgeia r0!, {r3 - r6}
+               tst     ip, #8
+               ldmneia r1!, {r3 - r4}                  @ Shouldnt fault
+               stmneia r0!, {r3 - r4}
+               tst     ip, #4
+       TUSER(  ldrne) r3, [r1], #4                     @ Shouldnt fault
+               strne   r3, [r0], #4
+               ands    ip, ip, #3
+               beq     .Lcfu_0fupi
+.Lcfu_0nowords:        teq     ip, #0
+               beq     .Lcfu_finished
+.Lcfu_nowords: cmp     ip, #2
+USER(  TUSER(  ldrb)   r3, [r1], #1)                   @ May fault
+               strb    r3, [r0], #1
+USER(  TUSER(  ldrgeb) r3, [r1], #1)                   @ May fault
+               strgeb  r3, [r0], #1
+USER(  TUSER(  ldrgtb) r3, [r1], #1)                   @ May fault
+               strgtb  r3, [r0], #1
+               b       .Lcfu_finished
+
+.Lcfu_not_enough:
+               movs    ip, r2
+               bne     .Lcfu_nowords
+.Lcfu_finished:        mov     r0, #0
+               add     sp, sp, #8
+               ldmfd   sp!, {r4 - r7, pc}
+
+.Lcfu_src_not_aligned:
+               bic     r1, r1, #3
+USER(  TUSER(  ldr)    r7, [r1], #4)                   @ May fault
+               cmp     ip, #2
+               bgt     .Lcfu_3fupi
+               beq     .Lcfu_2fupi
+.Lcfu_1fupi:   subs    r2, r2, #4
+               addmi   ip, r2, #4
+               bmi     .Lcfu_1nowords
+               mov     r3, r7, pull #8
+USER(  TUSER(  ldr)    r7, [r1], #4)                   @ May fault
+               orr     r3, r3, r7, push #24
+               str     r3, [r0], #4
+               mov     ip, r1, lsl #32 - PAGE_SHIFT
+               rsb     ip, ip, #0
+               movs    ip, ip, lsr #32 - PAGE_SHIFT
+               beq     .Lcfu_1fupi
+               cmp     r2, ip
+               movlt   ip, r2
+               sub     r2, r2, ip
+               subs    ip, ip, #16
+               blt     .Lcfu_1rem8lp
+
+.Lcfu_1cpy8lp: mov     r3, r7, pull #8
+               ldmia   r1!, {r4 - r7}                  @ Shouldnt fault
+               subs    ip, ip, #16
+               orr     r3, r3, r4, push #24
+               mov     r4, r4, pull #8
+               orr     r4, r4, r5, push #24
+               mov     r5, r5, pull #8
+               orr     r5, r5, r6, push #24
+               mov     r6, r6, pull #8
+               orr     r6, r6, r7, push #24
+               stmia   r0!, {r3 - r6}
+               bpl     .Lcfu_1cpy8lp
+
+.Lcfu_1rem8lp: tst     ip, #8
+               movne   r3, r7, pull #8
+               ldmneia r1!, {r4, r7}                   @ Shouldnt fault
+               orrne   r3, r3, r4, push #24
+               movne   r4, r4, pull #8
+               orrne   r4, r4, r7, push #24
+               stmneia r0!, {r3 - r4}
+               tst     ip, #4
+               movne   r3, r7, pull #8
+USER(  TUSER(  ldrne) r7, [r1], #4)                    @ May fault
+               orrne   r3, r3, r7, push #24
+               strne   r3, [r0], #4
+               ands    ip, ip, #3
+               beq     .Lcfu_1fupi
+.Lcfu_1nowords:        mov     r3, r7, get_byte_1
+               teq     ip, #0
+               beq     .Lcfu_finished
+               cmp     ip, #2
+               strb    r3, [r0], #1
+               movge   r3, r7, get_byte_2
+               strgeb  r3, [r0], #1
+               movgt   r3, r7, get_byte_3
+               strgtb  r3, [r0], #1
+               b       .Lcfu_finished
+
+.Lcfu_2fupi:   subs    r2, r2, #4
+               addmi   ip, r2, #4
+               bmi     .Lcfu_2nowords
+               mov     r3, r7, pull #16
+USER(  TUSER(  ldr)    r7, [r1], #4)                   @ May fault
+               orr     r3, r3, r7, push #16
+               str     r3, [r0], #4
+               mov     ip, r1, lsl #32 - PAGE_SHIFT
+               rsb     ip, ip, #0
+               movs    ip, ip, lsr #32 - PAGE_SHIFT
+               beq     .Lcfu_2fupi
+               cmp     r2, ip
+               movlt   ip, r2
+               sub     r2, r2, ip
+               subs    ip, ip, #16
+               blt     .Lcfu_2rem8lp
+
+
+.Lcfu_2cpy8lp: mov     r3, r7, pull #16
+               ldmia   r1!, {r4 - r7}                  @ Shouldnt fault
+               subs    ip, ip, #16
+               orr     r3, r3, r4, push #16
+               mov     r4, r4, pull #16
+               orr     r4, r4, r5, push #16
+               mov     r5, r5, pull #16
+               orr     r5, r5, r6, push #16
+               mov     r6, r6, pull #16
+               orr     r6, r6, r7, push #16
+               stmia   r0!, {r3 - r6}
+               bpl     .Lcfu_2cpy8lp
+
+.Lcfu_2rem8lp: tst     ip, #8
+               movne   r3, r7, pull #16
+               ldmneia r1!, {r4, r7}                   @ Shouldnt fault
+               orrne   r3, r3, r4, push #16
+               movne   r4, r4, pull #16
+               orrne   r4, r4, r7, push #16
+               stmneia r0!, {r3 - r4}
+               tst     ip, #4
+               movne   r3, r7, pull #16
+USER(  TUSER(  ldrne) r7, [r1], #4)                    @ May fault
+               orrne   r3, r3, r7, push #16
+               strne   r3, [r0], #4
+               ands    ip, ip, #3
+               beq     .Lcfu_2fupi
+.Lcfu_2nowords:        mov     r3, r7, get_byte_2
+               teq     ip, #0
+               beq     .Lcfu_finished
+               cmp     ip, #2
+               strb    r3, [r0], #1
+               movge   r3, r7, get_byte_3
+               strgeb  r3, [r0], #1
+USER(  TUSER(  ldrgtb) r3, [r1], #0)                   @ May fault
+               strgtb  r3, [r0], #1
+               b       .Lcfu_finished
+
+.Lcfu_3fupi:   subs    r2, r2, #4
+               addmi   ip, r2, #4
+               bmi     .Lcfu_3nowords
+               mov     r3, r7, pull #24
+USER(  TUSER(  ldr)    r7, [r1], #4)                   @ May fault
+               orr     r3, r3, r7, push #8
+               str     r3, [r0], #4
+               mov     ip, r1, lsl #32 - PAGE_SHIFT
+               rsb     ip, ip, #0
+               movs    ip, ip, lsr #32 - PAGE_SHIFT
+               beq     .Lcfu_3fupi
+               cmp     r2, ip
+               movlt   ip, r2
+               sub     r2, r2, ip
+               subs    ip, ip, #16
+               blt     .Lcfu_3rem8lp
+
+.Lcfu_3cpy8lp: mov     r3, r7, pull #24
+               ldmia   r1!, {r4 - r7}                  @ Shouldnt fault
+               orr     r3, r3, r4, push #8
+               mov     r4, r4, pull #24
+               orr     r4, r4, r5, push #8
+               mov     r5, r5, pull #24
+               orr     r5, r5, r6, push #8
+               mov     r6, r6, pull #24
+               orr     r6, r6, r7, push #8
+               stmia   r0!, {r3 - r6}
+               subs    ip, ip, #16
+               bpl     .Lcfu_3cpy8lp
+
+.Lcfu_3rem8lp: tst     ip, #8
+               movne   r3, r7, pull #24
+               ldmneia r1!, {r4, r7}                   @ Shouldnt fault
+               orrne   r3, r3, r4, push #8
+               movne   r4, r4, pull #24
+               orrne   r4, r4, r7, push #8
+               stmneia r0!, {r3 - r4}
+               tst     ip, #4
+               movne   r3, r7, pull #24
+USER(  TUSER(  ldrne) r7, [r1], #4)                    @ May fault
+               orrne   r3, r3, r7, push #8
+               strne   r3, [r0], #4
+               ands    ip, ip, #3
+               beq     .Lcfu_3fupi
+.Lcfu_3nowords:        mov     r3, r7, get_byte_3
+               teq     ip, #0
+               beq     .Lcfu_finished
+               cmp     ip, #2
+               strb    r3, [r0], #1
+USER(  TUSER(  ldrgeb) r3, [r1], #1)                   @ May fault
+               strgeb  r3, [r0], #1
+USER(  TUSER(  ldrgtb) r3, [r1], #1)                   @ May fault
+               strgtb  r3, [r0], #1
+               b       .Lcfu_finished
+ENDPROC(__copy_from_user)
+
+               .pushsection .fixup,"ax"
+               .align  0
+               /*
+                * We took an exception.  r0 contains a pointer to
+                * the byte not copied.
+                */
+9001:          ldr     r2, [sp], #4                    @ void *to
+               sub     r2, r0, r2                      @ bytes copied
+               ldr     r1, [sp], #4                    @ unsigned long count
+               subs    r4, r1, r2                      @ bytes left to copy
+               movne   r1, r4
+               blne    __memzero
+               mov     r0, r4
+               ldmfd   sp!, {r4 - r7, pc}
+               .popsection
+
index 01fb7325fecce0ef9a015835ff846655b3b4af11..9ac427a702da3d5cc25f380ededa12dcbcd73ed9 100644 (file)
@@ -294,9 +294,9 @@ void __init at91_add_device_cf(struct at91_cf_data *data) {}
  *  MMC / SD
  * -------------------------------------------------------------------- */
 
-#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
+#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
 static u64 mmc_dmamask = DMA_BIT_MASK(32);
-static struct at91_mmc_data mmc_data;
+static struct mci_platform_data mmc_data;
 
 static struct resource mmc_resources[] = {
        [0] = {
@@ -312,7 +312,7 @@ static struct resource mmc_resources[] = {
 };
 
 static struct platform_device at91rm9200_mmc_device = {
-       .name           = "at91_mci",
+       .name           = "atmel_mci",
        .id             = -1,
        .dev            = {
                                .dma_mask               = &mmc_dmamask,
@@ -323,53 +323,69 @@ static struct platform_device at91rm9200_mmc_device = {
        .num_resources  = ARRAY_SIZE(mmc_resources),
 };
 
-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
+void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
 {
+       unsigned int i;
+       unsigned int slot_count = 0;
+
        if (!data)
                return;
 
-       /* input/irq */
-       if (gpio_is_valid(data->det_pin)) {
-               at91_set_gpio_input(data->det_pin, 1);
-               at91_set_deglitch(data->det_pin, 1);
-       }
-       if (gpio_is_valid(data->wp_pin))
-               at91_set_gpio_input(data->wp_pin, 1);
-       if (gpio_is_valid(data->vcc_pin))
-               at91_set_gpio_output(data->vcc_pin, 0);
-
-       /* CLK */
-       at91_set_A_periph(AT91_PIN_PA27, 0);
+       for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
 
-       if (data->slot_b) {
-               /* CMD */
-               at91_set_B_periph(AT91_PIN_PA8, 1);
+               if (!data->slot[i].bus_width)
+                       continue;
 
-               /* DAT0, maybe DAT1..DAT3 */
-               at91_set_B_periph(AT91_PIN_PA9, 1);
-               if (data->wire4) {
-                       at91_set_B_periph(AT91_PIN_PA10, 1);
-                       at91_set_B_periph(AT91_PIN_PA11, 1);
-                       at91_set_B_periph(AT91_PIN_PA12, 1);
+               /* input/irq */
+               if (gpio_is_valid(data->slot[i].detect_pin)) {
+                       at91_set_gpio_input(data->slot[i].detect_pin, 1);
+                       at91_set_deglitch(data->slot[i].detect_pin, 1);
                }
-       } else {
-               /* CMD */
-               at91_set_A_periph(AT91_PIN_PA28, 1);
-
-               /* DAT0, maybe DAT1..DAT3 */
-               at91_set_A_periph(AT91_PIN_PA29, 1);
-               if (data->wire4) {
-                       at91_set_B_periph(AT91_PIN_PB3, 1);
-                       at91_set_B_periph(AT91_PIN_PB4, 1);
-                       at91_set_B_periph(AT91_PIN_PB5, 1);
+               if (gpio_is_valid(data->slot[i].wp_pin))
+                       at91_set_gpio_input(data->slot[i].wp_pin, 1);
+
+               switch (i) {
+               case 0:                                 /* slot A */
+                       /* CMD */
+                       at91_set_A_periph(AT91_PIN_PA28, 1);
+                       /* DAT0, maybe DAT1..DAT3 */
+                       at91_set_A_periph(AT91_PIN_PA29, 1);
+                       if (data->slot[i].bus_width == 4) {
+                               at91_set_B_periph(AT91_PIN_PB3, 1);
+                               at91_set_B_periph(AT91_PIN_PB4, 1);
+                               at91_set_B_periph(AT91_PIN_PB5, 1);
+                       }
+                       slot_count++;
+                       break;
+               case 1:                                 /* slot B */
+                       /* CMD */
+                       at91_set_B_periph(AT91_PIN_PA8, 1);
+                       /* DAT0, maybe DAT1..DAT3 */
+                       at91_set_B_periph(AT91_PIN_PA9, 1);
+                       if (data->slot[i].bus_width == 4) {
+                               at91_set_B_periph(AT91_PIN_PA10, 1);
+                               at91_set_B_periph(AT91_PIN_PA11, 1);
+                               at91_set_B_periph(AT91_PIN_PA12, 1);
+                       }
+                       slot_count++;
+                       break;
+               default:
+                       printk(KERN_ERR
+                              "AT91: SD/MMC slot %d not available\n", i);
+                       break;
+               }
+               if (slot_count) {
+                       /* CLK */
+                       at91_set_A_periph(AT91_PIN_PA27, 0);
+
+                       mmc_data = *data;
+                       platform_device_register(&at91rm9200_mmc_device);
                }
        }
 
-       mmc_data = *data;
-       platform_device_register(&at91rm9200_mmc_device);
 }
 #else
-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
+void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
 #endif
 
 
index 7b9c2ba396edb854cfd78ddef676250a751e60bc..156e639257c98de7ef9b86480cfbd33eb909fc28 100644 (file)
@@ -208,93 +208,11 @@ void __init at91_add_device_eth(struct macb_platform_data *data) {}
 #endif
 
 
-/* --------------------------------------------------------------------
- *  MMC / SD
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
-static u64 mmc_dmamask = DMA_BIT_MASK(32);
-static struct at91_mmc_data mmc_data;
-
-static struct resource mmc_resources[] = {
-       [0] = {
-               .start  = AT91SAM9260_BASE_MCI,
-               .end    = AT91SAM9260_BASE_MCI + SZ_16K - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = NR_IRQS_LEGACY + AT91SAM9260_ID_MCI,
-               .end    = NR_IRQS_LEGACY + AT91SAM9260_ID_MCI,
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device at91sam9260_mmc_device = {
-       .name           = "at91_mci",
-       .id             = -1,
-       .dev            = {
-                               .dma_mask               = &mmc_dmamask,
-                               .coherent_dma_mask      = DMA_BIT_MASK(32),
-                               .platform_data          = &mmc_data,
-       },
-       .resource       = mmc_resources,
-       .num_resources  = ARRAY_SIZE(mmc_resources),
-};
-
-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
-{
-       if (!data)
-               return;
-
-       /* input/irq */
-       if (gpio_is_valid(data->det_pin)) {
-               at91_set_gpio_input(data->det_pin, 1);
-               at91_set_deglitch(data->det_pin, 1);
-       }
-       if (gpio_is_valid(data->wp_pin))
-               at91_set_gpio_input(data->wp_pin, 1);
-       if (gpio_is_valid(data->vcc_pin))
-               at91_set_gpio_output(data->vcc_pin, 0);
-
-       /* CLK */
-       at91_set_A_periph(AT91_PIN_PA8, 0);
-
-       if (data->slot_b) {
-               /* CMD */
-               at91_set_B_periph(AT91_PIN_PA1, 1);
-
-               /* DAT0, maybe DAT1..DAT3 */
-               at91_set_B_periph(AT91_PIN_PA0, 1);
-               if (data->wire4) {
-                       at91_set_B_periph(AT91_PIN_PA5, 1);
-                       at91_set_B_periph(AT91_PIN_PA4, 1);
-                       at91_set_B_periph(AT91_PIN_PA3, 1);
-               }
-       } else {
-               /* CMD */
-               at91_set_A_periph(AT91_PIN_PA7, 1);
-
-               /* DAT0, maybe DAT1..DAT3 */
-               at91_set_A_periph(AT91_PIN_PA6, 1);
-               if (data->wire4) {
-                       at91_set_A_periph(AT91_PIN_PA9, 1);
-                       at91_set_A_periph(AT91_PIN_PA10, 1);
-                       at91_set_A_periph(AT91_PIN_PA11, 1);
-               }
-       }
-
-       mmc_data = *data;
-       platform_device_register(&at91sam9260_mmc_device);
-}
-#else
-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
-#endif
-
 /* --------------------------------------------------------------------
  *  MMC / SD Slot for Atmel MCI Driver
  * -------------------------------------------------------------------- */
 
-#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
+#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
 static u64 mmc_dmamask = DMA_BIT_MASK(32);
 static struct mci_platform_data mmc_data;
 
index 8df5c1bdff92f1d1194fa9d64da61e2aa9bc2598..06c0c6e025b98c3949818e170eee99da537cd61b 100644 (file)
@@ -137,9 +137,9 @@ void __init at91_add_device_udc(struct at91_udc_data *data) {}
  *  MMC / SD
  * -------------------------------------------------------------------- */
 
-#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
+#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
 static u64 mmc_dmamask = DMA_BIT_MASK(32);
-static struct at91_mmc_data mmc_data;
+static struct mci_platform_data mmc_data;
 
 static struct resource mmc_resources[] = {
        [0] = {
@@ -155,7 +155,7 @@ static struct resource mmc_resources[] = {
 };
 
 static struct platform_device at91sam9261_mmc_device = {
-       .name           = "at91_mci",
+       .name           = "atmel_mci",
        .id             = -1,
        .dev            = {
                                .dma_mask               = &mmc_dmamask,
@@ -166,40 +166,40 @@ static struct platform_device at91sam9261_mmc_device = {
        .num_resources  = ARRAY_SIZE(mmc_resources),
 };
 
-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
+void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
 {
        if (!data)
                return;
 
-       /* input/irq */
-       if (gpio_is_valid(data->det_pin)) {
-               at91_set_gpio_input(data->det_pin, 1);
-               at91_set_deglitch(data->det_pin, 1);
-       }
-       if (gpio_is_valid(data->wp_pin))
-               at91_set_gpio_input(data->wp_pin, 1);
-       if (gpio_is_valid(data->vcc_pin))
-               at91_set_gpio_output(data->vcc_pin, 0);
-
-       /* CLK */
-       at91_set_B_periph(AT91_PIN_PA2, 0);
-
-       /* CMD */
-       at91_set_B_periph(AT91_PIN_PA1, 1);
-
-       /* DAT0, maybe DAT1..DAT3 */
-       at91_set_B_periph(AT91_PIN_PA0, 1);
-       if (data->wire4) {
-               at91_set_B_periph(AT91_PIN_PA4, 1);
-               at91_set_B_periph(AT91_PIN_PA5, 1);
-               at91_set_B_periph(AT91_PIN_PA6, 1);
-       }
+       if (data->slot[0].bus_width) {
+               /* input/irq */
+               if (gpio_is_valid(data->slot[0].detect_pin)) {
+                       at91_set_gpio_input(data->slot[0].detect_pin, 1);
+                       at91_set_deglitch(data->slot[0].detect_pin, 1);
+               }
+               if (gpio_is_valid(data->slot[0].wp_pin))
+                       at91_set_gpio_input(data->slot[0].wp_pin, 1);
+
+               /* CLK */
+               at91_set_B_periph(AT91_PIN_PA2, 0);
 
-       mmc_data = *data;
-       platform_device_register(&at91sam9261_mmc_device);
+               /* CMD */
+               at91_set_B_periph(AT91_PIN_PA1, 1);
+
+               /* DAT0, maybe DAT1..DAT3 */
+               at91_set_B_periph(AT91_PIN_PA0, 1);
+               if (data->slot[0].bus_width == 4) {
+                       at91_set_B_periph(AT91_PIN_PA4, 1);
+                       at91_set_B_periph(AT91_PIN_PA5, 1);
+                       at91_set_B_periph(AT91_PIN_PA6, 1);
+               }
+
+               mmc_data = *data;
+               platform_device_register(&at91sam9261_mmc_device);
+       }
 }
 #else
-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
+void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
 #endif
 
 
index 84b38105231e91a52df082f3828f2042c1178201..144ef5de51b6beaf3b989801277aabe94aefe97b 100644 (file)
@@ -188,8 +188,8 @@ static struct clk_lookup periph_clocks_lookups[] = {
        CLKDEV_CON_ID("hclk", &macb_clk),
        CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),
        CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),
-       CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.0", &mmc0_clk),
-       CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.1", &mmc1_clk),
+       CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.0", &mmc0_clk),
+       CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.1", &mmc1_clk),
        CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
        CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
        CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb_clk),
index eb6bbf86fb9f597cc7424a52b459bb04ecff2326..1e176aaaaecb3b5c58d555a45282baf73683a0f5 100644 (file)
@@ -218,9 +218,9 @@ void __init at91_add_device_eth(struct macb_platform_data *data) {}
  *  MMC / SD
  * -------------------------------------------------------------------- */
 
-#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
+#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
 static u64 mmc_dmamask = DMA_BIT_MASK(32);
-static struct at91_mmc_data mmc0_data, mmc1_data;
+static struct mci_platform_data mmc0_data, mmc1_data;
 
 static struct resource mmc0_resources[] = {
        [0] = {
@@ -236,7 +236,7 @@ static struct resource mmc0_resources[] = {
 };
 
 static struct platform_device at91sam9263_mmc0_device = {
-       .name           = "at91_mci",
+       .name           = "atmel_mci",
        .id             = 0,
        .dev            = {
                                .dma_mask               = &mmc_dmamask,
@@ -261,7 +261,7 @@ static struct resource mmc1_resources[] = {
 };
 
 static struct platform_device at91sam9263_mmc1_device = {
-       .name           = "at91_mci",
+       .name           = "atmel_mci",
        .id             = 1,
        .dev            = {
                                .dma_mask               = &mmc_dmamask,
@@ -272,85 +272,110 @@ static struct platform_device at91sam9263_mmc1_device = {
        .num_resources  = ARRAY_SIZE(mmc1_resources),
 };
 
-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
+void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
 {
+       unsigned int i;
+       unsigned int slot_count = 0;
+
        if (!data)
                return;
 
-       /* input/irq */
-       if (gpio_is_valid(data->det_pin)) {
-               at91_set_gpio_input(data->det_pin, 1);
-               at91_set_deglitch(data->det_pin, 1);
-       }
-       if (gpio_is_valid(data->wp_pin))
-               at91_set_gpio_input(data->wp_pin, 1);
-       if (gpio_is_valid(data->vcc_pin))
-               at91_set_gpio_output(data->vcc_pin, 0);
+       for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
 
-       if (mmc_id == 0) {              /* MCI0 */
-               /* CLK */
-               at91_set_A_periph(AT91_PIN_PA12, 0);
+               if (!data->slot[i].bus_width)
+                       continue;
 
-               if (data->slot_b) {
-                       /* CMD */
-                       at91_set_A_periph(AT91_PIN_PA16, 1);
+               /* input/irq */
+               if (gpio_is_valid(data->slot[i].detect_pin)) {
+                       at91_set_gpio_input(data->slot[i].detect_pin,
+                                       1);
+                       at91_set_deglitch(data->slot[i].detect_pin,
+                                       1);
+               }
+               if (gpio_is_valid(data->slot[i].wp_pin))
+                       at91_set_gpio_input(data->slot[i].wp_pin, 1);
+
+               if (mmc_id == 0) {                              /* MCI0 */
+                       switch (i) {
+                       case 0:                                 /* slot A */
+                               /* CMD */
+                               at91_set_A_periph(AT91_PIN_PA1, 1);
+                               /* DAT0, maybe DAT1..DAT3 */
+                               at91_set_A_periph(AT91_PIN_PA0, 1);
+                               if (data->slot[i].bus_width == 4) {
+                                       at91_set_A_periph(AT91_PIN_PA3, 1);
+                                       at91_set_A_periph(AT91_PIN_PA4, 1);
+                                       at91_set_A_periph(AT91_PIN_PA5, 1);
+                               }
+                               slot_count++;
+                               break;
+                       case 1:                                 /* slot B */
+                               /* CMD */
+                               at91_set_A_periph(AT91_PIN_PA16, 1);
+                               /* DAT0, maybe DAT1..DAT3 */
+                               at91_set_A_periph(AT91_PIN_PA17, 1);
+                               if (data->slot[i].bus_width == 4) {
+                                       at91_set_A_periph(AT91_PIN_PA18, 1);
+                                       at91_set_A_periph(AT91_PIN_PA19, 1);
+                                       at91_set_A_periph(AT91_PIN_PA20, 1);
+                               }
+                               slot_count++;
+                               break;
+                       default:
+                               printk(KERN_ERR
+                                      "AT91: SD/MMC slot %d not available\n", i);
+                               break;
+                       }
+                       if (slot_count) {
+                               /* CLK */
+                               at91_set_A_periph(AT91_PIN_PA12, 0);
 
-                       /* DAT0, maybe DAT1..DAT3 */
-                       at91_set_A_periph(AT91_PIN_PA17, 1);
-                       if (data->wire4) {
-                               at91_set_A_periph(AT91_PIN_PA18, 1);
-                               at91_set_A_periph(AT91_PIN_PA19, 1);
-                               at91_set_A_periph(AT91_PIN_PA20, 1);
+                               mmc0_data = *data;
+                               platform_device_register(&at91sam9263_mmc0_device);
                        }
-               } else {
-                       /* CMD */
-                       at91_set_A_periph(AT91_PIN_PA1, 1);
-
-                       /* DAT0, maybe DAT1..DAT3 */
-                       at91_set_A_periph(AT91_PIN_PA0, 1);
-                       if (data->wire4) {
-                               at91_set_A_periph(AT91_PIN_PA3, 1);
-                               at91_set_A_periph(AT91_PIN_PA4, 1);
-                               at91_set_A_periph(AT91_PIN_PA5, 1);
+               } else if (mmc_id == 1) {                       /* MCI1 */
+                       switch (i) {
+                       case 0:                                 /* slot A */
+                               /* CMD */
+                               at91_set_A_periph(AT91_PIN_PA7, 1);
+                               /* DAT0, maybe DAT1..DAT3 */
+                               at91_set_A_periph(AT91_PIN_PA8, 1);
+                               if (data->slot[i].bus_width == 4) {
+                                       at91_set_A_periph(AT91_PIN_PA9, 1);
+                                       at91_set_A_periph(AT91_PIN_PA10, 1);
+                                       at91_set_A_periph(AT91_PIN_PA11, 1);
+                               }
+                               slot_count++;
+                               break;
+                       case 1:                                 /* slot B */
+                               /* CMD */
+                               at91_set_A_periph(AT91_PIN_PA21, 1);
+                               /* DAT0, maybe DAT1..DAT3 */
+                               at91_set_A_periph(AT91_PIN_PA22, 1);
+                               if (data->slot[i].bus_width == 4) {
+                                       at91_set_A_periph(AT91_PIN_PA23, 1);
+                                       at91_set_A_periph(AT91_PIN_PA24, 1);
+                                       at91_set_A_periph(AT91_PIN_PA25, 1);
+                               }
+                               slot_count++;
+                               break;
+                       default:
+                               printk(KERN_ERR
+                                      "AT91: SD/MMC slot %d not available\n", i);
+                               break;
                        }
-               }
+                       if (slot_count) {
+                               /* CLK */
+                               at91_set_A_periph(AT91_PIN_PA6, 0);
 
-               mmc0_data = *data;
-               platform_device_register(&at91sam9263_mmc0_device);
-       } else {                        /* MCI1 */
-               /* CLK */
-               at91_set_A_periph(AT91_PIN_PA6, 0);
-
-               if (data->slot_b) {
-                       /* CMD */
-                       at91_set_A_periph(AT91_PIN_PA21, 1);
-
-                       /* DAT0, maybe DAT1..DAT3 */
-                       at91_set_A_periph(AT91_PIN_PA22, 1);
-                       if (data->wire4) {
-                               at91_set_A_periph(AT91_PIN_PA23, 1);
-                               at91_set_A_periph(AT91_PIN_PA24, 1);
-                               at91_set_A_periph(AT91_PIN_PA25, 1);
-                       }
-               } else {
-                       /* CMD */
-                       at91_set_A_periph(AT91_PIN_PA7, 1);
-
-                       /* DAT0, maybe DAT1..DAT3 */
-                       at91_set_A_periph(AT91_PIN_PA8, 1);
-                       if (data->wire4) {
-                               at91_set_A_periph(AT91_PIN_PA9, 1);
-                               at91_set_A_periph(AT91_PIN_PA10, 1);
-                               at91_set_A_periph(AT91_PIN_PA11, 1);
+                               mmc1_data = *data;
+                               platform_device_register(&at91sam9263_mmc1_device);
                        }
                }
-
-               mmc1_data = *data;
-               platform_device_register(&at91sam9263_mmc1_device);
        }
 }
 #else
-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
+void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
 #endif
 
 /* --------------------------------------------------------------------
index f09fff932172ffec238c10714331d7c8970a53e1..ea4479e7c3f43af29e88c256e4d3364d2506a7a4 100644 (file)
@@ -161,9 +161,9 @@ void __init at91_add_device_usba(struct usba_platform_data *data) {}
  *  MMC / SD
  * -------------------------------------------------------------------- */
 
-#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
+#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
 static u64 mmc_dmamask = DMA_BIT_MASK(32);
-static struct at91_mmc_data mmc_data;
+static struct mci_platform_data mmc_data;
 
 static struct resource mmc_resources[] = {
        [0] = {
@@ -179,7 +179,7 @@ static struct resource mmc_resources[] = {
 };
 
 static struct platform_device at91sam9rl_mmc_device = {
-       .name           = "at91_mci",
+       .name           = "atmel_mci",
        .id             = -1,
        .dev            = {
                                .dma_mask               = &mmc_dmamask,
@@ -190,40 +190,40 @@ static struct platform_device at91sam9rl_mmc_device = {
        .num_resources  = ARRAY_SIZE(mmc_resources),
 };
 
-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
+void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
 {
        if (!data)
                return;
 
-       /* input/irq */
-       if (gpio_is_valid(data->det_pin)) {
-               at91_set_gpio_input(data->det_pin, 1);
-               at91_set_deglitch(data->det_pin, 1);
-       }
-       if (gpio_is_valid(data->wp_pin))
-               at91_set_gpio_input(data->wp_pin, 1);
-       if (gpio_is_valid(data->vcc_pin))
-               at91_set_gpio_output(data->vcc_pin, 0);
-
-       /* CLK */
-       at91_set_A_periph(AT91_PIN_PA2, 0);
-
-       /* CMD */
-       at91_set_A_periph(AT91_PIN_PA1, 1);
-
-       /* DAT0, maybe DAT1..DAT3 */
-       at91_set_A_periph(AT91_PIN_PA0, 1);
-       if (data->wire4) {
-               at91_set_A_periph(AT91_PIN_PA3, 1);
-               at91_set_A_periph(AT91_PIN_PA4, 1);
-               at91_set_A_periph(AT91_PIN_PA5, 1);
+       if (data->slot[0].bus_width) {
+               /* input/irq */
+               if (gpio_is_valid(data->slot[0].detect_pin)) {
+                       at91_set_gpio_input(data->slot[0].detect_pin, 1);
+                       at91_set_deglitch(data->slot[0].detect_pin, 1);
+               }
+               if (gpio_is_valid(data->slot[0].wp_pin))
+                       at91_set_gpio_input(data->slot[0].wp_pin, 1);
+
+               /* CLK */
+               at91_set_A_periph(AT91_PIN_PA2, 0);
+
+               /* CMD */
+               at91_set_A_periph(AT91_PIN_PA1, 1);
+
+               /* DAT0, maybe DAT1..DAT3 */
+               at91_set_A_periph(AT91_PIN_PA0, 1);
+               if (data->slot[0].bus_width == 4) {
+                       at91_set_A_periph(AT91_PIN_PA3, 1);
+                       at91_set_A_periph(AT91_PIN_PA4, 1);
+                       at91_set_A_periph(AT91_PIN_PA5, 1);
+               }
+
+               mmc_data = *data;
+               platform_device_register(&at91sam9rl_mmc_device);
        }
-
-       mmc_data = *data;
-       platform_device_register(&at91sam9rl_mmc_device);
 }
 #else
-void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
+void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
 #endif
 
 
index de7be193181795cb210e5865df30e6fb8babb0d8..93a832f7023230a8fba9f9ed8eb740fc89736c1b 100644 (file)
@@ -133,12 +133,12 @@ static struct atmel_nand_data __initdata afeb9260_nand_data = {
 /*
  * MCI (SD/MMC)
  */
-static struct at91_mmc_data __initdata afeb9260_mmc_data = {
-       .det_pin        = AT91_PIN_PC9,
-       .wp_pin         = AT91_PIN_PC4,
-       .slot_b         = 1,
-       .wire4          = 1,
-       .vcc_pin        = -EINVAL,
+static struct mci_platform_data __initdata afeb9260_mci0_data = {
+       .slot[1] = {
+               .bus_width      = 4,
+               .detect_pin     = AT91_PIN_PC9,
+               .wp_pin         = AT91_PIN_PC4,
+       },
 };
 
 
@@ -199,7 +199,7 @@ static void __init afeb9260_board_init(void)
        at91_set_B_periph(AT91_PIN_PA10, 0);    /* ETX2 */
        at91_set_B_periph(AT91_PIN_PA11, 0);    /* ETX3 */
        /* MMC */
-       at91_add_device_mmc(0, &afeb9260_mmc_data);
+       at91_add_device_mci(0, &afeb9260_mci0_data);
        /* I2C */
        at91_add_device_i2c(afeb9260_i2c_devices,
                        ARRAY_SIZE(afeb9260_i2c_devices));
index a5b002f32a6162e98e6ae5335fcdbec2eb911332..71d8f362a1d588ad017c43c0ccf4a3a93798b208 100644 (file)
@@ -71,12 +71,12 @@ static struct at91_udc_data __initdata carmeva_udc_data = {
        // .vcc_pin     = -EINVAL,
 // };
 
-static struct at91_mmc_data __initdata carmeva_mmc_data = {
-       .slot_b         = 0,
-       .wire4          = 1,
-       .det_pin        = AT91_PIN_PB10,
-       .wp_pin         = AT91_PIN_PC14,
-       .vcc_pin        = -EINVAL,
+static struct mci_platform_data __initdata carmeva_mci0_data = {
+       .slot[0] = {
+               .bus_width      = 4,
+               .detect_pin     = AT91_PIN_PB10,
+               .wp_pin         = AT91_PIN_PC14,
+       },
 };
 
 static struct spi_board_info carmeva_spi_devices[] = {
@@ -150,7 +150,7 @@ static void __init carmeva_board_init(void)
        /* Compact Flash */
 //     at91_add_device_cf(&carmeva_cf_data);
        /* MMC */
-       at91_add_device_mmc(0, &carmeva_mmc_data);
+       at91_add_device_mci(0, &carmeva_mci0_data);
        /* LEDs */
        at91_gpio_leds(carmeva_leds, ARRAY_SIZE(carmeva_leds));
 }
index ecbc13b594de05ed2877d27eab08b91db16cf475..e71c473316e32f8c93ba4068ef6da1a57899c0f7 100644 (file)
@@ -254,8 +254,7 @@ static struct gpio_led cpu9krea_leds[] = {
 
 static struct i2c_board_info __initdata cpu9krea_i2c_devices[] = {
        {
-               I2C_BOARD_INFO("rtc-ds1307", 0x68),
-               .type   = "ds1339",
+               I2C_BOARD_INFO("ds1339", 0x68),
        },
 };
 
@@ -312,12 +311,12 @@ static void __init cpu9krea_add_device_buttons(void)
 /*
  * MCI (SD/MMC)
  */
-static struct at91_mmc_data __initdata cpu9krea_mmc_data = {
-       .slot_b         = 0,
-       .wire4          = 1,
-       .det_pin        = AT91_PIN_PA29,
-       .wp_pin         = -EINVAL,
-       .vcc_pin        = -EINVAL,
+static struct mci_platform_data __initdata cpu9krea_mci0_data = {
+       .slot[0] = {
+               .bus_width      = 4,
+               .detect_pin     = AT91_PIN_PA29,
+               .wp_pin         = -EINVAL,
+       },
 };
 
 static void __init cpu9krea_board_init(void)
@@ -359,7 +358,7 @@ static void __init cpu9krea_board_init(void)
        /* Ethernet */
        at91_add_device_eth(&cpu9krea_macb_data);
        /* MMC */
-       at91_add_device_mmc(0, &cpu9krea_mmc_data);
+       at91_add_device_mci(0, &cpu9krea_mci0_data);
        /* I2C */
        at91_add_device_i2c(cpu9krea_i2c_devices,
                ARRAY_SIZE(cpu9krea_i2c_devices));
index 2e6d043c82f202e352b426e0ac699a74b15fbdcd..2cbd1a2b6c35d33bed32f776f52e640742611fc8 100644 (file)
@@ -78,11 +78,12 @@ static struct at91_udc_data __initdata cpuat91_udc_data = {
        .pullup_pin     = AT91_PIN_PC14,
 };
 
-static struct at91_mmc_data __initdata cpuat91_mmc_data = {
-       .det_pin        = AT91_PIN_PC2,
-       .wire4          = 1,
-       .wp_pin         = -EINVAL,
-       .vcc_pin        = -EINVAL,
+static struct mci_platform_data __initdata cpuat91_mci0_data = {
+       .slot[0] = {
+               .bus_width      = 4,
+               .detect_pin     = AT91_PIN_PC2,
+               .wp_pin         = -EINVAL,
+       },
 };
 
 static struct physmap_flash_data cpuat91_flash_data = {
@@ -168,7 +169,7 @@ static void __init cpuat91_board_init(void)
        /* USB Device */
        at91_add_device_udc(&cpuat91_udc_data);
        /* MMC */
-       at91_add_device_mmc(0, &cpuat91_mmc_data);
+       at91_add_device_mci(0, &cpuat91_mci0_data);
        /* I2C */
        at91_add_device_i2c(NULL, 0);
        /* Platform devices */
index 462bc319cbc589b2bc86d80c4ebcce642ac7bc33..3e37437a7a613222245df1f297e18cde4a02dc97 100644 (file)
@@ -87,12 +87,12 @@ static struct at91_cf_data __initdata csb337_cf_data = {
        .rst_pin        = AT91_PIN_PD2,
 };
 
-static struct at91_mmc_data __initdata csb337_mmc_data = {
-       .det_pin        = AT91_PIN_PD5,
-       .slot_b         = 0,
-       .wire4          = 1,
-       .wp_pin         = AT91_PIN_PD6,
-       .vcc_pin        = -EINVAL,
+static struct mci_platform_data __initdata csb337_mci0_data = {
+       .slot[0] = {
+               .bus_width      = 4,
+               .detect_pin     = AT91_PIN_PD5,
+               .wp_pin         = AT91_PIN_PD6,
+       },
 };
 
 static struct spi_board_info csb337_spi_devices[] = {
@@ -220,8 +220,6 @@ static struct gpio_led csb_leds[] = {
 
 static void __init csb337_board_init(void)
 {
-       /* Setup the LEDs */
-       at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1);
        /* Serial */
        /* DBGU on ttyS0 */
        at91_register_uart(0, 0, 0);
@@ -240,7 +238,7 @@ static void __init csb337_board_init(void)
        /* SPI */
        at91_add_device_spi(csb337_spi_devices, ARRAY_SIZE(csb337_spi_devices));
        /* MMC */
-       at91_add_device_mmc(0, &csb337_mmc_data);
+       at91_add_device_mci(0, &csb337_mci0_data);
        /* NOR flash */
        platform_device_register(&csb_flash);
        /* LEDs */
index d1e1f3fc0a47a06d912eddc622048b0663c8be8d..0cfac16ee9d5e75392ebd025e21521c34f33d3ab 100644 (file)
@@ -70,12 +70,12 @@ static struct at91_cf_data __initdata eb9200_cf_data = {
        .rst_pin        = AT91_PIN_PC5,
 };
 
-static struct at91_mmc_data __initdata eb9200_mmc_data = {
-       .slot_b         = 0,
-       .wire4          = 1,
-       .det_pin        = -EINVAL,
-       .wp_pin         = -EINVAL,
-       .vcc_pin        = -EINVAL,
+static struct mci_platform_data __initdata eb9200_mci0_data = {
+       .slot[0] = {
+               .bus_width      = 4,
+               .detect_pin     = -EINVAL,
+               .wp_pin         = -EINVAL,
+       },
 };
 
 static struct i2c_board_info __initdata eb9200_i2c_devices[] = {
@@ -113,7 +113,7 @@ static void __init eb9200_board_init(void)
        at91_add_device_spi(NULL, 0);
        /* MMC */
        /* only supports 1 or 4 bit interface, not wired through to SPI */
-       at91_add_device_mmc(0, &eb9200_mmc_data);
+       at91_add_device_mci(0, &eb9200_mci0_data);
 }
 
 MACHINE_START(ATEB9200, "Embest ATEB9200")
index 9c24cb25707c61dae73275d31c4c669af20528cd..3d931ffac4bf01d647c586c428627bb2be903f03 100644 (file)
@@ -64,12 +64,12 @@ static struct at91_usbh_data __initdata ecb_at91usbh_data = {
        .overcurrent_pin= {-EINVAL, -EINVAL},
 };
 
-static struct at91_mmc_data __initdata ecb_at91mmc_data = {
-       .slot_b         = 0,
-       .wire4          = 1,
-       .det_pin        = -EINVAL,
-       .wp_pin         = -EINVAL,
-       .vcc_pin        = -EINVAL,
+static struct mci_platform_data __initdata ecbat91_mci0_data = {
+       .slot[0] = {
+               .bus_width      = 4,
+               .detect_pin     = -EINVAL,
+               .wp_pin         = -EINVAL,
+       },
 };
 
 
@@ -138,11 +138,20 @@ static struct spi_board_info __initdata ecb_at91spi_devices[] = {
        },
 };
 
+/*
+ * LEDs
+ */
+static struct gpio_led ecb_leds[] = {
+       {       /* D1 */
+               .name                   = "led1",
+               .gpio                   = AT91_PIN_PC7,
+               .active_low             = 1,
+               .default_trigger        = "heartbeat",
+       }
+};
+
 static void __init ecb_at91board_init(void)
 {
-       /* Setup the LEDs */
-       at91_init_leds(AT91_PIN_PC7, AT91_PIN_PC7);
-
        /* Serial */
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -161,10 +170,13 @@ static void __init ecb_at91board_init(void)
        at91_add_device_i2c(NULL, 0);
 
        /* MMC */
-       at91_add_device_mmc(0, &ecb_at91mmc_data);
+       at91_add_device_mci(0, &ecbat91_mci0_data);
 
        /* SPI */
        at91_add_device_spi(ecb_at91spi_devices, ARRAY_SIZE(ecb_at91spi_devices));
+
+       /* LEDs */
+       at91_gpio_leds(ecb_leds, ARRAY_SIZE(ecb_leds));
 }
 
 MACHINE_START(ECBAT91, "emQbit's ECB_AT91")
index 82bdfde3405f52d0ef1fd34507b12bd4bfe56466..d93658a2b12828a14e70cbdacd418498f13c7f0f 100644 (file)
@@ -56,12 +56,12 @@ static struct at91_udc_data __initdata eco920_udc_data = {
        .pullup_pin     = AT91_PIN_PB13,
 };
 
-static struct at91_mmc_data __initdata eco920_mmc_data = {
-       .slot_b         = 0,
-       .wire4          = 0,
-       .det_pin        = -EINVAL,
-       .wp_pin         = -EINVAL,
-       .vcc_pin        = -EINVAL,
+static struct mci_platform_data __initdata eco920_mci0_data = {
+       .slot[0] = {
+               .bus_width      = 1,
+               .detect_pin     = -EINVAL,
+               .wp_pin         = -EINVAL,
+       },
 };
 
 static struct physmap_flash_data eco920_flash_data = {
@@ -93,10 +93,26 @@ static struct spi_board_info eco920_spi_devices[] = {
        },
 };
 
+/*
+ * LEDs
+ */
+static struct gpio_led eco920_leds[] = {
+       {       /* D1 */
+               .name                   = "led1",
+               .gpio                   = AT91_PIN_PB0,
+               .active_low             = 1,
+               .default_trigger        = "heartbeat",
+       },
+       {       /* D2 */
+               .name                   = "led2",
+               .gpio                   = AT91_PIN_PB1,
+               .active_low             = 1,
+               .default_trigger        = "timer",
+       }
+};
+
 static void __init eco920_board_init(void)
 {
-       /* Setup the LEDs */
-       at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1);
        /* DBGU on ttyS0. (Rx & Tx only */
        at91_register_uart(0, 0, 0);
        at91_add_device_serial();
@@ -104,7 +120,7 @@ static void __init eco920_board_init(void)
        at91_add_device_usbh(&eco920_usbh_data);
        at91_add_device_udc(&eco920_udc_data);
 
-       at91_add_device_mmc(0, &eco920_mmc_data);
+       at91_add_device_mci(0, &eco920_mci0_data);
        platform_device_register(&eco920_flash);
 
        at91_ramc_write(0, AT91_SMC_CSR(7),     AT91_SMC_RWHOLD_(1)
@@ -127,6 +143,8 @@ static void __init eco920_board_init(void)
        );
 
        at91_add_device_spi(eco920_spi_devices, ARRAY_SIZE(eco920_spi_devices));
+       /* LEDs */
+       at91_gpio_leds(eco920_leds, ARRAY_SIZE(eco920_leds));
 }
 
 MACHINE_START(ECO920, "eco920")
index 6cc83a87d77cf9422e958f9526720842de343cb9..fa98abacb1ba9ed18418ab107bdc27cbae645540 100644 (file)
@@ -75,12 +75,12 @@ static struct spi_board_info flexibity_spi_devices[] = {
 };
 
 /* MCI (SD/MMC) */
-static struct at91_mmc_data __initdata flexibity_mmc_data = {
-       .slot_b         = 0,
-       .wire4          = 1,
-       .det_pin        = AT91_PIN_PC9,
-       .wp_pin         = AT91_PIN_PC4,
-       .vcc_pin        = -EINVAL,
+static struct mci_platform_data __initdata flexibity_mci0_data = {
+       .slot[0] = {
+               .bus_width      = 4,
+               .detect_pin     = AT91_PIN_PC9,
+               .wp_pin         = AT91_PIN_PC4,
+       },
 };
 
 /* LEDs */
@@ -152,7 +152,7 @@ static void __init flexibity_board_init(void)
        at91_add_device_spi(flexibity_spi_devices,
                ARRAY_SIZE(flexibity_spi_devices));
        /* MMC */
-       at91_add_device_mmc(0, &flexibity_mmc_data);
+       at91_add_device_mci(0, &flexibity_mci0_data);
        /* LEDs */
        at91_gpio_leds(flexibity_leds, ARRAY_SIZE(flexibity_leds));
 }
index 69ab1247ef81263fb430de41d5c025263de5cb9e..6e47071d820639042fd3905437ee236b3b2b1d44 100644 (file)
@@ -86,7 +86,7 @@ static struct at91_udc_data __initdata foxg20_udc_data = {
  * SPI devices.
  */
 static struct spi_board_info foxg20_spi_devices[] = {
-#if !defined(CONFIG_MMC_AT91)
+#if !IS_ENABLED(CONFIG_MMC_ATMELMCI)
        {
                .modalias       = "mtd_dataflash",
                .chip_select    = 1,
@@ -109,12 +109,12 @@ static struct macb_platform_data __initdata foxg20_macb_data = {
  * MCI (SD/MMC)
  * det_pin, wp_pin and vcc_pin are not connected
  */
-static struct at91_mmc_data __initdata foxg20_mmc_data = {
-       .slot_b         = 1,
-       .wire4          = 1,
-       .det_pin        = -EINVAL,
-       .wp_pin         = -EINVAL,
-       .vcc_pin        = -EINVAL,
+static struct mci_platform_data __initdata foxg20_mci0_data = {
+       .slot[1] = {
+               .bus_width      = 4,
+               .detect_pin     = -EINVAL,
+               .wp_pin         = -EINVAL,
+       },
 };
 
 
@@ -247,7 +247,7 @@ static void __init foxg20_board_init(void)
        /* Ethernet */
        at91_add_device_eth(&foxg20_macb_data);
        /* MMC */
-       at91_add_device_mmc(0, &foxg20_mmc_data);
+       at91_add_device_mci(0, &foxg20_mci0_data);
        /* I2C */
        at91_add_device_i2c(foxg20_i2c_devices, ARRAY_SIZE(foxg20_i2c_devices));
        /* LEDs */
index 64c1dbf88a07bfe602f9c8c29071bff1ba5db774..86050da3ba53deb09efb650c019ebb03ee8ff6f0 100644 (file)
@@ -66,11 +66,20 @@ static struct at91_udc_data __initdata kafa_udc_data = {
        .pullup_pin     = AT91_PIN_PB7,
 };
 
+/*
+ * LEDs
+ */
+static struct gpio_led kafa_leds[] = {
+       {       /* D1 */
+               .name                   = "led1",
+               .gpio                   = AT91_PIN_PB4,
+               .active_low             = 1,
+               .default_trigger        = "heartbeat",
+       },
+};
+
 static void __init kafa_board_init(void)
 {
-       /* Set up the LEDs */
-       at91_init_leds(AT91_PIN_PB4, AT91_PIN_PB4);
-
        /* Serial */
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -88,6 +97,8 @@ static void __init kafa_board_init(void)
        at91_add_device_i2c(NULL, 0);
        /* SPI */
        at91_add_device_spi(NULL, 0);
+       /* LEDs */
+       at91_gpio_leds(kafa_leds, ARRAY_SIZE(kafa_leds));
 }
 
 MACHINE_START(KAFA, "Sperry-Sun KAFA")
index 5d96cb85175f9a6bce00c7b30ce12fa5d46b5821..abe9fed7a3e087b8fc1abe16d0c3731f702e665b 100644 (file)
@@ -69,12 +69,12 @@ static struct at91_udc_data __initdata kb9202_udc_data = {
        .pullup_pin     = AT91_PIN_PB22,
 };
 
-static struct at91_mmc_data __initdata kb9202_mmc_data = {
-       .det_pin        = AT91_PIN_PB2,
-       .slot_b         = 0,
-       .wire4          = 1,
-       .wp_pin         = -EINVAL,
-       .vcc_pin        = -EINVAL,
+static struct mci_platform_data __initdata kb9202_mci0_data = {
+       .slot[0] = {
+               .bus_width      = 4,
+               .detect_pin     = AT91_PIN_PB2,
+               .wp_pin         = -EINVAL,
+       },
 };
 
 static struct mtd_partition __initdata kb9202_nand_partition[] = {
@@ -96,11 +96,26 @@ static struct atmel_nand_data __initdata kb9202_nand_data = {
        .num_parts      = ARRAY_SIZE(kb9202_nand_partition),
 };
 
+/*
+ * LEDs
+ */
+static struct gpio_led kb9202_leds[] = {
+       {       /* D1 */
+               .name                   = "led1",
+               .gpio                   = AT91_PIN_PC19,
+               .active_low             = 1,
+               .default_trigger        = "heartbeat",
+       },
+       {       /* D2 */
+               .name                   = "led2",
+               .gpio                   = AT91_PIN_PC18,
+               .active_low             = 1,
+               .default_trigger        = "timer",
+       }
+};
+
 static void __init kb9202_board_init(void)
 {
-       /* Set up the LEDs */
-       at91_init_leds(AT91_PIN_PC19, AT91_PIN_PC18);
-
        /* Serial */
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -121,13 +136,15 @@ static void __init kb9202_board_init(void)
        /* USB Device */
        at91_add_device_udc(&kb9202_udc_data);
        /* MMC */
-       at91_add_device_mmc(0, &kb9202_mmc_data);
+       at91_add_device_mci(0, &kb9202_mci0_data);
        /* I2C */
        at91_add_device_i2c(NULL, 0);
        /* SPI */
        at91_add_device_spi(NULL, 0);
        /* NAND */
        at91_add_device_nand(&kb9202_nand_data);
+       /* LEDs */
+       at91_gpio_leds(kb9202_leds, ARRAY_SIZE(kb9202_leds));
 }
 
 MACHINE_START(KB9200, "KB920x")
index 18103c5d993ce24c148887d5bfc60331f4cb556d..9cda3fd346ae3e4657cf415b6dbe1e4040c20db5 100644 (file)
@@ -138,11 +138,12 @@ static struct spi_board_info neocore926_spi_devices[] = {
 /*
  * MCI (SD/MMC)
  */
-static struct at91_mmc_data __initdata neocore926_mmc_data = {
-       .wire4          = 1,
-       .det_pin        = AT91_PIN_PE18,
-       .wp_pin         = AT91_PIN_PE19,
-       .vcc_pin        = -EINVAL,
+static struct mci_platform_data __initdata neocore926_mci0_data = {
+       .slot[0] = {
+               .bus_width      = 4,
+               .detect_pin     = AT91_PIN_PE18,
+               .wp_pin         = AT91_PIN_PE19,
+       },
 };
 
 
@@ -354,7 +355,7 @@ static void __init neocore926_board_init(void)
        neocore926_add_device_ts();
 
        /* MMC */
-       at91_add_device_mmc(1, &neocore926_mmc_data);
+       at91_add_device_mci(0, &neocore926_mci0_data);
 
        /* Ethernet */
        at91_add_device_eth(&neocore926_macb_data);
index 127065504508c8fd5bffd4f00d778339fe497788..f83e1de699e626daec82ce5cd0307236b7d51174 100644 (file)
@@ -62,12 +62,12 @@ static struct at91_usbh_data __initdata picotux200_usbh_data = {
        .overcurrent_pin= {-EINVAL, -EINVAL},
 };
 
-static struct at91_mmc_data __initdata picotux200_mmc_data = {
-       .det_pin        = AT91_PIN_PB27,
-       .slot_b         = 0,
-       .wire4          = 1,
-       .wp_pin         = AT91_PIN_PA17,
-       .vcc_pin        = -EINVAL,
+static struct mci_platform_data __initdata picotux200_mci0_data = {
+       .slot[0] = {
+               .bus_width      = 4,
+               .detect_pin     = AT91_PIN_PB27,
+               .wp_pin         = AT91_PIN_PA17,
+       },
 };
 
 #define PICOTUX200_FLASH_BASE  AT91_CHIPSELECT_0
@@ -112,7 +112,7 @@ static void __init picotux200_board_init(void)
        at91_add_device_i2c(NULL, 0);
        /* MMC */
        at91_set_gpio_output(AT91_PIN_PB22, 1); /* this MMC card slot can optionally use SPI signaling (CS3). */
-       at91_add_device_mmc(0, &picotux200_mmc_data);
+       at91_add_device_mci(0, &picotux200_mci0_data);
        /* NOR Flash */
        platform_device_register(&picotux200_flash);
 }
index bf351e285422684cc71644e090ea428c766c556b..799f214edebe5a82a20a5a2af44eb6bef98afca8 100644 (file)
@@ -156,12 +156,12 @@ static void __init ek_add_device_nand(void)
 /*
  * MCI (SD/MMC)
  */
-static struct at91_mmc_data __initdata ek_mmc_data = {
-       .slot_b         = 0,
-       .wire4          = 1,
-       .det_pin        = -EINVAL,
-       .wp_pin         = -EINVAL,
-       .vcc_pin        = -EINVAL,
+static struct mci_platform_data __initdata ek_mci0_data = {
+       .slot[0] = {
+               .bus_width      = 4,
+               .detect_pin     = -EINVAL,
+               .wp_pin         = -EINVAL,
+       },
 };
 
 /*
@@ -245,7 +245,7 @@ static void __init ek_board_init(void)
        /* Ethernet */
        at91_add_device_eth(&ek_macb_data);
        /* MMC */
-       at91_add_device_mmc(0, &ek_mmc_data);
+       at91_add_device_mci(0, &ek_mci0_data);
        /* Push Buttons */
        ek_add_device_buttons();
        /* LEDs */
index cc2bf9796073bcb096883059c7cced4153287a91..66338e7ebfba69b1ce5f6b3b1fe669cbffb7c8fe 100644 (file)
@@ -77,12 +77,12 @@ static struct at91_cf_data __initdata dk_cf_data = {
 };
 
 #ifndef CONFIG_MTD_AT91_DATAFLASH_CARD
-static struct at91_mmc_data __initdata dk_mmc_data = {
-       .slot_b         = 0,
-       .wire4          = 1,
-       .det_pin        = -EINVAL,
-       .wp_pin         = -EINVAL,
-       .vcc_pin        = -EINVAL,
+static struct mci_platform_data __initdata dk_mci0_data = {
+       .slot[0] = {
+               .bus_width      = 4,
+               .detect_pin     = -EINVAL,
+               .wp_pin         = -EINVAL,
+       },
 };
 #endif
 
@@ -177,9 +177,6 @@ static struct gpio_led dk_leds[] = {
 
 static void __init dk_board_init(void)
 {
-       /* Setup the LEDs */
-       at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2);
-
        /* Serial */
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -208,7 +205,7 @@ static void __init dk_board_init(void)
 #else
        /* MMC */
        at91_set_gpio_output(AT91_PIN_PB7, 1);  /* this MMC card slot can optionally use SPI signaling (CS3). */
-       at91_add_device_mmc(0, &dk_mmc_data);
+       at91_add_device_mci(0, &dk_mci0_data);
 #endif
        /* NAND */
        at91_add_device_nand(&dk_nand_data);
index 62e19e64c9d3f52dc0d5ca8e2470dfe9cfc1918e..5d1b5729dc69189d7a98589505d6221100f08cff 100644 (file)
@@ -70,12 +70,12 @@ static struct at91_udc_data __initdata ek_udc_data = {
 };
 
 #ifndef CONFIG_MTD_AT91_DATAFLASH_CARD
-static struct at91_mmc_data __initdata ek_mmc_data = {
-       .det_pin        = AT91_PIN_PB27,
-       .slot_b         = 0,
-       .wire4          = 1,
-       .wp_pin         = AT91_PIN_PA17,
-       .vcc_pin        = -EINVAL,
+static struct mci_platform_data __initdata ek_mci0_data = {
+       .slot[0] = {
+               .bus_width      = 4,
+               .detect_pin     = AT91_PIN_PB27,
+               .wp_pin         = AT91_PIN_PA17,
+       }
 };
 #endif
 
@@ -148,9 +148,6 @@ static struct gpio_led ek_leds[] = {
 
 static void __init ek_board_init(void)
 {
-       /* Setup the LEDs */
-       at91_init_leds(AT91_PIN_PB1, AT91_PIN_PB2);
-
        /* Serial */
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -177,7 +174,7 @@ static void __init ek_board_init(void)
 #else
        /* MMC */
        at91_set_gpio_output(AT91_PIN_PB22, 1); /* this MMC card slot can optionally use SPI signaling (CS3). */
-       at91_add_device_mmc(0, &ek_mmc_data);
+       at91_add_device_mci(0, &ek_mci0_data);
 #endif
        /* NOR Flash */
        platform_device_register(&ek_flash);
index c3b43aefdb7597d2f71dc5e8e40e054019b891f6..a0ecf04e9ae3d233a94dab1ddf90749a5272f2dc 100644 (file)
@@ -58,11 +58,12 @@ static struct at91_usbh_data rsi_ews_usbh_data __initdata = {
 /*
  * SD/MC
  */
-static struct at91_mmc_data rsi_ews_mmc_data __initdata = {
-       .slot_b         = 0,
-       .wire4          = 1,
-       .det_pin        = AT91_PIN_PB27,
-       .wp_pin         = AT91_PIN_PB29,
+static struct mci_platform_data __initdata rsi_ews_mci0_data = {
+       .slot[0] = {
+               .bus_width      = 4,
+               .detect_pin     = AT91_PIN_PB27,
+               .wp_pin         = AT91_PIN_PB29,
+       },
 };
 
 /*
@@ -185,9 +186,6 @@ static struct platform_device rsiews_nor_flash = {
  */
 static void __init rsi_ews_board_init(void)
 {
-       /* Setup the LEDs */
-       at91_init_leds(AT91_PIN_PB6, AT91_PIN_PB9);
-
        /* Serial */
        /* DBGU on ttyS0. (Rx & Tx only) */
        /* This one is for debugging */
@@ -215,7 +213,7 @@ static void __init rsi_ews_board_init(void)
        at91_add_device_spi(rsi_ews_spi_devices,
                        ARRAY_SIZE(rsi_ews_spi_devices));
        /* MMC */
-       at91_add_device_mmc(0, &rsi_ews_mmc_data);
+       at91_add_device_mci(0, &rsi_ews_mci0_data);
        /* NOR Flash */
        platform_device_register(&rsiews_nor_flash);
        /* LEDs */
index 7bf6da70d7d56bbe735156f5c72add8a5441338b..c5f01acce3c03bb057f5df5c460b92f466185fac 100644 (file)
@@ -73,7 +73,7 @@ static struct at91_udc_data __initdata ek_udc_data = {
  * SPI devices.
  */
 static struct spi_board_info ek_spi_devices[] = {
-#if !defined(CONFIG_MMC_AT91)
+#if !IS_ENABLED(CONFIG_MMC_ATMELMCI)
        {       /* DataFlash chip */
                .modalias       = "mtd_dataflash",
                .chip_select    = 1,
@@ -158,19 +158,34 @@ static void __init ek_add_device_nand(void)
 /*
  * MCI (SD/MMC)
  */
-static struct at91_mmc_data __initdata ek_mmc_data = {
-       .slot_b         = 1,
-       .wire4          = 1,
-       .det_pin        = AT91_PIN_PC8,
-       .wp_pin         = AT91_PIN_PC4,
-       .vcc_pin        = -EINVAL,
+static struct mci_platform_data __initdata ek_mci0_data = {
+       .slot[1] = {
+               .bus_width      = 4,
+               .detect_pin     = AT91_PIN_PC8,
+               .wp_pin         = AT91_PIN_PC4,
+       },
+};
+
+/*
+ * LEDs
+ */
+static struct gpio_led ek_leds[] = {
+       {       /* D1 */
+               .name                   = "led1",
+               .gpio                   = AT91_PIN_PA9,
+               .active_low             = 1,
+               .default_trigger        = "heartbeat",
+       },
+       {       /* D2 */
+               .name                   = "led2",
+               .gpio                   = AT91_PIN_PA6,
+               .active_low             = 1,
+               .default_trigger        = "timer",
+       }
 };
 
 static void __init ek_board_init(void)
 {
-       /* Setup the LEDs */
-       at91_init_leds(AT91_PIN_PA9, AT91_PIN_PA6);
-
        /* Serial */
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -194,9 +209,11 @@ static void __init ek_board_init(void)
        /* Ethernet */
        at91_add_device_eth(&ek_macb_data);
        /* MMC */
-       at91_add_device_mmc(0, &ek_mmc_data);
+       at91_add_device_mci(0, &ek_mci0_data);
        /* I2C */
        at91_add_device_i2c(NULL, 0);
+       /* LEDs */
+       at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
 }
 
 MACHINE_START(SAM9_L9260, "Olimex SAM9-L9260")
index 889c1bf71eb596d2efd28fc76d086f2d87a42b9d..8cd6e679fbe071d9269d710b214197388209373c 100644 (file)
@@ -108,7 +108,7 @@ static void __init at73c213_set_clk(struct at73c213_board_info *info) {}
  * SPI devices.
  */
 static struct spi_board_info ek_spi_devices[] = {
-#if !defined(CONFIG_MMC_AT91)
+#if !IS_ENABLED(CONFIG_MMC_ATMELMCI)
        {       /* DataFlash chip */
                .modalias       = "mtd_dataflash",
                .chip_select    = 1,
@@ -211,12 +211,12 @@ static void __init ek_add_device_nand(void)
 /*
  * MCI (SD/MMC)
  */
-static struct at91_mmc_data __initdata ek_mmc_data = {
-       .slot_b         = 1,
-       .wire4          = 1,
-       .det_pin        = -EINVAL,
-       .wp_pin         = -EINVAL,
-       .vcc_pin        = -EINVAL,
+static struct mci_platform_data __initdata ek_mci0_data = {
+       .slot[1] = {
+               .bus_width      = 4,
+               .detect_pin     = -EINVAL,
+               .wp_pin         = -EINVAL,
+       },
 };
 
 
@@ -329,7 +329,7 @@ static void __init ek_board_init(void)
        /* Ethernet */
        at91_add_device_eth(&ek_macb_data);
        /* MMC */
-       at91_add_device_mmc(0, &ek_mmc_data);
+       at91_add_device_mci(0, &ek_mci0_data);
        /* I2C */
        at91_add_device_i2c(ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));
        /* SSC (to AT73C213) */
index 2269be5fa3841075539fd106746ce7c7cc88776d..27b3af1a3047e4bcf209e602f1fcc23a1561de0d 100644 (file)
@@ -340,11 +340,12 @@ static struct spi_board_info ek_spi_devices[] = {
  * MCI (SD/MMC)
  * det_pin, wp_pin and vcc_pin are not connected
  */
-static struct at91_mmc_data __initdata ek_mmc_data = {
-       .wire4          = 1,
-       .det_pin        = -EINVAL,
-       .wp_pin         = -EINVAL,
-       .vcc_pin        = -EINVAL,
+static struct mci_platform_data __initdata mci0_data = {
+       .slot[0] = {
+               .bus_width      = 4,
+               .detect_pin     = -EINVAL,
+               .wp_pin         = -EINVAL,
+       },
 };
 
 #endif /* CONFIG_SPI_ATMEL_* */
@@ -569,9 +570,6 @@ static struct gpio_led ek_leds[] = {
 
 static void __init ek_board_init(void)
 {
-       /* Setup the LEDs */
-       at91_init_leds(AT91_PIN_PA13, AT91_PIN_PA14);
-
        /* Serial */
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -598,7 +596,7 @@ static void __init ek_board_init(void)
        at91_add_device_ssc(AT91SAM9261_ID_SSC1, ATMEL_SSC_TX);
 #else
        /* MMC */
-       at91_add_device_mmc(0, &ek_mmc_data);
+       at91_add_device_mci(0, &mci0_data);
 #endif
        /* LCD Controller */
        at91_add_device_lcdc(&ek_lcdc_data);
index 82adf581afc2eb48868ea1d3198685bff22d457a..073e17403d982dad660126f0323754d0b36532c4 100644 (file)
@@ -141,11 +141,12 @@ static struct spi_board_info ek_spi_devices[] = {
 /*
  * MCI (SD/MMC)
  */
-static struct at91_mmc_data __initdata ek_mmc_data = {
-       .wire4          = 1,
-       .det_pin        = AT91_PIN_PE18,
-       .wp_pin         = AT91_PIN_PE19,
-       .vcc_pin        = -EINVAL,
+static struct mci_platform_data __initdata mci1_data = {
+       .slot[0] = {
+               .bus_width      = 4,
+               .detect_pin     = AT91_PIN_PE18,
+               .wp_pin         = AT91_PIN_PE19,
+       },
 };
 
 
@@ -420,7 +421,7 @@ static void __init ek_board_init(void)
        /* Touchscreen */
        ek_add_device_ts();
        /* MMC */
-       at91_add_device_mmc(1, &ek_mmc_data);
+       at91_add_device_mci(1, &mci1_data);
        /* Ethernet */
        at91_add_device_eth(&ek_macb_data);
        /* NAND */
index 4ea4ee00364b44fd2fe1ef693d72e08e57a734e9..3ab2b86a3762a67da9b808386d39c51fb8cd2544 100644 (file)
@@ -92,7 +92,7 @@ static struct at91_udc_data __initdata ek_udc_data = {
  * SPI devices.
  */
 static struct spi_board_info ek_spi_devices[] = {
-#if !(defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_AT91))
+#if !IS_ENABLED(CONFIG_MMC_ATMELMCI)
        {       /* DataFlash chip */
                .modalias       = "mtd_dataflash",
                .chip_select    = 1,
@@ -199,7 +199,6 @@ static void __init ek_add_device_nand(void)
  * MCI (SD/MMC)
  * wp_pin and vcc_pin are not connected
  */
-#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
 static struct mci_platform_data __initdata ek_mmc_data = {
        .slot[1] = {
                .bus_width      = 4,
@@ -208,28 +207,15 @@ static struct mci_platform_data __initdata ek_mmc_data = {
        },
 
 };
-#else
-static struct at91_mmc_data __initdata ek_mmc_data = {
-       .slot_b         = 1,    /* Only one slot so use slot B */
-       .wire4          = 1,
-       .det_pin        = AT91_PIN_PC9,
-       .wp_pin         = -EINVAL,
-       .vcc_pin        = -EINVAL,
-};
-#endif
 
 static void __init ek_add_device_mmc(void)
 {
-#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
        if (ek_have_2mmc()) {
                ek_mmc_data.slot[0].bus_width = 4;
                ek_mmc_data.slot[0].detect_pin = AT91_PIN_PC2;
                ek_mmc_data.slot[0].wp_pin = -1;
        }
        at91_add_device_mci(0, &ek_mmc_data);
-#else
-       at91_add_device_mmc(0, &ek_mmc_data);
-#endif
 }
 
 /*
index e7dc3ead7045f3f938c65729263a71be5050dafb..fb89ea92e3f24bc0f52934c18aec7528b43c643d 100644 (file)
@@ -56,11 +56,12 @@ static struct usba_platform_data __initdata ek_usba_udc_data = {
 /*
  * MCI (SD/MMC)
  */
-static struct at91_mmc_data __initdata ek_mmc_data = {
-       .wire4          = 1,
-       .det_pin        = AT91_PIN_PA15,
-       .wp_pin         = -EINVAL,
-       .vcc_pin        = -EINVAL,
+static struct mci_platform_data __initdata mci0_data = {
+       .slot[0] = {
+               .bus_width      = 4,
+               .detect_pin     = AT91_PIN_PA15,
+               .wp_pin         = -EINVAL,
+       },
 };
 
 
@@ -303,7 +304,7 @@ static void __init ek_board_init(void)
        /* SPI */
        at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
        /* MMC */
-       at91_add_device_mmc(0, &ek_mmc_data);
+       at91_add_device_mci(0, &mci0_data);
        /* LCD Controller */
        at91_add_device_lcdc(&ek_lcdc_data);
        /* AC97 */
index 29eae1626bf79ffa1ca4c4bf562d6ef255b81f82..c3fb31d5116e95daa3125974546b3628ad3770c9 100644 (file)
@@ -83,7 +83,6 @@ static void __init add_device_nand(void)
  * MCI (SD/MMC)
  * det_pin, wp_pin and vcc_pin are not connected
  */
-#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
 static struct mci_platform_data __initdata mmc_data = {
        .slot[0] = {
                .bus_width      = 4,
@@ -91,15 +90,6 @@ static struct mci_platform_data __initdata mmc_data = {
                .wp_pin         = -1,
        },
 };
-#else
-static struct at91_mmc_data __initdata mmc_data = {
-       .slot_b         = 0,
-       .wire4          = 1,
-       .det_pin        = -EINVAL,
-       .wp_pin         = -EINVAL,
-       .vcc_pin        = -EINVAL,
-};
-#endif
 
 
 /*
@@ -223,11 +213,7 @@ void __init stamp9g20_board_init(void)
        /* NAND */
        add_device_nand();
        /* MMC */
-#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
        at91_add_device_mci(0, &mmc_data);
-#else
-       at91_add_device_mmc(0, &mmc_data);
-#endif
        /* W1 */
        add_w1();
 }
index c1476b9fe7b91a98ef279e4be2ecd250300bb1fc..6ea069b5733584b5a0fc68dd2cc61665763258c9 100644 (file)
@@ -109,14 +109,12 @@ static struct mmc_spi_platform_data at91_mmc_spi_pdata = {
  * SPI devices.
  */
 static struct spi_board_info usb_a9263_spi_devices[] = {
-#if !defined(CONFIG_MMC_AT91)
        {       /* DataFlash chip */
                .modalias       = "mtd_dataflash",
                .chip_select    = 0,
                .max_speed_hz   = 15 * 1000 * 1000,
                .bus_num        = 0,
        }
-#endif
 };
 
 static struct spi_board_info usb_a9g20_spi_devices[] = {
index 516d340549d8db4c4ffe0a5ff461aee9cb7e6175..f162fdfd66ebda1f9df3ce1f4c747eadb60656ea 100644 (file)
@@ -119,11 +119,12 @@ static struct at91_udc_data __initdata yl9200_udc_data = {
 /*
  * MMC
  */
-static struct at91_mmc_data __initdata yl9200_mmc_data = {
-       .det_pin        = AT91_PIN_PB9,
-       .wire4          = 1,
-       .wp_pin         = -EINVAL,
-       .vcc_pin        = -EINVAL,
+static struct mci_platform_data __initdata yl9200_mci0_data = {
+       .slot[0] = {
+               .bus_width      = 4,
+               .detect_pin     = AT91_PIN_PB9,
+               .wp_pin         = -EINVAL,
+       },
 };
 
 /*
@@ -541,9 +542,6 @@ void __init yl9200_add_device_video(void) {}
 
 static void __init yl9200_board_init(void)
 {
-       /* Setup the LEDs D2=PB17 (timer), D3=PB16 (cpu) */
-       at91_init_leds(AT91_PIN_PB16, AT91_PIN_PB17);
-
        /* Serial */
        /* DBGU on ttyS0. (Rx & Tx only) */
        at91_register_uart(0, 0, 0);
@@ -568,7 +566,7 @@ static void __init yl9200_board_init(void)
        /* I2C */
        at91_add_device_i2c(yl9200_i2c_devices, ARRAY_SIZE(yl9200_i2c_devices));
        /* MMC */
-       at91_add_device_mmc(0, &yl9200_mmc_data);
+       at91_add_device_mci(0, &yl9200_mci0_data);
        /* NAND */
        at91_add_device_nand(&yl9200_nand_data);
        /* NOR Flash */
index 369afc2ffc5b972934872aa9266c8a8b774e9bec..c55a4364ffb433867aa150485880f7467081625f 100644 (file)
@@ -187,7 +187,6 @@ struct at91_can_data {
 extern void __init at91_add_device_can(struct at91_can_data *data);
 
  /* LEDs */
-extern void __init at91_init_leds(u8 cpu_led, u8 timer_led);
 extern void __init at91_gpio_leds(struct gpio_led *leds, int nr);
 extern void __init at91_pwm_leds(struct gpio_led *leds, int nr);
 
index 8dfafe76ffe6298f822ad2b4d3ea64ebf0243337..1b1e62b5f41be1e8b3249cb0961c19b43bbcf417 100644 (file)
@@ -90,108 +90,3 @@ void __init at91_pwm_leds(struct gpio_led *leds, int nr)
 #else
 void __init at91_pwm_leds(struct gpio_led *leds, int nr){}
 #endif
-
-
-/* ------------------------------------------------------------------------- */
-
-#if defined(CONFIG_LEDS)
-
-#include <asm/leds.h>
-
-/*
- * Old ARM-specific LED framework; not fully functional when generic time is
- * in use.
- */
-
-static u8 at91_leds_cpu;
-static u8 at91_leds_timer;
-
-static inline void at91_led_on(unsigned int led)
-{
-       at91_set_gpio_value(led, 0);
-}
-
-static inline void at91_led_off(unsigned int led)
-{
-       at91_set_gpio_value(led, 1);
-}
-
-static inline void at91_led_toggle(unsigned int led)
-{
-       unsigned long is_off = at91_get_gpio_value(led);
-       if (is_off)
-               at91_led_on(led);
-       else
-               at91_led_off(led);
-}
-
-
-/*
- * Handle LED events.
- */
-static void at91_leds_event(led_event_t evt)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-
-       switch(evt) {
-       case led_start:         /* System startup */
-               at91_led_on(at91_leds_cpu);
-               break;
-
-       case led_stop:          /* System stop / suspend */
-               at91_led_off(at91_leds_cpu);
-               break;
-
-#ifdef CONFIG_LEDS_TIMER
-       case led_timer:         /* Every 50 timer ticks */
-               at91_led_toggle(at91_leds_timer);
-               break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-       case led_idle_start:    /* Entering idle state */
-               at91_led_off(at91_leds_cpu);
-               break;
-
-       case led_idle_end:      /* Exit idle state */
-               at91_led_on(at91_leds_cpu);
-               break;
-#endif
-
-       default:
-               break;
-       }
-
-       local_irq_restore(flags);
-}
-
-
-static int __init leds_init(void)
-{
-       if (!at91_leds_timer || !at91_leds_cpu)
-               return -ENODEV;
-
-       leds_event = at91_leds_event;
-
-       leds_event(led_start);
-       return 0;
-}
-
-__initcall(leds_init);
-
-
-void __init at91_init_leds(u8 cpu_led, u8 timer_led)
-{
-       /* Enable GPIO to access the LEDs */
-       at91_set_gpio_output(cpu_led, 1);
-       at91_set_gpio_output(timer_led, 1);
-
-       at91_leds_cpu   = cpu_led;
-       at91_leds_timer = timer_led;
-}
-
-#else
-void __init at91_init_leds(u8 cpu_led, u8 timer_led) {}
-#endif
index 45c97b1ee9b1d59ba923a69b50e94337b48da993..c18a5048b6c5e5974437932c7b78e83c4c28f25f 100644 (file)
@@ -29,7 +29,6 @@
 #include <asm/setup.h>
 #include <asm/mach-types.h>
 #include <asm/mach/time.h>
-#include <asm/pmu.h>
 
 #include <asm/mach/arch.h>
 #include <mach/dma.h>
@@ -38,7 +37,7 @@
 #include <mach/csp/chipcHw_def.h>
 #include <mach/csp/chipcHw_inline.h>
 
-#include <cfg_global.h>
+#include <mach/cfg_global.h>
 
 #include "core.h"
 
@@ -116,7 +115,7 @@ static struct resource pmu_resource = {
 
 static struct platform_device pmu_device = {
        .name           = "arm-pmu",
-       .id             = ARM_PMU_DEVICE_CPU,
+       .id             = -1,
        .resource       = &pmu_resource,
        .num_resources  = 1,
 };
index adbfb1994582ee1352a511501279f5b58c378bfc..4b50228a67714de4b7f3a47f3c890b6be4767a9d 100644 (file)
 #include <asm/mach/time.h>
 #include <asm/mach/map.h>
 
-#include <cfg_global.h>
+#include <mach/cfg_global.h>
 
 #include "clock.h"
 
-#include <csp/secHw.h>
 #include <mach/csp/secHw_def.h>
 #include <mach/csp/chipcHw_inline.h>
 #include <mach/csp/tmrHw_reg.h>
index 96273ff349562b58ef62c1840d1fa4ac945d21d8..5050833817b7b6db05ee6c1635e3e3ba720a8b0d 100644 (file)
 
 /* ---- Include Files ---------------------------------------------------- */
 
-#include <csp/errno.h>
-#include <csp/stdint.h>
-#include <csp/module.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/export.h>
 
 #include <mach/csp/chipcHw_def.h>
 #include <mach/csp/chipcHw_inline.h>
 
-#include <csp/reg.h>
-#include <csp/delay.h>
+#include <mach/csp/reg.h>
+#include <linux/delay.h>
 
 /* ---- Private Constants and Types --------------------------------------- */
 
@@ -61,21 +61,21 @@ static int chipcHw_divide(int num, int denom)
 /****************************************************************************/
 chipcHw_freq chipcHw_getClockFrequency(chipcHw_CLOCK_e clock   /*  [ IN ] Configurable clock */
     ) {
-       volatile uint32_t *pPLLReg = (uint32_t *) 0x0;
-       volatile uint32_t *pClockCtrl = (uint32_t *) 0x0;
-       volatile uint32_t *pDependentClock = (uint32_t *) 0x0;
+       uint32_t __iomem *pPLLReg = NULL;
+       uint32_t __iomem *pClockCtrl = NULL;
+       uint32_t __iomem *pDependentClock = NULL;
        uint32_t vcoFreqPll1Hz = 0;     /* Effective VCO frequency for PLL1 in Hz */
        uint32_t vcoFreqPll2Hz = 0;     /* Effective VCO frequency for PLL2 in Hz */
        uint32_t dependentClockType = 0;
        uint32_t vcoHz = 0;
 
        /* Get VCO frequencies */
-       if ((pChipcHw->PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_MASK) != chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_INTEGER) {
+       if ((readl(&pChipcHw->PLLPreDivider) & chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_MASK) != chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_INTEGER) {
                uint64_t adjustFreq = 0;
 
                vcoFreqPll1Hz = chipcHw_XTAL_FREQ_Hz *
                    chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, chipcHw_REG_PLL_PREDIVIDER_P2) *
-                   ((pChipcHw->PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
+                   ((readl(&pChipcHw->PLLPreDivider) & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
                     chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT);
 
                /* Adjusted frequency due to chipcHw_REG_PLL_DIVIDER_NDIV_f_SS */
@@ -86,13 +86,13 @@ chipcHw_freq chipcHw_getClockFrequency(chipcHw_CLOCK_e clock        /*  [ IN ] Configur
        } else {
                vcoFreqPll1Hz = chipcHw_XTAL_FREQ_Hz *
                    chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, chipcHw_REG_PLL_PREDIVIDER_P2) *
-                   ((pChipcHw->PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
+                   ((readl(&pChipcHw->PLLPreDivider) & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
                     chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT);
        }
        vcoFreqPll2Hz =
            chipcHw_XTAL_FREQ_Hz *
                 chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, chipcHw_REG_PLL_PREDIVIDER_P2) *
-           ((pChipcHw->PLLPreDivider2 & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
+           ((readl(&pChipcHw->PLLPreDivider2) & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
             chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT);
 
        switch (clock) {
@@ -187,51 +187,51 @@ chipcHw_freq chipcHw_getClockFrequency(chipcHw_CLOCK_e clock      /*  [ IN ] Configur
 
        if (pPLLReg) {
                /* Obtain PLL clock frequency */
-               if (*pPLLReg & chipcHw_REG_PLL_CLOCK_BYPASS_SELECT) {
+               if (readl(pPLLReg) & chipcHw_REG_PLL_CLOCK_BYPASS_SELECT) {
                        /* Return crystal clock frequency when bypassed */
                        return chipcHw_XTAL_FREQ_Hz;
                } else if (clock == chipcHw_CLOCK_DDR) {
                        /* DDR frequency is configured in PLLDivider register */
-                       return chipcHw_divide (vcoHz, (((pChipcHw->PLLDivider & 0xFF000000) >> 24) ? ((pChipcHw->PLLDivider & 0xFF000000) >> 24) : 256));
+                       return chipcHw_divide (vcoHz, (((readl(&pChipcHw->PLLDivider) & 0xFF000000) >> 24) ? ((readl(&pChipcHw->PLLDivider) & 0xFF000000) >> 24) : 256));
                } else {
                        /* From chip revision number B0, LCD clock is internally divided by 2 */
                        if ((pPLLReg == &pChipcHw->LCDClock) && (chipcHw_getChipRevisionNumber() != chipcHw_REV_NUMBER_A0)) {
                                vcoHz >>= 1;
                        }
                        /* Obtain PLL clock frequency using VCO dividers */
-                       return chipcHw_divide(vcoHz, ((*pPLLReg & chipcHw_REG_PLL_CLOCK_MDIV_MASK) ? (*pPLLReg & chipcHw_REG_PLL_CLOCK_MDIV_MASK) : 256));
+                       return chipcHw_divide(vcoHz, ((readl(pPLLReg) & chipcHw_REG_PLL_CLOCK_MDIV_MASK) ?  (readl(pPLLReg) & chipcHw_REG_PLL_CLOCK_MDIV_MASK) : 256));
                }
        } else if (pClockCtrl) {
                /* Obtain divider clock frequency */
                uint32_t div;
                uint32_t freq = 0;
 
-               if (*pClockCtrl & chipcHw_REG_DIV_CLOCK_BYPASS_SELECT) {
+               if (readl(pClockCtrl) & chipcHw_REG_DIV_CLOCK_BYPASS_SELECT) {
                        /* Return crystal clock frequency when bypassed */
                        return chipcHw_XTAL_FREQ_Hz;
                } else if (pDependentClock) {
                        /* Identify the dependent clock frequency */
                        switch (dependentClockType) {
                        case PLL_CLOCK:
-                               if (*pDependentClock & chipcHw_REG_PLL_CLOCK_BYPASS_SELECT) {
+                               if (readl(pDependentClock) & chipcHw_REG_PLL_CLOCK_BYPASS_SELECT) {
                                        /* Use crystal clock frequency when dependent PLL clock is bypassed */
                                        freq = chipcHw_XTAL_FREQ_Hz;
                                } else {
                                        /* Obtain PLL clock frequency using VCO dividers */
-                                       div = *pDependentClock & chipcHw_REG_PLL_CLOCK_MDIV_MASK;
+                                       div = readl(pDependentClock) & chipcHw_REG_PLL_CLOCK_MDIV_MASK;
                                        freq = div ? chipcHw_divide(vcoHz, div) : 0;
                                }
                                break;
                        case NON_PLL_CLOCK:
-                               if (pDependentClock == (uint32_t *) &pChipcHw->ACLKClock) {
+                               if (pDependentClock == &pChipcHw->ACLKClock) {
                                        freq = chipcHw_getClockFrequency (chipcHw_CLOCK_BUS);
                                } else {
-                                       if (*pDependentClock & chipcHw_REG_DIV_CLOCK_BYPASS_SELECT) {
+                                       if (readl(pDependentClock) & chipcHw_REG_DIV_CLOCK_BYPASS_SELECT) {
                                                /* Use crystal clock frequency when dependent divider clock is bypassed */
                                                freq = chipcHw_XTAL_FREQ_Hz;
                                        } else {
                                                /* Obtain divider clock frequency using XTAL dividers */
-                                               div = *pDependentClock & chipcHw_REG_DIV_CLOCK_DIV_MASK;
+                                               div = readl(pDependentClock) & chipcHw_REG_DIV_CLOCK_DIV_MASK;
                                                freq = chipcHw_divide (chipcHw_XTAL_FREQ_Hz, (div ? div : 256));
                                        }
                                }
@@ -242,7 +242,7 @@ chipcHw_freq chipcHw_getClockFrequency(chipcHw_CLOCK_e clock        /*  [ IN ] Configur
                        freq = chipcHw_XTAL_FREQ_Hz;
                }
 
-               div = *pClockCtrl & chipcHw_REG_DIV_CLOCK_DIV_MASK;
+               div = readl(pClockCtrl) & chipcHw_REG_DIV_CLOCK_DIV_MASK;
                return chipcHw_divide(freq, (div ? div : 256));
        }
        return 0;
@@ -261,9 +261,9 @@ chipcHw_freq chipcHw_getClockFrequency(chipcHw_CLOCK_e clock        /*  [ IN ] Configur
 chipcHw_freq chipcHw_setClockFrequency(chipcHw_CLOCK_e clock,  /*  [ IN ] Configurable clock */
                                       uint32_t freq    /*  [ IN ] Clock frequency in Hz */
     ) {
-       volatile uint32_t *pPLLReg = (uint32_t *) 0x0;
-       volatile uint32_t *pClockCtrl = (uint32_t *) 0x0;
-       volatile uint32_t *pDependentClock = (uint32_t *) 0x0;
+       uint32_t __iomem *pPLLReg = NULL;
+       uint32_t __iomem *pClockCtrl = NULL;
+       uint32_t __iomem *pDependentClock = NULL;
        uint32_t vcoFreqPll1Hz = 0;     /* Effective VCO frequency for PLL1 in Hz */
        uint32_t desVcoFreqPll1Hz = 0;  /* Desired VCO frequency for PLL1 in Hz */
        uint32_t vcoFreqPll2Hz = 0;     /* Effective VCO frequency for PLL2 in Hz */
@@ -272,12 +272,12 @@ chipcHw_freq chipcHw_setClockFrequency(chipcHw_CLOCK_e clock,     /*  [ IN ] Configu
        uint32_t desVcoHz = 0;
 
        /* Get VCO frequencies */
-       if ((pChipcHw->PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_MASK) != chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_INTEGER) {
+       if ((readl(&pChipcHw->PLLPreDivider) & chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_MASK) != chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_INTEGER) {
                uint64_t adjustFreq = 0;
 
                vcoFreqPll1Hz = chipcHw_XTAL_FREQ_Hz *
                    chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, chipcHw_REG_PLL_PREDIVIDER_P2) *
-                   ((pChipcHw->PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
+                   ((readl(&pChipcHw->PLLPreDivider) & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
                     chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT);
 
                /* Adjusted frequency due to chipcHw_REG_PLL_DIVIDER_NDIV_f_SS */
@@ -289,16 +289,16 @@ chipcHw_freq chipcHw_setClockFrequency(chipcHw_CLOCK_e clock,     /*  [ IN ] Configu
                /* Desired VCO frequency */
                desVcoFreqPll1Hz = chipcHw_XTAL_FREQ_Hz *
                    chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, chipcHw_REG_PLL_PREDIVIDER_P2) *
-                   (((pChipcHw->PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
+                   (((readl(&pChipcHw->PLLPreDivider) & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
                      chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT) + 1);
        } else {
                vcoFreqPll1Hz = desVcoFreqPll1Hz = chipcHw_XTAL_FREQ_Hz *
                    chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, chipcHw_REG_PLL_PREDIVIDER_P2) *
-                   ((pChipcHw->PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
+                   ((readl(&pChipcHw->PLLPreDivider) & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
                     chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT);
        }
        vcoFreqPll2Hz = chipcHw_XTAL_FREQ_Hz * chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, chipcHw_REG_PLL_PREDIVIDER_P2) *
-           ((pChipcHw->PLLPreDivider2 & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
+           ((readl(&pChipcHw->PLLPreDivider2) & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
             chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT);
 
        switch (clock) {
@@ -307,8 +307,7 @@ chipcHw_freq chipcHw_setClockFrequency(chipcHw_CLOCK_e clock,       /*  [ IN ] Configu
                {
                        REG_LOCAL_IRQ_SAVE;
                        /* Dvide DDR_phy by two to obtain DDR_ctrl clock */
-                       pChipcHw->DDRClock = (pChipcHw->DDRClock & ~chipcHw_REG_PLL_CLOCK_TO_BUS_RATIO_MASK) | ((((freq / 2) / chipcHw_getClockFrequency(chipcHw_CLOCK_BUS)) - 1)
-                               << chipcHw_REG_PLL_CLOCK_TO_BUS_RATIO_SHIFT);
+                       writel((readl(&pChipcHw->DDRClock) & ~chipcHw_REG_PLL_CLOCK_TO_BUS_RATIO_MASK) | ((((freq / 2) / chipcHw_getClockFrequency(chipcHw_CLOCK_BUS)) - 1) << chipcHw_REG_PLL_CLOCK_TO_BUS_RATIO_SHIFT), &pChipcHw->DDRClock);
                        REG_LOCAL_IRQ_RESTORE;
                }
                pPLLReg = &pChipcHw->DDRClock;
@@ -329,8 +328,7 @@ chipcHw_freq chipcHw_setClockFrequency(chipcHw_CLOCK_e clock,       /*  [ IN ] Configu
                /* Configure the VPM:BUS ratio settings */
                {
                        REG_LOCAL_IRQ_SAVE;
-                       pChipcHw->VPMClock = (pChipcHw->VPMClock & ~chipcHw_REG_PLL_CLOCK_TO_BUS_RATIO_MASK) | ((chipcHw_divide (freq, chipcHw_getClockFrequency(chipcHw_CLOCK_BUS)) - 1)
-                               << chipcHw_REG_PLL_CLOCK_TO_BUS_RATIO_SHIFT);
+                       writel((readl(&pChipcHw->VPMClock) & ~chipcHw_REG_PLL_CLOCK_TO_BUS_RATIO_MASK) | ((chipcHw_divide (freq, chipcHw_getClockFrequency(chipcHw_CLOCK_BUS)) - 1) << chipcHw_REG_PLL_CLOCK_TO_BUS_RATIO_SHIFT), &pChipcHw->VPMClock);
                        REG_LOCAL_IRQ_RESTORE;
                }
                pPLLReg = &pChipcHw->VPMClock;
@@ -428,9 +426,9 @@ chipcHw_freq chipcHw_setClockFrequency(chipcHw_CLOCK_e clock,       /*  [ IN ] Configu
                /* For DDR settings use only the PLL divider clock */
                if (pPLLReg == &pChipcHw->DDRClock) {
                        /* Set M1DIV for PLL1, which controls the DDR clock */
-                       reg32_write(&pChipcHw->PLLDivider, (pChipcHw->PLLDivider & 0x00FFFFFF) | ((chipcHw_REG_PLL_DIVIDER_MDIV (desVcoHz, freq)) << 24));
+                       reg32_write(&pChipcHw->PLLDivider, (readl(&pChipcHw->PLLDivider) & 0x00FFFFFF) | ((chipcHw_REG_PLL_DIVIDER_MDIV (desVcoHz, freq)) << 24));
                        /* Calculate expected frequency */
-                       freq = chipcHw_divide(vcoHz, (((pChipcHw->PLLDivider & 0xFF000000) >> 24) ? ((pChipcHw->PLLDivider & 0xFF000000) >> 24) : 256));
+                       freq = chipcHw_divide(vcoHz, (((readl(&pChipcHw->PLLDivider) & 0xFF000000) >> 24) ? ((readl(&pChipcHw->PLLDivider) & 0xFF000000) >> 24) : 256));
                } else {
                        /* From chip revision number B0, LCD clock is internally divided by 2 */
                        if ((pPLLReg == &pChipcHw->LCDClock) && (chipcHw_getChipRevisionNumber() != chipcHw_REV_NUMBER_A0)) {
@@ -441,7 +439,7 @@ chipcHw_freq chipcHw_setClockFrequency(chipcHw_CLOCK_e clock,       /*  [ IN ] Configu
                        reg32_modify_and(pPLLReg, ~(chipcHw_REG_PLL_CLOCK_MDIV_MASK));
                        reg32_modify_or(pPLLReg, chipcHw_REG_PLL_DIVIDER_MDIV(desVcoHz, freq));
                        /* Calculate expected frequency */
-                       freq = chipcHw_divide(vcoHz, ((*(pPLLReg) & chipcHw_REG_PLL_CLOCK_MDIV_MASK) ? (*(pPLLReg) & chipcHw_REG_PLL_CLOCK_MDIV_MASK) : 256));
+                       freq = chipcHw_divide(vcoHz, ((readl(pPLLReg) & chipcHw_REG_PLL_CLOCK_MDIV_MASK) ? (readl(pPLLReg) & chipcHw_REG_PLL_CLOCK_MDIV_MASK) : 256));
                }
                /* Wait for for atleast 200ns as per the protocol to change frequency */
                udelay(1);
@@ -460,16 +458,16 @@ chipcHw_freq chipcHw_setClockFrequency(chipcHw_CLOCK_e clock,     /*  [ IN ] Configu
                if (pDependentClock) {
                        switch (dependentClockType) {
                        case PLL_CLOCK:
-                               divider = chipcHw_divide(chipcHw_divide (desVcoHz, (*pDependentClock & chipcHw_REG_PLL_CLOCK_MDIV_MASK)), freq);
+                               divider = chipcHw_divide(chipcHw_divide (desVcoHz, (readl(pDependentClock) & chipcHw_REG_PLL_CLOCK_MDIV_MASK)), freq);
                                break;
                        case NON_PLL_CLOCK:
                                {
                                        uint32_t sourceClock = 0;
 
-                                       if (pDependentClock == (uint32_t *) &pChipcHw->ACLKClock) {
+                                       if (pDependentClock == &pChipcHw->ACLKClock) {
                                                sourceClock = chipcHw_getClockFrequency (chipcHw_CLOCK_BUS);
                                        } else {
-                                               uint32_t div = *pDependentClock & chipcHw_REG_DIV_CLOCK_DIV_MASK;
+                                               uint32_t div = readl(pDependentClock) & chipcHw_REG_DIV_CLOCK_DIV_MASK;
                                                sourceClock = chipcHw_divide (chipcHw_XTAL_FREQ_Hz, ((div) ? div : 256));
                                        }
                                        divider = chipcHw_divide(sourceClock, freq);
@@ -483,7 +481,7 @@ chipcHw_freq chipcHw_setClockFrequency(chipcHw_CLOCK_e clock,       /*  [ IN ] Configu
                if (divider) {
                        REG_LOCAL_IRQ_SAVE;
                        /* Set the divider to obtain the required frequency */
-                       *pClockCtrl = (*pClockCtrl & (~chipcHw_REG_DIV_CLOCK_DIV_MASK)) | (((divider > 256) ? chipcHw_REG_DIV_CLOCK_DIV_256 : divider) & chipcHw_REG_DIV_CLOCK_DIV_MASK);
+                       writel((readl(pClockCtrl) & (~chipcHw_REG_DIV_CLOCK_DIV_MASK)) | (((divider > 256) ? chipcHw_REG_DIV_CLOCK_DIV_256 : divider) & chipcHw_REG_DIV_CLOCK_DIV_MASK), pClockCtrl);
                        REG_LOCAL_IRQ_RESTORE;
                        return freq;
                }
@@ -515,25 +513,26 @@ static int vpmPhaseAlignA0(void)
        int count = 0;
 
        for (iter = 0; (iter < MAX_PHASE_ALIGN_ATTEMPTS) && (adjustCount < MAX_PHASE_ADJUST_COUNT); iter++) {
-               phaseControl = (pChipcHw->VPMClock & chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK) >> chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT;
+               phaseControl = (readl(&pChipcHw->VPMClock) & chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK) >> chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT;
                phaseValue = 0;
                prevPhaseComp = 0;
 
                /* Step 1: Look for falling PH_COMP transition */
 
                /* Read the contents of VPM Clock resgister */
-               phaseValue = pChipcHw->VPMClock;
+               phaseValue = readl(&pChipcHw->VPMClock);
                do {
                        /* Store previous value of phase comparator */
                        prevPhaseComp = phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP;
                        /* Change the value of PH_CTRL. */
-                       reg32_write(&pChipcHw->VPMClock, (pChipcHw->VPMClock & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
+                       reg32_write(&pChipcHw->VPMClock,
+                       (readl(&pChipcHw->VPMClock) & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
                        /* Wait atleast 20 ns */
                        udelay(1);
                        /* Toggle the LOAD_CH after phase control is written. */
-                       pChipcHw->VPMClock ^= chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE;
+                       writel(readl(&pChipcHw->VPMClock) ^ chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE, &pChipcHw->VPMClock);
                        /* Read the contents of  VPM Clock resgister. */
-                       phaseValue = pChipcHw->VPMClock;
+                       phaseValue = readl(&pChipcHw->VPMClock);
 
                        if ((phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP) == 0x0) {
                                phaseControl = (0x3F & (phaseControl - 1));
@@ -557,12 +556,13 @@ static int vpmPhaseAlignA0(void)
 
                for (count = 0; (count < 5) && ((phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP) == 0); count++) {
                        phaseControl = (0x3F & (phaseControl + 1));
-                       reg32_write(&pChipcHw->VPMClock, (pChipcHw->VPMClock & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
+                       reg32_write(&pChipcHw->VPMClock,
+                       (readl(&pChipcHw->VPMClock) & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
                        /* Wait atleast 20 ns */
                        udelay(1);
                        /* Toggle the LOAD_CH after phase control is written. */
-                       pChipcHw->VPMClock ^= chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE;
-                       phaseValue = pChipcHw->VPMClock;
+                       writel(readl(&pChipcHw->VPMClock) ^ chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE, &pChipcHw->VPMClock);
+                       phaseValue = readl(&pChipcHw->VPMClock);
                        /* Count number of adjustment made */
                        adjustCount++;
                }
@@ -581,12 +581,13 @@ static int vpmPhaseAlignA0(void)
 
                for (count = 0; (count < 3) && ((phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP) == 0); count++) {
                        phaseControl = (0x3F & (phaseControl - 1));
-                       reg32_write(&pChipcHw->VPMClock, (pChipcHw->VPMClock & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
+                       reg32_write(&pChipcHw->VPMClock,
+                       (readl(&pChipcHw->VPMClock) & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
                        /* Wait atleast 20 ns */
                        udelay(1);
                        /* Toggle the LOAD_CH after phase control is written. */
-                       pChipcHw->VPMClock ^= chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE;
-                       phaseValue = pChipcHw->VPMClock;
+                       writel(readl(&pChipcHw->VPMClock) ^ chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE, &pChipcHw->VPMClock);
+                       phaseValue = readl(&pChipcHw->VPMClock);
                        /* Count number of adjustment made */
                        adjustCount++;
                }
@@ -605,12 +606,13 @@ static int vpmPhaseAlignA0(void)
 
                for (count = 0; (count < 5); count++) {
                        phaseControl = (0x3F & (phaseControl - 1));
-                       reg32_write(&pChipcHw->VPMClock, (pChipcHw->VPMClock & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
+                       reg32_write(&pChipcHw->VPMClock,
+                       (readl(&pChipcHw->VPMClock) & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
                        /* Wait atleast 20 ns */
                        udelay(1);
                        /* Toggle the LOAD_CH after phase control is written. */
-                       pChipcHw->VPMClock ^= chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE;
-                       phaseValue = pChipcHw->VPMClock;
+                       writel(readl(&pChipcHw->VPMClock) ^ chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE, &pChipcHw->VPMClock);
+                       phaseValue = readl(&pChipcHw->VPMClock);
                        /* Count number of adjustment made */
                        adjustCount++;
                }
@@ -631,14 +633,14 @@ static int vpmPhaseAlignA0(void)
                        /* Store previous value of phase comparator */
                        prevPhaseComp = phaseValue;
                        /* Change the value of PH_CTRL. */
-                       reg32_write(&pChipcHw->VPMClock, (pChipcHw->VPMClock & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
+                       reg32_write(&pChipcHw->VPMClock,
+                       (readl(&pChipcHw->VPMClock) & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
                        /* Wait atleast 20 ns */
                        udelay(1);
                        /* Toggle the LOAD_CH after phase control is written. */
-                       pChipcHw->VPMClock ^=
-                           chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE;
+                       writel(readl(&pChipcHw->VPMClock) ^ chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE, &pChipcHw->VPMClock);
                        /* Read the contents of  VPM Clock resgister. */
-                       phaseValue = pChipcHw->VPMClock;
+                       phaseValue = readl(&pChipcHw->VPMClock);
 
                        if ((phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP) == 0x0) {
                                phaseControl = (0x3F & (phaseControl - 1));
@@ -661,13 +663,13 @@ static int vpmPhaseAlignA0(void)
        }
 
        /* For VPM Phase should be perfectly aligned. */
-       phaseControl = (((pChipcHw->VPMClock >> chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT) - 1) & 0x3F);
+       phaseControl = (((readl(&pChipcHw->VPMClock) >> chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT) - 1) & 0x3F);
        {
                REG_LOCAL_IRQ_SAVE;
 
-               pChipcHw->VPMClock = (pChipcHw->VPMClock & ~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT);
+               writel((readl(&pChipcHw->VPMClock) & ~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT), &pChipcHw->VPMClock);
                /* Load new phase value */
-               pChipcHw->VPMClock ^= chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE;
+               writel(readl(&pChipcHw->VPMClock) ^ chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE, &pChipcHw->VPMClock);
 
                REG_LOCAL_IRQ_RESTORE;
        }
@@ -697,7 +699,7 @@ int chipcHw_vpmPhaseAlign(void)
                int adjustCount = 0;
 
                /* Disable VPM access */
-               pChipcHw->Spare1 &= ~chipcHw_REG_SPARE1_VPM_BUS_ACCESS_ENABLE;
+               writel(readl(&pChipcHw->Spare1) & ~chipcHw_REG_SPARE1_VPM_BUS_ACCESS_ENABLE, &pChipcHw->Spare1);
                /* Disable HW VPM phase alignment  */
                chipcHw_vpmHwPhaseAlignDisable();
                /* Enable SW VPM phase alignment  */
@@ -715,23 +717,24 @@ int chipcHw_vpmPhaseAlign(void)
                                phaseControl--;
                        } else {
                                /* Enable VPM access */
-                               pChipcHw->Spare1 |= chipcHw_REG_SPARE1_VPM_BUS_ACCESS_ENABLE;
+                               writel(readl(&pChipcHw->Spare1) | chipcHw_REG_SPARE1_VPM_BUS_ACCESS_ENABLE, &pChipcHw->Spare1);
                                /* Return adjust count */
                                return adjustCount;
                        }
                        /* Change the value of PH_CTRL. */
-                       reg32_write(&pChipcHw->VPMClock, (pChipcHw->VPMClock & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
+                       reg32_write(&pChipcHw->VPMClock,
+                       (readl(&pChipcHw->VPMClock) & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
                        /* Wait atleast 20 ns */
                        udelay(1);
                        /* Toggle the LOAD_CH after phase control is written. */
-                       pChipcHw->VPMClock ^= chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE;
+                       writel(readl(&pChipcHw->VPMClock) ^ chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE, &pChipcHw->VPMClock);
                        /* Count adjustment */
                        adjustCount++;
                }
        }
 
        /* Disable VPM access */
-       pChipcHw->Spare1 &= ~chipcHw_REG_SPARE1_VPM_BUS_ACCESS_ENABLE;
+       writel(readl(&pChipcHw->Spare1) & ~chipcHw_REG_SPARE1_VPM_BUS_ACCESS_ENABLE, &pChipcHw->Spare1);
        return -1;
 }
 
index 367df75d4bb332407f01bfe502f48b450be30401..8377d8054168012b26dcdaacdc42f7b13c465972 100644 (file)
 
 /* ---- Include Files ---------------------------------------------------- */
 
-#include <csp/errno.h>
-#include <csp/stdint.h>
-#include <csp/module.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/export.h>
 
 #include <mach/csp/chipcHw_def.h>
 #include <mach/csp/chipcHw_inline.h>
 
-#include <csp/reg.h>
-#include <csp/delay.h>
+#include <mach/csp/reg.h>
+#include <linux/delay.h>
 /* ---- Private Constants and Types --------------------------------------- */
 
 /*
@@ -73,9 +73,9 @@ void chipcHw_pll2Enable(uint32_t vcoFreqHz)
 
        {
                REG_LOCAL_IRQ_SAVE;
-               pChipcHw->PLLConfig2 =
-                   chipcHw_REG_PLL_CONFIG_D_RESET |
-                   chipcHw_REG_PLL_CONFIG_A_RESET;
+               writel(chipcHw_REG_PLL_CONFIG_D_RESET |
+                      chipcHw_REG_PLL_CONFIG_A_RESET,
+                       &pChipcHw->PLLConfig2);
 
                pllPreDivider2 = chipcHw_REG_PLL_PREDIVIDER_POWER_DOWN |
                    chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_INTEGER |
@@ -87,28 +87,30 @@ void chipcHw_pll2Enable(uint32_t vcoFreqHz)
                     chipcHw_REG_PLL_PREDIVIDER_P2_SHIFT);
 
                /* Enable CHIPC registers to control the PLL */
-               pChipcHw->PLLStatus |= chipcHw_REG_PLL_STATUS_CONTROL_ENABLE;
+               writel(readl(&pChipcHw->PLLStatus) | chipcHw_REG_PLL_STATUS_CONTROL_ENABLE, &pChipcHw->PLLStatus);
 
                /* Set pre divider to get desired VCO frequency */
-               pChipcHw->PLLPreDivider2 = pllPreDivider2;
+               writel(pllPreDivider2, &pChipcHw->PLLPreDivider2);
                /* Set NDIV Frac */
-               pChipcHw->PLLDivider2 = chipcHw_REG_PLL_DIVIDER_NDIV_f;
+               writel(chipcHw_REG_PLL_DIVIDER_NDIV_f, &pChipcHw->PLLDivider2);
 
                /* This has to be removed once the default values are fixed for PLL2. */
-               pChipcHw->PLLControl12 = 0x38000700;
-               pChipcHw->PLLControl22 = 0x00000015;
+               writel(0x38000700, &pChipcHw->PLLControl12);
+               writel(0x00000015, &pChipcHw->PLLControl22);
 
                /* Reset PLL2 */
                if (vcoFreqHz > chipcHw_REG_PLL_CONFIG_VCO_SPLIT_FREQ) {
-                       pChipcHw->PLLConfig2 = chipcHw_REG_PLL_CONFIG_D_RESET |
+                       writel(chipcHw_REG_PLL_CONFIG_D_RESET |
                            chipcHw_REG_PLL_CONFIG_A_RESET |
                            chipcHw_REG_PLL_CONFIG_VCO_1601_3200 |
-                           chipcHw_REG_PLL_CONFIG_POWER_DOWN;
+                           chipcHw_REG_PLL_CONFIG_POWER_DOWN,
+                           &pChipcHw->PLLConfig2);
                } else {
-                       pChipcHw->PLLConfig2 = chipcHw_REG_PLL_CONFIG_D_RESET |
+                       writel(chipcHw_REG_PLL_CONFIG_D_RESET |
                            chipcHw_REG_PLL_CONFIG_A_RESET |
                            chipcHw_REG_PLL_CONFIG_VCO_800_1600 |
-                           chipcHw_REG_PLL_CONFIG_POWER_DOWN;
+                           chipcHw_REG_PLL_CONFIG_POWER_DOWN,
+                           &pChipcHw->PLLConfig2);
                }
                REG_LOCAL_IRQ_RESTORE;
        }
@@ -119,22 +121,25 @@ void chipcHw_pll2Enable(uint32_t vcoFreqHz)
        {
                REG_LOCAL_IRQ_SAVE;
                /* Remove analog reset and Power on the PLL */
-               pChipcHw->PLLConfig2 &=
+               writel(readl(&pChipcHw->PLLConfig2) &
                    ~(chipcHw_REG_PLL_CONFIG_A_RESET |
-                     chipcHw_REG_PLL_CONFIG_POWER_DOWN);
+                     chipcHw_REG_PLL_CONFIG_POWER_DOWN),
+                     &pChipcHw->PLLConfig2);
 
                REG_LOCAL_IRQ_RESTORE;
 
        }
 
        /* Wait until PLL is locked */
-       while (!(pChipcHw->PLLStatus2 & chipcHw_REG_PLL_STATUS_LOCKED))
+       while (!(readl(&pChipcHw->PLLStatus2) & chipcHw_REG_PLL_STATUS_LOCKED))
                ;
 
        {
                REG_LOCAL_IRQ_SAVE;
                /* Remove digital reset */
-               pChipcHw->PLLConfig2 &= ~chipcHw_REG_PLL_CONFIG_D_RESET;
+               writel(readl(&pChipcHw->PLLConfig2) &
+                       ~chipcHw_REG_PLL_CONFIG_D_RESET,
+                       &pChipcHw->PLLConfig2);
 
                REG_LOCAL_IRQ_RESTORE;
        }
@@ -157,9 +162,9 @@ void chipcHw_pll1Enable(uint32_t vcoFreqHz, chipcHw_SPREAD_SPECTRUM_e ssSupport)
        {
                REG_LOCAL_IRQ_SAVE;
 
-               pChipcHw->PLLConfig =
-                   chipcHw_REG_PLL_CONFIG_D_RESET |
-                   chipcHw_REG_PLL_CONFIG_A_RESET;
+               writel(chipcHw_REG_PLL_CONFIG_D_RESET |
+                   chipcHw_REG_PLL_CONFIG_A_RESET,
+                   &pChipcHw->PLLConfig);
                /* Setting VCO frequency */
                if (ssSupport == chipcHw_SPREAD_SPECTRUM_ALLOW) {
                        pllPreDivider =
@@ -182,30 +187,22 @@ void chipcHw_pll1Enable(uint32_t vcoFreqHz, chipcHw_SPREAD_SPECTRUM_e ssSupport)
                }
 
                /* Enable CHIPC registers to control the PLL */
-               pChipcHw->PLLStatus |= chipcHw_REG_PLL_STATUS_CONTROL_ENABLE;
+               writel(readl(&pChipcHw->PLLStatus) | chipcHw_REG_PLL_STATUS_CONTROL_ENABLE, &pChipcHw->PLLStatus);
 
                /* Set pre divider to get desired VCO frequency */
-               pChipcHw->PLLPreDivider = pllPreDivider;
+               writel(pllPreDivider, &pChipcHw->PLLPreDivider);
                /* Set NDIV Frac */
                if (ssSupport == chipcHw_SPREAD_SPECTRUM_ALLOW) {
-                       pChipcHw->PLLDivider = chipcHw_REG_PLL_DIVIDER_M1DIV |
-                           chipcHw_REG_PLL_DIVIDER_NDIV_f_SS;
+                       writel(chipcHw_REG_PLL_DIVIDER_M1DIV | chipcHw_REG_PLL_DIVIDER_NDIV_f_SS, &pChipcHw->PLLDivider);
                } else {
-                       pChipcHw->PLLDivider = chipcHw_REG_PLL_DIVIDER_M1DIV |
-                           chipcHw_REG_PLL_DIVIDER_NDIV_f;
+                       writel(chipcHw_REG_PLL_DIVIDER_M1DIV | chipcHw_REG_PLL_DIVIDER_NDIV_f, &pChipcHw->PLLDivider);
                }
 
                /* Reset PLL1 */
                if (vcoFreqHz > chipcHw_REG_PLL_CONFIG_VCO_SPLIT_FREQ) {
-                       pChipcHw->PLLConfig = chipcHw_REG_PLL_CONFIG_D_RESET |
-                           chipcHw_REG_PLL_CONFIG_A_RESET |
-                           chipcHw_REG_PLL_CONFIG_VCO_1601_3200 |
-                           chipcHw_REG_PLL_CONFIG_POWER_DOWN;
+                       writel(chipcHw_REG_PLL_CONFIG_D_RESET | chipcHw_REG_PLL_CONFIG_A_RESET | chipcHw_REG_PLL_CONFIG_VCO_1601_3200 | chipcHw_REG_PLL_CONFIG_POWER_DOWN, &pChipcHw->PLLConfig);
                } else {
-                       pChipcHw->PLLConfig = chipcHw_REG_PLL_CONFIG_D_RESET |
-                           chipcHw_REG_PLL_CONFIG_A_RESET |
-                           chipcHw_REG_PLL_CONFIG_VCO_800_1600 |
-                           chipcHw_REG_PLL_CONFIG_POWER_DOWN;
+                       writel(chipcHw_REG_PLL_CONFIG_D_RESET | chipcHw_REG_PLL_CONFIG_A_RESET | chipcHw_REG_PLL_CONFIG_VCO_800_1600 | chipcHw_REG_PLL_CONFIG_POWER_DOWN, &pChipcHw->PLLConfig);
                }
 
                REG_LOCAL_IRQ_RESTORE;
@@ -216,22 +213,19 @@ void chipcHw_pll1Enable(uint32_t vcoFreqHz, chipcHw_SPREAD_SPECTRUM_e ssSupport)
                {
                        REG_LOCAL_IRQ_SAVE;
                        /* Remove analog reset and Power on the PLL */
-                       pChipcHw->PLLConfig &=
-                           ~(chipcHw_REG_PLL_CONFIG_A_RESET |
-                             chipcHw_REG_PLL_CONFIG_POWER_DOWN);
+                       writel(readl(&pChipcHw->PLLConfig) & ~(chipcHw_REG_PLL_CONFIG_A_RESET | chipcHw_REG_PLL_CONFIG_POWER_DOWN), &pChipcHw->PLLConfig);
                        REG_LOCAL_IRQ_RESTORE;
                }
 
                /* Wait until PLL is locked */
-               while (!(pChipcHw->PLLStatus & chipcHw_REG_PLL_STATUS_LOCKED)
-                      || !(pChipcHw->
-                           PLLStatus2 & chipcHw_REG_PLL_STATUS_LOCKED))
+               while (!(readl(&pChipcHw->PLLStatus) & chipcHw_REG_PLL_STATUS_LOCKED)
+                      || !(readl(&pChipcHw->PLLStatus2) & chipcHw_REG_PLL_STATUS_LOCKED))
                        ;
 
                /* Remove digital reset */
                {
                        REG_LOCAL_IRQ_SAVE;
-                       pChipcHw->PLLConfig &= ~chipcHw_REG_PLL_CONFIG_D_RESET;
+                       writel(readl(&pChipcHw->PLLConfig) & ~chipcHw_REG_PLL_CONFIG_D_RESET, &pChipcHw->PLLConfig);
                        REG_LOCAL_IRQ_RESTORE;
                }
        }
@@ -267,11 +261,7 @@ void chipcHw_Init(chipcHw_INIT_PARAM_t *initParam  /*  [ IN ] Misc chip initializ
        chipcHw_clearStickyBits(chipcHw_REG_STICKY_CHIP_SOFT_RESET);
 
        /* Before configuring the ARM clock, atleast we need to make sure BUS clock maintains the proper ratio with ARM clock */
-       pChipcHw->ACLKClock =
-           (pChipcHw->
-            ACLKClock & ~chipcHw_REG_ACLKClock_CLK_DIV_MASK) | (initParam->
-                                                                armBusRatio &
-                                                                chipcHw_REG_ACLKClock_CLK_DIV_MASK);
+       writel((readl(&pChipcHw->ACLKClock) & ~chipcHw_REG_ACLKClock_CLK_DIV_MASK) | (initParam-> armBusRatio & chipcHw_REG_ACLKClock_CLK_DIV_MASK), &pChipcHw->ACLKClock);
 
        /* Set various core component frequencies. The order in which this is done is important for some. */
        /* The RTBUS (DDR PHY) is derived from the BUS, and the BUS from the ARM, and VPM needs to know BUS */
index 2671d8896bbb5202e788218de8ad3ec0f963f119..f95ce913fa1e4aec3f1f77467e1d3bad2da7ab6b 100644 (file)
 *****************************************************************************/
 
 /* ---- Include Files ---------------------------------------------------- */
-#include <csp/stdint.h>
+#include <linux/types.h>
 #include <mach/csp/chipcHw_def.h>
 #include <mach/csp/chipcHw_inline.h>
-#include <csp/intcHw.h>
-#include <csp/cache.h>
+#include <mach/csp/intcHw_reg.h>
+#include <asm/cacheflush.h>
 
 /* ---- Private Constants and Types --------------------------------------- */
 /* ---- Private Variables ------------------------------------------------- */
@@ -50,17 +50,18 @@ void chipcHw_reset(uint32_t mask)
                        chipcHw_softReset(chipcHw_REG_SOFT_RESET_CHIP_SOFT);
                }
                /* Bypass the PLL clocks before reboot */
-               pChipcHw->UARTClock |= chipcHw_REG_PLL_CLOCK_BYPASS_SELECT;
-               pChipcHw->SPIClock |= chipcHw_REG_PLL_CLOCK_BYPASS_SELECT;
+               writel(readl(&pChipcHw->UARTClock) | chipcHw_REG_PLL_CLOCK_BYPASS_SELECT,
+                       &pChipcHw->UARTClock);
+               writel(readl(&pChipcHw->SPIClock) | chipcHw_REG_PLL_CLOCK_BYPASS_SELECT,
+                       &pChipcHw->SPIClock);
 
                /* Copy the chipcHw_warmReset_run_from_aram function into ARAM */
                do {
-                       ((uint32_t *) MM_IO_BASE_ARAM)[i] =
-                           ((uint32_t *) &chipcHw_reset_run_from_aram)[i];
+                       writel(((uint32_t *) &chipcHw_reset_run_from_aram)[i], ((uint32_t __iomem *) MM_IO_BASE_ARAM) + i);
                        i++;
-               } while (((uint32_t *) MM_IO_BASE_ARAM)[i - 1] != 0xe1a0f00f);  /* 0xe1a0f00f == asm ("mov r15, r15"); */
+               } while (readl(((uint32_t __iomem*) MM_IO_BASE_ARAM) + i - 1) != 0xe1a0f00f);   /* 0xe1a0f00f == asm ("mov r15, r15"); */
 
-               CSP_CACHE_FLUSH_ALL;
+               flush_cache_all();
 
                /* run the function from ARAM */
                runFunc();
index 6b9be2e98e510967293097b69f1eba1965462cc5..547f746c7ff4711331774d81dd238d454498fd7f 100644 (file)
 /****************************************************************************/
 
 /* ---- Include Files ---------------------------------------------------- */
-#include <csp/stdint.h>
-#include <csp/string.h>
-#include <stddef.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/stddef.h>
 
-#include <csp/dmacHw.h>
+#include <mach/csp/dmacHw.h>
 #include <mach/csp/dmacHw_reg.h>
 #include <mach/csp/dmacHw_priv.h>
 #include <mach/csp/chipcHw_inline.h>
@@ -55,33 +55,32 @@ static uint32_t GetFifoSize(dmacHw_HANDLE_t handle  /*   [ IN ] DMA Channel handl
     ) {
        uint32_t val = 0;
        dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
-       dmacHw_MISC_t *pMiscReg =
-           (dmacHw_MISC_t *) dmacHw_REG_MISC_BASE(pCblk->module);
+       dmacHw_MISC_t __iomem *pMiscReg = (void __iomem *)dmacHw_REG_MISC_BASE(pCblk->module);
 
        switch (pCblk->channel) {
        case 0:
-               val = (pMiscReg->CompParm2.lo & 0x70000000) >> 28;
+               val = (readl(&pMiscReg->CompParm2.lo) & 0x70000000) >> 28;
                break;
        case 1:
-               val = (pMiscReg->CompParm3.hi & 0x70000000) >> 28;
+               val = (readl(&pMiscReg->CompParm3.hi) & 0x70000000) >> 28;
                break;
        case 2:
-               val = (pMiscReg->CompParm3.lo & 0x70000000) >> 28;
+               val = (readl(&pMiscReg->CompParm3.lo) & 0x70000000) >> 28;
                break;
        case 3:
-               val = (pMiscReg->CompParm4.hi & 0x70000000) >> 28;
+               val = (readl(&pMiscReg->CompParm4.hi) & 0x70000000) >> 28;
                break;
        case 4:
-               val = (pMiscReg->CompParm4.lo & 0x70000000) >> 28;
+               val = (readl(&pMiscReg->CompParm4.lo) & 0x70000000) >> 28;
                break;
        case 5:
-               val = (pMiscReg->CompParm5.hi & 0x70000000) >> 28;
+               val = (readl(&pMiscReg->CompParm5.hi) & 0x70000000) >> 28;
                break;
        case 6:
-               val = (pMiscReg->CompParm5.lo & 0x70000000) >> 28;
+               val = (readl(&pMiscReg->CompParm5.lo) & 0x70000000) >> 28;
                break;
        case 7:
-               val = (pMiscReg->CompParm6.hi & 0x70000000) >> 28;
+               val = (readl(&pMiscReg->CompParm6.hi) & 0x70000000) >> 28;
                break;
        }
 
index a1f328357aa4b91b0f0d49f7b1b944de01cc6e8a..fe438699d11ed6dffad1e8f1ea29b2d215e922d5 100644 (file)
 
 /* ---- Include Files ---------------------------------------------------- */
 
-#include <csp/stdint.h>
-#include <stddef.h>
+#include <linux/types.h>
+#include <linux/stddef.h>
 
-#include <csp/dmacHw.h>
+#include <mach/csp/dmacHw.h>
 #include <mach/csp/dmacHw_reg.h>
 #include <mach/csp/dmacHw_priv.h>
 
index 16225e43f3c33dde11e0ab8d2761142b214cbf46..dc4137ff75cafed153e5ee952e8d46e4eee19389 100644 (file)
 
 /* ---- Include Files ---------------------------------------------------- */
 
-#include <csp/errno.h>
-#include <csp/stdint.h>
+#include <linux/errno.h>
+#include <linux/types.h>
 
-#include <csp/tmrHw.h>
+#include <mach/csp/tmrHw.h>
 #include <mach/csp/tmrHw_reg.h>
 
 #define tmrHw_ASSERT(a)                     if (!(a)) *(char *)0 = 0
diff --git a/arch/arm/mach-bcmring/include/cfg_global.h b/arch/arm/mach-bcmring/include/cfg_global.h
deleted file mode 100644 (file)
index f01da87..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef _CFG_GLOBAL_H_
-#define _CFG_GLOBAL_H_
-
-#include <cfg_global_defines.h>
-
-#define CFG_GLOBAL_CHIP                         BCM11107
-#define CFG_GLOBAL_CHIP_FAMILY                  CFG_GLOBAL_CHIP_FAMILY_BCMRING
-#define CFG_GLOBAL_CHIP_REV                     0xB0
-#define CFG_GLOBAL_RAM_SIZE                     0x10000000
-#define CFG_GLOBAL_RAM_BASE                     0x00000000
-#define CFG_GLOBAL_RAM_RESERVED_SIZE            0x000000
-
-#endif /* _CFG_GLOBAL_H_ */
diff --git a/arch/arm/mach-bcmring/include/csp/cache.h b/arch/arm/mach-bcmring/include/csp/cache.h
deleted file mode 100644 (file)
index caa20e5..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*****************************************************************************
-* Copyright 2003 - 2008 Broadcom Corporation.  All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-#ifndef CSP_CACHE_H
-#define CSP_CACHE_H
-
-/* ---- Include Files ---------------------------------------------------- */
-
-#include <csp/stdint.h>
-
-/* ---- Public Constants and Types --------------------------------------- */
-
-#if defined(__KERNEL__) && !defined(STANDALONE)
-#include <asm/cacheflush.h>
-
-#define CSP_CACHE_FLUSH_ALL      flush_cache_all()
-
-#else
-
-#define CSP_CACHE_FLUSH_ALL
-
-#endif
-
-#endif /* CSP_CACHE_H */
diff --git a/arch/arm/mach-bcmring/include/csp/delay.h b/arch/arm/mach-bcmring/include/csp/delay.h
deleted file mode 100644 (file)
index 8b3d803..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*****************************************************************************
-* Copyright 2003 - 2008 Broadcom Corporation.  All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-
-#ifndef CSP_DELAY_H
-#define CSP_DELAY_H
-
-/* ---- Include Files ---------------------------------------------------- */
-
-/* Some CSP routines require use of the following delay routines. Use the OS */
-/* version if available, otherwise use a CSP specific definition. */
-/* void udelay(unsigned long usecs); */
-/* void mdelay(unsigned long msecs); */
-
-#if defined(__KERNEL__) && !defined(STANDALONE)
-   #include <linux/delay.h>
-#else
-   #include <mach/csp/delay.h>
-#endif
-
-/* ---- Public Constants and Types --------------------------------------- */
-/* ---- Public Variable Externs ------------------------------------------ */
-/* ---- Public Function Prototypes --------------------------------------- */
-
-#endif /*  CSP_DELAY_H */
diff --git a/arch/arm/mach-bcmring/include/csp/errno.h b/arch/arm/mach-bcmring/include/csp/errno.h
deleted file mode 100644 (file)
index 51357dd..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*****************************************************************************
-* Copyright 2003 - 2008 Broadcom Corporation.  All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-#ifndef CSP_ERRNO_H
-#define CSP_ERRNO_H
-
-/* ---- Include Files ---------------------------------------------------- */
-
-#if   defined(__KERNEL__)
-#include <linux/errno.h>
-#elif defined(CSP_SIMULATION)
-#include <asm-generic/errno.h>
-#else
-#include <errno.h>
-#endif
-
-/* ---- Public Constants and Types --------------------------------------- */
-/* ---- Public Variable Externs ------------------------------------------ */
-/* ---- Public Function Prototypes --------------------------------------- */
-
-#endif /* CSP_ERRNO_H */
diff --git a/arch/arm/mach-bcmring/include/csp/intcHw.h b/arch/arm/mach-bcmring/include/csp/intcHw.h
deleted file mode 100644 (file)
index 1c639c8..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*****************************************************************************
-* Copyright 2003 - 2008 Broadcom Corporation.  All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-
-/****************************************************************************/
-/**
-*  @file    intcHw.h
-*
-*  @brief   generic interrupt controller API
-*
-*  @note
-*     None
-*/
-/****************************************************************************/
-
-#ifndef _INTCHW_H
-#define _INTCHW_H
-
-/* ---- Include Files ---------------------------------------------------- */
-#include <mach/csp/intcHw_reg.h>
-
-/* ---- Public Constants and Types --------------------------------------- */
-/* ---- Public Variable Externs ------------------------------------------ */
-/* ---- Public Function Prototypes --------------------------------------- */
-static inline void intcHw_irq_disable(void *basep, uint32_t mask);
-static inline void intcHw_irq_enable(void *basep, uint32_t mask);
-
-#endif /* _INTCHW_H */
-
diff --git a/arch/arm/mach-bcmring/include/csp/module.h b/arch/arm/mach-bcmring/include/csp/module.h
deleted file mode 100644 (file)
index c30d2a5..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*****************************************************************************
-* Copyright 2003 - 2008 Broadcom Corporation.  All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-
-#ifndef CSP_MODULE_H
-#define CSP_MODULE_H
-
-/* ---- Include Files ---------------------------------------------------- */
-
-#ifdef __KERNEL__
-    #include <linux/module.h>
-#else
-    #define EXPORT_SYMBOL(symbol)
-#endif
-
-/* ---- Public Constants and Types --------------------------------------- */
-/* ---- Public Variable Externs ------------------------------------------ */
-/* ---- Public Function Prototypes --------------------------------------- */
-
-
-#endif /* CSP_MODULE_H */
diff --git a/arch/arm/mach-bcmring/include/csp/secHw.h b/arch/arm/mach-bcmring/include/csp/secHw.h
deleted file mode 100644 (file)
index b9d7e07..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/*****************************************************************************
-* Copyright 2004 - 2008 Broadcom Corporation.  All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-/****************************************************************************/
-/**
-*  @file    secHw.h
-*
-*  @brief   Definitions for accessing low level security features
-*
-*/
-/****************************************************************************/
-#ifndef SECHW_H
-#define SECHW_H
-
-typedef void (*secHw_FUNC_t) (void);
-
-typedef enum {
-       secHw_MODE_SECURE = 0x0,        /* Switches processor into secure mode */
-       secHw_MODE_NONSECURE = 0x1      /* Switches processor into non-secure mode */
-} secHw_MODE;
-
-/****************************************************************************/
-/**
-*  @brief   Requesting to execute the function in secure mode
-*
-*  This function requests the given function to run in secure mode
-*
-*/
-/****************************************************************************/
-void secHw_RunSecure(secHw_FUNC_t      /* Function to run in secure mode */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Sets the  mode
-*
-*  his function sets the processor mode (secure/non-secure)
-*
-*/
-/****************************************************************************/
-void secHw_SetMode(secHw_MODE  /* Processor mode */
-    );
-
-/****************************************************************************/
-/**
-*  @brief   Get the current mode
-*
-*  This function retieves the processor mode (secure/non-secure)
-*
-*/
-/****************************************************************************/
-void secHw_GetMode(secHw_MODE *);
-
-#endif /* SECHW_H */
diff --git a/arch/arm/mach-bcmring/include/csp/stdint.h b/arch/arm/mach-bcmring/include/csp/stdint.h
deleted file mode 100644 (file)
index 3a8718b..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*****************************************************************************
-* Copyright 2003 - 2008 Broadcom Corporation.  All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-#ifndef CSP_STDINT_H
-#define CSP_STDINT_H
-
-/* ---- Include Files ---------------------------------------------------- */
-
-#ifdef __KERNEL__
-#include <linux/types.h>
-#else
-#include <stdint.h>
-#endif
-
-/* ---- Public Constants and Types --------------------------------------- */
-/* ---- Public Variable Externs ------------------------------------------ */
-/* ---- Public Function Prototypes --------------------------------------- */
-
-#endif /* CSP_STDINT_H */
diff --git a/arch/arm/mach-bcmring/include/csp/string.h b/arch/arm/mach-bcmring/include/csp/string.h
deleted file mode 100644 (file)
index ad9e400..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*****************************************************************************
-* Copyright 2003 - 2008 Broadcom Corporation.  All rights reserved.
-*
-* Unless you and Broadcom execute a separate written software license
-* agreement governing use of this software, this software is licensed to you
-* under the terms of the GNU General Public License version 2, available at
-* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
-*
-* Notwithstanding the above, under no circumstances may you combine this
-* software in any way with any other Broadcom software provided under a
-* license other than the GPL, without Broadcom's express prior written
-* consent.
-*****************************************************************************/
-
-
-
-#ifndef CSP_STRING_H
-#define CSP_STRING_H
-
-/* ---- Include Files ---------------------------------------------------- */
-
-#ifdef __KERNEL__
-   #include <linux/string.h>
-#else
-   #include <string.h>
-#endif
-
-/* ---- Public Constants and Types --------------------------------------- */
-/* ---- Public Variable Externs ------------------------------------------ */
-/* ---- Public Function Prototypes --------------------------------------- */
-
-
-#endif /* CSP_STRING_H */
-
similarity index 74%
rename from arch/arm/mach-bcmring/include/cfg_global_defines.h
rename to arch/arm/mach-bcmring/include/mach/cfg_global.h
index b5beb0b3073490d0000e8883a9bf352fc1e8509a..449133eacdf58447117ce7371197c37ad3453fa9 100644 (file)
 
 #define IMAGE_HEADER_SIZE_CHECKSUM    4
 #endif
+#ifndef _CFG_GLOBAL_H_
+#define _CFG_GLOBAL_H_
+
+#define CFG_GLOBAL_CHIP                         BCM11107
+#define CFG_GLOBAL_CHIP_FAMILY                  CFG_GLOBAL_CHIP_FAMILY_BCMRING
+#define CFG_GLOBAL_CHIP_REV                     0xB0
+#define CFG_GLOBAL_RAM_SIZE                     0x10000000
+#define CFG_GLOBAL_RAM_BASE                     0x00000000
+#define CFG_GLOBAL_RAM_RESERVED_SIZE            0x000000
+
+#endif /* _CFG_GLOBAL_H_ */
index 933ce68ed90b4980ae3720c363c9e1d8590b6037..0a89e0c63419384b03d6a7b644bf3baaea0dbb64 100644 (file)
@@ -17,7 +17,7 @@
 
 /* ---- Include Files ---------------------------------------------------- */
 #include <mach/csp/cap.h>
-#include <cfg_global.h>
+#include <mach/cfg_global.h>
 
 /* ---- Public Constants and Types --------------------------------------- */
 #define CAP_CONFIG0_VPM_DIS          0x00000001
index 161973385faf51ac2c98f80d46ab11dd9eed9d7d..39f09cb892080038d5b5104a636b658a03caa6ac 100644 (file)
@@ -17,9 +17,9 @@
 
 /* ---- Include Files ----------------------------------------------------- */
 
-#include <csp/stdint.h>
-#include <csp/errno.h>
-#include <csp/reg.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <mach/csp/reg.h>
 #include <mach/csp/chipcHw_reg.h>
 
 /* ---- Public Constants and Types ---------------------------------------- */
index 03238c299001a9893dffc80561cca43664a4d404..a66f3f7abb8646ef7797ec50ae2f81f22acccb82 100644 (file)
@@ -17,8 +17,8 @@
 
 /* ---- Include Files ----------------------------------------------------- */
 
-#include <csp/errno.h>
-#include <csp/reg.h>
+#include <linux/errno.h>
+#include <mach/csp/reg.h>
 #include <mach/csp/chipcHw_reg.h>
 #include <mach/csp/chipcHw_def.h>
 
@@ -47,7 +47,7 @@ static inline void chipcHw_setClock(chipcHw_CLOCK_e clock,
 /****************************************************************************/
 static inline uint32_t chipcHw_getChipId(void)
 {
-       return pChipcHw->ChipId;
+       return readl(&pChipcHw->ChipId);
 }
 
 /****************************************************************************/
@@ -59,15 +59,16 @@ static inline uint32_t chipcHw_getChipId(void)
 /****************************************************************************/
 static inline void chipcHw_enableSpreadSpectrum(void)
 {
-       if ((pChipcHw->
-            PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_MASK) !=
+       if ((readl(&pChipcHw->
+            PLLPreDivider) & chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_MASK) !=
            chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_INTEGER) {
-               ddrcReg_PHY_ADDR_CTL_REGP->ssCfg =
-                   (0xFFFF << ddrcReg_PHY_ADDR_SS_CFG_NDIV_AMPLITUDE_SHIFT) |
+               writel((0xFFFF << ddrcReg_PHY_ADDR_SS_CFG_NDIV_AMPLITUDE_SHIFT) |
                    (ddrcReg_PHY_ADDR_SS_CFG_MIN_CYCLE_PER_TICK <<
-                    ddrcReg_PHY_ADDR_SS_CFG_CYCLE_PER_TICK_SHIFT);
-               ddrcReg_PHY_ADDR_CTL_REGP->ssCtl |=
-                   ddrcReg_PHY_ADDR_SS_CTRL_ENABLE;
+                    ddrcReg_PHY_ADDR_SS_CFG_CYCLE_PER_TICK_SHIFT),
+                    &ddrcReg_PHY_ADDR_CTL_REGP->ssCfg);
+               writel(readl(&ddrcReg_PHY_ADDR_CTL_REGP->ssCtl) |
+                   ddrcReg_PHY_ADDR_SS_CTRL_ENABLE,
+                   &ddrcReg_PHY_ADDR_CTL_REGP->ssCtl);
        }
 }
 
@@ -93,8 +94,8 @@ static inline void chipcHw_disableSpreadSpectrum(void)
 /****************************************************************************/
 static inline uint32_t chipcHw_getChipProductId(void)
 {
-       return (pChipcHw->
-                ChipId & chipcHw_REG_CHIPID_BASE_MASK) >>
+       return (readl(&pChipcHw->
+                ChipId) & chipcHw_REG_CHIPID_BASE_MASK) >>
                chipcHw_REG_CHIPID_BASE_SHIFT;
 }
 
@@ -109,7 +110,7 @@ static inline uint32_t chipcHw_getChipProductId(void)
 /****************************************************************************/
 static inline chipcHw_REV_NUMBER_e chipcHw_getChipRevisionNumber(void)
 {
-       return pChipcHw->ChipId & chipcHw_REG_CHIPID_REV_MASK;
+       return readl(&pChipcHw->ChipId) & chipcHw_REG_CHIPID_REV_MASK;
 }
 
 /****************************************************************************/
@@ -156,7 +157,7 @@ static inline void chipcHw_busInterfaceClockDisable(uint32_t mask)
 /****************************************************************************/
 static inline uint32_t chipcHw_getBusInterfaceClockStatus(void)
 {
-       return pChipcHw->BusIntfClock;
+       return readl(&pChipcHw->BusIntfClock);
 }
 
 /****************************************************************************/
@@ -215,8 +216,9 @@ static inline void chipcHw_softResetDisable(uint64_t mask)
 
        /* Deassert module soft reset */
        REG_LOCAL_IRQ_SAVE;
-       pChipcHw->SoftReset1 ^= ctrl1;
-       pChipcHw->SoftReset2 ^= (ctrl2 & (~chipcHw_REG_SOFT_RESET_UNHOLD_MASK));
+       writel(readl(&pChipcHw->SoftReset1) ^ ctrl1, &pChipcHw->SoftReset1);
+       writel(readl(&pChipcHw->SoftReset2) ^ (ctrl2 &
+               (~chipcHw_REG_SOFT_RESET_UNHOLD_MASK)), &pChipcHw->SoftReset2);
        REG_LOCAL_IRQ_RESTORE;
 }
 
@@ -227,9 +229,10 @@ static inline void chipcHw_softResetEnable(uint64_t mask)
        uint32_t unhold = 0;
 
        REG_LOCAL_IRQ_SAVE;
-       pChipcHw->SoftReset1 |= ctrl1;
+       writel(readl(&pChipcHw->SoftReset1) | ctrl1, &pChipcHw->SoftReset1);
        /* Mask out unhold request bits */
-       pChipcHw->SoftReset2 |= (ctrl2 & (~chipcHw_REG_SOFT_RESET_UNHOLD_MASK));
+       writel(readl(&pChipcHw->SoftReset2) | (ctrl2 &
+               (~chipcHw_REG_SOFT_RESET_UNHOLD_MASK)), &pChipcHw->SoftReset2);
 
        /* Process unhold requests */
        if (ctrl2 & chipcHw_REG_SOFT_RESET_VPM_GLOBAL_UNHOLD) {
@@ -246,7 +249,7 @@ static inline void chipcHw_softResetEnable(uint64_t mask)
 
        if (unhold) {
                /* Make sure unhold request is effective */
-               pChipcHw->SoftReset1 &= ~unhold;
+               writel(readl(&pChipcHw->SoftReset1) & ~unhold, &pChipcHw->SoftReset1);
        }
        REG_LOCAL_IRQ_RESTORE;
 }
@@ -307,7 +310,7 @@ static inline void chipcHw_setOTPOption(uint64_t mask)
 /****************************************************************************/
 static inline uint32_t chipcHw_getStickyBits(void)
 {
-       return pChipcHw->Sticky;
+       return readl(&pChipcHw->Sticky);
 }
 
 /****************************************************************************/
@@ -328,7 +331,7 @@ static inline void chipcHw_setStickyBits(uint32_t mask)
                bits |= chipcHw_REG_STICKY_POR_BROM;
        } else {
                uint32_t sticky;
-               sticky = pChipcHw->Sticky;
+               sticky = readl(pChipcHw->Sticky);
 
                if ((mask & chipcHw_REG_STICKY_BOOT_DONE)
                    && (sticky & chipcHw_REG_STICKY_BOOT_DONE) == 0) {
@@ -355,7 +358,7 @@ static inline void chipcHw_setStickyBits(uint32_t mask)
                        bits |= chipcHw_REG_STICKY_GENERAL_5;
                }
        }
-       pChipcHw->Sticky = bits;
+       writel(bits, pChipcHw->Sticky);
        REG_LOCAL_IRQ_RESTORE;
 }
 
@@ -377,7 +380,7 @@ static inline void chipcHw_clearStickyBits(uint32_t mask)
            (chipcHw_REG_STICKY_BOOT_DONE | chipcHw_REG_STICKY_GENERAL_1 |
             chipcHw_REG_STICKY_GENERAL_2 | chipcHw_REG_STICKY_GENERAL_3 |
             chipcHw_REG_STICKY_GENERAL_4 | chipcHw_REG_STICKY_GENERAL_5)) {
-               uint32_t sticky = pChipcHw->Sticky;
+               uint32_t sticky = readl(&pChipcHw->Sticky);
 
                if ((mask & chipcHw_REG_STICKY_BOOT_DONE)
                    && (sticky & chipcHw_REG_STICKY_BOOT_DONE)) {
@@ -410,7 +413,7 @@ static inline void chipcHw_clearStickyBits(uint32_t mask)
                        mask &= ~chipcHw_REG_STICKY_GENERAL_5;
                }
        }
-       pChipcHw->Sticky = bits | mask;
+       writel(bits | mask, &pChipcHw->Sticky);
        REG_LOCAL_IRQ_RESTORE;
 }
 
@@ -426,7 +429,7 @@ static inline void chipcHw_clearStickyBits(uint32_t mask)
 /****************************************************************************/
 static inline uint32_t chipcHw_getSoftStraps(void)
 {
-       return pChipcHw->SoftStraps;
+       return readl(&pChipcHw->SoftStraps);
 }
 
 /****************************************************************************/
@@ -456,7 +459,7 @@ static inline void chipcHw_setSoftStraps(uint32_t strapOptions)
 /****************************************************************************/
 static inline uint32_t chipcHw_getPinStraps(void)
 {
-       return pChipcHw->PinStraps;
+       return readl(&pChipcHw->PinStraps);
 }
 
 /****************************************************************************/
@@ -671,9 +674,9 @@ static inline void chipcHw_selectGE3(void)
 /****************************************************************************/
 static inline chipcHw_GPIO_FUNCTION_e chipcHw_getGpioPinFunction(int pin)
 {
-       return (*((uint32_t *) chipcHw_REG_GPIO_MUX(pin)) &
+       return (readl(chipcHw_REG_GPIO_MUX(pin))) &
                (chipcHw_REG_GPIO_MUX_MASK <<
-                chipcHw_REG_GPIO_MUX_POSITION(pin))) >>
+                chipcHw_REG_GPIO_MUX_POSITION(pin)) >>
            chipcHw_REG_GPIO_MUX_POSITION(pin);
 }
 
@@ -841,8 +844,8 @@ static inline void chipcHw_setUsbDevice(void)
 static inline void chipcHw_setClock(chipcHw_CLOCK_e clock,
                                    chipcHw_OPTYPE_e type, int mode)
 {
-       volatile uint32_t *pPLLReg = (uint32_t *) 0x0;
-       volatile uint32_t *pClockCtrl = (uint32_t *) 0x0;
+       uint32_t __iomem *pPLLReg = NULL;
+       uint32_t __iomem *pClockCtrl = NULL;
 
        switch (clock) {
        case chipcHw_CLOCK_DDR:
@@ -1071,7 +1074,7 @@ static inline void chipcHw_bypassClockDisable(chipcHw_CLOCK_e clock)
 /****************************************************************************/
 static inline int chipcHw_isSoftwareStrapsEnable(void)
 {
-       return pChipcHw->SoftStraps & 0x00000001;
+       return readl(&pChipcHw->SoftStraps) & 0x00000001;
 }
 
 /****************************************************************************/
@@ -1138,7 +1141,7 @@ static inline void chipcHw_pll2TestDisable(void)
 /****************************************************************************/
 static inline int chipcHw_isPllTestEnable(void)
 {
-       return pChipcHw->PLLConfig & chipcHw_REG_PLL_CONFIG_TEST_ENABLE;
+       return readl(&pChipcHw->PLLConfig) & chipcHw_REG_PLL_CONFIG_TEST_ENABLE;
 }
 
 /****************************************************************************/
@@ -1147,7 +1150,7 @@ static inline int chipcHw_isPllTestEnable(void)
 /****************************************************************************/
 static inline int chipcHw_isPll2TestEnable(void)
 {
-       return pChipcHw->PLLConfig2 & chipcHw_REG_PLL_CONFIG_TEST_ENABLE;
+       return readl(&pChipcHw->PLLConfig2) & chipcHw_REG_PLL_CONFIG_TEST_ENABLE;
 }
 
 /****************************************************************************/
@@ -1183,8 +1186,8 @@ static inline void chipcHw_pll2TestSelect(uint32_t val)
 /****************************************************************************/
 static inline uint8_t chipcHw_getPllTestSelected(void)
 {
-       return (uint8_t) ((pChipcHw->
-                          PLLConfig & chipcHw_REG_PLL_CONFIG_TEST_SELECT_MASK)
+       return (uint8_t) ((readl(&pChipcHw->
+                          PLLConfig) & chipcHw_REG_PLL_CONFIG_TEST_SELECT_MASK)
                          >> chipcHw_REG_PLL_CONFIG_TEST_SELECT_SHIFT);
 }
 
@@ -1194,8 +1197,8 @@ static inline uint8_t chipcHw_getPllTestSelected(void)
 /****************************************************************************/
 static inline uint8_t chipcHw_getPll2TestSelected(void)
 {
-       return (uint8_t) ((pChipcHw->
-                          PLLConfig2 & chipcHw_REG_PLL_CONFIG_TEST_SELECT_MASK)
+       return (uint8_t) ((readl(&pChipcHw->
+                          PLLConfig2) & chipcHw_REG_PLL_CONFIG_TEST_SELECT_MASK)
                          >> chipcHw_REG_PLL_CONFIG_TEST_SELECT_SHIFT);
 }
 
@@ -1208,7 +1211,8 @@ static inline uint8_t chipcHw_getPll2TestSelected(void)
 static inline void chipcHw_pll1Disable(void)
 {
        REG_LOCAL_IRQ_SAVE;
-       pChipcHw->PLLConfig |= chipcHw_REG_PLL_CONFIG_POWER_DOWN;
+       writel(readl(&pChipcHw->PLLConfig) | chipcHw_REG_PLL_CONFIG_POWER_DOWN,
+               &pChipcHw->PLLConfig);
        REG_LOCAL_IRQ_RESTORE;
 }
 
@@ -1221,7 +1225,8 @@ static inline void chipcHw_pll1Disable(void)
 static inline void chipcHw_pll2Disable(void)
 {
        REG_LOCAL_IRQ_SAVE;
-       pChipcHw->PLLConfig2 |= chipcHw_REG_PLL_CONFIG_POWER_DOWN;
+       writel(readl(&pChipcHw->PLLConfig2) | chipcHw_REG_PLL_CONFIG_POWER_DOWN,
+               &pChipcHw->PLLConfig2);
        REG_LOCAL_IRQ_RESTORE;
 }
 
@@ -1233,7 +1238,8 @@ static inline void chipcHw_pll2Disable(void)
 static inline void chipcHw_ddrPhaseAlignInterruptEnable(void)
 {
        REG_LOCAL_IRQ_SAVE;
-       pChipcHw->Spare1 |= chipcHw_REG_SPARE1_DDR_PHASE_INTR_ENABLE;
+       writel(readl(&pChipcHw->Spare1) | chipcHw_REG_SPARE1_DDR_PHASE_INTR_ENABLE,
+               &pChipcHw->Spare1);
        REG_LOCAL_IRQ_RESTORE;
 }
 
@@ -1245,7 +1251,8 @@ static inline void chipcHw_ddrPhaseAlignInterruptEnable(void)
 static inline void chipcHw_ddrPhaseAlignInterruptDisable(void)
 {
        REG_LOCAL_IRQ_SAVE;
-       pChipcHw->Spare1 &= ~chipcHw_REG_SPARE1_DDR_PHASE_INTR_ENABLE;
+       writel(readl(&pChipcHw->Spare1) & ~chipcHw_REG_SPARE1_DDR_PHASE_INTR_ENABLE,
+               &pChipcHw->Spare1);
        REG_LOCAL_IRQ_RESTORE;
 }
 
@@ -1333,7 +1340,8 @@ static inline void chipcHw_ddrHwPhaseAlignDisable(void)
 static inline void chipcHw_vpmSwPhaseAlignEnable(void)
 {
        REG_LOCAL_IRQ_SAVE;
-       pChipcHw->VPMPhaseCtrl1 |= chipcHw_REG_VPM_SW_PHASE_CTRL_ENABLE;
+       writel(readl(&pChipcHw->VPMPhaseCtrl1) | chipcHw_REG_VPM_SW_PHASE_CTRL_ENABLE,
+                       &pChipcHw->VPMPhaseCtrl1);
        REG_LOCAL_IRQ_RESTORE;
 }
 
@@ -1372,7 +1380,8 @@ static inline void chipcHw_vpmHwPhaseAlignEnable(void)
 static inline void chipcHw_vpmHwPhaseAlignDisable(void)
 {
        REG_LOCAL_IRQ_SAVE;
-       pChipcHw->VPMPhaseCtrl1 &= ~chipcHw_REG_VPM_HW_PHASE_CTRL_ENABLE;
+       writel(readl(&pChipcHw->VPMPhaseCtrl1) & ~chipcHw_REG_VPM_HW_PHASE_CTRL_ENABLE,
+               &pChipcHw->VPMPhaseCtrl1);
        REG_LOCAL_IRQ_RESTORE;
 }
 
@@ -1474,8 +1483,8 @@ chipcHw_setVpmHwPhaseAlignMargin(chipcHw_VPM_HW_PHASE_MARGIN_e margin)
 /****************************************************************************/
 static inline uint32_t chipcHw_isDdrHwPhaseAligned(void)
 {
-       return (pChipcHw->
-               PhaseAlignStatus & chipcHw_REG_DDR_PHASE_ALIGNED) ? 1 : 0;
+       return (readl(&pChipcHw->
+               PhaseAlignStatus) & chipcHw_REG_DDR_PHASE_ALIGNED) ? 1 : 0;
 }
 
 /****************************************************************************/
@@ -1488,8 +1497,8 @@ static inline uint32_t chipcHw_isDdrHwPhaseAligned(void)
 /****************************************************************************/
 static inline uint32_t chipcHw_isVpmHwPhaseAligned(void)
 {
-       return (pChipcHw->
-               PhaseAlignStatus & chipcHw_REG_VPM_PHASE_ALIGNED) ? 1 : 0;
+       return (readl(&pChipcHw->
+               PhaseAlignStatus) & chipcHw_REG_VPM_PHASE_ALIGNED) ? 1 : 0;
 }
 
 /****************************************************************************/
@@ -1500,8 +1509,8 @@ static inline uint32_t chipcHw_isVpmHwPhaseAligned(void)
 /****************************************************************************/
 static inline uint32_t chipcHw_getDdrHwPhaseAlignStatus(void)
 {
-       return (pChipcHw->
-               PhaseAlignStatus & chipcHw_REG_DDR_PHASE_STATUS_MASK) >>
+       return (readl(&pChipcHw->
+               PhaseAlignStatus) & chipcHw_REG_DDR_PHASE_STATUS_MASK) >>
            chipcHw_REG_DDR_PHASE_STATUS_SHIFT;
 }
 
@@ -1513,8 +1522,8 @@ static inline uint32_t chipcHw_getDdrHwPhaseAlignStatus(void)
 /****************************************************************************/
 static inline uint32_t chipcHw_getVpmHwPhaseAlignStatus(void)
 {
-       return (pChipcHw->
-               PhaseAlignStatus & chipcHw_REG_VPM_PHASE_STATUS_MASK) >>
+       return (readl(&pChipcHw->
+               PhaseAlignStatus) & chipcHw_REG_VPM_PHASE_STATUS_MASK) >>
            chipcHw_REG_VPM_PHASE_STATUS_SHIFT;
 }
 
@@ -1526,8 +1535,8 @@ static inline uint32_t chipcHw_getVpmHwPhaseAlignStatus(void)
 /****************************************************************************/
 static inline uint32_t chipcHw_getDdrPhaseControl(void)
 {
-       return (pChipcHw->
-               PhaseAlignStatus & chipcHw_REG_DDR_PHASE_CTRL_MASK) >>
+       return (readl(&pChipcHw->
+               PhaseAlignStatus) & chipcHw_REG_DDR_PHASE_CTRL_MASK) >>
            chipcHw_REG_DDR_PHASE_CTRL_SHIFT;
 }
 
@@ -1539,8 +1548,8 @@ static inline uint32_t chipcHw_getDdrPhaseControl(void)
 /****************************************************************************/
 static inline uint32_t chipcHw_getVpmPhaseControl(void)
 {
-       return (pChipcHw->
-               PhaseAlignStatus & chipcHw_REG_VPM_PHASE_CTRL_MASK) >>
+       return (readl(&pChipcHw->
+               PhaseAlignStatus) & chipcHw_REG_VPM_PHASE_CTRL_MASK) >>
            chipcHw_REG_VPM_PHASE_CTRL_SHIFT;
 }
 
index b162448f613c969a0bc002df3a8b33c2899eaef3..26f5d0e4e1dd7f84214f1a0273c57d7168ab5b8b 100644 (file)
@@ -24,7 +24,7 @@
 #define CHIPCHW_REG_H
 
 #include <mach/csp/mm_io.h>
-#include <csp/reg.h>
+#include <mach/csp/reg.h>
 #include <mach/csp/ddrcReg.h>
 
 #define chipcHw_BASE_ADDRESS    MM_IO_BASE_CHIPC
@@ -131,8 +131,8 @@ typedef struct {
        uint32_t MiscInput_0_15;        /* Input type for MISC 0 - 16 */
 } chipcHw_REG_t;
 
-#define pChipcHw  ((volatile chipcHw_REG_t *) chipcHw_BASE_ADDRESS)
-#define pChipcPhysical  ((volatile chipcHw_REG_t *) MM_ADDR_IO_CHIPC)
+#define pChipcHw  ((chipcHw_REG_t __iomem *) chipcHw_BASE_ADDRESS)
+#define pChipcPhysical  (MM_ADDR_IO_CHIPC)
 
 #define chipcHw_REG_CHIPID_BASE_MASK                    0xFFFFF000
 #define chipcHw_REG_CHIPID_BASE_SHIFT                   12
index f1b68e26fa6dec7ec7b06f0c5bb654f149244243..39da2c1fdafb813cab8bf213dfedca717de683fa 100644 (file)
@@ -30,8 +30,8 @@ extern "C" {
 
 /* ---- Include Files ---------------------------------------------------- */
 
-#include <csp/reg.h>
-#include <csp/stdint.h>
+#include <mach/csp/reg.h>
+#include <linux/types.h>
 
 #include <mach/csp/mm_io.h>
 
@@ -416,7 +416,7 @@ extern "C" {
        } ddrcReg_PHY_ADDR_CTL_REG_t;
 
 #define ddrcReg_PHY_ADDR_CTL_REG_OFFSET                 0x0400
-#define ddrcReg_PHY_ADDR_CTL_REGP                       ((volatile ddrcReg_PHY_ADDR_CTL_REG_t *) (MM_IO_BASE_DDRC + ddrcReg_PHY_ADDR_CTL_REG_OFFSET))
+#define ddrcReg_PHY_ADDR_CTL_REGP                       ((volatile ddrcReg_PHY_ADDR_CTL_REG_t __iomem*) (MM_IO_BASE_DDRC + ddrcReg_PHY_ADDR_CTL_REG_OFFSET))
 
 /* @todo These SS definitions are duplicates of ones below */
 
similarity index 99%
rename from arch/arm/mach-bcmring/include/csp/dmacHw.h
rename to arch/arm/mach-bcmring/include/mach/csp/dmacHw.h
index e6a1dc484ca728f761a1a57c7cc73b0448371750..9dc90f46a84d919ec122af0bb8021d6d3066c73b 100644 (file)
@@ -23,9 +23,9 @@
 #ifndef _DMACHW_H
 #define _DMACHW_H
 
-#include <stddef.h>
+#include <linux/stddef.h>
 
-#include <csp/stdint.h>
+#include <linux/types.h>
 #include <mach/csp/dmacHw_reg.h>
 
 /* Define DMA Channel ID using DMA controller number (m) and channel number (c).
index d67e2f8c22de0c261c72c837bef0bca0be22e102..9d9455e0c3911c6c5f99866107a3e872d0080b53 100644 (file)
@@ -24,7 +24,7 @@
 #ifndef _DMACHW_PRIV_H
 #define _DMACHW_PRIV_H
 
-#include <csp/stdint.h>
+#include <linux/types.h>
 
 /* Data type for DMA Link List Item */
 typedef struct {
index f1ecf96f2da56980f5d03ce9bd67eb277ae47ae2..7cd0aafa6f6e65697507862a359d9ca8022973ad 100644 (file)
@@ -24,7 +24,7 @@
 #ifndef _DMACHW_REG_H
 #define _DMACHW_REG_H
 
-#include <csp/stdint.h>
+#include <linux/types.h>
 #include <mach/csp/mm_io.h>
 
 /* Data type for 64 bit little endian register */
@@ -121,75 +121,75 @@ typedef struct {
 } dmacHw_MISC_t;
 
 /* Base registers */
-#define dmacHw_0_MODULE_BASE_ADDR        (char *) MM_IO_BASE_DMA0      /* DMAC 0 module's base address */
-#define dmacHw_1_MODULE_BASE_ADDR        (char *) MM_IO_BASE_DMA1      /* DMAC 1 module's base address */
+#define dmacHw_0_MODULE_BASE_ADDR        (char __iomem*) MM_IO_BASE_DMA0       /* DMAC 0 module's base address */
+#define dmacHw_1_MODULE_BASE_ADDR        (char __iomem*) MM_IO_BASE_DMA1       /* DMAC 1 module's base address */
 
 extern uint32_t dmaChannelCount_0;
 extern uint32_t dmaChannelCount_1;
 
 /* Define channel specific registers */
-#define dmacHw_CHAN_BASE(module, chan)          ((dmacHw_CH_REG_t *) ((char *)((module) ? dmacHw_1_MODULE_BASE_ADDR : dmacHw_0_MODULE_BASE_ADDR) + ((chan) * sizeof(dmacHw_CH_REG_t))))
+#define dmacHw_CHAN_BASE(module, chan)          ((dmacHw_CH_REG_t __iomem*) ((char __iomem*)((module) ? dmacHw_1_MODULE_BASE_ADDR : dmacHw_0_MODULE_BASE_ADDR) + ((chan) * sizeof(dmacHw_CH_REG_t))))
 
 /* Raw interrupt status registers */
-#define dmacHw_REG_INT_RAW_BASE(module)         ((char *)dmacHw_CHAN_BASE((module), ((module) ? dmaChannelCount_1 : dmaChannelCount_0)))
-#define dmacHw_REG_INT_RAW_TRAN(module)         (((dmacHw_INT_RAW_t *) dmacHw_REG_INT_RAW_BASE((module)))->RawTfr.lo)
-#define dmacHw_REG_INT_RAW_BLOCK(module)        (((dmacHw_INT_RAW_t *) dmacHw_REG_INT_RAW_BASE((module)))->RawBlock.lo)
-#define dmacHw_REG_INT_RAW_STRAN(module)        (((dmacHw_INT_RAW_t *) dmacHw_REG_INT_RAW_BASE((module)))->RawSrcTran.lo)
-#define dmacHw_REG_INT_RAW_DTRAN(module)        (((dmacHw_INT_RAW_t *) dmacHw_REG_INT_RAW_BASE((module)))->RawDstTran.lo)
-#define dmacHw_REG_INT_RAW_ERROR(module)        (((dmacHw_INT_RAW_t *) dmacHw_REG_INT_RAW_BASE((module)))->RawErr.lo)
+#define dmacHw_REG_INT_RAW_BASE(module)         ((char __iomem *)dmacHw_CHAN_BASE((module), ((module) ? dmaChannelCount_1 : dmaChannelCount_0)))
+#define dmacHw_REG_INT_RAW_TRAN(module)         (((dmacHw_INT_RAW_t __iomem *) dmacHw_REG_INT_RAW_BASE((module)))->RawTfr.lo)
+#define dmacHw_REG_INT_RAW_BLOCK(module)        (((dmacHw_INT_RAW_t __iomem *) dmacHw_REG_INT_RAW_BASE((module)))->RawBlock.lo)
+#define dmacHw_REG_INT_RAW_STRAN(module)        (((dmacHw_INT_RAW_t __iomem *) dmacHw_REG_INT_RAW_BASE((module)))->RawSrcTran.lo)
+#define dmacHw_REG_INT_RAW_DTRAN(module)        (((dmacHw_INT_RAW_t __iomem *) dmacHw_REG_INT_RAW_BASE((module)))->RawDstTran.lo)
+#define dmacHw_REG_INT_RAW_ERROR(module)        (((dmacHw_INT_RAW_t __iomem *) dmacHw_REG_INT_RAW_BASE((module)))->RawErr.lo)
 
 /* Interrupt status registers */
-#define dmacHw_REG_INT_STAT_BASE(module)        ((char *)(dmacHw_REG_INT_RAW_BASE((module)) + sizeof(dmacHw_INT_RAW_t)))
-#define dmacHw_REG_INT_STAT_TRAN(module)        (((dmacHw_INT_STATUS_t *) dmacHw_REG_INT_STAT_BASE((module)))->StatusTfr.lo)
-#define dmacHw_REG_INT_STAT_BLOCK(module)       (((dmacHw_INT_STATUS_t *) dmacHw_REG_INT_STAT_BASE((module)))->StatusBlock.lo)
-#define dmacHw_REG_INT_STAT_STRAN(module)       (((dmacHw_INT_STATUS_t *) dmacHw_REG_INT_STAT_BASE((module)))->StatusSrcTran.lo)
-#define dmacHw_REG_INT_STAT_DTRAN(module)       (((dmacHw_INT_STATUS_t *) dmacHw_REG_INT_STAT_BASE((module)))->StatusDstTran.lo)
-#define dmacHw_REG_INT_STAT_ERROR(module)       (((dmacHw_INT_STATUS_t *) dmacHw_REG_INT_STAT_BASE((module)))->StatusErr.lo)
+#define dmacHw_REG_INT_STAT_BASE(module)        ((char __iomem*)(dmacHw_REG_INT_RAW_BASE((module)) + sizeof(dmacHw_INT_RAW_t)))
+#define dmacHw_REG_INT_STAT_TRAN(module)        (((dmacHw_INT_STATUS_t __iomem *) dmacHw_REG_INT_STAT_BASE((module)))->StatusTfr.lo)
+#define dmacHw_REG_INT_STAT_BLOCK(module)       (((dmacHw_INT_STATUS_t __iomem *) dmacHw_REG_INT_STAT_BASE((module)))->StatusBlock.lo)
+#define dmacHw_REG_INT_STAT_STRAN(module)       (((dmacHw_INT_STATUS_t __iomem *) dmacHw_REG_INT_STAT_BASE((module)))->StatusSrcTran.lo)
+#define dmacHw_REG_INT_STAT_DTRAN(module)       (((dmacHw_INT_STATUS_t __iomem *) dmacHw_REG_INT_STAT_BASE((module)))->StatusDstTran.lo)
+#define dmacHw_REG_INT_STAT_ERROR(module)       (((dmacHw_INT_STATUS_t __iomem *) dmacHw_REG_INT_STAT_BASE((module)))->StatusErr.lo)
 
 /* Interrupt status registers */
-#define dmacHw_REG_INT_MASK_BASE(module)        ((char *)(dmacHw_REG_INT_STAT_BASE((module)) + sizeof(dmacHw_INT_STATUS_t)))
-#define dmacHw_REG_INT_MASK_TRAN(module)        (((dmacHw_INT_MASK_t *) dmacHw_REG_INT_MASK_BASE((module)))->MaskTfr.lo)
-#define dmacHw_REG_INT_MASK_BLOCK(module)       (((dmacHw_INT_MASK_t *) dmacHw_REG_INT_MASK_BASE((module)))->MaskBlock.lo)
-#define dmacHw_REG_INT_MASK_STRAN(module)       (((dmacHw_INT_MASK_t *) dmacHw_REG_INT_MASK_BASE((module)))->MaskSrcTran.lo)
-#define dmacHw_REG_INT_MASK_DTRAN(module)       (((dmacHw_INT_MASK_t *) dmacHw_REG_INT_MASK_BASE((module)))->MaskDstTran.lo)
-#define dmacHw_REG_INT_MASK_ERROR(module)       (((dmacHw_INT_MASK_t *) dmacHw_REG_INT_MASK_BASE((module)))->MaskErr.lo)
+#define dmacHw_REG_INT_MASK_BASE(module)        ((char __iomem*)(dmacHw_REG_INT_STAT_BASE((module)) + sizeof(dmacHw_INT_STATUS_t)))
+#define dmacHw_REG_INT_MASK_TRAN(module)        (((dmacHw_INT_MASK_t __iomem *) dmacHw_REG_INT_MASK_BASE((module)))->MaskTfr.lo)
+#define dmacHw_REG_INT_MASK_BLOCK(module)       (((dmacHw_INT_MASK_t __iomem *) dmacHw_REG_INT_MASK_BASE((module)))->MaskBlock.lo)
+#define dmacHw_REG_INT_MASK_STRAN(module)       (((dmacHw_INT_MASK_t __iomem *) dmacHw_REG_INT_MASK_BASE((module)))->MaskSrcTran.lo)
+#define dmacHw_REG_INT_MASK_DTRAN(module)       (((dmacHw_INT_MASK_t __iomem *) dmacHw_REG_INT_MASK_BASE((module)))->MaskDstTran.lo)
+#define dmacHw_REG_INT_MASK_ERROR(module)       (((dmacHw_INT_MASK_t __iomem *) dmacHw_REG_INT_MASK_BASE((module)))->MaskErr.lo)
 
 /* Interrupt clear registers */
-#define dmacHw_REG_INT_CLEAR_BASE(module)       ((char *)(dmacHw_REG_INT_MASK_BASE((module)) + sizeof(dmacHw_INT_MASK_t)))
-#define dmacHw_REG_INT_CLEAR_TRAN(module)       (((dmacHw_INT_CLEAR_t *) dmacHw_REG_INT_CLEAR_BASE((module)))->ClearTfr.lo)
-#define dmacHw_REG_INT_CLEAR_BLOCK(module)      (((dmacHw_INT_CLEAR_t *) dmacHw_REG_INT_CLEAR_BASE((module)))->ClearBlock.lo)
-#define dmacHw_REG_INT_CLEAR_STRAN(module)      (((dmacHw_INT_CLEAR_t *) dmacHw_REG_INT_CLEAR_BASE((module)))->ClearSrcTran.lo)
-#define dmacHw_REG_INT_CLEAR_DTRAN(module)      (((dmacHw_INT_CLEAR_t *) dmacHw_REG_INT_CLEAR_BASE((module)))->ClearDstTran.lo)
-#define dmacHw_REG_INT_CLEAR_ERROR(module)      (((dmacHw_INT_CLEAR_t *) dmacHw_REG_INT_CLEAR_BASE((module)))->ClearErr.lo)
-#define dmacHw_REG_INT_STATUS(module)           (((dmacHw_INT_CLEAR_t *) dmacHw_REG_INT_CLEAR_BASE((module)))->StatusInt.lo)
+#define dmacHw_REG_INT_CLEAR_BASE(module)       ((char __iomem*)(dmacHw_REG_INT_MASK_BASE((module)) + sizeof(dmacHw_INT_MASK_t)))
+#define dmacHw_REG_INT_CLEAR_TRAN(module)       (((dmacHw_INT_CLEAR_t __iomem *) dmacHw_REG_INT_CLEAR_BASE((module)))->ClearTfr.lo)
+#define dmacHw_REG_INT_CLEAR_BLOCK(module)      (((dmacHw_INT_CLEAR_t __iomem *) dmacHw_REG_INT_CLEAR_BASE((module)))->ClearBlock.lo)
+#define dmacHw_REG_INT_CLEAR_STRAN(module)      (((dmacHw_INT_CLEAR_t __iomem *) dmacHw_REG_INT_CLEAR_BASE((module)))->ClearSrcTran.lo)
+#define dmacHw_REG_INT_CLEAR_DTRAN(module)      (((dmacHw_INT_CLEAR_t __iomem *) dmacHw_REG_INT_CLEAR_BASE((module)))->ClearDstTran.lo)
+#define dmacHw_REG_INT_CLEAR_ERROR(module)      (((dmacHw_INT_CLEAR_t __iomem *) dmacHw_REG_INT_CLEAR_BASE((module)))->ClearErr.lo)
+#define dmacHw_REG_INT_STATUS(module)           (((dmacHw_INT_CLEAR_t __iomem *) dmacHw_REG_INT_CLEAR_BASE((module)))->StatusInt.lo)
 
 /* Software handshaking registers */
-#define dmacHw_REG_SW_HS_BASE(module)           ((char *)(dmacHw_REG_INT_CLEAR_BASE((module)) + sizeof(dmacHw_INT_CLEAR_t)))
-#define dmacHw_REG_SW_HS_SRC_REQ(module)        (((dmacHw_SW_HANDSHAKE_t *) dmacHw_REG_SW_HS_BASE((module)))->ReqSrcReg.lo)
-#define dmacHw_REG_SW_HS_DST_REQ(module)        (((dmacHw_SW_HANDSHAKE_t *) dmacHw_REG_SW_HS_BASE((module)))->ReqDstReg.lo)
-#define dmacHw_REG_SW_HS_SRC_SGL_REQ(module)    (((dmacHw_SW_HANDSHAKE_t *) dmacHw_REG_SW_HS_BASE((module)))->SglReqSrcReg.lo)
-#define dmacHw_REG_SW_HS_DST_SGL_REQ(module)    (((dmacHw_SW_HANDSHAKE_t *) dmacHw_REG_SW_HS_BASE((module)))->SglReqDstReg.lo)
-#define dmacHw_REG_SW_HS_SRC_LST_REQ(module)    (((dmacHw_SW_HANDSHAKE_t *) dmacHw_REG_SW_HS_BASE((module)))->LstSrcReg.lo)
-#define dmacHw_REG_SW_HS_DST_LST_REQ(module)    (((dmacHw_SW_HANDSHAKE_t *) dmacHw_REG_SW_HS_BASE((module)))->LstDstReg.lo)
+#define dmacHw_REG_SW_HS_BASE(module)           ((char __iomem*)(dmacHw_REG_INT_CLEAR_BASE((module)) + sizeof(dmacHw_INT_CLEAR_t)))
+#define dmacHw_REG_SW_HS_SRC_REQ(module)        (((dmacHw_SW_HANDSHAKE_t __iomem *) dmacHw_REG_SW_HS_BASE((module)))->ReqSrcReg.lo)
+#define dmacHw_REG_SW_HS_DST_REQ(module)        (((dmacHw_SW_HANDSHAKE_t __iomem *) dmacHw_REG_SW_HS_BASE((module)))->ReqDstReg.lo)
+#define dmacHw_REG_SW_HS_SRC_SGL_REQ(module)    (((dmacHw_SW_HANDSHAKE_t __iomem *) dmacHw_REG_SW_HS_BASE((module)))->SglReqSrcReg.lo)
+#define dmacHw_REG_SW_HS_DST_SGL_REQ(module)    (((dmacHw_SW_HANDSHAKE_t __iomem *) dmacHw_REG_SW_HS_BASE((module)))->SglReqDstReg.lo)
+#define dmacHw_REG_SW_HS_SRC_LST_REQ(module)    (((dmacHw_SW_HANDSHAKE_t __iomem *) dmacHw_REG_SW_HS_BASE((module)))->LstSrcReg.lo)
+#define dmacHw_REG_SW_HS_DST_LST_REQ(module)    (((dmacHw_SW_HANDSHAKE_t __iomem *) dmacHw_REG_SW_HS_BASE((module)))->LstDstReg.lo)
 
 /* Miscellaneous registers */
-#define dmacHw_REG_MISC_BASE(module)            ((char *)(dmacHw_REG_SW_HS_BASE((module)) + sizeof(dmacHw_SW_HANDSHAKE_t)))
-#define dmacHw_REG_MISC_CFG(module)             (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->DmaCfgReg.lo)
-#define dmacHw_REG_MISC_CH_ENABLE(module)       (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->ChEnReg.lo)
-#define dmacHw_REG_MISC_ID(module)              (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->DmaIdReg.lo)
-#define dmacHw_REG_MISC_TEST(module)            (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->DmaTestReg.lo)
-#define dmacHw_REG_MISC_COMP_PARAM1_LO(module)  (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->CompParm1.lo)
-#define dmacHw_REG_MISC_COMP_PARAM1_HI(module)  (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->CompParm1.hi)
-#define dmacHw_REG_MISC_COMP_PARAM2_LO(module)  (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->CompParm2.lo)
-#define dmacHw_REG_MISC_COMP_PARAM2_HI(module)  (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->CompParm2.hi)
-#define dmacHw_REG_MISC_COMP_PARAM3_LO(module)  (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->CompParm3.lo)
-#define dmacHw_REG_MISC_COMP_PARAM3_HI(module)  (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->CompParm3.hi)
-#define dmacHw_REG_MISC_COMP_PARAM4_LO(module)  (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->CompParm4.lo)
-#define dmacHw_REG_MISC_COMP_PARAM4_HI(module)  (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->CompParm4.hi)
-#define dmacHw_REG_MISC_COMP_PARAM5_LO(module)  (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->CompParm5.lo)
-#define dmacHw_REG_MISC_COMP_PARAM5_HI(module)  (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->CompParm5.hi)
-#define dmacHw_REG_MISC_COMP_PARAM6_LO(module)  (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->CompParm6.lo)
-#define dmacHw_REG_MISC_COMP_PARAM6_HI(module)  (((dmacHw_MISC_t *) dmacHw_REG_MISC_BASE((module)))->CompParm6.hi)
+#define dmacHw_REG_MISC_BASE(module)            ((char __iomem*)(dmacHw_REG_SW_HS_BASE((module)) + sizeof(dmacHw_SW_HANDSHAKE_t)))
+#define dmacHw_REG_MISC_CFG(module)             (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->DmaCfgReg.lo)
+#define dmacHw_REG_MISC_CH_ENABLE(module)       (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->ChEnReg.lo)
+#define dmacHw_REG_MISC_ID(module)              (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->DmaIdReg.lo)
+#define dmacHw_REG_MISC_TEST(module)            (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->DmaTestReg.lo)
+#define dmacHw_REG_MISC_COMP_PARAM1_LO(module)  (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->CompParm1.lo)
+#define dmacHw_REG_MISC_COMP_PARAM1_HI(module)  (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->CompParm1.hi)
+#define dmacHw_REG_MISC_COMP_PARAM2_LO(module)  (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->CompParm2.lo)
+#define dmacHw_REG_MISC_COMP_PARAM2_HI(module)  (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->CompParm2.hi)
+#define dmacHw_REG_MISC_COMP_PARAM3_LO(module)  (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->CompParm3.lo)
+#define dmacHw_REG_MISC_COMP_PARAM3_HI(module)  (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->CompParm3.hi)
+#define dmacHw_REG_MISC_COMP_PARAM4_LO(module)  (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->CompParm4.lo)
+#define dmacHw_REG_MISC_COMP_PARAM4_HI(module)  (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->CompParm4.hi)
+#define dmacHw_REG_MISC_COMP_PARAM5_LO(module)  (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->CompParm5.lo)
+#define dmacHw_REG_MISC_COMP_PARAM5_HI(module)  (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->CompParm5.hi)
+#define dmacHw_REG_MISC_COMP_PARAM6_LO(module)  (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->CompParm6.lo)
+#define dmacHw_REG_MISC_COMP_PARAM6_HI(module)  (((dmacHw_MISC_t __iomem*) dmacHw_REG_MISC_BASE((module)))->CompParm6.hi)
 
 /* Channel control registers */
 #define dmacHw_REG_SAR(module, chan)            (dmacHw_CHAN_BASE((module), (chan))->ChannelSar.lo)
index cfa91bed9d3477303c4462855f2609177b8859a0..27f59dd277923e8be3cf5e6415d5d462493e0be2 100644 (file)
@@ -18,7 +18,7 @@
 
 /* ---- Include Files ---------------------------------------------------- */
 
-#include <cfg_global.h>
+#include <mach/cfg_global.h>
 #include <mach/csp/cap_inline.h>
 
 #if defined(__KERNEL__)
index 0aeb6a6fe7f8917b206993364455947564a78778..f59db25b5632a601c563d63ee11bb536e83604ef 100644 (file)
@@ -27,8 +27,8 @@
 #define _INTCHW_REG_H
 
 /* ---- Include Files ---------------------------------------------------- */
-#include <csp/stdint.h>
-#include <csp/reg.h>
+#include <linux/types.h>
+#include <mach/csp/reg.h>
 #include <mach/csp/mm_io.h>
 
 /* ---- Public Constants and Types --------------------------------------- */
@@ -37,9 +37,9 @@
 #define INTCHW_NUM_INTC           3
 
 /* Defines for interrupt controllers. This simplifies and cleans up the function calls. */
-#define INTCHW_INTC0    ((void *)MM_IO_BASE_INTC0)
-#define INTCHW_INTC1    ((void *)MM_IO_BASE_INTC1)
-#define INTCHW_SINTC    ((void *)MM_IO_BASE_SINTC)
+#define INTCHW_INTC0    (MM_IO_BASE_INTC0)
+#define INTCHW_INTC1    (MM_IO_BASE_INTC1)
+#define INTCHW_SINTC    (MM_IO_BASE_SINTC)
 
 /* INTC0 - interrupt controller 0 */
 #define INTCHW_INTC0_PIF_BITNUM           31   /* Peripheral interface interrupt */
 /* ---- Public Variable Externs ------------------------------------------ */
 /* ---- Public Function Prototypes --------------------------------------- */
 /* Clear one or more IRQ interrupts. */
-static inline void intcHw_irq_disable(void *basep, uint32_t mask)
+static inline void intcHw_irq_disable(void __iomem *basep, uint32_t mask)
 {
-       __REG32(basep + INTCHW_INTENCLEAR) = mask;
+       writel(mask, basep + INTCHW_INTENCLEAR);
 }
 
 /* Enables one or more IRQ interrupts. */
-static inline void intcHw_irq_enable(void *basep, uint32_t mask)
+static inline void intcHw_irq_enable(void __iomem *basep, uint32_t mask)
 {
-       __REG32(basep + INTCHW_INTENABLE) = mask;
+       writel(mask, basep + INTCHW_INTENABLE);
 }
 
 #endif /* _INTCHW_REG_H */
index ad58cf873377b0a1be0593b12c2acc8e67cc377b..d571962f29047adb41b5b02fa84905825a50cbba 100644 (file)
@@ -29,7 +29,7 @@
 /* ---- Include Files ---------------------------------------------------- */
 
 #if !defined(CSP_SIMULATION)
-#include <cfg_global.h>
+#include <mach/cfg_global.h>
 #endif
 
 /* ---- Public Constants and Types --------------------------------------- */
index de92ec6a01aa4136a2862732703d475ba4dfc517..47450c23685a9b64826b167ce41210d3e3595d55 100644 (file)
@@ -30,7 +30,7 @@
 #include <mach/csp/mm_addr.h>
 
 #if !defined(CSP_SIMULATION)
-#include <cfg_global.h>
+#include <mach/cfg_global.h>
 #endif
 
 /* ---- Public Constants and Types --------------------------------------- */
@@ -49,7 +49,7 @@
 #ifdef __ASSEMBLY__
 #define MM_IO_PHYS_TO_VIRT(phys)       (0xF0000000 | (((phys) >> 4) & 0x0F000000) | ((phys) & 0xFFFFFF))
 #else
-#define MM_IO_PHYS_TO_VIRT(phys)       (((phys) == MM_ADDR_IO_VPM_EXTMEM_RSVD) ? 0xF0000000 : \
+#define MM_IO_PHYS_TO_VIRT(phys)       (void __iomem *)(((phys) == MM_ADDR_IO_VPM_EXTMEM_RSVD) ? 0xF0000000 : \
                        (0xF0000000 | (((phys) >> 4) & 0x0F000000) | ((phys) & 0xFFFFFF)))
 #endif
 #endif
@@ -60,8 +60,8 @@
 #ifdef __ASSEMBLY__
 #define MM_IO_VIRT_TO_PHYS(virt)       ((((virt) & 0x0F000000) << 4) | ((virt) & 0xFFFFFF))
 #else
-#define MM_IO_VIRT_TO_PHYS(virt)       (((virt) == 0xF0000000) ? MM_ADDR_IO_VPM_EXTMEM_RSVD : \
-                       ((((virt) & 0x0F000000) << 4) | ((virt) & 0xFFFFFF)))
+#define MM_IO_VIRT_TO_PHYS(virt)       (((unsigned long)(virt) == 0xF0000000) ? MM_ADDR_IO_VPM_EXTMEM_RSVD : \
+                       ((((unsigned long)(virt) & 0x0F000000) << 4) | ((unsigned long)(virt) & 0xFFFFFF)))
 #endif
 #endif
 
similarity index 81%
rename from arch/arm/mach-bcmring/include/csp/reg.h
rename to arch/arm/mach-bcmring/include/mach/csp/reg.h
index 56654d23c3d7cbba4bc7fb61607c64be6be4dc24..d9cbdca8cd252689c1f7cfeb290374eff5559364 100644 (file)
 
 /* ---- Include Files ---------------------------------------------------- */
 
-#include <csp/stdint.h>
+#include <linux/types.h>
+#include <linux/io.h>
 
 /* ---- Public Constants and Types --------------------------------------- */
 
-#define __REG32(x)      (*((volatile uint32_t *)(x)))
-#define __REG16(x)      (*((volatile uint16_t *)(x)))
-#define __REG8(x)       (*((volatile uint8_t *) (x)))
+#define __REG32(x)      (*((volatile uint32_t __iomem *)(x)))
+#define __REG16(x)      (*((volatile uint16_t __iomem *)(x)))
+#define __REG8(x)       (*((volatile uint8_t __iomem *) (x)))
 
 /* Macros used to define a sequence of reserved registers. The start / end */
 /* are byte offsets in the particular register definition, with the "end" */
 
 #endif
 
-static inline void reg32_modify_and(volatile uint32_t *reg, uint32_t value)
+static inline void reg32_modify_and(volatile uint32_t __iomem *reg, uint32_t value)
 {
        REG_LOCAL_IRQ_SAVE;
-       *reg &= value;
+       __raw_writel(__raw_readl(reg) & value, reg);
        REG_LOCAL_IRQ_RESTORE;
 }
 
-static inline void reg32_modify_or(volatile uint32_t *reg, uint32_t value)
+static inline void reg32_modify_or(volatile uint32_t __iomem *reg, uint32_t value)
 {
        REG_LOCAL_IRQ_SAVE;
-       *reg |= value;
+       __raw_writel(__raw_readl(reg) | value, reg);
        REG_LOCAL_IRQ_RESTORE;
 }
 
-static inline void reg32_modify_mask(volatile uint32_t *reg, uint32_t mask,
+static inline void reg32_modify_mask(volatile uint32_t __iomem *reg, uint32_t mask,
                                     uint32_t value)
 {
        REG_LOCAL_IRQ_SAVE;
-       *reg = (*reg & mask) | value;
+       __raw_writel((__raw_readl(reg) & mask) | value, reg);
        REG_LOCAL_IRQ_RESTORE;
 }
 
-static inline void reg32_write(volatile uint32_t *reg, uint32_t value)
+static inline void reg32_write(volatile uint32_t __iomem *reg, uint32_t value)
 {
-       *reg = value;
+       __raw_writel(value, reg);
 }
 
 #endif /* CSP_REG_H */
index 9cd6a032ab716394dba50986a3a72b2da55f7bd4..55d3cd4fd1e736d3c649d4434be566ac082db17b 100644 (file)
@@ -34,7 +34,7 @@
 /****************************************************************************/
 static inline void secHw_setSecure(uint32_t mask       /*  mask of type secHw_BLK_MASK_XXXXXX */
     ) {
-       secHw_REGS_t *regp = (secHw_REGS_t *) MM_IO_BASE_TZPC;
+       secHw_REGS_t __iomem *regp = MM_IO_BASE_TZPC;
 
        if (mask & 0x0000FFFF) {
                regp->reg[secHw_IDX_LS].setSecure = mask & 0x0000FFFF;
@@ -53,13 +53,13 @@ static inline void secHw_setSecure(uint32_t mask    /*  mask of type secHw_BLK_MASK
 /****************************************************************************/
 static inline void secHw_setUnsecure(uint32_t mask     /*  mask of type secHw_BLK_MASK_XXXXXX */
     ) {
-       secHw_REGS_t *regp = (secHw_REGS_t *) MM_IO_BASE_TZPC;
+       secHw_REGS_t __iomem *regp = MM_IO_BASE_TZPC;
 
        if (mask & 0x0000FFFF) {
-               regp->reg[secHw_IDX_LS].setUnsecure = mask & 0x0000FFFF;
+               writel(mask & 0x0000FFFF, &regp->reg[secHw_IDX_LS].setUnsecure);
        }
        if (mask & 0xFFFF0000) {
-               regp->reg[secHw_IDX_MS].setUnsecure = mask >> 16;
+               writel(mask >> 16, &regp->reg[secHw_IDX_MS].setUnsecure);
        }
 }
 
@@ -71,7 +71,7 @@ static inline void secHw_setUnsecure(uint32_t mask    /*  mask of type secHw_BLK_MA
 /****************************************************************************/
 static inline uint32_t secHw_getStatus(void)
 {
-       secHw_REGS_t *regp = (secHw_REGS_t *) MM_IO_BASE_TZPC;
+       secHw_REGS_t __iomem *regp = MM_IO_BASE_TZPC;
 
        return (regp->reg[1].status << 16) + regp->reg[0].status;
 }
similarity index 99%
rename from arch/arm/mach-bcmring/include/csp/tmrHw.h
rename to arch/arm/mach-bcmring/include/mach/csp/tmrHw.h
index 2cbb530db8ea98eed1b2222570537e7db1d8ed95..1cc882ae60f5bc65b7188f016fc1d1140e646041 100644 (file)
@@ -23,7 +23,7 @@
 #ifndef _TMRHW_H
 #define _TMRHW_H
 
-#include <csp/stdint.h>
+#include <linux/types.h>
 
 typedef uint32_t tmrHw_ID_t;   /* Timer ID */
 typedef uint32_t tmrHw_COUNT_t;        /* Timer count */
index 72543781207b2f2a70e5bfbe5d84f44bec3239a7..13e01384d6fca5e9106e08d41f7f2f8be7921304 100644 (file)
@@ -27,7 +27,7 @@
 
 #include <linux/kernel.h>
 #include <linux/semaphore.h>
-#include <csp/dmacHw.h>
+#include <mach/csp/dmacHw.h>
 #include <mach/timer.h>
 
 /* ---- Constants and Types ---------------------------------------------- */
index 6ae20a649a97ba9b55dd32a423312feae57e5f7b..a0c92b4b8c60450edb9451b3db06f71706597d8c 100644 (file)
@@ -22,7 +22,7 @@
 #define __ASM_ARCH_HARDWARE_H
 
 #include <asm/sizes.h>
-#include <cfg_global.h>
+#include <mach/cfg_global.h>
 #include <mach/csp/mm_io.h>
 
 /* Hardware addresses of major areas.
index 387376ffb56bee3503c32fc89d1154b6292c6912..f8d51a8b0b1506847040c9ae0da435824b72a57e 100644 (file)
@@ -30,7 +30,7 @@
 #define __ASM_ARCH_REG_NAND_H
 
 /* ---- Include Files ---------------------------------------------------- */
-#include <csp/reg.h>
+#include <mach/csp/reg.h>
 #include <mach/reg_umi.h>
 
 /* ---- Constants and Types ---------------------------------------------- */
index 0992842caa77fc919e81f21dfbc66a68a2b9c2b4..56dd9de7d83f4118ffe4dcb9da87e137a8481172 100644 (file)
@@ -30,7 +30,7 @@
 #define __ASM_ARCH_REG_UMI_H
 
 /* ---- Include Files ---------------------------------------------------- */
-#include <csp/reg.h>
+#include <mach/csp/reg.h>
 #include <mach/csp/mm_io.h>
 
 /* ---- Constants and Types ---------------------------------------------- */
 #define REG_UMI_BCH_ERR_LOC_WORD              0x00000018
 /* location within a page (512 byte) */
 #define REG_UMI_BCH_ERR_LOC_PAGE              0x00001FE0
-#define REG_UMI_BCH_ERR_LOC_ADDR(index)     (__REG32(HW_UMI_BASE + 0x64 + (index / 2)*4) >> ((index % 2) * 16))
+#define REG_UMI_BCH_ERR_LOC_ADDR(index)     (readl(HW_UMI_BASE + 0x64 + (index / 2)*4) >> ((index % 2) * 16))
 #endif
index 1adec78ec940ef7a620a23e88752a1f6c0c2d642..33824a81cac4ce28cd68890ec34e638bc35b4e6e 100644 (file)
 #include <mach/hardware.h>
 #include <mach/csp/mm_io.h>
 
-#define IO_DESC(va, sz) { .virtual = va, \
+#define IO_DESC(va, sz) { .virtual = (unsigned long)va, \
        .pfn = __phys_to_pfn(HW_IO_VIRT_TO_PHYS(va)), \
        .length = sz, \
        .type = MT_DEVICE }
 
-#define MEM_DESC(va, sz) { .virtual = va, \
+#define MEM_DESC(va, sz) { .virtual = (unsigned long)va, \
        .pfn = __phys_to_pfn(HW_IO_VIRT_TO_PHYS(va)), \
        .length = sz, \
        .type = MT_MEMORY }
index af9c3d7e2a0cbb6758b9acbc6e343498f06ee0bf..59412903466e560151787e0125e30dbdb801bfd2 100644 (file)
@@ -14,7 +14,7 @@
 
 #include <linux/types.h>
 #include <linux/module.h>
-#include <csp/tmrHw.h>
+#include <mach/csp/tmrHw.h>
 
 #include <mach/timer.h>
 /* The core.c file initializes timers 1 and 3 as a linux clocksource. */
index f2f0256232e3bbbf4f4ac045697e2151f7be7db7..5872b49bfaed8ff84af31d2fe8158ac01402c6dd 100644 (file)
@@ -16,5 +16,3 @@ obj-$(CONFIG_ARCH_CLEP7312) += clep7312.o
 obj-$(CONFIG_ARCH_EDB7211)  += edb7211-arch.o edb7211-mm.o
 obj-$(CONFIG_ARCH_FORTUNET) += fortunet.o
 obj-$(CONFIG_ARCH_P720T)    += p720t.o
-leds-$(CONFIG_ARCH_P720T)   += p720t-leds.o
-obj-$(CONFIG_LEDS)          += $(leds-y)
index f15293bd797437805dd7fcf20a6ac062512144ec..3a4af00db9e39ee4eb51b0e9a36c1f4ac1004a78 100644 (file)
@@ -30,7 +30,6 @@
 #include <asm/sizes.h>
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/leds.h>
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <asm/mach/map.h>
diff --git a/arch/arm/mach-clps711x/p720t-leds.c b/arch/arm/mach-clps711x/p720t-leds.c
deleted file mode 100644 (file)
index bbc449f..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- *  linux/arch/arm/mach-clps711x/leds.c
- *
- *  Integrator LED control routines
- *
- *  Copyright (C) 2000 Deep Blue Solutions Ltd
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-#include <asm/mach-types.h>
-
-static void p720t_leds_event(led_event_t ledevt)
-{
-       unsigned long flags;
-       u32 pddr;
-
-       local_irq_save(flags);
-       switch(ledevt) {
-       case led_idle_start:
-               break;
-
-       case led_idle_end:
-               break;
-
-       case led_timer:
-               pddr = clps_readb(PDDR);
-               clps_writeb(pddr ^ 1, PDDR);
-               break;
-
-       default:
-               break;
-       }
-
-       local_irq_restore(flags);
-}
-
-static int __init leds_init(void)
-{
-       if (machine_is_p720t())
-               leds_event = p720t_leds_event;
-
-       return 0;
-}
-
-arch_initcall(leds_init);
index f266d90b9efc0e8a4cc79b92b8ece9214c31c2e7..b752b586fc2fd2c822677dd8009bd6256a998863 100644 (file)
@@ -23,6 +23,8 @@
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
 
 #include <mach/hardware.h>
 #include <asm/pgtable.h>
@@ -34,6 +36,8 @@
 #include <asm/mach/map.h>
 #include <mach/syspld.h>
 
+#include <asm/hardware/clps7111.h>
+
 #include "common.h"
 
 /*
@@ -107,6 +111,64 @@ static void __init p720t_init_early(void)
        }
 }
 
+/*
+ * LED controled by CPLD
+ */
+#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
+static void p720t_led_set(struct led_classdev *cdev,
+                             enum led_brightness b)
+{
+       u8 reg = clps_readb(PDDR);
+
+       if (b != LED_OFF)
+               reg |= 0x1;
+       else
+               reg &= ~0x1;
+
+       clps_writeb(reg, PDDR);
+}
+
+static enum led_brightness p720t_led_get(struct led_classdev *cdev)
+{
+       u8 reg = clps_readb(PDDR);
+
+       return (reg & 0x1) ? LED_FULL : LED_OFF;
+}
+
+static int __init p720t_leds_init(void)
+{
+
+       struct led_classdev *cdev;
+       int ret;
+
+       if (!machine_is_p720t())
+               return -ENODEV;
+
+       cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
+       if (!cdev)
+               return -ENOMEM;
+
+       cdev->name = "p720t:0";
+       cdev->brightness_set = p720t_led_set;
+       cdev->brightness_get = p720t_led_get;
+       cdev->default_trigger = "heartbeat";
+
+       ret = led_classdev_register(NULL, cdev);
+       if (ret < 0) {
+               kfree(cdev);
+               return ret;
+       }
+
+       return 0;
+}
+
+/*
+ * Since we may have triggers on any subsystem, defer registration
+ * until after subsystem_init.
+ */
+fs_initcall(p720t_leds_init);
+#endif
+
 MACHINE_START(P720T, "ARM-Prospector720T")
        /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
        .atag_offset    = 0x100,
index 5de69f2fcca9fec965fc300b506056c4a1f29e01..f6b9fc70161b43338772a9f092b589aecfb021df 100644 (file)
@@ -162,38 +162,6 @@ static void __init davinci_ntosd2_map_io(void)
        dm644x_init();
 }
 
-/*
- I2C initialization
-*/
-static struct davinci_i2c_platform_data ntosd2_i2c_pdata = {
-       .bus_freq       = 20 /* kHz */,
-       .bus_delay      = 100 /* usec */,
-};
-
-static struct i2c_board_info __initdata ntosd2_i2c_info[] =  {
-};
-
-static int ntosd2_init_i2c(void)
-{
-       int     status;
-
-       davinci_init_i2c(&ntosd2_i2c_pdata);
-       status = gpio_request(NTOSD2_MSP430_IRQ, ntosd2_i2c_info[0].type);
-       if (status == 0) {
-               status = gpio_direction_input(NTOSD2_MSP430_IRQ);
-               if (status == 0) {
-                       status = gpio_to_irq(NTOSD2_MSP430_IRQ);
-                       if (status > 0) {
-                               ntosd2_i2c_info[0].irq = status;
-                               i2c_register_board_info(1,
-                                       ntosd2_i2c_info,
-                                       ARRAY_SIZE(ntosd2_i2c_info));
-                       }
-               }
-       }
-       return status;
-}
-
 static struct davinci_mmc_config davinci_ntosd2_mmc_config = {
        .wires          = 4,
        .version        = MMC_CTLR_VERSION_1
@@ -218,7 +186,6 @@ static __init void davinci_ntosd2_init(void)
 {
        struct clk *aemif_clk;
        struct davinci_soc_info *soc_info = &davinci_soc_info;
-       int     status;
 
        aemif_clk = clk_get(NULL, "aemif");
        clk_enable(aemif_clk);
@@ -242,12 +209,6 @@ static __init void davinci_ntosd2_init(void)
        platform_add_devices(davinci_ntosd2_devices,
                                ARRAY_SIZE(davinci_ntosd2_devices));
 
-       /* Initialize I2C interface specific for this board */
-       status = ntosd2_init_i2c();
-       if (status < 0)
-               pr_warning("davinci_ntosd2_init: msp430 irq setup failed:"
-                                               "        %d\n", status);
-
        davinci_serial_init(&uart_config);
        dm644x_init_asp(&dm644x_ntosd2_snd_data);
 
index 4db5de54b6a7e1658639dc8888a79ec8cede8cc7..bd54d7b7ef8513bba6d937c40c8da022add81eb5 100644 (file)
@@ -49,16 +49,6 @@ static struct map_desc dove_io_desc[] __initdata = {
                .pfn            = __phys_to_pfn(DOVE_NB_REGS_PHYS_BASE),
                .length         = DOVE_NB_REGS_SIZE,
                .type           = MT_DEVICE,
-       }, {
-               .virtual        = DOVE_PCIE0_IO_VIRT_BASE,
-               .pfn            = __phys_to_pfn(DOVE_PCIE0_IO_PHYS_BASE),
-               .length         = DOVE_PCIE0_IO_SIZE,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = DOVE_PCIE1_IO_VIRT_BASE,
-               .pfn            = __phys_to_pfn(DOVE_PCIE1_IO_PHYS_BASE),
-               .length         = DOVE_PCIE1_IO_SIZE,
-               .type           = MT_DEVICE,
        },
 };
 
@@ -102,7 +92,8 @@ void __init dove_ehci1_init(void)
 void __init dove_ge00_init(struct mv643xx_eth_platform_data *eth_data)
 {
        orion_ge00_init(eth_data, DOVE_GE00_PHYS_BASE,
-                       IRQ_DOVE_GE00_SUM, IRQ_DOVE_GE00_ERR);
+                       IRQ_DOVE_GE00_SUM, IRQ_DOVE_GE00_ERR,
+                       1600);
 }
 
 /*****************************************************************************
@@ -288,7 +279,7 @@ void __init dove_init(void)
        printk(KERN_INFO "TCLK = %dMHz\n", (get_tclk() + 499999) / 1000000);
 
 #ifdef CONFIG_CACHE_TAUROS2
-       tauros2_init();
+       tauros2_init(0);
 #endif
        dove_setup_cpu_mbus();
 
index d52b0ef313b7e53c2efa6de67d0ddeddc4790ca5..c91e3004a47bc01f60f470be1d38904b94c13ca6 100644 (file)
 #define DOVE_NB_REGS_SIZE              SZ_8M
 
 #define DOVE_PCIE0_IO_PHYS_BASE                0xf2000000
-#define DOVE_PCIE0_IO_VIRT_BASE                0xfee00000
 #define DOVE_PCIE0_IO_BUS_BASE         0x00000000
-#define DOVE_PCIE0_IO_SIZE             SZ_1M
+#define DOVE_PCIE0_IO_SIZE             SZ_64K
 
 #define DOVE_PCIE1_IO_PHYS_BASE                0xf2100000
-#define DOVE_PCIE1_IO_VIRT_BASE                0xfef00000
-#define DOVE_PCIE1_IO_BUS_BASE         0x00100000
-#define DOVE_PCIE1_IO_SIZE             SZ_1M
+#define DOVE_PCIE1_IO_BUS_BASE         0x00010000
+#define DOVE_PCIE1_IO_SIZE             SZ_64K
 
 /*
  * Dove Core Registers Map
diff --git a/arch/arm/mach-dove/include/mach/io.h b/arch/arm/mach-dove/include/mach/io.h
deleted file mode 100644 (file)
index 29c8b85..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * arch/arm/mach-dove/include/mach/io.h
- *
- * 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.
- */
-
-#ifndef __ASM_ARCH_IO_H
-#define __ASM_ARCH_IO_H
-
-#include "dove.h"
-
-#define IO_SPACE_LIMIT         0xffffffff
-
-#define __io(a)        ((void __iomem *)(((a) - DOVE_PCIE0_IO_BUS_BASE) + \
-                                                DOVE_PCIE0_IO_VIRT_BASE))
-
-#endif
index 47921b0cdc65177e8b198e6d441301cd6a00cd1e..355332d502cb538cdec53e796bdf70b993f381ae 100644 (file)
@@ -26,9 +26,8 @@ struct pcie_port {
        u8                      root_bus_nr;
        void __iomem            *base;
        spinlock_t              conf_lock;
-       char                    io_space_name[16];
        char                    mem_space_name[16];
-       struct resource         res[2];
+       struct resource         res;
 };
 
 static struct pcie_port pcie_port[2];
@@ -53,24 +52,10 @@ static int __init dove_pcie_setup(int nr, struct pci_sys_data *sys)
 
        orion_pcie_setup(pp->base);
 
-       /*
-        * IORESOURCE_IO
-        */
-       snprintf(pp->io_space_name, sizeof(pp->io_space_name),
-                "PCIe %d I/O", pp->index);
-       pp->io_space_name[sizeof(pp->io_space_name) - 1] = 0;
-       pp->res[0].name = pp->io_space_name;
-       if (pp->index == 0) {
-               pp->res[0].start = DOVE_PCIE0_IO_PHYS_BASE;
-               pp->res[0].end = pp->res[0].start + DOVE_PCIE0_IO_SIZE - 1;
-       } else {
-               pp->res[0].start = DOVE_PCIE1_IO_PHYS_BASE;
-               pp->res[0].end = pp->res[0].start + DOVE_PCIE1_IO_SIZE - 1;
-       }
-       pp->res[0].flags = IORESOURCE_IO;
-       if (request_resource(&ioport_resource, &pp->res[0]))
-               panic("Request PCIe IO resource failed\n");
-       pci_add_resource_offset(&sys->resources, &pp->res[0], sys->io_offset);
+       if (pp->index == 0)
+               pci_ioremap_io(sys->busnr * SZ_64K, DOVE_PCIE0_IO_PHYS_BASE);
+       else
+               pci_ioremap_io(sys->busnr * SZ_64K, DOVE_PCIE1_IO_PHYS_BASE);
 
        /*
         * IORESOURCE_MEM
@@ -78,18 +63,18 @@ static int __init dove_pcie_setup(int nr, struct pci_sys_data *sys)
        snprintf(pp->mem_space_name, sizeof(pp->mem_space_name),
                 "PCIe %d MEM", pp->index);
        pp->mem_space_name[sizeof(pp->mem_space_name) - 1] = 0;
-       pp->res[1].name = pp->mem_space_name;
+       pp->res.name = pp->mem_space_name;
        if (pp->index == 0) {
-               pp->res[1].start = DOVE_PCIE0_MEM_PHYS_BASE;
-               pp->res[1].end = pp->res[1].start + DOVE_PCIE0_MEM_SIZE - 1;
+               pp->res.start = DOVE_PCIE0_MEM_PHYS_BASE;
+               pp->res.end = pp->res.start + DOVE_PCIE0_MEM_SIZE - 1;
        } else {
-               pp->res[1].start = DOVE_PCIE1_MEM_PHYS_BASE;
-               pp->res[1].end = pp->res[1].start + DOVE_PCIE1_MEM_SIZE - 1;
+               pp->res.start = DOVE_PCIE1_MEM_PHYS_BASE;
+               pp->res.end = pp->res.start + DOVE_PCIE1_MEM_SIZE - 1;
        }
-       pp->res[1].flags = IORESOURCE_MEM;
-       if (request_resource(&iomem_resource, &pp->res[1]))
+       pp->res.flags = IORESOURCE_MEM;
+       if (request_resource(&iomem_resource, &pp->res))
                panic("Request PCIe Memory resource failed\n");
-       pci_add_resource_offset(&sys->resources, &pp->res[1], sys->mem_offset);
+       pci_add_resource_offset(&sys->resources, &pp->res, sys->mem_offset);
 
        return 1;
 }
@@ -210,7 +195,7 @@ static void __init add_pcie_port(int index, unsigned long base)
                pp->root_bus_nr = -1;
                pp->base = (void __iomem *)base;
                spin_lock_init(&pp->conf_lock);
-               memset(pp->res, 0, sizeof(pp->res));
+               memset(&pp->res, 0, sizeof(pp->res));
        } else {
                printk(KERN_INFO "link down, ignoring\n");
        }
index 6520ac83580260f7c134e465bf43c0e336c5a5b9..935e4af01a2769a7ab83282bda801389f36a4d50 100644 (file)
@@ -4,9 +4,7 @@
 
 # Object file lists.
 
-obj-y                  := core.o io.o
+obj-y                  := core.o io.o leds.o
 obj-m                  :=
 obj-n                  :=
 obj-                   :=
-
-obj-$(CONFIG_LEDS)     += leds.o
index 99e14e3625003568f46f42bf1da6720163b1f588..0398258c20cd52f392bd0d312a07faeef582b2fc 100644 (file)
@@ -1,52 +1,71 @@
 /*
- *  linux/arch/arm/mach-ebsa110/leds.c
+ * Driver for the LED found on the EBSA110 machine
+ * Based on Versatile and RealView machine LED code
  *
- *  Copyright (C) 1998 Russell King
- *
- * 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.
- *
- *  EBSA-110 LED control routines.  We use the led as follows:
- *
- *   - Red - toggles state every 50 timer interrupts
+ * License terms: GNU General Public License (GPL) version 2
+ * Author: Bryan Wu <bryan.wu@canonical.com>
  */
-#include <linux/module.h>
-#include <linux/spinlock.h>
+#include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
 
-#include <mach/hardware.h>
-#include <asm/leds.h>
 #include <asm/mach-types.h>
 
 #include "core.h"
 
-static spinlock_t leds_lock;
-
-static void ebsa110_leds_event(led_event_t ledevt)
+#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
+static void ebsa110_led_set(struct led_classdev *cdev,
+                             enum led_brightness b)
 {
-       unsigned long flags;
+       u8 reg = __raw_readb(SOFT_BASE);
 
-       spin_lock_irqsave(&leds_lock, flags);
+       if (b != LED_OFF)
+               reg |= 0x80;
+       else
+               reg &= ~0x80;
 
-       switch(ledevt) {
-       case led_timer:
-               *(volatile unsigned char *)SOFT_BASE ^= 128;
-               break;
+       __raw_writeb(reg, SOFT_BASE);
+}
 
-       default:
-               break;
-       }
+static enum led_brightness ebsa110_led_get(struct led_classdev *cdev)
+{
+       u8 reg = __raw_readb(SOFT_BASE);
 
-       spin_unlock_irqrestore(&leds_lock, flags);
+       return (reg & 0x80) ? LED_FULL : LED_OFF;
 }
 
-static int __init leds_init(void)
+static int __init ebsa110_leds_init(void)
 {
-       if (machine_is_ebsa110())
-               leds_event = ebsa110_leds_event;
+
+       struct led_classdev *cdev;
+       int ret;
+
+       if (!machine_is_ebsa110())
+               return -ENODEV;
+
+       cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
+       if (!cdev)
+               return -ENOMEM;
+
+       cdev->name = "ebsa110:0";
+       cdev->brightness_set = ebsa110_led_set;
+       cdev->brightness_get = ebsa110_led_get;
+       cdev->default_trigger = "heartbeat";
+
+       ret = led_classdev_register(NULL, cdev);
+       if (ret < 0) {
+               kfree(cdev);
+               return ret;
+       }
 
        return 0;
 }
 
-__initcall(leds_init);
+/*
+ * Since we may have triggers on any subsystem, defer registration
+ * until after subsystem_init.
+ */
+fs_initcall(ebsa110_leds_init);
+#endif
index 36c3984aaa47909e5e02b12a317cbe1f373897e2..090e32b0cd5467b9a41a03fa4f6a91575007668e 100644 (file)
@@ -139,7 +139,7 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
 
                __raw_writel(virt_to_phys(exynos4_secondary_startup),
                        CPU1_BOOT_REG);
-               gic_raise_softirq(cpumask_of(cpu), 1);
+               gic_raise_softirq(cpumask_of(cpu), 0);
 
                if (pen_release == -1)
                        break;
index 373c3c00d24cdbbe054a1aae60625d97188e6208..c0bc83a7663ee5877edfc0ff768b63a1ed1a2e30 100644 (file)
@@ -115,7 +115,7 @@ static __init int exynos_pm_dt_parse_domains(void)
 }
 #endif /* CONFIG_OF */
 
-static __init void exynos_pm_add_dev_to_genpd(struct platform_device *pdev,
+static __init __maybe_unused void exynos_pm_add_dev_to_genpd(struct platform_device *pdev,
                                                struct exynos_pm_domain *pd)
 {
        if (pdev->dev.bus) {
index 3afb1b25946f96b88b5390ab2ec59414b53ba5b5..0b64dd430d6150317288302c94f3b11fa0f1762e 100644 (file)
@@ -14,15 +14,11 @@ pci-$(CONFIG_ARCH_EBSA285_HOST) += ebsa285-pci.o
 pci-$(CONFIG_ARCH_NETWINDER) += netwinder-pci.o
 pci-$(CONFIG_ARCH_PERSONAL_SERVER) += personal-pci.o
 
-leds-$(CONFIG_ARCH_EBSA285) += ebsa285-leds.o
-leds-$(CONFIG_ARCH_NETWINDER) += netwinder-leds.o
-
 obj-$(CONFIG_ARCH_CATS) += cats-hw.o isa-timer.o
 obj-$(CONFIG_ARCH_EBSA285) += ebsa285.o dc21285-timer.o
 obj-$(CONFIG_ARCH_NETWINDER) += netwinder-hw.o isa-timer.o
 obj-$(CONFIG_ARCH_PERSONAL_SERVER) += personal.o dc21285-timer.o
 
 obj-$(CONFIG_PCI)      +=$(pci-y)
-obj-$(CONFIG_LEDS)     +=$(leds-y)
 
 obj-$(CONFIG_ISA)      += isa.o isa-rtc.o
index 3e6aaa6361da5095761b0adcd6a5d04549481bc4..a42b369bc43914ba9e00e7eff8e800278d2daef1 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/spinlock.h>
+
 #include <asm/pgtable.h>
 #include <asm/page.h>
 #include <asm/irq.h>
@@ -26,6 +26,7 @@
 
 #include <asm/mach/irq.h>
 #include <asm/mach/map.h>
+#include <asm/mach/pci.h>
 
 #include "common.h"
 
@@ -175,11 +176,6 @@ static struct map_desc ebsa285_host_io_desc[] __initdata = {
                .pfn            = __phys_to_pfn(DC21285_PCI_IACK),
                .length         = PCIIACK_SIZE,
                .type           = MT_DEVICE,
-       }, {
-               .virtual        = PCIO_BASE,
-               .pfn            = __phys_to_pfn(DC21285_PCI_IO),
-               .length         = PCIO_SIZE,
-               .type           = MT_DEVICE,
        },
 #endif
 };
@@ -196,8 +192,10 @@ void __init footbridge_map_io(void)
         * Now, work out what we've got to map in addition on this
         * platform.
         */
-       if (footbridge_cfn_mode())
+       if (footbridge_cfn_mode()) {
                iotable_init(ebsa285_host_io_desc, ARRAY_SIZE(ebsa285_host_io_desc));
+               pci_map_io_early(__phys_to_pfn(DC21285_PCI_IO));
+       }
 }
 
 void footbridge_restart(char mode, const char *cmd)
index 9d62e338102486e38c1aa4a84af64da8a5434887..a7cd2cf5e08de32c2ceafc508559d3201919dcc4 100644 (file)
@@ -276,8 +276,8 @@ int __init dc21285_setup(int nr, struct pci_sys_data *sys)
 
        sys->mem_offset  = DC21285_PCI_MEM;
 
-       pci_add_resource_offset(&sys->resources,
-                               &ioport_resource, sys->io_offset);
+       pci_ioremap_io(0, DC21285_PCI_IO);
+
        pci_add_resource_offset(&sys->resources, &res[0], sys->mem_offset);
        pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
 
@@ -298,7 +298,7 @@ void __init dc21285_preinit(void)
        mem_size = (unsigned int)high_memory - PAGE_OFFSET;
        for (mem_mask = 0x00100000; mem_mask < 0x10000000; mem_mask <<= 1)
                if (mem_mask >= mem_size)
-                       break;          
+                       break;
 
        /*
         * These registers need to be set up whether we're the
@@ -350,14 +350,6 @@ void __init dc21285_preinit(void)
                            "PCI data parity", NULL);
 
        if (cfn_mode) {
-               static struct resource csrio;
-
-               csrio.flags  = IORESOURCE_IO;
-               csrio.name   = "Footbridge";
-
-               allocate_resource(&ioport_resource, &csrio, 128,
-                                 0xff00, 0xffff, 128, NULL, NULL);
-
                /*
                 * Map our SDRAM at a known address in PCI space, just in case
                 * the firmware had other ideas.  Using a nonzero base is
@@ -365,7 +357,7 @@ void __init dc21285_preinit(void)
                 * in the range 0x000a0000 to 0x000c0000. (eg, S3 cards).
                 */
                *CSR_PCICSRBASE       = 0xf4000000;
-               *CSR_PCICSRIOBASE     = csrio.start;
+               *CSR_PCICSRIOBASE     = 0;
                *CSR_PCISDRAMBASE     = __virt_to_bus(PAGE_OFFSET);
                *CSR_PCIROMBASE       = 0;
                *CSR_PCICMD = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
diff --git a/arch/arm/mach-footbridge/ebsa285-leds.c b/arch/arm/mach-footbridge/ebsa285-leds.c
deleted file mode 100644 (file)
index 5bd2667..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- *  linux/arch/arm/mach-footbridge/ebsa285-leds.c
- *
- *  Copyright (C) 1998-1999 Russell King
- *
- * 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.
- * EBSA-285 control routines.
- *
- * The EBSA-285 uses the leds as follows:
- *  - Green - toggles state every 50 timer interrupts
- *  - Amber - On if system is not idle
- *  - Red   - currently unused
- *
- * Changelog:
- *   02-05-1999        RMK     Various cleanups
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-#include <asm/mach-types.h>
-
-#define LED_STATE_ENABLED      1
-#define LED_STATE_CLAIMED      2
-static char led_state;
-static char hw_led_state;
-
-static DEFINE_SPINLOCK(leds_lock);
-
-static void ebsa285_leds_event(led_event_t evt)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&leds_lock, flags);
-
-       switch (evt) {
-       case led_start:
-               hw_led_state = XBUS_LED_RED | XBUS_LED_GREEN;
-#ifndef CONFIG_LEDS_CPU
-               hw_led_state |= XBUS_LED_AMBER;
-#endif
-               led_state |= LED_STATE_ENABLED;
-               break;
-
-       case led_stop:
-               led_state &= ~LED_STATE_ENABLED;
-               break;
-
-       case led_claim:
-               led_state |= LED_STATE_CLAIMED;
-               hw_led_state = XBUS_LED_RED | XBUS_LED_GREEN | XBUS_LED_AMBER;
-               break;
-
-       case led_release:
-               led_state &= ~LED_STATE_CLAIMED;
-               hw_led_state = XBUS_LED_RED | XBUS_LED_GREEN | XBUS_LED_AMBER;
-               break;
-
-#ifdef CONFIG_LEDS_TIMER
-       case led_timer:
-               if (!(led_state & LED_STATE_CLAIMED))
-                       hw_led_state ^= XBUS_LED_GREEN;
-               break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-       case led_idle_start:
-               if (!(led_state & LED_STATE_CLAIMED))
-                       hw_led_state |= XBUS_LED_AMBER;
-               break;
-
-       case led_idle_end:
-               if (!(led_state & LED_STATE_CLAIMED))
-                       hw_led_state &= ~XBUS_LED_AMBER;
-               break;
-#endif
-
-       case led_halted:
-               if (!(led_state & LED_STATE_CLAIMED))
-                       hw_led_state &= ~XBUS_LED_RED;
-               break;
-
-       case led_green_on:
-               if (led_state & LED_STATE_CLAIMED)
-                       hw_led_state &= ~XBUS_LED_GREEN;
-               break;
-
-       case led_green_off:
-               if (led_state & LED_STATE_CLAIMED)
-                       hw_led_state |= XBUS_LED_GREEN;
-               break;
-
-       case led_amber_on:
-               if (led_state & LED_STATE_CLAIMED)
-                       hw_led_state &= ~XBUS_LED_AMBER;
-               break;
-
-       case led_amber_off:
-               if (led_state & LED_STATE_CLAIMED)
-                       hw_led_state |= XBUS_LED_AMBER;
-               break;
-
-       case led_red_on:
-               if (led_state & LED_STATE_CLAIMED)
-                       hw_led_state &= ~XBUS_LED_RED;
-               break;
-
-       case led_red_off:
-               if (led_state & LED_STATE_CLAIMED)
-                       hw_led_state |= XBUS_LED_RED;
-               break;
-
-       default:
-               break;
-       }
-
-       if  (led_state & LED_STATE_ENABLED)
-               *XBUS_LEDS = hw_led_state;
-
-       spin_unlock_irqrestore(&leds_lock, flags);
-}
-
-static int __init leds_init(void)
-{
-       if (machine_is_ebsa285())
-               leds_event = ebsa285_leds_event;
-
-       leds_event(led_start);
-
-       return 0;
-}
-
-__initcall(leds_init);
index 27716a7e5fc16c88eab0bbf2bb4ad9a9f7b1df00..b09551ef89ca39163c7fa4823af36be57ca4f92c 100644 (file)
@@ -5,6 +5,8 @@
  */
 #include <linux/init.h>
 #include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
 
 #include <asm/hardware/dec21285.h>
 #include <asm/mach-types.h>
 
 #include "common.h"
 
+/* LEDs */
+#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
+struct ebsa285_led {
+       struct led_classdev     cdev;
+       u8                      mask;
+};
+
+/*
+ * The triggers lines up below will only be used if the
+ * LED triggers are compiled in.
+ */
+static const struct {
+       const char *name;
+       const char *trigger;
+} ebsa285_leds[] = {
+       { "ebsa285:amber", "heartbeat", },
+       { "ebsa285:green", "cpu0", },
+       { "ebsa285:red",},
+};
+
+static void ebsa285_led_set(struct led_classdev *cdev,
+               enum led_brightness b)
+{
+       struct ebsa285_led *led = container_of(cdev,
+                       struct ebsa285_led, cdev);
+
+       if (b != LED_OFF)
+               *XBUS_LEDS |= led->mask;
+       else
+               *XBUS_LEDS &= ~led->mask;
+}
+
+static enum led_brightness ebsa285_led_get(struct led_classdev *cdev)
+{
+       struct ebsa285_led *led = container_of(cdev,
+                       struct ebsa285_led, cdev);
+
+       return (*XBUS_LEDS & led->mask) ? LED_FULL : LED_OFF;
+}
+
+static int __init ebsa285_leds_init(void)
+{
+       int i;
+
+       if (machine_is_ebsa285())
+               return -ENODEV;
+
+       /* 3 LEDS All ON */
+       *XBUS_LEDS |= XBUS_LED_AMBER | XBUS_LED_GREEN | XBUS_LED_RED;
+
+       for (i = 0; i < ARRAY_SIZE(ebsa285_leds); i++) {
+               struct ebsa285_led *led;
+
+               led = kzalloc(sizeof(*led), GFP_KERNEL);
+               if (!led)
+                       break;
+
+               led->cdev.name = ebsa285_leds[i].name;
+               led->cdev.brightness_set = ebsa285_led_set;
+               led->cdev.brightness_get = ebsa285_led_get;
+               led->cdev.default_trigger = ebsa285_leds[i].trigger;
+               led->mask = BIT(i);
+
+               if (led_classdev_register(NULL, &led->cdev) < 0) {
+                       kfree(led);
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * Since we may have triggers on any subsystem, defer registration
+ * until after subsystem_init.
+ */
+fs_initcall(ebsa285_leds_init);
+#endif
+
 MACHINE_START(EBSA285, "EBSA285")
        /* Maintainer: Russell King */
        .atag_offset    = 0x100,
index e5acde25ffc5492249a3fefb52b6ef83d53a099b..c169f0c99b2a323ad2f88ff0f9d20fac4579a064 100644 (file)
@@ -17,7 +17,8 @@
        /* For NetWinder debugging */
                .macro  addruart, rp, rv, tmp
                mov     \rp, #0x000003f8
-               orr     \rv, \rp, #0xff000000   @ virtual
+               orr     \rv, \rp, #0xfe000000   @ virtual
+               orr     \rv, \rv, #0x00e00000   @ virtual
                orr     \rp, \rp, #0x7c000000   @ physical
                .endm
 
index aba531eebbc6723cfe5ea69c31634caac46a160b..aba46388cc0c16ef450d66483e1e8ca78b123cf0 100644 (file)
 #ifndef __ASM_ARM_ARCH_IO_H
 #define __ASM_ARM_ARCH_IO_H
 
-#ifdef CONFIG_MMU
-#define MMU_IO(a, b)   (a)
-#else
-#define MMU_IO(a, b)   (b)
-#endif
-
-#define PCIO_SIZE       0x00100000
-#define PCIO_BASE       MMU_IO(0xff000000, 0x7c000000)
-
 /*
- * Translation of various region addresses to virtual addresses
+ * Translation of various i/o addresses to host addresses for !CONFIG_MMU
  */
+#define PCIO_BASE       0x7c000000
 #define __io(a)                        ((void __iomem *)(PCIO_BASE + (a)))
 
 #endif
index cac9f67e7da7e195f4bdb98aaa5d0f1808315c22..d2d14339c6c4b9cda4382a9c946ca847a0ce69b1 100644 (file)
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
 
 #include <asm/hardware/dec21285.h>
-#include <asm/leds.h>
 #include <asm/mach-types.h>
 #include <asm/setup.h>
 #include <asm/system_misc.h>
 #define GP1_IO_BASE            0x338
 #define GP2_IO_BASE            0x33a
 
-
-#ifdef CONFIG_LEDS
-#define DEFAULT_LEDS   0
-#else
-#define DEFAULT_LEDS   GPIO_GREEN_LED
-#endif
-
 /*
  * Winbond WB83977F accessibility stuff
  */
@@ -611,15 +605,9 @@ static void __init rwa010_init(void)
 static int __init nw_hw_init(void)
 {
        if (machine_is_netwinder()) {
-               unsigned long flags;
-
                wb977_init();
                cpld_init();
                rwa010_init();
-
-               raw_spin_lock_irqsave(&nw_gpio_lock, flags);
-               nw_gpio_modify_op(GPIO_RED_LED|GPIO_GREEN_LED, DEFAULT_LEDS);
-               raw_spin_unlock_irqrestore(&nw_gpio_lock, flags);
        }
        return 0;
 }
@@ -672,6 +660,102 @@ static void netwinder_restart(char mode, const char *cmd)
        }
 }
 
+/* LEDs */
+#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
+struct netwinder_led {
+       struct led_classdev     cdev;
+       u8                      mask;
+};
+
+/*
+ * The triggers lines up below will only be used if the
+ * LED triggers are compiled in.
+ */
+static const struct {
+       const char *name;
+       const char *trigger;
+} netwinder_leds[] = {
+       { "netwinder:green", "heartbeat", },
+       { "netwinder:red", "cpu0", },
+};
+
+/*
+ * The LED control in Netwinder is reversed:
+ *  - setting bit means turn off LED
+ *  - clearing bit means turn on LED
+ */
+static void netwinder_led_set(struct led_classdev *cdev,
+               enum led_brightness b)
+{
+       struct netwinder_led *led = container_of(cdev,
+                       struct netwinder_led, cdev);
+       unsigned long flags;
+       u32 reg;
+
+       spin_lock_irqsave(&nw_gpio_lock, flags);
+       reg = nw_gpio_read();
+       if (b != LED_OFF)
+               reg &= ~led->mask;
+       else
+               reg |= led->mask;
+       nw_gpio_modify_op(led->mask, reg);
+       spin_unlock_irqrestore(&nw_gpio_lock, flags);
+}
+
+static enum led_brightness netwinder_led_get(struct led_classdev *cdev)
+{
+       struct netwinder_led *led = container_of(cdev,
+                       struct netwinder_led, cdev);
+       unsigned long flags;
+       u32 reg;
+
+       spin_lock_irqsave(&nw_gpio_lock, flags);
+       reg = nw_gpio_read();
+       spin_unlock_irqrestore(&nw_gpio_lock, flags);
+
+       return (reg & led->mask) ? LED_OFF : LED_FULL;
+}
+
+static int __init netwinder_leds_init(void)
+{
+       int i;
+
+       if (!machine_is_netwinder())
+               return -ENODEV;
+
+       for (i = 0; i < ARRAY_SIZE(netwinder_leds); i++) {
+               struct netwinder_led *led;
+
+               led = kzalloc(sizeof(*led), GFP_KERNEL);
+               if (!led)
+                       break;
+
+               led->cdev.name = netwinder_leds[i].name;
+               led->cdev.brightness_set = netwinder_led_set;
+               led->cdev.brightness_get = netwinder_led_get;
+               led->cdev.default_trigger = netwinder_leds[i].trigger;
+
+               if (i == 0)
+                       led->mask = GPIO_GREEN_LED;
+               else
+                       led->mask = GPIO_RED_LED;
+
+               if (led_classdev_register(NULL, &led->cdev) < 0) {
+                       kfree(led);
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * Since we may have triggers on any subsystem, defer registration
+ * until after subsystem_init.
+ */
+fs_initcall(netwinder_leds_init);
+#endif
+
 MACHINE_START(NETWINDER, "Rebel-NetWinder")
        /* Maintainer: Russell King/Rebel.com */
        .atag_offset    = 0x100,
diff --git a/arch/arm/mach-footbridge/netwinder-leds.c b/arch/arm/mach-footbridge/netwinder-leds.c
deleted file mode 100644 (file)
index 5a2bd89..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- *  linux/arch/arm/mach-footbridge/netwinder-leds.c
- *
- *  Copyright (C) 1998-1999 Russell King
- *
- * 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.
- *
- * NetWinder LED control routines.
- *
- * The Netwinder uses the leds as follows:
- *  - Green - toggles state every 50 timer interrupts
- *  - Red   - On if the system is not idle
- *
- * Changelog:
- *   02-05-1999        RMK     Various cleanups
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-#include <asm/mach-types.h>
-
-#define LED_STATE_ENABLED      1
-#define LED_STATE_CLAIMED      2
-static char led_state;
-static char hw_led_state;
-
-static DEFINE_RAW_SPINLOCK(leds_lock);
-
-static void netwinder_leds_event(led_event_t evt)
-{
-       unsigned long flags;
-
-       raw_spin_lock_irqsave(&leds_lock, flags);
-
-       switch (evt) {
-       case led_start:
-               led_state |= LED_STATE_ENABLED;
-               hw_led_state = GPIO_GREEN_LED;
-               break;
-
-       case led_stop:
-               led_state &= ~LED_STATE_ENABLED;
-               break;
-
-       case led_claim:
-               led_state |= LED_STATE_CLAIMED;
-               hw_led_state = 0;
-               break;
-
-       case led_release:
-               led_state &= ~LED_STATE_CLAIMED;
-               hw_led_state = 0;
-               break;
-
-#ifdef CONFIG_LEDS_TIMER
-       case led_timer:
-               if (!(led_state & LED_STATE_CLAIMED))
-                       hw_led_state ^= GPIO_GREEN_LED;
-               break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-       case led_idle_start:
-               if (!(led_state & LED_STATE_CLAIMED))
-                       hw_led_state &= ~GPIO_RED_LED;
-               break;
-
-       case led_idle_end:
-               if (!(led_state & LED_STATE_CLAIMED))
-                       hw_led_state |= GPIO_RED_LED;
-               break;
-#endif
-
-       case led_halted:
-               if (!(led_state & LED_STATE_CLAIMED))
-                       hw_led_state |= GPIO_RED_LED;
-               break;
-
-       case led_green_on:
-               if (led_state & LED_STATE_CLAIMED)
-                       hw_led_state |= GPIO_GREEN_LED;
-               break;
-
-       case led_green_off:
-               if (led_state & LED_STATE_CLAIMED)
-                       hw_led_state &= ~GPIO_GREEN_LED;
-               break;
-
-       case led_amber_on:
-               if (led_state & LED_STATE_CLAIMED)
-                       hw_led_state |= GPIO_GREEN_LED | GPIO_RED_LED;
-               break;
-
-       case led_amber_off:
-               if (led_state & LED_STATE_CLAIMED)
-                       hw_led_state &= ~(GPIO_GREEN_LED | GPIO_RED_LED);
-               break;
-
-       case led_red_on:
-               if (led_state & LED_STATE_CLAIMED)
-                       hw_led_state |= GPIO_RED_LED;
-               break;
-
-       case led_red_off:
-               if (led_state & LED_STATE_CLAIMED)
-                       hw_led_state &= ~GPIO_RED_LED;
-               break;
-
-       default:
-               break;
-       }
-
-       raw_spin_unlock_irqrestore(&leds_lock, flags);
-
-       if  (led_state & LED_STATE_ENABLED) {
-               raw_spin_lock_irqsave(&nw_gpio_lock, flags);
-               nw_gpio_modify_op(GPIO_RED_LED | GPIO_GREEN_LED, hw_led_state);
-               raw_spin_unlock_irqrestore(&nw_gpio_lock, flags);
-       }
-}
-
-static int __init leds_init(void)
-{
-       if (machine_is_netwinder())
-               leds_event = netwinder_leds_event;
-
-       leds_event(led_start);
-
-       return 0;
-}
-
-__initcall(leds_init);
index 7aa6313fb1671bbf975d6cf6407aad3ecee66498..3b6b640eed247ea1b7848c7a7fa01801f0190cde 100644 (file)
@@ -223,7 +223,7 @@ int __init mx27_clocks_init(unsigned long fref)
        clk_register_clkdev(clk[per3_gate], "per", "imx-fb.0");
        clk_register_clkdev(clk[lcdc_ipg_gate], "ipg", "imx-fb.0");
        clk_register_clkdev(clk[lcdc_ahb_gate], "ahb", "imx-fb.0");
-       clk_register_clkdev(clk[csi_ahb_gate], NULL, "mx2-camera.0");
+       clk_register_clkdev(clk[csi_ahb_gate], "ahb", "mx2-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");
@@ -239,8 +239,8 @@ int __init mx27_clocks_init(unsigned long fref)
        clk_register_clkdev(clk[ssi1_ipg_gate], NULL, "imx-ssi.0");
        clk_register_clkdev(clk[ssi2_ipg_gate], NULL, "imx-ssi.1");
        clk_register_clkdev(clk[nfc_baud_gate], NULL, "mxc_nand.0");
-       clk_register_clkdev(clk[vpu_baud_gate], "per", "imx-vpu");
-       clk_register_clkdev(clk[vpu_ahb_gate], "ahb", "imx-vpu");
+       clk_register_clkdev(clk[vpu_baud_gate], "per", "coda-imx27.0");
+       clk_register_clkdev(clk[vpu_ahb_gate], "ahb", "coda-imx27.0");
        clk_register_clkdev(clk[dma_ahb_gate], "ahb", "imx-dma");
        clk_register_clkdev(clk[dma_ipg_gate], "ipg", "imx-dma");
        clk_register_clkdev(clk[fec_ipg_gate], "ipg", "imx27-fec.0");
@@ -250,8 +250,10 @@ int __init mx27_clocks_init(unsigned long fref)
        clk_register_clkdev(clk[i2c2_ipg_gate], NULL, "imx-i2c.1");
        clk_register_clkdev(clk[owire_ipg_gate], NULL, "mxc_w1.0");
        clk_register_clkdev(clk[kpp_ipg_gate], NULL, "imx-keypad");
-       clk_register_clkdev(clk[emma_ahb_gate], "ahb", "imx-emma");
-       clk_register_clkdev(clk[emma_ipg_gate], "ipg", "imx-emma");
+       clk_register_clkdev(clk[emma_ahb_gate], "emma-ahb", "mx2-camera.0");
+       clk_register_clkdev(clk[emma_ipg_gate], "emma-ipg", "mx2-camera.0");
+       clk_register_clkdev(clk[emma_ahb_gate], "ahb", "m2m-emmaprp.0");
+       clk_register_clkdev(clk[emma_ipg_gate], "ipg", "m2m-emmaprp.0");
        clk_register_clkdev(clk[iim_ipg_gate], "iim", NULL);
        clk_register_clkdev(clk[gpio_ipg_gate], "gpio", NULL);
        clk_register_clkdev(clk[brom_ahb_gate], "brom", NULL);
index 8e19e70f90f97f121b6379945ebeadc2ae2284ab..1253af2d99715a63f157a9f838230895006d9323 100644 (file)
@@ -130,7 +130,7 @@ int __init mx31_clocks_init(unsigned long fref)
        clk_register_clkdev(clk[nfc], NULL, "mxc_nand.0");
        clk_register_clkdev(clk[ipu_gate], NULL, "ipu-core");
        clk_register_clkdev(clk[ipu_gate], NULL, "mx3_sdc_fb");
-       clk_register_clkdev(clk[kpp_gate], "kpp", NULL);
+       clk_register_clkdev(clk[kpp_gate], NULL, "imx-keypad");
        clk_register_clkdev(clk[usb_div_post], "per", "mxc-ehci.0");
        clk_register_clkdev(clk[usb_gate], "ahb", "mxc-ehci.0");
        clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.0");
index f6086693ebd2aa665e29fc7a5d5623caeb0d3d53..e81f17a70f0092574410c731454c09f9bce84c84 100644 (file)
@@ -303,6 +303,7 @@ static void __init mx5_clocks_common_init(unsigned long rate_ckil,
        clk_prepare_enable(clk[aips_tz2]); /* fec */
        clk_prepare_enable(clk[spba]);
        clk_prepare_enable(clk[emi_fast_gate]); /* fec */
+       clk_prepare_enable(clk[emi_slow_gate]); /* eim */
        clk_prepare_enable(clk[tmax1]);
        clk_prepare_enable(clk[tmax2]); /* esdhc2, fec */
        clk_prepare_enable(clk[tmax3]); /* esdhc1, esdhc4 */
@@ -366,6 +367,7 @@ int __init mx51_clocks_init(unsigned long rate_ckil, unsigned long rate_osc,
        clk_register_clkdev(clk[ssi1_ipg_gate], NULL, "83fcc000.ssi");
        clk_register_clkdev(clk[ssi2_ipg_gate], NULL, "70014000.ssi");
        clk_register_clkdev(clk[ssi3_ipg_gate], NULL, "83fe8000.ssi");
+       clk_register_clkdev(clk[nfc_gate], NULL, "83fdb000.nand");
 
        /* set the usboh3 parent to pll2_sw */
        clk_set_parent(clk[usboh3_sel], clk[pll2_sw]);
@@ -454,6 +456,7 @@ int __init mx53_clocks_init(unsigned long rate_ckil, unsigned long rate_osc,
        clk_register_clkdev(clk[ssi1_ipg_gate], NULL, "63fcc000.ssi");
        clk_register_clkdev(clk[ssi2_ipg_gate], NULL, "50014000.ssi");
        clk_register_clkdev(clk[ssi3_ipg_gate], NULL, "63fd0000.ssi");
+       clk_register_clkdev(clk[nfc_gate], NULL, "63fdb000.nand");
 
        /* set SDHC root clock to 200MHZ*/
        clk_set_rate(clk[esdhc_a_podf], 200000000);
index 436c5720fe6a40255a2c3bc5ab05378c23855e02..04822932cdd1d13c260b4e950ccb51dec9f4ff39 100644 (file)
@@ -17,6 +17,10 @@ extern const struct imx_fsl_usb2_udc_data imx27_fsl_usb2_udc_data;
 #define imx27_add_fsl_usb2_udc(pdata)  \
        imx_add_fsl_usb2_udc(&imx27_fsl_usb2_udc_data, pdata)
 
+extern const struct imx_imx27_coda_data imx27_coda_data;
+#define imx27_add_coda()       \
+       imx_add_imx27_coda(&imx27_coda_data)
+
 extern const struct imx_imx2_wdt_data imx27_imx2_wdt_data;
 #define imx27_add_imx2_wdt()   \
        imx_add_imx2_wdt(&imx27_imx2_wdt_data)
index f264ddddd47c395404203cdebf43b7dc2206abb0..821d6aac411cb9e5d9d56f8ffb3100b3affa1b6b 100644 (file)
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
 #include <linux/leds.h>
-#include <linux/memblock.h>
 #include <media/soc_camera.h>
 #include <sound/tlv320aic32x4.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
 #include <asm/system_info.h>
+#include <asm/memblock.h>
 #include <mach/common.h>
 #include <mach/hardware.h>
 #include <mach/iomux-mx27.h>
@@ -233,10 +233,8 @@ static void __init visstrim_camera_init(void)
 static void __init visstrim_reserve(void)
 {
        /* reserve 4 MiB for mx2-camera */
-       mx2_camera_base = memblock_alloc(MX2_CAMERA_BUF_SIZE,
+       mx2_camera_base = arm_memblock_steal(3 * MX2_CAMERA_BUF_SIZE,
                        MX2_CAMERA_BUF_SIZE);
-       memblock_free(mx2_camera_base, MX2_CAMERA_BUF_SIZE);
-       memblock_remove(mx2_camera_base, MX2_CAMERA_BUF_SIZE);
 }
 
 /* GPIOs used as events for applications */
@@ -405,6 +403,47 @@ static const struct imx_ssi_platform_data visstrim_m10_ssi_pdata __initconst = {
        .flags                  = IMX_SSI_DMA | IMX_SSI_SYN,
 };
 
+/* coda */
+
+static void __init visstrim_coda_init(void)
+{
+       struct platform_device *pdev;
+       int dma;
+
+       pdev = imx27_add_coda();
+       dma = dma_declare_coherent_memory(&pdev->dev,
+                                         mx2_camera_base + MX2_CAMERA_BUF_SIZE,
+                                         mx2_camera_base + MX2_CAMERA_BUF_SIZE,
+                                         MX2_CAMERA_BUF_SIZE,
+                                         DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE);
+       if (!(dma & DMA_MEMORY_MAP))
+               return;
+}
+
+/* DMA deinterlace */
+static struct platform_device visstrim_deinterlace = {
+       .name = "m2m-deinterlace",
+       .id = 0,
+};
+
+static void __init visstrim_deinterlace_init(void)
+{
+       int ret = -ENOMEM;
+       struct platform_device *pdev = &visstrim_deinterlace;
+       int dma;
+
+       ret = platform_device_register(pdev);
+
+       dma = dma_declare_coherent_memory(&pdev->dev,
+                                         mx2_camera_base + 2 * MX2_CAMERA_BUF_SIZE,
+                                         mx2_camera_base + 2 * MX2_CAMERA_BUF_SIZE,
+                                         MX2_CAMERA_BUF_SIZE,
+                                         DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE);
+       if (!(dma & DMA_MEMORY_MAP))
+               return;
+}
+
+
 static void __init visstrim_m10_revision(void)
 {
        int exp_version = 0;
@@ -467,7 +506,9 @@ static void __init visstrim_m10_board_init(void)
        platform_device_register_resndata(NULL, "soc-camera-pdrv", 0, NULL, 0,
                                      &iclink_tvp5150, sizeof(iclink_tvp5150));
        gpio_led_register_device(0, &visstrim_m10_led_data);
+       visstrim_deinterlace_init();
        visstrim_camera_init();
+       visstrim_coda_init();
 }
 
 static void __init visstrim_m10_timer_init(void)
index ebeef966e1f50544a54bfc43b70d86d616b19e01..5521d18bf19afce7d1c4244623262471bc08b044 100644 (file)
@@ -4,11 +4,10 @@
 
 # Object file lists.
 
-obj-y                                  := core.o lm.o
+obj-y                                  := core.o lm.o leds.o
 obj-$(CONFIG_ARCH_INTEGRATOR_AP)       += integrator_ap.o
 obj-$(CONFIG_ARCH_INTEGRATOR_CP)       += integrator_cp.o
 
-obj-$(CONFIG_LEDS)                     += leds.o
 obj-$(CONFIG_PCI)                      += pci_v3.o pci.o
 obj-$(CONFIG_CPU_FREQ_INTEGRATOR)      += cpu.o
 obj-$(CONFIG_INTEGRATOR_IMPD1)         += impd1.o
index ebf680bebdf2ad95a1928f6895f2a77fa60e9236..2af5034ea29e5eb69a611040089949f255e8e04c 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/device.h>
+#include <linux/export.h>
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
@@ -27,7 +28,6 @@
 #include <mach/cm.h>
 #include <mach/irqs.h>
 
-#include <asm/leds.h>
 #include <asm/mach-types.h>
 #include <asm/mach/time.h>
 #include <asm/pgtable.h>
@@ -127,8 +127,6 @@ static struct amba_pl010_data integrator_uart_data = {
        .set_mctrl = integrator_uart_set_mctrl,
 };
 
-#define CM_CTRL        IO_ADDRESS(INTEGRATOR_HDR_CTRL)
-
 static DEFINE_RAW_SPINLOCK(cm_lock);
 
 /**
index 445d57adb043afa2a23c681f9cdfda610b6bb7cd..1a78692e32a4bc5d42432180ff67f75a885ce084 100644 (file)
@@ -3,6 +3,8 @@
  */
 void cm_control(u32, u32);
 
+#define CM_CTRL        IO_ADDRESS(INTEGRATOR_HDR_CTRL)
+
 #define CM_CTRL_LED                    (1 << 0)
 #define CM_CTRL_nMBDET                 (1 << 1)
 #define CM_CTRL_REMAP                  (1 << 2)
diff --git a/arch/arm/mach-integrator/include/mach/io.h b/arch/arm/mach-integrator/include/mach/io.h
deleted file mode 100644 (file)
index 8de70de..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- *  arch/arm/mach-integrator/include/mach/io.h
- *
- *  Copyright (C) 1999 ARM Limited
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-/*
- * WARNING: this has to mirror definitions in platform.h
- */
-#define PCI_MEMORY_VADDR        0xe8000000
-#define PCI_CONFIG_VADDR        0xec000000
-#define PCI_V3_VADDR            0xed000000
-#define PCI_IO_VADDR            0xee000000
-
-#define __io(a)                        ((void __iomem *)(PCI_IO_VADDR + (a)))
-
-#endif
index ec467baade097c5ebcadc1699a879e7758b2874a..4c034752685152a84ad80b6b64cea298317984fc 100644 (file)
  */
 #define PHYS_PCI_V3_BASE                0x62000000
 
+#define PCI_MEMORY_VADDR               0xe8000000
+#define PCI_CONFIG_VADDR               0xec000000
+#define PCI_V3_VADDR                   0xed000000
+
 /* ------------------------------------------------------------------------
  *  Integrator Interrupt Controllers
  * ------------------------------------------------------------------------
index 7b1055c8e0b98c6619473ca4bca9cd711ccc316c..fd3ef28d2c1af6044b1fecb8ba75e27c6980763b 100644 (file)
@@ -50,6 +50,7 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/irq.h>
 #include <asm/mach/map.h>
+#include <asm/mach/pci.h>
 #include <asm/mach/time.h>
 
 #include <plat/fpga-irq.h>
@@ -73,7 +74,7 @@
  * e8000000    40000000        PCI memory              PHYS_PCI_MEM_BASE       (max 512M)
  * ec000000    61000000        PCI config space        PHYS_PCI_CONFIG_BASE    (max 16M)
  * ed000000    62000000        PCI V3 regs             PHYS_PCI_V3_BASE        (max 64k)
- * ee000000    60000000        PCI IO                  PHYS_PCI_IO_BASE        (max 16M)
+ * fee00000    60000000        PCI IO                  PHYS_PCI_IO_BASE        (max 16M)
  * ef000000                    Cache flush
  * f1000000    10000000        Core module registers
  * f1100000    11000000        System controller registers
@@ -147,11 +148,6 @@ static struct map_desc ap_io_desc[] __initdata = {
                .pfn            = __phys_to_pfn(PHYS_PCI_V3_BASE),
                .length         = SZ_64K,
                .type           = MT_DEVICE
-       }, {
-               .virtual        = PCI_IO_VADDR,
-               .pfn            = __phys_to_pfn(PHYS_PCI_IO_BASE),
-               .length         = SZ_64K,
-               .type           = MT_DEVICE
        }
 };
 
@@ -159,6 +155,7 @@ static void __init ap_map_io(void)
 {
        iotable_init(ap_io_desc, ARRAY_SIZE(ap_io_desc));
        vga_base = PCI_MEMORY_VADDR;
+       pci_map_io_early(__phys_to_pfn(PHYS_PCI_IO_BASE));
 }
 
 #define INTEGRATOR_SC_VALID_INT        0x003fffff
@@ -456,7 +453,7 @@ static void __init ap_init_timer(void)
 
        clk = clk_get_sys("ap_timer", NULL);
        BUG_ON(IS_ERR(clk));
-       clk_enable(clk);
+       clk_prepare_enable(clk);
        rate = clk_get_rate(clk);
 
        writel(0, TIMER0_VA_BASE + TIMER_CTRL);
index 466defa97842944171ef7fab1c8c151805291772..7a7f6d3273bf165b515eb8c4454731848ef661f0 100644 (file)
 /*
- *  linux/arch/arm/mach-integrator/leds.c
+ * Driver for the 4 user LEDs found on the Integrator AP/CP baseboard
+ * Based on Versatile and RealView machine LED code
  *
- *  Integrator/AP and Integrator/CP LED control routines
- *
- *  Copyright (C) 1999 ARM Limited
- *  Copyright (C) 2000 Deep Blue Solutions Ltd
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * License terms: GNU General Public License (GPL) version 2
+ * Author: Bryan Wu <bryan.wu@canonical.com>
  */
 #include <linux/kernel.h>
 #include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/spinlock.h>
 #include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
 
+#include <mach/cm.h>
 #include <mach/hardware.h>
 #include <mach/platform.h>
-#include <asm/leds.h>
-#include <asm/mach-types.h>
-#include <mach/cm.h>
 
-static int saved_leds;
+#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
+
+#define ALPHA_REG __io_address(INTEGRATOR_DBG_BASE)
+#define LEDREG (__io_address(INTEGRATOR_DBG_BASE) + INTEGRATOR_DBG_LEDS_OFFSET)
 
-static void integrator_leds_event(led_event_t ledevt)
+struct integrator_led {
+       struct led_classdev     cdev;
+       u8                      mask;
+};
+
+/*
+ * The triggers lines up below will only be used if the
+ * LED triggers are compiled in.
+ */
+static const struct {
+       const char *name;
+       const char *trigger;
+} integrator_leds[] = {
+       { "integrator:green0", "heartbeat", },
+       { "integrator:yellow", },
+       { "integrator:red", },
+       { "integrator:green1", },
+       { "integrator:core_module", "cpu0", },
+};
+
+static void integrator_led_set(struct led_classdev *cdev,
+                             enum led_brightness b)
 {
-       unsigned long flags;
-       const unsigned int dbg_base = IO_ADDRESS(INTEGRATOR_DBG_BASE);
-       unsigned int update_alpha_leds;
+       struct integrator_led *led = container_of(cdev,
+                                                struct integrator_led, cdev);
+       u32 reg = __raw_readl(LEDREG);
 
-       // yup, change the LEDs
-       local_irq_save(flags);
-       update_alpha_leds = 0;
+       if (b != LED_OFF)
+               reg |= led->mask;
+       else
+               reg &= ~led->mask;
 
-       switch(ledevt) {
-       case led_idle_start:
-               cm_control(CM_CTRL_LED, 0);
-               break;
+       while (__raw_readl(ALPHA_REG) & 1)
+               cpu_relax();
 
-       case led_idle_end:
-               cm_control(CM_CTRL_LED, CM_CTRL_LED);
-               break;
+       __raw_writel(reg, LEDREG);
+}
 
-       case led_timer:
-               saved_leds ^= GREEN_LED;
-               update_alpha_leds = 1;
-               break;
+static enum led_brightness integrator_led_get(struct led_classdev *cdev)
+{
+       struct integrator_led *led = container_of(cdev,
+                                                struct integrator_led, cdev);
+       u32 reg = __raw_readl(LEDREG);
 
-       case led_red_on:
-               saved_leds |= RED_LED;
-               update_alpha_leds = 1;
-               break;
+       return (reg & led->mask) ? LED_FULL : LED_OFF;
+}
 
-       case led_red_off:
-               saved_leds &= ~RED_LED;
-               update_alpha_leds = 1;
-               break;
+static void cm_led_set(struct led_classdev *cdev,
+                             enum led_brightness b)
+{
+       if (b != LED_OFF)
+               cm_control(CM_CTRL_LED, CM_CTRL_LED);
+       else
+               cm_control(CM_CTRL_LED, 0);
+}
 
-       default:
-               break;
-       }
+static enum led_brightness cm_led_get(struct led_classdev *cdev)
+{
+       u32 reg = readl(CM_CTRL);
 
-       if (update_alpha_leds) {
-               while (__raw_readl(dbg_base + INTEGRATOR_DBG_ALPHA_OFFSET) & 1);
-               __raw_writel(saved_leds, dbg_base + INTEGRATOR_DBG_LEDS_OFFSET);
-       }
-       local_irq_restore(flags);
+       return (reg & CM_CTRL_LED) ? LED_FULL : LED_OFF;
 }
 
-static int __init leds_init(void)
+static int __init integrator_leds_init(void)
 {
-       if (machine_is_integrator() || machine_is_cintegrator())
-               leds_event = integrator_leds_event;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(integrator_leds); i++) {
+               struct integrator_led *led;
+
+               led = kzalloc(sizeof(*led), GFP_KERNEL);
+               if (!led)
+                       break;
+
+
+               led->cdev.name = integrator_leds[i].name;
+
+               if (i == 4) { /* Setting for LED in core module */
+                       led->cdev.brightness_set = cm_led_set;
+                       led->cdev.brightness_get = cm_led_get;
+               } else {
+                       led->cdev.brightness_set = integrator_led_set;
+                       led->cdev.brightness_get = integrator_led_get;
+               }
+
+               led->cdev.default_trigger = integrator_leds[i].trigger;
+               led->mask = BIT(i);
+
+               if (led_classdev_register(NULL, &led->cdev) < 0) {
+                       kfree(led);
+                       break;
+               }
+       }
 
        return 0;
 }
 
-core_initcall(leds_init);
+/*
+ * Since we may have triggers on any subsystem, defer registration
+ * until after subsystem_init.
+ */
+fs_initcall(integrator_leds_init);
+#endif
index b866880e82acdf2e02ff173cb48a529654be9694..495f181fc9372214ecb9fe4cfdfcdd073aca557b 100644 (file)
 /*
  * The V3 PCI interface chip in Integrator provides several windows from
  * local bus memory into the PCI memory areas.   Unfortunately, there
- * are not really enough windows for our usage, therefore we reuse 
+ * are not really enough windows for our usage, therefore we reuse
  * one of the windows for access to PCI configuration space.  The
  * memory map is as follows:
- * 
+ *
  * Local Bus Memory         Usage
- * 
+ *
  * 40000000 - 4FFFFFFF      PCI memory.  256M non-prefetchable
  * 50000000 - 5FFFFFFF      PCI memory.  256M prefetchable
  * 60000000 - 60FFFFFF      PCI IO.  16M
  * 61000000 - 61FFFFFF      PCI Configuration. 16M
- * 
+ *
  * There are three V3 windows, each described by a pair of V3 registers.
  * These are LB_BASE0/LB_MAP0, LB_BASE1/LB_MAP1 and LB_BASE2/LB_MAP2.
  * Base0 and Base1 can be used for any type of PCI memory access.   Base2
  * can be used either for PCI I/O or for I20 accesses.  By default, uHAL
  * uses this only for PCI IO space.
- * 
+ *
  * Normally these spaces are mapped using the following base registers:
- * 
+ *
  * Usage Local Bus Memory         Base/Map registers used
- * 
+ *
  * Mem   40000000 - 4FFFFFFF      LB_BASE0/LB_MAP0
  * Mem   50000000 - 5FFFFFFF      LB_BASE1/LB_MAP1
  * IO    60000000 - 60FFFFFF      LB_BASE2/LB_MAP2
  * Cfg   61000000 - 61FFFFFF
- * 
+ *
  * This means that I20 and PCI configuration space accesses will fail.
- * When PCI configuration accesses are needed (via the uHAL PCI 
+ * When PCI configuration accesses are needed (via the uHAL PCI
  * configuration space primitives) we must remap the spaces as follows:
- * 
+ *
  * Usage Local Bus Memory         Base/Map registers used
- * 
+ *
  * Mem   40000000 - 4FFFFFFF      LB_BASE0/LB_MAP0
  * Mem   50000000 - 5FFFFFFF      LB_BASE0/LB_MAP0
  * IO    60000000 - 60FFFFFF      LB_BASE2/LB_MAP2
  * Cfg   61000000 - 61FFFFFF      LB_BASE1/LB_MAP1
- * 
+ *
  * To make this work, the code depends on overlapping windows working.
- * The V3 chip translates an address by checking its range within 
+ * The V3 chip translates an address by checking its range within
  * each of the BASE/MAP pairs in turn (in ascending register number
  * order).  It will use the first matching pair.   So, for example,
  * if the same address is mapped by both LB_BASE0/LB_MAP0 and
- * LB_BASE1/LB_MAP1, the V3 will use the translation from 
+ * LB_BASE1/LB_MAP1, the V3 will use the translation from
  * LB_BASE0/LB_MAP0.
- * 
+ *
  * To allow PCI Configuration space access, the code enlarges the
  * window mapped by LB_BASE0/LB_MAP0 from 256M to 512M.  This occludes
  * the windows currently mapped by LB_BASE1/LB_MAP1 so that it can
  * be remapped for use by configuration cycles.
- * 
- * At the end of the PCI Configuration space accesses, 
+ *
+ * At the end of the PCI Configuration space accesses,
  * LB_BASE1/LB_MAP1 is reset to map PCI Memory.  Finally the window
  * mapped by LB_BASE0/LB_MAP0 is reduced in size from 512M to 256M to
  * reveal the now restored LB_BASE1/LB_MAP1 window.
- * 
+ *
  * NOTE: We do not set up I2O mapping.  I suspect that this is only
  * for an intelligent (target) device.  Using I2O disables most of
  * the mappings into PCI memory.
  *
  * returns:    configuration address to play on the PCI bus
  *
- * To generate the appropriate PCI configuration cycles in the PCI 
- * configuration address space, you present the V3 with the following pattern 
+ * To generate the appropriate PCI configuration cycles in the PCI
+ * configuration address space, you present the V3 with the following pattern
  * (which is very nearly a type 1 (except that the lower two bits are 00 and
  * not 01).   In order for this mapping to work you need to set up one of
  * the local to PCI aperatures to 16Mbytes in length translating to
  *
  * Type 0:
  *
- *  3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 
+ *  3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1
  *  3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  * | | |D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|0|
  *
  * Type 1:
  *
- *  3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1 
+ *  3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1
  *  3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1|
  *     15:11   Device number (5 bits)
  *     10:8    function number
  *      7:2    register number
- *  
+ *
  */
 static DEFINE_RAW_SPINLOCK(v3_lock);
 
@@ -374,12 +374,9 @@ static int __init pci_v3_setup_resources(struct pci_sys_data *sys)
        }
 
        /*
-        * the IO resource for this bus
         * the mem resource for this bus
         * the prefetch mem resource for this bus
         */
-       pci_add_resource_offset(&sys->resources,
-                               &ioport_resource, sys->io_offset);
        pci_add_resource_offset(&sys->resources, &non_mem, sys->mem_offset);
        pci_add_resource_offset(&sys->resources, &pre_mem, sys->mem_offset);
 
@@ -498,7 +495,6 @@ void __init pci_v3_preinit(void)
        unsigned int temp;
        int ret;
 
-       pcibios_min_io = 0x6000;
        pcibios_min_mem = 0x00100000;
 
        /*
diff --git a/arch/arm/mach-iop13xx/include/mach/io.h b/arch/arm/mach-iop13xx/include/mach/io.h
deleted file mode 100644 (file)
index f131885..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * iop13xx custom ioremap implementation
- * Copyright (c) 2005-2006, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- *
- */
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-#define IO_SPACE_LIMIT 0xffffffff
-
-#define __io(a) __iop13xx_io(a)
-
-extern void __iomem * __iop13xx_io(unsigned long io_addr);
-
-#endif
index e190dcd7d72dc1afd69adb2d637ef6630c3af855..e10e101645dd1671ae913e961cb00e541a50d255 100644 (file)
@@ -69,21 +69,11 @@ extern unsigned long get_iop_tick_rate(void);
  * 0x8000.0000 + 928M  0x2.8000.0000   (ioremap)       PCIE outbound memory window
  *
  * IO MAP
- * 0x1000 + 64K        0x0.fffb.1000   0xfec6.1000     PCIX outbound i/o window
- * 0x1000 + 64K        0x0.fffd.1000   0xfed7.1000     PCIE outbound i/o window
+ * 0x00000 + 64K       0x0.fffb.0000   0xfee0.0000     PCIX outbound i/o window
+ * 0x10000 + 64K       0x0.fffd.0000   0xfee1.0000     PCIE outbound i/o window
  */
-#define IOP13XX_PCIX_IO_WINDOW_SIZE   0x10000UL
 #define IOP13XX_PCIX_LOWER_IO_PA      0xfffb0000UL
-#define IOP13XX_PCIX_LOWER_IO_VA      0xfec60000UL
 #define IOP13XX_PCIX_LOWER_IO_BA      0x0UL /* OIOTVR */
-#define IOP13XX_PCIX_IO_BUS_OFFSET    0x1000UL
-#define IOP13XX_PCIX_UPPER_IO_PA      (IOP13XX_PCIX_LOWER_IO_PA +\
-                                      IOP13XX_PCIX_IO_WINDOW_SIZE - 1)
-#define IOP13XX_PCIX_UPPER_IO_VA      (IOP13XX_PCIX_LOWER_IO_VA +\
-                                      IOP13XX_PCIX_IO_WINDOW_SIZE - 1)
-#define IOP13XX_PCIX_IO_PHYS_TO_VIRT(addr) (u32) ((u32) addr -\
-                                          (IOP13XX_PCIX_LOWER_IO_PA\
-                                          - IOP13XX_PCIX_LOWER_IO_VA))
 
 #define IOP13XX_PCIX_MEM_PHYS_OFFSET  0x100000000ULL
 #define IOP13XX_PCIX_MEM_WINDOW_SIZE  0x3a000000UL
@@ -103,20 +93,8 @@ extern unsigned long get_iop_tick_rate(void);
                                        IOP13XX_PCIX_LOWER_MEM_BA)
 
 /* PCI-E ranges */
-#define IOP13XX_PCIE_IO_WINDOW_SIZE     0x10000UL
 #define IOP13XX_PCIE_LOWER_IO_PA        0xfffd0000UL
-#define IOP13XX_PCIE_LOWER_IO_VA        0xfed70000UL
-#define IOP13XX_PCIE_LOWER_IO_BA        0x0UL  /* OIOTVR */
-#define IOP13XX_PCIE_IO_BUS_OFFSET      0x1000UL
-#define IOP13XX_PCIE_UPPER_IO_PA        (IOP13XX_PCIE_LOWER_IO_PA +\
-                                        IOP13XX_PCIE_IO_WINDOW_SIZE - 1)
-#define IOP13XX_PCIE_UPPER_IO_VA        (IOP13XX_PCIE_LOWER_IO_VA +\
-                                        IOP13XX_PCIE_IO_WINDOW_SIZE - 1)
-#define IOP13XX_PCIE_UPPER_IO_BA        (IOP13XX_PCIE_LOWER_IO_BA +\
-                                        IOP13XX_PCIE_IO_WINDOW_SIZE - 1)
-#define IOP13XX_PCIE_IO_PHYS_TO_VIRT(addr) (u32) ((u32) addr -\
-                                          (IOP13XX_PCIE_LOWER_IO_PA\
-                                          - IOP13XX_PCIE_LOWER_IO_VA))
+#define IOP13XX_PCIE_LOWER_IO_BA        0x10000UL  /* OIOTVR */
 
 #define IOP13XX_PCIE_MEM_PHYS_OFFSET    0x200000000ULL
 #define IOP13XX_PCIE_MEM_WINDOW_SIZE    0x3a000000UL
index 3c364198db9c91a9b611df556c5b08db35a74038..851dc8f2b6b5646abb94723aaf4fe2d6715210b2 100644 (file)
 
 #include "pci.h"
 
-void * __iomem __iop13xx_io(unsigned long io_addr)
-{
-       void __iomem * io_virt;
-
-       switch (io_addr) {
-       case IOP13XX_PCIE_LOWER_IO_PA ... IOP13XX_PCIE_UPPER_IO_PA:
-               io_virt = (void *) IOP13XX_PCIE_IO_PHYS_TO_VIRT(io_addr);
-               break;
-       case IOP13XX_PCIX_LOWER_IO_PA ... IOP13XX_PCIX_UPPER_IO_PA:
-               io_virt = (void *) IOP13XX_PCIX_IO_PHYS_TO_VIRT(io_addr);
-               break;
-       default:
-               BUG();
-       }
-
-       return io_virt;
-}
-EXPORT_SYMBOL(__iop13xx_io);
-
 static void __iomem *__iop13xx_ioremap_caller(unsigned long cookie,
        size_t size, unsigned int mtype, void *caller)
 {
@@ -67,12 +48,6 @@ static void __iomem *__iop13xx_ioremap_caller(unsigned long cookie,
                                       (cookie - IOP13XX_PBI_LOWER_MEM_RA),
                                       size, mtype, __builtin_return_address(0));
                break;
-       case IOP13XX_PCIE_LOWER_IO_PA ... IOP13XX_PCIE_UPPER_IO_PA:
-               retval = (void *) IOP13XX_PCIE_IO_PHYS_TO_VIRT(cookie);
-               break;
-       case IOP13XX_PCIX_LOWER_IO_PA ... IOP13XX_PCIX_UPPER_IO_PA:
-               retval = (void *) IOP13XX_PCIX_IO_PHYS_TO_VIRT(cookie);
-               break;
        case IOP13XX_PMMR_PHYS_MEM_BASE ... IOP13XX_PMMR_UPPER_MEM_PA:
                retval = (void *) IOP13XX_PMMR_PHYS_TO_VIRT(cookie);
                break;
@@ -99,8 +74,6 @@ static void __iop13xx_iounmap(volatile void __iomem *addr)
                    goto skip;
 
        switch ((u32) addr) {
-       case IOP13XX_PCIE_LOWER_IO_VA ... IOP13XX_PCIE_UPPER_IO_VA:
-       case IOP13XX_PCIX_LOWER_IO_VA ... IOP13XX_PCIX_UPPER_IO_VA:
        case IOP13XX_PMMR_VIRT_MEM_BASE ... IOP13XX_PMMR_UPPER_MEM_VA:
                goto skip;
        }
index 861cb12ef4363b69e78e83c34b4bc0b3c1c5ccbd..91f731a2957b93fd34de75a4d225cc011a8bc61d 100644 (file)
@@ -970,7 +970,6 @@ void __init iop13xx_pci_init(void)
        __raw_writel(__raw_readl(IOP13XX_XBG_BECSR) & 3, IOP13XX_XBG_BECSR);
 
        /* Setup the Min Address for PCI memory... */
-       pcibios_min_io = 0;
        pcibios_min_mem = IOP13XX_PCIX_LOWER_MEM_BA;
 
        /* if Linux is given control of an ATU
@@ -1003,7 +1002,7 @@ int iop13xx_pci_setup(int nr, struct pci_sys_data *sys)
        if (nr > 1)
                return 0;
 
-       res = kcalloc(2, sizeof(struct resource), GFP_KERNEL);
+       res = kzalloc(sizeof(struct resource), GFP_KERNEL);
        if (!res)
                panic("PCI: unable to alloc resources");
 
@@ -1042,17 +1041,13 @@ int iop13xx_pci_setup(int nr, struct pci_sys_data *sys)
                                  << IOP13XX_ATUX_PCIXSR_FUNC_NUM;
                __raw_writel(pcixsr, IOP13XX_ATUX_PCIXSR);
 
-               res[0].start = IOP13XX_PCIX_LOWER_IO_PA + IOP13XX_PCIX_IO_BUS_OFFSET;
-               res[0].end   = IOP13XX_PCIX_UPPER_IO_PA;
-               res[0].name  = "IQ81340 ATUX PCI I/O Space";
-               res[0].flags = IORESOURCE_IO;
+               pci_ioremap_io(0, IOP13XX_PCIX_LOWER_IO_PA);
 
-               res[1].start = IOP13XX_PCIX_LOWER_MEM_RA;
-               res[1].end   = IOP13XX_PCIX_UPPER_MEM_RA;
-               res[1].name  = "IQ81340 ATUX PCI Memory Space";
-               res[1].flags = IORESOURCE_MEM;
+               res->start = IOP13XX_PCIX_LOWER_MEM_RA;
+               res->end   = IOP13XX_PCIX_UPPER_MEM_RA;
+               res->name  = "IQ81340 ATUX PCI Memory Space";
+               res->flags = IORESOURCE_MEM;
                sys->mem_offset = IOP13XX_PCIX_MEM_OFFSET;
-               sys->io_offset = IOP13XX_PCIX_LOWER_IO_PA;
                break;
        case IOP13XX_INIT_ATU_ATUE:
                /* Note: the function number field in the PCSR is ro */
@@ -1063,17 +1058,13 @@ int iop13xx_pci_setup(int nr, struct pci_sys_data *sys)
 
                __raw_writel(pcsr, IOP13XX_ATUE_PCSR);
 
-               res[0].start = IOP13XX_PCIE_LOWER_IO_PA + IOP13XX_PCIE_IO_BUS_OFFSET;
-               res[0].end   = IOP13XX_PCIE_UPPER_IO_PA;
-               res[0].name  = "IQ81340 ATUE PCI I/O Space";
-               res[0].flags = IORESOURCE_IO;
+               pci_ioremap_io(SZ_64K, IOP13XX_PCIE_LOWER_IO_PA);
 
-               res[1].start = IOP13XX_PCIE_LOWER_MEM_RA;
-               res[1].end   = IOP13XX_PCIE_UPPER_MEM_RA;
-               res[1].name  = "IQ81340 ATUE PCI Memory Space";
-               res[1].flags = IORESOURCE_MEM;
+               res->start = IOP13XX_PCIE_LOWER_MEM_RA;
+               res->end   = IOP13XX_PCIE_UPPER_MEM_RA;
+               res->name  = "IQ81340 ATUE PCI Memory Space";
+               res->flags = IORESOURCE_MEM;
                sys->mem_offset = IOP13XX_PCIE_MEM_OFFSET;
-               sys->io_offset = IOP13XX_PCIE_LOWER_IO_PA;
                sys->map_irq = iop13xx_pcie_map_irq;
                break;
        default:
@@ -1081,11 +1072,9 @@ int iop13xx_pci_setup(int nr, struct pci_sys_data *sys)
                return 0;
        }
 
-       request_resource(&ioport_resource, &res[0]);
-       request_resource(&iomem_resource, &res[1]);
+       request_resource(&iomem_resource, res);
 
-       pci_add_resource_offset(&sys->resources, &res[0], sys->io_offset);
-       pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
+       pci_add_resource_offset(&sys->resources, res, sys->mem_offset);
 
        return 1;
 }
index daabb1fa6c2c3b19db0d570fbda1d84b03f9b3c4..4a7f20d7fb6e6002fee0116a87876cca43b1909f 100644 (file)
@@ -40,16 +40,6 @@ static struct map_desc iop13xx_std_desc[] __initdata = {
                .pfn     = __phys_to_pfn(IOP13XX_PMMR_PHYS_MEM_BASE),
                .length  = IOP13XX_PMMR_SIZE,
                .type    = MT_DEVICE,
-       }, { /* PCIE IO space */
-               .virtual = IOP13XX_PCIE_LOWER_IO_VA,
-               .pfn     = __phys_to_pfn(IOP13XX_PCIE_LOWER_IO_PA),
-               .length  = IOP13XX_PCIX_IO_WINDOW_SIZE,
-               .type    = MT_DEVICE,
-       }, { /* PCIX IO space */
-               .virtual = IOP13XX_PCIX_LOWER_IO_VA,
-               .pfn     = __phys_to_pfn(IOP13XX_PCIX_LOWER_IO_PA),
-               .length  = IOP13XX_PCIX_IO_WINDOW_SIZE,
-               .type    = MT_DEVICE,
        },
 };
 
diff --git a/arch/arm/mach-iop32x/include/mach/io.h b/arch/arm/mach-iop32x/include/mach/io.h
deleted file mode 100644 (file)
index e2ada26..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * arch/arm/mach-iop32x/include/mach/io.h
- *
- * Copyright (C) 2001 MontaVista Software, 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.
- */
-
-#ifndef __IO_H
-#define __IO_H
-
-#include <asm/hardware/iop3xx.h>
-
-#define IO_SPACE_LIMIT         0xffffffff
-#define __io(p)                ((void __iomem *)IOP3XX_PCI_IO_PHYS_TO_VIRT(p))
-
-#endif
diff --git a/arch/arm/mach-iop33x/include/mach/io.h b/arch/arm/mach-iop33x/include/mach/io.h
deleted file mode 100644 (file)
index f7c1b65..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * arch/arm/mach-iop33x/include/mach/io.h
- *
- * Copyright (C) 2001  MontaVista Software, 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.
- */
-
-#ifndef __IO_H
-#define __IO_H
-
-#include <asm/hardware/iop3xx.h>
-
-#define IO_SPACE_LIMIT         0xffffffff
-#define __io(p)                ((void __iomem *)IOP3XX_PCI_IO_PHYS_TO_VIRT(p))
-
-#endif
index 2a576abf409bd0323c64e0cac807d0f609e2135a..a13299d758e15540cfd6fef81b399efbe53d1691 100644 (file)
@@ -7,7 +7,8 @@ dtb-$(CONFIG_MACH_DLINK_KIRKWOOD_DT) += kirkwood-dns320.dtb
 dtb-$(CONFIG_MACH_DLINK_KIRKWOOD_DT) += kirkwood-dns325.dtb
 dtb-$(CONFIG_MACH_ICONNECT_DT) += kirkwood-iconnect.dtb
 dtb-$(CONFIG_MACH_IB62X0_DT) += kirkwood-ib62x0.dtb
-dtb-$(CONFIG_MACH_TS219_DT)    += kirkwood-qnap-ts219.dtb
+dtb-$(CONFIG_MACH_TS219_DT)    += kirkwood-ts219-6281.dtb
+dtb-$(CONFIG_MACH_TS219_DT)    += kirkwood-ts219-6282.dtb
 dtb-$(CONFIG_MACH_GOFLEXNET_DT) += kirkwood-goflexnet.dtb
-dbt-$(CONFIG_MACH_LSXL_DT) += kirkwood-lschlv2.dtb
-dbt-$(CONFIG_MACH_LSXL_DT) += kirkwood-lsxhl.dtb
+dtb-$(CONFIG_MACH_LSXL_DT) += kirkwood-lschlv2.dtb
+dtb-$(CONFIG_MACH_LSXL_DT) += kirkwood-lsxhl.dtb
index c4b64adcbfce4be58c7a9b149df9e33d19e02e51..936b31df644c5ac75e0dc224634a2de454aef7be 100644 (file)
  ****************************************************************************/
 static struct map_desc kirkwood_io_desc[] __initdata = {
        {
-               .virtual        = KIRKWOOD_PCIE_IO_VIRT_BASE,
-               .pfn            = __phys_to_pfn(KIRKWOOD_PCIE_IO_PHYS_BASE),
-               .length         = KIRKWOOD_PCIE_IO_SIZE,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = KIRKWOOD_PCIE1_IO_VIRT_BASE,
-               .pfn            = __phys_to_pfn(KIRKWOOD_PCIE1_IO_PHYS_BASE),
-               .length         = KIRKWOOD_PCIE1_IO_SIZE,
-               .type           = MT_DEVICE,
-       }, {
                .virtual        = KIRKWOOD_REGS_VIRT_BASE,
                .pfn            = __phys_to_pfn(KIRKWOOD_REGS_PHYS_BASE),
                .length         = KIRKWOOD_REGS_SIZE,
@@ -301,7 +291,7 @@ void __init kirkwood_ge00_init(struct mv643xx_eth_platform_data *eth_data)
 {
        orion_ge00_init(eth_data,
                        GE00_PHYS_BASE, IRQ_KIRKWOOD_GE00_SUM,
-                       IRQ_KIRKWOOD_GE00_ERR);
+                       IRQ_KIRKWOOD_GE00_ERR, 1600);
        /* The interface forgets the MAC address assigned by u-boot if
        the clock is turned off, so claim the clk now. */
        clk_prepare_enable(ge0);
@@ -315,7 +305,7 @@ void __init kirkwood_ge01_init(struct mv643xx_eth_platform_data *eth_data)
 {
        orion_ge01_init(eth_data,
                        GE01_PHYS_BASE, IRQ_KIRKWOOD_GE01_SUM,
-                       IRQ_KIRKWOOD_GE01_ERR);
+                       IRQ_KIRKWOOD_GE01_ERR, 1600);
        clk_prepare_enable(ge1);
 }
 
diff --git a/arch/arm/mach-kirkwood/include/mach/io.h b/arch/arm/mach-kirkwood/include/mach/io.h
deleted file mode 100644 (file)
index 5d0ab61..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * arch/arm/mach-kirkwood/include/mach/io.h
- *
- * 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.
- */
-
-#ifndef __ASM_ARCH_IO_H
-#define __ASM_ARCH_IO_H
-
-#include "kirkwood.h"
-
-#define IO_SPACE_LIMIT         0xffffffff
-
-static inline void __iomem *__io(unsigned long addr)
-{
-       return (void __iomem *)((addr - KIRKWOOD_PCIE_IO_BUS_BASE)
-                                       + KIRKWOOD_PCIE_IO_VIRT_BASE);
-}
-
-#define __io(a)                        __io(a)
-
-#endif
index c5b68510776b71c75c2731fcf5253a4114597c30..af4f0000dcef31adf260e4c1def6365e4158a002 100644 (file)
 #define KIRKWOOD_NAND_MEM_SIZE         SZ_1K
 
 #define KIRKWOOD_PCIE1_IO_PHYS_BASE    0xf3000000
-#define KIRKWOOD_PCIE1_IO_VIRT_BASE    0xfef00000
-#define KIRKWOOD_PCIE1_IO_BUS_BASE     0x00100000
-#define KIRKWOOD_PCIE1_IO_SIZE         SZ_1M
+#define KIRKWOOD_PCIE1_IO_BUS_BASE     0x00010000
+#define KIRKWOOD_PCIE1_IO_SIZE         SZ_64K
 
 #define KIRKWOOD_PCIE_IO_PHYS_BASE     0xf2000000
-#define KIRKWOOD_PCIE_IO_VIRT_BASE     0xfee00000
 #define KIRKWOOD_PCIE_IO_BUS_BASE      0x00000000
-#define KIRKWOOD_PCIE_IO_SIZE          SZ_1M
+#define KIRKWOOD_PCIE_IO_SIZE          SZ_64K
 
 #define KIRKWOOD_REGS_PHYS_BASE                0xf1000000
 #define KIRKWOOD_REGS_VIRT_BASE                0xfed00000
index 6e8b2efa3c353ae830639b5a25a526b305dd922e..532d8acb38f910233e8f525a68ab928dc9961e85 100644 (file)
@@ -56,7 +56,7 @@ struct pcie_port {
        void __iomem            *base;
        spinlock_t              conf_lock;
        int                     irq;
-       struct resource         res[2];
+       struct resource         res;
 };
 
 static int pcie_port_map[2];
@@ -136,21 +136,13 @@ static void __init pcie0_ioresources_init(struct pcie_port *pp)
        pp->base = (void __iomem *)PCIE_VIRT_BASE;
        pp->irq = IRQ_KIRKWOOD_PCIE;
 
-       /*
-        * IORESOURCE_IO
-        */
-       pp->res[0].name = "PCIe 0 I/O Space";
-       pp->res[0].start = KIRKWOOD_PCIE_IO_BUS_BASE;
-       pp->res[0].end = pp->res[0].start + KIRKWOOD_PCIE_IO_SIZE - 1;
-       pp->res[0].flags = IORESOURCE_IO;
-
        /*
         * IORESOURCE_MEM
         */
-       pp->res[1].name = "PCIe 0 MEM";
-       pp->res[1].start = KIRKWOOD_PCIE_MEM_PHYS_BASE;
-       pp->res[1].end = pp->res[1].start + KIRKWOOD_PCIE_MEM_SIZE - 1;
-       pp->res[1].flags = IORESOURCE_MEM;
+       pp->res.name = "PCIe 0 MEM";
+       pp->res.start = KIRKWOOD_PCIE_MEM_PHYS_BASE;
+       pp->res.end = pp->res.start + KIRKWOOD_PCIE_MEM_SIZE - 1;
+       pp->res.flags = IORESOURCE_MEM;
 }
 
 static void __init pcie1_ioresources_init(struct pcie_port *pp)
@@ -158,21 +150,13 @@ static void __init pcie1_ioresources_init(struct pcie_port *pp)
        pp->base = (void __iomem *)PCIE1_VIRT_BASE;
        pp->irq = IRQ_KIRKWOOD_PCIE1;
 
-       /*
-        * IORESOURCE_IO
-        */
-       pp->res[0].name = "PCIe 1 I/O Space";
-       pp->res[0].start = KIRKWOOD_PCIE1_IO_BUS_BASE;
-       pp->res[0].end = pp->res[0].start + KIRKWOOD_PCIE1_IO_SIZE - 1;
-       pp->res[0].flags = IORESOURCE_IO;
-
        /*
         * IORESOURCE_MEM
         */
-       pp->res[1].name = "PCIe 1 MEM";
-       pp->res[1].start = KIRKWOOD_PCIE1_MEM_PHYS_BASE;
-       pp->res[1].end = pp->res[1].start + KIRKWOOD_PCIE1_MEM_SIZE - 1;
-       pp->res[1].flags = IORESOURCE_MEM;
+       pp->res.name = "PCIe 1 MEM";
+       pp->res.start = KIRKWOOD_PCIE1_MEM_PHYS_BASE;
+       pp->res.end = pp->res.start + KIRKWOOD_PCIE1_MEM_SIZE - 1;
+       pp->res.flags = IORESOURCE_MEM;
 }
 
 static int __init kirkwood_pcie_setup(int nr, struct pci_sys_data *sys)
@@ -197,23 +181,21 @@ static int __init kirkwood_pcie_setup(int nr, struct pci_sys_data *sys)
        case 0:
                kirkwood_enable_pcie_clk("0");
                pcie0_ioresources_init(pp);
+               pci_ioremap_io(SZ_64K * sys->busnr, KIRKWOOD_PCIE_IO_PHYS_BASE);
                break;
        case 1:
                kirkwood_enable_pcie_clk("1");
                pcie1_ioresources_init(pp);
+               pci_ioremap_io(SZ_64K * sys->busnr, KIRKWOOD_PCIE1_IO_PHYS_BASE);
                break;
        default:
                panic("PCIe setup: invalid controller %d", index);
        }
 
-       if (request_resource(&ioport_resource, &pp->res[0]))
-               panic("Request PCIe%d IO resource failed\n", index);
-       if (request_resource(&iomem_resource, &pp->res[1]))
+       if (request_resource(&iomem_resource, &pp->res))
                panic("Request PCIe%d Memory resource failed\n", index);
 
-       sys->io_offset = 0;
-       pci_add_resource_offset(&sys->resources, &pp->res[0], sys->io_offset);
-       pci_add_resource_offset(&sys->resources, &pp->res[1], sys->mem_offset);
+       pci_add_resource_offset(&sys->resources, &pp->res, sys->mem_offset);
 
        /*
         * Generic PCIe unit setup.
index 853efd9133c6a8f91ed7e1bef24158f562006942..9324ef965c26d28a48c6447dcfda827e3f5fe48c 100644 (file)
@@ -11,9 +11,6 @@ obj-                          :=
 # PCI support is optional
 obj-$(CONFIG_PCI)              += pci.o
 
-# LEDs
-obj-$(CONFIG_LEDS)             += leds.o
-
 # Board-specific support
 obj-$(CONFIG_MACH_KS8695)      += board-micrel.o
 obj-$(CONFIG_MACH_DSM320)      += board-dsm320.o
index 73bd63812878548fcd1e7526ff3c5c22592a2664..47399bc3c024c1bdce49d19c08a59f41b982b0c8 100644 (file)
@@ -182,27 +182,6 @@ static void __init ks8695_add_device_watchdog(void)
 }
 
 
-/* --------------------------------------------------------------------
- *  LEDs
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_LEDS)
-short ks8695_leds_cpu = -1;
-short ks8695_leds_timer = -1;
-
-void __init ks8695_init_leds(u8 cpu_led, u8 timer_led)
-{
-       /* Enable GPIO to access the LEDs */
-       gpio_direction_output(cpu_led, 1);
-       gpio_direction_output(timer_led, 1);
-
-       ks8695_leds_cpu   = cpu_led;
-       ks8695_leds_timer = timer_led;
-}
-#else
-void __init ks8695_init_leds(u8 cpu_led, u8 timer_led) {}
-#endif
-
 /* -------------------------------------------------------------------- */
 
 /*
index 85a3c9aa7d1361e18d3407739be8a1b710b88956..1e6594a0f2978dfec93078a5ad918145073960cb 100644 (file)
@@ -18,11 +18,6 @@ extern void __init ks8695_add_device_wan(void);
 extern void __init ks8695_add_device_lan(void);
 extern void __init ks8695_add_device_hpna(void);
 
- /* LEDs */
-extern short ks8695_leds_cpu;
-extern short ks8695_leds_timer;
-extern void __init ks8695_init_leds(u8 cpu_led, u8 timer_led);
-
  /* PCI */
 #define KS8695_MODE_PCI                0
 #define KS8695_MODE_MINIPCI    1
diff --git a/arch/arm/mach-ks8695/leds.c b/arch/arm/mach-ks8695/leds.c
deleted file mode 100644 (file)
index 4bd7075..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * LED driver for KS8695-based boards.
- *
- * Copyright (C) Andrew Victor
- *
- * 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/module.h>
-#include <linux/init.h>
-
-#include <asm/leds.h>
-#include <mach/devices.h>
-
-
-static inline void ks8695_led_on(unsigned int led)
-{
-       gpio_set_value(led, 0);
-}
-
-static inline void ks8695_led_off(unsigned int led)
-{
-       gpio_set_value(led, 1);
-}
-
-static inline void ks8695_led_toggle(unsigned int led)
-{
-       unsigned long is_off = gpio_get_value(led);
-       if (is_off)
-               ks8695_led_on(led);
-       else
-               ks8695_led_off(led);
-}
-
-
-/*
- * Handle LED events.
- */
-static void ks8695_leds_event(led_event_t evt)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-
-       switch(evt) {
-       case led_start:         /* System startup */
-               ks8695_led_on(ks8695_leds_cpu);
-               break;
-
-       case led_stop:          /* System stop / suspend */
-               ks8695_led_off(ks8695_leds_cpu);
-               break;
-
-#ifdef CONFIG_LEDS_TIMER
-       case led_timer:         /* Every 50 timer ticks */
-               ks8695_led_toggle(ks8695_leds_timer);
-               break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-       case led_idle_start:    /* Entering idle state */
-               ks8695_led_off(ks8695_leds_cpu);
-               break;
-
-       case led_idle_end:      /* Exit idle state */
-               ks8695_led_on(ks8695_leds_cpu);
-               break;
-#endif
-
-       default:
-               break;
-       }
-
-       local_irq_restore(flags);
-}
-
-
-static int __init leds_init(void)
-{
-       if ((ks8695_leds_timer == -1) || (ks8695_leds_cpu == -1))
-               return -ENODEV;
-
-       leds_event = ks8695_leds_event;
-
-       leds_event(led_start);
-       return 0;
-}
-
-__initcall(leds_init);
index c709a24a9d256fceaab077914ccc0e8cffc7b634..c2bb95cf1a8250f15749e32a63c862f76bf97a57 100644 (file)
@@ -163,7 +163,7 @@ static int __init mmp2_init(void)
 {
        if (cpu_is_mmp2()) {
 #ifdef CONFIG_CACHE_TAUROS2
-               tauros2_init();
+               tauros2_init(0);
 #endif
                mfp_init_base(MFPR_VIRT_BASE);
                mfp_init_addr(mmp2_addr_map);
index 6da52e9f2bdcf7dc353687d71093887af9deb3f4..51ac8d1898c18911e03fd492a53a65c82d9599f3 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/io.h>
 #include <linux/platform_device.h>
 
+#include <asm/hardware/cache-tauros2.h>
 #include <asm/mach/time.h>
 #include <mach/addr-map.h>
 #include <mach/regs-apbc.h>
@@ -116,6 +117,9 @@ static struct clk_lookup pxa910_clkregs[] = {
 static int __init pxa910_init(void)
 {
        if (cpu_is_pxa910()) {
+#ifdef CONFIG_CACHE_TAUROS2
+               tauros2_init(0);
+#endif
                mfp_init_base(MFPR_VIRT_BASE);
                mfp_init_addr(pxa910_mfp_addr_map);
                pxa_init_dma(IRQ_PXA910_DMA_INT0, 32);
index 7a7de2b12a622d06abe13daa7efad655772f0fb4..ce55fd8821c40f3bdff6bd757ef9bc47af5b32c5 100644 (file)
@@ -177,12 +177,22 @@ static struct mv_usb_platform_data ttc_usb_pdata = {
 #endif
 #endif
 
+#ifdef CONFIG_MTD_NAND_PXA3xx
+static struct pxa3xx_nand_platform_data dkb_nand_info = {
+       .enable_arbiter = 1,
+       .num_cs = 1,
+};
+#endif
+
 static void __init ttc_dkb_init(void)
 {
        mfp_config(ARRAY_AND_SIZE(ttc_dkb_pin_config));
 
        /* on-chip devices */
        pxa910_add_uart(1);
+#ifdef CONFIG_MTD_NAND_PXA3xx
+       pxa910_add_nand(&dkb_nand_info);
+#endif
 
        /* off-chip devices */
        pxa910_add_twsi(0, NULL, ARRAY_AND_SIZE(ttc_dkb_i2c_info));
index 62b53d710efde1a0a71095b2e9e54186cb454886..137e479d15a0a48d81410eb60d05e239c7226812 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/mbus.h>
 #include <linux/io.h>
 #include <plat/addr-map.h>
+#include <mach/mv78xx0.h>
 #include "common.h"
 
 /*
@@ -37,7 +38,7 @@
 #define WIN0_OFF(n)            (BRIDGE_VIRT_BASE + 0x0000 + ((n) << 4))
 #define WIN8_OFF(n)            (BRIDGE_VIRT_BASE + 0x0900 + (((n) - 8) << 4))
 
-static void __init __iomem *win_cfg_base(int win)
+static void __init __iomem *win_cfg_base(const struct orion_addr_map_cfg *cfg, int win)
 {
        /*
         * Find the control register base address for this window.
@@ -81,7 +82,7 @@ void __init mv78xx0_setup_pcie_io_win(int window, u32 base, u32 size,
                                      int maj, int min)
 {
        orion_setup_cpu_win(&addr_map_cfg, window, base, size,
-                           TARGET_PCIE(maj), ATTR_PCIE_IO(min), -1);
+                           TARGET_PCIE(maj), ATTR_PCIE_IO(min), 0);
 }
 
 void __init mv78xx0_setup_pcie_mem_win(int window, u32 base, u32 size,
index b4c53b846c9caa8402ce764aec9f9f254379031a..6b0c38735527504be6ec58227f9a8be4d9a34286 100644 (file)
@@ -134,11 +134,6 @@ static struct map_desc mv78xx0_io_desc[] __initdata = {
                .pfn            = 0,
                .length         = MV78XX0_CORE_REGS_SIZE,
                .type           = MT_DEVICE,
-       }, {
-               .virtual        = MV78XX0_PCIE_IO_VIRT_BASE(0),
-               .pfn            = __phys_to_pfn(MV78XX0_PCIE_IO_PHYS_BASE(0)),
-               .length         = MV78XX0_PCIE_IO_SIZE * 8,
-               .type           = MT_DEVICE,
        }, {
                .virtual        = MV78XX0_REGS_VIRT_BASE,
                .pfn            = __phys_to_pfn(MV78XX0_REGS_PHYS_BASE),
@@ -213,7 +208,8 @@ void __init mv78xx0_ge00_init(struct mv643xx_eth_platform_data *eth_data)
 {
        orion_ge00_init(eth_data,
                        GE00_PHYS_BASE, IRQ_MV78XX0_GE00_SUM,
-                       IRQ_MV78XX0_GE_ERR);
+                       IRQ_MV78XX0_GE_ERR,
+                       MV643XX_TX_CSUM_DEFAULT_LIMIT);
 }
 
 
@@ -224,7 +220,8 @@ void __init mv78xx0_ge01_init(struct mv643xx_eth_platform_data *eth_data)
 {
        orion_ge01_init(eth_data,
                        GE01_PHYS_BASE, IRQ_MV78XX0_GE01_SUM,
-                       NO_IRQ);
+                       NO_IRQ,
+                       MV643XX_TX_CSUM_DEFAULT_LIMIT);
 }
 
 
diff --git a/arch/arm/mach-mv78xx0/include/mach/io.h b/arch/arm/mach-mv78xx0/include/mach/io.h
deleted file mode 100644 (file)
index c7d9d00..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * arch/arm/mach-mv78xx0/include/mach/io.h
- *
- * 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.
- */
-
-#ifndef __ASM_ARCH_IO_H
-#define __ASM_ARCH_IO_H
-
-#include "mv78xx0.h"
-
-#define IO_SPACE_LIMIT         0xffffffff
-
-static inline void __iomem *__io(unsigned long addr)
-{
-       return (void __iomem *)((addr - MV78XX0_PCIE_IO_PHYS_BASE(0))
-                                       + MV78XX0_PCIE_IO_VIRT_BASE(0));
-}
-
-#define __io(a)                        __io(a)
-
-#endif
index e807c4c52a0b6331a4e02146f71edc127d95cb7f..bd03fed1128eeaa93863428062f24d1f1fa2d285 100644 (file)
  *
  * virt                phys            size
  * fe400000    f102x000        16K     core-specific peripheral registers
- * fe700000    f0800000        1M      PCIe #0 I/O space
- * fe800000    f0900000        1M      PCIe #1 I/O space
- * fe900000    f0a00000        1M      PCIe #2 I/O space
- * fea00000    f0b00000        1M      PCIe #3 I/O space
- * feb00000    f0c00000        1M      PCIe #4 I/O space
- * fec00000    f0d00000        1M      PCIe #5 I/O space
- * fed00000    f0e00000        1M      PCIe #6 I/O space
- * fee00000    f0f00000        1M      PCIe #7 I/O space
- * fef00000    f1000000        1M      on-chip peripheral registers
+ * fee00000    f0800000        64K     PCIe #0 I/O space
+ * fee10000    f0900000        64K     PCIe #1 I/O space
+ * fee20000    f0a00000        64K     PCIe #2 I/O space
+ * fee30000    f0b00000        64K     PCIe #3 I/O space
+ * fee40000    f0c00000        64K     PCIe #4 I/O space
+ * fee50000    f0d00000        64K     PCIe #5 I/O space
+ * fee60000    f0e00000        64K     PCIe #6 I/O space
+ * fee70000    f0f00000        64K     PCIe #7 I/O space
+ * fd000000    f1000000        1M      on-chip peripheral registers
  */
 #define MV78XX0_CORE0_REGS_PHYS_BASE   0xf1020000
 #define MV78XX0_CORE1_REGS_PHYS_BASE   0xf1024000
 #define MV78XX0_CORE_REGS_SIZE         SZ_16K
 
 #define MV78XX0_PCIE_IO_PHYS_BASE(i)   (0xf0800000 + ((i) << 20))
-#define MV78XX0_PCIE_IO_VIRT_BASE(i)   (0xfe700000 + ((i) << 20))
 #define MV78XX0_PCIE_IO_SIZE           SZ_1M
 
 #define MV78XX0_REGS_PHYS_BASE         0xf1000000
-#define MV78XX0_REGS_VIRT_BASE         0xfef00000
+#define MV78XX0_REGS_VIRT_BASE         0xfd000000
 #define MV78XX0_REGS_SIZE              SZ_1M
 
 #define MV78XX0_PCIE_MEM_PHYS_BASE     0xc0000000
index 2e56e86b6d68fffba920f3c5c8118df599f7384b..26a059b4f4720173b1f12430d2a62bb0e1173f35 100644 (file)
@@ -15,6 +15,7 @@
 #include <asm/mach/pci.h>
 #include <plat/pcie.h>
 #include <plat/addr-map.h>
+#include <mach/mv78xx0.h>
 #include "common.h"
 
 struct pcie_port {
@@ -23,16 +24,13 @@ struct pcie_port {
        u8                      root_bus_nr;
        void __iomem            *base;
        spinlock_t              conf_lock;
-       char                    io_space_name[16];
        char                    mem_space_name[16];
-       struct resource         res[2];
+       struct resource         res;
 };
 
 static struct pcie_port pcie_port[8];
 static int num_pcie_ports;
 static struct resource pcie_io_space;
-static struct resource pcie_mem_space;
-
 
 void __init mv78xx0_pcie_id(u32 *dev, u32 *rev)
 {
@@ -40,102 +38,59 @@ void __init mv78xx0_pcie_id(u32 *dev, u32 *rev)
        *rev = orion_pcie_rev((void __iomem *)PCIE00_VIRT_BASE);
 }
 
+u32 pcie_port_size[8] = {
+       0,
+       0x30000000,
+       0x10000000,
+       0x10000000,
+       0x08000000,
+       0x08000000,
+       0x08000000,
+       0x04000000,
+};
+
 static void __init mv78xx0_pcie_preinit(void)
 {
        int i;
        u32 size_each;
        u32 start;
-       int win;
+       int win = 0;
 
        pcie_io_space.name = "PCIe I/O Space";
        pcie_io_space.start = MV78XX0_PCIE_IO_PHYS_BASE(0);
        pcie_io_space.end =
                MV78XX0_PCIE_IO_PHYS_BASE(0) + MV78XX0_PCIE_IO_SIZE * 8 - 1;
-       pcie_io_space.flags = IORESOURCE_IO;
+       pcie_io_space.flags = IORESOURCE_MEM;
        if (request_resource(&iomem_resource, &pcie_io_space))
                panic("can't allocate PCIe I/O space");
 
-       pcie_mem_space.name = "PCIe MEM Space";
-       pcie_mem_space.start = MV78XX0_PCIE_MEM_PHYS_BASE;
-       pcie_mem_space.end =
-               MV78XX0_PCIE_MEM_PHYS_BASE + MV78XX0_PCIE_MEM_SIZE - 1;
-       pcie_mem_space.flags = IORESOURCE_MEM;
-       if (request_resource(&iomem_resource, &pcie_mem_space))
-               panic("can't allocate PCIe MEM space");
+       if (num_pcie_ports > 7)
+               panic("invalid number of PCIe ports");
+
+       size_each = pcie_port_size[num_pcie_ports];
 
+       start = MV78XX0_PCIE_MEM_PHYS_BASE;
        for (i = 0; i < num_pcie_ports; i++) {
                struct pcie_port *pp = pcie_port + i;
 
-               snprintf(pp->io_space_name, sizeof(pp->io_space_name),
-                       "PCIe %d.%d I/O", pp->maj, pp->min);
-               pp->io_space_name[sizeof(pp->io_space_name) - 1] = 0;
-               pp->res[0].name = pp->io_space_name;
-               pp->res[0].start = MV78XX0_PCIE_IO_PHYS_BASE(i);
-               pp->res[0].end = pp->res[0].start + MV78XX0_PCIE_IO_SIZE - 1;
-               pp->res[0].flags = IORESOURCE_IO;
-
                snprintf(pp->mem_space_name, sizeof(pp->mem_space_name),
                        "PCIe %d.%d MEM", pp->maj, pp->min);
                pp->mem_space_name[sizeof(pp->mem_space_name) - 1] = 0;
-               pp->res[1].name = pp->mem_space_name;
-               pp->res[1].flags = IORESOURCE_MEM;
-       }
-
-       switch (num_pcie_ports) {
-       case 0:
-               size_each = 0;
-               break;
-
-       case 1:
-               size_each = 0x30000000;
-               break;
-
-       case 2 ... 3:
-               size_each = 0x10000000;
-               break;
-
-       case 4 ... 6:
-               size_each = 0x08000000;
-               break;
-
-       case 7:
-               size_each = 0x04000000;
-               break;
-
-       default:
-               panic("invalid number of PCIe ports");
-       }
-
-       start = MV78XX0_PCIE_MEM_PHYS_BASE;
-       for (i = 0; i < num_pcie_ports; i++) {
-               struct pcie_port *pp = pcie_port + i;
-
-               pp->res[1].start = start;
-               pp->res[1].end = start + size_each - 1;
+               pp->res.name = pp->mem_space_name;
+               pp->res.flags = IORESOURCE_MEM;
+               pp->res.start = start;
+               pp->res.end = start + size_each - 1;
                start += size_each;
-       }
-
-       for (i = 0; i < num_pcie_ports; i++) {
-               struct pcie_port *pp = pcie_port + i;
 
-               if (request_resource(&pcie_io_space, &pp->res[0]))
-                       panic("can't allocate PCIe I/O sub-space");
-
-               if (request_resource(&pcie_mem_space, &pp->res[1]))
+               if (request_resource(&iomem_resource, &pp->res))
                        panic("can't allocate PCIe MEM sub-space");
-       }
 
-       win = 0;
-       for (i = 0; i < num_pcie_ports; i++) {
-               struct pcie_port *pp = pcie_port + i;
+               mv78xx0_setup_pcie_mem_win(win + i + 8, pp->res.start,
+                                          resource_size(&pp->res),
+                                          pp->maj, pp->min);
 
-               mv78xx0_setup_pcie_io_win(win++, pp->res[0].start,
-                                         resource_size(&pp->res[0]),
+               mv78xx0_setup_pcie_io_win(win + i, i * SZ_64K, SZ_64K,
                                          pp->maj, pp->min);
-
-               mv78xx0_setup_pcie_mem_win(win++, pp->res[1].start,
-                                          resource_size(&pp->res[1]),
-                                          pp->maj, pp->min);
        }
 }
 
@@ -156,8 +111,9 @@ static int __init mv78xx0_pcie_setup(int nr, struct pci_sys_data *sys)
        orion_pcie_set_local_bus_nr(pp->base, sys->busnr);
        orion_pcie_setup(pp->base);
 
-       pci_add_resource_offset(&sys->resources, &pp->res[0], sys->io_offset);
-       pci_add_resource_offset(&sys->resources, &pp->res[1], sys->mem_offset);
+       pci_ioremap_io(nr * SZ_64K, MV78XX0_PCIE_IO_PHYS_BASE(nr));
+
+       pci_add_resource_offset(&sys->resources, &pp->res, sys->mem_offset);
 
        return 1;
 }
@@ -281,7 +237,7 @@ static void __init add_pcie_port(int maj, int min, unsigned long base)
                pp->root_bus_nr = -1;
                pp->base = (void __iomem *)base;
                spin_lock_init(&pp->conf_lock);
-               memset(pp->res, 0, sizeof(pp->res));
+               memset(&pp->res, 0, sizeof(pp->res));
        } else {
                printk("link down, ignoring\n");
        }
index ccdf83b17cf16030612bdf62c43711f7f926baa6..9a8bbda195b28a2b64e19a01d052990a2d6f1156 100644 (file)
@@ -2,9 +2,6 @@ if ARCH_MXS
 
 source "arch/arm/mach-mxs/devices/Kconfig"
 
-config MXS_OCOTP
-       bool
-
 config SOC_IMX23
        bool
        select ARM_AMBA
@@ -66,7 +63,6 @@ config MACH_MX28EVK
        select MXS_HAVE_PLATFORM_MXS_SAIF
        select MXS_HAVE_PLATFORM_MXS_I2C
        select MXS_HAVE_PLATFORM_RTC_STMP3XXX
-       select MXS_OCOTP
        help
          Include support for MX28EVK platform. This includes specific
          configurations for the board and its peripherals.
@@ -94,7 +90,6 @@ config MODULE_M28
        select MXS_HAVE_PLATFORM_MXS_I2C
        select MXS_HAVE_PLATFORM_MXS_MMC
        select MXS_HAVE_PLATFORM_MXSFB
-       select MXS_OCOTP
 
 config MODULE_APX4
        bool
@@ -106,7 +101,6 @@ config MODULE_APX4
        select MXS_HAVE_PLATFORM_MXS_I2C
        select MXS_HAVE_PLATFORM_MXS_MMC
        select MXS_HAVE_PLATFORM_MXS_SAIF
-       select MXS_OCOTP
 
 config MACH_TX28
        bool "Ka-Ro TX28 module"
index e41590ccb437feb62a0a9154778d91a700185521..fed3695a1339d89c754edb10ae382730429625b8 100644 (file)
@@ -1,7 +1,6 @@
 # Common support
-obj-y := devices.o icoll.o iomux.o system.o timer.o mm.o
+obj-y := devices.o icoll.o iomux.o ocotp.o system.o timer.o mm.o
 
-obj-$(CONFIG_MXS_OCOTP) += ocotp.o
 obj-$(CONFIG_PM) += pm.o
 
 obj-$(CONFIG_MACH_MXS_DT) += mach-mxs.o
index f4535a7dadf537d7ffc0a691598db24103ba4ab1..66862fb981f953107d8409fd1b3418e8fdb5f6fc 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/mtd/partitions.h>
 #include <linux/i2c.h>
 #include <linux/io.h>
+#include <linux/pinctrl/machine.h>
 #include <asm/hardware/vic.h>
 #include <asm/sizes.h>
 #include <asm/mach-types.h>
@@ -33,6 +34,7 @@
 
 #include <plat/gpio-nomadik.h>
 #include <plat/mtu.h>
+#include <plat/pincfg.h>
 
 #include <mach/nand.h>
 #include <mach/fsmc.h>
@@ -291,8 +293,42 @@ static struct i2c_board_info __initdata nhk8815_i2c2_devices[] = {
        },
 };
 
+static unsigned long out_low[] = { PIN_OUTPUT_LOW };
+static unsigned long out_high[] = { PIN_OUTPUT_HIGH };
+static unsigned long in_nopull[] = { PIN_INPUT_NOPULL };
+static unsigned long in_pullup[] = { PIN_INPUT_PULLUP };
+
+static struct pinctrl_map __initdata nhk8815_pinmap[] = {
+       PIN_MAP_MUX_GROUP_DEFAULT("uart0", "pinctrl-stn8815", "u0_a_1", "u0"),
+       PIN_MAP_MUX_GROUP_DEFAULT("uart1", "pinctrl-stn8815", "u1_a_1", "u1"),
+       /* Hog in MMC/SD card mux */
+       PIN_MAP_MUX_GROUP_HOG_DEFAULT("pinctrl-stn8815", "mmcsd_a_1", "mmcsd"),
+       /* MCCLK */
+       PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO8_B10", out_low),
+       /* MCCMD */
+       PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO9_A10", in_pullup),
+       /* MCCMDDIR */
+       PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO10_C11", out_high),
+       /* MCDAT3-0 */
+       PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO11_B11", in_pullup),
+       PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO12_A11", in_pullup),
+       PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO13_C12", in_pullup),
+       PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO14_B12", in_pullup),
+       /* MCDAT0DIR */
+       PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO15_A12", out_high),
+       /* MCDAT31DIR */
+       PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO16_C13", out_high),
+       /* MCMSFBCLK */
+       PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO24_C15", in_pullup),
+       /* CD input GPIO */
+       PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO111_H21", in_nopull),
+       /* CD bias drive */
+       PIN_MAP_CONFIGS_PIN_HOG_DEFAULT("pinctrl-stn8815", "GPIO112_J21", out_low),
+};
+
 static void __init nhk8815_platform_init(void)
 {
+       pinctrl_register_mappings(nhk8815_pinmap, ARRAY_SIZE(nhk8815_pinmap));
        cpu8815_platform_init();
        nhk8815_onenand_init();
        platform_add_devices(nhk8815_platform_devices,
index 6fd8e46567a4e602fc15bed22f97f8661e7dc1c5..b617eaed0ce58695ac709b460ac29b8ac2d4b1d6 100644 (file)
@@ -83,6 +83,18 @@ void cpu8815_add_gpios(resource_size_t *base, int num, int irq,
        }
 }
 
+static inline void
+cpu8815_add_pinctrl(struct device *parent, const char *name)
+{
+       struct platform_device_info pdevinfo = {
+               .parent = parent,
+               .name = name,
+               .id = -1,
+       };
+
+       platform_device_register_full(&pdevinfo);
+}
+
 static int __init cpu8815_init(void)
 {
        struct nmk_gpio_platform_data pdata = {
@@ -91,6 +103,7 @@ static int __init cpu8815_init(void)
 
        cpu8815_add_gpios(cpu8815_gpio_base, ARRAY_SIZE(cpu8815_gpio_base),
                          IRQ_GPIO0, &pdata);
+       cpu8815_add_pinctrl(NULL, "pinctrl-stn8815");
        amba_apb_device_add(NULL, "rng", NOMADIK_RNG_BASE, SZ_4K, 0, 0, NULL, 0);
        amba_apb_device_add(NULL, "rtc-pl031", NOMADIK_RTC_BASE, SZ_4K, IRQ_RTC_RTT, 0, NULL, 0);
        return 0;
index 398e9e53e1891afcbf8ade3a6dc3d1a6d5890c56..cd169c386161a58fc4f42702ec008f83c3194722 100644 (file)
@@ -61,14 +61,6 @@ obj-$(CONFIG_ARCH_OMAP850)           += gpio7xx.o
 obj-$(CONFIG_ARCH_OMAP15XX)            += gpio15xx.o
 obj-$(CONFIG_ARCH_OMAP16XX)            += gpio16xx.o
 
-# LEDs support
-led-$(CONFIG_MACH_OMAP_H2)             += leds-h2p2-debug.o
-led-$(CONFIG_MACH_OMAP_H3)             += leds-h2p2-debug.o
-led-$(CONFIG_MACH_OMAP_INNOVATOR)      += leds-innovator.o
-led-$(CONFIG_MACH_OMAP_PERSEUS2)       += leds-h2p2-debug.o
-led-$(CONFIG_MACH_OMAP_OSK)            += leds-osk.o
-obj-$(CONFIG_LEDS)                     += $(led-y)
-
 ifneq ($(CONFIG_FB_OMAP),)
 obj-y += lcd_dma.o
 endif
index 44a4ab195fbc54ec0537d24328fed150216d8e3b..cd8836f43f01ebb57e927ebb0db58f65a8db050d 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/i2c/tps65010.h>
 #include <linux/smc91x.h>
 #include <linux/omapfb.h>
+#include <linux/leds.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -306,12 +307,39 @@ static struct platform_device h2_irda_device = {
        .resource       = h2_irda_resources,
 };
 
+static struct gpio_led h2_gpio_led_pins[] = {
+       {
+               .name           = "h2:red",
+               .default_trigger = "heartbeat",
+               .gpio           = 3,
+       },
+       {
+               .name           = "h2:green",
+               .default_trigger = "cpu0",
+               .gpio           = OMAP_MPUIO(4),
+       },
+};
+
+static struct gpio_led_platform_data h2_gpio_led_data = {
+       .leds           = h2_gpio_led_pins,
+       .num_leds       = ARRAY_SIZE(h2_gpio_led_pins),
+};
+
+static struct platform_device h2_gpio_leds = {
+       .name   = "leds-gpio",
+       .id     = -1,
+       .dev    = {
+               .platform_data = &h2_gpio_led_data,
+       },
+};
+
 static struct platform_device *h2_devices[] __initdata = {
        &h2_nor_device,
        &h2_nand_device,
        &h2_smc91x_device,
        &h2_irda_device,
        &h2_kp_device,
+       &h2_gpio_leds,
 };
 
 static void __init h2_init_smc91x(void)
@@ -406,6 +434,10 @@ static void __init h2_init(void)
        omap_cfg_reg(E19_1610_KBR4);
        omap_cfg_reg(N19_1610_KBR5);
 
+       /* GPIO based LEDs */
+       omap_cfg_reg(P18_1610_GPIO3);
+       omap_cfg_reg(MPUIO4);
+
        h2_smc91x_resources[1].start = gpio_to_irq(0);
        h2_smc91x_resources[1].end = gpio_to_irq(0);
        platform_add_devices(h2_devices, ARRAY_SIZE(h2_devices));
index 86cb5a04a404e2ea3b8c89f5fb3051ab1d3583ec..1fa9c45c1ae591343e3d4ee4588fa01a34fcd21f 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/i2c/tps65010.h>
 #include <linux/smc91x.h>
 #include <linux/omapfb.h>
+#include <linux/leds.h>
 
 #include <asm/setup.h>
 #include <asm/page.h>
@@ -324,6 +325,32 @@ static struct spi_board_info h3_spi_board_info[] __initdata = {
        },
 };
 
+static struct gpio_led h3_gpio_led_pins[] = {
+       {
+               .name           = "h3:red",
+               .default_trigger = "heartbeat",
+               .gpio           = 3,
+       },
+       {
+               .name           = "h3:green",
+               .default_trigger = "cpu0",
+               .gpio           = OMAP_MPUIO(4),
+       },
+};
+
+static struct gpio_led_platform_data h3_gpio_led_data = {
+       .leds           = h3_gpio_led_pins,
+       .num_leds       = ARRAY_SIZE(h3_gpio_led_pins),
+};
+
+static struct platform_device h3_gpio_leds = {
+       .name   = "leds-gpio",
+       .id     = -1,
+       .dev    = {
+               .platform_data = &h3_gpio_led_data,
+       },
+};
+
 static struct platform_device *devices[] __initdata = {
        &nor_device,
        &nand_device,
@@ -331,6 +358,7 @@ static struct platform_device *devices[] __initdata = {
        &intlat_device,
        &h3_kp_device,
        &h3_lcd_device,
+       &h3_gpio_leds,
 };
 
 static struct omap_usb_config h3_usb_config __initdata = {
@@ -398,6 +426,10 @@ static void __init h3_init(void)
        omap_cfg_reg(E19_1610_KBR4);
        omap_cfg_reg(N19_1610_KBR5);
 
+       /* GPIO based LEDs */
+       omap_cfg_reg(P18_1610_GPIO3);
+       omap_cfg_reg(MPUIO4);
+
        smc91x_resources[1].start = gpio_to_irq(40);
        smc91x_resources[1].end = gpio_to_irq(40);
        platform_add_devices(devices, ARRAY_SIZE(devices));
index 8784705edb60135aac86a8bc660b02a8e1f284f5..7ee1c1eac3564c61b28fa87f47d2fc70ea9fa8ab 100644 (file)
@@ -380,10 +380,37 @@ static struct platform_device osk5912_lcd_device = {
        .id             = -1,
 };
 
+static struct gpio_led mistral_gpio_led_pins[] = {
+       {
+               .name           = "mistral:red",
+               .default_trigger = "heartbeat",
+               .gpio           = 3,
+       },
+       {
+               .name           = "mistral:green",
+               .default_trigger = "cpu0",
+               .gpio           = OMAP_MPUIO(4),
+       },
+};
+
+static struct gpio_led_platform_data mistral_gpio_led_data = {
+       .leds           = mistral_gpio_led_pins,
+       .num_leds       = ARRAY_SIZE(mistral_gpio_led_pins),
+};
+
+static struct platform_device mistral_gpio_leds = {
+       .name   = "leds-gpio",
+       .id     = -1,
+       .dev    = {
+               .platform_data = &mistral_gpio_led_data,
+       },
+};
+
 static struct platform_device *mistral_devices[] __initdata = {
        &osk5912_kp_device,
        &mistral_bl_device,
        &osk5912_lcd_device,
+       &mistral_gpio_leds,
 };
 
 static int mistral_get_pendown_state(void)
@@ -508,6 +535,12 @@ static void __init osk_mistral_init(void)
        if (gpio_request(2, "lcd_pwr") == 0)
                gpio_direction_output(2, 1);
 
+       /*
+        * GPIO based LEDs
+        */
+       omap_cfg_reg(P18_1610_GPIO3);
+       omap_cfg_reg(MPUIO4);
+
        i2c_register_board_info(1, mistral_i2c_board_info,
                        ARRAY_SIZE(mistral_i2c_board_info));
 
diff --git a/arch/arm/mach-omap1/leds-h2p2-debug.c b/arch/arm/mach-omap1/leds-h2p2-debug.c
deleted file mode 100644 (file)
index f6b14a1..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * linux/arch/arm/mach-omap1/leds-h2p2-debug.c
- *
- * Copyright 2003 by Texas Instruments Incorporated
- *
- * There are 16 LEDs on the debug board (all green); four may be used
- * for logical 'green', 'amber', 'red', and 'blue' (after "claiming").
- *
- * The "surfer" expansion board and H2 sample board also have two-color
- * green+red LEDs (in parallel), used here for timer and idle indicators.
- */
-#include <linux/gpio.h>
-#include <linux/init.h>
-#include <linux/kernel_stat.h>
-#include <linux/sched.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-#include <asm/mach-types.h>
-
-#include <plat/fpga.h>
-
-#include "leds.h"
-
-
-#define GPIO_LED_RED           3
-#define GPIO_LED_GREEN         OMAP_MPUIO(4)
-
-
-#define LED_STATE_ENABLED      0x01
-#define LED_STATE_CLAIMED      0x02
-#define LED_TIMER_ON           0x04
-
-#define GPIO_IDLE              GPIO_LED_GREEN
-#define GPIO_TIMER             GPIO_LED_RED
-
-
-void h2p2_dbg_leds_event(led_event_t evt)
-{
-       unsigned long flags;
-
-       static struct h2p2_dbg_fpga __iomem *fpga;
-       static u16 led_state, hw_led_state;
-
-       local_irq_save(flags);
-
-       if (!(led_state & LED_STATE_ENABLED) && evt != led_start)
-               goto done;
-
-       switch (evt) {
-       case led_start:
-               if (!fpga)
-                       fpga = ioremap(H2P2_DBG_FPGA_START,
-                                               H2P2_DBG_FPGA_SIZE);
-               if (fpga) {
-                       led_state |= LED_STATE_ENABLED;
-                       __raw_writew(~0, &fpga->leds);
-               }
-               break;
-
-       case led_stop:
-       case led_halted:
-               /* all leds off during suspend or shutdown */
-
-               if (! machine_is_omap_perseus2()) {
-                       gpio_set_value(GPIO_TIMER, 0);
-                       gpio_set_value(GPIO_IDLE, 0);
-               }
-
-               __raw_writew(~0, &fpga->leds);
-               led_state &= ~LED_STATE_ENABLED;
-               if (evt == led_halted) {
-                       iounmap(fpga);
-                       fpga = NULL;
-               }
-
-               goto done;
-
-       case led_claim:
-               led_state |= LED_STATE_CLAIMED;
-               hw_led_state = 0;
-               break;
-
-       case led_release:
-               led_state &= ~LED_STATE_CLAIMED;
-               break;
-
-#ifdef CONFIG_LEDS_TIMER
-       case led_timer:
-               led_state ^= LED_TIMER_ON;
-
-               if (machine_is_omap_perseus2())
-                       hw_led_state ^= H2P2_DBG_FPGA_P2_LED_TIMER;
-               else {
-                       gpio_set_value(GPIO_TIMER, led_state & LED_TIMER_ON);
-                       goto done;
-               }
-
-               break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-       case led_idle_start:
-               if (machine_is_omap_perseus2())
-                       hw_led_state |= H2P2_DBG_FPGA_P2_LED_IDLE;
-               else {
-                       gpio_set_value(GPIO_IDLE, 1);
-                       goto done;
-               }
-
-               break;
-
-       case led_idle_end:
-               if (machine_is_omap_perseus2())
-                       hw_led_state &= ~H2P2_DBG_FPGA_P2_LED_IDLE;
-               else {
-                       gpio_set_value(GPIO_IDLE, 0);
-                       goto done;
-               }
-
-               break;
-#endif
-
-       case led_green_on:
-               hw_led_state |= H2P2_DBG_FPGA_LED_GREEN;
-               break;
-       case led_green_off:
-               hw_led_state &= ~H2P2_DBG_FPGA_LED_GREEN;
-               break;
-
-       case led_amber_on:
-               hw_led_state |= H2P2_DBG_FPGA_LED_AMBER;
-               break;
-       case led_amber_off:
-               hw_led_state &= ~H2P2_DBG_FPGA_LED_AMBER;
-               break;
-
-       case led_red_on:
-               hw_led_state |= H2P2_DBG_FPGA_LED_RED;
-               break;
-       case led_red_off:
-               hw_led_state &= ~H2P2_DBG_FPGA_LED_RED;
-               break;
-
-       case led_blue_on:
-               hw_led_state |= H2P2_DBG_FPGA_LED_BLUE;
-               break;
-       case led_blue_off:
-               hw_led_state &= ~H2P2_DBG_FPGA_LED_BLUE;
-               break;
-
-       default:
-               break;
-       }
-
-
-       /*
-        *  Actually burn the LEDs
-        */
-       if (led_state & LED_STATE_ENABLED)
-               __raw_writew(~hw_led_state, &fpga->leds);
-
-done:
-       local_irq_restore(flags);
-}
diff --git a/arch/arm/mach-omap1/leds-innovator.c b/arch/arm/mach-omap1/leds-innovator.c
deleted file mode 100644 (file)
index 3a066ee..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * linux/arch/arm/mach-omap1/leds-innovator.c
- */
-#include <linux/init.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-
-#include "leds.h"
-
-
-#define LED_STATE_ENABLED      1
-#define LED_STATE_CLAIMED      2
-
-static unsigned int led_state;
-static unsigned int hw_led_state;
-
-void innovator_leds_event(led_event_t evt)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-
-       switch (evt) {
-       case led_start:
-               hw_led_state = 0;
-               led_state = LED_STATE_ENABLED;
-               break;
-
-       case led_stop:
-               led_state &= ~LED_STATE_ENABLED;
-               hw_led_state = 0;
-               break;
-
-       case led_claim:
-               led_state |= LED_STATE_CLAIMED;
-               hw_led_state = 0;
-               break;
-
-       case led_release:
-               led_state &= ~LED_STATE_CLAIMED;
-               hw_led_state = 0;
-               break;
-
-#ifdef CONFIG_LEDS_TIMER
-       case led_timer:
-               if (!(led_state & LED_STATE_CLAIMED))
-                       hw_led_state ^= 0;
-               break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-       case led_idle_start:
-               if (!(led_state & LED_STATE_CLAIMED))
-                       hw_led_state |= 0;
-               break;
-
-       case led_idle_end:
-               if (!(led_state & LED_STATE_CLAIMED))
-                       hw_led_state &= ~0;
-               break;
-#endif
-
-       case led_halted:
-               break;
-
-       case led_green_on:
-               if (led_state & LED_STATE_CLAIMED)
-                       hw_led_state &= ~0;
-               break;
-
-       case led_green_off:
-               if (led_state & LED_STATE_CLAIMED)
-                       hw_led_state |= 0;
-               break;
-
-       case led_amber_on:
-               break;
-
-       case led_amber_off:
-               break;
-
-       case led_red_on:
-               if (led_state & LED_STATE_CLAIMED)
-                       hw_led_state &= ~0;
-               break;
-
-       case led_red_off:
-               if (led_state & LED_STATE_CLAIMED)
-                       hw_led_state |= 0;
-               break;
-
-       default:
-               break;
-       }
-
-       local_irq_restore(flags);
-}
diff --git a/arch/arm/mach-omap1/leds-osk.c b/arch/arm/mach-omap1/leds-osk.c
deleted file mode 100644 (file)
index 936ed42..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * linux/arch/arm/mach-omap1/leds-osk.c
- *
- * LED driver for OSK with optional Mistral QVGA board
- */
-#include <linux/gpio.h>
-#include <linux/init.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-
-#include "leds.h"
-
-
-#define LED_STATE_ENABLED      (1 << 0)
-#define LED_STATE_CLAIMED      (1 << 1)
-static u8 led_state;
-
-#define        TIMER_LED               (1 << 3)        /* Mistral board */
-#define        IDLE_LED                (1 << 4)        /* Mistral board */
-static u8 hw_led_state;
-
-
-#ifdef CONFIG_OMAP_OSK_MISTRAL
-
-/* For now, all system indicators require the Mistral board, since that
- * LED can be manipulated without a task context.  This LED is either red,
- * or green, but not both; it can't give the full "disco led" effect.
- */
-
-#define GPIO_LED_RED           3
-#define GPIO_LED_GREEN         OMAP_MPUIO(4)
-
-static void mistral_setled(void)
-{
-       int     red = 0;
-       int     green = 0;
-
-       if (hw_led_state & TIMER_LED)
-               red = 1;
-       else if (hw_led_state & IDLE_LED)
-               green = 1;
-       /* else both sides are disabled */
-
-       gpio_set_value(GPIO_LED_GREEN, green);
-       gpio_set_value(GPIO_LED_RED, red);
-}
-
-#endif
-
-void osk_leds_event(led_event_t evt)
-{
-       unsigned long   flags;
-       u16             leds;
-
-       local_irq_save(flags);
-
-       if (!(led_state & LED_STATE_ENABLED) && evt != led_start)
-               goto done;
-
-       leds = hw_led_state;
-       switch (evt) {
-       case led_start:
-               led_state |= LED_STATE_ENABLED;
-               hw_led_state = 0;
-               leds = ~0;
-               break;
-
-       case led_halted:
-       case led_stop:
-               led_state &= ~LED_STATE_ENABLED;
-               hw_led_state = 0;
-               break;
-
-       case led_claim:
-               led_state |= LED_STATE_CLAIMED;
-               hw_led_state = 0;
-               leds = ~0;
-               break;
-
-       case led_release:
-               led_state &= ~LED_STATE_CLAIMED;
-               hw_led_state = 0;
-               break;
-
-#ifdef CONFIG_OMAP_OSK_MISTRAL
-
-       case led_timer:
-               hw_led_state ^= TIMER_LED;
-               mistral_setled();
-               break;
-
-       case led_idle_start:    /* idle == off */
-               hw_led_state &= ~IDLE_LED;
-               mistral_setled();
-               break;
-
-       case led_idle_end:
-               hw_led_state |= IDLE_LED;
-               mistral_setled();
-               break;
-
-#endif /* CONFIG_OMAP_OSK_MISTRAL */
-
-       default:
-               break;
-       }
-
-       leds ^= hw_led_state;
-
-done:
-       local_irq_restore(flags);
-}
diff --git a/arch/arm/mach-omap1/leds.c b/arch/arm/mach-omap1/leds.c
deleted file mode 100644 (file)
index ae6dd93..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * linux/arch/arm/mach-omap1/leds.c
- *
- * OMAP LEDs dispatcher
- */
-#include <linux/gpio.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <asm/leds.h>
-#include <asm/mach-types.h>
-
-#include <plat/mux.h>
-
-#include "leds.h"
-
-static int __init
-omap_leds_init(void)
-{
-       if (!cpu_class_is_omap1())
-               return -ENODEV;
-
-       if (machine_is_omap_innovator())
-               leds_event = innovator_leds_event;
-
-       else if (machine_is_omap_h2()
-                       || machine_is_omap_h3()
-                       || machine_is_omap_perseus2())
-               leds_event = h2p2_dbg_leds_event;
-
-       else if (machine_is_omap_osk())
-               leds_event = osk_leds_event;
-
-       else
-               return -1;
-
-       if (machine_is_omap_h2()
-                       || machine_is_omap_h3()
-#ifdef CONFIG_OMAP_OSK_MISTRAL
-                       || machine_is_omap_osk()
-#endif
-                       ) {
-
-               /* LED1/LED2 pins can be used as GPIO (as done here), or by
-                * the LPG (works even in deep sleep!), to drive a bicolor
-                * LED on the H2 sample board, and another on the H2/P2
-                * "surfer" expansion board.
-                *
-                * The same pins drive a LED on the OSK Mistral board, but
-                * that's a different kind of LED (just one color at a time).
-                */
-               omap_cfg_reg(P18_1610_GPIO3);
-               if (gpio_request(3, "LED red") == 0)
-                       gpio_direction_output(3, 1);
-               else
-                       printk(KERN_WARNING "LED: can't get GPIO3/red?\n");
-
-               omap_cfg_reg(MPUIO4);
-               if (gpio_request(OMAP_MPUIO(4), "LED green") == 0)
-                       gpio_direction_output(OMAP_MPUIO(4), 1);
-               else
-                       printk(KERN_WARNING "LED: can't get MPUIO4/green?\n");
-       }
-
-       leds_event(led_start);
-       return 0;
-}
-
-__initcall(omap_leds_init);
diff --git a/arch/arm/mach-omap1/leds.h b/arch/arm/mach-omap1/leds.h
deleted file mode 100644 (file)
index a1e9fed..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-extern void innovator_leds_event(led_event_t evt);
-extern void h2p2_dbg_leds_event(led_event_t evt);
-extern void osk_leds_event(led_event_t evt);
index 4062480bfec7ca6baf5237d177d77d853ba029bd..4d4816fd6fc9b8d6a9931162ca66c948500c23ea 100644 (file)
@@ -44,7 +44,6 @@
 #include <linux/clockchips.h>
 #include <linux/io.h>
 
-#include <asm/leds.h>
 #include <asm/irq.h>
 #include <asm/sched_clock.h>
 
index eae49c3980c9b22695af9a4e7e3c8db06da460ca..74529549130cbafd05997bba066dd537c3632d77 100644 (file)
@@ -46,7 +46,6 @@
 #include <linux/clockchips.h>
 #include <linux/io.h>
 
-#include <asm/leds.h>
 #include <asm/irq.h>
 #include <asm/mach/irq.h>
 #include <asm/mach/time.h>
index dd2db025f7787e590d94bb229cb143559f9a8317..4a4d058ed146d39e50353ea7c7cea114660a7c91 100644 (file)
@@ -69,6 +69,7 @@ config SOC_OMAP5
        select CPU_V7
        select ARM_GIC
        select HAVE_SMP
+       select ARM_CPU_SUSPEND if PM
 
 comment "OMAP Core Type"
        depends on ARCH_OMAP2
index 74915295482ec849e0d0fefe5fc9a22703ee1f2c..28214483aaba24420e96fde47cf5ce91482a0d29 100644 (file)
@@ -554,6 +554,8 @@ static const struct usbhs_omap_board_data igep3_usbhs_bdata __initconst = {
 
 #ifdef CONFIG_OMAP_MUX
 static struct omap_board_mux board_mux[] __initdata = {
+       /* SMSC9221 LAN Controller ETH IRQ (GPIO_176) */
+       OMAP3_MUX(MCSPI1_CS2, OMAP_MUX_MODE4 | OMAP_PIN_INPUT),
        { .reg_offset = OMAP_MUX_TERMINATOR },
 };
 #endif
index ef230a0eb5eb13e5cedde6f0a6c540f6a348eae6..0d362e9f9cb9a9854c32b378c5dd058f2f785327 100644 (file)
@@ -58,6 +58,7 @@
 #include "hsmmc.h"
 #include "common-board-devices.h"
 
+#define OMAP3_EVM_TS_GPIO      175
 #define OMAP3_EVM_EHCI_VBUS    22
 #define OMAP3_EVM_EHCI_SELECT  61
 
index 14734746457c2bd8bdfcabd1ea4681dc4edab36e..c1875862679fc7092044644bf83e6948ecdbe4c8 100644 (file)
@@ -35,16 +35,6 @@ static struct omap2_mcspi_device_config ads7846_mcspi_config = {
        .turbo_mode     = 0,
 };
 
-/*
- * ADS7846 driver maybe request a gpio according to the value
- * of pdata->get_pendown_state, but we have done this. So set
- * get_pendown_state to avoid twice gpio requesting.
- */
-static int omap3_get_pendown_state(void)
-{
-       return !gpio_get_value(OMAP3_EVM_TS_GPIO);
-}
-
 static struct ads7846_platform_data ads7846_config = {
        .x_max                  = 0x0fff,
        .y_max                  = 0x0fff,
@@ -55,7 +45,6 @@ static struct ads7846_platform_data ads7846_config = {
        .debounce_rep           = 1,
        .gpio_pendown           = -EINVAL,
        .keep_vref_on           = 1,
-       .get_pendown_state      = &omap3_get_pendown_state,
 };
 
 static struct spi_board_info ads7846_spi_board_info __initdata = {
index 4c4ef6a6166ba28b768ee46580b7f35dbafb7885..a0b4a42836ab9f7a29f1757ee410e37a237af00c 100644 (file)
@@ -4,7 +4,6 @@
 #include "twl-common.h"
 
 #define NAND_BLOCK_SIZE        SZ_128K
-#define OMAP3_EVM_TS_GPIO      175
 
 struct mtd_partition;
 struct ads7846_platform_data;
index c00c68961bb848d16a68802003a4ee6402cf4710..02b9478b786f0b1e42c886a7196b3b3e5fd441cb 100644 (file)
@@ -23,7 +23,6 @@
 #include <mach/irqs.h>
 #include <asm/mach-types.h>
 #include <asm/mach/map.h>
-#include <asm/pmu.h>
 
 #include "iomap.h"
 #include <plat/board.h>
@@ -448,7 +447,7 @@ static struct resource omap3_pmu_resource = {
 
 static struct platform_device omap_pmu_device = {
        .name           = "arm-pmu",
-       .id             = ARM_PMU_DEVICE_CPU,
+       .id             = -1,
        .num_resources  = 1,
 };
 
index 471e62a74a166fb64a7486670a54854239cfb3b6..76f9b3c2f586c577668d7f923f0aabff7bbd53a3 100644 (file)
@@ -127,7 +127,6 @@ struct omap_mux_partition {
  * @gpio:      GPIO number
  * @muxnames:  available signal modes for a ball
  * @balls:     available balls on the package
- * @partition: mux partition
  */
 struct omap_mux {
        u16     reg_offset;
index 2293ba27101b96fae1f387d5b366c5d77181f99b..c95415da23c275b184d2817372a990a371ddaf0c 100644 (file)
@@ -94,7 +94,7 @@ int __init omap4_opp_init(void)
 {
        int r = -ENODEV;
 
-       if (!cpu_is_omap44xx())
+       if (!cpu_is_omap443x())
                return r;
 
        r = omap_init_opp_table(omap44xx_opp_def_list,
index e4fc88c65dbd6a868b6dac07229de3ee3b7791ea..05bd8f02723f2966bfc559ae30b9c33feee9feb3 100644 (file)
@@ -272,21 +272,16 @@ void omap_sram_idle(void)
        per_next_state = pwrdm_read_next_pwrst(per_pwrdm);
        core_next_state = pwrdm_read_next_pwrst(core_pwrdm);
 
-       if (mpu_next_state < PWRDM_POWER_ON) {
-               pwrdm_pre_transition(mpu_pwrdm);
-               pwrdm_pre_transition(neon_pwrdm);
-       }
+       pwrdm_pre_transition(NULL);
 
        /* PER */
        if (per_next_state < PWRDM_POWER_ON) {
-               pwrdm_pre_transition(per_pwrdm);
                per_going_off = (per_next_state == PWRDM_POWER_OFF) ? 1 : 0;
                omap2_gpio_prepare_for_idle(per_going_off);
        }
 
        /* CORE */
        if (core_next_state < PWRDM_POWER_ON) {
-               pwrdm_pre_transition(core_pwrdm);
                if (core_next_state == PWRDM_POWER_OFF) {
                        omap3_core_save_context();
                        omap3_cm_save_context();
@@ -339,20 +334,14 @@ void omap_sram_idle(void)
                        omap2_prm_clear_mod_reg_bits(OMAP3430_AUTO_OFF_MASK,
                                               OMAP3430_GR_MOD,
                                               OMAP3_PRM_VOLTCTRL_OFFSET);
-               pwrdm_post_transition(core_pwrdm);
        }
        omap3_intc_resume_idle();
 
+       pwrdm_post_transition(NULL);
+
        /* PER */
-       if (per_next_state < PWRDM_POWER_ON) {
+       if (per_next_state < PWRDM_POWER_ON)
                omap2_gpio_resume_after_idle();
-               pwrdm_post_transition(per_pwrdm);
-       }
-
-       if (mpu_next_state < PWRDM_POWER_ON) {
-               pwrdm_post_transition(mpu_pwrdm);
-               pwrdm_post_transition(neon_pwrdm);
-       }
 }
 
 static void omap3_pm_idle(void)
index c1b93c752d7013307b982422f0d871472a3d3eb0..25d53b2800c1df2302ac345a58e1d79715d63957 100644 (file)
@@ -304,6 +304,9 @@ void __init omap_serial_init_port(struct omap_board_data *bdata,
        omap_up.dma_rx_timeout = info->dma_rx_timeout;
        omap_up.dma_rx_poll_rate = info->dma_rx_poll_rate;
        omap_up.autosuspend_timeout = info->autosuspend_timeout;
+       omap_up.DTR_gpio = info->DTR_gpio;
+       omap_up.DTR_inverted = info->DTR_inverted;
+       omap_up.DTR_present = info->DTR_present;
 
        pdata = &omap_up;
        pdata_size = sizeof(struct omap_uart_port_info);
index 9f6b83d1b193348a7af9e628cff41956c8684898..91e71d8f46f0aa731c9678e88423490aa1192cf9 100644 (file)
@@ -56,9 +56,13 @@ ppa_por_params:
  * The restore function pointer is stored at CPUx_WAKEUP_NS_PA_ADDR_OFFSET.
  * It returns to the caller for CPU INACTIVE and ON power states or in case
  * CPU failed to transition to targeted OFF/DORMANT state.
+ *
+ * omap4_finish_suspend() calls v7_flush_dcache_all() which doesn't save
+ * stack frame and it expects the caller to take care of it. Hence the entire
+ * stack frame is saved to avoid possible stack corruption.
  */
 ENTRY(omap4_finish_suspend)
-       stmfd   sp!, {lr}
+       stmfd   sp!, {r4-r12, lr}
        cmp     r0, #0x0
        beq     do_WFI                          @ No lowpower state, jump to WFI
 
@@ -226,7 +230,7 @@ scu_gp_clear:
 skip_scu_gp_clear:
        isb
        dsb
-       ldmfd   sp!, {pc}
+       ldmfd   sp!, {r4-r12, pc}
 ENDPROC(omap4_finish_suspend)
 
 /*
index de47f170ba50abf2506c363838d7cd82c70109ee..db5ff664237517562766ffdbc34887c6416c272f 100644 (file)
@@ -67,6 +67,7 @@ void __init omap_pmic_init(int bus, u32 clkrate,
                           const char *pmic_type, int pmic_irq,
                           struct twl4030_platform_data *pmic_data)
 {
+       omap_mux_init_signal("sys_nirq", OMAP_PIN_INPUT_PULLUP | OMAP_PIN_OFF_WAKEUPENABLE);
        strncpy(pmic_i2c_board_info.type, pmic_type,
                sizeof(pmic_i2c_board_info.type));
        pmic_i2c_board_info.irq = pmic_irq;
index 9148b229d0de925b4f95fea5154421fa462331ba..87a6cdabcad532bea28c09c5d9785e340d25460f 100644 (file)
@@ -46,16 +46,6 @@ static struct map_desc orion5x_io_desc[] __initdata = {
                .pfn            = __phys_to_pfn(ORION5X_REGS_PHYS_BASE),
                .length         = ORION5X_REGS_SIZE,
                .type           = MT_DEVICE,
-       }, {
-               .virtual        = ORION5X_PCIE_IO_VIRT_BASE,
-               .pfn            = __phys_to_pfn(ORION5X_PCIE_IO_PHYS_BASE),
-               .length         = ORION5X_PCIE_IO_SIZE,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = ORION5X_PCI_IO_VIRT_BASE,
-               .pfn            = __phys_to_pfn(ORION5X_PCI_IO_PHYS_BASE),
-               .length         = ORION5X_PCI_IO_SIZE,
-               .type           = MT_DEVICE,
        }, {
                .virtual        = ORION5X_PCIE_WA_VIRT_BASE,
                .pfn            = __phys_to_pfn(ORION5X_PCIE_WA_PHYS_BASE),
@@ -109,7 +99,8 @@ void __init orion5x_eth_init(struct mv643xx_eth_platform_data *eth_data)
 {
        orion_ge00_init(eth_data,
                        ORION5X_ETH_PHYS_BASE, IRQ_ORION5X_ETH_SUM,
-                       IRQ_ORION5X_ETH_ERR);
+                       IRQ_ORION5X_ETH_ERR,
+                       MV643XX_TX_CSUM_DEFAULT_LIMIT);
 }
 
 
diff --git a/arch/arm/mach-orion5x/include/mach/io.h b/arch/arm/mach-orion5x/include/mach/io.h
deleted file mode 100644 (file)
index 1aa5d0a..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * arch/arm/mach-orion5x/include/mach/io.h
- *
- * 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.
- */
-
-#ifndef __ASM_ARCH_IO_H
-#define __ASM_ARCH_IO_H
-
-#include <mach/orion5x.h>
-#include <asm/sizes.h>
-
-#define IO_SPACE_LIMIT         SZ_2M
-static inline void __iomem *__io(unsigned long addr)
-{
-       return (void __iomem *)(addr + ORION5X_PCIE_IO_VIRT_BASE);
-}
-
-#define __io(a)                         __io(a)
-#endif
index 683e085ce1624088f7ec138c1c4fa14c636a2ddd..1b60131b7f60828088b45e55de057d5ce6d13e2b 100644 (file)
  * fc000000    device bus mappings (cs0/cs1)
  *
  * virt                phys            size
- * fdd00000    f1000000        1M      on-chip peripheral registers
- * fde00000    f2000000        1M      PCIe I/O space
- * fdf00000    f2100000        1M      PCI I/O space
- * fe000000    f0000000        16M     PCIe WA space (Orion-1/Orion-NAS only)
+ * fe000000    f1000000        1M      on-chip peripheral registers
+ * fee00000    f2000000        64K     PCIe I/O space
+ * fee10000    f2100000        64K     PCI I/O space
+ * fd000000    f0000000        16M     PCIe WA space (Orion-1/Orion-NAS only)
  ****************************************************************************/
 #define ORION5X_REGS_PHYS_BASE         0xf1000000
-#define ORION5X_REGS_VIRT_BASE         0xfdd00000
+#define ORION5X_REGS_VIRT_BASE         0xfe000000
 #define ORION5X_REGS_SIZE              SZ_1M
 
 #define ORION5X_PCIE_IO_PHYS_BASE      0xf2000000
-#define ORION5X_PCIE_IO_VIRT_BASE      0xfde00000
 #define ORION5X_PCIE_IO_BUS_BASE       0x00000000
-#define ORION5X_PCIE_IO_SIZE           SZ_1M
+#define ORION5X_PCIE_IO_SIZE           SZ_64K
 
 #define ORION5X_PCI_IO_PHYS_BASE       0xf2100000
-#define ORION5X_PCI_IO_VIRT_BASE       0xfdf00000
-#define ORION5X_PCI_IO_BUS_BASE                0x00100000
-#define ORION5X_PCI_IO_SIZE            SZ_1M
+#define ORION5X_PCI_IO_BUS_BASE                0x00010000
+#define ORION5X_PCI_IO_SIZE            SZ_64K
 
 #define ORION5X_SRAM_PHYS_BASE         (0xf2200000)
 #define ORION5X_SRAM_SIZE              SZ_8K
 
 /* Relevant only for Orion-1/Orion-NAS */
 #define ORION5X_PCIE_WA_PHYS_BASE      0xf0000000
-#define ORION5X_PCIE_WA_VIRT_BASE      0xfe000000
+#define ORION5X_PCIE_WA_VIRT_BASE      0xfd000000
 #define ORION5X_PCIE_WA_SIZE           SZ_16M
 
 #define ORION5X_PCIE_MEM_PHYS_BASE     0xe0000000
index cb19e1661bb3dbabdde57626f0074d012e8440db..6921d49b988d3152f36295815611ab711cdc57a3 100644 (file)
@@ -162,35 +162,25 @@ static int __init pcie_setup(struct pci_sys_data *sys)
                pcie_ops.read = pcie_rd_conf_wa;
        }
 
+       pci_ioremap_io(sys->busnr * SZ_64K, ORION5X_PCIE_IO_PHYS_BASE);
+
        /*
         * Request resources.
         */
-       res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL);
+       res = kzalloc(sizeof(struct resource), GFP_KERNEL);
        if (!res)
                panic("pcie_setup unable to alloc resources");
 
-       /*
-        * IORESOURCE_IO
-        */
-       sys->io_offset = 0;
-       res[0].name = "PCIe I/O Space";
-       res[0].flags = IORESOURCE_IO;
-       res[0].start = ORION5X_PCIE_IO_BUS_BASE;
-       res[0].end = res[0].start + ORION5X_PCIE_IO_SIZE - 1;
-       if (request_resource(&ioport_resource, &res[0]))
-               panic("Request PCIe IO resource failed\n");
-       pci_add_resource_offset(&sys->resources, &res[0], sys->io_offset);
-
        /*
         * IORESOURCE_MEM
         */
-       res[1].name = "PCIe Memory Space";
-       res[1].flags = IORESOURCE_MEM;
-       res[1].start = ORION5X_PCIE_MEM_PHYS_BASE;
-       res[1].end = res[1].start + ORION5X_PCIE_MEM_SIZE - 1;
-       if (request_resource(&iomem_resource, &res[1]))
+       res->name = "PCIe Memory Space";
+       res->flags = IORESOURCE_MEM;
+       res->start = ORION5X_PCIE_MEM_PHYS_BASE;
+       res->end = res->start + ORION5X_PCIE_MEM_SIZE - 1;
+       if (request_resource(&iomem_resource, res))
                panic("Request PCIe Memory resource failed\n");
-       pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
+       pci_add_resource_offset(&sys->resources, res, sys->mem_offset);
 
        return 1;
 }
@@ -489,35 +479,25 @@ static int __init pci_setup(struct pci_sys_data *sys)
         */
        orion5x_setbits(PCI_CMD, PCI_CMD_HOST_REORDER);
 
+       pci_ioremap_io(sys->busnr * SZ_64K, ORION5X_PCI_IO_PHYS_BASE);
+
        /*
         * Request resources
         */
-       res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL);
+       res = kzalloc(sizeof(struct resource), GFP_KERNEL);
        if (!res)
                panic("pci_setup unable to alloc resources");
 
-       /*
-        * IORESOURCE_IO
-        */
-       sys->io_offset = 0;
-       res[0].name = "PCI I/O Space";
-       res[0].flags = IORESOURCE_IO;
-       res[0].start = ORION5X_PCI_IO_BUS_BASE;
-       res[0].end = res[0].start + ORION5X_PCI_IO_SIZE - 1;
-       if (request_resource(&ioport_resource, &res[0]))
-               panic("Request PCI IO resource failed\n");
-       pci_add_resource_offset(&sys->resources, &res[0], sys->io_offset);
-
        /*
         * IORESOURCE_MEM
         */
-       res[1].name = "PCI Memory Space";
-       res[1].flags = IORESOURCE_MEM;
-       res[1].start = ORION5X_PCI_MEM_PHYS_BASE;
-       res[1].end = res[1].start + ORION5X_PCI_MEM_SIZE - 1;
-       if (request_resource(&iomem_resource, &res[1]))
+       res->name = "PCI Memory Space";
+       res->flags = IORESOURCE_MEM;
+       res->start = ORION5X_PCI_MEM_PHYS_BASE;
+       res->end = res->start + ORION5X_PCI_MEM_SIZE - 1;
+       if (request_resource(&iomem_resource, res))
                panic("Request PCI Memory resource failed\n");
-       pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
+       pci_add_resource_offset(&sys->resources, res, sys->mem_offset);
 
        return 1;
 }
index 78a6a11d82168df2fad570a5898feefec0129a45..9b1c95310291e74896e9de9793006aa2ee181dcb 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/ethtool.h>
 #include <net/dsa.h>
 #include <asm/mach-types.h>
-#include <asm/leds.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/pci.h>
 #include <mach/orion5x.h>
index 2f5dc54cd4cd20dc3ad5eb8d747c1457b8494c4f..51ba2b81a10b7fe096f8467cdb83ec56d3682634 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/i2c.h>
 #include <net/dsa.h>
 #include <asm/mach-types.h>
-#include <asm/leds.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/pci.h>
 #include <mach/orion5x.h>
index 399130fac0b611cf50e6948d6990b56cc8297fe8..0a56b9444f1bc6b3a33f0a316bf112250f5141d5 100644 (file)
@@ -19,8 +19,8 @@
 #include <linux/mv643xx_eth.h>
 #include <linux/ata_platform.h>
 #include <linux/i2c.h>
+#include <linux/leds.h>
 #include <asm/mach-types.h>
-#include <asm/leds.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/pci.h>
 #include <mach/orion5x.h>
 #define RD88F5182_PCI_SLOT0_IRQ_A_PIN  7
 #define RD88F5182_PCI_SLOT0_IRQ_B_PIN  6
 
-/*
- * GPIO Debug LED
- */
-
-#define RD88F5182_GPIO_DBG_LED         0
-
 /*****************************************************************************
  * 16M NOR Flash on Device bus CS1
  ****************************************************************************/
@@ -83,55 +77,32 @@ static struct platform_device rd88f5182_nor_flash = {
        .resource               = &rd88f5182_nor_flash_resource,
 };
 
-#ifdef CONFIG_LEDS
-
 /*****************************************************************************
- * Use GPIO debug led as CPU active indication
+ * Use GPIO LED as CPU active indication
  ****************************************************************************/
 
-static void rd88f5182_dbgled_event(led_event_t evt)
-{
-       int val;
-
-       if (evt == led_idle_end)
-               val = 1;
-       else if (evt == led_idle_start)
-               val = 0;
-       else
-               return;
-
-       gpio_set_value(RD88F5182_GPIO_DBG_LED, val);
-}
-
-static int __init rd88f5182_dbgled_init(void)
-{
-       int pin;
-
-       if (machine_is_rd88f5182()) {
-               pin = RD88F5182_GPIO_DBG_LED;
+#define RD88F5182_GPIO_LED             0
 
-               if (gpio_request(pin, "DBGLED") == 0) {
-                       if (gpio_direction_output(pin, 0) != 0) {
-                               printk(KERN_ERR "rd88f5182_dbgled_init failed "
-                                               "to set output pin %d\n", pin);
-                               gpio_free(pin);
-                               return 0;
-                       }
-               } else {
-                       printk(KERN_ERR "rd88f5182_dbgled_init failed "
-                                       "to request gpio %d\n", pin);
-                       return 0;
-               }
-
-               leds_event = rd88f5182_dbgled_event;
-       }
-
-       return 0;
-}
+static struct gpio_led rd88f5182_gpio_led_pins[] = {
+       {
+               .name           = "rd88f5182:cpu",
+               .default_trigger = "cpu0",
+               .gpio           = RD88F5182_GPIO_LED,
+       },
+};
 
-__initcall(rd88f5182_dbgled_init);
+static struct gpio_led_platform_data rd88f5182_gpio_led_data = {
+       .leds           = rd88f5182_gpio_led_pins,
+       .num_leds       = ARRAY_SIZE(rd88f5182_gpio_led_pins),
+};
 
-#endif
+static struct platform_device rd88f5182_gpio_leds = {
+       .name   = "leds-gpio",
+       .id     = -1,
+       .dev    = {
+               .platform_data = &rd88f5182_gpio_led_data,
+       },
+};
 
 /*****************************************************************************
  * PCI
@@ -298,6 +269,7 @@ static void __init rd88f5182_init(void)
 
        orion5x_setup_dev1_win(RD88F5182_NOR_BASE, RD88F5182_NOR_SIZE);
        platform_device_register(&rd88f5182_nor_flash);
+       platform_device_register(&rd88f5182_gpio_leds);
 
        i2c_register_board_info(0, &rd88f5182_i2c_rtc, 1);
 }
index 92df49c1b62ad4c75cc510034411dc5722b1c34c..ed50910b08a42747aeeca5ca4b6b24acd7510e0b 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/ethtool.h>
 #include <net/dsa.h>
 #include <asm/mach-types.h>
-#include <asm/leds.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/pci.h>
 #include <mach/orion5x.h>
index 0cfe8af3d3be07b9bc29433e3f990b863487c973..47a7ae96156acbcc9f8ed4ff546a361d1e8b37fa 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/io.h>
 
 #include <mach/hardware.h>
-#include <asm/leds.h>
 #include <asm/mach/time.h>
 #include <asm/errno.h>
 
index fe2d1f80ef50ff340d63542e045e49295716cec9..8e6288de69b9d64c6532d5a48d8fa78b8713a485 100644 (file)
@@ -25,6 +25,18 @@ config PXA_V7_MACH_AUTO
 if !ARCH_PXA_V7
 comment "Intel/Marvell Dev Platforms (sorted by hardware release time)"
 
+config MACH_PXA3XX_DT
+       bool "Support PXA3xx platforms from device tree"
+       select PXA3xx
+       select CPU_PXA300
+       select POWER_SUPPLY
+       select HAVE_PWM
+       select USE_OF
+       help
+         Include support for Marvell PXA3xx based platforms using
+         the device tree. Needn't select any other machine while
+         MACH_PXA3XX_DT is enabled.
+
 config ARCH_LUBBOCK
        bool "Intel DBPXA250 Development Platform (aka Lubbock)"
        select PXA25x
index be0f7df8685c8487ec9b49677056cb21e0613933..ee88d6eae6485d71346324b133b68b093dfa0dcf 100644 (file)
@@ -26,6 +26,9 @@ obj-$(CONFIG_CPU_PXA930)      += pxa930.o
 
 # NOTE: keep the order of boards in accordance to their order in Kconfig
 
+# Device Tree support
+obj-$(CONFIG_MACH_PXA3XX_DT)   += pxa-dt.o
+
 # Intel/Marvell Dev Platforms
 obj-$(CONFIG_ARCH_LUBBOCK)     += lubbock.o
 obj-$(CONFIG_MACH_MAINSTONE)   += mainstone.o
@@ -95,12 +98,4 @@ obj-$(CONFIG_MACH_RAUMFELD_CONNECTOR)        += raumfeld.o
 obj-$(CONFIG_MACH_RAUMFELD_SPEAKER)    += raumfeld.o
 obj-$(CONFIG_MACH_ZIPIT2)      += z2.o
 
-# Support for blinky lights
-led-y := leds.o
-led-$(CONFIG_ARCH_LUBBOCK)     += leds-lubbock.o
-led-$(CONFIG_MACH_MAINSTONE)   += leds-mainstone.o
-led-$(CONFIG_ARCH_PXA_IDP)     += leds-idp.o
-
-obj-$(CONFIG_LEDS)             += $(led-y)
-
 obj-$(CONFIG_TOSA_BT)          += tosa-bt.o
index 2a37a9a8f62188cafffbe6289130129d1bfc9c9e..d4e9499832dc90bcfd17fce61eaee4b9a8cd31fb 100644 (file)
@@ -127,8 +127,10 @@ void clk_pxa3xx_cken_enable(struct clk *clk)
 
        if (clk->cken < 32)
                CKENA |= mask;
-       else
+       else if (clk->cken < 64)
                CKENB |= mask;
+       else
+               CKENC |= mask;
 }
 
 void clk_pxa3xx_cken_disable(struct clk *clk)
@@ -137,8 +139,10 @@ void clk_pxa3xx_cken_disable(struct clk *clk)
 
        if (clk->cken < 32)
                CKENA &= ~mask;
-       else
+       else if (clk->cken < 64)
                CKENB &= ~mask;
+       else
+               CKENC &= ~mask;
 }
 
 const struct clkops clk_pxa3xx_cken_ops = {
index 166eee5b8a70fe8f4bc555543ea8027564ee0392..c1f3b1279d97bc588ba7d9a44d18b45cc63cde80 100644 (file)
@@ -6,7 +6,6 @@
 #include <linux/spi/pxa2xx_spi.h>
 #include <linux/i2c/pxa-i2c.h>
 
-#include <asm/pmu.h>
 #include <mach/udc.h>
 #include <mach/pxa3xx-u2d.h>
 #include <mach/pxafb.h>
@@ -42,7 +41,7 @@ static struct resource pxa_resource_pmu = {
 
 struct platform_device pxa_device_pmu = {
        .name           = "arm-pmu",
-       .id             = ARM_PMU_DEVICE_CPU,
+       .id             = -1,
        .resource       = &pxa_resource_pmu,
        .num_resources  = 1,
 };
index 6ff466bd43e8840b76bc71b6f1bcebc97d2092bb..ae1e9977603ee48aaa4cd61b70ccea71b66a3553 100644 (file)
@@ -191,6 +191,87 @@ static void __init idp_map_io(void)
        iotable_init(idp_io_desc, ARRAY_SIZE(idp_io_desc));
 }
 
+/* LEDs */
+#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
+struct idp_led {
+       struct led_classdev     cdev;
+       u8                      mask;
+};
+
+/*
+ * The triggers lines up below will only be used if the
+ * LED triggers are compiled in.
+ */
+static const struct {
+       const char *name;
+       const char *trigger;
+} idp_leds[] = {
+       { "idp:green", "heartbeat", },
+       { "idp:red", "cpu0", },
+};
+
+static void idp_led_set(struct led_classdev *cdev,
+               enum led_brightness b)
+{
+       struct idp_led *led = container_of(cdev,
+                       struct idp_led, cdev);
+       u32 reg = IDP_CPLD_LED_CONTROL;
+
+       if (b != LED_OFF)
+               reg &= ~led->mask;
+       else
+               reg |= led->mask;
+
+       IDP_CPLD_LED_CONTROL = reg;
+}
+
+static enum led_brightness idp_led_get(struct led_classdev *cdev)
+{
+       struct idp_led *led = container_of(cdev,
+                       struct idp_led, cdev);
+
+       return (IDP_CPLD_LED_CONTROL & led->mask) ? LED_OFF : LED_FULL;
+}
+
+static int __init idp_leds_init(void)
+{
+       int i;
+
+       if (!machine_is_pxa_idp())
+               return -ENODEV;
+
+       for (i = 0; i < ARRAY_SIZE(idp_leds); i++) {
+               struct idp_led *led;
+
+               led = kzalloc(sizeof(*led), GFP_KERNEL);
+               if (!led)
+                       break;
+
+               led->cdev.name = idp_leds[i].name;
+               led->cdev.brightness_set = idp_led_set;
+               led->cdev.brightness_get = idp_led_get;
+               led->cdev.default_trigger = idp_leds[i].trigger;
+
+               if (i == 0)
+                       led->mask = IDP_HB_LED;
+               else
+                       led->mask = IDP_BUSY_LED;
+
+               if (led_classdev_register(NULL, &led->cdev) < 0) {
+                       kfree(led);
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * Since we may have triggers on any subsystem, defer registration
+ * until after subsystem_init.
+ */
+fs_initcall(idp_leds_init);
+#endif
 
 MACHINE_START(PXA_IDP, "Vibren PXA255 IDP")
        /* Maintainer: Vibren Technologies */
index 5dae15ea67184a5c1b60db8c5c3fd2e62f168961..b6cc1816463e57570622b2fbd59f0092647cb980 100644 (file)
@@ -17,6 +17,8 @@
 #include <linux/syscore_ops.h>
 #include <linux/io.h>
 #include <linux/irq.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
 
 #include <asm/exception.h>
 
@@ -25,8 +27,6 @@
 
 #include "generic.h"
 
-#define IRQ_BASE               io_p2v(0x40d00000)
-
 #define ICIP                   (0x000)
 #define ICMR                   (0x004)
 #define ICLR                   (0x008)
  * This is for peripheral IRQs internal to the PXA chip.
  */
 
+static void __iomem *pxa_irq_base;
 static int pxa_internal_irq_nr;
-
-static inline int cpu_has_ipr(void)
-{
-       return !cpu_is_pxa25x();
-}
+static bool cpu_has_ipr;
 
 static inline void __iomem *irq_base(int i)
 {
-       static unsigned long phys_base[] = {
-               0x40d00000,
-               0x40d0009c,
-               0x40d00130,
+       static unsigned long phys_base_offset[] = {
+               0x0,
+               0x9c,
+               0x130,
        };
 
-       return io_p2v(phys_base[i]);
+       return pxa_irq_base + phys_base_offset[i];
 }
 
 void pxa_mask_irq(struct irq_data *d)
@@ -96,8 +93,8 @@ asmlinkage void __exception_irq_entry icip_handle_irq(struct pt_regs *regs)
        uint32_t icip, icmr, mask;
 
        do {
-               icip = __raw_readl(IRQ_BASE + ICIP);
-               icmr = __raw_readl(IRQ_BASE + ICMR);
+               icip = __raw_readl(pxa_irq_base + ICIP);
+               icmr = __raw_readl(pxa_irq_base + ICMR);
                mask = icip & icmr;
 
                if (mask == 0)
@@ -128,6 +125,8 @@ void __init pxa_init_irq(int irq_nr, int (*fn)(struct irq_data *, unsigned int))
        BUG_ON(irq_nr > MAX_INTERNAL_IRQS);
 
        pxa_internal_irq_nr = irq_nr;
+       cpu_has_ipr = !cpu_is_pxa25x();
+       pxa_irq_base = io_p2v(0x40d00000);
 
        for (n = 0; n < irq_nr; n += 32) {
                void __iomem *base = irq_base(n >> 5);
@@ -136,8 +135,8 @@ void __init pxa_init_irq(int irq_nr, int (*fn)(struct irq_data *, unsigned int))
                __raw_writel(0, base + ICLR);   /* all IRQs are IRQ, not FIQ */
                for (i = n; (i < (n + 32)) && (i < irq_nr); i++) {
                        /* initialize interrupt priority */
-                       if (cpu_has_ipr())
-                               __raw_writel(i | IPR_VALID, IRQ_BASE + IPR(i));
+                       if (cpu_has_ipr)
+                               __raw_writel(i | IPR_VALID, pxa_irq_base + IPR(i));
 
                        irq = PXA_IRQ(i);
                        irq_set_chip_and_handler(irq, &pxa_internal_irq_chip,
@@ -168,9 +167,9 @@ static int pxa_irq_suspend(void)
                __raw_writel(0, base + ICMR);
        }
 
-       if (cpu_has_ipr()) {
+       if (cpu_has_ipr) {
                for (i = 0; i < pxa_internal_irq_nr; i++)
-                       saved_ipr[i] = __raw_readl(IRQ_BASE + IPR(i));
+                       saved_ipr[i] = __raw_readl(pxa_irq_base + IPR(i));
        }
 
        return 0;
@@ -187,11 +186,11 @@ static void pxa_irq_resume(void)
                __raw_writel(0, base + ICLR);
        }
 
-       if (cpu_has_ipr())
+       if (cpu_has_ipr)
                for (i = 0; i < pxa_internal_irq_nr; i++)
-                       __raw_writel(saved_ipr[i], IRQ_BASE + IPR(i));
+                       __raw_writel(saved_ipr[i], pxa_irq_base + IPR(i));
 
-       __raw_writel(1, IRQ_BASE + ICCR);
+       __raw_writel(1, pxa_irq_base + ICCR);
 }
 #else
 #define pxa_irq_suspend                NULL
@@ -202,3 +201,93 @@ struct syscore_ops pxa_irq_syscore_ops = {
        .suspend        = pxa_irq_suspend,
        .resume         = pxa_irq_resume,
 };
+
+#ifdef CONFIG_OF
+static struct irq_domain *pxa_irq_domain;
+
+static int pxa_irq_map(struct irq_domain *h, unsigned int virq,
+                      irq_hw_number_t hw)
+{
+       void __iomem *base = irq_base(hw / 32);
+
+       /* initialize interrupt priority */
+       if (cpu_has_ipr)
+               __raw_writel(hw | IPR_VALID, pxa_irq_base + IPR(hw));
+
+       irq_set_chip_and_handler(hw, &pxa_internal_irq_chip,
+                                handle_level_irq);
+       irq_set_chip_data(hw, base);
+       set_irq_flags(hw, IRQF_VALID);
+
+       return 0;
+}
+
+static struct irq_domain_ops pxa_irq_ops = {
+       .map    = pxa_irq_map,
+       .xlate  = irq_domain_xlate_onecell,
+};
+
+static const struct of_device_id intc_ids[] __initconst = {
+       { .compatible = "marvell,pxa-intc", },
+       {}
+};
+
+void __init pxa_dt_irq_init(int (*fn)(struct irq_data *, unsigned int))
+{
+       struct device_node *node;
+       const struct of_device_id *of_id;
+       struct pxa_intc_conf *conf;
+       struct resource res;
+       int n, ret;
+
+       node = of_find_matching_node(NULL, intc_ids);
+       if (!node) {
+               pr_err("Failed to find interrupt controller in arch-pxa\n");
+               return;
+       }
+       of_id = of_match_node(intc_ids, node);
+       conf = of_id->data;
+
+       ret = of_property_read_u32(node, "marvell,intc-nr-irqs",
+                                  &pxa_internal_irq_nr);
+       if (ret) {
+               pr_err("Not found marvell,intc-nr-irqs property\n");
+               return;
+       }
+
+       ret = of_address_to_resource(node, 0, &res);
+       if (ret < 0) {
+               pr_err("No registers defined for node\n");
+               return;
+       }
+       pxa_irq_base = io_p2v(res.start);
+
+       if (of_find_property(node, "marvell,intc-priority", NULL))
+               cpu_has_ipr = 1;
+
+       ret = irq_alloc_descs(-1, 0, pxa_internal_irq_nr, 0);
+       if (ret < 0) {
+               pr_err("Failed to allocate IRQ numbers\n");
+               return;
+       }
+
+       pxa_irq_domain = irq_domain_add_legacy(node, pxa_internal_irq_nr, 0, 0,
+                                              &pxa_irq_ops, NULL);
+       if (!pxa_irq_domain)
+               panic("Unable to add PXA IRQ domain\n");
+
+       irq_set_default_host(pxa_irq_domain);
+
+       for (n = 0; n < pxa_internal_irq_nr; n += 32) {
+               void __iomem *base = irq_base(n >> 5);
+
+               __raw_writel(0, base + ICMR);   /* disable all IRQs */
+               __raw_writel(0, base + ICLR);   /* all IRQs are IRQ, not FIQ */
+       }
+
+       /* only unmasked interrupts kick us out of idle */
+       __raw_writel(1, irq_base(0) + ICCR);
+
+       pxa_internal_irq_chip.irq_set_wake = fn;
+}
+#endif /* CONFIG_OF */
diff --git a/arch/arm/mach-pxa/leds-idp.c b/arch/arm/mach-pxa/leds-idp.c
deleted file mode 100644 (file)
index 06b0600..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * linux/arch/arm/mach-pxa/leds-idp.c
- *
- * Copyright (C) 2000 John Dorsey <john+@cs.cmu.edu>
- *
- * Copyright (c) 2001 Jeff Sutherland <jeffs@accelent.com>
- *
- * Original (leds-footbridge.c) by Russell King
- *
- * Macros for actual LED manipulation should be in machine specific
- * files in this 'mach' directory.
- */
-
-
-#include <linux/init.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-
-#include <mach/pxa25x.h>
-#include <mach/idp.h>
-
-#include "leds.h"
-
-#define LED_STATE_ENABLED      1
-#define LED_STATE_CLAIMED      2
-
-static unsigned int led_state;
-static unsigned int hw_led_state;
-
-void idp_leds_event(led_event_t evt)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-
-       switch (evt) {
-       case led_start:
-               hw_led_state = IDP_HB_LED | IDP_BUSY_LED;
-               led_state = LED_STATE_ENABLED;
-               break;
-
-       case led_stop:
-               led_state &= ~LED_STATE_ENABLED;
-               break;
-
-       case led_claim:
-               led_state |= LED_STATE_CLAIMED;
-               hw_led_state = IDP_HB_LED | IDP_BUSY_LED;
-               break;
-
-       case led_release:
-               led_state &= ~LED_STATE_CLAIMED;
-               hw_led_state = IDP_HB_LED | IDP_BUSY_LED;
-               break;
-
-#ifdef CONFIG_LEDS_TIMER
-       case led_timer:
-               if (!(led_state & LED_STATE_CLAIMED))
-                       hw_led_state ^= IDP_HB_LED;
-               break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-       case led_idle_start:
-               if (!(led_state & LED_STATE_CLAIMED))
-                       hw_led_state &= ~IDP_BUSY_LED;
-               break;
-
-       case led_idle_end:
-               if (!(led_state & LED_STATE_CLAIMED))
-                       hw_led_state |= IDP_BUSY_LED;
-               break;
-#endif
-
-       case led_halted:
-               break;
-
-       case led_green_on:
-               if (led_state & LED_STATE_CLAIMED)
-                       hw_led_state |= IDP_HB_LED;
-               break;
-
-       case led_green_off:
-               if (led_state & LED_STATE_CLAIMED)
-                       hw_led_state &= ~IDP_HB_LED;
-               break;
-
-       case led_amber_on:
-               break;
-
-       case led_amber_off:
-               break;
-
-       case led_red_on:
-               if (led_state & LED_STATE_CLAIMED)
-                       hw_led_state |= IDP_BUSY_LED;
-               break;
-
-       case led_red_off:
-               if (led_state & LED_STATE_CLAIMED)
-                       hw_led_state &= ~IDP_BUSY_LED;
-               break;
-
-       default:
-               break;
-       }
-
-       if  (led_state & LED_STATE_ENABLED)
-               IDP_CPLD_LED_CONTROL = ( (IDP_CPLD_LED_CONTROL | IDP_LEDS_MASK) & ~hw_led_state);
-       else
-               IDP_CPLD_LED_CONTROL |= IDP_LEDS_MASK;
-
-       local_irq_restore(flags);
-}
diff --git a/arch/arm/mach-pxa/leds-lubbock.c b/arch/arm/mach-pxa/leds-lubbock.c
deleted file mode 100644 (file)
index 0bd85c8..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * linux/arch/arm/mach-pxa/leds-lubbock.c
- *
- * Copyright (C) 2000 John Dorsey <john+@cs.cmu.edu>
- *
- * Copyright (c) 2001 Jeff Sutherland <jeffs@accelent.com>
- *
- * Original (leds-footbridge.c) by Russell King
- *
- * Major surgery on April 2004 by Nicolas Pitre for less global
- * namespace collision.  Mostly adapted the Mainstone version.
- */
-
-#include <linux/init.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-#include <mach/pxa25x.h>
-#include <mach/lubbock.h>
-
-#include "leds.h"
-
-/*
- * 8 discrete leds available for general use:
- *
- * Note: bits [15-8] are used to enable/blank the 8 7 segment hex displays
- * so be sure to not monkey with them here.
- */
-
-#define D28                    (1 << 0)
-#define D27                    (1 << 1)
-#define D26                    (1 << 2)
-#define D25                    (1 << 3)
-#define D24                    (1 << 4)
-#define D23                    (1 << 5)
-#define D22                    (1 << 6)
-#define D21                    (1 << 7)
-
-#define LED_STATE_ENABLED      1
-#define LED_STATE_CLAIMED      2
-
-static unsigned int led_state;
-static unsigned int hw_led_state;
-
-void lubbock_leds_event(led_event_t evt)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-
-       switch (evt) {
-       case led_start:
-               hw_led_state = 0;
-               led_state = LED_STATE_ENABLED;
-               break;
-
-       case led_stop:
-               led_state &= ~LED_STATE_ENABLED;
-               break;
-
-       case led_claim:
-               led_state |= LED_STATE_CLAIMED;
-               hw_led_state = 0;
-               break;
-
-       case led_release:
-               led_state &= ~LED_STATE_CLAIMED;
-               hw_led_state = 0;
-               break;
-
-#ifdef CONFIG_LEDS_TIMER
-       case led_timer:
-               hw_led_state ^= D26;
-               break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-       case led_idle_start:
-               hw_led_state &= ~D27;
-               break;
-
-       case led_idle_end:
-               hw_led_state |= D27;
-               break;
-#endif
-
-       case led_halted:
-               break;
-
-       case led_green_on:
-               hw_led_state |= D21;
-               break;
-
-       case led_green_off:
-               hw_led_state &= ~D21;
-               break;
-
-       case led_amber_on:
-               hw_led_state |= D22;
-               break;
-
-       case led_amber_off:
-               hw_led_state &= ~D22;
-               break;
-
-       case led_red_on:
-               hw_led_state |= D23;
-               break;
-
-       case led_red_off:
-               hw_led_state &= ~D23;
-               break;
-
-       default:
-               break;
-       }
-
-       if  (led_state & LED_STATE_ENABLED)
-               LUB_DISC_BLNK_LED = (LUB_DISC_BLNK_LED | 0xff) & ~hw_led_state;
-       else
-               LUB_DISC_BLNK_LED |= 0xff;
-
-       local_irq_restore(flags);
-}
diff --git a/arch/arm/mach-pxa/leds-mainstone.c b/arch/arm/mach-pxa/leds-mainstone.c
deleted file mode 100644 (file)
index 4058ab3..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * linux/arch/arm/mach-pxa/leds-mainstone.c
- *
- * Author:     Nicolas Pitre
- * Created:    Nov 05, 2002
- * Copyright:  MontaVista Software 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/init.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-
-#include <mach/pxa27x.h>
-#include <mach/mainstone.h>
-
-#include "leds.h"
-
-
-/* 8 discrete leds available for general use: */
-#define D28                    (1 << 0)
-#define D27                    (1 << 1)
-#define D26                    (1 << 2)
-#define D25                    (1 << 3)
-#define D24                    (1 << 4)
-#define D23                    (1 << 5)
-#define D22                    (1 << 6)
-#define D21                    (1 << 7)
-
-#define LED_STATE_ENABLED      1
-#define LED_STATE_CLAIMED      2
-
-static unsigned int led_state;
-static unsigned int hw_led_state;
-
-void mainstone_leds_event(led_event_t evt)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-
-       switch (evt) {
-       case led_start:
-               hw_led_state = 0;
-               led_state = LED_STATE_ENABLED;
-               break;
-
-       case led_stop:
-               led_state &= ~LED_STATE_ENABLED;
-               break;
-
-       case led_claim:
-               led_state |= LED_STATE_CLAIMED;
-               hw_led_state = 0;
-               break;
-
-       case led_release:
-               led_state &= ~LED_STATE_CLAIMED;
-               hw_led_state = 0;
-               break;
-
-#ifdef CONFIG_LEDS_TIMER
-       case led_timer:
-               hw_led_state ^= D26;
-               break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-       case led_idle_start:
-               hw_led_state &= ~D27;
-               break;
-
-       case led_idle_end:
-               hw_led_state |= D27;
-               break;
-#endif
-
-       case led_halted:
-               break;
-
-       case led_green_on:
-               hw_led_state |= D21;
-               break;
-
-       case led_green_off:
-               hw_led_state &= ~D21;
-               break;
-
-       case led_amber_on:
-               hw_led_state |= D22;
-               break;
-
-       case led_amber_off:
-               hw_led_state &= ~D22;
-               break;
-
-       case led_red_on:
-               hw_led_state |= D23;
-               break;
-
-       case led_red_off:
-               hw_led_state &= ~D23;
-               break;
-
-       default:
-               break;
-       }
-
-       if  (led_state & LED_STATE_ENABLED)
-               MST_LEDCTRL = (MST_LEDCTRL | 0xff) & ~hw_led_state;
-       else
-               MST_LEDCTRL |= 0xff;
-
-       local_irq_restore(flags);
-}
diff --git a/arch/arm/mach-pxa/leds.c b/arch/arm/mach-pxa/leds.c
deleted file mode 100644 (file)
index bbe4d5f..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * linux/arch/arm/mach-pxa/leds.c
- *
- * xscale LEDs dispatcher
- *
- * Copyright (C) 2001 Nicolas Pitre
- *
- * Copyright (c) 2001 Jeff Sutherland, Accelent Systems Inc.
- */
-#include <linux/compiler.h>
-#include <linux/init.h>
-
-#include <asm/leds.h>
-#include <asm/mach-types.h>
-
-#include "leds.h"
-
-static int __init
-pxa_leds_init(void)
-{
-       if (machine_is_lubbock())
-               leds_event = lubbock_leds_event;
-       if (machine_is_mainstone())
-               leds_event = mainstone_leds_event;
-       if (machine_is_pxa_idp())
-               leds_event = idp_leds_event;
-
-       leds_event(led_start);
-       return 0;
-}
-
-core_initcall(pxa_leds_init);
diff --git a/arch/arm/mach-pxa/leds.h b/arch/arm/mach-pxa/leds.h
deleted file mode 100644 (file)
index 7f0dfe0..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * arch/arm/mach-pxa/leds.h
- *
- * Copyright (c) 2001 Jeff Sutherland, Accelent Systems Inc.
- *
- * blinky lights for various PXA-based systems:
- *
- */
-
-extern void idp_leds_event(led_event_t evt);
-extern void lubbock_leds_event(led_event_t evt);
-extern void mainstone_leds_event(led_event_t evt);
-extern void trizeps4_leds_event(led_event_t evt);
index 0ca0db787903ab104ef9c0f216148cc3c32acee6..3c48035afd6bcf89c5acd64b5a96c3060fa763c3 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/syscore_ops.h>
 #include <linux/major.h>
@@ -23,6 +24,8 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/smc91x.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
 
 #include <linux/spi/spi.h>
 #include <linux/spi/ads7846.h>
@@ -549,6 +552,98 @@ static void __init lubbock_map_io(void)
        PCFR |= PCFR_OPDE;
 }
 
+/*
+ * Driver for the 8 discrete LEDs available for general use:
+ * Note: bits [15-8] are used to enable/blank the 8 7 segment hex displays
+ * so be sure to not monkey with them here.
+ */
+
+#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
+struct lubbock_led {
+       struct led_classdev     cdev;
+       u8                      mask;
+};
+
+/*
+ * The triggers lines up below will only be used if the
+ * LED triggers are compiled in.
+ */
+static const struct {
+       const char *name;
+       const char *trigger;
+} lubbock_leds[] = {
+       { "lubbock:D28", "default-on", },
+       { "lubbock:D27", "cpu0", },
+       { "lubbock:D26", "heartbeat" },
+       { "lubbock:D25", },
+       { "lubbock:D24", },
+       { "lubbock:D23", },
+       { "lubbock:D22", },
+       { "lubbock:D21", },
+};
+
+static void lubbock_led_set(struct led_classdev *cdev,
+                             enum led_brightness b)
+{
+       struct lubbock_led *led = container_of(cdev,
+                                        struct lubbock_led, cdev);
+       u32 reg = LUB_DISC_BLNK_LED;
+
+       if (b != LED_OFF)
+               reg |= led->mask;
+       else
+               reg &= ~led->mask;
+
+       LUB_DISC_BLNK_LED = reg;
+}
+
+static enum led_brightness lubbock_led_get(struct led_classdev *cdev)
+{
+       struct lubbock_led *led = container_of(cdev,
+                                        struct lubbock_led, cdev);
+       u32 reg = LUB_DISC_BLNK_LED;
+
+       return (reg & led->mask) ? LED_FULL : LED_OFF;
+}
+
+static int __init lubbock_leds_init(void)
+{
+       int i;
+
+       if (!machine_is_lubbock())
+               return -ENODEV;
+
+       /* All ON */
+       LUB_DISC_BLNK_LED |= 0xff;
+       for (i = 0; i < ARRAY_SIZE(lubbock_leds); i++) {
+               struct lubbock_led *led;
+
+               led = kzalloc(sizeof(*led), GFP_KERNEL);
+               if (!led)
+                       break;
+
+               led->cdev.name = lubbock_leds[i].name;
+               led->cdev.brightness_set = lubbock_led_set;
+               led->cdev.brightness_get = lubbock_led_get;
+               led->cdev.default_trigger = lubbock_leds[i].trigger;
+               led->mask = BIT(i);
+
+               if (led_classdev_register(NULL, &led->cdev) < 0) {
+                       kfree(led);
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * Since we may have triggers on any subsystem, defer registration
+ * until after subsystem_init.
+ */
+fs_initcall(lubbock_leds_init);
+#endif
+
 MACHINE_START(LUBBOCK, "Intel DBPXA250 Development Platform (aka Lubbock)")
        /* Maintainer: MontaVista Software Inc. */
        .map_io         = lubbock_map_io,
index 1aebaf719462e091f7b7c29a9180c115b346808c..bdc6c335830a32ce0d5a782c542fe1577e1ce872 100644 (file)
@@ -28,6 +28,8 @@
 #include <linux/pwm_backlight.h>
 #include <linux/smc91x.h>
 #include <linux/i2c/pxa-i2c.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
 
 #include <asm/types.h>
 #include <asm/setup.h>
@@ -613,6 +615,98 @@ static void __init mainstone_map_io(void)
        PCFR = 0x66;
 }
 
+/*
+ * Driver for the 8 discrete LEDs available for general use:
+ * Note: bits [15-8] are used to enable/blank the 8 7 segment hex displays
+ * so be sure to not monkey with them here.
+ */
+
+#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
+struct mainstone_led {
+       struct led_classdev     cdev;
+       u8                      mask;
+};
+
+/*
+ * The triggers lines up below will only be used if the
+ * LED triggers are compiled in.
+ */
+static const struct {
+       const char *name;
+       const char *trigger;
+} mainstone_leds[] = {
+       { "mainstone:D28", "default-on", },
+       { "mainstone:D27", "cpu0", },
+       { "mainstone:D26", "heartbeat" },
+       { "mainstone:D25", },
+       { "mainstone:D24", },
+       { "mainstone:D23", },
+       { "mainstone:D22", },
+       { "mainstone:D21", },
+};
+
+static void mainstone_led_set(struct led_classdev *cdev,
+                             enum led_brightness b)
+{
+       struct mainstone_led *led = container_of(cdev,
+                                        struct mainstone_led, cdev);
+       u32 reg = MST_LEDCTRL;
+
+       if (b != LED_OFF)
+               reg |= led->mask;
+       else
+               reg &= ~led->mask;
+
+       MST_LEDCTRL = reg;
+}
+
+static enum led_brightness mainstone_led_get(struct led_classdev *cdev)
+{
+       struct mainstone_led *led = container_of(cdev,
+                                        struct mainstone_led, cdev);
+       u32 reg = MST_LEDCTRL;
+
+       return (reg & led->mask) ? LED_FULL : LED_OFF;
+}
+
+static int __init mainstone_leds_init(void)
+{
+       int i;
+
+       if (!machine_is_mainstone())
+               return -ENODEV;
+
+       /* All ON */
+       MST_LEDCTRL |= 0xff;
+       for (i = 0; i < ARRAY_SIZE(mainstone_leds); i++) {
+               struct mainstone_led *led;
+
+               led = kzalloc(sizeof(*led), GFP_KERNEL);
+               if (!led)
+                       break;
+
+               led->cdev.name = mainstone_leds[i].name;
+               led->cdev.brightness_set = mainstone_led_set;
+               led->cdev.brightness_get = mainstone_led_get;
+               led->cdev.default_trigger = mainstone_leds[i].trigger;
+               led->mask = BIT(i);
+
+               if (led_classdev_register(NULL, &led->cdev) < 0) {
+                       kfree(led);
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * Since we may have triggers on any subsystem, defer registration
+ * until after subsystem_init.
+ */
+fs_initcall(mainstone_leds_init);
+#endif
+
 MACHINE_START(MAINSTONE, "Intel HCDDBBVA0 Development Platform (aka Mainstone)")
        /* Maintainer: MontaVista Software Inc. */
        .atag_offset    = 0x100,        /* BLOB boot parameter setting */
diff --git a/arch/arm/mach-pxa/pxa-dt.c b/arch/arm/mach-pxa/pxa-dt.c
new file mode 100644 (file)
index 0000000..c9192ce
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ *  linux/arch/arm/mach-pxa/pxa-dt.c
+ *
+ *  Copyright (C) 2012 Daniel Mack
+ *
+ *  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
+ *  publishhed by the Free Software Foundation.
+ */
+
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <mach/irqs.h>
+#include <mach/pxa3xx.h>
+
+#include "generic.h"
+
+#ifdef CONFIG_PXA3xx
+extern void __init pxa3xx_dt_init_irq(void);
+
+static const struct of_dev_auxdata pxa3xx_auxdata_lookup[] __initconst = {
+       OF_DEV_AUXDATA("mrvl,pxa-uart",         0x40100000, "pxa2xx-uart.0", NULL),
+       OF_DEV_AUXDATA("mrvl,pxa-uart",         0x40200000, "pxa2xx-uart.1", NULL),
+       OF_DEV_AUXDATA("mrvl,pxa-uart",         0x40700000, "pxa2xx-uart.2", NULL),
+       OF_DEV_AUXDATA("mrvl,pxa-uart",         0x41600000, "pxa2xx-uart.3", NULL),
+       OF_DEV_AUXDATA("marvell,pxa-mmc",       0x41100000, "pxa2xx-mci.0", NULL),
+       OF_DEV_AUXDATA("mrvl,pxa-gpio",         0x40e00000, "pxa-gpio", NULL),
+       OF_DEV_AUXDATA("marvell,pxa-ohci",      0x4c000000, "pxa27x-ohci", NULL),
+       OF_DEV_AUXDATA("mrvl,pxa-i2c",          0x40301680, "pxa2xx-i2c.0", NULL),
+       OF_DEV_AUXDATA("mrvl,pwri2c",           0x40f500c0, "pxa3xx-i2c.1", NULL),
+       OF_DEV_AUXDATA("marvell,pxa3xx-nand",   0x43100000, "pxa3xx-nand", NULL),
+       {}
+};
+
+static void __init pxa3xx_dt_init(void)
+{
+       of_platform_populate(NULL, of_default_bus_match_table,
+                            pxa3xx_auxdata_lookup, NULL);
+}
+
+static const char *pxa3xx_dt_board_compat[] __initdata = {
+       "marvell,pxa300",
+       "marvell,pxa310",
+       "marvell,pxa320",
+       NULL,
+};
+#endif
+
+#ifdef CONFIG_PXA3xx
+DT_MACHINE_START(PXA_DT, "Marvell PXA3xx (Device Tree Support)")
+       .map_io         = pxa3xx_map_io,
+       .init_irq       = pxa3xx_dt_init_irq,
+       .handle_irq     = pxa3xx_handle_irq,
+       .timer          = &pxa_timer,
+       .restart        = pxa_restart,
+       .init_machine   = pxa3xx_dt_init,
+       .dt_compat      = pxa3xx_dt_board_compat,
+MACHINE_END
+#endif
index dffb7e813d98743e3330db699770f5862eca6d49..4a9d04a57de536e69a5bd20088a4a8eb1894f0dd 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/platform_device.h>
 #include <linux/irq.h>
 #include <linux/io.h>
+#include <linux/of.h>
 #include <linux/syscore_ops.h>
 #include <linux/i2c/pxa-i2c.h>
 
@@ -40,6 +41,8 @@
 #define PECR_IE(n)     ((1 << ((n) * 2)) << 28)
 #define PECR_IS(n)     ((1 << ((n) * 2)) << 29)
 
+extern void __init pxa_dt_irq_init(int (*fn)(struct irq_data *, unsigned int));
+
 static DEFINE_PXA3_CKEN(pxa3xx_ffuart, FFUART, 14857000, 1);
 static DEFINE_PXA3_CKEN(pxa3xx_btuart, BTUART, 14857000, 1);
 static DEFINE_PXA3_CKEN(pxa3xx_stuart, STUART, 14857000, 1);
@@ -382,7 +385,7 @@ static void __init pxa_init_ext_wakeup_irq(int (*fn)(struct irq_data *,
        pxa_ext_wakeup_chip.irq_set_wake = fn;
 }
 
-void __init pxa3xx_init_irq(void)
+static void __init __pxa3xx_init_irq(void)
 {
        /* enable CP6 access */
        u32 value;
@@ -390,10 +393,21 @@ void __init pxa3xx_init_irq(void)
        value |= (1 << 6);
        __asm__ __volatile__("mcr p15, 0, %0, c15, c1, 0\n": :"r"(value));
 
-       pxa_init_irq(56, pxa3xx_set_wake);
        pxa_init_ext_wakeup_irq(pxa3xx_set_wake);
 }
 
+void __init pxa3xx_init_irq(void)
+{
+       __pxa3xx_init_irq();
+       pxa_init_irq(56, pxa3xx_set_wake);
+}
+
+void __init pxa3xx_dt_init_irq(void)
+{
+       __pxa3xx_init_irq();
+       pxa_dt_irq_init(pxa3xx_set_wake);
+}
+
 static struct map_desc pxa3xx_io_desc[] __initdata = {
        {       /* Mem Ctl */
                .virtual        = (unsigned long)SMEMC_VIRT,
@@ -466,7 +480,8 @@ static int __init pxa3xx_init(void)
                register_syscore_ops(&pxa3xx_mfp_syscore_ops);
                register_syscore_ops(&pxa3xx_clock_syscore_ops);
 
-               ret = platform_add_devices(devices, ARRAY_SIZE(devices));
+               if (!of_have_populated_dt())
+                       ret = platform_add_devices(devices, ARRAY_SIZE(devices));
        }
 
        return ret;
index 5905ed130e94200abe59867d0b916e718cedae98..d89d87ae144cc77d2e71e1efe470761544573e3d 100644 (file)
@@ -953,12 +953,12 @@ static struct i2c_board_info raumfeld_connector_i2c_board_info __initdata = {
 
 static struct eeti_ts_platform_data eeti_ts_pdata = {
        .irq_active_high = 1,
+       .irq_gpio = GPIO_TOUCH_IRQ,
 };
 
 static struct i2c_board_info raumfeld_controller_i2c_board_info __initdata = {
        .type   = "eeti_ts",
        .addr   = 0x0a,
-       .irq    = PXA_GPIO_TO_IRQ(GPIO_TOUCH_IRQ),
        .platform_data = &eeti_ts_pdata,
 };
 
index 45868bb43cbd2fbcbfcdfff638dc15f1cbd7d38b..d22dee96484dfc18c758d8cf245689962f1a39ed 100644 (file)
@@ -35,7 +35,6 @@
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/leds.h>
 #include <asm/mach-types.h>
 #include <asm/hardware/arm_timer.h>
 #include <asm/hardware/icst.h>
@@ -436,44 +435,6 @@ struct clcd_board clcd_plat_data = {
        .remove         = versatile_clcd_remove_dma,
 };
 
-#ifdef CONFIG_LEDS
-#define VA_LEDS_BASE (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_LED_OFFSET)
-
-void realview_leds_event(led_event_t ledevt)
-{
-       unsigned long flags;
-       u32 val;
-       u32 led = 1 << smp_processor_id();
-
-       local_irq_save(flags);
-       val = readl(VA_LEDS_BASE);
-
-       switch (ledevt) {
-       case led_idle_start:
-               val = val & ~led;
-               break;
-
-       case led_idle_end:
-               val = val | led;
-               break;
-
-       case led_timer:
-               val = val ^ REALVIEW_SYS_LED7;
-               break;
-
-       case led_halted:
-               val = 0;
-               break;
-
-       default:
-               break;
-       }
-
-       writel(val, VA_LEDS_BASE);
-       local_irq_restore(flags);
-}
-#endif /* CONFIG_LEDS */
-
 /*
  * Where is the timer (VA)?
  */
index f8f2c0ac4c01531d495b62817cfc01af202f7b8e..f2141ae5a7deb910322807b607baa4df66de67e8 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/io.h>
 
 #include <asm/setup.h>
-#include <asm/leds.h>
 
 #define APB_DEVICE(name, busid, base, plat)                    \
 static AMBA_APB_DEVICE(name, busid, 0, REALVIEW_##base##_BASE, base##_IRQ, plat)
@@ -47,7 +46,6 @@ extern void __iomem *timer1_va_base;
 extern void __iomem *timer2_va_base;
 extern void __iomem *timer3_va_base;
 
-extern void realview_leds_event(led_event_t ledevt);
 extern void realview_timer_init(unsigned int timer_irq);
 extern int realview_flash_register(struct resource *res, u32 num);
 extern int realview_eth_register(const char *name, struct resource *res);
index baf382c5e77601957b2ef8982ccdd61552f9b2f2..36f5d296131e832eb750a5a97998bb738fd297dc 100644 (file)
@@ -30,9 +30,7 @@
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/leds.h>
 #include <asm/mach-types.h>
-#include <asm/pmu.h>
 #include <asm/pgtable.h>
 #include <asm/hardware/gic.h>
 #include <asm/hardware/cache-l2x0.h>
@@ -297,7 +295,7 @@ static struct resource pmu_resources[] = {
 
 static struct platform_device pmu_device = {
        .name                   = "arm-pmu",
-       .id                     = ARM_PMU_DEVICE_CPU,
+       .id                     = -1,
        .num_resources          = ARRAY_SIZE(pmu_resources),
        .resource               = pmu_resources,
 };
@@ -462,10 +460,6 @@ static void __init realview_eb_init(void)
                struct amba_device *d = amba_devs[i];
                amba_device_register(d, &iomem_resource);
        }
-
-#ifdef CONFIG_LEDS
-       leds_event = realview_leds_event;
-#endif
 }
 
 MACHINE_START(REALVIEW_EB, "ARM-RealView EB")
index b1d7cafa1a6d2e295c2f95529b1d556df4b85db1..049c3738777b701e766b07b56b35a9dd3050b2cd 100644 (file)
@@ -32,9 +32,7 @@
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/leds.h>
 #include <asm/mach-types.h>
-#include <asm/pmu.h>
 #include <asm/pgtable.h>
 #include <asm/hardware/gic.h>
 #include <asm/hardware/cache-l2x0.h>
@@ -280,7 +278,7 @@ static struct resource pmu_resource = {
 
 static struct platform_device pmu_device = {
        .name                   = "arm-pmu",
-       .id                     = ARM_PMU_DEVICE_CPU,
+       .id                     = -1,
        .num_resources          = 1,
        .resource               = &pmu_resource,
 };
@@ -375,10 +373,6 @@ static void __init realview_pb1176_init(void)
                struct amba_device *d = amba_devs[i];
                amba_device_register(d, &iomem_resource);
        }
-
-#ifdef CONFIG_LEDS
-       leds_event = realview_leds_event;
-#endif
 }
 
 MACHINE_START(REALVIEW_PB1176, "ARM-RealView PB1176")
index a98c536e3327afa9823a2b29ffd081258be2ae5a..9966672d86cdf9f74f8f692f3fa6f8ad24d2da71 100644 (file)
@@ -30,9 +30,7 @@
 
 #include <mach/hardware.h>
 #include <asm/irq.h>
-#include <asm/leds.h>
 #include <asm/mach-types.h>
-#include <asm/pmu.h>
 #include <asm/pgtable.h>
 #include <asm/hardware/gic.h>
 #include <asm/hardware/cache-l2x0.h>
@@ -263,7 +261,7 @@ static struct resource pmu_resources[] = {
 
 static struct platform_device pmu_device = {
        .name                   = "arm-pmu",
-       .id                     = ARM_PMU_DEVICE_CPU,
+       .id                     = -1,
        .num_resources          = ARRAY_SIZE(pmu_resources),
        .resource               = pmu_resources,
 };
@@ -357,10 +355,6 @@ static void __init realview_pb11mp_init(void)
                struct amba_device *d = amba_devs[i];
                amba_device_register(d, &iomem_resource);
        }
-
-#ifdef CONFIG_LEDS
-       leds_event = realview_leds_event;
-#endif
 }
 
 MACHINE_START(REALVIEW_PB11MP, "ARM-RealView PB11MPCore")
index 59650174e6ed39e9c3bc9e44441beb48b22a4214..25fdc6b0135cdf067e527389f3bdb1d7ddff8f99 100644 (file)
@@ -29,9 +29,7 @@
 #include <linux/io.h>
 
 #include <asm/irq.h>
-#include <asm/leds.h>
 #include <asm/mach-types.h>
-#include <asm/pmu.h>
 #include <asm/pgtable.h>
 #include <asm/hardware/gic.h>
 
@@ -241,7 +239,7 @@ static struct resource pmu_resource = {
 
 static struct platform_device pmu_device = {
        .name                   = "arm-pmu",
-       .id                     = ARM_PMU_DEVICE_CPU,
+       .id                     = -1,
        .num_resources          = 1,
        .resource               = &pmu_resource,
 };
@@ -299,10 +297,6 @@ static void __init realview_pba8_init(void)
                struct amba_device *d = amba_devs[i];
                amba_device_register(d, &iomem_resource);
        }
-
-#ifdef CONFIG_LEDS
-       leds_event = realview_leds_event;
-#endif
 }
 
 MACHINE_START(REALVIEW_PBA8, "ARM-RealView PB-A8")
index 3f2f605624e95270fd1039e64a3a0a2d2180cd06..05f28d853c706d825cca0f77960767494d4109ba 100644 (file)
@@ -28,9 +28,7 @@
 #include <linux/io.h>
 
 #include <asm/irq.h>
-#include <asm/leds.h>
 #include <asm/mach-types.h>
-#include <asm/pmu.h>
 #include <asm/smp_twd.h>
 #include <asm/pgtable.h>
 #include <asm/hardware/gic.h>
@@ -280,7 +278,7 @@ static struct resource pmu_resources[] = {
 
 static struct platform_device pmu_device = {
        .name                   = "arm-pmu",
-       .id                     = ARM_PMU_DEVICE_CPU,
+       .id                     = -1,
        .num_resources          = ARRAY_SIZE(pmu_resources),
        .resource               = pmu_resources,
 };
@@ -394,10 +392,6 @@ static void __init realview_pbx_init(void)
                struct amba_device *d = amba_devs[i];
                amba_device_register(d, &iomem_resource);
        }
-
-#ifdef CONFIG_LEDS
-       leds_event = realview_leds_event;
-#endif
 }
 
 MACHINE_START(REALVIEW_PBX, "ARM-RealView PBX")
index e24961109b70286655c36c46a3083809511870c5..d56b0f7f2b202a0aaea0b36435328ff15b8c783f 100644 (file)
@@ -483,7 +483,7 @@ config MACH_NEO1973_GTA02
        select I2C
        select POWER_SUPPLY
        select MACH_NEO1973
-       select S3C2410_PWM
+       select S3C24XX_PWM
        select S3C_DEV_USB_HOST
        help
           Say Y here if you are using the Openmoko GTA02 / Freerunner GSM Phone
@@ -493,7 +493,7 @@ config MACH_RX1950
        select S3C24XX_DCLK
        select PM_H1940 if PM
        select I2C
-       select S3C2410_PWM
+       select S3C24XX_PWM
        select S3C_DEV_NAND
        select S3C2410_IOTIMING if S3C2440_CPUFREQ
        select S3C2440_XTAL_16934400
index 60b97ec01676fc7eff7471eebf415ae2a97f5696..1aed9e70465d5d3f8572c0bec308d3e06d089ab3 100644 (file)
@@ -7,21 +7,17 @@ obj-y := clock.o generic.o irq.o time.o #nmi-oopser.o
 obj-m :=
 obj-n :=
 obj-  :=
-led-y := leds.o
 
 obj-$(CONFIG_CPU_FREQ_SA1100)          += cpu-sa1100.o
 obj-$(CONFIG_CPU_FREQ_SA1110)          += cpu-sa1110.o
 
 # Specific board support
 obj-$(CONFIG_SA1100_ASSABET)           += assabet.o
-led-$(CONFIG_SA1100_ASSABET)           += leds-assabet.o
 obj-$(CONFIG_ASSABET_NEPONSET)         += neponset.o
 
 obj-$(CONFIG_SA1100_BADGE4)            += badge4.o
-led-$(CONFIG_SA1100_BADGE4)            += leds-badge4.o
 
 obj-$(CONFIG_SA1100_CERF)              += cerf.o
-led-$(CONFIG_SA1100_CERF)              += leds-cerf.o
 
 obj-$(CONFIG_SA1100_COLLIE)            += collie.o
 
@@ -29,13 +25,11 @@ obj-$(CONFIG_SA1100_H3100)          += h3100.o h3xxx.o
 obj-$(CONFIG_SA1100_H3600)             += h3600.o h3xxx.o
 
 obj-$(CONFIG_SA1100_HACKKIT)           += hackkit.o
-led-$(CONFIG_SA1100_HACKKIT)           += leds-hackkit.o
 
 obj-$(CONFIG_SA1100_JORNADA720)                += jornada720.o
 obj-$(CONFIG_SA1100_JORNADA720_SSP)    += jornada720_ssp.o
 
 obj-$(CONFIG_SA1100_LART)              += lart.o
-led-$(CONFIG_SA1100_LART)              += leds-lart.o
 
 obj-$(CONFIG_SA1100_NANOENGINE)                += nanoengine.o
 obj-$(CONFIG_PCI_NANOENGINE)           += pci-nanoengine.o
@@ -46,9 +40,6 @@ obj-$(CONFIG_SA1100_SHANNON)          += shannon.o
 
 obj-$(CONFIG_SA1100_SIMPAD)            += simpad.o
 
-# LEDs support
-obj-$(CONFIG_LEDS) += $(led-y)
-
 # Miscellaneous functions
 obj-$(CONFIG_PM)                       += pm.o sleep.o
 obj-$(CONFIG_SA1100_SSP)               += ssp.o
index d673211f121c4f8ce98805b0b508c3032162da0e..1710ed1a0ac0deac5a22e6287364fa05f500c3f3 100644 (file)
@@ -20,6 +20,8 @@
 #include <linux/mtd/partitions.h>
 #include <linux/delay.h>
 #include <linux/mm.h>
+#include <linux/leds.h>
+#include <linux/slab.h>
 
 #include <video/sa1100fb.h>
 
@@ -529,6 +531,89 @@ static void __init assabet_map_io(void)
        sa1100_register_uart(2, 3);
 }
 
+/* LEDs */
+#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
+struct assabet_led {
+       struct led_classdev cdev;
+       u32 mask;
+};
+
+/*
+ * The triggers lines up below will only be used if the
+ * LED triggers are compiled in.
+ */
+static const struct {
+       const char *name;
+       const char *trigger;
+} assabet_leds[] = {
+       { "assabet:red", "cpu0",},
+       { "assabet:green", "heartbeat", },
+};
+
+/*
+ * The LED control in Assabet is reversed:
+ *  - setting bit means turn off LED
+ *  - clearing bit means turn on LED
+ */
+static void assabet_led_set(struct led_classdev *cdev,
+               enum led_brightness b)
+{
+       struct assabet_led *led = container_of(cdev,
+                       struct assabet_led, cdev);
+
+       if (b != LED_OFF)
+               ASSABET_BCR_clear(led->mask);
+       else
+               ASSABET_BCR_set(led->mask);
+}
+
+static enum led_brightness assabet_led_get(struct led_classdev *cdev)
+{
+       struct assabet_led *led = container_of(cdev,
+                       struct assabet_led, cdev);
+
+       return (ASSABET_BCR & led->mask) ? LED_OFF : LED_FULL;
+}
+
+static int __init assabet_leds_init(void)
+{
+       int i;
+
+       if (!machine_is_assabet())
+               return -ENODEV;
+
+       for (i = 0; i < ARRAY_SIZE(assabet_leds); i++) {
+               struct assabet_led *led;
+
+               led = kzalloc(sizeof(*led), GFP_KERNEL);
+               if (!led)
+                       break;
+
+               led->cdev.name = assabet_leds[i].name;
+               led->cdev.brightness_set = assabet_led_set;
+               led->cdev.brightness_get = assabet_led_get;
+               led->cdev.default_trigger = assabet_leds[i].trigger;
+
+               if (!i)
+                       led->mask = ASSABET_BCR_LED_RED;
+               else
+                       led->mask = ASSABET_BCR_LED_GREEN;
+
+               if (led_classdev_register(NULL, &led->cdev) < 0) {
+                       kfree(led);
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * Since we may have triggers on any subsystem, defer registration
+ * until after subsystem_init.
+ */
+fs_initcall(assabet_leds_init);
+#endif
 
 MACHINE_START(ASSABET, "Intel-Assabet")
        .atag_offset    = 0x100,
index b30fb99b587c9fe1025def432f7c7c0a6eb9bbf2..038df4894b0fb84ad33befb082cbdd5ee0e2ae3d 100644 (file)
@@ -22,6 +22,8 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
 
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
@@ -76,8 +78,36 @@ static struct platform_device sa1111_device = {
        .resource       = sa1111_resources,
 };
 
+/* LEDs */
+struct gpio_led badge4_gpio_leds[] = {
+       {
+               .name                   = "badge4:red",
+               .default_trigger        = "heartbeat",
+               .gpio                   = 7,
+       },
+       {
+               .name                   = "badge4:green",
+               .default_trigger        = "cpu0",
+               .gpio                   = 9,
+       },
+};
+
+static struct gpio_led_platform_data badge4_gpio_led_info = {
+       .leds           = badge4_gpio_leds,
+       .num_leds       = ARRAY_SIZE(badge4_gpio_leds),
+};
+
+static struct platform_device badge4_leds = {
+       .name   = "leds-gpio",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = &badge4_gpio_led_info,
+       }
+};
+
 static struct platform_device *devices[] __initdata = {
        &sa1111_device,
+       &badge4_leds,
 };
 
 static int __init badge4_sa1111_init(void)
index 09d7f4b4b35487509840fe72ad0dd2d313c0e285..5240f104a3cd8a7c82a2d859f47aff476c10808f 100644 (file)
@@ -17,6 +17,8 @@
 #include <linux/irq.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
 
 #include <mach/hardware.h>
 #include <asm/setup.h>
@@ -43,8 +45,48 @@ static struct platform_device cerfuart2_device = {
        .resource       = cerfuart2_resources,
 };
 
+/* LEDs */
+struct gpio_led cerf_gpio_leds[] = {
+       {
+               .name                   = "cerf:d0",
+               .default_trigger        = "heartbeat",
+               .gpio                   = 0,
+       },
+       {
+               .name                   = "cerf:d1",
+               .default_trigger        = "cpu0",
+               .gpio                   = 1,
+       },
+       {
+               .name                   = "cerf:d2",
+               .default_trigger        = "default-on",
+               .gpio                   = 2,
+       },
+       {
+               .name                   = "cerf:d3",
+               .default_trigger        = "default-on",
+               .gpio                   = 3,
+       },
+
+};
+
+static struct gpio_led_platform_data cerf_gpio_led_info = {
+       .leds           = cerf_gpio_leds,
+       .num_leds       = ARRAY_SIZE(cerf_gpio_leds),
+};
+
+static struct platform_device cerf_leds = {
+       .name   = "leds-gpio",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = &cerf_gpio_led_info,
+       }
+};
+
+
 static struct platform_device *cerf_devices[] __initdata = {
        &cerfuart2_device,
+       &cerf_leds,
 };
 
 #ifdef CONFIG_SA1100_CERF_FLASH_32MB
index 7f86bd911826a4327462d577d43c53031c2fe185..fc106aab7c7e4a9e4b175c5a74fc7902f254a53b 100644 (file)
 #include <linux/serial_core.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
+#include <linux/tty.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
 
 #include <asm/mach-types.h>
 #include <asm/setup.h>
@@ -183,9 +187,37 @@ static struct flash_platform_data hackkit_flash_data = {
 static struct resource hackkit_flash_resource =
        DEFINE_RES_MEM(SA1100_CS0_PHYS, SZ_32M);
 
+/* LEDs */
+struct gpio_led hackkit_gpio_leds[] = {
+       {
+               .name                   = "hackkit:red",
+               .default_trigger        = "cpu0",
+               .gpio                   = 22,
+       },
+       {
+               .name                   = "hackkit:green",
+               .default_trigger        = "heartbeat",
+               .gpio                   = 23,
+       },
+};
+
+static struct gpio_led_platform_data hackkit_gpio_led_info = {
+       .leds           = hackkit_gpio_leds,
+       .num_leds       = ARRAY_SIZE(hackkit_gpio_leds),
+};
+
+static struct platform_device hackkit_leds = {
+       .name   = "leds-gpio",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = &hackkit_gpio_led_info,
+       }
+};
+
 static void __init hackkit_init(void)
 {
        sa11x0_register_mtd(&hackkit_flash_data, &hackkit_flash_resource, 1);
+       platform_device_register(&hackkit_leds);
 }
 
 /**********************************************************************
index b775a0abec0af7575dafebe8673eef8758c14300..b2ce04bf4c9bc19b187be619705f147f9fcae96f 100644 (file)
@@ -5,6 +5,9 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/tty.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
 
 #include <video/sa1100fb.h>
 
@@ -126,6 +129,27 @@ static struct map_desc lart_io_desc[] __initdata = {
        }
 };
 
+/* LEDs */
+struct gpio_led lart_gpio_leds[] = {
+       {
+               .name                   = "lart:red",
+               .default_trigger        = "cpu0",
+               .gpio                   = 23,
+       },
+};
+
+static struct gpio_led_platform_data lart_gpio_led_info = {
+       .leds           = lart_gpio_leds,
+       .num_leds       = ARRAY_SIZE(lart_gpio_leds),
+};
+
+static struct platform_device lart_leds = {
+       .name   = "leds-gpio",
+       .id     = -1,
+       .dev    = {
+               .platform_data  = &lart_gpio_led_info,
+       }
+};
 static void __init lart_map_io(void)
 {
        sa1100_map_io();
@@ -139,6 +163,8 @@ static void __init lart_map_io(void)
        GPDR |= GPIO_UART_TXD;
        GPDR &= ~GPIO_UART_RXD;
        PPAR |= PPAR_UPR;
+
+       platform_device_register(&lart_leds);
 }
 
 MACHINE_START(LART, "LART")
diff --git a/arch/arm/mach-sa1100/leds-assabet.c b/arch/arm/mach-sa1100/leds-assabet.c
deleted file mode 100644 (file)
index 3699176..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * linux/arch/arm/mach-sa1100/leds-assabet.c
- *
- * Copyright (C) 2000 John Dorsey <john+@cs.cmu.edu>
- *
- * Original (leds-footbridge.c) by Russell King
- *
- * Assabet uses the LEDs as follows:
- *   - Green - toggles state every 50 timer interrupts
- *   - Red   - on if system is not idle
- */
-#include <linux/init.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-#include <mach/assabet.h>
-
-#include "leds.h"
-
-
-#define LED_STATE_ENABLED      1
-#define LED_STATE_CLAIMED      2
-
-static unsigned int led_state;
-static unsigned int hw_led_state;
-
-#define ASSABET_BCR_LED_MASK   (ASSABET_BCR_LED_GREEN | ASSABET_BCR_LED_RED)
-
-void assabet_leds_event(led_event_t evt)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-
-       switch (evt) {
-       case led_start:
-               hw_led_state = ASSABET_BCR_LED_RED | ASSABET_BCR_LED_GREEN;
-               led_state = LED_STATE_ENABLED;
-               break;
-
-       case led_stop:
-               led_state &= ~LED_STATE_ENABLED;
-               hw_led_state = ASSABET_BCR_LED_RED | ASSABET_BCR_LED_GREEN;
-               ASSABET_BCR_frob(ASSABET_BCR_LED_MASK, hw_led_state);
-               break;
-
-       case led_claim:
-               led_state |= LED_STATE_CLAIMED;
-               hw_led_state = ASSABET_BCR_LED_RED | ASSABET_BCR_LED_GREEN;
-               break;
-
-       case led_release:
-               led_state &= ~LED_STATE_CLAIMED;
-               hw_led_state = ASSABET_BCR_LED_RED | ASSABET_BCR_LED_GREEN;
-               break;
-
-#ifdef CONFIG_LEDS_TIMER
-       case led_timer:
-               if (!(led_state & LED_STATE_CLAIMED))
-                       hw_led_state ^= ASSABET_BCR_LED_GREEN;
-               break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-       case led_idle_start:
-               if (!(led_state & LED_STATE_CLAIMED))
-                       hw_led_state |= ASSABET_BCR_LED_RED;
-               break;
-
-       case led_idle_end:
-               if (!(led_state & LED_STATE_CLAIMED))
-                       hw_led_state &= ~ASSABET_BCR_LED_RED;
-               break;
-#endif
-
-       case led_halted:
-               break;
-
-       case led_green_on:
-               if (led_state & LED_STATE_CLAIMED)
-                       hw_led_state &= ~ASSABET_BCR_LED_GREEN;
-               break;
-
-       case led_green_off:
-               if (led_state & LED_STATE_CLAIMED)
-                       hw_led_state |= ASSABET_BCR_LED_GREEN;
-               break;
-
-       case led_amber_on:
-               break;
-
-       case led_amber_off:
-               break;
-
-       case led_red_on:
-               if (led_state & LED_STATE_CLAIMED)
-                       hw_led_state &= ~ASSABET_BCR_LED_RED;
-               break;
-
-       case led_red_off:
-               if (led_state & LED_STATE_CLAIMED)
-                       hw_led_state |= ASSABET_BCR_LED_RED;
-               break;
-
-       default:
-               break;
-       }
-
-       if  (led_state & LED_STATE_ENABLED)
-               ASSABET_BCR_frob(ASSABET_BCR_LED_MASK, hw_led_state);
-
-       local_irq_restore(flags);
-}
diff --git a/arch/arm/mach-sa1100/leds-badge4.c b/arch/arm/mach-sa1100/leds-badge4.c
deleted file mode 100644 (file)
index f99fac3..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * linux/arch/arm/mach-sa1100/leds-badge4.c
- *
- * Author: Christopher Hoover <ch@hpl.hp.com>
- * Copyright (C) 2002 Hewlett-Packard Company
- *
- * 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/init.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-
-#include "leds.h"
-
-#define LED_STATE_ENABLED      1
-#define LED_STATE_CLAIMED      2
-
-static unsigned int led_state;
-static unsigned int hw_led_state;
-
-#define LED_RED                GPIO_GPIO(7)
-#define LED_GREEN       GPIO_GPIO(9)
-#define LED_MASK       (LED_RED|LED_GREEN)
-
-#define LED_IDLE       LED_GREEN
-#define LED_TIMER      LED_RED
-
-void badge4_leds_event(led_event_t evt)
-{
-        unsigned long flags;
-
-       local_irq_save(flags);
-
-        switch (evt) {
-        case led_start:
-               GPDR |= LED_MASK;
-                hw_led_state = LED_MASK;
-                led_state = LED_STATE_ENABLED;
-                break;
-
-        case led_stop:
-                led_state &= ~LED_STATE_ENABLED;
-                break;
-
-        case led_claim:
-                led_state |= LED_STATE_CLAIMED;
-                hw_led_state = LED_MASK;
-                break;
-
-        case led_release:
-                led_state &= ~LED_STATE_CLAIMED;
-                hw_led_state = LED_MASK;
-                break;
-
-#ifdef CONFIG_LEDS_TIMER
-        case led_timer:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state ^= LED_TIMER;
-                break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-        case led_idle_start:
-               /* LED off when system is idle */
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state &= ~LED_IDLE;
-                break;
-
-        case led_idle_end:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state |= LED_IDLE;
-                break;
-#endif
-
-        case led_red_on:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state &= ~LED_RED;
-                break;
-
-        case led_red_off:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state |= LED_RED;
-                break;
-
-        case led_green_on:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state &= ~LED_GREEN;
-                break;
-
-        case led_green_off:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state |= LED_GREEN;
-                break;
-
-       default:
-               break;
-        }
-
-        if  (led_state & LED_STATE_ENABLED) {
-                GPSR = hw_led_state;
-                GPCR = hw_led_state ^ LED_MASK;
-        }
-
-       local_irq_restore(flags);
-}
diff --git a/arch/arm/mach-sa1100/leds-cerf.c b/arch/arm/mach-sa1100/leds-cerf.c
deleted file mode 100644 (file)
index 30fc3b2..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * linux/arch/arm/mach-sa1100/leds-cerf.c
- *
- * Author: ???
- */
-#include <linux/init.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-
-#include "leds.h"
-
-
-#define LED_STATE_ENABLED      1
-#define LED_STATE_CLAIMED      2
-
-static unsigned int led_state;
-static unsigned int hw_led_state;
-
-#define LED_D0          GPIO_GPIO(0)
-#define LED_D1          GPIO_GPIO(1)
-#define LED_D2          GPIO_GPIO(2)
-#define LED_D3          GPIO_GPIO(3)
-#define LED_MASK        (LED_D0|LED_D1|LED_D2|LED_D3)
-
-void cerf_leds_event(led_event_t evt)
-{
-        unsigned long flags;
-
-       local_irq_save(flags);
-
-        switch (evt) {
-        case led_start:
-                hw_led_state = LED_MASK;
-                led_state = LED_STATE_ENABLED;
-                break;
-
-        case led_stop:
-                led_state &= ~LED_STATE_ENABLED;
-                break;
-
-        case led_claim:
-                led_state |= LED_STATE_CLAIMED;
-                hw_led_state = LED_MASK;
-                break;
-        case led_release:
-                led_state &= ~LED_STATE_CLAIMED;
-                hw_led_state = LED_MASK;
-                break;
-
-#ifdef CONFIG_LEDS_TIMER
-        case led_timer:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state ^= LED_D0;
-                break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-        case led_idle_start:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state &= ~LED_D1;
-                break;
-
-        case led_idle_end:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state |= LED_D1;
-                break;
-#endif
-        case led_green_on:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state &= ~LED_D2;
-                break;
-
-        case led_green_off:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state |= LED_D2;
-                break;
-
-        case led_amber_on:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state &= ~LED_D3;
-                break;
-
-        case led_amber_off:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state |= LED_D3;
-                break;
-
-        case led_red_on:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state &= ~LED_D1;
-                break;
-
-        case led_red_off:
-                if (!(led_state & LED_STATE_CLAIMED))
-                        hw_led_state |= LED_D1;
-                break;
-
-        default:
-                break;
-        }
-
-        if  (led_state & LED_STATE_ENABLED) {
-                GPSR = hw_led_state;
-                GPCR = hw_led_state ^ LED_MASK;
-        }
-
-       local_irq_restore(flags);
-}
diff --git a/arch/arm/mach-sa1100/leds-hackkit.c b/arch/arm/mach-sa1100/leds-hackkit.c
deleted file mode 100644 (file)
index 6a23524..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * linux/arch/arm/mach-sa1100/leds-hackkit.c
- *
- * based on leds-lart.c
- *
- * (C) Erik Mouw (J.A.K.Mouw@its.tudelft.nl), April 21, 2000
- * (C) Stefan Eletzhofer <stefan.eletzhofer@eletztrick.de>, 2002
- *
- * The HackKit has two leds (GPIO 22/23). The red led (gpio 22) is used
- * as cpu led, the green one is used as timer led.
- */
-#include <linux/init.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-
-#include "leds.h"
-
-
-#define LED_STATE_ENABLED      1
-#define LED_STATE_CLAIMED      2
-
-static unsigned int led_state;
-static unsigned int hw_led_state;
-
-#define LED_GREEN    GPIO_GPIO23
-#define LED_RED    GPIO_GPIO22
-#define LED_MASK  (LED_RED | LED_GREEN)
-
-void hackkit_leds_event(led_event_t evt)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-
-       switch(evt) {
-               case led_start:
-                       /* pin 22/23 are outputs */
-                       GPDR |= LED_MASK;
-                       hw_led_state = LED_MASK;
-                       led_state = LED_STATE_ENABLED;
-                       break;
-
-               case led_stop:
-                       led_state &= ~LED_STATE_ENABLED;
-                       break;
-
-               case led_claim:
-                       led_state |= LED_STATE_CLAIMED;
-                       hw_led_state = LED_MASK;
-                       break;
-
-               case led_release:
-                       led_state &= ~LED_STATE_CLAIMED;
-                       hw_led_state = LED_MASK;
-                       break;
-
-#ifdef CONFIG_LEDS_TIMER
-               case led_timer:
-                       if (!(led_state & LED_STATE_CLAIMED))
-                               hw_led_state ^= LED_GREEN;
-                       break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-               case led_idle_start:
-                       /* The LART people like the LED to be off when the
-                          system is idle... */
-                       if (!(led_state & LED_STATE_CLAIMED))
-                               hw_led_state &= ~LED_RED;
-                       break;
-
-               case led_idle_end:
-                       /* ... and on if the system is not idle */
-                       if (!(led_state & LED_STATE_CLAIMED))
-                               hw_led_state |= LED_RED;
-                       break;
-#endif
-
-               case led_red_on:
-                       if (led_state & LED_STATE_CLAIMED)
-                               hw_led_state &= ~LED_RED;
-                       break;
-
-               case led_red_off:
-                       if (led_state & LED_STATE_CLAIMED)
-                               hw_led_state |= LED_RED;
-                       break;
-
-               case led_green_on:
-                       if (led_state & LED_STATE_CLAIMED)
-                               hw_led_state &= ~LED_GREEN;
-                       break;
-
-               case led_green_off:
-                       if (led_state & LED_STATE_CLAIMED)
-                               hw_led_state |= LED_GREEN;
-                       break;
-
-               default:
-                       break;
-       }
-
-       /* Now set the GPIO state, or nothing will happen at all */
-       if (led_state & LED_STATE_ENABLED) {
-               GPSR = hw_led_state;
-               GPCR = hw_led_state ^ LED_MASK;
-       }
-
-       local_irq_restore(flags);
-}
diff --git a/arch/arm/mach-sa1100/leds-lart.c b/arch/arm/mach-sa1100/leds-lart.c
deleted file mode 100644 (file)
index 50a5b14..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * linux/arch/arm/mach-sa1100/leds-lart.c
- *
- * (C) Erik Mouw (J.A.K.Mouw@its.tudelft.nl), April 21, 2000
- *
- * LART uses the LED as follows:
- *   - GPIO23 is the LED, on if system is not idle
- *  You can use both CONFIG_LEDS_CPU and CONFIG_LEDS_TIMER at the same
- *  time, but in that case the timer events will still dictate the
- *  pace of the LED.
- */
-#include <linux/init.h>
-#include <linux/io.h>
-
-#include <mach/hardware.h>
-#include <asm/leds.h>
-
-#include "leds.h"
-
-
-#define LED_STATE_ENABLED      1
-#define LED_STATE_CLAIMED      2
-
-static unsigned int led_state;
-static unsigned int hw_led_state;
-
-#define LED_23    GPIO_GPIO23
-#define LED_MASK  (LED_23)
-
-void lart_leds_event(led_event_t evt)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-
-       switch(evt) {
-       case led_start:
-               /* pin 23 is output pin */
-               GPDR |= LED_23;
-               hw_led_state = LED_MASK;
-               led_state = LED_STATE_ENABLED;
-               break;
-
-       case led_stop:
-               led_state &= ~LED_STATE_ENABLED;
-               break;
-
-       case led_claim:
-               led_state |= LED_STATE_CLAIMED;
-               hw_led_state = LED_MASK;
-               break;
-
-       case led_release:
-               led_state &= ~LED_STATE_CLAIMED;
-               hw_led_state = LED_MASK;
-               break;
-
-#ifdef CONFIG_LEDS_TIMER
-       case led_timer:
-               if (!(led_state & LED_STATE_CLAIMED))
-                       hw_led_state ^= LED_23;
-               break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-       case led_idle_start:
-               /* The LART people like the LED to be off when the
-                   system is idle... */
-               if (!(led_state & LED_STATE_CLAIMED))
-                       hw_led_state &= ~LED_23;
-               break;
-
-       case led_idle_end:
-               /* ... and on if the system is not idle */
-               if (!(led_state & LED_STATE_CLAIMED))
-                       hw_led_state |= LED_23;
-               break;
-#endif
-
-       case led_red_on:
-               if (led_state & LED_STATE_CLAIMED)
-                       hw_led_state &= ~LED_23;
-               break;
-
-       case led_red_off:
-               if (led_state & LED_STATE_CLAIMED)
-                       hw_led_state |= LED_23;
-               break;
-
-       default:
-               break;
-       }
-
-       /* Now set the GPIO state, or nothing will happen at all */
-       if (led_state & LED_STATE_ENABLED) {
-               GPSR = hw_led_state;
-               GPCR = hw_led_state ^ LED_MASK;
-       }
-
-       local_irq_restore(flags);
-}
diff --git a/arch/arm/mach-sa1100/leds.c b/arch/arm/mach-sa1100/leds.c
deleted file mode 100644 (file)
index 5fe71a0..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * linux/arch/arm/mach-sa1100/leds.c
- *
- * SA1100 LEDs dispatcher
- *
- * Copyright (C) 2001 Nicolas Pitre
- */
-#include <linux/compiler.h>
-#include <linux/init.h>
-
-#include <asm/leds.h>
-#include <asm/mach-types.h>
-
-#include "leds.h"
-
-static int __init
-sa1100_leds_init(void)
-{
-       if (machine_is_assabet())
-               leds_event = assabet_leds_event;
-       if (machine_is_consus())
-               leds_event = consus_leds_event;
-       if (machine_is_badge4())
-               leds_event = badge4_leds_event;
-       if (machine_is_brutus())
-               leds_event = brutus_leds_event;
-       if (machine_is_cerf())
-               leds_event = cerf_leds_event;
-       if (machine_is_flexanet())
-               leds_event = flexanet_leds_event;
-       if (machine_is_graphicsclient())
-               leds_event = graphicsclient_leds_event;
-       if (machine_is_hackkit())
-               leds_event = hackkit_leds_event;
-       if (machine_is_lart())
-               leds_event = lart_leds_event;
-       if (machine_is_pfs168())
-               leds_event = pfs168_leds_event;
-       if (machine_is_graphicsmaster())
-               leds_event = graphicsmaster_leds_event;
-       if (machine_is_adsbitsy())
-               leds_event = adsbitsy_leds_event;
-       if (machine_is_pt_system3())
-               leds_event = system3_leds_event;
-
-       leds_event(led_start);
-       return 0;
-}
-
-core_initcall(sa1100_leds_init);
diff --git a/arch/arm/mach-sa1100/leds.h b/arch/arm/mach-sa1100/leds.h
deleted file mode 100644 (file)
index 776b602..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-extern void assabet_leds_event(led_event_t evt);
-extern void badge4_leds_event(led_event_t evt);
-extern void consus_leds_event(led_event_t evt);
-extern void brutus_leds_event(led_event_t evt);
-extern void cerf_leds_event(led_event_t evt);
-extern void flexanet_leds_event(led_event_t evt);
-extern void graphicsclient_leds_event(led_event_t evt);
-extern void hackkit_leds_event(led_event_t evt);
-extern void lart_leds_event(led_event_t evt);
-extern void pfs168_leds_event(led_event_t evt);
-extern void graphicsmaster_leds_event(led_event_t evt);
-extern void adsbitsy_leds_event(led_event_t evt);
-extern void system3_leds_event(led_event_t evt);
index 45be9b04e7baaf2cabe4640a411a43d96a159a81..29657183c4520ddedd9244682ec8a4599209e38a 100644 (file)
@@ -4,9 +4,7 @@
 
 # Object file lists.
 
-obj-y                  := core.o dma.o irq.o pci.o
+obj-y                  := core.o dma.o irq.o pci.o leds.o
 obj-m                  :=
 obj-n                  :=
 obj-                   :=
-
-obj-$(CONFIG_LEDS)     += leds.o
index 2704bcd869cdc1d61843bc85c3a4bd2e5f36d5fc..9ad2e9737fb5cabd3a1afc2785d31e8dc61dcfdf 100644 (file)
@@ -13,7 +13,6 @@
 
 #include <asm/setup.h>
 #include <asm/mach-types.h>
-#include <asm/leds.h>
 #include <asm/param.h>
 #include <asm/system_misc.h>
 
@@ -21,9 +20,6 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
 
-#define IO_BASE                 0xe0000000
-#define IO_SIZE                 0x08000000
-#define IO_START                0x40000000
 #define ROMCARD_SIZE            0x08000000
 #define ROMCARD_START           0x10000000
 
@@ -104,20 +100,6 @@ arch_initcall(shark_init);
 
 extern void shark_init_irq(void);
 
-static struct map_desc shark_io_desc[] __initdata = {
-       {
-               .virtual        = IO_BASE,
-               .pfn            = __phys_to_pfn(IO_START),
-               .length         = IO_SIZE,
-               .type           = MT_DEVICE
-       }
-};
-
-static void __init shark_map_io(void)
-{
-       iotable_init(shark_io_desc, ARRAY_SIZE(shark_io_desc));
-}
-
 #define IRQ_TIMER 0
 #define HZ_TIME ((1193180 + HZ/2) / HZ)
 
@@ -158,7 +140,6 @@ static void shark_init_early(void)
 MACHINE_START(SHARK, "Shark")
        /* Maintainer: Alexander Schulz */
        .atag_offset    = 0x3000,
-       .map_io         = shark_map_io,
        .init_early     = shark_init_early,
        .init_irq       = shark_init_irq,
        .timer          = &shark_timer,
index 20eb2bf2a42bfae2110acdec021bd23f965a0812..d129119a3f69189a6c636b04be0330ec4bbd8d72 100644 (file)
 */
 
                .macro  addruart, rp, rv, tmp
-               mov     \rp, #0xe0000000
-               orr     \rp, \rp, #0x000003f8
-               mov     \rv, \rp
+               mov     \rp, #0x3f8
+               orr     \rv, \rp, #0xfe000000
+               orr     \rv, \rv, #0x00e00000
+               orr     \rp, \rp, #0x40000000
                .endm
 
                .macro  senduart,rd,rx
index 5901b09fc96a356b1aa8d07a96c8efa3bfc9f6a6..c9e49f04953206050e629adb7ad9690b928aade1 100644 (file)
@@ -8,7 +8,8 @@
  * warranty of any kind, whether express or implied.
  */
                .macro  get_irqnr_preamble, base, tmp
-               mov     \base, #0xe0000000
+               mov     \base, #0xfe000000
+               orr     \base, \base, #0x00e00000
                .endm
 
                .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
diff --git a/arch/arm/mach-shark/include/mach/io.h b/arch/arm/mach-shark/include/mach/io.h
deleted file mode 100644 (file)
index 1a45fc0..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * arch/arm/mach-shark/include/mach/io.h
- *
- * by Alexander Schulz
- *
- * derived from:
- * arch/arm/mach-ebsa110/include/mach/io.h
- * Copyright (C) 1997,1998 Russell King
- */
-
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-#define IO_SPACE_LIMIT 0xffffffff
-
-#define __io(a)                 ((void __iomem *)(0xe0000000 + (a)))
-
-#endif
index 25609076921fc01970ba6319b414bec74168afac..081c778a10ac954a3a11a99716a21762cc5292f0 100644 (file)
 /*
- * arch/arm/mach-shark/leds.c
- * by Alexander Schulz
- *
- * derived from:
- * arch/arm/kernel/leds-footbridge.c
- * Copyright (C) 1998-1999 Russell King
- *
  * DIGITAL Shark LED control routines.
  *
- * The leds use is as follows:
- *  - Green front - toggles state every 50 timer interrupts
- *  - Amber front - Unused, this is a dual color led (Amber/Green)
- *  - Amber back  - On if system is not idle
+ * Driver for the 3 user LEDs found on the Shark
+ * Based on Versatile and RealView machine LED code
  *
- * Changelog:
+ * License terms: GNU General Public License (GPL) version 2
+ * Author: Bryan Wu <bryan.wu@canonical.com>
  */
 #include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/ioport.h>
 #include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/leds.h>
 
-#include <asm/leds.h>
+#include <asm/mach-types.h>
 
-#define LED_STATE_ENABLED      1
-#define LED_STATE_CLAIMED      2
+#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
+struct shark_led {
+       struct led_classdev cdev;
+       u8 mask;
+};
 
-#define SEQUOIA_LED_GREEN       (1<<6)
-#define SEQUOIA_LED_AMBER       (1<<5)
-#define SEQUOIA_LED_BACK        (1<<7)
+/*
+ * The triggers lines up below will only be used if the
+ * LED triggers are compiled in.
+ */
+static const struct {
+       const char *name;
+       const char *trigger;
+} shark_leds[] = {
+       { "shark:amber0", "default-on", },      /* Bit 5 */
+       { "shark:green", "heartbeat", },        /* Bit 6 */
+       { "shark:amber1", "cpu0" },             /* Bit 7 */
+};
+
+static u16 led_reg_read(void)
+{
+       outw(0x09, 0x24);
+       return inw(0x26);
+}
 
-static char led_state;
-static short hw_led_state;
-static short saved_state;
+static void led_reg_write(u16 value)
+{
+       outw(0x09, 0x24);
+       outw(value, 0x26);
+}
 
-static DEFINE_RAW_SPINLOCK(leds_lock);
+static void shark_led_set(struct led_classdev *cdev,
+                             enum led_brightness b)
+{
+       struct shark_led *led = container_of(cdev,
+                                                struct shark_led, cdev);
+       u16 reg = led_reg_read();
 
-short sequoia_read(int addr) {
-  outw(addr,0x24);
-  return inw(0x26);
-}
+       if (b != LED_OFF)
+               reg |= led->mask;
+       else
+               reg &= ~led->mask;
 
-void sequoia_write(short value,short addr) {
-  outw(addr,0x24);
-  outw(value,0x26);
+       led_reg_write(reg);
 }
 
-static void sequoia_leds_event(led_event_t evt)
+static enum led_brightness shark_led_get(struct led_classdev *cdev)
 {
-       unsigned long flags;
-
-       raw_spin_lock_irqsave(&leds_lock, flags);
+       struct shark_led *led = container_of(cdev,
+                                                struct shark_led, cdev);
+       u16 reg = led_reg_read();
 
-       hw_led_state = sequoia_read(0x09);
+       return (reg & led->mask) ? LED_FULL : LED_OFF;
+}
 
-       switch (evt) {
-       case led_start:
-               hw_led_state |= SEQUOIA_LED_GREEN;
-               hw_led_state |= SEQUOIA_LED_AMBER;
-#ifdef CONFIG_LEDS_CPU
-               hw_led_state |= SEQUOIA_LED_BACK;
-#else
-               hw_led_state &= ~SEQUOIA_LED_BACK;
-#endif
-               led_state |= LED_STATE_ENABLED;
-               break;
-
-       case led_stop:
-               hw_led_state &= ~SEQUOIA_LED_BACK;
-               hw_led_state |= SEQUOIA_LED_GREEN;
-               hw_led_state |= SEQUOIA_LED_AMBER;
-               led_state &= ~LED_STATE_ENABLED;
-               break;
-
-       case led_claim:
-               led_state |= LED_STATE_CLAIMED;
-               saved_state = hw_led_state;
-               hw_led_state &= ~SEQUOIA_LED_BACK;
-               hw_led_state |= SEQUOIA_LED_GREEN;
-               hw_led_state |= SEQUOIA_LED_AMBER;
-               break;
-
-       case led_release:
-               led_state &= ~LED_STATE_CLAIMED;
-               hw_led_state = saved_state;
-               break;
-
-#ifdef CONFIG_LEDS_TIMER
-       case led_timer:
-               if (!(led_state & LED_STATE_CLAIMED))
-                       hw_led_state ^= SEQUOIA_LED_GREEN;
-               break;
-#endif
+static int __init shark_leds_init(void)
+{
+       int i;
+       u16 reg;
 
-#ifdef CONFIG_LEDS_CPU
-       case led_idle_start:
-               if (!(led_state & LED_STATE_CLAIMED))
-                       hw_led_state &= ~SEQUOIA_LED_BACK;
-               break;
+       if (!machine_is_shark())
+               return -ENODEV;
 
-       case led_idle_end:
-               if (!(led_state & LED_STATE_CLAIMED))
-                       hw_led_state |= SEQUOIA_LED_BACK;
-               break;
-#endif
+       for (i = 0; i < ARRAY_SIZE(shark_leds); i++) {
+               struct shark_led *led;
 
-       case led_green_on:
-               if (led_state & LED_STATE_CLAIMED)
-                       hw_led_state &= ~SEQUOIA_LED_GREEN;
-               break;
-
-       case led_green_off:
-               if (led_state & LED_STATE_CLAIMED)
-                       hw_led_state |= SEQUOIA_LED_GREEN;
-               break;
-
-       case led_amber_on:
-               if (led_state & LED_STATE_CLAIMED)
-                       hw_led_state &= ~SEQUOIA_LED_AMBER;
-               break;
-
-       case led_amber_off:
-               if (led_state & LED_STATE_CLAIMED)
-                       hw_led_state |= SEQUOIA_LED_AMBER;
-               break;
-
-       case led_red_on:
-               if (led_state & LED_STATE_CLAIMED)
-                       hw_led_state |= SEQUOIA_LED_BACK;
-               break;
-
-       case led_red_off:
-               if (led_state & LED_STATE_CLAIMED)
-                       hw_led_state &= ~SEQUOIA_LED_BACK;
-               break;
-
-       default:
-               break;
-       }
+               led = kzalloc(sizeof(*led), GFP_KERNEL);
+               if (!led)
+                       break;
 
-       if  (led_state & LED_STATE_ENABLED)
-               sequoia_write(hw_led_state,0x09);
+               led->cdev.name = shark_leds[i].name;
+               led->cdev.brightness_set = shark_led_set;
+               led->cdev.brightness_get = shark_led_get;
+               led->cdev.default_trigger = shark_leds[i].trigger;
 
-       raw_spin_unlock_irqrestore(&leds_lock, flags);
-}
+               /* Count in 5 bits offset */
+               led->mask = BIT(i + 5);
 
-static int __init leds_init(void)
-{
-       extern void (*leds_event)(led_event_t);
-       short temp;
-       
-       leds_event = sequoia_leds_event;
+               if (led_classdev_register(NULL, &led->cdev) < 0) {
+                       kfree(led);
+                       break;
+               }
+       }
 
        /* Make LEDs independent of power-state */
-       request_region(0x24,4,"sequoia");
-       temp = sequoia_read(0x09);
-       temp |= 1<<10;
-       sequoia_write(temp,0x09);
-       leds_event(led_start);
+       request_region(0x24, 4, "led_reg");
+       reg = led_reg_read();
+       reg |= 1 << 10;
+       led_reg_write(reg);
+
        return 0;
 }
 
-__initcall(leds_init);
+/*
+ * Since we may have triggers on any subsystem, defer registration
+ * until after subsystem_init.
+ */
+fs_initcall(shark_leds_init);
+#endif
index 9089407d53266327c740707b673b01217b4c536c..b8b4ab323a3ed9a0c6b8ad16c16acc9b1266044d 100644 (file)
@@ -8,12 +8,15 @@
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <video/vga.h>
 
 #include <asm/irq.h>
 #include <asm/mach/pci.h>
 #include <asm/mach-types.h>
 
+#define IO_START       0x40000000
+
 static int __init shark_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        if (dev->bus->number == 0)
@@ -44,6 +47,8 @@ static int __init shark_pci_init(void)
        pcibios_min_mem = 0x50000000;
        vga_base = 0xe8000000;
 
+       pci_ioremap_io(0, IO_START);
+
        pci_common_init(&shark_pci);
 
        return 0;
index 0df5ae6740c6e491895cc20adfda5096437beb74..fe2c97c179d1de40ae6805cce076b46594a22101 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 # Common objects
-obj-y                          := timer.o console.o clock.o common.o
+obj-y                          := timer.o console.o clock.o
 
 # CPU objects
 obj-$(CONFIG_ARCH_SH7367)      += setup-sh7367.o clock-sh7367.o intc-sh7367.o
index f172ca85905cdf68d114d046ea987e43b0570af9..5168a0338cf41c910c86a3d5b1ee2798a4b1956c 100644 (file)
@@ -1229,6 +1229,15 @@ static struct i2c_board_info i2c1_devices[] = {
 #define USCCR1         0xE6058144
 static void __init ap4evb_init(void)
 {
+       struct pm_domain_device domain_devices[] = {
+               { "A4LC", &lcdc1_device, },
+               { "A4LC", &lcdc_device, },
+               { "A4MP", &fsi_device, },
+               { "A3SP", &sh_mmcif_device, },
+               { "A3SP", &sdhi0_device, },
+               { "A3SP", &sdhi1_device, },
+               { "A4R", &ceu_device, },
+       };
        u32 srcr4;
        struct clk *clk;
 
@@ -1461,14 +1470,8 @@ static void __init ap4evb_init(void)
 
        platform_add_devices(ap4evb_devices, ARRAY_SIZE(ap4evb_devices));
 
-       rmobile_add_device_to_domain(&sh7372_pd_a4lc, &lcdc1_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a4lc, &lcdc_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a4mp, &fsi_device);
-
-       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &sh_mmcif_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &sdhi0_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &sdhi1_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a4r, &ceu_device);
+       rmobile_add_devices_to_domains(domain_devices,
+                                      ARRAY_SIZE(domain_devices));
 
        hdmi_init_pm_clock();
        fsi_init_pm_clock();
index cf10f92856dcbb905712024b1d6a00e55c77cf51..28e6e1d0d51152c685b40e2e0acbac6f3a8f5eb0 100644 (file)
@@ -1181,10 +1181,10 @@ static void __init eva_init(void)
 
        eva_clock_init();
 
-       rmobile_add_device_to_domain(&r8a7740_pd_a4lc, &lcdc0_device);
-       rmobile_add_device_to_domain(&r8a7740_pd_a4lc, &hdmi_lcdc_device);
+       rmobile_add_device_to_domain("A4LC", &lcdc0_device);
+       rmobile_add_device_to_domain("A4LC", &hdmi_lcdc_device);
        if (usb)
-               rmobile_add_device_to_domain(&r8a7740_pd_a3sp, usb);
+               rmobile_add_device_to_domain("A3SP", usb);
 }
 
 static void __init eva_earlytimer_init(void)
index 7ea2b31e31991355cb9304dfcafcc4ab6db6f628..d1e8fe83588c6617dfb6d5e5872779d6d34e3bc5 100644 (file)
@@ -1409,6 +1409,22 @@ static struct i2c_board_info i2c1_devices[] = {
 #define USCCR1         0xE6058144
 static void __init mackerel_init(void)
 {
+       struct pm_domain_device domain_devices[] = {
+               { "A4LC", &lcdc_device, },
+               { "A4LC", &hdmi_lcdc_device, },
+               { "A4LC", &meram_device, },
+               { "A4MP", &fsi_device, },
+               { "A3SP", &usbhs0_device, },
+               { "A3SP", &usbhs1_device, },
+               { "A3SP", &nand_flash_device, },
+               { "A3SP", &sh_mmcif_device, },
+               { "A3SP", &sdhi0_device, },
+#if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE)
+               { "A3SP", &sdhi1_device, },
+#endif
+               { "A3SP", &sdhi2_device, },
+               { "A4R", &ceu_device, },
+       };
        u32 srcr4;
        struct clk *clk;
 
@@ -1623,20 +1639,8 @@ static void __init mackerel_init(void)
 
        platform_add_devices(mackerel_devices, ARRAY_SIZE(mackerel_devices));
 
-       rmobile_add_device_to_domain(&sh7372_pd_a4lc, &lcdc_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a4lc, &hdmi_lcdc_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a4lc, &meram_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a4mp, &fsi_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &usbhs0_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &usbhs1_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &nand_flash_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &sh_mmcif_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &sdhi0_device);
-#if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE)
-       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &sdhi1_device);
-#endif
-       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &sdhi2_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a4r, &ceu_device);
+       rmobile_add_devices_to_domains(domain_devices,
+                                      ARRAY_SIZE(domain_devices));
 
        hdmi_init_pm_clock();
        sh7372_pm_init();
diff --git a/arch/arm/mach-shmobile/common.c b/arch/arm/mach-shmobile/common.c
deleted file mode 100644 (file)
index 608aba9..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * 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.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <mach/common.h>
-
-void __init shmobile_init_late(void)
-{
-       shmobile_suspend_init();
-       shmobile_cpuidle_init();
-}
index 7b541e911ab4aebe99262ef74c8ec0fb6084c01c..9e050268cde4d237ab850a532b38c22cdb37c694 100644 (file)
 #include <asm/cpuidle.h>
 #include <asm/io.h>
 
-static void shmobile_enter_wfi(void)
+int shmobile_enter_wfi(struct cpuidle_device *dev, struct cpuidle_driver *drv,
+                      int index)
 {
        cpu_do_idle();
-}
-
-void (*shmobile_cpuidle_modes[CPUIDLE_STATE_MAX])(void) = {
-       shmobile_enter_wfi, /* regular sleep mode */
-};
-
-static int shmobile_cpuidle_enter(struct cpuidle_device *dev,
-                                 struct cpuidle_driver *drv,
-                                 int index)
-{
-       shmobile_cpuidle_modes[index]();
-
-       return index;
+       return 0;
 }
 
 static struct cpuidle_device shmobile_cpuidle_dev;
-static struct cpuidle_driver shmobile_cpuidle_driver = {
+static struct cpuidle_driver shmobile_cpuidle_default_driver = {
        .name                   = "shmobile_cpuidle",
        .owner                  = THIS_MODULE,
        .en_core_tk_irqen       = 1,
        .states[0]              = ARM_CPUIDLE_WFI_STATE,
+       .states[0].enter        = shmobile_enter_wfi,
        .safe_state_index       = 0, /* C1 */
        .state_count            = 1,
 };
 
-void (*shmobile_cpuidle_setup)(struct cpuidle_driver *drv);
+static struct cpuidle_driver *cpuidle_drv = &shmobile_cpuidle_default_driver;
+
+void shmobile_cpuidle_set_driver(struct cpuidle_driver *drv)
+{
+       cpuidle_drv = drv;
+}
 
 int shmobile_cpuidle_init(void)
 {
        struct cpuidle_device *dev = &shmobile_cpuidle_dev;
-       struct cpuidle_driver *drv = &shmobile_cpuidle_driver;
-       int i;
-
-       for (i = 0; i < CPUIDLE_STATE_MAX; i++)
-               drv->states[i].enter = shmobile_cpuidle_enter;
-
-       if (shmobile_cpuidle_setup)
-               shmobile_cpuidle_setup(drv);
 
-       cpuidle_register_driver(drv);
+       cpuidle_register_driver(cpuidle_drv);
 
-       dev->state_count = drv->state_count;
+       dev->state_count = cpuidle_drv->state_count;
        cpuidle_register_device(dev);
 
        return 0;
index 45e61dada030ba263fd721d4210d477e8664faba..eb89293fff4d36068a7fc3baf305bd7010209799 100644 (file)
@@ -14,8 +14,10 @@ extern int shmobile_clk_init(void);
 extern void shmobile_handle_irq_intc(struct pt_regs *);
 extern struct platform_suspend_ops shmobile_suspend_ops;
 struct cpuidle_driver;
-extern void (*shmobile_cpuidle_modes[])(void);
-extern void (*shmobile_cpuidle_setup)(struct cpuidle_driver *drv);
+struct cpuidle_device;
+extern int shmobile_enter_wfi(struct cpuidle_device *dev,
+                             struct cpuidle_driver *drv, int index);
+extern void shmobile_cpuidle_set_driver(struct cpuidle_driver *drv);
 
 extern void sh7367_init_irq(void);
 extern void sh7367_map_io(void);
@@ -86,8 +88,6 @@ extern int r8a7779_boot_secondary(unsigned int cpu);
 extern void r8a7779_smp_prepare_cpus(void);
 extern void r8a7779_register_twd(void);
 
-extern void shmobile_init_late(void);
-
 #ifdef CONFIG_SUSPEND
 int shmobile_suspend_init(void);
 #else
@@ -100,4 +100,10 @@ int shmobile_cpuidle_init(void);
 static inline int shmobile_cpuidle_init(void) { return 0; }
 #endif
 
+static inline void shmobile_init_late(void)
+{
+       shmobile_suspend_init();
+       shmobile_cpuidle_init();
+}
+
 #endif /* __ARCH_MACH_COMMON_H */
index 5a402840fe28afe2d630e8496d1edb6a69b0a9d8..690553a06887897a6c29ffb396ba60bafb29be8e 100644 (file)
@@ -12,6 +12,8 @@
 
 #include <linux/pm_domain.h>
 
+#define DEFAULT_DEV_LATENCY_NS 250000
+
 struct platform_device;
 
 struct rmobile_pm_domain {
@@ -29,16 +31,33 @@ struct rmobile_pm_domain *to_rmobile_pd(struct generic_pm_domain *d)
        return container_of(d, struct rmobile_pm_domain, genpd);
 }
 
+struct pm_domain_device {
+       const char *domain_name;
+       struct platform_device *pdev;
+};
+
 #ifdef CONFIG_PM
-extern void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd);
-extern void rmobile_add_device_to_domain(struct rmobile_pm_domain *rmobile_pd,
-                                       struct platform_device *pdev);
-extern void rmobile_pm_add_subdomain(struct rmobile_pm_domain *rmobile_pd,
-                                   struct rmobile_pm_domain *rmobile_sd);
+extern void rmobile_init_domains(struct rmobile_pm_domain domains[], int num);
+extern void rmobile_add_device_to_domain_td(const char *domain_name,
+                                           struct platform_device *pdev,
+                                           struct gpd_timing_data *td);
+
+static inline void rmobile_add_device_to_domain(const char *domain_name,
+                                               struct platform_device *pdev)
+{
+       rmobile_add_device_to_domain_td(domain_name, pdev, NULL);
+}
+
+extern void rmobile_add_devices_to_domains(struct pm_domain_device data[],
+                                          int size);
 #else
-#define rmobile_init_pm_domain(pd) do { } while (0)
-#define rmobile_add_device_to_domain(pd, pdev) do { } while (0)
-#define rmobile_pm_add_subdomain(pd, sd) do { } while (0)
+
+#define rmobile_init_domains(domains, num) do { } while (0)
+#define rmobile_add_device_to_domain_td(name, pdev, td) do { } while (0)
+#define rmobile_add_device_to_domain(name, pdev) do { } while (0)
+
+static inline void rmobile_add_devices_to_domains(struct pm_domain_device d[],
+                                                 int size) {}
 #endif /* CONFIG_PM */
 
 #endif /* PM_RMOBILE_H */
index 7143147780df55f6e17a689e9cc67ed2a9cd17e9..59d252f4cf975b3ecd64ffde955f8e6f387f7651 100644 (file)
@@ -607,9 +607,9 @@ enum {
 };
 
 #ifdef CONFIG_PM
-extern struct rmobile_pm_domain r8a7740_pd_a4s;
-extern struct rmobile_pm_domain r8a7740_pd_a3sp;
-extern struct rmobile_pm_domain r8a7740_pd_a4lc;
+extern void __init r8a7740_init_pm_domains(void);
+#else
+static inline void r8a7740_init_pm_domains(void) {}
 #endif /* CONFIG_PM */
 
 #endif /* __ASM_R8A7740_H__ */
index b07ad318eb2ec47577b2893bd9e8a7ba71c39d3d..7ad47977d2e7ba15e1b0674b0b96c292e050dd3d 100644 (file)
@@ -347,17 +347,9 @@ extern int r8a7779_sysc_power_down(struct r8a7779_pm_ch *r8a7779_ch);
 extern int r8a7779_sysc_power_up(struct r8a7779_pm_ch *r8a7779_ch);
 
 #ifdef CONFIG_PM
-extern struct r8a7779_pm_domain r8a7779_sh4a;
-extern struct r8a7779_pm_domain r8a7779_sgx;
-extern struct r8a7779_pm_domain r8a7779_vdp1;
-extern struct r8a7779_pm_domain r8a7779_impx3;
-
-extern void r8a7779_init_pm_domain(struct r8a7779_pm_domain *r8a7779_pd);
-extern void r8a7779_add_device_to_domain(struct r8a7779_pm_domain *r8a7779_pd,
-                                       struct platform_device *pdev);
+extern void __init r8a7779_init_pm_domains(void);
 #else
-#define r8a7779_init_pm_domain(pd) do { } while (0)
-#define r8a7779_add_device_to_domain(pd, pdev) do { } while (0)
+static inline void r8a7779_init_pm_domains(void) {}
 #endif /* CONFIG_PM */
 
 #endif /* __ASM_R8A7779_H__ */
index b59048e6d8fd7302717b9bb4f9359eae95ce10e5..40beb796d020cf8c03331638eac3c91e1550c002 100644 (file)
@@ -478,21 +478,15 @@ extern struct clk sh7372_fsibck_clk;
 extern struct clk sh7372_fsidiva_clk;
 extern struct clk sh7372_fsidivb_clk;
 
-#ifdef CONFIG_PM
-extern struct rmobile_pm_domain sh7372_pd_a4lc;
-extern struct rmobile_pm_domain sh7372_pd_a4mp;
-extern struct rmobile_pm_domain sh7372_pd_d4;
-extern struct rmobile_pm_domain sh7372_pd_a4r;
-extern struct rmobile_pm_domain sh7372_pd_a3rv;
-extern struct rmobile_pm_domain sh7372_pd_a3ri;
-extern struct rmobile_pm_domain sh7372_pd_a4s;
-extern struct rmobile_pm_domain sh7372_pd_a3sp;
-extern struct rmobile_pm_domain sh7372_pd_a3sg;
-#endif /* CONFIG_PM */
-
 extern void sh7372_intcs_suspend(void);
 extern void sh7372_intcs_resume(void);
 extern void sh7372_intca_suspend(void);
 extern void sh7372_intca_resume(void);
 
+#ifdef CONFIG_PM
+extern void __init sh7372_init_pm_domains(void);
+#else
+static inline void sh7372_init_pm_domains(void) {}
+#endif
+
 #endif /* __ASM_SH7372_H__ */
index 893504d012a6bb98b583b1660b156325496eabf0..21e5316d2d881aea42b507334b9fcedd139c760d 100644 (file)
@@ -21,14 +21,6 @@ static int r8a7740_pd_a4s_suspend(void)
        return -EBUSY;
 }
 
-struct rmobile_pm_domain r8a7740_pd_a4s = {
-       .genpd.name     = "A4S",
-       .bit_shift      = 10,
-       .gov            = &pm_domain_always_on_gov,
-       .no_debug       = true,
-       .suspend        = r8a7740_pd_a4s_suspend,
-};
-
 static int r8a7740_pd_a3sp_suspend(void)
 {
        /*
@@ -38,17 +30,31 @@ static int r8a7740_pd_a3sp_suspend(void)
        return console_suspend_enabled ? 0 : -EBUSY;
 }
 
-struct rmobile_pm_domain r8a7740_pd_a3sp = {
-       .genpd.name     = "A3SP",
-       .bit_shift      = 11,
-       .gov            = &pm_domain_always_on_gov,
-       .no_debug       = true,
-       .suspend        = r8a7740_pd_a3sp_suspend,
+static struct rmobile_pm_domain r8a7740_pm_domains[] = {
+       {
+               .genpd.name     = "A4S",
+               .bit_shift      = 10,
+               .gov            = &pm_domain_always_on_gov,
+               .no_debug       = true,
+               .suspend        = r8a7740_pd_a4s_suspend,
+       },
+       {
+               .genpd.name     = "A3SP",
+               .bit_shift      = 11,
+               .gov            = &pm_domain_always_on_gov,
+               .no_debug       = true,
+               .suspend        = r8a7740_pd_a3sp_suspend,
+       },
+       {
+               .genpd.name     = "A4LC",
+               .bit_shift      = 1,
+       },
 };
 
-struct rmobile_pm_domain r8a7740_pd_a4lc = {
-       .genpd.name     = "A4LC",
-       .bit_shift      = 1,
-};
+void __init r8a7740_init_pm_domains(void)
+{
+       rmobile_init_domains(r8a7740_pm_domains, ARRAY_SIZE(r8a7740_pm_domains));
+       pm_genpd_add_subdomain_names("A4S", "A3SP");
+}
 
 #endif /* CONFIG_PM */
index a18a4ae16d2bf7ff9072cda4bb70eae8392cf9f1..d50a8e9b94a4f9ac7030bdc49dc5450674e5af9a 100644 (file)
@@ -183,7 +183,7 @@ static bool pd_active_wakeup(struct device *dev)
        return true;
 }
 
-void r8a7779_init_pm_domain(struct r8a7779_pm_domain *r8a7779_pd)
+static void r8a7779_init_pm_domain(struct r8a7779_pm_domain *r8a7779_pd)
 {
        struct generic_pm_domain *genpd = &r8a7779_pd->genpd;
 
@@ -199,43 +199,44 @@ void r8a7779_init_pm_domain(struct r8a7779_pm_domain *r8a7779_pd)
                pd_power_up(&r8a7779_pd->genpd);
 }
 
-void r8a7779_add_device_to_domain(struct r8a7779_pm_domain *r8a7779_pd,
-                                struct platform_device *pdev)
-{
-       struct device *dev = &pdev->dev;
-
-       pm_genpd_add_device(&r8a7779_pd->genpd, dev);
-       if (pm_clk_no_clocks(dev))
-               pm_clk_add(dev, NULL);
-}
-
-struct r8a7779_pm_domain r8a7779_sh4a = {
-       .ch = {
-               .chan_offs = 0x80, /* PWRSR1 .. PWRER1 */
-               .isr_bit = 16, /* SH4A */
-       }
-};
-
-struct r8a7779_pm_domain r8a7779_sgx = {
-       .ch = {
-               .chan_offs = 0xc0, /* PWRSR2 .. PWRER2 */
-               .isr_bit = 20, /* SGX */
-       }
+static struct r8a7779_pm_domain r8a7779_pm_domains[] = {
+       {
+               .genpd.name = "SH4A",
+               .ch = {
+                       .chan_offs = 0x80, /* PWRSR1 .. PWRER1 */
+                       .isr_bit = 16, /* SH4A */
+               },
+       },
+       {
+               .genpd.name = "SGX",
+               .ch = {
+                       .chan_offs = 0xc0, /* PWRSR2 .. PWRER2 */
+                       .isr_bit = 20, /* SGX */
+               },
+       },
+       {
+               .genpd.name = "VDP1",
+               .ch = {
+                       .chan_offs = 0x100, /* PWRSR3 .. PWRER3 */
+                       .isr_bit = 21, /* VDP */
+               },
+       },
+       {
+               .genpd.name = "IMPX3",
+               .ch = {
+                       .chan_offs = 0x140, /* PWRSR4 .. PWRER4 */
+                       .isr_bit = 24, /* IMP */
+               },
+       },
 };
 
-struct r8a7779_pm_domain r8a7779_vdp1 = {
-       .ch = {
-               .chan_offs = 0x100, /* PWRSR3 .. PWRER3 */
-               .isr_bit = 21, /* VDP */
-       }
-};
+void __init r8a7779_init_pm_domains(void)
+{
+       int j;
 
-struct r8a7779_pm_domain r8a7779_impx3 = {
-       .ch = {
-               .chan_offs = 0x140, /* PWRSR4 .. PWRER4 */
-               .isr_bit = 24, /* IMP */
-       }
-};
+       for (j = 0; j < ARRAY_SIZE(r8a7779_pm_domains); j++)
+               r8a7779_init_pm_domain(&r8a7779_pm_domains[j]);
+}
 
 #endif /* CONFIG_PM */
 
index a8562540f1d64f44cd87d12960e2f82d4440a69d..d37d368434da84399c6159295c397dc10f652158 100644 (file)
@@ -134,7 +134,7 @@ static int rmobile_pd_start_dev(struct device *dev)
        return ret;
 }
 
-void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd)
+static void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd)
 {
        struct generic_pm_domain *genpd = &rmobile_pd->genpd;
        struct dev_power_governor *gov = rmobile_pd->gov;
@@ -149,19 +149,38 @@ void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd)
        __rmobile_pd_power_up(rmobile_pd, false);
 }
 
-void rmobile_add_device_to_domain(struct rmobile_pm_domain *rmobile_pd,
-                                struct platform_device *pdev)
+void rmobile_init_domains(struct rmobile_pm_domain domains[], int num)
+{
+       int j;
+
+       for (j = 0; j < num; j++)
+               rmobile_init_pm_domain(&domains[j]);
+}
+
+void rmobile_add_device_to_domain_td(const char *domain_name,
+                                    struct platform_device *pdev,
+                                    struct gpd_timing_data *td)
 {
        struct device *dev = &pdev->dev;
 
-       pm_genpd_add_device(&rmobile_pd->genpd, dev);
+       __pm_genpd_name_add_device(domain_name, dev, td);
        if (pm_clk_no_clocks(dev))
                pm_clk_add(dev, NULL);
 }
 
-void rmobile_pm_add_subdomain(struct rmobile_pm_domain *rmobile_pd,
-                            struct rmobile_pm_domain *rmobile_sd)
+void rmobile_add_devices_to_domains(struct pm_domain_device data[],
+                                   int size)
 {
-       pm_genpd_add_subdomain(&rmobile_pd->genpd, &rmobile_sd->genpd);
+       struct gpd_timing_data latencies = {
+               .stop_latency_ns = DEFAULT_DEV_LATENCY_NS,
+               .start_latency_ns = DEFAULT_DEV_LATENCY_NS,
+               .save_state_latency_ns = DEFAULT_DEV_LATENCY_NS,
+               .restore_state_latency_ns = DEFAULT_DEV_LATENCY_NS,
+       };
+       int j;
+
+       for (j = 0; j < size; j++)
+               rmobile_add_device_to_domain_td(data[j].domain_name,
+                                               data[j].pdev, &latencies);
 }
 #endif /* CONFIG_PM */
index 79203706922651dad75595869802fa3520c78a8c..5cafd35cc411c6a4c17e036007cd9ddcfed3adcc 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/irq.h>
 #include <linux/bitrev.h>
 #include <linux/console.h>
+#include <asm/cpuidle.h>
 #include <asm/io.h>
 #include <asm/tlbflush.h>
 #include <asm/suspend.h>
 
 #ifdef CONFIG_PM
 
-struct rmobile_pm_domain sh7372_pd_a4lc = {
-       .genpd.name = "A4LC",
-       .bit_shift = 1,
-};
-
-struct rmobile_pm_domain sh7372_pd_a4mp = {
-       .genpd.name = "A4MP",
-       .bit_shift = 2,
-};
-
-struct rmobile_pm_domain sh7372_pd_d4 = {
-       .genpd.name = "D4",
-       .bit_shift = 3,
-};
+#define PM_DOMAIN_ON_OFF_LATENCY_NS    250000
 
 static int sh7372_a4r_pd_suspend(void)
 {
@@ -93,39 +81,25 @@ static int sh7372_a4r_pd_suspend(void)
        return 0;
 }
 
-struct rmobile_pm_domain sh7372_pd_a4r = {
-       .genpd.name = "A4R",
-       .bit_shift = 5,
-       .suspend = sh7372_a4r_pd_suspend,
-       .resume = sh7372_intcs_resume,
-};
-
-struct rmobile_pm_domain sh7372_pd_a3rv = {
-       .genpd.name = "A3RV",
-       .bit_shift = 6,
-};
-
-struct rmobile_pm_domain sh7372_pd_a3ri = {
-       .genpd.name = "A3RI",
-       .bit_shift = 8,
-};
+static bool a4s_suspend_ready;
 
-static int sh7372_pd_a4s_suspend(void)
+static int sh7372_a4s_pd_suspend(void)
 {
        /*
         * The A4S domain contains the CPU core and therefore it should
-        * only be turned off if the CPU is in use.
+        * only be turned off if the CPU is not in use.  This may happen
+        * during system suspend, when SYSC is going to be used for generating
+        * resume signals and a4s_suspend_ready is set to let
+        * sh7372_enter_suspend() know that it can turn A4S off.
         */
+       a4s_suspend_ready = true;
        return -EBUSY;
 }
 
-struct rmobile_pm_domain sh7372_pd_a4s = {
-       .genpd.name = "A4S",
-       .bit_shift = 10,
-       .gov = &pm_domain_always_on_gov,
-       .no_debug = true,
-       .suspend = sh7372_pd_a4s_suspend,
-};
+static void sh7372_a4s_pd_resume(void)
+{
+       a4s_suspend_ready = false;
+}
 
 static int sh7372_a3sp_pd_suspend(void)
 {
@@ -136,18 +110,80 @@ static int sh7372_a3sp_pd_suspend(void)
        return console_suspend_enabled ? 0 : -EBUSY;
 }
 
-struct rmobile_pm_domain sh7372_pd_a3sp = {
-       .genpd.name = "A3SP",
-       .bit_shift = 11,
-       .gov = &pm_domain_always_on_gov,
-       .no_debug = true,
-       .suspend = sh7372_a3sp_pd_suspend,
+static struct rmobile_pm_domain sh7372_pm_domains[] = {
+       {
+               .genpd.name = "A4LC",
+               .genpd.power_on_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+               .genpd.power_off_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+               .bit_shift = 1,
+       },
+       {
+               .genpd.name = "A4MP",
+               .genpd.power_on_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+               .genpd.power_off_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+               .bit_shift = 2,
+       },
+       {
+               .genpd.name = "D4",
+               .genpd.power_on_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+               .genpd.power_off_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+               .bit_shift = 3,
+       },
+       {
+               .genpd.name = "A4R",
+               .genpd.power_on_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+               .genpd.power_off_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+               .bit_shift = 5,
+               .suspend = sh7372_a4r_pd_suspend,
+               .resume = sh7372_intcs_resume,
+       },
+       {
+               .genpd.name = "A3RV",
+               .genpd.power_on_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+               .genpd.power_off_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+               .bit_shift = 6,
+       },
+       {
+               .genpd.name = "A3RI",
+               .genpd.power_on_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+               .genpd.power_off_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+               .bit_shift = 8,
+       },
+       {
+               .genpd.name = "A4S",
+               .genpd.power_on_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+               .genpd.power_off_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+               .bit_shift = 10,
+               .gov = &pm_domain_always_on_gov,
+               .no_debug = true,
+               .suspend = sh7372_a4s_pd_suspend,
+               .resume = sh7372_a4s_pd_resume,
+       },
+       {
+               .genpd.name = "A3SP",
+               .genpd.power_on_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+               .genpd.power_off_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+               .bit_shift = 11,
+               .gov = &pm_domain_always_on_gov,
+               .no_debug = true,
+               .suspend = sh7372_a3sp_pd_suspend,
+       },
+       {
+               .genpd.name = "A3SG",
+               .genpd.power_on_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+               .genpd.power_off_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
+               .bit_shift = 13,
+       },
 };
 
-struct rmobile_pm_domain sh7372_pd_a3sg = {
-       .genpd.name = "A3SG",
-       .bit_shift = 13,
-};
+void __init sh7372_init_pm_domains(void)
+{
+       rmobile_init_domains(sh7372_pm_domains, ARRAY_SIZE(sh7372_pm_domains));
+       pm_genpd_add_subdomain_names("A4LC", "A3RV");
+       pm_genpd_add_subdomain_names("A4R", "A4LC");
+       pm_genpd_add_subdomain_names("A4S", "A3SG");
+       pm_genpd_add_subdomain_names("A4S", "A3SP");
+}
 
 #endif /* CONFIG_PM */
 
@@ -312,7 +348,8 @@ static int sh7372_do_idle_core_standby(unsigned long unused)
        return 0;
 }
 
-static void sh7372_enter_core_standby(void)
+static int sh7372_enter_core_standby(struct cpuidle_device *dev,
+                                    struct cpuidle_driver *drv, int index)
 {
        sh7372_set_reset_vector(__pa(sh7372_resume_core_standby_sysc));
 
@@ -323,52 +360,61 @@ static void sh7372_enter_core_standby(void)
 
         /* disable reset vector translation */
        __raw_writel(0, SBAR);
+
+       return 1;
 }
 
-static void sh7372_enter_a3sm_pll_on(void)
+static int sh7372_enter_a3sm_pll_on(struct cpuidle_device *dev,
+                                   struct cpuidle_driver *drv, int index)
 {
        sh7372_enter_a3sm_common(1);
+       return 2;
 }
 
-static void sh7372_enter_a3sm_pll_off(void)
+static int sh7372_enter_a3sm_pll_off(struct cpuidle_device *dev,
+                                    struct cpuidle_driver *drv, int index)
 {
        sh7372_enter_a3sm_common(0);
+       return 3;
 }
 
-static void sh7372_cpuidle_setup(struct cpuidle_driver *drv)
-{
-       struct cpuidle_state *state = &drv->states[drv->state_count];
-
-       snprintf(state->name, CPUIDLE_NAME_LEN, "C2");
-       strncpy(state->desc, "Core Standby Mode", CPUIDLE_DESC_LEN);
-       state->exit_latency = 10;
-       state->target_residency = 20 + 10;
-       state->flags = CPUIDLE_FLAG_TIME_VALID;
-       shmobile_cpuidle_modes[drv->state_count] = sh7372_enter_core_standby;
-       drv->state_count++;
-
-       state = &drv->states[drv->state_count];
-       snprintf(state->name, CPUIDLE_NAME_LEN, "C3");
-       strncpy(state->desc, "A3SM PLL ON", CPUIDLE_DESC_LEN);
-       state->exit_latency = 20;
-       state->target_residency = 30 + 20;
-       state->flags = CPUIDLE_FLAG_TIME_VALID;
-       shmobile_cpuidle_modes[drv->state_count] = sh7372_enter_a3sm_pll_on;
-       drv->state_count++;
-
-       state = &drv->states[drv->state_count];
-       snprintf(state->name, CPUIDLE_NAME_LEN, "C4");
-       strncpy(state->desc, "A3SM PLL OFF", CPUIDLE_DESC_LEN);
-       state->exit_latency = 120;
-       state->target_residency = 30 + 120;
-       state->flags = CPUIDLE_FLAG_TIME_VALID;
-       shmobile_cpuidle_modes[drv->state_count] = sh7372_enter_a3sm_pll_off;
-       drv->state_count++;
-}
+static struct cpuidle_driver sh7372_cpuidle_driver = {
+       .name                   = "sh7372_cpuidle",
+       .owner                  = THIS_MODULE,
+       .en_core_tk_irqen       = 1,
+       .state_count            = 4,
+       .safe_state_index       = 0, /* C1 */
+       .states[0] = ARM_CPUIDLE_WFI_STATE,
+       .states[0].enter = shmobile_enter_wfi,
+       .states[1] = {
+               .name = "C2",
+               .desc = "Core Standby Mode",
+               .exit_latency = 10,
+               .target_residency = 20 + 10,
+               .flags = CPUIDLE_FLAG_TIME_VALID,
+               .enter = sh7372_enter_core_standby,
+       },
+       .states[2] = {
+               .name = "C3",
+               .desc = "A3SM PLL ON",
+               .exit_latency = 20,
+               .target_residency = 30 + 20,
+               .flags = CPUIDLE_FLAG_TIME_VALID,
+               .enter = sh7372_enter_a3sm_pll_on,
+       },
+       .states[3] = {
+               .name = "C4",
+               .desc = "A3SM PLL OFF",
+               .exit_latency = 120,
+               .target_residency = 30 + 120,
+               .flags = CPUIDLE_FLAG_TIME_VALID,
+               .enter = sh7372_enter_a3sm_pll_off,
+       },
+};
 
 static void sh7372_cpuidle_init(void)
 {
-       shmobile_cpuidle_setup = sh7372_cpuidle_setup;
+       shmobile_cpuidle_set_driver(&sh7372_cpuidle_driver);
 }
 #else
 static void sh7372_cpuidle_init(void) {}
@@ -389,17 +435,14 @@ static int sh7372_enter_suspend(suspend_state_t suspend_state)
        unsigned long msk, msk2;
 
        /* check active clocks to determine potential wakeup sources */
-       if (sh7372_sysc_valid(&msk, &msk2)) {
-               if (!console_suspend_enabled &&
-                   sh7372_pd_a4s.genpd.status == GPD_STATE_POWER_OFF) {
-                       /* convert INTC mask/sense to SYSC mask/sense */
-                       sh7372_setup_sysc(msk, msk2);
-
-                       /* enter A4S sleep with PLLC0 off */
-                       pr_debug("entering A4S\n");
-                       sh7372_enter_a4s_common(0);
-                       return 0;
-               }
+       if (sh7372_sysc_valid(&msk, &msk2) && a4s_suspend_ready) {
+               /* convert INTC mask/sense to SYSC mask/sense */
+               sh7372_setup_sysc(msk, msk2);
+
+               /* enter A4S sleep with PLLC0 off */
+               pr_debug("entering A4S\n");
+               sh7372_enter_a4s_common(0);
+               return 0;
        }
 
        /* default to enter A3SM sleep with PLLC0 off */
@@ -425,7 +468,7 @@ static int sh7372_pm_notifier_fn(struct notifier_block *notifier,
                 * executed during system suspend and resume, respectively, so
                 * that those functions don't crash while accessing the INTCS.
                 */
-               pm_genpd_poweron(&sh7372_pd_a4r.genpd);
+               pm_genpd_name_poweron("A4R");
                break;
        case PM_POST_SUSPEND:
                pm_genpd_poweroff_unused();
index 78948a9dba0ec47547f5fca10b7aa71452600d7b..11bb1d9841975ef9be12c1591fae32c80903b55e 100644 (file)
@@ -673,12 +673,7 @@ void __init r8a7740_add_standard_devices(void)
        r8a7740_i2c_workaround(&i2c0_device);
        r8a7740_i2c_workaround(&i2c1_device);
 
-       /* PM domain */
-       rmobile_init_pm_domain(&r8a7740_pd_a4s);
-       rmobile_init_pm_domain(&r8a7740_pd_a3sp);
-       rmobile_init_pm_domain(&r8a7740_pd_a4lc);
-
-       rmobile_pm_add_subdomain(&r8a7740_pd_a4s, &r8a7740_pd_a3sp);
+       r8a7740_init_pm_domains();
 
        /* add devices */
        platform_add_devices(r8a7740_early_devices,
@@ -688,16 +683,16 @@ void __init r8a7740_add_standard_devices(void)
 
        /* add devices to PM domain  */
 
-       rmobile_add_device_to_domain(&r8a7740_pd_a3sp,  &scif0_device);
-       rmobile_add_device_to_domain(&r8a7740_pd_a3sp,  &scif1_device);
-       rmobile_add_device_to_domain(&r8a7740_pd_a3sp,  &scif2_device);
-       rmobile_add_device_to_domain(&r8a7740_pd_a3sp,  &scif3_device);
-       rmobile_add_device_to_domain(&r8a7740_pd_a3sp,  &scif4_device);
-       rmobile_add_device_to_domain(&r8a7740_pd_a3sp,  &scif5_device);
-       rmobile_add_device_to_domain(&r8a7740_pd_a3sp,  &scif6_device);
-       rmobile_add_device_to_domain(&r8a7740_pd_a3sp,  &scif7_device);
-       rmobile_add_device_to_domain(&r8a7740_pd_a3sp,  &scifb_device);
-       rmobile_add_device_to_domain(&r8a7740_pd_a3sp,  &i2c1_device);
+       rmobile_add_device_to_domain("A3SP",    &scif0_device);
+       rmobile_add_device_to_domain("A3SP",    &scif1_device);
+       rmobile_add_device_to_domain("A3SP",    &scif2_device);
+       rmobile_add_device_to_domain("A3SP",    &scif3_device);
+       rmobile_add_device_to_domain("A3SP",    &scif4_device);
+       rmobile_add_device_to_domain("A3SP",    &scif5_device);
+       rmobile_add_device_to_domain("A3SP",    &scif6_device);
+       rmobile_add_device_to_domain("A3SP",    &scif7_device);
+       rmobile_add_device_to_domain("A3SP",    &scifb_device);
+       rmobile_add_device_to_domain("A3SP",    &i2c1_device);
 }
 
 static void __init r8a7740_earlytimer_init(void)
index e98e46f6cf5508f8b1750c7abb2b2effd45a80db..2917668f0091c1042a70e512f50c12bacdb3ebb2 100644 (file)
@@ -251,10 +251,7 @@ void __init r8a7779_add_standard_devices(void)
 #endif
        r8a7779_pm_init();
 
-       r8a7779_init_pm_domain(&r8a7779_sh4a);
-       r8a7779_init_pm_domain(&r8a7779_sgx);
-       r8a7779_init_pm_domain(&r8a7779_vdp1);
-       r8a7779_init_pm_domain(&r8a7779_impx3);
+       r8a7779_init_pm_domains();
 
        platform_add_devices(r8a7779_early_devices,
                            ARRAY_SIZE(r8a7779_early_devices));
index 838a87be1d5c31cc46a932d58f27a73f00066ca9..a07954fbcd22b9017b588ef1f745bddf101bf419 100644 (file)
@@ -1001,21 +1001,34 @@ static struct platform_device *sh7372_late_devices[] __initdata = {
 
 void __init sh7372_add_standard_devices(void)
 {
-       rmobile_init_pm_domain(&sh7372_pd_a4lc);
-       rmobile_init_pm_domain(&sh7372_pd_a4mp);
-       rmobile_init_pm_domain(&sh7372_pd_d4);
-       rmobile_init_pm_domain(&sh7372_pd_a4r);
-       rmobile_init_pm_domain(&sh7372_pd_a3rv);
-       rmobile_init_pm_domain(&sh7372_pd_a3ri);
-       rmobile_init_pm_domain(&sh7372_pd_a4s);
-       rmobile_init_pm_domain(&sh7372_pd_a3sp);
-       rmobile_init_pm_domain(&sh7372_pd_a3sg);
-
-       rmobile_pm_add_subdomain(&sh7372_pd_a4lc, &sh7372_pd_a3rv);
-       rmobile_pm_add_subdomain(&sh7372_pd_a4r, &sh7372_pd_a4lc);
-
-       rmobile_pm_add_subdomain(&sh7372_pd_a4s, &sh7372_pd_a3sg);
-       rmobile_pm_add_subdomain(&sh7372_pd_a4s, &sh7372_pd_a3sp);
+       struct pm_domain_device domain_devices[] = {
+               { "A3RV", &vpu_device, },
+               { "A4MP", &spu0_device, },
+               { "A4MP", &spu1_device, },
+               { "A3SP", &scif0_device, },
+               { "A3SP", &scif1_device, },
+               { "A3SP", &scif2_device, },
+               { "A3SP", &scif3_device, },
+               { "A3SP", &scif4_device, },
+               { "A3SP", &scif5_device, },
+               { "A3SP", &scif6_device, },
+               { "A3SP", &iic1_device, },
+               { "A3SP", &dma0_device, },
+               { "A3SP", &dma1_device, },
+               { "A3SP", &dma2_device, },
+               { "A3SP", &usb_dma0_device, },
+               { "A3SP", &usb_dma1_device, },
+               { "A4R", &iic0_device, },
+               { "A4R", &veu0_device, },
+               { "A4R", &veu1_device, },
+               { "A4R", &veu2_device, },
+               { "A4R", &veu3_device, },
+               { "A4R", &jpu_device, },
+               { "A4R", &tmu00_device, },
+               { "A4R", &tmu01_device, },
+       };
+
+       sh7372_init_pm_domains();
 
        platform_add_devices(sh7372_early_devices,
                            ARRAY_SIZE(sh7372_early_devices));
@@ -1023,30 +1036,8 @@ void __init sh7372_add_standard_devices(void)
        platform_add_devices(sh7372_late_devices,
                            ARRAY_SIZE(sh7372_late_devices));
 
-       rmobile_add_device_to_domain(&sh7372_pd_a3rv, &vpu_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a4mp, &spu0_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a4mp, &spu1_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &scif0_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &scif1_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &scif2_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &scif3_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &scif4_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &scif5_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &scif6_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &iic1_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &dma0_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &dma1_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &dma2_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &usb_dma0_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a3sp, &usb_dma1_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a4r, &iic0_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a4r, &veu0_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a4r, &veu1_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a4r, &veu2_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a4r, &veu3_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a4r, &jpu_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a4r, &tmu00_device);
-       rmobile_add_device_to_domain(&sh7372_pd_a4r, &tmu01_device);
+       rmobile_add_devices_to_domains(domain_devices,
+                                      ARRAY_SIZE(domain_devices));
 }
 
 static void __init sh7372_earlytimer_init(void)
index 8fd387bf31f0c66a27b313d3b5edc8bd976e3d0a..b7344beec102b109d4d013b4db47a1ab56d90e42 100644 (file)
@@ -51,7 +51,7 @@ static struct regulator_init_data ldo0_data = {
        .consumer_supplies = tps658621_ldo0_supply,
 };
 
-#define HARMONY_REGULATOR_INIT(_id, _name, _supply, _minmv, _maxmv)    \
+#define HARMONY_REGULATOR_INIT(_id, _name, _supply, _minmv, _maxmv, _on)\
        static struct regulator_init_data _id##_data = {                \
                .supply_regulator = _supply,                            \
                .constraints = {                                        \
@@ -63,21 +63,22 @@ static struct regulator_init_data ldo0_data = {
                        .valid_ops_mask = (REGULATOR_CHANGE_MODE |      \
                                           REGULATOR_CHANGE_STATUS |    \
                                           REGULATOR_CHANGE_VOLTAGE),   \
+                       .always_on = _on,                               \
                },                                                      \
        }
 
-HARMONY_REGULATOR_INIT(sm0,  "vdd_sm0",  "vdd_sys", 725, 1500);
-HARMONY_REGULATOR_INIT(sm1,  "vdd_sm1",  "vdd_sys", 725, 1500);
-HARMONY_REGULATOR_INIT(sm2,  "vdd_sm2",  "vdd_sys", 3000, 4550);
-HARMONY_REGULATOR_INIT(ldo1, "vdd_ldo1", "vdd_sm2", 725, 1500);
-HARMONY_REGULATOR_INIT(ldo2, "vdd_ldo2", "vdd_sm2", 725, 1500);
-HARMONY_REGULATOR_INIT(ldo3, "vdd_ldo3", "vdd_sm2", 1250, 3300);
-HARMONY_REGULATOR_INIT(ldo4, "vdd_ldo4", "vdd_sm2", 1700, 2475);
-HARMONY_REGULATOR_INIT(ldo5, "vdd_ldo5", NULL,     1250, 3300);
-HARMONY_REGULATOR_INIT(ldo6, "vdd_ldo6", "vdd_sm2", 1250, 3300);
-HARMONY_REGULATOR_INIT(ldo7, "vdd_ldo7", "vdd_sm2", 1250, 3300);
-HARMONY_REGULATOR_INIT(ldo8, "vdd_ldo8", "vdd_sm2", 1250, 3300);
-HARMONY_REGULATOR_INIT(ldo9, "vdd_ldo9", "vdd_sm2", 1250, 3300);
+HARMONY_REGULATOR_INIT(sm0,  "vdd_sm0",  "vdd_sys", 725, 1500, 1);
+HARMONY_REGULATOR_INIT(sm1,  "vdd_sm1",  "vdd_sys", 725, 1500, 1);
+HARMONY_REGULATOR_INIT(sm2,  "vdd_sm2",  "vdd_sys", 3000, 4550, 1);
+HARMONY_REGULATOR_INIT(ldo1, "vdd_ldo1", "vdd_sm2", 725, 1500, 1);
+HARMONY_REGULATOR_INIT(ldo2, "vdd_ldo2", "vdd_sm2", 725, 1500, 0);
+HARMONY_REGULATOR_INIT(ldo3, "vdd_ldo3", "vdd_sm2", 1250, 3300, 1);
+HARMONY_REGULATOR_INIT(ldo4, "vdd_ldo4", "vdd_sm2", 1700, 2475, 1);
+HARMONY_REGULATOR_INIT(ldo5, "vdd_ldo5", NULL,     1250, 3300, 1);
+HARMONY_REGULATOR_INIT(ldo6, "vdd_ldo6", "vdd_sm2", 1250, 3300, 0);
+HARMONY_REGULATOR_INIT(ldo7, "vdd_ldo7", "vdd_sm2", 1250, 3300, 0);
+HARMONY_REGULATOR_INIT(ldo8, "vdd_ldo8", "vdd_sm2", 1250, 3300, 0);
+HARMONY_REGULATOR_INIT(ldo9, "vdd_ldo9", "vdd_sm2", 1250, 3300, 1);
 
 #define TPS_REG(_id, _data)                    \
        {                                       \
@@ -119,9 +120,10 @@ static struct i2c_board_info __initdata harmony_regulators[] = {
 
 int __init harmony_regulator_init(void)
 {
+       regulator_register_always_on(0, "vdd_sys",
+               NULL, 0, 5000000);
+
        if (machine_is_harmony()) {
-               regulator_register_always_on(0, "vdd_sys",
-                       NULL, 0, 5000000);
                i2c_register_board_info(3, harmony_regulators, 1);
        } else { /* Harmony, booted using device tree */
                struct device_node *np;
index c70e65ffa36ba8a91e16b372c8c616abd4414c20..61e9603744a778dfa53e25084e1d04449def7e3b 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/fsl_devices.h>
 #include <linux/serial_8250.h>
 #include <linux/i2c-tegra.h>
-#include <asm/pmu.h>
 #include <mach/irqs.h>
 #include <mach/iomap.h>
 #include <mach/dma.h>
@@ -516,7 +515,7 @@ static struct resource tegra_pmu_resources[] = {
 
 struct platform_device tegra_pmu_device = {
        .name           = "arm-pmu",
-       .id             = ARM_PMU_DEVICE_CPU,
+       .id             = -1,
        .num_resources  = ARRAY_SIZE(tegra_pmu_resources),
        .resource       = tegra_pmu_resources,
 };
diff --git a/arch/arm/mach-tegra/include/mach/io.h b/arch/arm/mach-tegra/include/mach/io.h
deleted file mode 100644 (file)
index fe700f9..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * arch/arm/mach-tegra/include/mach/io.h
- *
- * Copyright (C) 2010 Google, Inc.
- *
- * Author:
- *     Colin Cross <ccross@google.com>
- *     Erik Gilling <konkers@google.com>
- *
- * 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.
- *
- */
-
-#ifndef __MACH_TEGRA_IO_H
-#define __MACH_TEGRA_IO_H
-
-#define IO_SPACE_LIMIT 0xffff
-
-#ifndef __ASSEMBLER__
-
-#ifdef CONFIG_TEGRA_PCI
-extern void __iomem *tegra_pcie_io_base;
-
-static inline void __iomem *__io(unsigned long addr)
-{
-       return tegra_pcie_io_base + (addr & IO_SPACE_LIMIT);
-}
-#else
-static inline void __iomem *__io(unsigned long addr)
-{
-       return (void __iomem *)addr;
-}
-#endif
-
-#define __io(a)         __io(a)
-
-#endif
-
-#endif
index 7e76da73121cd418d2114ac6cfec494d8522239c..fee3a94c4549f8e7e90e81cfdb3d7335b2901a02 100644 (file)
 #define IO_APB_VIRT    IOMEM(0xFE300000)
 #define IO_APB_SIZE    SZ_1M
 
+#define TEGRA_PCIE_BASE                0x80000000
+#define TEGRA_PCIE_IO_BASE     (TEGRA_PCIE_BASE + SZ_4M)
+
 #define IO_TO_VIRT_BETWEEN(p, st, sz)  ((p) >= (st) && (p) < ((st) + (sz)))
 #define IO_TO_VIRT_XLATE(p, pst, vst)  (((p) - (pst) + (vst)))
 
index d3ad5150d6609e135a063421d2c9acad62e204df..3463fb5b79c7644ad84ba419fb78e95eb0ecf252 100644 (file)
@@ -171,8 +171,6 @@ static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
  * 0x90000000 - 0x9fffffff - non-prefetchable memory
  * 0xa0000000 - 0xbfffffff - prefetchable memory
  */
-#define TEGRA_PCIE_BASE                0x80000000
-
 #define PCIE_REGS_SZ           SZ_16K
 #define PCIE_CFG_OFF           PCIE_REGS_SZ
 #define PCIE_CFG_SZ            SZ_1M
@@ -180,8 +178,6 @@ static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
 #define PCIE_EXT_CFG_SZ                SZ_1M
 #define PCIE_IOMAP_SZ          (PCIE_REGS_SZ + PCIE_CFG_SZ + PCIE_EXT_CFG_SZ)
 
-#define MMIO_BASE              (TEGRA_PCIE_BASE + SZ_4M)
-#define MMIO_SIZE              SZ_64K
 #define MEM_BASE_0             (TEGRA_PCIE_BASE + SZ_256M)
 #define MEM_SIZE_0             SZ_128M
 #define MEM_BASE_1             (MEM_BASE_0 + MEM_SIZE_0)
@@ -204,10 +200,9 @@ struct tegra_pcie_port {
 
        bool                    link_up;
 
-       char                    io_space_name[16];
        char                    mem_space_name[16];
        char                    prefetch_space_name[20];
-       struct resource         res[3];
+       struct resource         res[2];
 };
 
 struct tegra_pcie_info {
@@ -223,17 +218,7 @@ struct tegra_pcie_info {
        struct clk              *pll_e;
 };
 
-static struct tegra_pcie_info tegra_pcie = {
-       .res_mmio = {
-               .name = "PCI IO",
-               .start = MMIO_BASE,
-               .end = MMIO_BASE + MMIO_SIZE - 1,
-               .flags = IORESOURCE_MEM,
-       },
-};
-
-void __iomem *tegra_pcie_io_base;
-EXPORT_SYMBOL(tegra_pcie_io_base);
+static struct tegra_pcie_info tegra_pcie;
 
 static inline void afi_writel(u32 value, unsigned long offset)
 {
@@ -391,24 +376,7 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
        pp = tegra_pcie.port + nr;
        pp->root_bus_nr = sys->busnr;
 
-       /*
-        * IORESOURCE_IO
-        */
-       snprintf(pp->io_space_name, sizeof(pp->io_space_name),
-                "PCIe %d I/O", pp->index);
-       pp->io_space_name[sizeof(pp->io_space_name) - 1] = 0;
-       pp->res[0].name = pp->io_space_name;
-       if (pp->index == 0) {
-               pp->res[0].start = PCIBIOS_MIN_IO;
-               pp->res[0].end = pp->res[0].start + SZ_32K - 1;
-       } else {
-               pp->res[0].start = PCIBIOS_MIN_IO + SZ_32K;
-               pp->res[0].end = IO_SPACE_LIMIT;
-       }
-       pp->res[0].flags = IORESOURCE_IO;
-       if (request_resource(&ioport_resource, &pp->res[0]))
-               panic("Request PCIe IO resource failed\n");
-       pci_add_resource_offset(&sys->resources, &pp->res[0], sys->io_offset);
+       pci_ioremap_io(nr * SZ_64K, TEGRA_PCIE_IO_BASE);
 
        /*
         * IORESOURCE_MEM
@@ -416,18 +384,18 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
        snprintf(pp->mem_space_name, sizeof(pp->mem_space_name),
                 "PCIe %d MEM", pp->index);
        pp->mem_space_name[sizeof(pp->mem_space_name) - 1] = 0;
-       pp->res[1].name = pp->mem_space_name;
+       pp->res[0].name = pp->mem_space_name;
        if (pp->index == 0) {
-               pp->res[1].start = MEM_BASE_0;
-               pp->res[1].end = pp->res[1].start + MEM_SIZE_0 - 1;
+               pp->res[0].start = MEM_BASE_0;
+               pp->res[0].end = pp->res[0].start + MEM_SIZE_0 - 1;
        } else {
-               pp->res[1].start = MEM_BASE_1;
-               pp->res[1].end = pp->res[1].start + MEM_SIZE_1 - 1;
+               pp->res[0].start = MEM_BASE_1;
+               pp->res[0].end = pp->res[0].start + MEM_SIZE_1 - 1;
        }
-       pp->res[1].flags = IORESOURCE_MEM;
-       if (request_resource(&iomem_resource, &pp->res[1]))
+       pp->res[0].flags = IORESOURCE_MEM;
+       if (request_resource(&iomem_resource, &pp->res[0]))
                panic("Request PCIe Memory resource failed\n");
-       pci_add_resource_offset(&sys->resources, &pp->res[1], sys->mem_offset);
+       pci_add_resource_offset(&sys->resources, &pp->res[0], sys->mem_offset);
 
        /*
         * IORESOURCE_MEM | IORESOURCE_PREFETCH
@@ -435,18 +403,18 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
        snprintf(pp->prefetch_space_name, sizeof(pp->prefetch_space_name),
                 "PCIe %d PREFETCH MEM", pp->index);
        pp->prefetch_space_name[sizeof(pp->prefetch_space_name) - 1] = 0;
-       pp->res[2].name = pp->prefetch_space_name;
+       pp->res[1].name = pp->prefetch_space_name;
        if (pp->index == 0) {
-               pp->res[2].start = PREFETCH_MEM_BASE_0;
-               pp->res[2].end = pp->res[2].start + PREFETCH_MEM_SIZE_0 - 1;
+               pp->res[1].start = PREFETCH_MEM_BASE_0;
+               pp->res[1].end = pp->res[1].start + PREFETCH_MEM_SIZE_0 - 1;
        } else {
-               pp->res[2].start = PREFETCH_MEM_BASE_1;
-               pp->res[2].end = pp->res[2].start + PREFETCH_MEM_SIZE_1 - 1;
+               pp->res[1].start = PREFETCH_MEM_BASE_1;
+               pp->res[1].end = pp->res[1].start + PREFETCH_MEM_SIZE_1 - 1;
        }
-       pp->res[2].flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
-       if (request_resource(&iomem_resource, &pp->res[2]))
+       pp->res[1].flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
+       if (request_resource(&iomem_resource, &pp->res[1]))
                panic("Request PCIe Prefetch Memory resource failed\n");
-       pci_add_resource_offset(&sys->resources, &pp->res[2], sys->mem_offset);
+       pci_add_resource_offset(&sys->resources, &pp->res[1], sys->mem_offset);
 
        return 1;
 }
@@ -541,8 +509,8 @@ static void tegra_pcie_setup_translations(void)
 
        /* Bar 2: downstream IO bar */
        fpci_bar = ((__u32)0xfdfc << 16);
-       size = MMIO_SIZE;
-       axi_address = MMIO_BASE;
+       size = SZ_128K;
+       axi_address = TEGRA_PCIE_IO_BASE;
        afi_writel(axi_address, AFI_AXI_BAR2_START);
        afi_writel(size >> 12, AFI_AXI_BAR2_SZ);
        afi_writel(fpci_bar, AFI_FPCI_BAR2);
@@ -776,7 +744,6 @@ static void tegra_pcie_clocks_put(void)
 
 static int __init tegra_pcie_get_resources(void)
 {
-       struct resource *res_mmio = &tegra_pcie.res_mmio;
        int err;
 
        err = tegra_pcie_clocks_get();
@@ -798,34 +765,16 @@ static int __init tegra_pcie_get_resources(void)
                goto err_map_reg;
        }
 
-       err = request_resource(&iomem_resource, res_mmio);
-       if (err) {
-               pr_err("PCIE: Failed to request resources: %d\n", err);
-               goto err_req_io;
-       }
-
-       tegra_pcie_io_base = ioremap_nocache(res_mmio->start,
-                                            resource_size(res_mmio));
-       if (tegra_pcie_io_base == NULL) {
-               pr_err("PCIE: Failed to map IO\n");
-               err = -ENOMEM;
-               goto err_map_io;
-       }
-
        err = request_irq(INT_PCIE_INTR, tegra_pcie_isr,
                          IRQF_SHARED, "PCIE", &tegra_pcie);
        if (err) {
                pr_err("PCIE: Failed to register IRQ: %d\n", err);
-               goto err_irq;
+               goto err_req_io;
        }
        set_irq_flags(INT_PCIE_INTR, IRQF_VALID);
 
        return 0;
 
-err_irq:
-       iounmap(tegra_pcie_io_base);
-err_map_io:
-       release_resource(&tegra_pcie.res_mmio);
 err_req_io:
        iounmap(tegra_pcie.regs);
 err_map_reg:
index 54d8f34fdee5d1d2770be32884011aac3949951f..f7e12ede008c11e564415cd4047045ec14a011ef 100644 (file)
@@ -1,6 +1,6 @@
 if ARCH_U300
 
-menu "ST-Ericsson AB U300/U330/U335/U365 Platform"
+menu "ST-Ericsson AB U300/U335 Platform"
 
 comment "ST-Ericsson Mobile Platform Products"
 
@@ -10,46 +10,7 @@ config MACH_U300
        select PINCTRL_U300
        select PINCTRL_COH901
 
-comment "ST-Ericsson U300/U330/U335/U365 Feature Selections"
-
-choice
-       prompt "U300/U330/U335/U365 system type"
-       default MACH_U300_BS2X
-       ---help---
-       You need to select the target system, i.e. the
-       U300/U330/U335/U365 board that you want to compile your kernel
-       for.
-
-config MACH_U300_BS2X
-       bool "S26/S26/B25/B26 Test Products"
-       depends on MACH_U300
-       help
-               Select this if you're developing on the
-               S26/S25 test products. (Also works on
-               B26/B25 big boards.)
-
-config MACH_U300_BS330
-       bool "S330/B330 Test Products"
-       depends on MACH_U300
-       help
-               Select this if you're developing on the
-               S330/B330 test products.
-
-config MACH_U300_BS335
-       bool "S335/B335 Test Products"
-       depends on MACH_U300
-       help
-               Select this if you're developing on the
-               S335/B335 test products.
-
-config MACH_U300_BS365
-       bool "S365/B365 Test Products"
-       depends on MACH_U300
-       help
-               Select this if you're developing on the
-               S365/B365 test products.
-
-endchoice
+comment "ST-Ericsson U300/U335 Feature Selections"
 
 config U300_DEBUG
        bool "Debug support for U300"
index 7e47d37aeb0ee4feaff53d372e25a3e4a98296ee..5a86c58da396b98bbbc312f732d1d64e3efee752 100644 (file)
@@ -7,7 +7,6 @@ obj-m           :=
 obj-n          :=
 obj-           :=
 
-obj-$(CONFIG_ARCH_U300)                  += u300.o
 obj-$(CONFIG_SPI_PL022)           += spi.o
 obj-$(CONFIG_MACH_U300_SPIDUMMY)  += dummyspichip.o
 obj-$(CONFIG_I2C_STU300)          += i2c.o
index 03acf1883ec74be7cee10d86e485a4f1d440bffb..ef6f602b7e489b483eaa274ecdaec1342c258ebb 100644 (file)
@@ -3,7 +3,7 @@
  * arch/arm/mach-u300/core.c
  *
  *
- * Copyright (C) 2007-2010 ST-Ericsson SA
+ * Copyright (C) 2007-2012 ST-Ericsson SA
  * License terms: GNU General Public License (GPL) version 2
  * Core platform support, IRQ handling and device definitions.
  * Author: Linus Walleij <linus.walleij@stericsson.com>
 #include <linux/pinctrl/pinconf-generic.h>
 #include <linux/dma-mapping.h>
 #include <linux/platform_data/clk-u300.h>
+#include <linux/platform_data/pinctrl-coh901.h>
 
 #include <asm/types.h>
 #include <asm/setup.h>
 #include <asm/memory.h>
 #include <asm/hardware/vic.h>
 #include <asm/mach/map.h>
-#include <asm/mach/irq.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
 
 #include <mach/coh901318.h>
 #include <mach/hardware.h>
 #include <mach/syscon.h>
-#include <mach/dma_channels.h>
-#include <mach/gpio-u300.h>
+#include <mach/irqs.h>
 
+#include "timer.h"
 #include "spi.h"
 #include "i2c.h"
 #include "u300-gpio.h"
+#include "dma_channels.h"
 
 /*
  * Static I/O mappings that are needed for booting the U300 platforms. The
@@ -76,7 +79,7 @@ static struct map_desc u300_io_desc[] __initdata = {
        },
 };
 
-void __init u300_map_io(void)
+static void __init u300_map_io(void)
 {
        iotable_init(u300_io_desc, ARRAY_SIZE(u300_io_desc));
        /* We enable a real big DMA buffer if need be. */
@@ -101,7 +104,6 @@ static AMBA_APB_DEVICE(uart0, "uart0", 0, U300_UART0_BASE,
        { IRQ_U300_UART0 }, &uart0_plat_data);
 
 /* The U335 have an additional UART1 on the APP CPU */
-#ifdef CONFIG_MACH_U300_BS335
 static struct amba_pl011_data uart1_plat_data = {
 #ifdef CONFIG_COH901318
        .dma_filter = coh901318_filter_id,
@@ -113,7 +115,6 @@ static struct amba_pl011_data uart1_plat_data = {
 /* Fast device at 0x7000 offset */
 static AMBA_APB_DEVICE(uart1, "uart1", 0, U300_UART1_BASE,
        { IRQ_U300_UART1 }, &uart1_plat_data);
-#endif
 
 /* AHB device at 0x4000 offset */
 static AMBA_APB_DEVICE(pl172, "pl172", 0, U300_EMIF_CFG_BASE, { }, NULL);
@@ -152,9 +153,7 @@ static AMBA_APB_DEVICE(mmcsd, "mmci", 0, U300_MMCSD_BASE,
  */
 static struct amba_device *amba_devs[] __initdata = {
        &uart0_device,
-#ifdef CONFIG_MACH_U300_BS335
        &uart1_device,
-#endif
        &pl022_device,
        &pl172_device,
        &mmcsd_device,
@@ -188,7 +187,6 @@ static struct resource gpio_resources[] = {
                .end   = IRQ_U300_GPIO_PORT2,
                .flags = IORESOURCE_IRQ,
        },
-#if defined(CONFIG_MACH_U300_BS365) || defined(CONFIG_MACH_U300_BS335)
        {
                .name  = "gpio3",
                .start = IRQ_U300_GPIO_PORT3,
@@ -201,8 +199,6 @@ static struct resource gpio_resources[] = {
                .end   = IRQ_U300_GPIO_PORT4,
                .flags = IORESOURCE_IRQ,
        },
-#endif
-#ifdef CONFIG_MACH_U300_BS335
        {
                .name  = "gpio5",
                .start = IRQ_U300_GPIO_PORT5,
@@ -215,7 +211,6 @@ static struct resource gpio_resources[] = {
                .end   = IRQ_U300_GPIO_PORT6,
                .flags = IORESOURCE_IRQ,
        },
-#endif /* CONFIG_MACH_U300_BS335 */
 };
 
 static struct resource keypad_resources[] = {
@@ -323,7 +318,6 @@ static struct resource dma_resource[] = {
        }
 };
 
-#ifdef CONFIG_MACH_U300_BS335
 /* points out all dma slave channels.
  * Syntax is [A1, B1, A2, B2, .... ,-1,-1]
  * Select all channels from A to B, end of list is marked with -1,-1
@@ -336,14 +330,6 @@ static int dma_slave_channels[] = {
 static int dma_memcpy_channels[] = {
        U300_DMA_GENERAL_PURPOSE_0, U300_DMA_GENERAL_PURPOSE_8, -1, -1};
 
-#else /* CONFIG_MACH_U300_BS335 */
-
-static int dma_slave_channels[] = {U300_DMA_MSL_TX_0, U300_DMA_SPI_RX, -1, -1};
-static int dma_memcpy_channels[] = {
-       U300_DMA_GENERAL_PURPOSE_0, U300_DMA_GENERAL_PURPOSE_10, -1, -1};
-
-#endif
-
 /** register dma for memory access
  *
  * active  1 means dma intends to access memory
@@ -1395,7 +1381,6 @@ const struct coh_dma_channel chan_config[U300_DMA_CHANNELS] = {
                .param.ctrl_lli = flags_memcpy_lli,
                .param.ctrl_lli_last = flags_memcpy_lli_last,
        },
-#ifdef CONFIG_MACH_U300_BS335
        {
                .number = U300_DMA_UART1_TX,
                .name = "UART1 TX",
@@ -1406,28 +1391,6 @@ const struct coh_dma_channel chan_config[U300_DMA_CHANNELS] = {
                .name = "UART1 RX",
                .priority_high = 0,
        }
-#else
-       {
-               .number = U300_DMA_GENERAL_PURPOSE_9,
-               .name = "GENERAL 09",
-               .priority_high = 0,
-
-               .param.config = flags_memcpy_config,
-               .param.ctrl_lli_chained = flags_memcpy_lli_chained,
-               .param.ctrl_lli = flags_memcpy_lli,
-               .param.ctrl_lli_last = flags_memcpy_lli_last,
-       },
-       {
-               .number = U300_DMA_GENERAL_PURPOSE_10,
-               .name = "GENERAL 10",
-               .priority_high = 0,
-
-               .param.config = flags_memcpy_config,
-               .param.ctrl_lli_chained = flags_memcpy_lli_chained,
-               .param.ctrl_lli = flags_memcpy_lli,
-               .param.ctrl_lli_last = flags_memcpy_lli_last,
-       }
-#endif
 };
 
 
@@ -1480,18 +1443,7 @@ static struct platform_device pinctrl_device = {
  * GPIO block, with different number of ports.
  */
 static struct u300_gpio_platform u300_gpio_plat = {
-#if defined(CONFIG_MACH_U300_BS2X) || defined(CONFIG_MACH_U300_BS330)
-       .variant = U300_GPIO_COH901335,
-       .ports = 3,
-#endif
-#ifdef CONFIG_MACH_U300_BS335
-       .variant = U300_GPIO_COH901571_3_BS335,
        .ports = 7,
-#endif
-#ifdef CONFIG_MACH_U300_BS365
-       .variant = U300_GPIO_COH901571_3_BS365,
-       .ports = 5,
-#endif
        .gpio_base = 0,
        .gpio_irq_base = IRQ_U300_GPIO_BASE,
        .pinctrl_device = &pinctrl_device,
@@ -1651,7 +1603,7 @@ static struct platform_device *platform_devs[] __initdata = {
  * together so some interrupts are connected to the first one and some
  * to the second one.
  */
-void __init u300_init_irq(void)
+static void __init u300_init_irq(void)
 {
        u32 mask[2] = {0, 0};
        struct clk *clk;
@@ -1756,29 +1708,11 @@ static void __init u300_init_check_chip(void)
        printk(KERN_INFO "Initializing U300 system on %s baseband chip " \
               "(chip ID 0x%04x)\n", chipname, val);
 
-#ifdef CONFIG_MACH_U300_BS330
-       if ((val & 0xFF00U) != 0xd800) {
-               printk(KERN_ERR "Platform configured for BS330 " \
-                      "with DB3200 but %s detected, expect problems!",
-                      chipname);
-       }
-#endif
-#ifdef CONFIG_MACH_U300_BS335
        if ((val & 0xFF00U) != 0xf000 && (val & 0xFF00U) != 0xf100) {
                printk(KERN_ERR "Platform configured for BS335 " \
                       " with DB3350 but %s detected, expect problems!",
                       chipname);
        }
-#endif
-#ifdef CONFIG_MACH_U300_BS365
-       if ((val & 0xFF00U) != 0xe800) {
-               printk(KERN_ERR "Platform configured for BS365 " \
-                      "with DB3210 but %s detected, expect problems!",
-                      chipname);
-       }
-#endif
-
-
 }
 
 /*
@@ -1811,7 +1745,7 @@ static void __init u300_assign_physmem(void)
        }
 }
 
-void __init u300_init_devices(void)
+static void __init u300_init_machine(void)
 {
        int i;
        u16 val;
@@ -1852,7 +1786,7 @@ void __init u300_init_devices(void)
 /* Forward declare this function from the watchdog */
 void coh901327_watchdog_reset(void);
 
-void u300_restart(char mode, const char *cmd)
+static void u300_restart(char mode, const char *cmd)
 {
        switch (mode) {
        case 's':
@@ -1868,3 +1802,15 @@ void u300_restart(char mode, const char *cmd)
        /* Wait for system do die/reset. */
        while (1);
 }
+
+MACHINE_START(U300, "Ericsson AB U335 S335/B335 Prototype Board")
+       /* Maintainer: Linus Walleij <linus.walleij@stericsson.com> */
+       .atag_offset    = 0x100,
+       .map_io         = u300_map_io,
+       .nr_irqs        = NR_IRQS_U300,
+       .init_irq       = u300_init_irq,
+       .handle_irq     = vic_handle_irq,
+       .timer          = &u300_timer,
+       .init_machine   = u300_init_machine,
+       .restart        = u300_restart,
+MACHINE_END
similarity index 88%
rename from arch/arm/mach-u300/include/mach/dma_channels.h
rename to arch/arm/mach-u300/dma_channels.h
index b239149ba0d0d63879e1b1d490ae7e58ae161759..4e8a88fbca497727b95148f095d14eda2481fbe7 100644 (file)
@@ -3,7 +3,7 @@
  * arch/arm/mach-u300/include/mach/dma_channels.h
  *
  *
- * Copyright (C) 2007-2009 ST-Ericsson
+ * Copyright (C) 2007-2012 ST-Ericsson
  * License terms: GNU General Public License (GPL) version 2
  * Map file for the U300 dma driver.
  * Author: Per Friden <per.friden@stericsson.com>
 #define U300_DMA_GENERAL_PURPOSE_6    35
 #define U300_DMA_GENERAL_PURPOSE_7    36
 #define U300_DMA_GENERAL_PURPOSE_8    37
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_DMA_UART1_TX             38
 #define U300_DMA_UART1_RX             39
-#else
-#define U300_DMA_GENERAL_PURPOSE_9    38
-#define U300_DMA_GENERAL_PURPOSE_10   39
-#endif
 
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_DMA_DEVICE_CHANNELS      32
-#else
-#define U300_DMA_DEVICE_CHANNELS      30
-#endif
 #define U300_DMA_CHANNELS             40
 
 
index cb04bd6ab3e7f07248f57372015cec729e030798..0d4620ed853c7c3a3c7cc9a3995c50ceecc40e2e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * arch/arm/mach-u300/i2c.c
  *
- * Copyright (C) 2009 ST-Ericsson AB
+ * Copyright (C) 2009-2012 ST-Ericsson AB
  * License terms: GNU General Public License (GPL) version 2
  *
  * Register board i2c devices
@@ -261,7 +261,6 @@ static struct i2c_board_info __initdata bus0_i2c_board_info[] = {
 };
 
 static struct i2c_board_info __initdata bus1_i2c_board_info[] = {
-#ifdef CONFIG_MACH_U300_BS335
        {
                .type = "fwcam",
                .addr = 0x10,
@@ -270,9 +269,6 @@ static struct i2c_board_info __initdata bus1_i2c_board_info[] = {
                .type = "fwcam",
                .addr = 0x5d,
        },
-#else
-       { },
-#endif
 };
 
 void __init u300_i2c_register_board_devices(void)
diff --git a/arch/arm/mach-u300/include/mach/clkdev.h b/arch/arm/mach-u300/include/mach/clkdev.h
deleted file mode 100644 (file)
index 92e3cc8..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef __MACH_CLKDEV_H
-#define __MACH_CLKDEV_H
-
-int __clk_get(struct clk *clk);
-void __clk_put(struct clk *clk);
-
-#endif
index ec09c1e07b1a8f6655e1887c353031f6471bc7f9..e27425a63fa1418837b4becaa23256e0ccbe6706 100644 (file)
@@ -3,7 +3,7 @@
  * arch/arm/mach-u300/include/mach/irqs.h
  *
  *
- * Copyright (C) 2006-2009 ST-Ericsson AB
+ * Copyright (C) 2006-2012 ST-Ericsson AB
  * License terms: GNU General Public License (GPL) version 2
  * IRQ channel definitions for the U300 platforms.
  * Author: Linus Walleij <linus.walleij@stericsson.com>
 #define IRQ_U300_XGAM_GAMCON           14
 #define IRQ_U300_XGAM_CDI              15
 #define IRQ_U300_XGAM_CDICON           16
-#if defined(CONFIG_MACH_U300_BS2X) || defined(CONFIG_MACH_U300_BS330)
-/* MMIACC not used on the DB3210 or DB3350 chips */
-#define IRQ_U300_XGAM_MMIACC           17
-#endif
 #define IRQ_U300_XGAM_PDI              18
 #define IRQ_U300_XGAM_PDICON           19
 #define IRQ_U300_XGAM_GAMEACC          20
@@ -55,8 +51,6 @@
 #define IRQ_U300_GPIO_PORT1            34
 #define IRQ_U300_GPIO_PORT2            35
 
-#if defined(CONFIG_MACH_U300_BS2X) || defined(CONFIG_MACH_U300_BS330) || \
-    defined(CONFIG_MACH_U300_BS335)
 /* These are for DB3150, DB3200 and DB3350 */
 #define IRQ_U300_WDOG                  36
 #define IRQ_U300_EVHIST                        37
 #define IRQ_U300_RTC                   43
 #define IRQ_U300_NFIF                  44
 #define IRQ_U300_NFIF2                 45
-#endif
-
-/* DB3150 and DB3200 have only 45 IRQs */
-#if defined(CONFIG_MACH_U300_BS2X) || defined(CONFIG_MACH_U300_BS330)
-#define U300_VIC_IRQS_END              46
-#endif
 
 /* The DB3350-specific interrupt lines */
-#ifdef CONFIG_MACH_U300_BS335
 #define IRQ_U300_ISP_F0                        46
 #define IRQ_U300_ISP_F1                        47
 #define IRQ_U300_ISP_F2                        48
 #define IRQ_U300_GPIO_PORT5            55
 #define IRQ_U300_GPIO_PORT6            56
 #define U300_VIC_IRQS_END              57
-#endif
-
-/* The DB3210-specific interrupt lines */
-#ifdef CONFIG_MACH_U300_BS365
-#define IRQ_U300_GPIO_PORT3            36
-#define IRQ_U300_GPIO_PORT4            37
-#define IRQ_U300_WDOG                  38
-#define IRQ_U300_EVHIST                        39
-#define IRQ_U300_MSPRO                 40
-#define IRQ_U300_MMCSD_MCIINTR0                41
-#define IRQ_U300_MMCSD_MCIINTR1                42
-#define IRQ_U300_I2C0                  43
-#define IRQ_U300_I2C1                  44
-#define IRQ_U300_RTC                   45
-#define IRQ_U300_NFIF                  46
-#define IRQ_U300_NFIF2                 47
-#define IRQ_U300_SYSCON_PLL_LOCK       48
-#define U300_VIC_IRQS_END              49
-#endif
 
 /* Maximum 8*7 GPIO lines */
 #ifdef CONFIG_PINCTRL_COH901
 #define IRQ_U300_GPIO_END              (U300_VIC_IRQS_END)
 #endif
 
-#define NR_IRQS                                (IRQ_U300_GPIO_END - IRQ_U300_INTCON0_START)
+#define NR_IRQS_U300                   (IRQ_U300_GPIO_END - IRQ_U300_INTCON0_START)
 
 #endif
diff --git a/arch/arm/mach-u300/include/mach/platform.h b/arch/arm/mach-u300/include/mach/platform.h
deleted file mode 100644 (file)
index 096333f..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- *
- * arch/arm/mach-u300/include/mach/platform.h
- *
- *
- * Copyright (C) 2006-2009 ST-Ericsson AB
- * License terms: GNU General Public License (GPL) version 2
- * Basic platform init and mapping functions.
- * Author: Linus Walleij <linus.walleij@stericsson.com>
- */
-
-#ifndef __ASSEMBLY__
-
-void u300_map_io(void);
-void u300_init_irq(void);
-void u300_init_devices(void);
-void u300_restart(char, const char *);
-extern struct sys_timer u300_timer;
-
-#endif
index 6e84f07a7c6f376d5fa894c3f2c0b18ea882cbbf..10bdd0be9774f3810f533fa819ac6e116f9d5386 100644 (file)
@@ -3,7 +3,7 @@
  * arch/arm/mach-u300/include/mach/syscon.h
  *
  *
- * Copyright (C) 2008 ST-Ericsson AB
+ * Copyright (C) 2008-2012 ST-Ericsson AB
  *
  * Author: Rickard Andersson <rickard.andersson@stericsson.com>
  */
@@ -36,9 +36,7 @@
 #define U300_SYSCON_CSR_PLL13_LOCK_IND                         (0x0001)
 /* Reset lines for SLOW devices 16bit (R/W) */
 #define U300_SYSCON_RSR                                                (0x0014)
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_SYSCON_RSR_PPM_RESET_EN                           (0x0200)
-#endif
 #define U300_SYSCON_RSR_ACC_TMR_RESET_EN                       (0x0100)
 #define U300_SYSCON_RSR_APP_TMR_RESET_EN                       (0x0080)
 #define U300_SYSCON_RSR_RTC_RESET_EN                           (0x0040)
@@ -50,9 +48,7 @@
 #define U300_SYSCON_RSR_SLOW_BRIDGE_RESET_EN                   (0x0001)
 /* Reset lines for FAST devices 16bit (R/W) */
 #define U300_SYSCON_RFR                                                (0x0018)
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_SYSCON_RFR_UART1_RESET_ENABLE                     (0x0080)
-#endif
 #define U300_SYSCON_RFR_SPI_RESET_ENABLE                       (0x0040)
 #define U300_SYSCON_RFR_MMC_RESET_ENABLE                       (0x0020)
 #define U300_SYSCON_RFR_PCM_I2S1_RESET_ENABLE                  (0x0010)
 #define U300_SYSCON_RFR_FAST_BRIDGE_RESET_ENABLE               (0x0001)
 /* Reset lines for the rest of the peripherals 16bit (R/W) */
 #define U300_SYSCON_RRR                                                (0x001c)
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_SYSCON_RRR_CDS_RESET_EN                           (0x4000)
 #define U300_SYSCON_RRR_ISP_RESET_EN                           (0x2000)
-#endif
 #define U300_SYSCON_RRR_INTCON_RESET_EN                                (0x1000)
 #define U300_SYSCON_RRR_MSPRO_RESET_EN                         (0x0800)
 #define U300_SYSCON_RRR_XGAM_RESET_EN                          (0x0100)
@@ -79,9 +73,7 @@
 #define U300_SYSCON_RRR_AAIF_RESET_EN                          (0x0001)
 /* Clock enable for SLOW peripherals 16bit (R/W) */
 #define U300_SYSCON_CESR                                       (0x0020)
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_SYSCON_CESR_PPM_CLK_EN                            (0x0200)
-#endif
 #define U300_SYSCON_CESR_ACC_TMR_CLK_EN                                (0x0100)
 #define U300_SYSCON_CESR_APP_TMR_CLK_EN                                (0x0080)
 #define U300_SYSCON_CESR_KEYPAD_CLK_EN                         (0x0040)
 #define U300_SYSCON_CESR_SLOW_BRIDGE_CLK_EN                    (0x0001)
 /* Clock enable for FAST peripherals 16bit (R/W) */
 #define U300_SYSCON_CEFR                                       (0x0024)
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_SYSCON_CEFR_UART1_CLK_EN                          (0x0200)
-#endif
 #define U300_SYSCON_CEFR_I2S1_CORE_CLK_EN                      (0x0100)
 #define U300_SYSCON_CEFR_I2S0_CORE_CLK_EN                      (0x0080)
 #define U300_SYSCON_CEFR_SPI_CLK_EN                            (0x0040)
 #define U300_SYSCON_CEFR_MMC_CLK_EN                            (0x0020)
-#define U300_SYSCON_CEFR_I2S1_CLK_EN                           (0x0010)
-#define U300_SYSCON_CEFR_I2S0_CLK_EN                           (0x0008)
-#define U300_SYSCON_CEFR_I2C1_CLK_EN                           (0x0004)
-#define U300_SYSCON_CEFR_I2C0_CLK_EN                           (0x0002)
+#define U300_SYSCON_CEFR_I2S1_CLK_EN                           (0x0010)
+#define U300_SYSCON_CEFR_I2S0_CLK_EN                           (0x0008)
+#define U300_SYSCON_CEFR_I2C1_CLK_EN                           (0x0004)
+#define U300_SYSCON_CEFR_I2C0_CLK_EN                           (0x0002)
 #define U300_SYSCON_CEFR_FAST_BRIDGE_CLK_EN                    (0x0001)
 /* Clock enable for the rest of the peripherals 16bit (R/W) */
 #define U300_SYSCON_CERR                                       (0x0028)
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_SYSCON_CERR_CDS_CLK_EN                            (0x2000)
 #define U300_SYSCON_CERR_ISP_CLK_EN                            (0x1000)
-#endif
 #define U300_SYSCON_CERR_MSPRO_CLK_EN                          (0x0800)
 #define U300_SYSCON_CERR_AHB_SUBSYS_BRIDGE_CLK_EN              (0x0400)
 #define U300_SYSCON_CERR_SEMI_CLK_EN                           (0x0200)
 #define U300_SYSCON_CERR_AAIF_CLK_EN                           (0x0001)
 /* Single block clock enable 16bit (-/W) */
 #define U300_SYSCON_SBCER                                      (0x002c)
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_SYSCON_SBCER_PPM_CLK_EN                           (0x0009)
-#endif
 #define U300_SYSCON_SBCER_ACC_TMR_CLK_EN                       (0x0008)
 #define U300_SYSCON_SBCER_APP_TMR_CLK_EN                       (0x0007)
 #define U300_SYSCON_SBCER_KEYPAD_CLK_EN                                (0x0006)
 #define U300_SYSCON_SBCER_BTR_CLK_EN                           (0x0002)
 #define U300_SYSCON_SBCER_UART_CLK_EN                          (0x0001)
 #define U300_SYSCON_SBCER_SLOW_BRIDGE_CLK_EN                   (0x0000)
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_SYSCON_SBCER_UART1_CLK_EN                         (0x0019)
-#endif
 #define U300_SYSCON_SBCER_I2S1_CORE_CLK_EN                     (0x0018)
 #define U300_SYSCON_SBCER_I2S0_CORE_CLK_EN                     (0x0017)
 #define U300_SYSCON_SBCER_SPI_CLK_EN                           (0x0016)
 #define U300_SYSCON_SBCER_I2C1_CLK_EN                          (0x0012)
 #define U300_SYSCON_SBCER_I2C0_CLK_EN                          (0x0011)
 #define U300_SYSCON_SBCER_FAST_BRIDGE_CLK_EN                   (0x0010)
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_SYSCON_SBCER_CDS_CLK_EN                           (0x002D)
 #define U300_SYSCON_SBCER_ISP_CLK_EN                           (0x002C)
-#endif
 #define U300_SYSCON_SBCER_MSPRO_CLK_EN                         (0x002B)
 #define U300_SYSCON_SBCER_AHB_SUBSYS_BRIDGE_CLK_EN             (0x002A)
 #define U300_SYSCON_SBCER_SEMI_CLK_EN                          (0x0029)
 /* Same values as above for SBCER */
 /* Clock force SLOW peripherals 16bit (R/W) */
 #define U300_SYSCON_CFSR                                       (0x003c)
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_SYSCON_CFSR_PPM_CLK_FORCE_EN                      (0x0200)
-#endif
 #define U300_SYSCON_CFSR_ACC_TMR_CLK_FORCE_EN                  (0x0100)
 #define U300_SYSCON_CFSR_APP_TMR_CLK_FORCE_EN                  (0x0080)
 #define U300_SYSCON_CFSR_KEYPAD_CLK_FORCE_EN                   (0x0020)
 /* Values not defined. Define if you want to use them. */
 /* Clock force the rest of the peripherals 16bit (R/W) */
 #define U300_SYSCON_CFRR                                       (0x44)
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_SYSCON_CFRR_CDS_CLK_FORCE_EN                      (0x2000)
 #define U300_SYSCON_CFRR_ISP_CLK_FORCE_EN                      (0x1000)
-#endif
 #define U300_SYSCON_CFRR_MSPRO_CLK_FORCE_EN                    (0x0800)
 #define U300_SYSCON_CFRR_AHB_SUBSYS_BRIDGE_CLK_FORCE_EN                (0x0400)
 #define U300_SYSCON_CFRR_SEMI_CLK_FORCE_EN                     (0x0200)
index 65f87c523892e0826ea65d4928cb14cb10b30349..1e49d901f2c9212d665848a13c7d2099f5a8d3a9 100644 (file)
@@ -28,7 +28,6 @@
 #define PLAT_NAND_CLE                  (1 << 16)
 #define PLAT_NAND_ALE                  (1 << 17)
 
-
 /* AHB Peripherals */
 #define U300_AHB_PER_PHYS_BASE         0xa0000000
 #define U300_AHB_PER_VIRT_BASE         0xff010000
 #define U300_BOOTROM_VIRT_BASE         0xffff0000
 
 /* SEMI config base */
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_SEMI_CONFIG_BASE          0x2FFE0000
-#else
-#define U300_SEMI_CONFIG_BASE          0x30000000
-#endif
 
 /*
  * AHB peripherals
 /* SPI controller */
 #define U300_SPI_BASE                  (U300_FAST_PER_PHYS_BASE+0x6000)
 
-#ifdef CONFIG_MACH_U300_BS335
 /* Fast UART1 on U335 only */
 #define U300_UART1_BASE                        (U300_SLOW_PER_PHYS_BASE+0x7000)
-#endif
 
 /*
  * SLOW peripherals
  * REST peripherals
  */
 
-/* ISP (image signal processor) is only available in U335 */
-#ifdef CONFIG_MACH_U300_BS335
+/* ISP (image signal processor) */
 #define U300_ISP_BASE                  (0xA0008000)
-#endif
 
 /* DMA Controller base */
 #define U300_DMAC_BASE                 (0xC0020000)
 #define U300_APEX_BASE                 (0xc0030000)
 
 /* Video Encoder Base */
-#ifdef CONFIG_MACH_U300_BS335
 #define U300_VIDEOENC_BASE             (0xc0080000)
-#else
-#define U300_VIDEOENC_BASE             (0xc0040000)
-#endif
 
 /* XGAM Base */
 #define U300_XGAM_BASE                 (0xd0000000)
 
-/*
- * Virtual accessor macros for static devices
- */
-
 #endif
index a1affacfa59c459c59a05f79843e306591b3d908..02e6659286d5b0e4d2e2761954ebd81ce09aa766 100644 (file)
@@ -12,7 +12,7 @@
 #include <linux/amba/pl022.h>
 #include <linux/err.h>
 #include <mach/coh901318.h>
-#include <mach/dma_channels.h>
+#include "dma_channels.h"
 
 /*
  * The following is for the actual devices on the SSP/SPI bus
index 56ac06d38ec18a97fbc3c37fd98717fb796bcc40..1da10e20e996556f9b527f3bd19d40e831a6a857 100644 (file)
 #include <linux/io.h>
 #include <linux/clk.h>
 #include <linux/err.h>
+#include <linux/irq.h>
 
 #include <mach/hardware.h>
+#include <mach/irqs.h>
 
 /* Generic stuff */
 #include <asm/sched_clock.h>
 #include <asm/mach/map.h>
 #include <asm/mach/time.h>
-#include <asm/mach/irq.h>
+
+#include "timer.h"
 
 /*
  * APP side special timer registers
diff --git a/arch/arm/mach-u300/timer.h b/arch/arm/mach-u300/timer.h
new file mode 100644 (file)
index 0000000..b5e9791
--- /dev/null
@@ -0,0 +1 @@
+extern struct sys_timer u300_timer;
index 847dc25300c68d23731fbcc419f978cef5614774..83f50772e169557a23e08480a2c123d548f63a28 100644 (file)
@@ -1,50 +1,11 @@
 /*
- * Individual pin assignments for the B26/S26. Notice that the
- * actual usage of these pins depends on the PAD MUX settings, that
- * is why the same number can potentially appear several times.
- * In the reference design each pin is only used for one purpose.
- * These were determined by inspecting the B26/S26 schematic:
- * 2/1911-ROA 128 1603
- */
-#ifdef CONFIG_MACH_U300_BS2X
-#define U300_GPIO_PIN_UART_RX          0
-#define U300_GPIO_PIN_UART_TX          1
-#define U300_GPIO_PIN_GPIO02           2  /* Unrouted */
-#define U300_GPIO_PIN_GPIO03           3  /* Unrouted */
-#define U300_GPIO_PIN_CAM_SLEEP                4
-#define U300_GPIO_PIN_CAM_REG_EN       5
-#define U300_GPIO_PIN_GPIO06           6  /* Unrouted */
-#define U300_GPIO_PIN_GPIO07           7  /* Unrouted */
-
-#define U300_GPIO_PIN_GPIO08           8  /* Service point SP2321 */
-#define U300_GPIO_PIN_GPIO09           9  /* Service point SP2322 */
-#define U300_GPIO_PIN_PHFSENSE         10 /* Headphone jack sensing */
-#define U300_GPIO_PIN_MMC_CLKRET       11 /* Clock return from MMC/SD card */
-#define U300_GPIO_PIN_MMC_CD           12 /* MMC Card insertion detection */
-#define U300_GPIO_PIN_FLIPSENSE                13 /* Mechanical flip sensing */
-#define U300_GPIO_PIN_GPIO14           14 /* DSP JTAG Port RTCK */
-#define U300_GPIO_PIN_GPIO15           15 /* Unrouted */
-
-#define U300_GPIO_PIN_GPIO16           16 /* Unrouted */
-#define U300_GPIO_PIN_GPIO17           17 /* Unrouted */
-#define U300_GPIO_PIN_GPIO18           18 /* Unrouted */
-#define U300_GPIO_PIN_GPIO19           19 /* Unrouted */
-#define U300_GPIO_PIN_GPIO20           20 /* Unrouted */
-#define U300_GPIO_PIN_GPIO21           21 /* Unrouted */
-#define U300_GPIO_PIN_GPIO22           22 /* Unrouted */
-#define U300_GPIO_PIN_GPIO23           23 /* Unrouted */
-#endif
-
-/*
- * Individual pin assignments for the B330/S330 and B365/S365.
+ * Individual pin assignments for the B335/S335.
  * Notice that the actual usage of these pins depends on the
  * PAD MUX settings, that is why the same number can potentially
  * appear several times. In the reference design each pin is only
  * used for one purpose. These were determined by inspecting the
  * S365 schematic.
  */
-#if defined(CONFIG_MACH_U300_BS330) || defined(CONFIG_MACH_U300_BS365) || \
-    defined(CONFIG_MACH_U300_BS335)
 #define U300_GPIO_PIN_UART_RX          0
 #define U300_GPIO_PIN_UART_TX          1
 #define U300_GPIO_PIN_UART_CTS         2
@@ -90,8 +51,6 @@
 #define U300_GPIO_PIN_GPIO38           38 /* Unrouted */
 #define U300_GPIO_PIN_GPIO39           39 /* Unrouted */
 
-#ifdef CONFIG_MACH_U300_BS335
-
 #define U300_GPIO_PIN_GPIO40           40 /* Unrouted */
 #define U300_GPIO_PIN_GPIO41           41 /* Unrouted */
 #define U300_GPIO_PIN_GPIO42           42 /* Unrouted */
 #define U300_GPIO_PIN_GPIO53           53 /* Unrouted */
 #define U300_GPIO_PIN_GPIO54           54 /* Unrouted */
 #define U300_GPIO_PIN_GPIO55           55 /* Unrouted */
-#endif
-
-#endif
diff --git a/arch/arm/mach-u300/u300.c b/arch/arm/mach-u300/u300.c
deleted file mode 100644 (file)
index f30c69d..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- *
- * arch/arm/mach-u300/u300.c
- *
- *
- * Copyright (C) 2006-2009 ST-Ericsson AB
- * License terms: GNU General Public License (GPL) version 2
- * Platform machine definition.
- * Author: Linus Walleij <linus.walleij@stericsson.com>
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/memblock.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-#include <mach/hardware.h>
-#include <mach/platform.h>
-#include <asm/hardware/vic.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/memory.h>
-
-static void __init u300_init_machine(void)
-{
-       u300_init_devices();
-}
-
-#ifdef CONFIG_MACH_U300_BS2X
-#define MACH_U300_STRING "Ericsson AB U300 S25/S26/B25/B26 Prototype Board"
-#endif
-
-#ifdef CONFIG_MACH_U300_BS330
-#define MACH_U300_STRING "Ericsson AB U330 S330/B330 Prototype Board"
-#endif
-
-#ifdef CONFIG_MACH_U300_BS335
-#define MACH_U300_STRING "Ericsson AB U335 S335/B335 Prototype Board"
-#endif
-
-#ifdef CONFIG_MACH_U300_BS365
-#define MACH_U300_STRING "Ericsson AB U365 S365/B365 Prototype Board"
-#endif
-
-MACHINE_START(U300, MACH_U300_STRING)
-       /* Maintainer: Linus Walleij <linus.walleij@stericsson.com> */
-       .atag_offset    = 0x100,
-       .map_io         = u300_map_io,
-       .init_irq       = u300_init_irq,
-       .handle_irq     = vic_handle_irq,
-       .timer          = &u300_timer,
-       .init_machine   = u300_init_machine,
-       .restart        = u300_restart,
-MACHINE_END
index dc12394295d5e5e8a6798e9295225aeb50b5039d..75d5b512a3d54fc8adf547be4aa128d3735a92a8 100644 (file)
@@ -38,7 +38,7 @@ static int __init ux500_l2x0_init(void)
 {
        u32 aux_val = 0x3e000000;
 
-       if (cpu_is_u8500_family())
+       if (cpu_is_u8500_family() || cpu_is_ux540_family())
                l2x0_base = __io_address(U8500_L2CC_BASE);
        else
                ux500_unknown_soc();
index db3c52d56ca46ad54bddbcaaa2f48d7c64f025a6..8169f2c72d6c593964db1a7f8a1abf88592db0ac 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/mfd/abx500/ab8500.h>
 
 #include <asm/mach/map.h>
-#include <asm/pmu.h>
 #include <plat/gpio-nomadik.h>
 #include <mach/hardware.h>
 #include <mach/setup.h>
@@ -80,7 +79,7 @@ void __init u8500_map_io(void)
 
        iotable_init(u8500_common_io_desc, ARRAY_SIZE(u8500_common_io_desc));
 
-       if (cpu_is_u9540())
+       if (cpu_is_ux540_family())
                iotable_init(u9540_io_desc, ARRAY_SIZE(u9540_io_desc));
        else
                iotable_init(u8500_io_desc, ARRAY_SIZE(u8500_io_desc));
@@ -122,7 +121,7 @@ struct arm_pmu_platdata db8500_pmu_platdata = {
 
 static struct platform_device db8500_pmu_device = {
        .name                   = "arm-pmu",
-       .id                     = ARM_PMU_DEVICE_CPU,
+       .id                     = -1,
        .num_resources          = ARRAY_SIZE(db8500_pmu_resources),
        .resource               = db8500_pmu_resources,
        .dev.platform_data      = &db8500_pmu_platdata,
index e2360e7c770d3a6c99b8abedfc38810503f290a7..4b0a9b3003123e51da736e6421aede1e29eaaf46 100644 (file)
@@ -51,7 +51,7 @@ void __init ux500_init_irq(void)
        void __iomem *dist_base;
        void __iomem *cpu_base;
 
-       if (cpu_is_u8500_family()) {
+       if (cpu_is_u8500_family() || cpu_is_ux540_family()) {
                dist_base = __io_address(U8500_GIC_DIST_BASE);
                cpu_base = __io_address(U8500_GIC_CPU_BASE);
        } else
index c6e2db9e9e5143db632a422fee1ff46067651715..9c42642ab1680b4ca5d7ec22c6cd6e51b8c82e7b 100644 (file)
@@ -41,43 +41,29 @@ static inline bool __attribute_const__ cpu_is_u8500(void)
        return dbx500_partnumber() == 0x8500;
 }
 
-static inline bool __attribute_const__ cpu_is_u9540(void)
+static inline bool __attribute_const__ cpu_is_u8520(void)
 {
-       return dbx500_partnumber() == 0x9540;
+       return dbx500_partnumber() == 0x8520;
 }
 
 static inline bool cpu_is_u8500_family(void)
 {
-       return cpu_is_u8500() || cpu_is_u9540();
-}
-
-static inline bool __attribute_const__ cpu_is_u5500(void)
-{
-       return dbx500_partnumber() == 0x5500;
-}
-
-/*
- * 5500 revisions
- */
-
-static inline bool __attribute_const__ cpu_is_u5500v1(void)
-{
-       return cpu_is_u5500() && (dbx500_revision() & 0xf0) == 0xA0;
+       return cpu_is_u8500() || cpu_is_u8520();
 }
 
-static inline bool __attribute_const__ cpu_is_u5500v2(void)
+static inline bool __attribute_const__ cpu_is_u9540(void)
 {
-       return (dbx500_id.revision & 0xf0) == 0xB0;
+       return dbx500_partnumber() == 0x9540;
 }
 
-static inline bool __attribute_const__ cpu_is_u5500v20(void)
+static inline bool __attribute_const__ cpu_is_u8540(void)
 {
-       return cpu_is_u5500() && ((dbx500_revision() & 0xf0) == 0xB0);
+       return dbx500_partnumber() == 0x8540;
 }
 
-static inline bool __attribute_const__ cpu_is_u5500v21(void)
+static inline bool cpu_is_ux540_family(void)
 {
-       return cpu_is_u5500() && (dbx500_revision() == 0xB1);
+       return cpu_is_u9540() || cpu_is_u8540();
 }
 
 /*
@@ -119,14 +105,14 @@ static inline bool cpu_is_u8500v21(void)
        return cpu_is_u8500() && (dbx500_revision() == 0xB1);
 }
 
+static inline bool cpu_is_u8500v22(void)
+{
+       return cpu_is_u8500() && (dbx500_revision() == 0xB2);
+}
+
 static inline bool cpu_is_u8500v20_or_later(void)
 {
-       /*
-        * U9540 has so much in common with U8500 that is is considered a
-        * U8500 variant.
-        */
-       return cpu_is_u9540() ||
-               (cpu_is_u8500() && !cpu_is_u8500v10() && !cpu_is_u8500v11());
+       return (cpu_is_u8500() && !cpu_is_u8500v10() && !cpu_is_u8500v11());
 }
 
 static inline bool ux500_is_svp(void)
index da1d5ad5bd4531ae3d142e8a65f39de6d67eae56..cb35897c1ea3df2e58392904c602a9cb3e3d73bb 100644 (file)
@@ -48,7 +48,7 @@ static void write_pen_release(int val)
 
 static void __iomem *scu_base_addr(void)
 {
-       if (cpu_is_u8500_family())
+       if (cpu_is_u8500_family() || cpu_is_ux540_family())
                return __io_address(U8500_SCU_BASE);
        else
                ux500_unknown_soc();
index cd8ea3588f93d3db2b557def5d0e844cf101b380..5b5c1eeb5b5c1c0d7517ba2b3c9849b07e045bdd 100644 (file)
@@ -37,7 +37,6 @@
 #include <linux/mtd/physmap.h>
 
 #include <asm/irq.h>
-#include <asm/leds.h>
 #include <asm/hardware/arm_timer.h>
 #include <asm/hardware/icst.h>
 #include <asm/hardware/vic.h>
@@ -169,11 +168,6 @@ static struct map_desc versatile_io_desc[] __initdata = {
                .pfn            = __phys_to_pfn(VERSATILE_PCI_CFG_BASE),
                .length         = VERSATILE_PCI_CFG_BASE_SIZE,
                .type           = MT_DEVICE
-       }, {
-               .virtual        =  (unsigned long)VERSATILE_PCI_VIRT_MEM_BASE0,
-               .pfn            = __phys_to_pfn(VERSATILE_PCI_MEM_BASE0),
-               .length         = IO_SPACE_LIMIT,
-               .type           = MT_DEVICE
        },
 #endif
 };
@@ -763,10 +757,6 @@ void __init versatile_init(void)
                struct amba_device *d = amba_devs[i];
                amba_device_register(d, &iomem_resource);
        }
-
-#ifdef CONFIG_LEDS
-       leds_event = versatile_leds_event;
-#endif
 }
 
 /*
index 408e58da46c641a81098622a028956f38e4e4253..3e5d425e2a926897b13d692403d6266ae29a5f15 100644 (file)
@@ -29,7 +29,6 @@
  */
 #define VERSATILE_PCI_VIRT_BASE                (void __iomem *)0xe8000000ul
 #define VERSATILE_PCI_CFG_VIRT_BASE    (void __iomem *)0xe9000000ul
-#define VERSATILE_PCI_VIRT_MEM_BASE0   (void __iomem *)PCIO_BASE
 
 /* macro to get at MMIO space when running virtually */
 #define IO_ADDRESS(x)          (((x) & 0x0fffffff) + (((x) >> 4) & 0x0f000000) + 0xf0000000)
diff --git a/arch/arm/mach-versatile/include/mach/io.h b/arch/arm/mach-versatile/include/mach/io.h
deleted file mode 100644 (file)
index 0406513..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- *  arch/arm/mach-versatile/include/mach/io.h
- *
- *  Copyright (C) 2003 ARM Limited
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-#ifndef __ASM_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
-
-#define PCIO_BASE      0xeb000000ul
-
-#define __io(a)                ((a) + PCIO_BASE)
-
-#endif
index e95bf84cc837550650ccc053e5afc72486d6682a..2f84f4094f13dfe186b9a14f87051fdb73d0e8d0 100644 (file)
@@ -169,13 +169,6 @@ static struct pci_ops pci_versatile_ops = {
        .write  = versatile_write_config,
 };
 
-static struct resource io_port = {
-       .name   = "PCI",
-       .start  = 0,
-       .end    = IO_SPACE_LIMIT,
-       .flags  = IORESOURCE_IO,
-};
-
 static struct resource io_mem = {
        .name   = "PCI I/O space",
        .start  = VERSATILE_PCI_MEM_BASE0,
@@ -207,12 +200,6 @@ static int __init pci_versatile_setup_resources(struct pci_sys_data *sys)
                       "memory region (%d)\n", ret);
                goto out;
        }
-       ret = request_resource(&ioport_resource, &io_port);
-       if (ret) {
-               printk(KERN_ERR "PCI: unable to allocate I/O "
-                      "port region (%d)\n", ret);
-               goto out;
-       }
        ret = request_resource(&iomem_resource, &non_mem);
        if (ret) {
                printk(KERN_ERR "PCI: unable to allocate non-prefetchable "
@@ -227,11 +214,9 @@ static int __init pci_versatile_setup_resources(struct pci_sys_data *sys)
        }
 
        /*
-        * the IO resource for this bus
         * the mem resource for this bus
         * the prefetch mem resource for this bus
         */
-       pci_add_resource_offset(&sys->resources, &io_port, sys->io_offset);
        pci_add_resource_offset(&sys->resources, &non_mem, sys->mem_offset);
        pci_add_resource_offset(&sys->resources, &pre_mem, sys->mem_offset);
 
@@ -260,9 +245,11 @@ int __init pci_versatile_setup(int nr, struct pci_sys_data *sys)
                goto out;
        }
 
+       ret = pci_ioremap_io(0, VERSATILE_PCI_MEM_BASE0);
+       if (ret)
+               goto out;
+
        if (nr == 0) {
-               sys->mem_offset = 0;
-               sys->io_offset = 0;
                ret = pci_versatile_setup_resources(sys);
                if (ret < 0) {
                        printk("pci_versatile_setup: resources... oops?\n");
@@ -319,7 +306,6 @@ int __init pci_versatile_setup(int nr, struct pci_sys_data *sys)
 
 void __init pci_versatile_preinit(void)
 {
-       pcibios_min_io = 0x44000000;
        pcibios_min_mem = 0x50000000;
 
        __raw_writel(VERSATILE_PCI_MEM_BASE0 >> 28, PCI_IMAP0);
index 61c492403b05f46957787a7836ef12a0eee44695..e4073a60a86457968a871fb8ad3096c1970f892c 100644 (file)
@@ -13,7 +13,6 @@
 #include <asm/hardware/arm_timer.h>
 #include <asm/hardware/cache-l2x0.h>
 #include <asm/hardware/gic.h>
-#include <asm/pmu.h>
 #include <asm/smp_scu.h>
 #include <asm/smp_twd.h>
 
@@ -144,7 +143,7 @@ static struct resource pmu_resources[] = {
 
 static struct platform_device pmu_device = {
        .name           = "arm-pmu",
-       .id             = ARM_PMU_DEVICE_CPU,
+       .id             = -1,
        .num_resources  = ARRAY_SIZE(pmu_resources),
        .resource       = pmu_resources,
 };
index f9fbeb2d10e988525c7c775d960f619ec643d6c4..6fd9d609ebaa59172c8683c8b4b9995862154eda 100644 (file)
@@ -33,6 +33,7 @@ static struct platform_device *devices[] __initdata = {
        &vt8500_device_uart0,
        &vt8500_device_lcdc,
        &vt8500_device_ehci,
+       &vt8500_device_uhci,
        &vt8500_device_ge_rops,
        &vt8500_device_pwm,
        &vt8500_device_pwmbl,
index 19519aeecf37abba6fe80c626f83383bd52f4492..def7fe393a2c9d2c7967ccae12ec31fc53af3ae4 100644 (file)
@@ -48,6 +48,11 @@ void __init vt8500_set_resources(void)
        tmp[1] = wmt_irq_res(IRQ_EHCI);
        wmt_res_add(&vt8500_device_ehci, tmp, 2);
 
+       /* vt8500 uses a single IRQ for both EHCI and UHCI controllers */
+       tmp[0] = wmt_mmio_res(VT8500_UHCI_BASE, SZ_512);
+       tmp[1] = wmt_irq_res(IRQ_EHCI);
+       wmt_res_add(&vt8500_device_uhci, tmp, 2);
+
        tmp[0] = wmt_mmio_res(VT8500_GEGEA_BASE, SZ_256);
        wmt_res_add(&vt8500_device_ge_rops, tmp, 1);
 
index db4594e029f4785eaf0b0ba3abb8316edfc04b7c..c810454178dcf091b7091f547cccfb5e530c3444 100644 (file)
@@ -55,6 +55,10 @@ void __init wm8505_set_resources(void)
        tmp[1] = wmt_irq_res(IRQ_EHCI);
        wmt_res_add(&vt8500_device_ehci, tmp, 2);
 
+       tmp[0] = wmt_mmio_res(WM8505_UHCI_BASE, SZ_512);
+       tmp[1] = wmt_irq_res(IRQ_UHCI);
+       wmt_res_add(&vt8500_device_uhci, tmp, 2);
+
        tmp[0] = wmt_mmio_res(WM8505_GEGEA_BASE, SZ_256);
        wmt_res_add(&vt8500_device_ge_rops, tmp, 1);
 
index 1fcdc36b358df112a536bdf835a542d8392d50f1..46ff82dad54409bd8f897feabbe4fab04d472612 100644 (file)
@@ -204,6 +204,17 @@ struct platform_device vt8500_device_ehci = {
        },
 };
 
+static u64 uhci_dma_mask = DMA_BIT_MASK(32);
+
+struct platform_device vt8500_device_uhci = {
+       .name           = "platform-uhci",
+       .id             = 0,
+       .dev            = {
+               .dma_mask       = &uhci_dma_mask,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
+       },
+};
+
 struct platform_device vt8500_device_ge_rops = {
        .name           = "wmt_ge_rops",
        .id             = -1,
index 188d4e17f35c3d2dc8c7ffc63fcad750774a517a..0e6d9f904c773aa87d5d4963bce82700d027a9c0 100644 (file)
@@ -81,6 +81,7 @@ extern struct platform_device vt8500_device_uart5;
 extern struct platform_device vt8500_device_lcdc;
 extern struct platform_device vt8500_device_wm8505_fb;
 extern struct platform_device vt8500_device_ehci;
+extern struct platform_device vt8500_device_uhci;
 extern struct platform_device vt8500_device_ge_rops;
 extern struct platform_device vt8500_device_pwm;
 extern struct platform_device vt8500_device_pwmbl;
index db19886caf7ce679ff6ac2f98f0d5d70568e2eac..4804e2a4557463d422bfdaae9a47223fafc9bdc4 100644 (file)
@@ -32,6 +32,7 @@ static void __iomem *pmc_hiber;
 static struct platform_device *devices[] __initdata = {
        &vt8500_device_uart0,
        &vt8500_device_ehci,
+       &vt8500_device_uhci,
        &vt8500_device_wm8505_fb,
        &vt8500_device_ge_rops,
        &vt8500_device_pwm,
index 2a8e380501e81a2c0bcaf08c8d018f0c9f20050c..577baf7d0a8de418aa7a949dcbfb0ec824b7c3d0 100644 (file)
@@ -554,7 +554,7 @@ static const struct of_device_id l2x0_ids[] __initconst = {
 int __init l2x0_of_init(u32 aux_val, u32 aux_mask)
 {
        struct device_node *np;
-       struct l2x0_of_data *data;
+       const struct l2x0_of_data *data;
        struct resource res;
 
        np = of_find_matching_node(NULL, l2x0_ids);
index 23a7643e9a875925be1280d1bff0c3ee6ffab7ee..1be0f4e5e6eb7067b871d32d5eeb7af47954c42e 100644 (file)
  */
 
 #include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
 #include <asm/cacheflush.h>
 #include <asm/cp15.h>
+#include <asm/cputype.h>
 #include <asm/hardware/cache-tauros2.h>
 
 
@@ -144,25 +147,8 @@ static inline void __init write_extra_features(u32 u)
        __asm__("mcr p15, 1, %0, c15, c1, 0" : : "r" (u));
 }
 
-static void __init disable_l2_prefetch(void)
-{
-       u32 u;
-
-       /*
-        * Read the CPU Extra Features register and verify that the
-        * Disable L2 Prefetch bit is set.
-        */
-       u = read_extra_features();
-       if (!(u & 0x01000000)) {
-               printk(KERN_INFO "Tauros2: Disabling L2 prefetch.\n");
-               write_extra_features(u | 0x01000000);
-       }
-}
-
 static inline int __init cpuid_scheme(void)
 {
-       extern int processor_id;
-
        return !!((processor_id & 0x000f0000) == 0x000f0000);
 }
 
@@ -189,12 +175,36 @@ static inline void __init write_actlr(u32 actlr)
        __asm__("mcr p15, 0, %0, c1, c0, 1\n" : : "r" (actlr));
 }
 
-void __init tauros2_init(void)
+static void enable_extra_feature(unsigned int features)
+{
+       u32 u;
+
+       u = read_extra_features();
+
+       if (features & CACHE_TAUROS2_PREFETCH_ON)
+               u &= ~0x01000000;
+       else
+               u |= 0x01000000;
+       printk(KERN_INFO "Tauros2: %s L2 prefetch.\n",
+                       (features & CACHE_TAUROS2_PREFETCH_ON)
+                       ? "Enabling" : "Disabling");
+
+       if (features & CACHE_TAUROS2_LINEFILL_BURST8)
+               u |= 0x00100000;
+       else
+               u &= ~0x00100000;
+       printk(KERN_INFO "Tauros2: %s line fill burt8.\n",
+                       (features & CACHE_TAUROS2_LINEFILL_BURST8)
+                       ? "Enabling" : "Disabling");
+
+       write_extra_features(u);
+}
+
+static void __init tauros2_internal_init(unsigned int features)
 {
-       extern int processor_id;
-       char *mode;
+       char *mode = NULL;
 
-       disable_l2_prefetch();
+       enable_extra_feature(features);
 
 #ifdef CONFIG_CPU_32v5
        if ((processor_id & 0xff0f0000) == 0x56050000) {
@@ -286,3 +296,34 @@ void __init tauros2_init(void)
        printk(KERN_INFO "Tauros2: L2 cache support initialised "
                         "in %s mode.\n", mode);
 }
+
+#ifdef CONFIG_OF
+static const struct of_device_id tauros2_ids[] __initconst = {
+       { .compatible = "marvell,tauros2-cache"},
+       {}
+};
+#endif
+
+void __init tauros2_init(unsigned int features)
+{
+#ifdef CONFIG_OF
+       struct device_node *node;
+       int ret;
+       unsigned int f;
+
+       node = of_find_matching_node(NULL, tauros2_ids);
+       if (!node) {
+               pr_info("Not found marvell,tauros2-cache, disable it\n");
+               return;
+       }
+
+       ret = of_property_read_u32(node, "marvell,tauros2-cache-features", &f);
+       if (ret) {
+               pr_info("Not found marvell,tauros-cache-features property, "
+                       "disable extra features\n");
+               features = 0;
+       } else
+               features = f;
+#endif
+       tauros2_internal_init(features);
+}
index c2cdf6500f75dc5a1ab5a688ea305099e8d30057..4e7d1182e8a3a59270073b5cb3b348e0bd690ef8 100644 (file)
@@ -358,7 +358,7 @@ void __init dma_contiguous_remap(void)
                if (end > arm_lowmem_limit)
                        end = arm_lowmem_limit;
                if (start >= end)
-                       return;
+                       continue;
 
                map.pfn = __phys_to_pfn(start);
                map.virtual = __phys_to_virt(start);
@@ -423,7 +423,7 @@ static void *__alloc_from_pool(size_t size, struct page **ret_page)
        unsigned int pageno;
        unsigned long flags;
        void *ptr = NULL;
-       size_t align;
+       unsigned long align_mask;
 
        if (!pool->vaddr) {
                WARN(1, "coherent pool not initialised!\n");
@@ -435,11 +435,11 @@ static void *__alloc_from_pool(size_t size, struct page **ret_page)
         * small, so align them to their order in pages, minimum is a page
         * size. This helps reduce fragmentation of the DMA space.
         */
-       align = PAGE_SIZE << get_order(size);
+       align_mask = (1 << get_order(size)) - 1;
 
        spin_lock_irqsave(&pool->lock, flags);
        pageno = bitmap_find_next_zero_area(pool->bitmap, pool->nr_pages,
-                                           0, count, (1 << align) - 1);
+                                           0, count, align_mask);
        if (pageno < pool->nr_pages) {
                bitmap_set(pool->bitmap, pageno, count);
                ptr = pool->vaddr + PAGE_SIZE * pageno;
@@ -648,12 +648,12 @@ void arm_dma_free(struct device *dev, size_t size, void *cpu_addr,
 
        if (arch_is_coherent() || nommu()) {
                __dma_free_buffer(page, size);
+       } else if (__free_from_pool(cpu_addr, size)) {
+               return;
        } else if (!IS_ENABLED(CONFIG_CMA)) {
                __dma_free_remap(cpu_addr, size);
                __dma_free_buffer(page, size);
        } else {
-               if (__free_from_pool(cpu_addr, size))
-                       return;
                /*
                 * Non-atomic allocations cannot be freed with IRQs disabled
                 */
index 77458548e031fe73d75a5a79ea36f923c95cc88a..40ca11ed6e5fbae9c54914db0123bf136e788481 100644 (file)
@@ -231,8 +231,6 @@ void __sync_icache_dcache(pte_t pteval)
        struct page *page;
        struct address_space *mapping;
 
-       if (!pte_present_user(pteval))
-               return;
        if (cache_is_vipt_nonaliasing() && !pte_exec(pteval))
                /* only flush non-aliasing VIPT caches for exec mappings */
                return;
index 9aec41fa80ae31a23429db805bc1800fd7b19cbd..ad722f1208a57d21cae7ebca50dbddc2251d8d82 100644 (file)
@@ -324,7 +324,7 @@ phys_addr_t __init arm_memblock_steal(phys_addr_t size, phys_addr_t align)
 
        BUG_ON(!arm_memblock_steal_permitted);
 
-       phys = memblock_alloc(size, align);
+       phys = memblock_alloc_base(size, align, MEMBLOCK_ALLOC_ANYWHERE);
        memblock_free(phys, size);
        memblock_remove(phys, size);
 
index 566750fa57d4289eeff21ed482b09f8a8cdefe72..9d869f93a3da29a275101418cceba6fb122189b4 100644 (file)
@@ -36,6 +36,7 @@
 #include <asm/system_info.h>
 
 #include <asm/mach/map.h>
+#include <asm/mach/pci.h>
 #include "mm.h"
 
 int ioremap_page(unsigned long virt, unsigned long phys,
@@ -383,3 +384,16 @@ void __arm_iounmap(volatile void __iomem *io_addr)
        arch_iounmap(io_addr);
 }
 EXPORT_SYMBOL(__arm_iounmap);
+
+#ifdef CONFIG_PCI
+int pci_ioremap_io(unsigned int offset, phys_addr_t phys_addr)
+{
+       BUG_ON(offset + SZ_64K > IO_SPACE_LIMIT);
+
+       return ioremap_page_range(PCI_IO_VIRT_BASE + offset,
+                                 PCI_IO_VIRT_BASE + offset + SZ_64K,
+                                 phys_addr,
+                                 __pgprot(get_mem_type(MT_DEVICE)->prot_pte));
+}
+EXPORT_SYMBOL_GPL(pci_ioremap_io);
+#endif
index 4c2d0451e84af1c2a0347a6fe462dd2e3306db3e..512b2c042ce1b864c5c929773c7f45a1d0fa13a6 100644 (file)
@@ -31,6 +31,7 @@
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
+#include <asm/mach/pci.h>
 
 #include "mm.h"
 
@@ -216,7 +217,7 @@ static struct mem_type mem_types[] = {
                .prot_l1        = PMD_TYPE_TABLE,
                .prot_sect      = PROT_SECT_DEVICE | PMD_SECT_WB,
                .domain         = DOMAIN_IO,
-       },      
+       },
        [MT_DEVICE_WC] = {      /* ioremap_wc */
                .prot_pte       = PROT_PTE_DEVICE | L_PTE_MT_DEV_WC,
                .prot_l1        = PMD_TYPE_TABLE,
@@ -777,14 +778,27 @@ void __init iotable_init(struct map_desc *io_desc, int nr)
                create_mapping(md);
                vm->addr = (void *)(md->virtual & PAGE_MASK);
                vm->size = PAGE_ALIGN(md->length + (md->virtual & ~PAGE_MASK));
-               vm->phys_addr = __pfn_to_phys(md->pfn); 
-               vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING; 
+               vm->phys_addr = __pfn_to_phys(md->pfn);
+               vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING;
                vm->flags |= VM_ARM_MTYPE(md->type);
                vm->caller = iotable_init;
                vm_area_add_early(vm++);
        }
 }
 
+void __init vm_reserve_area_early(unsigned long addr, unsigned long size,
+                                 void *caller)
+{
+       struct vm_struct *vm;
+
+       vm = early_alloc_aligned(sizeof(*vm), __alignof__(*vm));
+       vm->addr = (void *)addr;
+       vm->size = size;
+       vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING;
+       vm->caller = caller;
+       vm_area_add_early(vm);
+}
+
 #ifndef CONFIG_ARM_LPAE
 
 /*
@@ -802,14 +816,7 @@ void __init iotable_init(struct map_desc *io_desc, int nr)
 
 static void __init pmd_empty_section_gap(unsigned long addr)
 {
-       struct vm_struct *vm;
-
-       vm = early_alloc_aligned(sizeof(*vm), __alignof__(*vm));
-       vm->addr = (void *)addr;
-       vm->size = SECTION_SIZE;
-       vm->flags = VM_IOREMAP | VM_ARM_STATIC_MAPPING;
-       vm->caller = pmd_empty_section_gap;
-       vm_area_add_early(vm);
+       vm_reserve_area_early(addr, SECTION_SIZE, pmd_empty_section_gap);
 }
 
 static void __init fill_pmd_gaps(void)
@@ -858,6 +865,28 @@ static void __init fill_pmd_gaps(void)
 #define fill_pmd_gaps() do { } while (0)
 #endif
 
+#if defined(CONFIG_PCI) && !defined(CONFIG_NEED_MACH_IO_H)
+static void __init pci_reserve_io(void)
+{
+       struct vm_struct *vm;
+       unsigned long addr;
+
+       /* we're still single threaded hence no lock needed here */
+       for (vm = vmlist; vm; vm = vm->next) {
+               if (!(vm->flags & VM_ARM_STATIC_MAPPING))
+                       continue;
+               addr = (unsigned long)vm->addr;
+               addr &= ~(SZ_2M - 1);
+               if (addr == PCI_IO_VIRT_BASE)
+                       return;
+
+       }
+       vm_reserve_area_early(PCI_IO_VIRT_BASE, SZ_2M, pci_reserve_io);
+}
+#else
+#define pci_reserve_io() do { } while (0)
+#endif
+
 static void * __initdata vmalloc_min =
        (void *)(VMALLOC_END - (240 << 20) - VMALLOC_OFFSET);
 
@@ -1141,6 +1170,9 @@ static void __init devicemaps_init(struct machine_desc *mdesc)
                mdesc->map_io();
        fill_pmd_gaps();
 
+       /* Reserve fixed i/o space in VMALLOC region */
+       pci_reserve_io();
+
        /*
         * Finally flush the caches and tlb to ensure that we're in a
         * consistent state wrt the writebuffer.  This also ensures that
index c2021139cb563fd14a74c327d453f3cf0cee183d..ea94765acf9a3650f5cb850f6990893f3ccb459b 100644 (file)
@@ -38,10 +38,10 @@ ENTRY(v7wbi_flush_user_tlb_range)
        dsb
        mov     r0, r0, lsr #PAGE_SHIFT         @ align address
        mov     r1, r1, lsr #PAGE_SHIFT
-#ifdef CONFIG_ARM_ERRATA_720789
-       mov     r3, #0
-#else
        asid    r3, r3                          @ mask ASID
+#ifdef CONFIG_ARM_ERRATA_720789
+       ALT_SMP(W(mov)  r3, #0  )
+       ALT_UP(W(nop)           )
 #endif
        orr     r0, r3, r0, lsl #PAGE_SHIFT     @ Create initial MVA
        mov     r1, r1, lsl #PAGE_SHIFT
index 8daae9b230ea93035919848f562636173a5d0d18..362474b5c40d411015df7c2b03670d299afddb28 100644 (file)
@@ -192,30 +192,24 @@ int iop3xx_pci_setup(int nr, struct pci_sys_data *sys)
        if (nr != 0)
                return 0;
 
-       res = kzalloc(2 * sizeof(struct resource), GFP_KERNEL);
+       res = kzalloc(sizeof(struct resource), GFP_KERNEL);
        if (!res)
                panic("PCI: unable to alloc resources");
 
-       res[0].start = IOP3XX_PCI_LOWER_IO_PA;
-       res[0].end   = IOP3XX_PCI_LOWER_IO_PA + IOP3XX_PCI_IO_WINDOW_SIZE - 1;
-       res[0].name  = "IOP3XX PCI I/O Space";
-       res[0].flags = IORESOURCE_IO;
-       request_resource(&ioport_resource, &res[0]);
-
-       res[1].start = IOP3XX_PCI_LOWER_MEM_PA;
-       res[1].end   = IOP3XX_PCI_LOWER_MEM_PA + IOP3XX_PCI_MEM_WINDOW_SIZE - 1;
-       res[1].name  = "IOP3XX PCI Memory Space";
-       res[1].flags = IORESOURCE_MEM;
-       request_resource(&iomem_resource, &res[1]);
+       res->start = IOP3XX_PCI_LOWER_MEM_PA;
+       res->end   = IOP3XX_PCI_LOWER_MEM_PA + IOP3XX_PCI_MEM_WINDOW_SIZE - 1;
+       res->name  = "IOP3XX PCI Memory Space";
+       res->flags = IORESOURCE_MEM;
+       request_resource(&iomem_resource, res);
 
        /*
         * Use whatever translation is already setup.
         */
        sys->mem_offset = IOP3XX_PCI_LOWER_MEM_PA - *IOP3XX_OMWTVR0;
-       sys->io_offset  = IOP3XX_PCI_LOWER_IO_PA - *IOP3XX_OIOWTVR;
 
-       pci_add_resource_offset(&sys->resources, &res[0], sys->io_offset);
-       pci_add_resource_offset(&sys->resources, &res[1], sys->mem_offset);
+       pci_add_resource_offset(&sys->resources, res, sys->mem_offset);
+
+       pci_ioremap_io(0, IOP3XX_PCI_LOWER_IO_PA);
 
        return 1;
 }
@@ -367,7 +361,6 @@ void __init iop3xx_pci_preinit_cond(void)
 
 void __init iop3xx_pci_preinit(void)
 {
-       pcibios_min_io = 0;
        pcibios_min_mem = 0;
 
        iop3xx_atu_disable();
index a2024b8685a15a37a0141132bcc49ce8f80aa599..ad9f9744a82d12b22e4c8d8407e686867b79f351 100644 (file)
@@ -9,7 +9,6 @@
  */
 
 #include <linux/platform_device.h>
-#include <asm/pmu.h>
 #include <mach/irqs.h>
 
 static struct resource pmu_resource = {
@@ -26,7 +25,7 @@ static struct resource pmu_resource = {
 
 static struct platform_device pmu_device = {
        .name           = "arm-pmu",
-       .id             = ARM_PMU_DEVICE_CPU,
+       .id             = -1,
        .resource       = &pmu_resource,
        .num_resources  = 1,
 };
index bade586fed0ff0e44587ebf682c162e41366294c..5b217f460f18ce4d0cd5a2499f17eaa264a25fec 100644 (file)
@@ -25,11 +25,6 @@ static struct map_desc iop3xx_std_desc[] __initdata = {
                .pfn            = __phys_to_pfn(IOP3XX_PERIPHERAL_PHYS_BASE),
                .length         = IOP3XX_PERIPHERAL_SIZE,
                .type           = MT_UNCACHED,
-        }, {   /* PCI IO space */
-               .virtual        = IOP3XX_PCI_LOWER_IO_VA,
-               .pfn            = __phys_to_pfn(IOP3XX_PCI_LOWER_IO_PA),
-               .length         = IOP3XX_PCI_IO_WINDOW_SIZE,
-               .type           = MT_DEVICE,
         },
 };
 
index cb3e3eef55c0b6dec152d8f0ea75212c6c6754fc..6b46cee2f9cd45ec5d6536ef9cfe5611a5962850 100644 (file)
@@ -15,7 +15,11 @@ config IMX_HAVE_PLATFORM_GPIO_KEYS
 
 config IMX_HAVE_PLATFORM_IMX21_HCD
        bool
-       
+
+config IMX_HAVE_PLATFORM_IMX27_CODA
+       bool
+       default y if SOC_IMX27
+
 config IMX_HAVE_PLATFORM_IMX2_WDT
        bool
 
index c11ac8472bebae264374f13db3bdb8fdf3337c6e..76f3195475d06abd27a9114cf3c64301a2ebdf52 100644 (file)
@@ -4,6 +4,7 @@ obj-$(CONFIG_IMX_HAVE_PLATFORM_FSL_USB2_UDC) += platform-fsl-usb2-udc.o
 obj-$(CONFIG_IMX_HAVE_PLATFORM_GPIO_KEYS) += platform-gpio_keys.o
 obj-y += platform-gpio-mxc.o
 obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX21_HCD) += platform-imx21-hcd.o
+obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX27_CODA) += platform-imx27-coda.o
 obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX2_WDT) += platform-imx2-wdt.o
 obj-$(CONFIG_IMX_HAVE_PLATFORM_IMXDI_RTC) += platform-imxdi_rtc.o
 obj-y += platform-imx-dma.o
diff --git a/arch/arm/plat-mxc/devices/platform-imx27-coda.c b/arch/arm/plat-mxc/devices/platform-imx27-coda.c
new file mode 100644 (file)
index 0000000..8b12aac
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2012 Vista Silicon
+ * Javier Martin <javier.martin@vista-silicon.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 <mach/hardware.h>
+#include <mach/devices-common.h>
+
+#ifdef CONFIG_SOC_IMX27
+const struct imx_imx27_coda_data imx27_coda_data __initconst = {
+       .iobase = MX27_VPU_BASE_ADDR,
+       .iosize = SZ_512,
+       .irq = MX27_INT_VPU,
+};
+#endif
+
+struct platform_device *__init imx_add_imx27_coda(
+               const struct imx_imx27_coda_data *data)
+{
+       struct resource res[] = {
+               {
+                       .start = data->iobase,
+                       .end = data->iobase + data->iosize - 1,
+                       .flags = IORESOURCE_MEM,
+               }, {
+                       .start = data->irq,
+                       .end = data->irq,
+                       .flags = IORESOURCE_IRQ,
+               },
+       };
+       return imx_add_platform_device_dmamask("coda-imx27", 0, res, 2, NULL,
+                                       0, DMA_BIT_MASK(32));
+}
index 1568f39fba8bec5ee2b67e459bf861c62d406d29..95b75cc70515efa8ffc0465cc44585b99ff70ede 100644 (file)
@@ -63,10 +63,6 @@ struct platform_device *__init imx_add_mxc_nand(
        /* AXI has to come first, that's how the mxc_nand driver expect it */
        struct resource res[] = {
                {
-                       .start = data->axibase,
-                       .end = data->axibase + SZ_16K - 1,
-                       .flags = IORESOURCE_MEM,
-               }, {
                        .start = data->iobase,
                        .end = data->iobase + data->iosize - 1,
                        .flags = IORESOURCE_MEM,
@@ -74,10 +70,13 @@ struct platform_device *__init imx_add_mxc_nand(
                        .start = data->irq,
                        .end = data->irq,
                        .flags = IORESOURCE_IRQ,
+               }, {
+                       .start = data->axibase,
+                       .end = data->axibase + SZ_16K - 1,
+                       .flags = IORESOURCE_MEM,
                },
        };
        return imx_add_platform_device("mxc_nand", data->id,
-                       res + !data->axibase,
-                       ARRAY_SIZE(res) - !data->axibase,
+                       res, ARRAY_SIZE(res) - !data->axibase,
                        pdata, sizeof(*pdata));
 }
index a7f5bb1084d72da97843fb73468cdd1c8f4a70fd..762780cad1bd1fc3375b3b7219c970180de1a556 100644 (file)
@@ -83,6 +83,14 @@ struct platform_device *__init imx_add_imx21_hcd(
                const struct imx_imx21_hcd_data *data,
                const struct mx21_usbh_platform_data *pdata);
 
+struct imx_imx27_coda_data {
+       resource_size_t iobase;
+       resource_size_t iosize;
+       resource_size_t irq;
+};
+struct platform_device *__init imx_add_imx27_coda(
+               const struct imx_imx27_coda_data *data);
+
 struct imx_imx2_wdt_data {
        int id;
        resource_size_t iobase;
index dd36eba9506c85877d91e57d2d95894343199d7d..13910baae2282cdabd2f3f0d9704533664d8fa15 100644 (file)
@@ -41,9 +41,8 @@ config OMAP_DEBUG_DEVICES
          For debug cards on TI reference boards.
 
 config OMAP_DEBUG_LEDS
-       bool
+       def_bool y if NEW_LEDS
        depends on OMAP_DEBUG_DEVICES
-       default y if LEDS_CLASS
 
 config POWER_AVS_OMAP
        bool "AVS(Adaptive Voltage Scaling) support for OMAP IP versions 1&2"
index 39407cbe34c65ab0308a5b1585ad896d5c5f3c2f..24e23f3dd6a889b5df44a9310d308558d8caa283 100644 (file)
 /*
  * linux/arch/arm/plat-omap/debug-leds.c
  *
+ * Copyright 2011 by Bryan Wu <bryan.wu@canonical.com>
  * Copyright 2003 by Texas Instruments Incorporated
  *
  * 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/leds.h>
 #include <linux/io.h>
+#include <linux/slab.h>
 
 #include <mach/hardware.h>
-#include <asm/leds.h>
 #include <asm/mach-types.h>
 
 #include <plat/fpga.h>
 
-
 /* Many OMAP development platforms reuse the same "debug board"; these
  * platforms include H2, H3, H4, and Perseus2.  There are 16 LEDs on the
  * debug board (all green), accessed through FPGA registers.
- *
- * The "surfer" expansion board and H2 sample board also have two-color
- * green+red LEDs (in parallel), used here for timer and idle indicators
- * in preference to the ones on the debug board, for a "Disco LED" effect.
- *
- * This driver exports either the original ARM LED API, the new generic
- * one, or both.
- */
-
-static spinlock_t                      lock;
-static struct h2p2_dbg_fpga __iomem    *fpga;
-static u16                             led_state, hw_led_state;
-
-
-#ifdef CONFIG_OMAP_DEBUG_LEDS
-#define new_led_api()  1
-#else
-#define new_led_api()  0
-#endif
-
-
-/*-------------------------------------------------------------------------*/
-
-/* original ARM debug LED API:
- *  - timer and idle leds (some boards use non-FPGA leds here);
- *  - up to 4 generic leds, easily accessed in-kernel (any context)
  */
 
-#define GPIO_LED_RED           3
-#define GPIO_LED_GREEN         OMAP_MPUIO(4)
-
-#define LED_STATE_ENABLED      0x01
-#define LED_STATE_CLAIMED      0x02
-#define LED_TIMER_ON           0x04
-
-#define GPIO_IDLE              GPIO_LED_GREEN
-#define GPIO_TIMER             GPIO_LED_RED
-
-static void h2p2_dbg_leds_event(led_event_t evt)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&lock, flags);
-
-       if (!(led_state & LED_STATE_ENABLED) && evt != led_start)
-               goto done;
-
-       switch (evt) {
-       case led_start:
-               if (fpga)
-                       led_state |= LED_STATE_ENABLED;
-               break;
-
-       case led_stop:
-       case led_halted:
-               /* all leds off during suspend or shutdown */
-
-               if (!(machine_is_omap_perseus2() || machine_is_omap_h4())) {
-                       gpio_set_value(GPIO_TIMER, 0);
-                       gpio_set_value(GPIO_IDLE, 0);
-               }
-
-               __raw_writew(~0, &fpga->leds);
-               led_state &= ~LED_STATE_ENABLED;
-               goto done;
-
-       case led_claim:
-               led_state |= LED_STATE_CLAIMED;
-               hw_led_state = 0;
-               break;
-
-       case led_release:
-               led_state &= ~LED_STATE_CLAIMED;
-               break;
-
-#ifdef CONFIG_LEDS_TIMER
-       case led_timer:
-               led_state ^= LED_TIMER_ON;
-
-               if (machine_is_omap_perseus2() || machine_is_omap_h4())
-                       hw_led_state ^= H2P2_DBG_FPGA_P2_LED_TIMER;
-               else {
-                       gpio_set_value(GPIO_TIMER,
-                                       led_state & LED_TIMER_ON);
-                       goto done;
-               }
-
-               break;
-#endif
-
-#ifdef CONFIG_LEDS_CPU
-       /* LED lit iff busy */
-       case led_idle_start:
-               if (machine_is_omap_perseus2() || machine_is_omap_h4())
-                       hw_led_state &= ~H2P2_DBG_FPGA_P2_LED_IDLE;
-               else {
-                       gpio_set_value(GPIO_IDLE, 1);
-                       goto done;
-               }
-
-               break;
+static struct h2p2_dbg_fpga __iomem *fpga;
 
-       case led_idle_end:
-               if (machine_is_omap_perseus2() || machine_is_omap_h4())
-                       hw_led_state |= H2P2_DBG_FPGA_P2_LED_IDLE;
-               else {
-                       gpio_set_value(GPIO_IDLE, 0);
-                       goto done;
-               }
-
-               break;
-#endif
-
-       case led_green_on:
-               hw_led_state |= H2P2_DBG_FPGA_LED_GREEN;
-               break;
-       case led_green_off:
-               hw_led_state &= ~H2P2_DBG_FPGA_LED_GREEN;
-               break;
-
-       case led_amber_on:
-               hw_led_state |= H2P2_DBG_FPGA_LED_AMBER;
-               break;
-       case led_amber_off:
-               hw_led_state &= ~H2P2_DBG_FPGA_LED_AMBER;
-               break;
-
-       case led_red_on:
-               hw_led_state |= H2P2_DBG_FPGA_LED_RED;
-               break;
-       case led_red_off:
-               hw_led_state &= ~H2P2_DBG_FPGA_LED_RED;
-               break;
-
-       case led_blue_on:
-               hw_led_state |= H2P2_DBG_FPGA_LED_BLUE;
-               break;
-       case led_blue_off:
-               hw_led_state &= ~H2P2_DBG_FPGA_LED_BLUE;
-               break;
-
-       default:
-               break;
-       }
-
-
-       /*
-        *  Actually burn the LEDs
-        */
-       if (led_state & LED_STATE_ENABLED)
-               __raw_writew(~hw_led_state, &fpga->leds);
-
-done:
-       spin_unlock_irqrestore(&lock, flags);
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* "new" LED API
- *  - with syfs access and generic triggering
- *  - not readily accessible to in-kernel drivers
- */
+static u16 fpga_led_state;
 
 struct dbg_led {
        struct led_classdev     cdev;
        u16                     mask;
 };
 
-static struct dbg_led dbg_leds[] = {
-       /* REVISIT at least H2 uses different timer & cpu leds... */
-#ifndef CONFIG_LEDS_TIMER
-       { .mask = 1 << 0,  .cdev.name =  "d4:green",
-               .cdev.default_trigger = "heartbeat", },
-#endif
-#ifndef CONFIG_LEDS_CPU
-       { .mask = 1 << 1,  .cdev.name =  "d5:green", },         /* !idle */
-#endif
-       { .mask = 1 << 2,  .cdev.name =  "d6:green", },
-       { .mask = 1 << 3,  .cdev.name =  "d7:green", },
-
-       { .mask = 1 << 4,  .cdev.name =  "d8:green", },
-       { .mask = 1 << 5,  .cdev.name =  "d9:green", },
-       { .mask = 1 << 6,  .cdev.name = "d10:green", },
-       { .mask = 1 << 7,  .cdev.name = "d11:green", },
-
-       { .mask = 1 << 8,  .cdev.name = "d12:green", },
-       { .mask = 1 << 9,  .cdev.name = "d13:green", },
-       { .mask = 1 << 10, .cdev.name = "d14:green", },
-       { .mask = 1 << 11, .cdev.name = "d15:green", },
-
-#ifndef        CONFIG_LEDS
-       { .mask = 1 << 12, .cdev.name = "d16:green", },
-       { .mask = 1 << 13, .cdev.name = "d17:green", },
-       { .mask = 1 << 14, .cdev.name = "d18:green", },
-       { .mask = 1 << 15, .cdev.name = "d19:green", },
-#endif
+static const struct {
+       const char *name;
+       const char *trigger;
+} dbg_leds[] = {
+       { "dbg:d4", "heartbeat", },
+       { "dbg:d5", "cpu0", },
+       { "dbg:d6", "default-on", },
+       { "dbg:d7", },
+       { "dbg:d8", },
+       { "dbg:d9", },
+       { "dbg:d10", },
+       { "dbg:d11", },
+       { "dbg:d12", },
+       { "dbg:d13", },
+       { "dbg:d14", },
+       { "dbg:d15", },
+       { "dbg:d16", },
+       { "dbg:d17", },
+       { "dbg:d18", },
+       { "dbg:d19", },
 };
 
-static void
-fpga_led_set(struct led_classdev *cdev, enum led_brightness value)
+/*
+ * The triggers lines up below will only be used if the
+ * LED triggers are compiled in.
+ */
+static void dbg_led_set(struct led_classdev *cdev,
+                             enum led_brightness b)
 {
-       struct dbg_led  *led = container_of(cdev, struct dbg_led, cdev);
-       unsigned long   flags;
+       struct dbg_led *led = container_of(cdev, struct dbg_led, cdev);
+       u16 reg;
 
-       spin_lock_irqsave(&lock, flags);
-       if (value == LED_OFF)
-               hw_led_state &= ~led->mask;
+       reg = __raw_readw(&fpga->leds);
+       if (b != LED_OFF)
+               reg |= led->mask;
        else
-               hw_led_state |= led->mask;
-       __raw_writew(~hw_led_state, &fpga->leds);
-       spin_unlock_irqrestore(&lock, flags);
+               reg &= ~led->mask;
+       __raw_writew(reg, &fpga->leds);
 }
 
-static void __init newled_init(struct device *dev)
+static enum led_brightness dbg_led_get(struct led_classdev *cdev)
 {
-       unsigned        i;
-       struct dbg_led  *led;
-       int             status;
+       struct dbg_led *led = container_of(cdev, struct dbg_led, cdev);
+       u16 reg;
 
-       for (i = 0, led = dbg_leds; i < ARRAY_SIZE(dbg_leds); i++, led++) {
-               led->cdev.brightness_set = fpga_led_set;
-               status = led_classdev_register(dev, &led->cdev);
-               if (status < 0)
-                       break;
-       }
-       return;
+       reg = __raw_readw(&fpga->leds);
+       return (reg & led->mask) ? LED_FULL : LED_OFF;
 }
 
-
-/*-------------------------------------------------------------------------*/
-
-static int /* __init */ fpga_probe(struct platform_device *pdev)
+static int fpga_probe(struct platform_device *pdev)
 {
        struct resource *iomem;
-
-       spin_lock_init(&lock);
+       int i;
 
        iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!iomem)
                return -ENODEV;
 
        fpga = ioremap(iomem->start, H2P2_DBG_FPGA_SIZE);
-       __raw_writew(~0, &fpga->leds);
+       __raw_writew(0xff, &fpga->leds);
+
+       for (i = 0; i < ARRAY_SIZE(dbg_leds); i++) {
+               struct dbg_led *led;
+
+               led = kzalloc(sizeof(*led), GFP_KERNEL);
+               if (!led)
+                       break;
 
-#ifdef CONFIG_LEDS
-       leds_event = h2p2_dbg_leds_event;
-       leds_event(led_start);
-#endif
+               led->cdev.name = dbg_leds[i].name;
+               led->cdev.brightness_set = dbg_led_set;
+               led->cdev.brightness_get = dbg_led_get;
+               led->cdev.default_trigger = dbg_leds[i].trigger;
+               led->mask = BIT(i);
 
-       if (new_led_api()) {
-               newled_init(&pdev->dev);
+               if (led_classdev_register(NULL, &led->cdev) < 0) {
+                       kfree(led);
+                       break;
+               }
        }
 
        return 0;
@@ -281,13 +120,15 @@ static int /* __init */ fpga_probe(struct platform_device *pdev)
 
 static int fpga_suspend_noirq(struct device *dev)
 {
-       __raw_writew(~0, &fpga->leds);
+       fpga_led_state = __raw_readw(&fpga->leds);
+       __raw_writew(0xff, &fpga->leds);
+
        return 0;
 }
 
 static int fpga_resume_noirq(struct device *dev)
 {
-       __raw_writew(~hw_led_state, &fpga->leds);
+       __raw_writew(~fpga_led_state, &fpga->leds);
        return 0;
 }
 
index 626ad8cad7a9486d71408f611b4f99b46c85b995..938b50a33439b092202de715e81267b18b5f73cb 100644 (file)
@@ -189,6 +189,7 @@ struct omap_dm_timer *omap_dm_timer_request(void)
                timer->reserved = 1;
                break;
        }
+       spin_unlock_irqrestore(&dm_timer_lock, flags);
 
        if (timer) {
                ret = omap_dm_timer_prepare(timer);
@@ -197,7 +198,6 @@ struct omap_dm_timer *omap_dm_timer_request(void)
                        timer = NULL;
                }
        }
-       spin_unlock_irqrestore(&dm_timer_lock, flags);
 
        if (!timer)
                pr_debug("%s: timer request failed!\n", __func__);
@@ -220,6 +220,7 @@ struct omap_dm_timer *omap_dm_timer_request_specific(int id)
                        break;
                }
        }
+       spin_unlock_irqrestore(&dm_timer_lock, flags);
 
        if (timer) {
                ret = omap_dm_timer_prepare(timer);
@@ -228,7 +229,6 @@ struct omap_dm_timer *omap_dm_timer_request_specific(int id)
                        timer = NULL;
                }
        }
-       spin_unlock_irqrestore(&dm_timer_lock, flags);
 
        if (!timer)
                pr_debug("%s: timer%d request failed!\n", __func__, id);
@@ -258,7 +258,7 @@ EXPORT_SYMBOL_GPL(omap_dm_timer_enable);
 
 void omap_dm_timer_disable(struct omap_dm_timer *timer)
 {
-       pm_runtime_put(&timer->pdev->dev);
+       pm_runtime_put_sync(&timer->pdev->dev);
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_disable);
 
index 68b180edcfffd0e05c9256aaa153993500177f84..bb5d08a70dbc64ac961945669655e2c47d380750 100644 (file)
@@ -372,7 +372,8 @@ IS_OMAP_TYPE(3430, 0x3430)
 #define cpu_class_is_omap1()   (cpu_is_omap7xx() || cpu_is_omap15xx() || \
                                cpu_is_omap16xx())
 #define cpu_class_is_omap2()   (cpu_is_omap24xx() || cpu_is_omap34xx() || \
-                               cpu_is_omap44xx() || soc_is_omap54xx())
+                               cpu_is_omap44xx() || soc_is_omap54xx() || \
+                               soc_is_am33xx())
 
 /* Various silicon revisions for omap2 */
 #define OMAP242X_CLASS         0x24200024
index 045e320f1067408abc1ef08e6a3667fe911c63f7..324d31b14852e632d614635e40af358d24a36aab 100644 (file)
 # endif
 #endif
 
+#ifdef CONFIG_SOC_AM33XX
+# ifdef OMAP_NAME
+#  undef  MULTI_OMAP2
+#  define MULTI_OMAP2
+# else
+#  define OMAP_NAME am33xx
+# endif
+#endif
+
 #endif /* __PLAT_OMAP_MULTI_H */
index 1a52725ffcf25ca682f80c9d4004a0ce5411cfa4..52d3de45745fd1ed20ca7589a2cd561c6d31eff4 100644 (file)
@@ -69,6 +69,9 @@ struct omap_uart_port_info {
        unsigned int            dma_rx_timeout;
        unsigned int            autosuspend_timeout;
        unsigned int            dma_rx_poll_rate;
+       int                     DTR_gpio;
+       int                     DTR_inverted;
+       int                     DTR_present;
 
        int (*get_context_loss_count)(struct device *);
        void (*set_forceidle)(struct platform_device *);
@@ -131,6 +134,10 @@ struct uart_omap_port {
        u32                     errata;
        u8                      wakeups_enabled;
 
+       int                     DTR_gpio;
+       int                     DTR_inverted;
+       int                     DTR_active;
+
        struct pm_qos_request   pm_qos_request;
        u32                     latency;
        u32                     calc_latency;
index b8d19a136781e4ba89382cc151ba6fe0190ccbc3..7f7b112acccb897b90066a6b8357a943284c3a14 100644 (file)
@@ -110,7 +110,7 @@ static inline void flush(void)
        _DEBUG_LL_ENTRY(mach, AM33XX_UART##p##_BASE, OMAP_PORT_SHIFT,   \
                AM33XXUART##p)
 
-static inline void __arch_decomp_setup(unsigned long arch_id)
+static inline void arch_decomp_setup(void)
 {
        int port = 0;
 
@@ -198,8 +198,6 @@ static inline void __arch_decomp_setup(unsigned long arch_id)
        } while (0);
 }
 
-#define arch_decomp_setup()    __arch_decomp_setup(arch_id)
-
 /*
  * nothing to do
  */
index d245a87dc014d4c6cf3d1c9a3285add47a56ecb5..b8b747a9d360110e9ca24b505f5249a730209e3e 100644 (file)
@@ -291,10 +291,12 @@ static struct platform_device orion_ge00 = {
 void __init orion_ge00_init(struct mv643xx_eth_platform_data *eth_data,
                            unsigned long mapbase,
                            unsigned long irq,
-                           unsigned long irq_err)
+                           unsigned long irq_err,
+                           unsigned int tx_csum_limit)
 {
        fill_resources(&orion_ge00_shared, orion_ge00_shared_resources,
                       mapbase + 0x2000, SZ_16K - 1, irq_err);
+       orion_ge00_shared_data.tx_csum_limit = tx_csum_limit;
        ge_complete(&orion_ge00_shared_data,
                    orion_ge00_resources, irq, &orion_ge00_shared,
                    eth_data, &orion_ge00);
@@ -343,10 +345,12 @@ static struct platform_device orion_ge01 = {
 void __init orion_ge01_init(struct mv643xx_eth_platform_data *eth_data,
                            unsigned long mapbase,
                            unsigned long irq,
-                           unsigned long irq_err)
+                           unsigned long irq_err,
+                           unsigned int tx_csum_limit)
 {
        fill_resources(&orion_ge01_shared, orion_ge01_shared_resources,
                       mapbase + 0x2000, SZ_16K - 1, irq_err);
+       orion_ge01_shared_data.tx_csum_limit = tx_csum_limit;
        ge_complete(&orion_ge01_shared_data,
                    orion_ge01_resources, irq, &orion_ge01_shared,
                    eth_data, &orion_ge01);
index e00fdb2136090154ea930c9f224365677644444e..ae2377ef63e5d9c455e07a4c8db7590f8935d4dc 100644 (file)
@@ -39,12 +39,14 @@ void __init orion_rtc_init(unsigned long mapbase,
 void __init orion_ge00_init(struct mv643xx_eth_platform_data *eth_data,
                            unsigned long mapbase,
                            unsigned long irq,
-                           unsigned long irq_err);
+                           unsigned long irq_err,
+                           unsigned int tx_csum_limit);
 
 void __init orion_ge01_init(struct mv643xx_eth_platform_data *eth_data,
                            unsigned long mapbase,
                            unsigned long irq,
-                           unsigned long irq_err);
+                           unsigned long irq_err,
+                           unsigned int tx_csum_limit);
 
 void __init orion_ge10_init(struct mv643xx_eth_platform_data *eth_data,
                            unsigned long mapbase,
index 7aca31c1df1fe57ac91b4278b13ad8036a8dac93..9c3b90c3538e3b71bb1e71c8c8bf817ca5057a89 100644 (file)
@@ -403,7 +403,8 @@ config S5P_DEV_USB_EHCI
 
 config S3C24XX_PWM
        bool "PWM device support"
-       select HAVE_PWM
+       select PWM
+       select PWM_SAMSUNG
        help
          Support for exporting the PWM timer blocks via the pwm device
          system
index fc49f3dabd7653624b7f9ccc8e78ef12b102d527..6ff45d53362c1a0ef61d0806626829223f96e78e 100644 (file)
@@ -35,7 +35,6 @@
 #include <media/s5p_hdmi.h>
 
 #include <asm/irq.h>
-#include <asm/pmu.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
@@ -1132,7 +1131,7 @@ static struct resource s5p_pmu_resource[] = {
 
 static struct platform_device s5p_device_pmu = {
        .name           = "arm-pmu",
-       .id             = ARM_PMU_DEVICE_CPU,
+       .id             = -1,
        .num_resources  = ARRAY_SIZE(s5p_pmu_resource),
        .resource       = s5p_pmu_resource,
 };
index 4dcb11c3d894013e93d9a5c799e95ec5cc0a9582..60552e22f22e11ccd74fb63b02779f1481e22abb 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/io.h>
 #include <linux/platform_device.h>
 
-#include <asm/leds.h>
 #include <asm/mach-types.h>
 
 #include <asm/irq.h>
index 8d5c10a5084da5dcaa87855abacb9f0a7e005a02..2a4ae8a6a08116466d5aa60662ceeb2e92f7ed2a 100644 (file)
@@ -16,8 +16,10 @@ config PLAT_VERSATILE_FPGA_IRQ_NR
        depends on PLAT_VERSATILE_FPGA_IRQ
 
 config PLAT_VERSATILE_LEDS
-       def_bool y if LEDS_CLASS
+       def_bool y if NEW_LEDS
        depends on ARCH_REALVIEW || ARCH_VERSATILE
+       select LEDS_CLASS
+       select LEDS_TRIGGER
 
 config PLAT_VERSATILE_SCHED_CLOCK
        def_bool y
index 3169fa555ea689acc1875c6bbacba2d6f3319ad0..d2490d00b46cd4e2e6c17a685eda16942ee930d6 100644 (file)
@@ -37,10 +37,10 @@ static const struct {
 } versatile_leds[] = {
        { "versatile:0", "heartbeat", },
        { "versatile:1", "mmc0", },
-       { "versatile:2", },
-       { "versatile:3", },
-       { "versatile:4", },
-       { "versatile:5", },
+       { "versatile:2", "cpu0" },
+       { "versatile:3", "cpu1" },
+       { "versatile:4", "cpu2" },
+       { "versatile:5", "cpu3" },
        { "versatile:6", },
        { "versatile:7", },
 };
index fb849d044bde9b231d481201c985f84cc37c0a3d..c834b32af275d73d4cd760efeb4a365e940f1df7 100644 (file)
@@ -719,8 +719,10 @@ static int __init vfp_init(void)
                        if ((fmrx(MVFR1) & 0x000fff00) == 0x00011100)
                                elf_hwcap |= HWCAP_NEON;
 #endif
+#ifdef CONFIG_VFPv3
                        if ((fmrx(MVFR1) & 0xf0000000) == 0x10000000)
                                elf_hwcap |= HWCAP_VFPv4;
+#endif
                }
        }
        return 0;
index 5ade51c8a87fbf5cd99d319ddbe55feef8fbe6c7..06e73bf665e92cba042590dbe68a50a463d50f76 100644 (file)
@@ -15,6 +15,8 @@ config AVR32
        select ARCH_WANT_IPC_PARSE_VERSION
        select ARCH_HAVE_NMI_SAFE_CMPXCHG
        select GENERIC_CLOCKEVENTS
+       select HAVE_MOD_ARCH_SPECIFIC
+       select MODULES_USE_ELF_RELA
        help
          AVR32 is a high-performance 32-bit RISC microprocessor core,
          designed for cost-sensitive embedded applications, with particular
index 451444538a1b06d2121c40bcc81d6b08a8cc3427..3f083d385a64e43a6b16b6d2bff73df37a21e024 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __ASM_AVR32_MODULE_H
 #define __ASM_AVR32_MODULE_H
 
+#include <asm-generic/module.h>
+
 struct mod_arch_syminfo {
        unsigned long got_offset;
        int got_initialized;
@@ -17,10 +19,6 @@ struct mod_arch_specific {
        struct mod_arch_syminfo *syminfo;
 };
 
-#define Elf_Shdr               Elf32_Shdr
-#define Elf_Sym                        Elf32_Sym
-#define Elf_Ehdr               Elf32_Ehdr
-
 #define MODULE_PROC_FAMILY "AVR32v1"
 
 #define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY
index f34861920634d15c9de2b1149aa8562a767e64f1..a48d8bee720eb60556d4a3c0574b2e19caa5250a 100644 (file)
@@ -41,6 +41,8 @@ config BLACKFIN
        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
 
 config GENERIC_CSUM
        def_bool y
index ed5689b82c9fefa7edc3303136a14a6edba2d13d..231a149b3f77df96eb59fb8dcc0eda22449d614d 100644 (file)
@@ -7,9 +7,7 @@
 #ifndef _ASM_BFIN_MODULE_H
 #define _ASM_BFIN_MODULE_H
 
-#define Elf_Shdr        Elf32_Shdr
-#define Elf_Sym         Elf32_Sym
-#define Elf_Ehdr        Elf32_Ehdr
+#include <asm-generic/module.h>
 
 struct mod_arch_specific {
        Elf_Shdr        *text_l1;
index ada8f0fc71e4731fc9bb619aacc7a77df50d7d54..fb96e607adcf815890de6ce475c55a3cfd76a42b 100644 (file)
@@ -52,7 +52,6 @@ EXPORT_SYMBOL(reserved_mem_dcache_on);
 #ifdef CONFIG_MTD_UCLINUX
 extern struct map_info uclinux_ram_map;
 unsigned long memory_mtd_end, memory_mtd_start, mtd_size;
-unsigned long _ebss;
 EXPORT_SYMBOL(memory_mtd_end);
 EXPORT_SYMBOL(memory_mtd_start);
 EXPORT_SYMBOL(mtd_size);
index 052f81a762398670188778a0645c8ed9ad1a4982..f6a3648f5ec3c7030a8c4294be4e3bee54a25b6c 100644 (file)
@@ -6,6 +6,7 @@
 config C6X
        def_bool y
        select CLKDEV_LOOKUP
+       select GENERIC_ATOMIC64
        select GENERIC_IRQ_SHOW
        select HAVE_ARCH_TRACEHOOK
        select HAVE_DMA_API_DEBUG
@@ -16,6 +17,7 @@ config C6X
        select OF
        select OF_EARLY_FLATTREE
        select GENERIC_CLOCKEVENTS
+       select MODULES_USE_ELF_RELA
 
 config MMU
        def_bool n
index 6d521d96d94136e25cd83158a5706a1c6681a84f..09c5a0f5f4d1778156a5ee83715e6a2aec7f0441 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  Port on Texas Instruments TMS320C6x architecture
  *
- *  Copyright (C) 2005, 2006, 2009, 2010 Texas Instruments Incorporated
+ *  Copyright (C) 2005, 2006, 2009, 2010, 2012 Texas Instruments Incorporated
  *  Author: Aurelien Jacquiot (aurelien.jacquiot@jaluna.com)
  *
  *  This program is free software; you can redistribute it and/or modify
 /*
  * Cache line size
  */
-#define L1D_CACHE_BYTES   64
-#define L1P_CACHE_BYTES   32
-#define L2_CACHE_BYTES   128
+#define L1D_CACHE_SHIFT   6
+#define L1D_CACHE_BYTES   (1 << L1D_CACHE_SHIFT)
+
+#define L1P_CACHE_SHIFT   5
+#define L1P_CACHE_BYTES   (1 << L1P_CACHE_SHIFT)
+
+#define L2_CACHE_SHIFT    7
+#define L2_CACHE_BYTES    (1 << L2_CACHE_SHIFT)
 
 /*
  * L2 used as cache
@@ -29,7 +34,8 @@
  * For practical reasons the L1_CACHE_BYTES defines should not be smaller than
  * the L2 line size
  */
-#define L1_CACHE_BYTES        L2_CACHE_BYTES
+#define L1_CACHE_SHIFT        L2_CACHE_SHIFT
+#define L1_CACHE_BYTES        (1 << L1_CACHE_SHIFT)
 
 #define L2_CACHE_ALIGN_LOW(x) \
        (((x) & ~(L2_CACHE_BYTES - 1)))
index a453f9744f42aa0269e1512589a798ee38815d6d..5c7269c7ef73f72f8939af4ee23d929d39a506cd 100644 (file)
 #ifndef _ASM_C6X_MODULE_H
 #define _ASM_C6X_MODULE_H
 
-#define Elf_Shdr       Elf32_Shdr
-#define Elf_Sym                Elf32_Sym
-#define Elf_Ehdr       Elf32_Ehdr
-#define Elf_Addr       Elf32_Addr
-#define Elf_Word       Elf32_Word
-
-/*
- * This file contains the C6x architecture specific module code.
- */
-struct mod_arch_specific {
-};
+#include <asm-generic/module.h>
 
 struct loaded_sections {
        unsigned int new_vaddr;
index e92215428a37e315d0b5df9f962df8e4c8090dcc..26160e255d126c63781eb4309eb29a5940f76992 100644 (file)
@@ -47,6 +47,7 @@ config CRIS
        select GENERIC_IOMAP
        select GENERIC_SMP_IDLE_THREAD if ETRAX_ARCH_V32
        select GENERIC_CMOS_UPDATE
+       select MODULES_USE_ELF_RELA
 
 config HZ
        int
@@ -138,11 +139,6 @@ config CRIS_MACH_ARTPEC3
 
 endchoice
 
-config ETRAX_VCS_SIM
-       bool "VCS Simulator"
-       help
-         Setup hardware to be run in the VCS simulator.
-
 config ETRAX_ARCH_V10
        bool
        default y if ETRAX100LX || ETRAX100LX_V2
index b34438e026be436d6c71632a250a23c187d9c6f7..1b6ad6247204c0b9d09f63f7e4731aaf70cb83cd 100644 (file)
@@ -329,7 +329,6 @@ static int __init init_axis_flash(void)
        }
 #endif
 
-#ifndef CONFIG_ETRAX_VCS_SIM
        main_mtd = flash_probe();
        if (main_mtd)
                printk(KERN_INFO "%s: 0x%08x bytes of NOR flash memory.\n",
@@ -603,34 +602,7 @@ static int __init init_axis_flash(void)
                                        "partition %d\n", part);
                }
        }
-#endif /* CONFIG_EXTRAX_VCS_SIM */
 
-#ifdef CONFIG_ETRAX_VCS_SIM
-       /* For simulator, always use a RAM partition.
-        * The rootfs will be found after the kernel in RAM,
-        * with romfs_start and romfs_end indicating location and size.
-        */
-       struct mtd_info *mtd_ram;
-
-       mtd_ram = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
-       if (!mtd_ram) {
-               panic("axisflashmap: Couldn't allocate memory for "
-                     "mtd_info!\n");
-       }
-
-       printk(KERN_INFO "axisflashmap: Adding RAM partition for romfs, "
-              "at %u, size %u\n",
-              (unsigned) romfs_start, (unsigned) romfs_length);
-
-       err = mtdram_init_device(mtd_ram, (void *)romfs_start,
-                                romfs_length, "romfs");
-       if (err) {
-               panic("axisflashmap: Could not initialize MTD RAM "
-                     "device!\n");
-       }
-#endif /* CONFIG_EXTRAX_VCS_SIM */
-
-#ifndef CONFIG_ETRAX_VCS_SIM
        if (aux_mtd) {
                aux_partition.size = aux_mtd->size;
                err = mtd_device_register(aux_mtd, &aux_partition, 1);
@@ -639,7 +611,6 @@ static int __init init_axis_flash(void)
                              "aux mtd device!\n");
 
        }
-#endif /* CONFIG_EXTRAX_VCS_SIM */
 
        return err;
 }
index 5b1ee82f63c5452750caf791fff3bd975c6d9c6a..e3dfc72d0cfd760507f42ea74355511aa134c16d 100644 (file)
@@ -97,28 +97,3 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
                pcibios_enable_irq(dev);
        return 0;
 }
-
-int pcibios_assign_resources(void)
-{
-       struct pci_dev *dev = NULL;
-       int idx;
-       struct resource *r;
-
-       while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
-               int class = dev->class >> 8;
-
-               /* Don't touch classless devices and host bridges */
-               if (!class || class == PCI_CLASS_BRIDGE_HOST)
-                       continue;
-
-               for(idx=0; idx<6; idx++) {
-                       r = &dev->resource[idx];
-
-                       if (!r->start && r->end)
-                               pci_assign_resource(dev, idx);
-               }
-       }
-       return 0;
-}
-
-EXPORT_SYMBOL(pcibios_assign_resources);
index 5d502b9ab56da253f2bdb1336535754da99f52cf..51e34165ece7feb7d0da60d5e42af1581aa8b260 100644 (file)
        .global nand_boot
        .global swapper_pg_dir
 
-       ;; Dummy section to make it bootable with current VCS simulator
-#ifdef CONFIG_ETRAX_VCS_SIM
-       .section ".boot", "ax"
-       ba tstart
-       nop
-#endif
-
        .text
 tstart:
        ;; This is the entry point of the kernel. The CPU is currently in
@@ -75,17 +68,10 @@ secondary_cpu_entry: /* Entry point for secondary CPUs */
                | REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 4)     \
                | REG_FIELD(mmu, rw_mm_kbase_hi, base_d, 5)     \
                | REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb), $r0
-#elif !defined(CONFIG_ETRAX_VCS_SIM)
-       move.d  REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 8)       \
-               | REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 4)     \
-               | REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb), $r0
 #else
-       ;; Map the virtual DRAM to the RW eprom area at address 0.
-       ;; Also map 0xa for the hook calls,
        move.d  REG_FIELD(mmu, rw_mm_kbase_hi, base_e, 8)       \
                | REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 4)     \
-               | REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb)   \
-               | REG_FIELD(mmu, rw_mm_kbase_hi, base_a, 0xa), $r0
+               | REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb), $r0
 #endif
 
        ;; Temporary map of 0x40 -> 0x40 and 0x00 -> 0x00.
@@ -126,27 +112,6 @@ secondary_cpu_entry: /* Entry point for secondary CPUs */
                | REG_STATE(mmu, rw_mm_cfg, seg_2, page)        \
                | REG_STATE(mmu, rw_mm_cfg, seg_1, page)        \
                | REG_STATE(mmu, rw_mm_cfg, seg_0, linear), $r2
-#elif !defined(CONFIG_ETRAX_VCS_SIM)
-       move.d  REG_STATE(mmu, rw_mm_cfg, we, on)               \
-               | REG_STATE(mmu, rw_mm_cfg, acc, on)            \
-               | REG_STATE(mmu, rw_mm_cfg, ex, on)             \
-               | REG_STATE(mmu, rw_mm_cfg, inv, on)            \
-               | REG_STATE(mmu, rw_mm_cfg, seg_f, linear)      \
-               | REG_STATE(mmu, rw_mm_cfg, seg_e, linear)      \
-               | REG_STATE(mmu, rw_mm_cfg, seg_d, page)        \
-               | REG_STATE(mmu, rw_mm_cfg, seg_c, linear)      \
-               | REG_STATE(mmu, rw_mm_cfg, seg_b, linear)      \
-               | REG_STATE(mmu, rw_mm_cfg, seg_a, page)        \
-               | REG_STATE(mmu, rw_mm_cfg, seg_9, page)        \
-               | REG_STATE(mmu, rw_mm_cfg, seg_8, page)        \
-               | REG_STATE(mmu, rw_mm_cfg, seg_7, page)        \
-               | REG_STATE(mmu, rw_mm_cfg, seg_6, page)        \
-               | REG_STATE(mmu, rw_mm_cfg, seg_5, page)        \
-               | REG_STATE(mmu, rw_mm_cfg, seg_4, linear)      \
-               | REG_STATE(mmu, rw_mm_cfg, seg_3, page)        \
-               | REG_STATE(mmu, rw_mm_cfg, seg_2, page)        \
-               | REG_STATE(mmu, rw_mm_cfg, seg_1, page)        \
-               | REG_STATE(mmu, rw_mm_cfg, seg_0, linear), $r2
 #else
        move.d  REG_STATE(mmu, rw_mm_cfg, we, on)               \
                | REG_STATE(mmu, rw_mm_cfg, acc, on)            \
@@ -157,7 +122,7 @@ secondary_cpu_entry: /* Entry point for secondary CPUs */
                | REG_STATE(mmu, rw_mm_cfg, seg_d, page)        \
                | REG_STATE(mmu, rw_mm_cfg, seg_c, linear)      \
                | REG_STATE(mmu, rw_mm_cfg, seg_b, linear)      \
-               | REG_STATE(mmu, rw_mm_cfg, seg_a, linear)      \
+               | REG_STATE(mmu, rw_mm_cfg, seg_a, page)        \
                | REG_STATE(mmu, rw_mm_cfg, seg_9, page)        \
                | REG_STATE(mmu, rw_mm_cfg, seg_8, page)        \
                | REG_STATE(mmu, rw_mm_cfg, seg_7, page)        \
@@ -226,7 +191,6 @@ master_cpu:
        move.d secondary_cpu_entry, $r1
        move.d $r1, [$r0]
 #endif
-#ifndef CONFIG_ETRAX_VCS_SIM
        ; Check if starting from DRAM (network->RAM boot or unpacked
        ; compressed kernel), or directly from flash.
        lapcq   ., $r0
@@ -234,7 +198,6 @@ master_cpu:
        cmp.d   0x10000, $r0    ; Arbitrary, something above this code.
        blo     _inflash0
        nop
-#endif
 
        jump    _inram          ; Jump to cached RAM.
        nop
@@ -326,7 +289,6 @@ move_cramfs:
        move.d  romfs_length, $r1
        move.d  $r0, [$r1]
 
-#ifndef CONFIG_ETRAX_VCS_SIM
        ;; The kernel could have been unpacked to DRAM by the loader, but
        ;; the cramfs image could still be in the flash immediately
        ;; following the compressed kernel image. The loader passes the address
@@ -335,10 +297,6 @@ move_cramfs:
        cmp.d   0x0ffffff8, $r9
        bhs     _no_romfs_in_flash ; R9 points outside the flash area.
        nop
-#else
-       ba _no_romfs_in_flash
-       nop
-#endif
        ;; cramfs rootfs might to be in flash. Check for it.
        move.d  [$r9], $r0      ; cramfs_super.magic
        cmp.d   CRAMFS_MAGIC, $r0
@@ -396,7 +354,6 @@ _no_romfs_in_flash:
        move.d  romfs_length, $r3
        move.d  $r2, [$r3]      ; store size at romfs_length
 
-#ifndef CONFIG_ETRAX_VCS_SIM
        add.d   $r2, $r0        ; copy from end and downwards
        add.d   $r2, $r1
 
@@ -410,7 +367,6 @@ _no_romfs_in_flash:
        subq    1, $r2
        bne     1b
        nop
-#endif
 
 4:
        ;; BSS move done.
@@ -455,7 +411,6 @@ no_command_line:
        move.d  etrax_irv, $r1  ; Set the exception base register and pointer.
        move.d  $r0, [$r1]
 
-#ifndef CONFIG_ETRAX_VCS_SIM
        ;; Clear the BSS region from _bss_start to _end.
        move.d  __bss_start, $r0
        move.d  _end, $r1
@@ -463,15 +418,6 @@ no_command_line:
        cmp.d   $r1, $r0
        blo 1b
        nop
-#endif
-
-#ifdef CONFIG_ETRAX_VCS_SIM
-       /* Set the watchdog timeout to something big. Will be removed when */
-       /* watchdog can be disabled with command line option */
-       move.d  0x7fffffff, $r10
-       jsr     CPU_WATCHDOG_TIMEOUT
-       nop
-#endif
 
        ; Initialize registers to increase determinism
        move.d __bss_start, $r0
index 8c1d35cdf00a3aa0c0a65305148a92d091ebeaef..b06813aeb120147b82502029fc3b21d7c9204fd5 100644 (file)
@@ -381,23 +381,9 @@ static int read_register(char regno, unsigned int *valptr);
 /* Serial port, reads one character. ETRAX 100 specific. from debugport.c */
 int getDebugChar(void);
 
-#ifdef CONFIG_ETRAX_VCS_SIM
-int getDebugChar(void)
-{
-  return socketread();
-}
-#endif
-
 /* Serial port, writes one character. ETRAX 100 specific. from debugport.c */
 void putDebugChar(int val);
 
-#ifdef CONFIG_ETRAX_VCS_SIM
-void putDebugChar(int val)
-{
-  socketwrite((char *)&val, 1);
-}
-#endif
-
 /* Returns the integer equivalent of a hexadecimal character. */
 static int hex(char ch);
 
index 41fa6a6893a9ce2ce94247f95f750d68e3bd6f1a..d366e0891988ad24cbc378c83c0bf8100414df05 100644 (file)
@@ -1,10 +1,8 @@
-# $Id: Makefile,v 1.3 2007/03/13 11:57:46 starvik Exp $
 #
 # Makefile for the linux kernel.
 #
 
 obj-y   := dma.o pinmux.o io.o arbiter.o
-obj-$(CONFIG_ETRAX_VCS_SIM) += vcs_hook.o
 obj-$(CONFIG_CPU_FREQ)   += cpufreq.o
 
 clean:
diff --git a/arch/cris/arch-v32/mach-a3/vcs_hook.c b/arch/cris/arch-v32/mach-a3/vcs_hook.c
deleted file mode 100644 (file)
index 58b1a54..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Simulator hook mechanism
- */
-
-#include "vcs_hook.h"
-#include <asm/io.h>
-#include <stdarg.h>
-
-#define HOOK_TRIG_ADDR      0xb7000000
-#define HOOK_MEM_BASE_ADDR  0xce000000
-
-static volatile unsigned *hook_base;
-
-#define HOOK_DATA(offset) hook_base[offset]
-#define VHOOK_DATA(offset) hook_base[offset]
-#define HOOK_TRIG(funcid) \
-       do { \
-               *((unsigned *) HOOK_TRIG_ADDR) = funcid; \
-       } while (0)
-#define HOOK_DATA_BYTE(offset) ((unsigned char *)hook_base)[offset]
-
-static void hook_init(void)
-{
-       static int first = 1;
-       if (first) {
-               first = 0;
-               hook_base = ioremap(HOOK_MEM_BASE_ADDR, 8192);
-       }
-}
-
-static unsigned hook_trig(unsigned id)
-{
-       unsigned ret;
-
-       /* preempt_disable(); */
-
-       /* Dummy read from mem to make sure data has propagated to memory
-        * before trigging */
-       ret = *hook_base;
-
-       /* trigger hook */
-       HOOK_TRIG(id);
-
-       /* wait for call to finish */
-       while (VHOOK_DATA(0) > 0) ;
-
-       /* extract return value */
-
-       ret = VHOOK_DATA(1);
-
-       return ret;
-}
-
-int hook_call(unsigned id, unsigned pcnt, ...)
-{
-       va_list ap;
-       int i;
-       unsigned ret;
-
-       hook_init();
-
-       HOOK_DATA(0) = id;
-
-       va_start(ap, pcnt);
-       for (i = 1; i <= pcnt; i++)
-               HOOK_DATA(i) = va_arg(ap, unsigned);
-       va_end(ap);
-
-       ret = hook_trig(id);
-
-       return ret;
-}
-
-int hook_call_str(unsigned id, unsigned size, const char *str)
-{
-       int i;
-       unsigned ret;
-
-       hook_init();
-
-       HOOK_DATA(0) = id;
-       HOOK_DATA(1) = size;
-
-       for (i = 0; i < size; i++)
-               HOOK_DATA_BYTE(8 + i) = str[i];
-       HOOK_DATA_BYTE(8 + i) = 0;
-
-       ret = hook_trig(id);
-
-       return ret;
-}
-
-void print_str(const char *str)
-{
-       int i;
-       /* find null at end of string */
-       for (i = 1; str[i]; i++) ;
-       hook_call(hook_print_str, i, str);
-}
-
-void CPU_WATCHDOG_TIMEOUT(unsigned t)
-{
-}
diff --git a/arch/cris/arch-v32/mach-a3/vcs_hook.h b/arch/cris/arch-v32/mach-a3/vcs_hook.h
deleted file mode 100644 (file)
index 8b73d0e..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Simulator hook call mechanism
- */
-
-#ifndef __hook_h__
-#define __hook_h__
-
-int hook_call(unsigned id, unsigned pcnt, ...);
-int hook_call_str(unsigned id, unsigned size, const char *str);
-
-enum hook_ids {
-  hook_debug_on = 1,
-  hook_debug_off,
-  hook_stop_sim_ok,
-  hook_stop_sim_fail,
-  hook_alloc_shared,
-  hook_ptr_shared,
-  hook_free_shared,
-  hook_file2shared,
-  hook_cmp_shared,
-  hook_print_params,
-  hook_sim_time,
-  hook_stop_sim,
-  hook_kick_dog,
-  hook_dog_timeout,
-  hook_rand,
-  hook_srand,
-  hook_rand_range,
-  hook_print_str,
-  hook_print_hex,
-  hook_cmp_offset_shared,
-  hook_fill_random_shared,
-  hook_alloc_random_data,
-  hook_calloc_random_data,
-  hook_print_int,
-  hook_print_uint,
-  hook_fputc,
-  hook_init_fd,
-  hook_sbrk,
-  hook_print_context_descr,
-  hook_print_data_descr,
-  hook_print_group_descr,
-  hook_fill_shared,
-  hook_sl_srand,
-  hook_sl_rand_irange,
-  hook_sl_rand_urange,
-  hook_sl_sh_malloc_aligned,
-  hook_sl_sh_calloc_aligned,
-  hook_sl_sh_alloc_random_data,
-  hook_sl_sh_file2mem,
-  hook_sl_vera_mbox_handle,
-  hook_sl_vera_mbox_put,
-  hook_sl_vera_mbox_get,
-  hook_sl_system,
-  hook_sl_sh_hexdump
-};
-
-#endif
index 41fa6a6893a9ce2ce94247f95f750d68e3bd6f1a..d366e0891988ad24cbc378c83c0bf8100414df05 100644 (file)
@@ -1,10 +1,8 @@
-# $Id: Makefile,v 1.3 2007/03/13 11:57:46 starvik Exp $
 #
 # Makefile for the linux kernel.
 #
 
 obj-y   := dma.o pinmux.o io.o arbiter.o
-obj-$(CONFIG_ETRAX_VCS_SIM) += vcs_hook.o
 obj-$(CONFIG_CPU_FREQ)   += cpufreq.o
 
 clean:
diff --git a/arch/cris/arch-v32/mach-fs/vcs_hook.c b/arch/cris/arch-v32/mach-fs/vcs_hook.c
deleted file mode 100644 (file)
index b11594a..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Call simulator hook. This is the part running in the
- * simulated program.
- */
-
-#include "vcs_hook.h"
-#include <stdarg.h>
-#include <arch-v32/hwregs/reg_map.h>
-#include <arch-v32/hwregs/intr_vect_defs.h>
-
-#define HOOK_TRIG_ADDR     0xb7000000  /* hook cvlog model reg address */
-#define HOOK_MEM_BASE_ADDR 0xa0000000  /* csp4 (shared mem) base addr */
-
-#define HOOK_DATA(offset) ((unsigned *)HOOK_MEM_BASE_ADDR)[offset]
-#define VHOOK_DATA(offset) ((volatile unsigned *)HOOK_MEM_BASE_ADDR)[offset]
-#define HOOK_TRIG(funcid) \
-       do { \
-               *((unsigned *) HOOK_TRIG_ADDR) = funcid; \
-       } while (0)
-#define HOOK_DATA_BYTE(offset) ((unsigned char *)HOOK_MEM_BASE_ADDR)[offset]
-
-int hook_call(unsigned id, unsigned pcnt, ...)
-{
-       va_list ap;
-       unsigned i;
-       unsigned ret;
-#ifdef USING_SOS
-       PREEMPT_OFF_SAVE();
-#endif
-
-       /* pass parameters */
-       HOOK_DATA(0) = id;
-
-       /* Have to make hook_print_str a special case since we call with a
-        * parameter of byte type. Should perhaps be a separate
-        * hook_call. */
-
-       if (id == hook_print_str) {
-               int i;
-               char *str;
-
-               HOOK_DATA(1) = pcnt;
-
-               va_start(ap, pcnt);
-               str = (char *)va_arg(ap, unsigned);
-
-               for (i = 0; i != pcnt; i++)
-                       HOOK_DATA_BYTE(8 + i) = str[i];
-
-               HOOK_DATA_BYTE(8 + i) = 0;      /* null byte */
-       } else {
-               va_start(ap, pcnt);
-               for (i = 1; i <= pcnt; i++)
-                       HOOK_DATA(i) = va_arg(ap, unsigned);
-               va_end(ap);
-       }
-
-       /* read from mem to make sure data has propagated to memory before
-        * trigging */
-       ret = *((volatile unsigned *)HOOK_MEM_BASE_ADDR);
-
-       /* trigger hook */
-       HOOK_TRIG(id);
-
-       /* wait for call to finish */
-       while (VHOOK_DATA(0) > 0) ;
-
-       /* extract return value */
-
-       ret = VHOOK_DATA(1);
-
-#ifdef USING_SOS
-       PREEMPT_RESTORE();
-#endif
-       return ret;
-}
-
-unsigned hook_buf(unsigned i)
-{
-       return (HOOK_DATA(i));
-}
-
-void print_str(const char *str)
-{
-       int i;
-       /* find null at end of string */
-       for (i = 1; str[i]; i++) ;
-       hook_call(hook_print_str, i, str);
-}
-
-void CPU_KICK_DOG(void)
-{
-       (void)hook_call(hook_kick_dog, 0);
-}
-
-void CPU_WATCHDOG_TIMEOUT(unsigned t)
-{
-       (void)hook_call(hook_dog_timeout, 1, t);
-}
-
diff --git a/arch/cris/arch-v32/mach-fs/vcs_hook.h b/arch/cris/arch-v32/mach-fs/vcs_hook.h
deleted file mode 100644 (file)
index c000b9f..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Call simulator hook functions
- */
-
-#ifndef HOOK_H
-#define HOOK_H
-
-int hook_call(unsigned id, unsigned pcnt, ...);
-
-enum hook_ids {
-  hook_debug_on = 1,
-  hook_debug_off,
-  hook_stop_sim_ok,
-  hook_stop_sim_fail,
-  hook_alloc_shared,
-  hook_ptr_shared,
-  hook_free_shared,
-  hook_file2shared,
-  hook_cmp_shared,
-  hook_print_params,
-  hook_sim_time,
-  hook_stop_sim,
-  hook_kick_dog,
-  hook_dog_timeout,
-  hook_rand,
-  hook_srand,
-  hook_rand_range,
-  hook_print_str,
-  hook_print_hex,
-  hook_cmp_offset_shared,
-  hook_fill_random_shared,
-  hook_alloc_random_data,
-  hook_calloc_random_data,
-  hook_print_int,
-  hook_print_uint,
-  hook_fputc,
-  hook_init_fd,
-  hook_sbrk
-
-};
-
-#endif
index 0768bc409ca88dcb32c7650460e63a18fec4eca1..3deca5253d91be5e448253abec875994ba7b9f9b 100644 (file)
@@ -73,11 +73,7 @@ void __init cris_mmu_init(void)
 #endif
                       REG_STATE(mmu, rw_mm_cfg, seg_c, linear) |
                       REG_STATE(mmu, rw_mm_cfg, seg_b, linear) |
-#ifndef CONFIG_ETRAX_VCS_SIM
                        REG_STATE(mmu, rw_mm_cfg, seg_a, page)   |
-#else
-                      REG_STATE(mmu, rw_mm_cfg, seg_a, linear) |
-#endif
                       REG_STATE(mmu, rw_mm_cfg, seg_9, page)   |
                       REG_STATE(mmu, rw_mm_cfg, seg_8, page)   |
                       REG_STATE(mmu, rw_mm_cfg, seg_7, page)   |
@@ -100,11 +96,7 @@ void __init cris_mmu_init(void)
 #endif
                          REG_FIELD(mmu, rw_mm_kbase_hi, base_c, 0x4) |
                         REG_FIELD(mmu, rw_mm_kbase_hi, base_b, 0xb) |
-#ifndef CONFIG_ETRAX_VCS_SIM
                         REG_FIELD(mmu, rw_mm_kbase_hi, base_a, 0x0) |
-#else
-                         REG_FIELD(mmu, rw_mm_kbase_hi, base_a, 0xa) |
-#endif
                         REG_FIELD(mmu, rw_mm_kbase_hi, base_9, 0x0) |
                         REG_FIELD(mmu, rw_mm_kbase_hi, base_8, 0x0));
 
index 20f1b4806bfe4f6d4a35fd5e3fee626c53195be8..e5b5aab52de81ce29ef5b2994400185e2e617295 100644 (file)
  * selected bit it's possible to convert between KSEG_x and 0x40000000 where the
  * DRAM really resides. DRAM is virtually at 0xc.
  */
-#ifndef CONFIG_ETRAX_VCS_SIM
 #define __pa(x) ((unsigned long)(x) & 0x7fffffff)
 #define __va(x) ((void *)((unsigned long)(x) | 0x80000000))
-#else
-#define __pa(x) ((unsigned long)(x) & 0x3fffffff)
-#define __va(x) ((void *)((unsigned long)(x) | 0xc0000000))
-#endif
 
 #define VM_STACK_DEFAULT_FLAGS (VM_READ | VM_WRITE | \
                                 VM_MAYREAD | VM_MAYWRITE)
index 9603c907fbc4947f4d31077355224fb83638274d..a024b7d32fed9b9066cd66e11fe8ffcd222aba9b 100644 (file)
@@ -21,13 +21,9 @@ struct thread_struct {
 
 /*
  * User-space process size. This is hardcoded into a few places, so don't
- * changed it unless everything's clear!
+ * change it unless everything's clear!
  */
-#ifndef CONFIG_ETRAX_VCS_SIM
 #define TASK_SIZE      (0xB0000000UL)
-#else
-#define TASK_SIZE      (0xA0000000UL)
-#endif
 
 /* CCS I=1, enable interrupts. */
 #define INIT_THREAD { 0, 0, (1 << I_CCS_BITNR) }
index dd1abbdcbc7aff9133e73f98e46dac05546f38f2..96c3b0fb62c12dc8cba32a6bfd054cf4ca2993ee 100644 (file)
        move.d   REG_ADDR(bif_core, regi_bif_core, rw_grp4_cfg), $r0
        move.d   CONFIG_ETRAX_MEM_GRP4_CONFIG, $r1
        move.d   $r1, [$r0]
-#ifdef CONFIG_ETRAX_VCS_SIM
-       ;; Set up minimal flash waitstates
-       move.d 0, $r10
-       move.d REG_ADDR(bif_core, regi_bif_core, rw_grp1_cfg), $r11
-       move.d $r10, [$r11]
-#endif
        .endm
 
 #endif
index 04d02a51c5e90a2b7dde5403f23329ece74362bc..28b690de797116ca4f5deb292021b75e72924e82 100644 (file)
@@ -7,3 +7,5 @@ header-y += ethernet.h
 header-y += etraxgpio.h
 header-y += rs485.h
 header-y += sync_serial.h
+
+generic-y += module.h
diff --git a/arch/cris/include/asm/module.h b/arch/cris/include/asm/module.h
deleted file mode 100644 (file)
index 7ee7231..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef _ASM_CRIS_MODULE_H
-#define _ASM_CRIS_MODULE_H
-/* cris is simple */
-struct mod_arch_specific { };
-
-#define Elf_Shdr Elf32_Shdr
-#define Elf_Sym Elf32_Sym
-#define Elf_Ehdr Elf32_Ehdr
-#endif /* _ASM_CRIS_MODULE_H */
index 9f1cd56da28cc88884035107faa9497f220b7bd2..146da904cdd84c83fa67d5c3e88ca74f25bd8648 100644 (file)
@@ -19,7 +19,6 @@ extern unsigned long pci_mem_start;
 
 void pcibios_config_init(void);
 struct pci_bus * pcibios_scan_root(int bus);
-int pcibios_assign_resources(void);
 
 void pcibios_set_master(struct pci_dev *dev);
 void pcibios_penalize_isa_irq(int irq);
index 3d5c6360289a8085bb782c5909263bc00a83c697..a8848f09a217d6ead10e61c859713e5677cee828 100644 (file)
 #ifndef _ASM_MODULE_H
 #define _ASM_MODULE_H
 
-struct mod_arch_specific
-{
-};
-
-#define Elf_Shdr       Elf32_Shdr
-#define Elf_Sym                Elf32_Sym
-#define Elf_Ehdr       Elf32_Ehdr
+#include <asm-generic/module.h>
 
 /*
  * Include the architecture version.
index 5e8a0d9a09ce0035e424dc0334370607f306deb9..c149d3b29eb6a1b990c44025137e2632574a3d88 100644 (file)
@@ -6,6 +6,7 @@ config H8300
        select ARCH_WANT_IPC_PARSE_VERSION
        select GENERIC_IRQ_SHOW
        select GENERIC_CPU_DEVICES
+       select MODULES_USE_ELF_RELA
 
 config SYMBOL_PREFIX
        string
index c68e1680da0173d5754d1a1df4944120a5239e58..871382d239fef60105b37f50424afe24ed6773e3 100644 (file)
@@ -1 +1,3 @@
 include include/asm-generic/Kbuild.asm
+
+generic-y      += module.h
diff --git a/arch/h8300/include/asm/module.h b/arch/h8300/include/asm/module.h
deleted file mode 100644 (file)
index 8e46724..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef _ASM_H8300_MODULE_H
-#define _ASM_H8300_MODULE_H
-/*
- * This file contains the H8/300 architecture specific module code.
- */
-struct mod_arch_specific { };
-#define Elf_Shdr Elf32_Shdr
-#define Elf_Sym Elf32_Sym
-#define Elf_Ehdr Elf32_Ehdr
-
-#endif /* _ASM_H8/300_MODULE_H */
index b2fdfb700f505d2e7afeb4e8ddc92d88528f7fbb..0744f7d7b1fd096b5ccbc71cab7305ea997fb3c3 100644 (file)
@@ -30,6 +30,7 @@ config HEXAGON
        select KTIME_SCALAR
        select GENERIC_CLOCKEVENTS
        select GENERIC_CLOCKEVENTS_BROADCAST
+       select MODULES_USE_ELF_RELA
        ---help---
          Qualcomm Hexagon is a processor architecture designed for high
          performance and low power across a wide variety of applications.
index 310cf5781fad2438a6ab24845724364bed31c7e4..688146466d0dc54117e9aa809c713adcff3926c1 100644 (file)
@@ -39,6 +39,8 @@ config IA64
        select ARCH_THREAD_INFO_ALLOCATOR
        select ARCH_CLOCKSOURCE_DATA
        select GENERIC_TIME_VSYSCALL
+       select HAVE_MOD_ARCH_SPECIFIC
+       select MODULES_USE_ELF_RELA
        default y
        help
          The Itanium Processor Family is Intel's 64-bit successor to
index c34785dca92b8c7ce590c2460f6c9ddab4b65f30..ec536e4e36c9fcbd71646c34c7cd5914f654f695 100644 (file)
@@ -338,7 +338,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
 {
        /* Handle turning off CRTSCTS */
        if ((old_termios->c_cflag & CRTSCTS) &&
-           !(tty->termios->c_cflag & CRTSCTS)) {
+           !(tty->termios.c_cflag & CRTSCTS)) {
                tty->hw_stopped = 0;
        }
 }
@@ -545,6 +545,7 @@ static int __init simrs_init(void)
        /* the port is imaginary */
        printk(KERN_INFO "ttyS0 at 0x03f8 (irq = %d) is a 16550\n", state->irq);
 
+       tty_port_link_device(&state->port, hp_simserial_driver, 0);
        retval = tty_register_driver(hp_simserial_driver);
        if (retval) {
                printk(KERN_ERR "Couldn't register simserial driver\n");
index 908eaef42a08d1dfd9451b55cf9852f61faaab80..dfba22a872c31c5739c05b79019d229f13f7eab8 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _ASM_IA64_MODULE_H
 #define _ASM_IA64_MODULE_H
 
+#include <asm-generic/module.h>
+
 /*
  * IA-64-specific support for kernel module loader.
  *
@@ -29,10 +31,6 @@ struct mod_arch_specific {
        unsigned int next_got_entry;    /* index of next available got entry */
 };
 
-#define Elf_Shdr       Elf64_Shdr
-#define Elf_Sym                Elf64_Sym
-#define Elf_Ehdr       Elf64_Ehdr
-
 #define MODULE_PROC_FAMILY     "ia64"
 #define MODULE_ARCH_VERMAGIC   MODULE_PROC_FAMILY \
        "gcc-" __stringify(__GNUC__) "." __stringify(__GNUC_MINOR__)
index 6f38b6120d96bc841f4563c1fe3202ae7a78b7f3..440578850ae52bad9df8961aeec12d52f9a94ceb 100644 (file)
@@ -497,7 +497,7 @@ acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa)
        srat_num_cpus++;
 }
 
-void __init
+int __init
 acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
 {
        unsigned long paddr, size;
@@ -512,7 +512,7 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
 
        /* Ignore disabled entries */
        if (!(ma->flags & ACPI_SRAT_MEM_ENABLED))
-               return;
+               return -1;
 
        /* record this node in proximity bitmap */
        pxm_bit_set(pxm);
@@ -531,6 +531,7 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
        p->size = size;
        p->nid = pxm;
        num_node_memblks++;
+       return 0;
 }
 
 void __init acpi_numa_arch_fixup(void)
index bd77cb507c1c7401124dbd3dc86fe663c17e6737..eac65380bd201a78caf63f971240193235d93b23 100644 (file)
@@ -924,6 +924,16 @@ int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
        return 0;
 }
 
+int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_event)
+{
+       if (!irqchip_in_kernel(kvm))
+               return -ENXIO;
+
+       irq_event->status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID,
+                                       irq_event->irq, irq_event->level);
+       return 0;
+}
+
 long kvm_arch_vm_ioctl(struct file *filp,
                unsigned int ioctl, unsigned long arg)
 {
@@ -963,29 +973,6 @@ long kvm_arch_vm_ioctl(struct file *filp,
                        goto out;
                }
                break;
-       case KVM_IRQ_LINE_STATUS:
-       case KVM_IRQ_LINE: {
-               struct kvm_irq_level irq_event;
-
-               r = -EFAULT;
-               if (copy_from_user(&irq_event, argp, sizeof irq_event))
-                       goto out;
-               r = -ENXIO;
-               if (irqchip_in_kernel(kvm)) {
-                       __s32 status;
-                       status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID,
-                                   irq_event.irq, irq_event.level);
-                       if (ioctl == KVM_IRQ_LINE_STATUS) {
-                               r = -EFAULT;
-                               irq_event.status = status;
-                               if (copy_to_user(argp, &irq_event,
-                                                       sizeof irq_event))
-                                       goto out;
-                       }
-                       r = 0;
-               }
-               break;
-               }
        case KVM_GET_IRQCHIP: {
                /* 0: PIC master, 1: PIC slave, 2: IOAPIC */
                struct kvm_irqchip chip;
index 49498bbb96163ec10477fac83fdd9f21f277b5cc..fc6153361bf596e5b44659247f0946b4c446266c 100644 (file)
@@ -13,6 +13,7 @@ config M32R
        select GENERIC_IRQ_SHOW
        select GENERIC_ATOMIC64
        select ARCH_USES_GETTIMEOFFSET
+       select MODULES_USE_ELF_RELA
 
 config SBUS
        bool
index c68e1680da0173d5754d1a1df4944120a5239e58..871382d239fef60105b37f50424afe24ed6773e3 100644 (file)
@@ -1 +1,3 @@
 include include/asm-generic/Kbuild.asm
+
+generic-y      += module.h
diff --git a/arch/m32r/include/asm/module.h b/arch/m32r/include/asm/module.h
deleted file mode 100644 (file)
index eb73ee0..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef _ASM_M32R_MODULE_H
-#define _ASM_M32R_MODULE_H
-
-struct mod_arch_specific { };
-
-#define Elf_Shdr       Elf32_Shdr
-#define Elf_Sym                Elf32_Sym
-#define Elf_Ehdr       Elf32_Ehdr
-
-#endif /* _ASM_M32R_MODULE_H */
index 3071fe83ffc8aac10c1083bca7a7d940e9383400..38233b6596b6e837e7cdf67ccad02f93834fe1ef 100644 (file)
@@ -201,18 +201,3 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
        }
        return 0;
 }
-
-int apply_relocate(Elf32_Shdr *sechdrs,
-                      const char *strtab,
-                      unsigned int symindex,
-                      unsigned int relsec,
-                      struct module *me)
-{
-#if 0
-       printk(KERN_ERR "module %s: REL RELOCATION unsupported\n",
-              me->name);
-       return -ENOEXEC;
-#endif
-       return 0;
-
-}
index 0b0f8b8c4a266571d33fcd61900161d7961d8cea..0df07cee3faf5e1c0585f879a8e61e8d69a1d81b 100644 (file)
@@ -5,6 +5,7 @@ config M68K
        select HAVE_AOUT if MMU
        select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_SHOW
+       select GENERIC_ATOMIC64
        select ARCH_HAVE_NMI_SAFE_CMPXCHG if RMW_INSNS
        select GENERIC_CPU_DEVICES
        select GENERIC_STRNCPY_FROM_USER if MMU
@@ -12,6 +13,9 @@ config M68K
        select FPU if MMU
        select ARCH_WANT_IPC_PARSE_VERSION
        select ARCH_USES_GETTIMEOFFSET if MMU && !COLDFIRE
+       select HAVE_MOD_ARCH_SPECIFIC
+       select MODULES_USE_ELF_REL
+       select MODULES_USE_ELF_RELA
 
 config RWSEM_GENERIC_SPINLOCK
        bool
@@ -54,18 +58,6 @@ config ZONE_DMA
        bool
        default y
 
-config CPU_HAS_NO_BITFIELDS
-       bool
-
-config CPU_HAS_NO_MULDIV64
-       bool
-
-config CPU_HAS_ADDRESS_SPACES
-       bool
-
-config FPU
-       bool
-
 config HZ
        int
        default 1000 if CLEOPATRA
index 43a9f8f1b8eb43d41049051358b08667684cc6f0..c4eb79edecec04d58d5ad681c389118a3472cec5 100644 (file)
@@ -28,6 +28,7 @@ config COLDFIRE
        select CPU_HAS_NO_BITFIELDS
        select CPU_HAS_NO_MULDIV64
        select GENERIC_CSUM
+       select HAVE_CLK
 
 endchoice
 
@@ -37,6 +38,7 @@ config M68000
        bool
        select CPU_HAS_NO_BITFIELDS
        select CPU_HAS_NO_MULDIV64
+       select CPU_HAS_NO_UNALIGNED
        select GENERIC_CSUM
        help
          The Freescale (was Motorola) 68000 CPU is the first generation of
@@ -48,6 +50,7 @@ config M68000
 config MCPU32
        bool
        select CPU_HAS_NO_BITFIELDS
+       select CPU_HAS_NO_UNALIGNED
        help
          The Freescale (was then Motorola) CPU32 is a CPU core that is
          based on the 68020 processor. For the most part it is used in
@@ -56,7 +59,6 @@ config MCPU32
 config M68020
        bool "68020 support"
        depends on MMU
-       select GENERIC_ATOMIC64
        select CPU_HAS_ADDRESS_SPACES
        help
          If you anticipate running this kernel on a computer with a MC68020
@@ -67,7 +69,6 @@ config M68020
 config M68030
        bool "68030 support"
        depends on MMU && !MMU_SUN3
-       select GENERIC_ATOMIC64
        select CPU_HAS_ADDRESS_SPACES
        help
          If you anticipate running this kernel on a computer with a MC68030
@@ -77,7 +78,6 @@ config M68030
 config M68040
        bool "68040 support"
        depends on MMU && !MMU_SUN3
-       select GENERIC_ATOMIC64
        select CPU_HAS_ADDRESS_SPACES
        help
          If you anticipate running this kernel on a computer with a MC68LC040
@@ -88,7 +88,6 @@ config M68040
 config M68060
        bool "68060 support"
        depends on MMU && !MMU_SUN3
-       select GENERIC_ATOMIC64
        select CPU_HAS_ADDRESS_SPACES
        help
          If you anticipate running this kernel on a computer with a MC68060
@@ -376,6 +375,18 @@ config NODES_SHIFT
        default "3"
        depends on !SINGLE_MEMORY_CHUNK
 
+config CPU_HAS_NO_BITFIELDS
+       bool
+
+config CPU_HAS_NO_MULDIV64
+       bool
+
+config CPU_HAS_NO_UNALIGNED
+       bool
+
+config CPU_HAS_ADDRESS_SPACES
+       bool
+
 config FPU
        bool
 
index 0a30406b9442a4961b8f40fbc2832e0cc2079889..f5565d6eeb8e9bbe24b9ef1df22dea0310f9c4ee 100644 (file)
@@ -177,8 +177,8 @@ irqreturn_t dn_timer_int(int irq, void *dev_id)
 
        timer_handler(irq, dev_id);
 
-       x=*(volatile unsigned char *)(timer+3);
-       x=*(volatile unsigned char *)(timer+5);
+       x = *(volatile unsigned char *)(apollo_timer + 3);
+       x = *(volatile unsigned char *)(apollo_timer + 5);
 
        return IRQ_HANDLED;
 }
@@ -186,17 +186,17 @@ irqreturn_t dn_timer_int(int irq, void *dev_id)
 void dn_sched_init(irq_handler_t timer_routine)
 {
        /* program timer 1 */
-       *(volatile unsigned char *)(timer+3)=0x01;
-       *(volatile unsigned char *)(timer+1)=0x40;
-       *(volatile unsigned char *)(timer+5)=0x09;
-       *(volatile unsigned char *)(timer+7)=0xc4;
+       *(volatile unsigned char *)(apollo_timer + 3) = 0x01;
+       *(volatile unsigned char *)(apollo_timer + 1) = 0x40;
+       *(volatile unsigned char *)(apollo_timer + 5) = 0x09;
+       *(volatile unsigned char *)(apollo_timer + 7) = 0xc4;
 
        /* enable IRQ of PIC B */
        *(volatile unsigned char *)(pica+1)&=(~8);
 
 #if 0
-       printk("*(0x10803) %02x\n",*(volatile unsigned char *)(timer+0x3));
-       printk("*(0x10803) %02x\n",*(volatile unsigned char *)(timer+0x3));
+       printk("*(0x10803) %02x\n",*(volatile unsigned char *)(apollo_timer + 0x3));
+       printk("*(0x10803) %02x\n",*(volatile unsigned char *)(apollo_timer + 0x3));
 #endif
 
        if (request_irq(IRQ_APOLLO, dn_timer_int, 0, "time", timer_routine))
index 8db25e8069471f03f07335153bf8137c05ef41b4..16d170f53bfd0d521a15281b4565d3fae9f1ad44 100644 (file)
@@ -19,6 +19,7 @@
 #include <asm/natfeat.h>
 
 static int stderr_id;
+static struct tty_port nfcon_tty_port;
 static struct tty_driver *nfcon_tty_driver;
 
 static void nfputs(const char *str, unsigned int count)
@@ -119,6 +120,8 @@ static int __init nfcon_init(void)
 {
        int res;
 
+       tty_port_init(&nfcon_tty_port);
+
        stderr_id = nf_get_id("NF_STDERR");
        if (!stderr_id)
                return -ENODEV;
@@ -135,6 +138,7 @@ static int __init nfcon_init(void)
        nfcon_tty_driver->flags = TTY_DRIVER_REAL_RAW;
 
        tty_set_operations(nfcon_tty_driver, &nfcon_tty_ops);
+       tty_port_link_device(&nfcon_tty_port, nfcon_tty_driver, 0);
        res = tty_register_driver(nfcon_tty_driver);
        if (res) {
                pr_err("failed to register nfcon tty driver\n");
index eafa2539a8ee79dbcc65ea929ab082c767d93029..a74e5d95c384941583d99096bae1175634c9b4cb 100644 (file)
@@ -1,4 +1,29 @@
 include include/asm-generic/Kbuild.asm
 header-y += cachectl.h
 
+generic-y += bitsperlong.h
+generic-y += cputime.h
+generic-y += device.h
+generic-y += emergency-restart.h
+generic-y += errno.h
+generic-y += futex.h
+generic-y += ioctl.h
+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
+generic-y += mutex.h
+generic-y += percpu.h
+generic-y += resource.h
+generic-y += scatterlist.h
+generic-y += sections.h
+generic-y += siginfo.h
+generic-y += statfs.h
+generic-y += topology.h
+generic-y += types.h
 generic-y += word-at-a-time.h
+generic-y += xor.h
diff --git a/arch/m68k/include/asm/MC68332.h b/arch/m68k/include/asm/MC68332.h
deleted file mode 100644 (file)
index 6bb8f02..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-
-/* include/asm-m68knommu/MC68332.h: '332 control registers
- *
- * Copyright (C) 1998  Kenneth Albanowski <kjahds@kjahds.com>,
- *
- */
-
-#ifndef _MC68332_H_
-#define _MC68332_H_
-
-#define BYTE_REF(addr) (*((volatile unsigned char*)addr))
-#define WORD_REF(addr) (*((volatile unsigned short*)addr))
-
-#define PORTE_ADDR     0xfffa11
-#define PORTE  BYTE_REF(PORTE_ADDR)
-#define DDRE_ADDR      0xfffa15
-#define DDRE   BYTE_REF(DDRE_ADDR)
-#define PEPAR_ADDR     0xfffa17
-#define PEPAR  BYTE_REF(PEPAR_ADDR)
-
-#define PORTF_ADDR     0xfffa19
-#define PORTF  BYTE_REF(PORTF_ADDR)
-#define DDRF_ADDR      0xfffa1d
-#define DDRF   BYTE_REF(DDRF_ADDR)
-#define PFPAR_ADDR     0xfffa1f
-#define PFPAR  BYTE_REF(PFPAR_ADDR)
-
-#define PORTQS_ADDR    0xfffc15
-#define PORTQS BYTE_REF(PORTQS_ADDR)
-#define DDRQS_ADDR     0xfffc17
-#define DDRQS  BYTE_REF(DDRQS_ADDR)
-#define PQSPAR_ADDR    0xfffc16
-#define PQSPAR BYTE_REF(PQSPAR_ADDR)
-
-#define CSPAR0_ADDR 0xFFFA44
-#define CSPAR0 WORD_REF(CSPAR0_ADDR)
-#define CSPAR1_ADDR 0xFFFA46
-#define CSPAR1 WORD_REF(CSPAR1_ADDR)
-#define CSARBT_ADDR 0xFFFA48
-#define CSARBT WORD_REF(CSARBT_ADDR)
-#define CSOPBT_ADDR 0xFFFA4A
-#define CSOPBT WORD_REF(CSOPBT_ADDR)
-#define CSBAR0_ADDR 0xFFFA4C
-#define CSBAR0 WORD_REF(CSBAR0_ADDR)
-#define CSOR0_ADDR 0xFFFA4E
-#define CSOR0 WORD_REF(CSOR0_ADDR)
-#define CSBAR1_ADDR 0xFFFA50
-#define CSBAR1 WORD_REF(CSBAR1_ADDR)
-#define CSOR1_ADDR 0xFFFA52
-#define CSOR1 WORD_REF(CSOR1_ADDR)
-#define CSBAR2_ADDR 0xFFFA54
-#define CSBAR2 WORD_REF(CSBAR2_ADDR)
-#define CSOR2_ADDR 0xFFFA56
-#define CSOR2 WORD_REF(CSOR2_ADDR)
-#define CSBAR3_ADDR 0xFFFA58
-#define CSBAR3 WORD_REF(CSBAR3_ADDR)
-#define CSOR3_ADDR 0xFFFA5A
-#define CSOR3 WORD_REF(CSOR3_ADDR)
-#define CSBAR4_ADDR 0xFFFA5C
-#define CSBAR4 WORD_REF(CSBAR4_ADDR)
-#define CSOR4_ADDR 0xFFFA5E
-#define CSOR4 WORD_REF(CSOR4_ADDR)
-#define CSBAR5_ADDR 0xFFFA60
-#define CSBAR5 WORD_REF(CSBAR5_ADDR)
-#define CSOR5_ADDR 0xFFFA62
-#define CSOR5 WORD_REF(CSOR5_ADDR)
-#define CSBAR6_ADDR 0xFFFA64
-#define CSBAR6 WORD_REF(CSBAR6_ADDR)
-#define CSOR6_ADDR 0xFFFA66
-#define CSOR6 WORD_REF(CSOR6_ADDR)
-#define CSBAR7_ADDR 0xFFFA68
-#define CSBAR7 WORD_REF(CSBAR7_ADDR)
-#define CSOR7_ADDR 0xFFFA6A
-#define CSOR7 WORD_REF(CSOR7_ADDR)
-#define CSBAR8_ADDR 0xFFFA6C
-#define CSBAR8 WORD_REF(CSBAR8_ADDR)
-#define CSOR8_ADDR 0xFFFA6E
-#define CSOR8 WORD_REF(CSOR8_ADDR)
-#define CSBAR9_ADDR 0xFFFA70
-#define CSBAR9 WORD_REF(CSBAR9_ADDR)
-#define CSOR9_ADDR 0xFFFA72
-#define CSOR9 WORD_REF(CSOR9_ADDR)
-#define CSBAR10_ADDR 0xFFFA74
-#define CSBAR10 WORD_REF(CSBAR10_ADDR)
-#define CSOR10_ADDR 0xFFFA76
-#define CSOR10 WORD_REF(CSOR10_ADDR)
-
-#define CSOR_MODE_ASYNC        0x0000
-#define CSOR_MODE_SYNC 0x8000
-#define CSOR_MODE_MASK 0x8000
-#define CSOR_BYTE_DISABLE      0x0000
-#define CSOR_BYTE_UPPER                0x4000
-#define CSOR_BYTE_LOWER                0x2000
-#define CSOR_BYTE_BOTH         0x6000
-#define CSOR_BYTE_MASK         0x6000
-#define CSOR_RW_RSVD           0x0000
-#define CSOR_RW_READ           0x0800
-#define CSOR_RW_WRITE          0x1000
-#define CSOR_RW_BOTH           0x1800
-#define CSOR_RW_MASK           0x1800
-#define CSOR_STROBE_DS         0x0400
-#define CSOR_STROBE_AS         0x0000
-#define CSOR_STROBE_MASK       0x0400
-#define CSOR_DSACK_WAIT(x)     (wait << 6)
-#define CSOR_DSACK_FTERM       (14 << 6)
-#define CSOR_DSACK_EXTERNAL    (15 << 6)
-#define CSOR_DSACK_MASK                0x03c0
-#define CSOR_SPACE_CPU         0x0000
-#define CSOR_SPACE_USER                0x0010
-#define CSOR_SPACE_SU          0x0020
-#define CSOR_SPACE_BOTH                0x0030
-#define CSOR_SPACE_MASK                0x0030
-#define CSOR_IPL_ALL           0x0000
-#define CSOR_IPL_PRIORITY(x)   (x << 1)
-#define CSOR_IPL_MASK          0x000e
-#define CSOR_AVEC_ON           0x0001
-#define CSOR_AVEC_OFF          0x0000
-#define CSOR_AVEC_MASK         0x0001
-
-#define CSBAR_ADDR(x)          ((addr >> 11) << 3) 
-#define CSBAR_ADDR_MASK                0xfff8
-#define CSBAR_BLKSIZE_2K       0x0000
-#define CSBAR_BLKSIZE_8K       0x0001
-#define CSBAR_BLKSIZE_16K      0x0002
-#define CSBAR_BLKSIZE_64K      0x0003
-#define CSBAR_BLKSIZE_128K     0x0004
-#define CSBAR_BLKSIZE_256K     0x0005
-#define CSBAR_BLKSIZE_512K     0x0006
-#define CSBAR_BLKSIZE_1M       0x0007
-#define CSBAR_BLKSIZE_MASK     0x0007
-
-#define CSPAR_DISC     0
-#define CSPAR_ALT      1
-#define CSPAR_CS8      2
-#define CSPAR_CS16     3
-#define CSPAR_MASK     3
-
-#define CSPAR0_CSBOOT(x) (x << 0)
-#define CSPAR0_CS0(x)  (x << 2)
-#define CSPAR0_CS1(x)  (x << 4)
-#define CSPAR0_CS2(x)  (x << 6)
-#define CSPAR0_CS3(x)  (x << 8)
-#define CSPAR0_CS4(x)  (x << 10)
-#define CSPAR0_CS5(x)  (x << 12)
-
-#define CSPAR1_CS6(x)  (x << 0)
-#define CSPAR1_CS7(x)  (x << 2)
-#define CSPAR1_CS8(x)  (x << 4)
-#define CSPAR1_CS9(x)  (x << 6)
-#define CSPAR1_CS10(x) (x << 8)
-
-#endif
diff --git a/arch/m68k/include/asm/apollodma.h b/arch/m68k/include/asm/apollodma.h
deleted file mode 100644 (file)
index 954adc8..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * linux/include/asm/dma.h: Defines for using and allocating dma channels.
- * Written by Hennus Bergman, 1992.
- * High DMA channel support & info by Hannu Savolainen
- * and John Boyd, Nov. 1992.
- */
-
-#ifndef _ASM_APOLLO_DMA_H
-#define _ASM_APOLLO_DMA_H
-
-#include <asm/apollohw.h>              /* need byte IO */
-#include <linux/spinlock.h>            /* And spinlocks */
-#include <linux/delay.h>
-
-
-#define dma_outb(val,addr) (*((volatile unsigned char *)(addr+IO_BASE)) = (val))
-#define dma_inb(addr)     (*((volatile unsigned char *)(addr+IO_BASE)))
-
-/*
- * NOTES about DMA transfers:
- *
- *  controller 1: channels 0-3, byte operations, ports 00-1F
- *  controller 2: channels 4-7, word operations, ports C0-DF
- *
- *  - ALL registers are 8 bits only, regardless of transfer size
- *  - channel 4 is not used - cascades 1 into 2.
- *  - channels 0-3 are byte - addresses/counts are for physical bytes
- *  - channels 5-7 are word - addresses/counts are for physical words
- *  - transfers must not cross physical 64K (0-3) or 128K (5-7) boundaries
- *  - transfer count loaded to registers is 1 less than actual count
- *  - controller 2 offsets are all even (2x offsets for controller 1)
- *  - page registers for 5-7 don't use data bit 0, represent 128K pages
- *  - page registers for 0-3 use bit 0, represent 64K pages
- *
- * DMA transfers are limited to the lower 16MB of _physical_ memory.
- * Note that addresses loaded into registers must be _physical_ addresses,
- * not logical addresses (which may differ if paging is active).
- *
- *  Address mapping for channels 0-3:
- *
- *   A23 ... A16 A15 ... A8  A7 ... A0    (Physical addresses)
- *    |  ...  |   |  ... |   |  ... |
- *    |  ...  |   |  ... |   |  ... |
- *    |  ...  |   |  ... |   |  ... |
- *   P7  ...  P0  A7 ... A0  A7 ... A0
- * |    Page    | Addr MSB | Addr LSB |   (DMA registers)
- *
- *  Address mapping for channels 5-7:
- *
- *   A23 ... A17 A16 A15 ... A9 A8 A7 ... A1 A0    (Physical addresses)
- *    |  ...  |   \   \   ... \  \  \  ... \  \
- *    |  ...  |    \   \   ... \  \  \  ... \  (not used)
- *    |  ...  |     \   \   ... \  \  \  ... \
- *   P7  ...  P1 (0) A7 A6  ... A0 A7 A6 ... A0
- * |      Page      |  Addr MSB   |  Addr LSB  |   (DMA registers)
- *
- * Again, channels 5-7 transfer _physical_ words (16 bits), so addresses
- * and counts _must_ be word-aligned (the lowest address bit is _ignored_ at
- * the hardware level, so odd-byte transfers aren't possible).
- *
- * Transfer count (_not # bytes_) is limited to 64K, represented as actual
- * count - 1 : 64K => 0xFFFF, 1 => 0x0000.  Thus, count is always 1 or more,
- * and up to 128K bytes may be transferred on channels 5-7 in one operation.
- *
- */
-
-#define MAX_DMA_CHANNELS       8
-
-/* The maximum address that we can perform a DMA transfer to on this platform */#define MAX_DMA_ADDRESS      (PAGE_OFFSET+0x1000000)
-
-/* 8237 DMA controllers */
-#define IO_DMA1_BASE   0x10C00 /* 8 bit slave DMA, channels 0..3 */
-#define IO_DMA2_BASE   0x10D00 /* 16 bit master DMA, ch 4(=slave input)..7 */
-
-/* DMA controller registers */
-#define DMA1_CMD_REG           (IO_DMA1_BASE+0x08) /* command register (w) */
-#define DMA1_STAT_REG          (IO_DMA1_BASE+0x08) /* status register (r) */
-#define DMA1_REQ_REG            (IO_DMA1_BASE+0x09) /* request register (w) */
-#define DMA1_MASK_REG          (IO_DMA1_BASE+0x0A) /* single-channel mask (w) */
-#define DMA1_MODE_REG          (IO_DMA1_BASE+0x0B) /* mode register (w) */
-#define DMA1_CLEAR_FF_REG      (IO_DMA1_BASE+0x0C) /* clear pointer flip-flop (w) */
-#define DMA1_TEMP_REG           (IO_DMA1_BASE+0x0D) /* Temporary Register (r) */
-#define DMA1_RESET_REG         (IO_DMA1_BASE+0x0D) /* Master Clear (w) */
-#define DMA1_CLR_MASK_REG       (IO_DMA1_BASE+0x0E) /* Clear Mask */
-#define DMA1_MASK_ALL_REG       (IO_DMA1_BASE+0x0F) /* all-channels mask (w) */
-
-#define DMA2_CMD_REG           (IO_DMA2_BASE+0x10) /* command register (w) */
-#define DMA2_STAT_REG          (IO_DMA2_BASE+0x10) /* status register (r) */
-#define DMA2_REQ_REG            (IO_DMA2_BASE+0x12) /* request register (w) */
-#define DMA2_MASK_REG          (IO_DMA2_BASE+0x14) /* single-channel mask (w) */
-#define DMA2_MODE_REG          (IO_DMA2_BASE+0x16) /* mode register (w) */
-#define DMA2_CLEAR_FF_REG      (IO_DMA2_BASE+0x18) /* clear pointer flip-flop (w) */
-#define DMA2_TEMP_REG           (IO_DMA2_BASE+0x1A) /* Temporary Register (r) */
-#define DMA2_RESET_REG         (IO_DMA2_BASE+0x1A) /* Master Clear (w) */
-#define DMA2_CLR_MASK_REG       (IO_DMA2_BASE+0x1C) /* Clear Mask */
-#define DMA2_MASK_ALL_REG       (IO_DMA2_BASE+0x1E) /* all-channels mask (w) */
-
-#define DMA_ADDR_0              (IO_DMA1_BASE+0x00) /* DMA address registers */
-#define DMA_ADDR_1              (IO_DMA1_BASE+0x02)
-#define DMA_ADDR_2              (IO_DMA1_BASE+0x04)
-#define DMA_ADDR_3              (IO_DMA1_BASE+0x06)
-#define DMA_ADDR_4              (IO_DMA2_BASE+0x00)
-#define DMA_ADDR_5              (IO_DMA2_BASE+0x04)
-#define DMA_ADDR_6              (IO_DMA2_BASE+0x08)
-#define DMA_ADDR_7              (IO_DMA2_BASE+0x0C)
-
-#define DMA_CNT_0               (IO_DMA1_BASE+0x01)   /* DMA count registers */
-#define DMA_CNT_1               (IO_DMA1_BASE+0x03)
-#define DMA_CNT_2               (IO_DMA1_BASE+0x05)
-#define DMA_CNT_3               (IO_DMA1_BASE+0x07)
-#define DMA_CNT_4               (IO_DMA2_BASE+0x02)
-#define DMA_CNT_5               (IO_DMA2_BASE+0x06)
-#define DMA_CNT_6               (IO_DMA2_BASE+0x0A)
-#define DMA_CNT_7               (IO_DMA2_BASE+0x0E)
-
-#define DMA_MODE_READ  0x44    /* I/O to memory, no autoinit, increment, single mode */
-#define DMA_MODE_WRITE 0x48    /* memory to I/O, no autoinit, increment, single mode */
-#define DMA_MODE_CASCADE 0xC0   /* pass thru DREQ->HRQ, DACK<-HLDA only */
-
-#define DMA_AUTOINIT   0x10
-
-#define DMA_8BIT 0
-#define DMA_16BIT 1
-#define DMA_BUSMASTER 2
-
-extern spinlock_t  dma_spin_lock;
-
-static __inline__ unsigned long claim_dma_lock(void)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&dma_spin_lock, flags);
-       return flags;
-}
-
-static __inline__ void release_dma_lock(unsigned long flags)
-{
-       spin_unlock_irqrestore(&dma_spin_lock, flags);
-}
-
-/* enable/disable a specific DMA channel */
-static __inline__ void enable_dma(unsigned int dmanr)
-{
-       if (dmanr<=3)
-               dma_outb(dmanr,  DMA1_MASK_REG);
-       else
-               dma_outb(dmanr & 3,  DMA2_MASK_REG);
-}
-
-static __inline__ void disable_dma(unsigned int dmanr)
-{
-       if (dmanr<=3)
-               dma_outb(dmanr | 4,  DMA1_MASK_REG);
-       else
-               dma_outb((dmanr & 3) | 4,  DMA2_MASK_REG);
-}
-
-/* Clear the 'DMA Pointer Flip Flop'.
- * Write 0 for LSB/MSB, 1 for MSB/LSB access.
- * Use this once to initialize the FF to a known state.
- * After that, keep track of it. :-)
- * --- In order to do that, the DMA routines below should ---
- * --- only be used while holding the DMA lock ! ---
- */
-static __inline__ void clear_dma_ff(unsigned int dmanr)
-{
-       if (dmanr<=3)
-               dma_outb(0,  DMA1_CLEAR_FF_REG);
-       else
-               dma_outb(0,  DMA2_CLEAR_FF_REG);
-}
-
-/* set mode (above) for a specific DMA channel */
-static __inline__ void set_dma_mode(unsigned int dmanr, char mode)
-{
-       if (dmanr<=3)
-               dma_outb(mode | dmanr,  DMA1_MODE_REG);
-       else
-               dma_outb(mode | (dmanr&3),  DMA2_MODE_REG);
-}
-
-/* Set transfer address & page bits for specific DMA channel.
- * Assumes dma flipflop is clear.
- */
-static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int a)
-{
-       if (dmanr <= 3)  {
-           dma_outb( a & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE );
-            dma_outb( (a>>8) & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE );
-       }  else  {
-           dma_outb( (a>>1) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
-           dma_outb( (a>>9) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
-       }
-}
-
-
-/* Set transfer size (max 64k for DMA1..3, 128k for DMA5..7) for
- * a specific DMA channel.
- * You must ensure the parameters are valid.
- * NOTE: from a manual: "the number of transfers is one more
- * than the initial word count"! This is taken into account.
- * Assumes dma flip-flop is clear.
- * NOTE 2: "count" represents _bytes_ and must be even for channels 5-7.
- */
-static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count)
-{
-        count--;
-       if (dmanr <= 3)  {
-           dma_outb( count & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE );
-           dma_outb( (count>>8) & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE );
-        } else {
-           dma_outb( (count>>1) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
-           dma_outb( (count>>9) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
-        }
-}
-
-
-/* Get DMA residue count. After a DMA transfer, this
- * should return zero. Reading this while a DMA transfer is
- * still in progress will return unpredictable results.
- * If called before the channel has been used, it may return 1.
- * Otherwise, it returns the number of _bytes_ left to transfer.
- *
- * Assumes DMA flip-flop is clear.
- */
-static __inline__ int get_dma_residue(unsigned int dmanr)
-{
-       unsigned int io_port = (dmanr<=3)? ((dmanr&3)<<1) + 1 + IO_DMA1_BASE
-                                        : ((dmanr&3)<<2) + 2 + IO_DMA2_BASE;
-
-       /* using short to get 16-bit wrap around */
-       unsigned short count;
-
-       count = 1 + dma_inb(io_port);
-       count += dma_inb(io_port) << 8;
-
-       return (dmanr<=3)? count : (count<<1);
-}
-
-
-/* These are in kernel/dma.c: */
-extern int request_dma(unsigned int dmanr, const char * device_id);    /* reserve a DMA channel */
-extern void free_dma(unsigned int dmanr);      /* release it again */
-
-/* These are in arch/m68k/apollo/dma.c: */
-extern unsigned short dma_map_page(unsigned long phys_addr,int count,int type);
-extern void dma_unmap_page(unsigned short dma_addr);
-
-#endif /* _ASM_APOLLO_DMA_H */
index a1373b9aa2811535728a5e95c07fdd827b6099b1..635ef4f890102b187ef86710ceb341c5af91bdb5 100644 (file)
@@ -98,7 +98,7 @@ extern u_long timer_physaddr;
 #define cpuctrl (*(volatile unsigned int *)(IO_BASE + cpuctrl_physaddr))
 #define pica (IO_BASE + pica_physaddr)
 #define picb (IO_BASE + picb_physaddr)
-#define timer (IO_BASE + timer_physaddr)
+#define apollo_timer (IO_BASE + timer_physaddr)
 #define addr_xlat_map ((unsigned short *)(IO_BASE + 0x17000))
 
 #define isaIO2mem(x) (((((x) & 0x3f8)  << 7) | (((x) & 0xfc00) >> 6) | ((x) & 0x7)) + 0x40000 + IO_BASE)
diff --git a/arch/m68k/include/asm/bitsperlong.h b/arch/m68k/include/asm/bitsperlong.h
deleted file mode 100644 (file)
index 6dc0bb0..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/bitsperlong.h>
diff --git a/arch/m68k/include/asm/cputime.h b/arch/m68k/include/asm/cputime.h
deleted file mode 100644 (file)
index c79c5e8..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __M68K_CPUTIME_H
-#define __M68K_CPUTIME_H
-
-#include <asm-generic/cputime.h>
-
-#endif /* __M68K_CPUTIME_H */
index 9c09becfd4c97fa96c249288f8ef3056832e8f4e..12d8fe4f1d30b5e6fe0f86b191b05bd2b0307251 100644 (file)
@@ -43,7 +43,7 @@ static inline void __delay(unsigned long loops)
 extern void __bad_udelay(void);
 
 
-#if defined(CONFIG_M68000) || defined(CONFIG_COLDFIRE)
+#ifdef CONFIG_CPU_HAS_NO_MULDIV64
 /*
  * The simpler m68k and ColdFire processors do not have a 32*32->64
  * multiply instruction. So we need to handle them a little differently.
diff --git a/arch/m68k/include/asm/device.h b/arch/m68k/include/asm/device.h
deleted file mode 100644 (file)
index d8f9872..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-/*
- * Arch specific extensions to struct device
- *
- * This file is released under the GPLv2
- */
-#include <asm-generic/device.h>
-
diff --git a/arch/m68k/include/asm/emergency-restart.h b/arch/m68k/include/asm/emergency-restart.h
deleted file mode 100644 (file)
index 108d8c4..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_EMERGENCY_RESTART_H
-#define _ASM_EMERGENCY_RESTART_H
-
-#include <asm-generic/emergency-restart.h>
-
-#endif /* _ASM_EMERGENCY_RESTART_H */
diff --git a/arch/m68k/include/asm/errno.h b/arch/m68k/include/asm/errno.h
deleted file mode 100644 (file)
index 0d4e188..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _M68K_ERRNO_H
-#define _M68K_ERRNO_H
-
-#include <asm-generic/errno.h>
-
-#endif /* _M68K_ERRNO_H */
diff --git a/arch/m68k/include/asm/futex.h b/arch/m68k/include/asm/futex.h
deleted file mode 100644 (file)
index 6a332a9..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_FUTEX_H
-#define _ASM_FUTEX_H
-
-#include <asm-generic/futex.h>
-
-#endif
diff --git a/arch/m68k/include/asm/ioctl.h b/arch/m68k/include/asm/ioctl.h
deleted file mode 100644 (file)
index b279fe0..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/ioctl.h>
diff --git a/arch/m68k/include/asm/ipcbuf.h b/arch/m68k/include/asm/ipcbuf.h
deleted file mode 100644 (file)
index 84c7e51..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/ipcbuf.h>
diff --git a/arch/m68k/include/asm/irq_regs.h b/arch/m68k/include/asm/irq_regs.h
deleted file mode 100644 (file)
index 3dd9c0b..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/irq_regs.h>
diff --git a/arch/m68k/include/asm/kdebug.h b/arch/m68k/include/asm/kdebug.h
deleted file mode 100644 (file)
index 6ece1b0..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/kdebug.h>
diff --git a/arch/m68k/include/asm/kmap_types.h b/arch/m68k/include/asm/kmap_types.h
deleted file mode 100644 (file)
index 3413cc1..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_M68K_KMAP_TYPES_H
-#define __ASM_M68K_KMAP_TYPES_H
-
-#include <asm-generic/kmap_types.h>
-
-#endif /* __ASM_M68K_KMAP_TYPES_H */
diff --git a/arch/m68k/include/asm/kvm_para.h b/arch/m68k/include/asm/kvm_para.h
deleted file mode 100644 (file)
index 14fab8f..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/kvm_para.h>
diff --git a/arch/m68k/include/asm/local.h b/arch/m68k/include/asm/local.h
deleted file mode 100644 (file)
index 6c25926..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_M68K_LOCAL_H
-#define _ASM_M68K_LOCAL_H
-
-#include <asm-generic/local.h>
-
-#endif /* _ASM_M68K_LOCAL_H */
diff --git a/arch/m68k/include/asm/local64.h b/arch/m68k/include/asm/local64.h
deleted file mode 100644 (file)
index 36c93b5..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/local64.h>
diff --git a/arch/m68k/include/asm/mac_mouse.h b/arch/m68k/include/asm/mac_mouse.h
deleted file mode 100644 (file)
index 39a5c29..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef _ASM_MAC_MOUSE_H
-#define _ASM_MAC_MOUSE_H
-
-/*
- * linux/include/asm-m68k/mac_mouse.h
- * header file for Macintosh ADB mouse driver
- * 27-10-97 Michael Schmitz
- * copied from:
- * header file for Atari Mouse driver
- * by Robert de Vries (robert@and.nl) on 19Jul93
- */
-
-struct mouse_status {
-       char            buttons;
-       short           dx;
-       short           dy;
-       int             ready;
-       int             active;
-       wait_queue_head_t wait;
-       struct fasync_struct *fasyncptr;
-};
-
-#endif
diff --git a/arch/m68k/include/asm/mcfmbus.h b/arch/m68k/include/asm/mcfmbus.h
deleted file mode 100644 (file)
index 319899c..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/****************************************************************************/
-
-/*
- *      mcfmbus.h -- Coldfire MBUS support defines.
- *
- *      (C) Copyright 1999, Martin Floeer (mfloeer@axcent.de) 
- */
-
-/****************************************************************************/
-
-
-#ifndef mcfmbus_h
-#define mcfmbus_h
-
-
-#define MCFMBUS_BASE           0x280
-#define MCFMBUS_IRQ_VECTOR     0x19
-#define MCFMBUS_IRQ            0x1
-#define MCFMBUS_CLK            0x3f
-#define MCFMBUS_IRQ_LEVEL      0x07    /*IRQ Level 1*/
-#define MCFMBUS_ADDRESS                0x01
-
-
-/*
-*      Define the 5307 MBUS register set addresses
-*/
-
-#define MCFMBUS_MADR   0x00
-#define MCFMBUS_MFDR   0x04
-#define MCFMBUS_MBCR   0x08
-#define MCFMBUS_MBSR   0x0C
-#define MCFMBUS_MBDR   0x10
-
-
-#define MCFMBUS_MADR_ADDR(a)   (((a)&0x7F)<<0x01) /*Slave Address*/
-
-#define MCFMBUS_MFDR_MBC(a)    ((a)&0x3F)         /*M-Bus Clock*/
-
-/*
-*      Define bit flags in Control Register
-*/
-
-#define MCFMBUS_MBCR_MEN           (0x80)  /* M-Bus Enable                 */
-#define MCFMBUS_MBCR_MIEN          (0x40)  /* M-Bus Interrupt Enable       */
-#define MCFMBUS_MBCR_MSTA          (0x20)  /* Master/Slave Mode Select Bit */
-#define MCFMBUS_MBCR_MTX           (0x10)  /* Transmit/Rcv Mode Select Bit */
-#define MCFMBUS_MBCR_TXAK          (0x08)  /* Transmit Acknowledge Enable  */
-#define MCFMBUS_MBCR_RSTA          (0x04)  /* Repeat Start                 */
-
-/*
-*      Define bit flags in Status Register
-*/
-
-#define MCFMBUS_MBSR_MCF           (0x80)  /* Data Transfer Complete       */
-#define MCFMBUS_MBSR_MAAS          (0x40)  /* Addressed as a Slave         */
-#define MCFMBUS_MBSR_MBB           (0x20)  /* Bus Busy                     */
-#define MCFMBUS_MBSR_MAL           (0x10)  /* Arbitration Lost             */
-#define MCFMBUS_MBSR_SRW           (0x04)  /* Slave Transmit               */
-#define MCFMBUS_MBSR_MIF           (0x02)  /* M-Bus Interrupt              */
-#define MCFMBUS_MBSR_RXAK          (0x01)  /* No Acknowledge Received      */
-
-/*
-*      Define bit flags in DATA I/O Register
-*/
-
-#define MCFMBUS_MBDR_READ          (0x01)  /* 1=read 0=write MBUS */
-
-#define MBUSIOCSCLOCK          1
-#define MBUSIOCGCLOCK          2
-#define MBUSIOCSADDR                   3
-#define MBUSIOCGADDR                   4
-#define MBUSIOCSSLADDR                 5
-#define MBUSIOCGSLADDR                 6
-#define MBUSIOCSSUBADDR                        7
-#define MBUSIOCGSUBADDR                        8
-
-#endif
diff --git a/arch/m68k/include/asm/mman.h b/arch/m68k/include/asm/mman.h
deleted file mode 100644 (file)
index 8eebf89..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/mman.h>
index edffe66b7f4972aad851ccd5de39218f9c12a20d..8b58fce843ddc2bf06a4f6f030f241a2add7b312 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _ASM_M68K_MODULE_H
 #define _ASM_M68K_MODULE_H
 
+#include <asm-generic/module.h>
+
 enum m68k_fixup_type {
        m68k_fixup_memoffset,
        m68k_fixup_vnode_shift,
@@ -36,8 +38,4 @@ struct module;
 extern void module_fixup(struct module *mod, struct m68k_fixup_info *start,
                         struct m68k_fixup_info *end);
 
-#define Elf_Shdr Elf32_Shdr
-#define Elf_Sym Elf32_Sym
-#define Elf_Ehdr Elf32_Ehdr
-
 #endif /* _ASM_M68K_MODULE_H */
diff --git a/arch/m68k/include/asm/mutex.h b/arch/m68k/include/asm/mutex.h
deleted file mode 100644 (file)
index 458c1f7..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * Pull in the generic implementation for the mutex fastpath.
- *
- * TODO: implement optimized primitives instead, or leave the generic
- * implementation in place, or pick the atomic_xchg() based generic
- * implementation. (see asm-generic/mutex-xchg.h for details)
- */
-
-#include <asm-generic/mutex-dec.h>
diff --git a/arch/m68k/include/asm/percpu.h b/arch/m68k/include/asm/percpu.h
deleted file mode 100644 (file)
index 0859d04..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_M68K_PERCPU_H
-#define __ASM_M68K_PERCPU_H
-
-#include <asm-generic/percpu.h>
-
-#endif /* __ASM_M68K_PERCPU_H */
diff --git a/arch/m68k/include/asm/resource.h b/arch/m68k/include/asm/resource.h
deleted file mode 100644 (file)
index e7d3501..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _M68K_RESOURCE_H
-#define _M68K_RESOURCE_H
-
-#include <asm-generic/resource.h>
-
-#endif /* _M68K_RESOURCE_H */
diff --git a/arch/m68k/include/asm/sbus.h b/arch/m68k/include/asm/sbus.h
deleted file mode 100644 (file)
index bfe3ba1..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * some sbus structures and macros to make usage of sbus drivers possible
- */
-
-#ifndef __M68K_SBUS_H
-#define __M68K_SBUS_H
-
-struct sbus_dev {
-       struct {
-               unsigned int which_io;
-               unsigned int phys_addr;
-       } reg_addrs[1];
-};
-
-/* sbus IO functions stolen from include/asm-sparc/io.h for the serial driver */
-/* No SBUS on the Sun3, kludge -- sam */
-
-static inline void _sbus_writeb(unsigned char val, unsigned long addr)
-{
-       *(volatile unsigned char *)addr = val;
-}
-
-static inline unsigned char _sbus_readb(unsigned long addr)
-{
-       return *(volatile unsigned char *)addr;
-}
-
-static inline void _sbus_writel(unsigned long val, unsigned long addr)
-{
-       *(volatile unsigned long *)addr = val;
-
-}
-
-extern inline unsigned long _sbus_readl(unsigned long addr)
-{
-       return *(volatile unsigned long *)addr;
-}
-
-
-#define sbus_readb(a) _sbus_readb((unsigned long)a)
-#define sbus_writeb(v, a) _sbus_writeb(v, (unsigned long)a)
-#define sbus_readl(a) _sbus_readl((unsigned long)a)
-#define sbus_writel(v, a) _sbus_writel(v, (unsigned long)a)
-
-#endif
diff --git a/arch/m68k/include/asm/scatterlist.h b/arch/m68k/include/asm/scatterlist.h
deleted file mode 100644 (file)
index 3125054..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _M68K_SCATTERLIST_H
-#define _M68K_SCATTERLIST_H
-
-#include <asm-generic/scatterlist.h>
-
-#endif /* !(_M68K_SCATTERLIST_H) */
diff --git a/arch/m68k/include/asm/sections.h b/arch/m68k/include/asm/sections.h
deleted file mode 100644 (file)
index 5277e52..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef _ASM_M68K_SECTIONS_H
-#define _ASM_M68K_SECTIONS_H
-
-#include <asm-generic/sections.h>
-
-extern char _sbss[], _ebss[];
-
-#endif /* _ASM_M68K_SECTIONS_H */
diff --git a/arch/m68k/include/asm/shm.h b/arch/m68k/include/asm/shm.h
deleted file mode 100644 (file)
index fa56ec8..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef _M68K_SHM_H
-#define _M68K_SHM_H
-
-
-/* format of page table entries that correspond to shared memory pages
-   currently out in swap space (see also mm/swap.c):
-   bits 0-1 (PAGE_PRESENT) is  = 0
-   bits 8..2 (SWP_TYPE) are = SHM_SWP_TYPE
-   bits 31..9 are used like this:
-   bits 15..9 (SHM_ID) the id of the shared memory segment
-   bits 30..16 (SHM_IDX) the index of the page within the shared memory segment
-                    (actually only bits 25..16 get used since SHMMAX is so low)
-   bit 31 (SHM_READ_ONLY) flag whether the page belongs to a read-only attach
-*/
-/* on the m68k both bits 0 and 1 must be zero */
-/* format on the sun3 is similar, but bits 30, 31 are set to zero and all
-   others are reduced by 2. --m */
-
-#ifndef CONFIG_SUN3
-#define SHM_ID_SHIFT   9
-#else
-#define SHM_ID_SHIFT   7
-#endif
-#define _SHM_ID_BITS   7
-#define SHM_ID_MASK    ((1<<_SHM_ID_BITS)-1)
-
-#define SHM_IDX_SHIFT  (SHM_ID_SHIFT+_SHM_ID_BITS)
-#define _SHM_IDX_BITS  15
-#define SHM_IDX_MASK   ((1<<_SHM_IDX_BITS)-1)
-
-#endif /* _M68K_SHM_H */
diff --git a/arch/m68k/include/asm/siginfo.h b/arch/m68k/include/asm/siginfo.h
deleted file mode 100644 (file)
index 851d3d7..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _M68K_SIGINFO_H
-#define _M68K_SIGINFO_H
-
-#include <asm-generic/siginfo.h>
-
-#endif
diff --git a/arch/m68k/include/asm/statfs.h b/arch/m68k/include/asm/statfs.h
deleted file mode 100644 (file)
index 08d93f1..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _M68K_STATFS_H
-#define _M68K_STATFS_H
-
-#include <asm-generic/statfs.h>
-
-#endif /* _M68K_STATFS_H */
diff --git a/arch/m68k/include/asm/topology.h b/arch/m68k/include/asm/topology.h
deleted file mode 100644 (file)
index ca173e9..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_M68K_TOPOLOGY_H
-#define _ASM_M68K_TOPOLOGY_H
-
-#include <asm-generic/topology.h>
-
-#endif /* _ASM_M68K_TOPOLOGY_H */
diff --git a/arch/m68k/include/asm/types.h b/arch/m68k/include/asm/types.h
deleted file mode 100644 (file)
index 89705ad..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef _M68K_TYPES_H
-#define _M68K_TYPES_H
-
-/*
- * This file is never included by application software unless
- * explicitly requested (e.g., via linux/types.h) in which case the
- * application is Linux specific so (user-) name space pollution is
- * not a major issue.  However, for interoperability, libraries still
- * need to be careful to avoid a name clashes.
- */
-#include <asm-generic/int-ll64.h>
-
-/*
- * These aren't exported outside the kernel to avoid name space clashes
- */
-#ifdef __KERNEL__
-
-#define BITS_PER_LONG 32
-
-#endif /* __KERNEL__ */
-
-#endif /* _M68K_TYPES_H */
index f4043ae63db1292889957f28cee8d4375d5719e3..2b3ca0bf7a0df900b6442a9611e9da857020c0dc 100644 (file)
@@ -2,7 +2,7 @@
 #define _ASM_M68K_UNALIGNED_H
 
 
-#if defined(CONFIG_COLDFIRE) || defined(CONFIG_M68000)
+#ifdef CONFIG_CPU_HAS_NO_UNALIGNED
 #include <linux/unaligned/be_struct.h>
 #include <linux/unaligned/le_byteshift.h>
 #include <linux/unaligned/generic.h>
@@ -12,7 +12,7 @@
 
 #else
 /*
- * The m68k can do unaligned accesses itself. 
+ * The m68k can do unaligned accesses itself.
  */
 #include <linux/unaligned/access_ok.h>
 #include <linux/unaligned/generic.h>
diff --git a/arch/m68k/include/asm/xor.h b/arch/m68k/include/asm/xor.h
deleted file mode 100644 (file)
index c82eb12..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/xor.h>
index 7dc186b7a85fb27a098858a4106ac64d95abc1b4..71fb29938dba260b6e5895c3d7eb5f10f2afbb16 100644 (file)
@@ -218,13 +218,10 @@ void __init setup_arch(char **cmdline_p)
        printk(KERN_INFO "Motorola M5235EVB support (C)2005 Syn-tech Systems, Inc. (Jate Sujjavanich)\n");
 #endif
 
-       pr_debug("KERNEL -> TEXT=0x%06x-0x%06x DATA=0x%06x-0x%06x "
-                "BSS=0x%06x-0x%06x\n", (int) &_stext, (int) &_etext,
-                (int) &_sdata, (int) &_edata,
-                (int) &_sbss, (int) &_ebss);
-       pr_debug("MEMORY -> ROMFS=0x%06x-0x%06x MEM=0x%06x-0x%06x\n ",
-                (int) &_ebss, (int) memory_start,
-                (int) memory_start, (int) memory_end);
+       pr_debug("KERNEL -> TEXT=0x%p-0x%p DATA=0x%p-0x%p BSS=0x%p-0x%p\n",
+                _stext, _etext, _sdata, _edata, __bss_start, __bss_stop);
+       pr_debug("MEMORY -> ROMFS=0x%p-0x%06lx MEM=0x%06lx-0x%06lx\n ",
+                __bss_stop, memory_start, memory_start, memory_end);
 
        /* Keep a copy of command line */
        *cmdline_p = &command_line[0];
index 8623f8dc16f8a03c9da88910537ae93fc47bc510..9a5932ec368946bf808c5faf527cbf39731b5540 100644 (file)
@@ -479,9 +479,13 @@ sys_atomic_cmpxchg_32(unsigned long newval, int oldval, int d3, int d4, int d5,
                        goto bad_access;
                }
 
-               mem_value = *mem;
+               /*
+                * No need to check for EFAULT; we know that the page is
+                * present and writable.
+                */
+               __get_user(mem_value, mem);
                if (mem_value == oldval)
-                       *mem = newval;
+                       __put_user(newval, mem);
 
                pte_unmap_unlock(pte, ptl);
                up_read(&mm->mmap_sem);
index 40e02d9c38b4df4bac25bf659d44885dd99f9fa8..06a763f49fd34643d5330221a48011be00889b0e 100644 (file)
@@ -78,9 +78,7 @@ SECTIONS {
                __init_end = .;
        }
 
-       _sbss = .;
        BSS_SECTION(0, 0, 0)
-       _ebss = .;
 
        _end = .;
 
index 63407c836826842a9dc2648c84fb3c50ba5c4f79..d0993594f558b3408317aede57c634c407ea580f 100644 (file)
@@ -31,9 +31,7 @@ SECTIONS
 
   RW_DATA_SECTION(16, PAGE_SIZE, THREAD_SIZE)
 
-  _sbss = .;
   BSS_SECTION(0, 0, 0)
-  _ebss = .;
 
   _edata = .;                  /* End of data section */
 
index ad0f46d64c0b66a8d6b6cf4f82ffeaeeabbda084..8080469ee6c11c3e86ab59febaa4773790a2ffc7 100644 (file)
@@ -44,9 +44,7 @@ __init_begin = .;
        . = ALIGN(PAGE_SIZE);
        __init_end = .;
 
-  _sbss = .;
   BSS_SECTION(0, 0, 0)
-  _ebss = .;
 
   _end = . ;
 
index 79e928a525d078169e0617270e1fcea9da08b5f2..ee5f0b1b5c5dd9b86c78552f42e4e7e9210a74cb 100644 (file)
@@ -19,7 +19,7 @@ along with GNU CC; see the file COPYING.  If not, write to
 the Free Software Foundation, 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
-#if defined(CONFIG_M68000) || defined(CONFIG_COLDFIRE)
+#ifdef CONFIG_CPU_HAS_NO_MULDIV64
 
 #define SI_TYPE_SIZE 32
 #define __BITS4 (SI_TYPE_SIZE / 4)
index f77f258dce3aca67fbfbc2e02ba33718c918903f..282f9de68966ee20409af3e4d2244af716323ca8 100644 (file)
@@ -104,7 +104,7 @@ void __init print_memmap(void)
                MLK_ROUNDUP(__init_begin, __init_end),
                MLK_ROUNDUP(_stext, _etext),
                MLK_ROUNDUP(_sdata, _edata),
-               MLK_ROUNDUP(_sbss, _ebss));
+               MLK_ROUNDUP(__bss_start, __bss_stop));
 }
 
 void __init mem_init(void)
index 345ec0d83e3d4ab825ff89afd0f4b022f0c67246..688e3664aea072ef2e2ee951b9991db2ab7abb78 100644 (file)
@@ -91,7 +91,7 @@ void __init mem_init(void)
        totalram_pages = free_all_bootmem();
 
        codek = (_etext - _stext) >> 10;
-       datak = (_ebss - _sdata) >> 10;
+       datak = (__bss_stop - _sdata) >> 10;
        initk = (__init_begin - __init_end) >> 10;
 
        tmp = nr_free_pages() << PAGE_SHIFT;
index f632fdcb93e913b218b7e5a7743d089ac0f8172f..537d3245b539a9c7006dfc7abc03b1f9f4f5ff04 100644 (file)
@@ -60,8 +60,8 @@ _start:
  *     Move ROM filesystem above bss :-)
  */
 
-       moveal  #_sbss, %a0                     /* romfs at the start of bss */
-       moveal  #_ebss, %a1                     /* Set up destination  */
+       moveal  #__bss_start, %a0               /* romfs at the start of bss */
+       moveal  #__bss_stop, %a1                /* Set up destination  */
        movel   %a0, %a2                        /* Copy of bss start */
 
        movel   8(%a0), %d1                     /* Get size of ROMFS */
@@ -84,8 +84,8 @@ _start:
  * Initialize BSS segment to 0
  */
 
-       lea     _sbss, %a0
-       lea     _ebss, %a1
+       lea     __bss_start, %a0
+       lea     __bss_stop, %a1
 
        /* Copy 0 to %a0 until %a0 == %a1 */
 2:     cmpal   %a0, %a1
index 2ebfd642081855acb3af3e35dac9066ed886038c..45a9dad29e3d3948ba0f52dadd2d54cae7b4a31a 100644 (file)
@@ -110,7 +110,7 @@ L0:
        movel   #CONFIG_VECTORBASE, %d7
        addl    #16, %d7
        moveal  %d7, %a0
-       moveal  #_ebss, %a1
+       moveal  #__bss_stop, %a1
        lea     %a1@(512), %a2
 
        DBG_PUTC('C')
@@ -138,8 +138,8 @@ LD1:
 
        DBG_PUTC('E')
 
-       moveal  #_sbss, %a0
-       moveal  #_ebss, %a1
+       moveal  #__bss_start, %a0
+       moveal  #__bss_stop, %a1
 
        /* Copy 0 to %a0 until %a0 == %a1 */
 L1:
@@ -150,7 +150,7 @@ L1:
        DBG_PUTC('F')
 
        /* Copy command line from end of bss to command line */
-       moveal  #_ebss, %a0
+       moveal  #__bss_stop, %a0
        moveal  #command_line, %a1
        lea     %a1@(512), %a2
 
@@ -165,7 +165,7 @@ L3:
 
        movel   #_sdata, %d0    
        movel   %d0, _rambase   
-       movel   #_ebss, %d0
+       movel   #__bss_stop, %d0
        movel   %d0, _ramstart
 
        movel   %a4, %d0
index 7f1aeeacb219a7525f3b142f4e27fefa5cb99ba5..5189ef9260986c31e0baaafec7ba770846ae118f 100644 (file)
@@ -76,8 +76,8 @@ pclp3:
        beq     pclp3
 #endif /* DEBUG */
        moveal  #0x007ffff0, %ssp
-       moveal  #_sbss, %a0
-       moveal  #_ebss, %a1
+       moveal  #__bss_start, %a0
+       moveal  #__bss_stop, %a1
 
        /* Copy 0 to %a0 until %a0 >= %a1 */
 L1:
index a5ff96d0295f069e28ded27ace22a5d1296e6cff..3dff98ba2e97df254743af9eebb5b297d539e548 100644 (file)
@@ -59,8 +59,8 @@ _stext:       movew   #0x2700,%sr
        cmpal   %a1, %a2
        bhi     1b
 
-       moveal  #_sbss, %a0
-       moveal  #_ebss, %a1
+       moveal  #__bss_start, %a0
+       moveal  #__bss_stop, %a1
        /* Copy 0 to %a0 until %a0 == %a1 */
        
 1:
@@ -70,7 +70,7 @@ _stext:       movew   #0x2700,%sr
 
         movel   #_sdata, %d0    
         movel   %d0, _rambase        
-        movel   #_ebss, %d0
+        movel   #__bss_stop, %d0
         movel   %d0, _ramstart
        movel   #RAMEND-CONFIG_MEMORY_RESERVE*0x100000, %d0
        movel   %d0, _ramend
index 8eb94fb6b971a3c35867f558096af9a6f7cd6b0e..acd213170d80fe6ae1e74cddd2fcbd90c7b65115 100644 (file)
@@ -219,8 +219,8 @@ LD1:
        cmp.l   #_edata, %a1
        blt     LD1
 
-       moveal  #_sbss, %a0
-       moveal  #_ebss, %a1
+       moveal  #__bss_start, %a0
+       moveal  #__bss_stop, %a1
 
        /* Copy 0 to %a0 until %a0 == %a1 */
 L1:
@@ -234,7 +234,7 @@ load_quicc:
 store_ram_size:
        /* Set ram size information */
        move.l  #_sdata, _rambase
-       move.l  #_ebss, _ramstart
+       move.l  #__bss_stop, _ramstart
        move.l  #RAMEND, %d0
        sub.l   #0x1000, %d0                    /* Reserve 4K for stack space.*/
        move.l  %d0, _ramend                    /* Different from RAMEND.*/
index 97510e55b802a587ad547c9f36005540ae2c8fc5..dfc756d998861823e48ac2b87a291ea7d04cbbb2 100644 (file)
@@ -13,7 +13,7 @@
  */
 
 .global _stext
-.global _sbss
+.global __bss_start
 .global _start
 
 .global _rambase
@@ -229,8 +229,8 @@ LD1:
        cmp.l   #_edata, %a1
        blt     LD1
 
-       moveal  #_sbss, %a0
-       moveal  #_ebss, %a1
+       moveal  #__bss_start, %a0
+       moveal  #__bss_stop, %a1
 
        /* Copy 0 to %a0 until %a0 == %a1 */
 L1:
@@ -244,7 +244,7 @@ load_quicc:
 store_ram_size:
        /* Set ram size information */
        move.l  #_sdata, _rambase
-       move.l  #_ebss, _ramstart
+       move.l  #__bss_stop, _ramstart
        move.l  #RAMEND, %d0
        sub.l   #0x1000, %d0                    /* Reserve 4K for stack space.*/
        move.l  %d0, _ramend                    /* Different from RAMEND.*/
index 4e0c9eb3bd1f437df4d8c469f58070b3558e8f5a..b88f5716f357b7acecc2e38a2f1bed8676ced43e 100644 (file)
@@ -230,8 +230,8 @@ _vstart:
        /*
         *      Move ROM filesystem above bss :-)
         */
-       lea     _sbss,%a0                       /* get start of bss */
-       lea     _ebss,%a1                       /* set up destination  */
+       lea     __bss_start,%a0                 /* get start of bss */
+       lea     __bss_stop,%a1                  /* set up destination  */
        movel   %a0,%a2                         /* copy of bss start */
 
        movel   8(%a0),%d0                      /* get size of ROMFS */
@@ -249,7 +249,7 @@ _copy_romfs:
        bne     _copy_romfs
 
 #else /* CONFIG_ROMFS_FS */
-       lea     _ebss,%a1
+       lea     __bss_stop,%a1
        movel   %a1,_ramstart
 #endif /* CONFIG_ROMFS_FS */
 
@@ -257,8 +257,8 @@ _copy_romfs:
        /*
         *      Zero out the bss region.
         */
-       lea     _sbss,%a0                       /* get start of bss */
-       lea     _ebss,%a1                       /* get end of bss */
+       lea     __bss_start,%a0                 /* get start of bss */
+       lea     __bss_stop,%a1                  /* get end of bss */
        clrl    %d0                             /* set value */
 _clear_bss:
        movel   %d0,(%a0)+                      /* clear each word */
index d8e6349336b4f54e9f03d26ebfc095821f1da30a..eeba067d565f4470937da6a40a61dcaf8caaae18 100644 (file)
@@ -22,57 +22,13 @@ int prom_root_node;
 struct linux_nodeops *prom_nodeops;
 
 /* You must call prom_init() before you attempt to use any of the
- * routines in the prom library.  It returns 0 on success, 1 on
- * failure.  It gets passed the pointer to the PROM vector.
+ * routines in the prom library.
+ * It gets passed the pointer to the PROM vector.
  */
 
-extern void prom_meminit(void);
-extern void prom_ranges_init(void);
-
 void __init prom_init(struct linux_romvec *rp)
 {
        romvec = rp;
-#ifndef CONFIG_SUN3
-       switch(romvec->pv_romvers) {
-       case 0:
-               prom_vers = PROM_V0;
-               break;
-       case 2:
-               prom_vers = PROM_V2;
-               break;
-       case 3:
-               prom_vers = PROM_V3;
-               break;
-       case 4:
-               prom_vers = PROM_P1275;
-               prom_printf("PROMLIB: Sun IEEE Prom not supported yet\n");
-               prom_halt();
-               break;
-       default:
-               prom_printf("PROMLIB: Bad PROM version %d\n",
-                           romvec->pv_romvers);
-               prom_halt();
-               break;
-       };
-
-       prom_rev = romvec->pv_plugin_revision;
-       prom_prev = romvec->pv_printrev;
-       prom_nodeops = romvec->pv_nodeops;
-
-       prom_root_node = prom_getsibling(0);
-       if((prom_root_node == 0) || (prom_root_node == -1))
-               prom_halt();
-
-       if((((unsigned long) prom_nodeops) == 0) ||
-          (((unsigned long) prom_nodeops) == -1))
-               prom_halt();
-
-       prom_meminit();
-
-       prom_ranges_init();
-#endif
-//     printk("PROMLIB: Sun Boot Prom Version %d Revision %d\n",
-//            romvec->pv_romvers, prom_rev);
 
        /* Initialization successful. */
        return;
index ab9afcaa7f6a44bad81bb9d80a9c5775fcf7c4f8..b4f409f942ab759b85244d8429fefaf5f80c5d35 100644 (file)
@@ -24,6 +24,7 @@ config MICROBLAZE
        select GENERIC_CPU_DEVICES
        select GENERIC_ATOMIC64
        select GENERIC_CLOCKEVENTS
+       select MODULES_USE_ELF_RELA
 
 config SWAP
        def_bool n
index 4487e150b4555d2815417551cbdafc200234bb5a..c07ed5d2a82034f11cbadc6e836d4e31761d380f 100644 (file)
@@ -18,10 +18,6 @@ extern char _ssbss[], _esbss[];
 extern unsigned long __ivt_start[], __ivt_end[];
 extern char _etext[], _stext[];
 
-#  ifdef CONFIG_MTD_UCLINUX
-extern char *_ebss;
-#  endif
-
 extern u32 _fdt_start[], _fdt_end[];
 
 # endif /* !__ASSEMBLY__ */
index bb4907c828dcb4c64ba4f3f291af06046c86c8a7..2b25bcf05c0022e44bdd46eff061f0782b309c7d 100644 (file)
@@ -21,9 +21,6 @@
 #include <linux/ftrace.h>
 #include <linux/uaccess.h>
 
-extern char *_ebss;
-EXPORT_SYMBOL_GPL(_ebss);
-
 #ifdef CONFIG_FUNCTION_TRACER
 extern void _mcount(void);
 EXPORT_SYMBOL(_mcount);
index 16d8dfd9094b1a0df25eaa48799576449a8b234b..4da971d4392f6fc79c4fa2040c87cd0c224c46fc 100644 (file)
@@ -121,7 +121,7 @@ void __init machine_early_init(const char *cmdline, unsigned int ram,
 
        /* Move ROMFS out of BSS before clearing it */
        if (romfs_size > 0) {
-               memmove(&_ebss, (int *)romfs_base, romfs_size);
+               memmove(&__bss_stop, (int *)romfs_base, romfs_size);
                klimit += romfs_size;
        }
 #endif
@@ -165,7 +165,7 @@ void __init machine_early_init(const char *cmdline, unsigned int ram,
        BUG_ON(romfs_size < 0); /* What else can we do? */
 
        printk("Moved 0x%08x bytes from 0x%08x to 0x%08x\n",
-                       romfs_size, romfs_base, (unsigned)&_ebss);
+                       romfs_size, romfs_base, (unsigned)&__bss_stop);
 
        printk("New klimit: 0x%08x\n", (unsigned)klimit);
 #endif
index 109e9d86ade4e46051f25c1d375eac1cd9f83224..936d01a689d74157f3a63e53eff1de725fa67f9d 100644 (file)
@@ -131,7 +131,6 @@ SECTIONS {
                        *(COMMON)
                . = ALIGN (4) ;
                __bss_stop = . ;
-               _ebss = . ;
        }
        . = ALIGN(PAGE_SIZE);
        _end = .;
index 331d574df99c8d86ecdce41c9366164fac63f396..8a75c24713492d7dc8bf4b7998c70fe274a1dd86 100644 (file)
@@ -8,6 +8,8 @@ config MIPS
        select HAVE_PERF_EVENTS
        select PERF_USE_VMALLOC
        select HAVE_ARCH_KGDB
+       select HAVE_ARCH_SECCOMP_FILTER
+       select HAVE_ARCH_TRACEHOOK
        select ARCH_HAVE_CUSTOM_GPIO_H
        select HAVE_FUNCTION_TRACER
        select HAVE_FUNCTION_TRACE_MCOUNT_TEST
@@ -17,6 +19,7 @@ config MIPS
        select HAVE_FUNCTION_GRAPH_TRACER
        select HAVE_KPROBES
        select HAVE_KRETPROBES
+       select HAVE_SYSCALL_TRACEPOINTS
        select ARCH_BINFMT_ELF_RANDOMIZE_PIE
        select RTC_LIB if !MACH_LOONGSON
        select GENERIC_ATOMIC64 if !64BIT
@@ -36,6 +39,9 @@ config MIPS
        select BUILDTIME_EXTABLE_SORT
        select GENERIC_CLOCKEVENTS
        select GENERIC_CMOS_UPDATE
+       select HAVE_MOD_ARCH_SPECIFIC
+       select MODULES_USE_ELF_REL
+       select MODULES_USE_ELF_RELA if 64BIT
 
 menu "Machine selection"
 
@@ -89,6 +95,7 @@ config ATH79
        select CEVT_R4K
        select CSRC_R4K
        select DMA_NONCOHERENT
+       select HAVE_CLK
        select IRQ_CPU
        select MIPS_MACHINE
        select SYS_HAS_CPU_MIPS32_R2
@@ -1901,6 +1908,7 @@ config MIPS_MT_SMP
        select SYS_SUPPORTS_SCHED_SMT if SMP
        select SYS_SUPPORTS_SMP
        select SMP_UP
+       select MIPS_PERF_SHARED_TC_COUNTERS
        help
          This is a kernel model which is known a VSMP but lately has been
          marketesed into SMVP.
@@ -2251,6 +2259,9 @@ config NR_CPUS
          performance should round up your number of processors to the next
          power of two.
 
+config MIPS_PERF_SHARED_TC_COUNTERS
+       bool
+
 #
 # Timer Interrupt Frequency Configuration
 #
index 99969484c475c7fc7366d12fa50efd495656a9b9..a124c251c0c92a2bbbcc8f86ab2674aa5a8ad6a4 100644 (file)
@@ -228,6 +228,8 @@ static int mtx1_pci_idsel(unsigned int devsel, int assert)
         * adapter on the mtx-1 "singleboard" variant. It triggers a custom
         * logic chip connected to EXT_IO3 (GPIO1) to suppress IDSEL signals.
         */
+       udelay(1);
+
        if (assert && devsel != 0)
                /* Suppress signal to Cardbus */
                alchemy_gpio_set_value(1, 0);   /* set EXT_IO3 OFF */
index 36e9570e7bc4a250fbbc05c6312c5b2bf53adcb5..b2a2311ec85b492d1dbbbd22df5a57db0ba978c4 100644 (file)
@@ -145,6 +145,8 @@ static void __init ar7240_usb_setup(void)
 
        ath79_ohci_resources[0].start = AR7240_OHCI_BASE;
        ath79_ohci_resources[0].end = AR7240_OHCI_BASE + AR7240_OHCI_SIZE - 1;
+       ath79_ohci_resources[1].start = ATH79_CPU_IRQ_USB;
+       ath79_ohci_resources[1].end = ATH79_CPU_IRQ_USB;
        platform_device_register(&ath79_ohci_device);
 }
 
index 29054f211832505d371930d3e13f752af56f69f3..48fe762d2526885908c192545dbc70fa69d4cb9c 100644 (file)
@@ -188,8 +188,10 @@ void __init ath79_gpio_init(void)
 
        if (soc_is_ar71xx())
                ath79_gpio_count = AR71XX_GPIO_COUNT;
-       else if (soc_is_ar724x())
-               ath79_gpio_count = AR724X_GPIO_COUNT;
+       else if (soc_is_ar7240())
+               ath79_gpio_count = AR7240_GPIO_COUNT;
+       else if (soc_is_ar7241() || soc_is_ar7242())
+               ath79_gpio_count = AR7241_GPIO_COUNT;
        else if (soc_is_ar913x())
                ath79_gpio_count = AR913X_GPIO_COUNT;
        else if (soc_is_ar933x())
index e39f73048d4f653c48ba3b52a31976f290699bae..f1c9c3e2f678146e83772f3c7cb05a0989743fce 100644 (file)
@@ -106,11 +106,15 @@ int __init bcm63xx_spi_register(void)
        if (BCMCPU_IS_6338() || BCMCPU_IS_6348()) {
                spi_resources[0].end += BCM_6338_RSET_SPI_SIZE - 1;
                spi_pdata.fifo_size = SPI_6338_MSG_DATA_SIZE;
+               spi_pdata.msg_type_shift = SPI_6338_MSG_TYPE_SHIFT;
+               spi_pdata.msg_ctl_width = SPI_6338_MSG_CTL_WIDTH;
        }
 
        if (BCMCPU_IS_6358() || BCMCPU_IS_6368()) {
                spi_resources[0].end += BCM_6358_RSET_SPI_SIZE - 1;
                spi_pdata.fifo_size = SPI_6358_MSG_DATA_SIZE;
+               spi_pdata.msg_type_shift = SPI_6358_MSG_TYPE_SHIFT;
+               spi_pdata.msg_ctl_width = SPI_6358_MSG_CTL_WIDTH;
        }
 
        bcm63xx_spi_regs_init();
index 7fb1f222b8a538b9b000e99375899f37a0c069a9..274cd4fad30c4810f29a420e2dc1e4b139adba73 100644 (file)
@@ -61,6 +61,12 @@ static void octeon_irq_set_ciu_mapping(int irq, int line, int bit,
        octeon_irq_ciu_to_irq[line][bit] = irq;
 }
 
+static void octeon_irq_force_ciu_mapping(struct irq_domain *domain,
+                                        int irq, int line, int bit)
+{
+       irq_domain_associate(domain, irq, line << 6 | bit);
+}
+
 static int octeon_coreid_for_cpu(int cpu)
 {
 #ifdef CONFIG_SMP
@@ -183,19 +189,9 @@ static void __init octeon_irq_init_core(void)
                mutex_init(&cd->core_irq_mutex);
 
                irq = OCTEON_IRQ_SW0 + i;
-               switch (irq) {
-               case OCTEON_IRQ_TIMER:
-               case OCTEON_IRQ_SW0:
-               case OCTEON_IRQ_SW1:
-               case OCTEON_IRQ_5:
-               case OCTEON_IRQ_PERF:
-                       irq_set_chip_data(irq, cd);
-                       irq_set_chip_and_handler(irq, &octeon_irq_chip_core,
-                                                handle_percpu_irq);
-                       break;
-               default:
-                       break;
-               }
+               irq_set_chip_data(irq, cd);
+               irq_set_chip_and_handler(irq, &octeon_irq_chip_core,
+                                        handle_percpu_irq);
        }
 }
 
@@ -890,7 +886,6 @@ static int octeon_irq_gpio_xlat(struct irq_domain *d,
        unsigned int type;
        unsigned int pin;
        unsigned int trigger;
-       struct octeon_irq_gpio_domain_data *gpiod;
 
        if (d->of_node != node)
                return -EINVAL;
@@ -925,8 +920,7 @@ static int octeon_irq_gpio_xlat(struct irq_domain *d,
                break;
        }
        *out_type = type;
-       gpiod = d->host_data;
-       *out_hwirq = gpiod->base_hwirq + pin;
+       *out_hwirq = pin;
 
        return 0;
 }
@@ -996,19 +990,21 @@ static int octeon_irq_ciu_map(struct irq_domain *d,
 static int octeon_irq_gpio_map(struct irq_domain *d,
                               unsigned int virq, irq_hw_number_t hw)
 {
-       unsigned int line = hw >> 6;
-       unsigned int bit = hw & 63;
+       struct octeon_irq_gpio_domain_data *gpiod = d->host_data;
+       unsigned int line, bit;
 
        if (!octeon_irq_virq_in_range(virq))
                return -EINVAL;
 
+       hw += gpiod->base_hwirq;
+       line = hw >> 6;
+       bit = hw & 63;
        if (line > 1 || octeon_irq_ciu_to_irq[line][bit] != 0)
                return -EINVAL;
 
        octeon_irq_set_ciu_mapping(virq, line, bit,
                                   octeon_irq_gpio_chip,
                                   octeon_irq_handle_gpio);
-
        return 0;
 }
 
@@ -1149,6 +1145,7 @@ static void __init octeon_irq_init_ciu(void)
        struct irq_chip *chip_wd;
        struct device_node *gpio_node;
        struct device_node *ciu_node;
+       struct irq_domain *ciu_domain = NULL;
 
        octeon_irq_init_ciu_percpu();
        octeon_irq_setup_secondary = octeon_irq_setup_secondary_ciu;
@@ -1177,31 +1174,6 @@ static void __init octeon_irq_init_ciu(void)
        /* Mips internal */
        octeon_irq_init_core();
 
-       /* CIU_0 */
-       for (i = 0; i < 16; i++)
-               octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_WORKQ0, 0, i + 0, chip, handle_level_irq);
-
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_MBOX0, 0, 32, chip_mbox, handle_percpu_irq);
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_MBOX1, 0, 33, chip_mbox, handle_percpu_irq);
-
-       for (i = 0; i < 4; i++)
-               octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_PCI_INT0, 0, i + 36, chip, handle_level_irq);
-       for (i = 0; i < 4; i++)
-               octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_PCI_MSI0, 0, i + 40, chip, handle_level_irq);
-
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_RML, 0, 46, chip, handle_level_irq);
-       for (i = 0; i < 4; i++)
-               octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_TIMER0, 0, i + 52, chip, handle_edge_irq);
-
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_USB0, 0, 56, chip, handle_level_irq);
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_BOOTDMA, 0, 63, chip, handle_level_irq);
-
-       /* CIU_1 */
-       for (i = 0; i < 16; i++)
-               octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_WDOG0, 1, i + 0, chip_wd, handle_level_irq);
-
-       octeon_irq_set_ciu_mapping(OCTEON_IRQ_USB1, 1, 17, chip, handle_level_irq);
-
        gpio_node = of_find_compatible_node(NULL, NULL, "cavium,octeon-3860-gpio");
        if (gpio_node) {
                struct octeon_irq_gpio_domain_data *gpiod;
@@ -1219,10 +1191,35 @@ static void __init octeon_irq_init_ciu(void)
 
        ciu_node = of_find_compatible_node(NULL, NULL, "cavium,octeon-3860-ciu");
        if (ciu_node) {
-               irq_domain_add_tree(ciu_node, &octeon_irq_domain_ciu_ops, NULL);
+               ciu_domain = irq_domain_add_tree(ciu_node, &octeon_irq_domain_ciu_ops, NULL);
                of_node_put(ciu_node);
        } else
-               pr_warn("Cannot find device node for cavium,octeon-3860-ciu.\n");
+               panic("Cannot find device node for cavium,octeon-3860-ciu.");
+
+       /* CIU_0 */
+       for (i = 0; i < 16; i++)
+               octeon_irq_force_ciu_mapping(ciu_domain, i + OCTEON_IRQ_WORKQ0, 0, i + 0);
+
+       octeon_irq_set_ciu_mapping(OCTEON_IRQ_MBOX0, 0, 32, chip_mbox, handle_percpu_irq);
+       octeon_irq_set_ciu_mapping(OCTEON_IRQ_MBOX1, 0, 33, chip_mbox, handle_percpu_irq);
+
+       for (i = 0; i < 4; i++)
+               octeon_irq_force_ciu_mapping(ciu_domain, i + OCTEON_IRQ_PCI_INT0, 0, i + 36);
+       for (i = 0; i < 4; i++)
+               octeon_irq_force_ciu_mapping(ciu_domain, i + OCTEON_IRQ_PCI_MSI0, 0, i + 40);
+
+       octeon_irq_force_ciu_mapping(ciu_domain, OCTEON_IRQ_RML, 0, 46);
+       for (i = 0; i < 4; i++)
+               octeon_irq_force_ciu_mapping(ciu_domain, i + OCTEON_IRQ_TIMER0, 0, i + 52);
+
+       octeon_irq_force_ciu_mapping(ciu_domain, OCTEON_IRQ_USB0, 0, 56);
+       octeon_irq_force_ciu_mapping(ciu_domain, OCTEON_IRQ_BOOTDMA, 0, 63);
+
+       /* CIU_1 */
+       for (i = 0; i < 16; i++)
+               octeon_irq_set_ciu_mapping(i + OCTEON_IRQ_WDOG0, 1, i + 0, chip_wd, handle_level_irq);
+
+       octeon_irq_force_ciu_mapping(ciu_domain, OCTEON_IRQ_USB1, 1, 17);
 
        /* Enable the CIU lines */
        set_c0_status(STATUSF_IP3 | STATUSF_IP2);
index 138b2216b4f8ba396be6ae788e9a9b3215a13630..569f41bdcc466529501b4cbeb8ad4133e86e8205 100644 (file)
@@ -47,40 +47,40 @@ static int __devinit octeon_serial_probe(struct platform_device *pdev)
 {
        int irq, res;
        struct resource *res_mem;
-       struct uart_port port;
+       struct uart_8250_port up;
 
        /* All adaptors have an irq.  */
        irq = platform_get_irq(pdev, 0);
        if (irq < 0)
                return irq;
 
-       memset(&port, 0, sizeof(port));
+       memset(&up, 0, sizeof(up));
 
-       port.flags = ASYNC_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
-       port.type = PORT_OCTEON;
-       port.iotype = UPIO_MEM;
-       port.regshift = 3;
-       port.dev = &pdev->dev;
+       up.port.flags = ASYNC_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE;
+       up.port.type = PORT_OCTEON;
+       up.port.iotype = UPIO_MEM;
+       up.port.regshift = 3;
+       up.port.dev = &pdev->dev;
 
        if (octeon_is_simulation())
                /* Make simulator output fast*/
-               port.uartclk = 115200 * 16;
+               up.port.uartclk = 115200 * 16;
        else
-               port.uartclk = octeon_get_io_clock_rate();
+               up.port.uartclk = octeon_get_io_clock_rate();
 
-       port.serial_in = octeon_serial_in;
-       port.serial_out = octeon_serial_out;
-       port.irq = irq;
+       up.port.serial_in = octeon_serial_in;
+       up.port.serial_out = octeon_serial_out;
+       up.port.irq = irq;
 
        res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (res_mem == NULL) {
                dev_err(&pdev->dev, "found no memory resource\n");
                return -ENXIO;
        }
-       port.mapbase = res_mem->start;
-       port.membase = ioremap(res_mem->start, resource_size(res_mem));
+       up.port.mapbase = res_mem->start;
+       up.port.membase = ioremap(res_mem->start, resource_size(res_mem));
 
-       res = serial8250_register_port(&port);
+       res = serial8250_register_8250_port(&up);
 
        return res >= 0 ? 0 : res;
 }
index 3f4c5cb6433e2ac4765330353207d608cb1c68ed..01cc6ba64831f6973d2fb673a66f385612ea809d 100644 (file)
@@ -59,8 +59,8 @@ static __inline__ void atomic_add(int i, atomic_t * v)
                "       sc      %0, %1                                  \n"
                "       beqzl   %0, 1b                                  \n"
                "       .set    mips0                                   \n"
-               : "=&r" (temp), "=m" (v->counter)
-               : "Ir" (i), "m" (v->counter));
+               : "=&r" (temp), "+m" (v->counter)
+               : "Ir" (i));
        } else if (kernel_uses_llsc) {
                int temp;
 
@@ -71,8 +71,8 @@ static __inline__ void atomic_add(int i, atomic_t * v)
                        "       addu    %0, %2                          \n"
                        "       sc      %0, %1                          \n"
                        "       .set    mips0                           \n"
-                       : "=&r" (temp), "=m" (v->counter)
-                       : "Ir" (i), "m" (v->counter));
+                       : "=&r" (temp), "+m" (v->counter)
+                       : "Ir" (i));
                } while (unlikely(!temp));
        } else {
                unsigned long flags;
@@ -102,8 +102,8 @@ static __inline__ void atomic_sub(int i, atomic_t * v)
                "       sc      %0, %1                                  \n"
                "       beqzl   %0, 1b                                  \n"
                "       .set    mips0                                   \n"
-               : "=&r" (temp), "=m" (v->counter)
-               : "Ir" (i), "m" (v->counter));
+               : "=&r" (temp), "+m" (v->counter)
+               : "Ir" (i));
        } else if (kernel_uses_llsc) {
                int temp;
 
@@ -114,8 +114,8 @@ static __inline__ void atomic_sub(int i, atomic_t * v)
                        "       subu    %0, %2                          \n"
                        "       sc      %0, %1                          \n"
                        "       .set    mips0                           \n"
-                       : "=&r" (temp), "=m" (v->counter)
-                       : "Ir" (i), "m" (v->counter));
+                       : "=&r" (temp), "+m" (v->counter)
+                       : "Ir" (i));
                } while (unlikely(!temp));
        } else {
                unsigned long flags;
@@ -146,9 +146,8 @@ static __inline__ int atomic_add_return(int i, atomic_t * v)
                "       beqzl   %0, 1b                                  \n"
                "       addu    %0, %1, %3                              \n"
                "       .set    mips0                                   \n"
-               : "=&r" (result), "=&r" (temp), "=m" (v->counter)
-               : "Ir" (i), "m" (v->counter)
-               : "memory");
+               : "=&r" (result), "=&r" (temp), "+m" (v->counter)
+               : "Ir" (i));
        } else if (kernel_uses_llsc) {
                int temp;
 
@@ -159,9 +158,8 @@ static __inline__ int atomic_add_return(int i, atomic_t * v)
                        "       addu    %0, %1, %3                      \n"
                        "       sc      %0, %2                          \n"
                        "       .set    mips0                           \n"
-                       : "=&r" (result), "=&r" (temp), "=m" (v->counter)
-                       : "Ir" (i), "m" (v->counter)
-                       : "memory");
+                       : "=&r" (result), "=&r" (temp), "+m" (v->counter)
+                       : "Ir" (i));
                } while (unlikely(!result));
 
                result = temp + i;
@@ -212,9 +210,8 @@ static __inline__ int atomic_sub_return(int i, atomic_t * v)
                        "       subu    %0, %1, %3                      \n"
                        "       sc      %0, %2                          \n"
                        "       .set    mips0                           \n"
-                       : "=&r" (result), "=&r" (temp), "=m" (v->counter)
-                       : "Ir" (i), "m" (v->counter)
-                       : "memory");
+                       : "=&r" (result), "=&r" (temp), "+m" (v->counter)
+                       : "Ir" (i));
                } while (unlikely(!result));
 
                result = temp - i;
@@ -262,7 +259,7 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v)
                "       .set    reorder                                 \n"
                "1:                                                     \n"
                "       .set    mips0                                   \n"
-               : "=&r" (result), "=&r" (temp), "=m" (v->counter)
+               : "=&r" (result), "=&r" (temp), "+m" (v->counter)
                : "Ir" (i), "m" (v->counter)
                : "memory");
        } else if (kernel_uses_llsc) {
@@ -280,9 +277,8 @@ static __inline__ int atomic_sub_if_positive(int i, atomic_t * v)
                "       .set    reorder                                 \n"
                "1:                                                     \n"
                "       .set    mips0                                   \n"
-               : "=&r" (result), "=&r" (temp), "=m" (v->counter)
-               : "Ir" (i), "m" (v->counter)
-               : "memory");
+               : "=&r" (result), "=&r" (temp), "+m" (v->counter)
+               : "Ir" (i));
        } else {
                unsigned long flags;
 
@@ -430,8 +426,8 @@ static __inline__ void atomic64_add(long i, atomic64_t * v)
                "       scd     %0, %1                                  \n"
                "       beqzl   %0, 1b                                  \n"
                "       .set    mips0                                   \n"
-               : "=&r" (temp), "=m" (v->counter)
-               : "Ir" (i), "m" (v->counter));
+               : "=&r" (temp), "+m" (v->counter)
+               : "Ir" (i));
        } else if (kernel_uses_llsc) {
                long temp;
 
@@ -442,8 +438,8 @@ static __inline__ void atomic64_add(long i, atomic64_t * v)
                        "       daddu   %0, %2                          \n"
                        "       scd     %0, %1                          \n"
                        "       .set    mips0                           \n"
-                       : "=&r" (temp), "=m" (v->counter)
-                       : "Ir" (i), "m" (v->counter));
+                       : "=&r" (temp), "+m" (v->counter)
+                       : "Ir" (i));
                } while (unlikely(!temp));
        } else {
                unsigned long flags;
@@ -473,8 +469,8 @@ static __inline__ void atomic64_sub(long i, atomic64_t * v)
                "       scd     %0, %1                                  \n"
                "       beqzl   %0, 1b                                  \n"
                "       .set    mips0                                   \n"
-               : "=&r" (temp), "=m" (v->counter)
-               : "Ir" (i), "m" (v->counter));
+               : "=&r" (temp), "+m" (v->counter)
+               : "Ir" (i));
        } else if (kernel_uses_llsc) {
                long temp;
 
@@ -485,8 +481,8 @@ static __inline__ void atomic64_sub(long i, atomic64_t * v)
                        "       dsubu   %0, %2                          \n"
                        "       scd     %0, %1                          \n"
                        "       .set    mips0                           \n"
-                       : "=&r" (temp), "=m" (v->counter)
-                       : "Ir" (i), "m" (v->counter));
+                       : "=&r" (temp), "+m" (v->counter)
+                       : "Ir" (i));
                } while (unlikely(!temp));
        } else {
                unsigned long flags;
@@ -517,9 +513,8 @@ static __inline__ long atomic64_add_return(long i, atomic64_t * v)
                "       beqzl   %0, 1b                                  \n"
                "       daddu   %0, %1, %3                              \n"
                "       .set    mips0                                   \n"
-               : "=&r" (result), "=&r" (temp), "=m" (v->counter)
-               : "Ir" (i), "m" (v->counter)
-               : "memory");
+               : "=&r" (result), "=&r" (temp), "+m" (v->counter)
+               : "Ir" (i));
        } else if (kernel_uses_llsc) {
                long temp;
 
@@ -649,9 +644,8 @@ static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v)
                "       .set    reorder                                 \n"
                "1:                                                     \n"
                "       .set    mips0                                   \n"
-               : "=&r" (result), "=&r" (temp), "=m" (v->counter)
-               : "Ir" (i), "m" (v->counter)
-               : "memory");
+               : "=&r" (result), "=&r" (temp), "+m" (v->counter)
+               : "Ir" (i));
        } else {
                unsigned long flags;
 
index ca400f7c3f594944d31a7b1341b6aa04d7e4c757..55db8e1157f09dd7423d98cd2e03ec670abc0755 100644 (file)
 #define cpu_hwrena_impl_bits           0
 #endif
 
+#ifndef cpu_has_perf_cntr_intr_bit
+#define cpu_has_perf_cntr_intr_bit     (cpu_data[0].options & MIPS_CPU_PCI)
+#endif
+
 #endif /* __ASM_CPU_FEATURES_H */
index f21b7c04e95a2f70073e087e69d384e53d11862f..783e5989d3899aad05155b9eb06ce181d90b2030 100644 (file)
@@ -319,6 +319,7 @@ enum cpu_type_enum {
 #define MIPS_CPU_VINT          0x00080000 /* CPU supports MIPSR2 vectored interrupts */
 #define MIPS_CPU_VEIC          0x00100000 /* CPU supports MIPSR2 external interrupt controller mode */
 #define MIPS_CPU_ULRI          0x00200000 /* CPU has ULRI feature */
+#define MIPS_CPU_PCI           0x00400000 /* CPU has Perf Ctr Int indicator */
 
 /*
  * CPU ASE encodings
index 455c0ac7d4ea84632cc41c40ee48e7dd9e82ce86..aec51639eccc3082b193bf2f9bfe609cfc29e05d 100644 (file)
@@ -331,6 +331,7 @@ extern int dump_task_fpu(struct task_struct *, elf_fpregset_t *);
 #define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs)                  \
        dump_task_fpu(tsk, elf_fpregs)
 
+#define CORE_DUMP_USE_REGSET
 #define ELF_EXEC_PAGESIZE      PAGE_SIZE
 
 /* This yields a mask that user programs can use to figure out what
index 1caa78ad06d5833306ee367cd44fbefe5dbd6fe3..dde504477fac1521e95f2fe60b75c7ac2fd8e5aa 100644 (file)
 #define AR71XX_GPIO_REG_FUNC           0x28
 
 #define AR71XX_GPIO_COUNT              16
-#define AR724X_GPIO_COUNT              18
+#define AR7240_GPIO_COUNT              18
+#define AR7241_GPIO_COUNT              20
 #define AR913X_GPIO_COUNT              22
 #define AR933X_GPIO_COUNT              30
 #define AR934X_GPIO_COUNT              23
index 4476fa03bf36d5eee19b26e1443b697eb4c33502..6ddae926bf79717b95a709d71c40a99a888a310a 100644 (file)
@@ -42,7 +42,6 @@
 #define cpu_has_mips64r1       0
 #define cpu_has_mips64r2       0
 
-#define cpu_has_dsp            0
 #define cpu_has_mipsmt         0
 
 #define cpu_has_64bits         0
index 7d98dbe5d4b5ef9de38b25717747436e08e6179e..c9bae1362606aac10d79c921f3c8b7374cfc1ba5 100644 (file)
@@ -9,6 +9,8 @@ int __init bcm63xx_spi_register(void);
 
 struct bcm63xx_spi_pdata {
        unsigned int    fifo_size;
+       unsigned int    msg_type_shift;
+       unsigned int    msg_ctl_width;
        int             bus_num;
        int             num_chipselect;
        u32             speed_hz;
index 4ccc2a748aff2db6913dab0e8b67e1eb6fbceeb8..61f2a2a5099d02ad281290c675604a4e897e9bf9 100644 (file)
 #define SPI_6338_FILL_BYTE             0x07
 #define SPI_6338_MSG_TAIL              0x09
 #define SPI_6338_RX_TAIL               0x0b
-#define SPI_6338_MSG_CTL               0x40
+#define SPI_6338_MSG_CTL               0x40    /* 8-bits register */
+#define SPI_6338_MSG_CTL_WIDTH         8
 #define SPI_6338_MSG_DATA              0x41
 #define SPI_6338_MSG_DATA_SIZE         0x3f
 #define SPI_6338_RX_DATA               0x80
 #define SPI_6348_FILL_BYTE             0x07
 #define SPI_6348_MSG_TAIL              0x09
 #define SPI_6348_RX_TAIL               0x0b
-#define SPI_6348_MSG_CTL               0x40
+#define SPI_6348_MSG_CTL               0x40    /* 8-bits register */
+#define SPI_6348_MSG_CTL_WIDTH         8
 #define SPI_6348_MSG_DATA              0x41
 #define SPI_6348_MSG_DATA_SIZE         0x3f
 #define SPI_6348_RX_DATA               0x80
 
 /* BCM 6358 SPI core */
 #define SPI_6358_MSG_CTL               0x00    /* 16-bits register */
+#define SPI_6358_MSG_CTL_WIDTH         16
 #define SPI_6358_MSG_DATA              0x02
 #define SPI_6358_MSG_DATA_SIZE         0x21e
 #define SPI_6358_RX_DATA               0x400
 
 /* BCM 6358 SPI core */
 #define SPI_6368_MSG_CTL               0x00    /* 16-bits register */
+#define SPI_6368_MSG_CTL_WIDTH         16
 #define SPI_6368_MSG_DATA              0x02
 #define SPI_6368_MSG_DATA_SIZE         0x21e
 #define SPI_6368_RX_DATA               0x400
 #define SPI_HD_W                       0x01
 #define SPI_HD_R                       0x02
 #define SPI_BYTE_CNT_SHIFT             0
-#define SPI_MSG_TYPE_SHIFT             14
+#define SPI_6338_MSG_TYPE_SHIFT                6
+#define SPI_6348_MSG_TYPE_SHIFT                6
+#define SPI_6358_MSG_TYPE_SHIFT                14
+#define SPI_6368_MSG_TYPE_SHIFT                14
 
 /* Command */
 #define SPI_CMD_NOOP                   0x00
index 418992042f6fcbc23f1612a82ee886cd969c5fa5..c22a3078bf11b69f2da21547fc1c337da7b51206 100644 (file)
@@ -21,14 +21,10 @@ enum octeon_irq {
        OCTEON_IRQ_TIMER,
 /* sources in CIU_INTX_EN0 */
        OCTEON_IRQ_WORKQ0,
-       OCTEON_IRQ_GPIO0 = OCTEON_IRQ_WORKQ0 + 16,
-       OCTEON_IRQ_WDOG0 = OCTEON_IRQ_GPIO0 + 16,
+       OCTEON_IRQ_WDOG0 = OCTEON_IRQ_WORKQ0 + 16,
        OCTEON_IRQ_WDOG15 = OCTEON_IRQ_WDOG0 + 15,
        OCTEON_IRQ_MBOX0 = OCTEON_IRQ_WDOG0 + 16,
        OCTEON_IRQ_MBOX1,
-       OCTEON_IRQ_UART0,
-       OCTEON_IRQ_UART1,
-       OCTEON_IRQ_UART2,
        OCTEON_IRQ_PCI_INT0,
        OCTEON_IRQ_PCI_INT1,
        OCTEON_IRQ_PCI_INT2,
@@ -38,8 +34,6 @@ enum octeon_irq {
        OCTEON_IRQ_PCI_MSI2,
        OCTEON_IRQ_PCI_MSI3,
 
-       OCTEON_IRQ_TWSI,
-       OCTEON_IRQ_TWSI2,
        OCTEON_IRQ_RML,
        OCTEON_IRQ_TIMER0,
        OCTEON_IRQ_TIMER1,
@@ -47,8 +41,6 @@ enum octeon_irq {
        OCTEON_IRQ_TIMER3,
        OCTEON_IRQ_USB0,
        OCTEON_IRQ_USB1,
-       OCTEON_IRQ_MII0,
-       OCTEON_IRQ_MII1,
        OCTEON_IRQ_BOOTDMA,
 #ifndef CONFIG_PCI_MSI
        OCTEON_IRQ_LAST = 127
index 6a2df709c576956a4c58541d2fad5c2f9c726917..1de5d826c49e02a3f185b331f354872ec711c0a4 100644 (file)
@@ -87,5 +87,8 @@ extern __iomem void *ltq_cgu_membase;
 extern void ltq_pmu_enable(unsigned int module);
 extern void ltq_pmu_disable(unsigned int module);
 
+/* allow pci driver to set the pci clk delay */
+void ltq_pci_set_delay(u8 delay);
+
 #endif /* CONFIG_SOC_TYPE_XWAY */
 #endif /* _LTQ_XWAY_H__ */
index 7f87d824eeb089ca3be7aa4f56efa889ec98c40d..2b83c36bae48b55fb47510821db51d12926b5d64 100644 (file)
 #define  CAUSEF_IP7            (_ULCAST_(1)   << 15)
 #define  CAUSEB_IV             23
 #define  CAUSEF_IV             (_ULCAST_(1)   << 23)
+#define  CAUSEB_PCI            26
+#define  CAUSEF_PCI            (_ULCAST_(1)   << 26)
 #define  CAUSEB_CE             28
 #define  CAUSEF_CE             (_ULCAST_(3)   << 28)
 #define  CAUSEB_TI             30
index 7531ecd654d651df630d1d520e71f762c47547e3..26137da1c713cd95ca0de3bc422fcb8e5fa6f6e8 100644 (file)
@@ -10,6 +10,7 @@ struct mod_arch_specific {
        struct list_head dbe_list;
        const struct exception_table_entry *dbe_start;
        const struct exception_table_entry *dbe_end;
+       struct mips_hi16 *r_mips_hi16_list;
 };
 
 typedef uint8_t Elf64_Byte;            /* Type for a 8-bit quantity.  */
@@ -34,11 +35,14 @@ typedef struct {
 } Elf64_Mips_Rela;
 
 #ifdef CONFIG_32BIT
-
 #define Elf_Shdr       Elf32_Shdr
 #define Elf_Sym                Elf32_Sym
 #define Elf_Ehdr       Elf32_Ehdr
 #define Elf_Addr       Elf32_Addr
+#define Elf_Rel                Elf32_Rel
+#define Elf_Rela       Elf32_Rela
+#define ELF_R_TYPE(X)  ELF32_R_TYPE(X)
+#define ELF_R_SYM(X)   ELF32_R_SYM(X)
 
 #define Elf_Mips_Rel   Elf32_Rel
 #define Elf_Mips_Rela  Elf32_Rela
@@ -49,11 +53,14 @@ typedef struct {
 #endif
 
 #ifdef CONFIG_64BIT
-
 #define Elf_Shdr       Elf64_Shdr
 #define Elf_Sym                Elf64_Sym
 #define Elf_Ehdr       Elf64_Ehdr
 #define Elf_Addr       Elf64_Addr
+#define Elf_Rel                Elf64_Rel
+#define Elf_Rela       Elf64_Rela
+#define ELF_R_TYPE(X)  ELF64_R_TYPE(X)
+#define ELF_R_SYM(X)   ELF64_R_SYM(X)
 
 #define Elf_Mips_Rel   Elf64_Mips_Rel
 #define Elf_Mips_Rela  Elf64_Mips_Rela
index 4b7f5252d2fd31ba156723c23db11e57e983442b..8db2098829873dde2ab2b81c18536d3873a15083 100644 (file)
@@ -153,7 +153,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)
 
-extern asmlinkage void syscall_trace_enter(struct pt_regs *regs);
+extern asmlinkage long syscall_trace_enter(struct pt_regs *regs);
 extern asmlinkage void syscall_trace_leave(struct pt_regs *regs);
 
 extern void die(const char *, struct pt_regs *) __noreturn;
@@ -164,6 +164,19 @@ static inline void die_if_kernel(const char *str, struct pt_regs *regs)
                die(str, regs);
 }
 
-#endif
+/* Helpers for working with the user stack pointer */
+
+static inline unsigned long user_stack_pointer(struct pt_regs *regs)
+{
+       return regs->regs[29];
+}
+
+static inline void user_stack_pointer_set(struct pt_regs *regs,
+       unsigned long val)
+{
+       regs->regs[29] = val;
+}
+
+#endif /* __KERNEL__ */
 
 #endif /* _ASM_PTRACE_H */
index a37d12b3b61c0b3c2db45cc6a37f44fc4e6eac52..afe9e0e03fe96c5b7a710abe19075d9cf4a4f87b 100644 (file)
 
 #ifdef CONFIG_SYNC_R4K
 
-extern void synchronise_count_master(void);
-extern void synchronise_count_slave(void);
+extern void synchronise_count_master(int cpu);
+extern void synchronise_count_slave(int cpu);
 
 #else
 
-static inline void synchronise_count_master(void)
+static inline void synchronise_count_master(int cpu)
 {
 }
 
-static inline void synchronise_count_slave(void)
+static inline void synchronise_count_slave(int cpu)
 {
 }
 
index 20ebeb875ee6250938f883598b0cbf73da4dc31b..5fad4f6be089abe2f9d535692ab387be5196665b 100644 (file)
@@ -32,6 +32,8 @@ struct siginfo;
 #define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
 #endif
 
+#define __ARCH_SIGSYS
+
 #include <asm-generic/siginfo.h>
 
 typedef struct siginfo {
@@ -96,6 +98,13 @@ typedef struct siginfo {
                        __ARCH_SI_BAND_T _band; /* POLL_IN, POLL_OUT, POLL_MSG */
                        int _fd;
                } _sigpoll;
+
+               /* SIGSYS */
+               struct {
+                       void __user *_call_addr; /* calling user insn */
+                       int _syscall;   /* triggering system call number */
+                       unsigned int _arch;     /* AUDIT_ARCH_* of syscall */
+               } _sigsys;
        } _sifields;
 } siginfo_t;
 
diff --git a/arch/mips/include/asm/syscall.h b/arch/mips/include/asm/syscall.h
new file mode 100644 (file)
index 0000000..bd2c6c4
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Access to user system call parameters and results
+ *
+ * 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.
+ *
+ * See asm-generic/syscall.h for descriptions of what we must do here.
+ *
+ * Copyright (C) 2012 Ralf Baechle <ralf@linux-mips.org>
+ */
+
+#ifndef __ASM_MIPS_SYSCALL_H
+#define __ASM_MIPS_SYSCALL_H
+
+#include <linux/audit.h>
+#include <linux/elf-em.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <asm/ptrace.h>
+
+static inline long syscall_get_nr(struct task_struct *task,
+       struct pt_regs *regs)
+{
+       return regs->regs[2];
+}
+
+static inline void syscall_rollback(struct task_struct *task,
+                                   struct pt_regs *regs)
+{
+       regs->regs[7] = regs->regs[26];
+       regs->regs[2] = regs->regs[0];
+}
+
+static inline long syscall_get_return_value(struct task_struct *task,
+                                           struct pt_regs *regs)
+{
+       return regs->regs[2];
+}
+
+static inline void syscall_set_return_value(struct task_struct *task,
+                                           struct pt_regs *regs,
+                                           int error, long val)
+{
+       if (error) {
+               regs->regs[2] = -error;
+               regs->regs[7] = 1;
+       } else {
+               regs->regs[2] = val;
+               regs->regs[7] = 0;
+       }
+}
+
+static inline unsigned long mips_get_syscall_arg(unsigned long *arg,
+       struct task_struct *task, struct pt_regs *regs, unsigned int n)
+{
+       unsigned long usp = regs->regs[29];
+
+       switch (n) {
+       case 0: case 1: case 2: case 3:
+               *arg = regs->regs[4 + n];
+
+               return 0;
+
+#ifdef CONFIG_32BIT
+       case 4: case 5: case 6: case 7:
+               return get_user(*arg, (int *)usp + 4 * n);
+#endif
+
+#ifdef CONFIG_64BIT
+       case 4: case 5: case 6: case 7:
+#ifdef CONFIG_MIPS32_O32
+               if (test_thread_flag(TIF_32BIT_REGS))
+                       return get_user(*arg, (int *)usp + 4 * n);
+               else
+#endif
+                       *arg = regs->regs[4 + n];
+
+               return 0;
+#endif
+
+       default:
+               BUG();
+       }
+}
+
+static inline void syscall_get_arguments(struct task_struct *task,
+                                        struct pt_regs *regs,
+                                        unsigned int i, unsigned int n,
+                                        unsigned long *args)
+{
+       unsigned long arg;
+       int ret;
+
+       while (n--)
+               ret |= mips_get_syscall_arg(&arg, task, regs, i++);
+
+       /*
+        * No way to communicate an error because this is a void function.
+        */
+#if 0
+       return ret;
+#endif
+}
+
+extern const unsigned long sys_call_table[];
+extern const unsigned long sys32_call_table[];
+extern const unsigned long sysn32_call_table[];
+
+static inline int __syscall_get_arch(void)
+{
+       int arch = EM_MIPS;
+#ifdef CONFIG_64BIT
+       arch |=  __AUDIT_ARCH_64BIT;
+#endif
+#if defined(__LITTLE_ENDIAN)
+       arch |=  __AUDIT_ARCH_LE;
+#endif
+       return arch;
+}
+
+static inline int syscall_get_arch(struct task_struct *task,
+                                  struct pt_regs *regs)
+{
+       return __syscall_get_arch();
+}
+
+#endif /* __ASM_MIPS_SYSCALL_H */
index ca97e0ecb64b5054195b7d271017fa2760b7d05a..f3735431132e098a2fb8e4d0623a6968e2069dbb 100644 (file)
@@ -111,6 +111,7 @@ register struct thread_info *__current_thread_info __asm__("$28");
 #define TIF_32BIT_ADDR         23      /* 32-bit address space (o32/n32) */
 #define TIF_FPUBOUND           24      /* thread bound to FPU-full CPU set */
 #define TIF_LOAD_WATCH         25      /* If set, load watch registers */
+#define TIF_SYSCALL_TRACEPOINT 26      /* syscall tracepoint instrumentation */
 #define TIF_SYSCALL_TRACE      31      /* syscall trace active */
 
 #ifdef CONFIG_MIPS32_O32
@@ -134,6 +135,12 @@ register struct thread_info *__current_thread_info __asm__("$28");
 #define _TIF_32BIT_ADDR                (1<<TIF_32BIT_ADDR)
 #define _TIF_FPUBOUND          (1<<TIF_FPUBOUND)
 #define _TIF_LOAD_WATCH                (1<<TIF_LOAD_WATCH)
+#define _TIF_SYSCALL_TRACEPOINT        (1<<TIF_SYSCALL_TRACEPOINT)
+
+/* work to do in syscall_trace_enter() */
+#define _TIF_WORK_SYSCALL_ENTRY                                                \
+       (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP |       \
+        _TIF_SYSCALL_TRACEPOINT)
 
 /* work to do in syscall_trace_leave() */
 #define _TIF_WORK_SYSCALL_EXIT (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT)
index bebbde01be92870cf06ff40ee373b1e6dab71ccb..6b01e6721e58f08621cd94204a3dd07b784a08e4 100644 (file)
  */
 #define cond_syscall(x) asm(".weak\t" #x "\n" #x "\t=\tsys_ni_syscall")
 
+#ifdef CONFIG_32BIT
+# define NR_syscalls   (__NR_O32_Linux + __NR_O32_Linux_syscalls)
+#endif /* CONFIG_32BIT */
+#ifdef CONFIG_64BIT
+# ifdef CONFIG_MIPS32_N32
+#  define NR_syscalls  (__NR_N32_Linux + __NR_N32_Linux_syscalls)
+#else
+#  define NR_syscalls  (__NR_64_Linux + __NR_64_Linux_syscalls)
+# endif
+#endif /* CONFIG_64BIT */
+
 #endif /* __KERNEL__ */
 #endif /* _ASM_UNISTD_H */
index fdaf65e1a99d04ca07d9b5a440d584bccd040029..74316dcc55abe479065dddcfb670ea5cad07d4e8 100644 (file)
@@ -32,6 +32,7 @@ obj-$(CONFIG_SYNC_R4K)                += sync-r4k.o
 obj-$(CONFIG_STACKTRACE)       += stacktrace.o
 obj-$(CONFIG_MODULES)          += mips_ksyms.o module.o
 
+obj-$(CONFIG_FTRACE_SYSCALLS)  += ftrace.o
 obj-$(CONFIG_FUNCTION_TRACER)  += mcount.o ftrace.o
 
 obj-$(CONFIG_CPU_LOONGSON2)    += r4k_fpu.o r4k_switch.o
index 1b51046191e85a77dfb56aa284b96e66b035b083..7ae3895d68aff8154524d02a25b4f042a74040a7 100644 (file)
@@ -1186,8 +1186,11 @@ __cpuinit void cpu_probe(void)
                }
        }
 
-       if (cpu_has_mips_r2)
+       if (cpu_has_mips_r2) {
                c->srsets = ((read_c0_srsctl() >> 26) & 0x0f) + 1;
+               /* R2 has Performance Counter Interrupt indicator */
+               c->options |= MIPS_CPU_PCI;
+       }
        else
                c->srsets = 1;
 
index 6a2d758dd8e9ed0b4a0afb043d2972869620834c..dfc7441a81aa9b83fa1cb759a4fa451c82075489 100644 (file)
 #include <linux/uaccess.h>
 #include <linux/init.h>
 #include <linux/ftrace.h>
+#include <linux/syscalls.h>
 
 #include <asm/asm.h>
 #include <asm/asm-offsets.h>
 #include <asm/cacheflush.h>
+#include <asm/syscall.h>
 #include <asm/uasm.h>
+#include <asm/unistd.h>
 
 #include <asm-generic/sections.h>
 
@@ -326,3 +329,33 @@ out:
        WARN_ON(1);
 }
 #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
+#ifdef CONFIG_FTRACE_SYSCALLS
+
+#ifdef CONFIG_32BIT
+unsigned long __init arch_syscall_addr(int nr)
+{
+       return (unsigned long)sys_call_table[nr - __NR_O32_Linux];
+}
+#endif
+
+#ifdef CONFIG_64BIT
+
+unsigned long __init arch_syscall_addr(int nr)
+{
+#ifdef CONFIG_MIPS32_N32
+       if (nr >= __NR_N32_Linux && nr <= __NR_N32_Linux + __NR_N32_Linux_syscalls)
+               return (unsigned long)sysn32_call_table[nr - __NR_N32_Linux];
+#endif
+       if (nr >= __NR_64_Linux  && nr <= __NR_64_Linux + __NR_64_Linux_syscalls)
+               return (unsigned long)sys_call_table[nr - __NR_64_Linux];
+#ifdef CONFIG_MIPS32_O32
+       if (nr >= __NR_O32_Linux && nr <= __NR_O32_Linux + __NR_O32_Linux_syscalls)
+               return (unsigned long)sys32_call_table[nr - __NR_O32_Linux];
+#endif
+
+       return (unsigned long) &sys_ni_syscall;
+}
+#endif
+
+#endif /* CONFIG_FTRACE_SYSCALLS */
index f4546e97c60db111215495f924aa567595c39581..23817a6e32b606cde0a3a714c810db342b91fd0f 100644 (file)
@@ -283,6 +283,15 @@ static int kgdb_mips_notify(struct notifier_block *self, unsigned long cmd,
        struct pt_regs *regs = args->regs;
        int trap = (regs->cp0_cause & 0x7c) >> 2;
 
+#ifdef CONFIG_KPROBES
+       /*
+        * Return immediately if the kprobes fault notifier has set
+        * DIE_PAGE_FAULT.
+        */
+       if (cmd == DIE_PAGE_FAULT)
+               return NOTIFY_DONE;
+#endif /* CONFIG_KPROBES */
+
        /* Userspace events, ignore. */
        if (user_mode(regs))
                return NOTIFY_DONE;
index a5066b1c3de37185896fe529839c5133a158ccb0..9f102cf080a467a356c13c005dab9797a9a69db6 100644 (file)
@@ -39,8 +39,6 @@ struct mips_hi16 {
        Elf_Addr value;
 };
 
-static struct mips_hi16 *mips_hi16_list;
-
 static LIST_HEAD(dbe_list);
 static DEFINE_SPINLOCK(dbe_lock);
 
@@ -128,8 +126,8 @@ static int apply_r_mips_hi16_rel(struct module *me, u32 *location, Elf_Addr v)
 
        n->addr = (Elf_Addr *)location;
        n->value = v;
-       n->next = mips_hi16_list;
-       mips_hi16_list = n;
+       n->next = me->arch.r_mips_hi16_list;
+       me->arch.r_mips_hi16_list = n;
 
        return 0;
 }
@@ -142,18 +140,28 @@ static int apply_r_mips_hi16_rela(struct module *me, u32 *location, Elf_Addr v)
        return 0;
 }
 
+static void free_relocation_chain(struct mips_hi16 *l)
+{
+       struct mips_hi16 *next;
+
+       while (l) {
+               next = l->next;
+               kfree(l);
+               l = next;
+       }
+}
+
 static int apply_r_mips_lo16_rel(struct module *me, u32 *location, Elf_Addr v)
 {
        unsigned long insnlo = *location;
+       struct mips_hi16 *l;
        Elf_Addr val, vallo;
 
        /* Sign extend the addend we extract from the lo insn.  */
        vallo = ((insnlo & 0xffff) ^ 0x8000) - 0x8000;
 
-       if (mips_hi16_list != NULL) {
-               struct mips_hi16 *l;
-
-               l = mips_hi16_list;
+       if (me->arch.r_mips_hi16_list != NULL) {
+               l = me->arch.r_mips_hi16_list;
                while (l != NULL) {
                        struct mips_hi16 *next;
                        unsigned long insn;
@@ -188,7 +196,7 @@ static int apply_r_mips_lo16_rel(struct module *me, u32 *location, Elf_Addr v)
                        l = next;
                }
 
-               mips_hi16_list = NULL;
+               me->arch.r_mips_hi16_list = NULL;
        }
 
        /*
@@ -201,6 +209,9 @@ static int apply_r_mips_lo16_rel(struct module *me, u32 *location, Elf_Addr v)
        return 0;
 
 out_danger:
+       free_relocation_chain(l);
+       me->arch.r_mips_hi16_list = NULL;
+
        pr_err("module %s: dangerous R_MIPS_LO16 REL relocation\n", me->name);
 
        return -ENOEXEC;
@@ -273,6 +284,7 @@ int apply_relocate(Elf_Shdr *sechdrs, const char *strtab,
        pr_debug("Applying relocate section %u to %u\n", relsec,
               sechdrs[relsec].sh_info);
 
+       me->arch.r_mips_hi16_list = NULL;
        for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
                /* This is where to make the change */
                location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
@@ -296,9 +308,23 @@ int apply_relocate(Elf_Shdr *sechdrs, const char *strtab,
                        return res;
        }
 
+       /*
+        * Normally the hi16 list should be deallocated at this point.  A
+        * malformed binary however could contain a series of R_MIPS_HI16
+        * relocations not followed by a R_MIPS_LO16 relocation.  In that
+        * case, free up the list and return an error.
+        */
+       if (me->arch.r_mips_hi16_list) {
+               free_relocation_chain(me->arch.r_mips_hi16_list);
+               me->arch.r_mips_hi16_list = NULL;
+
+               return -ENOEXEC;
+       }
+
        return 0;
 }
 
+#ifdef CONFIG_MODULES_USE_ELF_RELA
 int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
                       unsigned int symindex, unsigned int relsec,
                       struct module *me)
@@ -338,6 +364,7 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
 
        return 0;
 }
+#endif
 
 /* Given an address, look for it in the module exception tables. */
 const struct exception_table_entry *search_module_dbetables(unsigned long addr)
index 2f28d3b55687eac42469051c34cb9a6749b21473..a9b995dcf69165b39b7dec0ddeefc9ed06b9980f 100644 (file)
@@ -28,6 +28,8 @@
 #include <asm/time.h> /* For perf_irq */
 
 #define MIPS_MAX_HWEVENTS 4
+#define MIPS_TCS_PER_COUNTER 2
+#define MIPS_CPUID_TO_COUNTER_MASK (MIPS_TCS_PER_COUNTER - 1)
 
 struct cpu_hw_events {
        /* Array of events on this cpu. */
@@ -78,7 +80,6 @@ struct mips_perf_event {
 static struct mips_perf_event raw_event;
 static DEFINE_MUTEX(raw_event_mutex);
 
-#define UNSUPPORTED_PERF_EVENT_ID 0xffffffff
 #define C(x) PERF_COUNT_HW_CACHE_##x
 
 struct mips_pmu {
@@ -109,13 +110,20 @@ static struct mips_pmu mipspmu;
 #define M_PERFCTL_INTERRUPT_ENABLE     (1      <<  4)
 #define M_PERFCTL_EVENT(event)         (((event) & 0x3ff)  << 5)
 #define M_PERFCTL_VPEID(vpe)           ((vpe)    << 16)
+
+#ifdef CONFIG_CPU_BMIPS5000
+#define M_PERFCTL_MT_EN(filter)                0
+#else /* !CONFIG_CPU_BMIPS5000 */
 #define M_PERFCTL_MT_EN(filter)                ((filter) << 20)
+#endif /* CONFIG_CPU_BMIPS5000 */
+
 #define    M_TC_EN_ALL                 M_PERFCTL_MT_EN(0)
 #define    M_TC_EN_VPE                 M_PERFCTL_MT_EN(1)
 #define    M_TC_EN_TC                  M_PERFCTL_MT_EN(2)
 #define M_PERFCTL_TCID(tcid)           ((tcid)   << 22)
 #define M_PERFCTL_WIDE                 (1      << 30)
 #define M_PERFCTL_MORE                 (1      << 31)
+#define M_PERFCTL_TC                   (1      << 30)
 
 #define M_PERFCTL_COUNT_EVENT_WHENEVER (M_PERFCTL_EXL |                \
                                        M_PERFCTL_KERNEL |              \
@@ -131,21 +139,21 @@ static struct mips_pmu mipspmu;
 #define M_PERFCTL_EVENT_MASK           0xfe0
 
 
-#ifdef CONFIG_MIPS_MT_SMP
+#ifdef CONFIG_MIPS_PERF_SHARED_TC_COUNTERS
 static int cpu_has_mipsmt_pertccounters;
 
 static DEFINE_RWLOCK(pmuint_rwlock);
 
+#if defined(CONFIG_CPU_BMIPS5000)
+#define vpe_id()       (cpu_has_mipsmt_pertccounters ? \
+                        0 : (smp_processor_id() & MIPS_CPUID_TO_COUNTER_MASK))
+#else
 /*
  * FIXME: For VSMP, vpe_id() is redefined for Perf-events, because
  * cpu_data[cpuid].vpe_id reports 0 for _both_ CPUs.
  */
-#if defined(CONFIG_HW_PERF_EVENTS)
-#define vpe_id()       (cpu_has_mipsmt_pertccounters ? \
-                       0 : smp_processor_id())
-#else
 #define vpe_id()       (cpu_has_mipsmt_pertccounters ? \
-                       0 : cpu_data[smp_processor_id()].vpe_id)
+                        0 : smp_processor_id())
 #endif
 
 /* Copied from op_model_mipsxx.c */
@@ -162,10 +170,10 @@ static unsigned int counters_total_to_per_cpu(unsigned int counters)
        return counters >> vpe_shift();
 }
 
-#else /* !CONFIG_MIPS_MT_SMP */
+#else /* !CONFIG_MIPS_PERF_SHARED_TC_COUNTERS */
 #define vpe_id()       0
 
-#endif /* CONFIG_MIPS_MT_SMP */
+#endif /* CONFIG_MIPS_PERF_SHARED_TC_COUNTERS */
 
 static void resume_local_counters(void);
 static void pause_local_counters(void);
@@ -340,6 +348,11 @@ static void mipsxx_pmu_enable_event(struct hw_perf_event *evt, int idx)
                (evt->config_base & M_PERFCTL_CONFIG_MASK) |
                /* Make sure interrupt enabled. */
                M_PERFCTL_INTERRUPT_ENABLE;
+       if (IS_ENABLED(CONFIG_CPU_BMIPS5000))
+               /* enable the counter for the calling thread */
+               cpuc->saved_ctrl[idx] |=
+                       (1 << (12 + vpe_id())) | M_PERFCTL_TC;
+
        /*
         * We do not actually let the counter run. Leave it until start().
         */
@@ -509,7 +522,7 @@ static void mipspmu_read(struct perf_event *event)
 
 static void mipspmu_enable(struct pmu *pmu)
 {
-#ifdef CONFIG_MIPS_MT_SMP
+#ifdef CONFIG_MIPS_PERF_SHARED_TC_COUNTERS
        write_unlock(&pmuint_rwlock);
 #endif
        resume_local_counters();
@@ -529,7 +542,7 @@ static void mipspmu_enable(struct pmu *pmu)
 static void mipspmu_disable(struct pmu *pmu)
 {
        pause_local_counters();
-#ifdef CONFIG_MIPS_MT_SMP
+#ifdef CONFIG_MIPS_PERF_SHARED_TC_COUNTERS
        write_lock(&pmuint_rwlock);
 #endif
 }
@@ -664,13 +677,10 @@ static unsigned int mipspmu_perf_event_encode(const struct mips_perf_event *pev)
 
 static const struct mips_perf_event *mipspmu_map_general_event(int idx)
 {
-       const struct mips_perf_event *pev;
-
-       pev = ((*mipspmu.general_event_map)[idx].event_id ==
-               UNSUPPORTED_PERF_EVENT_ID ? ERR_PTR(-EOPNOTSUPP) :
-               &(*mipspmu.general_event_map)[idx]);
 
-       return pev;
+       if ((*mipspmu.general_event_map)[idx].cntr_mask == 0)
+               return ERR_PTR(-EOPNOTSUPP);
+       return &(*mipspmu.general_event_map)[idx];
 }
 
 static const struct mips_perf_event *mipspmu_map_cache_event(u64 config)
@@ -695,7 +705,7 @@ static const struct mips_perf_event *mipspmu_map_cache_event(u64 config)
                                        [cache_op]
                                        [cache_result]);
 
-       if (pev->event_id == UNSUPPORTED_PERF_EVENT_ID)
+       if (pev->cntr_mask == 0)
                return ERR_PTR(-EOPNOTSUPP);
 
        return pev;
@@ -800,11 +810,8 @@ static const struct mips_perf_event mipsxxcore_event_map
                                [PERF_COUNT_HW_MAX] = {
        [PERF_COUNT_HW_CPU_CYCLES] = { 0x00, CNTR_EVEN | CNTR_ODD, P },
        [PERF_COUNT_HW_INSTRUCTIONS] = { 0x01, CNTR_EVEN | CNTR_ODD, T },
-       [PERF_COUNT_HW_CACHE_REFERENCES] = { UNSUPPORTED_PERF_EVENT_ID },
-       [PERF_COUNT_HW_CACHE_MISSES] = { UNSUPPORTED_PERF_EVENT_ID },
        [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = { 0x02, CNTR_EVEN, T },
        [PERF_COUNT_HW_BRANCH_MISSES] = { 0x02, CNTR_ODD, T },
-       [PERF_COUNT_HW_BUS_CYCLES] = { UNSUPPORTED_PERF_EVENT_ID },
 };
 
 /* 74K core has different branch event code. */
@@ -812,11 +819,8 @@ static const struct mips_perf_event mipsxx74Kcore_event_map
                                [PERF_COUNT_HW_MAX] = {
        [PERF_COUNT_HW_CPU_CYCLES] = { 0x00, CNTR_EVEN | CNTR_ODD, P },
        [PERF_COUNT_HW_INSTRUCTIONS] = { 0x01, CNTR_EVEN | CNTR_ODD, T },
-       [PERF_COUNT_HW_CACHE_REFERENCES] = { UNSUPPORTED_PERF_EVENT_ID },
-       [PERF_COUNT_HW_CACHE_MISSES] = { UNSUPPORTED_PERF_EVENT_ID },
        [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = { 0x27, CNTR_EVEN, T },
        [PERF_COUNT_HW_BRANCH_MISSES] = { 0x27, CNTR_ODD, T },
-       [PERF_COUNT_HW_BUS_CYCLES] = { UNSUPPORTED_PERF_EVENT_ID },
 };
 
 static const struct mips_perf_event octeon_event_map[PERF_COUNT_HW_MAX] = {
@@ -829,6 +833,13 @@ static const struct mips_perf_event octeon_event_map[PERF_COUNT_HW_MAX] = {
        [PERF_COUNT_HW_BUS_CYCLES] = { 0x25, CNTR_ALL },
 };
 
+static const struct mips_perf_event bmips5000_event_map
+                               [PERF_COUNT_HW_MAX] = {
+       [PERF_COUNT_HW_CPU_CYCLES] = { 0x00, CNTR_EVEN | CNTR_ODD, T },
+       [PERF_COUNT_HW_INSTRUCTIONS] = { 0x01, CNTR_EVEN | CNTR_ODD, T },
+       [PERF_COUNT_HW_BRANCH_MISSES] = { 0x02, CNTR_ODD, T },
+};
+
 /* 24K/34K/1004K cores can share the same cache event map. */
 static const struct mips_perf_event mipsxxcore_cache_map
                                [PERF_COUNT_HW_CACHE_MAX]
@@ -849,10 +860,6 @@ static const struct mips_perf_event mipsxxcore_cache_map
                [C(RESULT_ACCESS)]      = { 0x0a, CNTR_EVEN, T },
                [C(RESULT_MISS)]        = { 0x0b, CNTR_EVEN | CNTR_ODD, T },
        },
-       [C(OP_PREFETCH)] = {
-               [C(RESULT_ACCESS)]      = { UNSUPPORTED_PERF_EVENT_ID },
-               [C(RESULT_MISS)]        = { UNSUPPORTED_PERF_EVENT_ID },
-       },
 },
 [C(L1I)] = {
        [C(OP_READ)] = {
@@ -869,7 +876,6 @@ static const struct mips_perf_event mipsxxcore_cache_map
                 * Note that MIPS has only "hit" events countable for
                 * the prefetch operation.
                 */
-               [C(RESULT_MISS)]        = { UNSUPPORTED_PERF_EVENT_ID },
        },
 },
 [C(LL)] = {
@@ -881,10 +887,6 @@ static const struct mips_perf_event mipsxxcore_cache_map
                [C(RESULT_ACCESS)]      = { 0x15, CNTR_ODD, P },
                [C(RESULT_MISS)]        = { 0x16, CNTR_EVEN, P },
        },
-       [C(OP_PREFETCH)] = {
-               [C(RESULT_ACCESS)]      = { UNSUPPORTED_PERF_EVENT_ID },
-               [C(RESULT_MISS)]        = { UNSUPPORTED_PERF_EVENT_ID },
-       },
 },
 [C(DTLB)] = {
        [C(OP_READ)] = {
@@ -895,10 +897,6 @@ static const struct mips_perf_event mipsxxcore_cache_map
                [C(RESULT_ACCESS)]      = { 0x06, CNTR_EVEN, T },
                [C(RESULT_MISS)]        = { 0x06, CNTR_ODD, T },
        },
-       [C(OP_PREFETCH)] = {
-               [C(RESULT_ACCESS)]      = { UNSUPPORTED_PERF_EVENT_ID },
-               [C(RESULT_MISS)]        = { UNSUPPORTED_PERF_EVENT_ID },
-       },
 },
 [C(ITLB)] = {
        [C(OP_READ)] = {
@@ -909,10 +907,6 @@ static const struct mips_perf_event mipsxxcore_cache_map
                [C(RESULT_ACCESS)]      = { 0x05, CNTR_EVEN, T },
                [C(RESULT_MISS)]        = { 0x05, CNTR_ODD, T },
        },
-       [C(OP_PREFETCH)] = {
-               [C(RESULT_ACCESS)]      = { UNSUPPORTED_PERF_EVENT_ID },
-               [C(RESULT_MISS)]        = { UNSUPPORTED_PERF_EVENT_ID },
-       },
 },
 [C(BPU)] = {
        /* Using the same code for *HW_BRANCH* */
@@ -924,24 +918,6 @@ static const struct mips_perf_event mipsxxcore_cache_map
                [C(RESULT_ACCESS)]      = { 0x02, CNTR_EVEN, T },
                [C(RESULT_MISS)]        = { 0x02, CNTR_ODD, T },
        },
-       [C(OP_PREFETCH)] = {
-               [C(RESULT_ACCESS)]      = { UNSUPPORTED_PERF_EVENT_ID },
-               [C(RESULT_MISS)]        = { UNSUPPORTED_PERF_EVENT_ID },
-       },
-},
-[C(NODE)] = {
-       [C(OP_READ)] = {
-               [C(RESULT_ACCESS)]      = { UNSUPPORTED_PERF_EVENT_ID },
-               [C(RESULT_MISS)]        = { UNSUPPORTED_PERF_EVENT_ID },
-       },
-       [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 },
-       },
 },
 };
 
@@ -965,10 +941,6 @@ static const struct mips_perf_event mipsxx74Kcore_cache_map
                [C(RESULT_ACCESS)]      = { 0x17, CNTR_ODD, T },
                [C(RESULT_MISS)]        = { 0x18, CNTR_ODD, T },
        },
-       [C(OP_PREFETCH)] = {
-               [C(RESULT_ACCESS)]      = { UNSUPPORTED_PERF_EVENT_ID },
-               [C(RESULT_MISS)]        = { UNSUPPORTED_PERF_EVENT_ID },
-       },
 },
 [C(L1I)] = {
        [C(OP_READ)] = {
@@ -985,7 +957,6 @@ static const struct mips_perf_event mipsxx74Kcore_cache_map
                 * Note that MIPS has only "hit" events countable for
                 * the prefetch operation.
                 */
-               [C(RESULT_MISS)]        = { UNSUPPORTED_PERF_EVENT_ID },
        },
 },
 [C(LL)] = {
@@ -997,25 +968,6 @@ static const struct mips_perf_event mipsxx74Kcore_cache_map
                [C(RESULT_ACCESS)]      = { 0x1c, CNTR_ODD, P },
                [C(RESULT_MISS)]        = { 0x1d, CNTR_EVEN | CNTR_ODD, P },
        },
-       [C(OP_PREFETCH)] = {
-               [C(RESULT_ACCESS)]      = { UNSUPPORTED_PERF_EVENT_ID },
-               [C(RESULT_MISS)]        = { UNSUPPORTED_PERF_EVENT_ID },
-       },
-},
-[C(DTLB)] = {
-       /* 74K core does not have specific DTLB events. */
-       [C(OP_READ)] = {
-               [C(RESULT_ACCESS)]      = { UNSUPPORTED_PERF_EVENT_ID },
-               [C(RESULT_MISS)]        = { UNSUPPORTED_PERF_EVENT_ID },
-       },
-       [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(ITLB)] = {
        [C(OP_READ)] = {
@@ -1026,10 +978,6 @@ static const struct mips_perf_event mipsxx74Kcore_cache_map
                [C(RESULT_ACCESS)]      = { 0x04, CNTR_EVEN, T },
                [C(RESULT_MISS)]        = { 0x04, CNTR_ODD, T },
        },
-       [C(OP_PREFETCH)] = {
-               [C(RESULT_ACCESS)]      = { UNSUPPORTED_PERF_EVENT_ID },
-               [C(RESULT_MISS)]        = { UNSUPPORTED_PERF_EVENT_ID },
-       },
 },
 [C(BPU)] = {
        /* Using the same code for *HW_BRANCH* */
@@ -1041,23 +989,64 @@ static const struct mips_perf_event mipsxx74Kcore_cache_map
                [C(RESULT_ACCESS)]      = { 0x27, CNTR_EVEN, T },
                [C(RESULT_MISS)]        = { 0x27, CNTR_ODD, T },
        },
-       [C(OP_PREFETCH)] = {
-               [C(RESULT_ACCESS)]      = { UNSUPPORTED_PERF_EVENT_ID },
-               [C(RESULT_MISS)]        = { UNSUPPORTED_PERF_EVENT_ID },
+},
+};
+
+/* BMIPS5000 */
+static const struct mips_perf_event bmips5000_cache_map
+                               [PERF_COUNT_HW_CACHE_MAX]
+                               [PERF_COUNT_HW_CACHE_OP_MAX]
+                               [PERF_COUNT_HW_CACHE_RESULT_MAX] = {
+[C(L1D)] = {
+       /*
+        * Like some other architectures (e.g. ARM), the performance
+        * counters don't differentiate between read and write
+        * accesses/misses, so this isn't strictly correct, but it's the
+        * best we can do. Writes and reads get combined.
+        */
+       [C(OP_READ)] = {
+               [C(RESULT_ACCESS)]      = { 12, CNTR_EVEN, T },
+               [C(RESULT_MISS)]        = { 12, CNTR_ODD, T },
+       },
+       [C(OP_WRITE)] = {
+               [C(RESULT_ACCESS)]      = { 12, CNTR_EVEN, T },
+               [C(RESULT_MISS)]        = { 12, CNTR_ODD, T },
        },
 },
-[C(NODE)] = {
+[C(L1I)] = {
        [C(OP_READ)] = {
-               [C(RESULT_ACCESS)]      = { UNSUPPORTED_PERF_EVENT_ID },
-               [C(RESULT_MISS)]        = { UNSUPPORTED_PERF_EVENT_ID },
+               [C(RESULT_ACCESS)]      = { 10, CNTR_EVEN, T },
+               [C(RESULT_MISS)]        = { 10, CNTR_ODD, T },
        },
        [C(OP_WRITE)] = {
-               [C(RESULT_ACCESS)]      = { UNSUPPORTED_PERF_EVENT_ID },
-               [C(RESULT_MISS)]        = { UNSUPPORTED_PERF_EVENT_ID },
+               [C(RESULT_ACCESS)]      = { 10, CNTR_EVEN, T },
+               [C(RESULT_MISS)]        = { 10, CNTR_ODD, T },
        },
        [C(OP_PREFETCH)] = {
-               [C(RESULT_ACCESS)]      = { UNSUPPORTED_PERF_EVENT_ID },
-               [C(RESULT_MISS)]        = { UNSUPPORTED_PERF_EVENT_ID },
+               [C(RESULT_ACCESS)]      = { 23, CNTR_EVEN, T },
+               /*
+                * Note that MIPS has only "hit" events countable for
+                * the prefetch operation.
+                */
+       },
+},
+[C(LL)] = {
+       [C(OP_READ)] = {
+               [C(RESULT_ACCESS)]      = { 28, CNTR_EVEN, P },
+               [C(RESULT_MISS)]        = { 28, CNTR_ODD, P },
+       },
+       [C(OP_WRITE)] = {
+               [C(RESULT_ACCESS)]      = { 28, CNTR_EVEN, P },
+               [C(RESULT_MISS)]        = { 28, CNTR_ODD, P },
+       },
+},
+[C(BPU)] = {
+       /* Using the same code for *HW_BRANCH* */
+       [C(OP_READ)] = {
+               [C(RESULT_MISS)]        = { 0x02, CNTR_ODD, T },
+       },
+       [C(OP_WRITE)] = {
+               [C(RESULT_MISS)]        = { 0x02, CNTR_ODD, T },
        },
 },
 };
@@ -1074,39 +1063,14 @@ static const struct mips_perf_event octeon_cache_map
        },
        [C(OP_WRITE)] = {
                [C(RESULT_ACCESS)]      = { 0x30, CNTR_ALL },
-               [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(L1I)] = {
        [C(OP_READ)] = {
                [C(RESULT_ACCESS)]      = { 0x18, CNTR_ALL },
-               [C(RESULT_MISS)]        = { UNSUPPORTED_PERF_EVENT_ID },
-       },
-       [C(OP_WRITE)] = {
-               [C(RESULT_ACCESS)]      = { UNSUPPORTED_PERF_EVENT_ID },
-               [C(RESULT_MISS)]        = { UNSUPPORTED_PERF_EVENT_ID },
        },
        [C(OP_PREFETCH)] = {
                [C(RESULT_ACCESS)]      = { 0x19, CNTR_ALL },
-               [C(RESULT_MISS)]        = { UNSUPPORTED_PERF_EVENT_ID },
-       },
-},
-[C(LL)] = {
-       [C(OP_READ)] = {
-               [C(RESULT_ACCESS)]      = { UNSUPPORTED_PERF_EVENT_ID },
-               [C(RESULT_MISS)]        = { UNSUPPORTED_PERF_EVENT_ID },
-       },
-       [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(DTLB)] = {
@@ -1115,46 +1079,16 @@ static const struct mips_perf_event octeon_cache_map
         * read and write.
         */
        [C(OP_READ)] = {
-               [C(RESULT_ACCESS)]      = { UNSUPPORTED_PERF_EVENT_ID },
                [C(RESULT_MISS)]        = { 0x35, CNTR_ALL },
        },
        [C(OP_WRITE)] = {
-               [C(RESULT_ACCESS)]      = { UNSUPPORTED_PERF_EVENT_ID },
                [C(RESULT_MISS)]        = { 0x35, CNTR_ALL },
        },
-       [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)]        = { 0x37, 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 },
-       },
-},
-[C(BPU)] = {
-       /* Using the same code for *HW_BRANCH* */
-       [C(OP_READ)] = {
-               [C(RESULT_ACCESS)]      = { UNSUPPORTED_PERF_EVENT_ID },
-               [C(RESULT_MISS)]        = { UNSUPPORTED_PERF_EVENT_ID },
-       },
-       [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 },
-       },
 },
 };
 
@@ -1304,7 +1238,7 @@ static int mipsxx_pmu_handle_shared_irq(void)
        int handled = IRQ_NONE;
        struct pt_regs *regs;
 
-       if (cpu_has_mips_r2 && !(read_c0_cause() & (1 << 26)))
+       if (cpu_has_perf_cntr_intr_bit && !(read_c0_cause() & CAUSEF_PCI))
                return handled;
        /*
         * First we pause the local counters, so that when we are locked
@@ -1314,7 +1248,7 @@ static int mipsxx_pmu_handle_shared_irq(void)
         * See also mipsxx_pmu_start().
         */
        pause_local_counters();
-#ifdef CONFIG_MIPS_MT_SMP
+#ifdef CONFIG_MIPS_PERF_SHARED_TC_COUNTERS
        read_lock(&pmuint_rwlock);
 #endif
 
@@ -1346,7 +1280,7 @@ static int mipsxx_pmu_handle_shared_irq(void)
        if (handled == IRQ_HANDLED)
                irq_work_run();
 
-#ifdef CONFIG_MIPS_MT_SMP
+#ifdef CONFIG_MIPS_PERF_SHARED_TC_COUNTERS
        read_unlock(&pmuint_rwlock);
 #endif
        resume_local_counters();
@@ -1391,6 +1325,11 @@ static irqreturn_t mipsxx_pmu_handle_irq(int irq, void *dev)
 #define IS_RANGE_V_1004K_EVENT(r)      ((r) == 47)
 #endif
 
+/* BMIPS5000 */
+#define IS_BOTH_COUNTERS_BMIPS5000_EVENT(b)                            \
+       ((b) == 0 || (b) == 1)
+
+
 /*
  * User can use 0-255 raw events, where 0-127 for the events of even
  * counters, and 128-255 for odd counters. Note that bit 7 is used to
@@ -1461,6 +1400,12 @@ static const struct mips_perf_event *mipsxx_pmu_map_raw_event(u64 config)
                        raw_event.range = T;
 #endif
                break;
+       case CPU_BMIPS5000:
+               if (IS_BOTH_COUNTERS_BMIPS5000_EVENT(base_id))
+                       raw_event.cntr_mask = CNTR_EVEN | CNTR_ODD;
+               else
+                       raw_event.cntr_mask =
+                               raw_id > 127 ? CNTR_ODD : CNTR_EVEN;
        }
 
        return &raw_event;
@@ -1513,7 +1458,7 @@ init_hw_perf_events(void)
                return -ENODEV;
        }
 
-#ifdef CONFIG_MIPS_MT_SMP
+#ifdef CONFIG_MIPS_PERF_SHARED_TC_COUNTERS
        cpu_has_mipsmt_pertccounters = read_c0_config7() & (1<<19);
        if (!cpu_has_mipsmt_pertccounters)
                counters = counters_total_to_per_cpu(counters);
@@ -1572,6 +1517,11 @@ init_hw_perf_events(void)
                mipspmu.cache_event_map = &octeon_cache_map;
                mipspmu.map_raw_event = octeon_pmu_map_raw_event;
                break;
+       case CPU_BMIPS5000:
+               mipspmu.name = "BMIPS5000";
+               mipspmu.general_event_map = &bmips5000_event_map;
+               mipspmu.cache_event_map = &bmips5000_cache_map;
+               break;
        default:
                pr_cont("Either hardware does not support performance "
                        "counters, or not yet implemented.\n");
index 4812c6d916e4c5af7bf36f12aa7f1cdce4ad533f..a37bc88d6ed29ad42371dc46aaa87a80dd1a7d19 100644 (file)
  * binaries.
  */
 #include <linux/compiler.h>
+#include <linux/elf.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/errno.h>
 #include <linux/ptrace.h>
+#include <linux/regset.h>
 #include <linux/smp.h>
 #include <linux/user.h>
 #include <linux/security.h>
+#include <linux/tracehook.h>
 #include <linux/audit.h>
 #include <linux/seccomp.h>
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/syscalls.h>
+
 #include <asm/byteorder.h>
 #include <asm/cpu.h>
 #include <asm/dsp.h>
@@ -36,6 +42,7 @@
 #include <asm/page.h>
 #include <asm/uaccess.h>
 #include <asm/bootinfo.h>
+#include <asm/syscall.h>
 #include <asm/reg.h>
 
 /*
@@ -254,6 +261,133 @@ int ptrace_set_watch_regs(struct task_struct *child,
        return 0;
 }
 
+/* regset get/set implementations */
+
+static int 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 = task_pt_regs(target);
+
+       return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                  regs, 0, sizeof(*regs));
+}
+
+static int gpr_set(struct task_struct *target,
+                  const struct user_regset *regset,
+                  unsigned int pos, unsigned int count,
+                  const void *kbuf, const void __user *ubuf)
+{
+       struct pt_regs newregs;
+       int ret;
+
+       ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                &newregs,
+                                0, sizeof(newregs));
+       if (ret)
+               return ret;
+
+       *task_pt_regs(target) = newregs;
+
+       return 0;
+}
+
+static int fpr_get(struct task_struct *target,
+                  const struct user_regset *regset,
+                  unsigned int pos, unsigned int count,
+                  void *kbuf, void __user *ubuf)
+{
+       return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+                                  &target->thread.fpu,
+                                  0, sizeof(elf_fpregset_t));
+       /* XXX fcr31  */
+}
+
+static int fpr_set(struct task_struct *target,
+                  const struct user_regset *regset,
+                  unsigned int pos, unsigned int count,
+                  const void *kbuf, const void __user *ubuf)
+{
+       return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
+                                 &target->thread.fpu,
+                                 0, sizeof(elf_fpregset_t));
+       /* XXX fcr31  */
+}
+
+enum mips_regset {
+       REGSET_GPR,
+       REGSET_FPR,
+};
+
+static const struct user_regset mips_regsets[] = {
+       [REGSET_GPR] = {
+               .core_note_type = NT_PRSTATUS,
+               .n              = ELF_NGREG,
+               .size           = sizeof(unsigned int),
+               .align          = sizeof(unsigned int),
+               .get            = gpr_get,
+               .set            = gpr_set,
+       },
+       [REGSET_FPR] = {
+               .core_note_type = NT_PRFPREG,
+               .n              = ELF_NFPREG,
+               .size           = sizeof(elf_fpreg_t),
+               .align          = sizeof(elf_fpreg_t),
+               .get            = fpr_get,
+               .set            = fpr_set,
+       },
+};
+
+static const struct user_regset_view user_mips_view = {
+       .name           = "mips",
+       .e_machine      = ELF_ARCH,
+       .ei_osabi       = ELF_OSABI,
+       .regsets        = mips_regsets,
+       .n              = ARRAY_SIZE(mips_regsets),
+};
+
+static const struct user_regset mips64_regsets[] = {
+       [REGSET_GPR] = {
+               .core_note_type = NT_PRSTATUS,
+               .n              = ELF_NGREG,
+               .size           = sizeof(unsigned long),
+               .align          = sizeof(unsigned long),
+               .get            = gpr_get,
+               .set            = gpr_set,
+       },
+       [REGSET_FPR] = {
+               .core_note_type = NT_PRFPREG,
+               .n              = ELF_NFPREG,
+               .size           = sizeof(elf_fpreg_t),
+               .align          = sizeof(elf_fpreg_t),
+               .get            = fpr_get,
+               .set            = fpr_set,
+       },
+};
+
+static const struct user_regset_view user_mips64_view = {
+       .name           = "mips",
+       .e_machine      = ELF_ARCH,
+       .ei_osabi       = ELF_OSABI,
+       .regsets        = mips64_regsets,
+       .n              = ARRAY_SIZE(mips_regsets),
+};
+
+const struct user_regset_view *task_user_regset_view(struct task_struct *task)
+{
+#ifdef CONFIG_32BIT
+       return &user_mips_view;
+#endif
+
+#ifdef CONFIG_MIPS32_O32
+               if (test_thread_flag(TIF_32BIT_REGS))
+                       return &user_mips_view;
+#endif
+
+       return &user_mips64_view;
+}
+
 long arch_ptrace(struct task_struct *child, long request,
                 unsigned long addr, unsigned long data)
 {
@@ -516,52 +650,35 @@ long arch_ptrace(struct task_struct *child, long request,
        return ret;
 }
 
-static inline int audit_arch(void)
-{
-       int arch = EM_MIPS;
-#ifdef CONFIG_64BIT
-       arch |=  __AUDIT_ARCH_64BIT;
-#endif
-#if defined(__LITTLE_ENDIAN)
-       arch |=  __AUDIT_ARCH_LE;
-#endif
-       return arch;
-}
-
 /*
  * Notification of system call entry/exit
  * - triggered by current->work.syscall_trace
  */
-asmlinkage void syscall_trace_enter(struct pt_regs *regs)
+asmlinkage long syscall_trace_enter(struct pt_regs *regs)
 {
-       /* do the secure computing check first */
-       secure_computing_strict(regs->regs[2]);
+       long ret = 0;
 
-       if (!(current->ptrace & PT_PTRACED))
+       /* do the secure computing check first */
+       if (secure_computing(regs->regs[2])) {
+               /* seccomp failures shouldn't expose any additional code. */
+               ret = -1;
                goto out;
+       }
 
-       if (!test_thread_flag(TIF_SYSCALL_TRACE))
-               goto out;
+       if (test_thread_flag(TIF_SYSCALL_TRACE) &&
+           tracehook_report_syscall_entry(regs))
+               ret = -1;
 
-       /* The 0x80 provides a way for the tracing parent to distinguish
-          between a syscall stop and SIGTRAP delivery */
-       ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ?
-                                0x80 : 0));
-
-       /*
-        * this isn't the same as continuing with a signal, but it will do
-        * for normal use.  strace only continues with a signal if the
-        * stopping signal is not SIGTRAP.  -brl
-        */
-       if (current->exit_code) {
-               send_sig(current->exit_code, current, 1);
-               current->exit_code = 0;
-       }
+       if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
+               trace_sys_enter(regs, regs->regs[2]);
 
-out:
-       audit_syscall_entry(audit_arch(), regs->regs[2],
+       audit_syscall_entry(__syscall_get_arch(),
+                           regs->regs[2],
                            regs->regs[4], regs->regs[5],
                            regs->regs[6], regs->regs[7]);
+
+out:
+       return ret ?: regs->regs[2];
 }
 
 /*
@@ -572,24 +689,9 @@ asmlinkage void syscall_trace_leave(struct pt_regs *regs)
 {
        audit_syscall_exit(regs);
 
-       if (!(current->ptrace & PT_PTRACED))
-               return;
-
-       if (!test_thread_flag(TIF_SYSCALL_TRACE))
-               return;
-
-       /* The 0x80 provides a way for the tracing parent to distinguish
-          between a syscall stop and SIGTRAP delivery */
-       ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ?
-                                0x80 : 0));
-
-       /*
-        * this isn't the same as continuing with a signal, but it will do
-        * for normal use.  strace only continues with a signal if the
-        * stopping signal is not SIGTRAP.  -brl
-        */
-       if (current->exit_code) {
-               send_sig(current->exit_code, current, 1);
-               current->exit_code = 0;
-       }
+       if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
+               trace_sys_exit(regs, regs->regs[2]);
+
+       if (test_thread_flag(TIF_SYSCALL_TRACE))
+               tracehook_report_syscall_exit(regs, 0);
 }
index a632bc144efa1b9ca977a582864530e33ee039cb..27439e2c0e92ca38035ac1f16652bec1e2441e08 100644 (file)
@@ -32,29 +32,64 @@ NESTED(handle_sys, PT_SIZE, sp)
        STI
        .set    at
 
-       lw      t1, PT_EPC(sp)          # skip syscall on return
+       /*
+        * We intentionally keep the kernel stack a little below the top of
+        * userspace so we don't have to do a slower byte accurate check here.
+        */
+       lw      t0, PT_R29(sp)          # get user stack pointer
+       lw      t1, TI_ADDR_LIMIT($28)
+       addu    t2, t0, 16
+       addu    t3, t0, 32
+       or      t2, t3
+       and     t2, t1
+       bltz    t2, bad_stack           # -> sp is bad
 
-       subu    v0, v0, __NR_O32_Linux  # check syscall number
-       sltiu   t0, v0, __NR_O32_Linux_syscalls + 1
-       addiu   t1, 4                   # skip to next instruction
-       sw      t1, PT_EPC(sp)
-       beqz    t0, illegal_syscall
+       /*
+        * Ok, copy the args from the luser stack to the kernel stack.
+        * t3 is the precomputed number of instruction bytes needed to
+        * load or store arguments 6-8.
+        */
 
-       sll     t0, v0, 3
-       la      t1, sys_call_table
-       addu    t1, t0
-       lw      t2, (t1)                # syscall routine
-       lw      t3, 4(t1)               # >= 0 if we need stack arguments
-       beqz    t2, illegal_syscall
+       .set    push
+       .set    noreorder
+       .set    nomacro
 
-       sw      a3, PT_R26(sp)          # save a3 for syscall restarting
-       bgez    t3, stackargs
+1:     lw      t5, 16(t0)              # argument #5 from usp
+4:     lw      t6, 20(t0)              # argument #6 from usp
+3:     lw      t7, 24(t0)              # argument #7 from usp
+2:     lw      t8, 28(t0)              # argument #8 from usp
+
+       sw      t5, 16(sp)              # argument #5 to ksp
+       sw      t6, 20(sp)              # argument #6 to ksp
+       sw      t7, 24(sp)              # argument #7 to ksp
+       sw      t8, 28(sp)              # argument #8 to ksp
+
+       .set    pop
+
+       .section __ex_table,"a"
+       PTR     1b, bad_stack
+       PTR     2b, bad_stack
+       PTR     3b, bad_stack
+       PTR     4b, bad_stack
+       .previous
+
+       lw      t0, PT_EPC(sp)          # skip syscall on return
+       addiu   t0, 4                   # skip to next instruction
+       sw      t0, PT_EPC(sp)
 
-stack_done:
        lw      t0, TI_FLAGS($28)       # syscall tracing enabled?
-       li      t1, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
+       li      t1, _TIF_WORK_SYSCALL_ENTRY
        and     t0, t1
-       bnez    t0, syscall_trace_entry # -> yes
+       bnez    t0, syscall_trace_entry
+
+syscall_call:
+       subu    v0, v0, __NR_O32_Linux  # check syscall number
+       sltiu   t0, v0, __NR_O32_Linux_syscalls + 1
+       beqz    t0, illegal_syscall
+
+       sll     t0, v0, 2
+       lw      t2, sys_call_table(t0)
+       sw      a3, PT_R26(sp)          # save a3 for syscall restarting
 
        jalr    t2                      # Do The Real Thing (TM)
 
@@ -86,83 +121,19 @@ o32_syscall_exit_work:
 
 syscall_trace_entry:
        SAVE_STATIC
-       move    s0, t2
        move    a0, sp
        jal     syscall_trace_enter
 
-       move    t0, s0
-       RESTORE_STATIC
-       lw      a0, PT_R4(sp)           # Restore argument registers
+       lw      a0, PT_R4(sp)                   # Restore argument registers
        lw      a1, PT_R5(sp)
        lw      a2, PT_R6(sp)
        lw      a3, PT_R7(sp)
-       jalr    t0
-
-       li      t0, -EMAXERRNO - 1      # error?
-       sltu    t0, t0, v0
-       sw      t0, PT_R7(sp)           # set error flag
-       beqz    t0, 1f
-
-       lw      t1, PT_R2(sp)           # syscall number
-       negu    v0                      # error
-       sw      t1, PT_R0(sp)           # save it for syscall restarting
-1:     sw      v0, PT_R2(sp)           # result
 
-       j       syscall_exit
+       bgez    v0, syscall_call
+       j       o32_syscall_exit
 
 /* ------------------------------------------------------------------------ */
 
-       /*
-        * More than four arguments.  Try to deal with it by copying the
-        * stack arguments from the user stack to the kernel stack.
-        * This Sucks (TM).
-        */
-stackargs:
-       lw      t0, PT_R29(sp)          # get old user stack pointer
-
-       /*
-        * We intentionally keep the kernel stack a little below the top of
-        * userspace so we don't have to do a slower byte accurate check here.
-        */
-       lw      t5, TI_ADDR_LIMIT($28)
-       addu    t4, t0, 32
-       and     t5, t4
-       bltz    t5, bad_stack           # -> sp is bad
-
-       /* Ok, copy the args from the luser stack to the kernel stack.
-        * t3 is the precomputed number of instruction bytes needed to
-        * load or store arguments 6-8.
-        */
-
-       la      t1, 5f                  # load up to 3 arguments
-       subu    t1, t3
-1:     lw      t5, 16(t0)              # argument #5 from usp
-       .set    push
-       .set    noreorder
-       .set    nomacro
-       jr      t1
-        addiu  t1, 6f - 5f
-
-2:     lw      t8, 28(t0)              # argument #8 from usp
-3:     lw      t7, 24(t0)              # argument #7 from usp
-4:     lw      t6, 20(t0)              # argument #6 from usp
-5:     jr      t1
-        sw     t5, 16(sp)              # argument #5 to ksp
-
-       sw      t8, 28(sp)              # argument #8 to ksp
-       sw      t7, 24(sp)              # argument #7 to ksp
-       sw      t6, 20(sp)              # argument #6 to ksp
-6:     j       stack_done              # go back
-        nop
-       .set    pop
-
-       .section __ex_table,"a"
-       PTR     1b,bad_stack
-       PTR     2b,bad_stack
-       PTR     3b,bad_stack
-       PTR     4b,bad_stack
-       .previous
-
        /*
         * The stackpointer for a call with more than 4 arguments is bad.
         * We probably should handle this case a bit more drastic.
@@ -185,18 +156,20 @@ illegal_syscall:
        j       o32_syscall_exit
        END(handle_sys)
 
-       LEAF(sys_syscall)
-       subu    t0, a0, __NR_O32_Linux  # check syscall number
+LEAF(sys_syscall)
+       subu    t0, a0, __NR_O32_Linux          # check syscall number
        sltiu   v0, t0, __NR_O32_Linux_syscalls + 1
-       beqz    t0, einval              # do not recurse
-       sll     t1, t0, 3
+       beqz    t0, einval                      # do not recurse
+       sll     t1, t0, 2
        beqz    v0, einval
        lw      t2, sys_call_table(t1)          # syscall routine
 
-       /* Some syscalls like execve get their arguments from struct pt_regs
-          and claim zero arguments in the syscall table. Thus we have to
-          assume the worst case and shuffle around all potential arguments.
-          If you want performance, don't use indirect syscalls. */
+       /*
+        * Some syscalls like execve get their arguments from struct pt_regs
+        * and claim zero arguments in the syscall table. Thus we have to
+        * assume the worst case and shuffle around all potential arguments.
+        * If you want performance, don't use indirect syscalls.
+        */
 
        move    a0, a1                          # shift argument registers
        move    a1, a2
@@ -220,260 +193,248 @@ einval: li      v0, -ENOSYS
        jr      ra
        END(sys_syscall)
 
-       .macro  fifty ptr, nargs, from=1, to=50
-       sys     \ptr            \nargs
-       .if     \to-\from
-       fifty   \ptr,\nargs,"(\from+1)",\to
-       .endif
-       .endm
-
-       .macro  mille ptr, nargs, from=1, to=20
-       fifty   \ptr,\nargs
-       .if     \to-\from
-       mille   \ptr,\nargs,"(\from+1)",\to
-       .endif
-       .endm
-
-       .macro  syscalltable
-       sys     sys_syscall             8       /* 4000 */
-       sys     sys_exit                1
-       sys     sys_fork                0
-       sys     sys_read                3
-       sys     sys_write               3
-       sys     sys_open                3       /* 4005 */
-       sys     sys_close               1
-       sys     sys_waitpid             3
-       sys     sys_creat               2
-       sys     sys_link                2
-       sys     sys_unlink              1       /* 4010 */
-       sys     sys_execve              0
-       sys     sys_chdir               1
-       sys     sys_time                1
-       sys     sys_mknod               3
-       sys     sys_chmod               2       /* 4015 */
-       sys     sys_lchown              3
-       sys     sys_ni_syscall          0
-       sys     sys_ni_syscall          0       /* was sys_stat */
-       sys     sys_lseek               3
-       sys     sys_getpid              0       /* 4020 */
-       sys     sys_mount               5
-       sys     sys_oldumount           1
-       sys     sys_setuid              1
-       sys     sys_getuid              0
-       sys     sys_stime               1       /* 4025 */
-       sys     sys_ptrace              4
-       sys     sys_alarm               1
-       sys     sys_ni_syscall          0       /* was sys_fstat */
-       sys     sys_pause               0
-       sys     sys_utime               2       /* 4030 */
-       sys     sys_ni_syscall          0
-       sys     sys_ni_syscall          0
-       sys     sys_access              2
-       sys     sys_nice                1
-       sys     sys_ni_syscall          0       /* 4035 */
-       sys     sys_sync                0
-       sys     sys_kill                2
-       sys     sys_rename              2
-       sys     sys_mkdir               2
-       sys     sys_rmdir               1       /* 4040 */
-       sys     sys_dup                 1
-       sys     sysm_pipe               0
-       sys     sys_times               1
-       sys     sys_ni_syscall          0
-       sys     sys_brk                 1       /* 4045 */
-       sys     sys_setgid              1
-       sys     sys_getgid              0
-       sys     sys_ni_syscall          0       /* was signal(2) */
-       sys     sys_geteuid             0
-       sys     sys_getegid             0       /* 4050 */
-       sys     sys_acct                1
-       sys     sys_umount              2
-       sys     sys_ni_syscall          0
-       sys     sys_ioctl               3
-       sys     sys_fcntl               3       /* 4055 */
-       sys     sys_ni_syscall          2
-       sys     sys_setpgid             2
-       sys     sys_ni_syscall          0
-       sys     sys_olduname            1
-       sys     sys_umask               1       /* 4060 */
-       sys     sys_chroot              1
-       sys     sys_ustat               2
-       sys     sys_dup2                2
-       sys     sys_getppid             0
-       sys     sys_getpgrp             0       /* 4065 */
-       sys     sys_setsid              0
-       sys     sys_sigaction           3
-       sys     sys_sgetmask            0
-       sys     sys_ssetmask            1
-       sys     sys_setreuid            2       /* 4070 */
-       sys     sys_setregid            2
-       sys     sys_sigsuspend          0
-       sys     sys_sigpending          1
-       sys     sys_sethostname         2
-       sys     sys_setrlimit           2       /* 4075 */
-       sys     sys_getrlimit           2
-       sys     sys_getrusage           2
-       sys     sys_gettimeofday        2
-       sys     sys_settimeofday        2
-       sys     sys_getgroups           2       /* 4080 */
-       sys     sys_setgroups           2
-       sys     sys_ni_syscall          0       /* old_select */
-       sys     sys_symlink             2
-       sys     sys_ni_syscall          0       /* was sys_lstat */
-       sys     sys_readlink            3       /* 4085 */
-       sys     sys_uselib              1
-       sys     sys_swapon              2
-       sys     sys_reboot              3
-       sys     sys_old_readdir         3
-       sys     sys_mips_mmap           6       /* 4090 */
-       sys     sys_munmap              2
-       sys     sys_truncate            2
-       sys     sys_ftruncate           2
-       sys     sys_fchmod              2
-       sys     sys_fchown              3       /* 4095 */
-       sys     sys_getpriority         2
-       sys     sys_setpriority         3
-       sys     sys_ni_syscall          0
-       sys     sys_statfs              2
-       sys     sys_fstatfs             2       /* 4100 */
-       sys     sys_ni_syscall          0       /* was ioperm(2) */
-       sys     sys_socketcall          2
-       sys     sys_syslog              3
-       sys     sys_setitimer           3
-       sys     sys_getitimer           2       /* 4105 */
-       sys     sys_newstat             2
-       sys     sys_newlstat            2
-       sys     sys_newfstat            2
-       sys     sys_uname               1
-       sys     sys_ni_syscall          0       /* 4110 was iopl(2) */
-       sys     sys_vhangup             0
-       sys     sys_ni_syscall          0       /* was sys_idle() */
-       sys     sys_ni_syscall          0       /* was sys_vm86 */
-       sys     sys_wait4               4
-       sys     sys_swapoff             1       /* 4115 */
-       sys     sys_sysinfo             1
-       sys     sys_ipc                 6
-       sys     sys_fsync               1
-       sys     sys_sigreturn           0
-       sys     sys_clone               0       /* 4120 */
-       sys     sys_setdomainname       2
-       sys     sys_newuname            1
-       sys     sys_ni_syscall          0       /* sys_modify_ldt */
-       sys     sys_adjtimex            1
-       sys     sys_mprotect            3       /* 4125 */
-       sys     sys_sigprocmask         3
-       sys     sys_ni_syscall          0       /* was create_module */
-       sys     sys_init_module         5
-       sys     sys_delete_module       1
-       sys     sys_ni_syscall          0       /* 4130 was get_kernel_syms */
-       sys     sys_quotactl            4
-       sys     sys_getpgid             1
-       sys     sys_fchdir              1
-       sys     sys_bdflush             2
-       sys     sys_sysfs               3       /* 4135 */
-       sys     sys_personality         1
-       sys     sys_ni_syscall          0       /* for afs_syscall */
-       sys     sys_setfsuid            1
-       sys     sys_setfsgid            1
-       sys     sys_llseek              5       /* 4140 */
-       sys     sys_getdents            3
-       sys     sys_select              5
-       sys     sys_flock               2
-       sys     sys_msync               3
-       sys     sys_readv               3       /* 4145 */
-       sys     sys_writev              3
-       sys     sys_cacheflush          3
-       sys     sys_cachectl            3
-       sys     sys_sysmips             4
-       sys     sys_ni_syscall          0       /* 4150 */
-       sys     sys_getsid              1
-       sys     sys_fdatasync           1
-       sys     sys_sysctl              1
-       sys     sys_mlock               2
-       sys     sys_munlock             2       /* 4155 */
-       sys     sys_mlockall            1
-       sys     sys_munlockall          0
-       sys     sys_sched_setparam      2
-       sys     sys_sched_getparam      2
-       sys     sys_sched_setscheduler  3       /* 4160 */
-       sys     sys_sched_getscheduler  1
-       sys     sys_sched_yield         0
-       sys     sys_sched_get_priority_max 1
-       sys     sys_sched_get_priority_min 1
-       sys     sys_sched_rr_get_interval 2     /* 4165 */
-       sys     sys_nanosleep,          2
-       sys     sys_mremap,             5
-       sys     sys_accept              3
-       sys     sys_bind                3
-       sys     sys_connect             3       /* 4170 */
-       sys     sys_getpeername         3
-       sys     sys_getsockname         3
-       sys     sys_getsockopt          5
-       sys     sys_listen              2
-       sys     sys_recv                4       /* 4175 */
-       sys     sys_recvfrom            6
-       sys     sys_recvmsg             3
-       sys     sys_send                4
-       sys     sys_sendmsg             3
-       sys     sys_sendto              6       /* 4180 */
-       sys     sys_setsockopt          5
-       sys     sys_shutdown            2
-       sys     sys_socket              3
-       sys     sys_socketpair          4
-       sys     sys_setresuid           3       /* 4185 */
-       sys     sys_getresuid           3
-       sys     sys_ni_syscall          0       /* was sys_query_module */
-       sys     sys_poll                3
-       sys     sys_ni_syscall          0       /* was nfsservctl */
-       sys     sys_setresgid           3       /* 4190 */
-       sys     sys_getresgid           3
-       sys     sys_prctl               5
-       sys     sys_rt_sigreturn        0
-       sys     sys_rt_sigaction        4
-       sys     sys_rt_sigprocmask      4       /* 4195 */
-       sys     sys_rt_sigpending       2
-       sys     sys_rt_sigtimedwait     4
-       sys     sys_rt_sigqueueinfo     3
-       sys     sys_rt_sigsuspend       0
-       sys     sys_pread64             6       /* 4200 */
-       sys     sys_pwrite64            6
-       sys     sys_chown               3
-       sys     sys_getcwd              2
-       sys     sys_capget              2
-       sys     sys_capset              2       /* 4205 */
-       sys     sys_sigaltstack         0
-       sys     sys_sendfile            4
-       sys     sys_ni_syscall          0
-       sys     sys_ni_syscall          0
-       sys     sys_mips_mmap2          6       /* 4210 */
-       sys     sys_truncate64          4
-       sys     sys_ftruncate64         4
-       sys     sys_stat64              2
-       sys     sys_lstat64             2
-       sys     sys_fstat64             2       /* 4215 */
-       sys     sys_pivot_root          2
-       sys     sys_mincore             3
-       sys     sys_madvise             3
-       sys     sys_getdents64          3
-       sys     sys_fcntl64             3       /* 4220 */
-       sys     sys_ni_syscall          0
-       sys     sys_gettid              0
-       sys     sys_readahead           5
-       sys     sys_setxattr            5
-       sys     sys_lsetxattr           5       /* 4225 */
-       sys     sys_fsetxattr           5
-       sys     sys_getxattr            4
-       sys     sys_lgetxattr           4
-       sys     sys_fgetxattr           4
-       sys     sys_listxattr           3       /* 4230 */
-       sys     sys_llistxattr          3
-       sys     sys_flistxattr          3
-       sys     sys_removexattr         2
-       sys     sys_lremovexattr        2
-       sys     sys_fremovexattr        2       /* 4235 */
-       sys     sys_tkill               2
-       sys     sys_sendfile64          5
-       sys     sys_futex               6
+       .align  2
+       .type   sys_call_table, @object
+EXPORT(sys_call_table)
+       PTR     sys_syscall                     /* 4000 */
+       PTR     sys_exit
+       PTR     sys_fork
+       PTR     sys_read
+       PTR     sys_write
+       PTR     sys_open                        /* 4005 */
+       PTR     sys_close
+       PTR     sys_waitpid
+       PTR     sys_creat
+       PTR     sys_link
+       PTR     sys_unlink                      /* 4010 */
+       PTR     sys_execve
+       PTR     sys_chdir
+       PTR     sys_time
+       PTR     sys_mknod
+       PTR     sys_chmod                       /* 4015 */
+       PTR     sys_lchown
+       PTR     sys_ni_syscall
+       PTR     sys_ni_syscall                  /* was sys_stat */
+       PTR     sys_lseek
+       PTR     sys_getpid                      /* 4020 */
+       PTR     sys_mount
+       PTR     sys_oldumount
+       PTR     sys_setuid
+       PTR     sys_getuid
+       PTR     sys_stime                       /* 4025 */
+       PTR     sys_ptrace
+       PTR     sys_alarm
+       PTR     sys_ni_syscall                  /* was sys_fstat */
+       PTR     sys_pause
+       PTR     sys_utime                       /* 4030 */
+       PTR     sys_ni_syscall
+       PTR     sys_ni_syscall
+       PTR     sys_access
+       PTR     sys_nice
+       PTR     sys_ni_syscall                  /* 4035 */
+       PTR     sys_sync
+       PTR     sys_kill
+       PTR     sys_rename
+       PTR     sys_mkdir
+       PTR     sys_rmdir                       /* 4040 */
+       PTR     sys_dup
+       PTR     sysm_pipe
+       PTR     sys_times
+       PTR     sys_ni_syscall
+       PTR     sys_brk                         /* 4045 */
+       PTR     sys_setgid
+       PTR     sys_getgid
+       PTR     sys_ni_syscall                  /* was signal(2) */
+       PTR     sys_geteuid
+       PTR     sys_getegid                     /* 4050 */
+       PTR     sys_acct
+       PTR     sys_umount
+       PTR     sys_ni_syscall
+       PTR     sys_ioctl
+       PTR     sys_fcntl                       /* 4055 */
+       PTR     sys_ni_syscall
+       PTR     sys_setpgid
+       PTR     sys_ni_syscall
+       PTR     sys_olduname
+       PTR     sys_umask                       /* 4060 */
+       PTR     sys_chroot
+       PTR     sys_ustat
+       PTR     sys_dup2
+       PTR     sys_getppid
+       PTR     sys_getpgrp                     /* 4065 */
+       PTR     sys_setsid
+       PTR     sys_sigaction
+       PTR     sys_sgetmask
+       PTR     sys_ssetmask
+       PTR     sys_setreuid                    /* 4070 */
+       PTR     sys_setregid
+       PTR     sys_sigsuspend
+       PTR     sys_sigpending
+       PTR     sys_sethostname
+       PTR     sys_setrlimit                   /* 4075 */
+       PTR     sys_getrlimit
+       PTR     sys_getrusage
+       PTR     sys_gettimeofday
+       PTR     sys_settimeofday
+       PTR     sys_getgroups                   /* 4080 */
+       PTR     sys_setgroups
+       PTR     sys_ni_syscall                  /* old_select */
+       PTR     sys_symlink
+       PTR     sys_ni_syscall                  /* was sys_lstat */
+       PTR     sys_readlink                    /* 4085 */
+       PTR     sys_uselib
+       PTR     sys_swapon
+       PTR     sys_reboot
+       PTR     sys_old_readdir
+       PTR     sys_mips_mmap                   /* 4090 */
+       PTR     sys_munmap
+       PTR     sys_truncate
+       PTR     sys_ftruncate
+       PTR     sys_fchmod
+       PTR     sys_fchown                      /* 4095 */
+       PTR     sys_getpriority
+       PTR     sys_setpriority
+       PTR     sys_ni_syscall
+       PTR     sys_statfs
+       PTR     sys_fstatfs                     /* 4100 */
+       PTR     sys_ni_syscall                  /* was ioperm(2) */
+       PTR     sys_socketcall
+       PTR     sys_syslog
+       PTR     sys_setitimer
+       PTR     sys_getitimer                   /* 4105 */
+       PTR     sys_newstat
+       PTR     sys_newlstat
+       PTR     sys_newfstat
+       PTR     sys_uname
+       PTR     sys_ni_syscall                  /* 4110 was iopl(2) */
+       PTR     sys_vhangup
+       PTR     sys_ni_syscall                  /* was sys_idle() */
+       PTR     sys_ni_syscall                  /* was sys_vm86 */
+       PTR     sys_wait4
+       PTR     sys_swapoff                     /* 4115 */
+       PTR     sys_sysinfo
+       PTR     sys_ipc
+       PTR     sys_fsync
+       PTR     sys_sigreturn
+       PTR     sys_clone                       /* 4120 */
+       PTR     sys_setdomainname
+       PTR     sys_newuname
+       PTR     sys_ni_syscall                  /* sys_modify_ldt */
+       PTR     sys_adjtimex
+       PTR     sys_mprotect                    /* 4125 */
+       PTR     sys_sigprocmask
+       PTR     sys_ni_syscall                  /* was create_module */
+       PTR     sys_init_module
+       PTR     sys_delete_module
+       PTR     sys_ni_syscall                  /* 4130 was get_kernel_syms */
+       PTR     sys_quotactl
+       PTR     sys_getpgid
+       PTR     sys_fchdir
+       PTR     sys_bdflush
+       PTR     sys_sysfs                       /* 4135 */
+       PTR     sys_personality
+       PTR     sys_ni_syscall                  /* for afs_syscall */
+       PTR     sys_setfsuid
+       PTR     sys_setfsgid
+       PTR     sys_llseek                      /* 4140 */
+       PTR     sys_getdents
+       PTR     sys_select
+       PTR     sys_flock
+       PTR     sys_msync
+       PTR     sys_readv                       /* 4145 */
+       PTR     sys_writev
+       PTR     sys_cacheflush
+       PTR     sys_cachectl
+       PTR     sys_sysmips
+       PTR     sys_ni_syscall                  /* 4150 */
+       PTR     sys_getsid
+       PTR     sys_fdatasync
+       PTR     sys_sysctl
+       PTR     sys_mlock
+       PTR     sys_munlock                     /* 4155 */
+       PTR     sys_mlockall
+       PTR     sys_munlockall
+       PTR     sys_sched_setparam
+       PTR     sys_sched_getparam
+       PTR     sys_sched_setscheduler          /* 4160 */
+       PTR     sys_sched_getscheduler
+       PTR     sys_sched_yield
+       PTR     sys_sched_get_priority_max
+       PTR     sys_sched_get_priority_min
+       PTR     sys_sched_rr_get_interval       /* 4165 */
+       PTR     sys_nanosleep
+       PTR     sys_mremap
+       PTR     sys_accept
+       PTR     sys_bind
+       PTR     sys_connect                     /* 4170 */
+       PTR     sys_getpeername
+       PTR     sys_getsockname
+       PTR     sys_getsockopt
+       PTR     sys_listen
+       PTR     sys_recv                        /* 4175 */
+       PTR     sys_recvfrom
+       PTR     sys_recvmsg
+       PTR     sys_send
+       PTR     sys_sendmsg
+       PTR     sys_sendto                      /* 4180 */
+       PTR     sys_setsockopt
+       PTR     sys_shutdown
+       PTR     sys_socket
+       PTR     sys_socketpair
+       PTR     sys_setresuid                   /* 4185 */
+       PTR     sys_getresuid
+       PTR     sys_ni_syscall                  /* was sys_query_module */
+       PTR     sys_poll
+       PTR     sys_ni_syscall                  /* was nfsservctl */
+       PTR     sys_setresgid                   /* 4190 */
+       PTR     sys_getresgid
+       PTR     sys_prctl
+       PTR     sys_rt_sigreturn
+       PTR     sys_rt_sigaction
+       PTR     sys_rt_sigprocmask              /* 4195 */
+       PTR     sys_rt_sigpending
+       PTR     sys_rt_sigtimedwait
+       PTR     sys_rt_sigqueueinfo
+       PTR     sys_rt_sigsuspend
+       PTR     sys_pread64                     /* 4200 */
+       PTR     sys_pwrite64
+       PTR     sys_chown
+       PTR     sys_getcwd
+       PTR     sys_capget
+       PTR     sys_capset                      /* 4205 */
+       PTR     sys_sigaltstack
+       PTR     sys_sendfile
+       PTR     sys_ni_syscall
+       PTR     sys_ni_syscall
+       PTR     sys_mips_mmap2                  /* 4210 */
+       PTR     sys_truncate64
+       PTR     sys_ftruncate64
+       PTR     sys_stat64
+       PTR     sys_lstat64
+       PTR     sys_fstat64                     /* 4215 */
+       PTR     sys_pivot_root
+       PTR     sys_mincore
+       PTR     sys_madvise
+       PTR     sys_getdents64
+       PTR     sys_fcntl64                     /* 4220 */
+       PTR     sys_ni_syscall
+       PTR     sys_gettid
+       PTR     sys_readahead
+       PTR     sys_setxattr
+       PTR     sys_lsetxattr                   /* 4225 */
+       PTR     sys_fsetxattr
+       PTR     sys_getxattr
+       PTR     sys_lgetxattr
+       PTR     sys_fgetxattr
+       PTR     sys_listxattr                   /* 4230 */
+       PTR     sys_llistxattr
+       PTR     sys_flistxattr
+       PTR     sys_removexattr
+       PTR     sys_lremovexattr
+       PTR     sys_fremovexattr                /* 4235 */
+       PTR     sys_tkill
+       PTR     sys_sendfile64
+       PTR     sys_futex
 #ifdef CONFIG_MIPS_MT_FPAFF
        /*
         * For FPU affinity scheduling on MIPS MT processors, we need to
@@ -481,130 +442,116 @@ einval: li      v0, -ENOSYS
         * in kernel/sched.c.  Considered only temporary we only support these
         * hooks for the 32-bit kernel - there is no MIPS64 MT processor atm.
         */
-       sys     mipsmt_sys_sched_setaffinity    3
-       sys     mipsmt_sys_sched_getaffinity    3
+       PTR     mipsmt_sys_sched_setaffinity
+       PTR     mipsmt_sys_sched_getaffinity
 #else
-       sys     sys_sched_setaffinity   3
-       sys     sys_sched_getaffinity   3       /* 4240 */
+       PTR     sys_sched_setaffinity
+       PTR     sys_sched_getaffinity           /* 4240 */
 #endif /* CONFIG_MIPS_MT_FPAFF */
-       sys     sys_io_setup            2
-       sys     sys_io_destroy          1
-       sys     sys_io_getevents        5
-       sys     sys_io_submit           3
-       sys     sys_io_cancel           3       /* 4245 */
-       sys     sys_exit_group          1
-       sys     sys_lookup_dcookie      4
-       sys     sys_epoll_create        1
-       sys     sys_epoll_ctl           4
-       sys     sys_epoll_wait          4       /* 4250 */
-       sys     sys_remap_file_pages    5
-       sys     sys_set_tid_address     1
-       sys     sys_restart_syscall     0
-       sys     sys_fadvise64_64        7
-       sys     sys_statfs64            3       /* 4255 */
-       sys     sys_fstatfs64           2
-       sys     sys_timer_create        3
-       sys     sys_timer_settime       4
-       sys     sys_timer_gettime       2
-       sys     sys_timer_getoverrun    1       /* 4260 */
-       sys     sys_timer_delete        1
-       sys     sys_clock_settime       2
-       sys     sys_clock_gettime       2
-       sys     sys_clock_getres        2
-       sys     sys_clock_nanosleep     4       /* 4265 */
-       sys     sys_tgkill              3
-       sys     sys_utimes              2
-       sys     sys_mbind               4
-       sys     sys_ni_syscall          0       /* sys_get_mempolicy */
-       sys     sys_ni_syscall          0       /* 4270 sys_set_mempolicy */
-       sys     sys_mq_open             4
-       sys     sys_mq_unlink           1
-       sys     sys_mq_timedsend        5
-       sys     sys_mq_timedreceive     5
-       sys     sys_mq_notify           2       /* 4275 */
-       sys     sys_mq_getsetattr       3
-       sys     sys_ni_syscall          0       /* sys_vserver */
-       sys     sys_waitid              5
-       sys     sys_ni_syscall          0       /* available, was setaltroot */
-       sys     sys_add_key             5       /* 4280 */
-       sys     sys_request_key         4
-       sys     sys_keyctl              5
-       sys     sys_set_thread_area     1
-       sys     sys_inotify_init        0
-       sys     sys_inotify_add_watch   3       /* 4285 */
-       sys     sys_inotify_rm_watch    2
-       sys     sys_migrate_pages       4
-       sys     sys_openat              4
-       sys     sys_mkdirat             3
-       sys     sys_mknodat             4       /* 4290 */
-       sys     sys_fchownat            5
-       sys     sys_futimesat           3
-       sys     sys_fstatat64           4
-       sys     sys_unlinkat            3
-       sys     sys_renameat            4       /* 4295 */
-       sys     sys_linkat              5
-       sys     sys_symlinkat           3
-       sys     sys_readlinkat          4
-       sys     sys_fchmodat            3
-       sys     sys_faccessat           3       /* 4300 */
-       sys     sys_pselect6            6
-       sys     sys_ppoll               5
-       sys     sys_unshare             1
-       sys     sys_splice              6
-       sys     sys_sync_file_range     7       /* 4305 */
-       sys     sys_tee                 4
-       sys     sys_vmsplice            4
-       sys     sys_move_pages          6
-       sys     sys_set_robust_list     2
-       sys     sys_get_robust_list     3       /* 4310 */
-       sys     sys_kexec_load          4
-       sys     sys_getcpu              3
-       sys     sys_epoll_pwait         6
-       sys     sys_ioprio_set          3
-       sys     sys_ioprio_get          2       /* 4315 */
-       sys     sys_utimensat           4
-       sys     sys_signalfd            3
-       sys     sys_ni_syscall          0       /* was timerfd */
-       sys     sys_eventfd             1
-       sys     sys_fallocate           6       /* 4320 */
-       sys     sys_timerfd_create      2
-       sys     sys_timerfd_gettime     2
-       sys     sys_timerfd_settime     4
-       sys     sys_signalfd4           4
-       sys     sys_eventfd2            2       /* 4325 */
-       sys     sys_epoll_create1       1
-       sys     sys_dup3                3
-       sys     sys_pipe2               2
-       sys     sys_inotify_init1       1
-       sys     sys_preadv              6       /* 4330 */
-       sys     sys_pwritev             6
-       sys     sys_rt_tgsigqueueinfo   4
-       sys     sys_perf_event_open     5
-       sys     sys_accept4             4
-       sys     sys_recvmmsg            5       /* 4335 */
-       sys     sys_fanotify_init       2
-       sys     sys_fanotify_mark       6
-       sys     sys_prlimit64           4
-       sys     sys_name_to_handle_at   5
-       sys     sys_open_by_handle_at   3       /* 4340 */
-       sys     sys_clock_adjtime       2
-       sys     sys_syncfs              1
-       sys     sys_sendmmsg            4
-       sys     sys_setns               2
-       sys     sys_process_vm_readv    6       /* 4345 */
-       sys     sys_process_vm_writev   6
-       .endm
-
-       /* We pre-compute the number of _instruction_ bytes needed to
-          load or store the arguments 6-8. Negative values are ignored. */
-
-       .macro  sys function, nargs
-       PTR     \function
-       LONG    (\nargs << 2) - (5 << 2)
-       .endm
-
-       .align  3
-       .type   sys_call_table,@object
-EXPORT(sys_call_table)
-       syscalltable
+       PTR     sys_io_setup
+       PTR     sys_io_destroy
+       PTR     sys_io_getevents
+       PTR     sys_io_submit
+       PTR     sys_io_cancel                   /* 4245 */
+       PTR     sys_exit_group
+       PTR     sys_lookup_dcookie
+       PTR     sys_epoll_create
+       PTR     sys_epoll_ctl
+       PTR     sys_epoll_wait                  /* 4250 */
+       PTR     sys_remap_file_pages
+       PTR     sys_set_tid_address
+       PTR     sys_restart_syscall
+       PTR     sys_fadvise64_64
+       PTR     sys_statfs64                    /* 4255 */
+       PTR     sys_fstatfs64
+       PTR     sys_timer_create
+       PTR     sys_timer_settime
+       PTR     sys_timer_gettime
+       PTR     sys_timer_getoverrun            /* 4260 */
+       PTR     sys_timer_delete
+       PTR     sys_clock_settime
+       PTR     sys_clock_gettime
+       PTR     sys_clock_getres
+       PTR     sys_clock_nanosleep             /* 4265 */
+       PTR     sys_tgkill
+       PTR     sys_utimes
+       PTR     sys_mbind
+       PTR     sys_ni_syscall                  /* sys_get_mempolicy */
+       PTR     sys_ni_syscall                  /* 4270 sys_set_mempolicy */
+       PTR     sys_mq_open
+       PTR     sys_mq_unlink
+       PTR     sys_mq_timedsend
+       PTR     sys_mq_timedreceive
+       PTR     sys_mq_notify                   /* 4275 */
+       PTR     sys_mq_getsetattr
+       PTR     sys_ni_syscall                  /* sys_vserver */
+       PTR     sys_waitid
+       PTR     sys_ni_syscall                  /* available, was setaltroot */
+       PTR     sys_add_key                     /* 4280 */
+       PTR     sys_request_key
+       PTR     sys_keyctl
+       PTR     sys_set_thread_area
+       PTR     sys_inotify_init
+       PTR     sys_inotify_add_watch           /* 4285 */
+       PTR     sys_inotify_rm_watch
+       PTR     sys_migrate_pages
+       PTR     sys_openat
+       PTR     sys_mkdirat
+       PTR     sys_mknodat                     /* 4290 */
+       PTR     sys_fchownat
+       PTR     sys_futimesat
+       PTR     sys_fstatat64
+       PTR     sys_unlinkat
+       PTR     sys_renameat                    /* 4295 */
+       PTR     sys_linkat
+       PTR     sys_symlinkat
+       PTR     sys_readlinkat
+       PTR     sys_fchmodat
+       PTR     sys_faccessat                   /* 4300 */
+       PTR     sys_pselect6
+       PTR     sys_ppoll
+       PTR     sys_unshare
+       PTR     sys_splice
+       PTR     sys_sync_file_range             /* 4305 */
+       PTR     sys_tee
+       PTR     sys_vmsplice
+       PTR     sys_move_pages
+       PTR     sys_set_robust_list
+       PTR     sys_get_robust_list             /* 4310 */
+       PTR     sys_kexec_load
+       PTR     sys_getcpu
+       PTR     sys_epoll_pwait
+       PTR     sys_ioprio_set
+       PTR     sys_ioprio_get                  /* 4315 */
+       PTR     sys_utimensat
+       PTR     sys_signalfd
+       PTR     sys_ni_syscall                  /* was timerfd */
+       PTR     sys_eventfd
+       PTR     sys_fallocate                   /* 4320 */
+       PTR     sys_timerfd_create
+       PTR     sys_timerfd_gettime
+       PTR     sys_timerfd_settime
+       PTR     sys_signalfd4
+       PTR     sys_eventfd2                    /* 4325 */
+       PTR     sys_epoll_create1
+       PTR     sys_dup3
+       PTR     sys_pipe2
+       PTR     sys_inotify_init1
+       PTR     sys_preadv                      /* 4330 */
+       PTR     sys_pwritev
+       PTR     sys_rt_tgsigqueueinfo
+       PTR     sys_perf_event_open
+       PTR     sys_accept4
+       PTR     sys_recvmmsg                    /* 4335 */
+       PTR     sys_fanotify_init
+       PTR     sys_fanotify_mark
+       PTR     sys_prlimit64
+       PTR     sys_name_to_handle_at
+       PTR     sys_open_by_handle_at           /* 4340 */
+       PTR     sys_clock_adjtime
+       PTR     sys_syncfs
+       PTR     sys_sendmmsg
+       PTR     sys_setns
+       PTR     sys_process_vm_readv            /* 4345 */
+       PTR     sys_process_vm_writev
        .size   sys_call_table, . - sys_call_table
index 3b5a5e9ae49c132640c95a87037e48ac95e5b932..2abde76f0d6b7c0b662312bff420acf2c17a13e7 100644 (file)
@@ -39,26 +39,26 @@ NESTED(handle_sys64, PT_SIZE, sp)
        .set    at
 #endif
 
-       dsubu   t0, v0, __NR_64_Linux   # check syscall number
-       sltiu   t0, t0, __NR_64_Linux_syscalls + 1
 #if !defined(CONFIG_MIPS32_O32) && !defined(CONFIG_MIPS32_N32)
        ld      t1, PT_EPC(sp)          # skip syscall on return
        daddiu  t1, 4                   # skip to next instruction
        sd      t1, PT_EPC(sp)
 #endif
+
+       LONG_L  t0, TI_FLAGS($28)       # syscall tracing enabled?
+       li      t1, _TIF_WORK_SYSCALL_ENTRY
+       and     t0, t1
+       bnez    t0, syscall_trace_entry
+
+syscall_call:
+       dsubu   v0, v0, __NR_64_Linux   # check syscall number
+       sltiu   t0, v0, __NR_64_Linux_syscalls + 1
        beqz    t0, illegal_syscall
 
        dsll    t0, v0, 3               # offset into table
-       ld      t2, (sys_call_table - (__NR_64_Linux * 8))(t0)
-                                       # syscall routine
-
+       ld      t2, sys_call_table(t0)  # syscall routine
        sd      a3, PT_R26(sp)          # save a3 for syscall restarting
 
-       li      t1, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
-       LONG_L  t0, TI_FLAGS($28)       # syscall tracing enabled?
-       and     t0, t1, t0
-       bnez    t0, syscall_trace_entry
-
        jalr    t2                      # Do The Real Thing (TM)
 
        li      t0, -EMAXERRNO - 1      # error?
@@ -89,30 +89,17 @@ n64_syscall_exit_work:
 
 syscall_trace_entry:
        SAVE_STATIC
-       move    s0, t2
        move    a0, sp
        jal     syscall_trace_enter
 
-       move    t0, s0
-       RESTORE_STATIC
-       ld      a0, PT_R4(sp)           # Restore argument registers
+       ld      a0, PT_R4(sp)                   # Restore argument registers
        ld      a1, PT_R5(sp)
        ld      a2, PT_R6(sp)
        ld      a3, PT_R7(sp)
        ld      a4, PT_R8(sp)
        ld      a5, PT_R9(sp)
-       jalr    t0
-
-       li      t0, -EMAXERRNO - 1      # error?
-       sltu    t0, t0, v0
-       sd      t0, PT_R7(sp)           # set error flag
-       beqz    t0, 1f
-
-       ld      t1, PT_R2(sp)           # syscall number
-       dnegu   v0                      # error
-       sd      t1, PT_R0(sp)           # save it for syscall restarting
-1:     sd      v0, PT_R2(sp)           # result
 
+       bgez    v0, syscall_call
        j       syscall_exit
 
 illegal_syscall:
@@ -125,7 +112,8 @@ illegal_syscall:
        END(handle_sys64)
 
        .align  3
-sys_call_table:
+       .type   sys_call_table, @object
+EXPORT(sys_call_table)
        PTR     sys_read                        /* 5000 */
        PTR     sys_write
        PTR     sys_open
index 6be6f7020923f1224260a0bf4df420a2d951db7a..c8fc4dd1f531de2b3880bd23367a63babbd438af 100644 (file)
 #include <asm/thread_info.h>
 #include <asm/unistd.h>
 
-/* This duplicates the definition from <linux/sched.h> */
-#define PT_TRACESYS    0x00000002      /* tracing system calls */
-
-/* This duplicates the definition from <asm/signal.h> */
-#define SIGILL         4               /* Illegal instruction (ANSI).  */
-
 #ifndef CONFIG_MIPS32_O32
 /* No O32, so define handle_sys here */
 #define handle_sysn32 handle_sys
@@ -38,26 +32,25 @@ NESTED(handle_sysn32, PT_SIZE, sp)
        .set    at
 #endif
 
-       dsubu   t0, v0, __NR_N32_Linux  # check syscall number
-       sltiu   t0, t0, __NR_N32_Linux_syscalls + 1
-
 #ifndef CONFIG_MIPS32_O32
        ld      t1, PT_EPC(sp)          # skip syscall on return
        daddiu  t1, 4                   # skip to next instruction
        sd      t1, PT_EPC(sp)
 #endif
+       LONG_L  t0, TI_FLAGS($28)       # syscall tracing enabled?
+       li      t1, _TIF_WORK_SYSCALL_ENTRY
+       and     t0, t1
+       bnez    t0, syscall_trace_entry
+
+syscall_call:
+       dsubu   v0, v0, __NR_N32_Linux  # check syscall number
+       sltiu   t0, v0, __NR_N32_Linux_syscalls + 1
        beqz    t0, not_n32_scall
 
        dsll    t0, v0, 3               # offset into table
-       ld      t2, (sysn32_call_table - (__NR_N32_Linux * 8))(t0)
-
+       ld      t2, sysn32_call_table(t0) # syscall routine
        sd      a3, PT_R26(sp)          # save a3 for syscall restarting
 
-       li      t1, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
-       LONG_L  t0, TI_FLAGS($28)       # syscall tracing enabled?
-       and     t0, t1, t0
-       bnez    t0, n32_syscall_trace_entry
-
        jalr    t2                      # Do The Real Thing (TM)
 
        li      t0, -EMAXERRNO - 1      # error?
@@ -85,9 +78,8 @@ n32_syscall_exit_work:
 
 /* ------------------------------------------------------------------------ */
 
-n32_syscall_trace_entry:
+syscall_trace_entry:
        SAVE_STATIC
-       move    s0, t2
        move    a0, sp
        jal     syscall_trace_enter
 
@@ -99,27 +91,21 @@ n32_syscall_trace_entry:
        ld      a3, PT_R7(sp)
        ld      a4, PT_R8(sp)
        ld      a5, PT_R9(sp)
-       jalr    t0
-
-       li      t0, -EMAXERRNO - 1      # error?
-       sltu    t0, t0, v0
-       sd      t0, PT_R7(sp)           # set error flag
-       beqz    t0, 1f
-
-       ld      t1, PT_R2(sp)           # syscall number
-       dnegu   v0                      # error
-       sd      t1, PT_R0(sp)           # save it for syscall restarting
-1:     sd      v0, PT_R2(sp)           # result
+       ld      a5, PT_R10(sp)
 
+       bgez    v0, syscall_call
        j       syscall_exit
 
 not_n32_scall:
-       /* This is not an n32 compatibility syscall, pass it on to
-          the n64 syscall handlers.  */
+       /*
+        * This is not an N32 compatibility syscall, pass it on to
+        * the n64 syscall handlers.
+        */
        j       handle_sys64
 
        END(handle_sysn32)
 
+       .type   sysn32_call_table, @object
 EXPORT(sysn32_call_table)
        PTR     sys_read                        /* 6000 */
        PTR     sys_write
index 54228553691d60903559706c00bc8a0d16a05b86..3aa4f13608684ffe64ee08cd7054c438ec7ee783 100644 (file)
@@ -32,31 +32,24 @@ NESTED(handle_sys, PT_SIZE, sp)
        STI
        .set    at
        ld      t1, PT_EPC(sp)          # skip syscall on return
-
-       dsubu   t0, v0, __NR_O32_Linux  # check syscall number
-       sltiu   t0, t0, __NR_O32_Linux_syscalls + 1
        daddiu  t1, 4                   # skip to next instruction
        sd      t1, PT_EPC(sp)
-       beqz    t0, not_o32_scall
-#if 0
- SAVE_ALL
- move a1, v0
- PRINT("Scall %ld\n")
- RESTORE_ALL
-#endif
 
-       /* We don't want to stumble over broken sign extensions from
-          userland. O32 does never use the upper half. */
+       LONG_L  t0, TI_FLAGS($28)       # syscall tracing enabled?
+       li      t1, _TIF_WORK_SYSCALL_ENTRY
+       and     t0, t1
+       bnez    t0, syscall_trace_entry
+
+syscall_call:
+       /*
+        * We don't want to stumble over broken sign extensions from
+        * userland. O32 does never use the upper half.
+        */
        sll     a0, a0, 0
        sll     a1, a1, 0
        sll     a2, a2, 0
        sll     a3, a3, 0
 
-       dsll    t0, v0, 3               # offset into table
-       ld      t2, (sys_call_table - (__NR_O32_Linux * 8))(t0)
-
-       sd      a3, PT_R26(sp)          # save a3 for syscall restarting
-
        /*
         * More than four arguments.  Try to deal with it by copying the
         * stack arguments from the user stack to the kernel stack.
@@ -81,10 +74,20 @@ NESTED(handle_sys, PT_SIZE, sp)
        PTR     4b, bad_stack
        .previous
 
-       li      t1, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
-       LONG_L  t0, TI_FLAGS($28)       # syscall tracing enabled?
-       and     t0, t1, t0
-       bnez    t0, trace_a_syscall
+#if 0
+ SAVE_ALL
+ move a1, v0
+ PRINT("Scall %ld\n")
+ RESTORE_ALL
+#endif
+
+       dsubu   v0, v0, __NR_O32_Linux  # check syscall number
+       sltiu   t0, v0, __NR_O32_Linux_syscalls + 1
+       beqz    t0, not_o32_scall
+
+       dsll    t0, v0, 3               # offset into table
+       ld      t2, sys32_call_table(t0) # syscall routine
+       sd      a3, PT_R26(sp)          # save a3 for syscall restarting
 
        jalr    t2                      # Do The Real Thing (TM)
 
@@ -114,18 +117,12 @@ o32_syscall_exit_work:
 
 /* ------------------------------------------------------------------------ */
 
-trace_a_syscall:
+syscall_trace_entry:
        SAVE_STATIC
-       sd      a4, PT_R8(sp)           # Save argument registers
-       sd      a5, PT_R9(sp)
-       sd      a6, PT_R10(sp)
-       sd      a7, PT_R11(sp)          # For indirect syscalls
-
-       move    s0, t2                  # Save syscall pointer
        move    a0, sp
        jal     syscall_trace_enter
 
-       move    t0, s0
+       sw      a6, PT_R10(sp)
        RESTORE_STATIC
        ld      a0, PT_R4(sp)           # Restore argument registers
        ld      a1, PT_R5(sp)
@@ -133,26 +130,15 @@ trace_a_syscall:
        ld      a3, PT_R7(sp)
        ld      a4, PT_R8(sp)
        ld      a5, PT_R9(sp)
-       ld      a6, PT_R10(sp)
-       ld      a7, PT_R11(sp)          # For indirect syscalls
-       jalr    t0
-
-       li      t0, -EMAXERRNO - 1      # error?
-       sltu    t0, t0, v0
-       sd      t0, PT_R7(sp)           # set error flag
-       beqz    t0, 1f
-
-       ld      t1, PT_R2(sp)           # syscall number
-       dnegu   v0                      # error
-       sd      t1, PT_R0(sp)           # save it for syscall restarting
-1:     sd      v0, PT_R2(sp)           # result
+       ld      a6, PT_R10(sp)          # For indirect syscalls
 
+       bgez    v0, syscall_call
        j       syscall_exit
 
 /* ------------------------------------------------------------------------ */
 
        /*
-        * The stackpointer for a call with more than 4 arguments is bad.
+        * The stackpointer for arguments 5..8 is bad.
         */
 bad_stack:
        li      v0, EFAULT
@@ -163,7 +149,7 @@ bad_stack:
 
 not_o32_scall:
        /*
-        * This is not an o32 compatibility syscall, pass it on
+        * This is not an O32 compatibility syscall, pass it on
         * to the 64-bit syscall handlers.
         */
 #ifdef CONFIG_MIPS32_N32
@@ -179,7 +165,7 @@ LEAF(sys32_syscall)
        beqz    t0, einval              # do not recurse
        dsll    t1, t0, 3
        beqz    v0, einval
-       ld      t2, sys_call_table(t1)          # syscall routine
+       ld      t2, sys32_call_table(t1)# syscall routine
 
        move    a0, a1                  # shift argument registers
        move    a1, a2
@@ -201,8 +187,8 @@ einval:     li      v0, -ENOSYS
        END(sys32_syscall)
 
        .align  3
-       .type   sys_call_table,@object
-sys_call_table:
+       .type   sys32_call_table,@object
+EXPORT(sys32_call_table)
        PTR     sys32_syscall                   /* 4000 */
        PTR     sys_exit
        PTR     sys_fork
@@ -550,4 +536,4 @@ sys_call_table:
        PTR     sys_setns
        PTR     compat_sys_process_vm_readv     /* 4345 */
        PTR     compat_sys_process_vm_writev
-       .size   sys_call_table,.-sys_call_table
+       .size   sys32_call_table,.-sys32_call_table
index 31637d8c87381f04b02bcae714e8b2165952fc9c..9005bf9fb859552101d7e68638adc73ba4978ee7 100644 (file)
@@ -130,7 +130,7 @@ asmlinkage __cpuinit void start_secondary(void)
 
        cpu_set(cpu, cpu_callin_map);
 
-       synchronise_count_slave();
+       synchronise_count_slave(cpu);
 
        /*
         * irq will be enabled in ->smp_finish(), enabling it too early
@@ -173,7 +173,6 @@ void smp_send_stop(void)
 void __init smp_cpus_done(unsigned int max_cpus)
 {
        mp_ops->cpus_done();
-       synchronise_count_master();
 }
 
 /* called from main before smp_init() */
@@ -206,6 +205,7 @@ int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *tidle)
        while (!cpu_isset(cpu, cpu_callin_map))
                udelay(100);
 
+       synchronise_count_master(cpu);
        return 0;
 }
 
index 842d55e411fd396479b611ba0a1c0c2af2d4cb92..7f1eca3858def1845dc98dd1264206be19159b01 100644 (file)
@@ -28,12 +28,11 @@ static atomic_t __cpuinitdata count_reference = ATOMIC_INIT(0);
 #define COUNTON        100
 #define NR_LOOPS 5
 
-void __cpuinit synchronise_count_master(void)
+void __cpuinit synchronise_count_master(int cpu)
 {
        int i;
        unsigned long flags;
        unsigned int initcount;
-       int nslaves;
 
 #ifdef CONFIG_MIPS_MT_SMTC
        /*
@@ -43,8 +42,7 @@ void __cpuinit synchronise_count_master(void)
        return;
 #endif
 
-       printk(KERN_INFO "Synchronize counters across %u CPUs: ",
-              num_online_cpus());
+       printk(KERN_INFO "Synchronize counters for CPU %u: ", cpu);
 
        local_irq_save(flags);
 
@@ -52,7 +50,7 @@ void __cpuinit synchronise_count_master(void)
         * Notify the slaves that it's time to start
         */
        atomic_set(&count_reference, read_c0_count());
-       atomic_set(&count_start_flag, 1);
+       atomic_set(&count_start_flag, cpu);
        smp_wmb();
 
        /* Count will be initialised to current timer for all CPU's */
@@ -69,10 +67,9 @@ void __cpuinit synchronise_count_master(void)
         * two CPUs.
         */
 
-       nslaves = num_online_cpus()-1;
        for (i = 0; i < NR_LOOPS; i++) {
-               /* slaves loop on '!= ncpus' */
-               while (atomic_read(&count_count_start) != nslaves)
+               /* slaves loop on '!= 2' */
+               while (atomic_read(&count_count_start) != 1)
                        mb();
                atomic_set(&count_count_stop, 0);
                smp_wmb();
@@ -89,7 +86,7 @@ void __cpuinit synchronise_count_master(void)
                /*
                 * Wait for all slaves to leave the synchronization point:
                 */
-               while (atomic_read(&count_count_stop) != nslaves)
+               while (atomic_read(&count_count_stop) != 1)
                        mb();
                atomic_set(&count_count_start, 0);
                smp_wmb();
@@ -97,6 +94,7 @@ void __cpuinit synchronise_count_master(void)
        }
        /* Arrange for an interrupt in a short while */
        write_c0_compare(read_c0_count() + COUNTON);
+       atomic_set(&count_start_flag, 0);
 
        local_irq_restore(flags);
 
@@ -108,11 +106,10 @@ void __cpuinit synchronise_count_master(void)
        printk("done.\n");
 }
 
-void __cpuinit synchronise_count_slave(void)
+void __cpuinit synchronise_count_slave(int cpu)
 {
        int i;
        unsigned int initcount;
-       int ncpus;
 
 #ifdef CONFIG_MIPS_MT_SMTC
        /*
@@ -127,16 +124,15 @@ void __cpuinit synchronise_count_slave(void)
         * so we first wait for the master to say everyone is ready
         */
 
-       while (!atomic_read(&count_start_flag))
+       while (atomic_read(&count_start_flag) != cpu)
                mb();
 
        /* Count will be initialised to next expire for all CPU's */
        initcount = atomic_read(&count_reference);
 
-       ncpus = num_online_cpus();
        for (i = 0; i < NR_LOOPS; i++) {
                atomic_inc(&count_count_start);
-               while (atomic_read(&count_count_start) != ncpus)
+               while (atomic_read(&count_count_start) != 2)
                        mb();
 
                /*
@@ -146,7 +142,7 @@ void __cpuinit synchronise_count_slave(void)
                        write_c0_count(initcount);
 
                atomic_inc(&count_count_stop);
-               while (atomic_read(&count_count_stop) != ncpus)
+               while (atomic_read(&count_count_stop) != 2)
                        mb();
        }
        /* Arrange for an interrupt in a short while */
index df243a64f4305305564ec1e1e5b7f68c4c6e55ad..007ccbe1e26474a6788ef61ee046e226c480d877 100644 (file)
@@ -1,6 +1,13 @@
 #include <asm/asm-offsets.h>
 #include <asm/page.h>
 #include <asm/thread_info.h>
+
+/*
+ * Put .bss..swapper_pg_dir as the first thing in .bss. This will
+ * ensure that it has .bss alignment (64K).
+ */
+#define BSS_FIRST_SECTIONS *(.bss..swapper_pg_dir)
+
 #include <asm-generic/vmlinux.lds.h>
 
 #undef mips
@@ -119,11 +126,21 @@ SECTIONS
        }
 
        PERCPU_SECTION(1 << CONFIG_MIPS_L1_CACHE_SHIFT)
-       . = ALIGN(PAGE_SIZE);
+       /*
+        * Align to 64K in attempt to eliminate holes before the
+        * .bss..swapper_pg_dir section at the start of .bss.  This
+        * also satisfies PAGE_SIZE alignment as the largest page size
+        * allowed is 64K.
+        */
+       . = ALIGN(0x10000);
        __init_end = .;
        /* freed after init ends here */
 
-       BSS_SECTION(0, 0, 0)
+       /*
+        * Force .bss to 64K alignment so that .bss..swapper_pg_dir
+        * gets that alignment.  .sbss should be empty, so there will be
+        * no holes after __init_end. */
+       BSS_SECTION(0, 0x10000, 0)
 
        _end = . ;
 
index befbb760ab766aee198df2dfd2ff66d0bd1832d3..79887aff48da48617ae18c8cff69722beefef6d0 100644 (file)
 /* power status register */
 #define PWDSR(x) ((x) ? (PMU_PWDSR1) : (PMU_PWDSR))
 
+/* pci delay is 6 bit wide and 18 bit into the register*/
+#define PCI_DLY_MASK    0x3f
+#define PCI_DLY_SHIFT   18
+
 /* clock gates that we can en/disable */
 #define PMU_USB0_P     BIT(0)
 #define PMU_PCI                BIT(4)
@@ -258,6 +262,16 @@ static void clkdev_add_pci(void)
        clkdev_add(&clk_ext->cl);
 }
 
+/* allow PCI driver to specify the clock delay. This is a 6 bit value */
+void ltq_pci_set_delay(u8 delay)
+{
+       u32 val = ltq_cgu_r32(pcicr);
+
+       val &= ~(PCI_DLY_MASK << PCI_DLY_SHIFT);
+       val |= ((u32)(delay & PCI_DLY_MASK)) << PCI_DLY_SHIFT;
+       ltq_cgu_w32(val, pcicr);
+}
+
 /* xway socs can generate clocks on gpio pins */
 static unsigned long valid_clkout_rates[4][5] = {
        {CLOCK_32_768K, CLOCK_1_536M, CLOCK_2_5M, CLOCK_12M, 0},
index 1a85ba92eb5c274aaf7d96020bc34b6d7338ea27..be9acb2b959d4d125752dd564b1c3c0831b7e458 100644 (file)
@@ -469,19 +469,20 @@ void __init_refok free_initmem(void)
 #ifndef CONFIG_MIPS_PGD_C0_CONTEXT
 unsigned long pgd_current[NR_CPUS];
 #endif
-/*
- * On 64-bit we've got three-level pagetables with a slightly
- * different layout ...
- */
-#define __page_aligned(order) __attribute__((__aligned__(PAGE_SIZE<<order)))
 
 /*
  * gcc 3.3 and older have trouble determining that PTRS_PER_PGD and PGD_ORDER
  * are constants.  So we use the variants from asm-offset.h until that gcc
  * will officially be retired.
+ *
+ * Align swapper_pg_dir in to 64K, allows its address to be loaded
+ * with a single LUI instruction in the TLB handlers.  If we used
+ * __aligned(64K), its size would get rounded up to the alignment
+ * size, and waste space.  So we place it in its own section and align
+ * it in the linker script.
  */
-pgd_t swapper_pg_dir[_PTRS_PER_PGD] __page_aligned(_PGD_ORDER);
+pgd_t swapper_pg_dir[_PTRS_PER_PGD] __section(.bss..swapper_pg_dir);
 #ifndef __PAGETABLE_PMD_FOLDED
-pmd_t invalid_pmd_table[PTRS_PER_PMD] __page_aligned(PMD_ORDER);
+pmd_t invalid_pmd_table[PTRS_PER_PMD] __page_aligned_bss;
 #endif
-pte_t invalid_pte_table[PTRS_PER_PTE] __page_aligned(PTE_ORDER);
+pte_t invalid_pte_table[PTRS_PER_PTE] __page_aligned_bss;
index 075d87acd12ac4158e090b7918250e958f0d8c05..dae4349e374e51fd2f5c61432ff4327e85dd106a 100644 (file)
@@ -98,7 +98,7 @@ static inline u32 ltq_calc_bar11mask(void)
 static int __devinit ltq_pci_startup(struct platform_device *pdev)
 {
        struct device_node *node = pdev->dev.of_node;
-       const __be32 *req_mask, *bus_clk;
+       const __be32 *req_mask, *bus_clk, *delay;
        u32 temp_buffer;
 
        /* get our clocks */
@@ -127,6 +127,11 @@ static int __devinit ltq_pci_startup(struct platform_device *pdev)
        else
                clk_disable(clk_external);
 
+       /* pci ckl delay is a 6 bit value */
+       delay = of_get_property(node, "lantiq,delay", NULL);
+       if (delay)
+               ltq_pci_set_delay(*delay);
+
        /* setup reset gpio used by pci */
        reset_gpio = of_get_named_gpio(node, "gpio-reset", 0);
        if (gpio_is_valid(reset_gpio))
index 5cfb086b39034417208a3efd4a708c5835c91db7..aa03f2e13385fe5083a50b17ae6f8c02e3ccb269 100644 (file)
@@ -8,6 +8,7 @@ config MN10300
        select HAVE_ARCH_KGDB
        select HAVE_NMI_WATCHDOG if MN10300_WD_TIMER
        select GENERIC_CLOCKEVENTS
+       select MODULES_USE_ELF_RELA
 
 config AM33_2
        def_bool n
index 5d7057d01494a69f2dc4a1bfdb69fd7754d1ea93..6571103b051811c1e7e25a6ab7319d82f5209c49 100644 (file)
 #ifndef _ASM_MODULE_H
 #define _ASM_MODULE_H
 
-struct mod_arch_specific {
-};
-
-#define Elf_Shdr       Elf32_Shdr
-#define Elf_Sym                Elf32_Sym
-#define Elf_Ehdr       Elf32_Ehdr
+#include <asm-generic/module.h>
 
 /*
  * Include the MN10300 architecture version.
index 49765b53f6374709943a1c1a5d17b46cad1846fb..05f2ba41ff1aadd52634a136b0f4450bba2970cc 100644 (file)
@@ -21,6 +21,7 @@ config OPENRISC
        select GENERIC_CLOCKEVENTS
        select GENERIC_STRNCPY_FROM_USER
        select GENERIC_STRNLEN_USER
+       select MODULES_USE_ELF_RELA
 
 config MMU
        def_bool y
index 3ff21b536f28f6c1e84b06b665e6d7589579f6c9..166d9911bc836e3c6de518fada2d4dcb27d35638 100644 (file)
@@ -19,6 +19,8 @@ config PARISC
        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
 
        help
          The PA-RISC microprocessor is designed by Hewlett-Packard and used
index 6c6defc24619fbab673b6296387c1dead503158b..af9cf30ed47430720ffb4736378336ee04edc9fa 100644 (file)
@@ -141,7 +141,7 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u)
 
 #define atomic_sub_and_test(i,v)       (atomic_sub_return((i),(v)) == 0)
 
-#define ATOMIC_INIT(i) ((atomic_t) { (i) })
+#define ATOMIC_INIT(i) { (i) }
 
 #define smp_mb__before_atomic_dec()    smp_mb()
 #define smp_mb__after_atomic_dec()     smp_mb()
@@ -150,7 +150,7 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u)
 
 #ifdef CONFIG_64BIT
 
-#define ATOMIC64_INIT(i) ((atomic64_t) { (i) })
+#define ATOMIC64_INIT(i) { (i) }
 
 static __inline__ s64
 __atomic64_add_return(s64 i, atomic64_t *v)
index 1f4123427ea09c9c80c5b25c0cbb40fea5ca754a..bab37e99168a64324043f009481884338e7ea263 100644 (file)
@@ -1,21 +1,11 @@
 #ifndef _ASM_PARISC_MODULE_H
 #define _ASM_PARISC_MODULE_H
+
+#include <asm-generic/module.h>
+
 /*
  * This file contains the parisc architecture specific module code.
  */
-#ifdef CONFIG_64BIT
-#define Elf_Shdr Elf64_Shdr
-#define Elf_Sym Elf64_Sym
-#define Elf_Ehdr Elf64_Ehdr
-#define Elf_Addr Elf64_Addr
-#define Elf_Rela Elf64_Rela
-#else
-#define Elf_Shdr Elf32_Shdr
-#define Elf_Sym Elf32_Sym
-#define Elf_Ehdr Elf32_Ehdr
-#define Elf_Addr Elf32_Addr
-#define Elf_Rela Elf32_Rela
-#endif
 
 struct unwind_table;
 
index 47341aa208f2b417ac2c31aabc292fadcbf008ab..88238638aee67a7c6bf84cdc23756806c16a5d77 100644 (file)
@@ -202,6 +202,7 @@ static int __init pdc_console_tty_driver_init(void)
        pdc_console_tty_driver->flags = TTY_DRIVER_REAL_RAW |
                TTY_DRIVER_RESET_TERMIOS;
        tty_set_operations(pdc_console_tty_driver, &pdc_console_tty_ops);
+       tty_port_link_device(&tty_port, pdc_console_tty_driver, 0);
 
        err = tty_register_driver(pdc_console_tty_driver);
        if (err) {
index d4b94b395c1641f6a3c88bf9b50795b36e86d09f..2c05a9292a81cb1138a28af59216eef1d829c421 100644 (file)
@@ -309,7 +309,7 @@ copy_thread(unsigned long clone_flags, unsigned long usp,
                cregs->ksp = (unsigned long)stack
                        + (pregs->gr[21] & (THREAD_SIZE - 1));
                cregs->gr[30] = usp;
-               if (p->personality == PER_HPUX) {
+               if (personality(p->personality) == PER_HPUX) {
 #ifdef CONFIG_HPUX
                        cregs->kpc = (unsigned long) &hpux_child_return;
 #else
index c9b932260f4713969cc8df8c51a9813110fb622f..7426e40699bdbf08575d0b69722e6594a1535076 100644 (file)
@@ -225,12 +225,12 @@ long parisc_personality(unsigned long personality)
        long err;
 
        if (personality(current->personality) == PER_LINUX32
-           && personality == PER_LINUX)
-               personality = PER_LINUX32;
+           && personality(personality) == PER_LINUX)
+               personality = (personality & ~PER_MASK) | PER_LINUX32;
 
        err = sys_personality(personality);
-       if (err == PER_LINUX32)
-               err = PER_LINUX;
+       if (personality(err) == PER_LINUX32)
+               err = (err & ~PER_MASK) | PER_LINUX;
 
        return err;
 }
index 352f416269ce245c515e25e0cc5cbcf5a446d2a6..58088dd71e671be8185a5b4c4eab67df18330ae5 100644 (file)
@@ -139,6 +139,8 @@ config PPC
        select GENERIC_CLOCKEVENTS
        select GENERIC_STRNCPY_FROM_USER
        select GENERIC_STRNLEN_USER
+       select HAVE_MOD_ARCH_SPECIFIC
+       select MODULES_USE_ELF_RELA
 
 config EARLY_PRINTK
        bool
@@ -215,7 +217,8 @@ config ARCH_HIBERNATION_POSSIBLE
 config ARCH_SUSPEND_POSSIBLE
        def_bool y
        depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx || \
-                  (PPC_85xx && !SMP) || PPC_86xx || PPC_PSERIES || 44x || 40x
+                  (PPC_85xx && !PPC_E500MC) || PPC_86xx || PPC_PSERIES \
+                  || 44x || 40x
 
 config PPC_DCR_NATIVE
        bool
@@ -325,7 +328,8 @@ config SWIOTLB
 
 config HOTPLUG_CPU
        bool "Support for enabling/disabling CPUs"
-       depends on SMP && HOTPLUG && EXPERIMENTAL && (PPC_PSERIES || PPC_PMAC || PPC_POWERNV)
+       depends on SMP && HOTPLUG && EXPERIMENTAL && (PPC_PSERIES || \
+       PPC_PMAC || PPC_POWERNV || (PPC_85xx && !PPC_E500MC))
        ---help---
          Say Y here to be able to disable and re-enable individual
          CPUs at runtime on SMP machines.
diff --git a/arch/powerpc/boot/dts/fsl/e500mc_power_isa.dtsi b/arch/powerpc/boot/dts/fsl/e500mc_power_isa.dtsi
new file mode 100644 (file)
index 0000000..870c653
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * e500mc Power ISA Device Tree Source (include)
+ *
+ * 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.
+ */
+
+/ {
+       cpus {
+               power-isa-version = "2.06";
+               power-isa-b;            // Base
+               power-isa-e;            // Embedded
+               power-isa-atb;          // Alternate Time Base
+               power-isa-cs;           // Cache Specification
+               power-isa-ds;           // Decorated Storage
+               power-isa-e.ed;         // Embedded.Enhanced Debug
+               power-isa-e.pd;         // Embedded.External PID
+               power-isa-e.hv;         // Embedded.Hypervisor
+               power-isa-e.le;         // Embedded.Little-Endian
+               power-isa-e.pm;         // Embedded.Performance Monitor
+               power-isa-e.pc;         // Embedded.Processor Control
+               power-isa-ecl;          // Embedded Cache Locking
+               power-isa-exp;          // External Proxy
+               power-isa-fp;           // Floating Point
+               power-isa-fp.r;         // Floating Point.Record
+               power-isa-mmc;          // Memory Coherence
+               power-isa-scpm;         // Store Conditional Page Mobility
+               power-isa-wt;           // Wait
+               mmu-type = "power-embedded";
+       };
+};
diff --git a/arch/powerpc/boot/dts/fsl/e500v2_power_isa.dtsi b/arch/powerpc/boot/dts/fsl/e500v2_power_isa.dtsi
new file mode 100644 (file)
index 0000000..f492814
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * e500v2 Power ISA Device Tree Source (include)
+ *
+ * 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.
+ */
+
+/ {
+       cpus {
+               power-isa-version = "2.03";
+               power-isa-b;            // Base
+               power-isa-e;            // Embedded
+               power-isa-atb;          // Alternate Time Base
+               power-isa-cs;           // Cache Specification
+               power-isa-e.le;         // Embedded.Little-Endian
+               power-isa-e.pm;         // Embedded.Performance Monitor
+               power-isa-ecl;          // Embedded Cache Locking
+               power-isa-mmc;          // Memory Coherence
+               power-isa-sp;           // Signal Processing Engine
+               power-isa-sp.fd;        // SPE.Embedded Float Scalar Double
+               power-isa-sp.fs;        // SPE.Embedded Float Scalar Single
+               power-isa-sp.fv;        // SPE.Embedded Float Vector
+               mmu-type = "power-embedded";
+       };
+};
diff --git a/arch/powerpc/boot/dts/fsl/e5500_power_isa.dtsi b/arch/powerpc/boot/dts/fsl/e5500_power_isa.dtsi
new file mode 100644 (file)
index 0000000..3230212
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * e5500 Power ISA Device Tree Source (include)
+ *
+ * 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.
+ */
+
+/ {
+       cpus {
+               power-isa-version = "2.06";
+               power-isa-b;            // Base
+               power-isa-e;            // Embedded
+               power-isa-atb;          // Alternate Time Base
+               power-isa-cs;           // Cache Specification
+               power-isa-ds;           // Decorated Storage
+               power-isa-e.ed;         // Embedded.Enhanced Debug
+               power-isa-e.pd;         // Embedded.External PID
+               power-isa-e.hv;         // Embedded.Hypervisor
+               power-isa-e.le;         // Embedded.Little-Endian
+               power-isa-e.pm;         // Embedded.Performance Monitor
+               power-isa-e.pc;         // Embedded.Processor Control
+               power-isa-ecl;          // Embedded Cache Locking
+               power-isa-exp;          // External Proxy
+               power-isa-fp;           // Floating Point
+               power-isa-fp.r;         // Floating Point.Record
+               power-isa-mmc;          // Memory Coherence
+               power-isa-scpm;         // Store Conditional Page Mobility
+               power-isa-wt;           // Wait
+               power-isa-64;           // 64-bit
+               mmu-type = "power-embedded";
+       };
+};
index 7de45a784df6ab28b05f474979faac5d9db7fc4e..152906f98a0fc1c21df225a305e640d0b37429e3 100644 (file)
@@ -33,6 +33,9 @@
  */
 
 /dts-v1/;
+
+/include/ "e500v2_power_isa.dtsi"
+
 / {
        compatible = "fsl,MPC8536";
        #address-cells = <2>;
index 8777f9239d9edee6440fb258b6e230990ab38d52..5a69bafb652a760d97f6c78bfd684119ec756e4a 100644 (file)
@@ -33,6 +33,9 @@
  */
 
 /dts-v1/;
+
+/include/ "e500v2_power_isa.dtsi"
+
 / {
        compatible = "fsl,MPC8544";
        #address-cells = <2>;
index 720422d83529092fd9237e8b4b1992522e9d6faa..fc1ce977422bddda2c29a0077cafc157a06b395d 100644 (file)
@@ -33,6 +33,9 @@
  */
 
 /dts-v1/;
+
+/include/ "e500v2_power_isa.dtsi"
+
 / {
        compatible = "fsl,MPC8548";
        #address-cells = <2>;
index eacd62c5fe6c2372b30790a330713b182d3377a8..122ca3bd0b03ccf23220c4be655c86957ff7b9a8 100644 (file)
@@ -33,6 +33,9 @@
  */
 
 /dts-v1/;
+
+/include/ "e500v2_power_isa.dtsi"
+
 / {
        compatible = "fsl,MPC8568";
        #address-cells = <2>;
index b07064d1193084fd8cc6b5097d82c240057987df..2cd15a2a04228459b1f1bc2087659ff8aa47cde9 100644 (file)
@@ -33,6 +33,9 @@
  */
 
 /dts-v1/;
+
+/include/ "e500v2_power_isa.dtsi"
+
 / {
        compatible = "fsl,MPC8569";
        #address-cells = <2>;
index ca188326c2ca9bef36c9ffcc3acb8dcb23c49f50..28c2a862be96e77c92abff3d688a1d116c53c352 100644 (file)
@@ -33,6 +33,9 @@
  */
 
 /dts-v1/;
+
+/include/ "e500v2_power_isa.dtsi"
+
 / {
        compatible = "fsl,MPC8572";
        #address-cells = <2>;
index 7354a8f90ea5059d2ccbed0148b754c776bb5b7c..6e76f9b282a10908f7205048b977c2c08287943d 100644 (file)
@@ -33,6 +33,9 @@
  */
 
 /dts-v1/;
+
+/include/ "e500v2_power_isa.dtsi"
+
 / {
        compatible = "fsl,P1010";
        #address-cells = <2>;
index 6f0376e554ebe3a144495d2a7202c200bff2c189..fed9c4c8d9623b3fd4040799f300bdafe90c368a 100644 (file)
@@ -33,6 +33,9 @@
  */
 
 /dts-v1/;
+
+/include/ "e500v2_power_isa.dtsi"
+
 / {
        compatible = "fsl,P1020";
        #address-cells = <2>;
index 4abd54bc33084f4ef9b493c7f77cca6d3007952e..36161b5001762dc78cc42be19613fe5ab83ccdf3 100644 (file)
@@ -33,6 +33,9 @@
  */
 
 /dts-v1/;
+
+/include/ "e500v2_power_isa.dtsi"
+
 / {
        compatible = "fsl,P1021";
        #address-cells = <2>;
index e930f4f7ca89979973239e609eb74e8e44c088ce..1956dea040cca30a980ccdc4490766631135bb6f 100644 (file)
@@ -33,6 +33,9 @@
  */
 
 /dts-v1/;
+
+/include/ "e500v2_power_isa.dtsi"
+
 / {
        compatible = "fsl,P1022";
        #address-cells = <2>;
index ac45f6d93385916984f55f26e28c83404e816e17..132a1521921a3ae3db6d90fcf2bd8bf5bd716cbe 100644 (file)
@@ -33,6 +33,9 @@
  */
 
 /dts-v1/;
+
+/include/ "e500v2_power_isa.dtsi"
+
 / {
        compatible = "fsl,P1023";
        #address-cells = <2>;
index 3213288641d1a8ddff7572b3311b34a3ca2ea6be..42bf3c6d25ca350a67f6a7d74db4613c242faa3a 100644 (file)
@@ -33,6 +33,9 @@
  */
 
 /dts-v1/;
+
+/include/ "e500v2_power_isa.dtsi"
+
 / {
        compatible = "fsl,P2020";
        #address-cells = <2>;
index 2d0a40d6b10f9c4df2345aaf11fa699ea4f1462b..7a2697d04549535e74d5b78924c90e2bf193cef5 100644 (file)
@@ -33,6 +33,9 @@
  */
 
 /dts-v1/;
+
+/include/ "e500mc_power_isa.dtsi"
+
 / {
        compatible = "fsl,P2041";
        #address-cells = <2>;
index 136def3536b6caf9ca4c30d804859262f00241a2..c9ca2c305cfecff64052e084d44b35af7ff02ce1 100644 (file)
@@ -33,6 +33,9 @@
  */
 
 /dts-v1/;
+
+/include/ "e500mc_power_isa.dtsi"
+
 / {
        compatible = "fsl,P3041";
        #address-cells = <2>;
index 8d35d2c1f694772ae733fc4d20c0d1fad683948a..4f9c9f682ecfe14b074869b7e93e79fa74326026 100644 (file)
 /include/ "qoriq-duart-1.dtsi"
 /include/ "qoriq-gpio-0.dtsi"
 /include/ "qoriq-usb2-mph-0.dtsi"
+       usb@210000 {
+               compatible = "fsl-usb2-mph-v1.6", "fsl,mpc85xx-usb2-mph", "fsl-usb2-mph";
+               port0;
+       };
 /include/ "qoriq-usb2-dr-0.dtsi"
+       usb@211000 {
+               compatible = "fsl-usb2-dr-v1.6", "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr";
+       };
 /include/ "qoriq-sec4.0-0.dtsi"
 };
index b9556ee3a63975a57e17ad0c90d168dc622e2a37..493d9a056b5caceffbc58c80baf38a2fec8c2f25 100644 (file)
@@ -33,6 +33,9 @@
  */
 
 /dts-v1/;
+
+/include/ "e500mc_power_isa.dtsi"
+
 / {
        compatible = "fsl,P4080";
        #address-cells = <2>;
index ae823a47584eccf5d931e3c67780b784062d7924..0a198b0a77e53a3447600c8180f897a4790b9cf7 100644 (file)
@@ -33,6 +33,9 @@
  */
 
 /dts-v1/;
+
+/include/ "e5500_power_isa.dtsi"
+
 / {
        compatible = "fsl,P5020";
        #address-cells = <2>;
diff --git a/arch/powerpc/boot/dts/fsl/p5040si-post.dtsi b/arch/powerpc/boot/dts/fsl/p5040si-post.dtsi
new file mode 100644 (file)
index 0000000..db2c9a7
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ * P5040 Silicon/SoC Device Tree Source (post include)
+ *
+ * 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.
+ */
+
+&lbc {
+       compatible = "fsl,p5040-elbc", "fsl,elbc", "simple-bus";
+       interrupts = <25 2 0 0>;
+       #address-cells = <2>;
+       #size-cells = <1>;
+};
+
+/* controller at 0x200000 */
+&pci0 {
+       compatible = "fsl,p5040-pcie", "fsl,qoriq-pcie-v2.4";
+       device_type = "pci";
+       #size-cells = <2>;
+       #address-cells = <3>;
+       bus-range = <0x0 0xff>;
+       clock-frequency = <33333333>;
+       interrupts = <16 2 1 15>;
+       pcie@0 {
+               reg = <0 0 0 0 0>;
+               #interrupt-cells = <1>;
+               #size-cells = <2>;
+               #address-cells = <3>;
+               device_type = "pci";
+               interrupts = <16 2 1 15>;
+               interrupt-map-mask = <0xf800 0 0 7>;
+               interrupt-map = <
+                       /* IDSEL 0x0 */
+                       0000 0 0 1 &mpic 40 1 0 0
+                       0000 0 0 2 &mpic 1 1 0 0
+                       0000 0 0 3 &mpic 2 1 0 0
+                       0000 0 0 4 &mpic 3 1 0 0
+                       >;
+       };
+};
+
+/* controller at 0x201000 */
+&pci1 {
+       compatible = "fsl,p5040-pcie", "fsl,qoriq-pcie-v2.4";
+       device_type = "pci";
+       #size-cells = <2>;
+       #address-cells = <3>;
+       bus-range = <0 0xff>;
+       clock-frequency = <33333333>;
+       interrupts = <16 2 1 14>;
+       pcie@0 {
+               reg = <0 0 0 0 0>;
+               #interrupt-cells = <1>;
+               #size-cells = <2>;
+               #address-cells = <3>;
+               device_type = "pci";
+               interrupts = <16 2 1 14>;
+               interrupt-map-mask = <0xf800 0 0 7>;
+               interrupt-map = <
+                       /* IDSEL 0x0 */
+                       0000 0 0 1 &mpic 41 1 0 0
+                       0000 0 0 2 &mpic 5 1 0 0
+                       0000 0 0 3 &mpic 6 1 0 0
+                       0000 0 0 4 &mpic 7 1 0 0
+                       >;
+       };
+};
+
+/* controller at 0x202000 */
+&pci2 {
+       compatible = "fsl,p5040-pcie", "fsl,qoriq-pcie-v2.4";
+       device_type = "pci";
+       #size-cells = <2>;
+       #address-cells = <3>;
+       bus-range = <0x0 0xff>;
+       clock-frequency = <33333333>;
+       interrupts = <16 2 1 13>;
+       pcie@0 {
+               reg = <0 0 0 0 0>;
+               #interrupt-cells = <1>;
+               #size-cells = <2>;
+               #address-cells = <3>;
+               device_type = "pci";
+               interrupts = <16 2 1 13>;
+               interrupt-map-mask = <0xf800 0 0 7>;
+               interrupt-map = <
+                       /* IDSEL 0x0 */
+                       0000 0 0 1 &mpic 42 1 0 0
+                       0000 0 0 2 &mpic 9 1 0 0
+                       0000 0 0 3 &mpic 10 1 0 0
+                       0000 0 0 4 &mpic 11 1 0 0
+                       >;
+       };
+};
+
+&dcsr {
+       #address-cells = <1>;
+       #size-cells = <1>;
+       compatible = "fsl,dcsr", "simple-bus";
+
+       dcsr-epu@0 {
+               compatible = "fsl,dcsr-epu";
+               interrupts = <52 2 0 0
+                             84 2 0 0
+                             85 2 0 0>;
+               reg = <0x0 0x1000>;
+       };
+       dcsr-npc {
+               compatible = "fsl,dcsr-npc";
+               reg = <0x1000 0x1000 0x1000000 0x8000>;
+       };
+       dcsr-nxc@2000 {
+               compatible = "fsl,dcsr-nxc";
+               reg = <0x2000 0x1000>;
+       };
+       dcsr-corenet {
+               compatible = "fsl,dcsr-corenet";
+               reg = <0x8000 0x1000 0xB0000 0x1000>;
+       };
+       dcsr-dpaa@9000 {
+               compatible = "fsl,p5040-dcsr-dpaa", "fsl,dcsr-dpaa";
+               reg = <0x9000 0x1000>;
+       };
+       dcsr-ocn@11000 {
+               compatible = "fsl,p5040-dcsr-ocn", "fsl,dcsr-ocn";
+               reg = <0x11000 0x1000>;
+       };
+       dcsr-ddr@12000 {
+               compatible = "fsl,dcsr-ddr";
+               dev-handle = <&ddr1>;
+               reg = <0x12000 0x1000>;
+       };
+       dcsr-ddr@13000 {
+               compatible = "fsl,dcsr-ddr";
+               dev-handle = <&ddr2>;
+               reg = <0x13000 0x1000>;
+       };
+       dcsr-nal@18000 {
+               compatible = "fsl,p5040-dcsr-nal", "fsl,dcsr-nal";
+               reg = <0x18000 0x1000>;
+       };
+       dcsr-rcpm@22000 {
+               compatible = "fsl,p5040-dcsr-rcpm", "fsl,dcsr-rcpm";
+               reg = <0x22000 0x1000>;
+       };
+       dcsr-cpu-sb-proxy@40000 {
+               compatible = "fsl,dcsr-e5500-sb-proxy", "fsl,dcsr-cpu-sb-proxy";
+               cpu-handle = <&cpu0>;
+               reg = <0x40000 0x1000>;
+       };
+       dcsr-cpu-sb-proxy@41000 {
+               compatible = "fsl,dcsr-e5500-sb-proxy", "fsl,dcsr-cpu-sb-proxy";
+               cpu-handle = <&cpu1>;
+               reg = <0x41000 0x1000>;
+       };
+       dcsr-cpu-sb-proxy@42000 {
+               compatible = "fsl,dcsr-e5500-sb-proxy", "fsl,dcsr-cpu-sb-proxy";
+               cpu-handle = <&cpu2>;
+               reg = <0x42000 0x1000>;
+       };
+       dcsr-cpu-sb-proxy@43000 {
+               compatible = "fsl,dcsr-e5500-sb-proxy", "fsl,dcsr-cpu-sb-proxy";
+               cpu-handle = <&cpu3>;
+               reg = <0x43000 0x1000>;
+       };
+};
+
+&soc {
+       #address-cells = <1>;
+       #size-cells = <1>;
+       device_type = "soc";
+       compatible = "simple-bus";
+
+       soc-sram-error {
+               compatible = "fsl,soc-sram-error";
+               interrupts = <16 2 1 29>;
+       };
+
+       corenet-law@0 {
+               compatible = "fsl,corenet-law";
+               reg = <0x0 0x1000>;
+               fsl,num-laws = <32>;
+       };
+
+       ddr1: memory-controller@8000 {
+               compatible = "fsl,qoriq-memory-controller-v4.5", "fsl,qoriq-memory-controller";
+               reg = <0x8000 0x1000>;
+               interrupts = <16 2 1 23>;
+       };
+
+       ddr2: memory-controller@9000 {
+               compatible = "fsl,qoriq-memory-controller-v4.5","fsl,qoriq-memory-controller";
+               reg = <0x9000 0x1000>;
+               interrupts = <16 2 1 22>;
+       };
+
+       cpc: l3-cache-controller@10000 {
+               compatible = "fsl,p5040-l3-cache-controller", "fsl,p4080-l3-cache-controller", "cache";
+               reg = <0x10000 0x1000
+                      0x11000 0x1000>;
+               interrupts = <16 2 1 27
+                             16 2 1 26>;
+       };
+
+       corenet-cf@18000 {
+               compatible = "fsl,corenet-cf";
+               reg = <0x18000 0x1000>;
+               interrupts = <16 2 1 31>;
+               fsl,ccf-num-csdids = <32>;
+               fsl,ccf-num-snoopids = <32>;
+       };
+
+       iommu@20000 {
+               compatible = "fsl,pamu-v1.0", "fsl,pamu";
+               reg = <0x20000 0x5000>;
+               interrupts = <
+                       24 2 0 0
+                       16 2 1 30>;
+       };
+
+/include/ "qoriq-mpic.dtsi"
+
+       guts: global-utilities@e0000 {
+               compatible = "fsl,p5040-device-config", "fsl,qoriq-device-config-1.0";
+               reg = <0xe0000 0xe00>;
+               fsl,has-rstcr;
+               #sleep-cells = <1>;
+               fsl,liodn-bits = <12>;
+       };
+
+       pins: global-utilities@e0e00 {
+               compatible = "fsl,p5040-pin-control", "fsl,qoriq-pin-control-1.0";
+               reg = <0xe0e00 0x200>;
+               #sleep-cells = <2>;
+       };
+
+       clockgen: global-utilities@e1000 {
+               compatible = "fsl,p5040-clockgen", "fsl,qoriq-clockgen-1.0";
+               reg = <0xe1000 0x1000>;
+               clock-frequency = <0>;
+       };
+
+       rcpm: global-utilities@e2000 {
+               compatible = "fsl,p5040-rcpm", "fsl,qoriq-rcpm-1.0";
+               reg = <0xe2000 0x1000>;
+               #sleep-cells = <1>;
+       };
+
+       sfp: sfp@e8000 {
+               compatible = "fsl,p5040-sfp", "fsl,qoriq-sfp-1.0";
+               reg        = <0xe8000 0x1000>;
+       };
+
+       serdes: serdes@ea000 {
+               compatible = "fsl,p5040-serdes";
+               reg        = <0xea000 0x1000>;
+       };
+
+/include/ "qoriq-dma-0.dtsi"
+/include/ "qoriq-dma-1.dtsi"
+/include/ "qoriq-espi-0.dtsi"
+       spi@110000 {
+               fsl,espi-num-chipselects = <4>;
+       };
+
+/include/ "qoriq-esdhc-0.dtsi"
+       sdhc@114000 {
+               sdhci,auto-cmd12;
+       };
+
+/include/ "qoriq-i2c-0.dtsi"
+/include/ "qoriq-i2c-1.dtsi"
+/include/ "qoriq-duart-0.dtsi"
+/include/ "qoriq-duart-1.dtsi"
+/include/ "qoriq-gpio-0.dtsi"
+/include/ "qoriq-usb2-mph-0.dtsi"
+               usb0: usb@210000 {
+                       compatible = "fsl-usb2-mph-v1.6", "fsl,mpc85xx-usb2-mph", "fsl-usb2-mph";
+                       phy_type = "utmi";
+                       port0;
+               };
+
+/include/ "qoriq-usb2-dr-0.dtsi"
+               usb1: usb@211000 {
+                       compatible = "fsl-usb2-dr-v1.6", "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr";
+                       dr_mode = "host";
+                       phy_type = "utmi";
+               };
+
+/include/ "qoriq-sata2-0.dtsi"
+/include/ "qoriq-sata2-1.dtsi"
+/include/ "qoriq-sec5.2-0.dtsi"
+};
diff --git a/arch/powerpc/boot/dts/fsl/p5040si-pre.dtsi b/arch/powerpc/boot/dts/fsl/p5040si-pre.dtsi
new file mode 100644 (file)
index 0000000..40ca943
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * P5040 Silicon/SoC Device Tree Source (pre include)
+ *
+ * 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.
+ */
+
+/dts-v1/;
+
+/include/ "e5500_power_isa.dtsi"
+
+/ {
+       compatible = "fsl,P5040";
+       #address-cells = <2>;
+       #size-cells = <2>;
+       interrupt-parent = <&mpic>;
+
+       aliases {
+               ccsr = &soc;
+               dcsr = &dcsr;
+
+               serial0 = &serial0;
+               serial1 = &serial1;
+               serial2 = &serial2;
+               serial3 = &serial3;
+               pci0 = &pci0;
+               pci1 = &pci1;
+               pci2 = &pci2;
+               usb0 = &usb0;
+               usb1 = &usb1;
+               dma0 = &dma0;
+               dma1 = &dma1;
+               sdhc = &sdhc;
+               msi0 = &msi0;
+               msi1 = &msi1;
+               msi2 = &msi2;
+
+               crypto = &crypto;
+               sec_jr0 = &sec_jr0;
+               sec_jr1 = &sec_jr1;
+               sec_jr2 = &sec_jr2;
+               sec_jr3 = &sec_jr3;
+               rtic_a = &rtic_a;
+               rtic_b = &rtic_b;
+               rtic_c = &rtic_c;
+               rtic_d = &rtic_d;
+               sec_mon = &sec_mon;
+       };
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               cpu0: PowerPC,e5500@0 {
+                       device_type = "cpu";
+                       reg = <0>;
+                       next-level-cache = <&L2_0>;
+                       L2_0: l2-cache {
+                               next-level-cache = <&cpc>;
+                       };
+               };
+               cpu1: PowerPC,e5500@1 {
+                       device_type = "cpu";
+                       reg = <1>;
+                       next-level-cache = <&L2_1>;
+                       L2_1: l2-cache {
+                               next-level-cache = <&cpc>;
+                       };
+               };
+               cpu2: PowerPC,e5500@2 {
+                       device_type = "cpu";
+                       reg = <2>;
+                       next-level-cache = <&L2_2>;
+                       L2_2: l2-cache {
+                               next-level-cache = <&cpc>;
+                       };
+               };
+               cpu3: PowerPC,e5500@3 {
+                       device_type = "cpu";
+                       reg = <3>;
+                       next-level-cache = <&L2_3>;
+                       L2_3: l2-cache {
+                               next-level-cache = <&cpc>;
+                       };
+               };
+       };
+};
diff --git a/arch/powerpc/boot/dts/fsl/qoriq-sec5.2-0.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-sec5.2-0.dtsi
new file mode 100644 (file)
index 0000000..7b2ab8a
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * QorIQ Sec/Crypto 5.2 device tree stub [ controller @ offset 0x300000 ]
+ *
+ * Copyright 2011-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.
+ */
+
+crypto: crypto@300000 {
+       compatible = "fsl,sec-v5.2", "fsl,sec-v5.0", "fsl,sec-v4.0";
+       #address-cells = <1>;
+       #size-cells = <1>;
+       reg              = <0x300000 0x10000>;
+       ranges           = <0 0x300000 0x10000>;
+       interrupts       = <92 2 0 0>;
+
+       sec_jr0: jr@1000 {
+               compatible = "fsl,sec-v5.2-job-ring",
+                            "fsl,sec-v5.0-job-ring",
+                            "fsl,sec-v4.0-job-ring";
+               reg = <0x1000 0x1000>;
+               interrupts = <88 2 0 0>;
+       };
+
+       sec_jr1: jr@2000 {
+               compatible = "fsl,sec-v5.2-job-ring",
+                            "fsl,sec-v5.0-job-ring",
+                            "fsl,sec-v4.0-job-ring";
+               reg = <0x2000 0x1000>;
+               interrupts = <89 2 0 0>;
+       };
+
+       sec_jr2: jr@3000 {
+               compatible = "fsl,sec-v5.2-job-ring",
+                            "fsl,sec-v5.0-job-ring",
+                            "fsl,sec-v4.0-job-ring";
+               reg = <0x3000 0x1000>;
+               interrupts = <90 2 0 0>;
+       };
+
+       sec_jr3: jr@4000 {
+               compatible = "fsl,sec-v5.2-job-ring",
+                            "fsl,sec-v5.0-job-ring",
+                            "fsl,sec-v4.0-job-ring";
+               reg = <0x4000 0x1000>;
+               interrupts = <91 2 0 0>;
+       };
+
+       rtic@6000 {
+               compatible = "fsl,sec-v5.2-rtic",
+                            "fsl,sec-v5.0-rtic",
+                            "fsl,sec-v4.0-rtic";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               reg = <0x6000 0x100>;
+               ranges = <0x0 0x6100 0xe00>;
+
+               rtic_a: rtic-a@0 {
+                       compatible = "fsl,sec-v5.2-rtic-memory",
+                                    "fsl,sec-v5.0-rtic-memory",
+                                    "fsl,sec-v4.0-rtic-memory";
+                       reg = <0x00 0x20 0x100 0x80>;
+               };
+
+               rtic_b: rtic-b@20 {
+                       compatible = "fsl,sec-v5.2-rtic-memory",
+                                    "fsl,sec-v5.0-rtic-memory",
+                                    "fsl,sec-v4.0-rtic-memory";
+                       reg = <0x20 0x20 0x200 0x80>;
+               };
+
+               rtic_c: rtic-c@40 {
+                       compatible = "fsl,sec-v5.2-rtic-memory",
+                                    "fsl,sec-v5.0-rtic-memory",
+                                    "fsl,sec-v4.0-rtic-memory";
+                       reg = <0x40 0x20 0x300 0x80>;
+               };
+
+               rtic_d: rtic-d@60 {
+                       compatible = "fsl,sec-v5.2-rtic-memory",
+                                    "fsl,sec-v5.0-rtic-memory",
+                                    "fsl,sec-v4.0-rtic-memory";
+                       reg = <0x60 0x20 0x500 0x80>;
+               };
+       };
+};
+
+sec_mon: sec_mon@314000 {
+       compatible = "fsl,sec-v5.2-mon", "fsl,sec-v5.0-mon", "fsl,sec-v4.0-mon";
+       reg = <0x314000 0x1000>;
+       interrupts = <93 2 0 0>;
+};
index f99fb110c97fb2e1c329e79cd2cdec7f772c6574..2d31863accf5331112d575d6e44bc0152c6e47ab 100644 (file)
@@ -11,6 +11,8 @@
 
 /dts-v1/;
 
+/include/ "fsl/e500v2_power_isa.dtsi"
+
 / {
        model = "MPC8540ADS";
        compatible = "MPC8540ADS", "MPC85xxADS";
index 0f5e9391279964be6af6d40d1a60899e395f6894..1c03c2667373b41181552cef1c7d64a3caac6833 100644 (file)
@@ -11,6 +11,8 @@
 
 /dts-v1/;
 
+/include/ "fsl/e500v2_power_isa.dtsi"
+
 / {
        model = "MPC8541CDS";
        compatible = "MPC8541CDS", "MPC85xxCDS";
index fe10438613d686f5784e65f40a8696034d510c2f..36a7ea138c2f4a5c89e9596e8ec9fd41cb4f9f3c 100644 (file)
@@ -11,6 +11,8 @@
 
 /dts-v1/;
 
+/include/ "fsl/e500v2_power_isa.dtsi"
+
 / {
        model = "MPC8555CDS";
        compatible = "MPC8555CDS", "MPC85xxCDS";
index 6e85e1ba08514edaa63eacaec208359b6b3773bb..1a43f5a968f565c1a33787e4ae02d938758f35c1 100644 (file)
@@ -11,6 +11,8 @@
 
 /dts-v1/;
 
+/include/ "fsl/e500v2_power_isa.dtsi"
+
 / {
        model = "MPC8560ADS";
        compatible = "MPC8560ADS", "MPC85xxADS";
diff --git a/arch/powerpc/boot/dts/p1020rdb_camp_core0.dts b/arch/powerpc/boot/dts/p1020rdb_camp_core0.dts
deleted file mode 100644 (file)
index 41b4585..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * P1020 RDB  Core0 Device Tree Source in CAMP mode.
- *
- * In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache
- * can be shared, all the other devices must be assigned to one core only.
- * This dts file allows core0 to have memory, l2, i2c, spi, gpio, tdm, dma, usb,
- * eth1, eth2, sdhc, crypto, global-util, message, pci0, pci1, msi.
- *
- * Please note to add "-b 0" for core0's dts compiling.
- *
- * Copyright 2011 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 as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-
-/include/ "p1020rdb.dts"
-
-/ {
-       model = "fsl,P1020RDB";
-       compatible = "fsl,P1020RDB", "fsl,MPC85XXRDB-CAMP";
-
-       aliases {
-               ethernet1 = &enet1;
-               ethernet2 = &enet2;
-               serial0 = &serial0;
-               pci0 = &pci0;
-               pci1 = &pci1;
-       };
-
-       cpus {
-               PowerPC,P1020@1 {
-                       status = "disabled";
-               };
-       };
-
-       memory {
-               device_type = "memory";
-       };
-
-       localbus@ffe05000 {
-               status = "disabled";
-       };
-
-       soc@ffe00000 {
-               serial1: serial@4600 {
-                       status = "disabled";
-               };
-
-               enet0: ethernet@b0000 {
-                       status = "disabled";
-               };
-
-               mpic: pic@40000 {
-                       protected-sources = <
-                       42 29 30 34     /* serial1, enet0-queue-group0 */
-                       17 18 24 45     /* enet0-queue-group1, crypto */
-                       >;
-               };
-       };
-};
diff --git a/arch/powerpc/boot/dts/p1020rdb_camp_core1.dts b/arch/powerpc/boot/dts/p1020rdb_camp_core1.dts
deleted file mode 100644 (file)
index 5174538..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * P1020 RDB Core1 Device Tree Source in CAMP mode.
- *
- * In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache
- * can be shared, all the other devices must be assigned to one core only.
- * This dts allows core1 to have l2, eth0, crypto.
- *
- * Please note to add "-b 1" for core1's dts compiling.
- *
- * Copyright 2011 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 as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-
-/include/ "p1020rdb.dts"
-
-/ {
-       model = "fsl,P1020RDB";
-       compatible = "fsl,P1020RDB", "fsl,MPC85XXRDB-CAMP";
-
-       aliases {
-               ethernet0 = &enet0;
-               serial0 = &serial1;
-               };
-
-       cpus {
-               PowerPC,P1020@0 {
-                       status = "disabled";
-               };
-       };
-
-       memory {
-               device_type = "memory";
-       };
-
-       localbus@ffe05000 {
-               status = "disabled";
-       };
-
-       soc@ffe00000 {
-               ecm-law@0 {
-                       status = "disabled";
-               };
-
-               ecm@1000 {
-                       status = "disabled";
-               };
-
-               memory-controller@2000 {
-                       status = "disabled";
-               };
-
-               i2c@3000 {
-                       status = "disabled";
-               };
-
-               i2c@3100 {
-                       status = "disabled";
-               };
-
-               serial0: serial@4500 {
-                       status = "disabled";
-               };
-
-               spi@7000 {
-                       status = "disabled";
-               };
-
-               gpio: gpio-controller@f000 {
-                       status = "disabled";
-               };
-
-               dma@21300 {
-                       status = "disabled";
-               };
-
-               mdio@24000 {
-                       status = "disabled";
-               };
-
-               mdio@25000 {
-                       status = "disabled";
-               };
-
-               enet1: ethernet@b1000 {
-                       status = "disabled";
-               };
-
-               enet2: ethernet@b2000 {
-                       status = "disabled";
-               };
-
-               usb@22000 {
-                       status = "disabled";
-               };
-
-               sdhci@2e000 {
-                       status = "disabled";
-               };
-
-               mpic: pic@40000 {
-                       protected-sources = <
-                       16              /* ecm, mem, L2, pci0, pci1 */
-                       43 42 59        /* i2c, serial0, spi */
-                       47 63 62        /* gpio, tdm */
-                       20 21 22 23     /* dma */
-                       03 02           /* mdio */
-                       35 36 40        /* enet1-queue-group0 */
-                       51 52 67        /* enet1-queue-group1 */
-                       31 32 33        /* enet2-queue-group0 */
-                       25 26 27        /* enet2-queue-group1 */
-                       28 72 58        /* usb, sdhci, crypto */
-                       0xb0 0xb1 0xb2  /* message */
-                       0xb3 0xb4 0xb5
-                       0xb6 0xb7
-                       0xe0 0xe1 0xe2  /* msi */
-                       0xe3 0xe4 0xe5
-                       0xe6 0xe7               /* sdhci, crypto , pci */
-                       >;
-               };
-
-               msi@41600 {
-                       status = "disabled";
-               };
-
-               global-utilities@e0000 {        //global utilities block
-                       status = "disabled";
-               };
-       };
-
-       pci0: pcie@ffe09000 {
-               status = "disabled";
-       };
-
-       pci1: pcie@ffe0a000 {
-               status = "disabled";
-       };
-};
diff --git a/arch/powerpc/boot/dts/p1022rdk.dts b/arch/powerpc/boot/dts/p1022rdk.dts
new file mode 100644 (file)
index 0000000..51d82de
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * P1022 RDK 32-bit Physical Address Map Device Tree Source
+ *
+ * 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.
+ */
+
+/include/ "fsl/p1022si-pre.dtsi"
+/ {
+       model = "fsl,P1022RDK";
+       compatible = "fsl,P1022RDK";
+
+       memory {
+               device_type = "memory";
+       };
+
+       board_lbc: lbc: localbus@ffe05000 {
+               /* The P1022 RDK does not have any localbus devices */
+               status = "disabled";
+       };
+
+       board_soc: soc: soc@ffe00000 {
+               ranges = <0x0 0x0 0xffe00000 0x100000>;
+
+               i2c@3100 {
+                       wm8960:codec@1a {
+                               compatible = "wlf,wm8960";
+                               reg = <0x1a>;
+                               /* MCLK source is a stand-alone oscillator */
+                               clock-frequency = <12288000>;
+                       };
+                       rtc@68 {
+                               compatible = "stm,m41t62";
+                               reg = <0x68>;
+                       };
+                       adt7461@4c{
+                               compatible = "adi,adt7461";
+                               reg = <0x4c>;
+                       };
+                       zl6100@21{
+                               compatible = "isil,zl6100";
+                               reg = <0x21>;
+                       };
+                       zl6100@24{
+                               compatible = "isil,zl6100";
+                               reg = <0x24>;
+                       };
+                       zl6100@26{
+                               compatible = "isil,zl6100";
+                               reg = <0x26>;
+                       };
+                       zl6100@29{
+                               compatible = "isil,zl6100";
+                               reg = <0x29>;
+                       };
+               };
+
+               spi@7000 {
+                       flash@0 {
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+                               compatible = "spansion,m25p80";
+                               reg = <0>;
+                               spi-max-frequency = <1000000>;
+                               partition@0 {
+                                       label = "full-spi-flash";
+                                       reg = <0x00000000 0x00100000>;
+                               };
+                       };
+               };
+
+               ssi@15000 {
+                       fsl,mode = "i2s-slave";
+                       codec-handle = <&wm8960>;
+               };
+
+               usb@22000 {
+                       phy_type = "ulpi";
+               };
+
+               usb@23000 {
+                       phy_type = "ulpi";
+               };
+
+               mdio@24000 {
+                       phy0: ethernet-phy@0 {
+                               interrupts = <3 1 0 0>;
+                               reg = <0x1>;
+                       };
+                       phy1: ethernet-phy@1 {
+                               interrupts = <9 1 0 0>;
+                               reg = <0x2>;
+                       };
+               };
+
+               mdio@25000 {
+                       tbi0: tbi-phy@11 {
+                               reg = <0x11>;
+                               device_type = "tbi-phy";
+                       };
+               };
+
+               ethernet@b0000 {
+                       phy-handle = <&phy0>;
+                       phy-connection-type = "rgmii-id";
+               };
+
+               ethernet@b1000 {
+                       phy-handle = <&phy1>;
+                       tbi-handle = <&tbi0>;
+                       phy-connection-type = "sgmii";
+               };
+       };
+
+       pci0: pcie@ffe09000 {
+               ranges = <0x2000000 0x0 0xe0000000 0 0xa0000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>;
+               reg = <0x0 0xffe09000 0 0x1000>;
+               pcie@0 {
+                       ranges = <0x2000000 0x0 0xe0000000
+                                 0x2000000 0x0 0xe0000000
+                                 0x0 0x20000000
+
+                                 0x1000000 0x0 0x0
+                                 0x1000000 0x0 0x0
+                                 0x0 0x100000>;
+               };
+       };
+
+       pci1: pcie@ffe0a000 {
+               ranges = <0x2000000 0x0 0xe0000000 0 0xc0000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0 0xffc20000 0x0 0x10000>;
+               reg = <0 0xffe0a000 0 0x1000>;
+               pcie@0 {
+                       ranges = <0x2000000 0x0 0xe0000000
+                                 0x2000000 0x0 0xe0000000
+                                 0x0 0x20000000
+
+                                 0x1000000 0x0 0x0
+                                 0x1000000 0x0 0x0
+                                 0x0 0x100000>;
+               };
+       };
+
+       pci2: pcie@ffe0b000 {
+               ranges = <0x2000000 0x0 0xe0000000 0 0x80000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>;
+               reg = <0 0xffe0b000 0 0x1000>;
+               pcie@0 {
+                       ranges = <0x2000000 0x0 0xe0000000
+                                 0x2000000 0x0 0xe0000000
+                                 0x0 0x20000000
+
+                                 0x1000000 0x0 0x0
+                                 0x1000000 0x0 0x0
+                                 0x0 0x100000>;
+               };
+       };
+};
+
+/include/ "fsl/p1022si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/p2020rdb_camp_core0.dts b/arch/powerpc/boot/dts/p2020rdb_camp_core0.dts
deleted file mode 100644 (file)
index 66aac86..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * P2020 RDB  Core0 Device Tree Source in CAMP mode.
- *
- * In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache
- * can be shared, all the other devices must be assigned to one core only.
- * This dts file allows core0 to have memory, l2, i2c, spi, gpio, dma1, usb,
- * eth1, eth2, sdhc, crypto, global-util, pci0.
- *
- * Copyright 2009-2011 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 as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-
-/include/ "p2020rdb.dts"
-
-/ {
-       model = "fsl,P2020RDB";
-       compatible = "fsl,P2020RDB", "fsl,MPC85XXRDB-CAMP";
-
-       cpus {
-               PowerPC,P2020@1 {
-                       status = "disabled";
-               };
-       };
-
-       localbus@ffe05000 {
-               status = "disabled";
-       };
-
-       soc@ffe00000 {
-               serial1: serial@4600 {
-                       status = "disabled";
-               };
-
-               dma@c300 {
-                       status = "disabled";
-               };
-
-               enet0: ethernet@24000 {
-                       status = "disabled";
-               };
-
-               mpic: pic@40000 {
-                       protected-sources = <
-                       42 76 77 78 79 /* serial1 , dma2 */
-                       29 30 34 26 /* enet0, pci1 */
-                       0xe0 0xe1 0xe2 0xe3 /* msi */
-                       0xe4 0xe5 0xe6 0xe7
-                       >;
-               };
-
-               msi@41600 {
-                       status = "disabled";
-               };
-       };
-
-       pci0: pcie@ffe08000 {
-               status = "disabled";
-       };
-
-       pci2: pcie@ffe0a000 {
-               status = "disabled";
-       };
-};
diff --git a/arch/powerpc/boot/dts/p2020rdb_camp_core1.dts b/arch/powerpc/boot/dts/p2020rdb_camp_core1.dts
deleted file mode 100644 (file)
index 9bd8ef4..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * P2020 RDB Core1 Device Tree Source in CAMP mode.
- *
- * In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache
- * can be shared, all the other devices must be assigned to one core only.
- * This dts allows core1 to have l2, dma2, eth0, pci1, msi.
- *
- * Please note to add "-b 1" for core1's dts compiling.
- *
- * Copyright 2009-2011 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 as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-
-/include/ "p2020rdb.dts"
-
-/ {
-       model = "fsl,P2020RDB";
-       compatible = "fsl,P2020RDB", "fsl,MPC85XXRDB-CAMP";
-
-       cpus {
-               PowerPC,P2020@0 {
-                       status = "disabled";
-               };
-       };
-
-       localbus@ffe05000 {
-               status = "disabled";
-       };
-
-       soc@ffe00000 {
-               ecm-law@0 {
-                       status = "disabled";
-               };
-
-               ecm@1000 {
-                       status = "disabled";
-               };
-
-               memory-controller@2000 {
-                       status = "disabled";
-               };
-
-               i2c@3000 {
-                       status = "disabled";
-               };
-
-               i2c@3100 {
-                       status = "disabled";
-               };
-
-               serial0: serial@4500 {
-                       status = "disabled";
-               };
-
-               spi@7000 {
-                       status = "disabled";
-               };
-
-               gpio: gpio-controller@f000 {
-                       status = "disabled";
-               };
-
-               dma@21300 {
-                       status = "disabled";
-               };
-
-               usb@22000 {
-                       status = "disabled";
-               };
-
-               mdio@24520 {
-                       status = "disabled";
-               };
-
-               mdio@25520 {
-                       status = "disabled";
-               };
-
-               mdio@26520 {
-                       status = "disabled";
-               };
-
-               enet1: ethernet@25000 {
-                       status = "disabled";
-               };
-
-               enet2: ethernet@26000 {
-                       status = "disabled";
-               };
-
-               sdhci@2e000 {
-                       status = "disabled";
-               };
-
-               crypto@30000 {
-                       status = "disabled";
-               };
-
-               mpic: pic@40000 {
-                       protected-sources = <
-                       17 18 43 42 59 47 /*ecm, mem, i2c, serial0, spi,gpio */
-                       16 20 21 22 23 28       /* L2, dma1, USB */
-                       03 35 36 40 31 32 33    /* mdio, enet1, enet2 */
-                       72 45 58 25             /* sdhci, crypto , pci */
-                       >;
-               };
-
-               global-utilities@e0000 {        //global utilities block
-                       status = "disabled";
-               };
-
-       };
-
-       pci0: pcie@ffe08000 {
-               status = "disabled";
-       };
-
-       pci1: pcie@ffe09000 {
-               status = "disabled";
-       };
-};
diff --git a/arch/powerpc/boot/dts/p5040ds.dts b/arch/powerpc/boot/dts/p5040ds.dts
new file mode 100644 (file)
index 0000000..d86bf2e
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * P5040DS Device Tree Source
+ *
+ * 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.
+ */
+
+/include/ "fsl/p5040si-pre.dtsi"
+
+/ {
+       model = "fsl,P5040DS";
+       compatible = "fsl,P5040DS";
+       #address-cells = <2>;
+       #size-cells = <2>;
+       interrupt-parent = <&mpic>;
+
+       memory {
+               device_type = "memory";
+       };
+
+       dcsr: dcsr@f00000000 {
+               ranges = <0x00000000 0xf 0x00000000 0x01008000>;
+       };
+
+       soc: soc@ffe000000 {
+               ranges = <0x00000000 0xf 0xfe000000 0x1000000>;
+               reg = <0xf 0xfe000000 0 0x00001000>;
+               spi@110000 {
+                       flash@0 {
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+                               compatible = "spansion,s25sl12801";
+                               reg = <0>;
+                               spi-max-frequency = <40000000>; /* input clock */
+                               partition@u-boot {
+                                       label = "u-boot";
+                                       reg = <0x00000000 0x00100000>;
+                               };
+                               partition@kernel {
+                                       label = "kernel";
+                                       reg = <0x00100000 0x00500000>;
+                               };
+                               partition@dtb {
+                                       label = "dtb";
+                                       reg = <0x00600000 0x00100000>;
+                               };
+                               partition@fs {
+                                       label = "file system";
+                                       reg = <0x00700000 0x00900000>;
+                               };
+                       };
+               };
+
+               i2c@118100 {
+                       eeprom@51 {
+                               compatible = "at24,24c256";
+                               reg = <0x51>;
+                       };
+                       eeprom@52 {
+                               compatible = "at24,24c256";
+                               reg = <0x52>;
+                       };
+               };
+
+               i2c@119100 {
+                       rtc@68 {
+                               compatible = "dallas,ds3232";
+                               reg = <0x68>;
+                               interrupts = <0x1 0x1 0 0>;
+                       };
+               };
+       };
+
+       lbc: localbus@ffe124000 {
+               reg = <0xf 0xfe124000 0 0x1000>;
+               ranges = <0 0 0xf 0xe8000000 0x08000000
+                         2 0 0xf 0xffa00000 0x00040000
+                         3 0 0xf 0xffdf0000 0x00008000>;
+
+               flash@0,0 {
+                       compatible = "cfi-flash";
+                       reg = <0 0 0x08000000>;
+                       bank-width = <2>;
+                       device-width = <2>;
+               };
+
+               nand@2,0 {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       compatible = "fsl,elbc-fcm-nand";
+                       reg = <0x2 0x0 0x40000>;
+
+                       partition@0 {
+                               label = "NAND U-Boot Image";
+                               reg = <0x0 0x02000000>;
+                       };
+
+                       partition@2000000 {
+                               label = "NAND Root File System";
+                               reg = <0x02000000 0x10000000>;
+                       };
+
+                       partition@12000000 {
+                               label = "NAND Compressed RFS Image";
+                               reg = <0x12000000 0x08000000>;
+                       };
+
+                       partition@1a000000 {
+                               label = "NAND Linux Kernel Image";
+                               reg = <0x1a000000 0x04000000>;
+                       };
+
+                       partition@1e000000 {
+                               label = "NAND DTB Image";
+                               reg = <0x1e000000 0x01000000>;
+                       };
+
+                       partition@1f000000 {
+                               label = "NAND Writable User area";
+                               reg = <0x1f000000 0x01000000>;
+                       };
+               };
+
+               board-control@3,0 {
+                       compatible = "fsl,p5040ds-fpga", "fsl,fpga-ngpixis";
+                       reg = <3 0 0x40>;
+               };
+       };
+
+       pci0: pcie@ffe200000 {
+               reg = <0xf 0xfe200000 0 0x1000>;
+               ranges = <0x02000000 0 0xe0000000 0xc 0x00000000 0x0 0x20000000
+                         0x01000000 0 0x00000000 0xf 0xf8000000 0x0 0x00010000>;
+               pcie@0 {
+                       ranges = <0x02000000 0 0xe0000000
+                                 0x02000000 0 0xe0000000
+                                 0 0x20000000
+
+                                 0x01000000 0 0x00000000
+                                 0x01000000 0 0x00000000
+                                 0 0x00010000>;
+               };
+       };
+
+       pci1: pcie@ffe201000 {
+               reg = <0xf 0xfe201000 0 0x1000>;
+               ranges = <0x02000000 0x0 0xe0000000 0xc 0x20000000 0x0 0x20000000
+                         0x01000000 0x0 0x00000000 0xf 0xf8010000 0x0 0x00010000>;
+               pcie@0 {
+                       ranges = <0x02000000 0 0xe0000000
+                                 0x02000000 0 0xe0000000
+                                 0 0x20000000
+
+                                 0x01000000 0 0x00000000
+                                 0x01000000 0 0x00000000
+                                 0 0x00010000>;
+               };
+       };
+
+       pci2: pcie@ffe202000 {
+               reg = <0xf 0xfe202000 0 0x1000>;
+               ranges = <0x02000000 0 0xe0000000 0xc 0x40000000 0 0x20000000
+                         0x01000000 0 0x00000000 0xf 0xf8020000 0 0x00010000>;
+               pcie@0 {
+                       ranges = <0x02000000 0 0xe0000000
+                                 0x02000000 0 0xe0000000
+                                 0 0x20000000
+
+                                 0x01000000 0 0x00000000
+                                 0x01000000 0 0x00000000
+                                 0 0x00010000>;
+               };
+       };
+};
+
+/include/ "fsl/p5040si-post.dtsi"
index cbb98c1234fdea1040292542a4ec4277e5bf76e2..3b40015d96f95dad5372b3a154734d7221d64bca 100644 (file)
@@ -25,6 +25,7 @@ CONFIG_P2041_RDB=y
 CONFIG_P3041_DS=y
 CONFIG_P4080_DS=y
 CONFIG_P5020_DS=y
+CONFIG_P5040_DS=y
 CONFIG_HIGHMEM=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
index dd89de8b0b7f59945eb656564d49d19bcf2af121..36df45bd4dfd28380b454c6462655b6dc06bb025 100644 (file)
@@ -23,6 +23,7 @@ CONFIG_MODVERSIONS=y
 CONFIG_PARTITION_ADVANCED=y
 CONFIG_MAC_PARTITION=y
 CONFIG_P5020_DS=y
+CONFIG_P5040_DS=y
 # CONFIG_PPC_OF_BOOT_TRAMPOLINE is not set
 CONFIG_BINFMT_MISC=m
 CONFIG_IRQ_ALL_CPUS=y
index 03ee911c45775410c141ab108019b278ae726d17..627c2578bdb18a89cb4f4383b277556a80487e59 100644 (file)
@@ -26,6 +26,7 @@ CONFIG_MPC85xx_DS=y
 CONFIG_MPC85xx_RDB=y
 CONFIG_P1010_RDB=y
 CONFIG_P1022_DS=y
+CONFIG_P1022_RDK=y
 CONFIG_P1023_RDS=y
 CONFIG_SOCRATES=y
 CONFIG_KSI8560=y
@@ -115,6 +116,7 @@ CONFIG_ATA=y
 CONFIG_SATA_AHCI=y
 CONFIG_SATA_FSL=y
 CONFIG_PATA_ALI=y
+CONFIG_PATA_VIA=y
 CONFIG_NETDEVICES=y
 CONFIG_DUMMY=y
 CONFIG_FS_ENET=y
index fdfa84dc908f21c318f0b0409f0604524f99a2c2..8d1c2a4d64e633ca4d25bedcce01d797cddde655 100644 (file)
@@ -28,6 +28,7 @@ CONFIG_MPC85xx_DS=y
 CONFIG_MPC85xx_RDB=y
 CONFIG_P1010_RDB=y
 CONFIG_P1022_DS=y
+CONFIG_P1022_RDK=y
 CONFIG_P1023_RDS=y
 CONFIG_SOCRATES=y
 CONFIG_KSI8560=y
index db27c82e0542e44ebab171cee08701c0424fc68d..2d9150a1c2bab41f3e240148ad10e12e13e0e165 100644 (file)
@@ -487,7 +487,8 @@ CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_LZO=m
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
-CONFIG_CRYPTO_DEV_NX=m
+CONFIG_CRYPTO_DEV_NX=y
+CONFIG_CRYPTO_DEV_NX_ENCRYPT=m
 CONFIG_VIRTUALIZATION=y
 CONFIG_KVM_BOOK3S_64=m
 CONFIG_KVM_BOOK3S_64_HV=y
index 1f65b3c9b59ae79e09f17f7e13b1f2e81448c7f2..9f4a9368f51b11a36d9c0b2d053819a294d3e6f2 100644 (file)
@@ -369,7 +369,8 @@ CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_LZO=m
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
-CONFIG_CRYPTO_DEV_NX=m
+CONFIG_CRYPTO_DEV_NX=y
+CONFIG_CRYPTO_DEV_NX_ENCRYPT=m
 CONFIG_VIRTUALIZATION=y
 CONFIG_KVM_BOOK3S_64=m
 CONFIG_KVM_BOOK3S_64_HV=y
index 7e313f1ed1832a5048770ed7ac72a169ae603541..13d6b7bf3b69818641705770fed052999389afd5 100644 (file)
@@ -34,5 +34,6 @@ header-y += termios.h
 header-y += types.h
 header-y += ucontext.h
 header-y += unistd.h
+header-y += epapr_hcalls.h
 
 generic-y += rwsem.h
index ab9e402518e84bc23ef512b8d431c6fa9775f583..b843e35122e8934d7ea902e71ef0cae36f670611 100644 (file)
@@ -30,6 +30,8 @@ extern void flush_dcache_page(struct page *page);
 #define flush_dcache_mmap_lock(mapping)                do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)      do { } while (0)
 
+extern void __flush_disable_L1(void);
+
 extern void __flush_icache_range(unsigned long, unsigned long);
 static inline void flush_icache_range(unsigned long start, unsigned long stop)
 {
index bf2c06c338719e66c20db73bf8bc8d0bb8dabc5d..b8d94459a929d6d1c74203bd40d03b6ab8bea9ab 100644 (file)
 #ifndef _EPAPR_HCALLS_H
 #define _EPAPR_HCALLS_H
 
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <asm/byteorder.h>
-
 #define EV_BYTE_CHANNEL_SEND           1
 #define EV_BYTE_CHANNEL_RECEIVE                2
 #define EV_BYTE_CHANNEL_POLL           3
@@ -88,7 +84,8 @@
 #define _EV_HCALL_TOKEN(id, num) (((id) << 16) | (num))
 #define EV_HCALL_TOKEN(hcall_num) _EV_HCALL_TOKEN(EV_EPAPR_VENDOR_ID, hcall_num)
 
-/* epapr error codes */
+/* epapr return codes */
+#define EV_SUCCESS             0
 #define EV_EPERM               1       /* Operation not permitted */
 #define EV_ENOENT              2       /*  Entry Not Found */
 #define EV_EIO                 3       /* I/O error occured */
 #define EV_UNIMPLEMENTED       12      /* Unimplemented hypercall */
 #define EV_BUFFER_OVERFLOW     13      /* Caller-supplied buffer too small */
 
+#ifndef __ASSEMBLY__
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <asm/byteorder.h>
+
 /*
  * Hypercall register clobber list
  *
@@ -193,7 +195,7 @@ static inline unsigned int ev_int_set_config(unsigned int interrupt,
        r5  = priority;
        r6  = destination;
 
-       __asm__ __volatile__ ("sc 1"
+       asm volatile("bl        epapr_hypercall_start"
                : "+r" (r11), "+r" (r3), "+r" (r4), "+r" (r5), "+r" (r6)
                : : EV_HCALL_CLOBBERS4
        );
@@ -222,7 +224,7 @@ static inline unsigned int ev_int_get_config(unsigned int interrupt,
        r11 = EV_HCALL_TOKEN(EV_INT_GET_CONFIG);
        r3 = interrupt;
 
-       __asm__ __volatile__ ("sc 1"
+       asm volatile("bl        epapr_hypercall_start"
                : "+r" (r11), "+r" (r3), "=r" (r4), "=r" (r5), "=r" (r6)
                : : EV_HCALL_CLOBBERS4
        );
@@ -252,7 +254,7 @@ static inline unsigned int ev_int_set_mask(unsigned int interrupt,
        r3 = interrupt;
        r4 = mask;
 
-       __asm__ __volatile__ ("sc 1"
+       asm volatile("bl        epapr_hypercall_start"
                : "+r" (r11), "+r" (r3), "+r" (r4)
                : : EV_HCALL_CLOBBERS2
        );
@@ -277,7 +279,7 @@ static inline unsigned int ev_int_get_mask(unsigned int interrupt,
        r11 = EV_HCALL_TOKEN(EV_INT_GET_MASK);
        r3 = interrupt;
 
-       __asm__ __volatile__ ("sc 1"
+       asm volatile("bl        epapr_hypercall_start"
                : "+r" (r11), "+r" (r3), "=r" (r4)
                : : EV_HCALL_CLOBBERS2
        );
@@ -305,7 +307,7 @@ static inline unsigned int ev_int_eoi(unsigned int interrupt)
        r11 = EV_HCALL_TOKEN(EV_INT_EOI);
        r3 = interrupt;
 
-       __asm__ __volatile__ ("sc 1"
+       asm volatile("bl        epapr_hypercall_start"
                : "+r" (r11), "+r" (r3)
                : : EV_HCALL_CLOBBERS1
        );
@@ -344,7 +346,7 @@ static inline unsigned int ev_byte_channel_send(unsigned int handle,
        r7 = be32_to_cpu(p[2]);
        r8 = be32_to_cpu(p[3]);
 
-       __asm__ __volatile__ ("sc 1"
+       asm volatile("bl        epapr_hypercall_start"
                : "+r" (r11), "+r" (r3),
                  "+r" (r4), "+r" (r5), "+r" (r6), "+r" (r7), "+r" (r8)
                : : EV_HCALL_CLOBBERS6
@@ -383,7 +385,7 @@ static inline unsigned int ev_byte_channel_receive(unsigned int handle,
        r3 = handle;
        r4 = *count;
 
-       __asm__ __volatile__ ("sc 1"
+       asm volatile("bl        epapr_hypercall_start"
                : "+r" (r11), "+r" (r3), "+r" (r4),
                  "=r" (r5), "=r" (r6), "=r" (r7), "=r" (r8)
                : : EV_HCALL_CLOBBERS6
@@ -421,7 +423,7 @@ static inline unsigned int ev_byte_channel_poll(unsigned int handle,
        r11 = EV_HCALL_TOKEN(EV_BYTE_CHANNEL_POLL);
        r3 = handle;
 
-       __asm__ __volatile__ ("sc 1"
+       asm volatile("bl        epapr_hypercall_start"
                : "+r" (r11), "+r" (r3), "=r" (r4), "=r" (r5)
                : : EV_HCALL_CLOBBERS3
        );
@@ -454,7 +456,7 @@ static inline unsigned int ev_int_iack(unsigned int handle,
        r11 = EV_HCALL_TOKEN(EV_INT_IACK);
        r3 = handle;
 
-       __asm__ __volatile__ ("sc 1"
+       asm volatile("bl        epapr_hypercall_start"
                : "+r" (r11), "+r" (r3), "=r" (r4)
                : : EV_HCALL_CLOBBERS2
        );
@@ -478,7 +480,7 @@ static inline unsigned int ev_doorbell_send(unsigned int handle)
        r11 = EV_HCALL_TOKEN(EV_DOORBELL_SEND);
        r3 = handle;
 
-       __asm__ __volatile__ ("sc 1"
+       asm volatile("bl        epapr_hypercall_start"
                : "+r" (r11), "+r" (r3)
                : : EV_HCALL_CLOBBERS1
        );
@@ -498,12 +500,12 @@ static inline unsigned int ev_idle(void)
 
        r11 = EV_HCALL_TOKEN(EV_IDLE);
 
-       __asm__ __volatile__ ("sc 1"
+       asm volatile("bl        epapr_hypercall_start"
                : "+r" (r11), "=r" (r3)
                : : EV_HCALL_CLOBBERS1
        );
 
        return r3;
 }
-
+#endif /* !__ASSEMBLY__ */
 #endif
index aa4c488589ce51b7bbdf1089db7282e69bfaccad..dd5ba2c227712c79ffb574f6ecc2232c0ba91fda 100644 (file)
@@ -48,6 +48,8 @@ struct ccsr_guts {
         __be32  dmuxcr;                /* 0x.0068 - DMA Mux Control Register */
         u8     res06c[0x70 - 0x6c];
        __be32  devdisr;        /* 0x.0070 - Device Disable Control */
+#define CCSR_GUTS_DEVDISR_TB1  0x00001000
+#define CCSR_GUTS_DEVDISR_TB0  0x00004000
        __be32  devdisr2;       /* 0x.0074 - Device Disable Control 2 */
        u8      res078[0x7c - 0x78];
        __be32  pmjcr;          /* 0x.007c - 4 Power Management Jog Control Register */
index 922d9b5fe3d5c9b9863691ffff89c3122f103b21..3abb58394da4830d9d2b61ff6397e5f3090f1c69 100644 (file)
@@ -96,7 +96,7 @@ static inline unsigned int fh_send_nmi(unsigned int vcpu_mask)
        r11 = FH_HCALL_TOKEN(FH_SEND_NMI);
        r3 = vcpu_mask;
 
-       __asm__ __volatile__ ("sc 1"
+       asm volatile("bl        epapr_hypercall_start"
                : "+r" (r11), "+r" (r3)
                : : EV_HCALL_CLOBBERS1
        );
@@ -151,7 +151,7 @@ static inline unsigned int fh_partition_get_dtprop(int handle,
        r9 = (uint32_t)propvalue_addr;
        r10 = *propvalue_len;
 
-       __asm__ __volatile__ ("sc 1"
+       asm volatile("bl        epapr_hypercall_start"
                : "+r" (r11),
                  "+r" (r3), "+r" (r4), "+r" (r5), "+r" (r6), "+r" (r7),
                  "+r" (r8), "+r" (r9), "+r" (r10)
@@ -205,7 +205,7 @@ static inline unsigned int fh_partition_set_dtprop(int handle,
        r9 = (uint32_t)propvalue_addr;
        r10 = propvalue_len;
 
-       __asm__ __volatile__ ("sc 1"
+       asm volatile("bl        epapr_hypercall_start"
                : "+r" (r11),
                  "+r" (r3), "+r" (r4), "+r" (r5), "+r" (r6), "+r" (r7),
                  "+r" (r8), "+r" (r9), "+r" (r10)
@@ -229,7 +229,7 @@ static inline unsigned int fh_partition_restart(unsigned int partition)
        r11 = FH_HCALL_TOKEN(FH_PARTITION_RESTART);
        r3 = partition;
 
-       __asm__ __volatile__ ("sc 1"
+       asm volatile("bl        epapr_hypercall_start"
                : "+r" (r11), "+r" (r3)
                : : EV_HCALL_CLOBBERS1
        );
@@ -262,7 +262,7 @@ static inline unsigned int fh_partition_get_status(unsigned int partition,
        r11 = FH_HCALL_TOKEN(FH_PARTITION_GET_STATUS);
        r3 = partition;
 
-       __asm__ __volatile__ ("sc 1"
+       asm volatile("bl        epapr_hypercall_start"
                : "+r" (r11), "+r" (r3), "=r" (r4)
                : : EV_HCALL_CLOBBERS2
        );
@@ -295,7 +295,7 @@ static inline unsigned int fh_partition_start(unsigned int partition,
        r4 = entry_point;
        r5 = load;
 
-       __asm__ __volatile__ ("sc 1"
+       asm volatile("bl        epapr_hypercall_start"
                : "+r" (r11), "+r" (r3), "+r" (r4), "+r" (r5)
                : : EV_HCALL_CLOBBERS3
        );
@@ -317,7 +317,7 @@ static inline unsigned int fh_partition_stop(unsigned int partition)
        r11 = FH_HCALL_TOKEN(FH_PARTITION_STOP);
        r3 = partition;
 
-       __asm__ __volatile__ ("sc 1"
+       asm volatile("bl        epapr_hypercall_start"
                : "+r" (r11), "+r" (r3)
                : : EV_HCALL_CLOBBERS1
        );
@@ -376,7 +376,7 @@ static inline unsigned int fh_partition_memcpy(unsigned int source,
 #endif
        r7 = count;
 
-       __asm__ __volatile__ ("sc 1"
+       asm volatile("bl        epapr_hypercall_start"
                : "+r" (r11),
                  "+r" (r3), "+r" (r4), "+r" (r5), "+r" (r6), "+r" (r7)
                : : EV_HCALL_CLOBBERS5
@@ -399,7 +399,7 @@ static inline unsigned int fh_dma_enable(unsigned int liodn)
        r11 = FH_HCALL_TOKEN(FH_DMA_ENABLE);
        r3 = liodn;
 
-       __asm__ __volatile__ ("sc 1"
+       asm volatile("bl        epapr_hypercall_start"
                : "+r" (r11), "+r" (r3)
                : : EV_HCALL_CLOBBERS1
        );
@@ -421,7 +421,7 @@ static inline unsigned int fh_dma_disable(unsigned int liodn)
        r11 = FH_HCALL_TOKEN(FH_DMA_DISABLE);
        r3 = liodn;
 
-       __asm__ __volatile__ ("sc 1"
+       asm volatile("bl        epapr_hypercall_start"
                : "+r" (r11), "+r" (r3)
                : : EV_HCALL_CLOBBERS1
        );
@@ -447,7 +447,7 @@ static inline unsigned int fh_vmpic_get_msir(unsigned int interrupt,
        r11 = FH_HCALL_TOKEN(FH_VMPIC_GET_MSIR);
        r3 = interrupt;
 
-       __asm__ __volatile__ ("sc 1"
+       asm volatile("bl        epapr_hypercall_start"
                : "+r" (r11), "+r" (r3), "=r" (r4)
                : : EV_HCALL_CLOBBERS2
        );
@@ -469,7 +469,7 @@ static inline unsigned int fh_system_reset(void)
 
        r11 = FH_HCALL_TOKEN(FH_SYSTEM_RESET);
 
-       __asm__ __volatile__ ("sc 1"
+       asm volatile("bl        epapr_hypercall_start"
                : "+r" (r11), "=r" (r3)
                : : EV_HCALL_CLOBBERS1
        );
@@ -506,7 +506,7 @@ static inline unsigned int fh_err_get_info(int queue, uint32_t *bufsize,
        r6 = addr_lo;
        r7 = peek;
 
-       __asm__ __volatile__ ("sc 1"
+       asm volatile("bl        epapr_hypercall_start"
                : "+r" (r11), "+r" (r3), "+r" (r4), "+r" (r5), "+r" (r6),
                  "+r" (r7)
                : : EV_HCALL_CLOBBERS5
@@ -542,7 +542,7 @@ static inline unsigned int fh_get_core_state(unsigned int handle,
        r3 = handle;
        r4 = vcpu;
 
-       __asm__ __volatile__ ("sc 1"
+       asm volatile("bl        epapr_hypercall_start"
                : "+r" (r11), "+r" (r3), "+r" (r4)
                : : EV_HCALL_CLOBBERS2
        );
@@ -572,7 +572,7 @@ static inline unsigned int fh_enter_nap(unsigned int handle, unsigned int vcpu)
        r3 = handle;
        r4 = vcpu;
 
-       __asm__ __volatile__ ("sc 1"
+       asm volatile("bl        epapr_hypercall_start"
                : "+r" (r11), "+r" (r3), "+r" (r4)
                : : EV_HCALL_CLOBBERS2
        );
@@ -597,7 +597,7 @@ static inline unsigned int fh_exit_nap(unsigned int handle, unsigned int vcpu)
        r3 = handle;
        r4 = vcpu;
 
-       __asm__ __volatile__ ("sc 1"
+       asm volatile("bl        epapr_hypercall_start"
                : "+r" (r11), "+r" (r3), "+r" (r4)
                : : EV_HCALL_CLOBBERS2
        );
@@ -618,7 +618,7 @@ static inline unsigned int fh_claim_device(unsigned int handle)
        r11 = FH_HCALL_TOKEN(FH_CLAIM_DEVICE);
        r3 = handle;
 
-       __asm__ __volatile__ ("sc 1"
+       asm volatile("bl        epapr_hypercall_start"
                : "+r" (r11), "+r" (r3)
                : : EV_HCALL_CLOBBERS1
        );
@@ -645,7 +645,7 @@ static inline unsigned int fh_partition_stop_dma(unsigned int handle)
        r11 = FH_HCALL_TOKEN(FH_PARTITION_STOP_DMA);
        r3 = handle;
 
-       __asm__ __volatile__ ("sc 1"
+       asm volatile("bl        epapr_hypercall_start"
                : "+r" (r11), "+r" (r3)
                : : EV_HCALL_CLOBBERS1
        );
index 1bea4d8ea6f432d3e3425752aafa156a8fe7710b..3c14202a3c84ac6d6bb1b234df0280af25f2206d 100644 (file)
@@ -221,6 +221,12 @@ struct kvm_sregs {
 
                        __u32 dbsr;     /* KVM_SREGS_E_UPDATE_DBSR */
                        __u32 dbcr[3];
+                       /*
+                        * iac/dac registers are 64bit wide, while this API
+                        * interface provides only lower 32 bits on 64 bit
+                        * processors. ONE_REG interface is added for 64bit
+                        * iac/dac registers.
+                        */
                        __u32 iac[4];
                        __u32 dac[2];
                        __u32 dvc[2];
@@ -326,5 +332,11 @@ struct kvm_book3e_206_tlb_params {
 };
 
 #define KVM_REG_PPC_HIOR       (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x1)
+#define KVM_REG_PPC_IAC1       (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x2)
+#define KVM_REG_PPC_IAC2       (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x3)
+#define KVM_REG_PPC_IAC3       (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x4)
+#define KVM_REG_PPC_IAC4       (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x5)
+#define KVM_REG_PPC_DAC1       (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x6)
+#define KVM_REG_PPC_DAC2       (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0x7)
 
 #endif /* __LINUX_KVM_POWERPC_H */
index 50ea12fd7bf5eeab23e6fc1bccafdf4dbe2ad89b..f20a5ef1c7e8cf4aeb39b2a45980bc7ec699482b 100644 (file)
@@ -33,6 +33,7 @@
 #include <asm/kvm_asm.h>
 #include <asm/processor.h>
 #include <asm/page.h>
+#include <asm/cacheflush.h>
 
 #define KVM_MAX_VCPUS          NR_CPUS
 #define KVM_MAX_VCORES         NR_CPUS
 #define KVM_COALESCED_MMIO_PAGE_OFFSET 1
 #endif
 
-#ifdef CONFIG_KVM_BOOK3S_64_HV
+#if !defined(CONFIG_KVM_440)
 #include <linux/mmu_notifier.h>
 
 #define KVM_ARCH_WANT_MMU_NOTIFIER
 
 struct kvm;
 extern int kvm_unmap_hva(struct kvm *kvm, unsigned long hva);
+extern int kvm_unmap_hva_range(struct kvm *kvm,
+                              unsigned long start, unsigned long end);
 extern int kvm_age_hva(struct kvm *kvm, unsigned long hva);
 extern int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
 extern void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
@@ -219,6 +222,7 @@ struct revmap_entry {
 #define KVMPPC_GOT_PAGE                0x80
 
 struct kvm_arch_memory_slot {
+       unsigned long *rmap;
 };
 
 struct kvm_arch {
@@ -342,6 +346,27 @@ struct kvmppc_slb {
        bool class      : 1;
 };
 
+# ifdef CONFIG_PPC_FSL_BOOK3E
+#define KVMPPC_BOOKE_IAC_NUM   2
+#define KVMPPC_BOOKE_DAC_NUM   2
+# else
+#define KVMPPC_BOOKE_IAC_NUM   4
+#define KVMPPC_BOOKE_DAC_NUM   2
+# endif
+#define KVMPPC_BOOKE_MAX_IAC   4
+#define KVMPPC_BOOKE_MAX_DAC   2
+
+struct kvmppc_booke_debug_reg {
+       u32 dbcr0;
+       u32 dbcr1;
+       u32 dbcr2;
+#ifdef CONFIG_KVM_E500MC
+       u32 dbcr4;
+#endif
+       u64 iac[KVMPPC_BOOKE_MAX_IAC];
+       u64 dac[KVMPPC_BOOKE_MAX_DAC];
+};
+
 struct kvm_vcpu_arch {
        ulong host_stack;
        u32 host_pid;
@@ -436,8 +461,6 @@ struct kvm_vcpu_arch {
 
        u32 ccr0;
        u32 ccr1;
-       u32 dbcr0;
-       u32 dbcr1;
        u32 dbsr;
 
        u64 mmcr[3];
@@ -467,9 +490,12 @@ struct kvm_vcpu_arch {
        ulong fault_esr;
        ulong queued_dear;
        ulong queued_esr;
+       spinlock_t wdt_lock;
+       struct timer_list wdt_timer;
        u32 tlbcfg[4];
        u32 mmucfg;
        u32 epr;
+       struct kvmppc_booke_debug_reg dbg_reg;
 #endif
        gpa_t paddr_accessed;
        gva_t vaddr_accessed;
@@ -482,6 +508,7 @@ struct kvm_vcpu_arch {
        u8 osi_needed;
        u8 osi_enabled;
        u8 papr_enabled;
+       u8 watchdog_enabled;
        u8 sane;
        u8 cpu_type;
        u8 hcall_needed;
index c18916bff689af6719c015458b930bf51ec257ce..a168ce37d85ce35a76116be05f7f3d7befc3de15 100644 (file)
@@ -75,9 +75,10 @@ struct kvm_vcpu_arch_shared {
 };
 
 #define KVM_SC_MAGIC_R0                0x4b564d21 /* "KVM!" */
-#define HC_VENDOR_KVM          (42 << 16)
-#define HC_EV_SUCCESS          0
-#define HC_EV_UNIMPLEMENTED    12
+
+#define KVM_HCALL_TOKEN(num)     _EV_HCALL_TOKEN(EV_KVM_VENDOR_ID, num)
+
+#include <asm/epapr_hcalls.h>
 
 #define KVM_FEATURE_MAGIC_PAGE 1
 
@@ -121,7 +122,7 @@ static unsigned long kvm_hypercall(unsigned long *in,
                                   unsigned long *out,
                                   unsigned long nr)
 {
-       return HC_EV_UNIMPLEMENTED;
+       return EV_UNIMPLEMENTED;
 }
 
 #endif
@@ -132,7 +133,7 @@ static inline long kvm_hypercall0_1(unsigned int nr, unsigned long *r2)
        unsigned long out[8];
        unsigned long r;
 
-       r = kvm_hypercall(in, out, nr | HC_VENDOR_KVM);
+       r = kvm_hypercall(in, out, KVM_HCALL_TOKEN(nr));
        *r2 = out[0];
 
        return r;
@@ -143,7 +144,7 @@ static inline long kvm_hypercall0(unsigned int nr)
        unsigned long in[8];
        unsigned long out[8];
 
-       return kvm_hypercall(in, out, nr | HC_VENDOR_KVM);
+       return kvm_hypercall(in, out, KVM_HCALL_TOKEN(nr));
 }
 
 static inline long kvm_hypercall1(unsigned int nr, unsigned long p1)
@@ -152,7 +153,7 @@ static inline long kvm_hypercall1(unsigned int nr, unsigned long p1)
        unsigned long out[8];
 
        in[0] = p1;
-       return kvm_hypercall(in, out, nr | HC_VENDOR_KVM);
+       return kvm_hypercall(in, out, KVM_HCALL_TOKEN(nr));
 }
 
 static inline long kvm_hypercall2(unsigned int nr, unsigned long p1,
@@ -163,7 +164,7 @@ static inline long kvm_hypercall2(unsigned int nr, unsigned long p1,
 
        in[0] = p1;
        in[1] = p2;
-       return kvm_hypercall(in, out, nr | HC_VENDOR_KVM);
+       return kvm_hypercall(in, out, KVM_HCALL_TOKEN(nr));
 }
 
 static inline long kvm_hypercall3(unsigned int nr, unsigned long p1,
@@ -175,7 +176,7 @@ static inline long kvm_hypercall3(unsigned int nr, unsigned long p1,
        in[0] = p1;
        in[1] = p2;
        in[2] = p3;
-       return kvm_hypercall(in, out, nr | HC_VENDOR_KVM);
+       return kvm_hypercall(in, out, KVM_HCALL_TOKEN(nr));
 }
 
 static inline long kvm_hypercall4(unsigned int nr, unsigned long p1,
@@ -189,7 +190,7 @@ static inline long kvm_hypercall4(unsigned int nr, unsigned long p1,
        in[1] = p2;
        in[2] = p3;
        in[3] = p4;
-       return kvm_hypercall(in, out, nr | HC_VENDOR_KVM);
+       return kvm_hypercall(in, out, KVM_HCALL_TOKEN(nr));
 }
 
 
index 0124937a23b97e104260f9cd4bbe1c409bdf1ff5..c06a64b533623d45109b620bd13a814e7d4b2673 100644 (file)
@@ -68,6 +68,8 @@ extern void kvmppc_emulate_dec(struct kvm_vcpu *vcpu);
 extern u32 kvmppc_get_dec(struct kvm_vcpu *vcpu, u64 tb);
 extern void kvmppc_decrementer_func(unsigned long data);
 extern int kvmppc_sanity_check(struct kvm_vcpu *vcpu);
+extern int kvmppc_subarch_vcpu_init(struct kvm_vcpu *vcpu);
+extern void kvmppc_subarch_vcpu_uninit(struct kvm_vcpu *vcpu);
 
 /* Core-specific hooks */
 
@@ -104,6 +106,7 @@ extern void kvmppc_core_queue_external(struct kvm_vcpu *vcpu,
                                        struct kvm_interrupt *irq);
 extern void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu,
                                          struct kvm_interrupt *irq);
+extern void kvmppc_core_flush_tlb(struct kvm_vcpu *vcpu);
 
 extern int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
                                   unsigned int op, int *advance);
@@ -111,6 +114,7 @@ extern int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn,
                                     ulong val);
 extern int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn,
                                     ulong *val);
+extern int kvmppc_core_check_requests(struct kvm_vcpu *vcpu);
 
 extern int kvmppc_booke_init(void);
 extern void kvmppc_booke_exit(void);
@@ -149,6 +153,8 @@ extern int kvm_vm_ioctl_get_smmu_info(struct kvm *kvm,
 extern int kvmppc_bookehv_init(void);
 extern void kvmppc_bookehv_exit(void);
 
+extern int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu);
+
 /*
  * Cuts out inst bits with ordering according to spec.
  * That means the leftmost bit is zero. All given bits are included.
@@ -219,4 +225,26 @@ void kvmppc_claim_lpid(long lpid);
 void kvmppc_free_lpid(long lpid);
 void kvmppc_init_lpid(unsigned long nr_lpids);
 
+static inline void kvmppc_mmu_flush_icache(pfn_t pfn)
+{
+       /* Clear i-cache for new pages */
+       struct page *page;
+       page = pfn_to_page(pfn);
+       if (!test_bit(PG_arch_1, &page->flags)) {
+               flush_dcache_icache_page(page);
+               set_bit(PG_arch_1, &page->flags);
+       }
+}
+
+/* Please call after prepare_to_enter. This function puts the lazy ee state
+   back to normal mode, without actually enabling interrupts. */
+static inline void kvmppc_lazy_ee_enable(void)
+{
+#ifdef CONFIG_PPC64
+       /* Only need to enable IRQs by hard enabling them after this */
+       local_paca->irq_happened = 0;
+       local_paca->soft_enabled = 1;
+#endif
+}
+
 #endif /* __POWERPC_KVM_PPC_H__ */
index 0192a4ee2bc2b65354778a6ec2392f6cab5cddba..c1df590ec4440a96f81b97f6048ad79a7f326179 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/list.h>
 #include <asm/bug.h>
+#include <asm-generic/module.h>
 
 
 #ifndef __powerpc64__
@@ -60,16 +61,10 @@ struct mod_arch_specific {
  */
 
 #ifdef __powerpc64__
-#    define Elf_Shdr   Elf64_Shdr
-#    define Elf_Sym    Elf64_Sym
-#    define Elf_Ehdr   Elf64_Ehdr
 #    ifdef MODULE
        asm(".section .stubs,\"ax\",@nobits; .align 3; .previous");
 #    endif
 #else
-#    define Elf_Shdr   Elf32_Shdr
-#    define Elf_Sym    Elf32_Sym
-#    define Elf_Ehdr   Elf32_Ehdr
 #    ifdef MODULE
        asm(".section .plt,\"ax\",@nobits; .align 3; .previous");
        asm(".section .init.plt,\"ax\",@nobits; .align 3; .previous");
index c9f698a994be246860ee6cfdd6895d27d68cea7b..c0f9ef90f0b8407a22987dfe4c83c73ed0cbc1d3 100644 (file)
@@ -63,6 +63,7 @@
  */
 #define MPIC_TIMER_BASE                        0x01100
 #define MPIC_TIMER_STRIDE              0x40
+#define MPIC_TIMER_GROUP_STRIDE                0x1000
 
 #define MPIC_TIMER_CURRENT_CNT         0x00000
 #define MPIC_TIMER_BASE_CNT            0x00010
 #define        MPIC_VECPRI_SENSE_MASK                  0x00400000
 #define MPIC_IRQ_DESTINATION           0x00010
 
+#define MPIC_FSL_BRR1                  0x00000
+#define        MPIC_FSL_BRR1_VER                       0x0000ffff
+
 #define MPIC_MAX_IRQ_SOURCES   2048
 #define MPIC_MAX_CPUS          32
 #define MPIC_MAX_ISU           32
 
+#define MPIC_MAX_ERR      32
+#define MPIC_FSL_ERR_INT  16
+
 /*
  * Tsi108 implementation of MPIC has many differences from the original one
  */
@@ -266,6 +273,7 @@ struct mpic
        struct irq_chip         hc_ipi;
 #endif
        struct irq_chip         hc_tm;
+       struct irq_chip         hc_err;
        const char              *name;
        /* Flags */
        unsigned int            flags;
@@ -279,6 +287,8 @@ struct mpic
        /* vector numbers used for internal sources (ipi/timers) */
        unsigned int            ipi_vecs[4];
        unsigned int            timer_vecs[8];
+       /* vector numbers used for FSL MPIC error interrupts */
+       unsigned int            err_int_vecs[MPIC_MAX_ERR];
 
        /* Spurious vector to program into unused sources */
        unsigned int            spurious_vec;
@@ -296,11 +306,15 @@ struct mpic
        phys_addr_t paddr;
 
        /* The various ioremap'ed bases */
+       struct mpic_reg_bank    thiscpuregs;
        struct mpic_reg_bank    gregs;
        struct mpic_reg_bank    tmregs;
        struct mpic_reg_bank    cpuregs[MPIC_MAX_CPUS];
        struct mpic_reg_bank    isus[MPIC_MAX_ISU];
 
+       /* ioremap'ed base for error interrupt registers */
+       u32 __iomem     *err_regs;
+
        /* Protected sources */
        unsigned long           *protected;
 
@@ -365,6 +379,11 @@ struct mpic
 #define MPIC_NO_RESET                  0x00004000
 /* Freescale MPIC (compatible includes "fsl,mpic") */
 #define MPIC_FSL                       0x00008000
+/* Freescale MPIC supports EIMR (error interrupt mask register).
+ * This flag is set for MPIC version >= 4.1 (version determined
+ * from the BRR1 register).
+*/
+#define MPIC_FSL_HAS_EIMR              0x00010000
 
 /* MPIC HW modification ID */
 #define MPIC_REGSET_MASK               0xf0000000
index 2d916c4982c5136a71b10f917606757aa743792f..e07e6af5e1ff9938a00468d49c46aaaee7be8ee9 100644 (file)
 #define TCR_FIE                0x00800000      /* FIT Interrupt Enable */
 #define TCR_ARE                0x00400000      /* Auto Reload Enable */
 
+#ifdef CONFIG_E500
+#define TCR_GET_WP(tcr)  ((((tcr) & 0xC0000000) >> 30) | \
+                             (((tcr) & 0x1E0000) >> 15))
+#else
+#define TCR_GET_WP(tcr)  (((tcr) & 0xC0000000) >> 30)
+#endif
+
 /* Bit definitions for the TSR. */
 #define TSR_ENW                0x80000000      /* Enable Next Watchdog */
 #define TSR_WIS                0x40000000      /* WDT Interrupt Status */
index ebc24dc5b1a13433aaeb1f5f21a8e48192d1d3cc..e807e9d8e3f7ea60b184da83176d54b3bbb40dcd 100644 (file)
@@ -65,6 +65,7 @@ int generic_cpu_disable(void);
 void generic_cpu_die(unsigned int cpu);
 void generic_mach_cpu_die(void);
 void generic_set_cpu_dead(unsigned int cpu);
+void generic_set_cpu_up(unsigned int cpu);
 int generic_check_cpu_restart(unsigned int cpu);
 #endif
 
@@ -190,6 +191,7 @@ extern unsigned long __secondary_hold_spinloop;
 extern unsigned long __secondary_hold_acknowledge;
 extern char __secondary_hold;
 
+extern void __early_start(void);
 #endif /* __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
index 8979d4cd3d70500fc1f0dbada65b9f834e020faa..de99d6e29430341623fd8a0f6ee3d3a4c4e1a768 100644 (file)
@@ -22,4 +22,10 @@ int __init swiotlb_setup_bus_notifier(void);
 
 extern void pci_dma_dev_setup_swiotlb(struct pci_dev *pdev);
 
+#ifdef CONFIG_SWIOTLB
+void swiotlb_detect_4g(void);
+#else
+static inline void swiotlb_detect_4g(void) {}
+#endif
+
 #endif /* __ASM_SWIOTLB_H */
index 69fdd2322a6676c27e5e67fad4c5eefff3f9e1b5..dcd881937f7a9217c2c6b7843d218a1d6b777970 100644 (file)
@@ -16,6 +16,8 @@
 #include <asm/processor.h>
 #include <asm/cputable.h>
 #include <asm/ppc_asm.h>
+#include <asm/mmu-book3e.h>
+#include <asm/asm-offsets.h>
 
 _GLOBAL(__e500_icache_setup)
        mfspr   r0, SPRN_L1CSR1
@@ -73,27 +75,81 @@ _GLOBAL(__setup_cpu_e500v2)
        mtlr    r4
        blr
 _GLOBAL(__setup_cpu_e500mc)
-       mr      r5, r4
-       mflr    r4
+_GLOBAL(__setup_cpu_e5500)
+       mflr    r5
        bl      __e500_icache_setup
        bl      __e500_dcache_setup
        bl      __setup_e500mc_ivors
-       mtlr    r4
+       /*
+        * We only want to touch IVOR38-41 if we're running on hardware
+        * that supports category E.HV.  The architectural way to determine
+        * this is MMUCFG[LPIDSIZE].
+        */
+       mfspr   r3, SPRN_MMUCFG
+       rlwinm. r3, r3, 0, MMUCFG_LPIDSIZE
+       beq     1f
+       bl      __setup_ehv_ivors
+       b       2f
+1:
+       lwz     r3, CPU_SPEC_FEATURES(r4)
+       /* We need this check as cpu_setup is also called for
+        * the secondary cores. So, if we have already cleared
+        * the feature on the primary core, avoid doing it on the
+        * secondary core.
+        */
+       andis.  r6, r3, CPU_FTR_EMB_HV@h
+       beq     2f
+       rlwinm  r3, r3, 0, ~CPU_FTR_EMB_HV
+       stw     r3, CPU_SPEC_FEATURES(r4)
+2:
+       mtlr    r5
        blr
 #endif
-/* Right now, restore and setup are the same thing */
+
+#ifdef CONFIG_PPC_BOOK3E_64
 _GLOBAL(__restore_cpu_e5500)
-_GLOBAL(__setup_cpu_e5500)
        mflr    r4
        bl      __e500_icache_setup
        bl      __e500_dcache_setup
-#ifdef CONFIG_PPC_BOOK3E_64
        bl      .__setup_base_ivors
        bl      .setup_perfmon_ivor
        bl      .setup_doorbell_ivors
+       /*
+        * We only want to touch IVOR38-41 if we're running on hardware
+        * that supports category E.HV.  The architectural way to determine
+        * this is MMUCFG[LPIDSIZE].
+        */
+       mfspr   r10,SPRN_MMUCFG
+       rlwinm. r10,r10,0,MMUCFG_LPIDSIZE
+       beq     1f
        bl      .setup_ehv_ivors
-#else
-       bl      __setup_e500mc_ivors
-#endif
+1:
        mtlr    r4
        blr
+
+_GLOBAL(__setup_cpu_e5500)
+       mflr    r5
+       bl      __e500_icache_setup
+       bl      __e500_dcache_setup
+       bl      .__setup_base_ivors
+       bl      .setup_perfmon_ivor
+       bl      .setup_doorbell_ivors
+       /*
+        * We only want to touch IVOR38-41 if we're running on hardware
+        * that supports category E.HV.  The architectural way to determine
+        * this is MMUCFG[LPIDSIZE].
+        */
+       mfspr   r10,SPRN_MMUCFG
+       rlwinm. r10,r10,0,MMUCFG_LPIDSIZE
+       beq     1f
+       bl      .setup_ehv_ivors
+       b       2f
+1:
+       ld      r10,CPU_SPEC_FEATURES(r4)
+       LOAD_REG_IMMEDIATE(r9,CPU_FTR_EMB_HV)
+       andc    r10,r10,r9
+       std     r10,CPU_SPEC_FEATURES(r4)
+2:
+       mtlr    r5
+       blr
+#endif
index 455faa389876e51f3afaa732f74949b6859ae95c..0514c21f138bee013812ab5bcffde2ddb84da60a 100644 (file)
@@ -2016,7 +2016,9 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .oprofile_cpu_type      = "ppc/e500mc",
                .oprofile_type          = PPC_OPROFILE_FSL_EMB,
                .cpu_setup              = __setup_cpu_e5500,
+#ifndef CONFIG_PPC32
                .cpu_restore            = __restore_cpu_e5500,
+#endif
                .machine_check          = machine_check_e500mc,
                .platform               = "ppce5500",
        },
@@ -2034,7 +2036,9 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .oprofile_cpu_type      = "ppc/e6500",
                .oprofile_type          = PPC_OPROFILE_FSL_EMB,
                .cpu_setup              = __setup_cpu_e5500,
+#ifndef CONFIG_PPC32
                .cpu_restore            = __restore_cpu_e5500,
+#endif
                .machine_check          = machine_check_e500mc,
                .platform               = "ppce6500",
        },
index 46943651da23ba25b3e1093ea346fb31e154243c..dc5c6203a8c3b2e7e5a6ab871335726edc369f7d 100644 (file)
@@ -105,3 +105,23 @@ int __init swiotlb_setup_bus_notifier(void)
                              &ppc_swiotlb_plat_bus_notifier);
        return 0;
 }
+
+void swiotlb_detect_4g(void)
+{
+       if ((memblock_end_of_DRAM() - 1) > 0xffffffff)
+               ppc_swiotlb_enable = 1;
+}
+
+static int __init swiotlb_late_init(void)
+{
+       if (ppc_swiotlb_enable) {
+               swiotlb_print_info();
+               set_pci_dma_ops(&swiotlb_dma_ops);
+               ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb;
+       } else {
+               swiotlb_free();
+       }
+
+       return 0;
+}
+subsys_initcall(swiotlb_late_init);
index 697b390ebfd8af815075b1764699da52a7402da2..62c0dc2378266653cd97591f095261d2ed5c901a 100644 (file)
@@ -8,13 +8,41 @@
  */
 
 #include <linux/threads.h>
+#include <asm/epapr_hcalls.h>
 #include <asm/reg.h>
 #include <asm/page.h>
 #include <asm/cputable.h>
 #include <asm/thread_info.h>
 #include <asm/ppc_asm.h>
+#include <asm/asm-compat.h>
 #include <asm/asm-offsets.h>
 
+/* epapr_ev_idle() was derived from e500_idle() */
+_GLOBAL(epapr_ev_idle)
+       CURRENT_THREAD_INFO(r3, r1)
+       PPC_LL  r4, TI_LOCAL_FLAGS(r3)  /* set napping bit */
+       ori     r4, r4,_TLF_NAPPING     /* so when we take an exception */
+       PPC_STL r4, TI_LOCAL_FLAGS(r3)  /* it will return to our caller */
+
+       wrteei  1
+
+idle_loop:
+       LOAD_REG_IMMEDIATE(r11, EV_HCALL_TOKEN(EV_IDLE))
+
+.global epapr_ev_idle_start
+epapr_ev_idle_start:
+       li      r3, -1
+       nop
+       nop
+       nop
+
+       /*
+        * Guard against spurious wakeups from a hypervisor --
+        * only interrupt will cause us to return to LR due to
+        * _TLF_NAPPING.
+        */
+       b       idle_loop
+
 /* Hypercall entry point. Will be patched with device tree instructions. */
 .global epapr_hypercall_start
 epapr_hypercall_start:
index 028aeae370b657fb91096be96243efdf0e8bf61f..f3eab8594d9f873432deb94c770db354f20ffc76 100644 (file)
 #include <asm/epapr_hcalls.h>
 #include <asm/cacheflush.h>
 #include <asm/code-patching.h>
+#include <asm/machdep.h>
+
+extern void epapr_ev_idle(void);
+extern u32 epapr_ev_idle_start[];
 
 bool epapr_paravirt_enabled;
 
@@ -41,8 +45,13 @@ static int __init epapr_paravirt_init(void)
        if (len % 4 || len > (4 * 4))
                return -ENODEV;
 
-       for (i = 0; i < (len / 4); i++)
+       for (i = 0; i < (len / 4); i++) {
                patch_instruction(epapr_hypercall_start + i, insts[i]);
+               patch_instruction(epapr_ev_idle_start + i, insts[i]);
+       }
+
+       if (of_get_property(hyper_node, "has-idle", NULL))
+               ppc_md.power_save = epapr_ev_idle;
 
        epapr_paravirt_enabled = true;
 
index 98be7f0cd227019cbe6b6a07ad989327b8e36979..ca0ead8281e94047d4ad0ab1efe9ec0204435af9 100644 (file)
@@ -1302,25 +1302,11 @@ _GLOBAL(setup_perfmon_ivor)
 _GLOBAL(setup_doorbell_ivors)
        SET_IVOR(36, 0x280) /* Processor Doorbell */
        SET_IVOR(37, 0x2a0) /* Processor Doorbell Crit */
-
-       /* Check MMUCFG[LPIDSIZE] to determine if we have category E.HV */
-       mfspr   r10,SPRN_MMUCFG
-       rlwinm. r10,r10,0,MMUCFG_LPIDSIZE
-       beqlr
-
-       SET_IVOR(38, 0x2c0) /* Guest Processor Doorbell */
-       SET_IVOR(39, 0x2e0) /* Guest Processor Doorbell Crit/MC */
        blr
 
 _GLOBAL(setup_ehv_ivors)
-       /*
-        * We may be running as a guest and lack E.HV even on a chip
-        * that normally has it.
-        */
-       mfspr   r10,SPRN_MMUCFG
-       rlwinm. r10,r10,0,MMUCFG_LPIDSIZE
-       beqlr
-
        SET_IVOR(40, 0x300) /* Embedded Hypervisor System Call */
        SET_IVOR(41, 0x320) /* Embedded Hypervisor Privilege */
+       SET_IVOR(38, 0x2c0) /* Guest Processor Doorbell */
+       SET_IVOR(39, 0x2e0) /* Guest Processor Doorbell Crit/MC */
        blr
index 0f59863c3adeb3f220ef63093af71b1ce2bb23e4..6f62a737f607164d4bd63e9a1992e30df8f16334 100644 (file)
@@ -895,15 +895,11 @@ _GLOBAL(__setup_e500mc_ivors)
        mtspr   SPRN_IVOR36,r3
        li      r3,CriticalDoorbell@l
        mtspr   SPRN_IVOR37,r3
+       sync
+       blr
 
-       /*
-        * We only want to touch IVOR38-41 if we're running on hardware
-        * that supports category E.HV.  The architectural way to determine
-        * this is MMUCFG[LPIDSIZE].
-        */
-       mfspr   r3, SPRN_MMUCFG
-       andis.  r3, r3, MMUCFG_LPIDSIZE@h
-       beq     no_hv
+/* setup ehv ivors for */
+_GLOBAL(__setup_ehv_ivors)
        li      r3,GuestDoorbell@l
        mtspr   SPRN_IVOR38,r3
        li      r3,CriticalGuestDoorbell@l
@@ -912,14 +908,8 @@ _GLOBAL(__setup_e500mc_ivors)
        mtspr   SPRN_IVOR40,r3
        li      r3,Ehvpriv@l
        mtspr   SPRN_IVOR41,r3
-skip_hv_ivors:
        sync
        blr
-no_hv:
-       lwz     r3, CPU_SPEC_FEATURES(r5)
-       rlwinm  r3, r3, 0, ~CPU_FTR_EMB_HV
-       stw     r3, CPU_SPEC_FEATURES(r5)
-       b       skip_hv_ivors
 
 #ifdef CONFIG_SPE
 /*
@@ -1043,6 +1033,34 @@ _GLOBAL(flush_dcache_L1)
 
        blr
 
+/* Flush L1 d-cache, invalidate and disable d-cache and i-cache */
+_GLOBAL(__flush_disable_L1)
+       mflr    r10
+       bl      flush_dcache_L1 /* Flush L1 d-cache */
+       mtlr    r10
+
+       mfspr   r4, SPRN_L1CSR0 /* Invalidate and disable d-cache */
+       li      r5, 2
+       rlwimi  r4, r5, 0, 3
+
+       msync
+       isync
+       mtspr   SPRN_L1CSR0, r4
+       isync
+
+1:     mfspr   r4, SPRN_L1CSR0 /* Wait for the invalidate to finish */
+       andi.   r4, r4, 2
+       bne     1b
+
+       mfspr   r4, SPRN_L1CSR1 /* Invalidate and disable i-cache */
+       li      r5, 2
+       rlwimi  r4, r5, 0, 3
+
+       mtspr   SPRN_L1CSR1, r4
+       isync
+
+       blr
+
 #ifdef CONFIG_SMP
 /* When we get here, r24 needs to hold the CPU # */
        .globl __secondary_start
index 867db1de8949571a152cd9559a5b36bb7c91e090..a61b133c4f99b2a380b274fa7c39c7a5d301761a 100644 (file)
@@ -419,7 +419,7 @@ static void kvm_map_magic_page(void *data)
        in[0] = KVM_MAGIC_PAGE;
        in[1] = KVM_MAGIC_PAGE;
 
-       kvm_hypercall(in, out, HC_VENDOR_KVM | KVM_HC_PPC_MAP_MAGIC_PAGE);
+       kvm_hypercall(in, out, KVM_HCALL_TOKEN(KVM_HC_PPC_MAP_MAGIC_PAGE));
 
        *features = out[0];
 }
index 3e4031581c65482bb9348b17c9509e630b710570..e597dde124e8736d09caf15a8f1012c443b820cc 100644 (file)
@@ -43,6 +43,7 @@
 #include <asm/dcr.h>
 #include <asm/ftrace.h>
 #include <asm/switch_to.h>
+#include <asm/epapr_hcalls.h>
 
 #ifdef CONFIG_PPC32
 extern void transfer_to_handler(void);
@@ -192,3 +193,7 @@ EXPORT_SYMBOL(__arch_hweight64);
 #ifdef CONFIG_PPC_BOOK3S_64
 EXPORT_SYMBOL_GPL(mmu_psize_defs);
 #endif
+
+#ifdef CONFIG_EPAPR_PARAVIRT
+EXPORT_SYMBOL(epapr_hypercall_start);
+#endif
index 0794a3017b1b53e65e4d1aa325b79711a9fb04b1..9ec5e5525777a7ce1769092e54b983d366fa6b5c 100644 (file)
@@ -705,6 +705,7 @@ static void __init early_cmdline_parse(void)
 #endif
 #define OV5_TYPE1_AFFINITY     0x80    /* Type 1 NUMA affinity */
 #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 */
 
 /* Option Vector 6: IBM PAPR hints */
@@ -774,8 +775,7 @@ static unsigned char ibm_architecture_vec[] = {
        0,
        0,
        0,
-       OV5_PFO_HW_RNG | OV5_PFO_HW_ENCR,
-
+       OV5_PFO_HW_RNG | OV5_PFO_HW_ENCR | OV5_PFO_HW_842,
        /* option vector 6: IBM PAPR hints */
        4 - 2,                          /* length */
        0,
index 0321007086f7c499771ad0f71bc1f63969faff7a..fecb0382d3001727367ec3564d913aef4f6ca0ad 100644 (file)
@@ -102,7 +102,7 @@ int __devinit smp_generic_kick_cpu(int nr)
         * Ok it's not there, so it might be soft-unplugged, let's
         * try to bring it back
         */
-       per_cpu(cpu_state, nr) = CPU_UP_PREPARE;
+       generic_set_cpu_up(nr);
        smp_wmb();
        smp_send_reschedule(nr);
 #endif /* CONFIG_HOTPLUG_CPU */
@@ -406,6 +406,16 @@ void generic_set_cpu_dead(unsigned int cpu)
        per_cpu(cpu_state, cpu) = CPU_DEAD;
 }
 
+/*
+ * The cpu_state should be set to CPU_UP_PREPARE in kick_cpu(), otherwise
+ * the cpu_state is always CPU_DEAD after calling generic_set_cpu_dead(),
+ * which makes the delay in generic_cpu_die() not happen.
+ */
+void generic_set_cpu_up(unsigned int cpu)
+{
+       per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
+}
+
 int generic_check_cpu_restart(unsigned int cpu)
 {
        return per_cpu(cpu_state, cpu) == CPU_UP_PREPARE;
index 50e7dbc7356cd0ed574f3ac9fa61ea509fb26439..3d7fd21c65f92eeeb26ce19fc9d7fe07d0cdb36c 100644 (file)
@@ -83,6 +83,7 @@ int kvmppc_core_vcpu_setup(struct kvm_vcpu *vcpu)
                vcpu_44x->shadow_refs[i].gtlb_index = -1;
 
        vcpu->arch.cpu_type = KVM_CPU_440;
+       vcpu->arch.pvr = mfspr(SPRN_PVR);
 
        return 0;
 }
index c8c61578fdfc6e8420497854971d8da7b6d74598..1a793c4c4a6793cfa8880b7064611e8958856c05 100644 (file)
 #include "booke.h"
 #include "44x_tlb.h"
 
+#define XOP_MFDCRX  259
 #define XOP_MFDCR   323
+#define XOP_MTDCRX  387
 #define XOP_MTDCR   451
 #define XOP_TLBSX   914
 #define XOP_ICCCI   966
 #define XOP_TLBWE   978
 
+static int emulate_mtdcr(struct kvm_vcpu *vcpu, int rs, int dcrn)
+{
+       /* emulate some access in kernel */
+       switch (dcrn) {
+       case DCRN_CPR0_CONFIG_ADDR:
+               vcpu->arch.cpr0_cfgaddr = kvmppc_get_gpr(vcpu, rs);
+               return EMULATE_DONE;
+       default:
+               vcpu->run->dcr.dcrn = dcrn;
+               vcpu->run->dcr.data = kvmppc_get_gpr(vcpu, rs);
+               vcpu->run->dcr.is_write = 1;
+               vcpu->arch.dcr_needed = 1;
+               kvmppc_account_exit(vcpu, DCR_EXITS);
+               return EMULATE_DO_DCR;
+       }
+}
+
+static int emulate_mfdcr(struct kvm_vcpu *vcpu, int rt, int dcrn)
+{
+       /* The guest may access CPR0 registers to determine the timebase
+        * frequency, and it must know the real host frequency because it
+        * can directly access the timebase registers.
+        *
+        * It would be possible to emulate those accesses in userspace,
+        * but userspace can really only figure out the end frequency.
+        * We could decompose that into the factors that compute it, but
+        * that's tricky math, and it's easier to just report the real
+        * CPR0 values.
+        */
+       switch (dcrn) {
+       case DCRN_CPR0_CONFIG_ADDR:
+               kvmppc_set_gpr(vcpu, rt, vcpu->arch.cpr0_cfgaddr);
+               break;
+       case DCRN_CPR0_CONFIG_DATA:
+               local_irq_disable();
+               mtdcr(DCRN_CPR0_CONFIG_ADDR,
+                         vcpu->arch.cpr0_cfgaddr);
+               kvmppc_set_gpr(vcpu, rt,
+                              mfdcr(DCRN_CPR0_CONFIG_DATA));
+               local_irq_enable();
+               break;
+       default:
+               vcpu->run->dcr.dcrn = dcrn;
+               vcpu->run->dcr.data =  0;
+               vcpu->run->dcr.is_write = 0;
+               vcpu->arch.io_gpr = rt;
+               vcpu->arch.dcr_needed = 1;
+               kvmppc_account_exit(vcpu, DCR_EXITS);
+               return EMULATE_DO_DCR;
+       }
+
+       return EMULATE_DONE;
+}
+
 int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
                            unsigned int inst, int *advance)
 {
@@ -50,55 +106,21 @@ int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu,
                switch (get_xop(inst)) {
 
                case XOP_MFDCR:
-                       /* The guest may access CPR0 registers to determine the timebase
-                        * frequency, and it must know the real host frequency because it
-                        * can directly access the timebase registers.
-                        *
-                        * It would be possible to emulate those accesses in userspace,
-                        * but userspace can really only figure out the end frequency.
-                        * We could decompose that into the factors that compute it, but
-                        * that's tricky math, and it's easier to just report the real
-                        * CPR0 values.
-                        */
-                       switch (dcrn) {
-                       case DCRN_CPR0_CONFIG_ADDR:
-                               kvmppc_set_gpr(vcpu, rt, vcpu->arch.cpr0_cfgaddr);
-                               break;
-                       case DCRN_CPR0_CONFIG_DATA:
-                               local_irq_disable();
-                               mtdcr(DCRN_CPR0_CONFIG_ADDR,
-                                         vcpu->arch.cpr0_cfgaddr);
-                               kvmppc_set_gpr(vcpu, rt,
-                                              mfdcr(DCRN_CPR0_CONFIG_DATA));
-                               local_irq_enable();
-                               break;
-                       default:
-                               run->dcr.dcrn = dcrn;
-                               run->dcr.data =  0;
-                               run->dcr.is_write = 0;
-                               vcpu->arch.io_gpr = rt;
-                               vcpu->arch.dcr_needed = 1;
-                               kvmppc_account_exit(vcpu, DCR_EXITS);
-                               emulated = EMULATE_DO_DCR;
-                       }
+                       emulated = emulate_mfdcr(vcpu, rt, dcrn);
+                       break;
 
+               case XOP_MFDCRX:
+                       emulated = emulate_mfdcr(vcpu, rt,
+                                       kvmppc_get_gpr(vcpu, ra));
                        break;
 
                case XOP_MTDCR:
-                       /* emulate some access in kernel */
-                       switch (dcrn) {
-                       case DCRN_CPR0_CONFIG_ADDR:
-                               vcpu->arch.cpr0_cfgaddr = kvmppc_get_gpr(vcpu, rs);
-                               break;
-                       default:
-                               run->dcr.dcrn = dcrn;
-                               run->dcr.data = kvmppc_get_gpr(vcpu, rs);
-                               run->dcr.is_write = 1;
-                               vcpu->arch.dcr_needed = 1;
-                               kvmppc_account_exit(vcpu, DCR_EXITS);
-                               emulated = EMULATE_DO_DCR;
-                       }
+                       emulated = emulate_mtdcr(vcpu, rs, dcrn);
+                       break;
 
+               case XOP_MTDCRX:
+                       emulated = emulate_mtdcr(vcpu, rs,
+                                       kvmppc_get_gpr(vcpu, ra));
                        break;
 
                case XOP_TLBWE:
index 33aa715dab28b776deeea328271e5eb89abd37b8..5dd3ab46997603e6f55c681781b773e50a0ff557 100644 (file)
@@ -319,7 +319,6 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 gvaddr, gpa_t gpaddr,
        if (is_error_page(new_page)) {
                printk(KERN_ERR "Couldn't get guest page for gfn %llx!\n",
                        (unsigned long long)gfn);
-               kvm_release_page_clean(new_page);
                return;
        }
        hpaddr = page_to_phys(new_page);
index f4dacb9c57fac1a275291aedf1357c3070b6f750..71f0cd9edf335a4751895c16f6b3069e5f872950 100644 (file)
@@ -36,6 +36,7 @@ config KVM_BOOK3S_64_HANDLER
 config KVM_BOOK3S_PR
        bool
        select KVM_MMIO
+       select MMU_NOTIFIER
 
 config KVM_BOOK3S_32
        tristate "KVM support for PowerPC book3s_32 processors"
@@ -123,6 +124,7 @@ config KVM_E500V2
        depends on EXPERIMENTAL && E500 && !PPC_E500MC
        select KVM
        select KVM_MMIO
+       select MMU_NOTIFIER
        ---help---
          Support running unmodified E500 guest kernels in virtual machines on
          E500v2 host processors.
@@ -138,6 +140,7 @@ config KVM_E500MC
        select KVM
        select KVM_MMIO
        select KVM_BOOKE_HV
+       select MMU_NOTIFIER
        ---help---
          Support running unmodified E500MC/E5500 (32-bit) guest kernels in
          virtual machines on E500MC/E5500 host processors.
index 3f2a8360c857f1aae94a13631b2eb099a96795a0..e94666566fa93c6e1b9404a8e92d467731afbb35 100644 (file)
@@ -411,6 +411,15 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
        return 0;
 }
 
+int kvmppc_subarch_vcpu_init(struct kvm_vcpu *vcpu)
+{
+       return 0;
+}
+
+void kvmppc_subarch_vcpu_uninit(struct kvm_vcpu *vcpu)
+{
+}
+
 int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 {
        int i;
index f922c29bb234d9bc6f2baf44175e934b63de5f86..9fac0101ffb98ca99139d5ff8ed547cfc9e2461f 100644 (file)
@@ -211,6 +211,9 @@ next_pteg:
                pteg1 |= PP_RWRX;
        }
 
+       if (orig_pte->may_execute)
+               kvmppc_mmu_flush_icache(hpaddr >> PAGE_SHIFT);
+
        local_irq_disable();
 
        if (pteg[rr]) {
@@ -251,6 +254,7 @@ next_pteg:
 
        kvmppc_mmu_hpte_cache_map(vcpu, pte);
 
+       kvm_release_pfn_clean(hpaddr >> PAGE_SHIFT);
 out:
        return r;
 }
index 10fc8ec9d2a8b7e1e8e7ad8113e8dce633a5d977..6b2c80e496813c7a81b11da0b21769b7dd1212e9 100644 (file)
@@ -126,6 +126,8 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte)
 
        if (!orig_pte->may_execute)
                rflags |= HPTE_R_N;
+       else
+               kvmppc_mmu_flush_icache(hpaddr >> PAGE_SHIFT);
 
        hash = hpt_hash(va, PTE_SIZE, MMU_SEGSIZE_256M);
 
@@ -166,6 +168,7 @@ map_again:
 
                kvmppc_mmu_hpte_cache_map(vcpu, pte);
        }
+       kvm_release_pfn_clean(hpaddr >> PAGE_SHIFT);
 
 out:
        return r;
index d03eb6f7b0584e368bdd96e0f1969af58e885371..d95d11322a159912230832371eefbe74c61c8e62 100644 (file)
@@ -705,7 +705,7 @@ int kvmppc_book3s_hv_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
                goto out_unlock;
        hpte[0] = (hpte[0] & ~HPTE_V_ABSENT) | HPTE_V_VALID;
 
-       rmap = &memslot->rmap[gfn - memslot->base_gfn];
+       rmap = &memslot->arch.rmap[gfn - memslot->base_gfn];
        lock_rmap(rmap);
 
        /* Check if we might have been invalidated; let the guest retry if so */
@@ -756,9 +756,12 @@ int kvmppc_book3s_hv_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
        goto out_put;
 }
 
-static int kvm_handle_hva(struct kvm *kvm, unsigned long hva,
-                         int (*handler)(struct kvm *kvm, unsigned long *rmapp,
-                                        unsigned long gfn))
+static int kvm_handle_hva_range(struct kvm *kvm,
+                               unsigned long start,
+                               unsigned long end,
+                               int (*handler)(struct kvm *kvm,
+                                              unsigned long *rmapp,
+                                              unsigned long gfn))
 {
        int ret;
        int retval = 0;
@@ -767,15 +770,25 @@ static int kvm_handle_hva(struct kvm *kvm, unsigned long hva,
 
        slots = kvm_memslots(kvm);
        kvm_for_each_memslot(memslot, slots) {
-               unsigned long start = memslot->userspace_addr;
-               unsigned long end;
+               unsigned long hva_start, hva_end;
+               gfn_t gfn, gfn_end;
 
-               end = start + (memslot->npages << PAGE_SHIFT);
-               if (hva >= start && hva < end) {
-                       gfn_t gfn_offset = (hva - start) >> PAGE_SHIFT;
+               hva_start = max(start, memslot->userspace_addr);
+               hva_end = min(end, memslot->userspace_addr +
+                                       (memslot->npages << PAGE_SHIFT));
+               if (hva_start >= hva_end)
+                       continue;
+               /*
+                * {gfn(page) | page intersects with [hva_start, hva_end)} =
+                * {gfn, gfn+1, ..., gfn_end-1}.
+                */
+               gfn = hva_to_gfn_memslot(hva_start, memslot);
+               gfn_end = hva_to_gfn_memslot(hva_end + PAGE_SIZE - 1, memslot);
+
+               for (; gfn < gfn_end; ++gfn) {
+                       gfn_t gfn_offset = gfn - memslot->base_gfn;
 
-                       ret = handler(kvm, &memslot->rmap[gfn_offset],
-                                     memslot->base_gfn + gfn_offset);
+                       ret = handler(kvm, &memslot->arch.rmap[gfn_offset], gfn);
                        retval |= ret;
                }
        }
@@ -783,6 +796,13 @@ static int kvm_handle_hva(struct kvm *kvm, unsigned long hva,
        return retval;
 }
 
+static int kvm_handle_hva(struct kvm *kvm, unsigned long hva,
+                         int (*handler)(struct kvm *kvm, unsigned long *rmapp,
+                                        unsigned long gfn))
+{
+       return kvm_handle_hva_range(kvm, hva, hva + 1, handler);
+}
+
 static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp,
                           unsigned long gfn)
 {
@@ -850,6 +870,13 @@ int kvm_unmap_hva(struct kvm *kvm, unsigned long hva)
        return 0;
 }
 
+int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end)
+{
+       if (kvm->arch.using_mmu_notifiers)
+               kvm_handle_hva_range(kvm, start, end, kvm_unmap_rmapp);
+       return 0;
+}
+
 static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
                         unsigned long gfn)
 {
@@ -1009,7 +1036,7 @@ long kvmppc_hv_get_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot)
        unsigned long *rmapp, *map;
 
        preempt_disable();
-       rmapp = memslot->rmap;
+       rmapp = memslot->arch.rmap;
        map = memslot->dirty_bitmap;
        for (i = 0; i < memslot->npages; ++i) {
                if (kvm_test_clear_dirty(kvm, rmapp))
index fb4eac290fefc1c438b46a1cc5865c0b3200ce57..ec0a9e5de1005331e7372a5c76d3a153d2a4dfd5 100644 (file)
@@ -157,8 +157,8 @@ static void __init kvm_linear_init_one(ulong size, int count, int type)
        linear_info = alloc_bootmem(count * sizeof(struct kvmppc_linear_info));
        for (i = 0; i < count; ++i) {
                linear = alloc_bootmem_align(size, size);
-               pr_info("Allocated KVM %s at %p (%ld MB)\n", typestr, linear,
-                       size >> 20);
+               pr_debug("Allocated KVM %s at %p (%ld MB)\n", typestr, linear,
+                        size >> 20);
                linear_info[i].base_virt = linear;
                linear_info[i].base_pfn = __pa(linear) >> PAGE_SHIFT;
                linear_info[i].npages = npages;
index 5c70d19494f9251bee3968ba5f23a7c56cd6c926..56ac1a5d99129fea24213e7a8965f63a8678d9f0 100644 (file)
@@ -84,7 +84,7 @@ static void remove_revmap_chain(struct kvm *kvm, long pte_index,
        if (!memslot || (memslot->flags & KVM_MEMSLOT_INVALID))
                return;
 
-       rmap = real_vmalloc_addr(&memslot->rmap[gfn - memslot->base_gfn]);
+       rmap = real_vmalloc_addr(&memslot->arch.rmap[gfn - memslot->base_gfn]);
        lock_rmap(rmap);
 
        head = *rmap & KVMPPC_RMAP_INDEX;
@@ -180,7 +180,7 @@ long kvmppc_h_enter(struct kvm_vcpu *vcpu, unsigned long flags,
        if (!slot_is_aligned(memslot, psize))
                return H_PARAMETER;
        slot_fn = gfn - memslot->base_gfn;
-       rmap = &memslot->rmap[slot_fn];
+       rmap = &memslot->arch.rmap[slot_fn];
 
        if (!kvm->arch.using_mmu_notifiers) {
                physp = kvm->arch.slot_phys[memslot->id];
index 5a84c8d3d04050b98ab818c9d83cedeb74b8f235..44b72feaff7d9876fad230253be42c1aee6e8af7 100644 (file)
@@ -1421,13 +1421,13 @@ _GLOBAL(kvmppc_h_cede)
        sync                    /* order setting ceded vs. testing prodded */
        lbz     r5,VCPU_PRODDED(r3)
        cmpwi   r5,0
-       bne     1f
+       bne     kvm_cede_prodded
        li      r0,0            /* set trap to 0 to say hcall is handled */
        stw     r0,VCPU_TRAP(r3)
        li      r0,H_SUCCESS
        std     r0,VCPU_GPR(R3)(r3)
 BEGIN_FTR_SECTION
-       b       2f              /* just send it up to host on 970 */
+       b       kvm_cede_exit   /* just send it up to host on 970 */
 END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_206)
 
        /*
@@ -1446,7 +1446,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_206)
        or      r4,r4,r0
        PPC_POPCNTW(R7,R4)
        cmpw    r7,r8
-       bge     2f
+       bge     kvm_cede_exit
        stwcx.  r4,0,r6
        bne     31b
        li      r0,1
@@ -1555,7 +1555,8 @@ kvm_end_cede:
        b       hcall_real_fallback
 
        /* cede when already previously prodded case */
-1:     li      r0,0
+kvm_cede_prodded:
+       li      r0,0
        stb     r0,VCPU_PRODDED(r3)
        sync                    /* order testing prodded vs. clearing ceded */
        stb     r0,VCPU_CEDED(r3)
@@ -1563,7 +1564,8 @@ kvm_end_cede:
        blr
 
        /* we've ceded but we want to give control to the host */
-2:     li      r3,H_TOO_HARD
+kvm_cede_exit:
+       li      r3,H_TOO_HARD
        blr
 
 secondary_too_late:
index 41cb0017e757a1d8ccd83360624d9f1a40189426..2c86b0d6371494d4417b3e7e8d796c25a4b21a48 100644 (file)
@@ -114,11 +114,6 @@ static void invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
        hlist_del_init_rcu(&pte->list_vpte);
        hlist_del_init_rcu(&pte->list_vpte_long);
 
-       if (pte->pte.may_write)
-               kvm_release_pfn_dirty(pte->pfn);
-       else
-               kvm_release_pfn_clean(pte->pfn);
-
        spin_unlock(&vcpu3s->mmu_lock);
 
        vcpu3s->hpte_cache_count--;
index a1baec340f7ee3e0492d3fcd86e14e41a8811ccf..b3c584f94cb33860d90150c6ec0da3b2ebf8bd50 100644 (file)
@@ -52,8 +52,6 @@ static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr,
 #define MSR_USER32 MSR_USER
 #define MSR_USER64 MSR_USER
 #define HW_PAGE_SIZE PAGE_SIZE
-#define __hard_irq_disable local_irq_disable
-#define __hard_irq_enable local_irq_enable
 #endif
 
 void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
@@ -88,6 +86,61 @@ void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu)
        kvmppc_giveup_ext(vcpu, MSR_VSX);
 }
 
+int kvmppc_core_check_requests(struct kvm_vcpu *vcpu)
+{
+       int r = 1; /* Indicate we want to get back into the guest */
+
+       /* We misuse TLB_FLUSH to indicate that we want to clear
+          all shadow cache entries */
+       if (kvm_check_request(KVM_REQ_TLB_FLUSH, vcpu))
+               kvmppc_mmu_pte_flush(vcpu, 0, 0);
+
+       return r;
+}
+
+/************* MMU Notifiers *************/
+
+int kvm_unmap_hva(struct kvm *kvm, unsigned long hva)
+{
+       trace_kvm_unmap_hva(hva);
+
+       /*
+        * Flush all shadow tlb entries everywhere. This is slow, but
+        * we are 100% sure that we catch the to be unmapped page
+        */
+       kvm_flush_remote_tlbs(kvm);
+
+       return 0;
+}
+
+int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end)
+{
+       /* kvm_unmap_hva flushes everything anyways */
+       kvm_unmap_hva(kvm, start);
+
+       return 0;
+}
+
+int kvm_age_hva(struct kvm *kvm, unsigned long hva)
+{
+       /* XXX could be more clever ;) */
+       return 0;
+}
+
+int kvm_test_age_hva(struct kvm *kvm, unsigned long hva)
+{
+       /* XXX could be more clever ;) */
+       return 0;
+}
+
+void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte)
+{
+       /* The page will get remapped properly on its next fault */
+       kvm_unmap_hva(kvm, hva);
+}
+
+/*****************************************/
+
 static void kvmppc_recalc_shadow_msr(struct kvm_vcpu *vcpu)
 {
        ulong smsr = vcpu->arch.shared->msr;
@@ -242,10 +295,8 @@ static void kvmppc_patch_dcbz(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte)
        int i;
 
        hpage = gfn_to_page(vcpu->kvm, pte->raddr >> PAGE_SHIFT);
-       if (is_error_page(hpage)) {
-               kvm_release_page_clean(hpage);
+       if (is_error_page(hpage))
                return;
-       }
 
        hpage_offset = pte->raddr & ~PAGE_MASK;
        hpage_offset &= ~0xFFFULL;
@@ -542,18 +593,18 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
                        unsigned int exit_nr)
 {
        int r = RESUME_HOST;
+       int s;
 
        vcpu->stat.sum_exits++;
 
        run->exit_reason = KVM_EXIT_UNKNOWN;
        run->ready_for_interrupt_injection = 1;
 
-       /* We get here with MSR.EE=0, so enable it to be a nice citizen */
-       __hard_irq_enable();
+       /* We get here with MSR.EE=1 */
+
+       trace_kvm_exit(exit_nr, vcpu);
+       kvm_guest_exit();
 
-       trace_kvm_book3s_exit(exit_nr, vcpu);
-       preempt_enable();
-       kvm_resched(vcpu);
        switch (exit_nr) {
        case BOOK3S_INTERRUPT_INST_STORAGE:
        {
@@ -804,7 +855,6 @@ program_interrupt:
        }
        }
 
-       preempt_disable();
        if (!(r & RESUME_HOST)) {
                /* To avoid clobbering exit_reason, only check for signals if
                 * we aren't already exiting to userspace for some other
@@ -816,20 +866,13 @@ program_interrupt:
                 * and if we really did time things so badly, then we just exit
                 * again due to a host external interrupt.
                 */
-               __hard_irq_disable();
-               if (signal_pending(current)) {
-                       __hard_irq_enable();
-#ifdef EXIT_DEBUG
-                       printk(KERN_EMERG "KVM: Going back to host\n");
-#endif
-                       vcpu->stat.signal_exits++;
-                       run->exit_reason = KVM_EXIT_INTR;
-                       r = -EINTR;
+               local_irq_disable();
+               s = kvmppc_prepare_to_enter(vcpu);
+               if (s <= 0) {
+                       local_irq_enable();
+                       r = s;
                } else {
-                       /* In case an interrupt came in that was triggered
-                        * from userspace (like DEC), we need to check what
-                        * to inject now! */
-                       kvmppc_core_prepare_to_enter(vcpu);
+                       kvmppc_lazy_ee_enable();
                }
        }
 
@@ -1022,8 +1065,6 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 #endif
        ulong ext_msr;
 
-       preempt_disable();
-
        /* Check if we can run the vcpu at all */
        if (!vcpu->arch.sane) {
                kvm_run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
@@ -1031,21 +1072,16 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
                goto out;
        }
 
-       kvmppc_core_prepare_to_enter(vcpu);
-
        /*
         * Interrupts could be timers for the guest which we have to inject
         * again, so let's postpone them until we're in the guest and if we
         * really did time things so badly, then we just exit again due to
         * a host external interrupt.
         */
-       __hard_irq_disable();
-
-       /* No need to go into the guest when all we do is going out */
-       if (signal_pending(current)) {
-               __hard_irq_enable();
-               kvm_run->exit_reason = KVM_EXIT_INTR;
-               ret = -EINTR;
+       local_irq_disable();
+       ret = kvmppc_prepare_to_enter(vcpu);
+       if (ret <= 0) {
+               local_irq_enable();
                goto out;
        }
 
@@ -1082,11 +1118,12 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
        if (vcpu->arch.shared->msr & MSR_FP)
                kvmppc_handle_ext(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL, MSR_FP);
 
-       kvm_guest_enter();
+       kvmppc_lazy_ee_enable();
 
        ret = __kvmppc_vcpu_run(kvm_run, vcpu);
 
-       kvm_guest_exit();
+       /* No need for kvm_guest_exit. It's done in handle_exit.
+          We also get here with interrupts enabled. */
 
        current->thread.regs->msr = ext_msr;
 
@@ -1115,7 +1152,7 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 #endif
 
 out:
-       preempt_enable();
+       vcpu->mode = OUTSIDE_GUEST_MODE;
        return ret;
 }
 
index 9ecf6e35cd8de0de4fe148a7527524a46256c900..b2f8258b545ae9e7a5530d2c73e204dc7b8d3db8 100644 (file)
@@ -170,20 +170,21 @@ kvmppc_handler_skip_ins:
  * Call kvmppc_handler_trampoline_enter in real mode
  *
  * On entry, r4 contains the guest shadow MSR
+ * MSR.EE has to be 0 when calling this function
  */
 _GLOBAL(kvmppc_entry_trampoline)
        mfmsr   r5
        LOAD_REG_ADDR(r7, kvmppc_handler_trampoline_enter)
        toreal(r7)
 
-       li      r9, MSR_RI
-       ori     r9, r9, MSR_EE
-       andc    r9, r5, r9      /* Clear EE and RI in MSR value */
        li      r6, MSR_IR | MSR_DR
-       ori     r6, r6, MSR_EE
-       andc    r6, r5, r6      /* Clear EE, DR and IR in MSR value */
-       MTMSR_EERI(r9)          /* Clear EE and RI in MSR */
-       mtsrr0  r7              /* before we set srr0/1 */
+       andc    r6, r5, r6      /* Clear DR and IR in MSR value */
+       /*
+        * Set EE in HOST_MSR so that it's enabled when we get into our
+        * C exit handler function
+        */
+       ori     r5, r5, MSR_EE
+       mtsrr0  r7
        mtsrr1  r6
        RFI
 
index d25a097c852b75469785578cde71daef2043c65b..5f0476a602d8bd88f5a7f63df08d49ae3f9b9bae 100644 (file)
@@ -39,6 +39,7 @@
 
 #include "timing.h"
 #include "booke.h"
+#include "trace.h"
 
 unsigned long kvmppc_booke_handlers;
 
@@ -62,6 +63,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
        { "halt_wakeup", VCPU_STAT(halt_wakeup) },
        { "doorbell", VCPU_STAT(dbell_exits) },
        { "guest doorbell", VCPU_STAT(gdbell_exits) },
+       { "remote_tlb_flush", VM_STAT(remote_tlb_flush) },
        { NULL }
 };
 
@@ -120,6 +122,16 @@ static void kvmppc_vcpu_sync_spe(struct kvm_vcpu *vcpu)
 }
 #endif
 
+static void kvmppc_vcpu_sync_fpu(struct kvm_vcpu *vcpu)
+{
+#if defined(CONFIG_PPC_FPU) && !defined(CONFIG_KVM_BOOKE_HV)
+       /* We always treat the FP bit as enabled from the host
+          perspective, so only need to adjust the shadow MSR */
+       vcpu->arch.shadow_msr &= ~MSR_FP;
+       vcpu->arch.shadow_msr |= vcpu->arch.shared->msr & MSR_FP;
+#endif
+}
+
 /*
  * Helper function for "full" MSR writes.  No need to call this if only
  * EE/CE/ME/DE/RI are changing.
@@ -136,11 +148,13 @@ void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr)
 
        kvmppc_mmu_msr_notify(vcpu, old_msr);
        kvmppc_vcpu_sync_spe(vcpu);
+       kvmppc_vcpu_sync_fpu(vcpu);
 }
 
 static void kvmppc_booke_queue_irqprio(struct kvm_vcpu *vcpu,
                                        unsigned int priority)
 {
+       trace_kvm_booke_queue_irqprio(vcpu, priority);
        set_bit(priority, &vcpu->arch.pending_exceptions);
 }
 
@@ -206,6 +220,16 @@ void kvmppc_core_dequeue_external(struct kvm_vcpu *vcpu,
        clear_bit(BOOKE_IRQPRIO_EXTERNAL_LEVEL, &vcpu->arch.pending_exceptions);
 }
 
+static void kvmppc_core_queue_watchdog(struct kvm_vcpu *vcpu)
+{
+       kvmppc_booke_queue_irqprio(vcpu, BOOKE_IRQPRIO_WATCHDOG);
+}
+
+static void kvmppc_core_dequeue_watchdog(struct kvm_vcpu *vcpu)
+{
+       clear_bit(BOOKE_IRQPRIO_WATCHDOG, &vcpu->arch.pending_exceptions);
+}
+
 static void set_guest_srr(struct kvm_vcpu *vcpu, unsigned long srr0, u32 srr1)
 {
 #ifdef CONFIG_KVM_BOOKE_HV
@@ -325,6 +349,7 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
                msr_mask = MSR_CE | MSR_ME | MSR_DE;
                int_class = INT_CLASS_NONCRIT;
                break;
+       case BOOKE_IRQPRIO_WATCHDOG:
        case BOOKE_IRQPRIO_CRITICAL:
        case BOOKE_IRQPRIO_DBELL_CRIT:
                allowed = vcpu->arch.shared->msr & MSR_CE;
@@ -404,12 +429,121 @@ static int kvmppc_booke_irqprio_deliver(struct kvm_vcpu *vcpu,
        return allowed;
 }
 
+/*
+ * Return the number of jiffies until the next timeout.  If the timeout is
+ * longer than the NEXT_TIMER_MAX_DELTA, then return NEXT_TIMER_MAX_DELTA
+ * because the larger value can break the timer APIs.
+ */
+static unsigned long watchdog_next_timeout(struct kvm_vcpu *vcpu)
+{
+       u64 tb, wdt_tb, wdt_ticks = 0;
+       u64 nr_jiffies = 0;
+       u32 period = TCR_GET_WP(vcpu->arch.tcr);
+
+       wdt_tb = 1ULL << (63 - period);
+       tb = get_tb();
+       /*
+        * The watchdog timeout will hapeen when TB bit corresponding
+        * to watchdog will toggle from 0 to 1.
+        */
+       if (tb & wdt_tb)
+               wdt_ticks = wdt_tb;
+
+       wdt_ticks += wdt_tb - (tb & (wdt_tb - 1));
+
+       /* Convert timebase ticks to jiffies */
+       nr_jiffies = wdt_ticks;
+
+       if (do_div(nr_jiffies, tb_ticks_per_jiffy))
+               nr_jiffies++;
+
+       return min_t(unsigned long long, nr_jiffies, NEXT_TIMER_MAX_DELTA);
+}
+
+static void arm_next_watchdog(struct kvm_vcpu *vcpu)
+{
+       unsigned long nr_jiffies;
+       unsigned long flags;
+
+       /*
+        * If TSR_ENW and TSR_WIS are not set then no need to exit to
+        * userspace, so clear the KVM_REQ_WATCHDOG request.
+        */
+       if ((vcpu->arch.tsr & (TSR_ENW | TSR_WIS)) != (TSR_ENW | TSR_WIS))
+               clear_bit(KVM_REQ_WATCHDOG, &vcpu->requests);
+
+       spin_lock_irqsave(&vcpu->arch.wdt_lock, flags);
+       nr_jiffies = watchdog_next_timeout(vcpu);
+       /*
+        * If the number of jiffies of watchdog timer >= NEXT_TIMER_MAX_DELTA
+        * then do not run the watchdog timer as this can break timer APIs.
+        */
+       if (nr_jiffies < NEXT_TIMER_MAX_DELTA)
+               mod_timer(&vcpu->arch.wdt_timer, jiffies + nr_jiffies);
+       else
+               del_timer(&vcpu->arch.wdt_timer);
+       spin_unlock_irqrestore(&vcpu->arch.wdt_lock, flags);
+}
+
+void kvmppc_watchdog_func(unsigned long data)
+{
+       struct kvm_vcpu *vcpu = (struct kvm_vcpu *)data;
+       u32 tsr, new_tsr;
+       int final;
+
+       do {
+               new_tsr = tsr = vcpu->arch.tsr;
+               final = 0;
+
+               /* Time out event */
+               if (tsr & TSR_ENW) {
+                       if (tsr & TSR_WIS)
+                               final = 1;
+                       else
+                               new_tsr = tsr | TSR_WIS;
+               } else {
+                       new_tsr = tsr | TSR_ENW;
+               }
+       } while (cmpxchg(&vcpu->arch.tsr, tsr, new_tsr) != tsr);
+
+       if (new_tsr & TSR_WIS) {
+               smp_wmb();
+               kvm_make_request(KVM_REQ_PENDING_TIMER, vcpu);
+               kvm_vcpu_kick(vcpu);
+       }
+
+       /*
+        * If this is final watchdog expiry and some action is required
+        * then exit to userspace.
+        */
+       if (final && (vcpu->arch.tcr & TCR_WRC_MASK) &&
+           vcpu->arch.watchdog_enabled) {
+               smp_wmb();
+               kvm_make_request(KVM_REQ_WATCHDOG, vcpu);
+               kvm_vcpu_kick(vcpu);
+       }
+
+       /*
+        * Stop running the watchdog timer after final expiration to
+        * prevent the host from being flooded with timers if the
+        * guest sets a short period.
+        * Timers will resume when TSR/TCR is updated next time.
+        */
+       if (!final)
+               arm_next_watchdog(vcpu);
+}
+
 static void update_timer_ints(struct kvm_vcpu *vcpu)
 {
        if ((vcpu->arch.tcr & TCR_DIE) && (vcpu->arch.tsr & TSR_DIS))
                kvmppc_core_queue_dec(vcpu);
        else
                kvmppc_core_dequeue_dec(vcpu);
+
+       if ((vcpu->arch.tcr & TCR_WIE) && (vcpu->arch.tsr & TSR_WIS))
+               kvmppc_core_queue_watchdog(vcpu);
+       else
+               kvmppc_core_dequeue_watchdog(vcpu);
 }
 
 static void kvmppc_core_check_exceptions(struct kvm_vcpu *vcpu)
@@ -417,13 +551,6 @@ static void kvmppc_core_check_exceptions(struct kvm_vcpu *vcpu)
        unsigned long *pending = &vcpu->arch.pending_exceptions;
        unsigned int priority;
 
-       if (vcpu->requests) {
-               if (kvm_check_request(KVM_REQ_PENDING_TIMER, vcpu)) {
-                       smp_mb();
-                       update_timer_ints(vcpu);
-               }
-       }
-
        priority = __ffs(*pending);
        while (priority < BOOKE_IRQPRIO_MAX) {
                if (kvmppc_booke_irqprio_deliver(vcpu, priority))
@@ -459,37 +586,20 @@ int kvmppc_core_prepare_to_enter(struct kvm_vcpu *vcpu)
        return r;
 }
 
-/*
- * Common checks before entering the guest world.  Call with interrupts
- * disabled.
- *
- * returns !0 if a signal is pending and check_signal is true
- */
-static int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu)
+int kvmppc_core_check_requests(struct kvm_vcpu *vcpu)
 {
-       int r = 0;
-
-       WARN_ON_ONCE(!irqs_disabled());
-       while (true) {
-               if (need_resched()) {
-                       local_irq_enable();
-                       cond_resched();
-                       local_irq_disable();
-                       continue;
-               }
-
-               if (signal_pending(current)) {
-                       r = 1;
-                       break;
-               }
+       int r = 1; /* Indicate we want to get back into the guest */
 
-               if (kvmppc_core_prepare_to_enter(vcpu)) {
-                       /* interrupts got enabled in between, so we
-                          are back at square 1 */
-                       continue;
-               }
+       if (kvm_check_request(KVM_REQ_PENDING_TIMER, vcpu))
+               update_timer_ints(vcpu);
+#if defined(CONFIG_KVM_E500V2) || defined(CONFIG_KVM_E500MC)
+       if (kvm_check_request(KVM_REQ_TLB_FLUSH, vcpu))
+               kvmppc_core_flush_tlb(vcpu);
+#endif
 
-               break;
+       if (kvm_check_request(KVM_REQ_WATCHDOG, vcpu)) {
+               vcpu->run->exit_reason = KVM_EXIT_WATCHDOG;
+               r = 0;
        }
 
        return r;
@@ -497,7 +607,7 @@ static int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu)
 
 int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 {
-       int ret;
+       int ret, s;
 #ifdef CONFIG_PPC_FPU
        unsigned int fpscr;
        int fpexc_mode;
@@ -510,11 +620,13 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
        }
 
        local_irq_disable();
-       if (kvmppc_prepare_to_enter(vcpu)) {
-               kvm_run->exit_reason = KVM_EXIT_INTR;
-               ret = -EINTR;
+       s = kvmppc_prepare_to_enter(vcpu);
+       if (s <= 0) {
+               local_irq_enable();
+               ret = s;
                goto out;
        }
+       kvmppc_lazy_ee_enable();
 
        kvm_guest_enter();
 
@@ -542,6 +654,9 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 
        ret = __kvmppc_vcpu_run(kvm_run, vcpu);
 
+       /* No need for kvm_guest_exit. It's done in handle_exit.
+          We also get here with interrupts enabled. */
+
 #ifdef CONFIG_PPC_FPU
        kvmppc_save_guest_fp(vcpu);
 
@@ -557,10 +672,9 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
        current->thread.fpexc_mode = fpexc_mode;
 #endif
 
-       kvm_guest_exit();
-
 out:
-       local_irq_enable();
+       vcpu->mode = OUTSIDE_GUEST_MODE;
+       smp_wmb();
        return ret;
 }
 
@@ -668,6 +782,7 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
                        unsigned int exit_nr)
 {
        int r = RESUME_HOST;
+       int s;
 
        /* update before a new last_exit_type is rewritten */
        kvmppc_update_timing_stats(vcpu);
@@ -677,6 +792,9 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
 
        local_irq_enable();
 
+       trace_kvm_exit(exit_nr, vcpu);
+       kvm_guest_exit();
+
        run->exit_reason = KVM_EXIT_UNKNOWN;
        run->ready_for_interrupt_injection = 1;
 
@@ -971,10 +1089,12 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
         */
        if (!(r & RESUME_HOST)) {
                local_irq_disable();
-               if (kvmppc_prepare_to_enter(vcpu)) {
-                       run->exit_reason = KVM_EXIT_INTR;
-                       r = (-EINTR << 2) | RESUME_HOST | (r & RESUME_FLAG_NV);
-                       kvmppc_account_exit(vcpu, SIGNAL_EXITS);
+               s = kvmppc_prepare_to_enter(vcpu);
+               if (s <= 0) {
+                       local_irq_enable();
+                       r = (s << 2) | RESUME_HOST | (r & RESUME_FLAG_NV);
+               } else {
+                       kvmppc_lazy_ee_enable();
                }
        }
 
@@ -1011,6 +1131,21 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
        return r;
 }
 
+int kvmppc_subarch_vcpu_init(struct kvm_vcpu *vcpu)
+{
+       /* setup watchdog timer once */
+       spin_lock_init(&vcpu->arch.wdt_lock);
+       setup_timer(&vcpu->arch.wdt_timer, kvmppc_watchdog_func,
+                   (unsigned long)vcpu);
+
+       return 0;
+}
+
+void kvmppc_subarch_vcpu_uninit(struct kvm_vcpu *vcpu)
+{
+       del_timer_sync(&vcpu->arch.wdt_timer);
+}
+
 int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
 {
        int i;
@@ -1106,7 +1241,13 @@ static int set_sregs_base(struct kvm_vcpu *vcpu,
        }
 
        if (sregs->u.e.update_special & KVM_SREGS_E_UPDATE_TSR) {
+               u32 old_tsr = vcpu->arch.tsr;
+
                vcpu->arch.tsr = sregs->u.e.tsr;
+
+               if ((old_tsr ^ vcpu->arch.tsr) & (TSR_ENW | TSR_WIS))
+                       arm_next_watchdog(vcpu);
+
                update_timer_ints(vcpu);
        }
 
@@ -1221,12 +1362,56 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
 
 int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
 {
-       return -EINVAL;
+       int r = -EINVAL;
+
+       switch (reg->id) {
+       case KVM_REG_PPC_IAC1:
+       case KVM_REG_PPC_IAC2:
+       case KVM_REG_PPC_IAC3:
+       case KVM_REG_PPC_IAC4: {
+               int iac = reg->id - KVM_REG_PPC_IAC1;
+               r = copy_to_user((u64 __user *)(long)reg->addr,
+                                &vcpu->arch.dbg_reg.iac[iac], sizeof(u64));
+               break;
+       }
+       case KVM_REG_PPC_DAC1:
+       case KVM_REG_PPC_DAC2: {
+               int dac = reg->id - KVM_REG_PPC_DAC1;
+               r = copy_to_user((u64 __user *)(long)reg->addr,
+                                &vcpu->arch.dbg_reg.dac[dac], sizeof(u64));
+               break;
+       }
+       default:
+               break;
+       }
+       return r;
 }
 
 int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
 {
-       return -EINVAL;
+       int r = -EINVAL;
+
+       switch (reg->id) {
+       case KVM_REG_PPC_IAC1:
+       case KVM_REG_PPC_IAC2:
+       case KVM_REG_PPC_IAC3:
+       case KVM_REG_PPC_IAC4: {
+               int iac = reg->id - KVM_REG_PPC_IAC1;
+               r = copy_from_user(&vcpu->arch.dbg_reg.iac[iac],
+                            (u64 __user *)(long)reg->addr, sizeof(u64));
+               break;
+       }
+       case KVM_REG_PPC_DAC1:
+       case KVM_REG_PPC_DAC2: {
+               int dac = reg->id - KVM_REG_PPC_DAC1;
+               r = copy_from_user(&vcpu->arch.dbg_reg.dac[dac],
+                            (u64 __user *)(long)reg->addr, sizeof(u64));
+               break;
+       }
+       default:
+               break;
+       }
+       return r;
 }
 
 int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
@@ -1267,6 +1452,7 @@ void kvmppc_core_commit_memory_region(struct kvm *kvm,
 void kvmppc_set_tcr(struct kvm_vcpu *vcpu, u32 new_tcr)
 {
        vcpu->arch.tcr = new_tcr;
+       arm_next_watchdog(vcpu);
        update_timer_ints(vcpu);
 }
 
@@ -1281,6 +1467,14 @@ void kvmppc_set_tsr_bits(struct kvm_vcpu *vcpu, u32 tsr_bits)
 void kvmppc_clr_tsr_bits(struct kvm_vcpu *vcpu, u32 tsr_bits)
 {
        clear_bits(tsr_bits, &vcpu->arch.tsr);
+
+       /*
+        * We may have stopped the watchdog due to
+        * being stuck on final expiration.
+        */
+       if (tsr_bits & (TSR_ENW | TSR_WIS))
+               arm_next_watchdog(vcpu);
+
        update_timer_ints(vcpu);
 }
 
index 12834bb608aba1e41653fa6aaa96f0735d587b80..514790f41abafa9c752ebdaa90bde9f1e961423f 100644 (file)
@@ -133,10 +133,10 @@ int kvmppc_booke_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, ulong spr_val)
                vcpu->arch.csrr1 = spr_val;
                break;
        case SPRN_DBCR0:
-               vcpu->arch.dbcr0 = spr_val;
+               vcpu->arch.dbg_reg.dbcr0 = spr_val;
                break;
        case SPRN_DBCR1:
-               vcpu->arch.dbcr1 = spr_val;
+               vcpu->arch.dbg_reg.dbcr1 = spr_val;
                break;
        case SPRN_DBSR:
                vcpu->arch.dbsr &= ~spr_val;
@@ -145,6 +145,14 @@ int kvmppc_booke_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, ulong spr_val)
                kvmppc_clr_tsr_bits(vcpu, spr_val);
                break;
        case SPRN_TCR:
+               /*
+                * WRC is a 2-bit field that is supposed to preserve its
+                * value once written to non-zero.
+                */
+               if (vcpu->arch.tcr & TCR_WRC_MASK) {
+                       spr_val &= ~TCR_WRC_MASK;
+                       spr_val |= vcpu->arch.tcr & TCR_WRC_MASK;
+               }
                kvmppc_set_tcr(vcpu, spr_val);
                break;
 
@@ -229,6 +237,9 @@ int kvmppc_booke_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, ulong spr_val)
        case SPRN_IVOR15:
                vcpu->arch.ivor[BOOKE_IRQPRIO_DEBUG] = spr_val;
                break;
+       case SPRN_MCSR:
+               vcpu->arch.mcsr &= ~spr_val;
+               break;
 
        default:
                emulated = EMULATE_FAIL;
@@ -258,10 +269,10 @@ int kvmppc_booke_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, ulong *spr_val)
                *spr_val = vcpu->arch.csrr1;
                break;
        case SPRN_DBCR0:
-               *spr_val = vcpu->arch.dbcr0;
+               *spr_val = vcpu->arch.dbg_reg.dbcr0;
                break;
        case SPRN_DBCR1:
-               *spr_val = vcpu->arch.dbcr1;
+               *spr_val = vcpu->arch.dbg_reg.dbcr1;
                break;
        case SPRN_DBSR:
                *spr_val = vcpu->arch.dbsr;
@@ -321,6 +332,9 @@ int kvmppc_booke_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, ulong *spr_val)
        case SPRN_IVOR15:
                *spr_val = vcpu->arch.ivor[BOOKE_IRQPRIO_DEBUG];
                break;
+       case SPRN_MCSR:
+               *spr_val = vcpu->arch.mcsr;
+               break;
 
        default:
                emulated = EMULATE_FAIL;
index aa8b81428bf4afd168a1a2e8fa40da83f180b860..d1622864549ecc6b03c26bb1bde194a9ce691237 100644 (file)
@@ -27,8 +27,7 @@
 #define E500_TLB_NUM   2
 
 #define E500_TLB_VALID 1
-#define E500_TLB_DIRTY 2
-#define E500_TLB_BITMAP 4
+#define E500_TLB_BITMAP 2
 
 struct tlbe_ref {
        pfn_t pfn;
index c510fc961302c2d1ae1284cc3d1aab1139002fbd..43489a8fa98561eb6a8d7ecc1b351a94b6ff731d 100644 (file)
@@ -304,17 +304,13 @@ static inline void kvmppc_e500_ref_setup(struct tlbe_ref *ref,
        ref->flags = E500_TLB_VALID;
 
        if (tlbe_is_writable(gtlbe))
-               ref->flags |= E500_TLB_DIRTY;
+               kvm_set_pfn_dirty(pfn);
 }
 
 static inline void kvmppc_e500_ref_release(struct tlbe_ref *ref)
 {
        if (ref->flags & E500_TLB_VALID) {
-               if (ref->flags & E500_TLB_DIRTY)
-                       kvm_release_pfn_dirty(ref->pfn);
-               else
-                       kvm_release_pfn_clean(ref->pfn);
-
+               trace_kvm_booke206_ref_release(ref->pfn, ref->flags);
                ref->flags = 0;
        }
 }
@@ -322,11 +318,11 @@ static inline void kvmppc_e500_ref_release(struct tlbe_ref *ref)
 static void clear_tlb1_bitmap(struct kvmppc_vcpu_e500 *vcpu_e500)
 {
        if (vcpu_e500->g2h_tlb1_map)
-               memset(vcpu_e500->g2h_tlb1_map,
-                      sizeof(u64) * vcpu_e500->gtlb_params[1].entries, 0);
+               memset(vcpu_e500->g2h_tlb1_map, 0,
+                      sizeof(u64) * vcpu_e500->gtlb_params[1].entries);
        if (vcpu_e500->h2g_tlb1_rmap)
-               memset(vcpu_e500->h2g_tlb1_rmap,
-                      sizeof(unsigned int) * host_tlb_params[1].entries, 0);
+               memset(vcpu_e500->h2g_tlb1_rmap, 0,
+                      sizeof(unsigned int) * host_tlb_params[1].entries);
 }
 
 static void clear_tlb_privs(struct kvmppc_vcpu_e500 *vcpu_e500)
@@ -357,6 +353,13 @@ static void clear_tlb_refs(struct kvmppc_vcpu_e500 *vcpu_e500)
        clear_tlb_privs(vcpu_e500);
 }
 
+void kvmppc_core_flush_tlb(struct kvm_vcpu *vcpu)
+{
+       struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
+       clear_tlb_refs(vcpu_e500);
+       clear_tlb1_bitmap(vcpu_e500);
+}
+
 static inline void kvmppc_e500_deliver_tlb_miss(struct kvm_vcpu *vcpu,
                unsigned int eaddr, int as)
 {
@@ -520,11 +523,10 @@ static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
 
        if (likely(!pfnmap)) {
                unsigned long tsize_pages = 1 << (tsize + 10 - PAGE_SHIFT);
-               pfn = gfn_to_pfn_memslot(vcpu_e500->vcpu.kvm, slot, gfn);
+               pfn = gfn_to_pfn_memslot(slot, gfn);
                if (is_error_pfn(pfn)) {
                        printk(KERN_ERR "Couldn't get real page for gfn %lx!\n",
                                        (long)gfn);
-                       kvm_release_pfn_clean(pfn);
                        return;
                }
 
@@ -539,6 +541,12 @@ static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
 
        kvmppc_e500_setup_stlbe(&vcpu_e500->vcpu, gtlbe, tsize,
                                ref, gvaddr, stlbe);
+
+       /* Clear i-cache for new pages */
+       kvmppc_mmu_flush_icache(pfn);
+
+       /* Drop refcount on page, so that mmu notifiers can clear it */
+       kvm_release_pfn_clean(pfn);
 }
 
 /* XXX only map the one-one case, for now use TLB0 */
@@ -1037,8 +1045,12 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr,
                sesel = 0; /* unused */
                priv = &vcpu_e500->gtlb_priv[tlbsel][esel];
 
-               kvmppc_e500_setup_stlbe(vcpu, gtlbe, BOOK3E_PAGESZ_4K,
-                                       &priv->ref, eaddr, &stlbe);
+               /* Only triggers after clear_tlb_refs */
+               if (unlikely(!(priv->ref.flags & E500_TLB_VALID)))
+                       kvmppc_e500_tlb0_map(vcpu_e500, esel, &stlbe);
+               else
+                       kvmppc_e500_setup_stlbe(vcpu, gtlbe, BOOK3E_PAGESZ_4K,
+                                               &priv->ref, eaddr, &stlbe);
                break;
 
        case 1: {
@@ -1058,6 +1070,49 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr,
        write_stlbe(vcpu_e500, gtlbe, &stlbe, stlbsel, sesel);
 }
 
+/************* MMU Notifiers *************/
+
+int kvm_unmap_hva(struct kvm *kvm, unsigned long hva)
+{
+       trace_kvm_unmap_hva(hva);
+
+       /*
+        * Flush all shadow tlb entries everywhere. This is slow, but
+        * we are 100% sure that we catch the to be unmapped page
+        */
+       kvm_flush_remote_tlbs(kvm);
+
+       return 0;
+}
+
+int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end)
+{
+       /* kvm_unmap_hva flushes everything anyways */
+       kvm_unmap_hva(kvm, start);
+
+       return 0;
+}
+
+int kvm_age_hva(struct kvm *kvm, unsigned long hva)
+{
+       /* XXX could be more clever ;) */
+       return 0;
+}
+
+int kvm_test_age_hva(struct kvm *kvm, unsigned long hva)
+{
+       /* XXX could be more clever ;) */
+       return 0;
+}
+
+void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte)
+{
+       /* The page will get remapped properly on its next fault */
+       kvm_unmap_hva(kvm, hva);
+}
+
+/*****************************************/
+
 static void free_gtlb(struct kvmppc_vcpu_e500 *vcpu_e500)
 {
        int i;
index 87f4dc886076d3ad2d6ecede5dfbe1990cd568e0..32d217c8b3f92c2fd537b7aefd588f6af9ec6cea 100644 (file)
@@ -30,6 +30,7 @@
 #include <asm/kvm_ppc.h>
 #include <asm/tlbflush.h>
 #include <asm/cputhreads.h>
+#include <asm/irqflags.h>
 #include "timing.h"
 #include "../mm/mmu_decl.h"
 
@@ -38,8 +39,7 @@
 
 int kvm_arch_vcpu_runnable(struct kvm_vcpu *v)
 {
-       return !(v->arch.shared->msr & MSR_WE) ||
-              !!(v->arch.pending_exceptions) ||
+       return !!(v->arch.pending_exceptions) ||
               v->requests;
 }
 
@@ -48,6 +48,81 @@ int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
        return 1;
 }
 
+#ifndef CONFIG_KVM_BOOK3S_64_HV
+/*
+ * Common checks before entering the guest world.  Call with interrupts
+ * disabled.
+ *
+ * returns:
+ *
+ * == 1 if we're ready to go into guest state
+ * <= 0 if we need to go back to the host with return value
+ */
+int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu)
+{
+       int r = 1;
+
+       WARN_ON_ONCE(!irqs_disabled());
+       while (true) {
+               if (need_resched()) {
+                       local_irq_enable();
+                       cond_resched();
+                       local_irq_disable();
+                       continue;
+               }
+
+               if (signal_pending(current)) {
+                       kvmppc_account_exit(vcpu, SIGNAL_EXITS);
+                       vcpu->run->exit_reason = KVM_EXIT_INTR;
+                       r = -EINTR;
+                       break;
+               }
+
+               smp_mb();
+               if (vcpu->requests) {
+                       /* Make sure we process requests preemptable */
+                       local_irq_enable();
+                       trace_kvm_check_requests(vcpu);
+                       r = kvmppc_core_check_requests(vcpu);
+                       local_irq_disable();
+                       if (r > 0)
+                               continue;
+                       break;
+               }
+
+               if (kvmppc_core_prepare_to_enter(vcpu)) {
+                       /* interrupts got enabled in between, so we
+                          are back at square 1 */
+                       continue;
+               }
+
+#ifdef CONFIG_PPC64
+               /* lazy EE magic */
+               hard_irq_disable();
+               if (lazy_irq_pending()) {
+                       /* Got an interrupt in between, try again */
+                       local_irq_enable();
+                       local_irq_disable();
+                       kvm_guest_exit();
+                       continue;
+               }
+
+               trace_hardirqs_on();
+#endif
+
+               kvm_guest_enter();
+
+               /* Going into guest context! Yay! */
+               vcpu->mode = IN_GUEST_MODE;
+               smp_wmb();
+
+               break;
+       }
+
+       return r;
+}
+#endif /* CONFIG_KVM_BOOK3S_64_HV */
+
 int kvmppc_kvm_pv(struct kvm_vcpu *vcpu)
 {
        int nr = kvmppc_get_gpr(vcpu, 11);
@@ -67,18 +142,18 @@ int kvmppc_kvm_pv(struct kvm_vcpu *vcpu)
        }
 
        switch (nr) {
-       case HC_VENDOR_KVM | KVM_HC_PPC_MAP_MAGIC_PAGE:
+       case KVM_HCALL_TOKEN(KVM_HC_PPC_MAP_MAGIC_PAGE):
        {
                vcpu->arch.magic_page_pa = param1;
                vcpu->arch.magic_page_ea = param2;
 
                r2 = KVM_MAGIC_FEAT_SR | KVM_MAGIC_FEAT_MAS0_TO_SPRG7;
 
-               r = HC_EV_SUCCESS;
+               r = EV_SUCCESS;
                break;
        }
-       case HC_VENDOR_KVM | KVM_HC_FEATURES:
-               r = HC_EV_SUCCESS;
+       case KVM_HCALL_TOKEN(KVM_HC_FEATURES):
+               r = EV_SUCCESS;
 #if defined(CONFIG_PPC_BOOK3S) || defined(CONFIG_KVM_E500V2)
                /* XXX Missing magic page on 44x */
                r2 |= (1 << KVM_FEATURE_MAGIC_PAGE);
@@ -86,8 +161,13 @@ int kvmppc_kvm_pv(struct kvm_vcpu *vcpu)
 
                /* Second return value is in r4 */
                break;
+       case EV_HCALL_TOKEN(EV_IDLE):
+               r = EV_SUCCESS;
+               kvm_vcpu_block(vcpu);
+               clear_bit(KVM_REQ_UNHALT, &vcpu->requests);
+               break;
        default:
-               r = HC_EV_UNIMPLEMENTED;
+               r = EV_UNIMPLEMENTED;
                break;
        }
 
@@ -220,6 +300,7 @@ int kvm_dev_ioctl_check_extension(long ext)
        switch (ext) {
 #ifdef CONFIG_BOOKE
        case KVM_CAP_PPC_BOOKE_SREGS:
+       case KVM_CAP_PPC_BOOKE_WATCHDOG:
 #else
        case KVM_CAP_PPC_SEGSTATE:
        case KVM_CAP_PPC_HIOR:
@@ -260,10 +341,16 @@ int kvm_dev_ioctl_check_extension(long ext)
                if (cpu_has_feature(CPU_FTR_ARCH_201))
                        r = 2;
                break;
+#endif
        case KVM_CAP_SYNC_MMU:
+#ifdef CONFIG_KVM_BOOK3S_64_HV
                r = cpu_has_feature(CPU_FTR_ARCH_206) ? 1 : 0;
-               break;
+#elif defined(KVM_ARCH_WANT_MMU_NOTIFIER)
+               r = 1;
+#else
+               r = 0;
 #endif
+               break;
        case KVM_CAP_NR_VCPUS:
                /*
                 * Recommending a number of CPUs is somewhat arbitrary; we
@@ -302,10 +389,18 @@ long kvm_arch_dev_ioctl(struct file *filp,
 void kvm_arch_free_memslot(struct kvm_memory_slot *free,
                           struct kvm_memory_slot *dont)
 {
+       if (!dont || free->arch.rmap != dont->arch.rmap) {
+               vfree(free->arch.rmap);
+               free->arch.rmap = NULL;
+       }
 }
 
 int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages)
 {
+       slot->arch.rmap = vzalloc(npages * sizeof(*slot->arch.rmap));
+       if (!slot->arch.rmap)
+               return -ENOMEM;
+
        return 0;
 }
 
@@ -378,6 +473,8 @@ enum hrtimer_restart kvmppc_decrementer_wakeup(struct hrtimer *timer)
 
 int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
 {
+       int ret;
+
        hrtimer_init(&vcpu->arch.dec_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
        tasklet_init(&vcpu->arch.tasklet, kvmppc_decrementer_func, (ulong)vcpu);
        vcpu->arch.dec_timer.function = kvmppc_decrementer_wakeup;
@@ -386,13 +483,14 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
 #ifdef CONFIG_KVM_EXIT_TIMING
        mutex_init(&vcpu->arch.exit_timing_lock);
 #endif
-
-       return 0;
+       ret = kvmppc_subarch_vcpu_init(vcpu);
+       return ret;
 }
 
 void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
 {
        kvmppc_mmu_destroy(vcpu);
+       kvmppc_subarch_vcpu_uninit(vcpu);
 }
 
 void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
@@ -637,6 +735,12 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
                r = 0;
                vcpu->arch.papr_enabled = true;
                break;
+#ifdef CONFIG_BOOKE
+       case KVM_CAP_PPC_BOOKE_WATCHDOG:
+               r = 0;
+               vcpu->arch.watchdog_enabled = true;
+               break;
+#endif
 #if defined(CONFIG_KVM_E500V2) || defined(CONFIG_KVM_E500MC)
        case KVM_CAP_SW_TLB: {
                struct kvm_config_tlb cfg;
@@ -739,9 +843,16 @@ int kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf)
 
 static int kvm_vm_ioctl_get_pvinfo(struct kvm_ppc_pvinfo *pvinfo)
 {
+       u32 inst_nop = 0x60000000;
+#ifdef CONFIG_KVM_BOOKE_HV
+       u32 inst_sc1 = 0x44000022;
+       pvinfo->hcall[0] = inst_sc1;
+       pvinfo->hcall[1] = inst_nop;
+       pvinfo->hcall[2] = inst_nop;
+       pvinfo->hcall[3] = inst_nop;
+#else
        u32 inst_lis = 0x3c000000;
        u32 inst_ori = 0x60000000;
-       u32 inst_nop = 0x60000000;
        u32 inst_sc = 0x44000002;
        u32 inst_imm_mask = 0xffff;
 
@@ -758,6 +869,9 @@ static int kvm_vm_ioctl_get_pvinfo(struct kvm_ppc_pvinfo *pvinfo)
        pvinfo->hcall[1] = inst_ori | (KVM_SC_MAGIC_R0 & inst_imm_mask);
        pvinfo->hcall[2] = inst_sc;
        pvinfo->hcall[3] = inst_nop;
+#endif
+
+       pvinfo->flags = KVM_PPC_PVINFO_FLAGS_EV_IDLE;
 
        return 0;
 }
index 877186b7b1c360c5deae3905b076166f6843e21c..519aba8bb3d38e5cf227c346cc57f4d855a3ae6c 100644 (file)
@@ -31,6 +31,126 @@ TRACE_EVENT(kvm_ppc_instr,
                  __entry->inst, __entry->pc, __entry->emulate)
 );
 
+#ifdef CONFIG_PPC_BOOK3S
+#define kvm_trace_symbol_exit \
+       {0x100, "SYSTEM_RESET"}, \
+       {0x200, "MACHINE_CHECK"}, \
+       {0x300, "DATA_STORAGE"}, \
+       {0x380, "DATA_SEGMENT"}, \
+       {0x400, "INST_STORAGE"}, \
+       {0x480, "INST_SEGMENT"}, \
+       {0x500, "EXTERNAL"}, \
+       {0x501, "EXTERNAL_LEVEL"}, \
+       {0x502, "EXTERNAL_HV"}, \
+       {0x600, "ALIGNMENT"}, \
+       {0x700, "PROGRAM"}, \
+       {0x800, "FP_UNAVAIL"}, \
+       {0x900, "DECREMENTER"}, \
+       {0x980, "HV_DECREMENTER"}, \
+       {0xc00, "SYSCALL"}, \
+       {0xd00, "TRACE"}, \
+       {0xe00, "H_DATA_STORAGE"}, \
+       {0xe20, "H_INST_STORAGE"}, \
+       {0xe40, "H_EMUL_ASSIST"}, \
+       {0xf00, "PERFMON"}, \
+       {0xf20, "ALTIVEC"}, \
+       {0xf40, "VSX"}
+#else
+#define kvm_trace_symbol_exit \
+       {0, "CRITICAL"}, \
+       {1, "MACHINE_CHECK"}, \
+       {2, "DATA_STORAGE"}, \
+       {3, "INST_STORAGE"}, \
+       {4, "EXTERNAL"}, \
+       {5, "ALIGNMENT"}, \
+       {6, "PROGRAM"}, \
+       {7, "FP_UNAVAIL"}, \
+       {8, "SYSCALL"}, \
+       {9, "AP_UNAVAIL"}, \
+       {10, "DECREMENTER"}, \
+       {11, "FIT"}, \
+       {12, "WATCHDOG"}, \
+       {13, "DTLB_MISS"}, \
+       {14, "ITLB_MISS"}, \
+       {15, "DEBUG"}, \
+       {32, "SPE_UNAVAIL"}, \
+       {33, "SPE_FP_DATA"}, \
+       {34, "SPE_FP_ROUND"}, \
+       {35, "PERFORMANCE_MONITOR"}, \
+       {36, "DOORBELL"}, \
+       {37, "DOORBELL_CRITICAL"}, \
+       {38, "GUEST_DBELL"}, \
+       {39, "GUEST_DBELL_CRIT"}, \
+       {40, "HV_SYSCALL"}, \
+       {41, "HV_PRIV"}
+#endif
+
+TRACE_EVENT(kvm_exit,
+       TP_PROTO(unsigned int exit_nr, struct kvm_vcpu *vcpu),
+       TP_ARGS(exit_nr, vcpu),
+
+       TP_STRUCT__entry(
+               __field(        unsigned int,   exit_nr         )
+               __field(        unsigned long,  pc              )
+               __field(        unsigned long,  msr             )
+               __field(        unsigned long,  dar             )
+#ifdef CONFIG_KVM_BOOK3S_PR
+               __field(        unsigned long,  srr1            )
+#endif
+               __field(        unsigned long,  last_inst       )
+       ),
+
+       TP_fast_assign(
+#ifdef CONFIG_KVM_BOOK3S_PR
+               struct kvmppc_book3s_shadow_vcpu *svcpu;
+#endif
+               __entry->exit_nr        = exit_nr;
+               __entry->pc             = kvmppc_get_pc(vcpu);
+               __entry->dar            = kvmppc_get_fault_dar(vcpu);
+               __entry->msr            = vcpu->arch.shared->msr;
+#ifdef CONFIG_KVM_BOOK3S_PR
+               svcpu = svcpu_get(vcpu);
+               __entry->srr1           = svcpu->shadow_srr1;
+               svcpu_put(svcpu);
+#endif
+               __entry->last_inst      = vcpu->arch.last_inst;
+       ),
+
+       TP_printk("exit=%s"
+               " | pc=0x%lx"
+               " | msr=0x%lx"
+               " | dar=0x%lx"
+#ifdef CONFIG_KVM_BOOK3S_PR
+               " | srr1=0x%lx"
+#endif
+               " | last_inst=0x%lx"
+               ,
+               __print_symbolic(__entry->exit_nr, kvm_trace_symbol_exit),
+               __entry->pc,
+               __entry->msr,
+               __entry->dar,
+#ifdef CONFIG_KVM_BOOK3S_PR
+               __entry->srr1,
+#endif
+               __entry->last_inst
+               )
+);
+
+TRACE_EVENT(kvm_unmap_hva,
+       TP_PROTO(unsigned long hva),
+       TP_ARGS(hva),
+
+       TP_STRUCT__entry(
+               __field(        unsigned long,  hva             )
+       ),
+
+       TP_fast_assign(
+               __entry->hva            = hva;
+       ),
+
+       TP_printk("unmap hva 0x%lx\n", __entry->hva)
+);
+
 TRACE_EVENT(kvm_stlb_inval,
        TP_PROTO(unsigned int stlb_index),
        TP_ARGS(stlb_index),
@@ -98,41 +218,31 @@ TRACE_EVENT(kvm_gtlb_write,
                __entry->word1, __entry->word2)
 );
 
-
-/*************************************************************************
- *                         Book3S trace points                           *
- *************************************************************************/
-
-#ifdef CONFIG_KVM_BOOK3S_PR
-
-TRACE_EVENT(kvm_book3s_exit,
-       TP_PROTO(unsigned int exit_nr, struct kvm_vcpu *vcpu),
-       TP_ARGS(exit_nr, vcpu),
+TRACE_EVENT(kvm_check_requests,
+       TP_PROTO(struct kvm_vcpu *vcpu),
+       TP_ARGS(vcpu),
 
        TP_STRUCT__entry(
-               __field(        unsigned int,   exit_nr         )
-               __field(        unsigned long,  pc              )
-               __field(        unsigned long,  msr             )
-               __field(        unsigned long,  dar             )
-               __field(        unsigned long,  srr1            )
+               __field(        __u32,  cpu_nr          )
+               __field(        __u32,  requests        )
        ),
 
        TP_fast_assign(
-               struct kvmppc_book3s_shadow_vcpu *svcpu;
-               __entry->exit_nr        = exit_nr;
-               __entry->pc             = kvmppc_get_pc(vcpu);
-               __entry->dar            = kvmppc_get_fault_dar(vcpu);
-               __entry->msr            = vcpu->arch.shared->msr;
-               svcpu = svcpu_get(vcpu);
-               __entry->srr1           = svcpu->shadow_srr1;
-               svcpu_put(svcpu);
+               __entry->cpu_nr         = vcpu->vcpu_id;
+               __entry->requests       = vcpu->requests;
        ),
 
-       TP_printk("exit=0x%x | pc=0x%lx | msr=0x%lx | dar=0x%lx | srr1=0x%lx",
-                 __entry->exit_nr, __entry->pc, __entry->msr, __entry->dar,
-                 __entry->srr1)
+       TP_printk("vcpu=%x requests=%x",
+               __entry->cpu_nr, __entry->requests)
 );
 
+
+/*************************************************************************
+ *                         Book3S trace points                           *
+ *************************************************************************/
+
+#ifdef CONFIG_KVM_BOOK3S_PR
+
 TRACE_EVENT(kvm_book3s_reenter,
        TP_PROTO(int r, struct kvm_vcpu *vcpu),
        TP_ARGS(r, vcpu),
@@ -395,6 +505,44 @@ TRACE_EVENT(kvm_booke206_gtlb_write,
                __entry->mas2, __entry->mas7_3)
 );
 
+TRACE_EVENT(kvm_booke206_ref_release,
+       TP_PROTO(__u64 pfn, __u32 flags),
+       TP_ARGS(pfn, flags),
+
+       TP_STRUCT__entry(
+               __field(        __u64,  pfn             )
+               __field(        __u32,  flags           )
+       ),
+
+       TP_fast_assign(
+               __entry->pfn            = pfn;
+               __entry->flags          = flags;
+       ),
+
+       TP_printk("pfn=%llx flags=%x",
+               __entry->pfn, __entry->flags)
+);
+
+TRACE_EVENT(kvm_booke_queue_irqprio,
+       TP_PROTO(struct kvm_vcpu *vcpu, unsigned int priority),
+       TP_ARGS(vcpu, priority),
+
+       TP_STRUCT__entry(
+               __field(        __u32,  cpu_nr          )
+               __field(        __u32,  priority                )
+               __field(        unsigned long,  pending         )
+       ),
+
+       TP_fast_assign(
+               __entry->cpu_nr         = vcpu->vcpu_id;
+               __entry->priority       = priority;
+               __entry->pending        = vcpu->arch.pending_exceptions;
+       ),
+
+       TP_printk("vcpu=%x prio=%x pending=%lx",
+               __entry->cpu_nr, __entry->priority, __entry->pending)
+);
+
 #endif
 
 #endif /* _TRACE_KVM_H */
index baaafde7d13596af850a9d7452e596d84a52935a..46814f1f4c914e7d8816f5e49cf7f05ab80fda12 100644 (file)
@@ -300,8 +300,7 @@ void __init mem_init(void)
        unsigned long reservedpages = 0, codesize, initsize, datasize, bsssize;
 
 #ifdef CONFIG_SWIOTLB
-       if (ppc_swiotlb_enable)
-               swiotlb_init(1);
+       swiotlb_init(0);
 #endif
 
        num_physpages = memblock_phys_mem_size() >> PAGE_SHIFT;
@@ -469,6 +468,7 @@ void flush_dcache_icache_page(struct page *page)
        __flush_dcache_icache_phys(page_to_pfn(page) << PAGE_SHIFT);
 #endif
 }
+EXPORT_SYMBOL(flush_dcache_icache_page);
 
 void clear_user_page(void *page, unsigned long vaddr, struct page *pg)
 {
index 9f6c33d63a42c207a80444650646c1b3a1af7d08..6bd89a0e0dead4dcf112baca8aca5a0380f84a8c 100644 (file)
@@ -21,7 +21,6 @@
  */
 
 #include <linux/init.h>
-#include <linux/memblock.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/rtc.h>
@@ -159,13 +158,8 @@ static void __init ppc47x_setup_arch(void)
 
        /* No need to check the DMA config as we /know/ our windows are all of
         * RAM.  Lets hope that doesn't change */
-#ifdef CONFIG_SWIOTLB
-       if ((memblock_end_of_DRAM() - 1) > 0xffffffff) {
-               ppc_swiotlb_enable = 1;
-               set_pci_dma_ops(&swiotlb_dma_ops);
-               ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb;
-       }
-#endif
+       swiotlb_detect_4g();
+
        ppc47x_smp_init();
 }
 
index c16999802ecff6a5b960a1ffae9fba5c83c60f1f..b62508b113dbf0c3ec7467a917b3e04f99be78bf 100644 (file)
@@ -2,6 +2,7 @@ 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 1d8700ff60b0ec1b35eb2f989ea8ef33e2992d07..9f771e05457c78f263843247c49588dae021e911 100644 (file)
@@ -54,14 +54,16 @@ static DEFINE_MUTEX(clocks_mutex);
 static struct clk *mpc5121_clk_get(struct device *dev, const char *id)
 {
        struct clk *p, *clk = ERR_PTR(-ENOENT);
-       int dev_match = 0;
-       int id_match = 0;
+       int dev_match;
+       int id_match;
 
        if (dev == NULL || id == NULL)
                return clk;
 
        mutex_lock(&clocks_mutex);
        list_for_each_entry(p, &clocks, node) {
+               dev_match = id_match = 0;
+
                if (dev == p->dev)
                        dev_match++;
                if (strcmp(id, p->name) == 0)
index cfe958e94e1ef6b741ef4783a0790f20adbb67fa..1650e090ef3ad5b97ac1bde0ae2e53b00edaf473 100644 (file)
@@ -191,8 +191,6 @@ mpc512x_valid_monitor_port(enum fsl_diu_monitor_port port)
 
 static struct fsl_diu_shared_fb __attribute__ ((__aligned__(8))) diu_shared_fb;
 
-#if defined(CONFIG_FB_FSL_DIU) || \
-    defined(CONFIG_FB_FSL_DIU_MODULE)
 static inline void mpc512x_free_bootmem(struct page *page)
 {
        __ClearPageReserved(page);
@@ -220,7 +218,6 @@ void mpc512x_release_bootmem(void)
        }
        diu_ops.release_bootmem = NULL;
 }
-#endif
 
 /*
  * Check if DIU was pre-initialized. If so, perform steps
@@ -323,15 +320,12 @@ void __init mpc512x_setup_diu(void)
                }
        }
 
-#if defined(CONFIG_FB_FSL_DIU) || \
-    defined(CONFIG_FB_FSL_DIU_MODULE)
        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)
index 1a046715e4615fdb469ae95b81a99ba855c87e5c..1d769a29249f846a444bee68819730b5d12496ea 100644 (file)
@@ -326,7 +326,7 @@ static int pmc_probe(struct platform_device *ofdev)
        const struct of_device_id *match;
        struct device_node *np = ofdev->dev.of_node;
        struct resource res;
-       struct pmc_type *type;
+       const struct pmc_type *type;
        int ret = 0;
 
        match = of_match_device(pmc_match, &ofdev->dev);
index 159c01e914635d3cc025a502e88767f0d679d286..02d02a09942d2e53cf064d48aedce863fabcd9f7 100644 (file)
@@ -104,6 +104,13 @@ config P1022_DS
        help
          This option enables support for the Freescale P1022DS reference board.
 
+config P1022_RDK
+       bool "Freescale / iVeia P1022 RDK"
+       select DEFAULT_UIMAGE
+       help
+         This option enables support for the Freescale / iVeia P1022RDK
+         reference board.
+
 config P1023_RDS
        bool "Freescale P1023 RDS"
        select DEFAULT_UIMAGE
@@ -254,6 +261,20 @@ config P5020_DS
        help
          This option enables support for the P5020 DS board
 
+config P5040_DS
+       bool "Freescale P5040 DS"
+       select DEFAULT_UIMAGE
+       select E500
+       select PPC_E500MC
+       select PHYS_64BIT
+       select SWIOTLB
+       select ARCH_REQUIRE_GPIOLIB
+       select GPIO_MPC8XXX
+       select HAS_RAPIDIO
+       select PPC_EPAPR_HV_PIC
+       help
+         This option enables support for the P5040 DS board
+
 config PPC_QEMU_E500
        bool "QEMU generic e500 platform"
        depends on EXPERIMENTAL
index 3dfe81175036bb794dc5f3648b22571d001a7c02..76f679cb04a0d4f78ee128edad6f84fff06d3337 100644 (file)
@@ -15,11 +15,13 @@ obj-$(CONFIG_MPC85xx_MDS) += mpc85xx_mds.o
 obj-$(CONFIG_MPC85xx_RDB) += mpc85xx_rdb.o
 obj-$(CONFIG_P1010_RDB)   += p1010rdb.o
 obj-$(CONFIG_P1022_DS)    += p1022_ds.o
+obj-$(CONFIG_P1022_RDK)   += p1022_rdk.o
 obj-$(CONFIG_P1023_RDS)   += p1023_rds.o
 obj-$(CONFIG_P2041_RDB)   += p2041_rdb.o corenet_ds.o
 obj-$(CONFIG_P3041_DS)    += p3041_ds.o corenet_ds.o
 obj-$(CONFIG_P4080_DS)    += p4080_ds.o corenet_ds.o
 obj-$(CONFIG_P5020_DS)    += p5020_ds.o corenet_ds.o
+obj-$(CONFIG_P5040_DS)    += p5040_ds.o corenet_ds.o
 obj-$(CONFIG_STX_GP3)    += stx_gp3.o
 obj-$(CONFIG_TQM85xx)    += tqm85xx.o
 obj-$(CONFIG_SBC8548)     += sbc8548.o
index 925b02874233fe52dc118eec691a334d3be5fde8..473d5738111979241857cf2a0e8b66ff6fd9cccf 100644 (file)
@@ -63,7 +63,9 @@ void __init corenet_ds_setup_arch(void)
 #ifdef CONFIG_PCI
        for_each_node_by_type(np, "pci") {
                if (of_device_is_compatible(np, "fsl,p4080-pcie") ||
-                   of_device_is_compatible(np, "fsl,qoriq-pcie-v2.2")) {
+                   of_device_is_compatible(np, "fsl,qoriq-pcie-v2.2") ||
+                   of_device_is_compatible(np, "fsl,qoriq-pcie-v2.3") ||
+                   of_device_is_compatible(np, "fsl,qoriq-pcie-v2.4")) {
                        fsl_add_bridge(np, 0);
                        hose = pci_find_hose_for_OF_device(np);
                        max = min(max, hose->dma_window_base_cur +
@@ -99,6 +101,12 @@ static const struct of_device_id of_device_ids[] __devinitconst = {
        {
                .compatible     = "fsl,qoriq-pcie-v2.2",
        },
+       {
+               .compatible     = "fsl,qoriq-pcie-v2.3",
+       },
+       {
+               .compatible     = "fsl,qoriq-pcie-v2.4",
+       },
        /* The following two are for the Freescale hypervisor */
        {
                .name           = "hypervisor",
index 6d3265fe7718c7ff71785329133013ec1382c979..56f8c8f674df108d46d4f69866475b26ae1f1476 100644 (file)
@@ -159,6 +159,7 @@ static void __init mpc85xx_ds_setup_arch(void)
        if (ppc_md.progress)
                ppc_md.progress("mpc85xx_ds_setup_arch()", 0);
 
+       swiotlb_detect_4g();
        mpc85xx_ds_pci_init();
        mpc85xx_smp_init();
 
diff --git a/arch/powerpc/platforms/85xx/p1022_rdk.c b/arch/powerpc/platforms/85xx/p1022_rdk.c
new file mode 100644 (file)
index 0000000..b3cf11b
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * P1022 RDK board specific routines
+ *
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * Author: Timur Tabi <timur@freescale.com>
+ *
+ * Based on p1022_ds.c
+ *
+ * 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/pci.h>
+#include <linux/of_platform.h>
+#include <linux/memblock.h>
+#include <asm/div64.h>
+#include <asm/mpic.h>
+#include <asm/swiotlb.h>
+
+#include <sysdev/fsl_soc.h>
+#include <sysdev/fsl_pci.h>
+#include <asm/udbg.h>
+#include <asm/fsl_guts.h>
+#include "smp.h"
+
+#include "mpc85xx.h"
+
+#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
+
+/* DIU Pixel Clock bits of the CLKDVDR Global Utilities register */
+#define CLKDVDR_PXCKEN         0x80000000
+#define CLKDVDR_PXCKINV                0x10000000
+#define CLKDVDR_PXCKDLY                0x06000000
+#define CLKDVDR_PXCLK_MASK     0x00FF0000
+
+/**
+ * p1022rdk_set_monitor_port: switch the output to a different monitor port
+ */
+static void p1022rdk_set_monitor_port(enum fsl_diu_monitor_port port)
+{
+       if (port != FSL_DIU_PORT_DVI) {
+               pr_err("p1022rdk: unsupported monitor port %i\n", port);
+               return;
+       }
+}
+
+/**
+ * p1022rdk_set_pixel_clock: program the DIU's clock
+ *
+ * @pixclock: the wavelength, in picoseconds, of the clock
+ */
+void p1022rdk_set_pixel_clock(unsigned int pixclock)
+{
+       struct device_node *guts_np = NULL;
+       struct ccsr_guts __iomem *guts;
+       unsigned long freq;
+       u64 temp;
+       u32 pxclk;
+
+       /* Map the global utilities registers. */
+       guts_np = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts");
+       if (!guts_np) {
+               pr_err("p1022rdk: missing global utilties device node\n");
+               return;
+       }
+
+       guts = of_iomap(guts_np, 0);
+       of_node_put(guts_np);
+       if (!guts) {
+               pr_err("p1022rdk: could not map global utilties device\n");
+               return;
+       }
+
+       /* Convert pixclock from a wavelength to a frequency */
+       temp = 1000000000000ULL;
+       do_div(temp, pixclock);
+       freq = temp;
+
+       /*
+        * 'pxclk' is the ratio of the platform clock to the pixel clock.
+        * This number is programmed into the CLKDVDR register, and the valid
+        * range of values is 2-255.
+        */
+       pxclk = DIV_ROUND_CLOSEST(fsl_get_sys_freq(), freq);
+       pxclk = clamp_t(u32, pxclk, 2, 255);
+
+       /* Disable the pixel clock, and set it to non-inverted and no delay */
+       clrbits32(&guts->clkdvdr,
+                 CLKDVDR_PXCKEN | CLKDVDR_PXCKDLY | CLKDVDR_PXCLK_MASK);
+
+       /* Enable the clock and set the pxclk */
+       setbits32(&guts->clkdvdr, CLKDVDR_PXCKEN | (pxclk << 16));
+
+       iounmap(guts);
+}
+
+/**
+ * p1022rdk_valid_monitor_port: set the monitor port for sysfs
+ */
+enum fsl_diu_monitor_port
+p1022rdk_valid_monitor_port(enum fsl_diu_monitor_port port)
+{
+       return FSL_DIU_PORT_DVI;
+}
+
+#endif
+
+void __init p1022_rdk_pic_init(void)
+{
+       struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN |
+               MPIC_SINGLE_DEST_CPU,
+               0, 256, " OpenPIC  ");
+       BUG_ON(mpic == NULL);
+       mpic_init(mpic);
+}
+
+/*
+ * Setup the architecture
+ */
+static void __init p1022_rdk_setup_arch(void)
+{
+#ifdef CONFIG_PCI
+       struct device_node *np;
+#endif
+       dma_addr_t max = 0xffffffff;
+
+       if (ppc_md.progress)
+               ppc_md.progress("p1022_rdk_setup_arch()", 0);
+
+#ifdef CONFIG_PCI
+       for_each_compatible_node(np, "pci", "fsl,p1022-pcie") {
+               struct resource rsrc;
+               struct pci_controller *hose;
+
+               of_address_to_resource(np, 0, &rsrc);
+
+               if ((rsrc.start & 0xfffff) == 0x8000)
+                       fsl_add_bridge(np, 1);
+               else
+                       fsl_add_bridge(np, 0);
+
+               hose = pci_find_hose_for_OF_device(np);
+               max = min(max, hose->dma_window_base_cur +
+                         hose->dma_window_size);
+       }
+#endif
+
+#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
+       diu_ops.set_monitor_port        = p1022rdk_set_monitor_port;
+       diu_ops.set_pixel_clock         = p1022rdk_set_pixel_clock;
+       diu_ops.valid_monitor_port      = p1022rdk_valid_monitor_port;
+#endif
+
+       mpc85xx_smp_init();
+
+#ifdef CONFIG_SWIOTLB
+       if ((memblock_end_of_DRAM() - 1) > max) {
+               ppc_swiotlb_enable = 1;
+               set_pci_dma_ops(&swiotlb_dma_ops);
+               ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb;
+       }
+#endif
+
+       pr_info("Freescale / iVeia P1022 RDK reference board\n");
+}
+
+machine_device_initcall(p1022_rdk, mpc85xx_common_publish_devices);
+
+machine_arch_initcall(p1022_rdk, swiotlb_setup_bus_notifier);
+
+/*
+ * Called very early, device-tree isn't unflattened
+ */
+static int __init p1022_rdk_probe(void)
+{
+       unsigned long root = of_get_flat_dt_root();
+
+       return of_flat_dt_is_compatible(root, "fsl,p1022rdk");
+}
+
+define_machine(p1022_rdk) {
+       .name                   = "P1022 RDK",
+       .probe                  = p1022_rdk_probe,
+       .setup_arch             = p1022_rdk_setup_arch,
+       .init_IRQ               = p1022_rdk_pic_init,
+#ifdef CONFIG_PCI
+       .pcibios_fixup_bus      = fsl_pcibios_fixup_bus,
+#endif
+       .get_irq                = mpic_get_irq,
+       .restart                = fsl_rstcr_restart,
+       .calibrate_decr         = generic_calibrate_decr,
+       .progress               = udbg_progress,
+};
diff --git a/arch/powerpc/platforms/85xx/p5040_ds.c b/arch/powerpc/platforms/85xx/p5040_ds.c
new file mode 100644 (file)
index 0000000..8e22a34
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * P5040 DS Setup
+ *
+ * Copyright 2009-2010 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 as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
+#include <asm/machdep.h>
+#include <asm/udbg.h>
+#include <asm/mpic.h>
+
+#include <linux/of_fdt.h>
+
+#include <sysdev/fsl_soc.h>
+#include <sysdev/fsl_pci.h>
+#include <asm/ehv_pic.h>
+
+#include "corenet_ds.h"
+
+/*
+ * Called very early, device-tree isn't unflattened
+ */
+static int __init p5040_ds_probe(void)
+{
+       unsigned long root = of_get_flat_dt_root();
+#ifdef CONFIG_SMP
+       extern struct smp_ops_t smp_85xx_ops;
+#endif
+
+       if (of_flat_dt_is_compatible(root, "fsl,P5040DS"))
+               return 1;
+
+       /* Check if we're running under the Freescale hypervisor */
+       if (of_flat_dt_is_compatible(root, "fsl,P5040DS-hv")) {
+               ppc_md.init_IRQ = ehv_pic_init;
+               ppc_md.get_irq = ehv_pic_get_irq;
+               ppc_md.restart = fsl_hv_restart;
+               ppc_md.power_off = fsl_hv_halt;
+               ppc_md.halt = fsl_hv_halt;
+#ifdef CONFIG_SMP
+               /*
+                * Disable the timebase sync operations because we can't write
+                * to the timebase registers under the hypervisor.
+                 */
+               smp_85xx_ops.give_timebase = NULL;
+               smp_85xx_ops.take_timebase = NULL;
+#endif
+               return 1;
+       }
+
+       return 0;
+}
+
+define_machine(p5040_ds) {
+       .name                   = "P5040 DS",
+       .probe                  = p5040_ds_probe,
+       .setup_arch             = corenet_ds_setup_arch,
+       .init_IRQ               = corenet_ds_pic_init,
+#ifdef CONFIG_PCI
+       .pcibios_fixup_bus      = fsl_pcibios_fixup_bus,
+#endif
+/* coreint doesn't play nice with lazy EE, use legacy mpic for now */
+#ifdef CONFIG_PPC64
+       .get_irq                = mpic_get_irq,
+#else
+       .get_irq                = mpic_get_coreint_irq,
+#endif
+       .restart                = fsl_rstcr_restart,
+       .calibrate_decr         = generic_calibrate_decr,
+       .progress               = udbg_progress,
+#ifdef CONFIG_PPC64
+       .power_save             = book3e_idle,
+#else
+       .power_save             = e500_idle,
+#endif
+};
+
+machine_device_initcall(p5040_ds, corenet_ds_publish_devices);
+
+#ifdef CONFIG_SWIOTLB
+machine_arch_initcall(p5040_ds, swiotlb_setup_bus_notifier);
+#endif
index 95a2e53af71b6ee66fcbf0013aa1020c85068692..3c5490c8423feecd8ecd545e40e8eceb6a65cae6 100644 (file)
@@ -42,6 +42,7 @@ static void __init qemu_e500_setup_arch(void)
        ppc_md.progress("qemu_e500_setup_arch()", 0);
 
        fsl_pci_init();
+       swiotlb_detect_4g();
        mpc85xx_smp_init();
 }
 
index ff4249044a3ce3929771d0b1d69a502868644b5d..6fcfa12e5c56dd42a2b1335fe1d6a0a35d0bfeda 100644 (file)
@@ -2,7 +2,7 @@
  * Author: Andy Fleming <afleming@freescale.com>
  *        Kumar Gala <galak@kernel.crashing.org>
  *
- * Copyright 2006-2008, 2011 Freescale Semiconductor Inc.
+ * Copyright 2006-2008, 2011-2012 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 as published by the
@@ -17,6 +17,7 @@
 #include <linux/of.h>
 #include <linux/kexec.h>
 #include <linux/highmem.h>
+#include <linux/cpu.h>
 
 #include <asm/machdep.h>
 #include <asm/pgtable.h>
 #include <asm/mpic.h>
 #include <asm/cacheflush.h>
 #include <asm/dbell.h>
+#include <asm/fsl_guts.h>
 
 #include <sysdev/fsl_soc.h>
 #include <sysdev/mpic.h>
 #include "smp.h"
 
-extern void __early_start(void);
-
-#define BOOT_ENTRY_ADDR_UPPER  0
-#define BOOT_ENTRY_ADDR_LOWER  1
-#define BOOT_ENTRY_R3_UPPER    2
-#define BOOT_ENTRY_R3_LOWER    3
-#define BOOT_ENTRY_RESV                4
-#define BOOT_ENTRY_PIR         5
-#define BOOT_ENTRY_R6_UPPER    6
-#define BOOT_ENTRY_R6_LOWER    7
-#define NUM_BOOT_ENTRY         8
-#define SIZE_BOOT_ENTRY                (NUM_BOOT_ENTRY * sizeof(u32))
-
-static int __init
-smp_85xx_kick_cpu(int nr)
+struct epapr_spin_table {
+       u32     addr_h;
+       u32     addr_l;
+       u32     r3_h;
+       u32     r3_l;
+       u32     reserved;
+       u32     pir;
+};
+
+static struct ccsr_guts __iomem *guts;
+static u64 timebase;
+static int tb_req;
+static int tb_valid;
+
+static void mpc85xx_timebase_freeze(int freeze)
+{
+       uint32_t mask;
+
+       mask = CCSR_GUTS_DEVDISR_TB0 | CCSR_GUTS_DEVDISR_TB1;
+       if (freeze)
+               setbits32(&guts->devdisr, mask);
+       else
+               clrbits32(&guts->devdisr, mask);
+
+       in_be32(&guts->devdisr);
+}
+
+static void mpc85xx_give_timebase(void)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+
+       while (!tb_req)
+               barrier();
+       tb_req = 0;
+
+       mpc85xx_timebase_freeze(1);
+       timebase = get_tb();
+       mb();
+       tb_valid = 1;
+
+       while (tb_valid)
+               barrier();
+
+       mpc85xx_timebase_freeze(0);
+
+       local_irq_restore(flags);
+}
+
+static void mpc85xx_take_timebase(void)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+
+       tb_req = 1;
+       while (!tb_valid)
+               barrier();
+
+       set_tb(timebase >> 32, timebase & 0xffffffff);
+       isync();
+       tb_valid = 0;
+
+       local_irq_restore(flags);
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+static void __cpuinit smp_85xx_mach_cpu_die(void)
+{
+       unsigned int cpu = smp_processor_id();
+       u32 tmp;
+
+       local_irq_disable();
+       idle_task_exit();
+       generic_set_cpu_dead(cpu);
+       mb();
+
+       mtspr(SPRN_TCR, 0);
+
+       __flush_disable_L1();
+       tmp = (mfspr(SPRN_HID0) & ~(HID0_DOZE|HID0_SLEEP)) | HID0_NAP;
+       mtspr(SPRN_HID0, tmp);
+       isync();
+
+       /* Enter NAP mode. */
+       tmp = mfmsr();
+       tmp |= MSR_WE;
+       mb();
+       mtmsr(tmp);
+       isync();
+
+       while (1)
+               ;
+}
+#endif
+
+static int __cpuinit smp_85xx_kick_cpu(int nr)
 {
        unsigned long flags;
        const u64 *cpu_rel_addr;
-       __iomem u32 *bptr_vaddr;
+       __iomem struct epapr_spin_table *spin_table;
        struct device_node *np;
-       int n = 0, hw_cpu = get_hard_smp_processor_id(nr);
+       int hw_cpu = get_hard_smp_processor_id(nr);
        int ioremappable;
+       int ret = 0;
 
        WARN_ON(nr < 0 || nr >= NR_CPUS);
        WARN_ON(hw_cpu < 0 || hw_cpu >= NR_CPUS);
@@ -75,46 +161,81 @@ smp_85xx_kick_cpu(int nr)
 
        /* Map the spin table */
        if (ioremappable)
-               bptr_vaddr = ioremap(*cpu_rel_addr, SIZE_BOOT_ENTRY);
+               spin_table = ioremap(*cpu_rel_addr,
+                               sizeof(struct epapr_spin_table));
        else
-               bptr_vaddr = phys_to_virt(*cpu_rel_addr);
+               spin_table = phys_to_virt(*cpu_rel_addr);
 
        local_irq_save(flags);
-
-       out_be32(bptr_vaddr + BOOT_ENTRY_PIR, hw_cpu);
 #ifdef CONFIG_PPC32
-       out_be32(bptr_vaddr + BOOT_ENTRY_ADDR_LOWER, __pa(__early_start));
+#ifdef CONFIG_HOTPLUG_CPU
+       /* Corresponding to generic_set_cpu_dead() */
+       generic_set_cpu_up(nr);
+
+       if (system_state == SYSTEM_RUNNING) {
+               out_be32(&spin_table->addr_l, 0);
+
+               /*
+                * We don't set the BPTR register here since it already points
+                * to the boot page properly.
+                */
+               mpic_reset_core(hw_cpu);
+
+               /* wait until core is ready... */
+               if (!spin_event_timeout(in_be32(&spin_table->addr_l) == 1,
+                                               10000, 100)) {
+                       pr_err("%s: timeout waiting for core %d to reset\n",
+                                                       __func__, hw_cpu);
+                       ret = -ENOENT;
+                       goto out;
+               }
+
+               /*  clear the acknowledge status */
+               __secondary_hold_acknowledge = -1;
+       }
+#endif
+       out_be32(&spin_table->pir, hw_cpu);
+       out_be32(&spin_table->addr_l, __pa(__early_start));
 
        if (!ioremappable)
-               flush_dcache_range((ulong)bptr_vaddr,
-                               (ulong)(bptr_vaddr + SIZE_BOOT_ENTRY));
+               flush_dcache_range((ulong)spin_table,
+                       (ulong)spin_table + sizeof(struct epapr_spin_table));
 
        /* Wait a bit for the CPU to ack. */
-       while ((__secondary_hold_acknowledge != hw_cpu) && (++n < 1000))
-               mdelay(1);
+       if (!spin_event_timeout(__secondary_hold_acknowledge == hw_cpu,
+                                       10000, 100)) {
+               pr_err("%s: timeout waiting for core %d to ack\n",
+                                               __func__, hw_cpu);
+               ret = -ENOENT;
+               goto out;
+       }
+out:
 #else
        smp_generic_kick_cpu(nr);
 
-       out_be64((u64 *)(bptr_vaddr + BOOT_ENTRY_ADDR_UPPER),
-               __pa((u64)*((unsigned long long *) generic_secondary_smp_init)));
+       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)bptr_vaddr,
-                               (ulong)(bptr_vaddr + SIZE_BOOT_ENTRY));
+               flush_dcache_range((ulong)spin_table,
+                       (ulong)spin_table + sizeof(struct epapr_spin_table));
 #endif
 
        local_irq_restore(flags);
 
        if (ioremappable)
-               iounmap(bptr_vaddr);
-
-       pr_debug("waited %d msecs for CPU #%d.\n", n, nr);
+               iounmap(spin_table);
 
-       return 0;
+       return ret;
 }
 
 struct smp_ops_t smp_85xx_ops = {
        .kick_cpu = smp_85xx_kick_cpu,
+#ifdef CONFIG_HOTPLUG_CPU
+       .cpu_disable    = generic_cpu_disable,
+       .cpu_die        = generic_cpu_die,
+#endif
 #ifdef CONFIG_KEXEC
        .give_timebase  = smp_generic_give_timebase,
        .take_timebase  = smp_generic_take_timebase,
@@ -218,8 +339,7 @@ static void mpc85xx_smp_machine_kexec(struct kimage *image)
 }
 #endif /* CONFIG_KEXEC */
 
-static void __init
-smp_85xx_setup_cpu(int cpu_nr)
+static void __cpuinit smp_85xx_setup_cpu(int cpu_nr)
 {
        if (smp_85xx_ops.probe == smp_mpic_probe)
                mpic_setup_this_cpu();
@@ -228,6 +348,16 @@ smp_85xx_setup_cpu(int cpu_nr)
                doorbell_setup_this_cpu();
 }
 
+static const struct of_device_id mpc85xx_smp_guts_ids[] = {
+       { .compatible = "fsl,mpc8572-guts", },
+       { .compatible = "fsl,p1020-guts", },
+       { .compatible = "fsl,p1021-guts", },
+       { .compatible = "fsl,p1022-guts", },
+       { .compatible = "fsl,p1023-guts", },
+       { .compatible = "fsl,p2020-guts", },
+       {},
+};
+
 void __init mpc85xx_smp_init(void)
 {
        struct device_node *np;
@@ -249,6 +379,22 @@ void __init mpc85xx_smp_init(void)
                smp_85xx_ops.cause_ipi = doorbell_cause_ipi;
        }
 
+       np = of_find_matching_node(NULL, mpc85xx_smp_guts_ids);
+       if (np) {
+               guts = of_iomap(np, 0);
+               of_node_put(np);
+               if (!guts) {
+                       pr_err("%s: Could not map guts node address\n",
+                                                               __func__);
+                       return;
+               }
+               smp_85xx_ops.give_timebase = mpc85xx_give_timebase;
+               smp_85xx_ops.take_timebase = mpc85xx_take_timebase;
+#ifdef CONFIG_HOTPLUG_CPU
+               ppc_md.cpu_die = smp_85xx_mach_cpu_die;
+#endif
+       }
+
        smp_ops = &smp_85xx_ops;
 
 #ifdef CONFIG_KEXEC
index e7a896acd982798d20650bd9b0bd9df9aa202bff..48a920d514892b2e238a9bcfc60050cb25f95f00 100644 (file)
@@ -90,6 +90,7 @@ config MPIC
 config PPC_EPAPR_HV_PIC
        bool
        default n
+       select EPAPR_PARAVIRT
 
 config MPIC_WEIRD
        bool
index 5822141aa63f3f21f73739ea1b2210971698040b..abc8af43ea7c5abf293d56abca685963de63560b 100644 (file)
@@ -472,7 +472,7 @@ int __init celleb_setup_phb(struct pci_controller *phb)
 {
        struct device_node *dev = phb->dn;
        const struct of_device_id *match;
-       struct celleb_phb_spec *phb_spec;
+       const struct celleb_phb_spec *phb_spec;
        int rc;
 
        match = of_match_node(celleb_phb_match, dev);
index 1bd7ecb246207e8235d6d71dcb4cce3d2d418259..a57600b3a4e3667534c5dc7eb5cd2a188edd8425 100644 (file)
@@ -15,7 +15,7 @@ obj-$(CONFIG_PPC_DCR_NATIVE)  += dcr-low.o
 obj-$(CONFIG_PPC_PMI)          += pmi.o
 obj-$(CONFIG_U3_DART)          += dart_iommu.o
 obj-$(CONFIG_MMIO_NVRAM)       += mmio_nvram.o
-obj-$(CONFIG_FSL_SOC)          += fsl_soc.o
+obj-$(CONFIG_FSL_SOC)          += fsl_soc.o fsl_mpic_err.o
 obj-$(CONFIG_FSL_PCI)          += fsl_pci.o $(fsl-msi-obj-y)
 obj-$(CONFIG_FSL_PMC)          += fsl_pmc.o
 obj-$(CONFIG_FSL_LBC)          += fsl_lbc.o
index 68ac3aacb1919477ed4686f859979d9bc17c7b15..d131c8a1cb15908a955147ae9d4eee3bfa5b3eb4 100644 (file)
@@ -193,6 +193,16 @@ static struct of_device_id mpc85xx_l2ctlr_of_match[] = {
        {
                .compatible = "fsl,mpc8548-l2-cache-controller",
        },
+       {       .compatible = "fsl,mpc8544-l2-cache-controller",},
+       {       .compatible = "fsl,mpc8572-l2-cache-controller",},
+       {       .compatible = "fsl,mpc8536-l2-cache-controller",},
+       {       .compatible = "fsl,p1021-l2-cache-controller",},
+       {       .compatible = "fsl,p1012-l2-cache-controller",},
+       {       .compatible = "fsl,p1025-l2-cache-controller",},
+       {       .compatible = "fsl,p1016-l2-cache-controller",},
+       {       .compatible = "fsl,p1024-l2-cache-controller",},
+       {       .compatible = "fsl,p1015-l2-cache-controller",},
+       {       .compatible = "fsl,p1010-l2-cache-controller",},
        {},
 };
 
diff --git a/arch/powerpc/sysdev/fsl_mpic_err.c b/arch/powerpc/sysdev/fsl_mpic_err.c
new file mode 100644 (file)
index 0000000..b83f325
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2012 Freescale Semiconductor, Inc.
+ *
+ * Author: Varun Sethi <varun.sethi@freescale.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.
+ *
+ */
+
+#include <linux/irq.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mpic.h>
+
+#include "mpic.h"
+
+#define MPIC_ERR_INT_BASE      0x3900
+#define MPIC_ERR_INT_EISR      0x0000
+#define MPIC_ERR_INT_EIMR      0x0010
+
+static inline u32 mpic_fsl_err_read(u32 __iomem *base, unsigned int err_reg)
+{
+       return in_be32(base + (err_reg >> 2));
+}
+
+static inline void mpic_fsl_err_write(u32 __iomem *base, u32 value)
+{
+       out_be32(base + (MPIC_ERR_INT_EIMR >> 2), value);
+}
+
+static void fsl_mpic_mask_err(struct irq_data *d)
+{
+       u32 eimr;
+       struct mpic *mpic = irq_data_get_irq_chip_data(d);
+       unsigned int src = virq_to_hw(d->irq) - mpic->err_int_vecs[0];
+
+       eimr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EIMR);
+       eimr |= (1 << (31 - src));
+       mpic_fsl_err_write(mpic->err_regs, eimr);
+}
+
+static void fsl_mpic_unmask_err(struct irq_data *d)
+{
+       u32 eimr;
+       struct mpic *mpic = irq_data_get_irq_chip_data(d);
+       unsigned int src = virq_to_hw(d->irq) - mpic->err_int_vecs[0];
+
+       eimr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EIMR);
+       eimr &= ~(1 << (31 - src));
+       mpic_fsl_err_write(mpic->err_regs, eimr);
+}
+
+static struct irq_chip fsl_mpic_err_chip = {
+       .irq_disable    = fsl_mpic_mask_err,
+       .irq_mask       = fsl_mpic_mask_err,
+       .irq_unmask     = fsl_mpic_unmask_err,
+};
+
+int mpic_setup_error_int(struct mpic *mpic, int intvec)
+{
+       int i;
+
+       mpic->err_regs = ioremap(mpic->paddr + MPIC_ERR_INT_BASE, 0x1000);
+       if (!mpic->err_regs) {
+               pr_err("could not map mpic error registers\n");
+               return -ENOMEM;
+       }
+       mpic->hc_err = fsl_mpic_err_chip;
+       mpic->hc_err.name = mpic->name;
+       mpic->flags |= MPIC_FSL_HAS_EIMR;
+       /* allocate interrupt vectors for error interrupts */
+       for (i = MPIC_MAX_ERR - 1; i >= 0; i--)
+               mpic->err_int_vecs[i] = --intvec;
+
+       return 0;
+}
+
+int mpic_map_error_int(struct mpic *mpic, unsigned int virq, irq_hw_number_t  hw)
+{
+       if ((mpic->flags & MPIC_FSL_HAS_EIMR) &&
+           (hw >= mpic->err_int_vecs[0] &&
+            hw <= mpic->err_int_vecs[MPIC_MAX_ERR - 1])) {
+               WARN_ON(mpic->flags & MPIC_SECONDARY);
+
+               pr_debug("mpic: mapping as Error Interrupt\n");
+               irq_set_chip_data(virq, mpic);
+               irq_set_chip_and_handler(virq, &mpic->hc_err,
+                                        handle_level_irq);
+               return 1;
+       }
+
+       return 0;
+}
+
+static irqreturn_t fsl_error_int_handler(int irq, void *data)
+{
+       struct mpic *mpic = (struct mpic *) data;
+       u32 eisr, eimr;
+       int errint;
+       unsigned int cascade_irq;
+
+       eisr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EISR);
+       eimr = mpic_fsl_err_read(mpic->err_regs, MPIC_ERR_INT_EIMR);
+
+       if (!(eisr & ~eimr))
+               return IRQ_NONE;
+
+       while (eisr) {
+               errint = __builtin_clz(eisr);
+               cascade_irq = irq_linear_revmap(mpic->irqhost,
+                                mpic->err_int_vecs[errint]);
+               WARN_ON(cascade_irq == NO_IRQ);
+               if (cascade_irq != NO_IRQ) {
+                       generic_handle_irq(cascade_irq);
+               } else {
+                       eimr |=  1 << (31 - errint);
+                       mpic_fsl_err_write(mpic->err_regs, eimr);
+               }
+               eisr &= ~(1 << (31 - errint));
+       }
+
+       return IRQ_HANDLED;
+}
+
+void mpic_err_int_init(struct mpic *mpic, irq_hw_number_t irqnum)
+{
+       unsigned int virq;
+       int ret;
+
+       virq = irq_create_mapping(mpic->irqhost, irqnum);
+       if (virq == NO_IRQ) {
+               pr_err("Error interrupt setup failed\n");
+               return;
+       }
+
+       /* Mask all error interrupts */
+       mpic_fsl_err_write(mpic->err_regs, ~0);
+
+       ret = request_irq(virq, fsl_error_int_handler, IRQF_NO_THREAD,
+                   "mpic-error-int", mpic);
+       if (ret)
+               pr_err("Failed to register error interrupt handler\n");
+}
index 6e097de00e093741890b12c45cb13b16d99d1d20..63c5f04ea580177649aba38d101cb3f86b40cb35 100644 (file)
@@ -236,7 +236,6 @@ static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc)
        u32 intr_index;
        u32 have_shift = 0;
        struct fsl_msi_cascade_data *cascade_data;
-       unsigned int ret;
 
        cascade_data = irq_get_handler_data(irq);
        msi_data = cascade_data->msi_data;
@@ -268,7 +267,9 @@ static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc)
        case FSL_PIC_IP_IPIC:
                msir_value = fsl_msi_read(msi_data->msi_regs, msir_index * 0x4);
                break;
-       case FSL_PIC_IP_VMPIC:
+#ifdef CONFIG_EPAPR_PARAVIRT
+       case FSL_PIC_IP_VMPIC: {
+               unsigned int ret;
                ret = fh_vmpic_get_msir(virq_to_hw(irq), &msir_value);
                if (ret) {
                        pr_err("fsl-msi: fh_vmpic_get_msir() failed for "
@@ -277,6 +278,8 @@ static void fsl_msi_cascade(unsigned int irq, struct irq_desc *desc)
                }
                break;
        }
+#endif
+       }
 
        while (msir_value) {
                intr_index = ffs(msir_value) - 1;
@@ -368,7 +371,7 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev)
        int err, i, j, irq_index, count;
        int rc;
        const u32 *p;
-       struct fsl_msi_feature *features;
+       const struct fsl_msi_feature *features;
        int len;
        u32 offset;
        static const u32 all_avail[] = { 0, NR_MSI_IRQS };
@@ -502,16 +505,18 @@ static const struct fsl_msi_feature vmpic_msi_feature = {
 static const struct of_device_id fsl_of_msi_ids[] = {
        {
                .compatible = "fsl,mpic-msi",
-               .data = (void *)&mpic_msi_feature,
+               .data = &mpic_msi_feature,
        },
        {
                .compatible = "fsl,ipic-msi",
-               .data = (void *)&ipic_msi_feature,
+               .data = &ipic_msi_feature,
        },
+#ifdef CONFIG_EPAPR_PARAVIRT
        {
                .compatible = "fsl,vmpic-msi",
-               .data = (void *)&vmpic_msi_feature,
+               .data = &vmpic_msi_feature,
        },
+#endif
        {}
 };
 
index a7b2a600d0a4d0aa7878a633eb3549f0a0d3a373..da7a3d7f54cc8a20f685fc9e6abdde6c3fcc987c 100644 (file)
@@ -465,7 +465,7 @@ int __init fsl_add_bridge(struct device_node *dev, int is_primary)
                        iounmap(hose->cfg_data);
                iounmap(hose->cfg_addr);
                pcibios_free_controller(hose);
-               return 0;
+               return -ENODEV;
        }
 
        setup_pci_cmd(hose);
@@ -818,6 +818,7 @@ static const struct of_device_id pci_ids[] = {
        { .compatible = "fsl,p1010-pcie", },
        { .compatible = "fsl,p1023-pcie", },
        { .compatible = "fsl,p4080-pcie", },
+       { .compatible = "fsl,qoriq-pcie-v2.4", },
        { .compatible = "fsl,qoriq-pcie-v2.3", },
        { .compatible = "fsl,qoriq-pcie-v2.2", },
        {},
@@ -827,6 +828,7 @@ struct device_node *fsl_pci_primary;
 
 void __devinit fsl_pci_init(void)
 {
+       int ret;
        struct device_node *node;
        struct pci_controller *hose;
        dma_addr_t max = 0xffffffff;
@@ -855,10 +857,12 @@ void __devinit fsl_pci_init(void)
                        if (!fsl_pci_primary)
                                fsl_pci_primary = node;
 
-                       fsl_add_bridge(node, fsl_pci_primary == node);
-                       hose = pci_find_hose_for_OF_device(node);
-                       max = min(max, hose->dma_window_base_cur +
-                                       hose->dma_window_size);
+                       ret = fsl_add_bridge(node, fsl_pci_primary == node);
+                       if (ret == 0) {
+                               hose = pci_find_hose_for_OF_device(node);
+                               max = min(max, hose->dma_window_base_cur +
+                                               hose->dma_window_size);
+                       }
                }
        }
 
@@ -868,11 +872,8 @@ void __devinit fsl_pci_init(void)
         * we need SWIOTLB to handle buffers located outside of
         * dma capable memory region
         */
-       if (memblock_end_of_DRAM() - 1 > max) {
+       if (memblock_end_of_DRAM() - 1 > max)
                ppc_swiotlb_enable = 1;
-               set_pci_dma_ops(&swiotlb_dma_ops);
-               ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb;
-       }
 #endif
 }
 #endif
index c449dbd1c938f749447bf04944dde0e6ca1450e1..97118dc3d2851b7a33ce46a4aec162ff1cc4bba5 100644 (file)
@@ -253,6 +253,7 @@ struct platform_diu_data_ops diu_ops;
 EXPORT_SYMBOL(diu_ops);
 #endif
 
+#ifdef CONFIG_EPAPR_PARAVIRT
 /*
  * Restart the current partition
  *
@@ -278,3 +279,4 @@ void fsl_hv_halt(void)
        pr_info("hv exit\n");
        fh_partition_stop(-1);
 }
+#endif
index bfc6211e5422ef17b6e0bb0d24b926fa653354d9..9c6e535daad27b676422ea0813f27d322c576452 100644 (file)
@@ -6,7 +6,7 @@
  *  with various broken implementations of this HW.
  *
  *  Copyright (C) 2004 Benjamin Herrenschmidt, IBM Corp.
- *  Copyright 2010-2011 Freescale Semiconductor, Inc.
+ *  Copyright 2010-2012 Freescale Semiconductor, Inc.
  *
  *  This file is subject to the terms and conditions of the GNU General Public
  *  License.  See the file COPYING in the main directory of this archive
@@ -221,24 +221,24 @@ static inline void _mpic_ipi_write(struct mpic *mpic, unsigned int ipi, u32 valu
        _mpic_write(mpic->reg_type, &mpic->gregs, offset, value);
 }
 
-static inline u32 _mpic_tm_read(struct mpic *mpic, unsigned int tm)
+static inline unsigned int mpic_tm_offset(struct mpic *mpic, unsigned int tm)
 {
-       unsigned int offset = MPIC_INFO(TIMER_VECTOR_PRI) +
-                             ((tm & 3) * MPIC_INFO(TIMER_STRIDE));
+       return (tm >> 2) * MPIC_TIMER_GROUP_STRIDE +
+              (tm & 3) * MPIC_INFO(TIMER_STRIDE);
+}
 
-       if (tm >= 4)
-               offset += 0x1000 / 4;
+static inline u32 _mpic_tm_read(struct mpic *mpic, unsigned int tm)
+{
+       unsigned int offset = mpic_tm_offset(mpic, tm) +
+                             MPIC_INFO(TIMER_VECTOR_PRI);
 
        return _mpic_read(mpic->reg_type, &mpic->tmregs, offset);
 }
 
 static inline void _mpic_tm_write(struct mpic *mpic, unsigned int tm, u32 value)
 {
-       unsigned int offset = MPIC_INFO(TIMER_VECTOR_PRI) +
-                             ((tm & 3) * MPIC_INFO(TIMER_STRIDE));
-
-       if (tm >= 4)
-               offset += 0x1000 / 4;
+       unsigned int offset = mpic_tm_offset(mpic, tm) +
+                             MPIC_INFO(TIMER_VECTOR_PRI);
 
        _mpic_write(mpic->reg_type, &mpic->tmregs, offset, value);
 }
@@ -1026,6 +1026,9 @@ static int mpic_host_map(struct irq_domain *h, unsigned int virq,
                return 0;
        }
 
+       if (mpic_map_error_int(mpic, virq, hw))
+               return 0;
+
        if (hw >= mpic->num_sources)
                return -EINVAL;
 
@@ -1085,7 +1088,16 @@ static int mpic_host_xlate(struct irq_domain *h, struct device_node *ct,
                 */
                switch (intspec[2]) {
                case 0:
-               case 1: /* no EISR/EIMR support for now, treat as shared IRQ */
+                       break;
+               case 1:
+                       if (!(mpic->flags & MPIC_FSL_HAS_EIMR))
+                               break;
+
+                       if (intspec[3] >= ARRAY_SIZE(mpic->err_int_vecs))
+                               return -EINVAL;
+
+                       *out_hwirq = mpic->err_int_vecs[intspec[3]];
+
                        break;
                case 2:
                        if (intspec[0] >= ARRAY_SIZE(mpic->ipi_vecs))
@@ -1301,6 +1313,42 @@ struct mpic * __init mpic_alloc(struct device_node *node,
        mpic_map(mpic, mpic->paddr, &mpic->gregs, MPIC_INFO(GREG_BASE), 0x1000);
        mpic_map(mpic, mpic->paddr, &mpic->tmregs, MPIC_INFO(TIMER_BASE), 0x1000);
 
+       if (mpic->flags & MPIC_FSL) {
+               u32 brr1, version;
+               int ret;
+
+               /*
+                * Yes, Freescale really did put global registers in the
+                * magic per-cpu area -- and they don't even show up in the
+                * non-magic per-cpu copies that this driver normally uses.
+                */
+               mpic_map(mpic, mpic->paddr, &mpic->thiscpuregs,
+                        MPIC_CPU_THISBASE, 0x1000);
+
+               brr1 = _mpic_read(mpic->reg_type, &mpic->thiscpuregs,
+                               MPIC_FSL_BRR1);
+               version = brr1 & MPIC_FSL_BRR1_VER;
+
+               /* Error interrupt mask register (EIMR) is required for
+                * handling individual device error interrupts. EIMR
+                * was added in MPIC version 4.1.
+                *
+                * Over here we reserve vector number space for error
+                * interrupt vectors. This space is stolen from the
+                * global vector number space, as in case of ipis
+                * and timer interrupts.
+                *
+                * Available vector space = intvec_top - 12, where 12
+                * is the number of vectors which have been consumed by
+                * ipis and timer interrupts.
+                */
+               if (version >= 0x401) {
+                       ret = mpic_setup_error_int(mpic, intvec_top - 12);
+                       if (ret)
+                               return NULL;
+               }
+       }
+
        /* Reset */
 
        /* When using a device-node, reset requests are only honored if the MPIC
@@ -1440,6 +1488,7 @@ void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num,
 void __init mpic_init(struct mpic *mpic)
 {
        int i, cpu;
+       int num_timers = 4;
 
        BUG_ON(mpic->num_sources == 0);
 
@@ -1448,15 +1497,34 @@ void __init mpic_init(struct mpic *mpic)
        /* Set current processor priority to max */
        mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0xf);
 
+       if (mpic->flags & MPIC_FSL) {
+               u32 brr1 = _mpic_read(mpic->reg_type, &mpic->thiscpuregs,
+                                     MPIC_FSL_BRR1);
+               u32 version = brr1 & MPIC_FSL_BRR1_VER;
+
+               /*
+                * Timer group B is present at the latest in MPIC 3.1 (e.g.
+                * mpc8536).  It is not present in MPIC 2.0 (e.g. mpc8544).
+                * I don't know about the status of intermediate versions (or
+                * whether they even exist).
+                */
+               if (version >= 0x0301)
+                       num_timers = 8;
+       }
+
+       /* FSL mpic error interrupt intialization */
+       if (mpic->flags & MPIC_FSL_HAS_EIMR)
+               mpic_err_int_init(mpic, MPIC_FSL_ERR_INT);
+
        /* Initialize timers to our reserved vectors and mask them for now */
-       for (i = 0; i < 4; i++) {
+       for (i = 0; i < num_timers; i++) {
+               unsigned int offset = mpic_tm_offset(mpic, i);
+
                mpic_write(mpic->tmregs,
-                          i * MPIC_INFO(TIMER_STRIDE) +
-                          MPIC_INFO(TIMER_DESTINATION),
+                          offset + MPIC_INFO(TIMER_DESTINATION),
                           1 << hard_smp_processor_id());
                mpic_write(mpic->tmregs,
-                          i * MPIC_INFO(TIMER_STRIDE) +
-                          MPIC_INFO(TIMER_VECTOR_PRI),
+                          offset + MPIC_INFO(TIMER_VECTOR_PRI),
                           MPIC_VECPRI_MASK |
                           (9 << MPIC_VECPRI_PRIORITY_SHIFT) |
                           (mpic->timer_vecs[0] + i));
index 13f3e8913a932951061743e0884d203e16e73e0f..24bf07a63924e3c28745b6ab3eb264dbf93975bd 100644 (file)
@@ -40,4 +40,26 @@ extern int mpic_set_affinity(struct irq_data *d,
                             const struct cpumask *cpumask, bool force);
 extern void mpic_reset_core(int cpu);
 
+#ifdef CONFIG_FSL_SOC
+extern int mpic_map_error_int(struct mpic *mpic, unsigned int virq, irq_hw_number_t  hw);
+extern void mpic_err_int_init(struct mpic *mpic, irq_hw_number_t irqnum);
+extern int mpic_setup_error_int(struct mpic *mpic, int intvec);
+#else
+static inline int mpic_map_error_int(struct mpic *mpic, unsigned int virq, irq_hw_number_t  hw)
+{
+       return 0;
+}
+
+
+static inline void mpic_err_int_init(struct mpic *mpic, irq_hw_number_t irqnum)
+{
+       return;
+}
+
+static inline int mpic_setup_error_int(struct mpic *mpic, int intvec)
+{
+       return -1;
+}
+#endif
+
 #endif /* _POWERPC_SYSDEV_MPIC_H */
index 9858476fa0fee62dc8a25a4996203abaaeb3a942..cc45d25487b0ae945087000d7a347fa0ee6e0852 100644 (file)
@@ -5,3 +5,4 @@ obj-$(CONFIG_CRYPTO_HW)         += crypto/
 obj-$(CONFIG_S390_HYPFS_FS)    += hypfs/
 obj-$(CONFIG_APPLDATA_BASE)    += appldata/
 obj-$(CONFIG_MATHEMU)          += math-emu/
+obj-y                          += net/
index 76de6b68487c8a44aa4eabecc1dddc7d916546e2..e9886e2677186614ff1f1000f4d6cd5aebda6b97 100644 (file)
@@ -84,6 +84,7 @@ config S390
        select HAVE_KERNEL_XZ
        select HAVE_ARCH_MUTEX_CPU_RELAX
        select HAVE_ARCH_JUMP_LABEL if !MARCH_G5
+       select HAVE_BPF_JIT if 64BIT && PACK_STACK
        select ARCH_SAVE_PAGE_KEYS if HIBERNATION
        select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
        select HAVE_MEMBLOCK
@@ -124,6 +125,9 @@ config S390
        select GENERIC_TIME_VSYSCALL
        select GENERIC_CLOCKEVENTS
        select KTIME_SCALAR if 32BIT
+       select HAVE_ARCH_SECCOMP_FILTER
+       select HAVE_MOD_ARCH_SPECIFIC
+       select MODULES_USE_ELF_RELA
 
 config SCHED_OMIT_FRAME_POINTER
        def_bool y
index e402a9dd4eda67944893eeef40fa8d67a3066008..da3c1a7dcd8e4ddb7dc76f16e95a38e232ef6c5c 100644 (file)
@@ -216,7 +216,6 @@ static struct crypto_alg aes_alg = {
        .cra_blocksize          =       AES_BLOCK_SIZE,
        .cra_ctxsize            =       sizeof(struct s390_aes_ctx),
        .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(aes_alg.cra_list),
        .cra_init               =       fallback_init_cip,
        .cra_exit               =       fallback_exit_cip,
        .cra_u                  =       {
@@ -398,7 +397,6 @@ static struct crypto_alg ecb_aes_alg = {
        .cra_ctxsize            =       sizeof(struct s390_aes_ctx),
        .cra_type               =       &crypto_blkcipher_type,
        .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(ecb_aes_alg.cra_list),
        .cra_init               =       fallback_init_blk,
        .cra_exit               =       fallback_exit_blk,
        .cra_u                  =       {
@@ -508,7 +506,6 @@ static struct crypto_alg cbc_aes_alg = {
        .cra_ctxsize            =       sizeof(struct s390_aes_ctx),
        .cra_type               =       &crypto_blkcipher_type,
        .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(cbc_aes_alg.cra_list),
        .cra_init               =       fallback_init_blk,
        .cra_exit               =       fallback_exit_blk,
        .cra_u                  =       {
@@ -710,7 +707,6 @@ static struct crypto_alg xts_aes_alg = {
        .cra_ctxsize            =       sizeof(struct s390_xts_ctx),
        .cra_type               =       &crypto_blkcipher_type,
        .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(xts_aes_alg.cra_list),
        .cra_init               =       xts_fallback_init,
        .cra_exit               =       xts_fallback_exit,
        .cra_u                  =       {
@@ -832,7 +828,6 @@ static struct crypto_alg ctr_aes_alg = {
        .cra_ctxsize            =       sizeof(struct s390_aes_ctx),
        .cra_type               =       &crypto_blkcipher_type,
        .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(ctr_aes_alg.cra_list),
        .cra_u                  =       {
                .blkcipher = {
                        .min_keysize            =       AES_MIN_KEY_SIZE,
index 1eaa371ca3eea30fd9856c70371ffda5a335e0a5..b49fb96f42070623a1645db10ebee3457eb0a98a 100644 (file)
@@ -70,7 +70,6 @@ static struct crypto_alg des_alg = {
        .cra_blocksize          =       DES_BLOCK_SIZE,
        .cra_ctxsize            =       sizeof(struct s390_des_ctx),
        .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(des_alg.cra_list),
        .cra_u                  =       {
                .cipher = {
                        .cia_min_keysize        =       DES_KEY_SIZE,
@@ -163,7 +162,6 @@ static struct crypto_alg ecb_des_alg = {
        .cra_ctxsize            =       sizeof(struct s390_des_ctx),
        .cra_type               =       &crypto_blkcipher_type,
        .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(ecb_des_alg.cra_list),
        .cra_u                  =       {
                .blkcipher = {
                        .min_keysize            =       DES_KEY_SIZE,
@@ -206,7 +204,6 @@ static struct crypto_alg cbc_des_alg = {
        .cra_ctxsize            =       sizeof(struct s390_des_ctx),
        .cra_type               =       &crypto_blkcipher_type,
        .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(cbc_des_alg.cra_list),
        .cra_u                  =       {
                .blkcipher = {
                        .min_keysize            =       DES_KEY_SIZE,
@@ -271,7 +268,6 @@ static struct crypto_alg des3_alg = {
        .cra_blocksize          =       DES_BLOCK_SIZE,
        .cra_ctxsize            =       sizeof(struct s390_des_ctx),
        .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(des3_alg.cra_list),
        .cra_u                  =       {
                .cipher = {
                        .cia_min_keysize        =       DES3_KEY_SIZE,
@@ -314,8 +310,6 @@ static struct crypto_alg ecb_des3_alg = {
        .cra_ctxsize            =       sizeof(struct s390_des_ctx),
        .cra_type               =       &crypto_blkcipher_type,
        .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(
-                                               ecb_des3_alg.cra_list),
        .cra_u                  =       {
                .blkcipher = {
                        .min_keysize            =       DES3_KEY_SIZE,
@@ -358,8 +352,6 @@ static struct crypto_alg cbc_des3_alg = {
        .cra_ctxsize            =       sizeof(struct s390_des_ctx),
        .cra_type               =       &crypto_blkcipher_type,
        .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(
-                                               cbc_des3_alg.cra_list),
        .cra_u                  =       {
                .blkcipher = {
                        .min_keysize            =       DES3_KEY_SIZE,
@@ -452,7 +444,6 @@ static struct crypto_alg ctr_des_alg = {
        .cra_ctxsize            =       sizeof(struct s390_des_ctx),
        .cra_type               =       &crypto_blkcipher_type,
        .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(ctr_des_alg.cra_list),
        .cra_u                  =       {
                .blkcipher = {
                        .min_keysize            =       DES_KEY_SIZE,
@@ -496,7 +487,6 @@ static struct crypto_alg ctr_des3_alg = {
        .cra_ctxsize            =       sizeof(struct s390_des_ctx),
        .cra_type               =       &crypto_blkcipher_type,
        .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(ctr_des3_alg.cra_list),
        .cra_u                  =       {
                .blkcipher = {
                        .min_keysize            =       DES3_KEY_SIZE,
index b1bd170f24b147d207f13269677606d2f2311cfc..1ebd3a15cca47d499e3d3855b3f3b1e5bad0082a 100644 (file)
@@ -135,7 +135,6 @@ static struct shash_alg ghash_alg = {
                .cra_blocksize          = GHASH_BLOCK_SIZE,
                .cra_ctxsize            = sizeof(struct ghash_ctx),
                .cra_module             = THIS_MODULE,
-               .cra_list               = LIST_HEAD_INIT(ghash_alg.base.cra_list),
        },
 };
 
index f0b6b26b6e59de846b260deef64d3d0b07e0a188..df1f861a848a1ef85a2b902d7bf45a1ad6e81cef 100644 (file)
@@ -1,5 +1,8 @@
 #ifndef _ASM_S390_MODULE_H
 #define _ASM_S390_MODULE_H
+
+#include <asm-generic/module.h>
+
 /*
  * This file contains the s390 architecture specific module code.
  */
@@ -28,19 +31,4 @@ struct mod_arch_specific
        struct mod_arch_syminfo *syminfo;
 };
 
-#ifdef CONFIG_64BIT
-#define ElfW(x) Elf64_ ## x
-#define ELFW(x) ELF64_ ## x
-#else
-#define ElfW(x) Elf32_ ## x
-#define ELFW(x) ELF32_ ## x
-#endif
-
-#define Elf_Addr ElfW(Addr)
-#define Elf_Rela ElfW(Rela)
-#define Elf_Shdr ElfW(Shdr)
-#define Elf_Sym ElfW(Sym)
-#define Elf_Ehdr ElfW(Ehdr)
-#define ELF_R_SYM ELFW(R_SYM)
-#define ELF_R_TYPE ELFW(R_TYPE)
 #endif /* _ASM_S390_MODULE_H */
index 11e4e3236937e106aba159b83e7cc6ae6167c7b0..01c97b980fa4fcdfc29e16715746c198153192f0 100644 (file)
@@ -140,6 +140,8 @@ extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
 extern unsigned long thread_saved_pc(struct task_struct *t);
 
 extern void show_code(struct pt_regs *regs);
+extern void print_fn_code(unsigned char *code, unsigned long len);
+extern int insn_to_mnemonic(unsigned char *instruction, char buf[8]);
 
 unsigned long get_wchan(struct task_struct *p);
 #define task_pt_regs(tsk) ((struct pt_regs *) \
index 0fb34027d3f6fbdc5a851f796a0e23d368bea071..a60d085ddb4d90089d7e73850955432ca2372eb6 100644 (file)
@@ -4,13 +4,11 @@
 #ifdef CONFIG_64BIT
 
 #define SECTION_SIZE_BITS      28
-#define MAX_PHYSADDR_BITS      46
 #define MAX_PHYSMEM_BITS       46
 
 #else
 
 #define SECTION_SIZE_BITS      25
-#define MAX_PHYSADDR_BITS      31
 #define MAX_PHYSMEM_BITS       31
 
 #endif /* CONFIG_64BIT */
index fb214dd9b7e0631606072a00a6b3994de4e8a97b..fe7b99759e12ffcdf5f2df9880f86f91df3c9800 100644 (file)
@@ -12,6 +12,7 @@
 #ifndef _ASM_SYSCALL_H
 #define _ASM_SYSCALL_H 1
 
+#include <linux/audit.h>
 #include <linux/sched.h>
 #include <linux/err.h>
 #include <asm/ptrace.h>
@@ -87,4 +88,13 @@ static inline void syscall_set_arguments(struct task_struct *task,
                regs->orig_gpr2 = args[0];
 }
 
+static inline int syscall_get_arch(struct task_struct *task,
+                                  struct pt_regs *regs)
+{
+#ifdef CONFIG_COMPAT
+       if (test_tsk_thread_flag(task, TIF_31BIT))
+               return AUDIT_ARCH_S390;
+#endif
+       return sizeof(long) == 8 ? AUDIT_ARCH_S390X : AUDIT_ARCH_S390;
+}
 #endif /* _ASM_SYSCALL_H */
index d1225089a4bbe09519555c4f5336e283394ff03e..f606d935f4950dcbec6fca5f67b88ac70760dcda 100644 (file)
@@ -620,7 +620,6 @@ asmlinkage unsigned long old32_mmap(struct mmap_arg_struct_emu31 __user *arg)
                return -EFAULT;
        if (a.offset & ~PAGE_MASK)
                return -EINVAL;
-       a.addr = (unsigned long) compat_ptr(a.addr);
        return sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd,
                              a.offset >> PAGE_SHIFT);
 }
@@ -631,7 +630,6 @@ asmlinkage long sys32_mmap2(struct mmap_arg_struct_emu31 __user *arg)
 
        if (copy_from_user(&a, arg, sizeof(a)))
                return -EFAULT;
-       a.addr = (unsigned long) compat_ptr(a.addr);
        return sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, a.offset);
 }
 
index e835d6d5b7fdc94ee90e5293087328d638c2f74f..2d82cfcbce5b8cae9127aa115902fa6a2f3b5123 100644 (file)
@@ -1635,7 +1635,7 @@ ENTRY(compat_sys_process_vm_readv_wrapper)
        llgfr   %r6,%r6                 # unsigned long
        llgf    %r0,164(%r15)           # unsigned long
        stg     %r0,160(%r15)
-       jg      sys_process_vm_readv
+       jg      compat_sys_process_vm_readv
 
 ENTRY(compat_sys_process_vm_writev_wrapper)
        lgfr    %r2,%r2                 # compat_pid_t
@@ -1645,4 +1645,4 @@ ENTRY(compat_sys_process_vm_writev_wrapper)
        llgfr   %r6,%r6                 # unsigned long
        llgf    %r0,164(%r15)           # unsigned long
        stg     %r0,160(%r15)
-       jg      sys_process_vm_writev
+       jg      compat_sys_process_vm_writev
index 619c5d3507264ca1f7417563a9152b55270374a2..266d7228f856b1963d72b889d905b3435a0c73e7 100644 (file)
@@ -1468,6 +1468,33 @@ static struct insn *find_insn(unsigned char *code)
        return NULL;
 }
 
+/**
+ * insn_to_mnemonic - decode an s390 instruction
+ * @instruction: instruction to decode
+ * @buf: buffer to fill with mnemonic
+ *
+ * Decode the instruction at @instruction and store the corresponding
+ * mnemonic into @buf.
+ * @buf is left unchanged if the instruction could not be decoded.
+ * Returns:
+ *  %0 on success, %-ENOENT if the instruction was not found.
+ */
+int insn_to_mnemonic(unsigned char *instruction, char buf[8])
+{
+       struct insn *insn;
+
+       insn = find_insn(instruction);
+       if (!insn)
+               return -ENOENT;
+       if (insn->name[0] == '\0')
+               snprintf(buf, sizeof(buf), "%s",
+                        long_insn_name[(int) insn->name[1]]);
+       else
+               snprintf(buf, sizeof(buf), "%.5s", insn->name);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(insn_to_mnemonic);
+
 static int print_insn(char *buffer, unsigned char *code, unsigned long addr)
 {
        struct insn *insn;
@@ -1601,3 +1628,26 @@ void show_code(struct pt_regs *regs)
        }
        printk("\n");
 }
+
+void print_fn_code(unsigned char *code, unsigned long len)
+{
+       char buffer[64], *ptr;
+       int opsize, i;
+
+       while (len) {
+               ptr = buffer;
+               opsize = insn_length(*code);
+               ptr += sprintf(ptr, "%p: ", code);
+               for (i = 0; i < opsize; i++)
+                       ptr += sprintf(ptr, "%02x", code[i]);
+               *ptr++ = '\t';
+               if (i < 4)
+                       *ptr++ = '\t';
+               ptr += print_insn(ptr, code, (unsigned long) code);
+               *ptr++ = '\n';
+               *ptr++ = 0;
+               printk(buffer);
+               code += opsize;
+               len -= opsize;
+       }
+}
index f4eb37680b9152b458938ff37b875754823be695..e4be113fbac62de564bc8566263ae40bd6b4771b 100644 (file)
@@ -719,7 +719,11 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
        long ret = 0;
 
        /* Do the secure computing check first. */
-       secure_computing_strict(regs->gprs[2]);
+       if (secure_computing(regs->gprs[2])) {
+               /* seccomp failures shouldn't expose any additional code. */
+               ret = -1;
+               goto out;
+       }
 
        /*
         * The sysc_tracesys code in entry.S stored the system
@@ -745,6 +749,7 @@ asmlinkage long do_syscall_trace_enter(struct pt_regs *regs)
                            regs->gprs[2], regs->orig_gpr2,
                            regs->gprs[3], regs->gprs[4],
                            regs->gprs[5]);
+out:
        return ret ?: regs->gprs[2];
 }
 
index b4a29eee41b8d59a7542ce040019a62b0e5f4be8..d0964d22adb5aecb66d94005483e04c7c282b657 100644 (file)
@@ -81,11 +81,12 @@ SYSCALL_DEFINE1(s390_personality, unsigned int, personality)
 {
        unsigned int ret;
 
-       if (current->personality == PER_LINUX32 && personality == PER_LINUX)
-               personality = PER_LINUX32;
+       if (personality(current->personality) == PER_LINUX32 &&
+           personality(personality) == PER_LINUX)
+               personality |= PER_LINUX32;
        ret = sys_personality(personality);
-       if (ret == PER_LINUX32)
-               ret = PER_LINUX;
+       if (personality(ret) == PER_LINUX32)
+               ret &= ~PER_LINUX32;
 
        return ret;
 }
index 78eb9847008f2cc8eff307a89e330d42b3dcd69a..a6e2677724e169238a8dfa0a6b97200a764734fb 100644 (file)
@@ -21,6 +21,7 @@ config KVM
        depends on HAVE_KVM && EXPERIMENTAL
        select PREEMPT_NOTIFIERS
        select ANON_INODES
+       select HAVE_KVM_CPU_RELAX_INTERCEPT
        ---help---
          Support hosting paravirtualized guest machines using the SIE
          virtualization capability on the mainframe. This should work
index c88bb7793390d7a1e26d0982529b32d4747ca67f..a390687feb1359d6b579024d51787e4eeff0207e 100644 (file)
@@ -14,6 +14,8 @@
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 #include "kvm-s390.h"
+#include "trace.h"
+#include "trace-s390.h"
 
 static int diag_release_pages(struct kvm_vcpu *vcpu)
 {
@@ -98,6 +100,7 @@ static int __diag_ipl_functions(struct kvm_vcpu *vcpu)
        vcpu->run->exit_reason = KVM_EXIT_S390_RESET;
        VCPU_EVENT(vcpu, 3, "requesting userspace resets %llx",
          vcpu->run->s390_reset_flags);
+       trace_kvm_s390_request_resets(vcpu->run->s390_reset_flags);
        return -EREMOTE;
 }
 
@@ -105,6 +108,7 @@ int kvm_s390_handle_diag(struct kvm_vcpu *vcpu)
 {
        int code = (vcpu->arch.sie_block->ipb & 0xfff0000) >> 16;
 
+       trace_kvm_s390_handle_diag(vcpu, code);
        switch (code) {
        case 0x10:
                return diag_release_pages(vcpu);
index adae539f12e2fbaeb49f41b462f95bc4354ce3f9..22798ec33fd16bd58e5a9726a6f5eec41d798d6a 100644 (file)
@@ -19,6 +19,8 @@
 
 #include "kvm-s390.h"
 #include "gaccess.h"
+#include "trace.h"
+#include "trace-s390.h"
 
 static int handle_lctlg(struct kvm_vcpu *vcpu)
 {
@@ -45,6 +47,7 @@ static int handle_lctlg(struct kvm_vcpu *vcpu)
 
        VCPU_EVENT(vcpu, 5, "lctlg r1:%x, r3:%x,b2:%x,d2:%x", reg1, reg3, base2,
                   disp2);
+       trace_kvm_s390_handle_lctl(vcpu, 1, reg1, reg3, useraddr);
 
        do {
                rc = get_guest_u64(vcpu, useraddr,
@@ -82,6 +85,7 @@ static int handle_lctl(struct kvm_vcpu *vcpu)
 
        VCPU_EVENT(vcpu, 5, "lctl r1:%x, r3:%x,b2:%x,d2:%x", reg1, reg3, base2,
                   disp2);
+       trace_kvm_s390_handle_lctl(vcpu, 0, reg1, reg3, useraddr);
 
        reg = reg1;
        do {
@@ -135,6 +139,8 @@ static int handle_stop(struct kvm_vcpu *vcpu)
        vcpu->stat.exit_stop_request++;
        spin_lock_bh(&vcpu->arch.local_int.lock);
 
+       trace_kvm_s390_stop_request(vcpu->arch.local_int.action_bits);
+
        if (vcpu->arch.local_int.action_bits & ACTION_RELOADVCPU_ON_STOP) {
                vcpu->arch.local_int.action_bits &= ~ACTION_RELOADVCPU_ON_STOP;
                rc = SIE_INTERCEPT_RERUNVCPU;
@@ -171,6 +177,7 @@ static int handle_validity(struct kvm_vcpu *vcpu)
        int rc;
 
        vcpu->stat.exit_validity++;
+       trace_kvm_s390_intercept_validity(vcpu, viwhy);
        if (viwhy == 0x37) {
                vmaddr = gmap_fault(vcpu->arch.sie_block->prefix,
                                    vcpu->arch.gmap);
@@ -213,6 +220,9 @@ static int handle_instruction(struct kvm_vcpu *vcpu)
        intercept_handler_t handler;
 
        vcpu->stat.exit_instruction++;
+       trace_kvm_s390_intercept_instruction(vcpu,
+                                            vcpu->arch.sie_block->ipa,
+                                            vcpu->arch.sie_block->ipb);
        handler = instruction_handlers[vcpu->arch.sie_block->ipa >> 8];
        if (handler)
                return handler(vcpu);
@@ -222,6 +232,7 @@ static int handle_instruction(struct kvm_vcpu *vcpu)
 static int handle_prog(struct kvm_vcpu *vcpu)
 {
        vcpu->stat.exit_program_interruption++;
+       trace_kvm_s390_intercept_prog(vcpu, vcpu->arch.sie_block->iprcc);
        return kvm_s390_inject_program_int(vcpu, vcpu->arch.sie_block->iprcc);
 }
 
index b7bc1aac8ed2dc3611c50f24c7c4b53989642661..7556231fb073f919c9f89b97cbddc3e60b169da5 100644 (file)
@@ -19,6 +19,7 @@
 #include <asm/uaccess.h>
 #include "kvm-s390.h"
 #include "gaccess.h"
+#include "trace-s390.h"
 
 static int psw_extint_disabled(struct kvm_vcpu *vcpu)
 {
@@ -130,6 +131,8 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
        case KVM_S390_INT_EMERGENCY:
                VCPU_EVENT(vcpu, 4, "%s", "interrupt: sigp emerg");
                vcpu->stat.deliver_emergency_signal++;
+               trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
+                                                inti->emerg.code, 0);
                rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x1201);
                if (rc == -EFAULT)
                        exception = 1;
@@ -152,6 +155,8 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
        case KVM_S390_INT_EXTERNAL_CALL:
                VCPU_EVENT(vcpu, 4, "%s", "interrupt: sigp ext call");
                vcpu->stat.deliver_external_call++;
+               trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
+                                                inti->extcall.code, 0);
                rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x1202);
                if (rc == -EFAULT)
                        exception = 1;
@@ -175,6 +180,8 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
                VCPU_EVENT(vcpu, 4, "interrupt: sclp parm:%x",
                           inti->ext.ext_params);
                vcpu->stat.deliver_service_signal++;
+               trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
+                                                inti->ext.ext_params, 0);
                rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x2401);
                if (rc == -EFAULT)
                        exception = 1;
@@ -198,6 +205,9 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
                VCPU_EVENT(vcpu, 4, "interrupt: virtio parm:%x,parm64:%llx",
                           inti->ext.ext_params, inti->ext.ext_params2);
                vcpu->stat.deliver_virtio_interrupt++;
+               trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
+                                                inti->ext.ext_params,
+                                                inti->ext.ext_params2);
                rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x2603);
                if (rc == -EFAULT)
                        exception = 1;
@@ -229,6 +239,8 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
        case KVM_S390_SIGP_STOP:
                VCPU_EVENT(vcpu, 4, "%s", "interrupt: cpu stop");
                vcpu->stat.deliver_stop_signal++;
+               trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
+                                                0, 0);
                __set_intercept_indicator(vcpu, inti);
                break;
 
@@ -236,12 +248,16 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
                VCPU_EVENT(vcpu, 4, "interrupt: set prefix to %x",
                           inti->prefix.address);
                vcpu->stat.deliver_prefix_signal++;
+               trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
+                                                inti->prefix.address, 0);
                kvm_s390_set_prefix(vcpu, inti->prefix.address);
                break;
 
        case KVM_S390_RESTART:
                VCPU_EVENT(vcpu, 4, "%s", "interrupt: cpu restart");
                vcpu->stat.deliver_restart_signal++;
+               trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
+                                                0, 0);
                rc = copy_to_guest(vcpu, offsetof(struct _lowcore,
                  restart_old_psw), &vcpu->arch.sie_block->gpsw, sizeof(psw_t));
                if (rc == -EFAULT)
@@ -259,6 +275,8 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
                           inti->pgm.code,
                           table[vcpu->arch.sie_block->ipa >> 14]);
                vcpu->stat.deliver_program_int++;
+               trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
+                                                inti->pgm.code, 0);
                rc = put_guest_u16(vcpu, __LC_PGM_INT_CODE, inti->pgm.code);
                if (rc == -EFAULT)
                        exception = 1;
@@ -515,6 +533,7 @@ int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code)
        inti->pgm.code = code;
 
        VCPU_EVENT(vcpu, 3, "inject: program check %d (from kernel)", code);
+       trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, inti->type, code, 0, 1);
        spin_lock_bh(&li->lock);
        list_add(&inti->list, &li->list);
        atomic_set(&li->active, 1);
@@ -556,6 +575,8 @@ int kvm_s390_inject_vm(struct kvm *kvm,
                kfree(inti);
                return -EINVAL;
        }
+       trace_kvm_s390_inject_vm(s390int->type, s390int->parm, s390int->parm64,
+                                2);
 
        mutex_lock(&kvm->lock);
        fi = &kvm->arch.float_int;
@@ -621,6 +642,8 @@ int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
                kfree(inti);
                return -EINVAL;
        }
+       trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, s390int->type, s390int->parm,
+                                  s390int->parm64, 2);
 
        mutex_lock(&vcpu->kvm->lock);
        li = &vcpu->arch.local_int;
index d470ccbfabae02e015e206f833a93ec0820941fa..e83df7f0fedd08a084e97f43af61a94c7c15d88f 100644 (file)
 #include "kvm-s390.h"
 #include "gaccess.h"
 
+#define CREATE_TRACE_POINTS
+#include "trace.h"
+#include "trace-s390.h"
+
 #define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU
 
 struct kvm_stats_debugfs_item debugfs_entries[] = {
@@ -242,6 +246,7 @@ out_err:
 void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
 {
        VCPU_EVENT(vcpu, 3, "%s", "free cpu");
+       trace_kvm_s390_destroy_vcpu(vcpu->vcpu_id);
        if (!kvm_is_ucontrol(vcpu->kvm)) {
                clear_bit(63 - vcpu->vcpu_id,
                          (unsigned long *) &vcpu->kvm->arch.sca->mcn);
@@ -417,6 +422,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
                goto out_free_sie_block;
        VM_EVENT(kvm, 3, "create cpu %d at %p, sie block at %p", id, vcpu,
                 vcpu->arch.sie_block);
+       trace_kvm_s390_create_vcpu(id, vcpu, vcpu->arch.sie_block);
 
        return vcpu;
 out_free_sie_block:
@@ -607,18 +613,22 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)
        local_irq_enable();
        VCPU_EVENT(vcpu, 6, "entering sie flags %x",
                   atomic_read(&vcpu->arch.sie_block->cpuflags));
+       trace_kvm_s390_sie_enter(vcpu,
+                                atomic_read(&vcpu->arch.sie_block->cpuflags));
        rc = sie64a(vcpu->arch.sie_block, vcpu->run->s.regs.gprs);
        if (rc) {
                if (kvm_is_ucontrol(vcpu->kvm)) {
                        rc = SIE_INTERCEPT_UCONTROL;
                } else {
                        VCPU_EVENT(vcpu, 3, "%s", "fault in sie instruction");
+                       trace_kvm_s390_sie_fault(vcpu);
                        kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
                        rc = 0;
                }
        }
        VCPU_EVENT(vcpu, 6, "exit sie icptcode %d",
                   vcpu->arch.sie_block->icptcode);
+       trace_kvm_s390_sie_exit(vcpu, vcpu->arch.sie_block->icptcode);
        local_irq_disable();
        kvm_guest_exit();
        local_irq_enable();
index 60da903d6f3ecbb596a2fc90352be1fffc137315..ed256fdd7b58040ac9208ea9aa8ff01979bb8334 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/sysinfo.h>
 #include "gaccess.h"
 #include "kvm-s390.h"
+#include "trace.h"
 
 static int handle_set_prefix(struct kvm_vcpu *vcpu)
 {
@@ -59,6 +60,7 @@ static int handle_set_prefix(struct kvm_vcpu *vcpu)
        kvm_s390_set_prefix(vcpu, address);
 
        VCPU_EVENT(vcpu, 5, "setting prefix to %x", address);
+       trace_kvm_s390_handle_prefix(vcpu, 1, address);
 out:
        return 0;
 }
@@ -91,6 +93,7 @@ static int handle_store_prefix(struct kvm_vcpu *vcpu)
        }
 
        VCPU_EVENT(vcpu, 5, "storing prefix to %x", address);
+       trace_kvm_s390_handle_prefix(vcpu, 0, address);
 out:
        return 0;
 }
@@ -119,6 +122,7 @@ static int handle_store_cpu_address(struct kvm_vcpu *vcpu)
        }
 
        VCPU_EVENT(vcpu, 5, "storing cpu address to %llx", useraddr);
+       trace_kvm_s390_handle_stap(vcpu, useraddr);
 out:
        return 0;
 }
@@ -164,9 +168,11 @@ static int handle_stfl(struct kvm_vcpu *vcpu)
                           &facility_list, sizeof(facility_list));
        if (rc == -EFAULT)
                kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
-       else
+       else {
                VCPU_EVENT(vcpu, 5, "store facility list value %x",
                           facility_list);
+               trace_kvm_s390_handle_stfl(vcpu, facility_list);
+       }
        return 0;
 }
 
@@ -278,6 +284,7 @@ static int handle_stsi(struct kvm_vcpu *vcpu)
                kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
                goto out_mem;
        }
+       trace_kvm_s390_handle_stsi(vcpu, fc, sel1, sel2, operand2);
        free_page(mem);
        vcpu->arch.sie_block->gpsw.mask &= ~(3ul << 44);
        vcpu->run->s.regs.gprs[0] = 0;
index 56f80e1f98f7b1955e23d07bb80497ac3b33dca7..566ddf6e8dfb54290afdb69d706cceadd7b78dbb 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/sigp.h>
 #include "gaccess.h"
 #include "kvm-s390.h"
+#include "trace.h"
 
 static int __sigp_sense(struct kvm_vcpu *vcpu, u16 cpu_addr,
                        u64 *reg)
@@ -344,6 +345,7 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu)
        else
                parameter = vcpu->run->s.regs.gprs[r1 + 1];
 
+       trace_kvm_s390_handle_sigp(vcpu, order_code, cpu_addr, parameter);
        switch (order_code) {
        case SIGP_SENSE:
                vcpu->stat.instruction_sigp_sense++;
diff --git a/arch/s390/kvm/trace-s390.h b/arch/s390/kvm/trace-s390.h
new file mode 100644 (file)
index 0000000..90fdf85
--- /dev/null
@@ -0,0 +1,210 @@
+#if !defined(_TRACE_KVMS390_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_KVMS390_H
+
+#include <linux/tracepoint.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM kvm-s390
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace-s390
+
+/*
+ * Trace point for the creation of the kvm instance.
+ */
+TRACE_EVENT(kvm_s390_create_vm,
+           TP_PROTO(unsigned long type),
+           TP_ARGS(type),
+
+           TP_STRUCT__entry(
+                   __field(unsigned long, type)
+                   ),
+
+           TP_fast_assign(
+                   __entry->type = type;
+                   ),
+
+           TP_printk("create vm%s",
+                     __entry->type & KVM_VM_S390_UCONTROL ? " (UCONTROL)" : "")
+       );
+
+/*
+ * Trace points for creation and destruction of vpcus.
+ */
+TRACE_EVENT(kvm_s390_create_vcpu,
+           TP_PROTO(unsigned int id, struct kvm_vcpu *vcpu,
+                    struct kvm_s390_sie_block *sie_block),
+           TP_ARGS(id, vcpu, sie_block),
+
+           TP_STRUCT__entry(
+                   __field(unsigned int, id)
+                   __field(struct kvm_vcpu *, vcpu)
+                   __field(struct kvm_s390_sie_block *, sie_block)
+                   ),
+
+           TP_fast_assign(
+                   __entry->id = id;
+                   __entry->vcpu = vcpu;
+                   __entry->sie_block = sie_block;
+                   ),
+
+           TP_printk("create cpu %d at %p, sie block at %p", __entry->id,
+                     __entry->vcpu, __entry->sie_block)
+       );
+
+TRACE_EVENT(kvm_s390_destroy_vcpu,
+           TP_PROTO(unsigned int id),
+           TP_ARGS(id),
+
+           TP_STRUCT__entry(
+                   __field(unsigned int, id)
+                   ),
+
+           TP_fast_assign(
+                   __entry->id = id;
+                   ),
+
+           TP_printk("destroy cpu %d", __entry->id)
+       );
+
+/*
+ * Trace points for injection of interrupts, either per machine or
+ * per vcpu.
+ */
+
+#define kvm_s390_int_type                                              \
+       {KVM_S390_SIGP_STOP, "sigp stop"},                              \
+       {KVM_S390_PROGRAM_INT, "program interrupt"},                    \
+       {KVM_S390_SIGP_SET_PREFIX, "sigp set prefix"},                  \
+       {KVM_S390_RESTART, "sigp restart"},                             \
+       {KVM_S390_INT_VIRTIO, "virtio interrupt"},                      \
+       {KVM_S390_INT_SERVICE, "sclp interrupt"},                       \
+       {KVM_S390_INT_EMERGENCY, "sigp emergency"},                     \
+       {KVM_S390_INT_EXTERNAL_CALL, "sigp ext call"}
+
+TRACE_EVENT(kvm_s390_inject_vm,
+           TP_PROTO(__u64 type, __u32 parm, __u64 parm64, int who),
+           TP_ARGS(type, parm, parm64, who),
+
+           TP_STRUCT__entry(
+                   __field(__u32, inttype)
+                   __field(__u32, parm)
+                   __field(__u64, parm64)
+                   __field(int, who)
+                   ),
+
+           TP_fast_assign(
+                   __entry->inttype = type & 0x00000000ffffffff;
+                   __entry->parm = parm;
+                   __entry->parm64 = parm64;
+                   __entry->who = who;
+                   ),
+
+           TP_printk("inject%s: type:%x (%s) parm:%x parm64:%llx",
+                     (__entry->who == 1) ? " (from kernel)" :
+                     (__entry->who == 2) ? " (from user)" : "",
+                     __entry->inttype,
+                     __print_symbolic(__entry->inttype, kvm_s390_int_type),
+                     __entry->parm, __entry->parm64)
+       );
+
+TRACE_EVENT(kvm_s390_inject_vcpu,
+           TP_PROTO(unsigned int id, __u64 type, __u32 parm, __u64 parm64, \
+                    int who),
+           TP_ARGS(id, type, parm, parm64, who),
+
+           TP_STRUCT__entry(
+                   __field(int, id)
+                   __field(__u32, inttype)
+                   __field(__u32, parm)
+                   __field(__u64, parm64)
+                   __field(int, who)
+                   ),
+
+           TP_fast_assign(
+                   __entry->id = id;
+                   __entry->inttype = type & 0x00000000ffffffff;
+                   __entry->parm = parm;
+                   __entry->parm64 = parm64;
+                   __entry->who = who;
+                   ),
+
+           TP_printk("inject%s (vcpu %d): type:%x (%s) parm:%x parm64:%llx",
+                     (__entry->who == 1) ? " (from kernel)" :
+                     (__entry->who == 2) ? " (from user)" : "",
+                     __entry->id, __entry->inttype,
+                     __print_symbolic(__entry->inttype, kvm_s390_int_type),
+                     __entry->parm, __entry->parm64)
+       );
+
+/*
+ * Trace point for the actual delivery of interrupts.
+ */
+TRACE_EVENT(kvm_s390_deliver_interrupt,
+           TP_PROTO(unsigned int id, __u64 type, __u32 data0, __u64 data1),
+           TP_ARGS(id, type, data0, data1),
+
+           TP_STRUCT__entry(
+                   __field(int, id)
+                   __field(__u32, inttype)
+                   __field(__u32, data0)
+                   __field(__u64, data1)
+                   ),
+
+           TP_fast_assign(
+                   __entry->id = id;
+                   __entry->inttype = type & 0x00000000ffffffff;
+                   __entry->data0 = data0;
+                   __entry->data1 = data1;
+                   ),
+
+           TP_printk("deliver interrupt (vcpu %d): type:%x (%s) "      \
+                     "data:%08x %016llx",
+                     __entry->id, __entry->inttype,
+                     __print_symbolic(__entry->inttype, kvm_s390_int_type),
+                     __entry->data0, __entry->data1)
+       );
+
+/*
+ * Trace point for resets that may be requested from userspace.
+ */
+TRACE_EVENT(kvm_s390_request_resets,
+           TP_PROTO(__u64 resets),
+           TP_ARGS(resets),
+
+           TP_STRUCT__entry(
+                   __field(__u64, resets)
+                   ),
+
+           TP_fast_assign(
+                   __entry->resets = resets;
+                   ),
+
+           TP_printk("requesting userspace resets %llx",
+                     __entry->resets)
+       );
+
+/*
+ * Trace point for a vcpu's stop requests.
+ */
+TRACE_EVENT(kvm_s390_stop_request,
+           TP_PROTO(unsigned int action_bits),
+           TP_ARGS(action_bits),
+
+           TP_STRUCT__entry(
+                   __field(unsigned int, action_bits)
+                   ),
+
+           TP_fast_assign(
+                   __entry->action_bits = action_bits;
+                   ),
+
+           TP_printk("stop request, action_bits = %08x",
+                     __entry->action_bits)
+       );
+
+
+#endif /* _TRACE_KVMS390_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/arch/s390/kvm/trace.h b/arch/s390/kvm/trace.h
new file mode 100644 (file)
index 0000000..2b29e62
--- /dev/null
@@ -0,0 +1,341 @@
+#if !defined(_TRACE_KVM_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_KVM_H
+
+#include <linux/tracepoint.h>
+#include <asm/sigp.h>
+#include <asm/debug.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM kvm
+#define TRACE_INCLUDE_PATH .
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE trace
+
+/*
+ * Helpers for vcpu-specific tracepoints containing the same information
+ * as s390dbf VCPU_EVENTs.
+ */
+#define VCPU_PROTO_COMMON struct kvm_vcpu *vcpu
+#define VCPU_ARGS_COMMON vcpu
+#define VCPU_FIELD_COMMON __field(int, id)                     \
+       __field(unsigned long, pswmask)                         \
+       __field(unsigned long, pswaddr)
+#define VCPU_ASSIGN_COMMON do {                                                \
+       __entry->id = vcpu->vcpu_id;                                    \
+       __entry->pswmask = vcpu->arch.sie_block->gpsw.mask;             \
+       __entry->pswaddr = vcpu->arch.sie_block->gpsw.addr;             \
+       } while (0);
+#define VCPU_TP_PRINTK(p_str, p_args...)                               \
+       TP_printk("%02d[%016lx-%016lx]: " p_str, __entry->id,           \
+                 __entry->pswmask, __entry->pswaddr, p_args)
+
+/*
+ * Tracepoints for SIE entry and exit.
+ */
+TRACE_EVENT(kvm_s390_sie_enter,
+           TP_PROTO(VCPU_PROTO_COMMON, int cpuflags),
+           TP_ARGS(VCPU_ARGS_COMMON, cpuflags),
+
+           TP_STRUCT__entry(
+                   VCPU_FIELD_COMMON
+                   __field(int, cpuflags)
+                   ),
+
+           TP_fast_assign(
+                   VCPU_ASSIGN_COMMON
+                   __entry->cpuflags = cpuflags;
+                   ),
+
+           VCPU_TP_PRINTK("entering sie flags %x", __entry->cpuflags)
+       );
+
+TRACE_EVENT(kvm_s390_sie_fault,
+           TP_PROTO(VCPU_PROTO_COMMON),
+           TP_ARGS(VCPU_ARGS_COMMON),
+
+           TP_STRUCT__entry(
+                   VCPU_FIELD_COMMON
+                   ),
+
+           TP_fast_assign(
+                   VCPU_ASSIGN_COMMON
+                   ),
+
+           VCPU_TP_PRINTK("%s", "fault in sie instruction")
+       );
+
+#define sie_intercept_code                             \
+       {0x04, "Instruction"},                          \
+       {0x08, "Program interruption"},                 \
+       {0x0C, "Instruction and program interuption"},  \
+       {0x10, "External request"},                     \
+       {0x14, "External interruption"},                \
+       {0x18, "I/O request"},                          \
+       {0x1C, "Wait state"},                           \
+       {0x20, "Validity"},                             \
+       {0x28, "Stop request"}
+
+TRACE_EVENT(kvm_s390_sie_exit,
+           TP_PROTO(VCPU_PROTO_COMMON, u8 icptcode),
+           TP_ARGS(VCPU_ARGS_COMMON, icptcode),
+
+           TP_STRUCT__entry(
+                   VCPU_FIELD_COMMON
+                   __field(u8, icptcode)
+                   ),
+
+           TP_fast_assign(
+                   VCPU_ASSIGN_COMMON
+                   __entry->icptcode = icptcode;
+                   ),
+
+           VCPU_TP_PRINTK("exit sie icptcode %d (%s)", __entry->icptcode,
+                          __print_symbolic(__entry->icptcode,
+                                           sie_intercept_code))
+       );
+
+/*
+ * Trace point for intercepted instructions.
+ */
+TRACE_EVENT(kvm_s390_intercept_instruction,
+           TP_PROTO(VCPU_PROTO_COMMON, __u16 ipa, __u32 ipb),
+           TP_ARGS(VCPU_ARGS_COMMON, ipa, ipb),
+
+           TP_STRUCT__entry(
+                   VCPU_FIELD_COMMON
+                   __field(__u64, instruction)
+                   __field(char, insn[8])
+                   ),
+
+           TP_fast_assign(
+                   VCPU_ASSIGN_COMMON
+                   __entry->instruction = ((__u64)ipa << 48) |
+                   ((__u64)ipb << 16);
+                   ),
+
+           VCPU_TP_PRINTK("intercepted instruction %016llx (%s)",
+                          __entry->instruction,
+                          insn_to_mnemonic((unsigned char *)
+                                           &__entry->instruction,
+                                        __entry->insn) ?
+                          "unknown" : __entry->insn)
+       );
+
+/*
+ * Trace point for intercepted program interruptions.
+ */
+TRACE_EVENT(kvm_s390_intercept_prog,
+           TP_PROTO(VCPU_PROTO_COMMON, __u16 code),
+           TP_ARGS(VCPU_ARGS_COMMON, code),
+
+           TP_STRUCT__entry(
+                   VCPU_FIELD_COMMON
+                   __field(__u16, code)
+                   ),
+
+           TP_fast_assign(
+                   VCPU_ASSIGN_COMMON
+                   __entry->code = code;
+                   ),
+
+           VCPU_TP_PRINTK("intercepted program interruption %04x",
+                          __entry->code)
+       );
+
+/*
+ * Trace point for validity intercepts.
+ */
+TRACE_EVENT(kvm_s390_intercept_validity,
+           TP_PROTO(VCPU_PROTO_COMMON, __u16 viwhy),
+           TP_ARGS(VCPU_ARGS_COMMON, viwhy),
+
+           TP_STRUCT__entry(
+                   VCPU_FIELD_COMMON
+                   __field(__u16, viwhy)
+                   ),
+
+           TP_fast_assign(
+                   VCPU_ASSIGN_COMMON
+                   __entry->viwhy = viwhy;
+                   ),
+
+           VCPU_TP_PRINTK("got validity intercept %04x", __entry->viwhy)
+       );
+
+/*
+ * Trace points for instructions that are of special interest.
+ */
+
+#define sigp_order_codes                                       \
+       {SIGP_SENSE, "sense"},                                  \
+       {SIGP_EXTERNAL_CALL, "external call"},                  \
+       {SIGP_EMERGENCY_SIGNAL, "emergency signal"},            \
+       {SIGP_STOP, "stop"},                                    \
+       {SIGP_STOP_AND_STORE_STATUS, "stop and store status"},  \
+       {SIGP_SET_ARCHITECTURE, "set architecture"},            \
+       {SIGP_SET_PREFIX, "set prefix"},                        \
+       {SIGP_SENSE_RUNNING, "sense running"},                  \
+       {SIGP_RESTART, "restart"}
+
+TRACE_EVENT(kvm_s390_handle_sigp,
+           TP_PROTO(VCPU_PROTO_COMMON, __u8 order_code, __u16 cpu_addr, \
+                    __u32 parameter),
+           TP_ARGS(VCPU_ARGS_COMMON, order_code, cpu_addr, parameter),
+
+           TP_STRUCT__entry(
+                   VCPU_FIELD_COMMON
+                   __field(__u8, order_code)
+                   __field(__u16, cpu_addr)
+                   __field(__u32, parameter)
+                   ),
+
+           TP_fast_assign(
+                   VCPU_ASSIGN_COMMON
+                   __entry->order_code = order_code;
+                   __entry->cpu_addr = cpu_addr;
+                   __entry->parameter = parameter;
+                   ),
+
+           VCPU_TP_PRINTK("handle sigp order %02x (%s), cpu address %04x, " \
+                          "parameter %08x", __entry->order_code,
+                          __print_symbolic(__entry->order_code,
+                                           sigp_order_codes),
+                          __entry->cpu_addr, __entry->parameter)
+       );
+
+#define diagnose_codes                         \
+       {0x10, "release pages"},                \
+       {0x44, "time slice end"},               \
+       {0x308, "ipl functions"},               \
+       {0x500, "kvm hypercall"},               \
+       {0x501, "kvm breakpoint"}
+
+TRACE_EVENT(kvm_s390_handle_diag,
+           TP_PROTO(VCPU_PROTO_COMMON, __u16 code),
+           TP_ARGS(VCPU_ARGS_COMMON, code),
+
+           TP_STRUCT__entry(
+                   VCPU_FIELD_COMMON
+                   __field(__u16, code)
+                   ),
+
+           TP_fast_assign(
+                   VCPU_ASSIGN_COMMON
+                   __entry->code = code;
+                   ),
+
+           VCPU_TP_PRINTK("handle diagnose call %04x (%s)", __entry->code,
+                          __print_symbolic(__entry->code, diagnose_codes))
+       );
+
+TRACE_EVENT(kvm_s390_handle_lctl,
+           TP_PROTO(VCPU_PROTO_COMMON, int g, int reg1, int reg3, u64 addr),
+           TP_ARGS(VCPU_ARGS_COMMON, g, reg1, reg3, addr),
+
+           TP_STRUCT__entry(
+                   VCPU_FIELD_COMMON
+                   __field(int, g)
+                   __field(int, reg1)
+                   __field(int, reg3)
+                   __field(u64, addr)
+                   ),
+
+           TP_fast_assign(
+                   VCPU_ASSIGN_COMMON
+                   __entry->g = g;
+                   __entry->reg1 = reg1;
+                   __entry->reg3 = reg3;
+                   __entry->addr = addr;
+                   ),
+
+           VCPU_TP_PRINTK("%s: loading cr %x-%x from %016llx",
+                          __entry->g ? "lctlg" : "lctl",
+                          __entry->reg1, __entry->reg3, __entry->addr)
+       );
+
+TRACE_EVENT(kvm_s390_handle_prefix,
+           TP_PROTO(VCPU_PROTO_COMMON, int set, u32 address),
+           TP_ARGS(VCPU_ARGS_COMMON, set, address),
+
+           TP_STRUCT__entry(
+                   VCPU_FIELD_COMMON
+                   __field(int, set)
+                   __field(u32, address)
+                   ),
+
+           TP_fast_assign(
+                   VCPU_ASSIGN_COMMON
+                   __entry->set = set;
+                   __entry->address = address;
+                   ),
+
+           VCPU_TP_PRINTK("%s prefix to %08x",
+                          __entry->set ? "setting" : "storing",
+                          __entry->address)
+       );
+
+TRACE_EVENT(kvm_s390_handle_stap,
+           TP_PROTO(VCPU_PROTO_COMMON, u64 address),
+           TP_ARGS(VCPU_ARGS_COMMON, address),
+
+           TP_STRUCT__entry(
+                   VCPU_FIELD_COMMON
+                   __field(u64, address)
+                   ),
+
+           TP_fast_assign(
+                   VCPU_ASSIGN_COMMON
+                   __entry->address = address;
+                   ),
+
+           VCPU_TP_PRINTK("storing cpu address to %016llx",
+                          __entry->address)
+       );
+
+TRACE_EVENT(kvm_s390_handle_stfl,
+           TP_PROTO(VCPU_PROTO_COMMON, unsigned int facility_list),
+           TP_ARGS(VCPU_ARGS_COMMON, facility_list),
+
+           TP_STRUCT__entry(
+                   VCPU_FIELD_COMMON
+                   __field(unsigned int, facility_list)
+                   ),
+
+           TP_fast_assign(
+                   VCPU_ASSIGN_COMMON
+                   __entry->facility_list = facility_list;
+                   ),
+
+           VCPU_TP_PRINTK("store facility list value %08x",
+                          __entry->facility_list)
+       );
+
+TRACE_EVENT(kvm_s390_handle_stsi,
+           TP_PROTO(VCPU_PROTO_COMMON, int fc, int sel1, int sel2, u64 addr),
+           TP_ARGS(VCPU_ARGS_COMMON, fc, sel1, sel2, addr),
+
+           TP_STRUCT__entry(
+                   VCPU_FIELD_COMMON
+                   __field(int, fc)
+                   __field(int, sel1)
+                   __field(int, sel2)
+                   __field(u64, addr)
+                   ),
+
+           TP_fast_assign(
+                   VCPU_ASSIGN_COMMON
+                   __entry->fc = fc;
+                   __entry->sel1 = sel1;
+                   __entry->sel2 = sel2;
+                   __entry->addr = addr;
+                   ),
+
+           VCPU_TP_PRINTK("STSI %d.%d.%d information stored to %016llx",
+                          __entry->fc, __entry->sel1, __entry->sel2,
+                          __entry->addr)
+       );
+
+#endif /* _TRACE_KVM_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/arch/s390/net/Makefile b/arch/s390/net/Makefile
new file mode 100644 (file)
index 0000000..90568c3
--- /dev/null
@@ -0,0 +1,4 @@
+#
+# Arch-specific network modules
+#
+obj-$(CONFIG_BPF_JIT) += bpf_jit.o bpf_jit_comp.o
diff --git a/arch/s390/net/bpf_jit.S b/arch/s390/net/bpf_jit.S
new file mode 100644 (file)
index 0000000..d3fee59
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * BPF Jit compiler for s390, help functions.
+ *
+ * Copyright IBM Corp. 2012
+ *
+ * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
+ */
+#include <linux/linkage.h>
+
+/*
+ * Calling convention:
+ * registers %r2, %r3, %r6-%r15 are call saved
+ *   %r2: skb pointer
+ *   %r3: offset parameter
+ *   %r5: result in BPF A accumulator
+ *   %r8: return address
+ *   %r9: save register for skb pointer
+ *   %r10: skb->data
+ *   %r11: skb->len - skb->data_len (headlen)
+ *   %r12: BPF X accumulator
+ *
+ * skb_copy_bits takes 4 parameters:
+ *   %r2 = skb pointer
+ *   %r3 = offset into skb data
+ *   %r4 = length to copy
+ *   %r5 = pointer to temp buffer
+ */
+#define SKBDATA        %r8
+
+       /* A = *(u32 *) (skb->data+K+X) */
+ENTRY(sk_load_word_ind)
+       ar      %r3,%r12                # offset += X
+       bmr     %r8                     # < 0 -> return with cc
+
+       /* A = *(u32 *) (skb->data+K) */
+ENTRY(sk_load_word)
+       llgfr   %r1,%r3                 # extend offset
+       ahi     %r3,4                   # offset + 4
+       clr     %r11,%r3                # hlen <= offset + 4 ?
+       jl      sk_load_word_slow
+       l       %r5,0(%r1,%r10)         # get word from skb
+       xr      %r1,%r1                 # set cc to zero
+       br      %r8
+
+sk_load_word_slow:
+       lgr     %r9,%r2                 # save %r2
+       lhi     %r4,4                   # 4 bytes
+       la      %r5,160(%r15)           # pointer to temp buffer
+       brasl   %r14,skb_copy_bits      # get data from skb
+       l       %r5,160(%r15)           # load result from temp buffer
+       ltgr    %r2,%r2                 # set cc to (%r2 != 0)
+       lgr     %r2,%r9                 # restore %r2
+       br      %r8
+
+       /* A = *(u16 *) (skb->data+K+X) */
+ENTRY(sk_load_half_ind)
+       ar      %r3,%r12                # offset += X
+       bmr     %r8                     # < 0 -> return with cc
+
+       /* A = *(u16 *) (skb->data+K) */
+ENTRY(sk_load_half)
+       llgfr   %r1,%r3                 # extend offset
+       ahi     %r3,2                   # offset + 2
+       clr     %r11,%r3                # hlen <= offset + 2 ?
+       jl      sk_load_half_slow
+       llgh    %r5,0(%r1,%r10)         # get half from skb
+       xr      %r1,%r1                 # set cc to zero
+       br      %r8
+
+sk_load_half_slow:
+       lgr     %r9,%r2                 # save %r2
+       lhi     %r4,2                   # 2 bytes
+       la      %r5,162(%r15)           # pointer to temp buffer
+       brasl   %r14,skb_copy_bits      # get data from skb
+       xc      160(2,%r15),160(%r15)
+       l       %r5,160(%r15)           # load result from temp buffer
+       ltgr    %r2,%r2                 # set cc to (%r2 != 0)
+       lgr     %r2,%r9                 # restore %r2
+       br      %r8
+
+       /* A = *(u8 *) (skb->data+K+X) */
+ENTRY(sk_load_byte_ind)
+       ar      %r3,%r12                # offset += X
+       bmr     %r8                     # < 0 -> return with cc
+
+       /* A = *(u8 *) (skb->data+K) */
+ENTRY(sk_load_byte)
+       llgfr   %r1,%r3                 # extend offset
+       clr     %r11,%r3                # hlen < offset ?
+       jle     sk_load_byte_slow
+       lhi     %r5,0
+       ic      %r5,0(%r1,%r10)         # get byte from skb
+       xr      %r1,%r1                 # set cc to zero
+       br      %r8
+
+sk_load_byte_slow:
+       lgr     %r9,%r2                 # save %r2
+       lhi     %r4,1                   # 1 bytes
+       la      %r5,163(%r15)           # pointer to temp buffer
+       brasl   %r14,skb_copy_bits      # get data from skb
+       xc      160(3,%r15),160(%r15)
+       l       %r5,160(%r15)           # load result from temp buffer
+       ltgr    %r2,%r2                 # set cc to (%r2 != 0)
+       lgr     %r2,%r9                 # restore %r2
+       br      %r8
+
+       /* A = (*(u8 *)(skb->data+K) & 0xf) << 2 */
+ENTRY(sk_load_byte_msh)
+       llgfr   %r1,%r3                 # extend offset
+       clr     %r11,%r3                # hlen < offset ?
+       jle     sk_load_byte_slow
+       lhi     %r12,0
+       ic      %r12,0(%r1,%r10)        # get byte from skb
+       nill    %r12,0x0f
+       sll     %r12,2
+       xr      %r1,%r1                 # set cc to zero
+       br      %r8
+
+sk_load_byte_msh_slow:
+       lgr     %r9,%r2                 # save %r2
+       lhi     %r4,2                   # 2 bytes
+       la      %r5,162(%r15)           # pointer to temp buffer
+       brasl   %r14,skb_copy_bits      # get data from skb
+       xc      160(3,%r15),160(%r15)
+       l       %r12,160(%r15)          # load result from temp buffer
+       nill    %r12,0x0f
+       sll     %r12,2
+       ltgr    %r2,%r2                 # set cc to (%r2 != 0)
+       lgr     %r2,%r9                 # restore %r2
+       br      %r8
diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c
new file mode 100644 (file)
index 0000000..b07aa3d
--- /dev/null
@@ -0,0 +1,738 @@
+/*
+ * BPF Jit compiler for s390.
+ *
+ * Copyright IBM Corp. 2012
+ *
+ * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
+ */
+#include <linux/moduleloader.h>
+#include <linux/netdevice.h>
+#include <linux/filter.h>
+#include <asm/cacheflush.h>
+#include <asm/processor.h>
+
+/*
+ * Conventions:
+ *   %r2 = skb pointer
+ *   %r3 = offset parameter
+ *   %r4 = scratch register / length parameter
+ *   %r5 = BPF A accumulator
+ *   %r8 = return address
+ *   %r9 = save register for skb pointer
+ *   %r10 = skb->data
+ *   %r11 = skb->len - skb->data_len (headlen)
+ *   %r12 = BPF X accumulator
+ *   %r13 = literal pool pointer
+ *   0(%r15) - 63(%r15) scratch memory array with BPF_MEMWORDS
+ */
+int bpf_jit_enable __read_mostly;
+
+/*
+ * assembly code in arch/x86/net/bpf_jit.S
+ */
+extern u8 sk_load_word[], sk_load_half[], sk_load_byte[], sk_load_byte_msh[];
+extern u8 sk_load_word_ind[], sk_load_half_ind[], sk_load_byte_ind[];
+
+struct bpf_jit {
+       unsigned int seen;
+       u8 *start;
+       u8 *prg;
+       u8 *mid;
+       u8 *lit;
+       u8 *end;
+       u8 *base_ip;
+       u8 *ret0_ip;
+       u8 *exit_ip;
+       unsigned int off_load_word;
+       unsigned int off_load_half;
+       unsigned int off_load_byte;
+       unsigned int off_load_bmsh;
+       unsigned int off_load_iword;
+       unsigned int off_load_ihalf;
+       unsigned int off_load_ibyte;
+};
+
+#define BPF_SIZE_MAX   4096    /* Max size for program */
+
+#define SEEN_DATAREF   1       /* might call external helpers */
+#define SEEN_XREG      2       /* ebx is used */
+#define SEEN_MEM       4       /* use mem[] for temporary storage */
+#define SEEN_RET0      8       /* pc_ret0 points to a valid return 0 */
+#define SEEN_LITERAL   16      /* code uses literals */
+#define SEEN_LOAD_WORD 32      /* code uses sk_load_word */
+#define SEEN_LOAD_HALF 64      /* code uses sk_load_half */
+#define SEEN_LOAD_BYTE 128     /* code uses sk_load_byte */
+#define SEEN_LOAD_BMSH 256     /* code uses sk_load_byte_msh */
+#define SEEN_LOAD_IWORD        512     /* code uses sk_load_word_ind */
+#define SEEN_LOAD_IHALF        1024    /* code uses sk_load_half_ind */
+#define SEEN_LOAD_IBYTE        2048    /* code uses sk_load_byte_ind */
+
+#define EMIT2(op)                                      \
+({                                                     \
+       if (jit->prg + 2 <= jit->mid)                   \
+               *(u16 *) jit->prg = op;                 \
+       jit->prg += 2;                                  \
+})
+
+#define EMIT4(op)                                      \
+({                                                     \
+       if (jit->prg + 4 <= jit->mid)                   \
+               *(u32 *) jit->prg = op;                 \
+       jit->prg += 4;                                  \
+})
+
+#define EMIT4_DISP(op, disp)                           \
+({                                                     \
+       unsigned int __disp = (disp) & 0xfff;           \
+       EMIT4(op | __disp);                             \
+})
+
+#define EMIT4_IMM(op, imm)                             \
+({                                                     \
+       unsigned int __imm = (imm) & 0xffff;            \
+       EMIT4(op | __imm);                              \
+})
+
+#define EMIT4_PCREL(op, pcrel)                         \
+({                                                     \
+       long __pcrel = ((pcrel) >> 1) & 0xffff;         \
+       EMIT4(op | __pcrel);                            \
+})
+
+#define EMIT6(op1, op2)                                        \
+({                                                     \
+       if (jit->prg + 6 <= jit->mid) {                 \
+               *(u32 *) jit->prg = op1;                \
+               *(u16 *) (jit->prg + 4) = op2;          \
+       }                                               \
+       jit->prg += 6;                                  \
+})
+
+#define EMIT6_DISP(op1, op2, disp)                     \
+({                                                     \
+       unsigned int __disp = (disp) & 0xfff;           \
+       EMIT6(op1 | __disp, op2);                       \
+})
+
+#define EMIT_CONST(val)                                        \
+({                                                     \
+       unsigned int ret;                               \
+       ret = (unsigned int) (jit->lit - jit->base_ip); \
+       jit->seen |= SEEN_LITERAL;                      \
+       if (jit->lit + 4 <= jit->end)                   \
+               *(u32 *) jit->lit = val;                \
+       jit->lit += 4;                                  \
+       ret;                                            \
+})
+
+#define EMIT_FN_CONST(bit, fn)                         \
+({                                                     \
+       unsigned int ret;                               \
+       ret = (unsigned int) (jit->lit - jit->base_ip); \
+       if (jit->seen & bit) {                          \
+               jit->seen |= SEEN_LITERAL;              \
+               if (jit->lit + 8 <= jit->end)           \
+                       *(void **) jit->lit = fn;       \
+               jit->lit += 8;                          \
+       }                                               \
+       ret;                                            \
+})
+
+static void bpf_jit_prologue(struct bpf_jit *jit)
+{
+       /* Save registers and create stack frame if necessary */
+       if (jit->seen & SEEN_DATAREF) {
+               /* stmg %r8,%r15,88(%r15) */
+               EMIT6(0xeb8ff058, 0x0024);
+               /* lgr %r14,%r15 */
+               EMIT4(0xb90400ef);
+               /* ahi %r15,<offset> */
+               EMIT4_IMM(0xa7fa0000, (jit->seen & SEEN_MEM) ? -112 : -80);
+               /* stg %r14,152(%r15) */
+               EMIT6(0xe3e0f098, 0x0024);
+       } else if ((jit->seen & SEEN_XREG) && (jit->seen & SEEN_LITERAL))
+               /* stmg %r12,%r13,120(%r15) */
+               EMIT6(0xebcdf078, 0x0024);
+       else if (jit->seen & SEEN_XREG)
+               /* stg %r12,120(%r15) */
+               EMIT6(0xe3c0f078, 0x0024);
+       else if (jit->seen & SEEN_LITERAL)
+               /* stg %r13,128(%r15) */
+               EMIT6(0xe3d0f080, 0x0024);
+
+       /* Setup literal pool */
+       if (jit->seen & SEEN_LITERAL) {
+               /* basr %r13,0 */
+               EMIT2(0x0dd0);
+               jit->base_ip = jit->prg;
+       }
+       jit->off_load_word = EMIT_FN_CONST(SEEN_LOAD_WORD, sk_load_word);
+       jit->off_load_half = EMIT_FN_CONST(SEEN_LOAD_HALF, sk_load_half);
+       jit->off_load_byte = EMIT_FN_CONST(SEEN_LOAD_BYTE, sk_load_byte);
+       jit->off_load_bmsh = EMIT_FN_CONST(SEEN_LOAD_BMSH, sk_load_byte_msh);
+       jit->off_load_iword = EMIT_FN_CONST(SEEN_LOAD_IWORD, sk_load_word_ind);
+       jit->off_load_ihalf = EMIT_FN_CONST(SEEN_LOAD_IHALF, sk_load_half_ind);
+       jit->off_load_ibyte = EMIT_FN_CONST(SEEN_LOAD_IBYTE, sk_load_byte_ind);
+
+       /* Filter needs to access skb data */
+       if (jit->seen & SEEN_DATAREF) {
+               /* l %r11,<len>(%r2) */
+               EMIT4_DISP(0x58b02000, offsetof(struct sk_buff, len));
+               /* s %r11,<data_len>(%r2) */
+               EMIT4_DISP(0x5bb02000, offsetof(struct sk_buff, data_len));
+               /* lg %r10,<data>(%r2) */
+               EMIT6_DISP(0xe3a02000, 0x0004,
+                          offsetof(struct sk_buff, data));
+       }
+}
+
+static void bpf_jit_epilogue(struct bpf_jit *jit)
+{
+       /* Return 0 */
+       if (jit->seen & SEEN_RET0) {
+               jit->ret0_ip = jit->prg;
+               /* lghi %r2,0 */
+               EMIT4(0xa7290000);
+       }
+       jit->exit_ip = jit->prg;
+       /* Restore registers */
+       if (jit->seen & SEEN_DATAREF)
+               /* lmg %r8,%r15,<offset>(%r15) */
+               EMIT6_DISP(0xeb8ff000, 0x0004,
+                          (jit->seen & SEEN_MEM) ? 200 : 168);
+       else if ((jit->seen & SEEN_XREG) && (jit->seen & SEEN_LITERAL))
+               /* lmg %r12,%r13,120(%r15) */
+               EMIT6(0xebcdf078, 0x0004);
+       else if (jit->seen & SEEN_XREG)
+               /* lg %r12,120(%r15) */
+               EMIT6(0xe3c0f078, 0x0004);
+       else if (jit->seen & SEEN_LITERAL)
+               /* lg %r13,128(%r15) */
+               EMIT6(0xe3d0f080, 0x0004);
+       /* br %r14 */
+       EMIT2(0x07fe);
+}
+
+/*
+ * make sure we dont leak kernel information to user
+ */
+static void bpf_jit_noleaks(struct bpf_jit *jit, struct sock_filter *filter)
+{
+       /* Clear temporary memory if (seen & SEEN_MEM) */
+       if (jit->seen & SEEN_MEM)
+               /* xc 0(64,%r15),0(%r15) */
+               EMIT6(0xd73ff000, 0xf000);
+       /* Clear X if (seen & SEEN_XREG) */
+       if (jit->seen & SEEN_XREG)
+               /* lhi %r12,0 */
+               EMIT4(0xa7c80000);
+       /* Clear A if the first register does not set it. */
+       switch (filter[0].code) {
+       case BPF_S_LD_W_ABS:
+       case BPF_S_LD_H_ABS:
+       case BPF_S_LD_B_ABS:
+       case BPF_S_LD_W_LEN:
+       case BPF_S_LD_W_IND:
+       case BPF_S_LD_H_IND:
+       case BPF_S_LD_B_IND:
+       case BPF_S_LDX_B_MSH:
+       case BPF_S_LD_IMM:
+       case BPF_S_LD_MEM:
+       case BPF_S_MISC_TXA:
+       case BPF_S_ANC_PROTOCOL:
+       case BPF_S_ANC_PKTTYPE:
+       case BPF_S_ANC_IFINDEX:
+       case BPF_S_ANC_MARK:
+       case BPF_S_ANC_QUEUE:
+       case BPF_S_ANC_HATYPE:
+       case BPF_S_ANC_RXHASH:
+       case BPF_S_ANC_CPU:
+       case BPF_S_RET_K:
+               /* first instruction sets A register */
+               break;
+       default: /* A = 0 */
+               /* lhi %r5,0 */
+               EMIT4(0xa7580000);
+       }
+}
+
+static int bpf_jit_insn(struct bpf_jit *jit, struct sock_filter *filter,
+                       unsigned int *addrs, int i, int last)
+{
+       unsigned int K;
+       int offset;
+       unsigned int mask;
+
+       K = filter->k;
+       switch (filter->code) {
+       case BPF_S_ALU_ADD_X: /* A += X */
+               jit->seen |= SEEN_XREG;
+               /* ar %r5,%r12 */
+               EMIT2(0x1a5c);
+               break;
+       case BPF_S_ALU_ADD_K: /* A += K */
+               if (!K)
+                       break;
+               if (K <= 16383)
+                       /* ahi %r5,<K> */
+                       EMIT4_IMM(0xa75a0000, K);
+               else
+                       /* a %r5,<d(K)>(%r13) */
+                       EMIT4_DISP(0x5a50d000, EMIT_CONST(K));
+               break;
+       case BPF_S_ALU_SUB_X: /* A -= X */
+               jit->seen |= SEEN_XREG;
+               /* sr %r5,%r12 */
+               EMIT2(0x1b5c);
+               break;
+       case BPF_S_ALU_SUB_K: /* A -= K */
+               if (!K)
+                       break;
+               if (K <= 16384)
+                       /* ahi %r5,-K */
+                       EMIT4_IMM(0xa75a0000, -K);
+               else
+                       /* s %r5,<d(K)>(%r13) */
+                       EMIT4_DISP(0x5b50d000, EMIT_CONST(K));
+               break;
+       case BPF_S_ALU_MUL_X: /* A *= X */
+               jit->seen |= SEEN_XREG;
+               /* msr %r5,%r12 */
+               EMIT4(0xb252005c);
+               break;
+       case BPF_S_ALU_MUL_K: /* A *= K */
+               if (K <= 16383)
+                       /* mhi %r5,K */
+                       EMIT4_IMM(0xa75c0000, K);
+               else
+                       /* ms %r5,<d(K)>(%r13) */
+                       EMIT4_DISP(0x7150d000, EMIT_CONST(K));
+               break;
+       case BPF_S_ALU_DIV_X: /* A /= X */
+               jit->seen |= SEEN_XREG | SEEN_RET0;
+               /* ltr %r12,%r12 */
+               EMIT2(0x12cc);
+               /* jz <ret0> */
+               EMIT4_PCREL(0xa7840000, (jit->ret0_ip - jit->prg));
+               /* lhi %r4,0 */
+               EMIT4(0xa7480000);
+               /* dr %r4,%r12 */
+               EMIT2(0x1d4c);
+               break;
+       case BPF_S_ALU_DIV_K: /* A = reciprocal_divide(A, K) */
+               /* m %r4,<d(K)>(%r13) */
+               EMIT4_DISP(0x5c40d000, EMIT_CONST(K));
+               /* lr %r5,%r4 */
+               EMIT2(0x1854);
+               break;
+       case BPF_S_ALU_AND_X: /* A &= X */
+               jit->seen |= SEEN_XREG;
+               /* nr %r5,%r12 */
+               EMIT2(0x145c);
+               break;
+       case BPF_S_ALU_AND_K: /* A &= K */
+               /* n %r5,<d(K)>(%r13) */
+               EMIT4_DISP(0x5450d000, EMIT_CONST(K));
+               break;
+       case BPF_S_ALU_OR_X: /* A |= X */
+               jit->seen |= SEEN_XREG;
+               /* or %r5,%r12 */
+               EMIT2(0x165c);
+               break;
+       case BPF_S_ALU_OR_K: /* A |= K */
+               /* o %r5,<d(K)>(%r13) */
+               EMIT4_DISP(0x5650d000, EMIT_CONST(K));
+               break;
+       case BPF_S_ALU_LSH_X: /* A <<= X; */
+               jit->seen |= SEEN_XREG;
+               /* sll %r5,0(%r12) */
+               EMIT4(0x8950c000);
+               break;
+       case BPF_S_ALU_LSH_K: /* A <<= K */
+               if (K == 0)
+                       break;
+               /* sll %r5,K */
+               EMIT4_DISP(0x89500000, K);
+               break;
+       case BPF_S_ALU_RSH_X: /* A >>= X; */
+               jit->seen |= SEEN_XREG;
+               /* srl %r5,0(%r12) */
+               EMIT4(0x8850c000);
+               break;
+       case BPF_S_ALU_RSH_K: /* A >>= K; */
+               if (K == 0)
+                       break;
+               /* srl %r5,K */
+               EMIT4_DISP(0x88500000, K);
+               break;
+       case BPF_S_ALU_NEG: /* A = -A */
+               /* lnr %r5,%r5 */
+               EMIT2(0x1155);
+               break;
+       case BPF_S_JMP_JA: /* ip += K */
+               offset = addrs[i + K] + jit->start - jit->prg;
+               EMIT4_PCREL(0xa7f40000, offset);
+               break;
+       case BPF_S_JMP_JGT_K: /* ip += (A > K) ? jt : jf */
+               mask = 0x200000; /* jh */
+               goto kbranch;
+       case BPF_S_JMP_JGE_K: /* ip += (A >= K) ? jt : jf */
+               mask = 0xa00000; /* jhe */
+               goto kbranch;
+       case BPF_S_JMP_JEQ_K: /* ip += (A == K) ? jt : jf */
+               mask = 0x800000; /* je */
+kbranch:       /* Emit compare if the branch targets are different */
+               if (filter->jt != filter->jf) {
+                       if (K <= 16383)
+                               /* chi %r5,<K> */
+                               EMIT4_IMM(0xa75e0000, K);
+                       else
+                               /* c %r5,<d(K)>(%r13) */
+                               EMIT4_DISP(0x5950d000, EMIT_CONST(K));
+               }
+branch:                if (filter->jt == filter->jf) {
+                       if (filter->jt == 0)
+                               break;
+                       /* j <jt> */
+                       offset = addrs[i + filter->jt] + jit->start - jit->prg;
+                       EMIT4_PCREL(0xa7f40000, offset);
+                       break;
+               }
+               if (filter->jt != 0) {
+                       /* brc  <mask>,<jt> */
+                       offset = addrs[i + filter->jt] + jit->start - jit->prg;
+                       EMIT4_PCREL(0xa7040000 | mask, offset);
+               }
+               if (filter->jf != 0) {
+                       /* brc  <mask^15>,<jf> */
+                       offset = addrs[i + filter->jf] + jit->start - jit->prg;
+                       EMIT4_PCREL(0xa7040000 | (mask ^ 0xf00000), offset);
+               }
+               break;
+       case BPF_S_JMP_JSET_K: /* ip += (A & K) ? jt : jf */
+               mask = 0x700000; /* jnz */
+               /* Emit test if the branch targets are different */
+               if (filter->jt != filter->jf) {
+                       if (K > 65535) {
+                               /* lr %r4,%r5 */
+                               EMIT2(0x1845);
+                               /* n %r4,<d(K)>(%r13) */
+                               EMIT4_DISP(0x5440d000, EMIT_CONST(K));
+                       } else
+                               /* tmll %r5,K */
+                               EMIT4_IMM(0xa7510000, K);
+               }
+               goto branch;
+       case BPF_S_JMP_JGT_X: /* ip += (A > X) ? jt : jf */
+               mask = 0x200000; /* jh */
+               goto xbranch;
+       case BPF_S_JMP_JGE_X: /* ip += (A >= X) ? jt : jf */
+               mask = 0xa00000; /* jhe */
+               goto xbranch;
+       case BPF_S_JMP_JEQ_X: /* ip += (A == X) ? jt : jf */
+               mask = 0x800000; /* je */
+xbranch:       /* Emit compare if the branch targets are different */
+               if (filter->jt != filter->jf) {
+                       jit->seen |= SEEN_XREG;
+                       /* cr %r5,%r12 */
+                       EMIT2(0x195c);
+               }
+               goto branch;
+       case BPF_S_JMP_JSET_X: /* ip += (A & X) ? jt : jf */
+               mask = 0x700000; /* jnz */
+               /* Emit test if the branch targets are different */
+               if (filter->jt != filter->jf) {
+                       jit->seen |= SEEN_XREG;
+                       /* lr %r4,%r5 */
+                       EMIT2(0x1845);
+                       /* nr %r4,%r12 */
+                       EMIT2(0x144c);
+               }
+               goto branch;
+       case BPF_S_LD_W_ABS: /* A = *(u32 *) (skb->data+K) */
+               jit->seen |= SEEN_DATAREF | SEEN_RET0 | SEEN_LOAD_WORD;
+               offset = jit->off_load_word;
+               goto load_abs;
+       case BPF_S_LD_H_ABS: /* A = *(u16 *) (skb->data+K) */
+               jit->seen |= SEEN_DATAREF | SEEN_RET0 | SEEN_LOAD_HALF;
+               offset = jit->off_load_half;
+               goto load_abs;
+       case BPF_S_LD_B_ABS: /* A = *(u8 *) (skb->data+K) */
+               jit->seen |= SEEN_DATAREF | SEEN_RET0 | SEEN_LOAD_BYTE;
+               offset = jit->off_load_byte;
+load_abs:      if ((int) K < 0)
+                       goto out;
+call_fn:       /* lg %r1,<d(function)>(%r13) */
+               EMIT6_DISP(0xe310d000, 0x0004, offset);
+               /* l %r3,<d(K)>(%r13) */
+               EMIT4_DISP(0x5830d000, EMIT_CONST(K));
+               /* basr %r8,%r1 */
+               EMIT2(0x0d81);
+               /* jnz <ret0> */
+               EMIT4_PCREL(0xa7740000, (jit->ret0_ip - jit->prg));
+               break;
+       case BPF_S_LD_W_IND: /* A = *(u32 *) (skb->data+K+X) */
+               jit->seen |= SEEN_DATAREF | SEEN_RET0 | SEEN_LOAD_IWORD;
+               offset = jit->off_load_iword;
+               goto call_fn;
+       case BPF_S_LD_H_IND: /* A = *(u16 *) (skb->data+K+X) */
+               jit->seen |= SEEN_DATAREF | SEEN_RET0 | SEEN_LOAD_IHALF;
+               offset = jit->off_load_ihalf;
+               goto call_fn;
+       case BPF_S_LD_B_IND: /* A = *(u8 *) (skb->data+K+X) */
+               jit->seen |= SEEN_DATAREF | SEEN_RET0 | SEEN_LOAD_IBYTE;
+               offset = jit->off_load_ibyte;
+               goto call_fn;
+       case BPF_S_LDX_B_MSH:
+               /* X = (*(u8 *)(skb->data+K) & 0xf) << 2 */
+               jit->seen |= SEEN_RET0;
+               if ((int) K < 0) {
+                       /* j <ret0> */
+                       EMIT4_PCREL(0xa7f40000, (jit->ret0_ip - jit->prg));
+                       break;
+               }
+               jit->seen |= SEEN_DATAREF | SEEN_LOAD_BMSH;
+               offset = jit->off_load_bmsh;
+               goto call_fn;
+       case BPF_S_LD_W_LEN: /* A = skb->len; */
+               BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, len) != 4);
+               /* l %r5,<d(len)>(%r2) */
+               EMIT4_DISP(0x58502000, offsetof(struct sk_buff, len));
+               break;
+       case BPF_S_LDX_W_LEN: /* X = skb->len; */
+               jit->seen |= SEEN_XREG;
+               /* l %r12,<d(len)>(%r2) */
+               EMIT4_DISP(0x58c02000, offsetof(struct sk_buff, len));
+               break;
+       case BPF_S_LD_IMM: /* A = K */
+               if (K <= 16383)
+                       /* lhi %r5,K */
+                       EMIT4_IMM(0xa7580000, K);
+               else
+                       /* l %r5,<d(K)>(%r13) */
+                       EMIT4_DISP(0x5850d000, EMIT_CONST(K));
+               break;
+       case BPF_S_LDX_IMM: /* X = K */
+               jit->seen |= SEEN_XREG;
+               if (K <= 16383)
+                       /* lhi %r12,<K> */
+                       EMIT4_IMM(0xa7c80000, K);
+               else
+                       /* l %r12,<d(K)>(%r13) */
+                       EMIT4_DISP(0x58c0d000, EMIT_CONST(K));
+               break;
+       case BPF_S_LD_MEM: /* A = mem[K] */
+               jit->seen |= SEEN_MEM;
+               /* l %r5,<K>(%r15) */
+               EMIT4_DISP(0x5850f000,
+                          (jit->seen & SEEN_DATAREF) ? 160 + K*4 : K*4);
+               break;
+       case BPF_S_LDX_MEM: /* X = mem[K] */
+               jit->seen |= SEEN_XREG | SEEN_MEM;
+               /* l %r12,<K>(%r15) */
+               EMIT4_DISP(0x58c0f000,
+                          (jit->seen & SEEN_DATAREF) ? 160 + K*4 : K*4);
+               break;
+       case BPF_S_MISC_TAX: /* X = A */
+               jit->seen |= SEEN_XREG;
+               /* lr %r12,%r5 */
+               EMIT2(0x18c5);
+               break;
+       case BPF_S_MISC_TXA: /* A = X */
+               jit->seen |= SEEN_XREG;
+               /* lr %r5,%r12 */
+               EMIT2(0x185c);
+               break;
+       case BPF_S_RET_K:
+               if (K == 0) {
+                       jit->seen |= SEEN_RET0;
+                       if (last)
+                               break;
+                       /* j <ret0> */
+                       EMIT4_PCREL(0xa7f40000, jit->ret0_ip - jit->prg);
+               } else {
+                       if (K <= 16383)
+                               /* lghi %r2,K */
+                               EMIT4_IMM(0xa7290000, K);
+                       else
+                               /* llgf %r2,<K>(%r13) */
+                               EMIT6_DISP(0xe320d000, 0x0016, EMIT_CONST(K));
+                       /* j <exit> */
+                       if (last && !(jit->seen & SEEN_RET0))
+                               break;
+                       EMIT4_PCREL(0xa7f40000, jit->exit_ip - jit->prg);
+               }
+               break;
+       case BPF_S_RET_A:
+               /* llgfr %r2,%r5 */
+               EMIT4(0xb9160025);
+               /* j <exit> */
+               EMIT4_PCREL(0xa7f40000, jit->exit_ip - jit->prg);
+               break;
+       case BPF_S_ST: /* mem[K] = A */
+               jit->seen |= SEEN_MEM;
+               /* st %r5,<K>(%r15) */
+               EMIT4_DISP(0x5050f000,
+                          (jit->seen & SEEN_DATAREF) ? 160 + K*4 : K*4);
+               break;
+       case BPF_S_STX: /* mem[K] = X : mov %ebx,off8(%rbp) */
+               jit->seen |= SEEN_XREG | SEEN_MEM;
+               /* st %r12,<K>(%r15) */
+               EMIT4_DISP(0x50c0f000,
+                          (jit->seen & SEEN_DATAREF) ? 160 + K*4 : K*4);
+               break;
+       case BPF_S_ANC_PROTOCOL: /* A = ntohs(skb->protocol); */
+               BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, protocol) != 2);
+               /* lhi %r5,0 */
+               EMIT4(0xa7580000);
+               /* icm  %r5,3,<d(protocol)>(%r2) */
+               EMIT4_DISP(0xbf532000, offsetof(struct sk_buff, protocol));
+               break;
+       case BPF_S_ANC_IFINDEX: /* if (!skb->dev) return 0;
+                                * A = skb->dev->ifindex */
+               BUILD_BUG_ON(FIELD_SIZEOF(struct net_device, ifindex) != 4);
+               jit->seen |= SEEN_RET0;
+               /* lg %r1,<d(dev)>(%r2) */
+               EMIT6_DISP(0xe3102000, 0x0004, offsetof(struct sk_buff, dev));
+               /* ltgr %r1,%r1 */
+               EMIT4(0xb9020011);
+               /* jz <ret0> */
+               EMIT4_PCREL(0xa7840000, jit->ret0_ip - jit->prg);
+               /* l %r5,<d(ifindex)>(%r1) */
+               EMIT4_DISP(0x58501000, offsetof(struct net_device, ifindex));
+               break;
+       case BPF_S_ANC_MARK: /* A = skb->mark */
+               BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, mark) != 4);
+               /* l %r5,<d(mark)>(%r2) */
+               EMIT4_DISP(0x58502000, offsetof(struct sk_buff, mark));
+               break;
+       case BPF_S_ANC_QUEUE: /* A = skb->queue_mapping */
+               BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, queue_mapping) != 2);
+               /* lhi %r5,0 */
+               EMIT4(0xa7580000);
+               /* icm  %r5,3,<d(queue_mapping)>(%r2) */
+               EMIT4_DISP(0xbf532000, offsetof(struct sk_buff, queue_mapping));
+               break;
+       case BPF_S_ANC_HATYPE:  /* if (!skb->dev) return 0;
+                                * A = skb->dev->type */
+               BUILD_BUG_ON(FIELD_SIZEOF(struct net_device, type) != 2);
+               jit->seen |= SEEN_RET0;
+               /* lg %r1,<d(dev)>(%r2) */
+               EMIT6_DISP(0xe3102000, 0x0004, offsetof(struct sk_buff, dev));
+               /* ltgr %r1,%r1 */
+               EMIT4(0xb9020011);
+               /* jz <ret0> */
+               EMIT4_PCREL(0xa7840000, jit->ret0_ip - jit->prg);
+               /* lhi %r5,0 */
+               EMIT4(0xa7580000);
+               /* icm  %r5,3,<d(type)>(%r1) */
+               EMIT4_DISP(0xbf531000, offsetof(struct net_device, type));
+               break;
+       case BPF_S_ANC_RXHASH: /* A = skb->rxhash */
+               BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, rxhash) != 4);
+               /* l %r5,<d(rxhash)>(%r2) */
+               EMIT4_DISP(0x58502000, offsetof(struct sk_buff, rxhash));
+               break;
+       case BPF_S_ANC_CPU: /* A = smp_processor_id() */
+#ifdef CONFIG_SMP
+               /* l %r5,<d(cpu_nr)> */
+               EMIT4_DISP(0x58500000, offsetof(struct _lowcore, cpu_nr));
+#else
+               /* lhi %r5,0 */
+               EMIT4(0xa7580000);
+#endif
+               break;
+       default: /* too complex, give up */
+               goto out;
+       }
+       addrs[i] = jit->prg - jit->start;
+       return 0;
+out:
+       return -1;
+}
+
+void bpf_jit_compile(struct sk_filter *fp)
+{
+       unsigned long size, prg_len, lit_len;
+       struct bpf_jit jit, cjit;
+       unsigned int *addrs;
+       int pass, i;
+
+       if (!bpf_jit_enable)
+               return;
+       addrs = kmalloc(fp->len * sizeof(*addrs), GFP_KERNEL);
+       if (addrs == NULL)
+               return;
+       memset(addrs, 0, fp->len * sizeof(*addrs));
+       memset(&jit, 0, sizeof(cjit));
+       memset(&cjit, 0, sizeof(cjit));
+
+       for (pass = 0; pass < 10; pass++) {
+               jit.prg = jit.start;
+               jit.lit = jit.mid;
+
+               bpf_jit_prologue(&jit);
+               bpf_jit_noleaks(&jit, fp->insns);
+               for (i = 0; i < fp->len; i++) {
+                       if (bpf_jit_insn(&jit, fp->insns + i, addrs, i,
+                                        i == fp->len - 1))
+                               goto out;
+               }
+               bpf_jit_epilogue(&jit);
+               if (jit.start) {
+                       WARN_ON(jit.prg > cjit.prg || jit.lit > cjit.lit);
+                       if (memcmp(&jit, &cjit, sizeof(jit)) == 0)
+                               break;
+               } else if (jit.prg == cjit.prg && jit.lit == cjit.lit) {
+                       prg_len = jit.prg - jit.start;
+                       lit_len = jit.lit - jit.mid;
+                       size = max_t(unsigned long, prg_len + lit_len,
+                                    sizeof(struct work_struct));
+                       if (size >= BPF_SIZE_MAX)
+                               goto out;
+                       jit.start = module_alloc(size);
+                       if (!jit.start)
+                               goto out;
+                       jit.prg = jit.mid = jit.start + prg_len;
+                       jit.lit = jit.end = jit.start + prg_len + lit_len;
+                       jit.base_ip += (unsigned long) jit.start;
+                       jit.exit_ip += (unsigned long) jit.start;
+                       jit.ret0_ip += (unsigned long) jit.start;
+               }
+               cjit = jit;
+       }
+       if (bpf_jit_enable > 1) {
+               pr_err("flen=%d proglen=%lu pass=%d image=%p\n",
+                      fp->len, jit.end - jit.start, pass, jit.start);
+               if (jit.start) {
+                       printk(KERN_ERR "JIT code:\n");
+                       print_fn_code(jit.start, jit.mid - jit.start);
+                       print_hex_dump(KERN_ERR, "JIT literals:\n",
+                                      DUMP_PREFIX_ADDRESS, 16, 1,
+                                      jit.mid, jit.end - jit.mid, false);
+               }
+       }
+       if (jit.start)
+               fp->bpf_func = (void *) jit.start;
+out:
+       kfree(addrs);
+}
+
+static void jit_free_defer(struct work_struct *arg)
+{
+       module_free(NULL, arg);
+}
+
+/* run from softirq, we must use a work_struct to call
+ * module_free() from process context
+ */
+void bpf_jit_free(struct sk_filter *fp)
+{
+       struct work_struct *work;
+
+       if (fp->bpf_func == sk_run_filter)
+               return;
+       work = (struct work_struct *)fp->bpf_func;
+       INIT_WORK(work, jit_free_defer);
+       schedule_work(work);
+}
index ba0f412920befb05cdd0a26c6a707e2b91289954..e2c8db4533dc3be6cf1d88ba6a7c3863460955c7 100644 (file)
@@ -10,6 +10,8 @@ config SCORE
        select ARCH_DISCARD_MEMBLOCK
        select GENERIC_CPU_DEVICES
        select GENERIC_CLOCKEVENTS
+       select HAVE_MOD_ARCH_SPECIFIC
+       select MODULES_USE_ELF_REL
 
 choice
        prompt "System type"
index f0b5dc0bd023d738ee80f7fb936f1a5e681c330d..abf395bbfabadc23524e36cb169511a088563007 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/list.h>
 #include <asm/uaccess.h>
+#include <asm-generic/module.h>
 
 struct mod_arch_specific {
        /* Data Bus Error exception tables */
@@ -13,11 +14,6 @@ struct mod_arch_specific {
 
 typedef uint8_t Elf64_Byte;            /* Type for a 8-bit quantity. */
 
-#define Elf_Shdr       Elf32_Shdr
-#define Elf_Sym                Elf32_Sym
-#define Elf_Ehdr       Elf32_Ehdr
-#define Elf_Addr       Elf32_Addr
-
 /* Given an address, look for it in the exception tables. */
 #ifdef CONFIG_MODULES
 const struct exception_table_entry *search_module_dbetables(unsigned long addr);
index 469e3b64e2f26aa760a307d68827eacc0768df21..1378d99baa3d5744464ab4aa1f50591769ddc9a4 100644 (file)
@@ -125,16 +125,6 @@ int apply_relocate(Elf_Shdr *sechdrs, const char *strtab,
        return 0;
 }
 
-int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
-               unsigned int symindex, unsigned int relsec,
-               struct module *me)
-{
-       /* Non-standard return value... most other arch's return -ENOEXEC
-        * for an unsupported relocation variant
-        */
-       return 0;
-}
-
 /* Given an address, look for it in the module exception tables. */
 const struct exception_table_entry *search_module_dbetables(unsigned long addr)
 {
index 36f5141e80417ac6172ce6965602e4d15a67bdfb..656329a9a59b2bc40adf2689b347977a23114d76 100644 (file)
@@ -35,6 +35,8 @@ config SUPERH
        select GENERIC_CMOS_UPDATE if SH_SH03 || SH_DREAMCAST
        select GENERIC_STRNCPY_FROM_USER
        select GENERIC_STRNLEN_USER
+       select HAVE_MOD_ARCH_SPECIFIC if DWARF_UNWINDER
+       select MODULES_USE_ELF_RELA
        help
          The SuperH is a RISC processor targeted for use in embedded systems
          and consumer electronics; it was also used in the Sega Dreamcast
index 4c171f13b0e8792b5f88a564c1fef52e15218c22..b2256562314298e0e63918b7f60323691e08d5b3 100644 (file)
@@ -335,7 +335,7 @@ static int dmae_irq_init(void)
 
        for (n = 0; n < NR_DMAE; n++) {
                int i = request_irq(get_dma_error_irq(n), dma_err,
-                                   IRQF_SHARED, dmae_name[n], NULL);
+                                   IRQF_SHARED, dmae_name[n], (void *)dmae_name[n]);
                if (unlikely(i < 0)) {
                        printk(KERN_ERR "%s request_irq fail\n", dmae_name[n]);
                        return i;
index b7927de86f9fcfb9d220abfd03872d06307cf149..81300d8b5448c35e85ed1f895e054a1b73492550 100644 (file)
@@ -1,21 +1,13 @@
 #ifndef _ASM_SH_MODULE_H
 #define _ASM_SH_MODULE_H
 
-struct mod_arch_specific {
+#include <asm-generic/module.h>
+
 #ifdef CONFIG_DWARF_UNWINDER
+struct mod_arch_specific {
        struct list_head fde_list;
        struct list_head cie_list;
-#endif
 };
-
-#ifdef CONFIG_64BIT
-#define Elf_Shdr Elf64_Shdr
-#define Elf_Sym Elf64_Sym
-#define Elf_Ehdr Elf64_Ehdr
-#else
-#define Elf_Shdr Elf32_Shdr
-#define Elf_Sym Elf32_Sym
-#define Elf_Ehdr Elf32_Ehdr
 #endif
 
 #ifdef CONFIG_CPU_LITTLE_ENDIAN
index 4a5350037c8f59217a06e6e6ea1c429594d51073..1b6199740e98ab7e554f1676d615983f451e56a7 100644 (file)
@@ -6,7 +6,6 @@
 extern long __nosave_begin, __nosave_end;
 extern long __machvec_start, __machvec_end;
 extern char __uncached_start, __uncached_end;
-extern char _ebss[];
 extern char __start_eh_frame[], __stop_eh_frame[];
 
 #endif /* __ASM_SH_SECTIONS_H */
index 48d14498e7740aaf76fcdafa0bae17a3ec7b6ec6..2a0ca8780f0d8c343fb87e434cf6acec73acaddb 100644 (file)
@@ -183,18 +183,30 @@ enum {
        GPIO_FN_DV_DATA1, GPIO_FN_DV_DATA0,
        GPIO_FN_LCD_CLK, GPIO_FN_LCD_EXTCLK,
        GPIO_FN_LCD_VSYNC, GPIO_FN_LCD_HSYNC, GPIO_FN_LCD_DE,
-       GPIO_FN_LCD_DATA23, GPIO_FN_LCD_DATA22,
-       GPIO_FN_LCD_DATA21, GPIO_FN_LCD_DATA20,
-       GPIO_FN_LCD_DATA19, GPIO_FN_LCD_DATA18,
-       GPIO_FN_LCD_DATA17, GPIO_FN_LCD_DATA16,
-       GPIO_FN_LCD_DATA15, GPIO_FN_LCD_DATA14,
-       GPIO_FN_LCD_DATA13, GPIO_FN_LCD_DATA12,
-       GPIO_FN_LCD_DATA11, GPIO_FN_LCD_DATA10,
-       GPIO_FN_LCD_DATA9, GPIO_FN_LCD_DATA8,
-       GPIO_FN_LCD_DATA7, GPIO_FN_LCD_DATA6,
-       GPIO_FN_LCD_DATA5, GPIO_FN_LCD_DATA4,
-       GPIO_FN_LCD_DATA3, GPIO_FN_LCD_DATA2,
-       GPIO_FN_LCD_DATA1, GPIO_FN_LCD_DATA0,
+       GPIO_FN_LCD_DATA23_PG23, GPIO_FN_LCD_DATA22_PG22,
+       GPIO_FN_LCD_DATA21_PG21, GPIO_FN_LCD_DATA20_PG20,
+       GPIO_FN_LCD_DATA19_PG19, GPIO_FN_LCD_DATA18_PG18,
+       GPIO_FN_LCD_DATA17_PG17, GPIO_FN_LCD_DATA16_PG16,
+       GPIO_FN_LCD_DATA15_PG15, GPIO_FN_LCD_DATA14_PG14,
+       GPIO_FN_LCD_DATA13_PG13, GPIO_FN_LCD_DATA12_PG12,
+       GPIO_FN_LCD_DATA11_PG11, GPIO_FN_LCD_DATA10_PG10,
+       GPIO_FN_LCD_DATA9_PG9, GPIO_FN_LCD_DATA8_PG8,
+       GPIO_FN_LCD_DATA7_PG7, GPIO_FN_LCD_DATA6_PG6,
+       GPIO_FN_LCD_DATA5_PG5, GPIO_FN_LCD_DATA4_PG4,
+       GPIO_FN_LCD_DATA3_PG3, GPIO_FN_LCD_DATA2_PG2,
+       GPIO_FN_LCD_DATA1_PG1, GPIO_FN_LCD_DATA0_PG0,
+       GPIO_FN_LCD_DATA23_PJ23, GPIO_FN_LCD_DATA22_PJ22,
+       GPIO_FN_LCD_DATA21_PJ21, GPIO_FN_LCD_DATA20_PJ20,
+       GPIO_FN_LCD_DATA19_PJ19, GPIO_FN_LCD_DATA18_PJ18,
+       GPIO_FN_LCD_DATA17_PJ17, GPIO_FN_LCD_DATA16_PJ16,
+       GPIO_FN_LCD_DATA15_PJ15, GPIO_FN_LCD_DATA14_PJ14,
+       GPIO_FN_LCD_DATA13_PJ13, GPIO_FN_LCD_DATA12_PJ12,
+       GPIO_FN_LCD_DATA11_PJ11, GPIO_FN_LCD_DATA10_PJ10,
+       GPIO_FN_LCD_DATA9_PJ9, GPIO_FN_LCD_DATA8_PJ8,
+       GPIO_FN_LCD_DATA7_PJ7, GPIO_FN_LCD_DATA6_PJ6,
+       GPIO_FN_LCD_DATA5_PJ5, GPIO_FN_LCD_DATA4_PJ4,
+       GPIO_FN_LCD_DATA3_PJ3, GPIO_FN_LCD_DATA2_PJ2,
+       GPIO_FN_LCD_DATA1_PJ1, GPIO_FN_LCD_DATA0_PJ0,
        GPIO_FN_LCD_M_DISP,
 };
 
index f25127c46ecaff2df0e7bb7b38eca237903c7838..039e4587dd9b8cf2959e2d19159098f02136f7fd 100644 (file)
@@ -758,12 +758,22 @@ enum {
        DV_DATA3_MARK, DV_DATA2_MARK, DV_DATA1_MARK, DV_DATA0_MARK,
        LCD_CLK_MARK, LCD_EXTCLK_MARK,
        LCD_VSYNC_MARK, LCD_HSYNC_MARK, LCD_DE_MARK,
-       LCD_DATA23_MARK, LCD_DATA22_MARK, LCD_DATA21_MARK, LCD_DATA20_MARK,
-       LCD_DATA19_MARK, LCD_DATA18_MARK, LCD_DATA17_MARK, LCD_DATA16_MARK,
-       LCD_DATA15_MARK, LCD_DATA14_MARK, LCD_DATA13_MARK, LCD_DATA12_MARK,
-       LCD_DATA11_MARK, LCD_DATA10_MARK, LCD_DATA9_MARK, LCD_DATA8_MARK,
-       LCD_DATA7_MARK, LCD_DATA6_MARK, LCD_DATA5_MARK, LCD_DATA4_MARK,
-       LCD_DATA3_MARK, LCD_DATA2_MARK, LCD_DATA1_MARK, LCD_DATA0_MARK,
+       LCD_DATA23_PG23_MARK, LCD_DATA22_PG22_MARK, LCD_DATA21_PG21_MARK,
+       LCD_DATA20_PG20_MARK, LCD_DATA19_PG19_MARK, LCD_DATA18_PG18_MARK,
+       LCD_DATA17_PG17_MARK, LCD_DATA16_PG16_MARK, LCD_DATA15_PG15_MARK,
+       LCD_DATA14_PG14_MARK, LCD_DATA13_PG13_MARK, LCD_DATA12_PG12_MARK,
+       LCD_DATA11_PG11_MARK, LCD_DATA10_PG10_MARK, LCD_DATA9_PG9_MARK,
+       LCD_DATA8_PG8_MARK, LCD_DATA7_PG7_MARK, LCD_DATA6_PG6_MARK,
+       LCD_DATA5_PG5_MARK, LCD_DATA4_PG4_MARK, LCD_DATA3_PG3_MARK,
+       LCD_DATA2_PG2_MARK, LCD_DATA1_PG1_MARK, LCD_DATA0_PG0_MARK,
+       LCD_DATA23_PJ23_MARK, LCD_DATA22_PJ22_MARK, LCD_DATA21_PJ21_MARK,
+       LCD_DATA20_PJ20_MARK, LCD_DATA19_PJ19_MARK, LCD_DATA18_PJ18_MARK,
+       LCD_DATA17_PJ17_MARK, LCD_DATA16_PJ16_MARK, LCD_DATA15_PJ15_MARK,
+       LCD_DATA14_PJ14_MARK, LCD_DATA13_PJ13_MARK, LCD_DATA12_PJ12_MARK,
+       LCD_DATA11_PJ11_MARK, LCD_DATA10_PJ10_MARK, LCD_DATA9_PJ9_MARK,
+       LCD_DATA8_PJ8_MARK, LCD_DATA7_PJ7_MARK, LCD_DATA6_PJ6_MARK,
+       LCD_DATA5_PJ5_MARK, LCD_DATA4_PJ4_MARK, LCD_DATA3_PJ3_MARK,
+       LCD_DATA2_PJ2_MARK, LCD_DATA1_PJ1_MARK, LCD_DATA0_PJ0_MARK,
        LCD_TCON6_MARK, LCD_TCON5_MARK, LCD_TCON4_MARK,
        LCD_TCON3_MARK, LCD_TCON2_MARK, LCD_TCON1_MARK, LCD_TCON0_MARK,
        LCD_M_DISP_MARK,
@@ -1036,6 +1046,7 @@ static pinmux_enum_t pinmux_data[] = {
 
        PINMUX_DATA(PF1_DATA, PF1MD_000),
        PINMUX_DATA(BACK_MARK, PF1MD_001),
+       PINMUX_DATA(SSL10_MARK, PF1MD_011),
        PINMUX_DATA(TIOC4B_MARK, PF1MD_100),
        PINMUX_DATA(DACK0_MARK, PF1MD_101),
 
@@ -1049,47 +1060,50 @@ static pinmux_enum_t pinmux_data[] = {
        PINMUX_DATA(PG27_DATA, PG27MD_00),
        PINMUX_DATA(LCD_TCON2_MARK, PG27MD_10),
        PINMUX_DATA(LCD_EXTCLK_MARK, PG27MD_11),
+       PINMUX_DATA(LCD_DE_MARK, PG27MD_11),
 
        PINMUX_DATA(PG26_DATA, PG26MD_00),
        PINMUX_DATA(LCD_TCON1_MARK, PG26MD_10),
+       PINMUX_DATA(LCD_HSYNC_MARK, PG26MD_10),
 
        PINMUX_DATA(PG25_DATA, PG25MD_00),
        PINMUX_DATA(LCD_TCON0_MARK, PG25MD_10),
+       PINMUX_DATA(LCD_VSYNC_MARK, PG25MD_10),
 
        PINMUX_DATA(PG24_DATA, PG24MD_00),
        PINMUX_DATA(LCD_CLK_MARK, PG24MD_10),
 
        PINMUX_DATA(PG23_DATA, PG23MD_000),
-       PINMUX_DATA(LCD_DATA23_MARK, PG23MD_010),
+       PINMUX_DATA(LCD_DATA23_PG23_MARK, PG23MD_010),
        PINMUX_DATA(LCD_TCON6_MARK, PG23MD_011),
        PINMUX_DATA(TXD5_MARK, PG23MD_100),
 
        PINMUX_DATA(PG22_DATA, PG22MD_000),
-       PINMUX_DATA(LCD_DATA22_MARK, PG22MD_010),
+       PINMUX_DATA(LCD_DATA22_PG22_MARK, PG22MD_010),
        PINMUX_DATA(LCD_TCON5_MARK, PG22MD_011),
        PINMUX_DATA(RXD5_MARK, PG22MD_100),
 
        PINMUX_DATA(PG21_DATA, PG21MD_000),
        PINMUX_DATA(DV_DATA7_MARK, PG21MD_001),
-       PINMUX_DATA(LCD_DATA21_MARK, PG21MD_010),
+       PINMUX_DATA(LCD_DATA21_PG21_MARK, PG21MD_010),
        PINMUX_DATA(LCD_TCON4_MARK, PG21MD_011),
        PINMUX_DATA(TXD4_MARK, PG21MD_100),
 
        PINMUX_DATA(PG20_DATA, PG20MD_000),
        PINMUX_DATA(DV_DATA6_MARK, PG20MD_001),
-       PINMUX_DATA(LCD_DATA20_MARK, PG21MD_010),
+       PINMUX_DATA(LCD_DATA20_PG20_MARK, PG21MD_010),
        PINMUX_DATA(LCD_TCON3_MARK, PG20MD_011),
        PINMUX_DATA(RXD4_MARK, PG20MD_100),
 
        PINMUX_DATA(PG19_DATA, PG19MD_000),
        PINMUX_DATA(DV_DATA5_MARK, PG19MD_001),
-       PINMUX_DATA(LCD_DATA19_MARK, PG19MD_010),
+       PINMUX_DATA(LCD_DATA19_PG19_MARK, PG19MD_010),
        PINMUX_DATA(SPDIF_OUT_MARK, PG19MD_011),
        PINMUX_DATA(SCK5_MARK, PG19MD_100),
 
        PINMUX_DATA(PG18_DATA, PG18MD_000),
        PINMUX_DATA(DV_DATA4_MARK, PG18MD_001),
-       PINMUX_DATA(LCD_DATA18_MARK, PG18MD_010),
+       PINMUX_DATA(LCD_DATA18_PG18_MARK, PG18MD_010),
        PINMUX_DATA(SPDIF_IN_MARK, PG18MD_011),
        PINMUX_DATA(SCK4_MARK, PG18MD_100),
 
@@ -1097,103 +1111,103 @@ static pinmux_enum_t pinmux_data[] = {
 // we're going with 2 bits
        PINMUX_DATA(PG17_DATA, PG17MD_00),
        PINMUX_DATA(WE3ICIOWRAHDQMUU_MARK, PG17MD_01),
-       PINMUX_DATA(LCD_DATA17_MARK, PG17MD_10),
+       PINMUX_DATA(LCD_DATA17_PG17_MARK, PG17MD_10),
 
 // TODO hardware manual has PG16 3 bits wide in reg picture and 2 bits in description
 // we're going with 2 bits
        PINMUX_DATA(PG16_DATA, PG16MD_00),
        PINMUX_DATA(WE2ICIORDDQMUL_MARK, PG16MD_01),
-       PINMUX_DATA(LCD_DATA16_MARK, PG16MD_10),
+       PINMUX_DATA(LCD_DATA16_PG16_MARK, PG16MD_10),
 
        PINMUX_DATA(PG15_DATA, PG15MD_00),
        PINMUX_DATA(D31_MARK, PG15MD_01),
-       PINMUX_DATA(LCD_DATA15_MARK, PG15MD_10),
+       PINMUX_DATA(LCD_DATA15_PG15_MARK, PG15MD_10),
        PINMUX_DATA(PINT7_PG_MARK, PG15MD_11),
 
        PINMUX_DATA(PG14_DATA, PG14MD_00),
        PINMUX_DATA(D30_MARK, PG14MD_01),
-       PINMUX_DATA(LCD_DATA14_MARK, PG14MD_10),
+       PINMUX_DATA(LCD_DATA14_PG14_MARK, PG14MD_10),
        PINMUX_DATA(PINT6_PG_MARK, PG14MD_11),
 
        PINMUX_DATA(PG13_DATA, PG13MD_00),
        PINMUX_DATA(D29_MARK, PG13MD_01),
-       PINMUX_DATA(LCD_DATA13_MARK, PG13MD_10),
+       PINMUX_DATA(LCD_DATA13_PG13_MARK, PG13MD_10),
        PINMUX_DATA(PINT5_PG_MARK, PG13MD_11),
 
        PINMUX_DATA(PG12_DATA, PG12MD_00),
        PINMUX_DATA(D28_MARK, PG12MD_01),
-       PINMUX_DATA(LCD_DATA12_MARK, PG12MD_10),
+       PINMUX_DATA(LCD_DATA12_PG12_MARK, PG12MD_10),
        PINMUX_DATA(PINT4_PG_MARK, PG12MD_11),
 
        PINMUX_DATA(PG11_DATA, PG11MD_000),
        PINMUX_DATA(D27_MARK, PG11MD_001),
-       PINMUX_DATA(LCD_DATA11_MARK, PG11MD_010),
+       PINMUX_DATA(LCD_DATA11_PG11_MARK, PG11MD_010),
        PINMUX_DATA(PINT3_PG_MARK, PG11MD_011),
        PINMUX_DATA(TIOC3D_MARK, PG11MD_100),
 
        PINMUX_DATA(PG10_DATA, PG10MD_000),
        PINMUX_DATA(D26_MARK, PG10MD_001),
-       PINMUX_DATA(LCD_DATA10_MARK, PG10MD_010),
+       PINMUX_DATA(LCD_DATA10_PG10_MARK, PG10MD_010),
        PINMUX_DATA(PINT2_PG_MARK, PG10MD_011),
        PINMUX_DATA(TIOC3C_MARK, PG10MD_100),
 
        PINMUX_DATA(PG9_DATA, PG9MD_000),
        PINMUX_DATA(D25_MARK, PG9MD_001),
-       PINMUX_DATA(LCD_DATA9_MARK, PG9MD_010),
+       PINMUX_DATA(LCD_DATA9_PG9_MARK, PG9MD_010),
        PINMUX_DATA(PINT1_PG_MARK, PG9MD_011),
        PINMUX_DATA(TIOC3B_MARK, PG9MD_100),
 
        PINMUX_DATA(PG8_DATA, PG8MD_000),
        PINMUX_DATA(D24_MARK, PG8MD_001),
-       PINMUX_DATA(LCD_DATA8_MARK, PG8MD_010),
+       PINMUX_DATA(LCD_DATA8_PG8_MARK, PG8MD_010),
        PINMUX_DATA(PINT0_PG_MARK, PG8MD_011),
        PINMUX_DATA(TIOC3A_MARK, PG8MD_100),
 
        PINMUX_DATA(PG7_DATA, PG7MD_000),
        PINMUX_DATA(D23_MARK, PG7MD_001),
-       PINMUX_DATA(LCD_DATA7_MARK, PG7MD_010),
+       PINMUX_DATA(LCD_DATA7_PG7_MARK, PG7MD_010),
        PINMUX_DATA(IRQ7_PG_MARK, PG7MD_011),
        PINMUX_DATA(TIOC2B_MARK, PG7MD_100),
 
        PINMUX_DATA(PG6_DATA, PG6MD_000),
        PINMUX_DATA(D22_MARK, PG6MD_001),
-       PINMUX_DATA(LCD_DATA6_MARK, PG6MD_010),
+       PINMUX_DATA(LCD_DATA6_PG6_MARK, PG6MD_010),
        PINMUX_DATA(IRQ6_PG_MARK, PG6MD_011),
        PINMUX_DATA(TIOC2A_MARK, PG6MD_100),
 
        PINMUX_DATA(PG5_DATA, PG5MD_000),
        PINMUX_DATA(D21_MARK, PG5MD_001),
-       PINMUX_DATA(LCD_DATA5_MARK, PG5MD_010),
+       PINMUX_DATA(LCD_DATA5_PG5_MARK, PG5MD_010),
        PINMUX_DATA(IRQ5_PG_MARK, PG5MD_011),
        PINMUX_DATA(TIOC1B_MARK, PG5MD_100),
 
        PINMUX_DATA(PG4_DATA, PG4MD_000),
        PINMUX_DATA(D20_MARK, PG4MD_001),
-       PINMUX_DATA(LCD_DATA4_MARK, PG4MD_010),
+       PINMUX_DATA(LCD_DATA4_PG4_MARK, PG4MD_010),
        PINMUX_DATA(IRQ4_PG_MARK, PG4MD_011),
        PINMUX_DATA(TIOC1A_MARK, PG4MD_100),
 
        PINMUX_DATA(PG3_DATA, PG3MD_000),
        PINMUX_DATA(D19_MARK, PG3MD_001),
-       PINMUX_DATA(LCD_DATA3_MARK, PG3MD_010),
+       PINMUX_DATA(LCD_DATA3_PG3_MARK, PG3MD_010),
        PINMUX_DATA(IRQ3_PG_MARK, PG3MD_011),
        PINMUX_DATA(TIOC0D_MARK, PG3MD_100),
 
        PINMUX_DATA(PG2_DATA, PG2MD_000),
        PINMUX_DATA(D18_MARK, PG2MD_001),
-       PINMUX_DATA(LCD_DATA2_MARK, PG2MD_010),
+       PINMUX_DATA(LCD_DATA2_PG2_MARK, PG2MD_010),
        PINMUX_DATA(IRQ2_PG_MARK, PG2MD_011),
        PINMUX_DATA(TIOC0C_MARK, PG2MD_100),
 
        PINMUX_DATA(PG1_DATA, PG1MD_000),
        PINMUX_DATA(D17_MARK, PG1MD_001),
-       PINMUX_DATA(LCD_DATA1_MARK, PG1MD_010),
+       PINMUX_DATA(LCD_DATA1_PG1_MARK, PG1MD_010),
        PINMUX_DATA(IRQ1_PG_MARK, PG1MD_011),
        PINMUX_DATA(TIOC0B_MARK, PG1MD_100),
 
        PINMUX_DATA(PG0_DATA, PG0MD_000),
        PINMUX_DATA(D16_MARK, PG0MD_001),
-       PINMUX_DATA(LCD_DATA0_MARK, PG0MD_010),
+       PINMUX_DATA(LCD_DATA0_PG0_MARK, PG0MD_010),
        PINMUX_DATA(IRQ0_PG_MARK, PG0MD_011),
        PINMUX_DATA(TIOC0A_MARK, PG0MD_100),
 
@@ -1275,14 +1289,14 @@ static pinmux_enum_t pinmux_data[] = {
 
        PINMUX_DATA(PJ23_DATA, PJ23MD_000),
        PINMUX_DATA(DV_DATA23_MARK, PJ23MD_001),
-       PINMUX_DATA(LCD_DATA23_MARK, PJ23MD_010),
+       PINMUX_DATA(LCD_DATA23_PJ23_MARK, PJ23MD_010),
        PINMUX_DATA(LCD_TCON6_MARK, PJ23MD_011),
        PINMUX_DATA(IRQ3_PJ_MARK, PJ23MD_100),
        PINMUX_DATA(CTX1_MARK, PJ23MD_101),
 
        PINMUX_DATA(PJ22_DATA, PJ22MD_000),
        PINMUX_DATA(DV_DATA22_MARK, PJ22MD_001),
-       PINMUX_DATA(LCD_DATA22_MARK, PJ22MD_010),
+       PINMUX_DATA(LCD_DATA22_PJ22_MARK, PJ22MD_010),
        PINMUX_DATA(LCD_TCON5_MARK, PJ22MD_011),
        PINMUX_DATA(IRQ2_PJ_MARK, PJ22MD_100),
        PINMUX_DATA(CRX1_MARK, PJ22MD_101),
@@ -1290,14 +1304,14 @@ static pinmux_enum_t pinmux_data[] = {
 
        PINMUX_DATA(PJ21_DATA, PJ21MD_000),
        PINMUX_DATA(DV_DATA21_MARK, PJ21MD_001),
-       PINMUX_DATA(LCD_DATA21_MARK, PJ21MD_010),
+       PINMUX_DATA(LCD_DATA21_PJ21_MARK, PJ21MD_010),
        PINMUX_DATA(LCD_TCON4_MARK, PJ21MD_011),
        PINMUX_DATA(IRQ1_PJ_MARK, PJ21MD_100),
        PINMUX_DATA(CTX2_MARK, PJ21MD_101),
 
        PINMUX_DATA(PJ20_DATA, PJ20MD_000),
        PINMUX_DATA(DV_DATA20_MARK, PJ20MD_001),
-       PINMUX_DATA(LCD_DATA20_MARK, PJ20MD_010),
+       PINMUX_DATA(LCD_DATA20_PJ20_MARK, PJ20MD_010),
        PINMUX_DATA(LCD_TCON3_MARK, PJ20MD_011),
        PINMUX_DATA(IRQ0_PJ_MARK, PJ20MD_100),
        PINMUX_DATA(CRX2_MARK, PJ20MD_101),
@@ -1305,7 +1319,7 @@ static pinmux_enum_t pinmux_data[] = {
 
        PINMUX_DATA(PJ19_DATA, PJ19MD_000),
        PINMUX_DATA(DV_DATA19_MARK, PJ19MD_001),
-       PINMUX_DATA(LCD_DATA19_MARK, PJ19MD_010),
+       PINMUX_DATA(LCD_DATA19_PJ19_MARK, PJ19MD_010),
        PINMUX_DATA(MISO0_PJ19_MARK, PJ19MD_011),
        PINMUX_DATA(TIOC0D_MARK, PJ19MD_100),
        PINMUX_DATA(SIOFRXD_MARK, PJ19MD_101),
@@ -1313,126 +1327,126 @@ static pinmux_enum_t pinmux_data[] = {
 
        PINMUX_DATA(PJ18_DATA, PJ18MD_000),
        PINMUX_DATA(DV_DATA18_MARK, PJ18MD_001),
-       PINMUX_DATA(LCD_DATA18_MARK, PJ18MD_010),
+       PINMUX_DATA(LCD_DATA18_PJ18_MARK, PJ18MD_010),
        PINMUX_DATA(MOSI0_PJ18_MARK, PJ18MD_011),
        PINMUX_DATA(TIOC0C_MARK, PJ18MD_100),
        PINMUX_DATA(SIOFTXD_MARK, PJ18MD_101),
 
        PINMUX_DATA(PJ17_DATA, PJ17MD_000),
        PINMUX_DATA(DV_DATA17_MARK, PJ17MD_001),
-       PINMUX_DATA(LCD_DATA17_MARK, PJ17MD_010),
+       PINMUX_DATA(LCD_DATA17_PJ17_MARK, PJ17MD_010),
        PINMUX_DATA(SSL00_PJ17_MARK, PJ17MD_011),
        PINMUX_DATA(TIOC0B_MARK, PJ17MD_100),
        PINMUX_DATA(SIOFSYNC_MARK, PJ17MD_101),
 
        PINMUX_DATA(PJ16_DATA, PJ16MD_000),
        PINMUX_DATA(DV_DATA16_MARK, PJ16MD_001),
-       PINMUX_DATA(LCD_DATA16_MARK, PJ16MD_010),
+       PINMUX_DATA(LCD_DATA16_PJ16_MARK, PJ16MD_010),
        PINMUX_DATA(RSPCK0_PJ16_MARK, PJ16MD_011),
        PINMUX_DATA(TIOC0A_MARK, PJ16MD_100),
        PINMUX_DATA(SIOFSCK_MARK, PJ16MD_101),
 
        PINMUX_DATA(PJ15_DATA, PJ15MD_000),
        PINMUX_DATA(DV_DATA15_MARK, PJ15MD_001),
-       PINMUX_DATA(LCD_DATA15_MARK, PJ15MD_010),
+       PINMUX_DATA(LCD_DATA15_PJ15_MARK, PJ15MD_010),
        PINMUX_DATA(PINT7_PJ_MARK, PJ15MD_011),
        PINMUX_DATA(PWM2H_MARK, PJ15MD_100),
        PINMUX_DATA(TXD7_MARK, PJ15MD_101),
 
        PINMUX_DATA(PJ14_DATA, PJ14MD_000),
        PINMUX_DATA(DV_DATA14_MARK, PJ14MD_001),
-       PINMUX_DATA(LCD_DATA14_MARK, PJ14MD_010),
+       PINMUX_DATA(LCD_DATA14_PJ14_MARK, PJ14MD_010),
        PINMUX_DATA(PINT6_PJ_MARK, PJ14MD_011),
        PINMUX_DATA(PWM2G_MARK, PJ14MD_100),
        PINMUX_DATA(TXD6_MARK, PJ14MD_101),
 
        PINMUX_DATA(PJ13_DATA, PJ13MD_000),
        PINMUX_DATA(DV_DATA13_MARK, PJ13MD_001),
-       PINMUX_DATA(LCD_DATA13_MARK, PJ13MD_010),
+       PINMUX_DATA(LCD_DATA13_PJ13_MARK, PJ13MD_010),
        PINMUX_DATA(PINT5_PJ_MARK, PJ13MD_011),
        PINMUX_DATA(PWM2F_MARK, PJ13MD_100),
        PINMUX_DATA(TXD5_MARK, PJ13MD_101),
 
        PINMUX_DATA(PJ12_DATA, PJ12MD_000),
        PINMUX_DATA(DV_DATA12_MARK, PJ12MD_001),
-       PINMUX_DATA(LCD_DATA12_MARK, PJ12MD_010),
+       PINMUX_DATA(LCD_DATA12_PJ12_MARK, PJ12MD_010),
        PINMUX_DATA(PINT4_PJ_MARK, PJ12MD_011),
        PINMUX_DATA(PWM2E_MARK, PJ12MD_100),
        PINMUX_DATA(SCK7_MARK, PJ12MD_101),
 
        PINMUX_DATA(PJ11_DATA, PJ11MD_000),
        PINMUX_DATA(DV_DATA11_MARK, PJ11MD_001),
-       PINMUX_DATA(LCD_DATA11_MARK, PJ11MD_010),
+       PINMUX_DATA(LCD_DATA11_PJ11_MARK, PJ11MD_010),
        PINMUX_DATA(PINT3_PJ_MARK, PJ11MD_011),
        PINMUX_DATA(PWM2D_MARK, PJ11MD_100),
        PINMUX_DATA(SCK6_MARK, PJ11MD_101),
 
        PINMUX_DATA(PJ10_DATA, PJ10MD_000),
        PINMUX_DATA(DV_DATA10_MARK, PJ10MD_001),
-       PINMUX_DATA(LCD_DATA10_MARK, PJ10MD_010),
+       PINMUX_DATA(LCD_DATA10_PJ10_MARK, PJ10MD_010),
        PINMUX_DATA(PINT2_PJ_MARK, PJ10MD_011),
        PINMUX_DATA(PWM2C_MARK, PJ10MD_100),
        PINMUX_DATA(SCK5_MARK, PJ10MD_101),
 
        PINMUX_DATA(PJ9_DATA, PJ9MD_000),
        PINMUX_DATA(DV_DATA9_MARK, PJ9MD_001),
-       PINMUX_DATA(LCD_DATA9_MARK, PJ9MD_010),
+       PINMUX_DATA(LCD_DATA9_PJ9_MARK, PJ9MD_010),
        PINMUX_DATA(PINT1_PJ_MARK, PJ9MD_011),
        PINMUX_DATA(PWM2B_MARK, PJ9MD_100),
        PINMUX_DATA(RTS5_MARK, PJ9MD_101),
 
        PINMUX_DATA(PJ8_DATA, PJ8MD_000),
        PINMUX_DATA(DV_DATA8_MARK, PJ8MD_001),
-       PINMUX_DATA(LCD_DATA8_MARK, PJ8MD_010),
+       PINMUX_DATA(LCD_DATA8_PJ8_MARK, PJ8MD_010),
        PINMUX_DATA(PINT0_PJ_MARK, PJ8MD_011),
        PINMUX_DATA(PWM2A_MARK, PJ8MD_100),
        PINMUX_DATA(CTS5_MARK, PJ8MD_101),
 
        PINMUX_DATA(PJ7_DATA, PJ7MD_000),
        PINMUX_DATA(DV_DATA7_MARK, PJ7MD_001),
-       PINMUX_DATA(LCD_DATA7_MARK, PJ7MD_010),
+       PINMUX_DATA(LCD_DATA7_PJ7_MARK, PJ7MD_010),
        PINMUX_DATA(SD_D2_MARK, PJ7MD_011),
        PINMUX_DATA(PWM1H_MARK, PJ7MD_100),
 
        PINMUX_DATA(PJ6_DATA, PJ6MD_000),
        PINMUX_DATA(DV_DATA6_MARK, PJ6MD_001),
-       PINMUX_DATA(LCD_DATA6_MARK, PJ6MD_010),
+       PINMUX_DATA(LCD_DATA6_PJ6_MARK, PJ6MD_010),
        PINMUX_DATA(SD_D3_MARK, PJ6MD_011),
        PINMUX_DATA(PWM1G_MARK, PJ6MD_100),
 
        PINMUX_DATA(PJ5_DATA, PJ5MD_000),
        PINMUX_DATA(DV_DATA5_MARK, PJ5MD_001),
-       PINMUX_DATA(LCD_DATA5_MARK, PJ5MD_010),
+       PINMUX_DATA(LCD_DATA5_PJ5_MARK, PJ5MD_010),
        PINMUX_DATA(SD_CMD_MARK, PJ5MD_011),
        PINMUX_DATA(PWM1F_MARK, PJ5MD_100),
 
        PINMUX_DATA(PJ4_DATA, PJ4MD_000),
        PINMUX_DATA(DV_DATA4_MARK, PJ4MD_001),
-       PINMUX_DATA(LCD_DATA4_MARK, PJ4MD_010),
+       PINMUX_DATA(LCD_DATA4_PJ4_MARK, PJ4MD_010),
        PINMUX_DATA(SD_CLK_MARK, PJ4MD_011),
        PINMUX_DATA(PWM1E_MARK, PJ4MD_100),
 
        PINMUX_DATA(PJ3_DATA, PJ3MD_000),
        PINMUX_DATA(DV_DATA3_MARK, PJ3MD_001),
-       PINMUX_DATA(LCD_DATA3_MARK, PJ3MD_010),
+       PINMUX_DATA(LCD_DATA3_PJ3_MARK, PJ3MD_010),
        PINMUX_DATA(SD_D0_MARK, PJ3MD_011),
        PINMUX_DATA(PWM1D_MARK, PJ3MD_100),
 
        PINMUX_DATA(PJ2_DATA, PJ2MD_000),
        PINMUX_DATA(DV_DATA2_MARK, PJ2MD_001),
-       PINMUX_DATA(LCD_DATA2_MARK, PJ2MD_010),
+       PINMUX_DATA(LCD_DATA2_PJ2_MARK, PJ2MD_010),
        PINMUX_DATA(SD_D1_MARK, PJ2MD_011),
        PINMUX_DATA(PWM1C_MARK, PJ2MD_100),
 
        PINMUX_DATA(PJ1_DATA, PJ1MD_000),
        PINMUX_DATA(DV_DATA1_MARK, PJ1MD_001),
-       PINMUX_DATA(LCD_DATA1_MARK, PJ1MD_010),
+       PINMUX_DATA(LCD_DATA1_PJ1_MARK, PJ1MD_010),
        PINMUX_DATA(SD_WP_MARK, PJ1MD_011),
        PINMUX_DATA(PWM1B_MARK, PJ1MD_100),
 
        PINMUX_DATA(PJ0_DATA, PJ0MD_000),
        PINMUX_DATA(DV_DATA0_MARK, PJ0MD_001),
-       PINMUX_DATA(LCD_DATA0_MARK, PJ0MD_010),
+       PINMUX_DATA(LCD_DATA0_PJ0_MARK, PJ0MD_010),
        PINMUX_DATA(SD_CD_MARK, PJ0MD_011),
        PINMUX_DATA(PWM1A_MARK, PJ0MD_100),
 };
@@ -1877,30 +1891,55 @@ static struct pinmux_gpio pinmux_gpios[] = {
        PINMUX_GPIO(GPIO_FN_LCD_HSYNC, LCD_HSYNC_MARK),
        PINMUX_GPIO(GPIO_FN_LCD_DE, LCD_DE_MARK),
 
-       PINMUX_GPIO(GPIO_FN_LCD_DATA23, LCD_DATA23_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA22, LCD_DATA22_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA21, LCD_DATA21_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA20, LCD_DATA20_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA19, LCD_DATA19_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA18, LCD_DATA18_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA17, LCD_DATA17_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA16, LCD_DATA16_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA15, LCD_DATA15_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA14, LCD_DATA14_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA13, LCD_DATA13_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA12, LCD_DATA12_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA11, LCD_DATA11_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA10, LCD_DATA10_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA9, LCD_DATA9_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA8, LCD_DATA8_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA7, LCD_DATA7_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA6, LCD_DATA6_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA5, LCD_DATA5_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA4, LCD_DATA4_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA3, LCD_DATA3_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA2, LCD_DATA2_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA1, LCD_DATA1_MARK),
-       PINMUX_GPIO(GPIO_FN_LCD_DATA0, LCD_DATA0_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA23_PG23, LCD_DATA23_PG23_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA22_PG22, LCD_DATA22_PG22_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA21_PG21, LCD_DATA21_PG21_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA20_PG20, LCD_DATA20_PG20_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA19_PG19, LCD_DATA19_PG19_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA18_PG18, LCD_DATA18_PG18_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA17_PG17, LCD_DATA17_PG17_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA16_PG16, LCD_DATA16_PG16_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA15_PG15, LCD_DATA15_PG15_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA14_PG14, LCD_DATA14_PG14_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA13_PG13, LCD_DATA13_PG13_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA12_PG12, LCD_DATA12_PG12_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA11_PG11, LCD_DATA11_PG11_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA10_PG10, LCD_DATA10_PG10_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA9_PG9, LCD_DATA9_PG9_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA8_PG8, LCD_DATA8_PG8_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA7_PG7, LCD_DATA7_PG7_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA6_PG6, LCD_DATA6_PG6_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA5_PG5, LCD_DATA5_PG5_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA4_PG4, LCD_DATA4_PG4_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA3_PG3, LCD_DATA3_PG3_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA2_PG2, LCD_DATA2_PG2_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA1_PG1, LCD_DATA1_PG1_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA0_PG0, LCD_DATA0_PG0_MARK),
+
+       PINMUX_GPIO(GPIO_FN_LCD_DATA23_PJ23, LCD_DATA23_PJ23_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA22_PJ22, LCD_DATA22_PJ22_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA21_PJ21, LCD_DATA21_PJ21_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA20_PJ20, LCD_DATA20_PJ20_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA19_PJ19, LCD_DATA19_PJ19_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA18_PJ18, LCD_DATA18_PJ18_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA17_PJ17, LCD_DATA17_PJ17_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA16_PJ16, LCD_DATA16_PJ16_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA15_PJ15, LCD_DATA15_PJ15_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA14_PJ14, LCD_DATA14_PJ14_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA13_PJ13, LCD_DATA13_PJ13_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA12_PJ12, LCD_DATA12_PJ12_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA11_PJ11, LCD_DATA11_PJ11_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA10_PJ10, LCD_DATA10_PJ10_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA9_PJ9, LCD_DATA9_PJ9_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA8_PJ8, LCD_DATA8_PJ8_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA7_PJ7, LCD_DATA7_PJ7_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA6_PJ6, LCD_DATA6_PJ6_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA5_PJ5, LCD_DATA5_PJ5_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA4_PJ4, LCD_DATA4_PJ4_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA3_PJ3, LCD_DATA3_PJ3_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA2_PJ2, LCD_DATA2_PJ2_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA1_PJ1, LCD_DATA1_PJ1_MARK),
+       PINMUX_GPIO(GPIO_FN_LCD_DATA0_PJ0, LCD_DATA0_PJ0_MARK),
 
        PINMUX_GPIO(GPIO_FN_LCD_M_DISP, LCD_M_DISP_MARK),
 };
index 7b57bf1dc85510c08b40a9f88892ffacbf78c379..ebe7a7d97215e4978252af8a3512821e64148064 100644 (file)
@@ -273,7 +273,7 @@ void __init setup_arch(char **cmdline_p)
        data_resource.start = virt_to_phys(_etext);
        data_resource.end = virt_to_phys(_edata)-1;
        bss_resource.start = virt_to_phys(__bss_start);
-       bss_resource.end = virt_to_phys(_ebss)-1;
+       bss_resource.end = virt_to_phys(__bss_stop)-1;
 
 #ifdef CONFIG_CMDLINE_OVERWRITE
        strlcpy(command_line, CONFIG_CMDLINE, sizeof(command_line));
index 3896f26efa4a5c9466943dbe10bcfd87028c0011..2a0a596ebf67d948663df3009d1ca14c8b09dabc 100644 (file)
@@ -19,7 +19,6 @@ EXPORT_SYMBOL(csum_partial);
 EXPORT_SYMBOL(csum_partial_copy_generic);
 EXPORT_SYMBOL(copy_page);
 EXPORT_SYMBOL(__clear_user);
-EXPORT_SYMBOL(_ebss);
 EXPORT_SYMBOL(empty_zero_page);
 
 #define DECLARE_EXPORT(name)           \
index c98905f71e28ce78a1ab06e7b310653efa2156a9..db88cbf9eafdc815d76d72784c18e4df42b361e5 100644 (file)
@@ -78,7 +78,6 @@ SECTIONS
        . = ALIGN(PAGE_SIZE);
        __init_end = .;
        BSS_SECTION(0, PAGE_SIZE, 4)
-       _ebss = .;                      /* uClinux MTD sucks */
        _end = . ;
 
        STABS_DEBUG
index 84a57761f17e90ee8cfdfd71dfce2b02480002a4..60164e65d66551c4375121e984fd0ea28a9525fa 100644 (file)
@@ -39,7 +39,7 @@
  *
  * Make sure the stack pointer contains a valid address. Valid
  * addresses for kernel stacks are anywhere after the bss
- * (after _ebss) and anywhere in init_thread_union (init_stack).
+ * (after __bss_stop) and anywhere in init_thread_union (init_stack).
  */
 #define STACK_CHECK()                                  \
        mov     #(THREAD_SIZE >> 10), r0;               \
@@ -60,7 +60,7 @@
        cmp/hi  r2, r1;                                 \
        bf      stack_panic;                            \
                                                        \
-       /* If sp > _ebss then we're OK. */              \
+       /* If sp > __bss_stop then we're OK. */         \
        mov.l   .L_ebss, r1;                            \
        cmp/hi  r1, r15;                                \
        bt      1f;                                     \
@@ -70,7 +70,7 @@
        cmp/hs  r1, r15;                                \
        bf      stack_panic;                            \
                                                        \
-       /* If sp > init_stack && sp < _ebss, not OK. */ \
+       /* If sp > init_stack && sp < __bss_stop, not OK. */    \
        add     r0, r1;                                 \
        cmp/hs  r1, r15;                                \
        bt      stack_panic;                            \
@@ -292,8 +292,6 @@ stack_panic:
         nop
 
        .align 2
-.L_ebss:
-       .long   _ebss
 .L_init_thread_union:
        .long   init_thread_union
 .Lpanic:
index 67f1f6f5f4e14fa35408cda35ad1464297dd2859..a244e70b9bb0853520f0d2f155b76296b557f81f 100644 (file)
@@ -37,6 +37,7 @@ config SPARC
        select GENERIC_CLOCKEVENTS
        select GENERIC_STRNCPY_FROM_USER
        select GENERIC_STRNLEN_USER
+       select MODULES_USE_ELF_RELA
 
 config SPARC32
        def_bool !64BIT
index 67f83e0a0d68d47e3bebff7a365897614bfa411e..fbe1cb578fcd0fcdceeaa637724fdf13bbb12958 100644 (file)
@@ -21,4 +21,5 @@ generic-y += div64.h
 generic-y += local64.h
 generic-y += irq_regs.h
 generic-y += local.h
+generic-y += module.h
 generic-y += word-at-a-time.h
diff --git a/arch/sparc/include/asm/module.h b/arch/sparc/include/asm/module.h
deleted file mode 100644 (file)
index ff8e02d..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef __SPARC_MODULE_H
-#define __SPARC_MODULE_H
-struct mod_arch_specific { };
-
-/*
- * Use some preprocessor magic to define the correct symbol
- * for sparc32 and sparc64.
- * Elf_Addr becomes Elf32_Addr for sparc32 and Elf64_Addr for sparc64
- */
-#define ___ELF(a, b, c) a##b##c
-#define __ELF(a, b, c)  ___ELF(a, b, c)
-#define  _Elf(t)        __ELF(Elf, CONFIG_BITS, t)
-#define  _ELF(t)        __ELF(ELF, CONFIG_BITS, t)
-
-#define Elf_Shdr     _Elf(_Shdr)
-#define Elf_Sym      _Elf(_Sym)
-#define Elf_Ehdr     _Elf(_Ehdr)
-#define Elf_Rela     _Elf(_Rela)
-#define Elf_Addr     _Elf(_Addr)
-
-#define ELF_R_SYM    _ELF(_R_SYM)
-#define ELF_R_TYPE   _ELF(_R_TYPE)
-
-#endif /* __SPARC_MODULE_H */
index 0dc1f578608131002da0b869dcfa7c56b4b149e3..11c6c9603e71f03995a3c17fcdf2f28957d7fa43 100644 (file)
@@ -502,12 +502,12 @@ SYSCALL_DEFINE1(sparc64_personality, unsigned long, personality)
 {
        int ret;
 
-       if (current->personality == PER_LINUX32 &&
-           personality == PER_LINUX)
-               personality = PER_LINUX32;
+       if (personality(current->personality) == PER_LINUX32 &&
+           personality(personality) == PER_LINUX)
+               personality |= PER_LINUX32;
        ret = sys_personality(personality);
-       if (ret == PER_LINUX32)
-               ret = PER_LINUX;
+       if (personality(ret) == PER_LINUX32)
+               ret &= ~PER_LINUX32;
 
        return ret;
 }
index 6026fdd1b2eddedbf9dcff60e1079c176eb0d3d6..d58edf5fefdb6a4a3fdf484f46588cc411727c38 100644 (file)
@@ -2020,6 +2020,9 @@ EXPORT_SYMBOL(_PAGE_CACHE);
 #ifdef CONFIG_SPARSEMEM_VMEMMAP
 unsigned long vmemmap_table[VMEMMAP_SIZE];
 
+static long __meminitdata addr_start, addr_end;
+static int __meminitdata node_start;
+
 int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node)
 {
        unsigned long vstart = (unsigned long) start;
@@ -2050,15 +2053,30 @@ int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node)
 
                        *vmem_pp = pte_base | __pa(block);
 
-                       printk(KERN_INFO "[%p-%p] page_structs=%lu "
-                              "node=%d entry=%lu/%lu\n", start, block, nr,
-                              node,
-                              addr >> VMEMMAP_CHUNK_SHIFT,
-                              VMEMMAP_SIZE);
+                       /* check to see if we have contiguous blocks */
+                       if (addr_end != addr || node_start != node) {
+                               if (addr_start)
+                                       printk(KERN_DEBUG " [%lx-%lx] on node %d\n",
+                                              addr_start, addr_end-1, node_start);
+                               addr_start = addr;
+                               node_start = node;
+                       }
+                       addr_end = addr + VMEMMAP_CHUNK;
                }
        }
        return 0;
 }
+
+void __meminit vmemmap_populate_print_last(void)
+{
+       if (addr_start) {
+               printk(KERN_DEBUG " [%lx-%lx] on node %d\n",
+                      addr_start, addr_end-1, node_start);
+               addr_start = 0;
+               addr_end = 0;
+               node_start = 0;
+       }
+}
 #endif /* CONFIG_SPARSEMEM_VMEMMAP */
 
 static void prot_init_common(unsigned long page_none,
index 932e4430f7f3323ef9be06d2f4b1f8ac98ae611f..1603f304339986be9f96bdd8406ebf6973e8130b 100644 (file)
@@ -17,6 +17,7 @@ config TILE
        select SYS_HYPERVISOR
        select ARCH_HAVE_NMI_SAFE_CMPXCHG
        select GENERIC_CLOCKEVENTS
+       select MODULES_USE_ELF_RELA
 
 # FIXME: investigate whether we need/want these options.
 #      select HAVE_IOREMAP_PROT
index bbaf2c59830ac3561c432d8ac23d6f64bf62dd79..457475f98414392ece09be3dcfbf0578c31f1215 100644 (file)
@@ -409,7 +409,8 @@ int setup_one_line(struct line *lines, int n, char *init,
                line->valid = 1;
                err = parse_chan_pair(new, line, n, opts, error_out);
                if (!err) {
-                       struct device *d = tty_register_device(driver, n, NULL);
+                       struct device *d = tty_port_register_device(&line->port,
+                                       driver, n, NULL);
                        if (IS_ERR(d)) {
                                *error_out = "Failed to register device";
                                err = PTR_ERR(d);
index 664a60e8dfb442fe2cb75c1ed5ba388a7bdb42b0..c17de0db6736e1bcef0fca9ab1a3d624cd271580 100644 (file)
@@ -705,6 +705,7 @@ static void stack_proc(void *arg)
        struct task_struct *from = current, *to = arg;
 
        to->thread.saved_task = from;
+       rcu_switch(from, to);
        switch_to(from, to, from);
 }
 
index b0a47433341e4164988c8332ff85b1560eb11252..5d53ffd5736ff47c82f1c60b31f35d4f7a930233 100644 (file)
@@ -14,6 +14,7 @@ config UNICORE32
        select GENERIC_IRQ_SHOW
        select ARCH_WANT_FRAME_POINTERS
        select GENERIC_IOMAP
+       select MODULES_USE_ELF_REL
        help
          UniCore-32 is 32-bit Instruction Set Architecture,
          including a series of low-power-consumption RISC chip
@@ -65,6 +66,9 @@ config GENERIC_CALIBRATE_DELAY
 config ARCH_MAY_HAVE_PC_FDC
        bool
 
+config ZONE_DMA
+       def_bool y
+
 config NEED_DMA_MAP_STATE
        def_bool y
 
index b1ff8cadb0866bf38ead0c95353c0020160a3c62..93a56f3e2344079b49de459ad08bb798ad9b7935 100644 (file)
@@ -19,9 +19,4 @@ extern void die(const char *msg, struct pt_regs *regs, int err);
 extern void uc32_notify_die(const char *str, struct pt_regs *regs,
                struct siginfo *info, unsigned long err, unsigned long trap);
 
-extern asmlinkage void __backtrace(void);
-extern asmlinkage void c_backtrace(unsigned long fp, int pmode);
-
-extern void __show_regs(struct pt_regs *);
-
 #endif /* __UNICORE_BUG_H__ */
index df4d5acfd19f96c9a10598a9230a0331fb7be798..8e797ad4fa24f52cbadb7b6a860a3b214d83eb3f 100644 (file)
@@ -35,7 +35,7 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
                        : "memory", "cc");
                break;
        default:
-               ret = __xchg_bad_pointer();
+               __xchg_bad_pointer();
        }
 
        return ret;
index f23955028a183f70c0e0982ff934a06157bad659..30f749da8f7317ecf0613089ad0876f02ed533c7 100644 (file)
@@ -30,4 +30,10 @@ extern char __vectors_start[], __vectors_end[];
 extern void kernel_thread_helper(void);
 
 extern void __init early_signal_init(void);
+
+extern asmlinkage void __backtrace(void);
+extern asmlinkage void c_backtrace(unsigned long fp, int pmode);
+
+extern void __show_regs(struct pt_regs *);
+
 #endif
index 2eeb9c04cab057b5a2c6f542e251d6762cd6621b..f9b5c10bccee96e8838484aaf6effc39b3c89bd1 100644 (file)
@@ -168,7 +168,7 @@ static inline bool access_error(unsigned int fsr, struct vm_area_struct *vma)
 }
 
 static int __do_pf(struct mm_struct *mm, unsigned long addr, unsigned int fsr,
-               struct task_struct *tsk)
+               unsigned int flags, struct task_struct *tsk)
 {
        struct vm_area_struct *vma;
        int fault;
@@ -194,14 +194,7 @@ good_area:
         * If for any reason at all we couldn't handle the fault, make
         * sure we exit gracefully rather than endlessly redo the fault.
         */
-       fault = handle_mm_fault(mm, vma, addr & PAGE_MASK,
-                           (!(fsr ^ 0x12)) ? FAULT_FLAG_WRITE : 0);
-       if (unlikely(fault & VM_FAULT_ERROR))
-               return fault;
-       if (fault & VM_FAULT_MAJOR)
-               tsk->maj_flt++;
-       else
-               tsk->min_flt++;
+       fault = handle_mm_fault(mm, vma, addr & PAGE_MASK, flags);
        return fault;
 
 check_stack:
@@ -216,6 +209,8 @@ static int do_pf(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
        struct task_struct *tsk;
        struct mm_struct *mm;
        int fault, sig, code;
+       unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
+                                ((!(fsr ^ 0x12)) ? FAULT_FLAG_WRITE : 0);
 
        tsk = current;
        mm = tsk->mm;
@@ -236,6 +231,7 @@ static int do_pf(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
                if (!user_mode(regs)
                    && !search_exception_tables(regs->UCreg_pc))
                        goto no_context;
+retry:
                down_read(&mm->mmap_sem);
        } else {
                /*
@@ -251,7 +247,28 @@ static int do_pf(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 #endif
        }
 
-       fault = __do_pf(mm, addr, fsr, tsk);
+       fault = __do_pf(mm, addr, fsr, flags, tsk);
+
+       /* If we need to retry but a fatal signal is pending, handle the
+        * signal first. We do not need to release the mmap_sem because
+        * it would already be released in __lock_page_or_retry in
+        * mm/filemap.c. */
+       if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
+               return 0;
+
+       if (!(fault & VM_FAULT_ERROR) && (flags & FAULT_FLAG_ALLOW_RETRY)) {
+               if (fault & VM_FAULT_MAJOR)
+                       tsk->maj_flt++;
+               else
+                       tsk->min_flt++;
+               if (fault & VM_FAULT_RETRY) {
+                       /* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk
+                       * of starvation. */
+                       flags &= ~FAULT_FLAG_ALLOW_RETRY;
+                       goto retry;
+               }
+       }
+
        up_read(&mm->mmap_sem);
 
        /*
index ba2657c492171c5ce5c295d1e1d4ef85391608d8..e76af9e07e2232ce2298f94f7bc7ef676147afab 100644 (file)
@@ -97,6 +97,9 @@ config X86
        select KTIME_SCALAR if X86_32
        select GENERIC_STRNCPY_FROM_USER
        select GENERIC_STRNLEN_USER
+       select MODULES_USE_ELF_REL if X86_32
+       select MODULES_USE_ELF_RELA if X86_64
+       select HAVE_RCU_USER_QS if X86_64
 
 config INSTRUCTION_DECODER
        def_bool (KPROBES || PERF_EVENTS || UPROBES)
@@ -549,6 +552,37 @@ config SCHED_OMIT_FRAME_POINTER
 
          If in doubt, say "Y".
 
+config KVMTOOL_TEST_ENABLE
+       bool "Enable options to create a bootable tools/kvm/ kernel"
+       select NET
+       select NETDEVICES
+       select PCI
+       select BLOCK
+       select BLK_DEV
+       select NETWORK_FILESYSTEMS
+       select INET
+       select EXPERIMENTAL
+       select SERIAL_8250
+       select SERIAL_8250_CONSOLE
+       select IP_PNP
+       select IP_PNP_DHCP
+       select BINFMT_ELF
+       select PCI_MSI
+       select HAVE_ARCH_KGDB
+       select DEBUG_KERNEL
+       select KGDB
+       select KGDB_SERIAL_CONSOLE
+       select VIRTUALIZATION
+       select VIRTIO
+       select VIRTIO_RING
+       select VIRTIO_PCI
+       select VIRTIO_BLK
+       select VIRTIO_CONSOLE
+       select VIRTIO_NET
+       select 9P_FS
+       select NET_9P
+       select NET_9P_VIRTIO
+
 menuconfig PARAVIRT_GUEST
        bool "Paravirtualized guest support"
        ---help---
@@ -1527,7 +1561,7 @@ config SECCOMP
          If unsure, say Y. Only embedded should say N here.
 
 config CC_STACKPROTECTOR
-       bool "Enable -fstack-protector buffer overflow detection (EXPERIMENTAL)"
+       bool "Enable -fstack-protector buffer overflow detection"
        ---help---
          This option turns on the -fstack-protector GCC feature. This
          feature puts, at the beginning of functions, a canary value on
index e908e5de82d3caace8e418e2de3ff70efe12245d..5bacb4a226ac8e4ff88562b60e96f04f2e0cc8e4 100644 (file)
@@ -12,6 +12,8 @@ obj-$(CONFIG_CRYPTO_SERPENT_SSE2_586) += serpent-sse2-i586.o
 
 obj-$(CONFIG_CRYPTO_AES_X86_64) += aes-x86_64.o
 obj-$(CONFIG_CRYPTO_CAMELLIA_X86_64) += camellia-x86_64.o
+obj-$(CONFIG_CRYPTO_CAST5_AVX_X86_64) += cast5-avx-x86_64.o
+obj-$(CONFIG_CRYPTO_CAST6_AVX_X86_64) += cast6-avx-x86_64.o
 obj-$(CONFIG_CRYPTO_BLOWFISH_X86_64) += blowfish-x86_64.o
 obj-$(CONFIG_CRYPTO_TWOFISH_X86_64) += twofish-x86_64.o
 obj-$(CONFIG_CRYPTO_TWOFISH_X86_64_3WAY) += twofish-x86_64-3way.o
@@ -32,6 +34,8 @@ serpent-sse2-i586-y := serpent-sse2-i586-asm_32.o serpent_sse2_glue.o
 
 aes-x86_64-y := aes-x86_64-asm_64.o aes_glue.o
 camellia-x86_64-y := camellia-x86_64-asm_64.o camellia_glue.o
+cast5-avx-x86_64-y := cast5-avx-x86_64-asm_64.o cast5_avx_glue.o
+cast6-avx-x86_64-y := cast6-avx-x86_64-asm_64.o cast6_avx_glue.o
 blowfish-x86_64-y := blowfish-x86_64-asm_64.o blowfish_glue.o
 twofish-x86_64-y := twofish-x86_64-asm_64.o twofish_glue.o
 twofish-x86_64-3way-y := twofish-x86_64-asm_64-3way.o twofish_glue_3way.o
index 59b37deb8c8df03bc4360feb4cde2eae7db83a4a..aafe8ce0d65dd4f68b04dab1fecbf33038b4031e 100644 (file)
@@ -40,7 +40,6 @@ static struct crypto_alg aes_alg = {
        .cra_blocksize          = AES_BLOCK_SIZE,
        .cra_ctxsize            = sizeof(struct crypto_aes_ctx),
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(aes_alg.cra_list),
        .cra_u  = {
                .cipher = {
                        .cia_min_keysize        = AES_MIN_KEY_SIZE,
index 34fdcff4d2c8e42d7ed2c1908b5409d1982b942a..648347a0577309309d21f1a5aa0492f904caa4a0 100644 (file)
@@ -1118,7 +1118,7 @@ MODULE_DEVICE_TABLE(x86cpu, aesni_cpu_id);
 
 static int __init aesni_init(void)
 {
-       int err, i;
+       int err;
 
        if (!x86_match_cpu(aesni_cpu_id))
                return -ENODEV;
@@ -1127,9 +1127,6 @@ static int __init aesni_init(void)
        if (err)
                return err;
 
-       for (i = 0; i < ARRAY_SIZE(aesni_algs); i++)
-               INIT_LIST_HEAD(&aesni_algs[i].cra_list);
-
        return crypto_register_algs(aesni_algs, ARRAY_SIZE(aesni_algs));
 }
 
index 7967474de8f7c8e0c1c0f50db3ad4652d431f5a3..50ec333b70e62437e38d409444213eb94f54614e 100644 (file)
@@ -367,7 +367,6 @@ static struct crypto_alg bf_algs[4] = { {
        .cra_ctxsize            = sizeof(struct bf_ctx),
        .cra_alignmask          = 0,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(bf_algs[0].cra_list),
        .cra_u = {
                .cipher = {
                        .cia_min_keysize        = BF_MIN_KEY_SIZE,
@@ -387,7 +386,6 @@ static struct crypto_alg bf_algs[4] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_blkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(bf_algs[1].cra_list),
        .cra_u = {
                .blkcipher = {
                        .min_keysize    = BF_MIN_KEY_SIZE,
@@ -407,7 +405,6 @@ static struct crypto_alg bf_algs[4] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_blkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(bf_algs[2].cra_list),
        .cra_u = {
                .blkcipher = {
                        .min_keysize    = BF_MIN_KEY_SIZE,
@@ -428,7 +425,6 @@ static struct crypto_alg bf_algs[4] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_blkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(bf_algs[3].cra_list),
        .cra_u = {
                .blkcipher = {
                        .min_keysize    = BF_MIN_KEY_SIZE,
index eeb2b3b743e909855ffe6626d1e9d78efe8fd94f..7a74d7bb326ddb7dfa5b99bda199576484362e73 100644 (file)
@@ -1601,7 +1601,6 @@ static struct crypto_alg camellia_algs[6] = { {
        .cra_ctxsize            = sizeof(struct camellia_ctx),
        .cra_alignmask          = 0,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(camellia_algs[0].cra_list),
        .cra_u                  = {
                .cipher = {
                        .cia_min_keysize = CAMELLIA_MIN_KEY_SIZE,
@@ -1621,7 +1620,6 @@ static struct crypto_alg camellia_algs[6] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_blkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(camellia_algs[1].cra_list),
        .cra_u = {
                .blkcipher = {
                        .min_keysize    = CAMELLIA_MIN_KEY_SIZE,
@@ -1641,7 +1639,6 @@ static struct crypto_alg camellia_algs[6] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_blkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(camellia_algs[2].cra_list),
        .cra_u = {
                .blkcipher = {
                        .min_keysize    = CAMELLIA_MIN_KEY_SIZE,
@@ -1662,7 +1659,6 @@ static struct crypto_alg camellia_algs[6] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_blkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(camellia_algs[3].cra_list),
        .cra_u = {
                .blkcipher = {
                        .min_keysize    = CAMELLIA_MIN_KEY_SIZE,
@@ -1683,7 +1679,6 @@ static struct crypto_alg camellia_algs[6] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_blkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(camellia_algs[4].cra_list),
        .cra_exit               = lrw_exit_tfm,
        .cra_u = {
                .blkcipher = {
@@ -1707,7 +1702,6 @@ static struct crypto_alg camellia_algs[6] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_blkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(camellia_algs[5].cra_list),
        .cra_u = {
                .blkcipher = {
                        .min_keysize    = CAMELLIA_MIN_KEY_SIZE * 2,
diff --git a/arch/x86/crypto/cast5-avx-x86_64-asm_64.S b/arch/x86/crypto/cast5-avx-x86_64-asm_64.S
new file mode 100644 (file)
index 0000000..94693c8
--- /dev/null
@@ -0,0 +1,322 @@
+/*
+ * Cast5 Cipher 16-way parallel algorithm (AVX/x86_64)
+ *
+ * Copyright (C) 2012 Johannes Goetzfried
+ *     <Johannes.Goetzfried@informatik.stud.uni-erlangen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ * USA
+ *
+ */
+
+.file "cast5-avx-x86_64-asm_64.S"
+.text
+
+.extern cast5_s1
+.extern cast5_s2
+.extern cast5_s3
+.extern cast5_s4
+
+/* structure of crypto context */
+#define km     0
+#define kr     (16*4)
+#define rr     ((16*4)+16)
+
+/* s-boxes */
+#define s1     cast5_s1
+#define s2     cast5_s2
+#define s3     cast5_s3
+#define s4     cast5_s4
+
+/**********************************************************************
+  16-way AVX cast5
+ **********************************************************************/
+#define CTX %rdi
+
+#define RL1 %xmm0
+#define RR1 %xmm1
+#define RL2 %xmm2
+#define RR2 %xmm3
+#define RL3 %xmm4
+#define RR3 %xmm5
+#define RL4 %xmm6
+#define RR4 %xmm7
+
+#define RX %xmm8
+
+#define RKM  %xmm9
+#define RKRF %xmm10
+#define RKRR %xmm11
+
+#define RTMP  %xmm12
+#define RMASK %xmm13
+#define R32   %xmm14
+
+#define RID1  %rax
+#define RID1b %al
+#define RID2  %rbx
+#define RID2b %bl
+
+#define RGI1   %rdx
+#define RGI1bl %dl
+#define RGI1bh %dh
+#define RGI2   %rcx
+#define RGI2bl %cl
+#define RGI2bh %ch
+
+#define RFS1  %r8
+#define RFS1d %r8d
+#define RFS2  %r9
+#define RFS2d %r9d
+#define RFS3  %r10
+#define RFS3d %r10d
+
+
+#define lookup_32bit(src, dst, op1, op2, op3) \
+       movb            src ## bl,     RID1b;    \
+       movb            src ## bh,     RID2b;    \
+       movl            s1(, RID1, 4), dst ## d; \
+       op1             s2(, RID2, 4), dst ## d; \
+       shrq $16,       src;                     \
+       movb            src ## bl,     RID1b;    \
+       movb            src ## bh,     RID2b;    \
+       op2             s3(, RID1, 4), dst ## d; \
+       op3             s4(, RID2, 4), dst ## d;
+
+#define F(a, x, op0, op1, op2, op3) \
+       op0     a,      RKM,  x;                 \
+       vpslld  RKRF,   x,    RTMP;              \
+       vpsrld  RKRR,   x,    x;                 \
+       vpor    RTMP,   x,    x;                 \
+       \
+       vpshufb RMASK,  x,    x;                 \
+       vmovq           x,    RGI1;              \
+       vpsrldq $8,     x,    x;                 \
+       vmovq           x,    RGI2;              \
+       \
+       lookup_32bit(RGI1, RFS1, op1, op2, op3); \
+       shrq $16,       RGI1;                    \
+       lookup_32bit(RGI1, RFS2, op1, op2, op3); \
+       shlq $32,       RFS2;                    \
+       orq             RFS1, RFS2;              \
+       \
+       lookup_32bit(RGI2, RFS1, op1, op2, op3); \
+       shrq $16,       RGI2;                    \
+       lookup_32bit(RGI2, RFS3, op1, op2, op3); \
+       shlq $32,       RFS3;                    \
+       orq             RFS1, RFS3;              \
+       \
+       vmovq           RFS2, x;                 \
+       vpinsrq $1,     RFS3, x, x;
+
+#define F1(b, x) F(b, x, vpaddd, xorl, subl, addl)
+#define F2(b, x) F(b, x, vpxor,  subl, addl, xorl)
+#define F3(b, x) F(b, x, vpsubd, addl, xorl, subl)
+
+#define subround(a, b, x, n, f) \
+       F ## f(b, x);  \
+       vpxor a, x, a;
+
+#define round(l, r, n, f) \
+       vbroadcastss    (km+(4*n))(CTX), RKM;        \
+       vpinsrb $0,     (kr+n)(CTX),     RKRF, RKRF; \
+       vpsubq          RKRF,            R32,  RKRR; \
+       subround(l ## 1, r ## 1, RX, n, f);          \
+       subround(l ## 2, r ## 2, RX, n, f);          \
+       subround(l ## 3, r ## 3, RX, n, f);          \
+       subround(l ## 4, r ## 4, RX, n, f);
+
+
+#define transpose_2x4(x0, x1, t0, t1) \
+       vpunpckldq              x1, x0, t0; \
+       vpunpckhdq              x1, x0, t1; \
+       \
+       vpunpcklqdq             t1, t0, x0; \
+       vpunpckhqdq             t1, t0, x1;
+
+#define inpack_blocks(in, x0, x1, t0, t1) \
+       vmovdqu (0*4*4)(in),    x0; \
+       vmovdqu (1*4*4)(in),    x1; \
+       vpshufb RMASK, x0,      x0; \
+       vpshufb RMASK, x1,      x1; \
+       \
+       transpose_2x4(x0, x1, t0, t1)
+
+#define outunpack_blocks(out, x0, x1, t0, t1) \
+       transpose_2x4(x0, x1, t0, t1) \
+       \
+       vpshufb RMASK,  x0, x0;           \
+       vpshufb RMASK,  x1, x1;           \
+       vmovdqu         x0, (0*4*4)(out); \
+       vmovdqu         x1, (1*4*4)(out);
+
+#define outunpack_xor_blocks(out, x0, x1, t0, t1) \
+       transpose_2x4(x0, x1, t0, t1) \
+       \
+       vpshufb RMASK,  x0, x0;               \
+       vpshufb RMASK,  x1, x1;               \
+       vpxor           (0*4*4)(out), x0, x0; \
+       vmovdqu         x0, (0*4*4)(out);     \
+       vpxor           (1*4*4)(out), x1, x1; \
+       vmovdqu         x1, (1*4*4)(out);
+
+.align 16
+.Lbswap_mask:
+       .byte 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12
+.L32_mask:
+       .byte 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0
+
+.align 16
+.global __cast5_enc_blk_16way
+.type   __cast5_enc_blk_16way,@function;
+
+__cast5_enc_blk_16way:
+       /* input:
+        *      %rdi: ctx, CTX
+        *      %rsi: dst
+        *      %rdx: src
+        *      %rcx: bool, if true: xor output
+        */
+
+       pushq %rbx;
+       pushq %rcx;
+
+       vmovdqu .Lbswap_mask, RMASK;
+       vmovdqu .L32_mask, R32;
+       vpxor RKRF, RKRF, RKRF;
+
+       inpack_blocks(%rdx, RL1, RR1, RTMP, RX);
+       leaq (2*4*4)(%rdx), %rax;
+       inpack_blocks(%rax, RL2, RR2, RTMP, RX);
+       leaq (2*4*4)(%rax), %rax;
+       inpack_blocks(%rax, RL3, RR3, RTMP, RX);
+       leaq (2*4*4)(%rax), %rax;
+       inpack_blocks(%rax, RL4, RR4, RTMP, RX);
+
+       xorq RID1, RID1;
+       xorq RID2, RID2;
+
+       round(RL, RR, 0, 1);
+       round(RR, RL, 1, 2);
+       round(RL, RR, 2, 3);
+       round(RR, RL, 3, 1);
+       round(RL, RR, 4, 2);
+       round(RR, RL, 5, 3);
+       round(RL, RR, 6, 1);
+       round(RR, RL, 7, 2);
+       round(RL, RR, 8, 3);
+       round(RR, RL, 9, 1);
+       round(RL, RR, 10, 2);
+       round(RR, RL, 11, 3);
+
+       movb rr(CTX), %al;
+       testb %al, %al;
+       jnz __skip_enc;
+
+       round(RL, RR, 12, 1);
+       round(RR, RL, 13, 2);
+       round(RL, RR, 14, 3);
+       round(RR, RL, 15, 1);
+
+__skip_enc:
+       popq %rcx;
+       popq %rbx;
+
+       testb %cl, %cl;
+       jnz __enc_xor16;
+
+       outunpack_blocks(%rsi, RR1, RL1, RTMP, RX);
+       leaq (2*4*4)(%rsi), %rax;
+       outunpack_blocks(%rax, RR2, RL2, RTMP, RX);
+       leaq (2*4*4)(%rax), %rax;
+       outunpack_blocks(%rax, RR3, RL3, RTMP, RX);
+       leaq (2*4*4)(%rax), %rax;
+       outunpack_blocks(%rax, RR4, RL4, RTMP, RX);
+
+       ret;
+
+__enc_xor16:
+       outunpack_xor_blocks(%rsi, RR1, RL1, RTMP, RX);
+       leaq (2*4*4)(%rsi), %rax;
+       outunpack_xor_blocks(%rax, RR2, RL2, RTMP, RX);
+       leaq (2*4*4)(%rax), %rax;
+       outunpack_xor_blocks(%rax, RR3, RL3, RTMP, RX);
+       leaq (2*4*4)(%rax), %rax;
+       outunpack_xor_blocks(%rax, RR4, RL4, RTMP, RX);
+
+       ret;
+
+.align 16
+.global cast5_dec_blk_16way
+.type   cast5_dec_blk_16way,@function;
+
+cast5_dec_blk_16way:
+       /* input:
+        *      %rdi: ctx, CTX
+        *      %rsi: dst
+        *      %rdx: src
+        */
+
+       pushq %rbx;
+
+       vmovdqu .Lbswap_mask, RMASK;
+       vmovdqu .L32_mask, R32;
+       vpxor RKRF, RKRF, RKRF;
+
+       inpack_blocks(%rdx, RL1, RR1, RTMP, RX);
+       leaq (2*4*4)(%rdx), %rax;
+       inpack_blocks(%rax, RL2, RR2, RTMP, RX);
+       leaq (2*4*4)(%rax), %rax;
+       inpack_blocks(%rax, RL3, RR3, RTMP, RX);
+       leaq (2*4*4)(%rax), %rax;
+       inpack_blocks(%rax, RL4, RR4, RTMP, RX);
+
+       xorq RID1, RID1;
+       xorq RID2, RID2;
+
+       movb rr(CTX), %al;
+       testb %al, %al;
+       jnz __skip_dec;
+
+       round(RL, RR, 15, 1);
+       round(RR, RL, 14, 3);
+       round(RL, RR, 13, 2);
+       round(RR, RL, 12, 1);
+
+__skip_dec:
+       round(RL, RR, 11, 3);
+       round(RR, RL, 10, 2);
+       round(RL, RR, 9, 1);
+       round(RR, RL, 8, 3);
+       round(RL, RR, 7, 2);
+       round(RR, RL, 6, 1);
+       round(RL, RR, 5, 3);
+       round(RR, RL, 4, 2);
+       round(RL, RR, 3, 1);
+       round(RR, RL, 2, 3);
+       round(RL, RR, 1, 2);
+       round(RR, RL, 0, 1);
+
+       popq %rbx;
+
+       outunpack_blocks(%rsi, RR1, RL1, RTMP, RX);
+       leaq (2*4*4)(%rsi), %rax;
+       outunpack_blocks(%rax, RR2, RL2, RTMP, RX);
+       leaq (2*4*4)(%rax), %rax;
+       outunpack_blocks(%rax, RR3, RL3, RTMP, RX);
+       leaq (2*4*4)(%rax), %rax;
+       outunpack_blocks(%rax, RR4, RL4, RTMP, RX);
+
+       ret;
diff --git a/arch/x86/crypto/cast5_avx_glue.c b/arch/x86/crypto/cast5_avx_glue.c
new file mode 100644 (file)
index 0000000..445aab0
--- /dev/null
@@ -0,0 +1,530 @@
+/*
+ * Glue Code for the AVX assembler implemention of the Cast5 Cipher
+ *
+ * Copyright (C) 2012 Johannes Goetzfried
+ *     <Johannes.Goetzfried@informatik.stud.uni-erlangen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ * USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/hardirq.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <linux/err.h>
+#include <crypto/algapi.h>
+#include <crypto/cast5.h>
+#include <crypto/cryptd.h>
+#include <crypto/ctr.h>
+#include <asm/xcr.h>
+#include <asm/xsave.h>
+#include <asm/crypto/ablk_helper.h>
+#include <asm/crypto/glue_helper.h>
+
+#define CAST5_PARALLEL_BLOCKS 16
+
+asmlinkage void __cast5_enc_blk_16way(struct cast5_ctx *ctx, u8 *dst,
+                                     const u8 *src, bool xor);
+asmlinkage void cast5_dec_blk_16way(struct cast5_ctx *ctx, u8 *dst,
+                                   const u8 *src);
+
+static inline void cast5_enc_blk_xway(struct cast5_ctx *ctx, u8 *dst,
+                                     const u8 *src)
+{
+       __cast5_enc_blk_16way(ctx, dst, src, false);
+}
+
+static inline void cast5_enc_blk_xway_xor(struct cast5_ctx *ctx, u8 *dst,
+                                         const u8 *src)
+{
+       __cast5_enc_blk_16way(ctx, dst, src, true);
+}
+
+static inline void cast5_dec_blk_xway(struct cast5_ctx *ctx, u8 *dst,
+                                     const u8 *src)
+{
+       cast5_dec_blk_16way(ctx, dst, src);
+}
+
+
+static inline bool cast5_fpu_begin(bool fpu_enabled, unsigned int nbytes)
+{
+       return glue_fpu_begin(CAST5_BLOCK_SIZE, CAST5_PARALLEL_BLOCKS,
+                             NULL, fpu_enabled, nbytes);
+}
+
+static inline void cast5_fpu_end(bool fpu_enabled)
+{
+       return glue_fpu_end(fpu_enabled);
+}
+
+static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk,
+                    bool enc)
+{
+       bool fpu_enabled = false;
+       struct cast5_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       const unsigned int bsize = CAST5_BLOCK_SIZE;
+       unsigned int nbytes;
+       int err;
+
+       err = blkcipher_walk_virt(desc, walk);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       while ((nbytes = walk->nbytes)) {
+               u8 *wsrc = walk->src.virt.addr;
+               u8 *wdst = walk->dst.virt.addr;
+
+               fpu_enabled = cast5_fpu_begin(fpu_enabled, nbytes);
+
+               /* Process multi-block batch */
+               if (nbytes >= bsize * CAST5_PARALLEL_BLOCKS) {
+                       do {
+                               if (enc)
+                                       cast5_enc_blk_xway(ctx, wdst, wsrc);
+                               else
+                                       cast5_dec_blk_xway(ctx, wdst, wsrc);
+
+                               wsrc += bsize * CAST5_PARALLEL_BLOCKS;
+                               wdst += bsize * CAST5_PARALLEL_BLOCKS;
+                               nbytes -= bsize * CAST5_PARALLEL_BLOCKS;
+                       } while (nbytes >= bsize * CAST5_PARALLEL_BLOCKS);
+
+                       if (nbytes < bsize)
+                               goto done;
+               }
+
+               /* Handle leftovers */
+               do {
+                       if (enc)
+                               __cast5_encrypt(ctx, wdst, wsrc);
+                       else
+                               __cast5_decrypt(ctx, wdst, wsrc);
+
+                       wsrc += bsize;
+                       wdst += bsize;
+                       nbytes -= bsize;
+               } while (nbytes >= bsize);
+
+done:
+               err = blkcipher_walk_done(desc, walk, nbytes);
+       }
+
+       cast5_fpu_end(fpu_enabled);
+       return err;
+}
+
+static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct blkcipher_walk walk;
+
+       blkcipher_walk_init(&walk, dst, src, nbytes);
+       return ecb_crypt(desc, &walk, true);
+}
+
+static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct blkcipher_walk walk;
+
+       blkcipher_walk_init(&walk, dst, src, nbytes);
+       return ecb_crypt(desc, &walk, false);
+}
+
+static unsigned int __cbc_encrypt(struct blkcipher_desc *desc,
+                                 struct blkcipher_walk *walk)
+{
+       struct cast5_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       const unsigned int bsize = CAST5_BLOCK_SIZE;
+       unsigned int nbytes = walk->nbytes;
+       u64 *src = (u64 *)walk->src.virt.addr;
+       u64 *dst = (u64 *)walk->dst.virt.addr;
+       u64 *iv = (u64 *)walk->iv;
+
+       do {
+               *dst = *src ^ *iv;
+               __cast5_encrypt(ctx, (u8 *)dst, (u8 *)dst);
+               iv = dst;
+
+               src += 1;
+               dst += 1;
+               nbytes -= bsize;
+       } while (nbytes >= bsize);
+
+       *(u64 *)walk->iv ^= *iv;
+       return nbytes;
+}
+
+static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct blkcipher_walk walk;
+       int err;
+
+       blkcipher_walk_init(&walk, dst, src, nbytes);
+       err = blkcipher_walk_virt(desc, &walk);
+
+       while ((nbytes = walk.nbytes)) {
+               nbytes = __cbc_encrypt(desc, &walk);
+               err = blkcipher_walk_done(desc, &walk, nbytes);
+       }
+
+       return err;
+}
+
+static unsigned int __cbc_decrypt(struct blkcipher_desc *desc,
+                                 struct blkcipher_walk *walk)
+{
+       struct cast5_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       const unsigned int bsize = CAST5_BLOCK_SIZE;
+       unsigned int nbytes = walk->nbytes;
+       u64 *src = (u64 *)walk->src.virt.addr;
+       u64 *dst = (u64 *)walk->dst.virt.addr;
+       u64 ivs[CAST5_PARALLEL_BLOCKS - 1];
+       u64 last_iv;
+       int i;
+
+       /* Start of the last block. */
+       src += nbytes / bsize - 1;
+       dst += nbytes / bsize - 1;
+
+       last_iv = *src;
+
+       /* Process multi-block batch */
+       if (nbytes >= bsize * CAST5_PARALLEL_BLOCKS) {
+               do {
+                       nbytes -= bsize * (CAST5_PARALLEL_BLOCKS - 1);
+                       src -= CAST5_PARALLEL_BLOCKS - 1;
+                       dst -= CAST5_PARALLEL_BLOCKS - 1;
+
+                       for (i = 0; i < CAST5_PARALLEL_BLOCKS - 1; i++)
+                               ivs[i] = src[i];
+
+                       cast5_dec_blk_xway(ctx, (u8 *)dst, (u8 *)src);
+
+                       for (i = 0; i < CAST5_PARALLEL_BLOCKS - 1; i++)
+                               *(dst + (i + 1)) ^= *(ivs + i);
+
+                       nbytes -= bsize;
+                       if (nbytes < bsize)
+                               goto done;
+
+                       *dst ^= *(src - 1);
+                       src -= 1;
+                       dst -= 1;
+               } while (nbytes >= bsize * CAST5_PARALLEL_BLOCKS);
+
+               if (nbytes < bsize)
+                       goto done;
+       }
+
+       /* Handle leftovers */
+       for (;;) {
+               __cast5_decrypt(ctx, (u8 *)dst, (u8 *)src);
+
+               nbytes -= bsize;
+               if (nbytes < bsize)
+                       break;
+
+               *dst ^= *(src - 1);
+               src -= 1;
+               dst -= 1;
+       }
+
+done:
+       *dst ^= *(u64 *)walk->iv;
+       *(u64 *)walk->iv = last_iv;
+
+       return nbytes;
+}
+
+static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       bool fpu_enabled = false;
+       struct blkcipher_walk walk;
+       int err;
+
+       blkcipher_walk_init(&walk, dst, src, nbytes);
+       err = blkcipher_walk_virt(desc, &walk);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       while ((nbytes = walk.nbytes)) {
+               fpu_enabled = cast5_fpu_begin(fpu_enabled, nbytes);
+               nbytes = __cbc_decrypt(desc, &walk);
+               err = blkcipher_walk_done(desc, &walk, nbytes);
+       }
+
+       cast5_fpu_end(fpu_enabled);
+       return err;
+}
+
+static void ctr_crypt_final(struct blkcipher_desc *desc,
+                           struct blkcipher_walk *walk)
+{
+       struct cast5_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       u8 *ctrblk = walk->iv;
+       u8 keystream[CAST5_BLOCK_SIZE];
+       u8 *src = walk->src.virt.addr;
+       u8 *dst = walk->dst.virt.addr;
+       unsigned int nbytes = walk->nbytes;
+
+       __cast5_encrypt(ctx, keystream, ctrblk);
+       crypto_xor(keystream, src, nbytes);
+       memcpy(dst, keystream, nbytes);
+
+       crypto_inc(ctrblk, CAST5_BLOCK_SIZE);
+}
+
+static unsigned int __ctr_crypt(struct blkcipher_desc *desc,
+                               struct blkcipher_walk *walk)
+{
+       struct cast5_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       const unsigned int bsize = CAST5_BLOCK_SIZE;
+       unsigned int nbytes = walk->nbytes;
+       u64 *src = (u64 *)walk->src.virt.addr;
+       u64 *dst = (u64 *)walk->dst.virt.addr;
+       u64 ctrblk = be64_to_cpu(*(__be64 *)walk->iv);
+       __be64 ctrblocks[CAST5_PARALLEL_BLOCKS];
+       int i;
+
+       /* Process multi-block batch */
+       if (nbytes >= bsize * CAST5_PARALLEL_BLOCKS) {
+               do {
+                       /* create ctrblks for parallel encrypt */
+                       for (i = 0; i < CAST5_PARALLEL_BLOCKS; i++) {
+                               if (dst != src)
+                                       dst[i] = src[i];
+
+                               ctrblocks[i] = cpu_to_be64(ctrblk++);
+                       }
+
+                       cast5_enc_blk_xway_xor(ctx, (u8 *)dst,
+                                              (u8 *)ctrblocks);
+
+                       src += CAST5_PARALLEL_BLOCKS;
+                       dst += CAST5_PARALLEL_BLOCKS;
+                       nbytes -= bsize * CAST5_PARALLEL_BLOCKS;
+               } while (nbytes >= bsize * CAST5_PARALLEL_BLOCKS);
+
+               if (nbytes < bsize)
+                       goto done;
+       }
+
+       /* Handle leftovers */
+       do {
+               if (dst != src)
+                       *dst = *src;
+
+               ctrblocks[0] = cpu_to_be64(ctrblk++);
+
+               __cast5_encrypt(ctx, (u8 *)ctrblocks, (u8 *)ctrblocks);
+               *dst ^= ctrblocks[0];
+
+               src += 1;
+               dst += 1;
+               nbytes -= bsize;
+       } while (nbytes >= bsize);
+
+done:
+       *(__be64 *)walk->iv = cpu_to_be64(ctrblk);
+       return nbytes;
+}
+
+static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                    struct scatterlist *src, unsigned int nbytes)
+{
+       bool fpu_enabled = false;
+       struct blkcipher_walk walk;
+       int err;
+
+       blkcipher_walk_init(&walk, dst, src, nbytes);
+       err = blkcipher_walk_virt_block(desc, &walk, CAST5_BLOCK_SIZE);
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+
+       while ((nbytes = walk.nbytes) >= CAST5_BLOCK_SIZE) {
+               fpu_enabled = cast5_fpu_begin(fpu_enabled, nbytes);
+               nbytes = __ctr_crypt(desc, &walk);
+               err = blkcipher_walk_done(desc, &walk, nbytes);
+       }
+
+       cast5_fpu_end(fpu_enabled);
+
+       if (walk.nbytes) {
+               ctr_crypt_final(desc, &walk);
+               err = blkcipher_walk_done(desc, &walk, 0);
+       }
+
+       return err;
+}
+
+
+static struct crypto_alg cast5_algs[6] = { {
+       .cra_name               = "__ecb-cast5-avx",
+       .cra_driver_name        = "__driver-ecb-cast5-avx",
+       .cra_priority           = 0,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = CAST5_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct cast5_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = CAST5_MIN_KEY_SIZE,
+                       .max_keysize    = CAST5_MAX_KEY_SIZE,
+                       .setkey         = cast5_setkey,
+                       .encrypt        = ecb_encrypt,
+                       .decrypt        = ecb_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "__cbc-cast5-avx",
+       .cra_driver_name        = "__driver-cbc-cast5-avx",
+       .cra_priority           = 0,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = CAST5_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct cast5_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = CAST5_MIN_KEY_SIZE,
+                       .max_keysize    = CAST5_MAX_KEY_SIZE,
+                       .setkey         = cast5_setkey,
+                       .encrypt        = cbc_encrypt,
+                       .decrypt        = cbc_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "__ctr-cast5-avx",
+       .cra_driver_name        = "__driver-ctr-cast5-avx",
+       .cra_priority           = 0,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = 1,
+       .cra_ctxsize            = sizeof(struct cast5_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = CAST5_MIN_KEY_SIZE,
+                       .max_keysize    = CAST5_MAX_KEY_SIZE,
+                       .ivsize         = CAST5_BLOCK_SIZE,
+                       .setkey         = cast5_setkey,
+                       .encrypt        = ctr_crypt,
+                       .decrypt        = ctr_crypt,
+               },
+       },
+}, {
+       .cra_name               = "ecb(cast5)",
+       .cra_driver_name        = "ecb-cast5-avx",
+       .cra_priority           = 200,
+       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+       .cra_blocksize          = CAST5_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct async_helper_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_ablkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_init               = ablk_init,
+       .cra_exit               = ablk_exit,
+       .cra_u = {
+               .ablkcipher = {
+                       .min_keysize    = CAST5_MIN_KEY_SIZE,
+                       .max_keysize    = CAST5_MAX_KEY_SIZE,
+                       .setkey         = ablk_set_key,
+                       .encrypt        = ablk_encrypt,
+                       .decrypt        = ablk_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "cbc(cast5)",
+       .cra_driver_name        = "cbc-cast5-avx",
+       .cra_priority           = 200,
+       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+       .cra_blocksize          = CAST5_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct async_helper_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_ablkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_init               = ablk_init,
+       .cra_exit               = ablk_exit,
+       .cra_u = {
+               .ablkcipher = {
+                       .min_keysize    = CAST5_MIN_KEY_SIZE,
+                       .max_keysize    = CAST5_MAX_KEY_SIZE,
+                       .ivsize         = CAST5_BLOCK_SIZE,
+                       .setkey         = ablk_set_key,
+                       .encrypt        = __ablk_encrypt,
+                       .decrypt        = ablk_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "ctr(cast5)",
+       .cra_driver_name        = "ctr-cast5-avx",
+       .cra_priority           = 200,
+       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+       .cra_blocksize          = 1,
+       .cra_ctxsize            = sizeof(struct async_helper_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_ablkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_init               = ablk_init,
+       .cra_exit               = ablk_exit,
+       .cra_u = {
+               .ablkcipher = {
+                       .min_keysize    = CAST5_MIN_KEY_SIZE,
+                       .max_keysize    = CAST5_MAX_KEY_SIZE,
+                       .ivsize         = CAST5_BLOCK_SIZE,
+                       .setkey         = ablk_set_key,
+                       .encrypt        = ablk_encrypt,
+                       .decrypt        = ablk_encrypt,
+                       .geniv          = "chainiv",
+               },
+       },
+} };
+
+static int __init cast5_init(void)
+{
+       u64 xcr0;
+
+       if (!cpu_has_avx || !cpu_has_osxsave) {
+               pr_info("AVX instructions are not detected.\n");
+               return -ENODEV;
+       }
+
+       xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK);
+       if ((xcr0 & (XSTATE_SSE | XSTATE_YMM)) != (XSTATE_SSE | XSTATE_YMM)) {
+               pr_info("AVX detected but unusable.\n");
+               return -ENODEV;
+       }
+
+       return crypto_register_algs(cast5_algs, ARRAY_SIZE(cast5_algs));
+}
+
+static void __exit cast5_exit(void)
+{
+       crypto_unregister_algs(cast5_algs, ARRAY_SIZE(cast5_algs));
+}
+
+module_init(cast5_init);
+module_exit(cast5_exit);
+
+MODULE_DESCRIPTION("Cast5 Cipher Algorithm, AVX optimized");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("cast5");
diff --git a/arch/x86/crypto/cast6-avx-x86_64-asm_64.S b/arch/x86/crypto/cast6-avx-x86_64-asm_64.S
new file mode 100644 (file)
index 0000000..d258ce0
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ * Cast6 Cipher 8-way parallel algorithm (AVX/x86_64)
+ *
+ * Copyright (C) 2012 Johannes Goetzfried
+ *     <Johannes.Goetzfried@informatik.stud.uni-erlangen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ * USA
+ *
+ */
+
+.file "cast6-avx-x86_64-asm_64.S"
+.text
+
+.extern cast6_s1
+.extern cast6_s2
+.extern cast6_s3
+.extern cast6_s4
+
+/* structure of crypto context */
+#define km     0
+#define kr     (12*4*4)
+
+/* s-boxes */
+#define s1     cast6_s1
+#define s2     cast6_s2
+#define s3     cast6_s3
+#define s4     cast6_s4
+
+/**********************************************************************
+  8-way AVX cast6
+ **********************************************************************/
+#define CTX %rdi
+
+#define RA1 %xmm0
+#define RB1 %xmm1
+#define RC1 %xmm2
+#define RD1 %xmm3
+
+#define RA2 %xmm4
+#define RB2 %xmm5
+#define RC2 %xmm6
+#define RD2 %xmm7
+
+#define RX %xmm8
+
+#define RKM  %xmm9
+#define RKRF %xmm10
+#define RKRR %xmm11
+
+#define RTMP  %xmm12
+#define RMASK %xmm13
+#define R32   %xmm14
+
+#define RID1  %rax
+#define RID1b %al
+#define RID2  %rbx
+#define RID2b %bl
+
+#define RGI1   %rdx
+#define RGI1bl %dl
+#define RGI1bh %dh
+#define RGI2   %rcx
+#define RGI2bl %cl
+#define RGI2bh %ch
+
+#define RFS1  %r8
+#define RFS1d %r8d
+#define RFS2  %r9
+#define RFS2d %r9d
+#define RFS3  %r10
+#define RFS3d %r10d
+
+
+#define lookup_32bit(src, dst, op1, op2, op3) \
+       movb            src ## bl,     RID1b;    \
+       movb            src ## bh,     RID2b;    \
+       movl            s1(, RID1, 4), dst ## d; \
+       op1             s2(, RID2, 4), dst ## d; \
+       shrq $16,       src;                     \
+       movb            src ## bl,     RID1b;    \
+       movb            src ## bh,     RID2b;    \
+       op2             s3(, RID1, 4), dst ## d; \
+       op3             s4(, RID2, 4), dst ## d;
+
+#define F(a, x, op0, op1, op2, op3) \
+       op0     a,      RKM,  x;                 \
+       vpslld  RKRF,   x,    RTMP;              \
+       vpsrld  RKRR,   x,    x;                 \
+       vpor    RTMP,   x,    x;                 \
+       \
+       vpshufb RMASK,  x,    x;                 \
+       vmovq           x,    RGI1;              \
+       vpsrldq $8,     x,    x;                 \
+       vmovq           x,    RGI2;              \
+       \
+       lookup_32bit(RGI1, RFS1, op1, op2, op3); \
+       shrq $16,       RGI1;                    \
+       lookup_32bit(RGI1, RFS2, op1, op2, op3); \
+       shlq $32,       RFS2;                    \
+       orq             RFS1, RFS2;              \
+       \
+       lookup_32bit(RGI2, RFS1, op1, op2, op3); \
+       shrq $16,       RGI2;                    \
+       lookup_32bit(RGI2, RFS3, op1, op2, op3); \
+       shlq $32,       RFS3;                    \
+       orq             RFS1, RFS3;              \
+       \
+       vmovq           RFS2, x;                 \
+       vpinsrq $1,     RFS3, x, x;
+
+#define F1(b, x) F(b, x, vpaddd, xorl, subl, addl)
+#define F2(b, x) F(b, x, vpxor,  subl, addl, xorl)
+#define F3(b, x) F(b, x, vpsubd, addl, xorl, subl)
+
+#define qop(in, out, x, f) \
+       F ## f(in ## 1, x);          \
+       vpxor out ## 1, x, out ## 1; \
+       F ## f(in ## 2, x);          \
+       vpxor out ## 2, x, out ## 2; \
+
+#define Q(n) \
+       vbroadcastss    (km+(4*(4*n+0)))(CTX), RKM;        \
+       vpinsrb $0,     (kr+(4*n+0))(CTX),     RKRF, RKRF; \
+       vpsubq          RKRF,                  R32,  RKRR; \
+       qop(RD, RC, RX, 1);                                \
+       \
+       vbroadcastss    (km+(4*(4*n+1)))(CTX), RKM;        \
+       vpinsrb $0,     (kr+(4*n+1))(CTX),     RKRF, RKRF; \
+       vpsubq          RKRF,                  R32,  RKRR; \
+       qop(RC, RB, RX, 2);                                \
+       \
+       vbroadcastss    (km+(4*(4*n+2)))(CTX), RKM;        \
+       vpinsrb $0,     (kr+(4*n+2))(CTX),     RKRF, RKRF; \
+       vpsubq          RKRF,                  R32,  RKRR; \
+       qop(RB, RA, RX, 3);                                \
+       \
+       vbroadcastss    (km+(4*(4*n+3)))(CTX), RKM;        \
+       vpinsrb $0,     (kr+(4*n+3))(CTX),     RKRF, RKRF; \
+       vpsubq          RKRF,                  R32,  RKRR; \
+       qop(RA, RD, RX, 1);
+
+#define QBAR(n) \
+       vbroadcastss    (km+(4*(4*n+3)))(CTX), RKM;        \
+       vpinsrb $0,     (kr+(4*n+3))(CTX),     RKRF, RKRF; \
+       vpsubq          RKRF,                  R32,  RKRR; \
+       qop(RA, RD, RX, 1);                                \
+       \
+       vbroadcastss    (km+(4*(4*n+2)))(CTX), RKM;        \
+       vpinsrb $0,     (kr+(4*n+2))(CTX),     RKRF, RKRF; \
+       vpsubq          RKRF,                  R32,  RKRR; \
+       qop(RB, RA, RX, 3);                                \
+       \
+       vbroadcastss    (km+(4*(4*n+1)))(CTX), RKM;        \
+       vpinsrb $0,     (kr+(4*n+1))(CTX),     RKRF, RKRF; \
+       vpsubq          RKRF,                  R32,  RKRR; \
+       qop(RC, RB, RX, 2);                                \
+       \
+       vbroadcastss    (km+(4*(4*n+0)))(CTX), RKM;        \
+       vpinsrb $0,     (kr+(4*n+0))(CTX),     RKRF, RKRF; \
+       vpsubq          RKRF,                  R32,  RKRR; \
+       qop(RD, RC, RX, 1);
+
+
+#define transpose_4x4(x0, x1, x2, x3, t0, t1, t2) \
+       vpunpckldq              x1, x0, t0; \
+       vpunpckhdq              x1, x0, t2; \
+       vpunpckldq              x3, x2, t1; \
+       vpunpckhdq              x3, x2, x3; \
+       \
+       vpunpcklqdq             t1, t0, x0; \
+       vpunpckhqdq             t1, t0, x1; \
+       vpunpcklqdq             x3, t2, x2; \
+       vpunpckhqdq             x3, t2, x3;
+
+#define inpack_blocks(in, x0, x1, x2, x3, t0, t1, t2) \
+       vmovdqu (0*4*4)(in),    x0; \
+       vmovdqu (1*4*4)(in),    x1; \
+       vmovdqu (2*4*4)(in),    x2; \
+       vmovdqu (3*4*4)(in),    x3; \
+       vpshufb RMASK, x0,      x0; \
+       vpshufb RMASK, x1,      x1; \
+       vpshufb RMASK, x2,      x2; \
+       vpshufb RMASK, x3,      x3; \
+       \
+       transpose_4x4(x0, x1, x2, x3, t0, t1, t2)
+
+#define outunpack_blocks(out, x0, x1, x2, x3, t0, t1, t2) \
+       transpose_4x4(x0, x1, x2, x3, t0, t1, t2) \
+       \
+       vpshufb RMASK,          x0, x0;       \
+       vpshufb RMASK,          x1, x1;       \
+       vpshufb RMASK,          x2, x2;       \
+       vpshufb RMASK,          x3, x3;       \
+       vmovdqu x0,             (0*4*4)(out); \
+       vmovdqu x1,             (1*4*4)(out); \
+       vmovdqu x2,             (2*4*4)(out); \
+       vmovdqu x3,             (3*4*4)(out);
+
+#define outunpack_xor_blocks(out, x0, x1, x2, x3, t0, t1, t2) \
+       transpose_4x4(x0, x1, x2, x3, t0, t1, t2) \
+       \
+       vpshufb RMASK,          x0, x0;       \
+       vpshufb RMASK,          x1, x1;       \
+       vpshufb RMASK,          x2, x2;       \
+       vpshufb RMASK,          x3, x3;       \
+       vpxor (0*4*4)(out),     x0, x0;       \
+       vmovdqu x0,             (0*4*4)(out); \
+       vpxor (1*4*4)(out),     x1, x1;       \
+       vmovdqu x1,             (1*4*4)(out); \
+       vpxor (2*4*4)(out),     x2, x2;       \
+       vmovdqu x2,             (2*4*4)(out); \
+       vpxor (3*4*4)(out),     x3, x3;       \
+       vmovdqu x3,             (3*4*4)(out);
+
+.align 16
+.Lbswap_mask:
+       .byte 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12
+.L32_mask:
+       .byte 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0
+
+.align 16
+.global __cast6_enc_blk_8way
+.type   __cast6_enc_blk_8way,@function;
+
+__cast6_enc_blk_8way:
+       /* input:
+        *      %rdi: ctx, CTX
+        *      %rsi: dst
+        *      %rdx: src
+        *      %rcx: bool, if true: xor output
+        */
+
+       pushq %rbx;
+       pushq %rcx;
+
+       vmovdqu .Lbswap_mask, RMASK;
+       vmovdqu .L32_mask, R32;
+       vpxor RKRF, RKRF, RKRF;
+
+       leaq (4*4*4)(%rdx), %rax;
+       inpack_blocks(%rdx, RA1, RB1, RC1, RD1, RTMP, RX, RKM);
+       inpack_blocks(%rax, RA2, RB2, RC2, RD2, RTMP, RX, RKM);
+
+       xorq RID1, RID1;
+       xorq RID2, RID2;
+
+       Q(0);
+       Q(1);
+       Q(2);
+       Q(3);
+       Q(4);
+       Q(5);
+       QBAR(6);
+       QBAR(7);
+       QBAR(8);
+       QBAR(9);
+       QBAR(10);
+       QBAR(11);
+
+       popq %rcx;
+       popq %rbx;
+
+       leaq (4*4*4)(%rsi), %rax;
+
+       testb %cl, %cl;
+       jnz __enc_xor8;
+
+       outunpack_blocks(%rsi, RA1, RB1, RC1, RD1, RTMP, RX, RKM);
+       outunpack_blocks(%rax, RA2, RB2, RC2, RD2, RTMP, RX, RKM);
+
+       ret;
+
+__enc_xor8:
+       outunpack_xor_blocks(%rsi, RA1, RB1, RC1, RD1, RTMP, RX, RKM);
+       outunpack_xor_blocks(%rax, RA2, RB2, RC2, RD2, RTMP, RX, RKM);
+
+       ret;
+
+.align 16
+.global cast6_dec_blk_8way
+.type   cast6_dec_blk_8way,@function;
+
+cast6_dec_blk_8way:
+       /* input:
+        *      %rdi: ctx, CTX
+        *      %rsi: dst
+        *      %rdx: src
+        */
+
+       pushq %rbx;
+
+       vmovdqu .Lbswap_mask, RMASK;
+       vmovdqu .L32_mask, R32;
+       vpxor RKRF, RKRF, RKRF;
+
+       leaq (4*4*4)(%rdx), %rax;
+       inpack_blocks(%rdx, RA1, RB1, RC1, RD1, RTMP, RX, RKM);
+       inpack_blocks(%rax, RA2, RB2, RC2, RD2, RTMP, RX, RKM);
+
+       xorq RID1, RID1;
+       xorq RID2, RID2;
+
+       Q(11);
+       Q(10);
+       Q(9);
+       Q(8);
+       Q(7);
+       Q(6);
+       QBAR(5);
+       QBAR(4);
+       QBAR(3);
+       QBAR(2);
+       QBAR(1);
+       QBAR(0);
+
+       popq %rbx;
+
+       leaq (4*4*4)(%rsi), %rax;
+       outunpack_blocks(%rsi, RA1, RB1, RC1, RD1, RTMP, RX, RKM);
+       outunpack_blocks(%rax, RA2, RB2, RC2, RD2, RTMP, RX, RKM);
+
+       ret;
diff --git a/arch/x86/crypto/cast6_avx_glue.c b/arch/x86/crypto/cast6_avx_glue.c
new file mode 100644 (file)
index 0000000..15e5f85
--- /dev/null
@@ -0,0 +1,648 @@
+/*
+ * Glue Code for the AVX assembler implemention of the Cast6 Cipher
+ *
+ * Copyright (C) 2012 Johannes Goetzfried
+ *     <Johannes.Goetzfried@informatik.stud.uni-erlangen.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ * USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/hardirq.h>
+#include <linux/types.h>
+#include <linux/crypto.h>
+#include <linux/err.h>
+#include <crypto/algapi.h>
+#include <crypto/cast6.h>
+#include <crypto/cryptd.h>
+#include <crypto/b128ops.h>
+#include <crypto/ctr.h>
+#include <crypto/lrw.h>
+#include <crypto/xts.h>
+#include <asm/xcr.h>
+#include <asm/xsave.h>
+#include <asm/crypto/ablk_helper.h>
+#include <asm/crypto/glue_helper.h>
+
+#define CAST6_PARALLEL_BLOCKS 8
+
+asmlinkage void __cast6_enc_blk_8way(struct cast6_ctx *ctx, u8 *dst,
+                                    const u8 *src, bool xor);
+asmlinkage void cast6_dec_blk_8way(struct cast6_ctx *ctx, u8 *dst,
+                                  const u8 *src);
+
+static inline void cast6_enc_blk_xway(struct cast6_ctx *ctx, u8 *dst,
+                                     const u8 *src)
+{
+       __cast6_enc_blk_8way(ctx, dst, src, false);
+}
+
+static inline void cast6_enc_blk_xway_xor(struct cast6_ctx *ctx, u8 *dst,
+                                         const u8 *src)
+{
+       __cast6_enc_blk_8way(ctx, dst, src, true);
+}
+
+static inline void cast6_dec_blk_xway(struct cast6_ctx *ctx, u8 *dst,
+                                     const u8 *src)
+{
+       cast6_dec_blk_8way(ctx, dst, src);
+}
+
+
+static void cast6_decrypt_cbc_xway(void *ctx, u128 *dst, const u128 *src)
+{
+       u128 ivs[CAST6_PARALLEL_BLOCKS - 1];
+       unsigned int j;
+
+       for (j = 0; j < CAST6_PARALLEL_BLOCKS - 1; j++)
+               ivs[j] = src[j];
+
+       cast6_dec_blk_xway(ctx, (u8 *)dst, (u8 *)src);
+
+       for (j = 0; j < CAST6_PARALLEL_BLOCKS - 1; j++)
+               u128_xor(dst + (j + 1), dst + (j + 1), ivs + j);
+}
+
+static void cast6_crypt_ctr(void *ctx, u128 *dst, const u128 *src, u128 *iv)
+{
+       be128 ctrblk;
+
+       u128_to_be128(&ctrblk, iv);
+       u128_inc(iv);
+
+       __cast6_encrypt(ctx, (u8 *)&ctrblk, (u8 *)&ctrblk);
+       u128_xor(dst, src, (u128 *)&ctrblk);
+}
+
+static void cast6_crypt_ctr_xway(void *ctx, u128 *dst, const u128 *src,
+                                  u128 *iv)
+{
+       be128 ctrblks[CAST6_PARALLEL_BLOCKS];
+       unsigned int i;
+
+       for (i = 0; i < CAST6_PARALLEL_BLOCKS; i++) {
+               if (dst != src)
+                       dst[i] = src[i];
+
+               u128_to_be128(&ctrblks[i], iv);
+               u128_inc(iv);
+       }
+
+       cast6_enc_blk_xway_xor(ctx, (u8 *)dst, (u8 *)ctrblks);
+}
+
+static const struct common_glue_ctx cast6_enc = {
+       .num_funcs = 2,
+       .fpu_blocks_limit = CAST6_PARALLEL_BLOCKS,
+
+       .funcs = { {
+               .num_blocks = CAST6_PARALLEL_BLOCKS,
+               .fn_u = { .ecb = GLUE_FUNC_CAST(cast6_enc_blk_xway) }
+       }, {
+               .num_blocks = 1,
+               .fn_u = { .ecb = GLUE_FUNC_CAST(__cast6_encrypt) }
+       } }
+};
+
+static const struct common_glue_ctx cast6_ctr = {
+       .num_funcs = 2,
+       .fpu_blocks_limit = CAST6_PARALLEL_BLOCKS,
+
+       .funcs = { {
+               .num_blocks = CAST6_PARALLEL_BLOCKS,
+               .fn_u = { .ctr = GLUE_CTR_FUNC_CAST(cast6_crypt_ctr_xway) }
+       }, {
+               .num_blocks = 1,
+               .fn_u = { .ctr = GLUE_CTR_FUNC_CAST(cast6_crypt_ctr) }
+       } }
+};
+
+static const struct common_glue_ctx cast6_dec = {
+       .num_funcs = 2,
+       .fpu_blocks_limit = CAST6_PARALLEL_BLOCKS,
+
+       .funcs = { {
+               .num_blocks = CAST6_PARALLEL_BLOCKS,
+               .fn_u = { .ecb = GLUE_FUNC_CAST(cast6_dec_blk_xway) }
+       }, {
+               .num_blocks = 1,
+               .fn_u = { .ecb = GLUE_FUNC_CAST(__cast6_decrypt) }
+       } }
+};
+
+static const struct common_glue_ctx cast6_dec_cbc = {
+       .num_funcs = 2,
+       .fpu_blocks_limit = CAST6_PARALLEL_BLOCKS,
+
+       .funcs = { {
+               .num_blocks = CAST6_PARALLEL_BLOCKS,
+               .fn_u = { .cbc = GLUE_CBC_FUNC_CAST(cast6_decrypt_cbc_xway) }
+       }, {
+               .num_blocks = 1,
+               .fn_u = { .cbc = GLUE_CBC_FUNC_CAST(__cast6_decrypt) }
+       } }
+};
+
+static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       return glue_ecb_crypt_128bit(&cast6_enc, desc, dst, src, nbytes);
+}
+
+static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       return glue_ecb_crypt_128bit(&cast6_dec, desc, dst, src, nbytes);
+}
+
+static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       return glue_cbc_encrypt_128bit(GLUE_FUNC_CAST(__cast6_encrypt), desc,
+                                      dst, src, nbytes);
+}
+
+static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       return glue_cbc_decrypt_128bit(&cast6_dec_cbc, desc, dst, src,
+                                      nbytes);
+}
+
+static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                    struct scatterlist *src, unsigned int nbytes)
+{
+       return glue_ctr_crypt_128bit(&cast6_ctr, desc, dst, src, nbytes);
+}
+
+static inline bool cast6_fpu_begin(bool fpu_enabled, unsigned int nbytes)
+{
+       return glue_fpu_begin(CAST6_BLOCK_SIZE, CAST6_PARALLEL_BLOCKS,
+                             NULL, fpu_enabled, nbytes);
+}
+
+static inline void cast6_fpu_end(bool fpu_enabled)
+{
+       glue_fpu_end(fpu_enabled);
+}
+
+struct crypt_priv {
+       struct cast6_ctx *ctx;
+       bool fpu_enabled;
+};
+
+static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
+{
+       const unsigned int bsize = CAST6_BLOCK_SIZE;
+       struct crypt_priv *ctx = priv;
+       int i;
+
+       ctx->fpu_enabled = cast6_fpu_begin(ctx->fpu_enabled, nbytes);
+
+       if (nbytes == bsize * CAST6_PARALLEL_BLOCKS) {
+               cast6_enc_blk_xway(ctx->ctx, srcdst, srcdst);
+               return;
+       }
+
+       for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
+               __cast6_encrypt(ctx->ctx, srcdst, srcdst);
+}
+
+static void decrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
+{
+       const unsigned int bsize = CAST6_BLOCK_SIZE;
+       struct crypt_priv *ctx = priv;
+       int i;
+
+       ctx->fpu_enabled = cast6_fpu_begin(ctx->fpu_enabled, nbytes);
+
+       if (nbytes == bsize * CAST6_PARALLEL_BLOCKS) {
+               cast6_dec_blk_xway(ctx->ctx, srcdst, srcdst);
+               return;
+       }
+
+       for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
+               __cast6_decrypt(ctx->ctx, srcdst, srcdst);
+}
+
+struct cast6_lrw_ctx {
+       struct lrw_table_ctx lrw_table;
+       struct cast6_ctx cast6_ctx;
+};
+
+static int lrw_cast6_setkey(struct crypto_tfm *tfm, const u8 *key,
+                             unsigned int keylen)
+{
+       struct cast6_lrw_ctx *ctx = crypto_tfm_ctx(tfm);
+       int err;
+
+       err = __cast6_setkey(&ctx->cast6_ctx, key, keylen - CAST6_BLOCK_SIZE,
+                            &tfm->crt_flags);
+       if (err)
+               return err;
+
+       return lrw_init_table(&ctx->lrw_table, key + keylen - CAST6_BLOCK_SIZE);
+}
+
+static int lrw_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct cast6_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       be128 buf[CAST6_PARALLEL_BLOCKS];
+       struct crypt_priv crypt_ctx = {
+               .ctx = &ctx->cast6_ctx,
+               .fpu_enabled = false,
+       };
+       struct lrw_crypt_req req = {
+               .tbuf = buf,
+               .tbuflen = sizeof(buf),
+
+               .table_ctx = &ctx->lrw_table,
+               .crypt_ctx = &crypt_ctx,
+               .crypt_fn = encrypt_callback,
+       };
+       int ret;
+
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+       ret = lrw_crypt(desc, dst, src, nbytes, &req);
+       cast6_fpu_end(crypt_ctx.fpu_enabled);
+
+       return ret;
+}
+
+static int lrw_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct cast6_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       be128 buf[CAST6_PARALLEL_BLOCKS];
+       struct crypt_priv crypt_ctx = {
+               .ctx = &ctx->cast6_ctx,
+               .fpu_enabled = false,
+       };
+       struct lrw_crypt_req req = {
+               .tbuf = buf,
+               .tbuflen = sizeof(buf),
+
+               .table_ctx = &ctx->lrw_table,
+               .crypt_ctx = &crypt_ctx,
+               .crypt_fn = decrypt_callback,
+       };
+       int ret;
+
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+       ret = lrw_crypt(desc, dst, src, nbytes, &req);
+       cast6_fpu_end(crypt_ctx.fpu_enabled);
+
+       return ret;
+}
+
+static void lrw_exit_tfm(struct crypto_tfm *tfm)
+{
+       struct cast6_lrw_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       lrw_free_table(&ctx->lrw_table);
+}
+
+struct cast6_xts_ctx {
+       struct cast6_ctx tweak_ctx;
+       struct cast6_ctx crypt_ctx;
+};
+
+static int xts_cast6_setkey(struct crypto_tfm *tfm, const u8 *key,
+                             unsigned int keylen)
+{
+       struct cast6_xts_ctx *ctx = crypto_tfm_ctx(tfm);
+       u32 *flags = &tfm->crt_flags;
+       int err;
+
+       /* key consists of keys of equal size concatenated, therefore
+        * the length must be even
+        */
+       if (keylen % 2) {
+               *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+               return -EINVAL;
+       }
+
+       /* first half of xts-key is for crypt */
+       err = __cast6_setkey(&ctx->crypt_ctx, key, keylen / 2, flags);
+       if (err)
+               return err;
+
+       /* second half of xts-key is for tweak */
+       return __cast6_setkey(&ctx->tweak_ctx, key + keylen / 2, keylen / 2,
+                             flags);
+}
+
+static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct cast6_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       be128 buf[CAST6_PARALLEL_BLOCKS];
+       struct crypt_priv crypt_ctx = {
+               .ctx = &ctx->crypt_ctx,
+               .fpu_enabled = false,
+       };
+       struct xts_crypt_req req = {
+               .tbuf = buf,
+               .tbuflen = sizeof(buf),
+
+               .tweak_ctx = &ctx->tweak_ctx,
+               .tweak_fn = XTS_TWEAK_CAST(__cast6_encrypt),
+               .crypt_ctx = &crypt_ctx,
+               .crypt_fn = encrypt_callback,
+       };
+       int ret;
+
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+       ret = xts_crypt(desc, dst, src, nbytes, &req);
+       cast6_fpu_end(crypt_ctx.fpu_enabled);
+
+       return ret;
+}
+
+static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
+                      struct scatterlist *src, unsigned int nbytes)
+{
+       struct cast6_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
+       be128 buf[CAST6_PARALLEL_BLOCKS];
+       struct crypt_priv crypt_ctx = {
+               .ctx = &ctx->crypt_ctx,
+               .fpu_enabled = false,
+       };
+       struct xts_crypt_req req = {
+               .tbuf = buf,
+               .tbuflen = sizeof(buf),
+
+               .tweak_ctx = &ctx->tweak_ctx,
+               .tweak_fn = XTS_TWEAK_CAST(__cast6_encrypt),
+               .crypt_ctx = &crypt_ctx,
+               .crypt_fn = decrypt_callback,
+       };
+       int ret;
+
+       desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
+       ret = xts_crypt(desc, dst, src, nbytes, &req);
+       cast6_fpu_end(crypt_ctx.fpu_enabled);
+
+       return ret;
+}
+
+static struct crypto_alg cast6_algs[10] = { {
+       .cra_name               = "__ecb-cast6-avx",
+       .cra_driver_name        = "__driver-ecb-cast6-avx",
+       .cra_priority           = 0,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = CAST6_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct cast6_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = CAST6_MIN_KEY_SIZE,
+                       .max_keysize    = CAST6_MAX_KEY_SIZE,
+                       .setkey         = cast6_setkey,
+                       .encrypt        = ecb_encrypt,
+                       .decrypt        = ecb_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "__cbc-cast6-avx",
+       .cra_driver_name        = "__driver-cbc-cast6-avx",
+       .cra_priority           = 0,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = CAST6_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct cast6_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = CAST6_MIN_KEY_SIZE,
+                       .max_keysize    = CAST6_MAX_KEY_SIZE,
+                       .setkey         = cast6_setkey,
+                       .encrypt        = cbc_encrypt,
+                       .decrypt        = cbc_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "__ctr-cast6-avx",
+       .cra_driver_name        = "__driver-ctr-cast6-avx",
+       .cra_priority           = 0,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = 1,
+       .cra_ctxsize            = sizeof(struct cast6_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = CAST6_MIN_KEY_SIZE,
+                       .max_keysize    = CAST6_MAX_KEY_SIZE,
+                       .ivsize         = CAST6_BLOCK_SIZE,
+                       .setkey         = cast6_setkey,
+                       .encrypt        = ctr_crypt,
+                       .decrypt        = ctr_crypt,
+               },
+       },
+}, {
+       .cra_name               = "__lrw-cast6-avx",
+       .cra_driver_name        = "__driver-lrw-cast6-avx",
+       .cra_priority           = 0,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = CAST6_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct cast6_lrw_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_exit               = lrw_exit_tfm,
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = CAST6_MIN_KEY_SIZE +
+                                         CAST6_BLOCK_SIZE,
+                       .max_keysize    = CAST6_MAX_KEY_SIZE +
+                                         CAST6_BLOCK_SIZE,
+                       .ivsize         = CAST6_BLOCK_SIZE,
+                       .setkey         = lrw_cast6_setkey,
+                       .encrypt        = lrw_encrypt,
+                       .decrypt        = lrw_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "__xts-cast6-avx",
+       .cra_driver_name        = "__driver-xts-cast6-avx",
+       .cra_priority           = 0,
+       .cra_flags              = CRYPTO_ALG_TYPE_BLKCIPHER,
+       .cra_blocksize          = CAST6_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct cast6_xts_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_blkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_u = {
+               .blkcipher = {
+                       .min_keysize    = CAST6_MIN_KEY_SIZE * 2,
+                       .max_keysize    = CAST6_MAX_KEY_SIZE * 2,
+                       .ivsize         = CAST6_BLOCK_SIZE,
+                       .setkey         = xts_cast6_setkey,
+                       .encrypt        = xts_encrypt,
+                       .decrypt        = xts_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "ecb(cast6)",
+       .cra_driver_name        = "ecb-cast6-avx",
+       .cra_priority           = 200,
+       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+       .cra_blocksize          = CAST6_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct async_helper_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_ablkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_init               = ablk_init,
+       .cra_exit               = ablk_exit,
+       .cra_u = {
+               .ablkcipher = {
+                       .min_keysize    = CAST6_MIN_KEY_SIZE,
+                       .max_keysize    = CAST6_MAX_KEY_SIZE,
+                       .setkey         = ablk_set_key,
+                       .encrypt        = ablk_encrypt,
+                       .decrypt        = ablk_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "cbc(cast6)",
+       .cra_driver_name        = "cbc-cast6-avx",
+       .cra_priority           = 200,
+       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+       .cra_blocksize          = CAST6_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct async_helper_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_ablkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_init               = ablk_init,
+       .cra_exit               = ablk_exit,
+       .cra_u = {
+               .ablkcipher = {
+                       .min_keysize    = CAST6_MIN_KEY_SIZE,
+                       .max_keysize    = CAST6_MAX_KEY_SIZE,
+                       .ivsize         = CAST6_BLOCK_SIZE,
+                       .setkey         = ablk_set_key,
+                       .encrypt        = __ablk_encrypt,
+                       .decrypt        = ablk_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "ctr(cast6)",
+       .cra_driver_name        = "ctr-cast6-avx",
+       .cra_priority           = 200,
+       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+       .cra_blocksize          = 1,
+       .cra_ctxsize            = sizeof(struct async_helper_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_ablkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_init               = ablk_init,
+       .cra_exit               = ablk_exit,
+       .cra_u = {
+               .ablkcipher = {
+                       .min_keysize    = CAST6_MIN_KEY_SIZE,
+                       .max_keysize    = CAST6_MAX_KEY_SIZE,
+                       .ivsize         = CAST6_BLOCK_SIZE,
+                       .setkey         = ablk_set_key,
+                       .encrypt        = ablk_encrypt,
+                       .decrypt        = ablk_encrypt,
+                       .geniv          = "chainiv",
+               },
+       },
+}, {
+       .cra_name               = "lrw(cast6)",
+       .cra_driver_name        = "lrw-cast6-avx",
+       .cra_priority           = 200,
+       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+       .cra_blocksize          = CAST6_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct async_helper_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_ablkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_init               = ablk_init,
+       .cra_exit               = ablk_exit,
+       .cra_u = {
+               .ablkcipher = {
+                       .min_keysize    = CAST6_MIN_KEY_SIZE +
+                                         CAST6_BLOCK_SIZE,
+                       .max_keysize    = CAST6_MAX_KEY_SIZE +
+                                         CAST6_BLOCK_SIZE,
+                       .ivsize         = CAST6_BLOCK_SIZE,
+                       .setkey         = ablk_set_key,
+                       .encrypt        = ablk_encrypt,
+                       .decrypt        = ablk_decrypt,
+               },
+       },
+}, {
+       .cra_name               = "xts(cast6)",
+       .cra_driver_name        = "xts-cast6-avx",
+       .cra_priority           = 200,
+       .cra_flags              = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+       .cra_blocksize          = CAST6_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct async_helper_ctx),
+       .cra_alignmask          = 0,
+       .cra_type               = &crypto_ablkcipher_type,
+       .cra_module             = THIS_MODULE,
+       .cra_init               = ablk_init,
+       .cra_exit               = ablk_exit,
+       .cra_u = {
+               .ablkcipher = {
+                       .min_keysize    = CAST6_MIN_KEY_SIZE * 2,
+                       .max_keysize    = CAST6_MAX_KEY_SIZE * 2,
+                       .ivsize         = CAST6_BLOCK_SIZE,
+                       .setkey         = ablk_set_key,
+                       .encrypt        = ablk_encrypt,
+                       .decrypt        = ablk_decrypt,
+               },
+       },
+} };
+
+static int __init cast6_init(void)
+{
+       u64 xcr0;
+
+       if (!cpu_has_avx || !cpu_has_osxsave) {
+               pr_info("AVX instructions are not detected.\n");
+               return -ENODEV;
+       }
+
+       xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK);
+       if ((xcr0 & (XSTATE_SSE | XSTATE_YMM)) != (XSTATE_SSE | XSTATE_YMM)) {
+               pr_info("AVX detected but unusable.\n");
+               return -ENODEV;
+       }
+
+       return crypto_register_algs(cast6_algs, ARRAY_SIZE(cast6_algs));
+}
+
+static void __exit cast6_exit(void)
+{
+       crypto_unregister_algs(cast6_algs, ARRAY_SIZE(cast6_algs));
+}
+
+module_init(cast6_init);
+module_exit(cast6_exit);
+
+MODULE_DESCRIPTION("Cast6 Cipher Algorithm, AVX optimized");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("cast6");
index b4bf0a63b520152f101c72c4369c5b742bad2a68..6759dd1135be4cae1831435fab46cacd277f26df 100644 (file)
@@ -150,7 +150,6 @@ static struct shash_alg ghash_alg = {
                .cra_blocksize          = GHASH_BLOCK_SIZE,
                .cra_ctxsize            = sizeof(struct ghash_ctx),
                .cra_module             = THIS_MODULE,
-               .cra_list               = LIST_HEAD_INIT(ghash_alg.base.cra_list),
        },
 };
 
@@ -288,7 +287,6 @@ static struct ahash_alg ghash_async_alg = {
                        .cra_blocksize          = GHASH_BLOCK_SIZE,
                        .cra_type               = &crypto_ahash_type,
                        .cra_module             = THIS_MODULE,
-                       .cra_list               = LIST_HEAD_INIT(ghash_async_alg.halg.base.cra_list),
                        .cra_init               = ghash_async_init_tfm,
                        .cra_exit               = ghash_async_exit_tfm,
                },
index bccb76d8098782572321d7d12fd35093ac54431e..a3a3c0205c16b4c31d549d3cca9b5d5c3297a0da 100644 (file)
@@ -97,7 +97,6 @@ static struct crypto_alg alg = {
        .cra_ctxsize        =   sizeof(struct salsa20_ctx),
        .cra_alignmask      =   3,
        .cra_module         =   THIS_MODULE,
-       .cra_list           =   LIST_HEAD_INIT(alg.cra_list),
        .cra_u              =   {
                .blkcipher = {
                        .setkey         =   setkey,
index b36bdac237eb0ee736f93ca09b62c14defabde36..3f543a04cf1ee2c697e2b2ea1b427ea7f8631386 100644 (file)
@@ -390,7 +390,6 @@ static struct crypto_alg serpent_algs[10] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_blkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(serpent_algs[0].cra_list),
        .cra_u = {
                .blkcipher = {
                        .min_keysize    = SERPENT_MIN_KEY_SIZE,
@@ -410,7 +409,6 @@ static struct crypto_alg serpent_algs[10] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_blkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(serpent_algs[1].cra_list),
        .cra_u = {
                .blkcipher = {
                        .min_keysize    = SERPENT_MIN_KEY_SIZE,
@@ -430,7 +428,6 @@ static struct crypto_alg serpent_algs[10] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_blkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(serpent_algs[2].cra_list),
        .cra_u = {
                .blkcipher = {
                        .min_keysize    = SERPENT_MIN_KEY_SIZE,
@@ -451,7 +448,6 @@ static struct crypto_alg serpent_algs[10] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_blkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(serpent_algs[3].cra_list),
        .cra_exit               = lrw_exit_tfm,
        .cra_u = {
                .blkcipher = {
@@ -475,7 +471,6 @@ static struct crypto_alg serpent_algs[10] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_blkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(serpent_algs[4].cra_list),
        .cra_u = {
                .blkcipher = {
                        .min_keysize    = SERPENT_MIN_KEY_SIZE * 2,
@@ -496,7 +491,6 @@ static struct crypto_alg serpent_algs[10] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_ablkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(serpent_algs[5].cra_list),
        .cra_init               = ablk_init,
        .cra_exit               = ablk_exit,
        .cra_u = {
@@ -518,7 +512,6 @@ static struct crypto_alg serpent_algs[10] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_ablkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(serpent_algs[6].cra_list),
        .cra_init               = ablk_init,
        .cra_exit               = ablk_exit,
        .cra_u = {
@@ -541,7 +534,6 @@ static struct crypto_alg serpent_algs[10] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_ablkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(serpent_algs[7].cra_list),
        .cra_init               = ablk_init,
        .cra_exit               = ablk_exit,
        .cra_u = {
@@ -565,7 +557,6 @@ static struct crypto_alg serpent_algs[10] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_ablkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(serpent_algs[8].cra_list),
        .cra_init               = ablk_init,
        .cra_exit               = ablk_exit,
        .cra_u = {
@@ -590,7 +581,6 @@ static struct crypto_alg serpent_algs[10] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_ablkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(serpent_algs[9].cra_list),
        .cra_init               = ablk_init,
        .cra_exit               = ablk_exit,
        .cra_u = {
index d679c8675f4ad1994b8e3e71b47fe318c611babe..9107a9908c41ecb4a3e591f0c10380487d5c5b47 100644 (file)
@@ -393,7 +393,6 @@ static struct crypto_alg serpent_algs[10] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_blkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(serpent_algs[0].cra_list),
        .cra_u = {
                .blkcipher = {
                        .min_keysize    = SERPENT_MIN_KEY_SIZE,
@@ -413,7 +412,6 @@ static struct crypto_alg serpent_algs[10] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_blkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(serpent_algs[1].cra_list),
        .cra_u = {
                .blkcipher = {
                        .min_keysize    = SERPENT_MIN_KEY_SIZE,
@@ -433,7 +431,6 @@ static struct crypto_alg serpent_algs[10] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_blkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(serpent_algs[2].cra_list),
        .cra_u = {
                .blkcipher = {
                        .min_keysize    = SERPENT_MIN_KEY_SIZE,
@@ -454,7 +451,6 @@ static struct crypto_alg serpent_algs[10] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_blkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(serpent_algs[3].cra_list),
        .cra_exit               = lrw_exit_tfm,
        .cra_u = {
                .blkcipher = {
@@ -478,7 +474,6 @@ static struct crypto_alg serpent_algs[10] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_blkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(serpent_algs[4].cra_list),
        .cra_u = {
                .blkcipher = {
                        .min_keysize    = SERPENT_MIN_KEY_SIZE * 2,
@@ -499,7 +494,6 @@ static struct crypto_alg serpent_algs[10] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_ablkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(serpent_algs[5].cra_list),
        .cra_init               = ablk_init,
        .cra_exit               = ablk_exit,
        .cra_u = {
@@ -521,7 +515,6 @@ static struct crypto_alg serpent_algs[10] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_ablkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(serpent_algs[6].cra_list),
        .cra_init               = ablk_init,
        .cra_exit               = ablk_exit,
        .cra_u = {
@@ -544,7 +537,6 @@ static struct crypto_alg serpent_algs[10] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_ablkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(serpent_algs[7].cra_list),
        .cra_init               = ablk_init,
        .cra_exit               = ablk_exit,
        .cra_u = {
@@ -568,7 +560,6 @@ static struct crypto_alg serpent_algs[10] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_ablkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(serpent_algs[8].cra_list),
        .cra_init               = ablk_init,
        .cra_exit               = ablk_exit,
        .cra_u = {
@@ -593,7 +584,6 @@ static struct crypto_alg serpent_algs[10] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_ablkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(serpent_algs[9].cra_list),
        .cra_init               = ablk_init,
        .cra_exit               = ablk_exit,
        .cra_u = {
index 782b67ddaf6a833724973c9959e42d2e0cb41ec1..e7708b5442e0b59ab7478306124c8c84493a551c 100644 (file)
@@ -378,7 +378,6 @@ static struct crypto_alg twofish_algs[10] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_blkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(twofish_algs[0].cra_list),
        .cra_u = {
                .blkcipher = {
                        .min_keysize    = TF_MIN_KEY_SIZE,
@@ -398,7 +397,6 @@ static struct crypto_alg twofish_algs[10] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_blkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(twofish_algs[1].cra_list),
        .cra_u = {
                .blkcipher = {
                        .min_keysize    = TF_MIN_KEY_SIZE,
@@ -418,7 +416,6 @@ static struct crypto_alg twofish_algs[10] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_blkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(twofish_algs[2].cra_list),
        .cra_u = {
                .blkcipher = {
                        .min_keysize    = TF_MIN_KEY_SIZE,
@@ -439,7 +436,6 @@ static struct crypto_alg twofish_algs[10] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_blkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(twofish_algs[3].cra_list),
        .cra_exit               = lrw_twofish_exit_tfm,
        .cra_u = {
                .blkcipher = {
@@ -463,7 +459,6 @@ static struct crypto_alg twofish_algs[10] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_blkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(twofish_algs[4].cra_list),
        .cra_u = {
                .blkcipher = {
                        .min_keysize    = TF_MIN_KEY_SIZE * 2,
@@ -484,7 +479,6 @@ static struct crypto_alg twofish_algs[10] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_ablkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(twofish_algs[5].cra_list),
        .cra_init               = ablk_init,
        .cra_exit               = ablk_exit,
        .cra_u = {
@@ -506,7 +500,6 @@ static struct crypto_alg twofish_algs[10] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_ablkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(twofish_algs[6].cra_list),
        .cra_init               = ablk_init,
        .cra_exit               = ablk_exit,
        .cra_u = {
@@ -529,7 +522,6 @@ static struct crypto_alg twofish_algs[10] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_ablkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(twofish_algs[7].cra_list),
        .cra_init               = ablk_init,
        .cra_exit               = ablk_exit,
        .cra_u = {
@@ -553,7 +545,6 @@ static struct crypto_alg twofish_algs[10] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_ablkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(twofish_algs[8].cra_list),
        .cra_init               = ablk_init,
        .cra_exit               = ablk_exit,
        .cra_u = {
@@ -578,7 +569,6 @@ static struct crypto_alg twofish_algs[10] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_ablkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(twofish_algs[9].cra_list),
        .cra_init               = ablk_init,
        .cra_exit               = ablk_exit,
        .cra_u = {
index 359ae084275cbb2610d66c4d52d653c9564c2c3e..0a5202303501e29215e5f5bb9e143417ddd35452 100644 (file)
@@ -70,7 +70,6 @@ static struct crypto_alg alg = {
        .cra_ctxsize            =       sizeof(struct twofish_ctx),
        .cra_alignmask          =       0,
        .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(alg.cra_list),
        .cra_u                  =       {
                .cipher = {
                        .cia_min_keysize        =       TF_MIN_KEY_SIZE,
index 15f9347316c8409a243f7db60b91f128de4618a9..aa3eb358b7e81b82d1816cbafbc58a04349d3428 100644 (file)
@@ -342,7 +342,6 @@ static struct crypto_alg tf_algs[5] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_blkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(tf_algs[0].cra_list),
        .cra_u = {
                .blkcipher = {
                        .min_keysize    = TF_MIN_KEY_SIZE,
@@ -362,7 +361,6 @@ static struct crypto_alg tf_algs[5] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_blkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(tf_algs[1].cra_list),
        .cra_u = {
                .blkcipher = {
                        .min_keysize    = TF_MIN_KEY_SIZE,
@@ -383,7 +381,6 @@ static struct crypto_alg tf_algs[5] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_blkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(tf_algs[2].cra_list),
        .cra_u = {
                .blkcipher = {
                        .min_keysize    = TF_MIN_KEY_SIZE,
@@ -404,7 +401,6 @@ static struct crypto_alg tf_algs[5] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_blkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(tf_algs[3].cra_list),
        .cra_exit               = lrw_twofish_exit_tfm,
        .cra_u = {
                .blkcipher = {
@@ -426,7 +422,6 @@ static struct crypto_alg tf_algs[5] = { {
        .cra_alignmask          = 0,
        .cra_type               = &crypto_blkcipher_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(tf_algs[4].cra_list),
        .cra_u = {
                .blkcipher = {
                        .min_keysize    = TF_MIN_KEY_SIZE * 2,
index 09155d64cf7e6a560e3c6a1501e568918d9f2ed9..fc0e752e75640fbc3329babdfe1fe57e3575702b 100644 (file)
@@ -420,6 +420,8 @@ struct kvm_vcpu_arch {
        unsigned int hw_tsc_khz;
        unsigned int time_offset;
        struct page *time_page;
+       /* set guest stopped flag in pvclock flags field */
+       bool pvclock_set_guest_stopped_request;
 
        struct {
                u64 msr_val;
@@ -500,11 +502,11 @@ struct kvm_vcpu_arch {
 };
 
 struct kvm_lpage_info {
-       unsigned long rmap_pde;
        int write_count;
 };
 
 struct kvm_arch_memory_slot {
+       unsigned long *rmap[KVM_NR_PAGE_SIZES];
        struct kvm_lpage_info *lpage_info[KVM_NR_PAGE_SIZES - 1];
 };
 
@@ -957,6 +959,7 @@ extern bool kvm_rebooting;
 
 #define KVM_ARCH_WANT_MMU_NOTIFIER
 int kvm_unmap_hva(struct kvm *kvm, unsigned long hva);
+int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end);
 int kvm_age_hva(struct kvm *kvm, unsigned long hva);
 int kvm_test_age_hva(struct kvm *kvm, unsigned long hva);
 void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
index 2f7712e08b1e80ceb98b889ab1b3b19fb1706a11..20f5697888bd46a4aacf630c374d2bfe2ef5e2b6 100644 (file)
@@ -116,7 +116,7 @@ static inline bool kvm_check_and_clear_guest_paused(void)
  */
 #define KVM_HYPERCALL ".byte 0x0f,0x01,0xc1"
 
-/* For KVM hypercalls, a three-byte sequence of either the vmrun or the vmmrun
+/* For KVM hypercalls, a three-byte sequence of either the vmcall or the vmmcall
  * instruction.  The hypervisor may replace it with something else but only the
  * instructions are guaranteed to be supported.
  *
index 441520e4174f9f08736af4368f0c74e1f1ec5b0b..a3ac52b29cbfc5abd3c178fcfbfe7d7586d6e7f2 100644 (file)
 #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)
index dab39350e51e446917d5b5e302fe1ac2214b10d0..cb4e43bce98ab46e262f3b235765e5ebd6270ddd 100644 (file)
@@ -196,11 +196,16 @@ static inline u32 get_ibs_caps(void) { return 0; }
 extern void perf_events_lapic_init(void);
 
 /*
- * Abuse bit 3 of the cpu eflags register to indicate proper PEBS IP fixups.
- * This flag is otherwise unused and ABI specified to be 0, so nobody should
- * care what we do with it.
+ * Abuse bits {3,5} of the cpu eflags register. These flags are otherwise
+ * unused and ABI specified to be 0, so nobody should care what we do with
+ * them.
+ *
+ * EXACT - the IP points to the exact instruction that triggered the
+ *         event (HW bugs exempt).
+ * VM    - original X86_VM_MASK; see set_linear_ip().
  */
 #define PERF_EFLAGS_EXACT      (1UL << 3)
+#define PERF_EFLAGS_VM         (1UL << 5)
 
 struct pt_regs;
 extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
diff --git a/arch/x86/include/asm/rcu.h b/arch/x86/include/asm/rcu.h
new file mode 100644 (file)
index 0000000..439815b
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef _ASM_X86_RCU_H
+#define _ASM_X86_RCU_H
+
+#include <linux/rcupdate.h>
+#include <asm/ptrace.h>
+
+static inline void exception_enter(struct pt_regs *regs)
+{
+       rcu_user_exit();
+}
+
+static inline void exception_exit(struct pt_regs *regs)
+{
+#ifdef CONFIG_RCU_USER_QS
+       if (user_mode(regs))
+               rcu_user_enter();
+#endif
+}
+
+#endif
index 89f794f007ec1e4aa5bbd029bcb32182fffe1f48..c535d847e3b5f75dff0d8d2dd7988935fc35b63f 100644 (file)
@@ -89,6 +89,7 @@ struct thread_info {
 #define TIF_NOTSC              16      /* TSC is not accessible in userland */
 #define TIF_IA32               17      /* IA32 compatibility process */
 #define TIF_FORK               18      /* ret_from_fork */
+#define TIF_NOHZ               19      /* in adaptive nohz mode */
 #define TIF_MEMDIE             20      /* is terminating due to OOM killer */
 #define TIF_DEBUG              21      /* uses debug registers */
 #define TIF_IO_BITMAP          22      /* uses I/O bitmap */
@@ -114,6 +115,7 @@ struct thread_info {
 #define _TIF_NOTSC             (1 << TIF_NOTSC)
 #define _TIF_IA32              (1 << TIF_IA32)
 #define _TIF_FORK              (1 << TIF_FORK)
+#define _TIF_NOHZ              (1 << TIF_NOHZ)
 #define _TIF_DEBUG             (1 << TIF_DEBUG)
 #define _TIF_IO_BITMAP         (1 << TIF_IO_BITMAP)
 #define _TIF_FORCED_TF         (1 << TIF_FORCED_TF)
@@ -126,12 +128,13 @@ struct thread_info {
 /* work to do in syscall_trace_enter() */
 #define _TIF_WORK_SYSCALL_ENTRY        \
        (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_EMU | _TIF_SYSCALL_AUDIT |   \
-        _TIF_SECCOMP | _TIF_SINGLESTEP | _TIF_SYSCALL_TRACEPOINT)
+        _TIF_SECCOMP | _TIF_SINGLESTEP | _TIF_SYSCALL_TRACEPOINT |     \
+        _TIF_NOHZ)
 
 /* work to do in syscall_trace_leave() */
 #define _TIF_WORK_SYSCALL_EXIT \
        (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SINGLESTEP |    \
-        _TIF_SYSCALL_TRACEPOINT)
+        _TIF_SYSCALL_TRACEPOINT | _TIF_NOHZ)
 
 /* work to do on interrupt/exception return */
 #define _TIF_WORK_MASK                                                 \
@@ -141,7 +144,8 @@ struct thread_info {
 
 /* work to do on any return to user space */
 #define _TIF_ALLWORK_MASK                                              \
-       ((0x0000FFFF & ~_TIF_SECCOMP) | _TIF_SYSCALL_TRACEPOINT)
+       ((0x0000FFFF & ~_TIF_SECCOMP) | _TIF_SYSCALL_TRACEPOINT |       \
+       _TIF_NOHZ)
 
 /* Only used for 64 bit */
 #define _TIF_DO_NOTIFY_MASK                                            \
index 95bf99de9058128f320356caa6cad1ce9b2727da..1b8e5a03d942439c4b58a7470f181dcb99b29e85 100644 (file)
@@ -25,10 +25,6 @@ unsigned long acpi_realmode_flags;
 static char temp_stack[4096];
 #endif
 
-asmlinkage void acpi_enter_s3(void)
-{
-       acpi_enter_sleep_state(3, wake_sleep_flags);
-}
 /**
  * acpi_suspend_lowlevel - save kernel state
  *
index 5653a5791ec92291844a55665cc50a0cb402095b..67f59f8c695651977e45d88e15bc66781777f31c 100644 (file)
@@ -2,7 +2,6 @@
  *     Variables and functions used by the code in sleep.c
  */
 
-#include <linux/linkage.h>
 #include <asm/realmode.h>
 
 extern unsigned long saved_video_mode;
@@ -11,7 +10,6 @@ extern long saved_magic;
 extern int wakeup_pmode_return;
 
 extern u8 wake_sleep_flags;
-extern asmlinkage void acpi_enter_s3(void);
 
 extern unsigned long acpi_copy_wakeup_routine(unsigned long);
 extern void wakeup_long64(void);
index 72610839f03b3d45e8fa6adb49a13fe933b477b2..13ab720573e3e31e317ac52f977e168401552f17 100644 (file)
@@ -74,7 +74,9 @@ restore_registers:
 ENTRY(do_suspend_lowlevel)
        call    save_processor_state
        call    save_registers
-       call    acpi_enter_s3
+       pushl   $3
+       call    acpi_enter_sleep_state
+       addl    $4, %esp
 
 #      In case of S3 failure, we'll emerge here.  Jump
 #      to ret_point to recover
index 014d1d28c397076606be9d50f04af06892bf2f03..8ea5164cbd0451a27b9048699f60c2420057edb3 100644 (file)
@@ -71,7 +71,9 @@ ENTRY(do_suspend_lowlevel)
        movq    %rsi, saved_rsi
 
        addq    $8, %rsp
-       call    acpi_enter_s3
+       movl    $3, %edi
+       xorl    %eax, %eax
+       call    acpi_enter_sleep_state
        /* in case something went wrong, restore the machine status and go on */
        jmp     resume_point
 
index 931280ff8299471df09b60033cdb06b46a361677..afb7ff79a29fbb33c6578c9240c7e5b550417b88 100644 (file)
@@ -224,7 +224,7 @@ void __init arch_init_ideal_nops(void)
                        ideal_nops = intel_nops;
 #endif
                }
-
+               break;
        default:
 #ifdef CONFIG_X86_64
                ideal_nops = k8_nops;
index 406eee7846849990d8f87d53243e6cd171944e17..a6c64aaddf9ac9a52ccad2757e7bd387702061ca 100644 (file)
@@ -1204,7 +1204,7 @@ static void __clear_irq_vector(int irq, struct irq_cfg *cfg)
        BUG_ON(!cfg->vector);
 
        vector = cfg->vector;
-       for_each_cpu(cpu, cfg->domain)
+       for_each_cpu_and(cpu, cfg->domain, cpu_online_mask)
                per_cpu(vector_irq, cpu)[vector] = -1;
 
        cfg->vector = 0;
@@ -1212,7 +1212,7 @@ static void __clear_irq_vector(int irq, struct irq_cfg *cfg)
 
        if (likely(!cfg->move_in_progress))
                return;
-       for_each_cpu(cpu, cfg->old_domain) {
+       for_each_cpu_and(cpu, cfg->old_domain, cpu_online_mask) {
                for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS;
                                                                vector++) {
                        if (per_cpu(vector_irq, cpu)[vector] != irq)
index 9d92e19039f05f84b4c172de7c1c243a4dad72e0..f7e98a2c0d123ae0ebe7f61f1521f7dd7090a335 100644 (file)
@@ -737,6 +737,72 @@ static unsigned int __cpuinit amd_size_cache(struct cpuinfo_x86 *c,
 }
 #endif
 
+static void __cpuinit cpu_set_tlb_flushall_shift(struct cpuinfo_x86 *c)
+{
+       if (!cpu_has_invlpg)
+               return;
+
+       tlb_flushall_shift = 5;
+
+       if (c->x86 <= 0x11)
+               tlb_flushall_shift = 4;
+}
+
+static void __cpuinit cpu_detect_tlb_amd(struct cpuinfo_x86 *c)
+{
+       u32 ebx, eax, ecx, edx;
+       u16 mask = 0xfff;
+
+       if (c->x86 < 0xf)
+               return;
+
+       if (c->extended_cpuid_level < 0x80000006)
+               return;
+
+       cpuid(0x80000006, &eax, &ebx, &ecx, &edx);
+
+       tlb_lld_4k[ENTRIES] = (ebx >> 16) & mask;
+       tlb_lli_4k[ENTRIES] = ebx & mask;
+
+       /*
+        * K8 doesn't have 2M/4M entries in the L2 TLB so read out the L1 TLB
+        * characteristics from the CPUID function 0x80000005 instead.
+        */
+       if (c->x86 == 0xf) {
+               cpuid(0x80000005, &eax, &ebx, &ecx, &edx);
+               mask = 0xff;
+       }
+
+       /* Handle DTLB 2M and 4M sizes, fall back to L1 if L2 is disabled */
+       if (!((eax >> 16) & mask)) {
+               u32 a, b, c, d;
+
+               cpuid(0x80000005, &a, &b, &c, &d);
+               tlb_lld_2m[ENTRIES] = (a >> 16) & 0xff;
+       } else {
+               tlb_lld_2m[ENTRIES] = (eax >> 16) & mask;
+       }
+
+       /* a 4M entry uses two 2M entries */
+       tlb_lld_4m[ENTRIES] = tlb_lld_2m[ENTRIES] >> 1;
+
+       /* Handle ITLB 2M and 4M sizes, fall back to L1 if L2 is disabled */
+       if (!(eax & mask)) {
+               /* Erratum 658 */
+               if (c->x86 == 0x15 && c->x86_model <= 0x1f) {
+                       tlb_lli_2m[ENTRIES] = 1024;
+               } else {
+                       cpuid(0x80000005, &eax, &ebx, &ecx, &edx);
+                       tlb_lli_2m[ENTRIES] = eax & 0xff;
+               }
+       } else
+               tlb_lli_2m[ENTRIES] = eax & mask;
+
+       tlb_lli_4m[ENTRIES] = tlb_lli_2m[ENTRIES] >> 1;
+
+       cpu_set_tlb_flushall_shift(c);
+}
+
 static const struct cpu_dev __cpuinitconst amd_cpu_dev = {
        .c_vendor       = "AMD",
        .c_ident        = { "AuthenticAMD" },
@@ -756,6 +822,7 @@ static const struct cpu_dev __cpuinitconst amd_cpu_dev = {
        .c_size_cache   = amd_size_cache,
 #endif
        .c_early_init   = early_init_amd,
+       .c_detect_tlb   = cpu_detect_tlb_amd,
        .c_bsp_init     = bsp_init_amd,
        .c_init         = init_amd,
        .c_x86_vendor   = X86_VENDOR_AMD,
index 46d8786d655e402b702cc2f19ba4eab9cb5a62cd..080f4a737e3e798f53f69e68f2cbd0f81df83af4 100644 (file)
@@ -474,7 +474,7 @@ void __cpuinit cpu_detect_tlb(struct cpuinfo_x86 *c)
 
        printk(KERN_INFO "Last level iTLB entries: 4KB %d, 2MB %d, 4MB %d\n" \
                "Last level dTLB entries: 4KB %d, 2MB %d, 4MB %d\n"          \
-               "tlb_flushall_shift is 0x%x\n",
+               "tlb_flushall_shift: %d\n",
                tlb_lli_4k[ENTRIES], tlb_lli_2m[ENTRIES],
                tlb_lli_4m[ENTRIES], tlb_lld_4k[ENTRIES],
                tlb_lld_2m[ENTRIES], tlb_lld_4m[ENTRIES],
@@ -940,8 +940,7 @@ void __init identify_boot_cpu(void)
 #else
        vgetcpu_set_mode();
 #endif
-       if (boot_cpu_data.cpuid_level >= 2)
-               cpu_detect_tlb(&boot_cpu_data);
+       cpu_detect_tlb(&boot_cpu_data);
 }
 
 void __cpuinit identify_secondary_cpu(struct cpuinfo_x86 *c)
index 0a4ce2980a5a33e90bea05599a015a0c1381bf23..198e019a531af8f26c9c094560d87b325998428b 100644 (file)
@@ -648,6 +648,10 @@ static void __cpuinit intel_detect_tlb(struct cpuinfo_x86 *c)
        int i, j, n;
        unsigned int regs[4];
        unsigned char *desc = (unsigned char *)regs;
+
+       if (c->cpuid_level < 2)
+               return;
+
        /* Number of times to iterate */
        n = cpuid_eax(2) & 0xFF;
 
index 413c2ced887c66c89b1f49fb18a3bac29604ccb2..13017626f9a85c0948fe99cafa1102c0c9d010da 100644 (file)
@@ -55,13 +55,6 @@ static struct severity {
 #define MCI_UC_S (MCI_STATUS_UC|MCI_STATUS_S)
 #define MCI_UC_SAR (MCI_STATUS_UC|MCI_STATUS_S|MCI_STATUS_AR)
 #define        MCI_ADDR (MCI_STATUS_ADDRV|MCI_STATUS_MISCV)
-#define MCACOD 0xffff
-/* 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 */
 
        MCESEV(
                NO, "Invalid",
index 5e095f873e3eb731a42012c5e10310fc238ed9c7..292d0258311c82d04c5ec0aeab43924d00c669b4 100644 (file)
@@ -103,6 +103,8 @@ DEFINE_PER_CPU(mce_banks_t, mce_poll_banks) = {
 
 static DEFINE_PER_CPU(struct work_struct, mce_work);
 
+static void (*quirk_no_way_out)(int bank, struct mce *m, struct pt_regs *regs);
+
 /*
  * CPU/chipset specific EDAC code can register a notifier call here to print
  * MCE errors in a human-readable form.
@@ -650,14 +652,18 @@ EXPORT_SYMBOL_GPL(machine_check_poll);
  * Do a quick check if any of the events requires a panic.
  * This decides if we keep the events around or clear them.
  */
-static int mce_no_way_out(struct mce *m, char **msg, unsigned long *validp)
+static int mce_no_way_out(struct mce *m, char **msg, unsigned long *validp,
+                         struct pt_regs *regs)
 {
        int i, ret = 0;
 
        for (i = 0; i < banks; i++) {
                m->status = mce_rdmsrl(MSR_IA32_MCx_STATUS(i));
-               if (m->status & MCI_STATUS_VAL)
+               if (m->status & MCI_STATUS_VAL) {
                        __set_bit(i, validp);
+                       if (quirk_no_way_out)
+                               quirk_no_way_out(i, m, regs);
+               }
                if (mce_severity(m, tolerant, msg) >= MCE_PANIC_SEVERITY)
                        ret = 1;
        }
@@ -1040,7 +1046,7 @@ void do_machine_check(struct pt_regs *regs, long error_code)
        *final = m;
 
        memset(valid_banks, 0, sizeof(valid_banks));
-       no_way_out = mce_no_way_out(&m, &msg, valid_banks);
+       no_way_out = mce_no_way_out(&m, &msg, valid_banks, regs);
 
        barrier();
 
@@ -1418,6 +1424,34 @@ static void __mcheck_cpu_init_generic(void)
        }
 }
 
+/*
+ * During IFU recovery Sandy Bridge -EP4S processors set the RIPV and
+ * EIPV bits in MCG_STATUS to zero on the affected logical processor (SDM
+ * Vol 3B Table 15-20). But this confuses both the code that determines
+ * whether the machine check occurred in kernel or user mode, and also
+ * the severity assessment code. Pretend that EIPV was set, and take the
+ * ip/cs values from the pt_regs that mce_gather_info() ignored earlier.
+ */
+static void quirk_sandybridge_ifu(int bank, struct mce *m, struct pt_regs *regs)
+{
+       if (bank != 0)
+               return;
+       if ((m->mcgstatus & (MCG_STATUS_EIPV|MCG_STATUS_RIPV)) != 0)
+               return;
+       if ((m->status & (MCI_STATUS_OVER|MCI_STATUS_UC|
+                         MCI_STATUS_EN|MCI_STATUS_MISCV|MCI_STATUS_ADDRV|
+                         MCI_STATUS_PCC|MCI_STATUS_S|MCI_STATUS_AR|
+                         MCACOD)) !=
+                        (MCI_STATUS_UC|MCI_STATUS_EN|
+                         MCI_STATUS_MISCV|MCI_STATUS_ADDRV|MCI_STATUS_S|
+                         MCI_STATUS_AR|MCACOD_INSTR))
+               return;
+
+       m->mcgstatus |= MCG_STATUS_EIPV;
+       m->ip = regs->ip;
+       m->cs = regs->cs;
+}
+
 /* Add per CPU specific workarounds here */
 static int __cpuinit __mcheck_cpu_apply_quirks(struct cpuinfo_x86 *c)
 {
@@ -1515,6 +1549,9 @@ static int __cpuinit __mcheck_cpu_apply_quirks(struct cpuinfo_x86 *c)
                 */
                if (c->x86 == 6 && c->x86_model <= 13 && mce_bootlog < 0)
                        mce_bootlog = 0;
+
+               if (c->x86 == 6 && c->x86_model == 45)
+                       quirk_no_way_out = quirk_sandybridge_ifu;
        }
        if (monarch_timeout < 0)
                monarch_timeout = 0;
index 29557aa06dda6a724add1d6be6f7744f2d801d34..915b876edd1e2b8a509786446642302648989a73 100644 (file)
@@ -32,6 +32,8 @@
 #include <asm/smp.h>
 #include <asm/alternative.h>
 #include <asm/timer.h>
+#include <asm/desc.h>
+#include <asm/ldt.h>
 
 #include "perf_event.h"
 
@@ -1738,6 +1740,29 @@ valid_user_frame(const void __user *fp, unsigned long size)
        return (__range_not_ok(fp, size, TASK_SIZE) == 0);
 }
 
+static unsigned long get_segment_base(unsigned int segment)
+{
+       struct desc_struct *desc;
+       int idx = segment >> 3;
+
+       if ((segment & SEGMENT_TI_MASK) == SEGMENT_LDT) {
+               if (idx > LDT_ENTRIES)
+                       return 0;
+
+               if (idx > current->active_mm->context.size)
+                       return 0;
+
+               desc = current->active_mm->context.ldt;
+       } else {
+               if (idx > GDT_ENTRIES)
+                       return 0;
+
+               desc = __this_cpu_ptr(&gdt_page.gdt[0]);
+       }
+
+       return get_desc_base(desc + idx);
+}
+
 #ifdef CONFIG_COMPAT
 
 #include <asm/compat.h>
@@ -1746,13 +1771,17 @@ static inline int
 perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry *entry)
 {
        /* 32-bit process in 64-bit kernel. */
+       unsigned long ss_base, cs_base;
        struct stack_frame_ia32 frame;
        const void __user *fp;
 
        if (!test_thread_flag(TIF_IA32))
                return 0;
 
-       fp = compat_ptr(regs->bp);
+       cs_base = get_segment_base(regs->cs);
+       ss_base = get_segment_base(regs->ss);
+
+       fp = compat_ptr(ss_base + regs->bp);
        while (entry->nr < PERF_MAX_STACK_DEPTH) {
                unsigned long bytes;
                frame.next_frame     = 0;
@@ -1765,8 +1794,8 @@ perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry *entry)
                if (!valid_user_frame(fp, sizeof(frame)))
                        break;
 
-               perf_callchain_store(entry, frame.return_address);
-               fp = compat_ptr(frame.next_frame);
+               perf_callchain_store(entry, cs_base + frame.return_address);
+               fp = compat_ptr(ss_base + frame.next_frame);
        }
        return 1;
 }
@@ -1789,6 +1818,12 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
                return;
        }
 
+       /*
+        * We don't know what to do with VM86 stacks.. ignore them for now.
+        */
+       if (regs->flags & (X86_VM_MASK | PERF_EFLAGS_VM))
+               return;
+
        fp = (void __user *)regs->bp;
 
        perf_callchain_store(entry, regs->ip);
@@ -1816,16 +1851,50 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
        }
 }
 
-unsigned long perf_instruction_pointer(struct pt_regs *regs)
+/*
+ * Deal with code segment offsets for the various execution modes:
+ *
+ *   VM86 - the good olde 16 bit days, where the linear address is
+ *          20 bits and we use regs->ip + 0x10 * regs->cs.
+ *
+ *   IA32 - Where we need to look at GDT/LDT segment descriptor tables
+ *          to figure out what the 32bit base address is.
+ *
+ *    X32 - has TIF_X32 set, but is running in x86_64
+ *
+ * X86_64 - CS,DS,SS,ES are all zero based.
+ */
+static unsigned long code_segment_base(struct pt_regs *regs)
 {
-       unsigned long ip;
+       /*
+        * If we are in VM86 mode, add the segment offset to convert to a
+        * linear address.
+        */
+       if (regs->flags & X86_VM_MASK)
+               return 0x10 * regs->cs;
+
+       /*
+        * For IA32 we look at the GDT/LDT segment base to convert the
+        * effective IP to a linear address.
+        */
+#ifdef CONFIG_X86_32
+       if (user_mode(regs) && regs->cs != __USER_CS)
+               return get_segment_base(regs->cs);
+#else
+       if (test_thread_flag(TIF_IA32)) {
+               if (user_mode(regs) && regs->cs != __USER32_CS)
+                       return get_segment_base(regs->cs);
+       }
+#endif
+       return 0;
+}
 
+unsigned long perf_instruction_pointer(struct pt_regs *regs)
+{
        if (perf_guest_cbs && perf_guest_cbs->is_in_guest())
-               ip = perf_guest_cbs->get_guest_ip();
-       else
-               ip = instruction_pointer(regs);
+               return perf_guest_cbs->get_guest_ip();
 
-       return ip;
+       return regs->ip + code_segment_base(regs);
 }
 
 unsigned long perf_misc_flags(struct pt_regs *regs)
@@ -1838,7 +1907,7 @@ unsigned long perf_misc_flags(struct pt_regs *regs)
                else
                        misc |= PERF_RECORD_MISC_GUEST_KERNEL;
        } else {
-               if (!kernel_ip(regs->ip))
+               if (user_mode(regs))
                        misc |= PERF_RECORD_MISC_USER;
                else
                        misc |= PERF_RECORD_MISC_KERNEL;
index 821d53b696d1408fb1b71faffda28283052d9733..6605a81ba3399fb8c1c9044b0e7aa8c2e22ff882 100644 (file)
@@ -516,6 +516,26 @@ static inline bool kernel_ip(unsigned long ip)
 #endif
 }
 
+/*
+ * Not all PMUs provide the right context information to place the reported IP
+ * into full context. Specifically segment registers are typically not
+ * supplied.
+ *
+ * Assuming the address is a linear address (it is for IBS), we fake the CS and
+ * vm86 mode using the known zero-based code segment and 'fix up' the registers
+ * to reflect this.
+ *
+ * Intel PEBS/LBR appear to typically provide the effective address, nothing
+ * much we can do about that but pray and treat it like a linear address.
+ */
+static inline void set_linear_ip(struct pt_regs *regs, unsigned long ip)
+{
+       regs->cs = kernel_ip(ip) ? __KERNEL_CS : __USER_CS;
+       if (regs->flags & X86_VM_MASK)
+               regs->flags ^= (PERF_EFLAGS_VM | X86_VM_MASK);
+       regs->ip = ip;
+}
+
 #ifdef CONFIG_CPU_SUP_AMD
 
 int amd_pmu_init(void);
index da9bcdcd9856666daf006c06ae6e14af4c77bca9..7bfb5bec8630ada6580dd446e8a62de847d12288 100644 (file)
@@ -13,6 +13,8 @@
 
 #include <asm/apic.h>
 
+#include "perf_event.h"
+
 static u32 ibs_caps;
 
 #if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_AMD)
@@ -536,7 +538,7 @@ static int perf_ibs_handle_irq(struct perf_ibs *perf_ibs, struct pt_regs *iregs)
        if (check_rip && (ibs_data.regs[2] & IBS_RIP_INVALID)) {
                regs.flags &= ~PERF_EFLAGS_EXACT;
        } else {
-               instruction_pointer_set(&regs, ibs_data.regs[1]);
+               set_linear_ip(&regs, ibs_data.regs[1]);
                regs.flags |= PERF_EFLAGS_EXACT;
        }
 
index 629ae0b7ad901c88706716966b1fd71415debe19..e38d97bf4259fc579f2b070fef85980ae7aaab7a 100644 (file)
@@ -499,7 +499,7 @@ static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs)
         * We sampled a branch insn, rewind using the LBR stack
         */
        if (ip == to) {
-               regs->ip = from;
+               set_linear_ip(regs, from);
                return 1;
        }
 
@@ -529,7 +529,7 @@ static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs)
        } while (to < ip);
 
        if (to == ip) {
-               regs->ip = old_to;
+               set_linear_ip(regs, old_to);
                return 1;
        }
 
@@ -569,7 +569,8 @@ static void __intel_pmu_pebs_event(struct perf_event *event,
         * A possible PERF_SAMPLE_REGS will have to transfer all regs.
         */
        regs = *iregs;
-       regs.ip = pebs->ip;
+       regs.flags = pebs->flags;
+       set_linear_ip(&regs, pebs->ip);
        regs.bp = pebs->bp;
        regs.sp = pebs->sp;
 
index f3851892e0770c540c9df3a7da4925da9ecf2198..c9e5dc56630a0ba0809c685568ac8d8478b46579 100644 (file)
@@ -5,7 +5,7 @@
 #include "perf_event.h"
 
 #define UNCORE_PMU_NAME_LEN            32
-#define UNCORE_PMU_HRTIMER_INTERVAL    (60 * NSEC_PER_SEC)
+#define UNCORE_PMU_HRTIMER_INTERVAL    (60LL * NSEC_PER_SEC)
 
 #define UNCORE_FIXED_EVENT             0xff
 #define UNCORE_PMC_IDX_MAX_GENERIC     8
index 69babd8c834f920b4d54c48e1f41a08d4f7fef6f..62304871b26a2265c7762f667b9174c7af309663 100644 (file)
@@ -565,7 +565,7 @@ sysret_careful:
        TRACE_IRQS_ON
        ENABLE_INTERRUPTS(CLBR_NONE)
        pushq_cfi %rdi
-       call schedule
+       call schedule_user
        popq_cfi %rdi
        jmp sysret_check
 
@@ -678,7 +678,7 @@ int_careful:
        TRACE_IRQS_ON
        ENABLE_INTERRUPTS(CLBR_NONE)
        pushq_cfi %rdi
-       call schedule
+       call schedule_user
        popq_cfi %rdi
        DISABLE_INTERRUPTS(CLBR_NONE)
        TRACE_IRQS_OFF
@@ -974,7 +974,7 @@ retint_careful:
        TRACE_IRQS_ON
        ENABLE_INTERRUPTS(CLBR_NONE)
        pushq_cfi %rdi
-       call  schedule
+       call  schedule_user
        popq_cfi %rdi
        GET_THREAD_INFO(%rcx)
        DISABLE_INTERRUPTS(CLBR_NONE)
@@ -1449,7 +1449,7 @@ paranoid_userspace:
 paranoid_schedule:
        TRACE_IRQS_ON
        ENABLE_INTERRUPTS(CLBR_ANY)
-       call schedule
+       call schedule_user
        DISABLE_INTERRUPTS(CLBR_ANY)
        TRACE_IRQS_OFF
        jmp paranoid_userspace
index 1f5f1d5d2a022b21a6871c083af70f09b9def90f..7ad683d78645c1b8eed3a816e6fca23de94541f3 100644 (file)
@@ -328,6 +328,7 @@ void fixup_irqs(void)
                                chip->irq_retrigger(data);
                        raw_spin_unlock(&desc->lock);
                }
+               __this_cpu_write(vector_irq[vector], -1);
        }
 }
 #endif
index 1d5d31ea686be2aaedb2790637674cc0c0fec56b..dc1404bf8e4b4c48bc6a137c372ab3b4396fc376 100644 (file)
@@ -107,7 +107,7 @@ static int __init create_setup_data_nodes(struct dentry *parent)
 {
        struct setup_data_node *node;
        struct setup_data *data;
-       int error = -ENOMEM;
+       int error;
        struct dentry *d;
        struct page *pg;
        u64 pa_data;
@@ -121,8 +121,10 @@ static int __init create_setup_data_nodes(struct dentry *parent)
 
        while (pa_data) {
                node = kmalloc(sizeof(*node), GFP_KERNEL);
-               if (!node)
+               if (!node) {
+                       error = -ENOMEM;
                        goto err_dir;
+               }
 
                pg = pfn_to_page((pa_data+sizeof(*data)-1) >> PAGE_SHIFT);
                if (PageHighMem(pg)) {
index 3f61904365cff214d26efa4a378830559e39a7f9..836f8322960e4b78c3263c3a18ed70cb67b589a7 100644 (file)
@@ -746,7 +746,9 @@ void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip)
 int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt)
 {
        int err;
+#ifdef CONFIG_DEBUG_RODATA
        char opc[BREAK_INSTR_SIZE];
+#endif /* CONFIG_DEBUG_RODATA */
 
        bpt->type = BP_BREAKPOINT;
        err = probe_kernel_read(bpt->saved_instr, (char *)bpt->bpt_addr,
index c4c6a5c2bf0f393ffa8588a1fa7376bcaa9513bb..9f94f8ec26e40f60f35e36e3151c6115b876ba73 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/signal.h>
 #include <linux/perf_event.h>
 #include <linux/hw_breakpoint.h>
+#include <linux/rcupdate.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -1463,6 +1464,8 @@ long syscall_trace_enter(struct pt_regs *regs)
 {
        long ret = 0;
 
+       rcu_user_exit();
+
        /*
         * If we stepped into a sysenter/syscall insn, it trapped in
         * kernel mode; do_debug() cleared TF and set TIF_SINGLESTEP.
@@ -1526,4 +1529,6 @@ void syscall_trace_leave(struct pt_regs *regs)
                        !test_thread_flag(TIF_SYSCALL_EMU);
        if (step || test_thread_flag(TIF_SYSCALL_TRACE))
                tracehook_report_syscall_exit(regs, step);
+
+       rcu_user_enter();
 }
index b280908a376e20efc6773b76c6e80353ef8680f4..bca0ab903e577dd96c017cd2b1deeded1e28ea60 100644 (file)
@@ -779,6 +779,8 @@ static void do_signal(struct pt_regs *regs)
 void
 do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
 {
+       rcu_user_exit();
+
 #ifdef CONFIG_X86_MCE
        /* notify userspace of pending MCEs */
        if (thread_info_flags & _TIF_MCE_NOTIFY)
@@ -804,6 +806,8 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
 #ifdef CONFIG_X86_32
        clear_thread_flag(TIF_IRET);
 #endif /* CONFIG_X86_32 */
+
+       rcu_user_enter();
 }
 
 void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
index b481341c9369da649908b57c3e8c39b1586b0111..ab82cbda34c7466511f1caa8fe3f08f84b2534db 100644 (file)
@@ -55,6 +55,7 @@
 #include <asm/i387.h>
 #include <asm/fpu-internal.h>
 #include <asm/mce.h>
+#include <asm/rcu.h>
 
 #include <asm/mach_traps.h>
 
@@ -180,11 +181,15 @@ vm86_trap:
 #define DO_ERROR(trapnr, signr, str, name)                             \
 dotraplinkage void do_##name(struct pt_regs *regs, long error_code)    \
 {                                                                      \
-       if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)  \
-                                                       == NOTIFY_STOP) \
+       exception_enter(regs);                                          \
+       if (notify_die(DIE_TRAP, str, regs, error_code,                 \
+                       trapnr, signr) == NOTIFY_STOP) {                \
+               exception_exit(regs);                                   \
                return;                                                 \
+       }                                                               \
        conditional_sti(regs);                                          \
        do_trap(trapnr, signr, str, regs, error_code, NULL);            \
+       exception_exit(regs);                                           \
 }
 
 #define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr)                \
@@ -195,11 +200,15 @@ dotraplinkage void do_##name(struct pt_regs *regs, long error_code)       \
        info.si_errno = 0;                                              \
        info.si_code = sicode;                                          \
        info.si_addr = (void __user *)siaddr;                           \
-       if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr)  \
-                                                       == NOTIFY_STOP) \
+       exception_enter(regs);                                          \
+       if (notify_die(DIE_TRAP, str, regs, error_code,                 \
+                       trapnr, signr) == NOTIFY_STOP) {                \
+               exception_exit(regs);                                   \
                return;                                                 \
+       }                                                               \
        conditional_sti(regs);                                          \
        do_trap(trapnr, signr, str, regs, error_code, &info);           \
+       exception_exit(regs);                                           \
 }
 
 DO_ERROR_INFO(X86_TRAP_DE, SIGFPE, "divide error", divide_error, FPE_INTDIV,
@@ -312,6 +321,7 @@ dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_co
            ftrace_int3_handler(regs))
                return;
 #endif
+       exception_enter(regs);
 #ifdef CONFIG_KGDB_LOW_LEVEL_TRAP
        if (kgdb_ll_trap(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP,
                                SIGTRAP) == NOTIFY_STOP)
@@ -331,6 +341,7 @@ dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_co
        do_trap(X86_TRAP_BP, SIGTRAP, "int3", regs, error_code, NULL);
        preempt_conditional_cli(regs);
        debug_stack_usage_dec();
+       exception_exit(regs);
 }
 
 #ifdef CONFIG_X86_64
@@ -391,6 +402,8 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
        unsigned long dr6;
        int si_code;
 
+       exception_enter(regs);
+
        get_debugreg(dr6, 6);
 
        /* Filter out all the reserved bits which are preset to 1 */
@@ -406,7 +419,7 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
 
        /* Catch kmemcheck conditions first of all! */
        if ((dr6 & DR_STEP) && kmemcheck_trap(regs))
-               return;
+               goto exit;
 
        /* DR6 may or may not be cleared by the CPU */
        set_debugreg(0, 6);
@@ -421,7 +434,7 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
 
        if (notify_die(DIE_DEBUG, "debug", regs, PTR_ERR(&dr6), error_code,
                                                        SIGTRAP) == NOTIFY_STOP)
-               return;
+               goto exit;
 
        /*
         * Let others (NMI) know that the debug stack is in use
@@ -437,7 +450,7 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
                                        X86_TRAP_DB);
                preempt_conditional_cli(regs);
                debug_stack_usage_dec();
-               return;
+               goto exit;
        }
 
        /*
@@ -458,7 +471,8 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
        preempt_conditional_cli(regs);
        debug_stack_usage_dec();
 
-       return;
+exit:
+       exception_exit(regs);
 }
 
 /*
index a28f338843eaa083a046ea69dca78f6e3ff541fe..45c044f0fff7a8a4862a2bf05bbacfbb76d3d407 100644 (file)
@@ -37,6 +37,7 @@ config KVM
        select TASK_DELAY_ACCT
        select PERF_EVENTS
        select HAVE_KVM_MSI
+       select HAVE_KVM_CPU_RELAX_INTERCEPT
        ---help---
          Support hosting fully virtualized guest machines using hardware
          virtualization extensions.  You will need a fairly recent
index 4f579e8dcacf6747a7e3a34db765bf112233680f..04d30401c5cb26aa2b491ad3b0ceeb8d9fa7e8ff 100644 (file)
@@ -12,7 +12,7 @@ kvm-$(CONFIG_IOMMU_API)       += $(addprefix ../../../virt/kvm/, iommu.o)
 kvm-$(CONFIG_KVM_ASYNC_PF)     += $(addprefix ../../../virt/kvm/, async_pf.o)
 
 kvm-y                  += x86.o mmu.o emulate.o i8259.o irq.o lapic.o \
-                          i8254.o timer.o cpuid.o pmu.o
+                          i8254.o cpuid.o pmu.o
 kvm-intel-y            += vmx.o
 kvm-amd-y              += svm.o
 
index 0595f1397b7c0013058afec906e5d329f0d7f7d0..b496da684bd697ce2b50384f310af6d6af26d661 100644 (file)
@@ -316,7 +316,7 @@ static int do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
        }
        case 7: {
                entry->flags |= KVM_CPUID_FLAG_SIGNIFCANT_INDEX;
-               /* Mask ebx against host capbability word 9 */
+               /* Mask ebx against host capability word 9 */
                if (index == 0) {
                        entry->ebx &= kvm_supported_word9_x86_features;
                        cpuid_mask(&entry->ebx, 9);
index 97d9a9914ba8d772e522911252261110cfa58677..10f0136f50c125ac96cb1b713d6f7e69e99dfe67 100644 (file)
@@ -642,7 +642,7 @@ static int __linearize(struct x86_emulate_ctxt *ctxt,
                        if (addr.ea > lim || (u32)(addr.ea + size - 1) > lim)
                                goto bad;
                } else {
-                       /* exapand-down segment */
+                       /* expand-down segment */
                        if (addr.ea <= lim || (u32)(addr.ea + size - 1) <= lim)
                                goto bad;
                        lim = desc.d ? 0xffffffff : 0xffff;
@@ -1166,24 +1166,21 @@ static int read_emulated(struct x86_emulate_ctxt *ctxt,
        int rc;
        struct read_cache *mc = &ctxt->mem_read;
 
-       while (size) {
-               int n = min(size, 8u);
-               size -= n;
-               if (mc->pos < mc->end)
-                       goto read_cached;
+       if (mc->pos < mc->end)
+               goto read_cached;
 
-               rc = ctxt->ops->read_emulated(ctxt, addr, mc->data + mc->end, n,
-                                             &ctxt->exception);
-               if (rc != X86EMUL_CONTINUE)
-                       return rc;
-               mc->end += n;
+       WARN_ON((mc->end + size) >= sizeof(mc->data));
 
-       read_cached:
-               memcpy(dest, mc->data + mc->pos, n);
-               mc->pos += n;
-               dest += n;
-               addr += n;
-       }
+       rc = ctxt->ops->read_emulated(ctxt, addr, mc->data + mc->end, size,
+                                     &ctxt->exception);
+       if (rc != X86EMUL_CONTINUE)
+               return rc;
+
+       mc->end += size;
+
+read_cached:
+       memcpy(dest, mc->data + mc->pos, size);
+       mc->pos += size;
        return X86EMUL_CONTINUE;
 }
 
@@ -1383,7 +1380,7 @@ static int load_segment_descriptor(struct x86_emulate_ctxt *ctxt,
        err_code = selector & 0xfffc;
        err_vec = GP_VECTOR;
 
-       /* can't load system descriptor into segment selecor */
+       /* can't load system descriptor into segment selector */
        if (seg <= VCPU_SREG_GS && !seg_desc.s)
                goto exception;
 
@@ -2038,12 +2035,6 @@ static void
 setup_syscalls_segments(struct x86_emulate_ctxt *ctxt,
                        struct desc_struct *cs, struct desc_struct *ss)
 {
-       u16 selector;
-
-       memset(cs, 0, sizeof(struct desc_struct));
-       ctxt->ops->get_segment(ctxt, &selector, cs, NULL, VCPU_SREG_CS);
-       memset(ss, 0, sizeof(struct desc_struct));
-
        cs->l = 0;              /* will be adjusted later */
        set_desc_base(cs, 0);   /* flat segment */
        cs->g = 1;              /* 4kb granularity */
@@ -2053,6 +2044,7 @@ setup_syscalls_segments(struct x86_emulate_ctxt *ctxt,
        cs->dpl = 0;            /* will be adjusted later */
        cs->p = 1;
        cs->d = 1;
+       cs->avl = 0;
 
        set_desc_base(ss, 0);   /* flat segment */
        set_desc_limit(ss, 0xfffff);    /* 4GB limit */
@@ -2062,6 +2054,8 @@ setup_syscalls_segments(struct x86_emulate_ctxt *ctxt,
        ss->d = 1;              /* 32bit stack segment */
        ss->dpl = 0;
        ss->p = 1;
+       ss->l = 0;
+       ss->avl = 0;
 }
 
 static bool vendor_intel(struct x86_emulate_ctxt *ctxt)
@@ -2398,7 +2392,7 @@ static int load_state_from_tss16(struct x86_emulate_ctxt *ctxt,
        set_segment_selector(ctxt, tss->ds, VCPU_SREG_DS);
 
        /*
-        * Now load segment descriptors. If fault happenes at this stage
+        * Now load segment descriptors. If fault happens at this stage
         * it is handled in a context of new task
         */
        ret = load_segment_descriptor(ctxt, tss->ldt, VCPU_SREG_LDTR);
@@ -2640,7 +2634,7 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt,
         *
         * 1. jmp/call/int to task gate: Check against DPL of the task gate
         * 2. Exception/IRQ/iret: No check is performed
-        * 3. jmp/call to TSS: Check agains DPL of the TSS
+        * 3. jmp/call to TSS: Check against DPL of the TSS
         */
        if (reason == TASK_SWITCH_GATE) {
                if (idt_index != -1) {
@@ -2681,7 +2675,7 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt,
                ctxt->eflags = ctxt->eflags & ~X86_EFLAGS_NT;
 
        /* set back link to prev task only if NT bit is set in eflags
-          note that old_tss_sel is not used afetr this point */
+          note that old_tss_sel is not used after this point */
        if (reason != TASK_SWITCH_CALL && reason != TASK_SWITCH_GATE)
                old_tss_sel = 0xffff;
 
index adba28f88d1a9d56c45e9716ac8dc8a69958144c..11300d2fa71445ff332cbdff30e7c640b959f02d 100644 (file)
@@ -108,7 +108,7 @@ static s64 __kpit_elapsed(struct kvm *kvm)
        ktime_t remaining;
        struct kvm_kpit_state *ps = &kvm->arch.vpit->pit_state;
 
-       if (!ps->pit_timer.period)
+       if (!ps->period)
                return 0;
 
        /*
@@ -120,9 +120,9 @@ static s64 __kpit_elapsed(struct kvm *kvm)
         * itself with the initial count and continues counting
         * from there.
         */
-       remaining = hrtimer_get_remaining(&ps->pit_timer.timer);
-       elapsed = ps->pit_timer.period - ktime_to_ns(remaining);
-       elapsed = mod_64(elapsed, ps->pit_timer.period);
+       remaining = hrtimer_get_remaining(&ps->timer);
+       elapsed = ps->period - ktime_to_ns(remaining);
+       elapsed = mod_64(elapsed, ps->period);
 
        return elapsed;
 }
@@ -238,12 +238,12 @@ static void kvm_pit_ack_irq(struct kvm_irq_ack_notifier *kian)
        int value;
 
        spin_lock(&ps->inject_lock);
-       value = atomic_dec_return(&ps->pit_timer.pending);
+       value = atomic_dec_return(&ps->pending);
        if (value < 0)
                /* spurious acks can be generated if, for example, the
                 * PIC is being reset.  Handle it gracefully here
                 */
-               atomic_inc(&ps->pit_timer.pending);
+               atomic_inc(&ps->pending);
        else if (value > 0)
                /* in this case, we had multiple outstanding pit interrupts
                 * that we needed to inject.  Reinject
@@ -261,28 +261,17 @@ void __kvm_migrate_pit_timer(struct kvm_vcpu *vcpu)
        if (!kvm_vcpu_is_bsp(vcpu) || !pit)
                return;
 
-       timer = &pit->pit_state.pit_timer.timer;
+       timer = &pit->pit_state.timer;
        if (hrtimer_cancel(timer))
                hrtimer_start_expires(timer, HRTIMER_MODE_ABS);
 }
 
 static void destroy_pit_timer(struct kvm_pit *pit)
 {
-       hrtimer_cancel(&pit->pit_state.pit_timer.timer);
+       hrtimer_cancel(&pit->pit_state.timer);
        flush_kthread_work(&pit->expired);
 }
 
-static bool kpit_is_periodic(struct kvm_timer *ktimer)
-{
-       struct kvm_kpit_state *ps = container_of(ktimer, struct kvm_kpit_state,
-                                                pit_timer);
-       return ps->is_periodic;
-}
-
-static struct kvm_timer_ops kpit_ops = {
-       .is_periodic = kpit_is_periodic,
-};
-
 static void pit_do_work(struct kthread_work *work)
 {
        struct kvm_pit *pit = container_of(work, struct kvm_pit, expired);
@@ -322,16 +311,16 @@ static void pit_do_work(struct kthread_work *work)
 
 static enum hrtimer_restart pit_timer_fn(struct hrtimer *data)
 {
-       struct kvm_timer *ktimer = container_of(data, struct kvm_timer, timer);
-       struct kvm_pit *pt = ktimer->kvm->arch.vpit;
+       struct kvm_kpit_state *ps = container_of(data, struct kvm_kpit_state, timer);
+       struct kvm_pit *pt = ps->kvm->arch.vpit;
 
-       if (ktimer->reinject || !atomic_read(&ktimer->pending)) {
-               atomic_inc(&ktimer->pending);
+       if (ps->reinject || !atomic_read(&ps->pending)) {
+               atomic_inc(&ps->pending);
                queue_kthread_work(&pt->worker, &pt->expired);
        }
 
-       if (ktimer->t_ops->is_periodic(ktimer)) {
-               hrtimer_add_expires_ns(&ktimer->timer, ktimer->period);
+       if (ps->is_periodic) {
+               hrtimer_add_expires_ns(&ps->timer, ps->period);
                return HRTIMER_RESTART;
        } else
                return HRTIMER_NORESTART;
@@ -340,7 +329,6 @@ static enum hrtimer_restart pit_timer_fn(struct hrtimer *data)
 static void create_pit_timer(struct kvm *kvm, u32 val, int is_period)
 {
        struct kvm_kpit_state *ps = &kvm->arch.vpit->pit_state;
-       struct kvm_timer *pt = &ps->pit_timer;
        s64 interval;
 
        if (!irqchip_in_kernel(kvm) || ps->flags & KVM_PIT_FLAGS_HPET_LEGACY)
@@ -351,19 +339,18 @@ static void create_pit_timer(struct kvm *kvm, u32 val, int is_period)
        pr_debug("create pit timer, interval is %llu nsec\n", interval);
 
        /* TODO The new value only affected after the retriggered */
-       hrtimer_cancel(&pt->timer);
+       hrtimer_cancel(&ps->timer);
        flush_kthread_work(&ps->pit->expired);
-       pt->period = interval;
+       ps->period = interval;
        ps->is_periodic = is_period;
 
-       pt->timer.function = pit_timer_fn;
-       pt->t_ops = &kpit_ops;
-       pt->kvm = ps->pit->kvm;
+       ps->timer.function = pit_timer_fn;
+       ps->kvm = ps->pit->kvm;
 
-       atomic_set(&pt->pending, 0);
+       atomic_set(&ps->pending, 0);
        ps->irq_ack = 1;
 
-       hrtimer_start(&pt->timer, ktime_add_ns(ktime_get(), interval),
+       hrtimer_start(&ps->timer, ktime_add_ns(ktime_get(), interval),
                      HRTIMER_MODE_ABS);
 }
 
@@ -639,7 +626,7 @@ void kvm_pit_reset(struct kvm_pit *pit)
        }
        mutex_unlock(&pit->pit_state.lock);
 
-       atomic_set(&pit->pit_state.pit_timer.pending, 0);
+       atomic_set(&pit->pit_state.pending, 0);
        pit->pit_state.irq_ack = 1;
 }
 
@@ -648,7 +635,7 @@ static void pit_mask_notifer(struct kvm_irq_mask_notifier *kimn, bool mask)
        struct kvm_pit *pit = container_of(kimn, struct kvm_pit, mask_notifier);
 
        if (!mask) {
-               atomic_set(&pit->pit_state.pit_timer.pending, 0);
+               atomic_set(&pit->pit_state.pending, 0);
                pit->pit_state.irq_ack = 1;
        }
 }
@@ -706,12 +693,11 @@ struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags)
 
        pit_state = &pit->pit_state;
        pit_state->pit = pit;
-       hrtimer_init(&pit_state->pit_timer.timer,
-                    CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+       hrtimer_init(&pit_state->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
        pit_state->irq_ack_notifier.gsi = 0;
        pit_state->irq_ack_notifier.irq_acked = kvm_pit_ack_irq;
        kvm_register_irq_ack_notifier(kvm, &pit_state->irq_ack_notifier);
-       pit_state->pit_timer.reinject = true;
+       pit_state->reinject = true;
        mutex_unlock(&pit->pit_state.lock);
 
        kvm_pit_reset(pit);
@@ -761,7 +747,7 @@ void kvm_free_pit(struct kvm *kvm)
                kvm_unregister_irq_ack_notifier(kvm,
                                &kvm->arch.vpit->pit_state.irq_ack_notifier);
                mutex_lock(&kvm->arch.vpit->pit_state.lock);
-               timer = &kvm->arch.vpit->pit_state.pit_timer.timer;
+               timer = &kvm->arch.vpit->pit_state.timer;
                hrtimer_cancel(timer);
                flush_kthread_work(&kvm->arch.vpit->expired);
                kthread_stop(kvm->arch.vpit->worker_task);
index fdf40425ea1de2946bd40e31a1d1a6045ccdcb15..dd1b16b611b0ae6c9d2386a7e690e56a774f0b74 100644 (file)
@@ -24,8 +24,12 @@ struct kvm_kpit_channel_state {
 struct kvm_kpit_state {
        struct kvm_kpit_channel_state channels[3];
        u32 flags;
-       struct kvm_timer pit_timer;
        bool is_periodic;
+       s64 period;                             /* unit: ns */
+       struct hrtimer timer;
+       atomic_t pending;                       /* accumulated triggered timers */
+       bool reinject;
+       struct kvm *kvm;
        u32    speaker_data_on;
        struct mutex lock;
        struct kvm_pit *pit;
index 1df8fb9e1d5dafc47000ef644823a748c1b31c91..e498b18f010c7b97480ccf1f1018c87a5f07daa1 100644 (file)
@@ -316,6 +316,11 @@ static void pic_ioport_write(void *opaque, u32 addr, u32 val)
        addr &= 1;
        if (addr == 0) {
                if (val & 0x10) {
+                       u8 edge_irr = s->irr & ~s->elcr;
+                       int i;
+                       bool found;
+                       struct kvm_vcpu *vcpu;
+
                        s->init4 = val & 1;
                        s->last_irr = 0;
                        s->irr &= s->elcr;
@@ -333,6 +338,18 @@ static void pic_ioport_write(void *opaque, u32 addr, u32 val)
                        if (val & 0x08)
                                pr_pic_unimpl(
                                        "level sensitive irq not supported");
+
+                       kvm_for_each_vcpu(i, vcpu, s->pics_state->kvm)
+                               if (kvm_apic_accept_pic_intr(vcpu)) {
+                                       found = true;
+                                       break;
+                               }
+
+
+                       if (found)
+                               for (irq = 0; irq < PIC_NUM_PINS/2; irq++)
+                                       if (edge_irr & (1 << irq))
+                                               pic_clear_isr(s, irq);
                } else if (val & 0x08) {
                        if (val & 0x04)
                                s->poll = 1;
index 2086f2bfba33db1d11a119ef57fa82aa01763804..2d03568e9498356716b7504c195c71a912819f4d 100644 (file)
@@ -70,7 +70,7 @@ struct kvm_pic {
        struct kvm_io_device dev_slave;
        struct kvm_io_device dev_eclr;
        void (*ack_notifier)(void *opaque, int irq);
-       unsigned long irq_states[16];
+       unsigned long irq_states[PIC_NUM_PINS];
 };
 
 struct kvm_pic *kvm_create_pic(struct kvm *kvm);
diff --git a/arch/x86/kvm/kvm_timer.h b/arch/x86/kvm/kvm_timer.h
deleted file mode 100644 (file)
index 497dbaa..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-
-struct kvm_timer {
-       struct hrtimer timer;
-       s64 period;                             /* unit: ns */
-       u32 timer_mode_mask;
-       u64 tscdeadline;
-       atomic_t pending;                       /* accumulated triggered timers */
-       bool reinject;
-       struct kvm_timer_ops *t_ops;
-       struct kvm *kvm;
-       struct kvm_vcpu *vcpu;
-};
-
-struct kvm_timer_ops {
-       bool (*is_periodic)(struct kvm_timer *);
-};
-
-enum hrtimer_restart kvm_timer_fn(struct hrtimer *data);
index ce878788a39fd13e486fd3557011d5bf28a47d2d..18d149d802091e47c1eb7290bd14fe2795138396 100644 (file)
@@ -34,6 +34,7 @@
 #include <asm/current.h>
 #include <asm/apicdef.h>
 #include <linux/atomic.h>
+#include <linux/jump_label.h>
 #include "kvm_cache_regs.h"
 #include "irq.h"
 #include "trace.h"
 static unsigned int min_timer_period_us = 500;
 module_param(min_timer_period_us, uint, S_IRUGO | S_IWUSR);
 
-static inline u32 apic_get_reg(struct kvm_lapic *apic, int reg_off)
-{
-       return *((u32 *) (apic->regs + reg_off));
-}
-
 static inline void apic_set_reg(struct kvm_lapic *apic, int reg_off, u32 val)
 {
        *((u32 *) (apic->regs + reg_off)) = val;
@@ -117,19 +113,23 @@ static inline int __apic_test_and_clear_vector(int vec, void *bitmap)
        return __test_and_clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
 }
 
-static inline int apic_hw_enabled(struct kvm_lapic *apic)
-{
-       return (apic)->vcpu->arch.apic_base & MSR_IA32_APICBASE_ENABLE;
-}
+struct static_key_deferred apic_hw_disabled __read_mostly;
+struct static_key_deferred apic_sw_disabled __read_mostly;
 
-static inline int  apic_sw_enabled(struct kvm_lapic *apic)
+static inline void apic_set_spiv(struct kvm_lapic *apic, u32 val)
 {
-       return apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_APIC_ENABLED;
+       if ((kvm_apic_get_reg(apic, APIC_SPIV) ^ val) & APIC_SPIV_APIC_ENABLED) {
+               if (val & APIC_SPIV_APIC_ENABLED)
+                       static_key_slow_dec_deferred(&apic_sw_disabled);
+               else
+                       static_key_slow_inc(&apic_sw_disabled.key);
+       }
+       apic_set_reg(apic, APIC_SPIV, val);
 }
 
 static inline int apic_enabled(struct kvm_lapic *apic)
 {
-       return apic_sw_enabled(apic) && apic_hw_enabled(apic);
+       return kvm_apic_sw_enabled(apic) &&     kvm_apic_hw_enabled(apic);
 }
 
 #define LVT_MASK       \
@@ -141,34 +141,34 @@ static inline int apic_enabled(struct kvm_lapic *apic)
 
 static inline int kvm_apic_id(struct kvm_lapic *apic)
 {
-       return (apic_get_reg(apic, APIC_ID) >> 24) & 0xff;
+       return (kvm_apic_get_reg(apic, APIC_ID) >> 24) & 0xff;
 }
 
 static inline int apic_lvt_enabled(struct kvm_lapic *apic, int lvt_type)
 {
-       return !(apic_get_reg(apic, lvt_type) & APIC_LVT_MASKED);
+       return !(kvm_apic_get_reg(apic, lvt_type) & APIC_LVT_MASKED);
 }
 
 static inline int apic_lvt_vector(struct kvm_lapic *apic, int lvt_type)
 {
-       return apic_get_reg(apic, lvt_type) & APIC_VECTOR_MASK;
+       return kvm_apic_get_reg(apic, lvt_type) & APIC_VECTOR_MASK;
 }
 
 static inline int apic_lvtt_oneshot(struct kvm_lapic *apic)
 {
-       return ((apic_get_reg(apic, APIC_LVTT) &
+       return ((kvm_apic_get_reg(apic, APIC_LVTT) &
                apic->lapic_timer.timer_mode_mask) == APIC_LVT_TIMER_ONESHOT);
 }
 
 static inline int apic_lvtt_period(struct kvm_lapic *apic)
 {
-       return ((apic_get_reg(apic, APIC_LVTT) &
+       return ((kvm_apic_get_reg(apic, APIC_LVTT) &
                apic->lapic_timer.timer_mode_mask) == APIC_LVT_TIMER_PERIODIC);
 }
 
 static inline int apic_lvtt_tscdeadline(struct kvm_lapic *apic)
 {
-       return ((apic_get_reg(apic, APIC_LVTT) &
+       return ((kvm_apic_get_reg(apic, APIC_LVTT) &
                apic->lapic_timer.timer_mode_mask) ==
                        APIC_LVT_TIMER_TSCDEADLINE);
 }
@@ -184,7 +184,7 @@ void kvm_apic_set_version(struct kvm_vcpu *vcpu)
        struct kvm_cpuid_entry2 *feat;
        u32 v = APIC_VERSION;
 
-       if (!irqchip_in_kernel(vcpu->kvm))
+       if (!kvm_vcpu_has_lapic(vcpu))
                return;
 
        feat = kvm_find_cpuid_entry(apic->vcpu, 0x1, 0);
@@ -285,7 +285,6 @@ static inline void apic_clear_isr(int vec, struct kvm_lapic *apic)
 
 int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu)
 {
-       struct kvm_lapic *apic = vcpu->arch.apic;
        int highest_irr;
 
        /* This may race with setting of irr in __apic_accept_irq() and
@@ -293,9 +292,9 @@ int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu)
         * will cause vmexit immediately and the value will be recalculated
         * on the next vmentry.
         */
-       if (!apic)
+       if (!kvm_vcpu_has_lapic(vcpu))
                return 0;
-       highest_irr = apic_find_highest_irr(apic);
+       highest_irr = apic_find_highest_irr(vcpu->arch.apic);
 
        return highest_irr;
 }
@@ -378,8 +377,8 @@ static void apic_update_ppr(struct kvm_lapic *apic)
        u32 tpr, isrv, ppr, old_ppr;
        int isr;
 
-       old_ppr = apic_get_reg(apic, APIC_PROCPRI);
-       tpr = apic_get_reg(apic, APIC_TASKPRI);
+       old_ppr = kvm_apic_get_reg(apic, APIC_PROCPRI);
+       tpr = kvm_apic_get_reg(apic, APIC_TASKPRI);
        isr = apic_find_highest_isr(apic);
        isrv = (isr != -1) ? isr : 0;
 
@@ -415,13 +414,13 @@ int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda)
        u32 logical_id;
 
        if (apic_x2apic_mode(apic)) {
-               logical_id = apic_get_reg(apic, APIC_LDR);
+               logical_id = kvm_apic_get_reg(apic, APIC_LDR);
                return logical_id & mda;
        }
 
-       logical_id = GET_APIC_LOGICAL_ID(apic_get_reg(apic, APIC_LDR));
+       logical_id = GET_APIC_LOGICAL_ID(kvm_apic_get_reg(apic, APIC_LDR));
 
-       switch (apic_get_reg(apic, APIC_DFR)) {
+       switch (kvm_apic_get_reg(apic, APIC_DFR)) {
        case APIC_DFR_FLAT:
                if (logical_id & mda)
                        result = 1;
@@ -433,7 +432,7 @@ int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda)
                break;
        default:
                apic_debug("Bad DFR vcpu %d: %08x\n",
-                          apic->vcpu->vcpu_id, apic_get_reg(apic, APIC_DFR));
+                          apic->vcpu->vcpu_id, kvm_apic_get_reg(apic, APIC_DFR));
                break;
        }
 
@@ -591,7 +590,7 @@ static int apic_set_eoi(struct kvm_lapic *apic)
        apic_clear_isr(vector, apic);
        apic_update_ppr(apic);
 
-       if (!(apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI) &&
+       if (!(kvm_apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI) &&
            kvm_ioapic_handles_vector(apic->vcpu->kvm, vector)) {
                int trigger_mode;
                if (apic_test_vector(vector, apic->regs + APIC_TMR))
@@ -606,8 +605,8 @@ static int apic_set_eoi(struct kvm_lapic *apic)
 
 static void apic_send_ipi(struct kvm_lapic *apic)
 {
-       u32 icr_low = apic_get_reg(apic, APIC_ICR);
-       u32 icr_high = apic_get_reg(apic, APIC_ICR2);
+       u32 icr_low = kvm_apic_get_reg(apic, APIC_ICR);
+       u32 icr_high = kvm_apic_get_reg(apic, APIC_ICR2);
        struct kvm_lapic_irq irq;
 
        irq.vector = icr_low & APIC_VECTOR_MASK;
@@ -642,7 +641,7 @@ static u32 apic_get_tmcct(struct kvm_lapic *apic)
        ASSERT(apic != NULL);
 
        /* if initial count is 0, current count should also be 0 */
-       if (apic_get_reg(apic, APIC_TMICT) == 0)
+       if (kvm_apic_get_reg(apic, APIC_TMICT) == 0)
                return 0;
 
        remaining = hrtimer_get_remaining(&apic->lapic_timer.timer);
@@ -696,13 +695,15 @@ static u32 __apic_read(struct kvm_lapic *apic, unsigned int offset)
 
                val = apic_get_tmcct(apic);
                break;
-
+       case APIC_PROCPRI:
+               apic_update_ppr(apic);
+               val = kvm_apic_get_reg(apic, offset);
+               break;
        case APIC_TASKPRI:
                report_tpr_access(apic, false);
                /* fall thru */
        default:
-               apic_update_ppr(apic);
-               val = apic_get_reg(apic, offset);
+               val = kvm_apic_get_reg(apic, offset);
                break;
        }
 
@@ -719,7 +720,7 @@ static int apic_reg_read(struct kvm_lapic *apic, u32 offset, int len,
 {
        unsigned char alignment = offset & 0xf;
        u32 result;
-       /* this bitmask has a bit cleared for each reserver register */
+       /* this bitmask has a bit cleared for each reserved register */
        static const u64 rmask = 0x43ff01ffffffe70cULL;
 
        if ((alignment + len) > 4) {
@@ -754,7 +755,7 @@ static int apic_reg_read(struct kvm_lapic *apic, u32 offset, int len,
 
 static int apic_mmio_in_range(struct kvm_lapic *apic, gpa_t addr)
 {
-       return apic_hw_enabled(apic) &&
+       return kvm_apic_hw_enabled(apic) &&
            addr >= apic->base_address &&
            addr < apic->base_address + LAPIC_MMIO_LENGTH;
 }
@@ -777,7 +778,7 @@ static void update_divide_count(struct kvm_lapic *apic)
 {
        u32 tmp1, tmp2, tdcr;
 
-       tdcr = apic_get_reg(apic, APIC_TDCR);
+       tdcr = kvm_apic_get_reg(apic, APIC_TDCR);
        tmp1 = tdcr & 0xf;
        tmp2 = ((tmp1 & 0x3) | ((tmp1 & 0x8) >> 1)) + 1;
        apic->divide_count = 0x1 << (tmp2 & 0x7);
@@ -792,9 +793,9 @@ static void start_apic_timer(struct kvm_lapic *apic)
        atomic_set(&apic->lapic_timer.pending, 0);
 
        if (apic_lvtt_period(apic) || apic_lvtt_oneshot(apic)) {
-               /* lapic timer in oneshot or peroidic mode */
+               /* lapic timer in oneshot or periodic mode */
                now = apic->lapic_timer.timer.base->get_time();
-               apic->lapic_timer.period = (u64)apic_get_reg(apic, APIC_TMICT)
+               apic->lapic_timer.period = (u64)kvm_apic_get_reg(apic, APIC_TMICT)
                            * APIC_BUS_CYCLE_NS * apic->divide_count;
 
                if (!apic->lapic_timer.period)
@@ -826,7 +827,7 @@ static void start_apic_timer(struct kvm_lapic *apic)
                           "timer initial count 0x%x, period %lldns, "
                           "expire @ 0x%016" PRIx64 ".\n", __func__,
                           APIC_BUS_CYCLE_NS, ktime_to_ns(now),
-                          apic_get_reg(apic, APIC_TMICT),
+                          kvm_apic_get_reg(apic, APIC_TMICT),
                           apic->lapic_timer.period,
                           ktime_to_ns(ktime_add_ns(now,
                                        apic->lapic_timer.period)));
@@ -858,7 +859,7 @@ static void start_apic_timer(struct kvm_lapic *apic)
 
 static void apic_manage_nmi_watchdog(struct kvm_lapic *apic, u32 lvt0_val)
 {
-       int nmi_wd_enabled = apic_lvt_nmi_mode(apic_get_reg(apic, APIC_LVT0));
+       int nmi_wd_enabled = apic_lvt_nmi_mode(kvm_apic_get_reg(apic, APIC_LVT0));
 
        if (apic_lvt_nmi_mode(lvt0_val)) {
                if (!nmi_wd_enabled) {
@@ -909,15 +910,15 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
 
        case APIC_SPIV: {
                u32 mask = 0x3ff;
-               if (apic_get_reg(apic, APIC_LVR) & APIC_LVR_DIRECTED_EOI)
+               if (kvm_apic_get_reg(apic, APIC_LVR) & APIC_LVR_DIRECTED_EOI)
                        mask |= APIC_SPIV_DIRECTED_EOI;
-               apic_set_reg(apic, APIC_SPIV, val & mask);
+               apic_set_spiv(apic, val & mask);
                if (!(val & APIC_SPIV_APIC_ENABLED)) {
                        int i;
                        u32 lvt_val;
 
                        for (i = 0; i < APIC_LVT_NUM; i++) {
-                               lvt_val = apic_get_reg(apic,
+                               lvt_val = kvm_apic_get_reg(apic,
                                                       APIC_LVTT + 0x10 * i);
                                apic_set_reg(apic, APIC_LVTT + 0x10 * i,
                                             lvt_val | APIC_LVT_MASKED);
@@ -946,7 +947,7 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
        case APIC_LVT1:
        case APIC_LVTERR:
                /* TODO: Check vector */
-               if (!apic_sw_enabled(apic))
+               if (!kvm_apic_sw_enabled(apic))
                        val |= APIC_LVT_MASKED;
 
                val &= apic_lvt_mask[(reg - APIC_LVTT) >> 4];
@@ -955,12 +956,12 @@ static int apic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val)
                break;
 
        case APIC_LVTT:
-               if ((apic_get_reg(apic, APIC_LVTT) &
+               if ((kvm_apic_get_reg(apic, APIC_LVTT) &
                    apic->lapic_timer.timer_mode_mask) !=
                   (val & apic->lapic_timer.timer_mode_mask))
                        hrtimer_cancel(&apic->lapic_timer.timer);
 
-               if (!apic_sw_enabled(apic))
+               if (!kvm_apic_sw_enabled(apic))
                        val |= APIC_LVT_MASKED;
                val &= (apic_lvt_mask[0] | apic->lapic_timer.timer_mode_mask);
                apic_set_reg(apic, APIC_LVTT, val);
@@ -1039,24 +1040,30 @@ static int apic_mmio_write(struct kvm_io_device *this,
 
 void kvm_lapic_set_eoi(struct kvm_vcpu *vcpu)
 {
-       struct kvm_lapic *apic = vcpu->arch.apic;
-
-       if (apic)
+       if (kvm_vcpu_has_lapic(vcpu))
                apic_reg_write(vcpu->arch.apic, APIC_EOI, 0);
 }
 EXPORT_SYMBOL_GPL(kvm_lapic_set_eoi);
 
 void kvm_free_lapic(struct kvm_vcpu *vcpu)
 {
+       struct kvm_lapic *apic = vcpu->arch.apic;
+
        if (!vcpu->arch.apic)
                return;
 
-       hrtimer_cancel(&vcpu->arch.apic->lapic_timer.timer);
+       hrtimer_cancel(&apic->lapic_timer.timer);
+
+       if (!(vcpu->arch.apic_base & MSR_IA32_APICBASE_ENABLE))
+               static_key_slow_dec_deferred(&apic_hw_disabled);
+
+       if (!(kvm_apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_APIC_ENABLED))
+               static_key_slow_dec_deferred(&apic_sw_disabled);
 
-       if (vcpu->arch.apic->regs)
-               free_page((unsigned long)vcpu->arch.apic->regs);
+       if (apic->regs)
+               free_page((unsigned long)apic->regs);
 
-       kfree(vcpu->arch.apic);
+       kfree(apic);
 }
 
 /*
@@ -1068,10 +1075,9 @@ void kvm_free_lapic(struct kvm_vcpu *vcpu)
 u64 kvm_get_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu)
 {
        struct kvm_lapic *apic = vcpu->arch.apic;
-       if (!apic)
-               return 0;
 
-       if (apic_lvtt_oneshot(apic) || apic_lvtt_period(apic))
+       if (!kvm_vcpu_has_lapic(vcpu) || apic_lvtt_oneshot(apic) ||
+                       apic_lvtt_period(apic))
                return 0;
 
        return apic->lapic_timer.tscdeadline;
@@ -1080,10 +1086,9 @@ u64 kvm_get_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu)
 void kvm_set_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu, u64 data)
 {
        struct kvm_lapic *apic = vcpu->arch.apic;
-       if (!apic)
-               return;
 
-       if (apic_lvtt_oneshot(apic) || apic_lvtt_period(apic))
+       if (!kvm_vcpu_has_lapic(vcpu) || apic_lvtt_oneshot(apic) ||
+                       apic_lvtt_period(apic))
                return;
 
        hrtimer_cancel(&apic->lapic_timer.timer);
@@ -1095,20 +1100,21 @@ void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8)
 {
        struct kvm_lapic *apic = vcpu->arch.apic;
 
-       if (!apic)
+       if (!kvm_vcpu_has_lapic(vcpu))
                return;
+
        apic_set_tpr(apic, ((cr8 & 0x0f) << 4)
-                    | (apic_get_reg(apic, APIC_TASKPRI) & 4));
+                    | (kvm_apic_get_reg(apic, APIC_TASKPRI) & 4));
 }
 
 u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu)
 {
-       struct kvm_lapic *apic = vcpu->arch.apic;
        u64 tpr;
 
-       if (!apic)
+       if (!kvm_vcpu_has_lapic(vcpu))
                return 0;
-       tpr = (u64) apic_get_reg(apic, APIC_TASKPRI);
+
+       tpr = (u64) kvm_apic_get_reg(vcpu->arch.apic, APIC_TASKPRI);
 
        return (tpr & 0xf0) >> 4;
 }
@@ -1123,6 +1129,14 @@ void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value)
                return;
        }
 
+       /* update jump label if enable bit changes */
+       if ((vcpu->arch.apic_base ^ value) & MSR_IA32_APICBASE_ENABLE) {
+               if (value & MSR_IA32_APICBASE_ENABLE)
+                       static_key_slow_dec_deferred(&apic_hw_disabled);
+               else
+                       static_key_slow_inc(&apic_hw_disabled.key);
+       }
+
        if (!kvm_vcpu_is_bsp(apic->vcpu))
                value &= ~MSR_IA32_APICBASE_BSP;
 
@@ -1164,7 +1178,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu)
                     SET_APIC_DELIVERY_MODE(0, APIC_MODE_EXTINT));
 
        apic_set_reg(apic, APIC_DFR, 0xffffffffU);
-       apic_set_reg(apic, APIC_SPIV, 0xff);
+       apic_set_spiv(apic, 0xff);
        apic_set_reg(apic, APIC_TASKPRI, 0);
        apic_set_reg(apic, APIC_LDR, 0);
        apic_set_reg(apic, APIC_ESR, 0);
@@ -1183,7 +1197,8 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu)
        update_divide_count(apic);
        atomic_set(&apic->lapic_timer.pending, 0);
        if (kvm_vcpu_is_bsp(vcpu))
-               vcpu->arch.apic_base |= MSR_IA32_APICBASE_BSP;
+               kvm_lapic_set_base(vcpu,
+                               vcpu->arch.apic_base | MSR_IA32_APICBASE_BSP);
        vcpu->arch.pv_eoi.msr_val = 0;
        apic_update_ppr(apic);
 
@@ -1196,45 +1211,34 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu)
                   vcpu->arch.apic_base, apic->base_address);
 }
 
-bool kvm_apic_present(struct kvm_vcpu *vcpu)
-{
-       return vcpu->arch.apic && apic_hw_enabled(vcpu->arch.apic);
-}
-
-int kvm_lapic_enabled(struct kvm_vcpu *vcpu)
-{
-       return kvm_apic_present(vcpu) && apic_sw_enabled(vcpu->arch.apic);
-}
-
 /*
  *----------------------------------------------------------------------
  * timer interface
  *----------------------------------------------------------------------
  */
 
-static bool lapic_is_periodic(struct kvm_timer *ktimer)
+static bool lapic_is_periodic(struct kvm_lapic *apic)
 {
-       struct kvm_lapic *apic = container_of(ktimer, struct kvm_lapic,
-                                             lapic_timer);
        return apic_lvtt_period(apic);
 }
 
 int apic_has_pending_timer(struct kvm_vcpu *vcpu)
 {
-       struct kvm_lapic *lapic = vcpu->arch.apic;
+       struct kvm_lapic *apic = vcpu->arch.apic;
 
-       if (lapic && apic_enabled(lapic) && apic_lvt_enabled(lapic, APIC_LVTT))
-               return atomic_read(&lapic->lapic_timer.pending);
+       if (kvm_vcpu_has_lapic(vcpu) && apic_enabled(apic) &&
+                       apic_lvt_enabled(apic, APIC_LVTT))
+               return atomic_read(&apic->lapic_timer.pending);
 
        return 0;
 }
 
 int kvm_apic_local_deliver(struct kvm_lapic *apic, int lvt_type)
 {
-       u32 reg = apic_get_reg(apic, lvt_type);
+       u32 reg = kvm_apic_get_reg(apic, lvt_type);
        int vector, mode, trig_mode;
 
-       if (apic_hw_enabled(apic) && !(reg & APIC_LVT_MASKED)) {
+       if (kvm_apic_hw_enabled(apic) && !(reg & APIC_LVT_MASKED)) {
                vector = reg & APIC_VECTOR_MASK;
                mode = reg & APIC_MODE_MASK;
                trig_mode = reg & APIC_LVT_LEVEL_TRIGGER;
@@ -1251,15 +1255,40 @@ void kvm_apic_nmi_wd_deliver(struct kvm_vcpu *vcpu)
                kvm_apic_local_deliver(apic, APIC_LVT0);
 }
 
-static struct kvm_timer_ops lapic_timer_ops = {
-       .is_periodic = lapic_is_periodic,
-};
-
 static const struct kvm_io_device_ops apic_mmio_ops = {
        .read     = apic_mmio_read,
        .write    = apic_mmio_write,
 };
 
+static enum hrtimer_restart apic_timer_fn(struct hrtimer *data)
+{
+       struct kvm_timer *ktimer = container_of(data, struct kvm_timer, timer);
+       struct kvm_lapic *apic = container_of(ktimer, struct kvm_lapic, lapic_timer);
+       struct kvm_vcpu *vcpu = apic->vcpu;
+       wait_queue_head_t *q = &vcpu->wq;
+
+       /*
+        * There is a race window between reading and incrementing, but we do
+        * not care about potentially losing timer events in the !reinject
+        * case anyway. Note: KVM_REQ_PENDING_TIMER is implicitly checked
+        * in vcpu_enter_guest.
+        */
+       if (!atomic_read(&ktimer->pending)) {
+               atomic_inc(&ktimer->pending);
+               /* FIXME: this code should not know anything about vcpus */
+               kvm_make_request(KVM_REQ_PENDING_TIMER, vcpu);
+       }
+
+       if (waitqueue_active(q))
+               wake_up_interruptible(q);
+
+       if (lapic_is_periodic(apic)) {
+               hrtimer_add_expires_ns(&ktimer->timer, ktimer->period);
+               return HRTIMER_RESTART;
+       } else
+               return HRTIMER_NORESTART;
+}
+
 int kvm_create_lapic(struct kvm_vcpu *vcpu)
 {
        struct kvm_lapic *apic;
@@ -1283,14 +1312,17 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu)
 
        hrtimer_init(&apic->lapic_timer.timer, CLOCK_MONOTONIC,
                     HRTIMER_MODE_ABS);
-       apic->lapic_timer.timer.function = kvm_timer_fn;
-       apic->lapic_timer.t_ops = &lapic_timer_ops;
-       apic->lapic_timer.kvm = vcpu->kvm;
-       apic->lapic_timer.vcpu = vcpu;
+       apic->lapic_timer.timer.function = apic_timer_fn;
 
-       apic->base_address = APIC_DEFAULT_PHYS_BASE;
-       vcpu->arch.apic_base = APIC_DEFAULT_PHYS_BASE;
+       /*
+        * APIC is created enabled. This will prevent kvm_lapic_set_base from
+        * thinking that APIC satet has changed.
+        */
+       vcpu->arch.apic_base = MSR_IA32_APICBASE_ENABLE;
+       kvm_lapic_set_base(vcpu,
+                       APIC_DEFAULT_PHYS_BASE | MSR_IA32_APICBASE_ENABLE);
 
+       static_key_slow_inc(&apic_sw_disabled.key); /* sw disabled at reset */
        kvm_lapic_reset(vcpu);
        kvm_iodevice_init(&apic->dev, &apic_mmio_ops);
 
@@ -1306,23 +1338,23 @@ int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu)
        struct kvm_lapic *apic = vcpu->arch.apic;
        int highest_irr;
 
-       if (!apic || !apic_enabled(apic))
+       if (!kvm_vcpu_has_lapic(vcpu) || !apic_enabled(apic))
                return -1;
 
        apic_update_ppr(apic);
        highest_irr = apic_find_highest_irr(apic);
        if ((highest_irr == -1) ||
-           ((highest_irr & 0xF0) <= apic_get_reg(apic, APIC_PROCPRI)))
+           ((highest_irr & 0xF0) <= kvm_apic_get_reg(apic, APIC_PROCPRI)))
                return -1;
        return highest_irr;
 }
 
 int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu)
 {
-       u32 lvt0 = apic_get_reg(vcpu->arch.apic, APIC_LVT0);
+       u32 lvt0 = kvm_apic_get_reg(vcpu->arch.apic, APIC_LVT0);
        int r = 0;
 
-       if (!apic_hw_enabled(vcpu->arch.apic))
+       if (!kvm_apic_hw_enabled(vcpu->arch.apic))
                r = 1;
        if ((lvt0 & APIC_LVT_MASKED) == 0 &&
            GET_APIC_DELIVERY_MODE(lvt0) == APIC_MODE_EXTINT)
@@ -1334,7 +1366,10 @@ void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu)
 {
        struct kvm_lapic *apic = vcpu->arch.apic;
 
-       if (apic && atomic_read(&apic->lapic_timer.pending) > 0) {
+       if (!kvm_vcpu_has_lapic(vcpu))
+               return;
+
+       if (atomic_read(&apic->lapic_timer.pending) > 0) {
                if (kvm_apic_local_deliver(apic, APIC_LVTT))
                        atomic_dec(&apic->lapic_timer.pending);
        }
@@ -1354,12 +1389,15 @@ int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu)
        return vector;
 }
 
-void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu)
+void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu,
+               struct kvm_lapic_state *s)
 {
        struct kvm_lapic *apic = vcpu->arch.apic;
 
-       apic->base_address = vcpu->arch.apic_base &
-                            MSR_IA32_APICBASE_BASE;
+       kvm_lapic_set_base(vcpu, vcpu->arch.apic_base);
+       /* set SPIV separately to get count of SW disabled APICs right */
+       apic_set_spiv(apic, *((u32 *)(s->regs + APIC_SPIV)));
+       memcpy(vcpu->arch.apic->regs, s->regs, sizeof *s);
        kvm_apic_set_version(vcpu);
 
        apic_update_ppr(apic);
@@ -1374,13 +1412,12 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu)
 
 void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu)
 {
-       struct kvm_lapic *apic = vcpu->arch.apic;
        struct hrtimer *timer;
 
-       if (!apic)
+       if (!kvm_vcpu_has_lapic(vcpu))
                return;
 
-       timer = &apic->lapic_timer.timer;
+       timer = &vcpu->arch.apic->lapic_timer.timer;
        if (hrtimer_cancel(timer))
                hrtimer_start_expires(timer, HRTIMER_MODE_ABS);
 }
@@ -1478,7 +1515,7 @@ void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu)
        if (!test_bit(KVM_APIC_CHECK_VAPIC, &vcpu->arch.apic_attention))
                return;
 
-       tpr = apic_get_reg(apic, APIC_TASKPRI) & 0xff;
+       tpr = kvm_apic_get_reg(apic, APIC_TASKPRI) & 0xff;
        max_irr = apic_find_highest_irr(apic);
        if (max_irr < 0)
                max_irr = 0;
@@ -1537,7 +1574,7 @@ int kvm_hv_vapic_msr_write(struct kvm_vcpu *vcpu, u32 reg, u64 data)
 {
        struct kvm_lapic *apic = vcpu->arch.apic;
 
-       if (!irqchip_in_kernel(vcpu->kvm))
+       if (!kvm_vcpu_has_lapic(vcpu))
                return 1;
 
        /* if this is ICR write vector before command */
@@ -1551,7 +1588,7 @@ int kvm_hv_vapic_msr_read(struct kvm_vcpu *vcpu, u32 reg, u64 *data)
        struct kvm_lapic *apic = vcpu->arch.apic;
        u32 low, high = 0;
 
-       if (!irqchip_in_kernel(vcpu->kvm))
+       if (!kvm_vcpu_has_lapic(vcpu))
                return 1;
 
        if (apic_reg_read(apic, reg, 4, &low))
@@ -1576,3 +1613,10 @@ int kvm_lapic_enable_pv_eoi(struct kvm_vcpu *vcpu, u64 data)
        return kvm_gfn_to_hva_cache_init(vcpu->kvm, &vcpu->arch.pv_eoi.data,
                                         addr);
 }
+
+void kvm_lapic_init(void)
+{
+       /* do not patch jump label more than once per second */
+       jump_label_rate_limit(&apic_hw_disabled, HZ);
+       jump_label_rate_limit(&apic_sw_disabled, HZ);
+}
index 4af5405ae1e2f4e2822cde6bd844e73f0489e850..615a8b0301685bb0a61ad925d7576375eb5cebb5 100644 (file)
@@ -2,10 +2,17 @@
 #define __KVM_X86_LAPIC_H
 
 #include "iodev.h"
-#include "kvm_timer.h"
 
 #include <linux/kvm_host.h>
 
+struct kvm_timer {
+       struct hrtimer timer;
+       s64 period;                             /* unit: ns */
+       u32 timer_mode_mask;
+       u64 tscdeadline;
+       atomic_t pending;                       /* accumulated triggered timers */
+};
+
 struct kvm_lapic {
        unsigned long base_address;
        struct kvm_io_device dev;
@@ -47,9 +54,8 @@ int kvm_apic_local_deliver(struct kvm_lapic *apic, int lvt_type);
 
 u64 kvm_get_apic_base(struct kvm_vcpu *vcpu);
 void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data);
-void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu);
-int kvm_lapic_enabled(struct kvm_vcpu *vcpu);
-bool kvm_apic_present(struct kvm_vcpu *vcpu);
+void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu,
+               struct kvm_lapic_state *s);
 int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu);
 
 u64 kvm_get_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu);
@@ -71,4 +77,48 @@ static inline bool kvm_hv_vapic_assist_page_enabled(struct kvm_vcpu *vcpu)
 }
 
 int kvm_lapic_enable_pv_eoi(struct kvm_vcpu *vcpu, u64 data);
+void kvm_lapic_init(void);
+
+static inline u32 kvm_apic_get_reg(struct kvm_lapic *apic, int reg_off)
+{
+               return *((u32 *) (apic->regs + reg_off));
+}
+
+extern struct static_key kvm_no_apic_vcpu;
+
+static inline bool kvm_vcpu_has_lapic(struct kvm_vcpu *vcpu)
+{
+       if (static_key_false(&kvm_no_apic_vcpu))
+               return vcpu->arch.apic;
+       return true;
+}
+
+extern struct static_key_deferred apic_hw_disabled;
+
+static inline int kvm_apic_hw_enabled(struct kvm_lapic *apic)
+{
+       if (static_key_false(&apic_hw_disabled.key))
+               return apic->vcpu->arch.apic_base & MSR_IA32_APICBASE_ENABLE;
+       return MSR_IA32_APICBASE_ENABLE;
+}
+
+extern struct static_key_deferred apic_sw_disabled;
+
+static inline int kvm_apic_sw_enabled(struct kvm_lapic *apic)
+{
+       if (static_key_false(&apic_sw_disabled.key))
+               return kvm_apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_APIC_ENABLED;
+       return APIC_SPIV_APIC_ENABLED;
+}
+
+static inline bool kvm_apic_present(struct kvm_vcpu *vcpu)
+{
+       return kvm_vcpu_has_lapic(vcpu) && kvm_apic_hw_enabled(vcpu->arch.apic);
+}
+
+static inline int kvm_lapic_enabled(struct kvm_vcpu *vcpu)
+{
+       return kvm_apic_present(vcpu) && kvm_apic_sw_enabled(vcpu->arch.apic);
+}
+
 #endif
index 01ca00423938515cfe43781403e90bfb84929fc3..9651c2cd000505ee69bd526b5b63d03cc4bb505b 100644 (file)
@@ -556,6 +556,14 @@ static int mmu_spte_clear_track_bits(u64 *sptep)
                return 0;
 
        pfn = spte_to_pfn(old_spte);
+
+       /*
+        * KVM does not hold the refcount of the page used by
+        * kvm mmu, before reclaiming the page, we should
+        * unmap it from mmu first.
+        */
+       WARN_ON(!kvm_is_mmio_pfn(pfn) && !page_count(pfn_to_page(pfn)));
+
        if (!shadow_accessed_mask || old_spte & shadow_accessed_mask)
                kvm_set_pfn_accessed(pfn);
        if (!shadow_dirty_mask || (old_spte & shadow_dirty_mask))
@@ -960,13 +968,10 @@ static void pte_list_walk(unsigned long *pte_list, pte_list_walk_fn fn)
 static unsigned long *__gfn_to_rmap(gfn_t gfn, int level,
                                    struct kvm_memory_slot *slot)
 {
-       struct kvm_lpage_info *linfo;
-
-       if (likely(level == PT_PAGE_TABLE_LEVEL))
-               return &slot->rmap[gfn - slot->base_gfn];
+       unsigned long idx;
 
-       linfo = lpage_info_slot(gfn, slot, level);
-       return &linfo->rmap_pde;
+       idx = gfn_to_index(gfn, slot->base_gfn, level);
+       return &slot->arch.rmap[level - PT_PAGE_TABLE_LEVEL][idx];
 }
 
 /*
@@ -1173,7 +1178,8 @@ void kvm_mmu_write_protect_pt_masked(struct kvm *kvm,
        unsigned long *rmapp;
 
        while (mask) {
-               rmapp = &slot->rmap[gfn_offset + __ffs(mask)];
+               rmapp = __gfn_to_rmap(slot->base_gfn + gfn_offset + __ffs(mask),
+                                     PT_PAGE_TABLE_LEVEL, slot);
                __rmap_write_protect(kvm, rmapp, PT_PAGE_TABLE_LEVEL, false);
 
                /* clear the first set bit */
@@ -1200,7 +1206,7 @@ static bool rmap_write_protect(struct kvm *kvm, u64 gfn)
 }
 
 static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp,
-                          unsigned long data)
+                          struct kvm_memory_slot *slot, unsigned long data)
 {
        u64 *sptep;
        struct rmap_iterator iter;
@@ -1218,7 +1224,7 @@ static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp,
 }
 
 static int kvm_set_pte_rmapp(struct kvm *kvm, unsigned long *rmapp,
-                            unsigned long data)
+                            struct kvm_memory_slot *slot, unsigned long data)
 {
        u64 *sptep;
        struct rmap_iterator iter;
@@ -1259,43 +1265,67 @@ static int kvm_set_pte_rmapp(struct kvm *kvm, unsigned long *rmapp,
        return 0;
 }
 
-static int kvm_handle_hva(struct kvm *kvm, unsigned long hva,
-                         unsigned long data,
-                         int (*handler)(struct kvm *kvm, unsigned long *rmapp,
-                                        unsigned long data))
+static int kvm_handle_hva_range(struct kvm *kvm,
+                               unsigned long start,
+                               unsigned long end,
+                               unsigned long data,
+                               int (*handler)(struct kvm *kvm,
+                                              unsigned long *rmapp,
+                                              struct kvm_memory_slot *slot,
+                                              unsigned long data))
 {
        int j;
-       int ret;
-       int retval = 0;
+       int ret = 0;
        struct kvm_memslots *slots;
        struct kvm_memory_slot *memslot;
 
        slots = kvm_memslots(kvm);
 
        kvm_for_each_memslot(memslot, slots) {
-               unsigned long start = memslot->userspace_addr;
-               unsigned long end;
+               unsigned long hva_start, hva_end;
+               gfn_t gfn_start, gfn_end;
+
+               hva_start = max(start, memslot->userspace_addr);
+               hva_end = min(end, memslot->userspace_addr +
+                                       (memslot->npages << PAGE_SHIFT));
+               if (hva_start >= hva_end)
+                       continue;
+               /*
+                * {gfn(page) | page intersects with [hva_start, hva_end)} =
+                * {gfn_start, gfn_start+1, ..., gfn_end-1}.
+                */
+               gfn_start = hva_to_gfn_memslot(hva_start, memslot);
+               gfn_end = hva_to_gfn_memslot(hva_end + PAGE_SIZE - 1, memslot);
 
-               end = start + (memslot->npages << PAGE_SHIFT);
-               if (hva >= start && hva < end) {
-                       gfn_t gfn_offset = (hva - start) >> PAGE_SHIFT;
-                       gfn_t gfn = memslot->base_gfn + gfn_offset;
+               for (j = PT_PAGE_TABLE_LEVEL;
+                    j < PT_PAGE_TABLE_LEVEL + KVM_NR_PAGE_SIZES; ++j) {
+                       unsigned long idx, idx_end;
+                       unsigned long *rmapp;
 
-                       ret = handler(kvm, &memslot->rmap[gfn_offset], data);
+                       /*
+                        * {idx(page_j) | page_j intersects with
+                        *  [hva_start, hva_end)} = {idx, idx+1, ..., idx_end}.
+                        */
+                       idx = gfn_to_index(gfn_start, memslot->base_gfn, j);
+                       idx_end = gfn_to_index(gfn_end - 1, memslot->base_gfn, j);
 
-                       for (j = 0; j < KVM_NR_PAGE_SIZES - 1; ++j) {
-                               struct kvm_lpage_info *linfo;
+                       rmapp = __gfn_to_rmap(gfn_start, j, memslot);
 
-                               linfo = lpage_info_slot(gfn, memslot,
-                                                       PT_DIRECTORY_LEVEL + j);
-                               ret |= handler(kvm, &linfo->rmap_pde, data);
-                       }
-                       trace_kvm_age_page(hva, memslot, ret);
-                       retval |= ret;
+                       for (; idx <= idx_end; ++idx)
+                               ret |= handler(kvm, rmapp++, memslot, data);
                }
        }
 
-       return retval;
+       return ret;
+}
+
+static int kvm_handle_hva(struct kvm *kvm, unsigned long hva,
+                         unsigned long data,
+                         int (*handler)(struct kvm *kvm, unsigned long *rmapp,
+                                        struct kvm_memory_slot *slot,
+                                        unsigned long data))
+{
+       return kvm_handle_hva_range(kvm, hva, hva + 1, data, handler);
 }
 
 int kvm_unmap_hva(struct kvm *kvm, unsigned long hva)
@@ -1303,13 +1333,18 @@ int kvm_unmap_hva(struct kvm *kvm, unsigned long hva)
        return kvm_handle_hva(kvm, hva, 0, kvm_unmap_rmapp);
 }
 
+int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end)
+{
+       return kvm_handle_hva_range(kvm, start, end, 0, kvm_unmap_rmapp);
+}
+
 void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte)
 {
        kvm_handle_hva(kvm, hva, (unsigned long)&pte, kvm_set_pte_rmapp);
 }
 
 static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
-                        unsigned long data)
+                        struct kvm_memory_slot *slot, unsigned long data)
 {
        u64 *sptep;
        struct rmap_iterator uninitialized_var(iter);
@@ -1323,8 +1358,10 @@ static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
         * This has some overhead, but not as much as the cost of swapping
         * out actively used pages or breaking up actively used hugepages.
         */
-       if (!shadow_accessed_mask)
-               return kvm_unmap_rmapp(kvm, rmapp, data);
+       if (!shadow_accessed_mask) {
+               young = kvm_unmap_rmapp(kvm, rmapp, slot, data);
+               goto out;
+       }
 
        for (sptep = rmap_get_first(*rmapp, &iter); sptep;
             sptep = rmap_get_next(&iter)) {
@@ -1336,12 +1373,14 @@ static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
                                 (unsigned long *)sptep);
                }
        }
-
+out:
+       /* @data has hva passed to kvm_age_hva(). */
+       trace_kvm_age_page(data, slot, young);
        return young;
 }
 
 static int kvm_test_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
-                             unsigned long data)
+                             struct kvm_memory_slot *slot, unsigned long data)
 {
        u64 *sptep;
        struct rmap_iterator iter;
@@ -1379,13 +1418,13 @@ static void rmap_recycle(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn)
 
        rmapp = gfn_to_rmap(vcpu->kvm, gfn, sp->role.level);
 
-       kvm_unmap_rmapp(vcpu->kvm, rmapp, 0);
+       kvm_unmap_rmapp(vcpu->kvm, rmapp, NULL, 0);
        kvm_flush_remote_tlbs(vcpu->kvm);
 }
 
 int kvm_age_hva(struct kvm *kvm, unsigned long hva)
 {
-       return kvm_handle_hva(kvm, hva, 0, kvm_age_rmapp);
+       return kvm_handle_hva(kvm, hva, hva, kvm_age_rmapp);
 }
 
 int kvm_test_age_hva(struct kvm *kvm, unsigned long hva)
@@ -2457,7 +2496,9 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
                                rmap_recycle(vcpu, sptep, gfn);
                }
        }
-       kvm_release_pfn_clean(pfn);
+
+       if (!is_error_pfn(pfn))
+               kvm_release_pfn_clean(pfn);
 }
 
 static void nonpaging_new_cr3(struct kvm_vcpu *vcpu)
@@ -2472,14 +2513,12 @@ static pfn_t pte_prefetch_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn,
        unsigned long hva;
 
        slot = gfn_to_memslot_dirty_bitmap(vcpu, gfn, no_dirty_log);
-       if (!slot) {
-               get_page(fault_page);
-               return page_to_pfn(fault_page);
-       }
+       if (!slot)
+               return KVM_PFN_ERR_FAULT;
 
        hva = gfn_to_hva_memslot(slot, gfn);
 
-       return hva_to_pfn_atomic(vcpu->kvm, hva);
+       return hva_to_pfn_atomic(hva);
 }
 
 static int direct_pte_prefetch_many(struct kvm_vcpu *vcpu,
@@ -2611,8 +2650,7 @@ static void kvm_send_hwpoison_signal(unsigned long address, struct task_struct *
 
 static int kvm_handle_bad_page(struct kvm_vcpu *vcpu, gfn_t gfn, pfn_t pfn)
 {
-       kvm_release_pfn_clean(pfn);
-       if (is_hwpoison_pfn(pfn)) {
+       if (pfn == KVM_PFN_ERR_HWPOISON) {
                kvm_send_hwpoison_signal(gfn_to_hva(vcpu->kvm, gfn), current);
                return 0;
        }
@@ -3236,8 +3274,6 @@ static bool try_async_pf(struct kvm_vcpu *vcpu, bool prefault, gfn_t gfn,
        if (!async)
                return false; /* *pfn has correct page already */
 
-       put_page(pfn_to_page(*pfn));
-
        if (!prefault && can_do_async_pf(vcpu)) {
                trace_kvm_try_async_get_page(gva, gfn);
                if (kvm_find_async_pf_gfn(vcpu, gfn)) {
index 7d7d0b9e23eb2e3d7b256d74c58852c9f26e5772..daff69e21150d054a109a889630f730702088b76 100644 (file)
@@ -116,10 +116,8 @@ static void audit_mappings(struct kvm_vcpu *vcpu, u64 *sptep, int level)
        gfn = kvm_mmu_page_get_gfn(sp, sptep - sp->spt);
        pfn = gfn_to_pfn_atomic(vcpu->kvm, gfn);
 
-       if (is_error_pfn(pfn)) {
-               kvm_release_pfn_clean(pfn);
+       if (is_error_pfn(pfn))
                return;
-       }
 
        hpa =  pfn << PAGE_SHIFT;
        if ((*sptep & PT64_BASE_ADDR_MASK) != hpa)
@@ -190,7 +188,6 @@ static void check_mappings_rmap(struct kvm *kvm, struct kvm_mmu_page *sp)
 
 static void audit_write_protection(struct kvm *kvm, struct kvm_mmu_page *sp)
 {
-       struct kvm_memory_slot *slot;
        unsigned long *rmapp;
        u64 *sptep;
        struct rmap_iterator iter;
@@ -198,8 +195,7 @@ static void audit_write_protection(struct kvm *kvm, struct kvm_mmu_page *sp)
        if (sp->role.direct || sp->unsync || sp->role.invalid)
                return;
 
-       slot = gfn_to_memslot(kvm, sp->gfn);
-       rmapp = &slot->rmap[sp->gfn - slot->base_gfn];
+       rmapp = gfn_to_rmap(kvm, sp->gfn, PT_PAGE_TABLE_LEVEL);
 
        for (sptep = rmap_get_first(*rmapp, &iter); sptep;
             sptep = rmap_get_next(&iter)) {
index bb7cf01cae76ea735f759ef3c3d2428c271a7151..bf8c42bf50fe6f6d3b45494413d6fd16bb2c8520 100644 (file)
@@ -370,10 +370,8 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
        pgprintk("%s: gpte %llx spte %p\n", __func__, (u64)gpte, spte);
        pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte, true);
        pfn = gfn_to_pfn_atomic(vcpu->kvm, gpte_to_gfn(gpte));
-       if (mmu_invalid_pfn(pfn)) {
-               kvm_release_pfn_clean(pfn);
+       if (mmu_invalid_pfn(pfn))
                return;
-       }
 
        /*
         * we call mmu_set_spte() with host_writable = true because that
@@ -448,10 +446,8 @@ static void FNAME(pte_prefetch)(struct kvm_vcpu *vcpu, struct guest_walker *gw,
                gfn = gpte_to_gfn(gpte);
                pfn = pte_prefetch_gfn_to_pfn(vcpu, gfn,
                                      pte_access & ACC_WRITE_MASK);
-               if (mmu_invalid_pfn(pfn)) {
-                       kvm_release_pfn_clean(pfn);
+               if (mmu_invalid_pfn(pfn))
                        break;
-               }
 
                mmu_set_spte(vcpu, spte, sp->role.access, pte_access, 0, 0,
                             NULL, PT_PAGE_TABLE_LEVEL, gfn,
index 9b7ec1150ab01ad1390217cc04176d255c5d8382..cfc258a6bf97a1efda8b97bb0ae4fd4bd21a9f23 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Kernel-based Virtual Machine -- Performane Monitoring Unit support
+ * Kernel-based Virtual Machine -- Performance Monitoring Unit support
  *
  * Copyright 2011 Red Hat, Inc. and/or its affiliates.
  *
index baead950d6c82cfb3ae530c198ab9d022857170f..31be4a5574473204b12faf34f0fa88f1a6051f5e 100644 (file)
@@ -2063,7 +2063,7 @@ static inline bool nested_svm_intr(struct vcpu_svm *svm)
        if (svm->nested.intercept & 1ULL) {
                /*
                 * The #vmexit can't be emulated here directly because this
-                * code path runs with irqs and preemtion disabled. A
+                * code path runs with irqs and preemption disabled. A
                 * #vmexit emulation might sleep. Only signal request for
                 * the #vmexit here.
                 */
@@ -2105,7 +2105,6 @@ static void *nested_svm_map(struct vcpu_svm *svm, u64 gpa, struct page **_page)
        return kmap(page);
 
 error:
-       kvm_release_page_clean(page);
        kvm_inject_gp(&svm->vcpu, 0);
 
        return NULL;
@@ -2409,7 +2408,7 @@ static bool nested_svm_vmrun_msrpm(struct vcpu_svm *svm)
 {
        /*
         * This function merges the msr permission bitmaps of kvm and the
-        * nested vmcb. It is omptimized in that it only merges the parts where
+        * nested vmcb. It is optimized in that it only merges the parts where
         * the kvm msr permission bitmap may contain zero bits
         */
        int i;
diff --git a/arch/x86/kvm/timer.c b/arch/x86/kvm/timer.c
deleted file mode 100644 (file)
index 6b85cc6..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Kernel-based Virtual Machine driver for Linux
- *
- * This module enables machines with Intel VT-x extensions to run virtual
- * machines without emulation or binary translation.
- *
- * timer support
- *
- * Copyright 2010 Red Hat, Inc. and/or its affiliates.
- *
- * This work is licensed under the terms of the GNU GPL, version 2.  See
- * the COPYING file in the top-level directory.
- */
-
-#include <linux/kvm_host.h>
-#include <linux/kvm.h>
-#include <linux/hrtimer.h>
-#include <linux/atomic.h>
-#include "kvm_timer.h"
-
-enum hrtimer_restart kvm_timer_fn(struct hrtimer *data)
-{
-       struct kvm_timer *ktimer = container_of(data, struct kvm_timer, timer);
-       struct kvm_vcpu *vcpu = ktimer->vcpu;
-       wait_queue_head_t *q = &vcpu->wq;
-
-       /*
-        * There is a race window between reading and incrementing, but we do
-        * not care about potentially losing timer events in the !reinject
-        * case anyway. Note: KVM_REQ_PENDING_TIMER is implicitly checked
-        * in vcpu_enter_guest.
-        */
-       if (ktimer->reinject || !atomic_read(&ktimer->pending)) {
-               atomic_inc(&ktimer->pending);
-               /* FIXME: this code should not know anything about vcpus */
-               kvm_make_request(KVM_REQ_PENDING_TIMER, vcpu);
-       }
-
-       if (waitqueue_active(q))
-               wake_up_interruptible(q);
-
-       if (ktimer->t_ops->is_periodic(ktimer)) {
-               hrtimer_add_expires_ns(&ktimer->timer, ktimer->period);
-               return HRTIMER_RESTART;
-       } else
-               return HRTIMER_NORESTART;
-}
index c39b60707e0262be788b6909d3e46d63d746cadf..13e0296cea46b8cb1dd30e318ac91d404b637ecf 100644 (file)
@@ -596,10 +596,9 @@ static inline struct vmcs12 *get_vmcs12(struct kvm_vcpu *vcpu)
 static struct page *nested_get_page(struct kvm_vcpu *vcpu, gpa_t addr)
 {
        struct page *page = gfn_to_page(vcpu->kvm, addr >> PAGE_SHIFT);
-       if (is_error_page(page)) {
-               kvm_release_page_clean(page);
+       if (is_error_page(page))
                return NULL;
-       }
+
        return page;
 }
 
@@ -1343,7 +1342,7 @@ static bool update_transition_efer(struct vcpu_vmx *vmx, int efer_offset)
        guest_efer = vmx->vcpu.arch.efer;
 
        /*
-        * NX is emulated; LMA and LME handled by hardware; SCE meaninless
+        * NX is emulated; LMA and LME handled by hardware; SCE meaningless
         * outside long mode
         */
        ignore_bits = EFER_NX | EFER_SCE;
@@ -1488,13 +1487,6 @@ static void __vmx_load_host_state(struct vcpu_vmx *vmx)
                loadsegment(ds, vmx->host_state.ds_sel);
                loadsegment(es, vmx->host_state.es_sel);
        }
-#else
-       /*
-        * The sysexit path does not restore ds/es, so we must set them to
-        * a reasonable value ourselves.
-        */
-       loadsegment(ds, __USER_DS);
-       loadsegment(es, __USER_DS);
 #endif
        reload_tss();
 #ifdef CONFIG_X86_64
@@ -1998,7 +1990,7 @@ static __init void nested_vmx_setup_ctls_msrs(void)
 #endif
                CPU_BASED_MOV_DR_EXITING | CPU_BASED_UNCOND_IO_EXITING |
                CPU_BASED_USE_IO_BITMAPS | CPU_BASED_MONITOR_EXITING |
-               CPU_BASED_RDPMC_EXITING |
+               CPU_BASED_RDPMC_EXITING | CPU_BASED_RDTSC_EXITING |
                CPU_BASED_ACTIVATE_SECONDARY_CONTROLS;
        /*
         * We can allow some features even when not supported by the
@@ -3261,7 +3253,7 @@ static void vmx_set_segment(struct kvm_vcpu *vcpu,
         * qemu binaries.
         *   IA32 arch specifies that at the time of processor reset the
         * "Accessed" bit in the AR field of segment registers is 1. And qemu
-        * is setting it to 0 in the usedland code. This causes invalid guest
+        * is setting it to 0 in the userland code. This causes invalid guest
         * state vmexit when "unrestricted guest" mode is turned on.
         *    Fix for this setup issue in cpu_reset is being pushed in the qemu
         * tree. Newer qemu binaries with that qemu fix would not need this
@@ -4446,7 +4438,7 @@ vmx_patch_hypercall(struct kvm_vcpu *vcpu, unsigned char *hypercall)
        hypercall[2] = 0xc1;
 }
 
-/* called to set cr0 as approriate for a mov-to-cr0 exit. */
+/* called to set cr0 as appropriate for a mov-to-cr0 exit. */
 static int handle_set_cr0(struct kvm_vcpu *vcpu, unsigned long val)
 {
        if (to_vmx(vcpu)->nested.vmxon &&
@@ -6230,6 +6222,7 @@ static void atomic_switch_perf_msrs(struct vcpu_vmx *vmx)
 static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
+       unsigned long debugctlmsr;
 
        if (is_guest_mode(vcpu) && !vmx->nested.nested_run_pending) {
                struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
@@ -6269,6 +6262,7 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
                vmx_set_interrupt_shadow(vcpu, 0);
 
        atomic_switch_perf_msrs(vmx);
+       debugctlmsr = get_debugctlmsr();
 
        vmx->__launched = vmx->loaded_vmcs->launched;
        asm(
@@ -6370,6 +6364,23 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
 #endif
              );
 
+       /* MSR_IA32_DEBUGCTLMSR is zeroed on vmexit. Restore it if needed */
+       if (debugctlmsr)
+               update_debugctlmsr(debugctlmsr);
+
+#ifndef CONFIG_X86_64
+       /*
+        * The sysexit path does not restore ds/es, so we must set them to
+        * a reasonable value ourselves.
+        *
+        * We can't defer this to vmx_load_host_state() since that function
+        * may be executed in interrupt context, which saves and restore segments
+        * around it, nullifying its effect.
+        */
+       loadsegment(ds, __USER_DS);
+       loadsegment(es, __USER_DS);
+#endif
+
        vcpu->arch.regs_avail = ~((1 << VCPU_REGS_RIP) | (1 << VCPU_REGS_RSP)
                                  | (1 << VCPU_EXREG_RFLAGS)
                                  | (1 << VCPU_EXREG_CPL)
index 59b59508ff07dc2623887d6be43859215d5bd589..fb0d93788bfb416e575eb26990df111288956ab8 100644 (file)
@@ -246,20 +246,14 @@ static void drop_user_return_notifiers(void *ignore)
 
 u64 kvm_get_apic_base(struct kvm_vcpu *vcpu)
 {
-       if (irqchip_in_kernel(vcpu->kvm))
-               return vcpu->arch.apic_base;
-       else
-               return vcpu->arch.apic_base;
+       return vcpu->arch.apic_base;
 }
 EXPORT_SYMBOL_GPL(kvm_get_apic_base);
 
 void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data)
 {
        /* TODO: reserve bits check */
-       if (irqchip_in_kernel(vcpu->kvm))
-               kvm_lapic_set_base(vcpu, data);
-       else
-               vcpu->arch.apic_base = data;
+       kvm_lapic_set_base(vcpu, data);
 }
 EXPORT_SYMBOL_GPL(kvm_set_apic_base);
 
@@ -806,7 +800,7 @@ EXPORT_SYMBOL_GPL(kvm_rdpmc);
  * kvm-specific. Those are put in the beginning of the list.
  */
 
-#define KVM_SAVE_MSRS_BEGIN    9
+#define KVM_SAVE_MSRS_BEGIN    10
 static u32 msrs_to_save[] = {
        MSR_KVM_SYSTEM_TIME, MSR_KVM_WALL_CLOCK,
        MSR_KVM_SYSTEM_TIME_NEW, MSR_KVM_WALL_CLOCK_NEW,
@@ -925,6 +919,10 @@ static void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock)
         */
        getboottime(&boot);
 
+       if (kvm->arch.kvmclock_offset) {
+               struct timespec ts = ns_to_timespec(kvm->arch.kvmclock_offset);
+               boot = timespec_sub(boot, ts);
+       }
        wc.sec = boot.tv_sec;
        wc.nsec = boot.tv_nsec;
        wc.version = version;
@@ -1093,7 +1091,7 @@ void kvm_write_tsc(struct kvm_vcpu *vcpu, u64 data)
                 * For each generation, we track the original measured
                 * nanosecond time, offset, and write, so if TSCs are in
                 * sync, we can match exact offset, and if not, we can match
-                * exact software computaion in compute_guest_tsc()
+                * exact software computation in compute_guest_tsc()
                 *
                 * These values are tracked in kvm->arch.cur_xxx variables.
                 */
@@ -1136,6 +1134,7 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
        unsigned long this_tsc_khz;
        s64 kernel_ns, max_kernel_ns;
        u64 tsc_timestamp;
+       u8 pvclock_flags;
 
        /* Keep irq disabled to prevent changes to the clock */
        local_irq_save(flags);
@@ -1217,7 +1216,14 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
        vcpu->hv_clock.system_time = kernel_ns + v->kvm->arch.kvmclock_offset;
        vcpu->last_kernel_ns = kernel_ns;
        vcpu->last_guest_tsc = tsc_timestamp;
-       vcpu->hv_clock.flags = 0;
+
+       pvclock_flags = 0;
+       if (vcpu->pvclock_set_guest_stopped_request) {
+               pvclock_flags |= PVCLOCK_GUEST_STOPPED;
+               vcpu->pvclock_set_guest_stopped_request = false;
+       }
+
+       vcpu->hv_clock.flags = pvclock_flags;
 
        /*
         * The interface expects us to write an even number signaling that the
@@ -1500,7 +1506,7 @@ static int kvm_pv_enable_async_pf(struct kvm_vcpu *vcpu, u64 data)
 {
        gpa_t gpa = data & ~0x3f;
 
-       /* Bits 2:5 are resrved, Should be zero */
+       /* Bits 2:5 are reserved, Should be zero */
        if (data & 0x3c)
                return 1;
 
@@ -1635,10 +1641,9 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
                vcpu->arch.time_page =
                                gfn_to_page(vcpu->kvm, data >> PAGE_SHIFT);
 
-               if (is_error_page(vcpu->arch.time_page)) {
-                       kvm_release_page_clean(vcpu->arch.time_page);
+               if (is_error_page(vcpu->arch.time_page))
                        vcpu->arch.time_page = NULL;
-               }
+
                break;
        }
        case MSR_KVM_ASYNC_PF_EN:
@@ -1723,7 +1728,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data)
                 * Ignore all writes to this no longer documented MSR.
                 * Writes are only relevant for old K7 processors,
                 * all pre-dating SVM, but a recommended workaround from
-                * AMD for these chips. It is possible to speicify the
+                * AMD for these chips. It is possible to specify the
                 * affected processor models on the command line, hence
                 * the need to ignore the workaround.
                 */
@@ -2351,8 +2356,7 @@ static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu,
 static int kvm_vcpu_ioctl_set_lapic(struct kvm_vcpu *vcpu,
                                    struct kvm_lapic_state *s)
 {
-       memcpy(vcpu->arch.apic->regs, s->regs, sizeof *s);
-       kvm_apic_post_state_restore(vcpu);
+       kvm_apic_post_state_restore(vcpu, s);
        update_cr8_intercept(vcpu);
 
        return 0;
@@ -2628,11 +2632,9 @@ static int kvm_vcpu_ioctl_x86_set_xcrs(struct kvm_vcpu *vcpu,
  */
 static int kvm_set_guest_paused(struct kvm_vcpu *vcpu)
 {
-       struct pvclock_vcpu_time_info *src = &vcpu->arch.hv_clock;
        if (!vcpu->arch.time_page)
                return -EINVAL;
-       src->flags |= PVCLOCK_GUEST_STOPPED;
-       mark_page_dirty(vcpu->kvm, vcpu->arch.time >> PAGE_SHIFT);
+       vcpu->arch.pvclock_set_guest_stopped_request = true;
        kvm_make_request(KVM_REQ_CLOCK_UPDATE, vcpu);
        return 0;
 }
@@ -3083,7 +3085,7 @@ static int kvm_vm_ioctl_reinject(struct kvm *kvm,
        if (!kvm->arch.vpit)
                return -ENXIO;
        mutex_lock(&kvm->arch.vpit->pit_state.lock);
-       kvm->arch.vpit->pit_state.pit_timer.reinject = control->pit_reinject;
+       kvm->arch.vpit->pit_state.reinject = control->pit_reinject;
        mutex_unlock(&kvm->arch.vpit->pit_state.lock);
        return 0;
 }
@@ -3166,6 +3168,16 @@ out:
        return r;
 }
 
+int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_event)
+{
+       if (!irqchip_in_kernel(kvm))
+               return -ENXIO;
+
+       irq_event->status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID,
+                                       irq_event->irq, irq_event->level);
+       return 0;
+}
+
 long kvm_arch_vm_ioctl(struct file *filp,
                       unsigned int ioctl, unsigned long arg)
 {
@@ -3272,29 +3284,6 @@ long kvm_arch_vm_ioctl(struct file *filp,
        create_pit_unlock:
                mutex_unlock(&kvm->slots_lock);
                break;
-       case KVM_IRQ_LINE_STATUS:
-       case KVM_IRQ_LINE: {
-               struct kvm_irq_level irq_event;
-
-               r = -EFAULT;
-               if (copy_from_user(&irq_event, argp, sizeof irq_event))
-                       goto out;
-               r = -ENXIO;
-               if (irqchip_in_kernel(kvm)) {
-                       __s32 status;
-                       status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID,
-                                       irq_event.irq, irq_event.level);
-                       if (ioctl == KVM_IRQ_LINE_STATUS) {
-                               r = -EFAULT;
-                               irq_event.status = status;
-                               if (copy_to_user(argp, &irq_event,
-                                                       sizeof irq_event))
-                                       goto out;
-                       }
-                       r = 0;
-               }
-               break;
-       }
        case KVM_GET_IRQCHIP: {
                /* 0: PIC master, 1: PIC slave, 2: IOAPIC */
                struct kvm_irqchip *chip;
@@ -3955,10 +3944,8 @@ static int emulator_cmpxchg_emulated(struct x86_emulate_ctxt *ctxt,
                goto emul_write;
 
        page = gfn_to_page(vcpu->kvm, gpa >> PAGE_SHIFT);
-       if (is_error_page(page)) {
-               kvm_release_page_clean(page);
+       if (is_error_page(page))
                goto emul_write;
-       }
 
        kaddr = kmap_atomic(page);
        kaddr += offset_in_page(gpa);
@@ -4492,7 +4479,7 @@ static bool reexecute_instruction(struct kvm_vcpu *vcpu, gva_t gva)
 
        /*
         * if emulation was due to access to shadowed page table
-        * and it failed try to unshadow page and re-entetr the
+        * and it failed try to unshadow page and re-enter the
         * guest to let CPU execute the instruction.
         */
        if (kvm_mmu_unprotect_page_virt(vcpu, gva))
@@ -4922,6 +4909,7 @@ int kvm_arch_init(void *opaque)
        if (cpu_has_xsave)
                host_xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK);
 
+       kvm_lapic_init();
        return 0;
 
 out:
@@ -5588,7 +5576,7 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
                /*
                 * We are here if userspace calls get_regs() in the middle of
                 * instruction emulation. Registers state needs to be copied
-                * back from emulation context to vcpu. Usrapace shouldn't do
+                * back from emulation context to vcpu. Userspace shouldn't do
                 * that usually, but some bad designed PV devices (vmware
                 * backdoor interface) need this to work
                 */
@@ -6117,7 +6105,7 @@ int kvm_arch_hardware_enable(void *garbage)
         * as we reset last_host_tsc on all VCPUs to stop this from being
         * called multiple times (one for each physical CPU bringup).
         *
-        * Platforms with unnreliable TSCs don't have to deal with this, they
+        * Platforms with unreliable TSCs don't have to deal with this, they
         * will be compensated by the logic in vcpu_load, which sets the TSC to
         * catchup mode.  This will catchup all VCPUs to real time, but cannot
         * guarantee that they stay in perfect synchronization.
@@ -6170,6 +6158,8 @@ bool kvm_vcpu_compatible(struct kvm_vcpu *vcpu)
        return irqchip_in_kernel(vcpu->kvm) == (vcpu->arch.apic != NULL);
 }
 
+struct static_key kvm_no_apic_vcpu __read_mostly;
+
 int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
 {
        struct page *page;
@@ -6202,7 +6192,8 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
                r = kvm_create_lapic(vcpu);
                if (r < 0)
                        goto fail_mmu_destroy;
-       }
+       } else
+               static_key_slow_inc(&kvm_no_apic_vcpu);
 
        vcpu->arch.mce_banks = kzalloc(KVM_MAX_MCE_BANKS * sizeof(u64) * 4,
                                       GFP_KERNEL);
@@ -6242,6 +6233,8 @@ void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
        kvm_mmu_destroy(vcpu);
        srcu_read_unlock(&vcpu->kvm->srcu, idx);
        free_page((unsigned long)vcpu->arch.pio_data);
+       if (!irqchip_in_kernel(vcpu->kvm))
+               static_key_slow_dec(&kvm_no_apic_vcpu);
 }
 
 int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
@@ -6313,10 +6306,18 @@ void kvm_arch_free_memslot(struct kvm_memory_slot *free,
 {
        int i;
 
-       for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) {
-               if (!dont || free->arch.lpage_info[i] != dont->arch.lpage_info[i]) {
-                       kvm_kvfree(free->arch.lpage_info[i]);
-                       free->arch.lpage_info[i] = NULL;
+       for (i = 0; i < KVM_NR_PAGE_SIZES; ++i) {
+               if (!dont || free->arch.rmap[i] != dont->arch.rmap[i]) {
+                       kvm_kvfree(free->arch.rmap[i]);
+                       free->arch.rmap[i] = NULL;
+               }
+               if (i == 0)
+                       continue;
+
+               if (!dont || free->arch.lpage_info[i - 1] !=
+                            dont->arch.lpage_info[i - 1]) {
+                       kvm_kvfree(free->arch.lpage_info[i - 1]);
+                       free->arch.lpage_info[i - 1] = NULL;
                }
        }
 }
@@ -6325,23 +6326,30 @@ int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages)
 {
        int i;
 
-       for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) {
+       for (i = 0; i < KVM_NR_PAGE_SIZES; ++i) {
                unsigned long ugfn;
                int lpages;
-               int level = i + 2;
+               int level = i + 1;
 
                lpages = gfn_to_index(slot->base_gfn + npages - 1,
                                      slot->base_gfn, level) + 1;
 
-               slot->arch.lpage_info[i] =
-                       kvm_kvzalloc(lpages * sizeof(*slot->arch.lpage_info[i]));
-               if (!slot->arch.lpage_info[i])
+               slot->arch.rmap[i] =
+                       kvm_kvzalloc(lpages * sizeof(*slot->arch.rmap[i]));
+               if (!slot->arch.rmap[i])
+                       goto out_free;
+               if (i == 0)
+                       continue;
+
+               slot->arch.lpage_info[i - 1] = kvm_kvzalloc(lpages *
+                                       sizeof(*slot->arch.lpage_info[i - 1]));
+               if (!slot->arch.lpage_info[i - 1])
                        goto out_free;
 
                if (slot->base_gfn & (KVM_PAGES_PER_HPAGE(level) - 1))
-                       slot->arch.lpage_info[i][0].write_count = 1;
+                       slot->arch.lpage_info[i - 1][0].write_count = 1;
                if ((slot->base_gfn + npages) & (KVM_PAGES_PER_HPAGE(level) - 1))
-                       slot->arch.lpage_info[i][lpages - 1].write_count = 1;
+                       slot->arch.lpage_info[i - 1][lpages - 1].write_count = 1;
                ugfn = slot->userspace_addr >> PAGE_SHIFT;
                /*
                 * If the gfn and userspace address are not aligned wrt each
@@ -6353,16 +6361,21 @@ int kvm_arch_create_memslot(struct kvm_memory_slot *slot, unsigned long npages)
                        unsigned long j;
 
                        for (j = 0; j < lpages; ++j)
-                               slot->arch.lpage_info[i][j].write_count = 1;
+                               slot->arch.lpage_info[i - 1][j].write_count = 1;
                }
        }
 
        return 0;
 
 out_free:
-       for (i = 0; i < KVM_NR_PAGE_SIZES - 1; ++i) {
-               kvm_kvfree(slot->arch.lpage_info[i]);
-               slot->arch.lpage_info[i] = NULL;
+       for (i = 0; i < KVM_NR_PAGE_SIZES; ++i) {
+               kvm_kvfree(slot->arch.rmap[i]);
+               slot->arch.rmap[i] = NULL;
+               if (i == 0)
+                       continue;
+
+               kvm_kvfree(slot->arch.lpage_info[i - 1]);
+               slot->arch.lpage_info[i - 1] = NULL;
        }
        return -ENOMEM;
 }
@@ -6381,10 +6394,10 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
                map_flags = MAP_SHARED | MAP_ANONYMOUS;
 
        /*To keep backward compatibility with older userspace,
-        *x86 needs to hanlde !user_alloc case.
+        *x86 needs to handle !user_alloc case.
         */
        if (!user_alloc) {
-               if (npages && !old.rmap) {
+               if (npages && !old.npages) {
                        unsigned long userspace_addr;
 
                        userspace_addr = vm_mmap(NULL, 0,
@@ -6412,7 +6425,7 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
 
        int nr_mmu_pages = 0, npages = mem->memory_size >> PAGE_SHIFT;
 
-       if (!user_alloc && !old.user_alloc && old.rmap && !npages) {
+       if (!user_alloc && !old.user_alloc && old.npages && !npages) {
                int ret;
 
                ret = vm_munmap(old.userspace_addr,
index 3d1134ddb885622af79bdb0fefb589c8f7b4d5b6..2b5219c12ac8566c24a837ccff3f2fb14db1c7f8 100644 (file)
@@ -124,4 +124,5 @@ int kvm_write_guest_virt_system(struct x86_emulate_ctxt *ctxt,
 
 extern u64 host_xcr0;
 
+extern struct static_key kvm_no_apic_vcpu;
 #endif
index 76dcd9d8e0bcf6113ac4862f2e4b2fc9acff4012..7dde46d68a25a562b54fcdd300f232b051c10153 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/pgalloc.h>               /* pgd_*(), ...                 */
 #include <asm/kmemcheck.h>             /* kmemcheck_*(), ...           */
 #include <asm/fixmap.h>                        /* VSYSCALL_START               */
+#include <asm/rcu.h>                   /* exception_enter(), ...       */
 
 /*
  * Page fault error code bits:
@@ -1000,8 +1001,8 @@ static int fault_in_kernel_space(unsigned long address)
  * and the problem, and then passes it off to one of the appropriate
  * routines.
  */
-dotraplinkage void __kprobes
-do_page_fault(struct pt_regs *regs, unsigned long error_code)
+static void __kprobes
+__do_page_fault(struct pt_regs *regs, unsigned long error_code)
 {
        struct vm_area_struct *vma;
        struct task_struct *tsk;
@@ -1209,3 +1210,11 @@ good_area:
 
        up_read(&mm->mmap_sem);
 }
+
+dotraplinkage void __kprobes
+do_page_fault(struct pt_regs *regs, unsigned long error_code)
+{
+       exception_enter(regs);
+       __do_page_fault(regs, error_code);
+       exception_exit(regs);
+}
index 4599c3e8bcb63f39fe618f0075ba9e52e0fbb353..4ddf497ca65beae876d17867d4cd7d32cd37f39b 100644 (file)
@@ -142,23 +142,23 @@ static inline int save_add_info(void) {return 0;}
 #endif
 
 /* Callback for parsing of the Proximity Domain <-> Memory Area mappings */
-void __init
+int __init
 acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
 {
        u64 start, end;
        int node, pxm;
 
        if (srat_disabled())
-               return;
+               return -1;
        if (ma->header.length != sizeof(struct acpi_srat_mem_affinity)) {
                bad_srat();
-               return;
+               return -1;
        }
        if ((ma->flags & ACPI_SRAT_MEM_ENABLED) == 0)
-               return;
+               return -1;
 
        if ((ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) && !save_add_info())
-               return;
+               return -1;
        start = ma->base_address;
        end = start + ma->length;
        pxm = ma->proximity_domain;
@@ -168,12 +168,12 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
        if (node < 0) {
                printk(KERN_ERR "SRAT: Too many proximity domains.\n");
                bad_srat();
-               return;
+               return -1;
        }
 
        if (numa_add_memblk(node, start, end) < 0) {
                bad_srat();
-               return;
+               return -1;
        }
 
        node_set(node, numa_nodes_parsed);
@@ -181,6 +181,7 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
        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;
 }
 
 void __init acpi_numa_arch_fixup(void) {}
index 51171aeff0dc31483cdc6526e641459b0d64deb3..29aed7ac2c02a8b73aa2d58ab55f2d884bea2698 100644 (file)
 309    common  getcpu                  sys_getcpu
 310    64      process_vm_readv        sys_process_vm_readv
 311    64      process_vm_writev       sys_process_vm_writev
-312    64      kcmp                    sys_kcmp
+312    common  kcmp                    sys_kcmp
 
 #
 # x32-specific system call numbers start at 512 to avoid cache impact
index bf4bda6d3e9ad66f19af6e4669063a12739c78db..069332f5de4d0bf581d964666ca099d92f4b922b 100644 (file)
@@ -224,9 +224,6 @@ static void __init xen_banner(void)
               xen_feature(XENFEAT_mmu_pt_update_preserve_ad) ? " (preserve-AD)" : "");
 }
 
-#define CPUID_THERM_POWER_LEAF 6
-#define APERFMPERF_PRESENT 0
-
 static __read_mostly unsigned int cpuid_leaf1_edx_mask = ~0;
 static __read_mostly unsigned int cpuid_leaf1_ecx_mask = ~0;
 
@@ -260,11 +257,6 @@ static void xen_cpuid(unsigned int *ax, unsigned int *bx,
                *dx = cpuid_leaf5_edx_val;
                return;
 
-       case CPUID_THERM_POWER_LEAF:
-               /* Disabling APERFMPERF for kernel usage */
-               maskecx = ~(1 << APERFMPERF_PRESENT);
-               break;
-
        case 0xb:
                /* Suppress extended topology stuff */
                maskebx = 0;
index 64effdc6da9400c09515af384d3d4b94c8efcb50..b2e91d40a4cb32a851006d6194d70f3465ec26f3 100644 (file)
@@ -194,6 +194,11 @@ RESERVE_BRK(p2m_mid_mfn, PAGE_SIZE * (MAX_DOMAIN_PAGES / (P2M_PER_PAGE * P2M_MID
  * boundary violation will require three middle nodes. */
 RESERVE_BRK(p2m_mid_identity, PAGE_SIZE * 2 * 3);
 
+/* When we populate back during bootup, the amount of pages can vary. The
+ * max we have is seen is 395979, but that does not mean it can't be more.
+ * But some machines can have 3GB I/O holes even. So lets reserve enough
+ * for 4GB of I/O and E820 holes. */
+RESERVE_BRK(p2m_populated, PMD_SIZE * 4);
 static inline unsigned p2m_top_index(unsigned long pfn)
 {
        BUG_ON(pfn >= MAX_P2M_PFN);
index 8ed64cfae4ff1f46953315f04853ce06831394f5..8c82cd87082e43bf757e94c413419a7291feb2a1 100644 (file)
@@ -11,6 +11,8 @@ config XTENSA
        select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_SHOW
        select GENERIC_CPU_DEVICES
+       select GENERIC_PCI_IOMAP
+       select MODULES_USE_ELF_RELA
        help
          Xtensa processors are 32-bit RISC machines designed by Tensilica
          primarily for embedded systems.  These processors are both
@@ -59,6 +61,7 @@ choice
 config XTENSA_VARIANT_FSF
        bool "fsf - default (not generic) configuration"
        select MMU
+       select ARCH_WANT_OPTIONAL_GPIOLIB
 
 config XTENSA_VARIANT_DC232B
        bool "dc232b - Diamond 232L Standard Core Rev.B (LE)"
index 4beb43c087d3dd6498daa296548c29b854701c5d..c4d8b625ac9254bd8351616b351e9925b9524990 100644 (file)
@@ -16,6 +16,7 @@
 #include <asm/page.h>
 #include <linux/bug.h>
 #include <linux/kernel.h>
+#include <asm-generic/iomap.h>
 
 #include <linux/types.h>
 
@@ -112,6 +113,15 @@ static inline void iounmap(void *addr)
 #define writew(b, addr) (void)((*(volatile unsigned short *)(addr)) = (b))
 #define writel(b, addr) (void)((*(volatile unsigned int *)(addr)) = (b))
 
+#define ioport_map(port, nr) ((void __iomem *)(port))
+
+#define ioread8 read
+#define ioread16 readw
+#define ioread32 readl
+#define iowrite8 writeb
+#define iowrite16 writew
+#define iowrite32 writel
+
 static inline __u8 __raw_readb(const volatile void __iomem *addr)
 {
           return *(__force volatile __u8 *)(addr);
index d9b34bee4d4255955bb0fae7340eb135a43158c4..488b40c6f9b9aa89fcf0cce02d33e9bd6bfa6274 100644 (file)
 #ifndef _XTENSA_MODULE_H
 #define _XTENSA_MODULE_H
 
-struct mod_arch_specific
-{
-       /* No special elements, yet. */
-};
-
 #define MODULE_ARCH_VERMAGIC "xtensa-" __stringify(XCHAL_CORE_ID) " "
 
-#define Elf_Shdr Elf32_Shdr
-#define Elf_Sym Elf32_Sym
-#define Elf_Ehdr Elf32_Ehdr
+#include <asm-generic/module.h>
 
 #endif /* _XTENSA_MODULE_H */
index 59fc3fe15572af5231181d5b255998fcf6029294..0f9f35fc191af0c7d04f888be013cea06c3c586c 100644 (file)
@@ -24,6 +24,7 @@ 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' \
        -e 's/\*(\(\.text\.[a-z]*\))/*(\1.literal \1)/g'
 
 quiet_cmd__cpp_lds_S = LDS     $@
index 4340ee076bd522f88229aae7f474ce4a59493a40..98e77c3ef1c38d9e1401b7238a7a4a4c51cea460 100644 (file)
@@ -84,12 +84,12 @@ static void xtensa_irq_unmask(struct irq_data *d)
 static void xtensa_irq_enable(struct irq_data *d)
 {
        variant_irq_enable(d->irq);
-       xtensa_irq_unmask(d->irq);
+       xtensa_irq_unmask(d);
 }
 
 static void xtensa_irq_disable(struct irq_data *d)
 {
-       xtensa_irq_mask(d->irq);
+       xtensa_irq_mask(d);
        variant_irq_disable(d->irq);
 }
 
index 69759e9cb3ea8b6efd9ddca47c3578c7a5d253a8..96ccf17bcf31bc416feb82db2f339652f5522eb6 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/sched.h>
 #include <linux/errno.h>
 #include <linux/bootmem.h>
+#include <linux/module.h>
 
 #include <asm/pci-bridge.h>
 #include <asm/platform.h>
@@ -341,7 +342,7 @@ __pci_mmap_set_pgprot(struct pci_dev *dev, struct vm_area_struct *vma,
        int prot = pgprot_val(vma->vm_page_prot);
 
        /* Set to write-through */
-       prot &= ~_PAGE_NO_CACHE;
+       prot = (prot & _PAGE_CA_MASK) | _PAGE_CA_WT;
 #if 0
        if (!write_combine)
                prot |= _PAGE_WRITETHRU;
@@ -376,3 +377,9 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
 
        return ret;
 }
+
+void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
+{
+       iounmap(addr);
+}
+EXPORT_SYMBOL(pci_iounmap);
index 1b91a97f1d8401ff9899ed95deae80933e482f7a..97230e46cbe77d1439b51154233ff54ba17c67c3 100644 (file)
@@ -40,8 +40,8 @@ _F(int,  pcibios_fixup, (void), { return 0; });
 #ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
 _F(void, calibrate_ccount, (void),
 {
-  printk ("ERROR: Cannot calibrate cpu frequency! Assuming 100MHz.\n");
-  ccount_per_jiffy = 100 * (1000000UL/HZ);
+       pr_err("ERROR: Cannot calibrate cpu frequency! Assuming 10MHz.\n");
+       ccount_per_jiffy = 10 * (1000000UL/HZ);
 });
 #endif
 
index af96e314d71fa7a228abcb371ff862246410f9c9..c61dd3961b173b53d7cac2819f137b04fab6839d 100644 (file)
@@ -4,5 +4,5 @@
 # "prom monitor" library routines under Linux.
 #
 
-obj-y                  = io.o console.o setup.o network.o
-
+obj-y                  = io.o console.o setup.o
+obj-$(CONFIG_NET)      += network.o
index f9726f6afdf1f00432ca627820f61ab56f6c109c..367c2c8ebc7b91ce779999422435388de67cc359 100644 (file)
@@ -33,7 +33,7 @@
 #endif
 
 #define SERIAL_MAX_NUM_LINES 1
-#define SERIAL_TIMER_VALUE (20 * HZ)
+#define SERIAL_TIMER_VALUE (HZ / 10)
 
 static struct tty_driver *serial_driver;
 static struct tty_port serial_port;
@@ -43,14 +43,22 @@ static DEFINE_SPINLOCK(timer_lock);
 
 int errno;
 
-static int __simc (int a, int b, int c, int d, int e, int f) __attribute__((__noinline__));
 static int __simc (int a, int b, int c, int d, int e, int f)
 {
        int ret;
-       __asm__ __volatile__ ("simcall\n"
+       register int a1 asm("a2") = a;
+       register int b1 asm("a3") = b;
+       register int c1 asm("a4") = c;
+       register int d1 asm("a5") = d;
+       register int e1 asm("a6") = e;
+       register int f1 asm("a7") = f;
+       __asm__ __volatile__ (
+                       "simcall\n"
                        "mov %0, a2\n"
-                       "mov %1, a3\n" : "=a" (ret), "=a" (errno)
-                       : : "a2", "a3");
+                       "mov %1, a3\n"
+                       : "=a" (ret), "=a" (errno), "+r"(a1), "+r"(b1)
+                       : "r"(c1), "r"(d1), "r"(e1), "r"(f1)
+                       : );
        return ret;
 }
 
@@ -223,6 +231,7 @@ int __init rs_init(void)
        serial_driver->flags = TTY_DRIVER_REAL_RAW;
 
        tty_set_operations(serial_driver, &serial_ops);
+       tty_port_link_device(&serial_port, serial_driver, 0);
 
        if (tty_register_driver(serial_driver))
                panic("Couldn't register serial driver\n");
index f60c8cf6dfbe56a582be5a64f778f213ad554e94..927acf378ea35e3bb6364bfb78cfc1347f829ecb 100644 (file)
@@ -38,16 +38,22 @@ void __init platform_init(bp_tag_t* bootparam)
 
 }
 
+#ifdef CONFIG_PCI
+void platform_pcibios_init(void)
+{
+}
+#endif
+
 void platform_halt(void)
 {
-       printk (" ** Called platform_halt(), looping forever! **\n");
-       while (1);
+       pr_info(" ** Called platform_halt() **\n");
+       __asm__ __volatile__("movi a2, 1\nsimcall\n");
 }
 
 void platform_power_off(void)
 {
-       printk (" ** Called platform_power_off(), looping forever! **\n");
-       while (1);
+       pr_info(" ** Called platform_power_off() **\n");
+       __asm__ __volatile__("movi a2, 1\nsimcall\n");
 }
 void platform_restart(void)
 {
index 2b461b496a788c11d00616efaf16df121e620160..19cc761cacb2a4b71fe9d4579226025324ffddf5 100644 (file)
@@ -44,6 +44,7 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
        struct request_queue *q = bdev_get_queue(bdev);
        int type = REQ_WRITE | REQ_DISCARD;
        unsigned int max_discard_sectors;
+       unsigned int granularity, alignment, mask;
        struct bio_batch bb;
        struct bio *bio;
        int ret = 0;
@@ -54,18 +55,20 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
        if (!blk_queue_discard(q))
                return -EOPNOTSUPP;
 
+       /* Zero-sector (unknown) and one-sector granularities are the same.  */
+       granularity = max(q->limits.discard_granularity >> 9, 1U);
+       mask = granularity - 1;
+       alignment = (bdev_discard_alignment(bdev) >> 9) & mask;
+
        /*
         * Ensure that max_discard_sectors is of the proper
-        * granularity
+        * granularity, so that requests stay aligned after a split.
         */
        max_discard_sectors = min(q->limits.max_discard_sectors, UINT_MAX >> 9);
+       max_discard_sectors = round_down(max_discard_sectors, granularity);
        if (unlikely(!max_discard_sectors)) {
                /* Avoid infinite loop below. Being cautious never hurts. */
                return -EOPNOTSUPP;
-       } else if (q->limits.discard_granularity) {
-               unsigned int disc_sects = q->limits.discard_granularity >> 9;
-
-               max_discard_sectors &= ~(disc_sects - 1);
        }
 
        if (flags & BLKDEV_DISCARD_SECURE) {
@@ -79,25 +82,37 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
        bb.wait = &wait;
 
        while (nr_sects) {
+               unsigned int req_sects;
+               sector_t end_sect;
+
                bio = bio_alloc(gfp_mask, 1);
                if (!bio) {
                        ret = -ENOMEM;
                        break;
                }
 
+               req_sects = min_t(sector_t, nr_sects, max_discard_sectors);
+
+               /*
+                * If splitting a request, and the next starting sector would be
+                * misaligned, stop the discard at the previous aligned sector.
+                */
+               end_sect = sector + req_sects;
+               if (req_sects < nr_sects && (end_sect & mask) != alignment) {
+                       end_sect =
+                               round_down(end_sect - alignment, granularity)
+                               + alignment;
+                       req_sects = end_sect - sector;
+               }
+
                bio->bi_sector = sector;
                bio->bi_end_io = bio_batch_end_io;
                bio->bi_bdev = bdev;
                bio->bi_private = &bb;
 
-               if (nr_sects > max_discard_sectors) {
-                       bio->bi_size = max_discard_sectors << 9;
-                       nr_sects -= max_discard_sectors;
-                       sector += max_discard_sectors;
-               } else {
-                       bio->bi_size = nr_sects << 9;
-                       nr_sects = 0;
-               }
+               bio->bi_size = req_sects << 9;
+               nr_sects -= req_sects;
+               sector = end_sect;
 
                atomic_inc(&bb.done);
                submit_bio(type, bio);
index 160035f548823482968bcd58298fcf9c309e7d62..e76279e411622519eebb54d4802eb11b796788db 100644 (file)
@@ -110,6 +110,49 @@ static int blk_phys_contig_segment(struct request_queue *q, struct bio *bio,
        return 0;
 }
 
+static void
+__blk_segment_map_sg(struct request_queue *q, struct bio_vec *bvec,
+                    struct scatterlist *sglist, struct bio_vec **bvprv,
+                    struct scatterlist **sg, int *nsegs, int *cluster)
+{
+
+       int nbytes = bvec->bv_len;
+
+       if (*bvprv && *cluster) {
+               if ((*sg)->length + nbytes > queue_max_segment_size(q))
+                       goto new_segment;
+
+               if (!BIOVEC_PHYS_MERGEABLE(*bvprv, bvec))
+                       goto new_segment;
+               if (!BIOVEC_SEG_BOUNDARY(q, *bvprv, bvec))
+                       goto new_segment;
+
+               (*sg)->length += nbytes;
+       } else {
+new_segment:
+               if (!*sg)
+                       *sg = sglist;
+               else {
+                       /*
+                        * If the driver previously mapped a shorter
+                        * list, we could see a termination bit
+                        * prematurely unless it fully inits the sg
+                        * table on each mapping. We KNOW that there
+                        * must be more entries here or the driver
+                        * would be buggy, so force clear the
+                        * termination bit to avoid doing a full
+                        * sg_init_table() in drivers for each command.
+                        */
+                       (*sg)->page_link &= ~0x02;
+                       *sg = sg_next(*sg);
+               }
+
+               sg_set_page(*sg, bvec->bv_page, nbytes, bvec->bv_offset);
+               (*nsegs)++;
+       }
+       *bvprv = bvec;
+}
+
 /*
  * map a request to scatterlist, return number of sg entries setup. Caller
  * must make sure sg can hold rq->nr_phys_segments entries
@@ -131,41 +174,8 @@ int blk_rq_map_sg(struct request_queue *q, struct request *rq,
        bvprv = NULL;
        sg = NULL;
        rq_for_each_segment(bvec, rq, iter) {
-               int nbytes = bvec->bv_len;
-
-               if (bvprv && cluster) {
-                       if (sg->length + nbytes > queue_max_segment_size(q))
-                               goto new_segment;
-
-                       if (!BIOVEC_PHYS_MERGEABLE(bvprv, bvec))
-                               goto new_segment;
-                       if (!BIOVEC_SEG_BOUNDARY(q, bvprv, bvec))
-                               goto new_segment;
-
-                       sg->length += nbytes;
-               } else {
-new_segment:
-                       if (!sg)
-                               sg = sglist;
-                       else {
-                               /*
-                                * If the driver previously mapped a shorter
-                                * list, we could see a termination bit
-                                * prematurely unless it fully inits the sg
-                                * table on each mapping. We KNOW that there
-                                * must be more entries here or the driver
-                                * would be buggy, so force clear the
-                                * termination bit to avoid doing a full
-                                * sg_init_table() in drivers for each command.
-                                */
-                               sg->page_link &= ~0x02;
-                               sg = sg_next(sg);
-                       }
-
-                       sg_set_page(sg, bvec->bv_page, nbytes, bvec->bv_offset);
-                       nsegs++;
-               }
-               bvprv = bvec;
+               __blk_segment_map_sg(q, bvec, sglist, &bvprv, &sg,
+                                    &nsegs, &cluster);
        } /* segments in rq */
 
 
@@ -199,6 +209,43 @@ new_segment:
 }
 EXPORT_SYMBOL(blk_rq_map_sg);
 
+/**
+ * blk_bio_map_sg - map a bio to a scatterlist
+ * @q: request_queue in question
+ * @bio: bio being mapped
+ * @sglist: scatterlist being mapped
+ *
+ * Note:
+ *    Caller must make sure sg can hold bio->bi_phys_segments entries
+ *
+ * Will return the number of sg entries setup
+ */
+int blk_bio_map_sg(struct request_queue *q, struct bio *bio,
+                  struct scatterlist *sglist)
+{
+       struct bio_vec *bvec, *bvprv;
+       struct scatterlist *sg;
+       int nsegs, cluster;
+       unsigned long i;
+
+       nsegs = 0;
+       cluster = blk_queue_cluster(q);
+
+       bvprv = NULL;
+       sg = NULL;
+       bio_for_each_segment(bvec, bio, i) {
+               __blk_segment_map_sg(q, bvec, sglist, &bvprv, &sg,
+                                    &nsegs, &cluster);
+       } /* segments in bio */
+
+       if (sg)
+               sg_mark_end(sg);
+
+       BUG_ON(bio->bi_phys_segments && nsegs > bio->bi_phys_segments);
+       return nsegs;
+}
+EXPORT_SYMBOL(blk_bio_map_sg);
+
 static inline int ll_new_hw_segment(struct request_queue *q,
                                    struct request *req,
                                    struct bio *bio)
index cac7366957c376cedb2341753520e6f32516572c..41d013e86f11d75bfe7a4c61861d66156470f28c 100644 (file)
@@ -835,7 +835,7 @@ static void disk_seqf_stop(struct seq_file *seqf, void *v)
 
 static void *show_partition_start(struct seq_file *seqf, loff_t *pos)
 {
-       static void *p;
+       void *p;
 
        p = disk_seqf_start(seqf, pos);
        if (!IS_ERR_OR_NULL(p) && !*pos)
@@ -1534,10 +1534,8 @@ void disk_flush_events(struct gendisk *disk, unsigned int mask)
 
        spin_lock_irq(&ev->lock);
        ev->clearing |= mask;
-       if (!ev->block) {
-               cancel_delayed_work(&ev->dwork);
-               queue_delayed_work(system_nrt_freezable_wq, &ev->dwork, 0);
-       }
+       if (!ev->block)
+               mod_delayed_work(system_nrt_freezable_wq, &ev->dwork, 0);
        spin_unlock_irq(&ev->lock);
 }
 
diff --git a/crypto/842.c b/crypto/842.c
new file mode 100644 (file)
index 0000000..144767d
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * Cryptographic API for the 842 compression algorithm.
+ *
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Copyright (C) IBM Corporation, 2011
+ *
+ * Authors: Robert Jennings <rcj@linux.vnet.ibm.com>
+ *          Seth Jennings <sjenning@linux.vnet.ibm.com>
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/crypto.h>
+#include <linux/vmalloc.h>
+#include <linux/nx842.h>
+#include <linux/lzo.h>
+#include <linux/timer.h>
+
+static int nx842_uselzo;
+
+struct nx842_ctx {
+       void *nx842_wmem; /* working memory for 842/lzo */
+};
+
+enum nx842_crypto_type {
+       NX842_CRYPTO_TYPE_842,
+       NX842_CRYPTO_TYPE_LZO
+};
+
+#define NX842_SENTINEL 0xdeadbeef
+
+struct nx842_crypto_header {
+       unsigned int sentinel; /* debug */
+       enum nx842_crypto_type type;
+};
+
+static int nx842_init(struct crypto_tfm *tfm)
+{
+       struct nx842_ctx *ctx = crypto_tfm_ctx(tfm);
+       int wmemsize;
+
+       wmemsize = max_t(int, nx842_get_workmem_size(), LZO1X_MEM_COMPRESS);
+       ctx->nx842_wmem = kmalloc(wmemsize, GFP_NOFS);
+       if (!ctx->nx842_wmem)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static void nx842_exit(struct crypto_tfm *tfm)
+{
+       struct nx842_ctx *ctx = crypto_tfm_ctx(tfm);
+
+       kfree(ctx->nx842_wmem);
+}
+
+static void nx842_reset_uselzo(unsigned long data)
+{
+       nx842_uselzo = 0;
+}
+
+static DEFINE_TIMER(failover_timer, nx842_reset_uselzo, 0, 0);
+
+static int nx842_crypto_compress(struct crypto_tfm *tfm, const u8 *src,
+                           unsigned int slen, u8 *dst, unsigned int *dlen)
+{
+       struct nx842_ctx *ctx = crypto_tfm_ctx(tfm);
+       struct nx842_crypto_header *hdr;
+       unsigned int tmp_len = *dlen;
+       size_t lzodlen; /* needed for lzo */
+       int err;
+
+       *dlen = 0;
+       hdr = (struct nx842_crypto_header *)dst;
+       hdr->sentinel = NX842_SENTINEL; /* debug */
+       dst += sizeof(struct nx842_crypto_header);
+       tmp_len -= sizeof(struct nx842_crypto_header);
+       lzodlen = tmp_len;
+
+       if (likely(!nx842_uselzo)) {
+               err = nx842_compress(src, slen, dst, &tmp_len, ctx->nx842_wmem);
+
+               if (likely(!err)) {
+                       hdr->type = NX842_CRYPTO_TYPE_842;
+                       *dlen = tmp_len + sizeof(struct nx842_crypto_header);
+                       return 0;
+               }
+
+               /* hardware failed */
+               nx842_uselzo = 1;
+
+               /* set timer to check for hardware again in 1 second */
+               mod_timer(&failover_timer, jiffies + msecs_to_jiffies(1000));
+       }
+
+       /* no hardware, use lzo */
+       err = lzo1x_1_compress(src, slen, dst, &lzodlen, ctx->nx842_wmem);
+       if (err != LZO_E_OK)
+               return -EINVAL;
+
+       hdr->type = NX842_CRYPTO_TYPE_LZO;
+       *dlen = lzodlen + sizeof(struct nx842_crypto_header);
+       return 0;
+}
+
+static int nx842_crypto_decompress(struct crypto_tfm *tfm, const u8 *src,
+                             unsigned int slen, u8 *dst, unsigned int *dlen)
+{
+       struct nx842_ctx *ctx = crypto_tfm_ctx(tfm);
+       struct nx842_crypto_header *hdr;
+       unsigned int tmp_len = *dlen;
+       size_t lzodlen; /* needed for lzo */
+       int err;
+
+       *dlen = 0;
+       hdr = (struct nx842_crypto_header *)src;
+
+       if (unlikely(hdr->sentinel != NX842_SENTINEL))
+               return -EINVAL;
+
+       src += sizeof(struct nx842_crypto_header);
+       slen -= sizeof(struct nx842_crypto_header);
+
+       if (likely(hdr->type == NX842_CRYPTO_TYPE_842)) {
+               err = nx842_decompress(src, slen, dst, &tmp_len,
+                       ctx->nx842_wmem);
+               if (err)
+                       return -EINVAL;
+               *dlen = tmp_len;
+       } else if (hdr->type == NX842_CRYPTO_TYPE_LZO) {
+               lzodlen = tmp_len;
+               err = lzo1x_decompress_safe(src, slen, dst, &lzodlen);
+               if (err != LZO_E_OK)
+                       return -EINVAL;
+               *dlen = lzodlen;
+       } else
+               return -EINVAL;
+
+       return 0;
+}
+
+static struct crypto_alg alg = {
+       .cra_name               = "842",
+       .cra_flags              = CRYPTO_ALG_TYPE_COMPRESS,
+       .cra_ctxsize            = sizeof(struct nx842_ctx),
+       .cra_module             = THIS_MODULE,
+       .cra_list               = LIST_HEAD_INIT(alg.cra_list),
+       .cra_init               = nx842_init,
+       .cra_exit               = nx842_exit,
+       .cra_u                  = { .compress = {
+       .coa_compress           = nx842_crypto_compress,
+       .coa_decompress         = nx842_crypto_decompress } }
+};
+
+static int __init nx842_mod_init(void)
+{
+       del_timer(&failover_timer);
+       return crypto_register_alg(&alg);
+}
+
+static void __exit nx842_mod_exit(void)
+{
+       crypto_unregister_alg(&alg);
+}
+
+module_init(nx842_mod_init);
+module_exit(nx842_mod_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("842 Compression Algorithm");
index a3238051b03e73b2ab3f79e267b1e47a8716dc74..cbcc0e2eeda0d7f5c733c14521cd49654cda486d 100644 (file)
@@ -692,6 +692,20 @@ config CRYPTO_CAST5
          The CAST5 encryption algorithm (synonymous with CAST-128) is
          described in RFC2144.
 
+config CRYPTO_CAST5_AVX_X86_64
+       tristate "CAST5 (CAST-128) cipher algorithm (x86_64/AVX)"
+       depends on X86 && 64BIT
+       select CRYPTO_ALGAPI
+       select CRYPTO_CRYPTD
+       select CRYPTO_ABLK_HELPER_X86
+       select CRYPTO_CAST5
+       help
+         The CAST5 encryption algorithm (synonymous with CAST-128) is
+         described in RFC2144.
+
+         This module provides the Cast5 cipher algorithm that processes
+         sixteen blocks parallel using the AVX instruction set.
+
 config CRYPTO_CAST6
        tristate "CAST6 (CAST-256) cipher algorithm"
        select CRYPTO_ALGAPI
@@ -699,6 +713,23 @@ config CRYPTO_CAST6
          The CAST6 encryption algorithm (synonymous with CAST-256) is
          described in RFC2612.
 
+config CRYPTO_CAST6_AVX_X86_64
+       tristate "CAST6 (CAST-256) cipher algorithm (x86_64/AVX)"
+       depends on X86 && 64BIT
+       select CRYPTO_ALGAPI
+       select CRYPTO_CRYPTD
+       select CRYPTO_ABLK_HELPER_X86
+       select CRYPTO_GLUE_HELPER_X86
+       select CRYPTO_CAST6
+       select CRYPTO_LRW
+       select CRYPTO_XTS
+       help
+         The CAST6 encryption algorithm (synonymous with CAST-256) is
+         described in RFC2612.
+
+         This module provides the Cast6 cipher algorithm that processes
+         eight blocks parallel using the AVX instruction set.
+
 config CRYPTO_DES
        tristate "DES and Triple DES EDE cipher algorithms"
        select CRYPTO_ALGAPI
@@ -1008,6 +1039,15 @@ config CRYPTO_LZO
        help
          This is the LZO algorithm.
 
+config CRYPTO_842
+       tristate "842 compression algorithm"
+       depends on CRYPTO_DEV_NX_COMPRESS
+       # 842 uses lzo if the hardware becomes unavailable
+       select LZO_COMPRESS
+       select LZO_DECOMPRESS
+       help
+         This is the 842 algorithm.
+
 comment "Random Number Generation"
 
 config CRYPTO_ANSI_CPRNG
index 30f33d675330e4adfe680a343e98448a82a6171d..a301ad2b258c0cdbee39dbfecb1684235a6e0a48 100644 (file)
@@ -68,8 +68,8 @@ obj-$(CONFIG_CRYPTO_TWOFISH_COMMON) += twofish_common.o
 obj-$(CONFIG_CRYPTO_SERPENT) += serpent_generic.o
 obj-$(CONFIG_CRYPTO_AES) += aes_generic.o
 obj-$(CONFIG_CRYPTO_CAMELLIA) += camellia_generic.o
-obj-$(CONFIG_CRYPTO_CAST5) += cast5.o
-obj-$(CONFIG_CRYPTO_CAST6) += cast6.o
+obj-$(CONFIG_CRYPTO_CAST5) += cast5_generic.o
+obj-$(CONFIG_CRYPTO_CAST6) += cast6_generic.o
 obj-$(CONFIG_CRYPTO_ARC4) += arc4.o
 obj-$(CONFIG_CRYPTO_TEA) += tea.o
 obj-$(CONFIG_CRYPTO_KHAZAD) += khazad.o
@@ -82,6 +82,7 @@ obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
 obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o
 obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o authencesn.o
 obj-$(CONFIG_CRYPTO_LZO) += lzo.o
+obj-$(CONFIG_CRYPTO_842) += 842.o
 obj-$(CONFIG_CRYPTO_RNG2) += rng.o
 obj-$(CONFIG_CRYPTO_RNG2) += krng.o
 obj-$(CONFIG_CRYPTO_ANSI_CPRNG) += ansi_cprng.o
index a68c73dae15ad3e2a5408c3ddbf6a82885ec3b0e..47f2e5c717591847ed598db32b209bd6f1bbd254 100644 (file)
@@ -1448,7 +1448,6 @@ static struct crypto_alg aes_alg = {
        .cra_ctxsize            =       sizeof(struct crypto_aes_ctx),
        .cra_alignmask          =       3,
        .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(aes_alg.cra_list),
        .cra_u                  =       {
                .cipher = {
                        .cia_min_keysize        =       AES_MIN_KEY_SIZE,
index 6ddd99e6114b08fcef25cde0a3cfaa31885e9556..c0bb3778f1ae06976fbaf07c7e1b075fc0c581e7 100644 (file)
@@ -382,26 +382,6 @@ static int cprng_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen)
        return 0;
 }
 
-static struct crypto_alg rng_alg = {
-       .cra_name               = "stdrng",
-       .cra_driver_name        = "ansi_cprng",
-       .cra_priority           = 100,
-       .cra_flags              = CRYPTO_ALG_TYPE_RNG,
-       .cra_ctxsize            = sizeof(struct prng_context),
-       .cra_type               = &crypto_rng_type,
-       .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(rng_alg.cra_list),
-       .cra_init               = cprng_init,
-       .cra_exit               = cprng_exit,
-       .cra_u                  = {
-               .rng = {
-                       .rng_make_random        = cprng_get_random,
-                       .rng_reset              = cprng_reset,
-                       .seedsize = DEFAULT_PRNG_KSZ + 2*DEFAULT_BLK_SZ,
-               }
-       }
-};
-
 #ifdef CONFIG_CRYPTO_FIPS
 static int fips_cprng_get_random(struct crypto_rng *tfm, u8 *rdata,
                            unsigned int dlen)
@@ -438,8 +418,27 @@ static int fips_cprng_reset(struct crypto_rng *tfm, u8 *seed, unsigned int slen)
 out:
        return rc;
 }
+#endif
 
-static struct crypto_alg fips_rng_alg = {
+static struct crypto_alg rng_algs[] = { {
+       .cra_name               = "stdrng",
+       .cra_driver_name        = "ansi_cprng",
+       .cra_priority           = 100,
+       .cra_flags              = CRYPTO_ALG_TYPE_RNG,
+       .cra_ctxsize            = sizeof(struct prng_context),
+       .cra_type               = &crypto_rng_type,
+       .cra_module             = THIS_MODULE,
+       .cra_init               = cprng_init,
+       .cra_exit               = cprng_exit,
+       .cra_u                  = {
+               .rng = {
+                       .rng_make_random        = cprng_get_random,
+                       .rng_reset              = cprng_reset,
+                       .seedsize = DEFAULT_PRNG_KSZ + 2*DEFAULT_BLK_SZ,
+               }
+       }
+#ifdef CONFIG_CRYPTO_FIPS
+}, {
        .cra_name               = "fips(ansi_cprng)",
        .cra_driver_name        = "fips_ansi_cprng",
        .cra_priority           = 300,
@@ -447,7 +446,6 @@ static struct crypto_alg fips_rng_alg = {
        .cra_ctxsize            = sizeof(struct prng_context),
        .cra_type               = &crypto_rng_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(rng_alg.cra_list),
        .cra_init               = cprng_init,
        .cra_exit               = cprng_exit,
        .cra_u                  = {
@@ -457,33 +455,18 @@ static struct crypto_alg fips_rng_alg = {
                        .seedsize = DEFAULT_PRNG_KSZ + 2*DEFAULT_BLK_SZ,
                }
        }
-};
 #endif
+} };
 
 /* Module initalization */
 static int __init prng_mod_init(void)
 {
-       int rc = 0;
-
-       rc = crypto_register_alg(&rng_alg);
-#ifdef CONFIG_CRYPTO_FIPS
-       if (rc)
-               goto out;
-
-       rc = crypto_register_alg(&fips_rng_alg);
-
-out:
-#endif
-       return rc;
+       return crypto_register_algs(rng_algs, ARRAY_SIZE(rng_algs));
 }
 
 static void __exit prng_mod_fini(void)
 {
-       crypto_unregister_alg(&rng_alg);
-#ifdef CONFIG_CRYPTO_FIPS
-       crypto_unregister_alg(&fips_rng_alg);
-#endif
-       return;
+       crypto_unregister_algs(rng_algs, ARRAY_SIZE(rng_algs));
 }
 
 MODULE_LICENSE("GPL");
index 77530d571c961daf18abc05bbc1e8adc4ea195fd..008c8a4fb67ca77de02bc1c0359b4ef77c2b452d 100644 (file)
@@ -678,7 +678,6 @@ static struct crypto_alg anubis_alg = {
        .cra_ctxsize            =       sizeof (struct anubis_ctx),
        .cra_alignmask          =       3,
        .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(anubis_alg.cra_list),
        .cra_u                  =       { .cipher = {
        .cia_min_keysize        =       ANUBIS_MIN_KEY_SIZE,
        .cia_max_keysize        =       ANUBIS_MAX_KEY_SIZE,
index 6f269b5cfa3b1da05eeeb6f6ae5db7d99b85d4d1..8baf5447d35b58f70bc43fa1bfb6f3de896813ae 100644 (file)
@@ -115,7 +115,6 @@ static struct crypto_alg alg = {
        .cra_ctxsize            =       sizeof(struct bf_ctx),
        .cra_alignmask          =       3,
        .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(alg.cra_list),
        .cra_u                  =       { .cipher = {
        .cia_min_keysize        =       BF_MIN_KEY_SIZE,
        .cia_max_keysize        =       BF_MAX_KEY_SIZE,
index f7aaaaf869829c553cc34c90403b81a367762894..75efa20523053661e35fe209feaab50b418dc364 100644 (file)
@@ -1072,7 +1072,6 @@ static struct crypto_alg camellia_alg = {
        .cra_ctxsize            =       sizeof(struct camellia_ctx),
        .cra_alignmask          =       3,
        .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(camellia_alg.cra_list),
        .cra_u                  =       {
                .cipher = {
                        .cia_min_keysize        =       CAMELLIA_MIN_KEY_SIZE,
similarity index 95%
rename from crypto/cast5.c
rename to crypto/cast5_generic.c
index 4a230ddec87741ae1cd6398f90a27721ff5e085d..bc525dbd8a4bfa79009d2838ac1dd0d0f379ac7e 100644 (file)
@@ -4,8 +4,8 @@
 * Derived from GnuPG implementation of cast5.
 *
 * Major Changes.
-*      Complete conformance to rfc2144.
-*      Supports key size from 40 to 128 bits.
+*      Complete conformance to rfc2144.
+*      Supports key size from 40 to 128 bits.
 *
 * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
 * Copyright (C) 2003 Kartikey Mahendra Bhatt <kartik_me@hotmail.com>.
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/types.h>
+#include <crypto/cast5.h>
 
-#define CAST5_BLOCK_SIZE 8
-#define CAST5_MIN_KEY_SIZE 5
-#define CAST5_MAX_KEY_SIZE 16
 
-struct cast5_ctx {
-       u32 Km[16];
-       u8 Kr[16];
-       int rr; /* rr?number of rounds = 16:number of rounds = 12; (rfc 2144) */
-};
-
-
-static const u32 s1[256] = {
+const u32 cast5_s1[256] = {
        0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f,
        0x9c004dd3, 0x6003e540, 0xcf9fc949,
        0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0,
@@ -106,7 +97,8 @@ static const u32 s1[256] = {
        0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c,
        0x5ac9f049, 0xdd8f0f00, 0x5c8165bf
 };
-static const u32 s2[256] = {
+EXPORT_SYMBOL_GPL(cast5_s1);
+const u32 cast5_s2[256] = {
        0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a,
        0xeec5207a, 0x55889c94, 0x72fc0651,
        0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef,
@@ -172,7 +164,8 @@ static const u32 s2[256] = {
        0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539,
        0x73bfbe70, 0x83877605, 0x4523ecf1
 };
-static const u32 s3[256] = {
+EXPORT_SYMBOL_GPL(cast5_s2);
+const u32 cast5_s3[256] = {
        0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff,
        0x369fe44b, 0x8c1fc644, 0xaececa90,
        0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806,
@@ -238,7 +231,8 @@ static const u32 s3[256] = {
        0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636,
        0xa133c501, 0xe9d3531c, 0xee353783
 };
-static const u32 s4[256] = {
+EXPORT_SYMBOL_GPL(cast5_s3);
+const u32 cast5_s4[256] = {
        0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb,
        0x64ad8c57, 0x85510443, 0xfa020ed1,
        0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43,
@@ -304,6 +298,7 @@ static const u32 s4[256] = {
        0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0,
        0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2
 };
+EXPORT_SYMBOL_GPL(cast5_s4);
 static const u32 s5[256] = {
        0x7ec90c04, 0x2c6e74b9, 0x9b0e66df, 0xa6337911, 0xb86a7fff,
        0x1dd358f5, 0x44dd9d44, 0x1731167f,
@@ -569,17 +564,21 @@ static const u32 sb8[256] = {
        0xeaee6801, 0x8db2a283, 0xea8bf59e
 };
 
+#define s1 cast5_s1
+#define s2 cast5_s2
+#define s3 cast5_s3
+#define s4 cast5_s4
+
 #define F1(D, m, r)  ((I = ((m) + (D))), (I = rol32(I, (r))),   \
-    (((s1[I >> 24] ^ s2[(I>>16)&0xff]) - s3[(I>>8)&0xff]) + s4[I&0xff]))
+       (((s1[I >> 24] ^ s2[(I>>16)&0xff]) - s3[(I>>8)&0xff]) + s4[I&0xff]))
 #define F2(D, m, r)  ((I = ((m) ^ (D))), (I = rol32(I, (r))),   \
-    (((s1[I >> 24] - s2[(I>>16)&0xff]) + s3[(I>>8)&0xff]) ^ s4[I&0xff]))
+       (((s1[I >> 24] - s2[(I>>16)&0xff]) + s3[(I>>8)&0xff]) ^ s4[I&0xff]))
 #define F3(D, m, r)  ((I = ((m) - (D))), (I = rol32(I, (r))),   \
-    (((s1[I >> 24] + s2[(I>>16)&0xff]) ^ s3[(I>>8)&0xff]) - s4[I&0xff]))
+       (((s1[I >> 24] + s2[(I>>16)&0xff]) ^ s3[(I>>8)&0xff]) - s4[I&0xff]))
 
 
-static void cast5_encrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf)
+void __cast5_encrypt(struct cast5_ctx *c, u8 *outbuf, const u8 *inbuf)
 {
-       struct cast5_ctx *c = crypto_tfm_ctx(tfm);
        const __be32 *src = (const __be32 *)inbuf;
        __be32 *dst = (__be32 *)outbuf;
        u32 l, r, t;
@@ -628,10 +627,15 @@ static void cast5_encrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf)
        dst[0] = cpu_to_be32(r);
        dst[1] = cpu_to_be32(l);
 }
+EXPORT_SYMBOL_GPL(__cast5_encrypt);
 
-static void cast5_decrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf)
+static void cast5_encrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf)
+{
+       __cast5_encrypt(crypto_tfm_ctx(tfm), outbuf, inbuf);
+}
+
+void __cast5_decrypt(struct cast5_ctx *c, u8 *outbuf, const u8 *inbuf)
 {
-       struct cast5_ctx *c = crypto_tfm_ctx(tfm);
        const __be32 *src = (const __be32 *)inbuf;
        __be32 *dst = (__be32 *)outbuf;
        u32 l, r, t;
@@ -667,6 +671,12 @@ static void cast5_decrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf)
        dst[0] = cpu_to_be32(r);
        dst[1] = cpu_to_be32(l);
 }
+EXPORT_SYMBOL_GPL(__cast5_decrypt);
+
+static void cast5_decrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf)
+{
+       __cast5_decrypt(crypto_tfm_ctx(tfm), outbuf, inbuf);
+}
 
 static void key_schedule(u32 *x, u32 *z, u32 *k)
 {
@@ -743,7 +753,7 @@ static void key_schedule(u32 *x, u32 *z, u32 *k)
 }
 
 
-static int cast5_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned key_len)
+int cast5_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int key_len)
 {
        struct cast5_ctx *c = crypto_tfm_ctx(tfm);
        int i;
@@ -771,20 +781,22 @@ static int cast5_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned key_len)
                c->Kr[i] = k[i] & 0x1f;
        return 0;
 }
+EXPORT_SYMBOL_GPL(cast5_setkey);
 
 static struct crypto_alg alg = {
-       .cra_name       = "cast5",
-       .cra_flags      = CRYPTO_ALG_TYPE_CIPHER,
-       .cra_blocksize  = CAST5_BLOCK_SIZE,
-       .cra_ctxsize    = sizeof(struct cast5_ctx),
-       .cra_alignmask  = 3,
-       .cra_module     = THIS_MODULE,
-       .cra_list       = LIST_HEAD_INIT(alg.cra_list),
-       .cra_u          = {
+       .cra_name               = "cast5",
+       .cra_driver_name        = "cast5-generic",
+       .cra_priority           = 100,
+       .cra_flags              = CRYPTO_ALG_TYPE_CIPHER,
+       .cra_blocksize          = CAST5_BLOCK_SIZE,
+       .cra_ctxsize            = sizeof(struct cast5_ctx),
+       .cra_alignmask          = 3,
+       .cra_module             = THIS_MODULE,
+       .cra_u                  = {
                .cipher = {
                        .cia_min_keysize = CAST5_MIN_KEY_SIZE,
                        .cia_max_keysize = CAST5_MAX_KEY_SIZE,
-                       .cia_setkey = cast5_setkey,
+                       .cia_setkey  = cast5_setkey,
                        .cia_encrypt = cast5_encrypt,
                        .cia_decrypt = cast5_decrypt
                }
@@ -806,4 +818,4 @@ module_exit(cast5_mod_fini);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Cast5 Cipher Algorithm");
-
+MODULE_ALIAS("cast5");
similarity index 94%
rename from crypto/cast6.c
rename to crypto/cast6_generic.c
index e0c15a6c7c34d72fd3fa7c1c114197b07b0f7cd4..dc9309d704051f59264c40e4f8c6592b3625d205 100644 (file)
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/types.h>
+#include <crypto/cast6.h>
 
-#define CAST6_BLOCK_SIZE 16
-#define CAST6_MIN_KEY_SIZE 16
-#define CAST6_MAX_KEY_SIZE 32
-
-struct cast6_ctx {
-       u32 Km[12][4];
-       u8 Kr[12][4];
-};
+#define s1 cast6_s1
+#define s2 cast6_s2
+#define s3 cast6_s3
+#define s4 cast6_s4
 
 #define F1(D, r, m)  ((I = ((m) + (D))), (I = rol32(I, (r))),   \
-    (((s1[I >> 24] ^ s2[(I>>16)&0xff]) - s3[(I>>8)&0xff]) + s4[I&0xff]))
+       (((s1[I >> 24] ^ s2[(I>>16)&0xff]) - s3[(I>>8)&0xff]) + s4[I&0xff]))
 #define F2(D, r, m)  ((I = ((m) ^ (D))), (I = rol32(I, (r))),   \
-    (((s1[I >> 24] - s2[(I>>16)&0xff]) + s3[(I>>8)&0xff]) ^ s4[I&0xff]))
+       (((s1[I >> 24] - s2[(I>>16)&0xff]) + s3[(I>>8)&0xff]) ^ s4[I&0xff]))
 #define F3(D, r, m)  ((I = ((m) - (D))), (I = rol32(I, (r))),   \
-    (((s1[I >> 24] + s2[(I>>16)&0xff]) ^ s3[(I>>8)&0xff]) - s4[I&0xff]))
+       (((s1[I >> 24] + s2[(I>>16)&0xff]) ^ s3[(I>>8)&0xff]) - s4[I&0xff]))
 
-static const u32 s1[256] = {
+const u32 cast6_s1[256] = {
        0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f,
        0x9c004dd3, 0x6003e540, 0xcf9fc949,
        0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0,
@@ -108,8 +105,9 @@ static const u32 s1[256] = {
        0x1a69e783, 0x02cc4843, 0xa2f7c579, 0x429ef47d, 0x427b169c,
        0x5ac9f049, 0xdd8f0f00, 0x5c8165bf
 };
+EXPORT_SYMBOL_GPL(cast6_s1);
 
-static const u32 s2[256] = {
+const u32 cast6_s2[256] = {
        0x1f201094, 0xef0ba75b, 0x69e3cf7e, 0x393f4380, 0xfe61cf7a,
        0xeec5207a, 0x55889c94, 0x72fc0651,
        0xada7ef79, 0x4e1d7235, 0xd55a63ce, 0xde0436ba, 0x99c430ef,
@@ -175,8 +173,9 @@ static const u32 s2[256] = {
        0x43d79572, 0x7e6dd07c, 0x06dfdf1e, 0x6c6cc4ef, 0x7160a539,
        0x73bfbe70, 0x83877605, 0x4523ecf1
 };
+EXPORT_SYMBOL_GPL(cast6_s2);
 
-static const u32 s3[256] = {
+const u32 cast6_s3[256] = {
        0x8defc240, 0x25fa5d9f, 0xeb903dbf, 0xe810c907, 0x47607fff,
        0x369fe44b, 0x8c1fc644, 0xaececa90,
        0xbeb1f9bf, 0xeefbcaea, 0xe8cf1950, 0x51df07ae, 0x920e8806,
@@ -242,8 +241,9 @@ static const u32 s3[256] = {
        0xf7baefd5, 0x4142ed9c, 0xa4315c11, 0x83323ec5, 0xdfef4636,
        0xa133c501, 0xe9d3531c, 0xee353783
 };
+EXPORT_SYMBOL_GPL(cast6_s3);
 
-static const u32 s4[256] = {
+const u32 cast6_s4[256] = {
        0x9db30420, 0x1fb6e9de, 0xa7be7bef, 0xd273a298, 0x4a4f7bdb,
        0x64ad8c57, 0x85510443, 0xfa020ed1,
        0x7e287aff, 0xe60fb663, 0x095f35a1, 0x79ebf120, 0xfd059d43,
@@ -309,6 +309,7 @@ static const u32 s4[256] = {
        0x7ae5290c, 0x3cb9536b, 0x851e20fe, 0x9833557e, 0x13ecf0b0,
        0xd3ffb372, 0x3f85c5c1, 0x0aef7ed2
 };
+EXPORT_SYMBOL_GPL(cast6_s4);
 
 static const u32 Tm[24][8] = {
        { 0x5a827999, 0xc95c653a, 0x383650db, 0xa7103c7c, 0x15ea281d,
@@ -382,14 +383,12 @@ static void W(u32 *key, unsigned int i)
        key[7] ^= F2(key[0], Tr[i % 4][7], Tm[i][7]);
 }
 
-static int cast6_setkey(struct crypto_tfm *tfm, const u8 *in_key,
-                       unsigned key_len)
+int __cast6_setkey(struct cast6_ctx *c, const u8 *in_key,
+                  unsigned key_len, u32 *flags)
 {
        int i;
        u32 key[8];
        __be32 p_key[8]; /* padded key */
-       struct cast6_ctx *c = crypto_tfm_ctx(tfm);
-       u32 *flags = &tfm->crt_flags;
 
        if (key_len % 4 != 0) {
                *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
@@ -425,6 +424,14 @@ static int cast6_setkey(struct crypto_tfm *tfm, const u8 *in_key,
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(__cast6_setkey);
+
+int cast6_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
+{
+       return __cast6_setkey(crypto_tfm_ctx(tfm), key, keylen,
+                             &tfm->crt_flags);
+}
+EXPORT_SYMBOL_GPL(cast6_setkey);
 
 /*forward quad round*/
 static void Q(u32 *block, u8 *Kr, u32 *Km)
@@ -446,9 +453,8 @@ static void QBAR(u32 *block, u8 *Kr, u32 *Km)
        block[2] ^= F1(block[3], Kr[0], Km[0]);
 }
 
-static void cast6_encrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf)
+void __cast6_encrypt(struct cast6_ctx *c, u8 *outbuf, const u8 *inbuf)
 {
-       struct cast6_ctx *c = crypto_tfm_ctx(tfm);
        const __be32 *src = (const __be32 *)inbuf;
        __be32 *dst = (__be32 *)outbuf;
        u32 block[4];
@@ -478,10 +484,15 @@ static void cast6_encrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf)
        dst[2] = cpu_to_be32(block[2]);
        dst[3] = cpu_to_be32(block[3]);
 }
+EXPORT_SYMBOL_GPL(__cast6_encrypt);
 
-static void cast6_decrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf)
+static void cast6_encrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf)
+{
+       __cast6_encrypt(crypto_tfm_ctx(tfm), outbuf, inbuf);
+}
+
+void __cast6_decrypt(struct cast6_ctx *c, u8 *outbuf, const u8 *inbuf)
 {
-       struct cast6_ctx *c = crypto_tfm_ctx(tfm);
        const __be32 *src = (const __be32 *)inbuf;
        __be32 *dst = (__be32 *)outbuf;
        u32 block[4];
@@ -511,15 +522,22 @@ static void cast6_decrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf)
        dst[2] = cpu_to_be32(block[2]);
        dst[3] = cpu_to_be32(block[3]);
 }
+EXPORT_SYMBOL_GPL(__cast6_decrypt);
+
+static void cast6_decrypt(struct crypto_tfm *tfm, u8 *outbuf, const u8 *inbuf)
+{
+       __cast6_decrypt(crypto_tfm_ctx(tfm), outbuf, inbuf);
+}
 
 static struct crypto_alg alg = {
        .cra_name = "cast6",
+       .cra_driver_name = "cast6-generic",
+       .cra_priority = 100,
        .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
        .cra_blocksize = CAST6_BLOCK_SIZE,
        .cra_ctxsize = sizeof(struct cast6_ctx),
        .cra_alignmask = 3,
        .cra_module = THIS_MODULE,
-       .cra_list = LIST_HEAD_INIT(alg.cra_list),
        .cra_u = {
                  .cipher = {
                             .cia_min_keysize = CAST6_MIN_KEY_SIZE,
@@ -545,3 +563,4 @@ module_exit(cast6_mod_fini);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Cast6 Cipher Algorithm");
+MODULE_ALIAS("cast6");
index 07a8a96d46fc1f2ef373ebb485ebf37287636726..fee7265cd35df5aa3d752e3294cb0f50fada64d2 100644 (file)
@@ -94,18 +94,6 @@ static int skcipher_null_crypt(struct blkcipher_desc *desc,
        return err;
 }
 
-static struct crypto_alg compress_null = {
-       .cra_name               =       "compress_null",
-       .cra_flags              =       CRYPTO_ALG_TYPE_COMPRESS,
-       .cra_blocksize          =       NULL_BLOCK_SIZE,
-       .cra_ctxsize            =       0,
-       .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(compress_null.cra_list),
-       .cra_u                  =       { .compress = {
-       .coa_compress           =       null_compress,
-       .coa_decompress         =       null_compress } }
-};
-
 static struct shash_alg digest_null = {
        .digestsize             =       NULL_DIGEST_SIZE,
        .setkey                 =       null_hash_setkey,
@@ -122,22 +110,19 @@ static struct shash_alg digest_null = {
        }
 };
 
-static struct crypto_alg cipher_null = {
+static struct crypto_alg null_algs[3] = { {
        .cra_name               =       "cipher_null",
        .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
        .cra_blocksize          =       NULL_BLOCK_SIZE,
        .cra_ctxsize            =       0,
        .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(cipher_null.cra_list),
        .cra_u                  =       { .cipher = {
        .cia_min_keysize        =       NULL_KEY_SIZE,
        .cia_max_keysize        =       NULL_KEY_SIZE,
        .cia_setkey             =       null_setkey,
        .cia_encrypt            =       null_crypt,
        .cia_decrypt            =       null_crypt } }
-};
-
-static struct crypto_alg skcipher_null = {
+}, {
        .cra_name               =       "ecb(cipher_null)",
        .cra_driver_name        =       "ecb-cipher_null",
        .cra_priority           =       100,
@@ -146,7 +131,6 @@ static struct crypto_alg skcipher_null = {
        .cra_type               =       &crypto_blkcipher_type,
        .cra_ctxsize            =       0,
        .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(skcipher_null.cra_list),
        .cra_u                  =       { .blkcipher = {
        .min_keysize            =       NULL_KEY_SIZE,
        .max_keysize            =       NULL_KEY_SIZE,
@@ -154,7 +138,16 @@ static struct crypto_alg skcipher_null = {
        .setkey                 =       null_setkey,
        .encrypt                =       skcipher_null_crypt,
        .decrypt                =       skcipher_null_crypt } }
-};
+}, {
+       .cra_name               =       "compress_null",
+       .cra_flags              =       CRYPTO_ALG_TYPE_COMPRESS,
+       .cra_blocksize          =       NULL_BLOCK_SIZE,
+       .cra_ctxsize            =       0,
+       .cra_module             =       THIS_MODULE,
+       .cra_u                  =       { .compress = {
+       .coa_compress           =       null_compress,
+       .coa_decompress         =       null_compress } }
+} };
 
 MODULE_ALIAS("compress_null");
 MODULE_ALIAS("digest_null");
@@ -164,40 +157,26 @@ static int __init crypto_null_mod_init(void)
 {
        int ret = 0;
 
-       ret = crypto_register_alg(&cipher_null);
+       ret = crypto_register_algs(null_algs, ARRAY_SIZE(null_algs));
        if (ret < 0)
                goto out;
 
-       ret = crypto_register_alg(&skcipher_null);
-       if (ret < 0)
-               goto out_unregister_cipher;
-
        ret = crypto_register_shash(&digest_null);
        if (ret < 0)
-               goto out_unregister_skcipher;
+               goto out_unregister_algs;
 
-       ret = crypto_register_alg(&compress_null);
-       if (ret < 0)
-               goto out_unregister_digest;
+       return 0;
 
+out_unregister_algs:
+       crypto_unregister_algs(null_algs, ARRAY_SIZE(null_algs));
 out:
        return ret;
-
-out_unregister_digest:
-       crypto_unregister_shash(&digest_null);
-out_unregister_skcipher:
-       crypto_unregister_alg(&skcipher_null);
-out_unregister_cipher:
-       crypto_unregister_alg(&cipher_null);
-       goto out;
 }
 
 static void __exit crypto_null_mod_fini(void)
 {
-       crypto_unregister_alg(&compress_null);
        crypto_unregister_shash(&digest_null);
-       crypto_unregister_alg(&skcipher_null);
-       crypto_unregister_alg(&cipher_null);
+       crypto_unregister_algs(null_algs, ARRAY_SIZE(null_algs));
 }
 
 module_init(crypto_null_mod_init);
index b0165ecad0c5c4a407d76a24b2753bed2b77cf87..b57d70eb156b8c424b87d217c59f4700a0d3edca 100644 (file)
@@ -199,7 +199,6 @@ static struct crypto_alg alg = {
        .cra_flags              = CRYPTO_ALG_TYPE_COMPRESS,
        .cra_ctxsize            = sizeof(struct deflate_ctx),
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(alg.cra_list),
        .cra_init               = deflate_init,
        .cra_exit               = deflate_exit,
        .cra_u                  = { .compress = {
index 873818d48e86939b9492a158a3cd86a9d16b97b9..f6cf63f8846826506fc0068ba53142a52688dfd8 100644 (file)
@@ -943,59 +943,44 @@ static void des3_ede_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
        d[1] = cpu_to_le32(L);
 }
 
-static struct crypto_alg des_alg = {
+static struct crypto_alg des_algs[2] = { {
        .cra_name               =       "des",
        .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
        .cra_blocksize          =       DES_BLOCK_SIZE,
        .cra_ctxsize            =       sizeof(struct des_ctx),
        .cra_module             =       THIS_MODULE,
        .cra_alignmask          =       3,
-       .cra_list               =       LIST_HEAD_INIT(des_alg.cra_list),
        .cra_u                  =       { .cipher = {
        .cia_min_keysize        =       DES_KEY_SIZE,
        .cia_max_keysize        =       DES_KEY_SIZE,
        .cia_setkey             =       des_setkey,
        .cia_encrypt            =       des_encrypt,
        .cia_decrypt            =       des_decrypt } }
-};
-
-static struct crypto_alg des3_ede_alg = {
+}, {
        .cra_name               =       "des3_ede",
        .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
        .cra_blocksize          =       DES3_EDE_BLOCK_SIZE,
        .cra_ctxsize            =       sizeof(struct des3_ede_ctx),
        .cra_module             =       THIS_MODULE,
        .cra_alignmask          =       3,
-       .cra_list               =       LIST_HEAD_INIT(des3_ede_alg.cra_list),
        .cra_u                  =       { .cipher = {
        .cia_min_keysize        =       DES3_EDE_KEY_SIZE,
        .cia_max_keysize        =       DES3_EDE_KEY_SIZE,
        .cia_setkey             =       des3_ede_setkey,
        .cia_encrypt            =       des3_ede_encrypt,
        .cia_decrypt            =       des3_ede_decrypt } }
-};
+} };
 
 MODULE_ALIAS("des3_ede");
 
 static int __init des_generic_mod_init(void)
 {
-       int ret = 0;
-
-       ret = crypto_register_alg(&des_alg);
-       if (ret < 0)
-               goto out;
-
-       ret = crypto_register_alg(&des3_ede_alg);
-       if (ret < 0)
-               crypto_unregister_alg(&des_alg);
-out:
-       return ret;
+       return crypto_register_algs(des_algs, ARRAY_SIZE(des_algs));
 }
 
 static void __exit des_generic_mod_fini(void)
 {
-       crypto_unregister_alg(&des3_ede_alg);
-       crypto_unregister_alg(&des_alg);
+       crypto_unregister_algs(des_algs, ARRAY_SIZE(des_algs));
 }
 
 module_init(des_generic_mod_init);
index c33107e340b6c3774a1f709f14b889c8c034c19d..3b2cf569c684fa5c8a278a4919f9ee8513fb79b3 100644 (file)
@@ -396,7 +396,6 @@ static struct crypto_alg fcrypt_alg = {
        .cra_ctxsize            =       sizeof(struct fcrypt_ctx),
        .cra_module             =       THIS_MODULE,
        .cra_alignmask          =       3,
-       .cra_list               =       LIST_HEAD_INIT(fcrypt_alg.cra_list),
        .cra_u                  =       { .cipher = {
        .cia_min_keysize        =       8,
        .cia_max_keysize        =       8,
index 7835b8fc94db6d69b9e93c1806d677e8ea390736..9d3f0c69a86ff2caeb33b7cddccbf8a80c7f7926 100644 (file)
@@ -153,7 +153,6 @@ static struct shash_alg ghash_alg = {
                .cra_blocksize          = GHASH_BLOCK_SIZE,
                .cra_ctxsize            = sizeof(struct ghash_ctx),
                .cra_module             = THIS_MODULE,
-               .cra_list               = LIST_HEAD_INIT(ghash_alg.base.cra_list),
                .cra_exit               = ghash_exit_tfm,
        },
 };
index 527e4e395fc32f8f0d271b372ed93941fb6e1bcc..60e7cd66facc81c0ae051b4c71e3f220144ef6b8 100644 (file)
@@ -853,7 +853,6 @@ static struct crypto_alg khazad_alg = {
        .cra_ctxsize            =       sizeof (struct khazad_ctx),
        .cra_alignmask          =       7,
        .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(khazad_alg.cra_list),
        .cra_u                  =       { .cipher = {
        .cia_min_keysize        =       KHAZAD_KEY_SIZE,
        .cia_max_keysize        =       KHAZAD_KEY_SIZE,
index 4328bb3430edd8891654f9934d50d087936d83c4..a2d2b72fc135b428102141ab181cc802994d1178 100644 (file)
@@ -35,7 +35,6 @@ static struct crypto_alg krng_alg = {
        .cra_ctxsize            = 0,
        .cra_type               = &crypto_rng_type,
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(krng_alg.cra_list),
        .cra_u                  = {
                .rng = {
                        .rng_make_random        = krng_get_random,
index b5e77077d75144b5d120c4c29e16aef17440612a..1c2aa69c54b8557cce3d7c06934a5cd8a9f575b5 100644 (file)
@@ -81,7 +81,6 @@ static struct crypto_alg alg = {
        .cra_flags              = CRYPTO_ALG_TYPE_COMPRESS,
        .cra_ctxsize            = sizeof(struct lzo_ctx),
        .cra_module             = THIS_MODULE,
-       .cra_list               = LIST_HEAD_INIT(alg.cra_list),
        .cra_init               = lzo_init,
        .cra_exit               = lzo_exit,
        .cra_u                  = { .compress = {
index eac10c11685cd436472d9262347922b88165b50d..9a4770c022841542fc8a2a11e7f5c32fa8ae6ac3 100644 (file)
@@ -221,7 +221,6 @@ static struct crypto_alg alg = {
        .cra_ctxsize        =   sizeof(struct salsa20_ctx),
        .cra_alignmask      =   3,
        .cra_module         =   THIS_MODULE,
-       .cra_list           =   LIST_HEAD_INIT(alg.cra_list),
        .cra_u              =   {
                .blkcipher = {
                        .setkey         =   setkey,
index d3e422f6055621aea9a6f6c78a08738466ace49d..9c904d6d215140d38039aacd49922f374aac4ad6 100644 (file)
@@ -449,7 +449,6 @@ static struct crypto_alg seed_alg = {
        .cra_ctxsize            =       sizeof(struct seed_ctx),
        .cra_alignmask          =       3,
        .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(seed_alg.cra_list),
        .cra_u                  =       {
                .cipher = {
                        .cia_min_keysize        =       SEED_KEY_SIZE,
index 8f32cf35e5ce25140fd4de150853435e735983cf..7ddbd7e888595dfb96ef80423d01e685278445b7 100644 (file)
@@ -567,24 +567,6 @@ static void serpent_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
        __serpent_decrypt(ctx, dst, src);
 }
 
-static struct crypto_alg serpent_alg = {
-       .cra_name               =       "serpent",
-       .cra_driver_name        =       "serpent-generic",
-       .cra_priority           =       100,
-       .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
-       .cra_blocksize          =       SERPENT_BLOCK_SIZE,
-       .cra_ctxsize            =       sizeof(struct serpent_ctx),
-       .cra_alignmask          =       3,
-       .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(serpent_alg.cra_list),
-       .cra_u                  =       { .cipher = {
-       .cia_min_keysize        =       SERPENT_MIN_KEY_SIZE,
-       .cia_max_keysize        =       SERPENT_MAX_KEY_SIZE,
-       .cia_setkey             =       serpent_setkey,
-       .cia_encrypt            =       serpent_encrypt,
-       .cia_decrypt            =       serpent_decrypt } }
-};
-
 static int tnepres_setkey(struct crypto_tfm *tfm, const u8 *key,
                          unsigned int keylen)
 {
@@ -637,41 +619,44 @@ static void tnepres_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
        d[3] = swab32(rd[0]);
 }
 
-static struct crypto_alg tnepres_alg = {
+static struct crypto_alg srp_algs[2] = { {
+       .cra_name               =       "serpent",
+       .cra_driver_name        =       "serpent-generic",
+       .cra_priority           =       100,
+       .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
+       .cra_blocksize          =       SERPENT_BLOCK_SIZE,
+       .cra_ctxsize            =       sizeof(struct serpent_ctx),
+       .cra_alignmask          =       3,
+       .cra_module             =       THIS_MODULE,
+       .cra_u                  =       { .cipher = {
+       .cia_min_keysize        =       SERPENT_MIN_KEY_SIZE,
+       .cia_max_keysize        =       SERPENT_MAX_KEY_SIZE,
+       .cia_setkey             =       serpent_setkey,
+       .cia_encrypt            =       serpent_encrypt,
+       .cia_decrypt            =       serpent_decrypt } }
+}, {
        .cra_name               =       "tnepres",
        .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
        .cra_blocksize          =       SERPENT_BLOCK_SIZE,
        .cra_ctxsize            =       sizeof(struct serpent_ctx),
        .cra_alignmask          =       3,
        .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(serpent_alg.cra_list),
        .cra_u                  =       { .cipher = {
        .cia_min_keysize        =       SERPENT_MIN_KEY_SIZE,
        .cia_max_keysize        =       SERPENT_MAX_KEY_SIZE,
        .cia_setkey             =       tnepres_setkey,
        .cia_encrypt            =       tnepres_encrypt,
        .cia_decrypt            =       tnepres_decrypt } }
-};
+} };
 
 static int __init serpent_mod_init(void)
 {
-       int ret = crypto_register_alg(&serpent_alg);
-
-       if (ret)
-               return ret;
-
-       ret = crypto_register_alg(&tnepres_alg);
-
-       if (ret)
-               crypto_unregister_alg(&serpent_alg);
-
-       return ret;
+       return crypto_register_algs(srp_algs, ARRAY_SIZE(srp_algs));
 }
 
 static void __exit serpent_mod_fini(void)
 {
-       crypto_unregister_alg(&tnepres_alg);
-       crypto_unregister_alg(&serpent_alg);
+       crypto_unregister_algs(srp_algs, ARRAY_SIZE(srp_algs));
 }
 
 module_init(serpent_mod_init);
index c48459ebf05b4dc157c90190c29770c70bf64095..c3ed4ec924e1005dbefac4d93dc3f9eae3f54f5b 100644 (file)
@@ -336,7 +336,7 @@ static int sha256_import(struct shash_desc *desc, const void *in)
        return 0;
 }
 
-static struct shash_alg sha256 = {
+static struct shash_alg sha256_algs[2] = { {
        .digestsize     =       SHA256_DIGEST_SIZE,
        .init           =       sha256_init,
        .update         =       sha256_update,
@@ -352,9 +352,7 @@ static struct shash_alg sha256 = {
                .cra_blocksize  =       SHA256_BLOCK_SIZE,
                .cra_module     =       THIS_MODULE,
        }
-};
-
-static struct shash_alg sha224 = {
+}, {
        .digestsize     =       SHA224_DIGEST_SIZE,
        .init           =       sha224_init,
        .update         =       sha256_update,
@@ -367,29 +365,16 @@ static struct shash_alg sha224 = {
                .cra_blocksize  =       SHA224_BLOCK_SIZE,
                .cra_module     =       THIS_MODULE,
        }
-};
+} };
 
 static int __init sha256_generic_mod_init(void)
 {
-       int ret = 0;
-
-       ret = crypto_register_shash(&sha224);
-
-       if (ret < 0)
-               return ret;
-
-       ret = crypto_register_shash(&sha256);
-
-       if (ret < 0)
-               crypto_unregister_shash(&sha224);
-
-       return ret;
+       return crypto_register_shashes(sha256_algs, ARRAY_SIZE(sha256_algs));
 }
 
 static void __exit sha256_generic_mod_fini(void)
 {
-       crypto_unregister_shash(&sha224);
-       crypto_unregister_shash(&sha256);
+       crypto_unregister_shashes(sha256_algs, ARRAY_SIZE(sha256_algs));
 }
 
 module_init(sha256_generic_mod_init);
index dd30f40af9f505152bbc620211fa37d109eae1d7..71fcf361102dcee35e0fcff0bd332ed4f4e77215 100644 (file)
@@ -242,7 +242,7 @@ static int sha384_final(struct shash_desc *desc, u8 *hash)
        return 0;
 }
 
-static struct shash_alg sha512 = {
+static struct shash_alg sha512_algs[2] = { {
        .digestsize     =       SHA512_DIGEST_SIZE,
        .init           =       sha512_init,
        .update         =       sha512_update,
@@ -254,9 +254,7 @@ static struct shash_alg sha512 = {
                .cra_blocksize  =       SHA512_BLOCK_SIZE,
                .cra_module     =       THIS_MODULE,
        }
-};
-
-static struct shash_alg sha384 = {
+}, {
        .digestsize     =       SHA384_DIGEST_SIZE,
        .init           =       sha384_init,
        .update         =       sha512_update,
@@ -268,24 +266,16 @@ static struct shash_alg sha384 = {
                .cra_blocksize  =       SHA384_BLOCK_SIZE,
                .cra_module     =       THIS_MODULE,
        }
-};
+} };
 
 static int __init sha512_generic_mod_init(void)
 {
-        int ret = 0;
-
-        if ((ret = crypto_register_shash(&sha384)) < 0)
-                goto out;
-        if ((ret = crypto_register_shash(&sha512)) < 0)
-                crypto_unregister_shash(&sha384);
-out:
-        return ret;
+       return crypto_register_shashes(sha512_algs, ARRAY_SIZE(sha512_algs));
 }
 
 static void __exit sha512_generic_mod_fini(void)
 {
-        crypto_unregister_shash(&sha384);
-        crypto_unregister_shash(&sha512);
+       crypto_unregister_shashes(sha512_algs, ARRAY_SIZE(sha512_algs));
 }
 
 module_init(sha512_generic_mod_init);
index 32067f47e6c7bfbeea673d039e7ad5bc2bf90492..f426330f101755493a529d4dd8f9bcd900b51f73 100644 (file)
@@ -629,6 +629,42 @@ int crypto_unregister_shash(struct shash_alg *alg)
 }
 EXPORT_SYMBOL_GPL(crypto_unregister_shash);
 
+int crypto_register_shashes(struct shash_alg *algs, int count)
+{
+       int i, ret;
+
+       for (i = 0; i < count; i++) {
+               ret = crypto_register_shash(&algs[i]);
+               if (ret)
+                       goto err;
+       }
+
+       return 0;
+
+err:
+       for (--i; i >= 0; --i)
+               crypto_unregister_shash(&algs[i]);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(crypto_register_shashes);
+
+int crypto_unregister_shashes(struct shash_alg *algs, int count)
+{
+       int i, ret;
+
+       for (i = count - 1; i >= 0; --i) {
+               ret = crypto_unregister_shash(&algs[i]);
+               if (ret)
+                       pr_err("Failed to unregister %s %s: %d\n",
+                              algs[i].base.cra_driver_name,
+                              algs[i].base.cra_name, ret);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(crypto_unregister_shashes);
+
 int shash_register_instance(struct crypto_template *tmpl,
                            struct shash_instance *inst)
 {
index 5cf2ccb1540cb1731e68e3b9575ce00abe3554e0..871076b1e0abba639de0e3f6525475a7efcc4dce 100644 (file)
@@ -1037,10 +1037,16 @@ static int do_test(int m)
 
        case 14:
                ret += tcrypt_test("ecb(cast5)");
+               ret += tcrypt_test("cbc(cast5)");
+               ret += tcrypt_test("ctr(cast5)");
                break;
 
        case 15:
                ret += tcrypt_test("ecb(cast6)");
+               ret += tcrypt_test("cbc(cast6)");
+               ret += tcrypt_test("ctr(cast6)");
+               ret += tcrypt_test("lrw(cast6)");
+               ret += tcrypt_test("xts(cast6)");
                break;
 
        case 16:
@@ -1359,6 +1365,44 @@ static int do_test(int m)
                                  speed_template_8);
                break;
 
+       case 209:
+               test_cipher_speed("ecb(cast5)", ENCRYPT, sec, NULL, 0,
+                                 speed_template_8_16);
+               test_cipher_speed("ecb(cast5)", DECRYPT, sec, NULL, 0,
+                                 speed_template_8_16);
+               test_cipher_speed("cbc(cast5)", ENCRYPT, sec, NULL, 0,
+                                 speed_template_8_16);
+               test_cipher_speed("cbc(cast5)", DECRYPT, sec, NULL, 0,
+                                 speed_template_8_16);
+               test_cipher_speed("ctr(cast5)", ENCRYPT, sec, NULL, 0,
+                                 speed_template_8_16);
+               test_cipher_speed("ctr(cast5)", DECRYPT, sec, NULL, 0,
+                                 speed_template_8_16);
+               break;
+
+       case 210:
+               test_cipher_speed("ecb(cast6)", ENCRYPT, sec, NULL, 0,
+                                 speed_template_16_32);
+               test_cipher_speed("ecb(cast6)", DECRYPT, sec, NULL, 0,
+                                 speed_template_16_32);
+               test_cipher_speed("cbc(cast6)", ENCRYPT, sec, NULL, 0,
+                                 speed_template_16_32);
+               test_cipher_speed("cbc(cast6)", DECRYPT, sec, NULL, 0,
+                                 speed_template_16_32);
+               test_cipher_speed("ctr(cast6)", ENCRYPT, sec, NULL, 0,
+                                 speed_template_16_32);
+               test_cipher_speed("ctr(cast6)", DECRYPT, sec, NULL, 0,
+                                 speed_template_16_32);
+               test_cipher_speed("lrw(cast6)", ENCRYPT, sec, NULL, 0,
+                                 speed_template_32_48);
+               test_cipher_speed("lrw(cast6)", DECRYPT, sec, NULL, 0,
+                                 speed_template_32_48);
+               test_cipher_speed("xts(cast6)", ENCRYPT, sec, NULL, 0,
+                                 speed_template_32_64);
+               test_cipher_speed("xts(cast6)", DECRYPT, sec, NULL, 0,
+                                 speed_template_32_64);
+               break;
+
        case 300:
                /* fall through */
 
@@ -1639,6 +1683,44 @@ static int do_test(int m)
                                   speed_template_8);
                break;
 
+       case 506:
+               test_acipher_speed("ecb(cast5)", ENCRYPT, sec, NULL, 0,
+                                  speed_template_8_16);
+               test_acipher_speed("ecb(cast5)", DECRYPT, sec, NULL, 0,
+                                  speed_template_8_16);
+               test_acipher_speed("cbc(cast5)", ENCRYPT, sec, NULL, 0,
+                                  speed_template_8_16);
+               test_acipher_speed("cbc(cast5)", DECRYPT, sec, NULL, 0,
+                                  speed_template_8_16);
+               test_acipher_speed("ctr(cast5)", ENCRYPT, sec, NULL, 0,
+                                  speed_template_8_16);
+               test_acipher_speed("ctr(cast5)", DECRYPT, sec, NULL, 0,
+                                  speed_template_8_16);
+               break;
+
+       case 507:
+               test_acipher_speed("ecb(cast6)", ENCRYPT, sec, NULL, 0,
+                                  speed_template_16_32);
+               test_acipher_speed("ecb(cast6)", DECRYPT, sec, NULL, 0,
+                                  speed_template_16_32);
+               test_acipher_speed("cbc(cast6)", ENCRYPT, sec, NULL, 0,
+                                  speed_template_16_32);
+               test_acipher_speed("cbc(cast6)", DECRYPT, sec, NULL, 0,
+                                  speed_template_16_32);
+               test_acipher_speed("ctr(cast6)", ENCRYPT, sec, NULL, 0,
+                                  speed_template_16_32);
+               test_acipher_speed("ctr(cast6)", DECRYPT, sec, NULL, 0,
+                                  speed_template_16_32);
+               test_acipher_speed("lrw(cast6)", ENCRYPT, sec, NULL, 0,
+                                  speed_template_32_48);
+               test_acipher_speed("lrw(cast6)", DECRYPT, sec, NULL, 0,
+                                  speed_template_32_48);
+               test_acipher_speed("xts(cast6)", ENCRYPT, sec, NULL, 0,
+                                  speed_template_32_64);
+               test_acipher_speed("xts(cast6)", DECRYPT, sec, NULL, 0,
+                                  speed_template_32_64);
+               break;
+
        case 1000:
                test_available();
                break;
index 5be1fc8c1ab349e051bbb18efc4f37737abe1d5d..cd2068524f3f6766696cf5f350d546bb2c9c644b 100644 (file)
@@ -47,6 +47,7 @@ static struct cipher_speed_template des3_speed_template[] = {
  */
 static u8 speed_template_8[] = {8, 0};
 static u8 speed_template_24[] = {24, 0};
+static u8 speed_template_8_16[] = {8, 16, 0};
 static u8 speed_template_8_32[] = {8, 32, 0};
 static u8 speed_template_16_32[] = {16, 32, 0};
 static u8 speed_template_16_24_32[] = {16, 24, 32, 0};
index 412bc74f8179bb2add09ece93b470ba39bfde5d6..0a572323ee4a9e88cdb2d3e4bc92e56235af8a6a 100644 (file)
@@ -219,84 +219,55 @@ static void xeta_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
        out[1] = cpu_to_le32(z);
 }
 
-static struct crypto_alg tea_alg = {
+static struct crypto_alg tea_algs[3] = { {
        .cra_name               =       "tea",
        .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
        .cra_blocksize          =       TEA_BLOCK_SIZE,
        .cra_ctxsize            =       sizeof (struct tea_ctx),
        .cra_alignmask          =       3,
        .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(tea_alg.cra_list),
        .cra_u                  =       { .cipher = {
        .cia_min_keysize        =       TEA_KEY_SIZE,
        .cia_max_keysize        =       TEA_KEY_SIZE,
        .cia_setkey             =       tea_setkey,
        .cia_encrypt            =       tea_encrypt,
        .cia_decrypt            =       tea_decrypt } }
-};
-
-static struct crypto_alg xtea_alg = {
+}, {
        .cra_name               =       "xtea",
        .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
        .cra_blocksize          =       XTEA_BLOCK_SIZE,
        .cra_ctxsize            =       sizeof (struct xtea_ctx),
        .cra_alignmask          =       3,
        .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(xtea_alg.cra_list),
        .cra_u                  =       { .cipher = {
        .cia_min_keysize        =       XTEA_KEY_SIZE,
        .cia_max_keysize        =       XTEA_KEY_SIZE,
        .cia_setkey             =       xtea_setkey,
        .cia_encrypt            =       xtea_encrypt,
        .cia_decrypt            =       xtea_decrypt } }
-};
-
-static struct crypto_alg xeta_alg = {
+}, {
        .cra_name               =       "xeta",
        .cra_flags              =       CRYPTO_ALG_TYPE_CIPHER,
        .cra_blocksize          =       XTEA_BLOCK_SIZE,
        .cra_ctxsize            =       sizeof (struct xtea_ctx),
        .cra_alignmask          =       3,
        .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(xtea_alg.cra_list),
        .cra_u                  =       { .cipher = {
        .cia_min_keysize        =       XTEA_KEY_SIZE,
        .cia_max_keysize        =       XTEA_KEY_SIZE,
        .cia_setkey             =       xtea_setkey,
        .cia_encrypt            =       xeta_encrypt,
        .cia_decrypt            =       xeta_decrypt } }
-};
+} };
 
 static int __init tea_mod_init(void)
 {
-       int ret = 0;
-       
-       ret = crypto_register_alg(&tea_alg);
-       if (ret < 0)
-               goto out;
-
-       ret = crypto_register_alg(&xtea_alg);
-       if (ret < 0) {
-               crypto_unregister_alg(&tea_alg);
-               goto out;
-       }
-
-       ret = crypto_register_alg(&xeta_alg);
-       if (ret < 0) {
-               crypto_unregister_alg(&tea_alg);
-               crypto_unregister_alg(&xtea_alg);
-               goto out;
-       }
-
-out:   
-       return ret;
+       return crypto_register_algs(tea_algs, ARRAY_SIZE(tea_algs));
 }
 
 static void __exit tea_mod_fini(void)
 {
-       crypto_unregister_alg(&tea_alg);
-       crypto_unregister_alg(&xtea_alg);
-       crypto_unregister_alg(&xeta_alg);
+       crypto_unregister_algs(tea_algs, ARRAY_SIZE(tea_algs));
 }
 
 MODULE_ALIAS("xtea");
index a2ca7431760a245374a269ed19563ccc4d3ece91..575b57c3244bdff765ec6a7af9d8d3940029b2e7 100644 (file)
@@ -1534,6 +1534,36 @@ static int alg_test_null(const struct alg_test_desc *desc,
 /* Please keep this list sorted by algorithm name. */
 static const struct alg_test_desc alg_test_descs[] = {
        {
+               .alg = "__cbc-cast5-avx",
+               .test = alg_test_null,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = NULL,
+                                       .count = 0
+                               },
+                               .dec = {
+                                       .vecs = NULL,
+                                       .count = 0
+                               }
+                       }
+               }
+       }, {
+               .alg = "__cbc-cast6-avx",
+               .test = alg_test_null,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = NULL,
+                                       .count = 0
+                               },
+                               .dec = {
+                                       .vecs = NULL,
+                                       .count = 0
+                               }
+                       }
+               }
+       }, {
                .alg = "__cbc-serpent-avx",
                .test = alg_test_null,
                .suite = {
@@ -1594,6 +1624,36 @@ static const struct alg_test_desc alg_test_descs[] = {
                                }
                        }
                }
+       }, {
+               .alg = "__driver-cbc-cast5-avx",
+               .test = alg_test_null,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = NULL,
+                                       .count = 0
+                               },
+                               .dec = {
+                                       .vecs = NULL,
+                                       .count = 0
+                               }
+                       }
+               }
+       }, {
+               .alg = "__driver-cbc-cast6-avx",
+               .test = alg_test_null,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = NULL,
+                                       .count = 0
+                               },
+                               .dec = {
+                                       .vecs = NULL,
+                                       .count = 0
+                               }
+                       }
+               }
        }, {
                .alg = "__driver-cbc-serpent-avx",
                .test = alg_test_null,
@@ -1655,6 +1715,36 @@ static const struct alg_test_desc alg_test_descs[] = {
                                }
                        }
                }
+       }, {
+               .alg = "__driver-ecb-cast5-avx",
+               .test = alg_test_null,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = NULL,
+                                       .count = 0
+                               },
+                               .dec = {
+                                       .vecs = NULL,
+                                       .count = 0
+                               }
+                       }
+               }
+       }, {
+               .alg = "__driver-ecb-cast6-avx",
+               .test = alg_test_null,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = NULL,
+                                       .count = 0
+                               },
+                               .dec = {
+                                       .vecs = NULL,
+                                       .count = 0
+                               }
+                       }
+               }
        }, {
                .alg = "__driver-ecb-serpent-avx",
                .test = alg_test_null,
@@ -1817,6 +1907,36 @@ static const struct alg_test_desc alg_test_descs[] = {
                                }
                        }
                }
+       }, {
+               .alg = "cbc(cast5)",
+               .test = alg_test_skcipher,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = cast5_cbc_enc_tv_template,
+                                       .count = CAST5_CBC_ENC_TEST_VECTORS
+                               },
+                               .dec = {
+                                       .vecs = cast5_cbc_dec_tv_template,
+                                       .count = CAST5_CBC_DEC_TEST_VECTORS
+                               }
+                       }
+               }
+       }, {
+               .alg = "cbc(cast6)",
+               .test = alg_test_skcipher,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = cast6_cbc_enc_tv_template,
+                                       .count = CAST6_CBC_ENC_TEST_VECTORS
+                               },
+                               .dec = {
+                                       .vecs = cast6_cbc_dec_tv_template,
+                                       .count = CAST6_CBC_DEC_TEST_VECTORS
+                               }
+                       }
+               }
        }, {
                .alg = "cbc(des)",
                .test = alg_test_skcipher,
@@ -1936,6 +2056,36 @@ static const struct alg_test_desc alg_test_descs[] = {
                                }
                        }
                }
+       }, {
+               .alg = "cryptd(__driver-ecb-cast5-avx)",
+               .test = alg_test_null,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = NULL,
+                                       .count = 0
+                               },
+                               .dec = {
+                                       .vecs = NULL,
+                                       .count = 0
+                               }
+                       }
+               }
+       }, {
+               .alg = "cryptd(__driver-ecb-cast6-avx)",
+               .test = alg_test_null,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = NULL,
+                                       .count = 0
+                               },
+                               .dec = {
+                                       .vecs = NULL,
+                                       .count = 0
+                               }
+                       }
+               }
        }, {
                .alg = "cryptd(__driver-ecb-serpent-avx)",
                .test = alg_test_null,
@@ -2053,6 +2203,36 @@ static const struct alg_test_desc alg_test_descs[] = {
                                }
                        }
                }
+       }, {
+               .alg = "ctr(cast5)",
+               .test = alg_test_skcipher,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = cast5_ctr_enc_tv_template,
+                                       .count = CAST5_CTR_ENC_TEST_VECTORS
+                               },
+                               .dec = {
+                                       .vecs = cast5_ctr_dec_tv_template,
+                                       .count = CAST5_CTR_DEC_TEST_VECTORS
+                               }
+                       }
+               }
+       }, {
+               .alg = "ctr(cast6)",
+               .test = alg_test_skcipher,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = cast6_ctr_enc_tv_template,
+                                       .count = CAST6_CTR_ENC_TEST_VECTORS
+                               },
+                               .dec = {
+                                       .vecs = cast6_ctr_dec_tv_template,
+                                       .count = CAST6_CTR_DEC_TEST_VECTORS
+                               }
+                       }
+               }
        }, {
                .alg = "ctr(serpent)",
                .test = alg_test_skcipher,
@@ -2529,6 +2709,21 @@ static const struct alg_test_desc alg_test_descs[] = {
                                }
                        }
                }
+       }, {
+               .alg = "lrw(cast6)",
+               .test = alg_test_skcipher,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = cast6_lrw_enc_tv_template,
+                                       .count = CAST6_LRW_ENC_TEST_VECTORS
+                               },
+                               .dec = {
+                                       .vecs = cast6_lrw_dec_tv_template,
+                                       .count = CAST6_LRW_DEC_TEST_VECTORS
+                               }
+                       }
+               }
        }, {
                .alg = "lrw(serpent)",
                .test = alg_test_skcipher,
@@ -2881,6 +3076,21 @@ static const struct alg_test_desc alg_test_descs[] = {
                                }
                        }
                }
+       }, {
+               .alg = "xts(cast6)",
+               .test = alg_test_skcipher,
+               .suite = {
+                       .cipher = {
+                               .enc = {
+                                       .vecs = cast6_xts_enc_tv_template,
+                                       .count = CAST6_XTS_ENC_TEST_VECTORS
+                               },
+                               .dec = {
+                                       .vecs = cast6_xts_dec_tv_template,
+                                       .count = CAST6_XTS_DEC_TEST_VECTORS
+                               }
+                       }
+               }
        }, {
                .alg = "xts(serpent)",
                .test = alg_test_skcipher,
index f8179e0344ed6b76b286b65eec5e82a1fe49d922..6eb3ef5e3f88f92e32e4d31cab7a908ac3216895 100644 (file)
@@ -6896,8 +6896,16 @@ static struct cipher_testvec serpent_xts_dec_tv_template[] = {
 };
 
 /* Cast6 test vectors from RFC 2612 */
-#define CAST6_ENC_TEST_VECTORS 3
-#define CAST6_DEC_TEST_VECTORS  3
+#define CAST6_ENC_TEST_VECTORS         4
+#define CAST6_DEC_TEST_VECTORS         4
+#define CAST6_CBC_ENC_TEST_VECTORS     1
+#define CAST6_CBC_DEC_TEST_VECTORS     1
+#define CAST6_CTR_ENC_TEST_VECTORS     1
+#define CAST6_CTR_DEC_TEST_VECTORS     1
+#define CAST6_LRW_ENC_TEST_VECTORS     1
+#define CAST6_LRW_DEC_TEST_VECTORS     1
+#define CAST6_XTS_ENC_TEST_VECTORS     1
+#define CAST6_XTS_DEC_TEST_VECTORS     1
 
 static struct cipher_testvec cast6_enc_tv_template[] = {
        {
@@ -6930,6 +6938,140 @@ static struct cipher_testvec cast6_enc_tv_template[] = {
                .result = "\x4f\x6a\x20\x38\x28\x68\x97\xb9"
                          "\xc9\x87\x01\x36\x55\x33\x17\xfa",
                .rlen   = 16,
+       }, { /* Generated from TF test vectors */
+               .key    = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+                         "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A"
+                         "\x27\x04\xE1\x27\x04\xE1\xBE\x9B"
+                         "\x78\xBE\x9B\x78\x55\x32\x0F\x55",
+               .klen   = 32,
+               .iv     = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F"
+                         "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64",
+               .input  = "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+                         "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+                         "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+                         "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+                         "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+                         "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
+                         "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
+                         "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+                         "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+                         "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+                         "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+                         "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+                         "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+                         "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+                         "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+                         "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+                         "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+                         "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A"
+                         "\xF1\x65\xFC\x93\x07\x9E\x35\xCC"
+                         "\x40\xD7\x6E\x05\x79\x10\xA7\x1B"
+                         "\xB2\x49\xE0\x54\xEB\x82\x19\x8D"
+                         "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF"
+                         "\x96\x0A\xA1\x38\xCF\x43\xDA\x71"
+                         "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3"
+                         "\x57\xEE\x85\x1C\x90\x27\xBE\x32"
+                         "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4"
+                         "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16"
+                         "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88"
+                         "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA"
+                         "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49"
+                         "\xE0\x77\x0E\x82\x19\xB0\x24\xBB"
+                         "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D"
+                         "\xC4\x38\xCF\x66\xFD\x71\x08\x9F"
+                         "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11"
+                         "\x85\x1C\xB3\x27\xBE\x55\xEC\x60"
+                         "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2"
+                         "\x69\x00\x74\x0B\xA2\x16\xAD\x44"
+                         "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6"
+                         "\x2A\xC1\x58\xEF\x63\xFA\x91\x05"
+                         "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77"
+                         "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9"
+                         "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B"
+                         "\xF2\x66\xFD\x94\x08\x9F\x36\xCD"
+                         "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C"
+                         "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E"
+                         "\x25\xBC\x30\xC7\x5E\xF5\x69\x00"
+                         "\x97\x0B\xA2\x39\xD0\x44\xDB\x72"
+                         "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4"
+                         "\x58\xEF\x86\x1D\x91\x28\xBF\x33"
+                         "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5"
+                         "\x3C\xD3\x47\xDE\x75\x0C\x80\x17"
+                         "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89"
+                         "\x20\x94\x2B\xC2\x36\xCD\x64\xFB"
+                         "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A"
+                         "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC"
+                         "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E"
+                         "\xC5\x39\xD0\x67\xFE\x72\x09\xA0"
+                         "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12"
+                         "\x86\x1D\xB4\x28\xBF\x56\xED\x61"
+                         "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3"
+                         "\x6A\x01\x75\x0C\xA3\x17\xAE\x45"
+                         "\xDC\x50\xE7\x7E\x15\x89\x20\xB7",
+               .ilen   = 496,
+               .result = "\xC3\x70\x22\x32\xF5\x80\xCB\x54"
+                         "\xFC\x30\xE0\xF6\xEB\x39\x57\xA6"
+                         "\xB6\xB9\xC5\xA4\x91\x55\x14\x97"
+                         "\xC1\x20\xFF\x6C\x5C\xF0\x67\xEA"
+                         "\x2F\xED\xD8\xC9\xFB\x38\x3F\xFE"
+                         "\x93\xBE\xDC\x00\xD3\x7F\xAD\x4C"
+                         "\x5A\x08\x92\xD1\x47\x0C\xFA\x6C"
+                         "\xD0\x6A\x99\x10\x72\xF8\x47\x62"
+                         "\x81\x42\xF8\xD8\xF5\xBB\x94\x08"
+                         "\xAA\x97\xA2\x8B\x69\xB3\xD2\x7E"
+                         "\xBC\xB5\x00\x0C\xE5\x44\x4B\x58"
+                         "\xE8\x63\xDC\xB3\xC4\xE5\x23\x12"
+                         "\x5A\x72\x85\x47\x8B\xEC\x9F\x26"
+                         "\x84\xB6\xED\x10\x33\x63\x9B\x5F"
+                         "\x4D\x53\xEE\x94\x45\x8B\x60\x58"
+                         "\x86\x20\xF9\x1E\x82\x08\x3E\x58"
+                         "\x60\x1B\x34\x19\x02\xBE\x4E\x09"
+                         "\xBB\x7C\x15\xCC\x60\x27\x55\x7A"
+                         "\x12\xB8\xD8\x08\x89\x3C\xA6\xF3"
+                         "\xF1\xDD\xA7\x07\xA3\x12\x85\x28"
+                         "\xE9\x57\xAC\x80\x0C\x5C\x0F\x3A"
+                         "\x5D\xC2\x91\xC7\x90\xE4\x8C\x43"
+                         "\x92\xE4\x7C\x26\x69\x4D\x83\x68"
+                         "\x14\x96\x42\x47\xBD\xA9\xE4\x8A"
+                         "\x33\x19\xEB\x54\x8E\x0D\x4B\x6E"
+                         "\x91\x51\xB5\x36\x08\xDE\x1C\x06"
+                         "\x03\xBD\xDE\x81\x26\xF7\x99\xC2"
+                         "\xBA\xF7\x6D\x87\x0D\xE4\xA6\xCF"
+                         "\xC1\xF5\x27\x05\xB8\x02\x57\x72"
+                         "\xE6\x42\x13\x0B\xC6\x47\x05\x74"
+                         "\x24\x15\xF7\x0D\xC2\x23\x9D\xB9"
+                         "\x3C\x77\x18\x93\xBA\xB4\xFC\x8C"
+                         "\x98\x82\x67\x67\xB4\xD7\xD3\x43"
+                         "\x23\x08\x02\xB7\x9B\x99\x05\xFB"
+                         "\xD3\xB5\x00\x0A\xA9\x9D\x66\xD6"
+                         "\x2E\x49\x58\xD0\xA8\x57\x29\x7F"
+                         "\x0A\x0E\x7D\xFC\x92\x83\xCC\x67"
+                         "\xA2\xB1\x70\x3A\x8F\x87\x4A\x8D"
+                         "\x17\xE2\x58\x2B\x88\x0D\x68\x62"
+                         "\xBF\x35\xD1\x6F\xC0\xF0\x18\x62"
+                         "\xB2\xC7\x2D\x58\xC7\x16\xDE\x08"
+                         "\xEB\x84\x1D\x25\xA7\x38\x94\x06"
+                         "\x93\x9D\xF8\xFE\x88\x71\xE7\x84"
+                         "\x2C\xA0\x38\xA3\x1D\x48\xCF\x29"
+                         "\x0B\xBC\xD8\x50\x99\x1A\x26\xFB"
+                         "\x8E\x75\x3D\x73\xEB\x6A\xED\x29"
+                         "\xE0\x8E\xED\xFC\xFE\x6F\xF6\xBA"
+                         "\x41\xE2\x10\x4C\x01\x8B\x69\x2B"
+                         "\x25\x3F\x4D\x70\x7B\x92\xD6\x3B"
+                         "\xAC\xF9\x77\x18\xD9\x6A\x30\xA6"
+                         "\x2E\xFA\x30\xFF\xC8\xD5\x1D\x06"
+                         "\x59\x28\x1D\x86\x43\x04\x5D\x3B"
+                         "\x99\x4C\x04\x5A\x21\x17\x8B\x76"
+                         "\x8F\x72\xCB\xA1\x9C\x29\x4C\xC3"
+                         "\x65\xA2\x58\x2A\xC5\x66\x24\xBF"
+                         "\xBA\xE6\x0C\xDD\x34\x24\x74\xC8"
+                         "\x84\x0A\x66\x2C\xBE\x8F\x32\xA9"
+                         "\xE7\xE4\xA1\xD7\xDA\xAB\x23\x1E"
+                         "\xEB\xEE\x6C\x94\x6F\x9C\x2E\xD1"
+                         "\x49\x2C\xF3\xD4\x90\xCC\x93\x4C"
+                         "\x84\x52\x6D\x68\xDE\xC6\x64\xB2"
+                         "\x11\x74\x93\x57\xB4\x7E\xC6\x00",
+               .rlen   = 496,
        },
 };
 
@@ -6964,122 +7106,1388 @@ static struct cipher_testvec cast6_dec_tv_template[] = {
                .ilen   = 16,
                .result = zeroed_string,
                .rlen   = 16,
-       },
-};
-
-
-/*
- * AES test vectors.
- */
-#define AES_ENC_TEST_VECTORS 3
-#define AES_DEC_TEST_VECTORS 3
-#define AES_CBC_ENC_TEST_VECTORS 4
-#define AES_CBC_DEC_TEST_VECTORS 4
-#define HMAC_SHA1_AES_CBC_ENC_TEST_VECTORS 7
-#define HMAC_SHA256_AES_CBC_ENC_TEST_VECTORS 7
-#define HMAC_SHA512_AES_CBC_ENC_TEST_VECTORS 7
-#define AES_LRW_ENC_TEST_VECTORS 8
-#define AES_LRW_DEC_TEST_VECTORS 8
-#define AES_XTS_ENC_TEST_VECTORS 5
-#define AES_XTS_DEC_TEST_VECTORS 5
-#define AES_CTR_ENC_TEST_VECTORS 3
-#define AES_CTR_DEC_TEST_VECTORS 3
-#define AES_OFB_ENC_TEST_VECTORS 1
-#define AES_OFB_DEC_TEST_VECTORS 1
-#define AES_CTR_3686_ENC_TEST_VECTORS 7
-#define AES_CTR_3686_DEC_TEST_VECTORS 6
-#define AES_GCM_ENC_TEST_VECTORS 9
-#define AES_GCM_DEC_TEST_VECTORS 8
-#define AES_GCM_4106_ENC_TEST_VECTORS 7
-#define AES_GCM_4106_DEC_TEST_VECTORS 7
-#define AES_CCM_ENC_TEST_VECTORS 7
-#define AES_CCM_DEC_TEST_VECTORS 7
-#define AES_CCM_4309_ENC_TEST_VECTORS 7
-#define AES_CCM_4309_DEC_TEST_VECTORS 10
-
-static struct cipher_testvec aes_enc_tv_template[] = {
-       { /* From FIPS-197 */
-               .key    = "\x00\x01\x02\x03\x04\x05\x06\x07"
-                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
-               .klen   = 16,
-               .input  = "\x00\x11\x22\x33\x44\x55\x66\x77"
-                         "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
-               .ilen   = 16,
-               .result = "\x69\xc4\xe0\xd8\x6a\x7b\x04\x30"
-                         "\xd8\xcd\xb7\x80\x70\xb4\xc5\x5a",
-               .rlen   = 16,
-       }, {
-               .key    = "\x00\x01\x02\x03\x04\x05\x06\x07"
-                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-                         "\x10\x11\x12\x13\x14\x15\x16\x17",
-               .klen   = 24,
-               .input  = "\x00\x11\x22\x33\x44\x55\x66\x77"
-                         "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
-               .ilen   = 16,
-               .result = "\xdd\xa9\x7c\xa4\x86\x4c\xdf\xe0"
-                         "\x6e\xaf\x70\xa0\xec\x0d\x71\x91",
-               .rlen   = 16,
-       }, {
-               .key    = "\x00\x01\x02\x03\x04\x05\x06\x07"
-                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-                         "\x10\x11\x12\x13\x14\x15\x16\x17"
-                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+       }, { /* Generated from TF test vectors */
+               .key    = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+                         "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A"
+                         "\x27\x04\xE1\x27\x04\xE1\xBE\x9B"
+                         "\x78\xBE\x9B\x78\x55\x32\x0F\x55",
                .klen   = 32,
-               .input  = "\x00\x11\x22\x33\x44\x55\x66\x77"
-                         "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
-               .ilen   = 16,
-               .result = "\x8e\xa2\xb7\xca\x51\x67\x45\xbf"
-                         "\xea\xfc\x49\x90\x4b\x49\x60\x89",
-               .rlen   = 16,
+               .iv     = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F"
+                         "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64",
+               .input  = "\xC3\x70\x22\x32\xF5\x80\xCB\x54"
+                         "\xFC\x30\xE0\xF6\xEB\x39\x57\xA6"
+                         "\xB6\xB9\xC5\xA4\x91\x55\x14\x97"
+                         "\xC1\x20\xFF\x6C\x5C\xF0\x67\xEA"
+                         "\x2F\xED\xD8\xC9\xFB\x38\x3F\xFE"
+                         "\x93\xBE\xDC\x00\xD3\x7F\xAD\x4C"
+                         "\x5A\x08\x92\xD1\x47\x0C\xFA\x6C"
+                         "\xD0\x6A\x99\x10\x72\xF8\x47\x62"
+                         "\x81\x42\xF8\xD8\xF5\xBB\x94\x08"
+                         "\xAA\x97\xA2\x8B\x69\xB3\xD2\x7E"
+                         "\xBC\xB5\x00\x0C\xE5\x44\x4B\x58"
+                         "\xE8\x63\xDC\xB3\xC4\xE5\x23\x12"
+                         "\x5A\x72\x85\x47\x8B\xEC\x9F\x26"
+                         "\x84\xB6\xED\x10\x33\x63\x9B\x5F"
+                         "\x4D\x53\xEE\x94\x45\x8B\x60\x58"
+                         "\x86\x20\xF9\x1E\x82\x08\x3E\x58"
+                         "\x60\x1B\x34\x19\x02\xBE\x4E\x09"
+                         "\xBB\x7C\x15\xCC\x60\x27\x55\x7A"
+                         "\x12\xB8\xD8\x08\x89\x3C\xA6\xF3"
+                         "\xF1\xDD\xA7\x07\xA3\x12\x85\x28"
+                         "\xE9\x57\xAC\x80\x0C\x5C\x0F\x3A"
+                         "\x5D\xC2\x91\xC7\x90\xE4\x8C\x43"
+                         "\x92\xE4\x7C\x26\x69\x4D\x83\x68"
+                         "\x14\x96\x42\x47\xBD\xA9\xE4\x8A"
+                         "\x33\x19\xEB\x54\x8E\x0D\x4B\x6E"
+                         "\x91\x51\xB5\x36\x08\xDE\x1C\x06"
+                         "\x03\xBD\xDE\x81\x26\xF7\x99\xC2"
+                         "\xBA\xF7\x6D\x87\x0D\xE4\xA6\xCF"
+                         "\xC1\xF5\x27\x05\xB8\x02\x57\x72"
+                         "\xE6\x42\x13\x0B\xC6\x47\x05\x74"
+                         "\x24\x15\xF7\x0D\xC2\x23\x9D\xB9"
+                         "\x3C\x77\x18\x93\xBA\xB4\xFC\x8C"
+                         "\x98\x82\x67\x67\xB4\xD7\xD3\x43"
+                         "\x23\x08\x02\xB7\x9B\x99\x05\xFB"
+                         "\xD3\xB5\x00\x0A\xA9\x9D\x66\xD6"
+                         "\x2E\x49\x58\xD0\xA8\x57\x29\x7F"
+                         "\x0A\x0E\x7D\xFC\x92\x83\xCC\x67"
+                         "\xA2\xB1\x70\x3A\x8F\x87\x4A\x8D"
+                         "\x17\xE2\x58\x2B\x88\x0D\x68\x62"
+                         "\xBF\x35\xD1\x6F\xC0\xF0\x18\x62"
+                         "\xB2\xC7\x2D\x58\xC7\x16\xDE\x08"
+                         "\xEB\x84\x1D\x25\xA7\x38\x94\x06"
+                         "\x93\x9D\xF8\xFE\x88\x71\xE7\x84"
+                         "\x2C\xA0\x38\xA3\x1D\x48\xCF\x29"
+                         "\x0B\xBC\xD8\x50\x99\x1A\x26\xFB"
+                         "\x8E\x75\x3D\x73\xEB\x6A\xED\x29"
+                         "\xE0\x8E\xED\xFC\xFE\x6F\xF6\xBA"
+                         "\x41\xE2\x10\x4C\x01\x8B\x69\x2B"
+                         "\x25\x3F\x4D\x70\x7B\x92\xD6\x3B"
+                         "\xAC\xF9\x77\x18\xD9\x6A\x30\xA6"
+                         "\x2E\xFA\x30\xFF\xC8\xD5\x1D\x06"
+                         "\x59\x28\x1D\x86\x43\x04\x5D\x3B"
+                         "\x99\x4C\x04\x5A\x21\x17\x8B\x76"
+                         "\x8F\x72\xCB\xA1\x9C\x29\x4C\xC3"
+                         "\x65\xA2\x58\x2A\xC5\x66\x24\xBF"
+                         "\xBA\xE6\x0C\xDD\x34\x24\x74\xC8"
+                         "\x84\x0A\x66\x2C\xBE\x8F\x32\xA9"
+                         "\xE7\xE4\xA1\xD7\xDA\xAB\x23\x1E"
+                         "\xEB\xEE\x6C\x94\x6F\x9C\x2E\xD1"
+                         "\x49\x2C\xF3\xD4\x90\xCC\x93\x4C"
+                         "\x84\x52\x6D\x68\xDE\xC6\x64\xB2"
+                         "\x11\x74\x93\x57\xB4\x7E\xC6\x00",
+               .ilen   = 496,
+               .result = "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+                         "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+                         "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+                         "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+                         "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+                         "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
+                         "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
+                         "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+                         "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+                         "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+                         "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+                         "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+                         "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+                         "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+                         "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+                         "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+                         "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+                         "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A"
+                         "\xF1\x65\xFC\x93\x07\x9E\x35\xCC"
+                         "\x40\xD7\x6E\x05\x79\x10\xA7\x1B"
+                         "\xB2\x49\xE0\x54\xEB\x82\x19\x8D"
+                         "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF"
+                         "\x96\x0A\xA1\x38\xCF\x43\xDA\x71"
+                         "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3"
+                         "\x57\xEE\x85\x1C\x90\x27\xBE\x32"
+                         "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4"
+                         "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16"
+                         "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88"
+                         "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA"
+                         "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49"
+                         "\xE0\x77\x0E\x82\x19\xB0\x24\xBB"
+                         "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D"
+                         "\xC4\x38\xCF\x66\xFD\x71\x08\x9F"
+                         "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11"
+                         "\x85\x1C\xB3\x27\xBE\x55\xEC\x60"
+                         "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2"
+                         "\x69\x00\x74\x0B\xA2\x16\xAD\x44"
+                         "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6"
+                         "\x2A\xC1\x58\xEF\x63\xFA\x91\x05"
+                         "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77"
+                         "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9"
+                         "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B"
+                         "\xF2\x66\xFD\x94\x08\x9F\x36\xCD"
+                         "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C"
+                         "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E"
+                         "\x25\xBC\x30\xC7\x5E\xF5\x69\x00"
+                         "\x97\x0B\xA2\x39\xD0\x44\xDB\x72"
+                         "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4"
+                         "\x58\xEF\x86\x1D\x91\x28\xBF\x33"
+                         "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5"
+                         "\x3C\xD3\x47\xDE\x75\x0C\x80\x17"
+                         "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89"
+                         "\x20\x94\x2B\xC2\x36\xCD\x64\xFB"
+                         "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A"
+                         "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC"
+                         "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E"
+                         "\xC5\x39\xD0\x67\xFE\x72\x09\xA0"
+                         "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12"
+                         "\x86\x1D\xB4\x28\xBF\x56\xED\x61"
+                         "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3"
+                         "\x6A\x01\x75\x0C\xA3\x17\xAE\x45"
+                         "\xDC\x50\xE7\x7E\x15\x89\x20\xB7",
+               .rlen   = 496,
        },
 };
 
-static struct cipher_testvec aes_dec_tv_template[] = {
-       { /* From FIPS-197 */
-               .key    = "\x00\x01\x02\x03\x04\x05\x06\x07"
-                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
-               .klen   = 16,
-               .input  = "\x69\xc4\xe0\xd8\x6a\x7b\x04\x30"
-                         "\xd8\xcd\xb7\x80\x70\xb4\xc5\x5a",
-               .ilen   = 16,
-               .result = "\x00\x11\x22\x33\x44\x55\x66\x77"
-                         "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
-               .rlen   = 16,
-       }, {
-               .key    = "\x00\x01\x02\x03\x04\x05\x06\x07"
-                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-                         "\x10\x11\x12\x13\x14\x15\x16\x17",
-               .klen   = 24,
-               .input  = "\xdd\xa9\x7c\xa4\x86\x4c\xdf\xe0"
-                         "\x6e\xaf\x70\xa0\xec\x0d\x71\x91",
-               .ilen   = 16,
-               .result = "\x00\x11\x22\x33\x44\x55\x66\x77"
-                         "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
-               .rlen   = 16,
-       }, {
-               .key    = "\x00\x01\x02\x03\x04\x05\x06\x07"
-                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
-                         "\x10\x11\x12\x13\x14\x15\x16\x17"
-                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+static struct cipher_testvec cast6_cbc_enc_tv_template[] = {
+       { /* Generated from TF test vectors */
+               .key    = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+                         "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A"
+                         "\x27\x04\xE1\x27\x04\xE1\xBE\x9B"
+                         "\x78\xBE\x9B\x78\x55\x32\x0F\x55",
                .klen   = 32,
-               .input  = "\x8e\xa2\xb7\xca\x51\x67\x45\xbf"
-                         "\xea\xfc\x49\x90\x4b\x49\x60\x89",
-               .ilen   = 16,
-               .result = "\x00\x11\x22\x33\x44\x55\x66\x77"
-                         "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
-               .rlen   = 16,
-       },
-};
-
-static struct cipher_testvec aes_cbc_enc_tv_template[] = {
-       { /* From RFC 3602 */
-               .key    = "\x06\xa9\x21\x40\x36\xb8\xa1\x5b"
-                         "\x51\x2e\x03\xd5\x34\x12\x00\x06",
-               .klen   = 16,
-               .iv     = "\x3d\xaf\xba\x42\x9d\x9e\xb4\x30"
-                         "\xb4\x22\xda\x80\x2c\x9f\xac\x41",
-               .input  = "Single block msg",
-               .ilen   = 16,
+               .iv     = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F"
+                         "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64",
+               .input  = "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+                         "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+                         "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+                         "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+                         "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+                         "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
+                         "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
+                         "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+                         "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+                         "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+                         "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+                         "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+                         "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+                         "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+                         "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+                         "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+                         "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+                         "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A"
+                         "\xF1\x65\xFC\x93\x07\x9E\x35\xCC"
+                         "\x40\xD7\x6E\x05\x79\x10\xA7\x1B"
+                         "\xB2\x49\xE0\x54\xEB\x82\x19\x8D"
+                         "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF"
+                         "\x96\x0A\xA1\x38\xCF\x43\xDA\x71"
+                         "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3"
+                         "\x57\xEE\x85\x1C\x90\x27\xBE\x32"
+                         "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4"
+                         "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16"
+                         "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88"
+                         "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA"
+                         "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49"
+                         "\xE0\x77\x0E\x82\x19\xB0\x24\xBB"
+                         "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D"
+                         "\xC4\x38\xCF\x66\xFD\x71\x08\x9F"
+                         "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11"
+                         "\x85\x1C\xB3\x27\xBE\x55\xEC\x60"
+                         "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2"
+                         "\x69\x00\x74\x0B\xA2\x16\xAD\x44"
+                         "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6"
+                         "\x2A\xC1\x58\xEF\x63\xFA\x91\x05"
+                         "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77"
+                         "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9"
+                         "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B"
+                         "\xF2\x66\xFD\x94\x08\x9F\x36\xCD"
+                         "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C"
+                         "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E"
+                         "\x25\xBC\x30\xC7\x5E\xF5\x69\x00"
+                         "\x97\x0B\xA2\x39\xD0\x44\xDB\x72"
+                         "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4"
+                         "\x58\xEF\x86\x1D\x91\x28\xBF\x33"
+                         "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5"
+                         "\x3C\xD3\x47\xDE\x75\x0C\x80\x17"
+                         "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89"
+                         "\x20\x94\x2B\xC2\x36\xCD\x64\xFB"
+                         "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A"
+                         "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC"
+                         "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E"
+                         "\xC5\x39\xD0\x67\xFE\x72\x09\xA0"
+                         "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12"
+                         "\x86\x1D\xB4\x28\xBF\x56\xED\x61"
+                         "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3"
+                         "\x6A\x01\x75\x0C\xA3\x17\xAE\x45"
+                         "\xDC\x50\xE7\x7E\x15\x89\x20\xB7",
+               .ilen   = 496,
+               .result = "\xDF\x77\x68\x96\xC7\xBA\xF8\xE2"
+                         "\x0E\x24\x99\x1A\xAA\xF3\xC6\x9F"
+                         "\xA0\x73\xB3\x70\xC3\x68\x64\x70"
+                         "\xAD\x33\x02\xFB\x88\x74\xAA\x78"
+                         "\xC7\x47\x1A\x18\x61\x2D\xAC\x9F"
+                         "\x7E\x6F\xDF\x05\x13\x76\xA6\x72"
+                         "\xB7\x13\x09\x0F\x7D\x38\xDF\x25"
+                         "\x4E\xFD\x50\x45\xFA\x35\x6A\xC0"
+                         "\x57\x95\xE1\x21\x26\x10\x9A\x21"
+                         "\xA1\x8A\x51\x05\xD1\xB1\x78\x35"
+                         "\x98\xF5\xAE\xC0\xC1\x8B\x94\xFF"
+                         "\xD0\x69\x3F\x42\xC2\x01\xA7\x9B"
+                         "\x23\x16\x47\x72\x81\x13\x3A\x72"
+                         "\xEC\xD9\x40\x88\x00\x9C\xB0\xA8"
+                         "\x9C\xAC\xCE\x11\x73\x7B\x63\x3E"
+                         "\xA3\x63\x98\x7D\x35\xE4\xD9\x83"
+                         "\xE2\xD0\x52\x87\x0C\x1F\xB0\xB3"
+                         "\x41\x1A\x93\x8D\x76\x31\x9F\xF2"
+                         "\xFE\x09\xA3\x8F\x22\x6A\x3B\xB9"
+                         "\x6C\x9E\xE4\xA1\xA0\xC4\xE7\xA1"
+                         "\x21\x9C\x1A\xCA\x65\xDE\x44\x03"
+                         "\x99\xF2\xD2\x39\xE3\x3F\x0F\x37"
+                         "\x53\x50\x23\xA4\x81\x6E\xDA\xFB"
+                         "\xF8\x7B\x01\xD7\xB2\x32\x9C\xB8"
+                         "\xB1\x0E\x99\x17\xB5\x38\xF9\xD7"
+                         "\x86\x2D\x6E\x94\x5C\x99\x9D\xB3"
+                         "\xD3\x63\x4B\x2A\x7D\x44\x6A\xB2"
+                         "\xC1\x03\xE6\x5A\x37\xD8\x64\x18"
+                         "\xAA\x32\xCE\x29\xED\xC0\xA2\xCB"
+                         "\x8D\xAF\xCD\xBE\x8F\xB6\xEC\xB4"
+                         "\x89\x05\x81\x6E\x71\x4F\xC3\x28"
+                         "\x10\xC1\x62\xC4\x41\xE9\xD2\x39"
+                         "\xF3\x22\x39\x12\x2C\xC2\x95\x2D"
+                         "\xBF\x93\x58\x4B\x04\xD1\x8D\x57"
+                         "\xAE\xEB\x60\x03\x56\x35\xAD\x5A"
+                         "\xE9\xC3\xFF\x4E\x31\xE1\x37\xF8"
+                         "\x7D\xEE\x65\x8A\xB6\x88\x1A\x3E"
+                         "\x07\x09\x82\xBA\xF0\x80\x8A\xD0"
+                         "\xA0\x3F\x6A\xE9\x24\x87\x19\x65"
+                         "\x73\x3F\x12\x91\x47\x54\xBA\x39"
+                         "\x30\x5B\x1E\xE5\xC2\xF9\x3F\xEF"
+                         "\xD6\x75\xF9\xB8\x7C\x8B\x05\x76"
+                         "\xEE\xB7\x08\x25\x4B\xB6\x7B\x47"
+                         "\x72\xC0\x4C\xD4\xDA\xE0\x75\xF1"
+                         "\x7C\xE8\x94\x9E\x16\x6E\xB8\x12"
+                         "\xA1\xC1\x6E\x3B\x1C\x59\x41\x2D"
+                         "\x23\xFA\x7D\x77\xB8\x46\x75\xFE"
+                         "\x4F\x10\xD3\x09\x60\xA1\x36\x96"
+                         "\x5B\xC2\xDC\x6E\x84\x7D\x9B\x14"
+                         "\x80\x21\x83\x58\x3C\x76\xFD\x28"
+                         "\x1D\xF9\x93\x13\xD7\x0E\x62\x14"
+                         "\x5A\xC5\x4E\x08\xA5\x56\xA4\x3C"
+                         "\x68\x93\x44\x70\xDF\xCF\x4A\x51"
+                         "\x0B\x81\x29\x41\xE5\x62\x4D\x36"
+                         "\xB3\xEA\x94\xA6\xB9\xDD\x3F\x09"
+                         "\x62\x34\xA0\x6A\x7E\x7D\xF5\xF6"
+                         "\x01\x91\xB4\x27\xDA\x59\xD6\x17"
+                         "\x56\x4D\x82\x62\x37\xA3\x48\x01"
+                         "\x99\x91\x77\xB2\x08\x6B\x2C\x37"
+                         "\xC5\x5C\xAD\xB6\x07\xB6\x84\xF3"
+                         "\x4D\x59\x7D\xC5\x28\x69\xFA\x92"
+                         "\x22\x46\x89\x2D\x0F\x2B\x08\x24",
+               .rlen   = 496,
+       },
+};
+
+static struct cipher_testvec cast6_cbc_dec_tv_template[] = {
+       { /* Generated from TF test vectors */
+               .key    = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+                         "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A"
+                         "\x27\x04\xE1\x27\x04\xE1\xBE\x9B"
+                         "\x78\xBE\x9B\x78\x55\x32\x0F\x55",
+               .klen   = 32,
+               .iv     = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F"
+                         "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64",
+               .input  = "\xDF\x77\x68\x96\xC7\xBA\xF8\xE2"
+                         "\x0E\x24\x99\x1A\xAA\xF3\xC6\x9F"
+                         "\xA0\x73\xB3\x70\xC3\x68\x64\x70"
+                         "\xAD\x33\x02\xFB\x88\x74\xAA\x78"
+                         "\xC7\x47\x1A\x18\x61\x2D\xAC\x9F"
+                         "\x7E\x6F\xDF\x05\x13\x76\xA6\x72"
+                         "\xB7\x13\x09\x0F\x7D\x38\xDF\x25"
+                         "\x4E\xFD\x50\x45\xFA\x35\x6A\xC0"
+                         "\x57\x95\xE1\x21\x26\x10\x9A\x21"
+                         "\xA1\x8A\x51\x05\xD1\xB1\x78\x35"
+                         "\x98\xF5\xAE\xC0\xC1\x8B\x94\xFF"
+                         "\xD0\x69\x3F\x42\xC2\x01\xA7\x9B"
+                         "\x23\x16\x47\x72\x81\x13\x3A\x72"
+                         "\xEC\xD9\x40\x88\x00\x9C\xB0\xA8"
+                         "\x9C\xAC\xCE\x11\x73\x7B\x63\x3E"
+                         "\xA3\x63\x98\x7D\x35\xE4\xD9\x83"
+                         "\xE2\xD0\x52\x87\x0C\x1F\xB0\xB3"
+                         "\x41\x1A\x93\x8D\x76\x31\x9F\xF2"
+                         "\xFE\x09\xA3\x8F\x22\x6A\x3B\xB9"
+                         "\x6C\x9E\xE4\xA1\xA0\xC4\xE7\xA1"
+                         "\x21\x9C\x1A\xCA\x65\xDE\x44\x03"
+                         "\x99\xF2\xD2\x39\xE3\x3F\x0F\x37"
+                         "\x53\x50\x23\xA4\x81\x6E\xDA\xFB"
+                         "\xF8\x7B\x01\xD7\xB2\x32\x9C\xB8"
+                         "\xB1\x0E\x99\x17\xB5\x38\xF9\xD7"
+                         "\x86\x2D\x6E\x94\x5C\x99\x9D\xB3"
+                         "\xD3\x63\x4B\x2A\x7D\x44\x6A\xB2"
+                         "\xC1\x03\xE6\x5A\x37\xD8\x64\x18"
+                         "\xAA\x32\xCE\x29\xED\xC0\xA2\xCB"
+                         "\x8D\xAF\xCD\xBE\x8F\xB6\xEC\xB4"
+                         "\x89\x05\x81\x6E\x71\x4F\xC3\x28"
+                         "\x10\xC1\x62\xC4\x41\xE9\xD2\x39"
+                         "\xF3\x22\x39\x12\x2C\xC2\x95\x2D"
+                         "\xBF\x93\x58\x4B\x04\xD1\x8D\x57"
+                         "\xAE\xEB\x60\x03\x56\x35\xAD\x5A"
+                         "\xE9\xC3\xFF\x4E\x31\xE1\x37\xF8"
+                         "\x7D\xEE\x65\x8A\xB6\x88\x1A\x3E"
+                         "\x07\x09\x82\xBA\xF0\x80\x8A\xD0"
+                         "\xA0\x3F\x6A\xE9\x24\x87\x19\x65"
+                         "\x73\x3F\x12\x91\x47\x54\xBA\x39"
+                         "\x30\x5B\x1E\xE5\xC2\xF9\x3F\xEF"
+                         "\xD6\x75\xF9\xB8\x7C\x8B\x05\x76"
+                         "\xEE\xB7\x08\x25\x4B\xB6\x7B\x47"
+                         "\x72\xC0\x4C\xD4\xDA\xE0\x75\xF1"
+                         "\x7C\xE8\x94\x9E\x16\x6E\xB8\x12"
+                         "\xA1\xC1\x6E\x3B\x1C\x59\x41\x2D"
+                         "\x23\xFA\x7D\x77\xB8\x46\x75\xFE"
+                         "\x4F\x10\xD3\x09\x60\xA1\x36\x96"
+                         "\x5B\xC2\xDC\x6E\x84\x7D\x9B\x14"
+                         "\x80\x21\x83\x58\x3C\x76\xFD\x28"
+                         "\x1D\xF9\x93\x13\xD7\x0E\x62\x14"
+                         "\x5A\xC5\x4E\x08\xA5\x56\xA4\x3C"
+                         "\x68\x93\x44\x70\xDF\xCF\x4A\x51"
+                         "\x0B\x81\x29\x41\xE5\x62\x4D\x36"
+                         "\xB3\xEA\x94\xA6\xB9\xDD\x3F\x09"
+                         "\x62\x34\xA0\x6A\x7E\x7D\xF5\xF6"
+                         "\x01\x91\xB4\x27\xDA\x59\xD6\x17"
+                         "\x56\x4D\x82\x62\x37\xA3\x48\x01"
+                         "\x99\x91\x77\xB2\x08\x6B\x2C\x37"
+                         "\xC5\x5C\xAD\xB6\x07\xB6\x84\xF3"
+                         "\x4D\x59\x7D\xC5\x28\x69\xFA\x92"
+                         "\x22\x46\x89\x2D\x0F\x2B\x08\x24",
+               .ilen   = 496,
+               .result = "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+                         "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+                         "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+                         "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+                         "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+                         "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
+                         "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
+                         "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+                         "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+                         "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+                         "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+                         "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+                         "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+                         "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+                         "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+                         "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+                         "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+                         "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A"
+                         "\xF1\x65\xFC\x93\x07\x9E\x35\xCC"
+                         "\x40\xD7\x6E\x05\x79\x10\xA7\x1B"
+                         "\xB2\x49\xE0\x54\xEB\x82\x19\x8D"
+                         "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF"
+                         "\x96\x0A\xA1\x38\xCF\x43\xDA\x71"
+                         "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3"
+                         "\x57\xEE\x85\x1C\x90\x27\xBE\x32"
+                         "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4"
+                         "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16"
+                         "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88"
+                         "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA"
+                         "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49"
+                         "\xE0\x77\x0E\x82\x19\xB0\x24\xBB"
+                         "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D"
+                         "\xC4\x38\xCF\x66\xFD\x71\x08\x9F"
+                         "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11"
+                         "\x85\x1C\xB3\x27\xBE\x55\xEC\x60"
+                         "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2"
+                         "\x69\x00\x74\x0B\xA2\x16\xAD\x44"
+                         "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6"
+                         "\x2A\xC1\x58\xEF\x63\xFA\x91\x05"
+                         "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77"
+                         "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9"
+                         "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B"
+                         "\xF2\x66\xFD\x94\x08\x9F\x36\xCD"
+                         "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C"
+                         "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E"
+                         "\x25\xBC\x30\xC7\x5E\xF5\x69\x00"
+                         "\x97\x0B\xA2\x39\xD0\x44\xDB\x72"
+                         "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4"
+                         "\x58\xEF\x86\x1D\x91\x28\xBF\x33"
+                         "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5"
+                         "\x3C\xD3\x47\xDE\x75\x0C\x80\x17"
+                         "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89"
+                         "\x20\x94\x2B\xC2\x36\xCD\x64\xFB"
+                         "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A"
+                         "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC"
+                         "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E"
+                         "\xC5\x39\xD0\x67\xFE\x72\x09\xA0"
+                         "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12"
+                         "\x86\x1D\xB4\x28\xBF\x56\xED\x61"
+                         "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3"
+                         "\x6A\x01\x75\x0C\xA3\x17\xAE\x45"
+                         "\xDC\x50\xE7\x7E\x15\x89\x20\xB7",
+               .rlen   = 496,
+       },
+};
+
+static struct cipher_testvec cast6_ctr_enc_tv_template[] = {
+       { /* Generated from TF test vectors */
+               .key    = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+                         "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A"
+                         "\x27\x04\xE1\x27\x04\xE1\xBE\x9B"
+                         "\x78\xBE\x9B\x78\x55\x32\x0F\x55",
+               .klen   = 32,
+               .iv     = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F"
+                         "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64",
+               .input  = "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+                         "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+                         "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+                         "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+                         "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+                         "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
+                         "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
+                         "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+                         "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+                         "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+                         "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+                         "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+                         "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+                         "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+                         "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+                         "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+                         "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+                         "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A"
+                         "\xF1\x65\xFC\x93\x07\x9E\x35\xCC"
+                         "\x40\xD7\x6E\x05\x79\x10\xA7\x1B"
+                         "\xB2\x49\xE0\x54\xEB\x82\x19\x8D"
+                         "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF"
+                         "\x96\x0A\xA1\x38\xCF\x43\xDA\x71"
+                         "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3"
+                         "\x57\xEE\x85\x1C\x90\x27\xBE\x32"
+                         "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4"
+                         "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16"
+                         "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88"
+                         "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA"
+                         "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49"
+                         "\xE0\x77\x0E\x82\x19\xB0\x24\xBB"
+                         "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D"
+                         "\xC4\x38\xCF\x66\xFD\x71\x08\x9F"
+                         "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11"
+                         "\x85\x1C\xB3\x27\xBE\x55\xEC\x60"
+                         "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2"
+                         "\x69\x00\x74\x0B\xA2\x16\xAD\x44"
+                         "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6"
+                         "\x2A\xC1\x58\xEF\x63\xFA\x91\x05"
+                         "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77"
+                         "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9"
+                         "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B"
+                         "\xF2\x66\xFD\x94\x08\x9F\x36\xCD"
+                         "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C"
+                         "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E"
+                         "\x25\xBC\x30\xC7\x5E\xF5\x69\x00"
+                         "\x97\x0B\xA2\x39\xD0\x44\xDB\x72"
+                         "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4"
+                         "\x58\xEF\x86\x1D\x91\x28\xBF\x33"
+                         "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5"
+                         "\x3C\xD3\x47\xDE\x75\x0C\x80\x17"
+                         "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89"
+                         "\x20\x94\x2B\xC2\x36\xCD\x64\xFB"
+                         "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A"
+                         "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC"
+                         "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E"
+                         "\xC5\x39\xD0\x67\xFE\x72\x09\xA0"
+                         "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12"
+                         "\x86\x1D\xB4\x28\xBF\x56\xED\x61"
+                         "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3"
+                         "\x6A\x01\x75\x0C\xA3\x17\xAE\x45"
+                         "\xDC\x50\xE7\x7E\x15\x89\x20\xB7",
+               .ilen   = 496,
+               .result = "\x26\x0A\xF1\xE2\x3F\x8A\xEF\xA3"
+                         "\x53\x9A\x5E\x1B\x2A\x1A\xC6\x0A"
+                         "\x57\xA3\xEF\x47\x2A\xE8\x88\xA7"
+                         "\x3C\xD0\xEC\xB9\x94\x50\x7D\x56"
+                         "\xBC\xE1\xC1\xF5\xE1\xEE\x12\xF8"
+                         "\x4F\x03\x82\x3A\x93\x6B\x4C\xD3"
+                         "\xE3\xF3\xFA\xC2\x23\x55\x98\x20"
+                         "\x49\x76\x9B\x6B\xC1\x23\xBF\xE5"
+                         "\xD4\xC4\x2F\x61\xE1\x67\x2A\x30"
+                         "\x6F\x29\xCA\x54\xF8\x1B\xA6\x7D"
+                         "\x66\x45\xEE\xC8\x19\xBE\x50\xF0"
+                         "\x5F\x65\xF8\x1E\x4D\x07\x87\xD9"
+                         "\xD3\xD9\x1B\x09\x89\xFD\x42\xC5"
+                         "\xDB\xEB\x86\xF1\x67\x04\x0F\x5C"
+                         "\x81\xDF\x82\x12\xC7\x4C\x1B\x07"
+                         "\xDE\xE6\xFA\x29\x86\xD1\xB0\xBA"
+                         "\x3D\x6A\x69\x76\xEC\x0F\xB4\xE6"
+                         "\xCD\xA7\xF8\xA8\xB8\xE0\x33\xF5"
+                         "\x49\x61\x22\x52\x64\x8C\x46\x41"
+                         "\x1F\x48\x5F\x4F\xA2\x89\x36\x17"
+                         "\x20\xF8\x2F\x8F\x4B\xFA\xF2\xC0"
+                         "\x1E\x18\xA2\xF8\xB7\x6D\x98\xE3"
+                         "\x00\x14\x15\x59\xC1\x30\x64\xAF"
+                         "\xA8\x01\x38\xAB\xD4\x8B\xEC\x7C"
+                         "\x44\x9A\xC6\x2C\x2E\x2B\x2B\xF4"
+                         "\x02\x37\xC4\x69\xEF\x36\xC1\xF3"
+                         "\xA0\xFB\xFE\x29\xAD\x39\xCF\xD0"
+                         "\x51\x73\xA3\x22\x42\x41\xAB\xD2"
+                         "\x0F\x50\x14\xB9\x54\xD3\xD4\xFA"
+                         "\xBF\xC9\xBB\xCE\xC4\x1D\x2D\xAF"
+                         "\xC9\x3F\x07\x87\x42\x4B\x3A\x54"
+                         "\x34\x8E\x37\xA3\x03\x6F\x65\x66"
+                         "\xDB\x44\xC3\xE8\xD7\xDD\x7D\xDD"
+                         "\x61\xB4\x2B\x80\xA3\x98\x13\xF5"
+                         "\x5A\xD3\x34\x58\xC3\x6E\xF6\xB8"
+                         "\x0A\xC6\x50\x01\x8E\xD5\x6C\x7D"
+                         "\xFE\x16\xB6\xCF\xFC\x51\x40\xAE"
+                         "\xB3\x15\xAC\x90\x6F\x0B\x28\x3A"
+                         "\x60\x40\x38\x90\x20\x46\xC7\xB3"
+                         "\x0B\x12\x6D\x3B\x15\x14\xF9\xF4"
+                         "\x11\x41\x76\x6B\xB3\x60\x82\x3C"
+                         "\x84\xFB\x08\x2E\x92\x25\xCB\x79"
+                         "\x6F\x58\xC5\x94\x00\x00\x47\xB6"
+                         "\x9E\xDC\x0F\x29\x70\x46\x20\x76"
+                         "\x65\x75\x66\x5C\x00\x96\xB3\xE1"
+                         "\x0B\xA7\x11\x8B\x2E\x61\x4E\x45"
+                         "\x73\xFC\x91\xAB\x79\x41\x23\x14"
+                         "\x13\xB6\x72\x6C\x46\xB3\x03\x11"
+                         "\xE4\xF1\xEE\xC9\x7A\xCF\x96\x32"
+                         "\xB6\xF0\x8B\x97\xB4\xCF\x82\xB7"
+                         "\x15\x48\x44\x99\x09\xF6\xE0\xD7"
+                         "\xBC\xF1\x5B\x91\x4F\x30\x22\xA2"
+                         "\x45\xC4\x68\x55\xC2\xBE\xA7\xD2"
+                         "\x12\x53\x35\x9C\xF9\xE7\x35\x5D"
+                         "\x81\xE4\x86\x42\xC3\x58\xFB\xF0"
+                         "\x38\x9B\x8E\x5A\xEF\x83\x33\x0F"
+                         "\x00\x4E\x3F\x9F\xF5\x84\x62\xC4"
+                         "\x19\x35\x88\x22\x45\x59\x0E\x8F"
+                         "\xEC\x27\xDD\x4A\xA4\x1F\xBC\x41"
+                         "\x9B\x66\x8D\x32\xBA\x81\x34\x87"
+                         "\x0E\x74\x33\x30\x62\xB9\x89\xDF"
+                         "\xF9\xC5\xDD\x27\xB3\x39\xCB\xCB",
+               .rlen   = 496,
+       },
+};
+
+static struct cipher_testvec cast6_ctr_dec_tv_template[] = {
+       { /* Generated from TF test vectors */
+               .key    = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+                         "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A"
+                         "\x27\x04\xE1\x27\x04\xE1\xBE\x9B"
+                         "\x78\xBE\x9B\x78\x55\x32\x0F\x55",
+               .klen   = 32,
+               .iv     = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F"
+                         "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64",
+               .input  = "\x26\x0A\xF1\xE2\x3F\x8A\xEF\xA3"
+                         "\x53\x9A\x5E\x1B\x2A\x1A\xC6\x0A"
+                         "\x57\xA3\xEF\x47\x2A\xE8\x88\xA7"
+                         "\x3C\xD0\xEC\xB9\x94\x50\x7D\x56"
+                         "\xBC\xE1\xC1\xF5\xE1\xEE\x12\xF8"
+                         "\x4F\x03\x82\x3A\x93\x6B\x4C\xD3"
+                         "\xE3\xF3\xFA\xC2\x23\x55\x98\x20"
+                         "\x49\x76\x9B\x6B\xC1\x23\xBF\xE5"
+                         "\xD4\xC4\x2F\x61\xE1\x67\x2A\x30"
+                         "\x6F\x29\xCA\x54\xF8\x1B\xA6\x7D"
+                         "\x66\x45\xEE\xC8\x19\xBE\x50\xF0"
+                         "\x5F\x65\xF8\x1E\x4D\x07\x87\xD9"
+                         "\xD3\xD9\x1B\x09\x89\xFD\x42\xC5"
+                         "\xDB\xEB\x86\xF1\x67\x04\x0F\x5C"
+                         "\x81\xDF\x82\x12\xC7\x4C\x1B\x07"
+                         "\xDE\xE6\xFA\x29\x86\xD1\xB0\xBA"
+                         "\x3D\x6A\x69\x76\xEC\x0F\xB4\xE6"
+                         "\xCD\xA7\xF8\xA8\xB8\xE0\x33\xF5"
+                         "\x49\x61\x22\x52\x64\x8C\x46\x41"
+                         "\x1F\x48\x5F\x4F\xA2\x89\x36\x17"
+                         "\x20\xF8\x2F\x8F\x4B\xFA\xF2\xC0"
+                         "\x1E\x18\xA2\xF8\xB7\x6D\x98\xE3"
+                         "\x00\x14\x15\x59\xC1\x30\x64\xAF"
+                         "\xA8\x01\x38\xAB\xD4\x8B\xEC\x7C"
+                         "\x44\x9A\xC6\x2C\x2E\x2B\x2B\xF4"
+                         "\x02\x37\xC4\x69\xEF\x36\xC1\xF3"
+                         "\xA0\xFB\xFE\x29\xAD\x39\xCF\xD0"
+                         "\x51\x73\xA3\x22\x42\x41\xAB\xD2"
+                         "\x0F\x50\x14\xB9\x54\xD3\xD4\xFA"
+                         "\xBF\xC9\xBB\xCE\xC4\x1D\x2D\xAF"
+                         "\xC9\x3F\x07\x87\x42\x4B\x3A\x54"
+                         "\x34\x8E\x37\xA3\x03\x6F\x65\x66"
+                         "\xDB\x44\xC3\xE8\xD7\xDD\x7D\xDD"
+                         "\x61\xB4\x2B\x80\xA3\x98\x13\xF5"
+                         "\x5A\xD3\x34\x58\xC3\x6E\xF6\xB8"
+                         "\x0A\xC6\x50\x01\x8E\xD5\x6C\x7D"
+                         "\xFE\x16\xB6\xCF\xFC\x51\x40\xAE"
+                         "\xB3\x15\xAC\x90\x6F\x0B\x28\x3A"
+                         "\x60\x40\x38\x90\x20\x46\xC7\xB3"
+                         "\x0B\x12\x6D\x3B\x15\x14\xF9\xF4"
+                         "\x11\x41\x76\x6B\xB3\x60\x82\x3C"
+                         "\x84\xFB\x08\x2E\x92\x25\xCB\x79"
+                         "\x6F\x58\xC5\x94\x00\x00\x47\xB6"
+                         "\x9E\xDC\x0F\x29\x70\x46\x20\x76"
+                         "\x65\x75\x66\x5C\x00\x96\xB3\xE1"
+                         "\x0B\xA7\x11\x8B\x2E\x61\x4E\x45"
+                         "\x73\xFC\x91\xAB\x79\x41\x23\x14"
+                         "\x13\xB6\x72\x6C\x46\xB3\x03\x11"
+                         "\xE4\xF1\xEE\xC9\x7A\xCF\x96\x32"
+                         "\xB6\xF0\x8B\x97\xB4\xCF\x82\xB7"
+                         "\x15\x48\x44\x99\x09\xF6\xE0\xD7"
+                         "\xBC\xF1\x5B\x91\x4F\x30\x22\xA2"
+                         "\x45\xC4\x68\x55\xC2\xBE\xA7\xD2"
+                         "\x12\x53\x35\x9C\xF9\xE7\x35\x5D"
+                         "\x81\xE4\x86\x42\xC3\x58\xFB\xF0"
+                         "\x38\x9B\x8E\x5A\xEF\x83\x33\x0F"
+                         "\x00\x4E\x3F\x9F\xF5\x84\x62\xC4"
+                         "\x19\x35\x88\x22\x45\x59\x0E\x8F"
+                         "\xEC\x27\xDD\x4A\xA4\x1F\xBC\x41"
+                         "\x9B\x66\x8D\x32\xBA\x81\x34\x87"
+                         "\x0E\x74\x33\x30\x62\xB9\x89\xDF"
+                         "\xF9\xC5\xDD\x27\xB3\x39\xCB\xCB",
+               .ilen   = 496,
+               .result = "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+                         "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+                         "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+                         "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+                         "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+                         "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
+                         "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
+                         "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+                         "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+                         "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+                         "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+                         "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+                         "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+                         "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+                         "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+                         "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+                         "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+                         "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A"
+                         "\xF1\x65\xFC\x93\x07\x9E\x35\xCC"
+                         "\x40\xD7\x6E\x05\x79\x10\xA7\x1B"
+                         "\xB2\x49\xE0\x54\xEB\x82\x19\x8D"
+                         "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF"
+                         "\x96\x0A\xA1\x38\xCF\x43\xDA\x71"
+                         "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3"
+                         "\x57\xEE\x85\x1C\x90\x27\xBE\x32"
+                         "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4"
+                         "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16"
+                         "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88"
+                         "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA"
+                         "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49"
+                         "\xE0\x77\x0E\x82\x19\xB0\x24\xBB"
+                         "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D"
+                         "\xC4\x38\xCF\x66\xFD\x71\x08\x9F"
+                         "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11"
+                         "\x85\x1C\xB3\x27\xBE\x55\xEC\x60"
+                         "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2"
+                         "\x69\x00\x74\x0B\xA2\x16\xAD\x44"
+                         "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6"
+                         "\x2A\xC1\x58\xEF\x63\xFA\x91\x05"
+                         "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77"
+                         "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9"
+                         "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B"
+                         "\xF2\x66\xFD\x94\x08\x9F\x36\xCD"
+                         "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C"
+                         "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E"
+                         "\x25\xBC\x30\xC7\x5E\xF5\x69\x00"
+                         "\x97\x0B\xA2\x39\xD0\x44\xDB\x72"
+                         "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4"
+                         "\x58\xEF\x86\x1D\x91\x28\xBF\x33"
+                         "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5"
+                         "\x3C\xD3\x47\xDE\x75\x0C\x80\x17"
+                         "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89"
+                         "\x20\x94\x2B\xC2\x36\xCD\x64\xFB"
+                         "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A"
+                         "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC"
+                         "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E"
+                         "\xC5\x39\xD0\x67\xFE\x72\x09\xA0"
+                         "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12"
+                         "\x86\x1D\xB4\x28\xBF\x56\xED\x61"
+                         "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3"
+                         "\x6A\x01\x75\x0C\xA3\x17\xAE\x45"
+                         "\xDC\x50\xE7\x7E\x15\x89\x20\xB7",
+               .rlen   = 496,
+       },
+};
+
+static struct cipher_testvec cast6_lrw_enc_tv_template[] = {
+       { /* Generated from TF test vectors */
+               .key    = "\xf8\xd4\x76\xff\xd6\x46\xee\x6c"
+                         "\x23\x84\xcb\x1c\x77\xd6\x19\x5d"
+                         "\xfe\xf1\xa9\xf3\x7b\xbc\x8d\x21"
+                         "\xa7\x9c\x21\xf8\xcb\x90\x02\x89"
+                         "\xa8\x45\x34\x8e\xc8\xc5\xb5\xf1"
+                         "\x26\xf5\x0e\x76\xfe\xfd\x1b\x1e",
+               .klen   = 48,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x01",
+               .input  = "\x05\x11\xb7\x18\xab\xc6\x2d\xac"
+                         "\x70\x5d\xf6\x22\x94\xcd\xe5\x6c"
+                         "\x17\x6b\xf6\x1c\xf0\xf3\x6e\xf8"
+                         "\x50\x38\x1f\x71\x49\xb6\x57\xd6"
+                         "\x8f\xcb\x8d\x6b\xe3\xa6\x29\x90"
+                         "\xfe\x2a\x62\x82\xae\x6d\x8b\xf6"
+                         "\xad\x1e\x9e\x20\x5f\x38\xbe\x04"
+                         "\xda\x10\x8e\xed\xa2\xa4\x87\xab"
+                         "\xda\x6b\xb4\x0c\x75\xba\xd3\x7c"
+                         "\xc9\xac\x42\x31\x95\x7c\xc9\x04"
+                         "\xeb\xd5\x6e\x32\x69\x8a\xdb\xa6"
+                         "\x15\xd7\x3f\x4f\x2f\x66\x69\x03"
+                         "\x9c\x1f\x54\x0f\xde\x1f\xf3\x65"
+                         "\x4c\x96\x12\xed\x7c\x92\x03\x01"
+                         "\x6f\xbc\x35\x93\xac\xf1\x27\xf1"
+                         "\xb4\x96\x82\x5a\x5f\xb0\xa0\x50"
+                         "\x89\xa4\x8e\x66\x44\x85\xcc\xfd"
+                         "\x33\x14\x70\xe3\x96\xb2\xc3\xd3"
+                         "\xbb\x54\x5a\x1a\xf9\x74\xa2\xc5"
+                         "\x2d\x64\x75\xdd\xb4\x54\xe6\x74"
+                         "\x8c\xd3\x9d\x9e\x86\xab\x51\x53"
+                         "\xb7\x93\x3e\x6f\xd0\x4e\x2c\x40"
+                         "\xf6\xa8\x2e\x3e\x9d\xf4\x66\xa5"
+                         "\x76\x12\x73\x44\x1a\x56\xd7\x72"
+                         "\x88\xcd\x21\x8c\x4c\x0f\xfe\xda"
+                         "\x95\xe0\x3a\xa6\xa5\x84\x46\xcd"
+                         "\xd5\x3e\x9d\x3a\xe2\x67\xe6\x60"
+                         "\x1a\xe2\x70\x85\x58\xc2\x1b\x09"
+                         "\xe1\xd7\x2c\xca\xad\xa8\x8f\xf9"
+                         "\xac\xb3\x0e\xdb\xca\x2e\xe2\xb8"
+                         "\x51\x71\xd9\x3c\x6c\xf1\x56\xf8"
+                         "\xea\x9c\xf1\xfb\x0c\xe6\xb7\x10"
+                         "\x1c\xf8\xa9\x7c\xe8\x53\x35\xc1"
+                         "\x90\x3e\x76\x4a\x74\xa4\x21\x2c"
+                         "\xf6\x2c\x4e\x0f\x94\x3a\x88\x2e"
+                         "\x41\x09\x6a\x33\x7d\xf6\xdd\x3f"
+                         "\x8d\x23\x31\x74\x84\xeb\x88\x6e"
+                         "\xcc\xb9\xbc\x22\x83\x19\x07\x22"
+                         "\xa5\x2d\xdf\xa5\xf3\x80\x85\x78"
+                         "\x84\x39\x6a\x6d\x6a\x99\x4f\xa5"
+                         "\x15\xfe\x46\xb0\xe4\x6c\xa5\x41"
+                         "\x3c\xce\x8f\x42\x60\x71\xa7\x75"
+                         "\x08\x40\x65\x8a\x82\xbf\xf5\x43"
+                         "\x71\x96\xa9\x4d\x44\x8a\x20\xbe"
+                         "\xfa\x4d\xbb\xc0\x7d\x31\x96\x65"
+                         "\xe7\x75\xe5\x3e\xfd\x92\x3b\xc9"
+                         "\x55\xbb\x16\x7e\xf7\xc2\x8c\xa4"
+                         "\x40\x1d\xe5\xef\x0e\xdf\xe4\x9a"
+                         "\x62\x73\x65\xfd\x46\x63\x25\x3d"
+                         "\x2b\xaf\xe5\x64\xfe\xa5\x5c\xcf"
+                         "\x24\xf3\xb4\xac\x64\xba\xdf\x4b"
+                         "\xc6\x96\x7d\x81\x2d\x8d\x97\xf7"
+                         "\xc5\x68\x77\x84\x32\x2b\xcc\x85"
+                         "\x74\x96\xf0\x12\x77\x61\xb9\xeb"
+                         "\x71\xaa\x82\xcb\x1c\xdb\x89\xc8"
+                         "\xc6\xb5\xe3\x5c\x7d\x39\x07\x24"
+                         "\xda\x39\x87\x45\xc0\x2b\xbb\x01"
+                         "\xac\xbc\x2a\x5c\x7f\xfc\xe8\xce"
+                         "\x6d\x9c\x6f\xed\xd3\xc1\xa1\xd6"
+                         "\xc5\x55\xa9\x66\x2f\xe1\xc8\x32"
+                         "\xa6\x5d\xa4\x3a\x98\x73\xe8\x45"
+                         "\xa4\xc7\xa8\xb4\xf6\x13\x03\xf6"
+                         "\xe9\x2e\xc4\x29\x0f\x84\xdb\xc4"
+                         "\x21\xc4\xc2\x75\x67\x89\x37\x0a",
+               .ilen   = 512,
+               .result = "\x55\x25\x09\x8B\xB5\xD5\xF8\xBF"
+                         "\x37\x4A\xFE\x3C\x47\xD8\xE6\xEB"
+                         "\xCA\xA4\x9B\xB0\xAB\x6D\x64\xCA"
+                         "\x58\xB6\x73\xF0\xD7\x52\x34\xEF"
+                         "\xFB\x3E\x96\x81\xB7\x71\x34\xA4"
+                         "\x55\x20\xBE\x39\x5A\x2B\xF9\xD1"
+                         "\x65\x0B\xDA\xD3\x7E\xB3\xA6\xF7"
+                         "\x2E\x0B\x5A\x52\xDB\x39\x8C\x9B"
+                         "\x61\x17\x5F\xAF\xB6\x5A\xC8\x08"
+                         "\xA7\xB7\x2A\x11\x7C\x97\x38\x9D"
+                         "\x59\x0E\x66\x59\x5E\xD8\x8B\xCE"
+                         "\x70\xE0\xC3\x42\xB0\x8C\x0F\xBA"
+                         "\xB2\x0D\x81\xB6\xBE\x61\x1C\x2D"
+                         "\x7E\xEA\x91\x25\xAC\xEC\xF8\x28"
+                         "\x80\x1D\xF0\x30\xBA\x62\x77\x7D"
+                         "\xDB\x15\x69\xDF\xFA\x2A\x81\x64"
+                         "\x95\x5B\xA4\x7F\x3E\x4F\xE3\x30"
+                         "\xB0\x5C\xC2\x05\xF8\xF0\x29\xE7"
+                         "\x0A\xA0\x66\xB2\x5D\x0F\x39\x2B"
+                         "\xB4\xB3\x00\xA9\xD0\xAB\x63\x61"
+                         "\x5E\xDB\xFC\x11\x74\x25\x96\x65"
+                         "\xE8\xE2\x34\x57\x77\x15\x5E\x70"
+                         "\xFF\x10\x90\xC3\x64\xF0\x11\x0A"
+                         "\x63\x3A\xD3\x55\x92\x15\x4B\x0C"
+                         "\xC7\x08\x89\x17\x3B\x99\xAD\x63"
+                         "\xE7\x06\xDF\x52\xBC\x15\x64\x45"
+                         "\x9D\x7A\xFB\x69\xBC\x2D\x6E\xA9"
+                         "\x35\xD9\xD8\xF5\x0C\xC4\xA2\x23"
+                         "\x9C\x18\x8B\xA8\x8C\xFE\xF8\x0E"
+                         "\xBD\xAB\x60\x1A\x51\x17\x54\x27"
+                         "\xB6\xE8\xBE\x0F\xA9\xA5\x82\x19"
+                         "\x2F\x6F\x20\xA7\x47\xED\x74\x6C"
+                         "\x4E\xC1\xF8\x8C\x14\xF3\xBB\x1F"
+                         "\xED\x4D\x8F\x7C\x37\xEF\x19\xA1"
+                         "\x07\x16\xDE\x76\xCC\x5E\x94\x02"
+                         "\xFB\xBF\xE4\x81\x50\xCE\xFC\x0F"
+                         "\x9E\xCF\x3D\xF6\x67\x00\xBF\xA7"
+                         "\x6E\x21\x58\x36\x06\xDE\xB3\xD4"
+                         "\xA2\xFA\xD8\x4E\xE0\xB9\x7F\x23"
+                         "\x51\x21\x2B\x32\x68\xAA\xF8\xA8"
+                         "\x93\x08\xB5\x6D\xE6\x43\x2C\xB7"
+                         "\x31\xB2\x0F\xD0\xA2\x51\xC0\x25"
+                         "\x30\xC7\x10\x3F\x97\x27\x01\x8E"
+                         "\xFA\xD8\x4F\x78\xD8\x2E\x1D\xEB"
+                         "\xA1\x37\x52\x0F\x7B\x5E\x87\xA8"
+                         "\x22\xE2\xE6\x92\xA7\x5F\x11\x32"
+                         "\xCC\x93\x34\xFC\xD1\x7E\xAE\x54"
+                         "\xBC\x6A\x1B\x91\xD1\x2E\x21\xEC"
+                         "\x5D\xF1\xC4\xF1\x55\x20\xBF\xE5"
+                         "\x96\x3D\x69\x91\x20\x4E\xF2\x61"
+                         "\xDA\x77\xFE\xEE\xC3\x74\x57\x2A"
+                         "\x78\x39\xB0\xE0\xCF\x12\x56\xD6"
+                         "\x05\xDC\xF9\x19\x66\x44\x1D\xF9"
+                         "\x82\x37\xD4\xC2\x60\xB6\x31\xDF"
+                         "\x0C\xAF\xBC\x8B\x55\x9A\xC8\x2D"
+                         "\xAB\xA7\x88\x7B\x41\xE8\x29\xC9"
+                         "\x9B\x8D\xA7\x00\x86\x25\xB6\x14"
+                         "\xF5\x13\x73\xD7\x4B\x6B\x83\xF3"
+                         "\xAF\x96\x00\xE4\xB7\x3C\x65\xA6"
+                         "\x15\xB7\x94\x7D\x4E\x70\x4C\x75"
+                         "\xF3\xB4\x02\xA9\x17\x1C\x7A\x0A"
+                         "\xC0\xD5\x33\x11\x56\xDE\xDC\xF5"
+                         "\x8D\xD9\xCD\x3B\x22\x67\x18\xC7"
+                         "\xC4\xF5\x99\x61\xBC\xBB\x5B\x46",
+               .rlen   = 512,
+       },
+};
+
+static struct cipher_testvec cast6_lrw_dec_tv_template[] = {
+       { /* Generated from TF test vectors */
+               .key    = "\xf8\xd4\x76\xff\xd6\x46\xee\x6c"
+                         "\x23\x84\xcb\x1c\x77\xd6\x19\x5d"
+                         "\xfe\xf1\xa9\xf3\x7b\xbc\x8d\x21"
+                         "\xa7\x9c\x21\xf8\xcb\x90\x02\x89"
+                         "\xa8\x45\x34\x8e\xc8\xc5\xb5\xf1"
+                         "\x26\xf5\x0e\x76\xfe\xfd\x1b\x1e",
+               .klen   = 48,
+               .iv     = "\x00\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x01",
+               .input  = "\x55\x25\x09\x8B\xB5\xD5\xF8\xBF"
+                         "\x37\x4A\xFE\x3C\x47\xD8\xE6\xEB"
+                         "\xCA\xA4\x9B\xB0\xAB\x6D\x64\xCA"
+                         "\x58\xB6\x73\xF0\xD7\x52\x34\xEF"
+                         "\xFB\x3E\x96\x81\xB7\x71\x34\xA4"
+                         "\x55\x20\xBE\x39\x5A\x2B\xF9\xD1"
+                         "\x65\x0B\xDA\xD3\x7E\xB3\xA6\xF7"
+                         "\x2E\x0B\x5A\x52\xDB\x39\x8C\x9B"
+                         "\x61\x17\x5F\xAF\xB6\x5A\xC8\x08"
+                         "\xA7\xB7\x2A\x11\x7C\x97\x38\x9D"
+                         "\x59\x0E\x66\x59\x5E\xD8\x8B\xCE"
+                         "\x70\xE0\xC3\x42\xB0\x8C\x0F\xBA"
+                         "\xB2\x0D\x81\xB6\xBE\x61\x1C\x2D"
+                         "\x7E\xEA\x91\x25\xAC\xEC\xF8\x28"
+                         "\x80\x1D\xF0\x30\xBA\x62\x77\x7D"
+                         "\xDB\x15\x69\xDF\xFA\x2A\x81\x64"
+                         "\x95\x5B\xA4\x7F\x3E\x4F\xE3\x30"
+                         "\xB0\x5C\xC2\x05\xF8\xF0\x29\xE7"
+                         "\x0A\xA0\x66\xB2\x5D\x0F\x39\x2B"
+                         "\xB4\xB3\x00\xA9\xD0\xAB\x63\x61"
+                         "\x5E\xDB\xFC\x11\x74\x25\x96\x65"
+                         "\xE8\xE2\x34\x57\x77\x15\x5E\x70"
+                         "\xFF\x10\x90\xC3\x64\xF0\x11\x0A"
+                         "\x63\x3A\xD3\x55\x92\x15\x4B\x0C"
+                         "\xC7\x08\x89\x17\x3B\x99\xAD\x63"
+                         "\xE7\x06\xDF\x52\xBC\x15\x64\x45"
+                         "\x9D\x7A\xFB\x69\xBC\x2D\x6E\xA9"
+                         "\x35\xD9\xD8\xF5\x0C\xC4\xA2\x23"
+                         "\x9C\x18\x8B\xA8\x8C\xFE\xF8\x0E"
+                         "\xBD\xAB\x60\x1A\x51\x17\x54\x27"
+                         "\xB6\xE8\xBE\x0F\xA9\xA5\x82\x19"
+                         "\x2F\x6F\x20\xA7\x47\xED\x74\x6C"
+                         "\x4E\xC1\xF8\x8C\x14\xF3\xBB\x1F"
+                         "\xED\x4D\x8F\x7C\x37\xEF\x19\xA1"
+                         "\x07\x16\xDE\x76\xCC\x5E\x94\x02"
+                         "\xFB\xBF\xE4\x81\x50\xCE\xFC\x0F"
+                         "\x9E\xCF\x3D\xF6\x67\x00\xBF\xA7"
+                         "\x6E\x21\x58\x36\x06\xDE\xB3\xD4"
+                         "\xA2\xFA\xD8\x4E\xE0\xB9\x7F\x23"
+                         "\x51\x21\x2B\x32\x68\xAA\xF8\xA8"
+                         "\x93\x08\xB5\x6D\xE6\x43\x2C\xB7"
+                         "\x31\xB2\x0F\xD0\xA2\x51\xC0\x25"
+                         "\x30\xC7\x10\x3F\x97\x27\x01\x8E"
+                         "\xFA\xD8\x4F\x78\xD8\x2E\x1D\xEB"
+                         "\xA1\x37\x52\x0F\x7B\x5E\x87\xA8"
+                         "\x22\xE2\xE6\x92\xA7\x5F\x11\x32"
+                         "\xCC\x93\x34\xFC\xD1\x7E\xAE\x54"
+                         "\xBC\x6A\x1B\x91\xD1\x2E\x21\xEC"
+                         "\x5D\xF1\xC4\xF1\x55\x20\xBF\xE5"
+                         "\x96\x3D\x69\x91\x20\x4E\xF2\x61"
+                         "\xDA\x77\xFE\xEE\xC3\x74\x57\x2A"
+                         "\x78\x39\xB0\xE0\xCF\x12\x56\xD6"
+                         "\x05\xDC\xF9\x19\x66\x44\x1D\xF9"
+                         "\x82\x37\xD4\xC2\x60\xB6\x31\xDF"
+                         "\x0C\xAF\xBC\x8B\x55\x9A\xC8\x2D"
+                         "\xAB\xA7\x88\x7B\x41\xE8\x29\xC9"
+                         "\x9B\x8D\xA7\x00\x86\x25\xB6\x14"
+                         "\xF5\x13\x73\xD7\x4B\x6B\x83\xF3"
+                         "\xAF\x96\x00\xE4\xB7\x3C\x65\xA6"
+                         "\x15\xB7\x94\x7D\x4E\x70\x4C\x75"
+                         "\xF3\xB4\x02\xA9\x17\x1C\x7A\x0A"
+                         "\xC0\xD5\x33\x11\x56\xDE\xDC\xF5"
+                         "\x8D\xD9\xCD\x3B\x22\x67\x18\xC7"
+                         "\xC4\xF5\x99\x61\xBC\xBB\x5B\x46",
+               .ilen   = 512,
+               .result = "\x05\x11\xb7\x18\xab\xc6\x2d\xac"
+                         "\x70\x5d\xf6\x22\x94\xcd\xe5\x6c"
+                         "\x17\x6b\xf6\x1c\xf0\xf3\x6e\xf8"
+                         "\x50\x38\x1f\x71\x49\xb6\x57\xd6"
+                         "\x8f\xcb\x8d\x6b\xe3\xa6\x29\x90"
+                         "\xfe\x2a\x62\x82\xae\x6d\x8b\xf6"
+                         "\xad\x1e\x9e\x20\x5f\x38\xbe\x04"
+                         "\xda\x10\x8e\xed\xa2\xa4\x87\xab"
+                         "\xda\x6b\xb4\x0c\x75\xba\xd3\x7c"
+                         "\xc9\xac\x42\x31\x95\x7c\xc9\x04"
+                         "\xeb\xd5\x6e\x32\x69\x8a\xdb\xa6"
+                         "\x15\xd7\x3f\x4f\x2f\x66\x69\x03"
+                         "\x9c\x1f\x54\x0f\xde\x1f\xf3\x65"
+                         "\x4c\x96\x12\xed\x7c\x92\x03\x01"
+                         "\x6f\xbc\x35\x93\xac\xf1\x27\xf1"
+                         "\xb4\x96\x82\x5a\x5f\xb0\xa0\x50"
+                         "\x89\xa4\x8e\x66\x44\x85\xcc\xfd"
+                         "\x33\x14\x70\xe3\x96\xb2\xc3\xd3"
+                         "\xbb\x54\x5a\x1a\xf9\x74\xa2\xc5"
+                         "\x2d\x64\x75\xdd\xb4\x54\xe6\x74"
+                         "\x8c\xd3\x9d\x9e\x86\xab\x51\x53"
+                         "\xb7\x93\x3e\x6f\xd0\x4e\x2c\x40"
+                         "\xf6\xa8\x2e\x3e\x9d\xf4\x66\xa5"
+                         "\x76\x12\x73\x44\x1a\x56\xd7\x72"
+                         "\x88\xcd\x21\x8c\x4c\x0f\xfe\xda"
+                         "\x95\xe0\x3a\xa6\xa5\x84\x46\xcd"
+                         "\xd5\x3e\x9d\x3a\xe2\x67\xe6\x60"
+                         "\x1a\xe2\x70\x85\x58\xc2\x1b\x09"
+                         "\xe1\xd7\x2c\xca\xad\xa8\x8f\xf9"
+                         "\xac\xb3\x0e\xdb\xca\x2e\xe2\xb8"
+                         "\x51\x71\xd9\x3c\x6c\xf1\x56\xf8"
+                         "\xea\x9c\xf1\xfb\x0c\xe6\xb7\x10"
+                         "\x1c\xf8\xa9\x7c\xe8\x53\x35\xc1"
+                         "\x90\x3e\x76\x4a\x74\xa4\x21\x2c"
+                         "\xf6\x2c\x4e\x0f\x94\x3a\x88\x2e"
+                         "\x41\x09\x6a\x33\x7d\xf6\xdd\x3f"
+                         "\x8d\x23\x31\x74\x84\xeb\x88\x6e"
+                         "\xcc\xb9\xbc\x22\x83\x19\x07\x22"
+                         "\xa5\x2d\xdf\xa5\xf3\x80\x85\x78"
+                         "\x84\x39\x6a\x6d\x6a\x99\x4f\xa5"
+                         "\x15\xfe\x46\xb0\xe4\x6c\xa5\x41"
+                         "\x3c\xce\x8f\x42\x60\x71\xa7\x75"
+                         "\x08\x40\x65\x8a\x82\xbf\xf5\x43"
+                         "\x71\x96\xa9\x4d\x44\x8a\x20\xbe"
+                         "\xfa\x4d\xbb\xc0\x7d\x31\x96\x65"
+                         "\xe7\x75\xe5\x3e\xfd\x92\x3b\xc9"
+                         "\x55\xbb\x16\x7e\xf7\xc2\x8c\xa4"
+                         "\x40\x1d\xe5\xef\x0e\xdf\xe4\x9a"
+                         "\x62\x73\x65\xfd\x46\x63\x25\x3d"
+                         "\x2b\xaf\xe5\x64\xfe\xa5\x5c\xcf"
+                         "\x24\xf3\xb4\xac\x64\xba\xdf\x4b"
+                         "\xc6\x96\x7d\x81\x2d\x8d\x97\xf7"
+                         "\xc5\x68\x77\x84\x32\x2b\xcc\x85"
+                         "\x74\x96\xf0\x12\x77\x61\xb9\xeb"
+                         "\x71\xaa\x82\xcb\x1c\xdb\x89\xc8"
+                         "\xc6\xb5\xe3\x5c\x7d\x39\x07\x24"
+                         "\xda\x39\x87\x45\xc0\x2b\xbb\x01"
+                         "\xac\xbc\x2a\x5c\x7f\xfc\xe8\xce"
+                         "\x6d\x9c\x6f\xed\xd3\xc1\xa1\xd6"
+                         "\xc5\x55\xa9\x66\x2f\xe1\xc8\x32"
+                         "\xa6\x5d\xa4\x3a\x98\x73\xe8\x45"
+                         "\xa4\xc7\xa8\xb4\xf6\x13\x03\xf6"
+                         "\xe9\x2e\xc4\x29\x0f\x84\xdb\xc4"
+                         "\x21\xc4\xc2\x75\x67\x89\x37\x0a",
+               .rlen   = 512,
+       },
+};
+
+static struct cipher_testvec cast6_xts_enc_tv_template[] = {
+       { /* Generated from TF test vectors */
+               .key    = "\x27\x18\x28\x18\x28\x45\x90\x45"
+                         "\x23\x53\x60\x28\x74\x71\x35\x26"
+                         "\x62\x49\x77\x57\x24\x70\x93\x69"
+                         "\x99\x59\x57\x49\x66\x96\x76\x27"
+                         "\x31\x41\x59\x26\x53\x58\x97\x93"
+                         "\x23\x84\x62\x64\x33\x83\x27\x95"
+                         "\x02\x88\x41\x97\x16\x93\x99\x37"
+                         "\x51\x05\x82\x09\x74\x94\x45\x92",
+               .klen   = 64,
+               .iv     = "\xff\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+                         "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+               .ilen   = 512,
+               .result = "\xDE\x6F\x22\xA5\xE8\x39\xE8\x78"
+                         "\x88\x5A\x4F\x8D\x82\x76\x52\x6D"
+                         "\xB2\x41\x16\xF4\x2B\xA6\xEB\xF6"
+                         "\xE2\xC5\x62\x8D\x61\xA1\x01\xED"
+                         "\xD9\x38\x01\xC1\x43\x63\x4E\x88"
+                         "\xC9\x4B\x5A\x88\x80\xB7\x5C\x71"
+                         "\x47\xEE\x11\xD8\xB7\x2D\x5D\x13"
+                         "\x1A\xB1\x68\x5B\x61\xA7\xA9\x81"
+                         "\x8B\x83\xA1\x6A\xAA\x36\xD6\xB6"
+                         "\x60\x54\x09\x32\xFE\x6A\x76\x2E"
+                         "\x28\xFF\xD5\xD6\xDD\x1D\x45\x7D"
+                         "\xF0\x8B\xF3\x32\x4E\x6C\x12\xCB"
+                         "\xB8\x25\x70\xF8\x40\xBC\x90\x1B"
+                         "\x11\xC3\x59\xAF\xF0\x2F\x92\xDD"
+                         "\xD3\x3B\xCF\x60\xA1\x78\x94\x57"
+                         "\xAF\x76\xC1\x67\xA6\x3C\xCD\x98"
+                         "\xB1\xF7\x27\xB9\xA3\xBD\x10\xEA"
+                         "\xCD\x8B\xC2\xF2\x14\xF2\xB2\x67"
+                         "\x05\xDD\x1D\x58\x6E\x2F\x95\x08"
+                         "\x3A\xF8\x78\x76\x82\x56\xA7\xEC"
+                         "\x51\x4B\x85\x77\xC2\x4C\x4A\x34"
+                         "\x71\x38\x17\x91\x44\xE8\xFC\x65"
+                         "\x99\x0D\x52\x91\xEE\xF8\xEF\x27"
+                         "\x2A\x9E\x6E\x78\xC4\x26\x87\xF4"
+                         "\x8A\xF0\x2D\x04\xE8\x14\x92\x5D"
+                         "\x59\x22\x9B\x29\x5C\x18\xF0\xC3"
+                         "\x47\xF3\x76\xD8\xE4\xF3\x1B\xD1"
+                         "\x70\xA3\x0D\xB5\x70\x02\x1D\xA3"
+                         "\x91\x3B\x49\x73\x18\xAB\xD4\xC9"
+                         "\xC3\x1E\xEF\x1F\xFE\xD5\x59\x8A"
+                         "\xD7\xF6\xC9\x71\x67\x79\xD7\x0E"
+                         "\xBE\x1F\x8E\xEC\x55\x7E\x4F\x24"
+                         "\xE6\x87\xEA\xFE\x96\x25\x67\x8E"
+                         "\x93\x03\xFA\xFF\xCE\xAF\xB2\x3C"
+                         "\x6F\xEB\x57\xFB\xD3\x28\x87\xA9"
+                         "\xCE\xC2\xF5\x9C\xC6\x67\xB5\x97"
+                         "\x49\xF7\x04\xCB\xEF\x84\x98\x33"
+                         "\xAF\x38\xD3\x04\x1C\x24\x71\x38"
+                         "\xC7\x71\xDD\x43\x0D\x12\x4A\x18"
+                         "\xBA\xC4\xAF\xBA\xB2\x5B\xEB\x95"
+                         "\x02\x43\x5D\xCE\x19\xCC\xCD\x66"
+                         "\x91\x0B\x8C\x7F\x51\xC4\xBF\x3C"
+                         "\x8B\xF1\xCC\xAA\x29\xD7\x87\xCB"
+                         "\x3E\xC5\xF3\xC9\x75\xE8\xA3\x5B"
+                         "\x30\x45\xA9\xB7\xAF\x80\x64\x6F"
+                         "\x75\x4A\xA7\xC0\x6D\x19\x6B\xDE"
+                         "\x17\xDE\x6D\xEA\x87\x9F\x95\xAE"
+                         "\xF5\x3C\xEE\x54\xB8\x27\x84\xF8"
+                         "\x97\xA3\xE1\x6F\x38\x24\x34\x88"
+                         "\xCE\xBD\x32\x52\xE0\x00\x6C\x94"
+                         "\xC9\xD7\x5D\x37\x81\x33\x2E\x7F"
+                         "\x4F\x7E\x2E\x0D\x94\xBD\xEA\x59"
+                         "\x34\x39\xA8\x35\x12\xB7\xBC\xAC"
+                         "\xEA\x52\x9C\x78\x02\x6D\x92\x36"
+                         "\xFB\x59\x2B\xA4\xEA\x7B\x1B\x83"
+                         "\xE1\x4D\x5E\x2A\x7E\x92\xB1\x64"
+                         "\xDE\xE0\x27\x4B\x0A\x6F\x4C\xE3"
+                         "\xB0\xEB\x31\xE4\x69\x95\xAB\x35"
+                         "\x8B\x2C\xF5\x6B\x7F\xF1\xA2\x82"
+                         "\xF8\xD9\x47\x82\xA9\x82\x03\x91"
+                         "\x69\x1F\xBE\x4C\xE7\xC7\x34\x2F"
+                         "\x45\x72\x80\x17\x81\xBD\x9D\x62"
+                         "\xA1\xAC\xE8\xCF\xC6\x74\xCF\xDC"
+                         "\x22\x60\x4E\xE8\xA4\x5D\x85\xB9",
+               .rlen   = 512,
+       },
+};
+
+static struct cipher_testvec cast6_xts_dec_tv_template[] = {
+       { /* Generated from TF test vectors */
+               .key    = "\x27\x18\x28\x18\x28\x45\x90\x45"
+                         "\x23\x53\x60\x28\x74\x71\x35\x26"
+                         "\x62\x49\x77\x57\x24\x70\x93\x69"
+                         "\x99\x59\x57\x49\x66\x96\x76\x27"
+                         "\x31\x41\x59\x26\x53\x58\x97\x93"
+                         "\x23\x84\x62\x64\x33\x83\x27\x95"
+                         "\x02\x88\x41\x97\x16\x93\x99\x37"
+                         "\x51\x05\x82\x09\x74\x94\x45\x92",
+               .klen   = 64,
+               .iv     = "\xff\x00\x00\x00\x00\x00\x00\x00"
+                         "\x00\x00\x00\x00\x00\x00\x00\x00",
+               .input  = "\xDE\x6F\x22\xA5\xE8\x39\xE8\x78"
+                         "\x88\x5A\x4F\x8D\x82\x76\x52\x6D"
+                         "\xB2\x41\x16\xF4\x2B\xA6\xEB\xF6"
+                         "\xE2\xC5\x62\x8D\x61\xA1\x01\xED"
+                         "\xD9\x38\x01\xC1\x43\x63\x4E\x88"
+                         "\xC9\x4B\x5A\x88\x80\xB7\x5C\x71"
+                         "\x47\xEE\x11\xD8\xB7\x2D\x5D\x13"
+                         "\x1A\xB1\x68\x5B\x61\xA7\xA9\x81"
+                         "\x8B\x83\xA1\x6A\xAA\x36\xD6\xB6"
+                         "\x60\x54\x09\x32\xFE\x6A\x76\x2E"
+                         "\x28\xFF\xD5\xD6\xDD\x1D\x45\x7D"
+                         "\xF0\x8B\xF3\x32\x4E\x6C\x12\xCB"
+                         "\xB8\x25\x70\xF8\x40\xBC\x90\x1B"
+                         "\x11\xC3\x59\xAF\xF0\x2F\x92\xDD"
+                         "\xD3\x3B\xCF\x60\xA1\x78\x94\x57"
+                         "\xAF\x76\xC1\x67\xA6\x3C\xCD\x98"
+                         "\xB1\xF7\x27\xB9\xA3\xBD\x10\xEA"
+                         "\xCD\x8B\xC2\xF2\x14\xF2\xB2\x67"
+                         "\x05\xDD\x1D\x58\x6E\x2F\x95\x08"
+                         "\x3A\xF8\x78\x76\x82\x56\xA7\xEC"
+                         "\x51\x4B\x85\x77\xC2\x4C\x4A\x34"
+                         "\x71\x38\x17\x91\x44\xE8\xFC\x65"
+                         "\x99\x0D\x52\x91\xEE\xF8\xEF\x27"
+                         "\x2A\x9E\x6E\x78\xC4\x26\x87\xF4"
+                         "\x8A\xF0\x2D\x04\xE8\x14\x92\x5D"
+                         "\x59\x22\x9B\x29\x5C\x18\xF0\xC3"
+                         "\x47\xF3\x76\xD8\xE4\xF3\x1B\xD1"
+                         "\x70\xA3\x0D\xB5\x70\x02\x1D\xA3"
+                         "\x91\x3B\x49\x73\x18\xAB\xD4\xC9"
+                         "\xC3\x1E\xEF\x1F\xFE\xD5\x59\x8A"
+                         "\xD7\xF6\xC9\x71\x67\x79\xD7\x0E"
+                         "\xBE\x1F\x8E\xEC\x55\x7E\x4F\x24"
+                         "\xE6\x87\xEA\xFE\x96\x25\x67\x8E"
+                         "\x93\x03\xFA\xFF\xCE\xAF\xB2\x3C"
+                         "\x6F\xEB\x57\xFB\xD3\x28\x87\xA9"
+                         "\xCE\xC2\xF5\x9C\xC6\x67\xB5\x97"
+                         "\x49\xF7\x04\xCB\xEF\x84\x98\x33"
+                         "\xAF\x38\xD3\x04\x1C\x24\x71\x38"
+                         "\xC7\x71\xDD\x43\x0D\x12\x4A\x18"
+                         "\xBA\xC4\xAF\xBA\xB2\x5B\xEB\x95"
+                         "\x02\x43\x5D\xCE\x19\xCC\xCD\x66"
+                         "\x91\x0B\x8C\x7F\x51\xC4\xBF\x3C"
+                         "\x8B\xF1\xCC\xAA\x29\xD7\x87\xCB"
+                         "\x3E\xC5\xF3\xC9\x75\xE8\xA3\x5B"
+                         "\x30\x45\xA9\xB7\xAF\x80\x64\x6F"
+                         "\x75\x4A\xA7\xC0\x6D\x19\x6B\xDE"
+                         "\x17\xDE\x6D\xEA\x87\x9F\x95\xAE"
+                         "\xF5\x3C\xEE\x54\xB8\x27\x84\xF8"
+                         "\x97\xA3\xE1\x6F\x38\x24\x34\x88"
+                         "\xCE\xBD\x32\x52\xE0\x00\x6C\x94"
+                         "\xC9\xD7\x5D\x37\x81\x33\x2E\x7F"
+                         "\x4F\x7E\x2E\x0D\x94\xBD\xEA\x59"
+                         "\x34\x39\xA8\x35\x12\xB7\xBC\xAC"
+                         "\xEA\x52\x9C\x78\x02\x6D\x92\x36"
+                         "\xFB\x59\x2B\xA4\xEA\x7B\x1B\x83"
+                         "\xE1\x4D\x5E\x2A\x7E\x92\xB1\x64"
+                         "\xDE\xE0\x27\x4B\x0A\x6F\x4C\xE3"
+                         "\xB0\xEB\x31\xE4\x69\x95\xAB\x35"
+                         "\x8B\x2C\xF5\x6B\x7F\xF1\xA2\x82"
+                         "\xF8\xD9\x47\x82\xA9\x82\x03\x91"
+                         "\x69\x1F\xBE\x4C\xE7\xC7\x34\x2F"
+                         "\x45\x72\x80\x17\x81\xBD\x9D\x62"
+                         "\xA1\xAC\xE8\xCF\xC6\x74\xCF\xDC"
+                         "\x22\x60\x4E\xE8\xA4\x5D\x85\xB9",
+               .ilen   = 512,
+               .result = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
+                         "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+                         "\x20\x21\x22\x23\x24\x25\x26\x27"
+                         "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+                         "\x30\x31\x32\x33\x34\x35\x36\x37"
+                         "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+                         "\x40\x41\x42\x43\x44\x45\x46\x47"
+                         "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+                         "\x50\x51\x52\x53\x54\x55\x56\x57"
+                         "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+                         "\x60\x61\x62\x63\x64\x65\x66\x67"
+                         "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+                         "\x70\x71\x72\x73\x74\x75\x76\x77"
+                         "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+                         "\x80\x81\x82\x83\x84\x85\x86\x87"
+                         "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+                         "\x90\x91\x92\x93\x94\x95\x96\x97"
+                         "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+                         "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7"
+                         "\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+                         "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7"
+                         "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+                         "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7"
+                         "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+                         "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7"
+                         "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+                         "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7"
+                         "\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+                         "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7"
+                         "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+               .rlen   = 512,
+       },
+};
+
+
+/*
+ * AES test vectors.
+ */
+#define AES_ENC_TEST_VECTORS 3
+#define AES_DEC_TEST_VECTORS 3
+#define AES_CBC_ENC_TEST_VECTORS 4
+#define AES_CBC_DEC_TEST_VECTORS 4
+#define HMAC_SHA1_AES_CBC_ENC_TEST_VECTORS 7
+#define HMAC_SHA256_AES_CBC_ENC_TEST_VECTORS 7
+#define HMAC_SHA512_AES_CBC_ENC_TEST_VECTORS 7
+#define AES_LRW_ENC_TEST_VECTORS 8
+#define AES_LRW_DEC_TEST_VECTORS 8
+#define AES_XTS_ENC_TEST_VECTORS 5
+#define AES_XTS_DEC_TEST_VECTORS 5
+#define AES_CTR_ENC_TEST_VECTORS 3
+#define AES_CTR_DEC_TEST_VECTORS 3
+#define AES_OFB_ENC_TEST_VECTORS 1
+#define AES_OFB_DEC_TEST_VECTORS 1
+#define AES_CTR_3686_ENC_TEST_VECTORS 7
+#define AES_CTR_3686_DEC_TEST_VECTORS 6
+#define AES_GCM_ENC_TEST_VECTORS 9
+#define AES_GCM_DEC_TEST_VECTORS 8
+#define AES_GCM_4106_ENC_TEST_VECTORS 7
+#define AES_GCM_4106_DEC_TEST_VECTORS 7
+#define AES_CCM_ENC_TEST_VECTORS 7
+#define AES_CCM_DEC_TEST_VECTORS 7
+#define AES_CCM_4309_ENC_TEST_VECTORS 7
+#define AES_CCM_4309_DEC_TEST_VECTORS 10
+
+static struct cipher_testvec aes_enc_tv_template[] = {
+       { /* From FIPS-197 */
+               .key    = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+               .klen   = 16,
+               .input  = "\x00\x11\x22\x33\x44\x55\x66\x77"
+                         "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
+               .ilen   = 16,
+               .result = "\x69\xc4\xe0\xd8\x6a\x7b\x04\x30"
+                         "\xd8\xcd\xb7\x80\x70\xb4\xc5\x5a",
+               .rlen   = 16,
+       }, {
+               .key    = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17",
+               .klen   = 24,
+               .input  = "\x00\x11\x22\x33\x44\x55\x66\x77"
+                         "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
+               .ilen   = 16,
+               .result = "\xdd\xa9\x7c\xa4\x86\x4c\xdf\xe0"
+                         "\x6e\xaf\x70\xa0\xec\x0d\x71\x91",
+               .rlen   = 16,
+       }, {
+               .key    = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+               .klen   = 32,
+               .input  = "\x00\x11\x22\x33\x44\x55\x66\x77"
+                         "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
+               .ilen   = 16,
+               .result = "\x8e\xa2\xb7\xca\x51\x67\x45\xbf"
+                         "\xea\xfc\x49\x90\x4b\x49\x60\x89",
+               .rlen   = 16,
+       },
+};
+
+static struct cipher_testvec aes_dec_tv_template[] = {
+       { /* From FIPS-197 */
+               .key    = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
+               .klen   = 16,
+               .input  = "\x69\xc4\xe0\xd8\x6a\x7b\x04\x30"
+                         "\xd8\xcd\xb7\x80\x70\xb4\xc5\x5a",
+               .ilen   = 16,
+               .result = "\x00\x11\x22\x33\x44\x55\x66\x77"
+                         "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
+               .rlen   = 16,
+       }, {
+               .key    = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17",
+               .klen   = 24,
+               .input  = "\xdd\xa9\x7c\xa4\x86\x4c\xdf\xe0"
+                         "\x6e\xaf\x70\xa0\xec\x0d\x71\x91",
+               .ilen   = 16,
+               .result = "\x00\x11\x22\x33\x44\x55\x66\x77"
+                         "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
+               .rlen   = 16,
+       }, {
+               .key    = "\x00\x01\x02\x03\x04\x05\x06\x07"
+                         "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+                         "\x10\x11\x12\x13\x14\x15\x16\x17"
+                         "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+               .klen   = 32,
+               .input  = "\x8e\xa2\xb7\xca\x51\x67\x45\xbf"
+                         "\xea\xfc\x49\x90\x4b\x49\x60\x89",
+               .ilen   = 16,
+               .result = "\x00\x11\x22\x33\x44\x55\x66\x77"
+                         "\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
+               .rlen   = 16,
+       },
+};
+
+static struct cipher_testvec aes_cbc_enc_tv_template[] = {
+       { /* From RFC 3602 */
+               .key    = "\x06\xa9\x21\x40\x36\xb8\xa1\x5b"
+                         "\x51\x2e\x03\xd5\x34\x12\x00\x06",
+               .klen   = 16,
+               .iv     = "\x3d\xaf\xba\x42\x9d\x9e\xb4\x30"
+                         "\xb4\x22\xda\x80\x2c\x9f\xac\x41",
+               .input  = "Single block msg",
+               .ilen   = 16,
                .result = "\xe3\x53\x77\x9c\x10\x79\xae\xb8"
                          "\x27\x08\x94\x2d\xbe\x77\x18\x1a",
                .rlen   = 16,
@@ -12124,61 +13532,867 @@ static struct cprng_testvec ansi_cprng_aes_tv_template[] = {
        },
 };
 
-/* Cast5 test vectors from RFC 2144 */
-#define CAST5_ENC_TEST_VECTORS 3
-#define CAST5_DEC_TEST_VECTORS 3
+/* Cast5 test vectors from RFC 2144 */
+#define CAST5_ENC_TEST_VECTORS         4
+#define CAST5_DEC_TEST_VECTORS         4
+#define CAST5_CBC_ENC_TEST_VECTORS     1
+#define CAST5_CBC_DEC_TEST_VECTORS     1
+#define CAST5_CTR_ENC_TEST_VECTORS     1
+#define CAST5_CTR_DEC_TEST_VECTORS     1
+
+static struct cipher_testvec cast5_enc_tv_template[] = {
+       {
+               .key    = "\x01\x23\x45\x67\x12\x34\x56\x78"
+                         "\x23\x45\x67\x89\x34\x56\x78\x9a",
+               .klen   = 16,
+               .input  = "\x01\x23\x45\x67\x89\xab\xcd\xef",
+               .ilen   = 8,
+               .result = "\x23\x8b\x4f\xe5\x84\x7e\x44\xb2",
+               .rlen   = 8,
+       }, {
+               .key    = "\x01\x23\x45\x67\x12\x34\x56\x78"
+                         "\x23\x45",
+               .klen   = 10,
+               .input  = "\x01\x23\x45\x67\x89\xab\xcd\xef",
+               .ilen   = 8,
+               .result = "\xeb\x6a\x71\x1a\x2c\x02\x27\x1b",
+               .rlen   = 8,
+       }, {
+               .key    = "\x01\x23\x45\x67\x12",
+               .klen   = 5,
+               .input  = "\x01\x23\x45\x67\x89\xab\xcd\xef",
+               .ilen   = 8,
+               .result = "\x7a\xc8\x16\xd1\x6e\x9b\x30\x2e",
+               .rlen   = 8,
+       }, { /* Generated from TF test vectors */
+               .key    = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+                         "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A",
+               .klen   = 16,
+               .iv     = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F",
+               .input  = "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+                         "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+                         "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+                         "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+                         "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+                         "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
+                         "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
+                         "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+                         "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+                         "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+                         "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+                         "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+                         "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+                         "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+                         "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+                         "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+                         "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+                         "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A"
+                         "\xF1\x65\xFC\x93\x07\x9E\x35\xCC"
+                         "\x40\xD7\x6E\x05\x79\x10\xA7\x1B"
+                         "\xB2\x49\xE0\x54\xEB\x82\x19\x8D"
+                         "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF"
+                         "\x96\x0A\xA1\x38\xCF\x43\xDA\x71"
+                         "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3"
+                         "\x57\xEE\x85\x1C\x90\x27\xBE\x32"
+                         "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4"
+                         "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16"
+                         "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88"
+                         "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA"
+                         "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49"
+                         "\xE0\x77\x0E\x82\x19\xB0\x24\xBB"
+                         "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D"
+                         "\xC4\x38\xCF\x66\xFD\x71\x08\x9F"
+                         "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11"
+                         "\x85\x1C\xB3\x27\xBE\x55\xEC\x60"
+                         "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2"
+                         "\x69\x00\x74\x0B\xA2\x16\xAD\x44"
+                         "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6"
+                         "\x2A\xC1\x58\xEF\x63\xFA\x91\x05"
+                         "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77"
+                         "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9"
+                         "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B"
+                         "\xF2\x66\xFD\x94\x08\x9F\x36\xCD"
+                         "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C"
+                         "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E"
+                         "\x25\xBC\x30\xC7\x5E\xF5\x69\x00"
+                         "\x97\x0B\xA2\x39\xD0\x44\xDB\x72"
+                         "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4"
+                         "\x58\xEF\x86\x1D\x91\x28\xBF\x33"
+                         "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5"
+                         "\x3C\xD3\x47\xDE\x75\x0C\x80\x17"
+                         "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89"
+                         "\x20\x94\x2B\xC2\x36\xCD\x64\xFB"
+                         "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A"
+                         "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC"
+                         "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E"
+                         "\xC5\x39\xD0\x67\xFE\x72\x09\xA0"
+                         "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12"
+                         "\x86\x1D\xB4\x28\xBF\x56\xED\x61"
+                         "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3"
+                         "\x6A\x01\x75\x0C\xA3\x17\xAE\x45"
+                         "\xDC\x50\xE7\x7E\x15\x89\x20\xB7",
+               .ilen   = 496,
+               .result = "\x8D\xFC\x81\x9C\xCB\xAA\x5A\x1C"
+                         "\x7E\x95\xCF\x40\xAB\x4D\x6F\xEA"
+                         "\xD3\xD9\xB0\x9A\xB7\xC7\xE0\x2E"
+                         "\xD1\x39\x34\x92\x8F\xFA\x14\xF1"
+                         "\xD5\xD2\x7B\x59\x1F\x35\x28\xC2"
+                         "\x20\xD9\x42\x06\xC9\x0B\x10\x04"
+                         "\xF8\x79\xCD\x32\x86\x75\x4C\xB6"
+                         "\x7B\x1C\x52\xB1\x91\x64\x22\x4B"
+                         "\x13\xC7\xAE\x98\x0E\xB5\xCF\x6F"
+                         "\x3F\xF4\x43\x96\x73\x0D\xA2\x05"
+                         "\xDB\xFD\x28\x90\x2C\x56\xB9\x37"
+                         "\x5B\x69\x0C\xAD\x84\x67\xFF\x15"
+                         "\x4A\xD4\xA7\xD3\xDD\x99\x47\x3A"
+                         "\xED\x34\x35\x78\x6B\x91\xC9\x32"
+                         "\xE1\xBF\xBC\xB4\x04\x85\x6A\x39"
+                         "\xC0\xBA\x51\xD0\x0F\x4E\xD1\xE2"
+                         "\x1C\xFD\x0E\x05\x07\xF4\x10\xED"
+                         "\xA2\x17\xFF\xF5\x64\xC6\x1A\x22"
+                         "\xAD\x78\xE7\xD7\x11\xE9\x99\xB9"
+                         "\xAA\xEC\x6F\xF8\x3B\xBF\xCE\x77"
+                         "\x93\xE8\xAD\x1D\x50\x6C\xAE\xBC"
+                         "\xBA\x5C\x80\xD1\x91\x65\x51\x1B"
+                         "\xE8\x0A\xCD\x99\x96\x71\x3D\xB6"
+                         "\x78\x75\x37\x55\xC1\xF5\x90\x40"
+                         "\x34\xF4\x7E\xC8\xCC\x3A\x5F\x6E"
+                         "\x36\xA1\xA1\xC2\x3A\x72\x42\x8E"
+                         "\x0E\x37\x88\xE8\xCE\x83\xCB\xAD"
+                         "\xE0\x69\x77\x50\xC7\x0C\x99\xCA"
+                         "\x19\x5B\x30\x25\x9A\xEF\x9B\x0C"
+                         "\xEF\x8F\x74\x4C\xCF\x49\x4E\xB9"
+                         "\xC5\xAE\x9E\x2E\x78\x9A\xB9\x48"
+                         "\xD5\x81\xE4\x37\x1D\xBF\x27\xD9"
+                         "\xC5\xD6\x65\x43\x45\x8C\xBB\xB6"
+                         "\x55\xF4\x06\xBB\x49\x53\x8B\x1B"
+                         "\x07\xA9\x96\x69\x5B\xCB\x0F\xBC"
+                         "\x93\x85\x90\x0F\x0A\x68\x40\x2A"
+                         "\x95\xED\x2D\x88\xBF\x71\xD0\xBB"
+                         "\xEC\xB0\x77\x6C\x79\xFC\x3C\x05"
+                         "\x49\x3F\xB8\x24\xEF\x8E\x09\xA2"
+                         "\x1D\xEF\x92\x02\x96\xD4\x7F\xC8"
+                         "\x03\xB2\xCA\xDB\x17\x5C\x52\xCF"
+                         "\xDD\x70\x37\x63\xAA\xA5\x83\x20"
+                         "\x52\x02\xF6\xB9\xE7\x6E\x0A\xB6"
+                         "\x79\x03\xA0\xDA\xA3\x79\x21\xBD"
+                         "\xE3\x37\x3A\xC0\xF7\x2C\x32\xBE"
+                         "\x8B\xE8\xA6\x00\xC7\x32\xD5\x06"
+                         "\xBB\xE3\xAB\x06\x21\x82\xB8\x32"
+                         "\x31\x34\x2A\xA7\x1F\x64\x99\xBF"
+                         "\xFA\xDA\x3D\x75\xF7\x48\xD5\x48"
+                         "\x4B\x52\x7E\xF6\x7C\xAB\x67\x59"
+                         "\xC5\xDC\xA8\xC6\x63\x85\x4A\xDF"
+                         "\xF0\x40\x5F\xCF\xE3\x58\x52\x67"
+                         "\x7A\x24\x32\xC5\xEC\x9E\xA9\x6F"
+                         "\x58\x56\xDD\x94\x1F\x71\x8D\xF4"
+                         "\x6E\xFF\x2C\xA7\xA5\xD8\xBA\xAF"
+                         "\x1D\x8B\xA2\x46\xB5\xC4\x9F\x57"
+                         "\x8D\xD8\xB3\x3C\x02\x0D\xBB\x84"
+                         "\xC7\xBD\xB4\x9A\x6E\xBB\xB1\x37"
+                         "\x95\x79\xC4\xA7\xEA\x1D\xDC\x33"
+                         "\x5D\x0B\x3F\x03\x8F\x30\xF9\xAE"
+                         "\x4F\xFE\x24\x9C\x9A\x02\xE5\x57"
+                         "\xF5\xBC\x25\xD6\x02\x56\x57\x1C",
+               .rlen   = 496,
+       },
+};
+
+static struct cipher_testvec cast5_dec_tv_template[] = {
+       {
+               .key    = "\x01\x23\x45\x67\x12\x34\x56\x78"
+                         "\x23\x45\x67\x89\x34\x56\x78\x9a",
+               .klen   = 16,
+               .input  = "\x23\x8b\x4f\xe5\x84\x7e\x44\xb2",
+               .ilen   = 8,
+               .result = "\x01\x23\x45\x67\x89\xab\xcd\xef",
+               .rlen   = 8,
+       }, {
+               .key    = "\x01\x23\x45\x67\x12\x34\x56\x78"
+                         "\x23\x45",
+               .klen   = 10,
+               .input  = "\xeb\x6a\x71\x1a\x2c\x02\x27\x1b",
+               .ilen   = 8,
+               .result = "\x01\x23\x45\x67\x89\xab\xcd\xef",
+               .rlen   = 8,
+       }, {
+               .key    = "\x01\x23\x45\x67\x12",
+               .klen   = 5,
+               .input  = "\x7a\xc8\x16\xd1\x6e\x9b\x30\x2e",
+               .ilen   = 8,
+               .result = "\x01\x23\x45\x67\x89\xab\xcd\xef",
+               .rlen   = 8,
+       }, { /* Generated from TF test vectors */
+               .key    = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+                         "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A",
+               .klen   = 16,
+               .iv     = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F",
+               .input  = "\x8D\xFC\x81\x9C\xCB\xAA\x5A\x1C"
+                         "\x7E\x95\xCF\x40\xAB\x4D\x6F\xEA"
+                         "\xD3\xD9\xB0\x9A\xB7\xC7\xE0\x2E"
+                         "\xD1\x39\x34\x92\x8F\xFA\x14\xF1"
+                         "\xD5\xD2\x7B\x59\x1F\x35\x28\xC2"
+                         "\x20\xD9\x42\x06\xC9\x0B\x10\x04"
+                         "\xF8\x79\xCD\x32\x86\x75\x4C\xB6"
+                         "\x7B\x1C\x52\xB1\x91\x64\x22\x4B"
+                         "\x13\xC7\xAE\x98\x0E\xB5\xCF\x6F"
+                         "\x3F\xF4\x43\x96\x73\x0D\xA2\x05"
+                         "\xDB\xFD\x28\x90\x2C\x56\xB9\x37"
+                         "\x5B\x69\x0C\xAD\x84\x67\xFF\x15"
+                         "\x4A\xD4\xA7\xD3\xDD\x99\x47\x3A"
+                         "\xED\x34\x35\x78\x6B\x91\xC9\x32"
+                         "\xE1\xBF\xBC\xB4\x04\x85\x6A\x39"
+                         "\xC0\xBA\x51\xD0\x0F\x4E\xD1\xE2"
+                         "\x1C\xFD\x0E\x05\x07\xF4\x10\xED"
+                         "\xA2\x17\xFF\xF5\x64\xC6\x1A\x22"
+                         "\xAD\x78\xE7\xD7\x11\xE9\x99\xB9"
+                         "\xAA\xEC\x6F\xF8\x3B\xBF\xCE\x77"
+                         "\x93\xE8\xAD\x1D\x50\x6C\xAE\xBC"
+                         "\xBA\x5C\x80\xD1\x91\x65\x51\x1B"
+                         "\xE8\x0A\xCD\x99\x96\x71\x3D\xB6"
+                         "\x78\x75\x37\x55\xC1\xF5\x90\x40"
+                         "\x34\xF4\x7E\xC8\xCC\x3A\x5F\x6E"
+                         "\x36\xA1\xA1\xC2\x3A\x72\x42\x8E"
+                         "\x0E\x37\x88\xE8\xCE\x83\xCB\xAD"
+                         "\xE0\x69\x77\x50\xC7\x0C\x99\xCA"
+                         "\x19\x5B\x30\x25\x9A\xEF\x9B\x0C"
+                         "\xEF\x8F\x74\x4C\xCF\x49\x4E\xB9"
+                         "\xC5\xAE\x9E\x2E\x78\x9A\xB9\x48"
+                         "\xD5\x81\xE4\x37\x1D\xBF\x27\xD9"
+                         "\xC5\xD6\x65\x43\x45\x8C\xBB\xB6"
+                         "\x55\xF4\x06\xBB\x49\x53\x8B\x1B"
+                         "\x07\xA9\x96\x69\x5B\xCB\x0F\xBC"
+                         "\x93\x85\x90\x0F\x0A\x68\x40\x2A"
+                         "\x95\xED\x2D\x88\xBF\x71\xD0\xBB"
+                         "\xEC\xB0\x77\x6C\x79\xFC\x3C\x05"
+                         "\x49\x3F\xB8\x24\xEF\x8E\x09\xA2"
+                         "\x1D\xEF\x92\x02\x96\xD4\x7F\xC8"
+                         "\x03\xB2\xCA\xDB\x17\x5C\x52\xCF"
+                         "\xDD\x70\x37\x63\xAA\xA5\x83\x20"
+                         "\x52\x02\xF6\xB9\xE7\x6E\x0A\xB6"
+                         "\x79\x03\xA0\xDA\xA3\x79\x21\xBD"
+                         "\xE3\x37\x3A\xC0\xF7\x2C\x32\xBE"
+                         "\x8B\xE8\xA6\x00\xC7\x32\xD5\x06"
+                         "\xBB\xE3\xAB\x06\x21\x82\xB8\x32"
+                         "\x31\x34\x2A\xA7\x1F\x64\x99\xBF"
+                         "\xFA\xDA\x3D\x75\xF7\x48\xD5\x48"
+                         "\x4B\x52\x7E\xF6\x7C\xAB\x67\x59"
+                         "\xC5\xDC\xA8\xC6\x63\x85\x4A\xDF"
+                         "\xF0\x40\x5F\xCF\xE3\x58\x52\x67"
+                         "\x7A\x24\x32\xC5\xEC\x9E\xA9\x6F"
+                         "\x58\x56\xDD\x94\x1F\x71\x8D\xF4"
+                         "\x6E\xFF\x2C\xA7\xA5\xD8\xBA\xAF"
+                         "\x1D\x8B\xA2\x46\xB5\xC4\x9F\x57"
+                         "\x8D\xD8\xB3\x3C\x02\x0D\xBB\x84"
+                         "\xC7\xBD\xB4\x9A\x6E\xBB\xB1\x37"
+                         "\x95\x79\xC4\xA7\xEA\x1D\xDC\x33"
+                         "\x5D\x0B\x3F\x03\x8F\x30\xF9\xAE"
+                         "\x4F\xFE\x24\x9C\x9A\x02\xE5\x57"
+                         "\xF5\xBC\x25\xD6\x02\x56\x57\x1C",
+               .ilen   = 496,
+               .result = "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+                         "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+                         "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+                         "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+                         "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+                         "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
+                         "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
+                         "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+                         "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+                         "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+                         "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+                         "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+                         "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+                         "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+                         "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+                         "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+                         "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+                         "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A"
+                         "\xF1\x65\xFC\x93\x07\x9E\x35\xCC"
+                         "\x40\xD7\x6E\x05\x79\x10\xA7\x1B"
+                         "\xB2\x49\xE0\x54\xEB\x82\x19\x8D"
+                         "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF"
+                         "\x96\x0A\xA1\x38\xCF\x43\xDA\x71"
+                         "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3"
+                         "\x57\xEE\x85\x1C\x90\x27\xBE\x32"
+                         "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4"
+                         "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16"
+                         "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88"
+                         "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA"
+                         "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49"
+                         "\xE0\x77\x0E\x82\x19\xB0\x24\xBB"
+                         "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D"
+                         "\xC4\x38\xCF\x66\xFD\x71\x08\x9F"
+                         "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11"
+                         "\x85\x1C\xB3\x27\xBE\x55\xEC\x60"
+                         "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2"
+                         "\x69\x00\x74\x0B\xA2\x16\xAD\x44"
+                         "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6"
+                         "\x2A\xC1\x58\xEF\x63\xFA\x91\x05"
+                         "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77"
+                         "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9"
+                         "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B"
+                         "\xF2\x66\xFD\x94\x08\x9F\x36\xCD"
+                         "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C"
+                         "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E"
+                         "\x25\xBC\x30\xC7\x5E\xF5\x69\x00"
+                         "\x97\x0B\xA2\x39\xD0\x44\xDB\x72"
+                         "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4"
+                         "\x58\xEF\x86\x1D\x91\x28\xBF\x33"
+                         "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5"
+                         "\x3C\xD3\x47\xDE\x75\x0C\x80\x17"
+                         "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89"
+                         "\x20\x94\x2B\xC2\x36\xCD\x64\xFB"
+                         "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A"
+                         "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC"
+                         "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E"
+                         "\xC5\x39\xD0\x67\xFE\x72\x09\xA0"
+                         "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12"
+                         "\x86\x1D\xB4\x28\xBF\x56\xED\x61"
+                         "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3"
+                         "\x6A\x01\x75\x0C\xA3\x17\xAE\x45"
+                         "\xDC\x50\xE7\x7E\x15\x89\x20\xB7",
+               .rlen   = 496,
+       },
+};
+
+static struct cipher_testvec cast5_cbc_enc_tv_template[] = {
+       { /* Generated from TF test vectors */
+               .key    = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+                         "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A",
+               .klen   = 16,
+               .iv     = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F",
+               .input  = "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+                         "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+                         "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+                         "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+                         "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+                         "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
+                         "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
+                         "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+                         "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+                         "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+                         "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+                         "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+                         "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+                         "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+                         "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+                         "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+                         "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+                         "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A"
+                         "\xF1\x65\xFC\x93\x07\x9E\x35\xCC"
+                         "\x40\xD7\x6E\x05\x79\x10\xA7\x1B"
+                         "\xB2\x49\xE0\x54\xEB\x82\x19\x8D"
+                         "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF"
+                         "\x96\x0A\xA1\x38\xCF\x43\xDA\x71"
+                         "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3"
+                         "\x57\xEE\x85\x1C\x90\x27\xBE\x32"
+                         "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4"
+                         "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16"
+                         "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88"
+                         "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA"
+                         "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49"
+                         "\xE0\x77\x0E\x82\x19\xB0\x24\xBB"
+                         "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D"
+                         "\xC4\x38\xCF\x66\xFD\x71\x08\x9F"
+                         "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11"
+                         "\x85\x1C\xB3\x27\xBE\x55\xEC\x60"
+                         "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2"
+                         "\x69\x00\x74\x0B\xA2\x16\xAD\x44"
+                         "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6"
+                         "\x2A\xC1\x58\xEF\x63\xFA\x91\x05"
+                         "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77"
+                         "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9"
+                         "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B"
+                         "\xF2\x66\xFD\x94\x08\x9F\x36\xCD"
+                         "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C"
+                         "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E"
+                         "\x25\xBC\x30\xC7\x5E\xF5\x69\x00"
+                         "\x97\x0B\xA2\x39\xD0\x44\xDB\x72"
+                         "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4"
+                         "\x58\xEF\x86\x1D\x91\x28\xBF\x33"
+                         "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5"
+                         "\x3C\xD3\x47\xDE\x75\x0C\x80\x17"
+                         "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89"
+                         "\x20\x94\x2B\xC2\x36\xCD\x64\xFB"
+                         "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A"
+                         "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC"
+                         "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E"
+                         "\xC5\x39\xD0\x67\xFE\x72\x09\xA0"
+                         "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12"
+                         "\x86\x1D\xB4\x28\xBF\x56\xED\x61"
+                         "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3"
+                         "\x6A\x01\x75\x0C\xA3\x17\xAE\x45"
+                         "\xDC\x50\xE7\x7E\x15\x89\x20\xB7",
+               .ilen   = 496,
+               .result = "\x05\x28\xCE\x61\x90\x80\xE1\x78"
+                         "\xB9\x2A\x97\x7C\xB0\x83\xD8\x1A"
+                         "\xDE\x58\x7F\xD7\xFD\x72\xB8\xFB"
+                         "\xDA\xF0\x6E\x77\x14\x47\x82\xBA"
+                         "\x29\x0E\x25\x6E\xB4\x39\xD9\x7F"
+                         "\x05\xA7\xA7\x3A\xC1\x5D\x9E\x39"
+                         "\xA7\xFB\x0D\x05\x00\xF3\x58\x67"
+                         "\x60\xEC\x73\x77\x46\x85\x9B\x6A"
+                         "\x08\x3E\xBE\x59\xFB\xE4\x96\x34"
+                         "\xB4\x05\x49\x1A\x97\x43\xAD\xA0"
+                         "\xA9\x1E\x6E\x74\xF1\x94\xEC\xA8"
+                         "\xB5\x8A\x20\xEA\x89\x6B\x19\xAA"
+                         "\xA7\xF1\x33\x67\x90\x23\x0D\xEE"
+                         "\x81\xD5\x78\x4F\xD3\x63\xEA\x46"
+                         "\xB5\xB2\x6E\xBB\xCA\x76\x06\x10"
+                         "\x96\x2A\x0A\xBA\xF9\x41\x5A\x1D"
+                         "\x36\x7C\x56\x14\x54\x83\xFA\xA1"
+                         "\x27\xDD\xBA\x8A\x90\x29\xD6\xA6"
+                         "\xFA\x48\x3E\x1E\x23\x6E\x98\xA8"
+                         "\xA7\xD9\x67\x92\x5C\x13\xB4\x71"
+                         "\xA8\xAA\x89\x4A\xA4\xB3\x49\x7C"
+                         "\x7D\x7F\xCE\x6F\x29\x2E\x7E\x37"
+                         "\xC8\x52\x60\xD9\xE7\xCA\x60\x98"
+                         "\xED\xCD\xE8\x60\x83\xAD\x34\x4D"
+                         "\x96\x4A\x99\x2B\xB7\x14\x75\x66"
+                         "\x6C\x2C\x1A\xBA\x4B\xBB\x49\x56"
+                         "\xE1\x86\xA2\x0E\xD0\xF0\x07\xD3"
+                         "\x18\x38\x09\x9C\x0E\x8B\x86\x07"
+                         "\x90\x12\x37\x49\x27\x98\x69\x18"
+                         "\xB0\xCC\xFB\xD3\xBD\x04\xA0\x85"
+                         "\x4B\x22\x97\x07\xB6\x97\xE9\x95"
+                         "\x0F\x88\x36\xA9\x44\x00\xC6\xE9"
+                         "\x27\x53\x5C\x5B\x1F\xD3\xE2\xEE"
+                         "\xD0\xCD\x63\x30\xA9\xC0\xDD\x49"
+                         "\xFE\x16\xA4\x07\x0D\xE2\x5D\x97"
+                         "\xDE\x89\xBA\x2E\xF3\xA9\x5E\xBE"
+                         "\x03\x55\x0E\x02\x41\x4A\x45\x06"
+                         "\xBE\xEA\x32\xF2\xDC\x91\x5C\x20"
+                         "\x94\x02\x30\xD2\xFC\x29\xFA\x8E"
+                         "\x34\xA0\x31\xB8\x34\xBA\xAE\x54"
+                         "\xB5\x88\x1F\xDC\x43\xDC\x22\x9F"
+                         "\xDC\xCE\xD3\xFA\xA4\xA8\xBC\x8A"
+                         "\xC7\x5A\x43\x21\xA5\xB1\xDB\xC3"
+                         "\x84\x3B\xB4\x9B\xB5\xA7\xF1\x0A"
+                         "\xB6\x37\x21\x19\x55\xC2\xBD\x99"
+                         "\x49\x24\xBB\x7C\xB3\x8E\xEF\xD2"
+                         "\x3A\xCF\xA0\x31\x28\x0E\x25\xA2"
+                         "\x11\xB4\x18\x17\x1A\x65\x92\x56"
+                         "\xE8\xE0\x52\x9C\x61\x18\x2A\xB1"
+                         "\x1A\x01\x22\x45\x17\x62\x52\x6C"
+                         "\x91\x44\xCF\x98\xC7\xC0\x79\x26"
+                         "\x32\x66\x6F\x23\x7F\x94\x36\x88"
+                         "\x3C\xC9\xD0\xB7\x45\x30\x31\x86"
+                         "\x3D\xC6\xA3\x98\x62\x84\x1A\x8B"
+                         "\x16\x88\xC7\xA3\xE9\x4F\xE0\x86"
+                         "\xA4\x93\xA8\x34\x5A\xCA\xDF\xCA"
+                         "\x46\x38\xD2\xF4\xE0\x2D\x1E\xC9"
+                         "\x7C\xEF\x53\xB7\x60\x72\x41\xBF"
+                         "\x29\x00\x87\x02\xAF\x44\x4C\xB7"
+                         "\x8C\xF5\x3F\x19\xF4\x80\x45\xA7"
+                         "\x15\x5F\xDB\xE9\xB1\x83\xD2\xE6"
+                         "\x1D\x18\x66\x44\x5B\x8F\x14\xEB",
+               .rlen   = 496,
+       },
+};
+
+static struct cipher_testvec cast5_cbc_dec_tv_template[] = {
+       { /* Generated from TF test vectors */
+               .key    = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+                         "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A",
+               .klen   = 16,
+               .iv     = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F",
+               .input  = "\x05\x28\xCE\x61\x90\x80\xE1\x78"
+                         "\xB9\x2A\x97\x7C\xB0\x83\xD8\x1A"
+                         "\xDE\x58\x7F\xD7\xFD\x72\xB8\xFB"
+                         "\xDA\xF0\x6E\x77\x14\x47\x82\xBA"
+                         "\x29\x0E\x25\x6E\xB4\x39\xD9\x7F"
+                         "\x05\xA7\xA7\x3A\xC1\x5D\x9E\x39"
+                         "\xA7\xFB\x0D\x05\x00\xF3\x58\x67"
+                         "\x60\xEC\x73\x77\x46\x85\x9B\x6A"
+                         "\x08\x3E\xBE\x59\xFB\xE4\x96\x34"
+                         "\xB4\x05\x49\x1A\x97\x43\xAD\xA0"
+                         "\xA9\x1E\x6E\x74\xF1\x94\xEC\xA8"
+                         "\xB5\x8A\x20\xEA\x89\x6B\x19\xAA"
+                         "\xA7\xF1\x33\x67\x90\x23\x0D\xEE"
+                         "\x81\xD5\x78\x4F\xD3\x63\xEA\x46"
+                         "\xB5\xB2\x6E\xBB\xCA\x76\x06\x10"
+                         "\x96\x2A\x0A\xBA\xF9\x41\x5A\x1D"
+                         "\x36\x7C\x56\x14\x54\x83\xFA\xA1"
+                         "\x27\xDD\xBA\x8A\x90\x29\xD6\xA6"
+                         "\xFA\x48\x3E\x1E\x23\x6E\x98\xA8"
+                         "\xA7\xD9\x67\x92\x5C\x13\xB4\x71"
+                         "\xA8\xAA\x89\x4A\xA4\xB3\x49\x7C"
+                         "\x7D\x7F\xCE\x6F\x29\x2E\x7E\x37"
+                         "\xC8\x52\x60\xD9\xE7\xCA\x60\x98"
+                         "\xED\xCD\xE8\x60\x83\xAD\x34\x4D"
+                         "\x96\x4A\x99\x2B\xB7\x14\x75\x66"
+                         "\x6C\x2C\x1A\xBA\x4B\xBB\x49\x56"
+                         "\xE1\x86\xA2\x0E\xD0\xF0\x07\xD3"
+                         "\x18\x38\x09\x9C\x0E\x8B\x86\x07"
+                         "\x90\x12\x37\x49\x27\x98\x69\x18"
+                         "\xB0\xCC\xFB\xD3\xBD\x04\xA0\x85"
+                         "\x4B\x22\x97\x07\xB6\x97\xE9\x95"
+                         "\x0F\x88\x36\xA9\x44\x00\xC6\xE9"
+                         "\x27\x53\x5C\x5B\x1F\xD3\xE2\xEE"
+                         "\xD0\xCD\x63\x30\xA9\xC0\xDD\x49"
+                         "\xFE\x16\xA4\x07\x0D\xE2\x5D\x97"
+                         "\xDE\x89\xBA\x2E\xF3\xA9\x5E\xBE"
+                         "\x03\x55\x0E\x02\x41\x4A\x45\x06"
+                         "\xBE\xEA\x32\xF2\xDC\x91\x5C\x20"
+                         "\x94\x02\x30\xD2\xFC\x29\xFA\x8E"
+                         "\x34\xA0\x31\xB8\x34\xBA\xAE\x54"
+                         "\xB5\x88\x1F\xDC\x43\xDC\x22\x9F"
+                         "\xDC\xCE\xD3\xFA\xA4\xA8\xBC\x8A"
+                         "\xC7\x5A\x43\x21\xA5\xB1\xDB\xC3"
+                         "\x84\x3B\xB4\x9B\xB5\xA7\xF1\x0A"
+                         "\xB6\x37\x21\x19\x55\xC2\xBD\x99"
+                         "\x49\x24\xBB\x7C\xB3\x8E\xEF\xD2"
+                         "\x3A\xCF\xA0\x31\x28\x0E\x25\xA2"
+                         "\x11\xB4\x18\x17\x1A\x65\x92\x56"
+                         "\xE8\xE0\x52\x9C\x61\x18\x2A\xB1"
+                         "\x1A\x01\x22\x45\x17\x62\x52\x6C"
+                         "\x91\x44\xCF\x98\xC7\xC0\x79\x26"
+                         "\x32\x66\x6F\x23\x7F\x94\x36\x88"
+                         "\x3C\xC9\xD0\xB7\x45\x30\x31\x86"
+                         "\x3D\xC6\xA3\x98\x62\x84\x1A\x8B"
+                         "\x16\x88\xC7\xA3\xE9\x4F\xE0\x86"
+                         "\xA4\x93\xA8\x34\x5A\xCA\xDF\xCA"
+                         "\x46\x38\xD2\xF4\xE0\x2D\x1E\xC9"
+                         "\x7C\xEF\x53\xB7\x60\x72\x41\xBF"
+                         "\x29\x00\x87\x02\xAF\x44\x4C\xB7"
+                         "\x8C\xF5\x3F\x19\xF4\x80\x45\xA7"
+                         "\x15\x5F\xDB\xE9\xB1\x83\xD2\xE6"
+                         "\x1D\x18\x66\x44\x5B\x8F\x14\xEB",
+               .ilen   = 496,
+               .result = "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+                         "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+                         "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+                         "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+                         "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+                         "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
+                         "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
+                         "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+                         "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+                         "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+                         "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+                         "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+                         "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+                         "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+                         "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+                         "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+                         "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+                         "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A"
+                         "\xF1\x65\xFC\x93\x07\x9E\x35\xCC"
+                         "\x40\xD7\x6E\x05\x79\x10\xA7\x1B"
+                         "\xB2\x49\xE0\x54\xEB\x82\x19\x8D"
+                         "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF"
+                         "\x96\x0A\xA1\x38\xCF\x43\xDA\x71"
+                         "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3"
+                         "\x57\xEE\x85\x1C\x90\x27\xBE\x32"
+                         "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4"
+                         "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16"
+                         "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88"
+                         "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA"
+                         "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49"
+                         "\xE0\x77\x0E\x82\x19\xB0\x24\xBB"
+                         "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D"
+                         "\xC4\x38\xCF\x66\xFD\x71\x08\x9F"
+                         "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11"
+                         "\x85\x1C\xB3\x27\xBE\x55\xEC\x60"
+                         "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2"
+                         "\x69\x00\x74\x0B\xA2\x16\xAD\x44"
+                         "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6"
+                         "\x2A\xC1\x58\xEF\x63\xFA\x91\x05"
+                         "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77"
+                         "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9"
+                         "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B"
+                         "\xF2\x66\xFD\x94\x08\x9F\x36\xCD"
+                         "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C"
+                         "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E"
+                         "\x25\xBC\x30\xC7\x5E\xF5\x69\x00"
+                         "\x97\x0B\xA2\x39\xD0\x44\xDB\x72"
+                         "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4"
+                         "\x58\xEF\x86\x1D\x91\x28\xBF\x33"
+                         "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5"
+                         "\x3C\xD3\x47\xDE\x75\x0C\x80\x17"
+                         "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89"
+                         "\x20\x94\x2B\xC2\x36\xCD\x64\xFB"
+                         "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A"
+                         "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC"
+                         "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E"
+                         "\xC5\x39\xD0\x67\xFE\x72\x09\xA0"
+                         "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12"
+                         "\x86\x1D\xB4\x28\xBF\x56\xED\x61"
+                         "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3"
+                         "\x6A\x01\x75\x0C\xA3\x17\xAE\x45"
+                         "\xDC\x50\xE7\x7E\x15\x89\x20\xB7",
+               .rlen   = 496,
+       },
+};
 
-static struct cipher_testvec cast5_enc_tv_template[] = {
-       {
-               .key    = "\x01\x23\x45\x67\x12\x34\x56\x78"
-                         "\x23\x45\x67\x89\x34\x56\x78\x9a",
+static struct cipher_testvec cast5_ctr_enc_tv_template[] = {
+       { /* Generated from TF test vectors */
+               .key    = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+                         "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A",
                .klen   = 16,
-               .input  = "\x01\x23\x45\x67\x89\xab\xcd\xef",
-               .ilen   = 8,
-               .result = "\x23\x8b\x4f\xe5\x84\x7e\x44\xb2",
-               .rlen   = 8,
-       }, {
-               .key    = "\x01\x23\x45\x67\x12\x34\x56\x78"
-                         "\x23\x45",
-               .klen   = 10,
-               .input  = "\x01\x23\x45\x67\x89\xab\xcd\xef",
-               .ilen   = 8,
-               .result = "\xeb\x6a\x71\x1a\x2c\x02\x27\x1b",
-               .rlen   = 8,
-       }, {
-               .key    = "\x01\x23\x45\x67\x12",
-               .klen   = 5,
-               .input  = "\x01\x23\x45\x67\x89\xab\xcd\xef",
-               .ilen   = 8,
-               .result = "\x7a\xc8\x16\xd1\x6e\x9b\x30\x2e",
-               .rlen   = 8,
+               .iv     = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F",
+               .input  = "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+                         "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+                         "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+                         "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+                         "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+                         "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
+                         "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
+                         "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+                         "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+                         "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+                         "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+                         "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+                         "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+                         "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+                         "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+                         "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+                         "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+                         "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A"
+                         "\xF1\x65\xFC\x93\x07\x9E\x35\xCC"
+                         "\x40\xD7\x6E\x05\x79\x10\xA7\x1B"
+                         "\xB2\x49\xE0\x54\xEB\x82\x19\x8D"
+                         "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF"
+                         "\x96\x0A\xA1\x38\xCF\x43\xDA\x71"
+                         "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3"
+                         "\x57\xEE\x85\x1C\x90\x27\xBE\x32"
+                         "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4"
+                         "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16"
+                         "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88"
+                         "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA"
+                         "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49"
+                         "\xE0\x77\x0E\x82\x19\xB0\x24\xBB"
+                         "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D"
+                         "\xC4\x38\xCF\x66\xFD\x71\x08\x9F"
+                         "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11"
+                         "\x85\x1C\xB3\x27\xBE\x55\xEC\x60"
+                         "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2"
+                         "\x69\x00\x74\x0B\xA2\x16\xAD\x44"
+                         "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6"
+                         "\x2A\xC1\x58\xEF\x63\xFA\x91\x05"
+                         "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77"
+                         "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9"
+                         "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B"
+                         "\xF2\x66\xFD\x94\x08\x9F\x36\xCD"
+                         "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C"
+                         "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E"
+                         "\x25\xBC\x30\xC7\x5E\xF5\x69\x00"
+                         "\x97\x0B\xA2\x39\xD0\x44\xDB\x72"
+                         "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4"
+                         "\x58\xEF\x86\x1D\x91\x28\xBF\x33"
+                         "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5"
+                         "\x3C\xD3\x47\xDE\x75\x0C\x80\x17"
+                         "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89"
+                         "\x20\x94\x2B\xC2\x36\xCD\x64\xFB"
+                         "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A"
+                         "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC"
+                         "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E"
+                         "\xC5\x39\xD0\x67\xFE\x72\x09\xA0"
+                         "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12"
+                         "\x86\x1D\xB4\x28\xBF\x56\xED\x61"
+                         "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3"
+                         "\x6A\x01\x75\x0C\xA3\x17\xAE\x45"
+                         "\xDC\x50\xE7\x7E\x15\x89\x20\xB7",
+               .ilen   = 496,
+               .result = "\xFF\xC4\x2E\x82\x3D\xF8\xA8\x39"
+                         "\x7C\x52\xC4\xD3\xBB\x62\xC6\xA8"
+                         "\x0C\x63\xA5\x55\xE3\xF8\x1C\x7F"
+                         "\xDC\x59\xF9\xA0\x52\xAD\x83\xDF"
+                         "\xD5\x3B\x53\x4A\xAA\x1F\x49\x44"
+                         "\xE8\x20\xCC\xF8\x97\xE6\xE0\x3C"
+                         "\x5A\xD2\x83\xEC\xEE\x25\x3F\xCF"
+                         "\x0D\xC2\x79\x80\x99\x6E\xFF\x7B"
+                         "\x64\xB0\x7B\x86\x29\x1D\x9F\x17"
+                         "\x10\xA5\xA5\xEB\x16\x55\x9E\xE3"
+                         "\x88\x18\x52\x56\x48\x58\xD1\x6B"
+                         "\xE8\x74\x6E\x48\xB0\x2E\x69\x63"
+                         "\x32\xAA\xAC\x26\x55\x45\x94\xDE"
+                         "\x30\x26\x26\xE6\x08\x82\x2F\x5F"
+                         "\xA7\x15\x94\x07\x75\x2D\xC6\x3A"
+                         "\x1B\xA0\x39\xFB\xBA\xB9\x06\x56"
+                         "\xF6\x9F\xF1\x2F\x9B\xF3\x89\x8B"
+                         "\x08\xC8\x9D\x5E\x6B\x95\x09\xC7"
+                         "\x98\xB7\x62\xA4\x1D\x25\xFA\xC5"
+                         "\x62\xC8\x5D\x6B\xB4\x85\x88\x7F"
+                         "\x3B\x29\xF9\xB4\x32\x62\x69\xBF"
+                         "\x32\xB8\xEB\xFD\x0E\x26\xAA\xA3"
+                         "\x44\x67\x90\x20\xAC\x41\xDF\x43"
+                         "\xC6\xC7\x19\x9F\x2C\x28\x74\xEB"
+                         "\x3E\x7F\x7A\x80\x5B\xE4\x08\x60"
+                         "\xC7\xC9\x71\x34\x44\xCE\x05\xFD"
+                         "\xA8\x91\xA8\x44\x5E\xD3\x89\x2C"
+                         "\xAE\x59\x0F\x07\x88\x79\x53\x26"
+                         "\xAF\xAC\xCB\x1D\x6F\x08\x25\x62"
+                         "\xD0\x82\x65\x66\xE4\x2A\x29\x1C"
+                         "\x9C\x64\x5F\x49\x9D\xF8\x62\xF9"
+                         "\xED\xC4\x13\x52\x75\xDC\xE4\xF9"
+                         "\x68\x0F\x8A\xCD\xA6\x8D\x75\xAA"
+                         "\x49\xA1\x86\x86\x37\x5C\x6B\x3D"
+                         "\x56\xE5\x6F\xBE\x27\xC0\x10\xF8"
+                         "\x3C\x4D\x17\x35\x14\xDC\x1C\xA0"
+                         "\x6E\xAE\xD1\x10\xDD\x83\x06\xC2"
+                         "\x23\xD3\xC7\x27\x15\x04\x2C\x27"
+                         "\xDD\x1F\x2E\x97\x09\x9C\x33\x7D"
+                         "\xAC\x50\x1B\x2E\xC9\x52\x0C\x14"
+                         "\x4B\x78\xC4\xDE\x07\x6A\x12\x02"
+                         "\x6E\xD7\x4B\x91\xB9\x88\x4D\x02"
+                         "\xC3\xB5\x04\xBC\xE0\x67\xCA\x18"
+                         "\x22\xA1\xAE\x9A\x21\xEF\xB2\x06"
+                         "\x35\xCD\xEC\x37\x70\x2D\xFC\x1E"
+                         "\xA8\x31\xE7\xFC\xE5\x8E\x88\x66"
+                         "\x16\xB5\xC8\x45\x21\x37\xBD\x24"
+                         "\xA9\xD5\x36\x12\x9F\x6E\x67\x80"
+                         "\x87\x54\xD5\xAF\x97\xE1\x15\xA7"
+                         "\x11\xF0\x63\x7B\xE1\x44\x14\x1C"
+                         "\x06\x32\x05\x8C\x6C\xDB\x9B\x36"
+                         "\x6A\x6B\xAD\x3A\x27\x55\x20\x4C"
+                         "\x76\x36\x43\xE8\x16\x60\xB5\xF3"
+                         "\xDF\x5A\xC6\xA5\x69\x78\x59\x51"
+                         "\x54\x68\x65\x06\x84\xDE\x3D\xAE"
+                         "\x38\x91\xBD\xCC\xA2\x8A\xEC\xE6"
+                         "\x9E\x83\xAE\x1E\x8E\x34\x5D\xDE"
+                         "\x91\xCE\x8F\xED\x40\xF7\xC8\x8B"
+                         "\x9A\x13\x4C\xAD\x89\x97\x9E\xD1"
+                         "\x91\x01\xD7\x21\x23\x28\x1E\xCC"
+                         "\x8C\x98\xDB\xDE\xFC\x72\x94\xAA"
+                         "\xC0\x0D\x96\xAA\x23\xF8\xFE\x13",
+               .rlen   = 496,
        },
 };
 
-static struct cipher_testvec cast5_dec_tv_template[] = {
-       {
-               .key    = "\x01\x23\x45\x67\x12\x34\x56\x78"
-                         "\x23\x45\x67\x89\x34\x56\x78\x9a",
+static struct cipher_testvec cast5_ctr_dec_tv_template[] = {
+       { /* Generated from TF test vectors */
+               .key    = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9"
+                         "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A",
                .klen   = 16,
-               .input  = "\x23\x8b\x4f\xe5\x84\x7e\x44\xb2",
-               .ilen   = 8,
-               .result = "\x01\x23\x45\x67\x89\xab\xcd\xef",
-               .rlen   = 8,
-       }, {
-               .key    = "\x01\x23\x45\x67\x12\x34\x56\x78"
-                         "\x23\x45",
-               .klen   = 10,
-               .input  = "\xeb\x6a\x71\x1a\x2c\x02\x27\x1b",
-               .ilen   = 8,
-               .result = "\x01\x23\x45\x67\x89\xab\xcd\xef",
-               .rlen   = 8,
-       }, {
-               .key    = "\x01\x23\x45\x67\x12",
-               .klen   = 5,
-               .input  = "\x7a\xc8\x16\xd1\x6e\x9b\x30\x2e",
-               .ilen   = 8,
-               .result = "\x01\x23\x45\x67\x89\xab\xcd\xef",
-               .rlen   = 8,
+               .iv     = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F",
+               .input  = "\xFF\xC4\x2E\x82\x3D\xF8\xA8\x39"
+                         "\x7C\x52\xC4\xD3\xBB\x62\xC6\xA8"
+                         "\x0C\x63\xA5\x55\xE3\xF8\x1C\x7F"
+                         "\xDC\x59\xF9\xA0\x52\xAD\x83\xDF"
+                         "\xD5\x3B\x53\x4A\xAA\x1F\x49\x44"
+                         "\xE8\x20\xCC\xF8\x97\xE6\xE0\x3C"
+                         "\x5A\xD2\x83\xEC\xEE\x25\x3F\xCF"
+                         "\x0D\xC2\x79\x80\x99\x6E\xFF\x7B"
+                         "\x64\xB0\x7B\x86\x29\x1D\x9F\x17"
+                         "\x10\xA5\xA5\xEB\x16\x55\x9E\xE3"
+                         "\x88\x18\x52\x56\x48\x58\xD1\x6B"
+                         "\xE8\x74\x6E\x48\xB0\x2E\x69\x63"
+                         "\x32\xAA\xAC\x26\x55\x45\x94\xDE"
+                         "\x30\x26\x26\xE6\x08\x82\x2F\x5F"
+                         "\xA7\x15\x94\x07\x75\x2D\xC6\x3A"
+                         "\x1B\xA0\x39\xFB\xBA\xB9\x06\x56"
+                         "\xF6\x9F\xF1\x2F\x9B\xF3\x89\x8B"
+                         "\x08\xC8\x9D\x5E\x6B\x95\x09\xC7"
+                         "\x98\xB7\x62\xA4\x1D\x25\xFA\xC5"
+                         "\x62\xC8\x5D\x6B\xB4\x85\x88\x7F"
+                         "\x3B\x29\xF9\xB4\x32\x62\x69\xBF"
+                         "\x32\xB8\xEB\xFD\x0E\x26\xAA\xA3"
+                         "\x44\x67\x90\x20\xAC\x41\xDF\x43"
+                         "\xC6\xC7\x19\x9F\x2C\x28\x74\xEB"
+                         "\x3E\x7F\x7A\x80\x5B\xE4\x08\x60"
+                         "\xC7\xC9\x71\x34\x44\xCE\x05\xFD"
+                         "\xA8\x91\xA8\x44\x5E\xD3\x89\x2C"
+                         "\xAE\x59\x0F\x07\x88\x79\x53\x26"
+                         "\xAF\xAC\xCB\x1D\x6F\x08\x25\x62"
+                         "\xD0\x82\x65\x66\xE4\x2A\x29\x1C"
+                         "\x9C\x64\x5F\x49\x9D\xF8\x62\xF9"
+                         "\xED\xC4\x13\x52\x75\xDC\xE4\xF9"
+                         "\x68\x0F\x8A\xCD\xA6\x8D\x75\xAA"
+                         "\x49\xA1\x86\x86\x37\x5C\x6B\x3D"
+                         "\x56\xE5\x6F\xBE\x27\xC0\x10\xF8"
+                         "\x3C\x4D\x17\x35\x14\xDC\x1C\xA0"
+                         "\x6E\xAE\xD1\x10\xDD\x83\x06\xC2"
+                         "\x23\xD3\xC7\x27\x15\x04\x2C\x27"
+                         "\xDD\x1F\x2E\x97\x09\x9C\x33\x7D"
+                         "\xAC\x50\x1B\x2E\xC9\x52\x0C\x14"
+                         "\x4B\x78\xC4\xDE\x07\x6A\x12\x02"
+                         "\x6E\xD7\x4B\x91\xB9\x88\x4D\x02"
+                         "\xC3\xB5\x04\xBC\xE0\x67\xCA\x18"
+                         "\x22\xA1\xAE\x9A\x21\xEF\xB2\x06"
+                         "\x35\xCD\xEC\x37\x70\x2D\xFC\x1E"
+                         "\xA8\x31\xE7\xFC\xE5\x8E\x88\x66"
+                         "\x16\xB5\xC8\x45\x21\x37\xBD\x24"
+                         "\xA9\xD5\x36\x12\x9F\x6E\x67\x80"
+                         "\x87\x54\xD5\xAF\x97\xE1\x15\xA7"
+                         "\x11\xF0\x63\x7B\xE1\x44\x14\x1C"
+                         "\x06\x32\x05\x8C\x6C\xDB\x9B\x36"
+                         "\x6A\x6B\xAD\x3A\x27\x55\x20\x4C"
+                         "\x76\x36\x43\xE8\x16\x60\xB5\xF3"
+                         "\xDF\x5A\xC6\xA5\x69\x78\x59\x51"
+                         "\x54\x68\x65\x06\x84\xDE\x3D\xAE"
+                         "\x38\x91\xBD\xCC\xA2\x8A\xEC\xE6"
+                         "\x9E\x83\xAE\x1E\x8E\x34\x5D\xDE"
+                         "\x91\xCE\x8F\xED\x40\xF7\xC8\x8B"
+                         "\x9A\x13\x4C\xAD\x89\x97\x9E\xD1"
+                         "\x91\x01\xD7\x21\x23\x28\x1E\xCC"
+                         "\x8C\x98\xDB\xDE\xFC\x72\x94\xAA"
+                         "\xC0\x0D\x96\xAA\x23\xF8\xFE\x13",
+               .ilen   = 496,
+               .result = "\x56\xED\x84\x1B\x8F\x26\xBD\x31"
+                         "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3"
+                         "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15"
+                         "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87"
+                         "\x1E\x92\x29\xC0\x34\xCB\x62\xF9"
+                         "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48"
+                         "\xDF\x76\x0D\x81\x18\xAF\x23\xBA"
+                         "\x51\xE8\x5C\xF3\x8A\x21\x95\x2C"
+                         "\xC3\x37\xCE\x65\xFC\x70\x07\x9E"
+                         "\x12\xA9\x40\xD7\x4B\xE2\x79\x10"
+                         "\x84\x1B\xB2\x26\xBD\x54\xEB\x5F"
+                         "\xF6\x8D\x01\x98\x2F\xC6\x3A\xD1"
+                         "\x68\xFF\x73\x0A\xA1\x15\xAC\x43"
+                         "\xDA\x4E\xE5\x7C\x13\x87\x1E\xB5"
+                         "\x29\xC0\x57\xEE\x62\xF9\x90\x04"
+                         "\x9B\x32\xC9\x3D\xD4\x6B\x02\x76"
+                         "\x0D\xA4\x18\xAF\x46\xDD\x51\xE8"
+                         "\x7F\x16\x8A\x21\xB8\x2C\xC3\x5A"
+                         "\xF1\x65\xFC\x93\x07\x9E\x35\xCC"
+                         "\x40\xD7\x6E\x05\x79\x10\xA7\x1B"
+                         "\xB2\x49\xE0\x54\xEB\x82\x19\x8D"
+                         "\x24\xBB\x2F\xC6\x5D\xF4\x68\xFF"
+                         "\x96\x0A\xA1\x38\xCF\x43\xDA\x71"
+                         "\x08\x7C\x13\xAA\x1E\xB5\x4C\xE3"
+                         "\x57\xEE\x85\x1C\x90\x27\xBE\x32"
+                         "\xC9\x60\xF7\x6B\x02\x99\x0D\xA4"
+                         "\x3B\xD2\x46\xDD\x74\x0B\x7F\x16"
+                         "\xAD\x21\xB8\x4F\xE6\x5A\xF1\x88"
+                         "\x1F\x93\x2A\xC1\x35\xCC\x63\xFA"
+                         "\x6E\x05\x9C\x10\xA7\x3E\xD5\x49"
+                         "\xE0\x77\x0E\x82\x19\xB0\x24\xBB"
+                         "\x52\xE9\x5D\xF4\x8B\x22\x96\x2D"
+                         "\xC4\x38\xCF\x66\xFD\x71\x08\x9F"
+                         "\x13\xAA\x41\xD8\x4C\xE3\x7A\x11"
+                         "\x85\x1C\xB3\x27\xBE\x55\xEC\x60"
+                         "\xF7\x8E\x02\x99\x30\xC7\x3B\xD2"
+                         "\x69\x00\x74\x0B\xA2\x16\xAD\x44"
+                         "\xDB\x4F\xE6\x7D\x14\x88\x1F\xB6"
+                         "\x2A\xC1\x58\xEF\x63\xFA\x91\x05"
+                         "\x9C\x33\xCA\x3E\xD5\x6C\x03\x77"
+                         "\x0E\xA5\x19\xB0\x47\xDE\x52\xE9"
+                         "\x80\x17\x8B\x22\xB9\x2D\xC4\x5B"
+                         "\xF2\x66\xFD\x94\x08\x9F\x36\xCD"
+                         "\x41\xD8\x6F\x06\x7A\x11\xA8\x1C"
+                         "\xB3\x4A\xE1\x55\xEC\x83\x1A\x8E"
+                         "\x25\xBC\x30\xC7\x5E\xF5\x69\x00"
+                         "\x97\x0B\xA2\x39\xD0\x44\xDB\x72"
+                         "\x09\x7D\x14\xAB\x1F\xB6\x4D\xE4"
+                         "\x58\xEF\x86\x1D\x91\x28\xBF\x33"
+                         "\xCA\x61\xF8\x6C\x03\x9A\x0E\xA5"
+                         "\x3C\xD3\x47\xDE\x75\x0C\x80\x17"
+                         "\xAE\x22\xB9\x50\xE7\x5B\xF2\x89"
+                         "\x20\x94\x2B\xC2\x36\xCD\x64\xFB"
+                         "\x6F\x06\x9D\x11\xA8\x3F\xD6\x4A"
+                         "\xE1\x78\x0F\x83\x1A\xB1\x25\xBC"
+                         "\x53\xEA\x5E\xF5\x8C\x00\x97\x2E"
+                         "\xC5\x39\xD0\x67\xFE\x72\x09\xA0"
+                         "\x14\xAB\x42\xD9\x4D\xE4\x7B\x12"
+                         "\x86\x1D\xB4\x28\xBF\x56\xED\x61"
+                         "\xF8\x8F\x03\x9A\x31\xC8\x3C\xD3"
+                         "\x6A\x01\x75\x0C\xA3\x17\xAE\x45"
+                         "\xDC\x50\xE7\x7E\x15\x89\x20\xB7",
+               .rlen   = 496,
        },
 };
 
index cbca4f208c9f40017c8ff69c27c52f34862904fd..87403556fd0bfa5c3a4ecd40a5a707b6892fbc04 100644 (file)
@@ -628,7 +628,7 @@ static int tgr128_final(struct shash_desc *desc, u8 * out)
        return 0;
 }
 
-static struct shash_alg tgr192 = {
+static struct shash_alg tgr_algs[3] = { {
        .digestsize     =       TGR192_DIGEST_SIZE,
        .init           =       tgr192_init,
        .update         =       tgr192_update,
@@ -640,9 +640,7 @@ static struct shash_alg tgr192 = {
                .cra_blocksize  =       TGR192_BLOCK_SIZE,
                .cra_module     =       THIS_MODULE,
        }
-};
-
-static struct shash_alg tgr160 = {
+}, {
        .digestsize     =       TGR160_DIGEST_SIZE,
        .init           =       tgr192_init,
        .update         =       tgr192_update,
@@ -654,9 +652,7 @@ static struct shash_alg tgr160 = {
                .cra_blocksize  =       TGR192_BLOCK_SIZE,
                .cra_module     =       THIS_MODULE,
        }
-};
-
-static struct shash_alg tgr128 = {
+}, {
        .digestsize     =       TGR128_DIGEST_SIZE,
        .init           =       tgr192_init,
        .update         =       tgr192_update,
@@ -668,38 +664,16 @@ static struct shash_alg tgr128 = {
                .cra_blocksize  =       TGR192_BLOCK_SIZE,
                .cra_module     =       THIS_MODULE,
        }
-};
+} };
 
 static int __init tgr192_mod_init(void)
 {
-       int ret = 0;
-
-       ret = crypto_register_shash(&tgr192);
-
-       if (ret < 0) {
-               goto out;
-       }
-
-       ret = crypto_register_shash(&tgr160);
-       if (ret < 0) {
-               crypto_unregister_shash(&tgr192);
-               goto out;
-       }
-
-       ret = crypto_register_shash(&tgr128);
-       if (ret < 0) {
-               crypto_unregister_shash(&tgr192);
-               crypto_unregister_shash(&tgr160);
-       }
-      out:
-       return ret;
+       return crypto_register_shashes(tgr_algs, ARRAY_SIZE(tgr_algs));
 }
 
 static void __exit tgr192_mod_fini(void)
 {
-       crypto_unregister_shash(&tgr192);
-       crypto_unregister_shash(&tgr160);
-       crypto_unregister_shash(&tgr128);
+       crypto_unregister_shashes(tgr_algs, ARRAY_SIZE(tgr_algs));
 }
 
 MODULE_ALIAS("tgr160");
index 1f07b843e07cd3a00a8c02844a1f60c1941fdcd9..2d5000552d0f93b1bacb1e799e50605743c4d969 100644 (file)
@@ -188,7 +188,6 @@ static struct crypto_alg alg = {
        .cra_ctxsize        =   sizeof(struct twofish_ctx),
        .cra_alignmask      =   3,
        .cra_module         =   THIS_MODULE,
-       .cra_list           =   LIST_HEAD_INIT(alg.cra_list),
        .cra_u              =   { .cipher = {
        .cia_min_keysize    =   TF_MIN_KEY_SIZE,
        .cia_max_keysize    =   TF_MAX_KEY_SIZE,
index 71719a2be25afa5ca341bd65306ec976b52d42b2..180f1d6e03f48fc20ef787061d8866e6af429c68 100644 (file)
@@ -1119,7 +1119,7 @@ static int wp256_final(struct shash_desc *desc, u8 *out)
        return 0;
 }
 
-static struct shash_alg wp512 = {
+static struct shash_alg wp_algs[3] = { {
        .digestsize     =       WP512_DIGEST_SIZE,
        .init           =       wp512_init,
        .update         =       wp512_update,
@@ -1131,9 +1131,7 @@ static struct shash_alg wp512 = {
                .cra_blocksize  =       WP512_BLOCK_SIZE,
                .cra_module     =       THIS_MODULE,
        }
-};
-
-static struct shash_alg wp384 = {
+}, {
        .digestsize     =       WP384_DIGEST_SIZE,
        .init           =       wp512_init,
        .update         =       wp512_update,
@@ -1145,9 +1143,7 @@ static struct shash_alg wp384 = {
                .cra_blocksize  =       WP512_BLOCK_SIZE,
                .cra_module     =       THIS_MODULE,
        }
-};
-
-static struct shash_alg wp256 = {
+}, {
        .digestsize     =       WP256_DIGEST_SIZE,
        .init           =       wp512_init,
        .update         =       wp512_update,
@@ -1159,39 +1155,16 @@ static struct shash_alg wp256 = {
                .cra_blocksize  =       WP512_BLOCK_SIZE,
                .cra_module     =       THIS_MODULE,
        }
-};
+} };
 
 static int __init wp512_mod_init(void)
 {
-       int ret = 0;
-
-       ret = crypto_register_shash(&wp512);
-
-       if (ret < 0)
-               goto out;
-
-       ret = crypto_register_shash(&wp384);
-       if (ret < 0)
-       {
-               crypto_unregister_shash(&wp512);
-               goto out;
-       }
-
-       ret = crypto_register_shash(&wp256);
-       if (ret < 0)
-       {
-               crypto_unregister_shash(&wp512);
-               crypto_unregister_shash(&wp384);
-       }
-out:
-       return ret;
+       return crypto_register_shashes(wp_algs, ARRAY_SIZE(wp_algs));
 }
 
 static void __exit wp512_mod_fini(void)
 {
-       crypto_unregister_shash(&wp512);
-       crypto_unregister_shash(&wp384);
-       crypto_unregister_shash(&wp256);
+       crypto_unregister_shashes(wp_algs, ARRAY_SIZE(wp_algs));
 }
 
 MODULE_ALIAS("wp384");
index ac7034129f3f9e656d6cbf537dc063a2e49ba614..d5fdd36190cce3f385011b30a1f5c729a5b6a4dd 100644 (file)
@@ -69,7 +69,9 @@ static const struct acpi_device_id ac_device_ids[] = {
 };
 MODULE_DEVICE_TABLE(acpi, ac_device_ids);
 
+#ifdef CONFIG_PM_SLEEP
 static int acpi_ac_resume(struct device *dev);
+#endif
 static SIMPLE_DEV_PM_OPS(acpi_ac_pm, NULL, acpi_ac_resume);
 
 static struct acpi_driver acpi_ac_driver = {
@@ -313,6 +315,7 @@ static int acpi_ac_add(struct acpi_device *device)
        return result;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int acpi_ac_resume(struct device *dev)
 {
        struct acpi_ac *ac;
@@ -332,6 +335,7 @@ static int acpi_ac_resume(struct device *dev)
                kobject_uevent(&ac->charger.dev->kobj, KOBJ_CHANGE);
        return 0;
 }
+#endif
 
 static int acpi_ac_remove(struct acpi_device *device, int type)
 {
index 5ccb99ae3a6fae1872a13ab40755aa4ecd693106..5de4ec72766d653924068cb6887d07573ef93539 100644 (file)
@@ -83,22 +83,22 @@ acpi_status acpi_hw_clear_acpi_status(void);
 /*
  * hwsleep - sleep/wake support (Legacy sleep registers)
  */
-acpi_status acpi_hw_legacy_sleep(u8 sleep_state, u8 flags);
+acpi_status acpi_hw_legacy_sleep(u8 sleep_state);
 
-acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state, u8 flags);
+acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state);
 
-acpi_status acpi_hw_legacy_wake(u8 sleep_state, u8 flags);
+acpi_status acpi_hw_legacy_wake(u8 sleep_state);
 
 /*
  * hwesleep - sleep/wake support (Extended FADT-V5 sleep registers)
  */
 void acpi_hw_execute_sleep_method(char *method_name, u32 integer_argument);
 
-acpi_status acpi_hw_extended_sleep(u8 sleep_state, u8 flags);
+acpi_status acpi_hw_extended_sleep(u8 sleep_state);
 
-acpi_status acpi_hw_extended_wake_prep(u8 sleep_state, u8 flags);
+acpi_status acpi_hw_extended_wake_prep(u8 sleep_state);
 
-acpi_status acpi_hw_extended_wake(u8 sleep_state, u8 flags);
+acpi_status acpi_hw_extended_wake(u8 sleep_state);
 
 /*
  * hwvalid - Port I/O with validation
index 48518dac534230a8f59ee7bbfe1e36475396bb19..94996f9ae3ad164636364af38d6ce0b2524cdd72 100644 (file)
@@ -90,7 +90,6 @@ void acpi_hw_execute_sleep_method(char *method_pathname, u32 integer_argument)
  * FUNCTION:    acpi_hw_extended_sleep
  *
  * PARAMETERS:  sleep_state         - Which sleep state to enter
- *              flags               - ACPI_EXECUTE_GTS to run optional method
  *
  * RETURN:      Status
  *
@@ -100,7 +99,7 @@ void acpi_hw_execute_sleep_method(char *method_pathname, u32 integer_argument)
  *
  ******************************************************************************/
 
-acpi_status acpi_hw_extended_sleep(u8 sleep_state, u8 flags)
+acpi_status acpi_hw_extended_sleep(u8 sleep_state)
 {
        acpi_status status;
        u8 sleep_type_value;
@@ -125,12 +124,6 @@ acpi_status acpi_hw_extended_sleep(u8 sleep_state, u8 flags)
 
        acpi_gbl_system_awake_and_running = FALSE;
 
-       /* Optionally execute _GTS (Going To Sleep) */
-
-       if (flags & ACPI_EXECUTE_GTS) {
-               acpi_hw_execute_sleep_method(METHOD_PATHNAME__GTS, sleep_state);
-       }
-
        /* Flush caches, as per ACPI specification */
 
        ACPI_FLUSH_CPU_CACHE();
@@ -172,7 +165,6 @@ acpi_status acpi_hw_extended_sleep(u8 sleep_state, u8 flags)
  * FUNCTION:    acpi_hw_extended_wake_prep
  *
  * PARAMETERS:  sleep_state         - Which sleep state we just exited
- *              flags               - ACPI_EXECUTE_BFS to run optional method
  *
  * RETURN:      Status
  *
@@ -181,7 +173,7 @@ acpi_status acpi_hw_extended_sleep(u8 sleep_state, u8 flags)
  *
  ******************************************************************************/
 
-acpi_status acpi_hw_extended_wake_prep(u8 sleep_state, u8 flags)
+acpi_status acpi_hw_extended_wake_prep(u8 sleep_state)
 {
        acpi_status status;
        u8 sleep_type_value;
@@ -200,11 +192,6 @@ acpi_status acpi_hw_extended_wake_prep(u8 sleep_state, u8 flags)
                                 &acpi_gbl_FADT.sleep_control);
        }
 
-       /* Optionally execute _BFS (Back From Sleep) */
-
-       if (flags & ACPI_EXECUTE_BFS) {
-               acpi_hw_execute_sleep_method(METHOD_PATHNAME__BFS, sleep_state);
-       }
        return_ACPI_STATUS(AE_OK);
 }
 
@@ -222,7 +209,7 @@ acpi_status acpi_hw_extended_wake_prep(u8 sleep_state, u8 flags)
  *
  ******************************************************************************/
 
-acpi_status acpi_hw_extended_wake(u8 sleep_state, u8 flags)
+acpi_status acpi_hw_extended_wake(u8 sleep_state)
 {
        ACPI_FUNCTION_TRACE(hw_extended_wake);
 
index 9960fe9ef5334f719ed4e5cbd8cb2cbef530a2aa..3fddde056a5e1774e2e208f2478ce07d53fa5bf5 100644 (file)
@@ -56,7 +56,6 @@ ACPI_MODULE_NAME("hwsleep")
  * FUNCTION:    acpi_hw_legacy_sleep
  *
  * PARAMETERS:  sleep_state         - Which sleep state to enter
- *              flags               - ACPI_EXECUTE_GTS to run optional method
  *
  * RETURN:      Status
  *
@@ -64,7 +63,7 @@ ACPI_MODULE_NAME("hwsleep")
  *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
  *
  ******************************************************************************/
-acpi_status acpi_hw_legacy_sleep(u8 sleep_state, u8 flags)
+acpi_status acpi_hw_legacy_sleep(u8 sleep_state)
 {
        struct acpi_bit_register_info *sleep_type_reg_info;
        struct acpi_bit_register_info *sleep_enable_reg_info;
@@ -110,12 +109,6 @@ acpi_status acpi_hw_legacy_sleep(u8 sleep_state, u8 flags)
                return_ACPI_STATUS(status);
        }
 
-       /* Optionally execute _GTS (Going To Sleep) */
-
-       if (flags & ACPI_EXECUTE_GTS) {
-               acpi_hw_execute_sleep_method(METHOD_PATHNAME__GTS, sleep_state);
-       }
-
        /* Get current value of PM1A control */
 
        status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL,
@@ -214,7 +207,6 @@ acpi_status acpi_hw_legacy_sleep(u8 sleep_state, u8 flags)
  * FUNCTION:    acpi_hw_legacy_wake_prep
  *
  * PARAMETERS:  sleep_state         - Which sleep state we just exited
- *              flags               - ACPI_EXECUTE_BFS to run optional method
  *
  * RETURN:      Status
  *
@@ -224,7 +216,7 @@ acpi_status acpi_hw_legacy_sleep(u8 sleep_state, u8 flags)
  *
  ******************************************************************************/
 
-acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state, u8 flags)
+acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state)
 {
        acpi_status status;
        struct acpi_bit_register_info *sleep_type_reg_info;
@@ -275,11 +267,6 @@ acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state, u8 flags)
                }
        }
 
-       /* Optionally execute _BFS (Back From Sleep) */
-
-       if (flags & ACPI_EXECUTE_BFS) {
-               acpi_hw_execute_sleep_method(METHOD_PATHNAME__BFS, sleep_state);
-       }
        return_ACPI_STATUS(status);
 }
 
@@ -288,7 +275,6 @@ acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state, u8 flags)
  * FUNCTION:    acpi_hw_legacy_wake
  *
  * PARAMETERS:  sleep_state         - Which sleep state we just exited
- *              flags               - Reserved, set to zero
  *
  * RETURN:      Status
  *
@@ -297,7 +283,7 @@ acpi_status acpi_hw_legacy_wake_prep(u8 sleep_state, u8 flags)
  *
  ******************************************************************************/
 
-acpi_status acpi_hw_legacy_wake(u8 sleep_state, u8 flags)
+acpi_status acpi_hw_legacy_wake(u8 sleep_state)
 {
        acpi_status status;
 
index f8684bfe79079ba170c727b96d7ea404a91ee604..1f165a750ae28736ca5066c908d5ade37ba4740e 100644 (file)
@@ -50,7 +50,7 @@ ACPI_MODULE_NAME("hwxfsleep")
 
 /* Local prototypes */
 static acpi_status
-acpi_hw_sleep_dispatch(u8 sleep_state, u8 flags, u32 function_id);
+acpi_hw_sleep_dispatch(u8 sleep_state, u32 function_id);
 
 /*
  * Dispatch table used to efficiently branch to the various sleep
@@ -235,7 +235,7 @@ ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_s4bios)
  *
  ******************************************************************************/
 static acpi_status
-acpi_hw_sleep_dispatch(u8 sleep_state, u8 flags, u32 function_id)
+acpi_hw_sleep_dispatch(u8 sleep_state, u32 function_id)
 {
        acpi_status status;
        struct acpi_sleep_functions *sleep_functions =
@@ -248,11 +248,11 @@ acpi_hw_sleep_dispatch(u8 sleep_state, u8 flags, u32 function_id)
         * use the extended sleep registers
         */
        if (acpi_gbl_reduced_hardware || acpi_gbl_FADT.sleep_control.address) {
-               status = sleep_functions->extended_function(sleep_state, flags);
+               status = sleep_functions->extended_function(sleep_state);
        } else {
                /* Legacy sleep */
 
-               status = sleep_functions->legacy_function(sleep_state, flags);
+               status = sleep_functions->legacy_function(sleep_state);
        }
 
        return (status);
@@ -262,7 +262,7 @@ acpi_hw_sleep_dispatch(u8 sleep_state, u8 flags, u32 function_id)
         * For the case where reduced-hardware-only code is being generated,
         * we know that only the extended sleep registers are available
         */
-       status = sleep_functions->extended_function(sleep_state, flags);
+       status = sleep_functions->extended_function(sleep_state);
        return (status);
 
 #endif                         /* !ACPI_REDUCED_HARDWARE */
@@ -349,7 +349,6 @@ ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_prep)
  * FUNCTION:    acpi_enter_sleep_state
  *
  * PARAMETERS:  sleep_state         - Which sleep state to enter
- *              flags               - ACPI_EXECUTE_GTS to run optional method
  *
  * RETURN:      Status
  *
@@ -357,7 +356,7 @@ ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_prep)
  *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
  *
  ******************************************************************************/
-acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state, u8 flags)
+acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
 {
        acpi_status status;
 
@@ -371,7 +370,7 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state, u8 flags)
        }
 
        status =
-           acpi_hw_sleep_dispatch(sleep_state, flags, ACPI_SLEEP_FUNCTION_ID);
+           acpi_hw_sleep_dispatch(sleep_state, ACPI_SLEEP_FUNCTION_ID);
        return_ACPI_STATUS(status);
 }
 
@@ -391,14 +390,14 @@ ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state)
  *              Called with interrupts DISABLED.
  *
  ******************************************************************************/
-acpi_status acpi_leave_sleep_state_prep(u8 sleep_state, u8 flags)
+acpi_status acpi_leave_sleep_state_prep(u8 sleep_state)
 {
        acpi_status status;
 
        ACPI_FUNCTION_TRACE(acpi_leave_sleep_state_prep);
 
        status =
-           acpi_hw_sleep_dispatch(sleep_state, flags,
+           acpi_hw_sleep_dispatch(sleep_state,
                                   ACPI_WAKE_PREP_FUNCTION_ID);
        return_ACPI_STATUS(status);
 }
@@ -423,8 +422,7 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state)
 
        ACPI_FUNCTION_TRACE(acpi_leave_sleep_state);
 
-
-       status = acpi_hw_sleep_dispatch(sleep_state, 0, ACPI_WAKE_FUNCTION_ID);
+       status = acpi_hw_sleep_dispatch(sleep_state, ACPI_WAKE_FUNCTION_ID);
        return_ACPI_STATUS(status);
 }
 
index ff2c876ec412980a8f9a73188f925c964ecae0ad..45e3e1759fb88c09ddd401921d2a4ea035431bff 100644 (file)
@@ -1052,6 +1052,7 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
 /* this is needed to learn about changes made in suspended state */
 static int acpi_battery_resume(struct device *dev)
 {
@@ -1068,6 +1069,7 @@ static int acpi_battery_resume(struct device *dev)
        acpi_battery_update(battery);
        return 0;
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(acpi_battery_pm, NULL, acpi_battery_resume);
 
index 79d4c22f7a6d82c21e786b591f02f8bfe28b0f43..314a3b84bbc7e2626a227a4ef2a620204dbf2434 100644 (file)
@@ -78,7 +78,9 @@ static int acpi_button_add(struct acpi_device *device);
 static int acpi_button_remove(struct acpi_device *device, int type);
 static void acpi_button_notify(struct acpi_device *device, u32 event);
 
+#ifdef CONFIG_PM_SLEEP
 static int acpi_button_resume(struct device *dev);
+#endif
 static SIMPLE_DEV_PM_OPS(acpi_button_pm, NULL, acpi_button_resume);
 
 static struct acpi_driver acpi_button_driver = {
@@ -310,6 +312,7 @@ static void acpi_button_notify(struct acpi_device *device, u32 event)
        }
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int acpi_button_resume(struct device *dev)
 {
        struct acpi_device *device = to_acpi_device(dev);
@@ -319,6 +322,7 @@ static int acpi_button_resume(struct device *dev)
                return acpi_lid_send_state(device);
        return 0;
 }
+#endif
 
 static int acpi_button_add(struct acpi_device *device)
 {
index 669d9ee80d1678b7665a3b4b8b2ad709743a44aa..bc36a476f1abf139586391c4e490cad56aff4368 100644 (file)
@@ -53,8 +53,10 @@ static const struct acpi_device_id fan_device_ids[] = {
 };
 MODULE_DEVICE_TABLE(acpi, fan_device_ids);
 
+#ifdef CONFIG_PM_SLEEP
 static int acpi_fan_suspend(struct device *dev);
 static int acpi_fan_resume(struct device *dev);
+#endif
 static SIMPLE_DEV_PM_OPS(acpi_fan_pm, acpi_fan_suspend, acpi_fan_resume);
 
 static struct acpi_driver acpi_fan_driver = {
@@ -184,6 +186,7 @@ static int acpi_fan_remove(struct acpi_device *device, int type)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int acpi_fan_suspend(struct device *dev)
 {
        if (!dev)
@@ -207,6 +210,7 @@ static int acpi_fan_resume(struct device *dev)
 
        return result;
 }
+#endif
 
 static int __init acpi_fan_init(void)
 {
index e56f3be7b07d36fceb32dce25ede0fa35308f0e7..cb31298ca684f5d99578ada635eb2b011bd07b67 100644 (file)
@@ -237,6 +237,8 @@ acpi_parse_processor_affinity(struct acpi_subtable_header *header,
        return 0;
 }
 
+static int __initdata parsed_numa_memblks;
+
 static int __init
 acpi_parse_memory_affinity(struct acpi_subtable_header * header,
                           const unsigned long end)
@@ -250,8 +252,8 @@ acpi_parse_memory_affinity(struct acpi_subtable_header * header,
        acpi_table_print_srat_entry(header);
 
        /* let architecture-dependent part to do it */
-       acpi_numa_memory_affinity_init(memory_affinity);
-
+       if (!acpi_numa_memory_affinity_init(memory_affinity))
+               parsed_numa_memblks++;
        return 0;
 }
 
@@ -304,8 +306,10 @@ int __init acpi_numa_init(void)
 
        acpi_numa_arch_fixup();
 
-       if (cnt <= 0)
-               return cnt ?: -ENOENT;
+       if (cnt < 0)
+               return cnt;
+       else if (!parsed_numa_memblks)
+               return -ENOENT;
        return 0;
 }
 
index ec54014c321c5ffd72cf46cc14d877ecbdec1925..72a2c98bc4298e8518e7d2b388f0e2d5d3abdc5f 100644 (file)
@@ -573,8 +573,15 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
                        OSC_CLOCK_PWR_CAPABILITY_SUPPORT;
        if (pci_msi_enabled())
                flags |= OSC_MSI_SUPPORT;
-       if (flags != base_flags)
-               acpi_pci_osc_support(root, flags);
+       if (flags != base_flags) {
+               status = acpi_pci_osc_support(root, flags);
+               if (ACPI_FAILURE(status)) {
+                       dev_info(root->bus->bridge, "ACPI _OSC support "
+                               "notification failed, disabling PCIe ASPM\n");
+                       pcie_no_aspm();
+                       flags = base_flags;
+               }
+       }
 
        if (!pcie_ports_disabled
            && (flags & ACPI_PCIE_REQ_SUPPORT) == ACPI_PCIE_REQ_SUPPORT) {
index 215ecd09740888be80ce50bbd4ffb74f292c9753..fc1803414629d8233b0d6f11819efd166838952e 100644 (file)
@@ -67,7 +67,9 @@ static const struct acpi_device_id power_device_ids[] = {
 };
 MODULE_DEVICE_TABLE(acpi, power_device_ids);
 
+#ifdef CONFIG_PM_SLEEP
 static int acpi_power_resume(struct device *dev);
+#endif
 static SIMPLE_DEV_PM_OPS(acpi_power_pm, NULL, acpi_power_resume);
 
 static struct acpi_driver acpi_power_driver = {
@@ -775,6 +777,7 @@ static int acpi_power_remove(struct acpi_device *device, int type)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int acpi_power_resume(struct device *dev)
 {
        int result = 0, state;
@@ -803,6 +806,7 @@ static int acpi_power_resume(struct device *dev)
 
        return result;
 }
+#endif
 
 int __init acpi_power_init(void)
 {
index ff8e04f2fab40eb7ea14693a2ba70babe1ec8797..bfc31cb0dd3eac96292af65535c2ee4554cdbf10 100644 (file)
@@ -437,7 +437,7 @@ static int acpi_cpu_soft_notify(struct notifier_block *nfb,
                /* Normal CPU soft online event */
                } else {
                        acpi_processor_ppc_has_changed(pr, 0);
-                       acpi_processor_cst_has_changed(pr);
+                       acpi_processor_hotplug(pr);
                        acpi_processor_reevaluate_tstate(pr, action);
                        acpi_processor_tstate_has_changed(pr);
                }
index c0b9aa5faf4cdfd8d354fa89e8204704714cccf1..ff0740e0a9c248fc932992e56d23540a59489a55 100644 (file)
@@ -988,6 +988,7 @@ static void acpi_sbs_rmdirs(void)
 #endif
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int acpi_sbs_resume(struct device *dev)
 {
        struct acpi_sbs *sbs;
@@ -997,6 +998,7 @@ static int acpi_sbs_resume(struct device *dev)
        acpi_sbs_callback(sbs);
        return 0;
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(acpi_sbs_pm, NULL, acpi_sbs_resume);
 
index 7a7a9c929247e6faaecbeca3c9863f02abc1c283..fdcdbb652915a32340d91a7d6e6fcce15c3ee602 100644 (file)
 #include "internal.h"
 #include "sleep.h"
 
-u8 wake_sleep_flags = ACPI_NO_OPTIONAL_METHODS;
-static unsigned int gts, bfs;
-static int set_param_wake_flag(const char *val, struct kernel_param *kp)
-{
-       int ret = param_set_int(val, kp);
-
-       if (ret)
-               return ret;
-
-       if (kp->arg == (const char *)&gts) {
-               if (gts)
-                       wake_sleep_flags |= ACPI_EXECUTE_GTS;
-               else
-                       wake_sleep_flags &= ~ACPI_EXECUTE_GTS;
-       }
-       if (kp->arg == (const char *)&bfs) {
-               if (bfs)
-                       wake_sleep_flags |= ACPI_EXECUTE_BFS;
-               else
-                       wake_sleep_flags &= ~ACPI_EXECUTE_BFS;
-       }
-       return ret;
-}
-module_param_call(gts, set_param_wake_flag, param_get_int, &gts, 0644);
-module_param_call(bfs, set_param_wake_flag, param_get_int, &bfs, 0644);
-MODULE_PARM_DESC(gts, "Enable evaluation of _GTS on suspend.");
-MODULE_PARM_DESC(bfs, "Enable evaluation of _BFS on resume".);
-
 static u8 sleep_states[ACPI_S_STATE_COUNT];
-static bool pwr_btn_event_pending;
 
 static void acpi_sleep_tts_switch(u32 acpi_state)
 {
@@ -110,6 +81,7 @@ static int acpi_sleep_prepare(u32 acpi_state)
 
 #ifdef CONFIG_ACPI_SLEEP
 static u32 acpi_target_sleep_state = ACPI_STATE_S0;
+static bool pwr_btn_event_pending;
 
 /*
  * The ACPI specification wants us to save NVS memory regions during hibernation
@@ -305,7 +277,7 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
        switch (acpi_state) {
        case ACPI_STATE_S1:
                barrier();
-               status = acpi_enter_sleep_state(acpi_state, wake_sleep_flags);
+               status = acpi_enter_sleep_state(acpi_state);
                break;
 
        case ACPI_STATE_S3:
@@ -319,8 +291,8 @@ static int acpi_suspend_enter(suspend_state_t pm_state)
        /* This violates the spec but is required for bug compatibility. */
        acpi_write_bit_register(ACPI_BITREG_SCI_ENABLE, 1);
 
-       /* Reprogram control registers and execute _BFS */
-       acpi_leave_sleep_state_prep(acpi_state, wake_sleep_flags);
+       /* Reprogram control registers */
+       acpi_leave_sleep_state_prep(acpi_state);
 
        /* ACPI 3.0 specs (P62) says that it's the responsibility
         * of the OSPM to clear the status bit [ implying that the
@@ -603,9 +575,9 @@ static int acpi_hibernation_enter(void)
        ACPI_FLUSH_CPU_CACHE();
 
        /* This shouldn't return.  If it returns, we have a problem */
-       status = acpi_enter_sleep_state(ACPI_STATE_S4, wake_sleep_flags);
-       /* Reprogram control registers and execute _BFS */
-       acpi_leave_sleep_state_prep(ACPI_STATE_S4, wake_sleep_flags);
+       status = acpi_enter_sleep_state(ACPI_STATE_S4);
+       /* Reprogram control registers */
+       acpi_leave_sleep_state_prep(ACPI_STATE_S4);
 
        return ACPI_SUCCESS(status) ? 0 : -EFAULT;
 }
@@ -617,8 +589,8 @@ static void acpi_hibernation_leave(void)
         * enable it here.
         */
        acpi_enable();
-       /* Reprogram control registers and execute _BFS */
-       acpi_leave_sleep_state_prep(ACPI_STATE_S4, wake_sleep_flags);
+       /* Reprogram control registers */
+       acpi_leave_sleep_state_prep(ACPI_STATE_S4);
        /* Check the hardware signature */
        if (facs && s4_hardware_signature != facs->hardware_signature) {
                printk(KERN_EMERG "ACPI: Hardware changed while hibernated, "
@@ -892,33 +864,7 @@ static void acpi_power_off(void)
        /* acpi_sleep_prepare(ACPI_STATE_S5) should have already been called */
        printk(KERN_DEBUG "%s called\n", __func__);
        local_irq_disable();
-       acpi_enter_sleep_state(ACPI_STATE_S5, wake_sleep_flags);
-}
-
-/*
- * ACPI 2.0 created the optional _GTS and _BFS,
- * but industry adoption has been neither rapid nor broad.
- *
- * Linux gets into trouble when it executes poorly validated
- * paths through the BIOS, so disable _GTS and _BFS by default,
- * but do speak up and offer the option to enable them.
- */
-static void __init acpi_gts_bfs_check(void)
-{
-       acpi_handle dummy;
-
-       if (ACPI_SUCCESS(acpi_get_handle(ACPI_ROOT_OBJECT, METHOD_PATHNAME__GTS, &dummy)))
-       {
-               printk(KERN_NOTICE PREFIX "BIOS offers _GTS\n");
-               printk(KERN_NOTICE PREFIX "If \"acpi.gts=1\" improves suspend, "
-                       "please notify linux-acpi@vger.kernel.org\n");
-       }
-       if (ACPI_SUCCESS(acpi_get_handle(ACPI_ROOT_OBJECT, METHOD_PATHNAME__BFS, &dummy)))
-       {
-               printk(KERN_NOTICE PREFIX "BIOS offers _BFS\n");
-               printk(KERN_NOTICE PREFIX "If \"acpi.bfs=1\" improves resume, "
-                       "please notify linux-acpi@vger.kernel.org\n");
-       }
+       acpi_enter_sleep_state(ACPI_STATE_S5);
 }
 
 int __init acpi_sleep_init(void)
@@ -979,6 +925,5 @@ int __init acpi_sleep_init(void)
         * object can also be evaluated when the system enters S5.
         */
        register_reboot_notifier(&tts_notifier);
-       acpi_gts_bfs_check();
        return 0;
 }
index 240a24400976929c663b9b3f8ce8bafa36435d5f..7c3f98ba4afefd00686fffc36283ad783a3e4798 100644 (file)
@@ -173,7 +173,7 @@ static int param_set_trace_state(const char *val, struct kernel_param *kp)
 {
        int result = 0;
 
-       if (!strncmp(val, "enable", strlen("enable"))) {
+       if (!strncmp(val, "enable", sizeof("enable") - 1)) {
                result = acpi_debug_trace(trace_method_name, trace_debug_level,
                                          trace_debug_layer, 0);
                if (result)
@@ -181,7 +181,7 @@ static int param_set_trace_state(const char *val, struct kernel_param *kp)
                goto exit;
        }
 
-       if (!strncmp(val, "disable", strlen("disable"))) {
+       if (!strncmp(val, "disable", sizeof("disable") - 1)) {
                int name = 0;
                result = acpi_debug_trace((char *)&name, trace_debug_level,
                                          trace_debug_layer, 0);
index 9fe90e9fecb56ada8629a55c472c67653bbd02f5..804204d41999d0af951086f25b37a2f7ee783a90 100644 (file)
@@ -106,7 +106,9 @@ static const struct acpi_device_id  thermal_device_ids[] = {
 };
 MODULE_DEVICE_TABLE(acpi, thermal_device_ids);
 
+#ifdef CONFIG_PM_SLEEP
 static int acpi_thermal_resume(struct device *dev);
+#endif
 static SIMPLE_DEV_PM_OPS(acpi_thermal_pm, NULL, acpi_thermal_resume);
 
 static struct acpi_driver acpi_thermal_driver = {
@@ -706,6 +708,40 @@ static int thermal_get_crit_temp(struct thermal_zone_device *thermal,
                return -EINVAL;
 }
 
+static int thermal_get_trend(struct thermal_zone_device *thermal,
+                               int trip, enum thermal_trend *trend)
+{
+       struct acpi_thermal *tz = thermal->devdata;
+       enum thermal_trip_type type;
+       int i;
+
+       if (thermal_get_trip_type(thermal, trip, &type))
+               return -EINVAL;
+
+       if (type == THERMAL_TRIP_ACTIVE) {
+               /* aggressive active cooling */
+               *trend = THERMAL_TREND_RAISING;
+               return 0;
+       }
+
+       /*
+        * tz->temperature has already been updated by generic thermal layer,
+        * before this callback being invoked
+        */
+       i = (tz->trips.passive.tc1 * (tz->temperature - tz->last_temperature))
+               + (tz->trips.passive.tc2
+               * (tz->temperature - tz->trips.passive.temperature));
+
+       if (i > 0)
+               *trend = THERMAL_TREND_RAISING;
+       else if (i < 0)
+               *trend = THERMAL_TREND_DROPPING;
+       else
+               *trend = THERMAL_TREND_STABLE;
+       return 0;
+}
+
+
 static int thermal_notify(struct thermal_zone_device *thermal, int trip,
                           enum thermal_trip_type trip_type)
 {
@@ -729,11 +765,9 @@ static int thermal_notify(struct thermal_zone_device *thermal, int trip,
        return 0;
 }
 
-typedef int (*cb)(struct thermal_zone_device *, int,
-                 struct thermal_cooling_device *);
 static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
                                        struct thermal_cooling_device *cdev,
-                                       cb action)
+                                       bool bind)
 {
        struct acpi_device *device = cdev->devdata;
        struct acpi_thermal *tz = thermal->devdata;
@@ -757,11 +791,19 @@ static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
                    i++) {
                        handle = tz->trips.passive.devices.handles[i];
                        status = acpi_bus_get_device(handle, &dev);
-                       if (ACPI_SUCCESS(status) && (dev == device)) {
-                               result = action(thermal, trip, cdev);
-                               if (result)
-                                       goto failed;
-                       }
+                       if (ACPI_FAILURE(status) || dev != device)
+                               continue;
+                       if (bind)
+                               result =
+                                       thermal_zone_bind_cooling_device
+                                       (thermal, trip, cdev,
+                                        THERMAL_NO_LIMIT, THERMAL_NO_LIMIT);
+                       else
+                               result =
+                                       thermal_zone_unbind_cooling_device
+                                       (thermal, trip, cdev);
+                       if (result)
+                               goto failed;
                }
        }
 
@@ -774,11 +816,17 @@ static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
                    j++) {
                        handle = tz->trips.active[i].devices.handles[j];
                        status = acpi_bus_get_device(handle, &dev);
-                       if (ACPI_SUCCESS(status) && (dev == device)) {
-                               result = action(thermal, trip, cdev);
-                               if (result)
-                                       goto failed;
-                       }
+                       if (ACPI_FAILURE(status) || dev != device)
+                               continue;
+                       if (bind)
+                               result = thermal_zone_bind_cooling_device
+                                       (thermal, trip, cdev,
+                                        THERMAL_NO_LIMIT, THERMAL_NO_LIMIT);
+                       else
+                               result = thermal_zone_unbind_cooling_device
+                                       (thermal, trip, cdev);
+                       if (result)
+                               goto failed;
                }
        }
 
@@ -786,7 +834,14 @@ static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
                handle = tz->devices.handles[i];
                status = acpi_bus_get_device(handle, &dev);
                if (ACPI_SUCCESS(status) && (dev == device)) {
-                       result = action(thermal, -1, cdev);
+                       if (bind)
+                               result = thermal_zone_bind_cooling_device
+                                               (thermal, -1, cdev,
+                                                THERMAL_NO_LIMIT,
+                                                THERMAL_NO_LIMIT);
+                       else
+                               result = thermal_zone_unbind_cooling_device
+                                               (thermal, -1, cdev);
                        if (result)
                                goto failed;
                }
@@ -800,16 +855,14 @@ static int
 acpi_thermal_bind_cooling_device(struct thermal_zone_device *thermal,
                                        struct thermal_cooling_device *cdev)
 {
-       return acpi_thermal_cooling_device_cb(thermal, cdev,
-                               thermal_zone_bind_cooling_device);
+       return acpi_thermal_cooling_device_cb(thermal, cdev, true);
 }
 
 static int
 acpi_thermal_unbind_cooling_device(struct thermal_zone_device *thermal,
                                        struct thermal_cooling_device *cdev)
 {
-       return acpi_thermal_cooling_device_cb(thermal, cdev,
-                               thermal_zone_unbind_cooling_device);
+       return acpi_thermal_cooling_device_cb(thermal, cdev, false);
 }
 
 static const struct thermal_zone_device_ops acpi_thermal_zone_ops = {
@@ -821,6 +874,7 @@ static const struct thermal_zone_device_ops acpi_thermal_zone_ops = {
        .get_trip_type = thermal_get_trip_type,
        .get_trip_temp = thermal_get_trip_temp,
        .get_crit_temp = thermal_get_crit_temp,
+       .get_trend = thermal_get_trend,
        .notify = thermal_notify,
 };
 
@@ -847,15 +901,12 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
                tz->thermal_zone =
                        thermal_zone_device_register("acpitz", trips, 0, tz,
                                                     &acpi_thermal_zone_ops,
-                                                    tz->trips.passive.tc1,
-                                                    tz->trips.passive.tc2,
                                                     tz->trips.passive.tsp*100,
                                                     tz->polling_frequency*100);
        else
                tz->thermal_zone =
                        thermal_zone_device_register("acpitz", trips, 0, tz,
-                                                    &acpi_thermal_zone_ops,
-                                                    0, 0, 0,
+                                                    &acpi_thermal_zone_ops, 0,
                                                     tz->polling_frequency*100);
        if (IS_ERR(tz->thermal_zone))
                return -ENODEV;
@@ -1041,6 +1092,7 @@ static int acpi_thermal_remove(struct acpi_device *device, int type)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int acpi_thermal_resume(struct device *dev)
 {
        struct acpi_thermal *tz;
@@ -1075,6 +1127,7 @@ static int acpi_thermal_resume(struct device *dev)
 
        return AE_OK;
 }
+#endif
 
 static int thermal_act(const struct dmi_system_id *d) {
 
index fadd5866d40fd29b2eb70df29e3d026e2e3722db..2d479b67d0b43c80c80fc826aa4649956159fc64 100644 (file)
@@ -5252,16 +5252,20 @@ bool ata_link_offline(struct ata_link *link)
 #ifdef CONFIG_PM
 static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
                               unsigned int action, unsigned int ehi_flags,
-                              int wait)
+                              int *async)
 {
        struct ata_link *link;
        unsigned long flags;
-       int rc;
+       int rc = 0;
 
        /* Previous resume operation might still be in
         * progress.  Wait for PM_PENDING to clear.
         */
        if (ap->pflags & ATA_PFLAG_PM_PENDING) {
+               if (async) {
+                       *async = -EAGAIN;
+                       return 0;
+               }
                ata_port_wait_eh(ap);
                WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
        }
@@ -5270,10 +5274,10 @@ static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
        spin_lock_irqsave(ap->lock, flags);
 
        ap->pm_mesg = mesg;
-       if (wait) {
-               rc = 0;
+       if (async)
+               ap->pm_result = async;
+       else
                ap->pm_result = &rc;
-       }
 
        ap->pflags |= ATA_PFLAG_PM_PENDING;
        ata_for_each_link(link, ap, HOST_FIRST) {
@@ -5286,7 +5290,7 @@ static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
        spin_unlock_irqrestore(ap->lock, flags);
 
        /* wait and check result */
-       if (wait) {
+       if (!async) {
                ata_port_wait_eh(ap);
                WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING);
        }
@@ -5294,9 +5298,8 @@ static int ata_port_request_pm(struct ata_port *ap, pm_message_t mesg,
        return rc;
 }
 
-static int ata_port_suspend_common(struct device *dev, pm_message_t mesg)
+static int __ata_port_suspend_common(struct ata_port *ap, pm_message_t mesg, int *async)
 {
-       struct ata_port *ap = to_ata_port(dev);
        unsigned int ehi_flags = ATA_EHI_QUIET;
        int rc;
 
@@ -5311,10 +5314,17 @@ static int ata_port_suspend_common(struct device *dev, pm_message_t mesg)
        if (mesg.event == PM_EVENT_SUSPEND)
                ehi_flags |= ATA_EHI_NO_AUTOPSY | ATA_EHI_NO_RECOVERY;
 
-       rc = ata_port_request_pm(ap, mesg, 0, ehi_flags, 1);
+       rc = ata_port_request_pm(ap, mesg, 0, ehi_flags, async);
        return rc;
 }
 
+static int ata_port_suspend_common(struct device *dev, pm_message_t mesg)
+{
+       struct ata_port *ap = to_ata_port(dev);
+
+       return __ata_port_suspend_common(ap, mesg, NULL);
+}
+
 static int ata_port_suspend(struct device *dev)
 {
        if (pm_runtime_suspended(dev))
@@ -5339,16 +5349,22 @@ static int ata_port_poweroff(struct device *dev)
        return ata_port_suspend_common(dev, PMSG_HIBERNATE);
 }
 
-static int ata_port_resume_common(struct device *dev)
+static int __ata_port_resume_common(struct ata_port *ap, int *async)
 {
-       struct ata_port *ap = to_ata_port(dev);
        int rc;
 
        rc = ata_port_request_pm(ap, PMSG_ON, ATA_EH_RESET,
-               ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, 1);
+               ATA_EHI_NO_AUTOPSY | ATA_EHI_QUIET, async);
        return rc;
 }
 
+static int ata_port_resume_common(struct device *dev)
+{
+       struct ata_port *ap = to_ata_port(dev);
+
+       return __ata_port_resume_common(ap, NULL);
+}
+
 static int ata_port_resume(struct device *dev)
 {
        int rc;
@@ -5381,6 +5397,24 @@ static const struct dev_pm_ops ata_port_pm_ops = {
        .runtime_idle = ata_port_runtime_idle,
 };
 
+/* sas ports don't participate in pm runtime management of ata_ports,
+ * and need to resume ata devices at the domain level, not the per-port
+ * level. sas suspend/resume is async to allow parallel port recovery
+ * since sas has multiple ata_port instances per Scsi_Host.
+ */
+int ata_sas_port_async_suspend(struct ata_port *ap, int *async)
+{
+       return __ata_port_suspend_common(ap, PMSG_SUSPEND, async);
+}
+EXPORT_SYMBOL_GPL(ata_sas_port_async_suspend);
+
+int ata_sas_port_async_resume(struct ata_port *ap, int *async)
+{
+       return __ata_port_resume_common(ap, async);
+}
+EXPORT_SYMBOL_GPL(ata_sas_port_async_resume);
+
+
 /**
  *     ata_host_suspend - suspend host
  *     @host: host to suspend
@@ -5926,24 +5960,18 @@ int ata_host_start(struct ata_host *host)
 }
 
 /**
- *     ata_sas_host_init - Initialize a host struct
+ *     ata_sas_host_init - Initialize a host struct for sas (ipr, libsas)
  *     @host:  host to initialize
  *     @dev:   device host is attached to
- *     @flags: host flags
  *     @ops:   port_ops
  *
- *     LOCKING:
- *     PCI/etc. bus probe sem.
- *
  */
-/* KILLME - the only user left is ipr */
 void ata_host_init(struct ata_host *host, struct device *dev,
-                  unsigned long flags, struct ata_port_operations *ops)
+                  struct ata_port_operations *ops)
 {
        spin_lock_init(&host->lock);
        mutex_init(&host->eh_mutex);
        host->dev = dev;
-       host->flags = flags;
        host->ops = ops;
 }
 
@@ -6387,6 +6415,7 @@ static int __init ata_parse_force_one(char **cur,
                { "nohrst",     .lflags         = ATA_LFLAG_NO_HRST },
                { "nosrst",     .lflags         = ATA_LFLAG_NO_SRST },
                { "norst",      .lflags         = ATA_LFLAG_NO_HRST | ATA_LFLAG_NO_SRST },
+               { "rstonce",    .lflags         = ATA_LFLAG_RST_ONCE },
        };
        char *start = *cur, *p = *cur;
        char *id, *val, *endp;
index 7d4535e989bf5580d76909c2402460898ff86062..100428dde4219527f6f61b45781a46da93f9eedc 100644 (file)
@@ -2623,6 +2623,8 @@ int ata_eh_reset(struct ata_link *link, int classify,
         */
        while (ata_eh_reset_timeouts[max_tries] != ULONG_MAX)
                max_tries++;
+       if (link->flags & ATA_LFLAG_RST_ONCE)
+               max_tries = 1;
        if (link->flags & ATA_LFLAG_NO_HRST)
                hardreset = NULL;
        if (link->flags & ATA_LFLAG_NO_SRST)
index d4386019af5d59657812021e608a506adde44fe3..96cce6d5319592b20fbc8536c350d3cffdd841e8 100644 (file)
@@ -2362,7 +2362,7 @@ static int __devinit ia_init(struct atm_dev *dev)
        {  
                printk(DEV_LABEL " (itf %d): can't set up page mapping\n",  
                            dev->number);  
-               return error;  
+               return -ENOMEM;
        }  
        IF_INIT(printk(DEV_LABEL " (itf %d): rev.%d,base=%p,irq=%d\n",  
                        dev->number, iadev->pci->revision, base, iadev->irq);)
index f338037a4f3d9109e4d69da7a22a4e41070615b4..cdd01c52c629a61d8a2b4632b9115147595dbb44 100644 (file)
@@ -1865,6 +1865,7 @@ int __dev_printk(const char *level, const struct device *dev,
                 struct va_format *vaf)
 {
        char dict[128];
+       const char *level_extra = "";
        size_t dictlen = 0;
        const char *subsys;
 
@@ -1911,10 +1912,14 @@ int __dev_printk(const char *level, const struct device *dev,
                                    "DEVICE=+%s:%s", subsys, dev_name(dev));
        }
 skip:
+       if (level[3])
+               level_extra = &level[3]; /* skip past "<L>" */
+
        return printk_emit(0, level[1] - '0',
                           dictlen ? dict : NULL, dictlen,
-                          "%s %s: %pV",
-                          dev_driver_string(dev), dev_name(dev), vaf);
+                          "%s %s: %s%pV",
+                          dev_driver_string(dev), dev_name(dev),
+                          level_extra, vaf);
 }
 EXPORT_SYMBOL(__dev_printk);
 
index a1a72250258705eb059b6601b086cf9d296b1d1b..d51514b79efedc4ad446e5ce6dd87a8ee9d2fb6d 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/pm_runtime.h>
 
 #include "base.h"
+#include "power/power.h"
 
 #define to_platform_driver(drv)        (container_of((drv), struct platform_driver, \
                                 driver))
@@ -948,6 +949,7 @@ void __init early_platform_add_devices(struct platform_device **devs, int num)
                dev = &devs[i]->dev;
 
                if (!dev->devres_head.next) {
+                       pm_runtime_early_init(dev);
                        INIT_LIST_HEAD(&dev->devres_head);
                        list_add_tail(&dev->devres_head,
                                      &early_platform_device_list);
index 869d7ff2227f8aa87ba5a390644558e7e0585099..eb78e9640c4a86c0df9c0464e7dbd0b37f4ab75d 100644 (file)
@@ -169,8 +169,7 @@ void pm_clk_init(struct device *dev)
  */
 int pm_clk_create(struct device *dev)
 {
-       int ret = dev_pm_get_subsys_data(dev);
-       return ret < 0 ? ret : 0;
+       return dev_pm_get_subsys_data(dev);
 }
 
 /**
index a14085cc613fdfd2116afeb9da0f620b96c492f7..39c32529b83374c36eda18188c393930732ad99f 100644 (file)
@@ -24,7 +24,6 @@
 int dev_pm_get_subsys_data(struct device *dev)
 {
        struct pm_subsys_data *psd;
-       int ret = 0;
 
        psd = kzalloc(sizeof(*psd), GFP_KERNEL);
        if (!psd)
@@ -40,7 +39,6 @@ int dev_pm_get_subsys_data(struct device *dev)
                dev->power.subsys_data = psd;
                pm_clk_init(dev);
                psd = NULL;
-               ret = 1;
        }
 
        spin_unlock_irq(&dev->power.lock);
@@ -48,7 +46,7 @@ int dev_pm_get_subsys_data(struct device *dev)
        /* kfree() verifies that its argument is nonzero. */
        kfree(psd);
 
-       return ret;
+       return 0;
 }
 EXPORT_SYMBOL_GPL(dev_pm_get_subsys_data);
 
index ba3487c9835b67fa64daad5f6e23016f23a7f569..12ad070c244f057bca5179c6fec27fd3dce2a9d1 100644 (file)
 static LIST_HEAD(gpd_list);
 static DEFINE_MUTEX(gpd_list_lock);
 
+static struct generic_pm_domain *pm_genpd_lookup_name(const char *domain_name)
+{
+       struct generic_pm_domain *genpd = NULL, *gpd;
+
+       if (IS_ERR_OR_NULL(domain_name))
+               return NULL;
+
+       mutex_lock(&gpd_list_lock);
+       list_for_each_entry(gpd, &gpd_list, gpd_list_node) {
+               if (!strcmp(gpd->name, domain_name)) {
+                       genpd = gpd;
+                       break;
+               }
+       }
+       mutex_unlock(&gpd_list_lock);
+       return genpd;
+}
+
 #ifdef CONFIG_PM
 
 struct generic_pm_domain *dev_to_genpd(struct device *dev)
@@ -75,6 +93,12 @@ static int genpd_start_dev(struct generic_pm_domain *genpd, struct device *dev)
                                        start_latency_ns, "start");
 }
 
+static int genpd_start_dev_no_timing(struct generic_pm_domain *genpd,
+                                    struct device *dev)
+{
+       return GENPD_DEV_CALLBACK(genpd, int, start, dev);
+}
+
 static bool genpd_sd_counter_dec(struct generic_pm_domain *genpd)
 {
        bool ret = false;
@@ -256,6 +280,18 @@ int pm_genpd_poweron(struct generic_pm_domain *genpd)
        return ret;
 }
 
+/**
+ * pm_genpd_name_poweron - Restore power to a given PM domain and its masters.
+ * @domain_name: Name of the PM domain to power up.
+ */
+int pm_genpd_name_poweron(const char *domain_name)
+{
+       struct generic_pm_domain *genpd;
+
+       genpd = pm_genpd_lookup_name(domain_name);
+       return genpd ? pm_genpd_poweron(genpd) : -EINVAL;
+}
+
 #endif /* CONFIG_PM */
 
 #ifdef CONFIG_PM_RUNTIME
@@ -436,7 +472,7 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
        not_suspended = 0;
        list_for_each_entry(pdd, &genpd->dev_list, list_node)
                if (pdd->dev->driver && (!pm_runtime_suspended(pdd->dev)
-                   || pdd->dev->power.irq_safe || to_gpd_data(pdd)->always_on))
+                   || pdd->dev->power.irq_safe))
                        not_suspended++;
 
        if (not_suspended > genpd->in_progress)
@@ -578,9 +614,6 @@ static int pm_genpd_runtime_suspend(struct device *dev)
 
        might_sleep_if(!genpd->dev_irq_safe);
 
-       if (dev_gpd_data(dev)->always_on)
-               return -EBUSY;
-
        stop_ok = genpd->gov ? genpd->gov->stop_ok : NULL;
        if (stop_ok && !stop_ok(dev))
                return -EBUSY;
@@ -629,7 +662,7 @@ static int pm_genpd_runtime_resume(struct device *dev)
 
        /* If power.irq_safe, the PM domain is never powered off. */
        if (dev->power.irq_safe)
-               return genpd_start_dev(genpd, dev);
+               return genpd_start_dev_no_timing(genpd, dev);
 
        mutex_lock(&genpd->lock);
        ret = __pm_genpd_poweron(genpd);
@@ -697,6 +730,24 @@ static inline void genpd_power_off_work_fn(struct work_struct *work) {}
 
 #ifdef CONFIG_PM_SLEEP
 
+/**
+ * pm_genpd_present - Check if the given PM domain has been initialized.
+ * @genpd: PM domain to check.
+ */
+static bool pm_genpd_present(struct generic_pm_domain *genpd)
+{
+       struct generic_pm_domain *gpd;
+
+       if (IS_ERR_OR_NULL(genpd))
+               return false;
+
+       list_for_each_entry(gpd, &gpd_list, gpd_list_node)
+               if (gpd == genpd)
+                       return true;
+
+       return false;
+}
+
 static bool genpd_dev_active_wakeup(struct generic_pm_domain *genpd,
                                    struct device *dev)
 {
@@ -750,9 +801,10 @@ static int genpd_thaw_dev(struct generic_pm_domain *genpd, struct device *dev)
  * Check if the given PM domain can be powered off (during system suspend or
  * hibernation) and do that if so.  Also, in that case propagate to its masters.
  *
- * This function is only called in "noirq" stages of system power transitions,
- * so it need not acquire locks (all of the "noirq" callbacks are executed
- * sequentially, so it is guaranteed that it will never run twice in parallel).
+ * This function is only called in "noirq" and "syscore" stages of system power
+ * transitions, so it need not acquire locks (all of the "noirq" callbacks are
+ * executed sequentially, so it is guaranteed that it will never run twice in
+ * parallel).
  */
 static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd)
 {
@@ -776,6 +828,33 @@ static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd)
        }
 }
 
+/**
+ * pm_genpd_sync_poweron - Synchronously power on a PM domain and its masters.
+ * @genpd: PM domain to power on.
+ *
+ * This function is only called in "noirq" and "syscore" stages of system power
+ * transitions, so it need not acquire locks (all of the "noirq" callbacks are
+ * executed sequentially, so it is guaranteed that it will never run twice in
+ * parallel).
+ */
+static void pm_genpd_sync_poweron(struct generic_pm_domain *genpd)
+{
+       struct gpd_link *link;
+
+       if (genpd->status != GPD_STATE_POWER_OFF)
+               return;
+
+       list_for_each_entry(link, &genpd->slave_links, slave_node) {
+               pm_genpd_sync_poweron(link->master);
+               genpd_sd_counter_inc(link->master);
+       }
+
+       if (genpd->power_on)
+               genpd->power_on(genpd);
+
+       genpd->status = GPD_STATE_ACTIVE;
+}
+
 /**
  * resume_needed - Check whether to resume a device before system suspend.
  * @dev: Device to check.
@@ -937,7 +1016,7 @@ static int pm_genpd_suspend_noirq(struct device *dev)
        if (IS_ERR(genpd))
                return -EINVAL;
 
-       if (genpd->suspend_power_off || dev_gpd_data(dev)->always_on
+       if (genpd->suspend_power_off
            || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev)))
                return 0;
 
@@ -970,7 +1049,7 @@ static int pm_genpd_resume_noirq(struct device *dev)
        if (IS_ERR(genpd))
                return -EINVAL;
 
-       if (genpd->suspend_power_off || dev_gpd_data(dev)->always_on
+       if (genpd->suspend_power_off
            || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev)))
                return 0;
 
@@ -979,7 +1058,7 @@ static int pm_genpd_resume_noirq(struct device *dev)
         * guaranteed that this function will never run twice in parallel for
         * the same PM domain, so it is not necessary to use locking here.
         */
-       pm_genpd_poweron(genpd);
+       pm_genpd_sync_poweron(genpd);
        genpd->suspended_count--;
 
        return genpd_start_dev(genpd, dev);
@@ -1090,8 +1169,7 @@ static int pm_genpd_freeze_noirq(struct device *dev)
        if (IS_ERR(genpd))
                return -EINVAL;
 
-       return genpd->suspend_power_off || dev_gpd_data(dev)->always_on ?
-               0 : genpd_stop_dev(genpd, dev);
+       return genpd->suspend_power_off ? 0 : genpd_stop_dev(genpd, dev);
 }
 
 /**
@@ -1111,8 +1189,7 @@ static int pm_genpd_thaw_noirq(struct device *dev)
        if (IS_ERR(genpd))
                return -EINVAL;
 
-       return genpd->suspend_power_off || dev_gpd_data(dev)->always_on ?
-               0 : genpd_start_dev(genpd, dev);
+       return genpd->suspend_power_off ? 0 : genpd_start_dev(genpd, dev);
 }
 
 /**
@@ -1186,8 +1263,8 @@ static int pm_genpd_restore_noirq(struct device *dev)
        if (genpd->suspended_count++ == 0) {
                /*
                 * The boot kernel might put the domain into arbitrary state,
-                * so make it appear as powered off to pm_genpd_poweron(), so
-                * that it tries to power it on in case it was really off.
+                * so make it appear as powered off to pm_genpd_sync_poweron(),
+                * so that it tries to power it on in case it was really off.
                 */
                genpd->status = GPD_STATE_POWER_OFF;
                if (genpd->suspend_power_off) {
@@ -1205,9 +1282,9 @@ static int pm_genpd_restore_noirq(struct device *dev)
        if (genpd->suspend_power_off)
                return 0;
 
-       pm_genpd_poweron(genpd);
+       pm_genpd_sync_poweron(genpd);
 
-       return dev_gpd_data(dev)->always_on ? 0 : genpd_start_dev(genpd, dev);
+       return genpd_start_dev(genpd, dev);
 }
 
 /**
@@ -1246,6 +1323,31 @@ static void pm_genpd_complete(struct device *dev)
        }
 }
 
+/**
+ * pm_genpd_syscore_switch - Switch power during system core suspend or resume.
+ * @dev: Device that normally is marked as "always on" to switch power for.
+ *
+ * This routine may only be called during the system core (syscore) suspend or
+ * resume phase for devices whose "always on" flags are set.
+ */
+void pm_genpd_syscore_switch(struct device *dev, bool suspend)
+{
+       struct generic_pm_domain *genpd;
+
+       genpd = dev_to_genpd(dev);
+       if (!pm_genpd_present(genpd))
+               return;
+
+       if (suspend) {
+               genpd->suspended_count++;
+               pm_genpd_sync_poweroff(genpd);
+       } else {
+               pm_genpd_sync_poweron(genpd);
+               genpd->suspended_count--;
+       }
+}
+EXPORT_SYMBOL_GPL(pm_genpd_syscore_switch);
+
 #else
 
 #define pm_genpd_prepare               NULL
@@ -1393,6 +1495,19 @@ int __pm_genpd_of_add_device(struct device_node *genpd_node, struct device *dev,
        return __pm_genpd_add_device(genpd, dev, td);
 }
 
+
+/**
+ * __pm_genpd_name_add_device - Find I/O PM domain and add a device to it.
+ * @domain_name: Name of the PM domain to add the device to.
+ * @dev: Device to be added.
+ * @td: Set of PM QoS timing parameters to attach to the device.
+ */
+int __pm_genpd_name_add_device(const char *domain_name, struct device *dev,
+                              struct gpd_timing_data *td)
+{
+       return __pm_genpd_add_device(pm_genpd_lookup_name(domain_name), dev, td);
+}
+
 /**
  * pm_genpd_remove_device - Remove a device from an I/O PM domain.
  * @genpd: PM domain to remove the device from.
@@ -1454,26 +1569,6 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
        return ret;
 }
 
-/**
- * pm_genpd_dev_always_on - Set/unset the "always on" flag for a given device.
- * @dev: Device to set/unset the flag for.
- * @val: The new value of the device's "always on" flag.
- */
-void pm_genpd_dev_always_on(struct device *dev, bool val)
-{
-       struct pm_subsys_data *psd;
-       unsigned long flags;
-
-       spin_lock_irqsave(&dev->power.lock, flags);
-
-       psd = dev_to_psd(dev);
-       if (psd && psd->domain_data)
-               to_gpd_data(psd->domain_data)->always_on = val;
-
-       spin_unlock_irqrestore(&dev->power.lock, flags);
-}
-EXPORT_SYMBOL_GPL(pm_genpd_dev_always_on);
-
 /**
  * pm_genpd_dev_need_restore - Set/unset the device's "need restore" flag.
  * @dev: Device to set/unset the flag for.
@@ -1505,7 +1600,8 @@ int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
        struct gpd_link *link;
        int ret = 0;
 
-       if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(subdomain))
+       if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(subdomain)
+           || genpd == subdomain)
                return -EINVAL;
 
  start:
@@ -1551,6 +1647,35 @@ int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
        return ret;
 }
 
+/**
+ * pm_genpd_add_subdomain_names - Add a subdomain to an I/O PM domain.
+ * @master_name: Name of the master PM domain to add the subdomain to.
+ * @subdomain_name: Name of the subdomain to be added.
+ */
+int pm_genpd_add_subdomain_names(const char *master_name,
+                                const char *subdomain_name)
+{
+       struct generic_pm_domain *master = NULL, *subdomain = NULL, *gpd;
+
+       if (IS_ERR_OR_NULL(master_name) || IS_ERR_OR_NULL(subdomain_name))
+               return -EINVAL;
+
+       mutex_lock(&gpd_list_lock);
+       list_for_each_entry(gpd, &gpd_list, gpd_list_node) {
+               if (!master && !strcmp(gpd->name, master_name))
+                       master = gpd;
+
+               if (!subdomain && !strcmp(gpd->name, subdomain_name))
+                       subdomain = gpd;
+
+               if (master && subdomain)
+                       break;
+       }
+       mutex_unlock(&gpd_list_lock);
+
+       return pm_genpd_add_subdomain(master, subdomain);
+}
+
 /**
  * pm_genpd_remove_subdomain - Remove a subdomain from an I/O PM domain.
  * @genpd: Master PM domain to remove the subdomain from.
@@ -1704,7 +1829,16 @@ int __pm_genpd_remove_callbacks(struct device *dev, bool clear_td)
 }
 EXPORT_SYMBOL_GPL(__pm_genpd_remove_callbacks);
 
-int genpd_attach_cpuidle(struct generic_pm_domain *genpd, int state)
+/**
+ * pm_genpd_attach_cpuidle - Connect the given PM domain with cpuidle.
+ * @genpd: PM domain to be connected with cpuidle.
+ * @state: cpuidle state this domain can disable/enable.
+ *
+ * Make a PM domain behave as though it contained a CPU core, that is, instead
+ * of calling its power down routine it will enable the given cpuidle state so
+ * that the cpuidle subsystem can power it down (if possible and desirable).
+ */
+int pm_genpd_attach_cpuidle(struct generic_pm_domain *genpd, int state)
 {
        struct cpuidle_driver *cpuidle_drv;
        struct gpd_cpu_data *cpu_data;
@@ -1753,7 +1887,24 @@ int genpd_attach_cpuidle(struct generic_pm_domain *genpd, int state)
        goto out;
 }
 
-int genpd_detach_cpuidle(struct generic_pm_domain *genpd)
+/**
+ * pm_genpd_name_attach_cpuidle - Find PM domain and connect cpuidle to it.
+ * @name: Name of the domain to connect to cpuidle.
+ * @state: cpuidle state this domain can manipulate.
+ */
+int pm_genpd_name_attach_cpuidle(const char *name, int state)
+{
+       return pm_genpd_attach_cpuidle(pm_genpd_lookup_name(name), state);
+}
+
+/**
+ * pm_genpd_detach_cpuidle - Remove the cpuidle connection from a PM domain.
+ * @genpd: PM domain to remove the cpuidle connection from.
+ *
+ * Remove the cpuidle connection set up by pm_genpd_attach_cpuidle() from the
+ * given PM domain.
+ */
+int pm_genpd_detach_cpuidle(struct generic_pm_domain *genpd)
 {
        struct gpd_cpu_data *cpu_data;
        struct cpuidle_state *idle_state;
@@ -1784,6 +1935,15 @@ int genpd_detach_cpuidle(struct generic_pm_domain *genpd)
        return ret;
 }
 
+/**
+ * pm_genpd_name_detach_cpuidle - Find PM domain and disconnect cpuidle from it.
+ * @name: Name of the domain to disconnect cpuidle from.
+ */
+int pm_genpd_name_detach_cpuidle(const char *name)
+{
+       return pm_genpd_detach_cpuidle(pm_genpd_lookup_name(name));
+}
+
 /* Default device callbacks for generic PM domains. */
 
 /**
index 0113adc310dccc4a62a325cccde4221f34c5ce7e..57f5814c2732783d7c4f06c756728465f185fa2c 100644 (file)
@@ -57,20 +57,17 @@ static pm_message_t pm_transition;
 static int async_error;
 
 /**
- * device_pm_init - Initialize the PM-related part of a device object.
+ * device_pm_sleep_init - Initialize system suspend-related device fields.
  * @dev: Device object being initialized.
  */
-void device_pm_init(struct device *dev)
+void device_pm_sleep_init(struct device *dev)
 {
        dev->power.is_prepared = false;
        dev->power.is_suspended = false;
        init_completion(&dev->power.completion);
        complete_all(&dev->power.completion);
        dev->power.wakeup = NULL;
-       spin_lock_init(&dev->power.lock);
-       pm_runtime_init(dev);
        INIT_LIST_HEAD(&dev->power.entry);
-       dev->power.power_state = PMSG_INVALID;
 }
 
 /**
@@ -408,6 +405,9 @@ static int device_resume_noirq(struct device *dev, pm_message_t state)
        TRACE_DEVICE(dev);
        TRACE_RESUME(0);
 
+       if (dev->power.syscore)
+               goto Out;
+
        if (dev->pm_domain) {
                info = "noirq power domain ";
                callback = pm_noirq_op(&dev->pm_domain->ops, state);
@@ -429,6 +429,7 @@ static int device_resume_noirq(struct device *dev, pm_message_t state)
 
        error = dpm_run_callback(callback, dev, state, info);
 
+ Out:
        TRACE_RESUME(error);
        return error;
 }
@@ -486,6 +487,9 @@ static int device_resume_early(struct device *dev, pm_message_t state)
        TRACE_DEVICE(dev);
        TRACE_RESUME(0);
 
+       if (dev->power.syscore)
+               goto Out;
+
        if (dev->pm_domain) {
                info = "early power domain ";
                callback = pm_late_early_op(&dev->pm_domain->ops, state);
@@ -507,6 +511,7 @@ static int device_resume_early(struct device *dev, pm_message_t state)
 
        error = dpm_run_callback(callback, dev, state, info);
 
+ Out:
        TRACE_RESUME(error);
        return error;
 }
@@ -570,6 +575,9 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
        TRACE_DEVICE(dev);
        TRACE_RESUME(0);
 
+       if (dev->power.syscore)
+               goto Complete;
+
        dpm_wait(dev->parent, async);
        device_lock(dev);
 
@@ -632,6 +640,8 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
 
  Unlock:
        device_unlock(dev);
+
+ Complete:
        complete_all(&dev->power.completion);
 
        TRACE_RESUME(error);
@@ -722,6 +732,9 @@ static void device_complete(struct device *dev, pm_message_t state)
        void (*callback)(struct device *) = NULL;
        char *info = NULL;
 
+       if (dev->power.syscore)
+               return;
+
        device_lock(dev);
 
        if (dev->pm_domain) {
@@ -834,6 +847,9 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state)
        pm_callback_t callback = NULL;
        char *info = NULL;
 
+       if (dev->power.syscore)
+               return 0;
+
        if (dev->pm_domain) {
                info = "noirq power domain ";
                callback = pm_noirq_op(&dev->pm_domain->ops, state);
@@ -917,6 +933,9 @@ static int device_suspend_late(struct device *dev, pm_message_t state)
        pm_callback_t callback = NULL;
        char *info = NULL;
 
+       if (dev->power.syscore)
+               return 0;
+
        if (dev->pm_domain) {
                info = "late power domain ";
                callback = pm_late_early_op(&dev->pm_domain->ops, state);
@@ -1053,6 +1072,9 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
                goto Complete;
        }
 
+       if (dev->power.syscore)
+               goto Complete;
+
        device_lock(dev);
 
        if (dev->pm_domain) {
@@ -1209,6 +1231,9 @@ static int device_prepare(struct device *dev, pm_message_t state)
        char *info = NULL;
        int error = 0;
 
+       if (dev->power.syscore)
+               return 0;
+
        device_lock(dev);
 
        dev->power.wakeup_path = device_may_wakeup(dev);
index eeb4bff9505cd6dccd5d2cb30671fd69105966ef..0dbfdf4419af8914136060f0b9c88838e4f2db4a 100644 (file)
@@ -1,12 +1,32 @@
 #include <linux/pm_qos.h>
 
+static inline void device_pm_init_common(struct device *dev)
+{
+       if (!dev->power.early_init) {
+               spin_lock_init(&dev->power.lock);
+               dev->power.power_state = PMSG_INVALID;
+               dev->power.early_init = true;
+       }
+}
+
 #ifdef CONFIG_PM_RUNTIME
 
+static inline void pm_runtime_early_init(struct device *dev)
+{
+       dev->power.disable_depth = 1;
+       device_pm_init_common(dev);
+}
+
 extern void pm_runtime_init(struct device *dev);
 extern void pm_runtime_remove(struct device *dev);
 
 #else /* !CONFIG_PM_RUNTIME */
 
+static inline void pm_runtime_early_init(struct device *dev)
+{
+       device_pm_init_common(dev);
+}
+
 static inline void pm_runtime_init(struct device *dev) {}
 static inline void pm_runtime_remove(struct device *dev) {}
 
@@ -25,7 +45,7 @@ static inline struct device *to_device(struct list_head *entry)
        return container_of(entry, struct device, power.entry);
 }
 
-extern void device_pm_init(struct device *dev);
+extern void device_pm_sleep_init(struct device *dev);
 extern void device_pm_add(struct device *);
 extern void device_pm_remove(struct device *);
 extern void device_pm_move_before(struct device *, struct device *);
@@ -34,12 +54,7 @@ extern void device_pm_move_last(struct device *);
 
 #else /* !CONFIG_PM_SLEEP */
 
-static inline void device_pm_init(struct device *dev)
-{
-       spin_lock_init(&dev->power.lock);
-       dev->power.power_state = PMSG_INVALID;
-       pm_runtime_init(dev);
-}
+static inline void device_pm_sleep_init(struct device *dev) {}
 
 static inline void device_pm_add(struct device *dev)
 {
@@ -60,6 +75,13 @@ static inline void device_pm_move_last(struct device *dev) {}
 
 #endif /* !CONFIG_PM_SLEEP */
 
+static inline void device_pm_init(struct device *dev)
+{
+       device_pm_init_common(dev);
+       device_pm_sleep_init(dev);
+       pm_runtime_init(dev);
+}
+
 #ifdef CONFIG_PM
 
 /*
index 59894873a3b37de88a50d3b5e1f22ce67e454858..7d9c1cb1c39a7760081bae4d518efd8acf835902 100644 (file)
@@ -147,6 +147,8 @@ static int rpm_check_suspend_allowed(struct device *dev)
            || (dev->power.request_pending
                        && dev->power.request == RPM_REQ_RESUME))
                retval = -EAGAIN;
+       else if (__dev_pm_qos_read_value(dev) < 0)
+               retval = -EPERM;
        else if (dev->power.runtime_status == RPM_SUSPENDED)
                retval = 1;
 
@@ -388,7 +390,6 @@ static int rpm_suspend(struct device *dev, int rpmflags)
                goto repeat;
        }
 
-       dev->power.deferred_resume = false;
        if (dev->power.no_callbacks)
                goto no_callback;       /* Assume success. */
 
@@ -403,12 +404,6 @@ static int rpm_suspend(struct device *dev, int rpmflags)
                goto out;
        }
 
-       if (__dev_pm_qos_read_value(dev) < 0) {
-               /* Negative PM QoS constraint means "never suspend". */
-               retval = -EPERM;
-               goto out;
-       }
-
        __update_runtime_status(dev, RPM_SUSPENDING);
 
        if (dev->pm_domain)
@@ -440,6 +435,7 @@ static int rpm_suspend(struct device *dev, int rpmflags)
        wake_up_all(&dev->power.wait_queue);
 
        if (dev->power.deferred_resume) {
+               dev->power.deferred_resume = false;
                rpm_resume(dev, 0);
                retval = -EAGAIN;
                goto out;
@@ -584,6 +580,7 @@ static int rpm_resume(struct device *dev, int rpmflags)
                    || dev->parent->power.runtime_status == RPM_ACTIVE) {
                        atomic_inc(&dev->parent->power.child_count);
                        spin_unlock(&dev->parent->power.lock);
+                       retval = 1;
                        goto no_callback;       /* Assume success. */
                }
                spin_unlock(&dev->parent->power.lock);
@@ -664,7 +661,7 @@ static int rpm_resume(struct device *dev, int rpmflags)
        }
        wake_up_all(&dev->power.wait_queue);
 
-       if (!retval)
+       if (retval >= 0)
                rpm_idle(dev, RPM_ASYNC);
 
  out:
index cbb463b3a750e30bc70d7d8de40ff7555e7670ee..8a0a9ca6ad65f4534892a1ce45bd2b25d1253bc3 100644 (file)
@@ -649,6 +649,31 @@ void pm_wakeup_event(struct device *dev, unsigned int msec)
 }
 EXPORT_SYMBOL_GPL(pm_wakeup_event);
 
+static void print_active_wakeup_sources(void)
+{
+       struct wakeup_source *ws;
+       int active = 0;
+       struct wakeup_source *last_activity_ws = NULL;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
+               if (ws->active) {
+                       pr_info("active wakeup source: %s\n", ws->name);
+                       active = 1;
+               } else if (!active &&
+                          (!last_activity_ws ||
+                           ktime_to_ns(ws->last_time) >
+                           ktime_to_ns(last_activity_ws->last_time))) {
+                       last_activity_ws = ws;
+               }
+       }
+
+       if (!active && last_activity_ws)
+               pr_info("last active wakeup source: %s\n",
+                       last_activity_ws->name);
+       rcu_read_unlock();
+}
+
 /**
  * pm_wakeup_pending - Check if power transition in progress should be aborted.
  *
@@ -671,6 +696,10 @@ bool pm_wakeup_pending(void)
                events_check_enabled = !ret;
        }
        spin_unlock_irqrestore(&events_lock, flags);
+
+       if (ret)
+               print_active_wakeup_sources();
+
        return ret;
 }
 
index a89734621e517e367b15b925ccd507da04daca89..bb5e1030519709f7aa2ca12118383be1e82c5bcb 100644 (file)
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/irqdomain.h>
+#include <linux/pm_runtime.h>
 #include <linux/slab.h>
 
 #include "internal.h"
 
 struct regmap_irq_chip_data {
        struct mutex lock;
+       struct irq_chip irq_chip;
 
        struct regmap *map;
        const struct regmap_irq_chip *chip;
@@ -59,6 +61,14 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
        struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
        struct regmap *map = d->map;
        int i, ret;
+       u32 reg;
+
+       if (d->chip->runtime_pm) {
+               ret = pm_runtime_get_sync(map->dev);
+               if (ret < 0)
+                       dev_err(map->dev, "IRQ sync failed to resume: %d\n",
+                               ret);
+       }
 
        /*
         * If there's been a change in the mask write it back to the
@@ -66,15 +76,18 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
         * suppress pointless writes.
         */
        for (i = 0; i < d->chip->num_regs; i++) {
-               ret = regmap_update_bits(d->map, d->chip->mask_base +
-                                               (i * map->reg_stride *
-                                               d->irq_reg_stride),
+               reg = d->chip->mask_base +
+                       (i * map->reg_stride * d->irq_reg_stride);
+               ret = regmap_update_bits(d->map, reg,
                                         d->mask_buf_def[i], d->mask_buf[i]);
                if (ret != 0)
                        dev_err(d->map->dev, "Failed to sync masks in %x\n",
-                               d->chip->mask_base + (i * map->reg_stride));
+                               reg);
        }
 
+       if (d->chip->runtime_pm)
+               pm_runtime_put(map->dev);
+
        /* If we've changed our wakeup count propagate it to the parent */
        if (d->wake_count < 0)
                for (i = d->wake_count; i < 0; i++)
@@ -128,8 +141,7 @@ static int regmap_irq_set_wake(struct irq_data *data, unsigned int on)
        return 0;
 }
 
-static struct irq_chip regmap_irq_chip = {
-       .name                   = "regmap",
+static const struct irq_chip regmap_irq_chip = {
        .irq_bus_lock           = regmap_irq_lock,
        .irq_bus_sync_unlock    = regmap_irq_sync_unlock,
        .irq_disable            = regmap_irq_disable,
@@ -144,6 +156,16 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
        struct regmap *map = data->map;
        int ret, i;
        bool handled = false;
+       u32 reg;
+
+       if (chip->runtime_pm) {
+               ret = pm_runtime_get_sync(map->dev);
+               if (ret < 0) {
+                       dev_err(map->dev, "IRQ thread failed to resume: %d\n",
+                               ret);
+                       return IRQ_NONE;
+               }
+       }
 
        /*
         * Ignore masked IRQs and ack if we need to; we ack early so
@@ -160,20 +182,20 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
                if (ret != 0) {
                        dev_err(map->dev, "Failed to read IRQ status: %d\n",
                                        ret);
+                       if (chip->runtime_pm)
+                               pm_runtime_put(map->dev);
                        return IRQ_NONE;
                }
 
                data->status_buf[i] &= ~data->mask_buf[i];
 
                if (data->status_buf[i] && chip->ack_base) {
-                       ret = regmap_write(map, chip->ack_base +
-                                               (i * map->reg_stride *
-                                               data->irq_reg_stride),
-                                          data->status_buf[i]);
+                       reg = chip->ack_base +
+                               (i * map->reg_stride * data->irq_reg_stride);
+                       ret = regmap_write(map, reg, data->status_buf[i]);
                        if (ret != 0)
                                dev_err(map->dev, "Failed to ack 0x%x: %d\n",
-                                       chip->ack_base + (i * map->reg_stride),
-                                       ret);
+                                       reg, ret);
                }
        }
 
@@ -185,6 +207,9 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
                }
        }
 
+       if (chip->runtime_pm)
+               pm_runtime_put(map->dev);
+
        if (handled)
                return IRQ_HANDLED;
        else
@@ -197,7 +222,7 @@ static int regmap_irq_map(struct irq_domain *h, unsigned int virq,
        struct regmap_irq_chip_data *data = h->host_data;
 
        irq_set_chip_data(virq, data);
-       irq_set_chip_and_handler(virq, &regmap_irq_chip, handle_edge_irq);
+       irq_set_chip_and_handler(virq, &data->irq_chip, handle_edge_irq);
        irq_set_nested_thread(virq, 1);
 
        /* ARM needs us to explicitly flag the IRQ as valid
@@ -238,6 +263,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
        struct regmap_irq_chip_data *d;
        int i;
        int ret = -ENOMEM;
+       u32 reg;
 
        for (i = 0; i < chip->num_irqs; i++) {
                if (chip->irqs[i].reg_offset % map->reg_stride)
@@ -284,6 +310,13 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
                        goto err_alloc;
        }
 
+       d->irq_chip = regmap_irq_chip;
+       d->irq_chip.name = chip->name;
+       if (!chip->wake_base) {
+               d->irq_chip.irq_set_wake = NULL;
+               d->irq_chip.flags |= IRQCHIP_MASK_ON_SUSPEND |
+                                    IRQCHIP_SKIP_SET_WAKE;
+       }
        d->irq = irq;
        d->map = map;
        d->chip = chip;
@@ -303,16 +336,33 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
        /* Mask all the interrupts by default */
        for (i = 0; i < chip->num_regs; i++) {
                d->mask_buf[i] = d->mask_buf_def[i];
-               ret = regmap_write(map, chip->mask_base + (i * map->reg_stride
-                                  * d->irq_reg_stride),
-                                  d->mask_buf[i]);
+               reg = chip->mask_base +
+                       (i * map->reg_stride * d->irq_reg_stride);
+               ret = regmap_update_bits(map, reg,
+                                        d->mask_buf[i], d->mask_buf[i]);
                if (ret != 0) {
                        dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
-                               chip->mask_base + (i * map->reg_stride), ret);
+                               reg, ret);
                        goto err_alloc;
                }
        }
 
+       /* Wake is disabled by default */
+       if (d->wake_buf) {
+               for (i = 0; i < chip->num_regs; i++) {
+                       d->wake_buf[i] = d->mask_buf_def[i];
+                       reg = chip->wake_base +
+                               (i * map->reg_stride * d->irq_reg_stride);
+                       ret = regmap_update_bits(map, reg, d->wake_buf[i],
+                                                d->wake_buf[i]);
+                       if (ret != 0) {
+                               dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
+                                       reg, ret);
+                               goto err_alloc;
+                       }
+               }
+       }
+
        if (irq_base)
                d->domain = irq_domain_add_legacy(map->dev->of_node,
                                                  chip->num_irqs, irq_base, 0,
index c241ae2f2f10b91e8998e5b657d5f739cc0c0b7b..52069d29ff12ef197c7d8a447ab27ffb7096d85e 100644 (file)
@@ -659,13 +659,12 @@ EXPORT_SYMBOL_GPL(devm_regmap_init);
  * new cache.  This can be used to restore the cache to defaults or to
  * update the cache configuration to reflect runtime discovery of the
  * hardware.
+ *
+ * No explicit locking is done here, the user needs to ensure that
+ * this function will not race with other calls to regmap.
  */
 int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
 {
-       int ret;
-
-       map->lock(map);
-
        regcache_exit(map);
        regmap_debugfs_exit(map);
 
@@ -681,11 +680,7 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
        map->cache_bypass = false;
        map->cache_only = false;
 
-       ret = regcache_init(map, config);
-
-       map->unlock(map);
-
-       return ret;
+       return regcache_init(map, config);
 }
 EXPORT_SYMBOL_GPL(regmap_reinit_cache);
 
index c9a4f46c5143e28309ca55b788471f1241c2afff..8b8f2f3862a21060267501925a697dbab4aeb429 100644 (file)
@@ -101,7 +101,7 @@ void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable)
        bcma_cc_write32(cc, BCMA_CC_CHIPCTL, val);
 }
 
-void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
+static void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
 {
        struct bcma_bus *bus = cc->core->bus;
 
@@ -257,7 +257,7 @@ static u32 bcma_pmu_clock_bcm4706(struct bcma_drv_cc *cc, u32 pll0, u32 m)
 }
 
 /* query bus clock frequency for PMU-enabled chipcommon */
-u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
+static u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
 {
        struct bcma_bus *bus = cc->core->bus;
 
index 11b32d2642dfc25dd4b1d22b30c9e3bf0cf65555..f7b0af7100cdf5cc0c074a09ddd842c0b459b715 100644 (file)
@@ -77,8 +77,8 @@ static void bcma_host_pci_write32(struct bcma_device *core, u16 offset,
 }
 
 #ifdef CONFIG_BCMA_BLOCKIO
-void bcma_host_pci_block_read(struct bcma_device *core, void *buffer,
-                             size_t count, u16 offset, u8 reg_width)
+static void bcma_host_pci_block_read(struct bcma_device *core, void *buffer,
+                                    size_t count, u16 offset, u8 reg_width)
 {
        void __iomem *addr = core->bus->mmio + offset;
        if (core->bus->mapped_core != core)
@@ -100,8 +100,9 @@ void bcma_host_pci_block_read(struct bcma_device *core, void *buffer,
        }
 }
 
-void bcma_host_pci_block_write(struct bcma_device *core, const void *buffer,
-                              size_t count, u16 offset, u8 reg_width)
+static void bcma_host_pci_block_write(struct bcma_device *core,
+                                     const void *buffer, size_t count,
+                                     u16 offset, u8 reg_width)
 {
        void __iomem *addr = core->bus->mmio + offset;
        if (core->bus->mapped_core != core)
@@ -139,7 +140,7 @@ static void bcma_host_pci_awrite32(struct bcma_device *core, u16 offset,
        iowrite32(value, core->bus->mmio + (1 * BCMA_CORE_SIZE) + offset);
 }
 
-const struct bcma_host_ops bcma_host_pci_ops = {
+static const struct bcma_host_ops bcma_host_pci_ops = {
        .read8          = bcma_host_pci_read8,
        .read16         = bcma_host_pci_read16,
        .read32         = bcma_host_pci_read32,
@@ -272,6 +273,7 @@ static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = {
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) },
+       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4359) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) },
        { 0, },
 };
index 3c381fb8f9c4797c2a413246ed90ac26305582cd..3475e600011a5c5ce0ec6ffe2b41f4f68b04c0e7 100644 (file)
@@ -143,7 +143,7 @@ static void bcma_host_soc_awrite32(struct bcma_device *core, u16 offset,
        writel(value, core->io_wrap + offset);
 }
 
-const struct bcma_host_ops bcma_host_soc_ops = {
+static const struct bcma_host_ops bcma_host_soc_ops = {
        .read8          = bcma_host_soc_read8,
        .read16         = bcma_host_soc_read16,
        .read32         = bcma_host_soc_read32,
index 26823d97fd9f60925967b51a4fdfc158454bbe1b..9ea4627dc0c233a808f322816c2560fd9c145d3d 100644 (file)
@@ -507,7 +507,9 @@ static bool bcma_sprom_onchip_available(struct bcma_bus *bus)
                /* for these chips OTP is always available */
                present = true;
                break;
-
+       case BCMA_CHIP_ID_BCM43228:
+               present = chip_status & BCMA_CC_CHIPST_43228_OTP_PRESENT;
+               break;
        default:
                present = false;
                break;
index 2e0e7fc1dbbaf50e24d8a446a4e20aeb2239f5bb..dbe6135a2abeddfb78b8d812f4b892c7b5696d03 100644 (file)
@@ -3537,9 +3537,9 @@ static void drbd_cleanup(void)
 }
 
 /**
- * drbd_congested() - Callback for pdflush
+ * drbd_congested() - Callback for the flusher thread
  * @congested_data:    User data
- * @bdi_bits:          Bits pdflush is currently interested in
+ * @bdi_bits:          Bits the BDI flusher thread is currently interested in
  *
  * Returns 1<<BDI_async_congested and/or 1<<BDI_sync_congested if we are congested.
  */
index 10308cd8a7ed2276f146c86c752383de5517464a..11f36e5021367d7dd7c2b0794241154a0544ad0a 100644 (file)
@@ -79,6 +79,7 @@ static struct usb_device_id ath3k_table[] = {
        { USB_DEVICE(0x13d3, 0x3362) },
        { USB_DEVICE(0x0CF3, 0xE004) },
        { USB_DEVICE(0x0930, 0x0219) },
+       { USB_DEVICE(0x0489, 0xe057) },
 
        /* Atheros AR5BBU12 with sflash firmware */
        { USB_DEVICE(0x0489, 0xE02C) },
@@ -104,6 +105,7 @@ static struct usb_device_id ath3k_blist_tbl[] = {
        { 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 },
 
        /* Atheros AR5BBU22 with sflash firmware */
        { USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 },
index 37ae175162f346a3316b4864b2f1eebefd9e9d71..364f82b34d036bca12cbf0d48ef16af9b8ad68d2 100644 (file)
@@ -177,7 +177,7 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id
        if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
                return -ENODEV;
 
-       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);
        if (!data) {
                BT_ERR("Can't allocate memory for data structure");
                return -ENOMEM;
@@ -189,14 +189,12 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id
        data->urb = usb_alloc_urb(0, GFP_KERNEL);
        if (!data->urb) {
                BT_ERR("Can't allocate URB");
-               kfree(data);
                return -ENOMEM;
        }
 
        if (request_firmware(&firmware, "BCM2033-MD.hex", &udev->dev) < 0) {
                BT_ERR("Mini driver request failed");
                usb_free_urb(data->urb);
-               kfree(data);
                return -EIO;
        }
 
@@ -209,7 +207,6 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id
                BT_ERR("Can't allocate memory for mini driver");
                release_firmware(firmware);
                usb_free_urb(data->urb);
-               kfree(data);
                return -ENOMEM;
        }
 
@@ -224,7 +221,6 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id
                BT_ERR("Firmware request failed");
                usb_free_urb(data->urb);
                kfree(data->buffer);
-               kfree(data);
                return -EIO;
        }
 
@@ -236,7 +232,6 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id
                release_firmware(firmware);
                usb_free_urb(data->urb);
                kfree(data->buffer);
-               kfree(data);
                return -ENOMEM;
        }
 
@@ -271,7 +266,6 @@ static void bcm203x_disconnect(struct usb_interface *intf)
        usb_free_urb(data->urb);
        kfree(data->fw_data);
        kfree(data->buffer);
-       kfree(data);
 }
 
 static struct usb_driver bcm203x_driver = {
index 32e825144fe9835bb30ef4693bf902d6a13fc87e..995aee9cba22a8d871289004a4cef5ec60cdeaa2 100644 (file)
@@ -653,7 +653,7 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
        }
 
        /* Initialize control structure and load firmware */
-       data = kzalloc(sizeof(struct bfusb_data), GFP_KERNEL);
+       data = devm_kzalloc(&intf->dev, sizeof(struct bfusb_data), GFP_KERNEL);
        if (!data) {
                BT_ERR("Can't allocate memory for control structure");
                goto done;
@@ -674,7 +674,7 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
 
        if (request_firmware(&firmware, "bfubase.frm", &udev->dev) < 0) {
                BT_ERR("Firmware request failed");
-               goto error;
+               goto done;
        }
 
        BT_DBG("firmware data %p size %zu", firmware->data, firmware->size);
@@ -690,7 +690,7 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
        hdev = hci_alloc_dev();
        if (!hdev) {
                BT_ERR("Can't allocate HCI device");
-               goto error;
+               goto done;
        }
 
        data->hdev = hdev;
@@ -708,7 +708,7 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
        if (hci_register_dev(hdev) < 0) {
                BT_ERR("Can't register HCI device");
                hci_free_dev(hdev);
-               goto error;
+               goto done;
        }
 
        usb_set_intfdata(intf, data);
@@ -718,9 +718,6 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
 release:
        release_firmware(firmware);
 
-error:
-       kfree(data);
-
 done:
        return -EIO;
 }
@@ -741,7 +738,6 @@ static void bfusb_disconnect(struct usb_interface *intf)
 
        hci_unregister_dev(hdev);
        hci_free_dev(hdev);
-       kfree(data);
 }
 
 static struct usb_driver bfusb_driver = {
index 66c3a6770c417a5dbb714a9c10ae029fc2675109..0c0838d9b56c2ec266c9ad92448787576a5170d6 100644 (file)
@@ -849,7 +849,7 @@ static int bluecard_probe(struct pcmcia_device *link)
        bluecard_info_t *info;
 
        /* Create new info device */
-       info = kzalloc(sizeof(*info), GFP_KERNEL);
+       info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
        if (!info)
                return -ENOMEM;
 
@@ -864,10 +864,7 @@ static int bluecard_probe(struct pcmcia_device *link)
 
 static void bluecard_detach(struct pcmcia_device *link)
 {
-       bluecard_info_t *info = link->priv;
-
        bluecard_release(link);
-       kfree(info);
 }
 
 
index 29caaed2d715bd6de4f8b355bc8bc11b9580a7b6..2fe4a8031348f0c8b05074eb9889a1d2e02a7a91 100644 (file)
@@ -443,7 +443,7 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *
        if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
                return -ENODEV;
 
-       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
@@ -453,10 +453,8 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *
        init_usb_anchor(&data->rx_anchor);
 
        hdev = hci_alloc_dev();
-       if (!hdev) {
-               kfree(data);
+       if (!hdev)
                return -ENOMEM;
-       }
 
        hdev->bus = HCI_USB;
        hci_set_drvdata(hdev, data);
@@ -475,7 +473,6 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *
        err = hci_register_dev(hdev);
        if (err < 0) {
                hci_free_dev(hdev);
-               kfree(data);
                return err;
        }
 
@@ -500,7 +497,6 @@ static void bpa10x_disconnect(struct usb_interface *intf)
        hci_free_dev(data->hdev);
        kfree_skb(data->rx_skb[0]);
        kfree_skb(data->rx_skb[1]);
-       kfree(data);
 }
 
 static struct usb_driver bpa10x_driver = {
index 8925b6d672a6ef7c14dc89741e7662fc3e057ef4..7ffd3f407144dc05c2bb2a9d9b29848efeeba347 100644 (file)
@@ -638,7 +638,7 @@ static int bt3c_probe(struct pcmcia_device *link)
        bt3c_info_t *info;
 
        /* Create new info device */
-       info = kzalloc(sizeof(*info), GFP_KERNEL);
+       info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
        if (!info)
                return -ENOMEM;
 
@@ -654,10 +654,7 @@ static int bt3c_probe(struct pcmcia_device *link)
 
 static void bt3c_detach(struct pcmcia_device *link)
 {
-       bt3c_info_t *info = link->priv;
-
        bt3c_release(link);
-       kfree(info);
 }
 
 static int bt3c_check_config(struct pcmcia_device *p_dev, void *priv_data)
index 6a9e9717d3ab8327da49160823ef136ada65e053..03b3acba61431a4cf7f0bfc0e5cadab2ef9b76ce 100644 (file)
@@ -956,11 +956,9 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
        BT_INFO("vendor=0x%x, device=0x%x, class=%d, fn=%d",
                        id->vendor, id->device, id->class, func->num);
 
-       card = kzalloc(sizeof(*card), GFP_KERNEL);
-       if (!card) {
-               ret = -ENOMEM;
-               goto done;
-       }
+       card = devm_kzalloc(&func->dev, sizeof(*card), GFP_KERNEL);
+       if (!card)
+               return -ENOMEM;
 
        card->func = func;
 
@@ -974,8 +972,7 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
 
        if (btmrvl_sdio_register_dev(card) < 0) {
                BT_ERR("Failed to register BT device!");
-               ret = -ENODEV;
-               goto free_card;
+               return -ENODEV;
        }
 
        /* Disable the interrupts on the card */
@@ -1023,9 +1020,6 @@ disable_host_int:
        btmrvl_sdio_disable_host_int(card);
 unreg_dev:
        btmrvl_sdio_unregister_dev(card);
-free_card:
-       kfree(card);
-done:
        return ret;
 }
 
@@ -1047,7 +1041,6 @@ static void btmrvl_sdio_remove(struct sdio_func *func)
                        BT_DBG("unregester dev");
                        btmrvl_sdio_unregister_dev(card);
                        btmrvl_remove_card(card->priv);
-                       kfree(card);
                }
        }
 }
index e10ea03470510f876bd3b09ef572630c4ef83e29..4a9909713874dd03eb52240b148ed83b9a22b9d8 100644 (file)
@@ -304,7 +304,7 @@ static int btsdio_probe(struct sdio_func *func,
                tuple = tuple->next;
        }
 
-       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       data = devm_kzalloc(&func->dev, sizeof(*data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
@@ -315,10 +315,8 @@ static int btsdio_probe(struct sdio_func *func,
        skb_queue_head_init(&data->txq);
 
        hdev = hci_alloc_dev();
-       if (!hdev) {
-               kfree(data);
+       if (!hdev)
                return -ENOMEM;
-       }
 
        hdev->bus = HCI_SDIO;
        hci_set_drvdata(hdev, data);
@@ -340,7 +338,6 @@ static int btsdio_probe(struct sdio_func *func,
        err = hci_register_dev(hdev);
        if (err < 0) {
                hci_free_dev(hdev);
-               kfree(data);
                return err;
        }
 
@@ -366,7 +363,6 @@ static void btsdio_remove(struct sdio_func *func)
        hci_unregister_dev(hdev);
 
        hci_free_dev(hdev);
-       kfree(data);
 }
 
 static struct sdio_driver btsdio_driver = {
index 21e803a6a281690af1d6598ba73d800fbf70c5dc..2f510a87b28f90ae1c01370cb1df21882108868e 100644 (file)
@@ -567,7 +567,7 @@ static int btuart_probe(struct pcmcia_device *link)
        btuart_info_t *info;
 
        /* Create new info device */
-       info = kzalloc(sizeof(*info), GFP_KERNEL);
+       info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
        if (!info)
                return -ENOMEM;
 
@@ -583,10 +583,7 @@ static int btuart_probe(struct pcmcia_device *link)
 
 static void btuart_detach(struct pcmcia_device *link)
 {
-       btuart_info_t *info = link->priv;
-
        btuart_release(link);
-       kfree(info);
 }
 
 static int btuart_check_config(struct pcmcia_device *p_dev, void *priv_data)
index e272214110365510fcfcbb6f6f3f75778f65ed46..fa2a7d5a6b4383f6a67978b706ae103c6dd4d0fb 100644 (file)
@@ -98,6 +98,7 @@ static struct usb_device_id btusb_table[] = {
        { USB_DEVICE(0x0a5c, 0x21e6) },
        { USB_DEVICE(0x0a5c, 0x21e8) },
        { USB_DEVICE(0x0a5c, 0x21f3) },
+       { USB_DEVICE(0x0a5c, 0x21f4) },
        { USB_DEVICE(0x413c, 0x8197) },
 
        /* Foxconn - Hon Hai */
@@ -133,6 +134,7 @@ static struct usb_device_id blacklist_table[] = {
        { 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 },
 
        /* Atheros AR5BBU12 with sflash firmware */
        { USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
@@ -952,7 +954,7 @@ static int btusb_probe(struct usb_interface *intf,
                        return -ENODEV;
        }
 
-       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
@@ -975,10 +977,8 @@ static int btusb_probe(struct usb_interface *intf,
                }
        }
 
-       if (!data->intr_ep || !data->bulk_tx_ep || !data->bulk_rx_ep) {
-               kfree(data);
+       if (!data->intr_ep || !data->bulk_tx_ep || !data->bulk_rx_ep)
                return -ENODEV;
-       }
 
        data->cmdreq_type = USB_TYPE_CLASS;
 
@@ -998,10 +998,8 @@ static int btusb_probe(struct usb_interface *intf,
        init_usb_anchor(&data->deferred);
 
        hdev = hci_alloc_dev();
-       if (!hdev) {
-               kfree(data);
+       if (!hdev)
                return -ENOMEM;
-       }
 
        hdev->bus = HCI_USB;
        hci_set_drvdata(hdev, data);
@@ -1069,7 +1067,6 @@ static int btusb_probe(struct usb_interface *intf,
                                                        data->isoc, data);
                if (err < 0) {
                        hci_free_dev(hdev);
-                       kfree(data);
                        return err;
                }
        }
@@ -1077,7 +1074,6 @@ static int btusb_probe(struct usb_interface *intf,
        err = hci_register_dev(hdev);
        if (err < 0) {
                hci_free_dev(hdev);
-               kfree(data);
                return err;
        }
 
@@ -1110,7 +1106,6 @@ static void btusb_disconnect(struct usb_interface *intf)
                usb_driver_release_interface(&btusb_driver, data->isoc);
 
        hci_free_dev(hdev);
-       kfree(data);
 }
 
 #ifdef CONFIG_PM
index 88694697f34f68386cdb4273289ccea7baaeaa5b..4ad7b35cfc0e1b46d0285e64d77aca460ae8b2bd 100644 (file)
@@ -297,16 +297,14 @@ static int bt_ti_probe(struct platform_device *pdev)
        struct hci_dev *hdev;
        int err;
 
-       hst = kzalloc(sizeof(struct ti_st), GFP_KERNEL);
+       hst = devm_kzalloc(&pdev->dev, sizeof(struct ti_st), GFP_KERNEL);
        if (!hst)
                return -ENOMEM;
 
        /* Expose "hciX" device to user space */
        hdev = hci_alloc_dev();
-       if (!hdev) {
-               kfree(hst);
+       if (!hdev)
                return -ENOMEM;
-       }
 
        BT_DBG("hdev %p", hdev);
 
@@ -321,7 +319,6 @@ static int bt_ti_probe(struct platform_device *pdev)
        err = hci_register_dev(hdev);
        if (err < 0) {
                BT_ERR("Can't register HCI device error %d", err);
-               kfree(hst);
                hci_free_dev(hdev);
                return err;
        }
@@ -347,7 +344,6 @@ static int bt_ti_remove(struct platform_device *pdev)
        hci_unregister_dev(hdev);
 
        hci_free_dev(hdev);
-       kfree(hst);
 
        dev_set_drvdata(&pdev->dev, NULL);
        return 0;
index 97a7784db4a2d4b6431aa2e15d8ff122b40ccdf4..036cb366fe6e77d7c8e202cf2aee0f0d3fde2880 100644 (file)
@@ -550,7 +550,7 @@ static int dtl1_probe(struct pcmcia_device *link)
        dtl1_info_t *info;
 
        /* Create new info device */
-       info = kzalloc(sizeof(*info), GFP_KERNEL);
+       info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
        if (!info)
                return -ENOMEM;
 
@@ -569,7 +569,6 @@ static void dtl1_detach(struct pcmcia_device *link)
 
        dtl1_close(info);
        pcmcia_disable_device(link);
-       kfree(info);
 }
 
 static int dtl1_confcheck(struct pcmcia_device *p_dev, void *priv_data)
index 12172a6a95c440467666d1599f13bab4fe45253f..0bc8a6a6a14850744d27788b9850ddf9bacac99f 100644 (file)
@@ -58,7 +58,7 @@ static int ath_wakeup_ar3k(struct tty_struct *tty)
                return status;
 
        /* Disable Automatic RTSCTS */
-       memcpy(&ktermios, tty->termios, sizeof(ktermios));
+       ktermios = tty->termios;
        ktermios.c_cflag &= ~CRTSCTS;
        tty_set_termios(tty, &ktermios);
 
index 57226424690cb1f05ebfa560f776aa8adf967c55..6f007b6c240d9d6a9941efcbd7a654be34c6fd94 100644 (file)
 #define PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_GT2_IG         0x016A
 #define PCI_DEVICE_ID_INTEL_VALLEYVIEW_HB              0x0F00 /* VLV1 */
 #define PCI_DEVICE_ID_INTEL_VALLEYVIEW_IG              0x0F30
-#define PCI_DEVICE_ID_INTEL_HASWELL_HB                         0x0400 /* Desktop */
+#define PCI_DEVICE_ID_INTEL_HASWELL_HB                 0x0400 /* Desktop */
 #define PCI_DEVICE_ID_INTEL_HASWELL_D_GT1_IG           0x0402
 #define PCI_DEVICE_ID_INTEL_HASWELL_D_GT2_IG           0x0412
-#define PCI_DEVICE_ID_INTEL_HASWELL_M_HB                       0x0404 /* Mobile */
+#define PCI_DEVICE_ID_INTEL_HASWELL_D_GT2_PLUS_IG      0x0422
+#define PCI_DEVICE_ID_INTEL_HASWELL_M_HB               0x0404 /* Mobile */
 #define PCI_DEVICE_ID_INTEL_HASWELL_M_GT1_IG           0x0406
 #define PCI_DEVICE_ID_INTEL_HASWELL_M_GT2_IG           0x0416
-#define PCI_DEVICE_ID_INTEL_HASWELL_S_HB                       0x0408 /* Server */
+#define PCI_DEVICE_ID_INTEL_HASWELL_M_GT2_PLUS_IG      0x0426
+#define PCI_DEVICE_ID_INTEL_HASWELL_S_HB               0x0408 /* Server */
 #define PCI_DEVICE_ID_INTEL_HASWELL_S_GT1_IG           0x040a
 #define PCI_DEVICE_ID_INTEL_HASWELL_S_GT2_IG           0x041a
-#define PCI_DEVICE_ID_INTEL_HASWELL_SDV                0x0c16 /* SDV */
-#define PCI_DEVICE_ID_INTEL_HASWELL_E_HB                       0x0c04
+#define PCI_DEVICE_ID_INTEL_HASWELL_S_GT2_PLUS_IG      0x042a
+#define PCI_DEVICE_ID_INTEL_HASWELL_E_HB               0x0c04
+#define PCI_DEVICE_ID_INTEL_HASWELL_SDV_D_GT1_IG       0x0C02
+#define PCI_DEVICE_ID_INTEL_HASWELL_SDV_D_GT2_IG       0x0C12
+#define PCI_DEVICE_ID_INTEL_HASWELL_SDV_D_GT2_PLUS_IG  0x0C22
+#define PCI_DEVICE_ID_INTEL_HASWELL_SDV_M_GT1_IG       0x0C06
+#define PCI_DEVICE_ID_INTEL_HASWELL_SDV_M_GT2_IG       0x0C16
+#define PCI_DEVICE_ID_INTEL_HASWELL_SDV_M_GT2_PLUS_IG  0x0C26
+#define PCI_DEVICE_ID_INTEL_HASWELL_SDV_S_GT1_IG       0x0C0A
+#define PCI_DEVICE_ID_INTEL_HASWELL_SDV_S_GT2_IG       0x0C1A
+#define PCI_DEVICE_ID_INTEL_HASWELL_SDV_S_GT2_PLUS_IG  0x0C2A
+#define PCI_DEVICE_ID_INTEL_HASWELL_ULT_D_GT1_IG       0x0A02
+#define PCI_DEVICE_ID_INTEL_HASWELL_ULT_D_GT2_IG       0x0A12
+#define PCI_DEVICE_ID_INTEL_HASWELL_ULT_D_GT2_PLUS_IG  0x0A22
+#define PCI_DEVICE_ID_INTEL_HASWELL_ULT_M_GT1_IG       0x0A06
+#define PCI_DEVICE_ID_INTEL_HASWELL_ULT_M_GT2_IG       0x0A16
+#define PCI_DEVICE_ID_INTEL_HASWELL_ULT_M_GT2_PLUS_IG  0x0A26
+#define PCI_DEVICE_ID_INTEL_HASWELL_ULT_S_GT1_IG       0x0A0A
+#define PCI_DEVICE_ID_INTEL_HASWELL_ULT_S_GT2_IG       0x0A1A
+#define PCI_DEVICE_ID_INTEL_HASWELL_ULT_S_GT2_PLUS_IG  0x0A2A
+#define PCI_DEVICE_ID_INTEL_HASWELL_CRW_D_GT1_IG       0x0D12
+#define PCI_DEVICE_ID_INTEL_HASWELL_CRW_D_GT2_IG       0x0D22
+#define PCI_DEVICE_ID_INTEL_HASWELL_CRW_D_GT2_PLUS_IG  0x0D32
+#define PCI_DEVICE_ID_INTEL_HASWELL_CRW_M_GT1_IG       0x0D16
+#define PCI_DEVICE_ID_INTEL_HASWELL_CRW_M_GT2_IG       0x0D26
+#define PCI_DEVICE_ID_INTEL_HASWELL_CRW_M_GT2_PLUS_IG  0x0D36
+#define PCI_DEVICE_ID_INTEL_HASWELL_CRW_S_GT1_IG       0x0D1A
+#define PCI_DEVICE_ID_INTEL_HASWELL_CRW_S_GT2_IG       0x0D2A
+#define PCI_DEVICE_ID_INTEL_HASWELL_CRW_S_GT2_PLUS_IG  0x0D3A
 
 #endif
index 9ed92ef5829b8f54bb318e0b6510e59c2b40e939..08fc5cbb13cdde33f5b4a105c0dce99ecb0181c1 100644 (file)
@@ -1502,15 +1502,73 @@ static const struct intel_gtt_driver_description {
            "Haswell", &sandybridge_gtt_driver },
        { PCI_DEVICE_ID_INTEL_HASWELL_D_GT2_IG,
            "Haswell", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_D_GT2_PLUS_IG,
+           "Haswell", &sandybridge_gtt_driver },
        { PCI_DEVICE_ID_INTEL_HASWELL_M_GT1_IG,
            "Haswell", &sandybridge_gtt_driver },
        { PCI_DEVICE_ID_INTEL_HASWELL_M_GT2_IG,
            "Haswell", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_M_GT2_PLUS_IG,
+           "Haswell", &sandybridge_gtt_driver },
        { PCI_DEVICE_ID_INTEL_HASWELL_S_GT1_IG,
            "Haswell", &sandybridge_gtt_driver },
        { PCI_DEVICE_ID_INTEL_HASWELL_S_GT2_IG,
            "Haswell", &sandybridge_gtt_driver },
-       { PCI_DEVICE_ID_INTEL_HASWELL_SDV,
+       { PCI_DEVICE_ID_INTEL_HASWELL_S_GT2_PLUS_IG,
+           "Haswell", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_SDV_D_GT1_IG,
+           "Haswell", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_SDV_D_GT2_IG,
+           "Haswell", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_SDV_D_GT2_PLUS_IG,
+           "Haswell", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_SDV_M_GT1_IG,
+           "Haswell", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_SDV_M_GT2_IG,
+           "Haswell", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_SDV_M_GT2_PLUS_IG,
+           "Haswell", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_SDV_S_GT1_IG,
+           "Haswell", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_SDV_S_GT2_IG,
+           "Haswell", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_SDV_S_GT2_PLUS_IG,
+           "Haswell", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_ULT_D_GT1_IG,
+           "Haswell", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_ULT_D_GT2_IG,
+           "Haswell", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_ULT_D_GT2_PLUS_IG,
+           "Haswell", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_ULT_M_GT1_IG,
+           "Haswell", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_ULT_M_GT2_IG,
+           "Haswell", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_ULT_M_GT2_PLUS_IG,
+           "Haswell", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_ULT_S_GT1_IG,
+           "Haswell", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_ULT_S_GT2_IG,
+           "Haswell", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_ULT_S_GT2_PLUS_IG,
+           "Haswell", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_CRW_D_GT1_IG,
+           "Haswell", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_CRW_D_GT2_IG,
+           "Haswell", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_CRW_D_GT2_PLUS_IG,
+           "Haswell", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_CRW_M_GT1_IG,
+           "Haswell", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_CRW_M_GT2_IG,
+           "Haswell", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_CRW_M_GT2_PLUS_IG,
+           "Haswell", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_CRW_S_GT1_IG,
+           "Haswell", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_CRW_S_GT2_IG,
+           "Haswell", &sandybridge_gtt_driver },
+       { PCI_DEVICE_ID_INTEL_HASWELL_CRW_S_GT2_PLUS_IG,
            "Haswell", &sandybridge_gtt_driver },
        { 0, NULL, NULL }
 };
index d706bd0e9e800fd791e198b4b573b64296f3f40e..4fbdceb6f773d7e45189a22347668c34a0b52c63 100644 (file)
@@ -160,7 +160,7 @@ static int __exit omap_rng_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 
 static int omap_rng_suspend(struct device *dev)
 {
index 1d82d5838f0c38c416947d7f95b17d204d0a93b1..164544afd6809b1c1287c5d3fb02c99a29de7ab6 100644 (file)
@@ -430,7 +430,7 @@ static ssize_t mwave_write(struct file *file, const char __user *buf,
 
 static int register_serial_portandirq(unsigned int port, int irq)
 {
-       struct uart_port uart;
+       struct uart_8250_port uart;
        
        switch ( port ) {
                case 0x3f8:
@@ -462,14 +462,14 @@ static int register_serial_portandirq(unsigned int port, int irq)
        } /* switch */
        /* irq is okay */
 
-       memset(&uart, 0, sizeof(struct uart_port));
+       memset(&uart, 0, sizeof(uart));
        
-       uart.uartclk =  1843200;
-       uart.iobase = port;
-       uart.irq = irq;
-       uart.iotype = UPIO_PORT;
-       uart.flags =  UPF_SHARE_IRQ;
-       return serial8250_register_port(&uart);
+       uart.port.uartclk =  1843200;
+       uart.port.iobase = port;
+       uart.port.irq = irq;
+       uart.port.iotype = UPIO_PORT;
+       uart.port.flags =  UPF_SHARE_IRQ;
+       return serial8250_register_8250_port(&uart);
 }
 
 
index d45c3345b4af4dae61f6458b5e14bc490c2a084e..a0e2f7d70355a1c16e8c67df377e41f47aee37c3 100644 (file)
@@ -30,7 +30,6 @@
 
 #include <asm/hardware/dec21285.h>
 #include <asm/io.h>
-#include <asm/leds.h>
 #include <asm/mach-types.h>
 #include <asm/uaccess.h>
 
@@ -179,9 +178,6 @@ static ssize_t flash_write(struct file *file, const char __user *buf,
 
        written = 0;
 
-       leds_event(led_claim);
-       leds_event(led_green_on);
-
        nBlock = (int) p >> 16; //block # of 64K bytes
 
        /*
@@ -258,11 +254,6 @@ static ssize_t flash_write(struct file *file, const char __user *buf,
                        printk(KERN_DEBUG "flash_write: written 0x%X bytes OK.\n", written);
        }
 
-       /*
-        * restore reg on exit
-        */
-       leds_event(led_release);
-
        mutex_unlock(&nwflash_mutex);
 
        return written;
@@ -333,11 +324,6 @@ static int erase_block(int nBlock)
        unsigned long timeout;
        int temp, temp1;
 
-       /*
-        * orange LED == erase
-        */
-       leds_event(led_amber_on);
-
        /*
         * reset footbridge to the correct offset 0 (...0..3)
         */
@@ -446,12 +432,6 @@ static int write_block(unsigned long p, const char __user *buf, int count)
        unsigned long timeout;
        unsigned long timeout1;
 
-       /*
-        * red LED == write
-        */
-       leds_event(led_amber_off);
-       leds_event(led_red_on);
-
        pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + p));
 
        /*
@@ -557,18 +537,10 @@ static int write_block(unsigned long p, const char __user *buf, int count)
                                        printk(KERN_DEBUG "write_block: Retrying write at 0x%X)n",
                                               pWritePtr - FLASH_BASE);
 
-                               /*
-                                * no LED == waiting
-                                */
-                               leds_event(led_amber_off);
                                /*
                                 * wait couple ms
                                 */
                                msleep(10);
-                               /*
-                                * red LED == write
-                                */
-                               leds_event(led_red_on);
 
                                goto WriteRetry;
                        } else {
@@ -583,12 +555,6 @@ static int write_block(unsigned long p, const char __user *buf, int count)
                }
        }
 
-       /*
-        * green LED == read/verify
-        */
-       leds_event(led_amber_off);
-       leds_event(led_green_on);
-
        msleep(10);
 
        pWritePtr = (unsigned char *) ((unsigned int) (FLASH_BASE + p));
index 0a484b4a1b02bdabfd231a2ed21b5446ccd95642..5db08c78beb5a1423902f6bd3ed62d690a7d5213 100644 (file)
@@ -1344,7 +1344,7 @@ static void shutdown(MGSLPC_INFO * info, struct tty_struct *tty)
        /* TODO:disable interrupts instead of reset to preserve signal states */
        reset_device(info);
 
-       if (!tty || tty->termios->c_cflag & HUPCL) {
+       if (!tty || tty->termios.c_cflag & HUPCL) {
                info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS);
                set_signals(info);
        }
@@ -1385,7 +1385,7 @@ static void mgslpc_program_hw(MGSLPC_INFO *info, struct tty_struct *tty)
        port_irq_enable(info, (unsigned char) PVR_DSR | PVR_RI);
        get_signals(info);
 
-       if (info->netcount || (tty && (tty->termios->c_cflag & CREAD)))
+       if (info->netcount || (tty && (tty->termios.c_cflag & CREAD)))
                rx_start(info);
 
        spin_unlock_irqrestore(&info->lock,flags);
@@ -1398,14 +1398,14 @@ static void mgslpc_change_params(MGSLPC_INFO *info, struct tty_struct *tty)
        unsigned cflag;
        int bits_per_char;
 
-       if (!tty || !tty->termios)
+       if (!tty)
                return;
 
        if (debug_level >= DEBUG_LEVEL_INFO)
                printk("%s(%d):mgslpc_change_params(%s)\n",
                         __FILE__,__LINE__, info->device_name );
 
-       cflag = tty->termios->c_cflag;
+       cflag = tty->termios.c_cflag;
 
        /* if B0 rate (hangup) specified then negate DTR and RTS */
        /* otherwise assert DTR and RTS */
@@ -1728,7 +1728,7 @@ static void mgslpc_throttle(struct tty_struct * tty)
        if (I_IXOFF(tty))
                mgslpc_send_xchar(tty, STOP_CHAR(tty));
 
-       if (tty->termios->c_cflag & CRTSCTS) {
+       if (tty->termios.c_cflag & CRTSCTS) {
                spin_lock_irqsave(&info->lock,flags);
                info->serial_signals &= ~SerialSignal_RTS;
                set_signals(info);
@@ -1757,7 +1757,7 @@ static void mgslpc_unthrottle(struct tty_struct * tty)
                        mgslpc_send_xchar(tty, START_CHAR(tty));
        }
 
-       if (tty->termios->c_cflag & CRTSCTS) {
+       if (tty->termios.c_cflag & CRTSCTS) {
                spin_lock_irqsave(&info->lock,flags);
                info->serial_signals |= SerialSignal_RTS;
                set_signals(info);
@@ -2293,8 +2293,8 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term
                        tty->driver->name );
 
        /* just return if nothing has changed */
-       if ((tty->termios->c_cflag == old_termios->c_cflag)
-           && (RELEVANT_IFLAG(tty->termios->c_iflag)
+       if ((tty->termios.c_cflag == old_termios->c_cflag)
+           && (RELEVANT_IFLAG(tty->termios.c_iflag)
                == RELEVANT_IFLAG(old_termios->c_iflag)))
          return;
 
@@ -2302,7 +2302,7 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term
 
        /* Handle transition to B0 status */
        if (old_termios->c_cflag & CBAUD &&
-           !(tty->termios->c_cflag & CBAUD)) {
+           !(tty->termios.c_cflag & CBAUD)) {
                info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
                spin_lock_irqsave(&info->lock,flags);
                set_signals(info);
@@ -2311,9 +2311,9 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term
 
        /* Handle transition away from B0 status */
        if (!(old_termios->c_cflag & CBAUD) &&
-           tty->termios->c_cflag & CBAUD) {
+           tty->termios.c_cflag & CBAUD) {
                info->serial_signals |= SerialSignal_DTR;
-               if (!(tty->termios->c_cflag & CRTSCTS) ||
+               if (!(tty->termios.c_cflag & CRTSCTS) ||
                    !test_bit(TTY_THROTTLED, &tty->flags)) {
                        info->serial_signals |= SerialSignal_RTS;
                }
@@ -2324,7 +2324,7 @@ static void mgslpc_set_termios(struct tty_struct *tty, struct ktermios *old_term
 
        /* Handle turning off CRTSCTS */
        if (old_termios->c_cflag & CRTSCTS &&
-           !(tty->termios->c_cflag & CRTSCTS)) {
+           !(tty->termios.c_cflag & CRTSCTS)) {
                tty->hw_stopped = 0;
                tx_release(tty);
        }
@@ -2731,6 +2731,8 @@ static void mgslpc_add_device(MGSLPC_INFO *info)
 #if SYNCLINK_GENERIC_HDLC
        hdlcdev_init(info);
 #endif
+       tty_port_register_device(&info->port, serial_driver, info->line,
+                       &info->p_dev->dev);
 }
 
 static void mgslpc_remove_device(MGSLPC_INFO *remove_info)
@@ -2744,6 +2746,7 @@ static void mgslpc_remove_device(MGSLPC_INFO *remove_info)
                                last->next_device = info->next_device;
                        else
                                mgslpc_device_list = info->next_device;
+                       tty_unregister_device(serial_driver, info->line);
 #if SYNCLINK_GENERIC_HDLC
                        hdlcdev_exit(info);
 #endif
@@ -2798,77 +2801,63 @@ static const struct tty_operations mgslpc_ops = {
        .proc_fops = &mgslpc_proc_fops,
 };
 
-static void synclink_cs_cleanup(void)
+static int __init synclink_cs_init(void)
 {
        int rc;
 
-       while(mgslpc_device_list)
-               mgslpc_remove_device(mgslpc_device_list);
-
-       if (serial_driver) {
-               if ((rc = tty_unregister_driver(serial_driver)))
-                       printk("%s(%d) failed to unregister tty driver err=%d\n",
-                              __FILE__,__LINE__,rc);
-               put_tty_driver(serial_driver);
+       if (break_on_load) {
+               mgslpc_get_text_ptr();
+               BREAKPOINT();
        }
 
-       pcmcia_unregister_driver(&mgslpc_driver);
-}
-
-static int __init synclink_cs_init(void)
-{
-    int rc;
-
-    if (break_on_load) {
-           mgslpc_get_text_ptr();
-           BREAKPOINT();
-    }
-
-    if ((rc = pcmcia_register_driver(&mgslpc_driver)) < 0)
-           return rc;
-
-    serial_driver = alloc_tty_driver(MAX_DEVICE_COUNT);
-    if (!serial_driver) {
-           rc = -ENOMEM;
-           goto error;
-    }
+       serial_driver = tty_alloc_driver(MAX_DEVICE_COUNT,
+                       TTY_DRIVER_REAL_RAW |
+                       TTY_DRIVER_DYNAMIC_DEV);
+       if (IS_ERR(serial_driver)) {
+               rc = PTR_ERR(serial_driver);
+               goto err;
+       }
 
-    /* Initialize the tty_driver structure */
-
-    serial_driver->driver_name = "synclink_cs";
-    serial_driver->name = "ttySLP";
-    serial_driver->major = ttymajor;
-    serial_driver->minor_start = 64;
-    serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
-    serial_driver->subtype = SERIAL_TYPE_NORMAL;
-    serial_driver->init_termios = tty_std_termios;
-    serial_driver->init_termios.c_cflag =
-           B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-    serial_driver->flags = TTY_DRIVER_REAL_RAW;
-    tty_set_operations(serial_driver, &mgslpc_ops);
-
-    if ((rc = tty_register_driver(serial_driver)) < 0) {
-           printk("%s(%d):Couldn't register serial driver\n",
-                  __FILE__,__LINE__);
-           put_tty_driver(serial_driver);
-           serial_driver = NULL;
-           goto error;
-    }
+       /* Initialize the tty_driver structure */
+       serial_driver->driver_name = "synclink_cs";
+       serial_driver->name = "ttySLP";
+       serial_driver->major = ttymajor;
+       serial_driver->minor_start = 64;
+       serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
+       serial_driver->subtype = SERIAL_TYPE_NORMAL;
+       serial_driver->init_termios = tty_std_termios;
+       serial_driver->init_termios.c_cflag =
+       B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+       tty_set_operations(serial_driver, &mgslpc_ops);
+
+       rc = tty_register_driver(serial_driver);
+       if (rc < 0) {
+               printk(KERN_ERR "%s(%d):Couldn't register serial driver\n",
+                               __FILE__, __LINE__);
+               goto err_put_tty;
+       }
 
-    printk("%s %s, tty major#%d\n",
-          driver_name, driver_version,
-          serial_driver->major);
+       rc = pcmcia_register_driver(&mgslpc_driver);
+       if (rc < 0)
+               goto err_unreg_tty;
 
-    return 0;
+       printk(KERN_INFO "%s %s, tty major#%d\n", driver_name, driver_version,
+                       serial_driver->major);
 
-error:
-    synclink_cs_cleanup();
-    return rc;
+       return 0;
+err_unreg_tty:
+       tty_unregister_driver(serial_driver);
+err_put_tty:
+       put_tty_driver(serial_driver);
+err:
+       return rc;
 }
 
 static void __exit synclink_cs_exit(void)
 {
-       synclink_cs_cleanup();
+       pcmcia_unregister_driver(&mgslpc_driver);
+       tty_unregister_driver(serial_driver);
+       put_tty_driver(serial_driver);
 }
 
 module_init(synclink_cs_init);
index ce29e7cce528ec01268f41eb05be4ad7f6dcee3c..e95e0ab0bd870a4c8d679d7dbb092ea2521ee42e 100644 (file)
@@ -784,8 +784,10 @@ static int __init tlclk_init(void)
        }
        tlclk_major = ret;
        alarm_events = kzalloc( sizeof(struct tlclk_alarms), GFP_KERNEL);
-       if (!alarm_events)
+       if (!alarm_events) {
+               ret = -ENOMEM;
                goto out1;
+       }
 
        /* Read telecom clock IRQ number (Set by BIOS) */
        if (!request_region(TLCLK_BASE, 8, "telco_clock")) {
index 89682fa8801ea0fafb1f8e9556ca148ab0b4f6f9..c4be3519a587c4fe33c3a14be17ba72e6067d9a0 100644 (file)
@@ -807,6 +807,7 @@ module_param_string(hid, tpm_pnp_tbl[TIS_HID_USR_IDX].id,
 MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe");
 #endif
 
+#ifdef CONFIG_PM_SLEEP
 static int tpm_tis_resume(struct device *dev)
 {
        struct tpm_chip *chip = dev_get_drvdata(dev);
@@ -816,6 +817,7 @@ static int tpm_tis_resume(struct device *dev)
 
        return tpm_pm_resume(dev);
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(tpm_tis_pm, tpm_pm_suspend, tpm_tis_resume);
 
index 46b77ede84c01cb2b103b3256e2fab39bf16d889..af98f6d6509bfa29dece7ca9b853ef3e22cc3c2c 100644 (file)
@@ -67,7 +67,7 @@ static int tpk_printk(const unsigned char *buf, int count)
                                tmp[tpk_curr + 1] = '\0';
                                printk(KERN_INFO "%s%s", tpk_tag, tmp);
                                tpk_curr = 0;
-                               if (buf[i + 1] == '\n')
+                               if ((i + 1) < count && buf[i + 1] == '\n')
                                        i++;
                                break;
                        case '\n':
@@ -178,11 +178,17 @@ static struct tty_driver *ttyprintk_driver;
 static int __init ttyprintk_init(void)
 {
        int ret = -ENOMEM;
-       void *rp;
 
-       ttyprintk_driver = alloc_tty_driver(1);
-       if (!ttyprintk_driver)
-               return ret;
+       tty_port_init(&tpk_port.port);
+       tpk_port.port.ops = &null_ops;
+       mutex_init(&tpk_port.port_write_mutex);
+
+       ttyprintk_driver = tty_alloc_driver(1,
+                       TTY_DRIVER_RESET_TERMIOS |
+                       TTY_DRIVER_REAL_RAW |
+                       TTY_DRIVER_UNNUMBERED_NODE);
+       if (IS_ERR(ttyprintk_driver))
+               return PTR_ERR(ttyprintk_driver);
 
        ttyprintk_driver->driver_name = "ttyprintk";
        ttyprintk_driver->name = "ttyprintk";
@@ -191,9 +197,8 @@ static int __init ttyprintk_init(void)
        ttyprintk_driver->type = TTY_DRIVER_TYPE_CONSOLE;
        ttyprintk_driver->init_termios = tty_std_termios;
        ttyprintk_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET;
-       ttyprintk_driver->flags = TTY_DRIVER_RESET_TERMIOS |
-               TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
        tty_set_operations(ttyprintk_driver, &ttyprintk_ops);
+       tty_port_link_device(&tpk_port.port, ttyprintk_driver, 0);
 
        ret = tty_register_driver(ttyprintk_driver);
        if (ret < 0) {
@@ -201,22 +206,10 @@ static int __init ttyprintk_init(void)
                goto error;
        }
 
-       /* create our unnumbered device */
-       rp = device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 3), NULL,
-                               ttyprintk_driver->name);
-       if (IS_ERR(rp)) {
-               printk(KERN_ERR "Couldn't create ttyprintk device\n");
-               ret = PTR_ERR(rp);
-               goto error;
-       }
-
-       tty_port_init(&tpk_port.port);
-       tpk_port.port.ops = &null_ops;
-       mutex_init(&tpk_port.port_write_mutex);
-
        return 0;
 
 error:
+       tty_unregister_driver(ttyprintk_driver);
        put_tty_driver(ttyprintk_driver);
        ttyprintk_driver = NULL;
        return ret;
index 98b06baafcc64dd95c2a16965ea261210080c324..a5f7829f27993b8fefea105357229413b78e5309 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
 
 struct sh_cmt_priv {
        void __iomem *mapbase;
@@ -52,6 +53,7 @@ struct sh_cmt_priv {
        struct clock_event_device ced;
        struct clocksource cs;
        unsigned long total_cycles;
+       bool cs_enabled;
 };
 
 static DEFINE_RAW_SPINLOCK(sh_cmt_lock);
@@ -155,6 +157,9 @@ static int sh_cmt_enable(struct sh_cmt_priv *p, unsigned long *rate)
 {
        int k, ret;
 
+       pm_runtime_get_sync(&p->pdev->dev);
+       dev_pm_syscore_device(&p->pdev->dev, true);
+
        /* enable clock */
        ret = clk_enable(p->clk);
        if (ret) {
@@ -221,6 +226,9 @@ static void sh_cmt_disable(struct sh_cmt_priv *p)
 
        /* stop clock */
        clk_disable(p->clk);
+
+       dev_pm_syscore_device(&p->pdev->dev, false);
+       pm_runtime_put(&p->pdev->dev);
 }
 
 /* private flags */
@@ -451,22 +459,42 @@ static int sh_cmt_clocksource_enable(struct clocksource *cs)
        int ret;
        struct sh_cmt_priv *p = cs_to_sh_cmt(cs);
 
+       WARN_ON(p->cs_enabled);
+
        p->total_cycles = 0;
 
        ret = sh_cmt_start(p, FLAG_CLOCKSOURCE);
-       if (!ret)
+       if (!ret) {
                __clocksource_updatefreq_hz(cs, p->rate);
+               p->cs_enabled = true;
+       }
        return ret;
 }
 
 static void sh_cmt_clocksource_disable(struct clocksource *cs)
 {
-       sh_cmt_stop(cs_to_sh_cmt(cs), FLAG_CLOCKSOURCE);
+       struct sh_cmt_priv *p = cs_to_sh_cmt(cs);
+
+       WARN_ON(!p->cs_enabled);
+
+       sh_cmt_stop(p, FLAG_CLOCKSOURCE);
+       p->cs_enabled = false;
+}
+
+static void sh_cmt_clocksource_suspend(struct clocksource *cs)
+{
+       struct sh_cmt_priv *p = cs_to_sh_cmt(cs);
+
+       sh_cmt_stop(p, FLAG_CLOCKSOURCE);
+       pm_genpd_syscore_poweroff(&p->pdev->dev);
 }
 
 static void sh_cmt_clocksource_resume(struct clocksource *cs)
 {
-       sh_cmt_start(cs_to_sh_cmt(cs), FLAG_CLOCKSOURCE);
+       struct sh_cmt_priv *p = cs_to_sh_cmt(cs);
+
+       pm_genpd_syscore_poweron(&p->pdev->dev);
+       sh_cmt_start(p, FLAG_CLOCKSOURCE);
 }
 
 static int sh_cmt_register_clocksource(struct sh_cmt_priv *p,
@@ -479,7 +507,7 @@ static int sh_cmt_register_clocksource(struct sh_cmt_priv *p,
        cs->read = sh_cmt_clocksource_read;
        cs->enable = sh_cmt_clocksource_enable;
        cs->disable = sh_cmt_clocksource_disable;
-       cs->suspend = sh_cmt_clocksource_disable;
+       cs->suspend = sh_cmt_clocksource_suspend;
        cs->resume = sh_cmt_clocksource_resume;
        cs->mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8);
        cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
@@ -562,6 +590,16 @@ static int sh_cmt_clock_event_next(unsigned long delta,
        return 0;
 }
 
+static void sh_cmt_clock_event_suspend(struct clock_event_device *ced)
+{
+       pm_genpd_syscore_poweroff(&ced_to_sh_cmt(ced)->pdev->dev);
+}
+
+static void sh_cmt_clock_event_resume(struct clock_event_device *ced)
+{
+       pm_genpd_syscore_poweron(&ced_to_sh_cmt(ced)->pdev->dev);
+}
+
 static void sh_cmt_register_clockevent(struct sh_cmt_priv *p,
                                       char *name, unsigned long rating)
 {
@@ -576,6 +614,8 @@ static void sh_cmt_register_clockevent(struct sh_cmt_priv *p,
        ced->cpumask = cpumask_of(0);
        ced->set_next_event = sh_cmt_clock_event_next;
        ced->set_mode = sh_cmt_clock_event_mode;
+       ced->suspend = sh_cmt_clock_event_suspend;
+       ced->resume = sh_cmt_clock_event_resume;
 
        dev_info(&p->pdev->dev, "used for clock events\n");
        clockevents_register_device(ced);
@@ -670,6 +710,7 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
                dev_err(&p->pdev->dev, "registration failed\n");
                goto err1;
        }
+       p->cs_enabled = false;
 
        ret = setup_irq(irq, &p->irqaction);
        if (ret) {
@@ -688,14 +729,17 @@ err0:
 static int __devinit 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;
        int ret;
 
-       if (!is_early_platform_device(pdev))
-               pm_genpd_dev_always_on(&pdev->dev, true);
+       if (!is_early_platform_device(pdev)) {
+               pm_runtime_set_active(&pdev->dev);
+               pm_runtime_enable(&pdev->dev);
+       }
 
        if (p) {
                dev_info(&pdev->dev, "kept as earlytimer\n");
-               return 0;
+               goto out;
        }
 
        p = kmalloc(sizeof(*p), GFP_KERNEL);
@@ -708,8 +752,19 @@ static int __devinit sh_cmt_probe(struct platform_device *pdev)
        if (ret) {
                kfree(p);
                platform_set_drvdata(pdev, NULL);
+               pm_runtime_idle(&pdev->dev);
+               return ret;
        }
-       return ret;
+       if (is_early_platform_device(pdev))
+               return 0;
+
+ out:
+       if (cfg->clockevent_rating || cfg->clocksource_rating)
+               pm_runtime_irq_safe(&pdev->dev);
+       else
+               pm_runtime_idle(&pdev->dev);
+
+       return 0;
 }
 
 static int __devexit sh_cmt_remove(struct platform_device *pdev)
index d9b76ca64a611327c0ea79d979482f638e3c14d3..c5eea858054aa4e67195edf69c1b1951fa8cf11c 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
 
 struct sh_mtu2_priv {
        void __iomem *mapbase;
@@ -123,6 +124,9 @@ static int sh_mtu2_enable(struct sh_mtu2_priv *p)
 {
        int ret;
 
+       pm_runtime_get_sync(&p->pdev->dev);
+       dev_pm_syscore_device(&p->pdev->dev, true);
+
        /* enable clock */
        ret = clk_enable(p->clk);
        if (ret) {
@@ -157,6 +161,9 @@ static void sh_mtu2_disable(struct sh_mtu2_priv *p)
 
        /* stop clock */
        clk_disable(p->clk);
+
+       dev_pm_syscore_device(&p->pdev->dev, false);
+       pm_runtime_put(&p->pdev->dev);
 }
 
 static irqreturn_t sh_mtu2_interrupt(int irq, void *dev_id)
@@ -208,6 +215,16 @@ static void sh_mtu2_clock_event_mode(enum clock_event_mode mode,
        }
 }
 
+static void sh_mtu2_clock_event_suspend(struct clock_event_device *ced)
+{
+       pm_genpd_syscore_poweroff(&ced_to_sh_mtu2(ced)->pdev->dev);
+}
+
+static void sh_mtu2_clock_event_resume(struct clock_event_device *ced)
+{
+       pm_genpd_syscore_poweron(&ced_to_sh_mtu2(ced)->pdev->dev);
+}
+
 static void sh_mtu2_register_clockevent(struct sh_mtu2_priv *p,
                                       char *name, unsigned long rating)
 {
@@ -221,6 +238,8 @@ static void sh_mtu2_register_clockevent(struct sh_mtu2_priv *p,
        ced->rating = rating;
        ced->cpumask = cpumask_of(0);
        ced->set_mode = sh_mtu2_clock_event_mode;
+       ced->suspend = sh_mtu2_clock_event_suspend;
+       ced->resume = sh_mtu2_clock_event_resume;
 
        dev_info(&p->pdev->dev, "used for clock events\n");
        clockevents_register_device(ced);
@@ -305,14 +324,17 @@ static int sh_mtu2_setup(struct sh_mtu2_priv *p, struct platform_device *pdev)
 static int __devinit 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;
        int ret;
 
-       if (!is_early_platform_device(pdev))
-               pm_genpd_dev_always_on(&pdev->dev, true);
+       if (!is_early_platform_device(pdev)) {
+               pm_runtime_set_active(&pdev->dev);
+               pm_runtime_enable(&pdev->dev);
+       }
 
        if (p) {
                dev_info(&pdev->dev, "kept as earlytimer\n");
-               return 0;
+               goto out;
        }
 
        p = kmalloc(sizeof(*p), GFP_KERNEL);
@@ -325,8 +347,19 @@ static int __devinit sh_mtu2_probe(struct platform_device *pdev)
        if (ret) {
                kfree(p);
                platform_set_drvdata(pdev, NULL);
+               pm_runtime_idle(&pdev->dev);
+               return ret;
        }
-       return ret;
+       if (is_early_platform_device(pdev))
+               return 0;
+
+ out:
+       if (cfg->clockevent_rating)
+               pm_runtime_irq_safe(&pdev->dev);
+       else
+               pm_runtime_idle(&pdev->dev);
+
+       return 0;
 }
 
 static int __devexit sh_mtu2_remove(struct platform_device *pdev)
index c1b51d49d106e90d8f4927cf174983878ad58b2a..0cc4add882795ed048e5b98a9e215a758b8ad147 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
 
 struct sh_tmu_priv {
        void __iomem *mapbase;
@@ -43,6 +44,8 @@ struct sh_tmu_priv {
        unsigned long periodic;
        struct clock_event_device ced;
        struct clocksource cs;
+       bool cs_enabled;
+       unsigned int enable_count;
 };
 
 static DEFINE_RAW_SPINLOCK(sh_tmu_lock);
@@ -107,7 +110,7 @@ static void sh_tmu_start_stop_ch(struct sh_tmu_priv *p, int start)
        raw_spin_unlock_irqrestore(&sh_tmu_lock, flags);
 }
 
-static int sh_tmu_enable(struct sh_tmu_priv *p)
+static int __sh_tmu_enable(struct sh_tmu_priv *p)
 {
        int ret;
 
@@ -135,7 +138,18 @@ static int sh_tmu_enable(struct sh_tmu_priv *p)
        return 0;
 }
 
-static void sh_tmu_disable(struct sh_tmu_priv *p)
+static int sh_tmu_enable(struct sh_tmu_priv *p)
+{
+       if (p->enable_count++ > 0)
+               return 0;
+
+       pm_runtime_get_sync(&p->pdev->dev);
+       dev_pm_syscore_device(&p->pdev->dev, true);
+
+       return __sh_tmu_enable(p);
+}
+
+static void __sh_tmu_disable(struct sh_tmu_priv *p)
 {
        /* disable channel */
        sh_tmu_start_stop_ch(p, 0);
@@ -147,6 +161,20 @@ static void sh_tmu_disable(struct sh_tmu_priv *p)
        clk_disable(p->clk);
 }
 
+static void sh_tmu_disable(struct sh_tmu_priv *p)
+{
+       if (WARN_ON(p->enable_count == 0))
+               return;
+
+       if (--p->enable_count > 0)
+               return;
+
+       __sh_tmu_disable(p);
+
+       dev_pm_syscore_device(&p->pdev->dev, false);
+       pm_runtime_put(&p->pdev->dev);
+}
+
 static void sh_tmu_set_next(struct sh_tmu_priv *p, unsigned long delta,
                            int periodic)
 {
@@ -203,15 +231,53 @@ static int sh_tmu_clocksource_enable(struct clocksource *cs)
        struct sh_tmu_priv *p = cs_to_sh_tmu(cs);
        int ret;
 
+       if (WARN_ON(p->cs_enabled))
+               return 0;
+
        ret = sh_tmu_enable(p);
-       if (!ret)
+       if (!ret) {
                __clocksource_updatefreq_hz(cs, p->rate);
+               p->cs_enabled = true;
+       }
+
        return ret;
 }
 
 static void sh_tmu_clocksource_disable(struct clocksource *cs)
 {
-       sh_tmu_disable(cs_to_sh_tmu(cs));
+       struct sh_tmu_priv *p = cs_to_sh_tmu(cs);
+
+       if (WARN_ON(!p->cs_enabled))
+               return;
+
+       sh_tmu_disable(p);
+       p->cs_enabled = false;
+}
+
+static void sh_tmu_clocksource_suspend(struct clocksource *cs)
+{
+       struct sh_tmu_priv *p = cs_to_sh_tmu(cs);
+
+       if (!p->cs_enabled)
+               return;
+
+       if (--p->enable_count == 0) {
+               __sh_tmu_disable(p);
+               pm_genpd_syscore_poweroff(&p->pdev->dev);
+       }
+}
+
+static void sh_tmu_clocksource_resume(struct clocksource *cs)
+{
+       struct sh_tmu_priv *p = cs_to_sh_tmu(cs);
+
+       if (!p->cs_enabled)
+               return;
+
+       if (p->enable_count++ == 0) {
+               pm_genpd_syscore_poweron(&p->pdev->dev);
+               __sh_tmu_enable(p);
+       }
 }
 
 static int sh_tmu_register_clocksource(struct sh_tmu_priv *p,
@@ -224,6 +290,8 @@ static int sh_tmu_register_clocksource(struct sh_tmu_priv *p,
        cs->read = sh_tmu_clocksource_read;
        cs->enable = sh_tmu_clocksource_enable;
        cs->disable = sh_tmu_clocksource_disable;
+       cs->suspend = sh_tmu_clocksource_suspend;
+       cs->resume = sh_tmu_clocksource_resume;
        cs->mask = CLOCKSOURCE_MASK(32);
        cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
 
@@ -301,6 +369,16 @@ static int sh_tmu_clock_event_next(unsigned long delta,
        return 0;
 }
 
+static void sh_tmu_clock_event_suspend(struct clock_event_device *ced)
+{
+       pm_genpd_syscore_poweroff(&ced_to_sh_tmu(ced)->pdev->dev);
+}
+
+static void sh_tmu_clock_event_resume(struct clock_event_device *ced)
+{
+       pm_genpd_syscore_poweron(&ced_to_sh_tmu(ced)->pdev->dev);
+}
+
 static void sh_tmu_register_clockevent(struct sh_tmu_priv *p,
                                       char *name, unsigned long rating)
 {
@@ -316,6 +394,8 @@ static void sh_tmu_register_clockevent(struct sh_tmu_priv *p,
        ced->cpumask = cpumask_of(0);
        ced->set_next_event = sh_tmu_clock_event_next;
        ced->set_mode = sh_tmu_clock_event_mode;
+       ced->suspend = sh_tmu_clock_event_suspend;
+       ced->resume = sh_tmu_clock_event_resume;
 
        dev_info(&p->pdev->dev, "used for clock events\n");
 
@@ -392,6 +472,8 @@ static int sh_tmu_setup(struct sh_tmu_priv *p, struct platform_device *pdev)
                ret = PTR_ERR(p->clk);
                goto err1;
        }
+       p->cs_enabled = false;
+       p->enable_count = 0;
 
        return sh_tmu_register(p, (char *)dev_name(&p->pdev->dev),
                               cfg->clockevent_rating,
@@ -405,14 +487,17 @@ static int sh_tmu_setup(struct sh_tmu_priv *p, struct platform_device *pdev)
 static int __devinit 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;
        int ret;
 
-       if (!is_early_platform_device(pdev))
-               pm_genpd_dev_always_on(&pdev->dev, true);
+       if (!is_early_platform_device(pdev)) {
+               pm_runtime_set_active(&pdev->dev);
+               pm_runtime_enable(&pdev->dev);
+       }
 
        if (p) {
                dev_info(&pdev->dev, "kept as earlytimer\n");
-               return 0;
+               goto out;
        }
 
        p = kmalloc(sizeof(*p), GFP_KERNEL);
@@ -425,8 +510,19 @@ static int __devinit sh_tmu_probe(struct platform_device *pdev)
        if (ret) {
                kfree(p);
                platform_set_drvdata(pdev, NULL);
+               pm_runtime_idle(&pdev->dev);
+               return ret;
        }
-       return ret;
+       if (is_early_platform_device(pdev))
+               return 0;
+
+ out:
+       if (cfg->clockevent_rating || cfg->clocksource_rating)
+               pm_runtime_irq_safe(&pdev->dev);
+       else
+               pm_runtime_idle(&pdev->dev);
+
+       return 0;
 }
 
 static int __devexit sh_tmu_remove(struct platform_device *pdev)
index 235a340e81f20bcb63805f9c911f4fd99eafeab8..a1563d747fd20e445eda7ceae0e24addad93d401 100644 (file)
@@ -504,6 +504,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
                                j_dbs_info->prev_cpu_nice =
                                                kcpustat_cpu(j).cpustat[CPUTIME_NICE];
                }
+               this_dbs_info->cpu = cpu;
                this_dbs_info->down_skip = 0;
                this_dbs_info->requested_freq = policy->cur;
 
index 17fa04d08be9cc0af181e5f20398128d8b4d5234..b47034e650a579b9d0263f8d0a03af2ecc8b3aa7 100644 (file)
@@ -218,7 +218,7 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
 
        policy->cur = policy->min = policy->max = omap_getspeed(policy->cpu);
 
-       if (atomic_inc_return(&freq_table_users) == 1)
+       if (!freq_table)
                result = opp_init_cpufreq_table(mpu_dev, &freq_table);
 
        if (result) {
@@ -227,6 +227,8 @@ static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
                goto fail_ck;
        }
 
+       atomic_inc_return(&freq_table_users);
+
        result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
        if (result)
                goto fail_table;
index cdc02ac8f41a7ff5d3f121e2b0927fd8bf99ae7a..503996a94a6af3d4f41292794c14f261ada96ae1 100644 (file)
@@ -454,6 +454,7 @@ static int __init pcc_cpufreq_probe(void)
                                        mem_resource->address_length);
        if (pcch_virt_addr == NULL) {
                pr_debug("probe: could not map shared mem region\n");
+               ret = -ENOMEM;
                goto out_free;
        }
        pcch_hdr = pcch_virt_addr;
index 2c9bf2692232e51a66e5455368d9881383ccfc2f..3265844839bfe9c79ef8849705262a52d16cc4e1 100644 (file)
@@ -678,10 +678,22 @@ static int cpuidle_coupled_cpu_notify(struct notifier_block *nb,
        int cpu = (unsigned long)hcpu;
        struct cpuidle_device *dev;
 
+       switch (action & ~CPU_TASKS_FROZEN) {
+       case CPU_UP_PREPARE:
+       case CPU_DOWN_PREPARE:
+       case CPU_ONLINE:
+       case CPU_DEAD:
+       case CPU_UP_CANCELED:
+       case CPU_DOWN_FAILED:
+               break;
+       default:
+               return NOTIFY_OK;
+       }
+
        mutex_lock(&cpuidle_lock);
 
        dev = per_cpu(cpuidle_devices, cpu);
-       if (!dev->coupled)
+       if (!dev || !dev->coupled)
                goto out;
 
        switch (action & ~CPU_TASKS_FROZEN) {
index b6a09ea859b135c31e6dcffbad0e7a3d2ad66eee..9b784051ec12b47564b3d07429096556b2fc2035 100644 (file)
@@ -88,6 +88,8 @@ static int ladder_select_state(struct cpuidle_driver *drv,
 
        /* consider promotion */
        if (last_idx < drv->state_count - 1 &&
+           !drv->states[last_idx + 1].disabled &&
+           !dev->states_usage[last_idx + 1].disable &&
            last_residency > last_state->threshold.promotion_time &&
            drv->states[last_idx + 1].exit_latency <= latency_req) {
                last_state->stats.promotion_count++;
@@ -100,7 +102,9 @@ static int ladder_select_state(struct cpuidle_driver *drv,
 
        /* consider demotion */
        if (last_idx > CPUIDLE_DRIVER_STATE_START &&
-           drv->states[last_idx].exit_latency > latency_req) {
+           (drv->states[last_idx].disabled ||
+           dev->states_usage[last_idx].disable ||
+           drv->states[last_idx].exit_latency > latency_req)) {
                int i;
 
                for (i = last_idx - 1; i > CPUIDLE_DRIVER_STATE_START; i--) {
index 7d74d092aa8fe1bac90c6ccd8652099d138b6e2e..662588a1c41b6a48fd1d4eb468de521fc415989b 100644 (file)
@@ -298,21 +298,15 @@ config CRYPTO_DEV_TEGRA_AES
          will be called tegra-aes.
 
 config CRYPTO_DEV_NX
-       tristate "Support for Power7+ in-Nest cryptographic acceleration"
+       bool "Support for IBM Power7+ in-Nest cryptographic acceleration"
        depends on PPC64 && IBMVIO
-       select CRYPTO_AES
-       select CRYPTO_CBC
-       select CRYPTO_ECB
-       select CRYPTO_CCM
-       select CRYPTO_GCM
-       select CRYPTO_AUTHENC
-       select CRYPTO_XCBC
-       select CRYPTO_SHA256
-       select CRYPTO_SHA512
+       default n
        help
-         Support for Power7+ in-Nest cryptographic acceleration. This
-         module supports acceleration for AES and SHA2 algorithms. If you
-         choose 'M' here, this module will be called nx_crypto.
+         Support for Power7+ in-Nest cryptographic acceleration.
+
+if CRYPTO_DEV_NX
+       source "drivers/crypto/nx/Kconfig"
+endif
 
 config CRYPTO_DEV_UX500
        tristate "Driver for ST-Ericsson UX500 crypto hardware acceleration"
index 6bb20fffbf496e85fdccf2139f2fbe786032ba79..872ca8c8d83b08b398c9947549cf409487b95aec 100644 (file)
@@ -1017,7 +1017,6 @@ static int atmel_aes_register_algs(struct atmel_aes_dev *dd)
        int err, i, j;
 
        for (i = 0; i < ARRAY_SIZE(aes_algs); i++) {
-               INIT_LIST_HEAD(&aes_algs[i].cra_list);
                err = crypto_register_alg(&aes_algs[i]);
                if (err)
                        goto err_aes_algs;
@@ -1026,7 +1025,6 @@ static int atmel_aes_register_algs(struct atmel_aes_dev *dd)
        atmel_aes_hw_version_init(dd);
 
        if (dd->hw_version >= 0x130) {
-               INIT_LIST_HEAD(&aes_cfb64_alg[0].cra_list);
                err = crypto_register_alg(&aes_cfb64_alg[0]);
                if (err)
                        goto err_aes_cfb64_alg;
index eb2b61e57e2de394ad211dd661f405aac8be2ef3..53c1680b551316b8a201df8179d8591a62f4a085 100644 (file)
@@ -1044,7 +1044,6 @@ static int atmel_tdes_register_algs(struct atmel_tdes_dev *dd)
        int err, i, j;
 
        for (i = 0; i < ARRAY_SIZE(tdes_algs); i++) {
-               INIT_LIST_HEAD(&tdes_algs[i].cra_list);
                err = crypto_register_alg(&tdes_algs[i]);
                if (err)
                        goto err_tdes_algs;
index 0c1ea8492eff632401a5750e36bc09b88eaed6fc..6b48295e218bfbad7972165d875142bda91c79e5 100644 (file)
@@ -205,7 +205,7 @@ static void init_sh_desc_key_aead(u32 *desc, struct caam_ctx *ctx,
 {
        u32 *key_jump_cmd;
 
-       init_sh_desc(desc, HDR_SHARE_WAIT);
+       init_sh_desc(desc, HDR_SHARE_SERIAL);
 
        /* Skip if already shared */
        key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
@@ -302,7 +302,7 @@ static int aead_set_sh_desc(struct crypto_aead *aead)
        desc = ctx->sh_desc_dec;
 
        /* aead_decrypt shared descriptor */
-       init_sh_desc(desc, HDR_SHARE_WAIT);
+       init_sh_desc(desc, HDR_SHARE_SERIAL);
 
        /* Skip if already shared */
        key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
@@ -564,7 +564,7 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
 
        /* ablkcipher_encrypt shared descriptor */
        desc = ctx->sh_desc_enc;
-       init_sh_desc(desc, HDR_SHARE_WAIT);
+       init_sh_desc(desc, HDR_SHARE_SERIAL);
        /* Skip if already shared */
        key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
                                   JUMP_COND_SHRD);
@@ -605,7 +605,7 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher,
        /* ablkcipher_decrypt shared descriptor */
        desc = ctx->sh_desc_dec;
 
-       init_sh_desc(desc, HDR_SHARE_WAIT);
+       init_sh_desc(desc, HDR_SHARE_SERIAL);
        /* Skip if already shared */
        key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL |
                                   JUMP_COND_SHRD);
index 895aaf2bca92e85bb7bca724b9ef73afeb51af4a..fbf3fe8b62f0b52161515f59b9d651b18ea73e65 100644 (file)
@@ -225,7 +225,7 @@ static inline void init_sh_desc_key_ahash(u32 *desc, struct caam_hash_ctx *ctx)
 {
        u32 *key_jump_cmd;
 
-       init_sh_desc(desc, HDR_SHARE_WAIT);
+       init_sh_desc(desc, HDR_SHARE_SERIAL);
 
        if (ctx->split_key_len) {
                /* Skip if already shared */
@@ -311,7 +311,7 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash)
        /* ahash_update shared descriptor */
        desc = ctx->sh_desc_update;
 
-       init_sh_desc(desc, HDR_SHARE_WAIT);
+       init_sh_desc(desc, HDR_SHARE_SERIAL);
 
        /* Import context from software */
        append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT |
@@ -1736,8 +1736,11 @@ static void __exit caam_algapi_hash_exit(void)
        struct caam_hash_alg *t_alg, *n;
 
        dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
-       if (!dev_node)
-               return;
+       if (!dev_node) {
+               dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
+               if (!dev_node)
+                       return;
+       }
 
        pdev = of_find_device_by_node(dev_node);
        if (!pdev)
@@ -1812,8 +1815,11 @@ static int __init caam_algapi_hash_init(void)
        int i = 0, err = 0;
 
        dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
-       if (!dev_node)
-               return -ENODEV;
+       if (!dev_node) {
+               dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
+               if (!dev_node)
+                       return -ENODEV;
+       }
 
        pdev = of_find_device_by_node(dev_node);
        if (!pdev)
index e2bfe161dece0fd433f457659c12871eff4fc706..d1939a9539c06a4204a26b65d3d743d46c2346d3 100644 (file)
@@ -193,7 +193,7 @@ static inline void rng_create_sh_desc(struct caam_rng_ctx *ctx)
        struct device *jrdev = ctx->jrdev;
        u32 *desc = ctx->sh_desc;
 
-       init_sh_desc(desc, HDR_SHARE_WAIT);
+       init_sh_desc(desc, HDR_SHARE_SERIAL);
 
        /* Propagate errors from shared to job descriptor */
        append_cmd(desc, SET_OK_NO_PROP_ERRORS | CMD_LOAD);
@@ -284,8 +284,11 @@ static int __init caam_rng_init(void)
        struct caam_drv_private *priv;
 
        dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec-v4.0");
-       if (!dev_node)
-               return -ENODEV;
+       if (!dev_node) {
+               dev_node = of_find_compatible_node(NULL, NULL, "fsl,sec4.0");
+               if (!dev_node)
+                       return -ENODEV;
+       }
 
        pdev = of_find_device_by_node(dev_node);
        if (!pdev)
index 53c8c51d58817cb62b4641d5e923bb4f72b39f2f..93d14070141ae64fe4e96dd838fc28c36061b3cf 100644 (file)
@@ -63,7 +63,7 @@ static void caam_jr_dequeue(unsigned long devarg)
 
                head = ACCESS_ONCE(jrp->head);
 
-               spin_lock_bh(&jrp->outlock);
+               spin_lock(&jrp->outlock);
 
                sw_idx = tail = jrp->tail;
                hw_idx = jrp->out_ring_read_index;
@@ -115,7 +115,7 @@ static void caam_jr_dequeue(unsigned long devarg)
                        jrp->tail = tail;
                }
 
-               spin_unlock_bh(&jrp->outlock);
+               spin_unlock(&jrp->outlock);
 
                /* Finally, execute user's callback */
                usercall(dev, userdesc, userstatus, userarg);
@@ -236,14 +236,14 @@ int caam_jr_enqueue(struct device *dev, u32 *desc,
                return -EIO;
        }
 
-       spin_lock(&jrp->inplock);
+       spin_lock_bh(&jrp->inplock);
 
        head = jrp->head;
        tail = ACCESS_ONCE(jrp->tail);
 
        if (!rd_reg32(&jrp->rregs->inpring_avail) ||
            CIRC_SPACE(head, tail, JOBR_DEPTH) <= 0) {
-               spin_unlock(&jrp->inplock);
+               spin_unlock_bh(&jrp->inplock);
                dma_unmap_single(dev, desc_dma, desc_size, DMA_TO_DEVICE);
                return -EBUSY;
        }
@@ -265,7 +265,7 @@ int caam_jr_enqueue(struct device *dev, u32 *desc,
 
        wr_reg32(&jrp->rregs->inpring_jobadd, 1);
 
-       spin_unlock(&jrp->inplock);
+       spin_unlock_bh(&jrp->inplock);
 
        return 0;
 }
index f3e36c86b6c32f76995e9a28f152e1386c6f0dbd..933fb4b4a4c720d5e1316a6a5fb113a9d676804e 100644 (file)
@@ -289,7 +289,6 @@ static struct crypto_alg geode_alg = {
        .cra_blocksize          =       AES_MIN_BLOCK_SIZE,
        .cra_ctxsize            =       sizeof(struct geode_aes_op),
        .cra_module                     =       THIS_MODULE,
-       .cra_list                       =       LIST_HEAD_INIT(geode_alg.cra_list),
        .cra_u                          =       {
                .cipher =       {
                        .cia_min_keysize        =       AES_MIN_KEY_SIZE,
@@ -402,7 +401,6 @@ static struct crypto_alg geode_cbc_alg = {
        .cra_alignmask          =       15,
        .cra_type                       =       &crypto_blkcipher_type,
        .cra_module                     =       THIS_MODULE,
-       .cra_list                       =       LIST_HEAD_INIT(geode_cbc_alg.cra_list),
        .cra_u                          =       {
                .blkcipher      =       {
                        .min_keysize    =       AES_MIN_KEY_SIZE,
@@ -489,7 +487,6 @@ static struct crypto_alg geode_ecb_alg = {
        .cra_alignmask          =       15,
        .cra_type                       =       &crypto_blkcipher_type,
        .cra_module                     =       THIS_MODULE,
-       .cra_list                       =       LIST_HEAD_INIT(geode_ecb_alg.cra_list),
        .cra_u                          =       {
                .blkcipher      =       {
                        .min_keysize    =       AES_MIN_KEY_SIZE,
index c9c4befb5a8d261701698c570c668d5009113a64..df14358d7fa1658c48e10d8b7a768f32eec6b9ac 100644 (file)
@@ -821,8 +821,8 @@ static int hifn_register_rng(struct hifn_device *dev)
        /*
         * We must wait at least 256 Pk_clk cycles between two reads of the rng.
         */
-       dev->rng_wait_time      = DIV_ROUND_UP(NSEC_PER_SEC, dev->pk_clk_freq) *
-                                 256;
+       dev->rng_wait_time      = DIV_ROUND_UP_ULL(NSEC_PER_SEC,
+                                                  dev->pk_clk_freq) * 256;
 
        dev->rng.name           = dev->name;
        dev->rng.data_present   = hifn_rng_data_present,
diff --git a/drivers/crypto/nx/Kconfig b/drivers/crypto/nx/Kconfig
new file mode 100644 (file)
index 0000000..f826166
--- /dev/null
@@ -0,0 +1,26 @@
+config CRYPTO_DEV_NX_ENCRYPT
+       tristate "Encryption acceleration support"
+       depends on PPC64 && IBMVIO
+       default y
+       select CRYPTO_AES
+       select CRYPTO_CBC
+       select CRYPTO_ECB
+       select CRYPTO_CCM
+       select CRYPTO_GCM
+       select CRYPTO_AUTHENC
+       select CRYPTO_XCBC
+       select CRYPTO_SHA256
+       select CRYPTO_SHA512
+       help
+         Support for Power7+ in-Nest encryption acceleration. This
+         module supports acceleration for AES and SHA2 algorithms. If you
+         choose 'M' here, this module will be called nx_crypto.
+
+config CRYPTO_DEV_NX_COMPRESS
+       tristate "Compression acceleration support"
+       depends on PPC64 && IBMVIO
+       default y
+       help
+         Support for Power7+ in-Nest compression acceleration. This
+         module supports acceleration for AES and SHA2 algorithms. If you
+         choose 'M' here, this module will be called nx_compress.
index 411ce59c80d1169e4b2b579f85b5fa67ecddf12c..bb770ea45ce9390f47ac3bd52e5ecbb132c361c3 100644 (file)
@@ -1,4 +1,4 @@
-obj-$(CONFIG_CRYPTO_DEV_NX) += nx-crypto.o
+obj-$(CONFIG_CRYPTO_DEV_NX_ENCRYPT) += nx-crypto.o
 nx-crypto-objs := nx.o \
                  nx_debugfs.o \
                  nx-aes-cbc.o \
@@ -9,3 +9,6 @@ nx-crypto-objs := nx.o \
                  nx-aes-xcbc.o \
                  nx-sha256.o \
                  nx-sha512.o
+
+obj-$(CONFIG_CRYPTO_DEV_NX_COMPRESS) += nx-compress.o
+nx-compress-objs := nx-842.o
diff --git a/drivers/crypto/nx/nx-842.c b/drivers/crypto/nx/nx-842.c
new file mode 100644 (file)
index 0000000..9da0fb2
--- /dev/null
@@ -0,0 +1,1615 @@
+/*
+ * Driver for IBM Power 842 compression accelerator
+ *
+ * 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, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Copyright (C) IBM Corporation, 2012
+ *
+ * Authors: Robert Jennings <rcj@linux.vnet.ibm.com>
+ *          Seth Jennings <sjenning@linux.vnet.ibm.com>
+ */
+
+#include <linux/module.h>
+#include <asm/vio.h>
+#include <asm/pSeries_reconfig.h>
+#include <linux/slab.h>
+#include <asm/abs_addr.h>
+#include <linux/nx842.h>
+#include <linux/kernel.h>
+
+#include "nx_csbcpb.h" /* struct nx_csbcpb */
+
+#define MODULE_NAME "nx-compress"
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Robert Jennings <rcj@linux.vnet.ibm.com>");
+MODULE_DESCRIPTION("842 H/W Compression driver for IBM Power processors");
+
+#define SHIFT_4K 12
+#define SHIFT_64K 16
+#define SIZE_4K (1UL << SHIFT_4K)
+#define SIZE_64K (1UL << SHIFT_64K)
+
+/* IO buffer must be 128 byte aligned */
+#define IO_BUFFER_ALIGN 128
+
+struct nx842_header {
+       int blocks_nr; /* number of compressed blocks */
+       int offset; /* offset of the first block (from beginning of header) */
+       int sizes[0]; /* size of compressed blocks */
+};
+
+static inline int nx842_header_size(const struct nx842_header *hdr)
+{
+       return sizeof(struct nx842_header) +
+                       hdr->blocks_nr * sizeof(hdr->sizes[0]);
+}
+
+/* Macros for fields within nx_csbcpb */
+/* Check the valid bit within the csbcpb valid field */
+#define NX842_CSBCBP_VALID_CHK(x) (x & BIT_MASK(7))
+
+/* CE macros operate on the completion_extension field bits in the csbcpb.
+ * CE0 0=full completion, 1=partial completion
+ * CE1 0=CE0 indicates completion, 1=termination (output may be modified)
+ * CE2 0=processed_bytes is source bytes, 1=processed_bytes is target bytes */
+#define NX842_CSBCPB_CE0(x)    (x & BIT_MASK(7))
+#define NX842_CSBCPB_CE1(x)    (x & BIT_MASK(6))
+#define NX842_CSBCPB_CE2(x)    (x & BIT_MASK(5))
+
+/* The NX unit accepts data only on 4K page boundaries */
+#define NX842_HW_PAGE_SHIFT    SHIFT_4K
+#define NX842_HW_PAGE_SIZE     (ASM_CONST(1) << NX842_HW_PAGE_SHIFT)
+#define NX842_HW_PAGE_MASK     (~(NX842_HW_PAGE_SIZE-1))
+
+enum nx842_status {
+       UNAVAILABLE,
+       AVAILABLE
+};
+
+struct ibm_nx842_counters {
+       atomic64_t comp_complete;
+       atomic64_t comp_failed;
+       atomic64_t decomp_complete;
+       atomic64_t decomp_failed;
+       atomic64_t swdecomp;
+       atomic64_t comp_times[32];
+       atomic64_t decomp_times[32];
+};
+
+static struct nx842_devdata {
+       struct vio_dev *vdev;
+       struct device *dev;
+       struct ibm_nx842_counters *counters;
+       unsigned int max_sg_len;
+       unsigned int max_sync_size;
+       unsigned int max_sync_sg;
+       enum nx842_status status;
+} __rcu *devdata;
+static DEFINE_SPINLOCK(devdata_mutex);
+
+#define NX842_COUNTER_INC(_x) \
+static inline void nx842_inc_##_x( \
+       const struct nx842_devdata *dev) { \
+       if (dev) \
+               atomic64_inc(&dev->counters->_x); \
+}
+NX842_COUNTER_INC(comp_complete);
+NX842_COUNTER_INC(comp_failed);
+NX842_COUNTER_INC(decomp_complete);
+NX842_COUNTER_INC(decomp_failed);
+NX842_COUNTER_INC(swdecomp);
+
+#define NX842_HIST_SLOTS 16
+
+static void ibm_nx842_incr_hist(atomic64_t *times, unsigned int time)
+{
+       int bucket = fls(time);
+
+       if (bucket)
+               bucket = min((NX842_HIST_SLOTS - 1), bucket - 1);
+
+       atomic64_inc(&times[bucket]);
+}
+
+/* NX unit operation flags */
+#define NX842_OP_COMPRESS      0x0
+#define NX842_OP_CRC           0x1
+#define NX842_OP_DECOMPRESS    0x2
+#define NX842_OP_COMPRESS_CRC   (NX842_OP_COMPRESS | NX842_OP_CRC)
+#define NX842_OP_DECOMPRESS_CRC (NX842_OP_DECOMPRESS | NX842_OP_CRC)
+#define NX842_OP_ASYNC         (1<<23)
+#define NX842_OP_NOTIFY                (1<<22)
+#define NX842_OP_NOTIFY_INT(x) ((x & 0xff)<<8)
+
+static unsigned long nx842_get_desired_dma(struct vio_dev *viodev)
+{
+       /* No use of DMA mappings within the driver. */
+       return 0;
+}
+
+struct nx842_slentry {
+       unsigned long ptr; /* Absolute address (use virt_to_abs()) */
+       unsigned long len;
+};
+
+/* pHyp scatterlist entry */
+struct nx842_scatterlist {
+       int entry_nr; /* number of slentries */
+       struct nx842_slentry *entries; /* ptr to array of slentries */
+};
+
+/* Does not include sizeof(entry_nr) in the size */
+static inline unsigned long nx842_get_scatterlist_size(
+                               struct nx842_scatterlist *sl)
+{
+       return sl->entry_nr * sizeof(struct nx842_slentry);
+}
+
+static int nx842_build_scatterlist(unsigned long buf, int len,
+                       struct nx842_scatterlist *sl)
+{
+       unsigned long nextpage;
+       struct nx842_slentry *entry;
+
+       sl->entry_nr = 0;
+
+       entry = sl->entries;
+       while (len) {
+               entry->ptr = virt_to_abs(buf);
+               nextpage = ALIGN(buf + 1, NX842_HW_PAGE_SIZE);
+               if (nextpage < buf + len) {
+                       /* we aren't at the end yet */
+                       if (IS_ALIGNED(buf, NX842_HW_PAGE_SIZE))
+                               /* we are in the middle (or beginning) */
+                               entry->len = NX842_HW_PAGE_SIZE;
+                       else
+                               /* we are at the beginning */
+                               entry->len = nextpage - buf;
+               } else {
+                       /* at the end */
+                       entry->len = len;
+               }
+
+               len -= entry->len;
+               buf += entry->len;
+               sl->entry_nr++;
+               entry++;
+       }
+
+       return 0;
+}
+
+/*
+ * Working memory for software decompression
+ */
+struct sw842_fifo {
+       union {
+               char f8[256][8];
+               char f4[512][4];
+       };
+       char f2[256][2];
+       unsigned char f84_full;
+       unsigned char f2_full;
+       unsigned char f8_count;
+       unsigned char f2_count;
+       unsigned int f4_count;
+};
+
+/*
+ * Working memory for crypto API
+ */
+struct nx842_workmem {
+       char bounce[PAGE_SIZE]; /* bounce buffer for decompression input */
+       union {
+               /* hardware working memory */
+               struct {
+                       /* scatterlist */
+                       char slin[SIZE_4K];
+                       char slout[SIZE_4K];
+                       /* coprocessor status/parameter block */
+                       struct nx_csbcpb csbcpb;
+               };
+               /* software working memory */
+               struct sw842_fifo swfifo; /* software decompression fifo */
+       };
+};
+
+int nx842_get_workmem_size(void)
+{
+       return sizeof(struct nx842_workmem) + NX842_HW_PAGE_SIZE;
+}
+EXPORT_SYMBOL_GPL(nx842_get_workmem_size);
+
+int nx842_get_workmem_size_aligned(void)
+{
+       return sizeof(struct nx842_workmem);
+}
+EXPORT_SYMBOL_GPL(nx842_get_workmem_size_aligned);
+
+static int nx842_validate_result(struct device *dev,
+       struct cop_status_block *csb)
+{
+       /* The csb must be valid after returning from vio_h_cop_sync */
+       if (!NX842_CSBCBP_VALID_CHK(csb->valid)) {
+               dev_err(dev, "%s: cspcbp not valid upon completion.\n",
+                               __func__);
+               dev_dbg(dev, "valid:0x%02x cs:0x%02x cc:0x%02x ce:0x%02x\n",
+                               csb->valid,
+                               csb->crb_seq_number,
+                               csb->completion_code,
+                               csb->completion_extension);
+               dev_dbg(dev, "processed_bytes:%d address:0x%016lx\n",
+                               csb->processed_byte_count,
+                               (unsigned long)csb->address);
+               return -EIO;
+       }
+
+       /* Check return values from the hardware in the CSB */
+       switch (csb->completion_code) {
+       case 0: /* Completed without error */
+               break;
+       case 64: /* Target bytes > Source bytes during compression */
+       case 13: /* Output buffer too small */
+               dev_dbg(dev, "%s: Compression output larger than input\n",
+                                       __func__);
+               return -ENOSPC;
+       case 66: /* Input data contains an illegal template field */
+       case 67: /* Template indicates data past the end of the input stream */
+               dev_dbg(dev, "%s: Bad data for decompression (code:%d)\n",
+                                       __func__, csb->completion_code);
+               return -EINVAL;
+       default:
+               dev_dbg(dev, "%s: Unspecified error (code:%d)\n",
+                                       __func__, csb->completion_code);
+               return -EIO;
+       }
+
+       /* Hardware sanity check */
+       if (!NX842_CSBCPB_CE2(csb->completion_extension)) {
+               dev_err(dev, "%s: No error returned by hardware, but "
+                               "data returned is unusable, contact support.\n"
+                               "(Additional info: csbcbp->processed bytes "
+                               "does not specify processed bytes for the "
+                               "target buffer.)\n", __func__);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+/**
+ * nx842_compress - Compress data using the 842 algorithm
+ *
+ * Compression provide by the NX842 coprocessor on IBM Power systems.
+ * The input buffer is compressed and the result is stored in the
+ * provided output buffer.
+ *
+ * Upon return from this function @outlen contains the length of the
+ * compressed data.  If there is an error then @outlen will be 0 and an
+ * error will be specified by the return code from this function.
+ *
+ * @in: Pointer to input buffer, must be page aligned
+ * @inlen: Length of input buffer, must be PAGE_SIZE
+ * @out: Pointer to output buffer
+ * @outlen: Length of output buffer
+ * @wrkmem: ptr to buffer for working memory, size determined by
+ *          nx842_get_workmem_size()
+ *
+ * Returns:
+ *   0         Success, output of length @outlen stored in the buffer at @out
+ *   -ENOMEM   Unable to allocate internal buffers
+ *   -ENOSPC   Output buffer is to small
+ *   -EMSGSIZE XXX Difficult to describe this limitation
+ *   -EIO      Internal error
+ *   -ENODEV   Hardware unavailable
+ */
+int nx842_compress(const unsigned char *in, unsigned int inlen,
+                      unsigned char *out, unsigned int *outlen, void *wmem)
+{
+       struct nx842_header *hdr;
+       struct nx842_devdata *local_devdata;
+       struct device *dev = NULL;
+       struct nx842_workmem *workmem;
+       struct nx842_scatterlist slin, slout;
+       struct nx_csbcpb *csbcpb;
+       int ret = 0, max_sync_size, i, bytesleft, size, hdrsize;
+       unsigned long inbuf, outbuf, padding;
+       struct vio_pfo_op op = {
+               .done = NULL,
+               .handle = 0,
+               .timeout = 0,
+       };
+       unsigned long start_time = get_tb();
+
+       /*
+        * Make sure input buffer is 64k page aligned.  This is assumed since
+        * this driver is designed for page compression only (for now).  This
+        * is very nice since we can now use direct DDE(s) for the input and
+        * the alignment is guaranteed.
+       */
+       inbuf = (unsigned long)in;
+       if (!IS_ALIGNED(inbuf, PAGE_SIZE) || inlen != PAGE_SIZE)
+               return -EINVAL;
+
+       rcu_read_lock();
+       local_devdata = rcu_dereference(devdata);
+       if (!local_devdata || !local_devdata->dev) {
+               rcu_read_unlock();
+               return -ENODEV;
+       }
+       max_sync_size = local_devdata->max_sync_size;
+       dev = local_devdata->dev;
+
+       /* Create the header */
+       hdr = (struct nx842_header *)out;
+       hdr->blocks_nr = PAGE_SIZE / max_sync_size;
+       hdrsize = nx842_header_size(hdr);
+       outbuf = (unsigned long)out + hdrsize;
+       bytesleft = *outlen - hdrsize;
+
+       /* Init scatterlist */
+       workmem = (struct nx842_workmem *)ALIGN((unsigned long)wmem,
+               NX842_HW_PAGE_SIZE);
+       slin.entries = (struct nx842_slentry *)workmem->slin;
+       slout.entries = (struct nx842_slentry *)workmem->slout;
+
+       /* Init operation */
+       op.flags = NX842_OP_COMPRESS;
+       csbcpb = &workmem->csbcpb;
+       memset(csbcpb, 0, sizeof(*csbcpb));
+       op.csbcpb = virt_to_abs(csbcpb);
+       op.out = virt_to_abs(slout.entries);
+
+       for (i = 0; i < hdr->blocks_nr; i++) {
+               /*
+                * Aligning the output blocks to 128 bytes does waste space,
+                * but it prevents the need for bounce buffers and memory
+                * copies.  It also simplifies the code a lot.  In the worst
+                * case (64k page, 4k max_sync_size), you lose up to
+                * (128*16)/64k = ~3% the compression factor. For 64k
+                * max_sync_size, the loss would be at most 128/64k = ~0.2%.
+                */
+               padding = ALIGN(outbuf, IO_BUFFER_ALIGN) - outbuf;
+               outbuf += padding;
+               bytesleft -= padding;
+               if (i == 0)
+                       /* save offset into first block in header */
+                       hdr->offset = padding + hdrsize;
+
+               if (bytesleft <= 0) {
+                       ret = -ENOSPC;
+                       goto unlock;
+               }
+
+               /*
+                * NOTE: If the default max_sync_size is changed from 4k
+                * to 64k, remove the "likely" case below, since a
+                * scatterlist will always be needed.
+                */
+               if (likely(max_sync_size == NX842_HW_PAGE_SIZE)) {
+                       /* Create direct DDE */
+                       op.in = virt_to_abs(inbuf);
+                       op.inlen = max_sync_size;
+
+               } else {
+                       /* Create indirect DDE (scatterlist) */
+                       nx842_build_scatterlist(inbuf, max_sync_size, &slin);
+                       op.in = virt_to_abs(slin.entries);
+                       op.inlen = -nx842_get_scatterlist_size(&slin);
+               }
+
+               /*
+                * If max_sync_size != NX842_HW_PAGE_SIZE, an indirect
+                * DDE is required for the outbuf.
+                * If max_sync_size == NX842_HW_PAGE_SIZE, outbuf must
+                * also be page aligned (1 in 128/4k=32 chance) in order
+                * to use a direct DDE.
+                * This is unlikely, just use an indirect DDE always.
+                */
+               nx842_build_scatterlist(outbuf,
+                       min(bytesleft, max_sync_size), &slout);
+               /* op.out set before loop */
+               op.outlen = -nx842_get_scatterlist_size(&slout);
+
+               /* Send request to pHyp */
+               ret = vio_h_cop_sync(local_devdata->vdev, &op);
+
+               /* Check for pHyp error */
+               if (ret) {
+                       dev_dbg(dev, "%s: vio_h_cop_sync error (ret=%d, hret=%ld)\n",
+                               __func__, ret, op.hcall_err);
+                       ret = -EIO;
+                       goto unlock;
+               }
+
+               /* Check for hardware error */
+               ret = nx842_validate_result(dev, &csbcpb->csb);
+               if (ret && ret != -ENOSPC)
+                       goto unlock;
+
+               /* Handle incompressible data */
+               if (unlikely(ret == -ENOSPC)) {
+                       if (bytesleft < max_sync_size) {
+                               /*
+                                * Not enough space left in the output buffer
+                                * to store uncompressed block
+                                */
+                               goto unlock;
+                       } else {
+                               /* Store incompressible block */
+                               memcpy((void *)outbuf, (void *)inbuf,
+                                       max_sync_size);
+                               hdr->sizes[i] = -max_sync_size;
+                               outbuf += max_sync_size;
+                               bytesleft -= max_sync_size;
+                               /* Reset ret, incompressible data handled */
+                               ret = 0;
+                       }
+               } else {
+                       /* Normal case, compression was successful */
+                       size = csbcpb->csb.processed_byte_count;
+                       dev_dbg(dev, "%s: processed_bytes=%d\n",
+                               __func__, size);
+                       hdr->sizes[i] = size;
+                       outbuf += size;
+                       bytesleft -= size;
+               }
+
+               inbuf += max_sync_size;
+       }
+
+       *outlen = (unsigned int)(outbuf - (unsigned long)out);
+
+unlock:
+       if (ret)
+               nx842_inc_comp_failed(local_devdata);
+       else {
+               nx842_inc_comp_complete(local_devdata);
+               ibm_nx842_incr_hist(local_devdata->counters->comp_times,
+                       (get_tb() - start_time) / tb_ticks_per_usec);
+       }
+       rcu_read_unlock();
+       return ret;
+}
+EXPORT_SYMBOL_GPL(nx842_compress);
+
+static int sw842_decompress(const unsigned char *, int, unsigned char *, int *,
+                       const void *);
+
+/**
+ * nx842_decompress - Decompress data using the 842 algorithm
+ *
+ * Decompression provide by the NX842 coprocessor on IBM Power systems.
+ * The input buffer is decompressed and the result is stored in the
+ * provided output buffer.  The size allocated to the output buffer is
+ * provided by the caller of this function in @outlen.  Upon return from
+ * this function @outlen contains the length of the decompressed data.
+ * If there is an error then @outlen will be 0 and an error will be
+ * specified by the return code from this function.
+ *
+ * @in: Pointer to input buffer, will use bounce buffer if not 128 byte
+ *      aligned
+ * @inlen: Length of input buffer
+ * @out: Pointer to output buffer, must be page aligned
+ * @outlen: Length of output buffer, must be PAGE_SIZE
+ * @wrkmem: ptr to buffer for working memory, size determined by
+ *          nx842_get_workmem_size()
+ *
+ * Returns:
+ *   0         Success, output of length @outlen stored in the buffer at @out
+ *   -ENODEV   Hardware decompression device is unavailable
+ *   -ENOMEM   Unable to allocate internal buffers
+ *   -ENOSPC   Output buffer is to small
+ *   -EINVAL   Bad input data encountered when attempting decompress
+ *   -EIO      Internal error
+ */
+int nx842_decompress(const unsigned char *in, unsigned int inlen,
+                        unsigned char *out, unsigned int *outlen, void *wmem)
+{
+       struct nx842_header *hdr;
+       struct nx842_devdata *local_devdata;
+       struct device *dev = NULL;
+       struct nx842_workmem *workmem;
+       struct nx842_scatterlist slin, slout;
+       struct nx_csbcpb *csbcpb;
+       int ret = 0, i, size, max_sync_size;
+       unsigned long inbuf, outbuf;
+       struct vio_pfo_op op = {
+               .done = NULL,
+               .handle = 0,
+               .timeout = 0,
+       };
+       unsigned long start_time = get_tb();
+
+       /* Ensure page alignment and size */
+       outbuf = (unsigned long)out;
+       if (!IS_ALIGNED(outbuf, PAGE_SIZE) || *outlen != PAGE_SIZE)
+               return -EINVAL;
+
+       rcu_read_lock();
+       local_devdata = rcu_dereference(devdata);
+       if (local_devdata)
+               dev = local_devdata->dev;
+
+       /* Get header */
+       hdr = (struct nx842_header *)in;
+
+       workmem = (struct nx842_workmem *)ALIGN((unsigned long)wmem,
+               NX842_HW_PAGE_SIZE);
+
+       inbuf = (unsigned long)in + hdr->offset;
+       if (likely(!IS_ALIGNED(inbuf, IO_BUFFER_ALIGN))) {
+               /* Copy block(s) into bounce buffer for alignment */
+               memcpy(workmem->bounce, in + hdr->offset, inlen - hdr->offset);
+               inbuf = (unsigned long)workmem->bounce;
+       }
+
+       /* Init scatterlist */
+       slin.entries = (struct nx842_slentry *)workmem->slin;
+       slout.entries = (struct nx842_slentry *)workmem->slout;
+
+       /* Init operation */
+       op.flags = NX842_OP_DECOMPRESS;
+       csbcpb = &workmem->csbcpb;
+       memset(csbcpb, 0, sizeof(*csbcpb));
+       op.csbcpb = virt_to_abs(csbcpb);
+
+       /*
+        * max_sync_size may have changed since compression,
+        * so we can't read it from the device info. We need
+        * to derive it from hdr->blocks_nr.
+        */
+       max_sync_size = PAGE_SIZE / hdr->blocks_nr;
+
+       for (i = 0; i < hdr->blocks_nr; i++) {
+               /* Skip padding */
+               inbuf = ALIGN(inbuf, IO_BUFFER_ALIGN);
+
+               if (hdr->sizes[i] < 0) {
+                       /* Negative sizes indicate uncompressed data blocks */
+                       size = abs(hdr->sizes[i]);
+                       memcpy((void *)outbuf, (void *)inbuf, size);
+                       outbuf += size;
+                       inbuf += size;
+                       continue;
+               }
+
+               if (!dev)
+                       goto sw;
+
+               /*
+                * The better the compression, the more likely the "likely"
+                * case becomes.
+                */
+               if (likely((inbuf & NX842_HW_PAGE_MASK) ==
+                       ((inbuf + hdr->sizes[i] - 1) & NX842_HW_PAGE_MASK))) {
+                       /* Create direct DDE */
+                       op.in = virt_to_abs(inbuf);
+                       op.inlen = hdr->sizes[i];
+               } else {
+                       /* Create indirect DDE (scatterlist) */
+                       nx842_build_scatterlist(inbuf, hdr->sizes[i] , &slin);
+                       op.in = virt_to_abs(slin.entries);
+                       op.inlen = -nx842_get_scatterlist_size(&slin);
+               }
+
+               /*
+                * NOTE: If the default max_sync_size is changed from 4k
+                * to 64k, remove the "likely" case below, since a
+                * scatterlist will always be needed.
+                */
+               if (likely(max_sync_size == NX842_HW_PAGE_SIZE)) {
+                       /* Create direct DDE */
+                       op.out = virt_to_abs(outbuf);
+                       op.outlen = max_sync_size;
+               } else {
+                       /* Create indirect DDE (scatterlist) */
+                       nx842_build_scatterlist(outbuf, max_sync_size, &slout);
+                       op.out = virt_to_abs(slout.entries);
+                       op.outlen = -nx842_get_scatterlist_size(&slout);
+               }
+
+               /* Send request to pHyp */
+               ret = vio_h_cop_sync(local_devdata->vdev, &op);
+
+               /* Check for pHyp error */
+               if (ret) {
+                       dev_dbg(dev, "%s: vio_h_cop_sync error (ret=%d, hret=%ld)\n",
+                               __func__, ret, op.hcall_err);
+                       dev = NULL;
+                       goto sw;
+               }
+
+               /* Check for hardware error */
+               ret = nx842_validate_result(dev, &csbcpb->csb);
+               if (ret) {
+                       dev = NULL;
+                       goto sw;
+               }
+
+               /* HW decompression success */
+               inbuf += hdr->sizes[i];
+               outbuf += csbcpb->csb.processed_byte_count;
+               continue;
+
+sw:
+               /* software decompression */
+               size = max_sync_size;
+               ret = sw842_decompress(
+                       (unsigned char *)inbuf, hdr->sizes[i],
+                       (unsigned char *)outbuf, &size, wmem);
+               if (ret)
+                       pr_debug("%s: sw842_decompress failed with %d\n",
+                               __func__, ret);
+
+               if (ret) {
+                       if (ret != -ENOSPC && ret != -EINVAL &&
+                                       ret != -EMSGSIZE)
+                               ret = -EIO;
+                       goto unlock;
+               }
+
+               /* SW decompression success */
+               inbuf += hdr->sizes[i];
+               outbuf += size;
+       }
+
+       *outlen = (unsigned int)(outbuf - (unsigned long)out);
+
+unlock:
+       if (ret)
+               /* decompress fail */
+               nx842_inc_decomp_failed(local_devdata);
+       else {
+               if (!dev)
+                       /* software decompress */
+                       nx842_inc_swdecomp(local_devdata);
+               nx842_inc_decomp_complete(local_devdata);
+               ibm_nx842_incr_hist(local_devdata->counters->decomp_times,
+                       (get_tb() - start_time) / tb_ticks_per_usec);
+       }
+
+       rcu_read_unlock();
+       return ret;
+}
+EXPORT_SYMBOL_GPL(nx842_decompress);
+
+/**
+ * nx842_OF_set_defaults -- Set default (disabled) values for devdata
+ *
+ * @devdata - struct nx842_devdata to update
+ *
+ * Returns:
+ *  0 on success
+ *  -ENOENT if @devdata ptr is NULL
+ */
+static int nx842_OF_set_defaults(struct nx842_devdata *devdata)
+{
+       if (devdata) {
+               devdata->max_sync_size = 0;
+               devdata->max_sync_sg = 0;
+               devdata->max_sg_len = 0;
+               devdata->status = UNAVAILABLE;
+               return 0;
+       } else
+               return -ENOENT;
+}
+
+/**
+ * nx842_OF_upd_status -- Update the device info from OF status prop
+ *
+ * The status property indicates if the accelerator is enabled.  If the
+ * device is in the OF tree it indicates that the hardware is present.
+ * The status field indicates if the device is enabled when the status
+ * is 'okay'.  Otherwise the device driver will be disabled.
+ *
+ * @devdata - struct nx842_devdata to update
+ * @prop - struct property point containing the maxsyncop for the update
+ *
+ * Returns:
+ *  0 - Device is available
+ *  -EINVAL - Device is not available
+ */
+static int nx842_OF_upd_status(struct nx842_devdata *devdata,
+                                       struct property *prop) {
+       int ret = 0;
+       const char *status = (const char *)prop->value;
+
+       if (!strncmp(status, "okay", (size_t)prop->length)) {
+               devdata->status = AVAILABLE;
+       } else {
+               dev_info(devdata->dev, "%s: status '%s' is not 'okay'\n",
+                               __func__, status);
+               devdata->status = UNAVAILABLE;
+       }
+
+       return ret;
+}
+
+/**
+ * nx842_OF_upd_maxsglen -- Update the device info from OF maxsglen prop
+ *
+ * Definition of the 'ibm,max-sg-len' OF property:
+ *  This field indicates the maximum byte length of a scatter list
+ *  for the platform facility. It is a single cell encoded as with encode-int.
+ *
+ * Example:
+ *  # od -x ibm,max-sg-len
+ *  0000000 0000 0ff0
+ *
+ *  In this example, the maximum byte length of a scatter list is
+ *  0x0ff0 (4,080).
+ *
+ * @devdata - struct nx842_devdata to update
+ * @prop - struct property point containing the maxsyncop for the update
+ *
+ * Returns:
+ *  0 on success
+ *  -EINVAL on failure
+ */
+static int nx842_OF_upd_maxsglen(struct nx842_devdata *devdata,
+                                       struct property *prop) {
+       int ret = 0;
+       const int *maxsglen = prop->value;
+
+       if (prop->length != sizeof(*maxsglen)) {
+               dev_err(devdata->dev, "%s: unexpected format for ibm,max-sg-len property\n", __func__);
+               dev_dbg(devdata->dev, "%s: ibm,max-sg-len is %d bytes long, expected %lu bytes\n", __func__,
+                               prop->length, sizeof(*maxsglen));
+               ret = -EINVAL;
+       } else {
+               devdata->max_sg_len = (unsigned int)min(*maxsglen,
+                               (int)NX842_HW_PAGE_SIZE);
+       }
+
+       return ret;
+}
+
+/**
+ * nx842_OF_upd_maxsyncop -- Update the device info from OF maxsyncop prop
+ *
+ * Definition of the 'ibm,max-sync-cop' OF property:
+ *  Two series of cells.  The first series of cells represents the maximums
+ *  that can be synchronously compressed. The second series of cells
+ *  represents the maximums that can be synchronously decompressed.
+ *  1. The first cell in each series contains the count of the number of
+ *     data length, scatter list elements pairs that follow â€“ each being
+ *     of the form
+ *    a. One cell data byte length
+ *    b. One cell total number of scatter list elements
+ *
+ * Example:
+ *  # od -x ibm,max-sync-cop
+ *  0000000 0000 0001 0000 1000 0000 01fe 0000 0001
+ *  0000020 0000 1000 0000 01fe
+ *
+ *  In this example, compression supports 0x1000 (4,096) data byte length
+ *  and 0x1fe (510) total scatter list elements.  Decompression supports
+ *  0x1000 (4,096) data byte length and 0x1f3 (510) total scatter list
+ *  elements.
+ *
+ * @devdata - struct nx842_devdata to update
+ * @prop - struct property point containing the maxsyncop for the update
+ *
+ * Returns:
+ *  0 on success
+ *  -EINVAL on failure
+ */
+static int nx842_OF_upd_maxsyncop(struct nx842_devdata *devdata,
+                                       struct property *prop) {
+       int ret = 0;
+       const struct maxsynccop_t {
+               int comp_elements;
+               int comp_data_limit;
+               int comp_sg_limit;
+               int decomp_elements;
+               int decomp_data_limit;
+               int decomp_sg_limit;
+       } *maxsynccop;
+
+       if (prop->length != sizeof(*maxsynccop)) {
+               dev_err(devdata->dev, "%s: unexpected format for ibm,max-sync-cop property\n", __func__);
+               dev_dbg(devdata->dev, "%s: ibm,max-sync-cop is %d bytes long, expected %lu bytes\n", __func__, prop->length,
+                               sizeof(*maxsynccop));
+               ret = -EINVAL;
+               goto out;
+       }
+
+       maxsynccop = (const struct maxsynccop_t *)prop->value;
+
+       /* Use one limit rather than separate limits for compression and
+        * decompression. Set a maximum for this so as not to exceed the
+        * size that the header can support and round the value down to
+        * the hardware page size (4K) */
+       devdata->max_sync_size =
+                       (unsigned int)min(maxsynccop->comp_data_limit,
+                                       maxsynccop->decomp_data_limit);
+
+       devdata->max_sync_size = min_t(unsigned int, devdata->max_sync_size,
+                                       SIZE_64K);
+
+       if (devdata->max_sync_size < SIZE_4K) {
+               dev_err(devdata->dev, "%s: hardware max data size (%u) is "
+                               "less than the driver minimum, unable to use "
+                               "the hardware device\n",
+                               __func__, devdata->max_sync_size);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       devdata->max_sync_sg = (unsigned int)min(maxsynccop->comp_sg_limit,
+                                               maxsynccop->decomp_sg_limit);
+       if (devdata->max_sync_sg < 1) {
+               dev_err(devdata->dev, "%s: hardware max sg size (%u) is "
+                               "less than the driver minimum, unable to use "
+                               "the hardware device\n",
+                               __func__, devdata->max_sync_sg);
+               ret = -EINVAL;
+               goto out;
+       }
+
+out:
+       return ret;
+}
+
+/**
+ *
+ * nx842_OF_upd -- Handle OF properties updates for the device.
+ *
+ * Set all properties from the OF tree.  Optionally, a new property
+ * can be provided by the @new_prop pointer to overwrite an existing value.
+ * The device will remain disabled until all values are valid, this function
+ * will return an error for updates unless all values are valid.
+ *
+ * @new_prop: If not NULL, this property is being updated.  If NULL, update
+ *  all properties from the current values in the OF tree.
+ *
+ * Returns:
+ *  0 - Success
+ *  -ENOMEM - Could not allocate memory for new devdata structure
+ *  -EINVAL - property value not found, new_prop is not a recognized
+ *     property for the device or property value is not valid.
+ *  -ENODEV - Device is not available
+ */
+static int nx842_OF_upd(struct property *new_prop)
+{
+       struct nx842_devdata *old_devdata = NULL;
+       struct nx842_devdata *new_devdata = NULL;
+       struct device_node *of_node = NULL;
+       struct property *status = NULL;
+       struct property *maxsglen = NULL;
+       struct property *maxsyncop = NULL;
+       int ret = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&devdata_mutex, flags);
+       old_devdata = rcu_dereference_check(devdata,
+                       lockdep_is_held(&devdata_mutex));
+       if (old_devdata)
+               of_node = old_devdata->dev->of_node;
+
+       if (!old_devdata || !of_node) {
+               pr_err("%s: device is not available\n", __func__);
+               spin_unlock_irqrestore(&devdata_mutex, flags);
+               return -ENODEV;
+       }
+
+       new_devdata = kzalloc(sizeof(*new_devdata), GFP_NOFS);
+       if (!new_devdata) {
+               dev_err(old_devdata->dev, "%s: Could not allocate memory for device data\n", __func__);
+               ret = -ENOMEM;
+               goto error_out;
+       }
+
+       memcpy(new_devdata, old_devdata, sizeof(*old_devdata));
+       new_devdata->counters = old_devdata->counters;
+
+       /* Set ptrs for existing properties */
+       status = of_find_property(of_node, "status", NULL);
+       maxsglen = of_find_property(of_node, "ibm,max-sg-len", NULL);
+       maxsyncop = of_find_property(of_node, "ibm,max-sync-cop", NULL);
+       if (!status || !maxsglen || !maxsyncop) {
+               dev_err(old_devdata->dev, "%s: Could not locate device properties\n", __func__);
+               ret = -EINVAL;
+               goto error_out;
+       }
+
+       /* Set ptr to new property if provided */
+       if (new_prop) {
+               /* Single property */
+               if (!strncmp(new_prop->name, "status", new_prop->length)) {
+                       status = new_prop;
+
+               } else if (!strncmp(new_prop->name, "ibm,max-sg-len",
+                                       new_prop->length)) {
+                       maxsglen = new_prop;
+
+               } else if (!strncmp(new_prop->name, "ibm,max-sync-cop",
+                                       new_prop->length)) {
+                       maxsyncop = new_prop;
+
+               } else {
+                       /*
+                        * Skip the update, the property being updated
+                        * has no impact.
+                        */
+                       goto out;
+               }
+       }
+
+       /* Perform property updates */
+       ret = nx842_OF_upd_status(new_devdata, status);
+       if (ret)
+               goto error_out;
+
+       ret = nx842_OF_upd_maxsglen(new_devdata, maxsglen);
+       if (ret)
+               goto error_out;
+
+       ret = nx842_OF_upd_maxsyncop(new_devdata, maxsyncop);
+       if (ret)
+               goto error_out;
+
+out:
+       dev_info(old_devdata->dev, "%s: max_sync_size new:%u old:%u\n",
+                       __func__, new_devdata->max_sync_size,
+                       old_devdata->max_sync_size);
+       dev_info(old_devdata->dev, "%s: max_sync_sg new:%u old:%u\n",
+                       __func__, new_devdata->max_sync_sg,
+                       old_devdata->max_sync_sg);
+       dev_info(old_devdata->dev, "%s: max_sg_len new:%u old:%u\n",
+                       __func__, new_devdata->max_sg_len,
+                       old_devdata->max_sg_len);
+
+       rcu_assign_pointer(devdata, new_devdata);
+       spin_unlock_irqrestore(&devdata_mutex, flags);
+       synchronize_rcu();
+       dev_set_drvdata(new_devdata->dev, new_devdata);
+       kfree(old_devdata);
+       return 0;
+
+error_out:
+       if (new_devdata) {
+               dev_info(old_devdata->dev, "%s: device disabled\n", __func__);
+               nx842_OF_set_defaults(new_devdata);
+               rcu_assign_pointer(devdata, new_devdata);
+               spin_unlock_irqrestore(&devdata_mutex, flags);
+               synchronize_rcu();
+               dev_set_drvdata(new_devdata->dev, new_devdata);
+               kfree(old_devdata);
+       } else {
+               dev_err(old_devdata->dev, "%s: could not update driver from hardware\n", __func__);
+               spin_unlock_irqrestore(&devdata_mutex, flags);
+       }
+
+       if (!ret)
+               ret = -EINVAL;
+       return ret;
+}
+
+/**
+ * nx842_OF_notifier - Process updates to OF properties for the device
+ *
+ * @np: notifier block
+ * @action: notifier action
+ * @update: struct pSeries_reconfig_prop_update pointer if action is
+ *     PSERIES_UPDATE_PROPERTY
+ *
+ * Returns:
+ *     NOTIFY_OK on success
+ *     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)
+{
+       struct pSeries_reconfig_prop_update *upd;
+       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)) {
+               rcu_read_unlock();
+               nx842_OF_upd(upd->property);
+       } else
+               rcu_read_unlock();
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block nx842_of_nb = {
+       .notifier_call = nx842_OF_notifier,
+};
+
+#define nx842_counter_read(_name)                                      \
+static ssize_t nx842_##_name##_show(struct device *dev,                \
+               struct device_attribute *attr,                          \
+               char *buf) {                                            \
+       struct nx842_devdata *local_devdata;                    \
+       int p = 0;                                                      \
+       rcu_read_lock();                                                \
+       local_devdata = rcu_dereference(devdata);                       \
+       if (local_devdata)                                              \
+               p = snprintf(buf, PAGE_SIZE, "%ld\n",                   \
+                      atomic64_read(&local_devdata->counters->_name)); \
+       rcu_read_unlock();                                              \
+       return p;                                                       \
+}
+
+#define NX842DEV_COUNTER_ATTR_RO(_name)                                        \
+       nx842_counter_read(_name);                                      \
+       static struct device_attribute dev_attr_##_name = __ATTR(_name, \
+                                               0444,                   \
+                                               nx842_##_name##_show,\
+                                               NULL);
+
+NX842DEV_COUNTER_ATTR_RO(comp_complete);
+NX842DEV_COUNTER_ATTR_RO(comp_failed);
+NX842DEV_COUNTER_ATTR_RO(decomp_complete);
+NX842DEV_COUNTER_ATTR_RO(decomp_failed);
+NX842DEV_COUNTER_ATTR_RO(swdecomp);
+
+static ssize_t nx842_timehist_show(struct device *,
+               struct device_attribute *, char *);
+
+static struct device_attribute dev_attr_comp_times = __ATTR(comp_times, 0444,
+               nx842_timehist_show, NULL);
+static struct device_attribute dev_attr_decomp_times = __ATTR(decomp_times,
+               0444, nx842_timehist_show, NULL);
+
+static ssize_t nx842_timehist_show(struct device *dev,
+               struct device_attribute *attr, char *buf) {
+       char *p = buf;
+       struct nx842_devdata *local_devdata;
+       atomic64_t *times;
+       int bytes_remain = PAGE_SIZE;
+       int bytes;
+       int i;
+
+       rcu_read_lock();
+       local_devdata = rcu_dereference(devdata);
+       if (!local_devdata) {
+               rcu_read_unlock();
+               return 0;
+       }
+
+       if (attr == &dev_attr_comp_times)
+               times = local_devdata->counters->comp_times;
+       else if (attr == &dev_attr_decomp_times)
+               times = local_devdata->counters->decomp_times;
+       else {
+               rcu_read_unlock();
+               return 0;
+       }
+
+       for (i = 0; i < (NX842_HIST_SLOTS - 2); i++) {
+               bytes = snprintf(p, bytes_remain, "%u-%uus:\t%ld\n",
+                              i ? (2<<(i-1)) : 0, (2<<i)-1,
+                              atomic64_read(&times[i]));
+               bytes_remain -= bytes;
+               p += bytes;
+       }
+       /* The last bucket holds everything over
+        * 2<<(NX842_HIST_SLOTS - 2) us */
+       bytes = snprintf(p, bytes_remain, "%uus - :\t%ld\n",
+                       2<<(NX842_HIST_SLOTS - 2),
+                       atomic64_read(&times[(NX842_HIST_SLOTS - 1)]));
+       p += bytes;
+
+       rcu_read_unlock();
+       return p - buf;
+}
+
+static struct attribute *nx842_sysfs_entries[] = {
+       &dev_attr_comp_complete.attr,
+       &dev_attr_comp_failed.attr,
+       &dev_attr_decomp_complete.attr,
+       &dev_attr_decomp_failed.attr,
+       &dev_attr_swdecomp.attr,
+       &dev_attr_comp_times.attr,
+       &dev_attr_decomp_times.attr,
+       NULL,
+};
+
+static struct attribute_group nx842_attribute_group = {
+       .name = NULL,           /* put in device directory */
+       .attrs = nx842_sysfs_entries,
+};
+
+static int __init nx842_probe(struct vio_dev *viodev,
+                                 const struct vio_device_id *id)
+{
+       struct nx842_devdata *old_devdata, *new_devdata = NULL;
+       unsigned long flags;
+       int ret = 0;
+
+       spin_lock_irqsave(&devdata_mutex, flags);
+       old_devdata = rcu_dereference_check(devdata,
+                       lockdep_is_held(&devdata_mutex));
+
+       if (old_devdata && old_devdata->vdev != NULL) {
+               dev_err(&viodev->dev, "%s: Attempt to register more than one instance of the hardware\n", __func__);
+               ret = -1;
+               goto error_unlock;
+       }
+
+       dev_set_drvdata(&viodev->dev, NULL);
+
+       new_devdata = kzalloc(sizeof(*new_devdata), GFP_NOFS);
+       if (!new_devdata) {
+               dev_err(&viodev->dev, "%s: Could not allocate memory for device data\n", __func__);
+               ret = -ENOMEM;
+               goto error_unlock;
+       }
+
+       new_devdata->counters = kzalloc(sizeof(*new_devdata->counters),
+                       GFP_NOFS);
+       if (!new_devdata->counters) {
+               dev_err(&viodev->dev, "%s: Could not allocate memory for performance counters\n", __func__);
+               ret = -ENOMEM;
+               goto error_unlock;
+       }
+
+       new_devdata->vdev = viodev;
+       new_devdata->dev = &viodev->dev;
+       nx842_OF_set_defaults(new_devdata);
+
+       rcu_assign_pointer(devdata, new_devdata);
+       spin_unlock_irqrestore(&devdata_mutex, flags);
+       synchronize_rcu();
+       kfree(old_devdata);
+
+       pSeries_reconfig_notifier_register(&nx842_of_nb);
+
+       ret = nx842_OF_upd(NULL);
+       if (ret && ret != -ENODEV) {
+               dev_err(&viodev->dev, "could not parse device tree. %d\n", ret);
+               ret = -1;
+               goto error;
+       }
+
+       rcu_read_lock();
+       if (dev_set_drvdata(&viodev->dev, rcu_dereference(devdata))) {
+               rcu_read_unlock();
+               dev_err(&viodev->dev, "failed to set driver data for device\n");
+               ret = -1;
+               goto error;
+       }
+       rcu_read_unlock();
+
+       if (sysfs_create_group(&viodev->dev.kobj, &nx842_attribute_group)) {
+               dev_err(&viodev->dev, "could not create sysfs device attributes\n");
+               ret = -1;
+               goto error;
+       }
+
+       return 0;
+
+error_unlock:
+       spin_unlock_irqrestore(&devdata_mutex, flags);
+       if (new_devdata)
+               kfree(new_devdata->counters);
+       kfree(new_devdata);
+error:
+       return ret;
+}
+
+static int __exit nx842_remove(struct vio_dev *viodev)
+{
+       struct nx842_devdata *old_devdata;
+       unsigned long flags;
+
+       pr_info("Removing IBM Power 842 compression device\n");
+       sysfs_remove_group(&viodev->dev.kobj, &nx842_attribute_group);
+
+       spin_lock_irqsave(&devdata_mutex, flags);
+       old_devdata = rcu_dereference_check(devdata,
+                       lockdep_is_held(&devdata_mutex));
+       pSeries_reconfig_notifier_unregister(&nx842_of_nb);
+       rcu_assign_pointer(devdata, NULL);
+       spin_unlock_irqrestore(&devdata_mutex, flags);
+       synchronize_rcu();
+       dev_set_drvdata(&viodev->dev, NULL);
+       if (old_devdata)
+               kfree(old_devdata->counters);
+       kfree(old_devdata);
+       return 0;
+}
+
+static struct vio_device_id nx842_driver_ids[] = {
+       {"ibm,compression-v1", "ibm,compression"},
+       {"", ""},
+};
+
+static struct vio_driver nx842_driver = {
+       .name = MODULE_NAME,
+       .probe = nx842_probe,
+       .remove = nx842_remove,
+       .get_desired_dma = nx842_get_desired_dma,
+       .id_table = nx842_driver_ids,
+};
+
+static int __init nx842_init(void)
+{
+       struct nx842_devdata *new_devdata;
+       pr_info("Registering IBM Power 842 compression driver\n");
+
+       RCU_INIT_POINTER(devdata, NULL);
+       new_devdata = kzalloc(sizeof(*new_devdata), GFP_KERNEL);
+       if (!new_devdata) {
+               pr_err("Could not allocate memory for device data\n");
+               return -ENOMEM;
+       }
+       new_devdata->status = UNAVAILABLE;
+       RCU_INIT_POINTER(devdata, new_devdata);
+
+       return vio_register_driver(&nx842_driver);
+}
+
+module_init(nx842_init);
+
+static void __exit nx842_exit(void)
+{
+       struct nx842_devdata *old_devdata;
+       unsigned long flags;
+
+       pr_info("Exiting IBM Power 842 compression driver\n");
+       spin_lock_irqsave(&devdata_mutex, flags);
+       old_devdata = rcu_dereference_check(devdata,
+                       lockdep_is_held(&devdata_mutex));
+       rcu_assign_pointer(devdata, NULL);
+       spin_unlock_irqrestore(&devdata_mutex, flags);
+       synchronize_rcu();
+       if (old_devdata)
+               dev_set_drvdata(old_devdata->dev, NULL);
+       kfree(old_devdata);
+       vio_unregister_driver(&nx842_driver);
+}
+
+module_exit(nx842_exit);
+
+/*********************************
+ * 842 software decompressor
+*********************************/
+typedef int (*sw842_template_op)(const char **, int *, unsigned char **,
+                                               struct sw842_fifo *);
+
+static int sw842_data8(const char **, int *, unsigned char **,
+                                               struct sw842_fifo *);
+static int sw842_data4(const char **, int *, unsigned char **,
+                                               struct sw842_fifo *);
+static int sw842_data2(const char **, int *, unsigned char **,
+                                               struct sw842_fifo *);
+static int sw842_ptr8(const char **, int *, unsigned char **,
+                                               struct sw842_fifo *);
+static int sw842_ptr4(const char **, int *, unsigned char **,
+                                               struct sw842_fifo *);
+static int sw842_ptr2(const char **, int *, unsigned char **,
+                                               struct sw842_fifo *);
+
+/* special templates */
+#define SW842_TMPL_REPEAT 0x1B
+#define SW842_TMPL_ZEROS 0x1C
+#define SW842_TMPL_EOF 0x1E
+
+static sw842_template_op sw842_tmpl_ops[26][4] = {
+       { sw842_data8, NULL}, /* 0 (00000) */
+       { sw842_data4, sw842_data2, sw842_ptr2,  NULL},
+       { sw842_data4, sw842_ptr2,  sw842_data2, NULL},
+       { sw842_data4, sw842_ptr2,  sw842_ptr2,  NULL},
+       { sw842_data4, sw842_ptr4,  NULL},
+       { sw842_data2, sw842_ptr2,  sw842_data4, NULL},
+       { sw842_data2, sw842_ptr2,  sw842_data2, sw842_ptr2},
+       { sw842_data2, sw842_ptr2,  sw842_ptr2,  sw842_data2},
+       { sw842_data2, sw842_ptr2,  sw842_ptr2,  sw842_ptr2,},
+       { sw842_data2, sw842_ptr2,  sw842_ptr4,  NULL},
+       { sw842_ptr2,  sw842_data2, sw842_data4, NULL}, /* 10 (01010) */
+       { sw842_ptr2,  sw842_data4, sw842_ptr2,  NULL},
+       { sw842_ptr2,  sw842_data2, sw842_ptr2,  sw842_data2},
+       { sw842_ptr2,  sw842_data2, sw842_ptr2,  sw842_ptr2},
+       { sw842_ptr2,  sw842_data2, sw842_ptr4,  NULL},
+       { sw842_ptr2,  sw842_ptr2,  sw842_data4, NULL},
+       { sw842_ptr2,  sw842_ptr2,  sw842_data2, sw842_ptr2},
+       { sw842_ptr2,  sw842_ptr2,  sw842_ptr2,  sw842_data2},
+       { sw842_ptr2,  sw842_ptr2,  sw842_ptr2,  sw842_ptr2},
+       { sw842_ptr2,  sw842_ptr2,  sw842_ptr4,  NULL},
+       { sw842_ptr4,  sw842_data4, NULL}, /* 20 (10100) */
+       { sw842_ptr4,  sw842_data2, sw842_ptr2,  NULL},
+       { sw842_ptr4,  sw842_ptr2,  sw842_data2, NULL},
+       { sw842_ptr4,  sw842_ptr2,  sw842_ptr2,  NULL},
+       { sw842_ptr4,  sw842_ptr4,  NULL},
+       { sw842_ptr8,  NULL}
+};
+
+/* Software decompress helpers */
+
+static uint8_t sw842_get_byte(const char *buf, int bit)
+{
+       uint8_t tmpl;
+       uint16_t tmp;
+       tmp = htons(*(uint16_t *)(buf));
+       tmp = (uint16_t)(tmp << bit);
+       tmp = ntohs(tmp);
+       memcpy(&tmpl, &tmp, 1);
+       return tmpl;
+}
+
+static uint8_t sw842_get_template(const char **buf, int *bit)
+{
+       uint8_t byte;
+       byte = sw842_get_byte(*buf, *bit);
+       byte = byte >> 3;
+       byte &= 0x1F;
+       *buf += (*bit + 5) / 8;
+       *bit = (*bit + 5) % 8;
+       return byte;
+}
+
+/* repeat_count happens to be 5-bit too (like the template) */
+static uint8_t sw842_get_repeat_count(const char **buf, int *bit)
+{
+       uint8_t byte;
+       byte = sw842_get_byte(*buf, *bit);
+       byte = byte >> 2;
+       byte &= 0x3F;
+       *buf += (*bit + 6) / 8;
+       *bit = (*bit + 6) % 8;
+       return byte;
+}
+
+static uint8_t sw842_get_ptr2(const char **buf, int *bit)
+{
+       uint8_t ptr;
+       ptr = sw842_get_byte(*buf, *bit);
+       (*buf)++;
+       return ptr;
+}
+
+static uint16_t sw842_get_ptr4(const char **buf, int *bit,
+               struct sw842_fifo *fifo)
+{
+       uint16_t ptr;
+       ptr = htons(*(uint16_t *)(*buf));
+       ptr = (uint16_t)(ptr << *bit);
+       ptr = ptr >> 7;
+       ptr &= 0x01FF;
+       *buf += (*bit + 9) / 8;
+       *bit = (*bit + 9) % 8;
+       return ptr;
+}
+
+static uint8_t sw842_get_ptr8(const char **buf, int *bit,
+               struct sw842_fifo *fifo)
+{
+       return sw842_get_ptr2(buf, bit);
+}
+
+/* Software decompress template ops */
+
+static int sw842_data8(const char **inbuf, int *inbit,
+               unsigned char **outbuf, struct sw842_fifo *fifo)
+{
+       int ret;
+
+       ret = sw842_data4(inbuf, inbit, outbuf, fifo);
+       if (ret)
+               return ret;
+       ret = sw842_data4(inbuf, inbit, outbuf, fifo);
+       return ret;
+}
+
+static int sw842_data4(const char **inbuf, int *inbit,
+               unsigned char **outbuf, struct sw842_fifo *fifo)
+{
+       int ret;
+
+       ret = sw842_data2(inbuf, inbit, outbuf, fifo);
+       if (ret)
+               return ret;
+       ret = sw842_data2(inbuf, inbit, outbuf, fifo);
+       return ret;
+}
+
+static int sw842_data2(const char **inbuf, int *inbit,
+               unsigned char **outbuf, struct sw842_fifo *fifo)
+{
+       **outbuf = sw842_get_byte(*inbuf, *inbit);
+       (*inbuf)++;
+       (*outbuf)++;
+       **outbuf = sw842_get_byte(*inbuf, *inbit);
+       (*inbuf)++;
+       (*outbuf)++;
+       return 0;
+}
+
+static int sw842_ptr8(const char **inbuf, int *inbit,
+               unsigned char **outbuf, struct sw842_fifo *fifo)
+{
+       uint8_t ptr;
+       ptr = sw842_get_ptr8(inbuf, inbit, fifo);
+       if (!fifo->f84_full && (ptr >= fifo->f8_count))
+               return 1;
+       memcpy(*outbuf, fifo->f8[ptr], 8);
+       *outbuf += 8;
+       return 0;
+}
+
+static int sw842_ptr4(const char **inbuf, int *inbit,
+               unsigned char **outbuf, struct sw842_fifo *fifo)
+{
+       uint16_t ptr;
+       ptr = sw842_get_ptr4(inbuf, inbit, fifo);
+       if (!fifo->f84_full && (ptr >= fifo->f4_count))
+               return 1;
+       memcpy(*outbuf, fifo->f4[ptr], 4);
+       *outbuf += 4;
+       return 0;
+}
+
+static int sw842_ptr2(const char **inbuf, int *inbit,
+               unsigned char **outbuf, struct sw842_fifo *fifo)
+{
+       uint8_t ptr;
+       ptr = sw842_get_ptr2(inbuf, inbit);
+       if (!fifo->f2_full && (ptr >= fifo->f2_count))
+               return 1;
+       memcpy(*outbuf, fifo->f2[ptr], 2);
+       *outbuf += 2;
+       return 0;
+}
+
+static void sw842_copy_to_fifo(const char *buf, struct sw842_fifo *fifo)
+{
+       unsigned char initial_f2count = fifo->f2_count;
+
+       memcpy(fifo->f8[fifo->f8_count], buf, 8);
+       fifo->f4_count += 2;
+       fifo->f8_count += 1;
+
+       if (!fifo->f84_full && fifo->f4_count >= 512) {
+               fifo->f84_full = 1;
+               fifo->f4_count /= 512;
+       }
+
+       memcpy(fifo->f2[fifo->f2_count++], buf, 2);
+       memcpy(fifo->f2[fifo->f2_count++], buf + 2, 2);
+       memcpy(fifo->f2[fifo->f2_count++], buf + 4, 2);
+       memcpy(fifo->f2[fifo->f2_count++], buf + 6, 2);
+       if (fifo->f2_count < initial_f2count)
+               fifo->f2_full = 1;
+}
+
+static int sw842_decompress(const unsigned char *src, int srclen,
+                       unsigned char *dst, int *destlen,
+                       const void *wrkmem)
+{
+       uint8_t tmpl;
+       const char *inbuf;
+       int inbit = 0;
+       unsigned char *outbuf, *outbuf_end, *origbuf, *prevbuf;
+       const char *inbuf_end;
+       sw842_template_op op;
+       int opindex;
+       int i, repeat_count;
+       struct sw842_fifo *fifo;
+       int ret = 0;
+
+       fifo = &((struct nx842_workmem *)(wrkmem))->swfifo;
+       memset(fifo, 0, sizeof(*fifo));
+
+       origbuf = NULL;
+       inbuf = src;
+       inbuf_end = src + srclen;
+       outbuf = dst;
+       outbuf_end = dst + *destlen;
+
+       while ((tmpl = sw842_get_template(&inbuf, &inbit)) != SW842_TMPL_EOF) {
+               if (inbuf >= inbuf_end) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               opindex = 0;
+               prevbuf = origbuf;
+               origbuf = outbuf;
+               switch (tmpl) {
+               case SW842_TMPL_REPEAT:
+                       if (prevbuf == NULL) {
+                               ret = -EINVAL;
+                               goto out;
+                       }
+
+                       repeat_count = sw842_get_repeat_count(&inbuf,
+                                                               &inbit) + 1;
+
+                       /* Did the repeat count advance past the end of input */
+                       if (inbuf > inbuf_end) {
+                               ret = -EINVAL;
+                               goto out;
+                       }
+
+                       for (i = 0; i < repeat_count; i++) {
+                               /* Would this overflow the output buffer */
+                               if ((outbuf + 8) > outbuf_end) {
+                                       ret = -ENOSPC;
+                                       goto out;
+                               }
+
+                               memcpy(outbuf, prevbuf, 8);
+                               sw842_copy_to_fifo(outbuf, fifo);
+                               outbuf += 8;
+                       }
+                       break;
+
+               case SW842_TMPL_ZEROS:
+                       /* Would this overflow the output buffer */
+                       if ((outbuf + 8) > outbuf_end) {
+                               ret = -ENOSPC;
+                               goto out;
+                       }
+
+                       memset(outbuf, 0, 8);
+                       sw842_copy_to_fifo(outbuf, fifo);
+                       outbuf += 8;
+                       break;
+
+               default:
+                       if (tmpl > 25) {
+                               ret = -EINVAL;
+                               goto out;
+                       }
+
+                       /* Does this go past the end of the input buffer */
+                       if ((inbuf + 2) > inbuf_end) {
+                               ret = -EINVAL;
+                               goto out;
+                       }
+
+                       /* Would this overflow the output buffer */
+                       if ((outbuf + 8) > outbuf_end) {
+                               ret = -ENOSPC;
+                               goto out;
+                       }
+
+                       while (opindex < 4 &&
+                               (op = sw842_tmpl_ops[tmpl][opindex++])
+                                       != NULL) {
+                               ret = (*op)(&inbuf, &inbit, &outbuf, fifo);
+                               if (ret) {
+                                       ret = -EINVAL;
+                                       goto out;
+                               }
+                               sw842_copy_to_fifo(origbuf, fifo);
+                       }
+               }
+       }
+
+out:
+       if (!ret)
+               *destlen = (unsigned int)(outbuf - dst);
+       else
+               *destlen = 0;
+
+       return ret;
+}
index 69ed796ee327294f5ae1fdbbc1ae858cb1f33b42..a76d4c4f29f50798ed3ecafaa871d98a7d02c7e3 100644 (file)
@@ -127,7 +127,6 @@ struct crypto_alg nx_cbc_aes_alg = {
        .cra_ctxsize     = sizeof(struct nx_crypto_ctx),
        .cra_type        = &crypto_blkcipher_type,
        .cra_module      = THIS_MODULE,
-       .cra_list        = LIST_HEAD_INIT(nx_cbc_aes_alg.cra_list),
        .cra_init        = nx_crypto_ctx_aes_cbc_init,
        .cra_exit        = nx_crypto_ctx_exit,
        .cra_blkcipher = {
index 7aeac678b9c08e7660d825f48f394f17bc54dde0..ef5eae6d1400382a8830bca980752b123e12bf52 100644 (file)
@@ -430,7 +430,6 @@ struct crypto_alg nx_ccm_aes_alg = {
        .cra_ctxsize     = sizeof(struct nx_crypto_ctx),
        .cra_type        = &crypto_aead_type,
        .cra_module      = THIS_MODULE,
-       .cra_list        = LIST_HEAD_INIT(nx_ccm_aes_alg.cra_list),
        .cra_init        = nx_crypto_ctx_aes_ccm_init,
        .cra_exit        = nx_crypto_ctx_exit,
        .cra_aead = {
@@ -453,7 +452,6 @@ struct crypto_alg nx_ccm4309_aes_alg = {
        .cra_ctxsize     = sizeof(struct nx_crypto_ctx),
        .cra_type        = &crypto_nivaead_type,
        .cra_module      = THIS_MODULE,
-       .cra_list        = LIST_HEAD_INIT(nx_ccm4309_aes_alg.cra_list),
        .cra_init        = nx_crypto_ctx_aes_ccm_init,
        .cra_exit        = nx_crypto_ctx_exit,
        .cra_aead = {
index 52d4eb05e8f79a6a24a5e39bc2911e31f60d6c66..b6286f14680ba82fcb7a32136dddea9b2a24ce29 100644 (file)
@@ -141,7 +141,6 @@ struct crypto_alg nx_ctr_aes_alg = {
        .cra_ctxsize     = sizeof(struct nx_crypto_ctx),
        .cra_type        = &crypto_blkcipher_type,
        .cra_module      = THIS_MODULE,
-       .cra_list        = LIST_HEAD_INIT(nx_ctr_aes_alg.cra_list),
        .cra_init        = nx_crypto_ctx_aes_ctr_init,
        .cra_exit        = nx_crypto_ctx_exit,
        .cra_blkcipher = {
@@ -163,7 +162,6 @@ struct crypto_alg nx_ctr3686_aes_alg = {
        .cra_ctxsize     = sizeof(struct nx_crypto_ctx),
        .cra_type        = &crypto_blkcipher_type,
        .cra_module      = THIS_MODULE,
-       .cra_list        = LIST_HEAD_INIT(nx_ctr3686_aes_alg.cra_list),
        .cra_init        = nx_crypto_ctx_aes_ctr_init,
        .cra_exit        = nx_crypto_ctx_exit,
        .cra_blkcipher = {
index 7b77bc2d1df451724975e63e4b279b47f90469cd..ba5f1611336fe9fa5165cfa680e7acc2b7e38637 100644 (file)
@@ -126,7 +126,6 @@ struct crypto_alg nx_ecb_aes_alg = {
        .cra_ctxsize     = sizeof(struct nx_crypto_ctx),
        .cra_type        = &crypto_blkcipher_type,
        .cra_module      = THIS_MODULE,
-       .cra_list        = LIST_HEAD_INIT(nx_ecb_aes_alg.cra_list),
        .cra_init        = nx_crypto_ctx_aes_ecb_init,
        .cra_exit        = nx_crypto_ctx_exit,
        .cra_blkcipher = {
index 9ab1c7341dac3bbd7e0dcf50f71d35691d07b44a..c8109edc5cfb02063c1bd6c5914985846bccac2a 100644 (file)
@@ -316,7 +316,6 @@ struct crypto_alg nx_gcm_aes_alg = {
        .cra_ctxsize     = sizeof(struct nx_crypto_ctx),
        .cra_type        = &crypto_aead_type,
        .cra_module      = THIS_MODULE,
-       .cra_list        = LIST_HEAD_INIT(nx_gcm_aes_alg.cra_list),
        .cra_init        = nx_crypto_ctx_aes_gcm_init,
        .cra_exit        = nx_crypto_ctx_exit,
        .cra_aead = {
@@ -338,7 +337,6 @@ struct crypto_alg nx_gcm4106_aes_alg = {
        .cra_ctxsize     = sizeof(struct nx_crypto_ctx),
        .cra_type        = &crypto_nivaead_type,
        .cra_module      = THIS_MODULE,
-       .cra_list        = LIST_HEAD_INIT(nx_gcm4106_aes_alg.cra_list),
        .cra_init        = nx_crypto_ctx_aes_gcm_init,
        .cra_exit        = nx_crypto_ctx_exit,
        .cra_aead = {
index 63e57b57a12cb259ea27443070f543bcc1842956..093a8af59cbe46711fd0e750552598eb26f04d85 100644 (file)
@@ -876,7 +876,6 @@ static int omap_aes_probe(struct platform_device *pdev)
 
        for (i = 0; i < ARRAY_SIZE(algs); i++) {
                pr_debug("i: %d\n", i);
-               INIT_LIST_HEAD(&algs[i].cra_list);
                err = crypto_register_alg(&algs[i]);
                if (err)
                        goto err_algs;
index 37b2e9406af6d218785e77fada9aa6458b08e3a9..633ba945e153da2a61f88f4580afab6caaff2c73 100644 (file)
@@ -328,7 +328,6 @@ static struct crypto_alg aes_alg = {
        .cra_ctxsize            =       sizeof(struct aes_ctx),
        .cra_alignmask          =       PADLOCK_ALIGNMENT - 1,
        .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(aes_alg.cra_list),
        .cra_u                  =       {
                .cipher = {
                        .cia_min_keysize        =       AES_MIN_KEY_SIZE,
@@ -408,7 +407,6 @@ static struct crypto_alg ecb_aes_alg = {
        .cra_alignmask          =       PADLOCK_ALIGNMENT - 1,
        .cra_type               =       &crypto_blkcipher_type,
        .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(ecb_aes_alg.cra_list),
        .cra_u                  =       {
                .blkcipher = {
                        .min_keysize            =       AES_MIN_KEY_SIZE,
@@ -491,7 +489,6 @@ static struct crypto_alg cbc_aes_alg = {
        .cra_alignmask          =       PADLOCK_ALIGNMENT - 1,
        .cra_type               =       &crypto_blkcipher_type,
        .cra_module             =       THIS_MODULE,
-       .cra_list               =       LIST_HEAD_INIT(cbc_aes_alg.cra_list),
        .cra_u                  =       {
                .blkcipher = {
                        .min_keysize            =       AES_MIN_KEY_SIZE,
index bc986f806086dc0fab33f4ff5822811dba5a2f87..a22714412cda2061c26ccd5a26fe50a4e5891348 100644 (file)
@@ -626,7 +626,6 @@ static int s5p_aes_probe(struct platform_device *pdev)
        crypto_init_queue(&pdata->queue, CRYPTO_QUEUE_LEN);
 
        for (i = 0; i < ARRAY_SIZE(algs); i++) {
-               INIT_LIST_HEAD(&algs[i].cra_list);
                err = crypto_register_alg(&algs[i]);
                if (err)
                        goto err_algs;
index ac236f6724f4bf11d1130b1258af8eff0b731044..631149e50ef1ccf175aace390c8c9084c1c5af88 100644 (file)
@@ -1004,8 +1004,6 @@ static int tegra_aes_probe(struct platform_device *pdev)
 
        aes_dev = dd;
        for (i = 0; i < ARRAY_SIZE(algs); i++) {
-               INIT_LIST_HEAD(&algs[i].cra_list);
-
                algs[i].cra_priority = 300;
                algs[i].cra_ctxsize = sizeof(struct tegra_aes_ctx);
                algs[i].cra_module = THIS_MODULE;
index d3c5a5a88f1e9af91b97848f6d9c107ac2010da5..4f4ff1337cacd91c53660ca0a07b6a078a31d455 100644 (file)
@@ -1392,26 +1392,17 @@ static int __devinit dw_probe(struct platform_device *pdev)
 
        size = sizeof(struct dw_dma);
        size += pdata->nr_channels * sizeof(struct dw_dma_chan);
-       dw = kzalloc(size, GFP_KERNEL);
+       dw = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
        if (!dw)
                return -ENOMEM;
 
-       if (!request_mem_region(io->start, DW_REGLEN, pdev->dev.driver->name)) {
-               err = -EBUSY;
-               goto err_kfree;
-       }
-
-       dw->regs = ioremap(io->start, DW_REGLEN);
-       if (!dw->regs) {
-               err = -ENOMEM;
-               goto err_release_r;
-       }
+       dw->regs = devm_request_and_ioremap(&pdev->dev, io);
+       if (!dw->regs)
+               return -EBUSY;
 
-       dw->clk = clk_get(&pdev->dev, "hclk");
-       if (IS_ERR(dw->clk)) {
-               err = PTR_ERR(dw->clk);
-               goto err_clk;
-       }
+       dw->clk = devm_clk_get(&pdev->dev, "hclk");
+       if (IS_ERR(dw->clk))
+               return PTR_ERR(dw->clk);
        clk_prepare_enable(dw->clk);
 
        /* Calculate all channel mask before DMA setup */
@@ -1423,9 +1414,10 @@ static int __devinit dw_probe(struct platform_device *pdev)
        /* disable BLOCK interrupts as well */
        channel_clear_bit(dw, MASK.BLOCK, dw->all_chan_mask);
 
-       err = request_irq(irq, dw_dma_interrupt, 0, "dw_dmac", dw);
+       err = devm_request_irq(&pdev->dev, irq, dw_dma_interrupt, 0,
+                              "dw_dmac", dw);
        if (err)
-               goto err_irq;
+               return err;
 
        platform_set_drvdata(pdev, dw);
 
@@ -1491,30 +1483,16 @@ static int __devinit dw_probe(struct platform_device *pdev)
        dma_async_device_register(&dw->dma);
 
        return 0;
-
-err_irq:
-       clk_disable_unprepare(dw->clk);
-       clk_put(dw->clk);
-err_clk:
-       iounmap(dw->regs);
-       dw->regs = NULL;
-err_release_r:
-       release_resource(io);
-err_kfree:
-       kfree(dw);
-       return err;
 }
 
 static int __devexit dw_remove(struct platform_device *pdev)
 {
        struct dw_dma           *dw = platform_get_drvdata(pdev);
        struct dw_dma_chan      *dwc, *_dwc;
-       struct resource         *io;
 
        dw_dma_off(dw);
        dma_async_device_unregister(&dw->dma);
 
-       free_irq(platform_get_irq(pdev, 0), dw);
        tasklet_kill(&dw->tasklet);
 
        list_for_each_entry_safe(dwc, _dwc, &dw->dma.channels,
@@ -1523,17 +1501,6 @@ static int __devexit dw_remove(struct platform_device *pdev)
                channel_clear_bit(dw, CH_EN, dwc->mask);
        }
 
-       clk_disable_unprepare(dw->clk);
-       clk_put(dw->clk);
-
-       iounmap(dw->regs);
-       dw->regs = NULL;
-
-       io = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(io->start, DW_REGLEN);
-
-       kfree(dw);
-
        return 0;
 }
 
index 50830bee087a65eac6178e9111b72db9cbe0c49a..f6d92d72ae4062634e6736702801d87bcdf7885d 100644 (file)
@@ -140,8 +140,6 @@ struct dw_dma_regs {
 /* Bitfields in CFG */
 #define DW_CFG_DMA_EN          (1 << 0)
 
-#define DW_REGLEN              0x400
-
 enum dw_dmac_flags {
        DW_DMA_IS_CYCLIC = 0,
 };
index fcfeb3cd8d3170aff7c30d6d151a0e7e15ecd968..5084975d793cd25949e62ae68f5932bd3c456763 100644 (file)
@@ -172,7 +172,8 @@ struct imxdma_engine {
        struct device_dma_parameters    dma_parms;
        struct dma_device               dma_device;
        void __iomem                    *base;
-       struct clk                      *dma_clk;
+       struct clk                      *dma_ahb;
+       struct clk                      *dma_ipg;
        spinlock_t                      lock;
        struct imx_dma_2d_config        slots_2d[IMX_DMA_2D_SLOTS];
        struct imxdma_channel           channel[IMX_DMA_CHANNELS];
@@ -976,10 +977,20 @@ static int __init imxdma_probe(struct platform_device *pdev)
                return 0;
        }
 
-       imxdma->dma_clk = clk_get(NULL, "dma");
-       if (IS_ERR(imxdma->dma_clk))
-               return PTR_ERR(imxdma->dma_clk);
-       clk_enable(imxdma->dma_clk);
+       imxdma->dma_ipg = devm_clk_get(&pdev->dev, "ipg");
+       if (IS_ERR(imxdma->dma_ipg)) {
+               ret = PTR_ERR(imxdma->dma_ipg);
+               goto err_clk;
+       }
+
+       imxdma->dma_ahb = devm_clk_get(&pdev->dev, "ahb");
+       if (IS_ERR(imxdma->dma_ahb)) {
+               ret = PTR_ERR(imxdma->dma_ahb);
+               goto err_clk;
+       }
+
+       clk_prepare_enable(imxdma->dma_ipg);
+       clk_prepare_enable(imxdma->dma_ahb);
 
        /* reset DMA module */
        imx_dmav1_writel(imxdma, DCR_DRST, DMA_DCR);
@@ -988,16 +999,14 @@ static int __init imxdma_probe(struct platform_device *pdev)
                ret = request_irq(MX1_DMA_INT, dma_irq_handler, 0, "DMA", imxdma);
                if (ret) {
                        dev_warn(imxdma->dev, "Can't register IRQ for DMA\n");
-                       kfree(imxdma);
-                       return ret;
+                       goto err_enable;
                }
 
                ret = request_irq(MX1_DMA_ERR, imxdma_err_handler, 0, "DMA", imxdma);
                if (ret) {
                        dev_warn(imxdma->dev, "Can't register ERRIRQ for DMA\n");
                        free_irq(MX1_DMA_INT, NULL);
-                       kfree(imxdma);
-                       return ret;
+                       goto err_enable;
                }
        }
 
@@ -1094,7 +1103,10 @@ err_init:
                free_irq(MX1_DMA_INT, NULL);
                free_irq(MX1_DMA_ERR, NULL);
        }
-
+err_enable:
+       clk_disable_unprepare(imxdma->dma_ipg);
+       clk_disable_unprepare(imxdma->dma_ahb);
+err_clk:
        kfree(imxdma);
        return ret;
 }
@@ -1114,7 +1126,9 @@ static int __exit imxdma_remove(struct platform_device *pdev)
                free_irq(MX1_DMA_ERR, NULL);
        }
 
-        kfree(imxdma);
+       clk_disable_unprepare(imxdma->dma_ipg);
+       clk_disable_unprepare(imxdma->dma_ahb);
+       kfree(imxdma);
 
         return 0;
 }
index d52dbc6c54abdb346278b65bfbd8715f317d3e58..24acd711e0326852e2bf97bce308fb1fe272cea6 100644 (file)
@@ -1119,15 +1119,21 @@ struct dma_async_tx_descriptor *tegra_dma_prep_dma_cyclic(
 static int tegra_dma_alloc_chan_resources(struct dma_chan *dc)
 {
        struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
+       struct tegra_dma *tdma = tdc->tdma;
+       int ret;
 
        dma_cookie_init(&tdc->dma_chan);
        tdc->config_init = false;
-       return 0;
+       ret = clk_prepare_enable(tdma->dma_clk);
+       if (ret < 0)
+               dev_err(tdc2dev(tdc), "clk_prepare_enable failed: %d\n", ret);
+       return ret;
 }
 
 static void tegra_dma_free_chan_resources(struct dma_chan *dc)
 {
        struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
+       struct tegra_dma *tdma = tdc->tdma;
 
        struct tegra_dma_desc *dma_desc;
        struct tegra_dma_sg_req *sg_req;
@@ -1163,6 +1169,7 @@ static void tegra_dma_free_chan_resources(struct dma_chan *dc)
                list_del(&sg_req->node);
                kfree(sg_req);
        }
+       clk_disable_unprepare(tdma->dma_clk);
 }
 
 /* Tegra20 specific DMA controller information */
@@ -1255,6 +1262,13 @@ static int __devinit tegra_dma_probe(struct platform_device *pdev)
                }
        }
 
+       /* Enable clock before accessing registers */
+       ret = clk_prepare_enable(tdma->dma_clk);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret);
+               goto err_pm_disable;
+       }
+
        /* Reset DMA controller */
        tegra_periph_reset_assert(tdma->dma_clk);
        udelay(2);
@@ -1265,6 +1279,8 @@ static int __devinit tegra_dma_probe(struct platform_device *pdev)
        tdma_write(tdma, TEGRA_APBDMA_CONTROL, 0);
        tdma_write(tdma, TEGRA_APBDMA_IRQ_MASK_SET, 0xFFFFFFFFul);
 
+       clk_disable_unprepare(tdma->dma_clk);
+
        INIT_LIST_HEAD(&tdma->dma_dev.channels);
        for (i = 0; i < cdata->nr_channels; i++) {
                struct tegra_dma_channel *tdc = &tdma->channels[i];
index 616d90bcb3a4106929523c4a98fe32fb27f6a9a6..7c0df4af9ef7c03ced35d78a45a988fdd52da5a8 100644 (file)
@@ -538,7 +538,7 @@ static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec)
                return;
 
        INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function);
-       queue_delayed_work(edac_workqueue, &mci->work, msecs_to_jiffies(msec));
+       mod_delayed_work(edac_workqueue, &mci->work, msecs_to_jiffies(msec));
 }
 
 /*
@@ -578,21 +578,6 @@ void edac_mc_reset_delay_period(int value)
 
        mutex_lock(&mem_ctls_mutex);
 
-       /* scan the list and turn off all workq timers, doing so under lock
-        */
-       list_for_each(item, &mc_devices) {
-               mci = list_entry(item, struct mem_ctl_info, link);
-
-               if (mci->op_state == OP_RUNNING_POLL)
-                       cancel_delayed_work(&mci->work);
-       }
-
-       mutex_unlock(&mem_ctls_mutex);
-
-
-       /* re-walk the list, and reset the poll delay */
-       mutex_lock(&mem_ctls_mutex);
-
        list_for_each(item, &mc_devices) {
                mci = list_entry(item, struct mem_ctl_info, link);
 
index fe3db45fa83c13604db19590cb29546dc38efae1..3cc152e690b06087c8374bf35cb72106f9bfde32 100644 (file)
@@ -107,7 +107,8 @@ static int __devinit gpio_extcon_probe(struct platform_device *pdev)
        if (ret < 0)
                return ret;
 
-       ret = gpio_request_one(extcon_data->gpio, GPIOF_DIR_IN, pdev->name);
+       ret = devm_gpio_request_one(&pdev->dev, extcon_data->gpio, GPIOF_DIR_IN,
+                                   pdev->name);
        if (ret < 0)
                goto err;
 
index 150d9768811d4a09d30cef2ca9b69bdaf3c57275..ae37181798b3c979d9ce423a437f7ba09511166a 100644 (file)
@@ -266,7 +266,7 @@ static int __devinit em_gio_irq_domain_init(struct em_gio_priv *p)
        return 0;
 }
 
-static void __devexit em_gio_irq_domain_cleanup(struct em_gio_priv *p)
+static void em_gio_irq_domain_cleanup(struct em_gio_priv *p)
 {
        struct gpio_em_config *pdata = p->pdev->dev.platform_data;
 
index a1c8754f52cf1b523c3da1bb9e572dc084ddde0b..202a99207b7d40c1a0e98dbe728cb7f782704a0d 100644 (file)
@@ -339,7 +339,7 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev,
        resource_size_t start, len;
        struct lnw_gpio *lnw;
        u32 gpio_base;
-       int retval = 0;
+       int retval;
        int ngpio = id->driver_data;
 
        retval = pci_enable_device(pdev);
@@ -357,6 +357,7 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev,
        base = ioremap_nocache(start, len);
        if (!base) {
                dev_err(&pdev->dev, "error mapping bar1\n");
+               retval = -EFAULT;
                goto err3;
        }
        gpio_base = *((u32 *)base + 1);
@@ -381,8 +382,10 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev,
 
        lnw->domain = irq_domain_add_linear(pdev->dev.of_node, ngpio,
                                            &lnw_gpio_irq_ops, lnw);
-       if (!lnw->domain)
+       if (!lnw->domain) {
+               retval = -ENOMEM;
                goto err3;
+       }
 
        lnw->reg_base = base;
        lnw->chip.label = dev_name(&pdev->dev);
index db01f151d41c428f220f5a0b9fad9a4d6f427f18..6a29ee1847be92ad0038d0c0f828c1e0ac92fcb0 100644 (file)
@@ -87,8 +87,7 @@ struct ioh_gpio_reg_data {
  * @gpio_use_sel:              Save GPIO_USE_SEL1~4 register for PM
  * @ch:                                Indicate GPIO channel
  * @irq_base:          Save base of IRQ number for interrupt
- * @spinlock:          Used for register access protection in
- *                             interrupt context ioh_irq_type and PM;
+ * @spinlock:          Used for register access protection
  */
 struct ioh_gpio {
        void __iomem *base;
@@ -97,7 +96,6 @@ struct ioh_gpio {
        struct gpio_chip gpio;
        struct ioh_gpio_reg_data ioh_gpio_reg;
        u32 gpio_use_sel;
-       struct mutex lock;
        int ch;
        int irq_base;
        spinlock_t spinlock;
@@ -109,8 +107,9 @@ static void ioh_gpio_set(struct gpio_chip *gpio, unsigned nr, int val)
 {
        u32 reg_val;
        struct ioh_gpio *chip = container_of(gpio, struct ioh_gpio, gpio);
+       unsigned long flags;
 
-       mutex_lock(&chip->lock);
+       spin_lock_irqsave(&chip->spinlock, flags);
        reg_val = ioread32(&chip->reg->regs[chip->ch].po);
        if (val)
                reg_val |= (1 << nr);
@@ -118,7 +117,7 @@ static void ioh_gpio_set(struct gpio_chip *gpio, unsigned nr, int val)
                reg_val &= ~(1 << nr);
 
        iowrite32(reg_val, &chip->reg->regs[chip->ch].po);
-       mutex_unlock(&chip->lock);
+       spin_unlock_irqrestore(&chip->spinlock, flags);
 }
 
 static int ioh_gpio_get(struct gpio_chip *gpio, unsigned nr)
@@ -134,8 +133,9 @@ static int ioh_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
        struct ioh_gpio *chip = container_of(gpio, struct ioh_gpio, gpio);
        u32 pm;
        u32 reg_val;
+       unsigned long flags;
 
-       mutex_lock(&chip->lock);
+       spin_lock_irqsave(&chip->spinlock, flags);
        pm = ioread32(&chip->reg->regs[chip->ch].pm) &
                                        ((1 << num_ports[chip->ch]) - 1);
        pm |= (1 << nr);
@@ -148,7 +148,7 @@ static int ioh_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
                reg_val &= ~(1 << nr);
        iowrite32(reg_val, &chip->reg->regs[chip->ch].po);
 
-       mutex_unlock(&chip->lock);
+       spin_unlock_irqrestore(&chip->spinlock, flags);
 
        return 0;
 }
@@ -157,13 +157,14 @@ static int ioh_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
 {
        struct ioh_gpio *chip = container_of(gpio, struct ioh_gpio, gpio);
        u32 pm;
+       unsigned long flags;
 
-       mutex_lock(&chip->lock);
+       spin_lock_irqsave(&chip->spinlock, flags);
        pm = ioread32(&chip->reg->regs[chip->ch].pm) &
                                ((1 << num_ports[chip->ch]) - 1);
        pm &= ~(1 << nr);
        iowrite32(pm, &chip->reg->regs[chip->ch].pm);
-       mutex_unlock(&chip->lock);
+       spin_unlock_irqrestore(&chip->spinlock, flags);
 
        return 0;
 }
@@ -447,7 +448,6 @@ static int __devinit ioh_gpio_probe(struct pci_dev *pdev,
                chip->base = base;
                chip->reg = chip->base;
                chip->ch = i;
-               mutex_init(&chip->lock);
                spin_lock_init(&chip->spinlock);
                ioh_gpio_setup(chip, num_ports[i]);
                ret = gpiochip_add(&chip->gpio);
index 5a1817eedd1ba42a661bde558d212d748b9752a3..9ae29cc0d17faf78a5482cbd3b1878e785f45261 100644 (file)
@@ -38,7 +38,7 @@ struct mpc8xxx_gpio_chip {
         */
        u32 data;
        struct irq_domain *irq;
-       void *of_dev_id_data;
+       const void *of_dev_id_data;
 };
 
 static inline u32 mpc8xxx_gpio2mask(unsigned int gpio)
index 71a838f44501065b76e6253a3780959f15c85e0b..b38986285868ab96151c2c522463ccfb377aeae1 100644 (file)
@@ -99,7 +99,7 @@ static int msic_gpio_to_oreg(unsigned offset)
        if (offset < 20)
                return INTEL_MSIC_GPIO0HV0CTLO - offset + 16;
 
-       return INTEL_MSIC_GPIO1HV0CTLO + offset + 20;
+       return INTEL_MSIC_GPIO1HV0CTLO - offset + 20;
 }
 
 static int msic_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
index 4db460b6ecf7dbf1ffe7bfd14a1361d271609667..80f44bb64a871835b9cdf59561d8bff90d03126d 100644 (file)
@@ -465,9 +465,8 @@ static int __devinit mxc_gpio_probe(struct platform_device *pdev)
                goto out_iounmap;
 
        port->bgc.gc.to_irq = mxc_gpio_to_irq;
-       port->bgc.gc.base = pdev->id * 32;
-       port->bgc.dir = port->bgc.read_reg(port->bgc.reg_dir);
-       port->bgc.data = port->bgc.read_reg(port->bgc.reg_set);
+       port->bgc.gc.base = (pdev->id < 0) ? of_alias_get_id(np, "gpio") * 32 :
+                                            pdev->id * 32;
 
        err = gpiochip_add(&port->bgc.gc);
        if (err)
index e6efd77668f0fb5ccab3a917629b07134885ee73..0725d181581f276f803a7b457ca4ab6a8068619f 100644 (file)
@@ -1058,7 +1058,7 @@ static int __devinit omap_gpio_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct device_node *node = dev->of_node;
        const struct of_device_id *match;
-       struct omap_gpio_platform_data *pdata;
+       const struct omap_gpio_platform_data *pdata;
        struct resource *res;
        struct gpio_bank *bank;
        int ret = 0;
@@ -1440,19 +1440,19 @@ static struct omap_gpio_reg_offs omap4_gpio_regs = {
        .fallingdetect =        OMAP4_GPIO_FALLINGDETECT,
 };
 
-static struct omap_gpio_platform_data omap2_pdata = {
+const static struct omap_gpio_platform_data omap2_pdata = {
        .regs = &omap2_gpio_regs,
        .bank_width = 32,
        .dbck_flag = false,
 };
 
-static struct omap_gpio_platform_data omap3_pdata = {
+const static struct omap_gpio_platform_data omap3_pdata = {
        .regs = &omap2_gpio_regs,
        .bank_width = 32,
        .dbck_flag = true,
 };
 
-static struct omap_gpio_platform_data omap4_pdata = {
+const static struct omap_gpio_platform_data omap4_pdata = {
        .regs = &omap4_gpio_regs,
        .bank_width = 32,
        .dbck_flag = true,
index 139ad3e200113f29a679796324b756846065045e..4ad0c4f9171c18f4c7baa2cf1f253b1ea08af495 100644 (file)
@@ -92,9 +92,7 @@ struct pch_gpio_reg_data {
  * @lock:                      Used for register access protection
  * @irq_base:          Save base of IRQ number for interrupt
  * @ioh:               IOH ID
- * @spinlock:          Used for register access protection in
- *                             interrupt context pch_irq_mask,
- *                             pch_irq_unmask and pch_irq_type;
+ * @spinlock:          Used for register access protection
  */
 struct pch_gpio {
        void __iomem *base;
@@ -102,7 +100,6 @@ struct pch_gpio {
        struct device *dev;
        struct gpio_chip gpio;
        struct pch_gpio_reg_data pch_gpio_reg;
-       struct mutex lock;
        int irq_base;
        enum pch_type_t ioh;
        spinlock_t spinlock;
@@ -112,8 +109,9 @@ static void pch_gpio_set(struct gpio_chip *gpio, unsigned nr, int val)
 {
        u32 reg_val;
        struct pch_gpio *chip = container_of(gpio, struct pch_gpio, gpio);
+       unsigned long flags;
 
-       mutex_lock(&chip->lock);
+       spin_lock_irqsave(&chip->spinlock, flags);
        reg_val = ioread32(&chip->reg->po);
        if (val)
                reg_val |= (1 << nr);
@@ -121,7 +119,7 @@ static void pch_gpio_set(struct gpio_chip *gpio, unsigned nr, int val)
                reg_val &= ~(1 << nr);
 
        iowrite32(reg_val, &chip->reg->po);
-       mutex_unlock(&chip->lock);
+       spin_unlock_irqrestore(&chip->spinlock, flags);
 }
 
 static int pch_gpio_get(struct gpio_chip *gpio, unsigned nr)
@@ -137,8 +135,9 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
        struct pch_gpio *chip = container_of(gpio, struct pch_gpio, gpio);
        u32 pm;
        u32 reg_val;
+       unsigned long flags;
 
-       mutex_lock(&chip->lock);
+       spin_lock_irqsave(&chip->spinlock, flags);
        pm = ioread32(&chip->reg->pm) & ((1 << gpio_pins[chip->ioh]) - 1);
        pm |= (1 << nr);
        iowrite32(pm, &chip->reg->pm);
@@ -149,8 +148,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
        else
                reg_val &= ~(1 << nr);
        iowrite32(reg_val, &chip->reg->po);
-
-       mutex_unlock(&chip->lock);
+       spin_unlock_irqrestore(&chip->spinlock, flags);
 
        return 0;
 }
@@ -159,12 +157,13 @@ static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
 {
        struct pch_gpio *chip = container_of(gpio, struct pch_gpio, gpio);
        u32 pm;
+       unsigned long flags;
 
-       mutex_lock(&chip->lock);
+       spin_lock_irqsave(&chip->spinlock, flags);
        pm = ioread32(&chip->reg->pm) & ((1 << gpio_pins[chip->ioh]) - 1);
        pm &= ~(1 << nr);
        iowrite32(pm, &chip->reg->pm);
-       mutex_unlock(&chip->lock);
+       spin_unlock_irqrestore(&chip->spinlock, flags);
 
        return 0;
 }
@@ -387,7 +386,6 @@ static int __devinit pch_gpio_probe(struct pci_dev *pdev,
 
        chip->reg = chip->base;
        pci_set_drvdata(pdev, chip);
-       mutex_init(&chip->lock);
        spin_lock_init(&chip->spinlock);
        pch_gpio_setup(chip);
        ret = gpiochip_add(&chip->gpio);
index 58a6a63a6ece65ed9de822449ee0d53cd41e66eb..9528779ca463154334fa54db9a22b6f852cddd0f 100644 (file)
@@ -26,6 +26,8 @@
 #include <linux/syscore_ops.h>
 #include <linux/slab.h>
 
+#include <asm/mach/irq.h>
+
 #include <mach/irqs.h>
 
 /*
 #define BANK_OFF(n)    (((n) < 3) ? (n) << 2 : 0x100 + (((n) - 3) << 2))
 
 int pxa_last_gpio;
+static int irq_base;
 
 #ifdef CONFIG_OF
 static struct irq_domain *domain;
+static struct device_node *pxa_gpio_of_node;
 #endif
 
 struct pxa_gpio_chip {
@@ -166,63 +170,14 @@ static inline int __gpio_is_occupied(unsigned gpio)
        return ret;
 }
 
-#ifdef CONFIG_ARCH_PXA
-static inline int __pxa_gpio_to_irq(int gpio)
-{
-       if (gpio_is_pxa_type(gpio_type))
-               return PXA_GPIO_TO_IRQ(gpio);
-       return -1;
-}
-
-static inline int __pxa_irq_to_gpio(int irq)
-{
-       if (gpio_is_pxa_type(gpio_type))
-               return irq - PXA_GPIO_TO_IRQ(0);
-       return -1;
-}
-#else
-static inline int __pxa_gpio_to_irq(int gpio) { return -1; }
-static inline int __pxa_irq_to_gpio(int irq) { return -1; }
-#endif
-
-#ifdef CONFIG_ARCH_MMP
-static inline int __mmp_gpio_to_irq(int gpio)
-{
-       if (gpio_is_mmp_type(gpio_type))
-               return MMP_GPIO_TO_IRQ(gpio);
-       return -1;
-}
-
-static inline int __mmp_irq_to_gpio(int irq)
-{
-       if (gpio_is_mmp_type(gpio_type))
-               return irq - MMP_GPIO_TO_IRQ(0);
-       return -1;
-}
-#else
-static inline int __mmp_gpio_to_irq(int gpio) { return -1; }
-static inline int __mmp_irq_to_gpio(int irq) { return -1; }
-#endif
-
 static int pxa_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
 {
-       int gpio, ret;
-
-       gpio = chip->base + offset;
-       ret = __pxa_gpio_to_irq(gpio);
-       if (ret >= 0)
-               return ret;
-       return __mmp_gpio_to_irq(gpio);
+       return chip->base + offset + irq_base;
 }
 
 int pxa_irq_to_gpio(int irq)
 {
-       int ret;
-
-       ret = __pxa_irq_to_gpio(irq);
-       if (ret >= 0)
-               return ret;
-       return __mmp_irq_to_gpio(irq);
+       return irq - irq_base;
 }
 
 static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
@@ -277,6 +232,24 @@ static void pxa_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
                                (value ? GPSR_OFFSET : GPCR_OFFSET));
 }
 
+#ifdef CONFIG_OF_GPIO
+static int pxa_gpio_of_xlate(struct gpio_chip *gc,
+                            const struct of_phandle_args *gpiospec,
+                            u32 *flags)
+{
+       if (gpiospec->args[0] > pxa_last_gpio)
+               return -EINVAL;
+
+       if (gc != &pxa_gpio_chips[gpiospec->args[0] / 32].chip)
+               return -EINVAL;
+
+       if (flags)
+               *flags = gpiospec->args[1];
+
+       return gpiospec->args[0] % 32;
+}
+#endif
+
 static int __devinit pxa_init_gpio_chip(int gpio_end,
                                        int (*set_wake)(unsigned int, unsigned int))
 {
@@ -304,6 +277,11 @@ static int __devinit pxa_init_gpio_chip(int gpio_end,
                c->get = pxa_gpio_get;
                c->set = pxa_gpio_set;
                c->to_irq = pxa_gpio_to_irq;
+#ifdef CONFIG_OF_GPIO
+               c->of_node = pxa_gpio_of_node;
+               c->of_xlate = pxa_gpio_of_xlate;
+               c->of_gpio_n_cells = 2;
+#endif
 
                /* number of GPIOs on last bank may be less than 32 */
                c->ngpio = (gpio + 31 > gpio_end) ? (gpio_end - gpio + 1) : 32;
@@ -379,6 +357,9 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc)
        struct pxa_gpio_chip *c;
        int loop, gpio, gpio_base, n;
        unsigned long gedr;
+       struct irq_chip *chip = irq_desc_get_chip(desc);
+
+       chained_irq_enter(chip, desc);
 
        do {
                loop = 0;
@@ -398,6 +379,8 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irq_desc *desc)
                        }
                }
        } while (loop);
+
+       chained_irq_exit(chip, desc);
 }
 
 static void pxa_ack_muxed_gpio(struct irq_data *d)
@@ -488,6 +471,7 @@ static int pxa_gpio_nums(void)
        return count;
 }
 
+#ifdef CONFIG_OF
 static struct of_device_id pxa_gpio_dt_ids[] = {
        { .compatible = "mrvl,pxa-gpio" },
        { .compatible = "mrvl,mmp-gpio", .data = (void *)MMP_GPIO },
@@ -505,12 +489,12 @@ static int pxa_irq_domain_map(struct irq_domain *d, unsigned int irq,
 
 const struct irq_domain_ops pxa_irq_domain_ops = {
        .map    = pxa_irq_domain_map,
+       .xlate  = irq_domain_xlate_twocell,
 };
 
-#ifdef CONFIG_OF
 static int __devinit pxa_gpio_probe_dt(struct platform_device *pdev)
 {
-       int ret, nr_banks, nr_gpios, irq_base;
+       int ret, nr_banks, nr_gpios;
        struct device_node *prev, *next, *np = pdev->dev.of_node;
        const struct of_device_id *of_id =
                                of_match_device(pxa_gpio_dt_ids, &pdev->dev);
@@ -545,6 +529,7 @@ static int __devinit pxa_gpio_probe_dt(struct platform_device *pdev)
        }
        domain = irq_domain_add_legacy(np, nr_gpios, irq_base, 0,
                                       &pxa_irq_domain_ops, NULL);
+       pxa_gpio_of_node = np;
        return 0;
 err:
        iounmap(gpio_reg_base);
@@ -564,10 +549,20 @@ static int __devinit pxa_gpio_probe(struct platform_device *pdev)
        int irq0 = 0, irq1 = 0, irq_mux, gpio_offset = 0;
 
        ret = pxa_gpio_probe_dt(pdev);
-       if (ret < 0)
+       if (ret < 0) {
                pxa_last_gpio = pxa_gpio_nums();
-       else
+#ifdef CONFIG_ARCH_PXA
+               if (gpio_is_pxa_type(gpio_type))
+                       irq_base = PXA_GPIO_TO_IRQ(0);
+#endif
+#ifdef CONFIG_ARCH_MMP
+               if (gpio_is_mmp_type(gpio_type))
+                       irq_base = MMP_GPIO_TO_IRQ(0);
+#endif
+       } else {
                use_of = 1;
+       }
+
        if (!pxa_last_gpio)
                return -EINVAL;
 
@@ -653,7 +648,7 @@ static struct platform_driver pxa_gpio_driver = {
        .probe          = pxa_gpio_probe,
        .driver         = {
                .name   = "pxa-gpio",
-               .of_match_table = pxa_gpio_dt_ids,
+               .of_match_table = of_match_ptr(pxa_gpio_dt_ids),
        },
 };
 
index 92f7b2bb79d40ccf277d19a4d234a53fd8c98d83..ba126cc04073e04c0d304bd8b6cbbd455d3d1d67 100644 (file)
@@ -2452,12 +2452,6 @@ static struct samsung_gpio_chip exynos5_gpios_1[] = {
                        .ngpio  = EXYNOS5_GPIO_C3_NR,
                        .label  = "GPC3",
                },
-       }, {
-               .chip   = {
-                       .base   = EXYNOS5_GPC4(0),
-                       .ngpio  = EXYNOS5_GPIO_C4_NR,
-                       .label  = "GPC4",
-               },
        }, {
                .chip   = {
                        .base   = EXYNOS5_GPD0(0),
@@ -2512,6 +2506,12 @@ static struct samsung_gpio_chip exynos5_gpios_1[] = {
                        .ngpio  = EXYNOS5_GPIO_Y6_NR,
                        .label  = "GPY6",
                },
+       }, {
+               .chip   = {
+                       .base   = EXYNOS5_GPC4(0),
+                       .ngpio  = EXYNOS5_GPIO_C4_NR,
+                       .label  = "GPC4",
+               },
        }, {
                .config = &samsung_gpio_cfgs[9],
                .irq_base = IRQ_EINT(0),
@@ -2836,7 +2836,7 @@ static __init void exynos5_gpiolib_init(void)
        }
 
        /* need to set base address for gpc4 */
-       exynos5_gpios_1[11].base = gpio_base1 + 0x2E0;
+       exynos5_gpios_1[20].base = gpio_base1 + 0x2E0;
 
        /* need to set base address for gpx */
        chip = &exynos5_gpios_1[21];
index 424dce8e3f30107ce2e9b5eb9b5d2bb394164cf9..8707d4572a06bfee4713fab5b521cd58f220aefa 100644 (file)
@@ -241,7 +241,8 @@ static int __devinit sch_gpio_probe(struct platform_device *pdev)
                        break;
 
                default:
-                       return -ENODEV;
+                       err = -ENODEV;
+                       goto err_sch_gpio_core;
        }
 
        sch_gpio_core.dev = &pdev->dev;
index a18c4aa68b1e8dcfadd5340e3f076bf33ecb788f..f1a45997aea8c3255aa7ecb697c72abe0beaf6d0 100644 (file)
@@ -82,7 +82,7 @@ int of_get_named_gpio_flags(struct device_node *np, const char *propname,
        gpiochip_find(&gg_data, of_gpiochip_find_and_xlate);
 
        of_node_put(gg_data.gpiospec.np);
-       pr_debug("%s exited with status %d\n", __func__, ret);
+       pr_debug("%s exited with status %d\n", __func__, gg_data.out_gpio);
        return gg_data.out_gpio;
 }
 EXPORT_SYMBOL(of_get_named_gpio_flags);
index de0213c9d11ce12e5496d18b49c16ef4ef030d85..5d6c71edc73911c7765a7530e65352fda2478845 100644 (file)
@@ -1773,56 +1773,102 @@ static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
        }
 }
 
-static int gpiolib_show(struct seq_file *s, void *unused)
+static void *gpiolib_seq_start(struct seq_file *s, loff_t *pos)
 {
-       struct gpio_chip        *chip = NULL;
-       unsigned                gpio;
-       int                     started = 0;
+       struct gpio_chip *chip = NULL;
+       unsigned int gpio;
+       void *ret = NULL;
+       loff_t index = 0;
 
        /* REVISIT this isn't locked against gpio_chip removal ... */
 
        for (gpio = 0; gpio_is_valid(gpio); gpio++) {
-               struct device *dev;
-
-               if (chip == gpio_desc[gpio].chip)
+               if (gpio_desc[gpio].chip == chip)
                        continue;
+
                chip = gpio_desc[gpio].chip;
                if (!chip)
                        continue;
 
-               seq_printf(s, "%sGPIOs %d-%d",
-                               started ? "\n" : "",
-                               chip->base, chip->base + chip->ngpio - 1);
-               dev = chip->dev;
-               if (dev)
-                       seq_printf(s, ", %s/%s",
-                               dev->bus ? dev->bus->name : "no-bus",
-                               dev_name(dev));
-               if (chip->label)
-                       seq_printf(s, ", %s", chip->label);
-               if (chip->can_sleep)
-                       seq_printf(s, ", can sleep");
-               seq_printf(s, ":\n");
-
-               started = 1;
-               if (chip->dbg_show)
-                       chip->dbg_show(s, chip);
-               else
-                       gpiolib_dbg_show(s, chip);
+               if (index++ >= *pos) {
+                       ret = chip;
+                       break;
+               }
        }
+
+       s->private = "";
+
+       return ret;
+}
+
+static void *gpiolib_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+       struct gpio_chip *chip = v;
+       unsigned int gpio;
+       void *ret = NULL;
+
+       /* skip GPIOs provided by the current chip */
+       for (gpio = chip->base + chip->ngpio; gpio_is_valid(gpio); gpio++) {
+               chip = gpio_desc[gpio].chip;
+               if (chip) {
+                       ret = chip;
+                       break;
+               }
+       }
+
+       s->private = "\n";
+       ++*pos;
+
+       return ret;
+}
+
+static void gpiolib_seq_stop(struct seq_file *s, void *v)
+{
+}
+
+static int gpiolib_seq_show(struct seq_file *s, void *v)
+{
+       struct gpio_chip *chip = v;
+       struct device *dev;
+
+       seq_printf(s, "%sGPIOs %d-%d", (char *)s->private,
+                       chip->base, chip->base + chip->ngpio - 1);
+       dev = chip->dev;
+       if (dev)
+               seq_printf(s, ", %s/%s", dev->bus ? dev->bus->name : "no-bus",
+                       dev_name(dev));
+       if (chip->label)
+               seq_printf(s, ", %s", chip->label);
+       if (chip->can_sleep)
+               seq_printf(s, ", can sleep");
+       seq_printf(s, ":\n");
+
+       if (chip->dbg_show)
+               chip->dbg_show(s, chip);
+       else
+               gpiolib_dbg_show(s, chip);
+
        return 0;
 }
 
+static const struct seq_operations gpiolib_seq_ops = {
+       .start = gpiolib_seq_start,
+       .next = gpiolib_seq_next,
+       .stop = gpiolib_seq_stop,
+       .show = gpiolib_seq_show,
+};
+
 static int gpiolib_open(struct inode *inode, struct file *file)
 {
-       return single_open(file, gpiolib_show, NULL);
+       return seq_open(file, &gpiolib_seq_ops);
 }
 
 static const struct file_operations gpiolib_operations = {
+       .owner          = THIS_MODULE,
        .open           = gpiolib_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
-       .release        = single_release,
+       .release        = seq_release,
 };
 
 static int __init gpiolib_debugfs_init(void)
index 66d4a28ad5a23fc2cf4b7b745091296444e287b1..0303935d10e2ca45165509a7e9e8165962c99774 100644 (file)
@@ -119,7 +119,7 @@ static int edid_load(struct drm_connector *connector, char *name,
 {
        const struct firmware *fw;
        struct platform_device *pdev;
-       u8 *fwdata = NULL, *edid;
+       u8 *fwdata = NULL, *edid, *new_edid;
        int fwsize, expected;
        int builtin = 0, err = 0;
        int i, valid_extensions = 0;
@@ -195,12 +195,14 @@ static int edid_load(struct drm_connector *connector, char *name,
                    "\"%s\" for connector \"%s\"\n", valid_extensions,
                    edid[0x7e], name, connector_name);
                edid[0x7e] = valid_extensions;
-               edid = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH,
+               new_edid = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH,
                    GFP_KERNEL);
-               if (edid == NULL) {
+               if (new_edid == NULL) {
                        err = -ENOMEM;
+                       kfree(edid);
                        goto relfw_out;
                }
+               edid = new_edid;
        }
 
        connector->display_info.raw_edid = edid;
index ed22612bc8477a3aa6dc95cfc2e058f7071c4878..a24ffbe97c01cffd8a8fa5093a5ba15ff04db30b 100644 (file)
@@ -346,11 +346,40 @@ static const struct pci_device_id pciidlist[] = {         /* aka */
        INTEL_VGA_DEVICE(0x016a, &intel_ivybridge_d_info), /* GT2 server */
        INTEL_VGA_DEVICE(0x0402, &intel_haswell_d_info), /* GT1 desktop */
        INTEL_VGA_DEVICE(0x0412, &intel_haswell_d_info), /* GT2 desktop */
+       INTEL_VGA_DEVICE(0x0422, &intel_haswell_d_info), /* GT2 desktop */
        INTEL_VGA_DEVICE(0x040a, &intel_haswell_d_info), /* GT1 server */
        INTEL_VGA_DEVICE(0x041a, &intel_haswell_d_info), /* GT2 server */
+       INTEL_VGA_DEVICE(0x042a, &intel_haswell_d_info), /* GT2 server */
        INTEL_VGA_DEVICE(0x0406, &intel_haswell_m_info), /* GT1 mobile */
        INTEL_VGA_DEVICE(0x0416, &intel_haswell_m_info), /* GT2 mobile */
-       INTEL_VGA_DEVICE(0x0c16, &intel_haswell_d_info), /* SDV */
+       INTEL_VGA_DEVICE(0x0426, &intel_haswell_m_info), /* GT2 mobile */
+       INTEL_VGA_DEVICE(0x0C02, &intel_haswell_d_info), /* SDV GT1 desktop */
+       INTEL_VGA_DEVICE(0x0C12, &intel_haswell_d_info), /* SDV GT2 desktop */
+       INTEL_VGA_DEVICE(0x0C22, &intel_haswell_d_info), /* SDV GT2 desktop */
+       INTEL_VGA_DEVICE(0x0C0A, &intel_haswell_d_info), /* SDV GT1 server */
+       INTEL_VGA_DEVICE(0x0C1A, &intel_haswell_d_info), /* SDV GT2 server */
+       INTEL_VGA_DEVICE(0x0C2A, &intel_haswell_d_info), /* SDV GT2 server */
+       INTEL_VGA_DEVICE(0x0C06, &intel_haswell_m_info), /* SDV GT1 mobile */
+       INTEL_VGA_DEVICE(0x0C16, &intel_haswell_m_info), /* SDV GT2 mobile */
+       INTEL_VGA_DEVICE(0x0C26, &intel_haswell_m_info), /* SDV GT2 mobile */
+       INTEL_VGA_DEVICE(0x0A02, &intel_haswell_d_info), /* ULT GT1 desktop */
+       INTEL_VGA_DEVICE(0x0A12, &intel_haswell_d_info), /* ULT GT2 desktop */
+       INTEL_VGA_DEVICE(0x0A22, &intel_haswell_d_info), /* ULT GT2 desktop */
+       INTEL_VGA_DEVICE(0x0A0A, &intel_haswell_d_info), /* ULT GT1 server */
+       INTEL_VGA_DEVICE(0x0A1A, &intel_haswell_d_info), /* ULT GT2 server */
+       INTEL_VGA_DEVICE(0x0A2A, &intel_haswell_d_info), /* ULT GT2 server */
+       INTEL_VGA_DEVICE(0x0A06, &intel_haswell_m_info), /* ULT GT1 mobile */
+       INTEL_VGA_DEVICE(0x0A16, &intel_haswell_m_info), /* ULT GT2 mobile */
+       INTEL_VGA_DEVICE(0x0A26, &intel_haswell_m_info), /* ULT GT2 mobile */
+       INTEL_VGA_DEVICE(0x0D12, &intel_haswell_d_info), /* CRW GT1 desktop */
+       INTEL_VGA_DEVICE(0x0D22, &intel_haswell_d_info), /* CRW GT2 desktop */
+       INTEL_VGA_DEVICE(0x0D32, &intel_haswell_d_info), /* CRW GT2 desktop */
+       INTEL_VGA_DEVICE(0x0D1A, &intel_haswell_d_info), /* CRW GT1 server */
+       INTEL_VGA_DEVICE(0x0D2A, &intel_haswell_d_info), /* CRW GT2 server */
+       INTEL_VGA_DEVICE(0x0D3A, &intel_haswell_d_info), /* CRW GT2 server */
+       INTEL_VGA_DEVICE(0x0D16, &intel_haswell_m_info), /* CRW GT1 mobile */
+       INTEL_VGA_DEVICE(0x0D26, &intel_haswell_m_info), /* CRW GT2 mobile */
+       INTEL_VGA_DEVICE(0x0D36, &intel_haswell_m_info), /* CRW GT2 mobile */
        INTEL_VGA_DEVICE(0x0f30, &intel_valleyview_m_info),
        INTEL_VGA_DEVICE(0x0157, &intel_valleyview_m_info),
        INTEL_VGA_DEVICE(0x0155, &intel_valleyview_d_info),
index da8b01fb1bf8dbbc1cbe34457bb67f4ff3fe28eb..a9d58d72bb4da2215592bb8ba6554e9835fb48cf 100644 (file)
@@ -451,7 +451,6 @@ int i915_switch_context(struct intel_ring_buffer *ring,
        struct drm_i915_file_private *file_priv = NULL;
        struct i915_hw_context *to;
        struct drm_i915_gem_object *from_obj = ring->last_context_obj;
-       int ret;
 
        if (dev_priv->hw_contexts_disabled)
                return 0;
index 5af631e788c8e6d39118eac4483ff9e2a40f329d..ff2819ea08130fb98da5f67550a18d9ca3c5974d 100644 (file)
@@ -291,6 +291,16 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
        target_i915_obj = to_intel_bo(target_obj);
        target_offset = target_i915_obj->gtt_offset;
 
+       /* Sandybridge PPGTT errata: We need a global gtt mapping for MI and
+        * pipe_control writes because the gpu doesn't properly redirect them
+        * through the ppgtt for non_secure batchbuffers. */
+       if (unlikely(IS_GEN6(dev) &&
+           reloc->write_domain == I915_GEM_DOMAIN_INSTRUCTION &&
+           !target_i915_obj->has_global_gtt_mapping)) {
+               i915_gem_gtt_bind_object(target_i915_obj,
+                                        target_i915_obj->cache_level);
+       }
+
        /* The target buffer should have appeared before us in the
         * exec_object list, so it should have a GTT space bound by now.
         */
@@ -399,16 +409,6 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
                io_mapping_unmap_atomic(reloc_page);
        }
 
-       /* Sandybridge PPGTT errata: We need a global gtt mapping for MI and
-        * pipe_control writes because the gpu doesn't properly redirect them
-        * through the ppgtt for non_secure batchbuffers. */
-       if (unlikely(IS_GEN6(dev) &&
-           reloc->write_domain == I915_GEM_DOMAIN_INSTRUCTION &&
-           !target_i915_obj->has_global_gtt_mapping)) {
-               i915_gem_gtt_bind_object(target_i915_obj,
-                                        target_i915_obj->cache_level);
-       }
-
        /* and update the user's relocation entry */
        reloc->presumed_offset = target_offset;
 
index 9fd25a435536121a33651c66ac00f5999c81f6f4..ee9b68f6bc36c938213931065c50bb5d60836b23 100644 (file)
@@ -361,7 +361,8 @@ int i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj)
        struct drm_device *dev = obj->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       if (dev_priv->mm.gtt->needs_dmar)
+       /* don't map imported dma buf objects */
+       if (dev_priv->mm.gtt->needs_dmar && !obj->sg_table)
                return intel_gtt_map_memory(obj->pages,
                                            obj->base.size >> PAGE_SHIFT,
                                            &obj->sg_list,
index 2f5388af8df9cdf775d66d4d4f72f50f29bdecc0..7631807a27886e2483d77de1046461350f9c7d15 100644 (file)
@@ -32,6 +32,7 @@
 #include "intel_drv.h"
 #include "i915_drv.h"
 
+#ifdef CONFIG_PM
 static u32 calc_residency(struct drm_device *dev, const u32 reg)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -224,3 +225,14 @@ void i915_teardown_sysfs(struct drm_device *dev)
        device_remove_bin_file(&dev->primary->kdev,  &dpf_attrs);
        sysfs_unmerge_group(&dev->primary->kdev.kobj, &rc6_attr_group);
 }
+#else
+void i915_setup_sysfs(struct drm_device *dev)
+{
+       return;
+}
+
+void i915_teardown_sysfs(struct drm_device *dev)
+{
+       return;
+}
+#endif /* CONFIG_PM */
index f6159765f1ebe8cf8f6844c092deddd37bd44040..a69a3d0d3acf6c7bc81119342aa830b41c047025 100644 (file)
@@ -869,6 +869,7 @@ intel_vlv_find_best_pll(const intel_limit_t *limit, struct drm_crtc *crtc,
        unsigned long bestppm, ppm, absppm;
        int dotclk, flag;
 
+       flag = 0;
        dotclk = target * 1000;
        bestppm = 1000000;
        ppm = absppm = 0;
@@ -3753,17 +3754,6 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc,
                        continue;
                }
 
-               if (intel_encoder->type == INTEL_OUTPUT_EDP) {
-                       /* Use VBT settings if we have an eDP panel */
-                       unsigned int edp_bpc = dev_priv->edp.bpp / 3;
-
-                       if (edp_bpc < display_bpc) {
-                               DRM_DEBUG_KMS("clamping display bpc (was %d) to eDP (%d)\n", display_bpc, edp_bpc);
-                               display_bpc = edp_bpc;
-                       }
-                       continue;
-               }
-
                /* Not one of the known troublemakers, check the EDID */
                list_for_each_entry(connector, &dev->mode_config.connector_list,
                                    head) {
index 0a56b9ab0f5893d49b60499ae75db9f387b6fa2e..a6c426afaa7aca46144f5a3710c0ea6f10a46b83 100644 (file)
@@ -1174,10 +1174,14 @@ static void ironlake_edp_panel_off(struct intel_dp *intel_dp)
        WARN(!intel_dp->want_panel_vdd, "Need VDD to turn off panel\n");
 
        pp = ironlake_get_pp_control(dev_priv);
-       pp &= ~(POWER_TARGET_ON | PANEL_POWER_RESET | EDP_BLC_ENABLE);
+       /* We need to switch off panel power _and_ force vdd, for otherwise some
+        * panels get very unhappy and cease to work. */
+       pp &= ~(POWER_TARGET_ON | EDP_FORCE_VDD | PANEL_POWER_RESET | EDP_BLC_ENABLE);
        I915_WRITE(PCH_PP_CONTROL, pp);
        POSTING_READ(PCH_PP_CONTROL);
 
+       intel_dp->want_panel_vdd = false;
+
        ironlake_wait_panel_off(intel_dp);
 }
 
@@ -1287,11 +1291,9 @@ static void intel_dp_prepare(struct drm_encoder *encoder)
         * ensure that we have vdd while we switch off the panel. */
        ironlake_edp_panel_vdd_on(intel_dp);
        ironlake_edp_backlight_off(intel_dp);
-       ironlake_edp_panel_off(intel_dp);
-
        intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
+       ironlake_edp_panel_off(intel_dp);
        intel_dp_link_down(intel_dp);
-       ironlake_edp_panel_vdd_off(intel_dp, false);
 }
 
 static void intel_dp_commit(struct drm_encoder *encoder)
@@ -1326,11 +1328,9 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
                /* Switching the panel off requires vdd. */
                ironlake_edp_panel_vdd_on(intel_dp);
                ironlake_edp_backlight_off(intel_dp);
-               ironlake_edp_panel_off(intel_dp);
-
                intel_dp_sink_dpms(intel_dp, mode);
+               ironlake_edp_panel_off(intel_dp);
                intel_dp_link_down(intel_dp);
-               ironlake_edp_panel_vdd_off(intel_dp, false);
 
                if (is_cpu_edp(intel_dp))
                        ironlake_edp_pll_off(encoder);
index 84353559441cc2169dde4bef5042949de62ef251..132ab511b90cd24d5e26e4f41e86749d558670ac 100644 (file)
 })
 
 #define wait_for_atomic_us(COND, US) ({ \
-       int i, ret__ = -ETIMEDOUT;      \
-       for (i = 0; i < (US); i++) {    \
-               if ((COND)) {           \
-                       ret__ = 0;      \
-                       break;          \
-               }                       \
-               udelay(1);              \
-       }                               \
-       ret__;                          \
+       unsigned long timeout__ = jiffies + usecs_to_jiffies(US);       \
+       int ret__ = 0;                                                  \
+       while (!(COND)) {                                               \
+               if (time_after(jiffies, timeout__)) {                   \
+                       ret__ = -ETIMEDOUT;                             \
+                       break;                                          \
+               }                                                       \
+               cpu_relax();                                            \
+       }                                                               \
+       ret__;                                                          \
 })
 
 #define wait_for(COND, MS) _wait_for(COND, MS, 1)
@@ -380,7 +381,6 @@ extern void intel_pch_panel_fitting(struct drm_device *dev,
                                    const struct drm_display_mode *mode,
                                    struct drm_display_mode *adjusted_mode);
 extern u32 intel_panel_get_max_backlight(struct drm_device *dev);
-extern u32 intel_panel_get_backlight(struct drm_device *dev);
 extern void intel_panel_set_backlight(struct drm_device *dev, u32 level);
 extern int intel_panel_setup_backlight(struct drm_device *dev);
 extern void intel_panel_enable_backlight(struct drm_device *dev,
index 1991a4408cf9e10896bd5295ba4b3b4b1d74856b..b9755f6378d8d5a6b4ad9a979ce54b49b84a9814 100644 (file)
@@ -486,9 +486,6 @@ int intel_setup_gmbus(struct drm_device *dev)
                bus->dev_priv = dev_priv;
 
                bus->adapter.algo = &gmbus_algorithm;
-               ret = i2c_add_adapter(&bus->adapter);
-               if (ret)
-                       goto err;
 
                /* By default use a conservative clock rate */
                bus->reg0 = port | GMBUS_RATE_100KHZ;
@@ -498,6 +495,10 @@ int intel_setup_gmbus(struct drm_device *dev)
                        bus->force_bit = true;
 
                intel_gpio_setup(bus, port);
+
+               ret = i2c_add_adapter(&bus->adapter);
+               if (ret)
+                       goto err;
        }
 
        intel_i2c_reset(dev_priv->dev);
@@ -540,9 +541,6 @@ void intel_teardown_gmbus(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int i;
 
-       if (dev_priv->gmbus == NULL)
-               return;
-
        for (i = 0; i < GMBUS_NUM_PORTS; i++) {
                struct intel_gmbus *bus = &dev_priv->gmbus[i];
                i2c_del_adapter(&bus->adapter);
index 10c7d39034e1c8c0a3e17491e17ffa3286b5f97a..3df4f5fa892ad847b394c2050e8956779473afd8 100644 (file)
@@ -213,7 +213,7 @@ static u32 intel_panel_compute_brightness(struct drm_device *dev, u32 val)
        return val;
 }
 
-u32 intel_panel_get_backlight(struct drm_device *dev)
+static u32 intel_panel_get_backlight(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 val;
@@ -311,9 +311,6 @@ void intel_panel_enable_backlight(struct drm_device *dev,
        if (dev_priv->backlight_level == 0)
                dev_priv->backlight_level = intel_panel_get_max_backlight(dev);
 
-       dev_priv->backlight_enabled = true;
-       intel_panel_actually_set_backlight(dev, dev_priv->backlight_level);
-
        if (INTEL_INFO(dev)->gen >= 4) {
                uint32_t reg, tmp;
 
@@ -326,7 +323,7 @@ void intel_panel_enable_backlight(struct drm_device *dev,
                 * we don't track the backlight dpms state, hence check whether
                 * we have to do anything first. */
                if (tmp & BLM_PWM_ENABLE)
-                       return;
+                       goto set_level;
 
                if (dev_priv->num_pipe == 3)
                        tmp &= ~BLM_PIPE_SELECT_IVB;
@@ -347,6 +344,14 @@ void intel_panel_enable_backlight(struct drm_device *dev,
                        I915_WRITE(BLC_PWM_PCH_CTL1, tmp);
                }
        }
+
+set_level:
+       /* Call below after setting BLC_PWM_CPU_CTL2 and BLC_PWM_PCH_CTL1.
+        * BLC_PWM_CPU_CTL may be cleared to zero automatically when these
+        * registers are set.
+        */
+       dev_priv->backlight_enabled = true;
+       intel_panel_actually_set_backlight(dev, dev_priv->backlight_level);
 }
 
 static void intel_panel_init_backlight(struct drm_device *dev)
index 94aabcaa3a673a46aa0e9361133aa3331ed8e453..58c07cdafb7ed6c5c5ce08216f3dca999efa2a19 100644 (file)
@@ -3963,6 +3963,7 @@ static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
                DRM_ERROR("Force wake wait timed out\n");
 
        I915_WRITE_NOTRACE(FORCEWAKE, 1);
+       POSTING_READ(FORCEWAKE);
 
        if (wait_for_atomic_us((I915_READ_NOTRACE(forcewake_ack) & 1), 500))
                DRM_ERROR("Force wake wait timed out\n");
@@ -3983,6 +3984,7 @@ static void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv)
                DRM_ERROR("Force wake wait timed out\n");
 
        I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_ENABLE(1));
+       POSTING_READ(FORCEWAKE_MT);
 
        if (wait_for_atomic_us((I915_READ_NOTRACE(forcewake_ack) & 1), 500))
                DRM_ERROR("Force wake wait timed out\n");
@@ -4018,14 +4020,14 @@ 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);
-       /* The below doubles as a POSTING_READ */
+       POSTING_READ(FORCEWAKE);
        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(1));
-       /* The below doubles as a POSTING_READ */
+       POSTING_READ(FORCEWAKE_MT);
        gen6_gt_check_fifodbg(dev_priv);
 }
 
index bf0195a96d5308c48d273cb492081a8d415ba188..e2a73b38abe96e7dc49674d39806c5ca3cab6e51 100644 (file)
@@ -227,31 +227,36 @@ gen6_render_ring_flush(struct intel_ring_buffer *ring,
         * number of bits based on the write domains has little performance
         * impact.
         */
-       flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
-       flags |= PIPE_CONTROL_TLB_INVALIDATE;
-       flags |= PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE;
-       flags |= PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE;
-       flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
-       flags |= PIPE_CONTROL_VF_CACHE_INVALIDATE;
-       flags |= PIPE_CONTROL_CONST_CACHE_INVALIDATE;
-       flags |= PIPE_CONTROL_STATE_CACHE_INVALIDATE;
-       /*
-        * Ensure that any following seqno writes only happen when the render
-        * cache is indeed flushed (but only if the caller actually wants that).
-        */
-       if (flush_domains)
+       if (flush_domains) {
+               flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
+               flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
+               /*
+                * Ensure that any following seqno writes only happen
+                * when the render cache is indeed flushed.
+                */
                flags |= PIPE_CONTROL_CS_STALL;
+       }
+       if (invalidate_domains) {
+               flags |= PIPE_CONTROL_TLB_INVALIDATE;
+               flags |= PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE;
+               flags |= PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE;
+               flags |= PIPE_CONTROL_VF_CACHE_INVALIDATE;
+               flags |= PIPE_CONTROL_CONST_CACHE_INVALIDATE;
+               flags |= PIPE_CONTROL_STATE_CACHE_INVALIDATE;
+               /*
+                * TLB invalidate requires a post-sync write.
+                */
+               flags |= PIPE_CONTROL_QW_WRITE;
+       }
 
-       ret = intel_ring_begin(ring, 6);
+       ret = intel_ring_begin(ring, 4);
        if (ret)
                return ret;
 
-       intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(5));
+       intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(4));
        intel_ring_emit(ring, flags);
        intel_ring_emit(ring, scratch_addr | PIPE_CONTROL_GLOBAL_GTT);
-       intel_ring_emit(ring, 0); /* lower dword */
-       intel_ring_emit(ring, 0); /* uppwer dword */
-       intel_ring_emit(ring, MI_NOOP);
+       intel_ring_emit(ring, 0);
        intel_ring_advance(ring);
 
        return 0;
@@ -289,8 +294,6 @@ static int init_ring_common(struct intel_ring_buffer *ring)
        I915_WRITE_HEAD(ring, 0);
        ring->write_tail(ring, 0);
 
-       /* Initialize the ring. */
-       I915_WRITE_START(ring, obj->gtt_offset);
        head = I915_READ_HEAD(ring) & HEAD_ADDR;
 
        /* G45 ring initialization fails to reset head to zero */
@@ -316,6 +319,11 @@ static int init_ring_common(struct intel_ring_buffer *ring)
                }
        }
 
+       /* Initialize the ring. This must happen _after_ we've cleared the ring
+        * registers with the above sequence (the readback of the HEAD registers
+        * also enforces ordering), otherwise the hw might lose the new ring
+        * register values. */
+       I915_WRITE_START(ring, obj->gtt_offset);
        I915_WRITE_CTL(ring,
                        ((ring->size - PAGE_SIZE) & RING_NR_PAGES)
                        | RING_VALID);
index 26a6a4d0d0788b536de65f3b4ca6261768115179..d172e9873131cc708a5351fdec3cc690a73cabcd 100644 (file)
@@ -444,13 +444,16 @@ static bool intel_sdvo_write_cmd(struct intel_sdvo *intel_sdvo, u8 cmd,
        struct i2c_msg *msgs;
        int i, ret = true;
 
+        /* Would be simpler to allocate both in one go ? */        
        buf = (u8 *)kzalloc(args_len * 2 + 2, GFP_KERNEL);
        if (!buf)
                return false;
 
        msgs = kcalloc(args_len + 3, sizeof(*msgs), GFP_KERNEL);
-       if (!msgs)
+       if (!msgs) {
+               kfree(buf);
                return false;
+        }
 
        intel_sdvo_debug_write(intel_sdvo, cmd, args, args_len);
 
index a4d7c500c97b7f43d049a8ed8cc6bca59b20c100..b69642d5d850581694fe8741056a5d0529f4eeed 100644 (file)
@@ -468,10 +468,11 @@ static int mga_g200er_set_plls(struct mga_device *mdev, long clock)
 {
        unsigned int vcomax, vcomin, pllreffreq;
        unsigned int delta, tmpdelta;
-       unsigned int testr, testn, testm, testo;
+       int testr, testn, testm, testo;
        unsigned int p, m, n;
-       unsigned int computed;
+       unsigned int computed, vco;
        int tmp;
+       const unsigned int m_div_val[] = { 1, 2, 4, 8 };
 
        m = n = p = 0;
        vcomax = 1488000;
@@ -490,12 +491,13 @@ static int mga_g200er_set_plls(struct mga_device *mdev, long clock)
                                if (delta == 0)
                                        break;
                                for (testo = 5; testo < 33; testo++) {
-                                       computed = pllreffreq * (testn + 1) /
+                                       vco = pllreffreq * (testn + 1) /
                                                (testr + 1);
-                                       if (computed < vcomin)
+                                       if (vco < vcomin)
                                                continue;
-                                       if (computed > vcomax)
+                                       if (vco > vcomax)
                                                continue;
+                                       computed = vco / (m_div_val[testm] * (testo + 1));
                                        if (computed > clock)
                                                tmpdelta = computed - clock;
                                        else
index 77e564667b5c89d6fec1ad5e58f55ce5082f2c42..240cf962c999ee322e4f77fe2e612ffc731e6eb7 100644 (file)
@@ -229,7 +229,7 @@ nouveau_i2c_init(struct drm_device *dev)
                        }
                        break;
                case 6: /* NV50- DP AUX */
-                       port->drive = entry[0];
+                       port->drive = entry[0] & 0x0f;
                        port->sense = port->drive;
                        port->adapter.algo = &nouveau_dp_i2c_algo;
                        break;
index 1cdfd6e757ce7455c03ea35eaef42dbe6253ab7b..1866dbb499792e4e4758938c50802d11beb29bb7 100644 (file)
@@ -731,7 +731,6 @@ nouveau_card_init(struct drm_device *dev)
                        case 0xa3:
                        case 0xa5:
                        case 0xa8:
-                       case 0xaf:
                                nva3_copy_create(dev);
                                break;
                        }
index cc82d799fc3ba162ae2798d3a5e0df1e6db4abec..c564c5e4c30aa97841f5cf1060d3bbcf8686ebbf 100644 (file)
@@ -117,17 +117,22 @@ nv84_fifo_context_del(struct nouveau_channel *chan, int engine)
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        unsigned long flags;
+       u32 save;
 
        /* remove channel from playlist, will context switch if active */
        spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
        nv_mask(dev, 0x002600 + (chan->id * 4), 0x80000000, 0x00000000);
        nv50_fifo_playlist_update(dev);
 
+       save = nv_mask(dev, 0x002520, 0x0000003f, 0x15);
+
        /* tell any engines on this channel to unload their contexts */
        nv_wr32(dev, 0x0032fc, chan->ramin->vinst >> 12);
        if (!nv_wait_ne(dev, 0x0032fc, 0xffffffff, 0xffffffff))
                NV_INFO(dev, "PFIFO: channel %d unload timeout\n", chan->id);
 
+       nv_wr32(dev, 0x002520, save);
+
        nv_wr32(dev, 0x002600 + (chan->id * 4), 0x00000000);
        spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
 
@@ -184,10 +189,13 @@ nv84_fifo_fini(struct drm_device *dev, int engine, bool suspend)
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nv84_fifo_priv *priv = nv_engine(dev, engine);
        int i;
+       u32 save;
 
        /* set playlist length to zero, fifo will unload context */
        nv_wr32(dev, 0x0032ec, 0);
 
+       save = nv_mask(dev, 0x002520, 0x0000003f, 0x15);
+
        /* tell all connected engines to unload their contexts */
        for (i = 0; i < priv->base.channels; i++) {
                struct nouveau_channel *chan = dev_priv->channels.ptr[i];
@@ -199,6 +207,7 @@ nv84_fifo_fini(struct drm_device *dev, int engine, bool suspend)
                }
        }
 
+       nv_wr32(dev, 0x002520, save);
        nv_wr32(dev, 0x002140, 0);
        return 0;
 }
index 7c95c44e2887b870096964d600b98c80a0e16505..4e712b10ebdb682c7956c74a5f3e694ff57e61dd 100644 (file)
@@ -557,7 +557,7 @@ prog_mem(struct drm_device *dev, struct nvc0_pm_state *info)
        nouveau_mem_exec(&exec, info->perflvl);
 
        if (dev_priv->chipset < 0xd0)
-               nv_wr32(dev, 0x611200, 0x00003300);
+               nv_wr32(dev, 0x611200, 0x00003330);
        else
                nv_wr32(dev, 0x62c000, 0x03030300);
 }
index d0d60e1e7f95bf74c7209f81f6cd205edd8d71a5..dac525b2994ee4bd28ff862625e7a6fe7649d2cd 100644 (file)
@@ -790,7 +790,7 @@ nvd0_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
        int ch = EVO_CURS(nv_crtc->index);
 
-       evo_piow(crtc->dev, ch, 0x0084, (y << 16) | x);
+       evo_piow(crtc->dev, ch, 0x0084, (y << 16) | (x & 0xffff));
        evo_piow(crtc->dev, ch, 0x0080, 0x00000000);
        return 0;
 }
index 1855ecbd843b81161245cfd15ccb1f4e7f8e2343..e98d144e6eb9df766fc458e03bdd35acef349ce4 100644 (file)
@@ -294,6 +294,25 @@ nve0_fifo_isr_vm_fault(struct drm_device *dev, int unit)
        printk(" on channel 0x%010llx\n", (u64)inst << 12);
 }
 
+static int
+nve0_fifo_page_flip(struct drm_device *dev, u32 chid)
+{
+       struct nve0_fifo_priv *priv = nv_engine(dev, NVOBJ_ENGINE_FIFO);
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_channel *chan = NULL;
+       unsigned long flags;
+       int ret = -EINVAL;
+
+       spin_lock_irqsave(&dev_priv->channels.lock, flags);
+       if (likely(chid >= 0 && chid < priv->base.channels)) {
+               chan = dev_priv->channels.ptr[chid];
+               if (likely(chan))
+                       ret = nouveau_finish_page_flip(chan, NULL);
+       }
+       spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
+       return ret;
+}
+
 static void
 nve0_fifo_isr_subfifo_intr(struct drm_device *dev, int unit)
 {
@@ -303,11 +322,21 @@ nve0_fifo_isr_subfifo_intr(struct drm_device *dev, int unit)
        u32 chid = nv_rd32(dev, 0x040120 + (unit * 0x2000)) & 0x7f;
        u32 subc = (addr & 0x00070000);
        u32 mthd = (addr & 0x00003ffc);
+       u32 show = stat;
+
+       if (stat & 0x00200000) {
+               if (mthd == 0x0054) {
+                       if (!nve0_fifo_page_flip(dev, chid))
+                               show &= ~0x00200000;
+               }
+       }
 
-       NV_INFO(dev, "PSUBFIFO %d:", unit);
-       nouveau_bitfield_print(nve0_fifo_subfifo_intr, stat);
-       NV_INFO(dev, "PSUBFIFO %d: ch %d subc %d mthd 0x%04x data 0x%08x\n",
-               unit, chid, subc, mthd, data);
+       if (show) {
+               NV_INFO(dev, "PFIFO%d:", unit);
+               nouveau_bitfield_print(nve0_fifo_subfifo_intr, show);
+               NV_INFO(dev, "PFIFO%d: ch %d subc %d mthd 0x%04x data 0x%08x\n",
+                       unit, chid, subc, mthd, data);
+       }
 
        nv_wr32(dev, 0x0400c0 + (unit * 0x2000), 0x80600008);
        nv_wr32(dev, 0x040108 + (unit * 0x2000), stat);
index 9e6f76fec52789b4931e4e1098b9b52df765c270..c6fcb5b86a450de367794674bca0ac41ea49a051 100644 (file)
@@ -259,7 +259,7 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode)
                /* adjust pm to dpms changes BEFORE enabling crtcs */
                radeon_pm_compute_clocks(rdev);
                /* disable crtc pair power gating before programming */
-               if (ASIC_IS_DCE6(rdev))
+               if (ASIC_IS_DCE6(rdev) && !radeon_crtc->in_mode_set)
                        atombios_powergate_crtc(crtc, ATOM_DISABLE);
                atombios_enable_crtc(crtc, ATOM_ENABLE);
                if (ASIC_IS_DCE3(rdev) && !ASIC_IS_DCE6(rdev))
@@ -279,7 +279,7 @@ void atombios_crtc_dpms(struct drm_crtc *crtc, int mode)
                atombios_enable_crtc(crtc, ATOM_DISABLE);
                radeon_crtc->enabled = false;
                /* power gating is per-pair */
-               if (ASIC_IS_DCE6(rdev)) {
+               if (ASIC_IS_DCE6(rdev) && !radeon_crtc->in_mode_set) {
                        struct drm_crtc *other_crtc;
                        struct radeon_crtc *other_radeon_crtc;
                        list_for_each_entry(other_crtc, &rdev->ddev->mode_config.crtc_list, head) {
@@ -1531,12 +1531,12 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc)
                                 * crtc virtual pixel clock.
                                 */
                                if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) {
-                                       if (ASIC_IS_DCE5(rdev))
-                                               return ATOM_DCPLL;
+                                       if (rdev->clock.dp_extclk)
+                                               return ATOM_PPLL_INVALID;
                                        else if (ASIC_IS_DCE6(rdev))
                                                return ATOM_PPLL0;
-                                       else if (rdev->clock.dp_extclk)
-                                               return ATOM_PPLL_INVALID;
+                                       else if (ASIC_IS_DCE5(rdev))
+                                               return ATOM_DCPLL;
                                }
                        }
                }
@@ -1635,18 +1635,28 @@ static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc,
 static void atombios_crtc_prepare(struct drm_crtc *crtc)
 {
        struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       struct radeon_device *rdev = dev->dev_private;
 
+       radeon_crtc->in_mode_set = true;
        /* pick pll */
        radeon_crtc->pll_id = radeon_atom_pick_pll(crtc);
 
+       /* disable crtc pair power gating before programming */
+       if (ASIC_IS_DCE6(rdev))
+               atombios_powergate_crtc(crtc, ATOM_DISABLE);
+
        atombios_lock_crtc(crtc, ATOM_ENABLE);
        atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
 }
 
 static void atombios_crtc_commit(struct drm_crtc *crtc)
 {
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+
        atombios_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
        atombios_lock_crtc(crtc, ATOM_DISABLE);
+       radeon_crtc->in_mode_set = false;
 }
 
 static void atombios_crtc_disable(struct drm_crtc *crtc)
index e585a3b947eb7c169fe9869aa18880744ab92ef2..e93b80a6d4e969a30cdbbc934d2e8ddd8b8e8a1a 100644 (file)
@@ -1229,24 +1229,8 @@ void evergreen_agp_enable(struct radeon_device *rdev)
 
 void evergreen_mc_stop(struct radeon_device *rdev, struct evergreen_mc_save *save)
 {
-       save->vga_control[0] = RREG32(D1VGA_CONTROL);
-       save->vga_control[1] = RREG32(D2VGA_CONTROL);
        save->vga_render_control = RREG32(VGA_RENDER_CONTROL);
        save->vga_hdp_control = RREG32(VGA_HDP_CONTROL);
-       save->crtc_control[0] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET);
-       save->crtc_control[1] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET);
-       if (rdev->num_crtc >= 4) {
-               save->vga_control[2] = RREG32(EVERGREEN_D3VGA_CONTROL);
-               save->vga_control[3] = RREG32(EVERGREEN_D4VGA_CONTROL);
-               save->crtc_control[2] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET);
-               save->crtc_control[3] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET);
-       }
-       if (rdev->num_crtc >= 6) {
-               save->vga_control[4] = RREG32(EVERGREEN_D5VGA_CONTROL);
-               save->vga_control[5] = RREG32(EVERGREEN_D6VGA_CONTROL);
-               save->crtc_control[4] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET);
-               save->crtc_control[5] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET);
-       }
 
        /* Stop all video */
        WREG32(VGA_RENDER_CONTROL, 0);
@@ -1357,47 +1341,6 @@ void evergreen_mc_resume(struct radeon_device *rdev, struct evergreen_mc_save *s
        /* Unlock host access */
        WREG32(VGA_HDP_CONTROL, save->vga_hdp_control);
        mdelay(1);
-       /* Restore video state */
-       WREG32(D1VGA_CONTROL, save->vga_control[0]);
-       WREG32(D2VGA_CONTROL, save->vga_control[1]);
-       if (rdev->num_crtc >= 4) {
-               WREG32(EVERGREEN_D3VGA_CONTROL, save->vga_control[2]);
-               WREG32(EVERGREEN_D4VGA_CONTROL, save->vga_control[3]);
-       }
-       if (rdev->num_crtc >= 6) {
-               WREG32(EVERGREEN_D5VGA_CONTROL, save->vga_control[4]);
-               WREG32(EVERGREEN_D6VGA_CONTROL, save->vga_control[5]);
-       }
-       WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 1);
-       WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 1);
-       if (rdev->num_crtc >= 4) {
-               WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 1);
-               WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 1);
-       }
-       if (rdev->num_crtc >= 6) {
-               WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 1);
-               WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 1);
-       }
-       WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, save->crtc_control[0]);
-       WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, save->crtc_control[1]);
-       if (rdev->num_crtc >= 4) {
-               WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, save->crtc_control[2]);
-               WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, save->crtc_control[3]);
-       }
-       if (rdev->num_crtc >= 6) {
-               WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, save->crtc_control[4]);
-               WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, save->crtc_control[5]);
-       }
-       WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
-       WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
-       if (rdev->num_crtc >= 4) {
-               WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0);
-               WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0);
-       }
-       if (rdev->num_crtc >= 6) {
-               WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0);
-               WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
-       }
        WREG32(VGA_RENDER_CONTROL, save->vga_render_control);
 }
 
@@ -1986,10 +1929,18 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
        if (rdev->flags & RADEON_IS_IGP)
                rdev->config.evergreen.tile_config |= 1 << 4;
        else {
-               if ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT)
-                       rdev->config.evergreen.tile_config |= 1 << 4;
-               else
+               switch ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) {
+               case 0: /* four banks */
                        rdev->config.evergreen.tile_config |= 0 << 4;
+                       break;
+               case 1: /* eight banks */
+                       rdev->config.evergreen.tile_config |= 1 << 4;
+                       break;
+               case 2: /* sixteen banks */
+               default:
+                       rdev->config.evergreen.tile_config |= 2 << 4;
+                       break;
+               }
        }
        rdev->config.evergreen.tile_config |= 0 << 8;
        rdev->config.evergreen.tile_config |=
index c16554122ccd0fb482aa2f03bc93e8b47af55430..e44a62a07fe396f36e70dd6dce1b4460c6786b45 100644 (file)
@@ -788,6 +788,13 @@ static int evergreen_cs_track_validate_texture(struct radeon_cs_parser *p,
        case V_030000_SQ_TEX_DIM_1D_ARRAY:
        case V_030000_SQ_TEX_DIM_2D_ARRAY:
                depth = 1;
+               break;
+       case V_030000_SQ_TEX_DIM_2D_MSAA:
+       case V_030000_SQ_TEX_DIM_2D_ARRAY_MSAA:
+               surf.nsamples = 1 << llevel;
+               llevel = 0;
+               depth = 1;
+               break;
        case V_030000_SQ_TEX_DIM_3D:
                break;
        default:
@@ -961,13 +968,15 @@ static int evergreen_cs_track_check(struct radeon_cs_parser *p)
 
        if (track->db_dirty) {
                /* Check stencil buffer */
-               if (G_028800_STENCIL_ENABLE(track->db_depth_control)) {
+               if (G_028044_FORMAT(track->db_s_info) != V_028044_STENCIL_INVALID &&
+                   G_028800_STENCIL_ENABLE(track->db_depth_control)) {
                        r = evergreen_cs_track_validate_stencil(p);
                        if (r)
                                return r;
                }
                /* Check depth buffer */
-               if (G_028800_Z_ENABLE(track->db_depth_control)) {
+               if (G_028040_FORMAT(track->db_z_info) != V_028040_Z_INVALID &&
+                   G_028800_Z_ENABLE(track->db_depth_control)) {
                        r = evergreen_cs_track_validate_depth(p);
                        if (r)
                                return r;
index d3bd098e4e19d453aee64b691e6519a0d8c97066..79347855d9bf50cf024a34677ca2a4287f9f3df5 100644 (file)
 #define   S_028044_FORMAT(x)                           (((x) & 0x1) << 0)
 #define   G_028044_FORMAT(x)                           (((x) >> 0) & 0x1)
 #define   C_028044_FORMAT                              0xFFFFFFFE
+#define            V_028044_STENCIL_INVALID                    0
+#define            V_028044_STENCIL_8                          1
 #define   G_028044_TILE_SPLIT(x)                       (((x) >> 8) & 0x7)
 #define DB_Z_READ_BASE                                 0x28048
 #define DB_STENCIL_READ_BASE                           0x2804c
index 9945d86d900153b13210bcc967c594c638213f5c..853800e8582f972233dd20f6f6b4573d24f71f2f 100644 (file)
@@ -574,10 +574,18 @@ static void cayman_gpu_init(struct radeon_device *rdev)
        if (rdev->flags & RADEON_IS_IGP)
                rdev->config.cayman.tile_config |= 1 << 4;
        else {
-               if ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT)
-                       rdev->config.cayman.tile_config |= 1 << 4;
-               else
+               switch ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) {
+               case 0: /* four banks */
                        rdev->config.cayman.tile_config |= 0 << 4;
+                       break;
+               case 1: /* eight banks */
+                       rdev->config.cayman.tile_config |= 1 << 4;
+                       break;
+               case 2: /* sixteen banks */
+               default:
+                       rdev->config.cayman.tile_config |= 2 << 4;
+                       break;
+               }
        }
        rdev->config.cayman.tile_config |=
                ((gb_addr_config & PIPE_INTERLEAVE_SIZE_MASK) >> PIPE_INTERLEAVE_SIZE_SHIFT) << 8;
index 637280f541a38492e8a0289e209285e0bb518aaf..d79c639ae739cf68a35039d4ca94357d423c534a 100644 (file)
@@ -3789,3 +3789,23 @@ static void r600_pcie_gen2_enable(struct radeon_device *rdev)
                WREG32_PCIE_P(PCIE_LC_LINK_WIDTH_CNTL, link_width_cntl);
        }
 }
+
+/**
+ * r600_get_gpu_clock - return GPU clock counter snapshot
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Fetches a GPU clock counter snapshot (R6xx-cayman).
+ * Returns the 64 bit clock counter snapshot.
+ */
+uint64_t r600_get_gpu_clock(struct radeon_device *rdev)
+{
+       uint64_t clock;
+
+       mutex_lock(&rdev->gpu_clock_mutex);
+       WREG32(RLC_CAPTURE_GPU_CLOCK_COUNT, 1);
+       clock = (uint64_t)RREG32(RLC_GPU_CLOCK_COUNT_LSB) |
+               ((uint64_t)RREG32(RLC_GPU_CLOCK_COUNT_MSB) << 32ULL);
+       mutex_unlock(&rdev->gpu_clock_mutex);
+       return clock;
+}
index ca87f7afaf2374d02117ec91e479c1e5a385b8d2..3dab49cb1d4a6455b517c118719ef0a08ede5f84 100644 (file)
@@ -764,8 +764,10 @@ static int r600_cs_track_check(struct radeon_cs_parser *p)
        }
 
        /* Check depth buffer */
-       if (track->db_dirty && (G_028800_STENCIL_ENABLE(track->db_depth_control) ||
-               G_028800_Z_ENABLE(track->db_depth_control))) {
+       if (track->db_dirty &&
+           G_028010_FORMAT(track->db_depth_info) != V_028010_DEPTH_INVALID &&
+           (G_028800_STENCIL_ENABLE(track->db_depth_control) ||
+            G_028800_Z_ENABLE(track->db_depth_control))) {
                r = r600_cs_track_validate_db(p);
                if (r)
                        return r;
@@ -1557,13 +1559,14 @@ static int r600_check_texture_resource(struct radeon_cs_parser *p,  u32 idx,
                                              u32 tiling_flags)
 {
        struct r600_cs_track *track = p->track;
-       u32 nfaces, llevel, blevel, w0, h0, d0;
-       u32 word0, word1, l0_size, mipmap_size, word2, word3;
+       u32 dim, nfaces, llevel, blevel, w0, h0, d0;
+       u32 word0, word1, l0_size, mipmap_size, word2, word3, word4, word5;
        u32 height_align, pitch, pitch_align, depth_align;
-       u32 array, barray, larray;
+       u32 barray, larray;
        u64 base_align;
        struct array_mode_checker array_check;
        u32 format;
+       bool is_array;
 
        /* on legacy kernel we don't perform advanced check */
        if (p->rdev == NULL)
@@ -1581,12 +1584,28 @@ static int r600_check_texture_resource(struct radeon_cs_parser *p,  u32 idx,
                        word0 |= S_038000_TILE_MODE(V_038000_ARRAY_1D_TILED_THIN1);
        }
        word1 = radeon_get_ib_value(p, idx + 1);
+       word2 = radeon_get_ib_value(p, idx + 2) << 8;
+       word3 = radeon_get_ib_value(p, idx + 3) << 8;
+       word4 = radeon_get_ib_value(p, idx + 4);
+       word5 = radeon_get_ib_value(p, idx + 5);
+       dim = G_038000_DIM(word0);
        w0 = G_038000_TEX_WIDTH(word0) + 1;
+       pitch = (G_038000_PITCH(word0) + 1) * 8;
        h0 = G_038004_TEX_HEIGHT(word1) + 1;
        d0 = G_038004_TEX_DEPTH(word1);
+       format = G_038004_DATA_FORMAT(word1);
+       blevel = G_038010_BASE_LEVEL(word4);
+       llevel = G_038014_LAST_LEVEL(word5);
+       /* pitch in texels */
+       array_check.array_mode = G_038000_TILE_MODE(word0);
+       array_check.group_size = track->group_size;
+       array_check.nbanks = track->nbanks;
+       array_check.npipes = track->npipes;
+       array_check.nsamples = 1;
+       array_check.blocksize = r600_fmt_get_blocksize(format);
        nfaces = 1;
-       array = 0;
-       switch (G_038000_DIM(word0)) {
+       is_array = false;
+       switch (dim) {
        case V_038000_SQ_TEX_DIM_1D:
        case V_038000_SQ_TEX_DIM_2D:
        case V_038000_SQ_TEX_DIM_3D:
@@ -1599,29 +1618,25 @@ static int r600_check_texture_resource(struct radeon_cs_parser *p,  u32 idx,
                break;
        case V_038000_SQ_TEX_DIM_1D_ARRAY:
        case V_038000_SQ_TEX_DIM_2D_ARRAY:
-               array = 1;
+               is_array = true;
                break;
-       case V_038000_SQ_TEX_DIM_2D_MSAA:
        case V_038000_SQ_TEX_DIM_2D_ARRAY_MSAA:
+               is_array = true;
+               /* fall through */
+       case V_038000_SQ_TEX_DIM_2D_MSAA:
+               array_check.nsamples = 1 << llevel;
+               llevel = 0;
+               break;
        default:
                dev_warn(p->dev, "this kernel doesn't support %d texture dim\n", G_038000_DIM(word0));
                return -EINVAL;
        }
-       format = G_038004_DATA_FORMAT(word1);
        if (!r600_fmt_is_valid_texture(format, p->family)) {
                dev_warn(p->dev, "%s:%d texture invalid format %d\n",
                         __func__, __LINE__, format);
                return -EINVAL;
        }
 
-       /* pitch in texels */
-       pitch = (G_038000_PITCH(word0) + 1) * 8;
-       array_check.array_mode = G_038000_TILE_MODE(word0);
-       array_check.group_size = track->group_size;
-       array_check.nbanks = track->nbanks;
-       array_check.npipes = track->npipes;
-       array_check.nsamples = 1;
-       array_check.blocksize = r600_fmt_get_blocksize(format);
        if (r600_get_array_mode_alignment(&array_check,
                                          &pitch_align, &height_align, &depth_align, &base_align)) {
                dev_warn(p->dev, "%s:%d tex array mode (%d) invalid\n",
@@ -1647,20 +1662,13 @@ static int r600_check_texture_resource(struct radeon_cs_parser *p,  u32 idx,
                return -EINVAL;
        }
 
-       word2 = radeon_get_ib_value(p, idx + 2) << 8;
-       word3 = radeon_get_ib_value(p, idx + 3) << 8;
-
-       word0 = radeon_get_ib_value(p, idx + 4);
-       word1 = radeon_get_ib_value(p, idx + 5);
-       blevel = G_038010_BASE_LEVEL(word0);
-       llevel = G_038014_LAST_LEVEL(word1);
        if (blevel > llevel) {
                dev_warn(p->dev, "texture blevel %d > llevel %d\n",
                         blevel, llevel);
        }
-       if (array == 1) {
-               barray = G_038014_BASE_ARRAY(word1);
-               larray = G_038014_LAST_ARRAY(word1);
+       if (is_array) {
+               barray = G_038014_BASE_ARRAY(word5);
+               larray = G_038014_LAST_ARRAY(word5);
 
                nfaces = larray - barray + 1;
        }
@@ -1677,7 +1685,6 @@ static int r600_check_texture_resource(struct radeon_cs_parser *p,  u32 idx,
                return -EINVAL;
        }
        /* using get ib will give us the offset into the mipmap bo */
-       word3 = radeon_get_ib_value(p, idx + 3) << 8;
        if ((mipmap_size + word3) > radeon_bo_size(mipmap)) {
                /*dev_warn(p->dev, "mipmap bo too small (%d %d %d %d %d %d -> %d have %ld)\n",
                  w0, h0, format, blevel, nlevels, word3, mipmap_size, radeon_bo_size(texture));*/
index 4b116ae75fc2cedd41b2e446f1a421b7a085d81b..fd328f4c3ea82a98c3684e0bf3f223ce7606b7b9 100644 (file)
 #define RLC_HB_WPTR                                       0x3f1c
 #define RLC_HB_WPTR_LSB_ADDR                              0x3f14
 #define RLC_HB_WPTR_MSB_ADDR                              0x3f18
+#define RLC_GPU_CLOCK_COUNT_LSB                                  0x3f38
+#define RLC_GPU_CLOCK_COUNT_MSB                                  0x3f3c
+#define RLC_CAPTURE_GPU_CLOCK_COUNT                      0x3f40
 #define RLC_MC_CNTL                                       0x3f44
 #define RLC_UCODE_CNTL                                    0x3f48
 #define RLC_UCODE_ADDR                                    0x3f2c
index 5431af2924083676e7f017d13d2f32a4b9cc1aca..99304194a65c807b044cfd2796bf8247da3cbf22 100644 (file)
@@ -300,6 +300,7 @@ struct radeon_bo_va {
        uint64_t                        soffset;
        uint64_t                        eoffset;
        uint32_t                        flags;
+       struct radeon_fence             *fence;
        bool                            valid;
 };
 
@@ -1533,6 +1534,7 @@ struct radeon_device {
        unsigned                debugfs_count;
        /* virtual memory */
        struct radeon_vm_manager        vm_manager;
+       struct mutex                    gpu_clock_mutex;
 };
 
 int radeon_device_init(struct radeon_device *rdev,
@@ -1733,11 +1735,11 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v);
 #define radeon_pm_finish(rdev) (rdev)->asic->pm.finish((rdev))
 #define radeon_pm_init_profile(rdev) (rdev)->asic->pm.init_profile((rdev))
 #define radeon_pm_get_dynpm_state(rdev) (rdev)->asic->pm.get_dynpm_state((rdev))
-#define radeon_pre_page_flip(rdev, crtc) rdev->asic->pflip.pre_page_flip((rdev), (crtc))
-#define radeon_page_flip(rdev, crtc, base) rdev->asic->pflip.page_flip((rdev), (crtc), (base))
-#define radeon_post_page_flip(rdev, crtc) rdev->asic->pflip.post_page_flip((rdev), (crtc))
-#define radeon_wait_for_vblank(rdev, crtc) rdev->asic->display.wait_for_vblank((rdev), (crtc))
-#define radeon_mc_wait_for_idle(rdev) rdev->asic->mc_wait_for_idle((rdev))
+#define radeon_pre_page_flip(rdev, crtc) (rdev)->asic->pflip.pre_page_flip((rdev), (crtc))
+#define radeon_page_flip(rdev, crtc, base) (rdev)->asic->pflip.page_flip((rdev), (crtc), (base))
+#define radeon_post_page_flip(rdev, crtc) (rdev)->asic->pflip.post_page_flip((rdev), (crtc))
+#define radeon_wait_for_vblank(rdev, crtc) (rdev)->asic->display.wait_for_vblank((rdev), (crtc))
+#define radeon_mc_wait_for_idle(rdev) (rdev)->asic->mc_wait_for_idle((rdev))
 
 /* Common functions */
 /* AGP */
index f4af243104387b752638b62809c876970b16ce76..18c38d14c8cd88c70499f2eb03d8a282ca3d68b9 100644 (file)
@@ -255,13 +255,10 @@ extern int rs690_mc_wait_for_idle(struct radeon_device *rdev);
  * rv515
  */
 struct rv515_mc_save {
-       u32 d1vga_control;
-       u32 d2vga_control;
        u32 vga_render_control;
        u32 vga_hdp_control;
-       u32 d1crtc_control;
-       u32 d2crtc_control;
 };
+
 int rv515_init(struct radeon_device *rdev);
 void rv515_fini(struct radeon_device *rdev);
 uint32_t rv515_mc_rreg(struct radeon_device *rdev, uint32_t reg);
@@ -371,6 +368,7 @@ void r600_kms_blit_copy(struct radeon_device *rdev,
                        unsigned num_gpu_pages,
                        struct radeon_sa_bo *vb);
 int r600_mc_wait_for_idle(struct radeon_device *rdev);
+uint64_t r600_get_gpu_clock(struct radeon_device *rdev);
 
 /*
  * rv770,rv730,rv710,rv740
@@ -389,11 +387,10 @@ void r700_cp_fini(struct radeon_device *rdev);
  * evergreen
  */
 struct evergreen_mc_save {
-       u32 vga_control[6];
        u32 vga_render_control;
        u32 vga_hdp_control;
-       u32 crtc_control[6];
 };
+
 void evergreen_pcie_gart_tlb_flush(struct radeon_device *rdev);
 int evergreen_init(struct radeon_device *rdev);
 void evergreen_fini(struct radeon_device *rdev);
@@ -472,5 +469,6 @@ int si_vm_bind(struct radeon_device *rdev, struct radeon_vm *vm, int id);
 void si_vm_unbind(struct radeon_device *rdev, struct radeon_vm *vm);
 void si_vm_tlb_flush(struct radeon_device *rdev, struct radeon_vm *vm);
 int si_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib);
+uint64_t si_get_gpu_clock(struct radeon_device *rdev);
 
 #endif
index b1e3820df36397e9c2ad7a7798be5412c0853df2..f9c21f9d16bc470b44542103793d25e4d73969bc 100644 (file)
@@ -1263,6 +1263,8 @@ bool radeon_atom_get_clock_info(struct drm_device *dev)
 union igp_info {
        struct _ATOM_INTEGRATED_SYSTEM_INFO info;
        struct _ATOM_INTEGRATED_SYSTEM_INFO_V2 info_2;
+       struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 info_6;
+       struct _ATOM_INTEGRATED_SYSTEM_INFO_V1_7 info_7;
 };
 
 bool radeon_atombios_sideport_present(struct radeon_device *rdev)
@@ -1390,27 +1392,50 @@ static void radeon_atombios_get_igp_ss_overrides(struct radeon_device *rdev,
        struct radeon_mode_info *mode_info = &rdev->mode_info;
        int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
        u16 data_offset, size;
-       struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 *igp_info;
+       union igp_info *igp_info;
        u8 frev, crev;
        u16 percentage = 0, rate = 0;
 
        /* get any igp specific overrides */
        if (atom_parse_data_header(mode_info->atom_context, index, &size,
                                   &frev, &crev, &data_offset)) {
-               igp_info = (struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 *)
+               igp_info = (union igp_info *)
                        (mode_info->atom_context->bios + data_offset);
-               switch (id) {
-               case ASIC_INTERNAL_SS_ON_TMDS:
-                       percentage = le16_to_cpu(igp_info->usDVISSPercentage);
-                       rate = le16_to_cpu(igp_info->usDVISSpreadRateIn10Hz);
+               switch (crev) {
+               case 6:
+                       switch (id) {
+                       case ASIC_INTERNAL_SS_ON_TMDS:
+                               percentage = le16_to_cpu(igp_info->info_6.usDVISSPercentage);
+                               rate = le16_to_cpu(igp_info->info_6.usDVISSpreadRateIn10Hz);
+                               break;
+                       case ASIC_INTERNAL_SS_ON_HDMI:
+                               percentage = le16_to_cpu(igp_info->info_6.usHDMISSPercentage);
+                               rate = le16_to_cpu(igp_info->info_6.usHDMISSpreadRateIn10Hz);
+                               break;
+                       case ASIC_INTERNAL_SS_ON_LVDS:
+                               percentage = le16_to_cpu(igp_info->info_6.usLvdsSSPercentage);
+                               rate = le16_to_cpu(igp_info->info_6.usLvdsSSpreadRateIn10Hz);
+                               break;
+                       }
                        break;
-               case ASIC_INTERNAL_SS_ON_HDMI:
-                       percentage = le16_to_cpu(igp_info->usHDMISSPercentage);
-                       rate = le16_to_cpu(igp_info->usHDMISSpreadRateIn10Hz);
+               case 7:
+                       switch (id) {
+                       case ASIC_INTERNAL_SS_ON_TMDS:
+                               percentage = le16_to_cpu(igp_info->info_7.usDVISSPercentage);
+                               rate = le16_to_cpu(igp_info->info_7.usDVISSpreadRateIn10Hz);
+                               break;
+                       case ASIC_INTERNAL_SS_ON_HDMI:
+                               percentage = le16_to_cpu(igp_info->info_7.usHDMISSPercentage);
+                               rate = le16_to_cpu(igp_info->info_7.usHDMISSpreadRateIn10Hz);
+                               break;
+                       case ASIC_INTERNAL_SS_ON_LVDS:
+                               percentage = le16_to_cpu(igp_info->info_7.usLvdsSSPercentage);
+                               rate = le16_to_cpu(igp_info->info_7.usLvdsSSpreadRateIn10Hz);
+                               break;
+                       }
                        break;
-               case ASIC_INTERNAL_SS_ON_LVDS:
-                       percentage = le16_to_cpu(igp_info->usLvdsSSPercentage);
-                       rate = le16_to_cpu(igp_info->usLvdsSSpreadRateIn10Hz);
+               default:
+                       DRM_ERROR("Unsupported IGP table: %d %d\n", frev, crev);
                        break;
                }
                if (percentage)
index 576f4f6919f28d075ba0e77365d0a0cc52814f25..f75247d42ffdca3bd62e778f51bba1c6b6d6ab78 100644 (file)
@@ -719,6 +719,34 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde
        return i2c;
 }
 
+static struct radeon_i2c_bus_rec radeon_combios_get_i2c_info_from_table(struct radeon_device *rdev)
+{
+       struct drm_device *dev = rdev->ddev;
+       struct radeon_i2c_bus_rec i2c;
+       u16 offset;
+       u8 id, blocks, clk, data;
+       int i;
+
+       i2c.valid = false;
+
+       offset = combios_get_table_offset(dev, COMBIOS_I2C_INFO_TABLE);
+       if (offset) {
+               blocks = RBIOS8(offset + 2);
+               for (i = 0; i < blocks; i++) {
+                       id = RBIOS8(offset + 3 + (i * 5) + 0);
+                       if (id == 136) {
+                               clk = RBIOS8(offset + 3 + (i * 5) + 3);
+                               data = RBIOS8(offset + 3 + (i * 5) + 4);
+                               /* gpiopad */
+                               i2c = combios_setup_i2c_bus(rdev, DDC_MONID,
+                                                           (1 << clk), (1 << data));
+                               break;
+                       }
+               }
+       }
+       return i2c;
+}
+
 void radeon_combios_i2c_init(struct radeon_device *rdev)
 {
        struct drm_device *dev = rdev->ddev;
@@ -755,30 +783,14 @@ void radeon_combios_i2c_init(struct radeon_device *rdev)
        } else if (rdev->family == CHIP_RS300 ||
                   rdev->family == CHIP_RS400 ||
                   rdev->family == CHIP_RS480) {
-               u16 offset;
-               u8 id, blocks, clk, data;
-               int i;
-
                /* 0x68 */
                i2c = combios_setup_i2c_bus(rdev, DDC_CRT2, 0, 0);
                rdev->i2c_bus[3] = radeon_i2c_create(dev, &i2c, "MONID");
 
-               offset = combios_get_table_offset(dev, COMBIOS_I2C_INFO_TABLE);
-               if (offset) {
-                       blocks = RBIOS8(offset + 2);
-                       for (i = 0; i < blocks; i++) {
-                               id = RBIOS8(offset + 3 + (i * 5) + 0);
-                               if (id == 136) {
-                                       clk = RBIOS8(offset + 3 + (i * 5) + 3);
-                                       data = RBIOS8(offset + 3 + (i * 5) + 4);
-                                       /* gpiopad */
-                                       i2c = combios_setup_i2c_bus(rdev, DDC_MONID,
-                                                                   (1 << clk), (1 << data));
-                                       rdev->i2c_bus[4] = radeon_i2c_create(dev, &i2c, "GPIOPAD_MASK");
-                                       break;
-                               }
-                       }
-               }
+               /* gpiopad */
+               i2c = radeon_combios_get_i2c_info_from_table(rdev);
+               if (i2c.valid)
+                       rdev->i2c_bus[4] = radeon_i2c_create(dev, &i2c, "GPIOPAD_MASK");
        } else if ((rdev->family == CHIP_R200) ||
                   (rdev->family >= CHIP_R300)) {
                /* 0x68 */
@@ -2321,7 +2333,10 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
                        connector = (tmp >> 12) & 0xf;
 
                        ddc_type = (tmp >> 8) & 0xf;
-                       ddc_i2c = combios_setup_i2c_bus(rdev, ddc_type, 0, 0);
+                       if (ddc_type == 5)
+                               ddc_i2c = radeon_combios_get_i2c_info_from_table(rdev);
+                       else
+                               ddc_i2c = combios_setup_i2c_bus(rdev, ddc_type, 0, 0);
 
                        switch (connector) {
                        case CONNECTOR_PROPRIETARY_LEGACY:
index 8a4c49ef0cc4e40170b3300aa7ad9cffeea2bc72..b4a0db24f4ddc4611028b671499d5062bd713649 100644 (file)
@@ -278,6 +278,30 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)
        return 0;
 }
 
+static void radeon_bo_vm_fence_va(struct radeon_cs_parser *parser,
+                                 struct radeon_fence *fence)
+{
+       struct radeon_fpriv *fpriv = parser->filp->driver_priv;
+       struct radeon_vm *vm = &fpriv->vm;
+       struct radeon_bo_list *lobj;
+
+       if (parser->chunk_ib_idx == -1) {
+               return;
+       }
+       if ((parser->cs_flags & RADEON_CS_USE_VM) == 0) {
+               return;
+       }
+
+       list_for_each_entry(lobj, &parser->validated, tv.head) {
+               struct radeon_bo_va *bo_va;
+               struct radeon_bo *rbo = lobj->bo;
+
+               bo_va = radeon_bo_va(rbo, vm);
+               radeon_fence_unref(&bo_va->fence);
+               bo_va->fence = radeon_fence_ref(fence);
+       }
+}
+
 /**
  * cs_parser_fini() - clean parser states
  * @parser:    parser structure holding parsing context.
@@ -290,11 +314,14 @@ static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error)
 {
        unsigned i;
 
-       if (!error)
+       if (!error) {
+               /* fence all bo va before ttm_eu_fence_buffer_objects so bo are still reserved */
+               radeon_bo_vm_fence_va(parser, parser->ib.fence);
                ttm_eu_fence_buffer_objects(&parser->validated,
                                            parser->ib.fence);
-       else
+       } else {
                ttm_eu_backoff_reservation(&parser->validated);
+       }
 
        if (parser->relocs != NULL) {
                for (i = 0; i < parser->nrelocs; i++) {
@@ -388,7 +415,6 @@ static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev,
 
        if (parser->chunk_ib_idx == -1)
                return 0;
-
        if ((parser->cs_flags & RADEON_CS_USE_VM) == 0)
                return 0;
 
index 711e95ad39bfd600de1be7f94373dc57512ef820..8794744cdf1a58c1c14cb5c0d59dc595f80d05be 100644 (file)
@@ -67,7 +67,8 @@ static void radeon_hide_cursor(struct drm_crtc *crtc)
 
        if (ASIC_IS_DCE4(rdev)) {
                WREG32(RADEON_MM_INDEX, EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset);
-               WREG32(RADEON_MM_DATA, EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT));
+               WREG32(RADEON_MM_DATA, EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) |
+                      EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2));
        } else if (ASIC_IS_AVIVO(rdev)) {
                WREG32(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset);
                WREG32(RADEON_MM_DATA, (AVIVO_D1CURSOR_MODE_24BPP << AVIVO_D1CURSOR_MODE_SHIFT));
@@ -94,7 +95,8 @@ static void radeon_show_cursor(struct drm_crtc *crtc)
        if (ASIC_IS_DCE4(rdev)) {
                WREG32(RADEON_MM_INDEX, EVERGREEN_CUR_CONTROL + radeon_crtc->crtc_offset);
                WREG32(RADEON_MM_DATA, EVERGREEN_CURSOR_EN |
-                      EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT));
+                      EVERGREEN_CURSOR_MODE(EVERGREEN_CURSOR_24_8_PRE_MULT) |
+                      EVERGREEN_CURSOR_URGENT_CONTROL(EVERGREEN_CURSOR_URGENT_1_2));
        } else if (ASIC_IS_AVIVO(rdev)) {
                WREG32(RADEON_MM_INDEX, AVIVO_D1CUR_CONTROL + radeon_crtc->crtc_offset);
                WREG32(RADEON_MM_DATA, AVIVO_D1CURSOR_EN |
index 742af8244e898e565aed6bb9fa6dcffe1521dd98..d2e243867ac6f3c9fe4d6c28e25fa421cac6c48b 100644 (file)
@@ -1009,6 +1009,7 @@ int radeon_device_init(struct radeon_device *rdev,
        atomic_set(&rdev->ih.lock, 0);
        mutex_init(&rdev->gem.mutex);
        mutex_init(&rdev->pm.mutex);
+       mutex_init(&rdev->gpu_clock_mutex);
        init_rwsem(&rdev->pm.mclk_lock);
        init_rwsem(&rdev->exclusive_lock);
        init_waitqueue_head(&rdev->irq.vblank_queue);
index dcea6f01ae4e2ec3fe60def4a345c2528d3fedc9..d7269f48d37cc7116ffb00764abdd34326257192 100644 (file)
  *   2.15.0 - add max_pipes query
  *   2.16.0 - fix evergreen 2D tiled surface calculation
  *   2.17.0 - add STRMOUT_BASE_UPDATE for r7xx
+ *   2.18.0 - r600-eg: allow "invalid" DB formats
+ *   2.19.0 - r600-eg: MSAA textures
+ *   2.20.0 - r600-si: RADEON_INFO_TIMESTAMP query
  */
 #define KMS_DRIVER_MAJOR       2
-#define KMS_DRIVER_MINOR       17
+#define KMS_DRIVER_MINOR       20
 #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);
index b3720054614db5199684ad1d86924a1fd5c8f34d..bb3b7fe05ccdfe2905b9dc6650e854e6361dec8c 100644 (file)
@@ -814,7 +814,7 @@ int radeon_vm_bo_update_pte(struct radeon_device *rdev,
                return -EINVAL;
        }
 
-       if (bo_va->valid)
+       if (bo_va->valid && mem)
                return 0;
 
        ngpu_pages = radeon_bo_ngpu_pages(bo);
@@ -859,11 +859,27 @@ int radeon_vm_bo_rmv(struct radeon_device *rdev,
                     struct radeon_bo *bo)
 {
        struct radeon_bo_va *bo_va;
+       int r;
 
        bo_va = radeon_bo_va(bo, vm);
        if (bo_va == NULL)
                return 0;
 
+       /* wait for va use to end */
+       while (bo_va->fence) {
+               r = radeon_fence_wait(bo_va->fence, false);
+               if (r) {
+                       DRM_ERROR("error while waiting for fence: %d\n", r);
+               }
+               if (r == -EDEADLK) {
+                       r = radeon_gpu_reset(rdev);
+                       if (!r)
+                               continue;
+               }
+               break;
+       }
+       radeon_fence_unref(&bo_va->fence);
+
        mutex_lock(&rdev->vm_manager.lock);
        mutex_lock(&vm->mutex);
        radeon_vm_bo_update_pte(rdev, vm, bo, NULL);
@@ -934,7 +950,7 @@ int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm)
 }
 
 /**
- * radeon_vm_init - tear down a vm instance
+ * radeon_vm_fini - tear down a vm instance
  *
  * @rdev: radeon_device pointer
  * @vm: requested vm
@@ -952,12 +968,15 @@ void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm)
        radeon_vm_unbind_locked(rdev, vm);
        mutex_unlock(&rdev->vm_manager.lock);
 
-       /* remove all bo */
+       /* remove all bo at this point non are busy any more because unbind
+        * waited for the last vm fence to signal
+        */
        r = radeon_bo_reserve(rdev->ring_tmp_bo.bo, false);
        if (!r) {
                bo_va = radeon_bo_va(rdev->ring_tmp_bo.bo, vm);
                list_del_init(&bo_va->bo_list);
                list_del_init(&bo_va->vm_list);
+               radeon_fence_unref(&bo_va->fence);
                radeon_bo_unreserve(rdev->ring_tmp_bo.bo);
                kfree(bo_va);
        }
@@ -969,6 +988,7 @@ void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm)
                r = radeon_bo_reserve(bo_va->bo, false);
                if (!r) {
                        list_del_init(&bo_va->bo_list);
+                       radeon_fence_unref(&bo_va->fence);
                        radeon_bo_unreserve(bo_va->bo);
                        kfree(bo_va);
                }
index 84d045245739eb3b049e78f88693d6dc1dd229da..1b57b0058ad642e6d0d610dadbf7af235f517c71 100644 (file)
@@ -134,25 +134,16 @@ void radeon_gem_object_close(struct drm_gem_object *obj,
        struct radeon_device *rdev = rbo->rdev;
        struct radeon_fpriv *fpriv = file_priv->driver_priv;
        struct radeon_vm *vm = &fpriv->vm;
-       struct radeon_bo_va *bo_va, *tmp;
 
        if (rdev->family < CHIP_CAYMAN) {
                return;
        }
 
        if (radeon_bo_reserve(rbo, false)) {
+               dev_err(rdev->dev, "leaking bo va because we fail to reserve bo\n");
                return;
        }
-       list_for_each_entry_safe(bo_va, tmp, &rbo->va, bo_list) {
-               if (bo_va->vm == vm) {
-                       /* remove from this vm address space */
-                       mutex_lock(&vm->mutex);
-                       list_del(&bo_va->vm_list);
-                       mutex_unlock(&vm->mutex);
-                       list_del(&bo_va->bo_list);
-                       kfree(bo_va);
-               }
-       }
+       radeon_vm_bo_rmv(rdev, vm, rbo);
        radeon_bo_unreserve(rbo);
 }
 
index 1d73f16b5d97d4b480d18cf3831e134f66fa5e29..414b4acf69479abdfdcda63f226d112c0e3387da 100644 (file)
@@ -29,6 +29,7 @@
 #include "drm_sarea.h"
 #include "radeon.h"
 #include "radeon_drm.h"
+#include "radeon_asic.h"
 
 #include <linux/vga_switcheroo.h>
 #include <linux/slab.h>
@@ -167,17 +168,39 @@ static void radeon_set_filp_rights(struct drm_device *dev,
 int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
 {
        struct radeon_device *rdev = dev->dev_private;
-       struct drm_radeon_info *info;
+       struct drm_radeon_info *info = data;
        struct radeon_mode_info *minfo = &rdev->mode_info;
-       uint32_t *value_ptr;
-       uint32_t value;
+       uint32_t value, *value_ptr;
+       uint64_t value64, *value_ptr64;
        struct drm_crtc *crtc;
        int i, found;
 
-       info = data;
+       /* TIMESTAMP is a 64-bit value, needs special handling. */
+       if (info->request == RADEON_INFO_TIMESTAMP) {
+               if (rdev->family >= CHIP_R600) {
+                       value_ptr64 = (uint64_t*)((unsigned long)info->value);
+                       if (rdev->family >= CHIP_TAHITI) {
+                               value64 = si_get_gpu_clock(rdev);
+                       } else {
+                               value64 = r600_get_gpu_clock(rdev);
+                       }
+
+                       if (DRM_COPY_TO_USER(value_ptr64, &value64, sizeof(value64))) {
+                               DRM_ERROR("copy_to_user %s:%u\n", __func__, __LINE__);
+                               return -EFAULT;
+                       }
+                       return 0;
+               } else {
+                       DRM_DEBUG_KMS("timestamp is r6xx+ only!\n");
+                       return -EINVAL;
+               }
+       }
+
        value_ptr = (uint32_t *)((unsigned long)info->value);
-       if (DRM_COPY_FROM_USER(&value, value_ptr, sizeof(value)))
+       if (DRM_COPY_FROM_USER(&value, value_ptr, sizeof(value))) {
+               DRM_ERROR("copy_from_user %s:%u\n", __func__, __LINE__);
                return -EFAULT;
+       }
 
        switch (info->request) {
        case RADEON_INFO_DEVICE_ID:
@@ -337,7 +360,7 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
                return -EINVAL;
        }
        if (DRM_COPY_TO_USER(value_ptr, &value, sizeof(uint32_t))) {
-               DRM_ERROR("copy_to_user\n");
+               DRM_ERROR("copy_to_user %s:%u\n", __func__, __LINE__);
                return -EFAULT;
        }
        return 0;
index d5fd615897ec75ad13d8b1b1e7ddd1e85a1a859b..94b4a1c12893baab8ce72854661ed443fea1cfe0 100644 (file)
@@ -1025,9 +1025,11 @@ static int radeon_crtc_mode_set(struct drm_crtc *crtc,
 
 static void radeon_crtc_prepare(struct drm_crtc *crtc)
 {
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
        struct drm_device *dev = crtc->dev;
        struct drm_crtc *crtci;
 
+       radeon_crtc->in_mode_set = true;
        /*
        * The hardware wedges sometimes if you reconfigure one CRTC
        * whilst another is running (see fdo bug #24611).
@@ -1038,6 +1040,7 @@ static void radeon_crtc_prepare(struct drm_crtc *crtc)
 
 static void radeon_crtc_commit(struct drm_crtc *crtc)
 {
+       struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
        struct drm_device *dev = crtc->dev;
        struct drm_crtc *crtci;
 
@@ -1048,6 +1051,7 @@ static void radeon_crtc_commit(struct drm_crtc *crtc)
                if (crtci->enabled)
                        radeon_crtc_dpms(crtci, DRM_MODE_DPMS_ON);
        }
+       radeon_crtc->in_mode_set = false;
 }
 
 static const struct drm_crtc_helper_funcs legacy_helper_funcs = {
index f380d59c5763425f0fc0bd79a8733d15bcfdca33..d56978949f34927169cf3db6a832361f2139cb4b 100644 (file)
@@ -275,6 +275,7 @@ struct radeon_crtc {
        u16 lut_r[256], lut_g[256], lut_b[256];
        bool enabled;
        bool can_tile;
+       bool in_mode_set;
        uint32_t crtc_offset;
        struct drm_gem_object *cursor_bo;
        uint64_t cursor_addr;
index 1f1a4c803c1dd267158dece882e8fdf5b2d6b871..1cb014b571ab93d2479f4456de93e6c4c672f1c4 100644 (file)
@@ -52,11 +52,7 @@ void radeon_bo_clear_va(struct radeon_bo *bo)
 
        list_for_each_entry_safe(bo_va, tmp, &bo->va, bo_list) {
                /* remove from all vm address space */
-               mutex_lock(&bo_va->vm->mutex);
-               list_del(&bo_va->vm_list);
-               mutex_unlock(&bo_va->vm->mutex);
-               list_del(&bo_va->bo_list);
-               kfree(bo_va);
+               radeon_vm_bo_rmv(bo->rdev, bo_va->vm, bo);
        }
 }
 
index a12fbcc8ccb6834a9fba7b0d5cb08418538b52e9..aa8ef491ef3c17619ee9f1e64dd8262c5e74e103 100644 (file)
@@ -281,12 +281,8 @@ int rv515_debugfs_ga_info_init(struct radeon_device *rdev)
 
 void rv515_mc_stop(struct radeon_device *rdev, struct rv515_mc_save *save)
 {
-       save->d1vga_control = RREG32(R_000330_D1VGA_CONTROL);
-       save->d2vga_control = RREG32(R_000338_D2VGA_CONTROL);
        save->vga_render_control = RREG32(R_000300_VGA_RENDER_CONTROL);
        save->vga_hdp_control = RREG32(R_000328_VGA_HDP_CONTROL);
-       save->d1crtc_control = RREG32(R_006080_D1CRTC_CONTROL);
-       save->d2crtc_control = RREG32(R_006880_D2CRTC_CONTROL);
 
        /* Stop all video */
        WREG32(R_0068E8_D2CRTC_UPDATE_LOCK, 0);
@@ -311,15 +307,6 @@ void rv515_mc_resume(struct radeon_device *rdev, struct rv515_mc_save *save)
        /* Unlock host access */
        WREG32(R_000328_VGA_HDP_CONTROL, save->vga_hdp_control);
        mdelay(1);
-       /* Restore video state */
-       WREG32(R_000330_D1VGA_CONTROL, save->d1vga_control);
-       WREG32(R_000338_D2VGA_CONTROL, save->d2vga_control);
-       WREG32(R_0060E8_D1CRTC_UPDATE_LOCK, 1);
-       WREG32(R_0068E8_D2CRTC_UPDATE_LOCK, 1);
-       WREG32(R_006080_D1CRTC_CONTROL, save->d1crtc_control);
-       WREG32(R_006880_D2CRTC_CONTROL, save->d2crtc_control);
-       WREG32(R_0060E8_D1CRTC_UPDATE_LOCK, 0);
-       WREG32(R_0068E8_D2CRTC_UPDATE_LOCK, 0);
        WREG32(R_000300_VGA_RENDER_CONTROL, save->vga_render_control);
 }
 
index c053f8193771a1df17cfa092cabf15caaff880db..0139e227e3c7241712c5ed951f38b52f5120c564 100644 (file)
@@ -1639,11 +1639,19 @@ static void si_gpu_init(struct radeon_device *rdev)
                /* XXX what about 12? */
                rdev->config.si.tile_config |= (3 << 0);
                break;
-       }
-       if ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT)
-               rdev->config.si.tile_config |= 1 << 4;
-       else
+       }       
+       switch ((mc_arb_ramcfg & NOOFBANK_MASK) >> NOOFBANK_SHIFT) {
+       case 0: /* four banks */
                rdev->config.si.tile_config |= 0 << 4;
+               break;
+       case 1: /* eight banks */
+               rdev->config.si.tile_config |= 1 << 4;
+               break;
+       case 2: /* sixteen banks */
+       default:
+               rdev->config.si.tile_config |= 2 << 4;
+               break;
+       }
        rdev->config.si.tile_config |=
                ((gb_addr_config & PIPE_INTERLEAVE_SIZE_MASK) >> PIPE_INTERLEAVE_SIZE_SHIFT) << 8;
        rdev->config.si.tile_config |=
@@ -3960,3 +3968,22 @@ void si_fini(struct radeon_device *rdev)
        rdev->bios = NULL;
 }
 
+/**
+ * si_get_gpu_clock - return GPU clock counter snapshot
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Fetches a GPU clock counter snapshot (SI).
+ * Returns the 64 bit clock counter snapshot.
+ */
+uint64_t si_get_gpu_clock(struct radeon_device *rdev)
+{
+       uint64_t clock;
+
+       mutex_lock(&rdev->gpu_clock_mutex);
+       WREG32(RLC_CAPTURE_GPU_CLOCK_COUNT, 1);
+       clock = (uint64_t)RREG32(RLC_GPU_CLOCK_COUNT_LSB) |
+               ((uint64_t)RREG32(RLC_GPU_CLOCK_COUNT_MSB) << 32ULL);
+       mutex_unlock(&rdev->gpu_clock_mutex);
+       return clock;
+}
index 7869089e87619562663ca96c1c035c74b7dba710..ef4815c27b1c673e50ab9d675382586686b6495d 100644 (file)
 #define RLC_UCODE_ADDR                                    0xC32C
 #define RLC_UCODE_DATA                                    0xC330
 
+#define RLC_GPU_CLOCK_COUNT_LSB                           0xC338
+#define RLC_GPU_CLOCK_COUNT_MSB                           0xC33C
+#define RLC_CAPTURE_GPU_CLOCK_COUNT                       0xC340
 #define RLC_MC_CNTL                                       0xC344
 #define RLC_UCODE_CNTL                                    0xC348
 
index 7bd65bdd15a8092e955d959c08fd6dd04781d490..291ecc1455850400f6e596cde59dfac1acda83d4 100644 (file)
@@ -308,7 +308,7 @@ struct drm_gem_object *udl_gem_prime_import(struct drm_device *dev,
        /* need to attach */
        attach = dma_buf_attach(dma_buf, dev->dev);
        if (IS_ERR(attach))
-               return ERR_PTR(PTR_ERR(attach));
+               return ERR_CAST(attach);
 
        sg = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
        if (IS_ERR(sg)) {
index fbf49503508d8aa79a5e0cc4c901b716bb1233b6..a451cdb0841a4f84c00846a8e8cbf4146f9c26a2 100644 (file)
@@ -527,6 +527,14 @@ config HID_PICOLCD_LEDS
        ---help---
          Provide access to PicoLCD's GPO pins via leds class.
 
+config HID_PICOLCD_CIR
+       bool "CIR via RC class" if EXPERT
+       default !EXPERT
+       depends on HID_PICOLCD
+       depends on HID_PICOLCD=RC_CORE || RC_CORE=y
+       ---help---
+         Provide access to PicoLCD's CIR interface via remote control (LIRC).
+
 config HID_PRIMAX
        tristate "Primax non-fully HID-compliant devices"
        depends on USB_HID
index f975485f88b29636a6f26afba0b463924b154b05..3684750c976e2a407b59435b44b13fa597cd0fa8 100644 (file)
@@ -69,6 +69,26 @@ obj-$(CONFIG_HID_PRODIKEYS)  += hid-prodikeys.o
 obj-$(CONFIG_HID_PANTHERLORD)  += hid-pl.o
 obj-$(CONFIG_HID_PETALYNX)     += hid-petalynx.o
 obj-$(CONFIG_HID_PICOLCD)      += hid-picolcd.o
+hid-picolcd-y                  += hid-picolcd_core.o
+ifdef CONFIG_HID_PICOLCD_FB
+hid-picolcd-y                  += hid-picolcd_fb.o
+endif
+ifdef CONFIG_HID_PICOLCD_BACKLIGHT
+hid-picolcd-y                  += hid-picolcd_backlight.o
+endif
+ifdef CONFIG_HID_PICOLCD_LCD
+hid-picolcd-y                  += hid-picolcd_lcd.o
+endif
+ifdef CONFIG_HID_PICOLCD_LEDS
+hid-picolcd-y                  += hid-picolcd_leds.o
+endif
+ifdef CONFIG_HID_PICOLCD_CIR
+hid-picolcd-y                  += hid-picolcd_cir.o
+endif
+ifdef CONFIG_DEBUG_FS
+hid-picolcd-y                  += hid-picolcd_debugfs.o
+endif
+
 obj-$(CONFIG_HID_PRIMAX)       += hid-primax.o
 obj-$(CONFIG_HID_ROCCAT)       += hid-roccat.o hid-roccat-common.o \
        hid-roccat-arvo.o hid-roccat-isku.o hid-roccat-kone.o \
index 60ea284407cea4d1f62db43a72b3e6cdbea47e31..2b9dd76fe6987f1408d491ed8b58d11924a1e306 100644 (file)
@@ -374,7 +374,7 @@ static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
 
        case HID_GLOBAL_ITEM_TAG_REPORT_SIZE:
                parser->global.report_size = item_udata(item);
-               if (parser->global.report_size > 96) {
+               if (parser->global.report_size > 128) {
                        hid_err(parser->device, "invalid report_size %d\n",
                                        parser->global.report_size);
                        return -1;
index 1dcb76ff51e340a2215d735bdde23e5c370bade0..2fb6605139819f9ff2e542d53ea1e51fe89bc2ff 100644 (file)
 #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72FA      0x72fa
 #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7302      0x7302
 #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7349      0x7349
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_73F7      0x73f7
 #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001      0xa001
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7224      0x7224
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72D0      0x72d0
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72C4      0x72c4
 
 #define USB_VENDOR_ID_ELECOM           0x056e
 #define USB_DEVICE_ID_ELECOM_BM084     0x0061
 #define USB_VENDOR_ID_EZKEY            0x0518
 #define USB_DEVICE_ID_BTC_8193         0x0002
 
+#define USB_VENDOR_ID_FREESCALE                0x15A2
+#define USB_DEVICE_ID_FREESCALE_MX28   0x004F
+
 #define USB_VENDOR_ID_FRUCTEL  0x25B6
 #define USB_DEVICE_ID_GAMETEL_MT_MODE  0x0002
 
index 59c8b5c1d2de62b9a1d5a910dfa7f3ad5e470c51..e170112e2b84f8ccbeedd7ce14a7d380e7d6051a 100644 (file)
@@ -691,12 +691,10 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
        struct mt_device *td;
        struct mt_class *mtclass = mt_classes; /* MT_CLS_DEFAULT */
 
-       if (id) {
-               for (i = 0; mt_classes[i].name ; i++) {
-                       if (id->driver_data == mt_classes[i].name) {
-                               mtclass = &(mt_classes[i]);
-                               break;
-                       }
+       for (i = 0; mt_classes[i].name ; i++) {
+               if (id->driver_data == mt_classes[i].name) {
+                       mtclass = &(mt_classes[i]);
+                       break;
                }
        }
 
@@ -767,6 +765,32 @@ static int mt_reset_resume(struct hid_device *hdev)
        mt_set_input_mode(hdev);
        return 0;
 }
+
+static int mt_resume(struct hid_device *hdev)
+{
+       struct usb_interface *intf;
+       struct usb_host_interface *interface;
+       struct usb_device *dev;
+
+       if (hdev->bus != BUS_USB)
+               return 0;
+
+       intf = to_usb_interface(hdev->dev.parent);
+       interface = intf->cur_altsetting;
+       dev = hid_to_usb_dev(hdev);
+
+       /* Some Elan legacy devices require SET_IDLE to be set on resume.
+        * It should be safe to send it to other devices too.
+        * Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */
+
+       usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+                       HID_REQ_SET_IDLE,
+                       USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+                       0, interface->desc.bInterfaceNumber,
+                       NULL, 0, USB_CTRL_SET_TIMEOUT);
+
+       return 0;
+}
 #endif
 
 static void mt_remove(struct hid_device *hdev)
@@ -883,9 +907,21 @@ static const struct hid_device_id mt_devices[] = {
        { .driver_data = MT_CLS_EGALAX_SERIAL,
                MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
                        USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7349) },
+       { .driver_data = MT_CLS_EGALAX_SERIAL,
+               MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
+                       USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_73F7) },
        { .driver_data = MT_CLS_EGALAX_SERIAL,
                MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
                        USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) },
+       { .driver_data = MT_CLS_EGALAX,
+               HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+                       USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7224) },
+       { .driver_data = MT_CLS_EGALAX,
+               HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+                       USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72D0) },
+       { .driver_data = MT_CLS_EGALAX,
+               HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+                       USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72C4) },
 
        /* Elo TouchSystems IntelliTouch Plus panel */
        { .driver_data = MT_CLS_DUAL_NSMU_CONTACTID,
@@ -1092,6 +1128,7 @@ static struct hid_driver mt_driver = {
        .event = mt_event,
 #ifdef CONFIG_PM
        .reset_resume = mt_reset_resume,
+       .resume = mt_resume,
 #endif
 };
 
diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c
deleted file mode 100644 (file)
index 27c8ebd..0000000
+++ /dev/null
@@ -1,2748 +0,0 @@
-/***************************************************************************
- *   Copyright (C) 2010 by Bruno Prémont <bonbons@linux-vserver.org>       *
- *                                                                         *
- *   Based on Logitech G13 driver (v0.4)                                   *
- *     Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu>   *
- *                                                                         *
- *   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.               *
- *                                                                         *
- *   This driver 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 software. If not see <http://www.gnu.org/licenses/>.  *
- ***************************************************************************/
-
-#include <linux/hid.h>
-#include <linux/hid-debug.h>
-#include <linux/input.h>
-#include "hid-ids.h"
-#include "usbhid/usbhid.h"
-#include <linux/usb.h>
-
-#include <linux/fb.h>
-#include <linux/vmalloc.h>
-#include <linux/backlight.h>
-#include <linux/lcd.h>
-
-#include <linux/leds.h>
-
-#include <linux/seq_file.h>
-#include <linux/debugfs.h>
-
-#include <linux/completion.h>
-#include <linux/uaccess.h>
-#include <linux/module.h>
-
-#define PICOLCD_NAME "PicoLCD (graphic)"
-
-/* Report numbers */
-#define REPORT_ERROR_CODE      0x10 /* LCD: IN[16]  */
-#define   ERR_SUCCESS            0x00
-#define   ERR_PARAMETER_MISSING  0x01
-#define   ERR_DATA_MISSING       0x02
-#define   ERR_BLOCK_READ_ONLY    0x03
-#define   ERR_BLOCK_NOT_ERASABLE 0x04
-#define   ERR_BLOCK_TOO_BIG      0x05
-#define   ERR_SECTION_OVERFLOW   0x06
-#define   ERR_INVALID_CMD_LEN    0x07
-#define   ERR_INVALID_DATA_LEN   0x08
-#define REPORT_KEY_STATE       0x11 /* LCD: IN[2]   */
-#define REPORT_IR_DATA         0x21 /* LCD: IN[63]  */
-#define REPORT_EE_DATA         0x32 /* LCD: IN[63]  */
-#define REPORT_MEMORY          0x41 /* LCD: IN[63]  */
-#define REPORT_LED_STATE       0x81 /* LCD: OUT[1]  */
-#define REPORT_BRIGHTNESS      0x91 /* LCD: OUT[1]  */
-#define REPORT_CONTRAST        0x92 /* LCD: OUT[1]  */
-#define REPORT_RESET           0x93 /* LCD: OUT[2]  */
-#define REPORT_LCD_CMD         0x94 /* LCD: OUT[63] */
-#define REPORT_LCD_DATA        0x95 /* LCD: OUT[63] */
-#define REPORT_LCD_CMD_DATA    0x96 /* LCD: OUT[63] */
-#define        REPORT_EE_READ         0xa3 /* LCD: OUT[63] */
-#define REPORT_EE_WRITE        0xa4 /* LCD: OUT[63] */
-#define REPORT_ERASE_MEMORY    0xb2 /* LCD: OUT[2]  */
-#define REPORT_READ_MEMORY     0xb3 /* LCD: OUT[3]  */
-#define REPORT_WRITE_MEMORY    0xb4 /* LCD: OUT[63] */
-#define REPORT_SPLASH_RESTART  0xc1 /* LCD: OUT[1]  */
-#define REPORT_EXIT_KEYBOARD   0xef /* LCD: OUT[2]  */
-#define REPORT_VERSION         0xf1 /* LCD: IN[2],OUT[1]    Bootloader: IN[2],OUT[1]   */
-#define REPORT_BL_ERASE_MEMORY 0xf2 /*                      Bootloader: IN[36],OUT[4]  */
-#define REPORT_BL_READ_MEMORY  0xf3 /*                      Bootloader: IN[36],OUT[4]  */
-#define REPORT_BL_WRITE_MEMORY 0xf4 /*                      Bootloader: IN[36],OUT[36] */
-#define REPORT_DEVID           0xf5 /* LCD: IN[5], OUT[1]   Bootloader: IN[5],OUT[1]   */
-#define REPORT_SPLASH_SIZE     0xf6 /* LCD: IN[4], OUT[1]   */
-#define REPORT_HOOK_VERSION    0xf7 /* LCD: IN[2], OUT[1]   */
-#define REPORT_EXIT_FLASHER    0xff /*                      Bootloader: OUT[2]         */
-
-#ifdef CONFIG_HID_PICOLCD_FB
-/* Framebuffer
- *
- * The PicoLCD use a Topway LCD module of 256x64 pixel
- * This display area is tiled over 4 controllers with 8 tiles
- * each. Each tile has 8x64 pixel, each data byte representing
- * a 1-bit wide vertical line of the tile.
- *
- * The display can be updated at a tile granularity.
- *
- *       Chip 1           Chip 2           Chip 3           Chip 4
- * +----------------+----------------+----------------+----------------+
- * |     Tile 1     |     Tile 1     |     Tile 1     |     Tile 1     |
- * +----------------+----------------+----------------+----------------+
- * |     Tile 2     |     Tile 2     |     Tile 2     |     Tile 2     |
- * +----------------+----------------+----------------+----------------+
- *                                  ...
- * +----------------+----------------+----------------+----------------+
- * |     Tile 8     |     Tile 8     |     Tile 8     |     Tile 8     |
- * +----------------+----------------+----------------+----------------+
- */
-#define PICOLCDFB_NAME "picolcdfb"
-#define PICOLCDFB_WIDTH (256)
-#define PICOLCDFB_HEIGHT (64)
-#define PICOLCDFB_SIZE (PICOLCDFB_WIDTH * PICOLCDFB_HEIGHT / 8)
-
-#define PICOLCDFB_UPDATE_RATE_LIMIT   10
-#define PICOLCDFB_UPDATE_RATE_DEFAULT  2
-
-/* Framebuffer visual structures */
-static const struct fb_fix_screeninfo picolcdfb_fix = {
-       .id          = PICOLCDFB_NAME,
-       .type        = FB_TYPE_PACKED_PIXELS,
-       .visual      = FB_VISUAL_MONO01,
-       .xpanstep    = 0,
-       .ypanstep    = 0,
-       .ywrapstep   = 0,
-       .line_length = PICOLCDFB_WIDTH / 8,
-       .accel       = FB_ACCEL_NONE,
-};
-
-static const struct fb_var_screeninfo picolcdfb_var = {
-       .xres           = PICOLCDFB_WIDTH,
-       .yres           = PICOLCDFB_HEIGHT,
-       .xres_virtual   = PICOLCDFB_WIDTH,
-       .yres_virtual   = PICOLCDFB_HEIGHT,
-       .width          = 103,
-       .height         = 26,
-       .bits_per_pixel = 1,
-       .grayscale      = 1,
-       .red            = {
-               .offset = 0,
-               .length = 1,
-               .msb_right = 0,
-       },
-       .green          = {
-               .offset = 0,
-               .length = 1,
-               .msb_right = 0,
-       },
-       .blue           = {
-               .offset = 0,
-               .length = 1,
-               .msb_right = 0,
-       },
-       .transp         = {
-               .offset = 0,
-               .length = 0,
-               .msb_right = 0,
-       },
-};
-#endif /* CONFIG_HID_PICOLCD_FB */
-
-/* Input device
- *
- * The PicoLCD has an IR receiver header, a built-in keypad with 5 keys
- * and header for 4x4 key matrix. The built-in keys are part of the matrix.
- */
-static const unsigned short def_keymap[] = {
-       KEY_RESERVED,   /* none */
-       KEY_BACK,       /* col 4 + row 1 */
-       KEY_HOMEPAGE,   /* col 3 + row 1 */
-       KEY_RESERVED,   /* col 2 + row 1 */
-       KEY_RESERVED,   /* col 1 + row 1 */
-       KEY_SCROLLUP,   /* col 4 + row 2 */
-       KEY_OK,         /* col 3 + row 2 */
-       KEY_SCROLLDOWN, /* col 2 + row 2 */
-       KEY_RESERVED,   /* col 1 + row 2 */
-       KEY_RESERVED,   /* col 4 + row 3 */
-       KEY_RESERVED,   /* col 3 + row 3 */
-       KEY_RESERVED,   /* col 2 + row 3 */
-       KEY_RESERVED,   /* col 1 + row 3 */
-       KEY_RESERVED,   /* col 4 + row 4 */
-       KEY_RESERVED,   /* col 3 + row 4 */
-       KEY_RESERVED,   /* col 2 + row 4 */
-       KEY_RESERVED,   /* col 1 + row 4 */
-};
-#define PICOLCD_KEYS ARRAY_SIZE(def_keymap)
-
-/* Description of in-progress IO operation, used for operations
- * that trigger response from device */
-struct picolcd_pending {
-       struct hid_report *out_report;
-       struct hid_report *in_report;
-       struct completion ready;
-       int raw_size;
-       u8 raw_data[64];
-};
-
-/* Per device data structure */
-struct picolcd_data {
-       struct hid_device *hdev;
-#ifdef CONFIG_DEBUG_FS
-       struct dentry *debug_reset;
-       struct dentry *debug_eeprom;
-       struct dentry *debug_flash;
-       struct mutex mutex_flash;
-       int addr_sz;
-#endif
-       u8 version[2];
-       unsigned short opmode_delay;
-       /* input stuff */
-       u8 pressed_keys[2];
-       struct input_dev *input_keys;
-       struct input_dev *input_cir;
-       unsigned short keycode[PICOLCD_KEYS];
-
-#ifdef CONFIG_HID_PICOLCD_FB
-       /* Framebuffer stuff */
-       u8 fb_update_rate;
-       u8 fb_bpp;
-       u8 fb_force;
-       u8 *fb_vbitmap;         /* local copy of what was sent to PicoLCD */
-       u8 *fb_bitmap;          /* framebuffer */
-       struct fb_info *fb_info;
-       struct fb_deferred_io fb_defio;
-#endif /* CONFIG_HID_PICOLCD_FB */
-#ifdef CONFIG_HID_PICOLCD_LCD
-       struct lcd_device *lcd;
-       u8 lcd_contrast;
-#endif /* CONFIG_HID_PICOLCD_LCD */
-#ifdef CONFIG_HID_PICOLCD_BACKLIGHT
-       struct backlight_device *backlight;
-       u8 lcd_brightness;
-       u8 lcd_power;
-#endif /* CONFIG_HID_PICOLCD_BACKLIGHT */
-#ifdef CONFIG_HID_PICOLCD_LEDS
-       /* LED stuff */
-       u8 led_state;
-       struct led_classdev *led[8];
-#endif /* CONFIG_HID_PICOLCD_LEDS */
-
-       /* Housekeeping stuff */
-       spinlock_t lock;
-       struct mutex mutex;
-       struct picolcd_pending *pending;
-       int status;
-#define PICOLCD_BOOTLOADER 1
-#define PICOLCD_FAILED 2
-#define PICOLCD_READY_FB 4
-};
-
-
-/* Find a given report */
-#define picolcd_in_report(id, dev) picolcd_report(id, dev, HID_INPUT_REPORT)
-#define picolcd_out_report(id, dev) picolcd_report(id, dev, HID_OUTPUT_REPORT)
-
-static struct hid_report *picolcd_report(int id, struct hid_device *hdev, int dir)
-{
-       struct list_head *feature_report_list = &hdev->report_enum[dir].report_list;
-       struct hid_report *report = NULL;
-
-       list_for_each_entry(report, feature_report_list, list) {
-               if (report->id == id)
-                       return report;
-       }
-       hid_warn(hdev, "No report with id 0x%x found\n", id);
-       return NULL;
-}
-
-#ifdef CONFIG_DEBUG_FS
-static void picolcd_debug_out_report(struct picolcd_data *data,
-               struct hid_device *hdev, struct hid_report *report);
-#define usbhid_submit_report(a, b, c) \
-       do { \
-               picolcd_debug_out_report(hid_get_drvdata(a), a, b); \
-               usbhid_submit_report(a, b, c); \
-       } while (0)
-#endif
-
-/* Submit a report and wait for a reply from device - if device fades away
- * or does not respond in time, return NULL */
-static struct picolcd_pending *picolcd_send_and_wait(struct hid_device *hdev,
-               int report_id, const u8 *raw_data, int size)
-{
-       struct picolcd_data *data = hid_get_drvdata(hdev);
-       struct picolcd_pending *work;
-       struct hid_report *report = picolcd_out_report(report_id, hdev);
-       unsigned long flags;
-       int i, j, k;
-
-       if (!report || !data)
-               return NULL;
-       if (data->status & PICOLCD_FAILED)
-               return NULL;
-       work = kzalloc(sizeof(*work), GFP_KERNEL);
-       if (!work)
-               return NULL;
-
-       init_completion(&work->ready);
-       work->out_report = report;
-       work->in_report  = NULL;
-       work->raw_size   = 0;
-
-       mutex_lock(&data->mutex);
-       spin_lock_irqsave(&data->lock, flags);
-       for (i = k = 0; i < report->maxfield; i++)
-               for (j = 0; j < report->field[i]->report_count; j++) {
-                       hid_set_field(report->field[i], j, k < size ? raw_data[k] : 0);
-                       k++;
-               }
-       data->pending = work;
-       usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
-       spin_unlock_irqrestore(&data->lock, flags);
-       wait_for_completion_interruptible_timeout(&work->ready, HZ*2);
-       spin_lock_irqsave(&data->lock, flags);
-       data->pending = NULL;
-       spin_unlock_irqrestore(&data->lock, flags);
-       mutex_unlock(&data->mutex);
-       return work;
-}
-
-#ifdef CONFIG_HID_PICOLCD_FB
-/* Send a given tile to PicoLCD */
-static int picolcd_fb_send_tile(struct hid_device *hdev, int chip, int tile)
-{
-       struct picolcd_data *data = hid_get_drvdata(hdev);
-       struct hid_report *report1 = picolcd_out_report(REPORT_LCD_CMD_DATA, hdev);
-       struct hid_report *report2 = picolcd_out_report(REPORT_LCD_DATA, hdev);
-       unsigned long flags;
-       u8 *tdata;
-       int i;
-
-       if (!report1 || report1->maxfield != 1 || !report2 || report2->maxfield != 1)
-               return -ENODEV;
-
-       spin_lock_irqsave(&data->lock, flags);
-       hid_set_field(report1->field[0],  0, chip << 2);
-       hid_set_field(report1->field[0],  1, 0x02);
-       hid_set_field(report1->field[0],  2, 0x00);
-       hid_set_field(report1->field[0],  3, 0x00);
-       hid_set_field(report1->field[0],  4, 0xb8 | tile);
-       hid_set_field(report1->field[0],  5, 0x00);
-       hid_set_field(report1->field[0],  6, 0x00);
-       hid_set_field(report1->field[0],  7, 0x40);
-       hid_set_field(report1->field[0],  8, 0x00);
-       hid_set_field(report1->field[0],  9, 0x00);
-       hid_set_field(report1->field[0], 10,   32);
-
-       hid_set_field(report2->field[0],  0, (chip << 2) | 0x01);
-       hid_set_field(report2->field[0],  1, 0x00);
-       hid_set_field(report2->field[0],  2, 0x00);
-       hid_set_field(report2->field[0],  3,   32);
-
-       tdata = data->fb_vbitmap + (tile * 4 + chip) * 64;
-       for (i = 0; i < 64; i++)
-               if (i < 32)
-                       hid_set_field(report1->field[0], 11 + i, tdata[i]);
-               else
-                       hid_set_field(report2->field[0], 4 + i - 32, tdata[i]);
-
-       usbhid_submit_report(data->hdev, report1, USB_DIR_OUT);
-       usbhid_submit_report(data->hdev, report2, USB_DIR_OUT);
-       spin_unlock_irqrestore(&data->lock, flags);
-       return 0;
-}
-
-/* Translate a single tile*/
-static int picolcd_fb_update_tile(u8 *vbitmap, const u8 *bitmap, int bpp,
-               int chip, int tile)
-{
-       int i, b, changed = 0;
-       u8 tdata[64];
-       u8 *vdata = vbitmap + (tile * 4 + chip) * 64;
-
-       if (bpp == 1) {
-               for (b = 7; b >= 0; b--) {
-                       const u8 *bdata = bitmap + tile * 256 + chip * 8 + b * 32;
-                       for (i = 0; i < 64; i++) {
-                               tdata[i] <<= 1;
-                               tdata[i] |= (bdata[i/8] >> (i % 8)) & 0x01;
-                       }
-               }
-       } else if (bpp == 8) {
-               for (b = 7; b >= 0; b--) {
-                       const u8 *bdata = bitmap + (tile * 256 + chip * 8 + b * 32) * 8;
-                       for (i = 0; i < 64; i++) {
-                               tdata[i] <<= 1;
-                               tdata[i] |= (bdata[i] & 0x80) ? 0x01 : 0x00;
-                       }
-               }
-       } else {
-               /* Oops, we should never get here! */
-               WARN_ON(1);
-               return 0;
-       }
-
-       for (i = 0; i < 64; i++)
-               if (tdata[i] != vdata[i]) {
-                       changed = 1;
-                       vdata[i] = tdata[i];
-               }
-       return changed;
-}
-
-/* Reconfigure LCD display */
-static int picolcd_fb_reset(struct picolcd_data *data, int clear)
-{
-       struct hid_report *report = picolcd_out_report(REPORT_LCD_CMD, data->hdev);
-       int i, j;
-       unsigned long flags;
-       static const u8 mapcmd[8] = { 0x00, 0x02, 0x00, 0x64, 0x3f, 0x00, 0x64, 0xc0 };
-
-       if (!report || report->maxfield != 1)
-               return -ENODEV;
-
-       spin_lock_irqsave(&data->lock, flags);
-       for (i = 0; i < 4; i++) {
-               for (j = 0; j < report->field[0]->maxusage; j++)
-                       if (j == 0)
-                               hid_set_field(report->field[0], j, i << 2);
-                       else if (j < sizeof(mapcmd))
-                               hid_set_field(report->field[0], j, mapcmd[j]);
-                       else
-                               hid_set_field(report->field[0], j, 0);
-               usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
-       }
-
-       data->status |= PICOLCD_READY_FB;
-       spin_unlock_irqrestore(&data->lock, flags);
-
-       if (data->fb_bitmap) {
-               if (clear) {
-                       memset(data->fb_vbitmap, 0, PICOLCDFB_SIZE);
-                       memset(data->fb_bitmap, 0, PICOLCDFB_SIZE*data->fb_bpp);
-               }
-               data->fb_force = 1;
-       }
-
-       /* schedule first output of framebuffer */
-       if (data->fb_info)
-               schedule_delayed_work(&data->fb_info->deferred_work, 0);
-
-       return 0;
-}
-
-/* Update fb_vbitmap from the screen_base and send changed tiles to device */
-static void picolcd_fb_update(struct picolcd_data *data)
-{
-       int chip, tile, n;
-       unsigned long flags;
-
-       if (!data)
-               return;
-
-       spin_lock_irqsave(&data->lock, flags);
-       if (!(data->status & PICOLCD_READY_FB)) {
-               spin_unlock_irqrestore(&data->lock, flags);
-               picolcd_fb_reset(data, 0);
-       } else {
-               spin_unlock_irqrestore(&data->lock, flags);
-       }
-
-       /*
-        * Translate the framebuffer into the format needed by the PicoLCD.
-        * See display layout above.
-        * Do this one tile after the other and push those tiles that changed.
-        *
-        * Wait for our IO to complete as otherwise we might flood the queue!
-        */
-       n = 0;
-       for (chip = 0; chip < 4; chip++)
-               for (tile = 0; tile < 8; tile++)
-                       if (picolcd_fb_update_tile(data->fb_vbitmap,
-                                       data->fb_bitmap, data->fb_bpp, chip, tile) ||
-                               data->fb_force) {
-                               n += 2;
-                               if (!data->fb_info->par)
-                                       return; /* device lost! */
-                               if (n >= HID_OUTPUT_FIFO_SIZE / 2) {
-                                       usbhid_wait_io(data->hdev);
-                                       n = 0;
-                               }
-                               picolcd_fb_send_tile(data->hdev, chip, tile);
-                       }
-       data->fb_force = false;
-       if (n)
-               usbhid_wait_io(data->hdev);
-}
-
-/* Stub to call the system default and update the image on the picoLCD */
-static void picolcd_fb_fillrect(struct fb_info *info,
-               const struct fb_fillrect *rect)
-{
-       if (!info->par)
-               return;
-       sys_fillrect(info, rect);
-
-       schedule_delayed_work(&info->deferred_work, 0);
-}
-
-/* Stub to call the system default and update the image on the picoLCD */
-static void picolcd_fb_copyarea(struct fb_info *info,
-               const struct fb_copyarea *area)
-{
-       if (!info->par)
-               return;
-       sys_copyarea(info, area);
-
-       schedule_delayed_work(&info->deferred_work, 0);
-}
-
-/* Stub to call the system default and update the image on the picoLCD */
-static void picolcd_fb_imageblit(struct fb_info *info, const struct fb_image *image)
-{
-       if (!info->par)
-               return;
-       sys_imageblit(info, image);
-
-       schedule_delayed_work(&info->deferred_work, 0);
-}
-
-/*
- * this is the slow path from userspace. they can seek and write to
- * the fb. it's inefficient to do anything less than a full screen draw
- */
-static ssize_t picolcd_fb_write(struct fb_info *info, const char __user *buf,
-               size_t count, loff_t *ppos)
-{
-       ssize_t ret;
-       if (!info->par)
-               return -ENODEV;
-       ret = fb_sys_write(info, buf, count, ppos);
-       if (ret >= 0)
-               schedule_delayed_work(&info->deferred_work, 0);
-       return ret;
-}
-
-static int picolcd_fb_blank(int blank, struct fb_info *info)
-{
-       if (!info->par)
-               return -ENODEV;
-       /* We let fb notification do this for us via lcd/backlight device */
-       return 0;
-}
-
-static void picolcd_fb_destroy(struct fb_info *info)
-{
-       struct picolcd_data *data = info->par;
-       u32 *ref_cnt = info->pseudo_palette;
-       int may_release;
-
-       info->par = NULL;
-       if (data)
-               data->fb_info = NULL;
-       fb_deferred_io_cleanup(info);
-
-       ref_cnt--;
-       mutex_lock(&info->lock);
-       (*ref_cnt)--;
-       may_release = !*ref_cnt;
-       mutex_unlock(&info->lock);
-       if (may_release) {
-               vfree((u8 *)info->fix.smem_start);
-               framebuffer_release(info);
-       }
-}
-
-static int picolcd_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
-{
-       __u32 bpp      = var->bits_per_pixel;
-       __u32 activate = var->activate;
-
-       /* only allow 1/8 bit depth (8-bit is grayscale) */
-       *var = picolcdfb_var;
-       var->activate = activate;
-       if (bpp >= 8) {
-               var->bits_per_pixel = 8;
-               var->red.length     = 8;
-               var->green.length   = 8;
-               var->blue.length    = 8;
-       } else {
-               var->bits_per_pixel = 1;
-               var->red.length     = 1;
-               var->green.length   = 1;
-               var->blue.length    = 1;
-       }
-       return 0;
-}
-
-static int picolcd_set_par(struct fb_info *info)
-{
-       struct picolcd_data *data = info->par;
-       u8 *tmp_fb, *o_fb;
-       if (!data)
-               return -ENODEV;
-       if (info->var.bits_per_pixel == data->fb_bpp)
-               return 0;
-       /* switch between 1/8 bit depths */
-       if (info->var.bits_per_pixel != 1 && info->var.bits_per_pixel != 8)
-               return -EINVAL;
-
-       o_fb   = data->fb_bitmap;
-       tmp_fb = kmalloc(PICOLCDFB_SIZE*info->var.bits_per_pixel, GFP_KERNEL);
-       if (!tmp_fb)
-               return -ENOMEM;
-
-       /* translate FB content to new bits-per-pixel */
-       if (info->var.bits_per_pixel == 1) {
-               int i, b;
-               for (i = 0; i < PICOLCDFB_SIZE; i++) {
-                       u8 p = 0;
-                       for (b = 0; b < 8; b++) {
-                               p <<= 1;
-                               p |= o_fb[i*8+b] ? 0x01 : 0x00;
-                       }
-                       tmp_fb[i] = p;
-               }
-               memcpy(o_fb, tmp_fb, PICOLCDFB_SIZE);
-               info->fix.visual = FB_VISUAL_MONO01;
-               info->fix.line_length = PICOLCDFB_WIDTH / 8;
-       } else {
-               int i;
-               memcpy(tmp_fb, o_fb, PICOLCDFB_SIZE);
-               for (i = 0; i < PICOLCDFB_SIZE * 8; i++)
-                       o_fb[i] = tmp_fb[i/8] & (0x01 << (7 - i % 8)) ? 0xff : 0x00;
-               info->fix.visual = FB_VISUAL_DIRECTCOLOR;
-               info->fix.line_length = PICOLCDFB_WIDTH;
-       }
-
-       kfree(tmp_fb);
-       data->fb_bpp      = info->var.bits_per_pixel;
-       return 0;
-}
-
-/* Do refcounting on our FB and cleanup per worker if FB is
- * closed after unplug of our device
- * (fb_release holds info->lock and still touches info after
- *  we return so we can't release it immediately.
- */
-struct picolcd_fb_cleanup_item {
-       struct fb_info *info;
-       struct picolcd_fb_cleanup_item *next;
-};
-static struct picolcd_fb_cleanup_item *fb_pending;
-static DEFINE_SPINLOCK(fb_pending_lock);
-
-static void picolcd_fb_do_cleanup(struct work_struct *data)
-{
-       struct picolcd_fb_cleanup_item *item;
-       unsigned long flags;
-
-       do {
-               spin_lock_irqsave(&fb_pending_lock, flags);
-               item = fb_pending;
-               fb_pending = item ? item->next : NULL;
-               spin_unlock_irqrestore(&fb_pending_lock, flags);
-
-               if (item) {
-                       u8 *fb = (u8 *)item->info->fix.smem_start;
-                       /* make sure we do not race against fb core when
-                        * releasing */
-                       mutex_lock(&item->info->lock);
-                       mutex_unlock(&item->info->lock);
-                       framebuffer_release(item->info);
-                       vfree(fb);
-               }
-       } while (item);
-}
-
-static DECLARE_WORK(picolcd_fb_cleanup, picolcd_fb_do_cleanup);
-
-static int picolcd_fb_open(struct fb_info *info, int u)
-{
-       u32 *ref_cnt = info->pseudo_palette;
-       ref_cnt--;
-
-       (*ref_cnt)++;
-       return 0;
-}
-
-static int picolcd_fb_release(struct fb_info *info, int u)
-{
-       u32 *ref_cnt = info->pseudo_palette;
-       ref_cnt--;
-
-       (*ref_cnt)++;
-       if (!*ref_cnt) {
-               unsigned long flags;
-               struct picolcd_fb_cleanup_item *item = (struct picolcd_fb_cleanup_item *)ref_cnt;
-               item--;
-               spin_lock_irqsave(&fb_pending_lock, flags);
-               item->next = fb_pending;
-               fb_pending = item;
-               spin_unlock_irqrestore(&fb_pending_lock, flags);
-               schedule_work(&picolcd_fb_cleanup);
-       }
-       return 0;
-}
-
-/* Note this can't be const because of struct fb_info definition */
-static struct fb_ops picolcdfb_ops = {
-       .owner        = THIS_MODULE,
-       .fb_destroy   = picolcd_fb_destroy,
-       .fb_open      = picolcd_fb_open,
-       .fb_release   = picolcd_fb_release,
-       .fb_read      = fb_sys_read,
-       .fb_write     = picolcd_fb_write,
-       .fb_blank     = picolcd_fb_blank,
-       .fb_fillrect  = picolcd_fb_fillrect,
-       .fb_copyarea  = picolcd_fb_copyarea,
-       .fb_imageblit = picolcd_fb_imageblit,
-       .fb_check_var = picolcd_fb_check_var,
-       .fb_set_par   = picolcd_set_par,
-};
-
-
-/* Callback from deferred IO workqueue */
-static void picolcd_fb_deferred_io(struct fb_info *info, struct list_head *pagelist)
-{
-       picolcd_fb_update(info->par);
-}
-
-static const struct fb_deferred_io picolcd_fb_defio = {
-       .delay = HZ / PICOLCDFB_UPDATE_RATE_DEFAULT,
-       .deferred_io = picolcd_fb_deferred_io,
-};
-
-
-/*
- * The "fb_update_rate" sysfs attribute
- */
-static ssize_t picolcd_fb_update_rate_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct picolcd_data *data = dev_get_drvdata(dev);
-       unsigned i, fb_update_rate = data->fb_update_rate;
-       size_t ret = 0;
-
-       for (i = 1; i <= PICOLCDFB_UPDATE_RATE_LIMIT; i++)
-               if (ret >= PAGE_SIZE)
-                       break;
-               else if (i == fb_update_rate)
-                       ret += snprintf(buf+ret, PAGE_SIZE-ret, "[%u] ", i);
-               else
-                       ret += snprintf(buf+ret, PAGE_SIZE-ret, "%u ", i);
-       if (ret > 0)
-               buf[min(ret, (size_t)PAGE_SIZE)-1] = '\n';
-       return ret;
-}
-
-static ssize_t picolcd_fb_update_rate_store(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t count)
-{
-       struct picolcd_data *data = dev_get_drvdata(dev);
-       int i;
-       unsigned u;
-
-       if (count < 1 || count > 10)
-               return -EINVAL;
-
-       i = sscanf(buf, "%u", &u);
-       if (i != 1)
-               return -EINVAL;
-
-       if (u > PICOLCDFB_UPDATE_RATE_LIMIT)
-               return -ERANGE;
-       else if (u == 0)
-               u = PICOLCDFB_UPDATE_RATE_DEFAULT;
-
-       data->fb_update_rate = u;
-       data->fb_defio.delay = HZ / data->fb_update_rate;
-       return count;
-}
-
-static DEVICE_ATTR(fb_update_rate, 0666, picolcd_fb_update_rate_show,
-               picolcd_fb_update_rate_store);
-
-/* initialize Framebuffer device */
-static int picolcd_init_framebuffer(struct picolcd_data *data)
-{
-       struct device *dev = &data->hdev->dev;
-       struct fb_info *info = NULL;
-       int i, error = -ENOMEM;
-       u8 *fb_vbitmap = NULL;
-       u8 *fb_bitmap  = NULL;
-       u32 *palette;
-
-       fb_bitmap = vmalloc(PICOLCDFB_SIZE*8);
-       if (fb_bitmap == NULL) {
-               dev_err(dev, "can't get a free page for framebuffer\n");
-               goto err_nomem;
-       }
-
-       fb_vbitmap = kmalloc(PICOLCDFB_SIZE, GFP_KERNEL);
-       if (fb_vbitmap == NULL) {
-               dev_err(dev, "can't alloc vbitmap image buffer\n");
-               goto err_nomem;
-       }
-
-       data->fb_update_rate = PICOLCDFB_UPDATE_RATE_DEFAULT;
-       data->fb_defio = picolcd_fb_defio;
-       /* The extra memory is:
-        * - struct picolcd_fb_cleanup_item
-        * - u32 for ref_count
-        * - 256*u32 for pseudo_palette
-        */
-       info = framebuffer_alloc(257 * sizeof(u32) + sizeof(struct picolcd_fb_cleanup_item), dev);
-       if (info == NULL) {
-               dev_err(dev, "failed to allocate a framebuffer\n");
-               goto err_nomem;
-       }
-
-       palette  = info->par + sizeof(struct picolcd_fb_cleanup_item);
-       *palette = 1;
-       palette++;
-       for (i = 0; i < 256; i++)
-               palette[i] = i > 0 && i < 16 ? 0xff : 0;
-       info->pseudo_palette = palette;
-       info->fbdefio = &data->fb_defio;
-       info->screen_base = (char __force __iomem *)fb_bitmap;
-       info->fbops = &picolcdfb_ops;
-       info->var = picolcdfb_var;
-       info->fix = picolcdfb_fix;
-       info->fix.smem_len   = PICOLCDFB_SIZE*8;
-       info->fix.smem_start = (unsigned long)fb_bitmap;
-       info->par = data;
-       info->flags = FBINFO_FLAG_DEFAULT;
-
-       data->fb_vbitmap = fb_vbitmap;
-       data->fb_bitmap  = fb_bitmap;
-       data->fb_bpp     = picolcdfb_var.bits_per_pixel;
-       error = picolcd_fb_reset(data, 1);
-       if (error) {
-               dev_err(dev, "failed to configure display\n");
-               goto err_cleanup;
-       }
-       error = device_create_file(dev, &dev_attr_fb_update_rate);
-       if (error) {
-               dev_err(dev, "failed to create sysfs attributes\n");
-               goto err_cleanup;
-       }
-       fb_deferred_io_init(info);
-       data->fb_info    = info;
-       error = register_framebuffer(info);
-       if (error) {
-               dev_err(dev, "failed to register framebuffer\n");
-               goto err_sysfs;
-       }
-       /* schedule first output of framebuffer */
-       data->fb_force = 1;
-       schedule_delayed_work(&info->deferred_work, 0);
-       return 0;
-
-err_sysfs:
-       fb_deferred_io_cleanup(info);
-       device_remove_file(dev, &dev_attr_fb_update_rate);
-err_cleanup:
-       data->fb_vbitmap = NULL;
-       data->fb_bitmap  = NULL;
-       data->fb_bpp     = 0;
-       data->fb_info    = NULL;
-
-err_nomem:
-       framebuffer_release(info);
-       vfree(fb_bitmap);
-       kfree(fb_vbitmap);
-       return error;
-}
-
-static void picolcd_exit_framebuffer(struct picolcd_data *data)
-{
-       struct fb_info *info = data->fb_info;
-       u8 *fb_vbitmap = data->fb_vbitmap;
-
-       if (!info)
-               return;
-
-       info->par = NULL;
-       device_remove_file(&data->hdev->dev, &dev_attr_fb_update_rate);
-       unregister_framebuffer(info);
-       data->fb_vbitmap = NULL;
-       data->fb_bitmap  = NULL;
-       data->fb_bpp     = 0;
-       data->fb_info    = NULL;
-       kfree(fb_vbitmap);
-}
-
-#define picolcd_fbinfo(d) ((d)->fb_info)
-#else
-static inline int picolcd_fb_reset(struct picolcd_data *data, int clear)
-{
-       return 0;
-}
-static inline int picolcd_init_framebuffer(struct picolcd_data *data)
-{
-       return 0;
-}
-static inline void picolcd_exit_framebuffer(struct picolcd_data *data)
-{
-}
-#define picolcd_fbinfo(d) NULL
-#endif /* CONFIG_HID_PICOLCD_FB */
-
-#ifdef CONFIG_HID_PICOLCD_BACKLIGHT
-/*
- * backlight class device
- */
-static int picolcd_get_brightness(struct backlight_device *bdev)
-{
-       struct picolcd_data *data = bl_get_data(bdev);
-       return data->lcd_brightness;
-}
-
-static int picolcd_set_brightness(struct backlight_device *bdev)
-{
-       struct picolcd_data *data = bl_get_data(bdev);
-       struct hid_report *report = picolcd_out_report(REPORT_BRIGHTNESS, data->hdev);
-       unsigned long flags;
-
-       if (!report || report->maxfield != 1 || report->field[0]->report_count != 1)
-               return -ENODEV;
-
-       data->lcd_brightness = bdev->props.brightness & 0x0ff;
-       data->lcd_power      = bdev->props.power;
-       spin_lock_irqsave(&data->lock, flags);
-       hid_set_field(report->field[0], 0, data->lcd_power == FB_BLANK_UNBLANK ? data->lcd_brightness : 0);
-       usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
-       spin_unlock_irqrestore(&data->lock, flags);
-       return 0;
-}
-
-static int picolcd_check_bl_fb(struct backlight_device *bdev, struct fb_info *fb)
-{
-       return fb && fb == picolcd_fbinfo((struct picolcd_data *)bl_get_data(bdev));
-}
-
-static const struct backlight_ops picolcd_blops = {
-       .update_status  = picolcd_set_brightness,
-       .get_brightness = picolcd_get_brightness,
-       .check_fb       = picolcd_check_bl_fb,
-};
-
-static int picolcd_init_backlight(struct picolcd_data *data, struct hid_report *report)
-{
-       struct device *dev = &data->hdev->dev;
-       struct backlight_device *bdev;
-       struct backlight_properties props;
-       if (!report)
-               return -ENODEV;
-       if (report->maxfield != 1 || report->field[0]->report_count != 1 ||
-                       report->field[0]->report_size != 8) {
-               dev_err(dev, "unsupported BRIGHTNESS report");
-               return -EINVAL;
-       }
-
-       memset(&props, 0, sizeof(props));
-       props.type = BACKLIGHT_RAW;
-       props.max_brightness = 0xff;
-       bdev = backlight_device_register(dev_name(dev), dev, data,
-                       &picolcd_blops, &props);
-       if (IS_ERR(bdev)) {
-               dev_err(dev, "failed to register backlight\n");
-               return PTR_ERR(bdev);
-       }
-       bdev->props.brightness     = 0xff;
-       data->lcd_brightness       = 0xff;
-       data->backlight            = bdev;
-       picolcd_set_brightness(bdev);
-       return 0;
-}
-
-static void picolcd_exit_backlight(struct picolcd_data *data)
-{
-       struct backlight_device *bdev = data->backlight;
-
-       data->backlight = NULL;
-       if (bdev)
-               backlight_device_unregister(bdev);
-}
-
-static inline int picolcd_resume_backlight(struct picolcd_data *data)
-{
-       if (!data->backlight)
-               return 0;
-       return picolcd_set_brightness(data->backlight);
-}
-
-#ifdef CONFIG_PM
-static void picolcd_suspend_backlight(struct picolcd_data *data)
-{
-       int bl_power = data->lcd_power;
-       if (!data->backlight)
-               return;
-
-       data->backlight->props.power = FB_BLANK_POWERDOWN;
-       picolcd_set_brightness(data->backlight);
-       data->lcd_power = data->backlight->props.power = bl_power;
-}
-#endif /* CONFIG_PM */
-#else
-static inline int picolcd_init_backlight(struct picolcd_data *data,
-               struct hid_report *report)
-{
-       return 0;
-}
-static inline void picolcd_exit_backlight(struct picolcd_data *data)
-{
-}
-static inline int picolcd_resume_backlight(struct picolcd_data *data)
-{
-       return 0;
-}
-static inline void picolcd_suspend_backlight(struct picolcd_data *data)
-{
-}
-#endif /* CONFIG_HID_PICOLCD_BACKLIGHT */
-
-#ifdef CONFIG_HID_PICOLCD_LCD
-/*
- * lcd class device
- */
-static int picolcd_get_contrast(struct lcd_device *ldev)
-{
-       struct picolcd_data *data = lcd_get_data(ldev);
-       return data->lcd_contrast;
-}
-
-static int picolcd_set_contrast(struct lcd_device *ldev, int contrast)
-{
-       struct picolcd_data *data = lcd_get_data(ldev);
-       struct hid_report *report = picolcd_out_report(REPORT_CONTRAST, data->hdev);
-       unsigned long flags;
-
-       if (!report || report->maxfield != 1 || report->field[0]->report_count != 1)
-               return -ENODEV;
-
-       data->lcd_contrast = contrast & 0x0ff;
-       spin_lock_irqsave(&data->lock, flags);
-       hid_set_field(report->field[0], 0, data->lcd_contrast);
-       usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
-       spin_unlock_irqrestore(&data->lock, flags);
-       return 0;
-}
-
-static int picolcd_check_lcd_fb(struct lcd_device *ldev, struct fb_info *fb)
-{
-       return fb && fb == picolcd_fbinfo((struct picolcd_data *)lcd_get_data(ldev));
-}
-
-static struct lcd_ops picolcd_lcdops = {
-       .get_contrast   = picolcd_get_contrast,
-       .set_contrast   = picolcd_set_contrast,
-       .check_fb       = picolcd_check_lcd_fb,
-};
-
-static int picolcd_init_lcd(struct picolcd_data *data, struct hid_report *report)
-{
-       struct device *dev = &data->hdev->dev;
-       struct lcd_device *ldev;
-
-       if (!report)
-               return -ENODEV;
-       if (report->maxfield != 1 || report->field[0]->report_count != 1 ||
-                       report->field[0]->report_size != 8) {
-               dev_err(dev, "unsupported CONTRAST report");
-               return -EINVAL;
-       }
-
-       ldev = lcd_device_register(dev_name(dev), dev, data, &picolcd_lcdops);
-       if (IS_ERR(ldev)) {
-               dev_err(dev, "failed to register LCD\n");
-               return PTR_ERR(ldev);
-       }
-       ldev->props.max_contrast = 0x0ff;
-       data->lcd_contrast = 0xe5;
-       data->lcd = ldev;
-       picolcd_set_contrast(ldev, 0xe5);
-       return 0;
-}
-
-static void picolcd_exit_lcd(struct picolcd_data *data)
-{
-       struct lcd_device *ldev = data->lcd;
-
-       data->lcd = NULL;
-       if (ldev)
-               lcd_device_unregister(ldev);
-}
-
-static inline int picolcd_resume_lcd(struct picolcd_data *data)
-{
-       if (!data->lcd)
-               return 0;
-       return picolcd_set_contrast(data->lcd, data->lcd_contrast);
-}
-#else
-static inline int picolcd_init_lcd(struct picolcd_data *data,
-               struct hid_report *report)
-{
-       return 0;
-}
-static inline void picolcd_exit_lcd(struct picolcd_data *data)
-{
-}
-static inline int picolcd_resume_lcd(struct picolcd_data *data)
-{
-       return 0;
-}
-#endif /* CONFIG_HID_PICOLCD_LCD */
-
-#ifdef CONFIG_HID_PICOLCD_LEDS
-/**
- * LED class device
- */
-static void picolcd_leds_set(struct picolcd_data *data)
-{
-       struct hid_report *report;
-       unsigned long flags;
-
-       if (!data->led[0])
-               return;
-       report = picolcd_out_report(REPORT_LED_STATE, data->hdev);
-       if (!report || report->maxfield != 1 || report->field[0]->report_count != 1)
-               return;
-
-       spin_lock_irqsave(&data->lock, flags);
-       hid_set_field(report->field[0], 0, data->led_state);
-       usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
-       spin_unlock_irqrestore(&data->lock, flags);
-}
-
-static void picolcd_led_set_brightness(struct led_classdev *led_cdev,
-                       enum led_brightness value)
-{
-       struct device *dev;
-       struct hid_device *hdev;
-       struct picolcd_data *data;
-       int i, state = 0;
-
-       dev  = led_cdev->dev->parent;
-       hdev = container_of(dev, struct hid_device, dev);
-       data = hid_get_drvdata(hdev);
-       for (i = 0; i < 8; i++) {
-               if (led_cdev != data->led[i])
-                       continue;
-               state = (data->led_state >> i) & 1;
-               if (value == LED_OFF && state) {
-                       data->led_state &= ~(1 << i);
-                       picolcd_leds_set(data);
-               } else if (value != LED_OFF && !state) {
-                       data->led_state |= 1 << i;
-                       picolcd_leds_set(data);
-               }
-               break;
-       }
-}
-
-static enum led_brightness picolcd_led_get_brightness(struct led_classdev *led_cdev)
-{
-       struct device *dev;
-       struct hid_device *hdev;
-       struct picolcd_data *data;
-       int i, value = 0;
-
-       dev  = led_cdev->dev->parent;
-       hdev = container_of(dev, struct hid_device, dev);
-       data = hid_get_drvdata(hdev);
-       for (i = 0; i < 8; i++)
-               if (led_cdev == data->led[i]) {
-                       value = (data->led_state >> i) & 1;
-                       break;
-               }
-       return value ? LED_FULL : LED_OFF;
-}
-
-static int picolcd_init_leds(struct picolcd_data *data, struct hid_report *report)
-{
-       struct device *dev = &data->hdev->dev;
-       struct led_classdev *led;
-       size_t name_sz = strlen(dev_name(dev)) + 8;
-       char *name;
-       int i, ret = 0;
-
-       if (!report)
-               return -ENODEV;
-       if (report->maxfield != 1 || report->field[0]->report_count != 1 ||
-                       report->field[0]->report_size != 8) {
-               dev_err(dev, "unsupported LED_STATE report");
-               return -EINVAL;
-       }
-
-       for (i = 0; i < 8; i++) {
-               led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL);
-               if (!led) {
-                       dev_err(dev, "can't allocate memory for LED %d\n", i);
-                       ret = -ENOMEM;
-                       goto err;
-               }
-               name = (void *)(&led[1]);
-               snprintf(name, name_sz, "%s::GPO%d", dev_name(dev), i);
-               led->name = name;
-               led->brightness = 0;
-               led->max_brightness = 1;
-               led->brightness_get = picolcd_led_get_brightness;
-               led->brightness_set = picolcd_led_set_brightness;
-
-               data->led[i] = led;
-               ret = led_classdev_register(dev, data->led[i]);
-               if (ret) {
-                       data->led[i] = NULL;
-                       kfree(led);
-                       dev_err(dev, "can't register LED %d\n", i);
-                       goto err;
-               }
-       }
-       return 0;
-err:
-       for (i = 0; i < 8; i++)
-               if (data->led[i]) {
-                       led = data->led[i];
-                       data->led[i] = NULL;
-                       led_classdev_unregister(led);
-                       kfree(led);
-               }
-       return ret;
-}
-
-static void picolcd_exit_leds(struct picolcd_data *data)
-{
-       struct led_classdev *led;
-       int i;
-
-       for (i = 0; i < 8; i++) {
-               led = data->led[i];
-               data->led[i] = NULL;
-               if (!led)
-                       continue;
-               led_classdev_unregister(led);
-               kfree(led);
-       }
-}
-
-#else
-static inline int picolcd_init_leds(struct picolcd_data *data,
-               struct hid_report *report)
-{
-       return 0;
-}
-static inline void picolcd_exit_leds(struct picolcd_data *data)
-{
-}
-static inline int picolcd_leds_set(struct picolcd_data *data)
-{
-       return 0;
-}
-#endif /* CONFIG_HID_PICOLCD_LEDS */
-
-/*
- * input class device
- */
-static int picolcd_raw_keypad(struct picolcd_data *data,
-               struct hid_report *report, u8 *raw_data, int size)
-{
-       /*
-        * Keypad event
-        * First and second data bytes list currently pressed keys,
-        * 0x00 means no key and at most 2 keys may be pressed at same time
-        */
-       int i, j;
-
-       /* determine newly pressed keys */
-       for (i = 0; i < size; i++) {
-               unsigned int key_code;
-               if (raw_data[i] == 0)
-                       continue;
-               for (j = 0; j < sizeof(data->pressed_keys); j++)
-                       if (data->pressed_keys[j] == raw_data[i])
-                               goto key_already_down;
-               for (j = 0; j < sizeof(data->pressed_keys); j++)
-                       if (data->pressed_keys[j] == 0) {
-                               data->pressed_keys[j] = raw_data[i];
-                               break;
-                       }
-               input_event(data->input_keys, EV_MSC, MSC_SCAN, raw_data[i]);
-               if (raw_data[i] < PICOLCD_KEYS)
-                       key_code = data->keycode[raw_data[i]];
-               else
-                       key_code = KEY_UNKNOWN;
-               if (key_code != KEY_UNKNOWN) {
-                       dbg_hid(PICOLCD_NAME " got key press for %u:%d",
-                                       raw_data[i], key_code);
-                       input_report_key(data->input_keys, key_code, 1);
-               }
-               input_sync(data->input_keys);
-key_already_down:
-               continue;
-       }
-
-       /* determine newly released keys */
-       for (j = 0; j < sizeof(data->pressed_keys); j++) {
-               unsigned int key_code;
-               if (data->pressed_keys[j] == 0)
-                       continue;
-               for (i = 0; i < size; i++)
-                       if (data->pressed_keys[j] == raw_data[i])
-                               goto key_still_down;
-               input_event(data->input_keys, EV_MSC, MSC_SCAN, data->pressed_keys[j]);
-               if (data->pressed_keys[j] < PICOLCD_KEYS)
-                       key_code = data->keycode[data->pressed_keys[j]];
-               else
-                       key_code = KEY_UNKNOWN;
-               if (key_code != KEY_UNKNOWN) {
-                       dbg_hid(PICOLCD_NAME " got key release for %u:%d",
-                                       data->pressed_keys[j], key_code);
-                       input_report_key(data->input_keys, key_code, 0);
-               }
-               input_sync(data->input_keys);
-               data->pressed_keys[j] = 0;
-key_still_down:
-               continue;
-       }
-       return 1;
-}
-
-static int picolcd_raw_cir(struct picolcd_data *data,
-               struct hid_report *report, u8 *raw_data, int size)
-{
-       /* Need understanding of CIR data format to implement ... */
-       return 1;
-}
-
-static int picolcd_check_version(struct hid_device *hdev)
-{
-       struct picolcd_data *data = hid_get_drvdata(hdev);
-       struct picolcd_pending *verinfo;
-       int ret = 0;
-
-       if (!data)
-               return -ENODEV;
-
-       verinfo = picolcd_send_and_wait(hdev, REPORT_VERSION, NULL, 0);
-       if (!verinfo) {
-               hid_err(hdev, "no version response from PicoLCD\n");
-               return -ENODEV;
-       }
-
-       if (verinfo->raw_size == 2) {
-               data->version[0] = verinfo->raw_data[1];
-               data->version[1] = verinfo->raw_data[0];
-               if (data->status & PICOLCD_BOOTLOADER) {
-                       hid_info(hdev, "PicoLCD, bootloader version %d.%d\n",
-                                verinfo->raw_data[1], verinfo->raw_data[0]);
-               } else {
-                       hid_info(hdev, "PicoLCD, firmware version %d.%d\n",
-                                verinfo->raw_data[1], verinfo->raw_data[0]);
-               }
-       } else {
-               hid_err(hdev, "confused, got unexpected version response from PicoLCD\n");
-               ret = -EINVAL;
-       }
-       kfree(verinfo);
-       return ret;
-}
-
-/*
- * Reset our device and wait for answer to VERSION request
- */
-static int picolcd_reset(struct hid_device *hdev)
-{
-       struct picolcd_data *data = hid_get_drvdata(hdev);
-       struct hid_report *report = picolcd_out_report(REPORT_RESET, hdev);
-       unsigned long flags;
-       int error;
-
-       if (!data || !report || report->maxfield != 1)
-               return -ENODEV;
-
-       spin_lock_irqsave(&data->lock, flags);
-       if (hdev->product == USB_DEVICE_ID_PICOLCD_BOOTLOADER)
-               data->status |= PICOLCD_BOOTLOADER;
-
-       /* perform the reset */
-       hid_set_field(report->field[0], 0, 1);
-       usbhid_submit_report(hdev, report, USB_DIR_OUT);
-       spin_unlock_irqrestore(&data->lock, flags);
-
-       error = picolcd_check_version(hdev);
-       if (error)
-               return error;
-
-       picolcd_resume_lcd(data);
-       picolcd_resume_backlight(data);
-#ifdef CONFIG_HID_PICOLCD_FB
-       if (data->fb_info)
-               schedule_delayed_work(&data->fb_info->deferred_work, 0);
-#endif /* CONFIG_HID_PICOLCD_FB */
-
-       picolcd_leds_set(data);
-       return 0;
-}
-
-/*
- * The "operation_mode" sysfs attribute
- */
-static ssize_t picolcd_operation_mode_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct picolcd_data *data = dev_get_drvdata(dev);
-
-       if (data->status & PICOLCD_BOOTLOADER)
-               return snprintf(buf, PAGE_SIZE, "[bootloader] lcd\n");
-       else
-               return snprintf(buf, PAGE_SIZE, "bootloader [lcd]\n");
-}
-
-static ssize_t picolcd_operation_mode_store(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t count)
-{
-       struct picolcd_data *data = dev_get_drvdata(dev);
-       struct hid_report *report = NULL;
-       size_t cnt = count;
-       int timeout = data->opmode_delay;
-       unsigned long flags;
-
-       if (cnt >= 3 && strncmp("lcd", buf, 3) == 0) {
-               if (data->status & PICOLCD_BOOTLOADER)
-                       report = picolcd_out_report(REPORT_EXIT_FLASHER, data->hdev);
-               buf += 3;
-               cnt -= 3;
-       } else if (cnt >= 10 && strncmp("bootloader", buf, 10) == 0) {
-               if (!(data->status & PICOLCD_BOOTLOADER))
-                       report = picolcd_out_report(REPORT_EXIT_KEYBOARD, data->hdev);
-               buf += 10;
-               cnt -= 10;
-       }
-       if (!report)
-               return -EINVAL;
-
-       while (cnt > 0 && (buf[cnt-1] == '\n' || buf[cnt-1] == '\r'))
-               cnt--;
-       if (cnt != 0)
-               return -EINVAL;
-
-       spin_lock_irqsave(&data->lock, flags);
-       hid_set_field(report->field[0], 0, timeout & 0xff);
-       hid_set_field(report->field[0], 1, (timeout >> 8) & 0xff);
-       usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
-       spin_unlock_irqrestore(&data->lock, flags);
-       return count;
-}
-
-static DEVICE_ATTR(operation_mode, 0644, picolcd_operation_mode_show,
-               picolcd_operation_mode_store);
-
-/*
- * The "operation_mode_delay" sysfs attribute
- */
-static ssize_t picolcd_operation_mode_delay_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct picolcd_data *data = dev_get_drvdata(dev);
-
-       return snprintf(buf, PAGE_SIZE, "%hu\n", data->opmode_delay);
-}
-
-static ssize_t picolcd_operation_mode_delay_store(struct device *dev,
-               struct device_attribute *attr, const char *buf, size_t count)
-{
-       struct picolcd_data *data = dev_get_drvdata(dev);
-       unsigned u;
-       if (sscanf(buf, "%u", &u) != 1)
-               return -EINVAL;
-       if (u > 30000)
-               return -EINVAL;
-       else
-               data->opmode_delay = u;
-       return count;
-}
-
-static DEVICE_ATTR(operation_mode_delay, 0644, picolcd_operation_mode_delay_show,
-               picolcd_operation_mode_delay_store);
-
-
-#ifdef CONFIG_DEBUG_FS
-/*
- * The "reset" file
- */
-static int picolcd_debug_reset_show(struct seq_file *f, void *p)
-{
-       if (picolcd_fbinfo((struct picolcd_data *)f->private))
-               seq_printf(f, "all fb\n");
-       else
-               seq_printf(f, "all\n");
-       return 0;
-}
-
-static int picolcd_debug_reset_open(struct inode *inode, struct file *f)
-{
-       return single_open(f, picolcd_debug_reset_show, inode->i_private);
-}
-
-static ssize_t picolcd_debug_reset_write(struct file *f, const char __user *user_buf,
-               size_t count, loff_t *ppos)
-{
-       struct picolcd_data *data = ((struct seq_file *)f->private_data)->private;
-       char buf[32];
-       size_t cnt = min(count, sizeof(buf)-1);
-       if (copy_from_user(buf, user_buf, cnt))
-               return -EFAULT;
-
-       while (cnt > 0 && (buf[cnt-1] == ' ' || buf[cnt-1] == '\n'))
-               cnt--;
-       buf[cnt] = '\0';
-       if (strcmp(buf, "all") == 0) {
-               picolcd_reset(data->hdev);
-               picolcd_fb_reset(data, 1);
-       } else if (strcmp(buf, "fb") == 0) {
-               picolcd_fb_reset(data, 1);
-       } else {
-               return -EINVAL;
-       }
-       return count;
-}
-
-static const struct file_operations picolcd_debug_reset_fops = {
-       .owner    = THIS_MODULE,
-       .open     = picolcd_debug_reset_open,
-       .read     = seq_read,
-       .llseek   = seq_lseek,
-       .write    = picolcd_debug_reset_write,
-       .release  = single_release,
-};
-
-/*
- * The "eeprom" file
- */
-static ssize_t picolcd_debug_eeprom_read(struct file *f, char __user *u,
-               size_t s, loff_t *off)
-{
-       struct picolcd_data *data = f->private_data;
-       struct picolcd_pending *resp;
-       u8 raw_data[3];
-       ssize_t ret = -EIO;
-
-       if (s == 0)
-               return -EINVAL;
-       if (*off > 0x0ff)
-               return 0;
-
-       /* prepare buffer with info about what we want to read (addr & len) */
-       raw_data[0] = *off & 0xff;
-       raw_data[1] = (*off >> 8) & 0xff;
-       raw_data[2] = s < 20 ? s : 20;
-       if (*off + raw_data[2] > 0xff)
-               raw_data[2] = 0x100 - *off;
-       resp = picolcd_send_and_wait(data->hdev, REPORT_EE_READ, raw_data,
-                       sizeof(raw_data));
-       if (!resp)
-               return -EIO;
-
-       if (resp->in_report && resp->in_report->id == REPORT_EE_DATA) {
-               /* successful read :) */
-               ret = resp->raw_data[2];
-               if (ret > s)
-                       ret = s;
-               if (copy_to_user(u, resp->raw_data+3, ret))
-                       ret = -EFAULT;
-               else
-                       *off += ret;
-       } /* anything else is some kind of IO error */
-
-       kfree(resp);
-       return ret;
-}
-
-static ssize_t picolcd_debug_eeprom_write(struct file *f, const char __user *u,
-               size_t s, loff_t *off)
-{
-       struct picolcd_data *data = f->private_data;
-       struct picolcd_pending *resp;
-       ssize_t ret = -EIO;
-       u8 raw_data[23];
-
-       if (s == 0)
-               return -EINVAL;
-       if (*off > 0x0ff)
-               return -ENOSPC;
-
-       memset(raw_data, 0, sizeof(raw_data));
-       raw_data[0] = *off & 0xff;
-       raw_data[1] = (*off >> 8) & 0xff;
-       raw_data[2] = min((size_t)20, s);
-       if (*off + raw_data[2] > 0xff)
-               raw_data[2] = 0x100 - *off;
-
-       if (copy_from_user(raw_data+3, u, min((u8)20, raw_data[2])))
-               return -EFAULT;
-       resp = picolcd_send_and_wait(data->hdev, REPORT_EE_WRITE, raw_data,
-                       sizeof(raw_data));
-
-       if (!resp)
-               return -EIO;
-
-       if (resp->in_report && resp->in_report->id == REPORT_EE_DATA) {
-               /* check if written data matches */
-               if (memcmp(raw_data, resp->raw_data, 3+raw_data[2]) == 0) {
-                       *off += raw_data[2];
-                       ret = raw_data[2];
-               }
-       }
-       kfree(resp);
-       return ret;
-}
-
-/*
- * Notes:
- * - read/write happens in chunks of at most 20 bytes, it's up to userspace
- *   to loop in order to get more data.
- * - on write errors on otherwise correct write request the bytes
- *   that should have been written are in undefined state.
- */
-static const struct file_operations picolcd_debug_eeprom_fops = {
-       .owner    = THIS_MODULE,
-       .open     = simple_open,
-       .read     = picolcd_debug_eeprom_read,
-       .write    = picolcd_debug_eeprom_write,
-       .llseek   = generic_file_llseek,
-};
-
-/*
- * The "flash" file
- */
-/* record a flash address to buf (bounds check to be done by caller) */
-static int _picolcd_flash_setaddr(struct picolcd_data *data, u8 *buf, long off)
-{
-       buf[0] = off & 0xff;
-       buf[1] = (off >> 8) & 0xff;
-       if (data->addr_sz == 3)
-               buf[2] = (off >> 16) & 0xff;
-       return data->addr_sz == 2 ? 2 : 3;
-}
-
-/* read a given size of data (bounds check to be done by caller) */
-static ssize_t _picolcd_flash_read(struct picolcd_data *data, int report_id,
-               char __user *u, size_t s, loff_t *off)
-{
-       struct picolcd_pending *resp;
-       u8 raw_data[4];
-       ssize_t ret = 0;
-       int len_off, err = -EIO;
-
-       while (s > 0) {
-               err = -EIO;
-               len_off = _picolcd_flash_setaddr(data, raw_data, *off);
-               raw_data[len_off] = s > 32 ? 32 : s;
-               resp = picolcd_send_and_wait(data->hdev, report_id, raw_data, len_off+1);
-               if (!resp || !resp->in_report)
-                       goto skip;
-               if (resp->in_report->id == REPORT_MEMORY ||
-                       resp->in_report->id == REPORT_BL_READ_MEMORY) {
-                       if (memcmp(raw_data, resp->raw_data, len_off+1) != 0)
-                               goto skip;
-                       if (copy_to_user(u+ret, resp->raw_data+len_off+1, raw_data[len_off])) {
-                               err = -EFAULT;
-                               goto skip;
-                       }
-                       *off += raw_data[len_off];
-                       s    -= raw_data[len_off];
-                       ret  += raw_data[len_off];
-                       err   = 0;
-               }
-skip:
-               kfree(resp);
-               if (err)
-                       return ret > 0 ? ret : err;
-       }
-       return ret;
-}
-
-static ssize_t picolcd_debug_flash_read(struct file *f, char __user *u,
-               size_t s, loff_t *off)
-{
-       struct picolcd_data *data = f->private_data;
-
-       if (s == 0)
-               return -EINVAL;
-       if (*off > 0x05fff)
-               return 0;
-       if (*off + s > 0x05fff)
-               s = 0x06000 - *off;
-
-       if (data->status & PICOLCD_BOOTLOADER)
-               return _picolcd_flash_read(data, REPORT_BL_READ_MEMORY, u, s, off);
-       else
-               return _picolcd_flash_read(data, REPORT_READ_MEMORY, u, s, off);
-}
-
-/* erase block aligned to 64bytes boundary */
-static ssize_t _picolcd_flash_erase64(struct picolcd_data *data, int report_id,
-               loff_t *off)
-{
-       struct picolcd_pending *resp;
-       u8 raw_data[3];
-       int len_off;
-       ssize_t ret = -EIO;
-
-       if (*off & 0x3f)
-               return -EINVAL;
-
-       len_off = _picolcd_flash_setaddr(data, raw_data, *off);
-       resp = picolcd_send_and_wait(data->hdev, report_id, raw_data, len_off);
-       if (!resp || !resp->in_report)
-               goto skip;
-       if (resp->in_report->id == REPORT_MEMORY ||
-               resp->in_report->id == REPORT_BL_ERASE_MEMORY) {
-               if (memcmp(raw_data, resp->raw_data, len_off) != 0)
-                       goto skip;
-               ret = 0;
-       }
-skip:
-       kfree(resp);
-       return ret;
-}
-
-/* write a given size of data (bounds check to be done by caller) */
-static ssize_t _picolcd_flash_write(struct picolcd_data *data, int report_id,
-               const char __user *u, size_t s, loff_t *off)
-{
-       struct picolcd_pending *resp;
-       u8 raw_data[36];
-       ssize_t ret = 0;
-       int len_off, err = -EIO;
-
-       while (s > 0) {
-               err = -EIO;
-               len_off = _picolcd_flash_setaddr(data, raw_data, *off);
-               raw_data[len_off] = s > 32 ? 32 : s;
-               if (copy_from_user(raw_data+len_off+1, u, raw_data[len_off])) {
-                       err = -EFAULT;
-                       break;
-               }
-               resp = picolcd_send_and_wait(data->hdev, report_id, raw_data,
-                               len_off+1+raw_data[len_off]);
-               if (!resp || !resp->in_report)
-                       goto skip;
-               if (resp->in_report->id == REPORT_MEMORY ||
-                       resp->in_report->id == REPORT_BL_WRITE_MEMORY) {
-                       if (memcmp(raw_data, resp->raw_data, len_off+1+raw_data[len_off]) != 0)
-                               goto skip;
-                       *off += raw_data[len_off];
-                       s    -= raw_data[len_off];
-                       ret  += raw_data[len_off];
-                       err   = 0;
-               }
-skip:
-               kfree(resp);
-               if (err)
-                       break;
-       }
-       return ret > 0 ? ret : err;
-}
-
-static ssize_t picolcd_debug_flash_write(struct file *f, const char __user *u,
-               size_t s, loff_t *off)
-{
-       struct picolcd_data *data = f->private_data;
-       ssize_t err, ret = 0;
-       int report_erase, report_write;
-
-       if (s == 0)
-               return -EINVAL;
-       if (*off > 0x5fff)
-               return -ENOSPC;
-       if (s & 0x3f)
-               return -EINVAL;
-       if (*off & 0x3f)
-               return -EINVAL;
-
-       if (data->status & PICOLCD_BOOTLOADER) {
-               report_erase = REPORT_BL_ERASE_MEMORY;
-               report_write = REPORT_BL_WRITE_MEMORY;
-       } else {
-               report_erase = REPORT_ERASE_MEMORY;
-               report_write = REPORT_WRITE_MEMORY;
-       }
-       mutex_lock(&data->mutex_flash);
-       while (s > 0) {
-               err = _picolcd_flash_erase64(data, report_erase, off);
-               if (err)
-                       break;
-               err = _picolcd_flash_write(data, report_write, u, 64, off);
-               if (err < 0)
-                       break;
-               ret += err;
-               *off += err;
-               s -= err;
-               if (err != 64)
-                       break;
-       }
-       mutex_unlock(&data->mutex_flash);
-       return ret > 0 ? ret : err;
-}
-
-/*
- * Notes:
- * - concurrent writing is prevented by mutex and all writes must be
- *   n*64 bytes and 64-byte aligned, each write being preceded by an
- *   ERASE which erases a 64byte block.
- *   If less than requested was written or an error is returned for an
- *   otherwise correct write request the next 64-byte block which should
- *   have been written is in undefined state (mostly: original, erased,
- *   (half-)written with write error)
- * - reading can happen without special restriction
- */
-static const struct file_operations picolcd_debug_flash_fops = {
-       .owner    = THIS_MODULE,
-       .open     = simple_open,
-       .read     = picolcd_debug_flash_read,
-       .write    = picolcd_debug_flash_write,
-       .llseek   = generic_file_llseek,
-};
-
-
-/*
- * Helper code for HID report level dumping/debugging
- */
-static const char *error_codes[] = {
-       "success", "parameter missing", "data_missing", "block readonly",
-       "block not erasable", "block too big", "section overflow",
-       "invalid command length", "invalid data length",
-};
-
-static void dump_buff_as_hex(char *dst, size_t dst_sz, const u8 *data,
-               const size_t data_len)
-{
-       int i, j;
-       for (i = j = 0; i < data_len && j + 3 < dst_sz; i++) {
-               dst[j++] = hex_asc[(data[i] >> 4) & 0x0f];
-               dst[j++] = hex_asc[data[i] & 0x0f];
-               dst[j++] = ' ';
-       }
-       if (j < dst_sz) {
-               dst[j--] = '\0';
-               dst[j] = '\n';
-       } else
-               dst[j] = '\0';
-}
-
-static void picolcd_debug_out_report(struct picolcd_data *data,
-               struct hid_device *hdev, struct hid_report *report)
-{
-       u8 raw_data[70];
-       int raw_size = (report->size >> 3) + 1;
-       char *buff;
-#define BUFF_SZ 256
-
-       /* Avoid unnecessary overhead if debugfs is disabled */
-       if (list_empty(&hdev->debug_list))
-               return;
-
-       buff = kmalloc(BUFF_SZ, GFP_ATOMIC);
-       if (!buff)
-               return;
-
-       snprintf(buff, BUFF_SZ, "\nout report %d (size %d) =  ",
-                       report->id, raw_size);
-       hid_debug_event(hdev, buff);
-       if (raw_size + 5 > sizeof(raw_data)) {
-               kfree(buff);
-               hid_debug_event(hdev, " TOO BIG\n");
-               return;
-       } else {
-               raw_data[0] = report->id;
-               hid_output_report(report, raw_data);
-               dump_buff_as_hex(buff, BUFF_SZ, raw_data, raw_size);
-               hid_debug_event(hdev, buff);
-       }
-
-       switch (report->id) {
-       case REPORT_LED_STATE:
-               /* 1 data byte with GPO state */
-               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-                       "REPORT_LED_STATE", report->id, raw_size-1);
-               hid_debug_event(hdev, buff);
-               snprintf(buff, BUFF_SZ, "\tGPO state: 0x%02x\n", raw_data[1]);
-               hid_debug_event(hdev, buff);
-               break;
-       case REPORT_BRIGHTNESS:
-               /* 1 data byte with brightness */
-               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-                       "REPORT_BRIGHTNESS", report->id, raw_size-1);
-               hid_debug_event(hdev, buff);
-               snprintf(buff, BUFF_SZ, "\tBrightness: 0x%02x\n", raw_data[1]);
-               hid_debug_event(hdev, buff);
-               break;
-       case REPORT_CONTRAST:
-               /* 1 data byte with contrast */
-               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-                       "REPORT_CONTRAST", report->id, raw_size-1);
-               hid_debug_event(hdev, buff);
-               snprintf(buff, BUFF_SZ, "\tContrast: 0x%02x\n", raw_data[1]);
-               hid_debug_event(hdev, buff);
-               break;
-       case REPORT_RESET:
-               /* 2 data bytes with reset duration in ms */
-               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-                       "REPORT_RESET", report->id, raw_size-1);
-               hid_debug_event(hdev, buff);
-               snprintf(buff, BUFF_SZ, "\tDuration: 0x%02x%02x (%dms)\n",
-                               raw_data[2], raw_data[1], raw_data[2] << 8 | raw_data[1]);
-               hid_debug_event(hdev, buff);
-               break;
-       case REPORT_LCD_CMD:
-               /* 63 data bytes with LCD commands */
-               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-                       "REPORT_LCD_CMD", report->id, raw_size-1);
-               hid_debug_event(hdev, buff);
-               /* TODO: format decoding */
-               break;
-       case REPORT_LCD_DATA:
-               /* 63 data bytes with LCD data */
-               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-                       "REPORT_LCD_CMD", report->id, raw_size-1);
-               /* TODO: format decoding */
-               hid_debug_event(hdev, buff);
-               break;
-       case REPORT_LCD_CMD_DATA:
-               /* 63 data bytes with LCD commands and data */
-               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-                       "REPORT_LCD_CMD", report->id, raw_size-1);
-               /* TODO: format decoding */
-               hid_debug_event(hdev, buff);
-               break;
-       case REPORT_EE_READ:
-               /* 3 data bytes with read area description */
-               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-                       "REPORT_EE_READ", report->id, raw_size-1);
-               hid_debug_event(hdev, buff);
-               snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
-                               raw_data[2], raw_data[1]);
-               hid_debug_event(hdev, buff);
-               snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
-               hid_debug_event(hdev, buff);
-               break;
-       case REPORT_EE_WRITE:
-               /* 3+1..20 data bytes with write area description */
-               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-                       "REPORT_EE_WRITE", report->id, raw_size-1);
-               hid_debug_event(hdev, buff);
-               snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
-                               raw_data[2], raw_data[1]);
-               hid_debug_event(hdev, buff);
-               snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
-               hid_debug_event(hdev, buff);
-               if (raw_data[3] == 0) {
-                       snprintf(buff, BUFF_SZ, "\tNo data\n");
-               } else if (raw_data[3] + 4 <= raw_size) {
-                       snprintf(buff, BUFF_SZ, "\tData: ");
-                       hid_debug_event(hdev, buff);
-                       dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]);
-               } else {
-                       snprintf(buff, BUFF_SZ, "\tData overflowed\n");
-               }
-               hid_debug_event(hdev, buff);
-               break;
-       case REPORT_ERASE_MEMORY:
-       case REPORT_BL_ERASE_MEMORY:
-               /* 3 data bytes with pointer inside erase block */
-               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-                       "REPORT_ERASE_MEMORY", report->id, raw_size-1);
-               hid_debug_event(hdev, buff);
-               switch (data->addr_sz) {
-               case 2:
-                       snprintf(buff, BUFF_SZ, "\tAddress inside 64 byte block: 0x%02x%02x\n",
-                                       raw_data[2], raw_data[1]);
-                       break;
-               case 3:
-                       snprintf(buff, BUFF_SZ, "\tAddress inside 64 byte block: 0x%02x%02x%02x\n",
-                                       raw_data[3], raw_data[2], raw_data[1]);
-                       break;
-               default:
-                       snprintf(buff, BUFF_SZ, "\tNot supported\n");
-               }
-               hid_debug_event(hdev, buff);
-               break;
-       case REPORT_READ_MEMORY:
-       case REPORT_BL_READ_MEMORY:
-               /* 4 data bytes with read area description */
-               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-                       "REPORT_READ_MEMORY", report->id, raw_size-1);
-               hid_debug_event(hdev, buff);
-               switch (data->addr_sz) {
-               case 2:
-                       snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
-                                       raw_data[2], raw_data[1]);
-                       hid_debug_event(hdev, buff);
-                       snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
-                       break;
-               case 3:
-                       snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x%02x\n",
-                                       raw_data[3], raw_data[2], raw_data[1]);
-                       hid_debug_event(hdev, buff);
-                       snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[4]);
-                       break;
-               default:
-                       snprintf(buff, BUFF_SZ, "\tNot supported\n");
-               }
-               hid_debug_event(hdev, buff);
-               break;
-       case REPORT_WRITE_MEMORY:
-       case REPORT_BL_WRITE_MEMORY:
-               /* 4+1..32 data bytes with write adrea description */
-               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-                       "REPORT_WRITE_MEMORY", report->id, raw_size-1);
-               hid_debug_event(hdev, buff);
-               switch (data->addr_sz) {
-               case 2:
-                       snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
-                                       raw_data[2], raw_data[1]);
-                       hid_debug_event(hdev, buff);
-                       snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
-                       hid_debug_event(hdev, buff);
-                       if (raw_data[3] == 0) {
-                               snprintf(buff, BUFF_SZ, "\tNo data\n");
-                       } else if (raw_data[3] + 4 <= raw_size) {
-                               snprintf(buff, BUFF_SZ, "\tData: ");
-                               hid_debug_event(hdev, buff);
-                               dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]);
-                       } else {
-                               snprintf(buff, BUFF_SZ, "\tData overflowed\n");
-                       }
-                       break;
-               case 3:
-                       snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x%02x\n",
-                                       raw_data[3], raw_data[2], raw_data[1]);
-                       hid_debug_event(hdev, buff);
-                       snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[4]);
-                       hid_debug_event(hdev, buff);
-                       if (raw_data[4] == 0) {
-                               snprintf(buff, BUFF_SZ, "\tNo data\n");
-                       } else if (raw_data[4] + 5 <= raw_size) {
-                               snprintf(buff, BUFF_SZ, "\tData: ");
-                               hid_debug_event(hdev, buff);
-                               dump_buff_as_hex(buff, BUFF_SZ, raw_data+5, raw_data[4]);
-                       } else {
-                               snprintf(buff, BUFF_SZ, "\tData overflowed\n");
-                       }
-                       break;
-               default:
-                       snprintf(buff, BUFF_SZ, "\tNot supported\n");
-               }
-               hid_debug_event(hdev, buff);
-               break;
-       case REPORT_SPLASH_RESTART:
-               /* TODO */
-               break;
-       case REPORT_EXIT_KEYBOARD:
-               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-                       "REPORT_EXIT_KEYBOARD", report->id, raw_size-1);
-               hid_debug_event(hdev, buff);
-               snprintf(buff, BUFF_SZ, "\tRestart delay: %dms (0x%02x%02x)\n",
-                               raw_data[1] | (raw_data[2] << 8),
-                               raw_data[2], raw_data[1]);
-               hid_debug_event(hdev, buff);
-               break;
-       case REPORT_VERSION:
-               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-                       "REPORT_VERSION", report->id, raw_size-1);
-               hid_debug_event(hdev, buff);
-               break;
-       case REPORT_DEVID:
-               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-                       "REPORT_DEVID", report->id, raw_size-1);
-               hid_debug_event(hdev, buff);
-               break;
-       case REPORT_SPLASH_SIZE:
-               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-                       "REPORT_SPLASH_SIZE", report->id, raw_size-1);
-               hid_debug_event(hdev, buff);
-               break;
-       case REPORT_HOOK_VERSION:
-               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-                       "REPORT_HOOK_VERSION", report->id, raw_size-1);
-               hid_debug_event(hdev, buff);
-               break;
-       case REPORT_EXIT_FLASHER:
-               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-                       "REPORT_VERSION", report->id, raw_size-1);
-               hid_debug_event(hdev, buff);
-               snprintf(buff, BUFF_SZ, "\tRestart delay: %dms (0x%02x%02x)\n",
-                               raw_data[1] | (raw_data[2] << 8),
-                               raw_data[2], raw_data[1]);
-               hid_debug_event(hdev, buff);
-               break;
-       default:
-               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
-                       "<unknown>", report->id, raw_size-1);
-               hid_debug_event(hdev, buff);
-               break;
-       }
-       wake_up_interruptible(&hdev->debug_wait);
-       kfree(buff);
-}
-
-static void picolcd_debug_raw_event(struct picolcd_data *data,
-               struct hid_device *hdev, struct hid_report *report,
-               u8 *raw_data, int size)
-{
-       char *buff;
-
-#define BUFF_SZ 256
-       /* Avoid unnecessary overhead if debugfs is disabled */
-       if (!hdev->debug_events)
-               return;
-
-       buff = kmalloc(BUFF_SZ, GFP_ATOMIC);
-       if (!buff)
-               return;
-
-       switch (report->id) {
-       case REPORT_ERROR_CODE:
-               /* 2 data bytes with affected report and error code */
-               snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-                       "REPORT_ERROR_CODE", report->id, size-1);
-               hid_debug_event(hdev, buff);
-               if (raw_data[2] < ARRAY_SIZE(error_codes))
-                       snprintf(buff, BUFF_SZ, "\tError code 0x%02x (%s) in reply to report 0x%02x\n",
-                                       raw_data[2], error_codes[raw_data[2]], raw_data[1]);
-               else
-                       snprintf(buff, BUFF_SZ, "\tError code 0x%02x in reply to report 0x%02x\n",
-                                       raw_data[2], raw_data[1]);
-               hid_debug_event(hdev, buff);
-               break;
-       case REPORT_KEY_STATE:
-               /* 2 data bytes with key state */
-               snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-                       "REPORT_KEY_STATE", report->id, size-1);
-               hid_debug_event(hdev, buff);
-               if (raw_data[1] == 0)
-                       snprintf(buff, BUFF_SZ, "\tNo key pressed\n");
-               else if (raw_data[2] == 0)
-                       snprintf(buff, BUFF_SZ, "\tOne key pressed: 0x%02x (%d)\n",
-                                       raw_data[1], raw_data[1]);
-               else
-                       snprintf(buff, BUFF_SZ, "\tTwo keys pressed: 0x%02x (%d), 0x%02x (%d)\n",
-                                       raw_data[1], raw_data[1], raw_data[2], raw_data[2]);
-               hid_debug_event(hdev, buff);
-               break;
-       case REPORT_IR_DATA:
-               /* Up to 20 byes of IR scancode data */
-               snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-                       "REPORT_IR_DATA", report->id, size-1);
-               hid_debug_event(hdev, buff);
-               if (raw_data[1] == 0) {
-                       snprintf(buff, BUFF_SZ, "\tUnexpectedly 0 data length\n");
-                       hid_debug_event(hdev, buff);
-               } else if (raw_data[1] + 1 <= size) {
-                       snprintf(buff, BUFF_SZ, "\tData length: %d\n\tIR Data: ",
-                                       raw_data[1]-1);
-                       hid_debug_event(hdev, buff);
-                       dump_buff_as_hex(buff, BUFF_SZ, raw_data+2, raw_data[1]-1);
-                       hid_debug_event(hdev, buff);
-               } else {
-                       snprintf(buff, BUFF_SZ, "\tOverflowing data length: %d\n",
-                                       raw_data[1]-1);
-                       hid_debug_event(hdev, buff);
-               }
-               break;
-       case REPORT_EE_DATA:
-               /* Data buffer in response to REPORT_EE_READ or REPORT_EE_WRITE */
-               snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-                       "REPORT_EE_DATA", report->id, size-1);
-               hid_debug_event(hdev, buff);
-               snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
-                               raw_data[2], raw_data[1]);
-               hid_debug_event(hdev, buff);
-               snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
-               hid_debug_event(hdev, buff);
-               if (raw_data[3] == 0) {
-                       snprintf(buff, BUFF_SZ, "\tNo data\n");
-                       hid_debug_event(hdev, buff);
-               } else if (raw_data[3] + 4 <= size) {
-                       snprintf(buff, BUFF_SZ, "\tData: ");
-                       hid_debug_event(hdev, buff);
-                       dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]);
-                       hid_debug_event(hdev, buff);
-               } else {
-                       snprintf(buff, BUFF_SZ, "\tData overflowed\n");
-                       hid_debug_event(hdev, buff);
-               }
-               break;
-       case REPORT_MEMORY:
-               /* Data buffer in response to REPORT_READ_MEMORY or REPORT_WRTIE_MEMORY */
-               snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-                       "REPORT_MEMORY", report->id, size-1);
-               hid_debug_event(hdev, buff);
-               switch (data->addr_sz) {
-               case 2:
-                       snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
-                                       raw_data[2], raw_data[1]);
-                       hid_debug_event(hdev, buff);
-                       snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
-                       hid_debug_event(hdev, buff);
-                       if (raw_data[3] == 0) {
-                               snprintf(buff, BUFF_SZ, "\tNo data\n");
-                       } else if (raw_data[3] + 4 <= size) {
-                               snprintf(buff, BUFF_SZ, "\tData: ");
-                               hid_debug_event(hdev, buff);
-                               dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]);
-                       } else {
-                               snprintf(buff, BUFF_SZ, "\tData overflowed\n");
-                       }
-                       break;
-               case 3:
-                       snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x%02x\n",
-                                       raw_data[3], raw_data[2], raw_data[1]);
-                       hid_debug_event(hdev, buff);
-                       snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[4]);
-                       hid_debug_event(hdev, buff);
-                       if (raw_data[4] == 0) {
-                               snprintf(buff, BUFF_SZ, "\tNo data\n");
-                       } else if (raw_data[4] + 5 <= size) {
-                               snprintf(buff, BUFF_SZ, "\tData: ");
-                               hid_debug_event(hdev, buff);
-                               dump_buff_as_hex(buff, BUFF_SZ, raw_data+5, raw_data[4]);
-                       } else {
-                               snprintf(buff, BUFF_SZ, "\tData overflowed\n");
-                       }
-                       break;
-               default:
-                       snprintf(buff, BUFF_SZ, "\tNot supported\n");
-               }
-               hid_debug_event(hdev, buff);
-               break;
-       case REPORT_VERSION:
-               snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-                       "REPORT_VERSION", report->id, size-1);
-               hid_debug_event(hdev, buff);
-               snprintf(buff, BUFF_SZ, "\tFirmware version: %d.%d\n",
-                               raw_data[2], raw_data[1]);
-               hid_debug_event(hdev, buff);
-               break;
-       case REPORT_BL_ERASE_MEMORY:
-               snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-                       "REPORT_BL_ERASE_MEMORY", report->id, size-1);
-               hid_debug_event(hdev, buff);
-               /* TODO */
-               break;
-       case REPORT_BL_READ_MEMORY:
-               snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-                       "REPORT_BL_READ_MEMORY", report->id, size-1);
-               hid_debug_event(hdev, buff);
-               /* TODO */
-               break;
-       case REPORT_BL_WRITE_MEMORY:
-               snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-                       "REPORT_BL_WRITE_MEMORY", report->id, size-1);
-               hid_debug_event(hdev, buff);
-               /* TODO */
-               break;
-       case REPORT_DEVID:
-               snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-                       "REPORT_DEVID", report->id, size-1);
-               hid_debug_event(hdev, buff);
-               snprintf(buff, BUFF_SZ, "\tSerial: 0x%02x%02x%02x%02x\n",
-                               raw_data[1], raw_data[2], raw_data[3], raw_data[4]);
-               hid_debug_event(hdev, buff);
-               snprintf(buff, BUFF_SZ, "\tType: 0x%02x\n",
-                               raw_data[5]);
-               hid_debug_event(hdev, buff);
-               break;
-       case REPORT_SPLASH_SIZE:
-               snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-                       "REPORT_SPLASH_SIZE", report->id, size-1);
-               hid_debug_event(hdev, buff);
-               snprintf(buff, BUFF_SZ, "\tTotal splash space: %d\n",
-                               (raw_data[2] << 8) | raw_data[1]);
-               hid_debug_event(hdev, buff);
-               snprintf(buff, BUFF_SZ, "\tUsed splash space: %d\n",
-                               (raw_data[4] << 8) | raw_data[3]);
-               hid_debug_event(hdev, buff);
-               break;
-       case REPORT_HOOK_VERSION:
-               snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-                       "REPORT_HOOK_VERSION", report->id, size-1);
-               hid_debug_event(hdev, buff);
-               snprintf(buff, BUFF_SZ, "\tFirmware version: %d.%d\n",
-                               raw_data[1], raw_data[2]);
-               hid_debug_event(hdev, buff);
-               break;
-       default:
-               snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
-                       "<unknown>", report->id, size-1);
-               hid_debug_event(hdev, buff);
-               break;
-       }
-       wake_up_interruptible(&hdev->debug_wait);
-       kfree(buff);
-}
-
-static void picolcd_init_devfs(struct picolcd_data *data,
-               struct hid_report *eeprom_r, struct hid_report *eeprom_w,
-               struct hid_report *flash_r, struct hid_report *flash_w,
-               struct hid_report *reset)
-{
-       struct hid_device *hdev = data->hdev;
-
-       mutex_init(&data->mutex_flash);
-
-       /* reset */
-       if (reset)
-               data->debug_reset = debugfs_create_file("reset", 0600,
-                               hdev->debug_dir, data, &picolcd_debug_reset_fops);
-
-       /* eeprom */
-       if (eeprom_r || eeprom_w)
-               data->debug_eeprom = debugfs_create_file("eeprom",
-                       (eeprom_w ? S_IWUSR : 0) | (eeprom_r ? S_IRUSR : 0),
-                       hdev->debug_dir, data, &picolcd_debug_eeprom_fops);
-
-       /* flash */
-       if (flash_r && flash_r->maxfield == 1 && flash_r->field[0]->report_size == 8)
-               data->addr_sz = flash_r->field[0]->report_count - 1;
-       else
-               data->addr_sz = -1;
-       if (data->addr_sz == 2 || data->addr_sz == 3) {
-               data->debug_flash = debugfs_create_file("flash",
-                       (flash_w ? S_IWUSR : 0) | (flash_r ? S_IRUSR : 0),
-                       hdev->debug_dir, data, &picolcd_debug_flash_fops);
-       } else if (flash_r || flash_w)
-               hid_warn(hdev, "Unexpected FLASH access reports, please submit rdesc for review\n");
-}
-
-static void picolcd_exit_devfs(struct picolcd_data *data)
-{
-       struct dentry *dent;
-
-       dent = data->debug_reset;
-       data->debug_reset = NULL;
-       if (dent)
-               debugfs_remove(dent);
-       dent = data->debug_eeprom;
-       data->debug_eeprom = NULL;
-       if (dent)
-               debugfs_remove(dent);
-       dent = data->debug_flash;
-       data->debug_flash = NULL;
-       if (dent)
-               debugfs_remove(dent);
-       mutex_destroy(&data->mutex_flash);
-}
-#else
-static inline void picolcd_debug_raw_event(struct picolcd_data *data,
-               struct hid_device *hdev, struct hid_report *report,
-               u8 *raw_data, int size)
-{
-}
-static inline void picolcd_init_devfs(struct picolcd_data *data,
-               struct hid_report *eeprom_r, struct hid_report *eeprom_w,
-               struct hid_report *flash_r, struct hid_report *flash_w,
-               struct hid_report *reset)
-{
-}
-static inline void picolcd_exit_devfs(struct picolcd_data *data)
-{
-}
-#endif /* CONFIG_DEBUG_FS */
-
-/*
- * Handle raw report as sent by device
- */
-static int picolcd_raw_event(struct hid_device *hdev,
-               struct hid_report *report, u8 *raw_data, int size)
-{
-       struct picolcd_data *data = hid_get_drvdata(hdev);
-       unsigned long flags;
-       int ret = 0;
-
-       if (!data)
-               return 1;
-
-       if (report->id == REPORT_KEY_STATE) {
-               if (data->input_keys)
-                       ret = picolcd_raw_keypad(data, report, raw_data+1, size-1);
-       } else if (report->id == REPORT_IR_DATA) {
-               if (data->input_cir)
-                       ret = picolcd_raw_cir(data, report, raw_data+1, size-1);
-       } else {
-               spin_lock_irqsave(&data->lock, flags);
-               /*
-                * We let the caller of picolcd_send_and_wait() check if the
-                * report we got is one of the expected ones or not.
-                */
-               if (data->pending) {
-                       memcpy(data->pending->raw_data, raw_data+1, size-1);
-                       data->pending->raw_size  = size-1;
-                       data->pending->in_report = report;
-                       complete(&data->pending->ready);
-               }
-               spin_unlock_irqrestore(&data->lock, flags);
-       }
-
-       picolcd_debug_raw_event(data, hdev, report, raw_data, size);
-       return 1;
-}
-
-#ifdef CONFIG_PM
-static int picolcd_suspend(struct hid_device *hdev, pm_message_t message)
-{
-       if (PMSG_IS_AUTO(message))
-               return 0;
-
-       picolcd_suspend_backlight(hid_get_drvdata(hdev));
-       dbg_hid(PICOLCD_NAME " device ready for suspend\n");
-       return 0;
-}
-
-static int picolcd_resume(struct hid_device *hdev)
-{
-       int ret;
-       ret = picolcd_resume_backlight(hid_get_drvdata(hdev));
-       if (ret)
-               dbg_hid(PICOLCD_NAME " restoring backlight failed: %d\n", ret);
-       return 0;
-}
-
-static int picolcd_reset_resume(struct hid_device *hdev)
-{
-       int ret;
-       ret = picolcd_reset(hdev);
-       if (ret)
-               dbg_hid(PICOLCD_NAME " resetting our device failed: %d\n", ret);
-       ret = picolcd_fb_reset(hid_get_drvdata(hdev), 0);
-       if (ret)
-               dbg_hid(PICOLCD_NAME " restoring framebuffer content failed: %d\n", ret);
-       ret = picolcd_resume_lcd(hid_get_drvdata(hdev));
-       if (ret)
-               dbg_hid(PICOLCD_NAME " restoring lcd failed: %d\n", ret);
-       ret = picolcd_resume_backlight(hid_get_drvdata(hdev));
-       if (ret)
-               dbg_hid(PICOLCD_NAME " restoring backlight failed: %d\n", ret);
-       picolcd_leds_set(hid_get_drvdata(hdev));
-       return 0;
-}
-#endif
-
-/* initialize keypad input device */
-static int picolcd_init_keys(struct picolcd_data *data,
-               struct hid_report *report)
-{
-       struct hid_device *hdev = data->hdev;
-       struct input_dev *idev;
-       int error, i;
-
-       if (!report)
-               return -ENODEV;
-       if (report->maxfield != 1 || report->field[0]->report_count != 2 ||
-                       report->field[0]->report_size != 8) {
-               hid_err(hdev, "unsupported KEY_STATE report\n");
-               return -EINVAL;
-       }
-
-       idev = input_allocate_device();
-       if (idev == NULL) {
-               hid_err(hdev, "failed to allocate input device\n");
-               return -ENOMEM;
-       }
-       input_set_drvdata(idev, hdev);
-       memcpy(data->keycode, def_keymap, sizeof(def_keymap));
-       idev->name = hdev->name;
-       idev->phys = hdev->phys;
-       idev->uniq = hdev->uniq;
-       idev->id.bustype = hdev->bus;
-       idev->id.vendor  = hdev->vendor;
-       idev->id.product = hdev->product;
-       idev->id.version = hdev->version;
-       idev->dev.parent = hdev->dev.parent;
-       idev->keycode     = &data->keycode;
-       idev->keycodemax  = PICOLCD_KEYS;
-       idev->keycodesize = sizeof(data->keycode[0]);
-       input_set_capability(idev, EV_MSC, MSC_SCAN);
-       set_bit(EV_REP, idev->evbit);
-       for (i = 0; i < PICOLCD_KEYS; i++)
-               input_set_capability(idev, EV_KEY, data->keycode[i]);
-       error = input_register_device(idev);
-       if (error) {
-               hid_err(hdev, "error registering the input device\n");
-               input_free_device(idev);
-               return error;
-       }
-       data->input_keys = idev;
-       return 0;
-}
-
-static void picolcd_exit_keys(struct picolcd_data *data)
-{
-       struct input_dev *idev = data->input_keys;
-
-       data->input_keys = NULL;
-       if (idev)
-               input_unregister_device(idev);
-}
-
-/* initialize CIR input device */
-static inline int picolcd_init_cir(struct picolcd_data *data, struct hid_report *report)
-{
-       /* support not implemented yet */
-       return 0;
-}
-
-static inline void picolcd_exit_cir(struct picolcd_data *data)
-{
-}
-
-static int picolcd_probe_lcd(struct hid_device *hdev, struct picolcd_data *data)
-{
-       int error;
-
-       error = picolcd_check_version(hdev);
-       if (error)
-               return error;
-
-       if (data->version[0] != 0 && data->version[1] != 3)
-               hid_info(hdev, "Device with untested firmware revision, please submit /sys/kernel/debug/hid/%s/rdesc for this device.\n",
-                        dev_name(&hdev->dev));
-
-       /* Setup keypad input device */
-       error = picolcd_init_keys(data, picolcd_in_report(REPORT_KEY_STATE, hdev));
-       if (error)
-               goto err;
-
-       /* Setup CIR input device */
-       error = picolcd_init_cir(data, picolcd_in_report(REPORT_IR_DATA, hdev));
-       if (error)
-               goto err;
-
-       /* Set up the framebuffer device */
-       error = picolcd_init_framebuffer(data);
-       if (error)
-               goto err;
-
-       /* Setup lcd class device */
-       error = picolcd_init_lcd(data, picolcd_out_report(REPORT_CONTRAST, hdev));
-       if (error)
-               goto err;
-
-       /* Setup backlight class device */
-       error = picolcd_init_backlight(data, picolcd_out_report(REPORT_BRIGHTNESS, hdev));
-       if (error)
-               goto err;
-
-       /* Setup the LED class devices */
-       error = picolcd_init_leds(data, picolcd_out_report(REPORT_LED_STATE, hdev));
-       if (error)
-               goto err;
-
-       picolcd_init_devfs(data, picolcd_out_report(REPORT_EE_READ, hdev),
-                       picolcd_out_report(REPORT_EE_WRITE, hdev),
-                       picolcd_out_report(REPORT_READ_MEMORY, hdev),
-                       picolcd_out_report(REPORT_WRITE_MEMORY, hdev),
-                       picolcd_out_report(REPORT_RESET, hdev));
-       return 0;
-err:
-       picolcd_exit_leds(data);
-       picolcd_exit_backlight(data);
-       picolcd_exit_lcd(data);
-       picolcd_exit_framebuffer(data);
-       picolcd_exit_cir(data);
-       picolcd_exit_keys(data);
-       return error;
-}
-
-static int picolcd_probe_bootloader(struct hid_device *hdev, struct picolcd_data *data)
-{
-       int error;
-
-       error = picolcd_check_version(hdev);
-       if (error)
-               return error;
-
-       if (data->version[0] != 1 && data->version[1] != 0)
-               hid_info(hdev, "Device with untested bootloader revision, please submit /sys/kernel/debug/hid/%s/rdesc for this device.\n",
-                        dev_name(&hdev->dev));
-
-       picolcd_init_devfs(data, NULL, NULL,
-                       picolcd_out_report(REPORT_BL_READ_MEMORY, hdev),
-                       picolcd_out_report(REPORT_BL_WRITE_MEMORY, hdev), NULL);
-       return 0;
-}
-
-static int picolcd_probe(struct hid_device *hdev,
-                    const struct hid_device_id *id)
-{
-       struct picolcd_data *data;
-       int error = -ENOMEM;
-
-       dbg_hid(PICOLCD_NAME " hardware probe...\n");
-
-       /*
-        * Let's allocate the picolcd data structure, set some reasonable
-        * defaults, and associate it with the device
-        */
-       data = kzalloc(sizeof(struct picolcd_data), GFP_KERNEL);
-       if (data == NULL) {
-               hid_err(hdev, "can't allocate space for Minibox PicoLCD device data\n");
-               error = -ENOMEM;
-               goto err_no_cleanup;
-       }
-
-       spin_lock_init(&data->lock);
-       mutex_init(&data->mutex);
-       data->hdev = hdev;
-       data->opmode_delay = 5000;
-       if (hdev->product == USB_DEVICE_ID_PICOLCD_BOOTLOADER)
-               data->status |= PICOLCD_BOOTLOADER;
-       hid_set_drvdata(hdev, data);
-
-       /* Parse the device reports and start it up */
-       error = hid_parse(hdev);
-       if (error) {
-               hid_err(hdev, "device report parse failed\n");
-               goto err_cleanup_data;
-       }
-
-       error = hid_hw_start(hdev, 0);
-       if (error) {
-               hid_err(hdev, "hardware start failed\n");
-               goto err_cleanup_data;
-       }
-
-       error = hid_hw_open(hdev);
-       if (error) {
-               hid_err(hdev, "failed to open input interrupt pipe for key and IR events\n");
-               goto err_cleanup_hid_hw;
-       }
-
-       error = device_create_file(&hdev->dev, &dev_attr_operation_mode_delay);
-       if (error) {
-               hid_err(hdev, "failed to create sysfs attributes\n");
-               goto err_cleanup_hid_ll;
-       }
-
-       error = device_create_file(&hdev->dev, &dev_attr_operation_mode);
-       if (error) {
-               hid_err(hdev, "failed to create sysfs attributes\n");
-               goto err_cleanup_sysfs1;
-       }
-
-       if (data->status & PICOLCD_BOOTLOADER)
-               error = picolcd_probe_bootloader(hdev, data);
-       else
-               error = picolcd_probe_lcd(hdev, data);
-       if (error)
-               goto err_cleanup_sysfs2;
-
-       dbg_hid(PICOLCD_NAME " activated and initialized\n");
-       return 0;
-
-err_cleanup_sysfs2:
-       device_remove_file(&hdev->dev, &dev_attr_operation_mode);
-err_cleanup_sysfs1:
-       device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay);
-err_cleanup_hid_ll:
-       hid_hw_close(hdev);
-err_cleanup_hid_hw:
-       hid_hw_stop(hdev);
-err_cleanup_data:
-       kfree(data);
-err_no_cleanup:
-       hid_set_drvdata(hdev, NULL);
-
-       return error;
-}
-
-static void picolcd_remove(struct hid_device *hdev)
-{
-       struct picolcd_data *data = hid_get_drvdata(hdev);
-       unsigned long flags;
-
-       dbg_hid(PICOLCD_NAME " hardware remove...\n");
-       spin_lock_irqsave(&data->lock, flags);
-       data->status |= PICOLCD_FAILED;
-       spin_unlock_irqrestore(&data->lock, flags);
-#ifdef CONFIG_HID_PICOLCD_FB
-       /* short-circuit FB as early as possible in order to
-        * avoid long delays if we host console.
-        */
-       if (data->fb_info)
-               data->fb_info->par = NULL;
-#endif
-
-       picolcd_exit_devfs(data);
-       device_remove_file(&hdev->dev, &dev_attr_operation_mode);
-       device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay);
-       hid_hw_close(hdev);
-       hid_hw_stop(hdev);
-       hid_set_drvdata(hdev, NULL);
-
-       /* Shortcut potential pending reply that will never arrive */
-       spin_lock_irqsave(&data->lock, flags);
-       if (data->pending)
-               complete(&data->pending->ready);
-       spin_unlock_irqrestore(&data->lock, flags);
-
-       /* Cleanup LED */
-       picolcd_exit_leds(data);
-       /* Clean up the framebuffer */
-       picolcd_exit_backlight(data);
-       picolcd_exit_lcd(data);
-       picolcd_exit_framebuffer(data);
-       /* Cleanup input */
-       picolcd_exit_cir(data);
-       picolcd_exit_keys(data);
-
-       mutex_destroy(&data->mutex);
-       /* Finally, clean up the picolcd data itself */
-       kfree(data);
-}
-
-static const struct hid_device_id picolcd_devices[] = {
-       { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD_BOOTLOADER) },
-       { }
-};
-MODULE_DEVICE_TABLE(hid, picolcd_devices);
-
-static struct hid_driver picolcd_driver = {
-       .name =          "hid-picolcd",
-       .id_table =      picolcd_devices,
-       .probe =         picolcd_probe,
-       .remove =        picolcd_remove,
-       .raw_event =     picolcd_raw_event,
-#ifdef CONFIG_PM
-       .suspend =       picolcd_suspend,
-       .resume =        picolcd_resume,
-       .reset_resume =  picolcd_reset_resume,
-#endif
-};
-
-static int __init picolcd_init(void)
-{
-       return hid_register_driver(&picolcd_driver);
-}
-
-static void __exit picolcd_exit(void)
-{
-       hid_unregister_driver(&picolcd_driver);
-#ifdef CONFIG_HID_PICOLCD_FB
-       flush_work_sync(&picolcd_fb_cleanup);
-       WARN_ON(fb_pending);
-#endif
-}
-
-module_init(picolcd_init);
-module_exit(picolcd_exit);
-MODULE_DESCRIPTION("Minibox graphics PicoLCD Driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/hid/hid-picolcd.h b/drivers/hid/hid-picolcd.h
new file mode 100644 (file)
index 0000000..9200be1
--- /dev/null
@@ -0,0 +1,300 @@
+/***************************************************************************
+ *   Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org>  *
+ *                                                                         *
+ *   Based on Logitech G13 driver (v0.4)                                   *
+ *     Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu>   *
+ *                                                                         *
+ *   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.               *
+ *                                                                         *
+ *   This driver 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 software. If not see <http://www.gnu.org/licenses/>.  *
+ ***************************************************************************/
+
+#define PICOLCD_NAME "PicoLCD (graphic)"
+
+/* Report numbers */
+#define REPORT_ERROR_CODE      0x10 /* LCD: IN[16]  */
+#define   ERR_SUCCESS            0x00
+#define   ERR_PARAMETER_MISSING  0x01
+#define   ERR_DATA_MISSING       0x02
+#define   ERR_BLOCK_READ_ONLY    0x03
+#define   ERR_BLOCK_NOT_ERASABLE 0x04
+#define   ERR_BLOCK_TOO_BIG      0x05
+#define   ERR_SECTION_OVERFLOW   0x06
+#define   ERR_INVALID_CMD_LEN    0x07
+#define   ERR_INVALID_DATA_LEN   0x08
+#define REPORT_KEY_STATE       0x11 /* LCD: IN[2]   */
+#define REPORT_IR_DATA         0x21 /* LCD: IN[63]  */
+#define REPORT_EE_DATA         0x32 /* LCD: IN[63]  */
+#define REPORT_MEMORY          0x41 /* LCD: IN[63]  */
+#define REPORT_LED_STATE       0x81 /* LCD: OUT[1]  */
+#define REPORT_BRIGHTNESS      0x91 /* LCD: OUT[1]  */
+#define REPORT_CONTRAST        0x92 /* LCD: OUT[1]  */
+#define REPORT_RESET           0x93 /* LCD: OUT[2]  */
+#define REPORT_LCD_CMD         0x94 /* LCD: OUT[63] */
+#define REPORT_LCD_DATA        0x95 /* LCD: OUT[63] */
+#define REPORT_LCD_CMD_DATA    0x96 /* LCD: OUT[63] */
+#define        REPORT_EE_READ         0xa3 /* LCD: OUT[63] */
+#define REPORT_EE_WRITE        0xa4 /* LCD: OUT[63] */
+#define REPORT_ERASE_MEMORY    0xb2 /* LCD: OUT[2]  */
+#define REPORT_READ_MEMORY     0xb3 /* LCD: OUT[3]  */
+#define REPORT_WRITE_MEMORY    0xb4 /* LCD: OUT[63] */
+#define REPORT_SPLASH_RESTART  0xc1 /* LCD: OUT[1]  */
+#define REPORT_EXIT_KEYBOARD   0xef /* LCD: OUT[2]  */
+#define REPORT_VERSION         0xf1 /* LCD: IN[2],OUT[1]    Bootloader: IN[2],OUT[1]   */
+#define REPORT_BL_ERASE_MEMORY 0xf2 /*                      Bootloader: IN[36],OUT[4]  */
+#define REPORT_BL_READ_MEMORY  0xf3 /*                      Bootloader: IN[36],OUT[4]  */
+#define REPORT_BL_WRITE_MEMORY 0xf4 /*                      Bootloader: IN[36],OUT[36] */
+#define REPORT_DEVID           0xf5 /* LCD: IN[5], OUT[1]   Bootloader: IN[5],OUT[1]   */
+#define REPORT_SPLASH_SIZE     0xf6 /* LCD: IN[4], OUT[1]   */
+#define REPORT_HOOK_VERSION    0xf7 /* LCD: IN[2], OUT[1]   */
+#define REPORT_EXIT_FLASHER    0xff /*                      Bootloader: OUT[2]         */
+
+/* Description of in-progress IO operation, used for operations
+ * that trigger response from device */
+struct picolcd_pending {
+       struct hid_report *out_report;
+       struct hid_report *in_report;
+       struct completion ready;
+       int raw_size;
+       u8 raw_data[64];
+};
+
+
+#define PICOLCD_KEYS 17
+
+/* Per device data structure */
+struct picolcd_data {
+       struct hid_device *hdev;
+#ifdef CONFIG_DEBUG_FS
+       struct dentry *debug_reset;
+       struct dentry *debug_eeprom;
+       struct dentry *debug_flash;
+       struct mutex mutex_flash;
+       int addr_sz;
+#endif
+       u8 version[2];
+       unsigned short opmode_delay;
+       /* input stuff */
+       u8 pressed_keys[2];
+       struct input_dev *input_keys;
+       struct input_dev *input_cir;
+       unsigned short keycode[PICOLCD_KEYS];
+
+#ifdef CONFIG_HID_PICOLCD_FB
+       /* Framebuffer stuff */
+       u8 fb_update_rate;
+       u8 fb_bpp;
+       u8 fb_force;
+       u8 *fb_vbitmap;         /* local copy of what was sent to PicoLCD */
+       u8 *fb_bitmap;          /* framebuffer */
+       struct fb_info *fb_info;
+#endif /* CONFIG_HID_PICOLCD_FB */
+#ifdef CONFIG_HID_PICOLCD_LCD
+       struct lcd_device *lcd;
+       u8 lcd_contrast;
+#endif /* CONFIG_HID_PICOLCD_LCD */
+#ifdef CONFIG_HID_PICOLCD_BACKLIGHT
+       struct backlight_device *backlight;
+       u8 lcd_brightness;
+       u8 lcd_power;
+#endif /* CONFIG_HID_PICOLCD_BACKLIGHT */
+#ifdef CONFIG_HID_PICOLCD_LEDS
+       /* LED stuff */
+       u8 led_state;
+       struct led_classdev *led[8];
+#endif /* CONFIG_HID_PICOLCD_LEDS */
+
+       /* Housekeeping stuff */
+       spinlock_t lock;
+       struct mutex mutex;
+       struct picolcd_pending *pending;
+       int status;
+#define PICOLCD_BOOTLOADER 1
+#define PICOLCD_FAILED 2
+#define PICOLCD_READY_FB 4
+};
+
+
+/* Find a given report */
+#define picolcd_in_report(id, dev) picolcd_report(id, dev, HID_INPUT_REPORT)
+#define picolcd_out_report(id, dev) picolcd_report(id, dev, HID_OUTPUT_REPORT)
+
+struct hid_report *picolcd_report(int id, struct hid_device *hdev, int dir);
+
+#ifdef CONFIG_DEBUG_FS
+void picolcd_debug_out_report(struct picolcd_data *data,
+               struct hid_device *hdev, struct hid_report *report);
+#define usbhid_submit_report(a, b, c) \
+       do { \
+               picolcd_debug_out_report(hid_get_drvdata(a), a, b); \
+               usbhid_submit_report(a, b, c); \
+       } while (0)
+
+void picolcd_debug_raw_event(struct picolcd_data *data,
+               struct hid_device *hdev, struct hid_report *report,
+               u8 *raw_data, int size);
+
+void picolcd_init_devfs(struct picolcd_data *data,
+               struct hid_report *eeprom_r, struct hid_report *eeprom_w,
+               struct hid_report *flash_r, struct hid_report *flash_w,
+               struct hid_report *reset);
+
+void picolcd_exit_devfs(struct picolcd_data *data);
+#else
+static inline void picolcd_debug_raw_event(struct picolcd_data *data,
+               struct hid_device *hdev, struct hid_report *report,
+               u8 *raw_data, int size)
+{
+}
+static inline void picolcd_init_devfs(struct picolcd_data *data,
+               struct hid_report *eeprom_r, struct hid_report *eeprom_w,
+               struct hid_report *flash_r, struct hid_report *flash_w,
+               struct hid_report *reset)
+{
+}
+static inline void picolcd_exit_devfs(struct picolcd_data *data)
+{
+}
+static inline void picolcd_debug_raw_event(struct picolcd_data *data,
+               struct hid_device *hdev, struct hid_report *report,
+               u8 *raw_data, int size)
+{
+}
+#endif /* CONFIG_DEBUG_FS */
+
+
+#ifdef CONFIG_HID_PICOLCD_FB
+int picolcd_fb_reset(struct picolcd_data *data, int clear);
+
+int picolcd_init_framebuffer(struct picolcd_data *data);
+
+void picolcd_exit_framebuffer(struct picolcd_data *data);
+
+void picolcd_fb_refresh(struct picolcd_data *data);
+#define picolcd_fbinfo(d) ((d)->fb_info)
+#else
+static inline int picolcd_fb_reset(struct picolcd_data *data, int clear)
+{
+       return 0;
+}
+static inline int picolcd_init_framebuffer(struct picolcd_data *data)
+{
+       return 0;
+}
+static inline void picolcd_exit_framebuffer(struct picolcd_data *data)
+{
+}
+static inline void picolcd_fb_refresh(struct picolcd_data *data)
+{
+}
+#define picolcd_fbinfo(d) NULL
+#endif /* CONFIG_HID_PICOLCD_FB */
+
+
+#ifdef CONFIG_HID_PICOLCD_BACKLIGHT
+int picolcd_init_backlight(struct picolcd_data *data,
+               struct hid_report *report);
+
+void picolcd_exit_backlight(struct picolcd_data *data);
+
+int picolcd_resume_backlight(struct picolcd_data *data);
+
+void picolcd_suspend_backlight(struct picolcd_data *data);
+#else
+static inline int picolcd_init_backlight(struct picolcd_data *data,
+               struct hid_report *report)
+{
+       return 0;
+}
+static inline void picolcd_exit_backlight(struct picolcd_data *data)
+{
+}
+static inline int picolcd_resume_backlight(struct picolcd_data *data)
+{
+       return 0;
+}
+static inline void picolcd_suspend_backlight(struct picolcd_data *data)
+{
+}
+
+#endif /* CONFIG_HID_PICOLCD_BACKLIGHT */
+
+
+#ifdef CONFIG_HID_PICOLCD_LCD
+int picolcd_init_lcd(struct picolcd_data *data,
+               struct hid_report *report);
+
+void picolcd_exit_lcd(struct picolcd_data *data);
+
+int picolcd_resume_lcd(struct picolcd_data *data);
+#else
+static inline int picolcd_init_lcd(struct picolcd_data *data,
+               struct hid_report *report)
+{
+       return 0;
+}
+static inline void picolcd_exit_lcd(struct picolcd_data *data)
+{
+}
+static inline int picolcd_resume_lcd(struct picolcd_data *data)
+{
+       return 0;
+}
+#endif /* CONFIG_HID_PICOLCD_LCD */
+
+
+#ifdef CONFIG_HID_PICOLCD_LEDS
+int picolcd_init_leds(struct picolcd_data *data,
+               struct hid_report *report);
+
+void picolcd_exit_leds(struct picolcd_data *data);
+
+void picolcd_leds_set(struct picolcd_data *data);
+#else
+static inline int picolcd_init_leds(struct picolcd_data *data,
+               struct hid_report *report)
+{
+       return 0;
+}
+static inline void picolcd_exit_leds(struct picolcd_data *data)
+{
+}
+static inline void picolcd_leds_set(struct picolcd_data *data)
+{
+}
+#endif /* CONFIG_HID_PICOLCD_LEDS */
+
+
+#ifdef CONFIG_HID_PICOLCD_CIR
+int picolcd_raw_cir(struct picolcd_data *data,
+               struct hid_report *report, u8 *raw_data, int size);
+
+int picolcd_init_cir(struct picolcd_data *data, struct hid_report *report);
+
+void picolcd_exit_cir(struct picolcd_data *data);
+#else
+static inline int picolcd_raw_cir(struct picolcd_data *data,
+               struct hid_report *report, u8 *raw_data, int size)
+{
+       return 1;
+}
+static inline int picolcd_init_cir(struct picolcd_data *data, struct hid_report *report)
+{
+       return 0;
+}
+static inline void picolcd_exit_cir(struct picolcd_data *data)
+{
+}
+#endif /* CONFIG_HID_PICOLCD_LIRC */
+
+int picolcd_reset(struct hid_device *hdev);
+struct picolcd_pending *picolcd_send_and_wait(struct hid_device *hdev,
+                       int report_id, const u8 *raw_data, int size);
diff --git a/drivers/hid/hid-picolcd_backlight.c b/drivers/hid/hid-picolcd_backlight.c
new file mode 100644 (file)
index 0000000..b91f309
--- /dev/null
@@ -0,0 +1,122 @@
+/***************************************************************************
+ *   Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org>  *
+ *                                                                         *
+ *   Based on Logitech G13 driver (v0.4)                                   *
+ *     Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu>   *
+ *                                                                         *
+ *   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.               *
+ *                                                                         *
+ *   This driver 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 software. If not see <http://www.gnu.org/licenses/>.  *
+ ***************************************************************************/
+
+#include <linux/hid.h>
+#include "usbhid/usbhid.h"
+#include <linux/usb.h>
+
+#include <linux/fb.h>
+#include <linux/backlight.h>
+
+#include "hid-picolcd.h"
+
+static int picolcd_get_brightness(struct backlight_device *bdev)
+{
+       struct picolcd_data *data = bl_get_data(bdev);
+       return data->lcd_brightness;
+}
+
+static int picolcd_set_brightness(struct backlight_device *bdev)
+{
+       struct picolcd_data *data = bl_get_data(bdev);
+       struct hid_report *report = picolcd_out_report(REPORT_BRIGHTNESS, data->hdev);
+       unsigned long flags;
+
+       if (!report || report->maxfield != 1 || report->field[0]->report_count != 1)
+               return -ENODEV;
+
+       data->lcd_brightness = bdev->props.brightness & 0x0ff;
+       data->lcd_power      = bdev->props.power;
+       spin_lock_irqsave(&data->lock, flags);
+       hid_set_field(report->field[0], 0, data->lcd_power == FB_BLANK_UNBLANK ? data->lcd_brightness : 0);
+       if (!(data->status & PICOLCD_FAILED))
+               usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
+       spin_unlock_irqrestore(&data->lock, flags);
+       return 0;
+}
+
+static int picolcd_check_bl_fb(struct backlight_device *bdev, struct fb_info *fb)
+{
+       return fb && fb == picolcd_fbinfo((struct picolcd_data *)bl_get_data(bdev));
+}
+
+static const struct backlight_ops picolcd_blops = {
+       .update_status  = picolcd_set_brightness,
+       .get_brightness = picolcd_get_brightness,
+       .check_fb       = picolcd_check_bl_fb,
+};
+
+int picolcd_init_backlight(struct picolcd_data *data, struct hid_report *report)
+{
+       struct device *dev = &data->hdev->dev;
+       struct backlight_device *bdev;
+       struct backlight_properties props;
+       if (!report)
+               return -ENODEV;
+       if (report->maxfield != 1 || report->field[0]->report_count != 1 ||
+                       report->field[0]->report_size != 8) {
+               dev_err(dev, "unsupported BRIGHTNESS report");
+               return -EINVAL;
+       }
+
+       memset(&props, 0, sizeof(props));
+       props.type = BACKLIGHT_RAW;
+       props.max_brightness = 0xff;
+       bdev = backlight_device_register(dev_name(dev), dev, data,
+                       &picolcd_blops, &props);
+       if (IS_ERR(bdev)) {
+               dev_err(dev, "failed to register backlight\n");
+               return PTR_ERR(bdev);
+       }
+       bdev->props.brightness     = 0xff;
+       data->lcd_brightness       = 0xff;
+       data->backlight            = bdev;
+       picolcd_set_brightness(bdev);
+       return 0;
+}
+
+void picolcd_exit_backlight(struct picolcd_data *data)
+{
+       struct backlight_device *bdev = data->backlight;
+
+       data->backlight = NULL;
+       if (bdev)
+               backlight_device_unregister(bdev);
+}
+
+int picolcd_resume_backlight(struct picolcd_data *data)
+{
+       if (!data->backlight)
+               return 0;
+       return picolcd_set_brightness(data->backlight);
+}
+
+#ifdef CONFIG_PM
+void picolcd_suspend_backlight(struct picolcd_data *data)
+{
+       int bl_power = data->lcd_power;
+       if (!data->backlight)
+               return;
+
+       data->backlight->props.power = FB_BLANK_POWERDOWN;
+       picolcd_set_brightness(data->backlight);
+       data->lcd_power = data->backlight->props.power = bl_power;
+}
+#endif /* CONFIG_PM */
+
diff --git a/drivers/hid/hid-picolcd_cir.c b/drivers/hid/hid-picolcd_cir.c
new file mode 100644 (file)
index 0000000..dc632c3
--- /dev/null
@@ -0,0 +1,61 @@
+/***************************************************************************
+ *   Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org>  *
+ *                                                                         *
+ *   Based on Logitech G13 driver (v0.4)                                   *
+ *     Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu>   *
+ *                                                                         *
+ *   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.               *
+ *                                                                         *
+ *   This driver 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 software. If not see <http://www.gnu.org/licenses/>.  *
+ ***************************************************************************/
+
+#include <linux/hid.h>
+#include <linux/hid-debug.h>
+#include <linux/input.h>
+#include "hid-ids.h"
+#include "usbhid/usbhid.h"
+#include <linux/usb.h>
+
+#include <linux/fb.h>
+#include <linux/vmalloc.h>
+#include <linux/backlight.h>
+#include <linux/lcd.h>
+
+#include <linux/leds.h>
+
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+
+#include <linux/completion.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+
+#include "hid-picolcd.h"
+
+
+int picolcd_raw_cir(struct picolcd_data *data,
+               struct hid_report *report, u8 *raw_data, int size)
+{
+       /* Need understanding of CIR data format to implement ... */
+       return 1;
+}
+
+/* initialize CIR input device */
+int picolcd_init_cir(struct picolcd_data *data, struct hid_report *report)
+{
+       /* support not implemented yet */
+       return 0;
+}
+
+void picolcd_exit_cir(struct picolcd_data *data)
+{
+}
+
diff --git a/drivers/hid/hid-picolcd_core.c b/drivers/hid/hid-picolcd_core.c
new file mode 100644 (file)
index 0000000..2d7ef68
--- /dev/null
@@ -0,0 +1,712 @@
+/***************************************************************************
+ *   Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org>  *
+ *                                                                         *
+ *   Based on Logitech G13 driver (v0.4)                                   *
+ *     Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu>   *
+ *                                                                         *
+ *   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.               *
+ *                                                                         *
+ *   This driver 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 software. If not see <http://www.gnu.org/licenses/>.  *
+ ***************************************************************************/
+
+#include <linux/hid.h>
+#include <linux/hid-debug.h>
+#include <linux/input.h>
+#include "hid-ids.h"
+#include "usbhid/usbhid.h"
+#include <linux/usb.h>
+
+#include <linux/fb.h>
+#include <linux/vmalloc.h>
+
+#include <linux/completion.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+
+#include "hid-picolcd.h"
+
+
+/* Input device
+ *
+ * The PicoLCD has an IR receiver header, a built-in keypad with 5 keys
+ * and header for 4x4 key matrix. The built-in keys are part of the matrix.
+ */
+static const unsigned short def_keymap[PICOLCD_KEYS] = {
+       KEY_RESERVED,   /* none */
+       KEY_BACK,       /* col 4 + row 1 */
+       KEY_HOMEPAGE,   /* col 3 + row 1 */
+       KEY_RESERVED,   /* col 2 + row 1 */
+       KEY_RESERVED,   /* col 1 + row 1 */
+       KEY_SCROLLUP,   /* col 4 + row 2 */
+       KEY_OK,         /* col 3 + row 2 */
+       KEY_SCROLLDOWN, /* col 2 + row 2 */
+       KEY_RESERVED,   /* col 1 + row 2 */
+       KEY_RESERVED,   /* col 4 + row 3 */
+       KEY_RESERVED,   /* col 3 + row 3 */
+       KEY_RESERVED,   /* col 2 + row 3 */
+       KEY_RESERVED,   /* col 1 + row 3 */
+       KEY_RESERVED,   /* col 4 + row 4 */
+       KEY_RESERVED,   /* col 3 + row 4 */
+       KEY_RESERVED,   /* col 2 + row 4 */
+       KEY_RESERVED,   /* col 1 + row 4 */
+};
+
+
+/* Find a given report */
+struct hid_report *picolcd_report(int id, struct hid_device *hdev, int dir)
+{
+       struct list_head *feature_report_list = &hdev->report_enum[dir].report_list;
+       struct hid_report *report = NULL;
+
+       list_for_each_entry(report, feature_report_list, list) {
+               if (report->id == id)
+                       return report;
+       }
+       hid_warn(hdev, "No report with id 0x%x found\n", id);
+       return NULL;
+}
+
+/* Submit a report and wait for a reply from device - if device fades away
+ * or does not respond in time, return NULL */
+struct picolcd_pending *picolcd_send_and_wait(struct hid_device *hdev,
+               int report_id, const u8 *raw_data, int size)
+{
+       struct picolcd_data *data = hid_get_drvdata(hdev);
+       struct picolcd_pending *work;
+       struct hid_report *report = picolcd_out_report(report_id, hdev);
+       unsigned long flags;
+       int i, j, k;
+
+       if (!report || !data)
+               return NULL;
+       if (data->status & PICOLCD_FAILED)
+               return NULL;
+       work = kzalloc(sizeof(*work), GFP_KERNEL);
+       if (!work)
+               return NULL;
+
+       init_completion(&work->ready);
+       work->out_report = report;
+       work->in_report  = NULL;
+       work->raw_size   = 0;
+
+       mutex_lock(&data->mutex);
+       spin_lock_irqsave(&data->lock, flags);
+       for (i = k = 0; i < report->maxfield; i++)
+               for (j = 0; j < report->field[i]->report_count; j++) {
+                       hid_set_field(report->field[i], j, k < size ? raw_data[k] : 0);
+                       k++;
+               }
+       if (data->status & PICOLCD_FAILED) {
+               kfree(work);
+               work = NULL;
+       } else {
+               data->pending = work;
+               usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
+               spin_unlock_irqrestore(&data->lock, flags);
+               wait_for_completion_interruptible_timeout(&work->ready, HZ*2);
+               spin_lock_irqsave(&data->lock, flags);
+               data->pending = NULL;
+       }
+       spin_unlock_irqrestore(&data->lock, flags);
+       mutex_unlock(&data->mutex);
+       return work;
+}
+
+/*
+ * input class device
+ */
+static int picolcd_raw_keypad(struct picolcd_data *data,
+               struct hid_report *report, u8 *raw_data, int size)
+{
+       /*
+        * Keypad event
+        * First and second data bytes list currently pressed keys,
+        * 0x00 means no key and at most 2 keys may be pressed at same time
+        */
+       int i, j;
+
+       /* determine newly pressed keys */
+       for (i = 0; i < size; i++) {
+               unsigned int key_code;
+               if (raw_data[i] == 0)
+                       continue;
+               for (j = 0; j < sizeof(data->pressed_keys); j++)
+                       if (data->pressed_keys[j] == raw_data[i])
+                               goto key_already_down;
+               for (j = 0; j < sizeof(data->pressed_keys); j++)
+                       if (data->pressed_keys[j] == 0) {
+                               data->pressed_keys[j] = raw_data[i];
+                               break;
+                       }
+               input_event(data->input_keys, EV_MSC, MSC_SCAN, raw_data[i]);
+               if (raw_data[i] < PICOLCD_KEYS)
+                       key_code = data->keycode[raw_data[i]];
+               else
+                       key_code = KEY_UNKNOWN;
+               if (key_code != KEY_UNKNOWN) {
+                       dbg_hid(PICOLCD_NAME " got key press for %u:%d",
+                                       raw_data[i], key_code);
+                       input_report_key(data->input_keys, key_code, 1);
+               }
+               input_sync(data->input_keys);
+key_already_down:
+               continue;
+       }
+
+       /* determine newly released keys */
+       for (j = 0; j < sizeof(data->pressed_keys); j++) {
+               unsigned int key_code;
+               if (data->pressed_keys[j] == 0)
+                       continue;
+               for (i = 0; i < size; i++)
+                       if (data->pressed_keys[j] == raw_data[i])
+                               goto key_still_down;
+               input_event(data->input_keys, EV_MSC, MSC_SCAN, data->pressed_keys[j]);
+               if (data->pressed_keys[j] < PICOLCD_KEYS)
+                       key_code = data->keycode[data->pressed_keys[j]];
+               else
+                       key_code = KEY_UNKNOWN;
+               if (key_code != KEY_UNKNOWN) {
+                       dbg_hid(PICOLCD_NAME " got key release for %u:%d",
+                                       data->pressed_keys[j], key_code);
+                       input_report_key(data->input_keys, key_code, 0);
+               }
+               input_sync(data->input_keys);
+               data->pressed_keys[j] = 0;
+key_still_down:
+               continue;
+       }
+       return 1;
+}
+
+static int picolcd_check_version(struct hid_device *hdev)
+{
+       struct picolcd_data *data = hid_get_drvdata(hdev);
+       struct picolcd_pending *verinfo;
+       int ret = 0;
+
+       if (!data)
+               return -ENODEV;
+
+       verinfo = picolcd_send_and_wait(hdev, REPORT_VERSION, NULL, 0);
+       if (!verinfo) {
+               hid_err(hdev, "no version response from PicoLCD\n");
+               return -ENODEV;
+       }
+
+       if (verinfo->raw_size == 2) {
+               data->version[0] = verinfo->raw_data[1];
+               data->version[1] = verinfo->raw_data[0];
+               if (data->status & PICOLCD_BOOTLOADER) {
+                       hid_info(hdev, "PicoLCD, bootloader version %d.%d\n",
+                                verinfo->raw_data[1], verinfo->raw_data[0]);
+               } else {
+                       hid_info(hdev, "PicoLCD, firmware version %d.%d\n",
+                                verinfo->raw_data[1], verinfo->raw_data[0]);
+               }
+       } else {
+               hid_err(hdev, "confused, got unexpected version response from PicoLCD\n");
+               ret = -EINVAL;
+       }
+       kfree(verinfo);
+       return ret;
+}
+
+/*
+ * Reset our device and wait for answer to VERSION request
+ */
+int picolcd_reset(struct hid_device *hdev)
+{
+       struct picolcd_data *data = hid_get_drvdata(hdev);
+       struct hid_report *report = picolcd_out_report(REPORT_RESET, hdev);
+       unsigned long flags;
+       int error;
+
+       if (!data || !report || report->maxfield != 1)
+               return -ENODEV;
+
+       spin_lock_irqsave(&data->lock, flags);
+       if (hdev->product == USB_DEVICE_ID_PICOLCD_BOOTLOADER)
+               data->status |= PICOLCD_BOOTLOADER;
+
+       /* perform the reset */
+       hid_set_field(report->field[0], 0, 1);
+       if (data->status & PICOLCD_FAILED) {
+               spin_unlock_irqrestore(&data->lock, flags);
+               return -ENODEV;
+       }
+       usbhid_submit_report(hdev, report, USB_DIR_OUT);
+       spin_unlock_irqrestore(&data->lock, flags);
+
+       error = picolcd_check_version(hdev);
+       if (error)
+               return error;
+
+       picolcd_resume_lcd(data);
+       picolcd_resume_backlight(data);
+       picolcd_fb_refresh(data);
+       picolcd_leds_set(data);
+       return 0;
+}
+
+/*
+ * The "operation_mode" sysfs attribute
+ */
+static ssize_t picolcd_operation_mode_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct picolcd_data *data = dev_get_drvdata(dev);
+
+       if (data->status & PICOLCD_BOOTLOADER)
+               return snprintf(buf, PAGE_SIZE, "[bootloader] lcd\n");
+       else
+               return snprintf(buf, PAGE_SIZE, "bootloader [lcd]\n");
+}
+
+static ssize_t picolcd_operation_mode_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct picolcd_data *data = dev_get_drvdata(dev);
+       struct hid_report *report = NULL;
+       size_t cnt = count;
+       int timeout = data->opmode_delay;
+       unsigned long flags;
+
+       if (cnt >= 3 && strncmp("lcd", buf, 3) == 0) {
+               if (data->status & PICOLCD_BOOTLOADER)
+                       report = picolcd_out_report(REPORT_EXIT_FLASHER, data->hdev);
+               buf += 3;
+               cnt -= 3;
+       } else if (cnt >= 10 && strncmp("bootloader", buf, 10) == 0) {
+               if (!(data->status & PICOLCD_BOOTLOADER))
+                       report = picolcd_out_report(REPORT_EXIT_KEYBOARD, data->hdev);
+               buf += 10;
+               cnt -= 10;
+       }
+       if (!report)
+               return -EINVAL;
+
+       while (cnt > 0 && (buf[cnt-1] == '\n' || buf[cnt-1] == '\r'))
+               cnt--;
+       if (cnt != 0)
+               return -EINVAL;
+
+       spin_lock_irqsave(&data->lock, flags);
+       hid_set_field(report->field[0], 0, timeout & 0xff);
+       hid_set_field(report->field[0], 1, (timeout >> 8) & 0xff);
+       usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
+       spin_unlock_irqrestore(&data->lock, flags);
+       return count;
+}
+
+static DEVICE_ATTR(operation_mode, 0644, picolcd_operation_mode_show,
+               picolcd_operation_mode_store);
+
+/*
+ * The "operation_mode_delay" sysfs attribute
+ */
+static ssize_t picolcd_operation_mode_delay_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct picolcd_data *data = dev_get_drvdata(dev);
+
+       return snprintf(buf, PAGE_SIZE, "%hu\n", data->opmode_delay);
+}
+
+static ssize_t picolcd_operation_mode_delay_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct picolcd_data *data = dev_get_drvdata(dev);
+       unsigned u;
+       if (sscanf(buf, "%u", &u) != 1)
+               return -EINVAL;
+       if (u > 30000)
+               return -EINVAL;
+       else
+               data->opmode_delay = u;
+       return count;
+}
+
+static DEVICE_ATTR(operation_mode_delay, 0644, picolcd_operation_mode_delay_show,
+               picolcd_operation_mode_delay_store);
+
+/*
+ * Handle raw report as sent by device
+ */
+static int picolcd_raw_event(struct hid_device *hdev,
+               struct hid_report *report, u8 *raw_data, int size)
+{
+       struct picolcd_data *data = hid_get_drvdata(hdev);
+       unsigned long flags;
+       int ret = 0;
+
+       if (!data)
+               return 1;
+
+       if (report->id == REPORT_KEY_STATE) {
+               if (data->input_keys)
+                       ret = picolcd_raw_keypad(data, report, raw_data+1, size-1);
+       } else if (report->id == REPORT_IR_DATA) {
+               if (data->input_cir)
+                       ret = picolcd_raw_cir(data, report, raw_data+1, size-1);
+       } else {
+               spin_lock_irqsave(&data->lock, flags);
+               /*
+                * We let the caller of picolcd_send_and_wait() check if the
+                * report we got is one of the expected ones or not.
+                */
+               if (data->pending) {
+                       memcpy(data->pending->raw_data, raw_data+1, size-1);
+                       data->pending->raw_size  = size-1;
+                       data->pending->in_report = report;
+                       complete(&data->pending->ready);
+               }
+               spin_unlock_irqrestore(&data->lock, flags);
+       }
+
+       picolcd_debug_raw_event(data, hdev, report, raw_data, size);
+       return 1;
+}
+
+#ifdef CONFIG_PM
+static int picolcd_suspend(struct hid_device *hdev, pm_message_t message)
+{
+       if (PMSG_IS_AUTO(message))
+               return 0;
+
+       picolcd_suspend_backlight(hid_get_drvdata(hdev));
+       dbg_hid(PICOLCD_NAME " device ready for suspend\n");
+       return 0;
+}
+
+static int picolcd_resume(struct hid_device *hdev)
+{
+       int ret;
+       ret = picolcd_resume_backlight(hid_get_drvdata(hdev));
+       if (ret)
+               dbg_hid(PICOLCD_NAME " restoring backlight failed: %d\n", ret);
+       return 0;
+}
+
+static int picolcd_reset_resume(struct hid_device *hdev)
+{
+       int ret;
+       ret = picolcd_reset(hdev);
+       if (ret)
+               dbg_hid(PICOLCD_NAME " resetting our device failed: %d\n", ret);
+       ret = picolcd_fb_reset(hid_get_drvdata(hdev), 0);
+       if (ret)
+               dbg_hid(PICOLCD_NAME " restoring framebuffer content failed: %d\n", ret);
+       ret = picolcd_resume_lcd(hid_get_drvdata(hdev));
+       if (ret)
+               dbg_hid(PICOLCD_NAME " restoring lcd failed: %d\n", ret);
+       ret = picolcd_resume_backlight(hid_get_drvdata(hdev));
+       if (ret)
+               dbg_hid(PICOLCD_NAME " restoring backlight failed: %d\n", ret);
+       picolcd_leds_set(hid_get_drvdata(hdev));
+       return 0;
+}
+#endif
+
+/* initialize keypad input device */
+static int picolcd_init_keys(struct picolcd_data *data,
+               struct hid_report *report)
+{
+       struct hid_device *hdev = data->hdev;
+       struct input_dev *idev;
+       int error, i;
+
+       if (!report)
+               return -ENODEV;
+       if (report->maxfield != 1 || report->field[0]->report_count != 2 ||
+                       report->field[0]->report_size != 8) {
+               hid_err(hdev, "unsupported KEY_STATE report\n");
+               return -EINVAL;
+       }
+
+       idev = input_allocate_device();
+       if (idev == NULL) {
+               hid_err(hdev, "failed to allocate input device\n");
+               return -ENOMEM;
+       }
+       input_set_drvdata(idev, hdev);
+       memcpy(data->keycode, def_keymap, sizeof(def_keymap));
+       idev->name = hdev->name;
+       idev->phys = hdev->phys;
+       idev->uniq = hdev->uniq;
+       idev->id.bustype = hdev->bus;
+       idev->id.vendor  = hdev->vendor;
+       idev->id.product = hdev->product;
+       idev->id.version = hdev->version;
+       idev->dev.parent = hdev->dev.parent;
+       idev->keycode     = &data->keycode;
+       idev->keycodemax  = PICOLCD_KEYS;
+       idev->keycodesize = sizeof(data->keycode[0]);
+       input_set_capability(idev, EV_MSC, MSC_SCAN);
+       set_bit(EV_REP, idev->evbit);
+       for (i = 0; i < PICOLCD_KEYS; i++)
+               input_set_capability(idev, EV_KEY, data->keycode[i]);
+       error = input_register_device(idev);
+       if (error) {
+               hid_err(hdev, "error registering the input device\n");
+               input_free_device(idev);
+               return error;
+       }
+       data->input_keys = idev;
+       return 0;
+}
+
+static void picolcd_exit_keys(struct picolcd_data *data)
+{
+       struct input_dev *idev = data->input_keys;
+
+       data->input_keys = NULL;
+       if (idev)
+               input_unregister_device(idev);
+}
+
+static int picolcd_probe_lcd(struct hid_device *hdev, struct picolcd_data *data)
+{
+       int error;
+
+       error = picolcd_check_version(hdev);
+       if (error)
+               return error;
+
+       if (data->version[0] != 0 && data->version[1] != 3)
+               hid_info(hdev, "Device with untested firmware revision, please submit /sys/kernel/debug/hid/%s/rdesc for this device.\n",
+                        dev_name(&hdev->dev));
+
+       /* Setup keypad input device */
+       error = picolcd_init_keys(data, picolcd_in_report(REPORT_KEY_STATE, hdev));
+       if (error)
+               goto err;
+
+       /* Setup CIR input device */
+       error = picolcd_init_cir(data, picolcd_in_report(REPORT_IR_DATA, hdev));
+       if (error)
+               goto err;
+
+       /* Set up the framebuffer device */
+       error = picolcd_init_framebuffer(data);
+       if (error)
+               goto err;
+
+       /* Setup lcd class device */
+       error = picolcd_init_lcd(data, picolcd_out_report(REPORT_CONTRAST, hdev));
+       if (error)
+               goto err;
+
+       /* Setup backlight class device */
+       error = picolcd_init_backlight(data, picolcd_out_report(REPORT_BRIGHTNESS, hdev));
+       if (error)
+               goto err;
+
+       /* Setup the LED class devices */
+       error = picolcd_init_leds(data, picolcd_out_report(REPORT_LED_STATE, hdev));
+       if (error)
+               goto err;
+
+       picolcd_init_devfs(data, picolcd_out_report(REPORT_EE_READ, hdev),
+                       picolcd_out_report(REPORT_EE_WRITE, hdev),
+                       picolcd_out_report(REPORT_READ_MEMORY, hdev),
+                       picolcd_out_report(REPORT_WRITE_MEMORY, hdev),
+                       picolcd_out_report(REPORT_RESET, hdev));
+       return 0;
+err:
+       picolcd_exit_leds(data);
+       picolcd_exit_backlight(data);
+       picolcd_exit_lcd(data);
+       picolcd_exit_framebuffer(data);
+       picolcd_exit_cir(data);
+       picolcd_exit_keys(data);
+       return error;
+}
+
+static int picolcd_probe_bootloader(struct hid_device *hdev, struct picolcd_data *data)
+{
+       int error;
+
+       error = picolcd_check_version(hdev);
+       if (error)
+               return error;
+
+       if (data->version[0] != 1 && data->version[1] != 0)
+               hid_info(hdev, "Device with untested bootloader revision, please submit /sys/kernel/debug/hid/%s/rdesc for this device.\n",
+                        dev_name(&hdev->dev));
+
+       picolcd_init_devfs(data, NULL, NULL,
+                       picolcd_out_report(REPORT_BL_READ_MEMORY, hdev),
+                       picolcd_out_report(REPORT_BL_WRITE_MEMORY, hdev), NULL);
+       return 0;
+}
+
+static int picolcd_probe(struct hid_device *hdev,
+                    const struct hid_device_id *id)
+{
+       struct picolcd_data *data;
+       int error = -ENOMEM;
+
+       dbg_hid(PICOLCD_NAME " hardware probe...\n");
+
+       /*
+        * Let's allocate the picolcd data structure, set some reasonable
+        * defaults, and associate it with the device
+        */
+       data = kzalloc(sizeof(struct picolcd_data), GFP_KERNEL);
+       if (data == NULL) {
+               hid_err(hdev, "can't allocate space for Minibox PicoLCD device data\n");
+               error = -ENOMEM;
+               goto err_no_cleanup;
+       }
+
+       spin_lock_init(&data->lock);
+       mutex_init(&data->mutex);
+       data->hdev = hdev;
+       data->opmode_delay = 5000;
+       if (hdev->product == USB_DEVICE_ID_PICOLCD_BOOTLOADER)
+               data->status |= PICOLCD_BOOTLOADER;
+       hid_set_drvdata(hdev, data);
+
+       /* Parse the device reports and start it up */
+       error = hid_parse(hdev);
+       if (error) {
+               hid_err(hdev, "device report parse failed\n");
+               goto err_cleanup_data;
+       }
+
+       /* We don't use hidinput but hid_hw_start() fails if nothing is
+        * claimed. So spoof claimed input. */
+       hdev->claimed = HID_CLAIMED_INPUT;
+       error = hid_hw_start(hdev, 0);
+       hdev->claimed = 0;
+       if (error) {
+               hid_err(hdev, "hardware start failed\n");
+               goto err_cleanup_data;
+       }
+
+       error = hid_hw_open(hdev);
+       if (error) {
+               hid_err(hdev, "failed to open input interrupt pipe for key and IR events\n");
+               goto err_cleanup_hid_hw;
+       }
+
+       error = device_create_file(&hdev->dev, &dev_attr_operation_mode_delay);
+       if (error) {
+               hid_err(hdev, "failed to create sysfs attributes\n");
+               goto err_cleanup_hid_ll;
+       }
+
+       error = device_create_file(&hdev->dev, &dev_attr_operation_mode);
+       if (error) {
+               hid_err(hdev, "failed to create sysfs attributes\n");
+               goto err_cleanup_sysfs1;
+       }
+
+       if (data->status & PICOLCD_BOOTLOADER)
+               error = picolcd_probe_bootloader(hdev, data);
+       else
+               error = picolcd_probe_lcd(hdev, data);
+       if (error)
+               goto err_cleanup_sysfs2;
+
+       dbg_hid(PICOLCD_NAME " activated and initialized\n");
+       return 0;
+
+err_cleanup_sysfs2:
+       device_remove_file(&hdev->dev, &dev_attr_operation_mode);
+err_cleanup_sysfs1:
+       device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay);
+err_cleanup_hid_ll:
+       hid_hw_close(hdev);
+err_cleanup_hid_hw:
+       hid_hw_stop(hdev);
+err_cleanup_data:
+       kfree(data);
+err_no_cleanup:
+       hid_set_drvdata(hdev, NULL);
+
+       return error;
+}
+
+static void picolcd_remove(struct hid_device *hdev)
+{
+       struct picolcd_data *data = hid_get_drvdata(hdev);
+       unsigned long flags;
+
+       dbg_hid(PICOLCD_NAME " hardware remove...\n");
+       spin_lock_irqsave(&data->lock, flags);
+       data->status |= PICOLCD_FAILED;
+       spin_unlock_irqrestore(&data->lock, flags);
+
+       picolcd_exit_devfs(data);
+       device_remove_file(&hdev->dev, &dev_attr_operation_mode);
+       device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay);
+       hid_hw_close(hdev);
+       hid_hw_stop(hdev);
+       hid_set_drvdata(hdev, NULL);
+
+       /* Shortcut potential pending reply that will never arrive */
+       spin_lock_irqsave(&data->lock, flags);
+       if (data->pending)
+               complete(&data->pending->ready);
+       spin_unlock_irqrestore(&data->lock, flags);
+
+       /* Cleanup LED */
+       picolcd_exit_leds(data);
+       /* Clean up the framebuffer */
+       picolcd_exit_backlight(data);
+       picolcd_exit_lcd(data);
+       picolcd_exit_framebuffer(data);
+       /* Cleanup input */
+       picolcd_exit_cir(data);
+       picolcd_exit_keys(data);
+
+       mutex_destroy(&data->mutex);
+       /* Finally, clean up the picolcd data itself */
+       kfree(data);
+}
+
+static const struct hid_device_id picolcd_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD_BOOTLOADER) },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, picolcd_devices);
+
+static struct hid_driver picolcd_driver = {
+       .name =          "hid-picolcd",
+       .id_table =      picolcd_devices,
+       .probe =         picolcd_probe,
+       .remove =        picolcd_remove,
+       .raw_event =     picolcd_raw_event,
+#ifdef CONFIG_PM
+       .suspend =       picolcd_suspend,
+       .resume =        picolcd_resume,
+       .reset_resume =  picolcd_reset_resume,
+#endif
+};
+
+static int __init picolcd_init(void)
+{
+       return hid_register_driver(&picolcd_driver);
+}
+
+static void __exit picolcd_exit(void)
+{
+       hid_unregister_driver(&picolcd_driver);
+}
+
+module_init(picolcd_init);
+module_exit(picolcd_exit);
+MODULE_DESCRIPTION("Minibox graphics PicoLCD Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hid/hid-picolcd_debugfs.c b/drivers/hid/hid-picolcd_debugfs.c
new file mode 100644 (file)
index 0000000..f2491fa
--- /dev/null
@@ -0,0 +1,898 @@
+/***************************************************************************
+ *   Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org>  *
+ *                                                                         *
+ *   Based on Logitech G13 driver (v0.4)                                   *
+ *     Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu>   *
+ *                                                                         *
+ *   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.               *
+ *                                                                         *
+ *   This driver 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 software. If not see <http://www.gnu.org/licenses/>.  *
+ ***************************************************************************/
+
+#include <linux/hid.h>
+#include <linux/hid-debug.h>
+#include "usbhid/usbhid.h"
+#include <linux/usb.h>
+
+#include <linux/fb.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+
+#include <linux/module.h>
+
+#include "hid-picolcd.h"
+
+
+static int picolcd_debug_reset_show(struct seq_file *f, void *p)
+{
+       if (picolcd_fbinfo((struct picolcd_data *)f->private))
+               seq_printf(f, "all fb\n");
+       else
+               seq_printf(f, "all\n");
+       return 0;
+}
+
+static int picolcd_debug_reset_open(struct inode *inode, struct file *f)
+{
+       return single_open(f, picolcd_debug_reset_show, inode->i_private);
+}
+
+static ssize_t picolcd_debug_reset_write(struct file *f, const char __user *user_buf,
+               size_t count, loff_t *ppos)
+{
+       struct picolcd_data *data = ((struct seq_file *)f->private_data)->private;
+       char buf[32];
+       size_t cnt = min(count, sizeof(buf)-1);
+       if (copy_from_user(buf, user_buf, cnt))
+               return -EFAULT;
+
+       while (cnt > 0 && (buf[cnt-1] == ' ' || buf[cnt-1] == '\n'))
+               cnt--;
+       buf[cnt] = '\0';
+       if (strcmp(buf, "all") == 0) {
+               picolcd_reset(data->hdev);
+               picolcd_fb_reset(data, 1);
+       } else if (strcmp(buf, "fb") == 0) {
+               picolcd_fb_reset(data, 1);
+       } else {
+               return -EINVAL;
+       }
+       return count;
+}
+
+static const struct file_operations picolcd_debug_reset_fops = {
+       .owner    = THIS_MODULE,
+       .open     = picolcd_debug_reset_open,
+       .read     = seq_read,
+       .llseek   = seq_lseek,
+       .write    = picolcd_debug_reset_write,
+       .release  = single_release,
+};
+
+/*
+ * The "eeprom" file
+ */
+static ssize_t picolcd_debug_eeprom_read(struct file *f, char __user *u,
+               size_t s, loff_t *off)
+{
+       struct picolcd_data *data = f->private_data;
+       struct picolcd_pending *resp;
+       u8 raw_data[3];
+       ssize_t ret = -EIO;
+
+       if (s == 0)
+               return -EINVAL;
+       if (*off > 0x0ff)
+               return 0;
+
+       /* prepare buffer with info about what we want to read (addr & len) */
+       raw_data[0] = *off & 0xff;
+       raw_data[1] = (*off >> 8) & 0xff;
+       raw_data[2] = s < 20 ? s : 20;
+       if (*off + raw_data[2] > 0xff)
+               raw_data[2] = 0x100 - *off;
+       resp = picolcd_send_and_wait(data->hdev, REPORT_EE_READ, raw_data,
+                       sizeof(raw_data));
+       if (!resp)
+               return -EIO;
+
+       if (resp->in_report && resp->in_report->id == REPORT_EE_DATA) {
+               /* successful read :) */
+               ret = resp->raw_data[2];
+               if (ret > s)
+                       ret = s;
+               if (copy_to_user(u, resp->raw_data+3, ret))
+                       ret = -EFAULT;
+               else
+                       *off += ret;
+       } /* anything else is some kind of IO error */
+
+       kfree(resp);
+       return ret;
+}
+
+static ssize_t picolcd_debug_eeprom_write(struct file *f, const char __user *u,
+               size_t s, loff_t *off)
+{
+       struct picolcd_data *data = f->private_data;
+       struct picolcd_pending *resp;
+       ssize_t ret = -EIO;
+       u8 raw_data[23];
+
+       if (s == 0)
+               return -EINVAL;
+       if (*off > 0x0ff)
+               return -ENOSPC;
+
+       memset(raw_data, 0, sizeof(raw_data));
+       raw_data[0] = *off & 0xff;
+       raw_data[1] = (*off >> 8) & 0xff;
+       raw_data[2] = min_t(size_t, 20, s);
+       if (*off + raw_data[2] > 0xff)
+               raw_data[2] = 0x100 - *off;
+
+       if (copy_from_user(raw_data+3, u, min((u8)20, raw_data[2])))
+               return -EFAULT;
+       resp = picolcd_send_and_wait(data->hdev, REPORT_EE_WRITE, raw_data,
+                       sizeof(raw_data));
+
+       if (!resp)
+               return -EIO;
+
+       if (resp->in_report && resp->in_report->id == REPORT_EE_DATA) {
+               /* check if written data matches */
+               if (memcmp(raw_data, resp->raw_data, 3+raw_data[2]) == 0) {
+                       *off += raw_data[2];
+                       ret = raw_data[2];
+               }
+       }
+       kfree(resp);
+       return ret;
+}
+
+/*
+ * Notes:
+ * - read/write happens in chunks of at most 20 bytes, it's up to userspace
+ *   to loop in order to get more data.
+ * - on write errors on otherwise correct write request the bytes
+ *   that should have been written are in undefined state.
+ */
+static const struct file_operations picolcd_debug_eeprom_fops = {
+       .owner    = THIS_MODULE,
+       .open     = simple_open,
+       .read     = picolcd_debug_eeprom_read,
+       .write    = picolcd_debug_eeprom_write,
+       .llseek   = generic_file_llseek,
+};
+
+/*
+ * The "flash" file
+ */
+/* record a flash address to buf (bounds check to be done by caller) */
+static int _picolcd_flash_setaddr(struct picolcd_data *data, u8 *buf, long off)
+{
+       buf[0] = off & 0xff;
+       buf[1] = (off >> 8) & 0xff;
+       if (data->addr_sz == 3)
+               buf[2] = (off >> 16) & 0xff;
+       return data->addr_sz == 2 ? 2 : 3;
+}
+
+/* read a given size of data (bounds check to be done by caller) */
+static ssize_t _picolcd_flash_read(struct picolcd_data *data, int report_id,
+               char __user *u, size_t s, loff_t *off)
+{
+       struct picolcd_pending *resp;
+       u8 raw_data[4];
+       ssize_t ret = 0;
+       int len_off, err = -EIO;
+
+       while (s > 0) {
+               err = -EIO;
+               len_off = _picolcd_flash_setaddr(data, raw_data, *off);
+               raw_data[len_off] = s > 32 ? 32 : s;
+               resp = picolcd_send_and_wait(data->hdev, report_id, raw_data, len_off+1);
+               if (!resp || !resp->in_report)
+                       goto skip;
+               if (resp->in_report->id == REPORT_MEMORY ||
+                       resp->in_report->id == REPORT_BL_READ_MEMORY) {
+                       if (memcmp(raw_data, resp->raw_data, len_off+1) != 0)
+                               goto skip;
+                       if (copy_to_user(u+ret, resp->raw_data+len_off+1, raw_data[len_off])) {
+                               err = -EFAULT;
+                               goto skip;
+                       }
+                       *off += raw_data[len_off];
+                       s    -= raw_data[len_off];
+                       ret  += raw_data[len_off];
+                       err   = 0;
+               }
+skip:
+               kfree(resp);
+               if (err)
+                       return ret > 0 ? ret : err;
+       }
+       return ret;
+}
+
+static ssize_t picolcd_debug_flash_read(struct file *f, char __user *u,
+               size_t s, loff_t *off)
+{
+       struct picolcd_data *data = f->private_data;
+
+       if (s == 0)
+               return -EINVAL;
+       if (*off > 0x05fff)
+               return 0;
+       if (*off + s > 0x05fff)
+               s = 0x06000 - *off;
+
+       if (data->status & PICOLCD_BOOTLOADER)
+               return _picolcd_flash_read(data, REPORT_BL_READ_MEMORY, u, s, off);
+       else
+               return _picolcd_flash_read(data, REPORT_READ_MEMORY, u, s, off);
+}
+
+/* erase block aligned to 64bytes boundary */
+static ssize_t _picolcd_flash_erase64(struct picolcd_data *data, int report_id,
+               loff_t *off)
+{
+       struct picolcd_pending *resp;
+       u8 raw_data[3];
+       int len_off;
+       ssize_t ret = -EIO;
+
+       if (*off & 0x3f)
+               return -EINVAL;
+
+       len_off = _picolcd_flash_setaddr(data, raw_data, *off);
+       resp = picolcd_send_and_wait(data->hdev, report_id, raw_data, len_off);
+       if (!resp || !resp->in_report)
+               goto skip;
+       if (resp->in_report->id == REPORT_MEMORY ||
+               resp->in_report->id == REPORT_BL_ERASE_MEMORY) {
+               if (memcmp(raw_data, resp->raw_data, len_off) != 0)
+                       goto skip;
+               ret = 0;
+       }
+skip:
+       kfree(resp);
+       return ret;
+}
+
+/* write a given size of data (bounds check to be done by caller) */
+static ssize_t _picolcd_flash_write(struct picolcd_data *data, int report_id,
+               const char __user *u, size_t s, loff_t *off)
+{
+       struct picolcd_pending *resp;
+       u8 raw_data[36];
+       ssize_t ret = 0;
+       int len_off, err = -EIO;
+
+       while (s > 0) {
+               err = -EIO;
+               len_off = _picolcd_flash_setaddr(data, raw_data, *off);
+               raw_data[len_off] = s > 32 ? 32 : s;
+               if (copy_from_user(raw_data+len_off+1, u, raw_data[len_off])) {
+                       err = -EFAULT;
+                       break;
+               }
+               resp = picolcd_send_and_wait(data->hdev, report_id, raw_data,
+                               len_off+1+raw_data[len_off]);
+               if (!resp || !resp->in_report)
+                       goto skip;
+               if (resp->in_report->id == REPORT_MEMORY ||
+                       resp->in_report->id == REPORT_BL_WRITE_MEMORY) {
+                       if (memcmp(raw_data, resp->raw_data, len_off+1+raw_data[len_off]) != 0)
+                               goto skip;
+                       *off += raw_data[len_off];
+                       s    -= raw_data[len_off];
+                       ret  += raw_data[len_off];
+                       err   = 0;
+               }
+skip:
+               kfree(resp);
+               if (err)
+                       break;
+       }
+       return ret > 0 ? ret : err;
+}
+
+static ssize_t picolcd_debug_flash_write(struct file *f, const char __user *u,
+               size_t s, loff_t *off)
+{
+       struct picolcd_data *data = f->private_data;
+       ssize_t err, ret = 0;
+       int report_erase, report_write;
+
+       if (s == 0)
+               return -EINVAL;
+       if (*off > 0x5fff)
+               return -ENOSPC;
+       if (s & 0x3f)
+               return -EINVAL;
+       if (*off & 0x3f)
+               return -EINVAL;
+
+       if (data->status & PICOLCD_BOOTLOADER) {
+               report_erase = REPORT_BL_ERASE_MEMORY;
+               report_write = REPORT_BL_WRITE_MEMORY;
+       } else {
+               report_erase = REPORT_ERASE_MEMORY;
+               report_write = REPORT_WRITE_MEMORY;
+       }
+       mutex_lock(&data->mutex_flash);
+       while (s > 0) {
+               err = _picolcd_flash_erase64(data, report_erase, off);
+               if (err)
+                       break;
+               err = _picolcd_flash_write(data, report_write, u, 64, off);
+               if (err < 0)
+                       break;
+               ret += err;
+               *off += err;
+               s -= err;
+               if (err != 64)
+                       break;
+       }
+       mutex_unlock(&data->mutex_flash);
+       return ret > 0 ? ret : err;
+}
+
+/*
+ * Notes:
+ * - concurrent writing is prevented by mutex and all writes must be
+ *   n*64 bytes and 64-byte aligned, each write being preceded by an
+ *   ERASE which erases a 64byte block.
+ *   If less than requested was written or an error is returned for an
+ *   otherwise correct write request the next 64-byte block which should
+ *   have been written is in undefined state (mostly: original, erased,
+ *   (half-)written with write error)
+ * - reading can happen without special restriction
+ */
+static const struct file_operations picolcd_debug_flash_fops = {
+       .owner    = THIS_MODULE,
+       .open     = simple_open,
+       .read     = picolcd_debug_flash_read,
+       .write    = picolcd_debug_flash_write,
+       .llseek   = generic_file_llseek,
+};
+
+
+/*
+ * Helper code for HID report level dumping/debugging
+ */
+static const char * const error_codes[] = {
+       "success", "parameter missing", "data_missing", "block readonly",
+       "block not erasable", "block too big", "section overflow",
+       "invalid command length", "invalid data length",
+};
+
+static void dump_buff_as_hex(char *dst, size_t dst_sz, const u8 *data,
+               const size_t data_len)
+{
+       int i, j;
+       for (i = j = 0; i < data_len && j + 3 < dst_sz; i++) {
+               dst[j++] = hex_asc[(data[i] >> 4) & 0x0f];
+               dst[j++] = hex_asc[data[i] & 0x0f];
+               dst[j++] = ' ';
+       }
+       if (j < dst_sz) {
+               dst[j--] = '\0';
+               dst[j] = '\n';
+       } else
+               dst[j] = '\0';
+}
+
+void picolcd_debug_out_report(struct picolcd_data *data,
+               struct hid_device *hdev, struct hid_report *report)
+{
+       u8 raw_data[70];
+       int raw_size = (report->size >> 3) + 1;
+       char *buff;
+#define BUFF_SZ 256
+
+       /* Avoid unnecessary overhead if debugfs is disabled */
+       if (!hdev->debug_events)
+               return;
+
+       buff = kmalloc(BUFF_SZ, GFP_ATOMIC);
+       if (!buff)
+               return;
+
+       snprintf(buff, BUFF_SZ, "\nout report %d (size %d) =  ",
+                       report->id, raw_size);
+       hid_debug_event(hdev, buff);
+       if (raw_size + 5 > sizeof(raw_data)) {
+               kfree(buff);
+               hid_debug_event(hdev, " TOO BIG\n");
+               return;
+       } else {
+               raw_data[0] = report->id;
+               hid_output_report(report, raw_data);
+               dump_buff_as_hex(buff, BUFF_SZ, raw_data, raw_size);
+               hid_debug_event(hdev, buff);
+       }
+
+       switch (report->id) {
+       case REPORT_LED_STATE:
+               /* 1 data byte with GPO state */
+               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+                       "REPORT_LED_STATE", report->id, raw_size-1);
+               hid_debug_event(hdev, buff);
+               snprintf(buff, BUFF_SZ, "\tGPO state: 0x%02x\n", raw_data[1]);
+               hid_debug_event(hdev, buff);
+               break;
+       case REPORT_BRIGHTNESS:
+               /* 1 data byte with brightness */
+               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+                       "REPORT_BRIGHTNESS", report->id, raw_size-1);
+               hid_debug_event(hdev, buff);
+               snprintf(buff, BUFF_SZ, "\tBrightness: 0x%02x\n", raw_data[1]);
+               hid_debug_event(hdev, buff);
+               break;
+       case REPORT_CONTRAST:
+               /* 1 data byte with contrast */
+               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+                       "REPORT_CONTRAST", report->id, raw_size-1);
+               hid_debug_event(hdev, buff);
+               snprintf(buff, BUFF_SZ, "\tContrast: 0x%02x\n", raw_data[1]);
+               hid_debug_event(hdev, buff);
+               break;
+       case REPORT_RESET:
+               /* 2 data bytes with reset duration in ms */
+               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+                       "REPORT_RESET", report->id, raw_size-1);
+               hid_debug_event(hdev, buff);
+               snprintf(buff, BUFF_SZ, "\tDuration: 0x%02x%02x (%dms)\n",
+                               raw_data[2], raw_data[1], raw_data[2] << 8 | raw_data[1]);
+               hid_debug_event(hdev, buff);
+               break;
+       case REPORT_LCD_CMD:
+               /* 63 data bytes with LCD commands */
+               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+                       "REPORT_LCD_CMD", report->id, raw_size-1);
+               hid_debug_event(hdev, buff);
+               /* TODO: format decoding */
+               break;
+       case REPORT_LCD_DATA:
+               /* 63 data bytes with LCD data */
+               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+                       "REPORT_LCD_CMD", report->id, raw_size-1);
+               /* TODO: format decoding */
+               hid_debug_event(hdev, buff);
+               break;
+       case REPORT_LCD_CMD_DATA:
+               /* 63 data bytes with LCD commands and data */
+               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+                       "REPORT_LCD_CMD", report->id, raw_size-1);
+               /* TODO: format decoding */
+               hid_debug_event(hdev, buff);
+               break;
+       case REPORT_EE_READ:
+               /* 3 data bytes with read area description */
+               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+                       "REPORT_EE_READ", report->id, raw_size-1);
+               hid_debug_event(hdev, buff);
+               snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
+                               raw_data[2], raw_data[1]);
+               hid_debug_event(hdev, buff);
+               snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
+               hid_debug_event(hdev, buff);
+               break;
+       case REPORT_EE_WRITE:
+               /* 3+1..20 data bytes with write area description */
+               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+                       "REPORT_EE_WRITE", report->id, raw_size-1);
+               hid_debug_event(hdev, buff);
+               snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
+                               raw_data[2], raw_data[1]);
+               hid_debug_event(hdev, buff);
+               snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
+               hid_debug_event(hdev, buff);
+               if (raw_data[3] == 0) {
+                       snprintf(buff, BUFF_SZ, "\tNo data\n");
+               } else if (raw_data[3] + 4 <= raw_size) {
+                       snprintf(buff, BUFF_SZ, "\tData: ");
+                       hid_debug_event(hdev, buff);
+                       dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]);
+               } else {
+                       snprintf(buff, BUFF_SZ, "\tData overflowed\n");
+               }
+               hid_debug_event(hdev, buff);
+               break;
+       case REPORT_ERASE_MEMORY:
+       case REPORT_BL_ERASE_MEMORY:
+               /* 3 data bytes with pointer inside erase block */
+               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+                       "REPORT_ERASE_MEMORY", report->id, raw_size-1);
+               hid_debug_event(hdev, buff);
+               switch (data->addr_sz) {
+               case 2:
+                       snprintf(buff, BUFF_SZ, "\tAddress inside 64 byte block: 0x%02x%02x\n",
+                                       raw_data[2], raw_data[1]);
+                       break;
+               case 3:
+                       snprintf(buff, BUFF_SZ, "\tAddress inside 64 byte block: 0x%02x%02x%02x\n",
+                                       raw_data[3], raw_data[2], raw_data[1]);
+                       break;
+               default:
+                       snprintf(buff, BUFF_SZ, "\tNot supported\n");
+               }
+               hid_debug_event(hdev, buff);
+               break;
+       case REPORT_READ_MEMORY:
+       case REPORT_BL_READ_MEMORY:
+               /* 4 data bytes with read area description */
+               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+                       "REPORT_READ_MEMORY", report->id, raw_size-1);
+               hid_debug_event(hdev, buff);
+               switch (data->addr_sz) {
+               case 2:
+                       snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
+                                       raw_data[2], raw_data[1]);
+                       hid_debug_event(hdev, buff);
+                       snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
+                       break;
+               case 3:
+                       snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x%02x\n",
+                                       raw_data[3], raw_data[2], raw_data[1]);
+                       hid_debug_event(hdev, buff);
+                       snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[4]);
+                       break;
+               default:
+                       snprintf(buff, BUFF_SZ, "\tNot supported\n");
+               }
+               hid_debug_event(hdev, buff);
+               break;
+       case REPORT_WRITE_MEMORY:
+       case REPORT_BL_WRITE_MEMORY:
+               /* 4+1..32 data bytes with write adrea description */
+               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+                       "REPORT_WRITE_MEMORY", report->id, raw_size-1);
+               hid_debug_event(hdev, buff);
+               switch (data->addr_sz) {
+               case 2:
+                       snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
+                                       raw_data[2], raw_data[1]);
+                       hid_debug_event(hdev, buff);
+                       snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
+                       hid_debug_event(hdev, buff);
+                       if (raw_data[3] == 0) {
+                               snprintf(buff, BUFF_SZ, "\tNo data\n");
+                       } else if (raw_data[3] + 4 <= raw_size) {
+                               snprintf(buff, BUFF_SZ, "\tData: ");
+                               hid_debug_event(hdev, buff);
+                               dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]);
+                       } else {
+                               snprintf(buff, BUFF_SZ, "\tData overflowed\n");
+                       }
+                       break;
+               case 3:
+                       snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x%02x\n",
+                                       raw_data[3], raw_data[2], raw_data[1]);
+                       hid_debug_event(hdev, buff);
+                       snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[4]);
+                       hid_debug_event(hdev, buff);
+                       if (raw_data[4] == 0) {
+                               snprintf(buff, BUFF_SZ, "\tNo data\n");
+                       } else if (raw_data[4] + 5 <= raw_size) {
+                               snprintf(buff, BUFF_SZ, "\tData: ");
+                               hid_debug_event(hdev, buff);
+                               dump_buff_as_hex(buff, BUFF_SZ, raw_data+5, raw_data[4]);
+                       } else {
+                               snprintf(buff, BUFF_SZ, "\tData overflowed\n");
+                       }
+                       break;
+               default:
+                       snprintf(buff, BUFF_SZ, "\tNot supported\n");
+               }
+               hid_debug_event(hdev, buff);
+               break;
+       case REPORT_SPLASH_RESTART:
+               /* TODO */
+               break;
+       case REPORT_EXIT_KEYBOARD:
+               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+                       "REPORT_EXIT_KEYBOARD", report->id, raw_size-1);
+               hid_debug_event(hdev, buff);
+               snprintf(buff, BUFF_SZ, "\tRestart delay: %dms (0x%02x%02x)\n",
+                               raw_data[1] | (raw_data[2] << 8),
+                               raw_data[2], raw_data[1]);
+               hid_debug_event(hdev, buff);
+               break;
+       case REPORT_VERSION:
+               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+                       "REPORT_VERSION", report->id, raw_size-1);
+               hid_debug_event(hdev, buff);
+               break;
+       case REPORT_DEVID:
+               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+                       "REPORT_DEVID", report->id, raw_size-1);
+               hid_debug_event(hdev, buff);
+               break;
+       case REPORT_SPLASH_SIZE:
+               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+                       "REPORT_SPLASH_SIZE", report->id, raw_size-1);
+               hid_debug_event(hdev, buff);
+               break;
+       case REPORT_HOOK_VERSION:
+               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+                       "REPORT_HOOK_VERSION", report->id, raw_size-1);
+               hid_debug_event(hdev, buff);
+               break;
+       case REPORT_EXIT_FLASHER:
+               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+                       "REPORT_VERSION", report->id, raw_size-1);
+               hid_debug_event(hdev, buff);
+               snprintf(buff, BUFF_SZ, "\tRestart delay: %dms (0x%02x%02x)\n",
+                               raw_data[1] | (raw_data[2] << 8),
+                               raw_data[2], raw_data[1]);
+               hid_debug_event(hdev, buff);
+               break;
+       default:
+               snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
+                       "<unknown>", report->id, raw_size-1);
+               hid_debug_event(hdev, buff);
+               break;
+       }
+       wake_up_interruptible(&hdev->debug_wait);
+       kfree(buff);
+}
+
+void picolcd_debug_raw_event(struct picolcd_data *data,
+               struct hid_device *hdev, struct hid_report *report,
+               u8 *raw_data, int size)
+{
+       char *buff;
+
+#define BUFF_SZ 256
+       /* Avoid unnecessary overhead if debugfs is disabled */
+       if (!hdev->debug_events)
+               return;
+
+       buff = kmalloc(BUFF_SZ, GFP_ATOMIC);
+       if (!buff)
+               return;
+
+       switch (report->id) {
+       case REPORT_ERROR_CODE:
+               /* 2 data bytes with affected report and error code */
+               snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+                       "REPORT_ERROR_CODE", report->id, size-1);
+               hid_debug_event(hdev, buff);
+               if (raw_data[2] < ARRAY_SIZE(error_codes))
+                       snprintf(buff, BUFF_SZ, "\tError code 0x%02x (%s) in reply to report 0x%02x\n",
+                                       raw_data[2], error_codes[raw_data[2]], raw_data[1]);
+               else
+                       snprintf(buff, BUFF_SZ, "\tError code 0x%02x in reply to report 0x%02x\n",
+                                       raw_data[2], raw_data[1]);
+               hid_debug_event(hdev, buff);
+               break;
+       case REPORT_KEY_STATE:
+               /* 2 data bytes with key state */
+               snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+                       "REPORT_KEY_STATE", report->id, size-1);
+               hid_debug_event(hdev, buff);
+               if (raw_data[1] == 0)
+                       snprintf(buff, BUFF_SZ, "\tNo key pressed\n");
+               else if (raw_data[2] == 0)
+                       snprintf(buff, BUFF_SZ, "\tOne key pressed: 0x%02x (%d)\n",
+                                       raw_data[1], raw_data[1]);
+               else
+                       snprintf(buff, BUFF_SZ, "\tTwo keys pressed: 0x%02x (%d), 0x%02x (%d)\n",
+                                       raw_data[1], raw_data[1], raw_data[2], raw_data[2]);
+               hid_debug_event(hdev, buff);
+               break;
+       case REPORT_IR_DATA:
+               /* Up to 20 byes of IR scancode data */
+               snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+                       "REPORT_IR_DATA", report->id, size-1);
+               hid_debug_event(hdev, buff);
+               if (raw_data[1] == 0) {
+                       snprintf(buff, BUFF_SZ, "\tUnexpectedly 0 data length\n");
+                       hid_debug_event(hdev, buff);
+               } else if (raw_data[1] + 1 <= size) {
+                       snprintf(buff, BUFF_SZ, "\tData length: %d\n\tIR Data: ",
+                                       raw_data[1]-1);
+                       hid_debug_event(hdev, buff);
+                       dump_buff_as_hex(buff, BUFF_SZ, raw_data+2, raw_data[1]-1);
+                       hid_debug_event(hdev, buff);
+               } else {
+                       snprintf(buff, BUFF_SZ, "\tOverflowing data length: %d\n",
+                                       raw_data[1]-1);
+                       hid_debug_event(hdev, buff);
+               }
+               break;
+       case REPORT_EE_DATA:
+               /* Data buffer in response to REPORT_EE_READ or REPORT_EE_WRITE */
+               snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+                       "REPORT_EE_DATA", report->id, size-1);
+               hid_debug_event(hdev, buff);
+               snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
+                               raw_data[2], raw_data[1]);
+               hid_debug_event(hdev, buff);
+               snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
+               hid_debug_event(hdev, buff);
+               if (raw_data[3] == 0) {
+                       snprintf(buff, BUFF_SZ, "\tNo data\n");
+                       hid_debug_event(hdev, buff);
+               } else if (raw_data[3] + 4 <= size) {
+                       snprintf(buff, BUFF_SZ, "\tData: ");
+                       hid_debug_event(hdev, buff);
+                       dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]);
+                       hid_debug_event(hdev, buff);
+               } else {
+                       snprintf(buff, BUFF_SZ, "\tData overflowed\n");
+                       hid_debug_event(hdev, buff);
+               }
+               break;
+       case REPORT_MEMORY:
+               /* Data buffer in response to REPORT_READ_MEMORY or REPORT_WRTIE_MEMORY */
+               snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+                       "REPORT_MEMORY", report->id, size-1);
+               hid_debug_event(hdev, buff);
+               switch (data->addr_sz) {
+               case 2:
+                       snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
+                                       raw_data[2], raw_data[1]);
+                       hid_debug_event(hdev, buff);
+                       snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
+                       hid_debug_event(hdev, buff);
+                       if (raw_data[3] == 0) {
+                               snprintf(buff, BUFF_SZ, "\tNo data\n");
+                       } else if (raw_data[3] + 4 <= size) {
+                               snprintf(buff, BUFF_SZ, "\tData: ");
+                               hid_debug_event(hdev, buff);
+                               dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]);
+                       } else {
+                               snprintf(buff, BUFF_SZ, "\tData overflowed\n");
+                       }
+                       break;
+               case 3:
+                       snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x%02x\n",
+                                       raw_data[3], raw_data[2], raw_data[1]);
+                       hid_debug_event(hdev, buff);
+                       snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[4]);
+                       hid_debug_event(hdev, buff);
+                       if (raw_data[4] == 0) {
+                               snprintf(buff, BUFF_SZ, "\tNo data\n");
+                       } else if (raw_data[4] + 5 <= size) {
+                               snprintf(buff, BUFF_SZ, "\tData: ");
+                               hid_debug_event(hdev, buff);
+                               dump_buff_as_hex(buff, BUFF_SZ, raw_data+5, raw_data[4]);
+                       } else {
+                               snprintf(buff, BUFF_SZ, "\tData overflowed\n");
+                       }
+                       break;
+               default:
+                       snprintf(buff, BUFF_SZ, "\tNot supported\n");
+               }
+               hid_debug_event(hdev, buff);
+               break;
+       case REPORT_VERSION:
+               snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+                       "REPORT_VERSION", report->id, size-1);
+               hid_debug_event(hdev, buff);
+               snprintf(buff, BUFF_SZ, "\tFirmware version: %d.%d\n",
+                               raw_data[2], raw_data[1]);
+               hid_debug_event(hdev, buff);
+               break;
+       case REPORT_BL_ERASE_MEMORY:
+               snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+                       "REPORT_BL_ERASE_MEMORY", report->id, size-1);
+               hid_debug_event(hdev, buff);
+               /* TODO */
+               break;
+       case REPORT_BL_READ_MEMORY:
+               snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+                       "REPORT_BL_READ_MEMORY", report->id, size-1);
+               hid_debug_event(hdev, buff);
+               /* TODO */
+               break;
+       case REPORT_BL_WRITE_MEMORY:
+               snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+                       "REPORT_BL_WRITE_MEMORY", report->id, size-1);
+               hid_debug_event(hdev, buff);
+               /* TODO */
+               break;
+       case REPORT_DEVID:
+               snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+                       "REPORT_DEVID", report->id, size-1);
+               hid_debug_event(hdev, buff);
+               snprintf(buff, BUFF_SZ, "\tSerial: 0x%02x%02x%02x%02x\n",
+                               raw_data[1], raw_data[2], raw_data[3], raw_data[4]);
+               hid_debug_event(hdev, buff);
+               snprintf(buff, BUFF_SZ, "\tType: 0x%02x\n",
+                               raw_data[5]);
+               hid_debug_event(hdev, buff);
+               break;
+       case REPORT_SPLASH_SIZE:
+               snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+                       "REPORT_SPLASH_SIZE", report->id, size-1);
+               hid_debug_event(hdev, buff);
+               snprintf(buff, BUFF_SZ, "\tTotal splash space: %d\n",
+                               (raw_data[2] << 8) | raw_data[1]);
+               hid_debug_event(hdev, buff);
+               snprintf(buff, BUFF_SZ, "\tUsed splash space: %d\n",
+                               (raw_data[4] << 8) | raw_data[3]);
+               hid_debug_event(hdev, buff);
+               break;
+       case REPORT_HOOK_VERSION:
+               snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+                       "REPORT_HOOK_VERSION", report->id, size-1);
+               hid_debug_event(hdev, buff);
+               snprintf(buff, BUFF_SZ, "\tFirmware version: %d.%d\n",
+                               raw_data[1], raw_data[2]);
+               hid_debug_event(hdev, buff);
+               break;
+       default:
+               snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
+                       "<unknown>", report->id, size-1);
+               hid_debug_event(hdev, buff);
+               break;
+       }
+       wake_up_interruptible(&hdev->debug_wait);
+       kfree(buff);
+}
+
+void picolcd_init_devfs(struct picolcd_data *data,
+               struct hid_report *eeprom_r, struct hid_report *eeprom_w,
+               struct hid_report *flash_r, struct hid_report *flash_w,
+               struct hid_report *reset)
+{
+       struct hid_device *hdev = data->hdev;
+
+       mutex_init(&data->mutex_flash);
+
+       /* reset */
+       if (reset)
+               data->debug_reset = debugfs_create_file("reset", 0600,
+                               hdev->debug_dir, data, &picolcd_debug_reset_fops);
+
+       /* eeprom */
+       if (eeprom_r || eeprom_w)
+               data->debug_eeprom = debugfs_create_file("eeprom",
+                       (eeprom_w ? S_IWUSR : 0) | (eeprom_r ? S_IRUSR : 0),
+                       hdev->debug_dir, data, &picolcd_debug_eeprom_fops);
+
+       /* flash */
+       if (flash_r && flash_r->maxfield == 1 && flash_r->field[0]->report_size == 8)
+               data->addr_sz = flash_r->field[0]->report_count - 1;
+       else
+               data->addr_sz = -1;
+       if (data->addr_sz == 2 || data->addr_sz == 3) {
+               data->debug_flash = debugfs_create_file("flash",
+                       (flash_w ? S_IWUSR : 0) | (flash_r ? S_IRUSR : 0),
+                       hdev->debug_dir, data, &picolcd_debug_flash_fops);
+       } else if (flash_r || flash_w)
+               hid_warn(hdev, "Unexpected FLASH access reports, please submit rdesc for review\n");
+}
+
+void picolcd_exit_devfs(struct picolcd_data *data)
+{
+       struct dentry *dent;
+
+       dent = data->debug_reset;
+       data->debug_reset = NULL;
+       if (dent)
+               debugfs_remove(dent);
+       dent = data->debug_eeprom;
+       data->debug_eeprom = NULL;
+       if (dent)
+               debugfs_remove(dent);
+       dent = data->debug_flash;
+       data->debug_flash = NULL;
+       if (dent)
+               debugfs_remove(dent);
+       mutex_destroy(&data->mutex_flash);
+}
+
diff --git a/drivers/hid/hid-picolcd_fb.c b/drivers/hid/hid-picolcd_fb.c
new file mode 100644 (file)
index 0000000..cf295c5
--- /dev/null
@@ -0,0 +1,605 @@
+/***************************************************************************
+ *   Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org>  *
+ *                                                                         *
+ *   Based on Logitech G13 driver (v0.4)                                   *
+ *     Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu>   *
+ *                                                                         *
+ *   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.               *
+ *                                                                         *
+ *   This driver 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 software. If not see <http://www.gnu.org/licenses/>.  *
+ ***************************************************************************/
+
+#include <linux/hid.h>
+#include <linux/vmalloc.h>
+#include "usbhid/usbhid.h"
+#include <linux/usb.h>
+
+#include <linux/fb.h>
+#include <linux/module.h>
+
+#include "hid-picolcd.h"
+
+/* Framebuffer
+ *
+ * The PicoLCD use a Topway LCD module of 256x64 pixel
+ * This display area is tiled over 4 controllers with 8 tiles
+ * each. Each tile has 8x64 pixel, each data byte representing
+ * a 1-bit wide vertical line of the tile.
+ *
+ * The display can be updated at a tile granularity.
+ *
+ *       Chip 1           Chip 2           Chip 3           Chip 4
+ * +----------------+----------------+----------------+----------------+
+ * |     Tile 1     |     Tile 1     |     Tile 1     |     Tile 1     |
+ * +----------------+----------------+----------------+----------------+
+ * |     Tile 2     |     Tile 2     |     Tile 2     |     Tile 2     |
+ * +----------------+----------------+----------------+----------------+
+ *                                  ...
+ * +----------------+----------------+----------------+----------------+
+ * |     Tile 8     |     Tile 8     |     Tile 8     |     Tile 8     |
+ * +----------------+----------------+----------------+----------------+
+ */
+#define PICOLCDFB_NAME "picolcdfb"
+#define PICOLCDFB_WIDTH (256)
+#define PICOLCDFB_HEIGHT (64)
+#define PICOLCDFB_SIZE (PICOLCDFB_WIDTH * PICOLCDFB_HEIGHT / 8)
+
+#define PICOLCDFB_UPDATE_RATE_LIMIT   10
+#define PICOLCDFB_UPDATE_RATE_DEFAULT  2
+
+/* Framebuffer visual structures */
+static const struct fb_fix_screeninfo picolcdfb_fix = {
+       .id          = PICOLCDFB_NAME,
+       .type        = FB_TYPE_PACKED_PIXELS,
+       .visual      = FB_VISUAL_MONO01,
+       .xpanstep    = 0,
+       .ypanstep    = 0,
+       .ywrapstep   = 0,
+       .line_length = PICOLCDFB_WIDTH / 8,
+       .accel       = FB_ACCEL_NONE,
+};
+
+static const struct fb_var_screeninfo picolcdfb_var = {
+       .xres           = PICOLCDFB_WIDTH,
+       .yres           = PICOLCDFB_HEIGHT,
+       .xres_virtual   = PICOLCDFB_WIDTH,
+       .yres_virtual   = PICOLCDFB_HEIGHT,
+       .width          = 103,
+       .height         = 26,
+       .bits_per_pixel = 1,
+       .grayscale      = 1,
+       .red            = {
+               .offset = 0,
+               .length = 1,
+               .msb_right = 0,
+       },
+       .green          = {
+               .offset = 0,
+               .length = 1,
+               .msb_right = 0,
+       },
+       .blue           = {
+               .offset = 0,
+               .length = 1,
+               .msb_right = 0,
+       },
+       .transp         = {
+               .offset = 0,
+               .length = 0,
+               .msb_right = 0,
+       },
+};
+
+/* Send a given tile to PicoLCD */
+static int picolcd_fb_send_tile(struct hid_device *hdev, int chip, int tile)
+{
+       struct picolcd_data *data = hid_get_drvdata(hdev);
+       struct hid_report *report1 = picolcd_out_report(REPORT_LCD_CMD_DATA, hdev);
+       struct hid_report *report2 = picolcd_out_report(REPORT_LCD_DATA, hdev);
+       unsigned long flags;
+       u8 *tdata;
+       int i;
+
+       if (!report1 || report1->maxfield != 1 || !report2 || report2->maxfield != 1)
+               return -ENODEV;
+
+       spin_lock_irqsave(&data->lock, flags);
+       hid_set_field(report1->field[0],  0, chip << 2);
+       hid_set_field(report1->field[0],  1, 0x02);
+       hid_set_field(report1->field[0],  2, 0x00);
+       hid_set_field(report1->field[0],  3, 0x00);
+       hid_set_field(report1->field[0],  4, 0xb8 | tile);
+       hid_set_field(report1->field[0],  5, 0x00);
+       hid_set_field(report1->field[0],  6, 0x00);
+       hid_set_field(report1->field[0],  7, 0x40);
+       hid_set_field(report1->field[0],  8, 0x00);
+       hid_set_field(report1->field[0],  9, 0x00);
+       hid_set_field(report1->field[0], 10,   32);
+
+       hid_set_field(report2->field[0],  0, (chip << 2) | 0x01);
+       hid_set_field(report2->field[0],  1, 0x00);
+       hid_set_field(report2->field[0],  2, 0x00);
+       hid_set_field(report2->field[0],  3,   32);
+
+       tdata = data->fb_vbitmap + (tile * 4 + chip) * 64;
+       for (i = 0; i < 64; i++)
+               if (i < 32)
+                       hid_set_field(report1->field[0], 11 + i, tdata[i]);
+               else
+                       hid_set_field(report2->field[0], 4 + i - 32, tdata[i]);
+
+       usbhid_submit_report(data->hdev, report1, USB_DIR_OUT);
+       usbhid_submit_report(data->hdev, report2, USB_DIR_OUT);
+       spin_unlock_irqrestore(&data->lock, flags);
+       return 0;
+}
+
+/* Translate a single tile*/
+static int picolcd_fb_update_tile(u8 *vbitmap, const u8 *bitmap, int bpp,
+               int chip, int tile)
+{
+       int i, b, changed = 0;
+       u8 tdata[64];
+       u8 *vdata = vbitmap + (tile * 4 + chip) * 64;
+
+       if (bpp == 1) {
+               for (b = 7; b >= 0; b--) {
+                       const u8 *bdata = bitmap + tile * 256 + chip * 8 + b * 32;
+                       for (i = 0; i < 64; i++) {
+                               tdata[i] <<= 1;
+                               tdata[i] |= (bdata[i/8] >> (i % 8)) & 0x01;
+                       }
+               }
+       } else if (bpp == 8) {
+               for (b = 7; b >= 0; b--) {
+                       const u8 *bdata = bitmap + (tile * 256 + chip * 8 + b * 32) * 8;
+                       for (i = 0; i < 64; i++) {
+                               tdata[i] <<= 1;
+                               tdata[i] |= (bdata[i] & 0x80) ? 0x01 : 0x00;
+                       }
+               }
+       } else {
+               /* Oops, we should never get here! */
+               WARN_ON(1);
+               return 0;
+       }
+
+       for (i = 0; i < 64; i++)
+               if (tdata[i] != vdata[i]) {
+                       changed = 1;
+                       vdata[i] = tdata[i];
+               }
+       return changed;
+}
+
+void picolcd_fb_refresh(struct picolcd_data *data)
+{
+       if (data->fb_info)
+               schedule_delayed_work(&data->fb_info->deferred_work, 0);
+}
+
+/* Reconfigure LCD display */
+int picolcd_fb_reset(struct picolcd_data *data, int clear)
+{
+       struct hid_report *report = picolcd_out_report(REPORT_LCD_CMD, data->hdev);
+       int i, j;
+       unsigned long flags;
+       static const u8 mapcmd[8] = { 0x00, 0x02, 0x00, 0x64, 0x3f, 0x00, 0x64, 0xc0 };
+
+       if (!report || report->maxfield != 1)
+               return -ENODEV;
+
+       spin_lock_irqsave(&data->lock, flags);
+       for (i = 0; i < 4; i++) {
+               for (j = 0; j < report->field[0]->maxusage; j++)
+                       if (j == 0)
+                               hid_set_field(report->field[0], j, i << 2);
+                       else if (j < sizeof(mapcmd))
+                               hid_set_field(report->field[0], j, mapcmd[j]);
+                       else
+                               hid_set_field(report->field[0], j, 0);
+               usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
+       }
+
+       data->status |= PICOLCD_READY_FB;
+       spin_unlock_irqrestore(&data->lock, flags);
+
+       if (data->fb_bitmap) {
+               if (clear) {
+                       memset(data->fb_vbitmap, 0, PICOLCDFB_SIZE);
+                       memset(data->fb_bitmap, 0, PICOLCDFB_SIZE*data->fb_bpp);
+               }
+               data->fb_force = 1;
+       }
+
+       /* schedule first output of framebuffer */
+       picolcd_fb_refresh(data);
+
+       return 0;
+}
+
+/* Update fb_vbitmap from the screen_base and send changed tiles to device */
+static void picolcd_fb_update(struct fb_info *info)
+{
+       int chip, tile, n;
+       unsigned long flags;
+       struct picolcd_data *data;
+
+       mutex_lock(&info->lock);
+       data = info->par;
+       if (!data)
+               goto out;
+
+       spin_lock_irqsave(&data->lock, flags);
+       if (!(data->status & PICOLCD_READY_FB)) {
+               spin_unlock_irqrestore(&data->lock, flags);
+               picolcd_fb_reset(data, 0);
+       } else {
+               spin_unlock_irqrestore(&data->lock, flags);
+       }
+
+       /*
+        * Translate the framebuffer into the format needed by the PicoLCD.
+        * See display layout above.
+        * Do this one tile after the other and push those tiles that changed.
+        *
+        * Wait for our IO to complete as otherwise we might flood the queue!
+        */
+       n = 0;
+       for (chip = 0; chip < 4; chip++)
+               for (tile = 0; tile < 8; tile++)
+                       if (picolcd_fb_update_tile(data->fb_vbitmap,
+                                       data->fb_bitmap, data->fb_bpp, chip, tile) ||
+                               data->fb_force) {
+                               n += 2;
+                               if (n >= HID_OUTPUT_FIFO_SIZE / 2) {
+                                       mutex_unlock(&info->lock);
+                                       usbhid_wait_io(data->hdev);
+                                       mutex_lock(&info->lock);
+                                       data = info->par;
+                                       if (!data)
+                                               goto out;
+                                       spin_lock_irqsave(&data->lock, flags);
+                                       if (data->status & PICOLCD_FAILED) {
+                                               spin_unlock_irqrestore(&data->lock, flags);
+                                               goto out;
+                                       }
+                                       spin_unlock_irqrestore(&data->lock, flags);
+                                       n = 0;
+                               }
+                               picolcd_fb_send_tile(data->hdev, chip, tile);
+                       }
+       data->fb_force = false;
+       if (n) {
+               mutex_unlock(&info->lock);
+               usbhid_wait_io(data->hdev);
+               return;
+       }
+out:
+       mutex_unlock(&info->lock);
+}
+
+/* Stub to call the system default and update the image on the picoLCD */
+static void picolcd_fb_fillrect(struct fb_info *info,
+               const struct fb_fillrect *rect)
+{
+       if (!info->par)
+               return;
+       sys_fillrect(info, rect);
+
+       schedule_delayed_work(&info->deferred_work, 0);
+}
+
+/* Stub to call the system default and update the image on the picoLCD */
+static void picolcd_fb_copyarea(struct fb_info *info,
+               const struct fb_copyarea *area)
+{
+       if (!info->par)
+               return;
+       sys_copyarea(info, area);
+
+       schedule_delayed_work(&info->deferred_work, 0);
+}
+
+/* Stub to call the system default and update the image on the picoLCD */
+static void picolcd_fb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+       if (!info->par)
+               return;
+       sys_imageblit(info, image);
+
+       schedule_delayed_work(&info->deferred_work, 0);
+}
+
+/*
+ * this is the slow path from userspace. they can seek and write to
+ * the fb. it's inefficient to do anything less than a full screen draw
+ */
+static ssize_t picolcd_fb_write(struct fb_info *info, const char __user *buf,
+               size_t count, loff_t *ppos)
+{
+       ssize_t ret;
+       if (!info->par)
+               return -ENODEV;
+       ret = fb_sys_write(info, buf, count, ppos);
+       if (ret >= 0)
+               schedule_delayed_work(&info->deferred_work, 0);
+       return ret;
+}
+
+static int picolcd_fb_blank(int blank, struct fb_info *info)
+{
+       if (!info->par)
+               return -ENODEV;
+       /* We let fb notification do this for us via lcd/backlight device */
+       return 0;
+}
+
+static void picolcd_fb_destroy(struct fb_info *info)
+{
+       /* make sure no work is deferred */
+       fb_deferred_io_cleanup(info);
+
+       vfree((u8 *)info->fix.smem_start);
+       framebuffer_release(info);
+       printk(KERN_DEBUG "picolcd_fb_destroy(%p)\n", info);
+}
+
+static int picolcd_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+       __u32 bpp      = var->bits_per_pixel;
+       __u32 activate = var->activate;
+
+       /* only allow 1/8 bit depth (8-bit is grayscale) */
+       *var = picolcdfb_var;
+       var->activate = activate;
+       if (bpp >= 8) {
+               var->bits_per_pixel = 8;
+               var->red.length     = 8;
+               var->green.length   = 8;
+               var->blue.length    = 8;
+       } else {
+               var->bits_per_pixel = 1;
+               var->red.length     = 1;
+               var->green.length   = 1;
+               var->blue.length    = 1;
+       }
+       return 0;
+}
+
+static int picolcd_set_par(struct fb_info *info)
+{
+       struct picolcd_data *data = info->par;
+       u8 *tmp_fb, *o_fb;
+       if (!data)
+               return -ENODEV;
+       if (info->var.bits_per_pixel == data->fb_bpp)
+               return 0;
+       /* switch between 1/8 bit depths */
+       if (info->var.bits_per_pixel != 1 && info->var.bits_per_pixel != 8)
+               return -EINVAL;
+
+       o_fb   = data->fb_bitmap;
+       tmp_fb = kmalloc(PICOLCDFB_SIZE*info->var.bits_per_pixel, GFP_KERNEL);
+       if (!tmp_fb)
+               return -ENOMEM;
+
+       /* translate FB content to new bits-per-pixel */
+       if (info->var.bits_per_pixel == 1) {
+               int i, b;
+               for (i = 0; i < PICOLCDFB_SIZE; i++) {
+                       u8 p = 0;
+                       for (b = 0; b < 8; b++) {
+                               p <<= 1;
+                               p |= o_fb[i*8+b] ? 0x01 : 0x00;
+                       }
+                       tmp_fb[i] = p;
+               }
+               memcpy(o_fb, tmp_fb, PICOLCDFB_SIZE);
+               info->fix.visual = FB_VISUAL_MONO01;
+               info->fix.line_length = PICOLCDFB_WIDTH / 8;
+       } else {
+               int i;
+               memcpy(tmp_fb, o_fb, PICOLCDFB_SIZE);
+               for (i = 0; i < PICOLCDFB_SIZE * 8; i++)
+                       o_fb[i] = tmp_fb[i/8] & (0x01 << (7 - i % 8)) ? 0xff : 0x00;
+               info->fix.visual = FB_VISUAL_DIRECTCOLOR;
+               info->fix.line_length = PICOLCDFB_WIDTH;
+       }
+
+       kfree(tmp_fb);
+       data->fb_bpp      = info->var.bits_per_pixel;
+       return 0;
+}
+
+/* Note this can't be const because of struct fb_info definition */
+static struct fb_ops picolcdfb_ops = {
+       .owner        = THIS_MODULE,
+       .fb_destroy   = picolcd_fb_destroy,
+       .fb_read      = fb_sys_read,
+       .fb_write     = picolcd_fb_write,
+       .fb_blank     = picolcd_fb_blank,
+       .fb_fillrect  = picolcd_fb_fillrect,
+       .fb_copyarea  = picolcd_fb_copyarea,
+       .fb_imageblit = picolcd_fb_imageblit,
+       .fb_check_var = picolcd_fb_check_var,
+       .fb_set_par   = picolcd_set_par,
+};
+
+
+/* Callback from deferred IO workqueue */
+static void picolcd_fb_deferred_io(struct fb_info *info, struct list_head *pagelist)
+{
+       picolcd_fb_update(info);
+}
+
+static const struct fb_deferred_io picolcd_fb_defio = {
+       .delay = HZ / PICOLCDFB_UPDATE_RATE_DEFAULT,
+       .deferred_io = picolcd_fb_deferred_io,
+};
+
+
+/*
+ * The "fb_update_rate" sysfs attribute
+ */
+static ssize_t picolcd_fb_update_rate_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct picolcd_data *data = dev_get_drvdata(dev);
+       unsigned i, fb_update_rate = data->fb_update_rate;
+       size_t ret = 0;
+
+       for (i = 1; i <= PICOLCDFB_UPDATE_RATE_LIMIT; i++)
+               if (ret >= PAGE_SIZE)
+                       break;
+               else if (i == fb_update_rate)
+                       ret += snprintf(buf+ret, PAGE_SIZE-ret, "[%u] ", i);
+               else
+                       ret += snprintf(buf+ret, PAGE_SIZE-ret, "%u ", i);
+       if (ret > 0)
+               buf[min(ret, (size_t)PAGE_SIZE)-1] = '\n';
+       return ret;
+}
+
+static ssize_t picolcd_fb_update_rate_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct picolcd_data *data = dev_get_drvdata(dev);
+       int i;
+       unsigned u;
+
+       if (count < 1 || count > 10)
+               return -EINVAL;
+
+       i = sscanf(buf, "%u", &u);
+       if (i != 1)
+               return -EINVAL;
+
+       if (u > PICOLCDFB_UPDATE_RATE_LIMIT)
+               return -ERANGE;
+       else if (u == 0)
+               u = PICOLCDFB_UPDATE_RATE_DEFAULT;
+
+       data->fb_update_rate = u;
+       data->fb_info->fbdefio->delay = HZ / data->fb_update_rate;
+       return count;
+}
+
+static DEVICE_ATTR(fb_update_rate, 0666, picolcd_fb_update_rate_show,
+               picolcd_fb_update_rate_store);
+
+/* initialize Framebuffer device */
+int picolcd_init_framebuffer(struct picolcd_data *data)
+{
+       struct device *dev = &data->hdev->dev;
+       struct fb_info *info = NULL;
+       int i, error = -ENOMEM;
+       u8 *fb_vbitmap = NULL;
+       u8 *fb_bitmap  = NULL;
+       u32 *palette;
+
+       fb_bitmap = vmalloc(PICOLCDFB_SIZE*8);
+       if (fb_bitmap == NULL) {
+               dev_err(dev, "can't get a free page for framebuffer\n");
+               goto err_nomem;
+       }
+
+       fb_vbitmap = kmalloc(PICOLCDFB_SIZE, GFP_KERNEL);
+       if (fb_vbitmap == NULL) {
+               dev_err(dev, "can't alloc vbitmap image buffer\n");
+               goto err_nomem;
+       }
+
+       data->fb_update_rate = PICOLCDFB_UPDATE_RATE_DEFAULT;
+       /* The extra memory is:
+        * - 256*u32 for pseudo_palette
+        * - struct fb_deferred_io
+        */
+       info = framebuffer_alloc(256 * sizeof(u32) +
+                       sizeof(struct fb_deferred_io), dev);
+       if (info == NULL) {
+               dev_err(dev, "failed to allocate a framebuffer\n");
+               goto err_nomem;
+       }
+
+       info->fbdefio = info->par;
+       *info->fbdefio = picolcd_fb_defio;
+       palette  = info->par + sizeof(struct fb_deferred_io);
+       for (i = 0; i < 256; i++)
+               palette[i] = i > 0 && i < 16 ? 0xff : 0;
+       info->pseudo_palette = palette;
+       info->screen_base = (char __force __iomem *)fb_bitmap;
+       info->fbops = &picolcdfb_ops;
+       info->var = picolcdfb_var;
+       info->fix = picolcdfb_fix;
+       info->fix.smem_len   = PICOLCDFB_SIZE*8;
+       info->fix.smem_start = (unsigned long)fb_bitmap;
+       info->par = data;
+       info->flags = FBINFO_FLAG_DEFAULT;
+
+       data->fb_vbitmap = fb_vbitmap;
+       data->fb_bitmap  = fb_bitmap;
+       data->fb_bpp     = picolcdfb_var.bits_per_pixel;
+       error = picolcd_fb_reset(data, 1);
+       if (error) {
+               dev_err(dev, "failed to configure display\n");
+               goto err_cleanup;
+       }
+       error = device_create_file(dev, &dev_attr_fb_update_rate);
+       if (error) {
+               dev_err(dev, "failed to create sysfs attributes\n");
+               goto err_cleanup;
+       }
+       fb_deferred_io_init(info);
+       data->fb_info    = info;
+       error = register_framebuffer(info);
+       if (error) {
+               dev_err(dev, "failed to register framebuffer\n");
+               goto err_sysfs;
+       }
+       /* schedule first output of framebuffer */
+       data->fb_force = 1;
+       schedule_delayed_work(&info->deferred_work, 0);
+       return 0;
+
+err_sysfs:
+       fb_deferred_io_cleanup(info);
+       device_remove_file(dev, &dev_attr_fb_update_rate);
+err_cleanup:
+       data->fb_vbitmap = NULL;
+       data->fb_bitmap  = NULL;
+       data->fb_bpp     = 0;
+       data->fb_info    = NULL;
+
+err_nomem:
+       framebuffer_release(info);
+       vfree(fb_bitmap);
+       kfree(fb_vbitmap);
+       return error;
+}
+
+void picolcd_exit_framebuffer(struct picolcd_data *data)
+{
+       struct fb_info *info = data->fb_info;
+       u8 *fb_vbitmap = data->fb_vbitmap;
+
+       if (!info)
+               return;
+
+       device_remove_file(&data->hdev->dev, &dev_attr_fb_update_rate);
+       info->par = NULL;
+       unregister_framebuffer(info);
+       data->fb_vbitmap = NULL;
+       data->fb_bitmap  = NULL;
+       data->fb_bpp     = 0;
+       data->fb_info    = NULL;
+       kfree(fb_vbitmap);
+}
diff --git a/drivers/hid/hid-picolcd_lcd.c b/drivers/hid/hid-picolcd_lcd.c
new file mode 100644 (file)
index 0000000..2d0ddc5
--- /dev/null
@@ -0,0 +1,107 @@
+/***************************************************************************
+ *   Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org>  *
+ *                                                                         *
+ *   Based on Logitech G13 driver (v0.4)                                   *
+ *     Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu>   *
+ *                                                                         *
+ *   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.               *
+ *                                                                         *
+ *   This driver 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 software. If not see <http://www.gnu.org/licenses/>.  *
+ ***************************************************************************/
+
+#include <linux/hid.h>
+#include "usbhid/usbhid.h"
+#include <linux/usb.h>
+
+#include <linux/fb.h>
+#include <linux/lcd.h>
+
+#include "hid-picolcd.h"
+
+/*
+ * lcd class device
+ */
+static int picolcd_get_contrast(struct lcd_device *ldev)
+{
+       struct picolcd_data *data = lcd_get_data(ldev);
+       return data->lcd_contrast;
+}
+
+static int picolcd_set_contrast(struct lcd_device *ldev, int contrast)
+{
+       struct picolcd_data *data = lcd_get_data(ldev);
+       struct hid_report *report = picolcd_out_report(REPORT_CONTRAST, data->hdev);
+       unsigned long flags;
+
+       if (!report || report->maxfield != 1 || report->field[0]->report_count != 1)
+               return -ENODEV;
+
+       data->lcd_contrast = contrast & 0x0ff;
+       spin_lock_irqsave(&data->lock, flags);
+       hid_set_field(report->field[0], 0, data->lcd_contrast);
+       if (!(data->status & PICOLCD_FAILED))
+               usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
+       spin_unlock_irqrestore(&data->lock, flags);
+       return 0;
+}
+
+static int picolcd_check_lcd_fb(struct lcd_device *ldev, struct fb_info *fb)
+{
+       return fb && fb == picolcd_fbinfo((struct picolcd_data *)lcd_get_data(ldev));
+}
+
+static struct lcd_ops picolcd_lcdops = {
+       .get_contrast   = picolcd_get_contrast,
+       .set_contrast   = picolcd_set_contrast,
+       .check_fb       = picolcd_check_lcd_fb,
+};
+
+int picolcd_init_lcd(struct picolcd_data *data, struct hid_report *report)
+{
+       struct device *dev = &data->hdev->dev;
+       struct lcd_device *ldev;
+
+       if (!report)
+               return -ENODEV;
+       if (report->maxfield != 1 || report->field[0]->report_count != 1 ||
+                       report->field[0]->report_size != 8) {
+               dev_err(dev, "unsupported CONTRAST report");
+               return -EINVAL;
+       }
+
+       ldev = lcd_device_register(dev_name(dev), dev, data, &picolcd_lcdops);
+       if (IS_ERR(ldev)) {
+               dev_err(dev, "failed to register LCD\n");
+               return PTR_ERR(ldev);
+       }
+       ldev->props.max_contrast = 0x0ff;
+       data->lcd_contrast = 0xe5;
+       data->lcd = ldev;
+       picolcd_set_contrast(ldev, 0xe5);
+       return 0;
+}
+
+void picolcd_exit_lcd(struct picolcd_data *data)
+{
+       struct lcd_device *ldev = data->lcd;
+
+       data->lcd = NULL;
+       if (ldev)
+               lcd_device_unregister(ldev);
+}
+
+int picolcd_resume_lcd(struct picolcd_data *data)
+{
+       if (!data->lcd)
+               return 0;
+       return picolcd_set_contrast(data->lcd, data->lcd_contrast);
+}
+
diff --git a/drivers/hid/hid-picolcd_leds.c b/drivers/hid/hid-picolcd_leds.c
new file mode 100644 (file)
index 0000000..28cb6a4
--- /dev/null
@@ -0,0 +1,175 @@
+/***************************************************************************
+ *   Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org>  *
+ *                                                                         *
+ *   Based on Logitech G13 driver (v0.4)                                   *
+ *     Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu>   *
+ *                                                                         *
+ *   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.               *
+ *                                                                         *
+ *   This driver 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 software. If not see <http://www.gnu.org/licenses/>.  *
+ ***************************************************************************/
+
+#include <linux/hid.h>
+#include <linux/hid-debug.h>
+#include <linux/input.h>
+#include "hid-ids.h"
+#include "usbhid/usbhid.h"
+#include <linux/usb.h>
+
+#include <linux/fb.h>
+#include <linux/vmalloc.h>
+#include <linux/backlight.h>
+#include <linux/lcd.h>
+
+#include <linux/leds.h>
+
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+
+#include <linux/completion.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+
+#include "hid-picolcd.h"
+
+
+void picolcd_leds_set(struct picolcd_data *data)
+{
+       struct hid_report *report;
+       unsigned long flags;
+
+       if (!data->led[0])
+               return;
+       report = picolcd_out_report(REPORT_LED_STATE, data->hdev);
+       if (!report || report->maxfield != 1 || report->field[0]->report_count != 1)
+               return;
+
+       spin_lock_irqsave(&data->lock, flags);
+       hid_set_field(report->field[0], 0, data->led_state);
+       if (!(data->status & PICOLCD_FAILED))
+               usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
+       spin_unlock_irqrestore(&data->lock, flags);
+}
+
+static void picolcd_led_set_brightness(struct led_classdev *led_cdev,
+                       enum led_brightness value)
+{
+       struct device *dev;
+       struct hid_device *hdev;
+       struct picolcd_data *data;
+       int i, state = 0;
+
+       dev  = led_cdev->dev->parent;
+       hdev = container_of(dev, struct hid_device, dev);
+       data = hid_get_drvdata(hdev);
+       if (!data)
+               return;
+       for (i = 0; i < 8; i++) {
+               if (led_cdev != data->led[i])
+                       continue;
+               state = (data->led_state >> i) & 1;
+               if (value == LED_OFF && state) {
+                       data->led_state &= ~(1 << i);
+                       picolcd_leds_set(data);
+               } else if (value != LED_OFF && !state) {
+                       data->led_state |= 1 << i;
+                       picolcd_leds_set(data);
+               }
+               break;
+       }
+}
+
+static enum led_brightness picolcd_led_get_brightness(struct led_classdev *led_cdev)
+{
+       struct device *dev;
+       struct hid_device *hdev;
+       struct picolcd_data *data;
+       int i, value = 0;
+
+       dev  = led_cdev->dev->parent;
+       hdev = container_of(dev, struct hid_device, dev);
+       data = hid_get_drvdata(hdev);
+       for (i = 0; i < 8; i++)
+               if (led_cdev == data->led[i]) {
+                       value = (data->led_state >> i) & 1;
+                       break;
+               }
+       return value ? LED_FULL : LED_OFF;
+}
+
+int picolcd_init_leds(struct picolcd_data *data, struct hid_report *report)
+{
+       struct device *dev = &data->hdev->dev;
+       struct led_classdev *led;
+       size_t name_sz = strlen(dev_name(dev)) + 8;
+       char *name;
+       int i, ret = 0;
+
+       if (!report)
+               return -ENODEV;
+       if (report->maxfield != 1 || report->field[0]->report_count != 1 ||
+                       report->field[0]->report_size != 8) {
+               dev_err(dev, "unsupported LED_STATE report");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < 8; i++) {
+               led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL);
+               if (!led) {
+                       dev_err(dev, "can't allocate memory for LED %d\n", i);
+                       ret = -ENOMEM;
+                       goto err;
+               }
+               name = (void *)(&led[1]);
+               snprintf(name, name_sz, "%s::GPO%d", dev_name(dev), i);
+               led->name = name;
+               led->brightness = 0;
+               led->max_brightness = 1;
+               led->brightness_get = picolcd_led_get_brightness;
+               led->brightness_set = picolcd_led_set_brightness;
+
+               data->led[i] = led;
+               ret = led_classdev_register(dev, data->led[i]);
+               if (ret) {
+                       data->led[i] = NULL;
+                       kfree(led);
+                       dev_err(dev, "can't register LED %d\n", i);
+                       goto err;
+               }
+       }
+       return 0;
+err:
+       for (i = 0; i < 8; i++)
+               if (data->led[i]) {
+                       led = data->led[i];
+                       data->led[i] = NULL;
+                       led_classdev_unregister(led);
+                       kfree(led);
+               }
+       return ret;
+}
+
+void picolcd_exit_leds(struct picolcd_data *data)
+{
+       struct led_classdev *led;
+       int i;
+
+       for (i = 0; i < 8; i++) {
+               led = data->led[i];
+               data->led[i] = NULL;
+               if (!led)
+                       continue;
+               led_classdev_unregister(led);
+               kfree(led);
+       }
+}
+
+
index fe23a1eb586bdc6d30e049aaae8c34d49fdc7499..0f02358888a936235c5744ddf167f9a0553e9e9f 100644 (file)
@@ -33,6 +33,8 @@
 #define PAD_DEVICE_ID  0x0F
 
 #define WAC_CMD_LED_CONTROL     0x20
+#define WAC_CMD_ICON_START_STOP     0x21
+#define WAC_CMD_ICON_TRANSFER       0x26
 
 struct wacom_data {
        __u16 tool;
@@ -69,6 +71,91 @@ static enum power_supply_property wacom_ac_props[] = {
        POWER_SUPPLY_PROP_SCOPE,
 };
 
+static void wacom_scramble(__u8 *image)
+{
+       __u16 mask;
+       __u16 s1;
+       __u16 s2;
+       __u16 r1 ;
+       __u16 r2 ;
+       __u16 r;
+       __u8 buf[256];
+       int i, w, x, y, z;
+
+       for (x = 0; x < 32; x++) {
+               for (y = 0; y < 8; y++)
+                       buf[(8 * x) + (7 - y)] = image[(8 * x) + y];
+       }
+
+       /* Change 76543210 into GECA6420 as required by Intuos4 WL
+        *        HGFEDCBA      HFDB7531
+        */
+       for (x = 0; x < 4; x++) {
+               for (y = 0; y < 4; y++) {
+                       for (z = 0; z < 8; z++) {
+                               mask = 0x0001;
+                               r1 = 0;
+                               r2 = 0;
+                               i = (x << 6) + (y << 4) + z;
+                               s1 = buf[i];
+                               s2 = buf[i+8];
+                               for (w = 0; w < 8; w++) {
+                                       r1 |= (s1 & mask);
+                                       r2 |= (s2 & mask);
+                                       s1 <<= 1;
+                                       s2 <<= 1;
+                                       mask <<= 2;
+                               }
+                               r = r1 | (r2 << 1);
+                               i = (x << 6) + (y << 4) + (z << 1);
+                               image[i] = 0xFF & r;
+                               image[i+1] = (0xFF00 & r) >> 8;
+                       }
+               }
+       }
+}
+
+static void wacom_set_image(struct hid_device *hdev, const char *image,
+                                               __u8 icon_no)
+{
+       __u8 rep_data[68];
+       __u8 p[256];
+       int ret, i, j;
+
+       for (i = 0; i < 256; i++)
+               p[i] = image[i];
+
+       rep_data[0] = WAC_CMD_ICON_START_STOP;
+       rep_data[1] = 0;
+       ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
+                               HID_FEATURE_REPORT);
+       if (ret < 0)
+               goto err;
+
+       rep_data[0] = WAC_CMD_ICON_TRANSFER;
+       rep_data[1] = icon_no & 0x07;
+
+       wacom_scramble(p);
+
+       for (i = 0; i < 4; i++) {
+               for (j = 0; j < 64; j++)
+                       rep_data[j + 3] = p[(i << 6) + j];
+
+               rep_data[2] = i;
+               ret = hdev->hid_output_raw_report(hdev, rep_data, 67,
+                                       HID_FEATURE_REPORT);
+       }
+
+       rep_data[0] = WAC_CMD_ICON_START_STOP;
+       rep_data[1] = 0;
+
+       ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
+                               HID_FEATURE_REPORT);
+
+err:
+       return;
+}
+
 static void wacom_leds_set_brightness(struct led_classdev *led_dev,
                                                enum led_brightness value)
 {
@@ -91,7 +178,10 @@ static void wacom_leds_set_brightness(struct led_classdev *led_dev,
        if (buf) {
                buf[0] = WAC_CMD_LED_CONTROL;
                buf[1] = led;
-               buf[2] = value;
+               buf[2] = value >> 2;
+               buf[3] = value;
+               /* use fixed brightness for OLEDs */
+               buf[4] = 0x08;
                hdev->hid_output_raw_report(hdev, buf, 9, HID_FEATURE_REPORT);
                kfree(buf);
        }
@@ -317,6 +407,34 @@ static ssize_t wacom_store_speed(struct device *dev,
 static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR | S_IWGRP,
                wacom_show_speed, wacom_store_speed);
 
+#define WACOM_STORE(OLED_ID)                                           \
+static ssize_t wacom_oled##OLED_ID##_store(struct device *dev,         \
+                               struct device_attribute *attr,          \
+                               const char *buf, size_t count)          \
+{                                                                      \
+       struct hid_device *hdev = container_of(dev, struct hid_device,  \
+                               dev);                                   \
+                                                                       \
+       if (count != 256)                                               \
+               return -EINVAL;                                         \
+                                                                       \
+       wacom_set_image(hdev, buf, OLED_ID);                            \
+                                                                       \
+       return count;                                                   \
+}                                                                      \
+                                                                       \
+static DEVICE_ATTR(oled##OLED_ID##_img, S_IWUSR | S_IWGRP, NULL,       \
+                               wacom_oled##OLED_ID##_store)
+
+WACOM_STORE(0);
+WACOM_STORE(1);
+WACOM_STORE(2);
+WACOM_STORE(3);
+WACOM_STORE(4);
+WACOM_STORE(5);
+WACOM_STORE(6);
+WACOM_STORE(7);
+
 static int wacom_gr_parse_report(struct hid_device *hdev,
                        struct wacom_data *wdata,
                        struct input_dev *input, unsigned char *data)
@@ -717,6 +835,24 @@ static int wacom_probe(struct hid_device *hdev,
                hid_warn(hdev,
                         "can't create sysfs speed attribute err: %d\n", ret);
 
+#define OLED_INIT(OLED_ID)                                             \
+       do {                                                            \
+               ret = device_create_file(&hdev->dev,                    \
+                               &dev_attr_oled##OLED_ID##_img);         \
+               if (ret)                                                \
+                       hid_warn(hdev,                                  \
+                        "can't create sysfs oled attribute, err: %d\n", ret);\
+       } while (0)
+
+OLED_INIT(0);
+OLED_INIT(1);
+OLED_INIT(2);
+OLED_INIT(3);
+OLED_INIT(4);
+OLED_INIT(5);
+OLED_INIT(6);
+OLED_INIT(7);
+
        wdata->features = 0;
        wacom_set_features(hdev, 1);
 
@@ -781,6 +917,14 @@ static void wacom_remove(struct hid_device *hdev)
        struct wacom_data *wdata = hid_get_drvdata(hdev);
 
        wacom_destroy_leds(hdev);
+       device_remove_file(&hdev->dev, &dev_attr_oled0_img);
+       device_remove_file(&hdev->dev, &dev_attr_oled1_img);
+       device_remove_file(&hdev->dev, &dev_attr_oled2_img);
+       device_remove_file(&hdev->dev, &dev_attr_oled3_img);
+       device_remove_file(&hdev->dev, &dev_attr_oled4_img);
+       device_remove_file(&hdev->dev, &dev_attr_oled5_img);
+       device_remove_file(&hdev->dev, &dev_attr_oled6_img);
+       device_remove_file(&hdev->dev, &dev_attr_oled7_img);
        device_remove_file(&hdev->dev, &dev_attr_speed);
        hid_hw_stop(hdev);
 
index 3b6f7bf5a77e1407d787742886d4d10867890f82..7c47fc3f7b2b0b28f27021c75bb3b8d8f3771c4d 100644 (file)
@@ -559,21 +559,28 @@ int __init hidraw_init(void)
 
        if (result < 0) {
                pr_warn("can't get major number\n");
-               result = 0;
                goto out;
        }
 
        hidraw_class = class_create(THIS_MODULE, "hidraw");
        if (IS_ERR(hidraw_class)) {
                result = PTR_ERR(hidraw_class);
-               unregister_chrdev(hidraw_major, "hidraw");
-               goto out;
+               goto error_cdev;
        }
 
         cdev_init(&hidraw_cdev, &hidraw_ops);
-        cdev_add(&hidraw_cdev, dev_id, HIDRAW_MAX_DEVICES);
+       result = cdev_add(&hidraw_cdev, dev_id, HIDRAW_MAX_DEVICES);
+       if (result < 0)
+               goto error_class;
+
 out:
        return result;
+
+error_class:
+       class_destroy(hidraw_class);
+error_cdev:
+       unregister_chrdev_region(dev_id, HIDRAW_MAX_DEVICES);
+       goto out;
 }
 
 void hidraw_exit(void)
index 903eef3d3e10034f8e36974ba4e95ee746438702..ccb8de6156f3f3873247074c573978e0b4bed1e1 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_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET },
        { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1, HID_QUIRK_NO_INIT_REPORTS },
        { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2, HID_QUIRK_NO_INIT_REPORTS },
index 86f8885aeb4574fcb8a78c6b56446d5430124e3d..771e24f2981d29b160e5f616e86a9e83d86bd5ce 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/hyperv.h>
+#include <linux/version.h>
 #include <asm/hyperv.h>
 #include "hyperv_vmbus.h"
 
@@ -164,9 +165,11 @@ int hv_init(void)
 
        max_leaf = query_hypervisor_info();
 
-       /* Write our OS info */
-       wrmsrl(HV_X64_MSR_GUEST_OS_ID, HV_LINUX_GUEST_ID);
-       hv_context.guestid = HV_LINUX_GUEST_ID;
+       /*
+        * Write our OS ID.
+        */
+       hv_context.guestid = generate_guest_id(0, LINUX_VERSION_CODE, 0);
+       wrmsrl(HV_X64_MSR_GUEST_OS_ID, hv_context.guestid);
 
        /* See if the hypercall page is already set */
        rdmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
index 0614ff3a7d7e2ece52e0a4e487b60f96c9bc521d..d8d1fadb398aa75e11375fffe8826dbd8781f1fa 100644 (file)
@@ -410,10 +410,49 @@ enum {
 
 #define HV_PRESENT_BIT                 0x80000000
 
-#define HV_LINUX_GUEST_ID_LO           0x00000000
-#define HV_LINUX_GUEST_ID_HI           2976579765
-#define HV_LINUX_GUEST_ID              (((u64)HV_LINUX_GUEST_ID_HI << 32) | \
-                                          HV_LINUX_GUEST_ID_LO)
+/*
+ * The guest OS needs to register the guest ID with the hypervisor.
+ * The guest ID is a 64 bit entity and the structure of this ID is
+ * specified in the Hyper-V specification:
+ *
+ * http://msdn.microsoft.com/en-us/library/windows/hardware/ff542653%28v=vs.85%29.aspx
+ *
+ * While the current guideline does not specify how Linux guest ID(s)
+ * need to be generated, our plan is to publish the guidelines for
+ * Linux and other guest operating systems that currently are hosted
+ * on Hyper-V. The implementation here conforms to this yet
+ * unpublished guidelines.
+ *
+ *
+ * Bit(s)
+ * 63 - Indicates if the OS is Open Source or not; 1 is Open Source
+ * 62:56 - Os Type; Linux is 0x100
+ * 55:48 - Distro specific identification
+ * 47:16 - Linux kernel version number
+ * 15:0  - Distro specific identification
+ *
+ *
+ */
+
+#define HV_LINUX_VENDOR_ID             0x8100
+
+/*
+ * Generate the guest ID based on the guideline described above.
+ */
+
+static inline  __u64 generate_guest_id(__u8 d_info1, __u32 kernel_version,
+                                       __u16 d_info2)
+{
+       __u64 guest_id = 0;
+
+       guest_id = (((__u64)HV_LINUX_VENDOR_ID) << 48);
+       guest_id |= (((__u64)(d_info1)) << 48);
+       guest_id |= (((__u64)(kernel_version)) << 16);
+       guest_id |= ((__u64)(d_info2));
+
+       return guest_id;
+}
+
 
 #define HV_CPU_POWER_MANAGEMENT                (1 << 0)
 #define HV_RECOMMENDATIONS_MAX         4
index 4748086eaaf26ad41bd3b2fb0c7e40be4a34e054..b76e8b3212660034e86f85ac101b56c3d0307de5 100644 (file)
@@ -146,43 +146,9 @@ static ssize_t vmbus_show_device_attr(struct device *dev,
        get_channel_info(hv_dev, device_info);
 
        if (!strcmp(dev_attr->attr.name, "class_id")) {
-               ret = sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-"
-                              "%02x%02x%02x%02x%02x%02x%02x%02x}\n",
-                              device_info->chn_type.b[3],
-                              device_info->chn_type.b[2],
-                              device_info->chn_type.b[1],
-                              device_info->chn_type.b[0],
-                              device_info->chn_type.b[5],
-                              device_info->chn_type.b[4],
-                              device_info->chn_type.b[7],
-                              device_info->chn_type.b[6],
-                              device_info->chn_type.b[8],
-                              device_info->chn_type.b[9],
-                              device_info->chn_type.b[10],
-                              device_info->chn_type.b[11],
-                              device_info->chn_type.b[12],
-                              device_info->chn_type.b[13],
-                              device_info->chn_type.b[14],
-                              device_info->chn_type.b[15]);
+               ret = sprintf(buf, "{%pUl}\n", device_info->chn_type.b);
        } else if (!strcmp(dev_attr->attr.name, "device_id")) {
-               ret = sprintf(buf, "{%02x%02x%02x%02x-%02x%02x-%02x%02x-"
-                              "%02x%02x%02x%02x%02x%02x%02x%02x}\n",
-                              device_info->chn_instance.b[3],
-                              device_info->chn_instance.b[2],
-                              device_info->chn_instance.b[1],
-                              device_info->chn_instance.b[0],
-                              device_info->chn_instance.b[5],
-                              device_info->chn_instance.b[4],
-                              device_info->chn_instance.b[7],
-                              device_info->chn_instance.b[6],
-                              device_info->chn_instance.b[8],
-                              device_info->chn_instance.b[9],
-                              device_info->chn_instance.b[10],
-                              device_info->chn_instance.b[11],
-                              device_info->chn_instance.b[12],
-                              device_info->chn_instance.b[13],
-                              device_info->chn_instance.b[14],
-                              device_info->chn_instance.b[15]);
+               ret = sprintf(buf, "{%pUl}\n", device_info->chn_instance.b);
        } else if (!strcmp(dev_attr->attr.name, "modalias")) {
                print_alias_name(hv_dev, alias_name);
                ret = sprintf(buf, "vmbus:%s\n", alias_name);
index b0a2e4c37e12ff986f5155fdce7529f2b4a1ca8e..f50cb440575d5ccf148cb8538353baa06a8e597f 100644 (file)
@@ -179,6 +179,16 @@ config SENSORS_ADM9240
          This driver can also be built as a module.  If so, the module
          will be called adm9240.
 
+config SENSORS_ADT7410
+       tristate "Analog Devices ADT7410"
+       depends on I2C && EXPERIMENTAL
+       help
+         If you say yes here you get support for the Analog Devices
+         ADT7410 temperature monitoring chip.
+
+         This driver can also be built as a module. If so, the module
+         will be called adt7410.
+
 config SENSORS_ADT7411
        tristate "Analog Devices ADT7411"
        depends on I2C && EXPERIMENTAL
index 7aa98119c4ab2c21036abd6da0cde7b1eb728fd3..8b3d4382f61eed6b33e149740d6c12c6b4d868ce 100644 (file)
@@ -34,6 +34,7 @@ obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o
 obj-$(CONFIG_SENSORS_ADS1015)  += ads1015.o
 obj-$(CONFIG_SENSORS_ADS7828)  += ads7828.o
 obj-$(CONFIG_SENSORS_ADS7871)  += ads7871.o
+obj-$(CONFIG_SENSORS_ADT7410)  += adt7410.o
 obj-$(CONFIG_SENSORS_ADT7411)  += adt7411.o
 obj-$(CONFIG_SENSORS_ADT7462)  += adt7462.o
 obj-$(CONFIG_SENSORS_ADT7470)  += adt7470.o
index d4419b47f3d424b33407345cf17535c2f5731478..78b81793ddd99c18bc98506aed4505aeeaca4726 100644 (file)
@@ -1278,7 +1278,8 @@ static int __devinit abituguru_probe(struct platform_device *pdev)
                0x00, 0x01, 0x03, 0x04, 0x0A, 0x08, 0x0E, 0x02,
                0x09, 0x06, 0x05, 0x0B, 0x0F, 0x0D, 0x07, 0x0C };
 
-       data = kzalloc(sizeof(struct abituguru_data), GFP_KERNEL);
+       data = devm_kzalloc(&pdev->dev, sizeof(struct abituguru_data),
+                           GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
@@ -1430,8 +1431,6 @@ abituguru_probe_error:
        for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++)
                device_remove_file(&pdev->dev,
                        &abituguru_sysfs_attr[i].dev_attr);
-       platform_set_drvdata(pdev, NULL);
-       kfree(data);
        return res;
 }
 
@@ -1446,8 +1445,6 @@ static int __devexit abituguru_remove(struct platform_device *pdev)
        for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++)
                device_remove_file(&pdev->dev,
                        &abituguru_sysfs_attr[i].dev_attr);
-       platform_set_drvdata(pdev, NULL);
-       kfree(data);
 
        return 0;
 }
index 5d582aebff8747343938ec3e5d89c6cb58f9a775..b174b8b2b4dfedcc8bc8879f6f44b6825e6d8747 100644 (file)
@@ -976,7 +976,8 @@ static int __devinit abituguru3_probe(struct platform_device *pdev)
        u8 buf[2];
        u16 id;
 
-       data = kzalloc(sizeof(struct abituguru3_data), GFP_KERNEL);
+       data = devm_kzalloc(&pdev->dev, sizeof(struct abituguru3_data),
+                           GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
@@ -1068,7 +1069,6 @@ abituguru3_probe_error:
        for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++)
                device_remove_file(&pdev->dev,
                        &abituguru3_sysfs_attr[i].dev_attr);
-       kfree(data);
        return res;
 }
 
@@ -1084,8 +1084,6 @@ static int __devexit abituguru3_remove(struct platform_device *pdev)
        for (i = 0; i < ARRAY_SIZE(abituguru3_sysfs_attr); i++)
                device_remove_file(&pdev->dev,
                        &abituguru3_sysfs_attr[i].dev_attr);
-       kfree(data);
-
        return 0;
 }
 
index cfec802cf9ca949b705d24a1d862a702af223193..455294f89eac3815a9f53d3e74cb775ff52e8123 100644 (file)
@@ -104,16 +104,16 @@ static int __devinit ad7314_probe(struct spi_device *spi_dev)
        int ret;
        struct ad7314_data *chip;
 
-       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
-       if (chip == NULL) {
-               ret = -ENOMEM;
-               goto error_ret;
-       }
+       chip = devm_kzalloc(&spi_dev->dev, sizeof(*chip), GFP_KERNEL);
+       if (chip == NULL)
+               return -ENOMEM;
+
        dev_set_drvdata(&spi_dev->dev, chip);
 
        ret = sysfs_create_group(&spi_dev->dev.kobj, &ad7314_group);
        if (ret < 0)
-               goto error_free_chip;
+               return ret;
+
        chip->hwmon_dev = hwmon_device_register(&spi_dev->dev);
        if (IS_ERR(chip->hwmon_dev)) {
                ret = PTR_ERR(chip->hwmon_dev);
@@ -124,9 +124,6 @@ static int __devinit ad7314_probe(struct spi_device *spi_dev)
        return 0;
 error_remove_group:
        sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group);
-error_free_chip:
-       kfree(chip);
-error_ret:
        return ret;
 }
 
@@ -136,7 +133,6 @@ static int __devexit ad7314_remove(struct spi_device *spi_dev)
 
        hwmon_device_unregister(chip->hwmon_dev);
        sysfs_remove_group(&spi_dev->dev.kobj, &ad7314_group);
-       kfree(chip);
 
        return 0;
 }
index 06d2d60d1fd0ee7785e529344b584a887976dccf..b420fb3f3a71b78f66aec7991dea181f4f51d022 100644 (file)
@@ -185,16 +185,13 @@ static int ad7414_probe(struct i2c_client *client,
        int err;
 
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA |
-                                    I2C_FUNC_SMBUS_READ_WORD_DATA)) {
-               err = -EOPNOTSUPP;
-               goto exit;
-       }
+                                    I2C_FUNC_SMBUS_READ_WORD_DATA))
+               return -EOPNOTSUPP;
 
-       data = kzalloc(sizeof(struct ad7414_data), GFP_KERNEL);
-       if (!data) {
-               err = -ENOMEM;
-               goto exit;
-       }
+       data = devm_kzalloc(&client->dev, sizeof(struct ad7414_data),
+                           GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
 
        i2c_set_clientdata(client, data);
        mutex_init(&data->lock);
@@ -214,7 +211,7 @@ static int ad7414_probe(struct i2c_client *client,
        /* Register sysfs hooks */
        err = sysfs_create_group(&client->dev.kobj, &ad7414_group);
        if (err)
-               goto exit_free;
+               return err;
 
        data->hwmon_dev = hwmon_device_register(&client->dev);
        if (IS_ERR(data->hwmon_dev)) {
@@ -226,9 +223,6 @@ static int ad7414_probe(struct i2c_client *client,
 
 exit_remove:
        sysfs_remove_group(&client->dev.kobj, &ad7414_group);
-exit_free:
-       kfree(data);
-exit:
        return err;
 }
 
@@ -238,7 +232,6 @@ static int __devexit ad7414_remove(struct i2c_client *client)
 
        hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &ad7414_group);
-       kfree(data);
        return 0;
 }
 
index a50a6bef16c4b526a03dc176da76216dc9c4d2af..57d4a6295675159e38f67603bdd5fc96526e0938 100644 (file)
@@ -227,16 +227,13 @@ static int ad7418_probe(struct i2c_client *client,
        int err;
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
-                                       I2C_FUNC_SMBUS_WORD_DATA)) {
-               err = -EOPNOTSUPP;
-               goto exit;
-       }
+                                       I2C_FUNC_SMBUS_WORD_DATA))
+               return -EOPNOTSUPP;
 
-       data = kzalloc(sizeof(struct ad7418_data), GFP_KERNEL);
-       if (!data) {
-               err = -ENOMEM;
-               goto exit;
-       }
+       data = devm_kzalloc(&client->dev, sizeof(struct ad7418_data),
+                           GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
 
        i2c_set_clientdata(client, data);
 
@@ -268,7 +265,7 @@ static int ad7418_probe(struct i2c_client *client,
        /* Register sysfs hooks */
        err = sysfs_create_group(&client->dev.kobj, &data->attrs);
        if (err)
-               goto exit_free;
+               return err;
 
        data->hwmon_dev = hwmon_device_register(&client->dev);
        if (IS_ERR(data->hwmon_dev)) {
@@ -280,9 +277,6 @@ static int ad7418_probe(struct i2c_client *client,
 
 exit_remove:
        sysfs_remove_group(&client->dev.kobj, &data->attrs);
-exit_free:
-       kfree(data);
-exit:
        return err;
 }
 
@@ -291,7 +285,6 @@ static int ad7418_remove(struct i2c_client *client)
        struct ad7418_data *data = i2c_get_clientdata(client);
        hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &data->attrs);
-       kfree(data);
        return 0;
 }
 
index a3d3183454adb16e6854e0c0558ec1dc5a13d787..111af7c4a3d430749fa7c7ec269b4606778f8c42 100644 (file)
@@ -171,7 +171,7 @@ static int __devinit adcxx_probe(struct spi_device *spi)
        int status;
        int i;
 
-       adc = kzalloc(sizeof *adc, GFP_KERNEL);
+       adc = devm_kzalloc(&spi->dev, sizeof(*adc), GFP_KERNEL);
        if (!adc)
                return -ENOMEM;
 
@@ -208,7 +208,6 @@ out_err:
 
        spi_set_drvdata(spi, NULL);
        mutex_unlock(&adc->lock);
-       kfree(adc);
        return status;
 }
 
@@ -224,7 +223,6 @@ static int __devexit adcxx_remove(struct spi_device *spi)
 
        spi_set_drvdata(spi, NULL);
        mutex_unlock(&adc->lock);
-       kfree(adc);
 
        return 0;
 }
index 80cc465d8ac7006404d117be0a0081c6a76b1a53..97f4718382f6c5e6ab1f8bb9e617f237866a1194 100644 (file)
@@ -342,11 +342,10 @@ static int adm1029_probe(struct i2c_client *client,
        struct adm1029_data *data;
        int err;
 
-       data = kzalloc(sizeof(struct adm1029_data), GFP_KERNEL);
-       if (!data) {
-               err = -ENOMEM;
-               goto exit;
-       }
+       data = devm_kzalloc(&client->dev, sizeof(struct adm1029_data),
+                           GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
 
        i2c_set_clientdata(client, data);
        mutex_init(&data->update_lock);
@@ -355,15 +354,13 @@ static int adm1029_probe(struct i2c_client *client,
         * Initialize the ADM1029 chip
         * Check config register
         */
-       if (adm1029_init_client(client) == 0) {
-               err = -ENODEV;
-               goto exit_free;
-       }
+       if (adm1029_init_client(client) == 0)
+               return -ENODEV;
 
        /* Register sysfs hooks */
        err = sysfs_create_group(&client->dev.kobj, &adm1029_group);
        if (err)
-               goto exit_free;
+               return err;
 
        data->hwmon_dev = hwmon_device_register(&client->dev);
        if (IS_ERR(data->hwmon_dev)) {
@@ -375,9 +372,6 @@ static int adm1029_probe(struct i2c_client *client,
 
  exit_remove_files:
        sysfs_remove_group(&client->dev.kobj, &adm1029_group);
- exit_free:
-       kfree(data);
- exit:
        return err;
 }
 
@@ -405,7 +399,6 @@ static int adm1029_remove(struct i2c_client *client)
        hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &adm1029_group);
 
-       kfree(data);
        return 0;
 }
 
index 1958f03efd7aaa43f72416f809eb42fe569b413f..2798246ad81470988fadd920dee5e9282f463445 100644 (file)
@@ -156,7 +156,6 @@ static int ads1015_remove(struct i2c_client *client)
        hwmon_device_unregister(data->hwmon_dev);
        for (k = 0; k < ADS1015_CHANNELS; ++k)
                device_remove_file(&client->dev, &ads1015_in[k].dev_attr);
-       kfree(data);
        return 0;
 }
 
@@ -254,11 +253,10 @@ static int ads1015_probe(struct i2c_client *client,
        int err;
        unsigned int k;
 
-       data = kzalloc(sizeof(struct ads1015_data), GFP_KERNEL);
-       if (!data) {
-               err = -ENOMEM;
-               goto exit;
-       }
+       data = devm_kzalloc(&client->dev, sizeof(struct ads1015_data),
+                           GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
 
        i2c_set_clientdata(client, data);
        mutex_init(&data->update_lock);
@@ -284,8 +282,6 @@ static int ads1015_probe(struct i2c_client *client,
 exit_remove:
        for (k = 0; k < ADS1015_CHANNELS; ++k)
                device_remove_file(&client->dev, &ads1015_in[k].dev_attr);
-       kfree(data);
-exit:
        return err;
 }
 
index bf3fdf4955956766559b6e52885715379322ac2b..1f9e8af0f322a045ae09e4db7f877a4e3db4a8d8 100644 (file)
@@ -154,7 +154,6 @@ static int ads7828_remove(struct i2c_client *client)
        struct ads7828_data *data = i2c_get_clientdata(client);
        hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &ads7828_group);
-       kfree(i2c_get_clientdata(client));
        return 0;
 }
 
@@ -217,11 +216,10 @@ static int ads7828_probe(struct i2c_client *client,
        struct ads7828_data *data;
        int err;
 
-       data = kzalloc(sizeof(struct ads7828_data), GFP_KERNEL);
-       if (!data) {
-               err = -ENOMEM;
-               goto exit;
-       }
+       data = devm_kzalloc(&client->dev, sizeof(struct ads7828_data),
+                           GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
 
        i2c_set_clientdata(client, data);
        mutex_init(&data->update_lock);
@@ -229,7 +227,7 @@ static int ads7828_probe(struct i2c_client *client,
        /* Register sysfs hooks */
        err = sysfs_create_group(&client->dev.kobj, &ads7828_group);
        if (err)
-               goto exit_free;
+               return err;
 
        data->hwmon_dev = hwmon_device_register(&client->dev);
        if (IS_ERR(data->hwmon_dev)) {
@@ -241,9 +239,6 @@ static int ads7828_probe(struct i2c_client *client,
 
 exit_remove:
        sysfs_remove_group(&client->dev.kobj, &ads7828_group);
-exit_free:
-       kfree(data);
-exit:
        return err;
 }
 
index e65c6e45d36b05a24241680558fd2012be3f3c85..e8377079ad905088ebf41e0c8d41f89381ad3956 100644 (file)
@@ -189,20 +189,17 @@ static int __devinit ads7871_probe(struct spi_device *spi)
         * because there is no other error checking on an SPI bus
         * we need to make sure we really have a chip
         */
-       if (val != ret) {
-               err = -ENODEV;
-               goto exit;
-       }
+       if (val != ret)
+               return -ENODEV;
 
-       pdata = kzalloc(sizeof(struct ads7871_data), GFP_KERNEL);
-       if (!pdata) {
-               err = -ENOMEM;
-               goto exit;
-       }
+       pdata = devm_kzalloc(&spi->dev, sizeof(struct ads7871_data),
+                            GFP_KERNEL);
+       if (!pdata)
+               return -ENOMEM;
 
        err = sysfs_create_group(&spi->dev.kobj, &ads7871_group);
        if (err < 0)
-               goto error_free;
+               return err;
 
        spi_set_drvdata(spi, pdata);
 
@@ -216,9 +213,6 @@ static int __devinit ads7871_probe(struct spi_device *spi)
 
 error_remove:
        sysfs_remove_group(&spi->dev.kobj, &ads7871_group);
-error_free:
-       kfree(pdata);
-exit:
        return err;
 }
 
@@ -228,7 +222,6 @@ static int __devexit ads7871_remove(struct spi_device *spi)
 
        hwmon_device_unregister(pdata->hwmon_dev);
        sysfs_remove_group(&spi->dev.kobj, &ads7871_group);
-       kfree(pdata);
        return 0;
 }
 
diff --git a/drivers/hwmon/adt7410.c b/drivers/hwmon/adt7410.c
new file mode 100644 (file)
index 0000000..030c8d7
--- /dev/null
@@ -0,0 +1,464 @@
+/*
+ * adt7410.c - Part of lm_sensors, Linux kernel modules for hardware
+ *      monitoring
+ * This driver handles the ADT7410 and compatible digital temperature sensors.
+ * Hartmut Knaack <knaack.h@gmx.de> 2012-07-22
+ * based on lm75.c by Frodo Looijaard <frodol@dds.nl>
+ * and adt7410.c from iio-staging by Sonic Zhang <sonic.zhang@analog.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+
+/*
+ * ADT7410 registers definition
+ */
+
+#define ADT7410_TEMPERATURE            0
+#define ADT7410_STATUS                 2
+#define ADT7410_CONFIG                 3
+#define ADT7410_T_ALARM_HIGH           4
+#define ADT7410_T_ALARM_LOW            6
+#define ADT7410_T_CRIT                 8
+#define ADT7410_T_HYST                 0xA
+
+/*
+ * ADT7410 status
+ */
+#define ADT7410_STAT_T_LOW             (1 << 4)
+#define ADT7410_STAT_T_HIGH            (1 << 5)
+#define ADT7410_STAT_T_CRIT            (1 << 6)
+#define ADT7410_STAT_NOT_RDY           (1 << 7)
+
+/*
+ * ADT7410 config
+ */
+#define ADT7410_FAULT_QUEUE_MASK       (1 << 0 | 1 << 1)
+#define ADT7410_CT_POLARITY            (1 << 2)
+#define ADT7410_INT_POLARITY           (1 << 3)
+#define ADT7410_EVENT_MODE             (1 << 4)
+#define ADT7410_MODE_MASK              (1 << 5 | 1 << 6)
+#define ADT7410_FULL                   (0 << 5 | 0 << 6)
+#define ADT7410_PD                     (1 << 5 | 1 << 6)
+#define ADT7410_RESOLUTION             (1 << 7)
+
+/*
+ * ADT7410 masks
+ */
+#define ADT7410_T13_VALUE_MASK                 0xFFF8
+#define ADT7410_T_HYST_MASK                    0xF
+
+/* straight from the datasheet */
+#define ADT7410_TEMP_MIN (-55000)
+#define ADT7410_TEMP_MAX 150000
+
+enum adt7410_type {            /* keep sorted in alphabetical order */
+       adt7410,
+};
+
+/* Addresses scanned */
+static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
+                                       I2C_CLIENT_END };
+
+static const u8 ADT7410_REG_TEMP[4] = {
+       ADT7410_TEMPERATURE,            /* input */
+       ADT7410_T_ALARM_HIGH,           /* high */
+       ADT7410_T_ALARM_LOW,            /* low */
+       ADT7410_T_CRIT,                 /* critical */
+};
+
+/* Each client has this additional data */
+struct adt7410_data {
+       struct device           *hwmon_dev;
+       struct mutex            update_lock;
+       u8                      config;
+       u8                      oldconfig;
+       bool                    valid;          /* true if registers valid */
+       unsigned long           last_updated;   /* In jiffies */
+       s16                     temp[4];        /* Register values,
+                                                  0 = input
+                                                  1 = high
+                                                  2 = low
+                                                  3 = critical */
+       u8                      hyst;           /* hysteresis offset */
+};
+
+/*
+ * adt7410 register access by I2C
+ */
+static int adt7410_temp_ready(struct i2c_client *client)
+{
+       int i, status;
+
+       for (i = 0; i < 6; i++) {
+               status = i2c_smbus_read_byte_data(client, ADT7410_STATUS);
+               if (status < 0)
+                       return status;
+               if (!(status & ADT7410_STAT_NOT_RDY))
+                       return 0;
+               msleep(60);
+       }
+       return -ETIMEDOUT;
+}
+
+static struct adt7410_data *adt7410_update_device(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adt7410_data *data = i2c_get_clientdata(client);
+       struct adt7410_data *ret = data;
+       mutex_lock(&data->update_lock);
+
+       if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+           || !data->valid) {
+               int i, status;
+
+               dev_dbg(&client->dev, "Starting update\n");
+
+               status = adt7410_temp_ready(client); /* check for new value */
+               if (unlikely(status)) {
+                       ret = ERR_PTR(status);
+                       goto abort;
+               }
+               for (i = 0; i < ARRAY_SIZE(data->temp); i++) {
+                       status = i2c_smbus_read_word_swapped(client,
+                                                       ADT7410_REG_TEMP[i]);
+                       if (unlikely(status < 0)) {
+                               dev_dbg(dev,
+                                       "Failed to read value: reg %d, error %d\n",
+                                       ADT7410_REG_TEMP[i], status);
+                               ret = ERR_PTR(status);
+                               goto abort;
+                       }
+                       data->temp[i] = status;
+               }
+               status = i2c_smbus_read_byte_data(client, ADT7410_T_HYST);
+               if (unlikely(status < 0)) {
+                       dev_dbg(dev,
+                               "Failed to read value: reg %d, error %d\n",
+                               ADT7410_T_HYST, status);
+                       ret = ERR_PTR(status);
+                       goto abort;
+               }
+               data->hyst = status;
+               data->last_updated = jiffies;
+               data->valid = true;
+       }
+
+abort:
+       mutex_unlock(&data->update_lock);
+       return ret;
+}
+
+static s16 ADT7410_TEMP_TO_REG(long temp)
+{
+       return DIV_ROUND_CLOSEST(SENSORS_LIMIT(temp, ADT7410_TEMP_MIN,
+                                              ADT7410_TEMP_MAX) * 128, 1000);
+}
+
+static int ADT7410_REG_TO_TEMP(struct adt7410_data *data, s16 reg)
+{
+       /* in 13 bit mode, bits 0-2 are status flags - mask them out */
+       if (!(data->config & ADT7410_RESOLUTION))
+               reg &= ADT7410_T13_VALUE_MASK;
+       /*
+        * temperature is stored in twos complement format, in steps of
+        * 1/128°C
+        */
+       return DIV_ROUND_CLOSEST(reg * 1000, 128);
+}
+
+/*-----------------------------------------------------------------------*/
+
+/* sysfs attributes for hwmon */
+
+static ssize_t adt7410_show_temp(struct device *dev,
+                                struct device_attribute *da, char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       struct adt7410_data *data = adt7410_update_device(dev);
+
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       return sprintf(buf, "%d\n", ADT7410_REG_TO_TEMP(data,
+                      data->temp[attr->index]));
+}
+
+static ssize_t adt7410_set_temp(struct device *dev,
+                               struct device_attribute *da,
+                               const char *buf, size_t count)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adt7410_data *data = i2c_get_clientdata(client);
+       int nr = attr->index;
+       long temp;
+       int ret;
+
+       ret = kstrtol(buf, 10, &temp);
+       if (ret)
+               return ret;
+
+       mutex_lock(&data->update_lock);
+       data->temp[nr] = ADT7410_TEMP_TO_REG(temp);
+       ret = i2c_smbus_write_word_swapped(client, ADT7410_REG_TEMP[nr],
+                                          data->temp[nr]);
+       if (ret)
+               count = ret;
+       mutex_unlock(&data->update_lock);
+       return count;
+}
+
+static ssize_t adt7410_show_t_hyst(struct device *dev,
+                                  struct device_attribute *da,
+                                  char *buf)
+{
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       struct adt7410_data *data;
+       int nr = attr->index;
+       int hyst;
+
+       data = adt7410_update_device(dev);
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+       hyst = (data->hyst & ADT7410_T_HYST_MASK) * 1000;
+
+       /*
+        * hysteresis is stored as a 4 bit offset in the device, convert it
+        * to an absolute value
+        */
+       if (nr == 2)    /* min has positive offset, others have negative */
+               hyst = -hyst;
+       return sprintf(buf, "%d\n",
+                      ADT7410_REG_TO_TEMP(data, data->temp[nr]) - hyst);
+}
+
+static ssize_t adt7410_set_t_hyst(struct device *dev,
+                                 struct device_attribute *da,
+                                 const char *buf, size_t count)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adt7410_data *data = i2c_get_clientdata(client);
+       int limit, ret;
+       long hyst;
+
+       ret = kstrtol(buf, 10, &hyst);
+       if (ret)
+               return ret;
+       /* convert absolute hysteresis value to a 4 bit delta value */
+       limit = ADT7410_REG_TO_TEMP(data, data->temp[1]);
+       hyst = SENSORS_LIMIT(hyst, ADT7410_TEMP_MIN, ADT7410_TEMP_MAX);
+       data->hyst = SENSORS_LIMIT(DIV_ROUND_CLOSEST(limit - hyst, 1000),
+                                  0, ADT7410_T_HYST_MASK);
+       ret = i2c_smbus_write_byte_data(client, ADT7410_T_HYST, data->hyst);
+       if (ret)
+               return ret;
+
+       return count;
+}
+
+static ssize_t adt7410_show_alarm(struct device *dev,
+                                 struct device_attribute *da,
+                                 char *buf)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
+       int ret;
+
+       ret = i2c_smbus_read_byte_data(client, ADT7410_STATUS);
+       if (ret < 0)
+               return ret;
+
+       return sprintf(buf, "%d\n", !!(ret & attr->index));
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, adt7410_show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO,
+                         adt7410_show_temp, adt7410_set_temp, 1);
+static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO,
+                         adt7410_show_temp, adt7410_set_temp, 2);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO,
+                         adt7410_show_temp, adt7410_set_temp, 3);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO,
+                         adt7410_show_t_hyst, adt7410_set_t_hyst, 1);
+static SENSOR_DEVICE_ATTR(temp1_min_hyst, S_IRUGO,
+                         adt7410_show_t_hyst, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO,
+                         adt7410_show_t_hyst, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, adt7410_show_alarm,
+                         NULL, ADT7410_STAT_T_LOW);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, adt7410_show_alarm,
+                         NULL, ADT7410_STAT_T_HIGH);
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, adt7410_show_alarm,
+                         NULL, ADT7410_STAT_T_CRIT);
+
+static struct attribute *adt7410_attributes[] = {
+       &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp1_max.dev_attr.attr,
+       &sensor_dev_attr_temp1_min.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit.dev_attr.attr,
+       &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp1_min_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+       &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group adt7410_group = {
+       .attrs = adt7410_attributes,
+};
+
+/*-----------------------------------------------------------------------*/
+
+/* device probe and removal */
+
+static int adt7410_probe(struct i2c_client *client,
+                        const struct i2c_device_id *id)
+{
+       struct adt7410_data *data;
+       int ret;
+
+       if (!i2c_check_functionality(client->adapter,
+                       I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA))
+               return -ENODEV;
+
+       data = devm_kzalloc(&client->dev, sizeof(struct adt7410_data),
+                           GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, data);
+       mutex_init(&data->update_lock);
+
+       /* configure as specified */
+       ret = i2c_smbus_read_byte_data(client, ADT7410_CONFIG);
+       if (ret < 0) {
+               dev_dbg(&client->dev, "Can't read config? %d\n", ret);
+               return ret;
+       }
+       data->oldconfig = ret;
+       /*
+        * Set to 16 bit resolution, continous conversion and comparator mode.
+        */
+       data->config = ret | ADT7410_FULL | ADT7410_RESOLUTION |
+                       ADT7410_EVENT_MODE;
+       if (data->config != data->oldconfig) {
+               ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
+                                               data->config);
+               if (ret)
+                       return ret;
+       }
+       dev_dbg(&client->dev, "Config %02x\n", data->config);
+
+       /* Register sysfs hooks */
+       ret = sysfs_create_group(&client->dev.kobj, &adt7410_group);
+       if (ret)
+               goto exit_restore;
+
+       data->hwmon_dev = hwmon_device_register(&client->dev);
+       if (IS_ERR(data->hwmon_dev)) {
+               ret = PTR_ERR(data->hwmon_dev);
+               goto exit_remove;
+       }
+
+       dev_info(&client->dev, "sensor '%s'\n", client->name);
+
+       return 0;
+
+exit_remove:
+       sysfs_remove_group(&client->dev.kobj, &adt7410_group);
+exit_restore:
+       i2c_smbus_write_byte_data(client, ADT7410_CONFIG, data->oldconfig);
+       return ret;
+}
+
+static int adt7410_remove(struct i2c_client *client)
+{
+       struct adt7410_data *data = i2c_get_clientdata(client);
+
+       hwmon_device_unregister(data->hwmon_dev);
+       sysfs_remove_group(&client->dev.kobj, &adt7410_group);
+       if (data->oldconfig != data->config)
+               i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
+                                         data->oldconfig);
+       return 0;
+}
+
+static const struct i2c_device_id adt7410_ids[] = {
+       { "adt7410", adt7410, },
+       { /* LIST END */ }
+};
+MODULE_DEVICE_TABLE(i2c, adt7410_ids);
+
+#ifdef CONFIG_PM
+static int adt7410_suspend(struct device *dev)
+{
+       int ret;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adt7410_data *data = i2c_get_clientdata(client);
+
+       ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG,
+                                       data->config | ADT7410_PD);
+       return ret;
+}
+
+static int adt7410_resume(struct device *dev)
+{
+       int ret;
+       struct i2c_client *client = to_i2c_client(dev);
+       struct adt7410_data *data = i2c_get_clientdata(client);
+
+       ret = i2c_smbus_write_byte_data(client, ADT7410_CONFIG, data->config);
+       return ret;
+}
+
+static const struct dev_pm_ops adt7410_dev_pm_ops = {
+       .suspend        = adt7410_suspend,
+       .resume         = adt7410_resume,
+};
+#define ADT7410_DEV_PM_OPS (&adt7410_dev_pm_ops)
+#else
+#define ADT7410_DEV_PM_OPS NULL
+#endif /* CONFIG_PM */
+
+static struct i2c_driver adt7410_driver = {
+       .class          = I2C_CLASS_HWMON,
+       .driver = {
+               .name   = "adt7410",
+               .pm     = ADT7410_DEV_PM_OPS,
+       },
+       .probe          = adt7410_probe,
+       .remove         = adt7410_remove,
+       .id_table       = adt7410_ids,
+       .address_list   = normal_i2c,
+};
+
+module_i2c_driver(adt7410_driver);
+
+MODULE_AUTHOR("Hartmut Knaack");
+MODULE_DESCRIPTION("ADT7410 driver");
+MODULE_LICENSE("GPL");
index 71bacc56e1385b4c2c393b3a82b6bdcf80fef7a4..fe72c69a2d68b2f7b1d9858c455aafa74f4e4133 100644 (file)
@@ -283,7 +283,7 @@ static int __devinit adt7411_probe(struct i2c_client *client,
        struct adt7411_data *data;
        int ret;
 
-       data = kzalloc(sizeof(*data), GFP_KERNEL);
+       data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
@@ -294,14 +294,14 @@ static int __devinit adt7411_probe(struct i2c_client *client,
        ret = adt7411_modify_bit(client, ADT7411_REG_CFG1,
                                 ADT7411_CFG1_START_MONITOR, 1);
        if (ret < 0)
-               goto exit_free;
+               return ret;
 
        /* force update on first occasion */
        data->next_update = jiffies;
 
        ret = sysfs_create_group(&client->dev.kobj, &adt7411_attr_grp);
        if (ret)
-               goto exit_free;
+               return ret;
 
        data->hwmon_dev = hwmon_device_register(&client->dev);
        if (IS_ERR(data->hwmon_dev)) {
@@ -315,8 +315,6 @@ static int __devinit adt7411_probe(struct i2c_client *client,
 
  exit_remove:
        sysfs_remove_group(&client->dev.kobj, &adt7411_attr_grp);
- exit_free:
-       kfree(data);
        return ret;
 }
 
@@ -326,7 +324,6 @@ static int __devexit adt7411_remove(struct i2c_client *client)
 
        hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &adt7411_attr_grp);
-       kfree(data);
        return 0;
 }
 
index 339269f76e578e2eee05ba0d5f627bbaeff8827e..baee482aedfc716de5c674867b34f554148fa4d6 100644 (file)
@@ -1931,11 +1931,10 @@ static int adt7462_probe(struct i2c_client *client,
        struct adt7462_data *data;
        int err;
 
-       data = kzalloc(sizeof(struct adt7462_data), GFP_KERNEL);
-       if (!data) {
-               err = -ENOMEM;
-               goto exit;
-       }
+       data = devm_kzalloc(&client->dev, sizeof(struct adt7462_data),
+                           GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
 
        i2c_set_clientdata(client, data);
        mutex_init(&data->lock);
@@ -1946,7 +1945,7 @@ static int adt7462_probe(struct i2c_client *client,
        data->attrs.attrs = adt7462_attr;
        err = sysfs_create_group(&client->dev.kobj, &data->attrs);
        if (err)
-               goto exit_free;
+               return err;
 
        data->hwmon_dev = hwmon_device_register(&client->dev);
        if (IS_ERR(data->hwmon_dev)) {
@@ -1958,9 +1957,6 @@ static int adt7462_probe(struct i2c_client *client,
 
 exit_remove:
        sysfs_remove_group(&client->dev.kobj, &data->attrs);
-exit_free:
-       kfree(data);
-exit:
        return err;
 }
 
@@ -1970,7 +1966,6 @@ static int adt7462_remove(struct i2c_client *client)
 
        hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &data->attrs);
-       kfree(data);
        return 0;
 }
 
index 54ec890521ff31ad0f5d273e3315c22bec2734b6..39ecb1a3b9ef61982b0e81e9fbac5585da35dfac 100644 (file)
@@ -1256,11 +1256,10 @@ static int adt7470_probe(struct i2c_client *client,
        struct adt7470_data *data;
        int err;
 
-       data = kzalloc(sizeof(struct adt7470_data), GFP_KERNEL);
-       if (!data) {
-               err = -ENOMEM;
-               goto exit;
-       }
+       data = devm_kzalloc(&client->dev, sizeof(struct adt7470_data),
+                           GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
 
        data->num_temp_sensors = -1;
        data->auto_update_interval = AUTO_UPDATE_INTERVAL;
@@ -1277,7 +1276,7 @@ static int adt7470_probe(struct i2c_client *client,
        data->attrs.attrs = adt7470_attr;
        err = sysfs_create_group(&client->dev.kobj, &data->attrs);
        if (err)
-               goto exit_free;
+               return err;
 
        data->hwmon_dev = hwmon_device_register(&client->dev);
        if (IS_ERR(data->hwmon_dev)) {
@@ -1299,9 +1298,6 @@ exit_unregister:
        hwmon_device_unregister(data->hwmon_dev);
 exit_remove:
        sysfs_remove_group(&client->dev.kobj, &data->attrs);
-exit_free:
-       kfree(data);
-exit:
        return err;
 }
 
@@ -1313,7 +1309,6 @@ static int adt7470_remove(struct i2c_client *client)
        wait_for_completion(&data->auto_update_stop);
        hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &data->attrs);
-       kfree(data);
        return 0;
 }
 
index f600fa1f92e366962b0cf0162441d304a36211bb..ae482e3afdac8c135eb3d501a6f20773a1624db5 100644 (file)
@@ -862,12 +862,10 @@ static int amc6821_probe(
        struct amc6821_data *data;
        int err;
 
-       data = kzalloc(sizeof(struct amc6821_data), GFP_KERNEL);
-       if (!data) {
-               dev_err(&client->dev, "out of memory.\n");
+       data = devm_kzalloc(&client->dev, sizeof(struct amc6821_data),
+                           GFP_KERNEL);
+       if (!data)
                return -ENOMEM;
-       }
-
 
        i2c_set_clientdata(client, data);
        mutex_init(&data->update_lock);
@@ -877,11 +875,11 @@ static int amc6821_probe(
         */
        err = amc6821_init_client(client);
        if (err)
-               goto err_free;
+               return err;
 
        err = sysfs_create_group(&client->dev.kobj, &amc6821_attr_grp);
        if (err)
-               goto err_free;
+               return err;
 
        data->hwmon_dev = hwmon_device_register(&client->dev);
        if (!IS_ERR(data->hwmon_dev))
@@ -890,8 +888,6 @@ static int amc6821_probe(
        err = PTR_ERR(data->hwmon_dev);
        dev_err(&client->dev, "error registering hwmon device.\n");
        sysfs_remove_group(&client->dev.kobj, &amc6821_attr_grp);
-err_free:
-       kfree(data);
        return err;
 }
 
@@ -902,8 +898,6 @@ static int amc6821_remove(struct i2c_client *client)
        hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &amc6821_attr_grp);
 
-       kfree(data);
-
        return 0;
 }
 
index 4b8814deabb1eabf902cbdbdf2b8c105ecd68403..a227be47149f473bfd6fc2d41a8de99f842056fd 100644 (file)
@@ -787,12 +787,10 @@ static int asb100_probe(struct i2c_client *client,
        int err;
        struct asb100_data *data;
 
-       data = kzalloc(sizeof(struct asb100_data), GFP_KERNEL);
-       if (!data) {
-               pr_debug("probe failed, kzalloc failed!\n");
-               err = -ENOMEM;
-               goto ERROR0;
-       }
+       data = devm_kzalloc(&client->dev, sizeof(struct asb100_data),
+                           GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
 
        i2c_set_clientdata(client, data);
        mutex_init(&data->lock);
@@ -801,7 +799,7 @@ static int asb100_probe(struct i2c_client *client,
        /* Attach secondary lm75 clients */
        err = asb100_detect_subclients(client);
        if (err)
-               goto ERROR1;
+               return err;
 
        /* Initialize the chip */
        asb100_init_client(client);
@@ -829,9 +827,6 @@ ERROR4:
 ERROR3:
        i2c_unregister_device(data->lm75[1]);
        i2c_unregister_device(data->lm75[0]);
-ERROR1:
-       kfree(data);
-ERROR0:
        return err;
 }
 
@@ -845,8 +840,6 @@ static int asb100_remove(struct i2c_client *client)
        i2c_unregister_device(data->lm75[1]);
        i2c_unregister_device(data->lm75[0]);
 
-       kfree(data);
-
        return 0;
 }
 
index faa16f80db9cf652bbc75aaa7e5fd0e73b788ca4..59910653d7ab6d6a72e1ba6f5bb52e99e7d87f2f 100644 (file)
@@ -815,17 +815,20 @@ static int __init coretemp_init(void)
        if (err)
                goto exit;
 
+       get_online_cpus();
        for_each_online_cpu(i)
                get_core_online(i);
 
 #ifndef CONFIG_HOTPLUG_CPU
        if (list_empty(&pdev_list)) {
+               put_online_cpus();
                err = -ENODEV;
                goto exit_driver_unreg;
        }
 #endif
 
        register_hotcpu_notifier(&coretemp_cpu_notifier);
+       put_online_cpus();
        return 0;
 
 #ifndef CONFIG_HOTPLUG_CPU
@@ -840,6 +843,7 @@ static void __exit coretemp_exit(void)
 {
        struct pdev_entry *p, *n;
 
+       get_online_cpus();
        unregister_hotcpu_notifier(&coretemp_cpu_notifier);
        mutex_lock(&pdev_list_mutex);
        list_for_each_entry_safe(p, n, &pdev_list, list) {
@@ -848,6 +852,7 @@ static void __exit coretemp_exit(void)
                kfree(p);
        }
        mutex_unlock(&pdev_list_mutex);
+       put_online_cpus();
        platform_driver_unregister(&coretemp_driver);
 }
 
index e7c6a19f3b259875cecfcbb133ad9f47e9a1f6e7..fe0eeec0b750d201c6626bdef439c3faf5b916fa 100644 (file)
@@ -2475,11 +2475,9 @@ static int dme1737_i2c_probe(struct i2c_client *client,
        struct device *dev = &client->dev;
        int err;
 
-       data = kzalloc(sizeof(struct dme1737_data), GFP_KERNEL);
-       if (!data) {
-               err = -ENOMEM;
-               goto exit;
-       }
+       data = devm_kzalloc(dev, sizeof(struct dme1737_data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
 
        i2c_set_clientdata(client, data);
        data->type = id->driver_data;
@@ -2491,14 +2489,14 @@ static int dme1737_i2c_probe(struct i2c_client *client,
        err = dme1737_init_device(dev);
        if (err) {
                dev_err(dev, "Failed to initialize device.\n");
-               goto exit_kfree;
+               return err;
        }
 
        /* Create sysfs files */
        err = dme1737_create_files(dev);
        if (err) {
                dev_err(dev, "Failed to create sysfs files.\n");
-               goto exit_kfree;
+               return err;
        }
 
        /* Register device */
@@ -2513,9 +2511,6 @@ static int dme1737_i2c_probe(struct i2c_client *client,
 
 exit_remove:
        dme1737_remove_files(dev);
-exit_kfree:
-       kfree(data);
-exit:
        return err;
 }
 
@@ -2526,7 +2521,6 @@ static int dme1737_i2c_remove(struct i2c_client *client)
        hwmon_device_unregister(data->hwmon_dev);
        dme1737_remove_files(&client->dev);
 
-       kfree(data);
        return 0;
 }
 
@@ -2645,19 +2639,16 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev)
        int err;
 
        res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-       if (!request_region(res->start, DME1737_EXTENT, "dme1737")) {
+       if (!devm_request_region(dev, res->start, DME1737_EXTENT, "dme1737")) {
                dev_err(dev, "Failed to request region 0x%04x-0x%04x.\n",
                        (unsigned short)res->start,
                        (unsigned short)res->start + DME1737_EXTENT - 1);
-               err = -EBUSY;
-               goto exit;
+               return -EBUSY;
        }
 
-       data = kzalloc(sizeof(struct dme1737_data), GFP_KERNEL);
-       if (!data) {
-               err = -ENOMEM;
-               goto exit_release_region;
-       }
+       data = devm_kzalloc(dev, sizeof(struct dme1737_data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
 
        data->addr = res->start;
        platform_set_drvdata(pdev, data);
@@ -2683,8 +2674,7 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev)
                           (device == SCH5127_DEVICE)) {
                        data->type = sch5127;
                } else {
-                       err = -ENODEV;
-                       goto exit_kfree;
+                       return -ENODEV;
                }
        }
 
@@ -2703,14 +2693,14 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev)
        err = dme1737_init_device(dev);
        if (err) {
                dev_err(dev, "Failed to initialize device.\n");
-               goto exit_kfree;
+               return err;
        }
 
        /* Create sysfs files */
        err = dme1737_create_files(dev);
        if (err) {
                dev_err(dev, "Failed to create sysfs files.\n");
-               goto exit_kfree;
+               return err;
        }
 
        /* Register device */
@@ -2725,12 +2715,6 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev)
 
 exit_remove_files:
        dme1737_remove_files(dev);
-exit_kfree:
-       platform_set_drvdata(pdev, NULL);
-       kfree(data);
-exit_release_region:
-       release_region(res->start, DME1737_EXTENT);
-exit:
        return err;
 }
 
@@ -2740,9 +2724,6 @@ static int __devexit dme1737_isa_remove(struct platform_device *pdev)
 
        hwmon_device_unregister(data->hwmon_dev);
        dme1737_remove_files(&pdev->dev);
-       release_region(data->addr, DME1737_EXTENT);
-       platform_set_drvdata(pdev, NULL);
-       kfree(data);
 
        return 0;
 }
index 50663efad4121a76535f4a9553f5a7873ea47513..f1d6b422cf0682b43ed6b4354481d97de240fcef 100644 (file)
@@ -232,11 +232,10 @@ static int ds620_probe(struct i2c_client *client,
        struct ds620_data *data;
        int err;
 
-       data = kzalloc(sizeof(struct ds620_data), GFP_KERNEL);
-       if (!data) {
-               err = -ENOMEM;
-               goto exit;
-       }
+       data = devm_kzalloc(&client->dev, sizeof(struct ds620_data),
+                           GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
 
        i2c_set_clientdata(client, data);
        mutex_init(&data->update_lock);
@@ -247,7 +246,7 @@ static int ds620_probe(struct i2c_client *client,
        /* Register sysfs hooks */
        err = sysfs_create_group(&client->dev.kobj, &ds620_group);
        if (err)
-               goto exit_free;
+               return err;
 
        data->hwmon_dev = hwmon_device_register(&client->dev);
        if (IS_ERR(data->hwmon_dev)) {
@@ -261,9 +260,6 @@ static int ds620_probe(struct i2c_client *client,
 
 exit_remove_files:
        sysfs_remove_group(&client->dev.kobj, &ds620_group);
-exit_free:
-       kfree(data);
-exit:
        return err;
 }
 
@@ -274,8 +270,6 @@ static int ds620_remove(struct i2c_client *client)
        hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &ds620_group);
 
-       kfree(data);
-
        return 0;
 }
 
index 149dcb0e148f0842045a041e18d5a6417dc6b4b6..68ab94bde3f1d56c0acfbc4ab928ab8d08bf56eb 100644 (file)
@@ -306,11 +306,10 @@ static int emc1403_probe(struct i2c_client *client,
        int res;
        struct thermal_data *data;
 
-       data = kzalloc(sizeof(struct thermal_data), GFP_KERNEL);
-       if (data == NULL) {
-               dev_warn(&client->dev, "out of memory");
+       data = devm_kzalloc(&client->dev, sizeof(struct thermal_data),
+                           GFP_KERNEL);
+       if (data == NULL)
                return -ENOMEM;
-       }
 
        i2c_set_clientdata(client, data);
        mutex_init(&data->mutex);
@@ -319,21 +318,19 @@ static int emc1403_probe(struct i2c_client *client,
        res = sysfs_create_group(&client->dev.kobj, &m_thermal_gr);
        if (res) {
                dev_warn(&client->dev, "create group failed\n");
-               goto thermal_error1;
+               return res;
        }
        data->hwmon_dev = hwmon_device_register(&client->dev);
        if (IS_ERR(data->hwmon_dev)) {
                res = PTR_ERR(data->hwmon_dev);
                dev_warn(&client->dev, "register hwmon dev failed\n");
-               goto thermal_error2;
+               goto thermal_error;
        }
        dev_info(&client->dev, "EMC1403 Thermal chip found\n");
-       return res;
+       return 0;
 
-thermal_error2:
+thermal_error:
        sysfs_remove_group(&client->dev.kobj, &m_thermal_gr);
-thermal_error1:
-       kfree(data);
        return res;
 }
 
@@ -343,7 +340,6 @@ static int emc1403_remove(struct i2c_client *client)
 
        hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &m_thermal_gr);
-       kfree(data);
        return 0;
 }
 
index 7bb8e888692c4d7f49d352ab89609d16e7f61ff6..77f434c5823690930f0cfa0d2e41932d91eb3223 100644 (file)
@@ -590,7 +590,8 @@ emc2103_probe(struct i2c_client *client, const struct i2c_device_id *id)
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return -EIO;
 
-       data = kzalloc(sizeof(struct emc2103_data), GFP_KERNEL);
+       data = devm_kzalloc(&client->dev, sizeof(struct emc2103_data),
+                           GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
@@ -608,7 +609,7 @@ emc2103_probe(struct i2c_client *client, const struct i2c_device_id *id)
                if (status < 0) {
                        dev_dbg(&client->dev, "reg 0x%02x, err %d\n", REG_CONF1,
                                status);
-                       goto exit_free;
+                       return status;
                }
 
                /* detect current state of hardware */
@@ -631,7 +632,7 @@ emc2103_probe(struct i2c_client *client, const struct i2c_device_id *id)
        /* Register sysfs hooks */
        status = sysfs_create_group(&client->dev.kobj, &emc2103_group);
        if (status)
-               goto exit_free;
+               return status;
 
        if (data->temp_count >= 3) {
                status = sysfs_create_group(&client->dev.kobj,
@@ -666,8 +667,6 @@ exit_remove_temp3:
                sysfs_remove_group(&client->dev.kobj, &emc2103_temp3_group);
 exit_remove:
        sysfs_remove_group(&client->dev.kobj, &emc2103_group);
-exit_free:
-       kfree(data);
        return status;
 }
 
@@ -685,7 +684,6 @@ static int emc2103_remove(struct i2c_client *client)
 
        sysfs_remove_group(&client->dev.kobj, &emc2103_group);
 
-       kfree(data);
        return 0;
 }
 
index 6d1226365e30f55c2d541a17e2176cc90e655d67..50e4ce2d22d8b2bd0f5134581ac0dd35ea47a2a1 100644 (file)
@@ -2274,7 +2274,8 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
        int err, i;
        u8 start_reg, reg;
 
-       data = kzalloc(sizeof(struct f71882fg_data), GFP_KERNEL);
+       data = devm_kzalloc(&pdev->dev, sizeof(struct f71882fg_data),
+                           GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
@@ -2288,13 +2289,11 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
        start_reg = f71882fg_read8(data, F71882FG_REG_START);
        if (start_reg & 0x04) {
                dev_warn(&pdev->dev, "Hardware monitor is powered down\n");
-               err = -ENODEV;
-               goto exit_free;
+               return -ENODEV;
        }
        if (!(start_reg & 0x03)) {
                dev_warn(&pdev->dev, "Hardware monitoring not activated\n");
-               err = -ENODEV;
-               goto exit_free;
+               return -ENODEV;
        }
 
        /* Register sysfs interface files */
@@ -2422,8 +2421,6 @@ static int __devinit f71882fg_probe(struct platform_device *pdev)
 exit_unregister_sysfs:
        f71882fg_remove(pdev); /* Will unregister the sysfs files for us */
        return err; /* f71882fg_remove() also frees our data */
-exit_free:
-       kfree(data);
        return err;
 }
 
@@ -2525,17 +2522,13 @@ static int f71882fg_remove(struct platform_device *pdev)
                                ARRAY_SIZE(fxxxx_auto_pwm_attr[0]) * nr_fans);
                }
        }
-
-       platform_set_drvdata(pdev, NULL);
-       kfree(data);
-
        return 0;
 }
 
-static int __init f71882fg_find(int sioaddr, unsigned short *address,
-       struct f71882fg_sio_data *sio_data)
+static int __init f71882fg_find(int sioaddr, struct f71882fg_sio_data *sio_data)
 {
        u16 devid;
+       unsigned short address;
        int err = superio_enter(sioaddr);
        if (err)
                return err;
@@ -2603,25 +2596,25 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
                goto exit;
        }
 
-       *address = superio_inw(sioaddr, SIO_REG_ADDR);
-       if (*address == 0) {
+       address = superio_inw(sioaddr, SIO_REG_ADDR);
+       if (address == 0) {
                pr_warn("Base address not set\n");
                err = -ENODEV;
                goto exit;
        }
-       *address &= ~(REGION_LENGTH - 1);       /* Ignore 3 LSB */
+       address &= ~(REGION_LENGTH - 1);        /* Ignore 3 LSB */
 
-       err = 0;
+       err = address;
        pr_info("Found %s chip at %#x, revision %d\n",
-               f71882fg_names[sio_data->type], (unsigned int)*address,
+               f71882fg_names[sio_data->type], (unsigned int)address,
                (int)superio_inb(sioaddr, SIO_REG_DEVREV));
 exit:
        superio_exit(sioaddr);
        return err;
 }
 
-static int __init f71882fg_device_add(unsigned short address,
-       const struct f71882fg_sio_data *sio_data)
+static int __init f71882fg_device_add(int address,
+                                     const struct f71882fg_sio_data *sio_data)
 {
        struct resource res = {
                .start  = address,
@@ -2668,19 +2661,21 @@ exit_device_put:
 
 static int __init f71882fg_init(void)
 {
-       int err = -ENODEV;
-       unsigned short address;
+       int err;
+       int address;
        struct f71882fg_sio_data sio_data;
 
        memset(&sio_data, 0, sizeof(sio_data));
 
-       if (f71882fg_find(0x2e, &address, &sio_data) &&
-           f71882fg_find(0x4e, &address, &sio_data))
-               goto exit;
+       address = f71882fg_find(0x2e, &sio_data);
+       if (address < 0)
+               address = f71882fg_find(0x4e, &sio_data);
+       if (address < 0)
+               return address;
 
        err = platform_driver_register(&f71882fg_driver);
        if (err)
-               goto exit;
+               return err;
 
        err = f71882fg_device_add(address, &sio_data);
        if (err)
@@ -2690,7 +2685,6 @@ static int __init f71882fg_init(void)
 
 exit_driver:
        platform_driver_unregister(&f71882fg_driver);
-exit:
        return err;
 }
 
index ece4159bd4536553abafed0689d60d71f361d312..f7dba229395f9a844da9a8418ac9c5b2918d75dd 100644 (file)
@@ -838,7 +838,8 @@ static int f75375_probe(struct i2c_client *client,
        if (!i2c_check_functionality(client->adapter,
                                I2C_FUNC_SMBUS_BYTE_DATA))
                return -EIO;
-       data = kzalloc(sizeof(struct f75375_data), GFP_KERNEL);
+       data = devm_kzalloc(&client->dev, sizeof(struct f75375_data),
+                           GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
@@ -848,7 +849,7 @@ static int f75375_probe(struct i2c_client *client,
 
        err = sysfs_create_group(&client->dev.kobj, &f75375_group);
        if (err)
-               goto exit_free;
+               return err;
 
        if (data->kind != f75373) {
                err = sysfs_chmod_file(&client->dev.kobj,
@@ -875,8 +876,6 @@ static int f75375_probe(struct i2c_client *client,
 
 exit_remove:
        sysfs_remove_group(&client->dev.kobj, &f75375_group);
-exit_free:
-       kfree(data);
        return err;
 }
 
@@ -885,7 +884,6 @@ static int f75375_remove(struct i2c_client *client)
        struct f75375_data *data = i2c_get_clientdata(client);
        hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &f75375_group);
-       kfree(data);
        return 0;
 }
 
index 2764b78a784b9be83f9df1fd48f558452d9b8d61..9e93ae477c481beadded882e09d214af76933928 100644 (file)
@@ -188,7 +188,7 @@ static int __devinit fam15h_power_probe(struct pci_dev *pdev,
                                        const struct pci_device_id *id)
 {
        struct fam15h_power_data *data;
-       struct device *dev;
+       struct device *dev = &pdev->dev;
        int err;
 
        /*
@@ -198,23 +198,19 @@ static int __devinit fam15h_power_probe(struct pci_dev *pdev,
         */
        tweak_runavg_range(pdev);
 
-       if (!fam15h_power_is_internal_node0(pdev)) {
-               err = -ENODEV;
-               goto exit;
-       }
+       if (!fam15h_power_is_internal_node0(pdev))
+               return -ENODEV;
+
+       data = devm_kzalloc(dev, sizeof(struct fam15h_power_data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
 
-       data = kzalloc(sizeof(struct fam15h_power_data), GFP_KERNEL);
-       if (!data) {
-               err = -ENOMEM;
-               goto exit;
-       }
        fam15h_power_init_data(pdev, data);
-       dev = &pdev->dev;
 
        dev_set_drvdata(dev, data);
        err = sysfs_create_group(&dev->kobj, &fam15h_power_attr_group);
        if (err)
-               goto exit_free_data;
+               return err;
 
        data->hwmon_dev = hwmon_device_register(dev);
        if (IS_ERR(data->hwmon_dev)) {
@@ -226,9 +222,6 @@ static int __devinit fam15h_power_probe(struct pci_dev *pdev,
 
 exit_remove_group:
        sysfs_remove_group(&dev->kobj, &fam15h_power_attr_group);
-exit_free_data:
-       kfree(data);
-exit:
        return err;
 }
 
@@ -241,8 +234,6 @@ static void __devexit fam15h_power_remove(struct pci_dev *pdev)
        data = dev_get_drvdata(dev);
        hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&dev->kobj, &fam15h_power_attr_group);
-       dev_set_drvdata(dev, NULL);
-       kfree(data);
 }
 
 static DEFINE_PCI_DEVICE_TABLE(fam15h_power_id_table) = {
index ebcd2698e4dc168f057c5919e51694d551a6a119..8b2106f60edac7e91c4eb6eaabfb2cc6585636a0 100644 (file)
@@ -207,7 +207,8 @@ static int g760a_probe(struct i2c_client *client,
                                     I2C_FUNC_SMBUS_BYTE_DATA))
                return -EIO;
 
-       data = kzalloc(sizeof(struct g760a_data), GFP_KERNEL);
+       data = devm_kzalloc(&client->dev, sizeof(struct g760a_data),
+                           GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
@@ -223,7 +224,7 @@ static int g760a_probe(struct i2c_client *client,
        /* Register sysfs hooks */
        err = sysfs_create_group(&client->dev.kobj, &g760a_group);
        if (err)
-               goto error_sysfs_create_group;
+               return err;
 
        data->hwmon_dev = hwmon_device_register(&client->dev);
        if (IS_ERR(data->hwmon_dev)) {
@@ -235,9 +236,6 @@ static int g760a_probe(struct i2c_client *client,
 
 error_hwmon_device_register:
        sysfs_remove_group(&client->dev.kobj, &g760a_group);
-error_sysfs_create_group:
-       kfree(data);
-
        return err;
 }
 
@@ -246,8 +244,6 @@ static int g760a_remove(struct i2c_client *client)
        struct g760a_data *data = i2c_get_clientdata(client);
        hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &g760a_group);
-       kfree(data);
-
        return 0;
 }
 
index 5253d23361d91a4e93eefb00021bcd3ae4f9915f..84bf2152f0feb005384615b28394d89decff3324 100644 (file)
@@ -106,42 +106,36 @@ static int __devinit jz4740_hwmon_probe(struct platform_device *pdev)
        int ret;
        struct jz4740_hwmon *hwmon;
 
-       hwmon = kmalloc(sizeof(*hwmon), GFP_KERNEL);
-       if (!hwmon) {
-               dev_err(&pdev->dev, "Failed to allocate driver structure\n");
+       hwmon = devm_kzalloc(&pdev->dev, sizeof(*hwmon), GFP_KERNEL);
+       if (!hwmon)
                return -ENOMEM;
-       }
 
        hwmon->cell = mfd_get_cell(pdev);
 
        hwmon->irq = platform_get_irq(pdev, 0);
        if (hwmon->irq < 0) {
-               ret = hwmon->irq;
                dev_err(&pdev->dev, "Failed to get platform irq: %d\n", ret);
-               goto err_free;
+               return hwmon->irq;
        }
 
        hwmon->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!hwmon->mem) {
-               ret = -ENOENT;
                dev_err(&pdev->dev, "Failed to get platform mmio resource\n");
-               goto err_free;
+               return -ENOENT;
        }
 
-       hwmon->mem = request_mem_region(hwmon->mem->start,
+       hwmon->mem = devm_request_mem_region(&pdev->dev, hwmon->mem->start,
                        resource_size(hwmon->mem), pdev->name);
        if (!hwmon->mem) {
-               ret = -EBUSY;
                dev_err(&pdev->dev, "Failed to request mmio memory region\n");
-               goto err_free;
+               return -EBUSY;
        }
 
-       hwmon->base = ioremap_nocache(hwmon->mem->start,
-                       resource_size(hwmon->mem));
+       hwmon->base = devm_ioremap_nocache(&pdev->dev, hwmon->mem->start,
+                                          resource_size(hwmon->mem));
        if (!hwmon->base) {
-               ret = -EBUSY;
                dev_err(&pdev->dev, "Failed to ioremap mmio memory\n");
-               goto err_release_mem_region;
+               return -EBUSY;
        }
 
        init_completion(&hwmon->read_completion);
@@ -149,17 +143,18 @@ static int __devinit jz4740_hwmon_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, hwmon);
 
-       ret = request_irq(hwmon->irq, jz4740_hwmon_irq, 0, pdev->name, hwmon);
+       ret = devm_request_irq(&pdev->dev, hwmon->irq, jz4740_hwmon_irq, 0,
+                              pdev->name, hwmon);
        if (ret) {
                dev_err(&pdev->dev, "Failed to request irq: %d\n", ret);
-               goto err_iounmap;
+               return ret;
        }
        disable_irq(hwmon->irq);
 
        ret = sysfs_create_group(&pdev->dev.kobj, &jz4740_hwmon_attr_group);
        if (ret) {
                dev_err(&pdev->dev, "Failed to create sysfs group: %d\n", ret);
-               goto err_free_irq;
+               return ret;
        }
 
        hwmon->hwmon = hwmon_device_register(&pdev->dev);
@@ -172,16 +167,6 @@ static int __devinit jz4740_hwmon_probe(struct platform_device *pdev)
 
 err_remove_file:
        sysfs_remove_group(&pdev->dev.kobj, &jz4740_hwmon_attr_group);
-err_free_irq:
-       free_irq(hwmon->irq, hwmon);
-err_iounmap:
-       platform_set_drvdata(pdev, NULL);
-       iounmap(hwmon->base);
-err_release_mem_region:
-       release_mem_region(hwmon->mem->start, resource_size(hwmon->mem));
-err_free:
-       kfree(hwmon);
-
        return ret;
 }
 
@@ -192,14 +177,6 @@ static int __devexit jz4740_hwmon_remove(struct platform_device *pdev)
        hwmon_device_unregister(hwmon->hwmon);
        sysfs_remove_group(&pdev->dev.kobj, &jz4740_hwmon_attr_group);
 
-       free_irq(hwmon->irq, hwmon);
-
-       iounmap(hwmon->base);
-       release_mem_region(hwmon->mem->start, resource_size(hwmon->mem));
-
-       platform_set_drvdata(pdev, NULL);
-       kfree(hwmon);
-
        return 0;
 }
 
index 472f79521a96f1b29e9205e557bd0a3823c2b98b..dd7f0cafd197c85db5e76e81f60d6ab925fe9091 100644 (file)
@@ -149,7 +149,7 @@ static int __devinit lm70_probe(struct spi_device *spi)
 
        /* NOTE:  we assume 8-bit words, and convert to 16 bits manually */
 
-       p_lm70 = kzalloc(sizeof *p_lm70, GFP_KERNEL);
+       p_lm70 = devm_kzalloc(&spi->dev, sizeof(*p_lm70), GFP_KERNEL);
        if (!p_lm70)
                return -ENOMEM;
 
@@ -181,7 +181,6 @@ out_dev_create_file_failed:
        device_remove_file(&spi->dev, &dev_attr_temp1_input);
 out_dev_create_temp_file_failed:
        spi_set_drvdata(spi, NULL);
-       kfree(p_lm70);
        return status;
 }
 
@@ -193,7 +192,6 @@ static int __devexit lm70_remove(struct spi_device *spi)
        device_remove_file(&spi->dev, &dev_attr_temp1_input);
        device_remove_file(&spi->dev, &dev_attr_name);
        spi_set_drvdata(spi, NULL);
-       kfree(p_lm70);
 
        return 0;
 }
index bd8cdb7b96ed586cf6cbae1c676ab445f6620bcf..4b68fb2a31d75728da51e50eb66d9a72cd420bd7 100644 (file)
@@ -391,11 +391,10 @@ static int lm95241_probe(struct i2c_client *new_client,
        struct lm95241_data *data;
        int err;
 
-       data = kzalloc(sizeof(struct lm95241_data), GFP_KERNEL);
-       if (!data) {
-               err = -ENOMEM;
-               goto exit;
-       }
+       data = devm_kzalloc(&new_client->dev, sizeof(struct lm95241_data),
+                           GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
 
        i2c_set_clientdata(new_client, data);
        mutex_init(&data->update_lock);
@@ -406,7 +405,7 @@ static int lm95241_probe(struct i2c_client *new_client,
        /* Register sysfs hooks */
        err = sysfs_create_group(&new_client->dev.kobj, &lm95241_group);
        if (err)
-               goto exit_free;
+               return err;
 
        data->hwmon_dev = hwmon_device_register(&new_client->dev);
        if (IS_ERR(data->hwmon_dev)) {
@@ -418,9 +417,6 @@ static int lm95241_probe(struct i2c_client *new_client,
 
 exit_remove_files:
        sysfs_remove_group(&new_client->dev.kobj, &lm95241_group);
-exit_free:
-       kfree(data);
-exit:
        return err;
 }
 
@@ -431,7 +427,6 @@ static int lm95241_remove(struct i2c_client *client)
        hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &lm95241_group);
 
-       kfree(data);
        return 0;
 }
 
index 9a46c106a240230db8aaba95870e02447090cb5e..2915fd90836495c16cb4e89485daf5b457b6289b 100644 (file)
@@ -462,11 +462,10 @@ static int lm95245_probe(struct i2c_client *new_client,
        struct lm95245_data *data;
        int err;
 
-       data = kzalloc(sizeof(struct lm95245_data), GFP_KERNEL);
-       if (!data) {
-               err = -ENOMEM;
-               goto exit;
-       }
+       data = devm_kzalloc(&new_client->dev, sizeof(struct lm95245_data),
+                           GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
 
        i2c_set_clientdata(new_client, data);
        mutex_init(&data->update_lock);
@@ -477,7 +476,7 @@ static int lm95245_probe(struct i2c_client *new_client,
        /* Register sysfs hooks */
        err = sysfs_create_group(&new_client->dev.kobj, &lm95245_group);
        if (err)
-               goto exit_free;
+               return err;
 
        data->hwmon_dev = hwmon_device_register(&new_client->dev);
        if (IS_ERR(data->hwmon_dev)) {
@@ -489,9 +488,6 @@ static int lm95245_probe(struct i2c_client *new_client,
 
 exit_remove_files:
        sysfs_remove_group(&new_client->dev.kobj, &lm95245_group);
-exit_free:
-       kfree(data);
-exit:
        return err;
 }
 
@@ -502,7 +498,6 @@ static int lm95245_remove(struct i2c_client *client)
        hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &lm95245_group);
 
-       kfree(data);
        return 0;
 }
 
index 4d005b219de2d4749211652561376da68b8454c2..8496baa08bc8349183e537e4f61e0d2db03c7cd4 100644 (file)
@@ -181,11 +181,9 @@ static int ltc4151_probe(struct i2c_client *client,
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return -ENODEV;
 
-       data = kzalloc(sizeof(*data), GFP_KERNEL);
-       if (!data) {
-               ret = -ENOMEM;
-               goto out_kzalloc;
-       }
+       data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
 
        i2c_set_clientdata(client, data);
        mutex_init(&data->update_lock);
@@ -193,7 +191,7 @@ static int ltc4151_probe(struct i2c_client *client,
        /* Register sysfs hooks */
        ret = sysfs_create_group(&client->dev.kobj, &ltc4151_group);
        if (ret)
-               goto out_sysfs_create_group;
+               return ret;
 
        data->hwmon_dev = hwmon_device_register(&client->dev);
        if (IS_ERR(data->hwmon_dev)) {
@@ -205,9 +203,6 @@ static int ltc4151_probe(struct i2c_client *client,
 
 out_hwmon_device_register:
        sysfs_remove_group(&client->dev.kobj, &ltc4151_group);
-out_sysfs_create_group:
-       kfree(data);
-out_kzalloc:
        return ret;
 }
 
@@ -218,8 +213,6 @@ static int ltc4151_remove(struct i2c_client *client)
        hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &ltc4151_group);
 
-       kfree(data);
-
        return 0;
 }
 
index 429c5b2b66fd2b7b932db013789f8b61ac958454..98b3d04f98b70bee2713914031c4173451f5517a 100644 (file)
@@ -253,11 +253,9 @@ static int ltc4215_probe(struct i2c_client *client,
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return -ENODEV;
 
-       data = kzalloc(sizeof(*data), GFP_KERNEL);
-       if (!data) {
-               ret = -ENOMEM;
-               goto out_kzalloc;
-       }
+       data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
 
        i2c_set_clientdata(client, data);
        mutex_init(&data->update_lock);
@@ -268,7 +266,7 @@ static int ltc4215_probe(struct i2c_client *client,
        /* Register sysfs hooks */
        ret = sysfs_create_group(&client->dev.kobj, &ltc4215_group);
        if (ret)
-               goto out_sysfs_create_group;
+               return ret;
 
        data->hwmon_dev = hwmon_device_register(&client->dev);
        if (IS_ERR(data->hwmon_dev)) {
@@ -280,9 +278,6 @@ static int ltc4215_probe(struct i2c_client *client,
 
 out_hwmon_device_register:
        sysfs_remove_group(&client->dev.kobj, &ltc4215_group);
-out_sysfs_create_group:
-       kfree(data);
-out_kzalloc:
        return ret;
 }
 
@@ -293,8 +288,6 @@ static int ltc4215_remove(struct i2c_client *client)
        hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &ltc4215_group);
 
-       kfree(data);
-
        return 0;
 }
 
index b99b45bafdad4d501e285c3d8b7cb1542a70477e..52075914eb0bb1adb7a225a9f500de3869b4a125 100644 (file)
@@ -519,11 +519,9 @@ static int ltc4245_probe(struct i2c_client *client,
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return -ENODEV;
 
-       data = kzalloc(sizeof(*data), GFP_KERNEL);
-       if (!data) {
-               ret = -ENOMEM;
-               goto out_kzalloc;
-       }
+       data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
 
        i2c_set_clientdata(client, data);
        mutex_init(&data->update_lock);
@@ -536,7 +534,7 @@ static int ltc4245_probe(struct i2c_client *client,
        /* Register sysfs hooks */
        ret = ltc4245_sysfs_create_groups(client);
        if (ret)
-               goto out_sysfs_create_groups;
+               return ret;
 
        data->hwmon_dev = hwmon_device_register(&client->dev);
        if (IS_ERR(data->hwmon_dev)) {
@@ -548,9 +546,6 @@ static int ltc4245_probe(struct i2c_client *client,
 
 out_hwmon_device_register:
        ltc4245_sysfs_remove_groups(client);
-out_sysfs_create_groups:
-       kfree(data);
-out_kzalloc:
        return ret;
 }
 
@@ -560,7 +555,6 @@ static int ltc4245_remove(struct i2c_client *client)
 
        hwmon_device_unregister(data->hwmon_dev);
        ltc4245_sysfs_remove_groups(client);
-       kfree(data);
 
        return 0;
 }
index 335b183d7c022e6d3b7032848558de8b43894aeb..666d9f6263eb462e41a5ec319ca5d29dc67eb540 100644 (file)
@@ -411,7 +411,8 @@ static int max1668_probe(struct i2c_client *client,
        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return -ENODEV;
 
-       data = kzalloc(sizeof(struct max1668_data), GFP_KERNEL);
+       data = devm_kzalloc(&client->dev, sizeof(struct max1668_data),
+                           GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
@@ -422,7 +423,7 @@ static int max1668_probe(struct i2c_client *client,
        /* Register sysfs hooks */
        err = sysfs_create_group(&client->dev.kobj, &max1668_group_common);
        if (err)
-               goto error_free;
+               return err;
 
        if (data->type == max1668 || data->type == max1989) {
                err = sysfs_create_group(&client->dev.kobj,
@@ -444,8 +445,6 @@ error_sysrem1:
                sysfs_remove_group(&client->dev.kobj, &max1668_group_unique);
 error_sysrem0:
        sysfs_remove_group(&client->dev.kobj, &max1668_group_common);
-error_free:
-       kfree(data);
        return err;
 }
 
@@ -459,7 +458,6 @@ static int max1668_remove(struct i2c_client *client)
 
        sysfs_remove_group(&client->dev.kobj, &max1668_group_common);
 
-       kfree(data);
        return 0;
 }
 
index d0afc0cd3ff49a21ff37c94664aa0adeab934456..5162bb95bc614dc5a4a573ce558b61aa46858cd2 100644 (file)
@@ -103,7 +103,8 @@ static int mcp3021_probe(struct i2c_client *client,
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
                return -ENODEV;
 
-       data = kzalloc(sizeof(struct mcp3021_data), GFP_KERNEL);
+       data = devm_kzalloc(&client->dev, sizeof(struct mcp3021_data),
+                           GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
@@ -111,17 +112,14 @@ static int mcp3021_probe(struct i2c_client *client,
 
        if (client->dev.platform_data) {
                data->vdd = *(u32 *)client->dev.platform_data;
-               if (data->vdd > MCP3021_VDD_MAX ||
-                               data->vdd < MCP3021_VDD_MIN) {
-                       err = -EINVAL;
-                       goto exit_free;
-               }
+               if (data->vdd > MCP3021_VDD_MAX || data->vdd < MCP3021_VDD_MIN)
+                       return -EINVAL;
        } else
                data->vdd = MCP3021_VDD_REF;
 
        err = sysfs_create_file(&client->dev.kobj, &dev_attr_in0_input.attr);
        if (err)
-               goto exit_free;
+               return err;
 
        data->hwmon_dev = hwmon_device_register(&client->dev);
        if (IS_ERR(data->hwmon_dev)) {
@@ -133,8 +131,6 @@ static int mcp3021_probe(struct i2c_client *client,
 
 exit_remove:
        sysfs_remove_file(&client->dev.kobj, &dev_attr_in0_input.attr);
-exit_free:
-       kfree(data);
        return err;
 }
 
@@ -144,7 +140,6 @@ static int mcp3021_remove(struct i2c_client *client)
 
        hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_file(&client->dev.kobj, &dev_attr_in0_input.attr);
-       kfree(data);
 
        return 0;
 }
index 8342275378b85759f57b9af583f34d281e58cd25..49f6230bdcf133b473d27a92b223d9dc1c50aada 100644 (file)
@@ -461,8 +461,6 @@ static int sch5627_remove(struct platform_device *pdev)
                hwmon_device_unregister(data->hwmon_dev);
 
        sysfs_remove_group(&pdev->dev.kobj, &sch5627_group);
-       platform_set_drvdata(pdev, NULL);
-       kfree(data);
 
        return 0;
 }
@@ -472,7 +470,8 @@ static int __devinit sch5627_probe(struct platform_device *pdev)
        struct sch5627_data *data;
        int err, build_code, build_id, hwmon_rev, val;
 
-       data = kzalloc(sizeof(struct sch5627_data), GFP_KERNEL);
+       data = devm_kzalloc(&pdev->dev, sizeof(struct sch5627_data),
+                           GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
index 96a7e68718cadb8348ea4d7680750ade1d6d143b..5171180161929f207237d4c9ee0b11e9c58116f1 100644 (file)
@@ -402,9 +402,6 @@ static int sch5636_remove(struct platform_device *pdev)
                device_remove_file(&pdev->dev,
                                   &sch5636_fan_attr[i].dev_attr);
 
-       platform_set_drvdata(pdev, NULL);
-       kfree(data);
-
        return 0;
 }
 
@@ -414,7 +411,8 @@ static int __devinit sch5636_probe(struct platform_device *pdev)
        int i, err, val, revision[2];
        char id[4];
 
-       data = kzalloc(sizeof(struct sch5636_data), GFP_KERNEL);
+       data = devm_kzalloc(&pdev->dev, sizeof(struct sch5636_data),
+                           GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
index 4380f5d07be2b8b5398d43e2e393307f099341e6..d00b30adc34b1c50cb617ec4d6088c7093fc40a1 100644 (file)
@@ -503,10 +503,10 @@ EXPORT_SYMBOL(sch56xx_watchdog_unregister);
  * platform dev find, add and remove functions
  */
 
-static int __init sch56xx_find(int sioaddr, unsigned short *address,
-                              const char **name)
+static int __init sch56xx_find(int sioaddr, const char **name)
 {
        u8 devid;
+       unsigned short address;
        int err;
 
        err = superio_enter(sioaddr);
@@ -540,20 +540,21 @@ static int __init sch56xx_find(int sioaddr, unsigned short *address,
         * Warning the order of the low / high byte is the other way around
         * as on most other superio devices!!
         */
-       *address = superio_inb(sioaddr, SIO_REG_ADDR) |
+       address = superio_inb(sioaddr, SIO_REG_ADDR) |
                   superio_inb(sioaddr, SIO_REG_ADDR + 1) << 8;
-       if (*address == 0) {
+       if (address == 0) {
                pr_warn("Base address not set\n");
                err = -ENODEV;
                goto exit;
        }
+       err = address;
 
 exit:
        superio_exit(sioaddr);
        return err;
 }
 
-static int __init sch56xx_device_add(unsigned short address, const char *name)
+static int __init sch56xx_device_add(int address, const char *name)
 {
        struct resource res = {
                .start  = address,
@@ -593,15 +594,14 @@ exit_device_put:
 
 static int __init sch56xx_init(void)
 {
-       int err;
-       unsigned short address;
-       const char *name;
-
-       err = sch56xx_find(0x4e, &address, &name);
-       if (err)
-               err = sch56xx_find(0x2e, &address, &name);
-       if (err)
-               return err;
+       int address;
+       const char *name = NULL;
+
+       address = sch56xx_find(0x4e, &name);
+       if (address < 0)
+               address = sch56xx_find(0x2e, &name);
+       if (address < 0)
+               return address;
 
        return sch56xx_device_add(address, name);
 }
index 8b011d016621d0057124bf6055936162f50fecc9..e4614644408b0b019db807fd3d6cbe7176b6f9a0 100644 (file)
@@ -884,14 +884,12 @@ static int sht15_invalidate_voltage(struct notifier_block *nb,
 static int __devinit sht15_probe(struct platform_device *pdev)
 {
        int ret;
-       struct sht15_data *data = kzalloc(sizeof(*data), GFP_KERNEL);
+       struct sht15_data *data;
        u8 status = 0;
 
-       if (!data) {
-               ret = -ENOMEM;
-               dev_err(&pdev->dev, "kzalloc failed\n");
-               goto error_ret;
-       }
+       data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
 
        INIT_WORK(&data->read_work, sht15_bh_read_data);
        INIT_WORK(&data->update_supply_work, sht15_update_voltage);
@@ -901,9 +899,8 @@ static int __devinit sht15_probe(struct platform_device *pdev)
        init_waitqueue_head(&data->wait_queue);
 
        if (pdev->dev.platform_data == NULL) {
-               ret = -EINVAL;
                dev_err(&pdev->dev, "no platform data supplied\n");
-               goto err_free_data;
+               return -EINVAL;
        }
        data->pdata = pdev->dev.platform_data;
        data->supply_uV = data->pdata->supply_mv * 1000;
@@ -918,7 +915,7 @@ static int __devinit sht15_probe(struct platform_device *pdev)
         * If a regulator is available,
         * query what the supply voltage actually is!
         */
-       data->reg = regulator_get(data->dev, "vcc");
+       data->reg = devm_regulator_get(data->dev, "vcc");
        if (!IS_ERR(data->reg)) {
                int voltage;
 
@@ -937,51 +934,51 @@ static int __devinit sht15_probe(struct platform_device *pdev)
                        dev_err(&pdev->dev,
                                "regulator notifier request failed\n");
                        regulator_disable(data->reg);
-                       regulator_put(data->reg);
-                       goto err_free_data;
+                       return ret;
                }
        }
 
        /* Try requesting the GPIOs */
-       ret = gpio_request(data->pdata->gpio_sck, "SHT15 sck");
+       ret = devm_gpio_request(&pdev->dev, data->pdata->gpio_sck, "SHT15 sck");
        if (ret) {
                dev_err(&pdev->dev, "gpio request failed\n");
                goto err_release_reg;
        }
        gpio_direction_output(data->pdata->gpio_sck, 0);
 
-       ret = gpio_request(data->pdata->gpio_data, "SHT15 data");
+       ret = devm_gpio_request(&pdev->dev, data->pdata->gpio_data,
+                               "SHT15 data");
        if (ret) {
                dev_err(&pdev->dev, "gpio request failed\n");
-               goto err_release_gpio_sck;
+               goto err_release_reg;
        }
 
-       ret = request_irq(gpio_to_irq(data->pdata->gpio_data),
-                         sht15_interrupt_fired,
-                         IRQF_TRIGGER_FALLING,
-                         "sht15 data",
-                         data);
+       ret = devm_request_irq(&pdev->dev, gpio_to_irq(data->pdata->gpio_data),
+                              sht15_interrupt_fired,
+                              IRQF_TRIGGER_FALLING,
+                              "sht15 data",
+                              data);
        if (ret) {
                dev_err(&pdev->dev, "failed to get irq for data line\n");
-               goto err_release_gpio_data;
+               goto err_release_reg;
        }
        disable_irq_nosync(gpio_to_irq(data->pdata->gpio_data));
        sht15_connection_reset(data);
        ret = sht15_soft_reset(data);
        if (ret)
-               goto err_release_irq;
+               goto err_release_reg;
 
        /* write status with platform data options */
        if (status) {
                ret = sht15_send_status(data, status);
                if (ret)
-                       goto err_release_irq;
+                       goto err_release_reg;
        }
 
        ret = sysfs_create_group(&pdev->dev.kobj, &sht15_attr_group);
        if (ret) {
                dev_err(&pdev->dev, "sysfs create failed\n");
-               goto err_release_irq;
+               goto err_release_reg;
        }
 
        data->hwmon_dev = hwmon_device_register(data->dev);
@@ -994,21 +991,11 @@ static int __devinit sht15_probe(struct platform_device *pdev)
 
 err_release_sysfs_group:
        sysfs_remove_group(&pdev->dev.kobj, &sht15_attr_group);
-err_release_irq:
-       free_irq(gpio_to_irq(data->pdata->gpio_data), data);
-err_release_gpio_data:
-       gpio_free(data->pdata->gpio_data);
-err_release_gpio_sck:
-       gpio_free(data->pdata->gpio_sck);
 err_release_reg:
        if (!IS_ERR(data->reg)) {
                regulator_unregister_notifier(data->reg, &data->nb);
                regulator_disable(data->reg);
-               regulator_put(data->reg);
        }
-err_free_data:
-       kfree(data);
-error_ret:
        return ret;
 }
 
@@ -1030,14 +1017,9 @@ static int __devexit sht15_remove(struct platform_device *pdev)
        if (!IS_ERR(data->reg)) {
                regulator_unregister_notifier(data->reg, &data->nb);
                regulator_disable(data->reg);
-               regulator_put(data->reg);
        }
 
-       free_irq(gpio_to_irq(data->pdata->gpio_data), data);
-       gpio_free(data->pdata->gpio_data);
-       gpio_free(data->pdata->gpio_sck);
        mutex_unlock(&data->read_lock);
-       kfree(data);
 
        return 0;
 }
index 6c2dede4b8e7010ad06bf08df66e2208f53836b1..c2565d04cd4a104df117c32c65878d236f8522ec 100644 (file)
@@ -199,11 +199,10 @@ static int __devinit sht21_probe(struct i2c_client *client,
                return -ENODEV;
        }
 
-       sht21 = kzalloc(sizeof(*sht21), GFP_KERNEL);
-       if (!sht21) {
-               dev_dbg(&client->dev, "kzalloc failed\n");
+       sht21 = devm_kzalloc(&client->dev, sizeof(*sht21), GFP_KERNEL);
+       if (!sht21)
                return -ENOMEM;
-       }
+
        i2c_set_clientdata(client, sht21);
 
        mutex_init(&sht21->lock);
@@ -211,7 +210,7 @@ static int __devinit sht21_probe(struct i2c_client *client,
        err = sysfs_create_group(&client->dev.kobj, &sht21_attr_group);
        if (err) {
                dev_dbg(&client->dev, "could not create sysfs files\n");
-               goto fail_free;
+               return err;
        }
        sht21->hwmon_dev = hwmon_device_register(&client->dev);
        if (IS_ERR(sht21->hwmon_dev)) {
@@ -226,9 +225,6 @@ static int __devinit sht21_probe(struct i2c_client *client,
 
 fail_remove_sysfs:
        sysfs_remove_group(&client->dev.kobj, &sht21_attr_group);
-fail_free:
-       kfree(sht21);
-
        return err;
 }
 
@@ -242,7 +238,6 @@ static int __devexit sht21_remove(struct i2c_client *client)
 
        hwmon_device_unregister(sht21->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &sht21_attr_group);
-       kfree(sht21);
 
        return 0;
 }
index ee4ebc198a9448e868f45af079e8f3d5f51968ae..4cddee04f2e6e4d02102fc1c74000d7d633a6a3f 100644 (file)
@@ -128,12 +128,10 @@ static int __devinit via_cputemp_probe(struct platform_device *pdev)
        int err;
        u32 eax, edx;
 
-       data = kzalloc(sizeof(struct via_cputemp_data), GFP_KERNEL);
-       if (!data) {
-               err = -ENOMEM;
-               dev_err(&pdev->dev, "Out of memory\n");
-               goto exit;
-       }
+       data = devm_kzalloc(&pdev->dev, sizeof(struct via_cputemp_data),
+                           GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
 
        data->id = pdev->id;
        data->name = "via_cputemp";
@@ -151,8 +149,7 @@ static int __devinit via_cputemp_probe(struct platform_device *pdev)
                data->msr_temp = 0x1423;
                break;
        default:
-               err = -ENODEV;
-               goto exit_free;
+               return -ENODEV;
        }
 
        /* test if we can access the TEMPERATURE MSR */
@@ -160,14 +157,14 @@ static int __devinit via_cputemp_probe(struct platform_device *pdev)
        if (err) {
                dev_err(&pdev->dev,
                        "Unable to access TEMPERATURE MSR, giving up\n");
-               goto exit_free;
+               return err;
        }
 
        platform_set_drvdata(pdev, data);
 
        err = sysfs_create_group(&pdev->dev.kobj, &via_cputemp_group);
        if (err)
-               goto exit_free;
+               return err;
 
        if (data->msr_vid)
                data->vrm = vid_which_vrm();
@@ -192,10 +189,6 @@ exit_remove:
        if (data->vrm)
                device_remove_file(&pdev->dev, &dev_attr_cpu0_vid);
        sysfs_remove_group(&pdev->dev.kobj, &via_cputemp_group);
-exit_free:
-       platform_set_drvdata(pdev, NULL);
-       kfree(data);
-exit:
        return err;
 }
 
@@ -207,8 +200,6 @@ static int __devexit via_cputemp_remove(struct platform_device *pdev)
        if (data->vrm)
                device_remove_file(&pdev->dev, &dev_attr_cpu0_vid);
        sysfs_remove_group(&pdev->dev.kobj, &via_cputemp_group);
-       platform_set_drvdata(pdev, NULL);
-       kfree(data);
        return 0;
 }
 
@@ -328,6 +319,7 @@ static int __init via_cputemp_init(void)
        if (err)
                goto exit;
 
+       get_online_cpus();
        for_each_online_cpu(i) {
                struct cpuinfo_x86 *c = &cpu_data(i);
 
@@ -347,12 +339,14 @@ static int __init via_cputemp_init(void)
 
 #ifndef CONFIG_HOTPLUG_CPU
        if (list_empty(&pdev_list)) {
+               put_online_cpus();
                err = -ENODEV;
                goto exit_driver_unreg;
        }
 #endif
 
        register_hotcpu_notifier(&via_cputemp_cpu_notifier);
+       put_online_cpus();
        return 0;
 
 #ifndef CONFIG_HOTPLUG_CPU
@@ -367,6 +361,7 @@ static void __exit via_cputemp_exit(void)
 {
        struct pdev_entry *p, *n;
 
+       get_online_cpus();
        unregister_hotcpu_notifier(&via_cputemp_cpu_notifier);
        mutex_lock(&pdev_list_mutex);
        list_for_each_entry_safe(p, n, &pdev_list, list) {
@@ -375,6 +370,7 @@ static void __exit via_cputemp_exit(void)
                kfree(p);
        }
        mutex_unlock(&pdev_list_mutex);
+       put_online_cpus();
        platform_driver_unregister(&via_cputemp_driver);
 }
 
index 386a845380107f3e8e7e43093764e7a92bc45634..84e3dc5e3a831b0748f02e5a54229a665040594b 100644 (file)
@@ -789,18 +789,16 @@ static int vt8231_probe(struct platform_device *pdev)
 
        /* Reserve the ISA region */
        res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-       if (!request_region(res->start, VT8231_EXTENT,
-                           vt8231_driver.driver.name)) {
+       if (!devm_request_region(&pdev->dev, res->start, VT8231_EXTENT,
+                                vt8231_driver.driver.name)) {
                dev_err(&pdev->dev, "Region 0x%lx-0x%lx already in use!\n",
                        (unsigned long)res->start, (unsigned long)res->end);
                return -ENODEV;
        }
 
-       data = kzalloc(sizeof(struct vt8231_data), GFP_KERNEL);
-       if (!data) {
-               err = -ENOMEM;
-               goto exit_release;
-       }
+       data = devm_kzalloc(&pdev->dev, sizeof(struct vt8231_data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
 
        platform_set_drvdata(pdev, data);
        data->addr = res->start;
@@ -812,7 +810,7 @@ static int vt8231_probe(struct platform_device *pdev)
        /* Register sysfs hooks */
        err = sysfs_create_group(&pdev->dev.kobj, &vt8231_group);
        if (err)
-               goto exit_free;
+               return err;
 
        /* Must update device information to find out the config field */
        data->uch_config = vt8231_read_value(data, VT8231_REG_UCH_CONFIG);
@@ -850,13 +848,6 @@ exit_remove_files:
                sysfs_remove_group(&pdev->dev.kobj, &vt8231_group_temps[i]);
 
        sysfs_remove_group(&pdev->dev.kobj, &vt8231_group);
-
-exit_free:
-       platform_set_drvdata(pdev, NULL);
-       kfree(data);
-
-exit_release:
-       release_region(res->start, VT8231_EXTENT);
        return err;
 }
 
@@ -875,9 +866,6 @@ static int __devexit vt8231_remove(struct platform_device *pdev)
 
        sysfs_remove_group(&pdev->dev.kobj, &vt8231_group);
 
-       release_region(data->addr, VT8231_EXTENT);
-       platform_set_drvdata(pdev, NULL);
-       kfree(data);
        return 0;
 }
 
index 5850b77060885e696989c75e63f2618c38ff5001..c99c8a0473cf13257d9abeb548aa548536d7c8d1 100644 (file)
@@ -668,11 +668,10 @@ w83l786ng_probe(struct i2c_client *client, const struct i2c_device_id *id)
        int i, err = 0;
        u8 reg_tmp;
 
-       data = kzalloc(sizeof(struct w83l786ng_data), GFP_KERNEL);
-       if (!data) {
-               err = -ENOMEM;
-               goto exit;
-       }
+       data = devm_kzalloc(&client->dev, sizeof(struct w83l786ng_data),
+                           GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
 
        i2c_set_clientdata(client, data);
        mutex_init(&data->update_lock);
@@ -708,8 +707,6 @@ w83l786ng_probe(struct i2c_client *client, const struct i2c_device_id *id)
 
 exit_remove:
        sysfs_remove_group(&client->dev.kobj, &w83l786ng_group);
-       kfree(data);
-exit:
        return err;
 }
 
@@ -721,8 +718,6 @@ w83l786ng_remove(struct i2c_client *client)
        hwmon_device_unregister(data->hwmon_dev);
        sysfs_remove_group(&client->dev.kobj, &w83l786ng_group);
 
-       kfree(data);
-
        return 0;
 }
 
index b4aaa1bd6728503b629acea078f3021fc148115a..86b7847906f0c5faeb2f3603fef082798983d879 100644 (file)
@@ -80,6 +80,7 @@ config I2C_I801
        tristate "Intel 82801 (ICH/PCH)"
        depends on PCI
        select CHECK_SIGNATURE if X86 && DMI
+       select GPIOLIB if I2C_MUX
        help
          If you say yes to this option, support will be included for the Intel
          801 family of mainboard I2C interfaces.  Specifically, the following
index 898dcf9c7adeaac26d932b6e8c6a6e8d90e9be66..6f0078538ca6b67e9a9359645dbc3cba13899e6f 100644 (file)
 #include <linux/dmi.h>
 #include <linux/slab.h>
 #include <linux/wait.h>
+#include <linux/err.h>
+
+#if defined CONFIG_I2C_MUX || defined CONFIG_I2C_MUX_MODULE
+#include <linux/gpio.h>
+#include <linux/i2c-mux-gpio.h>
+#include <linux/platform_device.h>
+#endif
 
 /* I801 SMBus address offsets */
 #define SMBHSTSTS(p)   (0 + (p)->smba)
 #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS        0x3b30
 #define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS    0x8c22
 
+struct i801_mux_config {
+       char *gpio_chip;
+       unsigned values[3];
+       int n_values;
+       unsigned classes[3];
+       unsigned gpios[2];              /* Relative to gpio_chip->base */
+       int n_gpios;
+};
+
 struct i801_priv {
        struct i2c_adapter adapter;
        unsigned long smba;
@@ -173,6 +189,12 @@ struct i801_priv {
        int count;
        int len;
        u8 *data;
+
+#if defined CONFIG_I2C_MUX || defined CONFIG_I2C_MUX_MODULE
+       const struct i801_mux_config *mux_drvdata;
+       unsigned mux_priv[2];
+       struct platform_device *mux_pdev;
+#endif
 };
 
 static struct pci_driver i801_driver;
@@ -897,6 +919,193 @@ static void __init input_apanel_init(void) {}
 static void __devinit i801_probe_optional_slaves(struct i801_priv *priv) {}
 #endif /* CONFIG_X86 && CONFIG_DMI */
 
+#if defined CONFIG_I2C_MUX || defined CONFIG_I2C_MUX_MODULE
+static struct i801_mux_config i801_mux_config_asus_z8_d12 = {
+       .gpio_chip = "gpio_ich",
+       .values = { 0x02, 0x03 },
+       .n_values = 2,
+       .classes = { I2C_CLASS_SPD, I2C_CLASS_SPD },
+       .gpios = { 52, 53 },
+       .n_gpios = 2,
+};
+
+static struct i801_mux_config i801_mux_config_asus_z8_d18 = {
+       .gpio_chip = "gpio_ich",
+       .values = { 0x02, 0x03, 0x01 },
+       .n_values = 3,
+       .classes = { I2C_CLASS_SPD, I2C_CLASS_SPD, I2C_CLASS_SPD },
+       .gpios = { 52, 53 },
+       .n_gpios = 2,
+};
+
+static struct dmi_system_id __devinitdata mux_dmi_table[] = {
+       {
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+                       DMI_MATCH(DMI_BOARD_NAME, "Z8NA-D6(C)"),
+               },
+               .driver_data = &i801_mux_config_asus_z8_d12,
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+                       DMI_MATCH(DMI_BOARD_NAME, "Z8P(N)E-D12(X)"),
+               },
+               .driver_data = &i801_mux_config_asus_z8_d12,
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+                       DMI_MATCH(DMI_BOARD_NAME, "Z8NH-D12"),
+               },
+               .driver_data = &i801_mux_config_asus_z8_d12,
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+                       DMI_MATCH(DMI_BOARD_NAME, "Z8PH-D12/IFB"),
+               },
+               .driver_data = &i801_mux_config_asus_z8_d12,
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+                       DMI_MATCH(DMI_BOARD_NAME, "Z8NR-D12"),
+               },
+               .driver_data = &i801_mux_config_asus_z8_d12,
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+                       DMI_MATCH(DMI_BOARD_NAME, "Z8P(N)H-D12"),
+               },
+               .driver_data = &i801_mux_config_asus_z8_d12,
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+                       DMI_MATCH(DMI_BOARD_NAME, "Z8PG-D18"),
+               },
+               .driver_data = &i801_mux_config_asus_z8_d18,
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+                       DMI_MATCH(DMI_BOARD_NAME, "Z8PE-D18"),
+               },
+               .driver_data = &i801_mux_config_asus_z8_d18,
+       },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+                       DMI_MATCH(DMI_BOARD_NAME, "Z8PS-D12"),
+               },
+               .driver_data = &i801_mux_config_asus_z8_d12,
+       },
+       { }
+};
+
+static int __devinit match_gpio_chip_by_label(struct gpio_chip *chip,
+                                             void *data)
+{
+       return !strcmp(chip->label, data);
+}
+
+/* Setup multiplexing if needed */
+static int __devinit i801_add_mux(struct i801_priv *priv)
+{
+       struct device *dev = &priv->adapter.dev;
+       const struct i801_mux_config *mux_config;
+       struct gpio_chip *gpio;
+       struct i2c_mux_gpio_platform_data gpio_data;
+       int i, err;
+
+       if (!priv->mux_drvdata)
+               return 0;
+       mux_config = priv->mux_drvdata;
+
+       /* Find GPIO chip */
+       gpio = gpiochip_find(mux_config->gpio_chip, match_gpio_chip_by_label);
+       if (gpio) {
+               dev_info(dev,
+                        "GPIO chip %s found, SMBus multiplexing enabled\n",
+                        mux_config->gpio_chip);
+       } else {
+               dev_err(dev,
+                       "GPIO chip %s not found, SMBus multiplexing disabled\n",
+                       mux_config->gpio_chip);
+               return -ENODEV;
+       }
+
+       /* Find absolute GPIO pin numbers */
+       if (ARRAY_SIZE(priv->mux_priv) < mux_config->n_gpios) {
+               dev_err(dev, "i801_priv.mux_priv too small (%zu, need %d)\n",
+                       ARRAY_SIZE(priv->mux_priv), mux_config->n_gpios);
+               return -ENODEV;
+       }
+       for (i = 0; i < mux_config->n_gpios; i++)
+               priv->mux_priv[i] = gpio->base + mux_config->gpios[i];
+
+       /* Prepare the platform data */
+       memset(&gpio_data, 0, sizeof(struct i2c_mux_gpio_platform_data));
+       gpio_data.parent = priv->adapter.nr;
+       gpio_data.values = mux_config->values;
+       gpio_data.n_values = mux_config->n_values;
+       gpio_data.classes = mux_config->classes;
+       gpio_data.gpios = priv->mux_priv;
+       gpio_data.n_gpios = mux_config->n_gpios;
+       gpio_data.idle = I2C_MUX_GPIO_NO_IDLE;
+
+       /* Register the mux device */
+       priv->mux_pdev = platform_device_register_data(dev, "i2c-mux-gpio",
+                               priv->mux_priv[0], &gpio_data,
+                               sizeof(struct i2c_mux_gpio_platform_data));
+       if (IS_ERR(priv->mux_pdev)) {
+               err = PTR_ERR(priv->mux_pdev);
+               priv->mux_pdev = NULL;
+               dev_err(dev, "Failed to register i2c-mux-gpio device\n");
+               return err;
+       }
+
+       return 0;
+}
+
+static void __devexit 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)
+{
+       const struct dmi_system_id *id;
+       const struct i801_mux_config *mux_config;
+       unsigned int class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+       int i;
+
+       id = dmi_first_match(mux_dmi_table);
+       if (id) {
+               /* Remove from branch classes from trunk */
+               mux_config = id->driver_data;
+               for (i = 0; i < mux_config->n_values; i++)
+                       class &= ~mux_config->classes[i];
+
+               /* Remember for later */
+               priv->mux_drvdata = mux_config;
+       }
+
+       return class;
+}
+#else
+static inline int i801_add_mux(struct i801_priv *priv) { return 0; }
+static inline void i801_del_mux(struct i801_priv *priv) { }
+
+static inline unsigned int i801_get_adapter_class(struct i801_priv *priv)
+{
+       return I2C_CLASS_HWMON | I2C_CLASS_SPD;
+}
+#endif
+
 static int __devinit i801_probe(struct pci_dev *dev,
                                const struct pci_device_id *id)
 {
@@ -910,7 +1119,7 @@ static int __devinit i801_probe(struct pci_dev *dev,
 
        i2c_set_adapdata(&priv->adapter, priv);
        priv->adapter.owner = THIS_MODULE;
-       priv->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+       priv->adapter.class = i801_get_adapter_class(priv);
        priv->adapter.algo = &smbus_algorithm;
 
        priv->pci_dev = dev;
@@ -1030,6 +1239,8 @@ static int __devinit i801_probe(struct pci_dev *dev,
        }
 
        i801_probe_optional_slaves(priv);
+       /* We ignore errors - multiplexing is optional */
+       i801_add_mux(priv);
 
        pci_set_drvdata(dev, priv);
 
@@ -1049,6 +1260,7 @@ static void __devexit i801_remove(struct pci_dev *dev)
 {
        struct i801_priv *priv = pci_get_drvdata(dev);
 
+       i801_del_mux(priv);
        i2c_del_adapter(&priv->adapter);
        pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
 
index 93f147a96b6222253f367d4c6eb161922447a85a..2f99613fd677479a0b321412fa109d97c9a0b86f 100644 (file)
@@ -4,13 +4,13 @@
 /* Copyright (C) 2003 Peter Milne, D-TACQ Solutions Ltd
  *                    <Peter dot Milne at D hyphen TACQ dot com>
  *
- * With acknowledgements to i2c-algo-ibm_ocp.c by 
+ * With acknowledgements to i2c-algo-ibm_ocp.c by
  * Ian DaSilva, MontaVista Software, Inc. idasilva@mvista.com
  *
  * And i2c-algo-pcf.c, which was created by Simon G. Vogl and Hans Berglund:
  *
  * Copyright (C) 1995-1997 Simon G. Vogl, 1998-2000 Hans Berglund
- *  
+ *
  * And which acknowledged Kyösti Mälkki <kmalkki@cc.hut.fi>,
  * Frodo Looijaard <frodol@dds.nl>, Martin Bailey<mbailey@littlefeet-inc.com>
  *
 #include <linux/platform_device.h>
 #include <linux/i2c.h>
 #include <linux/io.h>
+#include <linux/gpio.h>
 
 #include "i2c-iop3xx.h"
 
 /* global unit counter */
 static int i2c_id;
 
-static inline unsigned char 
-iic_cook_addr(struct i2c_msg *msg) 
+static inline unsigned char
+iic_cook_addr(struct i2c_msg *msg)
 {
        unsigned char addr;
 
@@ -55,38 +56,38 @@ iic_cook_addr(struct i2c_msg *msg)
        if (msg->flags & I2C_M_RD)
                addr |= 1;
 
-       return addr;   
+       return addr;
 }
 
-static void 
+static void
 iop3xx_i2c_reset(struct i2c_algo_iop3xx_data *iop3xx_adap)
 {
        /* Follows devman 9.3 */
        __raw_writel(IOP3XX_ICR_UNIT_RESET, iop3xx_adap->ioaddr + CR_OFFSET);
        __raw_writel(IOP3XX_ISR_CLEARBITS, iop3xx_adap->ioaddr + SR_OFFSET);
        __raw_writel(0, iop3xx_adap->ioaddr + CR_OFFSET);
-} 
+}
 
-static void 
+static void
 iop3xx_i2c_enable(struct i2c_algo_iop3xx_data *iop3xx_adap)
 {
        u32 cr = IOP3XX_ICR_GCD | IOP3XX_ICR_SCLEN | IOP3XX_ICR_UE;
 
-       /* 
+       /*
         * Every time unit enable is asserted, GPOD needs to be cleared
         * on IOP3XX to avoid data corruption on the bus.
         */
 #if defined(CONFIG_ARCH_IOP32X) || defined(CONFIG_ARCH_IOP33X)
        if (iop3xx_adap->id == 0) {
-               gpio_line_set(IOP3XX_GPIO_LINE(7), GPIO_LOW);
-               gpio_line_set(IOP3XX_GPIO_LINE(6), GPIO_LOW);
+               gpio_set_value(7, 0);
+               gpio_set_value(6, 0);
        } else {
-               gpio_line_set(IOP3XX_GPIO_LINE(5), GPIO_LOW);
-               gpio_line_set(IOP3XX_GPIO_LINE(4), GPIO_LOW);
+               gpio_set_value(5, 0);
+               gpio_set_value(4, 0);
        }
 #endif
        /* NB SR bits not same position as CR IE bits :-( */
-       iop3xx_adap->SR_enabled = 
+       iop3xx_adap->SR_enabled =
                IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD |
                IOP3XX_ISR_RXFULL | IOP3XX_ISR_TXEMPTY;
 
@@ -96,23 +97,23 @@ iop3xx_i2c_enable(struct i2c_algo_iop3xx_data *iop3xx_adap)
        __raw_writel(cr, iop3xx_adap->ioaddr + CR_OFFSET);
 }
 
-static void 
+static void
 iop3xx_i2c_transaction_cleanup(struct i2c_algo_iop3xx_data *iop3xx_adap)
 {
        unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET);
-       
-       cr &= ~(IOP3XX_ICR_MSTART | IOP3XX_ICR_TBYTE | 
+
+       cr &= ~(IOP3XX_ICR_MSTART | IOP3XX_ICR_TBYTE |
                IOP3XX_ICR_MSTOP | IOP3XX_ICR_SCLEN);
 
        __raw_writel(cr, iop3xx_adap->ioaddr + CR_OFFSET);
 }
 
-/* 
- * NB: the handler has to clear the source of the interrupt! 
+/*
+ * NB: the handler has to clear the source of the interrupt!
  * Then it passes the SR flags of interest to BH via adap data
  */
-static irqreturn_t 
-iop3xx_i2c_irq_handler(int this_irq, void *dev_id) 
+static irqreturn_t
+iop3xx_i2c_irq_handler(int this_irq, void *dev_id)
 {
        struct i2c_algo_iop3xx_data *iop3xx_adap = dev_id;
        u32 sr = __raw_readl(iop3xx_adap->ioaddr + SR_OFFSET);
@@ -126,7 +127,7 @@ iop3xx_i2c_irq_handler(int this_irq, void *dev_id)
 }
 
 /* check all error conditions, clear them , report most important */
-static int 
+static int
 iop3xx_i2c_error(u32 sr)
 {
        int rc = 0;
@@ -135,12 +136,12 @@ iop3xx_i2c_error(u32 sr)
                if ( !rc ) rc = -I2C_ERR_BERR;
        }
        if ((sr & IOP3XX_ISR_ALD)) {
-               if ( !rc ) rc = -I2C_ERR_ALD;           
+               if ( !rc ) rc = -I2C_ERR_ALD;
        }
-       return rc;      
+       return rc;
 }
 
-static inline u32 
+static inline u32
 iop3xx_i2c_get_srstat(struct i2c_algo_iop3xx_data *iop3xx_adap)
 {
        unsigned long flags;
@@ -161,8 +162,8 @@ iop3xx_i2c_get_srstat(struct i2c_algo_iop3xx_data *iop3xx_adap)
 typedef int (* compare_func)(unsigned test, unsigned mask);
 /* returns 1 on correct comparison */
 
-static int 
-iop3xx_i2c_wait_event(struct i2c_algo_iop3xx_data *iop3xx_adap, 
+static int
+iop3xx_i2c_wait_event(struct i2c_algo_iop3xx_data *iop3xx_adap,
                          unsigned flags, unsigned* status,
                          compare_func compare)
 {
@@ -192,47 +193,47 @@ iop3xx_i2c_wait_event(struct i2c_algo_iop3xx_data *iop3xx_adap,
 }
 
 /*
- * Concrete compare_funcs 
+ * Concrete compare_funcs
  */
-static int 
+static int
 all_bits_clear(unsigned test, unsigned mask)
 {
        return (test & mask) == 0;
 }
 
-static int 
+static int
 any_bits_set(unsigned test, unsigned mask)
 {
        return (test & mask) != 0;
 }
 
-static int 
+static int
 iop3xx_i2c_wait_tx_done(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status)
 {
-       return iop3xx_i2c_wait_event( 
-               iop3xx_adap, 
+       return iop3xx_i2c_wait_event(
+               iop3xx_adap,
                IOP3XX_ISR_TXEMPTY | IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD,
                status, any_bits_set);
 }
 
-static int 
+static int
 iop3xx_i2c_wait_rx_done(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status)
 {
-       return iop3xx_i2c_wait_event( 
-               iop3xx_adap, 
+       return iop3xx_i2c_wait_event(
+               iop3xx_adap,
                IOP3XX_ISR_RXFULL | IOP3XX_ISR_ALD | IOP3XX_ISR_BERRD,
                status, any_bits_set);
 }
 
-static int 
+static int
 iop3xx_i2c_wait_idle(struct i2c_algo_iop3xx_data *iop3xx_adap, int *status)
 {
-       return iop3xx_i2c_wait_event( 
+       return iop3xx_i2c_wait_event(
                iop3xx_adap, IOP3XX_ISR_UNITBUSY, status, all_bits_clear);
 }
 
-static int 
-iop3xx_i2c_send_target_addr(struct i2c_algo_iop3xx_data *iop3xx_adap, 
+static int
+iop3xx_i2c_send_target_addr(struct i2c_algo_iop3xx_data *iop3xx_adap,
                                struct i2c_msg* msg)
 {
        unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET);
@@ -247,7 +248,7 @@ iop3xx_i2c_send_target_addr(struct i2c_algo_iop3xx_data *iop3xx_adap,
        }
 
        __raw_writel(iic_cook_addr(msg), iop3xx_adap->ioaddr + DBR_OFFSET);
-       
+
        cr &= ~(IOP3XX_ICR_MSTOP | IOP3XX_ICR_NACK);
        cr |= IOP3XX_ICR_MSTART | IOP3XX_ICR_TBYTE;
 
@@ -257,8 +258,8 @@ iop3xx_i2c_send_target_addr(struct i2c_algo_iop3xx_data *iop3xx_adap,
        return rc;
 }
 
-static int 
-iop3xx_i2c_write_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char byte, 
+static int
+iop3xx_i2c_write_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char byte,
                                int stop)
 {
        unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET);
@@ -277,10 +278,10 @@ iop3xx_i2c_write_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char byte,
        rc = iop3xx_i2c_wait_tx_done(iop3xx_adap, &status);
 
        return rc;
-} 
+}
 
-static int 
-iop3xx_i2c_read_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char* byte, 
+static int
+iop3xx_i2c_read_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char* byte,
                                int stop)
 {
        unsigned long cr = __raw_readl(iop3xx_adap->ioaddr + CR_OFFSET);
@@ -304,19 +305,19 @@ iop3xx_i2c_read_byte(struct i2c_algo_iop3xx_data *iop3xx_adap, char* byte,
        return rc;
 }
 
-static int 
+static int
 iop3xx_i2c_writebytes(struct i2c_adapter *i2c_adap, const char *buf, int count)
 {
        struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
        int ii;
        int rc = 0;
 
-       for (ii = 0; rc == 0 && ii != count; ++ii) 
+       for (ii = 0; rc == 0 && ii != count; ++ii)
                rc = iop3xx_i2c_write_byte(iop3xx_adap, buf[ii], ii==count-1);
        return rc;
 }
 
-static int 
+static int
 iop3xx_i2c_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count)
 {
        struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
@@ -325,7 +326,7 @@ iop3xx_i2c_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count)
 
        for (ii = 0; rc == 0 && ii != count; ++ii)
                rc = iop3xx_i2c_read_byte(iop3xx_adap, &buf[ii], ii==count-1);
-       
+
        return rc;
 }
 
@@ -336,8 +337,8 @@ iop3xx_i2c_readbytes(struct i2c_adapter *i2c_adap, char *buf, int count)
  * Each transfer (i.e. a read or a write) is separated by a repeated start
  * condition.
  */
-static int 
-iop3xx_i2c_handle_msg(struct i2c_adapter *i2c_adap, struct i2c_msg* pmsg) 
+static int
+iop3xx_i2c_handle_msg(struct i2c_adapter *i2c_adap, struct i2c_msg* pmsg)
 {
        struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
        int rc;
@@ -357,8 +358,8 @@ iop3xx_i2c_handle_msg(struct i2c_adapter *i2c_adap, struct i2c_msg* pmsg)
 /*
  * master_xfer() - main read/write entry
  */
-static int 
-iop3xx_i2c_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, 
+static int
+iop3xx_i2c_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
                                int num)
 {
        struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data;
@@ -375,14 +376,14 @@ iop3xx_i2c_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
        }
 
        iop3xx_i2c_transaction_cleanup(iop3xx_adap);
-       
+
        if(ret)
                return ret;
 
-       return im;   
+       return im;
 }
 
-static u32 
+static u32
 iop3xx_i2c_func(struct i2c_adapter *adap)
 {
        return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
@@ -393,11 +394,11 @@ static const struct i2c_algorithm iop3xx_i2c_algo = {
        .functionality  = iop3xx_i2c_func,
 };
 
-static int 
+static int
 iop3xx_i2c_remove(struct platform_device *pdev)
 {
        struct i2c_adapter *padapter = platform_get_drvdata(pdev);
-       struct i2c_algo_iop3xx_data *adapter_data = 
+       struct i2c_algo_iop3xx_data *adapter_data =
                (struct i2c_algo_iop3xx_data *)padapter->algo_data;
        struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        unsigned long cr = __raw_readl(adapter_data->ioaddr + CR_OFFSET);
@@ -419,7 +420,7 @@ iop3xx_i2c_remove(struct platform_device *pdev)
        return 0;
 }
 
-static int 
+static int
 iop3xx_i2c_probe(struct platform_device *pdev)
 {
        struct resource *res;
index b76731edbf106cfbe505173a677da38df02c146b..57f7703ce2e8cfbba6af7665b8cfde11e8d0fb9e 100644 (file)
@@ -647,7 +647,7 @@ static int __devinit fsl_i2c_probe(struct platform_device *op)
        }
 
        if (match->data) {
-               struct mpc_i2c_data *data = match->data;
+               const struct mpc_i2c_data *data = match->data;
                data->setup(op->dev.of_node, i2c, clock, data->prescaler);
        } else {
                /* Backwards compatibility */
@@ -730,24 +730,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 struct mpc_i2c_data mpc_i2c_data_512x __devinitdata = {
+static const struct mpc_i2c_data mpc_i2c_data_512x __devinitdata = {
        .setup = mpc_i2c_setup_512x,
 };
 
-static struct mpc_i2c_data mpc_i2c_data_52xx __devinitdata = {
+static const struct mpc_i2c_data mpc_i2c_data_52xx __devinitdata = {
        .setup = mpc_i2c_setup_52xx,
 };
 
-static struct mpc_i2c_data mpc_i2c_data_8313 __devinitdata = {
+static const struct mpc_i2c_data mpc_i2c_data_8313 __devinitdata = {
        .setup = mpc_i2c_setup_8xxx,
 };
 
-static struct mpc_i2c_data mpc_i2c_data_8543 __devinitdata = {
+static const struct mpc_i2c_data mpc_i2c_data_8543 __devinitdata = {
        .setup = mpc_i2c_setup_8xxx,
        .prescaler = 2,
 };
 
-static struct mpc_i2c_data mpc_i2c_data_8544 __devinitdata = {
+static const struct mpc_i2c_data mpc_i2c_data_8544 __devinitdata = {
        .setup = mpc_i2c_setup_8xxx,
        .prescaler = 3,
 };
index 6849635b268a81fe8f85d380d2d80d16ba6ab2b1..3d2a33a76ac2ab0f661d0d7a6e7f867cababaf5b 100644 (file)
@@ -944,7 +944,8 @@ omap_i2c_probe(struct platform_device *pdev)
        struct omap_i2c_dev     *dev;
        struct i2c_adapter      *adap;
        struct resource         *mem, *irq, *ioarea;
-       struct omap_i2c_bus_platform_data *pdata = pdev->dev.platform_data;
+       const struct omap_i2c_bus_platform_data *pdata =
+               pdev->dev.platform_data;
        struct device_node      *node = pdev->dev.of_node;
        const struct of_device_id *match;
        irq_handler_t isr;
index 2efa56c5ff2c32d10ff3018def5bc077b8492e4e..96ef3d88e3c31537bacffef80a17e8ba30bdfd17 100644 (file)
@@ -1971,12 +1971,22 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr,
        unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+3];
        unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2];
        int num = read_write == I2C_SMBUS_READ ? 2 : 1;
-       struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 },
-                                 { addr, flags | I2C_M_RD, 0, msgbuf1 }
-                               };
        int i;
        u8 partial_pec = 0;
        int status;
+       struct i2c_msg msg[2] = {
+               {
+                       .addr = addr,
+                       .flags = flags,
+                       .len = 1,
+                       .buf = msgbuf0,
+               }, {
+                       .addr = addr,
+                       .flags = flags | I2C_M_RD,
+                       .len = 0,
+                       .buf = msgbuf1,
+               },
+       };
 
        msgbuf0[0] = command;
        switch (size) {
index 1038c381aea5bf4542bb574ae308027e607594d9..d94e0ce78277c947b2ebfca2732ab88e36effa05 100644 (file)
@@ -88,9 +88,23 @@ static u32 i2c_mux_functionality(struct i2c_adapter *adap)
        return parent->algo->functionality(parent);
 }
 
+/* Return all parent classes, merged */
+static unsigned int i2c_mux_parent_classes(struct i2c_adapter *parent)
+{
+       unsigned int class = 0;
+
+       do {
+               class |= parent->class;
+               parent = i2c_parent_is_i2c_adapter(parent);
+       } while (parent);
+
+       return class;
+}
+
 struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
                                struct device *mux_dev,
                                void *mux_priv, u32 force_nr, u32 chan_id,
+                               unsigned int class,
                                int (*select) (struct i2c_adapter *,
                                               void *, u32),
                                int (*deselect) (struct i2c_adapter *,
@@ -127,6 +141,14 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
        priv->adap.algo_data = priv;
        priv->adap.dev.parent = &parent->dev;
 
+       /* Sanity check on class */
+       if (i2c_mux_parent_classes(parent) & class)
+               dev_err(&parent->dev,
+                       "Segment %d behind mux can't share classes with ancestors\n",
+                       chan_id);
+       else
+               priv->adap.class = class;
+
        /*
         * Try to populate the mux adapter's of_node, expands to
         * nothing if !CONFIG_OF.
index df3e0bf31eb3cb86a0ad287651ca183d58280a0e..92cdd2323b03f3adc8a3a0303d9f51c2eca23c5f 100644 (file)
@@ -142,7 +142,8 @@ static int smbalert_probe(struct i2c_client *ara,
        struct i2c_adapter *adapter = ara->adapter;
        int res;
 
-       alert = kzalloc(sizeof(struct i2c_smbus_alert), GFP_KERNEL);
+       alert = devm_kzalloc(&ara->dev, sizeof(struct i2c_smbus_alert),
+                            GFP_KERNEL);
        if (!alert)
                return -ENOMEM;
 
@@ -154,10 +155,8 @@ static int smbalert_probe(struct i2c_client *ara,
        if (setup->irq > 0) {
                res = devm_request_irq(&ara->dev, setup->irq, smbalert_irq,
                                       0, "smbus_alert", alert);
-               if (res) {
-                       kfree(alert);
+               if (res)
                        return res;
-               }
        }
 
        i2c_set_clientdata(ara, alert);
@@ -167,14 +166,12 @@ static int smbalert_probe(struct i2c_client *ara,
        return 0;
 }
 
-/* IRQ resource is managed so it is freed automatically */
+/* IRQ and memory resources are managed so they are freed automatically */
 static int smbalert_remove(struct i2c_client *ara)
 {
        struct i2c_smbus_alert *alert = i2c_get_clientdata(ara);
 
        cancel_work_sync(&alert->alert);
-
-       kfree(alert);
        return 0;
 }
 
index 68b1f8ec34363530241fc9c7c8a587a04d35c09b..56889e00c76e6522ca557a05683c7b94f8ba907a 100644 (file)
@@ -104,8 +104,10 @@ static int __devinit i2c_mux_gpio_probe(struct platform_device *pdev)
 
        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;
 
-               mux->adap[i] = i2c_add_mux_adapter(parent, &pdev->dev, mux, nr, i,
+               mux->adap[i] = i2c_add_mux_adapter(parent, &pdev->dev, mux, nr,
+                                                  i, class,
                                                   i2c_mux_gpio_select, deselect);
                if (!mux->adap[i]) {
                        ret = -ENODEV;
index f8f72f39e0b5605dbbbf2d32326d28c43abbfd7d..f3b8f9a6a89b65eb29050c591e181b908d0358f3 100644 (file)
@@ -354,7 +354,7 @@ static int pca9541_probe(struct i2c_client *client,
        if (pdata)
                force = pdata->modes[0].adap_id;
        data->mux_adap = i2c_add_mux_adapter(adap, &client->dev, client,
-                                            force, 0,
+                                            force, 0, 0,
                                             pca9541_select_chan,
                                             pca9541_release_chan);
 
index f2dfe0d8fcce89d703cb7ba29072ee4921e6697b..8e4387235b697eeeed46a8db77a2bf683e09d84f 100644 (file)
@@ -186,7 +186,7 @@ static int pca954x_probe(struct i2c_client *client,
 {
        struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
        struct pca954x_platform_data *pdata = client->dev.platform_data;
-       int num, force;
+       int num, force, class;
        struct pca954x *data;
        int ret = -ENODEV;
 
@@ -216,18 +216,20 @@ static int pca954x_probe(struct i2c_client *client,
        /* Now create an adapter for each channel */
        for (num = 0; num < chips[data->type].nchans; num++) {
                force = 0;                        /* dynamic adap number */
+               class = 0;                        /* no class by default */
                if (pdata) {
-                       if (num < pdata->num_modes)
+                       if (num < pdata->num_modes) {
                                /* force static number */
                                force = pdata->modes[num].adap_id;
-                       else
+                               class = pdata->modes[num].class;
+                       } else
                                /* discard unconfigured channels */
                                break;
                }
 
                data->virt_adaps[num] =
                        i2c_add_mux_adapter(adap, &client->dev, client,
-                               force, num, pca954x_select_chan,
+                               force, num, class, pca954x_select_chan,
                                (pdata && pdata->modes[num].deselect_on_exit)
                                        ? pca954x_deselect_mux : NULL);
 
index 46a669763476053be99d5601cb07c6d2dd0cd8e0..5f097f309b9f9e92c59a5525db04283ab699fc74 100644 (file)
@@ -221,7 +221,7 @@ static int __devinit i2c_mux_pinctrl_probe(struct platform_device *pdev)
                                (mux->pdata->base_bus_num + i) : 0;
 
                mux->busses[i] = i2c_add_mux_adapter(mux->parent, &pdev->dev,
-                                                    mux, bus, i,
+                                                    mux, bus, i, 0,
                                                     i2c_mux_pinctrl_select,
                                                     deselect);
                if (!mux->busses[i]) {
index f559088869f6451fc349a808778266b4f77557a9..e8726177d103082021a6549d4ce32d161e2bab2a 100644 (file)
@@ -606,8 +606,9 @@ static int __init intel_idle_init(void)
        intel_idle_cpuidle_driver_init();
        retval = cpuidle_register_driver(&intel_idle_driver);
        if (retval) {
+               struct cpuidle_driver *drv = cpuidle_get_driver();
                printk(KERN_DEBUG PREFIX "intel_idle yielding to %s",
-                       cpuidle_get_driver()->name);
+                       drv ? drv->name : "none");
                return retval;
        }
 
index f61780a02374d1f855af861092c3ebae5b35cd80..98c96f90c88b10168e6a5f72049730b6b337af93 100644 (file)
@@ -545,13 +545,6 @@ static int __devinit at91_adc_probe(struct platform_device *pdev)
                goto error_free_device;
        }
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "No resource defined\n");
-               ret = -ENXIO;
-               goto error_ret;
-       }
-
        platform_set_drvdata(pdev, idev);
 
        idev->dev.parent = &pdev->dev;
@@ -566,18 +559,12 @@ static int __devinit at91_adc_probe(struct platform_device *pdev)
                goto error_free_device;
        }
 
-       if (!request_mem_region(res->start, resource_size(res),
-                               "AT91 adc registers")) {
-               dev_err(&pdev->dev, "Resources are unavailable.\n");
-               ret = -EBUSY;
-               goto error_free_device;
-       }
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
-       st->reg_base = ioremap(res->start, resource_size(res));
+       st->reg_base = devm_request_and_ioremap(&pdev->dev, res);
        if (!st->reg_base) {
-               dev_err(&pdev->dev, "Failed to map registers.\n");
                ret = -ENOMEM;
-               goto error_release_mem;
+               goto error_free_device;
        }
 
        /*
@@ -592,10 +579,10 @@ static int __devinit at91_adc_probe(struct platform_device *pdev)
                          idev);
        if (ret) {
                dev_err(&pdev->dev, "Failed to allocate IRQ.\n");
-               goto error_unmap_reg;
+               goto error_free_device;
        }
 
-       st->clk = clk_get(&pdev->dev, "adc_clk");
+       st->clk = devm_clk_get(&pdev->dev, "adc_clk");
        if (IS_ERR(st->clk)) {
                dev_err(&pdev->dev, "Failed to get the clock.\n");
                ret = PTR_ERR(st->clk);
@@ -605,7 +592,7 @@ static int __devinit at91_adc_probe(struct platform_device *pdev)
        ret = clk_prepare(st->clk);
        if (ret) {
                dev_err(&pdev->dev, "Could not prepare the clock.\n");
-               goto error_free_clk;
+               goto error_free_irq;
        }
 
        ret = clk_enable(st->clk);
@@ -614,7 +601,7 @@ static int __devinit at91_adc_probe(struct platform_device *pdev)
                goto error_unprepare_clk;
        }
 
-       st->adc_clk = clk_get(&pdev->dev, "adc_op_clk");
+       st->adc_clk = devm_clk_get(&pdev->dev, "adc_op_clk");
        if (IS_ERR(st->adc_clk)) {
                dev_err(&pdev->dev, "Failed to get the ADC clock.\n");
                ret = PTR_ERR(st->clk);
@@ -624,7 +611,7 @@ static int __devinit at91_adc_probe(struct platform_device *pdev)
        ret = clk_prepare(st->adc_clk);
        if (ret) {
                dev_err(&pdev->dev, "Could not prepare the ADC clock.\n");
-               goto error_free_adc_clk;
+               goto error_disable_clk;
        }
 
        ret = clk_enable(st->adc_clk);
@@ -697,20 +684,12 @@ error_disable_adc_clk:
        clk_disable(st->adc_clk);
 error_unprepare_adc_clk:
        clk_unprepare(st->adc_clk);
-error_free_adc_clk:
-       clk_put(st->adc_clk);
 error_disable_clk:
        clk_disable(st->clk);
 error_unprepare_clk:
        clk_unprepare(st->clk);
-error_free_clk:
-       clk_put(st->clk);
 error_free_irq:
        free_irq(st->irq, idev);
-error_unmap_reg:
-       iounmap(st->reg_base);
-error_release_mem:
-       release_mem_region(res->start, resource_size(res));
 error_free_device:
        iio_device_free(idev);
 error_ret:
@@ -720,20 +699,15 @@ error_ret:
 static int __devexit at91_adc_remove(struct platform_device *pdev)
 {
        struct iio_dev *idev = platform_get_drvdata(pdev);
-       struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        struct at91_adc_state *st = iio_priv(idev);
 
        iio_device_unregister(idev);
        at91_adc_trigger_remove(idev);
        at91_adc_buffer_remove(idev);
        clk_disable_unprepare(st->adc_clk);
-       clk_put(st->adc_clk);
        clk_disable(st->clk);
        clk_unprepare(st->clk);
-       clk_put(st->clk);
        free_irq(st->irq, idev);
-       iounmap(st->reg_base);
-       release_mem_region(res->start, resource_size(res));
        iio_device_free(idev);
 
        return 0;
index 59fbb3ae40e7f4628b3bc9d545a27c86e379bdbc..e35bb8f6fe7597e8823527772b119cd3b579377d 100644 (file)
@@ -129,7 +129,7 @@ static int adf4350_set_freq(struct adf4350_state *st, unsigned long long freq)
 {
        struct adf4350_platform_data *pdata = st->pdata;
        u64 tmp;
-       u32 div_gcd, prescaler;
+       u32 div_gcd, prescaler, chspc;
        u16 mdiv, r_cnt = 0;
        u8 band_sel_div;
 
@@ -158,14 +158,20 @@ static int adf4350_set_freq(struct adf4350_state *st, unsigned long long freq)
        if (pdata->ref_div_factor)
                r_cnt = pdata->ref_div_factor - 1;
 
-       do  {
-               r_cnt = adf4350_tune_r_cnt(st, r_cnt);
+       chspc = st->chspc;
 
-               st->r1_mod = st->fpfd / st->chspc;
-               while (st->r1_mod > ADF4350_MAX_MODULUS) {
-                       r_cnt = adf4350_tune_r_cnt(st, r_cnt);
-                       st->r1_mod = st->fpfd / st->chspc;
-               }
+       do  {
+               do {
+                       do {
+                               r_cnt = adf4350_tune_r_cnt(st, r_cnt);
+                               st->r1_mod = st->fpfd / chspc;
+                               if (r_cnt > ADF4350_MAX_R_CNT) {
+                                       /* try higher spacing values */
+                                       chspc++;
+                                       r_cnt = 0;
+                               }
+                       } while ((st->r1_mod > ADF4350_MAX_MODULUS) && r_cnt);
+               } while (r_cnt == 0);
 
                tmp = freq * (u64)st->r1_mod + (st->fpfd > 1);
                do_div(tmp, st->fpfd); /* Div round closest (n + d/2)/d */
@@ -194,7 +200,7 @@ static int adf4350_set_freq(struct adf4350_state *st, unsigned long long freq)
        st->regs[ADF4350_REG0] = ADF4350_REG0_INT(st->r0_int) |
                                 ADF4350_REG0_FRACT(st->r0_fract);
 
-       st->regs[ADF4350_REG1] = ADF4350_REG1_PHASE(0) |
+       st->regs[ADF4350_REG1] = ADF4350_REG1_PHASE(1) |
                                 ADF4350_REG1_MOD(st->r1_mod) |
                                 prescaler;
 
index 1cbb449b319a8e9399af3b427342fb1702b1b173..9a99f43094f0824dde61203647462a8872faab83 100644 (file)
@@ -271,9 +271,10 @@ static int adjd_s311_update_scan_mode(struct iio_dev *indio_dev,
        const unsigned long *scan_mask)
 {
        struct adjd_s311_data *data = iio_priv(indio_dev);
-       data->buffer = krealloc(data->buffer, indio_dev->scan_bytes,
-                               GFP_KERNEL);
-       if (!data->buffer)
+
+       kfree(data->buffer);
+       data->buffer = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
+       if (data->buffer == NULL)
                return -ENOMEM;
 
        return 0;
index c3e7bac1312318470f29c805ca2ccdcfb6790402..e45712a921ce600cee7c10aa2d8a4dcbc46fccba 100644 (file)
@@ -404,7 +404,7 @@ out:
        return ret;
 }
 
-static int show_thresh_either_en(struct device *dev,
+static ssize_t show_thresh_either_en(struct device *dev,
                                        struct device_attribute *attr,
                                        char *buf)
 {
@@ -424,7 +424,7 @@ static int show_thresh_either_en(struct device *dev,
        return scnprintf(buf, PAGE_SIZE, "%u\n", enable);
 }
 
-static int store_thresh_either_en(struct device *dev,
+static ssize_t store_thresh_either_en(struct device *dev,
                                        struct device_attribute *attr,
                                        const char *buf, size_t len)
 {
index 28058ae33d38f0da431133e854302f6cbec0e2c6..eaec8d7a3b7372094cdabcb98c2277fd46bb93cf 100644 (file)
@@ -152,13 +152,11 @@ static void set_timeout(unsigned long time)
 {
        unsigned long delay;
 
-       cancel_delayed_work(&work);
-
        delay = time - jiffies;
        if ((long)delay <= 0)
                delay = 1;
 
-       queue_delayed_work(addr_wq, &work, delay);
+       mod_delayed_work(addr_wq, &work, delay);
 }
 
 static void queue_req(struct addr_req *req)
index 6bf8504228957eb8341342c16cfa9b88a234c8bd..055ed59838dca128eef4986a9b3186a1f0588b84 100644 (file)
@@ -267,6 +267,7 @@ static int ucma_event_handler(struct rdma_cm_id *cm_id,
        if (!uevent)
                return event->event == RDMA_CM_EVENT_CONNECT_REQUEST;
 
+       mutex_lock(&ctx->file->mut);
        uevent->cm_id = cm_id;
        ucma_set_event_context(ctx, event, uevent);
        uevent->resp.event = event->event;
@@ -277,7 +278,6 @@ static int ucma_event_handler(struct rdma_cm_id *cm_id,
                ucma_copy_conn_event(&uevent->resp.param.conn,
                                     &event->param.conn);
 
-       mutex_lock(&ctx->file->mut);
        if (event->event == RDMA_CM_EVENT_CONNECT_REQUEST) {
                if (!ctx->backlog) {
                        ret = -ENOMEM;
index 8c81992fa6db26275615d8f7f9e3998dd4223b7a..e4a73158fc7fc0392d9308146f2c695936b80532 100644 (file)
@@ -439,7 +439,7 @@ static int c2_rnic_close(struct c2_dev *c2dev)
 
 /*
  * Called by c2_probe to initialize the RNIC. This principally
- * involves initalizing the various limits and resouce pools that
+ * involves initializing the various limits and resource pools that
  * comprise the RNIC instance.
  */
 int __devinit c2_rnic_init(struct c2_dev *c2dev)
index 77b6b182778ad642b23bb9dc6a8f943cf83a6a10..aaf88ef9409cddfabef4fb90c88347e27887d464 100644 (file)
@@ -1680,7 +1680,7 @@ static int close_con_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
  * T3A does 3 things when a TERM is received:
  * 1) send up a CPL_RDMA_TERMINATE message with the TERM packet
  * 2) generate an async event on the QP with the TERMINATE opcode
- * 3) post a TERMINATE opcde cqe into the associated CQ.
+ * 3) post a TERMINATE opcode cqe into the associated CQ.
  *
  * For (1), we save the message in the qp for later consumer consumption.
  * For (2), we move the QP into TERMINATE, post a QP event and disconnect.
index c27141fef1ab2f6dca170bb07aecd11ecaa3d48b..9c2ae7efd00f4c03db74d67a4b5e8d84b0a87e28 100644 (file)
@@ -125,6 +125,7 @@ static void update_sm_ah(struct mlx4_ib_dev *dev, u8 port_num, u16 lid, u8 sl)
 {
        struct ib_ah *new_ah;
        struct ib_ah_attr ah_attr;
+       unsigned long flags;
 
        if (!dev->send_agent[port_num - 1][0])
                return;
@@ -139,11 +140,11 @@ static void update_sm_ah(struct mlx4_ib_dev *dev, u8 port_num, u16 lid, u8 sl)
        if (IS_ERR(new_ah))
                return;
 
-       spin_lock(&dev->sm_lock);
+       spin_lock_irqsave(&dev->sm_lock, flags);
        if (dev->sm_ah[port_num - 1])
                ib_destroy_ah(dev->sm_ah[port_num - 1]);
        dev->sm_ah[port_num - 1] = new_ah;
-       spin_unlock(&dev->sm_lock);
+       spin_unlock_irqrestore(&dev->sm_lock, flags);
 }
 
 /*
@@ -197,13 +198,15 @@ static void smp_snoop(struct ib_device *ibdev, u8 port_num, struct ib_mad *mad,
 static void node_desc_override(struct ib_device *dev,
                               struct ib_mad *mad)
 {
+       unsigned long flags;
+
        if ((mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED ||
             mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) &&
            mad->mad_hdr.method == IB_MGMT_METHOD_GET_RESP &&
            mad->mad_hdr.attr_id == IB_SMP_ATTR_NODE_DESC) {
-               spin_lock(&to_mdev(dev)->sm_lock);
+               spin_lock_irqsave(&to_mdev(dev)->sm_lock, flags);
                memcpy(((struct ib_smp *) mad)->data, dev->node_desc, 64);
-               spin_unlock(&to_mdev(dev)->sm_lock);
+               spin_unlock_irqrestore(&to_mdev(dev)->sm_lock, flags);
        }
 }
 
@@ -213,6 +216,7 @@ static void forward_trap(struct mlx4_ib_dev *dev, u8 port_num, struct ib_mad *ma
        struct ib_mad_send_buf *send_buf;
        struct ib_mad_agent *agent = dev->send_agent[port_num - 1][qpn];
        int ret;
+       unsigned long flags;
 
        if (agent) {
                send_buf = ib_create_send_mad(agent, qpn, 0, 0, IB_MGMT_MAD_HDR,
@@ -225,13 +229,13 @@ static void forward_trap(struct mlx4_ib_dev *dev, u8 port_num, struct ib_mad *ma
                 * wrong following the IB spec strictly, but we know
                 * it's OK for our devices).
                 */
-               spin_lock(&dev->sm_lock);
+               spin_lock_irqsave(&dev->sm_lock, flags);
                memcpy(send_buf->mad, mad, sizeof *mad);
                if ((send_buf->ah = dev->sm_ah[port_num - 1]))
                        ret = ib_post_send_mad(send_buf, NULL);
                else
                        ret = -EINVAL;
-               spin_unlock(&dev->sm_lock);
+               spin_unlock_irqrestore(&dev->sm_lock, flags);
 
                if (ret)
                        ib_free_send_mad(send_buf);
index fe2088cfa6eef699f0222b710aeb3de930c1c139..cc05579ebce7fd6b5f5fc9c86b2a1452db0101a7 100644 (file)
@@ -423,6 +423,7 @@ static int mlx4_ib_modify_device(struct ib_device *ibdev, int mask,
                                 struct ib_device_modify *props)
 {
        struct mlx4_cmd_mailbox *mailbox;
+       unsigned long flags;
 
        if (mask & ~IB_DEVICE_MODIFY_NODE_DESC)
                return -EOPNOTSUPP;
@@ -430,9 +431,9 @@ static int mlx4_ib_modify_device(struct ib_device *ibdev, int mask,
        if (!(mask & IB_DEVICE_MODIFY_NODE_DESC))
                return 0;
 
-       spin_lock(&to_mdev(ibdev)->sm_lock);
+       spin_lock_irqsave(&to_mdev(ibdev)->sm_lock, flags);
        memcpy(ibdev->node_desc, props->node_desc, 64);
-       spin_unlock(&to_mdev(ibdev)->sm_lock);
+       spin_unlock_irqrestore(&to_mdev(ibdev)->sm_lock, flags);
 
        /*
         * If possible, pass node desc to FW, so it can generate
index a6d8ea060ea896ad4f7c7d9a8639a8be8f67fb4e..f585eddef4b7d5c7921575cebaa508eefde4f934 100644 (file)
@@ -1407,6 +1407,7 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
        struct mlx4_wqe_mlx_seg *mlx = wqe;
        struct mlx4_wqe_inline_seg *inl = wqe + sizeof *mlx;
        struct mlx4_ib_ah *ah = to_mah(wr->wr.ud.ah);
+       struct net_device *ndev;
        union ib_gid sgid;
        u16 pkey;
        int send_size;
@@ -1483,7 +1484,10 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr,
 
                memcpy(sqp->ud_header.eth.dmac_h, ah->av.eth.mac, 6);
                /* FIXME: cache smac value? */
-               smac = to_mdev(sqp->qp.ibqp.device)->iboe.netdevs[sqp->qp.port - 1]->dev_addr;
+               ndev = to_mdev(sqp->qp.ibqp.device)->iboe.netdevs[sqp->qp.port - 1];
+               if (!ndev)
+                       return -ENODEV;
+               smac = ndev->dev_addr;
                memcpy(sqp->ud_header.eth.smac_h, smac, 6);
                if (!memcmp(sqp->ud_header.eth.smac_h, sqp->ud_header.eth.dmac_h, 6))
                        mlx->flags |= cpu_to_be32(MLX4_WQE_CTRL_FORCE_LOOPBACK);
index d42c9f435b1b7a62ad55a331c1f6bc76c84fdbab..9e0895b45eb86822ae3df65bdbf3be24a0be29ea 100644 (file)
@@ -2679,11 +2679,9 @@ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)
                        }
                }
                if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_SFP_D) {
-                       if (nesdev->link_recheck)
-                               cancel_delayed_work(&nesdev->work);
                        nesdev->link_recheck = 1;
-                       schedule_delayed_work(&nesdev->work,
-                                             NES_LINK_RECHECK_DELAY);
+                       mod_delayed_work(system_wq, &nesdev->work,
+                                        NES_LINK_RECHECK_DELAY);
                }
        }
 
index f3a3ecf8d09ebfbff9bcc37b1a4beac97d60ebeb..e43f6e41a6bdfa2542f02f27fdcbae7b69771391 100644 (file)
@@ -243,10 +243,9 @@ static int nes_netdev_open(struct net_device *netdev)
 
        spin_lock_irqsave(&nesdev->nesadapter->phy_lock, flags);
        if (nesdev->nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_SFP_D) {
-               if (nesdev->link_recheck)
-                       cancel_delayed_work(&nesdev->work);
                nesdev->link_recheck = 1;
-               schedule_delayed_work(&nesdev->work, NES_LINK_RECHECK_DELAY);
+               mod_delayed_work(system_wq, &nesdev->work,
+                                NES_LINK_RECHECK_DELAY);
        }
        spin_unlock_irqrestore(&nesdev->nesadapter->phy_lock, flags);
 
index 5a044526e4f4c379bf52e05f9b15c00953453df7..c4e0131f1b578fec8fa62d029ff380b3d976b13b 100644 (file)
@@ -161,7 +161,7 @@ static void ocrdma_add_default_sgid(struct ocrdma_dev *dev)
        ocrdma_get_guid(dev, &sgid->raw[8]);
 }
 
-#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
+#if IS_ENABLED(CONFIG_VLAN_8021Q)
 static void ocrdma_add_vlan_sgids(struct ocrdma_dev *dev)
 {
        struct net_device *netdev, *tmp;
@@ -202,14 +202,13 @@ static int ocrdma_build_sgid_tbl(struct ocrdma_dev *dev)
        return 0;
 }
 
-#if IS_ENABLED(CONFIG_IPV6) || IS_ENABLED(CONFIG_VLAN_8021Q)
+#if IS_ENABLED(CONFIG_IPV6)
 
 static int ocrdma_inet6addr_event(struct notifier_block *notifier,
                                  unsigned long event, void *ptr)
 {
        struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr;
-       struct net_device *event_netdev = ifa->idev->dev;
-       struct net_device *netdev = NULL;
+       struct net_device *netdev = ifa->idev->dev;
        struct ib_event gid_event;
        struct ocrdma_dev *dev;
        bool found = false;
@@ -217,11 +216,12 @@ static int ocrdma_inet6addr_event(struct notifier_block *notifier,
        bool is_vlan = false;
        u16 vid = 0;
 
-       netdev = vlan_dev_real_dev(event_netdev);
-       if (netdev != event_netdev) {
-               is_vlan = true;
-               vid = vlan_dev_vlan_id(event_netdev);
+       is_vlan = netdev->priv_flags & IFF_802_1Q_VLAN;
+       if (is_vlan) {
+               vid = vlan_dev_vlan_id(netdev);
+               netdev = vlan_dev_real_dev(netdev);
        }
+
        rcu_read_lock();
        list_for_each_entry_rcu(dev, &ocrdma_dev_list, entry) {
                if (dev->nic_info.netdev == netdev) {
index 0d7280af99bc81084d1977d5bfe8480450c85c77..3f6b21e9dc110513c0522b099adcfa0f131ef6b4 100644 (file)
@@ -6346,8 +6346,10 @@ static int qib_init_7322_variables(struct qib_devdata *dd)
                        dd->piobcnt4k * dd->align4k;
                dd->piovl15base = ioremap_nocache(vl15off,
                                                  NUM_VL15_BUFS * dd->align4k);
-               if (!dd->piovl15base)
+               if (!dd->piovl15base) {
+                       ret = -ENOMEM;
                        goto bail;
+               }
        }
        qib_7322_set_baseaddrs(dd); /* set chip access pointers now */
 
index a322d5171a2c793d0ec3cb5e08632a0264fd2ab5..50a8a0d4fe676f5467c677d66a4985170900059d 100644 (file)
@@ -372,7 +372,7 @@ static void qib_sd_trimdone_monitor(struct qib_devdata *dd,
                /* Read CTRL reg for each channel to check TRIMDONE */
                if (baduns & (1 << chn)) {
                        qib_dev_err(dd,
-                               "Reseting TRIMDONE on chn %d (%s)\n",
+                               "Resetting TRIMDONE on chn %d (%s)\n",
                                chn, where);
                        ret = qib_sd7220_reg_mod(dd, IB_7220_SERDES,
                                IB_CTRL2(chn), 0x10, 0x10);
index 95ecf4eadf5f75949f6a7e14acfa01a50fbdc0cd..24683fda8e21cdbaca2973cc69454013a2bbb995 100644 (file)
@@ -1271,12 +1271,15 @@ struct ipoib_cm_tx *ipoib_cm_create_tx(struct net_device *dev, struct ipoib_path
 void ipoib_cm_destroy_tx(struct ipoib_cm_tx *tx)
 {
        struct ipoib_dev_priv *priv = netdev_priv(tx->dev);
+       unsigned long flags;
        if (test_and_clear_bit(IPOIB_FLAG_INITIALIZED, &tx->flags)) {
+               spin_lock_irqsave(&priv->lock, flags);
                list_move(&tx->list, &priv->cm.reap_list);
                queue_work(ipoib_workqueue, &priv->cm.reap_task);
                ipoib_dbg(priv, "Reap connection for gid %pI6\n",
                          tx->neigh->daddr + 4);
                tx->neigh = NULL;
+               spin_unlock_irqrestore(&priv->lock, flags);
        }
 }
 
index 97920b77a5d0abe2f378ed060aa8243a2c5c33e7..3e2085a3ee474fc0111c7034ca013bfda7d63d7e 100644 (file)
@@ -1052,7 +1052,7 @@ void ipoib_neigh_free(struct ipoib_neigh *neigh)
        for (n = rcu_dereference_protected(*np,
                                            lockdep_is_held(&ntbl->rwlock));
             n != NULL;
-            n = rcu_dereference_protected(neigh->hnext,
+            n = rcu_dereference_protected(*np,
                                        lockdep_is_held(&ntbl->rwlock))) {
                if (n == neigh) {
                        /* found */
index bcbf22ee0aa77d3b99ae3fcceabd3ebce1302ee9..1b5b0c7300549cefee683b3d5745b39a446b5bca 100644 (file)
@@ -586,24 +586,62 @@ static void srp_unmap_data(struct scsi_cmnd *scmnd,
                        scmnd->sc_data_direction);
 }
 
-static void srp_remove_req(struct srp_target_port *target,
-                          struct srp_request *req, s32 req_lim_delta)
+/**
+ * srp_claim_req - Take ownership of the scmnd associated with a request.
+ * @target: SRP target port.
+ * @req: SRP request.
+ * @scmnd: If NULL, take ownership of @req->scmnd. If not NULL, only take
+ *         ownership of @req->scmnd if it equals @scmnd.
+ *
+ * Return value:
+ * Either NULL or a pointer to the SCSI command the caller became owner of.
+ */
+static struct scsi_cmnd *srp_claim_req(struct srp_target_port *target,
+                                      struct srp_request *req,
+                                      struct scsi_cmnd *scmnd)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&target->lock, flags);
+       if (!scmnd) {
+               scmnd = req->scmnd;
+               req->scmnd = NULL;
+       } else if (req->scmnd == scmnd) {
+               req->scmnd = NULL;
+       } else {
+               scmnd = NULL;
+       }
+       spin_unlock_irqrestore(&target->lock, flags);
+
+       return scmnd;
+}
+
+/**
+ * srp_free_req() - Unmap data and add request to the free request list.
+ */
+static void srp_free_req(struct srp_target_port *target,
+                        struct srp_request *req, struct scsi_cmnd *scmnd,
+                        s32 req_lim_delta)
 {
        unsigned long flags;
 
-       srp_unmap_data(req->scmnd, target, req);
+       srp_unmap_data(scmnd, target, req);
+
        spin_lock_irqsave(&target->lock, flags);
        target->req_lim += req_lim_delta;
-       req->scmnd = NULL;
        list_add_tail(&req->list, &target->free_reqs);
        spin_unlock_irqrestore(&target->lock, flags);
 }
 
 static void srp_reset_req(struct srp_target_port *target, struct srp_request *req)
 {
-       req->scmnd->result = DID_RESET << 16;
-       req->scmnd->scsi_done(req->scmnd);
-       srp_remove_req(target, req, 0);
+       struct scsi_cmnd *scmnd = srp_claim_req(target, req, NULL);
+
+       if (scmnd) {
+               scmnd->result = DID_RESET << 16;
+               scmnd->scsi_done(scmnd);
+               srp_free_req(target, req, scmnd, 0);
+       }
 }
 
 static int srp_reconnect_target(struct srp_target_port *target)
@@ -1073,11 +1111,18 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp)
                complete(&target->tsk_mgmt_done);
        } else {
                req = &target->req_ring[rsp->tag];
-               scmnd = req->scmnd;
-               if (!scmnd)
+               scmnd = srp_claim_req(target, req, NULL);
+               if (!scmnd) {
                        shost_printk(KERN_ERR, target->scsi_host,
                                     "Null scmnd for RSP w/tag %016llx\n",
                                     (unsigned long long) rsp->tag);
+
+                       spin_lock_irqsave(&target->lock, flags);
+                       target->req_lim += be32_to_cpu(rsp->req_lim_delta);
+                       spin_unlock_irqrestore(&target->lock, flags);
+
+                       return;
+               }
                scmnd->result = rsp->status;
 
                if (rsp->flags & SRP_RSP_FLAG_SNSVALID) {
@@ -1092,7 +1137,9 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp)
                else if (rsp->flags & (SRP_RSP_FLAG_DIOVER | SRP_RSP_FLAG_DIUNDER))
                        scsi_set_resid(scmnd, be32_to_cpu(rsp->data_in_res_cnt));
 
-               srp_remove_req(target, req, be32_to_cpu(rsp->req_lim_delta));
+               srp_free_req(target, req, scmnd,
+                            be32_to_cpu(rsp->req_lim_delta));
+
                scmnd->host_scribble = NULL;
                scmnd->scsi_done(scmnd);
        }
@@ -1631,25 +1678,17 @@ static int srp_abort(struct scsi_cmnd *scmnd)
 {
        struct srp_target_port *target = host_to_target(scmnd->device->host);
        struct srp_request *req = (struct srp_request *) scmnd->host_scribble;
-       int ret = SUCCESS;
 
        shost_printk(KERN_ERR, target->scsi_host, "SRP abort called\n");
 
-       if (!req || target->qp_in_error)
+       if (!req || target->qp_in_error || !srp_claim_req(target, req, scmnd))
                return FAILED;
-       if (srp_send_tsk_mgmt(target, req->index, scmnd->device->lun,
-                             SRP_TSK_ABORT_TASK))
-               return FAILED;
-
-       if (req->scmnd) {
-               if (!target->tsk_mgmt_status) {
-                       srp_remove_req(target, req, 0);
-                       scmnd->result = DID_ABORT << 16;
-               } else
-                       ret = FAILED;
-       }
+       srp_send_tsk_mgmt(target, req->index, scmnd->device->lun,
+                         SRP_TSK_ABORT_TASK);
+       srp_free_req(target, req, scmnd, 0);
+       scmnd->result = DID_ABORT << 16;
 
-       return ret;
+       return SUCCESS;
 }
 
 static int srp_reset_device(struct scsi_cmnd *scmnd)
index 7a0ce8d42887e225e81d20702892d8ed0d056f39..9e1449f8c6a26ea62349352de3f8178db2faa6fe 100644 (file)
@@ -1469,7 +1469,7 @@ static void srpt_handle_send_comp(struct srpt_rdma_ch *ch,
  *
  * XXX: what is now target_execute_cmd used to be asynchronous, and unmapping
  * the data that has been transferred via IB RDMA had to be postponed until the
- * check_stop_free() callback.  None of this is nessecary anymore and needs to
+ * check_stop_free() callback.  None of this is necessary anymore and needs to
  * be cleaned up.
  */
 static void srpt_handle_rdma_comp(struct srpt_rdma_ch *ch,
index e90ee3d306132aa91348485110ee8ac3fd119665..650177a3c858ba13159bbed2dbc9148c66370ec3 100644 (file)
@@ -33,7 +33,7 @@ static void system_power_event(unsigned int keycode)
 }
 
 static void apmpower_event(struct input_handle *handle, unsigned int type,
-                       unsigned int code, int value)
+                          unsigned int code, int value)
 {
        /* only react on key down events */
        if (value != 1)
index 480eb9d9876a57a79f4b7b5c599aa38db909faea..f50f6dd92274c3d25f686c02e5f710d71a9f4102 100644 (file)
@@ -138,8 +138,8 @@ int input_ff_upload(struct input_dev *dev, struct ff_effect *effect,
 
        if (effect->id == -1) {
                for (id = 0; id < ff->max_effects; id++)
-                    if (!ff->effect_owners[id])
-                       break;
+                       if (!ff->effect_owners[id])
+                               break;
 
                if (id >= ff->max_effects) {
                        ret = -ENOSPC;
index b107922514fb378a89e8951d985a0e89d5ed481d..74c0d8c6002aca6f74957c7f3a596f63e550199c 100644 (file)
@@ -72,12 +72,14 @@ static const struct ff_envelope *get_envelope(const struct ff_effect *effect)
        static const struct ff_envelope empty_envelope;
 
        switch (effect->type) {
-               case FF_PERIODIC:
-                       return &effect->u.periodic.envelope;
-               case FF_CONSTANT:
-                       return &effect->u.constant.envelope;
-               default:
-                       return &empty_envelope;
+       case FF_PERIODIC:
+               return &effect->u.periodic.envelope;
+
+       case FF_CONSTANT:
+               return &effect->u.constant.envelope;
+
+       default:
+               return &empty_envelope;
        }
 }
 
index 26043cc6a0165f80a36e7ee31436cc128a318de1..78f323ea1e4bff2821dcd8cd73bedf90ede73cbc 100644 (file)
@@ -711,7 +711,7 @@ static long joydev_ioctl(struct file *file,
 
        case JS_SET_ALL:
                retval = copy_from_user(&joydev->glue, argp,
-                                       sizeof(joydev->glue)) ? -EFAULT: 0;
+                                       sizeof(joydev->glue)) ? -EFAULT : 0;
                break;
 
        case JS_GET_ALL:
index cbb1add43d5e0b78e64d286a584abb3e799c6540..6ee68ec428a3899d51f58600e8e692a96324bc17 100644 (file)
@@ -43,11 +43,9 @@ struct gpio_button_data {
 };
 
 struct gpio_keys_drvdata {
+       const struct gpio_keys_platform_data *pdata;
        struct input_dev *input;
        struct mutex disable_lock;
-       unsigned int n_buttons;
-       int (*enable)(struct device *dev);
-       void (*disable)(struct device *dev);
        struct gpio_button_data data[0];
 };
 
@@ -171,7 +169,7 @@ static ssize_t gpio_keys_attr_show_helper(struct gpio_keys_drvdata *ddata,
        if (!bits)
                return -ENOMEM;
 
-       for (i = 0; i < ddata->n_buttons; i++) {
+       for (i = 0; i < ddata->pdata->nbuttons; i++) {
                struct gpio_button_data *bdata = &ddata->data[i];
 
                if (bdata->button->type != type)
@@ -219,7 +217,7 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
                goto out;
 
        /* First validate */
-       for (i = 0; i < ddata->n_buttons; i++) {
+       for (i = 0; i < ddata->pdata->nbuttons; i++) {
                struct gpio_button_data *bdata = &ddata->data[i];
 
                if (bdata->button->type != type)
@@ -234,7 +232,7 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
 
        mutex_lock(&ddata->disable_lock);
 
-       for (i = 0; i < ddata->n_buttons; i++) {
+       for (i = 0; i < ddata->pdata->nbuttons; i++) {
                struct gpio_button_data *bdata = &ddata->data[i];
 
                if (bdata->button->type != type)
@@ -346,6 +344,9 @@ static void gpio_keys_gpio_work_func(struct work_struct *work)
                container_of(work, struct gpio_button_data, work);
 
        gpio_keys_gpio_report_event(bdata);
+
+       if (bdata->button->wakeup)
+               pm_relax(bdata->input->dev.parent);
 }
 
 static void gpio_keys_gpio_timer(unsigned long _data)
@@ -361,6 +362,8 @@ static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id)
 
        BUG_ON(irq != bdata->irq);
 
+       if (bdata->button->wakeup)
+               pm_stay_awake(bdata->input->dev.parent);
        if (bdata->timer_debounce)
                mod_timer(&bdata->timer,
                        jiffies + msecs_to_jiffies(bdata->timer_debounce));
@@ -397,6 +400,9 @@ static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id)
        spin_lock_irqsave(&bdata->lock, flags);
 
        if (!bdata->key_pressed) {
+               if (bdata->button->wakeup)
+                       pm_wakeup_event(bdata->input->dev.parent, 0);
+
                input_event(input, EV_KEY, button->code, 1);
                input_sync(input);
 
@@ -523,56 +529,61 @@ fail:
 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;
 
-       return ddata->enable ? ddata->enable(input->dev.parent) : 0;
+       return pdata->enable ? pdata->enable(input->dev.parent) : 0;
 }
 
 static void gpio_keys_close(struct input_dev *input)
 {
        struct gpio_keys_drvdata *ddata = input_get_drvdata(input);
+       const struct gpio_keys_platform_data *pdata = ddata->pdata;
 
-       if (ddata->disable)
-               ddata->disable(input->dev.parent);
+       if (pdata->disable)
+               pdata->disable(input->dev.parent);
 }
 
 /*
  * Handlers for alternative sources of platform_data
  */
+
 #ifdef CONFIG_OF
 /*
  * Translate OpenFirmware node properties into platform_data
  */
-static int gpio_keys_get_devtree_pdata(struct device *dev,
-                           struct gpio_keys_platform_data *pdata)
+static struct gpio_keys_platform_data * __devinit
+gpio_keys_get_devtree_pdata(struct device *dev)
 {
        struct device_node *node, *pp;
+       struct gpio_keys_platform_data *pdata;
+       struct gpio_keys_button *button;
+       int error;
+       int nbuttons;
        int i;
-       struct gpio_keys_button *buttons;
-       u32 reg;
 
        node = dev->of_node;
-       if (node == NULL)
-               return -ENODEV;
-
-       memset(pdata, 0, sizeof *pdata);
-
-       pdata->rep = !!of_get_property(node, "autorepeat", NULL);
+       if (!node) {
+               error = -ENODEV;
+               goto err_out;
+       }
 
-       /* First count the subnodes */
-       pp = NULL;
-       while ((pp = of_get_next_child(node, pp)))
-               pdata->nbuttons++;
+       nbuttons = of_get_child_count(node);
+       if (nbuttons == 0) {
+               error = -ENODEV;
+               goto err_out;
+       }
 
-       if (pdata->nbuttons == 0)
-               return -ENODEV;
+       pdata = kzalloc(sizeof(*pdata) + nbuttons * (sizeof *button),
+                       GFP_KERNEL);
+       if (!pdata) {
+               error = -ENOMEM;
+               goto err_out;
+       }
 
-       buttons = kzalloc(pdata->nbuttons * (sizeof *buttons), GFP_KERNEL);
-       if (!buttons)
-               return -ENOMEM;
+       pdata->rep = !!of_get_property(node, "autorepeat", NULL);
 
-       pp = NULL;
        i = 0;
-       while ((pp = of_get_next_child(node, pp))) {
+       for_each_child_of_node(node, pp) {
                enum of_gpio_flags flags;
 
                if (!of_find_property(pp, "gpios", NULL)) {
@@ -580,39 +591,42 @@ static int gpio_keys_get_devtree_pdata(struct device *dev,
                        dev_warn(dev, "Found button without gpios\n");
                        continue;
                }
-               buttons[i].gpio = of_get_gpio_flags(pp, 0, &flags);
-               buttons[i].active_low = flags & OF_GPIO_ACTIVE_LOW;
 
-               if (of_property_read_u32(pp, "linux,code", &reg)) {
-                       dev_err(dev, "Button without keycode: 0x%x\n", buttons[i].gpio);
-                       goto out_fail;
-               }
-               buttons[i].code = reg;
+               button = &pdata->buttons[i++];
 
-               buttons[i].desc = of_get_property(pp, "label", NULL);
+               button->gpio = of_get_gpio_flags(pp, 0, &flags);
+               button->active_low = flags & OF_GPIO_ACTIVE_LOW;
 
-               if (of_property_read_u32(pp, "linux,input-type", &reg) == 0)
-                       buttons[i].type = reg;
-               else
-                       buttons[i].type = EV_KEY;
+               if (of_property_read_u32(pp, "linux,code", &button->code)) {
+                       dev_err(dev, "Button without keycode: 0x%x\n",
+                               button->gpio);
+                       error = -EINVAL;
+                       goto err_free_pdata;
+               }
 
-               buttons[i].wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL);
+               button->desc = of_get_property(pp, "label", NULL);
 
-               if (of_property_read_u32(pp, "debounce-interval", &reg) == 0)
-                       buttons[i].debounce_interval = reg;
-               else
-                       buttons[i].debounce_interval = 5;
+               if (of_property_read_u32(pp, "linux,input-type", &button->type))
+                       button->type = EV_KEY;
 
-               i++;
+               button->wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL);
+
+               if (of_property_read_u32(pp, "debounce-interval",
+                                        &button->debounce_interval))
+                       button->debounce_interval = 5;
        }
 
-       pdata->buttons = buttons;
+       if (pdata->nbuttons == 0) {
+               error = -EINVAL;
+               goto err_free_pdata;
+       }
 
-       return 0;
+       return pdata;
 
-out_fail:
-       kfree(buttons);
-       return -ENODEV;
+err_free_pdata:
+       kfree(pdata);
+err_out:
+       return ERR_PTR(error);
 }
 
 static struct of_device_id gpio_keys_of_match[] = {
@@ -623,14 +637,12 @@ MODULE_DEVICE_TABLE(of, gpio_keys_of_match);
 
 #else
 
-static int gpio_keys_get_devtree_pdata(struct device *dev,
-                           struct gpio_keys_platform_data *altp)
+static inline struct gpio_keys_platform_data *
+gpio_keys_get_devtree_pdata(struct device *dev)
 {
-       return -ENODEV;
+       return ERR_PTR(-ENODEV);
 }
 
-#define gpio_keys_of_match NULL
-
 #endif
 
 static void gpio_remove_key(struct gpio_button_data *bdata)
@@ -645,19 +657,17 @@ static void gpio_remove_key(struct gpio_button_data *bdata)
 
 static int __devinit gpio_keys_probe(struct platform_device *pdev)
 {
-       const struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
-       struct gpio_keys_drvdata *ddata;
        struct device *dev = &pdev->dev;
-       struct gpio_keys_platform_data alt_pdata;
+       const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev);
+       struct gpio_keys_drvdata *ddata;
        struct input_dev *input;
        int i, error;
        int wakeup = 0;
 
        if (!pdata) {
-               error = gpio_keys_get_devtree_pdata(dev, &alt_pdata);
-               if (error)
-                       return error;
-               pdata = &alt_pdata;
+               pdata = gpio_keys_get_devtree_pdata(dev);
+               if (IS_ERR(pdata))
+                       return PTR_ERR(pdata);
        }
 
        ddata = kzalloc(sizeof(struct gpio_keys_drvdata) +
@@ -670,10 +680,8 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
                goto fail1;
        }
 
+       ddata->pdata = pdata;
        ddata->input = input;
-       ddata->n_buttons = pdata->nbuttons;
-       ddata->enable = pdata->enable;
-       ddata->disable = pdata->disable;
        mutex_init(&ddata->disable_lock);
 
        platform_set_drvdata(pdev, ddata);
@@ -742,9 +750,9 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
  fail1:
        input_free_device(input);
        kfree(ddata);
-       /* If we have no platform_data, we allocated buttons dynamically. */
-       if (!pdev->dev.platform_data)
-               kfree(pdata->buttons);
+       /* If we have no platform data, we allocated pdata dynamically. */
+       if (!dev_get_platdata(&pdev->dev))
+               kfree(pdata);
 
        return error;
 }
@@ -759,18 +767,14 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
 
        device_init_wakeup(&pdev->dev, 0);
 
-       for (i = 0; i < ddata->n_buttons; i++)
+       for (i = 0; i < ddata->pdata->nbuttons; i++)
                gpio_remove_key(&ddata->data[i]);
 
        input_unregister_device(input);
 
-       /*
-        * If we had no platform_data, we allocated buttons dynamically, and
-        * must free them here. ddata->data[0].button is the pointer to the
-        * beginning of the allocated array.
-        */
-       if (!pdev->dev.platform_data)
-               kfree(ddata->data[0].button);
+       /* If we have no platform data, we allocated pdata dynamically. */
+       if (!dev_get_platdata(&pdev->dev))
+               kfree(ddata->pdata);
 
        kfree(ddata);
 
@@ -784,7 +788,7 @@ static int gpio_keys_suspend(struct device *dev)
        int i;
 
        if (device_may_wakeup(dev)) {
-               for (i = 0; i < ddata->n_buttons; i++) {
+               for (i = 0; i < ddata->pdata->nbuttons; i++) {
                        struct gpio_button_data *bdata = &ddata->data[i];
                        if (bdata->button->wakeup)
                                enable_irq_wake(bdata->irq);
@@ -799,7 +803,7 @@ static int gpio_keys_resume(struct device *dev)
        struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
        int i;
 
-       for (i = 0; i < ddata->n_buttons; 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);
@@ -822,7 +826,7 @@ static struct platform_driver gpio_keys_device_driver = {
                .name   = "gpio-keys",
                .owner  = THIS_MODULE,
                .pm     = &gpio_keys_pm_ops,
-               .of_match_table = gpio_keys_of_match,
+               .of_match_table = of_match_ptr(gpio_keys_of_match),
        }
 };
 
index 38e4b507b94cc629ef330cf173b1b41d3765e904..b3dd96d6448b324569bdf8dc64b2af6a50e40d58 100644 (file)
@@ -42,6 +42,7 @@ static irqreturn_t powerbutton_irq(int irq, void *_pwr)
        err = twl_i2c_read_u8(TWL4030_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);
                input_sync(pwr);
        } else {
index 0110b5a3a1678a7a0843672b8505e6f42c664fc1..964e43d81e29d9224a3261a0666f84dd500100c6 100644 (file)
@@ -551,17 +551,16 @@ static int mousedev_open(struct inode *inode, struct file *file)
                return -ENODEV;
 
        error = mutex_lock_interruptible(&mousedev_table_mutex);
-       if (error) {
+       if (error)
                return error;
-       }
+
        mousedev = mousedev_table[i];
        if (mousedev)
                get_device(&mousedev->dev);
        mutex_unlock(&mousedev_table_mutex);
 
-       if (!mousedev) {
+       if (!mousedev)
                return -ENODEV;
-       }
 
        client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL);
        if (!client) {
@@ -1088,7 +1087,7 @@ static int __init mousedev_init(void)
 #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
        error = misc_register(&psaux_mouse);
        if (error)
-               pr_warning("could not register psaux device, error: %d\n",
+               pr_warn("could not register psaux device, error: %d\n",
                           error);
        else
                psaux_registered = 1;
index 75fb040a3435c246b2077e96b5730f3d7030586b..a70aa555bbffe34d38d1e6f1378b697b9ee8665e 100644 (file)
@@ -180,11 +180,11 @@ int sparse_keymap_setup(struct input_dev *dev,
        for (e = keymap; e->type != KE_END; e++)
                map_size++;
 
-       map = kcalloc(map_size, sizeof (struct key_entry), GFP_KERNEL);
+       map = kcalloc(map_size, sizeof(struct key_entry), GFP_KERNEL);
        if (!map)
                return -ENOMEM;
 
-       memcpy(map, keymap, map_size * sizeof (struct key_entry));
+       memcpy(map, keymap, map_size * sizeof(struct key_entry));
 
        for (i = 0; i < map_size; i++) {
                entry = &map[i];
index 503c7096ed36263aac57c0165e846cb2d46fae49..908407efc672be69bcc0a13c5603b38b45d50440 100644 (file)
@@ -48,7 +48,7 @@ struct eeti_ts_priv {
        struct input_dev *input;
        struct work_struct work;
        struct mutex mutex;
-       int irq, irq_active_high;
+       int irq_gpio, irq, irq_active_high;
 };
 
 #define EETI_TS_BITDEPTH       (11)
@@ -62,7 +62,7 @@ struct eeti_ts_priv {
 
 static inline int eeti_ts_irq_active(struct eeti_ts_priv *priv)
 {
-       return gpio_get_value(irq_to_gpio(priv->irq)) == priv->irq_active_high;
+       return gpio_get_value(priv->irq_gpio) == priv->irq_active_high;
 }
 
 static void eeti_ts_read(struct work_struct *work)
@@ -157,7 +157,7 @@ static void eeti_ts_close(struct input_dev *dev)
 static int __devinit eeti_ts_probe(struct i2c_client *client,
                                   const struct i2c_device_id *idp)
 {
-       struct eeti_ts_platform_data *pdata;
+       struct eeti_ts_platform_data *pdata = client->dev.platform_data;
        struct eeti_ts_priv *priv;
        struct input_dev *input;
        unsigned int irq_flags;
@@ -199,9 +199,12 @@ static int __devinit eeti_ts_probe(struct i2c_client *client,
 
        priv->client = client;
        priv->input = input;
-       priv->irq = client->irq;
+       priv->irq_gpio = pdata->irq_gpio;
+       priv->irq = gpio_to_irq(pdata->irq_gpio);
 
-       pdata = client->dev.platform_data;
+       err = gpio_request_one(pdata->irq_gpio, GPIOF_IN, client->name);
+       if (err < 0)
+               goto err1;
 
        if (pdata)
                priv->irq_active_high = pdata->irq_active_high;
@@ -215,13 +218,13 @@ static int __devinit eeti_ts_probe(struct i2c_client *client,
 
        err = input_register_device(input);
        if (err)
-               goto err1;
+               goto err2;
 
        err = request_irq(priv->irq, eeti_ts_isr, irq_flags,
                          client->name, priv);
        if (err) {
                dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
-               goto err2;
+               goto err3;
        }
 
        /*
@@ -233,9 +236,11 @@ static int __devinit eeti_ts_probe(struct i2c_client *client,
        device_init_wakeup(&client->dev, 0);
        return 0;
 
-err2:
+err3:
        input_unregister_device(input);
        input = NULL; /* so we dont try to free it below */
+err2:
+       gpio_free(pdata->irq_gpio);
 err1:
        input_free_device(input);
        kfree(priv);
index 6d1cbdfc9b2a1af4a583460e8c4a5e5c80aabdfc..b64502dfa9f4567ca028bcb9b7913d4b38696019 100644 (file)
@@ -296,8 +296,13 @@ static int iommu_init_device(struct device *dev)
        } else
                dma_pdev = pci_dev_get(pdev);
 
+       /* Account for quirked devices */
        swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev));
 
+       /*
+        * If it's a multifunction device that does not support our
+        * required ACS flags, add to the same group as function 0.
+        */
        if (dma_pdev->multifunction &&
            !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS))
                swap_pci_ref(&dma_pdev,
@@ -305,14 +310,28 @@ static int iommu_init_device(struct device *dev)
                                          PCI_DEVFN(PCI_SLOT(dma_pdev->devfn),
                                          0)));
 
+       /*
+        * Devices on the root bus go through the iommu.  If that's not us,
+        * find the next upstream device and test ACS up to the root bus.
+        * Finding the next device may require skipping virtual buses.
+        */
        while (!pci_is_root_bus(dma_pdev->bus)) {
-               if (pci_acs_path_enabled(dma_pdev->bus->self,
-                                        NULL, REQ_ACS_FLAGS))
+               struct pci_bus *bus = dma_pdev->bus;
+
+               while (!bus->self) {
+                       if (!pci_is_root_bus(bus))
+                               bus = bus->parent;
+                       else
+                               goto root_bus;
+               }
+
+               if (pci_acs_path_enabled(bus->self, NULL, REQ_ACS_FLAGS))
                        break;
 
-               swap_pci_ref(&dma_pdev, pci_dev_get(dma_pdev->bus->self));
+               swap_pci_ref(&dma_pdev, pci_dev_get(bus->self));
        }
 
+root_bus:
        group = iommu_group_get(&dma_pdev->dev);
        pci_dev_put(dma_pdev);
        if (!group) {
index 500e7f15f5c266043d5d2bdc27a04f489595be79..18a89b760aaa3d78940021f0637e7f090116bb23 100644 (file)
@@ -1111,7 +1111,7 @@ static void print_iommu_info(void)
 
                if (iommu->cap & (1 << IOMMU_CAP_EFR)) {
                        pr_info("AMD-Vi:  Extended features: ");
-                       for (i = 0; ARRAY_SIZE(feat_str); ++i) {
+                       for (i = 0; i < ARRAY_SIZE(feat_str); ++i) {
                                if (iommu_feature(iommu, (1ULL << i)))
                                        pr_cont(" %s", feat_str[i]);
                        }
@@ -1131,9 +1131,6 @@ static int __init amd_iommu_init_pci(void)
                        break;
        }
 
-       /* Make sure ACS will be enabled */
-       pci_request_acs();
-
        ret = amd_iommu_init_devices();
 
        print_iommu_info();
@@ -1652,6 +1649,9 @@ static bool detect_ivrs(void)
 
        early_acpi_os_unmap_memory((char __iomem *)ivrs_base, ivrs_size);
 
+       /* Make sure ACS will be enabled during PCI probe */
+       pci_request_acs();
+
        return true;
 }
 
index 45350ff5e93c9cbe58c1f73c49e932c5f57eb376..80bad32aa46394443ad5a0aaa4a241c4e0e4b2c0 100644 (file)
@@ -732,9 +732,9 @@ static int exynos_iommu_domain_init(struct iommu_domain *domain)
        spin_lock_init(&priv->pgtablelock);
        INIT_LIST_HEAD(&priv->clients);
 
-       dom->geometry.aperture_start = 0;
-       dom->geometry.aperture_end   = ~0UL;
-       dom->geometry.force_aperture = true;
+       domain->geometry.aperture_start = 0;
+       domain->geometry.aperture_end   = ~0UL;
+       domain->geometry.force_aperture = true;
 
        domain->priv = priv;
        return 0;
index 7469b5346643595fe1788b04d76135ed30075cfd..2297ec193eb4b645812c85519c335361e935f296 100644 (file)
@@ -2008,6 +2008,7 @@ static struct dmar_domain *get_domain_for_dev(struct pci_dev *pdev, int gaw)
        if (!drhd) {
                printk(KERN_ERR "IOMMU: can't find DMAR for device %s\n",
                        pci_name(pdev));
+               free_domain_mem(domain);
                return NULL;
        }
        iommu = drhd->iommu;
@@ -4124,8 +4125,13 @@ static int intel_iommu_add_device(struct device *dev)
        } else
                dma_pdev = pci_dev_get(pdev);
 
+       /* Account for quirked devices */
        swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev));
 
+       /*
+        * If it's a multifunction device that does not support our
+        * required ACS flags, add to the same group as function 0.
+        */
        if (dma_pdev->multifunction &&
            !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS))
                swap_pci_ref(&dma_pdev,
@@ -4133,14 +4139,28 @@ static int intel_iommu_add_device(struct device *dev)
                                          PCI_DEVFN(PCI_SLOT(dma_pdev->devfn),
                                          0)));
 
+       /*
+        * Devices on the root bus go through the iommu.  If that's not us,
+        * find the next upstream device and test ACS up to the root bus.
+        * Finding the next device may require skipping virtual buses.
+        */
        while (!pci_is_root_bus(dma_pdev->bus)) {
-               if (pci_acs_path_enabled(dma_pdev->bus->self,
-                                        NULL, REQ_ACS_FLAGS))
+               struct pci_bus *bus = dma_pdev->bus;
+
+               while (!bus->self) {
+                       if (!pci_is_root_bus(bus))
+                               bus = bus->parent;
+                       else
+                               goto root_bus;
+               }
+
+               if (pci_acs_path_enabled(bus->self, NULL, REQ_ACS_FLAGS))
                        break;
 
-               swap_pci_ref(&dma_pdev, pci_dev_get(dma_pdev->bus->self));
+               swap_pci_ref(&dma_pdev, pci_dev_get(bus->self));
        }
 
+root_bus:
        group = iommu_group_get(&dma_pdev->dev);
        pci_dev_put(dma_pdev);
        if (!group) {
index e0b18f3ae9a862a22a8bc2ebe2eccc224c456252..af8904de1d44e63ca35be4a58320889b2bab7a8b 100644 (file)
@@ -736,6 +736,7 @@ int __init parse_ioapics_under_ir(void)
 {
        struct dmar_drhd_unit *drhd;
        int ir_supported = 0;
+       int ioapic_idx;
 
        for_each_drhd_unit(drhd) {
                struct intel_iommu *iommu = drhd->iommu;
@@ -748,13 +749,20 @@ int __init parse_ioapics_under_ir(void)
                }
        }
 
-       if (ir_supported && ir_ioapic_num != nr_ioapics) {
-               printk(KERN_WARNING
-                      "Not all IO-APIC's listed under remapping hardware\n");
-               return -1;
+       if (!ir_supported)
+               return 0;
+
+       for (ioapic_idx = 0; ioapic_idx < nr_ioapics; ioapic_idx++) {
+               int ioapic_id = mpc_ioapic_id(ioapic_idx);
+               if (!map_ioapic_to_ir(ioapic_id)) {
+                       pr_err(FW_BUG "ioapic %d has no mapping iommu, "
+                              "interrupt remapping will be disabled\n",
+                              ioapic_id);
+                       return -1;
+               }
        }
 
-       return ir_supported;
+       return 1;
 }
 
 int __init ir_dev_scope_init(void)
index 4ba325ab626249c2aa2aee1271a6d0c68ec20d9a..5e51fb77e524c76d69764bf6ae883cc6f0464153 100644 (file)
@@ -32,6 +32,8 @@
 #include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_iommu.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
 
 #include <asm/page.h>
 #include <asm/cacheflush.h>
 #define SMMU_CONFIG_DISABLE                    0
 #define SMMU_CONFIG_ENABLE                     1
 
-#define SMMU_TLB_CONFIG                                0x14
-#define SMMU_TLB_CONFIG_STATS__MASK            (1 << 31)
-#define SMMU_TLB_CONFIG_STATS__ENABLE          (1 << 31)
+/* REVISIT: To support multiple MCs */
+enum {
+       _MC = 0,
+};
+
+enum {
+       _TLB = 0,
+       _PTC,
+};
+
+#define SMMU_CACHE_CONFIG_BASE                 0x14
+#define __SMMU_CACHE_CONFIG(mc, cache)         (SMMU_CACHE_CONFIG_BASE + 4 * cache)
+#define SMMU_CACHE_CONFIG(cache)               __SMMU_CACHE_CONFIG(_MC, cache)
+
+#define SMMU_CACHE_CONFIG_STATS_SHIFT          31
+#define SMMU_CACHE_CONFIG_STATS_ENABLE         (1 << SMMU_CACHE_CONFIG_STATS_SHIFT)
+#define SMMU_CACHE_CONFIG_STATS_TEST_SHIFT     30
+#define SMMU_CACHE_CONFIG_STATS_TEST           (1 << SMMU_CACHE_CONFIG_STATS_TEST_SHIFT)
+
 #define SMMU_TLB_CONFIG_HIT_UNDER_MISS__ENABLE (1 << 29)
 #define SMMU_TLB_CONFIG_ACTIVE_LINES__VALUE    0x10
 #define SMMU_TLB_CONFIG_RESET_VAL              0x20000010
 
-#define SMMU_PTC_CONFIG                                0x18
-#define SMMU_PTC_CONFIG_STATS__MASK            (1 << 31)
-#define SMMU_PTC_CONFIG_STATS__ENABLE          (1 << 31)
 #define SMMU_PTC_CONFIG_CACHE__ENABLE          (1 << 29)
 #define SMMU_PTC_CONFIG_INDEX_MAP__PATTERN     0x3f
 #define SMMU_PTC_CONFIG_RESET_VAL              0x2000003f
 
 #define SMMU_ASID_SECURITY                     0x38
 
-#define SMMU_STATS_TLB_HIT_COUNT               0x1f0
-#define SMMU_STATS_TLB_MISS_COUNT              0x1f4
-#define SMMU_STATS_PTC_HIT_COUNT               0x1f8
-#define SMMU_STATS_PTC_MISS_COUNT              0x1fc
+#define SMMU_STATS_CACHE_COUNT_BASE            0x1f0
+
+#define SMMU_STATS_CACHE_COUNT(mc, cache, hitmiss)             \
+       (SMMU_STATS_CACHE_COUNT_BASE + 8 * cache + 4 * hitmiss)
 
 #define SMMU_TRANSLATION_ENABLE_0              0x228
 #define SMMU_TRANSLATION_ENABLE_1              0x22c
@@ -251,6 +266,8 @@ struct smmu_device {
        unsigned long translation_enable_2;
        unsigned long asid_security;
 
+       struct dentry *debugfs_root;
+
        struct device_node *ahb;
 
        int             num_as;
@@ -412,8 +429,8 @@ static int smmu_setup_regs(struct smmu_device *smmu)
        smmu_write(smmu, smmu->translation_enable_1, SMMU_TRANSLATION_ENABLE_1);
        smmu_write(smmu, smmu->translation_enable_2, SMMU_TRANSLATION_ENABLE_2);
        smmu_write(smmu, smmu->asid_security, SMMU_ASID_SECURITY);
-       smmu_write(smmu, SMMU_TLB_CONFIG_RESET_VAL, SMMU_TLB_CONFIG);
-       smmu_write(smmu, SMMU_PTC_CONFIG_RESET_VAL, SMMU_PTC_CONFIG);
+       smmu_write(smmu, SMMU_TLB_CONFIG_RESET_VAL, SMMU_CACHE_CONFIG(_TLB));
+       smmu_write(smmu, SMMU_PTC_CONFIG_RESET_VAL, SMMU_CACHE_CONFIG(_PTC));
 
        smmu_flush_regs(smmu, 1);
 
@@ -799,14 +816,14 @@ static void smmu_iommu_detach_dev(struct iommu_domain *domain,
                        goto out;
                }
        }
-       dev_err(smmu->dev, "Couldn't find %s\n", dev_name(c->dev));
+       dev_err(smmu->dev, "Couldn't find %s\n", dev_name(dev));
 out:
        spin_unlock(&as->client_lock);
 }
 
 static int smmu_iommu_domain_init(struct iommu_domain *domain)
 {
-       int i, err = -ENODEV;
+       int i, err = -EAGAIN;
        unsigned long flags;
        struct smmu_as *as;
        struct smmu_device *smmu = smmu_handle;
@@ -814,11 +831,14 @@ static int smmu_iommu_domain_init(struct iommu_domain *domain)
        /* Look for a free AS with lock held */
        for  (i = 0; i < smmu->num_as; i++) {
                as = &smmu->as[i];
-               if (!as->pdir_page) {
-                       err = alloc_pdir(as);
-                       if (!err)
-                               goto found;
-               }
+
+               if (as->pdir_page)
+                       continue;
+
+               err = alloc_pdir(as);
+               if (!err)
+                       goto found;
+
                if (err != -EAGAIN)
                        break;
        }
@@ -892,6 +912,164 @@ static struct iommu_ops smmu_iommu_ops = {
        .pgsize_bitmap  = SMMU_IOMMU_PGSIZES,
 };
 
+/* Should be in the order of enum */
+static const char * const smmu_debugfs_mc[] = { "mc", };
+static const char * const smmu_debugfs_cache[] = {  "tlb", "ptc", };
+
+static ssize_t smmu_debugfs_stats_write(struct file *file,
+                                       const char __user *buffer,
+                                       size_t count, loff_t *pos)
+{
+       struct smmu_device *smmu;
+       struct dentry *dent;
+       int i, cache, mc;
+       enum {
+               _OFF = 0,
+               _ON,
+               _RESET,
+       };
+       const char * const command[] = {
+               [_OFF]          = "off",
+               [_ON]           = "on",
+               [_RESET]        = "reset",
+       };
+       char str[] = "reset";
+       u32 val;
+       size_t offs;
+
+       count = min_t(size_t, count, sizeof(str));
+       if (copy_from_user(str, buffer, count))
+               return -EINVAL;
+
+       for (i = 0; i < ARRAY_SIZE(command); i++)
+               if (strncmp(str, command[i],
+                           strlen(command[i])) == 0)
+                       break;
+
+       if (i == ARRAY_SIZE(command))
+               return -EINVAL;
+
+       dent = file->f_dentry;
+       cache = (int)dent->d_inode->i_private;
+       mc = (int)dent->d_parent->d_inode->i_private;
+       smmu = dent->d_parent->d_parent->d_inode->i_private;
+
+       offs = SMMU_CACHE_CONFIG(cache);
+       val = smmu_read(smmu, offs);
+       switch (i) {
+       case _OFF:
+               val &= ~SMMU_CACHE_CONFIG_STATS_ENABLE;
+               val &= ~SMMU_CACHE_CONFIG_STATS_TEST;
+               smmu_write(smmu, val, offs);
+               break;
+       case _ON:
+               val |= SMMU_CACHE_CONFIG_STATS_ENABLE;
+               val &= ~SMMU_CACHE_CONFIG_STATS_TEST;
+               smmu_write(smmu, val, offs);
+               break;
+       case _RESET:
+               val |= SMMU_CACHE_CONFIG_STATS_TEST;
+               smmu_write(smmu, val, offs);
+               val &= ~SMMU_CACHE_CONFIG_STATS_TEST;
+               smmu_write(smmu, val, offs);
+               break;
+       default:
+               BUG();
+               break;
+       }
+
+       dev_dbg(smmu->dev, "%s() %08x, %08x @%08x\n", __func__,
+               val, smmu_read(smmu, offs), offs);
+
+       return count;
+}
+
+static int smmu_debugfs_stats_show(struct seq_file *s, void *v)
+{
+       struct smmu_device *smmu;
+       struct dentry *dent;
+       int i, cache, mc;
+       const char * const stats[] = { "hit", "miss", };
+
+       dent = d_find_alias(s->private);
+       cache = (int)dent->d_inode->i_private;
+       mc = (int)dent->d_parent->d_inode->i_private;
+       smmu = dent->d_parent->d_parent->d_inode->i_private;
+
+       for (i = 0; i < ARRAY_SIZE(stats); i++) {
+               u32 val;
+               size_t offs;
+
+               offs = SMMU_STATS_CACHE_COUNT(mc, cache, i);
+               val = smmu_read(smmu, offs);
+               seq_printf(s, "%s:%08x ", stats[i], val);
+
+               dev_dbg(smmu->dev, "%s() %s %08x @%08x\n", __func__,
+                       stats[i], val, offs);
+       }
+       seq_printf(s, "\n");
+
+       return 0;
+}
+
+static int smmu_debugfs_stats_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, smmu_debugfs_stats_show, inode);
+}
+
+static const struct file_operations smmu_debugfs_stats_fops = {
+       .open           = smmu_debugfs_stats_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+       .write          = smmu_debugfs_stats_write,
+};
+
+static void smmu_debugfs_delete(struct smmu_device *smmu)
+{
+       debugfs_remove_recursive(smmu->debugfs_root);
+}
+
+static void smmu_debugfs_create(struct smmu_device *smmu)
+{
+       int i;
+       struct dentry *root;
+
+       root = debugfs_create_file(dev_name(smmu->dev),
+                                  S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
+                                  NULL, smmu, NULL);
+       if (!root)
+               goto err_out;
+       smmu->debugfs_root = root;
+
+       for (i = 0; i < ARRAY_SIZE(smmu_debugfs_mc); i++) {
+               int j;
+               struct dentry *mc;
+
+               mc = debugfs_create_file(smmu_debugfs_mc[i],
+                                        S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
+                                        root, (void *)i, NULL);
+               if (!mc)
+                       goto err_out;
+
+               for (j = 0; j < ARRAY_SIZE(smmu_debugfs_cache); j++) {
+                       struct dentry *cache;
+
+                       cache = debugfs_create_file(smmu_debugfs_cache[j],
+                                                   S_IWUGO | S_IRUGO, mc,
+                                                   (void *)j,
+                                                   &smmu_debugfs_stats_fops);
+                       if (!cache)
+                               goto err_out;
+               }
+       }
+
+       return;
+
+err_out:
+       smmu_debugfs_delete(smmu);
+}
+
 static int tegra_smmu_suspend(struct device *dev)
 {
        struct smmu_device *smmu = dev_get_drvdata(dev);
@@ -996,6 +1174,7 @@ static int tegra_smmu_probe(struct platform_device *pdev)
        if (!smmu->avp_vector_page)
                return -ENOMEM;
 
+       smmu_debugfs_create(smmu);
        smmu_handle = smmu;
        return 0;
 }
@@ -1005,6 +1184,8 @@ static int tegra_smmu_remove(struct platform_device *pdev)
        struct smmu_device *smmu = platform_get_drvdata(pdev);
        int i;
 
+       smmu_debugfs_delete(smmu);
+
        smmu_write(smmu, SMMU_CONFIG_DISABLE, SMMU_CONFIG);
        for (i = 0; i < smmu->num_as; i++)
                free_pdir(&smmu->as[i]);
index 38c4bd87b2c98a2b0bfc45692823e8d62c8ca1b3..c679867c2ccd3f37682ef75def8481588dfbec9a 100644 (file)
@@ -234,7 +234,8 @@ static struct capiminor *capiminor_alloc(struct capi20_appl *ap, u32 ncci)
 
        mp->minor = minor;
 
-       dev = tty_register_device(capinc_tty_driver, minor, NULL);
+       dev = tty_port_register_device(&mp->port, capinc_tty_driver, minor,
+                       NULL);
        if (IS_ERR(dev))
                goto err_out2;
 
index a6d9fd2858f74d2b6690cfcf9c6edc832f641bb2..67abf3ff45e812eec6ce416a917cacec5a650b39 100644 (file)
@@ -446,8 +446,8 @@ static void if_set_termios(struct tty_struct *tty, struct ktermios *old)
                goto out;
        }
 
-       iflag = tty->termios->c_iflag;
-       cflag = tty->termios->c_cflag;
+       iflag = tty->termios.c_iflag;
+       cflag = tty->termios.c_cflag;
        old_cflag = old ? old->c_cflag : cflag;
        gig_dbg(DEBUG_IF, "%u: iflag %x cflag %x old %x",
                cs->minor_index, iflag, cflag, old_cflag);
@@ -524,7 +524,8 @@ void gigaset_if_init(struct cardstate *cs)
        tasklet_init(&cs->if_wake_tasklet, if_wake, (unsigned long) cs);
 
        mutex_lock(&cs->mutex);
-       cs->tty_dev = tty_register_device(drv->tty, cs->minor_index, NULL);
+       cs->tty_dev = tty_port_register_device(&cs->port, drv->tty,
+                       cs->minor_index, NULL);
 
        if (!IS_ERR(cs->tty_dev))
                dev_set_drvdata(cs->tty_dev, cs);
index 7bc50670d7d9fd3cb5c3d4decbf0e32ca86296ea..b817809f763cc4867a52f849418919f0783228c0 100644 (file)
@@ -1009,15 +1009,15 @@ isdn_tty_change_speed(modem_info *info)
                quot;
        int i;
 
-       if (!port->tty || !port->tty->termios)
+       if (!port->tty)
                return;
-       cflag = port->tty->termios->c_cflag;
+       cflag = port->tty->termios.c_cflag;
 
        quot = i = cflag & CBAUD;
        if (i & CBAUDEX) {
                i &= ~CBAUDEX;
                if (i < 1 || i > 2)
-                       port->tty->termios->c_cflag &= ~CBAUDEX;
+                       port->tty->termios.c_cflag &= ~CBAUDEX;
                else
                        i += 15;
        }
@@ -1097,7 +1097,7 @@ isdn_tty_shutdown(modem_info *info)
 #endif
        isdn_unlock_drivers();
        info->msr &= ~UART_MSR_RI;
-       if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) {
+       if (!info->port.tty || (info->port.tty->termios.c_cflag & HUPCL)) {
                info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);
                if (info->emu.mdmreg[REG_DTRHUP] & BIT_DTRHUP) {
                        isdn_tty_modem_reset_regs(info, 0);
@@ -1469,13 +1469,13 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
        if (!old_termios)
                isdn_tty_change_speed(info);
        else {
-               if (tty->termios->c_cflag == old_termios->c_cflag &&
-                   tty->termios->c_ispeed == old_termios->c_ispeed &&
-                   tty->termios->c_ospeed == old_termios->c_ospeed)
+               if (tty->termios.c_cflag == old_termios->c_cflag &&
+                   tty->termios.c_ispeed == old_termios->c_ispeed &&
+                   tty->termios.c_ospeed == old_termios->c_ospeed)
                        return;
                isdn_tty_change_speed(info);
                if ((old_termios->c_cflag & CRTSCTS) &&
-                   !(tty->termios->c_cflag & CRTSCTS))
+                   !(tty->termios.c_cflag & CRTSCTS))
                        tty->hw_stopped = 0;
        }
 }
@@ -1486,6 +1486,18 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
  * ------------------------------------------------------------
  */
 
+static int isdn_tty_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+       modem_info *info = &dev->mdm.info[tty->index];
+
+       if (isdn_tty_paranoia_check(info, tty->name, __func__))
+               return -ENODEV;
+
+       tty->driver_data = info;
+
+       return tty_port_install(&info->port, driver, tty);
+}
+
 /*
  * This routine is called whenever a serial port is opened.  It
  * enables interrupts for a serial port, linking in its async structure into
@@ -1495,22 +1507,16 @@ isdn_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
 static int
 isdn_tty_open(struct tty_struct *tty, struct file *filp)
 {
-       struct tty_port *port;
-       modem_info *info;
+       modem_info *info = tty->driver_data;
+       struct tty_port *port = &info->port;
        int retval;
 
-       info = &dev->mdm.info[tty->index];
-       if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_open"))
-               return -ENODEV;
-       port = &info->port;
 #ifdef ISDN_DEBUG_MODEM_OPEN
        printk(KERN_DEBUG "isdn_tty_open %s, count = %d\n", tty->name,
               port->count);
 #endif
        port->count++;
-       tty->driver_data = info;
        port->tty = tty;
-       tty->port = port;
        /*
         * Start up serial port
         */
@@ -1738,6 +1744,7 @@ modem_write_profile(atemu *m)
 }
 
 static const struct tty_operations modem_ops = {
+       .install = isdn_tty_install,
        .open = isdn_tty_open,
        .close = isdn_tty_close,
        .write = isdn_tty_write,
@@ -1782,7 +1789,7 @@ isdn_tty_modem_init(void)
        m->tty_modem->subtype = SERIAL_TYPE_NORMAL;
        m->tty_modem->init_termios = tty_std_termios;
        m->tty_modem->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-       m->tty_modem->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+       m->tty_modem->flags = TTY_DRIVER_REAL_RAW;
        m->tty_modem->driver_name = "isdn_tty";
        tty_set_operations(m->tty_modem, &modem_ops);
        retval = tty_register_driver(m->tty_modem);
index 5405ec644db3ee910df3765499300f11f7d1832c..baf2686aa8eb0cb027044e815dafa8b2aa6afae4 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/sched.h>
 #include "isdnloop.h"
 
-static char *revision = "$Revision: 1.11.6.7 $";
 static char *isdnloop_id = "loop0";
 
 MODULE_DESCRIPTION("ISDN4Linux: Pseudo Driver that simulates an ISDN card");
@@ -1494,17 +1493,6 @@ isdnloop_addcard(char *id1)
 static int __init
 isdnloop_init(void)
 {
-       char *p;
-       char rev[10];
-
-       if ((p = strchr(revision, ':'))) {
-               strcpy(rev, p + 1);
-               p = strchr(rev, '$');
-               *p = 0;
-       } else
-               strcpy(rev, " ??? ");
-       printk(KERN_NOTICE "isdnloop-ISDN-driver Rev%s\n", rev);
-
        if (isdnloop_id)
                return (isdnloop_addcard(isdnloop_id));
 
index 0dc8abca14079223c868effc3258e4b5f36590fe..949cabb88f1c113c9606d26ff72627f6cf9db108 100644 (file)
@@ -2222,7 +2222,7 @@ create_l2(struct mISDNchannel *ch, u_int protocol, u_long options, int tei,
        InitWin(l2);
        l2->l2m.fsm = &l2fsm;
        if (test_bit(FLG_LAPB, &l2->flag) ||
-           test_bit(FLG_PTP, &l2->flag) ||
+           test_bit(FLG_FIXED_TEI, &l2->flag) ||
            test_bit(FLG_LAPD_NET, &l2->flag))
                l2->l2m.state = ST_L2_4;
        else
index c96bbaadeebd75afa2357f638295c2b2e26c811e..16578d3b52bb8ba6e43f8437c7141a0b6fd0ab87 100644 (file)
@@ -506,6 +506,16 @@ config LEDS_TRIGGER_BACKLIGHT
 
          If unsure, say N.
 
+config LEDS_TRIGGER_CPU
+       bool "LED CPU Trigger"
+       depends on LEDS_TRIGGERS
+       help
+         This allows LEDs to be controlled by active CPUs. This shows
+         the active CPUs across an array of LEDs so you can see which
+         CPUs are active on the system at any given moment.
+
+         If unsure, say N.
+
 config LEDS_TRIGGER_GPIO
        tristate "LED GPIO Trigger"
        depends on LEDS_TRIGGERS
index a4429a9217bceb7303caa7a50fe49d0966f81ad5..a9b627c4f8ba94c5b1574a7f81800bc20d80c368 100644 (file)
@@ -61,5 +61,6 @@ obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK)   += ledtrig-ide-disk.o
 obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT)   += ledtrig-heartbeat.o
 obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT)   += ledtrig-backlight.o
 obj-$(CONFIG_LEDS_TRIGGER_GPIO)                += ledtrig-gpio.o
+obj-$(CONFIG_LEDS_TRIGGER_CPU)         += ledtrig-cpu.o
 obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON)  += ledtrig-default-on.o
 obj-$(CONFIG_LEDS_TRIGGER_TRANSIENT)   += ledtrig-transient.o
index c599095bc00556f9c79b3444dd2933f89ca0496a..c8100ec4265544cb6109641939b1c6f2dd2a3fe8 100644 (file)
@@ -124,6 +124,19 @@ static void led_timer_function(unsigned long data)
        mod_timer(&led_cdev->blink_timer, jiffies + msecs_to_jiffies(delay));
 }
 
+static void set_brightness_delayed(struct work_struct *ws)
+{
+       struct led_classdev *led_cdev =
+               container_of(ws, struct led_classdev, set_brightness_work);
+
+       /* stop and clear soft-blink timer */
+       del_timer_sync(&led_cdev->blink_timer);
+       led_cdev->blink_delay_on = 0;
+       led_cdev->blink_delay_off = 0;
+
+       __led_set_brightness(led_cdev, led_cdev->delayed_set_value);
+}
+
 /**
  * led_classdev_suspend - suspend an led_classdev.
  * @led_cdev: the led_classdev to suspend.
@@ -191,6 +204,8 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
 
        led_update_brightness(led_cdev);
 
+       INIT_WORK(&led_cdev->set_brightness_work, set_brightness_delayed);
+
        init_timer(&led_cdev->blink_timer);
        led_cdev->blink_timer.function = led_timer_function;
        led_cdev->blink_timer.data = (unsigned long)led_cdev;
index 2ab05af3de31ab188fb0300befb04a708702637f..ab89b58aecb3baa5fa1c79b21ab46e93bae593d7 100644 (file)
@@ -106,10 +106,12 @@ EXPORT_SYMBOL(led_blink_set_oneshot);
 void led_set_brightness(struct led_classdev *led_cdev,
                        enum led_brightness brightness)
 {
-       /* stop and clear soft-blink timer */
-       del_timer_sync(&led_cdev->blink_timer);
-       led_cdev->blink_delay_on = 0;
-       led_cdev->blink_delay_off = 0;
+       /* delay brightness setting if need to stop soft-blink timer */
+       if (led_cdev->blink_delay_on || led_cdev->blink_delay_off) {
+               led_cdev->delayed_set_value = brightness;
+               schedule_work(&led_cdev->set_brightness_work);
+               return;
+       }
 
        __led_set_brightness(led_cdev, brightness);
 }
index 1ed1677c916f260285d0acefa255ef7adf337802..e024b0b1c3b1e11fbae8dc6de27006d1cb1bc0b6 100644 (file)
@@ -31,7 +31,7 @@ static int __init clevo_mail_led_dmi_callback(const struct dmi_system_id *id)
 }
 
 /*
- * struct mail_led_whitelist - List of known good models
+ * struct clevo_mail_led_dmi_table - List of known good models
  *
  * Contains the known good models this driver is compatible with.
  * When adding a new model try to be as strict as possible. This
@@ -39,7 +39,7 @@ static int __init clevo_mail_led_dmi_callback(const struct dmi_system_id *id)
  * detected as working, but in reality it is not) as low as
  * possible.
  */
-static struct dmi_system_id __initdata mail_led_whitelist[] = {
+static struct dmi_system_id __initdata clevo_mail_led_dmi_table[] = {
        {
                .callback = clevo_mail_led_dmi_callback,
                .ident = "Clevo D410J",
@@ -59,11 +59,10 @@ static struct dmi_system_id __initdata mail_led_whitelist[] = {
        },
        {
                .callback = clevo_mail_led_dmi_callback,
-               .ident = "Positivo Mobile",
+               .ident = "Clevo M5x0V",
                .matches = {
                        DMI_MATCH(DMI_BOARD_VENDOR, "CLEVO Co. "),
                        DMI_MATCH(DMI_BOARD_NAME, "M5X0V "),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "Positivo Mobile"),
                        DMI_MATCH(DMI_PRODUCT_VERSION, "VT6198")
                }
        },
@@ -89,6 +88,7 @@ static struct dmi_system_id __initdata mail_led_whitelist[] = {
        },
        { }
 };
+MODULE_DEVICE_TABLE(dmi, clevo_mail_led_dmi_table);
 
 static void clevo_mail_led_set(struct led_classdev *led_cdev,
                                enum led_brightness value)
@@ -180,7 +180,7 @@ static int __init clevo_mail_led_init(void)
 
        /* Check with the help of DMI if we are running on supported hardware */
        if (!nodetect) {
-               count = dmi_check_system(mail_led_whitelist);
+               count = dmi_check_system(clevo_mail_led_dmi_table);
        } else {
                count = 1;
                printk(KERN_ERR KBUILD_MODNAME ": Skipping DMI detection. "
index 53bd136f1ef070a1e045b97f8dbc6b55e30c0ca6..0ade6ebfc914dba6e6809b46a428fc9ee219b83e 100644 (file)
@@ -63,7 +63,7 @@ static int lp8788_led_init_device(struct lp8788_led *led,
        /* scale configuration */
        addr = LP8788_ISINK_CTRL;
        mask = 1 << (cfg->num + LP8788_ISINK_SCALE_OFFSET);
-       val = cfg->scale << cfg->num;
+       val = cfg->scale << (cfg->num + LP8788_ISINK_SCALE_OFFSET);
        ret = lp8788_update_bits(led->lp, addr, mask, val);
        if (ret)
                return ret;
index 9ee12c28059a0a8e60bc879dd083db2b90ae2fdc..771ea067e680f8b64e9cd54672007a5d66091d9c 100644 (file)
@@ -247,7 +247,7 @@ static int __devinit r_tpu_probe(struct platform_device *pdev)
 
        if (!cfg) {
                dev_err(&pdev->dev, "missing platform data\n");
-               goto err0;
+               return -ENODEV;
        }
 
        p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
index 918d4baff1c7257c65276bfcf4cb05b73350553c..f5d9ac3ff16178480c6b39222170bcca4a82498a 100644 (file)
@@ -201,7 +201,7 @@ static int wm8350_led_probe(struct platform_device *pdev)
        struct regulator *isink, *dcdc;
        struct wm8350_led *led;
        struct wm8350_led_platform_data *pdata = pdev->dev.platform_data;
-       int ret, i;
+       int i;
 
        if (pdata == NULL) {
                dev_err(&pdev->dev, "no platform data\n");
@@ -214,24 +214,21 @@ static int wm8350_led_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       isink = regulator_get(&pdev->dev, "led_isink");
+       isink = devm_regulator_get(&pdev->dev, "led_isink");
        if (IS_ERR(isink)) {
                printk(KERN_ERR "%s: can't get ISINK\n", __func__);
                return PTR_ERR(isink);
        }
 
-       dcdc = regulator_get(&pdev->dev, "led_vcc");
+       dcdc = devm_regulator_get(&pdev->dev, "led_vcc");
        if (IS_ERR(dcdc)) {
                printk(KERN_ERR "%s: can't get DCDC\n", __func__);
-               ret = PTR_ERR(dcdc);
-               goto err_isink;
+               return PTR_ERR(dcdc);
        }
 
        led = devm_kzalloc(&pdev->dev, sizeof(*led), GFP_KERNEL);
-       if (led == NULL) {
-               ret = -ENOMEM;
-               goto err_dcdc;
-       }
+       if (led == NULL)
+               return -ENOMEM;
 
        led->cdev.brightness_set = wm8350_led_set;
        led->cdev.default_trigger = pdata->default_trigger;
@@ -257,17 +254,7 @@ static int wm8350_led_probe(struct platform_device *pdev)
        led->value = LED_OFF;
        platform_set_drvdata(pdev, led);
 
-       ret = led_classdev_register(&pdev->dev, &led->cdev);
-       if (ret < 0)
-               goto err_dcdc;
-
-       return 0;
-
- err_dcdc:
-       regulator_put(dcdc);
- err_isink:
-       regulator_put(isink);
-       return ret;
+       return led_classdev_register(&pdev->dev, &led->cdev);
 }
 
 static int wm8350_led_remove(struct platform_device *pdev)
@@ -277,8 +264,6 @@ static int wm8350_led_remove(struct platform_device *pdev)
        led_classdev_unregister(&led->cdev);
        flush_work_sync(&led->work);
        wm8350_led_disable(led);
-       regulator_put(led->dcdc);
-       regulator_put(led->isink);
        return 0;
 }
 
diff --git a/drivers/leds/ledtrig-cpu.c b/drivers/leds/ledtrig-cpu.c
new file mode 100644 (file)
index 0000000..b312056
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * ledtrig-cpu.c - LED trigger based on CPU activity
+ *
+ * This LED trigger will be registered for each possible CPU and named as
+ * cpu0, cpu1, cpu2, cpu3, etc.
+ *
+ * It can be bound to any LED just like other triggers using either a
+ * board file or via sysfs interface.
+ *
+ * An API named ledtrig_cpu is exported for any user, who want to add CPU
+ * activity indication in their code
+ *
+ * Copyright 2011 Linus Walleij <linus.walleij@linaro.org>
+ * Copyright 2011 - 2012 Bryan Wu <bryan.wu@canonical.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/init.h>
+#include <linux/slab.h>
+#include <linux/percpu.h>
+#include <linux/syscore_ops.h>
+#include <linux/rwsem.h>
+#include "leds.h"
+
+#define MAX_NAME_LEN   8
+
+struct led_trigger_cpu {
+       char name[MAX_NAME_LEN];
+       struct led_trigger *_trig;
+       struct mutex lock;
+       int lock_is_inited;
+};
+
+static DEFINE_PER_CPU(struct led_trigger_cpu, cpu_trig);
+
+/**
+ * ledtrig_cpu - emit a CPU event as a trigger
+ * @evt: CPU event to be emitted
+ *
+ * Emit a CPU event on a CPU core, which will trigger a
+ * binded LED to turn on or turn off.
+ */
+void ledtrig_cpu(enum cpu_led_event ledevt)
+{
+       struct led_trigger_cpu *trig = &__get_cpu_var(cpu_trig);
+
+       /* mutex lock should be initialized before calling mutex_call() */
+       if (!trig->lock_is_inited)
+               return;
+
+       mutex_lock(&trig->lock);
+
+       /* Locate the correct CPU LED */
+       switch (ledevt) {
+       case CPU_LED_IDLE_END:
+       case CPU_LED_START:
+               /* Will turn the LED on, max brightness */
+               led_trigger_event(trig->_trig, LED_FULL);
+               break;
+
+       case CPU_LED_IDLE_START:
+       case CPU_LED_STOP:
+       case CPU_LED_HALTED:
+               /* Will turn the LED off */
+               led_trigger_event(trig->_trig, LED_OFF);
+               break;
+
+       default:
+               /* Will leave the LED as it is */
+               break;
+       }
+
+       mutex_unlock(&trig->lock);
+}
+EXPORT_SYMBOL(ledtrig_cpu);
+
+static int ledtrig_cpu_syscore_suspend(void)
+{
+       ledtrig_cpu(CPU_LED_STOP);
+       return 0;
+}
+
+static void ledtrig_cpu_syscore_resume(void)
+{
+       ledtrig_cpu(CPU_LED_START);
+}
+
+static void ledtrig_cpu_syscore_shutdown(void)
+{
+       ledtrig_cpu(CPU_LED_HALTED);
+}
+
+static struct syscore_ops ledtrig_cpu_syscore_ops = {
+       .shutdown       = ledtrig_cpu_syscore_shutdown,
+       .suspend        = ledtrig_cpu_syscore_suspend,
+       .resume         = ledtrig_cpu_syscore_resume,
+};
+
+static int __init ledtrig_cpu_init(void)
+{
+       int cpu;
+
+       /* Supports up to 9999 cpu cores */
+       BUILD_BUG_ON(CONFIG_NR_CPUS > 9999);
+
+       /*
+        * Registering CPU led trigger for each CPU core here
+        * ignores CPU hotplug, but after this CPU hotplug works
+        * fine with this trigger.
+        */
+       for_each_possible_cpu(cpu) {
+               struct led_trigger_cpu *trig = &per_cpu(cpu_trig, cpu);
+
+               mutex_init(&trig->lock);
+
+               snprintf(trig->name, MAX_NAME_LEN, "cpu%d", cpu);
+
+               mutex_lock(&trig->lock);
+               led_trigger_register_simple(trig->name, &trig->_trig);
+               trig->lock_is_inited = 1;
+               mutex_unlock(&trig->lock);
+       }
+
+       register_syscore_ops(&ledtrig_cpu_syscore_ops);
+
+       pr_info("ledtrig-cpu: registered to indicate activity on CPUs\n");
+
+       return 0;
+}
+module_init(ledtrig_cpu_init);
+
+static void __exit ledtrig_cpu_exit(void)
+{
+       int cpu;
+
+       for_each_possible_cpu(cpu) {
+               struct led_trigger_cpu *trig = &per_cpu(cpu_trig, cpu);
+
+               mutex_lock(&trig->lock);
+
+               led_trigger_unregister_simple(trig->_trig);
+               trig->_trig = NULL;
+               memset(trig->name, 0, MAX_NAME_LEN);
+               trig->lock_is_inited = 0;
+
+               mutex_unlock(&trig->lock);
+               mutex_destroy(&trig->lock);
+       }
+
+       unregister_syscore_ops(&ledtrig_cpu_syscore_ops);
+}
+module_exit(ledtrig_cpu_exit);
+
+MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
+MODULE_AUTHOR("Bryan Wu <bryan.wu@canonical.com>");
+MODULE_DESCRIPTION("CPU LED trigger");
+MODULE_LICENSE("GPL");
index 831d7517c759294f4936e810f12008c257e5c1f4..3f8d032f180fd5c0ec76901742c00cb58212acb1 100644 (file)
@@ -63,7 +63,7 @@ struct media_bay_info {
        int                             value_count;
        int                             timer;
        struct macio_dev                *mdev;
-       struct mb_ops*                  ops;
+       const struct mb_ops*            ops;
        int                             index;
        int                             cached_gpio;
        int                             sleeping;
@@ -669,7 +669,7 @@ static int media_bay_resume(struct macio_dev *mdev)
 
 /* Definitions of "ops" structures.
  */
-static struct mb_ops ohare_mb_ops = {
+static const struct mb_ops ohare_mb_ops = {
        .name           = "Ohare",
        .content        = ohare_mb_content,
        .power          = ohare_mb_power,
@@ -678,7 +678,7 @@ static struct mb_ops ohare_mb_ops = {
        .un_reset_ide   = ohare_mb_un_reset_ide,
 };
 
-static struct mb_ops heathrow_mb_ops = {
+static const struct mb_ops heathrow_mb_ops = {
        .name           = "Heathrow",
        .content        = heathrow_mb_content,
        .power          = heathrow_mb_power,
@@ -687,7 +687,7 @@ static struct mb_ops heathrow_mb_ops = {
        .un_reset_ide   = heathrow_mb_un_reset_ide,
 };
 
-static struct mb_ops keylargo_mb_ops = {
+static const struct mb_ops keylargo_mb_ops = {
        .name           = "KeyLargo",
        .init           = keylargo_mb_init,
        .content        = keylargo_mb_content,
index fa211d80fc0a1e4e37603b1455184cbee7da6e56..21014836bdbf2286eba4fd02effbc4efcd9db625 100644 (file)
@@ -138,6 +138,7 @@ static struct linear_conf *linear_conf(struct mddev *mddev, int raid_disks)
        struct linear_conf *conf;
        struct md_rdev *rdev;
        int i, cnt;
+       bool discard_supported = false;
 
        conf = kzalloc (sizeof (*conf) + raid_disks*sizeof(struct dev_info),
                        GFP_KERNEL);
@@ -171,6 +172,8 @@ static struct linear_conf *linear_conf(struct mddev *mddev, int raid_disks)
                conf->array_sectors += rdev->sectors;
                cnt++;
 
+               if (blk_queue_discard(bdev_get_queue(rdev->bdev)))
+                       discard_supported = true;
        }
        if (cnt != raid_disks) {
                printk(KERN_ERR "md/linear:%s: not enough drives present. Aborting!\n",
@@ -178,6 +181,11 @@ static struct linear_conf *linear_conf(struct mddev *mddev, int raid_disks)
                goto out;
        }
 
+       if (!discard_supported)
+               queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, mddev->queue);
+       else
+               queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mddev->queue);
+
        /*
         * Here we calculate the device offsets.
         */
@@ -244,7 +252,9 @@ static int linear_add(struct mddev *mddev, struct md_rdev *rdev)
        if (!newconf)
                return -ENOMEM;
 
-       oldconf = rcu_dereference(mddev->private);
+       oldconf = rcu_dereference_protected(mddev->private,
+                                           lockdep_is_held(
+                                                   &mddev->reconfig_mutex));
        mddev->raid_disks++;
        rcu_assign_pointer(mddev->private, newconf);
        md_set_array_sectors(mddev, linear_size(mddev, 0, 0));
@@ -256,7 +266,10 @@ static int linear_add(struct mddev *mddev, struct md_rdev *rdev)
 
 static int linear_stop (struct mddev *mddev)
 {
-       struct linear_conf *conf = mddev->private;
+       struct linear_conf *conf =
+               rcu_dereference_protected(mddev->private,
+                                         lockdep_is_held(
+                                                 &mddev->reconfig_mutex));
 
        /*
         * We do not require rcu protection here since
@@ -326,6 +339,14 @@ static void linear_make_request(struct mddev *mddev, struct bio *bio)
        bio->bi_sector = bio->bi_sector - start_sector
                + tmp_dev->rdev->data_offset;
        rcu_read_unlock();
+
+       if (unlikely((bio->bi_rw & REQ_DISCARD) &&
+                    !blk_queue_discard(bdev_get_queue(bio->bi_bdev)))) {
+               /* Just ignore it */
+               bio_endio(bio, 0);
+               return;
+       }
+
        generic_make_request(bio);
 }
 
index fcd098794d37d16c7b48b12c54b5ba6f5e6ba60e..e34934a59c717ca609003645384a0541fb1d3257 100644 (file)
@@ -640,9 +640,9 @@ static struct mddev * mddev_find(dev_t unit)
        goto retry;
 }
 
-static inline int mddev_lock(struct mddev * mddev)
+int md_queue_misc_work(struct work_struct *work)
 {
-       return mutex_lock_interruptible(&mddev->reconfig_mutex);
+       return queue_work(md_misc_wq, work);
 }
 
 static inline int mddev_is_locked(struct mddev *mddev)
@@ -657,7 +657,7 @@ static inline int mddev_trylock(struct mddev * mddev)
 
 static struct attribute_group md_redundancy_group;
 
-static void mddev_unlock(struct mddev * mddev)
+void mddev_unlock(struct mddev * mddev)
 {
        if (mddev->to_remove) {
                /* These cannot be removed under reconfig_mutex as
@@ -711,6 +711,17 @@ static struct md_rdev * find_rdev_nr(struct mddev *mddev, int nr)
        return NULL;
 }
 
+static struct md_rdev * find_rdev_nr_rcu(struct mddev *mddev, int nr)
+{
+       struct md_rdev *rdev;
+
+       rdev_for_each_rcu(rdev, mddev)
+               if (rdev->desc_nr == nr)
+                       return rdev;
+
+       return NULL;
+}
+
 static struct md_rdev * find_rdev(struct mddev * mddev, dev_t dev)
 {
        struct md_rdev *rdev;
@@ -722,6 +733,17 @@ static struct md_rdev * find_rdev(struct mddev * mddev, dev_t dev)
        return NULL;
 }
 
+static struct md_rdev * find_rdev_rcu(struct mddev * mddev, dev_t dev)
+{
+       struct md_rdev *rdev;
+
+       rdev_for_each_rcu(rdev, mddev)
+               if (rdev->bdev->bd_dev == dev)
+                       return rdev;
+
+       return NULL;
+}
+
 static struct md_personality *find_pers(int level, char *clevel)
 {
        struct md_personality *pers;
@@ -1108,8 +1130,11 @@ static int super_90_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor
                        ret = 0;
        }
        rdev->sectors = rdev->sb_start;
-       /* Limit to 4TB as metadata cannot record more than that */
-       if (rdev->sectors >= (2ULL << 32))
+       /* Limit to 4TB as metadata cannot record more than that.
+        * (not needed for Linear and RAID0 as metadata doesn't
+        * record this size)
+        */
+       if (rdev->sectors >= (2ULL << 32) && sb->level >= 1)
                rdev->sectors = (2ULL << 32) - 2;
 
        if (rdev->sectors < ((sector_t)sb->size) * 2 && sb->level >= 1)
@@ -1400,7 +1425,7 @@ super_90_rdev_size_change(struct md_rdev *rdev, sector_t num_sectors)
        /* Limit to 4TB as metadata cannot record more than that.
         * 4TB == 2^32 KB, or 2*2^32 sectors.
         */
-       if (num_sectors >= (2ULL << 32))
+       if (num_sectors >= (2ULL << 32) && rdev->mddev->level >= 1)
                num_sectors = (2ULL << 32) - 2;
        md_super_write(rdev->mddev, rdev, rdev->sb_start, rdev->sb_size,
                       rdev->sb_page);
@@ -5544,8 +5569,9 @@ static int get_array_info(struct mddev * mddev, void __user * arg)
        int nr,working,insync,failed,spare;
        struct md_rdev *rdev;
 
-       nr=working=insync=failed=spare=0;
-       rdev_for_each(rdev, mddev) {
+       nr = working = insync = failed = spare = 0;
+       rcu_read_lock();
+       rdev_for_each_rcu(rdev, mddev) {
                nr++;
                if (test_bit(Faulty, &rdev->flags))
                        failed++;
@@ -5557,6 +5583,7 @@ static int get_array_info(struct mddev * mddev, void __user * arg)
                                spare++;
                }
        }
+       rcu_read_unlock();
 
        info.major_version = mddev->major_version;
        info.minor_version = mddev->minor_version;
@@ -5640,7 +5667,8 @@ static int get_disk_info(struct mddev * mddev, void __user * arg)
        if (copy_from_user(&info, arg, sizeof(info)))
                return -EFAULT;
 
-       rdev = find_rdev_nr(mddev, info.number);
+       rcu_read_lock();
+       rdev = find_rdev_nr_rcu(mddev, info.number);
        if (rdev) {
                info.major = MAJOR(rdev->bdev->bd_dev);
                info.minor = MINOR(rdev->bdev->bd_dev);
@@ -5659,6 +5687,7 @@ static int get_disk_info(struct mddev * mddev, void __user * arg)
                info.raid_disk = -1;
                info.state = (1<<MD_DISK_REMOVED);
        }
+       rcu_read_unlock();
 
        if (copy_to_user(arg, &info, sizeof(info)))
                return -EFAULT;
@@ -6267,18 +6296,22 @@ static int update_array_info(struct mddev *mddev, mdu_array_info_t *info)
 static int set_disk_faulty(struct mddev *mddev, dev_t dev)
 {
        struct md_rdev *rdev;
+       int err = 0;
 
        if (mddev->pers == NULL)
                return -ENODEV;
 
-       rdev = find_rdev(mddev, dev);
+       rcu_read_lock();
+       rdev = find_rdev_rcu(mddev, dev);
        if (!rdev)
-               return -ENODEV;
-
-       md_error(mddev, rdev);
-       if (!test_bit(Faulty, &rdev->flags))
-               return -EBUSY;
-       return 0;
+               err =  -ENODEV;
+       else {
+               md_error(mddev, rdev);
+               if (!test_bit(Faulty, &rdev->flags))
+                       err = -EBUSY;
+       }
+       rcu_read_unlock();
+       return err;
 }
 
 /*
@@ -6350,6 +6383,21 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode,
                goto abort;
        }
 
+       /* Some actions do not requires the mutex */
+       switch (cmd) {
+               case GET_ARRAY_INFO:
+                       err = get_array_info(mddev, argp);
+                       goto abort;
+
+               case GET_DISK_INFO:
+                       err = get_disk_info(mddev, argp);
+                       goto abort;
+
+               case SET_DISK_FAULTY:
+                       err = set_disk_faulty(mddev, new_decode_dev(arg));
+                       goto abort;
+       }
+
        err = mddev_lock(mddev);
        if (err) {
                printk(KERN_INFO 
@@ -6422,18 +6470,10 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode,
         */
        switch (cmd)
        {
-               case GET_ARRAY_INFO:
-                       err = get_array_info(mddev, argp);
-                       goto done_unlock;
-
                case GET_BITMAP_FILE:
                        err = get_bitmap_file(mddev, argp);
                        goto done_unlock;
 
-               case GET_DISK_INFO:
-                       err = get_disk_info(mddev, argp);
-                       goto done_unlock;
-
                case RESTART_ARRAY_RW:
                        err = restart_array(mddev);
                        goto done_unlock;
@@ -6515,10 +6555,6 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode,
                        err = hot_add_disk(mddev, new_decode_dev(arg));
                        goto done_unlock;
 
-               case SET_DISK_FAULTY:
-                       err = set_disk_faulty(mddev, new_decode_dev(arg));
-                       goto done_unlock;
-
                case RUN_ARRAY:
                        err = do_md_run(mddev);
                        goto done_unlock;
@@ -6676,7 +6712,7 @@ static int md_thread(void * arg)
 
                clear_bit(THREAD_WAKEUP, &thread->flags);
                if (!kthread_should_stop())
-                       thread->run(thread->mddev);
+                       thread->run(thread);
        }
 
        return 0;
@@ -6691,8 +6727,8 @@ void md_wakeup_thread(struct md_thread *thread)
        }
 }
 
-struct md_thread *md_register_thread(void (*run) (struct mddev *), struct mddev *mddev,
-                                const char *name)
+struct md_thread *md_register_thread(void (*run) (struct md_thread *),
+               struct mddev *mddev, const char *name)
 {
        struct md_thread *thread;
 
@@ -7241,8 +7277,9 @@ EXPORT_SYMBOL_GPL(md_allow_write);
 
 #define SYNC_MARKS     10
 #define        SYNC_MARK_STEP  (3*HZ)
-void md_do_sync(struct mddev *mddev)
+void md_do_sync(struct md_thread *thread)
 {
+       struct mddev *mddev = thread->mddev;
        struct mddev *mddev2;
        unsigned int currspeed = 0,
                 window;
@@ -8568,6 +8605,8 @@ EXPORT_SYMBOL(md_register_thread);
 EXPORT_SYMBOL(md_unregister_thread);
 EXPORT_SYMBOL(md_wakeup_thread);
 EXPORT_SYMBOL(md_check_recovery);
+EXPORT_SYMBOL(mddev_unlock);
+EXPORT_SYMBOL(md_queue_misc_work);
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("MD RAID framework");
 MODULE_ALIAS("md");
index f385b038589d32313014e07af203b8f742bec4a7..dce301ced932c188557d54038088f6a06cec3842 100644 (file)
@@ -540,12 +540,13 @@ static inline void sysfs_unlink_rdev(struct mddev *mddev, struct md_rdev *rdev)
        list_for_each_entry_rcu(rdev, &((mddev)->disks), same_set)
 
 struct md_thread {
-       void                    (*run) (struct mddev *mddev);
+       void                    (*run) (struct md_thread *thread);
        struct mddev            *mddev;
        wait_queue_head_t       wqueue;
        unsigned long           flags;
        struct task_struct      *tsk;
        unsigned long           timeout;
+       void                    *private;
 };
 
 #define THREAD_WAKEUP  0
@@ -584,7 +585,7 @@ static inline void safe_put_page(struct page *p)
 extern int register_md_personality(struct md_personality *p);
 extern int unregister_md_personality(struct md_personality *p);
 extern struct md_thread *md_register_thread(
-       void (*run)(struct mddev *mddev),
+       void (*run)(struct md_thread *thread),
        struct mddev *mddev,
        const char *name);
 extern void md_unregister_thread(struct md_thread **threadp);
@@ -603,7 +604,7 @@ extern void md_super_write(struct mddev *mddev, struct md_rdev *rdev,
 extern void md_super_wait(struct mddev *mddev);
 extern int sync_page_io(struct md_rdev *rdev, sector_t sector, int size, 
                        struct page *page, int rw, bool metadata_op);
-extern void md_do_sync(struct mddev *mddev);
+extern void md_do_sync(struct md_thread *thread);
 extern void md_new_event(struct mddev *mddev);
 extern int md_allow_write(struct mddev *mddev);
 extern void md_wait_for_blocked_rdev(struct md_rdev *rdev, struct mddev *mddev);
@@ -635,4 +636,12 @@ static inline int mddev_check_plugged(struct mddev *mddev)
        return !!blk_check_plugged(md_unplug, mddev,
                                   sizeof(struct blk_plug_cb));
 }
+
+static inline int mddev_lock(struct mddev * mddev)
+{
+       return mutex_lock_interruptible(&mddev->reconfig_mutex);
+}
+extern void mddev_unlock(struct mddev *mddev);
+extern int md_queue_misc_work(struct work_struct *work);
+
 #endif /* _MD_MD_H */
index 61a1833ebaf33ec40afaf752db9a849439c9bd13..2ab23d074dc6673951b59d19b78207388f59e2dc 100644 (file)
@@ -335,8 +335,9 @@ abort:
  *     3.      Performs writes following reads for array syncronising.
  */
 
-static void multipathd (struct mddev *mddev)
+static void multipathd (struct md_thread *thread)
 {
+       struct mddev *mddev = thread->mddev;
        struct multipath_bh *mp_bh;
        struct bio *bio;
        unsigned long flags;
index de63a1fc3737b7ac2af3c0f7cbf60cd99b495a31..1a8e5e3692b90c43d587a0fa4080680c5c258633 100644 (file)
@@ -88,6 +88,7 @@ static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf)
        char b[BDEVNAME_SIZE];
        char b2[BDEVNAME_SIZE];
        struct r0conf *conf = kzalloc(sizeof(*conf), GFP_KERNEL);
+       bool discard_supported = false;
 
        if (!conf)
                return -ENOMEM;
@@ -195,6 +196,9 @@ static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf)
                if (!smallest || (rdev1->sectors < smallest->sectors))
                        smallest = rdev1;
                cnt++;
+
+               if (blk_queue_discard(bdev_get_queue(rdev1->bdev)))
+                       discard_supported = true;
        }
        if (cnt != mddev->raid_disks) {
                printk(KERN_ERR "md/raid0:%s: too few disks (%d of %d) - "
@@ -272,6 +276,11 @@ static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf)
        blk_queue_io_opt(mddev->queue,
                         (mddev->chunk_sectors << 9) * mddev->raid_disks);
 
+       if (!discard_supported)
+               queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, mddev->queue);
+       else
+               queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mddev->queue);
+
        pr_debug("md/raid0:%s: done.\n", mdname(mddev));
        *private_conf = conf;
 
@@ -422,6 +431,7 @@ static int raid0_run(struct mddev *mddev)
        if (md_check_no_bitmap(mddev))
                return -EINVAL;
        blk_queue_max_hw_sectors(mddev->queue, mddev->chunk_sectors);
+       blk_queue_max_discard_sectors(mddev->queue, mddev->chunk_sectors);
 
        /* if private is not null, we are here after takeover */
        if (mddev->private == NULL) {
@@ -509,7 +519,7 @@ static void raid0_make_request(struct mddev *mddev, struct bio *bio)
                sector_t sector = bio->bi_sector;
                struct bio_pair *bp;
                /* Sanity check -- queue functions should prevent this happening */
-               if (bio->bi_vcnt != 1 ||
+               if ((bio->bi_vcnt != 1 && bio->bi_vcnt != 0) ||
                    bio->bi_idx != 0)
                        goto bad_map;
                /* This is a one page bio that upper layers
@@ -535,6 +545,13 @@ static void raid0_make_request(struct mddev *mddev, struct bio *bio)
        bio->bi_sector = sector_offset + zone->dev_start +
                tmp_dev->data_offset;
 
+       if (unlikely((bio->bi_rw & REQ_DISCARD) &&
+                    !blk_queue_discard(bdev_get_queue(bio->bi_bdev)))) {
+               /* Just ignore it */
+               bio_endio(bio, 0);
+               return;
+       }
+
        generic_make_request(bio);
        return;
 
index 611b5f79761826f8843ede2384c47ccbd0a87be1..3092afe635dbcb4318b58fc88988981e3f3ad2a2 100644 (file)
@@ -781,7 +781,12 @@ static void flush_pending_writes(struct r1conf *conf)
                while (bio) { /* submit pending writes */
                        struct bio *next = bio->bi_next;
                        bio->bi_next = NULL;
-                       generic_make_request(bio);
+                       if (unlikely((bio->bi_rw & REQ_DISCARD) &&
+                           !blk_queue_discard(bdev_get_queue(bio->bi_bdev))))
+                               /* Just ignore it */
+                               bio_endio(bio, 0);
+                       else
+                               generic_make_request(bio);
                        bio = next;
                }
        } else
@@ -994,6 +999,7 @@ static void make_request(struct mddev *mddev, struct bio * bio)
        const int rw = bio_data_dir(bio);
        const unsigned long do_sync = (bio->bi_rw & REQ_SYNC);
        const unsigned long do_flush_fua = (bio->bi_rw & (REQ_FLUSH | REQ_FUA));
+       const unsigned long do_discard = (bio->bi_rw & (REQ_DISCARD | REQ_SECURE));
        struct md_rdev *blocked_rdev;
        struct blk_plug_cb *cb;
        struct raid1_plug_cb *plug = NULL;
@@ -1295,7 +1301,7 @@ read_again:
                                   conf->mirrors[i].rdev->data_offset);
                mbio->bi_bdev = conf->mirrors[i].rdev->bdev;
                mbio->bi_end_io = raid1_end_write_request;
-               mbio->bi_rw = WRITE | do_flush_fua | do_sync;
+               mbio->bi_rw = WRITE | do_flush_fua | do_sync | do_discard;
                mbio->bi_private = r1_bio;
 
                atomic_inc(&r1_bio->remaining);
@@ -1549,6 +1555,8 @@ static int raid1_add_disk(struct mddev *mddev, struct md_rdev *rdev)
                clear_bit(Unmerged, &rdev->flags);
        }
        md_integrity_add_rdev(rdev, mddev);
+       if (blk_queue_discard(bdev_get_queue(rdev->bdev)))
+               queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mddev->queue);
        print_conf(conf);
        return err;
 }
@@ -2285,8 +2293,9 @@ read_more:
        }
 }
 
-static void raid1d(struct mddev *mddev)
+static void raid1d(struct md_thread *thread)
 {
+       struct mddev *mddev = thread->mddev;
        struct r1bio *r1_bio;
        unsigned long flags;
        struct r1conf *conf = mddev->private;
@@ -2783,6 +2792,7 @@ static int run(struct mddev *mddev)
        int i;
        struct md_rdev *rdev;
        int ret;
+       bool discard_supported = false;
 
        if (mddev->level != 1) {
                printk(KERN_ERR "md/raid1:%s: raid level not set to mirroring (%d)\n",
@@ -2812,6 +2822,8 @@ static int run(struct mddev *mddev)
                        continue;
                disk_stack_limits(mddev->gendisk, rdev->bdev,
                                  rdev->data_offset << 9);
+               if (blk_queue_discard(bdev_get_queue(rdev->bdev)))
+                       discard_supported = true;
        }
 
        mddev->degraded = 0;
@@ -2846,6 +2858,11 @@ static int run(struct mddev *mddev)
                mddev->queue->backing_dev_info.congested_fn = raid1_congested;
                mddev->queue->backing_dev_info.congested_data = mddev;
                blk_queue_merge_bvec(mddev->queue, raid1_mergeable_bvec);
+
+               if (discard_supported)
+                       queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mddev->queue);
+               else
+                       queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, mddev->queue);
        }
 
        ret =  md_integrity_register(mddev);
index de5ed6fd8806c3c3db39bbd894fabb04734b4523..974c653af3f91b55729435d33c981a1ff0478170 100644 (file)
@@ -659,7 +659,11 @@ static int raid10_mergeable_bvec(struct request_queue *q,
                max = biovec->bv_len;
 
        if (mddev->merge_check_needed) {
-               struct r10bio r10_bio;
+               struct {
+                       struct r10bio r10_bio;
+                       struct r10dev devs[conf->copies];
+               } on_stack;
+               struct r10bio *r10_bio = &on_stack.r10_bio;
                int s;
                if (conf->reshape_progress != MaxSector) {
                        /* Cannot give any guidance during reshape */
@@ -667,18 +671,18 @@ static int raid10_mergeable_bvec(struct request_queue *q,
                                return biovec->bv_len;
                        return 0;
                }
-               r10_bio.sector = sector;
-               raid10_find_phys(conf, &r10_bio);
+               r10_bio->sector = sector;
+               raid10_find_phys(conf, r10_bio);
                rcu_read_lock();
                for (s = 0; s < conf->copies; s++) {
-                       int disk = r10_bio.devs[s].devnum;
+                       int disk = r10_bio->devs[s].devnum;
                        struct md_rdev *rdev = rcu_dereference(
                                conf->mirrors[disk].rdev);
                        if (rdev && !test_bit(Faulty, &rdev->flags)) {
                                struct request_queue *q =
                                        bdev_get_queue(rdev->bdev);
                                if (q->merge_bvec_fn) {
-                                       bvm->bi_sector = r10_bio.devs[s].addr
+                                       bvm->bi_sector = r10_bio->devs[s].addr
                                                + rdev->data_offset;
                                        bvm->bi_bdev = rdev->bdev;
                                        max = min(max, q->merge_bvec_fn(
@@ -690,7 +694,7 @@ static int raid10_mergeable_bvec(struct request_queue *q,
                                struct request_queue *q =
                                        bdev_get_queue(rdev->bdev);
                                if (q->merge_bvec_fn) {
-                                       bvm->bi_sector = r10_bio.devs[s].addr
+                                       bvm->bi_sector = r10_bio->devs[s].addr
                                                + rdev->data_offset;
                                        bvm->bi_bdev = rdev->bdev;
                                        max = min(max, q->merge_bvec_fn(
@@ -907,7 +911,12 @@ static void flush_pending_writes(struct r10conf *conf)
                while (bio) { /* submit pending writes */
                        struct bio *next = bio->bi_next;
                        bio->bi_next = NULL;
-                       generic_make_request(bio);
+                       if (unlikely((bio->bi_rw & REQ_DISCARD) &&
+                           !blk_queue_discard(bdev_get_queue(bio->bi_bdev))))
+                               /* Just ignore it */
+                               bio_endio(bio, 0);
+                       else
+                               generic_make_request(bio);
                        bio = next;
                }
        } else
@@ -1057,6 +1066,7 @@ static void make_request(struct mddev *mddev, struct bio * bio)
        const int rw = bio_data_dir(bio);
        const unsigned long do_sync = (bio->bi_rw & REQ_SYNC);
        const unsigned long do_fua = (bio->bi_rw & REQ_FUA);
+       const unsigned long do_discard = (bio->bi_rw & (REQ_DISCARD | REQ_SECURE));
        unsigned long flags;
        struct md_rdev *blocked_rdev;
        int sectors_handled;
@@ -1077,7 +1087,7 @@ static void make_request(struct mddev *mddev, struct bio * bio)
                         || conf->prev.near_copies < conf->prev.raid_disks))) {
                struct bio_pair *bp;
                /* Sanity check -- queue functions should prevent this happening */
-               if (bio->bi_vcnt != 1 ||
+               if ((bio->bi_vcnt != 1 && bio->bi_vcnt !=0) ||
                    bio->bi_idx != 0)
                        goto bad_map;
                /* This is a one page bio that upper layers
@@ -1406,7 +1416,7 @@ retry_write:
                                                      conf->mirrors[d].rdev));
                mbio->bi_bdev = conf->mirrors[d].rdev->bdev;
                mbio->bi_end_io = raid10_end_write_request;
-               mbio->bi_rw = WRITE | do_sync | do_fua;
+               mbio->bi_rw = WRITE | do_sync | do_fua | do_discard;
                mbio->bi_private = r10_bio;
 
                atomic_inc(&r10_bio->remaining);
@@ -1435,7 +1445,7 @@ retry_write:
                                           conf->mirrors[d].replacement));
                mbio->bi_bdev = conf->mirrors[d].replacement->bdev;
                mbio->bi_end_io = raid10_end_write_request;
-               mbio->bi_rw = WRITE | do_sync | do_fua;
+               mbio->bi_rw = WRITE | do_sync | do_fua | do_discard;
                mbio->bi_private = r10_bio;
 
                atomic_inc(&r10_bio->remaining);
@@ -1719,6 +1729,9 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev)
                clear_bit(Unmerged, &rdev->flags);
        }
        md_integrity_add_rdev(rdev, mddev);
+       if (blk_queue_discard(bdev_get_queue(rdev->bdev)))
+               queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mddev->queue);
+
        print_conf(conf);
        return err;
 }
@@ -2667,8 +2680,9 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio)
        }
 }
 
-static void raid10d(struct mddev *mddev)
+static void raid10d(struct md_thread *thread)
 {
+       struct mddev *mddev = thread->mddev;
        struct r10bio *r10_bio;
        unsigned long flags;
        struct r10conf *conf = mddev->private;
@@ -3476,6 +3490,7 @@ static int run(struct mddev *mddev)
        sector_t size;
        sector_t min_offset_diff = 0;
        int first = 1;
+       bool discard_supported = false;
 
        if (mddev->private == NULL) {
                conf = setup_conf(mddev);
@@ -3490,6 +3505,7 @@ static int run(struct mddev *mddev)
        mddev->thread = conf->thread;
        conf->thread = NULL;
 
+       blk_queue_max_discard_sectors(mddev->queue, mddev->chunk_sectors);
        chunk_size = mddev->chunk_sectors << 9;
        if (mddev->queue) {
                blk_queue_io_min(mddev->queue, chunk_size);
@@ -3537,8 +3553,16 @@ static int run(struct mddev *mddev)
                                          rdev->data_offset << 9);
 
                disk->head_position = 0;
+
+               if (blk_queue_discard(bdev_get_queue(rdev->bdev)))
+                       discard_supported = true;
        }
 
+       if (discard_supported)
+               queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, mddev->queue);
+       else
+               queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, mddev->queue);
+
        /* need to check that every block has at least one working mirror */
        if (!enough(conf, -1)) {
                printk(KERN_ERR "md/raid10:%s: not enough operational mirrors.\n",
@@ -4414,14 +4438,18 @@ static int handle_reshape_read_error(struct mddev *mddev,
 {
        /* Use sync reads to get the blocks from somewhere else */
        int sectors = r10_bio->sectors;
-       struct r10bio r10b;
        struct r10conf *conf = mddev->private;
+       struct {
+               struct r10bio r10_bio;
+               struct r10dev devs[conf->copies];
+       } on_stack;
+       struct r10bio *r10b = &on_stack.r10_bio;
        int slot = 0;
        int idx = 0;
        struct bio_vec *bvec = r10_bio->master_bio->bi_io_vec;
 
-       r10b.sector = r10_bio->sector;
-       __raid10_find_phys(&conf->prev, &r10b);
+       r10b->sector = r10_bio->sector;
+       __raid10_find_phys(&conf->prev, r10b);
 
        while (sectors) {
                int s = sectors;
@@ -4432,7 +4460,7 @@ static int handle_reshape_read_error(struct mddev *mddev,
                        s = PAGE_SIZE >> 9;
 
                while (!success) {
-                       int d = r10b.devs[slot].devnum;
+                       int d = r10b->devs[slot].devnum;
                        struct md_rdev *rdev = conf->mirrors[d].rdev;
                        sector_t addr;
                        if (rdev == NULL ||
@@ -4440,7 +4468,7 @@ static int handle_reshape_read_error(struct mddev *mddev,
                            !test_bit(In_sync, &rdev->flags))
                                goto failed;
 
-                       addr = r10b.devs[slot].addr + idx * PAGE_SIZE;
+                       addr = r10b->devs[slot].addr + idx * PAGE_SIZE;
                        success = sync_page_io(rdev,
                                               addr,
                                               s << 9,
index 007c2c68dd8369f2acbcd9ae8d3c155399d13674..1054cf602345250f059ef81fae8bf9ef330cccd1 100644 (file)
@@ -110,7 +110,7 @@ struct r10bio {
         * We choose the number when they are allocated.
         * We sometimes need an extra bio to write to the replacement.
         */
-       struct {
+       struct r10dev {
                struct bio      *bio;
                union {
                        struct bio      *repl_bio; /* used for resync and
index adda94df5eb2352775e64fb7fae4e88c6e89a98b..7c8151a073c1ac73a2f420e91759a425bfbbf34d 100644 (file)
@@ -196,6 +196,21 @@ static int stripe_operations_active(struct stripe_head *sh)
               test_bit(STRIPE_COMPUTE_RUN, &sh->state);
 }
 
+static void raid5_wakeup_stripe_thread(struct stripe_head *sh)
+{
+       struct r5conf *conf = sh->raid_conf;
+       struct raid5_percpu *percpu;
+       int i, orphaned = 1;
+
+       percpu = per_cpu_ptr(conf->percpu, sh->cpu);
+       for_each_cpu(i, &percpu->handle_threads) {
+               md_wakeup_thread(conf->aux_threads[i]->thread);
+               orphaned = 0;
+       }
+       if (orphaned)
+               md_wakeup_thread(conf->mddev->thread);
+}
+
 static void do_release_stripe(struct r5conf *conf, struct stripe_head *sh)
 {
        BUG_ON(!list_empty(&sh->lru));
@@ -208,9 +223,19 @@ static void do_release_stripe(struct r5conf *conf, struct stripe_head *sh)
                           sh->bm_seq - conf->seq_write > 0)
                        list_add_tail(&sh->lru, &conf->bitmap_list);
                else {
+                       int cpu = sh->cpu;
+                       struct raid5_percpu *percpu;
+                       if (!cpu_online(cpu)) {
+                               cpu = cpumask_any(cpu_online_mask);
+                               sh->cpu = cpu;
+                       }
+                       percpu = per_cpu_ptr(conf->percpu, cpu);
+
                        clear_bit(STRIPE_DELAYED, &sh->state);
                        clear_bit(STRIPE_BIT_DELAY, &sh->state);
-                       list_add_tail(&sh->lru, &conf->handle_list);
+                       list_add_tail(&sh->lru, &percpu->handle_list);
+                       raid5_wakeup_stripe_thread(sh);
+                       return;
                }
                md_wakeup_thread(conf->mddev->thread);
        } else {
@@ -355,6 +380,7 @@ static void init_stripe(struct stripe_head *sh, sector_t sector, int previous)
                raid5_build_block(sh, i, previous);
        }
        insert_hash(conf, sh);
+       sh->cpu = smp_processor_id();
 }
 
 static struct stripe_head *__find_stripe(struct r5conf *conf, sector_t sector,
@@ -3689,12 +3715,19 @@ static void raid5_activate_delayed(struct r5conf *conf)
                while (!list_empty(&conf->delayed_list)) {
                        struct list_head *l = conf->delayed_list.next;
                        struct stripe_head *sh;
+                       int cpu;
                        sh = list_entry(l, struct stripe_head, lru);
                        list_del_init(l);
                        clear_bit(STRIPE_DELAYED, &sh->state);
                        if (!test_and_set_bit(STRIPE_PREREAD_ACTIVE, &sh->state))
                                atomic_inc(&conf->preread_active_stripes);
                        list_add_tail(&sh->lru, &conf->hold_list);
+                       cpu = sh->cpu;
+                       if (!cpu_online(cpu)) {
+                               cpu = cpumask_any(cpu_online_mask);
+                               sh->cpu = cpu;
+                       }
+                       raid5_wakeup_stripe_thread(sh);
                }
        }
 }
@@ -3968,18 +4001,29 @@ static int chunk_aligned_read(struct mddev *mddev, struct bio * raid_bio)
  * head of the hold_list has changed, i.e. the head was promoted to the
  * handle_list.
  */
-static struct stripe_head *__get_priority_stripe(struct r5conf *conf)
-{
-       struct stripe_head *sh;
-
+static struct stripe_head *__get_priority_stripe(struct r5conf *conf,
+       cpumask_t *mask)
+{
+       struct stripe_head *sh = NULL, *tmp;
+       struct list_head *handle_list = NULL;
+       int cpu;
+
+       /* Should we take action to avoid starvation of latter CPUs ? */
+       for_each_cpu(cpu, mask) {
+               struct raid5_percpu *percpu = per_cpu_ptr(conf->percpu, cpu);
+               if (!list_empty(&percpu->handle_list)) {
+                       handle_list = &percpu->handle_list;
+                       break;
+               }
+       }
        pr_debug("%s: handle: %s hold: %s full_writes: %d bypass_count: %d\n",
                  __func__,
-                 list_empty(&conf->handle_list) ? "empty" : "busy",
+                 !handle_list ? "empty" : "busy",
                  list_empty(&conf->hold_list) ? "empty" : "busy",
                  atomic_read(&conf->pending_full_writes), conf->bypass_count);
 
-       if (!list_empty(&conf->handle_list)) {
-               sh = list_entry(conf->handle_list.next, typeof(*sh), lru);
+       if (handle_list) {
+               sh = list_entry(handle_list->next, typeof(*sh), lru);
 
                if (list_empty(&conf->hold_list))
                        conf->bypass_count = 0;
@@ -3997,12 +4041,23 @@ static struct stripe_head *__get_priority_stripe(struct r5conf *conf)
                   ((conf->bypass_threshold &&
                     conf->bypass_count > conf->bypass_threshold) ||
                    atomic_read(&conf->pending_full_writes) == 0)) {
-               sh = list_entry(conf->hold_list.next,
-                               typeof(*sh), lru);
-               conf->bypass_count -= conf->bypass_threshold;
-               if (conf->bypass_count < 0)
-                       conf->bypass_count = 0;
-       } else
+
+               list_for_each_entry(tmp, &conf->hold_list,  lru) {
+                       if (cpumask_test_cpu(tmp->cpu, mask) ||
+                           !cpu_online(tmp->cpu)) {
+                               sh = tmp;
+                               break;
+                       }
+               }
+
+               if (sh) {
+                       conf->bypass_count -= conf->bypass_threshold;
+                       if (conf->bypass_count < 0)
+                               conf->bypass_count = 0;
+               }
+       }
+
+       if (!sh)
                return NULL;
 
        list_del_init(&sh->lru);
@@ -4594,13 +4649,13 @@ static int  retry_aligned_read(struct r5conf *conf, struct bio *raid_bio)
 }
 
 #define MAX_STRIPE_BATCH 8
-static int handle_active_stripes(struct r5conf *conf)
+static int handle_active_stripes(struct r5conf *conf, cpumask_t *mask)
 {
        struct stripe_head *batch[MAX_STRIPE_BATCH], *sh;
        int i, batch_size = 0;
 
        while (batch_size < MAX_STRIPE_BATCH &&
-                       (sh = __get_priority_stripe(conf)) != NULL)
+                       (sh = __get_priority_stripe(conf, mask)) != NULL)
                batch[batch_size++] = sh;
 
        if (batch_size == 0)
@@ -4618,6 +4673,35 @@ static int handle_active_stripes(struct r5conf *conf)
        return batch_size;
 }
 
+static void raid5auxd(struct md_thread *thread)
+{
+       struct mddev *mddev = thread->mddev;
+       struct r5conf *conf = mddev->private;
+       struct blk_plug plug;
+       int handled;
+       struct raid5_auxth *auxth = thread->private;
+
+       pr_debug("+++ raid5auxd active\n");
+
+       blk_start_plug(&plug);
+       handled = 0;
+       spin_lock_irq(&conf->device_lock);
+       while (1) {
+               int batch_size;
+
+               batch_size = handle_active_stripes(conf, &auxth->work_mask);
+               if (!batch_size)
+                       break;
+               handled += batch_size;
+       }
+       pr_debug("%d stripes handled\n", handled);
+
+       spin_unlock_irq(&conf->device_lock);
+       blk_finish_plug(&plug);
+
+       pr_debug("--- raid5auxd inactive\n");
+}
+
 /*
  * This is our raid5 kernel thread.
  *
@@ -4625,8 +4709,9 @@ static int handle_active_stripes(struct r5conf *conf)
  * During the scan, completed stripes are saved for us by the interrupt
  * handler, so that they will not have to wait for our next wakeup.
  */
-static void raid5d(struct mddev *mddev)
+static void raid5d(struct md_thread *thread)
 {
+       struct mddev *mddev = thread->mddev;
        struct r5conf *conf = mddev->private;
        int handled;
        struct blk_plug plug;
@@ -4664,7 +4749,7 @@ static void raid5d(struct mddev *mddev)
                        handled++;
                }
 
-               batch_size = handle_active_stripes(conf);
+               batch_size = handle_active_stripes(conf, &conf->work_mask);
                if (!batch_size)
                        break;
                handled += batch_size;
@@ -4793,10 +4878,270 @@ stripe_cache_active_show(struct mddev *mddev, char *page)
 static struct md_sysfs_entry
 raid5_stripecache_active = __ATTR_RO(stripe_cache_active);
 
+static void raid5_update_threads_handle_mask(struct mddev *mddev)
+{
+       int cpu, i;
+       struct raid5_percpu *percpu;
+       struct r5conf *conf = mddev->private;
+
+       for_each_online_cpu(cpu) {
+               percpu = per_cpu_ptr(conf->percpu, cpu);
+               cpumask_clear(&percpu->handle_threads);
+       }
+       cpumask_copy(&conf->work_mask, cpu_online_mask);
+
+       for (i = 0; i < conf->aux_thread_num; i++) {
+               cpumask_t *work_mask = &conf->aux_threads[i]->work_mask;
+               for_each_cpu(cpu, work_mask) {
+                       percpu = per_cpu_ptr(conf->percpu, cpu);
+                       cpumask_set_cpu(i, &percpu->handle_threads);
+               }
+               cpumask_andnot(&conf->work_mask, &conf->work_mask,
+                               work_mask);
+       }
+}
+
+struct raid5_auxth_sysfs {
+       struct attribute attr;
+       ssize_t (*show)(struct mddev *, struct raid5_auxth *, char *);
+       ssize_t (*store)(struct mddev *, struct raid5_auxth *,
+               const char *, size_t);
+};
+
+static ssize_t raid5_show_thread_cpulist(struct mddev *mddev,
+       struct raid5_auxth *thread, char *page)
+{
+       if (!mddev->private)
+               return 0;
+       return cpulist_scnprintf(page, PAGE_SIZE, &thread->work_mask);
+}
+
+static ssize_t
+raid5_store_thread_cpulist(struct mddev *mddev, struct raid5_auxth *thread,
+       const char *page, size_t len)
+{
+       struct r5conf *conf = mddev->private;
+       cpumask_var_t mask;
+
+       if (!conf)
+               return -ENODEV;
+       if (!alloc_cpumask_var(&mask, GFP_KERNEL))
+               return -ENOMEM;
+
+       if (cpulist_parse(page, mask)) {
+               free_cpumask_var(mask);
+               return -EINVAL;
+       }
+
+       get_online_cpus();
+       spin_lock_irq(&conf->device_lock);
+       cpumask_copy(&thread->work_mask, mask);
+       raid5_update_threads_handle_mask(mddev);
+       spin_unlock_irq(&conf->device_lock);
+       put_online_cpus();
+       set_cpus_allowed_ptr(thread->thread->tsk, mask);
+
+       free_cpumask_var(mask);
+       return len;
+}
+
+static struct raid5_auxth_sysfs thread_cpulist =
+__ATTR(cpulist, S_IRUGO|S_IWUSR, raid5_show_thread_cpulist,
+       raid5_store_thread_cpulist);
+
+static struct attribute *auxth_attrs[] = {
+       &thread_cpulist.attr,
+       NULL,
+};
+
+static ssize_t
+raid5_auxth_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
+{
+       struct raid5_auxth_sysfs *entry = container_of(attr,
+               struct raid5_auxth_sysfs, attr);
+       struct raid5_auxth *thread = container_of(kobj,
+               struct raid5_auxth, kobj);
+       struct mddev *mddev = thread->thread->mddev;
+       ssize_t ret;
+
+       if (!entry->show)
+               return -EIO;
+       mddev_lock(mddev);
+       ret = entry->show(mddev, thread, page);
+       mddev_unlock(mddev);
+       return ret;
+}
+
+static ssize_t
+raid5_auxth_attr_store(struct kobject *kobj, struct attribute *attr,
+             const char *page, size_t length)
+{
+       struct raid5_auxth_sysfs *entry = container_of(attr,
+               struct raid5_auxth_sysfs, attr);
+       struct raid5_auxth *thread = container_of(kobj,
+               struct raid5_auxth, kobj);
+       struct mddev *mddev = thread->thread->mddev;
+       ssize_t ret;
+
+       if (!entry->store)
+               return -EIO;
+       if (!capable(CAP_SYS_ADMIN))
+               return -EACCES;
+       mddev_lock(mddev);
+       ret = entry->store(mddev, thread, page, length);
+       mddev_unlock(mddev);
+       return ret;
+}
+
+static void raid5_auxth_release(struct kobject *kobj)
+{
+       struct raid5_auxth *thread = container_of(kobj,
+               struct raid5_auxth, kobj);
+       kfree(thread);
+}
+
+static const struct sysfs_ops raid5_auxth_sysfsops = {
+       .show = raid5_auxth_attr_show,
+       .store = raid5_auxth_attr_store,
+};
+static struct kobj_type raid5_auxth_ktype = {
+       .release = raid5_auxth_release,
+       .sysfs_ops = &raid5_auxth_sysfsops,
+       .default_attrs = auxth_attrs,
+};
+
+static ssize_t
+raid5_show_auxthread_number(struct mddev *mddev, char *page)
+{
+       struct r5conf *conf = mddev->private;
+       if (conf)
+               return sprintf(page, "%d\n", conf->aux_thread_num);
+       else
+               return 0;
+}
+
+static void raid5_auxth_delete(struct work_struct *ws)
+{
+       struct raid5_auxth *thread = container_of(ws, struct raid5_auxth,
+               del_work);
+
+       kobject_del(&thread->kobj);
+       kobject_put(&thread->kobj);
+}
+
+static void __free_aux_thread(struct mddev *mddev, struct raid5_auxth *thread)
+{
+       md_unregister_thread(&thread->thread);
+       INIT_WORK(&thread->del_work, raid5_auxth_delete);
+       kobject_get(&thread->kobj);
+       md_queue_misc_work(&thread->del_work);
+}
+
+static struct raid5_auxth *__create_aux_thread(struct mddev *mddev, int i)
+{
+       struct raid5_auxth *thread;
+       char name[10];
+
+       thread = kzalloc(sizeof(*thread), GFP_KERNEL);
+       if (!thread)
+               return NULL;
+       snprintf(name, 10, "aux%d", i);
+       thread->thread = md_register_thread(raid5auxd, mddev, name);
+       if (!thread->thread) {
+               kfree(thread);
+               return NULL;
+       }
+       thread->thread->private = thread;
+
+       cpumask_copy(&thread->work_mask, cpu_online_mask);
+
+       if (kobject_init_and_add(&thread->kobj, &raid5_auxth_ktype,
+           &mddev->kobj, "auxth%d", i)) {
+               md_unregister_thread(&thread->thread);
+               kfree(thread);
+               return NULL;
+       }
+       return thread;
+}
+
+static ssize_t
+raid5_store_auxthread_number(struct mddev *mddev, const char *page, size_t len)
+{
+       struct r5conf *conf = mddev->private;
+       unsigned long new;
+       int i;
+       struct raid5_auxth **threads;
+
+       if (len >= PAGE_SIZE)
+               return -EINVAL;
+       if (!conf)
+               return -ENODEV;
+
+       if (kstrtoul(page, 10, &new))
+               return -EINVAL;
+
+       if (new == conf->aux_thread_num)
+               return len;
+
+       /* There is no point creating more threads than cpu number */
+       if (new > num_online_cpus())
+               return -EINVAL;
+
+       if (new > conf->aux_thread_num) {
+               threads = kzalloc(sizeof(struct raid5_auxth *) * new,
+                               GFP_KERNEL);
+               if (!threads)
+                       return -ENOMEM;
+
+               i = conf->aux_thread_num;
+               while (i < new) {
+                       threads[i] = __create_aux_thread(mddev, i);
+                       if (!threads[i])
+                               goto error;
+
+                       i++;
+               }
+               memcpy(threads, conf->aux_threads,
+                       sizeof(struct raid5_auxth *) * conf->aux_thread_num);
+               get_online_cpus();
+               spin_lock_irq(&conf->device_lock);
+               kfree(conf->aux_threads);
+               conf->aux_threads = threads;
+               conf->aux_thread_num = new;
+               raid5_update_threads_handle_mask(mddev);
+               spin_unlock_irq(&conf->device_lock);
+               put_online_cpus();
+       } else {
+               int old = conf->aux_thread_num;
+
+               get_online_cpus();
+               spin_lock_irq(&conf->device_lock);
+               conf->aux_thread_num = new;
+               raid5_update_threads_handle_mask(mddev);
+               spin_unlock_irq(&conf->device_lock);
+               put_online_cpus();
+               for (i = new; i < old; i++)
+                       __free_aux_thread(mddev, conf->aux_threads[i]);
+       }
+
+       return len;
+error:
+       while (--i >= conf->aux_thread_num)
+               __free_aux_thread(mddev, threads[i]);
+       kfree(threads);
+       return -ENOMEM;
+}
+
+static struct md_sysfs_entry
+raid5_auxthread_number = __ATTR(auxthread_number, S_IRUGO|S_IWUSR,
+                               raid5_show_auxthread_number,
+                               raid5_store_auxthread_number);
+
 static struct attribute *raid5_attrs[] =  {
        &raid5_stripecache_size.attr,
        &raid5_stripecache_active.attr,
        &raid5_preread_bypass_threshold.attr,
+       &raid5_auxthread_number.attr,
        NULL,
 };
 static struct attribute_group raid5_attrs_group = {
@@ -4844,6 +5189,7 @@ static void raid5_free_percpu(struct r5conf *conf)
 
 static void free_conf(struct r5conf *conf)
 {
+       kfree(conf->aux_threads);
        shrink_stripes(conf);
        raid5_free_percpu(conf);
        kfree(conf->disks);
@@ -4856,7 +5202,7 @@ static int raid456_cpu_notify(struct notifier_block *nfb, unsigned long action,
                              void *hcpu)
 {
        struct r5conf *conf = container_of(nfb, struct r5conf, cpu_notify);
-       long cpu = (long)hcpu;
+       long cpu = (long)hcpu, anycpu;
        struct raid5_percpu *percpu = per_cpu_ptr(conf->percpu, cpu);
 
        switch (action) {
@@ -4875,9 +5221,17 @@ static int raid456_cpu_notify(struct notifier_block *nfb, unsigned long action,
                               __func__, cpu);
                        return notifier_from_errno(-ENOMEM);
                }
+               INIT_LIST_HEAD(&(percpu->handle_list));
+               cpumask_clear(&percpu->handle_threads);
                break;
        case CPU_DEAD:
        case CPU_DEAD_FROZEN:
+               spin_lock_irq(&conf->device_lock);
+               anycpu = cpumask_any(cpu_online_mask);
+               list_splice_tail_init(&percpu->handle_list,
+                       &per_cpu_ptr(conf->percpu, anycpu)->handle_list);
+               spin_unlock_irq(&conf->device_lock);
+
                safe_put_page(percpu->spare_page);
                kfree(percpu->scribble);
                percpu->spare_page = NULL;
@@ -4886,6 +5240,10 @@ static int raid456_cpu_notify(struct notifier_block *nfb, unsigned long action,
        default:
                break;
        }
+
+       spin_lock_irq(&conf->device_lock);
+       raid5_update_threads_handle_mask(conf->mddev);
+       spin_unlock_irq(&conf->device_lock);
        return NOTIFY_OK;
 }
 #endif
@@ -4906,20 +5264,24 @@ static int raid5_alloc_percpu(struct r5conf *conf)
        get_online_cpus();
        err = 0;
        for_each_present_cpu(cpu) {
+               struct raid5_percpu *percpu = per_cpu_ptr(conf->percpu, cpu);
+
                if (conf->level == 6) {
                        spare_page = alloc_page(GFP_KERNEL);
                        if (!spare_page) {
                                err = -ENOMEM;
                                break;
                        }
-                       per_cpu_ptr(conf->percpu, cpu)->spare_page = spare_page;
+                       percpu->spare_page = spare_page;
                }
                scribble = kmalloc(conf->scribble_len, GFP_KERNEL);
                if (!scribble) {
                        err = -ENOMEM;
                        break;
                }
-               per_cpu_ptr(conf->percpu, cpu)->scribble = scribble;
+               percpu->scribble = scribble;
+               INIT_LIST_HEAD(&percpu->handle_list);
+               cpumask_clear(&percpu->handle_threads);
        }
 #ifdef CONFIG_HOTPLUG_CPU
        conf->cpu_notify.notifier_call = raid456_cpu_notify;
@@ -4975,7 +5337,6 @@ static struct r5conf *setup_conf(struct mddev *mddev)
        spin_lock_init(&conf->device_lock);
        init_waitqueue_head(&conf->wait_for_stripe);
        init_waitqueue_head(&conf->wait_for_overlap);
-       INIT_LIST_HEAD(&conf->handle_list);
        INIT_LIST_HEAD(&conf->hold_list);
        INIT_LIST_HEAD(&conf->delayed_list);
        INIT_LIST_HEAD(&conf->bitmap_list);
@@ -4986,6 +5347,8 @@ static struct r5conf *setup_conf(struct mddev *mddev)
        conf->bypass_threshold = BYPASS_THRESHOLD;
        conf->recovery_disabled = mddev->recovery_disabled - 1;
 
+       cpumask_copy(&conf->work_mask, cpu_online_mask);
+
        conf->raid_disks = mddev->raid_disks;
        if (mddev->reshape_position == MaxSector)
                conf->previous_raid_disks = mddev->raid_disks;
@@ -5402,6 +5765,10 @@ abort:
 static int stop(struct mddev *mddev)
 {
        struct r5conf *conf = mddev->private;
+       int i;
+
+       for (i = 0; i < conf->aux_thread_num; i++)
+               __free_aux_thread(mddev, conf->aux_threads[i]);
 
        md_unregister_thread(&mddev->thread);
        if (mddev->queue)
index a9fc24901edad817b599219e9fb4c596c4c9e29b..813b6c18f2501211d407dd446f41ded9f0d01ca8 100644 (file)
@@ -211,6 +211,7 @@ struct stripe_head {
        enum check_states       check_state;
        enum reconstruct_states reconstruct_state;
        spinlock_t              stripe_lock;
+       int                     cpu;
        /**
         * struct stripe_operations
         * @target - STRIPE_OP_COMPUTE_BLK target
@@ -364,6 +365,14 @@ struct disk_info {
        struct md_rdev  *rdev, *replacement;
 };
 
+struct raid5_auxth {
+       struct md_thread        *thread;
+       /* which CPUs should the auxiliary thread handle stripes from */
+       cpumask_t               work_mask;
+       struct kobject          kobj;
+       struct work_struct      del_work;
+};
+
 struct r5conf {
        struct hlist_head       *stripe_hashtbl;
        struct mddev            *mddev;
@@ -432,6 +441,12 @@ struct r5conf {
                                              * lists and performing address
                                              * conversions
                                              */
+               struct list_head handle_list;
+               cpumask_t       handle_threads; /* Which threads can the CPU's
+                                                * stripes be handled. It really
+                                                * is a bitmap to aux_threads[],
+                                                * but has max bits NR_CPUS
+                                                */
        } __percpu *percpu;
        size_t                  scribble_len; /* size of scribble region must be
                                               * associated with conf to handle
@@ -459,6 +474,10 @@ struct r5conf {
         * the new thread here until we fully activate the array.
         */
        struct md_thread        *thread;
+       int                     aux_thread_num;
+       struct raid5_auxth      **aux_threads;
+       /* which CPUs should raid5d thread handle stripes from */
+       cpumask_t               work_mask;
 };
 
 /*
index d6b1cf66042d196b40a7b99c18241fe186840d1d..bb6ee5191eb183a415c6de0350a3ae02877a3fd2 100644 (file)
@@ -23,9 +23,6 @@
 #include <media/saa7146.h>
 #include <linux/module.h>
 
-LIST_HEAD(saa7146_devices);
-DEFINE_MUTEX(saa7146_devices_lock);
-
 static int saa7146_num;
 
 unsigned int saa7146_debug;
@@ -482,8 +479,6 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
           set it explicitly. */
        pci_set_drvdata(pci, &dev->v4l2_dev);
 
-       INIT_LIST_HEAD(&dev->item);
-       list_add_tail(&dev->item,&saa7146_devices);
        saa7146_num++;
 
        err = 0;
@@ -545,7 +540,6 @@ static void saa7146_remove_one(struct pci_dev *pdev)
 
        iounmap(dev->mem);
        pci_release_region(pdev, 0);
-       list_del(&dev->item);
        pci_disable_device(pdev);
        kfree(dev);
 
@@ -592,8 +586,6 @@ EXPORT_SYMBOL_GPL(saa7146_setgpio);
 EXPORT_SYMBOL_GPL(saa7146_i2c_adapter_prepare);
 
 EXPORT_SYMBOL_GPL(saa7146_debug);
-EXPORT_SYMBOL_GPL(saa7146_devices);
-EXPORT_SYMBOL_GPL(saa7146_devices_lock);
 
 MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
 MODULE_DESCRIPTION("driver for generic saa7146-based hardware");
index 0cdbd742974ae0404ccf724d734ea5da08a6f821..b3890bd49df6089fa0871f70d7b09abc47375b4c 100644 (file)
@@ -201,7 +201,7 @@ static int fops_open(struct file *file)
 
        DEB_EE("file:%p, dev:%s\n", file, video_device_node_name(vdev));
 
-       if (mutex_lock_interruptible(&saa7146_devices_lock))
+       if (mutex_lock_interruptible(vdev->lock))
                return -ERESTARTSYS;
 
        DEB_D("using: %p\n", dev);
@@ -253,7 +253,7 @@ out:
                kfree(fh);
                file->private_data = NULL;
        }
-       mutex_unlock(&saa7146_devices_lock);
+       mutex_unlock(vdev->lock);
        return result;
 }
 
@@ -265,7 +265,7 @@ static int fops_release(struct file *file)
 
        DEB_EE("file:%p\n", file);
 
-       if (mutex_lock_interruptible(&saa7146_devices_lock))
+       if (mutex_lock_interruptible(vdev->lock))
                return -ERESTARTSYS;
 
        if (vdev->vfl_type == VFL_TYPE_VBI) {
@@ -283,7 +283,7 @@ static int fops_release(struct file *file)
        file->private_data = NULL;
        kfree(fh);
 
-       mutex_unlock(&saa7146_devices_lock);
+       mutex_unlock(vdev->lock);
 
        return 0;
 }
@@ -293,6 +293,7 @@ static int fops_mmap(struct file *file, struct vm_area_struct * vma)
        struct video_device *vdev = video_devdata(file);
        struct saa7146_fh *fh = file->private_data;
        struct videobuf_queue *q;
+       int res;
 
        switch (vdev->vfl_type) {
        case VFL_TYPE_GRABBER: {
@@ -314,10 +315,14 @@ static int fops_mmap(struct file *file, struct vm_area_struct * vma)
                return 0;
        }
 
-       return videobuf_mmap_mapper(q,vma);
+       if (mutex_lock_interruptible(vdev->lock))
+               return -ERESTARTSYS;
+       res = videobuf_mmap_mapper(q, vma);
+       mutex_unlock(vdev->lock);
+       return res;
 }
 
-static unsigned int fops_poll(struct file *file, struct poll_table_struct *wait)
+static unsigned int __fops_poll(struct file *file, struct poll_table_struct *wait)
 {
        struct video_device *vdev = video_devdata(file);
        struct saa7146_fh *fh = file->private_data;
@@ -356,10 +361,22 @@ static unsigned int fops_poll(struct file *file, struct poll_table_struct *wait)
        return res;
 }
 
+static unsigned int fops_poll(struct file *file, struct poll_table_struct *wait)
+{
+       struct video_device *vdev = video_devdata(file);
+       unsigned int res;
+
+       mutex_lock(vdev->lock);
+       res = __fops_poll(file, wait);
+       mutex_unlock(vdev->lock);
+       return res;
+}
+
 static ssize_t fops_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
 {
        struct video_device *vdev = video_devdata(file);
        struct saa7146_fh *fh = file->private_data;
+       int ret;
 
        switch (vdev->vfl_type) {
        case VFL_TYPE_GRABBER:
@@ -373,8 +390,13 @@ static ssize_t fops_read(struct file *file, char __user *data, size_t count, lof
                DEB_EE("V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, data:%p, count:%lu\n",
                       file, data, (unsigned long)count);
 */
-               if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
-                       return saa7146_vbi_uops.read(file,data,count,ppos);
+               if (fh->dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE) {
+                       if (mutex_lock_interruptible(vdev->lock))
+                               return -ERESTARTSYS;
+                       ret = saa7146_vbi_uops.read(file, data, count, ppos);
+                       mutex_unlock(vdev->lock);
+                       return ret;
+               }
                return -EINVAL;
        default:
                BUG();
@@ -386,15 +408,20 @@ static ssize_t fops_write(struct file *file, const char __user *data, size_t cou
 {
        struct video_device *vdev = video_devdata(file);
        struct saa7146_fh *fh = file->private_data;
+       int ret;
 
        switch (vdev->vfl_type) {
        case VFL_TYPE_GRABBER:
                return -EINVAL;
        case VFL_TYPE_VBI:
-               if (fh->dev->ext_vv_data->vbi_fops.write)
-                       return fh->dev->ext_vv_data->vbi_fops.write(file, data, count, ppos);
-               else
-                       return -EINVAL;
+               if (fh->dev->ext_vv_data->vbi_fops.write) {
+                       if (mutex_lock_interruptible(vdev->lock))
+                               return -ERESTARTSYS;
+                       ret = fh->dev->ext_vv_data->vbi_fops.write(file, data, count, ppos);
+                       mutex_unlock(vdev->lock);
+                       return ret;
+               }
+               return -EINVAL;
        default:
                BUG();
                return -EINVAL;
@@ -584,10 +611,6 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
        else
                vfd->ioctl_ops = &dev->ext_vv_data->vbi_ops;
        vfd->release = video_device_release;
-       /* Locking in file operations other than ioctl should be done by
-          the driver, not the V4L2 core.
-          This driver needs auditing so that this flag can be removed. */
-       set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
        vfd->lock = &dev->v4l2_lock;
        vfd->v4l2_dev = &dev->v4l2_dev;
        vfd->tvnorms = 0;
index 2d79b1f5d5ebcebe9a00321ee278239ca64d0a7f..bdc39e11030ea8ddd5d9634c8d41b8ed0f26e983 100644 (file)
@@ -288,7 +288,7 @@ static int qt1010_init_meas1(struct qt1010_priv *priv,
        return qt1010_writereg(priv, 0x1e, 0x00);
 }
 
-static u8 qt1010_init_meas2(struct qt1010_priv *priv,
+static int qt1010_init_meas2(struct qt1010_priv *priv,
                            u8 reg_init_val, u8 *retval)
 {
        u8 i, val;
index 602c2e392b178c255a2d6fa476b8b2fa439f45d0..5d9f028425012e75ee7edefe97c149fb9f415df6 100644 (file)
@@ -18,8 +18,6 @@
  *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
 #include "tda18212.h"
 
 struct tda18212_priv {
@@ -29,16 +27,6 @@ struct tda18212_priv {
        u32 if_frequency;
 };
 
-#define dbg(fmt, arg...)                                       \
-do {                                                           \
-       if (debug)                                              \
-               pr_info("%s: " fmt, __func__, ##arg);           \
-} while (0)
-
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
-
 /* write multiple registers */
 static int tda18212_wr_regs(struct tda18212_priv *priv, u8 reg, u8 *val,
        int len)
@@ -61,8 +49,8 @@ static int tda18212_wr_regs(struct tda18212_priv *priv, u8 reg, u8 *val,
        if (ret == 1) {
                ret = 0;
        } else {
-               pr_warn("i2c wr failed ret:%d reg:%02x len:%d\n",
-                       ret, reg, len);
+               dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d reg=%02x " \
+                               "len=%d\n", KBUILD_MODNAME, ret, reg, len);
                ret = -EREMOTEIO;
        }
        return ret;
@@ -93,8 +81,8 @@ static int tda18212_rd_regs(struct tda18212_priv *priv, u8 reg, u8 *val,
                memcpy(val, buf, len);
                ret = 0;
        } else {
-               pr_warn("i2c rd failed ret:%d reg:%02x len:%d\n",
-                       ret, reg, len);
+               dev_warn(&priv->i2c->dev, "%s: i2c rd failed=%d reg=%02x " \
+                               "len=%d\n", KBUILD_MODNAME, ret, reg, len);
                ret = -EREMOTEIO;
        }
 
@@ -157,8 +145,10 @@ static int tda18212_set_params(struct dvb_frontend *fe)
                [DVBC_8]  = { 0x92, 0x53, 0x03 },
        };
 
-       dbg("delsys=%d RF=%d BW=%d\n",
-           c->delivery_system, c->frequency, c->bandwidth_hz);
+       dev_dbg(&priv->i2c->dev,
+                       "%s: delivery_system=%d frequency=%d bandwidth_hz=%d\n",
+                       __func__, c->delivery_system, c->frequency,
+                       c->bandwidth_hz);
 
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
@@ -247,7 +237,7 @@ exit:
        return ret;
 
 error:
-       dbg("failed:%d\n", ret);
+       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
        goto exit;
 }
 
@@ -287,7 +277,7 @@ struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
 {
        struct tda18212_priv *priv = NULL;
        int ret;
-       u8 val;
+       u8 uninitialized_var(val);
 
        priv = kzalloc(sizeof(struct tda18212_priv), GFP_KERNEL);
        if (priv == NULL)
@@ -306,13 +296,16 @@ struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe,
        if (fe->ops.i2c_gate_ctrl)
                fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
 
-       dbg("ret:%d chip ID:%02x\n", ret, val);
+       dev_dbg(&priv->i2c->dev, "%s: ret=%d chip id=%02x\n", __func__, ret,
+                       val);
        if (ret || val != 0xc7) {
                kfree(priv);
                return NULL;
        }
 
-       pr_info("NXP TDA18212HN successfully identified\n");
+       dev_info(&priv->i2c->dev,
+                       "%s: NXP TDA18212HN successfully identified\n",
+                       KBUILD_MODNAME);
 
        memcpy(&fe->ops.tuner_ops, &tda18212_tuner_ops,
                sizeof(struct dvb_tuner_ops));
index dfb3a831df4540541757f5b6cc0ce7f23f989cd3..8a6f9ca788f067c571f2dcbb2f01b412e06f3f68 100644 (file)
@@ -282,7 +282,7 @@ struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
        struct i2c_adapter *i2c, struct tda18218_config *cfg)
 {
        struct tda18218_priv *priv = NULL;
-       u8 val;
+       u8 uninitialized_var(val);
        int ret;
        /* chip default registers values */
        static u8 def_regs[] = {
index ea0550eafe7d185f9d547a80af33cead4d007050..49e63ec040b60f9e451b4c539e79bba45e86721d 100644 (file)
@@ -1414,8 +1414,8 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg)
                        tuner_err("Failed to request firmware %s\n",
                                  priv->fname);
                        priv->state = XC2028_NODEV;
-               }
-               priv->state = XC2028_WAITING_FIRMWARE;
+               } else
+                       priv->state = XC2028_WAITING_FIRMWARE;
        }
        mutex_unlock(&priv->lock);
 
index 362a8d7c9738e018df797ed7504c215b4595d0de..dc93cf338f366fb3a2200ff0656ca290547f168c 100644 (file)
@@ -62,6 +62,9 @@ struct xc5000_priv {
        u8  radio_input;
 
        int chip_id;
+       u16 pll_register_no;
+       u8 init_status_supported;
+       u8 fw_checksum_supported;
 };
 
 /* Misc Defines */
@@ -111,6 +114,9 @@ struct xc5000_priv {
 #define XREG_PRODUCT_ID   0x08
 #define XREG_BUSY         0x09
 #define XREG_BUILD        0x0D
+#define XREG_TOTALGAIN    0x0F
+#define XREG_FW_CHECKSUM  0x12
+#define XREG_INIT_STATUS  0x13
 
 /*
    Basic firmware description. This will remain with
@@ -208,18 +214,25 @@ static struct XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = {
 struct xc5000_fw_cfg {
        char *name;
        u16 size;
+       u16 pll_reg;
+       u8 init_status_supported;
+       u8 fw_checksum_supported;
 };
 
 #define XC5000A_FIRMWARE "dvb-fe-xc5000-1.6.114.fw"
 static const struct xc5000_fw_cfg xc5000a_1_6_114 = {
        .name = XC5000A_FIRMWARE,
        .size = 12401,
+       .pll_reg = 0x806c,
 };
 
-#define XC5000C_FIRMWARE "dvb-fe-xc5000c-41.024.5.fw"
+#define XC5000C_FIRMWARE "dvb-fe-xc5000c-4.1.30.7.fw"
 static const struct xc5000_fw_cfg xc5000c_41_024_5 = {
        .name = XC5000C_FIRMWARE,
        .size = 16497,
+       .pll_reg = 0x13,
+       .init_status_supported = 1,
+       .fw_checksum_supported = 1,
 };
 
 static inline const struct xc5000_fw_cfg *xc5000_assign_firmware(int chip_id)
@@ -233,7 +246,7 @@ static inline const struct xc5000_fw_cfg *xc5000_assign_firmware(int chip_id)
        }
 }
 
-static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe);
+static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe, int force);
 static int xc5000_is_firmware_loaded(struct dvb_frontend *fe);
 static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val);
 static int xc5000_TunerReset(struct dvb_frontend *fe);
@@ -342,7 +355,7 @@ static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData)
                        }
                }
        }
-       if (WatchDogTimer < 0)
+       if (WatchDogTimer <= 0)
                result = XC_RESULT_I2C_WRITE_FAILURE;
 
        return result;
@@ -541,6 +554,16 @@ static int xc_get_quality(struct xc5000_priv *priv, u16 *quality)
        return xc5000_readreg(priv, XREG_QUALITY, quality);
 }
 
+static int xc_get_analogsnr(struct xc5000_priv *priv, u16 *snr)
+{
+       return xc5000_readreg(priv, XREG_SNR, snr);
+}
+
+static int xc_get_totalgain(struct xc5000_priv *priv, u16 *totalgain)
+{
+       return xc5000_readreg(priv, XREG_TOTALGAIN, totalgain);
+}
+
 static u16 WaitForLock(struct xc5000_priv *priv)
 {
        u16 lockState = 0;
@@ -608,6 +631,9 @@ static int xc5000_fwupload(struct dvb_frontend *fe)
        int ret;
        const struct xc5000_fw_cfg *desired_fw =
                xc5000_assign_firmware(priv->chip_id);
+       priv->pll_register_no = desired_fw->pll_reg;
+       priv->init_status_supported = desired_fw->init_status_supported;
+       priv->fw_checksum_supported = desired_fw->fw_checksum_supported;
 
        /* request the firmware, this will block and timeout */
        printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n",
@@ -652,9 +678,12 @@ static void xc_debug_dump(struct xc5000_priv *priv)
        u32 hsync_freq_hz = 0;
        u16 frame_lines;
        u16 quality;
+       u16 snr;
+       u16 totalgain;
        u8 hw_majorversion = 0, hw_minorversion = 0;
        u8 fw_majorversion = 0, fw_minorversion = 0;
        u16 fw_buildversion = 0;
+       u16 regval;
 
        /* Wait for stats to stabilize.
         * Frame Lines needs two frame times after initial lock
@@ -675,7 +704,7 @@ static void xc_debug_dump(struct xc5000_priv *priv)
        xc_get_version(priv,  &hw_majorversion, &hw_minorversion,
                &fw_majorversion, &fw_minorversion);
        xc_get_buildversion(priv,  &fw_buildversion);
-       dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x.%04x\n",
+       dprintk(1, "*** HW: V%d.%d, FW: V %d.%d.%d\n",
                hw_majorversion, hw_minorversion,
                fw_majorversion, fw_minorversion, fw_buildversion);
 
@@ -686,7 +715,19 @@ static void xc_debug_dump(struct xc5000_priv *priv)
        dprintk(1, "*** Frame lines = %d\n", frame_lines);
 
        xc_get_quality(priv,  &quality);
-       dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality);
+       dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality & 0x07);
+
+       xc_get_analogsnr(priv,  &snr);
+       dprintk(1, "*** Unweighted analog SNR = %d dB\n", snr & 0x3f);
+
+       xc_get_totalgain(priv,  &totalgain);
+       dprintk(1, "*** Total gain = %d.%d dB\n", totalgain / 256,
+               (totalgain % 256) * 100 / 256);
+
+       if (priv->pll_register_no) {
+               xc5000_readreg(priv, priv->pll_register_no, &regval);
+               dprintk(1, "*** PLL lock status = 0x%04x\n", regval);
+       }
 }
 
 static int xc5000_set_params(struct dvb_frontend *fe)
@@ -697,11 +738,9 @@ static int xc5000_set_params(struct dvb_frontend *fe)
        u32 freq = fe->dtv_property_cache.frequency;
        u32 delsys  = fe->dtv_property_cache.delivery_system;
 
-       if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) {
-               if (xc_load_fw_and_init_tuner(fe) != XC_RESULT_SUCCESS) {
-                       dprintk(1, "Unable to load firmware and init tuner\n");
-                       return -EINVAL;
-               }
+       if (xc_load_fw_and_init_tuner(fe, 0) != XC_RESULT_SUCCESS) {
+               dprintk(1, "Unable to load firmware and init tuner\n");
+               return -EINVAL;
        }
 
        dprintk(1, "%s() frequency=%d (Hz)\n", __func__, freq);
@@ -832,6 +871,7 @@ static int xc5000_set_tv_freq(struct dvb_frontend *fe,
        struct analog_parameters *params)
 {
        struct xc5000_priv *priv = fe->tuner_priv;
+       u16 pll_lock_status;
        int ret;
 
        dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n",
@@ -912,6 +952,21 @@ tune_channel:
        if (debug)
                xc_debug_dump(priv);
 
+       if (priv->pll_register_no != 0) {
+               msleep(20);
+               xc5000_readreg(priv, priv->pll_register_no, &pll_lock_status);
+               if (pll_lock_status > 63) {
+                       /* PLL is unlocked, force reload of the firmware */
+                       dprintk(1, "xc5000: PLL not locked (0x%x).  Reloading...\n",
+                               pll_lock_status);
+                       if (xc_load_fw_and_init_tuner(fe, 1) != XC_RESULT_SUCCESS) {
+                               printk(KERN_ERR "xc5000: Unable to reload fw\n");
+                               return -EREMOTEIO;
+                       }
+                       goto tune_channel;
+               }
+       }
+
        return 0;
 }
 
@@ -982,11 +1037,9 @@ static int xc5000_set_analog_params(struct dvb_frontend *fe,
        if (priv->i2c_props.adap == NULL)
                return -EINVAL;
 
-       if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) {
-               if (xc_load_fw_and_init_tuner(fe) != XC_RESULT_SUCCESS) {
-                       dprintk(1, "Unable to load firmware and init tuner\n");
-                       return -EINVAL;
-               }
+       if (xc_load_fw_and_init_tuner(fe, 0) != XC_RESULT_SUCCESS) {
+               dprintk(1, "Unable to load firmware and init tuner\n");
+               return -EINVAL;
        }
 
        switch (params->mode) {
@@ -1042,29 +1095,77 @@ static int xc5000_get_status(struct dvb_frontend *fe, u32 *status)
        return 0;
 }
 
-static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe)
+static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe, int force)
 {
        struct xc5000_priv *priv = fe->tuner_priv;
-       int ret = 0;
+       int ret = XC_RESULT_SUCCESS;
+       u16 pll_lock_status;
+       u16 fw_ck;
+
+       if (force || xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) {
+
+fw_retry:
 
-       if (xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) {
                ret = xc5000_fwupload(fe);
                if (ret != XC_RESULT_SUCCESS)
                        return ret;
-       }
 
-       /* Start the tuner self-calibration process */
-       ret |= xc_initialize(priv);
+               msleep(20);
 
-       /* Wait for calibration to complete.
-        * We could continue but XC5000 will clock stretch subsequent
-        * I2C transactions until calibration is complete.  This way we
-        * don't have to rely on clock stretching working.
-        */
-       xc_wait(100);
+               if (priv->fw_checksum_supported) {
+                       if (xc5000_readreg(priv, XREG_FW_CHECKSUM, &fw_ck)
+                           != XC_RESULT_SUCCESS) {
+                               dprintk(1, "%s() FW checksum reading failed.\n",
+                                       __func__);
+                               goto fw_retry;
+                       }
+
+                       if (fw_ck == 0) {
+                               dprintk(1, "%s() FW checksum failed = 0x%04x\n",
+                                       __func__, fw_ck);
+                               goto fw_retry;
+                       }
+               }
+
+               /* Start the tuner self-calibration process */
+               ret |= xc_initialize(priv);
 
-       /* Default to "CABLE" mode */
-       ret |= xc_write_reg(priv, XREG_SIGNALSOURCE, XC_RF_MODE_CABLE);
+               if (ret != XC_RESULT_SUCCESS)
+                       goto fw_retry;
+
+               /* Wait for calibration to complete.
+                * We could continue but XC5000 will clock stretch subsequent
+                * I2C transactions until calibration is complete.  This way we
+                * don't have to rely on clock stretching working.
+                */
+               xc_wait(100);
+
+               if (priv->init_status_supported) {
+                       if (xc5000_readreg(priv, XREG_INIT_STATUS, &fw_ck) != XC_RESULT_SUCCESS) {
+                               dprintk(1, "%s() FW failed reading init status.\n",
+                                       __func__);
+                               goto fw_retry;
+                       }
+
+                       if (fw_ck == 0) {
+                               dprintk(1, "%s() FW init status failed = 0x%04x\n", __func__, fw_ck);
+                               goto fw_retry;
+                       }
+               }
+
+               if (priv->pll_register_no) {
+                       xc5000_readreg(priv, priv->pll_register_no,
+                                      &pll_lock_status);
+                       if (pll_lock_status > 63) {
+                               /* PLL is unlocked, force reload of the firmware */
+                               printk(KERN_ERR "xc5000: PLL not running after fwload.\n");
+                               goto fw_retry;
+                       }
+               }
+
+               /* Default to "CABLE" mode */
+               ret |= xc_write_reg(priv, XREG_SIGNALSOURCE, XC_RF_MODE_CABLE);
+       }
 
        return ret;
 }
@@ -1097,7 +1198,7 @@ static int xc5000_init(struct dvb_frontend *fe)
        struct xc5000_priv *priv = fe->tuner_priv;
        dprintk(1, "%s()\n", __func__);
 
-       if (xc_load_fw_and_init_tuner(fe) != XC_RESULT_SUCCESS) {
+       if (xc_load_fw_and_init_tuner(fe, 0) != XC_RESULT_SUCCESS) {
                printk(KERN_ERR "xc5000: Unable to initialise tuner\n");
                return -EREMOTEIO;
        }
index f6e40b3a44cc2204f842969deec3ea72c3170b21..3a6ccbc02addcc9e247b76984f9779e261869abb 100644 (file)
@@ -44,6 +44,7 @@ source "drivers/media/dvb/ttpci/Kconfig"
 comment "Supported USB Adapters"
        depends on DVB_CORE && USB && I2C
 source "drivers/media/dvb/dvb-usb/Kconfig"
+source "drivers/media/dvb/dvb-usb-v2/Kconfig"
 source "drivers/media/dvb/ttusb-budget/Kconfig"
 source "drivers/media/dvb/ttusb-dec/Kconfig"
 source "drivers/media/dvb/siano/Kconfig"
index b2cefe637a6410e42bb3ccc762beaa3c3b28901f..8f7e0129d70e3840f1cfda8162228238a454d01a 100644 (file)
@@ -10,6 +10,7 @@ obj-y        := dvb-core/     \
                b2c2/           \
                bt8xx/          \
                dvb-usb/        \
+               dvb-usb-v2/     \
                pluto2/         \
                siano/          \
                dm1105/         \
index aebcdf221ddacece9fd1413aa2c9906c836c88ba..746dfd86aeabe6943cbaaeff64a9083ac5fb6104 100644 (file)
@@ -2287,13 +2287,6 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
                break;
        };
 
-       if (fe->dvb->fe_ioctl_override) {
-               cb_err = fe->dvb->fe_ioctl_override(fe, cmd, parg,
-                                                   DVB_FE_IOCTL_POST);
-               if (cb_err < 0)
-                       return cb_err;
-       }
-
        return err;
 }
 
index fcc6ae98745e018588d21d83af953c6765aad85c..3b2c137b182c43b7ea824e8a19497e3eb1d1b954 100644 (file)
@@ -76,7 +76,6 @@ struct dvb_adapter {
         * after the core handles an ioctl:
         *
         * DVB_FE_IOCTL_PRE indicates that the ioctl has not yet been handled.
-        * DVB_FE_IOCTL_POST indicates that the ioctl has been handled.
         *
         * When DVB_FE_IOCTL_PRE is passed to the callback as the stage arg:
         *
@@ -86,14 +85,10 @@ struct dvb_adapter {
         * return a negative int to prevent dvb-core from handling the ioctl,
         *      and return that value as an error.
         *
-        * When DVB_FE_IOCTL_POST is passed to the callback as the stage arg:
-        *
-        * return 0 to allow the dvb_frontend ioctl handler to exit normally.
-        * return a negative int to cause the dvb_frontend ioctl handler to
-        *      return that value as an error.
+        * WARNING: Don't use it on newer drivers: this only affects DVBv3
+        * calls, and should be removed soon.
         */
 #define DVB_FE_IOCTL_PRE 0
-#define DVB_FE_IOCTL_POST 1
        int (*fe_ioctl_override)(struct dvb_frontend *fe,
                                 unsigned int cmd, void *parg,
                                 unsigned int stage);
diff --git a/drivers/media/dvb/dvb-usb-v2/Kconfig b/drivers/media/dvb/dvb-usb-v2/Kconfig
new file mode 100644 (file)
index 0000000..14a635b
--- /dev/null
@@ -0,0 +1,126 @@
+config DVB_USB_V2
+       tristate "Support for various USB DVB devices v2"
+       depends on DVB_CORE && USB && I2C && RC_CORE
+       help
+         By enabling this you will be able to choose the various supported
+         USB1.1 and USB2.0 DVB devices.
+
+         Almost every USB device needs a firmware, please look into
+         <file:Documentation/dvb/README.dvb-usb>.
+
+         For a complete list of supported USB devices see the LinuxTV DVB Wiki:
+         <http://www.linuxtv.org/wiki/index.php/DVB_USB>
+
+         Say Y if you own a USB DVB device.
+
+config DVB_USB_CYPRESS_FIRMWARE
+       tristate "Cypress firmware helper routines"
+       depends on DVB_USB_V2
+
+config DVB_USB_AF9015
+       tristate "Afatech AF9015 DVB-T USB2.0 support"
+       depends on DVB_USB_V2
+       select DVB_AF9013
+       select DVB_PLL              if !DVB_FE_CUSTOMISE
+       select MEDIA_TUNER_MT2060   if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_QT1010   if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_TDA18218 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE
+       help
+         Say Y here to support the Afatech AF9015 based DVB-T USB2.0 receiver
+
+config DVB_USB_AF9035
+       tristate "Afatech AF9035 DVB-T USB2.0 support"
+       depends on DVB_USB_V2
+       select DVB_AF9033
+       select MEDIA_TUNER_TUA9001 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_FC0011 if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE
+       select MEDIA_TUNER_TDA18218 if !MEDIA_TUNER_CUSTOMISE
+       help
+         Say Y here to support the Afatech AF9035 based DVB USB receiver.
+
+config DVB_USB_ANYSEE
+       tristate "Anysee DVB-T/C USB2.0 support"
+       depends on DVB_USB_V2
+       select DVB_PLL if !DVB_FE_CUSTOMISE
+       select DVB_MT352 if !DVB_FE_CUSTOMISE
+       select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+       select DVB_TDA10023 if !DVB_FE_CUSTOMISE
+       select MEDIA_TUNER_TDA18212 if !MEDIA_TUNER_CUSTOMISE
+       select DVB_CX24116 if !DVB_FE_CUSTOMISE
+       select DVB_STV0900 if !DVB_FE_CUSTOMISE
+       select DVB_STV6110 if !DVB_FE_CUSTOMISE
+       select DVB_ISL6423 if !DVB_FE_CUSTOMISE
+       select DVB_CXD2820R if !DVB_FE_CUSTOMISE
+       help
+         Say Y here to support the Anysee E30, Anysee E30 Plus or
+         Anysee E30 C Plus DVB USB2.0 receiver.
+
+config DVB_USB_AU6610
+       tristate "Alcor Micro AU6610 USB2.0 support"
+       depends on DVB_USB_V2
+       select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+       select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
+       help
+         Say Y here to support the Sigmatek DVB-110 DVB-T USB2.0 receiver.
+
+config DVB_USB_AZ6007
+       tristate "AzureWave 6007 and clones DVB-T/C USB2.0 support"
+       depends on DVB_USB_V2
+       select DVB_USB_CYPRESS_FIRMWARE
+       select DVB_DRXK if !DVB_FE_CUSTOMISE
+       select MEDIA_TUNER_MT2063 if !DVB_FE_CUSTOMISE
+       help
+         Say Y here to support the AZ6007 receivers like Terratec H7.
+
+config DVB_USB_CE6230
+       tristate "Intel CE6230 DVB-T USB2.0 support"
+       depends on DVB_USB_V2
+       select DVB_ZL10353
+       select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
+       help
+         Say Y here to support the Intel CE6230 DVB-T USB2.0 receiver
+
+config DVB_USB_EC168
+       tristate "E3C EC168 DVB-T USB2.0 support"
+       depends on DVB_USB_V2
+       select DVB_EC100
+       select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
+       help
+         Say Y here to support the E3C EC168 DVB-T USB2.0 receiver.
+
+config DVB_USB_GL861
+       tristate "Genesys Logic GL861 USB2.0 support"
+       depends on DVB_USB_V2
+       select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+       select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
+       help
+         Say Y here to support the MSI Megasky 580 (55801) DVB-T USB2.0
+         receiver with USB ID 0db0:5581.
+
+config DVB_USB_LME2510
+       tristate "LME DM04/QQBOX DVB-S USB2.0 support"
+       depends on DVB_USB_V2
+       select DVB_TDA10086 if !DVB_FE_CUSTOMISE
+       select DVB_TDA826X if !DVB_FE_CUSTOMISE
+       select DVB_STV0288 if !DVB_FE_CUSTOMISE
+       select DVB_IX2505V if !DVB_FE_CUSTOMISE
+       select DVB_STV0299 if !DVB_FE_CUSTOMISE
+       select DVB_PLL if !DVB_FE_CUSTOMISE
+       select DVB_M88RS2000 if !DVB_FE_CUSTOMISE
+       help
+         Say Y here to support the LME DM04/QQBOX DVB-S USB2.0
+
+config DVB_USB_MXL111SF
+       tristate "MxL111SF DTV USB2.0 support"
+       depends on DVB_USB_V2
+       select DVB_LGDT3305 if !DVB_FE_CUSTOMISE
+       select DVB_LG2160 if !DVB_FE_CUSTOMISE
+       select VIDEO_TVEEPROM
+       help
+         Say Y here to support the MxL111SF USB2.0 DTV receiver.
+
diff --git a/drivers/media/dvb/dvb-usb-v2/Makefile b/drivers/media/dvb/dvb-usb-v2/Makefile
new file mode 100644 (file)
index 0000000..26659bc
--- /dev/null
@@ -0,0 +1,42 @@
+dvb_usbv2-objs = dvb_usb_core.o dvb_usb_urb.o usb_urb.o
+obj-$(CONFIG_DVB_USB_V2) += dvb_usbv2.o
+
+dvb_usb_cypress_firmware-objs = cypress_firmware.o
+obj-$(CONFIG_DVB_USB_CYPRESS_FIRMWARE) += dvb_usb_cypress_firmware.o
+
+dvb-usb-af9015-objs = af9015.o
+obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o
+
+dvb-usb-af9035-objs = af9035.o
+obj-$(CONFIG_DVB_USB_AF9035) += dvb-usb-af9035.o
+
+dvb-usb-anysee-objs = anysee.o
+obj-$(CONFIG_DVB_USB_ANYSEE) += dvb-usb-anysee.o
+
+dvb-usb-au6610-objs = au6610.o
+obj-$(CONFIG_DVB_USB_AU6610) += dvb-usb-au6610.o
+
+dvb-usb-az6007-objs = az6007.o
+obj-$(CONFIG_DVB_USB_AZ6007) += dvb-usb-az6007.o
+
+dvb-usb-ce6230-objs = ce6230.o
+obj-$(CONFIG_DVB_USB_CE6230) += dvb-usb-ce6230.o
+
+dvb-usb-ec168-objs = ec168.o
+obj-$(CONFIG_DVB_USB_EC168) += dvb-usb-ec168.o
+
+dvb-usb-lmedm04-objs = lmedm04.o
+obj-$(CONFIG_DVB_USB_LME2510) += dvb-usb-lmedm04.o
+
+dvb-usb-gl861-objs = gl861.o
+obj-$(CONFIG_DVB_USB_GL861) += dvb-usb-gl861.o
+
+dvb-usb-mxl111sf-objs = mxl111sf.o mxl111sf-phy.o mxl111sf-i2c.o mxl111sf-gpio.o
+obj-$(CONFIG_DVB_USB_MXL111SF) += dvb-usb-mxl111sf.o
+obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-demod.o
+obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o
+
+ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb/frontends/
+ccflags-y += -I$(srctree)/drivers/media/common/tuners
+
diff --git a/drivers/media/dvb/dvb-usb-v2/af9015.c b/drivers/media/dvb/dvb-usb-v2/af9015.c
new file mode 100644 (file)
index 0000000..10363f6
--- /dev/null
@@ -0,0 +1,1435 @@
+/*
+ * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
+ *
+ * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
+ *
+ * Thanks to Afatech who kindly provided information.
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License
+ *    along with this program; if not, write to the Free Software
+ *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "af9015.h"
+
+static int dvb_usb_af9015_debug;
+module_param_named(debug, dvb_usb_af9015_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
+static int dvb_usb_af9015_remote;
+module_param_named(remote, dvb_usb_af9015_remote, int, 0644);
+MODULE_PARM_DESC(remote, "select remote");
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req)
+{
+#define BUF_LEN 63
+#define REQ_HDR_LEN 8 /* send header size */
+#define ACK_HDR_LEN 2 /* rece header size */
+       struct af9015_state *state = d_to_priv(d);
+       int ret, wlen, rlen;
+       u8 buf[BUF_LEN];
+       u8 write = 1;
+
+       buf[0] = req->cmd;
+       buf[1] = state->seq++;
+       buf[2] = req->i2c_addr;
+       buf[3] = req->addr >> 8;
+       buf[4] = req->addr & 0xff;
+       buf[5] = req->mbox;
+       buf[6] = req->addr_len;
+       buf[7] = req->data_len;
+
+       switch (req->cmd) {
+       case GET_CONFIG:
+       case READ_MEMORY:
+       case RECONNECT_USB:
+               write = 0;
+               break;
+       case READ_I2C:
+               write = 0;
+               buf[2] |= 0x01; /* set I2C direction */
+       case WRITE_I2C:
+               buf[0] = READ_WRITE_I2C;
+               break;
+       case WRITE_MEMORY:
+               if (((req->addr & 0xff00) == 0xff00) ||
+                   ((req->addr & 0xff00) == 0xae00))
+                       buf[0] = WRITE_VIRTUAL_MEMORY;
+       case WRITE_VIRTUAL_MEMORY:
+       case COPY_FIRMWARE:
+       case DOWNLOAD_FIRMWARE:
+       case BOOT:
+               break;
+       default:
+               err("unknown command:%d", req->cmd);
+               ret = -1;
+               goto error;
+       }
+
+       /* buffer overflow check */
+       if ((write && (req->data_len > BUF_LEN - REQ_HDR_LEN)) ||
+               (!write && (req->data_len > BUF_LEN - ACK_HDR_LEN))) {
+               err("too much data; cmd:%d len:%d", req->cmd, req->data_len);
+               ret = -EINVAL;
+               goto error;
+       }
+
+       /* write receives seq + status = 2 bytes
+          read receives seq + status + data = 2 + N bytes */
+       wlen = REQ_HDR_LEN;
+       rlen = ACK_HDR_LEN;
+       if (write) {
+               wlen += req->data_len;
+               memcpy(&buf[REQ_HDR_LEN], req->data, req->data_len);
+       } else {
+               rlen += req->data_len;
+       }
+
+       /* no ack for these packets */
+       if (req->cmd == DOWNLOAD_FIRMWARE || req->cmd == RECONNECT_USB)
+               rlen = 0;
+
+       ret = dvb_usbv2_generic_rw(d, buf, wlen, buf, rlen);
+       if (ret)
+               goto error;
+
+       /* check status */
+       if (rlen && buf[1]) {
+               err("command failed:%d", buf[1]);
+               ret = -1;
+               goto error;
+       }
+
+       /* read request, copy returned data to return buf */
+       if (!write)
+               memcpy(req->data, &buf[ACK_HDR_LEN], req->data_len);
+error:
+       return ret;
+}
+
+static int af9015_write_regs(struct dvb_usb_device *d, u16 addr, u8 *val,
+       u8 len)
+{
+       struct req_t req = {WRITE_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len,
+               val};
+       return af9015_ctrl_msg(d, &req);
+}
+
+static int af9015_read_regs(struct dvb_usb_device *d, u16 addr, u8 *val, u8 len)
+{
+       struct req_t req = {READ_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len,
+               val};
+       return af9015_ctrl_msg(d, &req);
+}
+
+static int af9015_write_reg(struct dvb_usb_device *d, u16 addr, u8 val)
+{
+       return af9015_write_regs(d, addr, &val, 1);
+}
+
+static int af9015_read_reg(struct dvb_usb_device *d, u16 addr, u8 *val)
+{
+       return af9015_read_regs(d, addr, val, 1);
+}
+
+static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg,
+       u8 val)
+{
+       struct af9015_state *state = d_to_priv(d);
+       struct req_t req = {WRITE_I2C, addr, reg, 1, 1, 1, &val};
+
+       if (addr == state->af9013_config[0].i2c_addr ||
+           addr == state->af9013_config[1].i2c_addr)
+               req.addr_len = 3;
+
+       return af9015_ctrl_msg(d, &req);
+}
+
+static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg,
+       u8 *val)
+{
+       struct af9015_state *state = d_to_priv(d);
+       struct req_t req = {READ_I2C, addr, reg, 0, 1, 1, val};
+
+       if (addr == state->af9013_config[0].i2c_addr ||
+           addr == state->af9013_config[1].i2c_addr)
+               req.addr_len = 3;
+
+       return af9015_ctrl_msg(d, &req);
+}
+
+static int af9015_do_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit, u8 op)
+{
+       int ret;
+       u8 val, mask = 0x01;
+
+       ret = af9015_read_reg(d, addr, &val);
+       if (ret)
+               return ret;
+
+       mask <<= bit;
+       if (op) {
+               /* set bit */
+               val |= mask;
+       } else {
+               /* clear bit */
+               mask ^= 0xff;
+               val &= mask;
+       }
+
+       return af9015_write_reg(d, addr, val);
+}
+
+static int af9015_set_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit)
+{
+       return af9015_do_reg_bit(d, addr, bit, 1);
+}
+
+static int af9015_clear_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit)
+{
+       return af9015_do_reg_bit(d, addr, bit, 0);
+}
+
+static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+       int num)
+{
+       struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       struct af9015_state *state = d_to_priv(d);
+       int ret = 0, i = 0;
+       u16 addr;
+       u8 uninitialized_var(mbox), addr_len;
+       struct req_t req;
+
+/*
+The bus lock is needed because there is two tuners both using same I2C-address.
+Due to that the only way to select correct tuner is use demodulator I2C-gate.
+
+................................................
+. AF9015 includes integrated AF9013 demodulator.
+. ____________                   ____________  .                ____________
+.|     uC     |                 |   demod    | .               |    tuner   |
+.|------------|                 |------------| .               |------------|
+.|   AF9015   |                 |  AF9013/5  | .               |   MXL5003  |
+.|            |--+----I2C-------|-----/ -----|-.-----I2C-------|            |
+.|            |  |              | addr 0x38  | .               |  addr 0xc6 |
+.|____________|  |              |____________| .               |____________|
+.................|..............................
+                |               ____________                   ____________
+                |              |   demod    |                 |    tuner   |
+                |              |------------|                 |------------|
+                |              |   AF9013   |                 |   MXL5003  |
+                +----I2C-------|-----/ -----|-------I2C-------|            |
+                               | addr 0x3a  |                 |  addr 0xc6 |
+                               |____________|                 |____________|
+*/
+       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+               return -EAGAIN;
+
+       while (i < num) {
+               if (msg[i].addr == state->af9013_config[0].i2c_addr ||
+                   msg[i].addr == state->af9013_config[1].i2c_addr) {
+                       addr = msg[i].buf[0] << 8;
+                       addr += msg[i].buf[1];
+                       mbox = msg[i].buf[2];
+                       addr_len = 3;
+               } else {
+                       addr = msg[i].buf[0];
+                       addr_len = 1;
+                       /* mbox is don't care in that case */
+               }
+
+               if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
+                       if (msg[i].len > 3 || msg[i+1].len > 61) {
+                               ret = -EOPNOTSUPP;
+                               goto error;
+                       }
+                       if (msg[i].addr == state->af9013_config[0].i2c_addr)
+                               req.cmd = READ_MEMORY;
+                       else
+                               req.cmd = READ_I2C;
+                       req.i2c_addr = msg[i].addr;
+                       req.addr = addr;
+                       req.mbox = mbox;
+                       req.addr_len = addr_len;
+                       req.data_len = msg[i+1].len;
+                       req.data = &msg[i+1].buf[0];
+                       ret = af9015_ctrl_msg(d, &req);
+                       i += 2;
+               } else if (msg[i].flags & I2C_M_RD) {
+                       if (msg[i].len > 61) {
+                               ret = -EOPNOTSUPP;
+                               goto error;
+                       }
+                       if (msg[i].addr == state->af9013_config[0].i2c_addr) {
+                               ret = -EINVAL;
+                               goto error;
+                       }
+                       req.cmd = READ_I2C;
+                       req.i2c_addr = msg[i].addr;
+                       req.addr = addr;
+                       req.mbox = mbox;
+                       req.addr_len = addr_len;
+                       req.data_len = msg[i].len;
+                       req.data = &msg[i].buf[0];
+                       ret = af9015_ctrl_msg(d, &req);
+                       i += 1;
+               } else {
+                       if (msg[i].len > 21) {
+                               ret = -EOPNOTSUPP;
+                               goto error;
+                       }
+                       if (msg[i].addr == state->af9013_config[0].i2c_addr)
+                               req.cmd = WRITE_MEMORY;
+                       else
+                               req.cmd = WRITE_I2C;
+                       req.i2c_addr = msg[i].addr;
+                       req.addr = addr;
+                       req.mbox = mbox;
+                       req.addr_len = addr_len;
+                       req.data_len = msg[i].len-addr_len;
+                       req.data = &msg[i].buf[addr_len];
+                       ret = af9015_ctrl_msg(d, &req);
+                       i += 1;
+               }
+               if (ret)
+                       goto error;
+
+       }
+       ret = i;
+
+error:
+       mutex_unlock(&d->i2c_mutex);
+
+       return ret;
+}
+
+static u32 af9015_i2c_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm af9015_i2c_algo = {
+       .master_xfer = af9015_i2c_xfer,
+       .functionality = af9015_i2c_func,
+};
+
+static int af9015_identify_state(struct dvb_usb_device *d, const char **name)
+{
+       int ret;
+       u8 reply;
+       struct req_t req = {GET_CONFIG, 0, 0, 0, 0, 1, &reply};
+
+       ret = af9015_ctrl_msg(d, &req);
+       if (ret)
+               return ret;
+
+       deb_info("%s: reply:%02x\n", __func__, reply);
+       if (reply == 0x02)
+               ret = WARM;
+       else
+               ret = COLD;
+
+       return ret;
+}
+
+static int af9015_download_firmware(struct dvb_usb_device *d,
+       const struct firmware *fw)
+{
+       struct af9015_state *state = d_to_priv(d);
+       int i, len, remaining, ret;
+       struct req_t req = {DOWNLOAD_FIRMWARE, 0, 0, 0, 0, 0, NULL};
+       u16 checksum = 0;
+
+       deb_info("%s:\n", __func__);
+
+       /* calc checksum */
+       for (i = 0; i < fw->size; i++)
+               checksum += fw->data[i];
+
+       state->firmware_size = fw->size;
+       state->firmware_checksum = checksum;
+
+       #define FW_ADDR 0x5100 /* firmware start address */
+       #define LEN_MAX 55 /* max packet size */
+       for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) {
+               len = remaining;
+               if (len > LEN_MAX)
+                       len = LEN_MAX;
+
+               req.data_len = len;
+               req.data = (u8 *) &fw->data[fw->size - remaining];
+               req.addr = FW_ADDR + fw->size - remaining;
+
+               ret = af9015_ctrl_msg(d, &req);
+               if (ret) {
+                       err("firmware download failed:%d", ret);
+                       goto error;
+               }
+       }
+
+       /* firmware loaded, request boot */
+       req.cmd = BOOT;
+       req.data_len = 0;
+       ret = af9015_ctrl_msg(d, &req);
+       if (ret) {
+               err("firmware boot failed:%d", ret);
+               goto error;
+       }
+
+error:
+       return ret;
+}
+
+/* hash (and dump) eeprom */
+static int af9015_eeprom_hash(struct dvb_usb_device *d)
+{
+       struct af9015_state *state = d_to_priv(d);
+       int ret;
+       static const unsigned int eeprom_size = 256;
+       unsigned int reg;
+       u8 val, *eeprom;
+       struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val};
+
+       eeprom = kmalloc(eeprom_size, GFP_KERNEL);
+       if (eeprom == NULL)
+               return -ENOMEM;
+
+       for (reg = 0; reg < eeprom_size; reg++) {
+               req.addr = reg;
+               ret = af9015_ctrl_msg(d, &req);
+               if (ret)
+                       goto free;
+
+               eeprom[reg] = val;
+       }
+
+       if (dvb_usb_af9015_debug & 0x01)
+               print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, eeprom,
+                               eeprom_size);
+
+       BUG_ON(eeprom_size % 4);
+
+       state->eeprom_sum = 0;
+       for (reg = 0; reg < eeprom_size / sizeof(u32); reg++) {
+               state->eeprom_sum *= GOLDEN_RATIO_PRIME_32;
+               state->eeprom_sum += le32_to_cpu(((u32 *)eeprom)[reg]);
+       }
+
+       deb_info("%s: eeprom sum=%.8x\n", __func__, state->eeprom_sum);
+
+       ret = 0;
+free:
+       kfree(eeprom);
+       return ret;
+}
+
+static int af9015_read_config(struct dvb_usb_device *d)
+{
+       struct af9015_state *state = d_to_priv(d);
+       int ret;
+       u8 val, i, offset = 0;
+       struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val};
+
+       deb_info("%s:\n", __func__);
+
+       /* IR remote controller */
+       req.addr = AF9015_EEPROM_IR_MODE;
+       /* first message will timeout often due to possible hw bug */
+       for (i = 0; i < 4; i++) {
+               ret = af9015_ctrl_msg(d, &req);
+               if (!ret)
+                       break;
+       }
+       if (ret)
+               goto error;
+
+       ret = af9015_eeprom_hash(d);
+       if (ret)
+               goto error;
+
+       deb_info("%s: IR mode=%d\n", __func__, val);
+       state->ir_mode = val;
+
+       /* TS mode - one or two receivers */
+       req.addr = AF9015_EEPROM_TS_MODE;
+       ret = af9015_ctrl_msg(d, &req);
+       if (ret)
+               goto error;
+
+       state->dual_mode = val;
+       deb_info("%s: TS mode=%d\n", __func__, state->dual_mode);
+
+       /* disable 2nd adapter because we don't have PID-filters */
+       if (d->udev->speed == USB_SPEED_FULL)
+               state->dual_mode = 0;
+
+       if (state->dual_mode) {
+               /* read 2nd demodulator I2C address */
+               req.addr = AF9015_EEPROM_DEMOD2_I2C;
+               ret = af9015_ctrl_msg(d, &req);
+               if (ret)
+                       goto error;
+
+               state->af9013_config[1].i2c_addr = val;
+       }
+
+       for (i = 0; i < state->dual_mode + 1; i++) {
+               if (i == 1)
+                       offset = AF9015_EEPROM_OFFSET;
+               /* xtal */
+               req.addr = AF9015_EEPROM_XTAL_TYPE1 + offset;
+               ret = af9015_ctrl_msg(d, &req);
+               if (ret)
+                       goto error;
+               switch (val) {
+               case 0:
+                       state->af9013_config[i].clock = 28800000;
+                       break;
+               case 1:
+                       state->af9013_config[i].clock = 20480000;
+                       break;
+               case 2:
+                       state->af9013_config[i].clock = 28000000;
+                       break;
+               case 3:
+                       state->af9013_config[i].clock = 25000000;
+                       break;
+               };
+               deb_info("%s: [%d] xtal=%d set clock=%d\n", __func__, i,
+                               val, state->af9013_config[i].clock);
+
+               /* IF frequency */
+               req.addr = AF9015_EEPROM_IF1H + offset;
+               ret = af9015_ctrl_msg(d, &req);
+               if (ret)
+                       goto error;
+
+               state->af9013_config[i].if_frequency = val << 8;
+
+               req.addr = AF9015_EEPROM_IF1L + offset;
+               ret = af9015_ctrl_msg(d, &req);
+               if (ret)
+                       goto error;
+
+               state->af9013_config[i].if_frequency += val;
+               state->af9013_config[i].if_frequency *= 1000;
+               deb_info("%s: [%d] IF frequency=%d\n", __func__, i,
+                               state->af9013_config[i].if_frequency);
+
+               /* MT2060 IF1 */
+               req.addr = AF9015_EEPROM_MT2060_IF1H  + offset;
+               ret = af9015_ctrl_msg(d, &req);
+               if (ret)
+                       goto error;
+               state->mt2060_if1[i] = val << 8;
+               req.addr = AF9015_EEPROM_MT2060_IF1L + offset;
+               ret = af9015_ctrl_msg(d, &req);
+               if (ret)
+                       goto error;
+               state->mt2060_if1[i] += val;
+               deb_info("%s: [%d] MT2060 IF1=%d\n", __func__, i,
+                               state->mt2060_if1[i]);
+
+               /* tuner */
+               req.addr =  AF9015_EEPROM_TUNER_ID1 + offset;
+               ret = af9015_ctrl_msg(d, &req);
+               if (ret)
+                       goto error;
+               switch (val) {
+               case AF9013_TUNER_ENV77H11D5:
+               case AF9013_TUNER_MT2060:
+               case AF9013_TUNER_QT1010:
+               case AF9013_TUNER_UNKNOWN:
+               case AF9013_TUNER_MT2060_2:
+               case AF9013_TUNER_TDA18271:
+               case AF9013_TUNER_QT1010A:
+               case AF9013_TUNER_TDA18218:
+                       state->af9013_config[i].spec_inv = 1;
+                       break;
+               case AF9013_TUNER_MXL5003D:
+               case AF9013_TUNER_MXL5005D:
+               case AF9013_TUNER_MXL5005R:
+               case AF9013_TUNER_MXL5007T:
+                       state->af9013_config[i].spec_inv = 0;
+                       break;
+               case AF9013_TUNER_MC44S803:
+                       state->af9013_config[i].gpio[1] = AF9013_GPIO_LO;
+                       state->af9013_config[i].spec_inv = 1;
+                       break;
+               default:
+                       warn("tuner id=%d not supported, please report!", val);
+                       return -ENODEV;
+               };
+
+               state->af9013_config[i].tuner = val;
+               deb_info("%s: [%d] tuner id=%d\n", __func__, i, val);
+       }
+
+error:
+       if (ret)
+               err("eeprom read failed=%d", ret);
+
+       /* AverMedia AVerTV Volar Black HD (A850) device have bad EEPROM
+          content :-( Override some wrong values here. Ditto for the
+          AVerTV Red HD+ (A850T) device. */
+       if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_AVERMEDIA &&
+               ((le16_to_cpu(d->udev->descriptor.idProduct) ==
+                       USB_PID_AVERMEDIA_A850) ||
+               (le16_to_cpu(d->udev->descriptor.idProduct) ==
+                       USB_PID_AVERMEDIA_A850T))) {
+               deb_info("%s: AverMedia A850: overriding config\n", __func__);
+               /* disable dual mode */
+               state->dual_mode = 0;
+
+               /* set correct IF */
+               state->af9013_config[0].if_frequency = 4570000;
+       }
+
+       return ret;
+}
+
+static int af9015_get_stream_config(struct dvb_frontend *fe, u8 *ts_type,
+               struct usb_data_stream_properties *stream)
+{
+       deb_info("%s: adap=%d\n", __func__, fe_to_adap(fe)->id);
+
+       if (fe_to_d(fe)->udev->speed == USB_SPEED_FULL)
+               stream->u.bulk.buffersize = TS_USB11_FRAME_SIZE;
+
+       return 0;
+}
+
+static int af9015_get_adapter_count(struct dvb_usb_device *d)
+{
+       struct af9015_state *state = d_to_priv(d);
+       return state->dual_mode + 1;
+}
+
+/* override demod callbacks for resource locking */
+static int af9015_af9013_set_frontend(struct dvb_frontend *fe)
+{
+       int ret;
+       struct af9015_state *state = fe_to_priv(fe);
+
+       if (mutex_lock_interruptible(&state->fe_mutex))
+               return -EAGAIN;
+
+       ret = state->set_frontend[fe_to_adap(fe)->id](fe);
+
+       mutex_unlock(&state->fe_mutex);
+
+       return ret;
+}
+
+/* override demod callbacks for resource locking */
+static int af9015_af9013_read_status(struct dvb_frontend *fe,
+       fe_status_t *status)
+{
+       int ret;
+       struct af9015_state *state = fe_to_priv(fe);
+
+       if (mutex_lock_interruptible(&state->fe_mutex))
+               return -EAGAIN;
+
+       ret = state->read_status[fe_to_adap(fe)->id](fe, status);
+
+       mutex_unlock(&state->fe_mutex);
+
+       return ret;
+}
+
+/* override demod callbacks for resource locking */
+static int af9015_af9013_init(struct dvb_frontend *fe)
+{
+       int ret;
+       struct af9015_state *state = fe_to_priv(fe);
+
+       if (mutex_lock_interruptible(&state->fe_mutex))
+               return -EAGAIN;
+
+       ret = state->init[fe_to_adap(fe)->id](fe);
+
+       mutex_unlock(&state->fe_mutex);
+
+       return ret;
+}
+
+/* override demod callbacks for resource locking */
+static int af9015_af9013_sleep(struct dvb_frontend *fe)
+{
+       int ret;
+       struct af9015_state *state = fe_to_priv(fe);
+
+       if (mutex_lock_interruptible(&state->fe_mutex))
+               return -EAGAIN;
+
+       ret = state->sleep[fe_to_adap(fe)->id](fe);
+
+       mutex_unlock(&state->fe_mutex);
+
+       return ret;
+}
+
+/* override tuner callbacks for resource locking */
+static int af9015_tuner_init(struct dvb_frontend *fe)
+{
+       int ret;
+       struct af9015_state *state = fe_to_priv(fe);
+
+       if (mutex_lock_interruptible(&state->fe_mutex))
+               return -EAGAIN;
+
+       ret = state->tuner_init[fe_to_adap(fe)->id](fe);
+
+       mutex_unlock(&state->fe_mutex);
+
+       return ret;
+}
+
+/* override tuner callbacks for resource locking */
+static int af9015_tuner_sleep(struct dvb_frontend *fe)
+{
+       int ret;
+       struct af9015_state *state = fe_to_priv(fe);
+
+       if (mutex_lock_interruptible(&state->fe_mutex))
+               return -EAGAIN;
+
+       ret = state->tuner_sleep[fe_to_adap(fe)->id](fe);
+
+       mutex_unlock(&state->fe_mutex);
+
+       return ret;
+}
+
+static int af9015_copy_firmware(struct dvb_usb_device *d)
+{
+       struct af9015_state *state = d_to_priv(d);
+       int ret;
+       u8 fw_params[4];
+       u8 val, i;
+       struct req_t req = {COPY_FIRMWARE, 0, 0x5100, 0, 0, sizeof(fw_params),
+               fw_params };
+       deb_info("%s:\n", __func__);
+
+       fw_params[0] = state->firmware_size >> 8;
+       fw_params[1] = state->firmware_size & 0xff;
+       fw_params[2] = state->firmware_checksum >> 8;
+       fw_params[3] = state->firmware_checksum & 0xff;
+
+       /* wait 2nd demodulator ready */
+       msleep(100);
+
+       ret = af9015_read_reg_i2c(d, state->af9013_config[1].i2c_addr,
+                       0x98be, &val);
+       if (ret)
+               goto error;
+       else
+               deb_info("%s: firmware status:%02x\n", __func__, val);
+
+       if (val == 0x0c) /* fw is running, no need for download */
+               goto exit;
+
+       /* set I2C master clock to fast (to speed up firmware copy) */
+       ret = af9015_write_reg(d, 0xd416, 0x04); /* 0x04 * 400ns */
+       if (ret)
+               goto error;
+
+       msleep(50);
+
+       /* copy firmware */
+       ret = af9015_ctrl_msg(d, &req);
+       if (ret)
+               err("firmware copy cmd failed:%d", ret);
+       deb_info("%s: firmware copy done\n", __func__);
+
+       /* set I2C master clock back to normal */
+       ret = af9015_write_reg(d, 0xd416, 0x14); /* 0x14 * 400ns */
+       if (ret)
+               goto error;
+
+       /* request boot firmware */
+       ret = af9015_write_reg_i2c(d, state->af9013_config[1].i2c_addr,
+                       0xe205, 1);
+       deb_info("%s: firmware boot cmd status:%d\n", __func__, ret);
+       if (ret)
+               goto error;
+
+       for (i = 0; i < 15; i++) {
+               msleep(100);
+
+               /* check firmware status */
+               ret = af9015_read_reg_i2c(d, state->af9013_config[1].i2c_addr,
+                               0x98be, &val);
+               deb_info("%s: firmware status cmd status:%d fw status:%02x\n",
+                       __func__, ret, val);
+               if (ret)
+                       goto error;
+
+               if (val == 0x0c || val == 0x04) /* success or fail */
+                       break;
+       }
+
+       if (val == 0x04) {
+               err("firmware did not run");
+               ret = -1;
+       } else if (val != 0x0c) {
+               err("firmware boot timeout");
+               ret = -1;
+       }
+
+error:
+exit:
+       return ret;
+}
+
+static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       int ret;
+       struct af9015_state *state = adap_to_priv(adap);
+
+       if (adap->id == 0) {
+               state->af9013_config[0].ts_mode = AF9013_TS_USB;
+               memcpy(state->af9013_config[0].api_version, "\x0\x1\x9\x0", 4);
+               state->af9013_config[0].gpio[0] = AF9013_GPIO_HI;
+               state->af9013_config[0].gpio[3] = AF9013_GPIO_TUNER_ON;
+       } else if (adap->id == 1) {
+               state->af9013_config[1].ts_mode = AF9013_TS_SERIAL;
+               memcpy(state->af9013_config[1].api_version, "\x0\x1\x9\x0", 4);
+               state->af9013_config[1].gpio[0] = AF9013_GPIO_TUNER_ON;
+               state->af9013_config[1].gpio[1] = AF9013_GPIO_LO;
+
+               /* copy firmware to 2nd demodulator */
+               if (state->dual_mode) {
+                       ret = af9015_copy_firmware(adap_to_d(adap));
+                       if (ret) {
+                               err("firmware copy to 2nd frontend " \
+                                       "failed, will disable it");
+                               state->dual_mode = 0;
+                               return -ENODEV;
+                       }
+               } else {
+                       return -ENODEV;
+               }
+       }
+
+       /* attach demodulator */
+       adap->fe[0] = dvb_attach(af9013_attach,
+               &state->af9013_config[adap->id], &adap_to_d(adap)->i2c_adap);
+
+       /*
+        * AF9015 firmware does not like if it gets interrupted by I2C adapter
+        * request on some critical phases. During normal operation I2C adapter
+        * is used only 2nd demodulator and tuner on dual tuner devices.
+        * Override demodulator callbacks and use mutex for limit access to
+        * those "critical" paths to keep AF9015 happy.
+        */
+       if (adap->fe[0]) {
+               state->set_frontend[adap->id] =
+                       adap->fe[0]->ops.set_frontend;
+               adap->fe[0]->ops.set_frontend =
+                       af9015_af9013_set_frontend;
+
+               state->read_status[adap->id] =
+                       adap->fe[0]->ops.read_status;
+               adap->fe[0]->ops.read_status =
+                       af9015_af9013_read_status;
+
+               state->init[adap->id] = adap->fe[0]->ops.init;
+               adap->fe[0]->ops.init = af9015_af9013_init;
+
+               state->sleep[adap->id] = adap->fe[0]->ops.sleep;
+               adap->fe[0]->ops.sleep = af9015_af9013_sleep;
+       }
+
+       return adap->fe[0] == NULL ? -ENODEV : 0;
+}
+
+static struct mt2060_config af9015_mt2060_config = {
+       .i2c_address = 0xc0,
+       .clock_out = 0,
+};
+
+static struct qt1010_config af9015_qt1010_config = {
+       .i2c_address = 0xc4,
+};
+
+static struct tda18271_config af9015_tda18271_config = {
+       .gate = TDA18271_GATE_DIGITAL,
+       .small_i2c = TDA18271_16_BYTE_CHUNK_INIT,
+};
+
+static struct mxl5005s_config af9015_mxl5003_config = {
+       .i2c_address     = 0xc6,
+       .if_freq         = IF_FREQ_4570000HZ,
+       .xtal_freq       = CRYSTAL_FREQ_16000000HZ,
+       .agc_mode        = MXL_SINGLE_AGC,
+       .tracking_filter = MXL_TF_DEFAULT,
+       .rssi_enable     = MXL_RSSI_ENABLE,
+       .cap_select      = MXL_CAP_SEL_ENABLE,
+       .div_out         = MXL_DIV_OUT_4,
+       .clock_out       = MXL_CLOCK_OUT_DISABLE,
+       .output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
+       .top             = MXL5005S_TOP_25P2,
+       .mod_mode        = MXL_DIGITAL_MODE,
+       .if_mode         = MXL_ZERO_IF,
+       .AgcMasterByte   = 0x00,
+};
+
+static struct mxl5005s_config af9015_mxl5005_config = {
+       .i2c_address     = 0xc6,
+       .if_freq         = IF_FREQ_4570000HZ,
+       .xtal_freq       = CRYSTAL_FREQ_16000000HZ,
+       .agc_mode        = MXL_SINGLE_AGC,
+       .tracking_filter = MXL_TF_OFF,
+       .rssi_enable     = MXL_RSSI_ENABLE,
+       .cap_select      = MXL_CAP_SEL_ENABLE,
+       .div_out         = MXL_DIV_OUT_4,
+       .clock_out       = MXL_CLOCK_OUT_DISABLE,
+       .output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
+       .top             = MXL5005S_TOP_25P2,
+       .mod_mode        = MXL_DIGITAL_MODE,
+       .if_mode         = MXL_ZERO_IF,
+       .AgcMasterByte   = 0x00,
+};
+
+static struct mc44s803_config af9015_mc44s803_config = {
+       .i2c_address = 0xc0,
+       .dig_out = 1,
+};
+
+static struct tda18218_config af9015_tda18218_config = {
+       .i2c_address = 0xc0,
+       .i2c_wr_max = 21, /* max wr bytes AF9015 I2C adap can handle at once */
+};
+
+static struct mxl5007t_config af9015_mxl5007t_config = {
+       .xtal_freq_hz = MxL_XTAL_24_MHZ,
+       .if_freq_hz = MxL_IF_4_57_MHZ,
+};
+
+static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       struct af9015_state *state = adap_to_priv(adap);
+       int ret;
+       deb_info("%s:\n", __func__);
+
+       switch (state->af9013_config[adap->id].tuner) {
+       case AF9013_TUNER_MT2060:
+       case AF9013_TUNER_MT2060_2:
+               ret = dvb_attach(mt2060_attach, adap->fe[0],
+                       &adap_to_d(adap)->i2c_adap, &af9015_mt2060_config,
+                       state->mt2060_if1[adap->id])
+                       == NULL ? -ENODEV : 0;
+               break;
+       case AF9013_TUNER_QT1010:
+       case AF9013_TUNER_QT1010A:
+               ret = dvb_attach(qt1010_attach, adap->fe[0],
+                       &adap_to_d(adap)->i2c_adap,
+                       &af9015_qt1010_config) == NULL ? -ENODEV : 0;
+               break;
+       case AF9013_TUNER_TDA18271:
+               ret = dvb_attach(tda18271_attach, adap->fe[0], 0xc0,
+                       &adap_to_d(adap)->i2c_adap,
+                       &af9015_tda18271_config) == NULL ? -ENODEV : 0;
+               break;
+       case AF9013_TUNER_TDA18218:
+               ret = dvb_attach(tda18218_attach, adap->fe[0],
+                       &adap_to_d(adap)->i2c_adap,
+                       &af9015_tda18218_config) == NULL ? -ENODEV : 0;
+               break;
+       case AF9013_TUNER_MXL5003D:
+               ret = dvb_attach(mxl5005s_attach, adap->fe[0],
+                       &adap_to_d(adap)->i2c_adap,
+                       &af9015_mxl5003_config) == NULL ? -ENODEV : 0;
+               break;
+       case AF9013_TUNER_MXL5005D:
+       case AF9013_TUNER_MXL5005R:
+               ret = dvb_attach(mxl5005s_attach, adap->fe[0],
+                       &adap_to_d(adap)->i2c_adap,
+                       &af9015_mxl5005_config) == NULL ? -ENODEV : 0;
+               break;
+       case AF9013_TUNER_ENV77H11D5:
+               ret = dvb_attach(dvb_pll_attach, adap->fe[0], 0xc0,
+                       &adap_to_d(adap)->i2c_adap,
+                       DVB_PLL_TDA665X) == NULL ? -ENODEV : 0;
+               break;
+       case AF9013_TUNER_MC44S803:
+               ret = dvb_attach(mc44s803_attach, adap->fe[0],
+                       &adap_to_d(adap)->i2c_adap,
+                       &af9015_mc44s803_config) == NULL ? -ENODEV : 0;
+               break;
+       case AF9013_TUNER_MXL5007T:
+               ret = dvb_attach(mxl5007t_attach, adap->fe[0],
+                       &adap_to_d(adap)->i2c_adap,
+                       0xc0, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0;
+               break;
+       case AF9013_TUNER_UNKNOWN:
+       default:
+               ret = -ENODEV;
+               err("Unknown tuner id:%d",
+                       state->af9013_config[adap->id].tuner);
+       }
+
+       if (adap->fe[0]->ops.tuner_ops.init) {
+               state->tuner_init[adap->id] =
+                       adap->fe[0]->ops.tuner_ops.init;
+               adap->fe[0]->ops.tuner_ops.init = af9015_tuner_init;
+       }
+
+       if (adap->fe[0]->ops.tuner_ops.sleep) {
+               state->tuner_sleep[adap->id] =
+                       adap->fe[0]->ops.tuner_ops.sleep;
+               adap->fe[0]->ops.tuner_ops.sleep = af9015_tuner_sleep;
+       }
+
+       return ret;
+}
+
+static int af9015_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+       int ret;
+       deb_info("%s: onoff:%d\n", __func__, onoff);
+
+       if (onoff)
+               ret = af9015_set_reg_bit(adap_to_d(adap), 0xd503, 0);
+       else
+               ret = af9015_clear_reg_bit(adap_to_d(adap), 0xd503, 0);
+
+       return ret;
+}
+
+static int af9015_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
+       int onoff)
+{
+       int ret;
+       u8 idx;
+
+       deb_info("%s: set pid filter, index %d, pid %x, onoff %d\n",
+               __func__, index, pid, onoff);
+
+       ret = af9015_write_reg(adap_to_d(adap), 0xd505, (pid & 0xff));
+       if (ret)
+               goto error;
+
+       ret = af9015_write_reg(adap_to_d(adap), 0xd506, (pid >> 8));
+       if (ret)
+               goto error;
+
+       idx = ((index & 0x1f) | (1 << 5));
+       ret = af9015_write_reg(adap_to_d(adap), 0xd504, idx);
+
+error:
+       return ret;
+}
+
+static int af9015_init_endpoint(struct dvb_usb_device *d)
+{
+       struct af9015_state *state = d_to_priv(d);
+       int ret;
+       u16 frame_size;
+       u8  packet_size;
+       deb_info("%s: USB speed:%d\n", __func__, d->udev->speed);
+
+       if (d->udev->speed == USB_SPEED_FULL) {
+               frame_size = TS_USB11_FRAME_SIZE/4;
+               packet_size = TS_USB11_MAX_PACKET_SIZE/4;
+       } else {
+               frame_size = TS_USB20_FRAME_SIZE/4;
+               packet_size = TS_USB20_MAX_PACKET_SIZE/4;
+       }
+
+       ret = af9015_set_reg_bit(d, 0xd507, 2); /* assert EP4 reset */
+       if (ret)
+               goto error;
+       ret = af9015_set_reg_bit(d, 0xd50b, 1); /* assert EP5 reset */
+       if (ret)
+               goto error;
+       ret = af9015_clear_reg_bit(d, 0xdd11, 5); /* disable EP4 */
+       if (ret)
+               goto error;
+       ret = af9015_clear_reg_bit(d, 0xdd11, 6); /* disable EP5 */
+       if (ret)
+               goto error;
+       ret = af9015_set_reg_bit(d, 0xdd11, 5); /* enable EP4 */
+       if (ret)
+               goto error;
+       if (state->dual_mode) {
+               ret = af9015_set_reg_bit(d, 0xdd11, 6); /* enable EP5 */
+               if (ret)
+                       goto error;
+       }
+       ret = af9015_clear_reg_bit(d, 0xdd13, 5); /* disable EP4 NAK */
+       if (ret)
+               goto error;
+       if (state->dual_mode) {
+               ret = af9015_clear_reg_bit(d, 0xdd13, 6); /* disable EP5 NAK */
+               if (ret)
+                       goto error;
+       }
+       /* EP4 xfer length */
+       ret = af9015_write_reg(d, 0xdd88, frame_size & 0xff);
+       if (ret)
+               goto error;
+       ret = af9015_write_reg(d, 0xdd89, frame_size >> 8);
+       if (ret)
+               goto error;
+       /* EP5 xfer length */
+       ret = af9015_write_reg(d, 0xdd8a, frame_size & 0xff);
+       if (ret)
+               goto error;
+       ret = af9015_write_reg(d, 0xdd8b, frame_size >> 8);
+       if (ret)
+               goto error;
+       ret = af9015_write_reg(d, 0xdd0c, packet_size); /* EP4 packet size */
+       if (ret)
+               goto error;
+       ret = af9015_write_reg(d, 0xdd0d, packet_size); /* EP5 packet size */
+       if (ret)
+               goto error;
+       ret = af9015_clear_reg_bit(d, 0xd507, 2); /* negate EP4 reset */
+       if (ret)
+               goto error;
+       if (state->dual_mode) {
+               ret = af9015_clear_reg_bit(d, 0xd50b, 1); /* negate EP5 reset */
+               if (ret)
+                       goto error;
+       }
+
+       /* enable / disable mp2if2 */
+       if (state->dual_mode)
+               ret = af9015_set_reg_bit(d, 0xd50b, 0);
+       else
+               ret = af9015_clear_reg_bit(d, 0xd50b, 0);
+
+error:
+       if (ret)
+               err("endpoint init failed:%d", ret);
+       return ret;
+}
+
+static int af9015_init(struct dvb_usb_device *d)
+{
+       struct af9015_state *state = d_to_priv(d);
+       int ret;
+       deb_info("%s:\n", __func__);
+
+       mutex_init(&state->fe_mutex);
+
+       /* init RC canary */
+       ret = af9015_write_reg(d, 0x98e9, 0xff);
+       if (ret)
+               goto error;
+
+       ret = af9015_init_endpoint(d);
+       if (ret)
+               goto error;
+
+error:
+       return ret;
+}
+
+struct af9015_rc_setup {
+       unsigned int id;
+       char *rc_codes;
+};
+
+static char *af9015_rc_setup_match(unsigned int id,
+       const struct af9015_rc_setup *table)
+{
+       for (; table->rc_codes; table++)
+               if (table->id == id)
+                       return table->rc_codes;
+       return NULL;
+}
+
+static const struct af9015_rc_setup af9015_rc_setup_modparam[] = {
+       { AF9015_REMOTE_A_LINK_DTU_M, RC_MAP_ALINK_DTU_M },
+       { AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, RC_MAP_MSI_DIGIVOX_II },
+       { AF9015_REMOTE_MYGICTV_U718, RC_MAP_TOTAL_MEDIA_IN_HAND },
+       { AF9015_REMOTE_DIGITTRADE_DVB_T, RC_MAP_DIGITTRADE },
+       { AF9015_REMOTE_AVERMEDIA_KS, RC_MAP_AVERMEDIA_RM_KS },
+       { }
+};
+
+static const struct af9015_rc_setup af9015_rc_setup_hashes[] = {
+       { 0xb8feb708, RC_MAP_MSI_DIGIVOX_II },
+       { 0xa3703d00, RC_MAP_ALINK_DTU_M },
+       { 0x9b7dc64e, RC_MAP_TOTAL_MEDIA_IN_HAND }, /* MYGICTV U718 */
+       { 0x5d49e3db, RC_MAP_DIGITTRADE }, /* LC-Power LC-USB-DVBT */
+       { }
+};
+
+static int af9015_rc_query(struct dvb_usb_device *d)
+{
+       struct af9015_state *state = d_to_priv(d);
+       int ret;
+       u8 buf[17];
+
+       deb_info("%s:\n", __func__);
+
+       /* read registers needed to detect remote controller code */
+       ret = af9015_read_regs(d, 0x98d9, buf, sizeof(buf));
+       if (ret)
+               goto error;
+
+       /* If any of these are non-zero, assume invalid data */
+       if (buf[1] || buf[2] || buf[3])
+               return ret;
+
+       /* Check for repeat of previous code */
+       if ((state->rc_repeat != buf[6] || buf[0]) &&
+                       !memcmp(&buf[12], state->rc_last, 4)) {
+               deb_rc("%s: key repeated\n", __func__);
+               rc_keydown(d->rc_dev, state->rc_keycode, 0);
+               state->rc_repeat = buf[6];
+               return ret;
+       }
+
+       /* Only process key if canary killed */
+       if (buf[16] != 0xff && buf[0] != 0x01) {
+               deb_rc("%s: key pressed %02x %02x %02x %02x\n", __func__,
+                       buf[12], buf[13], buf[14], buf[15]);
+
+               /* Reset the canary */
+               ret = af9015_write_reg(d, 0x98e9, 0xff);
+               if (ret)
+                       goto error;
+
+               /* Remember this key */
+               memcpy(state->rc_last, &buf[12], 4);
+               if (buf[14] == (u8) ~buf[15]) {
+                       if (buf[12] == (u8) ~buf[13]) {
+                               /* NEC */
+                               state->rc_keycode = buf[12] << 8 | buf[14];
+                       } else {
+                               /* NEC extended*/
+                               state->rc_keycode = buf[12] << 16 |
+                                       buf[13] << 8 | buf[14];
+                       }
+               } else {
+                       /* 32 bit NEC */
+                       state->rc_keycode = buf[12] << 24 | buf[13] << 16 |
+                                       buf[14] << 8 | buf[15];
+               }
+               rc_keydown(d->rc_dev, state->rc_keycode, 0);
+       } else {
+               deb_rc("%s: no key press\n", __func__);
+               /* Invalidate last keypress */
+               /* Not really needed, but helps with debug */
+               state->rc_last[2] = state->rc_last[3];
+       }
+
+       state->rc_repeat = buf[6];
+       state->rc_failed = false;
+
+error:
+       if (ret) {
+               err("%s: failed:%d", __func__, ret);
+
+               /* allow random errors as dvb-usb will stop polling on error */
+               if (!state->rc_failed)
+                       ret = 0;
+
+               state->rc_failed = true;
+       }
+
+       return ret;
+}
+
+static int af9015_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
+{
+       struct af9015_state *state = d_to_priv(d);
+       u16 vid = le16_to_cpu(d->udev->descriptor.idVendor);
+
+       if (state->ir_mode == AF9015_IR_MODE_DISABLED)
+               return 0;
+
+       /* try to load remote based module param */
+       if (!rc->map_name)
+               rc->map_name = af9015_rc_setup_match(dvb_usb_af9015_remote,
+                               af9015_rc_setup_modparam);
+
+       /* try to load remote based eeprom hash */
+       if (!rc->map_name)
+               rc->map_name = af9015_rc_setup_match(state->eeprom_sum,
+                               af9015_rc_setup_hashes);
+
+       /* try to load remote based USB iManufacturer string */
+       if (!rc->map_name && vid == USB_VID_AFATECH) {
+               /* Check USB manufacturer and product strings and try
+                  to determine correct remote in case of chip vendor
+                  reference IDs are used.
+                  DO NOT ADD ANYTHING NEW HERE. Use hashes instead. */
+               char manufacturer[10];
+               memset(manufacturer, 0, sizeof(manufacturer));
+               usb_string(d->udev, d->udev->descriptor.iManufacturer,
+                       manufacturer, sizeof(manufacturer));
+               if (!strcmp("MSI", manufacturer)) {
+                       /* iManufacturer 1 MSI
+                          iProduct      2 MSI K-VOX */
+                       rc->map_name = af9015_rc_setup_match(
+                                       AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
+                                       af9015_rc_setup_modparam);
+               }
+       }
+
+       /* load empty to enable rc */
+       if (!rc->map_name)
+               rc->map_name = RC_MAP_EMPTY;
+
+       rc->allowed_protos = RC_TYPE_NEC;
+       rc->query = af9015_rc_query;
+       rc->interval = 500;
+
+       return 0;
+}
+
+/* interface 0 is used by DVB-T receiver and
+   interface 1 is for remote controller (HID) */
+static struct dvb_usb_device_properties af9015_props = {
+       .driver_name = KBUILD_MODNAME,
+       .owner = THIS_MODULE,
+       .adapter_nr = adapter_nr,
+       .size_of_priv = sizeof(struct af9015_state),
+
+       .generic_bulk_ctrl_endpoint = 0x02,
+       .generic_bulk_ctrl_endpoint_response = 0x81,
+
+       .identify_state = af9015_identify_state,
+       .firmware = "dvb-usb-af9015.fw",
+       .download_firmware = af9015_download_firmware,
+
+       .i2c_algo = &af9015_i2c_algo,
+       .read_config = af9015_read_config,
+       .frontend_attach = af9015_af9013_frontend_attach,
+       .tuner_attach = af9015_tuner_attach,
+       .init = af9015_init,
+       .get_rc_config = af9015_get_rc_config,
+       .get_stream_config = af9015_get_stream_config,
+
+       .get_adapter_count = af9015_get_adapter_count,
+       .adapter = {
+               {
+                       .caps = DVB_USB_ADAP_HAS_PID_FILTER |
+                               DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+                       .pid_filter_count = 32,
+                       .pid_filter = af9015_pid_filter,
+                       .pid_filter_ctrl = af9015_pid_filter_ctrl,
+
+                       .stream = DVB_USB_STREAM_BULK(0x84, 8, TS_USB20_FRAME_SIZE),
+               }, {
+                       .stream = DVB_USB_STREAM_BULK(0x85, 8, TS_USB20_FRAME_SIZE),
+               },
+       },
+};
+
+static const struct usb_device_id af9015_id_table[] = {
+       { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9015,
+               &af9015_props, "Afatech AF9015 reference design", NULL) },
+       { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9016,
+               &af9015_props, "Afatech AF9015 reference design", NULL) },
+       { DVB_USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_GOLD,
+               &af9015_props, "Leadtek WinFast DTV Dongle Gold", RC_MAP_LEADTEK_Y04G0051) },
+       { DVB_USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV71E,
+               &af9015_props, "Pinnacle PCTV 71e", NULL) },
+       { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U,
+               &af9015_props, "KWorld PlusTV Dual DVB-T Stick (DVB-T 399U)", NULL) },
+       { DVB_USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TINYTWIN,
+               &af9015_props, "DigitalNow TinyTwin", RC_MAP_AZUREWAVE_AD_TU700) },
+       { DVB_USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_AZUREWAVE_AD_TU700,
+               &af9015_props, "TwinHan AzureWave AD-TU700(704J)", RC_MAP_AZUREWAVE_AD_TU700) },
+       { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2,
+               &af9015_props, "TerraTec Cinergy T USB XE", NULL) },
+       { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_2T,
+               &af9015_props, "KWorld PlusTV Dual DVB-T PCI (DVB-T PC160-2T)", NULL) },
+       { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X,
+               &af9015_props, "AVerMedia AVerTV DVB-T Volar X", RC_MAP_AVERMEDIA_M135A) },
+       { DVB_USB_DEVICE(USB_VID_XTENSIONS, USB_PID_XTENSIONS_XD_380,
+               &af9015_props, "Xtensions XD-380", NULL) },
+       { DVB_USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGIVOX_DUO,
+               &af9015_props, "MSI DIGIVOX Duo", RC_MAP_MSI_DIGIVOX_III) },
+       { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X_2,
+               &af9015_props, "Fujitsu-Siemens Slim Mobile USB DVB-T", NULL) },
+       { DVB_USB_DEVICE(USB_VID_TELESTAR,  USB_PID_TELESTAR_STARSTICK_2,
+               &af9015_props, "Telestar Starstick 2", NULL) },
+       { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309,
+               &af9015_props, "AVerMedia A309", NULL) },
+       { DVB_USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGI_VOX_MINI_III,
+               &af9015_props, "MSI Digi VOX mini III", RC_MAP_MSI_DIGIVOX_III) },
+       { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U,
+               &af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)", NULL) },
+       { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_2,
+               &af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)", NULL) },
+       { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_3,
+               &af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)", NULL) },
+       { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_TREKSTOR_DVBT,
+               &af9015_props, "TrekStor DVB-T USB Stick", RC_MAP_TREKSTOR) },
+       { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850,
+               &af9015_props, "AverMedia AVerTV Volar Black HD (A850)", NULL) },
+       { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A805,
+               &af9015_props, "AverMedia AVerTV Volar GPS 805 (A805)", NULL) },
+       { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CONCEPTRONIC_CTVDIGRCU,
+               &af9015_props, "Conceptronic USB2.0 DVB-T CTVDIGRCU V3.0", NULL) },
+       { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_MC810,
+               &af9015_props, "KWorld Digial MC-810", NULL) },
+       { DVB_USB_DEVICE(USB_VID_KYE, USB_PID_GENIUS_TVGO_DVB_T03,
+               &af9015_props, "Genius TVGo DVB-T03", NULL) },
+       { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U_2,
+               &af9015_props, "KWorld PlusTV Dual DVB-T Stick (DVB-T 399U)", NULL) },
+       { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_T,
+               &af9015_props, "KWorld PlusTV DVB-T PCI Pro Card (DVB-T PC160-T)", NULL) },
+       { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20,
+               &af9015_props, "Sveon STV20 Tuner USB DVB-T HDTV", NULL) },
+       { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_TINYTWIN_2,
+               &af9015_props, "DigitalNow TinyTwin v2", RC_MAP_DIGITALNOW_TINYTWIN) },
+       { DVB_USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV2000DS,
+               &af9015_props, "Leadtek WinFast DTV2000DS", RC_MAP_LEADTEK_Y04G0051) },
+       { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB383_T,
+               &af9015_props, "KWorld USB DVB-T Stick Mobile (UB383-T)", NULL) },
+       { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_4,
+               &af9015_props, "KWorld USB DVB-T TV Stick II (VS-DVB-T 395U)", NULL) },
+       { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A815M,
+               &af9015_props, "AverMedia AVerTV Volar M (A815Mac)", NULL) },
+       { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_RC,
+               &af9015_props, "TerraTec Cinergy T Stick RC", RC_MAP_TERRATEC_SLIM_2) },
+       { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC,
+               &af9015_props, "TerraTec Cinergy T Stick Dual RC", RC_MAP_TERRATEC_SLIM) },
+       { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T,
+               &af9015_props, "AverMedia AVerTV Red HD+ (A850T)", NULL) },
+       { DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_TINYTWIN_3,
+               &af9015_props, "DigitalNow TinyTwin v3", RC_MAP_DIGITALNOW_TINYTWIN) },
+       { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22,
+               &af9015_props, "Sveon STV22 Dual USB DVB-T Tuner HDTV", RC_MAP_MSI_DIGIVOX_III) },
+       { }
+};
+MODULE_DEVICE_TABLE(usb, af9015_id_table);
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver af9015_usb_driver = {
+       .name = KBUILD_MODNAME,
+       .id_table = af9015_id_table,
+       .probe = dvb_usbv2_probe,
+       .disconnect = dvb_usbv2_disconnect,
+       .suspend = dvb_usbv2_suspend,
+       .resume = dvb_usbv2_resume,
+       .no_dynamic_id = 1,
+       .soft_unbind = 1,
+};
+
+module_usb_driver(af9015_usb_driver);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Afatech AF9015 driver");
+MODULE_LICENSE("GPL");
similarity index 72%
rename from drivers/media/dvb/dvb-usb/af9015.h
rename to drivers/media/dvb/dvb-usb-v2/af9015.h
index 2f68419e899b670992f62366ec8563f4d28f9532..c6b304d962ad3fcaa2368010ea3f85335b1e7f59 100644 (file)
  *
  */
 
-#ifndef _DVB_USB_AF9015_H_
-#define _DVB_USB_AF9015_H_
+#ifndef AF9015_H
+#define AF9015_H
+
+#include <linux/hash.h>
+#include "dvb_usb.h"
+#include "af9013.h"
+#include "dvb-pll.h"
+#include "mt2060.h"
+#include "qt1010.h"
+#include "tda18271.h"
+#include "mxl5005s.h"
+#include "mc44s803.h"
+#include "tda18218.h"
+#include "mxl5007t.h"
 
 #define DVB_USB_LOG_PREFIX "af9015"
-#include "dvb-usb.h"
+
+#ifdef CONFIG_DVB_USB_DEBUG
+#define dprintk(var, level, args...) \
+       do { if ((var & level)) printk(args); } while (0)
+#define DVB_USB_DEBUG_STATUS
+#else
+#define dprintk(args...)
+#define DVB_USB_DEBUG_STATUS " (debugging is not enabled)"
+#endif
 
 #define deb_info(args...) dprintk(dvb_usb_af9015_debug, 0x01, args)
 #define deb_rc(args...)   dprintk(dvb_usb_af9015_debug, 0x02, args)
-#define deb_xfer(args...) dprintk(dvb_usb_af9015_debug, 0x04, args)
-#define deb_reg(args...)  dprintk(dvb_usb_af9015_debug, 0x08, args)
-#define deb_i2c(args...)  dprintk(dvb_usb_af9015_debug, 0x10, args)
-#define deb_fw(args...)   dprintk(dvb_usb_af9015_debug, 0x20, args)
+
+#undef err
+#define err(format, arg...) \
+       printk(KERN_ERR     DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
+#undef warn
+#define warn(format, arg...) \
+       printk(KERN_WARNING DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
+
+/* Windows driver uses packet count 21 for USB1.1 and 348 for USB2.0.
+   We use smaller - about 1/4 from the original, 5 and 87. */
+#define TS_PACKET_SIZE            188
+
+#define TS_USB20_PACKET_COUNT      87
+#define TS_USB20_FRAME_SIZE       (TS_PACKET_SIZE*TS_USB20_PACKET_COUNT)
+
+#define TS_USB11_PACKET_COUNT       5
+#define TS_USB11_FRAME_SIZE       (TS_PACKET_SIZE*TS_USB11_PACKET_COUNT)
+
+#define TS_USB20_MAX_PACKET_SIZE  512
+#define TS_USB11_MAX_PACKET_SIZE   64
 
 #define AF9015_I2C_EEPROM  0xa0
 #define AF9015_I2C_DEMOD   0x38
@@ -99,9 +135,18 @@ enum af9015_ir_mode {
 };
 
 struct af9015_state {
+       u8 ir_mode;
        u8 rc_repeat;
        u32 rc_keycode;
        u8 rc_last[4];
+       bool rc_failed;
+       u8 dual_mode;
+       u8 seq; /* packet sequence number */
+       u16 mt2060_if1[2];
+       u16 firmware_size;
+       u16 firmware_checksum;
+       u32 eeprom_sum;
+       struct af9013_config af9013_config[2];
 
        /* for demod callback override */
        int (*set_frontend[2]) (struct dvb_frontend *fe);
@@ -110,14 +155,7 @@ struct af9015_state {
        int (*sleep[2]) (struct dvb_frontend *fe);
        int (*tuner_init[2]) (struct dvb_frontend *fe);
        int (*tuner_sleep[2]) (struct dvb_frontend *fe);
-};
-
-struct af9015_config {
-       u8  dual_mode:1;
-       u16 mt2060_if1[2];
-       u16 firmware_size;
-       u16 firmware_checksum;
-       u32 eeprom_sum;
+       struct mutex fe_mutex;
 };
 
 enum af9015_remote {
similarity index 62%
rename from drivers/media/dvb/dvb-usb/af9035.c
rename to drivers/media/dvb/dvb-usb-v2/af9035.c
index e83b39d3993cebc70177891f5608f34b41ec2cc4..79197f46aa95031198a0ecfbc1f90d150b33fff2 100644 (file)
@@ -22,9 +22,6 @@
 #include "af9035.h"
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-static DEFINE_MUTEX(af9035_usb_mutex);
-static struct dvb_usb_device_properties af9035_properties[2];
-static int af9035_properties_count = ARRAY_SIZE(af9035_properties);
 
 static u16 af9035_checksum(const u8 *buf, size_t len)
 {
@@ -42,17 +39,16 @@ static u16 af9035_checksum(const u8 *buf, size_t len)
        return checksum;
 }
 
-static int af9035_ctrl_msg(struct usb_device *udev, struct usb_req *req)
+static int af9035_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req)
 {
 #define BUF_LEN 64
 #define REQ_HDR_LEN 4 /* send header size */
 #define ACK_HDR_LEN 3 /* rece header size */
 #define CHECKSUM_LEN 2
 #define USB_TIMEOUT 2000
-
-       int ret, msg_len, act_len;
+       struct state *state = d_to_priv(d);
+       int ret, wlen, rlen;
        u8 buf[BUF_LEN];
-       static u8 seq; /* packet sequence number */
        u16 checksum, tmp_checksum;
 
        /* buffer overflow check */
@@ -63,62 +59,41 @@ static int af9035_ctrl_msg(struct usb_device *udev, struct usb_req *req)
                return -EINVAL;
        }
 
-       if (mutex_lock_interruptible(&af9035_usb_mutex) < 0)
-               return -EAGAIN;
-
        buf[0] = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN - 1;
        buf[1] = req->mbox;
        buf[2] = req->cmd;
-       buf[3] = seq++;
-       if (req->wlen)
-               memcpy(&buf[4], req->wbuf, req->wlen);
+       buf[3] = state->seq++;
+       memcpy(&buf[REQ_HDR_LEN], req->wbuf, req->wlen);
+
+       wlen = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN;
+       rlen = ACK_HDR_LEN + req->rlen + CHECKSUM_LEN;
 
        /* calc and add checksum */
        checksum = af9035_checksum(buf, buf[0] - 1);
        buf[buf[0] - 1] = (checksum >> 8);
        buf[buf[0] - 0] = (checksum & 0xff);
 
-       msg_len = REQ_HDR_LEN + req->wlen + CHECKSUM_LEN ;
+       /* no ack for these packets */
+       if (req->cmd == CMD_FW_DL)
+               rlen = 0;
 
-       /* send req */
-       ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x02), buf, msg_len,
-                       &act_len, USB_TIMEOUT);
-       if (ret < 0)
-               err("bulk message failed=%d (%d/%d)", ret, msg_len, act_len);
-       else
-               if (act_len != msg_len)
-                       ret = -EIO; /* all data is not send */
-       if (ret < 0)
-               goto err_mutex_unlock;
+       ret = dvb_usbv2_generic_rw(d, buf, wlen, buf, rlen);
+       if (ret)
+               goto err;
 
        /* no ack for those packets */
        if (req->cmd == CMD_FW_DL)
-               goto exit_mutex_unlock;
-
-       /* receive ack and data if read req */
-       msg_len = ACK_HDR_LEN + req->rlen + CHECKSUM_LEN;
-       ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, 0x81), buf, msg_len,
-                       &act_len, USB_TIMEOUT);
-       if (ret < 0) {
-               err("recv bulk message failed=%d", ret);
-               ret = -EIO;
-               goto err_mutex_unlock;
-       }
-
-       if (act_len != msg_len) {
-               err("recv bulk message truncated (%d != %d)", act_len, msg_len);
-               ret = -EIO;
-               goto err_mutex_unlock;
-       }
+               goto exit;
 
        /* verify checksum */
-       checksum = af9035_checksum(buf, act_len - 2);
-       tmp_checksum = (buf[act_len - 2] << 8) | buf[act_len - 1];
+       checksum = af9035_checksum(buf, rlen - 2);
+       tmp_checksum = (buf[rlen - 2] << 8) | buf[rlen - 1];
        if (tmp_checksum != checksum) {
-               err("%s: command=%02x checksum mismatch (%04x != %04x)",
-                   __func__, req->cmd, tmp_checksum, checksum);
+               pr_err("%s: command=%02x checksum mismatch (%04x != %04x)\n",
+                               KBUILD_MODNAME, req->cmd, tmp_checksum,
+                               checksum);
                ret = -EIO;
-               goto err_mutex_unlock;
+               goto err;
        }
 
        /* check status */
@@ -126,16 +101,18 @@ static int af9035_ctrl_msg(struct usb_device *udev, struct usb_req *req)
                pr_debug("%s: command=%02x failed fw error=%d\n", __func__,
                                req->cmd, buf[2]);
                ret = -EIO;
-               goto err_mutex_unlock;
+               goto err;
        }
 
        /* read request, copy returned data to return buf */
        if (req->rlen)
                memcpy(req->rbuf, &buf[ACK_HDR_LEN], req->rlen);
 
-err_mutex_unlock:
-exit_mutex_unlock:
-       mutex_unlock(&af9035_usb_mutex);
+exit:
+       return 0;
+
+err:
+       pr_debug("%s: failed=%d\n", __func__, ret);
 
        return ret;
 }
@@ -155,7 +132,7 @@ static int af9035_wr_regs(struct dvb_usb_device *d, u32 reg, u8 *val, int len)
        wbuf[5] = (reg >> 0) & 0xff;
        memcpy(&wbuf[6], val, len);
 
-       return af9035_ctrl_msg(d->udev, &req);
+       return af9035_ctrl_msg(d, &req);
 }
 
 /* read multiple registers */
@@ -165,7 +142,7 @@ static int af9035_rd_regs(struct dvb_usb_device *d, u32 reg, u8 *val, int len)
        u8 mbox = (reg >> 16) & 0xff;
        struct usb_req req = { CMD_MEM_RD, mbox, sizeof(wbuf), wbuf, len, val };
 
-       return af9035_ctrl_msg(d->udev, &req);
+       return af9035_ctrl_msg(d, &req);
 }
 
 /* write single register */
@@ -205,7 +182,7 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
                struct i2c_msg msg[], int num)
 {
        struct dvb_usb_device *d = i2c_get_adapdata(adap);
-       struct state *state = d->priv;
+       struct state *state = d_to_priv(d);
        int ret;
 
        if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
@@ -249,7 +226,7 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
                        buf[3] = 0x00; /* reg addr MSB */
                        buf[4] = 0x00; /* reg addr LSB */
                        memcpy(&buf[5], msg[0].buf, msg[0].len);
-                       ret = af9035_ctrl_msg(d->udev, &req);
+                       ret = af9035_ctrl_msg(d, &req);
                }
        } else if (num == 1 && !(msg[0].flags & I2C_M_RD)) {
                if (msg[0].len > 40) {
@@ -272,7 +249,7 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
                        buf[3] = 0x00; /* reg addr MSB */
                        buf[4] = 0x00; /* reg addr LSB */
                        memcpy(&buf[5], msg[0].buf, msg[0].len);
-                       ret = af9035_ctrl_msg(d->udev, &req);
+                       ret = af9035_ctrl_msg(d, &req);
                }
        } else {
                /*
@@ -301,87 +278,7 @@ static struct i2c_algorithm af9035_i2c_algo = {
        .functionality = af9035_i2c_functionality,
 };
 
-#define AF9035_POLL 250
-static int af9035_rc_query(struct dvb_usb_device *d)
-{
-       unsigned int key;
-       unsigned char b[4];
-       int ret;
-       struct usb_req req = { CMD_IR_GET, 0, 0, NULL, 4, b };
-
-       ret = af9035_ctrl_msg(d->udev, &req);
-       if (ret < 0)
-               goto err;
-
-       if ((b[2] + b[3]) == 0xff) {
-               if ((b[0] + b[1]) == 0xff) {
-                       /* NEC */
-                       key = b[0] << 8 | b[2];
-               } else {
-                       /* ext. NEC */
-                       key = b[0] << 16 | b[1] << 8 | b[2];
-               }
-       } else {
-               key = b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3];
-       }
-
-       rc_keydown(d->rc_dev, key, 0);
-
-err:
-       /* ignore errors */
-       return 0;
-}
-
-static int af9035_init(struct dvb_usb_device *d)
-{
-       struct state *state = d->priv;
-       int ret, i;
-       u16 frame_size = 87 * 188 / 4;
-       u8  packet_size = 512 / 4;
-       struct reg_val_mask tab[] = {
-               { 0x80f99d, 0x01, 0x01 },
-               { 0x80f9a4, 0x01, 0x01 },
-               { 0x00dd11, 0x00, 0x20 },
-               { 0x00dd11, 0x00, 0x40 },
-               { 0x00dd13, 0x00, 0x20 },
-               { 0x00dd13, 0x00, 0x40 },
-               { 0x00dd11, 0x20, 0x20 },
-               { 0x00dd88, (frame_size >> 0) & 0xff, 0xff},
-               { 0x00dd89, (frame_size >> 8) & 0xff, 0xff},
-               { 0x00dd0c, packet_size, 0xff},
-               { 0x00dd11, state->dual_mode << 6, 0x40 },
-               { 0x00dd8a, (frame_size >> 0) & 0xff, 0xff},
-               { 0x00dd8b, (frame_size >> 8) & 0xff, 0xff},
-               { 0x00dd0d, packet_size, 0xff },
-               { 0x80f9a3, 0x00, 0x01 },
-               { 0x80f9cd, 0x00, 0x01 },
-               { 0x80f99d, 0x00, 0x01 },
-               { 0x80f9a4, 0x00, 0x01 },
-       };
-
-       pr_debug("%s: USB speed=%d frame_size=%04x packet_size=%02x\n",
-               __func__, d->udev->speed, frame_size, packet_size);
-
-       /* init endpoints */
-       for (i = 0; i < ARRAY_SIZE(tab); i++) {
-               ret = af9035_wr_reg_mask(d, tab[i].reg, tab[i].val,
-                               tab[i].mask);
-               if (ret < 0)
-                       goto err;
-       }
-
-       return 0;
-
-err:
-       pr_debug("%s: failed=%d\n", __func__, ret);
-
-       return ret;
-}
-
-static int af9035_identify_state(struct usb_device *udev,
-               struct dvb_usb_device_properties *props,
-               struct dvb_usb_device_description **desc,
-               int *cold)
+static int af9035_identify_state(struct dvb_usb_device *d, const char **name)
 {
        int ret;
        u8 wbuf[1] = { 1 };
@@ -389,18 +286,18 @@ static int af9035_identify_state(struct usb_device *udev,
        struct usb_req req = { CMD_FW_QUERYINFO, 0, sizeof(wbuf), wbuf,
                        sizeof(rbuf), rbuf };
 
-       ret = af9035_ctrl_msg(udev, &req);
+       ret = af9035_ctrl_msg(d, &req);
        if (ret < 0)
                goto err;
 
        pr_debug("%s: reply=%02x %02x %02x %02x\n", __func__,
                rbuf[0], rbuf[1], rbuf[2], rbuf[3]);
        if (rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])
-               *cold = 0;
+               ret = WARM;
        else
-               *cold = 1;
+               ret = COLD;
 
-       return 0;
+       return ret;
 
 err:
        pr_debug("%s: failed=%d\n", __func__, ret);
@@ -408,7 +305,7 @@ err:
        return ret;
 }
 
-static int af9035_download_firmware(struct usb_device *udev,
+static int af9035_download_firmware(struct dvb_usb_device *d,
                const struct firmware *fw)
 {
        int ret, i, j, len;
@@ -455,7 +352,7 @@ static int af9035_download_firmware(struct usb_device *udev,
 
                /* download begin packet */
                req.cmd = CMD_FW_DL_BEGIN;
-               ret = af9035_ctrl_msg(udev, &req);
+               ret = af9035_ctrl_msg(d, &req);
                if (ret < 0)
                        goto err;
 
@@ -467,14 +364,14 @@ static int af9035_download_firmware(struct usb_device *udev,
                        req_fw_dl.wlen = len;
                        req_fw_dl.wbuf = (u8 *) &fw->data[fw->size - i +
                                        HDR_SIZE + hdr_data_len - j];
-                       ret = af9035_ctrl_msg(udev, &req_fw_dl);
+                       ret = af9035_ctrl_msg(d, &req_fw_dl);
                        if (ret < 0)
                                goto err;
                }
 
                /* download end packet */
                req.cmd = CMD_FW_DL_END;
-               ret = af9035_ctrl_msg(udev, &req);
+               ret = af9035_ctrl_msg(d, &req);
                if (ret < 0)
                        goto err;
 
@@ -485,24 +382,24 @@ static int af9035_download_firmware(struct usb_device *udev,
 
        /* firmware loaded, request boot */
        req.cmd = CMD_FW_BOOT;
-       ret = af9035_ctrl_msg(udev, &req);
+       ret = af9035_ctrl_msg(d, &req);
        if (ret < 0)
                goto err;
 
        /* ensure firmware starts */
        wbuf[0] = 1;
-       ret = af9035_ctrl_msg(udev, &req_fw_ver);
+       ret = af9035_ctrl_msg(d, &req_fw_ver);
        if (ret < 0)
                goto err;
 
        if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) {
-               info("firmware did not run");
+               pr_err("%s: firmware did not run\n", KBUILD_MODNAME);
                ret = -ENODEV;
                goto err;
        }
 
-       info("firmware version=%d.%d.%d.%d", rbuf[0], rbuf[1], rbuf[2],
-                       rbuf[3]);
+       pr_info("%s: firmware version=%d.%d.%d.%d", KBUILD_MODNAME,
+                       rbuf[0], rbuf[1], rbuf[2], rbuf[3]);
 
        return 0;
 
@@ -512,7 +409,7 @@ err:
        return ret;
 }
 
-static int af9035_download_firmware_it9135(struct usb_device *udev,
+static int af9035_download_firmware_it9135(struct dvb_usb_device *d,
                const struct firmware *fw)
 {
        int ret, i, i_prev;
@@ -545,7 +442,7 @@ static int af9035_download_firmware_it9135(struct usb_device *udev,
                        req_fw_dl.wlen = i - i_prev;
                        req_fw_dl.wbuf = (u8 *) &fw->data[i_prev];
                        i_prev = i;
-                       ret = af9035_ctrl_msg(udev, &req_fw_dl);
+                       ret = af9035_ctrl_msg(d, &req_fw_dl);
                        if (ret < 0)
                                goto err;
 
@@ -555,24 +452,24 @@ static int af9035_download_firmware_it9135(struct usb_device *udev,
 
        /* firmware loaded, request boot */
        req.cmd = CMD_FW_BOOT;
-       ret = af9035_ctrl_msg(udev, &req);
+       ret = af9035_ctrl_msg(d, &req);
        if (ret < 0)
                goto err;
 
        /* ensure firmware starts */
        wbuf[0] = 1;
-       ret = af9035_ctrl_msg(udev, &req_fw_ver);
+       ret = af9035_ctrl_msg(d, &req_fw_ver);
        if (ret < 0)
                goto err;
 
        if (!(rbuf[0] || rbuf[1] || rbuf[2] || rbuf[3])) {
-               info("firmware did not run");
+               pr_err("%s: firmware did not run\n", KBUILD_MODNAME);
                ret = -ENODEV;
                goto err;
        }
 
-       info("firmware version=%d.%d.%d.%d", rbuf[0], rbuf[1], rbuf[2],
-                       rbuf[3]);
+       pr_info("%s: firmware version=%d.%d.%d.%d", KBUILD_MODNAME,
+                       rbuf[0], rbuf[1], rbuf[2], rbuf[3]);
 
        return 0;
 
@@ -582,10 +479,9 @@ err:
        return ret;
 }
 
-/* abuse that callback as there is no better one for reading eeprom */
-static int af9035_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
+static int af9035_read_config(struct dvb_usb_device *d)
 {
-       struct state *state = d->priv;
+       struct state *state = d_to_priv(d);
        int ret, i, eeprom_shift = 0;
        u8 tmp;
        u16 tmp16;
@@ -598,7 +494,7 @@ static int af9035_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
        state->dual_mode = tmp;
        pr_debug("%s: dual mode=%d\n", __func__, state->dual_mode);
 
-       for (i = 0; i < af9035_properties[0].num_adapters; i++) {
+       for (i = 0; i < state->dual_mode + 1; i++) {
                /* tuner */
                ret = af9035_rd_reg(d, EEPROM_1_TUNER_ID + eeprom_shift, &tmp);
                if (ret < 0)
@@ -615,8 +511,8 @@ static int af9035_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
                        state->af9033_config[i].spec_inv = 1;
                        break;
                default:
-                       warn("tuner ID=%02x not supported, please report!",
-                               tmp);
+                       pr_info("%s: tuner ID=%02x not supported, please " \
+                                       "report!", KBUILD_MODNAME, tmp);
                };
 
                /* tuner IF frequency */
@@ -644,35 +540,9 @@ static int af9035_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
 
        tmp = (tmp >> 0) & 0x0f;
 
-       for (i = 0; i < af9035_properties[0].num_adapters; i++)
+       for (i = 0; i < ARRAY_SIZE(state->af9033_config); i++)
                state->af9033_config[i].clock = clock_lut[tmp];
 
-       ret = af9035_rd_reg(d, EEPROM_IR_MODE, &tmp);
-       if (ret < 0)
-               goto err;
-       pr_debug("%s: ir_mode=%02x\n", __func__, tmp);
-
-       /* don't activate rc if in HID mode or if not available */
-       if (tmp == 5) {
-               ret = af9035_rd_reg(d, EEPROM_IR_TYPE, &tmp);
-               if (ret < 0)
-                       goto err;
-               pr_debug("%s: ir_type=%02x\n", __func__, tmp);
-
-               switch (tmp) {
-               case 0: /* NEC */
-               default:
-                       d->props.rc.core.protocol = RC_TYPE_NEC;
-                       d->props.rc.core.allowed_protos = RC_TYPE_NEC;
-                       break;
-               case 1: /* RC6 */
-                       d->props.rc.core.protocol = RC_TYPE_RC6;
-                       d->props.rc.core.allowed_protos = RC_TYPE_RC6;
-                       break;
-               }
-               d->props.rc.core.rc_query = af9035_rc_query;
-       }
-
        return 0;
 
 err:
@@ -681,10 +551,9 @@ err:
        return ret;
 }
 
-/* abuse that callback as there is no better one for reading eeprom */
-static int af9035_read_mac_address_it9135(struct dvb_usb_device *d, u8 mac[6])
+static int af9035_read_config_it9135(struct dvb_usb_device *d)
 {
-       struct state *state = d->priv;
+       struct state *state = d_to_priv(d);
        int ret, i;
        u8 tmp;
 
@@ -697,7 +566,7 @@ static int af9035_read_mac_address_it9135(struct dvb_usb_device *d, u8 mac[6])
 
        tmp = (tmp >> 0) & 0x0f;
 
-       for (i = 0; i < af9035_properties[0].num_adapters; i++)
+       for (i = 0; i < ARRAY_SIZE(state->af9033_config); i++)
                state->af9033_config[i].clock = clock_lut_it9135[tmp];
 
        return 0;
@@ -775,7 +644,7 @@ err:
 
 static int af9035_tuner_callback(struct dvb_usb_device *d, int cmd, int arg)
 {
-       struct state *state = d->priv;
+       struct state *state = d_to_priv(d);
 
        switch (state->af9033_config[0].tuner) {
        case AF9033_TUNER_FC0011:
@@ -805,7 +674,8 @@ static int af9035_frontend_callback(void *adapter_priv, int component,
 
 static int af9035_frontend_attach(struct dvb_usb_adapter *adap)
 {
-       struct state *state = adap->dev->priv;
+       struct state *state = adap_to_priv(adap);
+       struct dvb_usb_device *d = adap_to_d(adap);
        int ret;
 
        if (!state->af9033_config[adap->id].tuner) {
@@ -818,28 +688,28 @@ static int af9035_frontend_attach(struct dvb_usb_adapter *adap)
                state->af9033_config[0].ts_mode = AF9033_TS_MODE_USB;
                state->af9033_config[1].ts_mode = AF9033_TS_MODE_SERIAL;
 
-               ret = af9035_wr_reg(adap->dev, 0x00417f,
+               ret = af9035_wr_reg(d, 0x00417f,
                                state->af9033_config[1].i2c_addr);
                if (ret < 0)
                        goto err;
 
-               ret = af9035_wr_reg(adap->dev, 0x00d81a,
+               ret = af9035_wr_reg(d, 0x00d81a,
                                state->dual_mode);
                if (ret < 0)
                        goto err;
        }
 
        /* attach demodulator */
-       adap->fe_adap[0].fe = dvb_attach(af9033_attach,
-                       &state->af9033_config[adap->id], &adap->dev->i2c_adap);
-       if (adap->fe_adap[0].fe == NULL) {
+       adap->fe[0] = dvb_attach(af9033_attach,
+                       &state->af9033_config[adap->id], &d->i2c_adap);
+       if (adap->fe[0] == NULL) {
                ret = -ENODEV;
                goto err;
        }
 
        /* disable I2C-gate */
-       adap->fe_adap[0].fe->ops.i2c_gate_ctrl = NULL;
-       adap->fe_adap[0].fe->callback = af9035_frontend_callback;
+       adap->fe[0]->ops.i2c_gate_ctrl = NULL;
+       adap->fe[0]->callback = af9035_frontend_callback;
 
        return 0;
 
@@ -873,7 +743,8 @@ static struct tda18218_config af9035_tda18218_config = {
 
 static int af9035_tuner_attach(struct dvb_usb_adapter *adap)
 {
-       struct state *state = adap->dev->priv;
+       struct state *state = adap_to_priv(adap);
+       struct dvb_usb_device *d = adap_to_d(adap);
        int ret;
        struct dvb_frontend *fe;
 
@@ -883,93 +754,93 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap)
                   AF9035 gpiot2 = TUA9001 RXEN */
 
                /* configure gpiot2 and gpiot2 as output */
-               ret = af9035_wr_reg_mask(adap->dev, 0x00d8ec, 0x01, 0x01);
+               ret = af9035_wr_reg_mask(d, 0x00d8ec, 0x01, 0x01);
                if (ret < 0)
                        goto err;
 
-               ret = af9035_wr_reg_mask(adap->dev, 0x00d8ed, 0x01, 0x01);
+               ret = af9035_wr_reg_mask(d, 0x00d8ed, 0x01, 0x01);
                if (ret < 0)
                        goto err;
 
-               ret = af9035_wr_reg_mask(adap->dev, 0x00d8e8, 0x01, 0x01);
+               ret = af9035_wr_reg_mask(d, 0x00d8e8, 0x01, 0x01);
                if (ret < 0)
                        goto err;
 
-               ret = af9035_wr_reg_mask(adap->dev, 0x00d8e9, 0x01, 0x01);
+               ret = af9035_wr_reg_mask(d, 0x00d8e9, 0x01, 0x01);
                if (ret < 0)
                        goto err;
 
                /* reset tuner */
-               ret = af9035_wr_reg_mask(adap->dev, 0x00d8e7, 0x00, 0x01);
+               ret = af9035_wr_reg_mask(d, 0x00d8e7, 0x00, 0x01);
                if (ret < 0)
                        goto err;
 
                usleep_range(2000, 20000);
 
-               ret = af9035_wr_reg_mask(adap->dev, 0x00d8e7, 0x01, 0x01);
+               ret = af9035_wr_reg_mask(d, 0x00d8e7, 0x01, 0x01);
                if (ret < 0)
                        goto err;
 
                /* activate tuner RX */
                /* TODO: use callback for TUA9001 RXEN */
-               ret = af9035_wr_reg_mask(adap->dev, 0x00d8eb, 0x01, 0x01);
+               ret = af9035_wr_reg_mask(d, 0x00d8eb, 0x01, 0x01);
                if (ret < 0)
                        goto err;
 
                /* attach tuner */
-               fe = dvb_attach(tua9001_attach, adap->fe_adap[0].fe,
-                               &adap->dev->i2c_adap, &af9035_tua9001_config);
+               fe = dvb_attach(tua9001_attach, adap->fe[0],
+                               &d->i2c_adap, &af9035_tua9001_config);
                break;
        case AF9033_TUNER_FC0011:
-               fe = dvb_attach(fc0011_attach, adap->fe_adap[0].fe,
-                               &adap->dev->i2c_adap, &af9035_fc0011_config);
+               fe = dvb_attach(fc0011_attach, adap->fe[0],
+                               &d->i2c_adap, &af9035_fc0011_config);
                break;
        case AF9033_TUNER_MXL5007T:
-               ret = af9035_wr_reg(adap->dev, 0x00d8e0, 1);
+               ret = af9035_wr_reg(d, 0x00d8e0, 1);
                if (ret < 0)
                        goto err;
-               ret = af9035_wr_reg(adap->dev, 0x00d8e1, 1);
+               ret = af9035_wr_reg(d, 0x00d8e1, 1);
                if (ret < 0)
                        goto err;
-               ret = af9035_wr_reg(adap->dev, 0x00d8df, 0);
+               ret = af9035_wr_reg(d, 0x00d8df, 0);
                if (ret < 0)
                        goto err;
 
                msleep(30);
 
-               ret = af9035_wr_reg(adap->dev, 0x00d8df, 1);
+               ret = af9035_wr_reg(d, 0x00d8df, 1);
                if (ret < 0)
                        goto err;
 
                msleep(300);
 
-               ret = af9035_wr_reg(adap->dev, 0x00d8c0, 1);
+               ret = af9035_wr_reg(d, 0x00d8c0, 1);
                if (ret < 0)
                        goto err;
-               ret = af9035_wr_reg(adap->dev, 0x00d8c1, 1);
+               ret = af9035_wr_reg(d, 0x00d8c1, 1);
                if (ret < 0)
                        goto err;
-               ret = af9035_wr_reg(adap->dev, 0x00d8bf, 0);
+               ret = af9035_wr_reg(d, 0x00d8bf, 0);
                if (ret < 0)
                        goto err;
-               ret = af9035_wr_reg(adap->dev, 0x00d8b4, 1);
+               ret = af9035_wr_reg(d, 0x00d8b4, 1);
                if (ret < 0)
                        goto err;
-               ret = af9035_wr_reg(adap->dev, 0x00d8b5, 1);
+               ret = af9035_wr_reg(d, 0x00d8b5, 1);
                if (ret < 0)
                        goto err;
-               ret = af9035_wr_reg(adap->dev, 0x00d8b3, 1);
+               ret = af9035_wr_reg(d, 0x00d8b3, 1);
                if (ret < 0)
                        goto err;
 
                /* attach tuner */
-               fe = dvb_attach(mxl5007t_attach, adap->fe_adap[0].fe,
-                               &adap->dev->i2c_adap, 0x60, &af9035_mxl5007t_config);
+               fe = dvb_attach(mxl5007t_attach, adap->fe[0],
+                               &d->i2c_adap, 0x60, &af9035_mxl5007t_config);
                break;
        case AF9033_TUNER_TDA18218:
                /* attach tuner */
-               fe = dvb_attach(tda18218_attach, adap->fe_adap[0].fe,
-                               &adap->dev->i2c_adap, &af9035_tda18218_config);
+               fe = dvb_attach(tda18218_attach, adap->fe[0],
+                               &d->i2c_adap, &af9035_tda18218_config);
                break;
        default:
                fe = NULL;
@@ -988,235 +859,117 @@ err:
        return ret;
 }
 
-enum af9035_id_entry {
-       AF9035_15A4_9035,
-       AF9035_15A4_1000,
-       AF9035_15A4_1001,
-       AF9035_15A4_1002,
-       AF9035_15A4_1003,
-       AF9035_0CCD_0093,
-       AF9035_07CA_A835,
-       AF9035_07CA_B835,
-       AF9035_07CA_1867,
-       AF9035_07CA_A867,
-       AF9035_07CA_0825,
-};
-
-static struct usb_device_id af9035_id[] = {
-       [AF9035_15A4_9035] = {
-               USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_9035)},
-       [AF9035_15A4_1000] = {
-               USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1000)},
-       [AF9035_15A4_1001] = {
-               USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1001)},
-       [AF9035_15A4_1002] = {
-               USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1002)},
-       [AF9035_15A4_1003] = {
-               USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1003)},
-       [AF9035_0CCD_0093] = {
-               USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK)},
-       [AF9035_07CA_A835] = {
-               USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835)},
-       [AF9035_07CA_B835] = {
-               USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_B835)},
-       [AF9035_07CA_1867] = {
-               USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_1867)},
-       [AF9035_07CA_A867] = {
-               USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A867)},
-       [AF9035_07CA_0825] = {
-               USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_TWINSTAR)},
-       {},
-};
+static int af9035_init(struct dvb_usb_device *d)
+{
+       struct state *state = d_to_priv(d);
+       int ret, i;
+       u16 frame_size = 87 * 188 / 4;
+       u8  packet_size = 512 / 4;
+       struct reg_val_mask tab[] = {
+               { 0x80f99d, 0x01, 0x01 },
+               { 0x80f9a4, 0x01, 0x01 },
+               { 0x00dd11, 0x00, 0x20 },
+               { 0x00dd11, 0x00, 0x40 },
+               { 0x00dd13, 0x00, 0x20 },
+               { 0x00dd13, 0x00, 0x40 },
+               { 0x00dd11, 0x20, 0x20 },
+               { 0x00dd88, (frame_size >> 0) & 0xff, 0xff},
+               { 0x00dd89, (frame_size >> 8) & 0xff, 0xff},
+               { 0x00dd0c, packet_size, 0xff},
+               { 0x00dd11, state->dual_mode << 6, 0x40 },
+               { 0x00dd8a, (frame_size >> 0) & 0xff, 0xff},
+               { 0x00dd8b, (frame_size >> 8) & 0xff, 0xff},
+               { 0x00dd0d, packet_size, 0xff },
+               { 0x80f9a3, 0x00, 0x01 },
+               { 0x80f9cd, 0x00, 0x01 },
+               { 0x80f99d, 0x00, 0x01 },
+               { 0x80f9a4, 0x00, 0x01 },
+       };
 
-MODULE_DEVICE_TABLE(usb, af9035_id);
-
-static struct dvb_usb_device_properties af9035_properties[] = {
-       {
-               .caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-               .usb_ctrl = DEVICE_SPECIFIC,
-               .download_firmware = af9035_download_firmware,
-               .firmware = "dvb-usb-af9035-02.fw",
-               .no_reconnect = 1,
-
-               .size_of_priv = sizeof(struct state),
-
-               .num_adapters = 1,
-               .adapter = {
-                       {
-                               .num_frontends = 1,
-                               .fe = {
-                                       {
-                                               .frontend_attach = af9035_frontend_attach,
-                                               .tuner_attach = af9035_tuner_attach,
-                                               .stream = {
-                                                       .type = USB_BULK,
-                                                       .count = 6,
-                                                       .endpoint = 0x84,
-                                                       .u = {
-                                                               .bulk = {
-                                                                       .buffersize = (87 * 188),
-                                                               }
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               },
+       pr_debug("%s: USB speed=%d frame_size=%04x packet_size=%02x\n",
+               __func__, d->udev->speed, frame_size, packet_size);
 
-               .identify_state = af9035_identify_state,
-               .read_mac_address = af9035_read_mac_address,
+       /* init endpoints */
+       for (i = 0; i < ARRAY_SIZE(tab); i++) {
+               ret = af9035_wr_reg_mask(d, tab[i].reg, tab[i].val,
+                               tab[i].mask);
+               if (ret < 0)
+                       goto err;
+       }
 
-               .i2c_algo = &af9035_i2c_algo,
+       return 0;
 
-               .rc.core = {
-                       .protocol       = RC_TYPE_UNKNOWN,
-                       .module_name    = "af9035",
-                       .rc_query       = NULL,
-                       .rc_interval    = AF9035_POLL,
-                       .allowed_protos = RC_TYPE_UNKNOWN,
-                       .rc_codes       = RC_MAP_EMPTY,
-               },
-               .num_device_descs = 5,
-               .devices = {
-                       {
-                               .name = "Afatech AF9035 reference design",
-                               .cold_ids = {
-                                       &af9035_id[AF9035_15A4_9035],
-                                       &af9035_id[AF9035_15A4_1000],
-                                       &af9035_id[AF9035_15A4_1001],
-                                       &af9035_id[AF9035_15A4_1002],
-                                       &af9035_id[AF9035_15A4_1003],
-                               },
-                       }, {
-                               .name = "TerraTec Cinergy T Stick",
-                               .cold_ids = {
-                                       &af9035_id[AF9035_0CCD_0093],
-                               },
-                       }, {
-                               .name = "AVerMedia AVerTV Volar HD/PRO (A835)",
-                               .cold_ids = {
-                                       &af9035_id[AF9035_07CA_A835],
-                                       &af9035_id[AF9035_07CA_B835],
-                               },
-                       }, {
-                               .name = "AVerMedia HD Volar (A867)",
-                               .cold_ids = {
-                                       &af9035_id[AF9035_07CA_1867],
-                                       &af9035_id[AF9035_07CA_A867],
-                               },
-                       }, {
-                               .name = "AVerMedia Twinstar (A825)",
-                               .cold_ids = {
-                                       &af9035_id[AF9035_07CA_0825],
-                               },
-                       },
-               }
-       },
-       {
-               .caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-               .usb_ctrl = DEVICE_SPECIFIC,
-               .download_firmware = af9035_download_firmware_it9135,
-               .firmware = "dvb-usb-it9135-01.fw",
-               .no_reconnect = 1,
-
-               .size_of_priv = sizeof(struct state),
-
-               .num_adapters = 1,
-               .adapter = {
-                       {
-                               .num_frontends = 1,
-                               .fe = {
-                                       {
-                                               .frontend_attach = af9035_frontend_attach,
-                                               .tuner_attach = af9035_tuner_attach,
-                                               .stream = {
-                                                       .type = USB_BULK,
-                                                       .count = 6,
-                                                       .endpoint = 0x84,
-                                                       .u = {
-                                                               .bulk = {
-                                                                       .buffersize = (87 * 188),
-                                                               }
-                                                       }
-                                               }
-                                       }
-                               }
-                       }
-               },
+err:
+       pr_debug("%s: failed=%d\n", __func__, ret);
 
-               .identify_state = af9035_identify_state,
-               .read_mac_address = af9035_read_mac_address_it9135,
+       return ret;
+}
 
-               .i2c_algo = &af9035_i2c_algo,
+static int af9035_rc_query(struct dvb_usb_device *d)
+{
+       unsigned int key;
+       unsigned char b[4];
+       int ret;
+       struct usb_req req = { CMD_IR_GET, 0, 0, NULL, 4, b };
 
-               .num_device_descs = 0, /* disabled as no support for IT9135 */
-               .devices = {
-                       {
-                               .name = "ITE Tech. IT9135 reference design",
-                       },
-               }
-       },
-};
+       ret = af9035_ctrl_msg(d, &req);
+       if (ret < 0)
+               goto err;
 
-static int af9035_usb_probe(struct usb_interface *intf,
-                           const struct usb_device_id *id)
-{
-       int ret, i;
-       struct dvb_usb_device *d = NULL;
-       struct usb_device *udev;
-       bool found;
-
-       pr_debug("%s: interface=%d\n", __func__,
-                       intf->cur_altsetting->desc.bInterfaceNumber);
-
-       /* interface 0 is used by DVB-T receiver and
-          interface 1 is for remote controller (HID) */
-       if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
-               return 0;
-
-       /* Dynamic USB ID support. Replaces first device ID with current one. */
-       udev = interface_to_usbdev(intf);
-
-       for (i = 0, found = false; i < ARRAY_SIZE(af9035_id) - 1; i++) {
-               if (af9035_id[i].idVendor ==
-                               le16_to_cpu(udev->descriptor.idVendor) &&
-                               af9035_id[i].idProduct ==
-                               le16_to_cpu(udev->descriptor.idProduct)) {
-                       found = true;
-                       break;
+       if ((b[2] + b[3]) == 0xff) {
+               if ((b[0] + b[1]) == 0xff) {
+                       /* NEC */
+                       key = b[0] << 8 | b[2];
+               } else {
+                       /* ext. NEC */
+                       key = b[0] << 16 | b[1] << 8 | b[2];
                }
+       } else {
+               key = b[0] << 24 | b[1] << 16 | b[2] << 8 | b[3];
        }
 
-       if (!found) {
-               pr_debug("%s: using dynamic ID %04x:%04x\n", __func__,
-                               le16_to_cpu(udev->descriptor.idVendor),
-                               le16_to_cpu(udev->descriptor.idProduct));
-               af9035_properties[0].devices[0].cold_ids[0]->idVendor =
-                               le16_to_cpu(udev->descriptor.idVendor);
-               af9035_properties[0].devices[0].cold_ids[0]->idProduct =
-                               le16_to_cpu(udev->descriptor.idProduct);
-       }
-
+       rc_keydown(d->rc_dev, key, 0);
 
-       for (i = 0; i < af9035_properties_count; i++) {
-               ret = dvb_usb_device_init(intf, &af9035_properties[i],
-                               THIS_MODULE, &d, adapter_nr);
+err:
+       /* ignore errors */
+       return 0;
+}
 
-               if (ret == -ENODEV)
-                       continue;
-               else
-                       break;
-       }
+static int af9035_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
+{
+       int ret;
+       u8 tmp;
 
+       ret = af9035_rd_reg(d, EEPROM_IR_MODE, &tmp);
        if (ret < 0)
                goto err;
 
-       if (d) {
-               ret = af9035_init(d);
+       pr_debug("%s: ir_mode=%02x\n", __func__, tmp);
+
+       /* don't activate rc if in HID mode or if not available */
+       if (tmp == 5) {
+               ret = af9035_rd_reg(d, EEPROM_IR_TYPE, &tmp);
                if (ret < 0)
                        goto err;
+
+               pr_debug("%s: ir_type=%02x\n", __func__, tmp);
+
+               switch (tmp) {
+               case 0: /* NEC */
+               default:
+                       rc->allowed_protos = RC_TYPE_NEC;
+                       break;
+               case 1: /* RC6 */
+                       rc->allowed_protos = RC_TYPE_RC6;
+                       break;
+               }
+
+               rc->query = af9035_rc_query;
+               rc->interval = 500;
+
+               /* load empty to enable rc */
+               if (!rc->map_name)
+                       rc->map_name = RC_MAP_EMPTY;
        }
 
        return 0;
@@ -1227,12 +980,104 @@ err:
        return ret;
 }
 
-/* usb specific object needed to register this driver with the usb subsystem */
+/* interface 0 is used by DVB-T receiver and
+   interface 1 is for remote controller (HID) */
+static const struct dvb_usb_device_properties af9035_props = {
+       .driver_name = KBUILD_MODNAME,
+       .owner = THIS_MODULE,
+       .adapter_nr = adapter_nr,
+       .size_of_priv = sizeof(struct state),
+
+       .generic_bulk_ctrl_endpoint = 0x02,
+       .generic_bulk_ctrl_endpoint_response = 0x81,
+
+       .identify_state = af9035_identify_state,
+       .firmware = "dvb-usb-af9035-02.fw",
+       .download_firmware = af9035_download_firmware,
+
+       .i2c_algo = &af9035_i2c_algo,
+       .read_config = af9035_read_config,
+       .frontend_attach = af9035_frontend_attach,
+       .tuner_attach = af9035_tuner_attach,
+       .init = af9035_init,
+       .get_rc_config = af9035_get_rc_config,
+
+       .num_adapters = 1,
+       .adapter = {
+               {
+                       .stream = DVB_USB_STREAM_BULK(0x84, 6, 87 * 188),
+               }, {
+                       .stream = DVB_USB_STREAM_BULK(0x85, 6, 87 * 188),
+               },
+       },
+};
+
+static const struct dvb_usb_device_properties it9135_props = {
+       .driver_name = KBUILD_MODNAME,
+       .owner = THIS_MODULE,
+       .adapter_nr = adapter_nr,
+       .size_of_priv = sizeof(struct state),
+
+       .generic_bulk_ctrl_endpoint = 0x02,
+       .generic_bulk_ctrl_endpoint_response = 0x81,
+
+       .identify_state = af9035_identify_state,
+       .firmware = "dvb-usb-it9135-01.fw",
+       .download_firmware = af9035_download_firmware_it9135,
+
+       .i2c_algo = &af9035_i2c_algo,
+       .read_config = af9035_read_config_it9135,
+       .frontend_attach = af9035_frontend_attach,
+       .tuner_attach = af9035_tuner_attach,
+       .init = af9035_init,
+       .get_rc_config = af9035_get_rc_config,
+
+       .num_adapters = 1,
+       .adapter = {
+               {
+                       .stream = DVB_USB_STREAM_BULK(0x84, 6, 87 * 188),
+               }, {
+                       .stream = DVB_USB_STREAM_BULK(0x85, 6, 87 * 188),
+               },
+       },
+};
+
+static const struct usb_device_id af9035_id_table[] = {
+       { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_9035,
+               &af9035_props, "Afatech AF9035 reference design", NULL) },
+       { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1000,
+               &af9035_props, "Afatech AF9035 reference design", NULL) },
+       { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1001,
+               &af9035_props, "Afatech AF9035 reference design", NULL) },
+       { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1002,
+               &af9035_props, "Afatech AF9035 reference design", NULL) },
+       { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_1003,
+               &af9035_props, "Afatech AF9035 reference design", NULL) },
+       { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK,
+               &af9035_props, "TerraTec Cinergy T Stick", NULL) },
+       { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A835,
+               &af9035_props, "AVerMedia AVerTV Volar HD/PRO (A835)", NULL) },
+       { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_B835,
+               &af9035_props, "AVerMedia AVerTV Volar HD/PRO (A835)", NULL) },
+       { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_1867,
+               &af9035_props, "AVerMedia HD Volar (A867)", NULL) },
+       { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A867,
+               &af9035_props, "AVerMedia HD Volar (A867)", NULL) },
+       { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_TWINSTAR,
+               &af9035_props, "AVerMedia Twinstar (A825)", NULL) },
+       { }
+};
+MODULE_DEVICE_TABLE(usb, af9035_id_table);
+
 static struct usb_driver af9035_usb_driver = {
-       .name = "dvb_usb_af9035",
-       .probe = af9035_usb_probe,
-       .disconnect = dvb_usb_device_exit,
-       .id_table = af9035_id,
+       .name = KBUILD_MODNAME,
+       .id_table = af9035_id_table,
+       .probe = dvb_usbv2_probe,
+       .disconnect = dvb_usbv2_disconnect,
+       .suspend = dvb_usbv2_suspend,
+       .resume = dvb_usbv2_resume,
+       .no_dynamic_id = 1,
+       .soft_unbind = 1,
 };
 
 module_usb_driver(af9035_usb_driver);
similarity index 96%
rename from drivers/media/dvb/dvb-usb/af9035.h
rename to drivers/media/dvb/dvb-usb-v2/af9035.h
index 481a1a43dd2a65909ad9846f4b9332aa95f98bb4..59ff69ede0f016a6c940ccc9bee2615747657879 100644 (file)
 #ifndef AF9035_H
 #define AF9035_H
 
-/* prefix for dvb-usb log writings */
-#define DVB_USB_LOG_PREFIX "af9035"
-
-#include "dvb-usb.h"
+#include "dvb_usb.h"
 #include "af9033.h"
 #include "tua9001.h"
 #include "fc0011.h"
@@ -53,6 +50,7 @@ struct usb_req {
 };
 
 struct state {
+       u8 seq; /* packet sequence number */
        bool dual_mode;
 
        struct af9033_config af9033_config[2];
similarity index 70%
rename from drivers/media/dvb/dvb-usb/anysee.c
rename to drivers/media/dvb/dvb-usb-v2/anysee.c
index 03c28655af1be54eec6e10486ab5fa71ccc58787..fb3829a73d2df0fa5ad8a70cb3161f387b448e9c 100644 (file)
@@ -32,6 +32,7 @@
  */
 
 #include "anysee.h"
+#include "dvb-pll.h"
 #include "tda1002x.h"
 #include "mt352.h"
 #include "mt352_priv.h"
@@ -47,9 +48,6 @@
 static int dvb_usb_anysee_debug;
 module_param_named(debug, dvb_usb_anysee_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
-static int dvb_usb_anysee_delsys;
-module_param_named(delsys, dvb_usb_anysee_delsys, int, 0644);
-MODULE_PARM_DESC(delsys, "select delivery mode (0=DVB-C, 1=DVB-T)");
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 static DEFINE_MUTEX(anysee_usb_mutex);
@@ -57,22 +55,21 @@ static DEFINE_MUTEX(anysee_usb_mutex);
 static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen,
        u8 *rbuf, u8 rlen)
 {
-       struct anysee_state *state = d->priv;
+       struct anysee_state *state = d_to_priv(d);
        int act_len, ret, i;
        u8 buf[64];
 
        memcpy(&buf[0], sbuf, slen);
        buf[60] = state->seq++;
 
-       if (mutex_lock_interruptible(&anysee_usb_mutex) < 0)
-               return -EAGAIN;
+       mutex_lock(&anysee_usb_mutex);
 
        deb_xfer(">>> ");
        debug_dump(buf, slen, deb_xfer);
 
        /* We need receive one message more after dvb_usb_generic_rw due
           to weird transaction flow, which is 1 x send + 2 x receive. */
-       ret = dvb_usb_generic_rw(d, buf, sizeof(buf), buf, sizeof(buf), 0);
+       ret = dvb_usbv2_generic_rw(d, buf, sizeof(buf), buf, sizeof(buf));
        if (ret)
                goto error_unlock;
 
@@ -91,7 +88,7 @@ static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen,
        for (i = 0; i < 3; i++) {
                /* receive 2nd answer */
                ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev,
-                       d->props.generic_bulk_ctrl_endpoint), buf, sizeof(buf),
+                       d->props->generic_bulk_ctrl_endpoint), buf, sizeof(buf),
                        &act_len, 2000);
 
                if (ret) {
@@ -190,11 +187,11 @@ static int anysee_get_hw_info(struct dvb_usb_device *d, u8 *id)
        return anysee_ctrl_msg(d, buf, sizeof(buf), id, 3);
 }
 
-static int anysee_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+static int anysee_streaming_ctrl(struct dvb_frontend *fe, int onoff)
 {
        u8 buf[] = {CMD_STREAMING_CTRL, (u8)onoff, 0x00};
        deb_info("%s: onoff:%02x\n", __func__, onoff);
-       return anysee_ctrl_msg(adap->dev, buf, sizeof(buf), NULL, 0);
+       return anysee_ctrl_msg(fe_to_d(fe), buf, sizeof(buf), NULL, 0);
 }
 
 static int anysee_led_ctrl(struct dvb_usb_device *d, u8 mode, u8 interval)
@@ -509,20 +506,44 @@ static struct cxd2820r_config anysee_cxd2820r_config = {
  * IOE[5] STV0903 1=enabled
  */
 
+static int anysee_read_config(struct dvb_usb_device *d)
+{
+       struct anysee_state *state = d_to_priv(d);
+       int ret;
+       u8 hw_info[3];
+
+       /*
+        * Check which hardware we have.
+        * We must do this call two times to get reliable values (hw/fw bug).
+        */
+       ret = anysee_get_hw_info(d, hw_info);
+       if (ret)
+               goto error;
+
+       ret = anysee_get_hw_info(d, hw_info);
+       if (ret)
+               goto error;
+
+       /* Meaning of these info bytes are guessed. */
+       info("firmware version:%d.%d hardware id:%d",
+               hw_info[1], hw_info[2], hw_info[0]);
+
+       state->hw = hw_info[0];
+error:
+       return ret;
+}
 
 /* external I2C gate used for DNOD44CDH086A(TDA18212) tuner module */
 static int anysee_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
 {
-       struct dvb_usb_adapter *adap = fe->dvb->priv;
-
        /* enable / disable tuner access on IOE[4] */
-       return anysee_wr_reg_mask(adap->dev, REG_IOE, (enable << 4), 0x10);
+       return anysee_wr_reg_mask(fe_to_d(fe), REG_IOE, (enable << 4), 0x10);
 }
 
 static int anysee_frontend_ctrl(struct dvb_frontend *fe, int onoff)
 {
-       struct dvb_usb_adapter *adap = fe->dvb->priv;
-       struct anysee_state *state = adap->dev->priv;
+       struct anysee_state *state = fe_to_priv(fe);
+       struct dvb_usb_device *d = fe_to_d(fe);
        int ret;
 
        deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff);
@@ -536,40 +557,34 @@ static int anysee_frontend_ctrl(struct dvb_frontend *fe, int onoff)
                /* E30 Combo Plus */
                /* E30 C Plus */
 
-               if ((fe->id ^ dvb_usb_anysee_delsys) == 0)  {
+               if (fe->id == 0)  {
                        /* disable DVB-T demod on IOD[0] */
-                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 0),
-                               0x01);
+                       ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 0), 0x01);
                        if (ret)
                                goto error;
 
                        /* enable DVB-C demod on IOD[5] */
-                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5),
-                               0x20);
+                       ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 5), 0x20);
                        if (ret)
                                goto error;
 
                        /* enable DVB-C tuner on IOE[0] */
-                       ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 0),
-                               0x01);
+                       ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 0), 0x01);
                        if (ret)
                                goto error;
                } else {
                        /* disable DVB-C demod on IOD[5] */
-                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5),
-                               0x20);
+                       ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 5), 0x20);
                        if (ret)
                                goto error;
 
                        /* enable DVB-T demod on IOD[0] */
-                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0),
-                               0x01);
+                       ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01);
                        if (ret)
                                goto error;
 
                        /* enable DVB-T tuner on IOE[0] */
-                       ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 0),
-                               0x01);
+                       ret = anysee_wr_reg_mask(d, REG_IOE, (0 << 0), 0x01);
                        if (ret)
                                goto error;
                }
@@ -580,40 +595,34 @@ static int anysee_frontend_ctrl(struct dvb_frontend *fe, int onoff)
                /* E7 TC */
                /* E7 PTC */
 
-               if ((fe->id ^ dvb_usb_anysee_delsys) == 0)  {
+               if (fe->id == 0)  {
                        /* disable DVB-T demod on IOD[6] */
-                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 6),
-                               0x40);
+                       ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 6), 0x40);
                        if (ret)
                                goto error;
 
                        /* enable DVB-C demod on IOD[5] */
-                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5),
-                               0x20);
+                       ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 5), 0x20);
                        if (ret)
                                goto error;
 
                        /* enable IF route on IOE[0] */
-                       ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 0),
-                               0x01);
+                       ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 0), 0x01);
                        if (ret)
                                goto error;
                } else {
                        /* disable DVB-C demod on IOD[5] */
-                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5),
-                               0x20);
+                       ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 5), 0x20);
                        if (ret)
                                goto error;
 
                        /* enable DVB-T demod on IOD[6] */
-                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 6),
-                               0x40);
+                       ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 6), 0x40);
                        if (ret)
                                goto error;
 
                        /* enable IF route on IOE[0] */
-                       ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 0),
-                               0x01);
+                       ret = anysee_wr_reg_mask(d, REG_IOE, (0 << 0), 0x01);
                        if (ret)
                                goto error;
                }
@@ -629,9 +638,9 @@ error:
 
 static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
 {
+       struct anysee_state *state = adap_to_priv(adap);
+       struct dvb_usb_device *d = adap_to_d(adap);
        int ret;
-       struct anysee_state *state = adap->dev->priv;
-       u8 hw_info[3];
        u8 tmp;
        struct i2c_msg msg[2] = {
                {
@@ -647,100 +656,63 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
                }
        };
 
-       /* detect hardware only once */
-       if (adap->fe_adap[0].fe == NULL) {
-               /* Check which hardware we have.
-                * We must do this call two times to get reliable values
-                * (hw/fw bug).
-                */
-               ret = anysee_get_hw_info(adap->dev, hw_info);
-               if (ret)
-                       goto error;
-
-               ret = anysee_get_hw_info(adap->dev, hw_info);
-               if (ret)
-                       goto error;
-
-               /* Meaning of these info bytes are guessed. */
-               info("firmware version:%d.%d hardware id:%d",
-                       hw_info[1], hw_info[2], hw_info[0]);
-
-               state->hw = hw_info[0];
-       }
-
-       /* set current frondend ID for devices having two frondends */
-       if (adap->fe_adap[0].fe)
-               state->fe_id++;
-
        switch (state->hw) {
        case ANYSEE_HW_507T: /* 2 */
                /* E30 */
 
-               if (state->fe_id)
-                       break;
-
                /* attach demod */
-               adap->fe_adap[0].fe = dvb_attach(mt352_attach,
-                       &anysee_mt352_config, &adap->dev->i2c_adap);
-               if (adap->fe_adap[0].fe)
+               adap->fe[0] = dvb_attach(mt352_attach, &anysee_mt352_config,
+                               &d->i2c_adap);
+               if (adap->fe[0])
                        break;
 
                /* attach demod */
-               adap->fe_adap[0].fe = dvb_attach(zl10353_attach,
-                       &anysee_zl10353_config, &adap->dev->i2c_adap);
+               adap->fe[0] = dvb_attach(zl10353_attach, &anysee_zl10353_config,
+                               &d->i2c_adap);
 
                break;
        case ANYSEE_HW_507CD: /* 6 */
                /* E30 Plus */
 
-               if (state->fe_id)
-                       break;
-
                /* enable DVB-T demod on IOD[0] */
-               ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01);
+               ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01);
                if (ret)
                        goto error;
 
                /* enable transport stream on IOA[7] */
-               ret = anysee_wr_reg_mask(adap->dev, REG_IOA, (0 << 7), 0x80);
+               ret = anysee_wr_reg_mask(d, REG_IOA, (0 << 7), 0x80);
                if (ret)
                        goto error;
 
                /* attach demod */
-               adap->fe_adap[0].fe = dvb_attach(zl10353_attach,
-                       &anysee_zl10353_config, &adap->dev->i2c_adap);
+               adap->fe[0] = dvb_attach(zl10353_attach, &anysee_zl10353_config,
+                               &d->i2c_adap);
 
                break;
        case ANYSEE_HW_507DC: /* 10 */
                /* E30 C Plus */
 
-               if (state->fe_id)
-                       break;
-
                /* enable DVB-C demod on IOD[0] */
-               ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01);
+               ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01);
                if (ret)
                        goto error;
 
                /* attach demod */
-               adap->fe_adap[0].fe = dvb_attach(tda10023_attach,
-                       &anysee_tda10023_config, &adap->dev->i2c_adap, 0x48);
+               adap->fe[0] = dvb_attach(tda10023_attach,
+                               &anysee_tda10023_config, &d->i2c_adap, 0x48);
 
                break;
        case ANYSEE_HW_507SI: /* 11 */
                /* E30 S2 Plus */
 
-               if (state->fe_id)
-                       break;
-
                /* enable DVB-S/S2 demod on IOD[0] */
-               ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0), 0x01);
+               ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01);
                if (ret)
                        goto error;
 
                /* attach demod */
-               adap->fe_adap[0].fe = dvb_attach(cx24116_attach,
-                       &anysee_cx24116_config, &adap->dev->i2c_adap);
+               adap->fe[0] = dvb_attach(cx24116_attach, &anysee_cx24116_config,
+                               &d->i2c_adap);
 
                break;
        case ANYSEE_HW_507FA: /* 15 */
@@ -748,84 +720,81 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
                /* E30 C Plus */
 
                /* enable tuner on IOE[4] */
-               ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 4), 0x10);
+               ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 4), 0x10);
                if (ret)
                        goto error;
 
                /* probe TDA18212 */
                tmp = 0;
-               ret = i2c_transfer(&adap->dev->i2c_adap, msg, 2);
+               ret = i2c_transfer(&d->i2c_adap, msg, 2);
                if (ret == 2 && tmp == 0xc7)
                        deb_info("%s: TDA18212 found\n", __func__);
                else
                        tmp = 0;
 
                /* disable tuner on IOE[4] */
-               ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (0 << 4), 0x10);
+               ret = anysee_wr_reg_mask(d, REG_IOE, (0 << 4), 0x10);
                if (ret)
                        goto error;
 
-               if ((state->fe_id ^ dvb_usb_anysee_delsys) == 0)  {
-                       /* disable DVB-T demod on IOD[0] */
-                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 0),
-                               0x01);
-                       if (ret)
-                               goto error;
+               /* disable DVB-T demod on IOD[0] */
+               ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 0), 0x01);
+               if (ret)
+                       goto error;
 
-                       /* enable DVB-C demod on IOD[5] */
-                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5),
-                               0x20);
-                       if (ret)
-                               goto error;
+               /* enable DVB-C demod on IOD[5] */
+               ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 5), 0x20);
+               if (ret)
+                       goto error;
 
-                       /* attach demod */
-                       if (tmp == 0xc7) {
-                               /* TDA18212 config */
-                               adap->fe_adap[state->fe_id].fe = dvb_attach(
-                                       tda10023_attach,
+               /* attach demod */
+               if (tmp == 0xc7) {
+                       /* TDA18212 config */
+                       adap->fe[0] = dvb_attach(tda10023_attach,
                                        &anysee_tda10023_tda18212_config,
-                                       &adap->dev->i2c_adap, 0x48);
-                       } else {
-                               /* PLL config */
-                               adap->fe_adap[state->fe_id].fe = dvb_attach(
-                                       tda10023_attach,
-                                       &anysee_tda10023_config,
-                                       &adap->dev->i2c_adap, 0x48);
-                       }
+                                       &d->i2c_adap, 0x48);
+
+                       /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */
+                       if (adap->fe[0])
+                               adap->fe[0]->ops.i2c_gate_ctrl =
+                                               anysee_i2c_gate_ctrl;
                } else {
-                       /* disable DVB-C demod on IOD[5] */
-                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5),
-                               0x20);
-                       if (ret)
-                               goto error;
+                       /* PLL config */
+                       adap->fe[0] = dvb_attach(tda10023_attach,
+                                       &anysee_tda10023_config,
+                                       &d->i2c_adap, 0x48);
+               }
 
-                       /* enable DVB-T demod on IOD[0] */
-                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 0),
-                               0x01);
-                       if (ret)
-                               goto error;
+               /* break out if first frontend attaching fails */
+               if (!adap->fe[0])
+                       break;
 
-                       /* attach demod */
-                       if (tmp == 0xc7) {
-                               /* TDA18212 config */
-                               adap->fe_adap[state->fe_id].fe = dvb_attach(
-                                       zl10353_attach,
-                                       &anysee_zl10353_tda18212_config2,
-                                       &adap->dev->i2c_adap);
-                       } else {
-                               /* PLL config */
-                               adap->fe_adap[state->fe_id].fe = dvb_attach(
-                                       zl10353_attach,
-                                       &anysee_zl10353_config,
-                                       &adap->dev->i2c_adap);
-                       }
-               }
+               /* disable DVB-C demod on IOD[5] */
+               ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 5), 0x20);
+               if (ret)
+                       goto error;
 
-               /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */
+               /* enable DVB-T demod on IOD[0] */
+               ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 0), 0x01);
+               if (ret)
+                       goto error;
+
+               /* attach demod */
                if (tmp == 0xc7) {
-                       if (adap->fe_adap[state->fe_id].fe)
-                               adap->fe_adap[state->fe_id].fe->ops.i2c_gate_ctrl =
-                                       anysee_i2c_gate_ctrl;
+                       /* TDA18212 config */
+                       adap->fe[1] = dvb_attach(zl10353_attach,
+                                       &anysee_zl10353_tda18212_config2,
+                                       &d->i2c_adap);
+
+                       /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */
+                       if (adap->fe[1])
+                               adap->fe[1]->ops.i2c_gate_ctrl =
+                                               anysee_i2c_gate_ctrl;
+               } else {
+                       /* PLL config */
+                       adap->fe[1] = dvb_attach(zl10353_attach,
+                                       &anysee_zl10353_config,
+                                       &d->i2c_adap);
                }
 
                break;
@@ -834,48 +803,47 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
                /* E7 TC */
                /* E7 PTC */
 
-               if ((state->fe_id ^ dvb_usb_anysee_delsys) == 0)  {
-                       /* disable DVB-T demod on IOD[6] */
-                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 6),
-                               0x40);
-                       if (ret)
-                               goto error;
+               /* disable DVB-T demod on IOD[6] */
+               ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 6), 0x40);
+               if (ret)
+                       goto error;
 
-                       /* enable DVB-C demod on IOD[5] */
-                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 5),
-                               0x20);
-                       if (ret)
-                               goto error;
+               /* enable DVB-C demod on IOD[5] */
+               ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 5), 0x20);
+               if (ret)
+                       goto error;
 
-                       /* attach demod */
-                       adap->fe_adap[state->fe_id].fe =
-                               dvb_attach(tda10023_attach,
+               /* attach demod */
+               adap->fe[0] = dvb_attach(tda10023_attach,
                                &anysee_tda10023_tda18212_config,
-                               &adap->dev->i2c_adap, 0x48);
-               } else {
-                       /* disable DVB-C demod on IOD[5] */
-                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (0 << 5),
-                               0x20);
-                       if (ret)
-                               goto error;
+                               &d->i2c_adap, 0x48);
 
-                       /* enable DVB-T demod on IOD[6] */
-                       ret = anysee_wr_reg_mask(adap->dev, REG_IOD, (1 << 6),
-                               0x40);
-                       if (ret)
-                               goto error;
+               /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */
+               if (adap->fe[0])
+                       adap->fe[0]->ops.i2c_gate_ctrl = anysee_i2c_gate_ctrl;
+
+               /* break out if first frontend attaching fails */
+               if (!adap->fe[0])
+                       break;
+
+               /* disable DVB-C demod on IOD[5] */
+               ret = anysee_wr_reg_mask(d, REG_IOD, (0 << 5), 0x20);
+               if (ret)
+                       goto error;
 
-                       /* attach demod */
-                       adap->fe_adap[state->fe_id].fe =
-                               dvb_attach(zl10353_attach,
+               /* enable DVB-T demod on IOD[6] */
+               ret = anysee_wr_reg_mask(d, REG_IOD, (1 << 6), 0x40);
+               if (ret)
+                       goto error;
+
+               /* attach demod */
+               adap->fe[1] = dvb_attach(zl10353_attach,
                                &anysee_zl10353_tda18212_config,
-                               &adap->dev->i2c_adap);
-               }
+                               &d->i2c_adap);
 
                /* I2C gate for DNOD44CDH086A(TDA18212) tuner module */
-               if (adap->fe_adap[state->fe_id].fe)
-                       adap->fe_adap[state->fe_id].fe->ops.i2c_gate_ctrl =
-                               anysee_i2c_gate_ctrl;
+               if (adap->fe[1])
+                       adap->fe[1]->ops.i2c_gate_ctrl = anysee_i2c_gate_ctrl;
 
                state->has_ci = true;
 
@@ -885,17 +853,14 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
                /* E7 S2 */
                /* E7 PS2 */
 
-               if (state->fe_id)
-                       break;
-
                /* enable DVB-S/S2 demod on IOE[5] */
-               ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 5), 0x20);
+               ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 5), 0x20);
                if (ret)
                        goto error;
 
                /* attach demod */
-               adap->fe_adap[0].fe = dvb_attach(stv0900_attach,
-                       &anysee_stv0900_config, &adap->dev->i2c_adap, 0);
+               adap->fe[0] = dvb_attach(stv0900_attach,
+                               &anysee_stv0900_config, &d->i2c_adap, 0);
 
                state->has_ci = true;
 
@@ -903,24 +868,21 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
        case ANYSEE_HW_508T2C: /* 20 */
                /* E7 T2C */
 
-               if (state->fe_id)
-                       break;
-
                /* enable DVB-T/T2/C demod on IOE[5] */
-               ret = anysee_wr_reg_mask(adap->dev, REG_IOE, (1 << 5), 0x20);
+               ret = anysee_wr_reg_mask(d, REG_IOE, (1 << 5), 0x20);
                if (ret)
                        goto error;
 
                /* attach demod */
-               adap->fe_adap[state->fe_id].fe = dvb_attach(cxd2820r_attach,
-                               &anysee_cxd2820r_config, &adap->dev->i2c_adap);
+               adap->fe[0] = dvb_attach(cxd2820r_attach,
+                               &anysee_cxd2820r_config, &d->i2c_adap);
 
                state->has_ci = true;
 
                break;
        }
 
-       if (!adap->fe_adap[0].fe) {
+       if (!adap->fe[0]) {
                /* we have no frontend :-( */
                ret = -ENODEV;
                err("Unsupported Anysee version. " \
@@ -932,44 +894,43 @@ error:
 
 static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
 {
-       struct anysee_state *state = adap->dev->priv;
+       struct anysee_state *state = adap_to_priv(adap);
+       struct dvb_usb_device *d = adap_to_d(adap);
        struct dvb_frontend *fe;
        int ret;
-       deb_info("%s: fe=%d\n", __func__, state->fe_id);
+       deb_info("%s: adap=%d\n", __func__, adap->id);
 
        switch (state->hw) {
        case ANYSEE_HW_507T: /* 2 */
                /* E30 */
 
                /* attach tuner */
-               fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe,
-                       (0xc2 >> 1), NULL, DVB_PLL_THOMSON_DTT7579);
+               fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc2 >> 1), NULL,
+                               DVB_PLL_THOMSON_DTT7579);
 
                break;
        case ANYSEE_HW_507CD: /* 6 */
                /* E30 Plus */
 
                /* attach tuner */
-               fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe,
-                       (0xc2 >> 1), &adap->dev->i2c_adap,
-                       DVB_PLL_THOMSON_DTT7579);
+               fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc2 >> 1),
+                               &d->i2c_adap, DVB_PLL_THOMSON_DTT7579);
 
                break;
        case ANYSEE_HW_507DC: /* 10 */
                /* E30 C Plus */
 
                /* attach tuner */
-               fe = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe,
-                       (0xc0 >> 1), &adap->dev->i2c_adap,
-                       DVB_PLL_SAMSUNG_DTOS403IH102A);
+               fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc0 >> 1),
+                               &d->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A);
 
                break;
        case ANYSEE_HW_507SI: /* 11 */
                /* E30 S2 Plus */
 
                /* attach LNB controller */
-               fe = dvb_attach(isl6423_attach, adap->fe_adap[0].fe,
-                       &adap->dev->i2c_adap, &anysee_isl6423_config);
+               fe = dvb_attach(isl6423_attach, adap->fe[0], &d->i2c_adap,
+                               &anysee_isl6423_config);
 
                break;
        case ANYSEE_HW_507FA: /* 15 */
@@ -980,15 +941,28 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
                 * fails attach old simple PLL. */
 
                /* attach tuner */
-               fe = dvb_attach(tda18212_attach, adap->fe_adap[state->fe_id].fe,
-                       &adap->dev->i2c_adap, &anysee_tda18212_config);
-               if (fe)
+               fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap,
+                               &anysee_tda18212_config);
+
+               if (fe && adap->fe[1]) {
+                       /* attach tuner for 2nd FE */
+                       fe = dvb_attach(tda18212_attach, adap->fe[1],
+                                       &d->i2c_adap, &anysee_tda18212_config);
+                       break;
+               } else if (fe) {
                        break;
+               }
 
                /* attach tuner */
-               fe = dvb_attach(dvb_pll_attach, adap->fe_adap[state->fe_id].fe,
-                       (0xc0 >> 1), &adap->dev->i2c_adap,
-                       DVB_PLL_SAMSUNG_DTOS403IH102A);
+               fe = dvb_attach(dvb_pll_attach, adap->fe[0], (0xc0 >> 1),
+                               &d->i2c_adap, DVB_PLL_SAMSUNG_DTOS403IH102A);
+
+               if (fe && adap->fe[1]) {
+                       /* attach tuner for 2nd FE */
+                       fe = dvb_attach(dvb_pll_attach, adap->fe[0],
+                                       (0xc0 >> 1), &d->i2c_adap,
+                                       DVB_PLL_SAMSUNG_DTOS403IH102A);
+               }
 
                break;
        case ANYSEE_HW_508TC: /* 18 */
@@ -997,8 +971,14 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
                /* E7 PTC */
 
                /* attach tuner */
-               fe = dvb_attach(tda18212_attach, adap->fe_adap[state->fe_id].fe,
-                       &adap->dev->i2c_adap, &anysee_tda18212_config);
+               fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap,
+                               &anysee_tda18212_config);
+
+               if (fe) {
+                       /* attach tuner for 2nd FE */
+                       fe = dvb_attach(tda18212_attach, adap->fe[1],
+                                       &d->i2c_adap, &anysee_tda18212_config);
+               }
 
                break;
        case ANYSEE_HW_508S2: /* 19 */
@@ -1007,13 +987,13 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
                /* E7 PS2 */
 
                /* attach tuner */
-               fe = dvb_attach(stv6110_attach, adap->fe_adap[0].fe,
-                       &anysee_stv6110_config, &adap->dev->i2c_adap);
+               fe = dvb_attach(stv6110_attach, adap->fe[0],
+                               &anysee_stv6110_config, &d->i2c_adap);
 
                if (fe) {
                        /* attach LNB controller */
-                       fe = dvb_attach(isl6423_attach, adap->fe_adap[0].fe,
-                               &adap->dev->i2c_adap, &anysee_isl6423_config);
+                       fe = dvb_attach(isl6423_attach, adap->fe[0],
+                                       &d->i2c_adap, &anysee_isl6423_config);
                }
 
                break;
@@ -1022,8 +1002,8 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
                /* E7 T2C */
 
                /* attach tuner */
-               fe = dvb_attach(tda18212_attach, adap->fe_adap[state->fe_id].fe,
-                       &adap->dev->i2c_adap, &anysee_tda18212_config2);
+               fe = dvb_attach(tda18212_attach, adap->fe[0], &d->i2c_adap,
+                               &anysee_tda18212_config2);
 
                break;
        default:
@@ -1064,6 +1044,15 @@ static int anysee_rc_query(struct dvb_usb_device *d)
        return 0;
 }
 
+static int anysee_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
+{
+       rc->allowed_protos = RC_TYPE_NEC;
+       rc->query          = anysee_rc_query;
+       rc->interval       = 250;  /* windows driver uses 500ms */
+
+       return 0;
+}
+
 static int anysee_ci_read_attribute_mem(struct dvb_ca_en50221 *ci, int slot,
        int addr)
 {
@@ -1126,7 +1115,7 @@ static int anysee_ci_slot_reset(struct dvb_ca_en50221 *ci, int slot)
 {
        struct dvb_usb_device *d = ci->data;
        int ret;
-       struct anysee_state *state = d->priv;
+       struct anysee_state *state = d_to_priv(d);
 
        state->ci_cam_ready = jiffies + msecs_to_jiffies(1000);
 
@@ -1177,7 +1166,7 @@ static int anysee_ci_poll_slot_status(struct dvb_ca_en50221 *ci, int slot,
        int open)
 {
        struct dvb_usb_device *d = ci->data;
-       struct anysee_state *state = d->priv;
+       struct anysee_state *state = d_to_priv(d);
        int ret;
        u8 tmp;
 
@@ -1196,7 +1185,7 @@ static int anysee_ci_poll_slot_status(struct dvb_ca_en50221 *ci, int slot,
 
 static int anysee_ci_init(struct dvb_usb_device *d)
 {
-       struct anysee_state *state = d->priv;
+       struct anysee_state *state = d_to_priv(d);
        int ret;
 
        state->ci.owner               = THIS_MODULE;
@@ -1231,7 +1220,7 @@ static int anysee_ci_init(struct dvb_usb_device *d)
 
 static void anysee_ci_release(struct dvb_usb_device *d)
 {
-       struct anysee_state *state = d->priv;
+       struct anysee_state *state = d_to_priv(d);
 
        /* detach CI */
        if (state->has_ci)
@@ -1242,9 +1231,17 @@ static void anysee_ci_release(struct dvb_usb_device *d)
 
 static int anysee_init(struct dvb_usb_device *d)
 {
-       struct anysee_state *state = d->priv;
+       struct anysee_state *state = d_to_priv(d);
        int ret;
 
+       /* There is one interface with two alternate settings.
+          Alternate setting 0 is for bulk transfer.
+          Alternate setting 1 is for isochronous transfer.
+          We use bulk transfer (alternate setting 0). */
+       ret = usb_set_interface(d->udev, 0, 0);
+       if (ret)
+               return ret;
+
        /* LED light */
        ret = anysee_led_ctrl(d, 0x01, 0x03);
        if (ret)
@@ -1267,139 +1264,60 @@ static int anysee_init(struct dvb_usb_device *d)
        return 0;
 }
 
-/* DVB USB Driver stuff */
-static struct dvb_usb_device_properties anysee_properties;
-
-static int anysee_probe(struct usb_interface *intf,
-                       const struct usb_device_id *id)
+static void anysee_exit(struct dvb_usb_device *d)
 {
-       struct dvb_usb_device *d;
-       struct usb_host_interface *alt;
-       int ret;
-
-       /* There is one interface with two alternate settings.
-          Alternate setting 0 is for bulk transfer.
-          Alternate setting 1 is for isochronous transfer.
-          We use bulk transfer (alternate setting 0). */
-       if (intf->num_altsetting < 1)
-               return -ENODEV;
-
-       /*
-        * Anysee is always warm (its USB-bridge, Cypress FX2, uploads
-        * firmware from eeprom).  If dvb_usb_device_init() succeeds that
-        * means d is a valid pointer.
-        */
-       ret = dvb_usb_device_init(intf, &anysee_properties, THIS_MODULE, &d,
-               adapter_nr);
-       if (ret)
-               return ret;
-
-       alt = usb_altnum_to_altsetting(intf, 0);
-       if (alt == NULL) {
-               deb_info("%s: no alt found!\n", __func__);
-               return -ENODEV;
-       }
-
-       ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
-               alt->desc.bAlternateSetting);
-       if (ret)
-               return ret;
-
-       return anysee_init(d);
-}
-
-static void anysee_disconnect(struct usb_interface *intf)
-{
-       struct dvb_usb_device *d = usb_get_intfdata(intf);
-
-       anysee_ci_release(d);
-       dvb_usb_device_exit(intf);
-
-       return;
+       return anysee_ci_release(d);
 }
 
-static struct usb_device_id anysee_table[] = {
-       { USB_DEVICE(USB_VID_CYPRESS, USB_PID_ANYSEE) },
-       { USB_DEVICE(USB_VID_AMT,     USB_PID_ANYSEE) },
-       { }             /* Terminating entry */
-};
-MODULE_DEVICE_TABLE(usb, anysee_table);
-
-static struct dvb_usb_device_properties anysee_properties = {
-       .caps             = DVB_USB_IS_AN_I2C_ADAPTER,
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties anysee_props = {
+       .driver_name = KBUILD_MODNAME,
+       .owner = THIS_MODULE,
+       .adapter_nr = adapter_nr,
+       .size_of_priv = sizeof(struct anysee_state),
 
-       .usb_ctrl         = DEVICE_SPECIFIC,
+       .generic_bulk_ctrl_endpoint = 0x01,
+       .generic_bulk_ctrl_endpoint_response = 0x81,
 
-       .size_of_priv     = sizeof(struct anysee_state),
+       .i2c_algo         = &anysee_i2c_algo,
+       .read_config      = anysee_read_config,
+       .frontend_attach  = anysee_frontend_attach,
+       .tuner_attach     = anysee_tuner_attach,
+       .init             = anysee_init,
+       .get_rc_config    = anysee_get_rc_config,
+       .frontend_ctrl    = anysee_frontend_ctrl,
+       .streaming_ctrl   = anysee_streaming_ctrl,
+       .exit             = anysee_exit,
 
        .num_adapters = 1,
        .adapter = {
                {
-               .num_frontends    = 2,
-               .frontend_ctrl    = anysee_frontend_ctrl,
-               .fe = { {
-                       .streaming_ctrl   = anysee_streaming_ctrl,
-                       .frontend_attach  = anysee_frontend_attach,
-                       .tuner_attach     = anysee_tuner_attach,
-                       .stream = {
-                               .type = USB_BULK,
-                               .count = 8,
-                               .endpoint = 0x82,
-                               .u = {
-                                       .bulk = {
-                                               .buffersize = (16*512),
-                                       }
-                               }
-                       },
-               }, {
-                       .streaming_ctrl   = anysee_streaming_ctrl,
-                       .frontend_attach  = anysee_frontend_attach,
-                       .tuner_attach     = anysee_tuner_attach,
-                       .stream = {
-                               .type = USB_BULK,
-                               .count = 8,
-                               .endpoint = 0x82,
-                               .u = {
-                                       .bulk = {
-                                               .buffersize = (16*512),
-                                       }
-                               }
-                       },
-               } },
+                       .stream = DVB_USB_STREAM_BULK(0x82, 8, 16 * 512),
                }
-       },
-
-       .rc.core = {
-               .rc_codes         = RC_MAP_ANYSEE,
-               .protocol         = RC_TYPE_OTHER,
-               .module_name      = "anysee",
-               .rc_query         = anysee_rc_query,
-               .rc_interval      = 250,  /* windows driver uses 500ms */
-       },
-
-       .i2c_algo         = &anysee_i2c_algo,
-
-       .generic_bulk_ctrl_endpoint = 1,
-
-       .num_device_descs = 1,
-       .devices = {
-               {
-                       .name = "Anysee DVB USB2.0",
-                       .cold_ids = {NULL},
-                       .warm_ids = {&anysee_table[0],
-                                    &anysee_table[1], NULL},
-               },
        }
 };
 
-static struct usb_driver anysee_driver = {
-       .name       = "dvb_usb_anysee",
-       .probe      = anysee_probe,
-       .disconnect = anysee_disconnect,
-       .id_table   = anysee_table,
+static const struct usb_device_id anysee_id_table[] = {
+       { DVB_USB_DEVICE(USB_VID_CYPRESS, USB_PID_ANYSEE,
+               &anysee_props, "Anysee", RC_MAP_ANYSEE) },
+       { DVB_USB_DEVICE(USB_VID_AMT, USB_PID_ANYSEE,
+               &anysee_props, "Anysee", RC_MAP_ANYSEE) },
+       { }
+};
+MODULE_DEVICE_TABLE(usb, anysee_id_table);
+
+static struct usb_driver anysee_usb_driver = {
+       .name = KBUILD_MODNAME,
+       .id_table = anysee_id_table,
+       .probe = dvb_usbv2_probe,
+       .disconnect = dvb_usbv2_disconnect,
+       .suspend = dvb_usbv2_suspend,
+       .resume = dvb_usbv2_resume,
+       .no_dynamic_id = 1,
+       .soft_unbind = 1,
 };
 
-module_usb_driver(anysee_driver);
+module_usb_driver(anysee_usb_driver);
 
 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
 MODULE_DESCRIPTION("Driver Anysee E30 DVB-C & DVB-T USB2.0");
similarity index 95%
rename from drivers/media/dvb/dvb-usb/anysee.h
rename to drivers/media/dvb/dvb-usb-v2/anysee.h
index 8ac8794315401d06a087dcf4614444ce98c8d12b..dc40dcf7c32872e87ee037662241e35545419a6f 100644 (file)
 #define _DVB_USB_ANYSEE_H_
 
 #define DVB_USB_LOG_PREFIX "anysee"
-#include "dvb-usb.h"
+#include "dvb_usb.h"
 #include "dvb_ca_en50221.h"
 
+#ifdef CONFIG_DVB_USB_DEBUG
+#define dprintk(var, level, args...) \
+       do { if ((var & level)) printk(args); } while (0)
+#define DVB_USB_DEBUG_STATUS
+#else
+#define dprintk(args...)
+#define debug_dump(b, l, func)
+#define DVB_USB_DEBUG_STATUS " (debugging is not enabled)"
+#endif
+
+#define debug_dump(b, l, func) {\
+       int loop_; \
+       for (loop_ = 0; loop_ < l; loop_++) \
+               func("%02x ", b[loop_]); \
+       func("\n");\
+}
+
 #define deb_info(args...) dprintk(dvb_usb_anysee_debug, 0x01, args)
 #define deb_xfer(args...) dprintk(dvb_usb_anysee_debug, 0x02, args)
 #define deb_rc(args...)   dprintk(dvb_usb_anysee_debug, 0x04, args)
 #define deb_i2c(args...)  dprintk(dvb_usb_anysee_debug, 0x10, args)
 #define deb_fw(args...)   dprintk(dvb_usb_anysee_debug, 0x20, args)
 
+#undef err
+#define err(format, arg...)  printk(KERN_ERR     DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
+#undef info
+#define info(format, arg...) printk(KERN_INFO    DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
+#undef warn
+#define warn(format, arg...) printk(KERN_WARNING DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
+
 enum cmd {
        CMD_I2C_READ            = 0x33,
        CMD_I2C_WRITE           = 0x31,
similarity index 64%
rename from drivers/media/dvb/dvb-usb/au6610.c
rename to drivers/media/dvb/dvb-usb-v2/au6610.c
index 16210c060302a6114c912bf67d8c7034f2487194..05f2a8628142238fc3b5582f8bffecf7897f4bb5 100644 (file)
 #include "zl10353.h"
 #include "qt1010.h"
 
-/* debug */
-static int dvb_usb_au6610_debug;
-module_param_named(debug, dvb_usb_au6610_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr,
@@ -52,7 +48,7 @@ static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr,
                index += wbuf[1];
                break;
        default:
-               warn("wlen = %x, aborting.", wlen);
+               pr_err("%s: wlen = %d, aborting\n", KBUILD_MODNAME, wlen);
                ret = -EINVAL;
                goto error;
        }
@@ -140,9 +136,9 @@ static struct zl10353_config au6610_zl10353_config = {
 
 static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
 {
-       adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &au6610_zl10353_config,
-               &adap->dev->i2c_adap);
-       if (adap->fe_adap[0].fe == NULL)
+       adap->fe[0] = dvb_attach(zl10353_attach, &au6610_zl10353_config,
+                       &adap_to_d(adap)->i2c_adap);
+       if (adap->fe[0] == NULL)
                return -ENODEV;
 
        return 0;
@@ -154,94 +150,52 @@ static struct qt1010_config au6610_qt1010_config = {
 
 static int au6610_qt1010_tuner_attach(struct dvb_usb_adapter *adap)
 {
-       return dvb_attach(qt1010_attach,
-                         adap->fe_adap[0].fe, &adap->dev->i2c_adap,
-                         &au6610_qt1010_config) == NULL ? -ENODEV : 0;
+       return dvb_attach(qt1010_attach, adap->fe[0],
+                       &adap_to_d(adap)->i2c_adap,
+                       &au6610_qt1010_config) == NULL ? -ENODEV : 0;
 }
 
-/* DVB USB Driver stuff */
-static struct dvb_usb_device_properties au6610_properties;
-
-static int au6610_probe(struct usb_interface *intf,
-                       const struct usb_device_id *id)
+static int au6610_init(struct dvb_usb_device *d)
 {
-       struct dvb_usb_device *d;
-       struct usb_host_interface *alt;
-       int ret;
-
-       if (intf->num_altsetting < AU6610_ALTSETTING_COUNT)
-               return -ENODEV;
-
-       ret = dvb_usb_device_init(intf, &au6610_properties, THIS_MODULE, &d,
-                                 adapter_nr);
-       if (ret == 0) {
-               alt = usb_altnum_to_altsetting(intf, AU6610_ALTSETTING);
-
-               if (alt == NULL) {
-                       deb_info("%s: no alt found!\n", __func__);
-                       return -ENODEV;
-               }
-               ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
-                                       alt->desc.bAlternateSetting);
-       }
-
-       return ret;
+       /* TODO: this functionality belongs likely to the streaming control */
+       /* bInterfaceNumber 0, bAlternateSetting 5 */
+       return usb_set_interface(d->udev, 0, 5);
 }
 
-static struct usb_device_id au6610_table [] = {
-       { USB_DEVICE(USB_VID_ALCOR_MICRO, USB_PID_SIGMATEK_DVB_110) },
-       { }             /* Terminating entry */
-};
-MODULE_DEVICE_TABLE(usb, au6610_table);
-
-static struct dvb_usb_device_properties au6610_properties = {
-       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+static struct dvb_usb_device_properties au6610_props = {
+       .driver_name = KBUILD_MODNAME,
+       .owner = THIS_MODULE,
+       .adapter_nr = adapter_nr,
 
-       .usb_ctrl = DEVICE_SPECIFIC,
-
-       .size_of_priv = 0,
+       .i2c_algo = &au6610_i2c_algo,
+       .frontend_attach = au6610_zl10353_frontend_attach,
+       .tuner_attach = au6610_qt1010_tuner_attach,
+       .init = au6610_init,
 
        .num_adapters = 1,
        .adapter = {
                {
-               .num_frontends = 1,
-               .fe = {{
-                       .frontend_attach  = au6610_zl10353_frontend_attach,
-                       .tuner_attach     = au6610_qt1010_tuner_attach,
-
-                       .stream = {
-                               .type = USB_ISOC,
-                               .count = 5,
-                               .endpoint = 0x82,
-                               .u = {
-                                       .isoc = {
-                                               .framesperurb = 40,
-                                               .framesize = 942,
-                                               .interval = 1,
-                                       }
-                               }
-                       },
-               }},
-               }
+                       .stream = DVB_USB_STREAM_ISOC(0x82, 5, 40, 942, 1),
+               },
        },
+};
 
-       .i2c_algo = &au6610_i2c_algo,
-
-       .num_device_descs = 1,
-       .devices = {
-               {
-                       .name = "Sigmatek DVB-110 DVB-T USB2.0",
-                       .cold_ids = {NULL},
-                       .warm_ids = {&au6610_table[0], NULL},
-               },
-       }
+static const struct usb_device_id au6610_id_table[] = {
+       { DVB_USB_DEVICE(USB_VID_ALCOR_MICRO, USB_PID_SIGMATEK_DVB_110,
+               &au6610_props, "Sigmatek DVB-110", NULL) },
+       { }
 };
+MODULE_DEVICE_TABLE(usb, au6610_id_table);
 
 static struct usb_driver au6610_driver = {
-       .name       = "dvb_usb_au6610",
-       .probe      = au6610_probe,
-       .disconnect = dvb_usb_device_exit,
-       .id_table   = au6610_table,
+       .name = KBUILD_MODNAME,
+       .id_table = au6610_id_table,
+       .probe = dvb_usbv2_probe,
+       .disconnect = dvb_usbv2_disconnect,
+       .suspend = dvb_usbv2_suspend,
+       .resume = dvb_usbv2_resume,
+       .no_dynamic_id = 1,
+       .soft_unbind = 1,
 };
 
 module_usb_driver(au6610_driver);
similarity index 80%
rename from drivers/media/dvb/dvb-usb/au6610.h
rename to drivers/media/dvb/dvb-usb-v2/au6610.h
index 7849abe2c61433c685c58dd231f27c79575b7c9b..ea337bfc00b111aae5de96e85f370fddefa73cf2 100644 (file)
  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#ifndef _DVB_USB_AU6610_H_
-#define _DVB_USB_AU6610_H_
-
-#define DVB_USB_LOG_PREFIX "au6610"
-#include "dvb-usb.h"
-
-#define deb_info(args...)   dprintk(dvb_usb_au6610_debug, 0x01, args)
+#ifndef AU6610_H
+#define AU6610_H
+#include "dvb_usb.h"
 
 #define AU6610_REQ_I2C_WRITE   0x14
 #define AU6610_REQ_I2C_READ    0x13
@@ -33,7 +29,4 @@
 
 #define AU6610_USB_TIMEOUT 1000
 
-#define AU6610_ALTSETTING_COUNT 6
-#define AU6610_ALTSETTING       5
-
 #endif
similarity index 63%
rename from drivers/media/dvb/dvb-usb/az6007.c
rename to drivers/media/dvb/dvb-usb-v2/az6007.c
index 86861e6f86d23053ebe990aa58b24e7d377d7d45..54f1221d930df3c5eb0d554c4d56da63cc06583d 100644 (file)
@@ -7,9 +7,9 @@
  *     http://linux.terratec.de/files/TERRATEC_H7/20110323_TERRATEC_H7_Linux.tar.gz
  * The original driver's license is GPL, as declared with MODULE_LICENSE()
  *
- * Copyright (c) 2010-2011 Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010-2012 Mauro Carvalho Chehab <mchehab@redhat.com>
  *     Driver modified by in order to work with upstream drxk driver, and
- *     tons of bugs got fixed.
+ *     tons of bugs got fixed, and converted to use dvb-usb-v2.
  *
  * 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
 #include "drxk.h"
 #include "mt2063.h"
 #include "dvb_ca_en50221.h"
+#include "dvb_usb.h"
+#include "cypress_firmware.h"
 
-#define DVB_USB_LOG_PREFIX "az6007"
-#include "dvb-usb.h"
+#define AZ6007_FIRMWARE "dvb-usb-terratec-h7-az6007.fw"
 
-/* debug */
-int dvb_usb_az6007_debug;
-module_param_named(debug, dvb_usb_az6007_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))."
-                DVB_USB_DEBUG_STATUS);
-
-#define deb_info(args...) dprintk(dvb_usb_az6007_debug, 0x01, args)
-#define deb_xfer(args...) dprintk(dvb_usb_az6007_debug, 0x02, args)
-#define deb_rc(args...)   dprintk(dvb_usb_az6007_debug, 0x04, args)
-#define deb_fe(args...)   dprintk(dvb_usb_az6007_debug, 0x08, args)
+static int az6007_xfer_debug;
+module_param_named(xfer_debug, az6007_xfer_debug, int, 0644);
+MODULE_PARM_DESC(xfer_debug, "Enable xfer debug");
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
@@ -70,23 +64,19 @@ static struct drxk_config terratec_h7_drxk = {
        .no_i2c_bridge = false,
        .chunk_size = 64,
        .mpeg_out_clk_strength = 0x02,
+       .qam_demod_parameter_count = 2,
        .microcode_name = "dvb-usb-terratec-h7-drxk.fw",
 };
 
 static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
 {
+       struct az6007_device_state *st = fe_to_priv(fe);
        struct dvb_usb_adapter *adap = fe->sec_priv;
-       struct az6007_device_state *st;
        int status = 0;
 
-       deb_info("%s: %s\n", __func__, enable ? "enable" : "disable");
-
-       if (!adap)
-               return -EINVAL;
-
-       st = adap->dev->priv;
+       pr_debug("%s: %s\n", __func__, enable ? "enable" : "disable");
 
-       if (!st)
+       if (!adap || !st)
                return -EINVAL;
 
        if (enable)
@@ -113,13 +103,16 @@ static int __az6007_read(struct usb_device *udev, u8 req, u16 value,
                              USB_TYPE_VENDOR | USB_DIR_IN,
                              value, index, b, blen, 5000);
        if (ret < 0) {
-               warn("usb read operation failed. (%d)", ret);
+               pr_warn("usb read operation failed. (%d)\n", ret);
                return -EIO;
        }
 
-       deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ", req, value,
-                index);
-       debug_dump(b, blen, deb_xfer);
+       if (az6007_xfer_debug) {
+               printk(KERN_DEBUG "az6007: IN  req: %02x, value: %04x, index: %04x\n",
+                      req, value, index);
+               print_hex_dump_bytes("az6007: payload: ",
+                                    DUMP_PREFIX_NONE, b, blen);
+       }
 
        return ret;
 }
@@ -145,13 +138,16 @@ static int __az6007_write(struct usb_device *udev, u8 req, u16 value,
 {
        int ret;
 
-       deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ", req, value,
-                index);
-       debug_dump(b, blen, deb_xfer);
+       if (az6007_xfer_debug) {
+               printk(KERN_DEBUG "az6007: OUT req: %02x, value: %04x, index: %04x\n",
+                      req, value, index);
+               print_hex_dump_bytes("az6007: payload: ",
+                                    DUMP_PREFIX_NONE, b, blen);
+       }
 
        if (blen > 64) {
-               err("az6007: tried to write %d bytes, but I2C max size is 64 bytes\n",
-                   blen);
+               pr_err("az6007: tried to write %d bytes, but I2C max size is 64 bytes\n",
+                      blen);
                return -EOPNOTSUPP;
        }
 
@@ -161,7 +157,7 @@ static int __az6007_write(struct usb_device *udev, u8 req, u16 value,
                              USB_TYPE_VENDOR | USB_DIR_OUT,
                              value, index, b, blen, 5000);
        if (ret != blen) {
-               err("usb write operation failed. (%d)", ret);
+               pr_err("usb write operation failed. (%d)\n", ret);
                return -EIO;
        }
 
@@ -184,11 +180,11 @@ static int az6007_write(struct dvb_usb_device *d, u8 req, u16 value,
        return ret;
 }
 
-static int az6007_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+static int az6007_streaming_ctrl(struct dvb_frontend *fe, int onoff)
 {
-       struct dvb_usb_device *d = adap->dev;
+       struct dvb_usb_device *d = fe_to_d(fe);
 
-       deb_info("%s: %s", __func__, onoff ? "enable" : "disable");
+       pr_debug("%s: %s\n", __func__, onoff ? "enable" : "disable");
 
        return az6007_write(d, 0xbc, onoff, 0, NULL, 0);
 }
@@ -196,7 +192,7 @@ static int az6007_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 /* remote control stuff (does not work with my box) */
 static int az6007_rc_query(struct dvb_usb_device *d)
 {
-       struct az6007_device_state *st = d->priv;
+       struct az6007_device_state *st = d_to_priv(d);
        unsigned code = 0;
 
        az6007_read(d, AZ6007_READ_IR, 0, 0, st->data, 10);
@@ -224,7 +220,7 @@ static int az6007_ci_read_attribute_mem(struct dvb_ca_en50221 *ca,
                                        int address)
 {
        struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
-       struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
+       struct az6007_device_state *state = d_to_priv(d);
 
        int ret;
        u8 req;
@@ -249,7 +245,7 @@ static int az6007_ci_read_attribute_mem(struct dvb_ca_en50221 *ca,
 
        ret = az6007_read(d, req, value, index, b, blen);
        if (ret < 0) {
-               warn("usb in operation failed. (%d)", ret);
+               pr_warn("usb in operation failed. (%d)\n", ret);
                ret = -EINVAL;
        } else {
                ret = b[0];
@@ -266,7 +262,7 @@ static int az6007_ci_write_attribute_mem(struct dvb_ca_en50221 *ca,
                                         u8 value)
 {
        struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
-       struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
+       struct az6007_device_state *state = d_to_priv(d);
 
        int ret;
        u8 req;
@@ -274,7 +270,7 @@ static int az6007_ci_write_attribute_mem(struct dvb_ca_en50221 *ca,
        u16 index;
        int blen;
 
-       deb_info("%s %d", __func__, slot);
+       pr_debug("%s(), slot %d\n", __func__, slot);
        if (slot != 0)
                return -EINVAL;
 
@@ -286,7 +282,7 @@ static int az6007_ci_write_attribute_mem(struct dvb_ca_en50221 *ca,
 
        ret = az6007_write(d, req, value1, index, NULL, blen);
        if (ret != 0)
-               warn("usb out operation failed. (%d)", ret);
+               pr_warn("usb out operation failed. (%d)\n", ret);
 
        mutex_unlock(&state->ca_mutex);
        return ret;
@@ -297,7 +293,7 @@ static int az6007_ci_read_cam_control(struct dvb_ca_en50221 *ca,
                                      u8 address)
 {
        struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
-       struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
+       struct az6007_device_state *state = d_to_priv(d);
 
        int ret;
        u8 req;
@@ -322,14 +318,14 @@ static int az6007_ci_read_cam_control(struct dvb_ca_en50221 *ca,
 
        ret = az6007_read(d, req, value, index, b, blen);
        if (ret < 0) {
-               warn("usb in operation failed. (%d)", ret);
+               pr_warn("usb in operation failed. (%d)\n", ret);
                ret = -EINVAL;
        } else {
                if (b[0] == 0)
-                       warn("Read CI IO error");
+                       pr_warn("Read CI IO error\n");
 
                ret = b[1];
-               deb_info("read cam data = %x from 0x%x", b[1], value);
+               pr_debug("read cam data = %x from 0x%x\n", b[1], value);
        }
 
        mutex_unlock(&state->ca_mutex);
@@ -343,7 +339,7 @@ static int az6007_ci_write_cam_control(struct dvb_ca_en50221 *ca,
                                       u8 value)
 {
        struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
-       struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
+       struct az6007_device_state *state = d_to_priv(d);
 
        int ret;
        u8 req;
@@ -362,7 +358,7 @@ static int az6007_ci_write_cam_control(struct dvb_ca_en50221 *ca,
 
        ret = az6007_write(d, req, value1, index, NULL, blen);
        if (ret != 0) {
-               warn("usb out operation failed. (%d)", ret);
+               pr_warn("usb out operation failed. (%d)\n", ret);
                goto failed;
        }
 
@@ -393,7 +389,7 @@ static int CI_CamReady(struct dvb_ca_en50221 *ca, int slot)
 
        ret = az6007_read(d, req, value, index, b, blen);
        if (ret < 0) {
-               warn("usb in operation failed. (%d)", ret);
+               pr_warn("usb in operation failed. (%d)\n", ret);
                ret = -EIO;
        } else{
                ret = b[0];
@@ -405,7 +401,7 @@ static int CI_CamReady(struct dvb_ca_en50221 *ca, int slot)
 static int az6007_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot)
 {
        struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
-       struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
+       struct az6007_device_state *state = d_to_priv(d);
 
        int ret, i;
        u8 req;
@@ -422,7 +418,7 @@ static int az6007_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot)
 
        ret = az6007_write(d, req, value, index, NULL, blen);
        if (ret != 0) {
-               warn("usb out operation failed. (%d)", ret);
+               pr_warn("usb out operation failed. (%d)\n", ret);
                goto failed;
        }
 
@@ -434,7 +430,7 @@ static int az6007_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot)
 
        ret = az6007_write(d, req, value, index, NULL, blen);
        if (ret != 0) {
-               warn("usb out operation failed. (%d)", ret);
+               pr_warn("usb out operation failed. (%d)\n", ret);
                goto failed;
        }
 
@@ -442,7 +438,7 @@ static int az6007_ci_slot_reset(struct dvb_ca_en50221 *ca, int slot)
                msleep(100);
 
                if (CI_CamReady(ca, slot)) {
-                       deb_info("CAM Ready");
+                       pr_debug("CAM Ready\n");
                        break;
                }
        }
@@ -461,7 +457,7 @@ static int az6007_ci_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
 static int az6007_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
 {
        struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
-       struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
+       struct az6007_device_state *state = d_to_priv(d);
 
        int ret;
        u8 req;
@@ -469,7 +465,7 @@ static int az6007_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
        u16 index;
        int blen;
 
-       deb_info("%s", __func__);
+       pr_debug("%s()\n", __func__);
        mutex_lock(&state->ca_mutex);
        req = 0xC7;
        value = 1;
@@ -478,7 +474,7 @@ static int az6007_ci_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
 
        ret = az6007_write(d, req, value, index, NULL, blen);
        if (ret != 0) {
-               warn("usb out operation failed. (%d)", ret);
+               pr_warn("usb out operation failed. (%d)\n", ret);
                goto failed;
        }
 
@@ -490,7 +486,7 @@ failed:
 static int az6007_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
 {
        struct dvb_usb_device *d = (struct dvb_usb_device *)ca->data;
-       struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
+       struct az6007_device_state *state = d_to_priv(d);
        int ret;
        u8 req;
        u16 value;
@@ -510,7 +506,7 @@ static int az6007_ci_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int o
 
        ret = az6007_read(d, req, value, index, b, blen);
        if (ret < 0) {
-               warn("usb in operation failed. (%d)", ret);
+               pr_warn("usb in operation failed. (%d)\n", ret);
                ret = -EIO;
        } else
                ret = 0;
@@ -530,12 +526,12 @@ static void az6007_ci_uninit(struct dvb_usb_device *d)
 {
        struct az6007_device_state *state;
 
-       deb_info("%s", __func__);
+       pr_debug("%s()\n", __func__);
 
        if (NULL == d)
                return;
 
-       state = (struct az6007_device_state *)d->priv;
+       state = d_to_priv(d);
        if (NULL == state)
                return;
 
@@ -548,16 +544,15 @@ static void az6007_ci_uninit(struct dvb_usb_device *d)
 }
 
 
-static int az6007_ci_init(struct dvb_usb_adapter *a)
+static int az6007_ci_init(struct dvb_usb_adapter *adap)
 {
-       struct dvb_usb_device *d = a->dev;
-       struct az6007_device_state *state = (struct az6007_device_state *)d->priv;
+       struct dvb_usb_device *d = adap_to_d(adap);
+       struct az6007_device_state *state = adap_to_priv(adap);
        int ret;
 
-       deb_info("%s", __func__);
+       pr_debug("%s()\n", __func__);
 
        mutex_init(&state->ca_mutex);
-
        state->ca.owner                 = THIS_MODULE;
        state->ca.read_attribute_mem    = az6007_ci_read_attribute_mem;
        state->ca.write_attribute_mem   = az6007_ci_write_attribute_mem;
@@ -569,49 +564,51 @@ static int az6007_ci_init(struct dvb_usb_adapter *a)
        state->ca.poll_slot_status      = az6007_ci_poll_slot_status;
        state->ca.data                  = d;
 
-       ret = dvb_ca_en50221_init(&a->dvb_adap,
+       ret = dvb_ca_en50221_init(&adap->dvb_adap,
                                  &state->ca,
                                  0, /* flags */
                                  1);/* n_slots */
        if (ret != 0) {
-               err("Cannot initialize CI: Error %d.", ret);
+               pr_err("Cannot initialize CI: Error %d.\n", ret);
                memset(&state->ca, 0, sizeof(state->ca));
                return ret;
        }
 
-       deb_info("CI initialized.");
+       pr_debug("CI initialized.\n");
 
        return 0;
 }
 
-static int az6007_read_mac_addr(struct dvb_usb_device *d, u8 mac[6])
+static int az6007_read_mac_addr(struct dvb_usb_adapter *adap, u8 mac[6])
 {
-       struct az6007_device_state *st = d->priv;
+       struct dvb_usb_device *d = adap_to_d(adap);
+       struct az6007_device_state *st = adap_to_priv(adap);
        int ret;
 
        ret = az6007_read(d, AZ6007_READ_DATA, 6, 0, st->data, 6);
        memcpy(mac, st->data, 6);
 
        if (ret > 0)
-               deb_info("%s: mac is %pM\n", __func__, mac);
+               pr_debug("%s: mac is %pM\n", __func__, mac);
 
        return ret;
 }
 
 static int az6007_frontend_attach(struct dvb_usb_adapter *adap)
 {
-       struct az6007_device_state *st = adap->dev->priv;
+       struct az6007_device_state *st = adap_to_priv(adap);
+       struct dvb_usb_device *d = adap_to_d(adap);
 
-       deb_info("attaching demod drxk");
+       pr_debug("attaching demod drxk\n");
 
-       adap->fe_adap[0].fe = dvb_attach(drxk_attach, &terratec_h7_drxk,
-                                        &adap->dev->i2c_adap);
-       if (!adap->fe_adap[0].fe)
+       adap->fe[0] = dvb_attach(drxk_attach, &terratec_h7_drxk,
+                                &d->i2c_adap);
+       if (!adap->fe[0])
                return -EINVAL;
 
-       adap->fe_adap[0].fe->sec_priv = adap;
-       st->gate_ctrl = adap->fe_adap[0].fe->ops.i2c_gate_ctrl;
-       adap->fe_adap[0].fe->ops.i2c_gate_ctrl = drxk_gate_ctrl;
+       adap->fe[0]->sec_priv = adap;
+       st->gate_ctrl = adap->fe[0]->ops.i2c_gate_ctrl;
+       adap->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl;
 
        az6007_ci_init(adap);
 
@@ -620,31 +617,33 @@ static int az6007_frontend_attach(struct dvb_usb_adapter *adap)
 
 static int az6007_tuner_attach(struct dvb_usb_adapter *adap)
 {
-       deb_info("attaching tuner mt2063");
+       struct dvb_usb_device *d = adap_to_d(adap);
+
+       pr_debug("attaching tuner mt2063\n");
 
        /* Attach mt2063 to DVB-C frontend */
-       if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl)
-               adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 1);
-       if (!dvb_attach(mt2063_attach, adap->fe_adap[0].fe,
+       if (adap->fe[0]->ops.i2c_gate_ctrl)
+               adap->fe[0]->ops.i2c_gate_ctrl(adap->fe[0], 1);
+       if (!dvb_attach(mt2063_attach, adap->fe[0],
                        &az6007_mt2063_config,
-                       &adap->dev->i2c_adap))
+                       &d->i2c_adap))
                return -EINVAL;
 
-       if (adap->fe_adap[0].fe->ops.i2c_gate_ctrl)
-               adap->fe_adap[0].fe->ops.i2c_gate_ctrl(adap->fe_adap[0].fe, 0);
+       if (adap->fe[0]->ops.i2c_gate_ctrl)
+               adap->fe[0]->ops.i2c_gate_ctrl(adap->fe[0], 0);
 
        return 0;
 }
 
-int az6007_power_ctrl(struct dvb_usb_device *d, int onoff)
+static int az6007_power_ctrl(struct dvb_usb_device *d, int onoff)
 {
-       struct az6007_device_state *st = d->priv;
+       struct az6007_device_state *state = d_to_priv(d);
        int ret;
 
-       deb_info("%s()\n", __func__);
+       pr_debug("%s()\n", __func__);
 
-       if (!st->warm) {
-               mutex_init(&st->mutex);
+       if (!state->warm) {
+               mutex_init(&state->mutex);
 
                ret = az6007_write(d, AZ6007_POWER, 0, 2, NULL, 0);
                if (ret < 0)
@@ -675,7 +674,7 @@ int az6007_power_ctrl(struct dvb_usb_device *d, int onoff)
                if (ret < 0)
                        return ret;
 
-               st->warm = true;
+               state->warm = true;
 
                return 0;
        }
@@ -694,7 +693,7 @@ static int az6007_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
                           int num)
 {
        struct dvb_usb_device *d = i2c_get_adapdata(adap);
-       struct az6007_device_state *st = d->priv;
+       struct az6007_device_state *st = d_to_priv(d);
        int i, j, len;
        int ret = 0;
        u16 index;
@@ -709,7 +708,7 @@ static int az6007_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
                addr = msgs[i].addr << 1;
                if (((i + 1) < num)
                    && (msgs[i].len == 1)
-                   && (!msgs[i].flags & I2C_M_RD)
+                   && ((msgs[i].flags & I2C_M_RD) != I2C_M_RD)
                    && (msgs[i + 1].flags & I2C_M_RD)
                    && (msgs[i].addr == msgs[i + 1].addr)) {
                        /*
@@ -717,9 +716,8 @@ static int az6007_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
                         * the first xfer has just 1 byte length.
                         * Need to join both into one operation
                         */
-                       if (dvb_usb_az6007_debug & 2)
-                               printk(KERN_DEBUG
-                                      "az6007 I2C xfer write+read addr=0x%x len=%d/%d: ",
+                       if (az6007_xfer_debug)
+                               printk(KERN_DEBUG "az6007: I2C W/R addr=0x%x len=%d/%d\n",
                                       addr, msgs[i].len, msgs[i + 1].len);
                        req = AZ6007_I2C_RD;
                        index = msgs[i].buf[0];
@@ -729,42 +727,29 @@ static int az6007_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
                        ret = __az6007_read(d->udev, req, value, index,
                                            st->data, length);
                        if (ret >= len) {
-                               for (j = 0; j < len; j++) {
+                               for (j = 0; j < len; j++)
                                        msgs[i + 1].buf[j] = st->data[j + 5];
-                                       if (dvb_usb_az6007_debug & 2)
-                                               printk(KERN_CONT
-                                                      "0x%02x ",
-                                                      msgs[i + 1].buf[j]);
-                               }
                        } else
                                ret = -EIO;
                        i++;
                } else if (!(msgs[i].flags & I2C_M_RD)) {
                        /* write bytes */
-                       if (dvb_usb_az6007_debug & 2)
-                               printk(KERN_DEBUG
-                                      "az6007 I2C xfer write addr=0x%x len=%d: ",
+                       if (az6007_xfer_debug)
+                               printk(KERN_DEBUG "az6007: I2C W addr=0x%x len=%d\n",
                                       addr, msgs[i].len);
                        req = AZ6007_I2C_WR;
                        index = msgs[i].buf[0];
                        value = addr | (1 << 8);
                        length = msgs[i].len - 1;
                        len = msgs[i].len - 1;
-                       if (dvb_usb_az6007_debug & 2)
-                               printk(KERN_CONT "(0x%02x) ", msgs[i].buf[0]);
-                       for (j = 0; j < len; j++) {
+                       for (j = 0; j < len; j++)
                                st->data[j] = msgs[i].buf[j + 1];
-                               if (dvb_usb_az6007_debug & 2)
-                                       printk(KERN_CONT "0x%02x ",
-                                              st->data[j]);
-                       }
                        ret =  __az6007_write(d->udev, req, value, index,
                                              st->data, length);
                } else {
                        /* read bytes */
-                       if (dvb_usb_az6007_debug & 2)
-                               printk(KERN_DEBUG
-                                      "az6007 I2C xfer read addr=0x%x len=%d: ",
+                       if (az6007_xfer_debug)
+                               printk(KERN_DEBUG "az6007: I2C R addr=0x%x len=%d\n",
                                       addr, msgs[i].len);
                        req = AZ6007_I2C_RD;
                        index = msgs[i].buf[0];
@@ -773,15 +758,9 @@ static int az6007_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
                        len = msgs[i].len;
                        ret = __az6007_read(d->udev, req, value, index,
                                            st->data, length);
-                       for (j = 0; j < len; j++) {
+                       for (j = 0; j < len; j++)
                                msgs[i].buf[j] = st->data[j + 5];
-                               if (dvb_usb_az6007_debug & 2)
-                                       printk(KERN_CONT
-                                              "0x%02x ", st->data[j + 5]);
-                       }
                }
-               if (dvb_usb_az6007_debug & 2)
-                       printk(KERN_CONT "\n");
                if (ret < 0)
                        goto err;
        }
@@ -789,7 +768,7 @@ err:
        mutex_unlock(&st->mutex);
 
        if (ret < 0) {
-               info("%s ERROR: %i", __func__, ret);
+               pr_info("%s ERROR: %i\n", __func__, ret);
                return ret;
        }
        return num;
@@ -805,151 +784,136 @@ static struct i2c_algorithm az6007_i2c_algo = {
        .functionality = az6007_i2c_func,
 };
 
-int az6007_identify_state(struct usb_device *udev,
-                         struct dvb_usb_device_properties *props,
-                         struct dvb_usb_device_description **desc, int *cold)
+static int az6007_identify_state(struct dvb_usb_device *d, const char **name)
 {
        int ret;
        u8 *mac;
 
+       pr_debug("Identifying az6007 state\n");
+
        mac = kmalloc(6, GFP_ATOMIC);
        if (!mac)
                return -ENOMEM;
 
        /* Try to read the mac address */
-       ret = __az6007_read(udev, AZ6007_READ_DATA, 6, 0, mac, 6);
+       ret = __az6007_read(d->udev, AZ6007_READ_DATA, 6, 0, mac, 6);
        if (ret == 6)
-               *cold = 0;
+               ret = WARM;
        else
-               *cold = 1;
+               ret = COLD;
 
        kfree(mac);
 
-       if (*cold) {
-               __az6007_write(udev, 0x09, 1, 0, NULL, 0);
-               __az6007_write(udev, 0x00, 0, 0, NULL, 0);
-               __az6007_write(udev, 0x00, 0, 0, NULL, 0);
+       if (ret == COLD) {
+               __az6007_write(d->udev, 0x09, 1, 0, NULL, 0);
+               __az6007_write(d->udev, 0x00, 0, 0, NULL, 0);
+               __az6007_write(d->udev, 0x00, 0, 0, NULL, 0);
        }
 
-       deb_info("Device is on %s state\n", *cold ? "warm" : "cold");
-       return 0;
+       pr_debug("Device is on %s state\n",
+                ret == WARM ? "warm" : "cold");
+       return ret;
 }
 
-static struct dvb_usb_device_properties az6007_properties;
-
 static void az6007_usb_disconnect(struct usb_interface *intf)
 {
        struct dvb_usb_device *d = usb_get_intfdata(intf);
        az6007_ci_uninit(d);
-       dvb_usb_device_exit(intf);
+       dvb_usbv2_disconnect(intf);
 }
 
-static int az6007_usb_probe(struct usb_interface *intf,
-                           const struct usb_device_id *id)
+static int az6007_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
 {
-       return dvb_usb_device_init(intf, &az6007_properties,
-                                  THIS_MODULE, NULL, adapter_nr);
+       pr_debug("Getting az6007 Remote Control properties\n");
+
+       rc->allowed_protos = RC_TYPE_NEC;
+       rc->query          = az6007_rc_query;
+       rc->interval       = 400;
+
+       return 0;
 }
 
-static struct usb_device_id az6007_usb_table[] = {
-       {USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_6007)},
-       {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7)},
-       {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7_2)},
-       {0},
-};
+static int az6007_download_firmware(struct dvb_usb_device *d,
+       const struct firmware *fw)
+{
+       pr_debug("Loading az6007 firmware\n");
 
-MODULE_DEVICE_TABLE(usb, az6007_usb_table);
+       return usbv2_cypress_load_firmware(d->udev, fw, CYPRESS_FX2);
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties az6007_props = {
+       .driver_name         = KBUILD_MODNAME,
+       .owner               = THIS_MODULE,
+       .firmware            = AZ6007_FIRMWARE,
 
-static struct dvb_usb_device_properties az6007_properties = {
-       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
-       .usb_ctrl = CYPRESS_FX2,
-       .firmware            = "dvb-usb-terratec-h7-az6007.fw",
-       .no_reconnect        = 1,
+       .adapter_nr          = adapter_nr,
        .size_of_priv        = sizeof(struct az6007_device_state),
+       .i2c_algo            = &az6007_i2c_algo,
+       .tuner_attach        = az6007_tuner_attach,
+       .frontend_attach     = az6007_frontend_attach,
+       .streaming_ctrl      = az6007_streaming_ctrl,
+       .get_rc_config       = az6007_get_rc_config,
+       .read_mac_address    = az6007_read_mac_addr,
+       .download_firmware   = az6007_download_firmware,
        .identify_state      = az6007_identify_state,
-       .num_adapters = 1,
-       .adapter = {
-               {
-               .num_frontends = 1,
-               .fe = {{
-                       .streaming_ctrl   = az6007_streaming_ctrl,
-                       .tuner_attach     = az6007_tuner_attach,
-                       .frontend_attach  = az6007_frontend_attach,
-
-                       /* parameter for the MPEG2-data transfer */
-                       .stream = {
-                               .type = USB_BULK,
-                               .count = 10,
-                               .endpoint = 0x02,
-                               .u = {
-                                       .bulk = {
-                                               .buffersize = 4096,
-                                       }
-                               }
-                       },
-               } }
-       } },
-       .power_ctrl       = az6007_power_ctrl,
-       .read_mac_address = az6007_read_mac_addr,
-
-       .rc.core = {
-               .rc_interval      = 400,
-               .rc_codes         = RC_MAP_NEC_TERRATEC_CINERGY_XS,
-               .module_name      = "az6007",
-               .rc_query         = az6007_rc_query,
-               .allowed_protos   = RC_TYPE_NEC,
-       },
-       .i2c_algo         = &az6007_i2c_algo,
-
-       .num_device_descs = 2,
-       .devices = {
-               { .name = "AzureWave DTV StarBox DVB-T/C USB2.0 (az6007)",
-                 .cold_ids = { &az6007_usb_table[0], NULL },
-                 .warm_ids = { NULL },
-               },
-               { .name = "TerraTec DTV StarBox DVB-T/C USB2.0 (az6007)",
-                 .cold_ids = { &az6007_usb_table[1], &az6007_usb_table[2], NULL },
-                 .warm_ids = { NULL },
-               },
-               { NULL },
+       .power_ctrl          = az6007_power_ctrl,
+       .num_adapters        = 1,
+       .adapter             = {
+               { .stream = DVB_USB_STREAM_BULK(0x02, 10, 4096), }
        }
 };
 
-/* usb specific object needed to register this driver with the usb subsystem */
-static struct usb_driver az6007_usb_driver = {
-       .name           = "dvb_usb_az6007",
-       .probe          = az6007_usb_probe,
-       .disconnect     = az6007_usb_disconnect,
-       .id_table       = az6007_usb_table,
+static struct usb_device_id az6007_usb_table[] = {
+       {DVB_USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_6007,
+               &az6007_props, "Azurewave 6007", RC_MAP_EMPTY)},
+       {DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7,
+               &az6007_props, "Terratec H7", RC_MAP_NEC_TERRATEC_CINERGY_XS)},
+       {DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7_2,
+               &az6007_props, "Terratec H7", RC_MAP_NEC_TERRATEC_CINERGY_XS)},
+       {0},
 };
 
-/* module stuff */
-static int __init az6007_usb_module_init(void)
-{
-       int result;
-       deb_info("az6007 usb module init\n");
+MODULE_DEVICE_TABLE(usb, az6007_usb_table);
 
-       result = usb_register(&az6007_usb_driver);
-       if (result) {
-               err("usb_register failed. (%d)", result);
-               return result;
-       }
+static int az6007_suspend(struct usb_interface *intf, pm_message_t msg)
+{
+       struct dvb_usb_device *d = usb_get_intfdata(intf);
 
-       return 0;
+       az6007_ci_uninit(d);
+       return dvb_usbv2_suspend(intf, msg);
 }
 
-static void __exit az6007_usb_module_exit(void)
+static int az6007_resume(struct usb_interface *intf)
 {
-       /* deregister this driver from the USB subsystem */
-       deb_info("az6007 usb module exit\n");
-       usb_deregister(&az6007_usb_driver);
+       struct dvb_usb_device *d = usb_get_intfdata(intf);
+       struct dvb_usb_adapter *adap = &d->adapter[0];
+
+       az6007_ci_init(adap);
+       return dvb_usbv2_resume(intf);
 }
 
-module_init(az6007_usb_module_init);
-module_exit(az6007_usb_module_exit);
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver az6007_usb_driver = {
+       .name           = KBUILD_MODNAME,
+       .id_table       = az6007_usb_table,
+       .probe          = dvb_usbv2_probe,
+       .disconnect     = az6007_usb_disconnect,
+       .no_dynamic_id  = 1,
+       .soft_unbind    = 1,
+       /*
+        * FIXME: need to implement reset_resume, likely with
+        * dvb-usb-v2 core support
+        */
+       .suspend        = az6007_suspend,
+       .resume         = az6007_resume,
+};
+
+module_usb_driver(az6007_usb_driver);
 
 MODULE_AUTHOR("Henry Wang <Henry.wang@AzureWave.com>");
 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
 MODULE_DESCRIPTION("Driver for AzureWave 6007 DVB-C/T USB2.0 and clones");
-MODULE_VERSION("1.1");
+MODULE_VERSION("2.0");
 MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(AZ6007_FIRMWARE);
similarity index 59%
rename from drivers/media/dvb/dvb-usb/ce6230.c
rename to drivers/media/dvb/dvb-usb-v2/ce6230.c
index fa637255729c50a7026565d0bdc5eba2cc3ba903..84ff4a96ca4e89486e48346c6775a45b5a7a16a5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * DVB USB Linux driver for Intel CE6230 DVB-T USB2.0 receiver
+ * Intel CE6230 DVB USB driver
  *
  * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
  *
  */
 
 #include "ce6230.h"
-#include "zl10353.h"
-#include "mxl5005s.h"
 
-/* debug */
-static int dvb_usb_ce6230_debug;
-module_param_named(debug, dvb_usb_ce6230_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
-static struct zl10353_config ce6230_zl10353_config;
-
-static int ce6230_rw_udev(struct usb_device *udev, struct req_t *req)
+static int ce6230_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req)
 {
        int ret;
        unsigned int pipe;
@@ -57,8 +49,8 @@ static int ce6230_rw_udev(struct usb_device *udev, struct req_t *req)
                requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
                break;
        default:
-               err("unknown command:%02x", req->cmd);
-               ret = -EPERM;
+               pr_debug("%s: unknown command=%02x\n", __func__, req->cmd);
+               ret = -EINVAL;
                goto error;
        }
 
@@ -71,22 +63,23 @@ static int ce6230_rw_udev(struct usb_device *udev, struct req_t *req)
        if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) {
                /* write */
                memcpy(buf, req->data, req->data_len);
-               pipe = usb_sndctrlpipe(udev, 0);
+               pipe = usb_sndctrlpipe(d->udev, 0);
        } else {
                /* read */
-               pipe = usb_rcvctrlpipe(udev, 0);
+               pipe = usb_rcvctrlpipe(d->udev, 0);
        }
 
        msleep(1); /* avoid I2C errors */
 
-       ret = usb_control_msg(udev, pipe, request, requesttype, value, index,
-                               buf, req->data_len, CE6230_USB_TIMEOUT);
+       ret = usb_control_msg(d->udev, pipe, request, requesttype, value, index,
+                       buf, req->data_len, CE6230_USB_TIMEOUT);
 
        ce6230_debug_dump(request, requesttype, value, index, buf,
-               req->data_len, deb_xfer);
+                       req->data_len);
 
        if (ret < 0)
-               deb_info("%s: usb_control_msg failed:%d\n", __func__, ret);
+               pr_err("%s: usb_control_msg() failed=%d\n", KBUILD_MODNAME,
+                               ret);
        else
                ret = 0;
 
@@ -99,23 +92,20 @@ error:
        return ret;
 }
 
-static int ce6230_ctrl_msg(struct dvb_usb_device *d, struct req_t *req)
-{
-       return ce6230_rw_udev(d->udev, req);
-}
-
 /* I2C */
-static int ce6230_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
-                          int num)
+static struct zl10353_config ce6230_zl10353_config;
+
+static int ce6230_i2c_master_xfer(struct i2c_adapter *adap,
+               struct i2c_msg msg[], int num)
 {
        struct dvb_usb_device *d = i2c_get_adapdata(adap);
-       int i = 0;
-       struct req_t req;
-       int ret = 0;
-       memset(&req, 0, sizeof(req));
+       int ret = 0, i = 0;
+       struct usb_req req;
 
        if (num > 2)
-               return -EINVAL;
+               return -EOPNOTSUPP;
+
+       memset(&req, 0, sizeof(req));
 
        if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
                return -EAGAIN;
@@ -131,8 +121,9 @@ static int ce6230_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                                req.data = &msg[i+1].buf[0];
                                ret = ce6230_ctrl_msg(d, &req);
                        } else {
-                               err("i2c read not implemented");
-                               ret = -EPERM;
+                               pr_err("%s: I2C read not implemented\n",
+                                               KBUILD_MODNAME);
+                               ret = -EOPNOTSUPP;
                        }
                        i += 2;
                } else {
@@ -162,14 +153,14 @@ static int ce6230_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
        return ret ? ret : i;
 }
 
-static u32 ce6230_i2c_func(struct i2c_adapter *adapter)
+static u32 ce6230_i2c_functionality(struct i2c_adapter *adapter)
 {
        return I2C_FUNC_I2C;
 }
 
-static struct i2c_algorithm ce6230_i2c_algo = {
-       .master_xfer   = ce6230_i2c_xfer,
-       .functionality = ce6230_i2c_func,
+static struct i2c_algorithm ce6230_i2c_algorithm = {
+       .master_xfer   = ce6230_i2c_master_xfer,
+       .functionality = ce6230_i2c_functionality,
 };
 
 /* Callbacks for DVB USB */
@@ -185,11 +176,13 @@ static struct zl10353_config ce6230_zl10353_config = {
 
 static int ce6230_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
 {
-       deb_info("%s:\n", __func__);
-       adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &ce6230_zl10353_config,
-               &adap->dev->i2c_adap);
-       if (adap->fe_adap[0].fe == NULL)
+       pr_debug("%s:\n", __func__);
+
+       adap->fe[0] = dvb_attach(zl10353_attach, &ce6230_zl10353_config,
+                       &adap_to_d(adap)->i2c_adap);
+       if (adap->fe[0] == NULL)
                return -ENODEV;
+
        return 0;
 }
 
@@ -213,8 +206,11 @@ static struct mxl5005s_config ce6230_mxl5003s_config = {
 static int ce6230_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
 {
        int ret;
-       deb_info("%s:\n", __func__);
-       ret = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap,
+
+       pr_debug("%s:\n", __func__);
+
+       ret = dvb_attach(mxl5005s_attach, adap->fe[0],
+                       &adap_to_d(adap)->i2c_adap,
                        &ce6230_mxl5003s_config) == NULL ? -ENODEV : 0;
        return ret;
 }
@@ -222,103 +218,70 @@ static int ce6230_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
 static int ce6230_power_ctrl(struct dvb_usb_device *d, int onoff)
 {
        int ret;
-       deb_info("%s: onoff:%d\n", __func__, onoff);
+
+       pr_debug("%s: onoff=%d\n", __func__, onoff);
 
        /* InterfaceNumber 1 / AlternateSetting 0     idle
           InterfaceNumber 1 / AlternateSetting 1     streaming */
        ret = usb_set_interface(d->udev, 1, onoff);
        if (ret)
-               err("usb_set_interface failed with error:%d", ret);
+               pr_err("%s: usb_set_interface() failed=%d\n", KBUILD_MODNAME,
+                               ret);
 
        return ret;
 }
 
 /* DVB USB Driver stuff */
-static struct dvb_usb_device_properties ce6230_properties;
+static struct dvb_usb_device_properties ce6230_props = {
+       .driver_name = KBUILD_MODNAME,
+       .owner = THIS_MODULE,
+       .adapter_nr = adapter_nr,
+       .bInterfaceNumber = 1,
 
-static int ce6230_probe(struct usb_interface *intf,
-                       const struct usb_device_id *id)
-{
-       int ret = 0;
-       struct dvb_usb_device *d = NULL;
-
-       deb_info("%s: interface:%d\n", __func__,
-               intf->cur_altsetting->desc.bInterfaceNumber);
-
-       if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {
-               ret = dvb_usb_device_init(intf, &ce6230_properties, THIS_MODULE,
-                       &d, adapter_nr);
-               if (ret)
-                       err("init failed with error:%d\n", ret);
-       }
-
-       return ret;
-}
-
-static struct usb_device_id ce6230_table[] = {
-       { USB_DEVICE(USB_VID_INTEL, USB_PID_INTEL_CE9500) },
-       { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A310) },
-       { } /* Terminating entry */
-};
-MODULE_DEVICE_TABLE(usb, ce6230_table);
-
-static struct dvb_usb_device_properties ce6230_properties = {
-       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-       .usb_ctrl = DEVICE_SPECIFIC,
-       .no_reconnect = 1,
-
-       .size_of_priv = 0,
+       .i2c_algo = &ce6230_i2c_algorithm,
+       .power_ctrl = ce6230_power_ctrl,
+       .frontend_attach = ce6230_zl10353_frontend_attach,
+       .tuner_attach = ce6230_mxl5003s_tuner_attach,
 
        .num_adapters = 1,
        .adapter = {
                {
-               .num_frontends = 1,
-               .fe = {{
-                       .frontend_attach  = ce6230_zl10353_frontend_attach,
-                       .tuner_attach     = ce6230_mxl5003s_tuner_attach,
                        .stream = {
                                .type = USB_BULK,
                                .count = 6,
                                .endpoint = 0x82,
                                .u = {
                                        .bulk = {
-                                               .buffersize = (16*512),
+                                               .buffersize = (16 * 512),
                                        }
                                }
                        },
-               }},
                }
        },
-
-       .power_ctrl = ce6230_power_ctrl,
-
-       .i2c_algo = &ce6230_i2c_algo,
-
-       .num_device_descs = 2,
-       .devices = {
-               {
-                       .name = "Intel CE9500 reference design",
-                       .cold_ids = {NULL},
-                       .warm_ids = {&ce6230_table[0], NULL},
-               },
-               {
-                       .name = "AVerMedia A310 USB 2.0 DVB-T tuner",
-                       .cold_ids = {NULL},
-                       .warm_ids = {&ce6230_table[1], NULL},
-               },
-       }
 };
 
-static struct usb_driver ce6230_driver = {
-       .name       = "dvb_usb_ce6230",
-       .probe      = ce6230_probe,
-       .disconnect = dvb_usb_device_exit,
-       .id_table   = ce6230_table,
+static const struct usb_device_id ce6230_id_table[] = {
+       { DVB_USB_DEVICE(USB_VID_INTEL, USB_PID_INTEL_CE9500,
+               &ce6230_props, "Intel CE9500 reference design", NULL) },
+       { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A310,
+               &ce6230_props, "AVerMedia A310 USB 2.0 DVB-T tuner", NULL) },
+       { }
+};
+MODULE_DEVICE_TABLE(usb, ce6230_id_table);
+
+static struct usb_driver ce6230_usb_driver = {
+       .name = KBUILD_MODNAME,
+       .id_table = ce6230_id_table,
+       .probe = dvb_usbv2_probe,
+       .disconnect = dvb_usbv2_disconnect,
+       .suspend = dvb_usbv2_suspend,
+       .resume = dvb_usbv2_resume,
+       .no_dynamic_id = 1,
+       .soft_unbind = 1,
 };
 
-module_usb_driver(ce6230_driver);
+module_usb_driver(ce6230_usb_driver);
 
 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_DESCRIPTION("Driver for Intel CE6230 DVB-T USB2.0");
+MODULE_DESCRIPTION("Intel CE6230 driver");
 MODULE_LICENSE("GPL");
similarity index 60%
rename from drivers/media/dvb/dvb-usb/ce6230.h
rename to drivers/media/dvb/dvb-usb-v2/ce6230.h
index 97c42482ccb3de40e9f11e19289111227e501581..42d754494a3afa25c3aac946abf9e3be1e6c9192 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * DVB USB Linux driver for Intel CE6230 DVB-T USB2.0 receiver
+ * Intel CE6230 DVB USB driver
  *
  * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
  *
  *
  */
 
-#ifndef _DVB_USB_CE6230_H_
-#define _DVB_USB_CE6230_H_
+#ifndef CE6230_H
+#define CE6230_H
 
-#define DVB_USB_LOG_PREFIX "ce6230"
-#include "dvb-usb.h"
+#include "dvb_usb.h"
+#include "zl10353.h"
+#include "mxl5005s.h"
 
-#define deb_info(args...) dprintk(dvb_usb_ce6230_debug, 0x01, args)
-#define deb_rc(args...)   dprintk(dvb_usb_ce6230_debug, 0x02, args)
-#define deb_xfer(args...) dprintk(dvb_usb_ce6230_debug, 0x04, args)
-#define deb_reg(args...)  dprintk(dvb_usb_ce6230_debug, 0x08, args)
-#define deb_i2c(args...)  dprintk(dvb_usb_ce6230_debug, 0x10, args)
-#define deb_fw(args...)   dprintk(dvb_usb_ce6230_debug, 0x20, args)
-
-#define ce6230_debug_dump(r, t, v, i, b, l, func) { \
-       int loop_; \
-       func("%02x %02x %02x %02x %02x %02x %02x %02x", \
-               t, r, v & 0xff, v >> 8, i & 0xff, i >> 8, l & 0xff, l >> 8); \
+#define ce6230_debug_dump(r, t, v, i, b, l) { \
+       char *direction; \
        if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \
-               func(" >>> "); \
+               direction = ">>>"; \
        else \
-               func(" <<< "); \
-       for (loop_ = 0; loop_ < l; loop_++) \
-               func("%02x ", b[loop_]); \
-       func("\n");\
+               direction = "<<<"; \
+       pr_debug("%s: %02x %02x %02x %02x %02x %02x %02x %02x %s [%d bytes]\n", \
+                        __func__, t, r, v & 0xff, v >> 8, i & 0xff, i >> 8, \
+                       l & 0xff, l >> 8, direction, l); \
 }
 
 #define CE6230_USB_TIMEOUT 1000
 
-struct req_t {
+struct usb_req {
        u8  cmd;       /* [1] */
        u16 value;     /* [2|3] */
        u16 index;     /* [4|5] */
diff --git a/drivers/media/dvb/dvb-usb-v2/cypress_firmware.c b/drivers/media/dvb/dvb-usb-v2/cypress_firmware.c
new file mode 100644 (file)
index 0000000..9f7c970
--- /dev/null
@@ -0,0 +1,125 @@
+/*  cypress_firmware.c is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file contains functions for downloading the firmware to Cypress FX 1
+ * and 2 based devices.
+ *
+ */
+
+#include "dvb_usb.h"
+#include "cypress_firmware.h"
+
+struct usb_cypress_controller {
+       u8 id;
+       const char *name;       /* name of the usb controller */
+       u16 cs_reg;             /* needs to be restarted,
+                                * when the firmware has been downloaded */
+};
+
+static const struct usb_cypress_controller cypress[] = {
+       { .id = CYPRESS_AN2135, .name = "Cypress AN2135", .cs_reg = 0x7f92 },
+       { .id = CYPRESS_AN2235, .name = "Cypress AN2235", .cs_reg = 0x7f92 },
+       { .id = CYPRESS_FX2,    .name = "Cypress FX2",    .cs_reg = 0xe600 },
+};
+
+/*
+ * load a firmware packet to the device
+ */
+static int usb_cypress_writemem(struct usb_device *udev, u16 addr, u8 *data,
+               u8 len)
+{
+       return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+                       0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5000);
+}
+
+int usbv2_cypress_load_firmware(struct usb_device *udev,
+               const struct firmware *fw, int type)
+{
+       struct hexline hx;
+       u8 reset;
+       int ret, pos = 0;
+
+       /* stop the CPU */
+       reset = 1;
+       ret = usb_cypress_writemem(udev, cypress[type].cs_reg, &reset, 1);
+       if (ret != 1)
+               pr_err("%s: could not stop the USB controller CPU",
+                               KBUILD_MODNAME);
+
+       while ((ret = dvb_usbv2_get_hexline(fw, &hx, &pos)) > 0) {
+               pr_debug("%s: writing to address %04x (buffer: %02x %02x)\n",
+                               __func__, hx.addr, hx.len, hx.chk);
+
+               ret = usb_cypress_writemem(udev, hx.addr, hx.data, hx.len);
+               if (ret != hx.len) {
+                       pr_err("%s: error while transferring firmware " \
+                                       "(transferred size=%d, block size=%d)",
+                                       KBUILD_MODNAME, ret, hx.len);
+                       ret = -EINVAL;
+                       break;
+               }
+       }
+       if (ret < 0) {
+               pr_err("%s: firmware download failed at %d with %d",
+                               KBUILD_MODNAME, pos, ret);
+               return ret;
+       }
+
+       if (ret == 0) {
+               /* restart the CPU */
+               reset = 0;
+               if (ret || usb_cypress_writemem(
+                               udev, cypress[type].cs_reg, &reset, 1) != 1) {
+                       pr_err("%s: could not restart the USB controller CPU",
+                                       KBUILD_MODNAME);
+                       ret = -EINVAL;
+               }
+       } else
+               ret = -EIO;
+
+       return ret;
+}
+EXPORT_SYMBOL(usbv2_cypress_load_firmware);
+
+int dvb_usbv2_get_hexline(const struct firmware *fw, struct hexline *hx,
+               int *pos)
+{
+       u8 *b = (u8 *) &fw->data[*pos];
+       int data_offs = 4;
+
+       if (*pos >= fw->size)
+               return 0;
+
+       memset(hx, 0, sizeof(struct hexline));
+
+       hx->len = b[0];
+
+       if ((*pos + hx->len + 4) >= fw->size)
+               return -EINVAL;
+
+       hx->addr = b[1] | (b[2] << 8);
+       hx->type = b[3];
+
+       if (hx->type == 0x04) {
+               /* b[4] and b[5] are the Extended linear address record data
+                * field */
+               hx->addr |= (b[4] << 24) | (b[5] << 16);
+               /*
+               hx->len -= 2;
+               data_offs += 2;
+               */
+       }
+       memcpy(hx->data, &b[data_offs], hx->len);
+       hx->chk = b[hx->len + data_offs];
+
+       *pos += hx->len + 5;
+
+       return *pos;
+}
+EXPORT_SYMBOL(dvb_usbv2_get_hexline);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Cypress firmware download");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb-v2/cypress_firmware.h b/drivers/media/dvb/dvb-usb-v2/cypress_firmware.h
new file mode 100644 (file)
index 0000000..80085fd
--- /dev/null
@@ -0,0 +1,31 @@
+/* cypress_firmware.h is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file contains functions for downloading the firmware to Cypress FX 1
+ * and 2 based devices.
+ *
+ */
+
+#ifndef CYPRESS_FIRMWARE_H
+#define CYPRESS_FIRMWARE_H
+
+#define CYPRESS_AN2135  0
+#define CYPRESS_AN2235  1
+#define CYPRESS_FX2     2
+
+/* commonly used firmware download types and function */
+struct hexline {
+       u8 len;
+       u32 addr;
+       u8 type;
+       u8 data[255];
+       u8 chk;
+};
+extern int usbv2_cypress_load_firmware(struct usb_device *,
+               const struct firmware *, int);
+extern int dvb_usbv2_get_hexline(const struct firmware *,
+               struct hexline *, int *);
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb-v2/dvb_usb.h b/drivers/media/dvb/dvb-usb-v2/dvb_usb.h
new file mode 100644 (file)
index 0000000..773817b
--- /dev/null
@@ -0,0 +1,392 @@
+/*
+ * DVB USB framework
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher <patrick.boettcher@desy.de>
+ * Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
+ *
+ *    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 DVB_USB_H
+#define DVB_USB_H
+
+#include <linux/usb/input.h>
+#include <linux/firmware.h>
+#include <media/rc-core.h>
+
+#include "dvb_frontend.h"
+#include "dvb_demux.h"
+#include "dvb_net.h"
+#include "dmxdev.h"
+#include "dvb-usb-ids.h"
+
+/*
+ * device file: /dev/dvb/adapter[0-1]/frontend[0-2]
+ *
+ * |-- device
+ * |   |-- adapter0
+ * |   |   |-- frontend0
+ * |   |   |-- frontend1
+ * |   |   `-- frontend2
+ * |   `-- adapter1
+ * |       |-- frontend0
+ * |       |-- frontend1
+ * |       `-- frontend2
+ *
+ *
+ * Commonly used variable names:
+ * d = pointer to device (struct dvb_usb_device *)
+ * adap = pointer to adapter (struct dvb_usb_adapter *)
+ * fe = pointer to frontend (struct dvb_frontend *)
+ *
+ * Use macros defined in that file to resolve needed pointers.
+ */
+
+/* helper macros for every DVB USB driver use */
+#define adap_to_d(adap) (container_of(adap, struct dvb_usb_device, \
+               adapter[adap->id]))
+#define adap_to_priv(adap) (adap_to_d(adap)->priv)
+#define fe_to_adap(fe) ((struct dvb_usb_adapter *) ((fe)->dvb->priv))
+#define fe_to_d(fe) (adap_to_d(fe_to_adap(fe)))
+#define fe_to_priv(fe) (fe_to_d(fe)->priv)
+#define d_to_priv(d) (d->priv)
+
+#define DVB_USB_STREAM_BULK(endpoint_, count_, size_) { \
+       .type = USB_BULK, \
+       .count = count_, \
+       .endpoint = endpoint_, \
+       .u = { \
+               .bulk = { \
+                       .buffersize = size_, \
+               } \
+       } \
+}
+
+#define DVB_USB_STREAM_ISOC(endpoint_, count_, frames_, size_, interval_) { \
+       .type = USB_ISOC, \
+       .count = count_, \
+       .endpoint = endpoint_, \
+       .u = { \
+               .isoc = { \
+                       .framesperurb = frames_, \
+                       .framesize = size_,\
+                       .interval = interval_, \
+               } \
+       } \
+}
+
+#define DVB_USB_DEVICE(vend, prod, props_, name_, rc) \
+       .match_flags = USB_DEVICE_ID_MATCH_DEVICE, \
+       .idVendor = (vend), \
+       .idProduct = (prod), \
+       .driver_info = (kernel_ulong_t) &((const struct dvb_usb_driver_info) { \
+               .props = (props_), \
+               .name = (name_), \
+               .rc_map = (rc), \
+       })
+
+struct dvb_usb_device;
+struct dvb_usb_adapter;
+
+/**
+ * structure for carrying all needed data from the device driver to the general
+ * dvb usb routines
+ * @name: device name
+ * @rc_map: name of rc codes table
+ * @props: structure containing all device properties
+ */
+struct dvb_usb_driver_info {
+       const char *name;
+       const char *rc_map;
+       const struct dvb_usb_device_properties *props;
+};
+
+/**
+ * structure for remote controller configuration
+ * @map_name: name of rc codes table
+ * @allowed_protos: protocol(s) supported by the driver
+ * @change_protocol: callback to change protocol
+ * @query: called to query an event from the device
+ * @interval: time in ms between two queries
+ * @driver_type: used to point if a device supports raw mode
+ * @bulk_mode: device supports bulk mode for rc (disable polling mode)
+ */
+struct dvb_usb_rc {
+       const char *map_name;
+       u64 allowed_protos;
+       int (*change_protocol)(struct rc_dev *dev, u64 rc_type);
+       int (*query) (struct dvb_usb_device *d);
+       unsigned int interval;
+       const enum rc_driver_type driver_type;
+       bool bulk_mode;
+};
+
+/**
+ * usb streaming configration for adapter
+ * @type: urb type
+ * @count: count of used urbs
+ * @endpoint: stream usb endpoint number
+ */
+struct usb_data_stream_properties {
+#define USB_BULK  1
+#define USB_ISOC  2
+       u8 type;
+       u8 count;
+       u8 endpoint;
+
+       union {
+               struct {
+                       unsigned int buffersize; /* per URB */
+               } bulk;
+               struct {
+                       int framesperurb;
+                       int framesize;
+                       int interval;
+               } isoc;
+       } u;
+};
+
+/**
+ * properties of dvb usb device adapter
+ * @caps: adapter capabilities
+ * @pid_filter_count: pid count of adapter pid-filter
+ * @pid_filter_ctrl: called to enable/disable pid-filter
+ * @pid_filter: called to set/unset pid for filtering
+ * @stream: adapter usb stream configuration
+ */
+#define MAX_NO_OF_FE_PER_ADAP 3
+struct dvb_usb_adapter_properties {
+#define DVB_USB_ADAP_HAS_PID_FILTER               0x01
+#define DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF 0x02
+#define DVB_USB_ADAP_NEED_PID_FILTERING           0x04
+       u8 caps;
+
+       u8 pid_filter_count;
+       int (*pid_filter_ctrl) (struct dvb_usb_adapter *, int);
+       int (*pid_filter) (struct dvb_usb_adapter *, int, u16, int);
+
+       struct usb_data_stream_properties stream;
+};
+
+/**
+ * struct dvb_usb_device_properties - properties of a dvb-usb-device
+ * @driver_name: name of the owning driver module
+ * @owner: owner of the dvb_adapter
+ * @adapter_nr: values from the DVB_DEFINE_MOD_OPT_ADAPTER_NR() macro
+ * @bInterfaceNumber: usb interface number driver binds
+ * @size_of_priv: bytes allocated for the driver private data
+ * @generic_bulk_ctrl_endpoint: bulk control endpoint number for sent
+ * @generic_bulk_ctrl_endpoint_response: bulk control endpoint number for
+ *  receive
+ * @generic_bulk_ctrl_delay: delay between bulk control sent and receive message
+ * @identify_state: called to determine the firmware state (cold or warm) and
+ *  return possible firmware file name to be loaded
+ * @firmware: name of the firmware file to be loaded
+ * @download_firmware: called to download the firmware
+ * @i2c_algo: i2c_algorithm if the device has i2c-adapter
+ * @num_adapters: dvb usb device adapter count
+ * @get_adapter_count: called to resolve adapter count
+ * @adapter: array of all adapter properties of device
+ * @power_ctrl: called to enable/disable power of the device
+ * @read_config: called to resolve device configuration
+ * @read_mac_address: called to resolve adapter mac-address
+ * @frontend_attach: called to attach the possible frontends
+ * @tuner_attach: called to attach the possible tuners
+ * @frontend_ctrl: called to power on/off active frontend
+ * @streaming_ctrl: called to start/stop the usb streaming of adapter
+ * @fe_ioctl_override: frontend ioctl override. avoid using that is possible
+ * @init: called after adapters are created in order to finalize device
+ *  configuration
+ * @exit: called when driver is unloaded
+ * @get_rc_config: called to resolve used remote controller configuration
+ * @get_stream_config: called to resolve input and output stream configuration
+ *  of the adapter just before streaming is started. input stream is transport
+ *  stream from the demodulator and output stream is usb stream to host.
+ */
+#define MAX_NO_OF_ADAPTER_PER_DEVICE 2
+struct dvb_usb_device_properties {
+       const char *driver_name;
+       struct module *owner;
+       short *adapter_nr;
+
+       u8 bInterfaceNumber;
+       unsigned int size_of_priv;
+       u8 generic_bulk_ctrl_endpoint;
+       u8 generic_bulk_ctrl_endpoint_response;
+       unsigned int generic_bulk_ctrl_delay;
+
+#define WARM                  0
+#define COLD                  1
+       int (*identify_state) (struct dvb_usb_device *, const char **);
+       const char *firmware;
+#define RECONNECTS_USB        1
+       int (*download_firmware) (struct dvb_usb_device *,
+                       const struct firmware *);
+
+       struct i2c_algorithm *i2c_algo;
+
+       unsigned int num_adapters;
+       int (*get_adapter_count) (struct dvb_usb_device *);
+       struct dvb_usb_adapter_properties adapter[MAX_NO_OF_ADAPTER_PER_DEVICE];
+       int (*power_ctrl) (struct dvb_usb_device *, int);
+       int (*read_config) (struct dvb_usb_device *d);
+       int (*read_mac_address) (struct dvb_usb_adapter *, u8 []);
+       int (*frontend_attach) (struct dvb_usb_adapter *);
+       int (*tuner_attach) (struct dvb_usb_adapter *);
+       int (*frontend_ctrl) (struct dvb_frontend *, int);
+       int (*streaming_ctrl) (struct dvb_frontend *, int);
+       int (*fe_ioctl_override) (struct dvb_frontend *,
+                       unsigned int, void *, unsigned int);
+       int (*init) (struct dvb_usb_device *);
+       void (*exit) (struct dvb_usb_device *);
+       int (*get_rc_config) (struct dvb_usb_device *, struct dvb_usb_rc *);
+#define DVB_USB_FE_TS_TYPE_188        0
+#define DVB_USB_FE_TS_TYPE_204        1
+#define DVB_USB_FE_TS_TYPE_RAW        2
+       int (*get_stream_config) (struct dvb_frontend *,  u8 *,
+                       struct usb_data_stream_properties *);
+};
+
+/**
+ * generic object of an usb stream
+ * @buf_num: number of buffer allocated
+ * @buf_size: size of each buffer in buf_list
+ * @buf_list: array containing all allocate buffers for streaming
+ * @dma_addr: list of dma_addr_t for each buffer in buf_list
+ *
+ * @urbs_initialized: number of URBs initialized
+ * @urbs_submitted: number of URBs submitted
+ */
+#define MAX_NO_URBS_FOR_DATA_STREAM 10
+struct usb_data_stream {
+       struct usb_device *udev;
+       struct usb_data_stream_properties props;
+
+#define USB_STATE_INIT    0x00
+#define USB_STATE_URB_BUF 0x01
+       u8 state;
+
+       void (*complete) (struct usb_data_stream *, u8 *, size_t);
+
+       struct urb    *urb_list[MAX_NO_URBS_FOR_DATA_STREAM];
+       int            buf_num;
+       unsigned long  buf_size;
+       u8            *buf_list[MAX_NO_URBS_FOR_DATA_STREAM];
+       dma_addr_t     dma_addr[MAX_NO_URBS_FOR_DATA_STREAM];
+
+       int urbs_initialized;
+       int urbs_submitted;
+
+       void *user_priv;
+};
+
+/**
+ * dvb adapter object on dvb usb device
+ * @props: pointer to adapter properties
+ * @stream: adapter the usb data stream
+ * @id: index of this adapter (starting with 0)
+ * @ts_type: transport stream, input stream, type
+ * @pid_filtering: is hardware pid_filtering used or not
+ * @feed_count: current feed count
+ * @max_feed_count: maimum feed count device can handle
+ * @dvb_adap: adapter dvb_adapter
+ * @dmxdev: adapter dmxdev
+ * @demux: adapter software demuxer
+ * @dvb_net: adapter dvb_net interfaces
+ * @sync_mutex: mutex used to sync control and streaming of the adapter
+ * @fe: adapter frontends
+ * @fe_init: rerouted frontend-init function
+ * @fe_sleep: rerouted frontend-sleep function
+ */
+struct dvb_usb_adapter {
+       const struct dvb_usb_adapter_properties *props;
+       struct usb_data_stream stream;
+       u8 id;
+       u8 ts_type;
+       bool pid_filtering;
+       u8 feed_count;
+       u8 max_feed_count;
+       s8 active_fe;
+
+       /* dvb */
+       struct dvb_adapter   dvb_adap;
+       struct dmxdev        dmxdev;
+       struct dvb_demux     demux;
+       struct dvb_net       dvb_net;
+       struct mutex         sync_mutex;
+
+       struct dvb_frontend *fe[MAX_NO_OF_FE_PER_ADAP];
+       int (*fe_init[MAX_NO_OF_FE_PER_ADAP]) (struct dvb_frontend *);
+       int (*fe_sleep[MAX_NO_OF_FE_PER_ADAP]) (struct dvb_frontend *);
+};
+
+/**
+ * dvb usb device object
+ * @props: device properties
+ * @name: device name
+ * @rc_map: name of rc codes table
+ * @udev: pointer to the device's struct usb_device
+ * @intf: pointer to the device's usb interface
+ * @rc: remote controller configuration
+ * @probe_work: work to defer .probe()
+ * @powered: indicated whether the device is power or not
+ * @usb_mutex: mutex for usb control messages
+ * @i2c_mutex: mutex for i2c-transfers
+ * @i2c_adap: device's i2c-adapter
+ * @rc_dev: rc device for the remote control
+ * @rc_query_work: work for polling remote
+ * @priv: private data of the actual driver (allocate by dvb usb, size defined
+ *  in size_of_priv of dvb_usb_properties).
+ */
+struct dvb_usb_device {
+       const struct dvb_usb_device_properties *props;
+       const char *name;
+       const char *rc_map;
+
+       struct usb_device *udev;
+       struct usb_interface *intf;
+       struct dvb_usb_rc rc;
+       struct work_struct probe_work;
+       pid_t work_pid;
+       int powered;
+
+       /* locking */
+       struct mutex usb_mutex;
+
+       /* i2c */
+       struct mutex i2c_mutex;
+       struct i2c_adapter i2c_adap;
+
+       struct dvb_usb_adapter adapter[MAX_NO_OF_ADAPTER_PER_DEVICE];
+
+       /* remote control */
+       struct rc_dev *rc_dev;
+       char rc_phys[64];
+       struct delayed_work rc_query_work;
+
+       void *priv;
+};
+
+extern int dvb_usbv2_probe(struct usb_interface *,
+               const struct usb_device_id *);
+extern void dvb_usbv2_disconnect(struct usb_interface *);
+extern int dvb_usbv2_suspend(struct usb_interface *, pm_message_t);
+extern int dvb_usbv2_resume(struct usb_interface *);
+
+/* the generic read/write method for device control */
+extern int dvb_usbv2_generic_rw(struct dvb_usb_device *, u8 *, u16, u8 *, u16);
+extern int dvb_usbv2_generic_write(struct dvb_usb_device *, u8 *, u16);
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb-v2/dvb_usb_common.h b/drivers/media/dvb/dvb-usb-v2/dvb_usb_common.h
new file mode 100644 (file)
index 0000000..45f0709
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * DVB USB framework
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher <patrick.boettcher@desy.de>
+ * Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
+ *
+ *    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 DVB_USB_COMMON_H
+#define DVB_USB_COMMON_H
+
+#include "dvb_usb.h"
+
+/* commonly used  methods */
+extern int usb_urb_initv2(struct usb_data_stream *stream,
+               const struct usb_data_stream_properties *props);
+extern int usb_urb_exitv2(struct usb_data_stream *stream);
+extern int usb_urb_submitv2(struct usb_data_stream *stream,
+               struct usb_data_stream_properties *props);
+extern int usb_urb_killv2(struct usb_data_stream *stream);
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/dvb/dvb-usb-v2/dvb_usb_core.c
new file mode 100644 (file)
index 0000000..3224621
--- /dev/null
@@ -0,0 +1,999 @@
+/*
+ * DVB USB framework
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher <patrick.boettcher@desy.de>
+ * Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "dvb_usb_common.h"
+
+int dvb_usbv2_disable_rc_polling;
+module_param_named(disable_rc_polling, dvb_usbv2_disable_rc_polling, int, 0644);
+MODULE_PARM_DESC(disable_rc_polling,
+               "disable remote control polling (default: 0)");
+static int dvb_usb_force_pid_filter_usage;
+module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage,
+               int, 0444);
+MODULE_PARM_DESC(force_pid_filter_usage, "force all DVB USB devices to use a " \
+               "PID filter, if any (default: 0)");
+
+static int dvb_usbv2_download_firmware(struct dvb_usb_device *d, const char *name)
+{
+       int ret;
+       const struct firmware *fw;
+       dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+       if (!d->props->download_firmware) {
+               ret = -EINVAL;
+               goto err;
+       }
+
+       ret = request_firmware(&fw, name, &d->udev->dev);
+       if (ret < 0) {
+               dev_err(&d->udev->dev, "%s: Did not find the firmware file "\
+                               "'%s'. Please see linux/Documentation/dvb/ " \
+                               "for more details on firmware-problems. " \
+                               "Status %d\n", KBUILD_MODNAME, name, ret);
+               goto err;
+       }
+
+       dev_info(&d->udev->dev, "%s: downloading firmware from file '%s'\n",
+                       KBUILD_MODNAME, name);
+
+       ret = d->props->download_firmware(d, fw);
+       release_firmware(fw);
+       if (ret < 0)
+               goto err;
+
+       return ret;
+err:
+       dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+static int dvb_usbv2_i2c_init(struct dvb_usb_device *d)
+{
+       int ret;
+       dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+       if (!d->props->i2c_algo)
+               return 0;
+
+       strlcpy(d->i2c_adap.name, d->name, sizeof(d->i2c_adap.name));
+       d->i2c_adap.algo = d->props->i2c_algo;
+       d->i2c_adap.dev.parent = &d->udev->dev;
+       i2c_set_adapdata(&d->i2c_adap, d);
+
+       ret = i2c_add_adapter(&d->i2c_adap);
+       if (ret < 0) {
+               d->i2c_adap.algo = NULL;
+               dev_err(&d->udev->dev, "%s: i2c_add_adapter() failed=%d\n",
+                               KBUILD_MODNAME, ret);
+               goto err;
+       }
+
+       return 0;
+err:
+       dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+static int dvb_usbv2_i2c_exit(struct dvb_usb_device *d)
+{
+       dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+       if (d->i2c_adap.algo)
+               i2c_del_adapter(&d->i2c_adap);
+
+       return 0;
+}
+
+static void dvb_usb_read_remote_control(struct work_struct *work)
+{
+       struct dvb_usb_device *d = container_of(work,
+                       struct dvb_usb_device, rc_query_work.work);
+       int ret;
+
+       /*
+        * When the parameter has been set to 1 via sysfs while the
+        * driver was running, or when bulk mode is enabled after IR init.
+        */
+       if (dvb_usbv2_disable_rc_polling || d->rc.bulk_mode)
+               return;
+
+       ret = d->rc.query(d);
+       if (ret < 0) {
+               dev_err(&d->udev->dev, "%s: rc.query() failed=%d\n",
+                               KBUILD_MODNAME, ret);
+               return; /* stop polling */
+       }
+
+       schedule_delayed_work(&d->rc_query_work,
+                       msecs_to_jiffies(d->rc.interval));
+}
+
+static int dvb_usbv2_remote_init(struct dvb_usb_device *d)
+{
+       int ret;
+       struct rc_dev *dev;
+       dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+       if (dvb_usbv2_disable_rc_polling || !d->props->get_rc_config)
+               return 0;
+
+       d->rc.map_name = d->rc_map;
+       ret = d->props->get_rc_config(d, &d->rc);
+       if (ret < 0)
+               goto err;
+
+       /* disable rc when there is no keymap defined */
+       if (!d->rc.map_name)
+               return 0;
+
+       dev = rc_allocate_device();
+       if (!dev) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       dev->dev.parent = &d->udev->dev;
+       dev->input_name = d->name;
+       usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));
+       strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys));
+       dev->input_phys = d->rc_phys;
+       usb_to_input_id(d->udev, &dev->input_id);
+       /* TODO: likely RC-core should took const char * */
+       dev->driver_name = (char *) d->props->driver_name;
+       dev->map_name = d->rc.map_name;
+       dev->driver_type = d->rc.driver_type;
+       dev->allowed_protos = d->rc.allowed_protos;
+       dev->change_protocol = d->rc.change_protocol;
+       dev->priv = d;
+
+       ret = rc_register_device(dev);
+       if (ret < 0) {
+               rc_free_device(dev);
+               goto err;
+       }
+
+       d->rc_dev = dev;
+
+       /* start polling if needed */
+       if (d->rc.query && !d->rc.bulk_mode) {
+               /* initialize a work queue for handling polling */
+               INIT_DELAYED_WORK(&d->rc_query_work,
+                               dvb_usb_read_remote_control);
+               dev_info(&d->udev->dev, "%s: schedule remote query interval " \
+                               "to %d msecs\n", KBUILD_MODNAME,
+                               d->rc.interval);
+               schedule_delayed_work(&d->rc_query_work,
+                               msecs_to_jiffies(d->rc.interval));
+       }
+
+       return 0;
+err:
+       dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+static int dvb_usbv2_remote_exit(struct dvb_usb_device *d)
+{
+       dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+       if (d->rc_dev) {
+               cancel_delayed_work_sync(&d->rc_query_work);
+               rc_unregister_device(d->rc_dev);
+               d->rc_dev = NULL;
+       }
+
+       return 0;
+}
+
+static void dvb_usb_data_complete(struct usb_data_stream *stream, u8 *buf,
+               size_t len)
+{
+       struct dvb_usb_adapter *adap = stream->user_priv;
+       dvb_dmx_swfilter(&adap->demux, buf, len);
+}
+
+static void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buf,
+               size_t len)
+{
+       struct dvb_usb_adapter *adap = stream->user_priv;
+       dvb_dmx_swfilter_204(&adap->demux, buf, len);
+}
+
+static void dvb_usb_data_complete_raw(struct usb_data_stream *stream, u8 *buf,
+               size_t len)
+{
+       struct dvb_usb_adapter *adap = stream->user_priv;
+       dvb_dmx_swfilter_raw(&adap->demux, buf, len);
+}
+
+int dvb_usbv2_adapter_stream_init(struct dvb_usb_adapter *adap)
+{
+       dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__,
+                       adap->id);
+
+       adap->stream.udev = adap_to_d(adap)->udev;
+       adap->stream.user_priv = adap;
+       adap->stream.complete = dvb_usb_data_complete;
+
+       return usb_urb_initv2(&adap->stream, &adap->props->stream);
+}
+
+int dvb_usbv2_adapter_stream_exit(struct dvb_usb_adapter *adap)
+{
+       dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__,
+                       adap->id);
+
+       return usb_urb_exitv2(&adap->stream);
+}
+
+static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed,
+               int count)
+{
+       struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv;
+       struct dvb_usb_device *d = adap_to_d(adap);
+       int ret;
+       dev_dbg(&d->udev->dev, "%s: adap=%d active_fe=%d feed_type=%d " \
+                       "setting pid [%s]: %04x (%04d) at index %d '%s'\n",
+                       __func__, adap->id, adap->active_fe, dvbdmxfeed->type,
+                       adap->pid_filtering ? "yes" : "no", dvbdmxfeed->pid,
+                       dvbdmxfeed->pid, dvbdmxfeed->index,
+                       (count == 1) ? "on" : "off");
+
+       if (adap->active_fe == -1)
+               return -EINVAL;
+
+       adap->feed_count += count;
+
+       /* stop feeding if it is last pid */
+       if (adap->feed_count == 0) {
+               dev_dbg(&d->udev->dev, "%s: stop feeding\n", __func__);
+               usb_urb_killv2(&adap->stream);
+
+               if (d->props->streaming_ctrl) {
+                       ret = d->props->streaming_ctrl(
+                                       adap->fe[adap->active_fe], 0);
+                       if (ret < 0) {
+                               dev_err(&d->udev->dev, "%s: streaming_ctrl() " \
+                                               "failed=%d\n", KBUILD_MODNAME,
+                                               ret);
+                               goto err_mutex_unlock;
+                       }
+               }
+               mutex_unlock(&adap->sync_mutex);
+       }
+
+       /* activate the pid on the device pid filter */
+       if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER &&
+                       adap->pid_filtering &&
+                       adap->props->pid_filter)
+               ret = adap->props->pid_filter(adap, dvbdmxfeed->index,
+                               dvbdmxfeed->pid, (count == 1) ? 1 : 0);
+                       if (ret < 0)
+                               dev_err(&d->udev->dev, "%s: pid_filter() " \
+                                               "failed=%d\n", KBUILD_MODNAME,
+                                               ret);
+
+       /* start feeding if it is first pid */
+       if (adap->feed_count == 1 && count == 1) {
+               struct usb_data_stream_properties stream_props;
+               mutex_lock(&adap->sync_mutex);
+               dev_dbg(&d->udev->dev, "%s: start feeding\n", __func__);
+
+               /* resolve input and output streaming paramters */
+               if (d->props->get_stream_config) {
+                       memcpy(&stream_props, &adap->props->stream,
+                               sizeof(struct usb_data_stream_properties));
+                       ret = d->props->get_stream_config(
+                                       adap->fe[adap->active_fe],
+                                       &adap->ts_type, &stream_props);
+                       if (ret < 0)
+                               goto err_mutex_unlock;
+               } else {
+                       stream_props = adap->props->stream;
+               }
+
+               switch (adap->ts_type) {
+               case DVB_USB_FE_TS_TYPE_204:
+                       adap->stream.complete = dvb_usb_data_complete_204;
+                       break;
+               case DVB_USB_FE_TS_TYPE_RAW:
+                       adap->stream.complete = dvb_usb_data_complete_raw;
+                       break;
+               case DVB_USB_FE_TS_TYPE_188:
+               default:
+                       adap->stream.complete = dvb_usb_data_complete;
+                       break;
+               }
+
+               usb_urb_submitv2(&adap->stream, &stream_props);
+
+               if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER &&
+                               adap->props->caps &
+                               DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF &&
+                               adap->props->pid_filter_ctrl) {
+                       ret = adap->props->pid_filter_ctrl(adap,
+                                       adap->pid_filtering);
+                       if (ret < 0) {
+                               dev_err(&d->udev->dev, "%s: " \
+                                               "pid_filter_ctrl() failed=%d\n",
+                                               KBUILD_MODNAME, ret);
+                               goto err_mutex_unlock;
+                       }
+               }
+
+               if (d->props->streaming_ctrl) {
+                       ret = d->props->streaming_ctrl(
+                                       adap->fe[adap->active_fe], 1);
+                       if (ret < 0) {
+                               dev_err(&d->udev->dev, "%s: streaming_ctrl() " \
+                                               "failed=%d\n", KBUILD_MODNAME,
+                                               ret);
+                               goto err_mutex_unlock;
+                       }
+               }
+       }
+
+       return 0;
+err_mutex_unlock:
+       mutex_unlock(&adap->sync_mutex);
+       dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+       return dvb_usb_ctrl_feed(dvbdmxfeed, 1);
+}
+
+static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+       return dvb_usb_ctrl_feed(dvbdmxfeed, -1);
+}
+
+int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap)
+{
+       int ret;
+       struct dvb_usb_device *d = adap_to_d(adap);
+       dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, adap->id);
+
+       ret = dvb_register_adapter(&adap->dvb_adap, d->name, d->props->owner,
+                       &d->udev->dev, d->props->adapter_nr);
+       if (ret < 0) {
+               dev_dbg(&d->udev->dev, "%s: dvb_register_adapter() failed=%d\n",
+                               __func__, ret);
+               goto err_dvb_register_adapter;
+       }
+
+       adap->dvb_adap.priv = adap;
+
+       if (d->props->read_mac_address) {
+               ret = d->props->read_mac_address(adap,
+                               adap->dvb_adap.proposed_mac);
+               if (ret < 0)
+                       goto err_dvb_dmx_init;
+
+               dev_info(&d->udev->dev, "%s: MAC address: %pM\n",
+                               KBUILD_MODNAME, adap->dvb_adap.proposed_mac);
+       }
+
+       adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
+       adap->demux.priv             = adap;
+       adap->demux.filternum        = 0;
+       adap->demux.filternum        = adap->max_feed_count;
+       adap->demux.feednum          = adap->demux.filternum;
+       adap->demux.start_feed       = dvb_usb_start_feed;
+       adap->demux.stop_feed        = dvb_usb_stop_feed;
+       adap->demux.write_to_decoder = NULL;
+       ret = dvb_dmx_init(&adap->demux);
+       if (ret < 0) {
+               dev_err(&d->udev->dev, "%s: dvb_dmx_init() failed=%d\n",
+                               KBUILD_MODNAME, ret);
+               goto err_dvb_dmx_init;
+       }
+
+       adap->dmxdev.filternum       = adap->demux.filternum;
+       adap->dmxdev.demux           = &adap->demux.dmx;
+       adap->dmxdev.capabilities    = 0;
+       ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap);
+       if (ret < 0) {
+               dev_err(&d->udev->dev, "%s: dvb_dmxdev_init() failed=%d\n",
+                               KBUILD_MODNAME, ret);
+               goto err_dvb_dmxdev_init;
+       }
+
+       ret = dvb_net_init(&adap->dvb_adap, &adap->dvb_net, &adap->demux.dmx);
+       if (ret < 0) {
+               dev_err(&d->udev->dev, "%s: dvb_net_init() failed=%d\n",
+                               KBUILD_MODNAME, ret);
+               goto err_dvb_net_init;
+       }
+
+       mutex_init(&adap->sync_mutex);
+
+       return 0;
+err_dvb_net_init:
+       dvb_dmxdev_release(&adap->dmxdev);
+err_dvb_dmxdev_init:
+       dvb_dmx_release(&adap->demux);
+err_dvb_dmx_init:
+       dvb_unregister_adapter(&adap->dvb_adap);
+err_dvb_register_adapter:
+       adap->dvb_adap.priv = NULL;
+       return ret;
+}
+
+int dvb_usbv2_adapter_dvb_exit(struct dvb_usb_adapter *adap)
+{
+       dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__,
+                       adap->id);
+
+       if (adap->dvb_adap.priv) {
+               dvb_net_release(&adap->dvb_net);
+               adap->demux.dmx.close(&adap->demux.dmx);
+               dvb_dmxdev_release(&adap->dmxdev);
+               dvb_dmx_release(&adap->demux);
+               dvb_unregister_adapter(&adap->dvb_adap);
+       }
+
+       return 0;
+}
+
+int dvb_usbv2_device_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+       int ret;
+
+       if (onoff)
+               d->powered++;
+       else
+               d->powered--;
+
+       if (d->powered == 0 || (onoff && d->powered == 1)) {
+               /* when switching from 1 to 0 or from 0 to 1 */
+               dev_dbg(&d->udev->dev, "%s: power=%d\n", __func__, onoff);
+               if (d->props->power_ctrl) {
+                       ret = d->props->power_ctrl(d, onoff);
+                       if (ret < 0)
+                               goto err;
+               }
+       }
+
+       return 0;
+err:
+       dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+static int dvb_usb_fe_init(struct dvb_frontend *fe)
+{
+       int ret;
+       struct dvb_usb_adapter *adap = fe->dvb->priv;
+       struct dvb_usb_device *d = adap_to_d(adap);
+       mutex_lock(&adap->sync_mutex);
+       dev_dbg(&d->udev->dev, "%s: adap=%d fe=%d\n", __func__, adap->id,
+                       fe->id);
+
+       ret = dvb_usbv2_device_power_ctrl(d, 1);
+       if (ret < 0)
+               goto err;
+
+       if (d->props->frontend_ctrl) {
+               ret = d->props->frontend_ctrl(fe, 1);
+               if (ret < 0)
+                       goto err;
+       }
+
+       if (adap->fe_init[fe->id]) {
+               ret = adap->fe_init[fe->id](fe);
+               if (ret < 0)
+                       goto err;
+       }
+
+       adap->active_fe = fe->id;
+       mutex_unlock(&adap->sync_mutex);
+
+       return 0;
+err:
+       mutex_unlock(&adap->sync_mutex);
+       dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+static int dvb_usb_fe_sleep(struct dvb_frontend *fe)
+{
+       int ret;
+       struct dvb_usb_adapter *adap = fe->dvb->priv;
+       struct dvb_usb_device *d = adap_to_d(adap);
+       mutex_lock(&adap->sync_mutex);
+       dev_dbg(&d->udev->dev, "%s: adap=%d fe=%d\n", __func__, adap->id,
+                       fe->id);
+
+       if (adap->fe_sleep[fe->id]) {
+               ret = adap->fe_sleep[fe->id](fe);
+               if (ret < 0)
+                       goto err;
+       }
+
+       if (d->props->frontend_ctrl) {
+               ret = d->props->frontend_ctrl(fe, 0);
+               if (ret < 0)
+                       goto err;
+       }
+
+       ret = dvb_usbv2_device_power_ctrl(d, 0);
+       if (ret < 0)
+               goto err;
+
+       adap->active_fe = -1;
+       mutex_unlock(&adap->sync_mutex);
+
+       return 0;
+err:
+       mutex_unlock(&adap->sync_mutex);
+       dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap)
+{
+       int ret, i, count_registered = 0;
+       struct dvb_usb_device *d = adap_to_d(adap);
+       dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, adap->id);
+
+       memset(adap->fe, 0, sizeof(adap->fe));
+       adap->active_fe = -1;
+
+       if (d->props->frontend_attach) {
+               ret = d->props->frontend_attach(adap);
+               if (ret < 0) {
+                       dev_dbg(&d->udev->dev, "%s: frontend_attach() " \
+                                       "failed=%d\n", __func__, ret);
+                       goto err_dvb_frontend_detach;
+               }
+       } else {
+               dev_dbg(&d->udev->dev, "%s: frontend_attach() do not exists\n",
+                               __func__);
+               ret = 0;
+               goto err;
+       }
+
+       for (i = 0; i < MAX_NO_OF_FE_PER_ADAP && adap->fe[i]; i++) {
+               adap->fe[i]->id = i;
+               /* re-assign sleep and wakeup functions */
+               adap->fe_init[i] = adap->fe[i]->ops.init;
+               adap->fe[i]->ops.init = dvb_usb_fe_init;
+               adap->fe_sleep[i] = adap->fe[i]->ops.sleep;
+               adap->fe[i]->ops.sleep = dvb_usb_fe_sleep;
+
+               ret = dvb_register_frontend(&adap->dvb_adap, adap->fe[i]);
+               if (ret < 0) {
+                       dev_err(&d->udev->dev, "%s: frontend%d registration " \
+                                       "failed\n", KBUILD_MODNAME, i);
+                       goto err_dvb_unregister_frontend;
+               }
+
+               count_registered++;
+       }
+
+       if (d->props->tuner_attach) {
+               ret = d->props->tuner_attach(adap);
+               if (ret < 0) {
+                       dev_dbg(&d->udev->dev, "%s: tuner_attach() failed=%d\n",
+                                       __func__, ret);
+                       goto err_dvb_unregister_frontend;
+               }
+       }
+
+       return 0;
+
+err_dvb_unregister_frontend:
+       for (i = count_registered - 1; i >= 0; i--)
+               dvb_unregister_frontend(adap->fe[i]);
+
+err_dvb_frontend_detach:
+       for (i = MAX_NO_OF_FE_PER_ADAP - 1; i >= 0; i--) {
+               if (adap->fe[i])
+                       dvb_frontend_detach(adap->fe[i]);
+       }
+
+err:
+       dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+int dvb_usbv2_adapter_frontend_exit(struct dvb_usb_adapter *adap)
+{
+       int i;
+       dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__,
+                       adap->id);
+
+       for (i = MAX_NO_OF_FE_PER_ADAP - 1; i >= 0; i--) {
+               if (adap->fe[i]) {
+                       dvb_unregister_frontend(adap->fe[i]);
+                       dvb_frontend_detach(adap->fe[i]);
+               }
+       }
+
+       return 0;
+}
+
+static int dvb_usbv2_adapter_init(struct dvb_usb_device *d)
+{
+       struct dvb_usb_adapter *adap;
+       int ret, i, adapter_count;
+
+       /* resolve adapter count */
+       adapter_count = d->props->num_adapters;
+       if (d->props->get_adapter_count) {
+               ret = d->props->get_adapter_count(d);
+               if (ret < 0)
+                       goto err;
+
+               adapter_count = ret;
+       }
+
+       for (i = 0; i < adapter_count; i++) {
+               adap = &d->adapter[i];
+               adap->id = i;
+               adap->props = &d->props->adapter[i];
+
+               /* speed - when running at FULL speed we need a HW PID filter */
+               if (d->udev->speed == USB_SPEED_FULL &&
+                               !(adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER)) {
+                       dev_err(&d->udev->dev, "%s: this USB2.0 device " \
+                                       "cannot be run on a USB1.1 port (it " \
+                                       "lacks a hardware PID filter)\n",
+                                       KBUILD_MODNAME);
+                       ret = -ENODEV;
+                       goto err;
+               } else if ((d->udev->speed == USB_SPEED_FULL &&
+                               adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER) ||
+                               (adap->props->caps & DVB_USB_ADAP_NEED_PID_FILTERING)) {
+                       dev_info(&d->udev->dev, "%s: will use the device's " \
+                                       "hardware PID filter " \
+                                       "(table count: %d)\n", KBUILD_MODNAME,
+                                       adap->props->pid_filter_count);
+                       adap->pid_filtering  = 1;
+                       adap->max_feed_count = adap->props->pid_filter_count;
+               } else {
+                       dev_info(&d->udev->dev, "%s: will pass the complete " \
+                                       "MPEG2 transport stream to the " \
+                                       "software demuxer\n", KBUILD_MODNAME);
+                       adap->pid_filtering  = 0;
+                       adap->max_feed_count = 255;
+               }
+
+               if (!adap->pid_filtering && dvb_usb_force_pid_filter_usage &&
+                               adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER) {
+                       dev_info(&d->udev->dev, "%s: PID filter enabled by " \
+                                       "module option\n", KBUILD_MODNAME);
+                       adap->pid_filtering  = 1;
+                       adap->max_feed_count = adap->props->pid_filter_count;
+               }
+
+               ret = dvb_usbv2_adapter_stream_init(adap);
+               if (ret)
+                       goto err;
+
+               ret = dvb_usbv2_adapter_dvb_init(adap);
+               if (ret)
+                       goto err;
+
+               ret = dvb_usbv2_adapter_frontend_init(adap);
+               if (ret)
+                       goto err;
+
+               /* use exclusive FE lock if there is multiple shared FEs */
+               if (adap->fe[1])
+                       adap->dvb_adap.mfe_shared = 1;
+
+               adap->dvb_adap.fe_ioctl_override = d->props->fe_ioctl_override;
+       }
+
+       return 0;
+err:
+       dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+static int dvb_usbv2_adapter_exit(struct dvb_usb_device *d)
+{
+       int i;
+       dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+       for (i = MAX_NO_OF_ADAPTER_PER_DEVICE - 1; i >= 0; i--) {
+               if (d->adapter[i].props) {
+                       dvb_usbv2_adapter_frontend_exit(&d->adapter[i]);
+                       dvb_usbv2_adapter_dvb_exit(&d->adapter[i]);
+                       dvb_usbv2_adapter_stream_exit(&d->adapter[i]);
+               }
+       }
+
+       return 0;
+}
+
+/* general initialization functions */
+static int dvb_usbv2_exit(struct dvb_usb_device *d)
+{
+       dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+       dvb_usbv2_remote_exit(d);
+       dvb_usbv2_adapter_exit(d);
+       dvb_usbv2_i2c_exit(d);
+       kfree(d->priv);
+       kfree(d);
+
+       return 0;
+}
+
+static int dvb_usbv2_init(struct dvb_usb_device *d)
+{
+       int ret;
+       dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+       dvb_usbv2_device_power_ctrl(d, 1);
+
+       if (d->props->read_config) {
+               ret = d->props->read_config(d);
+               if (ret < 0)
+                       goto err;
+       }
+
+       ret = dvb_usbv2_i2c_init(d);
+       if (ret < 0)
+               goto err;
+
+       ret = dvb_usbv2_adapter_init(d);
+       if (ret < 0)
+               goto err;
+
+       if (d->props->init) {
+               ret = d->props->init(d);
+               if (ret < 0)
+                       goto err;
+       }
+
+       ret = dvb_usbv2_remote_init(d);
+       if (ret < 0)
+               goto err;
+
+       dvb_usbv2_device_power_ctrl(d, 0);
+
+       return 0;
+err:
+       dvb_usbv2_device_power_ctrl(d, 0);
+       dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+/*
+ * udev, which is used for the firmware downloading, requires we cannot
+ * block during module_init(). module_init() calls USB probe() which
+ * is this routine. Due to that we delay actual operation using workqueue
+ * and return always success here.
+ */
+static void dvb_usbv2_init_work(struct work_struct *work)
+{
+       int ret;
+       struct dvb_usb_device *d =
+                       container_of(work, struct dvb_usb_device, probe_work);
+
+       d->work_pid = current->pid;
+       dev_dbg(&d->udev->dev, "%s: work_pid=%d\n", __func__, d->work_pid);
+
+       if (d->props->size_of_priv) {
+               d->priv = kzalloc(d->props->size_of_priv, GFP_KERNEL);
+               if (!d->priv) {
+                       dev_err(&d->udev->dev, "%s: kzalloc() failed\n",
+                                       KBUILD_MODNAME);
+                       ret = -ENOMEM;
+                       goto err_usb_driver_release_interface;
+               }
+       }
+
+       if (d->props->identify_state) {
+               const char *name = NULL;
+               ret = d->props->identify_state(d, &name);
+               if (ret == 0) {
+                       ;
+               } else if (ret == COLD) {
+                       dev_info(&d->udev->dev, "%s: found a '%s' in cold " \
+                                       "state\n", KBUILD_MODNAME, d->name);
+
+                       if (!name)
+                               name = d->props->firmware;
+
+                       ret = dvb_usbv2_download_firmware(d, name);
+                       if (ret == 0) {
+                               /* device is warm, continue initialization */
+                               ;
+                       } else if (ret == RECONNECTS_USB) {
+                               /*
+                                * USB core will call disconnect() and then
+                                * probe() as device reconnects itself from the
+                                * USB bus. disconnect() will release all driver
+                                * resources and probe() is called for 'new'
+                                * device. As 'new' device is warm we should
+                                * never go here again.
+                                */
+                               return;
+                       } else {
+                               /*
+                                * Unexpected error. We must unregister driver
+                                * manually from the device, because device is
+                                * already register by returning from probe()
+                                * with success. usb_driver_release_interface()
+                                * finally calls disconnect() in order to free
+                                * resources.
+                                */
+                               goto err_usb_driver_release_interface;
+                       }
+               } else {
+                       goto err_usb_driver_release_interface;
+               }
+       }
+
+       dev_info(&d->udev->dev, "%s: found a '%s' in warm state\n",
+                       KBUILD_MODNAME, d->name);
+
+       ret = dvb_usbv2_init(d);
+       if (ret < 0)
+               goto err_usb_driver_release_interface;
+
+       dev_info(&d->udev->dev, "%s: '%s' successfully initialized and " \
+                       "connected\n", KBUILD_MODNAME, d->name);
+
+       return;
+err_usb_driver_release_interface:
+       dev_info(&d->udev->dev, "%s: '%s' error while loading driver (%d)\n",
+                       KBUILD_MODNAME, d->name, ret);
+       usb_driver_release_interface(to_usb_driver(d->intf->dev.driver),
+                       d->intf);
+       dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+       return;
+}
+
+int dvb_usbv2_probe(struct usb_interface *intf,
+               const struct usb_device_id *id)
+{
+       int ret;
+       struct dvb_usb_device *d;
+       struct usb_device *udev = interface_to_usbdev(intf);
+       struct dvb_usb_driver_info *driver_info =
+                       (struct dvb_usb_driver_info *) id->driver_info;
+
+       dev_dbg(&udev->dev, "%s: bInterfaceNumber=%d\n", __func__,
+                       intf->cur_altsetting->desc.bInterfaceNumber);
+
+       if (!id->driver_info) {
+               dev_err(&udev->dev, "%s: driver_info failed\n", KBUILD_MODNAME);
+               ret = -ENODEV;
+               goto err;
+       }
+
+       d = kzalloc(sizeof(struct dvb_usb_device), GFP_KERNEL);
+       if (!d) {
+               dev_err(&udev->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME);
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       d->name = driver_info->name;
+       d->rc_map = driver_info->rc_map;
+       d->udev = udev;
+       d->intf = intf;
+       d->props = driver_info->props;
+
+       if (d->intf->cur_altsetting->desc.bInterfaceNumber !=
+                       d->props->bInterfaceNumber) {
+               ret = -ENODEV;
+               goto err_kfree;
+       }
+
+       mutex_init(&d->usb_mutex);
+       mutex_init(&d->i2c_mutex);
+       INIT_WORK(&d->probe_work, dvb_usbv2_init_work);
+       usb_set_intfdata(intf, d);
+       ret = schedule_work(&d->probe_work);
+       if (ret < 0) {
+               dev_err(&d->udev->dev, "%s: schedule_work() failed\n",
+                               KBUILD_MODNAME);
+               goto err_kfree;
+       }
+
+       return 0;
+err_kfree:
+       kfree(d);
+err:
+       dev_dbg(&udev->dev, "%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+EXPORT_SYMBOL(dvb_usbv2_probe);
+
+void dvb_usbv2_disconnect(struct usb_interface *intf)
+{
+       struct dvb_usb_device *d = usb_get_intfdata(intf);
+       const char *name = d->name;
+       struct device dev = d->udev->dev;
+       dev_dbg(&d->udev->dev, "%s: pid=%d work_pid=%d\n", __func__,
+                       current->pid, d->work_pid);
+
+       /* ensure initialization work is finished until release resources */
+       if (d->work_pid != current->pid)
+               cancel_work_sync(&d->probe_work);
+
+       if (d->props->exit)
+               d->props->exit(d);
+
+       dvb_usbv2_exit(d);
+
+       dev_info(&dev, "%s: '%s' successfully deinitialized and disconnected\n",
+                       KBUILD_MODNAME, name);
+}
+EXPORT_SYMBOL(dvb_usbv2_disconnect);
+
+int dvb_usbv2_suspend(struct usb_interface *intf, pm_message_t msg)
+{
+       struct dvb_usb_device *d = usb_get_intfdata(intf);
+       int i;
+       dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+       /* stop remote controller poll */
+       if (d->rc.query && !d->rc.bulk_mode)
+               cancel_delayed_work_sync(&d->rc_query_work);
+
+       /* stop streaming */
+       for (i = MAX_NO_OF_ADAPTER_PER_DEVICE - 1; i >= 0; i--) {
+               if (d->adapter[i].dvb_adap.priv &&
+                               d->adapter[i].active_fe != -1)
+                       usb_urb_killv2(&d->adapter[i].stream);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(dvb_usbv2_suspend);
+
+int dvb_usbv2_resume(struct usb_interface *intf)
+{
+       struct dvb_usb_device *d = usb_get_intfdata(intf);
+       int i;
+       dev_dbg(&d->udev->dev, "%s:\n", __func__);
+
+       /* start streaming */
+       for (i = 0; i < MAX_NO_OF_ADAPTER_PER_DEVICE; i++) {
+               if (d->adapter[i].dvb_adap.priv &&
+                               d->adapter[i].active_fe != -1)
+                       usb_urb_submitv2(&d->adapter[i].stream, NULL);
+       }
+
+       /* start remote controller poll */
+       if (d->rc.query && !d->rc.bulk_mode)
+               schedule_delayed_work(&d->rc_query_work,
+                               msecs_to_jiffies(d->rc.interval));
+
+       return 0;
+}
+EXPORT_SYMBOL(dvb_usbv2_resume);
+
+MODULE_VERSION("2.0");
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("DVB USB common");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb-v2/dvb_usb_urb.c b/drivers/media/dvb/dvb-usb-v2/dvb_usb_urb.c
new file mode 100644 (file)
index 0000000..5f5bdd0
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * DVB USB framework
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher <patrick.boettcher@desy.de>
+ * Copyright (C) 2012 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "dvb_usb_common.h"
+
+#undef DVB_USB_XFER_DEBUG
+int dvb_usbv2_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf,
+               u16 rlen)
+{
+       int ret, actual_length;
+
+       if (!d || !wbuf || !wlen || !d->props->generic_bulk_ctrl_endpoint ||
+                       !d->props->generic_bulk_ctrl_endpoint_response) {
+               dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, -EINVAL);
+               return -EINVAL;
+       }
+
+       ret = mutex_lock_interruptible(&d->usb_mutex);
+       if (ret < 0)
+               return ret;
+
+#ifdef DVB_USB_XFER_DEBUG
+       print_hex_dump(KERN_DEBUG, KBUILD_MODNAME ": >>> ", DUMP_PREFIX_NONE,
+                       32, 1, wbuf, wlen, 0);
+#endif
+       ret = usb_bulk_msg(d->udev, usb_sndbulkpipe(d->udev,
+                       d->props->generic_bulk_ctrl_endpoint), wbuf, wlen,
+                       &actual_length, 2000);
+       if (ret < 0)
+               dev_err(&d->udev->dev, "%s: usb_bulk_msg() failed=%d\n",
+                               KBUILD_MODNAME, ret);
+       else
+               ret = actual_length != wlen ? -EIO : 0;
+
+       /* an answer is expected, and no error before */
+       if (!ret && rbuf && rlen) {
+               if (d->props->generic_bulk_ctrl_delay)
+                       usleep_range(d->props->generic_bulk_ctrl_delay,
+                                       d->props->generic_bulk_ctrl_delay
+                                       + 20000);
+
+               ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev,
+                               d->props->generic_bulk_ctrl_endpoint_response),
+                               rbuf, rlen, &actual_length, 2000);
+               if (ret)
+                       dev_err(&d->udev->dev, "%s: 2nd usb_bulk_msg() " \
+                                       "failed=%d\n", KBUILD_MODNAME, ret);
+
+#ifdef DVB_USB_XFER_DEBUG
+               print_hex_dump(KERN_DEBUG, KBUILD_MODNAME ": <<< ",
+                               DUMP_PREFIX_NONE, 32, 1, rbuf, actual_length,
+                               0);
+#endif
+       }
+
+       mutex_unlock(&d->usb_mutex);
+       return ret;
+}
+EXPORT_SYMBOL(dvb_usbv2_generic_rw);
+
+int dvb_usbv2_generic_write(struct dvb_usb_device *d, u8 *buf, u16 len)
+{
+       return dvb_usbv2_generic_rw(d, buf, len, NULL, 0);
+}
+EXPORT_SYMBOL(dvb_usbv2_generic_write);
similarity index 58%
rename from drivers/media/dvb/dvb-usb/ec168.c
rename to drivers/media/dvb/dvb-usb-v2/ec168.c
index b4989ba8897d5fd5dbea9e55c3786b4a07fd2446..ab77622c383dff9cd1af86338c61cefaa9689956 100644 (file)
 #include "ec100.h"
 #include "mxl5005s.h"
 
-/* debug */
-static int dvb_usb_ec168_debug;
-module_param_named(debug, dvb_usb_ec168_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
-static struct ec100_config ec168_ec100_config;
-
-static int ec168_rw_udev(struct usb_device *udev, struct ec168_req *req)
+static int ec168_ctrl_msg(struct dvb_usb_device *d, struct ec168_req *req)
 {
        int ret;
        unsigned int pipe;
        u8 request, requesttype;
        u8 *buf;
 
-
-
        switch (req->cmd) {
        case DOWNLOAD_FIRMWARE:
        case GPIO:
@@ -69,8 +61,8 @@ static int ec168_rw_udev(struct usb_device *udev, struct ec168_req *req)
                request = DEMOD_RW;
                break;
        default:
-               err("unknown command:%02x", req->cmd);
-               ret = -EPERM;
+               pr_err("%s: unknown command=%02x\n", KBUILD_MODNAME, req->cmd);
+               ret = -EINVAL;
                goto error;
        }
 
@@ -83,19 +75,19 @@ static int ec168_rw_udev(struct usb_device *udev, struct ec168_req *req)
        if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) {
                /* write */
                memcpy(buf, req->data, req->size);
-               pipe = usb_sndctrlpipe(udev, 0);
+               pipe = usb_sndctrlpipe(d->udev, 0);
        } else {
                /* read */
-               pipe = usb_rcvctrlpipe(udev, 0);
+               pipe = usb_rcvctrlpipe(d->udev, 0);
        }
 
        msleep(1); /* avoid I2C errors */
 
-       ret = usb_control_msg(udev, pipe, request, requesttype, req->value,
+       ret = usb_control_msg(d->udev, pipe, request, requesttype, req->value,
                req->index, buf, req->size, EC168_USB_TIMEOUT);
 
        ec168_debug_dump(request, requesttype, req->value, req->index, buf,
-               req->size, deb_xfer);
+               req->size);
 
        if (ret < 0)
                goto err_dealloc;
@@ -112,16 +104,13 @@ static int ec168_rw_udev(struct usb_device *udev, struct ec168_req *req)
 err_dealloc:
        kfree(buf);
 error:
-       deb_info("%s: failed:%d\n", __func__, ret);
+       pr_debug("%s: failed=%d\n", __func__, ret);
        return ret;
 }
 
-static int ec168_ctrl_msg(struct dvb_usb_device *d, struct ec168_req *req)
-{
-       return ec168_rw_udev(d->udev, req);
-}
-
 /* I2C */
+static struct ec100_config ec168_ec100_config;
+
 static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
        int num)
 {
@@ -147,8 +136,9 @@ static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                                ret = ec168_ctrl_msg(d, &req);
                                i += 2;
                        } else {
-                               err("I2C read not implemented");
-                               ret = -ENOSYS;
+                               pr_err("%s: I2C read not implemented\n",
+                                               KBUILD_MODNAME);
+                               ret = -EOPNOTSUPP;
                                i += 2;
                        }
                } else {
@@ -181,7 +171,6 @@ error:
        return i;
 }
 
-
 static u32 ec168_i2c_func(struct i2c_adapter *adapter)
 {
        return I2C_FUNC_I2C;
@@ -193,88 +182,62 @@ static struct i2c_algorithm ec168_i2c_algo = {
 };
 
 /* Callbacks for DVB USB */
-static struct ec100_config ec168_ec100_config = {
-       .demod_address = 0xff, /* not real address, demod is integrated */
-};
-
-static int ec168_ec100_frontend_attach(struct dvb_usb_adapter *adap)
+static int ec168_identify_state(struct dvb_usb_device *d, const char **name)
 {
-       deb_info("%s:\n", __func__);
-       adap->fe_adap[0].fe = dvb_attach(ec100_attach, &ec168_ec100_config,
-               &adap->dev->i2c_adap);
-       if (adap->fe_adap[0].fe == NULL)
-               return -ENODEV;
+       int ret;
+       u8 reply;
+       struct ec168_req req = {GET_CONFIG, 0, 1, sizeof(reply), &reply};
+       pr_debug("%s:\n", __func__);
 
-       return 0;
-}
+       ret = ec168_ctrl_msg(d, &req);
+       if (ret)
+               goto error;
 
-static struct mxl5005s_config ec168_mxl5003s_config = {
-       .i2c_address     = 0xc6,
-       .if_freq         = IF_FREQ_4570000HZ,
-       .xtal_freq       = CRYSTAL_FREQ_16000000HZ,
-       .agc_mode        = MXL_SINGLE_AGC,
-       .tracking_filter = MXL_TF_OFF,
-       .rssi_enable     = MXL_RSSI_ENABLE,
-       .cap_select      = MXL_CAP_SEL_ENABLE,
-       .div_out         = MXL_DIV_OUT_4,
-       .clock_out       = MXL_CLOCK_OUT_DISABLE,
-       .output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
-       .top             = MXL5005S_TOP_25P2,
-       .mod_mode        = MXL_DIGITAL_MODE,
-       .if_mode         = MXL_ZERO_IF,
-       .AgcMasterByte   = 0x00,
-};
+       pr_debug("%s: reply=%02x\n", __func__, reply);
 
-static int ec168_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
-{
-       deb_info("%s:\n", __func__);
-       return dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap,
-               &ec168_mxl5003s_config) == NULL ? -ENODEV : 0;
-}
+       if (reply == 0x01)
+               ret = WARM;
+       else
+               ret = COLD;
 
-static int ec168_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
-       struct ec168_req req = {STREAMING_CTRL, 0x7f01, 0x0202, 0, NULL};
-       deb_info("%s: onoff:%d\n", __func__, onoff);
-       if (onoff)
-               req.index = 0x0102;
-       return ec168_ctrl_msg(adap->dev, &req);
+       return ret;
+error:
+       pr_debug("%s: failed=%d\n", __func__, ret);
+       return ret;
 }
 
-static int ec168_download_firmware(struct usb_device *udev,
-       const struct firmware *fw)
+static int ec168_download_firmware(struct dvb_usb_device *d,
+               const struct firmware *fw)
 {
-       int i, len, packets, remainder, ret;
-       u16 addr = 0x0000; /* firmware start address */
+       int ret, len, remaining;
        struct ec168_req req = {DOWNLOAD_FIRMWARE, 0, 0, 0, NULL};
-       deb_info("%s:\n", __func__);
+       pr_debug("%s:\n", __func__);
 
-       #define FW_PACKET_MAX_DATA  2048
-       packets = fw->size / FW_PACKET_MAX_DATA;
-       remainder = fw->size % FW_PACKET_MAX_DATA;
-       len = FW_PACKET_MAX_DATA;
-       for (i = 0; i <= packets; i++) {
-               if (i == packets)  /* set size of the last packet */
-                       len = remainder;
+       #define LEN_MAX 2048 /* max packet size */
+       for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) {
+               len = remaining;
+               if (len > LEN_MAX)
+                       len = LEN_MAX;
 
                req.size = len;
-               req.data = (u8 *)(fw->data + i * FW_PACKET_MAX_DATA);
-               req.index = addr;
-               addr += FW_PACKET_MAX_DATA;
+               req.data = (u8 *) &fw->data[fw->size - remaining];
+               req.index = fw->size - remaining;
 
-               ret = ec168_rw_udev(udev, &req);
+               ret = ec168_ctrl_msg(d, &req);
                if (ret) {
-                       err("firmware download failed:%d packet:%d", ret, i);
+                       pr_err("%s: firmware download failed=%d\n",
+                                       KBUILD_MODNAME, ret);
                        goto error;
                }
        }
+
        req.size = 0;
 
        /* set "warm"? */
        req.cmd = SET_CONFIG;
        req.value = 0;
        req.index = 0x0001;
-       ret = ec168_rw_udev(udev, &req);
+       ret = ec168_ctrl_msg(d, &req);
        if (ret)
                goto error;
 
@@ -282,7 +245,7 @@ static int ec168_download_firmware(struct usb_device *udev,
        req.cmd = GPIO;
        req.value = 0;
        req.index = 0x0206;
-       ret = ec168_rw_udev(udev, &req);
+       ret = ec168_ctrl_msg(d, &req);
        if (ret)
                goto error;
 
@@ -290,146 +253,124 @@ static int ec168_download_firmware(struct usb_device *udev,
        req.cmd = WRITE_I2C;
        req.value = 0;
        req.index = 0x00c6;
-       ret = ec168_rw_udev(udev, &req);
+       ret = ec168_ctrl_msg(d, &req);
        if (ret)
                goto error;
 
        return ret;
 error:
-       deb_info("%s: failed:%d\n", __func__, ret);
+       pr_debug("%s: failed=%d\n", __func__, ret);
        return ret;
 }
 
-static int ec168_identify_state(struct usb_device *udev,
-       struct dvb_usb_device_properties *props,
-       struct dvb_usb_device_description **desc, int *cold)
-{
-       int ret;
-       u8 reply;
-       struct ec168_req req = {GET_CONFIG, 0, 1, sizeof(reply), &reply};
-       deb_info("%s:\n", __func__);
-
-       ret = ec168_rw_udev(udev, &req);
-       if (ret)
-               goto error;
-
-       deb_info("%s: reply:%02x\n", __func__, reply);
+static struct ec100_config ec168_ec100_config = {
+       .demod_address = 0xff, /* not real address, demod is integrated */
+};
 
-       if (reply == 0x01)
-               *cold = 0;
-       else
-               *cold = 1;
+static int ec168_ec100_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       pr_debug("%s:\n", __func__);
+       adap->fe[0] = dvb_attach(ec100_attach, &ec168_ec100_config,
+                       &adap_to_d(adap)->i2c_adap);
+       if (adap->fe[0] == NULL)
+               return -ENODEV;
 
-       return ret;
-error:
-       deb_info("%s: failed:%d\n", __func__, ret);
-       return ret;
+       return 0;
 }
 
-/* DVB USB Driver stuff */
-static struct dvb_usb_device_properties ec168_properties;
+static struct mxl5005s_config ec168_mxl5003s_config = {
+       .i2c_address     = 0xc6,
+       .if_freq         = IF_FREQ_4570000HZ,
+       .xtal_freq       = CRYSTAL_FREQ_16000000HZ,
+       .agc_mode        = MXL_SINGLE_AGC,
+       .tracking_filter = MXL_TF_OFF,
+       .rssi_enable     = MXL_RSSI_ENABLE,
+       .cap_select      = MXL_CAP_SEL_ENABLE,
+       .div_out         = MXL_DIV_OUT_4,
+       .clock_out       = MXL_CLOCK_OUT_DISABLE,
+       .output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
+       .top             = MXL5005S_TOP_25P2,
+       .mod_mode        = MXL_DIGITAL_MODE,
+       .if_mode         = MXL_ZERO_IF,
+       .AgcMasterByte   = 0x00,
+};
 
-static int ec168_probe(struct usb_interface *intf,
-       const struct usb_device_id *id)
+static int ec168_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
 {
-       int ret;
-       deb_info("%s: interface:%d\n", __func__,
-               intf->cur_altsetting->desc.bInterfaceNumber);
-
-       ret = dvb_usb_device_init(intf, &ec168_properties, THIS_MODULE, NULL,
-               adapter_nr);
-       if (ret)
-               goto error;
-
-       return ret;
-error:
-       deb_info("%s: failed:%d\n", __func__, ret);
-       return ret;
+       pr_debug("%s:\n", __func__);
+       return dvb_attach(mxl5005s_attach, adap->fe[0],
+                       &adap_to_d(adap)->i2c_adap,
+                       &ec168_mxl5003s_config) == NULL ? -ENODEV : 0;
 }
 
-#define E3C_EC168_1689                          0
-#define E3C_EC168_FFFA                          1
-#define E3C_EC168_FFFB                          2
-#define E3C_EC168_1001                          3
-#define E3C_EC168_1002                          4
-
-static struct usb_device_id ec168_id[] = {
-       [E3C_EC168_1689] =
-               {USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168)},
-       [E3C_EC168_FFFA] =
-               {USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_2)},
-       [E3C_EC168_FFFB] =
-               {USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_3)},
-       [E3C_EC168_1001] =
-               {USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_4)},
-       [E3C_EC168_1002] =
-               {USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_5)},
-       {} /* terminating entry */
-};
-
-MODULE_DEVICE_TABLE(usb, ec168_id);
+static int ec168_streaming_ctrl(struct dvb_frontend *fe, int onoff)
+{
+       struct ec168_req req = {STREAMING_CTRL, 0x7f01, 0x0202, 0, NULL};
+       pr_debug("%s: onoff=%d\n", __func__, onoff);
+       if (onoff)
+               req.index = 0x0102;
+       return ec168_ctrl_msg(fe_to_d(fe), &req);
+}
 
-static struct dvb_usb_device_properties ec168_properties = {
-       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+/* DVB USB Driver stuff */
+/* bInterfaceNumber 0 is HID
+ * bInterfaceNumber 1 is DVB-T */
+static struct dvb_usb_device_properties ec168_props = {
+       .driver_name = KBUILD_MODNAME,
+       .owner = THIS_MODULE,
+       .adapter_nr = adapter_nr,
+       .bInterfaceNumber = 1,
 
-       .usb_ctrl = DEVICE_SPECIFIC,
-       .download_firmware = ec168_download_firmware,
+       .identify_state = ec168_identify_state,
        .firmware = "dvb-usb-ec168.fw",
-       .no_reconnect = 1,
+       .download_firmware = ec168_download_firmware,
 
-       .size_of_priv = 0,
+       .i2c_algo = &ec168_i2c_algo,
+       .frontend_attach = ec168_ec100_frontend_attach,
+       .tuner_attach = ec168_mxl5003s_tuner_attach,
+       .streaming_ctrl = ec168_streaming_ctrl,
 
        .num_adapters = 1,
        .adapter = {
                {
-               .num_frontends = 1,
-               .fe = {{
-                       .streaming_ctrl   = ec168_streaming_ctrl,
-                       .frontend_attach  = ec168_ec100_frontend_attach,
-                       .tuner_attach     = ec168_mxl5003s_tuner_attach,
-                       .stream = {
-                               .type = USB_BULK,
-                               .count = 6,
-                               .endpoint = 0x82,
-                               .u = {
-                                       .bulk = {
-                                               .buffersize = (32*512),
-                                       }
-                               }
-                       },
-               }},
+                       .stream = DVB_USB_STREAM_BULK(0x82, 6, 32 * 512),
                }
        },
+};
 
-       .identify_state = ec168_identify_state,
-
-       .i2c_algo = &ec168_i2c_algo,
+static const struct dvb_usb_driver_info ec168_driver_info = {
+       .name = "E3C EC168 reference design",
+       .props = &ec168_props,
+};
 
-       .num_device_descs = 1,
-       .devices = {
-               {
-                       .name = "E3C EC168 DVB-T USB2.0 reference design",
-                       .cold_ids = {
-                               &ec168_id[E3C_EC168_1689],
-                               &ec168_id[E3C_EC168_FFFA],
-                               &ec168_id[E3C_EC168_FFFB],
-                               &ec168_id[E3C_EC168_1001],
-                               &ec168_id[E3C_EC168_1002],
-                               NULL},
-                       .warm_ids = {NULL},
-               },
-       }
+static const struct usb_device_id ec168_id[] = {
+       { USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168),
+               .driver_info = (kernel_ulong_t) &ec168_driver_info },
+       { USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_2),
+               .driver_info = (kernel_ulong_t) &ec168_driver_info },
+       { USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_3),
+               .driver_info = (kernel_ulong_t) &ec168_driver_info },
+       { USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_4),
+               .driver_info = (kernel_ulong_t) &ec168_driver_info },
+       { USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_5),
+               .driver_info = (kernel_ulong_t) &ec168_driver_info },
+       {}
 };
+MODULE_DEVICE_TABLE(usb, ec168_id);
 
 static struct usb_driver ec168_driver = {
-       .name       = "dvb_usb_ec168",
-       .probe      = ec168_probe,
-       .disconnect = dvb_usb_device_exit,
-       .id_table   = ec168_id,
+       .name = KBUILD_MODNAME,
+       .id_table = ec168_id,
+       .probe = dvb_usbv2_probe,
+       .disconnect = dvb_usbv2_disconnect,
+       .suspend = dvb_usbv2_suspend,
+       .resume = dvb_usbv2_resume,
+       .no_dynamic_id = 1,
+       .soft_unbind = 1,
 };
 
 module_usb_driver(ec168_driver);
 
 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_DESCRIPTION("E3C EC168 DVB-T USB2.0 driver");
+MODULE_DESCRIPTION("E3C EC168 driver");
 MODULE_LICENSE("GPL");
similarity index 65%
rename from drivers/media/dvb/dvb-usb/ec168.h
rename to drivers/media/dvb/dvb-usb-v2/ec168.h
index e7e0b831314eeec4c42334f074ce87311d846eab..9181236f6ebccea81d95b7c4f2eb6c6775df0e89 100644 (file)
 #ifndef EC168_H
 #define EC168_H
 
-#define DVB_USB_LOG_PREFIX "ec168"
-#include "dvb-usb.h"
+#include "dvb_usb.h"
 
-#define deb_info(args...) dprintk(dvb_usb_ec168_debug, 0x01, args)
-#define deb_rc(args...)   dprintk(dvb_usb_ec168_debug, 0x02, args)
-#define deb_xfer(args...) dprintk(dvb_usb_ec168_debug, 0x04, args)
-#define deb_reg(args...)  dprintk(dvb_usb_ec168_debug, 0x08, args)
-#define deb_i2c(args...)  dprintk(dvb_usb_ec168_debug, 0x10, args)
-#define deb_fw(args...)   dprintk(dvb_usb_ec168_debug, 0x20, args)
-
-#define ec168_debug_dump(r, t, v, i, b, l, func) { \
-       int loop_; \
-       func("%02x %02x %02x %02x %02x %02x %02x %02x", \
-               t, r, v & 0xff, v >> 8, i & 0xff, i >> 8, l & 0xff, l >> 8); \
+#define ec168_debug_dump(r, t, v, i, b, l) { \
+       char *direction; \
        if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \
-               func(" >>> "); \
+               direction = ">>>"; \
        else \
-               func(" <<< "); \
-       for (loop_ = 0; loop_ < l; loop_++) \
-               func("%02x ", b[loop_]); \
-       func("\n");\
+               direction = "<<<"; \
+       pr_debug("%s: %02x %02x %02x %02x %02x %02x %02x %02x %s\n", \
+                        __func__, t, r, v & 0xff, v >> 8, i & 0xff, i >> 8, \
+                       l & 0xff, l >> 8, direction); \
 }
 
 #define EC168_USB_TIMEOUT 1000
similarity index 54%
rename from drivers/media/dvb/dvb-usb/gl861.c
rename to drivers/media/dvb/dvb-usb-v2/gl861.c
index c1f5582e1cdfd3923d7fd816c22d0ce252d3c17e..cf29f43e35984ee15033cf4ad57331067c1c6f6c 100644 (file)
 #include "zl10353.h"
 #include "qt1010.h"
 
-/* debug */
-static int dvb_usb_gl861_debug;
-module_param_named(debug, dvb_usb_gl861_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))."
-       DVB_USB_DEBUG_STATUS);
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr,
@@ -43,7 +38,7 @@ static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr,
                value = value + wbuf[1];
                break;
        default:
-               warn("wlen = %x, aborting.", wlen);
+               pr_err("%s: wlen=%d, aborting\n", KBUILD_MODNAME, wlen);
                return -EINVAL;
        }
 
@@ -103,9 +98,9 @@ static struct zl10353_config gl861_zl10353_config = {
 static int gl861_frontend_attach(struct dvb_usb_adapter *adap)
 {
 
-       adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &gl861_zl10353_config,
-               &adap->dev->i2c_adap);
-       if (adap->fe_adap[0].fe == NULL)
+       adap->fe[0] = dvb_attach(zl10353_attach, &gl861_zl10353_config,
+               &adap_to_d(adap)->i2c_adap);
+       if (adap->fe[0] == NULL)
                return -EIO;
 
        return 0;
@@ -118,98 +113,61 @@ static struct qt1010_config gl861_qt1010_config = {
 static int gl861_tuner_attach(struct dvb_usb_adapter *adap)
 {
        return dvb_attach(qt1010_attach,
-                         adap->fe_adap[0].fe, &adap->dev->i2c_adap,
+                         adap->fe[0], &adap_to_d(adap)->i2c_adap,
                          &gl861_qt1010_config) == NULL ? -ENODEV : 0;
 }
 
-/* DVB USB Driver stuff */
-static struct dvb_usb_device_properties gl861_properties;
-
-static int gl861_probe(struct usb_interface *intf,
-                      const struct usb_device_id *id)
+static int gl861_init(struct dvb_usb_device *d)
 {
-       struct dvb_usb_device *d;
-       struct usb_host_interface *alt;
-       int ret;
-
-       if (intf->num_altsetting < 2)
-               return -ENODEV;
-
-       ret = dvb_usb_device_init(intf, &gl861_properties, THIS_MODULE, &d,
-                                 adapter_nr);
-       if (ret == 0) {
-               alt = usb_altnum_to_altsetting(intf, 0);
-
-               if (alt == NULL) {
-                       deb_rc("not alt found!\n");
-                       return -ENODEV;
-               }
-
-               ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
-                                       alt->desc.bAlternateSetting);
-       }
-
-       return ret;
+       /*
+        * There is 2 interfaces. Interface 0 is for TV and interface 1 is
+        * for HID remote controller. Interface 0 has 2 alternate settings.
+        * For some reason we need to set interface explicitly, defaulted
+        * as alternate setting 1?
+        */
+       return usb_set_interface(d->udev, 0, 0);
 }
 
-static struct usb_device_id gl861_table [] = {
-               { USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580_55801) },
-               { USB_DEVICE(USB_VID_ALINK, USB_VID_ALINK_DTU) },
-               { }             /* Terminating entry */
-};
-MODULE_DEVICE_TABLE(usb, gl861_table);
-
-static struct dvb_usb_device_properties gl861_properties = {
-       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
-       .usb_ctrl = DEVICE_SPECIFIC,
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties gl861_props = {
+       .driver_name = KBUILD_MODNAME,
+       .owner = THIS_MODULE,
+       .adapter_nr = adapter_nr,
 
-       .size_of_priv     = 0,
+       .i2c_algo = &gl861_i2c_algo,
+       .frontend_attach = gl861_frontend_attach,
+       .tuner_attach = gl861_tuner_attach,
+       .init = gl861_init,
 
        .num_adapters = 1,
-       .adapter = {{
-               .num_frontends = 1,
-               .fe = {{
-
-               .frontend_attach  = gl861_frontend_attach,
-               .tuner_attach     = gl861_tuner_attach,
-
-               .stream = {
-                       .type = USB_BULK,
-                       .count = 7,
-                       .endpoint = 0x81,
-                       .u = {
-                               .bulk = {
-                                       .buffersize = 512,
-                               }
-                       }
-               },
-               }},
-       } },
-       .i2c_algo         = &gl861_i2c_algo,
-
-       .num_device_descs = 2,
-       .devices = {
+       .adapter = {
                {
-                       .name = "MSI Mega Sky 55801 DVB-T USB2.0",
-                       .cold_ids = { NULL },
-                       .warm_ids = { &gl861_table[0], NULL },
-               },
-               {
-                       .name = "A-LINK DTU DVB-T USB2.0",
-                       .cold_ids = { NULL },
-                       .warm_ids = { &gl861_table[1], NULL },
-               },
+                       .stream = DVB_USB_STREAM_BULK(0x81, 7, 512),
+               }
        }
 };
 
-static struct usb_driver gl861_driver = {
-       .name           = "dvb_usb_gl861",
-       .probe          = gl861_probe,
-       .disconnect     = dvb_usb_device_exit,
-       .id_table       = gl861_table,
+static const struct usb_device_id gl861_id_table[] = {
+       { DVB_USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580_55801,
+               &gl861_props, "MSI Mega Sky 55801 DVB-T USB2.0", NULL) },
+       { DVB_USB_DEVICE(USB_VID_ALINK, USB_VID_ALINK_DTU,
+               &gl861_props, "A-LINK DTU DVB-T USB2.0", NULL) },
+       { }
+};
+MODULE_DEVICE_TABLE(usb, gl861_id_table);
+
+static struct usb_driver gl861_usb_driver = {
+       .name = KBUILD_MODNAME,
+       .id_table = gl861_id_table,
+       .probe = dvb_usbv2_probe,
+       .disconnect = dvb_usbv2_disconnect,
+       .suspend = dvb_usbv2_suspend,
+       .resume = dvb_usbv2_resume,
+       .no_dynamic_id = 1,
+       .soft_unbind = 1,
 };
 
-module_usb_driver(gl861_driver);
+module_usb_driver(gl861_usb_driver);
 
 MODULE_AUTHOR("Carl Lundqvist <comabug@gmail.com>");
 MODULE_DESCRIPTION("Driver MSI Mega Sky 580 DVB-T USB2.0 / GL861");
similarity index 59%
rename from drivers/media/dvb/dvb-usb/gl861.h
rename to drivers/media/dvb/dvb-usb-v2/gl861.h
index c54855e2c233f8ae007e30a31f2f57ecf5c6e32c..b0b80d87bb7e36f98a6e413d6f7c0e6cc63b77e0 100644 (file)
@@ -1,10 +1,7 @@
 #ifndef _DVB_USB_GL861_H_
 #define _DVB_USB_GL861_H_
 
-#define DVB_USB_LOG_PREFIX "gl861"
-#include "dvb-usb.h"
-
-#define deb_rc(args...)   dprintk(dvb_usb_gl861_debug, 0x01, args)
+#include "dvb_usb.h"
 
 #define GL861_WRITE            0x40
 #define GL861_READ             0xc0
similarity index 69%
rename from drivers/media/dvb/dvb-usb/lmedm04.c
rename to drivers/media/dvb/dvb-usb-v2/lmedm04.c
index 25d1031460f8071deaa2bd0e9a5e14879824fb37..c6bc1b8b58b8c84b6b8f610dc07c208571384680 100644 (file)
@@ -19,6 +19,8 @@
  *
  * MVB0194 (LME2510C+SHARP0194)
  *
+ * LME2510C + M88RS2000
+ *
  * For firmware see Documentation/dvb/lmedm04.txt
  *
  * I2C addresses:
  *     LME2510: SHARP:BS2F7HZ0194(MV0194) cannot cold reset and share system
  * with other tuners. After a cold reset streaming will not start.
  *
+ * M88RS2000 suffers from loss of lock.
  */
 #define DVB_USB_LOG_PREFIX "LME2510(C)"
 #include <linux/usb.h>
 #include <linux/usb/input.h>
 #include <media/rc-core.h>
 
-#include "dvb-usb.h"
+#include "dvb_usb.h"
 #include "lmedm04.h"
 #include "tda826x.h"
 #include "tda10086.h"
 #include "m88rs2000.h"
 
 
+#define LME2510_C_S7395        "dvb-usb-lme2510c-s7395.fw";
+#define LME2510_C_LG   "dvb-usb-lme2510c-lg.fw";
+#define LME2510_C_S0194        "dvb-usb-lme2510c-s0194.fw";
+#define LME2510_C_RS2000 "dvb-usb-lme2510c-rs2000.fw";
+#define LME2510_LG     "dvb-usb-lme2510-lg.fw";
+#define LME2510_S0194  "dvb-usb-lme2510-s0194.fw";
 
 /* debug */
 static int dvb_usb_lme2510_debug;
-#define l_dprintk(var, level, args...) do { \
+#define lme_debug(var, level, args...) do { \
        if ((var >= level)) \
-               printk(KERN_DEBUG DVB_USB_LOG_PREFIX ": " args); \
+               pr_debug(DVB_USB_LOG_PREFIX": " args); \
 } while (0)
-
-#define deb_info(level, args...) l_dprintk(dvb_usb_lme2510_debug, level, args)
+#define deb_info(level, args...) lme_debug(dvb_usb_lme2510_debug, level, args)
 #define debug_data_snipet(level, name, p) \
         deb_info(level, name" (%02x%02x%02x%02x%02x%02x%02x%02x)", \
                *p, *(p+1), *(p+2), *(p+3), *(p+4), \
                        *(p+5), *(p+6), *(p+7));
-
+#define info(args...) pr_info(DVB_USB_LOG_PREFIX": "args)
 
 module_param_named(debug, dvb_usb_lme2510_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."
-                       DVB_USB_DEBUG_STATUS);
+MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
 
 static int dvb_usb_lme2510_firmware;
 module_param_named(firmware, dvb_usb_lme2510_firmware, int, 0644);
@@ -136,7 +143,8 @@ struct lme2510_state {
        void *buffer;
        struct urb *lme_urb;
        void *usb_buffer;
-
+       int (*fe_set_voltage)(struct dvb_frontend *, fe_sec_voltage_t);
+       u8 dvb_usb_lme2510_firmware;
 };
 
 static int lme2510_bulk_write(struct usb_device *dev,
@@ -246,7 +254,7 @@ static int lme2510_enable_pid(struct dvb_usb_device *d, u8 index, u16 pid_out)
 static void lme2510_int_response(struct urb *lme_urb)
 {
        struct dvb_usb_adapter *adap = lme_urb->context;
-       struct lme2510_state *st = adap->dev->priv;
+       struct lme2510_state *st = adap_to_priv(adap);
        static u8 *ibuf, *rbuf;
        int i = 0, offset;
        u32 key;
@@ -283,8 +291,9 @@ static void lme2510_int_response(struct urb *lme_urb)
                                        ? (ibuf[3] ^ 0xff) << 8 : 0;
                                key += (ibuf[2] ^ 0xff) << 16;
                                deb_info(1, "INT Key =%08x", key);
-                               if (adap->dev->rc_dev != NULL)
-                                       rc_keydown(adap->dev->rc_dev, key, 0);
+                               if (adap_to_d(adap)->rc_dev != NULL)
+                                       rc_keydown(adap_to_d(adap)->rc_dev,
+                                               key, 0);
                        }
                        break;
                case 0xbb:
@@ -313,12 +322,12 @@ static void lme2510_int_response(struct urb *lme_urb)
                                }
                                break;
                        case TUNER_RS2000:
-                               if (ibuf[2] > 0)
+                               if (ibuf[1] == 0x3 &&  ibuf[6] == 0xff)
                                        st->signal_lock = 0xff;
                                else
-                                       st->signal_lock = 0xf0;
-                               st->signal_level = ibuf[4];
-                               st->signal_sn = ibuf[5];
+                                       st->signal_lock = 0x00;
+                               st->signal_level = ibuf[5];
+                               st->signal_sn = ibuf[4];
                                st->time_key = ibuf[7];
                        default:
                                break;
@@ -338,22 +347,23 @@ static void lme2510_int_response(struct urb *lme_urb)
 
 static int lme2510_int_read(struct dvb_usb_adapter *adap)
 {
-       struct lme2510_state *lme_int = adap->dev->priv;
+       struct dvb_usb_device *d = adap_to_d(adap);
+       struct lme2510_state *lme_int = adap_to_priv(adap);
 
        lme_int->lme_urb = usb_alloc_urb(0, GFP_ATOMIC);
 
        if (lme_int->lme_urb == NULL)
                        return -ENOMEM;
 
-       lme_int->buffer = usb_alloc_coherent(adap->dev->udev, 128, GFP_ATOMIC,
+       lme_int->buffer = usb_alloc_coherent(d->udev, 128, GFP_ATOMIC,
                                        &lme_int->lme_urb->transfer_dma);
 
        if (lme_int->buffer == NULL)
                        return -ENOMEM;
 
        usb_fill_int_urb(lme_int->lme_urb,
-                               adap->dev->udev,
-                               usb_rcvintpipe(adap->dev->udev, 0xa),
+                               d->udev,
+                               usb_rcvintpipe(d->udev, 0xa),
                                lme_int->buffer,
                                128,
                                lme2510_int_response,
@@ -370,17 +380,18 @@ static int lme2510_int_read(struct dvb_usb_adapter *adap)
 
 static int lme2510_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
 {
-       struct lme2510_state *st = adap->dev->priv;
+       struct dvb_usb_device *d = adap_to_d(adap);
+       struct lme2510_state *st = adap_to_priv(adap);
        static u8 clear_pid_reg[] = LME_ALL_PIDS;
        static u8 rbuf[1];
        int ret = 0;
 
        deb_info(1, "PID Clearing Filter");
 
-       mutex_lock(&adap->dev->i2c_mutex);
+       mutex_lock(&d->i2c_mutex);
 
        if (!onoff) {
-               ret |= lme2510_usb_talk(adap->dev, clear_pid_reg,
+               ret |= lme2510_usb_talk(d, clear_pid_reg,
                        sizeof(clear_pid_reg), rbuf, sizeof(rbuf));
                st->pid_off = true;
        } else
@@ -388,7 +399,7 @@ static int lme2510_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
 
        st->pid_size = 0;
 
-       mutex_unlock(&adap->dev->i2c_mutex);
+       mutex_unlock(&d->i2c_mutex);
 
        return 0;
 }
@@ -396,15 +407,16 @@ static int lme2510_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
 static int lme2510_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
        int onoff)
 {
+       struct dvb_usb_device *d = adap_to_d(adap);
        int ret = 0;
 
        deb_info(3, "%s PID=%04x Index=%04x onoff=%02x", __func__,
                pid, index, onoff);
 
        if (onoff) {
-               mutex_lock(&adap->dev->i2c_mutex);
-               ret |= lme2510_enable_pid(adap->dev, index, pid);
-               mutex_unlock(&adap->dev->i2c_mutex);
+               mutex_lock(&d->i2c_mutex);
+               ret |= lme2510_enable_pid(d, index, pid);
+               mutex_unlock(&d->i2c_mutex);
        }
 
 
@@ -412,7 +424,7 @@ static int lme2510_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
 }
 
 
-static int lme2510_return_status(struct usb_device *dev)
+static int lme2510_return_status(struct dvb_usb_device *d)
 {
        int ret = 0;
        u8 *data;
@@ -421,7 +433,7 @@ static int lme2510_return_status(struct usb_device *dev)
        if (!data)
                return -ENOMEM;
 
-       ret |= usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+       ret |= usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
                        0x06, 0x80, 0x0302, 0x00, data, 0x0006, 200);
        info("Firmware Status: %x (%x)", ret , data[2]);
 
@@ -613,10 +625,6 @@ static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
        if (gate == 0)
                gate = 5;
 
-       if (num > 2)
-               warn("more than 2 i2c messages"
-                       "at a time is not handled yet.  TODO.");
-
        for (i = 0; i < num; i++) {
                read_o = 1 & (msg[i].flags & I2C_M_RD);
                read = i+1 < num && (msg[i+1].flags & I2C_M_RD);
@@ -676,22 +684,11 @@ static struct i2c_algorithm lme2510_i2c_algo = {
        .functionality = lme2510_i2c_func,
 };
 
-/* Callbacks for DVB USB */
-static int lme2510_identify_state(struct usb_device *udev,
-               struct dvb_usb_device_properties *props,
-               struct dvb_usb_device_description **desc,
-               int *cold)
+static int lme2510_streaming_ctrl(struct dvb_frontend *fe, int onoff)
 {
-       if (pid_filter != 2)
-               props->adapter[0].fe[0].caps &=
-                       ~DVB_USB_ADAP_NEED_PID_FILTERING;
-       *cold = 0;
-       return 0;
-}
-
-static int lme2510_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
-       struct lme2510_state *st = adap->dev->priv;
+       struct dvb_usb_adapter *adap = fe_to_adap(fe);
+       struct dvb_usb_device *d = adap_to_d(adap);
+       struct lme2510_state *st = adap_to_priv(adap);
        static u8 clear_reg_3[] = LME_ALL_PIDS;
        static u8 rbuf[1];
        int ret = 0, rlen = sizeof(rbuf);
@@ -704,14 +701,14 @@ static int lme2510_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
        else {
                deb_info(1, "STM Steam Off");
                /* mutex is here only to avoid collision with I2C */
-               mutex_lock(&adap->dev->i2c_mutex);
+               mutex_lock(&d->i2c_mutex);
 
-               ret = lme2510_usb_talk(adap->dev, clear_reg_3,
+               ret = lme2510_usb_talk(d, clear_reg_3,
                                sizeof(clear_reg_3), rbuf, rlen);
                st->stream_on = 0;
                st->i2c_talk_onoff = 1;
 
-               mutex_unlock(&adap->dev->i2c_mutex);
+               mutex_unlock(&d->i2c_mutex);
        }
 
        return (ret < 0) ? -ENODEV : 0;
@@ -725,7 +722,7 @@ static u8 check_sum(u8 *p, u8 len)
        return sum;
 }
 
-static int lme2510_download_firmware(struct usb_device *dev,
+static int lme2510_download_firmware(struct dvb_usb_device *d,
                                        const struct firmware *fw)
 {
        int ret = 0;
@@ -737,9 +734,10 @@ static int lme2510_download_firmware(struct usb_device *dev,
        packet_size = 0x31;
        len_in = 1;
 
-       data = kzalloc(512, GFP_KERNEL);
+       data = kzalloc(128, GFP_KERNEL);
        if (!data) {
-               info("FRM Could not start Firmware Download (Buffer allocation failed)");
+               info("FRM Could not start Firmware Download"\
+                       "(Buffer allocation failed)");
                return -ENOMEM;
        }
 
@@ -763,21 +761,19 @@ static int lme2510_download_firmware(struct usb_device *dev,
                        data[wlen-1] = check_sum(fw_data, dlen+1);
                        deb_info(1, "Data S=%02x:E=%02x CS= %02x", data[3],
                                data[dlen+2], data[dlen+3]);
-                       ret |= lme2510_bulk_write(dev, data,  wlen, 1);
-                       ret |= lme2510_bulk_read(dev, data, len_in , 1);
+                       lme2510_usb_talk(d, data, wlen, data, len_in);
                        ret |= (data[0] == 0x88) ? 0 : -1;
                }
        }
 
-       usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+       usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
                        0x06, 0x80, 0x0200, 0x00, data, 0x0109, 1000);
 
 
        data[0] = 0x8a;
        len_in = 1;
        msleep(2000);
-       ret |= lme2510_bulk_write(dev, data , len_in, 1); /*Resetting*/
-       ret |= lme2510_bulk_read(dev, data, len_in, 1);
+       lme2510_usb_talk(d, data, len_in, data, len_in);
        msleep(400);
 
        if (ret < 0)
@@ -786,44 +782,42 @@ static int lme2510_download_firmware(struct usb_device *dev,
                info("FRM Firmware Download Completed - Resetting Device");
 
        kfree(data);
-       return (ret < 0) ? -ENODEV : 0;
+       return RECONNECTS_USB;
 }
 
-static void lme_coldreset(struct usb_device *dev)
+static void lme_coldreset(struct dvb_usb_device *d)
 {
-       int ret = 0, len_in;
-       u8 data[512] = {0};
-
+       u8 data[1] = {0};
        data[0] = 0x0a;
-       len_in = 1;
        info("FRM Firmware Cold Reset");
-       ret |= lme2510_bulk_write(dev, data , len_in, 1); /*Cold Resetting*/
-       ret |= lme2510_bulk_read(dev, data, len_in, 1);
+
+       lme2510_usb_talk(d, data, sizeof(data), data, sizeof(data));
 
        return;
 }
 
-static int lme_firmware_switch(struct usb_device *udev, int cold)
+static const char fw_c_s7395[] = LME2510_C_S7395;
+static const char fw_c_lg[] = LME2510_C_LG;
+static const char fw_c_s0194[] = LME2510_C_S0194;
+static const char fw_c_rs2000[] = LME2510_C_RS2000;
+static const char fw_lg[] = LME2510_LG;
+static const char fw_s0194[] = LME2510_S0194;
+
+const char *lme_firmware_switch(struct dvb_usb_device *d, int cold)
 {
+       struct lme2510_state *st = d->priv;
+       struct usb_device *udev = d->udev;
        const struct firmware *fw = NULL;
-       const char fw_c_s7395[] = "dvb-usb-lme2510c-s7395.fw";
-       const char fw_c_lg[] = "dvb-usb-lme2510c-lg.fw";
-       const char fw_c_s0194[] = "dvb-usb-lme2510c-s0194.fw";
-       const char fw_c_rs2000[] = "dvb-usb-lme2510c-rs2000.fw";
-       const char fw_lg[] = "dvb-usb-lme2510-lg.fw";
-       const char fw_s0194[] = "dvb-usb-lme2510-s0194.fw";
        const char *fw_lme;
-       int ret = 0, cold_fw;
+       int ret = 0;
 
        cold = (cold > 0) ? (cold & 1) : 0;
 
-       cold_fw = !cold;
-
        switch (le16_to_cpu(udev->descriptor.idProduct)) {
        case 0x1122:
-               switch (dvb_usb_lme2510_firmware) {
+               switch (st->dvb_usb_lme2510_firmware) {
                default:
-                       dvb_usb_lme2510_firmware = TUNER_S0194;
+                       st->dvb_usb_lme2510_firmware = TUNER_S0194;
                case TUNER_S0194:
                        fw_lme = fw_s0194;
                        ret = request_firmware(&fw, fw_lme, &udev->dev);
@@ -831,23 +825,20 @@ static int lme_firmware_switch(struct usb_device *udev, int cold)
                                cold = 0;
                                break;
                        }
-                       dvb_usb_lme2510_firmware = TUNER_LG;
+                       st->dvb_usb_lme2510_firmware = TUNER_LG;
                case TUNER_LG:
                        fw_lme = fw_lg;
                        ret = request_firmware(&fw, fw_lme, &udev->dev);
                        if (ret == 0)
                                break;
-                       info("FRM No Firmware Found - please install");
-                       dvb_usb_lme2510_firmware = TUNER_DEFAULT;
-                       cold = 0;
-                       cold_fw = 0;
+                       st->dvb_usb_lme2510_firmware = TUNER_DEFAULT;
                        break;
                }
                break;
        case 0x1120:
-               switch (dvb_usb_lme2510_firmware) {
+               switch (st->dvb_usb_lme2510_firmware) {
                default:
-                       dvb_usb_lme2510_firmware = TUNER_S7395;
+                       st->dvb_usb_lme2510_firmware = TUNER_S7395;
                case TUNER_S7395:
                        fw_lme = fw_c_s7395;
                        ret = request_firmware(&fw, fw_lme, &udev->dev);
@@ -855,49 +846,41 @@ static int lme_firmware_switch(struct usb_device *udev, int cold)
                                cold = 0;
                                break;
                        }
-                       dvb_usb_lme2510_firmware = TUNER_LG;
+                       st->dvb_usb_lme2510_firmware = TUNER_LG;
                case TUNER_LG:
                        fw_lme = fw_c_lg;
                        ret = request_firmware(&fw, fw_lme, &udev->dev);
                        if (ret == 0)
                                break;
-                       dvb_usb_lme2510_firmware = TUNER_S0194;
+                       st->dvb_usb_lme2510_firmware = TUNER_S0194;
                case TUNER_S0194:
                        fw_lme = fw_c_s0194;
                        ret = request_firmware(&fw, fw_lme, &udev->dev);
                        if (ret == 0)
                                break;
-                       info("FRM No Firmware Found - please install");
-                       dvb_usb_lme2510_firmware = TUNER_DEFAULT;
+                       st->dvb_usb_lme2510_firmware = TUNER_DEFAULT;
                        cold = 0;
-                       cold_fw = 0;
                        break;
                }
                break;
        case 0x22f0:
                fw_lme = fw_c_rs2000;
-               ret = request_firmware(&fw, fw_lme, &udev->dev);
-               dvb_usb_lme2510_firmware = TUNER_RS2000;
+               st->dvb_usb_lme2510_firmware = TUNER_RS2000;
                break;
        default:
                fw_lme = fw_c_s7395;
        }
 
-
-       if (cold_fw) {
-               info("FRM Loading %s file", fw_lme);
-               ret = lme2510_download_firmware(udev, fw);
-       }
-
        release_firmware(fw);
 
        if (cold) {
+               dvb_usb_lme2510_firmware = st->dvb_usb_lme2510_firmware;
                info("FRM Changing to %s firmware", fw_lme);
-               lme_coldreset(udev);
-               return -ENODEV;
+               lme_coldreset(d);
+               return NULL;
        }
 
-       return ret;
+       return fw_lme;
 }
 
 static int lme2510_kill_urb(struct usb_data_stream *stream)
@@ -949,8 +932,8 @@ static struct stv0299_config sharp_z0194_config = {
 static int dm04_rs2000_set_ts_param(struct dvb_frontend *fe,
        int caller)
 {
-       struct dvb_usb_adapter *adap = fe->dvb->priv;
-       struct dvb_usb_device *d = adap->dev;
+       struct dvb_usb_adapter *adap = fe_to_adap(fe);
+       struct dvb_usb_device *d = adap_to_d(adap);
        struct lme2510_state *st = d->priv;
 
        mutex_lock(&d->i2c_mutex);
@@ -972,29 +955,35 @@ static struct m88rs2000_config m88rs2000_config = {
 static int dm04_lme2510_set_voltage(struct dvb_frontend *fe,
                                        fe_sec_voltage_t voltage)
 {
-       struct dvb_usb_adapter *adap = fe->dvb->priv;
-       static u8 voltage_low[] = LME_VOLTAGE_L;
+       struct dvb_usb_device *d = fe_to_d(fe);
+       struct lme2510_state *st = fe_to_priv(fe);
+       static u8 voltage_low[] = LME_VOLTAGE_L;
        static u8 voltage_high[] = LME_VOLTAGE_H;
        static u8 rbuf[1];
        int ret = 0, len = 3, rlen = 1;
 
-       mutex_lock(&adap->dev->i2c_mutex);
+       mutex_lock(&d->i2c_mutex);
 
        switch (voltage) {
        case SEC_VOLTAGE_18:
-               ret |= lme2510_usb_talk(adap->dev,
+               ret |= lme2510_usb_talk(d,
                        voltage_high, len, rbuf, rlen);
                break;
 
        case SEC_VOLTAGE_OFF:
        case SEC_VOLTAGE_13:
        default:
-               ret |= lme2510_usb_talk(adap->dev,
+               ret |= lme2510_usb_talk(d,
                                voltage_low, len, rbuf, rlen);
                break;
        }
 
-       mutex_unlock(&adap->dev->i2c_mutex);
+       mutex_unlock(&d->i2c_mutex);
+
+       if (st->tuner_config == TUNER_RS2000)
+               if (st->fe_set_voltage)
+                       st->fe_set_voltage(fe, voltage);
+
 
        return (ret < 0) ? -ENODEV : 0;
 }
@@ -1002,29 +991,44 @@ static int dm04_lme2510_set_voltage(struct dvb_frontend *fe,
 static int dm04_rs2000_read_signal_strength(struct dvb_frontend *fe,
        u16 *strength)
 {
-       struct dvb_usb_adapter *adap = fe->dvb->priv;
-       struct lme2510_state *st = adap->dev->priv;
+       struct lme2510_state *st = fe_to_priv(fe);
+
+       *strength = (u16)((u32)st->signal_level * 0xffff / 0xff);
 
-       *strength = (u16)((u32)st->signal_level * 0xffff / 0x7f);
        return 0;
 }
 
 static int dm04_rs2000_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
-       struct dvb_usb_adapter *adap = fe->dvb->priv;
-       struct lme2510_state *st = adap->dev->priv;
+       struct lme2510_state *st = fe_to_priv(fe);
+
+       *snr = (u16)((u32)st->signal_sn * 0xffff / 0x7f);
+
+       return 0;
+}
+
+static int dm04_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+       *ber = 0;
+
+       return 0;
+}
+
+static int dm04_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+       *ucblocks = 0;
 
-       *snr = (u16)((u32)st->signal_sn * 0xffff / 0xff);
        return 0;
 }
 
 static int lme_name(struct dvb_usb_adapter *adap)
 {
-       struct lme2510_state *st = adap->dev->priv;
-       const char *desc = adap->dev->desc->name;
+       struct dvb_usb_device *d = adap_to_d(adap);
+       struct lme2510_state *st = adap_to_priv(adap);
+       const char *desc = d->name;
        char *fe_name[] = {"", " LG TDQY-P001F", " SHARP:BS2F7HZ7395",
                                " SHARP:BS2F7HZ0194", " RS2000"};
-       char *name = adap->fe_adap[0].fe->ops.info.name;
+       char *name = adap->fe[0]->ops.info.name;
 
        strlcpy(name, desc, 128);
        strlcat(name, fe_name[st->tuner_config], 128);
@@ -1034,120 +1038,128 @@ static int lme_name(struct dvb_usb_adapter *adap)
 
 static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap)
 {
-       struct lme2510_state *st = adap->dev->priv;
-
+       struct dvb_usb_device *d = adap_to_d(adap);
+       struct lme2510_state *st = d->priv;
        int ret = 0;
 
        st->i2c_talk_onoff = 1;
-       switch (le16_to_cpu(adap->dev->udev->descriptor.idProduct)) {
+       switch (le16_to_cpu(d->udev->descriptor.idProduct)) {
        case 0x1122:
        case 0x1120:
                st->i2c_gate = 4;
-               adap->fe_adap[0].fe = dvb_attach(tda10086_attach,
-                       &tda10086_config, &adap->dev->i2c_adap);
-               if (adap->fe_adap[0].fe) {
+               adap->fe[0] = dvb_attach(tda10086_attach,
+                       &tda10086_config, &d->i2c_adap);
+               if (adap->fe[0]) {
                        info("TUN Found Frontend TDA10086");
                        st->i2c_tuner_gate_w = 4;
                        st->i2c_tuner_gate_r = 4;
                        st->i2c_tuner_addr = 0xc0;
                        st->tuner_config = TUNER_LG;
-                       if (dvb_usb_lme2510_firmware != TUNER_LG) {
-                               dvb_usb_lme2510_firmware = TUNER_LG;
-                               ret = lme_firmware_switch(adap->dev->udev, 1);
+                       if (st->dvb_usb_lme2510_firmware != TUNER_LG) {
+                               st->dvb_usb_lme2510_firmware = TUNER_LG;
+                               ret = lme_firmware_switch(d, 1) ? 0 : -ENODEV;
                        }
                        break;
                }
 
                st->i2c_gate = 4;
-               adap->fe_adap[0].fe = dvb_attach(stv0299_attach,
-                               &sharp_z0194_config, &adap->dev->i2c_adap);
-               if (adap->fe_adap[0].fe) {
+               adap->fe[0] = dvb_attach(stv0299_attach,
+                               &sharp_z0194_config, &d->i2c_adap);
+               if (adap->fe[0]) {
                        info("FE Found Stv0299");
                        st->i2c_tuner_gate_w = 4;
                        st->i2c_tuner_gate_r = 5;
                        st->i2c_tuner_addr = 0xc0;
                        st->tuner_config = TUNER_S0194;
-                       if (dvb_usb_lme2510_firmware != TUNER_S0194) {
-                               dvb_usb_lme2510_firmware = TUNER_S0194;
-                               ret = lme_firmware_switch(adap->dev->udev, 1);
+                       if (st->dvb_usb_lme2510_firmware != TUNER_S0194) {
+                               st->dvb_usb_lme2510_firmware = TUNER_S0194;
+                               ret = lme_firmware_switch(d, 1) ? 0 : -ENODEV;
                        }
                        break;
                }
 
                st->i2c_gate = 5;
-               adap->fe_adap[0].fe = dvb_attach(stv0288_attach, &lme_config,
-                       &adap->dev->i2c_adap);
+               adap->fe[0] = dvb_attach(stv0288_attach, &lme_config,
+                       &d->i2c_adap);
 
-               if (adap->fe_adap[0].fe) {
+               if (adap->fe[0]) {
                        info("FE Found Stv0288");
                        st->i2c_tuner_gate_w = 4;
                        st->i2c_tuner_gate_r = 5;
                        st->i2c_tuner_addr = 0xc0;
                        st->tuner_config = TUNER_S7395;
-                       if (dvb_usb_lme2510_firmware != TUNER_S7395) {
-                               dvb_usb_lme2510_firmware = TUNER_S7395;
-                               ret = lme_firmware_switch(adap->dev->udev, 1);
+                       if (st->dvb_usb_lme2510_firmware != TUNER_S7395) {
+                               st->dvb_usb_lme2510_firmware = TUNER_S7395;
+                               ret = lme_firmware_switch(d, 1) ? 0 : -ENODEV;
                        }
                        break;
                }
        case 0x22f0:
                st->i2c_gate = 5;
-               adap->fe_adap[0].fe = dvb_attach(m88rs2000_attach,
-                       &m88rs2000_config, &adap->dev->i2c_adap);
+               adap->fe[0] = dvb_attach(m88rs2000_attach,
+                       &m88rs2000_config, &d->i2c_adap);
 
-               if (adap->fe_adap[0].fe) {
+               if (adap->fe[0]) {
                        info("FE Found M88RS2000");
                        st->i2c_tuner_gate_w = 5;
                        st->i2c_tuner_gate_r = 5;
                        st->i2c_tuner_addr = 0xc0;
                        st->tuner_config = TUNER_RS2000;
-                       adap->fe_adap[0].fe->ops.read_signal_strength =
+                       st->fe_set_voltage =
+                               adap->fe[0]->ops.set_voltage;
+
+                       adap->fe[0]->ops.read_signal_strength =
                                dm04_rs2000_read_signal_strength;
-                       adap->fe_adap[0].fe->ops.read_snr =
+                       adap->fe[0]->ops.read_snr =
                                dm04_rs2000_read_snr;
+                       adap->fe[0]->ops.read_ber =
+                               dm04_read_ber;
+                       adap->fe[0]->ops.read_ucblocks =
+                               dm04_read_ucblocks;
                }
                break;
        }
 
-       if (adap->fe_adap[0].fe == NULL) {
-                       info("DM04/QQBOX Not Powered up or not Supported");
-                       return -ENODEV;
+       if (adap->fe[0] == NULL) {
+               info("DM04/QQBOX Not Powered up or not Supported");
+               return -ENODEV;
        }
 
        if (ret) {
-               if (adap->fe_adap[0].fe) {
-                       dvb_frontend_detach(adap->fe_adap[0].fe);
-                       adap->fe_adap[0].fe = NULL;
+               if (adap->fe[0]) {
+                       dvb_frontend_detach(adap->fe[0]);
+                       adap->fe[0] = NULL;
                }
-               adap->dev->props.rc.core.rc_codes = NULL;
+               d->rc_map = NULL;
                return -ENODEV;
        }
 
-       adap->fe_adap[0].fe->ops.set_voltage = dm04_lme2510_set_voltage;
+       adap->fe[0]->ops.set_voltage = dm04_lme2510_set_voltage;
        ret = lme_name(adap);
        return ret;
 }
 
 static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap)
 {
-       struct lme2510_state *st = adap->dev->priv;
+       struct dvb_usb_device *d = adap_to_d(adap);
+       struct lme2510_state *st = adap_to_priv(adap);
        char *tun_msg[] = {"", "TDA8263", "IX2505V", "DVB_PLL_OPERA", "RS2000"};
        int ret = 0;
 
        switch (st->tuner_config) {
        case TUNER_LG:
-               if (dvb_attach(tda826x_attach, adap->fe_adap[0].fe, 0xc0,
-                       &adap->dev->i2c_adap, 1))
+               if (dvb_attach(tda826x_attach, adap->fe[0], 0xc0,
+                       &d->i2c_adap, 1))
                        ret = st->tuner_config;
                break;
        case TUNER_S7395:
-               if (dvb_attach(ix2505v_attach , adap->fe_adap[0].fe, &lme_tuner,
-                       &adap->dev->i2c_adap))
+               if (dvb_attach(ix2505v_attach , adap->fe[0], &lme_tuner,
+                       &d->i2c_adap))
                        ret = st->tuner_config;
                break;
        case TUNER_S0194:
-               if (dvb_attach(dvb_pll_attach , adap->fe_adap[0].fe, 0xc0,
-                       &adap->dev->i2c_adap, DVB_PLL_OPERA1))
+               if (dvb_attach(dvb_pll_attach , adap->fe[0], 0xc0,
+                       &d->i2c_adap, DVB_PLL_OPERA1))
                        ret = st->tuner_config;
                break;
        case TUNER_RS2000:
@@ -1161,7 +1173,7 @@ static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap)
                info("TUN Found %s tuner", tun_msg[ret]);
        else {
                info("TUN No tuner found --- resetting device");
-               lme_coldreset(adap->dev->udev);
+               lme_coldreset(d);
                return -ENODEV;
        }
 
@@ -1197,158 +1209,57 @@ static int lme2510_powerup(struct dvb_usb_device *d, int onoff)
        return ret;
 }
 
-/* DVB USB Driver stuff */
-static struct dvb_usb_device_properties lme2510_properties;
-static struct dvb_usb_device_properties lme2510c_properties;
+static int lme2510_get_adapter_count(struct dvb_usb_device *d)
+{
+       return 1;
+}
 
-static int lme2510_probe(struct usb_interface *intf,
-               const struct usb_device_id *id)
+static int lme2510_identify_state(struct dvb_usb_device *d, const char **name)
 {
-       struct usb_device *udev = interface_to_usbdev(intf);
+       struct lme2510_state *st = d->priv;
 
-       usb_reset_configuration(udev);
+       usb_reset_configuration(d->udev);
 
-       usb_set_interface(udev, intf->cur_altsetting->desc.bInterfaceNumber, 1);
+       usb_set_interface(d->udev,
+               d->intf->cur_altsetting->desc.bInterfaceNumber, 1);
 
-       if (udev->speed != USB_SPEED_HIGH) {
-               usb_reset_device(udev);
-               info("DEV Failed to connect in HIGH SPEED mode");
-               return -ENODEV;
-       }
-
-       if (lme2510_return_status(udev) == 0x44) {
-               lme_firmware_switch(udev, 0);
-               return -ENODEV;
-       }
+       st->dvb_usb_lme2510_firmware = dvb_usb_lme2510_firmware;
 
-       if (0 == dvb_usb_device_init(intf, &lme2510_properties,
-                                    THIS_MODULE, NULL, adapter_nr)) {
-               info("DEV registering device driver");
-               return 0;
-       }
-       if (0 == dvb_usb_device_init(intf, &lme2510c_properties,
-                                    THIS_MODULE, NULL, adapter_nr)) {
-               info("DEV registering device driver");
-               return 0;
+       if (lme2510_return_status(d) == 0x44) {
+               *name = lme_firmware_switch(d, 0);
+               return COLD;
        }
 
-       info("DEV lme2510 Error");
-       return -ENODEV;
-
+       return 0;
 }
 
-static struct usb_device_id lme2510_table[] = {
-       { USB_DEVICE(0x3344, 0x1122) },  /* LME2510 */
-       { USB_DEVICE(0x3344, 0x1120) },  /* LME2510C */
-       { USB_DEVICE(0x3344, 0x22f0) },  /* LME2510C RS2000 */
-       {}              /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(usb, lme2510_table);
-
-static struct dvb_usb_device_properties lme2510_properties = {
-       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
-       .size_of_priv = sizeof(struct lme2510_state),
-       .num_adapters = 1,
-       .adapter = {
-               {
-               .num_frontends = 1,
-               .fe = {{
-                       .caps = DVB_USB_ADAP_HAS_PID_FILTER|
-                               DVB_USB_ADAP_NEED_PID_FILTERING|
-                               DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-                       .streaming_ctrl   = lme2510_streaming_ctrl,
-                       .pid_filter_count = 32,
-                       .pid_filter = lme2510_pid_filter,
-                       .pid_filter_ctrl  = lme2510_pid_filter_ctrl,
-                       .frontend_attach  = dm04_lme2510_frontend_attach,
-                       .tuner_attach = dm04_lme2510_tuner,
-                       /* parameter for the MPEG2-data transfer */
-                       .stream = {
-                               .type = USB_BULK,
-                               .count = 10,
-                               .endpoint = 0x06,
-                               .u = {
-                                       .bulk = {
-                                               .buffersize = 4096,
-
-                                       }
-                               }
-                       }
-               }},
-               }
-       },
-       .rc.core = {
-               .protocol       = RC_TYPE_NEC,
-               .module_name    = "LME2510 Remote Control",
-               .allowed_protos = RC_TYPE_NEC,
-               .rc_codes       = RC_MAP_LME2510,
-       },
-       .power_ctrl       = lme2510_powerup,
-       .identify_state   = lme2510_identify_state,
-       .i2c_algo         = &lme2510_i2c_algo,
-       .generic_bulk_ctrl_endpoint = 0,
-       .num_device_descs = 1,
-       .devices = {
-               {   "DM04_LME2510_DVB-S",
-                       { &lme2510_table[0], NULL },
-                       },
+static int lme2510_get_stream_config(struct dvb_frontend *fe, u8 *ts_type,
+               struct usb_data_stream_properties *stream)
+{
+       struct dvb_usb_adapter *adap = fe_to_adap(fe);
+       struct dvb_usb_device *d = adap_to_d(adap);
 
+       if (adap == NULL)
+               return 0;
+       /* Turn PID filter on the fly by module option */
+       if (pid_filter == 2) {
+               adap->pid_filtering  = 1;
+               adap->max_feed_count = 15;
        }
-};
 
-static struct dvb_usb_device_properties lme2510c_properties = {
-       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
-       .size_of_priv = sizeof(struct lme2510_state),
-       .num_adapters = 1,
-       .adapter = {
-               {
-               .num_frontends = 1,
-               .fe = {{
-                       .caps = DVB_USB_ADAP_HAS_PID_FILTER|
-                               DVB_USB_ADAP_NEED_PID_FILTERING|
-                               DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-                       .streaming_ctrl   = lme2510_streaming_ctrl,
-                       .pid_filter_count = 32,
-                       .pid_filter = lme2510_pid_filter,
-                       .pid_filter_ctrl  = lme2510_pid_filter_ctrl,
-                       .frontend_attach  = dm04_lme2510_frontend_attach,
-                       .tuner_attach = dm04_lme2510_tuner,
-                       /* parameter for the MPEG2-data transfer */
-                       .stream = {
-                               .type = USB_BULK,
-                               .count = 10,
-                               .endpoint = 0x8,
-                               .u = {
-                                       .bulk = {
-                                               .buffersize = 4096,
+       if (!(le16_to_cpu(d->udev->descriptor.idProduct)
+               == 0x1122))
+               stream->endpoint = 0x8;
 
-                                       }
-                               }
-                       }
-               }},
-               }
-       },
-       .rc.core = {
-               .protocol       = RC_TYPE_NEC,
-               .module_name    = "LME2510 Remote Control",
-               .allowed_protos = RC_TYPE_NEC,
-               .rc_codes       = RC_MAP_LME2510,
-       },
-       .power_ctrl       = lme2510_powerup,
-       .identify_state   = lme2510_identify_state,
-       .i2c_algo         = &lme2510_i2c_algo,
-       .generic_bulk_ctrl_endpoint = 0,
-       .num_device_descs = 2,
-       .devices = {
-               {   "DM04_LME2510C_DVB-S",
-                       { &lme2510_table[1], NULL },
-                       },
-               {   "DM04_LME2510C_DVB-S RS2000",
-                       { &lme2510_table[2], NULL },
-                       },
-       }
-};
+       return 0;
+}
+
+static int lme2510_get_rc_config(struct dvb_usb_device *d,
+       struct dvb_usb_rc *rc)
+{
+       rc->allowed_protos = RC_TYPE_NEC;
+       return 0;
+}
 
 static void *lme2510_exit_int(struct dvb_usb_device *d)
 {
@@ -1357,8 +1268,7 @@ static void *lme2510_exit_int(struct dvb_usb_device *d)
        void *buffer = NULL;
 
        if (adap != NULL) {
-               lme2510_kill_urb(&adap->fe_adap[0].stream);
-               adap->feedcount = 0;
+               lme2510_kill_urb(&adap->stream);
        }
 
        if (st->usb_buffer != NULL) {
@@ -1379,29 +1289,85 @@ static void *lme2510_exit_int(struct dvb_usb_device *d)
        return buffer;
 }
 
-static void lme2510_exit(struct usb_interface *intf)
+static void lme2510_exit(struct dvb_usb_device *d)
 {
-       struct dvb_usb_device *d = usb_get_intfdata(intf);
        void *usb_buffer;
 
        if (d != NULL) {
                usb_buffer = lme2510_exit_int(d);
-               dvb_usb_device_exit(intf);
                if (usb_buffer != NULL)
                        kfree(usb_buffer);
        }
 }
 
+static struct dvb_usb_device_properties lme2510_props = {
+       .driver_name = KBUILD_MODNAME,
+       .owner = THIS_MODULE,
+       .bInterfaceNumber = 0,
+       .adapter_nr = adapter_nr,
+       .size_of_priv = sizeof(struct lme2510_state),
+
+       .download_firmware = lme2510_download_firmware,
+
+       .power_ctrl       = lme2510_powerup,
+       .identify_state   = lme2510_identify_state,
+       .i2c_algo         = &lme2510_i2c_algo,
+
+       .frontend_attach  = dm04_lme2510_frontend_attach,
+       .tuner_attach = dm04_lme2510_tuner,
+       .get_stream_config = lme2510_get_stream_config,
+       .get_adapter_count = lme2510_get_adapter_count,
+       .streaming_ctrl   = lme2510_streaming_ctrl,
+
+       .get_rc_config = lme2510_get_rc_config,
+
+       .exit = lme2510_exit,
+       .adapter = {
+               {
+                       .caps = DVB_USB_ADAP_HAS_PID_FILTER|
+                               DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+                       .pid_filter_count = 15,
+                       .pid_filter = lme2510_pid_filter,
+                       .pid_filter_ctrl  = lme2510_pid_filter_ctrl,
+                       .stream =
+                       DVB_USB_STREAM_BULK(0x86, 10, 4096),
+               },
+               {
+               }
+       },
+};
+
+static const struct usb_device_id lme2510_id_table[] = {
+       {       DVB_USB_DEVICE(0x3344, 0x1122, &lme2510_props,
+               "DM04_LME2510_DVB-S", RC_MAP_LME2510)   },
+       {       DVB_USB_DEVICE(0x3344, 0x1120, &lme2510_props,
+               "DM04_LME2510C_DVB-S", RC_MAP_LME2510)  },
+       {       DVB_USB_DEVICE(0x3344, 0x22f0, &lme2510_props,
+               "DM04_LME2510C_DVB-S RS2000", RC_MAP_LME2510)   },
+       {}              /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, lme2510_id_table);
+
 static struct usb_driver lme2510_driver = {
-       .name           = "LME2510C_DVB-S",
-       .probe          = lme2510_probe,
-       .disconnect     = lme2510_exit,
-       .id_table       = lme2510_table,
+       .name           = KBUILD_MODNAME,
+       .probe          = dvb_usbv2_probe,
+       .disconnect     = dvb_usbv2_disconnect,
+       .id_table       = lme2510_id_table,
+       .no_dynamic_id = 1,
+       .soft_unbind = 1,
 };
 
 module_usb_driver(lme2510_driver);
 
 MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
 MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0");
-MODULE_VERSION("1.99");
+MODULE_VERSION("2.06");
 MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(LME2510_C_S7395);
+MODULE_FIRMWARE(LME2510_C_LG);
+MODULE_FIRMWARE(LME2510_C_S0194);
+MODULE_FIRMWARE(LME2510_C_RS2000);
+MODULE_FIRMWARE(LME2510_LG);
+MODULE_FIRMWARE(LME2510_S0194);
+
similarity index 99%
rename from drivers/media/dvb/dvb-usb/mxl111sf-tuner.c
rename to drivers/media/dvb/dvb-usb-v2/mxl111sf-tuner.c
index 74da5bb1ce99c5ab934e64d769adb38f32cd642d..ef4c65fcbb734ce6852dbd30856a5f3409849e86 100644 (file)
@@ -31,6 +31,8 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
        if (mxl111sf_tuner_debug) \
                mxl_printk(KERN_DEBUG, fmt, ##arg)
 
+#define err pr_err
+
 /* ------------------------------------------------------------------------ */
 
 struct mxl111sf_tuner_state {
diff --git a/drivers/media/dvb/dvb-usb-v2/mxl111sf.c b/drivers/media/dvb/dvb-usb-v2/mxl111sf.c
new file mode 100644 (file)
index 0000000..861e0ae
--- /dev/null
@@ -0,0 +1,1459 @@
+/*
+ * Copyright (C) 2010 Michael Krufky (mkrufky@kernellabs.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.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+
+#include <linux/vmalloc.h>
+#include <linux/i2c.h>
+
+#include "mxl111sf.h"
+#include "mxl111sf-reg.h"
+#include "mxl111sf-phy.h"
+#include "mxl111sf-i2c.h"
+#include "mxl111sf-gpio.h"
+
+#include "mxl111sf-demod.h"
+#include "mxl111sf-tuner.h"
+
+#include "lgdt3305.h"
+#include "lg2160.h"
+
+int dvb_usb_mxl111sf_debug;
+module_param_named(debug, dvb_usb_mxl111sf_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level "
+                "(1=info, 2=xfer, 4=i2c, 8=reg, 16=adv (or-able)).");
+
+int dvb_usb_mxl111sf_isoc;
+module_param_named(isoc, dvb_usb_mxl111sf_isoc, int, 0644);
+MODULE_PARM_DESC(isoc, "enable usb isoc xfer (0=bulk, 1=isoc).");
+
+int dvb_usb_mxl111sf_spi;
+module_param_named(spi, dvb_usb_mxl111sf_spi, int, 0644);
+MODULE_PARM_DESC(spi, "use spi rather than tp for data xfer (0=tp, 1=spi).");
+
+#define ANT_PATH_AUTO 0
+#define ANT_PATH_EXTERNAL 1
+#define ANT_PATH_INTERNAL 2
+
+int dvb_usb_mxl111sf_rfswitch =
+#if 0
+               ANT_PATH_AUTO;
+#else
+               ANT_PATH_EXTERNAL;
+#endif
+
+module_param_named(rfswitch, dvb_usb_mxl111sf_rfswitch, int, 0644);
+MODULE_PARM_DESC(rfswitch, "force rf switch position (0=auto, 1=ext, 2=int).");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define deb_info pr_debug
+#define deb_reg pr_debug
+#define deb_adv pr_debug
+#define err pr_err
+#define info pr_info
+
+int mxl111sf_ctrl_msg(struct dvb_usb_device *d,
+                     u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
+{
+       int wo = (rbuf == NULL || rlen == 0); /* write-only */
+       int ret;
+       u8 sndbuf[1+wlen];
+
+       deb_adv("%s(wlen = %d, rlen = %d)\n", __func__, wlen, rlen);
+
+       memset(sndbuf, 0, 1+wlen);
+
+       sndbuf[0] = cmd;
+       memcpy(&sndbuf[1], wbuf, wlen);
+
+       ret = (wo) ? dvb_usbv2_generic_write(d, sndbuf, 1+wlen) :
+               dvb_usbv2_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen);
+       mxl_fail(ret);
+
+       return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+#define MXL_CMD_REG_READ       0xaa
+#define MXL_CMD_REG_WRITE      0x55
+
+int mxl111sf_read_reg(struct mxl111sf_state *state, u8 addr, u8 *data)
+{
+       u8 buf[2];
+       int ret;
+
+       ret = mxl111sf_ctrl_msg(state->d, MXL_CMD_REG_READ, &addr, 1, buf, 2);
+       if (mxl_fail(ret)) {
+               mxl_debug("error reading reg: 0x%02x", addr);
+               goto fail;
+       }
+
+       if (buf[0] == addr)
+               *data = buf[1];
+       else {
+               err("invalid response reading reg: 0x%02x != 0x%02x, 0x%02x",
+                   addr, buf[0], buf[1]);
+               ret = -EINVAL;
+       }
+
+       deb_reg("R: (0x%02x, 0x%02x)\n", addr, *data);
+fail:
+       return ret;
+}
+
+int mxl111sf_write_reg(struct mxl111sf_state *state, u8 addr, u8 data)
+{
+       u8 buf[] = { addr, data };
+       int ret;
+
+       deb_reg("W: (0x%02x, 0x%02x)\n", addr, data);
+
+       ret = mxl111sf_ctrl_msg(state->d, MXL_CMD_REG_WRITE, buf, 2, NULL, 0);
+       if (mxl_fail(ret))
+               err("error writing reg: 0x%02x, val: 0x%02x", addr, data);
+       return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+int mxl111sf_write_reg_mask(struct mxl111sf_state *state,
+                                  u8 addr, u8 mask, u8 data)
+{
+       int ret;
+       u8 val;
+
+       if (mask != 0xff) {
+               ret = mxl111sf_read_reg(state, addr, &val);
+#if 1
+               /* dont know why this usually errors out on the first try */
+               if (mxl_fail(ret))
+                       err("error writing addr: 0x%02x, mask: 0x%02x, "
+                           "data: 0x%02x, retrying...", addr, mask, data);
+
+               ret = mxl111sf_read_reg(state, addr, &val);
+#endif
+               if (mxl_fail(ret))
+                       goto fail;
+       }
+       val &= ~mask;
+       val |= data;
+
+       ret = mxl111sf_write_reg(state, addr, val);
+       mxl_fail(ret);
+fail:
+       return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+int mxl111sf_ctrl_program_regs(struct mxl111sf_state *state,
+                              struct mxl111sf_reg_ctrl_info *ctrl_reg_info)
+{
+       int i, ret = 0;
+
+       for (i = 0;  ctrl_reg_info[i].addr |
+                    ctrl_reg_info[i].mask |
+                    ctrl_reg_info[i].data;  i++) {
+
+               ret = mxl111sf_write_reg_mask(state,
+                                             ctrl_reg_info[i].addr,
+                                             ctrl_reg_info[i].mask,
+                                             ctrl_reg_info[i].data);
+               if (mxl_fail(ret)) {
+                       err("failed on reg #%d (0x%02x)", i,
+                           ctrl_reg_info[i].addr);
+                       break;
+               }
+       }
+       return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static int mxl1x1sf_get_chip_info(struct mxl111sf_state *state)
+{
+       int ret;
+       u8 id, ver;
+       char *mxl_chip, *mxl_rev;
+
+       if ((state->chip_id) && (state->chip_ver))
+               return 0;
+
+       ret = mxl111sf_read_reg(state, CHIP_ID_REG, &id);
+       if (mxl_fail(ret))
+               goto fail;
+       state->chip_id = id;
+
+       ret = mxl111sf_read_reg(state, TOP_CHIP_REV_ID_REG, &ver);
+       if (mxl_fail(ret))
+               goto fail;
+       state->chip_ver = ver;
+
+       switch (id) {
+       case 0x61:
+               mxl_chip = "MxL101SF";
+               break;
+       case 0x63:
+               mxl_chip = "MxL111SF";
+               break;
+       default:
+               mxl_chip = "UNKNOWN MxL1X1";
+               break;
+       }
+       switch (ver) {
+       case 0x36:
+               state->chip_rev = MXL111SF_V6;
+               mxl_rev = "v6";
+               break;
+       case 0x08:
+               state->chip_rev = MXL111SF_V8_100;
+               mxl_rev = "v8_100";
+               break;
+       case 0x18:
+               state->chip_rev = MXL111SF_V8_200;
+               mxl_rev = "v8_200";
+               break;
+       default:
+               state->chip_rev = 0;
+               mxl_rev = "UNKNOWN REVISION";
+               break;
+       }
+       info("%s detected, %s (0x%x)", mxl_chip, mxl_rev, ver);
+fail:
+       return ret;
+}
+
+#define get_chip_info(state)                                           \
+({                                                                     \
+       int ___ret;                                                     \
+       ___ret = mxl1x1sf_get_chip_info(state);                         \
+       if (mxl_fail(___ret)) {                                         \
+               mxl_debug("failed to get chip info"                     \
+                         " on first probe attempt");                   \
+               ___ret = mxl1x1sf_get_chip_info(state);                 \
+               if (mxl_fail(___ret))                                   \
+                       err("failed to get chip info during probe");    \
+               else                                                    \
+                       mxl_debug("probe needed a retry "               \
+                                 "in order to succeed.");              \
+       }                                                               \
+       ___ret;                                                         \
+})
+
+/* ------------------------------------------------------------------------ */
+#if 0
+static int mxl111sf_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+       /* power control depends on which adapter is being woken:
+        * save this for init, instead, via mxl111sf_adap_fe_init */
+       return 0;
+}
+#endif
+
+static int mxl111sf_adap_fe_init(struct dvb_frontend *fe)
+{
+       struct dvb_usb_device *d = fe_to_d(fe);
+       struct mxl111sf_state *state = fe_to_priv(fe);
+       struct mxl111sf_adap_state *adap_state = &state->adap_state[fe->id];
+       int err;
+
+       /* exit if we didnt initialize the driver yet */
+       if (!state->chip_id) {
+               mxl_debug("driver not yet initialized, exit.");
+               goto fail;
+       }
+
+       deb_info("%s()\n", __func__);
+
+       mutex_lock(&state->fe_lock);
+
+       state->alt_mode = adap_state->alt_mode;
+
+       if (usb_set_interface(d->udev, 0, state->alt_mode) < 0)
+               err("set interface failed");
+
+       err = mxl1x1sf_soft_reset(state);
+       mxl_fail(err);
+       err = mxl111sf_init_tuner_demod(state);
+       mxl_fail(err);
+       err = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
+
+       mxl_fail(err);
+       mxl111sf_enable_usb_output(state);
+       mxl_fail(err);
+       mxl1x1sf_top_master_ctrl(state, 1);
+       mxl_fail(err);
+
+       if ((MXL111SF_GPIO_MOD_DVBT != adap_state->gpio_mode) &&
+           (state->chip_rev > MXL111SF_V6)) {
+               mxl111sf_config_pin_mux_modes(state,
+                                             PIN_MUX_TS_SPI_IN_MODE_1);
+               mxl_fail(err);
+       }
+       err = mxl111sf_init_port_expander(state);
+       if (!mxl_fail(err)) {
+               state->gpio_mode = adap_state->gpio_mode;
+               err = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
+               mxl_fail(err);
+#if 0
+               err = fe->ops.init(fe);
+#endif
+               msleep(100); /* add short delay after enabling
+                             * the demod before touching it */
+       }
+
+       return (adap_state->fe_init) ? adap_state->fe_init(fe) : 0;
+fail:
+       return -ENODEV;
+}
+
+static int mxl111sf_adap_fe_sleep(struct dvb_frontend *fe)
+{
+       struct mxl111sf_state *state = fe_to_priv(fe);
+       struct mxl111sf_adap_state *adap_state = &state->adap_state[fe->id];
+       int err;
+
+       /* exit if we didnt initialize the driver yet */
+       if (!state->chip_id) {
+               mxl_debug("driver not yet initialized, exit.");
+               goto fail;
+       }
+
+       deb_info("%s()\n", __func__);
+
+       err = (adap_state->fe_sleep) ? adap_state->fe_sleep(fe) : 0;
+
+       mutex_unlock(&state->fe_lock);
+
+       return err;
+fail:
+       return -ENODEV;
+}
+
+
+static int mxl111sf_ep6_streaming_ctrl(struct dvb_frontend *fe, int onoff)
+{
+       struct mxl111sf_state *state = fe_to_priv(fe);
+       struct mxl111sf_adap_state *adap_state = &state->adap_state[fe->id];
+       int ret = 0;
+
+       deb_info("%s(%d)\n", __func__, onoff);
+
+       if (onoff) {
+               ret = mxl111sf_enable_usb_output(state);
+               mxl_fail(ret);
+               ret = mxl111sf_config_mpeg_in(state, 1, 1,
+                                             adap_state->ep6_clockphase,
+                                             0, 0);
+               mxl_fail(ret);
+#if 0
+       } else {
+               ret = mxl111sf_disable_656_port(state);
+               mxl_fail(ret);
+#endif
+       }
+
+       return ret;
+}
+
+static int mxl111sf_ep5_streaming_ctrl(struct dvb_frontend *fe, int onoff)
+{
+       struct mxl111sf_state *state = fe_to_priv(fe);
+       int ret = 0;
+
+       deb_info("%s(%d)\n", __func__, onoff);
+
+       if (onoff) {
+               ret = mxl111sf_enable_usb_output(state);
+               mxl_fail(ret);
+
+               ret = mxl111sf_init_i2s_port(state, 200);
+               mxl_fail(ret);
+               ret = mxl111sf_config_i2s(state, 0, 15);
+               mxl_fail(ret);
+       } else {
+               ret = mxl111sf_disable_i2s_port(state);
+               mxl_fail(ret);
+       }
+       if (state->chip_rev > MXL111SF_V6)
+               ret = mxl111sf_config_spi(state, onoff);
+       mxl_fail(ret);
+
+       return ret;
+}
+
+static int mxl111sf_ep4_streaming_ctrl(struct dvb_frontend *fe, int onoff)
+{
+       struct mxl111sf_state *state = fe_to_priv(fe);
+       int ret = 0;
+
+       deb_info("%s(%d)\n", __func__, onoff);
+
+       if (onoff) {
+               ret = mxl111sf_enable_usb_output(state);
+               mxl_fail(ret);
+       }
+
+       return ret;
+}
+
+/* ------------------------------------------------------------------------ */
+
+static struct lgdt3305_config hauppauge_lgdt3305_config = {
+       .i2c_addr           = 0xb2 >> 1,
+       .mpeg_mode          = LGDT3305_MPEG_SERIAL,
+       .tpclk_edge         = LGDT3305_TPCLK_RISING_EDGE,
+       .tpvalid_polarity   = LGDT3305_TP_VALID_HIGH,
+       .deny_i2c_rptr      = 1,
+       .spectral_inversion = 0,
+       .qam_if_khz         = 6000,
+       .vsb_if_khz         = 6000,
+};
+
+static int mxl111sf_lgdt3305_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_id)
+{
+       struct dvb_usb_device *d = adap_to_d(adap);
+       struct mxl111sf_state *state = d_to_priv(d);
+       struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id];
+       int ret;
+
+       deb_adv("%s()\n", __func__);
+
+       /* save a pointer to the dvb_usb_device in device state */
+       state->d = d;
+       adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1;
+       state->alt_mode = adap_state->alt_mode;
+
+       if (usb_set_interface(d->udev, 0, state->alt_mode) < 0)
+               err("set interface failed");
+
+       state->gpio_mode = MXL111SF_GPIO_MOD_ATSC;
+       adap_state->gpio_mode = state->gpio_mode;
+       adap_state->device_mode = MXL_TUNER_MODE;
+       adap_state->ep6_clockphase = 1;
+
+       ret = mxl1x1sf_soft_reset(state);
+       if (mxl_fail(ret))
+               goto fail;
+       ret = mxl111sf_init_tuner_demod(state);
+       if (mxl_fail(ret))
+               goto fail;
+
+       ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
+       if (mxl_fail(ret))
+               goto fail;
+
+       ret = mxl111sf_enable_usb_output(state);
+       if (mxl_fail(ret))
+               goto fail;
+       ret = mxl1x1sf_top_master_ctrl(state, 1);
+       if (mxl_fail(ret))
+               goto fail;
+
+       ret = mxl111sf_init_port_expander(state);
+       if (mxl_fail(ret))
+               goto fail;
+       ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
+       if (mxl_fail(ret))
+               goto fail;
+
+       adap->fe[fe_id] = dvb_attach(lgdt3305_attach,
+                                &hauppauge_lgdt3305_config,
+                                &d->i2c_adap);
+       if (adap->fe[fe_id]) {
+               state->num_frontends++;
+               adap_state->fe_init = adap->fe[fe_id]->ops.init;
+               adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init;
+               adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep;
+               adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep;
+               return 0;
+       }
+       ret = -EIO;
+fail:
+       return ret;
+}
+
+static struct lg2160_config hauppauge_lg2160_config = {
+       .lg_chip            = LG2160,
+       .i2c_addr           = 0x1c >> 1,
+       .deny_i2c_rptr      = 1,
+       .spectral_inversion = 0,
+       .if_khz             = 6000,
+};
+
+static int mxl111sf_lg2160_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_id)
+{
+       struct dvb_usb_device *d = adap_to_d(adap);
+       struct mxl111sf_state *state = d_to_priv(d);
+       struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id];
+       int ret;
+
+       deb_adv("%s()\n", __func__);
+
+       /* save a pointer to the dvb_usb_device in device state */
+       state->d = d;
+       adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1;
+       state->alt_mode = adap_state->alt_mode;
+
+       if (usb_set_interface(d->udev, 0, state->alt_mode) < 0)
+               err("set interface failed");
+
+       state->gpio_mode = MXL111SF_GPIO_MOD_MH;
+       adap_state->gpio_mode = state->gpio_mode;
+       adap_state->device_mode = MXL_TUNER_MODE;
+       adap_state->ep6_clockphase = 1;
+
+       ret = mxl1x1sf_soft_reset(state);
+       if (mxl_fail(ret))
+               goto fail;
+       ret = mxl111sf_init_tuner_demod(state);
+       if (mxl_fail(ret))
+               goto fail;
+
+       ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
+       if (mxl_fail(ret))
+               goto fail;
+
+       ret = mxl111sf_enable_usb_output(state);
+       if (mxl_fail(ret))
+               goto fail;
+       ret = mxl1x1sf_top_master_ctrl(state, 1);
+       if (mxl_fail(ret))
+               goto fail;
+
+       ret = mxl111sf_init_port_expander(state);
+       if (mxl_fail(ret))
+               goto fail;
+       ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
+       if (mxl_fail(ret))
+               goto fail;
+
+       ret = get_chip_info(state);
+       if (mxl_fail(ret))
+               goto fail;
+
+       adap->fe[fe_id] = dvb_attach(lg2160_attach,
+                             &hauppauge_lg2160_config,
+                             &d->i2c_adap);
+       if (adap->fe[fe_id]) {
+               state->num_frontends++;
+               adap_state->fe_init = adap->fe[fe_id]->ops.init;
+               adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init;
+               adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep;
+               adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep;
+               return 0;
+       }
+       ret = -EIO;
+fail:
+       return ret;
+}
+
+static struct lg2160_config hauppauge_lg2161_1019_config = {
+       .lg_chip            = LG2161_1019,
+       .i2c_addr           = 0x1c >> 1,
+       .deny_i2c_rptr      = 1,
+       .spectral_inversion = 0,
+       .if_khz             = 6000,
+       .output_if          = 2, /* LG2161_OIF_SPI_MAS */
+};
+
+static struct lg2160_config hauppauge_lg2161_1040_config = {
+       .lg_chip            = LG2161_1040,
+       .i2c_addr           = 0x1c >> 1,
+       .deny_i2c_rptr      = 1,
+       .spectral_inversion = 0,
+       .if_khz             = 6000,
+       .output_if          = 4, /* LG2161_OIF_SPI_MAS */
+};
+
+static int mxl111sf_lg2161_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_id)
+{
+       struct dvb_usb_device *d = adap_to_d(adap);
+       struct mxl111sf_state *state = d_to_priv(d);
+       struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id];
+       int ret;
+
+       deb_adv("%s()\n", __func__);
+
+       /* save a pointer to the dvb_usb_device in device state */
+       state->d = d;
+       adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1;
+       state->alt_mode = adap_state->alt_mode;
+
+       if (usb_set_interface(d->udev, 0, state->alt_mode) < 0)
+               err("set interface failed");
+
+       state->gpio_mode = MXL111SF_GPIO_MOD_MH;
+       adap_state->gpio_mode = state->gpio_mode;
+       adap_state->device_mode = MXL_TUNER_MODE;
+       adap_state->ep6_clockphase = 1;
+
+       ret = mxl1x1sf_soft_reset(state);
+       if (mxl_fail(ret))
+               goto fail;
+       ret = mxl111sf_init_tuner_demod(state);
+       if (mxl_fail(ret))
+               goto fail;
+
+       ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
+       if (mxl_fail(ret))
+               goto fail;
+
+       ret = mxl111sf_enable_usb_output(state);
+       if (mxl_fail(ret))
+               goto fail;
+       ret = mxl1x1sf_top_master_ctrl(state, 1);
+       if (mxl_fail(ret))
+               goto fail;
+
+       ret = mxl111sf_init_port_expander(state);
+       if (mxl_fail(ret))
+               goto fail;
+       ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
+       if (mxl_fail(ret))
+               goto fail;
+
+       ret = get_chip_info(state);
+       if (mxl_fail(ret))
+               goto fail;
+
+       adap->fe[fe_id] = dvb_attach(lg2160_attach,
+                             (MXL111SF_V8_200 == state->chip_rev) ?
+                             &hauppauge_lg2161_1040_config :
+                             &hauppauge_lg2161_1019_config,
+                             &d->i2c_adap);
+       if (adap->fe[fe_id]) {
+               state->num_frontends++;
+               adap_state->fe_init = adap->fe[fe_id]->ops.init;
+               adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init;
+               adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep;
+               adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep;
+               return 0;
+       }
+       ret = -EIO;
+fail:
+       return ret;
+}
+
+static struct lg2160_config hauppauge_lg2161_1019_ep6_config = {
+       .lg_chip            = LG2161_1019,
+       .i2c_addr           = 0x1c >> 1,
+       .deny_i2c_rptr      = 1,
+       .spectral_inversion = 0,
+       .if_khz             = 6000,
+       .output_if          = 1, /* LG2161_OIF_SERIAL_TS */
+};
+
+static struct lg2160_config hauppauge_lg2161_1040_ep6_config = {
+       .lg_chip            = LG2161_1040,
+       .i2c_addr           = 0x1c >> 1,
+       .deny_i2c_rptr      = 1,
+       .spectral_inversion = 0,
+       .if_khz             = 6000,
+       .output_if          = 7, /* LG2161_OIF_SERIAL_TS */
+};
+
+static int mxl111sf_lg2161_ep6_frontend_attach(struct dvb_usb_adapter *adap, u8 fe_id)
+{
+       struct dvb_usb_device *d = adap_to_d(adap);
+       struct mxl111sf_state *state = d_to_priv(d);
+       struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id];
+       int ret;
+
+       deb_adv("%s()\n", __func__);
+
+       /* save a pointer to the dvb_usb_device in device state */
+       state->d = d;
+       adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1;
+       state->alt_mode = adap_state->alt_mode;
+
+       if (usb_set_interface(d->udev, 0, state->alt_mode) < 0)
+               err("set interface failed");
+
+       state->gpio_mode = MXL111SF_GPIO_MOD_MH;
+       adap_state->gpio_mode = state->gpio_mode;
+       adap_state->device_mode = MXL_TUNER_MODE;
+       adap_state->ep6_clockphase = 0;
+
+       ret = mxl1x1sf_soft_reset(state);
+       if (mxl_fail(ret))
+               goto fail;
+       ret = mxl111sf_init_tuner_demod(state);
+       if (mxl_fail(ret))
+               goto fail;
+
+       ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
+       if (mxl_fail(ret))
+               goto fail;
+
+       ret = mxl111sf_enable_usb_output(state);
+       if (mxl_fail(ret))
+               goto fail;
+       ret = mxl1x1sf_top_master_ctrl(state, 1);
+       if (mxl_fail(ret))
+               goto fail;
+
+       ret = mxl111sf_init_port_expander(state);
+       if (mxl_fail(ret))
+               goto fail;
+       ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
+       if (mxl_fail(ret))
+               goto fail;
+
+       ret = get_chip_info(state);
+       if (mxl_fail(ret))
+               goto fail;
+
+       adap->fe[fe_id] = dvb_attach(lg2160_attach,
+                             (MXL111SF_V8_200 == state->chip_rev) ?
+                             &hauppauge_lg2161_1040_ep6_config :
+                             &hauppauge_lg2161_1019_ep6_config,
+                             &d->i2c_adap);
+       if (adap->fe[fe_id]) {
+               state->num_frontends++;
+               adap_state->fe_init = adap->fe[fe_id]->ops.init;
+               adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init;
+               adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep;
+               adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep;
+               return 0;
+       }
+       ret = -EIO;
+fail:
+       return ret;
+}
+
+static struct mxl111sf_demod_config mxl_demod_config = {
+       .read_reg        = mxl111sf_read_reg,
+       .write_reg       = mxl111sf_write_reg,
+       .program_regs    = mxl111sf_ctrl_program_regs,
+};
+
+static int mxl111sf_attach_demod(struct dvb_usb_adapter *adap, u8 fe_id)
+{
+       struct dvb_usb_device *d = adap_to_d(adap);
+       struct mxl111sf_state *state = d_to_priv(d);
+       struct mxl111sf_adap_state *adap_state = &state->adap_state[fe_id];
+       int ret;
+
+       deb_adv("%s()\n", __func__);
+
+       /* save a pointer to the dvb_usb_device in device state */
+       state->d = d;
+       adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 1 : 2;
+       state->alt_mode = adap_state->alt_mode;
+
+       if (usb_set_interface(d->udev, 0, state->alt_mode) < 0)
+               err("set interface failed");
+
+       state->gpio_mode = MXL111SF_GPIO_MOD_DVBT;
+       adap_state->gpio_mode = state->gpio_mode;
+       adap_state->device_mode = MXL_SOC_MODE;
+       adap_state->ep6_clockphase = 1;
+
+       ret = mxl1x1sf_soft_reset(state);
+       if (mxl_fail(ret))
+               goto fail;
+       ret = mxl111sf_init_tuner_demod(state);
+       if (mxl_fail(ret))
+               goto fail;
+
+       ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
+       if (mxl_fail(ret))
+               goto fail;
+
+       ret = mxl111sf_enable_usb_output(state);
+       if (mxl_fail(ret))
+               goto fail;
+       ret = mxl1x1sf_top_master_ctrl(state, 1);
+       if (mxl_fail(ret))
+               goto fail;
+
+       /* dont care if this fails */
+       mxl111sf_init_port_expander(state);
+
+       adap->fe[fe_id] = dvb_attach(mxl111sf_demod_attach, state,
+                             &mxl_demod_config);
+       if (adap->fe[fe_id]) {
+               state->num_frontends++;
+               adap_state->fe_init = adap->fe[fe_id]->ops.init;
+               adap->fe[fe_id]->ops.init = mxl111sf_adap_fe_init;
+               adap_state->fe_sleep = adap->fe[fe_id]->ops.sleep;
+               adap->fe[fe_id]->ops.sleep = mxl111sf_adap_fe_sleep;
+               return 0;
+       }
+       ret = -EIO;
+fail:
+       return ret;
+}
+
+static inline int mxl111sf_set_ant_path(struct mxl111sf_state *state,
+                                       int antpath)
+{
+       return mxl111sf_idac_config(state, 1, 1,
+                                   (antpath == ANT_PATH_INTERNAL) ?
+                                   0x3f : 0x00, 0);
+}
+
+#define DbgAntHunt(x, pwr0, pwr1, pwr2, pwr3) \
+       err("%s(%d) FINAL input set to %s rxPwr:%d|%d|%d|%d\n", \
+           __func__, __LINE__, \
+           (ANT_PATH_EXTERNAL == x) ? "EXTERNAL" : "INTERNAL", \
+           pwr0, pwr1, pwr2, pwr3)
+
+#define ANT_HUNT_SLEEP 90
+#define ANT_EXT_TWEAK 0
+
+static int mxl111sf_ant_hunt(struct dvb_frontend *fe)
+{
+       struct mxl111sf_state *state = fe_to_priv(fe);
+       int antctrl = dvb_usb_mxl111sf_rfswitch;
+
+       u16 rxPwrA, rxPwr0, rxPwr1, rxPwr2;
+
+       /* FIXME: must force EXTERNAL for QAM - done elsewhere */
+       mxl111sf_set_ant_path(state, antctrl == ANT_PATH_AUTO ?
+                             ANT_PATH_EXTERNAL : antctrl);
+
+       if (antctrl == ANT_PATH_AUTO) {
+#if 0
+               msleep(ANT_HUNT_SLEEP);
+#endif
+               fe->ops.tuner_ops.get_rf_strength(fe, &rxPwrA);
+
+               mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL);
+               msleep(ANT_HUNT_SLEEP);
+               fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr0);
+
+               mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL);
+               msleep(ANT_HUNT_SLEEP);
+               fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr1);
+
+               mxl111sf_set_ant_path(state, ANT_PATH_INTERNAL);
+               msleep(ANT_HUNT_SLEEP);
+               fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr2);
+
+               if (rxPwr1+ANT_EXT_TWEAK >= rxPwr2) {
+                       /* return with EXTERNAL enabled */
+                       mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL);
+                       DbgAntHunt(ANT_PATH_EXTERNAL, rxPwrA,
+                                  rxPwr0, rxPwr1, rxPwr2);
+               } else {
+                       /* return with INTERNAL enabled */
+                       DbgAntHunt(ANT_PATH_INTERNAL, rxPwrA,
+                                  rxPwr0, rxPwr1, rxPwr2);
+               }
+       }
+       return 0;
+}
+
+static struct mxl111sf_tuner_config mxl_tuner_config = {
+       .if_freq         = MXL_IF_6_0, /* applies to external IF output, only */
+       .invert_spectrum = 0,
+       .read_reg        = mxl111sf_read_reg,
+       .write_reg       = mxl111sf_write_reg,
+       .program_regs    = mxl111sf_ctrl_program_regs,
+       .top_master_ctrl = mxl1x1sf_top_master_ctrl,
+       .ant_hunt        = mxl111sf_ant_hunt,
+};
+
+static int mxl111sf_attach_tuner(struct dvb_usb_adapter *adap)
+{
+       struct mxl111sf_state *state = adap_to_priv(adap);
+       int i;
+
+       deb_adv("%s()\n", __func__);
+
+       for (i = 0; i < state->num_frontends; i++) {
+               if (dvb_attach(mxl111sf_tuner_attach, adap->fe[i], state,
+                               &mxl_tuner_config) == NULL)
+                       return -EIO;
+       }
+
+       return 0;
+}
+
+static int mxl111sf_fe_ioctl_override(struct dvb_frontend *fe,
+                                     unsigned int cmd, void *parg,
+                                     unsigned int stage)
+{
+       int err = 0;
+
+       switch (stage) {
+       case DVB_FE_IOCTL_PRE:
+
+               switch (cmd) {
+               case FE_READ_SIGNAL_STRENGTH:
+                       err = fe->ops.tuner_ops.get_rf_strength(fe, parg);
+                       /* If no error occurs, prevent dvb-core from handling
+                        * this IOCTL, otherwise return the error */
+                       if (0 == err)
+                               err = 1;
+                       break;
+               }
+               break;
+       }
+       return err;
+};
+
+static u32 mxl111sf_i2c_func(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C;
+}
+
+struct i2c_algorithm mxl111sf_i2c_algo = {
+       .master_xfer   = mxl111sf_i2c_xfer,
+       .functionality = mxl111sf_i2c_func,
+#ifdef NEED_ALGO_CONTROL
+       .algo_control = dummy_algo_control,
+#endif
+};
+
+static int mxl111sf_init(struct dvb_usb_device *d)
+{
+       struct mxl111sf_state *state = d_to_priv(d);
+       int ret;
+       static u8 eeprom[256];
+       struct i2c_client c;
+
+       ret = get_chip_info(state);
+       if (mxl_fail(ret))
+               err("failed to get chip info during probe");
+
+       mutex_init(&state->fe_lock);
+
+       if (state->chip_rev > MXL111SF_V6)
+               mxl111sf_config_pin_mux_modes(state, PIN_MUX_TS_SPI_IN_MODE_1);
+
+       c.adapter = &d->i2c_adap;
+       c.addr = 0xa0 >> 1;
+
+       ret = tveeprom_read(&c, eeprom, sizeof(eeprom));
+       if (mxl_fail(ret))
+               return 0;
+       tveeprom_hauppauge_analog(&c, &state->tv, (0x84 == eeprom[0xa0]) ?
+                       eeprom + 0xa0 : eeprom + 0x80);
+#if 0
+       switch (state->tv.model) {
+       case 117001:
+       case 126001:
+       case 138001:
+               break;
+       default:
+               printk(KERN_WARNING "%s: warning: "
+                      "unknown hauppauge model #%d\n",
+                      __func__, state->tv.model);
+       }
+#endif
+       return 0;
+}
+
+static int mxl111sf_frontend_attach_dvbt(struct dvb_usb_adapter *adap)
+{
+       return mxl111sf_attach_demod(adap, 0);
+}
+
+static int mxl111sf_frontend_attach_atsc(struct dvb_usb_adapter *adap)
+{
+       return mxl111sf_lgdt3305_frontend_attach(adap, 0);
+}
+
+static int mxl111sf_frontend_attach_mh(struct dvb_usb_adapter *adap)
+{
+       return mxl111sf_lg2160_frontend_attach(adap, 0);
+}
+
+static int mxl111sf_frontend_attach_atsc_mh(struct dvb_usb_adapter *adap)
+{
+       int ret;
+       deb_info("%s\n", __func__);
+
+       ret = mxl111sf_lgdt3305_frontend_attach(adap, 0);
+       if (ret < 0)
+               return ret;
+
+       ret = mxl111sf_attach_demod(adap, 1);
+       if (ret < 0)
+               return ret;
+
+       ret = mxl111sf_lg2160_frontend_attach(adap, 2);
+       if (ret < 0)
+               return ret;
+
+       return ret;
+}
+
+static int mxl111sf_frontend_attach_mercury(struct dvb_usb_adapter *adap)
+{
+       int ret;
+       deb_info("%s\n", __func__);
+
+       ret = mxl111sf_lgdt3305_frontend_attach(adap, 0);
+       if (ret < 0)
+               return ret;
+
+       ret = mxl111sf_attach_demod(adap, 1);
+       if (ret < 0)
+               return ret;
+
+       ret = mxl111sf_lg2161_ep6_frontend_attach(adap, 2);
+       if (ret < 0)
+               return ret;
+
+       return ret;
+}
+
+static int mxl111sf_frontend_attach_mercury_mh(struct dvb_usb_adapter *adap)
+{
+       int ret;
+       deb_info("%s\n", __func__);
+
+       ret = mxl111sf_attach_demod(adap, 0);
+       if (ret < 0)
+               return ret;
+
+       if (dvb_usb_mxl111sf_spi)
+               ret = mxl111sf_lg2161_frontend_attach(adap, 1);
+       else
+               ret = mxl111sf_lg2161_ep6_frontend_attach(adap, 1);
+
+       return ret;
+}
+
+static void mxl111sf_stream_config_bulk(struct usb_data_stream_properties *stream, u8 endpoint)
+{
+       deb_info("%s: endpoint=%d size=8192\n", __func__, endpoint);
+       stream->type = USB_BULK;
+       stream->count = 5;
+       stream->endpoint = endpoint;
+       stream->u.bulk.buffersize = 8192;
+}
+
+static void mxl111sf_stream_config_isoc(struct usb_data_stream_properties *stream,
+               u8 endpoint, int framesperurb, int framesize)
+{
+       deb_info("%s: endpoint=%d size=%d\n", __func__, endpoint,
+                       framesperurb * framesize);
+       stream->type = USB_ISOC;
+       stream->count = 5;
+       stream->endpoint = endpoint;
+       stream->u.isoc.framesperurb = framesperurb;
+       stream->u.isoc.framesize = framesize;
+       stream->u.isoc.interval = 1;
+}
+
+/* DVB USB Driver stuff */
+
+/* dvbt       mxl111sf
+ * bulk       EP4/BULK/5/8192
+ * isoc       EP4/ISOC/5/96/564
+ */
+static int mxl111sf_get_stream_config_dvbt(struct dvb_frontend *fe,
+               u8 *ts_type, struct usb_data_stream_properties *stream)
+{
+       deb_info("%s: fe=%d\n", __func__, fe->id);
+
+       *ts_type = DVB_USB_FE_TS_TYPE_188;
+       if (dvb_usb_mxl111sf_isoc)
+               mxl111sf_stream_config_isoc(stream, 4, 96, 564);
+       else
+               mxl111sf_stream_config_bulk(stream, 4);
+       return 0;
+}
+
+static struct dvb_usb_device_properties mxl111sf_props_dvbt = {
+       .driver_name = KBUILD_MODNAME,
+       .owner = THIS_MODULE,
+       .adapter_nr = adapter_nr,
+       .size_of_priv = sizeof(struct mxl111sf_state),
+
+       .generic_bulk_ctrl_endpoint = 0x02,
+       .generic_bulk_ctrl_endpoint_response = 0x81,
+
+       .i2c_algo          = &mxl111sf_i2c_algo,
+       .frontend_attach   = mxl111sf_frontend_attach_dvbt,
+       .tuner_attach      = mxl111sf_attach_tuner,
+       .init              = mxl111sf_init,
+       .streaming_ctrl    = mxl111sf_ep4_streaming_ctrl,
+       .get_stream_config = mxl111sf_get_stream_config_dvbt,
+       .fe_ioctl_override = mxl111sf_fe_ioctl_override,
+
+       .num_adapters = 1,
+       .adapter = {
+               {
+                       .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1),
+               }
+       }
+};
+
+/* atsc       lgdt3305
+ * bulk       EP6/BULK/5/8192
+ * isoc       EP6/ISOC/5/24/3072
+ */
+static int mxl111sf_get_stream_config_atsc(struct dvb_frontend *fe,
+               u8 *ts_type, struct usb_data_stream_properties *stream)
+{
+       deb_info("%s: fe=%d\n", __func__, fe->id);
+
+       *ts_type = DVB_USB_FE_TS_TYPE_188;
+       if (dvb_usb_mxl111sf_isoc)
+               mxl111sf_stream_config_isoc(stream, 6, 24, 3072);
+       else
+               mxl111sf_stream_config_bulk(stream, 6);
+       return 0;
+}
+
+static struct dvb_usb_device_properties mxl111sf_props_atsc = {
+       .driver_name = KBUILD_MODNAME,
+       .owner = THIS_MODULE,
+       .adapter_nr = adapter_nr,
+       .size_of_priv = sizeof(struct mxl111sf_state),
+
+       .generic_bulk_ctrl_endpoint = 0x02,
+       .generic_bulk_ctrl_endpoint_response = 0x81,
+
+       .i2c_algo          = &mxl111sf_i2c_algo,
+       .frontend_attach   = mxl111sf_frontend_attach_atsc,
+       .tuner_attach      = mxl111sf_attach_tuner,
+       .init              = mxl111sf_init,
+       .streaming_ctrl    = mxl111sf_ep6_streaming_ctrl,
+       .get_stream_config = mxl111sf_get_stream_config_atsc,
+       .fe_ioctl_override = mxl111sf_fe_ioctl_override,
+
+       .num_adapters = 1,
+       .adapter = {
+               {
+                       .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1),
+               }
+       }
+};
+
+/* mh         lg2160
+ * bulk       EP5/BULK/5/8192/RAW
+ * isoc       EP5/ISOC/5/96/200/RAW
+ */
+static int mxl111sf_get_stream_config_mh(struct dvb_frontend *fe,
+               u8 *ts_type, struct usb_data_stream_properties *stream)
+{
+       deb_info("%s: fe=%d\n", __func__, fe->id);
+
+       *ts_type = DVB_USB_FE_TS_TYPE_RAW;
+       if (dvb_usb_mxl111sf_isoc)
+               mxl111sf_stream_config_isoc(stream, 5, 96, 200);
+       else
+               mxl111sf_stream_config_bulk(stream, 5);
+       return 0;
+}
+
+static struct dvb_usb_device_properties mxl111sf_props_mh = {
+       .driver_name = KBUILD_MODNAME,
+       .owner = THIS_MODULE,
+       .adapter_nr = adapter_nr,
+       .size_of_priv = sizeof(struct mxl111sf_state),
+
+       .generic_bulk_ctrl_endpoint = 0x02,
+       .generic_bulk_ctrl_endpoint_response = 0x81,
+
+       .i2c_algo          = &mxl111sf_i2c_algo,
+       .frontend_attach   = mxl111sf_frontend_attach_mh,
+       .tuner_attach      = mxl111sf_attach_tuner,
+       .init              = mxl111sf_init,
+       .streaming_ctrl    = mxl111sf_ep5_streaming_ctrl,
+       .get_stream_config = mxl111sf_get_stream_config_mh,
+       .fe_ioctl_override = mxl111sf_fe_ioctl_override,
+
+       .num_adapters = 1,
+       .adapter = {
+               {
+                       .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1),
+               }
+       }
+};
+
+/* atsc mh    lgdt3305           mxl111sf          lg2160
+ * bulk       EP6/BULK/5/8192    EP4/BULK/5/8192   EP5/BULK/5/8192/RAW
+ * isoc       EP6/ISOC/5/24/3072 EP4/ISOC/5/96/564 EP5/ISOC/5/96/200/RAW
+ */
+static int mxl111sf_get_stream_config_atsc_mh(struct dvb_frontend *fe,
+               u8 *ts_type, struct usb_data_stream_properties *stream)
+{
+       deb_info("%s: fe=%d\n", __func__, fe->id);
+
+       if (fe->id == 0) {
+               *ts_type = DVB_USB_FE_TS_TYPE_188;
+               if (dvb_usb_mxl111sf_isoc)
+                       mxl111sf_stream_config_isoc(stream, 6, 24, 3072);
+               else
+                       mxl111sf_stream_config_bulk(stream, 6);
+       } else if (fe->id == 1) {
+               *ts_type = DVB_USB_FE_TS_TYPE_188;
+               if (dvb_usb_mxl111sf_isoc)
+                       mxl111sf_stream_config_isoc(stream, 4, 96, 564);
+               else
+                       mxl111sf_stream_config_bulk(stream, 4);
+       } else if (fe->id == 2) {
+               *ts_type = DVB_USB_FE_TS_TYPE_RAW;
+               if (dvb_usb_mxl111sf_isoc)
+                       mxl111sf_stream_config_isoc(stream, 5, 96, 200);
+               else
+                       mxl111sf_stream_config_bulk(stream, 5);
+       }
+       return 0;
+}
+
+static int mxl111sf_streaming_ctrl_atsc_mh(struct dvb_frontend *fe, int onoff)
+{
+       deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff);
+
+       if (fe->id == 0)
+               return mxl111sf_ep6_streaming_ctrl(fe, onoff);
+       else if (fe->id == 1)
+               return mxl111sf_ep4_streaming_ctrl(fe, onoff);
+       else if (fe->id == 2)
+               return mxl111sf_ep5_streaming_ctrl(fe, onoff);
+       return 0;
+}
+
+static struct dvb_usb_device_properties mxl111sf_props_atsc_mh = {
+       .driver_name = KBUILD_MODNAME,
+       .owner = THIS_MODULE,
+       .adapter_nr = adapter_nr,
+       .size_of_priv = sizeof(struct mxl111sf_state),
+
+       .generic_bulk_ctrl_endpoint = 0x02,
+       .generic_bulk_ctrl_endpoint_response = 0x81,
+
+       .i2c_algo          = &mxl111sf_i2c_algo,
+       .frontend_attach   = mxl111sf_frontend_attach_atsc_mh,
+       .tuner_attach      = mxl111sf_attach_tuner,
+       .init              = mxl111sf_init,
+       .streaming_ctrl    = mxl111sf_streaming_ctrl_atsc_mh,
+       .get_stream_config = mxl111sf_get_stream_config_atsc_mh,
+       .fe_ioctl_override = mxl111sf_fe_ioctl_override,
+
+       .num_adapters = 1,
+       .adapter = {
+               {
+                       .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1),
+               }
+       }
+};
+
+/* mercury    lgdt3305           mxl111sf          lg2161
+ * tp bulk    EP6/BULK/5/8192    EP4/BULK/5/8192   EP6/BULK/5/8192/RAW
+ * tp isoc    EP6/ISOC/5/24/3072 EP4/ISOC/5/96/564 EP6/ISOC/5/24/3072/RAW
+ * spi bulk   EP6/BULK/5/8192    EP4/BULK/5/8192   EP5/BULK/5/8192/RAW
+ * spi isoc   EP6/ISOC/5/24/3072 EP4/ISOC/5/96/564 EP5/ISOC/5/96/200/RAW
+ */
+static int mxl111sf_get_stream_config_mercury(struct dvb_frontend *fe,
+               u8 *ts_type, struct usb_data_stream_properties *stream)
+{
+       deb_info("%s: fe=%d\n", __func__, fe->id);
+
+       if (fe->id == 0) {
+               *ts_type = DVB_USB_FE_TS_TYPE_188;
+               if (dvb_usb_mxl111sf_isoc)
+                       mxl111sf_stream_config_isoc(stream, 6, 24, 3072);
+               else
+                       mxl111sf_stream_config_bulk(stream, 6);
+       } else if (fe->id == 1) {
+               *ts_type = DVB_USB_FE_TS_TYPE_188;
+               if (dvb_usb_mxl111sf_isoc)
+                       mxl111sf_stream_config_isoc(stream, 4, 96, 564);
+               else
+                       mxl111sf_stream_config_bulk(stream, 4);
+       } else if (fe->id == 2 && dvb_usb_mxl111sf_spi) {
+               *ts_type = DVB_USB_FE_TS_TYPE_RAW;
+               if (dvb_usb_mxl111sf_isoc)
+                       mxl111sf_stream_config_isoc(stream, 5, 96, 200);
+               else
+                       mxl111sf_stream_config_bulk(stream, 5);
+       } else if (fe->id == 2 && !dvb_usb_mxl111sf_spi) {
+               *ts_type = DVB_USB_FE_TS_TYPE_RAW;
+               if (dvb_usb_mxl111sf_isoc)
+                       mxl111sf_stream_config_isoc(stream, 6, 24, 3072);
+               else
+                       mxl111sf_stream_config_bulk(stream, 6);
+       }
+       return 0;
+}
+
+static int mxl111sf_streaming_ctrl_mercury(struct dvb_frontend *fe, int onoff)
+{
+       deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff);
+
+       if (fe->id == 0)
+               return mxl111sf_ep6_streaming_ctrl(fe, onoff);
+       else if (fe->id == 1)
+               return mxl111sf_ep4_streaming_ctrl(fe, onoff);
+       else if (fe->id == 2 && dvb_usb_mxl111sf_spi)
+               return mxl111sf_ep5_streaming_ctrl(fe, onoff);
+       else if (fe->id == 2 && !dvb_usb_mxl111sf_spi)
+               return mxl111sf_ep6_streaming_ctrl(fe, onoff);
+       return 0;
+}
+
+static struct dvb_usb_device_properties mxl111sf_props_mercury = {
+       .driver_name = KBUILD_MODNAME,
+       .owner = THIS_MODULE,
+       .adapter_nr = adapter_nr,
+       .size_of_priv = sizeof(struct mxl111sf_state),
+
+       .generic_bulk_ctrl_endpoint = 0x02,
+       .generic_bulk_ctrl_endpoint_response = 0x81,
+
+       .i2c_algo          = &mxl111sf_i2c_algo,
+       .frontend_attach   = mxl111sf_frontend_attach_mercury,
+       .tuner_attach      = mxl111sf_attach_tuner,
+       .init              = mxl111sf_init,
+       .streaming_ctrl    = mxl111sf_streaming_ctrl_mercury,
+       .get_stream_config = mxl111sf_get_stream_config_mercury,
+       .fe_ioctl_override = mxl111sf_fe_ioctl_override,
+
+       .num_adapters = 1,
+       .adapter = {
+               {
+                       .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1),
+               }
+       }
+};
+
+/* mercury mh mxl111sf          lg2161
+ * tp bulk    EP4/BULK/5/8192   EP6/BULK/5/8192/RAW
+ * tp isoc    EP4/ISOC/5/96/564 EP6/ISOC/5/24/3072/RAW
+ * spi bulk   EP4/BULK/5/8192   EP5/BULK/5/8192/RAW
+ * spi isoc   EP4/ISOC/5/96/564 EP5/ISOC/5/96/200/RAW
+ */
+static int mxl111sf_get_stream_config_mercury_mh(struct dvb_frontend *fe,
+               u8 *ts_type, struct usb_data_stream_properties *stream)
+{
+       deb_info("%s: fe=%d\n", __func__, fe->id);
+
+       if (fe->id == 0) {
+               *ts_type = DVB_USB_FE_TS_TYPE_188;
+               if (dvb_usb_mxl111sf_isoc)
+                       mxl111sf_stream_config_isoc(stream, 4, 96, 564);
+               else
+                       mxl111sf_stream_config_bulk(stream, 4);
+       } else if (fe->id == 1 && dvb_usb_mxl111sf_spi) {
+               *ts_type = DVB_USB_FE_TS_TYPE_RAW;
+               if (dvb_usb_mxl111sf_isoc)
+                       mxl111sf_stream_config_isoc(stream, 5, 96, 200);
+               else
+                       mxl111sf_stream_config_bulk(stream, 5);
+       } else if (fe->id == 1 && !dvb_usb_mxl111sf_spi) {
+               *ts_type = DVB_USB_FE_TS_TYPE_RAW;
+               if (dvb_usb_mxl111sf_isoc)
+                       mxl111sf_stream_config_isoc(stream, 6, 24, 3072);
+               else
+                       mxl111sf_stream_config_bulk(stream, 6);
+       }
+       return 0;
+}
+
+static int mxl111sf_streaming_ctrl_mercury_mh(struct dvb_frontend *fe, int onoff)
+{
+       deb_info("%s: fe=%d onoff=%d\n", __func__, fe->id, onoff);
+
+       if (fe->id == 0)
+               return mxl111sf_ep4_streaming_ctrl(fe, onoff);
+       else if (fe->id == 1  && dvb_usb_mxl111sf_spi)
+               return mxl111sf_ep5_streaming_ctrl(fe, onoff);
+       else if (fe->id == 1 && !dvb_usb_mxl111sf_spi)
+               return mxl111sf_ep6_streaming_ctrl(fe, onoff);
+       return 0;
+}
+
+static struct dvb_usb_device_properties mxl111sf_props_mercury_mh = {
+       .driver_name = KBUILD_MODNAME,
+       .owner = THIS_MODULE,
+       .adapter_nr = adapter_nr,
+       .size_of_priv = sizeof(struct mxl111sf_state),
+
+       .generic_bulk_ctrl_endpoint = 0x02,
+       .generic_bulk_ctrl_endpoint_response = 0x81,
+
+       .i2c_algo          = &mxl111sf_i2c_algo,
+       .frontend_attach   = mxl111sf_frontend_attach_mercury_mh,
+       .tuner_attach      = mxl111sf_attach_tuner,
+       .init              = mxl111sf_init,
+       .streaming_ctrl    = mxl111sf_streaming_ctrl_mercury_mh,
+       .get_stream_config = mxl111sf_get_stream_config_mercury_mh,
+       .fe_ioctl_override = mxl111sf_fe_ioctl_override,
+
+       .num_adapters = 1,
+       .adapter = {
+               {
+                       .stream = DVB_USB_STREAM_ISOC(6, 5, 24, 3072, 1),
+               }
+       }
+};
+
+static const struct usb_device_id mxl111sf_id_table[] = {
+       { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc600, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) },
+       { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc601, &mxl111sf_props_atsc, "Hauppauge 126xxx ATSC", NULL) },
+       { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc602, &mxl111sf_props_mh, "HCW 126xxx", NULL) },
+       { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc603, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) },
+       { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc604, &mxl111sf_props_dvbt, "Hauppauge 126xxx DVBT", NULL) },
+       { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc609, &mxl111sf_props_atsc, "Hauppauge 126xxx ATSC", NULL) },
+       { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60a, &mxl111sf_props_mh, "HCW 126xxx", NULL) },
+       { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60b, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) },
+       { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60c, &mxl111sf_props_dvbt, "Hauppauge 126xxx DVBT", NULL) },
+       { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc653, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) },
+       { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc65b, &mxl111sf_props_atsc_mh, "Hauppauge 126xxx ATSC+", NULL) },
+       { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb700, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) },
+       { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb701, &mxl111sf_props_atsc, "Hauppauge 126xxx ATSC", NULL) },
+       { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb702, &mxl111sf_props_mh, "HCW 117xxx", NULL) },
+       { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb703, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) },
+       { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb704, &mxl111sf_props_dvbt, "Hauppauge 117xxx DVBT", NULL) },
+       { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb753, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) },
+       { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb763, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) },
+       { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb764, &mxl111sf_props_dvbt, "Hauppauge 117xxx DVBT", NULL) },
+       { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd853, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) },
+       { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd854, &mxl111sf_props_dvbt, "Hauppauge 138xxx DVBT", NULL) },
+       { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd863, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) },
+       { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd864, &mxl111sf_props_dvbt, "Hauppauge 138xxx DVBT", NULL) },
+       { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8d3, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) },
+       { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8d4, &mxl111sf_props_dvbt, "Hauppauge 138xxx DVBT", NULL) },
+       { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8e3, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) },
+       { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8e4, &mxl111sf_props_dvbt, "Hauppauge 138xxx DVBT", NULL) },
+       { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8ff, &mxl111sf_props_mercury, "Hauppauge Mercury", NULL) },
+       { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc612, &mxl111sf_props_mercury_mh, "Hauppauge 126xxx", NULL) },
+       { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc613, &mxl111sf_props_mercury, "Hauppauge WinTV-Aero-M", NULL) },
+       { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc61a, &mxl111sf_props_mercury_mh, "Hauppauge 126xxx", NULL) },
+       { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xc61b, &mxl111sf_props_mercury, "Hauppauge WinTV-Aero-M", NULL) },
+       { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb757, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) },
+       { DVB_USB_DEVICE(USB_VID_HAUPPAUGE, 0xb767, &mxl111sf_props_atsc_mh, "Hauppauge 117xxx ATSC+", NULL) },
+       { }
+};
+MODULE_DEVICE_TABLE(usb, mxl111sf_id_table);
+
+static struct usb_driver mxl111sf_usb_driver = {
+       .name = KBUILD_MODNAME,
+       .id_table = mxl111sf_id_table,
+       .probe = dvb_usbv2_probe,
+       .disconnect = dvb_usbv2_disconnect,
+       .suspend = dvb_usbv2_suspend,
+       .resume = dvb_usbv2_resume,
+       .no_dynamic_id = 1,
+       .soft_unbind = 1,
+};
+
+module_usb_driver(mxl111sf_usb_driver);
+
+MODULE_AUTHOR("Michael Krufky <mkrufky@kernellabs.com>");
+MODULE_DESCRIPTION("Driver for MaxLinear MxL111SF");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
similarity index 98%
rename from drivers/media/dvb/dvb-usb/mxl111sf.h
rename to drivers/media/dvb/dvb-usb-v2/mxl111sf.h
index 364d89f826bd09318888175851cb3d357115f35f..9816de86e48cb4bd088c535b990d582db1e636db 100644 (file)
@@ -15,7 +15,7 @@
 #undef DVB_USB_LOG_PREFIX
 #endif
 #define DVB_USB_LOG_PREFIX "mxl111sf"
-#include "dvb-usb.h"
+#include "dvb_usb.h"
 #include <media/tveeprom.h>
 
 #define MXL_EP1_REG_READ     1
@@ -39,6 +39,15 @@ enum mxl111sf_gpio_port_expander {
        mxl111sf_PCA9534,
 };
 
+struct mxl111sf_adap_state {
+       int alt_mode;
+       int gpio_mode;
+       int device_mode;
+       int ep6_clockphase;
+       int (*fe_init)(struct dvb_frontend *);
+       int (*fe_sleep)(struct dvb_frontend *);
+};
+
 struct mxl111sf_state {
        struct dvb_usb_device *d;
 
@@ -74,15 +83,8 @@ struct mxl111sf_state {
        struct tveeprom tv;
 
        struct mutex fe_lock;
-};
-
-struct mxl111sf_adap_state {
-       int alt_mode;
-       int gpio_mode;
-       int device_mode;
-       int ep6_clockphase;
-       int (*fe_init)(struct dvb_frontend *);
-       int (*fe_sleep)(struct dvb_frontend *);
+       u8 num_frontends;
+       struct mxl111sf_adap_state adap_state[3];
 };
 
 int mxl111sf_read_reg(struct mxl111sf_state *state, u8 addr, u8 *data);
diff --git a/drivers/media/dvb/dvb-usb-v2/usb_urb.c b/drivers/media/dvb/dvb-usb-v2/usb_urb.c
new file mode 100644 (file)
index 0000000..eaf673a
--- /dev/null
@@ -0,0 +1,357 @@
+/* usb-urb.c is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file keeps functions for initializing and handling the
+ * BULK and ISOC USB data transfers in a generic way.
+ * Can be used for DVB-only and also, that's the plan, for
+ * Hybrid USB devices (analog and DVB).
+ */
+#include "dvb_usb_common.h"
+
+/* URB stuff for streaming */
+
+int usb_urb_reconfig(struct usb_data_stream *stream,
+               struct usb_data_stream_properties *props);
+
+static void usb_urb_complete(struct urb *urb)
+{
+       struct usb_data_stream *stream = urb->context;
+       int ptype = usb_pipetype(urb->pipe);
+       int i;
+       u8 *b;
+
+       dev_dbg(&stream->udev->dev, "%s: %s urb completed status=%d " \
+                       "length=%d/%d pack_num=%d errors=%d\n", __func__,
+                       ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk",
+                       urb->status, urb->actual_length,
+                       urb->transfer_buffer_length,
+                       urb->number_of_packets, urb->error_count);
+
+       switch (urb->status) {
+       case 0:         /* success */
+       case -ETIMEDOUT:    /* NAK */
+               break;
+       case -ECONNRESET:   /* kill */
+       case -ENOENT:
+       case -ESHUTDOWN:
+               return;
+       default:        /* error */
+               dev_dbg(&stream->udev->dev, "%s: urb completition failed=%d\n",
+                               __func__, urb->status);
+               break;
+       }
+
+       b = (u8 *) urb->transfer_buffer;
+       switch (ptype) {
+       case PIPE_ISOCHRONOUS:
+               for (i = 0; i < urb->number_of_packets; i++) {
+                       if (urb->iso_frame_desc[i].status != 0)
+                               dev_dbg(&stream->udev->dev, "%s: iso frame " \
+                                               "descriptor has an error=%d\n",
+                                               __func__,
+                                               urb->iso_frame_desc[i].status);
+                       else if (urb->iso_frame_desc[i].actual_length > 0)
+                               stream->complete(stream,
+                                       b + urb->iso_frame_desc[i].offset,
+                                       urb->iso_frame_desc[i].actual_length);
+
+                       urb->iso_frame_desc[i].status = 0;
+                       urb->iso_frame_desc[i].actual_length = 0;
+               }
+               break;
+       case PIPE_BULK:
+               if (urb->actual_length > 0)
+                       stream->complete(stream, b, urb->actual_length);
+               break;
+       default:
+               dev_err(&stream->udev->dev, "%s: unknown endpoint type in " \
+                               "completition handler\n", KBUILD_MODNAME);
+               return;
+       }
+       usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+int usb_urb_killv2(struct usb_data_stream *stream)
+{
+       int i;
+       for (i = 0; i < stream->urbs_submitted; i++) {
+               dev_dbg(&stream->udev->dev, "%s: kill urb=%d\n", __func__, i);
+               /* stop the URB */
+               usb_kill_urb(stream->urb_list[i]);
+       }
+       stream->urbs_submitted = 0;
+       return 0;
+}
+
+int usb_urb_submitv2(struct usb_data_stream *stream,
+               struct usb_data_stream_properties *props)
+{
+       int i, ret;
+
+       if (props) {
+               ret = usb_urb_reconfig(stream, props);
+               if (ret < 0)
+                       return ret;
+       }
+
+       for (i = 0; i < stream->urbs_initialized; i++) {
+               dev_dbg(&stream->udev->dev, "%s: submit urb=%d\n", __func__, i);
+               ret = usb_submit_urb(stream->urb_list[i], GFP_ATOMIC);
+               if (ret) {
+                       dev_err(&stream->udev->dev, "%s: could not submit " \
+                                       "urb no. %d - get them all back\n",
+                                       KBUILD_MODNAME, i);
+                       usb_urb_killv2(stream);
+                       return ret;
+               }
+               stream->urbs_submitted++;
+       }
+       return 0;
+}
+
+int usb_urb_free_urbs(struct usb_data_stream *stream)
+{
+       int i;
+
+       usb_urb_killv2(stream);
+
+       for (i = stream->urbs_initialized - 1; i >= 0; i--) {
+               if (stream->urb_list[i]) {
+                       dev_dbg(&stream->udev->dev, "%s: free urb=%d\n",
+                                       __func__, i);
+                       /* free the URBs */
+                       usb_free_urb(stream->urb_list[i]);
+               }
+       }
+       stream->urbs_initialized = 0;
+
+       return 0;
+}
+
+static int usb_urb_alloc_bulk_urbs(struct usb_data_stream *stream)
+{
+       int i, j;
+
+       /* allocate the URBs */
+       for (i = 0; i < stream->props.count; i++) {
+               dev_dbg(&stream->udev->dev, "%s: alloc urb=%d\n", __func__, i);
+               stream->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC);
+               if (!stream->urb_list[i]) {
+                       dev_dbg(&stream->udev->dev, "%s: failed\n", __func__);
+                       for (j = 0; j < i; j++)
+                               usb_free_urb(stream->urb_list[j]);
+                       return -ENOMEM;
+               }
+               usb_fill_bulk_urb(stream->urb_list[i],
+                               stream->udev,
+                               usb_rcvbulkpipe(stream->udev,
+                                               stream->props.endpoint),
+                               stream->buf_list[i],
+                               stream->props.u.bulk.buffersize,
+                               usb_urb_complete, stream);
+
+               stream->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+               stream->urb_list[i]->transfer_dma = stream->dma_addr[i];
+               stream->urbs_initialized++;
+       }
+       return 0;
+}
+
+static int usb_urb_alloc_isoc_urbs(struct usb_data_stream *stream)
+{
+       int i, j;
+
+       /* allocate the URBs */
+       for (i = 0; i < stream->props.count; i++) {
+               struct urb *urb;
+               int frame_offset = 0;
+               dev_dbg(&stream->udev->dev, "%s: alloc urb=%d\n", __func__, i);
+               stream->urb_list[i] = usb_alloc_urb(
+                               stream->props.u.isoc.framesperurb, GFP_ATOMIC);
+               if (!stream->urb_list[i]) {
+                       dev_dbg(&stream->udev->dev, "%s: failed\n", __func__);
+                       for (j = 0; j < i; j++)
+                               usb_free_urb(stream->urb_list[j]);
+                       return -ENOMEM;
+               }
+
+               urb = stream->urb_list[i];
+
+               urb->dev = stream->udev;
+               urb->context = stream;
+               urb->complete = usb_urb_complete;
+               urb->pipe = usb_rcvisocpipe(stream->udev,
+                               stream->props.endpoint);
+               urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+               urb->interval = stream->props.u.isoc.interval;
+               urb->number_of_packets = stream->props.u.isoc.framesperurb;
+               urb->transfer_buffer_length = stream->props.u.isoc.framesize *
+                               stream->props.u.isoc.framesperurb;
+               urb->transfer_buffer = stream->buf_list[i];
+               urb->transfer_dma = stream->dma_addr[i];
+
+               for (j = 0; j < stream->props.u.isoc.framesperurb; j++) {
+                       urb->iso_frame_desc[j].offset = frame_offset;
+                       urb->iso_frame_desc[j].length =
+                                       stream->props.u.isoc.framesize;
+                       frame_offset += stream->props.u.isoc.framesize;
+               }
+
+               stream->urbs_initialized++;
+       }
+       return 0;
+}
+
+int usb_free_stream_buffers(struct usb_data_stream *stream)
+{
+       if (stream->state & USB_STATE_URB_BUF) {
+               while (stream->buf_num) {
+                       stream->buf_num--;
+                       dev_dbg(&stream->udev->dev, "%s: free buf=%d\n",
+                               __func__, stream->buf_num);
+                       usb_free_coherent(stream->udev, stream->buf_size,
+                                         stream->buf_list[stream->buf_num],
+                                         stream->dma_addr[stream->buf_num]);
+               }
+       }
+
+       stream->state &= ~USB_STATE_URB_BUF;
+
+       return 0;
+}
+
+int usb_alloc_stream_buffers(struct usb_data_stream *stream, int num,
+               unsigned long size)
+{
+       stream->buf_num = 0;
+       stream->buf_size = size;
+
+       dev_dbg(&stream->udev->dev, "%s: all in all I will use %lu bytes for " \
+                       "streaming\n", __func__,  num * size);
+
+       for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) {
+               stream->buf_list[stream->buf_num] = usb_alloc_coherent(
+                               stream->udev, size, GFP_ATOMIC,
+                               &stream->dma_addr[stream->buf_num]);
+               if (!stream->buf_list[stream->buf_num]) {
+                       dev_dbg(&stream->udev->dev, "%s: alloc buf=%d failed\n",
+                                       __func__, stream->buf_num);
+                       usb_free_stream_buffers(stream);
+                       return -ENOMEM;
+               }
+
+               dev_dbg(&stream->udev->dev, "%s: alloc buf=%d %p (dma %llu)\n",
+                               __func__, stream->buf_num,
+                               stream->buf_list[stream->buf_num],
+                               (long long)stream->dma_addr[stream->buf_num]);
+               memset(stream->buf_list[stream->buf_num], 0, size);
+               stream->state |= USB_STATE_URB_BUF;
+       }
+
+       return 0;
+}
+
+int usb_urb_reconfig(struct usb_data_stream *stream,
+               struct usb_data_stream_properties *props)
+{
+       int buf_size;
+
+       if (!props)
+               return 0;
+
+       /* check allocated buffers are large enough for the request */
+       if (props->type == USB_BULK) {
+               buf_size = stream->props.u.bulk.buffersize;
+       } else if (props->type == USB_ISOC) {
+               buf_size = props->u.isoc.framesize * props->u.isoc.framesperurb;
+       } else {
+               dev_err(&stream->udev->dev, "%s: invalid endpoint type=%d\n",
+                               KBUILD_MODNAME, props->type);
+               return -EINVAL;
+       }
+
+       if (stream->buf_num < props->count || stream->buf_size < buf_size) {
+               dev_err(&stream->udev->dev, "%s: cannot reconfigure as " \
+                               "allocated buffers are too small\n",
+                               KBUILD_MODNAME);
+               return -EINVAL;
+       }
+
+       /* check if all fields are same */
+       if (stream->props.type == props->type &&
+                       stream->props.count == props->count &&
+                       stream->props.endpoint == props->endpoint) {
+               if (props->type == USB_BULK &&
+                               props->u.bulk.buffersize ==
+                               stream->props.u.bulk.buffersize)
+                       return 0;
+               else if (props->type == USB_ISOC &&
+                               props->u.isoc.framesperurb ==
+                               stream->props.u.isoc.framesperurb &&
+                               props->u.isoc.framesize ==
+                               stream->props.u.isoc.framesize &&
+                               props->u.isoc.interval ==
+                               stream->props.u.isoc.interval)
+                       return 0;
+       }
+
+       dev_dbg(&stream->udev->dev, "%s: re-alloc urbs\n", __func__);
+
+       usb_urb_free_urbs(stream);
+       memcpy(&stream->props, props, sizeof(*props));
+       if (props->type == USB_BULK)
+               return usb_urb_alloc_bulk_urbs(stream);
+       else if (props->type == USB_ISOC)
+               return usb_urb_alloc_isoc_urbs(stream);
+
+       return 0;
+}
+
+int usb_urb_initv2(struct usb_data_stream *stream,
+               const struct usb_data_stream_properties *props)
+{
+       int ret;
+
+       if (!stream || !props)
+               return -EINVAL;
+
+       memcpy(&stream->props, props, sizeof(*props));
+
+       if (!stream->complete) {
+               dev_err(&stream->udev->dev, "%s: there is no data callback - " \
+                               "this doesn't make sense\n", KBUILD_MODNAME);
+               return -EINVAL;
+       }
+
+       switch (stream->props.type) {
+       case USB_BULK:
+               ret = usb_alloc_stream_buffers(stream, stream->props.count,
+                               stream->props.u.bulk.buffersize);
+               if (ret < 0)
+                       return ret;
+
+               return usb_urb_alloc_bulk_urbs(stream);
+       case USB_ISOC:
+               ret = usb_alloc_stream_buffers(stream, stream->props.count,
+                               stream->props.u.isoc.framesize *
+                               stream->props.u.isoc.framesperurb);
+               if (ret < 0)
+                       return ret;
+
+               return usb_urb_alloc_isoc_urbs(stream);
+       default:
+               dev_err(&stream->udev->dev, "%s: unknown urb-type for data " \
+                               "transfer\n", KBUILD_MODNAME);
+               return -EINVAL;
+       }
+}
+
+int usb_urb_exitv2(struct usb_data_stream *stream)
+{
+       usb_urb_free_urbs(stream);
+       usb_free_stream_buffers(stream);
+
+       return 0;
+}
index c2161565023a4682d0ba77a5e5b681491b8a31c4..8e13877a5c2ca666259ea0abc6cab2531dd01c4e 100644 (file)
@@ -143,23 +143,6 @@ config DVB_USB_M920X
          "DTV USB MINI" (in cold state) are supported.
          Firmware required.
 
-config DVB_USB_GL861
-       tristate "Genesys Logic GL861 USB2.0 support"
-       depends on DVB_USB
-       select DVB_ZL10353 if !DVB_FE_CUSTOMISE
-       select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
-       help
-         Say Y here to support the MSI Megasky 580 (55801) DVB-T USB2.0
-         receiver with USB ID 0db0:5581.
-
-config DVB_USB_AU6610
-       tristate "Alcor Micro AU6610 USB2.0 support"
-       depends on DVB_USB
-       select DVB_ZL10353 if !DVB_FE_CUSTOMISE
-       select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
-       help
-         Say Y here to support the Sigmatek DVB-110 DVB-T USB2.0 receiver.
-
 config DVB_USB_DIGITV
        tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support"
        depends on DVB_USB
@@ -299,23 +282,6 @@ config DVB_USB_CINERGY_T2
 
          Say Y if you own such a device and want to use it.
 
-config DVB_USB_ANYSEE
-       tristate "Anysee DVB-T/C USB2.0 support"
-       depends on DVB_USB
-       select DVB_PLL if !DVB_FE_CUSTOMISE
-       select DVB_MT352 if !DVB_FE_CUSTOMISE
-       select DVB_ZL10353 if !DVB_FE_CUSTOMISE
-       select DVB_TDA10023 if !DVB_FE_CUSTOMISE
-       select MEDIA_TUNER_TDA18212 if !MEDIA_TUNER_CUSTOMISE
-       select DVB_CX24116 if !DVB_FE_CUSTOMISE
-       select DVB_STV0900 if !DVB_FE_CUSTOMISE
-       select DVB_STV6110 if !DVB_FE_CUSTOMISE
-       select DVB_ISL6423 if !DVB_FE_CUSTOMISE
-       select DVB_CXD2820R if !DVB_FE_CUSTOMISE
-       help
-         Say Y here to support the Anysee E30, Anysee E30 Plus or
-         Anysee E30 C Plus DVB USB2.0 receiver.
-
 config DVB_USB_DTV5100
        tristate "AME DTV-5100 USB2.0 DVB-T support"
        depends on DVB_USB
@@ -324,51 +290,12 @@ config DVB_USB_DTV5100
        help
          Say Y here to support the AME DTV-5100 USB2.0 DVB-T receiver.
 
-config DVB_USB_AF9015
-       tristate "Afatech AF9015 DVB-T USB2.0 support"
-       depends on DVB_USB
-       select DVB_AF9013
-       select DVB_PLL              if !DVB_FE_CUSTOMISE
-       select MEDIA_TUNER_MT2060   if !MEDIA_TUNER_CUSTOMISE
-       select MEDIA_TUNER_QT1010   if !MEDIA_TUNER_CUSTOMISE
-       select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
-       select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
-       select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE
-       select MEDIA_TUNER_TDA18218 if !MEDIA_TUNER_CUSTOMISE
-       select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE
-       help
-         Say Y here to support the Afatech AF9015 based DVB-T USB2.0 receiver
-
-config DVB_USB_CE6230
-       tristate "Intel CE6230 DVB-T USB2.0 support"
-       depends on DVB_USB
-       select DVB_ZL10353
-       select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
-       help
-         Say Y here to support the Intel CE6230 DVB-T USB2.0 receiver
-
 config DVB_USB_FRIIO
        tristate "Friio ISDB-T USB2.0 Receiver support"
        depends on DVB_USB
        help
          Say Y here to support the Japanese DTV receiver Friio.
 
-config DVB_USB_EC168
-       tristate "E3C EC168 DVB-T USB2.0 support"
-       depends on DVB_USB
-       select DVB_EC100
-       select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
-       help
-         Say Y here to support the E3C EC168 DVB-T USB2.0 receiver.
-
-config DVB_USB_AZ6007
-       tristate "AzureWave 6007 and clones DVB-T/C USB2.0 support"
-       depends on DVB_USB
-       select DVB_DRXK if !DVB_FE_CUSTOMISE
-       select MEDIA_TUNER_MT2063 if !DVB_FE_CUSTOMISE
-       help
-         Say Y here to support theAfatech AF9005 based DVB-T/DVB-C receivers.
-
 config DVB_USB_AZ6027
        tristate "Azurewave DVB-S/S2 USB2.0 AZ6027 support"
        depends on DVB_USB
@@ -377,19 +304,6 @@ config DVB_USB_AZ6027
        help
          Say Y here to support the AZ6027 device
 
-config DVB_USB_LME2510
-       tristate "LME DM04/QQBOX DVB-S USB2.0 support"
-       depends on DVB_USB
-       select DVB_TDA10086 if !DVB_FE_CUSTOMISE
-       select DVB_TDA826X if !DVB_FE_CUSTOMISE
-       select DVB_STV0288 if !DVB_FE_CUSTOMISE
-       select DVB_IX2505V if !DVB_FE_CUSTOMISE
-       select DVB_STV0299 if !DVB_FE_CUSTOMISE
-       select DVB_PLL if !DVB_FE_CUSTOMISE
-       select DVB_M88RS2000 if !DVB_FE_CUSTOMISE
-       help
-         Say Y here to support the LME DM04/QQBOX DVB-S USB2.0 .
-
 config DVB_USB_TECHNISAT_USB2
        tristate "Technisat DVB-S/S2 USB2.0 support"
        depends on DVB_USB
@@ -405,15 +319,6 @@ config DVB_USB_IT913X
        help
          Say Y here to support the it913x device
 
-config DVB_USB_MXL111SF
-       tristate "MxL111SF DTV USB2.0 support"
-       depends on DVB_USB
-       select DVB_LGDT3305 if !DVB_FE_CUSTOMISE
-       select DVB_LG2160 if !DVB_FE_CUSTOMISE
-       select VIDEO_TVEEPROM
-       help
-         Say Y here to support the MxL111SF USB2.0 DTV receiver.
-
 config DVB_USB_RTL28XXU
        tristate "Realtek RTL28xxU DVB USB support"
        depends on DVB_USB && EXPERIMENTAL
@@ -427,14 +332,3 @@ config DVB_USB_RTL28XXU
        help
          Say Y here to support the Realtek RTL28xxU DVB USB receiver.
 
-config DVB_USB_AF9035
-       tristate "Afatech AF9035 DVB-T USB2.0 support"
-       depends on DVB_USB
-       select DVB_AF9033
-       select MEDIA_TUNER_TUA9001 if !MEDIA_TUNER_CUSTOMISE
-       select MEDIA_TUNER_FC0011 if !MEDIA_TUNER_CUSTOMISE
-       select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE
-       select MEDIA_TUNER_TDA18218 if !MEDIA_TUNER_CUSTOMISE
-       help
-         Say Y here to support the Afatech AF9035 based DVB USB receiver.
-
index b667ac39a4e359eef6e173500cde10f46244de5d..859baf9c8e0c68b48fb4c106b9ff7acedc6b6c38 100644 (file)
@@ -33,12 +33,6 @@ obj-$(CONFIG_DVB_USB_UMT_010) += dvb-usb-dibusb-common.o dvb-usb-umt-010.o
 dvb-usb-m920x-objs = m920x.o
 obj-$(CONFIG_DVB_USB_M920X) += dvb-usb-m920x.o
 
-dvb-usb-gl861-objs = gl861.o
-obj-$(CONFIG_DVB_USB_GL861) += dvb-usb-gl861.o
-
-dvb-usb-au6610-objs = au6610.o
-obj-$(CONFIG_DVB_USB_AU6610) += dvb-usb-au6610.o
-
 dvb-usb-digitv-objs = digitv.o
 obj-$(CONFIG_DVB_USB_DIGITV) += dvb-usb-digitv.o
 
@@ -60,9 +54,6 @@ obj-$(CONFIG_DVB_USB_AF9005) += dvb-usb-af9005.o
 dvb-usb-af9005-remote-objs = af9005-remote.o
 obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o
 
-dvb-usb-anysee-objs = anysee.o
-obj-$(CONFIG_DVB_USB_ANYSEE) += dvb-usb-anysee.o
-
 dvb-usb-pctv452e-objs = pctv452e.o
 obj-$(CONFIG_DVB_USB_PCTV452E) += dvb-usb-pctv452e.o
 
@@ -72,50 +63,26 @@ obj-$(CONFIG_DVB_USB_DW2102) += dvb-usb-dw2102.o
 dvb-usb-dtv5100-objs = dtv5100.o
 obj-$(CONFIG_DVB_USB_DTV5100) += dvb-usb-dtv5100.o
 
-dvb-usb-af9015-objs = af9015.o
-obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o
-
 dvb-usb-cinergyT2-objs = cinergyT2-core.o cinergyT2-fe.o
 obj-$(CONFIG_DVB_USB_CINERGY_T2) += dvb-usb-cinergyT2.o
 
-dvb-usb-ce6230-objs = ce6230.o
-obj-$(CONFIG_DVB_USB_CE6230) += dvb-usb-ce6230.o
-
 dvb-usb-friio-objs = friio.o friio-fe.o
 obj-$(CONFIG_DVB_USB_FRIIO) += dvb-usb-friio.o
 
-dvb-usb-ec168-objs = ec168.o
-obj-$(CONFIG_DVB_USB_EC168) += dvb-usb-ec168.o
-
-dvb-usb-az6007-objs = az6007.o
-obj-$(CONFIG_DVB_USB_AZ6007) += dvb-usb-az6007.o
-
 dvb-usb-az6027-objs = az6027.o
 obj-$(CONFIG_DVB_USB_AZ6027) += dvb-usb-az6027.o
 
-dvb-usb-lmedm04-objs = lmedm04.o
-obj-$(CONFIG_DVB_USB_LME2510) += dvb-usb-lmedm04.o
-
 dvb-usb-technisat-usb2-objs = technisat-usb2.o
 obj-$(CONFIG_DVB_USB_TECHNISAT_USB2) += dvb-usb-technisat-usb2.o
 
 dvb-usb-it913x-objs := it913x.o
 obj-$(CONFIG_DVB_USB_IT913X) += dvb-usb-it913x.o
 
-dvb-usb-mxl111sf-objs = mxl111sf.o mxl111sf-phy.o mxl111sf-i2c.o mxl111sf-gpio.o
-obj-$(CONFIG_DVB_USB_MXL111SF) += dvb-usb-mxl111sf.o
-obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-demod.o
-obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o
-
 dvb-usb-rtl28xxu-objs = rtl28xxu.o
 obj-$(CONFIG_DVB_USB_RTL28XXU) += dvb-usb-rtl28xxu.o
 
-dvb-usb-af9035-objs = af9035.o
-obj-$(CONFIG_DVB_USB_AF9035) += dvb-usb-af9035.o
-
 ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
 ccflags-y += -I$(srctree)/drivers/media/dvb/frontends/
 # due to tuner-xc3028
 ccflags-y += -I$(srctree)/drivers/media/common/tuners
 ccflags-y += -I$(srctree)/drivers/media/dvb/ttpci
-
diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c
deleted file mode 100644 (file)
index 677fed7..0000000
+++ /dev/null
@@ -1,1952 +0,0 @@
-/*
- * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
- *
- * Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
- *
- * Thanks to Afatech who kindly provided information.
- *
- *    This program is free software; you can redistribute it and/or modify
- *    it under the terms of the GNU General Public License as published by
- *    the Free Software Foundation; either version 2 of the License, or
- *    (at your option) any later version.
- *
- *    This program is distributed in the hope that it will be useful,
- *    but WITHOUT ANY WARRANTY; without even the implied warranty of
- *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *    GNU General Public License for more details.
- *
- *    You should have received a copy of the GNU General Public License
- *    along with this program; if not, write to the Free Software
- *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include <linux/hash.h>
-#include <linux/slab.h>
-
-#include "af9015.h"
-#include "af9013.h"
-#include "mt2060.h"
-#include "qt1010.h"
-#include "tda18271.h"
-#include "mxl5005s.h"
-#include "mc44s803.h"
-#include "tda18218.h"
-#include "mxl5007t.h"
-
-static int dvb_usb_af9015_debug;
-module_param_named(debug, dvb_usb_af9015_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
-static int dvb_usb_af9015_remote;
-module_param_named(remote, dvb_usb_af9015_remote, int, 0644);
-MODULE_PARM_DESC(remote, "select remote");
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-static DEFINE_MUTEX(af9015_usb_mutex);
-
-static struct af9015_config af9015_config;
-static struct dvb_usb_device_properties af9015_properties[3];
-static int af9015_properties_count = ARRAY_SIZE(af9015_properties);
-
-static struct af9013_config af9015_af9013_config[] = {
-       {
-               .i2c_addr = AF9015_I2C_DEMOD,
-               .ts_mode = AF9013_TS_USB,
-               .api_version = { 0, 1, 9, 0 },
-               .gpio[0] = AF9013_GPIO_HI,
-               .gpio[3] = AF9013_GPIO_TUNER_ON,
-
-       }, {
-               .ts_mode = AF9013_TS_SERIAL,
-               .api_version = { 0, 1, 9, 0 },
-               .gpio[0] = AF9013_GPIO_TUNER_ON,
-               .gpio[1] = AF9013_GPIO_LO,
-       }
-};
-
-static int af9015_rw_udev(struct usb_device *udev, struct req_t *req)
-{
-#define BUF_LEN 63
-#define REQ_HDR_LEN 8 /* send header size */
-#define ACK_HDR_LEN 2 /* rece header size */
-       int act_len, ret;
-       u8 buf[BUF_LEN];
-       u8 write = 1;
-       u8 msg_len = REQ_HDR_LEN;
-       static u8 seq; /* packet sequence number */
-
-       if (mutex_lock_interruptible(&af9015_usb_mutex) < 0)
-               return -EAGAIN;
-
-       buf[0] = req->cmd;
-       buf[1] = seq++;
-       buf[2] = req->i2c_addr;
-       buf[3] = req->addr >> 8;
-       buf[4] = req->addr & 0xff;
-       buf[5] = req->mbox;
-       buf[6] = req->addr_len;
-       buf[7] = req->data_len;
-
-       switch (req->cmd) {
-       case GET_CONFIG:
-       case READ_MEMORY:
-       case RECONNECT_USB:
-               write = 0;
-               break;
-       case READ_I2C:
-               write = 0;
-               buf[2] |= 0x01; /* set I2C direction */
-       case WRITE_I2C:
-               buf[0] = READ_WRITE_I2C;
-               break;
-       case WRITE_MEMORY:
-               if (((req->addr & 0xff00) == 0xff00) ||
-                   ((req->addr & 0xff00) == 0xae00))
-                       buf[0] = WRITE_VIRTUAL_MEMORY;
-       case WRITE_VIRTUAL_MEMORY:
-       case COPY_FIRMWARE:
-       case DOWNLOAD_FIRMWARE:
-       case BOOT:
-               break;
-       default:
-               err("unknown command:%d", req->cmd);
-               ret = -1;
-               goto error_unlock;
-       }
-
-       /* buffer overflow check */
-       if ((write && (req->data_len > BUF_LEN - REQ_HDR_LEN)) ||
-               (!write && (req->data_len > BUF_LEN - ACK_HDR_LEN))) {
-               err("too much data; cmd:%d len:%d", req->cmd, req->data_len);
-               ret = -EINVAL;
-               goto error_unlock;
-       }
-
-       /* write requested */
-       if (write) {
-               memcpy(&buf[REQ_HDR_LEN], req->data, req->data_len);
-               msg_len += req->data_len;
-       }
-
-       deb_xfer(">>> ");
-       debug_dump(buf, msg_len, deb_xfer);
-
-       /* send req */
-       ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x02), buf, msg_len,
-               &act_len, AF9015_USB_TIMEOUT);
-       if (ret)
-               err("bulk message failed:%d (%d/%d)", ret, msg_len, act_len);
-       else
-               if (act_len != msg_len)
-                       ret = -1; /* all data is not send */
-       if (ret)
-               goto error_unlock;
-
-       /* no ack for those packets */
-       if (req->cmd == DOWNLOAD_FIRMWARE || req->cmd == RECONNECT_USB)
-               goto exit_unlock;
-
-       /* write receives seq + status = 2 bytes
-          read receives seq + status + data = 2 + N bytes */
-       msg_len = ACK_HDR_LEN;
-       if (!write)
-               msg_len += req->data_len;
-
-       ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, 0x81), buf, msg_len,
-               &act_len, AF9015_USB_TIMEOUT);
-       if (ret) {
-               err("recv bulk message failed:%d", ret);
-               ret = -1;
-               goto error_unlock;
-       }
-
-       deb_xfer("<<< ");
-       debug_dump(buf, act_len, deb_xfer);
-
-       /* check status */
-       if (buf[1]) {
-               err("command failed:%d", buf[1]);
-               ret = -1;
-               goto error_unlock;
-       }
-
-       /* read request, copy returned data to return buf */
-       if (!write)
-               memcpy(req->data, &buf[ACK_HDR_LEN], req->data_len);
-
-error_unlock:
-exit_unlock:
-       mutex_unlock(&af9015_usb_mutex);
-
-       return ret;
-}
-
-static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req)
-{
-       return af9015_rw_udev(d->udev, req);
-}
-
-static int af9015_write_regs(struct dvb_usb_device *d, u16 addr, u8 *val,
-       u8 len)
-{
-       struct req_t req = {WRITE_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len,
-               val};
-       return af9015_ctrl_msg(d, &req);
-}
-
-static int af9015_write_reg(struct dvb_usb_device *d, u16 addr, u8 val)
-{
-       return af9015_write_regs(d, addr, &val, 1);
-}
-
-static int af9015_read_regs(struct dvb_usb_device *d, u16 addr, u8 *val, u8 len)
-{
-       struct req_t req = {READ_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len,
-               val};
-       return af9015_ctrl_msg(d, &req);
-}
-
-static int af9015_read_reg(struct dvb_usb_device *d, u16 addr, u8 *val)
-{
-       return af9015_read_regs(d, addr, val, 1);
-}
-
-static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg,
-       u8 val)
-{
-       struct req_t req = {WRITE_I2C, addr, reg, 1, 1, 1, &val};
-
-       if (addr == af9015_af9013_config[0].i2c_addr ||
-           addr == af9015_af9013_config[1].i2c_addr)
-               req.addr_len = 3;
-
-       return af9015_ctrl_msg(d, &req);
-}
-
-static int af9015_read_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg,
-       u8 *val)
-{
-       struct req_t req = {READ_I2C, addr, reg, 0, 1, 1, val};
-
-       if (addr == af9015_af9013_config[0].i2c_addr ||
-           addr == af9015_af9013_config[1].i2c_addr)
-               req.addr_len = 3;
-
-       return af9015_ctrl_msg(d, &req);
-}
-
-static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
-       int num)
-{
-       struct dvb_usb_device *d = i2c_get_adapdata(adap);
-       int ret = 0, i = 0;
-       u16 addr;
-       u8 uninitialized_var(mbox), addr_len;
-       struct req_t req;
-
-/*
-The bus lock is needed because there is two tuners both using same I2C-address.
-Due to that the only way to select correct tuner is use demodulator I2C-gate.
-
-................................................
-. AF9015 includes integrated AF9013 demodulator.
-. ____________                   ____________  .                ____________
-.|     uC     |                 |   demod    | .               |    tuner   |
-.|------------|                 |------------| .               |------------|
-.|   AF9015   |                 |  AF9013/5  | .               |   MXL5003  |
-.|            |--+----I2C-------|-----/ -----|-.-----I2C-------|            |
-.|            |  |              | addr 0x38  | .               |  addr 0xc6 |
-.|____________|  |              |____________| .               |____________|
-.................|..............................
-                |               ____________                   ____________
-                |              |   demod    |                 |    tuner   |
-                |              |------------|                 |------------|
-                |              |   AF9013   |                 |   MXL5003  |
-                +----I2C-------|-----/ -----|-------I2C-------|            |
-                               | addr 0x3a  |                 |  addr 0xc6 |
-                               |____________|                 |____________|
-*/
-       if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
-               return -EAGAIN;
-
-       while (i < num) {
-               if (msg[i].addr == af9015_af9013_config[0].i2c_addr ||
-                   msg[i].addr == af9015_af9013_config[1].i2c_addr) {
-                       addr = msg[i].buf[0] << 8;
-                       addr += msg[i].buf[1];
-                       mbox = msg[i].buf[2];
-                       addr_len = 3;
-               } else {
-                       addr = msg[i].buf[0];
-                       addr_len = 1;
-                       /* mbox is don't care in that case */
-               }
-
-               if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
-                       if (msg[i].len > 3 || msg[i+1].len > 61) {
-                               ret = -EOPNOTSUPP;
-                               goto error;
-                       }
-                       if (msg[i].addr == af9015_af9013_config[0].i2c_addr)
-                               req.cmd = READ_MEMORY;
-                       else
-                               req.cmd = READ_I2C;
-                       req.i2c_addr = msg[i].addr;
-                       req.addr = addr;
-                       req.mbox = mbox;
-                       req.addr_len = addr_len;
-                       req.data_len = msg[i+1].len;
-                       req.data = &msg[i+1].buf[0];
-                       ret = af9015_ctrl_msg(d, &req);
-                       i += 2;
-               } else if (msg[i].flags & I2C_M_RD) {
-                       if (msg[i].len > 61) {
-                               ret = -EOPNOTSUPP;
-                               goto error;
-                       }
-                       if (msg[i].addr ==
-                               af9015_af9013_config[0].i2c_addr) {
-                               ret = -EINVAL;
-                               goto error;
-                       }
-                       req.cmd = READ_I2C;
-                       req.i2c_addr = msg[i].addr;
-                       req.addr = addr;
-                       req.mbox = mbox;
-                       req.addr_len = addr_len;
-                       req.data_len = msg[i].len;
-                       req.data = &msg[i].buf[0];
-                       ret = af9015_ctrl_msg(d, &req);
-                       i += 1;
-               } else {
-                       if (msg[i].len > 21) {
-                               ret = -EOPNOTSUPP;
-                               goto error;
-                       }
-                       if (msg[i].addr == af9015_af9013_config[0].i2c_addr)
-                               req.cmd = WRITE_MEMORY;
-                       else
-                               req.cmd = WRITE_I2C;
-                       req.i2c_addr = msg[i].addr;
-                       req.addr = addr;
-                       req.mbox = mbox;
-                       req.addr_len = addr_len;
-                       req.data_len = msg[i].len-addr_len;
-                       req.data = &msg[i].buf[addr_len];
-                       ret = af9015_ctrl_msg(d, &req);
-                       i += 1;
-               }
-               if (ret)
-                       goto error;
-
-       }
-       ret = i;
-
-error:
-       mutex_unlock(&d->i2c_mutex);
-
-       return ret;
-}
-
-static u32 af9015_i2c_func(struct i2c_adapter *adapter)
-{
-       return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm af9015_i2c_algo = {
-       .master_xfer = af9015_i2c_xfer,
-       .functionality = af9015_i2c_func,
-};
-
-static int af9015_do_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit, u8 op)
-{
-       int ret;
-       u8 val, mask = 0x01;
-
-       ret = af9015_read_reg(d, addr, &val);
-       if (ret)
-               return ret;
-
-       mask <<= bit;
-       if (op) {
-               /* set bit */
-               val |= mask;
-       } else {
-               /* clear bit */
-               mask ^= 0xff;
-               val &= mask;
-       }
-
-       return af9015_write_reg(d, addr, val);
-}
-
-static int af9015_set_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit)
-{
-       return af9015_do_reg_bit(d, addr, bit, 1);
-}
-
-static int af9015_clear_reg_bit(struct dvb_usb_device *d, u16 addr, u8 bit)
-{
-       return af9015_do_reg_bit(d, addr, bit, 0);
-}
-
-static int af9015_init_endpoint(struct dvb_usb_device *d)
-{
-       int ret;
-       u16 frame_size;
-       u8  packet_size;
-       deb_info("%s: USB speed:%d\n", __func__, d->udev->speed);
-
-       /* Windows driver uses packet count 21 for USB1.1 and 348 for USB2.0.
-          We use smaller - about 1/4 from the original, 5 and 87. */
-#define TS_PACKET_SIZE            188
-
-#define TS_USB20_PACKET_COUNT      87
-#define TS_USB20_FRAME_SIZE       (TS_PACKET_SIZE*TS_USB20_PACKET_COUNT)
-
-#define TS_USB11_PACKET_COUNT       5
-#define TS_USB11_FRAME_SIZE       (TS_PACKET_SIZE*TS_USB11_PACKET_COUNT)
-
-#define TS_USB20_MAX_PACKET_SIZE  512
-#define TS_USB11_MAX_PACKET_SIZE   64
-
-       if (d->udev->speed == USB_SPEED_FULL) {
-               frame_size = TS_USB11_FRAME_SIZE/4;
-               packet_size = TS_USB11_MAX_PACKET_SIZE/4;
-       } else {
-               frame_size = TS_USB20_FRAME_SIZE/4;
-               packet_size = TS_USB20_MAX_PACKET_SIZE/4;
-       }
-
-       ret = af9015_set_reg_bit(d, 0xd507, 2); /* assert EP4 reset */
-       if (ret)
-               goto error;
-       ret = af9015_set_reg_bit(d, 0xd50b, 1); /* assert EP5 reset */
-       if (ret)
-               goto error;
-       ret = af9015_clear_reg_bit(d, 0xdd11, 5); /* disable EP4 */
-       if (ret)
-               goto error;
-       ret = af9015_clear_reg_bit(d, 0xdd11, 6); /* disable EP5 */
-       if (ret)
-               goto error;
-       ret = af9015_set_reg_bit(d, 0xdd11, 5); /* enable EP4 */
-       if (ret)
-               goto error;
-       if (af9015_config.dual_mode) {
-               ret = af9015_set_reg_bit(d, 0xdd11, 6); /* enable EP5 */
-               if (ret)
-                       goto error;
-       }
-       ret = af9015_clear_reg_bit(d, 0xdd13, 5); /* disable EP4 NAK */
-       if (ret)
-               goto error;
-       if (af9015_config.dual_mode) {
-               ret = af9015_clear_reg_bit(d, 0xdd13, 6); /* disable EP5 NAK */
-               if (ret)
-                       goto error;
-       }
-       /* EP4 xfer length */
-       ret = af9015_write_reg(d, 0xdd88, frame_size & 0xff);
-       if (ret)
-               goto error;
-       ret = af9015_write_reg(d, 0xdd89, frame_size >> 8);
-       if (ret)
-               goto error;
-       /* EP5 xfer length */
-       ret = af9015_write_reg(d, 0xdd8a, frame_size & 0xff);
-       if (ret)
-               goto error;
-       ret = af9015_write_reg(d, 0xdd8b, frame_size >> 8);
-       if (ret)
-               goto error;
-       ret = af9015_write_reg(d, 0xdd0c, packet_size); /* EP4 packet size */
-       if (ret)
-               goto error;
-       ret = af9015_write_reg(d, 0xdd0d, packet_size); /* EP5 packet size */
-       if (ret)
-               goto error;
-       ret = af9015_clear_reg_bit(d, 0xd507, 2); /* negate EP4 reset */
-       if (ret)
-               goto error;
-       if (af9015_config.dual_mode) {
-               ret = af9015_clear_reg_bit(d, 0xd50b, 1); /* negate EP5 reset */
-               if (ret)
-                       goto error;
-       }
-
-       /* enable / disable mp2if2 */
-       if (af9015_config.dual_mode)
-               ret = af9015_set_reg_bit(d, 0xd50b, 0);
-       else
-               ret = af9015_clear_reg_bit(d, 0xd50b, 0);
-
-error:
-       if (ret)
-               err("endpoint init failed:%d", ret);
-       return ret;
-}
-
-static int af9015_copy_firmware(struct dvb_usb_device *d)
-{
-       int ret;
-       u8 fw_params[4];
-       u8 val, i;
-       struct req_t req = {COPY_FIRMWARE, 0, 0x5100, 0, 0, sizeof(fw_params),
-               fw_params };
-       deb_info("%s:\n", __func__);
-
-       fw_params[0] = af9015_config.firmware_size >> 8;
-       fw_params[1] = af9015_config.firmware_size & 0xff;
-       fw_params[2] = af9015_config.firmware_checksum >> 8;
-       fw_params[3] = af9015_config.firmware_checksum & 0xff;
-
-       /* wait 2nd demodulator ready */
-       msleep(100);
-
-       ret = af9015_read_reg_i2c(d,
-               af9015_af9013_config[1].i2c_addr, 0x98be, &val);
-       if (ret)
-               goto error;
-       else
-               deb_info("%s: firmware status:%02x\n", __func__, val);
-
-       if (val == 0x0c) /* fw is running, no need for download */
-               goto exit;
-
-       /* set I2C master clock to fast (to speed up firmware copy) */
-       ret = af9015_write_reg(d, 0xd416, 0x04); /* 0x04 * 400ns */
-       if (ret)
-               goto error;
-
-       msleep(50);
-
-       /* copy firmware */
-       ret = af9015_ctrl_msg(d, &req);
-       if (ret)
-               err("firmware copy cmd failed:%d", ret);
-       deb_info("%s: firmware copy done\n", __func__);
-
-       /* set I2C master clock back to normal */
-       ret = af9015_write_reg(d, 0xd416, 0x14); /* 0x14 * 400ns */
-       if (ret)
-               goto error;
-
-       /* request boot firmware */
-       ret = af9015_write_reg_i2c(d, af9015_af9013_config[1].i2c_addr,
-               0xe205, 1);
-       deb_info("%s: firmware boot cmd status:%d\n", __func__, ret);
-       if (ret)
-               goto error;
-
-       for (i = 0; i < 15; i++) {
-               msleep(100);
-
-               /* check firmware status */
-               ret = af9015_read_reg_i2c(d,
-                       af9015_af9013_config[1].i2c_addr, 0x98be, &val);
-               deb_info("%s: firmware status cmd status:%d fw status:%02x\n",
-                       __func__, ret, val);
-               if (ret)
-                       goto error;
-
-               if (val == 0x0c || val == 0x04) /* success or fail */
-                       break;
-       }
-
-       if (val == 0x04) {
-               err("firmware did not run");
-               ret = -1;
-       } else if (val != 0x0c) {
-               err("firmware boot timeout");
-               ret = -1;
-       }
-
-error:
-exit:
-       return ret;
-}
-
-/* hash (and dump) eeprom */
-static int af9015_eeprom_hash(struct usb_device *udev)
-{
-       static const unsigned int eeprom_size = 256;
-       unsigned int reg;
-       int ret;
-       u8 val, *eeprom;
-       struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val};
-
-       eeprom = kmalloc(eeprom_size, GFP_KERNEL);
-       if (eeprom == NULL)
-               return -ENOMEM;
-
-       for (reg = 0; reg < eeprom_size; reg++) {
-               req.addr = reg;
-               ret = af9015_rw_udev(udev, &req);
-               if (ret)
-                       goto free;
-               eeprom[reg] = val;
-       }
-
-       if (dvb_usb_af9015_debug & 0x01)
-               print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, eeprom,
-                               eeprom_size);
-
-       BUG_ON(eeprom_size % 4);
-
-       af9015_config.eeprom_sum = 0;
-       for (reg = 0; reg < eeprom_size / sizeof(u32); reg++) {
-               af9015_config.eeprom_sum *= GOLDEN_RATIO_PRIME_32;
-               af9015_config.eeprom_sum += le32_to_cpu(((u32 *)eeprom)[reg]);
-       }
-
-       deb_info("%s: eeprom sum=%.8x\n", __func__, af9015_config.eeprom_sum);
-
-       ret = 0;
-free:
-       kfree(eeprom);
-       return ret;
-}
-
-static int af9015_init(struct dvb_usb_device *d)
-{
-       int ret;
-       deb_info("%s:\n", __func__);
-
-       /* init RC canary */
-       ret = af9015_write_reg(d, 0x98e9, 0xff);
-       if (ret)
-               goto error;
-
-       ret = af9015_init_endpoint(d);
-       if (ret)
-               goto error;
-
-error:
-       return ret;
-}
-
-static int af9015_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
-       int ret;
-       deb_info("%s: onoff:%d\n", __func__, onoff);
-
-       if (onoff)
-               ret = af9015_set_reg_bit(adap->dev, 0xd503, 0);
-       else
-               ret = af9015_clear_reg_bit(adap->dev, 0xd503, 0);
-
-       return ret;
-}
-
-static int af9015_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
-       int onoff)
-{
-       int ret;
-       u8 idx;
-
-       deb_info("%s: set pid filter, index %d, pid %x, onoff %d\n",
-               __func__, index, pid, onoff);
-
-       ret = af9015_write_reg(adap->dev, 0xd505, (pid & 0xff));
-       if (ret)
-               goto error;
-
-       ret = af9015_write_reg(adap->dev, 0xd506, (pid >> 8));
-       if (ret)
-               goto error;
-
-       idx = ((index & 0x1f) | (1 << 5));
-       ret = af9015_write_reg(adap->dev, 0xd504, idx);
-
-error:
-       return ret;
-}
-
-static int af9015_download_firmware(struct usb_device *udev,
-       const struct firmware *fw)
-{
-       int i, len, remaining, ret;
-       struct req_t req = {DOWNLOAD_FIRMWARE, 0, 0, 0, 0, 0, NULL};
-       u16 checksum = 0;
-
-       deb_info("%s:\n", __func__);
-
-       /* calc checksum */
-       for (i = 0; i < fw->size; i++)
-               checksum += fw->data[i];
-
-       af9015_config.firmware_size = fw->size;
-       af9015_config.firmware_checksum = checksum;
-
-       #define FW_ADDR 0x5100 /* firmware start address */
-       #define LEN_MAX 55 /* max packet size */
-       for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) {
-               len = remaining;
-               if (len > LEN_MAX)
-                       len = LEN_MAX;
-
-               req.data_len = len;
-               req.data = (u8 *) &fw->data[fw->size - remaining];
-               req.addr = FW_ADDR + fw->size - remaining;
-
-               ret = af9015_rw_udev(udev, &req);
-               if (ret) {
-                       err("firmware download failed:%d", ret);
-                       goto error;
-               }
-       }
-
-       /* firmware loaded, request boot */
-       req.cmd = BOOT;
-       ret = af9015_rw_udev(udev, &req);
-       if (ret) {
-               err("firmware boot failed:%d", ret);
-               goto error;
-       }
-
-error:
-       return ret;
-}
-
-struct af9015_rc_setup {
-       unsigned int id;
-       char *rc_codes;
-};
-
-static char *af9015_rc_setup_match(unsigned int id,
-       const struct af9015_rc_setup *table)
-{
-       for (; table->rc_codes; table++)
-               if (table->id == id)
-                       return table->rc_codes;
-       return NULL;
-}
-
-static const struct af9015_rc_setup af9015_rc_setup_modparam[] = {
-       { AF9015_REMOTE_A_LINK_DTU_M, RC_MAP_ALINK_DTU_M },
-       { AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, RC_MAP_MSI_DIGIVOX_II },
-       { AF9015_REMOTE_MYGICTV_U718, RC_MAP_TOTAL_MEDIA_IN_HAND },
-       { AF9015_REMOTE_DIGITTRADE_DVB_T, RC_MAP_DIGITTRADE },
-       { AF9015_REMOTE_AVERMEDIA_KS, RC_MAP_AVERMEDIA_RM_KS },
-       { }
-};
-
-static const struct af9015_rc_setup af9015_rc_setup_hashes[] = {
-       { 0xb8feb708, RC_MAP_MSI_DIGIVOX_II },
-       { 0xa3703d00, RC_MAP_ALINK_DTU_M },
-       { 0x9b7dc64e, RC_MAP_TOTAL_MEDIA_IN_HAND }, /* MYGICTV U718 */
-       { 0x5d49e3db, RC_MAP_DIGITTRADE }, /* LC-Power LC-USB-DVBT */
-       { }
-};
-
-static const struct af9015_rc_setup af9015_rc_setup_usbids[] = {
-       { (USB_VID_TERRATEC << 16) | USB_PID_TERRATEC_CINERGY_T_STICK_RC,
-               RC_MAP_TERRATEC_SLIM_2 },
-       { (USB_VID_TERRATEC << 16) | USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC,
-               RC_MAP_TERRATEC_SLIM },
-       { (USB_VID_VISIONPLUS << 16) | USB_PID_AZUREWAVE_AD_TU700,
-               RC_MAP_AZUREWAVE_AD_TU700 },
-       { (USB_VID_VISIONPLUS << 16) | USB_PID_TINYTWIN,
-               RC_MAP_AZUREWAVE_AD_TU700 },
-       { (USB_VID_MSI_2 << 16) | USB_PID_MSI_DIGI_VOX_MINI_III,
-               RC_MAP_MSI_DIGIVOX_III },
-       { (USB_VID_MSI_2 << 16) | USB_PID_MSI_DIGIVOX_DUO,
-               RC_MAP_MSI_DIGIVOX_III },
-       { (USB_VID_LEADTEK << 16) | USB_PID_WINFAST_DTV_DONGLE_GOLD,
-               RC_MAP_LEADTEK_Y04G0051 },
-       { (USB_VID_LEADTEK << 16) | USB_PID_WINFAST_DTV2000DS,
-               RC_MAP_LEADTEK_Y04G0051 },
-       { (USB_VID_AVERMEDIA << 16) | USB_PID_AVERMEDIA_VOLAR_X,
-               RC_MAP_AVERMEDIA_M135A },
-       { (USB_VID_AFATECH << 16) | USB_PID_TREKSTOR_DVBT,
-               RC_MAP_TREKSTOR },
-       { (USB_VID_KWORLD_2 << 16) | USB_PID_TINYTWIN_2,
-               RC_MAP_DIGITALNOW_TINYTWIN },
-       { (USB_VID_GTEK << 16) | USB_PID_TINYTWIN_3,
-               RC_MAP_DIGITALNOW_TINYTWIN },
-       { (USB_VID_KWORLD_2 << 16) | USB_PID_SVEON_STV22,
-               RC_MAP_MSI_DIGIVOX_III },
-       { }
-};
-
-static void af9015_set_remote_config(struct usb_device *udev,
-               struct dvb_usb_device_properties *props)
-{
-       u16 vid = le16_to_cpu(udev->descriptor.idVendor);
-       u16 pid = le16_to_cpu(udev->descriptor.idProduct);
-
-       /* try to load remote based module param */
-       props->rc.core.rc_codes = af9015_rc_setup_match(
-               dvb_usb_af9015_remote, af9015_rc_setup_modparam);
-
-       /* try to load remote based eeprom hash */
-       if (!props->rc.core.rc_codes)
-               props->rc.core.rc_codes = af9015_rc_setup_match(
-                       af9015_config.eeprom_sum, af9015_rc_setup_hashes);
-
-       /* try to load remote based USB ID */
-       if (!props->rc.core.rc_codes)
-               props->rc.core.rc_codes = af9015_rc_setup_match(
-                       (vid << 16) | pid, af9015_rc_setup_usbids);
-
-       /* try to load remote based USB iManufacturer string */
-       if (!props->rc.core.rc_codes && vid == USB_VID_AFATECH) {
-               /* Check USB manufacturer and product strings and try
-                  to determine correct remote in case of chip vendor
-                  reference IDs are used.
-                  DO NOT ADD ANYTHING NEW HERE. Use hashes instead. */
-               char manufacturer[10];
-               memset(manufacturer, 0, sizeof(manufacturer));
-               usb_string(udev, udev->descriptor.iManufacturer,
-                       manufacturer, sizeof(manufacturer));
-               if (!strcmp("MSI", manufacturer)) {
-                       /* iManufacturer 1 MSI
-                          iProduct      2 MSI K-VOX */
-                       props->rc.core.rc_codes = af9015_rc_setup_match(
-                               AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
-                               af9015_rc_setup_modparam);
-               }
-       }
-
-       /* finally load "empty" just for leaving IR receiver enabled */
-       if (!props->rc.core.rc_codes)
-               props->rc.core.rc_codes = RC_MAP_EMPTY;
-
-       return;
-}
-
-static int af9015_read_config(struct usb_device *udev)
-{
-       int ret;
-       u8 val, i, offset = 0;
-       struct req_t req = {READ_I2C, AF9015_I2C_EEPROM, 0, 0, 1, 1, &val};
-
-       /* IR remote controller */
-       req.addr = AF9015_EEPROM_IR_MODE;
-       /* first message will timeout often due to possible hw bug */
-       for (i = 0; i < 4; i++) {
-               ret = af9015_rw_udev(udev, &req);
-               if (!ret)
-                       break;
-       }
-       if (ret)
-               goto error;
-
-       ret = af9015_eeprom_hash(udev);
-       if (ret)
-               goto error;
-
-       deb_info("%s: IR mode=%d\n", __func__, val);
-       for (i = 0; i < af9015_properties_count; i++) {
-               if (val == AF9015_IR_MODE_DISABLED)
-                       af9015_properties[i].rc.core.rc_codes = NULL;
-               else
-                       af9015_set_remote_config(udev, &af9015_properties[i]);
-       }
-
-       /* TS mode - one or two receivers */
-       req.addr = AF9015_EEPROM_TS_MODE;
-       ret = af9015_rw_udev(udev, &req);
-       if (ret)
-               goto error;
-       af9015_config.dual_mode = val;
-       deb_info("%s: TS mode=%d\n", __func__, af9015_config.dual_mode);
-
-       /* Set adapter0 buffer size according to USB port speed, adapter1 buffer
-          size can be static because it is enabled only USB2.0 */
-       for (i = 0; i < af9015_properties_count; i++) {
-               /* USB1.1 set smaller buffersize and disable 2nd adapter */
-               if (udev->speed == USB_SPEED_FULL) {
-                       af9015_properties[i].adapter[0].fe[0].stream.u.bulk.buffersize
-                               = TS_USB11_FRAME_SIZE;
-                       /* disable 2nd adapter because we don't have
-                          PID-filters */
-                       af9015_config.dual_mode = 0;
-               } else {
-                       af9015_properties[i].adapter[0].fe[0].stream.u.bulk.buffersize
-                               = TS_USB20_FRAME_SIZE;
-               }
-       }
-
-       if (af9015_config.dual_mode) {
-               /* read 2nd demodulator I2C address */
-               req.addr = AF9015_EEPROM_DEMOD2_I2C;
-               ret = af9015_rw_udev(udev, &req);
-               if (ret)
-                       goto error;
-               af9015_af9013_config[1].i2c_addr = val;
-
-               /* enable 2nd adapter */
-               for (i = 0; i < af9015_properties_count; i++)
-                       af9015_properties[i].num_adapters = 2;
-
-       } else {
-                /* disable 2nd adapter */
-               for (i = 0; i < af9015_properties_count; i++)
-                       af9015_properties[i].num_adapters = 1;
-       }
-
-       for (i = 0; i < af9015_properties[0].num_adapters; i++) {
-               if (i == 1)
-                       offset = AF9015_EEPROM_OFFSET;
-               /* xtal */
-               req.addr = AF9015_EEPROM_XTAL_TYPE1 + offset;
-               ret = af9015_rw_udev(udev, &req);
-               if (ret)
-                       goto error;
-               switch (val) {
-               case 0:
-                       af9015_af9013_config[i].clock = 28800000;
-                       break;
-               case 1:
-                       af9015_af9013_config[i].clock = 20480000;
-                       break;
-               case 2:
-                       af9015_af9013_config[i].clock = 28000000;
-                       break;
-               case 3:
-                       af9015_af9013_config[i].clock = 25000000;
-                       break;
-               };
-               deb_info("%s: [%d] xtal=%d set clock=%d\n", __func__, i,
-                       val, af9015_af9013_config[i].clock);
-
-               /* IF frequency */
-               req.addr = AF9015_EEPROM_IF1H + offset;
-               ret = af9015_rw_udev(udev, &req);
-               if (ret)
-                       goto error;
-
-               af9015_af9013_config[i].if_frequency = val << 8;
-
-               req.addr = AF9015_EEPROM_IF1L + offset;
-               ret = af9015_rw_udev(udev, &req);
-               if (ret)
-                       goto error;
-
-               af9015_af9013_config[i].if_frequency += val;
-               af9015_af9013_config[i].if_frequency *= 1000;
-               deb_info("%s: [%d] IF frequency=%d\n", __func__, i,
-                       af9015_af9013_config[0].if_frequency);
-
-               /* MT2060 IF1 */
-               req.addr = AF9015_EEPROM_MT2060_IF1H  + offset;
-               ret = af9015_rw_udev(udev, &req);
-               if (ret)
-                       goto error;
-               af9015_config.mt2060_if1[i] = val << 8;
-               req.addr = AF9015_EEPROM_MT2060_IF1L + offset;
-               ret = af9015_rw_udev(udev, &req);
-               if (ret)
-                       goto error;
-               af9015_config.mt2060_if1[i] += val;
-               deb_info("%s: [%d] MT2060 IF1=%d\n", __func__, i,
-                       af9015_config.mt2060_if1[i]);
-
-               /* tuner */
-               req.addr =  AF9015_EEPROM_TUNER_ID1 + offset;
-               ret = af9015_rw_udev(udev, &req);
-               if (ret)
-                       goto error;
-               switch (val) {
-               case AF9013_TUNER_ENV77H11D5:
-               case AF9013_TUNER_MT2060:
-               case AF9013_TUNER_QT1010:
-               case AF9013_TUNER_UNKNOWN:
-               case AF9013_TUNER_MT2060_2:
-               case AF9013_TUNER_TDA18271:
-               case AF9013_TUNER_QT1010A:
-               case AF9013_TUNER_TDA18218:
-                       af9015_af9013_config[i].spec_inv = 1;
-                       break;
-               case AF9013_TUNER_MXL5003D:
-               case AF9013_TUNER_MXL5005D:
-               case AF9013_TUNER_MXL5005R:
-               case AF9013_TUNER_MXL5007T:
-                       af9015_af9013_config[i].spec_inv = 0;
-                       break;
-               case AF9013_TUNER_MC44S803:
-                       af9015_af9013_config[i].gpio[1] = AF9013_GPIO_LO;
-                       af9015_af9013_config[i].spec_inv = 1;
-                       break;
-               default:
-                       warn("tuner id=%d not supported, please report!", val);
-                       return -ENODEV;
-               };
-
-               af9015_af9013_config[i].tuner = val;
-               deb_info("%s: [%d] tuner id=%d\n", __func__, i, val);
-       }
-
-error:
-       if (ret)
-               err("eeprom read failed=%d", ret);
-
-       /* AverMedia AVerTV Volar Black HD (A850) device have bad EEPROM
-          content :-( Override some wrong values here. Ditto for the
-          AVerTV Red HD+ (A850T) device. */
-       if (le16_to_cpu(udev->descriptor.idVendor) == USB_VID_AVERMEDIA &&
-               ((le16_to_cpu(udev->descriptor.idProduct) ==
-                       USB_PID_AVERMEDIA_A850) ||
-               (le16_to_cpu(udev->descriptor.idProduct) ==
-                       USB_PID_AVERMEDIA_A850T))) {
-               deb_info("%s: AverMedia A850: overriding config\n", __func__);
-               /* disable dual mode */
-               af9015_config.dual_mode = 0;
-                /* disable 2nd adapter */
-               for (i = 0; i < af9015_properties_count; i++)
-                       af9015_properties[i].num_adapters = 1;
-
-               /* set correct IF */
-               af9015_af9013_config[0].if_frequency = 4570000;
-       }
-
-       return ret;
-}
-
-static int af9015_identify_state(struct usb_device *udev,
-                                struct dvb_usb_device_properties *props,
-                                struct dvb_usb_device_description **desc,
-                                int *cold)
-{
-       int ret;
-       u8 reply;
-       struct req_t req = {GET_CONFIG, 0, 0, 0, 0, 1, &reply};
-
-       ret = af9015_rw_udev(udev, &req);
-       if (ret)
-               return ret;
-
-       deb_info("%s: reply:%02x\n", __func__, reply);
-       if (reply == 0x02)
-               *cold = 0;
-       else
-               *cold = 1;
-
-       return ret;
-}
-
-static int af9015_rc_query(struct dvb_usb_device *d)
-{
-       struct af9015_state *priv = d->priv;
-       int ret;
-       u8 buf[17];
-
-       /* read registers needed to detect remote controller code */
-       ret = af9015_read_regs(d, 0x98d9, buf, sizeof(buf));
-       if (ret)
-               goto error;
-
-       /* If any of these are non-zero, assume invalid data */
-       if (buf[1] || buf[2] || buf[3])
-               return ret;
-
-       /* Check for repeat of previous code */
-       if ((priv->rc_repeat != buf[6] || buf[0]) &&
-                                       !memcmp(&buf[12], priv->rc_last, 4)) {
-               deb_rc("%s: key repeated\n", __func__);
-               rc_keydown(d->rc_dev, priv->rc_keycode, 0);
-               priv->rc_repeat = buf[6];
-               return ret;
-       }
-
-       /* Only process key if canary killed */
-       if (buf[16] != 0xff && buf[0] != 0x01) {
-               deb_rc("%s: key pressed %02x %02x %02x %02x\n", __func__,
-                       buf[12], buf[13], buf[14], buf[15]);
-
-               /* Reset the canary */
-               ret = af9015_write_reg(d, 0x98e9, 0xff);
-               if (ret)
-                       goto error;
-
-               /* Remember this key */
-               memcpy(priv->rc_last, &buf[12], 4);
-               if (buf[14] == (u8) ~buf[15]) {
-                       if (buf[12] == (u8) ~buf[13]) {
-                               /* NEC */
-                               priv->rc_keycode = buf[12] << 8 | buf[14];
-                       } else {
-                               /* NEC extended*/
-                               priv->rc_keycode = buf[12] << 16 |
-                                       buf[13] << 8 | buf[14];
-                       }
-               } else {
-                       /* 32 bit NEC */
-                       priv->rc_keycode = buf[12] << 24 | buf[13] << 16 |
-                                       buf[14] << 8 | buf[15];
-               }
-               rc_keydown(d->rc_dev, priv->rc_keycode, 0);
-       } else {
-               deb_rc("%s: no key press\n", __func__);
-               /* Invalidate last keypress */
-               /* Not really needed, but helps with debug */
-               priv->rc_last[2] = priv->rc_last[3];
-       }
-
-       priv->rc_repeat = buf[6];
-
-error:
-       if (ret)
-               err("%s: failed:%d", __func__, ret);
-
-       return ret;
-}
-
-/* override demod callbacks for resource locking */
-static int af9015_af9013_set_frontend(struct dvb_frontend *fe)
-{
-       int ret;
-       struct dvb_usb_adapter *adap = fe->dvb->priv;
-       struct af9015_state *priv = adap->dev->priv;
-
-       if (mutex_lock_interruptible(&adap->dev->usb_mutex))
-               return -EAGAIN;
-
-       ret = priv->set_frontend[adap->id](fe);
-
-       mutex_unlock(&adap->dev->usb_mutex);
-
-       return ret;
-}
-
-/* override demod callbacks for resource locking */
-static int af9015_af9013_read_status(struct dvb_frontend *fe,
-       fe_status_t *status)
-{
-       int ret;
-       struct dvb_usb_adapter *adap = fe->dvb->priv;
-       struct af9015_state *priv = adap->dev->priv;
-
-       if (mutex_lock_interruptible(&adap->dev->usb_mutex))
-               return -EAGAIN;
-
-       ret = priv->read_status[adap->id](fe, status);
-
-       mutex_unlock(&adap->dev->usb_mutex);
-
-       return ret;
-}
-
-/* override demod callbacks for resource locking */
-static int af9015_af9013_init(struct dvb_frontend *fe)
-{
-       int ret;
-       struct dvb_usb_adapter *adap = fe->dvb->priv;
-       struct af9015_state *priv = adap->dev->priv;
-
-       if (mutex_lock_interruptible(&adap->dev->usb_mutex))
-               return -EAGAIN;
-
-       ret = priv->init[adap->id](fe);
-
-       mutex_unlock(&adap->dev->usb_mutex);
-
-       return ret;
-}
-
-/* override demod callbacks for resource locking */
-static int af9015_af9013_sleep(struct dvb_frontend *fe)
-{
-       int ret;
-       struct dvb_usb_adapter *adap = fe->dvb->priv;
-       struct af9015_state *priv = adap->dev->priv;
-
-       if (mutex_lock_interruptible(&adap->dev->usb_mutex))
-               return -EAGAIN;
-
-       ret = priv->sleep[adap->id](fe);
-
-       mutex_unlock(&adap->dev->usb_mutex);
-
-       return ret;
-}
-
-/* override tuner callbacks for resource locking */
-static int af9015_tuner_init(struct dvb_frontend *fe)
-{
-       int ret;
-       struct dvb_usb_adapter *adap = fe->dvb->priv;
-       struct af9015_state *priv = adap->dev->priv;
-
-       if (mutex_lock_interruptible(&adap->dev->usb_mutex))
-               return -EAGAIN;
-
-       ret = priv->tuner_init[adap->id](fe);
-
-       mutex_unlock(&adap->dev->usb_mutex);
-
-       return ret;
-}
-
-/* override tuner callbacks for resource locking */
-static int af9015_tuner_sleep(struct dvb_frontend *fe)
-{
-       int ret;
-       struct dvb_usb_adapter *adap = fe->dvb->priv;
-       struct af9015_state *priv = adap->dev->priv;
-
-       if (mutex_lock_interruptible(&adap->dev->usb_mutex))
-               return -EAGAIN;
-
-       ret = priv->tuner_sleep[adap->id](fe);
-
-       mutex_unlock(&adap->dev->usb_mutex);
-
-       return ret;
-}
-
-
-static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap)
-{
-       int ret;
-       struct af9015_state *state = adap->dev->priv;
-
-       if (adap->id == 1) {
-               /* copy firmware to 2nd demodulator */
-               if (af9015_config.dual_mode) {
-                       ret = af9015_copy_firmware(adap->dev);
-                       if (ret) {
-                               err("firmware copy to 2nd frontend " \
-                                       "failed, will disable it");
-                               af9015_config.dual_mode = 0;
-                               return -ENODEV;
-                       }
-               } else {
-                       return -ENODEV;
-               }
-       }
-
-       /* attach demodulator */
-       adap->fe_adap[0].fe = dvb_attach(af9013_attach,
-               &af9015_af9013_config[adap->id], &adap->dev->i2c_adap);
-
-       /*
-        * AF9015 firmware does not like if it gets interrupted by I2C adapter
-        * request on some critical phases. During normal operation I2C adapter
-        * is used only 2nd demodulator and tuner on dual tuner devices.
-        * Override demodulator callbacks and use mutex for limit access to
-        * those "critical" paths to keep AF9015 happy.
-        * Note: we abuse unused usb_mutex here.
-        */
-       if (adap->fe_adap[0].fe) {
-               state->set_frontend[adap->id] =
-                       adap->fe_adap[0].fe->ops.set_frontend;
-               adap->fe_adap[0].fe->ops.set_frontend =
-                       af9015_af9013_set_frontend;
-
-               state->read_status[adap->id] =
-                       adap->fe_adap[0].fe->ops.read_status;
-               adap->fe_adap[0].fe->ops.read_status =
-                       af9015_af9013_read_status;
-
-               state->init[adap->id] = adap->fe_adap[0].fe->ops.init;
-               adap->fe_adap[0].fe->ops.init = af9015_af9013_init;
-
-               state->sleep[adap->id] = adap->fe_adap[0].fe->ops.sleep;
-               adap->fe_adap[0].fe->ops.sleep = af9015_af9013_sleep;
-       }
-
-       return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
-}
-
-static struct mt2060_config af9015_mt2060_config = {
-       .i2c_address = 0xc0,
-       .clock_out = 0,
-};
-
-static struct qt1010_config af9015_qt1010_config = {
-       .i2c_address = 0xc4,
-};
-
-static struct tda18271_config af9015_tda18271_config = {
-       .gate = TDA18271_GATE_DIGITAL,
-       .small_i2c = TDA18271_16_BYTE_CHUNK_INIT,
-};
-
-static struct mxl5005s_config af9015_mxl5003_config = {
-       .i2c_address     = 0xc6,
-       .if_freq         = IF_FREQ_4570000HZ,
-       .xtal_freq       = CRYSTAL_FREQ_16000000HZ,
-       .agc_mode        = MXL_SINGLE_AGC,
-       .tracking_filter = MXL_TF_DEFAULT,
-       .rssi_enable     = MXL_RSSI_ENABLE,
-       .cap_select      = MXL_CAP_SEL_ENABLE,
-       .div_out         = MXL_DIV_OUT_4,
-       .clock_out       = MXL_CLOCK_OUT_DISABLE,
-       .output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
-       .top             = MXL5005S_TOP_25P2,
-       .mod_mode        = MXL_DIGITAL_MODE,
-       .if_mode         = MXL_ZERO_IF,
-       .AgcMasterByte   = 0x00,
-};
-
-static struct mxl5005s_config af9015_mxl5005_config = {
-       .i2c_address     = 0xc6,
-       .if_freq         = IF_FREQ_4570000HZ,
-       .xtal_freq       = CRYSTAL_FREQ_16000000HZ,
-       .agc_mode        = MXL_SINGLE_AGC,
-       .tracking_filter = MXL_TF_OFF,
-       .rssi_enable     = MXL_RSSI_ENABLE,
-       .cap_select      = MXL_CAP_SEL_ENABLE,
-       .div_out         = MXL_DIV_OUT_4,
-       .clock_out       = MXL_CLOCK_OUT_DISABLE,
-       .output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
-       .top             = MXL5005S_TOP_25P2,
-       .mod_mode        = MXL_DIGITAL_MODE,
-       .if_mode         = MXL_ZERO_IF,
-       .AgcMasterByte   = 0x00,
-};
-
-static struct mc44s803_config af9015_mc44s803_config = {
-       .i2c_address = 0xc0,
-       .dig_out = 1,
-};
-
-static struct tda18218_config af9015_tda18218_config = {
-       .i2c_address = 0xc0,
-       .i2c_wr_max = 21, /* max wr bytes AF9015 I2C adap can handle at once */
-};
-
-static struct mxl5007t_config af9015_mxl5007t_config = {
-       .xtal_freq_hz = MxL_XTAL_24_MHZ,
-       .if_freq_hz = MxL_IF_4_57_MHZ,
-};
-
-static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
-{
-       int ret;
-       struct af9015_state *state = adap->dev->priv;
-       deb_info("%s:\n", __func__);
-
-       switch (af9015_af9013_config[adap->id].tuner) {
-       case AF9013_TUNER_MT2060:
-       case AF9013_TUNER_MT2060_2:
-               ret = dvb_attach(mt2060_attach, adap->fe_adap[0].fe,
-                       &adap->dev->i2c_adap, &af9015_mt2060_config,
-                       af9015_config.mt2060_if1[adap->id])
-                       == NULL ? -ENODEV : 0;
-               break;
-       case AF9013_TUNER_QT1010:
-       case AF9013_TUNER_QT1010A:
-               ret = dvb_attach(qt1010_attach, adap->fe_adap[0].fe,
-                       &adap->dev->i2c_adap,
-                       &af9015_qt1010_config) == NULL ? -ENODEV : 0;
-               break;
-       case AF9013_TUNER_TDA18271:
-               ret = dvb_attach(tda18271_attach, adap->fe_adap[0].fe, 0xc0,
-                       &adap->dev->i2c_adap,
-                       &af9015_tda18271_config) == NULL ? -ENODEV : 0;
-               break;
-       case AF9013_TUNER_TDA18218:
-               ret = dvb_attach(tda18218_attach, adap->fe_adap[0].fe,
-                       &adap->dev->i2c_adap,
-                       &af9015_tda18218_config) == NULL ? -ENODEV : 0;
-               break;
-       case AF9013_TUNER_MXL5003D:
-               ret = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe,
-                       &adap->dev->i2c_adap,
-                       &af9015_mxl5003_config) == NULL ? -ENODEV : 0;
-               break;
-       case AF9013_TUNER_MXL5005D:
-       case AF9013_TUNER_MXL5005R:
-               ret = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe,
-                       &adap->dev->i2c_adap,
-                       &af9015_mxl5005_config) == NULL ? -ENODEV : 0;
-               break;
-       case AF9013_TUNER_ENV77H11D5:
-               ret = dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0xc0,
-                       &adap->dev->i2c_adap,
-                       DVB_PLL_TDA665X) == NULL ? -ENODEV : 0;
-               break;
-       case AF9013_TUNER_MC44S803:
-               ret = dvb_attach(mc44s803_attach, adap->fe_adap[0].fe,
-                       &adap->dev->i2c_adap,
-                       &af9015_mc44s803_config) == NULL ? -ENODEV : 0;
-               break;
-       case AF9013_TUNER_MXL5007T:
-               ret = dvb_attach(mxl5007t_attach, adap->fe_adap[0].fe,
-                       &adap->dev->i2c_adap,
-                       0xc0, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0;
-               break;
-       case AF9013_TUNER_UNKNOWN:
-       default:
-               ret = -ENODEV;
-               err("Unknown tuner id:%d",
-                       af9015_af9013_config[adap->id].tuner);
-       }
-
-       if (adap->fe_adap[0].fe->ops.tuner_ops.init) {
-               state->tuner_init[adap->id] =
-                       adap->fe_adap[0].fe->ops.tuner_ops.init;
-               adap->fe_adap[0].fe->ops.tuner_ops.init = af9015_tuner_init;
-       }
-
-       if (adap->fe_adap[0].fe->ops.tuner_ops.sleep) {
-               state->tuner_sleep[adap->id] =
-                       adap->fe_adap[0].fe->ops.tuner_ops.sleep;
-               adap->fe_adap[0].fe->ops.tuner_ops.sleep = af9015_tuner_sleep;
-       }
-
-       return ret;
-}
-
-enum af9015_usb_table_entry {
-       AFATECH_9015,
-       AFATECH_9016,
-       WINFAST_DTV_GOLD,
-       PINNACLE_PCTV_71E,
-       KWORLD_PLUSTV_399U,
-       TINYTWIN,
-       AZUREWAVE_TU700,
-       TERRATEC_AF9015,
-       KWORLD_PLUSTV_PC160,
-       AVERTV_VOLAR_X,
-       XTENSIONS_380U,
-       MSI_DIGIVOX_DUO,
-       AVERTV_VOLAR_X_REV2,
-       TELESTAR_STARSTICK_2,
-       AVERMEDIA_A309_USB,
-       MSI_DIGIVOX_MINI_III,
-       KWORLD_E396,
-       KWORLD_E39B,
-       KWORLD_E395,
-       TREKSTOR_DVBT,
-       AVERTV_A850,
-       AVERTV_A805,
-       CONCEPTRONIC_CTVDIGRCU,
-       KWORLD_MC810,
-       GENIUS_TVGO_DVB_T03,
-       KWORLD_399U_2,
-       KWORLD_PC160_T,
-       SVEON_STV20,
-       TINYTWIN_2,
-       WINFAST_DTV2000DS,
-       KWORLD_UB383_T,
-       KWORLD_E39A,
-       AVERMEDIA_A815M,
-       CINERGY_T_STICK_RC,
-       CINERGY_T_DUAL_RC,
-       AVERTV_A850T,
-       TINYTWIN_3,
-       SVEON_STV22,
-};
-
-static struct usb_device_id af9015_usb_table[] = {
-       [AFATECH_9015] = {
-               USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9015)},
-       [AFATECH_9016] = {
-               USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9015_9016)},
-       [WINFAST_DTV_GOLD] = {
-               USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_GOLD)},
-       [PINNACLE_PCTV_71E] = {
-               USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV71E)},
-       [KWORLD_PLUSTV_399U] = {
-               USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U)},
-       [TINYTWIN] = {
-               USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TINYTWIN)},
-       [AZUREWAVE_TU700] = {
-               USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_AZUREWAVE_AD_TU700)},
-       [TERRATEC_AF9015] = {
-               USB_DEVICE(USB_VID_TERRATEC,
-                               USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2)},
-       [KWORLD_PLUSTV_PC160] = {
-               USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_2T)},
-       [AVERTV_VOLAR_X] = {
-               USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X)},
-       [XTENSIONS_380U] = {
-               USB_DEVICE(USB_VID_XTENSIONS, USB_PID_XTENSIONS_XD_380)},
-       [MSI_DIGIVOX_DUO] = {
-               USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGIVOX_DUO)},
-       [AVERTV_VOLAR_X_REV2] = {
-               USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_X_2)},
-       [TELESTAR_STARSTICK_2] = {
-               USB_DEVICE(USB_VID_TELESTAR,  USB_PID_TELESTAR_STARSTICK_2)},
-       [AVERMEDIA_A309_USB] = {
-               USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A309)},
-       [MSI_DIGIVOX_MINI_III] = {
-               USB_DEVICE(USB_VID_MSI_2, USB_PID_MSI_DIGI_VOX_MINI_III)},
-       [KWORLD_E396] = {
-               USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U)},
-       [KWORLD_E39B] = {
-               USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_2)},
-       [KWORLD_E395] = {
-               USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_3)},
-       [TREKSTOR_DVBT] = {
-               USB_DEVICE(USB_VID_AFATECH, USB_PID_TREKSTOR_DVBT)},
-       [AVERTV_A850] = {
-               USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850)},
-       [AVERTV_A805] = {
-               USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A805)},
-       [CONCEPTRONIC_CTVDIGRCU] = {
-               USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CONCEPTRONIC_CTVDIGRCU)},
-       [KWORLD_MC810] = {
-               USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_MC810)},
-       [GENIUS_TVGO_DVB_T03] = {
-               USB_DEVICE(USB_VID_KYE, USB_PID_GENIUS_TVGO_DVB_T03)},
-       [KWORLD_399U_2] = {
-               USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U_2)},
-       [KWORLD_PC160_T] = {
-               USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_PC160_T)},
-       [SVEON_STV20] = {
-               USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20)},
-       [TINYTWIN_2] = {
-               USB_DEVICE(USB_VID_KWORLD_2, USB_PID_TINYTWIN_2)},
-       [WINFAST_DTV2000DS] = {
-               USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV2000DS)},
-       [KWORLD_UB383_T] = {
-               USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB383_T)},
-       [KWORLD_E39A] = {
-               USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_4)},
-       [AVERMEDIA_A815M] = {
-               USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A815M)},
-       [CINERGY_T_STICK_RC] = {
-               USB_DEVICE(USB_VID_TERRATEC,
-                               USB_PID_TERRATEC_CINERGY_T_STICK_RC)},
-       [CINERGY_T_DUAL_RC] = {
-               USB_DEVICE(USB_VID_TERRATEC,
-                               USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC)},
-       [AVERTV_A850T] = {
-               USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T)},
-       [TINYTWIN_3] = {
-               USB_DEVICE(USB_VID_GTEK, USB_PID_TINYTWIN_3)},
-       [SVEON_STV22] = {
-               USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV22)},
-       { }
-};
-MODULE_DEVICE_TABLE(usb, af9015_usb_table);
-
-#define AF9015_RC_INTERVAL 500
-static struct dvb_usb_device_properties af9015_properties[] = {
-       {
-               .caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-               .usb_ctrl = DEVICE_SPECIFIC,
-               .download_firmware = af9015_download_firmware,
-               .firmware = "dvb-usb-af9015.fw",
-               .no_reconnect = 1,
-
-               .size_of_priv = sizeof(struct af9015_state),
-
-               .num_adapters = 2,
-               .adapter = {
-                       {
-                               .num_frontends = 1,
-                               .fe = {
-                                       {
-                                               .caps = DVB_USB_ADAP_HAS_PID_FILTER |
-                                                       DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-
-                                               .pid_filter_count = 32,
-                                               .pid_filter       = af9015_pid_filter,
-                                               .pid_filter_ctrl  = af9015_pid_filter_ctrl,
-
-                                               .frontend_attach = af9015_af9013_frontend_attach,
-                                               .tuner_attach    = af9015_tuner_attach,
-                                               .stream = {
-                                                       .type = USB_BULK,
-                                                       .count = 6,
-                                                       .endpoint = 0x84,
-                                               },
-                                       }
-                               },
-                       },
-                       {
-                               .num_frontends = 1,
-                               .fe = {
-                                       {
-                                               .frontend_attach = af9015_af9013_frontend_attach,
-                                               .tuner_attach    = af9015_tuner_attach,
-                                               .stream = {
-                                                       .type = USB_BULK,
-                                                       .count = 6,
-                                                       .endpoint = 0x85,
-                                                       .u = {
-                                                               .bulk = {
-                                                                       .buffersize = TS_USB20_FRAME_SIZE,
-                                                               }
-                                                       }
-                                               },
-                                       }
-                               },
-                       }
-               },
-
-               .identify_state = af9015_identify_state,
-
-               .rc.core = {
-                       .protocol         = RC_TYPE_NEC,
-                       .module_name      = "af9015",
-                       .rc_query         = af9015_rc_query,
-                       .rc_interval      = AF9015_RC_INTERVAL,
-                       .allowed_protos   = RC_TYPE_NEC,
-               },
-
-               .i2c_algo = &af9015_i2c_algo,
-
-               .num_device_descs = 12, /* check max from dvb-usb.h */
-               .devices = {
-                       {
-                               .name = "Afatech AF9015 DVB-T USB2.0 stick",
-                               .cold_ids = {
-                                       &af9015_usb_table[AFATECH_9015],
-                                       &af9015_usb_table[AFATECH_9016],
-                               },
-                       }, {
-                               .name = "Leadtek WinFast DTV Dongle Gold",
-                               .cold_ids = {
-                                       &af9015_usb_table[WINFAST_DTV_GOLD],
-                               },
-                       }, {
-                               .name = "Pinnacle PCTV 71e",
-                               .cold_ids = {
-                                       &af9015_usb_table[PINNACLE_PCTV_71E],
-                               },
-                       }, {
-                               .name = "KWorld PlusTV Dual DVB-T Stick " \
-                                       "(DVB-T 399U)",
-                               .cold_ids = {
-                                       &af9015_usb_table[KWORLD_PLUSTV_399U],
-                                       &af9015_usb_table[KWORLD_399U_2],
-                               },
-                       }, {
-                               .name = "DigitalNow TinyTwin DVB-T Receiver",
-                               .cold_ids = {
-                                       &af9015_usb_table[TINYTWIN],
-                                       &af9015_usb_table[TINYTWIN_2],
-                                       &af9015_usb_table[TINYTWIN_3],
-                               },
-                       }, {
-                               .name = "TwinHan AzureWave AD-TU700(704J)",
-                               .cold_ids = {
-                                       &af9015_usb_table[AZUREWAVE_TU700],
-                               },
-                       }, {
-                               .name = "TerraTec Cinergy T USB XE",
-                               .cold_ids = {
-                                       &af9015_usb_table[TERRATEC_AF9015],
-                               },
-                       }, {
-                               .name = "KWorld PlusTV Dual DVB-T PCI " \
-                                       "(DVB-T PC160-2T)",
-                               .cold_ids = {
-                                       &af9015_usb_table[KWORLD_PLUSTV_PC160],
-                               },
-                       }, {
-                               .name = "AVerMedia AVerTV DVB-T Volar X",
-                               .cold_ids = {
-                                       &af9015_usb_table[AVERTV_VOLAR_X],
-                               },
-                       }, {
-                               .name = "TerraTec Cinergy T Stick RC",
-                               .cold_ids = {
-                                       &af9015_usb_table[CINERGY_T_STICK_RC],
-                               },
-                       }, {
-                               .name = "TerraTec Cinergy T Stick Dual RC",
-                               .cold_ids = {
-                                       &af9015_usb_table[CINERGY_T_DUAL_RC],
-                               },
-                       }, {
-                               .name = "AverMedia AVerTV Red HD+ (A850T)",
-                               .cold_ids = {
-                                       &af9015_usb_table[AVERTV_A850T],
-                               },
-                       },
-               }
-       }, {
-               .caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-               .usb_ctrl = DEVICE_SPECIFIC,
-               .download_firmware = af9015_download_firmware,
-               .firmware = "dvb-usb-af9015.fw",
-               .no_reconnect = 1,
-
-               .size_of_priv = sizeof(struct af9015_state),
-
-               .num_adapters = 2,
-               .adapter = {
-                       {
-                               .num_frontends = 1,
-                               .fe = {
-                                       {
-                                               .caps = DVB_USB_ADAP_HAS_PID_FILTER |
-                                                       DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-
-                                               .pid_filter_count = 32,
-                                               .pid_filter       = af9015_pid_filter,
-                                               .pid_filter_ctrl  = af9015_pid_filter_ctrl,
-
-                                               .frontend_attach = af9015_af9013_frontend_attach,
-                                               .tuner_attach    = af9015_tuner_attach,
-                                               .stream = {
-                                                       .type = USB_BULK,
-                                                       .count = 6,
-                                                       .endpoint = 0x84,
-                                               },
-                                       }
-                               },
-                       },
-                       {
-                               .num_frontends = 1,
-                               .fe = {
-                                       {
-                                               .frontend_attach = af9015_af9013_frontend_attach,
-                                               .tuner_attach    = af9015_tuner_attach,
-                                               .stream = {
-                                                       .type = USB_BULK,
-                                                       .count = 6,
-                                                       .endpoint = 0x85,
-                                                       .u = {
-                                                               .bulk = {
-                                                                       .buffersize = TS_USB20_FRAME_SIZE,
-                                                               }
-                                                       }
-                                               },
-                                       }
-                               },
-                       }
-               },
-
-               .identify_state = af9015_identify_state,
-
-               .rc.core = {
-                       .protocol         = RC_TYPE_NEC,
-                       .module_name      = "af9015",
-                       .rc_query         = af9015_rc_query,
-                       .rc_interval      = AF9015_RC_INTERVAL,
-                       .allowed_protos   = RC_TYPE_NEC,
-               },
-
-               .i2c_algo = &af9015_i2c_algo,
-
-               .num_device_descs = 10, /* check max from dvb-usb.h */
-               .devices = {
-                       {
-                               .name = "Xtensions XD-380",
-                               .cold_ids = {
-                                       &af9015_usb_table[XTENSIONS_380U],
-                               },
-                       }, {
-                               .name = "MSI DIGIVOX Duo",
-                               .cold_ids = {
-                                       &af9015_usb_table[MSI_DIGIVOX_DUO],
-                               },
-                       }, {
-                               .name = "Fujitsu-Siemens Slim Mobile USB DVB-T",
-                               .cold_ids = {
-                                       &af9015_usb_table[AVERTV_VOLAR_X_REV2],
-                               },
-                       }, {
-                               .name = "Telestar Starstick 2",
-                               .cold_ids = {
-                                       &af9015_usb_table[TELESTAR_STARSTICK_2],
-                               },
-                       }, {
-                               .name = "AVerMedia A309",
-                               .cold_ids = {
-                                       &af9015_usb_table[AVERMEDIA_A309_USB],
-                               },
-                       }, {
-                               .name = "MSI Digi VOX mini III",
-                               .cold_ids = {
-                                       &af9015_usb_table[MSI_DIGIVOX_MINI_III],
-                               },
-                       }, {
-                               .name = "KWorld USB DVB-T TV Stick II " \
-                                       "(VS-DVB-T 395U)",
-                               .cold_ids = {
-                                       &af9015_usb_table[KWORLD_E396],
-                                       &af9015_usb_table[KWORLD_E39B],
-                                       &af9015_usb_table[KWORLD_E395],
-                                       &af9015_usb_table[KWORLD_E39A],
-                               },
-                       }, {
-                               .name = "TrekStor DVB-T USB Stick",
-                               .cold_ids = {
-                                       &af9015_usb_table[TREKSTOR_DVBT],
-                               },
-                       }, {
-                               .name = "AverMedia AVerTV Volar Black HD " \
-                                       "(A850)",
-                               .cold_ids = {
-                                       &af9015_usb_table[AVERTV_A850],
-                               },
-                       }, {
-                               .name = "Sveon STV22 Dual USB DVB-T Tuner HDTV",
-                               .cold_ids = {
-                                       &af9015_usb_table[SVEON_STV22],
-                               },
-                       },
-               }
-       }, {
-               .caps = DVB_USB_IS_AN_I2C_ADAPTER,
-
-               .usb_ctrl = DEVICE_SPECIFIC,
-               .download_firmware = af9015_download_firmware,
-               .firmware = "dvb-usb-af9015.fw",
-               .no_reconnect = 1,
-
-               .size_of_priv = sizeof(struct af9015_state),
-
-               .num_adapters = 2,
-               .adapter = {
-                       {
-                               .num_frontends = 1,
-                               .fe = {
-                                       {
-                                               .caps = DVB_USB_ADAP_HAS_PID_FILTER |
-                                                       DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
-
-                                               .pid_filter_count = 32,
-                                               .pid_filter       = af9015_pid_filter,
-                                               .pid_filter_ctrl  = af9015_pid_filter_ctrl,
-
-                                               .frontend_attach = af9015_af9013_frontend_attach,
-                                               .tuner_attach    = af9015_tuner_attach,
-                                               .stream = {
-                                                       .type = USB_BULK,
-                                                       .count = 6,
-                                                       .endpoint = 0x84,
-                                               },
-                                       }
-                               },
-                       },
-                       {
-                               .num_frontends = 1,
-                               .fe = {
-                                       {
-                                               .frontend_attach = af9015_af9013_frontend_attach,
-                                               .tuner_attach    = af9015_tuner_attach,
-                                               .stream = {
-                                                       .type = USB_BULK,
-                                                       .count = 6,
-                                                       .endpoint = 0x85,
-                                                       .u = {
-                                                               .bulk = {
-                                                                       .buffersize = TS_USB20_FRAME_SIZE,
-                                                               }
-                                                       }
-                                               },
-                                       }
-                               },
-                       }
-               },
-
-               .identify_state = af9015_identify_state,
-
-               .rc.core = {
-                       .protocol         = RC_TYPE_NEC,
-                       .module_name      = "af9015",
-                       .rc_query         = af9015_rc_query,
-                       .rc_interval      = AF9015_RC_INTERVAL,
-                       .allowed_protos   = RC_TYPE_NEC,
-               },
-
-               .i2c_algo = &af9015_i2c_algo,
-
-               .num_device_descs = 9, /* check max from dvb-usb.h */
-               .devices = {
-                       {
-                               .name = "AverMedia AVerTV Volar GPS 805 (A805)",
-                               .cold_ids = {
-                                       &af9015_usb_table[AVERTV_A805],
-                               },
-                       }, {
-                               .name = "Conceptronic USB2.0 DVB-T CTVDIGRCU " \
-                                       "V3.0",
-                               .cold_ids = {
-                                       &af9015_usb_table[CONCEPTRONIC_CTVDIGRCU],
-                               },
-                       }, {
-                               .name = "KWorld Digial MC-810",
-                               .cold_ids = {
-                                       &af9015_usb_table[KWORLD_MC810],
-                               },
-                       }, {
-                               .name = "Genius TVGo DVB-T03",
-                               .cold_ids = {
-                                       &af9015_usb_table[GENIUS_TVGO_DVB_T03],
-                               },
-                       }, {
-                               .name = "KWorld PlusTV DVB-T PCI Pro Card " \
-                                       "(DVB-T PC160-T)",
-                               .cold_ids = {
-                                       &af9015_usb_table[KWORLD_PC160_T],
-                               },
-                       }, {
-                               .name = "Sveon STV20 Tuner USB DVB-T HDTV",
-                               .cold_ids = {
-                                       &af9015_usb_table[SVEON_STV20],
-                               },
-                       }, {
-                               .name = "Leadtek WinFast DTV2000DS",
-                               .cold_ids = {
-                                       &af9015_usb_table[WINFAST_DTV2000DS],
-                               },
-                       }, {
-                               .name = "KWorld USB DVB-T Stick Mobile " \
-                                       "(UB383-T)",
-                               .cold_ids = {
-                                       &af9015_usb_table[KWORLD_UB383_T],
-                               },
-                       }, {
-                               .name = "AverMedia AVerTV Volar M (A815Mac)",
-                               .cold_ids = {
-                                       &af9015_usb_table[AVERMEDIA_A815M],
-                               },
-                       },
-               }
-       },
-};
-
-static int af9015_usb_probe(struct usb_interface *intf,
-                           const struct usb_device_id *id)
-{
-       int ret = 0;
-       struct dvb_usb_device *d = NULL;
-       struct usb_device *udev = interface_to_usbdev(intf);
-       u8 i;
-
-       deb_info("%s: interface:%d\n", __func__,
-               intf->cur_altsetting->desc.bInterfaceNumber);
-
-       /* interface 0 is used by DVB-T receiver and
-          interface 1 is for remote controller (HID) */
-       if (intf->cur_altsetting->desc.bInterfaceNumber == 0) {
-               ret = af9015_read_config(udev);
-               if (ret)
-                       return ret;
-
-               for (i = 0; i < af9015_properties_count; i++) {
-                       ret = dvb_usb_device_init(intf, &af9015_properties[i],
-                               THIS_MODULE, &d, adapter_nr);
-                       if (!ret)
-                               break;
-                       if (ret != -ENODEV)
-                               return ret;
-               }
-               if (ret)
-                       return ret;
-
-               if (d)
-                       ret = af9015_init(d);
-       }
-
-       return ret;
-}
-
-/* usb specific object needed to register this driver with the usb subsystem */
-static struct usb_driver af9015_usb_driver = {
-       .name = "dvb_usb_af9015",
-       .probe = af9015_usb_probe,
-       .disconnect = dvb_usb_device_exit,
-       .id_table = af9015_usb_table,
-};
-
-module_usb_driver(af9015_usb_driver);
-
-MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
-MODULE_DESCRIPTION("Afatech AF9015 driver");
-MODULE_LICENSE("GPL");
index 7e9e00fae04e140aa4dafddb6e322386442980de..ef87229de6af5d791060b00cd82188bcebbc8c20 100644 (file)
@@ -768,13 +768,13 @@ int dib0700_rc_setup(struct dvb_usb_device *d)
        /* Starting in firmware 1.20, the RC info is provided on a bulk pipe */
        purb = usb_alloc_urb(0, GFP_KERNEL);
        if (purb == NULL) {
-               err("rc usb alloc urb failed\n");
+               err("rc usb alloc urb failed");
                return -ENOMEM;
        }
 
        purb->transfer_buffer = kzalloc(RC_MSG_SIZE_V1_20, GFP_KERNEL);
        if (purb->transfer_buffer == NULL) {
-               err("rc kzalloc failed\n");
+               err("rc kzalloc failed");
                usb_free_urb(purb);
                return -ENOMEM;
        }
@@ -786,7 +786,7 @@ int dib0700_rc_setup(struct dvb_usb_device *d)
 
        ret = usb_submit_urb(purb, GFP_ATOMIC);
        if (ret) {
-               err("rc submit urb failed\n");
+               err("rc submit urb failed");
                kfree(purb->transfer_buffer);
                usb_free_urb(purb);
        }
diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c b/drivers/media/dvb/dvb-usb/dvb_usb_dvb.c
new file mode 100644 (file)
index 0000000..384fe8e
--- /dev/null
@@ -0,0 +1,403 @@
+/* dvb-usb-dvb.c is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file contains functions for initializing and handling the
+ * linux-dvb API.
+ */
+#include "dvb_usb_common.h"
+
+static void dvb_usb_data_complete(struct usb_data_stream *stream, u8 *buf,
+               size_t len)
+{
+       struct dvb_usb_adapter *adap = stream->user_priv;
+       dvb_dmx_swfilter(&adap->demux, buf, len);
+}
+
+static void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buf,
+               size_t len)
+{
+       struct dvb_usb_adapter *adap = stream->user_priv;
+       dvb_dmx_swfilter_204(&adap->demux, buf, len);
+}
+
+static void dvb_usb_data_complete_raw(struct usb_data_stream *stream, u8 *buf,
+               size_t len)
+{
+       struct dvb_usb_adapter *adap = stream->user_priv;
+       dvb_dmx_swfilter_raw(&adap->demux, buf, len);
+}
+
+int dvb_usbv2_adapter_stream_init(struct dvb_usb_adapter *adap)
+{
+       pr_debug("%s: adap=%d\n", __func__, adap->id);
+
+       adap->stream.udev = adap_to_d(adap)->udev;
+       adap->stream.user_priv = adap;
+       adap->stream.complete = dvb_usb_data_complete;
+
+       return usb_urb_initv2(&adap->stream, &adap->props->stream);
+}
+
+int dvb_usbv2_adapter_stream_exit(struct dvb_usb_adapter *adap)
+{
+       pr_debug("%s: adap=%d\n", __func__, adap->id);
+       usb_urb_exitv2(&adap->stream);
+
+       return 0;
+}
+
+/* does the complete input transfer handling */
+static inline int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int count)
+{
+       struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv;
+       struct dvb_usb_device *d = adap_to_d(adap);
+       int ret;
+       pr_debug("%s: adap=%d active_fe=%d feed_type=%d setting pid [%s]: " \
+                       "%04x (%04d) at index %d '%s'\n", __func__, adap->id,
+                       adap->active_fe, dvbdmxfeed->type,
+                       adap->pid_filtering ? "yes" : "no", dvbdmxfeed->pid,
+                       dvbdmxfeed->pid, dvbdmxfeed->index,
+                       (count == 1) ? "on" : "off");
+
+       if (adap->active_fe == -1)
+               return -EINVAL;
+
+       adap->feed_count += count;
+
+       /* stop feeding if it is last pid */
+       if (adap->feed_count == 0) {
+               pr_debug("%s: stop feeding\n", __func__);
+               usb_urb_killv2(&adap->stream);
+
+               if (d->props->streaming_ctrl) {
+                       ret = d->props->streaming_ctrl(adap, 0);
+                       if (ret < 0) {
+                               pr_err("%s: streaming_ctrl() failed=%d\n",
+                                               KBUILD_MODNAME, ret);
+                               goto err_mutex_unlock;
+                       }
+               }
+               mutex_unlock(&adap->sync_mutex);
+       }
+
+       /* activate the pid on the device pid filter */
+       if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER &&
+                       adap->pid_filtering &&
+                       adap->props->pid_filter)
+               ret = adap->props->pid_filter(adap, dvbdmxfeed->index,
+                               dvbdmxfeed->pid, (count == 1) ? 1 : 0);
+                       if (ret < 0)
+                               pr_err("%s: pid_filter() failed=%d\n",
+                                               KBUILD_MODNAME, ret);
+
+       /* start feeding if it is first pid */
+       if (adap->feed_count == 1 && count == 1) {
+               struct usb_data_stream_properties stream_props;
+               mutex_lock(&adap->sync_mutex);
+               pr_debug("%s: start feeding\n", __func__);
+
+               /* resolve input and output streaming paramters */
+               if (d->props->get_stream_config) {
+                       memcpy(&stream_props, &adap->props->stream,
+                               sizeof(struct usb_data_stream_properties));
+                       ret = d->props->get_stream_config(
+                                       adap->fe[adap->active_fe],
+                                       &adap->ts_type, &stream_props);
+                       if (ret < 0)
+                               goto err_mutex_unlock;
+               } else {
+                       stream_props = adap->props->stream;
+               }
+
+               switch (adap->ts_type) {
+               case DVB_USB_FE_TS_TYPE_204:
+                       adap->stream.complete = dvb_usb_data_complete_204;
+                       break;
+               case DVB_USB_FE_TS_TYPE_RAW:
+                       adap->stream.complete = dvb_usb_data_complete_raw;
+                       break;
+               case DVB_USB_FE_TS_TYPE_188:
+               default:
+                       adap->stream.complete = dvb_usb_data_complete;
+                       break;
+               }
+
+               usb_urb_submitv2(&adap->stream, &stream_props);
+
+               if (adap->props->caps & DVB_USB_ADAP_HAS_PID_FILTER &&
+                               adap->props->caps &
+                               DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF &&
+                               adap->props->pid_filter_ctrl) {
+                       ret = adap->props->pid_filter_ctrl(adap,
+                                       adap->pid_filtering);
+                       if (ret < 0) {
+                               pr_err("%s: pid_filter_ctrl() failed=%d\n",
+                                               KBUILD_MODNAME, ret);
+                               goto err_mutex_unlock;
+                       }
+               }
+
+               if (d->props->streaming_ctrl) {
+                       ret = d->props->streaming_ctrl(adap, 1);
+                       if (ret < 0) {
+                               pr_err("%s: streaming_ctrl() failed=%d\n",
+                                               KBUILD_MODNAME, ret);
+                               goto err_mutex_unlock;
+                       }
+               }
+       }
+
+       return 0;
+err_mutex_unlock:
+       mutex_unlock(&adap->sync_mutex);
+       pr_debug("%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+       return dvb_usb_ctrl_feed(dvbdmxfeed, 1);
+}
+
+static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+       return dvb_usb_ctrl_feed(dvbdmxfeed, -1);
+}
+
+int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap)
+{
+       int ret;
+       struct dvb_usb_device *d = adap_to_d(adap);
+       pr_debug("%s: adap=%d\n", __func__, adap->id);
+
+       ret = dvb_register_adapter(&adap->dvb_adap, d->name, d->props->owner,
+                       &d->udev->dev, d->props->adapter_nr);
+       if (ret < 0) {
+               pr_debug("%s: dvb_register_adapter() failed=%d\n", __func__,
+                               ret);
+               goto err;
+       }
+
+       adap->dvb_adap.priv = adap;
+
+       if (d->props->read_mac_address) {
+               ret = d->props->read_mac_address(adap,
+                               adap->dvb_adap.proposed_mac);
+               if (ret < 0)
+                       goto err_dmx;
+
+               pr_info("%s: MAC address: %pM\n", KBUILD_MODNAME,
+                               adap->dvb_adap.proposed_mac);
+       }
+
+       adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
+       adap->demux.priv             = adap;
+       adap->demux.filternum        = 0;
+       if (adap->demux.filternum < adap->max_feed_count)
+               adap->demux.filternum = adap->max_feed_count;
+       adap->demux.feednum          = adap->demux.filternum;
+       adap->demux.start_feed       = dvb_usb_start_feed;
+       adap->demux.stop_feed        = dvb_usb_stop_feed;
+       adap->demux.write_to_decoder = NULL;
+       ret = dvb_dmx_init(&adap->demux);
+       if (ret < 0) {
+               pr_err("%s: dvb_dmx_init() failed=%d\n", KBUILD_MODNAME, ret);
+               goto err_dmx;
+       }
+
+       adap->dmxdev.filternum       = adap->demux.filternum;
+       adap->dmxdev.demux           = &adap->demux.dmx;
+       adap->dmxdev.capabilities    = 0;
+       ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap);
+       if (ret < 0) {
+               pr_err("%s: dvb_dmxdev_init() failed=%d\n", KBUILD_MODNAME,
+                               ret);
+               goto err_dmx_dev;
+       }
+
+       ret = dvb_net_init(&adap->dvb_adap, &adap->dvb_net, &adap->demux.dmx);
+       if (ret < 0) {
+               pr_err("%s: dvb_net_init() failed=%d\n", KBUILD_MODNAME, ret);
+               goto err_net_init;
+       }
+
+       mutex_init(&adap->sync_mutex);
+
+       return 0;
+err_net_init:
+       dvb_dmxdev_release(&adap->dmxdev);
+err_dmx_dev:
+       dvb_dmx_release(&adap->demux);
+err_dmx:
+       dvb_unregister_adapter(&adap->dvb_adap);
+err:
+       adap->dvb_adap.priv = NULL;
+       return ret;
+}
+
+int dvb_usbv2_adapter_dvb_exit(struct dvb_usb_adapter *adap)
+{
+       pr_debug("%s: adap=%d\n", __func__, adap->id);
+
+       if (adap->dvb_adap.priv) {
+               dvb_net_release(&adap->dvb_net);
+               adap->demux.dmx.close(&adap->demux.dmx);
+               dvb_dmxdev_release(&adap->dmxdev);
+               dvb_dmx_release(&adap->demux);
+               dvb_unregister_adapter(&adap->dvb_adap);
+       }
+
+       return 0;
+}
+
+static int dvb_usb_fe_wakeup(struct dvb_frontend *fe)
+{
+       int ret;
+       struct dvb_usb_adapter *adap = fe->dvb->priv;
+       struct dvb_usb_device *d = adap_to_d(adap);
+       mutex_lock(&adap->sync_mutex);
+       pr_debug("%s: adap=%d fe=%d\n", __func__, adap->id, fe->id);
+
+       ret = dvb_usbv2_device_power_ctrl(d, 1);
+       if (ret < 0)
+               goto err;
+
+       if (d->props->frontend_ctrl) {
+               ret = d->props->frontend_ctrl(fe, 1);
+               if (ret < 0)
+                       goto err;
+       }
+
+       if (adap->fe_init[fe->id]) {
+               ret = adap->fe_init[fe->id](fe);
+               if (ret < 0)
+                       goto err;
+       }
+
+       adap->active_fe = fe->id;
+       mutex_unlock(&adap->sync_mutex);
+
+       return 0;
+err:
+       mutex_unlock(&adap->sync_mutex);
+       pr_debug("%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+static int dvb_usb_fe_sleep(struct dvb_frontend *fe)
+{
+       int ret;
+       struct dvb_usb_adapter *adap = fe->dvb->priv;
+       struct dvb_usb_device *d = adap_to_d(adap);
+       mutex_lock(&adap->sync_mutex);
+       pr_debug("%s: adap=%d fe=%d\n", __func__, adap->id, fe->id);
+
+       if (adap->fe_sleep[fe->id]) {
+               ret = adap->fe_sleep[fe->id](fe);
+               if (ret < 0)
+                       goto err;
+       }
+
+       if (d->props->frontend_ctrl) {
+               ret = d->props->frontend_ctrl(fe, 0);
+               if (ret < 0)
+                       goto err;
+       }
+
+       ret = dvb_usbv2_device_power_ctrl(d, 0);
+       if (ret < 0)
+               goto err;
+
+       adap->active_fe = -1;
+       mutex_unlock(&adap->sync_mutex);
+
+       return 0;
+err:
+       mutex_unlock(&adap->sync_mutex);
+       pr_debug("%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap)
+{
+       int ret, i, count_registered = 0;
+       struct dvb_usb_device *d = adap_to_d(adap);
+       pr_debug("%s: adap=%d\n", __func__, adap->id);
+
+       memset(adap->fe, 0, sizeof(adap->fe));
+       adap->active_fe = -1;
+
+       if (d->props->frontend_attach) {
+               ret = d->props->frontend_attach(adap);
+               if (ret < 0) {
+                       pr_debug("%s: frontend_attach() failed=%d\n", __func__,
+                                       ret);
+                       goto err_dvb_frontend_detach;
+               }
+       } else {
+               pr_debug("%s: frontend_attach() do not exists\n", __func__);
+               ret = 0;
+               goto err;
+       }
+
+       for (i = 0; i < MAX_NO_OF_FE_PER_ADAP && adap->fe[i]; i++) {
+               adap->fe[i]->id = i;
+
+               /* re-assign sleep and wakeup functions */
+               adap->fe_init[i] = adap->fe[i]->ops.init;
+               adap->fe[i]->ops.init  = dvb_usb_fe_wakeup;
+               adap->fe_sleep[i] = adap->fe[i]->ops.sleep;
+               adap->fe[i]->ops.sleep = dvb_usb_fe_sleep;
+
+               ret = dvb_register_frontend(&adap->dvb_adap, adap->fe[i]);
+               if (ret < 0) {
+                       pr_err("%s: frontend%d registration failed\n",
+                                       KBUILD_MODNAME, i);
+                       goto err_dvb_unregister_frontend;
+               }
+
+               count_registered++;
+       }
+
+       if (d->props->tuner_attach) {
+               ret = d->props->tuner_attach(adap);
+               if (ret < 0) {
+                       pr_debug("%s: tuner_attach() failed=%d\n", __func__,
+                                       ret);
+                       goto err_dvb_unregister_frontend;
+               }
+       }
+
+       return 0;
+
+err_dvb_unregister_frontend:
+       for (i = count_registered - 1; i >= 0; i--)
+               dvb_unregister_frontend(adap->fe[i]);
+
+err_dvb_frontend_detach:
+       for (i = MAX_NO_OF_FE_PER_ADAP - 1; i >= 0; i--) {
+               if (adap->fe[i])
+                       dvb_frontend_detach(adap->fe[i]);
+       }
+
+err:
+       pr_debug("%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+int dvb_usbv2_adapter_frontend_exit(struct dvb_usb_adapter *adap)
+{
+       int i;
+       pr_debug("%s: adap=%d\n", __func__, adap->id);
+
+       for (i = MAX_NO_OF_FE_PER_ADAP - 1; i >= 0; i--) {
+               if (adap->fe[i]) {
+                       dvb_unregister_frontend(adap->fe[i]);
+                       dvb_frontend_detach(adap->fe[i]);
+               }
+       }
+
+       return 0;
+}
diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_remote.c b/drivers/media/dvb/dvb-usb/dvb_usb_remote.c
new file mode 100644 (file)
index 0000000..f856ab6
--- /dev/null
@@ -0,0 +1,117 @@
+/* dvb-usb-remote.c is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file contains functions for initializing the input-device and for
+ * handling remote-control-queries.
+ */
+#include "dvb_usb_common.h"
+#include <linux/usb/input.h>
+
+/* Remote-control poll function - called every dib->rc_query_interval ms to see
+ * whether the remote control has received anything.
+ *
+ * TODO: Fix the repeat rate of the input device.
+ */
+static void dvb_usb_read_remote_control(struct work_struct *work)
+{
+       struct dvb_usb_device *d = container_of(work,
+                       struct dvb_usb_device, rc_query_work.work);
+       int ret;
+
+       /* TODO: need a lock here.  We can simply skip checking for the remote
+          control if we're busy. */
+
+       /* when the parameter has been set to 1 via sysfs while the
+        * driver was running, or when bulk mode is enabled after IR init
+        */
+       if (dvb_usbv2_disable_rc_polling || d->rc.bulk_mode)
+               return;
+
+       ret = d->rc.query(d);
+       if (ret < 0)
+               pr_err("%s: error %d while querying for an remote control " \
+                               "event\n", KBUILD_MODNAME, ret);
+
+       schedule_delayed_work(&d->rc_query_work,
+                             msecs_to_jiffies(d->rc.interval));
+}
+
+int dvb_usbv2_remote_init(struct dvb_usb_device *d)
+{
+       int ret;
+       struct rc_dev *dev;
+
+       if (dvb_usbv2_disable_rc_polling || !d->props->get_rc_config)
+               return 0;
+
+       ret = d->props->get_rc_config(d, &d->rc);
+       if (ret < 0)
+               goto err;
+
+       dev = rc_allocate_device();
+       if (!dev) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       dev->dev.parent = &d->udev->dev;
+       dev->input_name = "IR-receiver inside an USB DVB receiver";
+       usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));
+       strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys));
+       dev->input_phys = d->rc_phys;
+       usb_to_input_id(d->udev, &dev->input_id);
+       /* TODO: likely RC-core should took const char * */
+       dev->driver_name = (char *) d->props->driver_name;
+       dev->driver_type = d->rc.driver_type;
+       dev->allowed_protos = d->rc.allowed_protos;
+       dev->change_protocol = d->rc.change_protocol;
+       dev->priv = d;
+       /* select used keymap */
+       if (d->rc.map_name)
+               dev->map_name = d->rc.map_name;
+       else if (d->rc_map)
+               dev->map_name = d->rc_map;
+       else
+               dev->map_name = RC_MAP_EMPTY; /* keep rc enabled */
+
+       ret = rc_register_device(dev);
+       if (ret < 0) {
+               rc_free_device(dev);
+               goto err;
+       }
+
+       d->input_dev = NULL;
+       d->rc_dev = dev;
+
+       /* start polling if needed */
+       if (d->rc.query && !d->rc.bulk_mode) {
+               /* initialize a work queue for handling polling */
+               INIT_DELAYED_WORK(&d->rc_query_work,
+                               dvb_usb_read_remote_control);
+               pr_info("%s: schedule remote query interval to %d msecs\n",
+                               KBUILD_MODNAME, d->rc.interval);
+               schedule_delayed_work(&d->rc_query_work,
+                               msecs_to_jiffies(d->rc.interval));
+       }
+
+       d->state |= DVB_USB_STATE_REMOTE;
+
+       return 0;
+err:
+       pr_debug("%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+int dvb_usbv2_remote_exit(struct dvb_usb_device *d)
+{
+       if (d->state & DVB_USB_STATE_REMOTE) {
+               cancel_delayed_work_sync(&d->rc_query_work);
+               rc_unregister_device(d->rc_dev);
+       }
+
+       d->state &= ~DVB_USB_STATE_REMOTE;
+
+       return 0;
+}
diff --git a/drivers/media/dvb/dvb-usb/mxl111sf.c b/drivers/media/dvb/dvb-usb/mxl111sf.c
deleted file mode 100644 (file)
index cd84279..0000000
+++ /dev/null
@@ -1,1835 +0,0 @@
-/*
- * Copyright (C) 2010 Michael Krufky (mkrufky@kernellabs.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.
- *
- * see Documentation/dvb/README.dvb-usb for more information
- */
-
-#include <linux/vmalloc.h>
-#include <linux/i2c.h>
-
-#include "mxl111sf.h"
-#include "mxl111sf-reg.h"
-#include "mxl111sf-phy.h"
-#include "mxl111sf-i2c.h"
-#include "mxl111sf-gpio.h"
-
-#include "mxl111sf-demod.h"
-#include "mxl111sf-tuner.h"
-
-#include "lgdt3305.h"
-#include "lg2160.h"
-
-int dvb_usb_mxl111sf_debug;
-module_param_named(debug, dvb_usb_mxl111sf_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level "
-                "(1=info, 2=xfer, 4=i2c, 8=reg, 16=adv (or-able)).");
-
-int dvb_usb_mxl111sf_isoc;
-module_param_named(isoc, dvb_usb_mxl111sf_isoc, int, 0644);
-MODULE_PARM_DESC(isoc, "enable usb isoc xfer (0=bulk, 1=isoc).");
-
-int dvb_usb_mxl111sf_spi;
-module_param_named(spi, dvb_usb_mxl111sf_spi, int, 0644);
-MODULE_PARM_DESC(spi, "use spi rather than tp for data xfer (0=tp, 1=spi).");
-
-#define ANT_PATH_AUTO 0
-#define ANT_PATH_EXTERNAL 1
-#define ANT_PATH_INTERNAL 2
-
-int dvb_usb_mxl111sf_rfswitch =
-#if 0
-               ANT_PATH_AUTO;
-#else
-               ANT_PATH_EXTERNAL;
-#endif
-
-module_param_named(rfswitch, dvb_usb_mxl111sf_rfswitch, int, 0644);
-MODULE_PARM_DESC(rfswitch, "force rf switch position (0=auto, 1=ext, 2=int).");
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-#define deb_info(args...)   dprintk(dvb_usb_mxl111sf_debug, 0x13, args)
-#define deb_reg(args...)    dprintk(dvb_usb_mxl111sf_debug, 0x08, args)
-#define deb_adv(args...)    dprintk(dvb_usb_mxl111sf_debug, MXL_ADV_DBG, args)
-
-int mxl111sf_ctrl_msg(struct dvb_usb_device *d,
-                     u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
-{
-       int wo = (rbuf == NULL || rlen == 0); /* write-only */
-       int ret;
-       u8 sndbuf[1+wlen];
-
-       deb_adv("%s(wlen = %d, rlen = %d)\n", __func__, wlen, rlen);
-
-       memset(sndbuf, 0, 1+wlen);
-
-       sndbuf[0] = cmd;
-       memcpy(&sndbuf[1], wbuf, wlen);
-
-       ret = (wo) ? dvb_usb_generic_write(d, sndbuf, 1+wlen) :
-               dvb_usb_generic_rw(d, sndbuf, 1+wlen, rbuf, rlen, 0);
-       mxl_fail(ret);
-
-       return ret;
-}
-
-/* ------------------------------------------------------------------------ */
-
-#define MXL_CMD_REG_READ       0xaa
-#define MXL_CMD_REG_WRITE      0x55
-
-int mxl111sf_read_reg(struct mxl111sf_state *state, u8 addr, u8 *data)
-{
-       u8 buf[2];
-       int ret;
-
-       ret = mxl111sf_ctrl_msg(state->d, MXL_CMD_REG_READ, &addr, 1, buf, 2);
-       if (mxl_fail(ret)) {
-               mxl_debug("error reading reg: 0x%02x", addr);
-               goto fail;
-       }
-
-       if (buf[0] == addr)
-               *data = buf[1];
-       else {
-               err("invalid response reading reg: 0x%02x != 0x%02x, 0x%02x",
-                   addr, buf[0], buf[1]);
-               ret = -EINVAL;
-       }
-
-       deb_reg("R: (0x%02x, 0x%02x)\n", addr, *data);
-fail:
-       return ret;
-}
-
-int mxl111sf_write_reg(struct mxl111sf_state *state, u8 addr, u8 data)
-{
-       u8 buf[] = { addr, data };
-       int ret;
-
-       deb_reg("W: (0x%02x, 0x%02x)\n", addr, data);
-
-       ret = mxl111sf_ctrl_msg(state->d, MXL_CMD_REG_WRITE, buf, 2, NULL, 0);
-       if (mxl_fail(ret))
-               err("error writing reg: 0x%02x, val: 0x%02x", addr, data);
-       return ret;
-}
-
-/* ------------------------------------------------------------------------ */
-
-int mxl111sf_write_reg_mask(struct mxl111sf_state *state,
-                                  u8 addr, u8 mask, u8 data)
-{
-       int ret;
-       u8 val;
-
-       if (mask != 0xff) {
-               ret = mxl111sf_read_reg(state, addr, &val);
-#if 1
-               /* dont know why this usually errors out on the first try */
-               if (mxl_fail(ret))
-                       err("error writing addr: 0x%02x, mask: 0x%02x, "
-                           "data: 0x%02x, retrying...", addr, mask, data);
-
-               ret = mxl111sf_read_reg(state, addr, &val);
-#endif
-               if (mxl_fail(ret))
-                       goto fail;
-       }
-       val &= ~mask;
-       val |= data;
-
-       ret = mxl111sf_write_reg(state, addr, val);
-       mxl_fail(ret);
-fail:
-       return ret;
-}
-
-/* ------------------------------------------------------------------------ */
-
-int mxl111sf_ctrl_program_regs(struct mxl111sf_state *state,
-                              struct mxl111sf_reg_ctrl_info *ctrl_reg_info)
-{
-       int i, ret = 0;
-
-       for (i = 0;  ctrl_reg_info[i].addr |
-                    ctrl_reg_info[i].mask |
-                    ctrl_reg_info[i].data;  i++) {
-
-               ret = mxl111sf_write_reg_mask(state,
-                                             ctrl_reg_info[i].addr,
-                                             ctrl_reg_info[i].mask,
-                                             ctrl_reg_info[i].data);
-               if (mxl_fail(ret)) {
-                       err("failed on reg #%d (0x%02x)", i,
-                           ctrl_reg_info[i].addr);
-                       break;
-               }
-       }
-       return ret;
-}
-
-/* ------------------------------------------------------------------------ */
-
-static int mxl1x1sf_get_chip_info(struct mxl111sf_state *state)
-{
-       int ret;
-       u8 id, ver;
-       char *mxl_chip, *mxl_rev;
-
-       if ((state->chip_id) && (state->chip_ver))
-               return 0;
-
-       ret = mxl111sf_read_reg(state, CHIP_ID_REG, &id);
-       if (mxl_fail(ret))
-               goto fail;
-       state->chip_id = id;
-
-       ret = mxl111sf_read_reg(state, TOP_CHIP_REV_ID_REG, &ver);
-       if (mxl_fail(ret))
-               goto fail;
-       state->chip_ver = ver;
-
-       switch (id) {
-       case 0x61:
-               mxl_chip = "MxL101SF";
-               break;
-       case 0x63:
-               mxl_chip = "MxL111SF";
-               break;
-       default:
-               mxl_chip = "UNKNOWN MxL1X1";
-               break;
-       }
-       switch (ver) {
-       case 0x36:
-               state->chip_rev = MXL111SF_V6;
-               mxl_rev = "v6";
-               break;
-       case 0x08:
-               state->chip_rev = MXL111SF_V8_100;
-               mxl_rev = "v8_100";
-               break;
-       case 0x18:
-               state->chip_rev = MXL111SF_V8_200;
-               mxl_rev = "v8_200";
-               break;
-       default:
-               state->chip_rev = 0;
-               mxl_rev = "UNKNOWN REVISION";
-               break;
-       }
-       info("%s detected, %s (0x%x)", mxl_chip, mxl_rev, ver);
-fail:
-       return ret;
-}
-
-#define get_chip_info(state)                                           \
-({                                                                     \
-       int ___ret;                                                     \
-       ___ret = mxl1x1sf_get_chip_info(state);                         \
-       if (mxl_fail(___ret)) {                                         \
-               mxl_debug("failed to get chip info"                     \
-                         " on first probe attempt");                   \
-               ___ret = mxl1x1sf_get_chip_info(state);                 \
-               if (mxl_fail(___ret))                                   \
-                       err("failed to get chip info during probe");    \
-               else                                                    \
-                       mxl_debug("probe needed a retry "               \
-                                 "in order to succeed.");              \
-       }                                                               \
-       ___ret;                                                         \
-})
-
-/* ------------------------------------------------------------------------ */
-
-static int mxl111sf_power_ctrl(struct dvb_usb_device *d, int onoff)
-{
-       /* power control depends on which adapter is being woken:
-        * save this for init, instead, via mxl111sf_adap_fe_init */
-       return 0;
-}
-
-static int mxl111sf_adap_fe_init(struct dvb_frontend *fe)
-{
-       struct dvb_usb_adapter *adap = fe->dvb->priv;
-       struct dvb_usb_device *d = adap->dev;
-       struct mxl111sf_state *state = d->priv;
-       struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe->id].priv;
-
-       int err;
-
-       /* exit if we didnt initialize the driver yet */
-       if (!state->chip_id) {
-               mxl_debug("driver not yet initialized, exit.");
-               goto fail;
-       }
-
-       deb_info("%s()\n", __func__);
-
-       mutex_lock(&state->fe_lock);
-
-       state->alt_mode = adap_state->alt_mode;
-
-       if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0)
-               err("set interface failed");
-
-       err = mxl1x1sf_soft_reset(state);
-       mxl_fail(err);
-       err = mxl111sf_init_tuner_demod(state);
-       mxl_fail(err);
-       err = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
-
-       mxl_fail(err);
-       mxl111sf_enable_usb_output(state);
-       mxl_fail(err);
-       mxl1x1sf_top_master_ctrl(state, 1);
-       mxl_fail(err);
-
-       if ((MXL111SF_GPIO_MOD_DVBT != adap_state->gpio_mode) &&
-           (state->chip_rev > MXL111SF_V6)) {
-               mxl111sf_config_pin_mux_modes(state,
-                                             PIN_MUX_TS_SPI_IN_MODE_1);
-               mxl_fail(err);
-       }
-       err = mxl111sf_init_port_expander(state);
-       if (!mxl_fail(err)) {
-               state->gpio_mode = adap_state->gpio_mode;
-               err = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
-               mxl_fail(err);
-#if 0
-               err = fe->ops.init(fe);
-#endif
-               msleep(100); /* add short delay after enabling
-                             * the demod before touching it */
-       }
-
-       return (adap_state->fe_init) ? adap_state->fe_init(fe) : 0;
-fail:
-       return -ENODEV;
-}
-
-static int mxl111sf_adap_fe_sleep(struct dvb_frontend *fe)
-{
-       struct dvb_usb_adapter *adap = fe->dvb->priv;
-       struct dvb_usb_device *d = adap->dev;
-       struct mxl111sf_state *state = d->priv;
-       struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe->id].priv;
-       int err;
-
-       /* exit if we didnt initialize the driver yet */
-       if (!state->chip_id) {
-               mxl_debug("driver not yet initialized, exit.");
-               goto fail;
-       }
-
-       deb_info("%s()\n", __func__);
-
-       err = (adap_state->fe_sleep) ? adap_state->fe_sleep(fe) : 0;
-
-       mutex_unlock(&state->fe_lock);
-
-       return err;
-fail:
-       return -ENODEV;
-}
-
-
-static int mxl111sf_ep6_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
-       struct dvb_usb_device *d = adap->dev;
-       struct mxl111sf_state *state = d->priv;
-       struct mxl111sf_adap_state *adap_state = adap->fe_adap[adap->active_fe].priv;
-       int ret = 0;
-
-       deb_info("%s(%d)\n", __func__, onoff);
-
-       if (onoff) {
-               ret = mxl111sf_enable_usb_output(state);
-               mxl_fail(ret);
-               ret = mxl111sf_config_mpeg_in(state, 1, 1,
-                                             adap_state->ep6_clockphase,
-                                             0, 0);
-               mxl_fail(ret);
-#if 0
-       } else {
-               ret = mxl111sf_disable_656_port(state);
-               mxl_fail(ret);
-#endif
-       }
-
-       return ret;
-}
-
-static int mxl111sf_ep5_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
-       struct dvb_usb_device *d = adap->dev;
-       struct mxl111sf_state *state = d->priv;
-       int ret = 0;
-
-       deb_info("%s(%d)\n", __func__, onoff);
-
-       if (onoff) {
-               ret = mxl111sf_enable_usb_output(state);
-               mxl_fail(ret);
-
-               ret = mxl111sf_init_i2s_port(state, 200);
-               mxl_fail(ret);
-               ret = mxl111sf_config_i2s(state, 0, 15);
-               mxl_fail(ret);
-       } else {
-               ret = mxl111sf_disable_i2s_port(state);
-               mxl_fail(ret);
-       }
-       if (state->chip_rev > MXL111SF_V6)
-               ret = mxl111sf_config_spi(state, onoff);
-       mxl_fail(ret);
-
-       return ret;
-}
-
-static int mxl111sf_ep4_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
-{
-       struct dvb_usb_device *d = adap->dev;
-       struct mxl111sf_state *state = d->priv;
-       int ret = 0;
-
-       deb_info("%s(%d)\n", __func__, onoff);
-
-       if (onoff) {
-               ret = mxl111sf_enable_usb_output(state);
-               mxl_fail(ret);
-       }
-
-       return ret;
-}
-
-/* ------------------------------------------------------------------------ */
-
-static struct lgdt3305_config hauppauge_lgdt3305_config = {
-       .i2c_addr           = 0xb2 >> 1,
-       .mpeg_mode          = LGDT3305_MPEG_SERIAL,
-       .tpclk_edge         = LGDT3305_TPCLK_RISING_EDGE,
-       .tpvalid_polarity   = LGDT3305_TP_VALID_HIGH,
-       .deny_i2c_rptr      = 1,
-       .spectral_inversion = 0,
-       .qam_if_khz         = 6000,
-       .vsb_if_khz         = 6000,
-};
-
-static int mxl111sf_lgdt3305_frontend_attach(struct dvb_usb_adapter *adap)
-{
-       struct dvb_usb_device *d = adap->dev;
-       struct mxl111sf_state *state = d->priv;
-       int fe_id = adap->num_frontends_initialized;
-       struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv;
-       int ret;
-
-       deb_adv("%s()\n", __func__);
-
-       /* save a pointer to the dvb_usb_device in device state */
-       state->d = d;
-       adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1;
-       state->alt_mode = adap_state->alt_mode;
-
-       if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0)
-               err("set interface failed");
-
-       state->gpio_mode = MXL111SF_GPIO_MOD_ATSC;
-       adap_state->gpio_mode = state->gpio_mode;
-       adap_state->device_mode = MXL_TUNER_MODE;
-       adap_state->ep6_clockphase = 1;
-
-       ret = mxl1x1sf_soft_reset(state);
-       if (mxl_fail(ret))
-               goto fail;
-       ret = mxl111sf_init_tuner_demod(state);
-       if (mxl_fail(ret))
-               goto fail;
-
-       ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
-       if (mxl_fail(ret))
-               goto fail;
-
-       ret = mxl111sf_enable_usb_output(state);
-       if (mxl_fail(ret))
-               goto fail;
-       ret = mxl1x1sf_top_master_ctrl(state, 1);
-       if (mxl_fail(ret))
-               goto fail;
-
-       ret = mxl111sf_init_port_expander(state);
-       if (mxl_fail(ret))
-               goto fail;
-       ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
-       if (mxl_fail(ret))
-               goto fail;
-
-       adap->fe_adap[fe_id].fe = dvb_attach(lgdt3305_attach,
-                                &hauppauge_lgdt3305_config,
-                                &adap->dev->i2c_adap);
-       if (adap->fe_adap[fe_id].fe) {
-               adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init;
-               adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init;
-               adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep;
-               adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep;
-               return 0;
-       }
-       ret = -EIO;
-fail:
-       return ret;
-}
-
-static struct lg2160_config hauppauge_lg2160_config = {
-       .lg_chip            = LG2160,
-       .i2c_addr           = 0x1c >> 1,
-       .deny_i2c_rptr      = 1,
-       .spectral_inversion = 0,
-       .if_khz             = 6000,
-};
-
-static int mxl111sf_lg2160_frontend_attach(struct dvb_usb_adapter *adap)
-{
-       struct dvb_usb_device *d = adap->dev;
-       struct mxl111sf_state *state = d->priv;
-       int fe_id = adap->num_frontends_initialized;
-       struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv;
-       int ret;
-
-       deb_adv("%s()\n", __func__);
-
-       /* save a pointer to the dvb_usb_device in device state */
-       state->d = d;
-       adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1;
-       state->alt_mode = adap_state->alt_mode;
-
-       if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0)
-               err("set interface failed");
-
-       state->gpio_mode = MXL111SF_GPIO_MOD_MH;
-       adap_state->gpio_mode = state->gpio_mode;
-       adap_state->device_mode = MXL_TUNER_MODE;
-       adap_state->ep6_clockphase = 1;
-
-       ret = mxl1x1sf_soft_reset(state);
-       if (mxl_fail(ret))
-               goto fail;
-       ret = mxl111sf_init_tuner_demod(state);
-       if (mxl_fail(ret))
-               goto fail;
-
-       ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
-       if (mxl_fail(ret))
-               goto fail;
-
-       ret = mxl111sf_enable_usb_output(state);
-       if (mxl_fail(ret))
-               goto fail;
-       ret = mxl1x1sf_top_master_ctrl(state, 1);
-       if (mxl_fail(ret))
-               goto fail;
-
-       ret = mxl111sf_init_port_expander(state);
-       if (mxl_fail(ret))
-               goto fail;
-       ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
-       if (mxl_fail(ret))
-               goto fail;
-
-       ret = get_chip_info(state);
-       if (mxl_fail(ret))
-               goto fail;
-
-       adap->fe_adap[fe_id].fe = dvb_attach(lg2160_attach,
-                             &hauppauge_lg2160_config,
-                             &adap->dev->i2c_adap);
-       if (adap->fe_adap[fe_id].fe) {
-               adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init;
-               adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init;
-               adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep;
-               adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep;
-               return 0;
-       }
-       ret = -EIO;
-fail:
-       return ret;
-}
-
-static struct lg2160_config hauppauge_lg2161_1019_config = {
-       .lg_chip            = LG2161_1019,
-       .i2c_addr           = 0x1c >> 1,
-       .deny_i2c_rptr      = 1,
-       .spectral_inversion = 0,
-       .if_khz             = 6000,
-       .output_if          = 2, /* LG2161_OIF_SPI_MAS */
-};
-
-static struct lg2160_config hauppauge_lg2161_1040_config = {
-       .lg_chip            = LG2161_1040,
-       .i2c_addr           = 0x1c >> 1,
-       .deny_i2c_rptr      = 1,
-       .spectral_inversion = 0,
-       .if_khz             = 6000,
-       .output_if          = 4, /* LG2161_OIF_SPI_MAS */
-};
-
-static int mxl111sf_lg2161_frontend_attach(struct dvb_usb_adapter *adap)
-{
-       struct dvb_usb_device *d = adap->dev;
-       struct mxl111sf_state *state = d->priv;
-       int fe_id = adap->num_frontends_initialized;
-       struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv;
-       int ret;
-
-       deb_adv("%s()\n", __func__);
-
-       /* save a pointer to the dvb_usb_device in device state */
-       state->d = d;
-       adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1;
-       state->alt_mode = adap_state->alt_mode;
-
-       if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0)
-               err("set interface failed");
-
-       state->gpio_mode = MXL111SF_GPIO_MOD_MH;
-       adap_state->gpio_mode = state->gpio_mode;
-       adap_state->device_mode = MXL_TUNER_MODE;
-       adap_state->ep6_clockphase = 1;
-
-       ret = mxl1x1sf_soft_reset(state);
-       if (mxl_fail(ret))
-               goto fail;
-       ret = mxl111sf_init_tuner_demod(state);
-       if (mxl_fail(ret))
-               goto fail;
-
-       ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
-       if (mxl_fail(ret))
-               goto fail;
-
-       ret = mxl111sf_enable_usb_output(state);
-       if (mxl_fail(ret))
-               goto fail;
-       ret = mxl1x1sf_top_master_ctrl(state, 1);
-       if (mxl_fail(ret))
-               goto fail;
-
-       ret = mxl111sf_init_port_expander(state);
-       if (mxl_fail(ret))
-               goto fail;
-       ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
-       if (mxl_fail(ret))
-               goto fail;
-
-       ret = get_chip_info(state);
-       if (mxl_fail(ret))
-               goto fail;
-
-       adap->fe_adap[fe_id].fe = dvb_attach(lg2160_attach,
-                             (MXL111SF_V8_200 == state->chip_rev) ?
-                             &hauppauge_lg2161_1040_config :
-                             &hauppauge_lg2161_1019_config,
-                             &adap->dev->i2c_adap);
-       if (adap->fe_adap[fe_id].fe) {
-               adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init;
-               adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init;
-               adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep;
-               adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep;
-               return 0;
-       }
-       ret = -EIO;
-fail:
-       return ret;
-}
-
-static struct lg2160_config hauppauge_lg2161_1019_ep6_config = {
-       .lg_chip            = LG2161_1019,
-       .i2c_addr           = 0x1c >> 1,
-       .deny_i2c_rptr      = 1,
-       .spectral_inversion = 0,
-       .if_khz             = 6000,
-       .output_if          = 1, /* LG2161_OIF_SERIAL_TS */
-};
-
-static struct lg2160_config hauppauge_lg2161_1040_ep6_config = {
-       .lg_chip            = LG2161_1040,
-       .i2c_addr           = 0x1c >> 1,
-       .deny_i2c_rptr      = 1,
-       .spectral_inversion = 0,
-       .if_khz             = 6000,
-       .output_if          = 7, /* LG2161_OIF_SERIAL_TS */
-};
-
-static int mxl111sf_lg2161_ep6_frontend_attach(struct dvb_usb_adapter *adap)
-{
-       struct dvb_usb_device *d = adap->dev;
-       struct mxl111sf_state *state = d->priv;
-       int fe_id = adap->num_frontends_initialized;
-       struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv;
-       int ret;
-
-       deb_adv("%s()\n", __func__);
-
-       /* save a pointer to the dvb_usb_device in device state */
-       state->d = d;
-       adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 2 : 1;
-       state->alt_mode = adap_state->alt_mode;
-
-       if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0)
-               err("set interface failed");
-
-       state->gpio_mode = MXL111SF_GPIO_MOD_MH;
-       adap_state->gpio_mode = state->gpio_mode;
-       adap_state->device_mode = MXL_TUNER_MODE;
-       adap_state->ep6_clockphase = 0;
-
-       ret = mxl1x1sf_soft_reset(state);
-       if (mxl_fail(ret))
-               goto fail;
-       ret = mxl111sf_init_tuner_demod(state);
-       if (mxl_fail(ret))
-               goto fail;
-
-       ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
-       if (mxl_fail(ret))
-               goto fail;
-
-       ret = mxl111sf_enable_usb_output(state);
-       if (mxl_fail(ret))
-               goto fail;
-       ret = mxl1x1sf_top_master_ctrl(state, 1);
-       if (mxl_fail(ret))
-               goto fail;
-
-       ret = mxl111sf_init_port_expander(state);
-       if (mxl_fail(ret))
-               goto fail;
-       ret = mxl111sf_gpio_mode_switch(state, state->gpio_mode);
-       if (mxl_fail(ret))
-               goto fail;
-
-       ret = get_chip_info(state);
-       if (mxl_fail(ret))
-               goto fail;
-
-       adap->fe_adap[fe_id].fe = dvb_attach(lg2160_attach,
-                             (MXL111SF_V8_200 == state->chip_rev) ?
-                             &hauppauge_lg2161_1040_ep6_config :
-                             &hauppauge_lg2161_1019_ep6_config,
-                             &adap->dev->i2c_adap);
-       if (adap->fe_adap[fe_id].fe) {
-               adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init;
-               adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init;
-               adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep;
-               adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep;
-               return 0;
-       }
-       ret = -EIO;
-fail:
-       return ret;
-}
-
-static struct mxl111sf_demod_config mxl_demod_config = {
-       .read_reg        = mxl111sf_read_reg,
-       .write_reg       = mxl111sf_write_reg,
-       .program_regs    = mxl111sf_ctrl_program_regs,
-};
-
-static int mxl111sf_attach_demod(struct dvb_usb_adapter *adap)
-{
-       struct dvb_usb_device *d = adap->dev;
-       struct mxl111sf_state *state = d->priv;
-       int fe_id = adap->num_frontends_initialized;
-       struct mxl111sf_adap_state *adap_state = adap->fe_adap[fe_id].priv;
-       int ret;
-
-       deb_adv("%s()\n", __func__);
-
-       /* save a pointer to the dvb_usb_device in device state */
-       state->d = d;
-       adap_state->alt_mode = (dvb_usb_mxl111sf_isoc) ? 1 : 2;
-       state->alt_mode = adap_state->alt_mode;
-
-       if (usb_set_interface(adap->dev->udev, 0, state->alt_mode) < 0)
-               err("set interface failed");
-
-       state->gpio_mode = MXL111SF_GPIO_MOD_DVBT;
-       adap_state->gpio_mode = state->gpio_mode;
-       adap_state->device_mode = MXL_SOC_MODE;
-       adap_state->ep6_clockphase = 1;
-
-       ret = mxl1x1sf_soft_reset(state);
-       if (mxl_fail(ret))
-               goto fail;
-       ret = mxl111sf_init_tuner_demod(state);
-       if (mxl_fail(ret))
-               goto fail;
-
-       ret = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
-       if (mxl_fail(ret))
-               goto fail;
-
-       ret = mxl111sf_enable_usb_output(state);
-       if (mxl_fail(ret))
-               goto fail;
-       ret = mxl1x1sf_top_master_ctrl(state, 1);
-       if (mxl_fail(ret))
-               goto fail;
-
-       /* dont care if this fails */
-       mxl111sf_init_port_expander(state);
-
-       adap->fe_adap[fe_id].fe = dvb_attach(mxl111sf_demod_attach, state,
-                             &mxl_demod_config);
-       if (adap->fe_adap[fe_id].fe) {
-               adap_state->fe_init = adap->fe_adap[fe_id].fe->ops.init;
-               adap->fe_adap[fe_id].fe->ops.init = mxl111sf_adap_fe_init;
-               adap_state->fe_sleep = adap->fe_adap[fe_id].fe->ops.sleep;
-               adap->fe_adap[fe_id].fe->ops.sleep = mxl111sf_adap_fe_sleep;
-               return 0;
-       }
-       ret = -EIO;
-fail:
-       return ret;
-}
-
-static inline int mxl111sf_set_ant_path(struct mxl111sf_state *state,
-                                       int antpath)
-{
-       return mxl111sf_idac_config(state, 1, 1,
-                                   (antpath == ANT_PATH_INTERNAL) ?
-                                   0x3f : 0x00, 0);
-}
-
-#define DbgAntHunt(x, pwr0, pwr1, pwr2, pwr3) \
-       err("%s(%d) FINAL input set to %s rxPwr:%d|%d|%d|%d\n", \
-           __func__, __LINE__, \
-           (ANT_PATH_EXTERNAL == x) ? "EXTERNAL" : "INTERNAL", \
-           pwr0, pwr1, pwr2, pwr3)
-
-#define ANT_HUNT_SLEEP 90
-#define ANT_EXT_TWEAK 0
-
-static int mxl111sf_ant_hunt(struct dvb_frontend *fe)
-{
-       struct dvb_usb_adapter *adap = fe->dvb->priv;
-       struct dvb_usb_device *d = adap->dev;
-       struct mxl111sf_state *state = d->priv;
-
-       int antctrl = dvb_usb_mxl111sf_rfswitch;
-
-       u16 rxPwrA, rxPwr0, rxPwr1, rxPwr2;
-
-       /* FIXME: must force EXTERNAL for QAM - done elsewhere */
-       mxl111sf_set_ant_path(state, antctrl == ANT_PATH_AUTO ?
-                             ANT_PATH_EXTERNAL : antctrl);
-
-       if (antctrl == ANT_PATH_AUTO) {
-#if 0
-               msleep(ANT_HUNT_SLEEP);
-#endif
-               fe->ops.tuner_ops.get_rf_strength(fe, &rxPwrA);
-
-               mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL);
-               msleep(ANT_HUNT_SLEEP);
-               fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr0);
-
-               mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL);
-               msleep(ANT_HUNT_SLEEP);
-               fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr1);
-
-               mxl111sf_set_ant_path(state, ANT_PATH_INTERNAL);
-               msleep(ANT_HUNT_SLEEP);
-               fe->ops.tuner_ops.get_rf_strength(fe, &rxPwr2);
-
-               if (rxPwr1+ANT_EXT_TWEAK >= rxPwr2) {
-                       /* return with EXTERNAL enabled */
-                       mxl111sf_set_ant_path(state, ANT_PATH_EXTERNAL);
-                       DbgAntHunt(ANT_PATH_EXTERNAL, rxPwrA,
-                                  rxPwr0, rxPwr1, rxPwr2);
-               } else {
-                       /* return with INTERNAL enabled */
-                       DbgAntHunt(ANT_PATH_INTERNAL, rxPwrA,
-                                  rxPwr0, rxPwr1, rxPwr2);
-               }
-       }
-       return 0;
-}
-
-static struct mxl111sf_tuner_config mxl_tuner_config = {
-       .if_freq         = MXL_IF_6_0, /* applies to external IF output, only */
-       .invert_spectrum = 0,
-       .read_reg        = mxl111sf_read_reg,
-       .write_reg       = mxl111sf_write_reg,
-       .program_regs    = mxl111sf_ctrl_program_regs,
-       .top_master_ctrl = mxl1x1sf_top_master_ctrl,
-       .ant_hunt        = mxl111sf_ant_hunt,
-};
-
-static int mxl111sf_attach_tuner(struct dvb_usb_adapter *adap)
-{
-       struct dvb_usb_device *d = adap->dev;
-       struct mxl111sf_state *state = d->priv;
-       int fe_id = adap->num_frontends_initialized;
-
-       deb_adv("%s()\n", __func__);
-
-       if (NULL != dvb_attach(mxl111sf_tuner_attach,
-                              adap->fe_adap[fe_id].fe, state,
-                              &mxl_tuner_config))
-               return 0;
-
-       return -EIO;
-}
-
-static int mxl111sf_fe_ioctl_override(struct dvb_frontend *fe,
-                                     unsigned int cmd, void *parg,
-                                     unsigned int stage)
-{
-       int err = 0;
-
-       switch (stage) {
-       case DVB_FE_IOCTL_PRE:
-
-               switch (cmd) {
-               case FE_READ_SIGNAL_STRENGTH:
-                       err = fe->ops.tuner_ops.get_rf_strength(fe, parg);
-                       /* If no error occurs, prevent dvb-core from handling
-                        * this IOCTL, otherwise return the error */
-                       if (0 == err)
-                               err = 1;
-                       break;
-               }
-               break;
-
-       case DVB_FE_IOCTL_POST:
-               /* no post-ioctl handling required */
-               break;
-       }
-       return err;
-};
-
-static u32 mxl111sf_i2c_func(struct i2c_adapter *adapter)
-{
-       return I2C_FUNC_I2C;
-}
-
-struct i2c_algorithm mxl111sf_i2c_algo = {
-       .master_xfer   = mxl111sf_i2c_xfer,
-       .functionality = mxl111sf_i2c_func,
-#ifdef NEED_ALGO_CONTROL
-       .algo_control = dummy_algo_control,
-#endif
-};
-
-static struct dvb_usb_device_properties mxl111sf_dvbt_bulk_properties;
-static struct dvb_usb_device_properties mxl111sf_dvbt_isoc_properties;
-static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties;
-static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties;
-static struct dvb_usb_device_properties mxl111sf_atsc_mh_bulk_properties;
-static struct dvb_usb_device_properties mxl111sf_atsc_mh_isoc_properties;
-static struct dvb_usb_device_properties mxl111sf_mh_bulk_properties;
-static struct dvb_usb_device_properties mxl111sf_mh_isoc_properties;
-static struct dvb_usb_device_properties mxl111sf_mercury_spi_bulk_properties;
-static struct dvb_usb_device_properties mxl111sf_mercury_spi_isoc_properties;
-static struct dvb_usb_device_properties mxl111sf_mercury_tp_bulk_properties;
-static struct dvb_usb_device_properties mxl111sf_mercury_tp_isoc_properties;
-static struct dvb_usb_device_properties mxl111sf_mercury_mh_spi_bulk_properties;
-static struct dvb_usb_device_properties mxl111sf_mercury_mh_spi_isoc_properties;
-static struct dvb_usb_device_properties mxl111sf_mercury_mh_tp_bulk_properties;
-static struct dvb_usb_device_properties mxl111sf_mercury_mh_tp_isoc_properties;
-
-static int mxl111sf_probe(struct usb_interface *intf,
-                         const struct usb_device_id *id)
-{
-       struct dvb_usb_device *d = NULL;
-
-       deb_adv("%s()\n", __func__);
-
-       if (((dvb_usb_mxl111sf_isoc) &&
-            (0 == dvb_usb_device_init(intf,
-                                      &mxl111sf_dvbt_isoc_properties,
-                                      THIS_MODULE, &d, adapter_nr) ||
-             0 == dvb_usb_device_init(intf,
-                                      &mxl111sf_atsc_isoc_properties,
-                                      THIS_MODULE, &d, adapter_nr) ||
-             0 == dvb_usb_device_init(intf,
-                                      &mxl111sf_atsc_mh_isoc_properties,
-                                      THIS_MODULE, &d, adapter_nr) ||
-             0 == dvb_usb_device_init(intf,
-                                      &mxl111sf_mh_isoc_properties,
-                                      THIS_MODULE, &d, adapter_nr) ||
-             ((dvb_usb_mxl111sf_spi) &&
-              (0 == dvb_usb_device_init(intf,
-                                        &mxl111sf_mercury_spi_isoc_properties,
-                                        THIS_MODULE, &d, adapter_nr) ||
-               0 == dvb_usb_device_init(intf,
-                                        &mxl111sf_mercury_mh_spi_isoc_properties,
-                                        THIS_MODULE, &d, adapter_nr))) ||
-             0 == dvb_usb_device_init(intf,
-                                      &mxl111sf_mercury_tp_isoc_properties,
-                                      THIS_MODULE, &d, adapter_nr) ||
-             0 == dvb_usb_device_init(intf,
-                                      &mxl111sf_mercury_mh_tp_isoc_properties,
-                                      THIS_MODULE, &d, adapter_nr))) ||
-           0 == dvb_usb_device_init(intf,
-                                    &mxl111sf_dvbt_bulk_properties,
-                                    THIS_MODULE, &d, adapter_nr) ||
-           0 == dvb_usb_device_init(intf,
-                                    &mxl111sf_atsc_bulk_properties,
-                                    THIS_MODULE, &d, adapter_nr) ||
-           0 == dvb_usb_device_init(intf,
-                                    &mxl111sf_atsc_mh_bulk_properties,
-                                    THIS_MODULE, &d, adapter_nr) ||
-           0 == dvb_usb_device_init(intf,
-                                    &mxl111sf_mh_bulk_properties,
-                                    THIS_MODULE, &d, adapter_nr) ||
-           ((dvb_usb_mxl111sf_spi) &&
-            (0 == dvb_usb_device_init(intf,
-                                      &mxl111sf_mercury_spi_bulk_properties,
-                                      THIS_MODULE, &d, adapter_nr) ||
-             0 == dvb_usb_device_init(intf,
-                                      &mxl111sf_mercury_mh_spi_bulk_properties,
-                                      THIS_MODULE, &d, adapter_nr))) ||
-           0 == dvb_usb_device_init(intf,
-                                    &mxl111sf_mercury_tp_bulk_properties,
-                                    THIS_MODULE, &d, adapter_nr) ||
-           0 == dvb_usb_device_init(intf,
-                                    &mxl111sf_mercury_mh_tp_bulk_properties,
-                                    THIS_MODULE, &d, adapter_nr) || 0) {
-
-               struct mxl111sf_state *state = d->priv;
-               static u8 eeprom[256];
-               struct i2c_client c;
-               int ret;
-
-               ret = get_chip_info(state);
-               if (mxl_fail(ret))
-                       err("failed to get chip info during probe");
-
-               mutex_init(&state->fe_lock);
-
-               if (state->chip_rev > MXL111SF_V6)
-                       mxl111sf_config_pin_mux_modes(state,
-                                                     PIN_MUX_TS_SPI_IN_MODE_1);
-
-               c.adapter = &d->i2c_adap;
-               c.addr = 0xa0 >> 1;
-
-               ret = tveeprom_read(&c, eeprom, sizeof(eeprom));
-               if (mxl_fail(ret))
-                       return 0;
-               tveeprom_hauppauge_analog(&c, &state->tv,
-                                         (0x84 == eeprom[0xa0]) ?
-                                         eeprom + 0xa0 : eeprom + 0x80);
-#if 0
-               switch (state->tv.model) {
-               case 117001:
-               case 126001:
-               case 138001:
-                       break;
-               default:
-                       printk(KERN_WARNING "%s: warning: "
-                              "unknown hauppauge model #%d\n",
-                              __func__, state->tv.model);
-               }
-#endif
-               return 0;
-       }
-       err("Your device is not yet supported by this driver. "
-           "See kernellabs.com for more info");
-       return -EINVAL;
-}
-
-static struct usb_device_id mxl111sf_table[] = {
-/* 0 */        { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc600) }, /* ATSC+ IR     */
-       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc601) }, /* ATSC         */
-       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc602) }, /*     +        */
-       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc603) }, /* ATSC+        */
-       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc604) }, /* DVBT         */
-/* 5 */        { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc609) }, /* ATSC  IR     */
-       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60a) }, /*     + IR     */
-       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60b) }, /* ATSC+ IR     */
-       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc60c) }, /* DVBT  IR     */
-       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc653) }, /* ATSC+        */
-/*10 */        { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc65b) }, /* ATSC+ IR     */
-       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb700) }, /* ATSC+ sw     */
-       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb701) }, /* ATSC  sw     */
-       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb702) }, /*     + sw     */
-       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb703) }, /* ATSC+ sw     */
-/*15 */        { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb704) }, /* DVBT  sw     */
-       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb753) }, /* ATSC+ sw     */
-       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb763) }, /* ATSC+ no     */
-       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb764) }, /* DVBT  no     */
-       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd853) }, /* ATSC+ sw     */
-/*20 */        { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd854) }, /* DVBT  sw     */
-       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd863) }, /* ATSC+ no     */
-       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd864) }, /* DVBT  no     */
-       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8d3) }, /* ATSC+ sw     */
-       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8d4) }, /* DVBT  sw     */
-/*25 */        { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8e3) }, /* ATSC+ no     */
-       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8e4) }, /* DVBT  no     */
-       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xd8ff) }, /* ATSC+        */
-       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc612) }, /*     +        */
-       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc613) }, /* ATSC+        */
-/*30 */        { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc61a) }, /*     + IR     */
-       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xc61b) }, /* ATSC+ IR     */
-       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb757) }, /* ATSC+DVBT sw */
-       { USB_DEVICE(USB_VID_HAUPPAUGE, 0xb767) }, /* ATSC+DVBT no */
-       {}              /* Terminating entry */
-};
-MODULE_DEVICE_TABLE(usb, mxl111sf_table);
-
-
-#define MXL111SF_EP4_BULK_STREAMING_CONFIG             \
-       .size_of_priv = sizeof(struct mxl111sf_adap_state), \
-       .streaming_ctrl = mxl111sf_ep4_streaming_ctrl,  \
-       .stream = {                                     \
-               .type = USB_BULK,                       \
-               .count = 5,                             \
-               .endpoint = 0x04,                       \
-               .u = {                                  \
-                       .bulk = {                       \
-                               .buffersize = 8192,     \
-                       }                               \
-               }                                       \
-       }
-
-/* FIXME: works for v6 but not v8 silicon */
-#define MXL111SF_EP4_ISOC_STREAMING_CONFIG             \
-       .size_of_priv = sizeof(struct mxl111sf_adap_state), \
-       .streaming_ctrl = mxl111sf_ep4_streaming_ctrl,  \
-       .stream = {                                     \
-               .type = USB_ISOC,                       \
-               .count = 5,                             \
-               .endpoint = 0x04,                       \
-               .u = {                                  \
-                       .isoc = {                       \
-                               .framesperurb = 96,     \
-                               /* FIXME: v6 SILICON: */        \
-                               .framesize = 564,       \
-                               .interval = 1,          \
-                       }                               \
-               }                                       \
-       }
-
-#define MXL111SF_EP5_BULK_STREAMING_CONFIG             \
-       .size_of_priv = sizeof(struct mxl111sf_adap_state), \
-       .streaming_ctrl = mxl111sf_ep5_streaming_ctrl,  \
-       .stream = {                                     \
-               .type = USB_BULK,                       \
-               .count = 5,                             \
-               .endpoint = 0x05,                       \
-               .u = {                                  \
-                       .bulk = {                       \
-                               .buffersize = 8192,     \
-                       }                               \
-               }                                       \
-       }
-
-#define MXL111SF_EP5_ISOC_STREAMING_CONFIG             \
-       .size_of_priv = sizeof(struct mxl111sf_adap_state), \
-       .streaming_ctrl = mxl111sf_ep5_streaming_ctrl,  \
-       .stream = {                                     \
-               .type = USB_ISOC,                       \
-               .count = 5,                             \
-               .endpoint = 0x05,                       \
-               .u = {                                  \
-                       .isoc = {                       \
-                               .framesperurb = 96,     \
-                               .framesize = 200,       \
-                               .interval = 1,          \
-                       }                               \
-               }                                       \
-       }
-
-#define MXL111SF_EP6_BULK_STREAMING_CONFIG             \
-       .size_of_priv = sizeof(struct mxl111sf_adap_state), \
-       .streaming_ctrl = mxl111sf_ep6_streaming_ctrl,  \
-       .stream = {                                     \
-               .type = USB_BULK,                       \
-               .count = 5,                             \
-               .endpoint = 0x06,                       \
-               .u = {                                  \
-                       .bulk = {                       \
-                               .buffersize = 8192,     \
-                       }                               \
-               }                                       \
-       }
-
-/* FIXME */
-#define MXL111SF_EP6_ISOC_STREAMING_CONFIG             \
-       .size_of_priv = sizeof(struct mxl111sf_adap_state), \
-       .streaming_ctrl = mxl111sf_ep6_streaming_ctrl,  \
-       .stream = {                                     \
-               .type = USB_ISOC,                       \
-               .count = 5,                             \
-               .endpoint = 0x06,                       \
-               .u = {                                  \
-                       .isoc = {                       \
-                               .framesperurb = 24,     \
-                               .framesize = 3072,      \
-                               .interval = 1,          \
-                       }                               \
-               }                                       \
-       }
-
-#define MXL111SF_DEFAULT_DEVICE_PROPERTIES                     \
-       .caps = DVB_USB_IS_AN_I2C_ADAPTER,                      \
-       .usb_ctrl = DEVICE_SPECIFIC,                            \
-       /* use usb alt setting 1 for EP4 ISOC transfer (dvb-t), \
-                                    EP6 BULK transfer (atsc/qam), \
-          use usb alt setting 2 for EP4 BULK transfer (dvb-t), \
-                                    EP6 ISOC transfer (atsc/qam), \
-       */                                                      \
-       .power_ctrl       = mxl111sf_power_ctrl,                \
-       .i2c_algo         = &mxl111sf_i2c_algo,                 \
-       .generic_bulk_ctrl_endpoint          = MXL_EP2_REG_WRITE, \
-       .generic_bulk_ctrl_endpoint_response = MXL_EP1_REG_READ, \
-       .size_of_priv     = sizeof(struct mxl111sf_state)
-
-static struct dvb_usb_device_properties mxl111sf_dvbt_bulk_properties = {
-       MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
-       .num_adapters = 1,
-       .adapter = {
-               {
-               .fe_ioctl_override = mxl111sf_fe_ioctl_override,
-               .num_frontends = 1,
-               .fe = {{
-                       .frontend_attach  = mxl111sf_attach_demod,
-                       .tuner_attach     = mxl111sf_attach_tuner,
-
-                       MXL111SF_EP4_BULK_STREAMING_CONFIG,
-               } },
-               },
-       },
-       .num_device_descs = 3,
-       .devices = {
-               {   "Hauppauge 126xxx DVBT (bulk)",
-                       { NULL },
-                       { &mxl111sf_table[4], &mxl111sf_table[8],
-                         NULL },
-               },
-               {   "Hauppauge 117xxx DVBT (bulk)",
-                       { NULL },
-                       { &mxl111sf_table[15], &mxl111sf_table[18],
-                         NULL },
-               },
-               {   "Hauppauge 138xxx DVBT (bulk)",
-                       { NULL },
-                       { &mxl111sf_table[20], &mxl111sf_table[22],
-                         &mxl111sf_table[24], &mxl111sf_table[26],
-                         NULL },
-               },
-       }
-};
-
-static struct dvb_usb_device_properties mxl111sf_dvbt_isoc_properties = {
-       MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
-       .num_adapters = 1,
-       .adapter = {
-               {
-               .fe_ioctl_override = mxl111sf_fe_ioctl_override,
-               .num_frontends = 1,
-               .fe = {{
-                       .frontend_attach  = mxl111sf_attach_demod,
-                       .tuner_attach     = mxl111sf_attach_tuner,
-
-                       MXL111SF_EP4_ISOC_STREAMING_CONFIG,
-               } },
-               },
-       },
-       .num_device_descs = 3,
-       .devices = {
-               {   "Hauppauge 126xxx DVBT (isoc)",
-                       { NULL },
-                       { &mxl111sf_table[4], &mxl111sf_table[8],
-                         NULL },
-               },
-               {   "Hauppauge 117xxx DVBT (isoc)",
-                       { NULL },
-                       { &mxl111sf_table[15], &mxl111sf_table[18],
-                         NULL },
-               },
-               {   "Hauppauge 138xxx DVBT (isoc)",
-                       { NULL },
-                       { &mxl111sf_table[20], &mxl111sf_table[22],
-                         &mxl111sf_table[24], &mxl111sf_table[26],
-                         NULL },
-               },
-       }
-};
-
-static struct dvb_usb_device_properties mxl111sf_atsc_bulk_properties = {
-       MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
-       .num_adapters = 1,
-       .adapter = {
-               {
-               .fe_ioctl_override = mxl111sf_fe_ioctl_override,
-               .num_frontends = 1,
-               .fe = {{
-                       .frontend_attach  = mxl111sf_lgdt3305_frontend_attach,
-                       .tuner_attach     = mxl111sf_attach_tuner,
-
-                       MXL111SF_EP6_BULK_STREAMING_CONFIG,
-               }},
-               },
-       },
-       .num_device_descs = 2,
-       .devices = {
-               {   "Hauppauge 126xxx ATSC (bulk)",
-                       { NULL },
-                       { &mxl111sf_table[1], &mxl111sf_table[5],
-                         NULL },
-               },
-               {   "Hauppauge 117xxx ATSC (bulk)",
-                       { NULL },
-                       { &mxl111sf_table[12],
-                         NULL },
-               },
-       }
-};
-
-static struct dvb_usb_device_properties mxl111sf_atsc_isoc_properties = {
-       MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
-       .num_adapters = 1,
-       .adapter = {
-               {
-               .fe_ioctl_override = mxl111sf_fe_ioctl_override,
-               .num_frontends = 1,
-               .fe = {{
-                       .frontend_attach  = mxl111sf_lgdt3305_frontend_attach,
-                       .tuner_attach     = mxl111sf_attach_tuner,
-
-                       MXL111SF_EP6_ISOC_STREAMING_CONFIG,
-               }},
-               },
-       },
-       .num_device_descs = 2,
-       .devices = {
-               {   "Hauppauge 126xxx ATSC (isoc)",
-                       { NULL },
-                       { &mxl111sf_table[1], &mxl111sf_table[5],
-                         NULL },
-               },
-               {   "Hauppauge 117xxx ATSC (isoc)",
-                       { NULL },
-                       { &mxl111sf_table[12],
-                         NULL },
-               },
-       }
-};
-
-static struct dvb_usb_device_properties mxl111sf_mh_bulk_properties = {
-       MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
-       .num_adapters = 1,
-       .adapter = {
-               {
-               .fe_ioctl_override = mxl111sf_fe_ioctl_override,
-               .num_frontends = 1,
-               .fe = {{
-                       .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
-
-                       .frontend_attach  = mxl111sf_lg2160_frontend_attach,
-                       .tuner_attach     = mxl111sf_attach_tuner,
-
-                       MXL111SF_EP5_BULK_STREAMING_CONFIG,
-               }},
-               },
-       },
-       .num_device_descs = 2,
-       .devices = {
-               {   "HCW 126xxx (bulk)",
-                       { NULL },
-                       { &mxl111sf_table[2], &mxl111sf_table[6],
-                         NULL },
-               },
-               {   "HCW 117xxx (bulk)",
-                       { NULL },
-                       { &mxl111sf_table[13],
-                         NULL },
-               },
-       }
-};
-
-static struct dvb_usb_device_properties mxl111sf_mh_isoc_properties = {
-       MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
-       .num_adapters = 1,
-       .adapter = {
-               {
-               .fe_ioctl_override = mxl111sf_fe_ioctl_override,
-               .num_frontends = 1,
-               .fe = {{
-                       .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
-
-                       .frontend_attach  = mxl111sf_lg2160_frontend_attach,
-                       .tuner_attach     = mxl111sf_attach_tuner,
-
-                       MXL111SF_EP5_ISOC_STREAMING_CONFIG,
-               }},
-               },
-       },
-       .num_device_descs = 2,
-       .devices = {
-               {   "HCW 126xxx (isoc)",
-                       { NULL },
-                       { &mxl111sf_table[2], &mxl111sf_table[6],
-                         NULL },
-               },
-               {   "HCW 117xxx (isoc)",
-                       { NULL },
-                       { &mxl111sf_table[13],
-                         NULL },
-               },
-       }
-};
-
-static struct dvb_usb_device_properties mxl111sf_atsc_mh_bulk_properties = {
-       MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
-       .num_adapters = 1,
-       .adapter = {
-               {
-               .fe_ioctl_override = mxl111sf_fe_ioctl_override,
-               .num_frontends = 3,
-               .fe = {{
-                       .frontend_attach  = mxl111sf_lgdt3305_frontend_attach,
-                       .tuner_attach     = mxl111sf_attach_tuner,
-
-                       MXL111SF_EP6_BULK_STREAMING_CONFIG,
-               },
-               {
-                       .frontend_attach  = mxl111sf_attach_demod,
-                       .tuner_attach     = mxl111sf_attach_tuner,
-
-                       MXL111SF_EP4_BULK_STREAMING_CONFIG,
-               },
-               {
-                       .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
-
-                       .frontend_attach  = mxl111sf_lg2160_frontend_attach,
-                       .tuner_attach     = mxl111sf_attach_tuner,
-
-                       MXL111SF_EP5_BULK_STREAMING_CONFIG,
-               }},
-               },
-       },
-       .num_device_descs = 2,
-       .devices = {
-               {   "Hauppauge 126xxx ATSC+ (bulk)",
-                       { NULL },
-                       { &mxl111sf_table[0], &mxl111sf_table[3],
-                         &mxl111sf_table[7], &mxl111sf_table[9],
-                         &mxl111sf_table[10], NULL },
-               },
-               {   "Hauppauge 117xxx ATSC+ (bulk)",
-                       { NULL },
-                       { &mxl111sf_table[11], &mxl111sf_table[14],
-                         &mxl111sf_table[16], &mxl111sf_table[17],
-                         &mxl111sf_table[32], &mxl111sf_table[33],
-                         NULL },
-               },
-       }
-};
-
-static struct dvb_usb_device_properties mxl111sf_atsc_mh_isoc_properties = {
-       MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
-       .num_adapters = 1,
-       .adapter = {
-               {
-               .fe_ioctl_override = mxl111sf_fe_ioctl_override,
-               .num_frontends = 3,
-               .fe = {{
-                       .frontend_attach  = mxl111sf_lgdt3305_frontend_attach,
-                       .tuner_attach     = mxl111sf_attach_tuner,
-
-                       MXL111SF_EP6_ISOC_STREAMING_CONFIG,
-               },
-               {
-                       .frontend_attach  = mxl111sf_attach_demod,
-                       .tuner_attach     = mxl111sf_attach_tuner,
-
-                       MXL111SF_EP4_ISOC_STREAMING_CONFIG,
-               },
-               {
-                       .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
-
-                       .frontend_attach  = mxl111sf_lg2160_frontend_attach,
-                       .tuner_attach     = mxl111sf_attach_tuner,
-
-                       MXL111SF_EP5_ISOC_STREAMING_CONFIG,
-               }},
-               },
-       },
-       .num_device_descs = 2,
-       .devices = {
-               {   "Hauppauge 126xxx ATSC+ (isoc)",
-                       { NULL },
-                       { &mxl111sf_table[0], &mxl111sf_table[3],
-                         &mxl111sf_table[7], &mxl111sf_table[9],
-                         &mxl111sf_table[10], NULL },
-               },
-               {   "Hauppauge 117xxx ATSC+ (isoc)",
-                       { NULL },
-                       { &mxl111sf_table[11], &mxl111sf_table[14],
-                         &mxl111sf_table[16], &mxl111sf_table[17],
-                         &mxl111sf_table[32], &mxl111sf_table[33],
-                         NULL },
-               },
-       }
-};
-
-static struct dvb_usb_device_properties mxl111sf_mercury_spi_bulk_properties = {
-       MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
-       .num_adapters = 1,
-       .adapter = {
-               {
-               .fe_ioctl_override = mxl111sf_fe_ioctl_override,
-               .num_frontends = 3,
-               .fe = {{
-                       .frontend_attach  = mxl111sf_lgdt3305_frontend_attach,
-                       .tuner_attach     = mxl111sf_attach_tuner,
-
-                       MXL111SF_EP6_BULK_STREAMING_CONFIG,
-               },
-               {
-                       .frontend_attach  = mxl111sf_attach_demod,
-                       .tuner_attach     = mxl111sf_attach_tuner,
-
-                       MXL111SF_EP4_BULK_STREAMING_CONFIG,
-               },
-               {
-                       .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
-
-                       .frontend_attach  = mxl111sf_lg2161_frontend_attach,
-                       .tuner_attach     = mxl111sf_attach_tuner,
-
-                       MXL111SF_EP5_BULK_STREAMING_CONFIG,
-               }},
-               },
-       },
-       .num_device_descs = 2,
-       .devices = {
-               {   "Hauppauge Mercury (spi-bulk)",
-                       { NULL },
-                       { &mxl111sf_table[19], &mxl111sf_table[21],
-                         &mxl111sf_table[23], &mxl111sf_table[25],
-                         NULL },
-               },
-               {   "Hauppauge WinTV-Aero-M (spi-bulk)",
-                       { NULL },
-                       { &mxl111sf_table[29], &mxl111sf_table[31],
-                         NULL },
-               },
-       }
-};
-
-static struct dvb_usb_device_properties mxl111sf_mercury_spi_isoc_properties = {
-       MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
-       .num_adapters = 1,
-       .adapter = {
-               {
-               .fe_ioctl_override = mxl111sf_fe_ioctl_override,
-               .num_frontends = 3,
-               .fe = {{
-                       .frontend_attach  = mxl111sf_lgdt3305_frontend_attach,
-                       .tuner_attach     = mxl111sf_attach_tuner,
-
-                       MXL111SF_EP6_ISOC_STREAMING_CONFIG,
-               },
-               {
-                       .frontend_attach  = mxl111sf_attach_demod,
-                       .tuner_attach     = mxl111sf_attach_tuner,
-
-                       MXL111SF_EP4_ISOC_STREAMING_CONFIG,
-               },
-               {
-                       .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
-
-                       .frontend_attach  = mxl111sf_lg2161_frontend_attach,
-                       .tuner_attach     = mxl111sf_attach_tuner,
-
-                       MXL111SF_EP5_ISOC_STREAMING_CONFIG,
-               }},
-               },
-       },
-       .num_device_descs = 2,
-       .devices = {
-               {   "Hauppauge Mercury (spi-isoc)",
-                       { NULL },
-                       { &mxl111sf_table[19], &mxl111sf_table[21],
-                         &mxl111sf_table[23], &mxl111sf_table[25],
-                         NULL },
-               },
-               {   "Hauppauge WinTV-Aero-M (spi-isoc)",
-                       { NULL },
-                       { &mxl111sf_table[29], &mxl111sf_table[31],
-                         NULL },
-               },
-       }
-};
-
-static struct dvb_usb_device_properties mxl111sf_mercury_tp_bulk_properties = {
-       MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
-       .num_adapters = 1,
-       .adapter = {
-               {
-               .fe_ioctl_override = mxl111sf_fe_ioctl_override,
-               .num_frontends = 3,
-               .fe = {{
-                       .frontend_attach  = mxl111sf_lgdt3305_frontend_attach,
-                       .tuner_attach     = mxl111sf_attach_tuner,
-
-                       MXL111SF_EP6_BULK_STREAMING_CONFIG,
-               },
-               {
-                       .frontend_attach  = mxl111sf_attach_demod,
-                       .tuner_attach     = mxl111sf_attach_tuner,
-
-                       MXL111SF_EP4_BULK_STREAMING_CONFIG,
-               },
-               {
-                       .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
-
-                       .frontend_attach  = mxl111sf_lg2161_ep6_frontend_attach,
-                       .tuner_attach     = mxl111sf_attach_tuner,
-
-                       MXL111SF_EP6_BULK_STREAMING_CONFIG,
-               }},
-               },
-       },
-       .num_device_descs = 2,
-       .devices = {
-               {   "Hauppauge Mercury (tp-bulk)",
-                       { NULL },
-                       { &mxl111sf_table[19], &mxl111sf_table[21],
-                         &mxl111sf_table[23], &mxl111sf_table[25],
-                         &mxl111sf_table[27], NULL },
-               },
-               {   "Hauppauge WinTV-Aero-M",
-                       { NULL },
-                       { &mxl111sf_table[29], &mxl111sf_table[31],
-                         NULL },
-               },
-       }
-};
-
-static struct dvb_usb_device_properties mxl111sf_mercury_tp_isoc_properties = {
-       MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
-       .num_adapters = 1,
-       .adapter = {
-               {
-               .fe_ioctl_override = mxl111sf_fe_ioctl_override,
-               .num_frontends = 3,
-               .fe = {{
-                       .frontend_attach  = mxl111sf_lgdt3305_frontend_attach,
-                       .tuner_attach     = mxl111sf_attach_tuner,
-
-                       MXL111SF_EP6_ISOC_STREAMING_CONFIG,
-               },
-               {
-                       .frontend_attach  = mxl111sf_attach_demod,
-                       .tuner_attach     = mxl111sf_attach_tuner,
-
-                       MXL111SF_EP4_ISOC_STREAMING_CONFIG,
-               },
-               {
-                       .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
-
-                       .frontend_attach  = mxl111sf_lg2161_ep6_frontend_attach,
-                       .tuner_attach     = mxl111sf_attach_tuner,
-
-                       MXL111SF_EP6_ISOC_STREAMING_CONFIG,
-               }},
-               },
-       },
-       .num_device_descs = 2,
-       .devices = {
-               {   "Hauppauge Mercury (tp-isoc)",
-                       { NULL },
-                       { &mxl111sf_table[19], &mxl111sf_table[21],
-                         &mxl111sf_table[23], &mxl111sf_table[25],
-                         &mxl111sf_table[27], NULL },
-               },
-               {   "Hauppauge WinTV-Aero-M (tp-isoc)",
-                       { NULL },
-                       { &mxl111sf_table[29], &mxl111sf_table[31],
-                         NULL },
-               },
-       }
-};
-
-static
-struct dvb_usb_device_properties mxl111sf_mercury_mh_tp_bulk_properties = {
-       MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
-       .num_adapters = 1,
-       .adapter = {
-               {
-               .fe_ioctl_override = mxl111sf_fe_ioctl_override,
-               .num_frontends = 2,
-               .fe = {{
-                       .frontend_attach  = mxl111sf_attach_demod,
-                       .tuner_attach     = mxl111sf_attach_tuner,
-
-                       MXL111SF_EP4_BULK_STREAMING_CONFIG,
-               },
-               {
-                       .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
-
-                       .frontend_attach  = mxl111sf_lg2161_ep6_frontend_attach,
-                       .tuner_attach     = mxl111sf_attach_tuner,
-
-                       MXL111SF_EP6_BULK_STREAMING_CONFIG,
-               }},
-               },
-       },
-       .num_device_descs = 1,
-       .devices = {
-               {   "Hauppauge 126xxx (tp-bulk)",
-                       { NULL },
-                       { &mxl111sf_table[28], &mxl111sf_table[30],
-                         NULL },
-               },
-       }
-};
-
-static
-struct dvb_usb_device_properties mxl111sf_mercury_mh_tp_isoc_properties = {
-       MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
-       .num_adapters = 1,
-       .adapter = {
-               {
-               .fe_ioctl_override = mxl111sf_fe_ioctl_override,
-               .num_frontends = 2,
-               .fe = {{
-                       .frontend_attach  = mxl111sf_attach_demod,
-                       .tuner_attach     = mxl111sf_attach_tuner,
-
-                       MXL111SF_EP4_ISOC_STREAMING_CONFIG,
-               },
-               {
-                       .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
-
-                       .frontend_attach  = mxl111sf_lg2161_ep6_frontend_attach,
-                       .tuner_attach     = mxl111sf_attach_tuner,
-
-                       MXL111SF_EP6_ISOC_STREAMING_CONFIG,
-               }},
-               },
-       },
-       .num_device_descs = 1,
-       .devices = {
-               {   "Hauppauge 126xxx (tp-isoc)",
-                       { NULL },
-                       { &mxl111sf_table[28], &mxl111sf_table[30],
-                         NULL },
-               },
-       }
-};
-
-static
-struct dvb_usb_device_properties mxl111sf_mercury_mh_spi_bulk_properties = {
-       MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
-       .num_adapters = 1,
-       .adapter = {
-               {
-               .fe_ioctl_override = mxl111sf_fe_ioctl_override,
-               .num_frontends = 2,
-               .fe = {{
-                       .frontend_attach  = mxl111sf_attach_demod,
-                       .tuner_attach     = mxl111sf_attach_tuner,
-
-                       MXL111SF_EP4_BULK_STREAMING_CONFIG,
-               },
-               {
-                       .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
-
-                       .frontend_attach  = mxl111sf_lg2161_frontend_attach,
-                       .tuner_attach     = mxl111sf_attach_tuner,
-
-                       MXL111SF_EP5_BULK_STREAMING_CONFIG,
-               }},
-               },
-       },
-       .num_device_descs = 1,
-       .devices = {
-               {   "Hauppauge 126xxx (spi-bulk)",
-                       { NULL },
-                       { &mxl111sf_table[28], &mxl111sf_table[30],
-                         NULL },
-               },
-       }
-};
-
-static
-struct dvb_usb_device_properties mxl111sf_mercury_mh_spi_isoc_properties = {
-       MXL111SF_DEFAULT_DEVICE_PROPERTIES,
-
-       .num_adapters = 1,
-       .adapter = {
-               {
-               .fe_ioctl_override = mxl111sf_fe_ioctl_override,
-               .num_frontends = 2,
-               .fe = {{
-                       .frontend_attach  = mxl111sf_attach_demod,
-                       .tuner_attach     = mxl111sf_attach_tuner,
-
-                       MXL111SF_EP4_ISOC_STREAMING_CONFIG,
-               },
-               {
-                       .caps = DVB_USB_ADAP_RECEIVES_RAW_PAYLOAD,
-
-                       .frontend_attach  = mxl111sf_lg2161_frontend_attach,
-                       .tuner_attach     = mxl111sf_attach_tuner,
-
-                       MXL111SF_EP5_ISOC_STREAMING_CONFIG,
-               }},
-               },
-       },
-       .num_device_descs = 1,
-       .devices = {
-               {   "Hauppauge 126xxx (spi-isoc)",
-                       { NULL },
-                       { &mxl111sf_table[28], &mxl111sf_table[30],
-                         NULL },
-               },
-       }
-};
-
-static struct usb_driver mxl111sf_driver = {
-       .name           = "dvb_usb_mxl111sf",
-       .probe          = mxl111sf_probe,
-       .disconnect     = dvb_usb_device_exit,
-       .id_table       = mxl111sf_table,
-};
-
-module_usb_driver(mxl111sf_driver);
-
-MODULE_AUTHOR("Michael Krufky <mkrufky@kernellabs.com>");
-MODULE_DESCRIPTION("Driver for MaxLinear MxL111SF");
-MODULE_VERSION("1.0");
-MODULE_LICENSE("GPL");
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
index 5cfe151ee394057cfac74059c10ed557494191f1..3559ff230045450ad885bf8e118aaa27a80c50df 100644 (file)
@@ -26,8 +26,6 @@
 #include "dvb_frontend.h"
 #include "au8522_priv.h"
 
-MODULE_LICENSE("GPL");
-
 static int debug;
 
 #define dprintk(arg...)\
@@ -101,6 +99,19 @@ int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
 }
 EXPORT_SYMBOL(au8522_i2c_gate_ctrl);
 
+int au8522_analog_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+       struct au8522_state *state = fe->demodulator_priv;
+
+       dprintk("%s(%d)\n", __func__, enable);
+
+       if (enable)
+               return au8522_writereg(state, 0x106, 1);
+       else
+               return au8522_writereg(state, 0x106, 0);
+}
+EXPORT_SYMBOL(au8522_analog_i2c_gate_ctrl);
+
 /* Reset the demod hardware and reset all of the configuration registers
    to a default state. */
 int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c,
@@ -257,3 +268,10 @@ int au8522_sleep(struct dvb_frontend *fe)
        return 0;
 }
 EXPORT_SYMBOL(au8522_sleep);
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable verbose debug messages");
+
+MODULE_DESCRIPTION("Auvitek AU8522 QAM-B/ATSC Demodulator driver");
+MODULE_AUTHOR("Steven Toth");
+MODULE_LICENSE("GPL");
index 55b6390198e34d3ac7b77a71194645cbf33d1951..5243ba6295cc1aabd93796aa23e90bdb300c59ad 100644 (file)
@@ -257,9 +257,11 @@ static void setup_decoder_defaults(struct au8522_state *state, u8 input_mode)
        au8522_writereg(state, AU8522_TVDED_DBG_MODE_REG060H,
                        AU8522_TVDED_DBG_MODE_REG060H_CVBS);
        au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL1_REG061H,
-                       AU8522_TVDEC_FORMAT_CTRL1_REG061H_CVBS13);
+                       AU8522_TVDEC_FORMAT_CTRL1_REG061H_FIELD_LEN_525 |
+                       AU8522_TVDEC_FORMAT_CTRL1_REG061H_LINE_LEN_63_492 |
+                       AU8522_TVDEC_FORMAT_CTRL1_REG061H_SUBCARRIER_NTSC_MN);
        au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL2_REG062H,
-                       AU8522_TVDEC_FORMAT_CTRL2_REG062H_CVBS13);
+                       AU8522_TVDEC_FORMAT_CTRL2_REG062H_STD_NTSC);
        au8522_writereg(state, AU8522_TVDEC_VCR_DET_LLIM_REG063H,
                        AU8522_TVDEC_VCR_DET_LLIM_REG063H_CVBS);
        au8522_writereg(state, AU8522_TVDEC_VCR_DET_HLIM_REG064H,
@@ -657,11 +659,6 @@ static int au8522_s_video_routing(struct v4l2_subdev *sd,
 
        au8522_reset(sd, 0);
 
-       /* Jam open the i2c gate to the tuner.  We do this here to handle the
-          case where the user went into digital mode (causing the gate to be
-          closed), and then came back to analog mode */
-       au8522_writereg(state, 0x106, 1);
-
        if (input == AU8522_COMPOSITE_CH1) {
                au8522_setup_cvbs_mode(state);
        } else if (input == AU8522_SVIDEO_CH13) {
index 5fc70d6cd04fad4e813d94c736d599d1cf22b3d3..a68974f6d7081f2bc877b43e3c9481d49de45dc9 100644 (file)
@@ -157,54 +157,54 @@ static struct mse2snr_tab qam64_mse2snr_tab[] = {
 
 /* QAM256 SNR lookup table */
 static struct mse2snr_tab qam256_mse2snr_tab[] = {
-       {  16,   0 },
-       {  17, 400 },
-       {  18, 398 },
-       {  19, 396 },
-       {  20, 394 },
-       {  21, 392 },
-       {  22, 390 },
-       {  23, 388 },
-       {  24, 386 },
-       {  25, 384 },
-       {  26, 382 },
-       {  27, 380 },
-       {  28, 379 },
-       {  29, 378 },
-       {  30, 377 },
-       {  31, 376 },
-       {  32, 375 },
-       {  33, 374 },
-       {  34, 373 },
-       {  35, 372 },
-       {  36, 371 },
-       {  37, 370 },
-       {  38, 362 },
-       {  39, 354 },
-       {  40, 346 },
-       {  41, 338 },
-       {  42, 330 },
-       {  43, 328 },
-       {  44, 326 },
-       {  45, 324 },
-       {  46, 322 },
-       {  47, 320 },
-       {  48, 319 },
-       {  49, 318 },
-       {  50, 317 },
-       {  51, 316 },
-       {  52, 315 },
-       {  53, 314 },
-       {  54, 313 },
-       {  55, 312 },
-       {  56, 311 },
-       {  57, 310 },
-       {  58, 308 },
-       {  59, 306 },
-       {  60, 304 },
-       {  61, 302 },
-       {  62, 300 },
-       {  63, 298 },
+       {  15,   0 },
+       {  16, 400 },
+       {  17, 398 },
+       {  18, 396 },
+       {  19, 394 },
+       {  20, 392 },
+       {  21, 390 },
+       {  22, 388 },
+       {  23, 386 },
+       {  24, 384 },
+       {  25, 382 },
+       {  26, 380 },
+       {  27, 379 },
+       {  28, 378 },
+       {  29, 377 },
+       {  30, 376 },
+       {  31, 375 },
+       {  32, 374 },
+       {  33, 373 },
+       {  34, 372 },
+       {  35, 371 },
+       {  36, 370 },
+       {  37, 362 },
+       {  38, 354 },
+       {  39, 346 },
+       {  40, 338 },
+       {  41, 330 },
+       {  42, 328 },
+       {  43, 326 },
+       {  44, 324 },
+       {  45, 322 },
+       {  46, 320 },
+       {  47, 319 },
+       {  48, 318 },
+       {  49, 317 },
+       {  50, 316 },
+       {  51, 315 },
+       {  52, 314 },
+       {  53, 313 },
+       {  54, 312 },
+       {  55, 311 },
+       {  56, 310 },
+       {  57, 308 },
+       {  58, 306 },
+       {  59, 304 },
+       {  60, 302 },
+       {  61, 300 },
+       {  62, 298 },
        {  65, 295 },
        {  68, 294 },
        {  70, 293 },
@@ -777,6 +777,8 @@ struct dvb_frontend *au8522_attach(const struct au8522_config *config,
               sizeof(struct dvb_frontend_ops));
        state->frontend.demodulator_priv = state;
 
+       state->frontend.ops.analog_ops.i2c_gate_ctrl = au8522_analog_i2c_gate_ctrl;
+
        if (au8522_init(&state->frontend) != 0) {
                printk(KERN_ERR "%s: Failed to initialize correctly\n",
                        __func__);
index 6e4a438732b569717a8f9e89bf78e6a532ab8c36..0529699a27bd64188f8c625d245db12278eb95e3 100644 (file)
@@ -82,6 +82,7 @@ int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c,
                     u8 client_address);
 void au8522_release_state(struct au8522_state *state);
 int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable);
+int au8522_analog_i2c_gate_ctrl(struct dvb_frontend *fe, int enable);
 int au8522_led_ctrl(struct au8522_state *state, int led);
 
 /* REGISTERS */
@@ -325,6 +326,31 @@ int au8522_led_ctrl(struct au8522_state *state, int led);
 
 /**************************************************************/
 
+/* Format control 1 */
+
+/* VCR Mode 7-6 */
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_VCR_MODE_YES         0x80
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_VCR_MODE_NO          0x40
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_VCR_MODE_AUTO                0x00
+/* Field len 5-4 */
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_FIELD_LEN_625                0x20
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_FIELD_LEN_525                0x10
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_FIELD_LEN_AUTO       0x00
+/* Line len (us) 3-2 */
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_LINE_LEN_64_000      0x0b
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_LINE_LEN_63_492      0x08
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_LINE_LEN_63_556      0x04
+/* Subcarrier freq 1-0 */
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_SUBCARRIER_NTSC_AUTO 0x03
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_SUBCARRIER_NTSC_443  0x02
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_SUBCARRIER_NTSC_MN   0x01
+#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_SUBCARRIER_NTSC_50   0x00
+
+/* Format control 2 */
+#define AU8522_TVDEC_FORMAT_CTRL2_REG062H_STD_AUTODETECT       0x00
+#define AU8522_TVDEC_FORMAT_CTRL2_REG062H_STD_NTSC             0x01
+
+
 #define AU8522_INPUT_CONTROL_REG081H_ATSC                      0xC4
 #define AU8522_INPUT_CONTROL_REG081H_ATVRF                     0xC4
 #define AU8522_INPUT_CONTROL_REG081H_ATVRF13                   0xC4
@@ -385,9 +411,6 @@ int au8522_led_ctrl(struct au8522_state *state, int led);
 #define AU8522_TVDEC_COMB_MODE_REG015H_CVBS                    0x00
 #define AU8522_REG016H_CVBS                                    0x00
 #define AU8522_TVDED_DBG_MODE_REG060H_CVBS                     0x00
-#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_CVBS                 0x0B
-#define AU8522_TVDEC_FORMAT_CTRL1_REG061H_CVBS13               0x03
-#define AU8522_TVDEC_FORMAT_CTRL2_REG062H_CVBS13               0x00
 #define AU8522_TVDEC_VCR_DET_LLIM_REG063H_CVBS                 0x19
 #define AU8522_REG0F9H_AUDIO                                   0x20
 #define AU8522_TVDEC_VCR_DET_HLIM_REG064H_CVBS                 0xA7
index 1ab34838221c0b14d09bdfec5bb67bbce382bd1c..6d8fe884323714f89392ecf221e81f3c6b8b0214 100644 (file)
@@ -116,6 +116,31 @@ static struct dvb_pll_desc dvb_pll_thomson_dtt759x = {
        },
 };
 
+static void thomson_dtt7520x_bw(struct dvb_frontend *fe, u8 *buf)
+{
+       u32 bw = fe->dtv_property_cache.bandwidth_hz;
+       if (bw == 8000000)
+               buf[3] ^= 0x10;
+}
+
+static struct dvb_pll_desc dvb_pll_thomson_dtt7520x = {
+       .name  = "Thomson dtt7520x",
+       .min   = 185000000,
+       .max   = 900000000,
+       .set   = thomson_dtt7520x_bw,
+       .iffreq = 36166667,
+       .count = 7,
+       .entries = {
+               {  305000000, 166667, 0xb4, 0x12 },
+               {  405000000, 166667, 0xbc, 0x12 },
+               {  445000000, 166667, 0xbc, 0x12 },
+               {  465000000, 166667, 0xf4, 0x18 },
+               {  735000000, 166667, 0xfc, 0x18 },
+               {  835000000, 166667, 0xbc, 0x18 },
+               {  999999999, 166667, 0xfc, 0x18 },
+       },
+};
+
 static struct dvb_pll_desc dvb_pll_lg_z201 = {
        .name  = "LG z201",
        .min   = 174000000,
@@ -513,6 +538,7 @@ static struct dvb_pll_desc *pll_list[] = {
        [DVB_PLL_UNDEFINED]              = NULL,
        [DVB_PLL_THOMSON_DTT7579]        = &dvb_pll_thomson_dtt7579,
        [DVB_PLL_THOMSON_DTT759X]        = &dvb_pll_thomson_dtt759x,
+       [DVB_PLL_THOMSON_DTT7520X]       = &dvb_pll_thomson_dtt7520x,
        [DVB_PLL_LG_Z201]                = &dvb_pll_lg_z201,
        [DVB_PLL_UNKNOWN_1]              = &dvb_pll_unknown_1,
        [DVB_PLL_TUA6010XS]              = &dvb_pll_tua6010xs,
index 086964344c38bd180d0fe6f798d918f48d7edada..4de754f76ce95d8b7183f76117579c7e0d128b54 100644 (file)
@@ -27,6 +27,7 @@
 #define DVB_PLL_SAMSUNG_TBDU18132      16
 #define DVB_PLL_SAMSUNG_TBMU24112      17
 #define DVB_PLL_TDEE4                 18
+#define DVB_PLL_THOMSON_DTT7520X       19
 
 /**
  * Attach a dvb-pll to the supplied frontend structure.
index 312588e84daeedf855ccc266b8484dbc13706ee0..633815ed90ca7262641185cdd17b2224079a3316 100644 (file)
@@ -481,7 +481,7 @@ static int m88rs2000_read_status(struct dvb_frontend *fe, fe_status_t *status)
 
        if ((reg & 0x7) == 0x7) {
                *status = FE_HAS_CARRIER | FE_HAS_SIGNAL | FE_HAS_VITERBI
-                       | FE_HAS_LOCK;
+                       | FE_HAS_SYNC | FE_HAS_LOCK;
                if (state->config->set_ts_params)
                        state->config->set_ts_params(fe, CALL_IS_READ);
        }
index 49ca78d883b18031ec110a6329be86bf49c9acbe..03af52ec2c5818f8b6e4bed5286389acc75b9984 100644 (file)
@@ -37,6 +37,8 @@
  * /usr/lib/hotplug/firmware/ or /lib/firmware/
  * (depending on configuration of firmware hotplug).
  */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #define NXT2002_DEFAULT_FIRMWARE "dvb-fe-nxt2002.fw"
 #define NXT2004_DEFAULT_FIRMWARE "dvb-fe-nxt2004.fw"
 #define CRC_CCIT_MASK 0x1021
@@ -62,10 +64,7 @@ struct nxt200x_state {
 };
 
 static int debug;
-#define dprintk(args...) \
-       do { \
-               if (debug) printk(KERN_DEBUG "nxt200x: " args); \
-       } while (0)
+#define dprintk(args...)       do { if (debug) pr_debug(args); } while (0)
 
 static int i2c_writebytes (struct nxt200x_state* state, u8 addr, u8 *buf, u8 len)
 {
@@ -73,7 +72,7 @@ static int i2c_writebytes (struct nxt200x_state* state, u8 addr, u8 *buf, u8 len
        struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = len };
 
        if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
-               printk (KERN_WARNING "nxt200x: %s: i2c write error (addr 0x%02x, err == %i)\n",
+               pr_warn("%s: i2c write error (addr 0x%02x, err == %i)\n",
                        __func__, addr, err);
                return -EREMOTEIO;
        }
@@ -86,7 +85,7 @@ static int i2c_readbytes(struct nxt200x_state *state, u8 addr, u8 *buf, u8 len)
        struct i2c_msg msg = { .addr = addr, .flags = I2C_M_RD, .buf = buf, .len = len };
 
        if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
-               printk (KERN_WARNING "nxt200x: %s: i2c read error (addr 0x%02x, err == %i)\n",
+               pr_warn("%s: i2c read error (addr 0x%02x, err == %i)\n",
                        __func__, addr, err);
                return -EREMOTEIO;
        }
@@ -104,7 +103,7 @@ static int nxt200x_writebytes (struct nxt200x_state* state, u8 reg,
        memcpy(&buf2[1], buf, len);
 
        if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
-               printk (KERN_WARNING "nxt200x: %s: i2c write error (addr 0x%02x, err == %i)\n",
+               pr_warn("%s: i2c write error (addr 0x%02x, err == %i)\n",
                        __func__, state->config->demod_address, err);
                return -EREMOTEIO;
        }
@@ -121,7 +120,7 @@ static int nxt200x_readbytes(struct nxt200x_state *state, u8 reg, u8 *buf, u8 le
        int err;
 
        if ((err = i2c_transfer (state->i2c, msg, 2)) != 2) {
-               printk (KERN_WARNING "nxt200x: %s: i2c read error (addr 0x%02x, err == %i)\n",
+               pr_warn("%s: i2c read error (addr 0x%02x, err == %i)\n",
                        __func__, state->config->demod_address, err);
                return -EREMOTEIO;
        }
@@ -199,7 +198,7 @@ static int nxt200x_writereg_multibyte (struct nxt200x_state* state, u8 reg, u8*
                        break;
        }
 
-       printk(KERN_WARNING "nxt200x: Error writing multireg register 0x%02X\n",reg);
+       pr_warn("Error writing multireg register 0x%02X\n", reg);
 
        return 0;
 }
@@ -281,7 +280,8 @@ static void nxt200x_microcontroller_stop (struct nxt200x_state* state)
                counter++;
        }
 
-       printk(KERN_WARNING "nxt200x: Timeout waiting for nxt200x to stop. This is ok after firmware upload.\n");
+       pr_warn("Timeout waiting for nxt200x to stop. This is ok after "
+               "firmware upload.\n");
        return;
 }
 
@@ -320,7 +320,7 @@ static void nxt2004_microcontroller_init (struct nxt200x_state* state)
                counter++;
        }
 
-       printk(KERN_WARNING "nxt200x: Timeout waiting for nxt2004 to init.\n");
+       pr_warn("Timeout waiting for nxt2004 to init.\n");
 
        return;
 }
@@ -338,7 +338,7 @@ static int nxt200x_writetuner (struct nxt200x_state* state, u8* data)
        switch (state->demod_chip) {
                case NXT2004:
                        if (i2c_writebytes(state, data[0], data+1, 4))
-                               printk(KERN_WARNING "nxt200x: error writing to tuner\n");
+                               pr_warn("error writing to tuner\n");
                        /* wait until we have a lock */
                        while (count < 20) {
                                i2c_readbytes(state, data[0], &buf, 1);
@@ -347,7 +347,7 @@ static int nxt200x_writetuner (struct nxt200x_state* state, u8* data)
                                msleep(100);
                                count++;
                        }
-                       printk("nxt2004: timeout waiting for tuner lock\n");
+                       pr_warn("timeout waiting for tuner lock\n");
                        break;
                case NXT2002:
                        /* set the i2c transfer speed to the tuner */
@@ -376,7 +376,7 @@ static int nxt200x_writetuner (struct nxt200x_state* state, u8* data)
                                msleep(100);
                                count++;
                        }
-                       printk("nxt2002: timeout error writing tuner\n");
+                       pr_warn("timeout error writing to tuner\n");
                        break;
                default:
                        return -EINVAL;
@@ -878,22 +878,24 @@ static int nxt2002_init(struct dvb_frontend* fe)
        u8 buf[2];
 
        /* request the firmware, this will block until someone uploads it */
-       printk("nxt2002: Waiting for firmware upload (%s)...\n", NXT2002_DEFAULT_FIRMWARE);
+       pr_debug("%s: Waiting for firmware upload (%s)...\n",
+                __func__, NXT2002_DEFAULT_FIRMWARE);
        ret = request_firmware(&fw, NXT2002_DEFAULT_FIRMWARE,
                               state->i2c->dev.parent);
-       printk("nxt2002: Waiting for firmware upload(2)...\n");
+       pr_debug("%s: Waiting for firmware upload(2)...\n", __func__);
        if (ret) {
-               printk("nxt2002: No firmware uploaded (timeout or file not found?)\n");
+               pr_err("%s: No firmware uploaded (timeout or file not found?)"
+                      "\n", __func__);
                return ret;
        }
 
        ret = nxt2002_load_firmware(fe, fw);
        release_firmware(fw);
        if (ret) {
-               printk("nxt2002: Writing firmware to device failed\n");
+               pr_err("%s: Writing firmware to device failed\n", __func__);
                return ret;
        }
-       printk("nxt2002: Firmware upload complete\n");
+       pr_info("%s: Firmware upload complete\n", __func__);
 
        /* Put the micro into reset */
        nxt200x_microcontroller_stop(state);
@@ -943,22 +945,24 @@ static int nxt2004_init(struct dvb_frontend* fe)
        nxt200x_writebytes(state, 0x1E, buf, 1);
 
        /* request the firmware, this will block until someone uploads it */
-       printk("nxt2004: Waiting for firmware upload (%s)...\n", NXT2004_DEFAULT_FIRMWARE);
+       pr_debug("%s: Waiting for firmware upload (%s)...\n",
+                __func__, NXT2004_DEFAULT_FIRMWARE);
        ret = request_firmware(&fw, NXT2004_DEFAULT_FIRMWARE,
                               state->i2c->dev.parent);
-       printk("nxt2004: Waiting for firmware upload(2)...\n");
+       pr_debug("%s: Waiting for firmware upload(2)...\n", __func__);
        if (ret) {
-               printk("nxt2004: No firmware uploaded (timeout or file not found?)\n");
+               pr_err("%s: No firmware uploaded (timeout or file not found?)"
+                      "\n", __func__);
                return ret;
        }
 
        ret = nxt2004_load_firmware(fe, fw);
        release_firmware(fw);
        if (ret) {
-               printk("nxt2004: Writing firmware to device failed\n");
+               pr_err("%s: Writing firmware to device failed\n", __func__);
                return ret;
        }
-       printk("nxt2004: Firmware upload complete\n");
+       pr_info("%s: Firmware upload complete\n", __func__);
 
        /* ensure transfer is complete */
        buf[0] = 0x01;
@@ -1164,11 +1168,11 @@ struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config,
        switch (buf[0]) {
                case 0x04:
                        state->demod_chip = NXT2002;
-                       printk("nxt200x: NXT2002 Detected\n");
+                       pr_info("NXT2002 Detected\n");
                        break;
                case 0x05:
                        state->demod_chip = NXT2004;
-                       printk("nxt200x: NXT2004 Detected\n");
+                       pr_info("NXT2004 Detected\n");
                        break;
                default:
                        goto error;
index 095cf3a994e2d958620e2cbd5f93eb5b2d7e2cbd..0207d1f064e080ea2739a8c1a47d6d5a95c6dbcd 100644 (file)
@@ -275,7 +275,7 @@ static struct pci_device_id mantis_pci_table[] = {
        MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2033_DVB_C, &vp2033_config),
        MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_2040_DVB_C, &vp2040_config),
        MAKE_ENTRY(TECHNISAT, CABLESTAR_HD2, &vp2040_config),
-       MAKE_ENTRY(TERRATEC, CINERGY_C, &vp2033_config),
+       MAKE_ENTRY(TERRATEC, CINERGY_C, &vp2040_config),
        MAKE_ENTRY(TWINHAN_TECHNOLOGIES, MANTIS_VP_3030_DVB_T, &vp3030_config),
        { }
 };
index 22524a8e6f61ec735773bab8d8a7f610b7319ec1..684d9061fe2aced0c817a6c1191c1226be5aa3d5 100644 (file)
@@ -121,7 +121,7 @@ static void mantis_load_config(struct mantis_pci *mantis)
                mantis->hwconfig = &vp2033_mantis_config;
                break;
        case MANTIS_VP_2040_DVB_C:      /* VP-2040 */
-       case TERRATEC_CINERGY_C_PCI:    /* VP-2040 clone */
+       case CINERGY_C: /* VP-2040 clone */
        case TECHNISAT_CABLESTAR_HD2:
                mantis->hwconfig = &vp2040_mantis_config;
                break;
index e5180e45d3100e72d8b0bb26758beccdca5a4b6d..5d15c6b74d9be621bb5cb8fecfae9ad50512804f 100644 (file)
@@ -248,8 +248,10 @@ int __devinit mantis_dvb_init(struct mantis_pci *mantis)
 err5:
        tasklet_kill(&mantis->tasklet);
        dvb_net_release(&mantis->dvbnet);
-       dvb_unregister_frontend(mantis->fe);
-       dvb_frontend_detach(mantis->fe);
+       if (mantis->fe) {
+               dvb_unregister_frontend(mantis->fe);
+               dvb_frontend_detach(mantis->fe);
+       }
 err4:
        mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem);
 
index 72ee8de0226025618ecd733716fa30f494eb646b..a6cd6959ad192a6207d96add36c69d6691ed3291 100644 (file)
@@ -42,6 +42,8 @@
 #include "mt2131.h"
 #include "tda18271c2dd.h"
 #include "drxk.h"
+#include "drxd.h"
+#include "dvb-pll.h"
 
 
 /****************************************************************************/
@@ -313,6 +315,235 @@ static int demod_attach_lg330x(struct ngene_channel *chan)
        return (chan->fe) ? 0 : -ENODEV;
 }
 
+static int demod_attach_drxd(struct ngene_channel *chan)
+{
+       struct drxd_config *feconf;
+
+       feconf = chan->dev->card_info->fe_config[chan->number];
+
+       chan->fe = dvb_attach(drxd_attach, feconf, chan,
+                       &chan->i2c_adapter, &chan->dev->pci_dev->dev);
+       if (!chan->fe) {
+               pr_err("No DRXD found!\n");
+               return -ENODEV;
+       }
+
+       if (!dvb_attach(dvb_pll_attach, chan->fe, feconf->pll_address,
+                       &chan->i2c_adapter,
+                       feconf->pll_type)) {
+               pr_err("No pll(%d) found!\n", feconf->pll_type);
+               return -ENODEV;
+       }
+       return 0;
+}
+
+/****************************************************************************/
+/* EEPROM TAGS **************************************************************/
+/****************************************************************************/
+
+#define MICNG_EE_START      0x0100
+#define MICNG_EE_END        0x0FF0
+
+#define MICNG_EETAG_END0    0x0000
+#define MICNG_EETAG_END1    0xFFFF
+
+/* 0x0001 - 0x000F reserved for housekeeping */
+/* 0xFFFF - 0xFFFE reserved for housekeeping */
+
+/* Micronas assigned tags
+   EEProm tags for hardware support */
+
+#define MICNG_EETAG_DRXD1_OSCDEVIATION  0x1000  /* 2 Bytes data */
+#define MICNG_EETAG_DRXD2_OSCDEVIATION  0x1001  /* 2 Bytes data */
+
+#define MICNG_EETAG_MT2060_1_1STIF      0x1100  /* 2 Bytes data */
+#define MICNG_EETAG_MT2060_2_1STIF      0x1101  /* 2 Bytes data */
+
+/* Tag range for OEMs */
+
+#define MICNG_EETAG_OEM_FIRST  0xC000
+#define MICNG_EETAG_OEM_LAST   0xFFEF
+
+static int i2c_write_eeprom(struct i2c_adapter *adapter,
+                           u8 adr, u16 reg, u8 data)
+{
+       u8 m[3] = {(reg >> 8), (reg & 0xff), data};
+       struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = m,
+                             .len = sizeof(m)};
+
+       if (i2c_transfer(adapter, &msg, 1) != 1) {
+               pr_err(DEVICE_NAME ": Error writing EEPROM!\n");
+               return -EIO;
+       }
+       return 0;
+}
+
+static int i2c_read_eeprom(struct i2c_adapter *adapter,
+                          u8 adr, u16 reg, u8 *data, int len)
+{
+       u8 msg[2] = {(reg >> 8), (reg & 0xff)};
+       struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
+                                  .buf = msg, .len = 2 },
+                                 {.addr = adr, .flags = I2C_M_RD,
+                                  .buf = data, .len = len} };
+
+       if (i2c_transfer(adapter, msgs, 2) != 2) {
+               pr_err(DEVICE_NAME ": Error reading EEPROM\n");
+               return -EIO;
+       }
+       return 0;
+}
+
+static int ReadEEProm(struct i2c_adapter *adapter,
+                     u16 Tag, u32 MaxLen, u8 *data, u32 *pLength)
+{
+       int status = 0;
+       u16 Addr = MICNG_EE_START, Length, tag = 0;
+       u8  EETag[3];
+
+       while (Addr + sizeof(u16) + 1 < MICNG_EE_END) {
+               if (i2c_read_eeprom(adapter, 0x50, Addr, EETag, sizeof(EETag)))
+                       return -1;
+               tag = (EETag[0] << 8) | EETag[1];
+               if (tag == MICNG_EETAG_END0 || tag == MICNG_EETAG_END1)
+                       return -1;
+               if (tag == Tag)
+                       break;
+               Addr += sizeof(u16) + 1 + EETag[2];
+       }
+       if (Addr + sizeof(u16) + 1 + EETag[2] > MICNG_EE_END) {
+               pr_err(DEVICE_NAME
+                      ": Reached EOEE @ Tag = %04x Length = %3d\n",
+                      tag, EETag[2]);
+               return -1;
+       }
+       Length = EETag[2];
+       if (Length > MaxLen)
+               Length = (u16) MaxLen;
+       if (Length > 0) {
+               Addr += sizeof(u16) + 1;
+               status = i2c_read_eeprom(adapter, 0x50, Addr, data, Length);
+               if (!status) {
+                       *pLength = EETag[2];
+                       if (Length < EETag[2])
+                               ; /*status=STATUS_BUFFER_OVERFLOW; */
+               }
+       }
+       return status;
+}
+
+static int WriteEEProm(struct i2c_adapter *adapter,
+                      u16 Tag, u32 Length, u8 *data)
+{
+       int status = 0;
+       u16 Addr = MICNG_EE_START;
+       u8 EETag[3];
+       u16 tag = 0;
+       int retry, i;
+
+       while (Addr + sizeof(u16) + 1 < MICNG_EE_END) {
+               if (i2c_read_eeprom(adapter, 0x50, Addr, EETag, sizeof(EETag)))
+                       return -1;
+               tag = (EETag[0] << 8) | EETag[1];
+               if (tag == MICNG_EETAG_END0 || tag == MICNG_EETAG_END1)
+                       return -1;
+               if (tag == Tag)
+                       break;
+               Addr += sizeof(u16) + 1 + EETag[2];
+       }
+       if (Addr + sizeof(u16) + 1 + EETag[2] > MICNG_EE_END) {
+               pr_err(DEVICE_NAME
+                      ": Reached EOEE @ Tag = %04x Length = %3d\n",
+                      tag, EETag[2]);
+               return -1;
+       }
+
+       if (Length > EETag[2])
+               return -EINVAL;
+       /* Note: We write the data one byte at a time to avoid
+          issues with page sizes. (which are different for
+          each manufacture and eeprom size)
+        */
+       Addr += sizeof(u16) + 1;
+       for (i = 0; i < Length; i++, Addr++) {
+               status = i2c_write_eeprom(adapter, 0x50, Addr, data[i]);
+
+               if (status)
+                       break;
+
+               /* Poll for finishing write cycle */
+               retry = 10;
+               while (retry) {
+                       u8 Tmp;
+
+                       msleep(50);
+                       status = i2c_read_eeprom(adapter, 0x50, Addr, &Tmp, 1);
+                       if (status)
+                               break;
+                       if (Tmp != data[i])
+                               pr_err(DEVICE_NAME
+                                      "eeprom write error\n");
+                       retry -= 1;
+               }
+               if (status) {
+                       pr_err(DEVICE_NAME
+                              ": Timeout polling eeprom\n");
+                       break;
+               }
+       }
+       return status;
+}
+
+static int eeprom_read_ushort(struct i2c_adapter *adapter, u16 tag, u16 *data)
+{
+       int stat;
+       u8 buf[2];
+       u32 len = 0;
+
+       stat = ReadEEProm(adapter, tag, 2, buf, &len);
+       if (stat)
+               return stat;
+       if (len != 2)
+               return -EINVAL;
+
+       *data = (buf[0] << 8) | buf[1];
+       return 0;
+}
+
+static int eeprom_write_ushort(struct i2c_adapter *adapter, u16 tag, u16 data)
+{
+       int stat;
+       u8 buf[2];
+
+       buf[0] = data >> 8;
+       buf[1] = data & 0xff;
+       stat = WriteEEProm(adapter, tag, 2, buf);
+       if (stat)
+               return stat;
+       return 0;
+}
+
+static s16 osc_deviation(void *priv, s16 deviation, int flag)
+{
+       struct ngene_channel *chan = priv;
+       struct i2c_adapter *adap = &chan->i2c_adapter;
+       u16 data = 0;
+
+       if (flag) {
+               data = (u16) deviation;
+               pr_info(DEVICE_NAME ": write deviation %d\n",
+                      deviation);
+               eeprom_write_ushort(adap, 0x1000 + chan->number, data);
+       } else {
+               if (eeprom_read_ushort(adap, 0x1000 + chan->number, &data))
+                       data = 0;
+               pr_info(DEVICE_NAME ": read deviation %d\n",
+                      (s16) data);
+       }
+
+       return (s16) data;
+}
+
 /****************************************************************************/
 /* Switch control (I2C gates, etc.) *****************************************/
 /****************************************************************************/
@@ -464,6 +695,37 @@ static struct ngene_info ngene_info_m780 = {
        .fw_version     = 15,
 };
 
+static struct drxd_config fe_terratec_dvbt_0 = {
+       .index          = 0,
+       .demod_address  = 0x70,
+       .demod_revision = 0xa2,
+       .demoda_address = 0x00,
+       .pll_address    = 0x60,
+       .pll_type       = DVB_PLL_THOMSON_DTT7520X,
+       .clock          = 20000,
+       .osc_deviation  = osc_deviation,
+};
+
+static struct drxd_config fe_terratec_dvbt_1 = {
+       .index          = 1,
+       .demod_address  = 0x71,
+       .demod_revision = 0xa2,
+       .demoda_address = 0x00,
+       .pll_address    = 0x60,
+       .pll_type       = DVB_PLL_THOMSON_DTT7520X,
+       .clock          = 20000,
+       .osc_deviation  = osc_deviation,
+};
+
+static struct ngene_info ngene_info_terratec = {
+       .type           = NGENE_TERRATEC,
+       .name           = "Terratec Integra/Cinergy2400i Dual DVB-T",
+       .io_type        = {NGENE_IO_TSIN, NGENE_IO_TSIN},
+       .demod_attach   = {demod_attach_drxd, demod_attach_drxd},
+       .fe_config      = {&fe_terratec_dvbt_0, &fe_terratec_dvbt_1},
+       .i2c_access     = 1,
+};
+
 /****************************************************************************/
 
 
@@ -488,6 +750,7 @@ static const struct pci_device_id ngene_id_tbl[] __devinitdata = {
        NGENE_ID(0x18c3, 0xdd10, ngene_info_duoFlex),
        NGENE_ID(0x18c3, 0xdd20, ngene_info_duoFlex),
        NGENE_ID(0x1461, 0x062e, ngene_info_m780),
+       NGENE_ID(0x153b, 0x1167, ngene_info_terratec),
        {0}
 };
 MODULE_DEVICE_TABLE(pci, ngene_id_tbl);
index b21bcce667088a2d0f09cf66cab7d9985a72427b..7e6e43ae5c5151a3b5a8411e884594552c0f64c4 100644 (file)
@@ -50,6 +50,8 @@
 #include "stv6110x.h"
 #include "stv090x.h"
 #include "isl6423.h"
+#include "lnbh24.h"
+
 
 static int diseqc_method;
 module_param(diseqc_method, int, 0444);
@@ -679,6 +681,62 @@ static void frontend_init(struct budget *budget)
                        }
                }
                break;
+
+       case 0x1020: { /* Omicom S2 */
+                       struct stv6110x_devctl *ctl;
+                       saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO);
+                       msleep(50);
+                       saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI);
+                       msleep(250);
+
+                       budget->dvb_frontend = dvb_attach(stv090x_attach,
+                                                         &tt1600_stv090x_config,
+                                                         &budget->i2c_adap,
+                                                         STV090x_DEMODULATOR_0);
+
+                       if (budget->dvb_frontend) {
+                               printk(KERN_INFO "budget: Omicom S2 detected\n");
+
+                               ctl = dvb_attach(stv6110x_attach,
+                                                budget->dvb_frontend,
+                                                &tt1600_stv6110x_config,
+                                                &budget->i2c_adap);
+
+                               if (ctl) {
+                                       tt1600_stv090x_config.tuner_init          = ctl->tuner_init;
+                                       tt1600_stv090x_config.tuner_sleep         = ctl->tuner_sleep;
+                                       tt1600_stv090x_config.tuner_set_mode      = ctl->tuner_set_mode;
+                                       tt1600_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency;
+                                       tt1600_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency;
+                                       tt1600_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth;
+                                       tt1600_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth;
+                                       tt1600_stv090x_config.tuner_set_bbgain    = ctl->tuner_set_bbgain;
+                                       tt1600_stv090x_config.tuner_get_bbgain    = ctl->tuner_get_bbgain;
+                                       tt1600_stv090x_config.tuner_set_refclk    = ctl->tuner_set_refclk;
+                                       tt1600_stv090x_config.tuner_get_status    = ctl->tuner_get_status;
+
+                                       /* call the init function once to initialize
+                                          tuner's clock output divider and demod's
+                                          master clock */
+                                       if (budget->dvb_frontend->ops.init)
+                                               budget->dvb_frontend->ops.init(budget->dvb_frontend);
+
+                                       if (dvb_attach(lnbh24_attach,
+                                                       budget->dvb_frontend,
+                                                       &budget->i2c_adap,
+                                                       LNBH24_PCL | LNBH24_TTX,
+                                                       LNBH24_TEN, 0x14>>1) == NULL) {
+                                               printk(KERN_ERR
+                                               "No LNBH24 found!\n");
+                                               goto error_out;
+                                       }
+                               } else {
+                                       printk(KERN_ERR "%s: No STV6110(A) Silicon Tuner found!\n", __func__);
+                                       goto error_out;
+                               }
+                       }
+               }
+               break;
        }
 
        if (budget->dvb_frontend == NULL) {
@@ -759,6 +817,7 @@ MAKE_BUDGET_INFO(fsacs0, "Fujitsu Siemens Activy Budget-S PCI (rev GR/grundig fr
 MAKE_BUDGET_INFO(fsacs1, "Fujitsu Siemens Activy Budget-S PCI (rev AL/alps frontend)", BUDGET_FS_ACTIVY);
 MAKE_BUDGET_INFO(fsact,         "Fujitsu Siemens Activy Budget-T PCI (rev GR/Grundig frontend)", BUDGET_FS_ACTIVY);
 MAKE_BUDGET_INFO(fsact1, "Fujitsu Siemens Activy Budget-T PCI (rev AL/ALPS TDHD1-204A)", BUDGET_FS_ACTIVY);
+MAKE_BUDGET_INFO(omicom, "Omicom S2 PCI", BUDGET_TT);
 
 static struct pci_device_id pci_tbl[] = {
        MAKE_EXTENSION_PCI(ttbs,  0x13c2, 0x1003),
@@ -772,6 +831,7 @@ static struct pci_device_id pci_tbl[] = {
        MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61),
        MAKE_EXTENSION_PCI(fsact1, 0x1131, 0x5f60),
        MAKE_EXTENSION_PCI(fsact, 0x1131, 0x5f61),
+       MAKE_EXTENSION_PCI(omicom, 0x14c4, 0x1020),
        {
                .vendor    = 0,
        }
index 6f9eb94e85b387f78f144fd74c244e0e0859237a..d01fcb7e87c2558e1b2c48c504d7dda0efada8df 100644 (file)
@@ -59,7 +59,9 @@ static int media_device_get_info(struct media_device *dev,
        info.hw_revision = dev->hw_revision;
        info.driver_version = dev->driver_version;
 
-       return copy_to_user(__info, &info, sizeof(*__info));
+       if (copy_to_user(__info, &info, sizeof(*__info)))
+               return -EFAULT;
+       return 0;
 }
 
 static struct media_entity *find_entity(struct media_device *mdev, u32 id)
index d0b6bb507634a5756e7c5d6335a42f8da2b0d90f..72ded29728bbb2cbf459184095be31cf45a81270 100644 (file)
 #include <media/v4l2-device.h>
 #include <sound/tea575x-tuner.h>
 
+#if defined(CONFIG_LEDS_CLASS) || \
+    (defined(CONFIG_LEDS_CLASS_MODULE) && defined(CONFIG_RADIO_SHARK_MODULE))
+#define SHARK_USE_LEDS 1
+#endif
+
 /*
  * Version Information
  */
@@ -56,44 +61,18 @@ MODULE_LICENSE("GPL");
 
 enum { BLUE_LED, BLUE_PULSE_LED, RED_LED, NO_LEDS };
 
-static void shark_led_set_blue(struct led_classdev *led_cdev,
-                              enum led_brightness value);
-static void shark_led_set_blue_pulse(struct led_classdev *led_cdev,
-                                    enum led_brightness value);
-static void shark_led_set_red(struct led_classdev *led_cdev,
-                             enum led_brightness value);
-
-static const struct led_classdev shark_led_templates[NO_LEDS] = {
-       [BLUE_LED] = {
-               .name           = "%s:blue:",
-               .brightness     = LED_OFF,
-               .max_brightness = 127,
-               .brightness_set = shark_led_set_blue,
-       },
-       [BLUE_PULSE_LED] = {
-               .name           = "%s:blue-pulse:",
-               .brightness     = LED_OFF,
-               .max_brightness = 255,
-               .brightness_set = shark_led_set_blue_pulse,
-       },
-       [RED_LED] = {
-               .name           = "%s:red:",
-               .brightness     = LED_OFF,
-               .max_brightness = 1,
-               .brightness_set = shark_led_set_red,
-       },
-};
-
 struct shark_device {
        struct usb_device *usbdev;
        struct v4l2_device v4l2_dev;
        struct snd_tea575x tea;
 
+#ifdef SHARK_USE_LEDS
        struct work_struct led_work;
        struct led_classdev leds[NO_LEDS];
        char led_names[NO_LEDS][32];
        atomic_t brightness[NO_LEDS];
        unsigned long brightness_new;
+#endif
 
        u8 *transfer_buffer;
        u32 last_val;
@@ -175,20 +154,13 @@ static struct snd_tea575x_ops shark_tea_ops = {
        .read_val  = shark_read_val,
 };
 
+#ifdef SHARK_USE_LEDS
 static void shark_led_work(struct work_struct *work)
 {
        struct shark_device *shark =
                container_of(work, struct shark_device, led_work);
        int i, res, brightness, actual_len;
 
-       /*
-        * We use the v4l2_dev lock and registered bit to ensure the device
-        * does not get unplugged and unreffed while we're running.
-        */
-       mutex_lock(&shark->tea.mutex);
-       if (!video_is_registered(&shark->tea.vd))
-               goto leave;
-
        for (i = 0; i < 3; i++) {
                if (!test_and_clear_bit(i, &shark->brightness_new))
                        continue;
@@ -208,8 +180,6 @@ static void shark_led_work(struct work_struct *work)
                        v4l2_err(&shark->v4l2_dev, "set LED %s error: %d\n",
                                 shark->led_names[i], res);
        }
-leave:
-       mutex_unlock(&shark->tea.mutex);
 }
 
 static void shark_led_set_blue(struct led_classdev *led_cdev,
@@ -245,19 +215,78 @@ static void shark_led_set_red(struct led_classdev *led_cdev,
        schedule_work(&shark->led_work);
 }
 
+static const struct led_classdev shark_led_templates[NO_LEDS] = {
+       [BLUE_LED] = {
+               .name           = "%s:blue:",
+               .brightness     = LED_OFF,
+               .max_brightness = 127,
+               .brightness_set = shark_led_set_blue,
+       },
+       [BLUE_PULSE_LED] = {
+               .name           = "%s:blue-pulse:",
+               .brightness     = LED_OFF,
+               .max_brightness = 255,
+               .brightness_set = shark_led_set_blue_pulse,
+       },
+       [RED_LED] = {
+               .name           = "%s:red:",
+               .brightness     = LED_OFF,
+               .max_brightness = 1,
+               .brightness_set = shark_led_set_red,
+       },
+};
+
+static int shark_register_leds(struct shark_device *shark, struct device *dev)
+{
+       int i, retval;
+
+       INIT_WORK(&shark->led_work, shark_led_work);
+       for (i = 0; i < NO_LEDS; i++) {
+               shark->leds[i] = shark_led_templates[i];
+               snprintf(shark->led_names[i], sizeof(shark->led_names[0]),
+                        shark->leds[i].name, shark->v4l2_dev.name);
+               shark->leds[i].name = shark->led_names[i];
+               retval = led_classdev_register(dev, &shark->leds[i]);
+               if (retval) {
+                       v4l2_err(&shark->v4l2_dev,
+                                "couldn't register led: %s\n",
+                                shark->led_names[i]);
+                       return retval;
+               }
+       }
+       return 0;
+}
+
+static void shark_unregister_leds(struct shark_device *shark)
+{
+       int i;
+
+       for (i = 0; i < NO_LEDS; i++)
+               led_classdev_unregister(&shark->leds[i]);
+
+       cancel_work_sync(&shark->led_work);
+}
+#else
+static int shark_register_leds(struct shark_device *shark, struct device *dev)
+{
+       v4l2_warn(&shark->v4l2_dev,
+                 "CONFIG_LED_CLASS not enabled, LED support disabled\n");
+       return 0;
+}
+static inline void shark_unregister_leds(struct shark_device *shark) { }
+#endif
+
 static void usb_shark_disconnect(struct usb_interface *intf)
 {
        struct v4l2_device *v4l2_dev = usb_get_intfdata(intf);
        struct shark_device *shark = v4l2_dev_to_shark(v4l2_dev);
-       int i;
 
        mutex_lock(&shark->tea.mutex);
        v4l2_device_disconnect(&shark->v4l2_dev);
        snd_tea575x_exit(&shark->tea);
        mutex_unlock(&shark->tea.mutex);
 
-       for (i = 0; i < NO_LEDS; i++)
-               led_classdev_unregister(&shark->leds[i]);
+       shark_unregister_leds(shark);
 
        v4l2_device_put(&shark->v4l2_dev);
 }
@@ -266,7 +295,6 @@ static void usb_shark_release(struct v4l2_device *v4l2_dev)
 {
        struct shark_device *shark = v4l2_dev_to_shark(v4l2_dev);
 
-       cancel_work_sync(&shark->led_work);
        v4l2_device_unregister(&shark->v4l2_dev);
        kfree(shark->transfer_buffer);
        kfree(shark);
@@ -276,7 +304,7 @@ static int usb_shark_probe(struct usb_interface *intf,
                           const struct usb_device_id *id)
 {
        struct shark_device *shark;
-       int i, retval = -ENOMEM;
+       int retval = -ENOMEM;
 
        shark = kzalloc(sizeof(struct shark_device), GFP_KERNEL);
        if (!shark)
@@ -286,17 +314,13 @@ static int usb_shark_probe(struct usb_interface *intf,
        if (!shark->transfer_buffer)
                goto err_alloc_buffer;
 
-       /*
-        * Work around a bug in usbhid/hid-core.c, where it leaves a dangling
-        * pointer in intfdata causing v4l2-device.c to not set it. Which
-        * results in usb_shark_disconnect() referencing the dangling pointer
-        *
-        * REMOVE (as soon as the above bug is fixed, patch submitted)
-        */
-       usb_set_intfdata(intf, NULL);
+       v4l2_device_set_name(&shark->v4l2_dev, DRV_NAME, &shark_instance);
+
+       retval = shark_register_leds(shark, &intf->dev);
+       if (retval)
+               goto err_reg_leds;
 
        shark->v4l2_dev.release = usb_shark_release;
-       v4l2_device_set_name(&shark->v4l2_dev, DRV_NAME, &shark_instance);
        retval = v4l2_device_register(&intf->dev, &shark->v4l2_dev);
        if (retval) {
                v4l2_err(&shark->v4l2_dev, "couldn't register v4l2_device\n");
@@ -320,32 +344,13 @@ static int usb_shark_probe(struct usb_interface *intf,
                goto err_init_tea;
        }
 
-       INIT_WORK(&shark->led_work, shark_led_work);
-       for (i = 0; i < NO_LEDS; i++) {
-               shark->leds[i] = shark_led_templates[i];
-               snprintf(shark->led_names[i], sizeof(shark->led_names[0]),
-                        shark->leds[i].name, shark->v4l2_dev.name);
-               shark->leds[i].name = shark->led_names[i];
-               /*
-                * We don't fail the probe if we fail to register the leds,
-                * because once we've called snd_tea575x_init, the /dev/radio0
-                * node may be opened from userspace holding a reference to us!
-                *
-                * Note we cannot register the leds first instead as
-                * shark_led_work depends on the v4l2 mutex and registered bit.
-                */
-               retval = led_classdev_register(&intf->dev, &shark->leds[i]);
-               if (retval)
-                       v4l2_err(&shark->v4l2_dev,
-                                "couldn't register led: %s\n",
-                                shark->led_names[i]);
-       }
-
        return 0;
 
 err_init_tea:
        v4l2_device_unregister(&shark->v4l2_dev);
 err_reg_dev:
+       shark_unregister_leds(shark);
+err_reg_leds:
        kfree(shark->transfer_buffer);
 err_alloc_buffer:
        kfree(shark);
index b9575de3e7e8306d5f9cdf6fa6efbd2b74c0984d..7b4efdfaae283748edea0dc359ae647667add6b6 100644 (file)
 #include <media/v4l2-device.h>
 #include "radio-tea5777.h"
 
+#if defined(CONFIG_LEDS_CLASS) || \
+    (defined(CONFIG_LEDS_CLASS_MODULE) && defined(CONFIG_RADIO_SHARK2_MODULE))
+#define SHARK_USE_LEDS 1
+#endif
+
 MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
 MODULE_DESCRIPTION("Griffin radioSHARK2, USB radio receiver driver");
 MODULE_LICENSE("GPL");
@@ -43,7 +48,6 @@ static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
-
 #define SHARK_IN_EP            0x83
 #define SHARK_OUT_EP           0x05
 
@@ -54,36 +58,18 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
 enum { BLUE_LED, RED_LED, NO_LEDS };
 
-static void shark_led_set_blue(struct led_classdev *led_cdev,
-                              enum led_brightness value);
-static void shark_led_set_red(struct led_classdev *led_cdev,
-                             enum led_brightness value);
-
-static const struct led_classdev shark_led_templates[NO_LEDS] = {
-       [BLUE_LED] = {
-               .name           = "%s:blue:",
-               .brightness     = LED_OFF,
-               .max_brightness = 127,
-               .brightness_set = shark_led_set_blue,
-       },
-       [RED_LED] = {
-               .name           = "%s:red:",
-               .brightness     = LED_OFF,
-               .max_brightness = 1,
-               .brightness_set = shark_led_set_red,
-       },
-};
-
 struct shark_device {
        struct usb_device *usbdev;
        struct v4l2_device v4l2_dev;
        struct radio_tea5777 tea;
 
+#ifdef SHARK_USE_LEDS
        struct work_struct led_work;
        struct led_classdev leds[NO_LEDS];
        char led_names[NO_LEDS][32];
        atomic_t brightness[NO_LEDS];
        unsigned long brightness_new;
+#endif
 
        u8 *transfer_buffer;
 };
@@ -161,18 +147,12 @@ static struct radio_tea5777_ops shark_tea_ops = {
        .read_reg  = shark_read_reg,
 };
 
+#ifdef SHARK_USE_LEDS
 static void shark_led_work(struct work_struct *work)
 {
        struct shark_device *shark =
                container_of(work, struct shark_device, led_work);
        int i, res, brightness, actual_len;
-       /*
-        * We use the v4l2_dev lock and registered bit to ensure the device
-        * does not get unplugged and unreffed while we're running.
-        */
-       mutex_lock(&shark->tea.mutex);
-       if (!video_is_registered(&shark->tea.vd))
-               goto leave;
 
        for (i = 0; i < 2; i++) {
                if (!test_and_clear_bit(i, &shark->brightness_new))
@@ -191,8 +171,6 @@ static void shark_led_work(struct work_struct *work)
                        v4l2_err(&shark->v4l2_dev, "set LED %s error: %d\n",
                                 shark->led_names[i], res);
        }
-leave:
-       mutex_unlock(&shark->tea.mutex);
 }
 
 static void shark_led_set_blue(struct led_classdev *led_cdev,
@@ -217,19 +195,72 @@ static void shark_led_set_red(struct led_classdev *led_cdev,
        schedule_work(&shark->led_work);
 }
 
+static const struct led_classdev shark_led_templates[NO_LEDS] = {
+       [BLUE_LED] = {
+               .name           = "%s:blue:",
+               .brightness     = LED_OFF,
+               .max_brightness = 127,
+               .brightness_set = shark_led_set_blue,
+       },
+       [RED_LED] = {
+               .name           = "%s:red:",
+               .brightness     = LED_OFF,
+               .max_brightness = 1,
+               .brightness_set = shark_led_set_red,
+       },
+};
+
+static int shark_register_leds(struct shark_device *shark, struct device *dev)
+{
+       int i, retval;
+
+       INIT_WORK(&shark->led_work, shark_led_work);
+       for (i = 0; i < NO_LEDS; i++) {
+               shark->leds[i] = shark_led_templates[i];
+               snprintf(shark->led_names[i], sizeof(shark->led_names[0]),
+                        shark->leds[i].name, shark->v4l2_dev.name);
+               shark->leds[i].name = shark->led_names[i];
+               retval = led_classdev_register(dev, &shark->leds[i]);
+               if (retval) {
+                       v4l2_err(&shark->v4l2_dev,
+                                "couldn't register led: %s\n",
+                                shark->led_names[i]);
+                       return retval;
+               }
+       }
+       return 0;
+}
+
+static void shark_unregister_leds(struct shark_device *shark)
+{
+       int i;
+
+       for (i = 0; i < NO_LEDS; i++)
+               led_classdev_unregister(&shark->leds[i]);
+
+       cancel_work_sync(&shark->led_work);
+}
+#else
+static int shark_register_leds(struct shark_device *shark, struct device *dev)
+{
+       v4l2_warn(&shark->v4l2_dev,
+                 "CONFIG_LED_CLASS not enabled, LED support disabled\n");
+       return 0;
+}
+static inline void shark_unregister_leds(struct shark_device *shark) { }
+#endif
+
 static void usb_shark_disconnect(struct usb_interface *intf)
 {
        struct v4l2_device *v4l2_dev = usb_get_intfdata(intf);
        struct shark_device *shark = v4l2_dev_to_shark(v4l2_dev);
-       int i;
 
        mutex_lock(&shark->tea.mutex);
        v4l2_device_disconnect(&shark->v4l2_dev);
        radio_tea5777_exit(&shark->tea);
        mutex_unlock(&shark->tea.mutex);
 
-       for (i = 0; i < NO_LEDS; i++)
-               led_classdev_unregister(&shark->leds[i]);
+       shark_unregister_leds(shark);
 
        v4l2_device_put(&shark->v4l2_dev);
 }
@@ -238,7 +269,6 @@ static void usb_shark_release(struct v4l2_device *v4l2_dev)
 {
        struct shark_device *shark = v4l2_dev_to_shark(v4l2_dev);
 
-       cancel_work_sync(&shark->led_work);
        v4l2_device_unregister(&shark->v4l2_dev);
        kfree(shark->transfer_buffer);
        kfree(shark);
@@ -248,7 +278,7 @@ static int usb_shark_probe(struct usb_interface *intf,
                           const struct usb_device_id *id)
 {
        struct shark_device *shark;
-       int i, retval = -ENOMEM;
+       int retval = -ENOMEM;
 
        shark = kzalloc(sizeof(struct shark_device), GFP_KERNEL);
        if (!shark)
@@ -258,17 +288,13 @@ static int usb_shark_probe(struct usb_interface *intf,
        if (!shark->transfer_buffer)
                goto err_alloc_buffer;
 
-       /*
-        * Work around a bug in usbhid/hid-core.c, where it leaves a dangling
-        * pointer in intfdata causing v4l2-device.c to not set it. Which
-        * results in usb_shark_disconnect() referencing the dangling pointer
-        *
-        * REMOVE (as soon as the above bug is fixed, patch submitted)
-        */
-       usb_set_intfdata(intf, NULL);
+       v4l2_device_set_name(&shark->v4l2_dev, DRV_NAME, &shark_instance);
+
+       retval = shark_register_leds(shark, &intf->dev);
+       if (retval)
+               goto err_reg_leds;
 
        shark->v4l2_dev.release = usb_shark_release;
-       v4l2_device_set_name(&shark->v4l2_dev, DRV_NAME, &shark_instance);
        retval = v4l2_device_register(&intf->dev, &shark->v4l2_dev);
        if (retval) {
                v4l2_err(&shark->v4l2_dev, "couldn't register v4l2_device\n");
@@ -292,32 +318,13 @@ static int usb_shark_probe(struct usb_interface *intf,
                goto err_init_tea;
        }
 
-       INIT_WORK(&shark->led_work, shark_led_work);
-       for (i = 0; i < NO_LEDS; i++) {
-               shark->leds[i] = shark_led_templates[i];
-               snprintf(shark->led_names[i], sizeof(shark->led_names[0]),
-                        shark->leds[i].name, shark->v4l2_dev.name);
-               shark->leds[i].name = shark->led_names[i];
-               /*
-                * We don't fail the probe if we fail to register the leds,
-                * because once we've called radio_tea5777_init, the /dev/radio0
-                * node may be opened from userspace holding a reference to us!
-                *
-                * Note we cannot register the leds first instead as
-                * shark_led_work depends on the v4l2 mutex and registered bit.
-                */
-               retval = led_classdev_register(&intf->dev, &shark->leds[i]);
-               if (retval)
-                       v4l2_err(&shark->v4l2_dev,
-                                "couldn't register led: %s\n",
-                                shark->led_names[i]);
-       }
-
        return 0;
 
 err_init_tea:
        v4l2_device_unregister(&shark->v4l2_dev);
 err_reg_dev:
+       shark_unregister_leds(shark);
+err_reg_leds:
        kfree(shark->transfer_buffer);
 err_alloc_buffer:
        kfree(shark);
index 9e38132afec66488299ebd4227a94e9a2e5d3a11..9bb65e170d99bd87455107083379931c6bda40a6 100644 (file)
@@ -151,6 +151,7 @@ static const struct v4l2_frequency_band bands[] = {
                .index = 0,
                .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
                            V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO |
+                           V4L2_TUNER_CAP_FREQ_BANDS |
                            V4L2_TUNER_CAP_HWSEEK_BOUNDED |
                            V4L2_TUNER_CAP_HWSEEK_WRAP,
                .rangelow   =  87500 * 16,
@@ -162,6 +163,7 @@ static const struct v4l2_frequency_band bands[] = {
                .index = 1,
                .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
                            V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO |
+                           V4L2_TUNER_CAP_FREQ_BANDS |
                            V4L2_TUNER_CAP_HWSEEK_BOUNDED |
                            V4L2_TUNER_CAP_HWSEEK_WRAP,
                .rangelow   =  76000 * 16,
@@ -173,6 +175,7 @@ static const struct v4l2_frequency_band bands[] = {
                .index = 2,
                .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
                            V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO |
+                           V4L2_TUNER_CAP_FREQ_BANDS |
                            V4L2_TUNER_CAP_HWSEEK_BOUNDED |
                            V4L2_TUNER_CAP_HWSEEK_WRAP,
                .rangelow   =  76000 * 16,
index 643a6ff7c5d0e629e70112c0c4e67fe0459c580b..f867f04cccc99626bb7fc5dee97d34f2adaed9fa 100644 (file)
@@ -225,8 +225,9 @@ int si470x_vidioc_querycap(struct file *file, void *priv,
 {
        strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver));
        strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
-       capability->capabilities = V4L2_CAP_HW_FREQ_SEEK |
-               V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+       capability->device_caps = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_READWRITE |
+               V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE;
+       capability->capabilities = capability->device_caps | V4L2_CAP_DEVICE_CAPS;
 
        return 0;
 }
index 146be4263ea17d92ab072d13ae4d12fa610b9276..be076f7181e728b1ab177ca340290a2c1ae29dc4 100644 (file)
@@ -531,7 +531,7 @@ int si470x_vidioc_querycap(struct file *file, void *priv,
        strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card));
        usb_make_path(radio->usbdev, capability->bus_info,
                        sizeof(capability->bus_info));
-       capability->device_caps = V4L2_CAP_HW_FREQ_SEEK |
+       capability->device_caps = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_READWRITE |
                V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE;
        capability->capabilities = capability->device_caps | V4L2_CAP_DEVICE_CAPS;
        return 0;
index 49a11ec1f44967fe99bce27b3a602ed320e41170..db2248ee9498b54940dce319c378e29f6a42071b 100644 (file)
@@ -56,23 +56,29 @@ static ssize_t fm_v4l2_fops_read(struct file *file, char __user * buf,
                return -EIO;
        }
 
-       /* Turn on RDS mode , if it is disabled */
+       if (mutex_lock_interruptible(&fmdev->mutex))
+               return -ERESTARTSYS;
+
+       /* Turn on RDS mode if it is disabled */
        ret = fm_rx_get_rds_mode(fmdev, &rds_mode);
        if (ret < 0) {
                fmerr("Unable to read current rds mode\n");
-               return ret;
+               goto read_unlock;
        }
 
        if (rds_mode == FM_RDS_DISABLE) {
                ret = fmc_set_rds_mode(fmdev, FM_RDS_ENABLE);
                if (ret < 0) {
                        fmerr("Failed to enable rds mode\n");
-                       return ret;
+                       goto read_unlock;
                }
        }
 
        /* Copy RDS data from internal buffer to user buffer */
-       return fmc_transfer_rds_from_internal_buff(fmdev, file, buf, count);
+       ret = fmc_transfer_rds_from_internal_buff(fmdev, file, buf, count);
+read_unlock:
+       mutex_unlock(&fmdev->mutex);
+       return ret;
 }
 
 /* Write TX RDS data */
@@ -91,8 +97,11 @@ static ssize_t fm_v4l2_fops_write(struct file *file, const char __user * buf,
                return -EFAULT;
 
        fmdev = video_drvdata(file);
+       if (mutex_lock_interruptible(&fmdev->mutex))
+               return -ERESTARTSYS;
        fm_tx_set_radio_text(fmdev, rds.text, rds.text_type);
        fm_tx_set_af(fmdev, rds.af_freq);
+       mutex_unlock(&fmdev->mutex);
 
        return sizeof(rds);
 }
@@ -103,7 +112,9 @@ static u32 fm_v4l2_fops_poll(struct file *file, struct poll_table_struct *pts)
        struct fmdev *fmdev;
 
        fmdev = video_drvdata(file);
+       mutex_lock(&fmdev->mutex);
        ret = fmc_is_rds_data_available(fmdev, file, pts);
+       mutex_unlock(&fmdev->mutex);
        if (ret < 0)
                return POLLIN | POLLRDNORM;
 
@@ -127,10 +138,12 @@ static int fm_v4l2_fops_open(struct file *file)
 
        fmdev = video_drvdata(file);
 
+       if (mutex_lock_interruptible(&fmdev->mutex))
+               return -ERESTARTSYS;
        ret = fmc_prepare(fmdev);
        if (ret < 0) {
                fmerr("Unable to prepare FM CORE\n");
-               return ret;
+               goto open_unlock;
        }
 
        fmdbg("Load FM RX firmware..\n");
@@ -138,10 +151,12 @@ static int fm_v4l2_fops_open(struct file *file)
        ret = fmc_set_mode(fmdev, FM_MODE_RX);
        if (ret < 0) {
                fmerr("Unable to load FM RX firmware\n");
-               return ret;
+               goto open_unlock;
        }
        radio_disconnected = 1;
 
+open_unlock:
+       mutex_unlock(&fmdev->mutex);
        return ret;
 }
 
@@ -156,19 +171,22 @@ static int fm_v4l2_fops_release(struct file *file)
                return 0;
        }
 
+       mutex_lock(&fmdev->mutex);
        ret = fmc_set_mode(fmdev, FM_MODE_OFF);
        if (ret < 0) {
                fmerr("Unable to turn off the chip\n");
-               return ret;
+               goto release_unlock;
        }
 
        ret = fmc_release(fmdev);
        if (ret < 0) {
                fmerr("FM CORE release failed\n");
-               return ret;
+               goto release_unlock;
        }
        radio_disconnected = 0;
 
+release_unlock:
+       mutex_unlock(&fmdev->mutex);
        return ret;
 }
 
@@ -520,10 +538,6 @@ int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr)
        video_set_drvdata(gradio_dev, fmdev);
 
        gradio_dev->lock = &fmdev->mutex;
-       /* Locking in file operations other than ioctl should be done
-          by the driver, not the V4L2 core.
-          This driver needs auditing so that this flag can be removed. */
-       set_bit(V4L2_FL_LOCK_ALL_FOPS, &gradio_dev->flags);
 
        /* Register with V4L2 subsystem as RADIO device */
        if (video_register_device(gradio_dev, VFL_TYPE_RADIO, radio_nr)) {
index 5180390be7ab0915ffa24189269ce4707e1e3baf..8be57634ba60f23e09fc5840a6bb6837920549e2 100644 (file)
@@ -261,6 +261,7 @@ config IR_WINBOND_CIR
 
 config IR_IGUANA
        tristate "IguanaWorks USB IR Transceiver"
+       depends on USB_ARCH_HAS_HCD
        depends on RC_CORE
        select USB
        ---help---
index 3c9431a9f62d282d37238ab6089cd63ca73ad77b..2ca509e6e16b6c73cc09b0bc84616b8b1b1beafe 100644 (file)
@@ -70,7 +70,7 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
                if (!ev.pulse)
                        break;
 
-               if (eq_margin(ev.duration, NEC_HEADER_PULSE, NEC_UNIT / 2)) {
+               if (eq_margin(ev.duration, NEC_HEADER_PULSE, NEC_UNIT * 2)) {
                        data->is_nec_x = false;
                        data->necx_repeat = false;
                } else if (eq_margin(ev.duration, NECX_HEADER_PULSE, NEC_UNIT / 2))
@@ -86,7 +86,7 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
                if (ev.pulse)
                        break;
 
-               if (eq_margin(ev.duration, NEC_HEADER_SPACE, NEC_UNIT / 2)) {
+               if (eq_margin(ev.duration, NEC_HEADER_SPACE, NEC_UNIT)) {
                        data->state = STATE_BIT_PULSE;
                        return 0;
                } else if (eq_margin(ev.duration, NEC_REPEAT_SPACE, NEC_UNIT / 2)) {
index c128fac0ce2cf4b4c0f2d7484fc21b024b3cb5ef..966954de599b341bb1e4cadc15cce913516e9086 100644 (file)
@@ -748,6 +748,8 @@ source "drivers/media/video/tm6000/Kconfig"
 
 source "drivers/media/video/usbvision/Kconfig"
 
+source "drivers/media/video/stk1160/Kconfig"
+
 endif # V4L_USB_DRIVERS
 
 #
@@ -1224,6 +1226,23 @@ config VIDEO_MEM2MEM_TESTDEV
          This is a virtual test device for the memory-to-memory driver
          framework.
 
+config VIDEO_CODA
+       tristate "Chips&Media Coda multi-standard codec IP"
+       depends on VIDEO_DEV && VIDEO_V4L2
+       select VIDEOBUF2_DMA_CONTIG
+       select V4L2_MEM2MEM_DEV
+       ---help---
+          Coda is a range of video codec IPs that supports
+          H.264, MPEG-4, and other video formats.
+
+config VIDEO_MEM2MEM_DEINTERLACE
+       tristate "Deinterlace support"
+       depends on VIDEO_DEV && VIDEO_V4L2 && DMA_ENGINE
+       select VIDEOBUF2_DMA_CONTIG
+       select V4L2_MEM2MEM_DEV
+       help
+           Generic deinterlacing V4L2 driver.
+
 config VIDEO_SAMSUNG_S5P_G2D
        tristate "Samsung S5P and EXYNOS4 G2D 2d graphics accelerator driver"
        depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P
index b7da9faa3b0ac96030983dbf1c057d2c7f88ac8e..12cad1206148e82da4b8354e542e50a1c7fccfa2 100644 (file)
@@ -126,6 +126,7 @@ obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o
 obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o
 obj-$(CONFIG_STA2X11_VIP) += sta2x11_vip.o
 obj-$(CONFIG_VIDEO_TIMBERDALE) += timblogiw.o
+obj-$(CONFIG_VIDEO_STK1160) += stk1160/
 
 obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
 obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
@@ -188,6 +189,9 @@ obj-$(CONFIG_VIDEO_OMAP1)           += omap1_camera.o
 obj-$(CONFIG_VIDEO_ATMEL_ISI)          += atmel-isi.o
 
 obj-$(CONFIG_VIDEO_MX2_EMMAPRP)                += mx2_emmaprp.o
+obj-$(CONFIG_VIDEO_CODA)                       += coda.o
+
+obj-$(CONFIG_VIDEO_MEM2MEM_DEINTERLACE)        += m2m-deinterlace.o
 
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC)   += s5p-fimc/
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG)   += s5p-jpeg/
index e3fe9a6637f66ad446786af6053f084962c42214..448361c6a13eea6e74adefab2ec9d50d448fe7a3 100644 (file)
@@ -46,7 +46,7 @@ struct au0828_board au0828_boards[] = {
                .name   = "Hauppauge HVR850",
                .tuner_type = TUNER_XC5000,
                .tuner_addr = 0x61,
-               .i2c_clk_divider = AU0828_I2C_CLK_30KHZ,
+               .i2c_clk_divider = AU0828_I2C_CLK_20KHZ,
                .input = {
                        {
                                .type = AU0828_VMUX_TELEVISION,
@@ -77,7 +77,7 @@ struct au0828_board au0828_boards[] = {
                   stretch fits inside of a normal clock cycle, or else the
                   au0828 fails to set the STOP bit.  A 30 KHz clock puts the
                   clock pulse width at 18us */
-               .i2c_clk_divider = AU0828_I2C_CLK_30KHZ,
+               .i2c_clk_divider = AU0828_I2C_CLK_20KHZ,
                .input = {
                        {
                                .type = AU0828_VMUX_TELEVISION,
index 1e4ce5068ec2db52ca634f9a90e12ad66f755f6b..745a80a798c8b034f76401c43ce9935b71ce5569 100644 (file)
@@ -46,7 +46,7 @@ MODULE_PARM_DESC(disable_usb_speed_check,
 #define _BULKPIPESIZE 0xffff
 
 static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value,
-       u16 index, unsigned char *cp, u16 size);
+                           u16 index);
 static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
        u16 index, unsigned char *cp, u16 size);
 
@@ -56,41 +56,25 @@ static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
 
 u32 au0828_readreg(struct au0828_dev *dev, u16 reg)
 {
-       recv_control_msg(dev, CMD_REQUEST_IN, 0, reg, dev->ctrlmsg, 1);
-       dprintk(8, "%s(0x%04x) = 0x%02x\n", __func__, reg, dev->ctrlmsg[0]);
-       return dev->ctrlmsg[0];
+       u8 result = 0;
+
+       recv_control_msg(dev, CMD_REQUEST_IN, 0, reg, &result, 1);
+       dprintk(8, "%s(0x%04x) = 0x%02x\n", __func__, reg, result);
+
+       return result;
 }
 
 u32 au0828_writereg(struct au0828_dev *dev, u16 reg, u32 val)
 {
        dprintk(8, "%s(0x%04x, 0x%02x)\n", __func__, reg, val);
-       return send_control_msg(dev, CMD_REQUEST_OUT, val, reg,
-                               dev->ctrlmsg, 0);
-}
-
-static void cmd_msg_dump(struct au0828_dev *dev)
-{
-       int i;
-
-       for (i = 0; i < sizeof(dev->ctrlmsg); i += 16)
-               dprintk(2, "%s() %02x %02x %02x %02x %02x %02x %02x %02x "
-                               "%02x %02x %02x %02x %02x %02x %02x %02x\n",
-                       __func__,
-                       dev->ctrlmsg[i+0], dev->ctrlmsg[i+1],
-                       dev->ctrlmsg[i+2], dev->ctrlmsg[i+3],
-                       dev->ctrlmsg[i+4], dev->ctrlmsg[i+5],
-                       dev->ctrlmsg[i+6], dev->ctrlmsg[i+7],
-                       dev->ctrlmsg[i+8], dev->ctrlmsg[i+9],
-                       dev->ctrlmsg[i+10], dev->ctrlmsg[i+11],
-                       dev->ctrlmsg[i+12], dev->ctrlmsg[i+13],
-                       dev->ctrlmsg[i+14], dev->ctrlmsg[i+15]);
+       return send_control_msg(dev, CMD_REQUEST_OUT, val, reg);
 }
 
 static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value,
-       u16 index, unsigned char *cp, u16 size)
+       u16 index)
 {
        int status = -ENODEV;
-       mutex_lock(&dev->mutex);
+
        if (dev->usbdev) {
 
                /* cp must be memory that has been allocated by kmalloc */
@@ -99,8 +83,7 @@ static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value,
                                request,
                                USB_DIR_OUT | USB_TYPE_VENDOR |
                                        USB_RECIP_DEVICE,
-                               value, index,
-                               cp, size, 1000);
+                               value, index, NULL, 0, 1000);
 
                status = min(status, 0);
 
@@ -110,7 +93,7 @@ static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value,
                }
 
        }
-       mutex_unlock(&dev->mutex);
+
        return status;
 }
 
@@ -120,24 +103,23 @@ static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
        int status = -ENODEV;
        mutex_lock(&dev->mutex);
        if (dev->usbdev) {
-
-               memset(dev->ctrlmsg, 0, sizeof(dev->ctrlmsg));
-
-               /* cp must be memory that has been allocated by kmalloc */
                status = usb_control_msg(dev->usbdev,
                                usb_rcvctrlpipe(dev->usbdev, 0),
                                request,
                                USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
                                value, index,
-                               cp, size, 1000);
+                               dev->ctrlmsg, size, 1000);
 
                status = min(status, 0);
 
                if (status < 0) {
                        printk(KERN_ERR "%s() Failed receiving control message, error %d.\n",
                                __func__, status);
-               } else
-                       cmd_msg_dump(dev);
+               }
+
+               /* the host controller requires heap allocated memory, which
+                  is why we didn't just pass "cp" into usb_control_msg */
+               memcpy(cp, dev->ctrlmsg, size);
        }
        mutex_unlock(&dev->mutex);
        return status;
@@ -205,6 +187,8 @@ static int au0828_usb_probe(struct usb_interface *interface,
                return -ENOMEM;
        }
 
+       mutex_init(&dev->lock);
+       mutex_lock(&dev->lock);
        mutex_init(&dev->mutex);
        mutex_init(&dev->dvb.lock);
        dev->usbdev = usbdev;
@@ -215,6 +199,7 @@ static int au0828_usb_probe(struct usb_interface *interface,
        if (retval) {
                printk(KERN_ERR "%s() v4l2_device_register failed\n",
                       __func__);
+               mutex_unlock(&dev->lock);
                kfree(dev);
                return -EIO;
        }
@@ -245,6 +230,8 @@ static int au0828_usb_probe(struct usb_interface *interface,
        printk(KERN_INFO "Registered device AU0828 [%s]\n",
                dev->board.name == NULL ? "Unset" : dev->board.name);
 
+       mutex_unlock(&dev->lock);
+
        return 0;
 }
 
index 39ece8e2498578d68664d49568ecec26aeb1a616..b328f6550d0b28714ff7339e08844e5491c8b407 100644 (file)
@@ -101,11 +101,14 @@ static struct tda18271_config hauppauge_woodbury_tunerconfig = {
        .gate    = TDA18271_GATE_DIGITAL,
 };
 
+static void au0828_restart_dvb_streaming(struct work_struct *work);
+
 /*-------------------------------------------------------------------*/
 static void urb_completion(struct urb *purb)
 {
        struct au0828_dev *dev = purb->context;
        int ptype = usb_pipetype(purb->pipe);
+       unsigned char *ptr;
 
        dprintk(2, "%s()\n", __func__);
 
@@ -121,6 +124,16 @@ static void urb_completion(struct urb *purb)
                return;
        }
 
+       /* See if the stream is corrupted (to work around a hardware
+          bug where the stream gets misaligned */
+       ptr = purb->transfer_buffer;
+       if (purb->actual_length > 0 && ptr[0] != 0x47) {
+               dprintk(1, "Need to restart streaming %02x len=%d!\n",
+                       ptr[0], purb->actual_length);
+               schedule_work(&dev->restart_streaming);
+               return;
+       }
+
        /* Feed the transport payload into the kernel demux */
        dvb_dmx_swfilter_packets(&dev->dvb.demux,
                purb->transfer_buffer, purb->actual_length / 188);
@@ -138,14 +151,13 @@ static int stop_urb_transfer(struct au0828_dev *dev)
 
        dprintk(2, "%s()\n", __func__);
 
+       dev->urb_streaming = 0;
        for (i = 0; i < URB_COUNT; i++) {
                usb_kill_urb(dev->urbs[i]);
                kfree(dev->urbs[i]->transfer_buffer);
                usb_free_urb(dev->urbs[i]);
        }
 
-       dev->urb_streaming = 0;
-
        return 0;
 }
 
@@ -246,11 +258,8 @@ static int au0828_dvb_stop_feed(struct dvb_demux_feed *feed)
                mutex_lock(&dvb->lock);
                if (--dvb->feeding == 0) {
                        /* Stop transport */
-                       au0828_write(dev, 0x608, 0x00);
-                       au0828_write(dev, 0x609, 0x00);
-                       au0828_write(dev, 0x60a, 0x00);
-                       au0828_write(dev, 0x60b, 0x00);
                        ret = stop_urb_transfer(dev);
+                       au0828_write(dev, 0x60b, 0x00);
                }
                mutex_unlock(&dvb->lock);
        }
@@ -258,6 +267,37 @@ static int au0828_dvb_stop_feed(struct dvb_demux_feed *feed)
        return ret;
 }
 
+static void au0828_restart_dvb_streaming(struct work_struct *work)
+{
+       struct au0828_dev *dev = container_of(work, struct au0828_dev,
+                                             restart_streaming);
+       struct au0828_dvb *dvb = &dev->dvb;
+       int ret;
+
+       if (dev->urb_streaming == 0)
+               return;
+
+       dprintk(1, "Restarting streaming...!\n");
+
+       mutex_lock(&dvb->lock);
+
+       /* Stop transport */
+       ret = stop_urb_transfer(dev);
+       au0828_write(dev, 0x608, 0x00);
+       au0828_write(dev, 0x609, 0x00);
+       au0828_write(dev, 0x60a, 0x00);
+       au0828_write(dev, 0x60b, 0x00);
+
+       /* Start transport */
+       au0828_write(dev, 0x608, 0x90);
+       au0828_write(dev, 0x609, 0x72);
+       au0828_write(dev, 0x60a, 0x71);
+       au0828_write(dev, 0x60b, 0x01);
+       ret = start_urb_transfer(dev);
+
+       mutex_unlock(&dvb->lock);
+}
+
 static int dvb_register(struct au0828_dev *dev)
 {
        struct au0828_dvb *dvb = &dev->dvb;
@@ -265,6 +305,8 @@ static int dvb_register(struct au0828_dev *dev)
 
        dprintk(1, "%s()\n", __func__);
 
+       INIT_WORK(&dev->restart_streaming, au0828_restart_dvb_streaming);
+
        /* register adapter */
        result = dvb_register_adapter(&dvb->adapter, DRIVER_NAME, THIS_MODULE,
                                      &dev->usbdev->dev, adapter_nr);
index 05c299fa5d79f5c90de3da3eca758ad45f7f2933..4ded17fe195792d53158e7936048213376c40e6b 100644 (file)
 #include <linux/io.h>
 
 #include "au0828.h"
-
+#include "media/tuner.h"
 #include <media/v4l2-common.h>
 
 static int i2c_scan;
 module_param(i2c_scan, int, 0444);
 MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
 
-#define I2C_WAIT_DELAY 512
-#define I2C_WAIT_RETRY 64
+#define I2C_WAIT_DELAY 25
+#define I2C_WAIT_RETRY 1000
 
 static inline int i2c_slave_did_write_ack(struct i2c_adapter *i2c_adap)
 {
@@ -147,8 +147,19 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
        au0828_write(dev, AU0828_I2C_MULTIBYTE_MODE_2FF, 0x01);
 
        /* Set the I2C clock */
-       au0828_write(dev, AU0828_I2C_CLK_DIVIDER_202,
-                    dev->board.i2c_clk_divider);
+       if (((dev->board.tuner_type == TUNER_XC5000) ||
+            (dev->board.tuner_type == TUNER_XC5000C)) &&
+           (dev->board.tuner_addr == msg->addr) &&
+           (msg->len == 64)) {
+               /* Hack to speed up firmware load.  The xc5000 lets us do up
+                  to 400 KHz when in firmware download mode */
+               au0828_write(dev, AU0828_I2C_CLK_DIVIDER_202,
+                            AU0828_I2C_CLK_250KHZ);
+       } else {
+               /* Use the i2c clock speed in the board configuration */
+               au0828_write(dev, AU0828_I2C_CLK_DIVIDER_202,
+                            dev->board.i2c_clk_divider);
+       }
 
        /* Hardware needs 8 bit addresses */
        au0828_write(dev, AU0828_I2C_DEST_ADDR_203, msg->addr << 1);
index c39f3d2b721e22580b786f6a0a56f96394a1d563..2140f4cfb645679901e71853a940240a64024029 100644 (file)
@@ -63,3 +63,4 @@
 #define AU0828_I2C_CLK_250KHZ 0x07
 #define AU0828_I2C_CLK_100KHZ 0x14
 #define AU0828_I2C_CLK_30KHZ  0x40
+#define AU0828_I2C_CLK_20KHZ  0x60
index ac3dd733ab815da3ce4345109bee032d6884bbb1..fa0fa9ae91c7402d207be22cfb7469a20f42283b 100644 (file)
@@ -864,17 +864,15 @@ static int res_get(struct au0828_fh *fh, unsigned int bit)
                return 1;
 
        /* is it free? */
-       mutex_lock(&dev->lock);
        if (dev->resources & bit) {
                /* no, someone else uses it */
-               mutex_unlock(&dev->lock);
                return 0;
        }
        /* it's free, grab it */
        fh->resources  |= bit;
        dev->resources |= bit;
        dprintk(1, "res: get %d\n", bit);
-       mutex_unlock(&dev->lock);
+
        return 1;
 }
 
@@ -894,11 +892,9 @@ static void res_free(struct au0828_fh *fh, unsigned int bits)
 
        BUG_ON((fh->resources & bits) != bits);
 
-       mutex_lock(&dev->lock);
        fh->resources  &= ~bits;
        dev->resources &= ~bits;
        dprintk(1, "res: put %d\n", bits);
-       mutex_unlock(&dev->lock);
 }
 
 static int get_ressource(struct au0828_fh *fh)
@@ -1023,7 +1019,8 @@ static int au0828_v4l2_open(struct file *filp)
                                    NULL, &dev->slock,
                                    V4L2_BUF_TYPE_VIDEO_CAPTURE,
                                    V4L2_FIELD_INTERLACED,
-                                   sizeof(struct au0828_buffer), fh, NULL);
+                                   sizeof(struct au0828_buffer), fh,
+                                   &dev->lock);
 
        /* VBI Setup */
        dev->vbi_width = 720;
@@ -1032,8 +1029,8 @@ static int au0828_v4l2_open(struct file *filp)
                                    NULL, &dev->slock,
                                    V4L2_BUF_TYPE_VBI_CAPTURE,
                                    V4L2_FIELD_SEQ_TB,
-                                   sizeof(struct au0828_buffer), fh, NULL);
-
+                                   sizeof(struct au0828_buffer), fh,
+                                   &dev->lock);
        return ret;
 }
 
@@ -1312,8 +1309,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
        if (rc < 0)
                return rc;
 
-       mutex_lock(&dev->lock);
-
        if (videobuf_queue_is_busy(&fh->vb_vidq)) {
                printk(KERN_INFO "%s queue busy\n", __func__);
                rc = -EBUSY;
@@ -1322,7 +1317,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 
        rc = au0828_set_format(dev, VIDIOC_S_FMT, f);
 out:
-       mutex_unlock(&dev->lock);
        return rc;
 }
 
@@ -1331,11 +1325,19 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * norm)
        struct au0828_fh *fh = priv;
        struct au0828_dev *dev = fh->dev;
 
+       if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
+               dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 1);
+
        /* FIXME: when we support something other than NTSC, we are going to
           have to make the au0828 bridge adjust the size of its capture
           buffer, which is currently hardcoded at 720x480 */
 
        v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, *norm);
+       dev->std_set_in_tuner_core = 1;
+
+       if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
+               dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 0);
+
        return 0;
 }
 
@@ -1515,9 +1517,18 @@ static int vidioc_s_tuner(struct file *file, void *priv,
                return -EINVAL;
 
        t->type = V4L2_TUNER_ANALOG_TV;
+
+       if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
+               dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 1);
+
        v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
+
+       if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
+               dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 0);
+
        dprintk(1, "VIDIOC_S_TUNER: signal = %x, afc = %x\n", t->signal,
                t->afc);
+
        return 0;
 
 }
@@ -1546,8 +1557,23 @@ static int vidioc_s_frequency(struct file *file, void *priv,
 
        dev->ctrl_freq = freq->frequency;
 
+       if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
+               dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 1);
+
+       if (dev->std_set_in_tuner_core == 0) {
+         /* If we've never sent the standard in tuner core, do so now.  We
+            don't do this at device probe because we don't want to incur
+            the cost of a firmware load */
+         v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std,
+                              dev->vdev->tvnorms);
+         dev->std_set_in_tuner_core = 1;
+       }
+
        v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, freq);
 
+       if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
+               dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, 0);
+
        au0828_analog_stream_reset(dev);
 
        return 0;
@@ -1692,14 +1718,18 @@ static int vidioc_streamoff(struct file *file, void *priv,
                        (AUVI_INPUT(i).audio_setup)(dev, 0);
                }
 
-               videobuf_streamoff(&fh->vb_vidq);
-               res_free(fh, AU0828_RESOURCE_VIDEO);
+               if (res_check(fh, AU0828_RESOURCE_VIDEO)) {
+                       videobuf_streamoff(&fh->vb_vidq);
+                       res_free(fh, AU0828_RESOURCE_VIDEO);
+               }
        } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
                dev->vbi_timeout_running = 0;
                del_timer_sync(&dev->vbi_timeout);
 
-               videobuf_streamoff(&fh->vb_vbiq);
-               res_free(fh, AU0828_RESOURCE_VBI);
+               if (res_check(fh, AU0828_RESOURCE_VBI)) {
+                       videobuf_streamoff(&fh->vb_vbiq);
+                       res_free(fh, AU0828_RESOURCE_VBI);
+               }
        }
 
        return 0;
@@ -1717,8 +1747,12 @@ static int vidioc_g_register(struct file *file, void *priv,
                v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
                return 0;
        default:
-               return -EINVAL;
+               if (!v4l2_chip_match_host(&reg->match))
+                       return -EINVAL;
        }
+
+       reg->val = au0828_read(dev, reg->reg);
+       return 0;
 }
 
 static int vidioc_s_register(struct file *file, void *priv,
@@ -1732,9 +1766,10 @@ static int vidioc_s_register(struct file *file, void *priv,
                v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
                return 0;
        default:
-               return -EINVAL;
+               if (!v4l2_chip_match_host(&reg->match))
+                       return -EINVAL;
        }
-       return 0;
+       return au0828_writereg(dev, reg->reg, reg->val);
 }
 #endif
 
@@ -1827,7 +1862,7 @@ static struct v4l2_file_operations au0828_v4l_fops = {
        .read       = au0828_v4l2_read,
        .poll       = au0828_v4l2_poll,
        .mmap       = au0828_v4l2_mmap,
-       .ioctl      = video_ioctl2,
+       .unlocked_ioctl = video_ioctl2,
 };
 
 static const struct v4l2_ioctl_ops video_ioctl_ops = {
@@ -1917,7 +1952,6 @@ int au0828_analog_register(struct au0828_dev *dev,
 
        init_waitqueue_head(&dev->open);
        spin_lock_init(&dev->slock);
-       mutex_init(&dev->lock);
 
        /* init video dma queues */
        INIT_LIST_HEAD(&dev->vidq.active);
@@ -1958,11 +1992,13 @@ int au0828_analog_register(struct au0828_dev *dev,
        /* Fill the video capture device struct */
        *dev->vdev = au0828_video_template;
        dev->vdev->parent = &dev->usbdev->dev;
+       dev->vdev->lock = &dev->lock;
        strcpy(dev->vdev->name, "au0828a video");
 
        /* Setup the VBI device */
        *dev->vbi_dev = au0828_video_template;
        dev->vbi_dev->parent = &dev->usbdev->dev;
+       dev->vbi_dev->lock = &dev->lock;
        strcpy(dev->vbi_dev->name, "au0828a vbi");
 
        /* Register the v4l2 device */
index 9cde3532182414dc1a72ec265714015453c29fbb..66a56ef7bbe4f4921a9ebc1af6911a293693573f 100644 (file)
@@ -197,6 +197,7 @@ struct au0828_dev {
 
        /* Digital */
        struct au0828_dvb               dvb;
+       struct work_struct              restart_streaming;
 
        /* Analog */
        struct v4l2_device v4l2_dev;
@@ -224,6 +225,7 @@ struct au0828_dev {
        unsigned int frame_count;
        int ctrl_freq;
        int input_type;
+       int std_set_in_tuner_core;
        unsigned int ctrl_input;
        enum au0828_dev_state dev_state;
        enum au0828_stream_state stream_state;
index 0aba45e34f70e57aee9128d721d6949f08c97018..1677623d8296e72ecbf0a3246c9e7b4c5ee50beb 100644 (file)
@@ -235,8 +235,13 @@ static int bcap_release(struct file *file)
 static int bcap_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct bcap_device *bcap_dev = video_drvdata(file);
+       int ret;
 
-       return vb2_mmap(&bcap_dev->buffer_queue, vma);
+       if (mutex_lock_interruptible(&bcap_dev->mutex))
+               return -ERESTARTSYS;
+       ret = vb2_mmap(&bcap_dev->buffer_queue, vma);
+       mutex_unlock(&bcap_dev->mutex);
+       return ret;
 }
 
 #ifndef CONFIG_MMU
@@ -259,8 +264,12 @@ static unsigned long bcap_get_unmapped_area(struct file *file,
 static unsigned int bcap_poll(struct file *file, poll_table *wait)
 {
        struct bcap_device *bcap_dev = video_drvdata(file);
+       unsigned int res;
 
-       return vb2_poll(&bcap_dev->buffer_queue, file, wait);
+       mutex_lock(&bcap_dev->mutex);
+       res = vb2_poll(&bcap_dev->buffer_queue, file, wait);
+       mutex_unlock(&bcap_dev->mutex);
+       return res;
 }
 
 static int bcap_queue_setup(struct vb2_queue *vq,
@@ -942,10 +951,6 @@ static int __devinit bcap_probe(struct platform_device *pdev)
        INIT_LIST_HEAD(&bcap_dev->dma_queue);
 
        vfd->lock = &bcap_dev->mutex;
-       /* Locking in file operations other than ioctl should be done
-          by the driver, not the V4L2 core.
-          This driver needs auditing so that this flag can be removed. */
-       set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
 
        /* register video device */
        ret = video_register_device(bcap_dev->video_dev, VFL_TYPE_GRABBER, -1);
diff --git a/drivers/media/video/coda.c b/drivers/media/video/coda.c
new file mode 100644 (file)
index 0000000..0d6e0a0
--- /dev/null
@@ -0,0 +1,1849 @@
+/*
+ * Coda multi-standard codec IP
+ *
+ * Copyright (C) 2012 Vista Silicon S.L.
+ *    Javier Martin, <javier.martin@vista-silicon.com>
+ *    Xavier Duret
+ *
+ * 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/clk.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <linux/of.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "coda.h"
+
+#define CODA_NAME              "coda"
+
+#define CODA_MAX_INSTANCES     4
+
+#define CODA_FMO_BUF_SIZE      32
+#define CODADX6_WORK_BUF_SIZE  (288 * 1024 + CODA_FMO_BUF_SIZE * 8 * 1024)
+#define CODA7_WORK_BUF_SIZE    (512 * 1024 + CODA_FMO_BUF_SIZE * 8 * 1024)
+#define CODA_PARA_BUF_SIZE     (10 * 1024)
+#define CODA_ISRAM_SIZE        (2048 * 2)
+
+#define CODA_OUTPUT_BUFS       4
+#define CODA_CAPTURE_BUFS      2
+
+#define MAX_W          720
+#define MAX_H          576
+#define CODA_MAX_FRAME_SIZE    0x90000
+#define FMO_SLICE_SAVE_BUF_SIZE         (32)
+#define CODA_DEFAULT_GAMMA             4096
+
+#define MIN_W 176
+#define MIN_H 144
+#define MAX_W 720
+#define MAX_H 576
+
+#define S_ALIGN                1 /* multiple of 2 */
+#define W_ALIGN                1 /* multiple of 2 */
+#define H_ALIGN                1 /* multiple of 2 */
+
+#define fh_to_ctx(__fh)        container_of(__fh, struct coda_ctx, fh)
+
+static int coda_debug;
+module_param(coda_debug, int, 0);
+MODULE_PARM_DESC(coda_debug, "Debug level (0-1)");
+
+enum {
+       V4L2_M2M_SRC = 0,
+       V4L2_M2M_DST = 1,
+};
+
+enum coda_fmt_type {
+       CODA_FMT_ENC,
+       CODA_FMT_RAW,
+};
+
+enum coda_inst_type {
+       CODA_INST_ENCODER,
+       CODA_INST_DECODER,
+};
+
+enum coda_product {
+       CODA_DX6 = 0xf001,
+};
+
+struct coda_fmt {
+       char *name;
+       u32 fourcc;
+       enum coda_fmt_type type;
+};
+
+struct coda_devtype {
+       char                    *firmware;
+       enum coda_product       product;
+       struct coda_fmt         *formats;
+       unsigned int            num_formats;
+       size_t                  workbuf_size;
+};
+
+/* Per-queue, driver-specific private data */
+struct coda_q_data {
+       unsigned int            width;
+       unsigned int            height;
+       unsigned int            sizeimage;
+       struct coda_fmt *fmt;
+};
+
+struct coda_aux_buf {
+       void                    *vaddr;
+       dma_addr_t              paddr;
+       u32                     size;
+};
+
+struct coda_dev {
+       struct v4l2_device      v4l2_dev;
+       struct video_device     vfd;
+       struct platform_device  *plat_dev;
+       struct coda_devtype     *devtype;
+
+       void __iomem            *regs_base;
+       struct clk              *clk_per;
+       struct clk              *clk_ahb;
+
+       struct coda_aux_buf     codebuf;
+       struct coda_aux_buf     workbuf;
+
+       spinlock_t              irqlock;
+       struct mutex            dev_mutex;
+       struct v4l2_m2m_dev     *m2m_dev;
+       struct vb2_alloc_ctx    *alloc_ctx;
+       int                     instances;
+};
+
+struct coda_params {
+       u8                      h264_intra_qp;
+       u8                      h264_inter_qp;
+       u8                      mpeg4_intra_qp;
+       u8                      mpeg4_inter_qp;
+       u8                      gop_size;
+       int                     codec_mode;
+       enum v4l2_mpeg_video_multi_slice_mode slice_mode;
+       u32                     framerate;
+       u16                     bitrate;
+       u32                     slice_max_mb;
+};
+
+struct coda_ctx {
+       struct coda_dev                 *dev;
+       int                             aborting;
+       int                             rawstreamon;
+       int                             compstreamon;
+       u32                             isequence;
+       struct coda_q_data              q_data[2];
+       enum coda_inst_type             inst_type;
+       enum v4l2_colorspace            colorspace;
+       struct coda_params              params;
+       struct v4l2_m2m_ctx             *m2m_ctx;
+       struct v4l2_ctrl_handler        ctrls;
+       struct v4l2_fh                  fh;
+       struct vb2_buffer               *reference;
+       int                             gopcounter;
+       char                            vpu_header[3][64];
+       int                             vpu_header_size[3];
+       struct coda_aux_buf             parabuf;
+       int                             idx;
+};
+
+static inline void coda_write(struct coda_dev *dev, u32 data, u32 reg)
+{
+       v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+                "%s: data=0x%x, reg=0x%x\n", __func__, data, reg);
+       writel(data, dev->regs_base + reg);
+}
+
+static inline unsigned int coda_read(struct coda_dev *dev, u32 reg)
+{
+       u32 data;
+       data = readl(dev->regs_base + reg);
+       v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+                "%s: data=0x%x, reg=0x%x\n", __func__, data, reg);
+       return data;
+}
+
+static inline unsigned long coda_isbusy(struct coda_dev *dev)
+{
+       return coda_read(dev, CODA_REG_BIT_BUSY);
+}
+
+static inline int coda_is_initialized(struct coda_dev *dev)
+{
+       return (coda_read(dev, CODA_REG_BIT_CUR_PC) != 0);
+}
+
+static int coda_wait_timeout(struct coda_dev *dev)
+{
+       unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+
+       while (coda_isbusy(dev)) {
+               if (time_after(jiffies, timeout))
+                       return -ETIMEDOUT;
+       }
+       return 0;
+}
+
+static void coda_command_async(struct coda_ctx *ctx, int cmd)
+{
+       struct coda_dev *dev = ctx->dev;
+       coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY);
+
+       coda_write(dev, ctx->idx, CODA_REG_BIT_RUN_INDEX);
+       coda_write(dev, ctx->params.codec_mode, CODA_REG_BIT_RUN_COD_STD);
+       coda_write(dev, cmd, CODA_REG_BIT_RUN_COMMAND);
+}
+
+static int coda_command_sync(struct coda_ctx *ctx, int cmd)
+{
+       struct coda_dev *dev = ctx->dev;
+
+       coda_command_async(ctx, cmd);
+       return coda_wait_timeout(dev);
+}
+
+static struct coda_q_data *get_q_data(struct coda_ctx *ctx,
+                                        enum v4l2_buf_type type)
+{
+       switch (type) {
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+               return &(ctx->q_data[V4L2_M2M_SRC]);
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               return &(ctx->q_data[V4L2_M2M_DST]);
+       default:
+               BUG();
+       }
+       return NULL;
+}
+
+/*
+ * Add one array of supported formats for each version of Coda:
+ *  i.MX27 -> codadx6
+ *  i.MX51 -> coda7
+ *  i.MX6  -> coda960
+ */
+static struct coda_fmt codadx6_formats[] = {
+       {
+               .name = "YUV 4:2:0 Planar",
+               .fourcc = V4L2_PIX_FMT_YUV420,
+               .type = CODA_FMT_RAW,
+       },
+       {
+               .name = "H264 Encoded Stream",
+               .fourcc = V4L2_PIX_FMT_H264,
+               .type = CODA_FMT_ENC,
+       },
+       {
+               .name = "MPEG4 Encoded Stream",
+               .fourcc = V4L2_PIX_FMT_MPEG4,
+               .type = CODA_FMT_ENC,
+       },
+};
+
+static struct coda_fmt *find_format(struct coda_dev *dev, struct v4l2_format *f)
+{
+       struct coda_fmt *formats = dev->devtype->formats;
+       int num_formats = dev->devtype->num_formats;
+       unsigned int k;
+
+       for (k = 0; k < num_formats; k++) {
+               if (formats[k].fourcc == f->fmt.pix.pixelformat)
+                       break;
+       }
+
+       if (k == num_formats)
+               return NULL;
+
+       return &formats[k];
+}
+
+/*
+ * V4L2 ioctl() operations.
+ */
+static int vidioc_querycap(struct file *file, void *priv,
+                          struct v4l2_capability *cap)
+{
+       strlcpy(cap->driver, CODA_NAME, sizeof(cap->driver));
+       strlcpy(cap->card, CODA_NAME, sizeof(cap->card));
+       strlcpy(cap->bus_info, CODA_NAME, sizeof(cap->bus_info));
+       cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT
+                               | V4L2_CAP_STREAMING;
+       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+
+       return 0;
+}
+
+static int enum_fmt(void *priv, struct v4l2_fmtdesc *f,
+                       enum coda_fmt_type type)
+{
+       struct coda_ctx *ctx = fh_to_ctx(priv);
+       struct coda_dev *dev = ctx->dev;
+       struct coda_fmt *formats = dev->devtype->formats;
+       struct coda_fmt *fmt;
+       int num_formats = dev->devtype->num_formats;
+       int i, num = 0;
+
+       for (i = 0; i < num_formats; i++) {
+               if (formats[i].type == type) {
+                       if (num == f->index)
+                               break;
+                       ++num;
+               }
+       }
+
+       if (i < num_formats) {
+               fmt = &formats[i];
+               strlcpy(f->description, fmt->name, sizeof(f->description));
+               f->pixelformat = fmt->fourcc;
+               return 0;
+       }
+
+       /* Format not found */
+       return -EINVAL;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+                                  struct v4l2_fmtdesc *f)
+{
+       return enum_fmt(priv, f, CODA_FMT_ENC);
+}
+
+static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
+                                  struct v4l2_fmtdesc *f)
+{
+       return enum_fmt(priv, f, CODA_FMT_RAW);
+}
+
+static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+       struct vb2_queue *vq;
+       struct coda_q_data *q_data;
+       struct coda_ctx *ctx = fh_to_ctx(priv);
+
+       vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+       if (!vq)
+               return -EINVAL;
+
+       q_data = get_q_data(ctx, f->type);
+
+       f->fmt.pix.field        = V4L2_FIELD_NONE;
+       f->fmt.pix.pixelformat  = q_data->fmt->fourcc;
+       f->fmt.pix.width        = q_data->width;
+       f->fmt.pix.height       = q_data->height;
+       if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420)
+               f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 2);
+       else /* encoded formats h.264/mpeg4 */
+               f->fmt.pix.bytesperline = 0;
+
+       f->fmt.pix.sizeimage    = q_data->sizeimage;
+       f->fmt.pix.colorspace   = ctx->colorspace;
+
+       return 0;
+}
+
+static int vidioc_try_fmt(struct coda_dev *dev, struct v4l2_format *f)
+{
+       enum v4l2_field field;
+
+       field = f->fmt.pix.field;
+       if (field == V4L2_FIELD_ANY)
+               field = V4L2_FIELD_NONE;
+       else if (V4L2_FIELD_NONE != field)
+               return -EINVAL;
+
+       /* V4L2 specification suggests the driver corrects the format struct
+        * if any of the dimensions is unsupported */
+       f->fmt.pix.field = field;
+
+       if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV420) {
+               v4l_bound_align_image(&f->fmt.pix.width, MIN_W, MAX_W,
+                                     W_ALIGN, &f->fmt.pix.height,
+                                     MIN_H, MAX_H, H_ALIGN, S_ALIGN);
+               f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 2);
+               f->fmt.pix.sizeimage = f->fmt.pix.height *
+                                       f->fmt.pix.bytesperline;
+       } else { /*encoded formats h.264/mpeg4 */
+               f->fmt.pix.bytesperline = 0;
+               f->fmt.pix.sizeimage = CODA_MAX_FRAME_SIZE;
+       }
+
+       return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+                                 struct v4l2_format *f)
+{
+       int ret;
+       struct coda_fmt *fmt;
+       struct coda_ctx *ctx = fh_to_ctx(priv);
+
+       fmt = find_format(ctx->dev, f);
+       /*
+        * Since decoding support is not implemented yet do not allow
+        * CODA_FMT_RAW formats in the capture interface.
+        */
+       if (!fmt || !(fmt->type == CODA_FMT_ENC))
+               f->fmt.pix.pixelformat = V4L2_PIX_FMT_H264;
+
+       f->fmt.pix.colorspace = ctx->colorspace;
+
+       ret = vidioc_try_fmt(ctx->dev, f);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
+                                 struct v4l2_format *f)
+{
+       struct coda_ctx *ctx = fh_to_ctx(priv);
+       struct coda_fmt *fmt;
+       int ret;
+
+       fmt = find_format(ctx->dev, f);
+       /*
+        * Since decoding support is not implemented yet do not allow
+        * CODA_FMT formats in the capture interface.
+        */
+       if (!fmt || !(fmt->type == CODA_FMT_RAW))
+               f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
+
+       if (!f->fmt.pix.colorspace)
+               f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
+
+       ret = vidioc_try_fmt(ctx->dev, f);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int vidioc_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f)
+{
+       struct coda_q_data *q_data;
+       struct vb2_queue *vq;
+       int ret;
+
+       vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+       if (!vq)
+               return -EINVAL;
+
+       q_data = get_q_data(ctx, f->type);
+       if (!q_data)
+               return -EINVAL;
+
+       if (vb2_is_busy(vq)) {
+               v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__);
+               return -EBUSY;
+       }
+
+       ret = vidioc_try_fmt(ctx->dev, f);
+       if (ret)
+               return ret;
+
+       q_data->fmt = find_format(ctx->dev, f);
+       q_data->width = f->fmt.pix.width;
+       q_data->height = f->fmt.pix.height;
+       if (q_data->fmt->fourcc == V4L2_PIX_FMT_YUV420) {
+               q_data->sizeimage = q_data->width * q_data->height * 3 / 2;
+       } else { /* encoded format h.264/mpeg-4 */
+               q_data->sizeimage = CODA_MAX_FRAME_SIZE;
+       }
+
+       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+               "Setting format for type %d, wxh: %dx%d, fmt: %d\n",
+               f->type, q_data->width, q_data->height, q_data->fmt->fourcc);
+
+       return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       int ret;
+
+       ret = vidioc_try_fmt_vid_cap(file, priv, f);
+       if (ret)
+               return ret;
+
+       return vidioc_s_fmt(fh_to_ctx(priv), f);
+}
+
+static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct coda_ctx *ctx = fh_to_ctx(priv);
+       int ret;
+
+       ret = vidioc_try_fmt_vid_out(file, priv, f);
+       if (ret)
+               return ret;
+
+       ret = vidioc_s_fmt(fh_to_ctx(priv), f);
+       if (ret)
+               ctx->colorspace = f->fmt.pix.colorspace;
+
+       return ret;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+                         struct v4l2_requestbuffers *reqbufs)
+{
+       struct coda_ctx *ctx = fh_to_ctx(priv);
+
+       return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+                          struct v4l2_buffer *buf)
+{
+       struct coda_ctx *ctx = fh_to_ctx(priv);
+
+       return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+       struct coda_ctx *ctx = fh_to_ctx(priv);
+
+       return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+       struct coda_ctx *ctx = fh_to_ctx(priv);
+
+       return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_streamon(struct file *file, void *priv,
+                          enum v4l2_buf_type type)
+{
+       struct coda_ctx *ctx = fh_to_ctx(priv);
+
+       return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
+}
+
+static int vidioc_streamoff(struct file *file, void *priv,
+                           enum v4l2_buf_type type)
+{
+       struct coda_ctx *ctx = fh_to_ctx(priv);
+
+       return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
+}
+
+static const struct v4l2_ioctl_ops coda_ioctl_ops = {
+       .vidioc_querycap        = vidioc_querycap,
+
+       .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+       .vidioc_g_fmt_vid_cap   = vidioc_g_fmt,
+       .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap   = vidioc_s_fmt_vid_cap,
+
+       .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
+       .vidioc_g_fmt_vid_out   = vidioc_g_fmt,
+       .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
+       .vidioc_s_fmt_vid_out   = vidioc_s_fmt_vid_out,
+
+       .vidioc_reqbufs         = vidioc_reqbufs,
+       .vidioc_querybuf        = vidioc_querybuf,
+
+       .vidioc_qbuf            = vidioc_qbuf,
+       .vidioc_dqbuf           = vidioc_dqbuf,
+
+       .vidioc_streamon        = vidioc_streamon,
+       .vidioc_streamoff       = vidioc_streamoff,
+};
+
+/*
+ * Mem-to-mem operations.
+ */
+static void coda_device_run(void *m2m_priv)
+{
+       struct coda_ctx *ctx = m2m_priv;
+       struct coda_q_data *q_data_src, *q_data_dst;
+       struct vb2_buffer *src_buf, *dst_buf;
+       struct coda_dev *dev = ctx->dev;
+       int force_ipicture;
+       int quant_param = 0;
+       u32 picture_y, picture_cb, picture_cr;
+       u32 pic_stream_buffer_addr, pic_stream_buffer_size;
+       u32 dst_fourcc;
+
+       src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+       dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+       q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+       q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+       dst_fourcc = q_data_dst->fmt->fourcc;
+
+       src_buf->v4l2_buf.sequence = ctx->isequence;
+       dst_buf->v4l2_buf.sequence = ctx->isequence;
+       ctx->isequence++;
+
+       /*
+        * Workaround coda firmware BUG that only marks the first
+        * frame as IDR. This is a problem for some decoders that can't
+        * recover when a frame is lost.
+        */
+       if (src_buf->v4l2_buf.sequence % ctx->params.gop_size) {
+               src_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
+               src_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME;
+       } else {
+               src_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
+               src_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME;
+       }
+
+       /*
+        * Copy headers at the beginning of the first frame for H.264 only.
+        * In MPEG4 they are already copied by the coda.
+        */
+       if (src_buf->v4l2_buf.sequence == 0) {
+               pic_stream_buffer_addr =
+                       vb2_dma_contig_plane_dma_addr(dst_buf, 0) +
+                       ctx->vpu_header_size[0] +
+                       ctx->vpu_header_size[1] +
+                       ctx->vpu_header_size[2];
+               pic_stream_buffer_size = CODA_MAX_FRAME_SIZE -
+                       ctx->vpu_header_size[0] -
+                       ctx->vpu_header_size[1] -
+                       ctx->vpu_header_size[2];
+               memcpy(vb2_plane_vaddr(dst_buf, 0),
+                      &ctx->vpu_header[0][0], ctx->vpu_header_size[0]);
+               memcpy(vb2_plane_vaddr(dst_buf, 0) + ctx->vpu_header_size[0],
+                      &ctx->vpu_header[1][0], ctx->vpu_header_size[1]);
+               memcpy(vb2_plane_vaddr(dst_buf, 0) + ctx->vpu_header_size[0] +
+                       ctx->vpu_header_size[1], &ctx->vpu_header[2][0],
+                       ctx->vpu_header_size[2]);
+       } else {
+               pic_stream_buffer_addr =
+                       vb2_dma_contig_plane_dma_addr(dst_buf, 0);
+               pic_stream_buffer_size = CODA_MAX_FRAME_SIZE;
+       }
+
+       if (src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) {
+               force_ipicture = 1;
+               switch (dst_fourcc) {
+               case V4L2_PIX_FMT_H264:
+                       quant_param = ctx->params.h264_intra_qp;
+                       break;
+               case V4L2_PIX_FMT_MPEG4:
+                       quant_param = ctx->params.mpeg4_intra_qp;
+                       break;
+               default:
+                       v4l2_warn(&ctx->dev->v4l2_dev,
+                               "cannot set intra qp, fmt not supported\n");
+                       break;
+               }
+       } else {
+               force_ipicture = 0;
+               switch (dst_fourcc) {
+               case V4L2_PIX_FMT_H264:
+                       quant_param = ctx->params.h264_inter_qp;
+                       break;
+               case V4L2_PIX_FMT_MPEG4:
+                       quant_param = ctx->params.mpeg4_inter_qp;
+                       break;
+               default:
+                       v4l2_warn(&ctx->dev->v4l2_dev,
+                               "cannot set inter qp, fmt not supported\n");
+                       break;
+               }
+       }
+
+       /* submit */
+       coda_write(dev, 0, CODA_CMD_ENC_PIC_ROT_MODE);
+       coda_write(dev, quant_param, CODA_CMD_ENC_PIC_QS);
+
+
+       picture_y = vb2_dma_contig_plane_dma_addr(src_buf, 0);
+       picture_cb = picture_y + q_data_src->width * q_data_src->height;
+       picture_cr = picture_cb + q_data_src->width / 2 *
+                       q_data_src->height / 2;
+
+       coda_write(dev, picture_y, CODA_CMD_ENC_PIC_SRC_ADDR_Y);
+       coda_write(dev, picture_cb, CODA_CMD_ENC_PIC_SRC_ADDR_CB);
+       coda_write(dev, picture_cr, CODA_CMD_ENC_PIC_SRC_ADDR_CR);
+       coda_write(dev, force_ipicture << 1 & 0x2,
+                  CODA_CMD_ENC_PIC_OPTION);
+
+       coda_write(dev, pic_stream_buffer_addr, CODA_CMD_ENC_PIC_BB_START);
+       coda_write(dev, pic_stream_buffer_size / 1024,
+                  CODA_CMD_ENC_PIC_BB_SIZE);
+       coda_command_async(ctx, CODA_COMMAND_PIC_RUN);
+}
+
+static int coda_job_ready(void *m2m_priv)
+{
+       struct coda_ctx *ctx = m2m_priv;
+
+       /*
+        * For both 'P' and 'key' frame cases 1 picture
+        * and 1 frame are needed.
+        */
+       if (!v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) ||
+               !v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx)) {
+               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                        "not ready: not enough video buffers.\n");
+               return 0;
+       }
+
+       /* For P frames a reference picture is needed too */
+       if ((ctx->gopcounter != (ctx->params.gop_size - 1)) &&
+          !ctx->reference) {
+               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                        "not ready: reference picture not available.\n");
+               return 0;
+       }
+
+       if (coda_isbusy(ctx->dev)) {
+               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                        "not ready: coda is still busy.\n");
+               return 0;
+       }
+
+       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                       "job ready\n");
+       return 1;
+}
+
+static void coda_job_abort(void *priv)
+{
+       struct coda_ctx *ctx = priv;
+       struct coda_dev *dev = ctx->dev;
+
+       ctx->aborting = 1;
+
+       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                "Aborting task\n");
+
+       v4l2_m2m_job_finish(dev->m2m_dev, ctx->m2m_ctx);
+}
+
+static void coda_lock(void *m2m_priv)
+{
+       struct coda_ctx *ctx = m2m_priv;
+       struct coda_dev *pcdev = ctx->dev;
+       mutex_lock(&pcdev->dev_mutex);
+}
+
+static void coda_unlock(void *m2m_priv)
+{
+       struct coda_ctx *ctx = m2m_priv;
+       struct coda_dev *pcdev = ctx->dev;
+       mutex_unlock(&pcdev->dev_mutex);
+}
+
+static struct v4l2_m2m_ops coda_m2m_ops = {
+       .device_run     = coda_device_run,
+       .job_ready      = coda_job_ready,
+       .job_abort      = coda_job_abort,
+       .lock           = coda_lock,
+       .unlock         = coda_unlock,
+};
+
+static void set_default_params(struct coda_ctx *ctx)
+{
+       struct coda_dev *dev = ctx->dev;
+
+       ctx->params.codec_mode = CODA_MODE_INVALID;
+       ctx->colorspace = V4L2_COLORSPACE_REC709;
+       ctx->params.framerate = 30;
+       ctx->reference = NULL;
+       ctx->aborting = 0;
+
+       /* Default formats for output and input queues */
+       ctx->q_data[V4L2_M2M_SRC].fmt = &dev->devtype->formats[0];
+       ctx->q_data[V4L2_M2M_DST].fmt = &dev->devtype->formats[1];
+       ctx->q_data[V4L2_M2M_SRC].width = MAX_W;
+       ctx->q_data[V4L2_M2M_SRC].height = MAX_H;
+       ctx->q_data[V4L2_M2M_SRC].sizeimage = (MAX_W * MAX_H * 3) / 2;
+       ctx->q_data[V4L2_M2M_DST].width = MAX_W;
+       ctx->q_data[V4L2_M2M_DST].height = MAX_H;
+       ctx->q_data[V4L2_M2M_DST].sizeimage = CODA_MAX_FRAME_SIZE;
+}
+
+/*
+ * Queue operations
+ */
+static int coda_queue_setup(struct vb2_queue *vq,
+                               const struct v4l2_format *fmt,
+                               unsigned int *nbuffers, unsigned int *nplanes,
+                               unsigned int sizes[], void *alloc_ctxs[])
+{
+       struct coda_ctx *ctx = vb2_get_drv_priv(vq);
+       unsigned int size;
+
+       if (vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+               *nbuffers = CODA_OUTPUT_BUFS;
+               if (fmt)
+                       size = fmt->fmt.pix.width *
+                               fmt->fmt.pix.height * 3 / 2;
+               else
+                       size = MAX_W *
+                               MAX_H * 3 / 2;
+       } else {
+               *nbuffers = CODA_CAPTURE_BUFS;
+               size = CODA_MAX_FRAME_SIZE;
+       }
+
+       *nplanes = 1;
+       sizes[0] = size;
+
+       alloc_ctxs[0] = ctx->dev->alloc_ctx;
+
+       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                "get %d buffer(s) of size %d each.\n", *nbuffers, size);
+
+       return 0;
+}
+
+static int coda_buf_prepare(struct vb2_buffer *vb)
+{
+       struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+       struct coda_q_data *q_data;
+
+       q_data = get_q_data(ctx, vb->vb2_queue->type);
+
+       if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
+               v4l2_warn(&ctx->dev->v4l2_dev,
+                         "%s data will not fit into plane (%lu < %lu)\n",
+                         __func__, vb2_plane_size(vb, 0),
+                         (long)q_data->sizeimage);
+               return -EINVAL;
+       }
+
+       vb2_set_plane_payload(vb, 0, q_data->sizeimage);
+
+       return 0;
+}
+
+static void coda_buf_queue(struct vb2_buffer *vb)
+{
+       struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+       v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
+}
+
+static void coda_wait_prepare(struct vb2_queue *q)
+{
+       struct coda_ctx *ctx = vb2_get_drv_priv(q);
+       coda_unlock(ctx);
+}
+
+static void coda_wait_finish(struct vb2_queue *q)
+{
+       struct coda_ctx *ctx = vb2_get_drv_priv(q);
+       coda_lock(ctx);
+}
+
+static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+       struct coda_ctx *ctx = vb2_get_drv_priv(q);
+       struct v4l2_device *v4l2_dev = &ctx->dev->v4l2_dev;
+       u32 bitstream_buf, bitstream_size;
+       struct coda_dev *dev = ctx->dev;
+       struct coda_q_data *q_data_src, *q_data_dst;
+       u32 dst_fourcc;
+       struct vb2_buffer *buf;
+       struct vb2_queue *src_vq;
+       u32 value;
+       int i = 0;
+
+       if (count < 1)
+               return -EINVAL;
+
+       if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+               ctx->rawstreamon = 1;
+       else
+               ctx->compstreamon = 1;
+
+       /* Don't start the coda unless both queues are on */
+       if (!(ctx->rawstreamon & ctx->compstreamon))
+               return 0;
+
+       ctx->gopcounter = ctx->params.gop_size - 1;
+
+       q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+       buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+       bitstream_buf = vb2_dma_contig_plane_dma_addr(buf, 0);
+       q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+       bitstream_size = q_data_dst->sizeimage;
+       dst_fourcc = q_data_dst->fmt->fourcc;
+
+       /* Find out whether coda must encode or decode */
+       if (q_data_src->fmt->type == CODA_FMT_RAW &&
+           q_data_dst->fmt->type == CODA_FMT_ENC) {
+               ctx->inst_type = CODA_INST_ENCODER;
+       } else if (q_data_src->fmt->type == CODA_FMT_ENC &&
+                  q_data_dst->fmt->type == CODA_FMT_RAW) {
+               ctx->inst_type = CODA_INST_DECODER;
+               v4l2_err(v4l2_dev, "decoding not supported.\n");
+               return -EINVAL;
+       } else {
+               v4l2_err(v4l2_dev, "couldn't tell instance type.\n");
+               return -EINVAL;
+       }
+
+       if (!coda_is_initialized(dev)) {
+               v4l2_err(v4l2_dev, "coda is not initialized.\n");
+               return -EFAULT;
+       }
+       coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR);
+       coda_write(dev, bitstream_buf, CODA_REG_BIT_RD_PTR(ctx->idx));
+       coda_write(dev, bitstream_buf, CODA_REG_BIT_WR_PTR(ctx->idx));
+       switch (dev->devtype->product) {
+       case CODA_DX6:
+               coda_write(dev, CODADX6_STREAM_BUF_DYNALLOC_EN |
+                       CODADX6_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL);
+               break;
+       default:
+               coda_write(dev, CODA7_STREAM_BUF_DYNALLOC_EN |
+                       CODA7_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL);
+       }
+
+       /* Configure the coda */
+       coda_write(dev, 0xffff4c00, CODA_REG_BIT_SEARCH_RAM_BASE_ADDR);
+
+       /* Could set rotation here if needed */
+       switch (dev->devtype->product) {
+       case CODA_DX6:
+               value = (q_data_src->width & CODADX6_PICWIDTH_MASK) << CODADX6_PICWIDTH_OFFSET;
+               break;
+       default:
+               value = (q_data_src->width & CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET;
+       }
+       value |= (q_data_src->height & CODA_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET;
+       coda_write(dev, value, CODA_CMD_ENC_SEQ_SRC_SIZE);
+       coda_write(dev, ctx->params.framerate,
+                  CODA_CMD_ENC_SEQ_SRC_F_RATE);
+
+       switch (dst_fourcc) {
+       case V4L2_PIX_FMT_MPEG4:
+               if (dev->devtype->product == CODA_DX6)
+                       ctx->params.codec_mode = CODADX6_MODE_ENCODE_MP4;
+               else
+                       ctx->params.codec_mode = CODA7_MODE_ENCODE_MP4;
+
+               coda_write(dev, CODA_STD_MPEG4, CODA_CMD_ENC_SEQ_COD_STD);
+               coda_write(dev, 0, CODA_CMD_ENC_SEQ_MP4_PARA);
+               break;
+       case V4L2_PIX_FMT_H264:
+               if (dev->devtype->product == CODA_DX6)
+                       ctx->params.codec_mode = CODADX6_MODE_ENCODE_H264;
+               else
+                       ctx->params.codec_mode = CODA7_MODE_ENCODE_H264;
+
+               coda_write(dev, CODA_STD_H264, CODA_CMD_ENC_SEQ_COD_STD);
+               coda_write(dev, 0, CODA_CMD_ENC_SEQ_264_PARA);
+               break;
+       default:
+               v4l2_err(v4l2_dev,
+                        "dst format (0x%08x) invalid.\n", dst_fourcc);
+               return -EINVAL;
+       }
+
+       value  = (ctx->params.slice_max_mb & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET;
+       value |= (1 & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET;
+       if (ctx->params.slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB)
+               value |=  1 & CODA_SLICING_MODE_MASK;
+       coda_write(dev, value, CODA_CMD_ENC_SEQ_SLICE_MODE);
+       value  =  ctx->params.gop_size & CODA_GOP_SIZE_MASK;
+       coda_write(dev, value, CODA_CMD_ENC_SEQ_GOP_SIZE);
+
+       if (ctx->params.bitrate) {
+               /* Rate control enabled */
+               value = (ctx->params.bitrate & CODA_RATECONTROL_BITRATE_MASK) << CODA_RATECONTROL_BITRATE_OFFSET;
+               value |=  1 & CODA_RATECONTROL_ENABLE_MASK;
+       } else {
+               value = 0;
+       }
+       coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_PARA);
+
+       coda_write(dev, 0, CODA_CMD_ENC_SEQ_RC_BUF_SIZE);
+       coda_write(dev, 0, CODA_CMD_ENC_SEQ_INTRA_REFRESH);
+
+       coda_write(dev, bitstream_buf, CODA_CMD_ENC_SEQ_BB_START);
+       coda_write(dev, bitstream_size / 1024, CODA_CMD_ENC_SEQ_BB_SIZE);
+
+       /* set default gamma */
+       value = (CODA_DEFAULT_GAMMA & CODA_GAMMA_MASK) << CODA_GAMMA_OFFSET;
+       coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_GAMMA);
+
+       value  = (CODA_DEFAULT_GAMMA > 0) << CODA_OPTION_GAMMA_OFFSET;
+       value |= (0 & CODA_OPTION_SLICEREPORT_MASK) << CODA_OPTION_SLICEREPORT_OFFSET;
+       coda_write(dev, value, CODA_CMD_ENC_SEQ_OPTION);
+
+       if (dst_fourcc == V4L2_PIX_FMT_H264) {
+               value  = (FMO_SLICE_SAVE_BUF_SIZE << 7);
+               value |= (0 & CODA_FMOPARAM_TYPE_MASK) << CODA_FMOPARAM_TYPE_OFFSET;
+               value |=  0 & CODA_FMOPARAM_SLICENUM_MASK;
+               coda_write(dev, value, CODA_CMD_ENC_SEQ_FMO);
+       }
+
+       if (coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT)) {
+               v4l2_err(v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n");
+               return -ETIMEDOUT;
+       }
+
+       if (coda_read(dev, CODA_RET_ENC_SEQ_SUCCESS) == 0)
+               return -EFAULT;
+
+       /*
+        * Walk the src buffer list and let the codec know the
+        * addresses of the pictures.
+        */
+       src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+       for (i = 0; i < src_vq->num_buffers; i++) {
+               u32 *p;
+
+               buf = src_vq->bufs[i];
+               p = ctx->parabuf.vaddr;
+
+               p[i * 3] = vb2_dma_contig_plane_dma_addr(buf, 0);
+               p[i * 3 + 1] = p[i * 3] + q_data_src->width *
+                               q_data_src->height;
+               p[i * 3 + 2] = p[i * 3 + 1] + q_data_src->width / 2 *
+                               q_data_src->height / 2;
+       }
+
+       coda_write(dev, src_vq->num_buffers, CODA_CMD_SET_FRAME_BUF_NUM);
+       coda_write(dev, q_data_src->width, CODA_CMD_SET_FRAME_BUF_STRIDE);
+       if (coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF)) {
+               v4l2_err(v4l2_dev, "CODA_COMMAND_SET_FRAME_BUF timeout\n");
+               return -ETIMEDOUT;
+       }
+
+       /* Save stream headers */
+       buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+       switch (dst_fourcc) {
+       case V4L2_PIX_FMT_H264:
+               /*
+                * Get SPS in the first frame and copy it to an
+                * intermediate buffer.
+                */
+               coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0), CODA_CMD_ENC_HEADER_BB_START);
+               coda_write(dev, bitstream_size, CODA_CMD_ENC_HEADER_BB_SIZE);
+               coda_write(dev, CODA_HEADER_H264_SPS, CODA_CMD_ENC_HEADER_CODE);
+               if (coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER)) {
+                       v4l2_err(v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n");
+                       return -ETIMEDOUT;
+               }
+               ctx->vpu_header_size[0] = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx)) -
+                               coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
+               memcpy(&ctx->vpu_header[0][0], vb2_plane_vaddr(buf, 0),
+                      ctx->vpu_header_size[0]);
+
+               /*
+                * Get PPS in the first frame and copy it to an
+                * intermediate buffer.
+                */
+               coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0), CODA_CMD_ENC_HEADER_BB_START);
+               coda_write(dev, bitstream_size, CODA_CMD_ENC_HEADER_BB_SIZE);
+               coda_write(dev, CODA_HEADER_H264_PPS, CODA_CMD_ENC_HEADER_CODE);
+               if (coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER)) {
+                       v4l2_err(v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n");
+                       return -ETIMEDOUT;
+               }
+               ctx->vpu_header_size[1] = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx)) -
+                               coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
+               memcpy(&ctx->vpu_header[1][0], vb2_plane_vaddr(buf, 0),
+                      ctx->vpu_header_size[1]);
+               ctx->vpu_header_size[2] = 0;
+               break;
+       case V4L2_PIX_FMT_MPEG4:
+               /*
+                * Get VOS in the first frame and copy it to an
+                * intermediate buffer
+                */
+               coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0), CODA_CMD_ENC_HEADER_BB_START);
+               coda_write(dev, bitstream_size, CODA_CMD_ENC_HEADER_BB_SIZE);
+               coda_write(dev, CODA_HEADER_MP4V_VOS, CODA_CMD_ENC_HEADER_CODE);
+               if (coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER)) {
+                       v4l2_err(v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n");
+                       return -ETIMEDOUT;
+               }
+               ctx->vpu_header_size[0] = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx)) -
+                               coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
+               memcpy(&ctx->vpu_header[0][0], vb2_plane_vaddr(buf, 0),
+                      ctx->vpu_header_size[0]);
+
+               coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0), CODA_CMD_ENC_HEADER_BB_START);
+               coda_write(dev, bitstream_size, CODA_CMD_ENC_HEADER_BB_SIZE);
+               coda_write(dev, CODA_HEADER_MP4V_VIS, CODA_CMD_ENC_HEADER_CODE);
+               if (coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER)) {
+                       v4l2_err(v4l2_dev, "CODA_COMMAND_ENCODE_HEADER failed\n");
+                       return -ETIMEDOUT;
+               }
+               ctx->vpu_header_size[1] = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx)) -
+                               coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
+               memcpy(&ctx->vpu_header[1][0], vb2_plane_vaddr(buf, 0),
+                      ctx->vpu_header_size[1]);
+
+               coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0), CODA_CMD_ENC_HEADER_BB_START);
+               coda_write(dev, bitstream_size, CODA_CMD_ENC_HEADER_BB_SIZE);
+               coda_write(dev, CODA_HEADER_MP4V_VOL, CODA_CMD_ENC_HEADER_CODE);
+               if (coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER)) {
+                       v4l2_err(v4l2_dev, "CODA_COMMAND_ENCODE_HEADER failed\n");
+                       return -ETIMEDOUT;
+               }
+               ctx->vpu_header_size[2] = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx)) -
+                               coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
+               memcpy(&ctx->vpu_header[2][0], vb2_plane_vaddr(buf, 0),
+                      ctx->vpu_header_size[2]);
+               break;
+       default:
+               /* No more formats need to save headers at the moment */
+               break;
+       }
+
+       return 0;
+}
+
+static int coda_stop_streaming(struct vb2_queue *q)
+{
+       struct coda_ctx *ctx = vb2_get_drv_priv(q);
+
+       if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                        "%s: output\n", __func__);
+               ctx->rawstreamon = 0;
+       } else {
+               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                        "%s: capture\n", __func__);
+               ctx->compstreamon = 0;
+       }
+
+       if (!ctx->rawstreamon && !ctx->compstreamon) {
+               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                        "%s: sent command 'SEQ_END' to coda\n", __func__);
+               if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) {
+                       v4l2_err(&ctx->dev->v4l2_dev,
+                                "CODA_COMMAND_SEQ_END failed\n");
+                       return -ETIMEDOUT;
+               }
+       }
+
+       return 0;
+}
+
+static struct vb2_ops coda_qops = {
+       .queue_setup            = coda_queue_setup,
+       .buf_prepare            = coda_buf_prepare,
+       .buf_queue              = coda_buf_queue,
+       .wait_prepare           = coda_wait_prepare,
+       .wait_finish            = coda_wait_finish,
+       .start_streaming        = coda_start_streaming,
+       .stop_streaming         = coda_stop_streaming,
+};
+
+static int coda_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct coda_ctx *ctx =
+                       container_of(ctrl->handler, struct coda_ctx, ctrls);
+
+       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                "s_ctrl: id = %d, val = %d\n", ctrl->id, ctrl->val);
+
+       switch (ctrl->id) {
+       case V4L2_CID_MPEG_VIDEO_BITRATE:
+               ctx->params.bitrate = ctrl->val / 1000;
+               break;
+       case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+               ctx->params.gop_size = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
+               ctx->params.h264_intra_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
+               ctx->params.h264_inter_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP:
+               ctx->params.mpeg4_intra_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP:
+               ctx->params.mpeg4_inter_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
+               ctx->params.slice_mode = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB:
+               ctx->params.slice_max_mb = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
+               break;
+       default:
+               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                       "Invalid control, id=%d, val=%d\n",
+                       ctrl->id, ctrl->val);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static struct v4l2_ctrl_ops coda_ctrl_ops = {
+       .s_ctrl = coda_s_ctrl,
+};
+
+static int coda_ctrls_setup(struct coda_ctx *ctx)
+{
+       v4l2_ctrl_handler_init(&ctx->ctrls, 9);
+
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_BITRATE, 0, 32767000, 1, 0);
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 60, 1, 16);
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, 1, 51, 1, 25);
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, 1, 51, 1, 25);
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP, 1, 31, 1, 2);
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP, 1, 31, 1, 2);
+       v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE,
+               V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB, 0,
+               V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB);
+       v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, 1, 0x3fffffff, 1, 1);
+       v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
+               V4L2_CID_MPEG_VIDEO_HEADER_MODE,
+               V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME,
+               (1 << V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE),
+               V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME);
+
+       if (ctx->ctrls.error) {
+               v4l2_err(&ctx->dev->v4l2_dev, "control initialization error (%d)",
+                       ctx->ctrls.error);
+               return -EINVAL;
+       }
+
+       return v4l2_ctrl_handler_setup(&ctx->ctrls);
+}
+
+static int coda_queue_init(void *priv, struct vb2_queue *src_vq,
+                     struct vb2_queue *dst_vq)
+{
+       struct coda_ctx *ctx = priv;
+       int ret;
+
+       memset(src_vq, 0, sizeof(*src_vq));
+       src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+       src_vq->io_modes = VB2_MMAP;
+       src_vq->drv_priv = ctx;
+       src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+       src_vq->ops = &coda_qops;
+       src_vq->mem_ops = &vb2_dma_contig_memops;
+
+       ret = vb2_queue_init(src_vq);
+       if (ret)
+               return ret;
+
+       memset(dst_vq, 0, sizeof(*dst_vq));
+       dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       dst_vq->io_modes = VB2_MMAP;
+       dst_vq->drv_priv = ctx;
+       dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+       dst_vq->ops = &coda_qops;
+       dst_vq->mem_ops = &vb2_dma_contig_memops;
+
+       return vb2_queue_init(dst_vq);
+}
+
+static int coda_open(struct file *file)
+{
+       struct coda_dev *dev = video_drvdata(file);
+       struct coda_ctx *ctx = NULL;
+       int ret = 0;
+
+       if (dev->instances >= CODA_MAX_INSTANCES)
+               return -EBUSY;
+
+       ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+
+       v4l2_fh_init(&ctx->fh, video_devdata(file));
+       file->private_data = &ctx->fh;
+       v4l2_fh_add(&ctx->fh);
+       ctx->dev = dev;
+
+       set_default_params(ctx);
+       ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx,
+                                        &coda_queue_init);
+       if (IS_ERR(ctx->m2m_ctx)) {
+               int ret = PTR_ERR(ctx->m2m_ctx);
+
+               v4l2_err(&dev->v4l2_dev, "%s return error (%d)\n",
+                        __func__, ret);
+               goto err;
+       }
+       ret = coda_ctrls_setup(ctx);
+       if (ret) {
+               v4l2_err(&dev->v4l2_dev, "failed to setup coda controls\n");
+               goto err;
+       }
+
+       ctx->fh.ctrl_handler = &ctx->ctrls;
+
+       ctx->parabuf.vaddr = dma_alloc_coherent(&dev->plat_dev->dev,
+                       CODA_PARA_BUF_SIZE, &ctx->parabuf.paddr, GFP_KERNEL);
+       if (!ctx->parabuf.vaddr) {
+               v4l2_err(&dev->v4l2_dev, "failed to allocate parabuf");
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       coda_lock(ctx);
+       ctx->idx = dev->instances++;
+       coda_unlock(ctx);
+
+       clk_prepare_enable(dev->clk_per);
+       clk_prepare_enable(dev->clk_ahb);
+
+       v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Created instance %d (%p)\n",
+                ctx->idx, ctx);
+
+       return 0;
+
+err:
+       v4l2_fh_del(&ctx->fh);
+       v4l2_fh_exit(&ctx->fh);
+       kfree(ctx);
+       return ret;
+}
+
+static int coda_release(struct file *file)
+{
+       struct coda_dev *dev = video_drvdata(file);
+       struct coda_ctx *ctx = fh_to_ctx(file->private_data);
+
+       v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Releasing instance %p\n",
+                ctx);
+
+       coda_lock(ctx);
+       dev->instances--;
+       coda_unlock(ctx);
+
+       dma_free_coherent(&dev->plat_dev->dev, CODA_PARA_BUF_SIZE,
+               ctx->parabuf.vaddr, ctx->parabuf.paddr);
+       v4l2_m2m_ctx_release(ctx->m2m_ctx);
+       v4l2_ctrl_handler_free(&ctx->ctrls);
+       clk_disable_unprepare(dev->clk_per);
+       clk_disable_unprepare(dev->clk_ahb);
+       v4l2_fh_del(&ctx->fh);
+       v4l2_fh_exit(&ctx->fh);
+       kfree(ctx);
+
+       return 0;
+}
+
+static unsigned int coda_poll(struct file *file,
+                                struct poll_table_struct *wait)
+{
+       struct coda_ctx *ctx = fh_to_ctx(file->private_data);
+       int ret;
+
+       coda_lock(ctx);
+       ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+       coda_unlock(ctx);
+       return ret;
+}
+
+static int coda_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct coda_ctx *ctx = fh_to_ctx(file->private_data);
+
+       return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+}
+
+static const struct v4l2_file_operations coda_fops = {
+       .owner          = THIS_MODULE,
+       .open           = coda_open,
+       .release        = coda_release,
+       .poll           = coda_poll,
+       .unlocked_ioctl = video_ioctl2,
+       .mmap           = coda_mmap,
+};
+
+static irqreturn_t coda_irq_handler(int irq, void *data)
+{
+       struct vb2_buffer *src_buf, *dst_buf, *tmp_buf;
+       struct coda_dev *dev = data;
+       u32 wr_ptr, start_ptr;
+       struct coda_ctx *ctx;
+
+       /* read status register to attend the IRQ */
+       coda_read(dev, CODA_REG_BIT_INT_STATUS);
+       coda_write(dev, CODA_REG_BIT_INT_CLEAR_SET,
+                     CODA_REG_BIT_INT_CLEAR);
+
+       ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
+       if (ctx == NULL) {
+               v4l2_err(&dev->v4l2_dev, "Instance released before the end of transaction\n");
+               return IRQ_HANDLED;
+       }
+
+       if (ctx->aborting) {
+               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                        "task has been aborted\n");
+               return IRQ_HANDLED;
+       }
+
+       if (coda_isbusy(ctx->dev)) {
+               v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+                        "coda is still busy!!!!\n");
+               return IRQ_NONE;
+       }
+
+       src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+       dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+
+       /* Get results from the coda */
+       coda_read(dev, CODA_RET_ENC_PIC_TYPE);
+       start_ptr = coda_read(dev, CODA_CMD_ENC_PIC_BB_START);
+       wr_ptr = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx));
+       /* Calculate bytesused field */
+       if (dst_buf->v4l2_buf.sequence == 0) {
+               dst_buf->v4l2_planes[0].bytesused = (wr_ptr - start_ptr) +
+                                               ctx->vpu_header_size[0] +
+                                               ctx->vpu_header_size[1] +
+                                               ctx->vpu_header_size[2];
+       } else {
+               dst_buf->v4l2_planes[0].bytesused = (wr_ptr - start_ptr);
+       }
+
+       v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "frame size = %u\n",
+                wr_ptr - start_ptr);
+
+       coda_read(dev, CODA_RET_ENC_PIC_SLICE_NUM);
+       coda_read(dev, CODA_RET_ENC_PIC_FLAG);
+
+       if (src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) {
+               dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
+               dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME;
+       } else {
+               dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
+               dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME;
+       }
+
+       /* Free previous reference picture if available */
+       if (ctx->reference) {
+               v4l2_m2m_buf_done(ctx->reference, VB2_BUF_STATE_DONE);
+               ctx->reference = NULL;
+       }
+
+       /*
+        * For the last frame of the gop we don't need to save
+        * a reference picture.
+        */
+       v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+       tmp_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+       if (ctx->gopcounter == 0)
+               v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
+       else
+               ctx->reference = tmp_buf;
+
+       v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
+
+       ctx->gopcounter--;
+       if (ctx->gopcounter < 0)
+               ctx->gopcounter = ctx->params.gop_size - 1;
+
+       v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+               "job finished: encoding frame (%d) (%s)\n",
+               dst_buf->v4l2_buf.sequence,
+               (dst_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) ?
+               "KEYFRAME" : "PFRAME");
+
+       v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->m2m_ctx);
+
+       return IRQ_HANDLED;
+}
+
+static u32 coda_supported_firmwares[] = {
+       CODA_FIRMWARE_VERNUM(CODA_DX6, 2, 2, 5),
+};
+
+static bool coda_firmware_supported(u32 vernum)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(coda_supported_firmwares); i++)
+               if (vernum == coda_supported_firmwares[i])
+                       return true;
+       return false;
+}
+
+static char *coda_product_name(int product)
+{
+       static char buf[9];
+
+       switch (product) {
+       case CODA_DX6:
+               return "CodaDx6";
+       default:
+               snprintf(buf, sizeof(buf), "(0x%04x)", product);
+               return buf;
+       }
+}
+
+static int coda_hw_init(struct coda_dev *dev, const struct firmware *fw)
+{
+       u16 product, major, minor, release;
+       u32 data;
+       u16 *p;
+       int i;
+
+       clk_prepare_enable(dev->clk_per);
+       clk_prepare_enable(dev->clk_ahb);
+
+       /* Copy the whole firmware image to the code buffer */
+       memcpy(dev->codebuf.vaddr, fw->data, fw->size);
+       /*
+        * Copy the first CODA_ISRAM_SIZE in the internal SRAM.
+        * This memory seems to be big-endian here, which is weird, since
+        * the internal ARM processor of the coda is little endian.
+        * Data in this SRAM survives a reboot.
+        */
+       p = (u16 *)fw->data;
+       for (i = 0; i < (CODA_ISRAM_SIZE / 2); i++)  {
+               data = CODA_DOWN_ADDRESS_SET(i) |
+                       CODA_DOWN_DATA_SET(p[i ^ 1]);
+               coda_write(dev, data, CODA_REG_BIT_CODE_DOWN);
+       }
+       release_firmware(fw);
+
+       /* Tell the BIT where to find everything it needs */
+       coda_write(dev, dev->workbuf.paddr,
+                     CODA_REG_BIT_WORK_BUF_ADDR);
+       coda_write(dev, dev->codebuf.paddr,
+                     CODA_REG_BIT_CODE_BUF_ADDR);
+       coda_write(dev, 0, CODA_REG_BIT_CODE_RUN);
+
+       /* Set default values */
+       switch (dev->devtype->product) {
+       case CODA_DX6:
+               coda_write(dev, CODADX6_STREAM_BUF_PIC_FLUSH, CODA_REG_BIT_STREAM_CTRL);
+               break;
+       default:
+               coda_write(dev, CODA7_STREAM_BUF_PIC_FLUSH, CODA_REG_BIT_STREAM_CTRL);
+       }
+       coda_write(dev, 0, CODA_REG_BIT_FRAME_MEM_CTRL);
+       coda_write(dev, CODA_INT_INTERRUPT_ENABLE,
+                     CODA_REG_BIT_INT_ENABLE);
+
+       /* Reset VPU and start processor */
+       data = coda_read(dev, CODA_REG_BIT_CODE_RESET);
+       data |= CODA_REG_RESET_ENABLE;
+       coda_write(dev, data, CODA_REG_BIT_CODE_RESET);
+       udelay(10);
+       data &= ~CODA_REG_RESET_ENABLE;
+       coda_write(dev, data, CODA_REG_BIT_CODE_RESET);
+       coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN);
+
+       /* Load firmware */
+       coda_write(dev, 0, CODA_CMD_FIRMWARE_VERNUM);
+       coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY);
+       coda_write(dev, 0, CODA_REG_BIT_RUN_INDEX);
+       coda_write(dev, 0, CODA_REG_BIT_RUN_COD_STD);
+       coda_write(dev, CODA_COMMAND_FIRMWARE_GET, CODA_REG_BIT_RUN_COMMAND);
+       if (coda_wait_timeout(dev)) {
+               clk_disable_unprepare(dev->clk_per);
+               clk_disable_unprepare(dev->clk_ahb);
+               v4l2_err(&dev->v4l2_dev, "firmware get command error\n");
+               return -EIO;
+       }
+
+       /* Check we are compatible with the loaded firmware */
+       data = coda_read(dev, CODA_CMD_FIRMWARE_VERNUM);
+       product = CODA_FIRMWARE_PRODUCT(data);
+       major = CODA_FIRMWARE_MAJOR(data);
+       minor = CODA_FIRMWARE_MINOR(data);
+       release = CODA_FIRMWARE_RELEASE(data);
+
+       clk_disable_unprepare(dev->clk_per);
+       clk_disable_unprepare(dev->clk_ahb);
+
+       if (product != dev->devtype->product) {
+               v4l2_err(&dev->v4l2_dev, "Wrong firmware. Hw: %s, Fw: %s,"
+                        " Version: %u.%u.%u\n",
+                        coda_product_name(dev->devtype->product),
+                        coda_product_name(product), major, minor, release);
+               return -EINVAL;
+       }
+
+       v4l2_info(&dev->v4l2_dev, "Initialized %s.\n",
+                 coda_product_name(product));
+
+       if (coda_firmware_supported(data)) {
+               v4l2_info(&dev->v4l2_dev, "Firmware version: %u.%u.%u\n",
+                         major, minor, release);
+       } else {
+               v4l2_warn(&dev->v4l2_dev, "Unsupported firmware version: "
+                         "%u.%u.%u\n", major, minor, release);
+       }
+
+       return 0;
+}
+
+static void coda_fw_callback(const struct firmware *fw, void *context)
+{
+       struct coda_dev *dev = context;
+       struct platform_device *pdev = dev->plat_dev;
+       int ret;
+
+       if (!fw) {
+               v4l2_err(&dev->v4l2_dev, "firmware request failed\n");
+               return;
+       }
+
+       /* allocate auxiliary per-device code buffer for the BIT processor */
+       dev->codebuf.size = fw->size;
+       dev->codebuf.vaddr = dma_alloc_coherent(&pdev->dev, fw->size,
+                                                   &dev->codebuf.paddr,
+                                                   GFP_KERNEL);
+       if (!dev->codebuf.vaddr) {
+               dev_err(&pdev->dev, "failed to allocate code buffer\n");
+               return;
+       }
+
+       ret = coda_hw_init(dev, fw);
+       if (ret) {
+               v4l2_err(&dev->v4l2_dev, "HW initialization failed\n");
+               return;
+       }
+
+       dev->vfd.fops   = &coda_fops,
+       dev->vfd.ioctl_ops      = &coda_ioctl_ops;
+       dev->vfd.release        = video_device_release_empty,
+       dev->vfd.lock   = &dev->dev_mutex;
+       dev->vfd.v4l2_dev       = &dev->v4l2_dev;
+       snprintf(dev->vfd.name, sizeof(dev->vfd.name), "%s", CODA_NAME);
+       video_set_drvdata(&dev->vfd, dev);
+
+       dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+       if (IS_ERR(dev->alloc_ctx)) {
+               v4l2_err(&dev->v4l2_dev, "Failed to alloc vb2 context\n");
+               return;
+       }
+
+       dev->m2m_dev = v4l2_m2m_init(&coda_m2m_ops);
+       if (IS_ERR(dev->m2m_dev)) {
+               v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n");
+               goto rel_ctx;
+       }
+
+       ret = video_register_device(&dev->vfd, VFL_TYPE_GRABBER, 0);
+       if (ret) {
+               v4l2_err(&dev->v4l2_dev, "Failed to register video device\n");
+               goto rel_m2m;
+       }
+       v4l2_info(&dev->v4l2_dev, "codec registered as /dev/video%d\n",
+                 dev->vfd.num);
+
+       return;
+
+rel_m2m:
+       v4l2_m2m_release(dev->m2m_dev);
+rel_ctx:
+       vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
+}
+
+static int coda_firmware_request(struct coda_dev *dev)
+{
+       char *fw = dev->devtype->firmware;
+
+       dev_dbg(&dev->plat_dev->dev, "requesting firmware '%s' for %s\n", fw,
+               coda_product_name(dev->devtype->product));
+
+       return request_firmware_nowait(THIS_MODULE, true,
+               fw, &dev->plat_dev->dev, GFP_KERNEL, dev, coda_fw_callback);
+}
+
+enum coda_platform {
+       CODA_IMX27,
+};
+
+static struct coda_devtype coda_devdata[] = {
+       [CODA_IMX27] = {
+               .firmware    = "v4l-codadx6-imx27.bin",
+               .product     = CODA_DX6,
+               .formats     = codadx6_formats,
+               .num_formats = ARRAY_SIZE(codadx6_formats),
+       },
+};
+
+static struct platform_device_id coda_platform_ids[] = {
+       { .name = "coda-imx27", .driver_data = CODA_IMX27 },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, coda_platform_ids);
+
+#ifdef CONFIG_OF
+static const struct of_device_id coda_dt_ids[] = {
+       { .compatible = "fsl,imx27-vpu", .data = &coda_platform_ids[CODA_IMX27] },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, coda_dt_ids);
+#endif
+
+static int __devinit coda_probe(struct platform_device *pdev)
+{
+       const struct of_device_id *of_id =
+                       of_match_device(of_match_ptr(coda_dt_ids), &pdev->dev);
+       const struct platform_device_id *pdev_id;
+       struct coda_dev *dev;
+       struct resource *res;
+       int ret, irq;
+
+       dev = devm_kzalloc(&pdev->dev, sizeof *dev, GFP_KERNEL);
+       if (!dev) {
+               dev_err(&pdev->dev, "Not enough memory for %s\n",
+                       CODA_NAME);
+               return -ENOMEM;
+       }
+
+       spin_lock_init(&dev->irqlock);
+
+       dev->plat_dev = pdev;
+       dev->clk_per = devm_clk_get(&pdev->dev, "per");
+       if (IS_ERR(dev->clk_per)) {
+               dev_err(&pdev->dev, "Could not get per clock\n");
+               return PTR_ERR(dev->clk_per);
+       }
+
+       dev->clk_ahb = devm_clk_get(&pdev->dev, "ahb");
+       if (IS_ERR(dev->clk_ahb)) {
+               dev_err(&pdev->dev, "Could not get ahb clock\n");
+               return PTR_ERR(dev->clk_ahb);
+       }
+
+       /* Get  memory for physical registers */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(&pdev->dev, "failed to get memory region resource\n");
+               return -ENOENT;
+       }
+
+       if (devm_request_mem_region(&pdev->dev, res->start,
+                       resource_size(res), CODA_NAME) == NULL) {
+               dev_err(&pdev->dev, "failed to request memory region\n");
+               return -ENOENT;
+       }
+       dev->regs_base = devm_ioremap(&pdev->dev, res->start,
+                                     resource_size(res));
+       if (!dev->regs_base) {
+               dev_err(&pdev->dev, "failed to ioremap address region\n");
+               return -ENOENT;
+       }
+
+       /* IRQ */
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "failed to get irq resource\n");
+               return -ENOENT;
+       }
+
+       if (devm_request_irq(&pdev->dev, irq, coda_irq_handler,
+               0, CODA_NAME, dev) < 0) {
+               dev_err(&pdev->dev, "failed to request irq\n");
+               return -ENOENT;
+       }
+
+       ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+       if (ret)
+               return ret;
+
+       mutex_init(&dev->dev_mutex);
+
+       pdev_id = of_id ? of_id->data : platform_get_device_id(pdev);
+
+       if (of_id) {
+               dev->devtype = of_id->data;
+       } else if (pdev_id) {
+               dev->devtype = &coda_devdata[pdev_id->driver_data];
+       } else {
+               v4l2_device_unregister(&dev->v4l2_dev);
+               return -EINVAL;
+       }
+
+       /* allocate auxiliary per-device buffers for the BIT processor */
+       switch (dev->devtype->product) {
+       case CODA_DX6:
+               dev->workbuf.size = CODADX6_WORK_BUF_SIZE;
+               break;
+       default:
+               dev->workbuf.size = CODA7_WORK_BUF_SIZE;
+       }
+       dev->workbuf.vaddr = dma_alloc_coherent(&pdev->dev, dev->workbuf.size,
+                                                   &dev->workbuf.paddr,
+                                                   GFP_KERNEL);
+       if (!dev->workbuf.vaddr) {
+               dev_err(&pdev->dev, "failed to allocate work buffer\n");
+               v4l2_device_unregister(&dev->v4l2_dev);
+               return -ENOMEM;
+       }
+
+       platform_set_drvdata(pdev, dev);
+
+       return coda_firmware_request(dev);
+}
+
+static int coda_remove(struct platform_device *pdev)
+{
+       struct coda_dev *dev = platform_get_drvdata(pdev);
+
+       video_unregister_device(&dev->vfd);
+       if (dev->m2m_dev)
+               v4l2_m2m_release(dev->m2m_dev);
+       if (dev->alloc_ctx)
+               vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
+       v4l2_device_unregister(&dev->v4l2_dev);
+       if (dev->codebuf.vaddr)
+               dma_free_coherent(&pdev->dev, dev->codebuf.size,
+                                 &dev->codebuf.vaddr, dev->codebuf.paddr);
+       if (dev->workbuf.vaddr)
+               dma_free_coherent(&pdev->dev, dev->workbuf.size, &dev->workbuf.vaddr,
+                         dev->workbuf.paddr);
+       return 0;
+}
+
+static struct platform_driver coda_driver = {
+       .probe  = coda_probe,
+       .remove = __devexit_p(coda_remove),
+       .driver = {
+               .name   = CODA_NAME,
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(coda_dt_ids),
+       },
+       .id_table = coda_platform_ids,
+};
+
+module_platform_driver(coda_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>");
+MODULE_DESCRIPTION("Coda multi-standard codec V4L2 driver");
diff --git a/drivers/media/video/coda.h b/drivers/media/video/coda.h
new file mode 100644 (file)
index 0000000..4cf4a04
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * linux/drivers/media/video/coda/coda_regs.h
+ *
+ * Copyright (C) 2012 Vista Silicon SL
+ *    Javier Martin <javier.martin@vista-silicon.com>
+ *    Xavier Duret
+ *
+ * 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 _REGS_CODA_H_
+#define _REGS_CODA_H_
+
+/* HW registers */
+#define CODA_REG_BIT_CODE_RUN                  0x000
+#define                CODA_REG_RUN_ENABLE             (1 << 0)
+#define CODA_REG_BIT_CODE_DOWN                 0x004
+#define                CODA_DOWN_ADDRESS_SET(x)        (((x) & 0xffff) << 16)
+#define                CODA_DOWN_DATA_SET(x)           ((x) & 0xffff)
+#define CODA_REG_BIT_HOST_IN_REQ               0x008
+#define CODA_REG_BIT_INT_CLEAR                 0x00c
+#define                CODA_REG_BIT_INT_CLEAR_SET      0x1
+#define CODA_REG_BIT_INT_STATUS                0x010
+#define CODA_REG_BIT_CODE_RESET                0x014
+#define                CODA_REG_RESET_ENABLE           (1 << 0)
+#define CODA_REG_BIT_CUR_PC                    0x018
+
+/* Static SW registers */
+#define CODA_REG_BIT_CODE_BUF_ADDR             0x100
+#define CODA_REG_BIT_WORK_BUF_ADDR             0x104
+#define CODA_REG_BIT_PARA_BUF_ADDR             0x108
+#define CODA_REG_BIT_STREAM_CTRL               0x10c
+#define                CODA7_STREAM_BUF_PIC_RESET      (1 << 4)
+#define                CODADX6_STREAM_BUF_PIC_RESET    (1 << 3)
+#define                CODA7_STREAM_BUF_PIC_FLUSH      (1 << 3)
+#define                CODADX6_STREAM_BUF_PIC_FLUSH    (1 << 2)
+#define                CODA7_STREAM_BUF_DYNALLOC_EN    (1 << 5)
+#define                CODADX6_STREAM_BUF_DYNALLOC_EN  (1 << 4)
+#define        CODA_STREAM_CHKDIS_OFFSET       (1 << 1)
+#define                CODA_STREAM_ENDIAN_SELECT       (1 << 0)
+#define CODA_REG_BIT_FRAME_MEM_CTRL            0x110
+#define                CODA_IMAGE_ENDIAN_SELECT        (1 << 0)
+#define CODA_REG_BIT_RD_PTR(x)                 (0x120 + 8 * (x))
+#define CODA_REG_BIT_WR_PTR(x)                 (0x124 + 8 * (x))
+#define CODA_REG_BIT_SEARCH_RAM_BASE_ADDR      0x140
+#define CODA_REG_BIT_BUSY                      0x160
+#define                CODA_REG_BIT_BUSY_FLAG          1
+#define CODA_REG_BIT_RUN_COMMAND               0x164
+#define                CODA_COMMAND_SEQ_INIT           1
+#define                CODA_COMMAND_SEQ_END            2
+#define                CODA_COMMAND_PIC_RUN            3
+#define                CODA_COMMAND_SET_FRAME_BUF      4
+#define                CODA_COMMAND_ENCODE_HEADER      5
+#define                CODA_COMMAND_ENC_PARA_SET       6
+#define                CODA_COMMAND_DEC_PARA_SET       7
+#define                CODA_COMMAND_DEC_BUF_FLUSH      8
+#define                CODA_COMMAND_RC_CHANGE_PARAMETER 9
+#define                CODA_COMMAND_FIRMWARE_GET       0xf
+#define CODA_REG_BIT_RUN_INDEX                 0x168
+#define                CODA_INDEX_SET(x)               ((x) & 0x3)
+#define CODA_REG_BIT_RUN_COD_STD               0x16c
+#define                CODADX6_MODE_DECODE_MP4         0
+#define                CODADX6_MODE_ENCODE_MP4         1
+#define                CODADX6_MODE_DECODE_H264        2
+#define                CODADX6_MODE_ENCODE_H264        3
+#define                CODA7_MODE_DECODE_H264          0
+#define                CODA7_MODE_DECODE_VC1           1
+#define                CODA7_MODE_DECODE_MP2           2
+#define                CODA7_MODE_DECODE_MP4           3
+#define                CODA7_MODE_DECODE_DV3           3
+#define                CODA7_MODE_DECODE_RV            4
+#define                CODA7_MODE_DECODE_MJPG          5
+#define                CODA7_MODE_ENCODE_H264          8
+#define                CODA7_MODE_ENCODE_MP4           11
+#define                CODA7_MODE_ENCODE_MJPG          13
+#define        CODA_MODE_INVALID               0xffff
+#define CODA_REG_BIT_INT_ENABLE                0x170
+#define                CODA_INT_INTERRUPT_ENABLE       (1 << 3)
+
+/*
+ * Commands' mailbox:
+ * registers with offsets in the range 0x180-0x1d0
+ * have different meaning depending on the command being
+ * issued.
+ */
+
+/* Encoder Sequence Initialization */
+#define CODA_CMD_ENC_SEQ_BB_START                              0x180
+#define CODA_CMD_ENC_SEQ_BB_SIZE                               0x184
+#define CODA_CMD_ENC_SEQ_OPTION                                0x188
+#define                CODA_OPTION_GAMMA_OFFSET                        7
+#define                CODA_OPTION_GAMMA_MASK                          0x01
+#define                CODA_OPTION_LIMITQP_OFFSET                      6
+#define                CODA_OPTION_LIMITQP_MASK                        0x01
+#define                CODA_OPTION_RCINTRAQP_OFFSET                    5
+#define                CODA_OPTION_RCINTRAQP_MASK                      0x01
+#define                CODA_OPTION_FMO_OFFSET                          4
+#define                CODA_OPTION_FMO_MASK                            0x01
+#define                CODA_OPTION_SLICEREPORT_OFFSET                  1
+#define                CODA_OPTION_SLICEREPORT_MASK                    0x01
+#define CODA_CMD_ENC_SEQ_COD_STD                               0x18c
+#define                CODA_STD_MPEG4                                  0
+#define                CODA_STD_H263                                   1
+#define                CODA_STD_H264                                   2
+#define                CODA_STD_MJPG                                   3
+#define CODA_CMD_ENC_SEQ_SRC_SIZE                              0x190
+#define                CODA7_PICWIDTH_OFFSET                           16
+#define                CODA7_PICWIDTH_MASK                             0xffff
+#define                CODADX6_PICWIDTH_OFFSET                         10
+#define                CODADX6_PICWIDTH_MASK                           0x3ff
+#define                CODA_PICHEIGHT_OFFSET                           0
+#define                CODA_PICHEIGHT_MASK                             0x3ff
+#define CODA_CMD_ENC_SEQ_SRC_F_RATE                            0x194
+#define CODA_CMD_ENC_SEQ_MP4_PARA                              0x198
+#define                CODA_MP4PARAM_VERID_OFFSET                      6
+#define                CODA_MP4PARAM_VERID_MASK                        0x01
+#define                CODA_MP4PARAM_INTRADCVLCTHR_OFFSET              2
+#define                CODA_MP4PARAM_INTRADCVLCTHR_MASK                0x07
+#define                CODA_MP4PARAM_REVERSIBLEVLCENABLE_OFFSET        1
+#define                CODA_MP4PARAM_REVERSIBLEVLCENABLE_MASK          0x01
+#define                CODA_MP4PARAM_DATAPARTITIONENABLE_OFFSET        0
+#define                CODA_MP4PARAM_DATAPARTITIONENABLE_MASK          0x01
+#define CODA_CMD_ENC_SEQ_263_PARA                              0x19c
+#define                CODA_263PARAM_ANNEXJENABLE_OFFSET               2
+#define                CODA_263PARAM_ANNEXJENABLE_MASK         0x01
+#define                CODA_263PARAM_ANNEXKENABLE_OFFSET               1
+#define                CODA_263PARAM_ANNEXKENABLE_MASK         0x01
+#define                CODA_263PARAM_ANNEXTENABLE_OFFSET               0
+#define                CODA_263PARAM_ANNEXTENABLE_MASK         0x01
+#define CODA_CMD_ENC_SEQ_264_PARA                              0x1a0
+#define                CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET      12
+#define                CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK        0x0f
+#define                CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET     8
+#define                CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK       0x0f
+#define                CODA_264PARAM_DISABLEDEBLK_OFFSET               6
+#define                CODA_264PARAM_DISABLEDEBLK_MASK         0x01
+#define                CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_OFFSET   5
+#define                CODA_264PARAM_CONSTRAINEDINTRAPREDFLAG_MASK     0x01
+#define                CODA_264PARAM_CHROMAQPOFFSET_OFFSET             0
+#define                CODA_264PARAM_CHROMAQPOFFSET_MASK               0x1f
+#define CODA_CMD_ENC_SEQ_SLICE_MODE                            0x1a4
+#define                CODA_SLICING_SIZE_OFFSET                        2
+#define                CODA_SLICING_SIZE_MASK                          0x3fffffff
+#define                CODA_SLICING_UNIT_OFFSET                        1
+#define                CODA_SLICING_UNIT_MASK                          0x01
+#define                CODA_SLICING_MODE_OFFSET                        0
+#define                CODA_SLICING_MODE_MASK                          0x01
+#define CODA_CMD_ENC_SEQ_GOP_SIZE                              0x1a8
+#define                CODA_GOP_SIZE_OFFSET                            0
+#define                CODA_GOP_SIZE_MASK                              0x3f
+#define CODA_CMD_ENC_SEQ_RC_PARA                               0x1ac
+#define                CODA_RATECONTROL_AUTOSKIP_OFFSET                31
+#define                CODA_RATECONTROL_AUTOSKIP_MASK                  0x01
+#define                CODA_RATECONTROL_INITIALDELAY_OFFSET            16
+#define                CODA_RATECONTROL_INITIALDELAY_MASK              0x7f
+#define                CODA_RATECONTROL_BITRATE_OFFSET         1
+#define                CODA_RATECONTROL_BITRATE_MASK                   0x7f
+#define                CODA_RATECONTROL_ENABLE_OFFSET                  0
+#define                CODA_RATECONTROL_ENABLE_MASK                    0x01
+#define CODA_CMD_ENC_SEQ_RC_BUF_SIZE                           0x1b0
+#define CODA_CMD_ENC_SEQ_INTRA_REFRESH                         0x1b4
+#define CODA_CMD_ENC_SEQ_FMO                                   0x1b8
+#define                CODA_FMOPARAM_TYPE_OFFSET                       4
+#define                CODA_FMOPARAM_TYPE_MASK                         1
+#define                CODA_FMOPARAM_SLICENUM_OFFSET                   0
+#define                CODA_FMOPARAM_SLICENUM_MASK                     0x0f
+#define CODA_CMD_ENC_SEQ_RC_QP_MAX                             0x1c8
+#define                CODA_QPMAX_OFFSET                               0
+#define                CODA_QPMAX_MASK                                 0x3f
+#define CODA_CMD_ENC_SEQ_RC_GAMMA                              0x1cc
+#define                CODA_GAMMA_OFFSET                               0
+#define                CODA_GAMMA_MASK                                 0xffff
+#define CODA_RET_ENC_SEQ_SUCCESS                               0x1c0
+
+/* Encoder Picture Run */
+#define CODA_CMD_ENC_PIC_SRC_ADDR_Y    0x180
+#define CODA_CMD_ENC_PIC_SRC_ADDR_CB   0x184
+#define CODA_CMD_ENC_PIC_SRC_ADDR_CR   0x188
+#define CODA_CMD_ENC_PIC_QS            0x18c
+#define CODA_CMD_ENC_PIC_ROT_MODE      0x190
+#define CODA_CMD_ENC_PIC_OPTION        0x194
+#define CODA_CMD_ENC_PIC_BB_START      0x198
+#define CODA_CMD_ENC_PIC_BB_SIZE       0x19c
+#define CODA_RET_ENC_PIC_TYPE          0x1c4
+#define CODA_RET_ENC_PIC_SLICE_NUM     0x1cc
+#define CODA_RET_ENC_PIC_FLAG          0x1d0
+
+/* Set Frame Buffer */
+#define CODA_CMD_SET_FRAME_BUF_NUM     0x180
+#define CODA_CMD_SET_FRAME_BUF_STRIDE  0x184
+
+/* Encoder Header */
+#define CODA_CMD_ENC_HEADER_CODE       0x180
+#define                CODA_GAMMA_OFFSET       0
+#define                CODA_HEADER_H264_SPS    0
+#define                CODA_HEADER_H264_PPS    1
+#define                CODA_HEADER_MP4V_VOL    0
+#define                CODA_HEADER_MP4V_VOS    1
+#define                CODA_HEADER_MP4V_VIS    2
+#define CODA_CMD_ENC_HEADER_BB_START   0x184
+#define CODA_CMD_ENC_HEADER_BB_SIZE    0x188
+
+/* Get Version */
+#define CODA_CMD_FIRMWARE_VERNUM               0x1c0
+#define                CODA_FIRMWARE_PRODUCT(x)        (((x) >> 16) & 0xffff)
+#define                CODA_FIRMWARE_MAJOR(x)          (((x) >> 12) & 0x0f)
+#define                CODA_FIRMWARE_MINOR(x)          (((x) >> 8) & 0x0f)
+#define                CODA_FIRMWARE_RELEASE(x)        ((x) & 0xff)
+#define                CODA_FIRMWARE_VERNUM(product, major, minor, release)    \
+                       ((product) << 16 | ((major) << 12) |            \
+                       ((minor) << 8) | (release))
+
+#endif
index 17188e234770fa8170502ab25d87959cc9b9c959..187012ce444bd2aef05235335c32e8302b3d3727 100644 (file)
 
 #include "cpia2.h"
 
+#include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/vmalloc.h>
 #include <linux/firmware.h>
 
+#define FIRMWARE "cpia2/stv0672_vp4.bin"
+MODULE_FIRMWARE(FIRMWARE);
+
 /* #define _CPIA2_DEBUG_ */
 
 #ifdef _CPIA2_DEBUG_
@@ -898,7 +902,7 @@ static int cpia2_send_onebyte_command(struct camera_data *cam,
 static int apply_vp_patch(struct camera_data *cam)
 {
        const struct firmware *fw;
-       const char fw_name[] = "cpia2/stv0672_vp4.bin";
+       const char fw_name[] = FIRMWARE;
        int i, ret;
        struct cpia2_command cmd;
 
index a62a7b739991806567231870dc143ceb3cac675a..5ca6f44b4c6327fd2c0edc9b1ee0ed63408b4c6a 100644 (file)
@@ -84,21 +84,26 @@ MODULE_VERSION(CPIA_VERSION);
 static int cpia2_open(struct file *file)
 {
        struct camera_data *cam = video_drvdata(file);
-       int retval = v4l2_fh_open(file);
+       int retval;
 
+       if (mutex_lock_interruptible(&cam->v4l2_lock))
+               return -ERESTARTSYS;
+       retval = v4l2_fh_open(file);
        if (retval)
-               return retval;
+               goto open_unlock;
 
        if (v4l2_fh_is_singular_file(file)) {
                if (cpia2_allocate_buffers(cam)) {
                        v4l2_fh_release(file);
-                       return -ENOMEM;
+                       retval = -ENOMEM;
+                       goto open_unlock;
                }
 
                /* reset the camera */
                if (cpia2_reset_camera(cam) < 0) {
                        v4l2_fh_release(file);
-                       return -EIO;
+                       retval = -EIO;
+                       goto open_unlock;
                }
 
                cam->APP_len = 0;
@@ -106,7 +111,9 @@ static int cpia2_open(struct file *file)
        }
 
        cpia2_dbg_dump_registers(cam);
-       return 0;
+open_unlock:
+       mutex_unlock(&cam->v4l2_lock);
+       return retval;
 }
 
 /******************************************************************************
@@ -119,6 +126,7 @@ static int cpia2_close(struct file *file)
        struct video_device *dev = video_devdata(file);
        struct camera_data *cam = video_get_drvdata(dev);
 
+       mutex_lock(&cam->v4l2_lock);
        if (video_is_registered(&cam->vdev) && v4l2_fh_is_singular_file(file)) {
                cpia2_usb_stream_stop(cam);
 
@@ -133,6 +141,7 @@ static int cpia2_close(struct file *file)
                cam->stream_fh = NULL;
                cam->mmapped = 0;
        }
+       mutex_unlock(&cam->v4l2_lock);
        return v4l2_fh_release(file);
 }
 
@@ -146,11 +155,16 @@ static ssize_t cpia2_v4l_read(struct file *file, char __user *buf, size_t count,
 {
        struct camera_data *cam = video_drvdata(file);
        int noblock = file->f_flags&O_NONBLOCK;
+       ssize_t ret;
 
        if(!cam)
                return -EINVAL;
 
-       return cpia2_read(cam, buf, count, noblock);
+       if (mutex_lock_interruptible(&cam->v4l2_lock))
+               return -ERESTARTSYS;
+       ret = cpia2_read(cam, buf, count, noblock);
+       mutex_unlock(&cam->v4l2_lock);
+       return ret;
 }
 
 
@@ -162,8 +176,12 @@ static ssize_t cpia2_v4l_read(struct file *file, char __user *buf, size_t count,
 static unsigned int cpia2_v4l_poll(struct file *filp, struct poll_table_struct *wait)
 {
        struct camera_data *cam = video_drvdata(filp);
+       unsigned int res;
 
-       return cpia2_poll(cam, filp, wait);
+       mutex_lock(&cam->v4l2_lock);
+       res = cpia2_poll(cam, filp, wait);
+       mutex_unlock(&cam->v4l2_lock);
+       return res;
 }
 
 
@@ -987,10 +1005,13 @@ static int cpia2_mmap(struct file *file, struct vm_area_struct *area)
        struct camera_data *cam = video_drvdata(file);
        int retval;
 
+       if (mutex_lock_interruptible(&cam->v4l2_lock))
+               return -ERESTARTSYS;
        retval = cpia2_remap_buffer(cam, area);
 
        if(!retval)
                cam->stream_fh = file->private_data;
+       mutex_unlock(&cam->v4l2_lock);
        return retval;
 }
 
@@ -1147,10 +1168,6 @@ int cpia2_register_camera(struct camera_data *cam)
        cam->vdev.ctrl_handler = hdl;
        cam->vdev.v4l2_dev = &cam->v4l2_dev;
        set_bit(V4L2_FL_USE_FH_PRIO, &cam->vdev.flags);
-       /* Locking in file operations other than ioctl should be done
-          by the driver, not the V4L2 core.
-          This driver needs auditing so that this flag can be removed. */
-       set_bit(V4L2_FL_LOCK_ALL_FOPS, &cam->vdev.flags);
 
        reset_camera_struct_v4l(cam);
 
index 280aa4d22488c658a712e8907823ef0e800358ed..a34fd082b76ed8e2216bf0bbe1f1d9a382660f8d 100644 (file)
@@ -221,3 +221,5 @@ int cx18_av_loadfw(struct cx18 *cx)
        release_firmware(fw);
        return 0;
 }
+
+MODULE_FIRMWARE(FWFILE);
index 7e5ffd6f51786d3390b629b8794b4139aa410551..c67733d32c8a888d61ced937bb6427c38dc830fa 100644 (file)
@@ -1357,3 +1357,4 @@ static void __exit module_cleanup(void)
 
 module_init(module_start);
 module_exit(module_cleanup);
+MODULE_FIRMWARE(XC2028_DEFAULT_FIRMWARE);
index f41922bd402025118a9e35c8453675ed1ffa62cf..3eac59c51231c0f97b9ae52f1dd8e35f77615427 100644 (file)
@@ -40,6 +40,8 @@
 
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
+#define FWFILE "dvb-cx18-mpc718-mt352.fw"
+
 #define CX18_REG_DMUX_NUM_PORT_0_CONTROL 0xd5a000
 #define CX18_CLOCK_ENABLE2              0xc71024
 #define CX18_DMUX_CLK_MASK              0x0080
@@ -135,7 +137,7 @@ static int yuan_mpc718_mt352_reqfw(struct cx18_stream *stream,
                                   const struct firmware **fw)
 {
        struct cx18 *cx = stream->cx;
-       const char *fn = "dvb-cx18-mpc718-mt352.fw";
+       const char *fn = FWFILE;
        int ret;
 
        ret = request_firmware(fw, fn, &cx->pci_dev->dev);
@@ -603,3 +605,5 @@ static int dvb_register(struct cx18_stream *stream)
 
        return ret;
 }
+
+MODULE_FIRMWARE(FWFILE);
index b85c292a849ac2debe36c828e506254cd65214a7..a1c1cec05f98e4693bdc3dacfa073a64adec1d32 100644 (file)
@@ -376,6 +376,9 @@ void cx18_init_memory(struct cx18 *cx)
        cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT14);  /* AVO */
 }
 
+#define CX18_CPU_FIRMWARE "v4l-cx23418-cpu.fw"
+#define CX18_APU_FIRMWARE "v4l-cx23418-apu.fw"
+
 int cx18_firmware_init(struct cx18 *cx)
 {
        u32 fw_entry_addr;
@@ -400,7 +403,7 @@ int cx18_firmware_init(struct cx18 *cx)
        cx18_sw1_irq_enable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
        cx18_sw2_irq_enable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
 
-       sz = load_cpu_fw_direct("v4l-cx23418-cpu.fw", cx->enc_mem, cx);
+       sz = load_cpu_fw_direct(CX18_CPU_FIRMWARE, cx->enc_mem, cx);
        if (sz <= 0)
                return sz;
 
@@ -408,7 +411,7 @@ int cx18_firmware_init(struct cx18 *cx)
        cx18_init_scb(cx);
 
        fw_entry_addr = 0;
-       sz = load_apu_fw_direct("v4l-cx23418-apu.fw", cx->enc_mem, cx,
+       sz = load_apu_fw_direct(CX18_APU_FIRMWARE, cx->enc_mem, cx,
                                &fw_entry_addr);
        if (sz <= 0)
                return sz;
@@ -451,3 +454,6 @@ int cx18_firmware_init(struct cx18 *cx)
        cx18_write_reg_expect(cx, 0x14001400, 0xc78110, 0x00001400, 0x14001400);
        return 0;
 }
+
+MODULE_FIRMWARE(CX18_CPU_FIRMWARE);
+MODULE_FIRMWARE(CX18_APU_FIRMWARE);
index b3348975c7c2039df3b72fc184ec9a3a43555665..cb06b022e011f7ac927794c34ded02f70f5c23a0 100644 (file)
@@ -12,5 +12,4 @@ ccflags-y += -Idrivers/media/video
 ccflags-y += -Idrivers/media/common/tuners
 ccflags-y += -Idrivers/media/dvb/dvb-core
 ccflags-y += -Idrivers/media/dvb/frontends
-ccflags-y += -Idrivers/media/dvb/dvb-usb
 
index ce2f62238a19d8ae6fabf4df49532db7da0779c4..b024e5197a755fa01cc36fff2be2c7be1a876740 100644 (file)
@@ -2193,3 +2193,5 @@ int cx231xx_417_register(struct cx231xx *dev)
 
        return 0;
 }
+
+MODULE_FIRMWARE(CX231xx_FIRM_IMAGE_NAME);
index 523aa49d6b868e5f0c68b2345e374cb5ddd45a5c..790b28d7f764f99086ae5ebb9d66357e08a4a87b 100644 (file)
@@ -2168,6 +2168,10 @@ static int cx231xx_v4l2_open(struct file *filp)
                cx231xx_errdev("cx231xx-video.c: Out of memory?!\n");
                return -ENOMEM;
        }
+       if (mutex_lock_interruptible(&dev->lock)) {
+               kfree(fh);
+               return -ERESTARTSYS;
+       }
        fh->dev = dev;
        fh->radio = radio;
        fh->type = fh_type;
@@ -2226,6 +2230,7 @@ static int cx231xx_v4l2_open(struct file *filp)
                                            sizeof(struct cx231xx_buffer),
                                            fh, &dev->lock);
        }
+       mutex_unlock(&dev->lock);
 
        return errCode;
 }
@@ -2272,11 +2277,11 @@ void cx231xx_release_analog_resources(struct cx231xx *dev)
 }
 
 /*
- * cx231xx_v4l2_close()
+ * cx231xx_close()
  * stops streaming and deallocates all resources allocated by the v4l2
  * calls and ioctls
  */
-static int cx231xx_v4l2_close(struct file *filp)
+static int cx231xx_close(struct file *filp)
 {
        struct cx231xx_fh *fh = filp->private_data;
        struct cx231xx *dev = fh->dev;
@@ -2355,6 +2360,18 @@ static int cx231xx_v4l2_close(struct file *filp)
        return 0;
 }
 
+static int cx231xx_v4l2_close(struct file *filp)
+{
+       struct cx231xx_fh *fh = filp->private_data;
+       struct cx231xx *dev = fh->dev;
+       int rc;
+
+       mutex_lock(&dev->lock);
+       rc = cx231xx_close(filp);
+       mutex_unlock(&dev->lock);
+       return rc;
+}
+
 /*
  * cx231xx_v4l2_read()
  * will allocate buffers when called for the first time
@@ -2378,8 +2395,12 @@ cx231xx_v4l2_read(struct file *filp, char __user *buf, size_t count,
                if (unlikely(rc < 0))
                        return rc;
 
-               return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
+               if (mutex_lock_interruptible(&dev->lock))
+                       return -ERESTARTSYS;
+               rc = videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
                                            filp->f_flags & O_NONBLOCK);
+               mutex_unlock(&dev->lock);
+               return rc;
        }
        return 0;
 }
@@ -2404,10 +2425,15 @@ static unsigned int cx231xx_v4l2_poll(struct file *filp, poll_table *wait)
                return POLLERR;
 
        if ((V4L2_BUF_TYPE_VIDEO_CAPTURE == fh->type) ||
-           (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type))
-               return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
-       else
-               return POLLERR;
+           (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type)) {
+               unsigned int res;
+
+               mutex_lock(&dev->lock);
+               res = videobuf_poll_stream(filp, &fh->vb_vidq, wait);
+               mutex_unlock(&dev->lock);
+               return res;
+       }
+       return POLLERR;
 }
 
 /*
@@ -2428,7 +2454,10 @@ static int cx231xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
        if (unlikely(rc < 0))
                return rc;
 
+       if (mutex_lock_interruptible(&dev->lock))
+               return -ERESTARTSYS;
        rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+       mutex_unlock(&dev->lock);
 
        cx231xx_videodbg("vma start=0x%08lx, size=%ld, ret=%d\n",
                         (unsigned long)vma->vm_start,
@@ -2545,10 +2574,6 @@ static struct video_device *cx231xx_vdev_init(struct cx231xx *dev,
        vfd->release = video_device_release;
        vfd->debug = video_debug;
        vfd->lock = &dev->lock;
-       /* Locking in file operations other than ioctl should be done
-          by the driver, not the V4L2 core.
-          This driver needs auditing so that this flag can be removed. */
-       set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
 
        snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name);
 
index f5c79e53e5a145bce2fc8a0f898ca7482d2ab0e6..5d5052d0253f00808d5960d46b388b20b6c0bf98 100644 (file)
@@ -1786,3 +1786,5 @@ int cx23885_417_register(struct cx23885_dev *dev)
 
        return 0;
 }
+
+MODULE_FIRMWARE(CX23885_FIRM_IMAGE_NAME);
index 080e11157e5fe89afdb384c702376d80528daf5d..d365e9a8efc4e1e4cb8570ae58baa107cf9ee3bf 100644 (file)
@@ -46,6 +46,7 @@ MODULE_PARM_DESC(enable_885_ir,
                 "Enable integrated IR controller for supported\n"
                 "\t\t    CX2388[57] boards that are wired for it:\n"
                 "\t\t\tHVR-1250 (reported safe)\n"
+                "\t\t\tTerraTec Cinergy T PCIe Dual (not well tested, appears to be safe)\n"
                 "\t\t\tTeVii S470 (reported unsafe)\n"
                 "\t\t    This can cause an interrupt storm with some cards.\n"
                 "\t\t    Default: 0 [Disabled]");
@@ -1363,6 +1364,7 @@ int cx23885_ir_init(struct cx23885_dev *dev)
                params.shutdown = true;
                v4l2_subdev_call(dev->sd_ir, ir, tx_s_parameters, &params);
                break;
+       case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
        case CX23885_BOARD_TEVII_S470:
                if (!enable_885_ir)
                        break;
@@ -1403,6 +1405,7 @@ void cx23885_ir_fini(struct cx23885_dev *dev)
                cx23888_ir_remove(dev);
                dev->sd_ir = NULL;
                break;
+       case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
        case CX23885_BOARD_TEVII_S470:
        case CX23885_BOARD_HAUPPAUGE_HVR1250:
                cx23885_irq_remove(dev, PCI_MSK_AV_CORE);
@@ -1446,6 +1449,7 @@ void cx23885_ir_pci_int_enable(struct cx23885_dev *dev)
                if (dev->sd_ir)
                        cx23885_irq_add_enable(dev, PCI_MSK_IR);
                break;
+       case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
        case CX23885_BOARD_TEVII_S470:
        case CX23885_BOARD_HAUPPAUGE_HVR1250:
                if (dev->sd_ir)
index ce765e3f77bdf6b679ba1b56900035f4f38d51c2..56066721edc17423726188858aa66e4ea017ff0b 100644 (file)
@@ -85,6 +85,7 @@ void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events)
        case CX23885_BOARD_HAUPPAUGE_HVR1270:
        case CX23885_BOARD_HAUPPAUGE_HVR1850:
        case CX23885_BOARD_HAUPPAUGE_HVR1290:
+       case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
        case CX23885_BOARD_TEVII_S470:
        case CX23885_BOARD_HAUPPAUGE_HVR1250:
                /*
@@ -162,6 +163,7 @@ static int cx23885_input_ir_start(struct cx23885_dev *dev)
                 */
                params.invert_level = true;
                break;
+       case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
        case CX23885_BOARD_TEVII_S470:
                /*
                 * The IR controller on this board only returns pulse widths.
@@ -272,6 +274,13 @@ int cx23885_input_init(struct cx23885_dev *dev)
                /* The grey Hauppauge RC-5 remote */
                rc_map = RC_MAP_HAUPPAUGE;
                break;
+       case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
+               /* Integrated CX23885 IR controller */
+               driver_type = RC_DRIVER_IR_RAW;
+               allowed_protos = RC_TYPE_NEC;
+               /* The grey Terratec remote with orange buttons */
+               rc_map = RC_MAP_NEC_TERRATEC_CINERGY_XS;
+               break;
        case CX23885_BOARD_TEVII_S470:
                /* Integrated CX23885 IR controller */
                driver_type = RC_DRIVER_IR_RAW;
index 8150200511daed0ce52918e0e9024a2aa762002c..b3169f94ece879ee89ecb45d61e4a390927b5582 100644 (file)
@@ -61,6 +61,10 @@ static void end_fw_load(struct i2c_client *client)
        cx25840_write(client, 0x803, 0x03);
 }
 
+#define CX2388x_FIRMWARE "v4l-cx23885-avcore-01.fw"
+#define CX231xx_FIRMWARE "v4l-cx231xx-avcore-01.fw"
+#define CX25840_FIRMWARE "v4l-cx25840.fw"
+
 static const char *get_fw_name(struct i2c_client *client)
 {
        struct cx25840_state *state = to_state(i2c_get_clientdata(client));
@@ -68,10 +72,10 @@ static const char *get_fw_name(struct i2c_client *client)
        if (firmware[0])
                return firmware;
        if (is_cx2388x(state))
-               return "v4l-cx23885-avcore-01.fw";
+               return CX2388x_FIRMWARE;
        if (is_cx231xx(state))
-               return "v4l-cx231xx-avcore-01.fw";
-       return "v4l-cx25840.fw";
+               return CX231xx_FIRMWARE;
+       return CX25840_FIRMWARE;
 }
 
 static int check_fw_load(struct i2c_client *client, int size)
@@ -164,3 +168,8 @@ int cx25840_loadfw(struct i2c_client *client)
 
        return check_fw_load(client, size);
 }
+
+MODULE_FIRMWARE(CX2388x_FIRMWARE);
+MODULE_FIRMWARE(CX231xx_FIRMWARE);
+MODULE_FIRMWARE(CX25840_FIRMWARE);
+
index 6fe7034bea7c427e9da4503ea42b4b83991bb1ec..9a05c817462c6ea643cbd354f6a0188f438f03db 100644 (file)
@@ -1376,10 +1376,15 @@ static int vpbe_display_mmap(struct file *filep, struct vm_area_struct *vma)
        struct vpbe_fh *fh = filep->private_data;
        struct vpbe_layer *layer = fh->layer;
        struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+       int ret;
 
        v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_mmap\n");
 
-       return videobuf_mmap_mapper(&layer->buffer_queue, vma);
+       if (mutex_lock_interruptible(&layer->opslock))
+               return -ERESTARTSYS;
+       ret = videobuf_mmap_mapper(&layer->buffer_queue, vma);
+       mutex_unlock(&layer->opslock);
+       return ret;
 }
 
 /* vpbe_display_poll(): It is used for select/poll system call
@@ -1392,8 +1397,11 @@ static unsigned int vpbe_display_poll(struct file *filep, poll_table *wait)
        unsigned int err = 0;
 
        v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_poll\n");
-       if (layer->started)
+       if (layer->started) {
+               mutex_lock(&layer->opslock);
                err = videobuf_poll_stream(filep, &layer->buffer_queue, wait);
+               mutex_unlock(&layer->opslock);
+       }
        return err;
 }
 
@@ -1428,10 +1436,12 @@ static int vpbe_display_open(struct file *file)
        fh->disp_dev = disp_dev;
 
        if (!layer->usrs) {
-
+               if (mutex_lock_interruptible(&layer->opslock))
+                       return -ERESTARTSYS;
                /* First claim the layer for this device */
                err = osd_device->ops.request_layer(osd_device,
                                                layer->layer_info.id);
+               mutex_unlock(&layer->opslock);
                if (err < 0) {
                        /* Couldn't get layer */
                        v4l2_err(&vpbe_dev->v4l2_dev,
@@ -1469,6 +1479,7 @@ static int vpbe_display_release(struct file *file)
 
        v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_release\n");
 
+       mutex_lock(&layer->opslock);
        /* if this instance is doing IO */
        if (fh->io_allowed) {
                /* Reset io_usrs member of layer object */
@@ -1503,6 +1514,7 @@ static int vpbe_display_release(struct file *file)
        /* Close the priority */
        v4l2_prio_close(&layer->prio, fh->prio);
        file->private_data = NULL;
+       mutex_unlock(&layer->opslock);
 
        /* Free memory allocated to file handle object */
        kfree(fh);
@@ -1620,10 +1632,6 @@ static __devinit int init_vpbe_layer(int i, struct vpbe_display *disp_dev,
        vbd->ioctl_ops  = &vpbe_ioctl_ops;
        vbd->minor      = -1;
        vbd->v4l2_dev   = &disp_dev->vpbe_dev->v4l2_dev;
-       /* Locking in file operations other than ioctl should be done
-          by the driver, not the V4L2 core.
-          This driver needs auditing so that this flag can be removed. */
-       set_bit(V4L2_FL_LOCK_ALL_FOPS, &vbd->flags);
        vbd->lock       = &vpbe_display_layer->opslock;
 
        if (disp_dev->vpbe_dev->current_timings.timings_type &
index 266025e5d81d424b90ceedd4a1de6fe9c1d016e8..1b625b065c3268f3b81f97fe93a52f8974e06b2c 100644 (file)
@@ -820,10 +820,15 @@ static int vpif_mmap(struct file *filep, struct vm_area_struct *vma)
        struct vpif_fh *fh = filep->private_data;
        struct channel_obj *ch = fh->channel;
        struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]);
+       int ret;
 
        vpif_dbg(2, debug, "vpif_mmap\n");
 
-       return vb2_mmap(&common->buffer_queue, vma);
+       if (mutex_lock_interruptible(&common->lock))
+               return -ERESTARTSYS;
+       ret = vb2_mmap(&common->buffer_queue, vma);
+       mutex_unlock(&common->lock);
+       return ret;
 }
 
 /**
@@ -836,12 +841,16 @@ static unsigned int vpif_poll(struct file *filep, poll_table * wait)
        struct vpif_fh *fh = filep->private_data;
        struct channel_obj *channel = fh->channel;
        struct common_obj *common = &(channel->common[VPIF_VIDEO_INDEX]);
+       unsigned int res = 0;
 
        vpif_dbg(2, debug, "vpif_poll\n");
 
-       if (common->started)
-               return vb2_poll(&common->buffer_queue, filep, wait);
-       return 0;
+       if (common->started) {
+               mutex_lock(&common->lock);
+               res = vb2_poll(&common->buffer_queue, filep, wait);
+               mutex_unlock(&common->lock);
+       }
+       return res;
 }
 
 /**
@@ -895,6 +904,10 @@ static int vpif_open(struct file *filep)
                return -ENOMEM;
        }
 
+       if (mutex_lock_interruptible(&common->lock)) {
+               kfree(fh);
+               return -ERESTARTSYS;
+       }
        /* store pointer to fh in private_data member of filep */
        filep->private_data = fh;
        fh->channel = ch;
@@ -912,6 +925,7 @@ static int vpif_open(struct file *filep)
        /* Initialize priority of this instance to default priority */
        fh->prio = V4L2_PRIORITY_UNSET;
        v4l2_prio_open(&ch->prio, &fh->prio);
+       mutex_unlock(&common->lock);
        return 0;
 }
 
@@ -932,6 +946,7 @@ static int vpif_release(struct file *filep)
 
        common = &ch->common[VPIF_VIDEO_INDEX];
 
+       mutex_lock(&common->lock);
        /* if this instance is doing IO */
        if (fh->io_allowed[VPIF_VIDEO_INDEX]) {
                /* Reset io_usrs member of channel object */
@@ -961,6 +976,7 @@ static int vpif_release(struct file *filep)
        if (fh->initialized)
                ch->initialized = 0;
 
+       mutex_unlock(&common->lock);
        filep->private_data = NULL;
        kfree(fh);
        return 0;
@@ -2208,10 +2224,6 @@ static __init int vpif_probe(struct platform_device *pdev)
                common = &(ch->common[VPIF_VIDEO_INDEX]);
                spin_lock_init(&common->irqlock);
                mutex_init(&common->lock);
-               /* Locking in file operations other than ioctl should be done
-                  by the driver, not the V4L2 core.
-                  This driver needs auditing so that this flag can be removed. */
-               set_bit(V4L2_FL_LOCK_ALL_FOPS, &ch->video_dev->flags);
                ch->video_dev->lock = &common->lock;
                /* Initialize prio member of channel object */
                v4l2_prio_init(&ch->prio);
index e129c98921ad493b0b8ea90562d2878325218fc5..4a24848c1a665df0df0e05eb610550e49231fb6f 100644 (file)
@@ -695,10 +695,15 @@ static int vpif_mmap(struct file *filep, struct vm_area_struct *vma)
        struct vpif_fh *fh = filep->private_data;
        struct channel_obj *ch = fh->channel;
        struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]);
+       int ret;
 
        vpif_dbg(2, debug, "vpif_mmap\n");
 
-       return vb2_mmap(&common->buffer_queue, vma);
+       if (mutex_lock_interruptible(&common->lock))
+               return -ERESTARTSYS;
+       ret = vb2_mmap(&common->buffer_queue, vma);
+       mutex_unlock(&common->lock);
+       return ret;
 }
 
 /*
@@ -709,11 +714,15 @@ static unsigned int vpif_poll(struct file *filep, poll_table *wait)
        struct vpif_fh *fh = filep->private_data;
        struct channel_obj *ch = fh->channel;
        struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+       unsigned int res = 0;
 
-       if (common->started)
-               return vb2_poll(&common->buffer_queue, filep, wait);
+       if (common->started) {
+               mutex_lock(&common->lock);
+               res = vb2_poll(&common->buffer_queue, filep, wait);
+               mutex_unlock(&common->lock);
+       }
 
-       return 0;
+       return res;
 }
 
 /*
@@ -723,10 +732,10 @@ static unsigned int vpif_poll(struct file *filep, poll_table *wait)
 static int vpif_open(struct file *filep)
 {
        struct video_device *vdev = video_devdata(filep);
-       struct channel_obj *ch = NULL;
-       struct vpif_fh *fh = NULL;
+       struct channel_obj *ch = video_get_drvdata(vdev);
+       struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+       struct vpif_fh *fh;
 
-       ch = video_get_drvdata(vdev);
        /* Allocate memory for the file handle object */
        fh = kzalloc(sizeof(struct vpif_fh), GFP_KERNEL);
        if (fh == NULL) {
@@ -734,6 +743,10 @@ static int vpif_open(struct file *filep)
                return -ENOMEM;
        }
 
+       if (mutex_lock_interruptible(&common->lock)) {
+               kfree(fh);
+               return -ERESTARTSYS;
+       }
        /* store pointer to fh in private_data member of filep */
        filep->private_data = fh;
        fh->channel = ch;
@@ -751,6 +764,7 @@ static int vpif_open(struct file *filep)
        /* Initialize priority of this instance to default priority */
        fh->prio = V4L2_PRIORITY_UNSET;
        v4l2_prio_open(&ch->prio, &fh->prio);
+       mutex_unlock(&common->lock);
 
        return 0;
 }
@@ -765,6 +779,7 @@ static int vpif_release(struct file *filep)
        struct channel_obj *ch = fh->channel;
        struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
 
+       mutex_lock(&common->lock);
        /* if this instance is doing IO */
        if (fh->io_allowed[VPIF_VIDEO_INDEX]) {
                /* Reset io_usrs member of channel object */
@@ -799,6 +814,7 @@ static int vpif_release(struct file *filep)
        v4l2_prio_close(&ch->prio, fh->prio);
        filep->private_data = NULL;
        fh->initialized = 0;
+       mutex_unlock(&common->lock);
        kfree(fh);
 
        return 0;
@@ -1789,10 +1805,6 @@ static __init int vpif_probe(struct platform_device *pdev)
                v4l2_prio_init(&ch->prio);
                ch->common[VPIF_VIDEO_INDEX].fmt.type =
                                                V4L2_BUF_TYPE_VIDEO_OUTPUT;
-               /* Locking in file operations other than ioctl should be done
-                  by the driver, not the V4L2 core.
-                  This driver needs auditing so that this flag can be removed. */
-               set_bit(V4L2_FL_LOCK_ALL_FOPS, &ch->video_dev->flags);
                ch->video_dev->lock = &common->lock;
 
                /* register video device */
index 07dc594e79f04bea706c8cebfba1b514a8a3623e..2fdb66ee44ab7532b7e0d6a9bf3e043eddec8a87 100644 (file)
@@ -306,7 +306,6 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
 
        snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
        dev->adev.capture_pcm_substream = substream;
-       runtime->private_data = dev;
 
        return 0;
 err:
index de2cb20ad2cc1d676c6aa0c532e36bc251c4273e..bed07a6c33f8156df80919725c05857cd0fd9b37 100644 (file)
@@ -785,12 +785,8 @@ int em28xx_resolution_set(struct em28xx *dev)
        else
                dev->vbi_height = 18;
 
-       if (!dev->progressive)
-               height >>= norm_maxh(dev);
-
        em28xx_set_outfmt(dev);
 
-
        em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2);
 
        /* If we don't set the start position to 2 in VBI mode, we end up
index 50f5f4fc2148ce76db99619930137345e3d4b0a3..ecb23df7f16efb178cd735cbc147cef1ae7b75c6 100644 (file)
@@ -2146,9 +2146,12 @@ static int em28xx_v4l2_open(struct file *filp)
                        dev->users);
 
 
+       if (mutex_lock_interruptible(&dev->lock))
+               return -ERESTARTSYS;
        fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL);
        if (!fh) {
                em28xx_errdev("em28xx-video.c: Out of memory?!\n");
+               mutex_unlock(&dev->lock);
                return -ENOMEM;
        }
        fh->dev = dev;
@@ -2189,6 +2192,7 @@ static int em28xx_v4l2_open(struct file *filp)
                                    V4L2_BUF_TYPE_VBI_CAPTURE,
                                    V4L2_FIELD_SEQ_TB,
                                    sizeof(struct em28xx_buffer), fh, &dev->lock);
+       mutex_unlock(&dev->lock);
 
        return errCode;
 }
@@ -2243,6 +2247,7 @@ static int em28xx_v4l2_close(struct file *filp)
 
        em28xx_videodbg("users=%d\n", dev->users);
 
+       mutex_lock(&dev->lock);
        if (res_check(fh, EM28XX_RESOURCE_VIDEO)) {
                videobuf_stop(&fh->vb_vidq);
                res_free(fh, EM28XX_RESOURCE_VIDEO);
@@ -2261,6 +2266,7 @@ static int em28xx_v4l2_close(struct file *filp)
                        kfree(dev->alt_max_pkt_size);
                        kfree(dev);
                        kfree(fh);
+                       mutex_unlock(&dev->lock);
                        return 0;
                }
 
@@ -2285,6 +2291,7 @@ static int em28xx_v4l2_close(struct file *filp)
        videobuf_mmap_free(&fh->vb_vbiq);
        kfree(fh);
        dev->users--;
+       mutex_unlock(&dev->lock);
        return 0;
 }
 
@@ -2304,35 +2311,35 @@ em28xx_v4l2_read(struct file *filp, char __user *buf, size_t count,
        if (rc < 0)
                return rc;
 
+       if (mutex_lock_interruptible(&dev->lock))
+               return -ERESTARTSYS;
        /* FIXME: read() is not prepared to allow changing the video
           resolution while streaming. Seems a bug at em28xx_set_fmt
         */
 
        if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
                if (res_locked(dev, EM28XX_RESOURCE_VIDEO))
-                       return -EBUSY;
-
-               return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
+                       rc = -EBUSY;
+               else
+                       rc = videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
                                        filp->f_flags & O_NONBLOCK);
-       }
-
-
-       if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+       } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
                if (!res_get(fh, EM28XX_RESOURCE_VBI))
-                       return -EBUSY;
-
-               return videobuf_read_stream(&fh->vb_vbiq, buf, count, pos, 0,
+                       rc = -EBUSY;
+               else
+                       rc = videobuf_read_stream(&fh->vb_vbiq, buf, count, pos, 0,
                                        filp->f_flags & O_NONBLOCK);
        }
+       mutex_unlock(&dev->lock);
 
-       return 0;
+       return rc;
 }
 
 /*
- * em28xx_v4l2_poll()
+ * em28xx_poll()
  * will allocate buffers when called for the first time
  */
-static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table *wait)
+static unsigned int em28xx_poll(struct file *filp, poll_table *wait)
 {
        struct em28xx_fh *fh = filp->private_data;
        struct em28xx *dev = fh->dev;
@@ -2355,6 +2362,18 @@ static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table *wait)
        }
 }
 
+static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table *wait)
+{
+       struct em28xx_fh *fh = filp->private_data;
+       struct em28xx *dev = fh->dev;
+       unsigned int res;
+
+       mutex_lock(&dev->lock);
+       res = em28xx_poll(filp, wait);
+       mutex_unlock(&dev->lock);
+       return res;
+}
+
 /*
  * em28xx_v4l2_mmap()
  */
@@ -2368,10 +2387,13 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
        if (rc < 0)
                return rc;
 
+       if (mutex_lock_interruptible(&dev->lock))
+               return -ERESTARTSYS;
        if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
                rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
        else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
                rc = videobuf_mmap_mapper(&fh->vb_vbiq, vma);
+       mutex_unlock(&dev->lock);
 
        em28xx_videodbg("vma start=0x%08lx, size=%ld, ret=%d\n",
                (unsigned long)vma->vm_start,
@@ -2495,10 +2517,6 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev,
        vfd->release    = video_device_release;
        vfd->debug      = video_debug;
        vfd->lock       = &dev->lock;
-       /* Locking in file operations other than ioctl should be done
-          by the driver, not the V4L2 core.
-          This driver needs auditing so that this flag can be removed. */
-       set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
 
        snprintf(vfd->name, sizeof(vfd->name), "%s %s",
                 dev->name, type_name);
index 777486f7cadb65761e25d393e1c16f043426eaea..20f981008fafccf7cfd53f82dbe1176da6b4178d 100644 (file)
@@ -1279,10 +1279,16 @@ static int viu_open(struct file *file)
        dprintk(1, "open minor=%d type=%s users=%d\n", minor,
                v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users);
 
+       if (mutex_lock_interruptible(&dev->lock)) {
+               dev->users--;
+               return -ERESTARTSYS;
+       }
+
        /* allocate and initialize per filehandle data */
        fh = kzalloc(sizeof(*fh), GFP_KERNEL);
        if (!fh) {
                dev->users--;
+               mutex_unlock(&dev->lock);
                return -ENOMEM;
        }
 
@@ -1325,6 +1331,7 @@ static int viu_open(struct file *file)
                                       fh->type, V4L2_FIELD_INTERLACED,
                                       sizeof(struct viu_buf), fh,
                                       &fh->dev->lock);
+       mutex_unlock(&dev->lock);
        return 0;
 }
 
@@ -1340,9 +1347,12 @@ static ssize_t viu_read(struct file *file, char __user *data, size_t count,
                dev->ovenable = 0;
 
        if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               if (mutex_lock_interruptible(&dev->lock))
+                       return -ERESTARTSYS;
                viu_start_dma(dev);
                ret = videobuf_read_stream(&fh->vb_vidq, data, count,
                                ppos, 0, file->f_flags & O_NONBLOCK);
+               mutex_unlock(&dev->lock);
                return ret;
        }
        return 0;
@@ -1352,11 +1362,16 @@ static unsigned int viu_poll(struct file *file, struct poll_table_struct *wait)
 {
        struct viu_fh *fh = file->private_data;
        struct videobuf_queue *q = &fh->vb_vidq;
+       struct viu_dev *dev = fh->dev;
+       unsigned int res;
 
        if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
                return POLLERR;
 
-       return videobuf_poll_stream(file, q, wait);
+       mutex_lock(&dev->lock);
+       res = videobuf_poll_stream(file, q, wait);
+       mutex_unlock(&dev->lock);
+       return res;
 }
 
 static int viu_release(struct file *file)
@@ -1365,9 +1380,11 @@ static int viu_release(struct file *file)
        struct viu_dev *dev = fh->dev;
        int minor = video_devdata(file)->minor;
 
+       mutex_lock(&dev->lock);
        viu_stop_dma(dev);
        videobuf_stop(&fh->vb_vidq);
        videobuf_mmap_free(&fh->vb_vidq);
+       mutex_unlock(&dev->lock);
 
        kfree(fh);
 
@@ -1394,11 +1411,15 @@ void viu_reset(struct viu_reg *reg)
 static int viu_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct viu_fh *fh = file->private_data;
+       struct viu_dev *dev = fh->dev;
        int ret;
 
        dprintk(1, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
 
+       if (mutex_lock_interruptible(&dev->lock))
+               return -ERESTARTSYS;
        ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+       mutex_unlock(&dev->lock);
 
        dprintk(1, "vma start=0x%08lx, size=%ld, ret=%d\n",
                (unsigned long)vma->vm_start,
@@ -1544,10 +1565,6 @@ static int __devinit viu_of_probe(struct platform_device *op)
 
        /* initialize locks */
        mutex_init(&viu_dev->lock);
-       /* Locking in file operations other than ioctl should be done
-          by the driver, not the V4L2 core.
-          This driver needs auditing so that this flag can be removed. */
-       set_bit(V4L2_FL_LOCK_ALL_FOPS, &viu_dev->vdev->flags);
        viu_dev->vdev->lock = &viu_dev->lock;
        spin_lock_init(&viu_dev->slock);
 
index 9ff69b5a87e2bda7294e29480f751ffdefd08ac2..88bce907cdeffed4f1ded62bf6747eb4cf1ada72 100644 (file)
@@ -505,14 +505,17 @@ ssize_t ivtv_v4l2_read(struct file * filp, char __user *buf, size_t count, loff_
        struct ivtv_open_id *id = fh2id(filp->private_data);
        struct ivtv *itv = id->itv;
        struct ivtv_stream *s = &itv->streams[id->type];
-       int rc;
+       ssize_t rc;
 
        IVTV_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name);
 
+       if (mutex_lock_interruptible(&itv->serialize_lock))
+               return -ERESTARTSYS;
        rc = ivtv_start_capture(id);
-       if (rc)
-               return rc;
-       return ivtv_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK);
+       if (!rc)
+               rc = ivtv_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK);
+       mutex_unlock(&itv->serialize_lock);
+       return rc;
 }
 
 int ivtv_start_decoding(struct ivtv_open_id *id, int speed)
@@ -540,7 +543,7 @@ int ivtv_start_decoding(struct ivtv_open_id *id, int speed)
        return 0;
 }
 
-ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t count, loff_t *pos)
+static ssize_t ivtv_write(struct file *filp, const char __user *user_buf, size_t count, loff_t *pos)
 {
        struct ivtv_open_id *id = fh2id(filp->private_data);
        struct ivtv *itv = id->itv;
@@ -712,6 +715,19 @@ retry:
        return bytes_written;
 }
 
+ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t count, loff_t *pos)
+{
+       struct ivtv_open_id *id = fh2id(filp->private_data);
+       struct ivtv *itv = id->itv;
+       ssize_t res;
+
+       if (mutex_lock_interruptible(&itv->serialize_lock))
+               return -ERESTARTSYS;
+       res = ivtv_write(filp, user_buf, count, pos);
+       mutex_unlock(&itv->serialize_lock);
+       return res;
+}
+
 unsigned int ivtv_v4l2_dec_poll(struct file *filp, poll_table *wait)
 {
        struct ivtv_open_id *id = fh2id(filp->private_data);
@@ -760,7 +776,9 @@ unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table *wait)
                        (req_events & (POLLIN | POLLRDNORM))) {
                int rc;
 
+               mutex_lock(&itv->serialize_lock);
                rc = ivtv_start_capture(id);
+               mutex_unlock(&itv->serialize_lock);
                if (rc) {
                        IVTV_DEBUG_INFO("Could not start capture for %s (%d)\n",
                                        s->name, rc);
@@ -863,6 +881,8 @@ int ivtv_v4l2_close(struct file *filp)
 
        IVTV_DEBUG_FILE("close %s\n", s->name);
 
+       mutex_lock(&itv->serialize_lock);
+
        /* Stop radio */
        if (id->type == IVTV_ENC_STREAM_TYPE_RAD &&
                        v4l2_fh_is_singular_file(filp)) {
@@ -892,10 +912,8 @@ int ivtv_v4l2_close(struct file *filp)
        v4l2_fh_exit(fh);
 
        /* Easy case first: this stream was never claimed by us */
-       if (s->fh != &id->fh) {
-               kfree(id);
-               return 0;
-       }
+       if (s->fh != &id->fh)
+               goto close_done;
 
        /* 'Unclaim' this stream */
 
@@ -913,11 +931,13 @@ int ivtv_v4l2_close(struct file *filp)
        } else {
                ivtv_stop_capture(id, 0);
        }
+close_done:
        kfree(id);
+       mutex_unlock(&itv->serialize_lock);
        return 0;
 }
 
-int ivtv_v4l2_open(struct file *filp)
+static int ivtv_open(struct file *filp)
 {
        struct video_device *vdev = video_devdata(filp);
        struct ivtv_stream *s = video_get_drvdata(vdev);
@@ -1020,6 +1040,18 @@ int ivtv_v4l2_open(struct file *filp)
        return 0;
 }
 
+int ivtv_v4l2_open(struct file *filp)
+{
+       struct video_device *vdev = video_devdata(filp);
+       int res;
+
+       if (mutex_lock_interruptible(vdev->lock))
+               return -ERESTARTSYS;
+       res = ivtv_open(filp);
+       mutex_unlock(vdev->lock);
+       return res;
+}
+
 void ivtv_mute(struct ivtv *itv)
 {
        if (atomic_read(&itv->capturing))
index 02c5adebf517aac57248c473a60c793952629e75..6ec7705af55592015ed8ca07fc8e311866077d69 100644 (file)
@@ -396,3 +396,7 @@ int ivtv_firmware_check(struct ivtv *itv, char *where)
 
        return res;
 }
+
+MODULE_FIRMWARE(CX2341X_FIRM_ENC_FILENAME);
+MODULE_FIRMWARE(CX2341X_FIRM_DEC_FILENAME);
+MODULE_FIRMWARE(IVTV_DECODE_INIT_MPEG_FILENAME);
index 87990c5f0910331d9f692fa7cbd828ada8325a77..f08ec17cc3dc52ec634b0660a8ee9d367dbc1ce3 100644 (file)
@@ -228,10 +228,6 @@ static int ivtv_prep_dev(struct ivtv *itv, int type)
        s->vdev->release = video_device_release;
        s->vdev->tvnorms = V4L2_STD_ALL;
        s->vdev->lock = &itv->serialize_lock;
-       /* Locking in file operations other than ioctl should be done
-          by the driver, not the V4L2 core.
-          This driver needs auditing so that this flag can be removed. */
-       set_bit(V4L2_FL_LOCK_ALL_FOPS, &s->vdev->flags);
        set_bit(V4L2_FL_USE_FH_PRIO, &s->vdev->flags);
        ivtv_set_funcs(s->vdev);
        return 0;
diff --git a/drivers/media/video/m2m-deinterlace.c b/drivers/media/video/m2m-deinterlace.c
new file mode 100644 (file)
index 0000000..a38c152
--- /dev/null
@@ -0,0 +1,1120 @@
+/*
+ * V4L2 deinterlacing support.
+ *
+ * Copyright (c) 2012 Vista Silicon S.L.
+ * Javier Martin <javier.martin@vista-silicon.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/slab.h>
+#include <linux/interrupt.h>
+#include <linux/dmaengine.h>
+#include <linux/platform_device.h>
+
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-dma-contig.h>
+
+#define MEM2MEM_TEST_MODULE_NAME "mem2mem-deinterlace"
+
+MODULE_DESCRIPTION("mem2mem device which supports deinterlacing using dmaengine");
+MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.0.1");
+
+static bool debug = true;
+module_param(debug, bool, 0644);
+
+/* Flags that indicate a format can be used for capture/output */
+#define MEM2MEM_CAPTURE        (1 << 0)
+#define MEM2MEM_OUTPUT (1 << 1)
+
+#define MEM2MEM_NAME           "m2m-deinterlace"
+
+#define dprintk(dev, fmt, arg...) \
+       v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
+
+struct deinterlace_fmt {
+       char    *name;
+       u32     fourcc;
+       /* Types the format can be used for */
+       u32     types;
+};
+
+static struct deinterlace_fmt formats[] = {
+       {
+               .name   = "YUV 4:2:0 Planar",
+               .fourcc = V4L2_PIX_FMT_YUV420,
+               .types  = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
+       },
+       {
+               .name   = "YUYV 4:2:2",
+               .fourcc = V4L2_PIX_FMT_YUYV,
+               .types  = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT,
+       },
+};
+
+#define NUM_FORMATS ARRAY_SIZE(formats)
+
+/* Per-queue, driver-specific private data */
+struct deinterlace_q_data {
+       unsigned int            width;
+       unsigned int            height;
+       unsigned int            sizeimage;
+       struct deinterlace_fmt  *fmt;
+       enum v4l2_field         field;
+};
+
+enum {
+       V4L2_M2M_SRC = 0,
+       V4L2_M2M_DST = 1,
+};
+
+enum {
+       YUV420_DMA_Y_ODD,
+       YUV420_DMA_Y_EVEN,
+       YUV420_DMA_U_ODD,
+       YUV420_DMA_U_EVEN,
+       YUV420_DMA_V_ODD,
+       YUV420_DMA_V_EVEN,
+       YUV420_DMA_Y_ODD_DOUBLING,
+       YUV420_DMA_U_ODD_DOUBLING,
+       YUV420_DMA_V_ODD_DOUBLING,
+       YUYV_DMA_ODD,
+       YUYV_DMA_EVEN,
+       YUYV_DMA_EVEN_DOUBLING,
+};
+
+/* Source and destination queue data */
+static struct deinterlace_q_data q_data[2];
+
+static struct deinterlace_q_data *get_q_data(enum v4l2_buf_type type)
+{
+       switch (type) {
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+               return &q_data[V4L2_M2M_SRC];
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               return &q_data[V4L2_M2M_DST];
+       default:
+               BUG();
+       }
+       return NULL;
+}
+
+static struct deinterlace_fmt *find_format(struct v4l2_format *f)
+{
+       struct deinterlace_fmt *fmt;
+       unsigned int k;
+
+       for (k = 0; k < NUM_FORMATS; k++) {
+               fmt = &formats[k];
+               if ((fmt->types & f->type) &&
+                       (fmt->fourcc == f->fmt.pix.pixelformat))
+                       break;
+       }
+
+       if (k == NUM_FORMATS)
+               return NULL;
+
+       return &formats[k];
+}
+
+struct deinterlace_dev {
+       struct v4l2_device      v4l2_dev;
+       struct video_device     *vfd;
+
+       atomic_t                busy;
+       struct mutex            dev_mutex;
+       spinlock_t              irqlock;
+
+       struct dma_chan         *dma_chan;
+
+       struct v4l2_m2m_dev     *m2m_dev;
+       struct vb2_alloc_ctx    *alloc_ctx;
+};
+
+struct deinterlace_ctx {
+       struct deinterlace_dev  *dev;
+
+       /* Abort requested by m2m */
+       int                     aborting;
+       enum v4l2_colorspace    colorspace;
+       dma_cookie_t            cookie;
+       struct v4l2_m2m_ctx     *m2m_ctx;
+       struct dma_interleaved_template *xt;
+};
+
+/*
+ * mem2mem callbacks
+ */
+static int deinterlace_job_ready(void *priv)
+{
+       struct deinterlace_ctx *ctx = priv;
+       struct deinterlace_dev *pcdev = ctx->dev;
+
+       if ((v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) > 0)
+           && (v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) > 0)
+           && (atomic_read(&ctx->dev->busy) == 0)) {
+               dprintk(pcdev, "Task ready\n");
+               return 1;
+       }
+
+       dprintk(pcdev, "Task not ready to run\n");
+
+       return 0;
+}
+
+static void deinterlace_job_abort(void *priv)
+{
+       struct deinterlace_ctx *ctx = priv;
+       struct deinterlace_dev *pcdev = ctx->dev;
+
+       ctx->aborting = 1;
+
+       dprintk(pcdev, "Aborting task\n");
+
+       v4l2_m2m_job_finish(pcdev->m2m_dev, ctx->m2m_ctx);
+}
+
+static void deinterlace_lock(void *priv)
+{
+       struct deinterlace_ctx *ctx = priv;
+       struct deinterlace_dev *pcdev = ctx->dev;
+       mutex_lock(&pcdev->dev_mutex);
+}
+
+static void deinterlace_unlock(void *priv)
+{
+       struct deinterlace_ctx *ctx = priv;
+       struct deinterlace_dev *pcdev = ctx->dev;
+       mutex_unlock(&pcdev->dev_mutex);
+}
+
+static void dma_callback(void *data)
+{
+       struct deinterlace_ctx *curr_ctx = data;
+       struct deinterlace_dev *pcdev = curr_ctx->dev;
+       struct vb2_buffer *src_vb, *dst_vb;
+
+       atomic_set(&pcdev->busy, 0);
+
+       src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
+       dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
+
+       v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
+       v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
+
+       v4l2_m2m_job_finish(pcdev->m2m_dev, curr_ctx->m2m_ctx);
+
+       dprintk(pcdev, "dma transfers completed.\n");
+}
+
+static void deinterlace_issue_dma(struct deinterlace_ctx *ctx, int op,
+                                 int do_callback)
+{
+       struct deinterlace_q_data *s_q_data, *d_q_data;
+       struct vb2_buffer *src_buf, *dst_buf;
+       struct deinterlace_dev *pcdev = ctx->dev;
+       struct dma_chan *chan = pcdev->dma_chan;
+       struct dma_device *dmadev = chan->device;
+       struct dma_async_tx_descriptor *tx;
+       unsigned int s_width, s_height;
+       unsigned int d_width, d_height;
+       unsigned int d_size, s_size;
+       dma_addr_t p_in, p_out;
+       enum dma_ctrl_flags flags;
+
+       src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+       dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+
+       s_q_data = get_q_data(V4L2_BUF_TYPE_VIDEO_OUTPUT);
+       s_width = s_q_data->width;
+       s_height = s_q_data->height;
+       s_size = s_width * s_height;
+
+       d_q_data = get_q_data(V4L2_BUF_TYPE_VIDEO_CAPTURE);
+       d_width = d_q_data->width;
+       d_height = d_q_data->height;
+       d_size = d_width * d_height;
+
+       p_in = (dma_addr_t)vb2_dma_contig_plane_dma_addr(src_buf, 0);
+       p_out = (dma_addr_t)vb2_dma_contig_plane_dma_addr(dst_buf, 0);
+       if (!p_in || !p_out) {
+               v4l2_err(&pcdev->v4l2_dev,
+                        "Acquiring kernel pointers to buffers failed\n");
+               return;
+       }
+
+       switch (op) {
+       case YUV420_DMA_Y_ODD:
+               ctx->xt->numf = s_height / 2;
+               ctx->xt->sgl[0].size = s_width;
+               ctx->xt->sgl[0].icg = s_width;
+               ctx->xt->src_start = p_in;
+               ctx->xt->dst_start = p_out;
+               break;
+       case YUV420_DMA_Y_EVEN:
+               ctx->xt->numf = s_height / 2;
+               ctx->xt->sgl[0].size = s_width;
+               ctx->xt->sgl[0].icg = s_width;
+               ctx->xt->src_start = p_in + s_size / 2;
+               ctx->xt->dst_start = p_out + s_width;
+               break;
+       case YUV420_DMA_U_ODD:
+               ctx->xt->numf = s_height / 4;
+               ctx->xt->sgl[0].size = s_width / 2;
+               ctx->xt->sgl[0].icg = s_width / 2;
+               ctx->xt->src_start = p_in + s_size;
+               ctx->xt->dst_start = p_out + s_size;
+               break;
+       case YUV420_DMA_U_EVEN:
+               ctx->xt->numf = s_height / 4;
+               ctx->xt->sgl[0].size = s_width / 2;
+               ctx->xt->sgl[0].icg = s_width / 2;
+               ctx->xt->src_start = p_in + (9 * s_size) / 8;
+               ctx->xt->dst_start = p_out + s_size + s_width / 2;
+               break;
+       case YUV420_DMA_V_ODD:
+               ctx->xt->numf = s_height / 4;
+               ctx->xt->sgl[0].size = s_width / 2;
+               ctx->xt->sgl[0].icg = s_width / 2;
+               ctx->xt->src_start = p_in + (5 * s_size) / 4;
+               ctx->xt->dst_start = p_out + (5 * s_size) / 4;
+               break;
+       case YUV420_DMA_V_EVEN:
+               ctx->xt->numf = s_height / 4;
+               ctx->xt->sgl[0].size = s_width / 2;
+               ctx->xt->sgl[0].icg = s_width / 2;
+               ctx->xt->src_start = p_in + (11 * s_size) / 8;
+               ctx->xt->dst_start = p_out + (5 * s_size) / 4 + s_width / 2;
+               break;
+       case YUV420_DMA_Y_ODD_DOUBLING:
+               ctx->xt->numf = s_height / 2;
+               ctx->xt->sgl[0].size = s_width;
+               ctx->xt->sgl[0].icg = s_width;
+               ctx->xt->src_start = p_in;
+               ctx->xt->dst_start = p_out + s_width;
+               break;
+       case YUV420_DMA_U_ODD_DOUBLING:
+               ctx->xt->numf = s_height / 4;
+               ctx->xt->sgl[0].size = s_width / 2;
+               ctx->xt->sgl[0].icg = s_width / 2;
+               ctx->xt->src_start = p_in + s_size;
+               ctx->xt->dst_start = p_out + s_size + s_width / 2;
+               break;
+       case YUV420_DMA_V_ODD_DOUBLING:
+               ctx->xt->numf = s_height / 4;
+               ctx->xt->sgl[0].size = s_width / 2;
+               ctx->xt->sgl[0].icg = s_width / 2;
+               ctx->xt->src_start = p_in + (5 * s_size) / 4;
+               ctx->xt->dst_start = p_out + (5 * s_size) / 4 + s_width / 2;
+               break;
+       case YUYV_DMA_ODD:
+               ctx->xt->numf = s_height / 2;
+               ctx->xt->sgl[0].size = s_width * 2;
+               ctx->xt->sgl[0].icg = s_width * 2;
+               ctx->xt->src_start = p_in;
+               ctx->xt->dst_start = p_out;
+               break;
+       case YUYV_DMA_EVEN:
+               ctx->xt->numf = s_height / 2;
+               ctx->xt->sgl[0].size = s_width * 2;
+               ctx->xt->sgl[0].icg = s_width * 2;
+               ctx->xt->src_start = p_in + s_size;
+               ctx->xt->dst_start = p_out + s_width * 2;
+               break;
+       case YUYV_DMA_EVEN_DOUBLING:
+       default:
+               ctx->xt->numf = s_height / 2;
+               ctx->xt->sgl[0].size = s_width * 2;
+               ctx->xt->sgl[0].icg = s_width * 2;
+               ctx->xt->src_start = p_in;
+               ctx->xt->dst_start = p_out + s_width * 2;
+               break;
+       }
+
+       /* Common parameters for al transfers */
+       ctx->xt->frame_size = 1;
+       ctx->xt->dir = DMA_MEM_TO_MEM;
+       ctx->xt->src_sgl = false;
+       ctx->xt->dst_sgl = true;
+       flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT |
+               DMA_COMPL_SKIP_DEST_UNMAP | DMA_COMPL_SKIP_SRC_UNMAP;
+
+       tx = dmadev->device_prep_interleaved_dma(chan, ctx->xt, flags);
+       if (tx == NULL) {
+               v4l2_warn(&pcdev->v4l2_dev, "DMA interleaved prep error\n");
+               return;
+       }
+
+       if (do_callback) {
+               tx->callback = dma_callback;
+               tx->callback_param = ctx;
+       }
+
+       ctx->cookie = dmaengine_submit(tx);
+       if (dma_submit_error(ctx->cookie)) {
+               v4l2_warn(&pcdev->v4l2_dev,
+                         "DMA submit error %d with src=0x%x dst=0x%x len=0x%x\n",
+                         ctx->cookie, (unsigned)p_in, (unsigned)p_out,
+                         s_size * 3/2);
+               return;
+       }
+
+       dma_async_issue_pending(chan);
+}
+
+static void deinterlace_device_run(void *priv)
+{
+       struct deinterlace_ctx *ctx = priv;
+       struct deinterlace_q_data *dst_q_data;
+
+       atomic_set(&ctx->dev->busy, 1);
+
+       dprintk(ctx->dev, "%s: DMA try issue.\n", __func__);
+
+       dst_q_data = get_q_data(V4L2_BUF_TYPE_VIDEO_CAPTURE);
+
+       /*
+        * 4 possible field conversions are possible at the moment:
+        *  V4L2_FIELD_SEQ_TB --> V4L2_FIELD_INTERLACED_TB:
+        *      two separate fields in the same input buffer are interlaced
+        *      in the output buffer using weaving. Top field comes first.
+        *  V4L2_FIELD_SEQ_TB --> V4L2_FIELD_NONE:
+        *      top field from the input buffer is copied to the output buffer
+        *      using line doubling. Bottom field from the input buffer is discarded.
+        * V4L2_FIELD_SEQ_BT --> V4L2_FIELD_INTERLACED_BT:
+        *      two separate fields in the same input buffer are interlaced
+        *      in the output buffer using weaving. Bottom field comes first.
+        * V4L2_FIELD_SEQ_BT --> V4L2_FIELD_NONE:
+        *      bottom field from the input buffer is copied to the output buffer
+        *      using line doubling. Top field from the input buffer is discarded.
+        */
+       switch (dst_q_data->fmt->fourcc) {
+       case V4L2_PIX_FMT_YUV420:
+               switch (dst_q_data->field) {
+               case V4L2_FIELD_INTERLACED_TB:
+               case V4L2_FIELD_INTERLACED_BT:
+                       dprintk(ctx->dev, "%s: yuv420 interlaced tb.\n",
+                               __func__);
+                       deinterlace_issue_dma(ctx, YUV420_DMA_Y_ODD, 0);
+                       deinterlace_issue_dma(ctx, YUV420_DMA_Y_EVEN, 0);
+                       deinterlace_issue_dma(ctx, YUV420_DMA_U_ODD, 0);
+                       deinterlace_issue_dma(ctx, YUV420_DMA_U_EVEN, 0);
+                       deinterlace_issue_dma(ctx, YUV420_DMA_V_ODD, 0);
+                       deinterlace_issue_dma(ctx, YUV420_DMA_V_EVEN, 1);
+                       break;
+               case V4L2_FIELD_NONE:
+               default:
+                       dprintk(ctx->dev, "%s: yuv420 interlaced line doubling.\n",
+                               __func__);
+                       deinterlace_issue_dma(ctx, YUV420_DMA_Y_ODD, 0);
+                       deinterlace_issue_dma(ctx, YUV420_DMA_Y_ODD_DOUBLING, 0);
+                       deinterlace_issue_dma(ctx, YUV420_DMA_U_ODD, 0);
+                       deinterlace_issue_dma(ctx, YUV420_DMA_U_ODD_DOUBLING, 0);
+                       deinterlace_issue_dma(ctx, YUV420_DMA_V_ODD, 0);
+                       deinterlace_issue_dma(ctx, YUV420_DMA_V_ODD_DOUBLING, 1);
+                       break;
+               }
+               break;
+       case V4L2_PIX_FMT_YUYV:
+       default:
+               switch (dst_q_data->field) {
+               case V4L2_FIELD_INTERLACED_TB:
+               case V4L2_FIELD_INTERLACED_BT:
+                       dprintk(ctx->dev, "%s: yuyv interlaced_tb.\n",
+                               __func__);
+                       deinterlace_issue_dma(ctx, YUYV_DMA_ODD, 0);
+                       deinterlace_issue_dma(ctx, YUYV_DMA_EVEN, 1);
+                       break;
+               case V4L2_FIELD_NONE:
+               default:
+                       dprintk(ctx->dev, "%s: yuyv interlaced line doubling.\n",
+                               __func__);
+                       deinterlace_issue_dma(ctx, YUYV_DMA_ODD, 0);
+                       deinterlace_issue_dma(ctx, YUYV_DMA_EVEN_DOUBLING, 1);
+                       break;
+               }
+               break;
+       }
+
+       dprintk(ctx->dev, "%s: DMA issue done.\n", __func__);
+}
+
+/*
+ * video ioctls
+ */
+static int vidioc_querycap(struct file *file, void *priv,
+                          struct v4l2_capability *cap)
+{
+       strlcpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver));
+       strlcpy(cap->card, MEM2MEM_NAME, sizeof(cap->card));
+       strlcpy(cap->bus_info, MEM2MEM_NAME, sizeof(cap->card));
+       cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT
+                         | V4L2_CAP_STREAMING;
+       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+
+       return 0;
+}
+
+static int enum_fmt(struct v4l2_fmtdesc *f, u32 type)
+{
+       int i, num;
+       struct deinterlace_fmt *fmt;
+
+       num = 0;
+
+       for (i = 0; i < NUM_FORMATS; ++i) {
+               if (formats[i].types & type) {
+                       /* index-th format of type type found ? */
+                       if (num == f->index)
+                               break;
+                       /* Correct type but haven't reached our index yet,
+                        * just increment per-type index */
+                       ++num;
+               }
+       }
+
+       if (i < NUM_FORMATS) {
+               /* Format found */
+               fmt = &formats[i];
+               strlcpy(f->description, fmt->name, sizeof(f->description));
+               f->pixelformat = fmt->fourcc;
+               return 0;
+       }
+
+       /* Format not found */
+       return -EINVAL;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+                                  struct v4l2_fmtdesc *f)
+{
+       return enum_fmt(f, MEM2MEM_CAPTURE);
+}
+
+static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
+                                  struct v4l2_fmtdesc *f)
+{
+       return enum_fmt(f, MEM2MEM_OUTPUT);
+}
+
+static int vidioc_g_fmt(struct deinterlace_ctx *ctx, struct v4l2_format *f)
+{
+       struct vb2_queue *vq;
+       struct deinterlace_q_data *q_data;
+
+       vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+       if (!vq)
+               return -EINVAL;
+
+       q_data = get_q_data(f->type);
+
+       f->fmt.pix.width        = q_data->width;
+       f->fmt.pix.height       = q_data->height;
+       f->fmt.pix.field        = q_data->field;
+       f->fmt.pix.pixelformat  = q_data->fmt->fourcc;
+
+       switch (q_data->fmt->fourcc) {
+       case V4L2_PIX_FMT_YUV420:
+               f->fmt.pix.bytesperline = q_data->width * 3 / 2;
+               break;
+       case V4L2_PIX_FMT_YUYV:
+       default:
+               f->fmt.pix.bytesperline = q_data->width * 2;
+       }
+
+       f->fmt.pix.sizeimage    = q_data->sizeimage;
+       f->fmt.pix.colorspace   = ctx->colorspace;
+
+       return 0;
+}
+
+static int vidioc_g_fmt_vid_out(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       return vidioc_g_fmt(priv, f);
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       return vidioc_g_fmt(priv, f);
+}
+
+static int vidioc_try_fmt(struct v4l2_format *f, struct deinterlace_fmt *fmt)
+{
+       switch (f->fmt.pix.pixelformat) {
+       case V4L2_PIX_FMT_YUV420:
+               f->fmt.pix.bytesperline = f->fmt.pix.width * 3 / 2;
+               break;
+       case V4L2_PIX_FMT_YUYV:
+       default:
+               f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
+       }
+       f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+       return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+                                 struct v4l2_format *f)
+{
+       struct deinterlace_fmt *fmt;
+       struct deinterlace_ctx *ctx = priv;
+
+       fmt = find_format(f);
+       if (!fmt || !(fmt->types & MEM2MEM_CAPTURE))
+               f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
+
+       f->fmt.pix.colorspace = ctx->colorspace;
+
+       if (f->fmt.pix.field != V4L2_FIELD_INTERLACED_TB &&
+           f->fmt.pix.field != V4L2_FIELD_INTERLACED_BT &&
+           f->fmt.pix.field != V4L2_FIELD_NONE)
+               f->fmt.pix.field = V4L2_FIELD_INTERLACED_TB;
+
+       return vidioc_try_fmt(f, fmt);
+}
+
+static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
+                                 struct v4l2_format *f)
+{
+       struct deinterlace_fmt *fmt;
+
+       fmt = find_format(f);
+       if (!fmt || !(fmt->types & MEM2MEM_OUTPUT))
+               f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
+
+       if (!f->fmt.pix.colorspace)
+               f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
+
+       if (f->fmt.pix.field != V4L2_FIELD_SEQ_TB &&
+           f->fmt.pix.field != V4L2_FIELD_SEQ_BT)
+               f->fmt.pix.field = V4L2_FIELD_SEQ_TB;
+
+       return vidioc_try_fmt(f, fmt);
+}
+
+static int vidioc_s_fmt(struct deinterlace_ctx *ctx, struct v4l2_format *f)
+{
+       struct deinterlace_q_data *q_data;
+       struct vb2_queue *vq;
+
+       vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+       if (!vq)
+               return -EINVAL;
+
+       q_data = get_q_data(f->type);
+       if (!q_data)
+               return -EINVAL;
+
+       if (vb2_is_busy(vq)) {
+               v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__);
+               return -EBUSY;
+       }
+
+       q_data->fmt = find_format(f);
+       if (!q_data->fmt) {
+               v4l2_err(&ctx->dev->v4l2_dev,
+                        "Couldn't set format type %d, wxh: %dx%d. fmt: %d, field: %d\n",
+                       f->type, f->fmt.pix.width, f->fmt.pix.height,
+                       f->fmt.pix.pixelformat, f->fmt.pix.field);
+               return -EINVAL;
+       }
+
+       q_data->width           = f->fmt.pix.width;
+       q_data->height          = f->fmt.pix.height;
+       q_data->field           = f->fmt.pix.field;
+
+       switch (f->fmt.pix.pixelformat) {
+       case V4L2_PIX_FMT_YUV420:
+               f->fmt.pix.bytesperline = f->fmt.pix.width * 3 / 2;
+               q_data->sizeimage = (q_data->width * q_data->height * 3) / 2;
+               break;
+       case V4L2_PIX_FMT_YUYV:
+       default:
+               f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
+               q_data->sizeimage = q_data->width * q_data->height * 2;
+       }
+
+       dprintk(ctx->dev,
+               "Setting format for type %d, wxh: %dx%d, fmt: %d, field: %d\n",
+               f->type, q_data->width, q_data->height, q_data->fmt->fourcc,
+               q_data->field);
+
+       return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       int ret;
+
+       ret = vidioc_try_fmt_vid_cap(file, priv, f);
+       if (ret)
+               return ret;
+       return vidioc_s_fmt(priv, f);
+}
+
+static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
+                               struct v4l2_format *f)
+{
+       struct deinterlace_ctx *ctx = priv;
+       int ret;
+
+       ret = vidioc_try_fmt_vid_out(file, priv, f);
+       if (ret)
+               return ret;
+
+       ret = vidioc_s_fmt(priv, f);
+       if (!ret)
+               ctx->colorspace = f->fmt.pix.colorspace;
+
+       return ret;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+                         struct v4l2_requestbuffers *reqbufs)
+{
+       struct deinterlace_ctx *ctx = priv;
+
+       return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+                          struct v4l2_buffer *buf)
+{
+       struct deinterlace_ctx *ctx = priv;
+
+       return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+       struct deinterlace_ctx *ctx = priv;
+
+       return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+       struct deinterlace_ctx *ctx = priv;
+
+       return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int vidioc_streamon(struct file *file, void *priv,
+                          enum v4l2_buf_type type)
+{
+       struct deinterlace_q_data *s_q_data, *d_q_data;
+       struct deinterlace_ctx *ctx = priv;
+
+       s_q_data = get_q_data(V4L2_BUF_TYPE_VIDEO_OUTPUT);
+       d_q_data = get_q_data(V4L2_BUF_TYPE_VIDEO_CAPTURE);
+
+       /* Check that src and dst queues have the same pix format */
+       if (s_q_data->fmt->fourcc != d_q_data->fmt->fourcc) {
+               v4l2_err(&ctx->dev->v4l2_dev,
+                        "src and dst formats don't match.\n");
+               return -EINVAL;
+       }
+
+       /* Check that input and output deinterlacing types are compatible */
+       switch (s_q_data->field) {
+       case V4L2_FIELD_SEQ_BT:
+               if (d_q_data->field != V4L2_FIELD_NONE &&
+                       d_q_data->field != V4L2_FIELD_INTERLACED_BT) {
+                       v4l2_err(&ctx->dev->v4l2_dev,
+                        "src and dst field conversion [(%d)->(%d)] not supported.\n",
+                               s_q_data->field, d_q_data->field);
+                       return -EINVAL;
+               }
+               break;
+       case V4L2_FIELD_SEQ_TB:
+               if (d_q_data->field != V4L2_FIELD_NONE &&
+                       d_q_data->field != V4L2_FIELD_INTERLACED_TB) {
+                       v4l2_err(&ctx->dev->v4l2_dev,
+                        "src and dst field conversion [(%d)->(%d)] not supported.\n",
+                               s_q_data->field, d_q_data->field);
+                       return -EINVAL;
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
+}
+
+static int vidioc_streamoff(struct file *file, void *priv,
+                           enum v4l2_buf_type type)
+{
+       struct deinterlace_ctx *ctx = priv;
+
+       return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
+}
+
+static const struct v4l2_ioctl_ops deinterlace_ioctl_ops = {
+       .vidioc_querycap        = vidioc_querycap,
+
+       .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+       .vidioc_g_fmt_vid_cap   = vidioc_g_fmt_vid_cap,
+       .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap   = vidioc_s_fmt_vid_cap,
+
+       .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out,
+       .vidioc_g_fmt_vid_out   = vidioc_g_fmt_vid_out,
+       .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
+       .vidioc_s_fmt_vid_out   = vidioc_s_fmt_vid_out,
+
+       .vidioc_reqbufs         = vidioc_reqbufs,
+       .vidioc_querybuf        = vidioc_querybuf,
+
+       .vidioc_qbuf            = vidioc_qbuf,
+       .vidioc_dqbuf           = vidioc_dqbuf,
+
+       .vidioc_streamon        = vidioc_streamon,
+       .vidioc_streamoff       = vidioc_streamoff,
+};
+
+
+/*
+ * Queue operations
+ */
+struct vb2_dc_conf {
+       struct device           *dev;
+};
+
+static int deinterlace_queue_setup(struct vb2_queue *vq,
+                               const struct v4l2_format *fmt,
+                               unsigned int *nbuffers, unsigned int *nplanes,
+                               unsigned int sizes[], void *alloc_ctxs[])
+{
+       struct deinterlace_ctx *ctx = vb2_get_drv_priv(vq);
+       struct deinterlace_q_data *q_data;
+       unsigned int size, count = *nbuffers;
+
+       q_data = get_q_data(vq->type);
+
+       switch (q_data->fmt->fourcc) {
+       case V4L2_PIX_FMT_YUV420:
+               size = q_data->width * q_data->height * 3 / 2;
+               break;
+       case V4L2_PIX_FMT_YUYV:
+       default:
+               size = q_data->width * q_data->height * 2;
+       }
+
+       *nplanes = 1;
+       *nbuffers = count;
+       sizes[0] = size;
+
+       alloc_ctxs[0] = ctx->dev->alloc_ctx;
+
+       dprintk(ctx->dev, "get %d buffer(s) of size %d each.\n", count, size);
+
+       return 0;
+}
+
+static int deinterlace_buf_prepare(struct vb2_buffer *vb)
+{
+       struct deinterlace_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+       struct deinterlace_q_data *q_data;
+
+       dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type);
+
+       q_data = get_q_data(vb->vb2_queue->type);
+
+       if (vb2_plane_size(vb, 0) < q_data->sizeimage) {
+               dprintk(ctx->dev, "%s data will not fit into plane (%lu < %lu)\n",
+                       __func__, vb2_plane_size(vb, 0), (long)q_data->sizeimage);
+               return -EINVAL;
+       }
+
+       vb2_set_plane_payload(vb, 0, q_data->sizeimage);
+
+       return 0;
+}
+
+static void deinterlace_buf_queue(struct vb2_buffer *vb)
+{
+       struct deinterlace_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+       v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
+}
+
+static struct vb2_ops deinterlace_qops = {
+       .queue_setup     = deinterlace_queue_setup,
+       .buf_prepare     = deinterlace_buf_prepare,
+       .buf_queue       = deinterlace_buf_queue,
+};
+
+static int queue_init(void *priv, struct vb2_queue *src_vq,
+                     struct vb2_queue *dst_vq)
+{
+       struct deinterlace_ctx *ctx = priv;
+       int ret;
+
+       memset(src_vq, 0, sizeof(*src_vq));
+       src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+       src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+       src_vq->drv_priv = ctx;
+       src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+       src_vq->ops = &deinterlace_qops;
+       src_vq->mem_ops = &vb2_dma_contig_memops;
+       q_data[V4L2_M2M_SRC].fmt = &formats[0];
+       q_data[V4L2_M2M_SRC].width = 640;
+       q_data[V4L2_M2M_SRC].height = 480;
+       q_data[V4L2_M2M_SRC].sizeimage = (640 * 480 * 3) / 2;
+       q_data[V4L2_M2M_SRC].field = V4L2_FIELD_SEQ_TB;
+
+       ret = vb2_queue_init(src_vq);
+       if (ret)
+               return ret;
+
+       memset(dst_vq, 0, sizeof(*dst_vq));
+       dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
+       dst_vq->drv_priv = ctx;
+       dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+       dst_vq->ops = &deinterlace_qops;
+       dst_vq->mem_ops = &vb2_dma_contig_memops;
+       q_data[V4L2_M2M_DST].fmt = &formats[0];
+       q_data[V4L2_M2M_DST].width = 640;
+       q_data[V4L2_M2M_DST].height = 480;
+       q_data[V4L2_M2M_DST].sizeimage = (640 * 480 * 3) / 2;
+       q_data[V4L2_M2M_SRC].field = V4L2_FIELD_INTERLACED_TB;
+
+       return vb2_queue_init(dst_vq);
+}
+
+/*
+ * File operations
+ */
+static int deinterlace_open(struct file *file)
+{
+       struct deinterlace_dev *pcdev = video_drvdata(file);
+       struct deinterlace_ctx *ctx = NULL;
+
+       ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+
+       file->private_data = ctx;
+       ctx->dev = pcdev;
+
+       ctx->m2m_ctx = v4l2_m2m_ctx_init(pcdev->m2m_dev, ctx, &queue_init);
+       if (IS_ERR(ctx->m2m_ctx)) {
+               int ret = PTR_ERR(ctx->m2m_ctx);
+
+               kfree(ctx);
+               return ret;
+       }
+
+       ctx->xt = kzalloc(sizeof(struct dma_async_tx_descriptor) +
+                               sizeof(struct data_chunk), GFP_KERNEL);
+       if (!ctx->xt) {
+               int ret = PTR_ERR(ctx->xt);
+
+               kfree(ctx);
+               return ret;
+       }
+
+       ctx->colorspace = V4L2_COLORSPACE_REC709;
+
+       dprintk(pcdev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->m2m_ctx);
+
+       return 0;
+}
+
+static int deinterlace_release(struct file *file)
+{
+       struct deinterlace_dev *pcdev = video_drvdata(file);
+       struct deinterlace_ctx *ctx = file->private_data;
+
+       dprintk(pcdev, "Releasing instance %p\n", ctx);
+
+       v4l2_m2m_ctx_release(ctx->m2m_ctx);
+       kfree(ctx->xt);
+       kfree(ctx);
+
+       return 0;
+}
+
+static unsigned int deinterlace_poll(struct file *file,
+                                struct poll_table_struct *wait)
+{
+       struct deinterlace_ctx *ctx = file->private_data;
+       int ret;
+
+       deinterlace_lock(ctx);
+       ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+       deinterlace_unlock(ctx);
+
+       return ret;
+}
+
+static int deinterlace_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct deinterlace_ctx *ctx = file->private_data;
+
+       return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+}
+
+static const struct v4l2_file_operations deinterlace_fops = {
+       .owner          = THIS_MODULE,
+       .open           = deinterlace_open,
+       .release        = deinterlace_release,
+       .poll           = deinterlace_poll,
+       .unlocked_ioctl = video_ioctl2,
+       .mmap           = deinterlace_mmap,
+};
+
+static struct video_device deinterlace_videodev = {
+       .name           = MEM2MEM_NAME,
+       .fops           = &deinterlace_fops,
+       .ioctl_ops      = &deinterlace_ioctl_ops,
+       .minor          = -1,
+       .release        = video_device_release,
+};
+
+static struct v4l2_m2m_ops m2m_ops = {
+       .device_run     = deinterlace_device_run,
+       .job_ready      = deinterlace_job_ready,
+       .job_abort      = deinterlace_job_abort,
+       .lock           = deinterlace_lock,
+       .unlock         = deinterlace_unlock,
+};
+
+static int deinterlace_probe(struct platform_device *pdev)
+{
+       struct deinterlace_dev *pcdev;
+       struct video_device *vfd;
+       dma_cap_mask_t mask;
+       int ret = 0;
+
+       pcdev = kzalloc(sizeof *pcdev, GFP_KERNEL);
+       if (!pcdev)
+               return -ENOMEM;
+
+       spin_lock_init(&pcdev->irqlock);
+
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_INTERLEAVE, mask);
+       pcdev->dma_chan = dma_request_channel(mask, NULL, pcdev);
+       if (!pcdev->dma_chan)
+               goto free_dev;
+
+       if (!dma_has_cap(DMA_INTERLEAVE, pcdev->dma_chan->device->cap_mask)) {
+               v4l2_err(&pcdev->v4l2_dev, "DMA does not support INTERLEAVE\n");
+               goto rel_dma;
+       }
+
+       ret = v4l2_device_register(&pdev->dev, &pcdev->v4l2_dev);
+       if (ret)
+               goto rel_dma;
+
+       atomic_set(&pcdev->busy, 0);
+       mutex_init(&pcdev->dev_mutex);
+
+       vfd = video_device_alloc();
+       if (!vfd) {
+               v4l2_err(&pcdev->v4l2_dev, "Failed to allocate video device\n");
+               ret = -ENOMEM;
+               goto unreg_dev;
+       }
+
+       *vfd = deinterlace_videodev;
+       vfd->lock = &pcdev->dev_mutex;
+
+       ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+       if (ret) {
+               v4l2_err(&pcdev->v4l2_dev, "Failed to register video device\n");
+               goto rel_vdev;
+       }
+
+       video_set_drvdata(vfd, pcdev);
+       snprintf(vfd->name, sizeof(vfd->name), "%s", deinterlace_videodev.name);
+       pcdev->vfd = vfd;
+       v4l2_info(&pcdev->v4l2_dev, MEM2MEM_TEST_MODULE_NAME
+                       " Device registered as /dev/video%d\n", vfd->num);
+
+       platform_set_drvdata(pdev, pcdev);
+
+       pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+       if (IS_ERR(pcdev->alloc_ctx)) {
+               v4l2_err(&pcdev->v4l2_dev, "Failed to alloc vb2 context\n");
+               ret = PTR_ERR(pcdev->alloc_ctx);
+               goto err_ctx;
+       }
+
+       pcdev->m2m_dev = v4l2_m2m_init(&m2m_ops);
+       if (IS_ERR(pcdev->m2m_dev)) {
+               v4l2_err(&pcdev->v4l2_dev, "Failed to init mem2mem device\n");
+               ret = PTR_ERR(pcdev->m2m_dev);
+               goto err_m2m;
+       }
+
+       return 0;
+
+       v4l2_m2m_release(pcdev->m2m_dev);
+err_m2m:
+       video_unregister_device(pcdev->vfd);
+err_ctx:
+       vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
+rel_vdev:
+       video_device_release(vfd);
+unreg_dev:
+       v4l2_device_unregister(&pcdev->v4l2_dev);
+rel_dma:
+       dma_release_channel(pcdev->dma_chan);
+free_dev:
+       kfree(pcdev);
+
+       return ret;
+}
+
+static int deinterlace_remove(struct platform_device *pdev)
+{
+       struct deinterlace_dev *pcdev =
+               (struct deinterlace_dev *)platform_get_drvdata(pdev);
+
+       v4l2_info(&pcdev->v4l2_dev, "Removing " MEM2MEM_TEST_MODULE_NAME);
+       v4l2_m2m_release(pcdev->m2m_dev);
+       video_unregister_device(pcdev->vfd);
+       v4l2_device_unregister(&pcdev->v4l2_dev);
+       vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
+       dma_release_channel(pcdev->dma_chan);
+       kfree(pcdev);
+
+       return 0;
+}
+
+static struct platform_driver deinterlace_pdrv = {
+       .probe          = deinterlace_probe,
+       .remove         = deinterlace_remove,
+       .driver         = {
+               .name   = MEM2MEM_NAME,
+               .owner  = THIS_MODULE,
+       },
+};
+
+static void __exit deinterlace_exit(void)
+{
+       platform_driver_unregister(&deinterlace_pdrv);
+}
+
+static int __init deinterlace_init(void)
+{
+       return platform_driver_register(&deinterlace_pdrv);
+}
+
+module_init(deinterlace_init);
+module_exit(deinterlace_exit);
+
index 7efe9ad7acc7f90f0942644ee4d909b8b9705618..0aa8c47a6177288968a7dbc5aa091d02a4727fcf 100644 (file)
@@ -431,7 +431,7 @@ static int vidioc_querycap(struct file *file, void *priv,
        strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1);
        strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
        strlcpy(cap->bus_info, MEM2MEM_NAME, sizeof(cap->bus_info));
-       cap->capabilities = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
+       cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
        cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
        return 0;
 }
@@ -891,10 +891,15 @@ static int m2mtest_open(struct file *file)
        struct m2mtest_dev *dev = video_drvdata(file);
        struct m2mtest_ctx *ctx = NULL;
        struct v4l2_ctrl_handler *hdl;
+       int rc = 0;
 
+       if (mutex_lock_interruptible(&dev->dev_mutex))
+               return -ERESTARTSYS;
        ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
-       if (!ctx)
-               return -ENOMEM;
+       if (!ctx) {
+               rc = -ENOMEM;
+               goto open_unlock;
+       }
 
        v4l2_fh_init(&ctx->fh, video_devdata(file));
        file->private_data = &ctx->fh;
@@ -927,11 +932,11 @@ static int m2mtest_open(struct file *file)
        ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
 
        if (IS_ERR(ctx->m2m_ctx)) {
-               int ret = PTR_ERR(ctx->m2m_ctx);
+               rc = PTR_ERR(ctx->m2m_ctx);
 
                v4l2_ctrl_handler_free(hdl);
                kfree(ctx);
-               return ret;
+               goto open_unlock;
        }
 
        v4l2_fh_add(&ctx->fh);
@@ -939,6 +944,8 @@ static int m2mtest_open(struct file *file)
 
        dprintk(dev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->m2m_ctx);
 
+open_unlock:
+       mutex_unlock(&dev->dev_mutex);
        return 0;
 }
 
@@ -952,7 +959,9 @@ static int m2mtest_release(struct file *file)
        v4l2_fh_del(&ctx->fh);
        v4l2_fh_exit(&ctx->fh);
        v4l2_ctrl_handler_free(&ctx->hdl);
+       mutex_lock(&dev->dev_mutex);
        v4l2_m2m_ctx_release(ctx->m2m_ctx);
+       mutex_unlock(&dev->dev_mutex);
        kfree(ctx);
 
        atomic_dec(&dev->num_inst);
@@ -970,9 +979,15 @@ static unsigned int m2mtest_poll(struct file *file,
 
 static int m2mtest_mmap(struct file *file, struct vm_area_struct *vma)
 {
+       struct m2mtest_dev *dev = video_drvdata(file);
        struct m2mtest_ctx *ctx = file2ctx(file);
+       int res;
 
-       return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+       if (mutex_lock_interruptible(&dev->dev_mutex))
+               return -ERESTARTSYS;
+       res = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+       mutex_unlock(&dev->dev_mutex);
+       return res;
 }
 
 static const struct v4l2_file_operations m2mtest_fops = {
@@ -1027,10 +1042,6 @@ static int m2mtest_probe(struct platform_device *pdev)
        }
 
        *vfd = m2mtest_videodev;
-       /* Locking in file operations other than ioctl should be done
-          by the driver, not the V4L2 core.
-          This driver needs auditing so that this flag can be removed. */
-       set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
        vfd->lock = &dev->dev_mutex;
 
        ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
index 5f8a6f5b98f91c3af4e1bdbd06654e7b496d8d65..2810015d78f4ea253743b950a26e3a46ffe5efb7 100644 (file)
@@ -209,7 +209,7 @@ struct emmaprp_dev {
 
        int                     irq_emma;
        void __iomem            *base_emma;
-       struct clk              *clk_emma;
+       struct clk              *clk_emma_ahb, *clk_emma_ipg;
        struct resource         *res_emma;
 
        struct v4l2_m2m_dev     *m2m_dev;
@@ -795,18 +795,26 @@ static int emmaprp_open(struct file *file)
        file->private_data = ctx;
        ctx->dev = pcdev;
 
+       if (mutex_lock_interruptible(&pcdev->dev_mutex)) {
+               kfree(ctx);
+               return -ERESTARTSYS;
+       }
+
        ctx->m2m_ctx = v4l2_m2m_ctx_init(pcdev->m2m_dev, ctx, &queue_init);
 
        if (IS_ERR(ctx->m2m_ctx)) {
                int ret = PTR_ERR(ctx->m2m_ctx);
 
+               mutex_unlock(&pcdev->dev_mutex);
                kfree(ctx);
                return ret;
        }
 
-       clk_enable(pcdev->clk_emma);
+       clk_prepare_enable(pcdev->clk_emma_ipg);
+       clk_prepare_enable(pcdev->clk_emma_ahb);
        ctx->q_data[V4L2_M2M_SRC].fmt = &formats[1];
        ctx->q_data[V4L2_M2M_DST].fmt = &formats[0];
+       mutex_unlock(&pcdev->dev_mutex);
 
        dprintk(pcdev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->m2m_ctx);
 
@@ -820,8 +828,11 @@ static int emmaprp_release(struct file *file)
 
        dprintk(pcdev, "Releasing instance %p\n", ctx);
 
-       clk_disable(pcdev->clk_emma);
+       mutex_lock(&pcdev->dev_mutex);
+       clk_disable_unprepare(pcdev->clk_emma_ahb);
+       clk_disable_unprepare(pcdev->clk_emma_ipg);
        v4l2_m2m_ctx_release(ctx->m2m_ctx);
+       mutex_unlock(&pcdev->dev_mutex);
        kfree(ctx);
 
        return 0;
@@ -830,16 +841,27 @@ static int emmaprp_release(struct file *file)
 static unsigned int emmaprp_poll(struct file *file,
                                 struct poll_table_struct *wait)
 {
+       struct emmaprp_dev *pcdev = video_drvdata(file);
        struct emmaprp_ctx *ctx = file->private_data;
+       unsigned int res;
 
-       return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+       mutex_lock(&pcdev->dev_mutex);
+       res = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+       mutex_unlock(&pcdev->dev_mutex);
+       return res;
 }
 
 static int emmaprp_mmap(struct file *file, struct vm_area_struct *vma)
 {
+       struct emmaprp_dev *pcdev = video_drvdata(file);
        struct emmaprp_ctx *ctx = file->private_data;
+       int ret;
 
-       return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+       if (mutex_lock_interruptible(&pcdev->dev_mutex))
+               return -ERESTARTSYS;
+       ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+       mutex_unlock(&pcdev->dev_mutex);
+       return ret;
 }
 
 static const struct v4l2_file_operations emmaprp_fops = {
@@ -880,9 +902,15 @@ static int emmaprp_probe(struct platform_device *pdev)
 
        spin_lock_init(&pcdev->irqlock);
 
-       pcdev->clk_emma = clk_get(&pdev->dev, NULL);
-       if (IS_ERR(pcdev->clk_emma)) {
-               ret = PTR_ERR(pcdev->clk_emma);
+       pcdev->clk_emma_ipg = devm_clk_get(&pdev->dev, "ipg");
+       if (IS_ERR(pcdev->clk_emma_ipg)) {
+               ret = PTR_ERR(pcdev->clk_emma_ipg);
+               goto free_dev;
+       }
+
+       pcdev->clk_emma_ahb = devm_clk_get(&pdev->dev, "ahb");
+       if (IS_ERR(pcdev->clk_emma_ipg)) {
+               ret = PTR_ERR(pcdev->clk_emma_ahb);
                goto free_dev;
        }
 
@@ -891,12 +919,12 @@ static int emmaprp_probe(struct platform_device *pdev)
        if (irq_emma < 0 || res_emma == NULL) {
                dev_err(&pdev->dev, "Missing platform resources data\n");
                ret = -ENODEV;
-               goto free_clk;
+               goto free_dev;
        }
 
        ret = v4l2_device_register(&pdev->dev, &pcdev->v4l2_dev);
        if (ret)
-               goto free_clk;
+               goto free_dev;
 
        mutex_init(&pcdev->dev_mutex);
 
@@ -908,10 +936,6 @@ static int emmaprp_probe(struct platform_device *pdev)
        }
 
        *vfd = emmaprp_videodev;
-       /* Locking in file operations other than ioctl should be done
-          by the driver, not the V4L2 core.
-          This driver needs auditing so that this flag can be removed. */
-       set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
        vfd->lock = &pcdev->dev_mutex;
 
        video_set_drvdata(vfd, pcdev);
@@ -969,8 +993,6 @@ rel_vdev:
        video_device_release(vfd);
 unreg_dev:
        v4l2_device_unregister(&pcdev->v4l2_dev);
-free_clk:
-       clk_put(pcdev->clk_emma);
 free_dev:
        kfree(pcdev);
 
@@ -987,7 +1009,6 @@ static int emmaprp_remove(struct platform_device *pdev)
        v4l2_m2m_release(pcdev->m2m_dev);
        vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
        v4l2_device_unregister(&pcdev->v4l2_dev);
-       clk_put(pcdev->clk_emma);
        kfree(pcdev);
 
        return 0;
index c60df0ed075aae3f42ef43460ce9b51b39b53e46..c84df0706f3e098542d822e8fefc0755b010d836 100644 (file)
@@ -23,7 +23,7 @@
  * 02110-1301 USA
  */
 
-244,   0, 247,   0,  12,  27,  36, 247, 250,   0,  27,   0,   4, 250,  12, 244,
+{ 244, 0, 247,   0,  12,  27,  36, 247, 250,   0,  27,   0,   4, 250,  12, 244,
 248,   0,   0,   0,   0,  40,   0,   0, 244,  12, 250,   4,   0,  27,   0, 250,
 247,  36,  27,  12,   0, 247,   0, 244,   0,   0,  40,   0,   0,   0,   0, 248,
 244,   0, 247,   0,  12,  27,  36, 247, 250,   0,  27,   0,   4, 250,  12, 244,
@@ -31,8 +31,8 @@
 247,  36,  27,  12,   0, 247,   0, 244,   0,   0,  40,   0,   0,   0,   0, 248,
 244,   0, 247,   0,  12,  27,  36, 247, 250,   0,  27,   0,   4, 250,  12, 244,
 248,   0,   0,   0,   0,  40,   0,   0, 244,  12, 250,   4,   0,  27,   0, 250,
-247,  36,  27,  12,   0, 247,   0, 244,   0,   0,  40,   0,   0,   0,   0, 248,
-  0, 247,   0, 244, 247,  36,  27,  12,   0,  27,   0, 250, 244,  12, 250,   4,
+247,  36,  27,  12,   0, 247,   0, 244,   0,   0,  40,   0,   0,   0,   0, 248 },
+{ 0, 247,   0, 244, 247,  36,  27,  12,   0,  27,   0, 250, 244,  12, 250,   4,
   0,   0,   0, 248,   0,   0,  40,   0,   4, 250,  12, 244, 250,   0,  27,   0,
  12,  27,  36, 247, 244,   0, 247,   0,   0,  40,   0,   0, 248,   0,   0,   0,
   0, 247,   0, 244, 247,  36,  27,  12,   0,  27,   0, 250, 244,  12, 250,   4,
@@ -40,8 +40,8 @@
  12,  27,  36, 247, 244,   0, 247,   0,   0,  40,   0,   0, 248,   0,   0,   0,
   0, 247,   0, 244, 247,  36,  27,  12,   0,  27,   0, 250, 244,  12, 250,   4,
   0,   0,   0, 248,   0,   0,  40,   0,   4, 250,  12, 244, 250,   0,  27,   0,
- 12,  27,  36, 247, 244,   0, 247,   0,   0,  40,   0,   0, 248,   0,   0,   0,
-  4, 250,  12, 244, 250,   0,  27,   0,  12,  27,  36, 247, 244,   0, 247,   0,
+ 12,  27,  36, 247, 244,   0, 247,   0,   0,  40,   0,   0, 248,   0,   0,   0 },
+{ 4, 250,  12, 244, 250,   0,  27,   0,  12,  27,  36, 247, 244,   0, 247,   0,
   0,   0,   0, 248,   0,   0,  40,   0,   0, 247,   0, 244, 247,  36,  27,  12,
   0,  27,   0, 250, 244,  12, 250,   4,   0,  40,   0,   0, 248,   0,   0,   0,
   4, 250,  12, 244, 250,   0,  27,   0,  12,  27,  36, 247, 244,   0, 247,   0,
@@ -49,8 +49,8 @@
   0,  27,   0, 250, 244,  12, 250,   4,   0,  40,   0,   0, 248,   0,   0,   0,
   4, 250,  12, 244, 250,   0,  27,   0,  12,  27,  36, 247, 244,   0, 247,   0,
   0,   0,   0, 248,   0,   0,  40,   0,   0, 247,   0, 244, 247,  36,  27,  12,
-  0,  27,   0, 250, 244,  12, 250,   4,   0,  40,   0,   0, 248,   0,   0,   0,
-244,  12, 250,   4,   0,  27,   0, 250, 247,  36,  27,  12,   0, 247,   0, 244,
+  0,  27,   0, 250, 244,  12, 250,   4,   0,  40,   0,   0, 248,   0,   0,   0 },
+{ 244,12, 250,   4,   0,  27,   0, 250, 247,  36,  27,  12,   0, 247,   0, 244,
 248,   0,   0,   0,   0,  40,   0,   0, 244,   0, 247,   0,  12,  27,  36, 247,
 250,   0,  27,   0,   4, 250,  12, 244,   0,   0,  40,   0,   0,   0,   0, 248,
 244,  12, 250,   4,   0,  27,   0, 250, 247,  36,  27,  12,   0, 247,   0, 244,
@@ -58,4 +58,4 @@
 250,   0,  27,   0,   4, 250,  12, 244,   0,   0,  40,   0,   0,   0,   0, 248,
 244,  12, 250,   4,   0,  27,   0, 250, 247,  36,  27,  12,   0, 247,   0, 244,
 248,   0,   0,   0,   0,  40,   0,   0, 244,   0, 247,   0,  12,  27,  36, 247,
-250,   0,  27,   0,   4, 250,  12, 244,   0,   0,  40,   0,   0,   0,   0, 248
+250,   0,  27,   0,   4, 250,  12, 244,   0,   0,  40,   0,   0,   0,   0, 248 },
index 1c347633e663b65b1acb561ad6c2e00a868920c2..e0096e07dbdc51e78b1117860379e40ad50aa5ca 100644 (file)
@@ -252,13 +252,18 @@ static u32 isp_set_xclk(struct isp_device *isp, u32 xclk, u8 xclksel)
 }
 
 /*
- * isp_power_settings - Sysconfig settings, for Power Management.
+ * isp_core_init - ISP core settings
  * @isp: OMAP3 ISP device
  * @idle: Consider idle state.
  *
- * Sets the power settings for the ISP, and SBL bus.
+ * Set the power settings for the ISP and SBL bus and cConfigure the HS/VS
+ * interrupt source.
+ *
+ * We need to configure the HS/VS interrupt source before interrupts get
+ * enabled, as the sensor might be free-running and the ISP default setting
+ * (HS edge) would put an unnecessary burden on the CPU.
  */
-static void isp_power_settings(struct isp_device *isp, int idle)
+static void isp_core_init(struct isp_device *isp, int idle)
 {
        isp_reg_writel(isp,
                       ((idle ? ISP_SYSCONFIG_MIDLEMODE_SMARTSTANDBY :
@@ -268,9 +273,10 @@ static void isp_power_settings(struct isp_device *isp, int idle)
                          ISP_SYSCONFIG_AUTOIDLE : 0),
                       OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG);
 
-       if (isp->autoidle)
-               isp_reg_writel(isp, ISPCTRL_SBL_AUTOIDLE, OMAP3_ISP_IOMEM_MAIN,
-                              ISP_CTRL);
+       isp_reg_writel(isp,
+                      (isp->autoidle ? ISPCTRL_SBL_AUTOIDLE : 0) |
+                      ISPCTRL_SYNC_DETECT_VSRISE,
+                      OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
 }
 
 /*
@@ -287,7 +293,7 @@ static void isp_power_settings(struct isp_device *isp, int idle)
 void omap3isp_configure_bridge(struct isp_device *isp,
                               enum ccdc_input_entity input,
                               const struct isp_parallel_platform_data *pdata,
-                              unsigned int shift)
+                              unsigned int shift, unsigned int bridge)
 {
        u32 ispctrl_val;
 
@@ -296,12 +302,12 @@ void omap3isp_configure_bridge(struct isp_device *isp,
        ispctrl_val &= ~ISPCTRL_PAR_CLK_POL_INV;
        ispctrl_val &= ~ISPCTRL_PAR_SER_CLK_SEL_MASK;
        ispctrl_val &= ~ISPCTRL_PAR_BRIDGE_MASK;
+       ispctrl_val |= bridge;
 
        switch (input) {
        case CCDC_INPUT_PARALLEL:
                ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_PARALLEL;
                ispctrl_val |= pdata->clk_pol << ISPCTRL_PAR_CLK_POL_SHIFT;
-               ispctrl_val |= pdata->bridge << ISPCTRL_PAR_BRIDGE_SHIFT;
                shift += pdata->data_lane_shift * 2;
                break;
 
@@ -323,9 +329,6 @@ void omap3isp_configure_bridge(struct isp_device *isp,
 
        ispctrl_val |= ((shift/2) << ISPCTRL_SHIFT_SHIFT) & ISPCTRL_SHIFT_MASK;
 
-       ispctrl_val &= ~ISPCTRL_SYNC_DETECT_MASK;
-       ispctrl_val |= ISPCTRL_SYNC_DETECT_VSRISE;
-
        isp_reg_writel(isp, ispctrl_val, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
 }
 
@@ -1281,7 +1284,9 @@ static void __isp_subclk_update(struct isp_device *isp)
 {
        u32 clk = 0;
 
-       if (isp->subclk_resources & OMAP3_ISP_SUBCLK_H3A)
+       /* AEWB and AF share the same clock. */
+       if (isp->subclk_resources &
+           (OMAP3_ISP_SUBCLK_AEWB | OMAP3_ISP_SUBCLK_AF))
                clk |= ISPCTRL_H3A_CLK_EN;
 
        if (isp->subclk_resources & OMAP3_ISP_SUBCLK_HIST)
@@ -1441,7 +1446,7 @@ static int isp_get_clocks(struct isp_device *isp)
  *
  * Return a pointer to the ISP device structure, or NULL if an error occurred.
  */
-struct isp_device *omap3isp_get(struct isp_device *isp)
+static struct isp_device *__omap3isp_get(struct isp_device *isp, bool irq)
 {
        struct isp_device *__isp = isp;
 
@@ -1460,10 +1465,9 @@ struct isp_device *omap3isp_get(struct isp_device *isp)
        /* We don't want to restore context before saving it! */
        if (isp->has_context)
                isp_restore_ctx(isp);
-       else
-               isp->has_context = 1;
 
-       isp_enable_interrupts(isp);
+       if (irq)
+               isp_enable_interrupts(isp);
 
 out:
        if (__isp != NULL)
@@ -1473,6 +1477,11 @@ out:
        return __isp;
 }
 
+struct isp_device *omap3isp_get(struct isp_device *isp)
+{
+       return __omap3isp_get(isp, true);
+}
+
 /*
  * omap3isp_put - Release the ISP
  *
@@ -1488,8 +1497,10 @@ void omap3isp_put(struct isp_device *isp)
        BUG_ON(isp->ref_count == 0);
        if (--isp->ref_count == 0) {
                isp_disable_interrupts(isp);
-               if (isp->domain)
+               if (isp->domain) {
                        isp_save_ctx(isp);
+                       isp->has_context = 1;
+               }
                /* Reset the ISP if an entity has failed to stop. This is the
                 * only way to recover from such conditions.
                 */
@@ -1973,7 +1984,7 @@ static int __devexit isp_remove(struct platform_device *pdev)
        isp_unregister_entities(isp);
        isp_cleanup_modules(isp);
 
-       omap3isp_get(isp);
+       __omap3isp_get(isp, false);
        iommu_detach_device(isp->domain, &pdev->dev);
        iommu_domain_free(isp->domain);
        isp->domain = NULL;
@@ -2091,7 +2102,7 @@ static int __devinit isp_probe(struct platform_device *pdev)
        if (ret < 0)
                goto error;
 
-       if (omap3isp_get(isp) == NULL)
+       if (__omap3isp_get(isp, false) == NULL)
                goto error;
 
        ret = isp_reset(isp);
@@ -2158,7 +2169,7 @@ static int __devinit isp_probe(struct platform_device *pdev)
        if (ret < 0)
                goto error_modules;
 
-       isp_power_settings(isp, 1);
+       isp_core_init(isp, 1);
        omap3isp_put(isp);
 
        return 0;
index fc7af3e32efd247bd83b16f5197a8a992913e1e8..8be7487c326f7741b5de7145db939667ead5887f 100644 (file)
@@ -90,10 +90,11 @@ enum isp_sbl_resource {
 
 enum isp_subclk_resource {
        OMAP3_ISP_SUBCLK_CCDC           = (1 << 0),
-       OMAP3_ISP_SUBCLK_H3A            = (1 << 1),
-       OMAP3_ISP_SUBCLK_HIST           = (1 << 2),
-       OMAP3_ISP_SUBCLK_PREVIEW        = (1 << 3),
-       OMAP3_ISP_SUBCLK_RESIZER        = (1 << 4),
+       OMAP3_ISP_SUBCLK_AEWB           = (1 << 1),
+       OMAP3_ISP_SUBCLK_AF             = (1 << 2),
+       OMAP3_ISP_SUBCLK_HIST           = (1 << 3),
+       OMAP3_ISP_SUBCLK_PREVIEW        = (1 << 4),
+       OMAP3_ISP_SUBCLK_RESIZER        = (1 << 5),
 };
 
 /* ISP: OMAP 34xx ES 1.0 */
@@ -235,7 +236,7 @@ int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe,
 void omap3isp_configure_bridge(struct isp_device *isp,
                               enum ccdc_input_entity input,
                               const struct isp_parallel_platform_data *pdata,
-                              unsigned int shift);
+                              unsigned int shift, unsigned int bridge);
 
 struct isp_device *omap3isp_get(struct isp_device *isp);
 void omap3isp_put(struct isp_device *isp);
index f1220d3d4970d75fb2dec5c91ce77fc2f01f7aae..aa9df9d71a7b0a455544446ed3e79e7c83ac7218 100644 (file)
@@ -61,6 +61,8 @@ static const unsigned int ccdc_fmts[] = {
        V4L2_MBUS_FMT_SRGGB12_1X12,
        V4L2_MBUS_FMT_SBGGR12_1X12,
        V4L2_MBUS_FMT_SGBRG12_1X12,
+       V4L2_MBUS_FMT_YUYV8_2X8,
+       V4L2_MBUS_FMT_UYVY8_2X8,
 };
 
 /*
@@ -627,9 +629,12 @@ static void ccdc_configure_lpf(struct isp_ccdc_device *ccdc)
 static void ccdc_configure_alaw(struct isp_ccdc_device *ccdc)
 {
        struct isp_device *isp = to_isp_device(ccdc);
+       const struct isp_format_info *info;
        u32 alaw = 0;
 
-       switch (ccdc->syncif.datsz) {
+       info = omap3isp_video_format_info(ccdc->formats[CCDC_PAD_SINK].code);
+
+       switch (info->width) {
        case 8:
                return;
 
@@ -813,6 +818,7 @@ static void ccdc_config_vp(struct isp_ccdc_device *ccdc)
 {
        struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->subdev.entity);
        struct isp_device *isp = to_isp_device(ccdc);
+       const struct isp_format_info *info;
        unsigned long l3_ick = pipe->l3_ick;
        unsigned int max_div = isp->revision == ISP_REVISION_15_0 ? 64 : 8;
        unsigned int div = 0;
@@ -821,7 +827,9 @@ static void ccdc_config_vp(struct isp_ccdc_device *ccdc)
        fmtcfg_vp = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG)
                  & ~(ISPCCDC_FMTCFG_VPIN_MASK | ISPCCDC_FMTCFG_VPIF_FRQ_MASK);
 
-       switch (ccdc->syncif.datsz) {
+       info = omap3isp_video_format_info(ccdc->formats[CCDC_PAD_SINK].code);
+
+       switch (info->width) {
        case 8:
        case 10:
                fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_9_0;
@@ -835,7 +843,7 @@ static void ccdc_config_vp(struct isp_ccdc_device *ccdc)
        case 13:
                fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_12_3;
                break;
-       };
+       }
 
        if (pipe->input)
                div = DIV_ROUND_UP(l3_ick, pipe->max_rate);
@@ -959,26 +967,28 @@ void omap3isp_ccdc_max_rate(struct isp_ccdc_device *ccdc,
 /*
  * ccdc_config_sync_if - Set CCDC sync interface configuration
  * @ccdc: Pointer to ISP CCDC device.
- * @syncif: Structure containing the sync parameters like field state, CCDC in
- *          master/slave mode, raw/yuv data, polarity of data, field, hs, vs
- *          signals.
+ * @pdata: Parallel interface platform data (may be NULL)
+ * @data_size: Data size
  */
 static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc,
-                               struct ispccdc_syncif *syncif)
+                               struct isp_parallel_platform_data *pdata,
+                               unsigned int data_size)
 {
        struct isp_device *isp = to_isp_device(ccdc);
-       u32 syn_mode = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC,
-                                    ISPCCDC_SYN_MODE);
+       const struct v4l2_mbus_framefmt *format;
+       u32 syn_mode = ISPCCDC_SYN_MODE_VDHDEN;
 
-       syn_mode |= ISPCCDC_SYN_MODE_VDHDEN;
+       format = &ccdc->formats[CCDC_PAD_SINK];
 
-       if (syncif->fldstat)
-               syn_mode |= ISPCCDC_SYN_MODE_FLDSTAT;
-       else
-               syn_mode &= ~ISPCCDC_SYN_MODE_FLDSTAT;
+       if (format->code == V4L2_MBUS_FMT_YUYV8_2X8 ||
+           format->code == V4L2_MBUS_FMT_UYVY8_2X8) {
+               /* The bridge is enabled for YUV8 formats. Configure the input
+                * mode accordingly.
+                */
+               syn_mode |= ISPCCDC_SYN_MODE_INPMOD_YCBCR16;
+       }
 
-       syn_mode &= ~ISPCCDC_SYN_MODE_DATSIZ_MASK;
-       switch (syncif->datsz) {
+       switch (data_size) {
        case 8:
                syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_8;
                break;
@@ -991,55 +1001,31 @@ static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc,
        case 12:
                syn_mode |= ISPCCDC_SYN_MODE_DATSIZ_12;
                break;
-       };
-
-       if (syncif->fldmode)
-               syn_mode |= ISPCCDC_SYN_MODE_FLDMODE;
-       else
-               syn_mode &= ~ISPCCDC_SYN_MODE_FLDMODE;
+       }
 
-       if (syncif->datapol)
+       if (pdata && pdata->data_pol)
                syn_mode |= ISPCCDC_SYN_MODE_DATAPOL;
-       else
-               syn_mode &= ~ISPCCDC_SYN_MODE_DATAPOL;
-
-       if (syncif->fldpol)
-               syn_mode |= ISPCCDC_SYN_MODE_FLDPOL;
-       else
-               syn_mode &= ~ISPCCDC_SYN_MODE_FLDPOL;
 
-       if (syncif->hdpol)
+       if (pdata && pdata->hs_pol)
                syn_mode |= ISPCCDC_SYN_MODE_HDPOL;
-       else
-               syn_mode &= ~ISPCCDC_SYN_MODE_HDPOL;
 
-       if (syncif->vdpol)
+       if (pdata && pdata->vs_pol)
                syn_mode |= ISPCCDC_SYN_MODE_VDPOL;
-       else
-               syn_mode &= ~ISPCCDC_SYN_MODE_VDPOL;
-
-       if (syncif->ccdc_mastermode) {
-               syn_mode |= ISPCCDC_SYN_MODE_FLDOUT | ISPCCDC_SYN_MODE_VDHDOUT;
-               isp_reg_writel(isp,
-                              syncif->hs_width << ISPCCDC_HD_VD_WID_HDW_SHIFT
-                            | syncif->vs_width << ISPCCDC_HD_VD_WID_VDW_SHIFT,
-                              OMAP3_ISP_IOMEM_CCDC,
-                              ISPCCDC_HD_VD_WID);
-
-               isp_reg_writel(isp,
-                              syncif->ppln << ISPCCDC_PIX_LINES_PPLN_SHIFT
-                            | syncif->hlprf << ISPCCDC_PIX_LINES_HLPRF_SHIFT,
-                              OMAP3_ISP_IOMEM_CCDC,
-                              ISPCCDC_PIX_LINES);
-       } else
-               syn_mode &= ~(ISPCCDC_SYN_MODE_FLDOUT |
-                             ISPCCDC_SYN_MODE_VDHDOUT);
 
        isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
 
-       if (!syncif->bt_r656_en)
-               isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_REC656IF,
-                           ISPCCDC_REC656IF_R656ON);
+       /* The CCDC_CFG.Y8POS bit is used in YCbCr8 input mode only. The
+        * hardware seems to ignore it in all other input modes.
+        */
+       if (format->code == V4L2_MBUS_FMT_UYVY8_2X8)
+               isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
+                           ISPCCDC_CFG_Y8POS);
+       else
+               isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
+                           ISPCCDC_CFG_Y8POS);
+
+       isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_REC656IF,
+                   ISPCCDC_REC656IF_R656ON);
 }
 
 /* CCDC formats descriptions */
@@ -1128,6 +1114,7 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
        unsigned int depth_in = 0;
        struct media_pad *pad;
        unsigned long flags;
+       unsigned int bridge;
        unsigned int shift;
        u32 syn_mode;
        u32 ccdc_pattern;
@@ -1138,28 +1125,31 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
                pdata = &((struct isp_v4l2_subdevs_group *)sensor->host_priv)
                        ->bus.parallel;
 
-       /* Compute shift value for lane shifter to configure the bridge. */
+       /* Compute the lane shifter shift value and enable the bridge when the
+        * input format is YUV.
+        */
        fmt_src.pad = pad->index;
        fmt_src.which = V4L2_SUBDEV_FORMAT_ACTIVE;
        if (!v4l2_subdev_call(sensor, pad, get_fmt, NULL, &fmt_src)) {
                fmt_info = omap3isp_video_format_info(fmt_src.format.code);
-               depth_in = fmt_info->bpp;
+               depth_in = fmt_info->width;
        }
 
        fmt_info = omap3isp_video_format_info
                (isp->isp_ccdc.formats[CCDC_PAD_SINK].code);
-       depth_out = fmt_info->bpp;
-
+       depth_out = fmt_info->width;
        shift = depth_in - depth_out;
-       omap3isp_configure_bridge(isp, ccdc->input, pdata, shift);
 
-       ccdc->syncif.datsz = depth_out;
-       ccdc->syncif.hdpol = pdata ? pdata->hs_pol : 0;
-       ccdc->syncif.vdpol = pdata ? pdata->vs_pol : 0;
-       ccdc_config_sync_if(ccdc, &ccdc->syncif);
+       if (fmt_info->code == V4L2_MBUS_FMT_YUYV8_2X8)
+               bridge = ISPCTRL_PAR_BRIDGE_LENDIAN;
+       else if (fmt_info->code == V4L2_MBUS_FMT_UYVY8_2X8)
+               bridge = ISPCTRL_PAR_BRIDGE_BENDIAN;
+       else
+               bridge = ISPCTRL_PAR_BRIDGE_DISABLE;
+
+       omap3isp_configure_bridge(isp, ccdc->input, pdata, shift, bridge);
 
-       /* CCDC_PAD_SINK */
-       format = &ccdc->formats[CCDC_PAD_SINK];
+       ccdc_config_sync_if(ccdc, pdata, depth_out);
 
        syn_mode = isp_reg_readl(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
 
@@ -1178,13 +1168,8 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
        else
                syn_mode &= ~ISPCCDC_SYN_MODE_SDR2RSZ;
 
-       /* Use PACK8 mode for 1byte per pixel formats. */
-       if (omap3isp_video_format_info(format->code)->bpp <= 8)
-               syn_mode |= ISPCCDC_SYN_MODE_PACK8;
-       else
-               syn_mode &= ~ISPCCDC_SYN_MODE_PACK8;
-
-       isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
+       /* CCDC_PAD_SINK */
+       format = &ccdc->formats[CCDC_PAD_SINK];
 
        /* Mosaic filter */
        switch (format->code) {
@@ -1215,6 +1200,7 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
                       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VDINT);
 
        /* CCDC_PAD_SOURCE_OF */
+       format = &ccdc->formats[CCDC_PAD_SOURCE_OF];
        crop = &ccdc->crop;
 
        isp_reg_writel(isp, (crop->left << ISPCCDC_HORZ_INFO_SPH_SHIFT) |
@@ -1228,6 +1214,24 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
 
        ccdc_config_outlineoffset(ccdc, ccdc->video_out.bpl_value, 0, 0);
 
+       /* The CCDC outputs data in UYVY order by default. Swap bytes to get
+        * YUYV.
+        */
+       if (format->code == V4L2_MBUS_FMT_YUYV8_1X16)
+               isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
+                           ISPCCDC_CFG_BSWD);
+       else
+               isp_reg_clr(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
+                           ISPCCDC_CFG_BSWD);
+
+       /* Use PACK8 mode for 1byte per pixel formats. */
+       if (omap3isp_video_format_info(format->code)->width <= 8)
+               syn_mode |= ISPCCDC_SYN_MODE_PACK8;
+       else
+               syn_mode &= ~ISPCCDC_SYN_MODE_PACK8;
+
+       isp_reg_writel(isp, syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
+
        /* CCDC_PAD_SOURCE_VP */
        format = &ccdc->formats[CCDC_PAD_SOURCE_VP];
 
@@ -1242,6 +1246,7 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
                       (format->height << ISPCCDC_VP_OUT_VERT_NUM_SHIFT),
                       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VP_OUT);
 
+       /* Lens shading correction. */
        spin_lock_irqsave(&ccdc->lsc.req_lock, flags);
        if (ccdc->lsc.request == NULL)
                goto unlock;
@@ -1819,8 +1824,8 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
                unsigned int pad, struct v4l2_mbus_framefmt *fmt,
                enum v4l2_subdev_format_whence which)
 {
-       struct v4l2_mbus_framefmt *format;
        const struct isp_format_info *info;
+       enum v4l2_mbus_pixelcode pixelcode;
        unsigned int width = fmt->width;
        unsigned int height = fmt->height;
        struct v4l2_rect *crop;
@@ -1828,9 +1833,6 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
 
        switch (pad) {
        case CCDC_PAD_SINK:
-               /* TODO: If the CCDC output formatter pad is connected directly
-                * to the resizer, only YUV formats can be used.
-                */
                for (i = 0; i < ARRAY_SIZE(ccdc_fmts); i++) {
                        if (fmt->code == ccdc_fmts[i])
                                break;
@@ -1846,8 +1848,26 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
                break;
 
        case CCDC_PAD_SOURCE_OF:
-               format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which);
-               memcpy(fmt, format, sizeof(*fmt));
+               pixelcode = fmt->code;
+               *fmt = *__ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which);
+
+               /* YUV formats are converted from 2X8 to 1X16 by the bridge and
+                * can be byte-swapped.
+                */
+               if (fmt->code == V4L2_MBUS_FMT_YUYV8_2X8 ||
+                   fmt->code == V4L2_MBUS_FMT_UYVY8_2X8) {
+                       /* Use the user requested format if YUV. */
+                       if (pixelcode == V4L2_MBUS_FMT_YUYV8_2X8 ||
+                           pixelcode == V4L2_MBUS_FMT_UYVY8_2X8 ||
+                           pixelcode == V4L2_MBUS_FMT_YUYV8_1X16 ||
+                           pixelcode == V4L2_MBUS_FMT_UYVY8_1X16)
+                               fmt->code = pixelcode;
+
+                       if (fmt->code == V4L2_MBUS_FMT_YUYV8_2X8)
+                               fmt->code = V4L2_MBUS_FMT_YUYV8_1X16;
+                       else if (fmt->code == V4L2_MBUS_FMT_UYVY8_2X8)
+                               fmt->code = V4L2_MBUS_FMT_UYVY8_1X16;
+               }
 
                /* Hardcode the output size to the crop rectangle size. */
                crop = __ccdc_get_crop(ccdc, fh, which);
@@ -1856,13 +1876,17 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
                break;
 
        case CCDC_PAD_SOURCE_VP:
-               format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which);
-               memcpy(fmt, format, sizeof(*fmt));
+               *fmt = *__ccdc_get_format(ccdc, fh, CCDC_PAD_SINK, which);
 
                /* The video port interface truncates the data to 10 bits. */
                info = omap3isp_video_format_info(fmt->code);
                fmt->code = info->truncated;
 
+               /* YUV formats are not supported by the video port. */
+               if (fmt->code == V4L2_MBUS_FMT_YUYV8_2X8 ||
+                   fmt->code == V4L2_MBUS_FMT_UYVY8_2X8)
+                       fmt->code = 0;
+
                /* The number of lines that can be clocked out from the video
                 * port output must be at least one line less than the number
                 * of input lines.
@@ -1945,14 +1969,46 @@ static int ccdc_enum_mbus_code(struct v4l2_subdev *sd,
                break;
 
        case CCDC_PAD_SOURCE_OF:
+               format = __ccdc_get_format(ccdc, fh, code->pad,
+                                          V4L2_SUBDEV_FORMAT_TRY);
+
+               if (format->code == V4L2_MBUS_FMT_YUYV8_2X8 ||
+                   format->code == V4L2_MBUS_FMT_UYVY8_2X8) {
+                       /* In YUV mode the CCDC can swap bytes. */
+                       if (code->index == 0)
+                               code->code = V4L2_MBUS_FMT_YUYV8_1X16;
+                       else if (code->index == 1)
+                               code->code = V4L2_MBUS_FMT_UYVY8_1X16;
+                       else
+                               return -EINVAL;
+               } else {
+                       /* In raw mode, no configurable format confversion is
+                        * available.
+                        */
+                       if (code->index == 0)
+                               code->code = format->code;
+                       else
+                               return -EINVAL;
+               }
+               break;
+
        case CCDC_PAD_SOURCE_VP:
-               /* No format conversion inside CCDC */
+               /* The CCDC supports no configurable format conversion
+                * compatible with the video port. Enumerate a single output
+                * format code.
+                */
                if (code->index != 0)
                        return -EINVAL;
 
-               format = __ccdc_get_format(ccdc, fh, CCDC_PAD_SINK,
+               format = __ccdc_get_format(ccdc, fh, code->pad,
                                           V4L2_SUBDEV_FORMAT_TRY);
 
+               /* A pixel code equal to 0 means that the video port doesn't
+                * support the input format. Don't enumerate any pixel code.
+                */
+               if (format->code == 0)
+                       return -EINVAL;
+
                code->code = format->code;
                break;
 
@@ -2182,7 +2238,7 @@ static bool ccdc_is_shiftable(enum v4l2_mbus_pixelcode in,
        if (in_info->flavor != out_info->flavor)
                return false;
 
-       return in_info->bpp - out_info->bpp + additional_shift <= 6;
+       return in_info->width - out_info->width + additional_shift <= 6;
 }
 
 static int ccdc_link_validate(struct v4l2_subdev *sd,
@@ -2487,14 +2543,6 @@ int omap3isp_ccdc_init(struct isp_device *isp)
        INIT_LIST_HEAD(&ccdc->lsc.free_queue);
        spin_lock_init(&ccdc->lsc.req_lock);
 
-       ccdc->syncif.ccdc_mastermode = 0;
-       ccdc->syncif.datapol = 0;
-       ccdc->syncif.datsz = 0;
-       ccdc->syncif.fldmode = 0;
-       ccdc->syncif.fldout = 0;
-       ccdc->syncif.fldpol = 0;
-       ccdc->syncif.fldstat = 0;
-
        ccdc->clamp.oblen = 0;
        ccdc->clamp.dcsubval = 0;
 
index 890f6b3a68fd04530bcdd28380f144e0539e1a12..a5da9e19edbf632e5e22bb1920944cec66157b27 100644 (file)
@@ -46,40 +46,6 @@ enum ccdc_input_entity {
 
 #define        OMAP3ISP_CCDC_NEVENTS   16
 
-/*
- * struct ispccdc_syncif - Structure for Sync Interface between sensor and CCDC
- * @ccdc_mastermode: Master mode. 1 - Master, 0 - Slave.
- * @fldstat: Field state. 0 - Odd Field, 1 - Even Field.
- * @datsz: Data size.
- * @fldmode: 0 - Progressive, 1 - Interlaced.
- * @datapol: 0 - Positive, 1 - Negative.
- * @fldpol: 0 - Positive, 1 - Negative.
- * @hdpol: 0 - Positive, 1 - Negative.
- * @vdpol: 0 - Positive, 1 - Negative.
- * @fldout: 0 - Input, 1 - Output.
- * @hs_width: Width of the Horizontal Sync pulse, used for HS/VS Output.
- * @vs_width: Width of the Vertical Sync pulse, used for HS/VS Output.
- * @ppln: Number of pixels per line, used for HS/VS Output.
- * @hlprf: Number of half lines per frame, used for HS/VS Output.
- * @bt_r656_en: 1 - Enable ITU-R BT656 mode, 0 - Sync mode.
- */
-struct ispccdc_syncif {
-       u8 ccdc_mastermode;
-       u8 fldstat;
-       u8 datsz;
-       u8 fldmode;
-       u8 datapol;
-       u8 fldpol;
-       u8 hdpol;
-       u8 vdpol;
-       u8 fldout;
-       u8 hs_width;
-       u8 vs_width;
-       u8 ppln;
-       u8 hlprf;
-       u8 bt_r656_en;
-};
-
 enum ispccdc_lsc_state {
        LSC_STATE_STOPPED = 0,
        LSC_STATE_STOPPING = 1,
@@ -153,7 +119,6 @@ struct ispccdc_lsc {
  * @lsc: Lens shading compensation configuration
  * @update: Bitmask of controls to update during the next interrupt
  * @shadow_update: Controls update in progress by userspace
- * @syncif: Interface synchronization configuration
  * @underrun: A buffer underrun occurred and a new buffer has been queued
  * @state: Streaming state
  * @lock: Serializes shadow_update with interrupt handler
@@ -182,8 +147,6 @@ struct isp_ccdc_device {
        unsigned int update;
        unsigned int shadow_update;
 
-       struct ispccdc_syncif syncif;
-
        unsigned int underrun:1;
        enum isp_pipeline_stream_state state;
        spinlock_t lock;
index a1724362b6d5e039307eeb7849244f43da97a5a0..6a3ff792af7d6a3b07042bc2d7c582b9f9ba5b95 100644 (file)
@@ -96,11 +96,12 @@ static const unsigned int csi2_input_fmts[] = {
        V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8,
        V4L2_MBUS_FMT_SGBRG10_1X10,
        V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8,
+       V4L2_MBUS_FMT_YUYV8_2X8,
 };
 
 /* To set the format on the CSI2 requires a mapping function that takes
  * the following inputs:
- * - 2 different formats (at this time)
+ * - 3 different formats (at this time)
  * - 2 destinations (mem, vp+mem) (vp only handled separately)
  * - 2 decompression options (on, off)
  * - 2 isp revisions (certain format must be handled differently on OMAP3630)
@@ -108,7 +109,7 @@ static const unsigned int csi2_input_fmts[] = {
  * Array indices as follows: [format][dest][decompr][is_3630]
  * Not all combinations are valid. 0 means invalid.
  */
-static const u16 __csi2_fmt_map[2][2][2][2] = {
+static const u16 __csi2_fmt_map[3][2][2][2] = {
        /* RAW10 formats */
        {
                /* Output to memory */
@@ -147,6 +148,25 @@ static const u16 __csi2_fmt_map[2][2][2][2] = {
                          CSI2_USERDEF_8BIT_DATA1_DPCM10_VP },
                },
        },
+       /* YUYV8 2X8 formats */
+       {
+               /* Output to memory */
+               {
+                       /* No DPCM decompression */
+                       { CSI2_PIX_FMT_YUV422_8BIT,
+                         CSI2_PIX_FMT_YUV422_8BIT },
+                       /* DPCM decompression */
+                       { 0, 0 },
+               },
+               /* Output to both */
+               {
+                       /* No DPCM decompression */
+                       { CSI2_PIX_FMT_YUV422_8BIT_VP,
+                         CSI2_PIX_FMT_YUV422_8BIT_VP },
+                       /* DPCM decompression */
+                       { 0, 0 },
+               },
+       },
 };
 
 /*
@@ -173,6 +193,9 @@ static u16 csi2_ctx_map_format(struct isp_csi2_device *csi2)
        case V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8:
                fmtidx = 1;
                break;
+       case V4L2_MBUS_FMT_YUYV8_2X8:
+               fmtidx = 2;
+               break;
        default:
                WARN(1, KERN_ERR "CSI2: pixel format %08x unsupported!\n",
                     fmt->code);
index a3c76bf1817585997ebe7dcad9bcdbe3c7345aa1..036e9961d0279a174f075b56dbec29fae1a9ffa3 100644 (file)
@@ -93,17 +93,11 @@ static void h3a_aewb_enable(struct ispstat *aewb, int enable)
        if (enable) {
                isp_reg_set(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
                            ISPH3A_PCR_AEW_EN);
-               /* This bit is already set if AF is enabled */
-               if (aewb->isp->isp_af.state != ISPSTAT_ENABLED)
-                       isp_reg_set(aewb->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
-                                   ISPCTRL_H3A_CLK_EN);
+               omap3isp_subclk_enable(aewb->isp, OMAP3_ISP_SUBCLK_AEWB);
        } else {
                isp_reg_clr(aewb->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
                            ISPH3A_PCR_AEW_EN);
-               /* This bit can't be cleared if AF is enabled */
-               if (aewb->isp->isp_af.state != ISPSTAT_ENABLED)
-                       isp_reg_clr(aewb->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
-                                   ISPCTRL_H3A_CLK_EN);
+               omap3isp_subclk_disable(aewb->isp, OMAP3_ISP_SUBCLK_AEWB);
        }
 }
 
index 58e0bc41489971a16d47e0afcf6722fc318687dd..42ccce318d5d08adf107953c5662146dc56a9aeb 100644 (file)
@@ -143,17 +143,11 @@ static void h3a_af_enable(struct ispstat *af, int enable)
        if (enable) {
                isp_reg_set(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
                            ISPH3A_PCR_AF_EN);
-               /* This bit is already set if AEWB is enabled */
-               if (af->isp->isp_aewb.state != ISPSTAT_ENABLED)
-                       isp_reg_set(af->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
-                                   ISPCTRL_H3A_CLK_EN);
+               omap3isp_subclk_enable(af->isp, OMAP3_ISP_SUBCLK_AF);
        } else {
                isp_reg_clr(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
                            ISPH3A_PCR_AF_EN);
-               /* This bit can't be cleared if AEWB is enabled */
-               if (af->isp->isp_aewb.state != ISPSTAT_ENABLED)
-                       isp_reg_clr(af->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
-                                   ISPCTRL_H3A_CLK_EN);
+               omap3isp_subclk_disable(af->isp, OMAP3_ISP_SUBCLK_AF);
        }
 }
 
index 1163907bcddcb17fcdbb3fb8070d697f0842dc98..d1a8dee5e1ca4720adb96fde8c87e6280187d862 100644 (file)
@@ -167,13 +167,11 @@ static void hist_enable(struct ispstat *hist, int enable)
        if (enable) {
                isp_reg_set(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR,
                            ISPHIST_PCR_ENABLE);
-               isp_reg_set(hist->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
-                           ISPCTRL_HIST_CLK_EN);
+               omap3isp_subclk_enable(hist->isp, OMAP3_ISP_SUBCLK_HIST);
        } else {
                isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR,
                            ISPHIST_PCR_ENABLE);
-               isp_reg_clr(hist->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
-                           ISPCTRL_HIST_CLK_EN);
+               omap3isp_subclk_disable(hist->isp, OMAP3_ISP_SUBCLK_HIST);
        }
 }
 
index 53f5a703e31abd218692a679cd4b0ccf9b16d98a..1ae1c0909ed1c5f5302dd21982f32ec39f19044e 100644 (file)
@@ -131,7 +131,7 @@ static struct omap3isp_prev_csc flr_prev_csc = {
  * CFA Filter Coefficient Table
  *
  */
-static u32 cfa_coef_table[] = {
+static u32 cfa_coef_table[4][OMAP3ISP_PREV_CFA_BLK_SIZE] = {
 #include "cfa_coef_table.h"
 };
 
@@ -157,85 +157,74 @@ static u32 luma_enhance_table[] = {
 };
 
 /*
- * preview_enable_invalaw - Enable/Disable Inverse A-Law module in Preview.
- * @enable: 1 - Reverse the A-Law done in CCDC.
+ * preview_config_luma_enhancement - Configure the Luminance Enhancement table
  */
 static void
-preview_enable_invalaw(struct isp_prev_device *prev, u8 enable)
+preview_config_luma_enhancement(struct isp_prev_device *prev,
+                               const struct prev_params *params)
 {
        struct isp_device *isp = to_isp_device(prev);
+       const struct omap3isp_prev_luma *yt = &params->luma;
+       unsigned int i;
 
-       if (enable)
-               isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
-                           ISPPRV_PCR_WIDTH | ISPPRV_PCR_INVALAW);
-       else
-               isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
-                           ISPPRV_PCR_WIDTH | ISPPRV_PCR_INVALAW);
+       isp_reg_writel(isp, ISPPRV_YENH_TABLE_ADDR,
+                      OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
+       for (i = 0; i < OMAP3ISP_PREV_YENH_TBL_SIZE; i++) {
+               isp_reg_writel(isp, yt->table[i],
+                              OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
+       }
 }
 
 /*
- * preview_enable_drkframe_capture - Enable/Disable of the darkframe capture.
- * @prev -
- * @enable: 1 - Enable, 0 - Disable
- *
- * NOTE: PRV_WSDR_ADDR and PRV_WADD_OFFSET must be set also
- * The process is applied for each captured frame.
+ * preview_enable_luma_enhancement - Enable/disable Luminance Enhancement
  */
 static void
-preview_enable_drkframe_capture(struct isp_prev_device *prev, u8 enable)
+preview_enable_luma_enhancement(struct isp_prev_device *prev, bool enable)
 {
        struct isp_device *isp = to_isp_device(prev);
 
        if (enable)
                isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
-                           ISPPRV_PCR_DRKFCAP);
+                           ISPPRV_PCR_YNENHEN);
        else
                isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
-                           ISPPRV_PCR_DRKFCAP);
+                           ISPPRV_PCR_YNENHEN);
 }
 
 /*
- * preview_enable_drkframe - Enable/Disable of the darkframe subtract.
- * @enable: 1 - Acquires memory bandwidth since the pixels in each frame is
- *          subtracted with the pixels in the current frame.
- *
- * The process is applied for each captured frame.
+ * preview_enable_invalaw - Enable/disable Inverse A-Law decompression
  */
-static void
-preview_enable_drkframe(struct isp_prev_device *prev, u8 enable)
+static void preview_enable_invalaw(struct isp_prev_device *prev, bool enable)
 {
        struct isp_device *isp = to_isp_device(prev);
 
        if (enable)
                isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
-                           ISPPRV_PCR_DRKFEN);
+                           ISPPRV_PCR_WIDTH | ISPPRV_PCR_INVALAW);
        else
                isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
-                           ISPPRV_PCR_DRKFEN);
+                           ISPPRV_PCR_WIDTH | ISPPRV_PCR_INVALAW);
 }
 
 /*
- * preview_config_drkf_shadcomp - Configures shift value in shading comp.
- * @scomp_shtval: 3bit value of shift used in shading compensation.
+ * preview_config_hmed - Configure the Horizontal Median Filter
  */
-static void
-preview_config_drkf_shadcomp(struct isp_prev_device *prev,
-                            const void *scomp_shtval)
+static void preview_config_hmed(struct isp_prev_device *prev,
+                               const struct prev_params *params)
 {
        struct isp_device *isp = to_isp_device(prev);
-       const u32 *shtval = scomp_shtval;
+       const struct omap3isp_prev_hmed *hmed = &params->hmed;
 
-       isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
-                       ISPPRV_PCR_SCOMP_SFT_MASK,
-                       *shtval << ISPPRV_PCR_SCOMP_SFT_SHIFT);
+       isp_reg_writel(isp, (hmed->odddist == 1 ? 0 : ISPPRV_HMED_ODDDIST) |
+                      (hmed->evendist == 1 ? 0 : ISPPRV_HMED_EVENDIST) |
+                      (hmed->thres << ISPPRV_HMED_THRESHOLD_SHIFT),
+                      OMAP3_ISP_IOMEM_PREV, ISPPRV_HMED);
 }
 
 /*
- * preview_enable_hmed - Enables/Disables of the Horizontal Median Filter.
- * @enable: 1 - Enables Horizontal Median Filter.
+ * preview_enable_hmed - Enable/disable the Horizontal Median Filter
  */
-static void
-preview_enable_hmed(struct isp_prev_device *prev, u8 enable)
+static void preview_enable_hmed(struct isp_prev_device *prev, bool enable)
 {
        struct isp_device *isp = to_isp_device(prev);
 
@@ -248,81 +237,27 @@ preview_enable_hmed(struct isp_prev_device *prev, u8 enable)
 }
 
 /*
- * preview_config_hmed - Configures the Horizontal Median Filter.
- * @prev_hmed: Structure containing the odd and even distance between the
- *             pixels in the image along with the filter threshold.
- */
-static void
-preview_config_hmed(struct isp_prev_device *prev, const void *prev_hmed)
-{
-       struct isp_device *isp = to_isp_device(prev);
-       const struct omap3isp_prev_hmed *hmed = prev_hmed;
-
-       isp_reg_writel(isp, (hmed->odddist == 1 ? 0 : ISPPRV_HMED_ODDDIST) |
-                      (hmed->evendist == 1 ? 0 : ISPPRV_HMED_EVENDIST) |
-                      (hmed->thres << ISPPRV_HMED_THRESHOLD_SHIFT),
-                      OMAP3_ISP_IOMEM_PREV, ISPPRV_HMED);
-}
-
-/*
- * preview_config_noisefilter - Configures the Noise Filter.
- * @prev_nf: Structure containing the noisefilter table, strength to be used
- *           for the noise filter and the defect correction enable flag.
- */
-static void
-preview_config_noisefilter(struct isp_prev_device *prev, const void *prev_nf)
-{
-       struct isp_device *isp = to_isp_device(prev);
-       const struct omap3isp_prev_nf *nf = prev_nf;
-       unsigned int i;
-
-       isp_reg_writel(isp, nf->spread, OMAP3_ISP_IOMEM_PREV, ISPPRV_NF);
-       isp_reg_writel(isp, ISPPRV_NF_TABLE_ADDR,
-                      OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
-       for (i = 0; i < OMAP3ISP_PREV_NF_TBL_SIZE; i++) {
-               isp_reg_writel(isp, nf->table[i],
-                              OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
-       }
-}
-
-/*
- * preview_config_dcor - Configures the defect correction
- * @prev_dcor: Structure containing the defect correct thresholds
- */
-static void
-preview_config_dcor(struct isp_prev_device *prev, const void *prev_dcor)
-{
-       struct isp_device *isp = to_isp_device(prev);
-       const struct omap3isp_prev_dcor *dcor = prev_dcor;
-
-       isp_reg_writel(isp, dcor->detect_correct[0],
-                      OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR0);
-       isp_reg_writel(isp, dcor->detect_correct[1],
-                      OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR1);
-       isp_reg_writel(isp, dcor->detect_correct[2],
-                      OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR2);
-       isp_reg_writel(isp, dcor->detect_correct[3],
-                      OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR3);
-       isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
-                       ISPPRV_PCR_DCCOUP,
-                       dcor->couplet_mode_en ? ISPPRV_PCR_DCCOUP : 0);
-}
-
-/*
- * preview_config_cfa - Configures the CFA Interpolation parameters.
- * @prev_cfa: Structure containing the CFA interpolation table, CFA format
- *            in the image, vertical and horizontal gradient threshold.
- */
-static void
-preview_config_cfa(struct isp_prev_device *prev, const void *prev_cfa)
-{
+ * preview_config_cfa - Configure CFA Interpolation for Bayer formats
+ *
+ * The CFA table is organised in four blocks, one per Bayer component. The
+ * hardware expects blocks to follow the Bayer order of the input data, while
+ * the driver stores the table in GRBG order in memory. The blocks need to be
+ * reordered to support non-GRBG Bayer patterns.
+ */
+static void preview_config_cfa(struct isp_prev_device *prev,
+                              const struct prev_params *params)
+{
+       static const unsigned int cfa_coef_order[4][4] = {
+               { 0, 1, 2, 3 }, /* GRBG */
+               { 1, 0, 3, 2 }, /* RGGB */
+               { 2, 3, 0, 1 }, /* BGGR */
+               { 3, 2, 1, 0 }, /* GBRG */
+       };
+       const unsigned int *order = cfa_coef_order[prev->params.cfa_order];
+       const struct omap3isp_prev_cfa *cfa = &params->cfa;
        struct isp_device *isp = to_isp_device(prev);
-       const struct omap3isp_prev_cfa *cfa = prev_cfa;
        unsigned int i;
-
-       isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
-                       ISPPRV_PCR_CFAFMT_MASK,
-                       cfa->format << ISPPRV_PCR_CFAFMT_SHIFT);
+       unsigned int j;
 
        isp_reg_writel(isp,
                (cfa->gradthrs_vert << ISPPRV_CFA_GRADTH_VER_SHIFT) |
@@ -332,73 +267,24 @@ preview_config_cfa(struct isp_prev_device *prev, const void *prev_cfa)
        isp_reg_writel(isp, ISPPRV_CFA_TABLE_ADDR,
                       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
 
-       for (i = 0; i < OMAP3ISP_PREV_CFA_TBL_SIZE; i++) {
-               isp_reg_writel(isp, cfa->table[i],
-                              OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
-       }
-}
-
-/*
- * preview_config_gammacorrn - Configures the Gamma Correction table values
- * @gtable: Structure containing the table for red, blue, green gamma table.
- */
-static void
-preview_config_gammacorrn(struct isp_prev_device *prev, const void *gtable)
-{
-       struct isp_device *isp = to_isp_device(prev);
-       const struct omap3isp_prev_gtables *gt = gtable;
-       unsigned int i;
-
-       isp_reg_writel(isp, ISPPRV_REDGAMMA_TABLE_ADDR,
-                      OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
-       for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++)
-               isp_reg_writel(isp, gt->red[i], OMAP3_ISP_IOMEM_PREV,
-                              ISPPRV_SET_TBL_DATA);
-
-       isp_reg_writel(isp, ISPPRV_GREENGAMMA_TABLE_ADDR,
-                      OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
-       for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++)
-               isp_reg_writel(isp, gt->green[i], OMAP3_ISP_IOMEM_PREV,
-                              ISPPRV_SET_TBL_DATA);
-
-       isp_reg_writel(isp, ISPPRV_BLUEGAMMA_TABLE_ADDR,
-                      OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
-       for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++)
-               isp_reg_writel(isp, gt->blue[i], OMAP3_ISP_IOMEM_PREV,
-                              ISPPRV_SET_TBL_DATA);
-}
-
-/*
- * preview_config_luma_enhancement - Sets the Luminance Enhancement table.
- * @ytable: Structure containing the table for Luminance Enhancement table.
- */
-static void
-preview_config_luma_enhancement(struct isp_prev_device *prev,
-                               const void *ytable)
-{
-       struct isp_device *isp = to_isp_device(prev);
-       const struct omap3isp_prev_luma *yt = ytable;
-       unsigned int i;
+       for (i = 0; i < 4; ++i) {
+               const __u32 *block = cfa->table[order[i]];
 
-       isp_reg_writel(isp, ISPPRV_YENH_TABLE_ADDR,
-                      OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
-       for (i = 0; i < OMAP3ISP_PREV_YENH_TBL_SIZE; i++) {
-               isp_reg_writel(isp, yt->table[i],
-                              OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
+               for (j = 0; j < OMAP3ISP_PREV_CFA_BLK_SIZE; ++j)
+                       isp_reg_writel(isp, block[j], OMAP3_ISP_IOMEM_PREV,
+                                      ISPPRV_SET_TBL_DATA);
        }
 }
 
 /*
- * preview_config_chroma_suppression - Configures the Chroma Suppression.
- * @csup: Structure containing the threshold value for suppression
- *        and the hypass filter enable flag.
+ * preview_config_chroma_suppression - Configure Chroma Suppression
  */
 static void
 preview_config_chroma_suppression(struct isp_prev_device *prev,
-                                 const void *csup)
+                                 const struct prev_params *params)
 {
        struct isp_device *isp = to_isp_device(prev);
-       const struct omap3isp_prev_csup *cs = csup;
+       const struct omap3isp_prev_csup *cs = &params->csup;
 
        isp_reg_writel(isp,
                       cs->gain | (cs->thres << ISPPRV_CSUP_THRES_SHIFT) |
@@ -407,80 +293,10 @@ preview_config_chroma_suppression(struct isp_prev_device *prev,
 }
 
 /*
- * preview_enable_noisefilter - Enables/Disables the Noise Filter.
- * @enable: 1 - Enables the Noise Filter.
- */
-static void
-preview_enable_noisefilter(struct isp_prev_device *prev, u8 enable)
-{
-       struct isp_device *isp = to_isp_device(prev);
-
-       if (enable)
-               isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
-                           ISPPRV_PCR_NFEN);
-       else
-               isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
-                           ISPPRV_PCR_NFEN);
-}
-
-/*
- * preview_enable_dcor - Enables/Disables the defect correction.
- * @enable: 1 - Enables the defect correction.
- */
-static void
-preview_enable_dcor(struct isp_prev_device *prev, u8 enable)
-{
-       struct isp_device *isp = to_isp_device(prev);
-
-       if (enable)
-               isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
-                           ISPPRV_PCR_DCOREN);
-       else
-               isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
-                           ISPPRV_PCR_DCOREN);
-}
-
-/*
- * preview_enable_gammabypass - Enables/Disables the GammaByPass
- * @enable: 1 - Bypasses Gamma - 10bit input is cropped to 8MSB.
- *          0 - Goes through Gamma Correction. input and output is 10bit.
+ * preview_enable_chroma_suppression - Enable/disable Chrominance Suppression
  */
 static void
-preview_enable_gammabypass(struct isp_prev_device *prev, u8 enable)
-{
-       struct isp_device *isp = to_isp_device(prev);
-
-       if (enable)
-               isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
-                           ISPPRV_PCR_GAMMA_BYPASS);
-       else
-               isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
-                           ISPPRV_PCR_GAMMA_BYPASS);
-}
-
-/*
- * preview_enable_luma_enhancement - Enables/Disables Luminance Enhancement
- * @enable: 1 - Enable the Luminance Enhancement.
- */
-static void
-preview_enable_luma_enhancement(struct isp_prev_device *prev, u8 enable)
-{
-       struct isp_device *isp = to_isp_device(prev);
-
-       if (enable)
-               isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
-                           ISPPRV_PCR_YNENHEN);
-       else
-               isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
-                           ISPPRV_PCR_YNENHEN);
-}
-
-/*
- * preview_enable_chroma_suppression - Enables/Disables Chrominance Suppr.
- * @enable: 1 - Enable the Chrominance Suppression.
- */
-static void
-preview_enable_chroma_suppression(struct isp_prev_device *prev, u8 enable)
+preview_enable_chroma_suppression(struct isp_prev_device *prev, bool enable)
 {
        struct isp_device *isp = to_isp_device(prev);
 
@@ -493,17 +309,16 @@ preview_enable_chroma_suppression(struct isp_prev_device *prev, u8 enable)
 }
 
 /*
- * preview_config_whitebalance - Configures the White Balance parameters.
- * @prev_wbal: Structure containing the digital gain and white balance
- *             coefficient.
+ * preview_config_whitebalance - Configure White Balance parameters
  *
  * Coefficient matrix always with default values.
  */
 static void
-preview_config_whitebalance(struct isp_prev_device *prev, const void *prev_wbal)
+preview_config_whitebalance(struct isp_prev_device *prev,
+                           const struct prev_params *params)
 {
        struct isp_device *isp = to_isp_device(prev);
-       const struct omap3isp_prev_wbal *wbal = prev_wbal;
+       const struct omap3isp_prev_wbal *wbal = &params->wbal;
        u32 val;
 
        isp_reg_writel(isp, wbal->dgain, OMAP3_ISP_IOMEM_PREV, ISPPRV_WB_DGAIN);
@@ -535,15 +350,14 @@ preview_config_whitebalance(struct isp_prev_device *prev, const void *prev_wbal)
 }
 
 /*
- * preview_config_blkadj - Configures the Black Adjustment parameters.
- * @prev_blkadj: Structure containing the black adjustment towards red, green,
- *               blue.
+ * preview_config_blkadj - Configure Black Adjustment
  */
 static void
-preview_config_blkadj(struct isp_prev_device *prev, const void *prev_blkadj)
+preview_config_blkadj(struct isp_prev_device *prev,
+                     const struct prev_params *params)
 {
        struct isp_device *isp = to_isp_device(prev);
-       const struct omap3isp_prev_blkadj *blkadj = prev_blkadj;
+       const struct omap3isp_prev_blkadj *blkadj = &params->blkadj;
 
        isp_reg_writel(isp, (blkadj->blue << ISPPRV_BLKADJOFF_B_SHIFT) |
                       (blkadj->green << ISPPRV_BLKADJOFF_G_SHIFT) |
@@ -552,15 +366,14 @@ preview_config_blkadj(struct isp_prev_device *prev, const void *prev_blkadj)
 }
 
 /*
- * preview_config_rgb_blending - Configures the RGB-RGB Blending matrix.
- * @rgb2rgb: Structure containing the rgb to rgb blending matrix and the rgb
- *           offset.
+ * preview_config_rgb_blending - Configure RGB-RGB Blending
  */
 static void
-preview_config_rgb_blending(struct isp_prev_device *prev, const void *rgb2rgb)
+preview_config_rgb_blending(struct isp_prev_device *prev,
+                           const struct prev_params *params)
 {
        struct isp_device *isp = to_isp_device(prev);
-       const struct omap3isp_prev_rgbtorgb *rgbrgb = rgb2rgb;
+       const struct omap3isp_prev_rgbtorgb *rgbrgb = &params->rgb2rgb;
        u32 val;
 
        val = (rgbrgb->matrix[0][0] & 0xfff) << ISPPRV_RGB_MAT1_MTX_RR_SHIFT;
@@ -591,15 +404,14 @@ preview_config_rgb_blending(struct isp_prev_device *prev, const void *rgb2rgb)
 }
 
 /*
- * Configures the color space conversion (RGB toYCbYCr) matrix
- * @prev_csc: Structure containing the RGB to YCbYCr matrix and the
- *            YCbCr offset.
+ * preview_config_csc - Configure Color Space Conversion (RGB to YCbYCr)
  */
 static void
-preview_config_csc(struct isp_prev_device *prev, const void *prev_csc)
+preview_config_csc(struct isp_prev_device *prev,
+                  const struct prev_params *params)
 {
        struct isp_device *isp = to_isp_device(prev);
-       const struct omap3isp_prev_csc *csc = prev_csc;
+       const struct omap3isp_prev_csc *csc = &params->csc;
        u32 val;
 
        val = (csc->matrix[0][0] & 0x3ff) << ISPPRV_CSC0_RY_SHIFT;
@@ -623,6 +435,208 @@ preview_config_csc(struct isp_prev_device *prev, const void *prev_csc)
        isp_reg_writel(isp, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC_OFFSET);
 }
 
+/*
+ * preview_config_yc_range - Configure the max and min Y and C values
+ */
+static void
+preview_config_yc_range(struct isp_prev_device *prev,
+                       const struct prev_params *params)
+{
+       struct isp_device *isp = to_isp_device(prev);
+       const struct omap3isp_prev_yclimit *yc = &params->yclimit;
+
+       isp_reg_writel(isp,
+                      yc->maxC << ISPPRV_SETUP_YC_MAXC_SHIFT |
+                      yc->maxY << ISPPRV_SETUP_YC_MAXY_SHIFT |
+                      yc->minC << ISPPRV_SETUP_YC_MINC_SHIFT |
+                      yc->minY << ISPPRV_SETUP_YC_MINY_SHIFT,
+                      OMAP3_ISP_IOMEM_PREV, ISPPRV_SETUP_YC);
+}
+
+/*
+ * preview_config_dcor - Configure Couplet Defect Correction
+ */
+static void
+preview_config_dcor(struct isp_prev_device *prev,
+                   const struct prev_params *params)
+{
+       struct isp_device *isp = to_isp_device(prev);
+       const struct omap3isp_prev_dcor *dcor = &params->dcor;
+
+       isp_reg_writel(isp, dcor->detect_correct[0],
+                      OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR0);
+       isp_reg_writel(isp, dcor->detect_correct[1],
+                      OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR1);
+       isp_reg_writel(isp, dcor->detect_correct[2],
+                      OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR2);
+       isp_reg_writel(isp, dcor->detect_correct[3],
+                      OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR3);
+       isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                       ISPPRV_PCR_DCCOUP,
+                       dcor->couplet_mode_en ? ISPPRV_PCR_DCCOUP : 0);
+}
+
+/*
+ * preview_enable_dcor - Enable/disable Couplet Defect Correction
+ */
+static void preview_enable_dcor(struct isp_prev_device *prev, bool enable)
+{
+       struct isp_device *isp = to_isp_device(prev);
+
+       if (enable)
+               isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_DCOREN);
+       else
+               isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_DCOREN);
+}
+
+/*
+ * preview_enable_drkframe_capture - Enable/disable Dark Frame Capture
+ */
+static void
+preview_enable_drkframe_capture(struct isp_prev_device *prev, bool enable)
+{
+       struct isp_device *isp = to_isp_device(prev);
+
+       if (enable)
+               isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_DRKFCAP);
+       else
+               isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_DRKFCAP);
+}
+
+/*
+ * preview_enable_drkframe - Enable/disable Dark Frame Subtraction
+ */
+static void preview_enable_drkframe(struct isp_prev_device *prev, bool enable)
+{
+       struct isp_device *isp = to_isp_device(prev);
+
+       if (enable)
+               isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_DRKFEN);
+       else
+               isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_DRKFEN);
+}
+
+/*
+ * preview_config_noisefilter - Configure the Noise Filter
+ */
+static void
+preview_config_noisefilter(struct isp_prev_device *prev,
+                          const struct prev_params *params)
+{
+       struct isp_device *isp = to_isp_device(prev);
+       const struct omap3isp_prev_nf *nf = &params->nf;
+       unsigned int i;
+
+       isp_reg_writel(isp, nf->spread, OMAP3_ISP_IOMEM_PREV, ISPPRV_NF);
+       isp_reg_writel(isp, ISPPRV_NF_TABLE_ADDR,
+                      OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
+       for (i = 0; i < OMAP3ISP_PREV_NF_TBL_SIZE; i++) {
+               isp_reg_writel(isp, nf->table[i],
+                              OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
+       }
+}
+
+/*
+ * preview_enable_noisefilter - Enable/disable the Noise Filter
+ */
+static void
+preview_enable_noisefilter(struct isp_prev_device *prev, bool enable)
+{
+       struct isp_device *isp = to_isp_device(prev);
+
+       if (enable)
+               isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_NFEN);
+       else
+               isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_NFEN);
+}
+
+/*
+ * preview_config_gammacorrn - Configure the Gamma Correction tables
+ */
+static void
+preview_config_gammacorrn(struct isp_prev_device *prev,
+                         const struct prev_params *params)
+{
+       struct isp_device *isp = to_isp_device(prev);
+       const struct omap3isp_prev_gtables *gt = &params->gamma;
+       unsigned int i;
+
+       isp_reg_writel(isp, ISPPRV_REDGAMMA_TABLE_ADDR,
+                      OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
+       for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++)
+               isp_reg_writel(isp, gt->red[i], OMAP3_ISP_IOMEM_PREV,
+                              ISPPRV_SET_TBL_DATA);
+
+       isp_reg_writel(isp, ISPPRV_GREENGAMMA_TABLE_ADDR,
+                      OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
+       for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++)
+               isp_reg_writel(isp, gt->green[i], OMAP3_ISP_IOMEM_PREV,
+                              ISPPRV_SET_TBL_DATA);
+
+       isp_reg_writel(isp, ISPPRV_BLUEGAMMA_TABLE_ADDR,
+                      OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
+       for (i = 0; i < OMAP3ISP_PREV_GAMMA_TBL_SIZE; i++)
+               isp_reg_writel(isp, gt->blue[i], OMAP3_ISP_IOMEM_PREV,
+                              ISPPRV_SET_TBL_DATA);
+}
+
+/*
+ * preview_enable_gammacorrn - Enable/disable Gamma Correction
+ *
+ * When gamma correction is disabled, the module is bypassed and its output is
+ * the 8 MSB of the 10-bit input .
+ */
+static void
+preview_enable_gammacorrn(struct isp_prev_device *prev, bool enable)
+{
+       struct isp_device *isp = to_isp_device(prev);
+
+       if (enable)
+               isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_GAMMA_BYPASS);
+       else
+               isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_GAMMA_BYPASS);
+}
+
+/*
+ * preview_config_contrast - Configure the Contrast
+ *
+ * Value should be programmed before enabling the module.
+ */
+static void
+preview_config_contrast(struct isp_prev_device *prev,
+                       const struct prev_params *params)
+{
+       struct isp_device *isp = to_isp_device(prev);
+
+       isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT,
+                       0xff << ISPPRV_CNT_BRT_CNT_SHIFT,
+                       params->contrast << ISPPRV_CNT_BRT_CNT_SHIFT);
+}
+
+/*
+ * preview_config_brightness - Configure the Brightness
+ */
+static void
+preview_config_brightness(struct isp_prev_device *prev,
+                         const struct prev_params *params)
+{
+       struct isp_device *isp = to_isp_device(prev);
+
+       isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT,
+                       0xff << ISPPRV_CNT_BRT_BRT_SHIFT,
+                       params->brightness << ISPPRV_CNT_BRT_BRT_SHIFT);
+}
+
 /*
  * preview_update_contrast - Updates the contrast.
  * @contrast: Pointer to hold the current programmed contrast value.
@@ -646,22 +660,6 @@ preview_update_contrast(struct isp_prev_device *prev, u8 contrast)
        spin_unlock_irqrestore(&prev->params.lock, flags);
 }
 
-/*
- * preview_config_contrast - Configures the Contrast.
- * @params: Contrast value (u8 pointer, U8Q0 format).
- *
- * Value should be programmed before enabling the module.
- */
-static void
-preview_config_contrast(struct isp_prev_device *prev, const void *params)
-{
-       struct isp_device *isp = to_isp_device(prev);
-
-       isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT,
-                       0xff << ISPPRV_CNT_BRT_CNT_SHIFT,
-                       *(u8 *)params << ISPPRV_CNT_BRT_CNT_SHIFT);
-}
-
 /*
  * preview_update_brightness - Updates the brightness in preview module.
  * @brightness: Pointer to hold the current programmed brightness value.
@@ -684,38 +682,6 @@ preview_update_brightness(struct isp_prev_device *prev, u8 brightness)
        spin_unlock_irqrestore(&prev->params.lock, flags);
 }
 
-/*
- * preview_config_brightness - Configures the brightness.
- * @params: Brightness value (u8 pointer, U8Q0 format).
- */
-static void
-preview_config_brightness(struct isp_prev_device *prev, const void *params)
-{
-       struct isp_device *isp = to_isp_device(prev);
-
-       isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT,
-                       0xff << ISPPRV_CNT_BRT_BRT_SHIFT,
-                       *(u8 *)params << ISPPRV_CNT_BRT_BRT_SHIFT);
-}
-
-/*
- * preview_config_yc_range - Configures the max and min Y and C values.
- * @yclimit: Structure containing the range of Y and C values.
- */
-static void
-preview_config_yc_range(struct isp_prev_device *prev, const void *yclimit)
-{
-       struct isp_device *isp = to_isp_device(prev);
-       const struct omap3isp_prev_yclimit *yc = yclimit;
-
-       isp_reg_writel(isp,
-                      yc->maxC << ISPPRV_SETUP_YC_MAXC_SHIFT |
-                      yc->maxY << ISPPRV_SETUP_YC_MAXY_SHIFT |
-                      yc->minC << ISPPRV_SETUP_YC_MINC_SHIFT |
-                      yc->minY << ISPPRV_SETUP_YC_MINY_SHIFT,
-                      OMAP3_ISP_IOMEM_PREV, ISPPRV_SETUP_YC);
-}
-
 static u32
 preview_params_lock(struct isp_prev_device *prev, u32 update, bool shadow)
 {
@@ -787,8 +753,8 @@ static void preview_params_switch(struct isp_prev_device *prev)
 
 /* preview parameters update structure */
 struct preview_update {
-       void (*config)(struct isp_prev_device *, const void *);
-       void (*enable)(struct isp_prev_device *, u8);
+       void (*config)(struct isp_prev_device *, const struct prev_params *);
+       void (*enable)(struct isp_prev_device *, bool);
        unsigned int param_offset;
        unsigned int param_size;
        unsigned int config_offset;
@@ -860,9 +826,9 @@ static const struct preview_update update_attrs[] = {
                offsetof(struct prev_params, dcor),
                FIELD_SIZEOF(struct prev_params, dcor),
                offsetof(struct omap3isp_prev_update_config, dcor),
-       }, /* OMAP3ISP_PREV_GAMMABYPASS */ {
+       }, /* Previously OMAP3ISP_PREV_GAMMABYPASS, not used anymore */ {
+               NULL,
                NULL,
-               preview_enable_gammabypass,
        }, /* OMAP3ISP_PREV_DRK_FRM_CAPTURE */ {
                NULL,
                preview_enable_drkframe_capture,
@@ -870,7 +836,7 @@ static const struct preview_update update_attrs[] = {
                NULL,
                preview_enable_drkframe,
        }, /* OMAP3ISP_PREV_LENS_SHADING */ {
-               preview_config_drkf_shadcomp,
+               NULL,
                preview_enable_drkframe,
        }, /* OMAP3ISP_PREV_NF */ {
                preview_config_noisefilter,
@@ -880,20 +846,18 @@ static const struct preview_update update_attrs[] = {
                offsetof(struct omap3isp_prev_update_config, nf),
        }, /* OMAP3ISP_PREV_GAMMA */ {
                preview_config_gammacorrn,
-               NULL,
+               preview_enable_gammacorrn,
                offsetof(struct prev_params, gamma),
                FIELD_SIZEOF(struct prev_params, gamma),
                offsetof(struct omap3isp_prev_update_config, gamma),
        }, /* OMAP3ISP_PREV_CONTRAST */ {
                preview_config_contrast,
                NULL,
-               offsetof(struct prev_params, contrast),
-               0, 0, true,
+               0, 0, 0, true,
        }, /* OMAP3ISP_PREV_BRIGHTNESS */ {
                preview_config_brightness,
                NULL,
-               offsetof(struct prev_params, brightness),
-               0, 0, true,
+               0, 0, 0, true,
        },
 };
 
@@ -988,7 +952,6 @@ static void preview_setup_hw(struct isp_prev_device *prev, u32 update,
                const struct preview_update *attr = &update_attrs[i];
                struct prev_params *params;
                unsigned int bit = 1 << i;
-               void *param_ptr;
 
                if (!(update & bit))
                        continue;
@@ -996,15 +959,13 @@ static void preview_setup_hw(struct isp_prev_device *prev, u32 update,
                params = &prev->params.params[!(active & bit)];
 
                if (params->features & bit) {
-                       if (attr->config) {
-                               param_ptr = (void *)params + attr->param_offset;
-                               attr->config(prev, param_ptr);
-                       }
+                       if (attr->config)
+                               attr->config(prev, params);
                        if (attr->enable)
-                               attr->enable(prev, 1);
+                               attr->enable(prev, true);
                } else {
                        if (attr->enable)
-                               attr->enable(prev, 0);
+                               attr->enable(prev, false);
                }
        }
 }
@@ -1043,42 +1004,60 @@ preview_config_ycpos(struct isp_prev_device *prev,
 static void preview_config_averager(struct isp_prev_device *prev, u8 average)
 {
        struct isp_device *isp = to_isp_device(prev);
-       struct prev_params *params;
-       int reg = 0;
-
-       params = (prev->params.active & OMAP3ISP_PREV_CFA)
-              ? &prev->params.params[0] : &prev->params.params[1];
 
-       if (params->cfa.format == OMAP3ISP_CFAFMT_BAYER)
-               reg = ISPPRV_AVE_EVENDIST_2 << ISPPRV_AVE_EVENDIST_SHIFT |
-                     ISPPRV_AVE_ODDDIST_2 << ISPPRV_AVE_ODDDIST_SHIFT |
-                     average;
-       else if (params->cfa.format == OMAP3ISP_CFAFMT_RGBFOVEON)
-               reg = ISPPRV_AVE_EVENDIST_3 << ISPPRV_AVE_EVENDIST_SHIFT |
-                     ISPPRV_AVE_ODDDIST_3 << ISPPRV_AVE_ODDDIST_SHIFT |
-                     average;
-       isp_reg_writel(isp, reg, OMAP3_ISP_IOMEM_PREV, ISPPRV_AVE);
+       isp_reg_writel(isp, ISPPRV_AVE_EVENDIST_2 << ISPPRV_AVE_EVENDIST_SHIFT |
+                      ISPPRV_AVE_ODDDIST_2 << ISPPRV_AVE_ODDDIST_SHIFT |
+                      average, OMAP3_ISP_IOMEM_PREV, ISPPRV_AVE);
 }
 
+
 /*
  * preview_config_input_format - Configure the input format
  * @prev: The preview engine
  * @format: Format on the preview engine sink pad
  *
- * Enable CFA interpolation for Bayer formats and disable it for greyscale
- * formats.
+ * Enable and configure CFA interpolation for Bayer formats and disable it for
+ * greyscale formats.
+ *
+ * The CFA table is organised in four blocks, one per Bayer component. The
+ * hardware expects blocks to follow the Bayer order of the input data, while
+ * the driver stores the table in GRBG order in memory. The blocks need to be
+ * reordered to support non-GRBG Bayer patterns.
  */
 static void preview_config_input_format(struct isp_prev_device *prev,
                                        const struct v4l2_mbus_framefmt *format)
 {
        struct isp_device *isp = to_isp_device(prev);
+       struct prev_params *params;
 
-       if (format->code != V4L2_MBUS_FMT_Y10_1X10)
-               isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
-                           ISPPRV_PCR_CFAEN);
-       else
+       switch (format->code) {
+       case V4L2_MBUS_FMT_SGRBG10_1X10:
+               prev->params.cfa_order = 0;
+               break;
+       case V4L2_MBUS_FMT_SRGGB10_1X10:
+               prev->params.cfa_order = 1;
+               break;
+       case V4L2_MBUS_FMT_SBGGR10_1X10:
+               prev->params.cfa_order = 2;
+               break;
+       case V4L2_MBUS_FMT_SGBRG10_1X10:
+               prev->params.cfa_order = 3;
+               break;
+       default:
+               /* Disable CFA for non-Bayer formats. */
                isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
                            ISPPRV_PCR_CFAEN);
+               return;
+       }
+
+       isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, ISPPRV_PCR_CFAEN);
+       isp_reg_clr_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                       ISPPRV_PCR_CFAFMT_MASK, ISPPRV_PCR_CFAFMT_BAYER);
+
+       params = (prev->params.active & OMAP3ISP_PREV_CFA)
+              ? &prev->params.params[0] : &prev->params.params[1];
+
+       preview_config_cfa(prev, params);
 }
 
 /*
@@ -1421,22 +1400,6 @@ static void preview_configure(struct isp_prev_device *prev)
        active = prev->params.active;
        spin_unlock_irqrestore(&prev->params.lock, flags);
 
-       preview_setup_hw(prev, update, active);
-
-       if (prev->output & PREVIEW_OUTPUT_MEMORY)
-               isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
-                           ISPPRV_PCR_SDRPORT);
-       else
-               isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
-                           ISPPRV_PCR_SDRPORT);
-
-       if (prev->output & PREVIEW_OUTPUT_RESIZER)
-               isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
-                           ISPPRV_PCR_RSZPORT);
-       else
-               isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
-                           ISPPRV_PCR_RSZPORT);
-
        /* PREV_PAD_SINK */
        format = &prev->formats[PREV_PAD_SINK];
 
@@ -1451,9 +1414,25 @@ static void preview_configure(struct isp_prev_device *prev)
                preview_config_inlineoffset(prev,
                                ALIGN(format->width, 0x20) * 2);
 
+       preview_setup_hw(prev, update, active);
+
        /* PREV_PAD_SOURCE */
        format = &prev->formats[PREV_PAD_SOURCE];
 
+       if (prev->output & PREVIEW_OUTPUT_MEMORY)
+               isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_SDRPORT);
+       else
+               isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_SDRPORT);
+
+       if (prev->output & PREVIEW_OUTPUT_RESIZER)
+               isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_RSZPORT);
+       else
+               isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+                           ISPPRV_PCR_RSZPORT);
+
        if (prev->output & PREVIEW_OUTPUT_MEMORY)
                preview_config_outlineoffset(prev,
                                ALIGN(format->width, 0x10) * 2);
index 6663ab64e4b1bbca413e96c77a9868ff7356a663..f66923407f8c5a90f2a4280201cb21460ad2fab6 100644 (file)
@@ -144,6 +144,7 @@ struct isp_prev_device {
        struct isp_video video_out;
 
        struct {
+               unsigned int cfa_order;
                struct prev_params params[2];
                u32 active;
                spinlock_t lock;
index 9bebb1e57aab0dac17e8bccbb6e55cf1566661df..15bf3eab2224ab3d835380c4a55b1e83e1269636 100644 (file)
@@ -647,7 +647,7 @@ static int isp_video_queue_alloc(struct isp_video_queue *queue,
        if (ret < 0)
                return ret;
 
-       /* Bail out of no buffers should be allocated. */
+       /* Bail out if no buffers should be allocated. */
        if (nbuffers == 0)
                return 0;
 
@@ -908,13 +908,14 @@ done:
  *
  * This function is intended to be used as a VIDIOC_DQBUF ioctl handler.
  *
- * The v4l2_buffer structure passed from userspace is first sanity tested. If
- * sane, the buffer is then processed and added to the main queue and, if the
- * queue is streaming, to the IRQ queue.
+ * Wait until a buffer is ready to be dequeued, remove it from the queue and
+ * copy its information to the v4l2_buffer structure.
  *
- * Before being enqueued, USERPTR buffers are checked for address changes. If
- * the buffer has a different userspace address, the old memory area is unlocked
- * and the new memory area is locked.
+ * If the nonblocking argument is not zero and no buffer is ready, return
+ * -EAGAIN immediately instead of waiting.
+ *
+ * If no buffer has been enqueued, or if the requested buffer type doesn't match
+ * the queue type, return -EINVAL.
  */
 int omap3isp_video_queue_dqbuf(struct isp_video_queue *queue,
                               struct v4l2_buffer *vbuf, int nonblocking)
index ae17d917f77b3657ef4553e26ea039768b9bc3e3..d11fb261d53070a131b4a3fbbd6cd2195bb3f574 100644 (file)
@@ -690,7 +690,7 @@ static void resizer_print_status(struct isp_res_device *res)
 }
 
 /*
- * resizer_calc_ratios - Helper function for calculate resizer ratios
+ * resizer_calc_ratios - Helper function for calculating resizer ratios
  * @res: pointer to resizer private data structure
  * @input: input frame size
  * @output: output frame size
@@ -734,7 +734,7 @@ static void resizer_print_status(struct isp_res_device *res)
  * value will still satisfy the original inequality, as b will disappear when
  * the expression will be shifted right by 8.
  *
- * The reverted the equations thus become
+ * The reverted equations thus become
  *
  * - 8-phase, 4-tap mode
  *     hrsz = ((iw - 7) * 256 + 255 - 16 - 32 * sph) / (ow - 1)
@@ -759,7 +759,7 @@ static void resizer_print_status(struct isp_res_device *res)
  * loop', the smallest of the ratio values will be used, never exceeding the
  * requested input size.
  *
- * We first clamp the output size according to the hardware capabilitie to avoid
+ * We first clamp the output size according to the hardware capability to avoid
  * auto-cropping the input more than required to satisfy the TRM equations. The
  * minimum output size is achieved with a scaling factor of 1024. It is thus
  * computed using the 7-tap equations.
@@ -1730,6 +1730,8 @@ static int resizer_init_entities(struct isp_res_device *res)
        if (ret < 0)
                goto error_video_out;
 
+       res->video_out.video.entity.flags |= MEDIA_ENT_FL_DEFAULT;
+
        /* Connect the video nodes to the resizer subdev. */
        ret = media_entity_create_link(&res->video_in.video.entity, 0,
                        &res->subdev.entity, RESZ_PAD_SINK, 0);
index b37379d39cdd888c72731377bb49886361b285e8..3a5085e9002465e13e0283260ed26c0a1087c567 100644 (file)
 static struct isp_format_info formats[] = {
        { V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8,
          V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8,
-         V4L2_PIX_FMT_GREY, 8, },
+         V4L2_PIX_FMT_GREY, 8, 1, },
        { V4L2_MBUS_FMT_Y10_1X10, V4L2_MBUS_FMT_Y10_1X10,
          V4L2_MBUS_FMT_Y10_1X10, V4L2_MBUS_FMT_Y8_1X8,
-         V4L2_PIX_FMT_Y10, 10, },
+         V4L2_PIX_FMT_Y10, 10, 2, },
        { V4L2_MBUS_FMT_Y12_1X12, V4L2_MBUS_FMT_Y10_1X10,
          V4L2_MBUS_FMT_Y12_1X12, V4L2_MBUS_FMT_Y8_1X8,
-         V4L2_PIX_FMT_Y12, 12, },
+         V4L2_PIX_FMT_Y12, 12, 2, },
        { V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_MBUS_FMT_SBGGR8_1X8,
          V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_MBUS_FMT_SBGGR8_1X8,
-         V4L2_PIX_FMT_SBGGR8, 8, },
+         V4L2_PIX_FMT_SBGGR8, 8, 1, },
        { V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGBRG8_1X8,
          V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGBRG8_1X8,
-         V4L2_PIX_FMT_SGBRG8, 8, },
+         V4L2_PIX_FMT_SGBRG8, 8, 1, },
        { V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_MBUS_FMT_SGRBG8_1X8,
          V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_MBUS_FMT_SGRBG8_1X8,
-         V4L2_PIX_FMT_SGRBG8, 8, },
+         V4L2_PIX_FMT_SGRBG8, 8, 1, },
        { V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8,
          V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8,
-         V4L2_PIX_FMT_SRGGB8, 8, },
+         V4L2_PIX_FMT_SRGGB8, 8, 1, },
        { V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8, V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8,
          V4L2_MBUS_FMT_SBGGR10_1X10, 0,
-         V4L2_PIX_FMT_SBGGR10DPCM8, 8, },
+         V4L2_PIX_FMT_SBGGR10DPCM8, 8, 1, },
        { V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8, V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8,
          V4L2_MBUS_FMT_SGBRG10_1X10, 0,
-         V4L2_PIX_FMT_SGBRG10DPCM8, 8, },
+         V4L2_PIX_FMT_SGBRG10DPCM8, 8, 1, },
        { V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
          V4L2_MBUS_FMT_SGRBG10_1X10, 0,
-         V4L2_PIX_FMT_SGRBG10DPCM8, 8, },
+         V4L2_PIX_FMT_SGRBG10DPCM8, 8, 1, },
        { V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8, V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8,
          V4L2_MBUS_FMT_SRGGB10_1X10, 0,
-         V4L2_PIX_FMT_SRGGB10DPCM8, 8, },
+         V4L2_PIX_FMT_SRGGB10DPCM8, 8, 1, },
        { V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR10_1X10,
          V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR8_1X8,
-         V4L2_PIX_FMT_SBGGR10, 10, },
+         V4L2_PIX_FMT_SBGGR10, 10, 2, },
        { V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG10_1X10,
          V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG8_1X8,
-         V4L2_PIX_FMT_SGBRG10, 10, },
+         V4L2_PIX_FMT_SGBRG10, 10, 2, },
        { V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG10_1X10,
          V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG8_1X8,
-         V4L2_PIX_FMT_SGRBG10, 10, },
+         V4L2_PIX_FMT_SGRBG10, 10, 2, },
        { V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB10_1X10,
          V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB8_1X8,
-         V4L2_PIX_FMT_SRGGB10, 10, },
+         V4L2_PIX_FMT_SRGGB10, 10, 2, },
        { V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR10_1X10,
          V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR8_1X8,
-         V4L2_PIX_FMT_SBGGR12, 12, },
+         V4L2_PIX_FMT_SBGGR12, 12, 2, },
        { V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG10_1X10,
          V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG8_1X8,
-         V4L2_PIX_FMT_SGBRG12, 12, },
+         V4L2_PIX_FMT_SGBRG12, 12, 2, },
        { V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG10_1X10,
          V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG8_1X8,
-         V4L2_PIX_FMT_SGRBG12, 12, },
+         V4L2_PIX_FMT_SGRBG12, 12, 2, },
        { V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB10_1X10,
          V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB8_1X8,
-         V4L2_PIX_FMT_SRGGB12, 12, },
+         V4L2_PIX_FMT_SRGGB12, 12, 2, },
        { V4L2_MBUS_FMT_UYVY8_1X16, V4L2_MBUS_FMT_UYVY8_1X16,
          V4L2_MBUS_FMT_UYVY8_1X16, 0,
-         V4L2_PIX_FMT_UYVY, 16, },
+         V4L2_PIX_FMT_UYVY, 16, 2, },
        { V4L2_MBUS_FMT_YUYV8_1X16, V4L2_MBUS_FMT_YUYV8_1X16,
          V4L2_MBUS_FMT_YUYV8_1X16, 0,
-         V4L2_PIX_FMT_YUYV, 16, },
+         V4L2_PIX_FMT_YUYV, 16, 2, },
+       { V4L2_MBUS_FMT_UYVY8_2X8, V4L2_MBUS_FMT_UYVY8_2X8,
+         V4L2_MBUS_FMT_UYVY8_2X8, 0,
+         V4L2_PIX_FMT_UYVY, 8, 2, },
+       { V4L2_MBUS_FMT_YUYV8_2X8, V4L2_MBUS_FMT_YUYV8_2X8,
+         V4L2_MBUS_FMT_YUYV8_2X8, 0,
+         V4L2_PIX_FMT_YUYV, 8, 2, },
+       /* Empty entry to catch the unsupported pixel code (0) used by the CCDC
+        * module and avoid NULL pointer dereferences.
+        */
+       { 0, }
 };
 
 const struct isp_format_info *
@@ -161,7 +171,7 @@ static unsigned int isp_video_mbus_to_pix(const struct isp_video *video,
        if (WARN_ON(i == ARRAY_SIZE(formats)))
                return 0;
 
-       min_bpl = pix->width * ALIGN(formats[i].bpp, 8) / 8;
+       min_bpl = pix->width * formats[i].bpp;
 
        /* Clamp the requested bytes per line value. If the maximum bytes per
         * line value is zero, the module doesn't support user configurable line
@@ -921,7 +931,8 @@ static int isp_video_check_external_subdevs(struct isp_video *video,
                return ret;
        }
 
-       pipe->external_bpp = omap3isp_video_format_info(fmt.format.code)->bpp;
+       pipe->external_width =
+               omap3isp_video_format_info(fmt.format.code)->width;
 
        memset(&ctrls, 0, sizeof(ctrls));
        memset(&ctrl, 0, sizeof(ctrl));
index 5acc909500ec0c52db0537201c88d01b2ca612d7..1ad470ec2b9d5ab5f4cd212f11d0b3d412d93b20 100644 (file)
@@ -51,7 +51,8 @@ struct v4l2_pix_format;
  * @flavor: V4L2 media bus format code for the same pixel layout but
  *     shifted to be 8 bits per pixel. =0 if format is not shiftable.
  * @pixelformat: V4L2 pixel format FCC identifier
- * @bpp: Bits per pixel
+ * @width: Bits per pixel (when transferred over a bus)
+ * @bpp: Bytes per pixel (when stored in memory)
  */
 struct isp_format_info {
        enum v4l2_mbus_pixelcode code;
@@ -59,6 +60,7 @@ struct isp_format_info {
        enum v4l2_mbus_pixelcode uncompressed;
        enum v4l2_mbus_pixelcode flavor;
        u32 pixelformat;
+       unsigned int width;
        unsigned int bpp;
 };
 
@@ -106,7 +108,7 @@ struct isp_pipeline {
        struct v4l2_fract max_timeperframe;
        struct v4l2_subdev *external;
        unsigned int external_rate;
-       unsigned int external_bpp;
+       unsigned int external_width;
 };
 
 #define to_isp_pipeline(__e) \
index d8c898278e8ca9b2a40c0db69dfe1c139d82e5ef..adc501d3c287fe0f6ba8893abd58d06603440873 100644 (file)
@@ -54,8 +54,9 @@ static const struct pvr2_device_client_desc pvr2_cli_29xxx[] = {
        { .module_id = PVR2_CLIENT_ID_DEMOD },
 };
 
+#define PVR2_FIRMWARE_29xxx "v4l-pvrusb2-29xxx-01.fw"
 static const char *pvr2_fw1_names_29xxx[] = {
-               "v4l-pvrusb2-29xxx-01.fw",
+               PVR2_FIRMWARE_29xxx,
 };
 
 static const struct pvr2_device_desc pvr2_device_29xxx = {
@@ -87,8 +88,9 @@ static const struct pvr2_device_client_desc pvr2_cli_24xxx[] = {
        { .module_id = PVR2_CLIENT_ID_DEMOD },
 };
 
+#define PVR2_FIRMWARE_24xxx "v4l-pvrusb2-24xxx-01.fw"
 static const char *pvr2_fw1_names_24xxx[] = {
-               "v4l-pvrusb2-24xxx-01.fw",
+               PVR2_FIRMWARE_24xxx,
 };
 
 static const struct pvr2_device_desc pvr2_device_24xxx = {
@@ -369,8 +371,9 @@ static const struct pvr2_device_client_desc pvr2_cli_73xxx[] = {
          .i2c_address_list = "\x42"},
 };
 
+#define PVR2_FIRMWARE_73xxx "v4l-pvrusb2-73xxx-01.fw"
 static const char *pvr2_fw1_names_73xxx[] = {
-               "v4l-pvrusb2-73xxx-01.fw",
+               PVR2_FIRMWARE_73xxx,
 };
 
 static const struct pvr2_device_desc pvr2_device_73xxx = {
@@ -475,8 +478,9 @@ static const struct pvr2_dvb_props pvr2_751xx_dvb_props = {
 };
 #endif
 
+#define PVR2_FIRMWARE_75xxx "v4l-pvrusb2-73xxx-01.fw"
 static const char *pvr2_fw1_names_75xxx[] = {
-               "v4l-pvrusb2-73xxx-01.fw",
+               PVR2_FIRMWARE_75xxx,
 };
 
 static const struct pvr2_device_desc pvr2_device_750xx = {
@@ -556,7 +560,10 @@ struct usb_device_id pvr2_device_table[] = {
 };
 
 MODULE_DEVICE_TABLE(usb, pvr2_device_table);
-
+MODULE_FIRMWARE(PVR2_FIRMWARE_29xxx);
+MODULE_FIRMWARE(PVR2_FIRMWARE_24xxx);
+MODULE_FIRMWARE(PVR2_FIRMWARE_73xxx);
+MODULE_FIRMWARE(PVR2_FIRMWARE_75xxx);
 
 /*
   Stuff for Emacs to see, in order to encourage consistent editing style:
index 95007dda0c93e8ed8a2395d0dd63ba05f3064583..6c7960cc75064f7055ee4d3a2c230504041cef56 100644 (file)
@@ -258,7 +258,6 @@ struct s2255_dev {
        atomic_t                num_channels;
        int                     frames;
        struct mutex            lock;   /* channels[].vdev.lock */
-       struct mutex            open_lock;
        struct usb_device       *udev;
        struct usb_interface    *interface;
        u8                      read_endpoint;
@@ -1684,7 +1683,7 @@ static int vidioc_enum_frameintervals(struct file *file, void *priv,
        return 0;
 }
 
-static int s2255_open(struct file *file)
+static int __s2255_open(struct file *file)
 {
        struct video_device *vdev = video_devdata(file);
        struct s2255_channel *channel = video_drvdata(file);
@@ -1694,16 +1693,9 @@ static int s2255_open(struct file *file)
        int state;
        dprintk(1, "s2255: open called (dev=%s)\n",
                video_device_node_name(vdev));
-       /*
-        * open lock necessary to prevent multiple instances
-        * of v4l-conf (or other programs) from simultaneously
-        * reloading firmware.
-        */
-       mutex_lock(&dev->open_lock);
        state = atomic_read(&dev->fw_data->fw_state);
        switch (state) {
        case S2255_FW_DISCONNECTING:
-               mutex_unlock(&dev->open_lock);
                return -ENODEV;
        case S2255_FW_FAILED:
                s2255_dev_err(&dev->udev->dev,
@@ -1742,11 +1734,9 @@ static int s2255_open(struct file *file)
                break;
        case S2255_FW_FAILED:
                printk(KERN_INFO "2255 firmware load failed.\n");
-               mutex_unlock(&dev->open_lock);
                return -ENODEV;
        case S2255_FW_DISCONNECTING:
                printk(KERN_INFO "%s: disconnecting\n", __func__);
-               mutex_unlock(&dev->open_lock);
                return -ENODEV;
        case S2255_FW_LOADED_DSPWAIT:
        case S2255_FW_NOTLOADED:
@@ -1760,14 +1750,11 @@ static int s2255_open(struct file *file)
                 */
                atomic_set(&dev->fw_data->fw_state,
                           S2255_FW_FAILED);
-               mutex_unlock(&dev->open_lock);
                return -EAGAIN;
        default:
                printk(KERN_INFO "%s: unknown state\n", __func__);
-               mutex_unlock(&dev->open_lock);
                return -EFAULT;
        }
-       mutex_unlock(&dev->open_lock);
        /* allocate + initialize per filehandle data */
        fh = kzalloc(sizeof(*fh), GFP_KERNEL);
        if (NULL == fh)
@@ -1798,16 +1785,30 @@ static int s2255_open(struct file *file)
        return 0;
 }
 
+static int s2255_open(struct file *file)
+{
+       struct video_device *vdev = video_devdata(file);
+       int ret;
+
+       if (mutex_lock_interruptible(vdev->lock))
+               return -ERESTARTSYS;
+       ret = __s2255_open(file);
+       mutex_unlock(vdev->lock);
+       return ret;
+}
 
 static unsigned int s2255_poll(struct file *file,
                               struct poll_table_struct *wait)
 {
        struct s2255_fh *fh = file->private_data;
+       struct s2255_dev *dev = fh->dev;
        int rc;
        dprintk(100, "%s\n", __func__);
        if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
                return POLLERR;
+       mutex_lock(&dev->lock);
        rc = videobuf_poll_stream(file, &fh->vb_vidq, wait);
+       mutex_unlock(&dev->lock);
        return rc;
 }
 
@@ -1827,7 +1828,6 @@ static void s2255_destroy(struct s2255_dev *dev)
        kfree(dev->fw_data);
        /* reset the DSP so firmware can be reloaded next time */
        s2255_reset_dsppower(dev);
-       mutex_destroy(&dev->open_lock);
        mutex_destroy(&dev->lock);
        usb_put_dev(dev->udev);
        v4l2_device_unregister(&dev->v4l2_dev);
@@ -1843,6 +1843,7 @@ static int s2255_release(struct file *file)
        struct s2255_channel *channel = fh->channel;
        if (!dev)
                return -ENODEV;
+       mutex_lock(&dev->lock);
        /* turn off stream */
        if (res_check(fh)) {
                if (channel->b_acquire)
@@ -1851,6 +1852,7 @@ static int s2255_release(struct file *file)
                res_free(fh);
        }
        videobuf_mmap_free(&fh->vb_vidq);
+       mutex_unlock(&dev->lock);
        dprintk(1, "%s (dev=%s)\n", __func__, video_device_node_name(vdev));
        kfree(fh);
        return 0;
@@ -1859,12 +1861,16 @@ static int s2255_release(struct file *file)
 static int s2255_mmap_v4l(struct file *file, struct vm_area_struct *vma)
 {
        struct s2255_fh *fh = file->private_data;
+       struct s2255_dev *dev = fh->dev;
        int ret;
 
        if (!fh)
                return -ENODEV;
        dprintk(4, "%s, vma=0x%08lx\n", __func__, (unsigned long)vma);
+       if (mutex_lock_interruptible(&dev->lock))
+               return -ERESTARTSYS;
        ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+       mutex_unlock(&dev->lock);
        dprintk(4, "%s vma start=0x%08lx, size=%ld, ret=%d\n", __func__,
                (unsigned long)vma->vm_start,
                (unsigned long)vma->vm_end - (unsigned long)vma->vm_start, ret);
@@ -1944,10 +1950,6 @@ static int s2255_probe_v4l(struct s2255_dev *dev)
                /* register 4 video devices */
                channel->vdev = template;
                channel->vdev.lock = &dev->lock;
-               /* Locking in file operations other than ioctl should be done
-                  by the driver, not the V4L2 core.
-                  This driver needs auditing so that this flag can be removed. */
-               set_bit(V4L2_FL_LOCK_ALL_FOPS, &channel->vdev.flags);
                channel->vdev.v4l2_dev = &dev->v4l2_dev;
                video_set_drvdata(&channel->vdev, channel);
                if (video_nr == -1)
@@ -2535,7 +2537,6 @@ static int s2255_probe(struct usb_interface *interface,
        if (!dev->fw_data)
                goto errorFWDATA1;
        mutex_init(&dev->lock);
-       mutex_init(&dev->open_lock);
        /* grab usb_device and save it */
        dev->udev = usb_get_dev(interface_to_usbdev(interface));
        if (dev->udev == NULL) {
@@ -2637,7 +2638,6 @@ errorEP:
        usb_put_dev(dev->udev);
 errorUDEV:
        kfree(dev->fw_data);
-       mutex_destroy(&dev->open_lock);
        mutex_destroy(&dev->lock);
 errorFWDATA1:
        kfree(dev);
index 6625e46a4638d5a0e916d3ff91fdbeb6dd8355fc..decb648083460dc0ed21691e2bf76e3735c9b98d 100644 (file)
@@ -1436,7 +1436,7 @@ static int s5k6aa_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
        return 0;
 }
 
-int s5k6aa_check_fw_revision(struct s5k6aa *s5k6aa)
+static int s5k6aa_check_fw_revision(struct s5k6aa *s5k6aa)
 {
        struct i2c_client *client = v4l2_get_subdevdata(&s5k6aa->sd);
        u16 api_ver = 0, fw_rev = 0;
index 7c22004352068ffeec6493b2594710ad184438e5..0edc2df98732df4f8b77b6e692a0ec39f61dfc5b 100644 (file)
@@ -248,9 +248,14 @@ static int g2d_open(struct file *file)
        ctx->in         = def_frame;
        ctx->out        = def_frame;
 
+       if (mutex_lock_interruptible(&dev->mutex)) {
+               kfree(ctx);
+               return -ERESTARTSYS;
+       }
        ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
        if (IS_ERR(ctx->m2m_ctx)) {
                ret = PTR_ERR(ctx->m2m_ctx);
+               mutex_unlock(&dev->mutex);
                kfree(ctx);
                return ret;
        }
@@ -264,6 +269,7 @@ static int g2d_open(struct file *file)
        v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
 
        ctx->fh.ctrl_handler = &ctx->ctrl_handler;
+       mutex_unlock(&dev->mutex);
 
        v4l2_info(&dev->v4l2_dev, "instance opened\n");
        return 0;
@@ -406,13 +412,26 @@ static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f)
 static unsigned int g2d_poll(struct file *file, struct poll_table_struct *wait)
 {
        struct g2d_ctx *ctx = fh2ctx(file->private_data);
-       return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+       struct g2d_dev *dev = ctx->dev;
+       unsigned int res;
+
+       mutex_lock(&dev->mutex);
+       res = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+       mutex_unlock(&dev->mutex);
+       return res;
 }
 
 static int g2d_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct g2d_ctx *ctx = fh2ctx(file->private_data);
-       return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+       struct g2d_dev *dev = ctx->dev;
+       int ret;
+
+       if (mutex_lock_interruptible(&dev->mutex))
+               return -ERESTARTSYS;
+       ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+       mutex_unlock(&dev->mutex);
+       return ret;
 }
 
 static int vidioc_reqbufs(struct file *file, void *priv,
@@ -753,10 +772,6 @@ static int g2d_probe(struct platform_device *pdev)
                goto unreg_v4l2_dev;
        }
        *vfd = g2d_videodev;
-       /* Locking in file operations other than ioctl should be done
-          by the driver, not the V4L2 core.
-          This driver needs auditing so that this flag can be removed. */
-       set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
        vfd->lock = &dev->mutex;
        ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
        if (ret) {
index 813b801238d1f72e910ab8eea63feeb586b477bb..be04d584e36a414a75ac5427b1e08e1e9b22ddc3 100644 (file)
@@ -292,6 +292,11 @@ static int s5p_jpeg_open(struct file *file)
        if (!ctx)
                return -ENOMEM;
 
+       if (mutex_lock_interruptible(&jpeg->lock)) {
+               ret = -ERESTARTSYS;
+               goto free;
+       }
+
        v4l2_fh_init(&ctx->fh, vfd);
        /* Use separate control handler per file handle */
        ctx->fh.ctrl_handler = &ctx->ctrl_handler;
@@ -319,20 +324,26 @@ static int s5p_jpeg_open(struct file *file)
 
        ctx->out_q.fmt = out_fmt;
        ctx->cap_q.fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_YUYV);
+       mutex_unlock(&jpeg->lock);
        return 0;
 
 error:
        v4l2_fh_del(&ctx->fh);
        v4l2_fh_exit(&ctx->fh);
+       mutex_unlock(&jpeg->lock);
+free:
        kfree(ctx);
        return ret;
 }
 
 static int s5p_jpeg_release(struct file *file)
 {
+       struct s5p_jpeg *jpeg = video_drvdata(file);
        struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
 
+       mutex_lock(&jpeg->lock);
        v4l2_m2m_ctx_release(ctx->m2m_ctx);
+       mutex_unlock(&jpeg->lock);
        v4l2_ctrl_handler_free(&ctx->ctrl_handler);
        v4l2_fh_del(&ctx->fh);
        v4l2_fh_exit(&ctx->fh);
@@ -344,16 +355,27 @@ static int s5p_jpeg_release(struct file *file)
 static unsigned int s5p_jpeg_poll(struct file *file,
                                 struct poll_table_struct *wait)
 {
+       struct s5p_jpeg *jpeg = video_drvdata(file);
        struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
+       unsigned int res;
 
-       return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+       mutex_lock(&jpeg->lock);
+       res = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+       mutex_unlock(&jpeg->lock);
+       return res;
 }
 
 static int s5p_jpeg_mmap(struct file *file, struct vm_area_struct *vma)
 {
+       struct s5p_jpeg *jpeg = video_drvdata(file);
        struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
+       int ret;
 
-       return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+       if (mutex_lock_interruptible(&jpeg->lock))
+               return -ERESTARTSYS;
+       ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+       mutex_unlock(&jpeg->lock);
+       return ret;
 }
 
 static const struct v4l2_file_operations s5p_jpeg_fops = {
@@ -1372,10 +1394,6 @@ static int s5p_jpeg_probe(struct platform_device *pdev)
        jpeg->vfd_encoder->release      = video_device_release;
        jpeg->vfd_encoder->lock         = &jpeg->lock;
        jpeg->vfd_encoder->v4l2_dev     = &jpeg->v4l2_dev;
-       /* Locking in file operations other than ioctl should be done
-          by the driver, not the V4L2 core.
-          This driver needs auditing so that this flag can be removed. */
-       set_bit(V4L2_FL_LOCK_ALL_FOPS, &jpeg->vfd_encoder->flags);
 
        ret = video_register_device(jpeg->vfd_encoder, VFL_TYPE_GRABBER, -1);
        if (ret) {
@@ -1403,10 +1421,6 @@ static int s5p_jpeg_probe(struct platform_device *pdev)
        jpeg->vfd_decoder->release      = video_device_release;
        jpeg->vfd_decoder->lock         = &jpeg->lock;
        jpeg->vfd_decoder->v4l2_dev     = &jpeg->v4l2_dev;
-       /* Locking in file operations other than ioctl should be done by the driver,
-          not the V4L2 core.
-          This driver needs auditing so that this flag can be removed. */
-       set_bit(V4L2_FL_LOCK_ALL_FOPS, &jpeg->vfd_decoder->flags);
 
        ret = video_register_device(jpeg->vfd_decoder, VFL_TYPE_GRABBER, -1);
        if (ret) {
index 9bb68e7b5ae80833b827586fbf09a5642495d050..e3e616d8a09d2eafd0537d29987e76c1bd1d146b 100644 (file)
@@ -645,6 +645,8 @@ static int s5p_mfc_open(struct file *file)
        int ret = 0;
 
        mfc_debug_enter();
+       if (mutex_lock_interruptible(&dev->mfc_mutex))
+               return -ERESTARTSYS;
        dev->num_inst++;        /* It is guarded by mfc_mutex in vfd */
        /* Allocate memory for context */
        ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
@@ -765,6 +767,7 @@ static int s5p_mfc_open(struct file *file)
                goto err_queue_init;
        }
        init_waitqueue_head(&ctx->queue);
+       mutex_unlock(&dev->mfc_mutex);
        mfc_debug_leave();
        return ret;
        /* Deinit when failure occured */
@@ -790,6 +793,7 @@ err_no_ctx:
        kfree(ctx);
 err_alloc:
        dev->num_inst--;
+       mutex_unlock(&dev->mfc_mutex);
        mfc_debug_leave();
        return ret;
 }
@@ -802,6 +806,7 @@ static int s5p_mfc_release(struct file *file)
        unsigned long flags;
 
        mfc_debug_enter();
+       mutex_lock(&dev->mfc_mutex);
        s5p_mfc_clock_on();
        vb2_queue_release(&ctx->vq_src);
        vb2_queue_release(&ctx->vq_dst);
@@ -855,6 +860,7 @@ static int s5p_mfc_release(struct file *file)
        v4l2_fh_exit(&ctx->fh);
        kfree(ctx);
        mfc_debug_leave();
+       mutex_unlock(&dev->mfc_mutex);
        return 0;
 }
 
@@ -869,6 +875,7 @@ static unsigned int s5p_mfc_poll(struct file *file,
        unsigned int rc = 0;
        unsigned long flags;
 
+       mutex_lock(&dev->mfc_mutex);
        src_q = &ctx->vq_src;
        dst_q = &ctx->vq_dst;
        /*
@@ -902,6 +909,7 @@ static unsigned int s5p_mfc_poll(struct file *file,
                rc |= POLLIN | POLLRDNORM;
        spin_unlock_irqrestore(&dst_q->done_lock, flags);
 end:
+       mutex_unlock(&dev->mfc_mutex);
        return rc;
 }
 
@@ -909,8 +917,12 @@ end:
 static int s5p_mfc_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct s5p_mfc_ctx *ctx = fh_to_ctx(file->private_data);
+       struct s5p_mfc_dev *dev = ctx->dev;
        unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
        int ret;
+
+       if (mutex_lock_interruptible(&dev->mfc_mutex))
+               return -ERESTARTSYS;
        if (offset < DST_QUEUE_OFF_BASE) {
                mfc_debug(2, "mmaping source\n");
                ret = vb2_mmap(&ctx->vq_src, vma);
@@ -919,6 +931,7 @@ static int s5p_mfc_mmap(struct file *file, struct vm_area_struct *vma)
                vma->vm_pgoff -= (DST_QUEUE_OFF_BASE >> PAGE_SHIFT);
                ret = vb2_mmap(&ctx->vq_dst, vma);
        }
+       mutex_unlock(&dev->mfc_mutex);
        return ret;
 }
 
@@ -1034,10 +1047,6 @@ static int s5p_mfc_probe(struct platform_device *pdev)
        vfd->ioctl_ops  = get_dec_v4l2_ioctl_ops();
        vfd->release    = video_device_release,
        vfd->lock       = &dev->mfc_mutex;
-       /* Locking in file operations other than ioctl should be done
-          by the driver, not the V4L2 core.
-          This driver needs auditing so that this flag can be removed. */
-       set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
        vfd->v4l2_dev   = &dev->v4l2_dev;
        snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_DEC_NAME);
        dev->vfd_dec    = vfd;
@@ -1062,8 +1071,6 @@ static int s5p_mfc_probe(struct platform_device *pdev)
        vfd->ioctl_ops  = get_enc_v4l2_ioctl_ops();
        vfd->release    = video_device_release,
        vfd->lock       = &dev->mfc_mutex;
-       /* This should not be necessary */
-       set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
        vfd->v4l2_dev   = &dev->v4l2_dev;
        snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_ENC_NAME);
        dev->vfd_enc    = vfd;
index 6c74b05d1f95382e691feb48f863e96b175d1a4b..e0e02cce1bcb1d8af8641961c453385200054da8 100644 (file)
@@ -750,18 +750,20 @@ static int mxr_video_open(struct file *file)
        int ret = 0;
 
        mxr_dbg(mdev, "%s:%d\n", __func__, __LINE__);
+       if (mutex_lock_interruptible(&layer->mutex))
+               return -ERESTARTSYS;
        /* assure device probe is finished */
        wait_for_device_probe();
        /* creating context for file descriptor */
        ret = v4l2_fh_open(file);
        if (ret) {
                mxr_err(mdev, "v4l2_fh_open failed\n");
-               return ret;
+               goto unlock;
        }
 
        /* leaving if layer is already initialized */
        if (!v4l2_fh_is_singular_file(file))
-               return 0;
+               goto unlock;
 
        /* FIXME: should power be enabled on open? */
        ret = mxr_power_get(mdev);
@@ -779,6 +781,7 @@ static int mxr_video_open(struct file *file)
        layer->fmt = layer->fmt_array[0];
        /* setup default geometry */
        mxr_layer_default_geo(layer);
+       mutex_unlock(&layer->mutex);
 
        return 0;
 
@@ -788,6 +791,9 @@ fail_power:
 fail_fh_open:
        v4l2_fh_release(file);
 
+unlock:
+       mutex_unlock(&layer->mutex);
+
        return ret;
 }
 
@@ -795,19 +801,28 @@ static unsigned int
 mxr_video_poll(struct file *file, struct poll_table_struct *wait)
 {
        struct mxr_layer *layer = video_drvdata(file);
+       unsigned int res;
 
        mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
 
-       return vb2_poll(&layer->vb_queue, file, wait);
+       mutex_lock(&layer->mutex);
+       res = vb2_poll(&layer->vb_queue, file, wait);
+       mutex_unlock(&layer->mutex);
+       return res;
 }
 
 static int mxr_video_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct mxr_layer *layer = video_drvdata(file);
+       int ret;
 
        mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
 
-       return vb2_mmap(&layer->vb_queue, vma);
+       if (mutex_lock_interruptible(&layer->mutex))
+               return -ERESTARTSYS;
+       ret = vb2_mmap(&layer->vb_queue, vma);
+       mutex_unlock(&layer->mutex);
+       return ret;
 }
 
 static int mxr_video_release(struct file *file)
@@ -815,11 +830,13 @@ static int mxr_video_release(struct file *file)
        struct mxr_layer *layer = video_drvdata(file);
 
        mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__);
+       mutex_lock(&layer->mutex);
        if (v4l2_fh_is_singular_file(file)) {
                vb2_queue_release(&layer->vb_queue);
                mxr_power_put(layer->mdev);
        }
        v4l2_fh_release(file);
+       mutex_unlock(&layer->mutex);
        return 0;
 }
 
@@ -1069,10 +1086,6 @@ struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev,
        set_bit(V4L2_FL_USE_FH_PRIO, &layer->vfd.flags);
 
        video_set_drvdata(&layer->vfd, layer);
-       /* Locking in file operations other than ioctl should be done
-          by the driver, not the V4L2 core.
-          This driver needs auditing so that this flag can be removed. */
-       set_bit(V4L2_FL_LOCK_ALL_FOPS, &layer->vfd.flags);
        layer->vfd.lock = &layer->mutex;
        layer->vfd.v4l2_dev = &mdev->v4l2_dev;
 
index c8799fdaae67d074e0bdbe64ea2bac4f752edb2f..eff7135cf0e8999beb790f0c406f0d7fdd1d772e 100644 (file)
@@ -670,7 +670,8 @@ int saa7164_api_set_dif(struct saa7164_port *port, u8 reg, u8 val)
        if (ret != SAA_OK)
                printk(KERN_ERR "%s() error, ret(2) = 0x%x\n", __func__, ret);
 #if 0
-       saa7164_dumphex16(dev, buf, 16);
+       print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1, buf, 16,
+                      false);
 #endif
        return ret == SAA_OK ? 0 : -EIO;
 }
@@ -1352,7 +1353,8 @@ int saa7164_api_enum_subdevs(struct saa7164_dev *dev)
        }
 
        if (saa_debug & DBGLVL_API)
-               saa7164_dumphex16(dev, buf, (buflen/16)*16);
+               print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1, buf,
+                              buflen & ~15, false);
 
        saa7164_api_dump_subdevs(dev, buf, buflen);
 
@@ -1403,7 +1405,8 @@ int saa7164_api_i2c_read(struct saa7164_i2c *bus, u8 addr, u32 reglen, u8 *reg,
        dprintk(DBGLVL_API, "%s() len = %d bytes\n", __func__, len);
 
        if (saa_debug & DBGLVL_I2C)
-               saa7164_dumphex16(dev, buf, 2 * 16);
+               print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1, buf,
+                              32, false);
 
        ret = saa7164_cmd_send(bus->dev, unitid, GET_CUR,
                EXU_REGISTER_ACCESS_CONTROL, len, &buf);
@@ -1411,7 +1414,8 @@ int saa7164_api_i2c_read(struct saa7164_i2c *bus, u8 addr, u32 reglen, u8 *reg,
                printk(KERN_ERR "%s() error, ret(2) = 0x%x\n", __func__, ret);
        else {
                if (saa_debug & DBGLVL_I2C)
-                       saa7164_dumphex16(dev, buf, sizeof(buf));
+                       print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1,
+                                      buf, sizeof(buf), false);
                memcpy(data, (buf + 2 * sizeof(u32) + reglen), datalen);
        }
 
@@ -1471,7 +1475,8 @@ int saa7164_api_i2c_write(struct saa7164_i2c *bus, u8 addr, u32 datalen,
        memcpy((buf + 2 * sizeof(u32)), data, datalen);
 
        if (saa_debug & DBGLVL_I2C)
-               saa7164_dumphex16(dev, buf, sizeof(buf));
+               print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1,
+                              buf, sizeof(buf), false);
 
        ret = saa7164_cmd_send(bus->dev, unitid, SET_CUR,
                EXU_REGISTER_ACCESS_CONTROL, len, &buf);
index 3b7d7b4e303448187f6b74ee51b802d82c89ac0c..2c9ad878bef3dedab9c91a19019d7443d151affb 100644 (file)
@@ -92,28 +92,6 @@ LIST_HEAD(saa7164_devlist);
 
 #define INT_SIZE 16
 
-void saa7164_dumphex16FF(struct saa7164_dev *dev, u8 *buf, int len)
-{
-       int i;
-       u8 tmp[16];
-       memset(&tmp[0], 0xff, sizeof(tmp));
-
-       printk(KERN_INFO "--------------------> "
-               "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n");
-
-       for (i = 0; i < len; i += 16) {
-               if (memcmp(&tmp, buf + i, sizeof(tmp)) != 0) {
-                       printk(KERN_INFO "         [0x%08x] "
-                               "%02x %02x %02x %02x %02x %02x %02x %02x "
-                               "%02x %02x %02x %02x %02x %02x %02x %02x\n", i,
-                       *(buf+i+0), *(buf+i+1), *(buf+i+2), *(buf+i+3),
-                       *(buf+i+4), *(buf+i+5), *(buf+i+6), *(buf+i+7),
-                       *(buf+i+8), *(buf+i+9), *(buf+i+10), *(buf+i+11),
-                       *(buf+i+12), *(buf+i+13), *(buf+i+14), *(buf+i+15));
-               }
-       }
-}
-
 static void saa7164_pack_verifier(struct saa7164_buffer *buf)
 {
        u8 *p = (u8 *)buf->cpu;
@@ -125,7 +103,8 @@ static void saa7164_pack_verifier(struct saa7164_buffer *buf)
                        (*(p + i + 2) != 0x01) || (*(p + i + 3) != 0xBA)) {
                        printk(KERN_ERR "No pack at 0x%x\n", i);
 #if 0
-                       saa7164_dumphex16FF(buf->port->dev, (p + i), 32);
+                       print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1,
+                                      p + 1, 32, false);
 #endif
                }
        }
@@ -316,7 +295,8 @@ static void saa7164_work_enchandler_helper(struct saa7164_port *port, int bufnr)
                                                printk(KERN_ERR "%s() buf %p guard buffer breach\n",
                                                        __func__, buf);
 #if 0
-                                               saa7164_dumphex16FF(dev, (p + buf->actual_size) - 32 , 64);
+                       print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 1,
+                                      p + buf->actual_size - 32, 64, false);
 #endif
                                }
                        }
@@ -776,24 +756,6 @@ u32 saa7164_getcurrentfirmwareversion(struct saa7164_dev *dev)
        return reg;
 }
 
-/* TODO: Debugging func, remove */
-void saa7164_dumphex16(struct saa7164_dev *dev, u8 *buf, int len)
-{
-       int i;
-
-       printk(KERN_INFO "--------------------> "
-               "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n");
-
-       for (i = 0; i < len; i += 16)
-               printk(KERN_INFO "         [0x%08x] "
-                       "%02x %02x %02x %02x %02x %02x %02x %02x "
-                       "%02x %02x %02x %02x %02x %02x %02x %02x\n", i,
-               *(buf+i+0), *(buf+i+1), *(buf+i+2), *(buf+i+3),
-               *(buf+i+4), *(buf+i+5), *(buf+i+6), *(buf+i+7),
-               *(buf+i+8), *(buf+i+9), *(buf+i+10), *(buf+i+11),
-               *(buf+i+12), *(buf+i+13), *(buf+i+14), *(buf+i+15));
-}
-
 /* TODO: Debugging func, remove */
 void saa7164_dumpregs(struct saa7164_dev *dev, u32 addr)
 {
index 35219b9b0fbcc05844dac644aa82a268a5213fde..437284e747c973d5a3025eb1c39e989313891a08 100644 (file)
@@ -484,7 +484,6 @@ extern unsigned int vbi_buffers;
 /* ----------------------------------------------------------- */
 /* saa7164-core.c                                              */
 void saa7164_dumpregs(struct saa7164_dev *dev, u32 addr);
-void saa7164_dumphex16(struct saa7164_dev *dev, u8 *buf, int len);
 void saa7164_getfirmwarestatus(struct saa7164_dev *dev);
 u32 saa7164_getcurrentfirmwareversion(struct saa7164_dev *dev);
 void saa7164_histogram_update(struct saa7164_histogram *hg, u32 val);
index 8fd1874382c65f7479fddb819a6c171aa6305579..9f62fd89ab57ad5d96272cd57c35f1601e11d243 100644 (file)
@@ -1171,6 +1171,8 @@ static int sh_vou_open(struct file *file)
 
        file->private_data = vou_file;
 
+       if (mutex_lock_interruptible(&vou_dev->fop_lock))
+               return -ERESTARTSYS;
        if (atomic_inc_return(&vou_dev->use_count) == 1) {
                int ret;
                /* First open */
@@ -1181,6 +1183,7 @@ static int sh_vou_open(struct file *file)
                        atomic_dec(&vou_dev->use_count);
                        pm_runtime_put(vdev->v4l2_dev->dev);
                        vou_dev->status = SH_VOU_IDLE;
+                       mutex_unlock(&vou_dev->fop_lock);
                        return ret;
                }
        }
@@ -1191,6 +1194,7 @@ static int sh_vou_open(struct file *file)
                                       V4L2_FIELD_NONE,
                                       sizeof(struct videobuf_buffer), vdev,
                                       &vou_dev->fop_lock);
+       mutex_unlock(&vou_dev->fop_lock);
 
        return 0;
 }
@@ -1204,10 +1208,12 @@ static int sh_vou_release(struct file *file)
        dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
 
        if (!atomic_dec_return(&vou_dev->use_count)) {
+               mutex_lock(&vou_dev->fop_lock);
                /* Last close */
                vou_dev->status = SH_VOU_IDLE;
                sh_vou_reg_a_set(vou_dev, VOUER, 0, 0x101);
                pm_runtime_put(vdev->v4l2_dev->dev);
+               mutex_unlock(&vou_dev->fop_lock);
        }
 
        file->private_data = NULL;
@@ -1218,20 +1224,31 @@ static int sh_vou_release(struct file *file)
 
 static int sh_vou_mmap(struct file *file, struct vm_area_struct *vma)
 {
+       struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
        struct sh_vou_file *vou_file = file->private_data;
+       int ret;
 
        dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
 
-       return videobuf_mmap_mapper(&vou_file->vbq, vma);
+       if (mutex_lock_interruptible(&vou_dev->fop_lock))
+               return -ERESTARTSYS;
+       ret = videobuf_mmap_mapper(&vou_file->vbq, vma);
+       mutex_unlock(&vou_dev->fop_lock);
+       return ret;
 }
 
 static unsigned int sh_vou_poll(struct file *file, poll_table *wait)
 {
+       struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
        struct sh_vou_file *vou_file = file->private_data;
+       unsigned int res;
 
        dev_dbg(vou_file->vbq.dev, "%s()\n", __func__);
 
-       return videobuf_poll_stream(file, &vou_file->vbq, wait);
+       mutex_lock(&vou_dev->fop_lock);
+       res = videobuf_poll_stream(file, &vou_file->vbq, wait);
+       mutex_unlock(&vou_dev->fop_lock);
+       return res;
 }
 
 static int sh_vou_g_chip_ident(struct file *file, void *fh,
@@ -1390,10 +1407,6 @@ static int __devinit sh_vou_probe(struct platform_device *pdev)
        vdev->v4l2_dev = &vou_dev->v4l2_dev;
        vdev->release = video_device_release;
        vdev->lock = &vou_dev->fop_lock;
-       /* Locking in file operations other than ioctl should be done
-          by the driver, not the V4L2 core.
-          This driver needs auditing so that this flag can be removed. */
-       set_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags);
 
        vou_dev->vdev = vdev;
        video_set_drvdata(vdev, vou_dev);
index b03ffecb7438002ee5aad631453d0fa9030c2edc..9758217470f0373961c19de5535de7779f22c2d8 100644 (file)
@@ -507,9 +507,12 @@ static int soc_camera_open(struct file *file)
 
        ici = to_soc_camera_host(icd->parent);
 
+       if (mutex_lock_interruptible(&icd->video_lock))
+               return -ERESTARTSYS;
        if (!try_module_get(ici->ops->owner)) {
                dev_err(icd->pdev, "Couldn't lock capture bus driver.\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto emodule;
        }
 
        icd->use_count++;
@@ -570,6 +573,7 @@ static int soc_camera_open(struct file *file)
                }
                v4l2_ctrl_handler_setup(&icd->ctrl_handler);
        }
+       mutex_unlock(&icd->video_lock);
 
        file->private_data = icd;
        dev_dbg(icd->pdev, "camera device open\n");
@@ -590,6 +594,8 @@ epower:
 eiciadd:
        icd->use_count--;
        module_put(ici->ops->owner);
+emodule:
+       mutex_unlock(&icd->video_lock);
 
        return ret;
 }
@@ -599,6 +605,7 @@ static int soc_camera_close(struct file *file)
        struct soc_camera_device *icd = file->private_data;
        struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
 
+       mutex_lock(&icd->video_lock);
        icd->use_count--;
        if (!icd->use_count) {
                struct soc_camera_link *icl = to_soc_camera_link(icd);
@@ -615,6 +622,7 @@ static int soc_camera_close(struct file *file)
 
        if (icd->streamer == file)
                icd->streamer = NULL;
+       mutex_unlock(&icd->video_lock);
 
        module_put(ici->ops->owner);
 
@@ -645,10 +653,13 @@ static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma)
        if (icd->streamer != file)
                return -EBUSY;
 
+       if (mutex_lock_interruptible(&icd->video_lock))
+               return -ERESTARTSYS;
        if (ici->ops->init_videobuf)
                err = videobuf_mmap_mapper(&icd->vb_vidq, vma);
        else
                err = vb2_mmap(&icd->vb2_vidq, vma);
+       mutex_unlock(&icd->video_lock);
 
        dev_dbg(icd->pdev, "vma start=0x%08lx, size=%ld, ret=%d\n",
                (unsigned long)vma->vm_start,
@@ -662,16 +673,18 @@ static unsigned int soc_camera_poll(struct file *file, poll_table *pt)
 {
        struct soc_camera_device *icd = file->private_data;
        struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+       unsigned res = POLLERR;
 
        if (icd->streamer != file)
-               return -EBUSY;
-
-       if (ici->ops->init_videobuf && list_empty(&icd->vb_vidq.stream)) {
-               dev_err(icd->pdev, "Trying to poll with no queued buffers!\n");
                return POLLERR;
-       }
 
-       return ici->ops->poll(file, pt);
+       mutex_lock(&icd->video_lock);
+       if (ici->ops->init_videobuf && list_empty(&icd->vb_vidq.stream))
+               dev_err(icd->pdev, "Trying to poll with no queued buffers!\n");
+       else
+               res = ici->ops->poll(file, pt);
+       mutex_unlock(&icd->video_lock);
+       return res;
 }
 
 void soc_camera_lock(struct vb2_queue *vq)
@@ -1432,10 +1445,6 @@ static int video_dev_create(struct soc_camera_device *icd)
        vdev->tvnorms           = V4L2_STD_UNKNOWN;
        vdev->ctrl_handler      = &icd->ctrl_handler;
        vdev->lock              = &icd->video_lock;
-       /* Locking in file operations other than ioctl should be done
-          by the driver, not the V4L2 core.
-          This driver needs auditing so that this flag can be removed. */
-       set_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags);
 
        icd->vdev = vdev;
 
diff --git a/drivers/media/video/stk1160/Kconfig b/drivers/media/video/stk1160/Kconfig
new file mode 100644 (file)
index 0000000..1c3a1ec
--- /dev/null
@@ -0,0 +1,20 @@
+config VIDEO_STK1160
+       tristate "STK1160 USB video capture support"
+       depends on VIDEO_DEV && I2C
+       select VIDEOBUF2_VMALLOC
+       select VIDEO_SAA711X
+
+       ---help---
+         This is a video4linux driver for STK1160 based video capture devices.
+
+         To compile this driver as a module, choose M here: the
+         module will be called stk1160
+
+config VIDEO_STK1160_AC97
+       bool "STK1160 AC97 codec support"
+       depends on VIDEO_STK1160 && SND
+       select SND_AC97_CODEC
+
+       ---help---
+         Enables AC97 codec support for stk1160 driver.
+.
diff --git a/drivers/media/video/stk1160/Makefile b/drivers/media/video/stk1160/Makefile
new file mode 100644 (file)
index 0000000..8a3c784
--- /dev/null
@@ -0,0 +1,11 @@
+obj-stk1160-ac97-$(CONFIG_VIDEO_STK1160_AC97) := stk1160-ac97.o
+
+stk1160-y :=   stk1160-core.o \
+               stk1160-v4l.o \
+               stk1160-video.o \
+               stk1160-i2c.o \
+               $(obj-stk1160-ac97-y)
+
+obj-$(CONFIG_VIDEO_STK1160) += stk1160.o
+
+ccflags-y += -Idrivers/media/video
diff --git a/drivers/media/video/stk1160/stk1160-ac97.c b/drivers/media/video/stk1160/stk1160-ac97.c
new file mode 100644 (file)
index 0000000..8d325f5
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * STK1160 driver
+ *
+ * Copyright (C) 2012 Ezequiel Garcia
+ * <elezegarcia--a.t--gmail.com>
+ *
+ * Based on Easycap driver by R.M. Thomas
+ *     Copyright (C) 2010 R.M. Thomas
+ *     <rmthomas--a.t--sciolus.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/ac97_codec.h>
+
+#include "stk1160.h"
+#include "stk1160-reg.h"
+
+static struct snd_ac97 *stk1160_ac97;
+
+static void stk1160_write_ac97(struct snd_ac97 *ac97, u16 reg, u16 value)
+{
+       struct stk1160 *dev = ac97->private_data;
+
+       /* Set codec register address */
+       stk1160_write_reg(dev, STK1160_AC97_ADDR, reg);
+
+       /* Set codec command */
+       stk1160_write_reg(dev, STK1160_AC97_CMD, value & 0xff);
+       stk1160_write_reg(dev, STK1160_AC97_CMD + 1, (value & 0xff00) >> 8);
+
+       /*
+        * Set command write bit to initiate write operation.
+        * The bit will be cleared when transfer is done.
+        */
+       stk1160_write_reg(dev, STK1160_AC97CTL_0, 0x8c);
+}
+
+static u16 stk1160_read_ac97(struct snd_ac97 *ac97, u16 reg)
+{
+       struct stk1160 *dev = ac97->private_data;
+       u8 vall = 0;
+       u8 valh = 0;
+
+       /* Set codec register address */
+       stk1160_write_reg(dev, STK1160_AC97_ADDR, reg);
+
+       /*
+        * Set command read bit to initiate read operation.
+        * The bit will be cleared when transfer is done.
+        */
+       stk1160_write_reg(dev, STK1160_AC97CTL_0, 0x8b);
+
+       /* Retrieve register value */
+       stk1160_read_reg(dev, STK1160_AC97_CMD, &vall);
+       stk1160_read_reg(dev, STK1160_AC97_CMD + 1, &valh);
+
+       return (valh << 8) | vall;
+}
+
+static void stk1160_reset_ac97(struct snd_ac97 *ac97)
+{
+       struct stk1160 *dev = ac97->private_data;
+       /* Two-step reset AC97 interface and hardware codec */
+       stk1160_write_reg(dev, STK1160_AC97CTL_0, 0x94);
+       stk1160_write_reg(dev, STK1160_AC97CTL_0, 0x88);
+
+       /* Set 16-bit audio data and choose L&R channel*/
+       stk1160_write_reg(dev, STK1160_AC97CTL_1 + 2, 0x01);
+}
+
+static struct snd_ac97_bus_ops stk1160_ac97_ops = {
+       .read   = stk1160_read_ac97,
+       .write  = stk1160_write_ac97,
+       .reset  = stk1160_reset_ac97,
+};
+
+int stk1160_ac97_register(struct stk1160 *dev)
+{
+       struct snd_card *card = NULL;
+       struct snd_ac97_bus *ac97_bus;
+       struct snd_ac97_template ac97_template;
+       int rc;
+
+       /*
+        * Just want a card to access ac96 controls,
+        * the actual capture interface will be handled by snd-usb-audio
+        */
+       rc = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+                             THIS_MODULE, 0, &card);
+       if (rc < 0)
+               return rc;
+
+       snd_card_set_dev(card, dev->dev);
+
+       /* TODO: I'm not sure where should I get these names :-( */
+       snprintf(card->shortname, sizeof(card->shortname),
+                "stk1160-mixer");
+       snprintf(card->longname, sizeof(card->longname),
+                "stk1160 ac97 codec mixer control");
+       strncpy(card->driver, dev->dev->driver->name, sizeof(card->driver));
+
+       rc = snd_ac97_bus(card, 0, &stk1160_ac97_ops, NULL, &ac97_bus);
+       if (rc)
+               goto err;
+
+       /* We must set private_data before calling snd_ac97_mixer */
+       memset(&ac97_template, 0, sizeof(ac97_template));
+       ac97_template.private_data = dev;
+       ac97_template.scaps = AC97_SCAP_SKIP_MODEM;
+       rc = snd_ac97_mixer(ac97_bus, &ac97_template, &stk1160_ac97);
+       if (rc)
+               goto err;
+
+       dev->snd_card = card;
+       rc = snd_card_register(card);
+       if (rc)
+               goto err;
+
+       return 0;
+
+err:
+       dev->snd_card = NULL;
+       if (card)
+               snd_card_free(card);
+       return rc;
+}
+
+int stk1160_ac97_unregister(struct stk1160 *dev)
+{
+       struct snd_card *card = dev->snd_card;
+
+       /*
+        * We need to check usb_device,
+        * because ac97 release attempts to communicate with codec
+        */
+       if (card && dev->udev)
+               snd_card_free(card);
+
+       return 0;
+}
diff --git a/drivers/media/video/stk1160/stk1160-core.c b/drivers/media/video/stk1160/stk1160-core.c
new file mode 100644 (file)
index 0000000..74236fd
--- /dev/null
@@ -0,0 +1,432 @@
+/*
+ * STK1160 driver
+ *
+ * Copyright (C) 2012 Ezequiel Garcia
+ * <elezegarcia--a.t--gmail.com>
+ *
+ * Based on Easycap driver by R.M. Thomas
+ *     Copyright (C) 2010 R.M. Thomas
+ *     <rmthomas--a.t--sciolus.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * TODO:
+ *
+ * 1. (Try to) detect if we must register ac97 mixer
+ * 2. Support stream at lower speed: lower frame rate or lower frame size.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+#include <linux/usb.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <media/saa7115.h>
+
+#include "stk1160.h"
+#include "stk1160-reg.h"
+
+static unsigned int input;
+module_param(input, int, 0644);
+MODULE_PARM_DESC(input, "Set default input");
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ezequiel Garcia");
+MODULE_DESCRIPTION("STK1160 driver");
+
+/* Devices supported by this driver */
+static struct usb_device_id stk1160_id_table[] = {
+       { USB_DEVICE(0x05e1, 0x0408) },
+       { }
+};
+MODULE_DEVICE_TABLE(usb, stk1160_id_table);
+
+/* saa7113 I2C address */
+static unsigned short saa7113_addrs[] = {
+       0x4a >> 1,
+       I2C_CLIENT_END
+};
+
+/*
+ * Read/Write stk registers
+ */
+int stk1160_read_reg(struct stk1160 *dev, u16 reg, u8 *value)
+{
+       int ret;
+       int pipe = usb_rcvctrlpipe(dev->udev, 0);
+
+       *value = 0;
+       ret = usb_control_msg(dev->udev, pipe, 0x00,
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       0x00, reg, value, sizeof(u8), HZ);
+       if (ret < 0) {
+               stk1160_err("read failed on reg 0x%x (%d)\n",
+                       reg, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+int stk1160_write_reg(struct stk1160 *dev, u16 reg, u16 value)
+{
+       int ret;
+       int pipe = usb_sndctrlpipe(dev->udev, 0);
+
+       ret =  usb_control_msg(dev->udev, pipe, 0x01,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       value, reg, NULL, 0, HZ);
+       if (ret < 0) {
+               stk1160_err("write failed on reg 0x%x (%d)\n",
+                       reg, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+void stk1160_select_input(struct stk1160 *dev)
+{
+       static const u8 gctrl[] = {
+               0x98, 0x90, 0x88, 0x80
+       };
+
+       if (dev->ctl_input < ARRAY_SIZE(gctrl))
+               stk1160_write_reg(dev, STK1160_GCTRL, gctrl[dev->ctl_input]);
+}
+
+/* TODO: We should break this into pieces */
+static void stk1160_reg_reset(struct stk1160 *dev)
+{
+       int i;
+
+       static const struct regval ctl[] = {
+               {STK1160_GCTRL+2, 0x0078},
+
+               {STK1160_RMCTL+1, 0x0000},
+               {STK1160_RMCTL+3, 0x0002},
+
+               {STK1160_PLLSO,   0x0010},
+               {STK1160_PLLSO+1, 0x0000},
+               {STK1160_PLLSO+2, 0x0014},
+               {STK1160_PLLSO+3, 0x000E},
+
+               {STK1160_PLLFD,   0x0046},
+
+               /* Timing generator setup */
+               {STK1160_TIGEN,   0x0012},
+               {STK1160_TICTL,   0x002D},
+               {STK1160_TICTL+1, 0x0001},
+               {STK1160_TICTL+2, 0x0000},
+               {STK1160_TICTL+3, 0x0000},
+               {STK1160_TIGEN,   0x0080},
+
+               {0xffff, 0xffff}
+       };
+
+       for (i = 0; ctl[i].reg != 0xffff; i++)
+               stk1160_write_reg(dev, ctl[i].reg, ctl[i].val);
+}
+
+static void stk1160_release(struct v4l2_device *v4l2_dev)
+{
+       struct stk1160 *dev = container_of(v4l2_dev, struct stk1160, v4l2_dev);
+
+       stk1160_info("releasing all resources\n");
+
+       stk1160_i2c_unregister(dev);
+
+       v4l2_ctrl_handler_free(&dev->ctrl_handler);
+       v4l2_device_unregister(&dev->v4l2_dev);
+       kfree(dev->alt_max_pkt_size);
+       kfree(dev);
+}
+
+/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
+#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
+
+/*
+ * Scan usb interface and populate max_pkt_size array
+ * with information on each alternate setting.
+ * The array should be allocated by the caller.
+ */
+static int stk1160_scan_usb(struct usb_interface *intf, struct usb_device *udev,
+               unsigned int *max_pkt_size)
+{
+       int i, e, sizedescr, size, ifnum;
+       const struct usb_endpoint_descriptor *desc;
+
+       bool has_video = false, has_audio = false;
+       const char *speed;
+
+       ifnum = intf->altsetting[0].desc.bInterfaceNumber;
+
+       /* Get endpoints */
+       for (i = 0; i < intf->num_altsetting; i++) {
+
+               for (e = 0; e < intf->altsetting[i].desc.bNumEndpoints; e++) {
+
+                       /* This isn't clear enough, at least to me */
+                       desc = &intf->altsetting[i].endpoint[e].desc;
+                       sizedescr = le16_to_cpu(desc->wMaxPacketSize);
+                       size = sizedescr & 0x7ff;
+
+                       if (udev->speed == USB_SPEED_HIGH)
+                               size = size * hb_mult(sizedescr);
+
+                       if (usb_endpoint_xfer_isoc(desc) &&
+                           usb_endpoint_dir_in(desc)) {
+                               switch (desc->bEndpointAddress) {
+                               case STK1160_EP_AUDIO:
+                                       has_audio = true;
+                                       break;
+                               case STK1160_EP_VIDEO:
+                                       has_video = true;
+                                       max_pkt_size[i] = size;
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       /* Is this even possible? */
+       if (!(has_audio || has_video)) {
+               dev_err(&udev->dev, "no audio or video endpoints found\n");
+               return -ENODEV;
+       }
+
+       switch (udev->speed) {
+       case USB_SPEED_LOW:
+               speed = "1.5";
+               break;
+       case USB_SPEED_FULL:
+               speed = "12";
+               break;
+       case USB_SPEED_HIGH:
+               speed = "480";
+               break;
+       default:
+               speed = "unknown";
+       }
+
+       dev_info(&udev->dev, "New device %s %s @ %s Mbps (%04x:%04x, interface %d, class %d)\n",
+               udev->manufacturer ? udev->manufacturer : "",
+               udev->product ? udev->product : "",
+               speed,
+               le16_to_cpu(udev->descriptor.idVendor),
+               le16_to_cpu(udev->descriptor.idProduct),
+               ifnum,
+               intf->altsetting->desc.bInterfaceNumber);
+
+       /* This should never happen, since we rejected audio interfaces */
+       if (has_audio)
+               dev_warn(&udev->dev, "audio interface %d found.\n\
+                               This is not implemented by this driver,\
+                               you should use snd-usb-audio instead\n", ifnum);
+
+       if (has_video)
+               dev_info(&udev->dev, "video interface %d found\n",
+                               ifnum);
+
+       /*
+        * Make sure we have 480 Mbps of bandwidth, otherwise things like
+        * video stream wouldn't likely work, since 12 Mbps is generally
+        * not enough even for most streams.
+        */
+       if (udev->speed != USB_SPEED_HIGH)
+               dev_warn(&udev->dev, "must be connected to a high-speed USB 2.0 port\n\
+                               You may not be able to stream video smoothly\n");
+
+       return 0;
+}
+
+static int stk1160_probe(struct usb_interface *interface,
+               const struct usb_device_id *id)
+{
+       int ifnum;
+       int rc = 0;
+
+       unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */
+       struct usb_device *udev;
+       struct stk1160 *dev;
+
+       ifnum = interface->altsetting[0].desc.bInterfaceNumber;
+       udev = interface_to_usbdev(interface);
+
+       /*
+        * Since usb audio class is supported by snd-usb-audio,
+        * we reject audio interface.
+        */
+       if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO)
+               return -ENODEV;
+
+       /* Alloc an array for all possible max_pkt_size */
+       alt_max_pkt_size = kmalloc(sizeof(alt_max_pkt_size[0]) *
+                       interface->num_altsetting, GFP_KERNEL);
+       if (alt_max_pkt_size == NULL)
+               return -ENOMEM;
+
+       /*
+        * Scan usb posibilities and populate alt_max_pkt_size array.
+        * Also, check if device speed is fast enough.
+        */
+       rc = stk1160_scan_usb(interface, udev, alt_max_pkt_size);
+       if (rc < 0) {
+               kfree(alt_max_pkt_size);
+               return rc;
+       }
+
+       dev = kzalloc(sizeof(struct stk1160), GFP_KERNEL);
+       if (dev == NULL) {
+               kfree(alt_max_pkt_size);
+               return -ENOMEM;
+       }
+
+       dev->alt_max_pkt_size = alt_max_pkt_size;
+       dev->udev = udev;
+       dev->num_alt = interface->num_altsetting;
+       dev->ctl_input = input;
+
+       /* We save struct device for debug purposes only */
+       dev->dev = &interface->dev;
+
+       usb_set_intfdata(interface, dev);
+
+       /* initialize videobuf2 stuff */
+       rc = stk1160_vb2_setup(dev);
+       if (rc < 0)
+               goto free_err;
+
+       /*
+        * There is no need to take any locks here in probe
+        * because we register the device node as the *last* thing.
+        */
+       spin_lock_init(&dev->buf_lock);
+       mutex_init(&dev->v4l_lock);
+       mutex_init(&dev->vb_queue_lock);
+
+       rc = v4l2_ctrl_handler_init(&dev->ctrl_handler, 0);
+       if (rc) {
+               stk1160_err("v4l2_ctrl_handler_init failed (%d)\n", rc);
+               goto free_err;
+       }
+
+       /*
+        * We obtain a v4l2_dev but defer
+        * registration of video device node as the last thing.
+        * There is no need to set the name if we give a device struct
+        */
+       dev->v4l2_dev.release = stk1160_release;
+       dev->v4l2_dev.ctrl_handler = &dev->ctrl_handler;
+       rc = v4l2_device_register(dev->dev, &dev->v4l2_dev);
+       if (rc) {
+               stk1160_err("v4l2_device_register failed (%d)\n", rc);
+               goto free_ctrl;
+       }
+
+       rc = stk1160_i2c_register(dev);
+       if (rc < 0)
+               goto unreg_v4l2;
+
+       /*
+        * To the best of my knowledge stk1160 boards only have
+        * saa7113, but it doesn't hurt to support them all.
+        */
+       dev->sd_saa7115 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
+               "saa7115_auto", 0, saa7113_addrs);
+
+       stk1160_info("driver ver %s successfully loaded\n",
+               STK1160_VERSION);
+
+       /* i2c reset saa711x */
+       v4l2_device_call_all(&dev->v4l2_dev, 0, core, reset, 0);
+       v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
+                               0, 0, 0);
+       v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
+
+       /* reset stk1160 to default values */
+       stk1160_reg_reset(dev);
+
+       /* select default input */
+       stk1160_select_input(dev);
+
+       stk1160_ac97_register(dev);
+
+       rc = stk1160_video_register(dev);
+       if (rc < 0)
+               goto unreg_i2c;
+
+       return 0;
+
+unreg_i2c:
+       stk1160_i2c_unregister(dev);
+unreg_v4l2:
+       v4l2_device_unregister(&dev->v4l2_dev);
+free_ctrl:
+       v4l2_ctrl_handler_free(&dev->ctrl_handler);
+free_err:
+       kfree(alt_max_pkt_size);
+       kfree(dev);
+
+       return rc;
+}
+
+static void stk1160_disconnect(struct usb_interface *interface)
+{
+       struct stk1160 *dev;
+
+       dev = usb_get_intfdata(interface);
+       usb_set_intfdata(interface, NULL);
+
+       /*
+        * Wait until all current v4l2 operation are finished
+        * then deallocate resources
+        */
+       mutex_lock(&dev->vb_queue_lock);
+       mutex_lock(&dev->v4l_lock);
+
+       /* Here is the only place where isoc get released */
+       stk1160_uninit_isoc(dev);
+
+       /* ac97 unregister needs to be done before usb_device is cleared */
+       stk1160_ac97_unregister(dev);
+
+       stk1160_clear_queue(dev);
+
+       video_unregister_device(&dev->vdev);
+       v4l2_device_disconnect(&dev->v4l2_dev);
+
+       /* This way current users can detect device is gone */
+       dev->udev = NULL;
+
+       mutex_unlock(&dev->v4l_lock);
+       mutex_unlock(&dev->vb_queue_lock);
+
+       /*
+        * This calls stk1160_release if it's the last reference.
+        * therwise, release is posponed until there are no users left.
+        */
+       v4l2_device_put(&dev->v4l2_dev);
+}
+
+static struct usb_driver stk1160_usb_driver = {
+       .name = "stk1160",
+       .id_table = stk1160_id_table,
+       .probe = stk1160_probe,
+       .disconnect = stk1160_disconnect,
+};
+
+module_usb_driver(stk1160_usb_driver);
diff --git a/drivers/media/video/stk1160/stk1160-i2c.c b/drivers/media/video/stk1160/stk1160-i2c.c
new file mode 100644 (file)
index 0000000..176ac93
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * STK1160 driver
+ *
+ * Copyright (C) 2012 Ezequiel Garcia
+ * <elezegarcia--a.t--gmail.com>
+ *
+ * Based on Easycap driver by R.M. Thomas
+ *     Copyright (C) 2010 R.M. Thomas
+ *     <rmthomas--a.t--sciolus.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+
+#include "stk1160.h"
+#include "stk1160-reg.h"
+
+static unsigned int i2c_debug;
+module_param(i2c_debug, int, 0644);
+MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
+
+#define dprintk_i2c(fmt, args...)                              \
+do {                                                           \
+       if (i2c_debug)                                          \
+               printk(KERN_DEBUG fmt, ##args);                 \
+} while (0)
+
+static int stk1160_i2c_busy_wait(struct stk1160 *dev, u8 wait_bit_mask)
+{
+       unsigned long end;
+       u8 flag;
+
+       /* Wait until read/write finish bit is set */
+       end = jiffies + msecs_to_jiffies(STK1160_I2C_TIMEOUT);
+       while (time_is_after_jiffies(end)) {
+
+               stk1160_read_reg(dev, STK1160_SICTL+1, &flag);
+               /* read/write done? */
+               if (flag & wait_bit_mask)
+                       goto done;
+
+               usleep_range(10 * USEC_PER_MSEC, 20 * USEC_PER_MSEC);
+       }
+
+       return -ETIMEDOUT;
+
+done:
+       return 0;
+}
+
+static int stk1160_i2c_write_reg(struct stk1160 *dev, u8 addr,
+               u8 reg, u8 value)
+{
+       int rc;
+
+       /* Set serial device address */
+       rc = stk1160_write_reg(dev, STK1160_SICTL_SDA, addr);
+       if (rc < 0)
+               return rc;
+
+       /* Set i2c device register sub-address */
+       rc = stk1160_write_reg(dev, STK1160_SBUSW_WA, reg);
+       if (rc < 0)
+               return rc;
+
+       /* Set i2c device register value */
+       rc = stk1160_write_reg(dev, STK1160_SBUSW_WD, value);
+       if (rc < 0)
+               return rc;
+
+       /* Start write now */
+       rc = stk1160_write_reg(dev, STK1160_SICTL, 0x01);
+       if (rc < 0)
+               return rc;
+
+       rc = stk1160_i2c_busy_wait(dev, 0x04);
+       if (rc < 0)
+               return rc;
+
+       return 0;
+}
+
+static int stk1160_i2c_read_reg(struct stk1160 *dev, u8 addr,
+               u8 reg, u8 *value)
+{
+       int rc;
+
+       /* Set serial device address */
+       rc = stk1160_write_reg(dev, STK1160_SICTL_SDA, addr);
+       if (rc < 0)
+               return rc;
+
+       /* Set i2c device register sub-address */
+       rc = stk1160_write_reg(dev, STK1160_SBUSR_RA, reg);
+       if (rc < 0)
+               return rc;
+
+       /* Start read now */
+       rc = stk1160_write_reg(dev, STK1160_SICTL, 0x20);
+       if (rc < 0)
+               return rc;
+
+       rc = stk1160_i2c_busy_wait(dev, 0x01);
+       if (rc < 0)
+               return rc;
+
+       stk1160_read_reg(dev, STK1160_SBUSR_RD, value);
+       if (rc < 0)
+               return rc;
+
+       return 0;
+}
+
+/*
+ * stk1160_i2c_check_for_device()
+ * check if there is a i2c_device at the supplied address
+ */
+static int stk1160_i2c_check_for_device(struct stk1160 *dev,
+               unsigned char addr)
+{
+       int rc;
+
+       /* Set serial device address */
+       rc = stk1160_write_reg(dev, STK1160_SICTL_SDA, addr);
+       if (rc < 0)
+               return rc;
+
+       /* Set device sub-address, we'll chip version reg */
+       rc = stk1160_write_reg(dev, STK1160_SBUSR_RA, 0x00);
+       if (rc < 0)
+               return rc;
+
+       /* Start read now */
+       rc = stk1160_write_reg(dev, STK1160_SICTL, 0x20);
+       if (rc < 0)
+               return rc;
+
+       rc = stk1160_i2c_busy_wait(dev, 0x01);
+       if (rc < 0)
+               return -ENODEV;
+
+       return 0;
+}
+
+/*
+ * stk1160_i2c_xfer()
+ * the main i2c transfer function
+ */
+static int stk1160_i2c_xfer(struct i2c_adapter *i2c_adap,
+                          struct i2c_msg msgs[], int num)
+{
+       struct stk1160 *dev = i2c_adap->algo_data;
+       int addr, rc, i;
+
+       for (i = 0; i < num; i++) {
+               addr = msgs[i].addr << 1;
+               dprintk_i2c("%s: addr=%x", __func__, addr);
+
+               if (!msgs[i].len) {
+                       /* no len: check only for device presence */
+                       rc = stk1160_i2c_check_for_device(dev, addr);
+                       if (rc < 0) {
+                               dprintk_i2c(" no device\n");
+                               return rc;
+                       }
+
+               } else if (msgs[i].flags & I2C_M_RD) {
+                       /* read request without preceding register selection */
+                       dprintk_i2c(" subaddr not selected");
+                       rc = -EOPNOTSUPP;
+                       goto err;
+
+               } else if (i + 1 < num && msgs[i].len <= 2 &&
+                          (msgs[i + 1].flags & I2C_M_RD) &&
+                          msgs[i].addr == msgs[i + 1].addr) {
+
+                       if (msgs[i].len != 1 || msgs[i + 1].len != 1) {
+                               dprintk_i2c(" len not supported");
+                               rc = -EOPNOTSUPP;
+                               goto err;
+                       }
+
+                       dprintk_i2c(" subaddr=%x", msgs[i].buf[0]);
+
+                       rc = stk1160_i2c_read_reg(dev, addr, msgs[i].buf[0],
+                               msgs[i + 1].buf);
+
+                       dprintk_i2c(" read=%x", *msgs[i + 1].buf);
+
+                       /* consumed two msgs, so we skip one of them */
+                       i++;
+
+               } else {
+                       if (msgs[i].len != 2) {
+                               dprintk_i2c(" len not supported");
+                               rc = -EOPNOTSUPP;
+                               goto err;
+                       }
+
+                       dprintk_i2c(" subaddr=%x write=%x",
+                               msgs[i].buf[0],  msgs[i].buf[1]);
+
+                       rc = stk1160_i2c_write_reg(dev, addr, msgs[i].buf[0],
+                               msgs[i].buf[1]);
+               }
+
+               if (rc < 0)
+                       goto err;
+               dprintk_i2c(" OK\n");
+       }
+
+       return num;
+err:
+       dprintk_i2c(" ERROR: %d\n", rc);
+       return num;
+}
+
+/*
+ * functionality(), what da heck is this?
+ */
+static u32 functionality(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm algo = {
+       .master_xfer   = stk1160_i2c_xfer,
+       .functionality = functionality,
+};
+
+static struct i2c_adapter adap_template = {
+       .owner = THIS_MODULE,
+       .name = "stk1160",
+       .algo = &algo,
+};
+
+static struct i2c_client client_template = {
+       .name = "stk1160 internal",
+};
+
+/*
+ * stk1160_i2c_register()
+ * register i2c bus
+ */
+int stk1160_i2c_register(struct stk1160 *dev)
+{
+       int rc;
+
+       dev->i2c_adap = adap_template;
+       dev->i2c_adap.dev.parent = dev->dev;
+       strcpy(dev->i2c_adap.name, "stk1160");
+       dev->i2c_adap.algo_data = dev;
+
+       i2c_set_adapdata(&dev->i2c_adap, &dev->v4l2_dev);
+
+       rc = i2c_add_adapter(&dev->i2c_adap);
+       if (rc < 0) {
+               stk1160_err("cannot add i2c adapter (%d)\n", rc);
+               return rc;
+       }
+
+       dev->i2c_client = client_template;
+       dev->i2c_client.adapter = &dev->i2c_adap;
+
+       /* Set i2c clock divider device address */
+       stk1160_write_reg(dev, STK1160_SICTL_CD,  0x0f);
+
+       /* ??? */
+       stk1160_write_reg(dev, STK1160_ASIC + 3,  0x00);
+
+       return 0;
+}
+
+/*
+ * stk1160_i2c_unregister()
+ * unregister i2c_bus
+ */
+int stk1160_i2c_unregister(struct stk1160 *dev)
+{
+       i2c_del_adapter(&dev->i2c_adap);
+       return 0;
+}
diff --git a/drivers/media/video/stk1160/stk1160-reg.h b/drivers/media/video/stk1160/stk1160-reg.h
new file mode 100644 (file)
index 0000000..3e49da6
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * STK1160 driver
+ *
+ * Copyright (C) 2012 Ezequiel Garcia
+ * <elezegarcia--a.t--gmail.com>
+ *
+ * Based on Easycap driver by R.M. Thomas
+ *     Copyright (C) 2010 R.M. Thomas
+ *     <rmthomas--a.t--sciolus.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+/* GPIO Control */
+#define STK1160_GCTRL                  0x000
+
+/* Remote Wakup Control */
+#define STK1160_RMCTL                  0x00c
+
+/*
+ * Decoder Control Register:
+ * This byte controls capture start/stop
+ * with bit #7 (0x?? OR 0x80 to activate).
+ */
+#define STK1160_DCTRL                  0x100
+
+/* Capture Frame Start Position */
+#define STK116_CFSPO                   0x110
+#define STK116_CFSPO_STX_L             0x110
+#define STK116_CFSPO_STX_H             0x111
+#define STK116_CFSPO_STY_L             0x112
+#define STK116_CFSPO_STY_H             0x113
+
+/* Capture Frame End Position */
+#define STK116_CFEPO                   0x114
+#define STK116_CFEPO_ENX_L             0x114
+#define STK116_CFEPO_ENX_H             0x115
+#define STK116_CFEPO_ENY_L             0x116
+#define STK116_CFEPO_ENY_H             0x117
+
+/* Serial Interface Control  */
+#define STK1160_SICTL                  0x200
+#define STK1160_SICTL_CD               0x202
+#define STK1160_SICTL_SDA              0x203
+
+/* Serial Bus Write */
+#define STK1160_SBUSW                  0x204
+#define STK1160_SBUSW_WA               0x204
+#define STK1160_SBUSW_WD               0x205
+
+/* Serial Bus Read */
+#define STK1160_SBUSR                  0x208
+#define STK1160_SBUSR_RA               0x208
+#define STK1160_SBUSR_RD               0x209
+
+/* Alternate Serial Inteface Control */
+#define STK1160_ASIC                   0x2fc
+
+/* PLL Select Options */
+#define STK1160_PLLSO                  0x018
+
+/* PLL Frequency Divider */
+#define STK1160_PLLFD                  0x01c
+
+/* Timing Generator */
+#define STK1160_TIGEN                  0x300
+
+/* Timing Control Parameter */
+#define STK1160_TICTL                  0x350
+
+/* AC97 Audio Control */
+#define STK1160_AC97CTL_0              0x500
+#define STK1160_AC97CTL_1              0x504
+
+/* Use [0:6] bits of register 0x504 to set codec command address */
+#define STK1160_AC97_ADDR              0x504
+/* Use [16:31] bits of register 0x500 to set codec command data */
+#define STK1160_AC97_CMD               0x502
+
+/* Audio I2S Interface */
+#define STK1160_I2SCTL                 0x50c
+
+/* EEPROM Interface */
+#define STK1160_EEPROM_SZ              0x5f0
diff --git a/drivers/media/video/stk1160/stk1160-v4l.c b/drivers/media/video/stk1160/stk1160-v4l.c
new file mode 100644 (file)
index 0000000..360bdbe
--- /dev/null
@@ -0,0 +1,738 @@
+/*
+ * STK1160 driver
+ *
+ * Copyright (C) 2012 Ezequiel Garcia
+ * <elezegarcia--a.t--gmail.com>
+ *
+ * Based on Easycap driver by R.M. Thomas
+ *     Copyright (C) 2010 R.M. Thomas
+ *     <rmthomas--a.t--sciolus.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-fh.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/videobuf2-vmalloc.h>
+
+#include <media/saa7115.h>
+
+#include "stk1160.h"
+#include "stk1160-reg.h"
+
+static unsigned int vidioc_debug;
+module_param(vidioc_debug, int, 0644);
+MODULE_PARM_DESC(vidioc_debug, "enable debug messages [vidioc]");
+
+static bool keep_buffers;
+module_param(keep_buffers, bool, 0644);
+MODULE_PARM_DESC(keep_buffers, "don't release buffers upon stop streaming");
+
+/* supported video standards */
+static struct stk1160_fmt format[] = {
+       {
+               .name     = "16 bpp YUY2, 4:2:2, packed",
+               .fourcc   = V4L2_PIX_FMT_UYVY,
+               .depth    = 16,
+       }
+};
+
+static void stk1160_set_std(struct stk1160 *dev)
+{
+       int i;
+
+       static struct regval std525[] = {
+
+               /* 720x480 */
+
+               /* Frame start */
+               {STK116_CFSPO_STX_L, 0x0000},
+               {STK116_CFSPO_STX_H, 0x0000},
+               {STK116_CFSPO_STY_L, 0x0003},
+               {STK116_CFSPO_STY_H, 0x0000},
+
+               /* Frame end */
+               {STK116_CFEPO_ENX_L, 0x05a0},
+               {STK116_CFEPO_ENX_H, 0x0005},
+               {STK116_CFEPO_ENY_L, 0x00f3},
+               {STK116_CFEPO_ENY_H, 0x0000},
+
+               {0xffff, 0xffff}
+       };
+
+       static struct regval std625[] = {
+
+               /* 720x576 */
+
+               /* TODO: Each line of frame has some junk at the end */
+               /* Frame start */
+               {STK116_CFSPO,   0x0000},
+               {STK116_CFSPO+1, 0x0000},
+               {STK116_CFSPO+2, 0x0001},
+               {STK116_CFSPO+3, 0x0000},
+
+               /* Frame end */
+               {STK116_CFEPO,   0x05a0},
+               {STK116_CFEPO+1, 0x0005},
+               {STK116_CFEPO+2, 0x0121},
+               {STK116_CFEPO+3, 0x0001},
+
+               {0xffff, 0xffff}
+       };
+
+       if (dev->norm & V4L2_STD_525_60) {
+               stk1160_dbg("registers to NTSC like standard\n");
+               for (i = 0; std525[i].reg != 0xffff; i++)
+                       stk1160_write_reg(dev, std525[i].reg, std525[i].val);
+       } else {
+               stk1160_dbg("registers to PAL like standard\n");
+               for (i = 0; std625[i].reg != 0xffff; i++)
+                       stk1160_write_reg(dev, std625[i].reg, std625[i].val);
+       }
+
+}
+
+/*
+ * Set a new alternate setting.
+ * Returns true is dev->max_pkt_size has changed, false otherwise.
+ */
+static bool stk1160_set_alternate(struct stk1160 *dev)
+{
+       int i, prev_alt = dev->alt;
+       unsigned int min_pkt_size;
+       bool new_pkt_size;
+
+       /*
+        * If we don't set right alternate,
+        * then we will get a green screen with junk.
+        */
+       min_pkt_size = STK1160_MIN_PKT_SIZE;
+
+       for (i = 0; i < dev->num_alt; i++) {
+               /* stop when the selected alt setting offers enough bandwidth */
+               if (dev->alt_max_pkt_size[i] >= min_pkt_size) {
+                       dev->alt = i;
+                       break;
+               /*
+                * otherwise make sure that we end up with the maximum bandwidth
+                * because the min_pkt_size equation might be wrong...
+                */
+               } else if (dev->alt_max_pkt_size[i] >
+                          dev->alt_max_pkt_size[dev->alt])
+                       dev->alt = i;
+       }
+
+       stk1160_info("setting alternate %d\n", dev->alt);
+
+       if (dev->alt != prev_alt) {
+               stk1160_dbg("minimum isoc packet size: %u (alt=%d)\n",
+                               min_pkt_size, dev->alt);
+               stk1160_dbg("setting alt %d with wMaxPacketSize=%u\n",
+                              dev->alt, dev->alt_max_pkt_size[dev->alt]);
+               usb_set_interface(dev->udev, 0, dev->alt);
+       }
+
+       new_pkt_size = dev->max_pkt_size != dev->alt_max_pkt_size[dev->alt];
+       dev->max_pkt_size = dev->alt_max_pkt_size[dev->alt];
+
+       return new_pkt_size;
+}
+
+static int stk1160_start_streaming(struct stk1160 *dev)
+{
+       int i, rc;
+       bool new_pkt_size;
+
+       /* Check device presence */
+       if (!dev->udev)
+               return -ENODEV;
+
+       if (mutex_lock_interruptible(&dev->v4l_lock))
+               return -ERESTARTSYS;
+       /*
+        * For some reason it is mandatory to set alternate *first*
+        * and only *then* initialize isoc urbs.
+        * Someone please explain me why ;)
+        */
+       new_pkt_size = stk1160_set_alternate(dev);
+
+       /*
+        * We (re)allocate isoc urbs if:
+        * there is no allocated isoc urbs, OR
+        * a new dev->max_pkt_size is detected
+        */
+       if (!dev->isoc_ctl.num_bufs || new_pkt_size) {
+               rc = stk1160_alloc_isoc(dev);
+               if (rc < 0)
+                       return rc;
+       }
+
+       /* submit urbs and enables IRQ */
+       for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+               rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_KERNEL);
+               if (rc) {
+                       stk1160_err("cannot submit urb[%d] (%d)\n", i, rc);
+                       stk1160_uninit_isoc(dev);
+                       return rc;
+               }
+       }
+
+       /* Start saa711x */
+       v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 1);
+
+       /* Start stk1160 */
+       stk1160_write_reg(dev, STK1160_DCTRL, 0xb3);
+       stk1160_write_reg(dev, STK1160_DCTRL+3, 0x00);
+
+       stk1160_dbg("streaming started\n");
+
+       mutex_unlock(&dev->v4l_lock);
+
+       return 0;
+}
+
+/* Must be called with v4l_lock hold */
+static void stk1160_stop_hw(struct stk1160 *dev)
+{
+       /* If the device is not physically present, there is nothing to do */
+       if (!dev->udev)
+               return;
+
+       /* set alternate 0 */
+       dev->alt = 0;
+       stk1160_info("setting alternate %d\n", dev->alt);
+       usb_set_interface(dev->udev, 0, 0);
+
+       /* Stop stk1160 */
+       stk1160_write_reg(dev, STK1160_DCTRL, 0x00);
+       stk1160_write_reg(dev, STK1160_DCTRL+3, 0x00);
+
+       /* Stop saa711x */
+       v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
+}
+
+static int stk1160_stop_streaming(struct stk1160 *dev)
+{
+       if (mutex_lock_interruptible(&dev->v4l_lock))
+               return -ERESTARTSYS;
+
+       stk1160_cancel_isoc(dev);
+
+       /*
+        * It is possible to keep buffers around using a module parameter.
+        * This is intended to avoid memory fragmentation.
+        */
+       if (!keep_buffers)
+               stk1160_free_isoc(dev);
+
+       stk1160_stop_hw(dev);
+
+       stk1160_clear_queue(dev);
+
+       stk1160_dbg("streaming stopped\n");
+
+       mutex_unlock(&dev->v4l_lock);
+
+       return 0;
+}
+
+static struct v4l2_file_operations stk1160_fops = {
+       .owner = THIS_MODULE,
+       .open = v4l2_fh_open,
+       .release = vb2_fop_release,
+       .read = vb2_fop_read,
+       .poll = vb2_fop_poll,
+       .mmap = vb2_fop_mmap,
+       .unlocked_ioctl = video_ioctl2,
+};
+
+/*
+ * vidioc ioctls
+ */
+static int vidioc_querycap(struct file *file,
+               void *priv, struct v4l2_capability *cap)
+{
+       struct stk1160 *dev = video_drvdata(file);
+
+       strcpy(cap->driver, "stk1160");
+       strcpy(cap->card, "stk1160");
+       usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
+       cap->device_caps =
+               V4L2_CAP_VIDEO_CAPTURE |
+               V4L2_CAP_STREAMING |
+               V4L2_CAP_READWRITE;
+       cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+       return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
+               struct v4l2_fmtdesc *f)
+{
+       if (f->index != 0)
+               return -EINVAL;
+
+       strlcpy(f->description, format[f->index].name, sizeof(f->description));
+       f->pixelformat = format[f->index].fourcc;
+       return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct stk1160 *dev = video_drvdata(file);
+
+       f->fmt.pix.width = dev->width;
+       f->fmt.pix.height = dev->height;
+       f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+       f->fmt.pix.pixelformat = dev->fmt->fourcc;
+       f->fmt.pix.bytesperline = dev->width * 2;
+       f->fmt.pix.sizeimage = dev->height * f->fmt.pix.bytesperline;
+       f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+       return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+                       struct v4l2_format *f)
+{
+       struct stk1160 *dev = video_drvdata(file);
+
+       if (f->fmt.pix.pixelformat != format[0].fourcc) {
+               stk1160_err("fourcc format 0x%08x invalid\n",
+                       f->fmt.pix.pixelformat);
+               return -EINVAL;
+       }
+
+       /*
+        * User can't choose size at his own will,
+        * so we just return him the current size chosen
+        * at standard selection.
+        * TODO: Implement frame scaling?
+        */
+
+       f->fmt.pix.width = dev->width;
+       f->fmt.pix.height = dev->height;
+       f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+       f->fmt.pix.bytesperline = dev->width * 2;
+       f->fmt.pix.sizeimage = dev->height * f->fmt.pix.bytesperline;
+       f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+
+       return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+                                       struct v4l2_format *f)
+{
+       struct stk1160 *dev = video_drvdata(file);
+       struct vb2_queue *q = &dev->vb_vidq;
+       int rc;
+
+       if (vb2_is_busy(q))
+               return -EBUSY;
+
+       rc = vidioc_try_fmt_vid_cap(file, priv, f);
+       if (rc < 0)
+               return rc;
+
+       /* We don't support any format changes */
+
+       return 0;
+}
+
+static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *norm)
+{
+       struct stk1160 *dev = video_drvdata(file);
+       v4l2_device_call_all(&dev->v4l2_dev, 0, video, querystd, norm);
+       return 0;
+}
+
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
+{
+       struct stk1160 *dev = video_drvdata(file);
+
+       *norm = dev->norm;
+       return 0;
+}
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
+{
+       struct stk1160 *dev = video_drvdata(file);
+       struct vb2_queue *q = &dev->vb_vidq;
+
+       if (vb2_is_busy(q))
+               return -EBUSY;
+
+       /* Check device presence */
+       if (!dev->udev)
+               return -ENODEV;
+
+       /* We need to set this now, before we call stk1160_set_std */
+       dev->norm = *norm;
+
+       /* This is taken from saa7115 video decoder */
+       if (dev->norm & V4L2_STD_525_60) {
+               dev->width = 720;
+               dev->height = 480;
+       } else if (dev->norm & V4L2_STD_625_50) {
+               dev->width = 720;
+               dev->height = 576;
+       } else {
+               stk1160_err("invalid standard\n");
+               return -EINVAL;
+       }
+
+       stk1160_set_std(dev);
+
+       v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std,
+                       dev->norm);
+
+       return 0;
+}
+
+
+static int vidioc_enum_input(struct file *file, void *priv,
+                               struct v4l2_input *i)
+{
+       struct stk1160 *dev = video_drvdata(file);
+
+       if (i->index > STK1160_MAX_INPUT)
+               return -EINVAL;
+
+       sprintf(i->name, "Composite%d", i->index);
+       i->type = V4L2_INPUT_TYPE_CAMERA;
+       i->std = dev->vdev.tvnorms;
+       return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+       struct stk1160 *dev = video_drvdata(file);
+       *i = dev->ctl_input;
+       return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+       struct stk1160 *dev = video_drvdata(file);
+
+       if (vb2_is_busy(&dev->vb_vidq))
+               return -EBUSY;
+
+       if (i > STK1160_MAX_INPUT)
+               return -EINVAL;
+
+       dev->ctl_input = i;
+
+       stk1160_select_input(dev);
+
+       return 0;
+}
+
+static int vidioc_g_chip_ident(struct file *file, void *priv,
+              struct v4l2_dbg_chip_ident *chip)
+{
+       switch (chip->match.type) {
+       case V4L2_CHIP_MATCH_HOST:
+               chip->ident = V4L2_IDENT_NONE;
+               chip->revision = 0;
+               return 0;
+       default:
+               return -EINVAL;
+       }
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int vidioc_g_register(struct file *file, void *priv,
+                            struct v4l2_dbg_register *reg)
+{
+       struct stk1160 *dev = video_drvdata(file);
+       int rc;
+       u8 val;
+
+       switch (reg->match.type) {
+       case V4L2_CHIP_MATCH_AC97:
+               /* TODO: Support me please :-( */
+               return -EINVAL;
+       case V4L2_CHIP_MATCH_I2C_DRIVER:
+               v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
+               return 0;
+       case V4L2_CHIP_MATCH_I2C_ADDR:
+               /* TODO: is this correct? */
+               v4l2_device_call_all(&dev->v4l2_dev, 0, core, g_register, reg);
+               return 0;
+       default:
+               if (!v4l2_chip_match_host(&reg->match))
+                       return -EINVAL;
+       }
+
+       /* Match host */
+       rc = stk1160_read_reg(dev, reg->reg, &val);
+       reg->val = val;
+       reg->size = 1;
+
+       return rc;
+}
+
+static int vidioc_s_register(struct file *file, void *priv,
+                            struct v4l2_dbg_register *reg)
+{
+       struct stk1160 *dev = video_drvdata(file);
+
+       switch (reg->match.type) {
+       case V4L2_CHIP_MATCH_AC97:
+               return -EINVAL;
+       case V4L2_CHIP_MATCH_I2C_DRIVER:
+               v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
+               return 0;
+       case V4L2_CHIP_MATCH_I2C_ADDR:
+               /* TODO: is this correct? */
+               v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
+               return 0;
+       default:
+               if (!v4l2_chip_match_host(&reg->match))
+                       return -EINVAL;
+       }
+
+       /* Match host */
+       return stk1160_write_reg(dev, reg->reg, cpu_to_le16(reg->val));
+}
+#endif
+
+static const struct v4l2_ioctl_ops stk1160_ioctl_ops = {
+       .vidioc_querycap      = vidioc_querycap,
+       .vidioc_enum_fmt_vid_cap  = vidioc_enum_fmt_vid_cap,
+       .vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,
+       .vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,
+       .vidioc_querystd      = vidioc_querystd,
+       .vidioc_g_std         = vidioc_g_std,
+       .vidioc_s_std         = vidioc_s_std,
+       .vidioc_enum_input    = vidioc_enum_input,
+       .vidioc_g_input       = vidioc_g_input,
+       .vidioc_s_input       = vidioc_s_input,
+
+       /* vb2 takes care of these */
+       .vidioc_reqbufs       = vb2_ioctl_reqbufs,
+       .vidioc_querybuf      = vb2_ioctl_querybuf,
+       .vidioc_qbuf          = vb2_ioctl_qbuf,
+       .vidioc_dqbuf         = vb2_ioctl_dqbuf,
+       .vidioc_streamon      = vb2_ioctl_streamon,
+       .vidioc_streamoff     = vb2_ioctl_streamoff,
+
+       .vidioc_log_status  = v4l2_ctrl_log_status,
+       .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+       .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+       .vidioc_g_chip_ident = vidioc_g_chip_ident,
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+       .vidioc_g_register = vidioc_g_register,
+       .vidioc_s_register = vidioc_s_register,
+#endif
+};
+
+/********************************************************************/
+
+/*
+ * Videobuf2 operations
+ */
+static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *v4l_fmt,
+                               unsigned int *nbuffers, unsigned int *nplanes,
+                               unsigned int sizes[], void *alloc_ctxs[])
+{
+       struct stk1160 *dev = vb2_get_drv_priv(vq);
+       unsigned long size;
+
+       size = dev->width * dev->height * 2;
+
+       /*
+        * Here we can change the number of buffers being requested.
+        * So, we set a minimum and a maximum like this:
+        */
+       *nbuffers = clamp_t(unsigned int, *nbuffers,
+                       STK1160_MIN_VIDEO_BUFFERS, STK1160_MAX_VIDEO_BUFFERS);
+
+       /* This means a packed colorformat */
+       *nplanes = 1;
+
+       sizes[0] = size;
+
+       stk1160_info("%s: buffer count %d, each %ld bytes\n",
+                       __func__, *nbuffers, size);
+
+       return 0;
+}
+
+static void buffer_queue(struct vb2_buffer *vb)
+{
+       unsigned long flags;
+       struct stk1160 *dev = vb2_get_drv_priv(vb->vb2_queue);
+       struct stk1160_buffer *buf =
+               container_of(vb, struct stk1160_buffer, vb);
+
+       spin_lock_irqsave(&dev->buf_lock, flags);
+       if (!dev->udev) {
+               /*
+                * If the device is disconnected return the buffer to userspace
+                * directly. The next QBUF call will fail with -ENODEV.
+                */
+               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+       } else {
+
+               buf->mem = vb2_plane_vaddr(vb, 0);
+               buf->length = vb2_plane_size(vb, 0);
+               buf->bytesused = 0;
+               buf->pos = 0;
+
+               /*
+                * If buffer length is less from expected then we return
+                * the buffer to userspace directly.
+                */
+               if (buf->length < dev->width * dev->height * 2)
+                       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+               else
+                       list_add_tail(&buf->list, &dev->avail_bufs);
+
+       }
+       spin_unlock_irqrestore(&dev->buf_lock, flags);
+}
+
+static int start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+       struct stk1160 *dev = vb2_get_drv_priv(vq);
+       return stk1160_start_streaming(dev);
+}
+
+/* abort streaming and wait for last buffer */
+static int stop_streaming(struct vb2_queue *vq)
+{
+       struct stk1160 *dev = vb2_get_drv_priv(vq);
+       return stk1160_stop_streaming(dev);
+}
+
+static struct vb2_ops stk1160_video_qops = {
+       .queue_setup            = queue_setup,
+       .buf_queue              = buffer_queue,
+       .start_streaming        = start_streaming,
+       .stop_streaming         = stop_streaming,
+       .wait_prepare           = vb2_ops_wait_prepare,
+       .wait_finish            = vb2_ops_wait_finish,
+};
+
+static struct video_device v4l_template = {
+       .name = "stk1160",
+       .tvnorms = V4L2_STD_525_60 | V4L2_STD_625_50,
+       .fops = &stk1160_fops,
+       .ioctl_ops = &stk1160_ioctl_ops,
+       .release = video_device_release_empty,
+};
+
+/********************************************************************/
+
+/* Must be called with both v4l_lock and vb_queue_lock hold */
+void stk1160_clear_queue(struct stk1160 *dev)
+{
+       struct stk1160_buffer *buf;
+       unsigned long flags;
+
+       /* Release all active buffers */
+       spin_lock_irqsave(&dev->buf_lock, flags);
+       while (!list_empty(&dev->avail_bufs)) {
+               buf = list_first_entry(&dev->avail_bufs,
+                       struct stk1160_buffer, list);
+               list_del(&buf->list);
+               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+               stk1160_info("buffer [%p/%d] aborted\n",
+                               buf, buf->vb.v4l2_buf.index);
+       }
+       /* It's important to clear current buffer */
+       dev->isoc_ctl.buf = NULL;
+       spin_unlock_irqrestore(&dev->buf_lock, flags);
+}
+
+int stk1160_vb2_setup(struct stk1160 *dev)
+{
+       int rc;
+       struct vb2_queue *q;
+
+       q = &dev->vb_vidq;
+       memset(q, 0, sizeof(dev->vb_vidq));
+       q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR;
+       q->drv_priv = dev;
+       q->buf_struct_size = sizeof(struct stk1160_buffer);
+       q->ops = &stk1160_video_qops;
+       q->mem_ops = &vb2_vmalloc_memops;
+
+       rc = vb2_queue_init(q);
+       if (rc < 0)
+               return rc;
+
+       /* initialize video dma queue */
+       INIT_LIST_HEAD(&dev->avail_bufs);
+
+       return 0;
+}
+
+int stk1160_video_register(struct stk1160 *dev)
+{
+       int rc;
+
+       /* Initialize video_device with a template structure */
+       dev->vdev = v4l_template;
+       dev->vdev.debug = vidioc_debug;
+       dev->vdev.queue = &dev->vb_vidq;
+
+       /*
+        * Provide mutexes for v4l2 core and for videobuf2 queue.
+        * It will be used to protect *only* v4l2 ioctls.
+        */
+       dev->vdev.lock = &dev->v4l_lock;
+       dev->vdev.queue->lock = &dev->vb_queue_lock;
+
+       /* This will be used to set video_device parent */
+       dev->vdev.v4l2_dev = &dev->v4l2_dev;
+       set_bit(V4L2_FL_USE_FH_PRIO, &dev->vdev.flags);
+
+       /* NTSC is default */
+       dev->norm = V4L2_STD_NTSC_M;
+       dev->width = 720;
+       dev->height = 480;
+
+       /* set default format */
+       dev->fmt = &format[0];
+       stk1160_set_std(dev);
+
+       v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std,
+                       dev->norm);
+
+       video_set_drvdata(&dev->vdev, dev);
+       rc = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1);
+       if (rc < 0) {
+               stk1160_err("video_register_device failed (%d)\n", rc);
+               return rc;
+       }
+
+       v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n",
+                 video_device_node_name(&dev->vdev));
+
+       return 0;
+}
diff --git a/drivers/media/video/stk1160/stk1160-video.c b/drivers/media/video/stk1160/stk1160-video.c
new file mode 100644 (file)
index 0000000..3785269
--- /dev/null
@@ -0,0 +1,518 @@
+/*
+ * STK1160 driver
+ *
+ * Copyright (C) 2012 Ezequiel Garcia
+ * <elezegarcia--a.t--gmail.com>
+ *
+ * Based on Easycap driver by R.M. Thomas
+ *     Copyright (C) 2010 R.M. Thomas
+ *     <rmthomas--a.t--sciolus.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/slab.h>
+#include <linux/ratelimit.h>
+
+#include "stk1160.h"
+
+static unsigned int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debug messages");
+
+static inline void print_err_status(struct stk1160 *dev,
+                                    int packet, int status)
+{
+       char *errmsg = "Unknown";
+
+       switch (status) {
+       case -ENOENT:
+               errmsg = "unlinked synchronuously";
+               break;
+       case -ECONNRESET:
+               errmsg = "unlinked asynchronuously";
+               break;
+       case -ENOSR:
+               errmsg = "Buffer error (overrun)";
+               break;
+       case -EPIPE:
+               errmsg = "Stalled (device not responding)";
+               break;
+       case -EOVERFLOW:
+               errmsg = "Babble (bad cable?)";
+               break;
+       case -EPROTO:
+               errmsg = "Bit-stuff error (bad cable?)";
+               break;
+       case -EILSEQ:
+               errmsg = "CRC/Timeout (could be anything)";
+               break;
+       case -ETIME:
+               errmsg = "Device does not respond";
+               break;
+       }
+
+       if (packet < 0)
+               printk_ratelimited(KERN_WARNING "URB status %d [%s].\n",
+                               status, errmsg);
+       else
+               printk_ratelimited(KERN_INFO "URB packet %d, status %d [%s].\n",
+                              packet, status, errmsg);
+}
+
+static inline
+struct stk1160_buffer *stk1160_next_buffer(struct stk1160 *dev)
+{
+       struct stk1160_buffer *buf = NULL;
+       unsigned long flags = 0;
+
+       /* Current buffer must be NULL when this functions gets called */
+       BUG_ON(dev->isoc_ctl.buf);
+
+       spin_lock_irqsave(&dev->buf_lock, flags);
+       if (!list_empty(&dev->avail_bufs)) {
+               buf = list_first_entry(&dev->avail_bufs,
+                               struct stk1160_buffer, list);
+               list_del(&buf->list);
+       }
+       spin_unlock_irqrestore(&dev->buf_lock, flags);
+
+       return buf;
+}
+
+static inline
+void stk1160_buffer_done(struct stk1160 *dev)
+{
+       struct stk1160_buffer *buf = dev->isoc_ctl.buf;
+
+       dev->field_count++;
+
+       buf->vb.v4l2_buf.sequence = dev->field_count >> 1;
+       buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED;
+       buf->vb.v4l2_buf.bytesused = buf->bytesused;
+       do_gettimeofday(&buf->vb.v4l2_buf.timestamp);
+
+       vb2_set_plane_payload(&buf->vb, 0, buf->bytesused);
+       vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
+
+       dev->isoc_ctl.buf = NULL;
+}
+
+static inline
+void stk1160_copy_video(struct stk1160 *dev, u8 *src, int len)
+{
+       int linesdone, lineoff, lencopy;
+       int bytesperline = dev->width * 2;
+       struct stk1160_buffer *buf = dev->isoc_ctl.buf;
+       u8 *dst = buf->mem;
+       int remain;
+
+       /*
+        * TODO: These stk1160_dbg are very spammy!
+        * We should 1) check why we are getting them
+        * and 2) add ratelimit.
+        *
+        * UPDATE: One of the reasons (the only one?) for getting these
+        * is incorrect standard (mismatch between expected and configured).
+        * So perhaps, we could add a counter for errors. When the counter
+        * reaches some value, we simply stop streaming.
+        */
+
+       len -= 4;
+       src += 4;
+
+       remain = len;
+
+       linesdone = buf->pos / bytesperline;
+       lineoff = buf->pos % bytesperline; /* offset in current line */
+
+       if (!buf->odd)
+               dst += bytesperline;
+
+       /* Multiply linesdone by two, to take account of the other field */
+       dst += linesdone * bytesperline * 2 + lineoff;
+
+       /* Copy the remaining of current line */
+       if (remain < (bytesperline - lineoff))
+               lencopy = remain;
+       else
+               lencopy = bytesperline - lineoff;
+
+       /*
+        * Check if we have enough space left in the buffer.
+        * In that case, we force loop exit after copy.
+        */
+       if (lencopy > buf->bytesused - buf->length) {
+               lencopy = buf->bytesused - buf->length;
+               remain = lencopy;
+       }
+
+       /* Check if the copy is done */
+       if (lencopy == 0 || remain == 0)
+               return;
+
+       /* Let the bug hunt begin! sanity checks! */
+       if (lencopy < 0) {
+               stk1160_dbg("copy skipped: negative lencopy\n");
+               return;
+       }
+
+       if ((unsigned long)dst + lencopy >
+               (unsigned long)buf->mem + buf->length) {
+               printk_ratelimited(KERN_WARNING "stk1160: buffer overflow detected\n");
+               return;
+       }
+
+       memcpy(dst, src, lencopy);
+
+       buf->bytesused += lencopy;
+       buf->pos += lencopy;
+       remain -= lencopy;
+
+       /* Copy current field line by line, interlacing with the other field */
+       while (remain > 0) {
+
+               dst += lencopy + bytesperline;
+               src += lencopy;
+
+               /* Copy one line at a time */
+               if (remain < bytesperline)
+                       lencopy = remain;
+               else
+                       lencopy = bytesperline;
+
+               /*
+                * Check if we have enough space left in the buffer.
+                * In that case, we force loop exit after copy.
+                */
+               if (lencopy > buf->bytesused - buf->length) {
+                       lencopy = buf->bytesused - buf->length;
+                       remain = lencopy;
+               }
+
+               /* Check if the copy is done */
+               if (lencopy == 0 || remain == 0)
+                       return;
+
+               if (lencopy < 0) {
+                       printk_ratelimited(KERN_WARNING "stk1160: negative lencopy detected\n");
+                       return;
+               }
+
+               if ((unsigned long)dst + lencopy >
+                       (unsigned long)buf->mem + buf->length) {
+                       printk_ratelimited(KERN_WARNING "stk1160: buffer overflow detected\n");
+                       return;
+               }
+
+               memcpy(dst, src, lencopy);
+               remain -= lencopy;
+
+               buf->bytesused += lencopy;
+               buf->pos += lencopy;
+       }
+}
+
+/*
+ * Controls the isoc copy of each urb packet
+ */
+static void stk1160_process_isoc(struct stk1160 *dev, struct urb *urb)
+{
+       int i, len, status;
+       u8 *p;
+
+       if (!dev) {
+               stk1160_warn("%s called with null device\n", __func__);
+               return;
+       }
+
+       if (urb->status < 0) {
+               /* Print status and drop current packet (or field?) */
+               print_err_status(dev, -1, urb->status);
+               return;
+       }
+
+       for (i = 0; i < urb->number_of_packets; i++) {
+               status = urb->iso_frame_desc[i].status;
+               if (status < 0) {
+                       print_err_status(dev, i, status);
+                       continue;
+               }
+
+               /* Get packet actual length and pointer to data */
+               p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+               len = urb->iso_frame_desc[i].actual_length;
+
+               /* Empty packet */
+               if (len <= 4)
+                       continue;
+
+               /*
+                * An 8-byte packet sequence means end of field.
+                * So if we don't have any packet, we start receiving one now
+                * and if we do have a packet, then we are done with it.
+                *
+                * These end of field packets are always 0xc0 or 0x80,
+                * but not always 8-byte long so we don't check packet length.
+                */
+               if (p[0] == 0xc0) {
+
+                       /*
+                        * If first byte is 0xc0 then we received
+                        * second field, and frame has ended.
+                        */
+                       if (dev->isoc_ctl.buf != NULL)
+                               stk1160_buffer_done(dev);
+
+                       dev->isoc_ctl.buf = stk1160_next_buffer(dev);
+                       if (dev->isoc_ctl.buf == NULL)
+                               return;
+               }
+
+               /*
+                * If we don't have a buffer here, then it means we
+                * haven't found the start mark sequence.
+                */
+               if (dev->isoc_ctl.buf == NULL)
+                       continue;
+
+               if (p[0] == 0xc0 || p[0] == 0x80) {
+
+                       /* We set next packet parity and
+                        * continue to get next one
+                        */
+                       dev->isoc_ctl.buf->odd = *p & 0x40;
+                       dev->isoc_ctl.buf->pos = 0;
+                       continue;
+               }
+
+               stk1160_copy_video(dev, p, len);
+       }
+}
+
+
+/*
+ * IRQ callback, called by URB callback
+ */
+static void stk1160_isoc_irq(struct urb *urb)
+{
+       int i, rc;
+       struct stk1160 *dev = urb->context;
+
+       switch (urb->status) {
+       case 0:
+               break;
+       case -ECONNRESET:   /* kill */
+       case -ENOENT:
+       case -ESHUTDOWN:
+               /* TODO: check uvc driver: he frees the queue here */
+               return;
+       default:
+               stk1160_err("urb error! status %d\n", urb->status);
+               return;
+       }
+
+       stk1160_process_isoc(dev, urb);
+
+       /* Reset urb buffers */
+       for (i = 0; i < urb->number_of_packets; i++) {
+               urb->iso_frame_desc[i].status = 0;
+               urb->iso_frame_desc[i].actual_length = 0;
+       }
+
+       rc = usb_submit_urb(urb, GFP_ATOMIC);
+       if (rc)
+               stk1160_err("urb re-submit failed (%d)\n", rc);
+}
+
+/*
+ * Cancel urbs
+ * This function can't be called in atomic context
+ */
+void stk1160_cancel_isoc(struct stk1160 *dev)
+{
+       int i;
+
+       /*
+        * This check is not necessary, but we add it
+        * to avoid a spurious debug message
+        */
+       if (!dev->isoc_ctl.num_bufs)
+               return;
+
+       stk1160_dbg("killing urbs...\n");
+
+       for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+
+               /*
+                * To kill urbs we can't be in atomic context.
+                * We don't care for NULL pointer since
+                * usb_kill_urb allows it.
+                */
+               usb_kill_urb(dev->isoc_ctl.urb[i]);
+       }
+
+       stk1160_dbg("all urbs killed\n");
+}
+
+/*
+ * Releases urb and transfer buffers
+ * Obviusly, associated urb must be killed before releasing it.
+ */
+void stk1160_free_isoc(struct stk1160 *dev)
+{
+       struct urb *urb;
+       int i;
+
+       stk1160_dbg("freeing urb buffers...\n");
+
+       for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+
+               urb = dev->isoc_ctl.urb[i];
+               if (urb) {
+
+                       if (dev->isoc_ctl.transfer_buffer[i]) {
+#ifndef CONFIG_DMA_NONCOHERENT
+                               usb_free_coherent(dev->udev,
+                                       urb->transfer_buffer_length,
+                                       dev->isoc_ctl.transfer_buffer[i],
+                                       urb->transfer_dma);
+#else
+                               kfree(dev->isoc_ctl.transfer_buffer[i]);
+#endif
+                       }
+                       usb_free_urb(urb);
+                       dev->isoc_ctl.urb[i] = NULL;
+               }
+               dev->isoc_ctl.transfer_buffer[i] = NULL;
+       }
+
+       kfree(dev->isoc_ctl.urb);
+       kfree(dev->isoc_ctl.transfer_buffer);
+
+       dev->isoc_ctl.urb = NULL;
+       dev->isoc_ctl.transfer_buffer = NULL;
+       dev->isoc_ctl.num_bufs = 0;
+
+       stk1160_dbg("all urb buffers freed\n");
+}
+
+/*
+ * Helper for cancelling and freeing urbs
+ * This function can't be called in atomic context
+ */
+void stk1160_uninit_isoc(struct stk1160 *dev)
+{
+       stk1160_cancel_isoc(dev);
+       stk1160_free_isoc(dev);
+}
+
+/*
+ * Allocate URBs
+ */
+int stk1160_alloc_isoc(struct stk1160 *dev)
+{
+       struct urb *urb;
+       int i, j, k, sb_size, max_packets, num_bufs;
+
+       /*
+        * It may be necessary to release isoc here,
+        * since isoc are only released on disconnection.
+        * (see new_pkt_size flag)
+        */
+       if (dev->isoc_ctl.num_bufs)
+               stk1160_uninit_isoc(dev);
+
+       stk1160_dbg("allocating urbs...\n");
+
+       num_bufs = STK1160_NUM_BUFS;
+       max_packets = STK1160_NUM_PACKETS;
+       sb_size = max_packets * dev->max_pkt_size;
+
+       dev->isoc_ctl.buf = NULL;
+       dev->isoc_ctl.max_pkt_size = dev->max_pkt_size;
+       dev->isoc_ctl.urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL);
+       if (!dev->isoc_ctl.urb) {
+               stk1160_err("out of memory for urb array\n");
+               return -ENOMEM;
+       }
+
+       dev->isoc_ctl.transfer_buffer = kzalloc(sizeof(void *)*num_bufs,
+                                             GFP_KERNEL);
+       if (!dev->isoc_ctl.transfer_buffer) {
+               stk1160_err("out of memory for usb transfers\n");
+               kfree(dev->isoc_ctl.urb);
+               return -ENOMEM;
+       }
+
+       /* allocate urbs and transfer buffers */
+       for (i = 0; i < num_bufs; i++) {
+
+               urb = usb_alloc_urb(max_packets, GFP_KERNEL);
+               if (!urb) {
+                       stk1160_err("cannot alloc urb[%d]\n", i);
+                       stk1160_uninit_isoc(dev);
+                       return -ENOMEM;
+               }
+               dev->isoc_ctl.urb[i] = urb;
+
+#ifndef CONFIG_DMA_NONCOHERENT
+               dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->udev,
+                       sb_size, GFP_KERNEL, &urb->transfer_dma);
+#else
+               dev->isoc_ctl.transfer_buffer[i] = kmalloc(sb_size, GFP_KERNEL);
+#endif
+               if (!dev->isoc_ctl.transfer_buffer[i]) {
+                       stk1160_err("cannot alloc %d bytes for tx buffer\n",
+                               sb_size);
+                       stk1160_uninit_isoc(dev);
+                       return -ENOMEM;
+               }
+               memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size);
+
+               /*
+                * FIXME: Where can I get the endpoint?
+                */
+               urb->dev = dev->udev;
+               urb->pipe = usb_rcvisocpipe(dev->udev, STK1160_EP_VIDEO);
+               urb->transfer_buffer = dev->isoc_ctl.transfer_buffer[i];
+               urb->transfer_buffer_length = sb_size;
+               urb->complete = stk1160_isoc_irq;
+               urb->context = dev;
+               urb->interval = 1;
+               urb->start_frame = 0;
+               urb->number_of_packets = max_packets;
+#ifndef CONFIG_DMA_NONCOHERENT
+               urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+#else
+               urb->transfer_flags = URB_ISO_ASAP;
+#endif
+
+               k = 0;
+               for (j = 0; j < max_packets; j++) {
+                       urb->iso_frame_desc[j].offset = k;
+                       urb->iso_frame_desc[j].length =
+                                       dev->isoc_ctl.max_pkt_size;
+                       k += dev->isoc_ctl.max_pkt_size;
+               }
+       }
+
+       stk1160_dbg("urbs allocated\n");
+
+       /* At last we can say we have some buffers */
+       dev->isoc_ctl.num_bufs = num_bufs;
+
+       return 0;
+}
+
diff --git a/drivers/media/video/stk1160/stk1160.h b/drivers/media/video/stk1160/stk1160.h
new file mode 100644 (file)
index 0000000..3feba00
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * STK1160 driver
+ *
+ * Copyright (C) 2012 Ezequiel Garcia
+ * <elezegarcia--a.t--gmail.com>
+ *
+ * Based on Easycap driver by R.M. Thomas
+ *     Copyright (C) 2010 R.M. Thomas
+ *     <rmthomas--a.t--sciolus.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/i2c.h>
+#include <sound/core.h>
+#include <sound/ac97_codec.h>
+#include <media/videobuf2-core.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+
+#define STK1160_VERSION                "0.9.5"
+#define STK1160_VERSION_NUM    0x000905
+
+/* TODO: Decide on number of packets for each buffer */
+#define STK1160_NUM_PACKETS 64
+
+/* Number of buffers for isoc transfers */
+#define STK1160_NUM_BUFS 16 /* TODO */
+
+/* TODO: This endpoint address should be retrieved */
+#define STK1160_EP_VIDEO 0x82
+#define STK1160_EP_AUDIO 0x81
+
+/* Max and min video buffers */
+#define STK1160_MIN_VIDEO_BUFFERS 8
+#define STK1160_MAX_VIDEO_BUFFERS 32
+
+#define STK1160_MIN_PKT_SIZE 3072
+
+#define STK1160_MAX_INPUT 3
+
+#define STK1160_I2C_TIMEOUT 100
+
+/* TODO: Print helpers
+ * I could use dev_xxx, pr_xxx, v4l2_xxx or printk.
+ * However, there isn't a solid consensus on which
+ * new drivers should use.
+ *
+ */
+#define DEBUG
+#ifdef DEBUG
+#define stk1160_dbg(fmt, args...) \
+       printk(KERN_DEBUG "stk1160: " fmt,  ## args)
+#else
+#define stk1160_dbg(fmt, args...)
+#endif
+
+#define stk1160_info(fmt, args...) \
+       pr_info("stk1160: " fmt, ## args)
+
+#define stk1160_warn(fmt, args...) \
+       pr_warn("stk1160: " fmt, ## args)
+
+#define stk1160_err(fmt, args...) \
+       pr_err("stk1160: " fmt, ## args)
+
+/* Buffer for one video frame */
+struct stk1160_buffer {
+       /* common v4l buffer stuff -- must be first */
+       struct vb2_buffer vb;
+       struct list_head list;
+
+       void *mem;
+       unsigned int length;            /* buffer length */
+       unsigned int bytesused;         /* bytes written */
+       int odd;                        /* current oddity */
+
+       /*
+        * Since we interlace two fields per frame,
+        * this is different from bytesused.
+        */
+       unsigned int pos;               /* current pos inside buffer */
+};
+
+struct stk1160_isoc_ctl {
+       /* max packet size of isoc transaction */
+       int max_pkt_size;
+
+       /* number of allocated urbs */
+       int num_bufs;
+
+       /* urb for isoc transfers */
+       struct urb **urb;
+
+       /* transfer buffers for isoc transfer */
+       char **transfer_buffer;
+
+       /* current buffer */
+       struct stk1160_buffer *buf;
+};
+
+struct stk1160_fmt {
+       char  *name;
+       u32   fourcc;          /* v4l2 format id */
+       int   depth;
+};
+
+struct stk1160 {
+       struct v4l2_device v4l2_dev;
+       struct video_device vdev;
+       struct v4l2_ctrl_handler ctrl_handler;
+
+       struct device *dev;
+       struct usb_device *udev;
+
+       /* saa7115 subdev */
+       struct v4l2_subdev *sd_saa7115;
+
+       /* isoc control struct */
+       struct list_head avail_bufs;
+
+       /* video capture */
+       struct vb2_queue vb_vidq;
+
+       /* max packet size of isoc transaction */
+       int max_pkt_size;
+       /* array of wMaxPacketSize */
+       unsigned int *alt_max_pkt_size;
+       /* alternate */
+       int alt;
+       /* Number of alternative settings */
+       int num_alt;
+
+       struct stk1160_isoc_ctl isoc_ctl;
+       char urb_buf[255];       /* urb control msg buffer */
+
+       /* frame properties */
+       int width;                /* current frame width */
+       int height;               /* current frame height */
+       unsigned int ctl_input;   /* selected input */
+       v4l2_std_id norm;         /* current norm */
+       struct stk1160_fmt *fmt;  /* selected format */
+
+       unsigned int field_count; /* not sure ??? */
+       enum v4l2_field field;    /* also not sure :/ */
+
+       /* i2c i/o */
+       struct i2c_adapter i2c_adap;
+       struct i2c_client i2c_client;
+
+       struct mutex v4l_lock;
+       struct mutex vb_queue_lock;
+       spinlock_t buf_lock;
+
+       struct file *fh_owner;  /* filehandle ownership */
+
+       /* EXPERIMENTAL */
+       struct snd_card *snd_card;
+};
+
+struct regval {
+       u16 reg;
+       u16 val;
+};
+
+/* Provided by stk1160-v4l.c */
+int stk1160_vb2_setup(struct stk1160 *dev);
+int stk1160_video_register(struct stk1160 *dev);
+void stk1160_video_unregister(struct stk1160 *dev);
+void stk1160_clear_queue(struct stk1160 *dev);
+
+/* Provided by stk1160-video.c */
+int stk1160_alloc_isoc(struct stk1160 *dev);
+void stk1160_free_isoc(struct stk1160 *dev);
+void stk1160_cancel_isoc(struct stk1160 *dev);
+void stk1160_uninit_isoc(struct stk1160 *dev);
+
+/* Provided by stk1160-i2c.c */
+int stk1160_i2c_register(struct stk1160 *dev);
+int stk1160_i2c_unregister(struct stk1160 *dev);
+
+/* Provided by stk1160-core.c */
+int stk1160_read_reg(struct stk1160 *dev, u16 reg, u8 *value);
+int stk1160_write_reg(struct stk1160 *dev, u16 reg, u16 value);
+int stk1160_write_regs_req(struct stk1160 *dev, u8 req, u16 reg,
+               char *buf, int len);
+int stk1160_read_reg_req_len(struct stk1160 *dev, u8 req, u16 reg,
+               char *buf, int len);
+void stk1160_select_input(struct stk1160 *dev);
+
+/* Provided by stk1160-ac97.c */
+#ifdef CONFIG_VIDEO_STK1160_AC97
+int stk1160_ac97_register(struct stk1160 *dev);
+int stk1160_ac97_unregister(struct stk1160 *dev);
+#else
+static inline int stk1160_ac97_register(struct stk1160 *dev) { return 0; }
+static inline int stk1160_ac97_unregister(struct stk1160 *dev) { return 0; }
+#endif
+
index f7034df94e0a6640a77c0bf0090ab08baeaf1e47..45ed59cb2d04df8b6205d2cd9e45f1a8314a7243 100644 (file)
@@ -1448,7 +1448,7 @@ static int radio_queryctrl(struct file *file, void *priv,
        File operations for the device
    ------------------------------------------------------------------*/
 
-static int tm6000_open(struct file *file)
+static int __tm6000_open(struct file *file)
 {
        struct video_device *vdev = video_devdata(file);
        struct tm6000_core *dev = video_drvdata(file);
@@ -1540,23 +1540,41 @@ static int tm6000_open(struct file *file)
        return 0;
 }
 
+static int tm6000_open(struct file *file)
+{
+       struct video_device *vdev = video_devdata(file);
+       int res;
+
+       mutex_lock(vdev->lock);
+       res = __tm6000_open(file);
+       mutex_unlock(vdev->lock);
+       return res;
+}
+
 static ssize_t
 tm6000_read(struct file *file, char __user *data, size_t count, loff_t *pos)
 {
-       struct tm6000_fh        *fh = file->private_data;
+       struct tm6000_fh *fh = file->private_data;
+       struct tm6000_core *dev = fh->dev;
 
        if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               int res;
+
                if (!res_get(fh->dev, fh, true))
                        return -EBUSY;
 
-               return videobuf_read_stream(&fh->vb_vidq, data, count, pos, 0,
+               if (mutex_lock_interruptible(&dev->lock))
+                       return -ERESTARTSYS;
+               res = videobuf_read_stream(&fh->vb_vidq, data, count, pos, 0,
                                        file->f_flags & O_NONBLOCK);
+               mutex_unlock(&dev->lock);
+               return res;
        }
        return 0;
 }
 
 static unsigned int
-tm6000_poll(struct file *file, struct poll_table_struct *wait)
+__tm6000_poll(struct file *file, struct poll_table_struct *wait)
 {
        struct tm6000_fh        *fh = file->private_data;
        struct tm6000_buffer    *buf;
@@ -1583,6 +1601,18 @@ tm6000_poll(struct file *file, struct poll_table_struct *wait)
        return 0;
 }
 
+static unsigned int tm6000_poll(struct file *file, struct poll_table_struct *wait)
+{
+       struct tm6000_fh *fh = file->private_data;
+       struct tm6000_core *dev = fh->dev;
+       unsigned int res;
+
+       mutex_lock(&dev->lock);
+       res = __tm6000_poll(file, wait);
+       mutex_unlock(&dev->lock);
+       return res;
+}
+
 static int tm6000_release(struct file *file)
 {
        struct tm6000_fh         *fh = file->private_data;
@@ -1592,6 +1622,7 @@ static int tm6000_release(struct file *file)
        dprintk(dev, V4L2_DEBUG_OPEN, "tm6000: close called (dev=%s, users=%d)\n",
                video_device_node_name(vdev), dev->users);
 
+       mutex_lock(&dev->lock);
        dev->users--;
 
        res_free(dev, fh);
@@ -1619,6 +1650,7 @@ static int tm6000_release(struct file *file)
        }
 
        kfree(fh);
+       mutex_unlock(&dev->lock);
 
        return 0;
 }
@@ -1626,8 +1658,14 @@ static int tm6000_release(struct file *file)
 static int tm6000_mmap(struct file *file, struct vm_area_struct * vma)
 {
        struct tm6000_fh *fh = file->private_data;
+       struct tm6000_core *dev = fh->dev;
+       int res;
 
-       return videobuf_mmap_mapper(&fh->vb_vidq, vma);
+       if (mutex_lock_interruptible(&dev->lock))
+               return -ERESTARTSYS;
+       res = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+       mutex_unlock(&dev->lock);
+       return res;
 }
 
 static struct v4l2_file_operations tm6000_fops = {
@@ -1724,10 +1762,6 @@ static struct video_device *vdev_init(struct tm6000_core *dev,
        vfd->release = video_device_release;
        vfd->debug = tm6000_debug;
        vfd->lock = &dev->lock;
-       /* Locking in file operations other than ioctl should be done
-          by the driver, not the V4L2 core.
-          This driver needs auditing so that this flag can be removed. */
-       set_bit(V4L2_FL_LOCK_ALL_FOPS, &vfd->flags);
 
        snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name);
 
index 9bd8f084f3489671143d879218d29495d66753c0..8a4317979a43d784972283d4d61f978ff51236c2 100644 (file)
@@ -349,6 +349,8 @@ static int usbvision_v4l2_open(struct file *file)
 
        PDEBUG(DBG_IO, "open");
 
+       if (mutex_lock_interruptible(&usbvision->v4l2_lock))
+               return -ERESTARTSYS;
        usbvision_reset_power_off_timer(usbvision);
 
        if (usbvision->user)
@@ -402,6 +404,7 @@ static int usbvision_v4l2_open(struct file *file)
 
        /* prepare queues */
        usbvision_empty_framequeues(usbvision);
+       mutex_unlock(&usbvision->v4l2_lock);
 
        PDEBUG(DBG_IO, "success");
        return err_code;
@@ -421,6 +424,7 @@ static int usbvision_v4l2_close(struct file *file)
 
        PDEBUG(DBG_IO, "close");
 
+       mutex_lock(&usbvision->v4l2_lock);
        usbvision_audio_off(usbvision);
        usbvision_restart_isoc(usbvision);
        usbvision_stop_isoc(usbvision);
@@ -443,6 +447,7 @@ static int usbvision_v4l2_close(struct file *file)
                printk(KERN_INFO "%s: Final disconnect\n", __func__);
                usbvision_release(usbvision);
        }
+       mutex_unlock(&usbvision->v4l2_lock);
 
        PDEBUG(DBG_IO, "success");
        return 0;
@@ -956,7 +961,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
        return 0;
 }
 
-static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
+static ssize_t usbvision_read(struct file *file, char __user *buf,
                      size_t count, loff_t *ppos)
 {
        struct usb_usbvision *usbvision = video_drvdata(file);
@@ -1060,7 +1065,20 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
        return count;
 }
 
-static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
+static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
+                     size_t count, loff_t *ppos)
+{
+       struct usb_usbvision *usbvision = video_drvdata(file);
+       int res;
+
+       if (mutex_lock_interruptible(&usbvision->v4l2_lock))
+               return -ERESTARTSYS;
+       res = usbvision_read(file, buf, count, ppos);
+       mutex_unlock(&usbvision->v4l2_lock);
+       return res;
+}
+
+static int usbvision_mmap(struct file *file, struct vm_area_struct *vma)
 {
        unsigned long size = vma->vm_end - vma->vm_start,
                start = vma->vm_start;
@@ -1107,6 +1125,17 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
        return 0;
 }
 
+static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct usb_usbvision *usbvision = video_drvdata(file);
+       int res;
+
+       if (mutex_lock_interruptible(&usbvision->v4l2_lock))
+               return -ERESTARTSYS;
+       res = usbvision_mmap(file, vma);
+       mutex_unlock(&usbvision->v4l2_lock);
+       return res;
+}
 
 /*
  * Here comes the stuff for radio on usbvision based devices
@@ -1119,6 +1148,8 @@ static int usbvision_radio_open(struct file *file)
 
        PDEBUG(DBG_IO, "%s:", __func__);
 
+       if (mutex_lock_interruptible(&usbvision->v4l2_lock))
+               return -ERESTARTSYS;
        if (usbvision->user) {
                dev_err(&usbvision->rdev->dev,
                        "%s: Someone tried to open an already opened USBVision Radio!\n",
@@ -1156,6 +1187,7 @@ static int usbvision_radio_open(struct file *file)
                }
        }
 out:
+       mutex_unlock(&usbvision->v4l2_lock);
        return err_code;
 }
 
@@ -1167,6 +1199,7 @@ static int usbvision_radio_close(struct file *file)
 
        PDEBUG(DBG_IO, "");
 
+       mutex_lock(&usbvision->v4l2_lock);
        /* Set packet size to 0 */
        usbvision->iface_alt = 0;
        err_code = usb_set_interface(usbvision->dev, usbvision->iface,
@@ -1186,6 +1219,7 @@ static int usbvision_radio_close(struct file *file)
                usbvision_release(usbvision);
        }
 
+       mutex_unlock(&usbvision->v4l2_lock);
        PDEBUG(DBG_IO, "success");
        return err_code;
 }
@@ -1296,10 +1330,6 @@ static struct video_device *usbvision_vdev_init(struct usb_usbvision *usbvision,
        if (NULL == vdev)
                return NULL;
        *vdev = *vdev_template;
-       /* Locking in file operations other than ioctl should be done
-          by the driver, not the V4L2 core.
-          This driver needs auditing so that this flag can be removed. */
-       set_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags);
        vdev->lock = &usbvision->v4l2_lock;
        vdev->v4l2_dev = &usbvision->v4l2_dev;
        snprintf(vdev->name, sizeof(vdev->name), "%s", name);
index 9288fbd5001b26e8bcf3210ffbfc0da7891f1182..5577381b5bf057357c6c4f591e4eb09269c2eb38 100644 (file)
@@ -338,6 +338,7 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
        if ((queue->flags & UVC_QUEUE_DROP_CORRUPTED) && buf->error) {
                buf->error = 0;
                buf->state = UVC_BUF_STATE_QUEUED;
+               buf->bytesused = 0;
                vb2_set_plane_payload(&buf->buf, 0, 0);
                return buf;
        }
index 1baec8393306de0c1c781c88987615a24701c91f..105f88cdb9d667a5dfc75646a2a1a14aaea4a937 100644 (file)
@@ -418,7 +418,7 @@ EXPORT_SYMBOL_GPL(v4l2_i2c_tuner_addrs);
 
 #if defined(CONFIG_SPI)
 
-/* Load a spi sub-device. */
+/* Load an spi sub-device. */
 
 void v4l2_spi_subdev_init(struct v4l2_subdev *sd, struct spi_device *spi,
                const struct v4l2_subdev_ops *ops)
index 07aeafca9eaabfd0f23117168945f0d1e603533a..71237f5f85f4f6b5bc232618c1aeb9d03736c95d 100644 (file)
@@ -298,13 +298,8 @@ static ssize_t v4l2_read(struct file *filp, char __user *buf,
 
        if (!vdev->fops->read)
                return -EINVAL;
-       if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags) &&
-           mutex_lock_interruptible(vdev->lock))
-               return -ERESTARTSYS;
        if (video_is_registered(vdev))
                ret = vdev->fops->read(filp, buf, sz, off);
-       if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags))
-               mutex_unlock(vdev->lock);
        if (vdev->debug)
                printk(KERN_DEBUG "%s: read: %zd (%d)\n",
                        video_device_node_name(vdev), sz, ret);
@@ -319,13 +314,8 @@ static ssize_t v4l2_write(struct file *filp, const char __user *buf,
 
        if (!vdev->fops->write)
                return -EINVAL;
-       if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags) &&
-           mutex_lock_interruptible(vdev->lock))
-               return -ERESTARTSYS;
        if (video_is_registered(vdev))
                ret = vdev->fops->write(filp, buf, sz, off);
-       if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags))
-               mutex_unlock(vdev->lock);
        if (vdev->debug)
                printk(KERN_DEBUG "%s: write: %zd (%d)\n",
                        video_device_node_name(vdev), sz, ret);
@@ -335,20 +325,16 @@ static ssize_t v4l2_write(struct file *filp, const char __user *buf,
 static unsigned int v4l2_poll(struct file *filp, struct poll_table_struct *poll)
 {
        struct video_device *vdev = video_devdata(filp);
-       int ret = POLLERR | POLLHUP;
+       unsigned int res = POLLERR | POLLHUP;
 
        if (!vdev->fops->poll)
                return DEFAULT_POLLMASK;
-       if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags))
-               mutex_lock(vdev->lock);
        if (video_is_registered(vdev))
-               ret = vdev->fops->poll(filp, poll);
-       if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags))
-               mutex_unlock(vdev->lock);
+               res = vdev->fops->poll(filp, poll);
        if (vdev->debug)
                printk(KERN_DEBUG "%s: poll: %08x\n",
-                       video_device_node_name(vdev), ret);
-       return ret;
+                       video_device_node_name(vdev), res);
+       return res;
 }
 
 static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
@@ -432,14 +418,9 @@ static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm)
        int ret = -ENODEV;
 
        if (!vdev->fops->mmap)
-               return ret;
-       if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags) &&
-           mutex_lock_interruptible(vdev->lock))
-               return -ERESTARTSYS;
+               return -ENODEV;
        if (video_is_registered(vdev))
                ret = vdev->fops->mmap(filp, vm);
-       if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags))
-               mutex_unlock(vdev->lock);
        if (vdev->debug)
                printk(KERN_DEBUG "%s: mmap (%d)\n",
                        video_device_node_name(vdev), ret);
@@ -464,20 +445,12 @@ static int v4l2_open(struct inode *inode, struct file *filp)
        video_get(vdev);
        mutex_unlock(&videodev_lock);
        if (vdev->fops->open) {
-               if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags) &&
-                   mutex_lock_interruptible(vdev->lock)) {
-                       ret = -ERESTARTSYS;
-                       goto err;
-               }
                if (video_is_registered(vdev))
                        ret = vdev->fops->open(filp);
                else
                        ret = -ENODEV;
-               if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags))
-                       mutex_unlock(vdev->lock);
        }
 
-err:
        if (vdev->debug)
                printk(KERN_DEBUG "%s: open (%d)\n",
                        video_device_node_name(vdev), ret);
@@ -493,16 +466,12 @@ static int v4l2_release(struct inode *inode, struct file *filp)
        struct video_device *vdev = video_devdata(filp);
        int ret = 0;
 
-       if (vdev->fops->release) {
-               if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags))
-                       mutex_lock(vdev->lock);
-               vdev->fops->release(filp);
-               if (test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags))
-                       mutex_unlock(vdev->lock);
-       }
+       if (vdev->fops->release)
+               ret = vdev->fops->release(filp);
        if (vdev->debug)
                printk(KERN_DEBUG "%s: release\n",
                        video_device_node_name(vdev));
+
        /* decrease the refcount unconditionally since the release()
           return value is ignored. */
        video_put(vdev);
@@ -882,10 +851,6 @@ int __video_register_device(struct video_device *vdev, int type, int nr,
        WARN_ON(video_device[vdev->minor] != NULL);
        vdev->index = get_index(vdev);
        mutex_unlock(&videodev_lock);
-       /* if no lock was passed, then make sure the LOCK_ALL_FOPS bit is
-          clear and warn if it wasn't. */
-       if (vdev->lock == NULL)
-               WARN_ON(test_and_clear_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags));
 
        if (vdev->ioctl_ops)
                determine_valid_ioctls(vdev);
index c3b7b5f59b328a8beea170977261e4d650da88b7..6bc47fc82fe2f799bfff8a3f885fae27bf1a0aa0 100644 (file)
@@ -402,8 +402,10 @@ static void v4l_print_hw_freq_seek(const void *arg, bool write_only)
 {
        const struct v4l2_hw_freq_seek *p = arg;
 
-       pr_cont("tuner=%u, type=%u, seek_upward=%u, wrap_around=%u, spacing=%u\n",
-               p->tuner, p->type, p->seek_upward, p->wrap_around, p->spacing);
+       pr_cont("tuner=%u, type=%u, seek_upward=%u, wrap_around=%u, spacing=%u, "
+               "rangelow=%u, rangehigh=%u\n",
+               p->tuner, p->type, p->seek_upward, p->wrap_around, p->spacing,
+               p->rangelow, p->rangehigh);
 }
 
 static void v4l_print_requestbuffers(const void *arg, bool write_only)
@@ -1853,6 +1855,8 @@ static int v4l_enum_freq_bands(const struct v4l2_ioctl_ops *ops,
                        .type = type,
                };
 
+               if (p->index)
+                       return -EINVAL;
                err = ops->vidioc_g_tuner(file, fh, &t);
                if (err)
                        return err;
@@ -1870,6 +1874,8 @@ static int v4l_enum_freq_bands(const struct v4l2_ioctl_ops *ops,
 
                if (type != V4L2_TUNER_RADIO)
                        return -EINVAL;
+               if (p->index)
+                       return -EINVAL;
                err = ops->vidioc_g_modulator(file, fh, &m);
                if (err)
                        return err;
index 268c7dd4f8231ebc2f3ca033bfea4bbc689f07f7..4da3df61901fbf549f7192af3c93518e5acc5e83 100644 (file)
@@ -2270,10 +2270,9 @@ ssize_t vb2_fop_write(struct file *file, char __user *buf,
 {
        struct video_device *vdev = video_devdata(file);
        struct mutex *lock = vdev->queue->lock ? vdev->queue->lock : vdev->lock;
-       bool must_lock = !test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags) && lock;
        int err = -EBUSY;
 
-       if (must_lock && mutex_lock_interruptible(lock))
+       if (lock && mutex_lock_interruptible(lock))
                return -ERESTARTSYS;
        if (vb2_queue_is_busy(vdev, file))
                goto exit;
@@ -2282,7 +2281,7 @@ ssize_t vb2_fop_write(struct file *file, char __user *buf,
        if (err >= 0)
                vdev->queue->owner = file->private_data;
 exit:
-       if (must_lock)
+       if (lock)
                mutex_unlock(lock);
        return err;
 }
@@ -2293,10 +2292,9 @@ ssize_t vb2_fop_read(struct file *file, char __user *buf,
 {
        struct video_device *vdev = video_devdata(file);
        struct mutex *lock = vdev->queue->lock ? vdev->queue->lock : vdev->lock;
-       bool must_lock = !test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags) && vdev->lock;
        int err = -EBUSY;
 
-       if (must_lock && mutex_lock_interruptible(lock))
+       if (lock && mutex_lock_interruptible(lock))
                return -ERESTARTSYS;
        if (vb2_queue_is_busy(vdev, file))
                goto exit;
@@ -2305,7 +2303,7 @@ ssize_t vb2_fop_read(struct file *file, char __user *buf,
        if (err >= 0)
                vdev->queue->owner = file->private_data;
 exit:
-       if (must_lock)
+       if (lock)
                mutex_unlock(lock);
        return err;
 }
@@ -2319,11 +2317,6 @@ unsigned int vb2_fop_poll(struct file *file, poll_table *wait)
        unsigned long req_events = poll_requested_events(wait);
        unsigned res;
        void *fileio;
-       /* Yuck. We really need to get rid of this flag asap. If it is
-          set, then the core took the serialization lock before calling
-          poll(). This is being phased out, but for now we have to handle
-          this case. */
-       bool locked = test_bit(V4L2_FL_LOCK_ALL_FOPS, &vdev->flags);
        bool must_lock = false;
 
        /* Try to be smart: only lock if polling might start fileio,
@@ -2339,9 +2332,9 @@ unsigned int vb2_fop_poll(struct file *file, poll_table *wait)
 
        /* If locking is needed, but this helper doesn't know how, then you
           shouldn't be using this helper but you should write your own. */
-       WARN_ON(must_lock && !locked && !lock);
+       WARN_ON(must_lock && !lock);
 
-       if (must_lock && !locked && lock && mutex_lock_interruptible(lock))
+       if (must_lock && lock && mutex_lock_interruptible(lock))
                return POLLERR;
 
        fileio = q->fileio;
@@ -2351,7 +2344,7 @@ unsigned int vb2_fop_poll(struct file *file, poll_table *wait)
        /* If fileio was started, then we have a new queue owner. */
        if (must_lock && !fileio && q->fileio)
                q->owner = file->private_data;
-       if (must_lock && !locked && lock)
+       if (must_lock && lock)
                mutex_unlock(lock);
        return res;
 }
index 6b5ca6c70a46076b42cebdcee55613b02ebd2f0f..94efa04d8d55f3e4af400f0910cf791dbf9faf02 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/vmalloc.h>
 
 #include <media/videobuf2-core.h>
+#include <media/videobuf2-vmalloc.h>
 #include <media/videobuf2-memops.h>
 
 struct vb2_vmalloc_buf {
index a05494b71b20a7247a8bfb27c05304dcf8ae3272..a6351c49bfd31defc899d2dd171a7060cba876b6 100644 (file)
@@ -80,7 +80,8 @@ static const u8 *font8x16;
 struct vivi_fmt {
        char  *name;
        u32   fourcc;          /* v4l2 format id */
-       int   depth;
+       u8    depth;
+       bool  is_yuv;
 };
 
 static struct vivi_fmt formats[] = {
@@ -88,21 +89,25 @@ static struct vivi_fmt formats[] = {
                .name     = "4:2:2, packed, YUYV",
                .fourcc   = V4L2_PIX_FMT_YUYV,
                .depth    = 16,
+               .is_yuv   = true,
        },
        {
                .name     = "4:2:2, packed, UYVY",
                .fourcc   = V4L2_PIX_FMT_UYVY,
                .depth    = 16,
+               .is_yuv   = true,
        },
        {
                .name     = "4:2:2, packed, YVYU",
                .fourcc   = V4L2_PIX_FMT_YVYU,
                .depth    = 16,
+               .is_yuv   = true,
        },
        {
                .name     = "4:2:2, packed, VYUY",
                .fourcc   = V4L2_PIX_FMT_VYUY,
                .depth    = 16,
+               .is_yuv   = true,
        },
        {
                .name     = "RGB565 (LE)",
@@ -309,15 +314,9 @@ static void precalculate_bars(struct vivi_dev *dev)
                r = bars[dev->input].bar[k][0];
                g = bars[dev->input].bar[k][1];
                b = bars[dev->input].bar[k][2];
-               is_yuv = 0;
+               is_yuv = dev->fmt->is_yuv;
 
                switch (dev->fmt->fourcc) {
-               case V4L2_PIX_FMT_YUYV:
-               case V4L2_PIX_FMT_UYVY:
-               case V4L2_PIX_FMT_YVYU:
-               case V4L2_PIX_FMT_VYUY:
-                       is_yuv = 1;
-                       break;
                case V4L2_PIX_FMT_RGB565:
                case V4L2_PIX_FMT_RGB565X:
                        r >>= 3;
@@ -330,6 +329,10 @@ static void precalculate_bars(struct vivi_dev *dev)
                        g >>= 3;
                        b >>= 3;
                        break;
+               case V4L2_PIX_FMT_YUYV:
+               case V4L2_PIX_FMT_UYVY:
+               case V4L2_PIX_FMT_YVYU:
+               case V4L2_PIX_FMT_VYUY:
                case V4L2_PIX_FMT_RGB24:
                case V4L2_PIX_FMT_BGR24:
                case V4L2_PIX_FMT_RGB32:
@@ -930,8 +933,7 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
                (f->fmt.pix.width * dev->fmt->depth) >> 3;
        f->fmt.pix.sizeimage =
                f->fmt.pix.height * f->fmt.pix.bytesperline;
-       if (dev->fmt->fourcc == V4L2_PIX_FMT_YUYV ||
-           dev->fmt->fourcc == V4L2_PIX_FMT_UYVY)
+       if (dev->fmt->is_yuv)
                f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
        else
                f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
@@ -959,11 +961,11 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
                (f->fmt.pix.width * fmt->depth) >> 3;
        f->fmt.pix.sizeimage =
                f->fmt.pix.height * f->fmt.pix.bytesperline;
-       if (fmt->fourcc == V4L2_PIX_FMT_YUYV ||
-           fmt->fourcc == V4L2_PIX_FMT_UYVY)
+       if (fmt->is_yuv)
                f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
        else
                f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
+       f->fmt.pix.priv = 0;
        return 0;
 }
 
@@ -990,6 +992,27 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
        return 0;
 }
 
+static int vidioc_enum_framesizes(struct file *file, void *fh,
+                                        struct v4l2_frmsizeenum *fsize)
+{
+       static const struct v4l2_frmsize_stepwise sizes = {
+               48, MAX_WIDTH, 4,
+               32, MAX_HEIGHT, 1
+       };
+       int i;
+
+       if (fsize->index)
+               return -EINVAL;
+       for (i = 0; i < ARRAY_SIZE(formats); i++)
+               if (formats[i].fourcc == fsize->pixel_format)
+                       break;
+       if (i == ARRAY_SIZE(formats))
+               return -EINVAL;
+       fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+       fsize->stepwise = sizes;
+       return 0;
+}
+
 /* only one input in this sample driver */
 static int vidioc_enum_input(struct file *file, void *priv,
                                struct v4l2_input *inp)
@@ -1174,6 +1197,7 @@ static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
        .vidioc_g_fmt_vid_cap     = vidioc_g_fmt_vid_cap,
        .vidioc_try_fmt_vid_cap   = vidioc_try_fmt_vid_cap,
        .vidioc_s_fmt_vid_cap     = vidioc_s_fmt_vid_cap,
+       .vidioc_enum_framesizes   = vidioc_enum_framesizes,
        .vidioc_reqbufs       = vb2_ioctl_reqbufs,
        .vidioc_create_bufs   = vb2_ioctl_create_bufs,
        .vidioc_prepare_buf   = vb2_ioctl_prepare_buf,
index 383421bf57609a994b7f8d537f97c269d2ab6302..683e18a23329802875d03f92d53e354a6474ad9d 100644 (file)
@@ -925,6 +925,7 @@ static int __init asic3_mfd_probe(struct platform_device *pdev,
                        goto out;
        }
 
+       ret = 0;
        if (pdata->leds) {
                int i;
 
index 82c9d64502868ba94ea8d215d9a5e864ed42f19a..352c58b5a90d2406e8467bfdacfbd2ba5fefa1b6 100644 (file)
@@ -46,7 +46,7 @@ static int da9052_i2c_enable_multiwrite(struct da9052 *da9052)
        return 0;
 }
 
-static struct i2c_device_id da9052_i2c_id[] = {
+static const struct i2c_device_id da9052_i2c_id[] = {
        {"da9052", DA9052},
        {"da9053-aa", DA9053_AA},
        {"da9053-ba", DA9053_BA},
@@ -104,7 +104,7 @@ static int __devinit da9052_i2c_probe(struct i2c_client *client,
                const struct of_device_id *deviceid;
 
                deviceid = of_match_node(dialog_dt_ids, np);
-               id = (const struct i2c_device_id *)deviceid->data;
+               id = deviceid->data;
        }
 #endif
 
index 43a76c41cfcc9fe39084dd2967eaba23a4e87a52..db662e2dcfa5ba3cae4cd07694dc0caa95e72d80 100644 (file)
@@ -202,7 +202,7 @@ static void pcap_isr_work(struct work_struct *work)
                }
                local_irq_enable();
                ezx_pcap_write(pcap, PCAP_REG_MSR, pcap->msr);
-       } while (gpio_get_value(irq_to_gpio(pcap->spi->irq)));
+       } while (gpio_get_value(pdata->gpio));
 }
 
 static void pcap_irq_handler(unsigned int irq, struct irq_desc *desc)
index 353c34812120fc46e37140c0b6a04babdd5cb080..380a3c886d31201eb8ec04ad14de412fa438fe7e 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/i2c.h>
 #include <linux/regmap.h>
 #include <linux/regulator/of_regulator.h>
+#include <linux/regulator/machine.h>
 
 #include <linux/mfd/core.h>
 #include <linux/mfd/tps6586x.h>
@@ -346,6 +347,7 @@ failed:
 
 #ifdef CONFIG_OF
 static struct of_regulator_match tps6586x_matches[] = {
+       { .name = "sys",     .driver_data = (void *)TPS6586X_ID_SYS     },
        { .name = "sm0",     .driver_data = (void *)TPS6586X_ID_SM_0    },
        { .name = "sm1",     .driver_data = (void *)TPS6586X_ID_SM_1    },
        { .name = "sm2",     .driver_data = (void *)TPS6586X_ID_SM_2    },
@@ -369,6 +371,7 @@ static struct tps6586x_platform_data *tps6586x_parse_dt(struct i2c_client *clien
        struct tps6586x_platform_data *pdata;
        struct tps6586x_subdev_info *devs;
        struct device_node *regs;
+       const char *sys_rail_name = NULL;
        unsigned int count;
        unsigned int i, j;
        int err;
@@ -391,12 +394,22 @@ static struct tps6586x_platform_data *tps6586x_parse_dt(struct i2c_client *clien
                return NULL;
 
        for (i = 0, j = 0; i < num && j < count; i++) {
+               struct regulator_init_data *reg_idata;
+
                if (!tps6586x_matches[i].init_data)
                        continue;
 
+               reg_idata  = tps6586x_matches[i].init_data;
                devs[j].name = "tps6586x-regulator";
                devs[j].platform_data = tps6586x_matches[i].init_data;
                devs[j].id = (int)tps6586x_matches[i].driver_data;
+               if (devs[j].id == TPS6586X_ID_SYS)
+                       sys_rail_name = reg_idata->constraints.name;
+
+               if ((devs[j].id == TPS6586X_ID_LDO_5) ||
+                       (devs[j].id == TPS6586X_ID_LDO_RTC))
+                       reg_idata->supply_regulator = sys_rail_name;
+
                devs[j].of_node = tps6586x_matches[i].of_node;
                j++;
        }
index 0aac4aff17a5f6cf4d66144883608157a720d7ed..a050e56a9bbdcf16f200dbe363391393ce4f6756 100644 (file)
@@ -135,6 +135,7 @@ static struct regmap_irq_chip wm8994_irq_chip = {
        .status_base = WM8994_INTERRUPT_STATUS_1,
        .mask_base = WM8994_INTERRUPT_STATUS_1_MASK,
        .ack_base = WM8994_INTERRUPT_STATUS_1,
+       .runtime_pm = true,
 };
 
 int wm8994_irq_init(struct wm8994 *wm8994)
index 9943971c13e346a6d1d0f742df90c428024e1f71..a4f33c995ea17c6eabe257ae92c4fc950e49f0a5 100644 (file)
@@ -57,12 +57,6 @@ static int bmp085_i2c_remove(struct i2c_client *client)
        return bmp085_remove(&client->dev);
 }
 
-static const struct of_device_id bmp085_of_match[] = {
-       { .compatible = "bosch,bmp085", },
-       { },
-};
-MODULE_DEVICE_TABLE(of, bmp085_of_match);
-
 static const struct i2c_device_id bmp085_id[] = {
        { BMP085_NAME, 0 },
        { "bmp180", 0 },
@@ -74,7 +68,6 @@ static struct i2c_driver bmp085_i2c_driver = {
        .driver = {
                .owner  = THIS_MODULE,
                .name   = BMP085_NAME,
-               .of_match_table = bmp085_of_match
        },
        .id_table       = bmp085_id,
        .probe          = bmp085_i2c_probe,
index a2d25e4857e31387fc0457b5a47efc4c1e438bd0..eaddfe9db149a8f070ec11e5ae78c4e8821f175d 100644 (file)
@@ -978,7 +978,6 @@ static int fpga_of_probe(struct platform_device *op)
        dev_set_drvdata(priv->dev, priv);
        dma_cap_zero(mask);
        dma_cap_set(DMA_MEMCPY, mask);
-       dma_cap_set(DMA_INTERRUPT, mask);
        dma_cap_set(DMA_SLAVE, mask);
        dma_cap_set(DMA_SG, mask);
 
index 8c279da0741026322b6ab71d712e438a7e077fe9..0c43297ed9ac6262ca2e901703f3e3bb3c10a2cb 100644 (file)
@@ -666,7 +666,7 @@ static int data_submit_dma(struct fpga_device *priv, struct data_buf *buf)
        src = SYS_FPGA_BLOCK;
        tx = chan->device->device_prep_dma_memcpy(chan, dst, src,
                                                  REG_BLOCK_SIZE,
-                                                 DMA_PREP_INTERRUPT);
+                                                 0);
        if (!tx) {
                dev_err(priv->dev, "unable to prep SYS-FPGA DMA\n");
                return -ENOMEM;
index 1dcb9ae1905a0853d45795082561f61a0fb56a15..01e2b0d7e59043cfcf652090b5c328a789dd9383 100644 (file)
@@ -33,7 +33,7 @@
 
 void ibmasm_register_uart(struct service_processor *sp)
 {
-       struct uart_port uport;
+       struct uart_8250_port uart;
        void __iomem *iomem_base;
 
        iomem_base = sp->base_address + SCOUT_COM_B_BASE;
@@ -47,14 +47,14 @@ void ibmasm_register_uart(struct service_processor *sp)
                return;
        }
 
-       memset(&uport, 0, sizeof(struct uart_port));
-       uport.irq       = sp->irq;
-       uport.uartclk   = 3686400;
-       uport.flags     = UPF_SHARE_IRQ;
-       uport.iotype    = UPIO_MEM;
-       uport.membase   = iomem_base;
+       memset(&uart, 0, sizeof(uart));
+       uart.port.irq           = sp->irq;
+       uart.port.uartclk       = 3686400;
+       uart.port.flags         = UPF_SHARE_IRQ;
+       uart.port.iotype        = UPIO_MEM;
+       uart.port.membase       = iomem_base;
 
-       sp->serial_line = serial8250_register_port(&uport);
+       sp->serial_line = serial8250_register_8250_port(&uart);
        if (sp->serial_line < 0) {
                dev_err(sp->dev, "Failed to register serial port\n");
                return;
index 24c4c962819e766f34a0ad211c28d8dcf5642609..b3b4c6dcbaa76ca2bb5ded68acf5f0091a27422c 100644 (file)
 /*
  * MEI device IDs
  */
-#define    MEI_DEV_ID_82946GZ  0x2974  /* 82946GZ/GL */
-#define    MEI_DEV_ID_82G35    0x2984  /* 82G35 Express */
-#define    MEI_DEV_ID_82Q965   0x2994  /* 82Q963/Q965 */
-#define    MEI_DEV_ID_82G965   0x29A4  /* 82P965/G965 */
-
-#define    MEI_DEV_ID_82GM965  0x2A04  /* Mobile PM965/GM965 */
-#define    MEI_DEV_ID_82GME965 0x2A14  /* Mobile GME965/GLE960 */
-
-#define    MEI_DEV_ID_ICH9_82Q35 0x29B4  /* 82Q35 Express */
-#define    MEI_DEV_ID_ICH9_82G33 0x29C4  /* 82G33/G31/P35/P31 Express */
-#define    MEI_DEV_ID_ICH9_82Q33 0x29D4  /* 82Q33 Express */
-#define    MEI_DEV_ID_ICH9_82X38 0x29E4  /* 82X38/X48 Express */
-#define    MEI_DEV_ID_ICH9_3200  0x29F4  /* 3200/3210 Server */
-
-#define    MEI_DEV_ID_ICH9_6   0x28B4  /* Bearlake */
-#define    MEI_DEV_ID_ICH9_7   0x28C4  /* Bearlake */
-#define    MEI_DEV_ID_ICH9_8   0x28D4  /* Bearlake */
-#define    MEI_DEV_ID_ICH9_9    0x28E4  /* Bearlake */
-#define    MEI_DEV_ID_ICH9_10  0x28F4  /* Bearlake */
-
-#define    MEI_DEV_ID_ICH9M_1  0x2A44  /* Cantiga */
-#define    MEI_DEV_ID_ICH9M_2  0x2A54  /* Cantiga */
-#define    MEI_DEV_ID_ICH9M_3  0x2A64  /* Cantiga */
-#define    MEI_DEV_ID_ICH9M_4  0x2A74  /* Cantiga */
-
-#define    MEI_DEV_ID_ICH10_1  0x2E04  /* Eaglelake */
-#define    MEI_DEV_ID_ICH10_2  0x2E14  /* Eaglelake */
-#define    MEI_DEV_ID_ICH10_3  0x2E24  /* Eaglelake */
-#define    MEI_DEV_ID_ICH10_4  0x2E34  /* Eaglelake */
-
-#define    MEI_DEV_ID_IBXPK_1  0x3B64  /* Calpella */
-#define    MEI_DEV_ID_IBXPK_2  0x3B65  /* Calpella */
-
-#define    MEI_DEV_ID_CPT_1    0x1C3A    /* Cougerpoint */
-#define    MEI_DEV_ID_PBG_1    0x1D3A    /* PBG */
-
-#define    MEI_DEV_ID_PPT_1    0x1E3A    /* Pantherpoint PPT */
-#define    MEI_DEV_ID_PPT_2    0x1CBA    /* Pantherpoint PPT */
-#define    MEI_DEV_ID_PPT_3    0x1DBA    /* Pantherpoint PPT */
-
+#define MEI_DEV_ID_82946GZ    0x2974  /* 82946GZ/GL */
+#define MEI_DEV_ID_82G35      0x2984  /* 82G35 Express */
+#define MEI_DEV_ID_82Q965     0x2994  /* 82Q963/Q965 */
+#define MEI_DEV_ID_82G965     0x29A4  /* 82P965/G965 */
+
+#define MEI_DEV_ID_82GM965    0x2A04  /* Mobile PM965/GM965 */
+#define MEI_DEV_ID_82GME965   0x2A14  /* Mobile GME965/GLE960 */
+
+#define MEI_DEV_ID_ICH9_82Q35 0x29B4  /* 82Q35 Express */
+#define MEI_DEV_ID_ICH9_82G33 0x29C4  /* 82G33/G31/P35/P31 Express */
+#define MEI_DEV_ID_ICH9_82Q33 0x29D4  /* 82Q33 Express */
+#define MEI_DEV_ID_ICH9_82X38 0x29E4  /* 82X38/X48 Express */
+#define MEI_DEV_ID_ICH9_3200  0x29F4  /* 3200/3210 Server */
+
+#define MEI_DEV_ID_ICH9_6     0x28B4  /* Bearlake */
+#define MEI_DEV_ID_ICH9_7     0x28C4  /* Bearlake */
+#define MEI_DEV_ID_ICH9_8     0x28D4  /* Bearlake */
+#define MEI_DEV_ID_ICH9_9     0x28E4  /* Bearlake */
+#define MEI_DEV_ID_ICH9_10    0x28F4  /* Bearlake */
+
+#define MEI_DEV_ID_ICH9M_1    0x2A44  /* Cantiga */
+#define MEI_DEV_ID_ICH9M_2    0x2A54  /* Cantiga */
+#define MEI_DEV_ID_ICH9M_3    0x2A64  /* Cantiga */
+#define MEI_DEV_ID_ICH9M_4    0x2A74  /* Cantiga */
+
+#define MEI_DEV_ID_ICH10_1    0x2E04  /* Eaglelake */
+#define MEI_DEV_ID_ICH10_2    0x2E14  /* Eaglelake */
+#define MEI_DEV_ID_ICH10_3    0x2E24  /* Eaglelake */
+#define MEI_DEV_ID_ICH10_4    0x2E34  /* Eaglelake */
+
+#define MEI_DEV_ID_IBXPK_1    0x3B64  /* Calpella */
+#define MEI_DEV_ID_IBXPK_2    0x3B65  /* Calpella */
+
+#define MEI_DEV_ID_CPT_1      0x1C3A  /* Couger Point */
+#define MEI_DEV_ID_PBG_1      0x1D3A  /* C600/X79 Patsburg */
+
+#define MEI_DEV_ID_PPT_1      0x1E3A  /* Panther Point */
+#define MEI_DEV_ID_PPT_2      0x1CBA  /* Panther Point */
+#define MEI_DEV_ID_PPT_3      0x1DBA  /* Panther Point */
 
 /*
  * MEI HW Section
index e77f86e69fb5f55ba89bfac1e6b217a4318d0fe2..98f1430e3e1446b272725bffbf25da609c0aa3e7 100644 (file)
 #include "interface.h"
 #include <linux/mei.h>
 
+const char *mei_dev_state_str(int state)
+{
+#define MEI_DEV_STATE(state) case MEI_DEV_##state: return #state
+       switch (state) {
+       MEI_DEV_STATE(INITIALIZING);
+       MEI_DEV_STATE(INIT_CLIENTS);
+       MEI_DEV_STATE(ENABLED);
+       MEI_DEV_STATE(RESETING);
+       MEI_DEV_STATE(DISABLED);
+       MEI_DEV_STATE(RECOVERING_FROM_RESET);
+       MEI_DEV_STATE(POWER_DOWN);
+       MEI_DEV_STATE(POWER_UP);
+       default:
+               return "unkown";
+       }
+#undef MEI_DEV_STATE
+}
+
+
 const uuid_le mei_amthi_guid  = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, 0xac,
                                                0xa8, 0x46, 0xe0, 0xff, 0x65,
                                                0x81, 0x4c);
@@ -123,7 +142,7 @@ struct mei_device *mei_device_init(struct pci_dev *pdev)
        mutex_init(&dev->device_lock);
        init_waitqueue_head(&dev->wait_recvd_msg);
        init_waitqueue_head(&dev->wait_stop_wd);
-       dev->mei_state = MEI_INITIALIZING;
+       dev->dev_state = MEI_DEV_INITIALIZING;
        dev->iamthif_state = MEI_IAMTHIF_IDLE;
        dev->wd_interface_reg = false;
 
@@ -182,7 +201,7 @@ int mei_hw_init(struct mei_device *dev)
        }
 
        if (err <= 0 && !dev->recvd_msg) {
-               dev->mei_state = MEI_DISABLED;
+               dev->dev_state = MEI_DEV_DISABLED;
                dev_dbg(&dev->pdev->dev,
                        "wait_event_interruptible_timeout failed"
                        "on wait for ME to turn on ME_RDY.\n");
@@ -192,7 +211,7 @@ int mei_hw_init(struct mei_device *dev)
 
        if (!(((dev->host_hw_state & H_RDY) == H_RDY) &&
              ((dev->me_hw_state & ME_RDY_HRA) == ME_RDY_HRA))) {
-               dev->mei_state = MEI_DISABLED;
+               dev->dev_state = MEI_DEV_DISABLED;
                dev_dbg(&dev->pdev->dev,
                        "host_hw_state = 0x%08x, me_hw_state = 0x%08x.\n",
                        dev->host_hw_state, dev->me_hw_state);
@@ -258,15 +277,15 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
        struct mei_cl_cb *cb_next = NULL;
        bool unexpected;
 
-       if (dev->mei_state == MEI_RECOVERING_FROM_RESET) {
+       if (dev->dev_state == MEI_DEV_RECOVERING_FROM_RESET) {
                dev->need_reset = true;
                return;
        }
 
-       unexpected = (dev->mei_state != MEI_INITIALIZING &&
-                       dev->mei_state != MEI_DISABLED &&
-                       dev->mei_state != MEI_POWER_DOWN &&
-                       dev->mei_state != MEI_POWER_UP);
+       unexpected = (dev->dev_state != MEI_DEV_INITIALIZING &&
+                       dev->dev_state != MEI_DEV_DISABLED &&
+                       dev->dev_state != MEI_DEV_POWER_DOWN &&
+                       dev->dev_state != MEI_DEV_POWER_UP);
 
        dev->host_hw_state = mei_hcsr_read(dev);
 
@@ -285,10 +304,10 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
 
        dev->need_reset = false;
 
-       if (dev->mei_state != MEI_INITIALIZING) {
-               if (dev->mei_state != MEI_DISABLED &&
-                   dev->mei_state != MEI_POWER_DOWN)
-                       dev->mei_state = MEI_RESETING;
+       if (dev->dev_state != MEI_DEV_INITIALIZING) {
+               if (dev->dev_state != MEI_DEV_DISABLED &&
+                   dev->dev_state != MEI_DEV_POWER_DOWN)
+                       dev->dev_state = MEI_DEV_RESETING;
 
                list_for_each_entry_safe(cl_pos,
                                cl_next, &dev->file_list, link) {
@@ -311,7 +330,6 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
 
        dev->me_clients_num = 0;
        dev->rd_msg_hdr = 0;
-       dev->stop = false;
        dev->wd_pending = false;
 
        /* update the state of the registers after reset */
@@ -322,7 +340,8 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled)
            dev->host_hw_state, dev->me_hw_state);
 
        if (unexpected)
-               dev_warn(&dev->pdev->dev, "unexpected reset.\n");
+               dev_warn(&dev->pdev->dev, "unexpected reset: dev_state = %s\n",
+                        mei_dev_state_str(dev->dev_state));
 
        /* Wake up all readings so they can be interrupted */
        list_for_each_entry_safe(cl_pos, cl_next, &dev->file_list, link) {
@@ -371,7 +390,7 @@ void mei_host_start_message(struct mei_device *dev)
        if (mei_write_message(dev, mei_hdr, (unsigned char *)host_start_req,
                                       mei_hdr->length)) {
                dev_dbg(&dev->pdev->dev, "write send version message to FW fail.\n");
-               dev->mei_state = MEI_RESETING;
+               dev->dev_state = MEI_DEV_RESETING;
                mei_reset(dev, 1);
        }
        dev->init_clients_state = MEI_START_MESSAGE;
@@ -403,7 +422,7 @@ void mei_host_enum_clients_message(struct mei_device *dev)
        host_enum_req->hbm_cmd = HOST_ENUM_REQ_CMD;
        if (mei_write_message(dev, mei_hdr, (unsigned char *)host_enum_req,
                                mei_hdr->length)) {
-               dev->mei_state = MEI_RESETING;
+               dev->dev_state = MEI_DEV_RESETING;
                dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n");
                mei_reset(dev, 1);
        }
@@ -444,7 +463,7 @@ void mei_allocate_me_clients_storage(struct mei_device *dev)
                        sizeof(struct mei_me_client), GFP_KERNEL);
        if (!clients) {
                dev_dbg(&dev->pdev->dev, "memory allocation for ME clients failed.\n");
-               dev->mei_state = MEI_RESETING;
+               dev->dev_state = MEI_DEV_RESETING;
                mei_reset(dev, 1);
                return ;
        }
@@ -490,7 +509,7 @@ int mei_host_client_properties(struct mei_device *dev)
                if (mei_write_message(dev, mei_header,
                                (unsigned char *)host_cli_req,
                                mei_header->length)) {
-                       dev->mei_state = MEI_RESETING;
+                       dev->dev_state = MEI_DEV_RESETING;
                        dev_dbg(&dev->pdev->dev, "write send enumeration request message to FW fail.\n");
                        mei_reset(dev, 1);
                        return -EIO;
@@ -522,12 +541,12 @@ void mei_cl_init(struct mei_cl *priv, struct mei_device *dev)
        priv->dev = dev;
 }
 
-int mei_find_me_client_index(const struct mei_device *dev, uuid_le cuuid)
+int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *cuuid)
 {
-       int i, res = -1;
+       int i, res = -ENOENT;
 
        for (i = 0; i < dev->me_clients_num; ++i)
-               if (uuid_le_cmp(cuuid,
+               if (uuid_le_cmp(*cuuid,
                                dev->me_clients[i].props.protocol_name) == 0) {
                        res = i;
                        break;
@@ -538,35 +557,35 @@ int mei_find_me_client_index(const struct mei_device *dev, uuid_le cuuid)
 
 
 /**
- * mei_find_me_client_update_filext - searches for ME client guid
+ * mei_me_cl_update_filext - searches for ME client guid
  *                       sets client_id in mei_file_private if found
  * @dev: the device structure
- * @priv: private file structure to set client_id in
- * @cguid: searched guid of ME client
+ * @cl: private file structure to set client_id in
+ * @cuuid: searched uuid of ME client
  * @client_id: id of host client to be set in file private structure
  *
  * returns ME client index
  */
-u8 mei_find_me_client_update_filext(struct mei_device *dev, struct mei_cl *priv,
-                               const uuid_le *cguid, u8 client_id)
+int mei_me_cl_update_filext(struct mei_device *dev, struct mei_cl *cl,
+                               const uuid_le *cuuid, u8 host_cl_id)
 {
        int i;
 
-       if (!dev || !priv || !cguid)
-               return 0;
+       if (!dev || !cl || !cuuid)
+               return -EINVAL;
 
        /* check for valid client id */
-       i = mei_find_me_client_index(dev, *cguid);
+       i = mei_me_cl_by_uuid(dev, cuuid);
        if (i >= 0) {
-               priv->me_client_id = dev->me_clients[i].client_id;
-               priv->state = MEI_FILE_CONNECTING;
-               priv->host_client_id = client_id;
+               cl->me_client_id = dev->me_clients[i].client_id;
+               cl->state = MEI_FILE_CONNECTING;
+               cl->host_client_id = host_cl_id;
 
-               list_add_tail(&priv->link, &dev->file_list);
+               list_add_tail(&cl->link, &dev->file_list);
                return (u8)i;
        }
 
-       return 0;
+       return -ENOENT;
 }
 
 /**
@@ -577,16 +596,16 @@ u8 mei_find_me_client_update_filext(struct mei_device *dev, struct mei_cl *priv,
  */
 void mei_host_init_iamthif(struct mei_device *dev)
 {
-       u8 i;
+       int i;
        unsigned char *msg_buf;
 
        mei_cl_init(&dev->iamthif_cl, dev);
        dev->iamthif_cl.state = MEI_FILE_DISCONNECTED;
 
        /* find ME amthi client */
-       i = mei_find_me_client_update_filext(dev, &dev->iamthif_cl,
+       i = mei_me_cl_update_filext(dev, &dev->iamthif_cl,
                            &mei_amthi_guid, MEI_IAMTHIF_HOST_CLIENT_ID);
-       if (dev->iamthif_cl.state != MEI_FILE_CONNECTING) {
+       if (i < 0) {
                dev_dbg(&dev->pdev->dev, "failed to find iamthif client.\n");
                return;
        }
index fb5c7db4723bd4da189f03adee97a7affd06a345..ec6c785a3961db4cd82e347436b23817326a026b 100644 (file)
 #include "mei_dev.h"
 
 
-#define AMT_WD_DEFAULT_TIMEOUT 120     /* seconds */
-#define AMT_WD_MIN_TIMEOUT 120 /* seconds */
-#define AMT_WD_MAX_TIMEOUT 65535       /* seconds */
-
-#define MEI_WATCHDOG_DATA_SIZE         16
-#define MEI_START_WD_DATA_SIZE         20
-#define MEI_WD_PARAMS_SIZE             4
-
 
 void mei_read_slots(struct mei_device *dev,
                     unsigned char *buffer,
@@ -64,7 +56,7 @@ int mei_flow_ctrl_creds(struct mei_device *dev, struct mei_cl *cl);
 
 
 int mei_wd_send(struct mei_device *dev);
-int mei_wd_stop(struct mei_device *dev, bool preserve);
+int mei_wd_stop(struct mei_device *dev);
 int mei_wd_host_init(struct mei_device *dev);
 /*
  * mei_watchdog_register  - Registering watchdog interface
index c6ffbbe5a6c014b11ee05855795c1c941d0f0abe..0900a711badda0c28010278dc9c8adde3f50c075 100644 (file)
@@ -633,7 +633,7 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev,
                if (version_res->host_version_supported) {
                        dev->version.major_version = HBM_MAJOR_VERSION;
                        dev->version.minor_version = HBM_MINOR_VERSION;
-                       if (dev->mei_state == MEI_INIT_CLIENTS &&
+                       if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
                            dev->init_clients_state == MEI_START_MESSAGE) {
                                dev->init_clients_timer = 0;
                                mei_host_enum_clients_message(dev);
@@ -707,7 +707,7 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev,
                        dev->me_clients[dev->me_client_presentation_num].props
                                                = props_res->client_properties;
 
-                       if (dev->mei_state == MEI_INIT_CLIENTS &&
+                       if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
                            dev->init_clients_state ==
                                        MEI_CLIENT_PROPERTIES_MESSAGE) {
                                dev->me_client_index++;
@@ -734,7 +734,7 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev,
                                         * Client ID 2 - Reserved for AMTHI
                                         */
                                        bitmap_set(dev->host_clients_map, 0, 3);
-                                       dev->mei_state = MEI_ENABLED;
+                                       dev->dev_state = MEI_DEV_ENABLED;
 
                                        /* if wd initialization fails, initialization the AMTHI client,
                                         * otherwise the AMTHI client will be initialized after the WD client connect response
@@ -759,7 +759,7 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev,
        case HOST_ENUM_RES_CMD:
                enum_res = (struct hbm_host_enum_response *) mei_msg;
                memcpy(dev->me_clients_map, enum_res->valid_addresses, 32);
-               if (dev->mei_state == MEI_INIT_CLIENTS &&
+               if (dev->dev_state == MEI_DEV_INIT_CLIENTS &&
                    dev->init_clients_state == MEI_ENUM_CLIENTS_MESSAGE) {
                                dev->init_clients_timer = 0;
                                dev->me_client_presentation_num = 0;
@@ -776,7 +776,7 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev,
                break;
 
        case HOST_STOP_RES_CMD:
-               dev->mei_state = MEI_DISABLED;
+               dev->dev_state = MEI_DEV_DISABLED;
                dev_dbg(&dev->pdev->dev, "resetting because of FW stop response.\n");
                mei_reset(dev, 1);
                break;
@@ -1224,10 +1224,9 @@ static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list,
                }
        }
 
-       if (dev->stop && !dev->wd_pending) {
-               dev->wd_stopped = true;
+       if (dev->wd_state == MEI_WD_STOPPING) {
+               dev->wd_state = MEI_WD_IDLE;
                wake_up_interruptible(&dev->wait_stop_wd);
-               return 0;
        }
 
        if (dev->extra_write_index) {
@@ -1240,7 +1239,7 @@ static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list,
                *slots -= dev->extra_write_index;
                dev->extra_write_index = 0;
        }
-       if (dev->mei_state == MEI_ENABLED) {
+       if (dev->dev_state == MEI_DEV_ENABLED) {
                if (dev->wd_pending &&
                    mei_flow_ctrl_creds(dev, &dev->wd_cl) > 0) {
                        if (mei_wd_send(dev))
@@ -1250,14 +1249,12 @@ static int mei_irq_thread_write_handler(struct mei_io_list *cmpl_list,
 
                        dev->wd_pending = false;
 
-                       if (dev->wd_timeout)
-                               *slots -= mei_data2slots(MEI_START_WD_DATA_SIZE);
+                       if (dev->wd_state == MEI_WD_RUNNING)
+                               *slots -= mei_data2slots(MEI_WD_START_MSG_SIZE);
                        else
-                               *slots -= mei_data2slots(MEI_START_WD_DATA_SIZE);
+                               *slots -= mei_data2slots(MEI_WD_STOP_MSG_SIZE);
                }
        }
-       if (dev->stop)
-               return -ENODEV;
 
        /* complete control write list CB */
        dev_dbg(&dev->pdev->dev, "complete control write list cb.\n");
@@ -1361,8 +1358,8 @@ void mei_timer(struct work_struct *work)
 
 
        mutex_lock(&dev->device_lock);
-       if (dev->mei_state != MEI_ENABLED) {
-               if (dev->mei_state == MEI_INIT_CLIENTS) {
+       if (dev->dev_state != MEI_DEV_ENABLED) {
+               if (dev->dev_state == MEI_DEV_INIT_CLIENTS) {
                        if (dev->init_clients_timer) {
                                if (--dev->init_clients_timer == 0) {
                                        dev_dbg(&dev->pdev->dev, "IMEI reset due to init clients timeout ,init clients state = %d.\n",
@@ -1484,8 +1481,8 @@ irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id)
 
        /* check if ME wants a reset */
        if ((dev->me_hw_state & ME_RDY_HRA) == 0 &&
-           dev->mei_state != MEI_RESETING &&
-           dev->mei_state != MEI_INITIALIZING) {
+           dev->dev_state != MEI_DEV_RESETING &&
+           dev->dev_state != MEI_DEV_INITIALIZING) {
                dev_dbg(&dev->pdev->dev, "FW not ready.\n");
                mei_reset(dev, 1);
                mutex_unlock(&dev->device_lock);
@@ -1498,7 +1495,7 @@ irqreturn_t mei_interrupt_thread_handler(int irq, void *dev_id)
                        dev_dbg(&dev->pdev->dev, "we need to start the dev.\n");
                        dev->host_hw_state |= (H_IE | H_IG | H_RDY);
                        mei_hcsr_set(dev);
-                       dev->mei_state = MEI_INIT_CLIENTS;
+                       dev->dev_state = MEI_DEV_INIT_CLIENTS;
                        dev_dbg(&dev->pdev->dev, "link is established start sending messages.\n");
                        /* link is established
                         * start sending messages.
index 50f52e21f587a229e374a9f72149186aace43777..fcba98eb892e1e410d62a4c198d978ab82b667f5 100644 (file)
 #include <linux/mei.h>
 #include "interface.h"
 
+/**
+ * mei_me_cl_by_id return index to me_clients for client_id
+ *
+ * @dev: the device structure
+ * @client_id: me client id
+ *
+ * Locking: called under "dev->device_lock" lock
+ *
+ * returns index on success, -ENOENT on failure.
+ */
 
+int mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
+{
+       int i;
+       for (i = 0; i < dev->me_clients_num; i++)
+               if (dev->me_clients[i].client_id == client_id)
+                       break;
+       if (WARN_ON(dev->me_clients[i].client_id != client_id))
+               return -ENOENT;
+
+       if (i == dev->me_clients_num)
+               return -ENOENT;
+
+       return i;
+}
 
 /**
  * mei_ioctl_connect_client - the connect to fw client IOCTL function
@@ -84,7 +108,7 @@ int mei_ioctl_connect_client(struct file *file,
 
        cb->major_file_operations = MEI_IOCTL;
 
-       if (dev->mei_state != MEI_ENABLED) {
+       if (dev->dev_state != MEI_DEV_ENABLED) {
                rets = -ENODEV;
                goto end;
        }
@@ -95,7 +119,7 @@ int mei_ioctl_connect_client(struct file *file,
        }
 
        /* find ME client we're trying to connect to */
-       i = mei_find_me_client_index(dev, data->in_client_uuid);
+       i = mei_me_cl_by_uuid(dev, &data->in_client_uuid);
        if (i >= 0 && !dev->me_clients[i].props.fixed_address) {
                cl->me_client_id = dev->me_clients[i].client_id;
                cl->state = MEI_FILE_CONNECTING;
@@ -273,19 +297,12 @@ int amthi_read(struct mei_device *dev, struct file *file,
                return -ETIMEDOUT;
        }
 
-       for (i = 0; i < dev->me_clients_num; i++) {
-               if (dev->me_clients[i].client_id ==
-                   dev->iamthif_cl.me_client_id)
-                       break;
-       }
+       i = mei_me_cl_by_id(dev, dev->iamthif_cl.me_client_id);
 
-       if (i == dev->me_clients_num) {
+       if (i < 0) {
                dev_dbg(&dev->pdev->dev, "amthi client not found.\n");
                return -ENODEV;
        }
-       if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id))
-               return -ENODEV;
-
        dev_dbg(&dev->pdev->dev, "checking amthi data\n");
        cb = find_amthi_read_list_entry(dev, file);
 
@@ -316,8 +333,7 @@ int amthi_read(struct mei_device *dev, struct file *file,
        dev->iamthif_timer = 0;
 
        if (cb) {
-               timeout = cb->read_time +
-                                       msecs_to_jiffies(IAMTHIF_READ_TIMER);
+               timeout = cb->read_time + msecs_to_jiffies(IAMTHIF_READ_TIMER);
                dev_dbg(&dev->pdev->dev, "amthi timeout = %lud\n",
                                timeout);
 
@@ -386,7 +402,7 @@ int mei_start_read(struct mei_device *dev, struct mei_cl *cl)
        if (cl->state != MEI_FILE_CONNECTED)
                return -ENODEV;
 
-       if (dev->mei_state != MEI_ENABLED)
+       if (dev->dev_state != MEI_DEV_ENABLED)
                return -ENODEV;
 
        dev_dbg(&dev->pdev->dev, "check if read is pending.\n");
@@ -401,19 +417,8 @@ int mei_start_read(struct mei_device *dev, struct mei_cl *cl)
 
        dev_dbg(&dev->pdev->dev, "allocation call back successful. host client = %d, ME client = %d\n",
                cl->host_client_id, cl->me_client_id);
-
-       for (i = 0; i < dev->me_clients_num; i++) {
-               if (dev->me_clients[i].client_id == cl->me_client_id)
-                       break;
-
-       }
-
-       if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id)) {
-               rets = -ENODEV;
-               goto unlock;
-       }
-
-       if (i == dev->me_clients_num) {
+       i = mei_me_cl_by_id(dev, cl->me_client_id);
+       if (i < 0) {
                rets = -ENODEV;
                goto unlock;
        }
index 092330208869640a1e474abfd781bce41a5c6043..9a595338ae1555daa628152895b7910ac47c520b 100644 (file)
@@ -41,8 +41,6 @@
 #include <linux/mei.h>
 #include "interface.h"
 
-static const char mei_driver_name[] = "mei";
-
 /* The device pointer */
 /* Currently this driver works as long as there is only a single AMT device. */
 struct pci_dev *mei_device;
@@ -234,9 +232,9 @@ static int mei_open(struct inode *inode, struct file *file)
                goto out_unlock;
 
        err = -ENODEV;
-       if (dev->mei_state != MEI_ENABLED) {
-               dev_dbg(&dev->pdev->dev, "mei_state != MEI_ENABLED  mei_state= %d\n",
-                   dev->mei_state);
+       if (dev->dev_state != MEI_DEV_ENABLED) {
+               dev_dbg(&dev->pdev->dev, "dev_state != MEI_ENABLED  dev_state = %s\n",
+                   mei_dev_state_str(dev->dev_state));
                goto out_unlock;
        }
        err = -EMFILE;
@@ -386,17 +384,16 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
        dev = cl->dev;
 
        mutex_lock(&dev->device_lock);
-       if (dev->mei_state != MEI_ENABLED) {
+       if (dev->dev_state != MEI_DEV_ENABLED) {
                rets = -ENODEV;
                goto out;
        }
 
        if ((cl->sm_state & MEI_WD_STATE_INDEPENDENCE_MSG_SENT) == 0) {
                /* Do not allow to read watchdog client */
-               i = mei_find_me_client_index(dev, mei_wd_guid);
+               i = mei_me_cl_by_uuid(dev, &mei_wd_guid);
                if (i >= 0) {
                        struct mei_me_client *me_client = &dev->me_clients[i];
-
                        if (cl->me_client_id == me_client->client_id) {
                                rets = -EBADF;
                                goto out;
@@ -541,7 +538,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
 
        mutex_lock(&dev->device_lock);
 
-       if (dev->mei_state != MEI_ENABLED) {
+       if (dev->dev_state != MEI_DEV_ENABLED) {
                mutex_unlock(&dev->device_lock);
                return -ENODEV;
        }
@@ -616,26 +613,16 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
                        rets = -ENOMEM;
                        goto unlock_dev;
                }
-               if (dev->mei_state != MEI_ENABLED) {
+               if (dev->dev_state != MEI_DEV_ENABLED) {
                        rets = -ENODEV;
                        goto unlock_dev;
                }
-               for (i = 0; i < dev->me_clients_num; i++) {
-                       if (dev->me_clients[i].client_id ==
-                               dev->iamthif_cl.me_client_id)
-                               break;
-               }
-
-               if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id)) {
+               i = mei_me_cl_by_id(dev, dev->iamthif_cl.me_client_id);
+               if (i < 0) {
                        rets = -ENODEV;
                        goto unlock_dev;
                }
-               if (i == dev->me_clients_num ||
-                   (dev->me_clients[i].client_id !=
-                     dev->iamthif_cl.me_client_id)) {
-                       rets = -ENODEV;
-                       goto unlock_dev;
-               } else if (length > dev->me_clients[i].props.max_msg_length ||
+               if (length > dev->me_clients[i].props.max_msg_length ||
                           length <= 0) {
                        rets = -EMSGSIZE;
                        goto unlock_dev;
@@ -688,16 +675,8 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
                    cl->me_client_id);
                goto unlock_dev;
        }
-       for (i = 0; i < dev->me_clients_num; i++) {
-               if (dev->me_clients[i].client_id ==
-                   cl->me_client_id)
-                       break;
-       }
-       if (WARN_ON(dev->me_clients[i].client_id != cl->me_client_id)) {
-               rets = -ENODEV;
-               goto unlock_dev;
-       }
-       if (i == dev->me_clients_num) {
+       i = mei_me_cl_by_id(dev, cl->me_client_id);
+       if (i < 0) {
                rets = -ENODEV;
                goto unlock_dev;
        }
@@ -790,7 +769,7 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data)
        dev_dbg(&dev->pdev->dev, "IOCTL cmd = 0x%x", cmd);
 
        mutex_lock(&dev->device_lock);
-       if (dev->mei_state != MEI_ENABLED) {
+       if (dev->dev_state != MEI_DEV_ENABLED) {
                rets = -ENODEV;
                goto out;
        }
@@ -869,7 +848,7 @@ static unsigned int mei_poll(struct file *file, poll_table *wait)
 
        mutex_lock(&dev->device_lock);
 
-       if (dev->mei_state != MEI_ENABLED)
+       if (dev->dev_state != MEI_DEV_ENABLED)
                goto out;
 
 
@@ -924,6 +903,27 @@ static struct miscdevice  mei_misc_device = {
                .minor = MISC_DYNAMIC_MINOR,
 };
 
+/**
+ * mei_quirk_probe - probe for devices that doesn't valid ME interface
+ * @pdev: PCI device structure
+ * @ent: entry into pci_device_table
+ *
+ * returns true if ME Interface is valid, false otherwise
+ */
+static bool __devinit mei_quirk_probe(struct pci_dev *pdev,
+                               const struct pci_device_id *ent)
+{
+       u32 reg;
+       if (ent->device == MEI_DEV_ID_PBG_1) {
+               pci_read_config_dword(pdev, 0x48, &reg);
+               /* make sure that bit 9 is up and bit 10 is down */
+               if ((reg & 0x600) == 0x200) {
+                       dev_info(&pdev->dev, "Device doesn't have valid ME Interface\n");
+                       return false;
+               }
+       }
+       return true;
+}
 /**
  * mei_probe - Device Initialization Routine
  *
@@ -939,6 +939,12 @@ static int __devinit mei_probe(struct pci_dev *pdev,
        int err;
 
        mutex_lock(&mei_mutex);
+
+       if (!mei_quirk_probe(pdev, ent)) {
+               err = -ENODEV;
+               goto end;
+       }
+
        if (mei_device) {
                err = -EEXIST;
                goto end;
@@ -952,7 +958,7 @@ static int __devinit mei_probe(struct pci_dev *pdev,
        /* set PCI host mastering  */
        pci_set_master(pdev);
        /* pci request regions for mei driver */
-       err = pci_request_regions(pdev, mei_driver_name);
+       err = pci_request_regions(pdev, KBUILD_MODNAME);
        if (err) {
                dev_err(&pdev->dev, "failed to get pci regions.\n");
                goto disable_device;
@@ -977,12 +983,12 @@ static int __devinit mei_probe(struct pci_dev *pdev,
                err = request_threaded_irq(pdev->irq,
                        NULL,
                        mei_interrupt_thread_handler,
-                       IRQF_ONESHOT, mei_driver_name, dev);
+                       IRQF_ONESHOT, KBUILD_MODNAME, dev);
        else
                err = request_threaded_irq(pdev->irq,
                        mei_interrupt_quick_handler,
                        mei_interrupt_thread_handler,
-                       IRQF_SHARED, mei_driver_name, dev);
+                       IRQF_SHARED, KBUILD_MODNAME, dev);
 
        if (err) {
                dev_err(&pdev->dev, "request_threaded_irq failure. irq = %d\n",
@@ -1054,7 +1060,9 @@ static void __devexit mei_remove(struct pci_dev *pdev)
 
        mutex_lock(&dev->device_lock);
 
-       mei_wd_stop(dev, false);
+       cancel_delayed_work(&dev->timer_work);
+
+       mei_wd_stop(dev);
 
        mei_device = NULL;
 
@@ -1109,12 +1117,15 @@ static int mei_pci_suspend(struct device *device)
        if (!dev)
                return -ENODEV;
        mutex_lock(&dev->device_lock);
+
+       cancel_delayed_work(&dev->timer_work);
+
        /* Stop watchdog if exists */
-       err = mei_wd_stop(dev, true);
+       err = mei_wd_stop(dev);
        /* Set new mei state */
-       if (dev->mei_state == MEI_ENABLED ||
-           dev->mei_state == MEI_RECOVERING_FROM_RESET) {
-               dev->mei_state = MEI_POWER_DOWN;
+       if (dev->dev_state == MEI_DEV_ENABLED ||
+           dev->dev_state == MEI_DEV_RECOVERING_FROM_RESET) {
+               dev->dev_state = MEI_DEV_POWER_DOWN;
                mei_reset(dev, 0);
        }
        mutex_unlock(&dev->device_lock);
@@ -1142,12 +1153,12 @@ static int mei_pci_resume(struct device *device)
                err = request_threaded_irq(pdev->irq,
                        NULL,
                        mei_interrupt_thread_handler,
-                       IRQF_ONESHOT, mei_driver_name, dev);
+                       IRQF_ONESHOT, KBUILD_MODNAME, dev);
        else
                err = request_threaded_irq(pdev->irq,
                        mei_interrupt_quick_handler,
                        mei_interrupt_thread_handler,
-                       IRQF_SHARED, mei_driver_name, dev);
+                       IRQF_SHARED, KBUILD_MODNAME, dev);
 
        if (err) {
                dev_err(&pdev->dev, "request_threaded_irq failed: irq = %d.\n",
@@ -1156,7 +1167,7 @@ static int mei_pci_resume(struct device *device)
        }
 
        mutex_lock(&dev->device_lock);
-       dev->mei_state = MEI_POWER_UP;
+       dev->dev_state = MEI_DEV_POWER_UP;
        mei_reset(dev, 1);
        mutex_unlock(&dev->device_lock);
 
@@ -1174,7 +1185,7 @@ static SIMPLE_DEV_PM_OPS(mei_pm_ops, mei_pci_suspend, mei_pci_resume);
  *  PCI driver structure
  */
 static struct pci_driver mei_driver = {
-       .name = mei_driver_name,
+       .name = KBUILD_MODNAME,
        .id_table = mei_pci_tbl,
        .probe = mei_probe,
        .remove = __devexit_p(mei_remove),
index d61c4ddfc80c3fa80f804f2c0a7528284b7b957a..c8660c0eb1c7045d51e6552a88e5769cc4301216 100644 (file)
 /*
  * watch dog definition
  */
-#define MEI_WATCHDOG_DATA_SIZE         16
-#define MEI_START_WD_DATA_SIZE         20
-#define MEI_WD_PARAMS_SIZE             4
+#define MEI_WD_HDR_SIZE       4
+#define MEI_WD_STOP_MSG_SIZE  MEI_WD_HDR_SIZE
+#define MEI_WD_START_MSG_SIZE (MEI_WD_HDR_SIZE + 16)
+
+#define MEI_WD_DEFAULT_TIMEOUT   120  /* seconds */
+#define MEI_WD_MIN_TIMEOUT       120  /* seconds */
+#define MEI_WD_MAX_TIMEOUT     65535  /* seconds */
+
+#define MEI_WD_STOP_TIMEOUT      10 /* msecs */
+
 #define MEI_WD_STATE_INDEPENDENCE_MSG_SENT       (1 << 0)
 
 #define MEI_RD_MSG_BUF_SIZE           (128 * sizeof(u32))
@@ -78,17 +85,19 @@ enum file_state {
 };
 
 /* MEI device states */
-enum mei_states {
-       MEI_INITIALIZING = 0,
-       MEI_INIT_CLIENTS,
-       MEI_ENABLED,
-       MEI_RESETING,
-       MEI_DISABLED,
-       MEI_RECOVERING_FROM_RESET,
-       MEI_POWER_DOWN,
-       MEI_POWER_UP
+enum mei_dev_state {
+       MEI_DEV_INITIALIZING = 0,
+       MEI_DEV_INIT_CLIENTS,
+       MEI_DEV_ENABLED,
+       MEI_DEV_RESETING,
+       MEI_DEV_DISABLED,
+       MEI_DEV_RECOVERING_FROM_RESET,
+       MEI_DEV_POWER_DOWN,
+       MEI_DEV_POWER_UP
 };
 
+const char *mei_dev_state_str(int state);
+
 /* init clients states*/
 enum mei_init_clients_states {
        MEI_START_MESSAGE = 0,
@@ -113,6 +122,12 @@ enum mei_file_transaction_states {
        MEI_READ_COMPLETE
 };
 
+enum mei_wd_states {
+       MEI_WD_IDLE,
+       MEI_WD_RUNNING,
+       MEI_WD_STOPPING,
+};
+
 /* MEI CB */
 enum mei_cb_major_types {
        MEI_READ = 0,
@@ -218,10 +233,9 @@ struct mei_device {
        /*
         * mei device  states
         */
-       enum mei_states mei_state;
+       enum mei_dev_state dev_state;
        enum mei_init_clients_states init_clients_state;
        u16 init_clients_timer;
-       bool stop;
        bool need_reset;
 
        u32 extra_write_index;
@@ -241,12 +255,11 @@ struct mei_device {
        bool mei_host_buffer_is_empty;
 
        struct mei_cl wd_cl;
+       enum mei_wd_states wd_state;
        bool wd_interface_reg;
        bool wd_pending;
-       bool wd_stopped;
-       bool wd_bypass; /* if false, don't refresh watchdog ME client */
-       u16 wd_timeout; /* seconds ((wd_data[1] << 8) + wd_data[0]) */
-       unsigned char wd_data[MEI_START_WD_DATA_SIZE];
+       u16 wd_timeout;
+       unsigned char wd_data[MEI_WD_START_MSG_SIZE];
 
 
        struct file *iamthif_file_object;
@@ -279,9 +292,10 @@ void mei_host_init_iamthif(struct mei_device *dev);
 void mei_allocate_me_clients_storage(struct mei_device *dev);
 
 
-u8 mei_find_me_client_update_filext(struct mei_device *dev,
-                               struct mei_cl *priv,
-                               const uuid_le *cguid, u8 client_id);
+int mei_me_cl_update_filext(struct mei_device *dev, struct mei_cl *cl,
+                       const uuid_le *cguid, u8 host_client_id);
+int mei_me_cl_by_uuid(const struct mei_device *dev, const uuid_le *cuuid);
+int mei_me_cl_by_id(struct mei_device *dev, u8 client_id);
 
 /*
  * MEI IO List Functions
@@ -348,7 +362,6 @@ void mei_run_next_iamthif_cmd(struct mei_device *dev);
 
 void mei_free_cb_private(struct mei_cl_cb *priv_cb);
 
-int mei_find_me_client_index(const struct mei_device *dev, uuid_le cuuid);
 
 /*
  * Register Access Function
index 5133fd77b91cc8e01be11736094cd9869b265a86..d96c537f046ffd4abf58b2a84db5e5dc48690747 100644 (file)
@@ -48,8 +48,8 @@ const uuid_le mei_wd_guid = UUID_LE(0x05B79A6F, 0x4628, 0x4D7F, 0x89,
 static void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout)
 {
        dev_dbg(&dev->pdev->dev, "wd: set timeout=%d.\n", timeout);
-       memcpy(dev->wd_data, mei_start_wd_params, MEI_WD_PARAMS_SIZE);
-       memcpy(dev->wd_data + MEI_WD_PARAMS_SIZE, &timeout, sizeof(u16));
+       memcpy(dev->wd_data, mei_start_wd_params, MEI_WD_HDR_SIZE);
+       memcpy(dev->wd_data + MEI_WD_HDR_SIZE, &timeout, sizeof(u16));
 }
 
 /**
@@ -66,10 +66,11 @@ int mei_wd_host_init(struct mei_device *dev)
 
        /* look for WD client and connect to it */
        dev->wd_cl.state = MEI_FILE_DISCONNECTED;
-       dev->wd_timeout = AMT_WD_DEFAULT_TIMEOUT;
+       dev->wd_timeout = MEI_WD_DEFAULT_TIMEOUT;
+       dev->wd_state = MEI_WD_IDLE;
 
        /* find ME WD client */
-       mei_find_me_client_update_filext(dev, &dev->wd_cl,
+       mei_me_cl_update_filext(dev, &dev->wd_cl,
                                &mei_wd_guid, MEI_WD_HOST_CLIENT_ID);
 
        dev_dbg(&dev->pdev->dev, "wd: check client\n");
@@ -108,10 +109,10 @@ int mei_wd_send(struct mei_device *dev)
        mei_hdr->msg_complete = 1;
        mei_hdr->reserved = 0;
 
-       if (!memcmp(dev->wd_data, mei_start_wd_params, MEI_WD_PARAMS_SIZE))
-               mei_hdr->length = MEI_START_WD_DATA_SIZE;
-       else if (!memcmp(dev->wd_data, mei_stop_wd_params, MEI_WD_PARAMS_SIZE))
-               mei_hdr->length = MEI_WD_PARAMS_SIZE;
+       if (!memcmp(dev->wd_data, mei_start_wd_params, MEI_WD_HDR_SIZE))
+               mei_hdr->length = MEI_WD_START_MSG_SIZE;
+       else if (!memcmp(dev->wd_data, mei_stop_wd_params, MEI_WD_HDR_SIZE))
+               mei_hdr->length = MEI_WD_STOP_MSG_SIZE;
        else
                return -EINVAL;
 
@@ -128,18 +129,17 @@ int mei_wd_send(struct mei_device *dev)
  *     -EIO when message send fails
  *     -EINVAL when invalid message is to be sent
  */
-int mei_wd_stop(struct mei_device *dev, bool preserve)
+int mei_wd_stop(struct mei_device *dev)
 {
        int ret;
-       u16 wd_timeout = dev->wd_timeout;
 
-       cancel_delayed_work(&dev->timer_work);
-       if (dev->wd_cl.state != MEI_FILE_CONNECTED || !dev->wd_timeout)
+       if (dev->wd_cl.state != MEI_FILE_CONNECTED ||
+           dev->wd_state != MEI_WD_RUNNING)
                return 0;
 
-       dev->wd_timeout = 0;
-       memcpy(dev->wd_data, mei_stop_wd_params, MEI_WD_PARAMS_SIZE);
-       dev->stop = true;
+       memcpy(dev->wd_data, mei_stop_wd_params, MEI_WD_STOP_MSG_SIZE);
+
+       dev->wd_state = MEI_WD_STOPPING;
 
        ret = mei_flow_ctrl_creds(dev, &dev->wd_cl);
        if (ret < 0)
@@ -161,13 +161,14 @@ int mei_wd_stop(struct mei_device *dev, bool preserve)
        } else {
                dev->wd_pending = true;
        }
-       dev->wd_stopped = false;
+
        mutex_unlock(&dev->device_lock);
 
        ret = wait_event_interruptible_timeout(dev->wait_stop_wd,
-                                       dev->wd_stopped, 10 * HZ);
+                                       dev->wd_state == MEI_WD_IDLE,
+                                       msecs_to_jiffies(MEI_WD_STOP_TIMEOUT));
        mutex_lock(&dev->device_lock);
-       if (dev->wd_stopped) {
+       if (dev->wd_state == MEI_WD_IDLE) {
                dev_dbg(&dev->pdev->dev, "wd: stop completed ret=%d.\n", ret);
                ret = 0;
        } else {
@@ -177,9 +178,6 @@ int mei_wd_stop(struct mei_device *dev, bool preserve)
                        "wd: stop failed to complete ret=%d.\n", ret);
        }
 
-       if (preserve)
-               dev->wd_timeout = wd_timeout;
-
 out:
        return ret;
 }
@@ -196,16 +194,16 @@ static int mei_wd_ops_start(struct watchdog_device *wd_dev)
        int err = -ENODEV;
        struct mei_device *dev;
 
-       dev = pci_get_drvdata(mei_device);
+       dev = watchdog_get_drvdata(wd_dev);
        if (!dev)
                return -ENODEV;
 
        mutex_lock(&dev->device_lock);
 
-       if (dev->mei_state != MEI_ENABLED) {
+       if (dev->dev_state != MEI_DEV_ENABLED) {
                dev_dbg(&dev->pdev->dev,
-                       "wd: mei_state != MEI_ENABLED  mei_state = %d\n",
-                       dev->mei_state);
+                       "wd: dev_state != MEI_DEV_ENABLED  dev_state = %s\n",
+                       mei_dev_state_str(dev->dev_state));
                goto end_unlock;
        }
 
@@ -233,13 +231,13 @@ end_unlock:
 static int mei_wd_ops_stop(struct watchdog_device *wd_dev)
 {
        struct mei_device *dev;
-       dev = pci_get_drvdata(mei_device);
 
+       dev = watchdog_get_drvdata(wd_dev);
        if (!dev)
                return -ENODEV;
 
        mutex_lock(&dev->device_lock);
-       mei_wd_stop(dev, false);
+       mei_wd_stop(dev);
        mutex_unlock(&dev->device_lock);
 
        return 0;
@@ -256,8 +254,8 @@ static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
 {
        int ret = 0;
        struct mei_device *dev;
-       dev = pci_get_drvdata(mei_device);
 
+       dev = watchdog_get_drvdata(wd_dev);
        if (!dev)
                return -ENODEV;
 
@@ -269,6 +267,8 @@ static int mei_wd_ops_ping(struct watchdog_device *wd_dev)
                goto end;
        }
 
+       dev->wd_state = MEI_WD_RUNNING;
+
        /* Check if we can send the ping to HW*/
        if (dev->mei_host_buffer_is_empty &&
                mei_flow_ctrl_creds(dev, &dev->wd_cl) > 0) {
@@ -309,13 +309,13 @@ end:
 static int mei_wd_ops_set_timeout(struct watchdog_device *wd_dev, unsigned int timeout)
 {
        struct mei_device *dev;
-       dev = pci_get_drvdata(mei_device);
 
+       dev = watchdog_get_drvdata(wd_dev);
        if (!dev)
                return -ENODEV;
 
        /* Check Timeout value */
-       if (timeout < AMT_WD_MIN_TIMEOUT || timeout > AMT_WD_MAX_TIMEOUT)
+       if (timeout < MEI_WD_MIN_TIMEOUT || timeout > MEI_WD_MAX_TIMEOUT)
                return -EINVAL;
 
        mutex_lock(&dev->device_lock);
@@ -341,37 +341,42 @@ static const struct watchdog_ops wd_ops = {
 };
 static const struct watchdog_info wd_info = {
                .identity = INTEL_AMT_WATCHDOG_ID,
-               .options = WDIOF_KEEPALIVEPING | WDIOF_ALARMONLY,
+               .options = WDIOF_KEEPALIVEPING |
+                          WDIOF_SETTIMEOUT |
+                          WDIOF_ALARMONLY,
 };
 
 static struct watchdog_device amt_wd_dev = {
                .info = &wd_info,
                .ops = &wd_ops,
-               .timeout = AMT_WD_DEFAULT_TIMEOUT,
-               .min_timeout = AMT_WD_MIN_TIMEOUT,
-               .max_timeout = AMT_WD_MAX_TIMEOUT,
+               .timeout = MEI_WD_DEFAULT_TIMEOUT,
+               .min_timeout = MEI_WD_MIN_TIMEOUT,
+               .max_timeout = MEI_WD_MAX_TIMEOUT,
 };
 
 
-void  mei_watchdog_register(struct mei_device *dev)
+void mei_watchdog_register(struct mei_device *dev)
 {
-       dev_dbg(&dev->pdev->dev, "dev->wd_timeout =%d.\n", dev->wd_timeout);
-
        if (watchdog_register_device(&amt_wd_dev)) {
                dev_err(&dev->pdev->dev,
                        "wd: unable to register watchdog device.\n");
                dev->wd_interface_reg = false;
-       } else {
-               dev_dbg(&dev->pdev->dev,
-                       "wd: successfully register watchdog interface.\n");
-               dev->wd_interface_reg = true;
+               return;
        }
+
+       dev_dbg(&dev->pdev->dev,
+               "wd: successfully register watchdog interface.\n");
+       dev->wd_interface_reg = true;
+       watchdog_set_drvdata(&amt_wd_dev, dev);
 }
 
 void mei_watchdog_unregister(struct mei_device *dev)
 {
-       if (dev->wd_interface_reg)
-               watchdog_unregister_device(&amt_wd_dev);
+       if (!dev->wd_interface_reg)
+               return;
+
+       watchdog_set_drvdata(&amt_wd_dev, NULL);
+       watchdog_unregister_device(&amt_wd_dev);
        dev->wd_interface_reg = false;
 }
 
index 9fbcacd703d502b660f5491a706e06fdd9952f2f..c9f20dae18557deb40f9ed55e9aebae6e4992222 100644 (file)
@@ -699,7 +699,7 @@ static int __devinit pch_phub_probe(struct pci_dev *pdev,
        chip->pch_phub_base_address = pci_iomap(pdev, 1, 0);
 
 
-       if (chip->pch_phub_base_address == 0) {
+       if (chip->pch_phub_base_address == NULL) {
                dev_err(&pdev->dev, "%s : pci_iomap FAILED", __func__);
                ret = -ENOMEM;
                goto err_pci_iomap;
@@ -893,18 +893,7 @@ static struct pci_driver pch_phub_driver = {
        .resume = pch_phub_resume
 };
 
-static int __init pch_phub_pci_init(void)
-{
-       return pci_register_driver(&pch_phub_driver);
-}
-
-static void __exit pch_phub_pci_exit(void)
-{
-       pci_unregister_driver(&pch_phub_driver);
-}
-
-module_init(pch_phub_pci_init);
-module_exit(pch_phub_pci_exit);
+module_pci_driver(pch_phub_driver);
 
 MODULE_DESCRIPTION("Intel EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7223) PHUB");
 MODULE_LICENSE("GPL");
index b7eb545394b1c0c2e3d01aa50d29829af90619e6..4999b34b7a6015c7f7cd66347a26037812100553 100644 (file)
@@ -60,7 +60,7 @@ struct pti_tty {
 };
 
 struct pti_dev {
-       struct tty_port port;
+       struct tty_port port[PTITTY_MINOR_NUM];
        unsigned long pti_addr;
        unsigned long aperture_base;
        void __iomem *pti_ioaddr;
@@ -76,7 +76,7 @@ struct pti_dev {
  */
 static DEFINE_MUTEX(alloclock);
 
-static struct pci_device_id pci_ids[] __devinitconst = {
+static const struct pci_device_id pci_ids[] __devinitconst = {
                {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x82B)},
                {0}
 };
@@ -393,25 +393,6 @@ void pti_writedata(struct pti_masterchannel *mc, u8 *buf, int count)
 }
 EXPORT_SYMBOL_GPL(pti_writedata);
 
-/**
- * pti_pci_remove()- Driver exit method to remove PTI from
- *                PCI bus.
- * @pdev: variable containing pci info of PTI.
- */
-static void __devexit pti_pci_remove(struct pci_dev *pdev)
-{
-       struct pti_dev *drv_data;
-
-       drv_data = pci_get_drvdata(pdev);
-       if (drv_data != NULL) {
-               pci_iounmap(pdev, drv_data->pti_ioaddr);
-               pci_set_drvdata(pdev, NULL);
-               kfree(drv_data);
-               pci_release_region(pdev, 1);
-               pci_disable_device(pdev);
-       }
-}
-
 /*
  * for the tty_driver_*() basic function descriptions, see tty_driver.h.
  * Specific header comments made for PTI-related specifics.
@@ -446,7 +427,7 @@ static int pti_tty_driver_open(struct tty_struct *tty, struct file *filp)
         * also removes a locking requirement for the actual write
         * procedure.
         */
-       return tty_port_open(&drv_data->port, tty, filp);
+       return tty_port_open(tty->port, tty, filp);
 }
 
 /**
@@ -462,7 +443,7 @@ static int pti_tty_driver_open(struct tty_struct *tty, struct file *filp)
  */
 static void pti_tty_driver_close(struct tty_struct *tty, struct file *filp)
 {
-       tty_port_close(&drv_data->port, tty, filp);
+       tty_port_close(tty->port, tty, filp);
 }
 
 /**
@@ -818,6 +799,7 @@ static const struct tty_port_operations tty_port_ops = {
 static int __devinit pti_pci_probe(struct pci_dev *pdev,
                const struct pci_device_id *ent)
 {
+       unsigned int a;
        int retval = -EINVAL;
        int pci_bar = 1;
 
@@ -830,7 +812,7 @@ static int __devinit pti_pci_probe(struct pci_dev *pdev,
                        __func__, __LINE__);
                pr_err("%s(%d): Error value returned: %d\n",
                        __func__, __LINE__, retval);
-               return retval;
+               goto err;
        }
 
        retval = pci_enable_device(pdev);
@@ -838,17 +820,16 @@ static int __devinit pti_pci_probe(struct pci_dev *pdev,
                dev_err(&pdev->dev,
                        "%s: pci_enable_device() returned error %d\n",
                        __func__, retval);
-               return retval;
+               goto err_unreg_misc;
        }
 
        drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL);
-
        if (drv_data == NULL) {
                retval = -ENOMEM;
                dev_err(&pdev->dev,
                        "%s(%d): kmalloc() returned NULL memory.\n",
                        __func__, __LINE__);
-               return retval;
+               goto err_disable_pci;
        }
        drv_data->pti_addr = pci_resource_start(pdev, pci_bar);
 
@@ -857,33 +838,65 @@ static int __devinit pti_pci_probe(struct pci_dev *pdev,
                dev_err(&pdev->dev,
                        "%s(%d): pci_request_region() returned error %d\n",
                        __func__, __LINE__, retval);
-               kfree(drv_data);
-               return retval;
+               goto err_free_dd;
        }
        drv_data->aperture_base = drv_data->pti_addr+APERTURE_14;
        drv_data->pti_ioaddr =
                ioremap_nocache((u32)drv_data->aperture_base,
                APERTURE_LEN);
        if (!drv_data->pti_ioaddr) {
-               pci_release_region(pdev, pci_bar);
                retval = -ENOMEM;
-               kfree(drv_data);
-               return retval;
+               goto err_rel_reg;
        }
 
        pci_set_drvdata(pdev, drv_data);
 
-       tty_port_init(&drv_data->port);
-       drv_data->port.ops = &tty_port_ops;
+       for (a = 0; a < PTITTY_MINOR_NUM; a++) {
+               struct tty_port *port = &drv_data->port[a];
+               tty_port_init(port);
+               port->ops = &tty_port_ops;
 
-       tty_register_device(pti_tty_driver, 0, &pdev->dev);
-       tty_register_device(pti_tty_driver, 1, &pdev->dev);
+               tty_port_register_device(port, pti_tty_driver, a, &pdev->dev);
+       }
 
        register_console(&pti_console);
 
+       return 0;
+err_rel_reg:
+       pci_release_region(pdev, pci_bar);
+err_free_dd:
+       kfree(drv_data);
+err_disable_pci:
+       pci_disable_device(pdev);
+err_unreg_misc:
+       misc_deregister(&pti_char_driver);
+err:
        return retval;
 }
 
+/**
+ * pti_pci_remove()- Driver exit method to remove PTI from
+ *                PCI bus.
+ * @pdev: variable containing pci info of PTI.
+ */
+static void __devexit pti_pci_remove(struct pci_dev *pdev)
+{
+       struct pti_dev *drv_data = pci_get_drvdata(pdev);
+
+       unregister_console(&pti_console);
+
+       tty_unregister_device(pti_tty_driver, 0);
+       tty_unregister_device(pti_tty_driver, 1);
+
+       iounmap(drv_data->pti_ioaddr);
+       pci_set_drvdata(pdev, NULL);
+       kfree(drv_data);
+       pci_release_region(pdev, 1);
+       pci_disable_device(pdev);
+
+       misc_deregister(&pti_char_driver);
+}
+
 static struct pci_driver pti_pci_driver = {
        .name           = PCINAME,
        .id_table       = pci_ids,
@@ -933,25 +946,24 @@ static int __init pti_init(void)
                pr_err("%s(%d): Error value returned: %d\n",
                        __func__, __LINE__, retval);
 
-               pti_tty_driver = NULL;
-               return retval;
+               goto put_tty;
        }
 
        retval = pci_register_driver(&pti_pci_driver);
-
        if (retval) {
                pr_err("%s(%d): PCI registration failed of pti driver\n",
                        __func__, __LINE__);
                pr_err("%s(%d): Error value returned: %d\n",
                        __func__, __LINE__, retval);
-
-               tty_unregister_driver(pti_tty_driver);
-               pr_err("%s(%d): Unregistering TTY part of pti driver\n",
-                       __func__, __LINE__);
-               pti_tty_driver = NULL;
-               return retval;
+               goto unreg_tty;
        }
 
+       return 0;
+unreg_tty:
+       tty_unregister_driver(pti_tty_driver);
+put_tty:
+       put_tty_driver(pti_tty_driver);
+       pti_tty_driver = NULL;
        return retval;
 }
 
@@ -960,31 +972,9 @@ static int __init pti_init(void)
  */
 static void __exit pti_exit(void)
 {
-       int retval;
-
-       tty_unregister_device(pti_tty_driver, 0);
-       tty_unregister_device(pti_tty_driver, 1);
-
-       retval = tty_unregister_driver(pti_tty_driver);
-       if (retval) {
-               pr_err("%s(%d): TTY unregistration failed of pti driver\n",
-                       __func__, __LINE__);
-               pr_err("%s(%d): Error value returned: %d\n",
-                       __func__, __LINE__, retval);
-       }
-
+       tty_unregister_driver(pti_tty_driver);
        pci_unregister_driver(&pti_pci_driver);
-
-       retval = misc_deregister(&pti_char_driver);
-       if (retval) {
-               pr_err("%s(%d): CHAR unregistration failed of pti driver\n",
-                       __func__, __LINE__);
-               pr_err("%s(%d): Error value returned: %d\n",
-                       __func__, __LINE__, retval);
-       }
-
-       unregister_console(&pti_console);
-       return;
+       put_tty_driver(pti_tty_driver);
 }
 
 module_init(pti_init);
index acfaeeb9e01a98e7f296d5c2081f35ef4d53b325..46937b107261df5fddeb39c6dd16d491e898833e 100644 (file)
 
 #include <linux/ti_wilink_st.h>
 
+extern void st_kim_recv(void *, const unsigned char *, long);
+void st_int_recv(void *, const unsigned char *, long);
 /* function pointer pointing to either,
  * st_kim_recv during registration to receive fw download responses
  * st_int_recv after registration to receive proto stack responses
  */
-void (*st_recv) (void*, const unsigned char*, long);
+static void (*st_recv) (void *, const unsigned char *, long);
 
 /********************************************************************/
 static void add_channel_to_table(struct st_data_s *st_gdata,
@@ -100,7 +102,7 @@ int st_int_write(struct st_data_s *st_gdata,
  * push the skb received to relevant
  * protocol stacks
  */
-void st_send_frame(unsigned char chnl_id, struct st_data_s *st_gdata)
+static void st_send_frame(unsigned char chnl_id, struct st_data_s *st_gdata)
 {
        pr_debug(" %s(prot:%d) ", __func__, chnl_id);
 
@@ -140,7 +142,7 @@ void st_send_frame(unsigned char chnl_id, struct st_data_s *st_gdata)
  * This function is being called with spin lock held, protocol drivers are
  * only expected to complete their waits and do nothing more than that.
  */
-void st_reg_complete(struct st_data_s *st_gdata, char err)
+static void st_reg_complete(struct st_data_s *st_gdata, char err)
 {
        unsigned char i = 0;
        pr_info(" %s ", __func__);
@@ -379,7 +381,7 @@ done:
  *     completely, return that skb which has the pending data.
  *     In normal cases, return top of txq.
  */
-struct sk_buff *st_int_dequeue(struct st_data_s *st_gdata)
+static struct sk_buff *st_int_dequeue(struct st_data_s *st_gdata)
 {
        struct sk_buff *returning_skb;
 
@@ -401,7 +403,7 @@ struct sk_buff *st_int_dequeue(struct st_data_s *st_gdata)
  *     txq and waitq needs protection since the other contexts
  *     may be sending data, waking up chip.
  */
-void st_int_enqueue(struct st_data_s *st_gdata, struct sk_buff *skb)
+static void st_int_enqueue(struct st_data_s *st_gdata, struct sk_buff *skb)
 {
        unsigned long flags = 0;
 
index 7c14f8fd98db2eec7e50c1ad5dff75a0bc90a82f..04a819944f6b4707a50eed443ef17450e9b31b23 100644 (file)
@@ -63,10 +63,27 @@ static struct platform_device *st_get_plat_device(int id)
  *     in case of error don't complete so that waiting for proper
  *     response times out
  */
-void validate_firmware_response(struct kim_data_s *kim_gdata)
+static void validate_firmware_response(struct kim_data_s *kim_gdata)
 {
        struct sk_buff *skb = kim_gdata->rx_skb;
-       if (unlikely(skb->data[5] != 0)) {
+       if (!skb)
+               return;
+
+       /* these magic numbers are the position in the response buffer which
+        * allows us to distinguish whether the response is for the read
+        * version info. command
+        */
+       if (skb->data[2] == 0x01 && skb->data[3] == 0x01 &&
+                       skb->data[4] == 0x10 && skb->data[5] == 0x00) {
+               /* fw version response */
+               memcpy(kim_gdata->resp_buffer,
+                               kim_gdata->rx_skb->data,
+                               kim_gdata->rx_skb->len);
+               complete_all(&kim_gdata->kim_rcvd);
+               kim_gdata->rx_state = ST_W4_PACKET_TYPE;
+               kim_gdata->rx_skb = NULL;
+               kim_gdata->rx_count = 0;
+       } else if (unlikely(skb->data[5] != 0)) {
                pr_err("no proper response during fw download");
                pr_err("data6 %x", skb->data[5]);
                kfree_skb(skb);
@@ -119,7 +136,7 @@ static inline int kim_check_data_len(struct kim_data_s *kim_gdata, int len)
  *     have been observed to come in bursts of different
  *     tty_receive and hence the logic
  */
-void kim_int_recv(struct kim_data_s *kim_gdata,
+static void kim_int_recv(struct kim_data_s *kim_gdata,
        const unsigned char *data, long count)
 {
        const unsigned char *ptr;
@@ -207,16 +224,19 @@ static long read_local_version(struct kim_data_s *kim_gdata, char *bts_scr_name)
                return -EIO;
        }
 
-       if (!wait_for_completion_timeout
-           (&kim_gdata->kim_rcvd, msecs_to_jiffies(CMD_RESP_TIME))) {
+       if (!wait_for_completion_interruptible_timeout(
+               &kim_gdata->kim_rcvd, msecs_to_jiffies(CMD_RESP_TIME))) {
                pr_err(" waiting for ver info- timed out ");
                return -ETIMEDOUT;
        }
        INIT_COMPLETION(kim_gdata->kim_rcvd);
+       /* the positions 12 & 13 in the response buffer provide with the
+        * chip, major & minor numbers
+        */
 
        version =
-               MAKEWORD(kim_gdata->resp_buffer[13],
-                               kim_gdata->resp_buffer[14]);
+               MAKEWORD(kim_gdata->resp_buffer[12],
+                               kim_gdata->resp_buffer[13]);
        chip = (version & 0x7C00) >> 10;
        min_ver = (version & 0x007F);
        maj_ver = (version & 0x0380) >> 7;
@@ -236,7 +256,7 @@ static long read_local_version(struct kim_data_s *kim_gdata, char *bts_scr_name)
        return 0;
 }
 
-void skip_change_remote_baud(unsigned char **ptr, long *len)
+static void skip_change_remote_baud(unsigned char **ptr, long *len)
 {
        unsigned char *nxt_action, *cur_action;
        cur_action = *ptr;
@@ -370,9 +390,9 @@ static long download_firmware(struct kim_data_s *kim_gdata)
                        break;
                case ACTION_WAIT_EVENT:  /* wait */
                        pr_debug("W");
-                       if (!wait_for_completion_timeout
-                                       (&kim_gdata->kim_rcvd,
-                                        msecs_to_jiffies(CMD_RESP_TIME))) {
+                       if (!wait_for_completion_interruptible_timeout(
+                                       &kim_gdata->kim_rcvd,
+                                       msecs_to_jiffies(CMD_RESP_TIME))) {
                                pr_err("response timeout during fw download ");
                                /* timed out */
                                release_firmware(kim_gdata->fw_entry);
@@ -410,16 +430,10 @@ void st_kim_recv(void *disc_data, const unsigned char *data, long count)
        struct st_data_s        *st_gdata = (struct st_data_s *)disc_data;
        struct kim_data_s       *kim_gdata = st_gdata->kim_data;
 
-       /* copy to local buffer */
-       if (unlikely(data[4] == 0x01 && data[5] == 0x10 && data[0] == 0x04)) {
-               /* must be the read_ver_cmd */
-               memcpy(kim_gdata->resp_buffer, data, count);
-               complete_all(&kim_gdata->kim_rcvd);
-               return;
-       } else {
-               kim_int_recv(kim_gdata, data, count);
-               /* either completes or times out */
-       }
+       /* proceed to gather all data and distinguish read fw version response
+        * from other fw responses when data gathering is complete
+        */
+       kim_int_recv(kim_gdata, data, count);
        return;
 }
 
@@ -454,11 +468,6 @@ 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 */
@@ -467,8 +476,8 @@ long st_kim_start(void *kim_data)
                sysfs_notify(&kim_gdata->kim_pdev->dev.kobj,
                                NULL, "install");
                /* wait for ldisc to be installed */
-               err = wait_for_completion_timeout(&kim_gdata->ldisc_installed,
-                               msecs_to_jiffies(LDISC_TIME));
+               err = wait_for_completion_interruptible_timeout(
+                       &kim_gdata->ldisc_installed, msecs_to_jiffies(LDISC_TIME));
                if (!err) {
                        /* ldisc installation timeout,
                         * flush uart, power cycle BT_EN */
@@ -500,8 +509,7 @@ 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) reset BT_EN - pull down nshutdown at the end.
- *     (d) invoke platform's chip disabling routine.
+ *     (c) invoke platform's chip disabling routine.
  */
 long st_kim_stop(void *kim_data)
 {
@@ -526,20 +534,13 @@ long st_kim_stop(void *kim_data)
        sysfs_notify(&kim_gdata->kim_pdev->dev.kobj, NULL, "install");
 
        /* wait for ldisc to be un-installed */
-       err = wait_for_completion_timeout(&kim_gdata->ldisc_installed,
-                       msecs_to_jiffies(LDISC_TIME));
+       err = wait_for_completion_interruptible_timeout(
+               &kim_gdata->ldisc_installed, msecs_to_jiffies(LDISC_TIME));
        if (!err) {             /* timeout */
                pr_err(" timed out waiting for ldisc to be un-installed");
-               return -ETIMEDOUT;
+               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);
@@ -701,7 +702,7 @@ static const struct file_operations list_debugfs_fops = {
  * board-*.c file
  */
 
-struct dentry *kim_debugfs_dir;
+static struct dentry *kim_debugfs_dir;
 static int kim_probe(struct platform_device *pdev)
 {
        long status;
@@ -731,20 +732,6 @@ 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;
-       status = gpio_request(kim_gdata->nshutdown, "kim");
-       if (unlikely(status)) {
-               pr_err(" gpio %ld request failed ", kim_gdata->nshutdown);
-               return status;
-       }
-
-       /* Configure nShutdown GPIO as output=0 */
-       status = gpio_direction_output(kim_gdata->nshutdown, 0);
-       if (unlikely(status)) {
-               pr_err(" unable to configure gpio %ld", kim_gdata->nshutdown);
-               return status;
-       }
        /* get reference of pdev for request_firmware
         */
        kim_gdata->kim_pdev = pdev;
@@ -780,18 +767,10 @@ static int kim_probe(struct platform_device *pdev)
 
 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");
@@ -804,7 +783,7 @@ static int kim_remove(struct platform_device *pdev)
        return 0;
 }
 
-int kim_suspend(struct platform_device *pdev, pm_message_t state)
+static int kim_suspend(struct platform_device *pdev, pm_message_t state)
 {
        struct ti_st_plat_data  *pdata = pdev->dev.platform_data;
 
@@ -814,7 +793,7 @@ int kim_suspend(struct platform_device *pdev, pm_message_t state)
        return -EOPNOTSUPP;
 }
 
-int kim_resume(struct platform_device *pdev)
+static int kim_resume(struct platform_device *pdev)
 {
        struct ti_st_plat_data  *pdata = pdev->dev.platform_data;
 
index 1ff460a8e9c74f67e584d634016fa25332fd351c..93b4d67cc4a3a6bc30197acf709d4f73faaad070 100644 (file)
@@ -87,7 +87,7 @@ static void ll_device_want_to_wakeup(struct st_data_s *st_data)
        /* communicate to platform about chip wakeup */
        kim_data = st_data->kim_data;
        pdata = kim_data->kim_pdev->dev.platform_data;
-       if (pdata->chip_asleep)
+       if (pdata->chip_awake)
                pdata->chip_awake(NULL);
 }
 
index 5a2cbfac66d23b3197ea548df65b59c8b5f2bbcf..d2339ea378152070ce8496e25f1dc15f0cbe9f14 100644 (file)
@@ -518,7 +518,7 @@ static void sdio_uart_check_modem_status(struct sdio_uart_port *port)
        if (status & UART_MSR_DCTS) {
                port->icount.cts++;
                tty = tty_port_tty_get(&port->port);
-               if (tty && (tty->termios->c_cflag & CRTSCTS)) {
+               if (tty && (tty->termios.c_cflag & CRTSCTS)) {
                        int cts = (status & UART_MSR_CTS);
                        if (tty->hw_stopped) {
                                if (cts) {
@@ -671,12 +671,12 @@ static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty)
        port->ier = UART_IER_RLSI|UART_IER_RDI|UART_IER_RTOIE|UART_IER_UUE;
        port->mctrl = TIOCM_OUT2;
 
-       sdio_uart_change_speed(port, tty->termios, NULL);
+       sdio_uart_change_speed(port, &tty->termios, NULL);
 
-       if (tty->termios->c_cflag & CBAUD)
+       if (tty->termios.c_cflag & CBAUD)
                sdio_uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR);
 
-       if (tty->termios->c_cflag & CRTSCTS)
+       if (tty->termios.c_cflag & CRTSCTS)
                if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS))
                        tty->hw_stopped = 1;
 
@@ -850,7 +850,7 @@ static void sdio_uart_throttle(struct tty_struct *tty)
 {
        struct sdio_uart_port *port = tty->driver_data;
 
-       if (!I_IXOFF(tty) && !(tty->termios->c_cflag & CRTSCTS))
+       if (!I_IXOFF(tty) && !(tty->termios.c_cflag & CRTSCTS))
                return;
 
        if (sdio_uart_claim_func(port) != 0)
@@ -861,7 +861,7 @@ static void sdio_uart_throttle(struct tty_struct *tty)
                sdio_uart_start_tx(port);
        }
 
-       if (tty->termios->c_cflag & CRTSCTS)
+       if (tty->termios.c_cflag & CRTSCTS)
                sdio_uart_clear_mctrl(port, TIOCM_RTS);
 
        sdio_uart_irq(port->func);
@@ -872,7 +872,7 @@ static void sdio_uart_unthrottle(struct tty_struct *tty)
 {
        struct sdio_uart_port *port = tty->driver_data;
 
-       if (!I_IXOFF(tty) && !(tty->termios->c_cflag & CRTSCTS))
+       if (!I_IXOFF(tty) && !(tty->termios.c_cflag & CRTSCTS))
                return;
 
        if (sdio_uart_claim_func(port) != 0)
@@ -887,7 +887,7 @@ static void sdio_uart_unthrottle(struct tty_struct *tty)
                }
        }
 
-       if (tty->termios->c_cflag & CRTSCTS)
+       if (tty->termios.c_cflag & CRTSCTS)
                sdio_uart_set_mctrl(port, TIOCM_RTS);
 
        sdio_uart_irq(port->func);
@@ -898,12 +898,12 @@ static void sdio_uart_set_termios(struct tty_struct *tty,
                                                struct ktermios *old_termios)
 {
        struct sdio_uart_port *port = tty->driver_data;
-       unsigned int cflag = tty->termios->c_cflag;
+       unsigned int cflag = tty->termios.c_cflag;
 
        if (sdio_uart_claim_func(port) != 0)
                return;
 
-       sdio_uart_change_speed(port, tty->termios, old_termios);
+       sdio_uart_change_speed(port, &tty->termios, old_termios);
 
        /* Handle transition to B0 status */
        if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD))
@@ -1132,8 +1132,8 @@ static int sdio_uart_probe(struct sdio_func *func,
                kfree(port);
        } else {
                struct device *dev;
-               dev = tty_register_device(sdio_uart_tty_driver,
-                                               port->index, &func->dev);
+               dev = tty_port_register_device(&port->port,
+                               sdio_uart_tty_driver, port->index, &func->dev);
                if (IS_ERR(dev)) {
                        sdio_uart_port_remove(port);
                        ret = PTR_ERR(dev);
index 322412cec4eeb8ca6970d2d12f37c7c83bbba42e..8c72828239b21fb6064ac076a6759052bdb6dd1c 100644 (file)
@@ -19,6 +19,9 @@
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
 #include <linux/platform_device.h>
 #include <linux/scatterlist.h>
 #include <linux/seq_file.h>
@@ -81,6 +84,7 @@ struct atmel_mci_caps {
        bool    has_bad_data_ordering;
        bool    need_reset_after_xfer;
        bool    need_blksz_mul_4;
+       bool    need_notbusy_for_read_ops;
 };
 
 struct atmel_mci_dma {
@@ -499,6 +503,70 @@ err:
        dev_err(&mmc->class_dev, "failed to initialize debugfs for slot\n");
 }
 
+#if defined(CONFIG_OF)
+static const struct of_device_id atmci_dt_ids[] = {
+       { .compatible = "atmel,hsmci" },
+       { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, atmci_dt_ids);
+
+static struct mci_platform_data __devinit*
+atmci_of_init(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct device_node *cnp;
+       struct mci_platform_data *pdata;
+       u32 slot_id;
+
+       if (!np) {
+               dev_err(&pdev->dev, "device node not found\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata) {
+               dev_err(&pdev->dev, "could not allocate memory for pdata\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       for_each_child_of_node(np, cnp) {
+               if (of_property_read_u32(cnp, "reg", &slot_id)) {
+                       dev_warn(&pdev->dev, "reg property is missing for %s\n",
+                                cnp->full_name);
+                       continue;
+               }
+
+               if (slot_id >= ATMCI_MAX_NR_SLOTS) {
+                       dev_warn(&pdev->dev, "can't have more than %d slots\n",
+                                ATMCI_MAX_NR_SLOTS);
+                       break;
+               }
+
+               if (of_property_read_u32(cnp, "bus-width",
+                                        &pdata->slot[slot_id].bus_width))
+                       pdata->slot[slot_id].bus_width = 1;
+
+               pdata->slot[slot_id].detect_pin =
+                       of_get_named_gpio(cnp, "cd-gpios", 0);
+
+               pdata->slot[slot_id].detect_is_active_high =
+                       of_property_read_bool(cnp, "cd-inverted");
+
+               pdata->slot[slot_id].wp_pin =
+                       of_get_named_gpio(cnp, "wp-gpios", 0);
+       }
+
+       return pdata;
+}
+#else /* CONFIG_OF */
+static inline struct mci_platform_data*
+atmci_of_init(struct platform_device *dev)
+{
+       return ERR_PTR(-EINVAL);
+}
+#endif
+
 static inline unsigned int atmci_get_version(struct atmel_mci *host)
 {
        return atmci_readl(host, ATMCI_VERSION) & 0x00000fff;
@@ -1625,7 +1693,8 @@ static void atmci_tasklet_func(unsigned long priv)
                                __func__);
                        atmci_set_completed(host, EVENT_XFER_COMPLETE);
 
-                       if (host->data->flags & MMC_DATA_WRITE) {
+                       if (host->caps.need_notbusy_for_read_ops ||
+                          (host->data->flags & MMC_DATA_WRITE)) {
                                atmci_writel(host, ATMCI_IER, ATMCI_NOTBUSY);
                                state = STATE_WAITING_NOTBUSY;
                        } else if (host->mrq->stop) {
@@ -2044,6 +2113,13 @@ static int __init atmci_init_slot(struct atmel_mci *host,
        slot->sdc_reg = sdc_reg;
        slot->sdio_irq = sdio_irq;
 
+       dev_dbg(&mmc->class_dev,
+               "slot[%u]: bus_width=%u, detect_pin=%d, "
+               "detect_is_active_high=%s, wp_pin=%d\n",
+               id, slot_data->bus_width, slot_data->detect_pin,
+               slot_data->detect_is_active_high ? "true" : "false",
+               slot_data->wp_pin);
+
        mmc->ops = &atmci_ops;
        mmc->f_min = DIV_ROUND_UP(host->bus_hz, 512);
        mmc->f_max = host->bus_hz / 2;
@@ -2218,6 +2294,7 @@ static void __init atmci_get_cap(struct atmel_mci *host)
        host->caps.has_bad_data_ordering = 1;
        host->caps.need_reset_after_xfer = 1;
        host->caps.need_blksz_mul_4 = 1;
+       host->caps.need_notbusy_for_read_ops = 0;
 
        /* keep only major version number */
        switch (version & 0xf00) {
@@ -2238,6 +2315,7 @@ static void __init atmci_get_cap(struct atmel_mci *host)
        case 0x200:
                host->caps.has_rwproof = 1;
                host->caps.need_blksz_mul_4 = 0;
+               host->caps.need_notbusy_for_read_ops = 1;
        case 0x100:
                host->caps.has_bad_data_ordering = 0;
                host->caps.need_reset_after_xfer = 0;
@@ -2264,8 +2342,14 @@ static int __init atmci_probe(struct platform_device *pdev)
        if (!regs)
                return -ENXIO;
        pdata = pdev->dev.platform_data;
-       if (!pdata)
-               return -ENXIO;
+       if (!pdata) {
+               pdata = atmci_of_init(pdev);
+               if (IS_ERR(pdata)) {
+                       dev_err(&pdev->dev, "platform data not available\n");
+                       return PTR_ERR(pdata);
+               }
+       }
+
        irq = platform_get_irq(pdev, 0);
        if (irq < 0)
                return irq;
@@ -2483,6 +2567,7 @@ static struct platform_driver atmci_driver = {
        .driver         = {
                .name           = "atmel_mci",
                .pm             = ATMCI_PM_OPS,
+               .of_match_table = of_match_ptr(atmci_dt_ids),
        },
 };
 
index 03666174ca483e61a351626ad428a9bc833ef981..b9b463eca1ec64a2d608f3362ede48cd418842b6 100644 (file)
@@ -24,9 +24,7 @@
 #include <asm/portmux.h>
 #include <asm/bfin_sdh.h>
 
-#if defined(CONFIG_BF51x)
-#define bfin_read_SDH_PWR_CTL          bfin_read_RSI_PWR_CTL
-#define bfin_write_SDH_PWR_CTL         bfin_write_RSI_PWR_CTL
+#if defined(CONFIG_BF51x) || defined(__ADSPBF60x__)
 #define bfin_read_SDH_CLK_CTL          bfin_read_RSI_CLK_CTL
 #define bfin_write_SDH_CLK_CTL         bfin_write_RSI_CLK_CTL
 #define bfin_write_SDH_ARGUMENT                bfin_write_RSI_ARGUMENT
 #define bfin_write_SDH_E_STATUS                bfin_write_RSI_E_STATUS
 #define bfin_read_SDH_STATUS           bfin_read_RSI_STATUS
 #define bfin_write_SDH_MASK0           bfin_write_RSI_MASK0
+#define bfin_write_SDH_E_MASK          bfin_write_RSI_E_MASK
 #define bfin_read_SDH_CFG              bfin_read_RSI_CFG
 #define bfin_write_SDH_CFG             bfin_write_RSI_CFG
+# if defined(__ADSPBF60x__)
+#  define bfin_read_SDH_BLK_SIZE       bfin_read_RSI_BLKSZ
+#  define bfin_write_SDH_BLK_SIZE      bfin_write_RSI_BLKSZ
+# else
+#  define bfin_read_SDH_PWR_CTL                bfin_read_RSI_PWR_CTL
+#  define bfin_write_SDH_PWR_CTL       bfin_write_RSI_PWR_CTL
+# endif
 #endif
 
-struct dma_desc_array {
-       unsigned long   start_addr;
-       unsigned short  cfg;
-       unsigned short  x_count;
-       short           x_modify;
-} __packed;
-
 struct sdh_host {
        struct mmc_host         *mmc;
        spinlock_t              lock;
@@ -69,6 +68,7 @@ struct sdh_host {
        dma_addr_t              sg_dma;
        int                     dma_len;
 
+       unsigned long           sclk;
        unsigned int            imask;
        unsigned int            power_mode;
        unsigned int            clk_div;
@@ -134,11 +134,15 @@ static int sdh_setup_data(struct sdh_host *host, struct mmc_data *data)
        /* Only supports power-of-2 block size */
        if (data->blksz & (data->blksz - 1))
                return -EINVAL;
+#ifndef RSI_BLKSZ
        data_ctl |= ((ffs(data->blksz) - 1) << 4);
+#else
+        bfin_write_SDH_BLK_SIZE(data->blksz);
+#endif
 
        bfin_write_SDH_DATA_CTL(data_ctl);
        /* the time of a host clock period in ns */
-       cycle_ns = 1000000000 / (get_sclk() / (2 * (host->clk_div + 1)));
+       cycle_ns = 1000000000 / (host->sclk / (2 * (host->clk_div + 1)));
        timeout = data->timeout_ns / cycle_ns;
        timeout += data->timeout_clks;
        bfin_write_SDH_DATA_TIMER(timeout);
@@ -152,8 +156,13 @@ static int sdh_setup_data(struct sdh_host *host, struct mmc_data *data)
 
        sdh_enable_stat_irq(host, (DAT_CRC_FAIL | DAT_TIME_OUT | DAT_END));
        host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, host->dma_dir);
-#if defined(CONFIG_BF54x)
-       dma_cfg |= DMAFLOW_ARRAY | NDSIZE_5 | RESTART | WDSIZE_32 | DMAEN;
+#if defined(CONFIG_BF54x) || defined(CONFIG_BF60x)
+       dma_cfg |= DMAFLOW_ARRAY | RESTART | WDSIZE_32 | DMAEN;
+# ifdef RSI_BLKSZ
+       dma_cfg |= PSIZE_32 | NDSIZE_3;
+# else
+       dma_cfg |= NDSIZE_5;
+# endif
        {
                struct scatterlist *sg;
                int i;
@@ -163,7 +172,7 @@ static int sdh_setup_data(struct sdh_host *host, struct mmc_data *data)
                        host->sg_cpu[i].x_count = sg_dma_len(sg) / 4;
                        host->sg_cpu[i].x_modify = 4;
                        dev_dbg(mmc_dev(host->mmc), "%d: start_addr:0x%lx, "
-                               "cfg:0x%x, x_count:0x%x, x_modify:0x%x\n",
+                               "cfg:0x%lx, x_count:0x%lx, x_modify:0x%lx\n",
                                i, host->sg_cpu[i].start_addr,
                                host->sg_cpu[i].cfg, host->sg_cpu[i].x_count,
                                host->sg_cpu[i].x_modify);
@@ -179,6 +188,7 @@ static int sdh_setup_data(struct sdh_host *host, struct mmc_data *data)
        set_dma_curr_desc_addr(host->dma_ch, (unsigned long *)host->sg_dma);
        set_dma_x_count(host->dma_ch, 0);
        set_dma_x_modify(host->dma_ch, 0);
+       SSYNC();
        set_dma_config(host->dma_ch, dma_cfg);
 #elif defined(CONFIG_BF51x)
        /* RSI DMA doesn't work in array mode */
@@ -186,6 +196,7 @@ static int sdh_setup_data(struct sdh_host *host, struct mmc_data *data)
        set_dma_start_addr(host->dma_ch, sg_dma_address(&data->sg[0]));
        set_dma_x_count(host->dma_ch, length / 4);
        set_dma_x_modify(host->dma_ch, 4);
+       SSYNC();
        set_dma_config(host->dma_ch, dma_cfg);
 #endif
        bfin_write_SDH_DATA_CTL(bfin_read_SDH_DATA_CTL() | DTX_DMA_E | DTX_E);
@@ -303,7 +314,6 @@ static int sdh_data_done(struct sdh_host *host, unsigned int stat)
        else
                data->bytes_xfered = 0;
 
-       sdh_disable_stat_irq(host, DAT_END | DAT_TIME_OUT | DAT_CRC_FAIL | RX_OVERRUN | TX_UNDERRUN);
        bfin_write_SDH_STATUS_CLR(DAT_END_STAT | DAT_TIMEOUT_STAT | \
                        DAT_CRC_FAIL_STAT | DAT_BLK_END_STAT | RX_OVERRUN | TX_UNDERRUN);
        bfin_write_SDH_DATA_CTL(0);
@@ -328,74 +338,115 @@ static void sdh_request(struct mmc_host *mmc, struct mmc_request *mrq)
        dev_dbg(mmc_dev(host->mmc), "%s enter, mrp:%p, cmd:%p\n", __func__, mrq, mrq->cmd);
        WARN_ON(host->mrq != NULL);
 
+       spin_lock(&host->lock);
        host->mrq = mrq;
        host->data = mrq->data;
 
        if (mrq->data && mrq->data->flags & MMC_DATA_READ) {
                ret = sdh_setup_data(host, mrq->data);
                if (ret)
-                       return;
+                       goto data_err;
        }
 
        sdh_start_cmd(host, mrq->cmd);
+data_err:
+       spin_unlock(&host->lock);
 }
 
 static void sdh_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 {
        struct sdh_host *host;
-       unsigned long flags;
        u16 clk_ctl = 0;
+#ifndef RSI_BLKSZ
        u16 pwr_ctl = 0;
+#endif
        u16 cfg;
        host = mmc_priv(mmc);
 
-       spin_lock_irqsave(&host->lock, flags);
-       if (ios->clock) {
-               unsigned long  sys_clk, ios_clk;
-               unsigned char clk_div;
-               ios_clk = 2 * ios->clock;
-               sys_clk = get_sclk();
-               clk_div = sys_clk / ios_clk;
-               if (sys_clk % ios_clk == 0)
-                       clk_div -= 1;
-               clk_div = min_t(unsigned char, clk_div, 0xFF);
-               clk_ctl |= clk_div;
-               clk_ctl |= CLK_E;
-               host->clk_div = clk_div;
-       } else
-               sdh_stop_clock(host);
-
-       if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
-#ifdef CONFIG_SDH_BFIN_MISSING_CMD_PULLUP_WORKAROUND
-               pwr_ctl |= ROD_CTL;
-#else
-               pwr_ctl |= SD_CMD_OD | ROD_CTL;
-#endif
+       spin_lock(&host->lock);
 
-       if (ios->bus_width == MMC_BUS_WIDTH_4) {
-               cfg = bfin_read_SDH_CFG();
+       cfg = bfin_read_SDH_CFG();
+       cfg |= MWE;
+       switch (ios->bus_width) {
+       case MMC_BUS_WIDTH_4:
+#ifndef RSI_BLKSZ
                cfg &= ~PD_SDDAT3;
+#endif
                cfg |= PUP_SDDAT3;
                /* Enable 4 bit SDIO */
-               cfg |= (SD4E | MWE);
-               bfin_write_SDH_CFG(cfg);
-               clk_ctl |= WIDE_BUS;
-       } else {
-               cfg = bfin_read_SDH_CFG();
-               cfg |= MWE;
-               bfin_write_SDH_CFG(cfg);
+               cfg |= SD4E;
+               clk_ctl |= WIDE_BUS_4;
+               break;
+       case MMC_BUS_WIDTH_8:
+#ifndef RSI_BLKSZ
+               cfg &= ~PD_SDDAT3;
+#endif
+               cfg |= PUP_SDDAT3;
+               /* Disable 4 bit SDIO */
+               cfg &= ~SD4E;
+               clk_ctl |= BYTE_BUS_8;
+               break;
+       default:
+               cfg &= ~PUP_SDDAT3;
+               /* Disable 4 bit SDIO */
+               cfg &= ~SD4E;
        }
 
-       bfin_write_SDH_CLK_CTL(clk_ctl);
-
        host->power_mode = ios->power_mode;
-       if (ios->power_mode == MMC_POWER_ON)
+#ifndef RSI_BLKSZ
+       if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN) {
+               pwr_ctl |= ROD_CTL;
+# ifndef CONFIG_SDH_BFIN_MISSING_CMD_PULLUP_WORKAROUND
+               pwr_ctl |= SD_CMD_OD;
+# endif
+       }
+
+       if (ios->power_mode != MMC_POWER_OFF)
                pwr_ctl |= PWR_ON;
+       else
+               pwr_ctl &= ~PWR_ON;
 
        bfin_write_SDH_PWR_CTL(pwr_ctl);
+#else
+# ifndef CONFIG_SDH_BFIN_MISSING_CMD_PULLUP_WORKAROUND
+       if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
+               cfg |= SD_CMD_OD;
+       else
+               cfg &= ~SD_CMD_OD;
+# endif
+
+
+       if (ios->power_mode != MMC_POWER_OFF)
+               cfg |= PWR_ON;
+       else
+               cfg &= ~PWR_ON;
+
+       bfin_write_SDH_CFG(cfg);
+#endif
        SSYNC();
 
-       spin_unlock_irqrestore(&host->lock, flags);
+       if (ios->power_mode == MMC_POWER_ON && ios->clock) {
+               unsigned char clk_div;
+               clk_div = (get_sclk() / ios->clock - 1) / 2;
+               clk_div = min_t(unsigned char, clk_div, 0xFF);
+               clk_ctl |= clk_div;
+               clk_ctl |= CLK_E;
+               host->clk_div = clk_div;
+               bfin_write_SDH_CLK_CTL(clk_ctl);
+
+       } else
+               sdh_stop_clock(host);
+
+       /* set up sdh interrupt mask*/
+       if (ios->power_mode == MMC_POWER_ON)
+               bfin_write_SDH_MASK0(DAT_END | DAT_TIME_OUT | DAT_CRC_FAIL |
+                       RX_OVERRUN | TX_UNDERRUN | CMD_SENT | CMD_RESP_END |
+                       CMD_TIME_OUT | CMD_CRC_FAIL);
+       else
+               bfin_write_SDH_MASK0(0);
+       SSYNC();
+
+       spin_unlock(&host->lock);
 
        dev_dbg(mmc_dev(host->mmc), "SDH: clk_div = 0x%x actual clock:%ld expected clock:%d\n",
                host->clk_div,
@@ -412,7 +463,7 @@ static irqreturn_t sdh_dma_irq(int irq, void *devid)
 {
        struct sdh_host *host = devid;
 
-       dev_dbg(mmc_dev(host->mmc), "%s enter, irq_stat: 0x%04x\n", __func__,
+       dev_dbg(mmc_dev(host->mmc), "%s enter, irq_stat: 0x%04lx\n", __func__,
                get_dma_curr_irqstat(host->dma_ch));
        clear_dma_irqstat(host->dma_ch);
        SSYNC();
@@ -427,6 +478,9 @@ static irqreturn_t sdh_stat_irq(int irq, void *devid)
        int handled = 0;
 
        dev_dbg(mmc_dev(host->mmc), "%s enter\n", __func__);
+
+       spin_lock(&host->lock);
+
        status = bfin_read_SDH_E_STATUS();
        if (status & SD_CARD_DET) {
                mmc_detect_change(host->mmc, 0);
@@ -444,11 +498,30 @@ static irqreturn_t sdh_stat_irq(int irq, void *devid)
        if (status & (DAT_END | DAT_TIME_OUT | DAT_CRC_FAIL | RX_OVERRUN | TX_UNDERRUN))
                handled |= sdh_data_done(host, status);
 
+       spin_unlock(&host->lock);
+
        dev_dbg(mmc_dev(host->mmc), "%s exit\n\n", __func__);
 
        return IRQ_RETVAL(handled);
 }
 
+static void sdh_reset(void)
+{
+#if defined(CONFIG_BF54x)
+       /* Secure Digital Host shares DMA with Nand controller */
+       bfin_write_DMAC1_PERIMUX(bfin_read_DMAC1_PERIMUX() | 0x1);
+#endif
+
+       bfin_write_SDH_CFG(bfin_read_SDH_CFG() | CLKS_EN);
+       SSYNC();
+
+       /* Disable card inserting detection pin. set MMC_CAP_NEEDS_POLL, and
+        * mmc stack will do the detection.
+        */
+       bfin_write_SDH_CFG((bfin_read_SDH_CFG() & 0x1F) | (PUP_SDDAT | PUP_SDDAT3));
+       SSYNC();
+}
+
 static int __devinit sdh_probe(struct platform_device *pdev)
 {
        struct mmc_host *mmc;
@@ -469,8 +542,16 @@ static int __devinit sdh_probe(struct platform_device *pdev)
        }
 
        mmc->ops = &sdh_ops;
-       mmc->max_segs = 32;
+#if defined(CONFIG_BF51x)
+       mmc->max_segs = 1;
+#else
+       mmc->max_segs = PAGE_SIZE / sizeof(struct dma_desc_array);
+#endif
+#ifdef RSI_BLKSZ
+       mmc->max_seg_size = -1;
+#else
        mmc->max_seg_size = 1 << 16;
+#endif
        mmc->max_blk_size = 1 << 11;
        mmc->max_blk_count = 1 << 11;
        mmc->max_req_size = PAGE_SIZE;
@@ -480,6 +561,7 @@ static int __devinit sdh_probe(struct platform_device *pdev)
        mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_NEEDS_POLL;
        host = mmc_priv(mmc);
        host->mmc = mmc;
+       host->sclk = get_sclk();
 
        spin_lock_init(&host->lock);
        host->irq = drv_data->irq_int0;
@@ -504,7 +586,6 @@ static int __devinit sdh_probe(struct platform_device *pdev)
        }
 
        platform_set_drvdata(pdev, mmc);
-       mmc_add_host(mmc);
 
        ret = request_irq(host->irq, sdh_stat_irq, 0, "SDH Status IRQ", host);
        if (ret) {
@@ -517,20 +598,10 @@ static int __devinit sdh_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "unable to request peripheral pins\n");
                goto out4;
        }
-#if defined(CONFIG_BF54x)
-       /* Secure Digital Host shares DMA with Nand controller */
-       bfin_write_DMAC1_PERIMUX(bfin_read_DMAC1_PERIMUX() | 0x1);
-#endif
 
-       bfin_write_SDH_CFG(bfin_read_SDH_CFG() | CLKS_EN);
-       SSYNC();
-
-       /* Disable card inserting detection pin. set MMC_CAP_NEES_POLL, and
-        * mmc stack will do the detection.
-        */
-       bfin_write_SDH_CFG((bfin_read_SDH_CFG() & 0x1F) | (PUP_SDDAT | PUP_SDDAT3));
-       SSYNC();
+       sdh_reset();
 
+       mmc_add_host(mmc);
        return 0;
 
 out4:
@@ -578,7 +649,6 @@ static int sdh_suspend(struct platform_device *dev, pm_message_t state)
        if (mmc)
                ret = mmc_suspend_host(mmc);
 
-       bfin_write_SDH_PWR_CTL(bfin_read_SDH_PWR_CTL() & ~PWR_ON);
        peripheral_free_list(drv_data->pin_req);
 
        return ret;
@@ -596,16 +666,7 @@ static int sdh_resume(struct platform_device *dev)
                return ret;
        }
 
-       bfin_write_SDH_PWR_CTL(bfin_read_SDH_PWR_CTL() | PWR_ON);
-#if defined(CONFIG_BF54x)
-       /* Secure Digital Host shares DMA with Nand controller */
-       bfin_write_DMAC1_PERIMUX(bfin_read_DMAC1_PERIMUX() | 0x1);
-#endif
-       bfin_write_SDH_CFG(bfin_read_SDH_CFG() | CLKS_EN);
-       SSYNC();
-
-       bfin_write_SDH_CFG((bfin_read_SDH_CFG() & 0x1F) | (PUP_SDDAT | PUP_SDDAT3));
-       SSYNC();
+       sdh_reset();
 
        if (mmc)
                ret = mmc_resume_host(mmc);
index 72dc3cde646d063513f3a55fc8ba0ec74197261b..af40d227bece22ecb51bb0862df913aadc3ce6da 100644 (file)
@@ -627,6 +627,7 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot)
 {
        struct dw_mci *host = slot->host;
        u32 div;
+       u32 clk_en_a;
 
        if (slot->clock != host->current_speed) {
                div = host->bus_hz / slot->clock;
@@ -659,9 +660,11 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot)
                mci_send_cmd(slot,
                             SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT, 0);
 
-               /* enable clock */
-               mci_writel(host, CLKENA, ((SDMMC_CLKEN_ENABLE |
-                          SDMMC_CLKEN_LOW_PWR) << slot->id));
+               /* enable clock; only low power if no SDIO */
+               clk_en_a = SDMMC_CLKEN_ENABLE << slot->id;
+               if (!(mci_readl(host, INTMASK) & SDMMC_INT_SDIO(slot->id)))
+                       clk_en_a |= SDMMC_CLKEN_LOW_PWR << slot->id;
+               mci_writel(host, CLKENA, clk_en_a);
 
                /* inform CIU */
                mci_send_cmd(slot,
@@ -862,6 +865,30 @@ static int dw_mci_get_cd(struct mmc_host *mmc)
        return present;
 }
 
+/*
+ * Disable lower power mode.
+ *
+ * Low power mode will stop the card clock when idle.  According to the
+ * description of the CLKENA register we should disable low power mode
+ * for SDIO cards if we need SDIO interrupts to work.
+ *
+ * This function is fast if low power mode is already disabled.
+ */
+static void dw_mci_disable_low_power(struct dw_mci_slot *slot)
+{
+       struct dw_mci *host = slot->host;
+       u32 clk_en_a;
+       const u32 clken_low_pwr = SDMMC_CLKEN_LOW_PWR << slot->id;
+
+       clk_en_a = mci_readl(host, CLKENA);
+
+       if (clk_en_a & clken_low_pwr) {
+               mci_writel(host, CLKENA, clk_en_a & ~clken_low_pwr);
+               mci_send_cmd(slot, SDMMC_CMD_UPD_CLK |
+                            SDMMC_CMD_PRV_DAT_WAIT, 0);
+       }
+}
+
 static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
 {
        struct dw_mci_slot *slot = mmc_priv(mmc);
@@ -871,6 +898,14 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
        /* Enable/disable Slot Specific SDIO interrupt */
        int_mask = mci_readl(host, INTMASK);
        if (enb) {
+               /*
+                * Turn off low power mode if it was enabled.  This is a bit of
+                * a heavy operation and we disable / enable IRQs a lot, so
+                * we'll leave low power mode disabled and it will get
+                * re-enabled again in dw_mci_setup_bus().
+                */
+               dw_mci_disable_low_power(slot);
+
                mci_writel(host, INTMASK,
                           (int_mask | SDMMC_INT_SDIO(slot->id)));
        } else {
@@ -1429,22 +1464,10 @@ static void dw_mci_read_data_pio(struct dw_mci *host)
                        nbytes += len;
                        remain -= len;
                } while (remain);
-               sg_miter->consumed = offset;
 
+               sg_miter->consumed = offset;
                status = mci_readl(host, MINTSTS);
                mci_writel(host, RINTSTS, SDMMC_INT_RXDR);
-               if (status & DW_MCI_DATA_ERROR_FLAGS) {
-                       host->data_status = status;
-                       data->bytes_xfered += nbytes;
-                       sg_miter_stop(sg_miter);
-                       host->sg = NULL;
-                       smp_wmb();
-
-                       set_bit(EVENT_DATA_ERROR, &host->pending_events);
-
-                       tasklet_schedule(&host->tasklet);
-                       return;
-               }
        } while (status & SDMMC_INT_RXDR); /*if the RXDR is ready read again*/
        data->bytes_xfered += nbytes;
 
@@ -1497,23 +1520,10 @@ static void dw_mci_write_data_pio(struct dw_mci *host)
                        nbytes += len;
                        remain -= len;
                } while (remain);
-               sg_miter->consumed = offset;
 
+               sg_miter->consumed = offset;
                status = mci_readl(host, MINTSTS);
                mci_writel(host, RINTSTS, SDMMC_INT_TXDR);
-               if (status & DW_MCI_DATA_ERROR_FLAGS) {
-                       host->data_status = status;
-                       data->bytes_xfered += nbytes;
-                       sg_miter_stop(sg_miter);
-                       host->sg = NULL;
-
-                       smp_wmb();
-
-                       set_bit(EVENT_DATA_ERROR, &host->pending_events);
-
-                       tasklet_schedule(&host->tasklet);
-                       return;
-               }
        } while (status & SDMMC_INT_TXDR); /* if TXDR write again */
        data->bytes_xfered += nbytes;
 
@@ -1547,12 +1557,11 @@ static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status)
 static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
 {
        struct dw_mci *host = dev_id;
-       u32 status, pending;
+       u32 pending;
        unsigned int pass_count = 0;
        int i;
 
        do {
-               status = mci_readl(host, RINTSTS);
                pending = mci_readl(host, MINTSTS); /* read-only mask reg */
 
                /*
@@ -1570,7 +1579,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
 
                if (pending & DW_MCI_CMD_ERROR_FLAGS) {
                        mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS);
-                       host->cmd_status = status;
+                       host->cmd_status = pending;
                        smp_wmb();
                        set_bit(EVENT_CMD_COMPLETE, &host->pending_events);
                }
@@ -1578,18 +1587,16 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
                if (pending & DW_MCI_DATA_ERROR_FLAGS) {
                        /* if there is an error report DATA_ERROR */
                        mci_writel(host, RINTSTS, DW_MCI_DATA_ERROR_FLAGS);
-                       host->data_status = status;
+                       host->data_status = pending;
                        smp_wmb();
                        set_bit(EVENT_DATA_ERROR, &host->pending_events);
-                       if (!(pending & (SDMMC_INT_DTO | SDMMC_INT_DCRC |
-                                        SDMMC_INT_SBE | SDMMC_INT_EBE)))
-                               tasklet_schedule(&host->tasklet);
+                       tasklet_schedule(&host->tasklet);
                }
 
                if (pending & SDMMC_INT_DATA_OVER) {
                        mci_writel(host, RINTSTS, SDMMC_INT_DATA_OVER);
                        if (!host->data_status)
-                               host->data_status = status;
+                               host->data_status = pending;
                        smp_wmb();
                        if (host->dir_status == DW_MCI_RECV_STATUS) {
                                if (host->sg != NULL)
@@ -1613,7 +1620,7 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
 
                if (pending & SDMMC_INT_CMD_DONE) {
                        mci_writel(host, RINTSTS, SDMMC_INT_CMD_DONE);
-                       dw_mci_cmd_interrupt(host, status);
+                       dw_mci_cmd_interrupt(host, pending);
                }
 
                if (pending & SDMMC_INT_CD) {
index 3a09f93cc3b6f846a2b4cd327a7fd2a4524e31bc..46e7effa93d51c49f9cf81fe5139c3036e8dfee3 100644 (file)
@@ -301,12 +301,12 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
        struct regulator *reg;
        int ocr_value = 0;
 
-       mmc_slot(host).set_power = omap_hsmmc_set_power;
-
        reg = regulator_get(host->dev, "vmmc");
        if (IS_ERR(reg)) {
                dev_dbg(host->dev, "vmmc regulator missing\n");
+               return PTR_ERR(reg);
        } else {
+               mmc_slot(host).set_power = omap_hsmmc_set_power;
                host->vcc = reg;
                ocr_value = mmc_regulator_get_ocrmask(reg);
                if (!mmc_slot(host).ocr_mask) {
@@ -1782,7 +1782,7 @@ static int __devinit omap_hsmmc_probe(struct platform_device *pdev)
        if (match) {
                pdata = of_get_hsmmc_pdata(&pdev->dev);
                if (match->data) {
-                       u16 *offsetp = match->data;
+                       const u16 *offsetp = match->data;
                        pdata->reg_offset = *offsetp;
                }
        }
index cb2dc0e75ba7fc1ff8d6610176326fa4eb675a5d..11df8006d47e72f1faf7b5a9a78b987216c997b7 100644 (file)
@@ -30,6 +30,9 @@
 #include <linux/regulator/consumer.h>
 #include <linux/gpio.h>
 #include <linux/gfp.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
 
 #include <asm/sizes.h>
 
@@ -573,6 +576,50 @@ static irqreturn_t pxamci_detect_irq(int irq, void *devid)
        return IRQ_HANDLED;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id pxa_mmc_dt_ids[] = {
+        { .compatible = "marvell,pxa-mmc" },
+        { }
+};
+
+MODULE_DEVICE_TABLE(of, pxa_mmc_dt_ids);
+
+static int __devinit pxamci_of_init(struct platform_device *pdev)
+{
+        struct device_node *np = pdev->dev.of_node;
+        struct pxamci_platform_data *pdata;
+        u32 tmp;
+
+        if (!np)
+                return 0;
+
+        pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+        if (!pdata)
+                return -ENOMEM;
+
+       pdata->gpio_card_detect =
+               of_get_named_gpio(np, "cd-gpios", 0);
+       pdata->gpio_card_ro =
+               of_get_named_gpio(np, "wp-gpios", 0);
+
+       /* pxa-mmc specific */
+       pdata->gpio_power =
+               of_get_named_gpio(np, "pxa-mmc,gpio-power", 0);
+
+       if (of_property_read_u32(np, "pxa-mmc,detect-delay-ms", &tmp) == 0)
+               pdata->detect_delay_ms = tmp;
+
+        pdev->dev.platform_data = pdata;
+
+        return 0;
+}
+#else
+static int __devinit pxamci_of_init(struct platform_device *pdev)
+{
+        return 0;
+}
+#endif
+
 static int pxamci_probe(struct platform_device *pdev)
 {
        struct mmc_host *mmc;
@@ -580,6 +627,10 @@ static int pxamci_probe(struct platform_device *pdev)
        struct resource *r, *dmarx, *dmatx;
        int ret, irq, gpio_cd = -1, gpio_ro = -1, gpio_power = -1;
 
+       ret = pxamci_of_init(pdev);
+       if (ret)
+               return ret;
+
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        irq = platform_get_irq(pdev, 0);
        if (!r || irq < 0)
@@ -866,6 +917,7 @@ static struct platform_driver pxamci_driver = {
        .driver         = {
                .name   = DRIVER_NAME,
                .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(pxa_mmc_dt_ids),
 #ifdef CONFIG_PM
                .pm     = &pxamci_pm_ops,
 #endif
index a6e53a1ebb0888639a49d75c72f562f45b48e4f1..90140eb03e36a2766ffc40470271a0e63be34845 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/err.h>
 #include <linux/module.h>
 #include <linux/mmc/host.h>
+#include <linux/of.h>
 
 #include "sdhci-pltfm.h"
 
@@ -126,11 +127,18 @@ static int __devexit sdhci_dove_remove(struct platform_device *pdev)
        return sdhci_pltfm_unregister(pdev);
 }
 
+static const struct of_device_id sdhci_dove_of_match_table[] __devinitdata = {
+       { .compatible = "marvell,dove-sdhci", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, sdhci_dove_of_match_table);
+
 static struct platform_driver sdhci_dove_driver = {
        .driver         = {
                .name   = "sdhci-dove",
                .owner  = THIS_MODULE,
                .pm     = SDHCI_PLTFM_PMOPS,
+               .of_match_table = of_match_ptr(sdhci_dove_of_match_table),
        },
        .probe          = sdhci_dove_probe,
        .remove         = __devexit_p(sdhci_dove_remove),
index f8eb1fb0c9219283c9624f3f0a8adde251bcd5e9..ae5fcbfa1eef5986ec832616ed1ad350106e64ef 100644 (file)
 #include "sdhci-pltfm.h"
 #include "sdhci-esdhc.h"
 
+#define VENDOR_V_22    0x12
+static u32 esdhc_readl(struct sdhci_host *host, int reg)
+{
+       u32 ret;
+
+       ret = in_be32(host->ioaddr + reg);
+       /*
+        * The bit of ADMA flag in eSDHC is not compatible with standard
+        * SDHC register, so set fake flag SDHCI_CAN_DO_ADMA2 when ADMA is
+        * supported by eSDHC.
+        * And for many FSL eSDHC controller, the reset value of field
+        * SDHCI_CAN_DO_ADMA1 is one, but some of them can't support ADMA,
+        * only these vendor version is greater than 2.2/0x12 support ADMA.
+        * For FSL eSDHC, must aligned 4-byte, so use 0xFC to read the
+        * the verdor version number, oxFE is SDHCI_HOST_VERSION.
+        */
+       if ((reg == SDHCI_CAPABILITIES) && (ret & SDHCI_CAN_DO_ADMA1)) {
+               u32 tmp = in_be32(host->ioaddr + SDHCI_SLOT_INT_STATUS);
+               tmp = (tmp & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT;
+               if (tmp > VENDOR_V_22)
+                       ret |= SDHCI_CAN_DO_ADMA2;
+       }
+
+       return ret;
+}
+
 static u16 esdhc_readw(struct sdhci_host *host, int reg)
 {
        u16 ret;
@@ -144,7 +170,7 @@ static void esdhc_of_resume(struct sdhci_host *host)
 #endif
 
 static struct sdhci_ops sdhci_esdhc_ops = {
-       .read_l = sdhci_be32bs_readl,
+       .read_l = esdhc_readl,
        .read_w = esdhc_readw,
        .read_b = esdhc_readb,
        .write_l = sdhci_be32bs_writel,
@@ -161,9 +187,13 @@ static struct sdhci_ops sdhci_esdhc_ops = {
 };
 
 static struct sdhci_pltfm_data sdhci_esdhc_pdata = {
-       /* card detection could be handled via GPIO */
+       /*
+        * card detection could be handled via GPIO
+        * eSDHC cannot support End Attribute in NOP ADMA descriptor
+        */
        .quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_CARD_DETECTION
-               | SDHCI_QUIRK_NO_CARD_NO_RESET,
+               | SDHCI_QUIRK_NO_CARD_NO_RESET
+               | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
        .ops = &sdhci_esdhc_ops,
 };
 
index b6ee8857e226fc163d53c1a66d52eda26121735d..8e63a9c04e3176fd9f8950caa2c461636b6cce47 100644 (file)
@@ -197,7 +197,7 @@ static int __devinit sdhci_pxav2_probe(struct platform_device *pdev)
                goto err_clk_get;
        }
        pltfm_host->clk = clk;
-       clk_enable(clk);
+       clk_prepare_enable(clk);
 
        host->quirks = SDHCI_QUIRK_BROKEN_ADMA
                | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
@@ -239,7 +239,7 @@ static int __devinit sdhci_pxav2_probe(struct platform_device *pdev)
        return 0;
 
 err_add_host:
-       clk_disable(clk);
+       clk_disable_unprepare(clk);
        clk_put(clk);
 err_clk_get:
        sdhci_pltfm_free(pdev);
@@ -255,7 +255,7 @@ static int __devexit sdhci_pxav2_remove(struct platform_device *pdev)
 
        sdhci_remove_host(host, 1);
 
-       clk_disable(pltfm_host->clk);
+       clk_disable_unprepare(pltfm_host->clk);
        clk_put(pltfm_host->clk);
        sdhci_pltfm_free(pdev);
        kfree(pxa);
index 07fe3834fe0b224119d0591672de48949dd18105..a553b180d3404268ce8fe1fb8b430c3ff62b589f 100644 (file)
@@ -231,14 +231,14 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev)
        pltfm_host = sdhci_priv(host);
        pltfm_host->priv = pxa;
 
-       clk = clk_get(dev, "PXA-SDHCLK");
+       clk = clk_get(dev, NULL);
        if (IS_ERR(clk)) {
                dev_err(dev, "failed to get io clock\n");
                ret = PTR_ERR(clk);
                goto err_clk_get;
        }
        pltfm_host->clk = clk;
-       clk_enable(clk);
+       clk_prepare_enable(clk);
 
        host->quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL
                | SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC
@@ -283,7 +283,7 @@ static int __devinit sdhci_pxav3_probe(struct platform_device *pdev)
        return 0;
 
 err_add_host:
-       clk_disable(clk);
+       clk_disable_unprepare(clk);
        clk_put(clk);
 err_clk_get:
        sdhci_pltfm_free(pdev);
@@ -299,7 +299,7 @@ static int __devexit sdhci_pxav3_remove(struct platform_device *pdev)
 
        sdhci_remove_host(host, 1);
 
-       clk_disable(pltfm_host->clk);
+       clk_disable_unprepare(pltfm_host->clk);
        clk_put(pltfm_host->clk);
        sdhci_pltfm_free(pdev);
        kfree(pxa);
index 9a11dc39921c06ebdf67a3ed602fbba79cc38b89..d98b1992d778ca8f87ff3a405c783ad506a17f2a 100644 (file)
@@ -1597,57 +1597,65 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
        spin_unlock_irqrestore(&host->lock, flags);
 }
 
-static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
-                                               struct mmc_ios *ios)
+static int sdhci_do_3_3v_signal_voltage_switch(struct sdhci_host *host,
+                                               u16 ctrl)
 {
-       u8 pwr;
-       u16 clk, ctrl;
-       u32 present_state;
+       int ret;
 
-       /*
-        * Signal Voltage Switching is only applicable for Host Controllers
-        * v3.00 and above.
-        */
-       if (host->version < SDHCI_SPEC_300)
-               return 0;
+       /* Set 1.8V Signal Enable in the Host Control2 register to 0 */
+       ctrl &= ~SDHCI_CTRL_VDD_180;
+       sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
 
-       /*
-        * We first check whether the request is to set signalling voltage
-        * to 3.3V. If so, we change the voltage to 3.3V and return quickly.
-        */
+       if (host->vqmmc) {
+               ret = regulator_set_voltage(host->vqmmc, 3300000, 3300000);
+               if (ret) {
+                       pr_warning("%s: Switching to 3.3V signalling voltage "
+                                  " failed\n", mmc_hostname(host->mmc));
+                       return -EIO;
+               }
+       }
+       /* Wait for 5ms */
+       usleep_range(5000, 5500);
+
+       /* 3.3V regulator output should be stable within 5 ms */
        ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
-       if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
-               /* Set 1.8V Signal Enable in the Host Control2 register to 0 */
-               ctrl &= ~SDHCI_CTRL_VDD_180;
-               sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+       if (!(ctrl & SDHCI_CTRL_VDD_180))
+               return 0;
 
-               /* Wait for 5ms */
-               usleep_range(5000, 5500);
+       pr_warning("%s: 3.3V regulator output did not became stable\n",
+                  mmc_hostname(host->mmc));
 
-               /* 3.3V regulator output should be stable within 5 ms */
-               ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
-               if (!(ctrl & SDHCI_CTRL_VDD_180))
-                       return 0;
-               else {
-                       pr_info(DRIVER_NAME ": Switching to 3.3V "
-                               "signalling voltage failed\n");
-                       return -EIO;
-               }
-       } else if (!(ctrl & SDHCI_CTRL_VDD_180) &&
-                 (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180)) {
-               /* Stop SDCLK */
-               clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
-               clk &= ~SDHCI_CLOCK_CARD_EN;
-               sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+       return -EIO;
+}
 
-               /* Check whether DAT[3:0] is 0000 */
-               present_state = sdhci_readl(host, SDHCI_PRESENT_STATE);
-               if (!((present_state & SDHCI_DATA_LVL_MASK) >>
-                      SDHCI_DATA_LVL_SHIFT)) {
-                       /*
-                        * Enable 1.8V Signal Enable in the Host Control2
-                        * register
-                        */
+static int sdhci_do_1_8v_signal_voltage_switch(struct sdhci_host *host,
+                                               u16 ctrl)
+{
+       u8 pwr;
+       u16 clk;
+       u32 present_state;
+       int ret;
+
+       /* Stop SDCLK */
+       clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+       clk &= ~SDHCI_CLOCK_CARD_EN;
+       sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+       /* Check whether DAT[3:0] is 0000 */
+       present_state = sdhci_readl(host, SDHCI_PRESENT_STATE);
+       if (!((present_state & SDHCI_DATA_LVL_MASK) >>
+              SDHCI_DATA_LVL_SHIFT)) {
+               /*
+                * Enable 1.8V Signal Enable in the Host Control2
+                * register
+                */
+               if (host->vqmmc)
+                       ret = regulator_set_voltage(host->vqmmc,
+                               1800000, 1800000);
+               else
+                       ret = 0;
+
+               if (!ret) {
                        ctrl |= SDHCI_CTRL_VDD_180;
                        sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
 
@@ -1656,7 +1664,7 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
 
                        ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
                        if (ctrl & SDHCI_CTRL_VDD_180) {
-                               /* Provide SDCLK again and wait for 1ms*/
+                               /* Provide SDCLK again and wait for 1ms */
                                clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
                                clk |= SDHCI_CLOCK_CARD_EN;
                                sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
@@ -1673,29 +1681,55 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
                                        return 0;
                        }
                }
+       }
 
-               /*
-                * If we are here, that means the switch to 1.8V signaling
-                * failed. We power cycle the card, and retry initialization
-                * sequence by setting S18R to 0.
-                */
-               pwr = sdhci_readb(host, SDHCI_POWER_CONTROL);
-               pwr &= ~SDHCI_POWER_ON;
-               sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
-               if (host->vmmc)
-                       regulator_disable(host->vmmc);
+       /*
+        * If we are here, that means the switch to 1.8V signaling
+        * failed. We power cycle the card, and retry initialization
+        * sequence by setting S18R to 0.
+        */
+       pwr = sdhci_readb(host, SDHCI_POWER_CONTROL);
+       pwr &= ~SDHCI_POWER_ON;
+       sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
+       if (host->vmmc)
+               regulator_disable(host->vmmc);
 
-               /* Wait for 1ms as per the spec */
-               usleep_range(1000, 1500);
-               pwr |= SDHCI_POWER_ON;
-               sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
-               if (host->vmmc)
-                       regulator_enable(host->vmmc);
+       /* Wait for 1ms as per the spec */
+       usleep_range(1000, 1500);
+       pwr |= SDHCI_POWER_ON;
+       sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
+       if (host->vmmc)
+               regulator_enable(host->vmmc);
 
-               pr_info(DRIVER_NAME ": Switching to 1.8V signalling "
-                       "voltage failed, retrying with S18R set to 0\n");
-               return -EAGAIN;
-       } else
+       pr_warning("%s: Switching to 1.8V signalling voltage failed, "
+                  "retrying with S18R set to 0\n", mmc_hostname(host->mmc));
+
+       return -EAGAIN;
+}
+
+static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
+                                               struct mmc_ios *ios)
+{
+       u16 ctrl;
+
+       /*
+        * Signal Voltage Switching is only applicable for Host Controllers
+        * v3.00 and above.
+        */
+       if (host->version < SDHCI_SPEC_300)
+               return 0;
+
+       /*
+        * We first check whether the request is to set signalling voltage
+        * to 3.3V. If so, we change the voltage to 3.3V and return quickly.
+        */
+       ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+       if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330)
+               return sdhci_do_3_3v_signal_voltage_switch(host, ctrl);
+       else if (!(ctrl & SDHCI_CTRL_VDD_180) &&
+                       (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180))
+               return sdhci_do_1_8v_signal_voltage_switch(host, ctrl);
+       else
                /* No signal voltage switch required */
                return 0;
 }
@@ -2802,6 +2836,18 @@ int sdhci_add_host(struct sdhci_host *host)
            !(host->mmc->caps & MMC_CAP_NONREMOVABLE))
                mmc->caps |= MMC_CAP_NEEDS_POLL;
 
+       /* If vqmmc regulator and no 1.8V signalling, then there's no UHS */
+       host->vqmmc = regulator_get(mmc_dev(mmc), "vqmmc");
+       if (IS_ERR(host->vqmmc)) {
+               pr_info("%s: no vqmmc regulator found\n", mmc_hostname(mmc));
+               host->vqmmc = NULL;
+       }
+       else if (regulator_is_supported_voltage(host->vqmmc, 1800000, 1800000))
+               regulator_enable(host->vqmmc);
+       else
+               caps[1] &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 |
+                      SDHCI_SUPPORT_DDR50);
+
        /* Any UHS-I mode in caps implies SDR12 and SDR25 support. */
        if (caps[1] & (SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 |
                       SDHCI_SUPPORT_DDR50))
@@ -2862,7 +2908,8 @@ int sdhci_add_host(struct sdhci_host *host)
        if (IS_ERR(host->vmmc)) {
                pr_info("%s: no vmmc regulator found\n", mmc_hostname(mmc));
                host->vmmc = NULL;
-       }
+       } else
+               regulator_enable(host->vmmc);
 
 #ifdef CONFIG_REGULATOR
        if (host->vmmc) {
@@ -3119,8 +3166,15 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
        tasklet_kill(&host->card_tasklet);
        tasklet_kill(&host->finish_tasklet);
 
-       if (host->vmmc)
+       if (host->vmmc) {
+               regulator_disable(host->vmmc);
                regulator_put(host->vmmc);
+       }
+
+       if (host->vqmmc) {
+               regulator_disable(host->vqmmc);
+               regulator_put(host->vqmmc);
+       }
 
        kfree(host->adma_desc);
        kfree(host->align_buffer);
index 3135a1a5d75d004fda64cf0160f14481bc6af333..6c39bf1fd279c26afb1a6304f92d9734b0dff6a1 100644 (file)
@@ -2358,9 +2358,9 @@ error5:
         * which is contained at the end of struct mmc
         */
 error4:
-       usb_free_urb(command_out_urb);
-error1:
        usb_free_urb(command_res_urb);
+error1:
+       usb_free_urb(command_out_urb);
 error0:
        return retval;
 }
index b1e3c26edd6dad3953cfc11203de1497b25887aa..e469b01d40d26960594380602b67e1baefcab4d2 100644 (file)
@@ -43,9 +43,6 @@ choice
        prompt "Flash cmd/query data swapping"
        depends on MTD_CFI_ADV_OPTIONS
        default MTD_CFI_NOSWAP
-
-config MTD_CFI_NOSWAP
-       bool "NO"
        ---help---
          This option defines the way in which the CPU attempts to arrange
          data bits when writing the 'magic' commands to the chips. Saying
@@ -55,12 +52,8 @@ config MTD_CFI_NOSWAP
          Specific arrangements are possible with the BIG_ENDIAN_BYTE and
          LITTLE_ENDIAN_BYTE, if the bytes are reversed.
 
-         If you have a LART, on which the data (and address) lines were
-         connected in a fashion which ensured that the nets were as short
-         as possible, resulting in a bit-shuffling which seems utterly
-         random to the untrained eye, you need the LART_ENDIAN_BYTE option.
-
-         Yes, there really exists something sicker than PDP-endian :)
+config MTD_CFI_NOSWAP
+       bool "NO"
 
 config MTD_CFI_BE_BYTE_SWAP
        bool "BIG_ENDIAN_BYTE"
index 22d0493a026ff7adfe07b62bf7e11555e9f67982..5ff5c4a16943c16dfefca20def28300b398ad6b6 100644 (file)
@@ -431,6 +431,68 @@ static void cfi_fixup_major_minor(struct cfi_private *cfi,
        }
 }
 
+static int is_m29ew(struct cfi_private *cfi)
+{
+       if (cfi->mfr == CFI_MFR_INTEL &&
+           ((cfi->device_type == CFI_DEVICETYPE_X8 && (cfi->id & 0xff) == 0x7e) ||
+            (cfi->device_type == CFI_DEVICETYPE_X16 && cfi->id == 0x227e)))
+               return 1;
+       return 0;
+}
+
+/*
+ * From TN-13-07: Patching the Linux Kernel and U-Boot for M29 Flash, page 20:
+ * Some revisions of the M29EW suffer from erase suspend hang ups. In
+ * particular, it can occur when the sequence
+ * Erase Confirm -> Suspend -> Program -> Resume
+ * causes a lockup due to internal timing issues. The consequence is that the
+ * erase cannot be resumed without inserting a dummy command after programming
+ * and prior to resuming. [...] The work-around is to issue a dummy write cycle
+ * that writes an F0 command code before the RESUME command.
+ */
+static void cfi_fixup_m29ew_erase_suspend(struct map_info *map,
+                                         unsigned long adr)
+{
+       struct cfi_private *cfi = map->fldrv_priv;
+       /* before resume, insert a dummy 0xF0 cycle for Micron M29EW devices */
+       if (is_m29ew(cfi))
+               map_write(map, CMD(0xF0), adr);
+}
+
+/*
+ * From TN-13-07: Patching the Linux Kernel and U-Boot for M29 Flash, page 22:
+ *
+ * Some revisions of the M29EW (for example, A1 and A2 step revisions)
+ * are affected by a problem that could cause a hang up when an ERASE SUSPEND
+ * command is issued after an ERASE RESUME operation without waiting for a
+ * minimum delay.  The result is that once the ERASE seems to be completed
+ * (no bits are toggling), the contents of the Flash memory block on which
+ * the erase was ongoing could be inconsistent with the expected values
+ * (typically, the array value is stuck to the 0xC0, 0xC4, 0x80, or 0x84
+ * values), causing a consequent failure of the ERASE operation.
+ * The occurrence of this issue could be high, especially when file system
+ * operations on the Flash are intensive.  As a result, it is recommended
+ * that a patch be applied.  Intensive file system operations can cause many
+ * calls to the garbage routine to free Flash space (also by erasing physical
+ * Flash blocks) and as a result, many consecutive SUSPEND and RESUME
+ * commands can occur.  The problem disappears when a delay is inserted after
+ * the RESUME command by using the udelay() function available in Linux.
+ * The DELAY value must be tuned based on the customer's platform.
+ * The maximum value that fixes the problem in all cases is 500us.
+ * But, in our experience, a delay of 30 Âµs to 50 Âµs is sufficient
+ * in most cases.
+ * We have chosen 500µs because this latency is acceptable.
+ */
+static void cfi_fixup_m29ew_delay_after_resume(struct cfi_private *cfi)
+{
+       /*
+        * Resolving the Delay After Resume Issue see Micron TN-13-07
+        * Worst case delay must be 500µs but 30-50µs should be ok as well
+        */
+       if (is_m29ew(cfi))
+               cfi_udelay(500);
+}
+
 struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
 {
        struct cfi_private *cfi = map->fldrv_priv;
@@ -776,7 +838,10 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad
 
        switch(chip->oldstate) {
        case FL_ERASING:
+               cfi_fixup_m29ew_erase_suspend(map,
+                       chip->in_progress_block_addr);
                map_write(map, cfi->sector_erase_cmd, chip->in_progress_block_addr);
+               cfi_fixup_m29ew_delay_after_resume(cfi);
                chip->oldstate = FL_READY;
                chip->state = FL_ERASING;
                break;
@@ -916,6 +981,8 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
                        /* Disallow XIP again */
                        local_irq_disable();
 
+                       /* Correct Erase Suspend Hangups for M29EW */
+                       cfi_fixup_m29ew_erase_suspend(map, adr);
                        /* Resume the write or erase operation */
                        map_write(map, cfi->sector_erase_cmd, adr);
                        chip->state = oldstate;
index 4cdb2af7bf44e74dbb72bab223d39beabd7c265a..6cc5a1ac380218809155eed6ff1ce2f3c861e68a 100644 (file)
@@ -97,7 +97,7 @@ config MTD_M25P80
          doesn't support the JEDEC ID instruction.
 
 config M25PXX_USE_FAST_READ
-       bool "Use FAST_READ OPCode allowing SPI CLK <= 50MHz"
+       bool "Use FAST_READ OPCode allowing SPI CLK >= 50MHz"
        depends on MTD_M25P80
        default y
        help
index 5d0d68c3fe27a79a097d64fa03246c276510ad3b..d16f75ce16e95a1174bc35d67e27d8f6ff5b2b66 100644 (file)
@@ -633,6 +633,8 @@ static const struct spi_device_id m25p_ids[] = {
        { "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32, SECT_4K) },
        { "at26df321",  INFO(0x1f4700, 0, 64 * 1024, 64, SECT_4K) },
 
+       { "at45db081d", INFO(0x1f2500, 0, 64 * 1024, 16, SECT_4K) },
+
        /* EON -- en25xxx */
        { "en25f32", INFO(0x1c3116, 0, 64 * 1024,  64, SECT_4K) },
        { "en25p32", INFO(0x1c2016, 0, 64 * 1024,  64, 0) },
@@ -646,6 +648,7 @@ static const struct spi_device_id m25p_ids[] = {
        { "160s33b",  INFO(0x898911, 0, 64 * 1024,  32, 0) },
        { "320s33b",  INFO(0x898912, 0, 64 * 1024,  64, 0) },
        { "640s33b",  INFO(0x898913, 0, 64 * 1024, 128, 0) },
+       { "n25q064",  INFO(0x20ba17, 0, 64 * 1024, 128, 0) },
 
        /* Macronix */
        { "mx25l2005a",  INFO(0xc22012, 0, 64 * 1024,   4, SECT_4K) },
@@ -662,12 +665,8 @@ static const struct spi_device_id m25p_ids[] = {
        /* Spansion -- single (large) sector size only, at least
         * for the chips listed here (without boot sectors).
         */
-       { "s25sl004a",  INFO(0x010212,      0,  64 * 1024,   8, 0) },
-       { "s25sl008a",  INFO(0x010213,      0,  64 * 1024,  16, 0) },
-       { "s25sl016a",  INFO(0x010214,      0,  64 * 1024,  32, 0) },
-       { "s25sl032a",  INFO(0x010215,      0,  64 * 1024,  64, 0) },
        { "s25sl032p",  INFO(0x010215, 0x4d00,  64 * 1024,  64, SECT_4K) },
-       { "s25sl064a",  INFO(0x010216,      0,  64 * 1024, 128, 0) },
+       { "s25sl064p",  INFO(0x010216, 0x4d00,  64 * 1024, 128, SECT_4K) },
        { "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, 0) },
        { "s25fl256s1", INFO(0x010219, 0x4d01,  64 * 1024, 512, 0) },
        { "s25fl512s",  INFO(0x010220, 0x4d00, 256 * 1024, 256, 0) },
@@ -676,6 +675,11 @@ static const struct spi_device_id m25p_ids[] = {
        { "s25sl12801", INFO(0x012018, 0x0301,  64 * 1024, 256, 0) },
        { "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024,  64, 0) },
        { "s25fl129p1", INFO(0x012018, 0x4d01,  64 * 1024, 256, 0) },
+       { "s25sl004a",  INFO(0x010212,      0,  64 * 1024,   8, 0) },
+       { "s25sl008a",  INFO(0x010213,      0,  64 * 1024,  16, 0) },
+       { "s25sl016a",  INFO(0x010214,      0,  64 * 1024,  32, 0) },
+       { "s25sl032a",  INFO(0x010215,      0,  64 * 1024,  64, 0) },
+       { "s25sl064a",  INFO(0x010216,      0,  64 * 1024, 128, 0) },
        { "s25fl016k",  INFO(0xef4015,      0,  64 * 1024,  32, SECT_4K) },
        { "s25fl064k",  INFO(0xef4017,      0,  64 * 1024, 128, SECT_4K) },
 
@@ -699,6 +703,7 @@ static const struct spi_device_id m25p_ids[] = {
        { "m25p32",  INFO(0x202016,  0,  64 * 1024,  64, 0) },
        { "m25p64",  INFO(0x202017,  0,  64 * 1024, 128, 0) },
        { "m25p128", INFO(0x202018,  0, 256 * 1024,  64, 0) },
+       { "n25q032", INFO(0x20ba16,  0,  64 * 1024,  64, 0) },
 
        { "m25p05-nonjedec",  INFO(0, 0,  32 * 1024,   2, 0) },
        { "m25p10-nonjedec",  INFO(0, 0,  32 * 1024,   4, 0) },
@@ -714,6 +719,7 @@ static const struct spi_device_id m25p_ids[] = {
        { "m45pe80", INFO(0x204014,  0, 64 * 1024,   16, 0) },
        { "m45pe16", INFO(0x204015,  0, 64 * 1024,   32, 0) },
 
+       { "m25pe20", INFO(0x208012,  0, 64 * 1024,  4,       0) },
        { "m25pe80", INFO(0x208014,  0, 64 * 1024, 16,       0) },
        { "m25pe16", INFO(0x208015,  0, 64 * 1024, 32, SECT_4K) },
 
@@ -730,6 +736,7 @@ static const struct spi_device_id m25p_ids[] = {
        { "w25x16", INFO(0xef3015, 0, 64 * 1024,  32, SECT_4K) },
        { "w25x32", INFO(0xef3016, 0, 64 * 1024,  64, SECT_4K) },
        { "w25q32", INFO(0xef4016, 0, 64 * 1024,  64, SECT_4K) },
+       { "w25q32dw", INFO(0xef6016, 0, 64 * 1024,  64, SECT_4K) },
        { "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) },
index 67960362681e7f7a72933aaf87b5ffa515c36cfa..b85f183d24c00151b8c5c1ed87e4f1338b8b2369 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/module.h>
 #include <linux/param.h>
 #include <linux/platform_device.h>
+#include <linux/pm.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/spear_smi.h>
@@ -240,8 +241,8 @@ static int spear_smi_read_sr(struct spear_smi *dev, u32 bank)
        /* copy dev->status (lower 16 bits) in order to release lock */
        if (ret > 0)
                ret = dev->status & 0xffff;
-       else
-               ret = -EIO;
+       else if (ret == 0)
+               ret = -ETIMEDOUT;
 
        /* restore the ctrl regs state */
        writel(ctrlreg1, dev->io_base + SMI_CR1);
@@ -269,16 +270,19 @@ static int spear_smi_wait_till_ready(struct spear_smi *dev, u32 bank,
        finish = jiffies + timeout;
        do {
                status = spear_smi_read_sr(dev, bank);
-               if (status < 0)
-                       continue; /* try till timeout */
-               else if (!(status & SR_WIP))
+               if (status < 0) {
+                       if (status == -ETIMEDOUT)
+                               continue; /* try till finish */
+                       return status;
+               } else if (!(status & SR_WIP)) {
                        return 0;
+               }
 
                cond_resched();
        } while (!time_after_eq(jiffies, finish));
 
        dev_err(&dev->pdev->dev, "smi controller is busy, timeout\n");
-       return status;
+       return -EBUSY;
 }
 
 /**
@@ -335,6 +339,9 @@ static void spear_smi_hw_init(struct spear_smi *dev)
        val = HOLD1 | BANK_EN | DSEL_TIME | (prescale << 8);
 
        mutex_lock(&dev->lock);
+       /* clear all interrupt conditions */
+       writel(0, dev->io_base + SMI_SR);
+
        writel(val, dev->io_base + SMI_CR1);
        mutex_unlock(&dev->lock);
 }
@@ -391,11 +398,11 @@ static int spear_smi_write_enable(struct spear_smi *dev, u32 bank)
        writel(ctrlreg1, dev->io_base + SMI_CR1);
        writel(0, dev->io_base + SMI_CR2);
 
-       if (ret <= 0) {
+       if (ret == 0) {
                ret = -EIO;
                dev_err(&dev->pdev->dev,
                        "smi controller failed on write enable\n");
-       } else {
+       } else if (ret > 0) {
                /* check whether write mode status is set for required bank */
                if (dev->status & (1 << (bank + WM_SHIFT)))
                        ret = 0;
@@ -462,10 +469,10 @@ static int spear_smi_erase_sector(struct spear_smi *dev,
        ret = wait_event_interruptible_timeout(dev->cmd_complete,
                        dev->status & TFF, SMI_CMD_TIMEOUT);
 
-       if (ret <= 0) {
+       if (ret == 0) {
                ret = -EIO;
                dev_err(&dev->pdev->dev, "sector erase failed\n");
-       } else
+       } else if (ret > 0)
                ret = 0; /* success */
 
        /* restore ctrl regs */
@@ -1086,29 +1093,33 @@ static int __devexit spear_smi_remove(struct platform_device *pdev)
        return 0;
 }
 
-int spear_smi_suspend(struct platform_device *pdev, pm_message_t state)
+#ifdef CONFIG_PM
+static int spear_smi_suspend(struct device *dev)
 {
-       struct spear_smi *dev = platform_get_drvdata(pdev);
+       struct spear_smi *sdev = dev_get_drvdata(dev);
 
-       if (dev && dev->clk)
-               clk_disable_unprepare(dev->clk);
+       if (sdev && sdev->clk)
+               clk_disable_unprepare(sdev->clk);
 
        return 0;
 }
 
-int spear_smi_resume(struct platform_device *pdev)
+static int spear_smi_resume(struct device *dev)
 {
-       struct spear_smi *dev = platform_get_drvdata(pdev);
+       struct spear_smi *sdev = dev_get_drvdata(dev);
        int ret = -EPERM;
 
-       if (dev && dev->clk)
-               ret = clk_prepare_enable(dev->clk);
+       if (sdev && sdev->clk)
+               ret = clk_prepare_enable(sdev->clk);
 
        if (!ret)
-               spear_smi_hw_init(dev);
+               spear_smi_hw_init(sdev);
        return ret;
 }
 
+static SIMPLE_DEV_PM_OPS(spear_smi_pm_ops, spear_smi_suspend, spear_smi_resume);
+#endif
+
 #ifdef CONFIG_OF
 static const struct of_device_id spear_smi_id_table[] = {
        { .compatible = "st,spear600-smi" },
@@ -1123,11 +1134,12 @@ static struct platform_driver spear_smi_driver = {
                .bus = &platform_bus_type,
                .owner = THIS_MODULE,
                .of_match_table = of_match_ptr(spear_smi_id_table),
+#ifdef CONFIG_PM
+               .pm = &spear_smi_pm_ops,
+#endif
        },
        .probe = spear_smi_probe,
        .remove = __devexit_p(spear_smi_remove),
-       .suspend = spear_smi_suspend,
-       .resume = spear_smi_resume,
 };
 
 static int spear_smi_init(void)
index 5ba2458e799ac4e3db5d8d78b7c9b4814bec5a09..53850f19db8c01f4dd5cdac2ffc819085ffc3262 100644 (file)
@@ -447,18 +447,6 @@ config MTD_UCLINUX
        help
          Map driver to support image based filesystems for uClinux.
 
-config MTD_WRSBC8260
-       tristate "Map driver for WindRiver PowerQUICC II MPC82xx board"
-       depends on (SBC82xx || SBC8560)
-       select MTD_MAP_BANK_WIDTH_4
-       select MTD_MAP_BANK_WIDTH_1
-       select MTD_CFI_I1
-       select MTD_CFI_I4
-       help
-         Map driver for WindRiver PowerQUICC II MPC82xx board. Drives
-         all three flash regions on CS0, CS1 and CS6 if they are configured
-         correctly by the boot loader.
-
 config MTD_DMV182
         tristate "Map driver for Dy-4 SVME/DMV-182 board."
         depends on DMV182
index 68a9a91d344fbc65974e5978fb6ee4d6a7ee113e..deb43e9a1e7f1d929f13afb2d9a90f3299c3dddb 100644 (file)
@@ -47,7 +47,6 @@ obj-$(CONFIG_MTD_SCB2_FLASH)  += scb2_flash.o
 obj-$(CONFIG_MTD_H720X)                += h720x-flash.o
 obj-$(CONFIG_MTD_IXP4XX)       += ixp4xx.o
 obj-$(CONFIG_MTD_IXP2000)      += ixp2000.o
-obj-$(CONFIG_MTD_WRSBC8260)    += wr_sbc82xx_flash.o
 obj-$(CONFIG_MTD_DMV182)       += dmv182.o
 obj-$(CONFIG_MTD_PLATRAM)      += plat-ram.o
 obj-$(CONFIG_MTD_INTEL_VR_NOR) += intel_vr_nor.o
index cfff454f628ba73498f0876355e9c1266d67c7fa..c3bb304eca076ffab133b7cd1e6a363a0763dfaa 100644 (file)
 #include <linux/mtd/map.h>
 #include <linux/mtd/partitions.h>
 #include <asm/io.h>
+#include <asm/sections.h>
 
 /****************************************************************************/
 
-extern char _ebss;
-
 struct map_info uclinux_ram_map = {
        .name = "RAM",
-       .phys = (unsigned long)&_ebss,
+       .phys = (unsigned long)__bss_stop,
        .size = 0,
 };
 
diff --git a/drivers/mtd/maps/wr_sbc82xx_flash.c b/drivers/mtd/maps/wr_sbc82xx_flash.c
deleted file mode 100644 (file)
index e7534c8..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Map for flash chips on Wind River PowerQUICC II SBC82xx board.
- *
- * Copyright (C) 2004 Red Hat, Inc.
- *
- * Author: David Woodhouse <dwmw2@infradead.org>
- *
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <asm/io.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/immap_cpm2.h>
-
-static struct mtd_info *sbcmtd[3];
-
-struct map_info sbc82xx_flash_map[3] = {
-       {.name = "Boot flash"},
-       {.name = "Alternate boot flash"},
-       {.name = "User flash"}
-};
-
-static struct mtd_partition smallflash_parts[] = {
-       {
-               .name =         "space",
-               .size =         0x100000,
-               .offset =       0,
-       }, {
-               .name =         "bootloader",
-               .size =         MTDPART_SIZ_FULL,
-               .offset =       MTDPART_OFS_APPEND,
-       }
-};
-
-static struct mtd_partition bigflash_parts[] = {
-       {
-               .name =         "bootloader",
-               .size =         0x00100000,
-               .offset =       0,
-       }, {
-               .name =         "file system",
-               .size =         0x01f00000,
-               .offset =       MTDPART_OFS_APPEND,
-       }, {
-               .name =         "boot config",
-               .size =         0x00100000,
-               .offset =       MTDPART_OFS_APPEND,
-       }, {
-               .name =         "space",
-               .size =         0x01f00000,
-               .offset =       MTDPART_OFS_APPEND,
-       }
-};
-
-static const char *part_probes[] __initconst = {"cmdlinepart", "RedBoot", NULL};
-
-#define init_sbc82xx_one_flash(map, br, or)                    \
-do {                                                           \
-       (map).phys = (br & 1) ? (br & 0xffff8000) : 0;          \
-       (map).size = (br & 1) ? (~(or & 0xffff8000) + 1) : 0;   \
-       switch (br & 0x00001800) {                              \
-       case 0x00000000:                                        \
-       case 0x00000800:        (map).bankwidth = 1;    break;  \
-       case 0x00001000:        (map).bankwidth = 2;    break;  \
-       case 0x00001800:        (map).bankwidth = 4;    break;  \
-       }                                                       \
-} while (0);
-
-static int __init init_sbc82xx_flash(void)
-{
-       volatile memctl_cpm2_t *mc = &cpm2_immr->im_memctl;
-       int bigflash;
-       int i;
-
-#ifdef CONFIG_SBC8560
-       mc = ioremap(0xff700000 + 0x5000, sizeof(memctl_cpm2_t));
-#else
-       mc = &cpm2_immr->im_memctl;
-#endif
-
-       bigflash = 1;
-       if ((mc->memc_br0 & 0x00001800) == 0x00001800)
-               bigflash = 0;
-
-       init_sbc82xx_one_flash(sbc82xx_flash_map[0], mc->memc_br0, mc->memc_or0);
-       init_sbc82xx_one_flash(sbc82xx_flash_map[1], mc->memc_br6, mc->memc_or6);
-       init_sbc82xx_one_flash(sbc82xx_flash_map[2], mc->memc_br1, mc->memc_or1);
-
-#ifdef CONFIG_SBC8560
-       iounmap((void *) mc);
-#endif
-
-       for (i=0; i<3; i++) {
-               int8_t flashcs[3] = { 0, 6, 1 };
-               int nr_parts;
-               struct mtd_partition *defparts;
-
-               printk(KERN_NOTICE "PowerQUICC II %s (%ld MiB on CS%d",
-                      sbc82xx_flash_map[i].name,
-                      (sbc82xx_flash_map[i].size >> 20),
-                      flashcs[i]);
-               if (!sbc82xx_flash_map[i].phys) {
-                       /* We know it can't be at zero. */
-                       printk("): disabled by bootloader.\n");
-                       continue;
-               }
-               printk(" at %08lx)\n",  sbc82xx_flash_map[i].phys);
-
-               sbc82xx_flash_map[i].virt = ioremap(sbc82xx_flash_map[i].phys,
-                                                   sbc82xx_flash_map[i].size);
-
-               if (!sbc82xx_flash_map[i].virt) {
-                       printk("Failed to ioremap\n");
-                       continue;
-               }
-
-               simple_map_init(&sbc82xx_flash_map[i]);
-
-               sbcmtd[i] = do_map_probe("cfi_probe", &sbc82xx_flash_map[i]);
-
-               if (!sbcmtd[i])
-                       continue;
-
-               sbcmtd[i]->owner = THIS_MODULE;
-
-               /* No partitioning detected. Use default */
-               if (i == 2) {
-                       defparts = NULL;
-                       nr_parts = 0;
-               } else if (i == bigflash) {
-                       defparts = bigflash_parts;
-                       nr_parts = ARRAY_SIZE(bigflash_parts);
-               } else {
-                       defparts = smallflash_parts;
-                       nr_parts = ARRAY_SIZE(smallflash_parts);
-               }
-
-               mtd_device_parse_register(sbcmtd[i], part_probes, NULL,
-                                         defparts, nr_parts);
-       }
-       return 0;
-}
-
-static void __exit cleanup_sbc82xx_flash(void)
-{
-       int i;
-
-       for (i=0; i<3; i++) {
-               if (!sbcmtd[i])
-                       continue;
-
-               mtd_device_unregister(sbcmtd[i]);
-
-               map_destroy(sbcmtd[i]);
-
-               iounmap((void *)sbc82xx_flash_map[i].virt);
-               sbc82xx_flash_map[i].virt = 0;
-       }
-}
-
-module_init(init_sbc82xx_flash);
-module_exit(cleanup_sbc82xx_flash);
-
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
-MODULE_DESCRIPTION("Flash map driver for WindRiver PowerQUICC II");
index 575730744fdb3ce83dc8e4a78cf65cefb3413fdc..ec794a72975dd886205f2460e2eaba08089a8daf 100644 (file)
@@ -858,6 +858,27 @@ int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
 }
 EXPORT_SYMBOL_GPL(mtd_panic_write);
 
+int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
+{
+       int ret_code;
+       ops->retlen = ops->oobretlen = 0;
+       if (!mtd->_read_oob)
+               return -EOPNOTSUPP;
+       /*
+        * In cases where ops->datbuf != NULL, mtd->_read_oob() has semantics
+        * similar to mtd->_read(), returning a non-negative integer
+        * representing max bitflips. In other cases, mtd->_read_oob() may
+        * return -EUCLEAN. In all cases, perform similar logic to mtd_read().
+        */
+       ret_code = mtd->_read_oob(mtd, from, ops);
+       if (unlikely(ret_code < 0))
+               return ret_code;
+       if (mtd->ecc_strength == 0)
+               return 0;       /* device lacks ecc */
+       return ret_code >= mtd->bitflip_threshold ? -EUCLEAN : 0;
+}
+EXPORT_SYMBOL_GPL(mtd_read_oob);
+
 /*
  * Method to access the protection register area, present in some flash
  * devices. The user data is one time programmable but the factory data is read
index 551e316e4454d99f9b552a2924bea045784c7a8c..788f00be8d07d9a7724e1ab1e771d8a33fde75bd 100644 (file)
@@ -169,14 +169,7 @@ static void mtdoops_workfunc_erase(struct work_struct *work)
                        cxt->nextpage = 0;
        }
 
-       while (1) {
-               ret = mtd_block_isbad(mtd, cxt->nextpage * record_size);
-               if (!ret)
-                       break;
-               if (ret < 0) {
-                       printk(KERN_ERR "mtdoops: block_isbad failed, aborting\n");
-                       return;
-               }
+       while ((ret = mtd_block_isbad(mtd, cxt->nextpage * record_size)) > 0) {
 badblock:
                printk(KERN_WARNING "mtdoops: bad block at %08lx\n",
                       cxt->nextpage * record_size);
@@ -190,6 +183,11 @@ badblock:
                }
        }
 
+       if (ret < 0) {
+               printk(KERN_ERR "mtdoops: mtd_block_isbad failed, aborting\n");
+               return;
+       }
+
        for (j = 0, ret = -1; (j < 3) && (ret < 0); j++)
                ret = mtdoops_erase_block(cxt, cxt->nextpage * record_size);
 
index 31bb7e5b504aa8f05e31472787d2dac7aff9659f..588e98930aac65cde559808eeba1bab57e94557a 100644 (file)
@@ -406,53 +406,35 @@ config MTD_NAND_ATMEL
        help
          Enables support for NAND Flash / Smart Media Card interface
          on Atmel AT91 and AVR32 processors.
-choice
-       prompt "ECC management for NAND Flash / SmartMedia on AT91 / AVR32"
-       depends on MTD_NAND_ATMEL
 
-config MTD_NAND_ATMEL_ECC_HW
-       bool "Hardware ECC"
-       depends on ARCH_AT91SAM9263 || ARCH_AT91SAM9260 || AVR32
+config MTD_NAND_PXA3xx
+       tristate "Support for NAND flash devices on PXA3xx"
+       depends on PXA3xx || ARCH_MMP
        help
-         Use hardware ECC instead of software ECC when the chip
-         supports it.
-
-         The hardware ECC controller is capable of single bit error
-         correction and 2-bit random detection per page.
-
-         NB : hardware and software ECC schemes are incompatible.
-         If you switch from one to another, you'll have to erase your
-         mtd partition.
-
-         If unsure, say Y
+         This enables the driver for the NAND flash device found on
+         PXA3xx processors
 
-config MTD_NAND_ATMEL_ECC_SOFT
-       bool "Software ECC"
+config MTD_NAND_SLC_LPC32XX
+       tristate "NXP LPC32xx SLC Controller"
+       depends on ARCH_LPC32XX
        help
-         Use software ECC.
+         Enables support for NXP's LPC32XX SLC (i.e. for Single Level Cell
+         chips) NAND controller. This is the default for the PHYTEC 3250
+         reference board which contains a NAND256R3A2CZA6 chip.
 
-         NB : hardware and software ECC schemes are incompatible.
-         If you switch from one to another, you'll have to erase your
-         mtd partition.
+         Please check the actual NAND chip connected and its support
+         by the SLC NAND controller.
 
-config MTD_NAND_ATMEL_ECC_NONE
-       bool "No ECC (testing only, DANGEROUS)"
-       depends on DEBUG_KERNEL
+config MTD_NAND_MLC_LPC32XX
+       tristate "NXP LPC32xx MLC Controller"
+       depends on ARCH_LPC32XX
        help
-         No ECC will be used.
-         It's not a good idea and it should be reserved for testing
-         purpose only.
+         Uses the LPC32XX MLC (i.e. for Multi Level Cell chips) NAND
+         controller. This is the default for the WORK92105 controller
+         board.
 
-         If unsure, say N
-
-endchoice
-
-config MTD_NAND_PXA3xx
-       tristate "Support for NAND flash devices on PXA3xx"
-       depends on PXA3xx || ARCH_MMP
-       help
-         This enables the driver for the NAND flash device found on
-         PXA3xx processors
+         Please check the actual NAND chip connected and its support
+         by the MLC NAND controller.
 
 config MTD_NAND_CM_X270
        tristate "Support for NAND Flash on CM-X270 modules"
@@ -480,7 +462,7 @@ config MTD_NAND_NANDSIM
 
 config MTD_NAND_GPMI_NAND
         bool "GPMI NAND Flash Controller driver"
-        depends on MTD_NAND && (SOC_IMX23 || SOC_IMX28 || SOC_IMX6Q)
+        depends on MTD_NAND && MXS_DMA
         help
         Enables NAND Flash support for IMX23 or IMX28.
         The GPMI controller is very powerful, with the help of BCH
@@ -550,7 +532,7 @@ config MTD_NAND_MPC5121_NFC
 
 config MTD_NAND_MXC
        tristate "MXC NAND support"
-       depends on IMX_HAVE_PLATFORM_MXC_NAND
+       depends on ARCH_MXC
        help
          This enables the driver for the NAND flash controller on the
          MXC processors.
index d4b4d8739bd8e88584e4b8f425d7cc9234b3e304..ddee81811b4a1f493a05a35878fa138012c30b3d 100644 (file)
@@ -40,6 +40,8 @@ obj-$(CONFIG_MTD_NAND_ORION)          += orion_nand.o
 obj-$(CONFIG_MTD_NAND_FSL_ELBC)                += fsl_elbc_nand.o
 obj-$(CONFIG_MTD_NAND_FSL_IFC)         += fsl_ifc_nand.o
 obj-$(CONFIG_MTD_NAND_FSL_UPM)         += fsl_upm.o
+obj-$(CONFIG_MTD_NAND_SLC_LPC32XX)      += lpc32xx_slc.o
+obj-$(CONFIG_MTD_NAND_MLC_LPC32XX)      += lpc32xx_mlc.o
 obj-$(CONFIG_MTD_NAND_SH_FLCTL)                += sh_flctl.o
 obj-$(CONFIG_MTD_NAND_MXC)             += mxc_nand.o
 obj-$(CONFIG_MTD_NAND_SOCRATES)                += socrates_nand.o
index 97ac6712bb1926c6ff8e31292cc3c362d4d53d9d..647275524e09fb6b48740e313ce133d11479ad1c 100644 (file)
@@ -1,20 +1,22 @@
 /*
- *  Copyright (C) 2003 Rick Bronson
+ *  Copyright Â© 2003 Rick Bronson
  *
  *  Derived from drivers/mtd/nand/autcpu12.c
- *      Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
+ *      Copyright Â© 2001 Thomas Gleixner (gleixner@autronix.de)
  *
  *  Derived from drivers/mtd/spia.c
- *      Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
+ *      Copyright Â© 2000 Steven J. Hill (sjhill@cotw.com)
  *
  *
  *  Add Hardware ECC support for AT91SAM9260 / AT91SAM9263
- *     Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright (C) 2007
+ *     Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright Â© 2007
  *
  *     Derived from Das U-Boot source code
  *                     (u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c)
- *     (C) Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas
+ *     Â© Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas
  *
+ *  Add Programmable Multibit ECC support for various AT91 SoC
+ *     Â© Copyright 2012 ATMEL, Hong Xu
  *
  * 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
@@ -93,8 +95,36 @@ struct atmel_nand_host {
 
        struct completion       comp;
        struct dma_chan         *dma_chan;
+
+       bool                    has_pmecc;
+       u8                      pmecc_corr_cap;
+       u16                     pmecc_sector_size;
+       u32                     pmecc_lookup_table_offset;
+
+       int                     pmecc_bytes_per_sector;
+       int                     pmecc_sector_number;
+       int                     pmecc_degree;   /* Degree of remainders */
+       int                     pmecc_cw_len;   /* Length of codeword */
+
+       void __iomem            *pmerrloc_base;
+       void __iomem            *pmecc_rom_base;
+
+       /* lookup table for alpha_to and index_of */
+       void __iomem            *pmecc_alpha_to;
+       void __iomem            *pmecc_index_of;
+
+       /* data for pmecc computation */
+       int16_t                 *pmecc_partial_syn;
+       int16_t                 *pmecc_si;
+       int16_t                 *pmecc_smu;     /* Sigma table */
+       int16_t                 *pmecc_lmu;     /* polynomal order */
+       int                     *pmecc_mu;
+       int                     *pmecc_dmu;
+       int                     *pmecc_delta;
 };
 
+static struct nand_ecclayout atmel_pmecc_oobinfo;
+
 static int cpu_has_dma(void)
 {
        return cpu_is_at91sam9rl() || cpu_is_at91sam9g45();
@@ -287,6 +317,703 @@ static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
                atmel_write_buf8(mtd, buf, len);
 }
 
+/*
+ * Return number of ecc bytes per sector according to sector size and
+ * correction capability
+ *
+ * Following table shows what at91 PMECC supported:
+ * Correction Capability       Sector_512_bytes        Sector_1024_bytes
+ * =====================       ================        =================
+ *                2-bits                 4-bytes                  4-bytes
+ *                4-bits                 7-bytes                  7-bytes
+ *                8-bits                13-bytes                 14-bytes
+ *               12-bits                20-bytes                 21-bytes
+ *               24-bits                39-bytes                 42-bytes
+ */
+static int __devinit 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)
+{
+       int i;
+
+       layout->eccbytes = ecc_len;
+
+       /* ECC will occupy the last ecc_len bytes continuously */
+       for (i = 0; i < ecc_len; i++)
+               layout->eccpos[i] = oobsize - ecc_len + i;
+
+       layout->oobfree[0].offset = 2;
+       layout->oobfree[0].length =
+               oobsize - ecc_len - layout->oobfree[0].offset;
+}
+
+static void __devinit __iomem *pmecc_get_alpha_to(struct atmel_nand_host *host)
+{
+       int table_size;
+
+       table_size = host->pmecc_sector_size == 512 ?
+               PMECC_LOOKUP_TABLE_SIZE_512 : PMECC_LOOKUP_TABLE_SIZE_1024;
+
+       return host->pmecc_rom_base + host->pmecc_lookup_table_offset +
+                       table_size * sizeof(int16_t);
+}
+
+static void pmecc_data_free(struct atmel_nand_host *host)
+{
+       kfree(host->pmecc_partial_syn);
+       kfree(host->pmecc_si);
+       kfree(host->pmecc_lmu);
+       kfree(host->pmecc_smu);
+       kfree(host->pmecc_mu);
+       kfree(host->pmecc_dmu);
+       kfree(host->pmecc_delta);
+}
+
+static int __devinit pmecc_data_alloc(struct atmel_nand_host *host)
+{
+       const int cap = host->pmecc_corr_cap;
+
+       host->pmecc_partial_syn = kzalloc((2 * cap + 1) * sizeof(int16_t),
+                                       GFP_KERNEL);
+       host->pmecc_si = kzalloc((2 * cap + 1) * sizeof(int16_t), GFP_KERNEL);
+       host->pmecc_lmu = kzalloc((cap + 1) * sizeof(int16_t), GFP_KERNEL);
+       host->pmecc_smu = kzalloc((cap + 2) * (2 * cap + 1) * sizeof(int16_t),
+                                       GFP_KERNEL);
+       host->pmecc_mu = kzalloc((cap + 1) * sizeof(int), GFP_KERNEL);
+       host->pmecc_dmu = kzalloc((cap + 1) * sizeof(int), GFP_KERNEL);
+       host->pmecc_delta = kzalloc((cap + 1) * sizeof(int), GFP_KERNEL);
+
+       if (host->pmecc_partial_syn &&
+                       host->pmecc_si &&
+                       host->pmecc_lmu &&
+                       host->pmecc_smu &&
+                       host->pmecc_mu &&
+                       host->pmecc_dmu &&
+                       host->pmecc_delta)
+               return 0;
+
+       /* error happened */
+       pmecc_data_free(host);
+       return -ENOMEM;
+}
+
+static void pmecc_gen_syndrome(struct mtd_info *mtd, int sector)
+{
+       struct nand_chip *nand_chip = mtd->priv;
+       struct atmel_nand_host *host = nand_chip->priv;
+       int i;
+       uint32_t value;
+
+       /* Fill odd syndromes */
+       for (i = 0; i < host->pmecc_corr_cap; i++) {
+               value = pmecc_readl_rem_relaxed(host->ecc, sector, i / 2);
+               if (i & 1)
+                       value >>= 16;
+               value &= 0xffff;
+               host->pmecc_partial_syn[(2 * i) + 1] = (int16_t)value;
+       }
+}
+
+static void pmecc_substitute(struct mtd_info *mtd)
+{
+       struct nand_chip *nand_chip = mtd->priv;
+       struct atmel_nand_host *host = nand_chip->priv;
+       int16_t __iomem *alpha_to = host->pmecc_alpha_to;
+       int16_t __iomem *index_of = host->pmecc_index_of;
+       int16_t *partial_syn = host->pmecc_partial_syn;
+       const int cap = host->pmecc_corr_cap;
+       int16_t *si;
+       int i, j;
+
+       /* si[] is a table that holds the current syndrome value,
+        * an element of that table belongs to the field
+        */
+       si = host->pmecc_si;
+
+       memset(&si[1], 0, sizeof(int16_t) * (2 * cap - 1));
+
+       /* Computation 2t syndromes based on S(x) */
+       /* Odd syndromes */
+       for (i = 1; i < 2 * cap; i += 2) {
+               for (j = 0; j < host->pmecc_degree; j++) {
+                       if (partial_syn[i] & ((unsigned short)0x1 << j))
+                               si[i] = readw_relaxed(alpha_to + i * j) ^ si[i];
+               }
+       }
+       /* Even syndrome = (Odd syndrome) ** 2 */
+       for (i = 2, j = 1; j <= cap; i = ++j << 1) {
+               if (si[j] == 0) {
+                       si[i] = 0;
+               } else {
+                       int16_t tmp;
+
+                       tmp = readw_relaxed(index_of + si[j]);
+                       tmp = (tmp * 2) % host->pmecc_cw_len;
+                       si[i] = readw_relaxed(alpha_to + tmp);
+               }
+       }
+
+       return;
+}
+
+static void pmecc_get_sigma(struct mtd_info *mtd)
+{
+       struct nand_chip *nand_chip = mtd->priv;
+       struct atmel_nand_host *host = nand_chip->priv;
+
+       int16_t *lmu = host->pmecc_lmu;
+       int16_t *si = host->pmecc_si;
+       int *mu = host->pmecc_mu;
+       int *dmu = host->pmecc_dmu;     /* Discrepancy */
+       int *delta = host->pmecc_delta; /* Delta order */
+       int cw_len = host->pmecc_cw_len;
+       const int16_t cap = host->pmecc_corr_cap;
+       const int num = 2 * cap + 1;
+       int16_t __iomem *index_of = host->pmecc_index_of;
+       int16_t __iomem *alpha_to = host->pmecc_alpha_to;
+       int i, j, k;
+       uint32_t dmu_0_count, tmp;
+       int16_t *smu = host->pmecc_smu;
+
+       /* index of largest delta */
+       int ro;
+       int largest;
+       int diff;
+
+       dmu_0_count = 0;
+
+       /* First Row */
+
+       /* Mu */
+       mu[0] = -1;
+
+       memset(smu, 0, sizeof(int16_t) * num);
+       smu[0] = 1;
+
+       /* discrepancy set to 1 */
+       dmu[0] = 1;
+       /* polynom order set to 0 */
+       lmu[0] = 0;
+       delta[0] = (mu[0] * 2 - lmu[0]) >> 1;
+
+       /* Second Row */
+
+       /* Mu */
+       mu[1] = 0;
+       /* Sigma(x) set to 1 */
+       memset(&smu[num], 0, sizeof(int16_t) * num);
+       smu[num] = 1;
+
+       /* discrepancy set to S1 */
+       dmu[1] = si[1];
+
+       /* polynom order set to 0 */
+       lmu[1] = 0;
+
+       delta[1] = (mu[1] * 2 - lmu[1]) >> 1;
+
+       /* Init the Sigma(x) last row */
+       memset(&smu[(cap + 1) * num], 0, sizeof(int16_t) * num);
+
+       for (i = 1; i <= cap; i++) {
+               mu[i + 1] = i << 1;
+               /* Begin Computing Sigma (Mu+1) and L(mu) */
+               /* check if discrepancy is set to 0 */
+               if (dmu[i] == 0) {
+                       dmu_0_count++;
+
+                       tmp = ((cap - (lmu[i] >> 1) - 1) / 2);
+                       if ((cap - (lmu[i] >> 1) - 1) & 0x1)
+                               tmp += 2;
+                       else
+                               tmp += 1;
+
+                       if (dmu_0_count == tmp) {
+                               for (j = 0; j <= (lmu[i] >> 1) + 1; j++)
+                                       smu[(cap + 1) * num + j] =
+                                                       smu[i * num + j];
+
+                               lmu[cap + 1] = lmu[i];
+                               return;
+                       }
+
+                       /* copy polynom */
+                       for (j = 0; j <= lmu[i] >> 1; j++)
+                               smu[(i + 1) * num + j] = smu[i * num + j];
+
+                       /* copy previous polynom order to the next */
+                       lmu[i + 1] = lmu[i];
+               } else {
+                       ro = 0;
+                       largest = -1;
+                       /* find largest delta with dmu != 0 */
+                       for (j = 0; j < i; j++) {
+                               if ((dmu[j]) && (delta[j] > largest)) {
+                                       largest = delta[j];
+                                       ro = j;
+                               }
+                       }
+
+                       /* compute difference */
+                       diff = (mu[i] - mu[ro]);
+
+                       /* Compute degree of the new smu polynomial */
+                       if ((lmu[i] >> 1) > ((lmu[ro] >> 1) + diff))
+                               lmu[i + 1] = lmu[i];
+                       else
+                               lmu[i + 1] = ((lmu[ro] >> 1) + diff) * 2;
+
+                       /* Init smu[i+1] with 0 */
+                       for (k = 0; k < num; k++)
+                               smu[(i + 1) * num + k] = 0;
+
+                       /* Compute smu[i+1] */
+                       for (k = 0; k <= lmu[ro] >> 1; k++) {
+                               int16_t a, b, c;
+
+                               if (!(smu[ro * num + k] && dmu[i]))
+                                       continue;
+                               a = readw_relaxed(index_of + dmu[i]);
+                               b = readw_relaxed(index_of + dmu[ro]);
+                               c = readw_relaxed(index_of + smu[ro * num + k]);
+                               tmp = a + (cw_len - b) + c;
+                               a = readw_relaxed(alpha_to + tmp % cw_len);
+                               smu[(i + 1) * num + (k + diff)] = a;
+                       }
+
+                       for (k = 0; k <= lmu[i] >> 1; k++)
+                               smu[(i + 1) * num + k] ^= smu[i * num + k];
+               }
+
+               /* End Computing Sigma (Mu+1) and L(mu) */
+               /* In either case compute delta */
+               delta[i + 1] = (mu[i + 1] * 2 - lmu[i + 1]) >> 1;
+
+               /* Do not compute discrepancy for the last iteration */
+               if (i >= cap)
+                       continue;
+
+               for (k = 0; k <= (lmu[i + 1] >> 1); k++) {
+                       tmp = 2 * (i - 1);
+                       if (k == 0) {
+                               dmu[i + 1] = si[tmp + 3];
+                       } else if (smu[(i + 1) * num + k] && si[tmp + 3 - k]) {
+                               int16_t a, b, c;
+                               a = readw_relaxed(index_of +
+                                               smu[(i + 1) * num + k]);
+                               b = si[2 * (i - 1) + 3 - k];
+                               c = readw_relaxed(index_of + b);
+                               tmp = a + c;
+                               tmp %= cw_len;
+                               dmu[i + 1] = readw_relaxed(alpha_to + tmp) ^
+                                       dmu[i + 1];
+                       }
+               }
+       }
+
+       return;
+}
+
+static int pmecc_err_location(struct mtd_info *mtd)
+{
+       struct nand_chip *nand_chip = mtd->priv;
+       struct atmel_nand_host *host = nand_chip->priv;
+       unsigned long end_time;
+       const int cap = host->pmecc_corr_cap;
+       const int num = 2 * cap + 1;
+       int sector_size = host->pmecc_sector_size;
+       int err_nbr = 0;        /* number of error */
+       int roots_nbr;          /* number of roots */
+       int i;
+       uint32_t val;
+       int16_t *smu = host->pmecc_smu;
+
+       pmerrloc_writel(host->pmerrloc_base, ELDIS, PMERRLOC_DISABLE);
+
+       for (i = 0; i <= host->pmecc_lmu[cap + 1] >> 1; i++) {
+               pmerrloc_writel_sigma_relaxed(host->pmerrloc_base, i,
+                                     smu[(cap + 1) * num + i]);
+               err_nbr++;
+       }
+
+       val = (err_nbr - 1) << 16;
+       if (sector_size == 1024)
+               val |= 1;
+
+       pmerrloc_writel(host->pmerrloc_base, ELCFG, val);
+       pmerrloc_writel(host->pmerrloc_base, ELEN,
+                       sector_size * 8 + host->pmecc_degree * cap);
+
+       end_time = jiffies + msecs_to_jiffies(PMECC_MAX_TIMEOUT_MS);
+       while (!(pmerrloc_readl_relaxed(host->pmerrloc_base, ELISR)
+                & PMERRLOC_CALC_DONE)) {
+               if (unlikely(time_after(jiffies, end_time))) {
+                       dev_err(host->dev, "PMECC: Timeout to calculate error location.\n");
+                       return -1;
+               }
+               cpu_relax();
+       }
+
+       roots_nbr = (pmerrloc_readl_relaxed(host->pmerrloc_base, ELISR)
+               & PMERRLOC_ERR_NUM_MASK) >> 8;
+       /* Number of roots == degree of smu hence <= cap */
+       if (roots_nbr == host->pmecc_lmu[cap + 1] >> 1)
+               return err_nbr - 1;
+
+       /* Number of roots does not match the degree of smu
+        * unable to correct error */
+       return -1;
+}
+
+static void pmecc_correct_data(struct mtd_info *mtd, uint8_t *buf, uint8_t *ecc,
+               int sector_num, int extra_bytes, int err_nbr)
+{
+       struct nand_chip *nand_chip = mtd->priv;
+       struct atmel_nand_host *host = nand_chip->priv;
+       int i = 0;
+       int byte_pos, bit_pos, sector_size, pos;
+       uint32_t tmp;
+       uint8_t err_byte;
+
+       sector_size = host->pmecc_sector_size;
+
+       while (err_nbr) {
+               tmp = pmerrloc_readl_el_relaxed(host->pmerrloc_base, i) - 1;
+               byte_pos = tmp / 8;
+               bit_pos  = tmp % 8;
+
+               if (byte_pos >= (sector_size + extra_bytes))
+                       BUG();  /* should never happen */
+
+               if (byte_pos < sector_size) {
+                       err_byte = *(buf + byte_pos);
+                       *(buf + byte_pos) ^= (1 << bit_pos);
+
+                       pos = sector_num * host->pmecc_sector_size + byte_pos;
+                       dev_info(host->dev, "Bit flip in data area, byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
+                               pos, bit_pos, err_byte, *(buf + byte_pos));
+               } else {
+                       /* Bit flip in OOB area */
+                       tmp = sector_num * host->pmecc_bytes_per_sector
+                                       + (byte_pos - sector_size);
+                       err_byte = ecc[tmp];
+                       ecc[tmp] ^= (1 << bit_pos);
+
+                       pos = tmp + nand_chip->ecc.layout->eccpos[0];
+                       dev_info(host->dev, "Bit flip in OOB, oob_byte_pos: %d, bit_pos: %d, 0x%02x -> 0x%02x\n",
+                               pos, bit_pos, err_byte, ecc[tmp]);
+               }
+
+               i++;
+               err_nbr--;
+       }
+
+       return;
+}
+
+static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf,
+       u8 *ecc)
+{
+       struct nand_chip *nand_chip = mtd->priv;
+       struct atmel_nand_host *host = nand_chip->priv;
+       int i, err_nbr, eccbytes;
+       uint8_t *buf_pos;
+
+       eccbytes = nand_chip->ecc.bytes;
+       for (i = 0; i < eccbytes; i++)
+               if (ecc[i] != 0xff)
+                       goto normal_check;
+       /* Erased page, return OK */
+       return 0;
+
+normal_check:
+       for (i = 0; i < host->pmecc_sector_number; i++) {
+               err_nbr = 0;
+               if (pmecc_stat & 0x1) {
+                       buf_pos = buf + i * host->pmecc_sector_size;
+
+                       pmecc_gen_syndrome(mtd, i);
+                       pmecc_substitute(mtd);
+                       pmecc_get_sigma(mtd);
+
+                       err_nbr = pmecc_err_location(mtd);
+                       if (err_nbr == -1) {
+                               dev_err(host->dev, "PMECC: Too many errors\n");
+                               mtd->ecc_stats.failed++;
+                               return -EIO;
+                       } else {
+                               pmecc_correct_data(mtd, buf_pos, ecc, i,
+                                       host->pmecc_bytes_per_sector, err_nbr);
+                               mtd->ecc_stats.corrected += err_nbr;
+                       }
+               }
+               pmecc_stat >>= 1;
+       }
+
+       return 0;
+}
+
+static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
+       struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
+{
+       struct atmel_nand_host *host = chip->priv;
+       int eccsize = chip->ecc.size;
+       uint8_t *oob = chip->oob_poi;
+       uint32_t *eccpos = chip->ecc.layout->eccpos;
+       uint32_t stat;
+       unsigned long end_time;
+
+       pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
+       pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
+       pmecc_writel(host->ecc, CFG, (pmecc_readl_relaxed(host->ecc, CFG)
+               & ~PMECC_CFG_WRITE_OP) | PMECC_CFG_AUTO_ENABLE);
+
+       pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
+       pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA);
+
+       chip->read_buf(mtd, buf, eccsize);
+       chip->read_buf(mtd, oob, mtd->oobsize);
+
+       end_time = jiffies + msecs_to_jiffies(PMECC_MAX_TIMEOUT_MS);
+       while ((pmecc_readl_relaxed(host->ecc, SR) & PMECC_SR_BUSY)) {
+               if (unlikely(time_after(jiffies, end_time))) {
+                       dev_err(host->dev, "PMECC: Timeout to get error status.\n");
+                       return -EIO;
+               }
+               cpu_relax();
+       }
+
+       stat = pmecc_readl_relaxed(host->ecc, ISR);
+       if (stat != 0)
+               if (pmecc_correction(mtd, stat, buf, &oob[eccpos[0]]) != 0)
+                       return -EIO;
+
+       return 0;
+}
+
+static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
+               struct nand_chip *chip, const uint8_t *buf, int oob_required)
+{
+       struct atmel_nand_host *host = chip->priv;
+       uint32_t *eccpos = chip->ecc.layout->eccpos;
+       int i, j;
+       unsigned long end_time;
+
+       pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
+       pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
+
+       pmecc_writel(host->ecc, CFG, (pmecc_readl_relaxed(host->ecc, CFG) |
+               PMECC_CFG_WRITE_OP) & ~PMECC_CFG_AUTO_ENABLE);
+
+       pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
+       pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA);
+
+       chip->write_buf(mtd, (u8 *)buf, mtd->writesize);
+
+       end_time = jiffies + msecs_to_jiffies(PMECC_MAX_TIMEOUT_MS);
+       while ((pmecc_readl_relaxed(host->ecc, SR) & PMECC_SR_BUSY)) {
+               if (unlikely(time_after(jiffies, end_time))) {
+                       dev_err(host->dev, "PMECC: Timeout to get ECC value.\n");
+                       return -EIO;
+               }
+               cpu_relax();
+       }
+
+       for (i = 0; i < host->pmecc_sector_number; i++) {
+               for (j = 0; j < host->pmecc_bytes_per_sector; j++) {
+                       int pos;
+
+                       pos = i * host->pmecc_bytes_per_sector + j;
+                       chip->oob_poi[eccpos[pos]] =
+                               pmecc_readb_ecc_relaxed(host->ecc, i, j);
+               }
+       }
+       chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+       return 0;
+}
+
+static void atmel_pmecc_core_init(struct mtd_info *mtd)
+{
+       struct nand_chip *nand_chip = mtd->priv;
+       struct atmel_nand_host *host = nand_chip->priv;
+       uint32_t val = 0;
+       struct nand_ecclayout *ecc_layout;
+
+       pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
+       pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
+
+       switch (host->pmecc_corr_cap) {
+       case 2:
+               val = PMECC_CFG_BCH_ERR2;
+               break;
+       case 4:
+               val = PMECC_CFG_BCH_ERR4;
+               break;
+       case 8:
+               val = PMECC_CFG_BCH_ERR8;
+               break;
+       case 12:
+               val = PMECC_CFG_BCH_ERR12;
+               break;
+       case 24:
+               val = PMECC_CFG_BCH_ERR24;
+               break;
+       }
+
+       if (host->pmecc_sector_size == 512)
+               val |= PMECC_CFG_SECTOR512;
+       else if (host->pmecc_sector_size == 1024)
+               val |= PMECC_CFG_SECTOR1024;
+
+       switch (host->pmecc_sector_number) {
+       case 1:
+               val |= PMECC_CFG_PAGE_1SECTOR;
+               break;
+       case 2:
+               val |= PMECC_CFG_PAGE_2SECTORS;
+               break;
+       case 4:
+               val |= PMECC_CFG_PAGE_4SECTORS;
+               break;
+       case 8:
+               val |= PMECC_CFG_PAGE_8SECTORS;
+               break;
+       }
+
+       val |= (PMECC_CFG_READ_OP | PMECC_CFG_SPARE_DISABLE
+               | PMECC_CFG_AUTO_DISABLE);
+       pmecc_writel(host->ecc, CFG, val);
+
+       ecc_layout = nand_chip->ecc.layout;
+       pmecc_writel(host->ecc, SAREA, mtd->oobsize - 1);
+       pmecc_writel(host->ecc, SADDR, ecc_layout->eccpos[0]);
+       pmecc_writel(host->ecc, EADDR,
+                       ecc_layout->eccpos[ecc_layout->eccbytes - 1]);
+       /* See datasheet about PMECC Clock Control Register */
+       pmecc_writel(host->ecc, CLK, 2);
+       pmecc_writel(host->ecc, IDR, 0xff);
+       pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
+}
+
+static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
+                                        struct atmel_nand_host *host)
+{
+       struct mtd_info *mtd = &host->mtd;
+       struct nand_chip *nand_chip = &host->nand_chip;
+       struct resource *regs, *regs_pmerr, *regs_rom;
+       int cap, sector_size, err_no;
+
+       cap = host->pmecc_corr_cap;
+       sector_size = host->pmecc_sector_size;
+       dev_info(host->dev, "Initialize PMECC params, cap: %d, sector: %d\n",
+                cap, sector_size);
+
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (!regs) {
+               dev_warn(host->dev,
+                       "Can't get I/O resource regs for PMECC controller, rolling back on software ECC\n");
+               nand_chip->ecc.mode = NAND_ECC_SOFT;
+               return 0;
+       }
+
+       host->ecc = ioremap(regs->start, resource_size(regs));
+       if (host->ecc == NULL) {
+               dev_err(host->dev, "ioremap failed\n");
+               err_no = -EIO;
+               goto err_pmecc_ioremap;
+       }
+
+       regs_pmerr = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+       regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+       if (regs_pmerr && regs_rom) {
+               host->pmerrloc_base = ioremap(regs_pmerr->start,
+                       resource_size(regs_pmerr));
+               host->pmecc_rom_base = ioremap(regs_rom->start,
+                       resource_size(regs_rom));
+       }
+
+       if (!host->pmerrloc_base || !host->pmecc_rom_base) {
+               dev_err(host->dev,
+                       "Can not get I/O resource for PMECC ERRLOC controller or ROM!\n");
+               err_no = -EIO;
+               goto err_pmloc_ioremap;
+       }
+
+       /* ECC is calculated for the whole page (1 step) */
+       nand_chip->ecc.size = mtd->writesize;
+
+       /* set ECC page size and oob layout */
+       switch (mtd->writesize) {
+       case 2048:
+               host->pmecc_degree = PMECC_GF_DIMENSION_13;
+               host->pmecc_cw_len = (1 << host->pmecc_degree) - 1;
+               host->pmecc_sector_number = mtd->writesize / sector_size;
+               host->pmecc_bytes_per_sector = pmecc_get_ecc_bytes(
+                       cap, sector_size);
+               host->pmecc_alpha_to = pmecc_get_alpha_to(host);
+               host->pmecc_index_of = host->pmecc_rom_base +
+                       host->pmecc_lookup_table_offset;
+
+               nand_chip->ecc.steps = 1;
+               nand_chip->ecc.strength = cap;
+               nand_chip->ecc.bytes = host->pmecc_bytes_per_sector *
+                                      host->pmecc_sector_number;
+               if (nand_chip->ecc.bytes > mtd->oobsize - 2) {
+                       dev_err(host->dev, "No room for ECC bytes\n");
+                       err_no = -EINVAL;
+                       goto err_no_ecc_room;
+               }
+               pmecc_config_ecc_layout(&atmel_pmecc_oobinfo,
+                                       mtd->oobsize,
+                                       nand_chip->ecc.bytes);
+               nand_chip->ecc.layout = &atmel_pmecc_oobinfo;
+               break;
+       case 512:
+       case 1024:
+       case 4096:
+               /* TODO */
+               dev_warn(host->dev,
+                       "Unsupported page size for PMECC, use Software ECC\n");
+       default:
+               /* page size not handled by HW ECC */
+               /* switching back to soft ECC */
+               nand_chip->ecc.mode = NAND_ECC_SOFT;
+               return 0;
+       }
+
+       /* Allocate data for PMECC computation */
+       err_no = pmecc_data_alloc(host);
+       if (err_no) {
+               dev_err(host->dev,
+                               "Cannot allocate memory for PMECC computation!\n");
+               goto err_pmecc_data_alloc;
+       }
+
+       nand_chip->ecc.read_page = atmel_nand_pmecc_read_page;
+       nand_chip->ecc.write_page = atmel_nand_pmecc_write_page;
+
+       atmel_pmecc_core_init(mtd);
+
+       return 0;
+
+err_pmecc_data_alloc:
+err_no_ecc_room:
+err_pmloc_ioremap:
+       iounmap(host->ecc);
+       if (host->pmerrloc_base)
+               iounmap(host->pmerrloc_base);
+       if (host->pmecc_rom_base)
+               iounmap(host->pmecc_rom_base);
+err_pmecc_ioremap:
+       return err_no;
+}
+
 /*
  * Calculate HW ECC
  *
@@ -481,7 +1208,8 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode)
 static int __devinit atmel_of_init_port(struct atmel_nand_host *host,
                                         struct device_node *np)
 {
-       u32 val;
+       u32 val, table_offset;
+       u32 offset[2];
        int ecc_mode;
        struct atmel_nand_data *board = &host->board;
        enum of_gpio_flags flags;
@@ -517,6 +1245,50 @@ static int __devinit atmel_of_init_port(struct atmel_nand_host *host,
        board->enable_pin = of_get_gpio(np, 1);
        board->det_pin = of_get_gpio(np, 2);
 
+       host->has_pmecc = of_property_read_bool(np, "atmel,has-pmecc");
+
+       if (!(board->ecc_mode == NAND_ECC_HW) || !host->has_pmecc)
+               return 0;       /* Not using PMECC */
+
+       /* use PMECC, get correction capability, sector size and lookup
+        * table offset.
+        */
+       if (of_property_read_u32(np, "atmel,pmecc-cap", &val) != 0) {
+               dev_err(host->dev, "Cannot decide PMECC Capability\n");
+               return -EINVAL;
+       } else if ((val != 2) && (val != 4) && (val != 8) && (val != 12) &&
+           (val != 24)) {
+               dev_err(host->dev,
+                       "Unsupported PMECC correction capability: %d; should be 2, 4, 8, 12 or 24\n",
+                       val);
+               return -EINVAL;
+       }
+       host->pmecc_corr_cap = (u8)val;
+
+       if (of_property_read_u32(np, "atmel,pmecc-sector-size", &val) != 0) {
+               dev_err(host->dev, "Cannot decide PMECC Sector Size\n");
+               return -EINVAL;
+       } else if ((val != 512) && (val != 1024)) {
+               dev_err(host->dev,
+                       "Unsupported PMECC sector size: %d; should be 512 or 1024 bytes\n",
+                       val);
+               return -EINVAL;
+       }
+       host->pmecc_sector_size = (u16)val;
+
+       if (of_property_read_u32_array(np, "atmel,pmecc-lookup-table-offset",
+                       offset, 2) != 0) {
+               dev_err(host->dev, "Cannot get PMECC lookup table offset\n");
+               return -EINVAL;
+       }
+       table_offset = host->pmecc_sector_size == 512 ? offset[0] : offset[1];
+
+       if (!table_offset) {
+               dev_err(host->dev, "Invalid PMECC lookup table offset\n");
+               return -EINVAL;
+       }
+       host->pmecc_lookup_table_offset = table_offset;
+
        return 0;
 }
 #else
@@ -527,6 +1299,66 @@ static int __devinit atmel_of_init_port(struct atmel_nand_host *host,
 }
 #endif
 
+static int __init atmel_hw_nand_init_params(struct platform_device *pdev,
+                                        struct atmel_nand_host *host)
+{
+       struct mtd_info *mtd = &host->mtd;
+       struct nand_chip *nand_chip = &host->nand_chip;
+       struct resource         *regs;
+
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (!regs) {
+               dev_err(host->dev,
+                       "Can't get I/O resource regs, use software ECC\n");
+               nand_chip->ecc.mode = NAND_ECC_SOFT;
+               return 0;
+       }
+
+       host->ecc = ioremap(regs->start, resource_size(regs));
+       if (host->ecc == NULL) {
+               dev_err(host->dev, "ioremap failed\n");
+               return -EIO;
+       }
+
+       /* ECC is calculated for the whole page (1 step) */
+       nand_chip->ecc.size = mtd->writesize;
+
+       /* set ECC page size and oob layout */
+       switch (mtd->writesize) {
+       case 512:
+               nand_chip->ecc.layout = &atmel_oobinfo_small;
+               ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528);
+               break;
+       case 1024:
+               nand_chip->ecc.layout = &atmel_oobinfo_large;
+               ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056);
+               break;
+       case 2048:
+               nand_chip->ecc.layout = &atmel_oobinfo_large;
+               ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112);
+               break;
+       case 4096:
+               nand_chip->ecc.layout = &atmel_oobinfo_large;
+               ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224);
+               break;
+       default:
+               /* page size not handled by HW ECC */
+               /* switching back to soft ECC */
+               nand_chip->ecc.mode = NAND_ECC_SOFT;
+               return 0;
+       }
+
+       /* set up for HW ECC */
+       nand_chip->ecc.calculate = atmel_nand_calculate;
+       nand_chip->ecc.correct = atmel_nand_correct;
+       nand_chip->ecc.hwctl = atmel_nand_hwctl;
+       nand_chip->ecc.read_page = atmel_nand_read_page;
+       nand_chip->ecc.bytes = 4;
+       nand_chip->ecc.strength = 1;
+
+       return 0;
+}
+
 /*
  * Probe for the NAND device.
  */
@@ -535,7 +1367,6 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
        struct atmel_nand_host *host;
        struct mtd_info *mtd;
        struct nand_chip *nand_chip;
-       struct resource *regs;
        struct resource *mem;
        struct mtd_part_parser_data ppdata = {};
        int res;
@@ -587,29 +1418,6 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
                nand_chip->dev_ready = atmel_nand_device_ready;
 
        nand_chip->ecc.mode = host->board.ecc_mode;
-
-       regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-       if (!regs && nand_chip->ecc.mode == NAND_ECC_HW) {
-               printk(KERN_ERR "atmel_nand: can't get I/O resource "
-                               "regs\nFalling back on software ECC\n");
-               nand_chip->ecc.mode = NAND_ECC_SOFT;
-       }
-
-       if (nand_chip->ecc.mode == NAND_ECC_HW) {
-               host->ecc = ioremap(regs->start, resource_size(regs));
-               if (host->ecc == NULL) {
-                       printk(KERN_ERR "atmel_nand: ioremap failed\n");
-                       res = -EIO;
-                       goto err_ecc_ioremap;
-               }
-               nand_chip->ecc.calculate = atmel_nand_calculate;
-               nand_chip->ecc.correct = atmel_nand_correct;
-               nand_chip->ecc.hwctl = atmel_nand_hwctl;
-               nand_chip->ecc.read_page = atmel_nand_read_page;
-               nand_chip->ecc.bytes = 4;
-               nand_chip->ecc.strength = 1;
-       }
-
        nand_chip->chip_delay = 20;             /* 20us command delay time */
 
        if (host->board.bus_width_16)   /* 16-bit bus width */
@@ -661,40 +1469,13 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
        }
 
        if (nand_chip->ecc.mode == NAND_ECC_HW) {
-               /* ECC is calculated for the whole page (1 step) */
-               nand_chip->ecc.size = mtd->writesize;
-
-               /* set ECC page size and oob layout */
-               switch (mtd->writesize) {
-               case 512:
-                       nand_chip->ecc.layout = &atmel_oobinfo_small;
-                       ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528);
-                       break;
-               case 1024:
-                       nand_chip->ecc.layout = &atmel_oobinfo_large;
-                       ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056);
-                       break;
-               case 2048:
-                       nand_chip->ecc.layout = &atmel_oobinfo_large;
-                       ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112);
-                       break;
-               case 4096:
-                       nand_chip->ecc.layout = &atmel_oobinfo_large;
-                       ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224);
-                       break;
-               default:
-                       /* page size not handled by HW ECC */
-                       /* switching back to soft ECC */
-                       nand_chip->ecc.mode = NAND_ECC_SOFT;
-                       nand_chip->ecc.calculate = NULL;
-                       nand_chip->ecc.correct = NULL;
-                       nand_chip->ecc.hwctl = NULL;
-                       nand_chip->ecc.read_page = NULL;
-                       nand_chip->ecc.postpad = 0;
-                       nand_chip->ecc.prepad = 0;
-                       nand_chip->ecc.bytes = 0;
-                       break;
-               }
+               if (host->has_pmecc)
+                       res = atmel_pmecc_nand_init_params(pdev, host);
+               else
+                       res = atmel_hw_nand_init_params(pdev, host);
+
+               if (res != 0)
+                       goto err_hw_ecc;
        }
 
        /* second phase scan */
@@ -711,15 +1492,23 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
                return res;
 
 err_scan_tail:
+       if (host->has_pmecc && host->nand_chip.ecc.mode == NAND_ECC_HW) {
+               pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
+               pmecc_data_free(host);
+       }
+       if (host->ecc)
+               iounmap(host->ecc);
+       if (host->pmerrloc_base)
+               iounmap(host->pmerrloc_base);
+       if (host->pmecc_rom_base)
+               iounmap(host->pmecc_rom_base);
+err_hw_ecc:
 err_scan_ident:
 err_no_card:
        atmel_nand_disable(host);
        platform_set_drvdata(pdev, NULL);
        if (host->dma_chan)
                dma_release_channel(host->dma_chan);
-       if (host->ecc)
-               iounmap(host->ecc);
-err_ecc_ioremap:
        iounmap(host->io_base);
 err_nand_ioremap:
        kfree(host);
@@ -738,8 +1527,19 @@ static int __exit atmel_nand_remove(struct platform_device *pdev)
 
        atmel_nand_disable(host);
 
+       if (host->has_pmecc && host->nand_chip.ecc.mode == NAND_ECC_HW) {
+               pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
+               pmerrloc_writel(host->pmerrloc_base, ELDIS,
+                               PMERRLOC_DISABLE);
+               pmecc_data_free(host);
+       }
+
        if (host->ecc)
                iounmap(host->ecc);
+       if (host->pmecc_rom_base)
+               iounmap(host->pmecc_rom_base);
+       if (host->pmerrloc_base)
+               iounmap(host->pmerrloc_base);
 
        if (host->dma_chan)
                dma_release_channel(host->dma_chan);
index 578c776e135632144c30fc20671c35becdb8b489..8a1e9a686759fb5f2796716e50db3877711c7389 100644 (file)
@@ -3,7 +3,7 @@
  * Based on AT91SAM9260 datasheet revision B.
  *
  * Copyright (C) 2007 Andrew Victor
- * Copyright (C) 2007 Atmel Corporation.
+ * Copyright (C) 2007 - 2012 Atmel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
 #define ATMEL_ECC_NPR          0x10                    /* NParity register */
 #define                ATMEL_ECC_NPARITY       (0xffff << 0)           /* NParity */
 
+/* PMECC Register Definitions */
+#define ATMEL_PMECC_CFG                        0x000   /* Configuration Register */
+#define                PMECC_CFG_BCH_ERR2              (0 << 0)
+#define                PMECC_CFG_BCH_ERR4              (1 << 0)
+#define                PMECC_CFG_BCH_ERR8              (2 << 0)
+#define                PMECC_CFG_BCH_ERR12             (3 << 0)
+#define                PMECC_CFG_BCH_ERR24             (4 << 0)
+
+#define                PMECC_CFG_SECTOR512             (0 << 4)
+#define                PMECC_CFG_SECTOR1024            (1 << 4)
+
+#define                PMECC_CFG_PAGE_1SECTOR          (0 << 8)
+#define                PMECC_CFG_PAGE_2SECTORS         (1 << 8)
+#define                PMECC_CFG_PAGE_4SECTORS         (2 << 8)
+#define                PMECC_CFG_PAGE_8SECTORS         (3 << 8)
+
+#define                PMECC_CFG_READ_OP               (0 << 12)
+#define                PMECC_CFG_WRITE_OP              (1 << 12)
+
+#define                PMECC_CFG_SPARE_ENABLE          (1 << 16)
+#define                PMECC_CFG_SPARE_DISABLE         (0 << 16)
+
+#define                PMECC_CFG_AUTO_ENABLE           (1 << 20)
+#define                PMECC_CFG_AUTO_DISABLE          (0 << 20)
+
+#define ATMEL_PMECC_SAREA              0x004   /* Spare area size */
+#define ATMEL_PMECC_SADDR              0x008   /* PMECC starting address */
+#define ATMEL_PMECC_EADDR              0x00c   /* PMECC ending address */
+#define ATMEL_PMECC_CLK                        0x010   /* PMECC clock control */
+#define                PMECC_CLK_133MHZ                (2 << 0)
+
+#define ATMEL_PMECC_CTRL               0x014   /* PMECC control register */
+#define                PMECC_CTRL_RST                  (1 << 0)
+#define                PMECC_CTRL_DATA                 (1 << 1)
+#define                PMECC_CTRL_USER                 (1 << 2)
+#define                PMECC_CTRL_ENABLE               (1 << 4)
+#define                PMECC_CTRL_DISABLE              (1 << 5)
+
+#define ATMEL_PMECC_SR                 0x018   /* PMECC status register */
+#define                PMECC_SR_BUSY                   (1 << 0)
+#define                PMECC_SR_ENABLE                 (1 << 4)
+
+#define ATMEL_PMECC_IER                        0x01c   /* PMECC interrupt enable */
+#define                PMECC_IER_ENABLE                (1 << 0)
+#define ATMEL_PMECC_IDR                        0x020   /* PMECC interrupt disable */
+#define                PMECC_IER_DISABLE               (1 << 0)
+#define ATMEL_PMECC_IMR                        0x024   /* PMECC interrupt mask */
+#define                PMECC_IER_MASK                  (1 << 0)
+#define ATMEL_PMECC_ISR                        0x028   /* PMECC interrupt status */
+#define ATMEL_PMECC_ECCx               0x040   /* PMECC ECC x */
+#define ATMEL_PMECC_REMx               0x240   /* PMECC REM x */
+
+/* PMERRLOC Register Definitions */
+#define ATMEL_PMERRLOC_ELCFG           0x000   /* Error location config */
+#define                PMERRLOC_ELCFG_SECTOR_512       (0 << 0)
+#define                PMERRLOC_ELCFG_SECTOR_1024      (1 << 0)
+#define                PMERRLOC_ELCFG_NUM_ERRORS(n)    ((n) << 16)
+
+#define ATMEL_PMERRLOC_ELPRIM          0x004   /* Error location primitive */
+#define ATMEL_PMERRLOC_ELEN            0x008   /* Error location enable */
+#define ATMEL_PMERRLOC_ELDIS           0x00c   /* Error location disable */
+#define                PMERRLOC_DISABLE                (1 << 0)
+
+#define ATMEL_PMERRLOC_ELSR            0x010   /* Error location status */
+#define                PMERRLOC_ELSR_BUSY              (1 << 0)
+#define ATMEL_PMERRLOC_ELIER           0x014   /* Error location int enable */
+#define ATMEL_PMERRLOC_ELIDR           0x018   /* Error location int disable */
+#define ATMEL_PMERRLOC_ELIMR           0x01c   /* Error location int mask */
+#define ATMEL_PMERRLOC_ELISR           0x020   /* Error location int status */
+#define                PMERRLOC_ERR_NUM_MASK           (0x1f << 8)
+#define                PMERRLOC_CALC_DONE              (1 << 0)
+#define ATMEL_PMERRLOC_SIGMAx          0x028   /* Error location SIGMA x */
+#define ATMEL_PMERRLOC_ELx             0x08c   /* Error location x */
+
+/* Register access macros for PMECC */
+#define pmecc_readl_relaxed(addr, reg) \
+       readl_relaxed((addr) + ATMEL_PMECC_##reg)
+
+#define pmecc_writel(addr, reg, value) \
+       writel((value), (addr) + ATMEL_PMECC_##reg)
+
+#define pmecc_readb_ecc_relaxed(addr, sector, n) \
+       readb_relaxed((addr) + ATMEL_PMECC_ECCx + ((sector) * 0x40) + (n))
+
+#define pmecc_readl_rem_relaxed(addr, sector, n) \
+       readl_relaxed((addr) + ATMEL_PMECC_REMx + ((sector) * 0x40) + ((n) * 4))
+
+#define pmerrloc_readl_relaxed(addr, reg) \
+       readl_relaxed((addr) + ATMEL_PMERRLOC_##reg)
+
+#define pmerrloc_writel(addr, reg, value) \
+       writel((value), (addr) + ATMEL_PMERRLOC_##reg)
+
+#define pmerrloc_writel_sigma_relaxed(addr, n, value) \
+       writel_relaxed((value), (addr) + ATMEL_PMERRLOC_SIGMAx + ((n) * 4))
+
+#define pmerrloc_readl_sigma_relaxed(addr, n) \
+       readl_relaxed((addr) + ATMEL_PMERRLOC_SIGMAx + ((n) * 4))
+
+#define pmerrloc_readl_el_relaxed(addr, n) \
+       readl_relaxed((addr) + ATMEL_PMERRLOC_ELx + ((n) * 4))
+
+/* Galois field dimension */
+#define PMECC_GF_DIMENSION_13                  13
+#define PMECC_GF_DIMENSION_14                  14
+
+#define PMECC_LOOKUP_TABLE_SIZE_512            0x2000
+#define PMECC_LOOKUP_TABLE_SIZE_1024           0x4000
+
+/* Time out value for reading PMECC status register */
+#define PMECC_MAX_TIMEOUT_MS                   100
+
 #endif
index 5914bb32e0014e189cd42aafd34017698222dd27..c8799a001833f71ec2b5a34ee6ea46c8486f351b 100644 (file)
@@ -23,7 +23,7 @@
 /* ---- Private Function Prototypes -------------------------------------- */
 static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd,
        struct nand_chip *chip, uint8_t *buf, int oob_required, int page);
-static void bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd,
+static int bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd,
        struct nand_chip *chip, const uint8_t *buf, int oob_required);
 
 /* ---- Private Variables ------------------------------------------------ */
@@ -194,7 +194,7 @@ static int bcm_umi_bch_read_page_hwecc(struct mtd_info *mtd,
 *  @oob_required:      must write chip->oob_poi to OOB
 *
 ***************************************************************************/
-static void bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd,
+static int bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd,
        struct nand_chip *chip, const uint8_t *buf, int oob_required)
 {
        int sectorIdx = 0;
@@ -214,4 +214,6 @@ static void bcm_umi_bch_write_page_hwecc(struct mtd_info *mtd,
        }
 
        bcm_umi_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+       return 0;
 }
index c855e7cd337b2f7a278a164c2e7a7b7f17a723f8..d0d1bd4d0e7d13b4d065077632dac5773264e7f2 100644 (file)
@@ -249,20 +249,20 @@ static int nand_dev_ready(struct mtd_info *mtd)
 int bcm_umi_nand_inithw(void)
 {
        /* Configure nand timing parameters */
-       REG_UMI_NAND_TCR &= ~0x7ffff;
-       REG_UMI_NAND_TCR |= HW_CFG_NAND_TCR;
+       writel(readl(&REG_UMI_NAND_TCR) & ~0x7ffff, &REG_UMI_NAND_TCR);
+       writel(readl(&REG_UMI_NAND_TCR) | HW_CFG_NAND_TCR, &REG_UMI_NAND_TCR);
 
 #if !defined(CONFIG_MTD_NAND_BCM_UMI_HWCS)
        /* enable software control of CS */
-       REG_UMI_NAND_TCR |= REG_UMI_NAND_TCR_CS_SWCTRL;
+       writel(readl(&REG_UMI_NAND_TCR) | REG_UMI_NAND_TCR_CS_SWCTRL, &REG_UMI_NAND_TCR);
 #endif
 
        /* keep NAND chip select asserted */
-       REG_UMI_NAND_RCSR |= REG_UMI_NAND_RCSR_CS_ASSERTED;
+       writel(readl(&REG_UMI_NAND_RCSR) | REG_UMI_NAND_RCSR_CS_ASSERTED, &REG_UMI_NAND_RCSR);
 
-       REG_UMI_NAND_TCR &= ~REG_UMI_NAND_TCR_WORD16;
+       writel(readl(&REG_UMI_NAND_TCR) & ~REG_UMI_NAND_TCR_WORD16, &REG_UMI_NAND_TCR);
        /* enable writes to flash */
-       REG_UMI_MMD_ICR |= REG_UMI_MMD_ICR_FLASH_WP;
+       writel(readl(&REG_UMI_MMD_ICR) | REG_UMI_MMD_ICR_FLASH_WP, &REG_UMI_MMD_ICR);
 
        writel(NAND_CMD_RESET, bcm_umi_io_base + REG_NAND_CMD_OFFSET);
        nand_bcm_umi_wait_till_ready();
index 3f1c18599cbd9484096caed856f69c79c61c2bff..ab0caa74eb43e428b57e298b1ff29d4b7a38a0a0 100644 (file)
@@ -566,11 +566,13 @@ static int bf5xx_nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip
        return 0;
 }
 
-static void bf5xx_nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
-               const uint8_t *buf, int oob_required)
+static int bf5xx_nand_write_page_raw(struct mtd_info *mtd,
+               struct nand_chip *chip, const uint8_t *buf, int oob_required)
 {
        bf5xx_nand_write_buf(mtd, buf, mtd->writesize);
        bf5xx_nand_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+       return 0;
 }
 
 /*
index f3f6cfedd69eb5e1367c196de7e8e249740bb77b..08248a0a167e00e68cde8e7c767cabd0dab8cb12 100644 (file)
@@ -377,7 +377,7 @@ static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
  * @buf:       buffer to store read data
  * @oob_required:      caller expects OOB data read to chip->oob_poi
  *
- * The hw generator calculates the error syndrome automatically. Therefor
+ * The hw generator calculates the error syndrome automatically. Therefore
  * we need a special oob layout and handling.
  */
 static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
@@ -520,7 +520,7 @@ static struct nand_bbt_descr cafe_bbt_mirror_descr_512 = {
 };
 
 
-static void cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
+static int cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
                                          struct nand_chip *chip,
                                          const uint8_t *buf, int oob_required)
 {
@@ -531,6 +531,8 @@ static void cafe_nand_write_page_lowlevel(struct mtd_info *mtd,
 
        /* Set up ECC autogeneration */
        cafe->ctl2 |= (1<<30);
+
+       return 0;
 }
 
 static int cafe_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
@@ -542,9 +544,12 @@ static int cafe_nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
        chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
 
        if (unlikely(raw))
-               chip->ecc.write_page_raw(mtd, chip, buf, oob_required);
+               status = chip->ecc.write_page_raw(mtd, chip, buf, oob_required);
        else
-               chip->ecc.write_page(mtd, chip, buf, oob_required);
+               status = chip->ecc.write_page(mtd, chip, buf, oob_required);
+
+       if (status < 0)
+               return status;
 
        /*
         * Cached progamming disabled for now, Not sure if its worth the
index 0650aafa0dd2238b2af08a1328970e5efb38d24e..e706a237170f503142089cb5644fe2957cafae07 100644 (file)
@@ -1028,7 +1028,7 @@ static void denali_setup_dma(struct denali_nand_info *denali, int op)
 
 /* writes a page. user specifies type, and this function handles the
  * configuration details. */
-static void write_page(struct mtd_info *mtd, struct nand_chip *chip,
+static int write_page(struct mtd_info *mtd, struct nand_chip *chip,
                        const uint8_t *buf, bool raw_xfer)
 {
        struct denali_nand_info *denali = mtd_to_denali(mtd);
@@ -1078,6 +1078,8 @@ static void write_page(struct mtd_info *mtd, struct nand_chip *chip,
 
        denali_enable_dma(denali, false);
        dma_sync_single_for_cpu(denali->dev, addr, size, DMA_TO_DEVICE);
+
+       return 0;
 }
 
 /* NAND core entry points */
@@ -1086,24 +1088,24 @@ static void write_page(struct mtd_info *mtd, struct nand_chip *chip,
  * writing a page with ECC or without is similar, all the work is done
  * by write_page above.
  * */
-static void denali_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+static int denali_write_page(struct mtd_info *mtd, struct nand_chip *chip,
                                const uint8_t *buf, int oob_required)
 {
        /* for regular page writes, we let HW handle all the ECC
         * data written to the device. */
-       write_page(mtd, chip, buf, false);
+       return write_page(mtd, chip, buf, false);
 }
 
 /* This is the callback that the NAND core calls to write a page without ECC.
  * raw access is similar to ECC page writes, so all the work is done in the
  * write_page() function above.
  */
-static void denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+static int denali_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
                                        const uint8_t *buf, int oob_required)
 {
        /* for raw page writes, we want to disable ECC and simply write
           whatever data is in the buffer. */
-       write_page(mtd, chip, buf, true);
+       return write_page(mtd, chip, buf, true);
 }
 
 static int denali_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
index a225e49a56235763b35cfd5118f30f7c20c4fb55..0f2ffd7b6c822c55d0309338f2f4d3f834fbf4a6 100644 (file)
@@ -898,7 +898,7 @@ static void docg4_erase_block(struct mtd_info *mtd, int page)
        write_nop(docptr);
 }
 
-static void write_page(struct mtd_info *mtd, struct nand_chip *nand,
+static int write_page(struct mtd_info *mtd, struct nand_chip *nand,
                       const uint8_t *buf, bool use_ecc)
 {
        struct docg4_priv *doc = nand->priv;
@@ -950,15 +950,17 @@ static void write_page(struct mtd_info *mtd, struct nand_chip *nand,
        write_nop(docptr);
        writew(0, docptr + DOC_DATAEND);
        write_nop(docptr);
+
+       return 0;
 }
 
-static void docg4_write_page_raw(struct mtd_info *mtd, struct nand_chip *nand,
+static int docg4_write_page_raw(struct mtd_info *mtd, struct nand_chip *nand,
                                 const uint8_t *buf, int oob_required)
 {
        return write_page(mtd, nand, buf, false);
 }
 
-static void docg4_write_page(struct mtd_info *mtd, struct nand_chip *nand,
+static int docg4_write_page(struct mtd_info *mtd, struct nand_chip *nand,
                             const uint8_t *buf, int oob_required)
 {
        return write_page(mtd, nand, buf, true);
index 784293806110acc63ee4ae062c689dab534860d6..8143873d17a5c2bebc19c140445a5ad30fac8dee 100644 (file)
@@ -766,11 +766,13 @@ static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
 /* ECC will be calculated automatically, and errors will be detected in
  * waitfunc.
  */
-static void fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+static int fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
                                const uint8_t *buf, int oob_required)
 {
        fsl_elbc_write_buf(mtd, buf, mtd->writesize);
        fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+       return 0;
 }
 
 static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
@@ -805,7 +807,6 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv)
        chip->bbt_md = &bbt_mirror_descr;
 
        /* set up nand options */
-       chip->options = NAND_NO_READRDY;
        chip->bbt_options = NAND_BBT_USE_FLASH;
 
        chip->controller = &elbc_fcm_ctrl->controller;
@@ -916,7 +917,8 @@ static int __devinit fsl_elbc_nand_probe(struct platform_device *pdev)
        elbc_fcm_ctrl->chips[bank] = priv;
        priv->bank = bank;
        priv->ctrl = fsl_lbc_ctrl_dev;
-       priv->dev = dev;
+       priv->dev = &pdev->dev;
+       dev_set_drvdata(priv->dev, priv);
 
        priv->vbase = ioremap(res.start, resource_size(&res));
        if (!priv->vbase) {
@@ -963,11 +965,10 @@ err:
 
 static int fsl_elbc_nand_remove(struct platform_device *pdev)
 {
-       int i;
        struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = fsl_lbc_ctrl_dev->nand;
-       for (i = 0; i < MAX_BANKS; i++)
-               if (elbc_fcm_ctrl->chips[i])
-                       fsl_elbc_chip_remove(elbc_fcm_ctrl->chips[i]);
+       struct fsl_elbc_mtd *priv = dev_get_drvdata(&pdev->dev);
+
+       fsl_elbc_chip_remove(priv);
 
        mutex_lock(&fsl_elbc_nand_mutex);
        elbc_fcm_ctrl->counter--;
index 9602c1b7e27e8e5a70c66f50a47df04693b4bf1e..1f71b545062aa0e548b7cca6de6a0d763a357826 100644 (file)
@@ -721,11 +721,13 @@ static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
 /* ECC will be calculated automatically, and errors will be detected in
  * waitfunc.
  */
-static void fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+static int fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
                               const uint8_t *buf, int oob_required)
 {
        fsl_ifc_write_buf(mtd, buf, mtd->writesize);
        fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+       return 0;
 }
 
 static int fsl_ifc_chip_init_tail(struct mtd_info *mtd)
@@ -805,7 +807,6 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
        out_be32(&ifc->ifc_nand.ncfgr, 0x0);
 
        /* set up nand options */
-       chip->options = NAND_NO_READRDY;
        chip->bbt_options = NAND_BBT_USE_FLASH;
 
 
index a1f43329ad43d2c7898f7c978cb3f9f15721fe5e..6bb0998dcb4042ba28a1b22312953455a168fe3d 100644 (file)
@@ -124,12 +124,42 @@ error:
        return -ETIMEDOUT;
 }
 
+static int __gpmi_enable_clk(struct gpmi_nand_data *this, bool v)
+{
+       struct clk *clk;
+       int ret;
+       int i;
+
+       for (i = 0; i < GPMI_CLK_MAX; i++) {
+               clk = this->resources.clock[i];
+               if (!clk)
+                       break;
+
+               if (v) {
+                       ret = clk_prepare_enable(clk);
+                       if (ret)
+                               goto err_clk;
+               } else {
+                       clk_disable_unprepare(clk);
+               }
+       }
+       return 0;
+
+err_clk:
+       for (; i > 0; i--)
+               clk_disable_unprepare(this->resources.clock[i - 1]);
+       return ret;
+}
+
+#define gpmi_enable_clk(x) __gpmi_enable_clk(x, true)
+#define gpmi_disable_clk(x) __gpmi_enable_clk(x, false)
+
 int gpmi_init(struct gpmi_nand_data *this)
 {
        struct resources *r = &this->resources;
        int ret;
 
-       ret = clk_prepare_enable(r->clock);
+       ret = gpmi_enable_clk(this);
        if (ret)
                goto err_out;
        ret = gpmi_reset_block(r->gpmi_regs, false);
@@ -149,7 +179,7 @@ int gpmi_init(struct gpmi_nand_data *this)
        /* Select BCH ECC. */
        writel(BM_GPMI_CTRL1_BCH_MODE, r->gpmi_regs + HW_GPMI_CTRL1_SET);
 
-       clk_disable_unprepare(r->clock);
+       gpmi_disable_clk(this);
        return 0;
 err_out:
        return ret;
@@ -205,7 +235,7 @@ int bch_set_geometry(struct gpmi_nand_data *this)
        ecc_strength  = bch_geo->ecc_strength >> 1;
        page_size     = bch_geo->page_size;
 
-       ret = clk_prepare_enable(r->clock);
+       ret = gpmi_enable_clk(this);
        if (ret)
                goto err_out;
 
@@ -240,7 +270,7 @@ int bch_set_geometry(struct gpmi_nand_data *this)
        writel(BM_BCH_CTRL_COMPLETE_IRQ_EN,
                                r->bch_regs + HW_BCH_CTRL_SET);
 
-       clk_disable_unprepare(r->clock);
+       gpmi_disable_clk(this);
        return 0;
 err_out:
        return ret;
@@ -716,7 +746,7 @@ void gpmi_begin(struct gpmi_nand_data *this)
        int ret;
 
        /* Enable the clock. */
-       ret = clk_prepare_enable(r->clock);
+       ret = gpmi_enable_clk(this);
        if (ret) {
                pr_err("We failed in enable the clk\n");
                goto err_out;
@@ -727,7 +757,7 @@ void gpmi_begin(struct gpmi_nand_data *this)
                gpmi_regs + HW_GPMI_TIMING1);
 
        /* Get the timing information we need. */
-       nfc->clock_frequency_in_hz = clk_get_rate(r->clock);
+       nfc->clock_frequency_in_hz = clk_get_rate(r->clock[0]);
        clock_period_in_ns = 1000000000 / nfc->clock_frequency_in_hz;
 
        gpmi_nfc_compute_hardware_timing(this, &hw);
@@ -784,8 +814,7 @@ err_out:
 
 void gpmi_end(struct gpmi_nand_data *this)
 {
-       struct resources *r = &this->resources;
-       clk_disable_unprepare(r->clock);
+       gpmi_disable_clk(this);
 }
 
 /* Clears a BCH interrupt. */
index a6cad5caba788fe8b665270a3fc7494d7a071887..8c0d2f0a526fee442ab8310806af0d3f0c182919 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/pinctrl/consumer.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/of_mtd.h>
 #include "gpmi-nand.h"
 
 /* add our owner bbt descriptor */
@@ -464,9 +465,78 @@ acquire_err:
        return -EINVAL;
 }
 
+static void gpmi_put_clks(struct gpmi_nand_data *this)
+{
+       struct resources *r = &this->resources;
+       struct clk *clk;
+       int i;
+
+       for (i = 0; i < GPMI_CLK_MAX; i++) {
+               clk = r->clock[i];
+               if (clk) {
+                       clk_put(clk);
+                       r->clock[i] = NULL;
+               }
+       }
+}
+
+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)
+{
+       struct resources *r = &this->resources;
+       char **extra_clks = NULL;
+       struct clk *clk;
+       int i;
+
+       /* The main clock is stored in the first. */
+       r->clock[0] = clk_get(this->dev, "gpmi_io");
+       if (IS_ERR(r->clock[0]))
+               goto err_clock;
+
+       /* Get extra clocks */
+       if (GPMI_IS_MX6Q(this))
+               extra_clks = extra_clks_for_mx6q;
+       if (!extra_clks)
+               return 0;
+
+       for (i = 1; i < GPMI_CLK_MAX; i++) {
+               if (extra_clks[i - 1] == NULL)
+                       break;
+
+               clk = clk_get(this->dev, extra_clks[i - 1]);
+               if (IS_ERR(clk))
+                       goto err_clock;
+
+               r->clock[i] = clk;
+       }
+
+       if (GPMI_IS_MX6Q(this)) {
+               /*
+                * Set the default values for the clocks in mx6q:
+                *    The main clock(enfc) : 22MHz
+                *    The others           : 44.5MHz
+                *
+                * These are just the default values. If you want to use
+                * the ONFI nand which is in the Synchronous Mode, you should
+                * change the clocks's frequencies as you need.
+                */
+               clk_set_rate(r->clock[0], 22000000);
+               for (i = 1; i < GPMI_CLK_MAX && r->clock[i]; i++)
+                       clk_set_rate(r->clock[i], 44500000);
+       }
+       return 0;
+
+err_clock:
+       dev_dbg(this->dev, "failed in finding the clocks.\n");
+       gpmi_put_clks(this);
+       return -ENOMEM;
+}
+
 static int __devinit acquire_resources(struct gpmi_nand_data *this)
 {
-       struct resources *res = &this->resources;
        struct pinctrl *pinctrl;
        int ret;
 
@@ -492,12 +562,9 @@ static int __devinit acquire_resources(struct gpmi_nand_data *this)
                goto exit_pin;
        }
 
-       res->clock = clk_get(&this->pdev->dev, NULL);
-       if (IS_ERR(res->clock)) {
-               pr_err("can not get the clock\n");
-               ret = -ENOENT;
+       ret = gpmi_get_clks(this);
+       if (ret)
                goto exit_clock;
-       }
        return 0;
 
 exit_clock:
@@ -512,9 +579,7 @@ exit_regs:
 
 static void release_resources(struct gpmi_nand_data *this)
 {
-       struct resources *r = &this->resources;
-
-       clk_put(r->clock);
+       gpmi_put_clks(this);
        release_register_block(this);
        release_bch_irq(this);
        release_dma_channels(this);
@@ -930,7 +995,7 @@ exit_nfc:
        return ret;
 }
 
-static void gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
                                const uint8_t *buf, int oob_required)
 {
        struct gpmi_nand_data *this = chip->priv;
@@ -972,7 +1037,7 @@ static void gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
                                &payload_virt, &payload_phys);
                if (ret) {
                        pr_err("Inadequate payload DMA buffer\n");
-                       return;
+                       return 0;
                }
 
                ret = send_page_prepare(this,
@@ -1002,6 +1067,8 @@ exit_auxiliary:
                                nfc_geo->payload_size,
                                payload_virt, payload_phys);
        }
+
+       return 0;
 }
 
 /*
@@ -1064,6 +1131,9 @@ exit_auxiliary:
  * ECC-based or raw view of the page is implicit in which function it calls
  * (there is a similar pair of ECC-based/raw functions for writing).
  *
+ * FIXME: The following paragraph is incorrect, now that there exist
+ * ecc.read_oob_raw and ecc.write_oob_raw functions.
+ *
  * Since MTD assumes the OOB is not covered by ECC, there is no pair of
  * ECC-based/raw functions for reading or or writing the OOB. The fact that the
  * caller wants an ECC-based or raw view of the page is not propagated down to
@@ -1436,6 +1506,7 @@ static int gpmi_pre_bbt_scan(struct gpmi_nand_data  *this)
        /* Adjust the ECC strength according to the chip. */
        this->nand.ecc.strength = this->bch_geometry.ecc_strength;
        this->mtd.ecc_strength = this->bch_geometry.ecc_strength;
+       this->mtd.bitflip_threshold = this->bch_geometry.ecc_strength;
 
        /* NAND boot init, depends on the gpmi_set_geometry(). */
        return nand_boot_init(this);
@@ -1497,6 +1568,8 @@ static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this)
        chip->ecc.size          = 1;
        chip->ecc.strength      = 8;
        chip->ecc.layout        = &gpmi_hw_ecclayout;
+       if (of_get_nand_on_flash_bbt(this->dev->of_node))
+               chip->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
 
        /* Allocate a temporary DMA buffer for reading ID in the nand_scan() */
        this->bch_geometry.payload_size = 1024;
index ce5daa1609203923caee19f576be884c27919a97..1547a60c1c6f8b4d30729bdc94e51bf48010156a 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/fsl/mxs-dma.h>
 
+#define GPMI_CLK_MAX 5 /* MX6Q needs five clocks */
 struct resources {
        void          *gpmi_regs;
        void          *bch_regs;
@@ -29,7 +30,7 @@ struct resources {
        unsigned int  bch_high_interrupt;
        unsigned int  dma_low_channel;
        unsigned int  dma_high_channel;
-       struct clk    *clock;
+       struct clk    *clock[GPMI_CLK_MAX];
 };
 
 /**
diff --git a/drivers/mtd/nand/lpc32xx_mlc.c b/drivers/mtd/nand/lpc32xx_mlc.c
new file mode 100644 (file)
index 0000000..1cf3593
--- /dev/null
@@ -0,0 +1,925 @@
+/*
+ * Driver for NAND MLC Controller in LPC32xx
+ *
+ * Author: Roland Stigge <stigge@antcom.de>
+ *
+ * Copyright Â© 2011 WORK Microwave GmbH
+ * Copyright Â© 2011, 2012 Roland Stigge
+ *
+ * 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.
+ *
+ *
+ * NAND Flash Controller Operation:
+ * - Read: Auto Decode
+ * - Write: Auto Encode
+ * - Tested Page Sizes: 2048, 4096
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_mtd.h>
+#include <linux/of_gpio.h>
+#include <linux/amba/pl08x.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/mtd/nand_ecc.h>
+
+#define DRV_NAME "lpc32xx_mlc"
+
+/**********************************************************************
+* MLC NAND controller register offsets
+**********************************************************************/
+
+#define MLC_BUFF(x)                    (x + 0x00000)
+#define MLC_DATA(x)                    (x + 0x08000)
+#define MLC_CMD(x)                     (x + 0x10000)
+#define MLC_ADDR(x)                    (x + 0x10004)
+#define MLC_ECC_ENC_REG(x)             (x + 0x10008)
+#define MLC_ECC_DEC_REG(x)             (x + 0x1000C)
+#define MLC_ECC_AUTO_ENC_REG(x)                (x + 0x10010)
+#define MLC_ECC_AUTO_DEC_REG(x)                (x + 0x10014)
+#define MLC_RPR(x)                     (x + 0x10018)
+#define MLC_WPR(x)                     (x + 0x1001C)
+#define MLC_RUBP(x)                    (x + 0x10020)
+#define MLC_ROBP(x)                    (x + 0x10024)
+#define MLC_SW_WP_ADD_LOW(x)           (x + 0x10028)
+#define MLC_SW_WP_ADD_HIG(x)           (x + 0x1002C)
+#define MLC_ICR(x)                     (x + 0x10030)
+#define MLC_TIME_REG(x)                        (x + 0x10034)
+#define MLC_IRQ_MR(x)                  (x + 0x10038)
+#define MLC_IRQ_SR(x)                  (x + 0x1003C)
+#define MLC_LOCK_PR(x)                 (x + 0x10044)
+#define MLC_ISR(x)                     (x + 0x10048)
+#define MLC_CEH(x)                     (x + 0x1004C)
+
+/**********************************************************************
+* MLC_CMD bit definitions
+**********************************************************************/
+#define MLCCMD_RESET                   0xFF
+
+/**********************************************************************
+* MLC_ICR bit definitions
+**********************************************************************/
+#define MLCICR_WPROT                   (1 << 3)
+#define MLCICR_LARGEBLOCK              (1 << 2)
+#define MLCICR_LONGADDR                        (1 << 1)
+#define MLCICR_16BIT                   (1 << 0)  /* unsupported by LPC32x0! */
+
+/**********************************************************************
+* MLC_TIME_REG bit definitions
+**********************************************************************/
+#define MLCTIMEREG_TCEA_DELAY(n)       (((n) & 0x03) << 24)
+#define MLCTIMEREG_BUSY_DELAY(n)       (((n) & 0x1F) << 19)
+#define MLCTIMEREG_NAND_TA(n)          (((n) & 0x07) << 16)
+#define MLCTIMEREG_RD_HIGH(n)          (((n) & 0x0F) << 12)
+#define MLCTIMEREG_RD_LOW(n)           (((n) & 0x0F) << 8)
+#define MLCTIMEREG_WR_HIGH(n)          (((n) & 0x0F) << 4)
+#define MLCTIMEREG_WR_LOW(n)           (((n) & 0x0F) << 0)
+
+/**********************************************************************
+* MLC_IRQ_MR and MLC_IRQ_SR bit definitions
+**********************************************************************/
+#define MLCIRQ_NAND_READY              (1 << 5)
+#define MLCIRQ_CONTROLLER_READY                (1 << 4)
+#define MLCIRQ_DECODE_FAILURE          (1 << 3)
+#define MLCIRQ_DECODE_ERROR            (1 << 2)
+#define MLCIRQ_ECC_READY               (1 << 1)
+#define MLCIRQ_WRPROT_FAULT            (1 << 0)
+
+/**********************************************************************
+* MLC_LOCK_PR bit definitions
+**********************************************************************/
+#define MLCLOCKPR_MAGIC                        0xA25E
+
+/**********************************************************************
+* MLC_ISR bit definitions
+**********************************************************************/
+#define MLCISR_DECODER_FAILURE         (1 << 6)
+#define MLCISR_ERRORS                  ((1 << 4) | (1 << 5))
+#define MLCISR_ERRORS_DETECTED         (1 << 3)
+#define MLCISR_ECC_READY               (1 << 2)
+#define MLCISR_CONTROLLER_READY                (1 << 1)
+#define MLCISR_NAND_READY              (1 << 0)
+
+/**********************************************************************
+* MLC_CEH bit definitions
+**********************************************************************/
+#define MLCCEH_NORMAL                  (1 << 0)
+
+struct lpc32xx_nand_cfg_mlc {
+       uint32_t tcea_delay;
+       uint32_t busy_delay;
+       uint32_t nand_ta;
+       uint32_t rd_high;
+       uint32_t rd_low;
+       uint32_t wr_high;
+       uint32_t wr_low;
+       int wp_gpio;
+       struct mtd_partition *parts;
+       unsigned num_parts;
+};
+
+static struct nand_ecclayout lpc32xx_nand_oob = {
+       .eccbytes = 40,
+       .eccpos = { 6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+                  22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+                  38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+                  54, 55, 56, 57, 58, 59, 60, 61, 62, 63 },
+       .oobfree = {
+               { .offset = 0,
+                 .length = 6, },
+               { .offset = 16,
+                 .length = 6, },
+               { .offset = 32,
+                 .length = 6, },
+               { .offset = 48,
+                 .length = 6, },
+               },
+};
+
+static struct nand_bbt_descr lpc32xx_nand_bbt = {
+       .options = NAND_BBT_ABSPAGE | NAND_BBT_2BIT | NAND_BBT_NO_OOB |
+                  NAND_BBT_WRITE,
+       .pages = { 524224, 0, 0, 0, 0, 0, 0, 0 },
+};
+
+static struct nand_bbt_descr lpc32xx_nand_bbt_mirror = {
+       .options = NAND_BBT_ABSPAGE | NAND_BBT_2BIT | NAND_BBT_NO_OOB |
+                  NAND_BBT_WRITE,
+       .pages = { 524160, 0, 0, 0, 0, 0, 0, 0 },
+};
+
+struct lpc32xx_nand_host {
+       struct nand_chip        nand_chip;
+       struct clk              *clk;
+       struct mtd_info         mtd;
+       void __iomem            *io_base;
+       int                     irq;
+       struct lpc32xx_nand_cfg_mlc     *ncfg;
+       struct completion       comp_nand;
+       struct completion       comp_controller;
+       uint32_t llptr;
+       /*
+        * Physical addresses of ECC buffer, DMA data buffers, OOB data buffer
+        */
+       dma_addr_t              oob_buf_phy;
+       /*
+        * Virtual addresses of ECC buffer, DMA data buffers, OOB data buffer
+        */
+       uint8_t                 *oob_buf;
+       /* Physical address of DMA base address */
+       dma_addr_t              io_base_phy;
+
+       struct completion       comp_dma;
+       struct dma_chan         *dma_chan;
+       struct dma_slave_config dma_slave_config;
+       struct scatterlist      sgl;
+       uint8_t                 *dma_buf;
+       uint8_t                 *dummy_buf;
+       int                     mlcsubpages; /* number of 512bytes-subpages */
+};
+
+/*
+ * Activate/Deactivate DMA Operation:
+ *
+ * Using the PL080 DMA Controller for transferring the 512 byte subpages
+ * instead of doing readl() / writel() in a loop slows it down significantly.
+ * Measurements via getnstimeofday() upon 512 byte subpage reads reveal:
+ *
+ * - readl() of 128 x 32 bits in a loop: ~20us
+ * - DMA read of 512 bytes (32 bit, 4...128 words bursts): ~60us
+ * - DMA read of 512 bytes (32 bit, no bursts): ~100us
+ *
+ * This applies to the transfer itself. In the DMA case: only the
+ * wait_for_completion() (DMA setup _not_ included).
+ *
+ * Note that the 512 bytes subpage transfer is done directly from/to a
+ * FIFO/buffer inside the NAND controller. Most of the time (~400-800us for a
+ * 2048 bytes page) is spent waiting for the NAND IRQ, anyway. (The NAND
+ * controller transferring data between its internal buffer to/from the NAND
+ * chip.)
+ *
+ * Therefore, using the PL080 DMA is disabled by default, for now.
+ *
+ */
+static int use_dma;
+
+static void lpc32xx_nand_setup(struct lpc32xx_nand_host *host)
+{
+       uint32_t clkrate, tmp;
+
+       /* Reset MLC controller */
+       writel(MLCCMD_RESET, MLC_CMD(host->io_base));
+       udelay(1000);
+
+       /* Get base clock for MLC block */
+       clkrate = clk_get_rate(host->clk);
+       if (clkrate == 0)
+               clkrate = 104000000;
+
+       /* Unlock MLC_ICR
+        * (among others, will be locked again automatically) */
+       writew(MLCLOCKPR_MAGIC, MLC_LOCK_PR(host->io_base));
+
+       /* Configure MLC Controller: Large Block, 5 Byte Address */
+       tmp = MLCICR_LARGEBLOCK | MLCICR_LONGADDR;
+       writel(tmp, MLC_ICR(host->io_base));
+
+       /* Unlock MLC_TIME_REG
+        * (among others, will be locked again automatically) */
+       writew(MLCLOCKPR_MAGIC, MLC_LOCK_PR(host->io_base));
+
+       /* Compute clock setup values, see LPC and NAND manual */
+       tmp = 0;
+       tmp |= MLCTIMEREG_TCEA_DELAY(clkrate / host->ncfg->tcea_delay + 1);
+       tmp |= MLCTIMEREG_BUSY_DELAY(clkrate / host->ncfg->busy_delay + 1);
+       tmp |= MLCTIMEREG_NAND_TA(clkrate / host->ncfg->nand_ta + 1);
+       tmp |= MLCTIMEREG_RD_HIGH(clkrate / host->ncfg->rd_high + 1);
+       tmp |= MLCTIMEREG_RD_LOW(clkrate / host->ncfg->rd_low);
+       tmp |= MLCTIMEREG_WR_HIGH(clkrate / host->ncfg->wr_high + 1);
+       tmp |= MLCTIMEREG_WR_LOW(clkrate / host->ncfg->wr_low);
+       writel(tmp, MLC_TIME_REG(host->io_base));
+
+       /* Enable IRQ for CONTROLLER_READY and NAND_READY */
+       writeb(MLCIRQ_CONTROLLER_READY | MLCIRQ_NAND_READY,
+                       MLC_IRQ_MR(host->io_base));
+
+       /* Normal nCE operation: nCE controlled by controller */
+       writel(MLCCEH_NORMAL, MLC_CEH(host->io_base));
+}
+
+/*
+ * Hardware specific access to control lines
+ */
+static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+                                 unsigned int ctrl)
+{
+       struct nand_chip *nand_chip = mtd->priv;
+       struct lpc32xx_nand_host *host = nand_chip->priv;
+
+       if (cmd != NAND_CMD_NONE) {
+               if (ctrl & NAND_CLE)
+                       writel(cmd, MLC_CMD(host->io_base));
+               else
+                       writel(cmd, MLC_ADDR(host->io_base));
+       }
+}
+
+/*
+ * Read Device Ready (NAND device _and_ controller ready)
+ */
+static int lpc32xx_nand_device_ready(struct mtd_info *mtd)
+{
+       struct nand_chip *nand_chip = mtd->priv;
+       struct lpc32xx_nand_host *host = nand_chip->priv;
+
+       if ((readb(MLC_ISR(host->io_base)) &
+            (MLCISR_CONTROLLER_READY | MLCISR_NAND_READY)) ==
+           (MLCISR_CONTROLLER_READY | MLCISR_NAND_READY))
+               return  1;
+
+       return 0;
+}
+
+static irqreturn_t lpc3xxx_nand_irq(int irq, struct lpc32xx_nand_host *host)
+{
+       uint8_t sr;
+
+       /* Clear interrupt flag by reading status */
+       sr = readb(MLC_IRQ_SR(host->io_base));
+       if (sr & MLCIRQ_NAND_READY)
+               complete(&host->comp_nand);
+       if (sr & MLCIRQ_CONTROLLER_READY)
+               complete(&host->comp_controller);
+
+       return IRQ_HANDLED;
+}
+
+static int lpc32xx_waitfunc_nand(struct mtd_info *mtd, struct nand_chip *chip)
+{
+       struct lpc32xx_nand_host *host = chip->priv;
+
+       if (readb(MLC_ISR(host->io_base)) & MLCISR_NAND_READY)
+               goto exit;
+
+       wait_for_completion(&host->comp_nand);
+
+       while (!(readb(MLC_ISR(host->io_base)) & MLCISR_NAND_READY)) {
+               /* Seems to be delayed sometimes by controller */
+               dev_dbg(&mtd->dev, "Warning: NAND not ready.\n");
+               cpu_relax();
+       }
+
+exit:
+       return NAND_STATUS_READY;
+}
+
+static int lpc32xx_waitfunc_controller(struct mtd_info *mtd,
+                                      struct nand_chip *chip)
+{
+       struct lpc32xx_nand_host *host = chip->priv;
+
+       if (readb(MLC_ISR(host->io_base)) & MLCISR_CONTROLLER_READY)
+               goto exit;
+
+       wait_for_completion(&host->comp_controller);
+
+       while (!(readb(MLC_ISR(host->io_base)) &
+                MLCISR_CONTROLLER_READY)) {
+               dev_dbg(&mtd->dev, "Warning: Controller not ready.\n");
+               cpu_relax();
+       }
+
+exit:
+       return NAND_STATUS_READY;
+}
+
+static int lpc32xx_waitfunc(struct mtd_info *mtd, struct nand_chip *chip)
+{
+       lpc32xx_waitfunc_nand(mtd, chip);
+       lpc32xx_waitfunc_controller(mtd, chip);
+
+       return NAND_STATUS_READY;
+}
+
+/*
+ * Enable NAND write protect
+ */
+static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host)
+{
+       if (gpio_is_valid(host->ncfg->wp_gpio))
+               gpio_set_value(host->ncfg->wp_gpio, 0);
+}
+
+/*
+ * Disable NAND write protect
+ */
+static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host)
+{
+       if (gpio_is_valid(host->ncfg->wp_gpio))
+               gpio_set_value(host->ncfg->wp_gpio, 1);
+}
+
+static void lpc32xx_dma_complete_func(void *completion)
+{
+       complete(completion);
+}
+
+static int lpc32xx_xmit_dma(struct mtd_info *mtd, void *mem, int len,
+                           enum dma_transfer_direction dir)
+{
+       struct nand_chip *chip = mtd->priv;
+       struct lpc32xx_nand_host *host = chip->priv;
+       struct dma_async_tx_descriptor *desc;
+       int flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
+       int res;
+
+       sg_init_one(&host->sgl, mem, len);
+
+       res = dma_map_sg(host->dma_chan->device->dev, &host->sgl, 1,
+                        DMA_BIDIRECTIONAL);
+       if (res != 1) {
+               dev_err(mtd->dev.parent, "Failed to map sg list\n");
+               return -ENXIO;
+       }
+       desc = dmaengine_prep_slave_sg(host->dma_chan, &host->sgl, 1, dir,
+                                      flags);
+       if (!desc) {
+               dev_err(mtd->dev.parent, "Failed to prepare slave sg\n");
+               goto out1;
+       }
+
+       init_completion(&host->comp_dma);
+       desc->callback = lpc32xx_dma_complete_func;
+       desc->callback_param = &host->comp_dma;
+
+       dmaengine_submit(desc);
+       dma_async_issue_pending(host->dma_chan);
+
+       wait_for_completion_timeout(&host->comp_dma, msecs_to_jiffies(1000));
+
+       dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1,
+                    DMA_BIDIRECTIONAL);
+       return 0;
+out1:
+       dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1,
+                    DMA_BIDIRECTIONAL);
+       return -ENXIO;
+}
+
+static int lpc32xx_read_page(struct mtd_info *mtd, struct nand_chip *chip,
+                            uint8_t *buf, int oob_required, int page)
+{
+       struct lpc32xx_nand_host *host = chip->priv;
+       int i, j;
+       uint8_t *oobbuf = chip->oob_poi;
+       uint32_t mlc_isr;
+       int res;
+       uint8_t *dma_buf;
+       bool dma_mapped;
+
+       if ((void *)buf <= high_memory) {
+               dma_buf = buf;
+               dma_mapped = true;
+       } else {
+               dma_buf = host->dma_buf;
+               dma_mapped = false;
+       }
+
+       /* Writing Command and Address */
+       chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+
+       /* For all sub-pages */
+       for (i = 0; i < host->mlcsubpages; i++) {
+               /* Start Auto Decode Command */
+               writeb(0x00, MLC_ECC_AUTO_DEC_REG(host->io_base));
+
+               /* Wait for Controller Ready */
+               lpc32xx_waitfunc_controller(mtd, chip);
+
+               /* Check ECC Error status */
+               mlc_isr = readl(MLC_ISR(host->io_base));
+               if (mlc_isr & MLCISR_DECODER_FAILURE) {
+                       mtd->ecc_stats.failed++;
+                       dev_warn(&mtd->dev, "%s: DECODER_FAILURE\n", __func__);
+               } else if (mlc_isr & MLCISR_ERRORS_DETECTED) {
+                       mtd->ecc_stats.corrected += ((mlc_isr >> 4) & 0x3) + 1;
+               }
+
+               /* Read 512 + 16 Bytes */
+               if (use_dma) {
+                       res = lpc32xx_xmit_dma(mtd, dma_buf + i * 512, 512,
+                                              DMA_DEV_TO_MEM);
+                       if (res)
+                               return res;
+               } else {
+                       for (j = 0; j < (512 >> 2); j++) {
+                               *((uint32_t *)(buf)) =
+                                       readl(MLC_BUFF(host->io_base));
+                               buf += 4;
+                       }
+               }
+               for (j = 0; j < (16 >> 2); j++) {
+                       *((uint32_t *)(oobbuf)) =
+                               readl(MLC_BUFF(host->io_base));
+                       oobbuf += 4;
+               }
+       }
+
+       if (use_dma && !dma_mapped)
+               memcpy(buf, dma_buf, mtd->writesize);
+
+       return 0;
+}
+
+static int lpc32xx_write_page_lowlevel(struct mtd_info *mtd,
+                                      struct nand_chip *chip,
+                                      const uint8_t *buf, int oob_required)
+{
+       struct lpc32xx_nand_host *host = chip->priv;
+       const uint8_t *oobbuf = chip->oob_poi;
+       uint8_t *dma_buf = (uint8_t *)buf;
+       int res;
+       int i, j;
+
+       if (use_dma && (void *)buf >= high_memory) {
+               dma_buf = host->dma_buf;
+               memcpy(dma_buf, buf, mtd->writesize);
+       }
+
+       for (i = 0; i < host->mlcsubpages; i++) {
+               /* Start Encode */
+               writeb(0x00, MLC_ECC_ENC_REG(host->io_base));
+
+               /* Write 512 + 6 Bytes to Buffer */
+               if (use_dma) {
+                       res = lpc32xx_xmit_dma(mtd, dma_buf + i * 512, 512,
+                                              DMA_MEM_TO_DEV);
+                       if (res)
+                               return res;
+               } else {
+                       for (j = 0; j < (512 >> 2); j++) {
+                               writel(*((uint32_t *)(buf)),
+                                      MLC_BUFF(host->io_base));
+                               buf += 4;
+                       }
+               }
+               writel(*((uint32_t *)(oobbuf)), MLC_BUFF(host->io_base));
+               oobbuf += 4;
+               writew(*((uint16_t *)(oobbuf)), MLC_BUFF(host->io_base));
+               oobbuf += 12;
+
+               /* Auto Encode w/ Bit 8 = 0 (see LPC MLC Controller manual) */
+               writeb(0x00, MLC_ECC_AUTO_ENC_REG(host->io_base));
+
+               /* Wait for Controller Ready */
+               lpc32xx_waitfunc_controller(mtd, chip);
+       }
+       return 0;
+}
+
+static int lpc32xx_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+                             const uint8_t *buf, int oob_required, int page,
+                             int cached, int raw)
+{
+       int res;
+
+       chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
+       res = lpc32xx_write_page_lowlevel(mtd, chip, buf, oob_required);
+       chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+       lpc32xx_waitfunc(mtd, chip);
+
+       return res;
+}
+
+static int lpc32xx_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+                           int page)
+{
+       struct lpc32xx_nand_host *host = chip->priv;
+
+       /* Read whole page - necessary with MLC controller! */
+       lpc32xx_read_page(mtd, chip, host->dummy_buf, 1, page);
+
+       return 0;
+}
+
+static int lpc32xx_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
+                             int page)
+{
+       /* None, write_oob conflicts with the automatic LPC MLC ECC decoder! */
+       return 0;
+}
+
+/* Prepares MLC for transfers with H/W ECC enabled: always enabled anyway */
+static void lpc32xx_ecc_enable(struct mtd_info *mtd, int mode)
+{
+       /* Always enabled! */
+}
+
+static int lpc32xx_dma_setup(struct lpc32xx_nand_host *host)
+{
+       struct mtd_info *mtd = &host->mtd;
+       dma_cap_mask_t mask;
+
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
+       host->dma_chan = dma_request_channel(mask, pl08x_filter_id, "nand-mlc");
+       if (!host->dma_chan) {
+               dev_err(mtd->dev.parent, "Failed to request DMA channel\n");
+               return -EBUSY;
+       }
+
+       /*
+        * Set direction to a sensible value even if the dmaengine driver
+        * should ignore it. With the default (DMA_MEM_TO_MEM), the amba-pl08x
+        * driver criticizes it as "alien transfer direction".
+        */
+       host->dma_slave_config.direction = DMA_DEV_TO_MEM;
+       host->dma_slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       host->dma_slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       host->dma_slave_config.src_maxburst = 128;
+       host->dma_slave_config.dst_maxburst = 128;
+       /* DMA controller does flow control: */
+       host->dma_slave_config.device_fc = false;
+       host->dma_slave_config.src_addr = MLC_BUFF(host->io_base_phy);
+       host->dma_slave_config.dst_addr = MLC_BUFF(host->io_base_phy);
+       if (dmaengine_slave_config(host->dma_chan, &host->dma_slave_config)) {
+               dev_err(mtd->dev.parent, "Failed to setup DMA slave\n");
+               goto out1;
+       }
+
+       return 0;
+out1:
+       dma_release_channel(host->dma_chan);
+       return -ENXIO;
+}
+
+#ifdef CONFIG_OF
+static struct lpc32xx_nand_cfg_mlc *lpc32xx_parse_dt(struct device *dev)
+{
+       struct lpc32xx_nand_cfg_mlc *pdata;
+       struct device_node *np = dev->of_node;
+
+       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata) {
+               dev_err(dev, "could not allocate memory for platform data\n");
+               return NULL;
+       }
+
+       of_property_read_u32(np, "nxp,tcea-delay", &pdata->tcea_delay);
+       of_property_read_u32(np, "nxp,busy-delay", &pdata->busy_delay);
+       of_property_read_u32(np, "nxp,nand-ta", &pdata->nand_ta);
+       of_property_read_u32(np, "nxp,rd-high", &pdata->rd_high);
+       of_property_read_u32(np, "nxp,rd-low", &pdata->rd_low);
+       of_property_read_u32(np, "nxp,wr-high", &pdata->wr_high);
+       of_property_read_u32(np, "nxp,wr-low", &pdata->wr_low);
+
+       if (!pdata->tcea_delay || !pdata->busy_delay || !pdata->nand_ta ||
+           !pdata->rd_high || !pdata->rd_low || !pdata->wr_high ||
+           !pdata->wr_low) {
+               dev_err(dev, "chip parameters not specified correctly\n");
+               return NULL;
+       }
+
+       pdata->wp_gpio = of_get_named_gpio(np, "gpios", 0);
+
+       return pdata;
+}
+#else
+static struct lpc32xx_nand_cfg_mlc *lpc32xx_parse_dt(struct device *dev)
+{
+       return NULL;
+}
+#endif
+
+/*
+ * Probe for NAND controller
+ */
+static int __devinit lpc32xx_nand_probe(struct platform_device *pdev)
+{
+       struct lpc32xx_nand_host *host;
+       struct mtd_info *mtd;
+       struct nand_chip *nand_chip;
+       struct resource *rc;
+       int res;
+       struct mtd_part_parser_data ppdata = {};
+
+       /* Allocate memory for the device structure (and zero it) */
+       host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
+       if (!host) {
+               dev_err(&pdev->dev, "failed to allocate device structure.\n");
+               return -ENOMEM;
+       }
+
+       rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (rc == NULL) {
+               dev_err(&pdev->dev, "No memory resource found for device!\r\n");
+               return -ENXIO;
+       }
+
+       host->io_base = devm_request_and_ioremap(&pdev->dev, rc);
+       if (host->io_base == NULL) {
+               dev_err(&pdev->dev, "ioremap failed\n");
+               return -EIO;
+       }
+       host->io_base_phy = rc->start;
+
+       mtd = &host->mtd;
+       nand_chip = &host->nand_chip;
+       if (pdev->dev.of_node)
+               host->ncfg = lpc32xx_parse_dt(&pdev->dev);
+       else
+               host->ncfg = pdev->dev.platform_data;
+       if (!host->ncfg) {
+               dev_err(&pdev->dev, "Missing platform data\n");
+               return -ENOENT;
+       }
+       if (host->ncfg->wp_gpio == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+       if (gpio_is_valid(host->ncfg->wp_gpio) &&
+                       gpio_request(host->ncfg->wp_gpio, "NAND WP")) {
+               dev_err(&pdev->dev, "GPIO not available\n");
+               return -EBUSY;
+       }
+       lpc32xx_wp_disable(host);
+
+       nand_chip->priv = host;         /* link the private data structures */
+       mtd->priv = nand_chip;
+       mtd->owner = THIS_MODULE;
+       mtd->dev.parent = &pdev->dev;
+
+       /* Get NAND clock */
+       host->clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(host->clk)) {
+               dev_err(&pdev->dev, "Clock initialization failure\n");
+               res = -ENOENT;
+               goto err_exit1;
+       }
+       clk_enable(host->clk);
+
+       nand_chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl;
+       nand_chip->dev_ready = lpc32xx_nand_device_ready;
+       nand_chip->chip_delay = 25; /* us */
+       nand_chip->IO_ADDR_R = MLC_DATA(host->io_base);
+       nand_chip->IO_ADDR_W = MLC_DATA(host->io_base);
+
+       /* Init NAND controller */
+       lpc32xx_nand_setup(host);
+
+       platform_set_drvdata(pdev, host);
+
+       /* Initialize function pointers */
+       nand_chip->ecc.hwctl = lpc32xx_ecc_enable;
+       nand_chip->ecc.read_page_raw = lpc32xx_read_page;
+       nand_chip->ecc.read_page = lpc32xx_read_page;
+       nand_chip->ecc.write_page_raw = lpc32xx_write_page_lowlevel;
+       nand_chip->ecc.write_page = lpc32xx_write_page_lowlevel;
+       nand_chip->ecc.write_oob = lpc32xx_write_oob;
+       nand_chip->ecc.read_oob = lpc32xx_read_oob;
+       nand_chip->ecc.strength = 4;
+       nand_chip->write_page = lpc32xx_write_page;
+       nand_chip->waitfunc = lpc32xx_waitfunc;
+
+       nand_chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
+       nand_chip->bbt_td = &lpc32xx_nand_bbt;
+       nand_chip->bbt_md = &lpc32xx_nand_bbt_mirror;
+
+       /* bitflip_threshold's default is defined as ecc_strength anyway.
+        * Unfortunately, it is set only later at add_mtd_device(). Meanwhile
+        * being 0, it causes bad block table scanning errors in
+        * nand_scan_tail(), so preparing it here. */
+       mtd->bitflip_threshold = nand_chip->ecc.strength;
+
+       if (use_dma) {
+               res = lpc32xx_dma_setup(host);
+               if (res) {
+                       res = -EIO;
+                       goto err_exit2;
+               }
+       }
+
+       /*
+        * Scan to find existance of the device and
+        * Get the type of NAND device SMALL block or LARGE block
+        */
+       if (nand_scan_ident(mtd, 1, NULL)) {
+               res = -ENXIO;
+               goto err_exit3;
+       }
+
+       host->dma_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL);
+       if (!host->dma_buf) {
+               dev_err(&pdev->dev, "Error allocating dma_buf memory\n");
+               res = -ENOMEM;
+               goto err_exit3;
+       }
+
+       host->dummy_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL);
+       if (!host->dummy_buf) {
+               dev_err(&pdev->dev, "Error allocating dummy_buf memory\n");
+               res = -ENOMEM;
+               goto err_exit3;
+       }
+
+       nand_chip->ecc.mode = NAND_ECC_HW;
+       nand_chip->ecc.size = mtd->writesize;
+       nand_chip->ecc.layout = &lpc32xx_nand_oob;
+       host->mlcsubpages = mtd->writesize / 512;
+
+       /* initially clear interrupt status */
+       readb(MLC_IRQ_SR(host->io_base));
+
+       init_completion(&host->comp_nand);
+       init_completion(&host->comp_controller);
+
+       host->irq = platform_get_irq(pdev, 0);
+       if ((host->irq < 0) || (host->irq >= NR_IRQS)) {
+               dev_err(&pdev->dev, "failed to get platform irq\n");
+               res = -EINVAL;
+               goto err_exit3;
+       }
+
+       if (request_irq(host->irq, (irq_handler_t)&lpc3xxx_nand_irq,
+                       IRQF_TRIGGER_HIGH, DRV_NAME, host)) {
+               dev_err(&pdev->dev, "Error requesting NAND IRQ\n");
+               res = -ENXIO;
+               goto err_exit3;
+       }
+
+       /*
+        * Fills out all the uninitialized function pointers with the defaults
+        * And scans for a bad block table if appropriate.
+        */
+       if (nand_scan_tail(mtd)) {
+               res = -ENXIO;
+               goto err_exit4;
+       }
+
+       mtd->name = DRV_NAME;
+
+       ppdata.of_node = pdev->dev.of_node;
+       res = mtd_device_parse_register(mtd, NULL, &ppdata, host->ncfg->parts,
+                                       host->ncfg->num_parts);
+       if (!res)
+               return res;
+
+       nand_release(mtd);
+
+err_exit4:
+       free_irq(host->irq, host);
+err_exit3:
+       if (use_dma)
+               dma_release_channel(host->dma_chan);
+err_exit2:
+       clk_disable(host->clk);
+       clk_put(host->clk);
+       platform_set_drvdata(pdev, NULL);
+err_exit1:
+       lpc32xx_wp_enable(host);
+       gpio_free(host->ncfg->wp_gpio);
+
+       return res;
+}
+
+/*
+ * Remove NAND device
+ */
+static int __devexit lpc32xx_nand_remove(struct platform_device *pdev)
+{
+       struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
+       struct mtd_info *mtd = &host->mtd;
+
+       nand_release(mtd);
+       free_irq(host->irq, host);
+       if (use_dma)
+               dma_release_channel(host->dma_chan);
+
+       clk_disable(host->clk);
+       clk_put(host->clk);
+       platform_set_drvdata(pdev, NULL);
+
+       lpc32xx_wp_enable(host);
+       gpio_free(host->ncfg->wp_gpio);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int lpc32xx_nand_resume(struct platform_device *pdev)
+{
+       struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
+
+       /* Re-enable NAND clock */
+       clk_enable(host->clk);
+
+       /* Fresh init of NAND controller */
+       lpc32xx_nand_setup(host);
+
+       /* Disable write protect */
+       lpc32xx_wp_disable(host);
+
+       return 0;
+}
+
+static int lpc32xx_nand_suspend(struct platform_device *pdev, pm_message_t pm)
+{
+       struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
+
+       /* Enable write protect for safety */
+       lpc32xx_wp_enable(host);
+
+       /* Disable clock */
+       clk_disable(host->clk);
+       return 0;
+}
+
+#else
+#define lpc32xx_nand_resume NULL
+#define lpc32xx_nand_suspend NULL
+#endif
+
+#if defined(CONFIG_OF)
+static const struct of_device_id lpc32xx_nand_match[] = {
+       { .compatible = "nxp,lpc3220-mlc" },
+       { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, lpc32xx_nand_match);
+#endif
+
+static struct platform_driver lpc32xx_nand_driver = {
+       .probe          = lpc32xx_nand_probe,
+       .remove         = __devexit_p(lpc32xx_nand_remove),
+       .resume         = lpc32xx_nand_resume,
+       .suspend        = lpc32xx_nand_suspend,
+       .driver         = {
+               .name   = DRV_NAME,
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(lpc32xx_nand_match),
+       },
+};
+
+module_platform_driver(lpc32xx_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
+MODULE_DESCRIPTION("NAND driver for the NXP LPC32XX MLC controller");
diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c
new file mode 100644 (file)
index 0000000..c8c1d06
--- /dev/null
@@ -0,0 +1,1059 @@
+/*
+ * NXP LPC32XX NAND SLC driver
+ *
+ * Authors:
+ *    Kevin Wells <kevin.wells@nxp.com>
+ *    Roland Stigge <stigge@antcom.de>
+ *
+ * Copyright Â© 2011 NXP Semiconductors
+ * Copyright Â© 2012 Roland Stigge
+ *
+ * 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/slab.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_mtd.h>
+#include <linux/of_gpio.h>
+#include <linux/amba/pl08x.h>
+
+#define LPC32XX_MODNAME                "lpc32xx-nand"
+
+/**********************************************************************
+* SLC NAND controller register offsets
+**********************************************************************/
+
+#define SLC_DATA(x)            (x + 0x000)
+#define SLC_ADDR(x)            (x + 0x004)
+#define SLC_CMD(x)             (x + 0x008)
+#define SLC_STOP(x)            (x + 0x00C)
+#define SLC_CTRL(x)            (x + 0x010)
+#define SLC_CFG(x)             (x + 0x014)
+#define SLC_STAT(x)            (x + 0x018)
+#define SLC_INT_STAT(x)                (x + 0x01C)
+#define SLC_IEN(x)             (x + 0x020)
+#define SLC_ISR(x)             (x + 0x024)
+#define SLC_ICR(x)             (x + 0x028)
+#define SLC_TAC(x)             (x + 0x02C)
+#define SLC_TC(x)              (x + 0x030)
+#define SLC_ECC(x)             (x + 0x034)
+#define SLC_DMA_DATA(x)                (x + 0x038)
+
+/**********************************************************************
+* slc_ctrl register definitions
+**********************************************************************/
+#define SLCCTRL_SW_RESET       (1 << 2) /* Reset the NAND controller bit */
+#define SLCCTRL_ECC_CLEAR      (1 << 1) /* Reset ECC bit */
+#define SLCCTRL_DMA_START      (1 << 0) /* Start DMA channel bit */
+
+/**********************************************************************
+* slc_cfg register definitions
+**********************************************************************/
+#define SLCCFG_CE_LOW          (1 << 5) /* Force CE low bit */
+#define SLCCFG_DMA_ECC         (1 << 4) /* Enable DMA ECC bit */
+#define SLCCFG_ECC_EN          (1 << 3) /* ECC enable bit */
+#define SLCCFG_DMA_BURST       (1 << 2) /* DMA burst bit */
+#define SLCCFG_DMA_DIR         (1 << 1) /* DMA write(0)/read(1) bit */
+#define SLCCFG_WIDTH           (1 << 0) /* External device width, 0=8bit */
+
+/**********************************************************************
+* slc_stat register definitions
+**********************************************************************/
+#define SLCSTAT_DMA_FIFO       (1 << 2) /* DMA FIFO has data bit */
+#define SLCSTAT_SLC_FIFO       (1 << 1) /* SLC FIFO has data bit */
+#define SLCSTAT_NAND_READY     (1 << 0) /* NAND device is ready bit */
+
+/**********************************************************************
+* slc_int_stat, slc_ien, slc_isr, and slc_icr register definitions
+**********************************************************************/
+#define SLCSTAT_INT_TC         (1 << 1) /* Transfer count bit */
+#define SLCSTAT_INT_RDY_EN     (1 << 0) /* Ready interrupt bit */
+
+/**********************************************************************
+* slc_tac register definitions
+**********************************************************************/
+/* Clock setting for RDY write sample wait time in 2*n clocks */
+#define SLCTAC_WDR(n)          (((n) & 0xF) << 28)
+/* Write pulse width in clock cycles, 1 to 16 clocks */
+#define SLCTAC_WWIDTH(n)       (((n) & 0xF) << 24)
+/* Write hold time of control and data signals, 1 to 16 clocks */
+#define SLCTAC_WHOLD(n)                (((n) & 0xF) << 20)
+/* Write setup time of control and data signals, 1 to 16 clocks */
+#define SLCTAC_WSETUP(n)       (((n) & 0xF) << 16)
+/* Clock setting for RDY read sample wait time in 2*n clocks */
+#define SLCTAC_RDR(n)          (((n) & 0xF) << 12)
+/* Read pulse width in clock cycles, 1 to 16 clocks */
+#define SLCTAC_RWIDTH(n)       (((n) & 0xF) << 8)
+/* Read hold time of control and data signals, 1 to 16 clocks */
+#define SLCTAC_RHOLD(n)                (((n) & 0xF) << 4)
+/* Read setup time of control and data signals, 1 to 16 clocks */
+#define SLCTAC_RSETUP(n)       (((n) & 0xF) << 0)
+
+/**********************************************************************
+* slc_ecc register definitions
+**********************************************************************/
+/* ECC line party fetch macro */
+#define SLCECC_TO_LINEPAR(n)   (((n) >> 6) & 0x7FFF)
+#define SLCECC_TO_COLPAR(n)    ((n) & 0x3F)
+
+/*
+ * DMA requires storage space for the DMA local buffer and the hardware ECC
+ * storage area. The DMA local buffer is only used if DMA mapping fails
+ * during runtime.
+ */
+#define LPC32XX_DMA_DATA_SIZE          4096
+#define LPC32XX_ECC_SAVE_SIZE          ((4096 / 256) * 4)
+
+/* Number of bytes used for ECC stored in NAND per 256 bytes */
+#define LPC32XX_SLC_DEV_ECC_BYTES      3
+
+/*
+ * If the NAND base clock frequency can't be fetched, this frequency will be
+ * used instead as the base. This rate is used to setup the timing registers
+ * used for NAND accesses.
+ */
+#define LPC32XX_DEF_BUS_RATE           133250000
+
+/* Milliseconds for DMA FIFO timeout (unlikely anyway) */
+#define LPC32XX_DMA_TIMEOUT            100
+
+/*
+ * NAND ECC Layout for small page NAND devices
+ * Note: For large and huge page devices, the default layouts are used
+ */
+static struct nand_ecclayout lpc32xx_nand_oob_16 = {
+       .eccbytes = 6,
+       .eccpos = {10, 11, 12, 13, 14, 15},
+       .oobfree = {
+               { .offset = 0, .length = 4 },
+               { .offset = 6, .length = 4 },
+       },
+};
+
+static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
+static u8 mirror_pattern[] = {'1', 't', 'b', 'B' };
+
+/*
+ * Small page FLASH BBT descriptors, marker at offset 0, version at offset 6
+ * Note: Large page devices used the default layout
+ */
+static struct nand_bbt_descr bbt_smallpage_main_descr = {
+       .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+               | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+       .offs = 0,
+       .len = 4,
+       .veroffs = 6,
+       .maxblocks = 4,
+       .pattern = bbt_pattern
+};
+
+static struct nand_bbt_descr bbt_smallpage_mirror_descr = {
+       .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+               | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
+       .offs = 0,
+       .len = 4,
+       .veroffs = 6,
+       .maxblocks = 4,
+       .pattern = mirror_pattern
+};
+
+/*
+ * NAND platform configuration structure
+ */
+struct lpc32xx_nand_cfg_slc {
+       uint32_t wdr_clks;
+       uint32_t wwidth;
+       uint32_t whold;
+       uint32_t wsetup;
+       uint32_t rdr_clks;
+       uint32_t rwidth;
+       uint32_t rhold;
+       uint32_t rsetup;
+       bool use_bbt;
+       int wp_gpio;
+       struct mtd_partition *parts;
+       unsigned num_parts;
+};
+
+struct lpc32xx_nand_host {
+       struct nand_chip        nand_chip;
+       struct clk              *clk;
+       struct mtd_info         mtd;
+       void __iomem            *io_base;
+       struct lpc32xx_nand_cfg_slc *ncfg;
+
+       struct completion       comp;
+       struct dma_chan         *dma_chan;
+       uint32_t                dma_buf_len;
+       struct dma_slave_config dma_slave_config;
+       struct scatterlist      sgl;
+
+       /*
+        * DMA and CPU addresses of ECC work area and data buffer
+        */
+       uint32_t                *ecc_buf;
+       uint8_t                 *data_buf;
+       dma_addr_t              io_base_dma;
+};
+
+static void lpc32xx_nand_setup(struct lpc32xx_nand_host *host)
+{
+       uint32_t clkrate, tmp;
+
+       /* Reset SLC controller */
+       writel(SLCCTRL_SW_RESET, SLC_CTRL(host->io_base));
+       udelay(1000);
+
+       /* Basic setup */
+       writel(0, SLC_CFG(host->io_base));
+       writel(0, SLC_IEN(host->io_base));
+       writel((SLCSTAT_INT_TC | SLCSTAT_INT_RDY_EN),
+               SLC_ICR(host->io_base));
+
+       /* Get base clock for SLC block */
+       clkrate = clk_get_rate(host->clk);
+       if (clkrate == 0)
+               clkrate = LPC32XX_DEF_BUS_RATE;
+
+       /* Compute clock setup values */
+       tmp = SLCTAC_WDR(host->ncfg->wdr_clks) |
+               SLCTAC_WWIDTH(1 + (clkrate / host->ncfg->wwidth)) |
+               SLCTAC_WHOLD(1 + (clkrate / host->ncfg->whold)) |
+               SLCTAC_WSETUP(1 + (clkrate / host->ncfg->wsetup)) |
+               SLCTAC_RDR(host->ncfg->rdr_clks) |
+               SLCTAC_RWIDTH(1 + (clkrate / host->ncfg->rwidth)) |
+               SLCTAC_RHOLD(1 + (clkrate / host->ncfg->rhold)) |
+               SLCTAC_RSETUP(1 + (clkrate / host->ncfg->rsetup));
+       writel(tmp, SLC_TAC(host->io_base));
+}
+
+/*
+ * Hardware specific access to control lines
+ */
+static void lpc32xx_nand_cmd_ctrl(struct mtd_info *mtd, int cmd,
+       unsigned int ctrl)
+{
+       uint32_t tmp;
+       struct nand_chip *chip = mtd->priv;
+       struct lpc32xx_nand_host *host = chip->priv;
+
+       /* Does CE state need to be changed? */
+       tmp = readl(SLC_CFG(host->io_base));
+       if (ctrl & NAND_NCE)
+               tmp |= SLCCFG_CE_LOW;
+       else
+               tmp &= ~SLCCFG_CE_LOW;
+       writel(tmp, SLC_CFG(host->io_base));
+
+       if (cmd != NAND_CMD_NONE) {
+               if (ctrl & NAND_CLE)
+                       writel(cmd, SLC_CMD(host->io_base));
+               else
+                       writel(cmd, SLC_ADDR(host->io_base));
+       }
+}
+
+/*
+ * Read the Device Ready pin
+ */
+static int lpc32xx_nand_device_ready(struct mtd_info *mtd)
+{
+       struct nand_chip *chip = mtd->priv;
+       struct lpc32xx_nand_host *host = chip->priv;
+       int rdy = 0;
+
+       if ((readl(SLC_STAT(host->io_base)) & SLCSTAT_NAND_READY) != 0)
+               rdy = 1;
+
+       return rdy;
+}
+
+/*
+ * Enable NAND write protect
+ */
+static void lpc32xx_wp_enable(struct lpc32xx_nand_host *host)
+{
+       if (gpio_is_valid(host->ncfg->wp_gpio))
+               gpio_set_value(host->ncfg->wp_gpio, 0);
+}
+
+/*
+ * Disable NAND write protect
+ */
+static void lpc32xx_wp_disable(struct lpc32xx_nand_host *host)
+{
+       if (gpio_is_valid(host->ncfg->wp_gpio))
+               gpio_set_value(host->ncfg->wp_gpio, 1);
+}
+
+/*
+ * Prepares SLC for transfers with H/W ECC enabled
+ */
+static void lpc32xx_nand_ecc_enable(struct mtd_info *mtd, int mode)
+{
+       /* Hardware ECC is enabled automatically in hardware as needed */
+}
+
+/*
+ * Calculates the ECC for the data
+ */
+static int lpc32xx_nand_ecc_calculate(struct mtd_info *mtd,
+                                     const unsigned char *buf,
+                                     unsigned char *code)
+{
+       /*
+        * ECC is calculated automatically in hardware during syndrome read
+        * and write operations, so it doesn't need to be calculated here.
+        */
+       return 0;
+}
+
+/*
+ * Read a single byte from NAND device
+ */
+static uint8_t lpc32xx_nand_read_byte(struct mtd_info *mtd)
+{
+       struct nand_chip *chip = mtd->priv;
+       struct lpc32xx_nand_host *host = chip->priv;
+
+       return (uint8_t)readl(SLC_DATA(host->io_base));
+}
+
+/*
+ * Simple device read without ECC
+ */
+static void lpc32xx_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+       struct nand_chip *chip = mtd->priv;
+       struct lpc32xx_nand_host *host = chip->priv;
+
+       /* Direct device read with no ECC */
+       while (len-- > 0)
+               *buf++ = (uint8_t)readl(SLC_DATA(host->io_base));
+}
+
+/*
+ * Simple device write without ECC
+ */
+static void lpc32xx_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+       struct nand_chip *chip = mtd->priv;
+       struct lpc32xx_nand_host *host = chip->priv;
+
+       /* Direct device write with no ECC */
+       while (len-- > 0)
+               writel((uint32_t)*buf++, SLC_DATA(host->io_base));
+}
+
+/*
+ * Verify data in buffer to data on device
+ */
+static int lpc32xx_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+       struct nand_chip *chip = mtd->priv;
+       struct lpc32xx_nand_host *host = chip->priv;
+       int i;
+
+       /* DATA register must be read as 32 bits or it will fail */
+       for (i = 0; i < len; i++) {
+               if (buf[i] != (uint8_t)readl(SLC_DATA(host->io_base)))
+                       return -EFAULT;
+       }
+
+       return 0;
+}
+
+/*
+ * Read the OOB data from the device without ECC using FIFO method
+ */
+static int lpc32xx_nand_read_oob_syndrome(struct mtd_info *mtd,
+                                         struct nand_chip *chip, int page)
+{
+       chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
+       chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+       return 0;
+}
+
+/*
+ * Write the OOB data to the device without ECC using FIFO method
+ */
+static int lpc32xx_nand_write_oob_syndrome(struct mtd_info *mtd,
+       struct nand_chip *chip, int page)
+{
+       int status;
+
+       chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
+       chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+       /* Send command to program the OOB data */
+       chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+
+       status = chip->waitfunc(mtd, chip);
+
+       return status & NAND_STATUS_FAIL ? -EIO : 0;
+}
+
+/*
+ * Fills in the ECC fields in the OOB buffer with the hardware generated ECC
+ */
+static void lpc32xx_slc_ecc_copy(uint8_t *spare, const uint32_t *ecc, int count)
+{
+       int i;
+
+       for (i = 0; i < (count * 3); i += 3) {
+               uint32_t ce = ecc[i / 3];
+               ce = ~(ce << 2) & 0xFFFFFF;
+               spare[i + 2] = (uint8_t)(ce & 0xFF);
+               ce >>= 8;
+               spare[i + 1] = (uint8_t)(ce & 0xFF);
+               ce >>= 8;
+               spare[i] = (uint8_t)(ce & 0xFF);
+       }
+}
+
+static void lpc32xx_dma_complete_func(void *completion)
+{
+       complete(completion);
+}
+
+static int lpc32xx_xmit_dma(struct mtd_info *mtd, dma_addr_t dma,
+                           void *mem, int len, enum dma_transfer_direction dir)
+{
+       struct nand_chip *chip = mtd->priv;
+       struct lpc32xx_nand_host *host = chip->priv;
+       struct dma_async_tx_descriptor *desc;
+       int flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
+       int res;
+
+       host->dma_slave_config.direction = dir;
+       host->dma_slave_config.src_addr = dma;
+       host->dma_slave_config.dst_addr = dma;
+       host->dma_slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       host->dma_slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+       host->dma_slave_config.src_maxburst = 4;
+       host->dma_slave_config.dst_maxburst = 4;
+       /* DMA controller does flow control: */
+       host->dma_slave_config.device_fc = false;
+       if (dmaengine_slave_config(host->dma_chan, &host->dma_slave_config)) {
+               dev_err(mtd->dev.parent, "Failed to setup DMA slave\n");
+               return -ENXIO;
+       }
+
+       sg_init_one(&host->sgl, mem, len);
+
+       res = dma_map_sg(host->dma_chan->device->dev, &host->sgl, 1,
+                        DMA_BIDIRECTIONAL);
+       if (res != 1) {
+               dev_err(mtd->dev.parent, "Failed to map sg list\n");
+               return -ENXIO;
+       }
+       desc = dmaengine_prep_slave_sg(host->dma_chan, &host->sgl, 1, dir,
+                                      flags);
+       if (!desc) {
+               dev_err(mtd->dev.parent, "Failed to prepare slave sg\n");
+               goto out1;
+       }
+
+       init_completion(&host->comp);
+       desc->callback = lpc32xx_dma_complete_func;
+       desc->callback_param = &host->comp;
+
+       dmaengine_submit(desc);
+       dma_async_issue_pending(host->dma_chan);
+
+       wait_for_completion_timeout(&host->comp, msecs_to_jiffies(1000));
+
+       dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1,
+                    DMA_BIDIRECTIONAL);
+
+       return 0;
+out1:
+       dma_unmap_sg(host->dma_chan->device->dev, &host->sgl, 1,
+                    DMA_BIDIRECTIONAL);
+       return -ENXIO;
+}
+
+/*
+ * DMA read/write transfers with ECC support
+ */
+static int lpc32xx_xfer(struct mtd_info *mtd, uint8_t *buf, int eccsubpages,
+                       int read)
+{
+       struct nand_chip *chip = mtd->priv;
+       struct lpc32xx_nand_host *host = chip->priv;
+       int i, status = 0;
+       unsigned long timeout;
+       int res;
+       enum dma_transfer_direction dir =
+               read ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV;
+       uint8_t *dma_buf;
+       bool dma_mapped;
+
+       if ((void *)buf <= high_memory) {
+               dma_buf = buf;
+               dma_mapped = true;
+       } else {
+               dma_buf = host->data_buf;
+               dma_mapped = false;
+               if (!read)
+                       memcpy(host->data_buf, buf, mtd->writesize);
+       }
+
+       if (read) {
+               writel(readl(SLC_CFG(host->io_base)) |
+                      SLCCFG_DMA_DIR | SLCCFG_ECC_EN | SLCCFG_DMA_ECC |
+                      SLCCFG_DMA_BURST, SLC_CFG(host->io_base));
+       } else {
+               writel((readl(SLC_CFG(host->io_base)) |
+                       SLCCFG_ECC_EN | SLCCFG_DMA_ECC | SLCCFG_DMA_BURST) &
+                      ~SLCCFG_DMA_DIR,
+                       SLC_CFG(host->io_base));
+       }
+
+       /* Clear initial ECC */
+       writel(SLCCTRL_ECC_CLEAR, SLC_CTRL(host->io_base));
+
+       /* Transfer size is data area only */
+       writel(mtd->writesize, SLC_TC(host->io_base));
+
+       /* Start transfer in the NAND controller */
+       writel(readl(SLC_CTRL(host->io_base)) | SLCCTRL_DMA_START,
+              SLC_CTRL(host->io_base));
+
+       for (i = 0; i < chip->ecc.steps; i++) {
+               /* Data */
+               res = lpc32xx_xmit_dma(mtd, SLC_DMA_DATA(host->io_base_dma),
+                                      dma_buf + i * chip->ecc.size,
+                                      mtd->writesize / chip->ecc.steps, dir);
+               if (res)
+                       return res;
+
+               /* Always _read_ ECC */
+               if (i == chip->ecc.steps - 1)
+                       break;
+               if (!read) /* ECC availability delayed on write */
+                       udelay(10);
+               res = lpc32xx_xmit_dma(mtd, SLC_ECC(host->io_base_dma),
+                                      &host->ecc_buf[i], 4, DMA_DEV_TO_MEM);
+               if (res)
+                       return res;
+       }
+
+       /*
+        * According to NXP, the DMA can be finished here, but the NAND
+        * controller may still have buffered data. After porting to using the
+        * dmaengine DMA driver (amba-pl080), the condition (DMA_FIFO empty)
+        * appears to be always true, according to tests. Keeping the check for
+        * safety reasons for now.
+        */
+       if (readl(SLC_STAT(host->io_base)) & SLCSTAT_DMA_FIFO) {
+               dev_warn(mtd->dev.parent, "FIFO not empty!\n");
+               timeout = jiffies + msecs_to_jiffies(LPC32XX_DMA_TIMEOUT);
+               while ((readl(SLC_STAT(host->io_base)) & SLCSTAT_DMA_FIFO) &&
+                      time_before(jiffies, timeout))
+                       cpu_relax();
+               if (!time_before(jiffies, timeout)) {
+                       dev_err(mtd->dev.parent, "FIFO held data too long\n");
+                       status = -EIO;
+               }
+       }
+
+       /* Read last calculated ECC value */
+       if (!read)
+               udelay(10);
+       host->ecc_buf[chip->ecc.steps - 1] =
+               readl(SLC_ECC(host->io_base));
+
+       /* Flush DMA */
+       dmaengine_terminate_all(host->dma_chan);
+
+       if (readl(SLC_STAT(host->io_base)) & SLCSTAT_DMA_FIFO ||
+           readl(SLC_TC(host->io_base))) {
+               /* Something is left in the FIFO, something is wrong */
+               dev_err(mtd->dev.parent, "DMA FIFO failure\n");
+               status = -EIO;
+       }
+
+       /* Stop DMA & HW ECC */
+       writel(readl(SLC_CTRL(host->io_base)) & ~SLCCTRL_DMA_START,
+              SLC_CTRL(host->io_base));
+       writel(readl(SLC_CFG(host->io_base)) &
+              ~(SLCCFG_DMA_DIR | SLCCFG_ECC_EN | SLCCFG_DMA_ECC |
+                SLCCFG_DMA_BURST), SLC_CFG(host->io_base));
+
+       if (!dma_mapped && read)
+               memcpy(buf, host->data_buf, mtd->writesize);
+
+       return status;
+}
+
+/*
+ * Read the data and OOB data from the device, use ECC correction with the
+ * data, disable ECC for the OOB data
+ */
+static int lpc32xx_nand_read_page_syndrome(struct mtd_info *mtd,
+                                          struct nand_chip *chip, uint8_t *buf,
+                                          int oob_required, int page)
+{
+       struct lpc32xx_nand_host *host = chip->priv;
+       int stat, i, status;
+       uint8_t *oobecc, tmpecc[LPC32XX_ECC_SAVE_SIZE];
+
+       /* Issue read command */
+       chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+
+       /* Read data and oob, calculate ECC */
+       status = lpc32xx_xfer(mtd, buf, chip->ecc.steps, 1);
+
+       /* Get OOB data */
+       chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+       /* Convert to stored ECC format */
+       lpc32xx_slc_ecc_copy(tmpecc, (uint32_t *) host->ecc_buf, chip->ecc.steps);
+
+       /* Pointer to ECC data retrieved from NAND spare area */
+       oobecc = chip->oob_poi + chip->ecc.layout->eccpos[0];
+
+       for (i = 0; i < chip->ecc.steps; i++) {
+               stat = chip->ecc.correct(mtd, buf, oobecc,
+                                        &tmpecc[i * chip->ecc.bytes]);
+               if (stat < 0)
+                       mtd->ecc_stats.failed++;
+               else
+                       mtd->ecc_stats.corrected += stat;
+
+               buf += chip->ecc.size;
+               oobecc += chip->ecc.bytes;
+       }
+
+       return status;
+}
+
+/*
+ * Read the data and OOB data from the device, no ECC correction with the
+ * data or OOB data
+ */
+static int lpc32xx_nand_read_page_raw_syndrome(struct mtd_info *mtd,
+                                              struct nand_chip *chip,
+                                              uint8_t *buf, int oob_required,
+                                              int page)
+{
+       /* Issue read command */
+       chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+
+       /* Raw reads can just use the FIFO interface */
+       chip->read_buf(mtd, buf, chip->ecc.size * chip->ecc.steps);
+       chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+       return 0;
+}
+
+/*
+ * Write the data and OOB data to the device, use ECC with the data,
+ * disable ECC for the OOB data
+ */
+static int lpc32xx_nand_write_page_syndrome(struct mtd_info *mtd,
+                                           struct nand_chip *chip,
+                                           const uint8_t *buf, int oob_required)
+{
+       struct lpc32xx_nand_host *host = chip->priv;
+       uint8_t *pb = chip->oob_poi + chip->ecc.layout->eccpos[0];
+       int error;
+
+       /* Write data, calculate ECC on outbound data */
+       error = lpc32xx_xfer(mtd, (uint8_t *)buf, chip->ecc.steps, 0);
+       if (error)
+               return error;
+
+       /*
+        * The calculated ECC needs some manual work done to it before
+        * committing it to NAND. Process the calculated ECC and place
+        * the resultant values directly into the OOB buffer. */
+       lpc32xx_slc_ecc_copy(pb, (uint32_t *)host->ecc_buf, chip->ecc.steps);
+
+       /* Write ECC data to device */
+       chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+       return 0;
+}
+
+/*
+ * Write the data and OOB data to the device, no ECC correction with the
+ * data or OOB data
+ */
+static int lpc32xx_nand_write_page_raw_syndrome(struct mtd_info *mtd,
+                                               struct nand_chip *chip,
+                                               const uint8_t *buf,
+                                               int oob_required)
+{
+       /* Raw writes can just use the FIFO interface */
+       chip->write_buf(mtd, buf, chip->ecc.size * chip->ecc.steps);
+       chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+       return 0;
+}
+
+static int lpc32xx_nand_dma_setup(struct lpc32xx_nand_host *host)
+{
+       struct mtd_info *mtd = &host->mtd;
+       dma_cap_mask_t mask;
+
+       dma_cap_zero(mask);
+       dma_cap_set(DMA_SLAVE, mask);
+       host->dma_chan = dma_request_channel(mask, pl08x_filter_id, "nand-slc");
+       if (!host->dma_chan) {
+               dev_err(mtd->dev.parent, "Failed to request DMA channel\n");
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+#ifdef CONFIG_OF
+static struct lpc32xx_nand_cfg_slc *lpc32xx_parse_dt(struct device *dev)
+{
+       struct lpc32xx_nand_cfg_slc *pdata;
+       struct device_node *np = dev->of_node;
+
+       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata) {
+               dev_err(dev, "could not allocate memory for platform data\n");
+               return NULL;
+       }
+
+       of_property_read_u32(np, "nxp,wdr-clks", &pdata->wdr_clks);
+       of_property_read_u32(np, "nxp,wwidth", &pdata->wwidth);
+       of_property_read_u32(np, "nxp,whold", &pdata->whold);
+       of_property_read_u32(np, "nxp,wsetup", &pdata->wsetup);
+       of_property_read_u32(np, "nxp,rdr-clks", &pdata->rdr_clks);
+       of_property_read_u32(np, "nxp,rwidth", &pdata->rwidth);
+       of_property_read_u32(np, "nxp,rhold", &pdata->rhold);
+       of_property_read_u32(np, "nxp,rsetup", &pdata->rsetup);
+
+       if (!pdata->wdr_clks || !pdata->wwidth || !pdata->whold ||
+           !pdata->wsetup || !pdata->rdr_clks || !pdata->rwidth ||
+           !pdata->rhold || !pdata->rsetup) {
+               dev_err(dev, "chip parameters not specified correctly\n");
+               return NULL;
+       }
+
+       pdata->use_bbt = of_get_nand_on_flash_bbt(np);
+       pdata->wp_gpio = of_get_named_gpio(np, "gpios", 0);
+
+       return pdata;
+}
+#else
+static struct lpc32xx_nand_cfg_slc *lpc32xx_parse_dt(struct device *dev)
+{
+       return NULL;
+}
+#endif
+
+/*
+ * Probe for NAND controller
+ */
+static int __devinit lpc32xx_nand_probe(struct platform_device *pdev)
+{
+       struct lpc32xx_nand_host *host;
+       struct mtd_info *mtd;
+       struct nand_chip *chip;
+       struct resource *rc;
+       struct mtd_part_parser_data ppdata = {};
+       int res;
+
+       rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (rc == NULL) {
+               dev_err(&pdev->dev, "No memory resource found for device\n");
+               return -EBUSY;
+       }
+
+       /* Allocate memory for the device structure (and zero it) */
+       host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
+       if (!host) {
+               dev_err(&pdev->dev, "failed to allocate device structure\n");
+               return -ENOMEM;
+       }
+       host->io_base_dma = rc->start;
+
+       host->io_base = devm_request_and_ioremap(&pdev->dev, rc);
+       if (host->io_base == NULL) {
+               dev_err(&pdev->dev, "ioremap failed\n");
+               return -ENOMEM;
+       }
+
+       if (pdev->dev.of_node)
+               host->ncfg = lpc32xx_parse_dt(&pdev->dev);
+       else
+               host->ncfg = pdev->dev.platform_data;
+       if (!host->ncfg) {
+               dev_err(&pdev->dev, "Missing platform data\n");
+               return -ENOENT;
+       }
+       if (host->ncfg->wp_gpio == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+       if (gpio_is_valid(host->ncfg->wp_gpio) &&
+                       gpio_request(host->ncfg->wp_gpio, "NAND WP")) {
+               dev_err(&pdev->dev, "GPIO not available\n");
+               return -EBUSY;
+       }
+       lpc32xx_wp_disable(host);
+
+       mtd = &host->mtd;
+       chip = &host->nand_chip;
+       chip->priv = host;
+       mtd->priv = chip;
+       mtd->owner = THIS_MODULE;
+       mtd->dev.parent = &pdev->dev;
+
+       /* Get NAND clock */
+       host->clk = clk_get(&pdev->dev, NULL);
+       if (IS_ERR(host->clk)) {
+               dev_err(&pdev->dev, "Clock failure\n");
+               res = -ENOENT;
+               goto err_exit1;
+       }
+       clk_enable(host->clk);
+
+       /* Set NAND IO addresses and command/ready functions */
+       chip->IO_ADDR_R = SLC_DATA(host->io_base);
+       chip->IO_ADDR_W = SLC_DATA(host->io_base);
+       chip->cmd_ctrl = lpc32xx_nand_cmd_ctrl;
+       chip->dev_ready = lpc32xx_nand_device_ready;
+       chip->chip_delay = 20; /* 20us command delay time */
+
+       /* Init NAND controller */
+       lpc32xx_nand_setup(host);
+
+       platform_set_drvdata(pdev, host);
+
+       /* NAND callbacks for LPC32xx SLC hardware */
+       chip->ecc.mode = NAND_ECC_HW_SYNDROME;
+       chip->read_byte = lpc32xx_nand_read_byte;
+       chip->read_buf = lpc32xx_nand_read_buf;
+       chip->write_buf = lpc32xx_nand_write_buf;
+       chip->ecc.read_page_raw = lpc32xx_nand_read_page_raw_syndrome;
+       chip->ecc.read_page = lpc32xx_nand_read_page_syndrome;
+       chip->ecc.write_page_raw = lpc32xx_nand_write_page_raw_syndrome;
+       chip->ecc.write_page = lpc32xx_nand_write_page_syndrome;
+       chip->ecc.write_oob = lpc32xx_nand_write_oob_syndrome;
+       chip->ecc.read_oob = lpc32xx_nand_read_oob_syndrome;
+       chip->ecc.calculate = lpc32xx_nand_ecc_calculate;
+       chip->ecc.correct = nand_correct_data;
+       chip->ecc.strength = 1;
+       chip->ecc.hwctl = lpc32xx_nand_ecc_enable;
+       chip->verify_buf = lpc32xx_verify_buf;
+
+       /* bitflip_threshold's default is defined as ecc_strength anyway.
+        * Unfortunately, it is set only later at add_mtd_device(). Meanwhile
+        * being 0, it causes bad block table scanning errors in
+        * nand_scan_tail(), so preparing it here already. */
+       mtd->bitflip_threshold = chip->ecc.strength;
+
+       /*
+        * Allocate a large enough buffer for a single huge page plus
+        * extra space for the spare area and ECC storage area
+        */
+       host->dma_buf_len = LPC32XX_DMA_DATA_SIZE + LPC32XX_ECC_SAVE_SIZE;
+       host->data_buf = devm_kzalloc(&pdev->dev, host->dma_buf_len,
+                                     GFP_KERNEL);
+       if (host->data_buf == NULL) {
+               dev_err(&pdev->dev, "Error allocating memory\n");
+               res = -ENOMEM;
+               goto err_exit2;
+       }
+
+       res = lpc32xx_nand_dma_setup(host);
+       if (res) {
+               res = -EIO;
+               goto err_exit2;
+       }
+
+       /* Find NAND device */
+       if (nand_scan_ident(mtd, 1, NULL)) {
+               res = -ENXIO;
+               goto err_exit3;
+       }
+
+       /* OOB and ECC CPU and DMA work areas */
+       host->ecc_buf = (uint32_t *)(host->data_buf + LPC32XX_DMA_DATA_SIZE);
+
+       /*
+        * Small page FLASH has a unique OOB layout, but large and huge
+        * page FLASH use the standard layout. Small page FLASH uses a
+        * custom BBT marker layout.
+        */
+       if (mtd->writesize <= 512)
+               chip->ecc.layout = &lpc32xx_nand_oob_16;
+
+       /* These sizes remain the same regardless of page size */
+       chip->ecc.size = 256;
+       chip->ecc.bytes = LPC32XX_SLC_DEV_ECC_BYTES;
+       chip->ecc.prepad = chip->ecc.postpad = 0;
+
+       /* Avoid extra scan if using BBT, setup BBT support */
+       if (host->ncfg->use_bbt) {
+               chip->options |= NAND_SKIP_BBTSCAN;
+               chip->bbt_options |= NAND_BBT_USE_FLASH;
+
+               /*
+                * Use a custom BBT marker setup for small page FLASH that
+                * won't interfere with the ECC layout. Large and huge page
+                * FLASH use the standard layout.
+                */
+               if (mtd->writesize <= 512) {
+                       chip->bbt_td = &bbt_smallpage_main_descr;
+                       chip->bbt_md = &bbt_smallpage_mirror_descr;
+               }
+       }
+
+       /*
+        * Fills out all the uninitialized function pointers with the defaults
+        */
+       if (nand_scan_tail(mtd)) {
+               res = -ENXIO;
+               goto err_exit3;
+       }
+
+       /* Standard layout in FLASH for bad block tables */
+       if (host->ncfg->use_bbt) {
+               if (nand_default_bbt(mtd) < 0)
+                       dev_err(&pdev->dev,
+                              "Error initializing default bad block tables\n");
+       }
+
+       mtd->name = "nxp_lpc3220_slc";
+       ppdata.of_node = pdev->dev.of_node;
+       res = mtd_device_parse_register(mtd, NULL, &ppdata, host->ncfg->parts,
+                                       host->ncfg->num_parts);
+       if (!res)
+               return res;
+
+       nand_release(mtd);
+
+err_exit3:
+       dma_release_channel(host->dma_chan);
+err_exit2:
+       clk_disable(host->clk);
+       clk_put(host->clk);
+       platform_set_drvdata(pdev, NULL);
+err_exit1:
+       lpc32xx_wp_enable(host);
+       gpio_free(host->ncfg->wp_gpio);
+
+       return res;
+}
+
+/*
+ * Remove NAND device.
+ */
+static int __devexit lpc32xx_nand_remove(struct platform_device *pdev)
+{
+       uint32_t tmp;
+       struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
+       struct mtd_info *mtd = &host->mtd;
+
+       nand_release(mtd);
+       dma_release_channel(host->dma_chan);
+
+       /* Force CE high */
+       tmp = readl(SLC_CTRL(host->io_base));
+       tmp &= ~SLCCFG_CE_LOW;
+       writel(tmp, SLC_CTRL(host->io_base));
+
+       clk_disable(host->clk);
+       clk_put(host->clk);
+       platform_set_drvdata(pdev, NULL);
+       lpc32xx_wp_enable(host);
+       gpio_free(host->ncfg->wp_gpio);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int lpc32xx_nand_resume(struct platform_device *pdev)
+{
+       struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
+
+       /* Re-enable NAND clock */
+       clk_enable(host->clk);
+
+       /* Fresh init of NAND controller */
+       lpc32xx_nand_setup(host);
+
+       /* Disable write protect */
+       lpc32xx_wp_disable(host);
+
+       return 0;
+}
+
+static int lpc32xx_nand_suspend(struct platform_device *pdev, pm_message_t pm)
+{
+       uint32_t tmp;
+       struct lpc32xx_nand_host *host = platform_get_drvdata(pdev);
+
+       /* Force CE high */
+       tmp = readl(SLC_CTRL(host->io_base));
+       tmp &= ~SLCCFG_CE_LOW;
+       writel(tmp, SLC_CTRL(host->io_base));
+
+       /* Enable write protect for safety */
+       lpc32xx_wp_enable(host);
+
+       /* Disable clock */
+       clk_disable(host->clk);
+
+       return 0;
+}
+
+#else
+#define lpc32xx_nand_resume NULL
+#define lpc32xx_nand_suspend NULL
+#endif
+
+#if defined(CONFIG_OF)
+static const struct of_device_id lpc32xx_nand_match[] = {
+       { .compatible = "nxp,lpc3220-slc" },
+       { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, lpc32xx_nand_match);
+#endif
+
+static struct platform_driver lpc32xx_nand_driver = {
+       .probe          = lpc32xx_nand_probe,
+       .remove         = __devexit_p(lpc32xx_nand_remove),
+       .resume         = lpc32xx_nand_resume,
+       .suspend        = lpc32xx_nand_suspend,
+       .driver         = {
+               .name   = LPC32XX_MODNAME,
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(lpc32xx_nand_match),
+       },
+};
+
+module_platform_driver(lpc32xx_nand_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com>");
+MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
+MODULE_DESCRIPTION("NAND driver for the NXP LPC32XX SLC controller");
index 6acc790c2fbb96880ec29642a1d2e7e2528dbee9..3f94e1f13231b07ea43b71d945e9615eabe1fc65 100644 (file)
@@ -43,8 +43,8 @@
 
 #define nfc_is_v21()           (cpu_is_mx25() || cpu_is_mx35())
 #define nfc_is_v1()            (cpu_is_mx31() || cpu_is_mx27() || cpu_is_mx21())
-#define nfc_is_v3_2()          (cpu_is_mx51() || cpu_is_mx53())
-#define nfc_is_v3()            nfc_is_v3_2()
+#define nfc_is_v3_2a()         cpu_is_mx51()
+#define nfc_is_v3_2b()         cpu_is_mx53()
 
 /* Addresses for NFC registers */
 #define NFC_V1_V2_BUF_SIZE             (host->regs + 0x00)
 #define NFC_V3_CONFIG2_2CMD_PHASES             (1 << 4)
 #define NFC_V3_CONFIG2_NUM_ADDR_PHASE0         (1 << 5)
 #define NFC_V3_CONFIG2_ECC_MODE_8              (1 << 6)
-#define NFC_V3_CONFIG2_PPB(x)                  (((x) & 0x3) << 7)
+#define NFC_V3_CONFIG2_PPB(x, shift)           (((x) & 0x3) << shift)
 #define NFC_V3_CONFIG2_NUM_ADDR_PHASE1(x)      (((x) & 0x3) << 12)
 #define NFC_V3_CONFIG2_INT_MSK                 (1 << 15)
 #define NFC_V3_CONFIG2_ST_CMD(x)               (((x) & 0xff) << 24)
@@ -174,6 +174,7 @@ struct mxc_nand_devtype_data {
        int spare_len;
        int eccbytes;
        int eccsize;
+       int ppb_shift;
 };
 
 struct mxc_nand_host {
@@ -784,7 +785,7 @@ static void mxc_nand_select_chip_v2(struct mtd_info *mtd, int chip)
        if (chip == -1) {
                /* Disable the NFC clock */
                if (host->clk_act) {
-                       clk_disable(host->clk);
+                       clk_disable_unprepare(host->clk);
                        host->clk_act = 0;
                }
                return;
@@ -792,7 +793,7 @@ static void mxc_nand_select_chip_v2(struct mtd_info *mtd, int chip)
 
        if (!host->clk_act) {
                /* Enable the NFC clock */
-               clk_enable(host->clk);
+               clk_prepare_enable(host->clk);
                host->clk_act = 1;
        }
 
@@ -1021,7 +1022,9 @@ static void preset_v3(struct mtd_info *mtd)
        }
 
        if (mtd->writesize) {
-               config2 |= NFC_V3_CONFIG2_PPB(ffs(mtd->erasesize / mtd->writesize) - 6);
+               config2 |= NFC_V3_CONFIG2_PPB(
+                               ffs(mtd->erasesize / mtd->writesize) - 6,
+                               host->devtype_data->ppb_shift);
                host->eccsize = get_eccsize(mtd);
                if (host->eccsize == 8)
                        config2 |= NFC_V3_CONFIG2_ECC_MODE_8;
@@ -1234,7 +1237,7 @@ static const struct mxc_nand_devtype_data imx25_nand_devtype_data = {
        .eccsize = 0,
 };
 
-/* v3: i.MX51, i.MX53 */
+/* v3.2a: i.MX51 */
 static const struct mxc_nand_devtype_data imx51_nand_devtype_data = {
        .preset = preset_v3,
        .send_cmd = send_cmd_v3,
@@ -1258,6 +1261,34 @@ static const struct mxc_nand_devtype_data imx51_nand_devtype_data = {
        .spare_len = 64,
        .eccbytes = 0,
        .eccsize = 0,
+       .ppb_shift = 7,
+};
+
+/* v3.2b: i.MX53 */
+static const struct mxc_nand_devtype_data imx53_nand_devtype_data = {
+       .preset = preset_v3,
+       .send_cmd = send_cmd_v3,
+       .send_addr = send_addr_v3,
+       .send_page = send_page_v3,
+       .send_read_id = send_read_id_v3,
+       .get_dev_status = get_dev_status_v3,
+       .check_int = check_int_v3,
+       .irq_control = irq_control_v3,
+       .get_ecc_status = get_ecc_status_v3,
+       .ecclayout_512 = &nandv2_hw_eccoob_smallpage,
+       .ecclayout_2k = &nandv2_hw_eccoob_largepage,
+       .ecclayout_4k = &nandv2_hw_eccoob_smallpage, /* XXX: needs fix */
+       .select_chip = mxc_nand_select_chip_v1_v3,
+       .correct_data = mxc_nand_correct_data_v2_v3,
+       .irqpending_quirk = 0,
+       .needs_ip = 1,
+       .regs_offset = 0,
+       .spare0_offset = 0x1000,
+       .axi_offset = 0x1e00,
+       .spare_len = 64,
+       .eccbytes = 0,
+       .eccsize = 0,
+       .ppb_shift = 8,
 };
 
 #ifdef CONFIG_OF_MTD
@@ -1274,6 +1305,9 @@ static const struct of_device_id mxcnd_dt_ids[] = {
        }, {
                .compatible = "fsl,imx51-nand",
                .data = &imx51_nand_devtype_data,
+       }, {
+               .compatible = "fsl,imx53-nand",
+               .data = &imx53_nand_devtype_data,
        },
        { /* sentinel */ }
 };
@@ -1327,8 +1361,10 @@ static int __init mxcnd_probe_pdata(struct mxc_nand_host *host)
                        host->devtype_data = &imx27_nand_devtype_data;
        } else if (nfc_is_v21()) {
                host->devtype_data = &imx25_nand_devtype_data;
-       } else if (nfc_is_v3_2()) {
+       } else if (nfc_is_v3_2a()) {
                host->devtype_data = &imx51_nand_devtype_data;
+       } else if (nfc_is_v3_2b()) {
+               host->devtype_data = &imx53_nand_devtype_data;
        } else
                BUG();
 
@@ -1344,8 +1380,8 @@ static int __init mxcnd_probe(struct platform_device *pdev)
        int err = 0;
 
        /* Allocate memory for MTD device structure and private data */
-       host = kzalloc(sizeof(struct mxc_nand_host) + NAND_MAX_PAGESIZE +
-                       NAND_MAX_OOBSIZE, GFP_KERNEL);
+       host = devm_kzalloc(&pdev->dev, sizeof(struct mxc_nand_host) +
+                       NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE, GFP_KERNEL);
        if (!host)
                return -ENOMEM;
 
@@ -1372,34 +1408,37 @@ static int __init mxcnd_probe(struct platform_device *pdev)
        this->read_buf = mxc_nand_read_buf;
        this->verify_buf = mxc_nand_verify_buf;
 
-       host->clk = clk_get(&pdev->dev, "nfc");
-       if (IS_ERR(host->clk)) {
-               err = PTR_ERR(host->clk);
-               goto eclk;
-       }
+       host->clk = devm_clk_get(&pdev->dev, "nfc");
+       if (IS_ERR(host->clk))
+               return PTR_ERR(host->clk);
 
-       clk_prepare_enable(host->clk);
-       host->clk_act = 1;
+       err = mxcnd_probe_dt(host);
+       if (err > 0)
+               err = mxcnd_probe_pdata(host);
+       if (err < 0)
+               return err;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               err = -ENODEV;
-               goto eres;
-       }
+       if (host->devtype_data->needs_ip) {
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+               if (!res)
+                       return -ENODEV;
+               host->regs_ip = devm_request_and_ioremap(&pdev->dev, res);
+               if (!host->regs_ip)
+                       return -ENOMEM;
 
-       host->base = ioremap(res->start, resource_size(res));
-       if (!host->base) {
-               err = -ENOMEM;
-               goto eres;
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       } else {
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        }
 
-       host->main_area0 = host->base;
+       if (!res)
+               return -ENODEV;
 
-       err = mxcnd_probe_dt(host);
-       if (err > 0)
-               err = mxcnd_probe_pdata(host);
-       if (err < 0)
-               goto eirq;
+       host->base = devm_request_and_ioremap(&pdev->dev, res);
+       if (!host->base)
+               return -ENOMEM;
+
+       host->main_area0 = host->base;
 
        if (host->devtype_data->regs_offset)
                host->regs = host->base + host->devtype_data->regs_offset;
@@ -1414,19 +1453,6 @@ static int __init mxcnd_probe(struct platform_device *pdev)
        this->ecc.size = 512;
        this->ecc.layout = host->devtype_data->ecclayout_512;
 
-       if (host->devtype_data->needs_ip) {
-               res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-               if (!res) {
-                       err = -ENODEV;
-                       goto eirq;
-               }
-               host->regs_ip = ioremap(res->start, resource_size(res));
-               if (!host->regs_ip) {
-                       err = -ENOMEM;
-                       goto eirq;
-               }
-       }
-
        if (host->pdata.hw_ecc) {
                this->ecc.calculate = mxc_nand_calculate_ecc;
                this->ecc.hwctl = mxc_nand_enable_hwecc;
@@ -1458,9 +1484,13 @@ static int __init mxcnd_probe(struct platform_device *pdev)
         */
        host->devtype_data->irq_control(host, 0);
 
-       err = request_irq(host->irq, mxc_nfc_irq, IRQF_DISABLED, DRIVER_NAME, host);
+       err = devm_request_irq(&pdev->dev, host->irq, mxc_nfc_irq,
+                       IRQF_DISABLED, DRIVER_NAME, host);
        if (err)
-               goto eirq;
+               return err;
+
+       clk_prepare_enable(host->clk);
+       host->clk_act = 1;
 
        /*
         * Now that we "own" the interrupt make sure the interrupt mask bit is
@@ -1512,15 +1542,7 @@ static int __init mxcnd_probe(struct platform_device *pdev)
        return 0;
 
 escan:
-       free_irq(host->irq, host);
-eirq:
-       if (host->regs_ip)
-               iounmap(host->regs_ip);
-       iounmap(host->base);
-eres:
-       clk_put(host->clk);
-eclk:
-       kfree(host);
+       clk_disable_unprepare(host->clk);
 
        return err;
 }
@@ -1529,16 +1551,9 @@ static int __devexit mxcnd_remove(struct platform_device *pdev)
 {
        struct mxc_nand_host *host = platform_get_drvdata(pdev);
 
-       clk_put(host->clk);
-
        platform_set_drvdata(pdev, NULL);
 
        nand_release(&host->mtd);
-       free_irq(host->irq, host);
-       if (host->regs_ip)
-               iounmap(host->regs_ip);
-       iounmap(host->base);
-       kfree(host);
 
        return 0;
 }
index a11253a0fcabd6ef7362b9fcae4972ba06fc4966..ead301a455ee8784caa7002c633000b1bb4d913c 100644 (file)
@@ -1565,14 +1565,6 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
                                        oobreadlen -= toread;
                                }
                        }
-
-                       if (!(chip->options & NAND_NO_READRDY)) {
-                               /* Apply delay or wait for ready/busy pin */
-                               if (!chip->dev_ready)
-                                       udelay(chip->chip_delay);
-                               else
-                                       nand_wait_ready(mtd);
-                       }
                } else {
                        memcpy(buf, chip->buffers->databuf + col, bytes);
                        buf += bytes;
@@ -1633,7 +1625,7 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
        ops.len = len;
        ops.datbuf = buf;
        ops.oobbuf = NULL;
-       ops.mode = 0;
+       ops.mode = MTD_OPS_PLACE_OOB;
        ret = nand_do_read_ops(mtd, from, &ops);
        *retlen = ops.retlen;
        nand_release_device(mtd);
@@ -1837,14 +1829,6 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
                len = min(len, readlen);
                buf = nand_transfer_oob(chip, buf, ops, len);
 
-               if (!(chip->options & NAND_NO_READRDY)) {
-                       /* Apply delay or wait for ready/busy pin */
-                       if (!chip->dev_ready)
-                               udelay(chip->chip_delay);
-                       else
-                               nand_wait_ready(mtd);
-               }
-
                readlen -= len;
                if (!readlen)
                        break;
@@ -1927,12 +1911,14 @@ out:
  *
  * Not for syndrome calculating ECC controllers, which use a special oob layout.
  */
-static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
                                const uint8_t *buf, int oob_required)
 {
        chip->write_buf(mtd, buf, mtd->writesize);
        if (oob_required)
                chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+       return 0;
 }
 
 /**
@@ -1944,7 +1930,7 @@ static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
  *
  * We need a special oob layout and handling even when ECC isn't checked.
  */
-static void nand_write_page_raw_syndrome(struct mtd_info *mtd,
+static int nand_write_page_raw_syndrome(struct mtd_info *mtd,
                                        struct nand_chip *chip,
                                        const uint8_t *buf, int oob_required)
 {
@@ -1974,6 +1960,8 @@ static void nand_write_page_raw_syndrome(struct mtd_info *mtd,
        size = mtd->oobsize - (oob - chip->oob_poi);
        if (size)
                chip->write_buf(mtd, oob, size);
+
+       return 0;
 }
 /**
  * nand_write_page_swecc - [REPLACEABLE] software ECC based page write function
@@ -1982,7 +1970,7 @@ static void nand_write_page_raw_syndrome(struct mtd_info *mtd,
  * @buf: data buffer
  * @oob_required: must write chip->oob_poi to OOB
  */
-static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
+static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
                                  const uint8_t *buf, int oob_required)
 {
        int i, eccsize = chip->ecc.size;
@@ -1999,7 +1987,7 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
        for (i = 0; i < chip->ecc.total; i++)
                chip->oob_poi[eccpos[i]] = ecc_calc[i];
 
-       chip->ecc.write_page_raw(mtd, chip, buf, 1);
+       return chip->ecc.write_page_raw(mtd, chip, buf, 1);
 }
 
 /**
@@ -2009,7 +1997,7 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
  * @buf: data buffer
  * @oob_required: must write chip->oob_poi to OOB
  */
-static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
+static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
                                  const uint8_t *buf, int oob_required)
 {
        int i, eccsize = chip->ecc.size;
@@ -2029,6 +2017,8 @@ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
                chip->oob_poi[eccpos[i]] = ecc_calc[i];
 
        chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+       return 0;
 }
 
 /**
@@ -2041,7 +2031,7 @@ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
  * The hw generator calculates the error syndrome automatically. Therefore we
  * need a special oob layout and handling.
  */
-static void nand_write_page_syndrome(struct mtd_info *mtd,
+static int nand_write_page_syndrome(struct mtd_info *mtd,
                                    struct nand_chip *chip,
                                    const uint8_t *buf, int oob_required)
 {
@@ -2075,6 +2065,8 @@ static void nand_write_page_syndrome(struct mtd_info *mtd,
        i = mtd->oobsize - (oob - chip->oob_poi);
        if (i)
                chip->write_buf(mtd, oob, i);
+
+       return 0;
 }
 
 /**
@@ -2096,9 +2088,12 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
        chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
 
        if (unlikely(raw))
-               chip->ecc.write_page_raw(mtd, chip, buf, oob_required);
+               status = chip->ecc.write_page_raw(mtd, chip, buf, oob_required);
        else
-               chip->ecc.write_page(mtd, chip, buf, oob_required);
+               status = chip->ecc.write_page(mtd, chip, buf, oob_required);
+
+       if (status < 0)
+               return status;
 
        /*
         * Cached progamming disabled for now. Not sure if it's worth the
@@ -2336,7 +2331,7 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
        ops.len = len;
        ops.datbuf = (uint8_t *)buf;
        ops.oobbuf = NULL;
-       ops.mode = 0;
+       ops.mode = MTD_OPS_PLACE_OOB;
 
        ret = nand_do_write_ops(mtd, to, &ops);
 
@@ -2365,7 +2360,7 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
        ops.len = len;
        ops.datbuf = (uint8_t *)buf;
        ops.oobbuf = NULL;
-       ops.mode = 0;
+       ops.mode = MTD_OPS_PLACE_OOB;
        ret = nand_do_write_ops(mtd, to, &ops);
        *retlen = ops.retlen;
        nand_release_device(mtd);
@@ -2915,7 +2910,6 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
                *busw = NAND_BUSWIDTH_16;
 
        chip->options &= ~NAND_CHIPOPTIONS_MSK;
-       chip->options |= NAND_NO_READRDY & NAND_CHIPOPTIONS_MSK;
 
        pr_info("ONFI flash detected\n");
        return 1;
index 30d1319ff0657ce75b063023d9eee0c65d2f5873..9a5402e320bf1f761f652970376abf23fe86b8f6 100644 (file)
@@ -22,7 +22,7 @@
  * BBT on flash. If a BBT is found then the contents are read and the memory
  * based BBT is created. If a mirrored BBT is selected then the mirror is
  * searched too and the versions are compared. If the mirror has a greater
- * version number than the mirror BBT is used to build the memory based BBT.
+ * version number, then the mirror BBT is used to build the memory based BBT.
  * If the tables are not versioned, then we "or" the bad block information.
  * If one of the BBTs is out of date or does not exist it is (re)created.
  * If no BBT exists at all then the device is scanned for factory marked
 #include <linux/delay.h>
 #include <linux/vmalloc.h>
 #include <linux/export.h>
+#include <linux/string.h>
 
 static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td)
 {
-       int ret;
-
-       ret = memcmp(buf, td->pattern, td->len);
-       if (!ret)
-               return ret;
-       return -1;
+       if (memcmp(buf, td->pattern, td->len))
+               return -1;
+       return 0;
 }
 
 /**
@@ -92,19 +90,16 @@ static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td)
  */
 static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)
 {
-       int i, end = 0;
+       int end = 0;
        uint8_t *p = buf;
 
        if (td->options & NAND_BBT_NO_OOB)
                return check_pattern_no_oob(buf, td);
 
        end = paglen + td->offs;
-       if (td->options & NAND_BBT_SCANEMPTY) {
-               for (i = 0; i < end; i++) {
-                       if (p[i] != 0xff)
-                               return -1;
-               }
-       }
+       if (td->options & NAND_BBT_SCANEMPTY)
+               if (memchr_inv(p, 0xff, end))
+                       return -1;
        p += end;
 
        /* Compare the pattern */
@@ -114,10 +109,8 @@ static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_desc
        if (td->options & NAND_BBT_SCANEMPTY) {
                p += td->len;
                end += td->len;
-               for (i = end; i < len; i++) {
-                       if (*p++ != 0xff)
-                               return -1;
-               }
+               if (memchr_inv(p, 0xff, len - end))
+                       return -1;
        }
        return 0;
 }
@@ -133,14 +126,9 @@ static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_desc
  */
 static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td)
 {
-       int i;
-       uint8_t *p = buf;
-
        /* Compare the pattern */
-       for (i = 0; i < td->len; i++) {
-               if (p[td->offs + i] != td->pattern[i])
-                       return -1;
-       }
+       if (memcmp(buf + td->offs, td->pattern, td->len))
+               return -1;
        return 0;
 }
 
@@ -288,7 +276,7 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
 }
 
 /* BBT marker is in the first page, no OOB */
-static int scan_read_raw_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
+static int scan_read_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
                         struct nand_bbt_descr *td)
 {
        size_t retlen;
@@ -301,14 +289,24 @@ static int scan_read_raw_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
        return mtd_read(mtd, offs, len, &retlen, buf);
 }
 
-/* Scan read raw data from flash */
-static int scan_read_raw_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
+/**
+ * scan_read_oob - [GENERIC] Scan data+OOB region to buffer
+ * @mtd: MTD device structure
+ * @buf: temporary buffer
+ * @offs: offset at which to scan
+ * @len: length of data region to read
+ *
+ * Scan read data from data+OOB. May traverse multiple pages, interleaving
+ * page,OOB,page,OOB,... in buf. Completes transfer and returns the "strongest"
+ * ECC condition (error or bitflip). May quit on the first (non-ECC) error.
+ */
+static int scan_read_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
                         size_t len)
 {
        struct mtd_oob_ops ops;
-       int res;
+       int res, ret = 0;
 
-       ops.mode = MTD_OPS_RAW;
+       ops.mode = MTD_OPS_PLACE_OOB;
        ops.ooboffs = 0;
        ops.ooblen = mtd->oobsize;
 
@@ -318,24 +316,27 @@ static int scan_read_raw_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
                ops.oobbuf = buf + ops.len;
 
                res = mtd_read_oob(mtd, offs, &ops);
-
-               if (res)
-                       return res;
+               if (res) {
+                       if (!mtd_is_bitflip_or_eccerr(res))
+                               return res;
+                       else if (mtd_is_eccerr(res) || !ret)
+                               ret = res;
+               }
 
                buf += mtd->oobsize + mtd->writesize;
                len -= mtd->writesize;
                offs += mtd->writesize;
        }
-       return 0;
+       return ret;
 }
 
-static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
+static int scan_read(struct mtd_info *mtd, uint8_t *buf, loff_t offs,
                         size_t len, struct nand_bbt_descr *td)
 {
        if (td->options & NAND_BBT_NO_OOB)
-               return scan_read_raw_data(mtd, buf, offs, td);
+               return scan_read_data(mtd, buf, offs, td);
        else
-               return scan_read_raw_oob(mtd, buf, offs, len);
+               return scan_read_oob(mtd, buf, offs, len);
 }
 
 /* Scan write data with oob to flash */
@@ -373,14 +374,14 @@ static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td)
  * Read the bad block table(s) for all chips starting at a given page. We
  * assume that the bbt bits are in consecutive order.
  */
-static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
-                        struct nand_bbt_descr *td, struct nand_bbt_descr *md)
+static void read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
+                         struct nand_bbt_descr *td, struct nand_bbt_descr *md)
 {
        struct nand_chip *this = mtd->priv;
 
        /* Read the primary version, if available */
        if (td->options & NAND_BBT_VERSION) {
-               scan_read_raw(mtd, buf, (loff_t)td->pages[0] << this->page_shift,
+               scan_read(mtd, buf, (loff_t)td->pages[0] << this->page_shift,
                              mtd->writesize, td);
                td->version[0] = buf[bbt_get_ver_offs(mtd, td)];
                pr_info("Bad block table at page %d, version 0x%02X\n",
@@ -389,13 +390,12 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,
 
        /* Read the mirror version, if available */
        if (md && (md->options & NAND_BBT_VERSION)) {
-               scan_read_raw(mtd, buf, (loff_t)md->pages[0] << this->page_shift,
-                             mtd->writesize, td);
+               scan_read(mtd, buf, (loff_t)md->pages[0] << this->page_shift,
+                             mtd->writesize, md);
                md->version[0] = buf[bbt_get_ver_offs(mtd, md)];
                pr_info("Bad block table at page %d, version 0x%02X\n",
                         md->pages[0], md->version[0]);
        }
-       return 1;
 }
 
 /* Scan a given block full */
@@ -405,7 +405,7 @@ static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd,
 {
        int ret, j;
 
-       ret = scan_read_raw_oob(mtd, buf, offs, readlen);
+       ret = scan_read_oob(mtd, buf, offs, readlen);
        /* Ignore ECC errors when checking for BBM */
        if (ret && !mtd_is_bitflip_or_eccerr(ret))
                return ret;
@@ -594,7 +594,7 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
                        loff_t offs = (loff_t)actblock << this->bbt_erase_shift;
 
                        /* Read first page */
-                       scan_read_raw(mtd, buf, offs, mtd->writesize, td);
+                       scan_read(mtd, buf, offs, mtd->writesize, td);
                        if (!check_pattern(buf, scanlen, mtd->writesize, td)) {
                                td->pages[i] = actblock << blocktopage;
                                if (td->options & NAND_BBT_VERSION) {
@@ -626,7 +626,9 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
  *
  * Search and read the bad block table(s).
  */
-static int search_read_bbts(struct mtd_info *mtd, uint8_t * buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md)
+static void search_read_bbts(struct mtd_info *mtd, uint8_t *buf,
+                            struct nand_bbt_descr *td,
+                            struct nand_bbt_descr *md)
 {
        /* Search the primary table */
        search_bbt(mtd, buf, td);
@@ -634,9 +636,6 @@ static int search_read_bbts(struct mtd_info *mtd, uint8_t * buf, struct nand_bbt
        /* Search the mirror table */
        if (md)
                search_bbt(mtd, buf, md);
-
-       /* Force result check */
-       return 1;
 }
 
 /**
@@ -1162,14 +1161,13 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
 
        /* Is the bbt at a given page? */
        if (td->options & NAND_BBT_ABSPAGE) {
-               res = read_abs_bbts(mtd, buf, td, md);
+               read_abs_bbts(mtd, buf, td, md);
        } else {
                /* Search the bad block table using a pattern in oob */
-               res = search_read_bbts(mtd, buf, td, md);
+               search_read_bbts(mtd, buf, td, md);
        }
 
-       if (res)
-               res = check_create(mtd, buf, bd);
+       res = check_create(mtd, buf, bd);
 
        /* Prevent the bbt regions from erasing / writing */
        mark_bbt_region(mtd, td);
@@ -1274,7 +1272,7 @@ static struct nand_bbt_descr bbt_mirror_descr = {
        .pattern = mirror_pattern
 };
 
-static struct nand_bbt_descr bbt_main_no_bbt_descr = {
+static struct nand_bbt_descr bbt_main_no_oob_descr = {
        .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
                | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP
                | NAND_BBT_NO_OOB,
@@ -1284,7 +1282,7 @@ static struct nand_bbt_descr bbt_main_no_bbt_descr = {
        .pattern = bbt_pattern
 };
 
-static struct nand_bbt_descr bbt_mirror_no_bbt_descr = {
+static struct nand_bbt_descr bbt_mirror_no_oob_descr = {
        .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
                | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP
                | NAND_BBT_NO_OOB,
@@ -1355,8 +1353,8 @@ int nand_default_bbt(struct mtd_info *mtd)
                /* Use the default pattern descriptors */
                if (!this->bbt_td) {
                        if (this->bbt_options & NAND_BBT_NO_OOB) {
-                               this->bbt_td = &bbt_main_no_bbt_descr;
-                               this->bbt_md = &bbt_mirror_no_bbt_descr;
+                               this->bbt_td = &bbt_main_no_oob_descr;
+                               this->bbt_md = &bbt_mirror_no_oob_descr;
                        } else {
                                this->bbt_td = &bbt_main_descr;
                                this->bbt_md = &bbt_mirror_descr;
index 198b304d6f7298ce61b049af9d382fcb744b92ca..d90186684db85ff18a99fbbb95f93a466824e37b 100644 (file)
@@ -17,7 +17,7 @@
 /* ---- Include Files ---------------------------------------------------- */
 #include <mach/reg_umi.h>
 #include <mach/reg_nand.h>
-#include <cfg_global.h>
+#include <mach/cfg_global.h>
 
 /* ---- Constants and Types ---------------------------------------------- */
 #if (CFG_GLOBAL_CHIP_FAMILY == CFG_GLOBAL_CHIP_FAMILY_BCMRING)
@@ -48,7 +48,7 @@ int nand_bcm_umi_bch_correct_page(uint8_t *datap, uint8_t *readEccData,
 /* Check in device is ready */
 static inline int nand_bcm_umi_dev_ready(void)
 {
-       return REG_UMI_NAND_RCSR & REG_UMI_NAND_RCSR_RDY;
+       return readl(&REG_UMI_NAND_RCSR) & REG_UMI_NAND_RCSR_RDY;
 }
 
 /* Wait until device is ready */
@@ -62,10 +62,11 @@ static inline void nand_bcm_umi_wait_till_ready(void)
 static inline void nand_bcm_umi_hamming_enable_hwecc(void)
 {
        /* disable and reset ECC, 512 byte page */
-       REG_UMI_NAND_ECC_CSR &= ~(REG_UMI_NAND_ECC_CSR_ECC_ENABLE |
-               REG_UMI_NAND_ECC_CSR_256BYTE);
+       writel(readl(&REG_UMI_NAND_ECC_CSR) & ~(REG_UMI_NAND_ECC_CSR_ECC_ENABLE |
+               REG_UMI_NAND_ECC_CSR_256BYTE), &REG_UMI_NAND_ECC_CSR);
        /* enable ECC */
-       REG_UMI_NAND_ECC_CSR |= REG_UMI_NAND_ECC_CSR_ECC_ENABLE;
+       writel(readl(&REG_UMI_NAND_ECC_CSR) | REG_UMI_NAND_ECC_CSR_ECC_ENABLE,
+               &REG_UMI_NAND_ECC_CSR);
 }
 
 #if NAND_ECC_BCH
@@ -76,18 +77,18 @@ static inline void nand_bcm_umi_hamming_enable_hwecc(void)
 static inline void nand_bcm_umi_bch_enable_read_hwecc(void)
 {
        /* disable and reset ECC */
-       REG_UMI_BCH_CTRL_STATUS = REG_UMI_BCH_CTRL_STATUS_RD_ECC_VALID;
+       writel(REG_UMI_BCH_CTRL_STATUS_RD_ECC_VALID, &REG_UMI_BCH_CTRL_STATUS);
        /* Turn on ECC */
-       REG_UMI_BCH_CTRL_STATUS = REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN;
+       writel(REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN, &REG_UMI_BCH_CTRL_STATUS);
 }
 
 /* Enable BCH Write ECC */
 static inline void nand_bcm_umi_bch_enable_write_hwecc(void)
 {
        /* disable and reset ECC */
-       REG_UMI_BCH_CTRL_STATUS = REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID;
+       writel(REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID, &REG_UMI_BCH_CTRL_STATUS);
        /* Turn on ECC */
-       REG_UMI_BCH_CTRL_STATUS = REG_UMI_BCH_CTRL_STATUS_ECC_WR_EN;
+       writel(REG_UMI_BCH_CTRL_STATUS_ECC_WR_EN, &REG_UMI_BCH_CTRL_STATUS);
 }
 
 /* Config number of BCH ECC bytes */
@@ -99,9 +100,9 @@ static inline void nand_bcm_umi_bch_config_ecc(uint8_t numEccBytes)
        uint32_t numBits = numEccBytes * 8;
 
        /* disable and reset ECC */
-       REG_UMI_BCH_CTRL_STATUS =
-           REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID |
-           REG_UMI_BCH_CTRL_STATUS_RD_ECC_VALID;
+       writel(REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID |
+              REG_UMI_BCH_CTRL_STATUS_RD_ECC_VALID,
+              &REG_UMI_BCH_CTRL_STATUS);
 
        /* Every correctible bit requires 13 ECC bits */
        tValue = (uint32_t) (numBits / ECC_BITS_PER_CORRECTABLE_BIT);
@@ -113,23 +114,21 @@ static inline void nand_bcm_umi_bch_config_ecc(uint8_t numEccBytes)
        kValue = nValue - (tValue * ECC_BITS_PER_CORRECTABLE_BIT);
 
        /* Write the settings */
-       REG_UMI_BCH_N = nValue;
-       REG_UMI_BCH_T = tValue;
-       REG_UMI_BCH_K = kValue;
+       writel(nValue, &REG_UMI_BCH_N);
+       writel(tValue, &REG_UMI_BCH_T);
+       writel(kValue, &REG_UMI_BCH_K);
 }
 
 /* Pause during ECC read calculation to skip bytes in OOB */
 static inline void nand_bcm_umi_bch_pause_read_ecc_calc(void)
 {
-       REG_UMI_BCH_CTRL_STATUS =
-           REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN |
-           REG_UMI_BCH_CTRL_STATUS_PAUSE_ECC_DEC;
+       writel(REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN | REG_UMI_BCH_CTRL_STATUS_PAUSE_ECC_DEC, &REG_UMI_BCH_CTRL_STATUS);
 }
 
 /* Resume during ECC read calculation after skipping bytes in OOB */
 static inline void nand_bcm_umi_bch_resume_read_ecc_calc(void)
 {
-       REG_UMI_BCH_CTRL_STATUS = REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN;
+       writel(REG_UMI_BCH_CTRL_STATUS_ECC_RD_EN, &REG_UMI_BCH_CTRL_STATUS);
 }
 
 /* Poll read ECC calc to check when hardware completes */
@@ -139,7 +138,7 @@ static inline uint32_t nand_bcm_umi_bch_poll_read_ecc_calc(void)
 
        do {
                /* wait for ECC to be valid */
-               regVal = REG_UMI_BCH_CTRL_STATUS;
+               regVal = readl(&REG_UMI_BCH_CTRL_STATUS);
        } while ((regVal & REG_UMI_BCH_CTRL_STATUS_RD_ECC_VALID) == 0);
 
        return regVal;
@@ -149,7 +148,7 @@ static inline uint32_t nand_bcm_umi_bch_poll_read_ecc_calc(void)
 static inline void nand_bcm_umi_bch_poll_write_ecc_calc(void)
 {
        /* wait for ECC to be valid */
-       while ((REG_UMI_BCH_CTRL_STATUS & REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID)
+       while ((readl(&REG_UMI_BCH_CTRL_STATUS) & REG_UMI_BCH_CTRL_STATUS_WR_ECC_VALID)
               == 0)
                ;
 }
@@ -170,9 +169,9 @@ static inline void nand_bcm_umi_bch_read_oobEcc(uint32_t pageSize,
        if (pageSize != NAND_DATA_ACCESS_SIZE) {
                /* skip BI */
 #if defined(__KERNEL__) && !defined(STANDALONE)
-               *oobp++ = REG_NAND_DATA8;
+               *oobp++ = readb(&REG_NAND_DATA8);
 #else
-               REG_NAND_DATA8;
+               readb(&REG_NAND_DATA8);
 #endif
                numToRead--;
        }
@@ -180,9 +179,9 @@ static inline void nand_bcm_umi_bch_read_oobEcc(uint32_t pageSize,
        while (numToRead > numEccBytes) {
                /* skip free oob region */
 #if defined(__KERNEL__) && !defined(STANDALONE)
-               *oobp++ = REG_NAND_DATA8;
+               *oobp++ = readb(&REG_NAND_DATA8);
 #else
-               REG_NAND_DATA8;
+               readb(&REG_NAND_DATA8);
 #endif
                numToRead--;
        }
@@ -193,11 +192,11 @@ static inline void nand_bcm_umi_bch_read_oobEcc(uint32_t pageSize,
 
                while (numToRead > 11) {
 #if defined(__KERNEL__) && !defined(STANDALONE)
-                       *oobp = REG_NAND_DATA8;
+                       *oobp = readb(&REG_NAND_DATA8);
                        eccCalc[eccPos++] = *oobp;
                        oobp++;
 #else
-                       eccCalc[eccPos++] = REG_NAND_DATA8;
+                       eccCalc[eccPos++] = readb(&REG_NAND_DATA8);
 #endif
                        numToRead--;
                }
@@ -207,9 +206,9 @@ static inline void nand_bcm_umi_bch_read_oobEcc(uint32_t pageSize,
                if (numToRead == 11) {
                        /* read BI */
 #if defined(__KERNEL__) && !defined(STANDALONE)
-                       *oobp++ = REG_NAND_DATA8;
+                       *oobp++ = readb(&REG_NAND_DATA8);
 #else
-                       REG_NAND_DATA8;
+                       readb(&REG_NAND_DATA8);
 #endif
                        numToRead--;
                }
@@ -219,11 +218,11 @@ static inline void nand_bcm_umi_bch_read_oobEcc(uint32_t pageSize,
        nand_bcm_umi_bch_resume_read_ecc_calc();
        while (numToRead) {
 #if defined(__KERNEL__) && !defined(STANDALONE)
-               *oobp = REG_NAND_DATA8;
+               *oobp = readb(&REG_NAND_DATA8);
                eccCalc[eccPos++] = *oobp;
                oobp++;
 #else
-               eccCalc[eccPos++] = REG_NAND_DATA8;
+               eccCalc[eccPos++] = readb(&REG_NAND_DATA8);
 #endif
                numToRead--;
        }
@@ -255,7 +254,7 @@ static inline void nand_bcm_umi_bch_write_oobEcc(uint32_t pageSize,
        if (pageSize == NAND_DATA_ACCESS_SIZE) {
                /* Now fill in the ECC bytes */
                if (numEccBytes >= 13)
-                       eccVal = REG_UMI_BCH_WR_ECC_3;
+                       eccVal = readl(&REG_UMI_BCH_WR_ECC_3);
 
                /* Usually we skip CM in oob[0,1] */
                NAND_BCM_UMI_ECC_WRITE(numEccBytes, 15, &oobp[0],
@@ -268,7 +267,7 @@ static inline void nand_bcm_umi_bch_write_oobEcc(uint32_t pageSize,
                        eccVal & 0xff); /* ECC 12 */
 
                if (numEccBytes >= 9)
-                       eccVal = REG_UMI_BCH_WR_ECC_2;
+                       eccVal = readl(&REG_UMI_BCH_WR_ECC_2);
 
                NAND_BCM_UMI_ECC_WRITE(numEccBytes, 12, &oobp[3],
                        (eccVal >> 24) & 0xff); /* ECC11 */
@@ -281,7 +280,7 @@ static inline void nand_bcm_umi_bch_write_oobEcc(uint32_t pageSize,
 
                /* Now fill in the ECC bytes */
                if (numEccBytes >= 13)
-                       eccVal = REG_UMI_BCH_WR_ECC_3;
+                       eccVal = readl(&REG_UMI_BCH_WR_ECC_3);
 
                /* Usually skip CM in oob[1,2] */
                NAND_BCM_UMI_ECC_WRITE(numEccBytes, 15, &oobp[1],
@@ -294,7 +293,7 @@ static inline void nand_bcm_umi_bch_write_oobEcc(uint32_t pageSize,
                        eccVal & 0xff); /* ECC12 */
 
                if (numEccBytes >= 9)
-                       eccVal = REG_UMI_BCH_WR_ECC_2;
+                       eccVal = readl(&REG_UMI_BCH_WR_ECC_2);
 
                NAND_BCM_UMI_ECC_WRITE(numEccBytes, 12, &oobp[4],
                        (eccVal >> 24) & 0xff); /* ECC11 */
@@ -309,7 +308,7 @@ static inline void nand_bcm_umi_bch_write_oobEcc(uint32_t pageSize,
                eccVal & 0xff); /* ECC8 */
 
        if (numEccBytes >= 5)
-               eccVal = REG_UMI_BCH_WR_ECC_1;
+               eccVal = readl(&REG_UMI_BCH_WR_ECC_1);
 
        NAND_BCM_UMI_ECC_WRITE(numEccBytes, 8, &oobp[8],
                (eccVal >> 24) & 0xff); /* ECC7 */
@@ -321,7 +320,7 @@ static inline void nand_bcm_umi_bch_write_oobEcc(uint32_t pageSize,
                eccVal & 0xff); /* ECC4 */
 
        if (numEccBytes >= 1)
-               eccVal = REG_UMI_BCH_WR_ECC_0;
+               eccVal = readl(&REG_UMI_BCH_WR_ECC_0);
 
        NAND_BCM_UMI_ECC_WRITE(numEccBytes, 4, &oobp[12],
                (eccVal >> 24) & 0xff); /* ECC3 */
index 621b70b7a159099ffc3060bdf2651a38dc2dae43..e3aa2748a6e7af1cac818aaa170d5f6aff253056 100644 (file)
@@ -70,7 +70,7 @@ struct nand_flash_dev nand_flash_ids[] = {
         * These are the new chips with large page size. The pagesize and the
         * erasesize is determined from the extended id bytes
         */
-#define LP_OPTIONS (NAND_SAMSUNG_LP_OPTIONS | NAND_NO_READRDY)
+#define LP_OPTIONS NAND_SAMSUNG_LP_OPTIONS
 #define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16)
 
        /* 512 Megabit */
@@ -157,7 +157,7 @@ struct nand_flash_dev nand_flash_ids[] = {
         * writes possible, but not implemented now
         */
        {"AND 128MiB 3,3V 8-bit",       0x01, 2048, 128, 0x4000,
-        NAND_IS_AND | NAND_NO_READRDY | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH},
+        NAND_IS_AND | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH},
 
        {NULL,}
 };
@@ -174,8 +174,9 @@ struct nand_manufacturers nand_manuf_ids[] = {
        {NAND_MFR_STMICRO, "ST Micro"},
        {NAND_MFR_HYNIX, "Hynix"},
        {NAND_MFR_MICRON, "Micron"},
-       {NAND_MFR_AMD, "AMD"},
+       {NAND_MFR_AMD, "AMD/Spansion"},
        {NAND_MFR_MACRONIX, "Macronix"},
+       {NAND_MFR_EON, "Eon"},
        {0x0, "Unknown"}
 };
 
index e9309b3659e746096b08a953fd055e2517babb3d..ac4fd756eda375ab40f873b9f29bcaad0a5aeea0 100644 (file)
@@ -1245,7 +1245,6 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
                        goto out_release_mem_region;
                } else {
                        struct dma_slave_config cfg;
-                       int rc;
 
                        memset(&cfg, 0, sizeof(cfg));
                        cfg.src_addr = info->phys_base;
@@ -1254,10 +1253,10 @@ static int __devinit omap_nand_probe(struct platform_device *pdev)
                        cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
                        cfg.src_maxburst = 16;
                        cfg.dst_maxburst = 16;
-                       rc = dmaengine_slave_config(info->dma, &cfg);
-                       if (rc) {
+                       err = dmaengine_slave_config(info->dma, &cfg);
+                       if (err) {
                                dev_err(&pdev->dev, "DMA engine slave config failed: %d\n",
-                                       rc);
+                                       err);
                                goto out_release_mem_region;
                        }
                        info->nand.read_buf   = omap_read_buf_dma_pref;
index 252aaefcacfa2ba0e07d1425672afcaa8c665bdf..9c086911b3af827fd419b4de9d6bdb509755a6b5 100644 (file)
@@ -22,6 +22,8 @@
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <mach/dma.h>
 #include <plat/pxa3xx_nand.h>
@@ -681,11 +683,13 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
        info->state = STATE_IDLE;
 }
 
-static void pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd,
+static int pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd,
                struct nand_chip *chip, const uint8_t *buf, int oob_required)
 {
        chip->write_buf(mtd, buf, mtd->writesize);
        chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+       return 0;
 }
 
 static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,
@@ -1005,7 +1009,6 @@ KEEP_CONFIG:
        chip->ecc.size = host->page_size;
        chip->ecc.strength = 1;
 
-       chip->options |= NAND_NO_READRDY;
        if (host->reg_ndcr & NDCR_DWIDTH_M)
                chip->options |= NAND_BUSWIDTH_16;
 
@@ -1081,21 +1084,31 @@ static int alloc_nand_resource(struct platform_device *pdev)
        }
        clk_enable(info->clk);
 
-       r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-       if (r == NULL) {
-               dev_err(&pdev->dev, "no resource defined for data DMA\n");
-               ret = -ENXIO;
-               goto fail_put_clk;
-       }
-       info->drcmr_dat = r->start;
+       /*
+        * This is a dirty hack to make this driver work from devicetree
+        * bindings. It can be removed once we have a prober DMA controller
+        * framework for DT.
+        */
+       if (pdev->dev.of_node && cpu_is_pxa3xx()) {
+               info->drcmr_dat = 97;
+               info->drcmr_cmd = 99;
+       } else {
+               r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+               if (r == NULL) {
+                       dev_err(&pdev->dev, "no resource defined for data DMA\n");
+                       ret = -ENXIO;
+                       goto fail_put_clk;
+               }
+               info->drcmr_dat = r->start;
 
-       r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-       if (r == NULL) {
-               dev_err(&pdev->dev, "no resource defined for command DMA\n");
-               ret = -ENXIO;
-               goto fail_put_clk;
+               r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+               if (r == NULL) {
+                       dev_err(&pdev->dev, "no resource defined for command DMA\n");
+                       ret = -ENXIO;
+                       goto fail_put_clk;
+               }
+               info->drcmr_cmd = r->start;
        }
-       info->drcmr_cmd = r->start;
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
@@ -1200,12 +1213,55 @@ static int pxa3xx_nand_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_OF
+static struct of_device_id pxa3xx_nand_dt_ids[] = {
+       { .compatible = "marvell,pxa3xx-nand" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, i2c_pxa_dt_ids);
+
+static int pxa3xx_nand_probe_dt(struct platform_device *pdev)
+{
+       struct pxa3xx_nand_platform_data *pdata;
+       struct device_node *np = pdev->dev.of_node;
+       const struct of_device_id *of_id =
+                       of_match_device(pxa3xx_nand_dt_ids, &pdev->dev);
+
+       if (!of_id)
+               return 0;
+
+       pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return -ENOMEM;
+
+       if (of_get_property(np, "marvell,nand-enable-arbiter", NULL))
+               pdata->enable_arbiter = 1;
+       if (of_get_property(np, "marvell,nand-keep-config", NULL))
+               pdata->keep_config = 1;
+       of_property_read_u32(np, "num-cs", &pdata->num_cs);
+
+       pdev->dev.platform_data = pdata;
+
+       return 0;
+}
+#else
+static inline int pxa3xx_nand_probe_dt(struct platform_device *)
+{
+       return 0;
+}
+#endif
+
 static int pxa3xx_nand_probe(struct platform_device *pdev)
 {
        struct pxa3xx_nand_platform_data *pdata;
+       struct mtd_part_parser_data ppdata = {};
        struct pxa3xx_nand_info *info;
        int ret, cs, probe_success;
 
+       ret = pxa3xx_nand_probe_dt(pdev);
+       if (ret)
+               return ret;
+
        pdata = pdev->dev.platform_data;
        if (!pdata) {
                dev_err(&pdev->dev, "no platform data defined\n");
@@ -1229,8 +1285,9 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
                        continue;
                }
 
+               ppdata.of_node = pdev->dev.of_node;
                ret = mtd_device_parse_register(info->host[cs]->mtd, NULL,
-                                               NULL, pdata->parts[cs],
+                                               &ppdata, pdata->parts[cs],
                                                pdata->nr_parts[cs]);
                if (!ret)
                        probe_success = 1;
@@ -1306,6 +1363,7 @@ static int pxa3xx_nand_resume(struct platform_device *pdev)
 static struct platform_driver pxa3xx_nand_driver = {
        .driver = {
                .name   = "pxa3xx-nand",
+               .of_match_table = of_match_ptr(pxa3xx_nand_dt_ids),
        },
        .probe          = pxa3xx_nand_probe,
        .remove         = pxa3xx_nand_remove,
index aa9b8a5e0b8f94b66f6356b4346000feeea0e6d8..0b798fbf902cd225d0969c9bbf625f5662e44919 100644 (file)
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
+#include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
+#include <linux/string.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
@@ -43,11 +45,17 @@ static struct nand_ecclayout flctl_4secc_oob_16 = {
 };
 
 static struct nand_ecclayout flctl_4secc_oob_64 = {
-       .eccbytes = 10,
-       .eccpos = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57},
+       .eccbytes = 4 * 10,
+       .eccpos = {
+                6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+               22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+               38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+               54, 55, 56, 57, 58, 59, 60, 61, 62, 63 },
        .oobfree = {
-               {.offset = 60,
-               . length = 4} },
+               {.offset =  2, .length = 4},
+               {.offset = 16, .length = 6},
+               {.offset = 32, .length = 6},
+               {.offset = 48, .length = 6} },
 };
 
 static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
@@ -61,15 +69,17 @@ static struct nand_bbt_descr flctl_4secc_smallpage = {
 
 static struct nand_bbt_descr flctl_4secc_largepage = {
        .options = NAND_BBT_SCAN2NDPAGE,
-       .offs = 58,
+       .offs = 0,
        .len = 2,
        .pattern = scan_ff_pattern,
 };
 
+static int loop_timeout_max;
+
 static void empty_fifo(struct sh_flctl *flctl)
 {
-       writel(0x000c0000, FLINTDMACR(flctl));  /* FIFO Clear */
-       writel(0x00000000, FLINTDMACR(flctl));  /* Clear Error flags */
+       writel(flctl->flintdmacr_base | AC1CLR | AC0CLR, FLINTDMACR(flctl));
+       writel(flctl->flintdmacr_base, FLINTDMACR(flctl));
 }
 
 static void start_translation(struct sh_flctl *flctl)
@@ -84,7 +94,7 @@ static void timeout_error(struct sh_flctl *flctl, const char *str)
 
 static void wait_completion(struct sh_flctl *flctl)
 {
-       uint32_t timeout = LOOP_TIMEOUT_MAX;
+       uint32_t timeout = loop_timeout_max;
 
        while (timeout--) {
                if (readb(FLTRCR(flctl)) & TREND) {
@@ -131,7 +141,7 @@ static void set_addr(struct mtd_info *mtd, int column, int page_addr)
 
 static void wait_rfifo_ready(struct sh_flctl *flctl)
 {
-       uint32_t timeout = LOOP_TIMEOUT_MAX;
+       uint32_t timeout = loop_timeout_max;
 
        while (timeout--) {
                uint32_t val;
@@ -146,7 +156,7 @@ static void wait_rfifo_ready(struct sh_flctl *flctl)
 
 static void wait_wfifo_ready(struct sh_flctl *flctl)
 {
-       uint32_t len, timeout = LOOP_TIMEOUT_MAX;
+       uint32_t len, timeout = loop_timeout_max;
 
        while (timeout--) {
                /* check FIFO */
@@ -158,27 +168,56 @@ static void wait_wfifo_ready(struct sh_flctl *flctl)
        timeout_error(flctl, __func__);
 }
 
-static int wait_recfifo_ready(struct sh_flctl *flctl, int sector_number)
+static enum flctl_ecc_res_t wait_recfifo_ready
+               (struct sh_flctl *flctl, int sector_number)
 {
-       uint32_t timeout = LOOP_TIMEOUT_MAX;
-       int checked[4];
+       uint32_t timeout = loop_timeout_max;
        void __iomem *ecc_reg[4];
        int i;
+       int state = FL_SUCCESS;
        uint32_t data, size;
 
-       memset(checked, 0, sizeof(checked));
-
+       /*
+        * First this loops checks in FLDTCNTR if we are ready to read out the
+        * oob data. This is the case if either all went fine without errors or
+        * if the bottom part of the loop corrected the errors or marked them as
+        * uncorrectable and the controller is given time to push the data into
+        * the FIFO.
+        */
        while (timeout--) {
+               /* check if all is ok and we can read out the OOB */
                size = readl(FLDTCNTR(flctl)) >> 24;
-               if (size & 0xFF)
-                       return 0;       /* success */
+               if ((size & 0xFF) == 4)
+                       return state;
+
+               /* check if a correction code has been calculated */
+               if (!(readl(FL4ECCCR(flctl)) & _4ECCEND)) {
+                       /*
+                        * either we wait for the fifo to be filled or a
+                        * correction pattern is being generated
+                        */
+                       udelay(1);
+                       continue;
+               }
 
-               if (readl(FL4ECCCR(flctl)) & _4ECCFA)
-                       return 1;       /* can't correct */
+               /* check for an uncorrectable error */
+               if (readl(FL4ECCCR(flctl)) & _4ECCFA) {
+                       /* check if we face a non-empty page */
+                       for (i = 0; i < 512; i++) {
+                               if (flctl->done_buff[i] != 0xff) {
+                                       state = FL_ERROR; /* can't correct */
+                                       break;
+                               }
+                       }
 
-               udelay(1);
-               if (!(readl(FL4ECCCR(flctl)) & _4ECCEND))
+                       if (state == FL_SUCCESS)
+                               dev_dbg(&flctl->pdev->dev,
+                               "reading empty sector %d, ecc error ignored\n",
+                               sector_number);
+
+                       writel(0, FL4ECCCR(flctl));
                        continue;
+               }
 
                /* start error correction */
                ecc_reg[0] = FL4ECCRESULT0(flctl);
@@ -187,33 +226,31 @@ static int wait_recfifo_ready(struct sh_flctl *flctl, int sector_number)
                ecc_reg[3] = FL4ECCRESULT3(flctl);
 
                for (i = 0; i < 3; i++) {
+                       uint8_t org;
+                       int index;
+
                        data = readl(ecc_reg[i]);
-                       if (data != INIT_FL4ECCRESULT_VAL && !checked[i]) {
-                               uint8_t org;
-                               int index;
-
-                               if (flctl->page_size)
-                                       index = (512 * sector_number) +
-                                               (data >> 16);
-                               else
-                                       index = data >> 16;
-
-                               org = flctl->done_buff[index];
-                               flctl->done_buff[index] = org ^ (data & 0xFF);
-                               checked[i] = 1;
-                       }
-               }
 
+                       if (flctl->page_size)
+                               index = (512 * sector_number) +
+                                       (data >> 16);
+                       else
+                               index = data >> 16;
+
+                       org = flctl->done_buff[index];
+                       flctl->done_buff[index] = org ^ (data & 0xFF);
+               }
+               state = FL_REPAIRABLE;
                writel(0, FL4ECCCR(flctl));
        }
 
        timeout_error(flctl, __func__);
-       return 1;       /* timeout */
+       return FL_TIMEOUT;      /* timeout */
 }
 
 static void wait_wecfifo_ready(struct sh_flctl *flctl)
 {
-       uint32_t timeout = LOOP_TIMEOUT_MAX;
+       uint32_t timeout = loop_timeout_max;
        uint32_t len;
 
        while (timeout--) {
@@ -241,31 +278,33 @@ static void read_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
 {
        int i, len_4align;
        unsigned long *buf = (unsigned long *)&flctl->done_buff[offset];
-       void *fifo_addr = (void *)FLDTFIFO(flctl);
 
        len_4align = (rlen + 3) / 4;
 
        for (i = 0; i < len_4align; i++) {
                wait_rfifo_ready(flctl);
-               buf[i] = readl(fifo_addr);
+               buf[i] = readl(FLDTFIFO(flctl));
                buf[i] = be32_to_cpu(buf[i]);
        }
 }
 
-static int read_ecfiforeg(struct sh_flctl *flctl, uint8_t *buff, int sector)
+static enum flctl_ecc_res_t read_ecfiforeg
+               (struct sh_flctl *flctl, uint8_t *buff, int sector)
 {
        int i;
+       enum flctl_ecc_res_t res;
        unsigned long *ecc_buf = (unsigned long *)buff;
-       void *fifo_addr = (void *)FLECFIFO(flctl);
 
-       for (i = 0; i < 4; i++) {
-               if (wait_recfifo_ready(flctl , sector))
-                       return 1;
-               ecc_buf[i] = readl(fifo_addr);
-               ecc_buf[i] = be32_to_cpu(ecc_buf[i]);
+       res = wait_recfifo_ready(flctl , sector);
+
+       if (res != FL_ERROR) {
+               for (i = 0; i < 4; i++) {
+                       ecc_buf[i] = readl(FLECFIFO(flctl));
+                       ecc_buf[i] = be32_to_cpu(ecc_buf[i]);
+               }
        }
 
-       return 0;
+       return res;
 }
 
 static void write_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
@@ -281,6 +320,18 @@ static void write_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
        }
 }
 
+static void write_ec_fiforeg(struct sh_flctl *flctl, int rlen, int offset)
+{
+       int i, len_4align;
+       unsigned long *data = (unsigned long *)&flctl->done_buff[offset];
+
+       len_4align = (rlen + 3) / 4;
+       for (i = 0; i < len_4align; i++) {
+               wait_wecfifo_ready(flctl);
+               writel(cpu_to_be32(data[i]), FLECFIFO(flctl));
+       }
+}
+
 static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_val)
 {
        struct sh_flctl *flctl = mtd_to_flctl(mtd);
@@ -346,73 +397,65 @@ static void set_cmd_regs(struct mtd_info *mtd, uint32_t cmd, uint32_t flcmcdr_va
 static int flctl_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
                                uint8_t *buf, int oob_required, int page)
 {
-       int i, eccsize = chip->ecc.size;
-       int eccbytes = chip->ecc.bytes;
-       int eccsteps = chip->ecc.steps;
-       uint8_t *p = buf;
-       struct sh_flctl *flctl = mtd_to_flctl(mtd);
-
-       for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
-               chip->read_buf(mtd, p, eccsize);
-
-       for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
-               if (flctl->hwecc_cant_correct[i])
-                       mtd->ecc_stats.failed++;
-               else
-                       mtd->ecc_stats.corrected += 0; /* FIXME */
-       }
-
+       chip->read_buf(mtd, buf, mtd->writesize);
+       if (oob_required)
+               chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
        return 0;
 }
 
-static void flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
+static int flctl_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
                                   const uint8_t *buf, int oob_required)
 {
-       int i, eccsize = chip->ecc.size;
-       int eccbytes = chip->ecc.bytes;
-       int eccsteps = chip->ecc.steps;
-       const uint8_t *p = buf;
-
-       for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
-               chip->write_buf(mtd, p, eccsize);
+       chip->write_buf(mtd, buf, mtd->writesize);
+       chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+       return 0;
 }
 
 static void execmd_read_page_sector(struct mtd_info *mtd, int page_addr)
 {
        struct sh_flctl *flctl = mtd_to_flctl(mtd);
        int sector, page_sectors;
+       enum flctl_ecc_res_t ecc_result;
 
-       if (flctl->page_size)
-               page_sectors = 4;
-       else
-               page_sectors = 1;
-
-       writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE | _4ECCCORRECT,
-                FLCMNCR(flctl));
+       page_sectors = flctl->page_size ? 4 : 1;
 
        set_cmd_regs(mtd, NAND_CMD_READ0,
                (NAND_CMD_READSTART << 8) | NAND_CMD_READ0);
 
-       for (sector = 0; sector < page_sectors; sector++) {
-               int ret;
+       writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE | _4ECCCORRECT,
+                FLCMNCR(flctl));
+       writel(readl(FLCMDCR(flctl)) | page_sectors, FLCMDCR(flctl));
+       writel(page_addr << 2, FLADR(flctl));
 
-               empty_fifo(flctl);
-               writel(readl(FLCMDCR(flctl)) | 1, FLCMDCR(flctl));
-               writel(page_addr << 2 | sector, FLADR(flctl));
+       empty_fifo(flctl);
+       start_translation(flctl);
 
-               start_translation(flctl);
+       for (sector = 0; sector < page_sectors; sector++) {
                read_fiforeg(flctl, 512, 512 * sector);
 
-               ret = read_ecfiforeg(flctl,
+               ecc_result = read_ecfiforeg(flctl,
                        &flctl->done_buff[mtd->writesize + 16 * sector],
                        sector);
 
-               if (ret)
-                       flctl->hwecc_cant_correct[sector] = 1;
-
-               writel(0x0, FL4ECCCR(flctl));
-               wait_completion(flctl);
+               switch (ecc_result) {
+               case FL_REPAIRABLE:
+                       dev_info(&flctl->pdev->dev,
+                               "applied ecc on page 0x%x", page_addr);
+                       flctl->mtd.ecc_stats.corrected++;
+                       break;
+               case FL_ERROR:
+                       dev_warn(&flctl->pdev->dev,
+                               "page 0x%x contains corrupted data\n",
+                               page_addr);
+                       flctl->mtd.ecc_stats.failed++;
+                       break;
+               default:
+                       ;
+               }
        }
+
+       wait_completion(flctl);
+
        writel(readl(FLCMNCR(flctl)) & ~(ACM_SACCES_MODE | _4ECCCORRECT),
                        FLCMNCR(flctl));
 }
@@ -420,30 +463,20 @@ static void execmd_read_page_sector(struct mtd_info *mtd, int page_addr)
 static void execmd_read_oob(struct mtd_info *mtd, int page_addr)
 {
        struct sh_flctl *flctl = mtd_to_flctl(mtd);
+       int page_sectors = flctl->page_size ? 4 : 1;
+       int i;
 
        set_cmd_regs(mtd, NAND_CMD_READ0,
                (NAND_CMD_READSTART << 8) | NAND_CMD_READ0);
 
        empty_fifo(flctl);
-       if (flctl->page_size) {
-               int i;
-               /* In case that the page size is 2k */
-               for (i = 0; i < 16 * 3; i++)
-                       flctl->done_buff[i] = 0xFF;
-
-               set_addr(mtd, 3 * 528 + 512, page_addr);
-               writel(16, FLDTCNTR(flctl));
 
-               start_translation(flctl);
-               read_fiforeg(flctl, 16, 16 * 3);
-               wait_completion(flctl);
-       } else {
-               /* In case that the page size is 512b */
-               set_addr(mtd, 512, page_addr);
+       for (i = 0; i < page_sectors; i++) {
+               set_addr(mtd, (512 + 16) * i + 512 , page_addr);
                writel(16, FLDTCNTR(flctl));
 
                start_translation(flctl);
-               read_fiforeg(flctl, 16, 0);
+               read_fiforeg(flctl, 16, 16 * i);
                wait_completion(flctl);
        }
 }
@@ -451,34 +484,26 @@ static void execmd_read_oob(struct mtd_info *mtd, int page_addr)
 static void execmd_write_page_sector(struct mtd_info *mtd)
 {
        struct sh_flctl *flctl = mtd_to_flctl(mtd);
-       int i, page_addr = flctl->seqin_page_addr;
+       int page_addr = flctl->seqin_page_addr;
        int sector, page_sectors;
 
-       if (flctl->page_size)
-               page_sectors = 4;
-       else
-               page_sectors = 1;
-
-       writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE, FLCMNCR(flctl));
+       page_sectors = flctl->page_size ? 4 : 1;
 
        set_cmd_regs(mtd, NAND_CMD_PAGEPROG,
                        (NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN);
 
-       for (sector = 0; sector < page_sectors; sector++) {
-               empty_fifo(flctl);
-               writel(readl(FLCMDCR(flctl)) | 1, FLCMDCR(flctl));
-               writel(page_addr << 2 | sector, FLADR(flctl));
+       empty_fifo(flctl);
+       writel(readl(FLCMNCR(flctl)) | ACM_SACCES_MODE, FLCMNCR(flctl));
+       writel(readl(FLCMDCR(flctl)) | page_sectors, FLCMDCR(flctl));
+       writel(page_addr << 2, FLADR(flctl));
+       start_translation(flctl);
 
-               start_translation(flctl);
+       for (sector = 0; sector < page_sectors; sector++) {
                write_fiforeg(flctl, 512, 512 * sector);
-
-               for (i = 0; i < 4; i++) {
-                       wait_wecfifo_ready(flctl); /* wait for write ready */
-                       writel(0xFFFFFFFF, FLECFIFO(flctl));
-               }
-               wait_completion(flctl);
+               write_ec_fiforeg(flctl, 16, mtd->writesize + 16 * sector);
        }
 
+       wait_completion(flctl);
        writel(readl(FLCMNCR(flctl)) & ~ACM_SACCES_MODE, FLCMNCR(flctl));
 }
 
@@ -488,18 +513,12 @@ static void execmd_write_oob(struct mtd_info *mtd)
        int page_addr = flctl->seqin_page_addr;
        int sector, page_sectors;
 
-       if (flctl->page_size) {
-               sector = 3;
-               page_sectors = 4;
-       } else {
-               sector = 0;
-               page_sectors = 1;
-       }
+       page_sectors = flctl->page_size ? 4 : 1;
 
        set_cmd_regs(mtd, NAND_CMD_PAGEPROG,
                        (NAND_CMD_PAGEPROG << 8) | NAND_CMD_SEQIN);
 
-       for (; sector < page_sectors; sector++) {
+       for (sector = 0; sector < page_sectors; sector++) {
                empty_fifo(flctl);
                set_addr(mtd, sector * 528 + 512, page_addr);
                writel(16, FLDTCNTR(flctl));    /* set read size */
@@ -731,10 +750,9 @@ 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 i, index = flctl->index;
+       int index = flctl->index;
 
-       for (i = 0; i < len; i++)
-               flctl->done_buff[index + i] = buf[i];
+       memcpy(&flctl->done_buff[index], buf, len);
        flctl->index += len;
 }
 
@@ -763,10 +781,11 @@ static uint16_t flctl_read_word(struct mtd_info *mtd)
 
 static void flctl_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 {
-       int i;
+       struct sh_flctl *flctl = mtd_to_flctl(mtd);
+       int index = flctl->index;
 
-       for (i = 0; i < len; i++)
-               buf[i] = flctl_read_byte(mtd);
+       memcpy(buf, &flctl->done_buff[index], len);
+       flctl->index += len;
 }
 
 static int flctl_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
@@ -831,7 +850,7 @@ static int flctl_chip_init_tail(struct mtd_info *mtd)
                chip->ecc.mode = NAND_ECC_HW;
 
                /* 4 symbols ECC enabled */
-               flctl->flcmncr_base |= _4ECCEN | ECCPOS2 | ECCPOS_02;
+               flctl->flcmncr_base |= _4ECCEN;
        } else {
                chip->ecc.mode = NAND_ECC_SOFT;
        }
@@ -839,6 +858,16 @@ static int flctl_chip_init_tail(struct mtd_info *mtd)
        return 0;
 }
 
+static irqreturn_t flctl_handle_flste(int irq, void *dev_id)
+{
+       struct sh_flctl *flctl = dev_id;
+
+       dev_err(&flctl->pdev->dev, "flste irq: %x\n", readl(FLINTDMACR(flctl)));
+       writel(flctl->flintdmacr_base, FLINTDMACR(flctl));
+
+       return IRQ_HANDLED;
+}
+
 static int __devinit flctl_probe(struct platform_device *pdev)
 {
        struct resource *res;
@@ -847,6 +876,7 @@ static int __devinit flctl_probe(struct platform_device *pdev)
        struct nand_chip *nand;
        struct sh_flctl_platform_data *pdata;
        int ret = -ENXIO;
+       int irq;
 
        pdata = pdev->dev.platform_data;
        if (pdata == NULL) {
@@ -872,14 +902,27 @@ static int __devinit flctl_probe(struct platform_device *pdev)
                goto err_iomap;
        }
 
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "failed to get flste irq data\n");
+               goto err_flste;
+       }
+
+       ret = request_irq(irq, flctl_handle_flste, IRQF_SHARED, "flste", flctl);
+       if (ret) {
+               dev_err(&pdev->dev, "request interrupt failed.\n");
+               goto err_flste;
+       }
+
        platform_set_drvdata(pdev, flctl);
        flctl_mtd = &flctl->mtd;
        nand = &flctl->chip;
        flctl_mtd->priv = nand;
        flctl->pdev = pdev;
-       flctl->flcmncr_base = pdata->flcmncr_val;
        flctl->hwecc = pdata->has_hwecc;
        flctl->holden = pdata->use_holden;
+       flctl->flcmncr_base = pdata->flcmncr_val;
+       flctl->flintdmacr_base = flctl->hwecc ? (STERINTE | ECERB) : STERINTE;
 
        /* Set address of hardware control function */
        /* 20 us command delay time */
@@ -900,6 +943,8 @@ static int __devinit flctl_probe(struct platform_device *pdev)
        pm_runtime_enable(&pdev->dev);
        pm_runtime_resume(&pdev->dev);
 
+       loop_timeout_max = loops_per_jiffy * msecs_to_jiffies(LOOP_TIMEOUT_MS);
+
        ret = nand_scan_ident(flctl_mtd, 1, NULL);
        if (ret)
                goto err_chip;
@@ -918,6 +963,9 @@ static int __devinit flctl_probe(struct platform_device *pdev)
 
 err_chip:
        pm_runtime_disable(&pdev->dev);
+       free_irq(irq, flctl);
+err_flste:
+       iounmap(flctl->reg);
 err_iomap:
        kfree(flctl);
        return ret;
@@ -929,6 +977,8 @@ static int __devexit flctl_remove(struct platform_device *pdev)
 
        nand_release(&flctl->mtd);
        pm_runtime_disable(&pdev->dev);
+       free_irq(platform_get_irq(pdev, 0), flctl);
+       iounmap(flctl->reg);
        kfree(flctl);
 
        return 0;
index 2aec4f3b72be3d9975ce92d83b1fdd063872a95b..42b0f7456fc4a4876d94ed1131c5dab1c7ff7dee 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
+#include <linux/random.h>
 
 #define PRINT_PREF KERN_INFO "mtd_speedtest: "
 
@@ -47,25 +48,13 @@ static int ebcnt;
 static int pgcnt;
 static int goodebcnt;
 static struct timeval start, finish;
-static unsigned long next = 1;
-
-static inline unsigned int simple_rand(void)
-{
-       next = next * 1103515245 + 12345;
-       return (unsigned int)((next / 65536) % 32768);
-}
-
-static inline void simple_srand(unsigned long seed)
-{
-       next = seed;
-}
 
 static void set_random_data(unsigned char *buf, size_t len)
 {
        size_t i;
 
        for (i = 0; i < len; ++i)
-               buf[i] = simple_rand();
+               buf[i] = random32();
 }
 
 static int erase_eraseblock(int ebnum)
@@ -407,7 +396,6 @@ static int __init mtd_speedtest_init(void)
                goto out;
        }
 
-       simple_srand(1);
        set_random_data(iobuf, mtd->erasesize);
 
        err = scan_for_bad_eraseblocks();
index 7b33f22d0b583196ae0a7fb5ccd6563293e239af..cb268cebf01ae0c7fec1c3951975bc22bde34daa 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/slab.h>
 #include <linux/sched.h>
 #include <linux/vmalloc.h>
+#include <linux/random.h>
 
 #define PRINT_PREF KERN_INFO "mtd_stresstest: "
 
@@ -48,28 +49,13 @@ static int pgsize;
 static int bufsize;
 static int ebcnt;
 static int pgcnt;
-static unsigned long next = 1;
-
-static inline unsigned int simple_rand(void)
-{
-       next = next * 1103515245 + 12345;
-       return (unsigned int)((next / 65536) % 32768);
-}
-
-static inline void simple_srand(unsigned long seed)
-{
-       next = seed;
-}
 
 static int rand_eb(void)
 {
-       int eb;
+       unsigned int eb;
 
 again:
-       if (ebcnt < 32768)
-               eb = simple_rand();
-       else
-               eb = (simple_rand() << 15) | simple_rand();
+       eb = random32();
        /* Read or write up 2 eraseblocks at a time - hence 'ebcnt - 1' */
        eb %= (ebcnt - 1);
        if (bbt[eb])
@@ -79,24 +65,18 @@ again:
 
 static int rand_offs(void)
 {
-       int offs;
+       unsigned int offs;
 
-       if (bufsize < 32768)
-               offs = simple_rand();
-       else
-               offs = (simple_rand() << 15) | simple_rand();
+       offs = random32();
        offs %= bufsize;
        return offs;
 }
 
 static int rand_len(int offs)
 {
-       int len;
+       unsigned int len;
 
-       if (bufsize < 32768)
-               len = simple_rand();
-       else
-               len = (simple_rand() << 15) | simple_rand();
+       len = random32();
        len %= (bufsize - offs);
        return len;
 }
@@ -211,7 +191,7 @@ static int do_write(void)
 
 static int do_operation(void)
 {
-       if (simple_rand() & 1)
+       if (random32() & 1)
                return do_read();
        else
                return do_write();
@@ -302,9 +282,8 @@ static int __init mtd_stresstest_init(void)
        }
        for (i = 0; i < ebcnt; i++)
                offsets[i] = mtd->erasesize;
-       simple_srand(current->pid);
        for (i = 0; i < bufsize; i++)
-               writebuf[i] = simple_rand();
+               writebuf[i] = random32();
 
        err = scan_for_bad_eraseblocks();
        if (err)
index ea4b95b5451c8b6c2ec25a0905c5e4af7e1e76ee..b2f4f0f032f1912ec31eaaffb42d2fe17de84cf0 100644 (file)
@@ -27,20 +27,16 @@ config MTD_UBI_WL_THRESHOLD
          life-cycle less than 10000, the threshold should be lessened (e.g.,
          to 128 or 256, although it does not have to be power of 2).
 
-config MTD_UBI_BEB_RESERVE
-       int "Percentage of reserved eraseblocks for bad eraseblocks handling"
+config MTD_UBI_BEB_LIMIT
+       int "Percentage of maximum expected bad eraseblocks"
        default 2
        range 0 25
        help
-         If the MTD device admits of bad eraseblocks (e.g. NAND flash), UBI
-         reserves some amount of physical eraseblocks to handle new bad
-         eraseblocks. For example, if a flash physical eraseblock becomes bad,
-         UBI uses these reserved physical eraseblocks to relocate the bad one.
-         This option specifies how many physical eraseblocks will be reserved
-         for bad eraseblock handling (percents of total number of good flash
-         eraseblocks). If the underlying flash does not admit of bad
-         eraseblocks (e.g. NOR flash), this value is ignored and nothing is
-         reserved. Leave the default value if unsure.
+         This option specifies the maximum bad physical eraseblocks UBI
+         expects on the UBI device (percents of total number of physical
+         eraseblocks on this MTD partition). If the underlying flash does not
+         admit of bad eraseblocks (e.g. NOR flash), this value is ignored.
+         Leave the default value if unsure.
 
 config MTD_UBI_GLUEBI
        tristate "MTD devices emulation driver (gluebi)"
index 2c5ed5ca9c3370bdf64ec05ccfab068585975fdf..7b6b5f9c4343bf4e564fa6c9b6127ce14008c534 100644 (file)
@@ -607,8 +607,18 @@ static int io_init(struct ubi_device *ubi)
        ubi->peb_count  = mtd_div_by_eb(ubi->mtd->size, ubi->mtd);
        ubi->flash_size = ubi->mtd->size;
 
-       if (mtd_can_have_bb(ubi->mtd))
+       if (mtd_can_have_bb(ubi->mtd)) {
                ubi->bad_allowed = 1;
+               if (CONFIG_MTD_UBI_BEB_LIMIT > 0) {
+                       int percent = CONFIG_MTD_UBI_BEB_LIMIT;
+                       int limit = mult_frac(ubi->peb_count, percent, 100);
+
+                       /* Round it up */
+                       if (mult_frac(limit, 100, percent) < ubi->peb_count)
+                               limit += 1;
+                       ubi->bad_peb_limit = limit;
+               }
+       }
 
        if (ubi->mtd->type == MTD_NORFLASH) {
                ubi_assert(ubi->mtd->writesize == 1);
index 8bbfb444b89525cbb9c0a071914a4de0af65f1fe..d089df055484fdd16a4cd3085b6b04424fbd877a 100644 (file)
@@ -121,10 +121,18 @@ void ubi_update_reserved(struct ubi_device *ubi)
  */
 void ubi_calculate_reserved(struct ubi_device *ubi)
 {
-       ubi->beb_rsvd_level = ubi->good_peb_count/100;
-       ubi->beb_rsvd_level *= CONFIG_MTD_UBI_BEB_RESERVE;
-       if (ubi->beb_rsvd_level < MIN_RESEVED_PEBS)
-               ubi->beb_rsvd_level = MIN_RESEVED_PEBS;
+       /*
+        * Calculate the actual number of PEBs currently needed to be reserved
+        * for future bad eraseblock handling.
+        */
+       ubi->beb_rsvd_level = ubi->bad_peb_limit - ubi->bad_peb_count;
+       if (ubi->beb_rsvd_level < 0) {
+               ubi->beb_rsvd_level = 0;
+               ubi_warn("number of bad PEBs (%d) is above the expected limit "
+                        "(%d), not reserving any PEBs for bad PEB handling, "
+                        "will use available PEBs (if any)",
+                        ubi->bad_peb_count, ubi->bad_peb_limit);
+       }
 }
 
 /**
index 84f66e3fa05d7d39ef265a657ec296fd1be1448c..c94612e67c47e2400ecdf736d2799e17527dce4a 100644 (file)
@@ -59,9 +59,6 @@
 #define ubi_err(fmt, ...) printk(KERN_ERR "UBI error: %s: " fmt "\n", \
                                 __func__, ##__VA_ARGS__)
 
-/* Lowest number PEBs reserved for bad PEB handling */
-#define MIN_RESEVED_PEBS 2
-
 /* Background thread name pattern */
 #define UBI_BGT_NAME_PATTERN "ubi_bgt%dd"
 
@@ -363,6 +360,7 @@ struct ubi_wl_entry;
  * @flash_size: underlying MTD device size (in bytes)
  * @peb_count: count of physical eraseblocks on the MTD device
  * @peb_size: physical eraseblock size
+ * @bad_peb_limit: top limit of expected bad physical eraseblocks
  * @bad_peb_count: count of bad physical eraseblocks
  * @good_peb_count: count of good physical eraseblocks
  * @corr_peb_count: count of corrupted physical eraseblocks (preserved and not
@@ -410,6 +408,7 @@ struct ubi_device {
        int avail_pebs;
        int beb_rsvd_pebs;
        int beb_rsvd_level;
+       int bad_peb_limit;
 
        int autoresize_vol_id;
        int vtbl_slots;
index b6be644e7b85f5194c9f0e1303ffa4d2a51e9cf6..bd05276252fb0e0c7b44367707b09d7903087667 100644 (file)
@@ -978,9 +978,10 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
                        int cancel)
 {
        struct ubi_wl_entry *e = wl_wrk->e;
-       int pnum = e->pnum, err, need;
+       int pnum = e->pnum;
        int vol_id = wl_wrk->vol_id;
        int lnum = wl_wrk->lnum;
+       int err, available_consumed = 0;
 
        if (cancel) {
                dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec);
@@ -1045,20 +1046,14 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
        }
 
        spin_lock(&ubi->volumes_lock);
-       need = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs + 1;
-       if (need > 0) {
-               need = ubi->avail_pebs >= need ? need : ubi->avail_pebs;
-               ubi->avail_pebs -= need;
-               ubi->rsvd_pebs += need;
-               ubi->beb_rsvd_pebs += need;
-               if (need > 0)
-                       ubi_msg("reserve more %d PEBs", need);
-       }
-
        if (ubi->beb_rsvd_pebs == 0) {
-               spin_unlock(&ubi->volumes_lock);
-               ubi_err("no reserved physical eraseblocks");
-               goto out_ro;
+               if (ubi->avail_pebs == 0) {
+                       spin_unlock(&ubi->volumes_lock);
+                       ubi_err("no reserved/available physical eraseblocks");
+                       goto out_ro;
+               }
+               ubi->avail_pebs -= 1;
+               available_consumed = 1;
        }
        spin_unlock(&ubi->volumes_lock);
 
@@ -1068,19 +1063,36 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
                goto out_ro;
 
        spin_lock(&ubi->volumes_lock);
-       ubi->beb_rsvd_pebs -= 1;
+       if (ubi->beb_rsvd_pebs > 0) {
+               if (available_consumed) {
+                       /*
+                        * The amount of reserved PEBs increased since we last
+                        * checked.
+                        */
+                       ubi->avail_pebs += 1;
+                       available_consumed = 0;
+               }
+               ubi->beb_rsvd_pebs -= 1;
+       }
        ubi->bad_peb_count += 1;
        ubi->good_peb_count -= 1;
        ubi_calculate_reserved(ubi);
-       if (ubi->beb_rsvd_pebs)
+       if (available_consumed)
+               ubi_warn("no PEBs in the reserved pool, used an available PEB");
+       else if (ubi->beb_rsvd_pebs)
                ubi_msg("%d PEBs left in the reserve", ubi->beb_rsvd_pebs);
        else
-               ubi_warn("last PEB from the reserved pool was used");
+               ubi_warn("last PEB from the reserve was used");
        spin_unlock(&ubi->volumes_lock);
 
        return err;
 
 out_ro:
+       if (available_consumed) {
+               spin_lock(&ubi->volumes_lock);
+               ubi->avail_pebs += 1;
+               spin_unlock(&ubi->volumes_lock);
+       }
        ubi_ro_mode(ubi);
        return err;
 }
index 545c09ed9079baead2abff5ad9b309a5a0856cac..cff6f023c03a2c78e9869375f93b00c3201af802 100644 (file)
@@ -996,9 +996,7 @@ static int __init cops_module_init(void)
                printk(KERN_WARNING "%s: You shouldn't autoprobe with insmod\n",
                        cardname);
        cops_dev = cops_probe(-1);
-       if (IS_ERR(cops_dev))
-               return PTR_ERR(cops_dev);
-        return 0;
+       return PTR_RET(cops_dev);
 }
 
 static void __exit cops_module_exit(void)
index 0910dce3996d08a64c5c158056e0430c472962f1..b5782cdf0bcae1b5500b31477c26a54194f67f41 100644 (file)
@@ -1243,9 +1243,7 @@ static int __init ltpc_module_init(void)
                       "ltpc: Autoprobing is not recommended for modules\n");
 
        dev_ltpc = ltpc_probe();
-       if (IS_ERR(dev_ltpc))
-               return PTR_ERR(dev_ltpc);
-       return 0;
+       return PTR_RET(dev_ltpc);
 }
 module_init(ltpc_module_init);
 #endif
index 6fae5f3ec7f6d646e4efc79aac1a0449ca5bde21..a86174c9fed1c815b29a5f1c96814adefe0df5e4 100644 (file)
@@ -398,7 +398,7 @@ int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb,
                     sizeof(qdisc_skb_cb(skb)->slave_dev_queue_mapping));
        skb->queue_mapping = qdisc_skb_cb(skb)->slave_dev_queue_mapping;
 
-       if (unlikely(netpoll_tx_running(slave_dev)))
+       if (unlikely(netpoll_tx_running(bond->dev)))
                bond_netpoll_send_skb(bond_get_slave_by_dev(bond, slave_dev), skb);
        else
                dev_queue_xmit(skb);
@@ -1120,10 +1120,10 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
                        write_unlock_bh(&bond->curr_slave_lock);
                        read_unlock(&bond->lock);
 
-                       netdev_bonding_change(bond->dev, NETDEV_BONDING_FAILOVER);
+                       call_netdevice_notifiers(NETDEV_BONDING_FAILOVER, bond->dev);
                        if (should_notify_peers)
-                               netdev_bonding_change(bond->dev,
-                                                     NETDEV_NOTIFY_PEERS);
+                               call_netdevice_notifiers(NETDEV_NOTIFY_PEERS,
+                                                        bond->dev);
 
                        read_lock(&bond->lock);
                        write_lock_bh(&bond->curr_slave_lock);
@@ -1235,12 +1235,12 @@ static inline int slave_enable_netpoll(struct slave *slave)
        struct netpoll *np;
        int err = 0;
 
-       np = kzalloc(sizeof(*np), GFP_KERNEL);
+       np = kzalloc(sizeof(*np), GFP_ATOMIC);
        err = -ENOMEM;
        if (!np)
                goto out;
 
-       err = __netpoll_setup(np, slave->dev);
+       err = __netpoll_setup(np, slave->dev, GFP_ATOMIC);
        if (err) {
                kfree(np);
                goto out;
@@ -1257,9 +1257,7 @@ static inline void slave_disable_netpoll(struct slave *slave)
                return;
 
        slave->np = NULL;
-       synchronize_rcu_bh();
-       __netpoll_cleanup(np);
-       kfree(np);
+       __netpoll_free_rcu(np);
 }
 static inline bool slave_dev_support_netpoll(struct net_device *slave_dev)
 {
@@ -1292,7 +1290,7 @@ static void bond_netpoll_cleanup(struct net_device *bond_dev)
        read_unlock(&bond->lock);
 }
 
-static int bond_netpoll_setup(struct net_device *dev, struct netpoll_info *ni)
+static int bond_netpoll_setup(struct net_device *dev, struct netpoll_info *ni, gfp_t gfp)
 {
        struct bonding *bond = netdev_priv(dev);
        struct slave *slave;
@@ -1560,8 +1558,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                                 bond_dev->name,
                                 bond_dev->type, slave_dev->type);
 
-                       res = netdev_bonding_change(bond_dev,
-                                                   NETDEV_PRE_TYPE_CHANGE);
+                       res = call_netdevice_notifiers(NETDEV_PRE_TYPE_CHANGE,
+                                                      bond_dev);
                        res = notifier_to_errno(res);
                        if (res) {
                                pr_err("%s: refused to change device type\n",
@@ -1581,8 +1579,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                                bond_dev->priv_flags &= ~IFF_TX_SKB_SHARING;
                        }
 
-                       netdev_bonding_change(bond_dev,
-                                             NETDEV_POST_TYPE_CHANGE);
+                       call_netdevice_notifiers(NETDEV_POST_TYPE_CHANGE,
+                                                bond_dev);
                }
        } else if (bond_dev->type != slave_dev->type) {
                pr_err("%s ether type (%d) is different from other slaves (%d), can not enslave it.\n",
@@ -1943,7 +1941,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
        }
 
        block_netpoll_tx();
-       netdev_bonding_change(bond_dev, NETDEV_RELEASE);
+       call_netdevice_notifiers(NETDEV_RELEASE, bond_dev);
        write_lock_bh(&bond->lock);
 
        slave = bond_get_slave_by_dev(bond, slave_dev);
@@ -2586,7 +2584,7 @@ re_arm:
                        read_unlock(&bond->lock);
                        return;
                }
-               netdev_bonding_change(bond->dev, NETDEV_NOTIFY_PEERS);
+               call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, bond->dev);
                rtnl_unlock();
        }
 }
@@ -3205,7 +3203,7 @@ re_arm:
                        read_unlock(&bond->lock);
                        return;
                }
-               netdev_bonding_change(bond->dev, NETDEV_NOTIFY_PEERS);
+               call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, bond->dev);
                rtnl_unlock();
        }
 }
index 06adf881ea24b39fef1401b40db6b5a5a88410d3..8a8df82988d13d238e2b7b8448e6b691bc82300a 100644 (file)
@@ -380,12 +380,12 @@ static int mpc5xxx_can_resume(struct platform_device *ofdev)
 }
 #endif
 
-static struct mpc5xxx_can_data __devinitdata mpc5200_can_data = {
+static const struct mpc5xxx_can_data __devinitdata mpc5200_can_data = {
        .type = MSCAN_TYPE_MPC5200,
        .get_clock = mpc52xx_can_get_clock,
 };
 
-static struct mpc5xxx_can_data __devinitdata mpc5121_can_data = {
+static const struct mpc5xxx_can_data __devinitdata mpc5121_can_data = {
        .type = MSCAN_TYPE_MPC5121,
        .get_clock = mpc512x_can_get_clock,
 };
index f0c8bd54ce2930d87a5c6479fef7e9f39e4ca37d..021d69c5d9bc951797ede8e72dde15bad706613b 100644 (file)
@@ -1712,7 +1712,7 @@ e100_set_network_leds(int active)
 static void
 e100_netpoll(struct net_device* netdev)
 {
-       e100rxtx_interrupt(NETWORK_DMA_TX_IRQ_NBR, netdev, NULL);
+       e100rxtx_interrupt(NETWORK_DMA_TX_IRQ_NBR, netdev);
 }
 #endif
 
index 77bcd4cb4ffb945a8c696cc3f6bab1e363733c48..463b9ec57d8077c8a1599457974ab15dc1210536 100644 (file)
@@ -1278,7 +1278,7 @@ struct bnx2x {
 #define BNX2X_FW_RX_ALIGN_START        (1UL << BNX2X_RX_ALIGN_SHIFT)
 
 #define BNX2X_FW_RX_ALIGN_END                                  \
-       max(1UL << BNX2X_RX_ALIGN_SHIFT,                        \
+       max_t(u64, 1UL << BNX2X_RX_ALIGN_SHIFT,                 \
            SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
 
 #define BNX2X_PXP_DRAM_ALIGN           (BNX2X_RX_ALIGN_SHIFT - 5)
index dd451c3dd83d1d614a13070e85ffc9a3e8c458e8..02b5a343b19506a2edc60be5dd6b41d781aadb85 100644 (file)
@@ -4041,20 +4041,6 @@ static bool bnx2x_get_load_status(struct bnx2x *bp, int engine)
        return val != 0;
 }
 
-/*
- * Reset the load status for the current engine.
- */
-static void bnx2x_clear_load_status(struct bnx2x *bp)
-{
-       u32 val;
-       u32 mask = (BP_PATH(bp) ? BNX2X_PATH1_LOAD_CNT_MASK :
-                   BNX2X_PATH0_LOAD_CNT_MASK);
-       bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_RECOVERY_REG);
-       val = REG_RD(bp, BNX2X_RECOVERY_GLOB_REG);
-       REG_WR(bp, BNX2X_RECOVERY_GLOB_REG, val & (~mask));
-       bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_RECOVERY_REG);
-}
-
 static void _print_next_block(int idx, const char *blk)
 {
        pr_cont("%s%s", idx ? ", " : "", blk);
@@ -9384,32 +9370,24 @@ static int __devinit bnx2x_prev_mark_path(struct bnx2x *bp)
        return rc;
 }
 
-static bool __devinit bnx2x_can_flr(struct bnx2x *bp)
-{
-       int pos;
-       u32 cap;
-       struct pci_dev *dev = bp->pdev;
-
-       pos = pci_pcie_cap(dev);
-       if (!pos)
-               return false;
-
-       pci_read_config_dword(dev, pos + PCI_EXP_DEVCAP, &cap);
-       if (!(cap & PCI_EXP_DEVCAP_FLR))
-               return false;
-
-       return true;
-}
-
 static int __devinit bnx2x_do_flr(struct bnx2x *bp)
 {
        int i, pos;
        u16 status;
        struct pci_dev *dev = bp->pdev;
 
-       /* probe the capability first */
-       if (bnx2x_can_flr(bp))
-               return -ENOTTY;
+
+       if (CHIP_IS_E1x(bp)) {
+               BNX2X_DEV_INFO("FLR not supported in E1/E1H\n");
+               return -EINVAL;
+       }
+
+       /* only bootcode REQ_BC_VER_4_INITIATE_FLR and onwards support flr */
+       if (bp->common.bc_ver < REQ_BC_VER_4_INITIATE_FLR) {
+               BNX2X_ERR("FLR not supported by BC_VER: 0x%x\n",
+                         bp->common.bc_ver);
+               return -EINVAL;
+       }
 
        pos = pci_pcie_cap(dev);
        if (!pos)
@@ -9429,12 +9407,8 @@ static int __devinit bnx2x_do_flr(struct bnx2x *bp)
                "transaction is not cleared; proceeding with reset anyway\n");
 
 clear:
-       if (bp->common.bc_ver < REQ_BC_VER_4_INITIATE_FLR) {
-               BNX2X_ERR("FLR not supported by BC_VER: 0x%x\n",
-                         bp->common.bc_ver);
-               return -EINVAL;
-       }
 
+       BNX2X_DEV_INFO("Initiating FLR\n");
        bnx2x_fw_command(bp, DRV_MSG_CODE_INITIATE_FLR, 0);
 
        return 0;
@@ -9454,8 +9428,21 @@ static int __devinit bnx2x_prev_unload_uncommon(struct bnx2x *bp)
         * the one required, then FLR will be sufficient to clean any residue
         * left by previous driver
         */
-       if (bnx2x_test_firmware_version(bp, false) && bnx2x_can_flr(bp))
-               return bnx2x_do_flr(bp);
+       rc = bnx2x_test_firmware_version(bp, false);
+
+       if (!rc) {
+               /* fw version is good */
+               BNX2X_DEV_INFO("FW version matches our own. Attempting FLR\n");
+               rc = bnx2x_do_flr(bp);
+       }
+
+       if (!rc) {
+               /* FLR was performed */
+               BNX2X_DEV_INFO("FLR successful\n");
+               return 0;
+       }
+
+       BNX2X_DEV_INFO("Could not FLR\n");
 
        /* Close the MCP request, return failure*/
        rc = bnx2x_prev_mcp_done(bp);
@@ -11427,9 +11414,6 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
        if (!chip_is_e1x)
                REG_WR(bp, PGLUE_B_REG_INTERNAL_PFID_ENABLE_TARGET_READ, 1);
 
-       /* Reset the load counter */
-       bnx2x_clear_load_status(bp);
-
        dev->watchdog_timeo = TX_TIMEOUT;
 
        dev->netdev_ops = &bnx2x_netdev_ops;
index 734fd87cd99093e0d30899006cb12cacd10a027c..62f754bd0dfe65704a1af826a754a720dc8cfd43 100644 (file)
@@ -2485,6 +2485,7 @@ static int bnx2x_mcast_enqueue_cmd(struct bnx2x *bp,
                break;
 
        default:
+               kfree(new_cmd);
                BNX2X_ERR("Unknown command: %d\n", cmd);
                return -EINVAL;
        }
index c60de89b66696759a453ff4d69650c1905209c58..90a903d83d8747ca26d711b7b3a188f81a554611 100644 (file)
@@ -1948,7 +1948,7 @@ static int be_rx_cqs_create(struct be_adapter *adapter)
 
        if (adapter->num_rx_qs != MAX_RX_QS)
                dev_info(&adapter->pdev->dev,
-                       "Created only %d receive queues", adapter->num_rx_qs);
+                       "Created only %d receive queues\n", adapter->num_rx_qs);
 
        return 0;
 }
index 0f2d1a710909e5044b3c2c402bf2aba0b950ff88..151453309401694360f311ccb09e0caea8480b01 100644 (file)
@@ -174,8 +174,10 @@ static int __devinit fs_enet_mdio_probe(struct platform_device *ofdev)
 
        new_bus->phy_mask = ~0;
        new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
-       if (!new_bus->irq)
+       if (!new_bus->irq) {
+               ret = -ENOMEM;
                goto out_unmap_regs;
+       }
 
        new_bus->parent = &ofdev->dev;
        dev_set_drvdata(&ofdev->dev, new_bus);
index 55bb867258e6aa1d2baa1dbf4da546c705a2e83f..cdf702a594858146fd4f04ab02966d941edeeea5 100644 (file)
@@ -137,8 +137,10 @@ static int __devinit fs_enet_mdio_probe(struct platform_device *ofdev)
        snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", res.start);
 
        fec->fecp = ioremap(res.start, resource_size(&res));
-       if (!fec->fecp)
+       if (!fec->fecp) {
+               ret = -ENOMEM;
                goto out_fec;
+       }
 
        if (get_bus_freq) {
                clock = get_bus_freq(ofdev->dev.of_node);
@@ -172,8 +174,10 @@ static int __devinit fs_enet_mdio_probe(struct platform_device *ofdev)
 
        new_bus->phy_mask = ~0;
        new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
-       if (!new_bus->irq)
+       if (!new_bus->irq) {
+               ret = -ENOMEM;
                goto out_unmap_regs;
+       }
 
        new_bus->parent = &ofdev->dev;
        dev_set_drvdata(&ofdev->dev, new_bus);
index 0b3bade957fd8424f59f16ff6e5e27a7c0b6058e..080c89093feb5df6393c6d8f58421ff254f2b05d 100644 (file)
@@ -999,7 +999,7 @@ static s32 e1000_set_d0_lplu_state_82571(struct e1000_hw *hw, bool active)
  **/
 static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
 {
-       u32 ctrl, ctrl_ext, eecd;
+       u32 ctrl, ctrl_ext, eecd, tctl;
        s32 ret_val;
 
        /*
@@ -1014,7 +1014,9 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
        ew32(IMC, 0xffffffff);
 
        ew32(RCTL, 0);
-       ew32(TCTL, E1000_TCTL_PSP);
+       tctl = er32(TCTL);
+       tctl &= ~E1000_TCTL_EN;
+       ew32(TCTL, tctl);
        e1e_flush();
 
        usleep_range(10000, 20000);
@@ -1601,10 +1603,8 @@ static s32 e1000_check_for_serdes_link_82571(struct e1000_hw *hw)
                         * auto-negotiation in the TXCW register and disable
                         * forced link in the Device Control register in an
                         * attempt to auto-negotiate with our link partner.
-                        * If the partner code word is null, stop forcing
-                        * and restart auto negotiation.
                         */
-                       if ((rxcw & E1000_RXCW_C) || !(rxcw & E1000_RXCW_CW))  {
+                       if (rxcw & E1000_RXCW_C) {
                                /* Enable autoneg, and unforce link up */
                                ew32(TXCW, mac->txcw);
                                ew32(CTRL, (ctrl & ~E1000_CTRL_SLU));
index 95b245310f1761fa4f9b06de319cea48fdc28c92..46c3b1f9ff8997af685836bb82fb0e1bd5e599cf 100644 (file)
@@ -178,6 +178,24 @@ static void e1000_regdump(struct e1000_hw *hw, struct e1000_reg_info *reginfo)
        pr_info("%-15s %08x %08x\n", rname, regs[0], regs[1]);
 }
 
+static void e1000e_dump_ps_pages(struct e1000_adapter *adapter,
+                                struct e1000_buffer *bi)
+{
+       int i;
+       struct e1000_ps_page *ps_page;
+
+       for (i = 0; i < adapter->rx_ps_pages; i++) {
+               ps_page = &bi->ps_pages[i];
+
+               if (ps_page->page) {
+                       pr_info("packet dump for ps_page %d:\n", i);
+                       print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS,
+                                      16, 1, page_address(ps_page->page),
+                                      PAGE_SIZE, true);
+               }
+       }
+}
+
 /*
  * e1000e_dump - Print registers, Tx-ring and Rx-ring
  */
@@ -299,10 +317,10 @@ static void e1000e_dump(struct e1000_adapter *adapter)
                        (unsigned long long)buffer_info->time_stamp,
                        buffer_info->skb, next_desc);
 
-               if (netif_msg_pktdata(adapter) && buffer_info->dma != 0)
+               if (netif_msg_pktdata(adapter) && buffer_info->skb)
                        print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS,
-                                      16, 1, phys_to_virt(buffer_info->dma),
-                                      buffer_info->length, true);
+                                      16, 1, buffer_info->skb->data,
+                                      buffer_info->skb->len, true);
        }
 
        /* Print Rx Ring Summary */
@@ -381,10 +399,8 @@ rx_ring_summary:
                                        buffer_info->skb, next_desc);
 
                                if (netif_msg_pktdata(adapter))
-                                       print_hex_dump(KERN_INFO, "",
-                                               DUMP_PREFIX_ADDRESS, 16, 1,
-                                               phys_to_virt(buffer_info->dma),
-                                               adapter->rx_ps_bsize0, true);
+                                       e1000e_dump_ps_pages(adapter,
+                                                            buffer_info);
                        }
                }
                break;
@@ -444,12 +460,12 @@ rx_ring_summary:
                                        (unsigned long long)buffer_info->dma,
                                        buffer_info->skb, next_desc);
 
-                               if (netif_msg_pktdata(adapter))
+                               if (netif_msg_pktdata(adapter) &&
+                                   buffer_info->skb)
                                        print_hex_dump(KERN_INFO, "",
                                                       DUMP_PREFIX_ADDRESS, 16,
                                                       1,
-                                                      phys_to_virt
-                                                      (buffer_info->dma),
+                                                      buffer_info->skb->data,
                                                       adapter->rx_buffer_len,
                                                       true);
                        }
index 5e84eaac48c191727d9ac733c80ffbb13ce1473f..ba994fb4cec69bc60baaff7c9407faf9553d40be 100644 (file)
@@ -254,6 +254,14 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
         */
        size += NVM_WORD_SIZE_BASE_SHIFT;
 
+       /*
+        * Check for invalid size
+        */
+       if ((hw->mac.type == e1000_82576) && (size > 15)) {
+               pr_notice("The NVM size is not valid, defaulting to 32K\n");
+               size = 15;
+       }
+
        nvm->word_size = 1 << size;
        if (hw->mac.type < e1000_i210) {
                nvm->opcode_bits        = 8;
@@ -281,14 +289,6 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
        } else
                nvm->type = e1000_nvm_flash_hw;
 
-       /*
-        * Check for invalid size
-        */
-       if ((hw->mac.type == e1000_82576) && (size > 15)) {
-               pr_notice("The NVM size is not valid, defaulting to 32K\n");
-               size = 15;
-       }
-
        /* NVM Function Pointers */
        switch (hw->mac.type) {
        case e1000_82580:
index 10efcd88dca00c81ef2539914851d25536447c78..28394bea5253fc280e1aba973b20958ed1b9662f 100644 (file)
                                    : (0x0E018 + ((_n) * 0x40)))
 #define E1000_TXDCTL(_n)  ((_n) < 4 ? (0x03828 + ((_n) * 0x100)) \
                                    : (0x0E028 + ((_n) * 0x40)))
-#define E1000_DCA_TXCTRL(_n) (0x03814 + (_n << 8))
-#define E1000_DCA_RXCTRL(_n) (0x02814 + (_n << 8))
+#define E1000_RXCTL(_n)          ((_n) < 4 ? (0x02814 + ((_n) * 0x100)) : \
+                                     (0x0C014 + ((_n) * 0x40)))
+#define E1000_DCA_RXCTRL(_n)   E1000_RXCTL(_n)
+#define E1000_TXCTL(_n)   ((_n) < 4 ? (0x03814 + ((_n) * 0x100)) : \
+                                     (0x0E014 + ((_n) * 0x40)))
+#define E1000_DCA_TXCTRL(_n) E1000_TXCTL(_n)
 #define E1000_TDWBAL(_n)  ((_n) < 4 ? (0x03838 + ((_n) * 0x100)) \
                                    : (0x0E038 + ((_n) * 0x40)))
 #define E1000_TDWBAH(_n)  ((_n) < 4 ? (0x0383C + ((_n) * 0x100)) \
index a19c84cad0e991fc429b846b913f704e9cc41f30..70591117051bf2faa446af5a3b81055f091d491d 100644 (file)
@@ -209,8 +209,8 @@ static int igb_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
        /* When SoL/IDER sessions are active, autoneg/speed/duplex
         * cannot be changed */
        if (igb_check_reset_block(hw)) {
-               dev_err(&adapter->pdev->dev, "Cannot change link "
-                       "characteristics when SoL/IDER is active.\n");
+               dev_err(&adapter->pdev->dev,
+                       "Cannot change link characteristics when SoL/IDER is active.\n");
                return -EINVAL;
        }
 
@@ -1089,8 +1089,8 @@ static bool reg_pattern_test(struct igb_adapter *adapter, u64 *data,
                wr32(reg, (_test[pat] & write));
                val = rd32(reg) & mask;
                if (val != (_test[pat] & write & mask)) {
-                       dev_err(&adapter->pdev->dev, "pattern test reg %04X "
-                               "failed: got 0x%08X expected 0x%08X\n",
+                       dev_err(&adapter->pdev->dev,
+                               "pattern test reg %04X failed: got 0x%08X expected 0x%08X\n",
                                reg, val, (_test[pat] & write & mask));
                        *data = reg;
                        return 1;
@@ -1108,8 +1108,8 @@ static bool reg_set_and_check(struct igb_adapter *adapter, u64 *data,
        wr32(reg, write & mask);
        val = rd32(reg);
        if ((write & mask) != (val & mask)) {
-               dev_err(&adapter->pdev->dev, "set/check reg %04X test failed:"
-                       " got 0x%08X expected 0x%08X\n", reg,
+               dev_err(&adapter->pdev->dev,
+                       "set/check reg %04X test failed: got 0x%08X expected 0x%08X\n", reg,
                        (val & mask), (write & mask));
                *data = reg;
                return 1;
@@ -1171,8 +1171,9 @@ static int igb_reg_test(struct igb_adapter *adapter, u64 *data)
        wr32(E1000_STATUS, toggle);
        after = rd32(E1000_STATUS) & toggle;
        if (value != after) {
-               dev_err(&adapter->pdev->dev, "failed STATUS register test "
-                       "got: 0x%08X expected: 0x%08X\n", after, value);
+               dev_err(&adapter->pdev->dev,
+                       "failed STATUS register test got: 0x%08X expected: 0x%08X\n",
+                       after, value);
                *data = 1;
                return 1;
        }
@@ -1497,6 +1498,9 @@ static int igb_integrated_phy_loopback(struct igb_adapter *adapter)
                break;
        }
 
+       /* add small delay to avoid loopback test failure */
+       msleep(50);
+
        /* force 1000, set loopback */
        igb_write_phy_reg(hw, PHY_CONTROL, 0x4140);
 
@@ -1777,16 +1781,14 @@ static int igb_loopback_test(struct igb_adapter *adapter, u64 *data)
         * sessions are active */
        if (igb_check_reset_block(&adapter->hw)) {
                dev_err(&adapter->pdev->dev,
-                       "Cannot do PHY loopback test "
-                       "when SoL/IDER is active.\n");
+                       "Cannot do PHY loopback test when SoL/IDER is active.\n");
                *data = 0;
                goto out;
        }
        if ((adapter->hw.mac.type == e1000_i210)
-               || (adapter->hw.mac.type == e1000_i210)) {
+               || (adapter->hw.mac.type == e1000_i211)) {
                dev_err(&adapter->pdev->dev,
-                       "Loopback test not supported "
-                       "on this part at this time.\n");
+                       "Loopback test not supported on this part at this time.\n");
                *data = 0;
                goto out;
        }
index b7c2d5050572828c8d07e228b2e44235e9f01801..48cc4fb1a307f0d7c2821cc9f57c4c67d0ffc31b 100644 (file)
@@ -462,10 +462,10 @@ static void igb_dump(struct igb_adapter *adapter)
                                (u64)buffer_info->time_stamp,
                                buffer_info->skb, next_desc);
 
-                       if (netif_msg_pktdata(adapter) && buffer_info->dma != 0)
+                       if (netif_msg_pktdata(adapter) && buffer_info->skb)
                                print_hex_dump(KERN_INFO, "",
                                        DUMP_PREFIX_ADDRESS,
-                                       16, 1, phys_to_virt(buffer_info->dma),
+                                       16, 1, buffer_info->skb->data,
                                        buffer_info->length, true);
                }
        }
@@ -547,18 +547,17 @@ rx_ring_summary:
                                        (u64)buffer_info->dma,
                                        buffer_info->skb, next_desc);
 
-                               if (netif_msg_pktdata(adapter)) {
+                               if (netif_msg_pktdata(adapter) &&
+                                   buffer_info->dma && buffer_info->skb) {
                                        print_hex_dump(KERN_INFO, "",
-                                               DUMP_PREFIX_ADDRESS,
-                                               16, 1,
-                                               phys_to_virt(buffer_info->dma),
-                                               IGB_RX_HDR_LEN, true);
+                                                 DUMP_PREFIX_ADDRESS,
+                                                 16, 1, buffer_info->skb->data,
+                                                 IGB_RX_HDR_LEN, true);
                                        print_hex_dump(KERN_INFO, "",
                                          DUMP_PREFIX_ADDRESS,
                                          16, 1,
-                                         phys_to_virt(
-                                           buffer_info->page_dma +
-                                           buffer_info->page_offset),
+                                         page_address(buffer_info->page) +
+                                                     buffer_info->page_offset,
                                          PAGE_SIZE/2, true);
                                }
                        }
index 50fc137501da087d9cb73c1c924a0e9f85562c79..18bf08c9d7a4428e3a82f9f29a5837fddc3f6860 100644 (file)
@@ -804,12 +804,13 @@ static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw,
            link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR_SGMII) {
                /* Set KX4/KX/KR support according to speed requested */
                autoc &= ~(IXGBE_AUTOC_KX4_KX_SUPP_MASK | IXGBE_AUTOC_KR_SUPP);
-               if (speed & IXGBE_LINK_SPEED_10GB_FULL)
+               if (speed & IXGBE_LINK_SPEED_10GB_FULL) {
                        if (orig_autoc & IXGBE_AUTOC_KX4_SUPP)
                                autoc |= IXGBE_AUTOC_KX4_SUPP;
                        if ((orig_autoc & IXGBE_AUTOC_KR_SUPP) &&
                            (hw->phy.smart_speed_active == false))
                                autoc |= IXGBE_AUTOC_KR_SUPP;
+               }
                if (speed & IXGBE_LINK_SPEED_1GB_FULL)
                        autoc |= IXGBE_AUTOC_KX_SUPP;
        } else if ((pma_pmd_1g == IXGBE_AUTOC_1G_SFI) &&
index f32e703007702ba0652bca4bce23f7ac44287c14..5aba5ecdf1e28157fadf44072c87a4a98511d249 100644 (file)
@@ -614,8 +614,8 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
                /* If source MAC is equal to our own MAC and not performing
                 * the selftest or flb disabled - drop the packet */
                if (s_mac == priv->mac &&
-                       (!(dev->features & NETIF_F_LOOPBACK) ||
-                        !priv->validate_loopback))
+                   !((dev->features & NETIF_F_LOOPBACK) ||
+                     priv->validate_loopback))
                        goto next;
 
                /*
index 019d856b1334fc4e7b389eb00d16da872d63ee4a..10bba09c44ea508d047123aeafb5e001b6bbd1be 100644 (file)
@@ -164,7 +164,6 @@ int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv,
        ring->cons = 0xffffffff;
        ring->last_nr_txbb = 1;
        ring->poll_cnt = 0;
-       ring->blocked = 0;
        memset(ring->tx_info, 0, ring->size * sizeof(struct mlx4_en_tx_info));
        memset(ring->buf, 0, ring->buf_size);
 
@@ -365,14 +364,13 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq)
        ring->cons += txbbs_skipped;
        netdev_tx_completed_queue(ring->tx_queue, packets, bytes);
 
-       /* Wakeup Tx queue if this ring stopped it */
-       if (unlikely(ring->blocked)) {
-               if ((u32) (ring->prod - ring->cons) <=
-                    ring->size - HEADROOM - MAX_DESC_TXBBS) {
-                       ring->blocked = 0;
-                       netif_tx_wake_queue(ring->tx_queue);
-                       priv->port_stats.wake_queue++;
-               }
+       /*
+        * Wakeup Tx queue if this stopped, and at least 1 packet
+        * was completed
+        */
+       if (netif_tx_queue_stopped(ring->tx_queue) && txbbs_skipped > 0) {
+               netif_tx_wake_queue(ring->tx_queue);
+               priv->port_stats.wake_queue++;
        }
 }
 
@@ -592,7 +590,6 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
                     ring->size - HEADROOM - MAX_DESC_TXBBS)) {
                /* every full Tx ring stops queue */
                netif_tx_stop_queue(ring->tx_queue);
-               ring->blocked = 1;
                priv->port_stats.queue_stopped++;
 
                return NETDEV_TX_BUSY;
index 88b7b3e75ab197706b3a1f0c7fa953e1f5f9da0b..daf41792366147c7381e9f8f7f1017489c55a57e 100644 (file)
@@ -358,13 +358,14 @@ void mlx4_table_put_range(struct mlx4_dev *dev, struct mlx4_icm_table *table,
 }
 
 int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table,
-                       u64 virt, int obj_size, int nobj, int reserved,
+                       u64 virt, int obj_size, u32 nobj, int reserved,
                        int use_lowmem, int use_coherent)
 {
        int obj_per_chunk;
        int num_icm;
        unsigned chunk_size;
        int i;
+       u64 size;
 
        obj_per_chunk = MLX4_TABLE_CHUNK_SIZE / obj_size;
        num_icm = (nobj + obj_per_chunk - 1) / obj_per_chunk;
@@ -380,10 +381,12 @@ int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table,
        table->coherent = use_coherent;
        mutex_init(&table->mutex);
 
+       size = (u64) nobj * obj_size;
        for (i = 0; i * MLX4_TABLE_CHUNK_SIZE < reserved * obj_size; ++i) {
                chunk_size = MLX4_TABLE_CHUNK_SIZE;
-               if ((i + 1) * MLX4_TABLE_CHUNK_SIZE > nobj * obj_size)
-                       chunk_size = PAGE_ALIGN(nobj * obj_size - i * MLX4_TABLE_CHUNK_SIZE);
+               if ((i + 1) * MLX4_TABLE_CHUNK_SIZE > size)
+                       chunk_size = PAGE_ALIGN(size -
+                                       i * MLX4_TABLE_CHUNK_SIZE);
 
                table->icm[i] = mlx4_alloc_icm(dev, chunk_size >> PAGE_SHIFT,
                                               (use_lowmem ? GFP_KERNEL : GFP_HIGHUSER) |
index 19e4efc0b3429adb982b69c5366321385c8d3e05..a67744f53506af7f86c0de581445e1e67568de7f 100644 (file)
@@ -78,7 +78,7 @@ int mlx4_table_get_range(struct mlx4_dev *dev, struct mlx4_icm_table *table,
 void mlx4_table_put_range(struct mlx4_dev *dev, struct mlx4_icm_table *table,
                          int start, int end);
 int mlx4_init_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table,
-                       u64 virt, int obj_size, int nobj, int reserved,
+                       u64 virt, int obj_size, u32 nobj, int reserved,
                        int use_lowmem, int use_coherent);
 void mlx4_cleanup_icm_table(struct mlx4_dev *dev, struct mlx4_icm_table *table);
 void *mlx4_table_find(struct mlx4_icm_table *table, int obj, dma_addr_t *dma_handle);
index 48d0e90194cb19d2a322990425b478f9e178b623..827b72dfce99690093f0fe81ee3ccf804d59db85 100644 (file)
@@ -157,9 +157,6 @@ int mlx4_check_port_params(struct mlx4_dev *dev,
                                         "on this HCA, aborting.\n");
                                return -EINVAL;
                        }
-                       if (port_type[i] == MLX4_PORT_TYPE_ETH &&
-                           port_type[i + 1] == MLX4_PORT_TYPE_IB)
-                               return -EINVAL;
                }
        }
 
index 4ec3835e1bc2cb8dd88958ce7a1276150898e86f..a018ea2a43deb9c67e773032e62d8a83f54bb3d9 100644 (file)
@@ -432,8 +432,10 @@ static int add_promisc_qp(struct mlx4_dev *dev, u8 port,
                        if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qpn) {
                                /* Entry already exists, add to duplicates */
                                dqp = kmalloc(sizeof *dqp, GFP_KERNEL);
-                               if (!dqp)
+                               if (!dqp) {
+                                       err = -ENOMEM;
                                        goto out_mailbox;
+                               }
                                dqp->qpn = qpn;
                                list_add_tail(&dqp->list, &entry->duplicates);
                                found = true;
index 59ebc0339638a3c760f8b540d2066a7aaa7fa9cb..4d9df8f2a12617047355fc9988d5187af80a95f5 100644 (file)
@@ -249,7 +249,7 @@ struct mlx4_bitmap {
 struct mlx4_buddy {
        unsigned long         **bits;
        unsigned int           *num_free;
-       int                     max_order;
+       u32                     max_order;
        spinlock_t              lock;
 };
 
@@ -258,7 +258,7 @@ struct mlx4_icm;
 struct mlx4_icm_table {
        u64                     virt;
        int                     num_icm;
-       int                     num_obj;
+       u32                     num_obj;
        int                     obj_size;
        int                     lowmem;
        int                     coherent;
index 5f1ab105debc28b4b8ba7bdaca3f0bcb2f1cdb66..9d27e42264e2b64aea3827d760c409ab3de0c301 100644 (file)
@@ -248,7 +248,6 @@ struct mlx4_en_tx_ring {
        u32 doorbell_qpn;
        void *buf;
        u16 poll_cnt;
-       int blocked;
        struct mlx4_en_tx_info *tx_info;
        u8 *bounce_buf;
        u32 last_nr_txbb;
index af55b7ce53413cc27273b9102e609c0ae97d6169..c202d3ad2a0efbb6a852b18874414ba1036a1129 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/kernel.h>
+#include <linux/vmalloc.h>
 
 #include <linux/mlx4/cmd.h>
 
@@ -120,7 +121,7 @@ static int mlx4_buddy_init(struct mlx4_buddy *buddy, int max_order)
        buddy->max_order = max_order;
        spin_lock_init(&buddy->lock);
 
-       buddy->bits = kzalloc((buddy->max_order + 1) * sizeof (long *),
+       buddy->bits = kcalloc(buddy->max_order + 1, sizeof (long *),
                              GFP_KERNEL);
        buddy->num_free = kcalloc((buddy->max_order + 1), sizeof *buddy->num_free,
                                  GFP_KERNEL);
@@ -129,10 +130,12 @@ static int mlx4_buddy_init(struct mlx4_buddy *buddy, int max_order)
 
        for (i = 0; i <= buddy->max_order; ++i) {
                s = BITS_TO_LONGS(1 << (buddy->max_order - i));
-               buddy->bits[i] = kmalloc(s * sizeof (long), GFP_KERNEL);
-               if (!buddy->bits[i])
-                       goto err_out_free;
-               bitmap_zero(buddy->bits[i], 1 << (buddy->max_order - i));
+               buddy->bits[i] = kcalloc(s, sizeof (long), GFP_KERNEL | __GFP_NOWARN);
+               if (!buddy->bits[i]) {
+                       buddy->bits[i] = vzalloc(s * sizeof(long));
+                       if (!buddy->bits[i])
+                               goto err_out_free;
+               }
        }
 
        set_bit(0, buddy->bits[buddy->max_order]);
@@ -142,7 +145,10 @@ static int mlx4_buddy_init(struct mlx4_buddy *buddy, int max_order)
 
 err_out_free:
        for (i = 0; i <= buddy->max_order; ++i)
-               kfree(buddy->bits[i]);
+               if (buddy->bits[i] && is_vmalloc_addr(buddy->bits[i]))
+                       vfree(buddy->bits[i]);
+               else
+                       kfree(buddy->bits[i]);
 
 err_out:
        kfree(buddy->bits);
@@ -156,7 +162,10 @@ static void mlx4_buddy_cleanup(struct mlx4_buddy *buddy)
        int i;
 
        for (i = 0; i <= buddy->max_order; ++i)
-               kfree(buddy->bits[i]);
+               if (is_vmalloc_addr(buddy->bits[i]))
+                       vfree(buddy->bits[i]);
+               else
+                       kfree(buddy->bits[i]);
 
        kfree(buddy->bits);
        kfree(buddy->num_free);
@@ -668,7 +677,7 @@ int mlx4_init_mr_table(struct mlx4_dev *dev)
                return err;
 
        err = mlx4_buddy_init(&mr_table->mtt_buddy,
-                             ilog2(dev->caps.num_mtts /
+                             ilog2((u32)dev->caps.num_mtts /
                              (1 << log_mtts_per_seg)));
        if (err)
                goto err_buddy;
@@ -678,7 +687,7 @@ int mlx4_init_mr_table(struct mlx4_dev *dev)
                        mlx4_alloc_mtt_range(dev,
                                             fls(dev->caps.reserved_mtts - 1));
                if (priv->reserved_mtts < 0) {
-                       mlx4_warn(dev, "MTT table of order %d is too small.\n",
+                       mlx4_warn(dev, "MTT table of order %u is too small.\n",
                                  mr_table->mtt_buddy.max_order);
                        err = -ENOMEM;
                        goto err_reserve_mtts;
index 9ee4725363d5d25d88135d2bbffb4d67a67023ab..8e0c3cc2a1ec786739de7298fc450c483d8fe37a 100644 (file)
@@ -76,7 +76,7 @@ u64 mlx4_make_profile(struct mlx4_dev *dev,
                u64 size;
                u64 start;
                int type;
-               int num;
+               u32 num;
                int log_num;
        };
 
@@ -105,7 +105,7 @@ u64 mlx4_make_profile(struct mlx4_dev *dev,
        si_meminfo(&si);
        request->num_mtt =
                roundup_pow_of_two(max_t(unsigned, request->num_mtt,
-                                        min(1UL << 31,
+                                        min(1UL << (31 - log_mtts_per_seg),
                                             si.totalram >> (log_mtts_per_seg - 1))));
 
        profile[MLX4_RES_QP].size     = dev_cap->qpc_entry_sz;
index 802498293528307b5c2e123eae089f84929759ea..34ee09bae36e98dcb28c8ff9b4c8d12a2da97292 100644 (file)
@@ -80,20 +80,6 @@ void mlx4_do_sense_ports(struct mlx4_dev *dev,
                        stype[i - 1] = defaults[i - 1];
        }
 
-       /*
-        * Adjust port configuration:
-        * If port 1 sensed nothing and port 2 is IB, set both as IB
-        * If port 2 sensed nothing and port 1 is Eth, set both as Eth
-        */
-       if (stype[0] == MLX4_PORT_TYPE_ETH) {
-               for (i = 1; i < dev->caps.num_ports; i++)
-                       stype[i] = stype[i] ? stype[i] : MLX4_PORT_TYPE_ETH;
-       }
-       if (stype[dev->caps.num_ports - 1] == MLX4_PORT_TYPE_IB) {
-               for (i = 0; i < dev->caps.num_ports - 1; i++)
-                       stype[i] = stype[i] ? stype[i] : MLX4_PORT_TYPE_IB;
-       }
-
        /*
         * If sensed nothing, remain in current configuration.
         */
index 4069edab229e9a53cfc3bdec5256cf4cdbc573ae..53743f7a2ca9604d6f264de3a2e3c727556a0619 100644 (file)
@@ -346,28 +346,15 @@ static phy_interface_t lpc_phy_interface_mode(struct device *dev)
                                                   "phy-mode", NULL);
                if (mode && !strcmp(mode, "mii"))
                        return PHY_INTERFACE_MODE_MII;
-               return PHY_INTERFACE_MODE_RMII;
        }
-
-       /* non-DT */
-#ifdef CONFIG_ARCH_LPC32XX_MII_SUPPORT
-       return PHY_INTERFACE_MODE_MII;
-#else
        return PHY_INTERFACE_MODE_RMII;
-#endif
 }
 
 static bool use_iram_for_net(struct device *dev)
 {
        if (dev && dev->of_node)
                return of_property_read_bool(dev->of_node, "use-iram");
-
-       /* non-DT */
-#ifdef CONFIG_ARCH_LPC32XX_IRAM_FOR_NET
-       return true;
-#else
        return false;
-#endif
 }
 
 /* Receive Status information word */
index 70554a1b2b02dd37440db75ba06ec9eed8c84fe9..65a8d49106a4c63c6a7faf04c8e3334421ce6472 100644 (file)
@@ -1503,6 +1503,11 @@ static int efx_probe_all(struct efx_nic *efx)
                goto fail2;
        }
 
+       BUILD_BUG_ON(EFX_DEFAULT_DMAQ_SIZE < EFX_RXQ_MIN_ENT);
+       if (WARN_ON(EFX_DEFAULT_DMAQ_SIZE < EFX_TXQ_MIN_ENT(efx))) {
+               rc = -EINVAL;
+               goto fail3;
+       }
        efx->rxq_entries = efx->txq_entries = EFX_DEFAULT_DMAQ_SIZE;
 
        rc = efx_probe_filters(efx);
@@ -2070,6 +2075,7 @@ static int efx_register_netdev(struct efx_nic *efx)
        net_dev->irq = efx->pci_dev->irq;
        net_dev->netdev_ops = &efx_netdev_ops;
        SET_ETHTOOL_OPS(net_dev, &efx_ethtool_ops);
+       net_dev->gso_max_segs = EFX_TSO_MAX_SEGS;
 
        rtnl_lock();
 
index be8f9158a7149388b5e4edfeb41ee2c848319a28..70755c97251aaab4e9cafe969b0a8b95821a1cbb 100644 (file)
@@ -30,6 +30,7 @@ extern netdev_tx_t
 efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb);
 extern void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index);
 extern int efx_setup_tc(struct net_device *net_dev, u8 num_tc);
+extern unsigned int efx_tx_max_skb_descs(struct efx_nic *efx);
 
 /* RX */
 extern int efx_probe_rx_queue(struct efx_rx_queue *rx_queue);
@@ -52,10 +53,15 @@ extern void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue);
 #define EFX_MAX_EVQ_SIZE 16384UL
 #define EFX_MIN_EVQ_SIZE 512UL
 
-/* The smallest [rt]xq_entries that the driver supports. Callers of
- * efx_wake_queue() assume that they can subsequently send at least one
- * skb. Falcon/A1 may require up to three descriptors per skb_frag. */
-#define EFX_MIN_RING_SIZE (roundup_pow_of_two(2 * 3 * MAX_SKB_FRAGS))
+/* Maximum number of TCP segments we support for soft-TSO */
+#define EFX_TSO_MAX_SEGS       100
+
+/* The smallest [rt]xq_entries that the driver supports.  RX minimum
+ * is a bit arbitrary.  For TX, we must have space for at least 2
+ * TSO skbs.
+ */
+#define EFX_RXQ_MIN_ENT                128U
+#define EFX_TXQ_MIN_ENT(efx)   (2 * efx_tx_max_skb_descs(efx))
 
 /* Filters */
 extern int efx_probe_filters(struct efx_nic *efx);
index 10536f93b5611d15a22a56b3ca280e0f107ea828..8cba2df82b18b9f2dfa1ff82eee3b22ef9eeb0c9 100644 (file)
@@ -680,21 +680,27 @@ static int efx_ethtool_set_ringparam(struct net_device *net_dev,
                                     struct ethtool_ringparam *ring)
 {
        struct efx_nic *efx = netdev_priv(net_dev);
+       u32 txq_entries;
 
        if (ring->rx_mini_pending || ring->rx_jumbo_pending ||
            ring->rx_pending > EFX_MAX_DMAQ_SIZE ||
            ring->tx_pending > EFX_MAX_DMAQ_SIZE)
                return -EINVAL;
 
-       if (ring->rx_pending < EFX_MIN_RING_SIZE ||
-           ring->tx_pending < EFX_MIN_RING_SIZE) {
+       if (ring->rx_pending < EFX_RXQ_MIN_ENT) {
                netif_err(efx, drv, efx->net_dev,
-                         "TX and RX queues cannot be smaller than %ld\n",
-                         EFX_MIN_RING_SIZE);
+                         "RX queues cannot be smaller than %u\n",
+                         EFX_RXQ_MIN_ENT);
                return -EINVAL;
        }
 
-       return efx_realloc_channels(efx, ring->rx_pending, ring->tx_pending);
+       txq_entries = max(ring->tx_pending, EFX_TXQ_MIN_ENT(efx));
+       if (txq_entries != ring->tx_pending)
+               netif_warn(efx, drv, efx->net_dev,
+                          "increasing TX queue size to minimum of %u\n",
+                          txq_entries);
+
+       return efx_realloc_channels(efx, ring->rx_pending, txq_entries);
 }
 
 static int efx_ethtool_set_pauseparam(struct net_device *net_dev,
index 9b225a7769f765a1f1bf3ef024ae3b73a18a66c2..18713436b44345a110ed263d54c5411d1e93c6fa 100644 (file)
@@ -119,6 +119,25 @@ efx_max_tx_len(struct efx_nic *efx, dma_addr_t dma_addr)
        return len;
 }
 
+unsigned int efx_tx_max_skb_descs(struct efx_nic *efx)
+{
+       /* Header and payload descriptor for each output segment, plus
+        * one for every input fragment boundary within a segment
+        */
+       unsigned int max_descs = EFX_TSO_MAX_SEGS * 2 + MAX_SKB_FRAGS;
+
+       /* Possibly one more per segment for the alignment workaround */
+       if (EFX_WORKAROUND_5391(efx))
+               max_descs += EFX_TSO_MAX_SEGS;
+
+       /* Possibly more for PCIe page boundaries within input fragments */
+       if (PAGE_SIZE > EFX_PAGE_SIZE)
+               max_descs += max_t(unsigned int, MAX_SKB_FRAGS,
+                                  DIV_ROUND_UP(GSO_MAX_SIZE, EFX_PAGE_SIZE));
+
+       return max_descs;
+}
+
 /*
  * Add a socket buffer to a TX queue
  *
index b5ba3084c7fc056db06cc07f1e19b1aae1f71c7a..3e5519a0acc7ebcccb897ed3719b8506a3b585ba 100644 (file)
@@ -1147,15 +1147,17 @@ static void __devinit ioc3_8250_register(struct ioc3_uartregs __iomem *uart)
 {
 #define COSMISC_CONSTANT 6
 
-       struct uart_port port = {
-               .irq            = 0,
-               .flags          = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
-               .iotype         = UPIO_MEM,
-               .regshift       = 0,
-               .uartclk        = (22000000 << 1) / COSMISC_CONSTANT,
-
-               .membase        = (unsigned char __iomem *) uart,
-               .mapbase        = (unsigned long) uart,
+       struct uart_8250_port port = {
+               .port = {
+                       .irq            = 0,
+                       .flags          = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF,
+                       .iotype         = UPIO_MEM,
+                       .regshift       = 0,
+                       .uartclk        = (22000000 << 1) / COSMISC_CONSTANT,
+
+                       .membase        = (unsigned char __iomem *) uart,
+                       .mapbase        = (unsigned long) uart,
+                }
        };
        unsigned char lcr;
 
@@ -1164,7 +1166,7 @@ static void __devinit ioc3_8250_register(struct ioc3_uartregs __iomem *uart)
        uart->iu_scr = COSMISC_CONSTANT,
        uart->iu_lcr = lcr;
        uart->iu_lcr;
-       serial8250_register_port(&port);
+       serial8250_register_8250_port(&port);
 }
 
 static void __devinit ioc3_serial_probe(struct pci_dev *pdev, struct ioc3 *ioc3)
index cd01ee7ecef19339c90765747a57b2d621765806..b93245c11995bc15329321e6879be78d4c1b44dc 100644 (file)
@@ -74,7 +74,7 @@ static int __devinit stmmac_probe_config_dt(struct platform_device *pdev,
  * the necessary resources and invokes the main to init
  * the net device, register the mdio bus etc.
  */
-static int stmmac_pltfr_probe(struct platform_device *pdev)
+static int __devinit stmmac_pltfr_probe(struct platform_device *pdev)
 {
        int ret = 0;
        struct resource *res;
index 1b173a6145d642fb3c2fe26c58c8d8b995ce50b8..b26cbda5efa9b5264dd4e2bb885d35ea7e26b692 100644 (file)
@@ -32,7 +32,7 @@ config TI_DAVINCI_EMAC
 
 config TI_DAVINCI_MDIO
        tristate "TI DaVinci MDIO Support"
-       depends on ARM && ( ARCH_DAVINCI || ARCH_OMAP3 )
+       depends on ARM && ( ARCH_DAVINCI || ARCH_OMAP3 || SOC_AM33XX )
        select PHYLIB
        ---help---
          This driver supports TI's DaVinci MDIO module.
@@ -42,7 +42,7 @@ config TI_DAVINCI_MDIO
 
 config TI_DAVINCI_CPDMA
        tristate "TI DaVinci CPDMA Support"
-       depends on ARM && ( ARCH_DAVINCI || ARCH_OMAP3 )
+       depends on ARM && ( ARCH_DAVINCI || ARCH_OMAP3 || SOC_AM33XX )
        ---help---
          This driver supports TI's DaVinci CPDMA dma engine.
 
index 1e5d85b06e71b1dea196be8e0f4db1a928c62c4b..0cbc0e59252c52ebdc00daeec1ca7e97cd539492 100644 (file)
@@ -28,6 +28,9 @@
 #include <linux/workqueue.h>
 #include <linux/delay.h>
 #include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_net.h>
+#include <linux/of_device.h>
 
 #include <linux/platform_data/cpsw.h>
 
@@ -709,6 +712,158 @@ static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv)
        slave->sliver   = regs + data->sliver_reg_ofs;
 }
 
+static int cpsw_probe_dt(struct cpsw_platform_data *data,
+                        struct platform_device *pdev)
+{
+       struct device_node *node = pdev->dev.of_node;
+       struct device_node *slave_node;
+       int i = 0, ret;
+       u32 prop;
+
+       if (!node)
+               return -EINVAL;
+
+       if (of_property_read_u32(node, "slaves", &prop)) {
+               pr_err("Missing slaves property in the DT.\n");
+               return -EINVAL;
+       }
+       data->slaves = prop;
+
+       data->slave_data = kzalloc(sizeof(struct cpsw_slave_data) *
+                                  data->slaves, GFP_KERNEL);
+       if (!data->slave_data) {
+               pr_err("Could not allocate slave memory.\n");
+               return -EINVAL;
+       }
+
+       data->no_bd_ram = of_property_read_bool(node, "no_bd_ram");
+
+       if (of_property_read_u32(node, "cpdma_channels", &prop)) {
+               pr_err("Missing cpdma_channels property in the DT.\n");
+               ret = -EINVAL;
+               goto error_ret;
+       }
+       data->channels = prop;
+
+       if (of_property_read_u32(node, "host_port_no", &prop)) {
+               pr_err("Missing host_port_no property in the DT.\n");
+               ret = -EINVAL;
+               goto error_ret;
+       }
+       data->host_port_num = prop;
+
+       if (of_property_read_u32(node, "cpdma_reg_ofs", &prop)) {
+               pr_err("Missing cpdma_reg_ofs property in the DT.\n");
+               ret = -EINVAL;
+               goto error_ret;
+       }
+       data->cpdma_reg_ofs = prop;
+
+       if (of_property_read_u32(node, "cpdma_sram_ofs", &prop)) {
+               pr_err("Missing cpdma_sram_ofs property in the DT.\n");
+               ret = -EINVAL;
+               goto error_ret;
+       }
+       data->cpdma_sram_ofs = prop;
+
+       if (of_property_read_u32(node, "ale_reg_ofs", &prop)) {
+               pr_err("Missing ale_reg_ofs property in the DT.\n");
+               ret = -EINVAL;
+               goto error_ret;
+       }
+       data->ale_reg_ofs = prop;
+
+       if (of_property_read_u32(node, "ale_entries", &prop)) {
+               pr_err("Missing ale_entries property in the DT.\n");
+               ret = -EINVAL;
+               goto error_ret;
+       }
+       data->ale_entries = prop;
+
+       if (of_property_read_u32(node, "host_port_reg_ofs", &prop)) {
+               pr_err("Missing host_port_reg_ofs property in the DT.\n");
+               ret = -EINVAL;
+               goto error_ret;
+       }
+       data->host_port_reg_ofs = prop;
+
+       if (of_property_read_u32(node, "hw_stats_reg_ofs", &prop)) {
+               pr_err("Missing hw_stats_reg_ofs property in the DT.\n");
+               ret = -EINVAL;
+               goto error_ret;
+       }
+       data->hw_stats_reg_ofs = prop;
+
+       if (of_property_read_u32(node, "bd_ram_ofs", &prop)) {
+               pr_err("Missing bd_ram_ofs property in the DT.\n");
+               ret = -EINVAL;
+               goto error_ret;
+       }
+       data->bd_ram_ofs = prop;
+
+       if (of_property_read_u32(node, "bd_ram_size", &prop)) {
+               pr_err("Missing bd_ram_size property in the DT.\n");
+               ret = -EINVAL;
+               goto error_ret;
+       }
+       data->bd_ram_size = prop;
+
+       if (of_property_read_u32(node, "rx_descs", &prop)) {
+               pr_err("Missing rx_descs property in the DT.\n");
+               ret = -EINVAL;
+               goto error_ret;
+       }
+       data->rx_descs = prop;
+
+       if (of_property_read_u32(node, "mac_control", &prop)) {
+               pr_err("Missing mac_control property in the DT.\n");
+               ret = -EINVAL;
+               goto error_ret;
+       }
+       data->mac_control = prop;
+
+       for_each_child_of_node(node, slave_node) {
+               struct cpsw_slave_data *slave_data = data->slave_data + i;
+               const char *phy_id = NULL;
+               const void *mac_addr = NULL;
+
+               if (of_property_read_string(slave_node, "phy_id", &phy_id)) {
+                       pr_err("Missing slave[%d] phy_id property\n", i);
+                       ret = -EINVAL;
+                       goto error_ret;
+               }
+               slave_data->phy_id = phy_id;
+
+               if (of_property_read_u32(slave_node, "slave_reg_ofs", &prop)) {
+                       pr_err("Missing slave[%d] slave_reg_ofs property\n", i);
+                       ret = -EINVAL;
+                       goto error_ret;
+               }
+               slave_data->slave_reg_ofs = prop;
+
+               if (of_property_read_u32(slave_node, "sliver_reg_ofs",
+                                        &prop)) {
+                       pr_err("Missing slave[%d] sliver_reg_ofs property\n",
+                               i);
+                       ret = -EINVAL;
+                       goto error_ret;
+               }
+               slave_data->sliver_reg_ofs = prop;
+
+               mac_addr = of_get_mac_address(slave_node);
+               if (mac_addr)
+                       memcpy(slave_data->mac_addr, mac_addr, ETH_ALEN);
+
+               i++;
+       }
+
+       return 0;
+
+error_ret:
+       kfree(data->slave_data);
+       return ret;
+}
+
 static int __devinit cpsw_probe(struct platform_device *pdev)
 {
        struct cpsw_platform_data       *data = pdev->dev.platform_data;
@@ -720,11 +875,6 @@ static int __devinit cpsw_probe(struct platform_device *pdev)
        struct resource                 *res;
        int ret = 0, i, k = 0;
 
-       if (!data) {
-               pr_err("platform data missing\n");
-               return -ENODEV;
-       }
-
        ndev = alloc_etherdev(sizeof(struct cpsw_priv));
        if (!ndev) {
                pr_err("error allocating net_device\n");
@@ -734,13 +884,19 @@ static int __devinit cpsw_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, ndev);
        priv = netdev_priv(ndev);
        spin_lock_init(&priv->lock);
-       priv->data = *data;
        priv->pdev = pdev;
        priv->ndev = ndev;
        priv->dev  = &ndev->dev;
        priv->msg_enable = netif_msg_init(debug_level, CPSW_DEBUG);
        priv->rx_packet_max = max(rx_packet_max, 128);
 
+       if (cpsw_probe_dt(&priv->data, pdev)) {
+               pr_err("cpsw: platform data missing\n");
+               ret = -ENODEV;
+               goto clean_ndev_ret;
+       }
+       data = &priv->data;
+
        if (is_valid_ether_addr(data->slave_data[0].mac_addr)) {
                memcpy(priv->mac_addr, data->slave_data[0].mac_addr, ETH_ALEN);
                pr_info("Detected MACID = %pM", priv->mac_addr);
@@ -996,11 +1152,17 @@ static const struct dev_pm_ops cpsw_pm_ops = {
        .resume         = cpsw_resume,
 };
 
+static const struct of_device_id cpsw_of_mtable[] = {
+       { .compatible = "ti,cpsw", },
+       { /* sentinel */ },
+};
+
 static struct platform_driver cpsw_driver = {
        .driver = {
                .name    = "cpsw",
                .owner   = THIS_MODULE,
                .pm      = &cpsw_pm_ops,
+               .of_match_table = of_match_ptr(cpsw_of_mtable),
        },
        .probe = cpsw_probe,
        .remove = __devexit_p(cpsw_remove),
index 3b5c4571b55e3c922a4b6e5a94a0a4a8adcb2fce..d15c888e9df8a15b02d104ace349c1926ad81107 100644 (file)
@@ -538,11 +538,12 @@ EXPORT_SYMBOL_GPL(cpdma_chan_create);
 
 int cpdma_chan_destroy(struct cpdma_chan *chan)
 {
-       struct cpdma_ctlr *ctlr = chan->ctlr;
+       struct cpdma_ctlr *ctlr;
        unsigned long flags;
 
        if (!chan)
                return -EINVAL;
+       ctlr = chan->ctlr;
 
        spin_lock_irqsave(&ctlr->lock, flags);
        if (chan->state != CPDMA_STATE_IDLE)
index cd7ee204e94a10abaa88b3288dcd2cace5ceca3e..573f3be5f42173d80b5ccca91fc06301127713b5 100644 (file)
@@ -36,6 +36,8 @@
 #include <linux/io.h>
 #include <linux/pm_runtime.h>
 #include <linux/davinci_emac.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 /*
  * This timeout definition is a worst-case ultra defensive measure against
@@ -289,6 +291,25 @@ static int davinci_mdio_write(struct mii_bus *bus, int phy_id,
        return 0;
 }
 
+static int davinci_mdio_probe_dt(struct mdio_platform_data *data,
+                        struct platform_device *pdev)
+{
+       struct device_node *node = pdev->dev.of_node;
+       u32 prop;
+
+       if (!node)
+               return -EINVAL;
+
+       if (of_property_read_u32(node, "bus_freq", &prop)) {
+               pr_err("Missing bus_freq property in the DT.\n");
+               return -EINVAL;
+       }
+       data->bus_freq = prop;
+
+       return 0;
+}
+
+
 static int __devinit davinci_mdio_probe(struct platform_device *pdev)
 {
        struct mdio_platform_data *pdata = pdev->dev.platform_data;
@@ -304,8 +325,6 @@ static int __devinit davinci_mdio_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
-       data->pdata = pdata ? (*pdata) : default_pdata;
-
        data->bus = mdiobus_alloc();
        if (!data->bus) {
                dev_err(dev, "failed to alloc mii bus\n");
@@ -313,14 +332,22 @@ static int __devinit davinci_mdio_probe(struct platform_device *pdev)
                goto bail_out;
        }
 
+       if (dev->of_node) {
+               if (davinci_mdio_probe_dt(&data->pdata, pdev))
+                       data->pdata = default_pdata;
+               snprintf(data->bus->id, MII_BUS_ID_SIZE, "%s", pdev->name);
+       } else {
+               data->pdata = pdata ? (*pdata) : default_pdata;
+               snprintf(data->bus->id, MII_BUS_ID_SIZE, "%s-%x",
+                        pdev->name, pdev->id);
+       }
+
        data->bus->name         = dev_name(dev);
        data->bus->read         = davinci_mdio_read,
        data->bus->write        = davinci_mdio_write,
        data->bus->reset        = davinci_mdio_reset,
        data->bus->parent       = dev;
        data->bus->priv         = data;
-       snprintf(data->bus->id, MII_BUS_ID_SIZE, "%s-%x",
-               pdev->name, pdev->id);
 
        pm_runtime_enable(&pdev->dev);
        pm_runtime_get_sync(&pdev->dev);
@@ -454,11 +481,17 @@ static const struct dev_pm_ops davinci_mdio_pm_ops = {
        .resume         = davinci_mdio_resume,
 };
 
+static const struct of_device_id davinci_mdio_of_mtable[] = {
+       { .compatible = "ti,davinci_mdio", },
+       { /* sentinel */ },
+};
+
 static struct platform_driver davinci_mdio_driver = {
        .driver = {
                .name    = "davinci_mdio",
                .owner   = THIS_MODULE,
                .pm      = &davinci_mdio_pm_ops,
+               .of_match_table = of_match_ptr(davinci_mdio_of_mtable),
        },
        .probe = davinci_mdio_probe,
        .remove = __devexit_p(davinci_mdio_remove),
index 482648fcf0b6327bb9c482c1c36880ece1627caa..98934bdf6acffc053fcd317721e8d92cf649ba14 100644 (file)
@@ -1003,6 +1003,7 @@ static int ixp4xx_nway_reset(struct net_device *dev)
 }
 
 int ixp46x_phc_index = -1;
+EXPORT_SYMBOL_GPL(ixp46x_phc_index);
 
 static int ixp4xx_get_ts_info(struct net_device *dev,
                              struct ethtool_ts_info *info)
index 6cee2917eb0276369e6933ebf933c386167fa9a4..4a1a5f58fa73ffd7899429bcaf28062e29f83dc3 100644 (file)
@@ -383,13 +383,6 @@ int netvsc_device_remove(struct hv_device *device)
        unsigned long flags;
 
        net_device = hv_get_drvdata(device);
-       spin_lock_irqsave(&device->channel->inbound_lock, flags);
-       net_device->destroy = true;
-       spin_unlock_irqrestore(&device->channel->inbound_lock, flags);
-
-       /* Wait for all send completions */
-       wait_event(net_device->wait_drain,
-                  atomic_read(&net_device->num_outstanding_sends) == 0);
 
        netvsc_disconnect_vsp(net_device);
 
index 8c5a1c43c81d257c09a67385e01da93f3c24465f..e91111a656f715b77398e1208208f4b0ab5644a8 100644 (file)
@@ -400,7 +400,7 @@ static void netvsc_send_garp(struct work_struct *w)
        ndev_ctx = container_of(w, struct net_device_context, dwork.work);
        net_device = hv_get_drvdata(ndev_ctx->device_ctx);
        net = net_device->ndev;
-       netif_notify_peers(net);
+       netdev_notify_peers(net);
 }
 
 
index e5d6146937fa0aade2476662ce87084b7337187c..06f8601f32fcb8eb82ce6429e08438f451e05e7d 100644 (file)
@@ -46,8 +46,14 @@ struct rndis_request {
        /* Simplify allocation by having a netvsc packet inline */
        struct hv_netvsc_packet pkt;
        struct hv_page_buffer buf;
-       /* FIXME: We assumed a fixed size request here. */
+
        struct rndis_message request_msg;
+       /*
+        * The buffer for the extended info after the RNDIS message. It's
+        * referenced based on the data offset in the RNDIS message. Its size
+        * is enough for current needs, and should be sufficient for the near
+        * future.
+        */
        u8 ext[100];
 };
 
@@ -718,6 +724,9 @@ static void rndis_filter_halt_device(struct rndis_device *dev)
 {
        struct rndis_request *request;
        struct rndis_halt_request *halt;
+       struct netvsc_device *nvdev = dev->net_dev;
+       struct hv_device *hdev = nvdev->dev;
+       ulong flags;
 
        /* Attempt to do a rndis device halt */
        request = get_rndis_request(dev, RNDIS_MSG_HALT,
@@ -735,6 +744,14 @@ static void rndis_filter_halt_device(struct rndis_device *dev)
        dev->state = RNDIS_DEV_UNINITIALIZED;
 
 cleanup:
+       spin_lock_irqsave(&hdev->channel->inbound_lock, flags);
+       nvdev->destroy = true;
+       spin_unlock_irqrestore(&hdev->channel->inbound_lock, flags);
+
+       /* Wait for all send completions */
+       wait_event(nvdev->wait_drain,
+               atomic_read(&nvdev->num_outstanding_sends) == 0);
+
        if (request)
                put_rndis_request(dev, request);
        return;
index a561ae44a9ac1c982b1d5390a6f288abe0094523..c6a0299aa9f912241e6b544727df47913b01db1d 100644 (file)
@@ -158,7 +158,7 @@ static int bfin_sir_set_speed(struct bfin_sir_port *port, int speed)
        /* If not add the 'RPOLC', we can't catch the receive interrupt.
         * It's related with the HW layout and the IR transiver.
         */
-       val |= IREN | RPOLC;
+       val |= UMOD_IRDA | RPOLC;
        UART_PUT_GCTL(port, val);
        return ret;
 }
@@ -432,7 +432,7 @@ static void bfin_sir_shutdown(struct bfin_sir_port *port, struct net_device *dev
        bfin_sir_stop_rx(port);
 
        val = UART_GET_GCTL(port);
-       val &= ~(UCEN | IREN | RPOLC);
+       val &= ~(UCEN | UMOD_MASK | RPOLC);
        UART_PUT_GCTL(port, val);
 
 #ifdef CONFIG_SIR_BFIN_DMA
@@ -518,10 +518,10 @@ static void bfin_sir_send_work(struct work_struct *work)
         * reset all the UART.
         */
        val = UART_GET_GCTL(port);
-       val &= ~(IREN | RPOLC);
+       val &= ~(UMOD_MASK | RPOLC);
        UART_PUT_GCTL(port, val);
        SSYNC();
-       val |= IREN | RPOLC;
+       val |= UMOD_IRDA | RPOLC;
        UART_PUT_GCTL(port, val);
        SSYNC();
        /* bfin_sir_set_speed(port, self->speed); */
index 3352b2443e58eb1ca0a45856c628850c08092be6..30087ca23a0fc7e6c33c75fcb80f020aae42186c 100644 (file)
@@ -124,8 +124,8 @@ static int irtty_change_speed(struct sir_dev *dev, unsigned speed)
        tty = priv->tty;
 
        mutex_lock(&tty->termios_mutex);
-       old_termios = *(tty->termios);
-       cflag = tty->termios->c_cflag;
+       old_termios = tty->termios;
+       cflag = tty->termios.c_cflag;
        tty_encode_baud_rate(tty, speed, speed);
        if (tty->ops->set_termios)
                tty->ops->set_termios(tty, &old_termios);
@@ -281,15 +281,15 @@ static inline void irtty_stop_receiver(struct tty_struct *tty, int stop)
        int cflag;
 
        mutex_lock(&tty->termios_mutex);
-       old_termios = *(tty->termios);
-       cflag = tty->termios->c_cflag;
+       old_termios = tty->termios;
+       cflag = tty->termios.c_cflag;
        
        if (stop)
                cflag &= ~CREAD;
        else
                cflag |= CREAD;
 
-       tty->termios->c_cflag = cflag;
+       tty->termios.c_cflag = cflag;
        if (tty->ops->set_termios)
                tty->ops->set_termios(tty, &old_termios);
        mutex_unlock(&tty->termios_mutex);
index e2a06fd996d51409ed711fb360105d7f423f27a8..4a075babe1937b9d9b4cc98b18360b181acfdb56 100644 (file)
@@ -197,6 +197,7 @@ static __net_init int loopback_net_init(struct net *net)
        if (err)
                goto out_free_netdev;
 
+       BUG_ON(dev->ifindex != LOOPBACK_IFINDEX);
        net->loopback_dev = dev;
        return 0;
 
index 0737bd4d16696e4a90475a124f17568f87eb2c14..0f0f9ce3a7769ec552cc9f01f1915b44e44958fe 100644 (file)
@@ -94,7 +94,8 @@ static int get_slot(struct macvlan_dev *vlan, struct macvtap_queue *q)
        int i;
 
        for (i = 0; i < MAX_MACVTAP_QUEUES; i++) {
-               if (rcu_dereference(vlan->taps[i]) == q)
+               if (rcu_dereference_protected(vlan->taps[i],
+                                             lockdep_is_held(&macvtap_lock)) == q)
                        return i;
        }
 
index f9347ea3d381e113d20c6a13ec32f0f51c5fc04c..f0ad56c13933e1e8de4aec326d21295f832c94cc 100644 (file)
@@ -640,12 +640,7 @@ static int netconsole_netdev_event(struct notifier_block *this,
                                 * rtnl_lock already held
                                 */
                                if (nt->np.dev) {
-                                       spin_unlock_irqrestore(
-                                                             &target_list_lock,
-                                                             flags);
                                        __netpoll_cleanup(&nt->np);
-                                       spin_lock_irqsave(&target_list_lock,
-                                                         flags);
                                        dev_put(nt->np.dev);
                                        nt->np.dev = NULL;
                                        netconsole_target_put(nt);
index e0cc4ef33dee2b035ee576ecbb17196984925d74..eefe49e8713ca633c8383b1c388826f45e5c9e0c 100644 (file)
@@ -101,7 +101,6 @@ err:
                n--;
                gpio_free(s->gpio[n]);
        }
-       devm_kfree(&pdev->dev, s);
        return r;
 }
 
index 5c0557222f20b26a10fa450146098b699ff4e98e..eb3f5cefeba3c6ddcbd53a44cb63a759d9b803ef 100644 (file)
@@ -93,6 +93,18 @@ struct ppp_file {
 #define PF_TO_PPP(pf)          PF_TO_X(pf, struct ppp)
 #define PF_TO_CHANNEL(pf)      PF_TO_X(pf, struct channel)
 
+/*
+ * Data structure to hold primary network stats for which
+ * we want to use 64 bit storage.  Other network stats
+ * are stored in dev->stats of the ppp strucute.
+ */
+struct ppp_link_stats {
+       u64 rx_packets;
+       u64 tx_packets;
+       u64 rx_bytes;
+       u64 tx_bytes;
+};
+
 /*
  * Data structure describing one ppp unit.
  * A ppp unit corresponds to a ppp network interface device
@@ -136,6 +148,7 @@ struct ppp {
        unsigned pass_len, active_len;
 #endif /* CONFIG_PPP_FILTER */
        struct net      *ppp_net;       /* the net we belong to */
+       struct ppp_link_stats stats64;  /* 64 bit network stats */
 };
 
 /*
@@ -1021,9 +1034,34 @@ ppp_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        return err;
 }
 
+struct rtnl_link_stats64*
+ppp_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats64)
+{
+       struct ppp *ppp = netdev_priv(dev);
+
+       ppp_recv_lock(ppp);
+       stats64->rx_packets = ppp->stats64.rx_packets;
+       stats64->rx_bytes   = ppp->stats64.rx_bytes;
+       ppp_recv_unlock(ppp);
+
+       ppp_xmit_lock(ppp);
+       stats64->tx_packets = ppp->stats64.tx_packets;
+       stats64->tx_bytes   = ppp->stats64.tx_bytes;
+       ppp_xmit_unlock(ppp);
+
+       stats64->rx_errors        = dev->stats.rx_errors;
+       stats64->tx_errors        = dev->stats.tx_errors;
+       stats64->rx_dropped       = dev->stats.rx_dropped;
+       stats64->tx_dropped       = dev->stats.tx_dropped;
+       stats64->rx_length_errors = dev->stats.rx_length_errors;
+
+       return stats64;
+}
+
 static const struct net_device_ops ppp_netdev_ops = {
-       .ndo_start_xmit = ppp_start_xmit,
-       .ndo_do_ioctl   = ppp_net_ioctl,
+       .ndo_start_xmit  = ppp_start_xmit,
+       .ndo_do_ioctl    = ppp_net_ioctl,
+       .ndo_get_stats64 = ppp_get_stats64,
 };
 
 static void ppp_setup(struct net_device *dev)
@@ -1157,8 +1195,8 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
 #endif /* CONFIG_PPP_FILTER */
        }
 
-       ++ppp->dev->stats.tx_packets;
-       ppp->dev->stats.tx_bytes += skb->len - 2;
+       ++ppp->stats64.tx_packets;
+       ppp->stats64.tx_bytes += skb->len - 2;
 
        switch (proto) {
        case PPP_IP:
@@ -1745,8 +1783,8 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
                break;
        }
 
-       ++ppp->dev->stats.rx_packets;
-       ppp->dev->stats.rx_bytes += skb->len - 2;
+       ++ppp->stats64.rx_packets;
+       ppp->stats64.rx_bytes += skb->len - 2;
 
        npi = proto_to_npindex(proto);
        if (npi < 0) {
@@ -2570,12 +2608,12 @@ ppp_get_stats(struct ppp *ppp, struct ppp_stats *st)
        struct slcompress *vj = ppp->vj;
 
        memset(st, 0, sizeof(*st));
-       st->p.ppp_ipackets = ppp->dev->stats.rx_packets;
+       st->p.ppp_ipackets = ppp->stats64.rx_packets;
        st->p.ppp_ierrors = ppp->dev->stats.rx_errors;
-       st->p.ppp_ibytes = ppp->dev->stats.rx_bytes;
-       st->p.ppp_opackets = ppp->dev->stats.tx_packets;
+       st->p.ppp_ibytes = ppp->stats64.rx_bytes;
+       st->p.ppp_opackets = ppp->stats64.tx_packets;
        st->p.ppp_oerrors = ppp->dev->stats.tx_errors;
-       st->p.ppp_obytes = ppp->dev->stats.tx_bytes;
+       st->p.ppp_obytes = ppp->stats64.tx_bytes;
        if (!vj)
                return;
        st->vj.vjs_packets = vj->sls_o_compressed + vj->sls_o_uncompressed;
index 1c98321b56cc1547eb105b39758d2663e54de3ae..162464fe86bf7634fb9ac6c21ecd76e25beb10b6 100644 (file)
@@ -189,7 +189,7 @@ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
        if (sk_pppox(po)->sk_state & PPPOX_DEAD)
                goto tx_error;
 
-       rt = ip_route_output_ports(&init_net, &fl4, NULL,
+       rt = ip_route_output_ports(sock_net(sk), &fl4, NULL,
                                   opt->dst_addr.sin_addr.s_addr,
                                   opt->src_addr.sin_addr.s_addr,
                                   0, 0, IPPROTO_GRE,
@@ -468,7 +468,7 @@ static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr,
        po->chan.private = sk;
        po->chan.ops = &pptp_chan_ops;
 
-       rt = ip_route_output_ports(&init_net, &fl4, sk,
+       rt = ip_route_output_ports(sock_net(sk), &fl4, sk,
                                   opt->dst_addr.sin_addr.s_addr,
                                   opt->src_addr.sin_addr.s_addr,
                                   0, 0,
index 87707ab3943084821e1b7e5c5b9a201d51a944ba..bbb85240cb8c4fe3feec223f2e8e6c4fe46e15f8 100644 (file)
@@ -658,6 +658,122 @@ static rx_handler_result_t team_handle_frame(struct sk_buff **pskb)
 }
 
 
+/*************************************
+ * Multiqueue Tx port select override
+ *************************************/
+
+static int team_queue_override_init(struct team *team)
+{
+       struct list_head *listarr;
+       unsigned int queue_cnt = team->dev->num_tx_queues - 1;
+       unsigned int i;
+
+       if (!queue_cnt)
+               return 0;
+       listarr = kmalloc(sizeof(struct list_head) * queue_cnt, GFP_KERNEL);
+       if (!listarr)
+               return -ENOMEM;
+       team->qom_lists = listarr;
+       for (i = 0; i < queue_cnt; i++)
+               INIT_LIST_HEAD(listarr++);
+       return 0;
+}
+
+static void team_queue_override_fini(struct team *team)
+{
+       kfree(team->qom_lists);
+}
+
+static struct list_head *__team_get_qom_list(struct team *team, u16 queue_id)
+{
+       return &team->qom_lists[queue_id - 1];
+}
+
+/*
+ * note: already called with rcu_read_lock
+ */
+static bool team_queue_override_transmit(struct team *team, struct sk_buff *skb)
+{
+       struct list_head *qom_list;
+       struct team_port *port;
+
+       if (!team->queue_override_enabled || !skb->queue_mapping)
+               return false;
+       qom_list = __team_get_qom_list(team, skb->queue_mapping);
+       list_for_each_entry_rcu(port, qom_list, qom_list) {
+               if (!team_dev_queue_xmit(team, port, skb))
+                       return true;
+       }
+       return false;
+}
+
+static void __team_queue_override_port_del(struct team *team,
+                                          struct team_port *port)
+{
+       list_del_rcu(&port->qom_list);
+       synchronize_rcu();
+       INIT_LIST_HEAD(&port->qom_list);
+}
+
+static bool team_queue_override_port_has_gt_prio_than(struct team_port *port,
+                                                     struct team_port *cur)
+{
+       if (port->priority < cur->priority)
+               return true;
+       if (port->priority > cur->priority)
+               return false;
+       if (port->index < cur->index)
+               return true;
+       return false;
+}
+
+static void __team_queue_override_port_add(struct team *team,
+                                          struct team_port *port)
+{
+       struct team_port *cur;
+       struct list_head *qom_list;
+       struct list_head *node;
+
+       if (!port->queue_id || !team_port_enabled(port))
+               return;
+
+       qom_list = __team_get_qom_list(team, port->queue_id);
+       node = qom_list;
+       list_for_each_entry(cur, qom_list, qom_list) {
+               if (team_queue_override_port_has_gt_prio_than(port, cur))
+                       break;
+               node = &cur->qom_list;
+       }
+       list_add_tail_rcu(&port->qom_list, node);
+}
+
+static void __team_queue_override_enabled_check(struct team *team)
+{
+       struct team_port *port;
+       bool enabled = false;
+
+       list_for_each_entry(port, &team->port_list, list) {
+               if (!list_empty(&port->qom_list)) {
+                       enabled = true;
+                       break;
+               }
+       }
+       if (enabled == team->queue_override_enabled)
+               return;
+       netdev_dbg(team->dev, "%s queue override\n",
+                  enabled ? "Enabling" : "Disabling");
+       team->queue_override_enabled = enabled;
+}
+
+static void team_queue_override_port_refresh(struct team *team,
+                                            struct team_port *port)
+{
+       __team_queue_override_port_del(team, port);
+       __team_queue_override_port_add(team, port);
+       __team_queue_override_enabled_check(team);
+}
+
+
 /****************
  * Port handling
  ****************/
@@ -688,6 +804,7 @@ static void team_port_enable(struct team *team,
        hlist_add_head_rcu(&port->hlist,
                           team_port_index_hash(team, port->index));
        team_adjust_ops(team);
+       team_queue_override_port_refresh(team, port);
        if (team->ops.port_enabled)
                team->ops.port_enabled(team, port);
 }
@@ -716,6 +833,7 @@ static void team_port_disable(struct team *team,
        hlist_del_rcu(&port->hlist);
        __reconstruct_port_hlist(team, port->index);
        port->index = -1;
+       team_queue_override_port_refresh(team, port);
        __team_adjust_ops(team, team->en_port_count - 1);
        /*
         * Wait until readers see adjusted ops. This ensures that
@@ -795,16 +913,17 @@ static void team_port_leave(struct team *team, struct team_port *port)
 }
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
-static int team_port_enable_netpoll(struct team *team, struct team_port *port)
+static int team_port_enable_netpoll(struct team *team, struct team_port *port,
+                                   gfp_t gfp)
 {
        struct netpoll *np;
        int err;
 
-       np = kzalloc(sizeof(*np), GFP_KERNEL);
+       np = kzalloc(sizeof(*np), gfp);
        if (!np)
                return -ENOMEM;
 
-       err = __netpoll_setup(np, port->dev);
+       err = __netpoll_setup(np, port->dev, gfp);
        if (err) {
                kfree(np);
                return err;
@@ -833,7 +952,8 @@ static struct netpoll_info *team_netpoll_info(struct team *team)
 }
 
 #else
-static int team_port_enable_netpoll(struct team *team, struct team_port *port)
+static int team_port_enable_netpoll(struct team *team, struct team_port *port,
+                                   gfp_t gfp)
 {
        return 0;
 }
@@ -881,6 +1001,7 @@ static int team_port_add(struct team *team, struct net_device *port_dev)
 
        port->dev = port_dev;
        port->team = team;
+       INIT_LIST_HEAD(&port->qom_list);
 
        port->orig.mtu = port_dev->mtu;
        err = dev_set_mtu(port_dev, dev->mtu);
@@ -913,7 +1034,7 @@ static int team_port_add(struct team *team, struct net_device *port_dev)
        }
 
        if (team_netpoll_info(team)) {
-               err = team_port_enable_netpoll(team, port);
+               err = team_port_enable_netpoll(team, port, GFP_KERNEL);
                if (err) {
                        netdev_err(dev, "Failed to enable netpoll on device %s\n",
                                   portname);
@@ -1092,6 +1213,49 @@ static int team_user_linkup_en_option_set(struct team *team,
        return 0;
 }
 
+static int team_priority_option_get(struct team *team,
+                                   struct team_gsetter_ctx *ctx)
+{
+       struct team_port *port = ctx->info->port;
+
+       ctx->data.s32_val = port->priority;
+       return 0;
+}
+
+static int team_priority_option_set(struct team *team,
+                                   struct team_gsetter_ctx *ctx)
+{
+       struct team_port *port = ctx->info->port;
+
+       port->priority = ctx->data.s32_val;
+       team_queue_override_port_refresh(team, port);
+       return 0;
+}
+
+static int team_queue_id_option_get(struct team *team,
+                                   struct team_gsetter_ctx *ctx)
+{
+       struct team_port *port = ctx->info->port;
+
+       ctx->data.u32_val = port->queue_id;
+       return 0;
+}
+
+static int team_queue_id_option_set(struct team *team,
+                                   struct team_gsetter_ctx *ctx)
+{
+       struct team_port *port = ctx->info->port;
+
+       if (port->queue_id == ctx->data.u32_val)
+               return 0;
+       if (ctx->data.u32_val >= team->dev->real_num_tx_queues)
+               return -EINVAL;
+       port->queue_id = ctx->data.u32_val;
+       team_queue_override_port_refresh(team, port);
+       return 0;
+}
+
+
 static const struct team_option team_options[] = {
        {
                .name = "mode",
@@ -1120,6 +1284,20 @@ static const struct team_option team_options[] = {
                .getter = team_user_linkup_en_option_get,
                .setter = team_user_linkup_en_option_set,
        },
+       {
+               .name = "priority",
+               .type = TEAM_OPTION_TYPE_S32,
+               .per_port = true,
+               .getter = team_priority_option_get,
+               .setter = team_priority_option_set,
+       },
+       {
+               .name = "queue_id",
+               .type = TEAM_OPTION_TYPE_U32,
+               .per_port = true,
+               .getter = team_queue_id_option_get,
+               .setter = team_queue_id_option_set,
+       },
 };
 
 static struct lock_class_key team_netdev_xmit_lock_key;
@@ -1155,6 +1333,9 @@ static int team_init(struct net_device *dev)
        for (i = 0; i < TEAM_PORT_HASHENTRIES; i++)
                INIT_HLIST_HEAD(&team->en_port_hlist[i]);
        INIT_LIST_HEAD(&team->port_list);
+       err = team_queue_override_init(team);
+       if (err)
+               goto err_team_queue_override_init;
 
        team_adjust_ops(team);
 
@@ -1170,6 +1351,8 @@ static int team_init(struct net_device *dev)
        return 0;
 
 err_options_register:
+       team_queue_override_fini(team);
+err_team_queue_override_init:
        free_percpu(team->pcpu_stats);
 
        return err;
@@ -1187,6 +1370,7 @@ static void team_uninit(struct net_device *dev)
 
        __team_change_mode(team, NULL); /* cleanup */
        __team_options_unregister(team, team_options, ARRAY_SIZE(team_options));
+       team_queue_override_fini(team);
        mutex_unlock(&team->lock);
 }
 
@@ -1216,10 +1400,12 @@ static int team_close(struct net_device *dev)
 static netdev_tx_t team_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct team *team = netdev_priv(dev);
-       bool tx_success = false;
+       bool tx_success;
        unsigned int len = skb->len;
 
-       tx_success = team->ops.transmit(team, skb);
+       tx_success = team_queue_override_transmit(team, skb);
+       if (!tx_success)
+               tx_success = team->ops.transmit(team, skb);
        if (tx_success) {
                struct team_pcpu_stats *pcpu_stats;
 
@@ -1443,7 +1629,7 @@ static void team_netpoll_cleanup(struct net_device *dev)
 }
 
 static int team_netpoll_setup(struct net_device *dev,
-                             struct netpoll_info *npifo)
+                             struct netpoll_info *npifo, gfp_t gfp)
 {
        struct team *team = netdev_priv(dev);
        struct team_port *port;
@@ -1451,7 +1637,7 @@ static int team_netpoll_setup(struct net_device *dev,
 
        mutex_lock(&team->lock);
        list_for_each_entry(port, &team->port_list, list) {
-               err = team_port_enable_netpoll(team, port);
+               err = team_port_enable_netpoll(team, port, gfp);
                if (err) {
                        __team_netpoll_cleanup(team);
                        break;
@@ -1787,6 +1973,12 @@ static int team_nl_fill_one_option_get(struct sk_buff *skb, struct team *team,
                    nla_put_flag(skb, TEAM_ATTR_OPTION_DATA))
                        goto nest_cancel;
                break;
+       case TEAM_OPTION_TYPE_S32:
+               if (nla_put_u8(skb, TEAM_ATTR_OPTION_TYPE, NLA_S32))
+                       goto nest_cancel;
+               if (nla_put_s32(skb, TEAM_ATTR_OPTION_DATA, ctx.data.s32_val))
+                       goto nest_cancel;
+               break;
        default:
                BUG();
        }
@@ -1975,6 +2167,9 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info)
                case NLA_FLAG:
                        opt_type = TEAM_OPTION_TYPE_BOOL;
                        break;
+               case NLA_S32:
+                       opt_type = TEAM_OPTION_TYPE_S32;
+                       break;
                default:
                        goto team_put;
                }
@@ -2031,6 +2226,9 @@ static int team_nl_cmd_options_set(struct sk_buff *skb, struct genl_info *info)
                        case TEAM_OPTION_TYPE_BOOL:
                                ctx.data.bool_val = attr_data ? true : false;
                                break;
+                       case TEAM_OPTION_TYPE_S32:
+                               ctx.data.s32_val = nla_get_s32(attr_data);
+                               break;
                        default:
                                BUG();
                        }
index 926d4db5cb384f2de6df5ae871d0ec6171c6fe7d..3a16d4fdaa052817135c885b23cb28d90d872ec6 100644 (file)
@@ -187,7 +187,6 @@ static void __tun_detach(struct tun_struct *tun)
        netif_tx_lock_bh(tun->dev);
        netif_carrier_off(tun->dev);
        tun->tfile = NULL;
-       tun->socket.file = NULL;
        netif_tx_unlock_bh(tun->dev);
 
        /* Drop read queue */
index 64610048ce87c178770059b163395a285cb69e77..7d78669000d704d8448aea5e24a8a73c312badfc 100644 (file)
@@ -232,6 +232,7 @@ static int usbpn_open(struct net_device *dev)
                struct urb *req = usb_alloc_urb(0, GFP_KERNEL);
 
                if (!req || rx_submit(pnd, req, GFP_KERNEL | __GFP_COLD)) {
+                       usb_free_urb(req);
                        usbpn_close(dev);
                        return -ENOMEM;
                }
index f4ce5957df326bb94131031fabdb1daf6dcabf42..4cd582a4f625d55d5edd8c2cd3952d5571074921 100644 (file)
@@ -1225,6 +1225,26 @@ static const struct usb_device_id cdc_devs[] = {
          .driver_info = (unsigned long) &wwan_info,
        },
 
+       /* Dell branded MBM devices like DW5550 */
+       { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
+               | USB_DEVICE_ID_MATCH_VENDOR,
+         .idVendor = 0x413c,
+         .bInterfaceClass = USB_CLASS_COMM,
+         .bInterfaceSubClass = USB_CDC_SUBCLASS_NCM,
+         .bInterfaceProtocol = USB_CDC_PROTO_NONE,
+         .driver_info = (unsigned long) &wwan_info,
+       },
+
+       /* Toshiba branded MBM devices */
+       { .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
+               | USB_DEVICE_ID_MATCH_VENDOR,
+         .idVendor = 0x0930,
+         .bInterfaceClass = USB_CLASS_COMM,
+         .bInterfaceSubClass = USB_CDC_SUBCLASS_NCM,
+         .bInterfaceProtocol = USB_CDC_PROTO_NONE,
+         .driver_info = (unsigned long) &wwan_info,
+       },
+
        /* Generic CDC-NCM devices */
        { USB_INTERFACE_INFO(USB_CLASS_COMM,
                USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE),
index 62f30b46fa42d26544f20e3158e964eccaa05da4..605a4baa9b7b89083e27c5a5d8b76ef938959dd4 100644 (file)
@@ -1107,7 +1107,6 @@ static void _hso_serial_set_termios(struct tty_struct *tty,
                                    struct ktermios *old)
 {
        struct hso_serial *serial = tty->driver_data;
-       struct ktermios *termios;
 
        if (!serial) {
                printk(KERN_ERR "%s: no tty structures", __func__);
@@ -1119,16 +1118,15 @@ static void _hso_serial_set_termios(struct tty_struct *tty,
        /*
         *      Fix up unsupported bits
         */
-       termios = tty->termios;
-       termios->c_iflag &= ~IXON; /* disable enable XON/XOFF flow control */
+       tty->termios.c_iflag &= ~IXON; /* disable enable XON/XOFF flow control */
 
-       termios->c_cflag &=
+       tty->termios.c_cflag &=
                ~(CSIZE         /* no size */
                | PARENB        /* disable parity bit */
                | CBAUD         /* clear current baud rate */
                | CBAUDEX);     /* clear current buad rate */
 
-       termios->c_cflag |= CS8;        /* character size 8 bits */
+       tty->termios.c_cflag |= CS8;    /* character size 8 bits */
 
        /* baud rate 115200 */
        tty_encode_baud_rate(tty, 115200, 115200);
@@ -1425,14 +1423,14 @@ static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old)
 
        if (old)
                D5("Termios called with: cflags new[%d] - old[%d]",
-                  tty->termios->c_cflag, old->c_cflag);
+                  tty->termios.c_cflag, old->c_cflag);
 
        /* the actual setup */
        spin_lock_irqsave(&serial->serial_lock, flags);
        if (serial->port.count)
                _hso_serial_set_termios(tty, old);
        else
-               tty->termios = old;
+               tty->termios = *old;
        spin_unlock_irqrestore(&serial->serial_lock, flags);
 
        /* done */
@@ -2289,9 +2287,11 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs,
        if (minor < 0)
                goto exit;
 
+       tty_port_init(&serial->port);
+
        /* register our minor number */
-       serial->parent->dev = tty_register_device(tty_drv, minor,
-                                       &serial->parent->interface->dev);
+       serial->parent->dev = tty_port_register_device(&serial->port, tty_drv,
+                       minor, &serial->parent->interface->dev);
        dev = serial->parent->dev;
        dev_set_drvdata(dev, serial->parent);
        i = device_create_file(dev, &dev_attr_hsotype);
@@ -2300,7 +2300,6 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs,
        serial->minor = minor;
        serial->magic = HSO_SERIAL_MAGIC;
        spin_lock_init(&serial->serial_lock);
-       tty_port_init(&serial->port);
        serial->num_rx_urbs = num_urbs;
 
        /* RX, allocate urb and initialize */
index 2ea126a16d79add1f5271e8848942ffc2a755b37..aaa061b7355d68723ec031a689c6cfac5588b0a6 100644 (file)
@@ -247,30 +247,12 @@ err:
  */
 static int qmi_wwan_bind_shared(struct usbnet *dev, struct usb_interface *intf)
 {
-       int rv;
        struct qmi_wwan_state *info = (void *)&dev->data;
 
-       /* ZTE makes devices where the interface descriptors and endpoint
-        * configurations of two or more interfaces are identical, even
-        * though the functions are completely different.  If set, then
-        * driver_info->data is a bitmap of acceptable interface numbers
-        * allowing us to bind to one such interface without binding to
-        * all of them
-        */
-       if (dev->driver_info->data &&
-           !test_bit(intf->cur_altsetting->desc.bInterfaceNumber, &dev->driver_info->data)) {
-               dev_info(&intf->dev, "not on our whitelist - ignored");
-               rv = -ENODEV;
-               goto err;
-       }
-
        /*  control and data is shared */
        info->control = intf;
        info->data = intf;
-       rv = qmi_wwan_register_subdriver(dev);
-
-err:
-       return rv;
+       return qmi_wwan_register_subdriver(dev);
 }
 
 static void qmi_wwan_unbind(struct usbnet *dev, struct usb_interface *intf)
@@ -356,214 +338,59 @@ static const struct driver_info  qmi_wwan_shared = {
        .manage_power   = qmi_wwan_manage_power,
 };
 
-static const struct driver_info        qmi_wwan_force_int0 = {
-       .description    = "Qualcomm WWAN/QMI device",
-       .flags          = FLAG_WWAN,
-       .bind           = qmi_wwan_bind_shared,
-       .unbind         = qmi_wwan_unbind,
-       .manage_power   = qmi_wwan_manage_power,
-       .data           = BIT(0), /* interface whitelist bitmap */
-};
-
-static const struct driver_info        qmi_wwan_force_int1 = {
-       .description    = "Qualcomm WWAN/QMI device",
-       .flags          = FLAG_WWAN,
-       .bind           = qmi_wwan_bind_shared,
-       .unbind         = qmi_wwan_unbind,
-       .manage_power   = qmi_wwan_manage_power,
-       .data           = BIT(1), /* interface whitelist bitmap */
-};
-
-static const struct driver_info qmi_wwan_force_int2 = {
-       .description    = "Qualcomm WWAN/QMI device",
-       .flags          = FLAG_WWAN,
-       .bind           = qmi_wwan_bind_shared,
-       .unbind         = qmi_wwan_unbind,
-       .manage_power   = qmi_wwan_manage_power,
-       .data           = BIT(2), /* interface whitelist bitmap */
-};
-
-static const struct driver_info        qmi_wwan_force_int3 = {
-       .description    = "Qualcomm WWAN/QMI device",
-       .flags          = FLAG_WWAN,
-       .bind           = qmi_wwan_bind_shared,
-       .unbind         = qmi_wwan_unbind,
-       .manage_power   = qmi_wwan_manage_power,
-       .data           = BIT(3), /* interface whitelist bitmap */
-};
-
-static const struct driver_info        qmi_wwan_force_int4 = {
-       .description    = "Qualcomm WWAN/QMI device",
-       .flags          = FLAG_WWAN,
-       .bind           = qmi_wwan_bind_shared,
-       .unbind         = qmi_wwan_unbind,
-       .manage_power   = qmi_wwan_manage_power,
-       .data           = BIT(4), /* interface whitelist bitmap */
-};
-
-/* Sierra Wireless provide equally useless interface descriptors
- * Devices in QMI mode can be switched between two different
- * configurations:
- *   a) USB interface #8 is QMI/wwan
- *   b) USB interfaces #8, #19 and #20 are QMI/wwan
- *
- * Both configurations provide a number of other interfaces (serial++),
- * some of which have the same endpoint configuration as we expect, so
- * a whitelist or blacklist is necessary.
- *
- * FIXME: The below whitelist should include BIT(20).  It does not
- * because I cannot get it to work...
- */
-static const struct driver_info        qmi_wwan_sierra = {
-       .description    = "Sierra Wireless wwan/QMI device",
-       .flags          = FLAG_WWAN,
-       .bind           = qmi_wwan_bind_shared,
-       .unbind         = qmi_wwan_unbind,
-       .manage_power   = qmi_wwan_manage_power,
-       .data           = BIT(8) | BIT(19), /* interface whitelist bitmap */
-};
-
 #define HUAWEI_VENDOR_ID       0x12D1
 
+/* map QMI/wwan function by a fixed interface number */
+#define QMI_FIXED_INTF(vend, prod, num) \
+       USB_DEVICE_INTERFACE_NUMBER(vend, prod, num), \
+       .driver_info = (unsigned long)&qmi_wwan_shared
+
 /* Gobi 1000 QMI/wwan interface number is 3 according to qcserial */
 #define QMI_GOBI1K_DEVICE(vend, prod) \
-       USB_DEVICE(vend, prod), \
-       .driver_info = (unsigned long)&qmi_wwan_force_int3
+       QMI_FIXED_INTF(vend, prod, 3)
 
-/* Gobi 2000 and Gobi 3000 QMI/wwan interface number is 0 according to qcserial */
+/* Gobi 2000/3000 QMI/wwan interface number is 0 according to qcserial */
 #define QMI_GOBI_DEVICE(vend, prod) \
-       USB_DEVICE(vend, prod), \
-       .driver_info = (unsigned long)&qmi_wwan_force_int0
+       QMI_FIXED_INTF(vend, prod, 0)
 
 static const struct usb_device_id products[] = {
+       /* 1. CDC ECM like devices match on the control interface */
        {       /* Huawei E392, E398 and possibly others sharing both device id and more... */
-               .match_flags        = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO,
-               .idVendor           = HUAWEI_VENDOR_ID,
-               .bInterfaceClass    = USB_CLASS_VENDOR_SPEC,
-               .bInterfaceSubClass = 1,
-               .bInterfaceProtocol = 9, /* CDC Ethernet *control* interface */
+               USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 1, 9),
                .driver_info        = (unsigned long)&qmi_wwan_info,
        },
        {       /* Vodafone/Huawei K5005 (12d1:14c8) and similar modems */
-               .match_flags        = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO,
-               .idVendor           = HUAWEI_VENDOR_ID,
-               .bInterfaceClass    = USB_CLASS_VENDOR_SPEC,
-               .bInterfaceSubClass = 1,
-               .bInterfaceProtocol = 57, /* CDC Ethernet *control* interface */
+               USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 1, 57),
                .driver_info        = (unsigned long)&qmi_wwan_info,
        },
-       {       /* Huawei E392, E398 and possibly others in "Windows mode"
-                * using a combined control and data interface without any CDC
-                * functional descriptors
-                */
-               .match_flags        = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO,
-               .idVendor           = HUAWEI_VENDOR_ID,
-               .bInterfaceClass    = USB_CLASS_VENDOR_SPEC,
-               .bInterfaceSubClass = 1,
-               .bInterfaceProtocol = 17,
+
+       /* 2. Combined interface devices matching on class+protocol */
+       {       /* Huawei E392, E398 and possibly others in "Windows mode" */
+               USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_VENDOR_SPEC, 1, 17),
                .driver_info        = (unsigned long)&qmi_wwan_shared,
        },
        {       /* Pantech UML290 */
-               .match_flags        = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
-               .idVendor           = 0x106c,
-               .idProduct          = 0x3718,
-               .bInterfaceClass    = 0xff,
-               .bInterfaceSubClass = 0xf0,
-               .bInterfaceProtocol = 0xff,
+               USB_DEVICE_AND_INTERFACE_INFO(0x106c, 0x3718, USB_CLASS_VENDOR_SPEC, 0xf0, 0xff),
                .driver_info        = (unsigned long)&qmi_wwan_shared,
        },
-       {       /* ZTE MF820D */
-               .match_flags        = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
-               .idVendor           = 0x19d2,
-               .idProduct          = 0x0167,
-               .bInterfaceClass    = 0xff,
-               .bInterfaceSubClass = 0xff,
-               .bInterfaceProtocol = 0xff,
-               .driver_info        = (unsigned long)&qmi_wwan_force_int4,
-       },
-       {       /* ZTE MF821D */
-               .match_flags        = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
-               .idVendor           = 0x19d2,
-               .idProduct          = 0x0326,
-               .bInterfaceClass    = 0xff,
-               .bInterfaceSubClass = 0xff,
-               .bInterfaceProtocol = 0xff,
-               .driver_info        = (unsigned long)&qmi_wwan_force_int4,
-       },
-       {       /* ZTE (Vodafone) K3520-Z */
-               .match_flags        = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
-               .idVendor           = 0x19d2,
-               .idProduct          = 0x0055,
-               .bInterfaceClass    = 0xff,
-               .bInterfaceSubClass = 0xff,
-               .bInterfaceProtocol = 0xff,
-               .driver_info        = (unsigned long)&qmi_wwan_force_int1,
-       },
-       {       /* ZTE (Vodafone) K3565-Z */
-               .match_flags        = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
-               .idVendor           = 0x19d2,
-               .idProduct          = 0x0063,
-               .bInterfaceClass    = 0xff,
-               .bInterfaceSubClass = 0xff,
-               .bInterfaceProtocol = 0xff,
-               .driver_info        = (unsigned long)&qmi_wwan_force_int4,
-       },
-       {       /* ZTE (Vodafone) K3570-Z */
-               .match_flags        = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
-               .idVendor           = 0x19d2,
-               .idProduct          = 0x1008,
-               .bInterfaceClass    = 0xff,
-               .bInterfaceSubClass = 0xff,
-               .bInterfaceProtocol = 0xff,
-               .driver_info        = (unsigned long)&qmi_wwan_force_int4,
-       },
-       {       /* ZTE (Vodafone) K3571-Z */
-               .match_flags        = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
-               .idVendor           = 0x19d2,
-               .idProduct          = 0x1010,
-               .bInterfaceClass    = 0xff,
-               .bInterfaceSubClass = 0xff,
-               .bInterfaceProtocol = 0xff,
-               .driver_info        = (unsigned long)&qmi_wwan_force_int4,
-       },
-       {       /* ZTE (Vodafone) K3765-Z */
-               .match_flags        = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
-               .idVendor           = 0x19d2,
-               .idProduct          = 0x2002,
-               .bInterfaceClass    = 0xff,
-               .bInterfaceSubClass = 0xff,
-               .bInterfaceProtocol = 0xff,
-               .driver_info        = (unsigned long)&qmi_wwan_force_int4,
-       },
-       {       /* ZTE (Vodafone) K4505-Z */
-               .match_flags        = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
-               .idVendor           = 0x19d2,
-               .idProduct          = 0x0104,
-               .bInterfaceClass    = 0xff,
-               .bInterfaceSubClass = 0xff,
-               .bInterfaceProtocol = 0xff,
-               .driver_info        = (unsigned long)&qmi_wwan_force_int4,
-       },
-       {       /* ZTE MF60 */
-               .match_flags        = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
-               .idVendor           = 0x19d2,
-               .idProduct          = 0x1402,
-               .bInterfaceClass    = 0xff,
-               .bInterfaceSubClass = 0xff,
-               .bInterfaceProtocol = 0xff,
-               .driver_info        = (unsigned long)&qmi_wwan_force_int2,
-       },
-       {       /* Sierra Wireless MC77xx in QMI mode */
-               .match_flags        = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO,
-               .idVendor           = 0x1199,
-               .idProduct          = 0x68a2,
-               .bInterfaceClass    = 0xff,
-               .bInterfaceSubClass = 0xff,
-               .bInterfaceProtocol = 0xff,
-               .driver_info        = (unsigned long)&qmi_wwan_sierra,
-       },
 
-       /* Gobi 1000 devices */
+       /* 3. Combined interface devices matching on interface number */
+       {QMI_FIXED_INTF(0x19d2, 0x0055, 1)},    /* ZTE (Vodafone) K3520-Z */
+       {QMI_FIXED_INTF(0x19d2, 0x0063, 4)},    /* ZTE (Vodafone) K3565-Z */
+       {QMI_FIXED_INTF(0x19d2, 0x0104, 4)},    /* ZTE (Vodafone) K4505-Z */
+       {QMI_FIXED_INTF(0x19d2, 0x0167, 4)},    /* ZTE MF820D */
+       {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 */
+       {QMI_FIXED_INTF(0x19d2, 0x1402, 2)},    /* ZTE MF60 */
+       {QMI_FIXED_INTF(0x19d2, 0x2002, 4)},    /* ZTE (Vodafone) K3765-Z */
+       {QMI_FIXED_INTF(0x0f3d, 0x68a2, 8)},    /* Sierra Wireless MC7700 */
+       {QMI_FIXED_INTF(0x114f, 0x68a2, 8)},    /* Sierra Wireless MC7750 */
+       {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 */
+
+       /* 4. Gobi 1000 devices */
        {QMI_GOBI1K_DEVICE(0x05c6, 0x9212)},    /* Acer Gobi Modem Device */
        {QMI_GOBI1K_DEVICE(0x03f0, 0x1f1d)},    /* HP un2400 Gobi Modem Device */
        {QMI_GOBI1K_DEVICE(0x03f0, 0x371d)},    /* HP un2430 Mobile Broadband Module */
@@ -579,7 +406,7 @@ static const struct usb_device_id products[] = {
        {QMI_GOBI1K_DEVICE(0x05c6, 0x9222)},    /* Generic Gobi Modem device */
        {QMI_GOBI1K_DEVICE(0x05c6, 0x9009)},    /* Generic Gobi Modem device */
 
-       /* Gobi 2000 and 3000 devices */
+       /* 5. Gobi 2000 and 3000 devices */
        {QMI_GOBI_DEVICE(0x413c, 0x8186)},      /* Dell Gobi 2000 Modem device (N0218, VU936) */
        {QMI_GOBI_DEVICE(0x05c6, 0x920b)},      /* Generic Gobi 2000 Modem device */
        {QMI_GOBI_DEVICE(0x05c6, 0x9225)},      /* Sony Gobi 2000 Modem device (N0279, VU730) */
@@ -589,6 +416,8 @@ static const struct usb_device_id products[] = {
        {QMI_GOBI_DEVICE(0x05c6, 0x9265)},      /* Asus Gobi 2000 Modem device (VR305) */
        {QMI_GOBI_DEVICE(0x05c6, 0x9235)},      /* Top Global Gobi 2000 Modem device (VR306) */
        {QMI_GOBI_DEVICE(0x05c6, 0x9275)},      /* iRex Technologies Gobi 2000 Modem device (VR307) */
+       {QMI_GOBI_DEVICE(0x1199, 0x68a5)},      /* Sierra Wireless Modem */
+       {QMI_GOBI_DEVICE(0x1199, 0x68a9)},      /* Sierra Wireless Modem */
        {QMI_GOBI_DEVICE(0x1199, 0x9001)},      /* Sierra Wireless Gobi 2000 Modem device (VT773) */
        {QMI_GOBI_DEVICE(0x1199, 0x9002)},      /* Sierra Wireless Gobi 2000 Modem device (VT773) */
        {QMI_GOBI_DEVICE(0x1199, 0x9003)},      /* Sierra Wireless Gobi 2000 Modem device (VT773) */
@@ -600,11 +429,14 @@ static const struct usb_device_id products[] = {
        {QMI_GOBI_DEVICE(0x1199, 0x9009)},      /* Sierra Wireless Gobi 2000 Modem device (VT773) */
        {QMI_GOBI_DEVICE(0x1199, 0x900a)},      /* Sierra Wireless Gobi 2000 Modem device (VT773) */
        {QMI_GOBI_DEVICE(0x1199, 0x9011)},      /* Sierra Wireless Gobi 2000 Modem device (MC8305) */
+       {QMI_FIXED_INTF(0x1199, 0x9011, 5)},    /* alternate interface number!? */
        {QMI_GOBI_DEVICE(0x16d8, 0x8002)},      /* CMDTech Gobi 2000 Modem device (VU922) */
        {QMI_GOBI_DEVICE(0x05c6, 0x9205)},      /* Gobi 2000 Modem device */
        {QMI_GOBI_DEVICE(0x1199, 0x9013)},      /* Sierra Wireless Gobi 3000 Modem device (MC8355) */
        {QMI_GOBI_DEVICE(0x1199, 0x9015)},      /* Sierra Wireless Gobi 3000 Modem device */
        {QMI_GOBI_DEVICE(0x1199, 0x9019)},      /* Sierra Wireless Gobi 3000 Modem device */
+       {QMI_GOBI_DEVICE(0x1199, 0x901b)},      /* Sierra Wireless MC7770 */
+
        { }                                     /* END */
 };
 MODULE_DEVICE_TABLE(usb, products);
index d75d1f56becff95ae9cf7b8f8dc08990d142d06c..7be49ea60b6d8f9353720d757f47c2c61b16fc60 100644 (file)
@@ -68,15 +68,8 @@ static       atomic_t iface_counter = ATOMIC_INIT(0);
  */
 #define SIERRA_NET_USBCTL_BUF_LEN      1024
 
-/* list of interface numbers - used for constructing interface lists */
-struct sierra_net_iface_info {
-       const u32 infolen;      /* number of interface numbers on list */
-       const u8  *ifaceinfo;   /* pointer to the array holding the numbers */
-};
-
 struct sierra_net_info_data {
        u16 rx_urb_size;
-       struct sierra_net_iface_info whitelist;
 };
 
 /* Private data structure */
@@ -637,21 +630,6 @@ static int sierra_net_change_mtu(struct net_device *net, int new_mtu)
        return usbnet_change_mtu(net, new_mtu);
 }
 
-static int is_whitelisted(const u8 ifnum,
-                       const struct sierra_net_iface_info *whitelist)
-{
-       if (whitelist) {
-               const u8 *list = whitelist->ifaceinfo;
-               int i;
-
-               for (i = 0; i < whitelist->infolen; i++) {
-                       if (list[i] == ifnum)
-                               return 1;
-               }
-       }
-       return 0;
-}
-
 static int sierra_net_get_fw_attr(struct usbnet *dev, u16 *datap)
 {
        int result = 0;
@@ -706,11 +684,6 @@ static int sierra_net_bind(struct usbnet *dev, struct usb_interface *intf)
        dev_dbg(&dev->udev->dev, "%s", __func__);
 
        ifacenum = intf->cur_altsetting->desc.bInterfaceNumber;
-       /* We only accept certain interfaces */
-       if (!is_whitelisted(ifacenum, &data->whitelist)) {
-               dev_dbg(&dev->udev->dev, "Ignoring interface: %d", ifacenum);
-               return -ENODEV;
-       }
        numendpoints = intf->cur_altsetting->desc.bNumEndpoints;
        /* We have three endpoints, bulk in and out, and a status */
        if (numendpoints != 3) {
@@ -945,13 +918,8 @@ struct sk_buff *sierra_net_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
        return NULL;
 }
 
-static const u8 sierra_net_ifnum_list[] = { 7, 10, 11 };
 static const struct sierra_net_info_data sierra_net_info_data_direct_ip = {
        .rx_urb_size = 8 * 1024,
-       .whitelist = {
-               .infolen = ARRAY_SIZE(sierra_net_ifnum_list),
-               .ifaceinfo = sierra_net_ifnum_list
-       }
 };
 
 static const struct driver_info sierra_net_info_direct_ip = {
@@ -965,15 +933,19 @@ static const struct driver_info sierra_net_info_direct_ip = {
        .data = (unsigned long)&sierra_net_info_data_direct_ip,
 };
 
+#define DIRECT_IP_DEVICE(vend, prod) \
+       {USB_DEVICE_INTERFACE_NUMBER(vend, prod, 7), \
+       .driver_info = (unsigned long)&sierra_net_info_direct_ip}, \
+       {USB_DEVICE_INTERFACE_NUMBER(vend, prod, 10), \
+       .driver_info = (unsigned long)&sierra_net_info_direct_ip}, \
+       {USB_DEVICE_INTERFACE_NUMBER(vend, prod, 11), \
+       .driver_info = (unsigned long)&sierra_net_info_direct_ip}
+
 static const struct usb_device_id products[] = {
-       {USB_DEVICE(0x1199, 0x68A3), /* Sierra Wireless USB-to-WWAN modem */
-       .driver_info = (unsigned long) &sierra_net_info_direct_ip},
-       {USB_DEVICE(0x0F3D, 0x68A3), /* AT&T Direct IP modem */
-       .driver_info = (unsigned long) &sierra_net_info_direct_ip},
-       {USB_DEVICE(0x1199, 0x68AA), /* Sierra Wireless Direct IP LTE modem */
-       .driver_info = (unsigned long) &sierra_net_info_direct_ip},
-       {USB_DEVICE(0x0F3D, 0x68AA), /* AT&T Direct IP LTE modem */
-       .driver_info = (unsigned long) &sierra_net_info_direct_ip},
+       DIRECT_IP_DEVICE(0x1199, 0x68A3), /* Sierra Wireless USB-to-WWAN modem */
+       DIRECT_IP_DEVICE(0x0F3D, 0x68A3), /* AT&T Direct IP modem */
+       DIRECT_IP_DEVICE(0x1199, 0x68AA), /* Sierra Wireless Direct IP LTE modem */
+       DIRECT_IP_DEVICE(0x0F3D, 0x68AA), /* AT&T Direct IP LTE modem */
 
        {}, /* last item */
 };
index 5852361032c459735e915db5443ac08d560f2c7c..e522ff70444cd0d7e8f1ce34132055e438ded7ce 100644 (file)
@@ -348,6 +348,9 @@ static int veth_newlink(struct net *src_net, struct net_device *dev,
        if (tbp[IFLA_ADDRESS] == NULL)
                eth_hw_addr_random(peer);
 
+       if (ifmp && (dev->ifindex != 0))
+               peer->ifindex = ifmp->ifi_index;
+
        err = register_netdevice(peer);
        put_net(net);
        net = NULL;
index 83d2b0c34c5e63045eaeb63c3e40b14ab68e7875..81a64c58e8adb09c9d868a0eb4ccc3bb782d9182 100644 (file)
@@ -993,7 +993,7 @@ static void virtnet_config_changed_work(struct work_struct *work)
                goto done;
 
        if (v & VIRTIO_NET_S_ANNOUNCE) {
-               netif_notify_peers(vi->dev);
+               netdev_notify_peers(vi->dev);
                virtnet_ack_link_announce(vi);
        }
 
index 93e0cfb739b89b3f53964e6596c5b36e804b4a1b..ce9d4f2c9776e08d1b543f18de8cb7100fe43a86 100644 (file)
@@ -3019,6 +3019,7 @@ vmxnet3_probe_device(struct pci_dev *pdev,
        netdev->watchdog_timeo = 5 * HZ;
 
        INIT_WORK(&adapter->work, vmxnet3_reset_work);
+       set_bit(VMXNET3_STATE_BIT_QUIESCED, &adapter->state);
 
        if (adapter->intr.type == VMXNET3_IT_MSIX) {
                int i;
@@ -3043,7 +3044,6 @@ vmxnet3_probe_device(struct pci_dev *pdev,
                goto err_register;
        }
 
-       set_bit(VMXNET3_STATE_BIT_QUIESCED, &adapter->state);
        vmxnet3_check_link(adapter, false);
        atomic_inc(&devices_found);
        return 0;
index efc162e0b511c6d67ecdd4d011caa84c84708b8b..88b8d64c90f1b49a302deaca3af07788ee4b27c1 100644 (file)
@@ -342,7 +342,7 @@ static int at76_dfu_get_status(struct usb_device *udev,
        return ret;
 }
 
-static u8 at76_dfu_get_state(struct usb_device *udev, u8 *state)
+static int at76_dfu_get_state(struct usb_device *udev, u8 *state)
 {
        int ret;
 
index 64a453a6dfe442d22c533435787df147b86101fe..3150def17193b72652bb068c8fde9ca99e0a6e5f 100644 (file)
@@ -1331,7 +1331,6 @@ struct ath5k_hw {
        unsigned int            nexttbtt;       /* next beacon time in TU */
        struct ath5k_txq        *cabq;          /* content after beacon */
 
-       int                     power_level;    /* Requested tx power in dBm */
        bool                    assoc;          /* associate state */
        bool                    enable_beacon;  /* true if beacons are on */
 
@@ -1425,6 +1424,7 @@ struct ath5k_hw {
                /* Value in dB units */
                s16             txp_cck_ofdm_pwr_delta;
                bool            txp_setup;
+               int             txp_requested;  /* Requested tx power in dBm */
        } ah_txpower;
 
        struct ath5k_nfcal_hist ah_nfcal_hist;
index 8c4c040a47b8cf69e75b4f022dafc3542f2ae908..a0a202de110953c0808539667f0f3bfacd57173b 100644 (file)
@@ -723,7 +723,7 @@ ath5k_txbuf_setup(struct ath5k_hw *ah, struct ath5k_buf *bf,
        ret = ah->ah_setup_tx_desc(ah, ds, pktlen,
                ieee80211_get_hdrlen_from_skb(skb), padsize,
                get_hw_packet_type(skb),
-               (ah->power_level * 2),
+               (ah->ah_txpower.txp_requested * 2),
                hw_rate,
                info->control.rates[0].count, keyidx, ah->ah_tx_ant, flags,
                cts_rate, duration);
@@ -1778,7 +1778,8 @@ ath5k_beacon_setup(struct ath5k_hw *ah, struct ath5k_buf *bf)
        ds->ds_data = bf->skbaddr;
        ret = ah->ah_setup_tx_desc(ah, ds, skb->len,
                        ieee80211_get_hdrlen_from_skb(skb), padsize,
-                       AR5K_PKT_TYPE_BEACON, (ah->power_level * 2),
+                       AR5K_PKT_TYPE_BEACON,
+                       (ah->ah_txpower.txp_requested * 2),
                        ieee80211_get_tx_rate(ah->hw, info)->hw_value,
                        1, AR5K_TXKEYIX_INVALID,
                        antenna, flags, 0, 0);
@@ -2056,9 +2057,7 @@ ath5k_beacon_update_timers(struct ath5k_hw *ah, u64 bc_tsf)
 void
 ath5k_beacon_config(struct ath5k_hw *ah)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&ah->block, flags);
+       spin_lock_bh(&ah->block);
        ah->bmisscount = 0;
        ah->imask &= ~(AR5K_INT_BMISS | AR5K_INT_SWBA);
 
@@ -2085,7 +2084,7 @@ ath5k_beacon_config(struct ath5k_hw *ah)
 
        ath5k_hw_set_imr(ah, ah->imask);
        mmiowb();
-       spin_unlock_irqrestore(&ah->block, flags);
+       spin_unlock_bh(&ah->block);
 }
 
 static void ath5k_tasklet_beacon(unsigned long data)
index 260e7dc7f7512af8442f957e2b4e6b2985355237..384e67af73bcec369c3edc1dc3c83c5d9c7f4683 100644 (file)
@@ -207,8 +207,8 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed)
        }
 
        if ((changed & IEEE80211_CONF_CHANGE_POWER) &&
-       (ah->power_level != conf->power_level)) {
-               ah->power_level = conf->power_level;
+       (ah->ah_txpower.txp_requested != conf->power_level)) {
+               ah->ah_txpower.txp_requested = conf->power_level;
 
                /* Half dB steps */
                ath5k_hw_set_txpower_limit(ah, (conf->power_level * 2));
@@ -254,7 +254,6 @@ ath5k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
        struct ath5k_vif *avf = (void *)vif->drv_priv;
        struct ath5k_hw *ah = hw->priv;
        struct ath_common *common = ath5k_hw_common(ah);
-       unsigned long flags;
 
        mutex_lock(&ah->lock);
 
@@ -300,9 +299,9 @@ ath5k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
        }
 
        if (changes & BSS_CHANGED_BEACON) {
-               spin_lock_irqsave(&ah->block, flags);
+               spin_lock_bh(&ah->block);
                ath5k_beacon_update(hw, vif);
-               spin_unlock_irqrestore(&ah->block, flags);
+               spin_unlock_bh(&ah->block);
        }
 
        if (changes & BSS_CHANGED_BEACON_ENABLED)
index 8b71a2d947e0c9348c1e1b402b4d6092e4d0b587..01c90ed58453af446a76344b4d72558a6af702de 100644 (file)
@@ -3516,6 +3516,7 @@ ath5k_setup_rate_powertable(struct ath5k_hw *ah, u16 max_pwr,
 {
        unsigned int i;
        u16 *rates;
+       s16 rate_idx_scaled = 0;
 
        /* max_pwr is power level we got from driver/user in 0.5dB
         * units, switch to 0.25dB units so we can compare */
@@ -3562,20 +3563,32 @@ ath5k_setup_rate_powertable(struct ath5k_hw *ah, u16 max_pwr,
                for (i = 8; i <= 15; i++)
                        rates[i] -= ah->ah_txpower.txp_cck_ofdm_gainf_delta;
 
+       /* Save min/max and current tx power for this channel
+        * in 0.25dB units.
+        *
+        * Note: We use rates[0] for current tx power because
+        * it covers most of the rates, in most cases. It's our
+        * tx power limit and what the user expects to see. */
+       ah->ah_txpower.txp_min_pwr = 2 * rates[7];
+       ah->ah_txpower.txp_cur_pwr = 2 * rates[0];
+
+       /* Set max txpower for correct OFDM operation on all rates
+        * -that is the txpower for 54Mbit-, it's used for the PAPD
+        * gain probe and it's in 0.5dB units */
+       ah->ah_txpower.txp_ofdm = rates[7];
+
        /* Now that we have all rates setup use table offset to
         * match the power range set by user with the power indices
         * on PCDAC/PDADC table */
        for (i = 0; i < 16; i++) {
-               rates[i] += ah->ah_txpower.txp_offset;
+               rate_idx_scaled = rates[i] + ah->ah_txpower.txp_offset;
                /* Don't get out of bounds */
-               if (rates[i] > 63)
-                       rates[i] = 63;
+               if (rate_idx_scaled > 63)
+                       rate_idx_scaled = 63;
+               if (rate_idx_scaled < 0)
+                       rate_idx_scaled = 0;
+               rates[i] = rate_idx_scaled;
        }
-
-       /* Min/max in 0.25dB units */
-       ah->ah_txpower.txp_min_pwr = 2 * rates[7];
-       ah->ah_txpower.txp_cur_pwr = 2 * rates[0];
-       ah->ah_txpower.txp_ofdm = rates[7];
 }
 
 
@@ -3639,10 +3652,17 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
        if (!ah->ah_txpower.txp_setup ||
            (channel->hw_value != curr_channel->hw_value) ||
            (channel->center_freq != curr_channel->center_freq)) {
-               /* Reset TX power values */
+               /* Reset TX power values but preserve requested
+                * tx power from above */
+               int requested_txpower = ah->ah_txpower.txp_requested;
+
                memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower));
+
+               /* Restore TPC setting and requested tx power */
                ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER;
 
+               ah->ah_txpower.txp_requested = requested_txpower;
+
                /* Calculate the powertable */
                ret = ath5k_setup_channel_powertable(ah, channel,
                                                        ee_mode, type);
@@ -3789,8 +3809,9 @@ ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
         * RF buffer settings on 5211/5212+ so that we
         * properly set curve indices.
         */
-       ret = ath5k_hw_txpower(ah, channel, ah->ah_txpower.txp_cur_pwr ?
-                       ah->ah_txpower.txp_cur_pwr / 2 : AR5K_TUNE_MAX_TXPOWER);
+       ret = ath5k_hw_txpower(ah, channel, ah->ah_txpower.txp_requested ?
+                                       ah->ah_txpower.txp_requested * 2 :
+                                       AR5K_TUNE_MAX_TXPOWER);
        if (ret)
                return ret;
 
index 2588848f4a822a1bf879ce447f9f146c5e186873..c37fe9620e41ace5f906f58fe5729dc4b3daae28 100644 (file)
@@ -4901,90 +4901,79 @@ static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah,
                                i, cfgCtl, pCtlMode[ctlMode], ctlIndex[i],
                                chan->channel);
 
-                               /*
-                                * compare test group from regulatory
-                                * channel list with test mode from pCtlMode
-                                * list
-                                */
-                               if ((((cfgCtl & ~CTL_MODE_M) |
-                                      (pCtlMode[ctlMode] & CTL_MODE_M)) ==
-                                       ctlIndex[i]) ||
-                                   (((cfgCtl & ~CTL_MODE_M) |
-                                      (pCtlMode[ctlMode] & CTL_MODE_M)) ==
-                                    ((ctlIndex[i] & CTL_MODE_M) |
-                                      SD_NO_CTL))) {
-                                       twiceMinEdgePower =
-                                         ar9003_hw_get_max_edge_power(pEepData,
-                                                                      freq, i,
-                                                                      is2ghz);
-
-                                       if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL)
-                                               /*
-                                                * Find the minimum of all CTL
-                                                * edge powers that apply to
-                                                * this channel
-                                                */
-                                               twiceMaxEdgePower =
-                                                       min(twiceMaxEdgePower,
-                                                           twiceMinEdgePower);
-                                               else {
-                                                       /* specific */
-                                                       twiceMaxEdgePower =
-                                                         twiceMinEdgePower;
-                                                       break;
-                                               }
+                       /*
+                        * compare test group from regulatory
+                        * channel list with test mode from pCtlMode
+                        * list
+                        */
+                       if ((((cfgCtl & ~CTL_MODE_M) |
+                              (pCtlMode[ctlMode] & CTL_MODE_M)) ==
+                               ctlIndex[i]) ||
+                           (((cfgCtl & ~CTL_MODE_M) |
+                              (pCtlMode[ctlMode] & CTL_MODE_M)) ==
+                            ((ctlIndex[i] & CTL_MODE_M) |
+                              SD_NO_CTL))) {
+                               twiceMinEdgePower =
+                                 ar9003_hw_get_max_edge_power(pEepData,
+                                                              freq, i,
+                                                              is2ghz);
+
+                               if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL)
+                                       /*
+                                        * Find the minimum of all CTL
+                                        * edge powers that apply to
+                                        * this channel
+                                        */
+                                       twiceMaxEdgePower =
+                                               min(twiceMaxEdgePower,
+                                                   twiceMinEdgePower);
+                               else {
+                                       /* specific */
+                                       twiceMaxEdgePower = twiceMinEdgePower;
+                                       break;
                                }
                        }
+               }
 
-                       minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower);
+               minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower);
 
-                       ath_dbg(common, REGULATORY,
-                               "SEL-Min ctlMode %d pCtlMode %d 2xMaxEdge %d sP %d minCtlPwr %d\n",
-                               ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower,
-                               scaledPower, minCtlPower);
-
-                       /* Apply ctl mode to correct target power set */
-                       switch (pCtlMode[ctlMode]) {
-                       case CTL_11B:
-                               for (i = ALL_TARGET_LEGACY_1L_5L;
-                                    i <= ALL_TARGET_LEGACY_11S; i++)
-                                       pPwrArray[i] =
-                                         (u8)min((u16)pPwrArray[i],
-                                                 minCtlPower);
-                               break;
-                       case CTL_11A:
-                       case CTL_11G:
-                               for (i = ALL_TARGET_LEGACY_6_24;
-                                    i <= ALL_TARGET_LEGACY_54; i++)
-                                       pPwrArray[i] =
-                                         (u8)min((u16)pPwrArray[i],
-                                                 minCtlPower);
-                               break;
-                       case CTL_5GHT20:
-                       case CTL_2GHT20:
-                               for (i = ALL_TARGET_HT20_0_8_16;
-                                    i <= ALL_TARGET_HT20_21; i++)
-                                       pPwrArray[i] =
-                                         (u8)min((u16)pPwrArray[i],
-                                                 minCtlPower);
-                               pPwrArray[ALL_TARGET_HT20_22] =
-                                 (u8)min((u16)pPwrArray[ALL_TARGET_HT20_22],
-                                         minCtlPower);
-                               pPwrArray[ALL_TARGET_HT20_23] =
-                                 (u8)min((u16)pPwrArray[ALL_TARGET_HT20_23],
-                                          minCtlPower);
-                               break;
-                       case CTL_5GHT40:
-                       case CTL_2GHT40:
-                               for (i = ALL_TARGET_HT40_0_8_16;
-                                    i <= ALL_TARGET_HT40_23; i++)
-                                       pPwrArray[i] =
-                                         (u8)min((u16)pPwrArray[i],
-                                                 minCtlPower);
-                               break;
-                       default:
-                           break;
-                       }
+               ath_dbg(common, REGULATORY,
+                       "SEL-Min ctlMode %d pCtlMode %d 2xMaxEdge %d sP %d minCtlPwr %d\n",
+                       ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower,
+                       scaledPower, minCtlPower);
+
+               /* Apply ctl mode to correct target power set */
+               switch (pCtlMode[ctlMode]) {
+               case CTL_11B:
+                       for (i = ALL_TARGET_LEGACY_1L_5L;
+                            i <= ALL_TARGET_LEGACY_11S; i++)
+                               pPwrArray[i] = (u8)min((u16)pPwrArray[i],
+                                                      minCtlPower);
+                       break;
+               case CTL_11A:
+               case CTL_11G:
+                       for (i = ALL_TARGET_LEGACY_6_24;
+                            i <= ALL_TARGET_LEGACY_54; i++)
+                               pPwrArray[i] = (u8)min((u16)pPwrArray[i],
+                                                      minCtlPower);
+                       break;
+               case CTL_5GHT20:
+               case CTL_2GHT20:
+                       for (i = ALL_TARGET_HT20_0_8_16;
+                            i <= ALL_TARGET_HT20_23; i++)
+                               pPwrArray[i] = (u8)min((u16)pPwrArray[i],
+                                                      minCtlPower);
+                       break;
+               case CTL_5GHT40:
+               case CTL_2GHT40:
+                       for (i = ALL_TARGET_HT40_0_8_16;
+                            i <= ALL_TARGET_HT40_23; i++)
+                               pPwrArray[i] = (u8)min((u16)pPwrArray[i],
+                                                      minCtlPower);
+                       break;
+               default:
+                       break;
+               }
        } /* end ctl mode checking */
 }
 
index cfa91ab7acf8b1fd7c4b29fab82cb812f6423d5d..60b6a9daff7e21cde68fb6eda800e4ca065c62aa 100644 (file)
@@ -730,6 +730,7 @@ int ath9k_hw_init(struct ath_hw *ah)
        case AR9300_DEVID_QCA955X:
        case AR9300_DEVID_AR9580:
        case AR9300_DEVID_AR9462:
+       case AR9485_DEVID_AR1111:
                break;
        default:
                if (common->bus_ops->ath_bus_type == ATH_USB)
index dd0c146d81dccd77d1d735db888884be6227c782..ce7332c64efb2c5b417cd40fec2428522186142a 100644 (file)
@@ -49,6 +49,7 @@
 #define AR9300_DEVID_AR9462    0x0034
 #define AR9300_DEVID_AR9330    0x0035
 #define AR9300_DEVID_QCA955X   0x0038
+#define AR9485_DEVID_AR1111    0x0037
 
 #define AR5416_AR9100_DEVID    0x000b
 
index 7990cd55599cd319a51537ed0ad1981b6edf9a4b..b42be910a83dc94845fa6be33370357b18416e2f 100644 (file)
@@ -773,15 +773,10 @@ bool ath9k_hw_intrpend(struct ath_hw *ah)
 }
 EXPORT_SYMBOL(ath9k_hw_intrpend);
 
-void ath9k_hw_disable_interrupts(struct ath_hw *ah)
+void ath9k_hw_kill_interrupts(struct ath_hw *ah)
 {
        struct ath_common *common = ath9k_hw_common(ah);
 
-       if (!(ah->imask & ATH9K_INT_GLOBAL))
-               atomic_set(&ah->intr_ref_cnt, -1);
-       else
-               atomic_dec(&ah->intr_ref_cnt);
-
        ath_dbg(common, INTERRUPT, "disable IER\n");
        REG_WRITE(ah, AR_IER, AR_IER_DISABLE);
        (void) REG_READ(ah, AR_IER);
@@ -793,6 +788,17 @@ void ath9k_hw_disable_interrupts(struct ath_hw *ah)
                (void) REG_READ(ah, AR_INTR_SYNC_ENABLE);
        }
 }
+EXPORT_SYMBOL(ath9k_hw_kill_interrupts);
+
+void ath9k_hw_disable_interrupts(struct ath_hw *ah)
+{
+       if (!(ah->imask & ATH9K_INT_GLOBAL))
+               atomic_set(&ah->intr_ref_cnt, -1);
+       else
+               atomic_dec(&ah->intr_ref_cnt);
+
+       ath9k_hw_kill_interrupts(ah);
+}
 EXPORT_SYMBOL(ath9k_hw_disable_interrupts);
 
 void ath9k_hw_enable_interrupts(struct ath_hw *ah)
index 0eba36dca6f8fe897dcbbdc56cd0318af46f4fba..4a745e68dd941d9351e4fe911b47d76ec288551d 100644 (file)
@@ -738,6 +738,7 @@ bool ath9k_hw_intrpend(struct ath_hw *ah);
 void ath9k_hw_set_interrupts(struct ath_hw *ah);
 void ath9k_hw_enable_interrupts(struct ath_hw *ah);
 void ath9k_hw_disable_interrupts(struct ath_hw *ah);
+void ath9k_hw_kill_interrupts(struct ath_hw *ah);
 
 void ar9002_hw_attach_mac_ops(struct ath_hw *ah);
 
index 6049d8b82855a7542192b247657e58964fc9f496..a22df749b8db3d8641b4ef8cb78ad99b9e34adbb 100644 (file)
@@ -462,8 +462,10 @@ irqreturn_t ath_isr(int irq, void *dev)
        if (!ath9k_hw_intrpend(ah))
                return IRQ_NONE;
 
-       if(test_bit(SC_OP_HW_RESET, &sc->sc_flags))
+       if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) {
+               ath9k_hw_kill_interrupts(ah);
                return IRQ_HANDLED;
+       }
 
        /*
         * Figure out the reason(s) for the interrupt.  Note
index 87b89d55e637758febf06629599ebe9e60478b85..a978984d78a53e93b5148ed54271deedf7b1d25c 100644 (file)
@@ -37,6 +37,7 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
        { PCI_VDEVICE(ATHEROS, 0x0032) }, /* PCI-E  AR9485 */
        { PCI_VDEVICE(ATHEROS, 0x0033) }, /* PCI-E  AR9580 */
        { PCI_VDEVICE(ATHEROS, 0x0034) }, /* PCI-E  AR9462 */
+       { PCI_VDEVICE(ATHEROS, 0x0037) }, /* PCI-E  AR1111/AR9485 */
        { 0 }
 };
 
@@ -320,6 +321,7 @@ static int ath_pci_suspend(struct device *device)
         * Otherwise the chip never moved to full sleep,
         * when no interface is up.
         */
+       ath9k_stop_btcoex(sc);
        ath9k_hw_disable(sc->sc_ah);
        ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_FULL_SLEEP);
 
index e034add9cd5a478a2dd085f5133a18898913b932..4b12c347d18828714484890539c99a81cec2a709 100644 (file)
@@ -25,141 +25,141 @@ static const struct ath_rate_table ar5416_11na_ratetable = {
        8, /* MCS start */
        {
                [0] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 6000,
-                       5400, 0, 12, 0, 0, 0, 0 }, /* 6 Mb */
+                       5400, 0, 12 }, /* 6 Mb */
                [1] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 9000,
-                       7800,  1, 18, 0, 1, 1, 1 }, /* 9 Mb */
+                       7800,  1, 18 }, /* 9 Mb */
                [2] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 12000,
-                       10000, 2, 24, 2, 2, 2, 2 }, /* 12 Mb */
+                       10000, 2, 24 }, /* 12 Mb */
                [3] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 18000,
-                       13900, 3, 36, 2, 3, 3, 3 }, /* 18 Mb */
+                       13900, 3, 36 }, /* 18 Mb */
                [4] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 24000,
-                       17300, 4, 48, 4, 4, 4, 4 }, /* 24 Mb */
+                       17300, 4, 48 }, /* 24 Mb */
                [5] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 36000,
-                       23000, 5, 72, 4, 5, 5, 5 }, /* 36 Mb */
+                       23000, 5, 72 }, /* 36 Mb */
                [6] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 48000,
-                       27400, 6, 96, 4, 6, 6, 6 }, /* 48 Mb */
+                       27400, 6, 96 }, /* 48 Mb */
                [7] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 54000,
-                       29300, 7, 108, 4, 7, 7, 7 }, /* 54 Mb */
+                       29300, 7, 108 }, /* 54 Mb */
                [8] = { RC_HT_SDT_2040, WLAN_RC_PHY_HT_20_SS, 6500,
-                       6400, 0, 0, 0, 38, 8, 38 }, /* 6.5 Mb */
+                       6400, 0, 0 }, /* 6.5 Mb */
                [9] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 13000,
-                       12700, 1, 1, 2, 39, 9, 39 }, /* 13 Mb */
+                       12700, 1, 1 }, /* 13 Mb */
                [10] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 19500,
-                       18800, 2, 2, 2, 40, 10, 40 }, /* 19.5 Mb */
+                       18800, 2, 2 }, /* 19.5 Mb */
                [11] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 26000,
-                       25000, 3, 3, 4, 41, 11, 41 }, /* 26 Mb */
+                       25000, 3, 3 }, /* 26 Mb */
                [12] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 39000,
-                       36700, 4, 4, 4, 42, 12, 42 }, /* 39 Mb */
+                       36700, 4, 4 }, /* 39 Mb */
                [13] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 52000,
-                       48100, 5, 5, 4, 43, 13, 43 }, /* 52 Mb */
+                       48100, 5, 5 }, /* 52 Mb */
                [14] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 58500,
-                       53500, 6, 6, 4, 44, 14, 44 }, /* 58.5 Mb */
+                       53500, 6, 6 }, /* 58.5 Mb */
                [15] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 65000,
-                       59000, 7, 7, 4, 45, 16, 46 }, /* 65 Mb */
+                       59000, 7, 7 }, /* 65 Mb */
                [16] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS_HGI, 72200,
-                       65400, 7, 7, 4, 45, 16, 46 }, /* 75 Mb */
+                       65400, 7, 7 }, /* 75 Mb */
                [17] = { RC_INVALID, WLAN_RC_PHY_HT_20_DS, 13000,
-                       12700, 8, 8, 0, 47, 17, 47 }, /* 13 Mb */
+                       12700, 8, 8 }, /* 13 Mb */
                [18] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 26000,
-                       24800, 9, 9, 2, 48, 18, 48 }, /* 26 Mb */
+                       24800, 9, 9 }, /* 26 Mb */
                [19] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 39000,
-                       36600, 10, 10, 2, 49, 19, 49 }, /* 39 Mb */
+                       36600, 10, 10 }, /* 39 Mb */
                [20] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 52000,
-                       48100, 11, 11, 4, 50, 20, 50 }, /* 52 Mb */
+                       48100, 11, 11 }, /* 52 Mb */
                [21] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 78000,
-                       69500, 12, 12, 4, 51, 21, 51 }, /* 78 Mb */
+                       69500, 12, 12 }, /* 78 Mb */
                [22] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 104000,
-                       89500, 13, 13, 4, 52, 22, 52 }, /* 104 Mb */
+                       89500, 13, 13 }, /* 104 Mb */
                [23] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 117000,
-                       98900, 14, 14, 4, 53, 23, 53 }, /* 117 Mb */
+                       98900, 14, 14 }, /* 117 Mb */
                [24] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 130000,
-                       108300, 15, 15, 4, 54, 25, 55 }, /* 130 Mb */
+                       108300, 15, 15 }, /* 130 Mb */
                [25] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS_HGI, 144400,
-                       120000, 15, 15, 4, 54, 25, 55 }, /* 144.4 Mb */
+                       120000, 15, 15 }, /* 144.4 Mb */
                [26] = {  RC_INVALID, WLAN_RC_PHY_HT_20_TS, 19500,
-                       17400, 16, 16, 0, 56, 26, 56 }, /* 19.5 Mb */
+                       17400, 16, 16 }, /* 19.5 Mb */
                [27] = {  RC_INVALID, WLAN_RC_PHY_HT_20_TS, 39000,
-                       35100, 17, 17, 2, 57, 27, 57 }, /* 39 Mb */
+                       35100, 17, 17 }, /* 39 Mb */
                [28] = {  RC_INVALID, WLAN_RC_PHY_HT_20_TS, 58500,
-                       52600, 18, 18, 2, 58, 28, 58 }, /* 58.5 Mb */
+                       52600, 18, 18 }, /* 58.5 Mb */
                [29] = {  RC_INVALID, WLAN_RC_PHY_HT_20_TS, 78000,
-                       70400, 19, 19, 4, 59, 29, 59 }, /* 78 Mb */
+                       70400, 19, 19 }, /* 78 Mb */
                [30] = {  RC_INVALID, WLAN_RC_PHY_HT_20_TS, 117000,
-                       104900, 20, 20, 4, 60, 31, 61 }, /* 117 Mb */
+                       104900, 20, 20 }, /* 117 Mb */
                [31] = {  RC_INVALID, WLAN_RC_PHY_HT_20_TS_HGI, 130000,
-                       115800, 20, 20, 4, 60, 31, 61 }, /* 130 Mb*/
+                       115800, 20, 20 }, /* 130 Mb*/
                [32] = {  RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 156000,
-                       137200, 21, 21, 4, 62, 33, 63 }, /* 156 Mb */
+                       137200, 21, 21 }, /* 156 Mb */
                [33] = {  RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 173300,
-                       151100, 21, 21, 4, 62, 33, 63 }, /* 173.3 Mb */
+                       151100, 21, 21 }, /* 173.3 Mb */
                [34] = {  RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 175500,
-                       152800, 22, 22, 4, 64, 35, 65 }, /* 175.5 Mb */
+                       152800, 22, 22 }, /* 175.5 Mb */
                [35] = {  RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 195000,
-                       168400, 22, 22, 4, 64, 35, 65 }, /* 195 Mb*/
+                       168400, 22, 22 }, /* 195 Mb*/
                [36] = {  RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 195000,
-                       168400, 23, 23, 4, 66, 37, 67 }, /* 195 Mb */
+                       168400, 23, 23 }, /* 195 Mb */
                [37] = {  RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 216700,
-                       185000, 23, 23, 4, 66, 37, 67 }, /* 216.7 Mb */
+                       185000, 23, 23 }, /* 216.7 Mb */
                [38] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 13500,
-                       13200, 0, 0, 0, 38, 38, 38 }, /* 13.5 Mb*/
+                       13200, 0, 0 }, /* 13.5 Mb*/
                [39] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 27500,
-                       25900, 1, 1, 2, 39, 39, 39 }, /* 27.0 Mb*/
+                       25900, 1, 1 }, /* 27.0 Mb*/
                [40] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 40500,
-                       38600, 2, 2, 2, 40, 40, 40 }, /* 40.5 Mb*/
+                       38600, 2, 2 }, /* 40.5 Mb*/
                [41] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 54000,
-                       49800, 3, 3, 4, 41, 41, 41 }, /* 54 Mb */
+                       49800, 3, 3 }, /* 54 Mb */
                [42] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 81500,
-                       72200, 4, 4, 4, 42, 42, 42 }, /* 81 Mb */
+                       72200, 4, 4 }, /* 81 Mb */
                [43] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 108000,
-                       92900, 5, 5, 4, 43, 43, 43 }, /* 108 Mb */
+                       92900, 5, 5 }, /* 108 Mb */
                [44] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 121500,
-                       102700, 6, 6, 4, 44, 44, 44 }, /* 121.5 Mb*/
+                       102700, 6, 6 }, /* 121.5 Mb*/
                [45] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 135000,
-                       112000, 7, 7, 4, 45, 46, 46 }, /* 135 Mb */
+                       112000, 7, 7 }, /* 135 Mb */
                [46] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000,
-                       122000, 7, 7, 4, 45, 46, 46 }, /* 150 Mb */
+                       122000, 7, 7 }, /* 150 Mb */
                [47] = { RC_INVALID, WLAN_RC_PHY_HT_40_DS, 27000,
-                       25800, 8, 8, 0, 47, 47, 47 }, /* 27 Mb */
+                       25800, 8, 8 }, /* 27 Mb */
                [48] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 54000,
-                       49800, 9, 9, 2, 48, 48, 48 }, /* 54 Mb */
+                       49800, 9, 9 }, /* 54 Mb */
                [49] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 81000,
-                       71900, 10, 10, 2, 49, 49, 49 }, /* 81 Mb */
+                       71900, 10, 10 }, /* 81 Mb */
                [50] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 108000,
-                       92500, 11, 11, 4, 50, 50, 50 }, /* 108 Mb */
+                       92500, 11, 11 }, /* 108 Mb */
                [51] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 162000,
-                       130300, 12, 12, 4, 51, 51, 51 }, /* 162 Mb */
+                       130300, 12, 12 }, /* 162 Mb */
                [52] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 216000,
-                       162800, 13, 13, 4, 52, 52, 52 }, /* 216 Mb */
+                       162800, 13, 13 }, /* 216 Mb */
                [53] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 243000,
-                       178200, 14, 14, 4, 53, 53, 53 }, /* 243 Mb */
+                       178200, 14, 14 }, /* 243 Mb */
                [54] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 270000,
-                       192100, 15, 15, 4, 54, 55, 55 }, /* 270 Mb */
+                       192100, 15, 15 }, /* 270 Mb */
                [55] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS_HGI, 300000,
-                       207000, 15, 15, 4, 54, 55, 55 }, /* 300 Mb */
+                       207000, 15, 15 }, /* 300 Mb */
                [56] = {  RC_INVALID, WLAN_RC_PHY_HT_40_TS, 40500,
-                       36100, 16, 16, 0, 56, 56, 56 }, /* 40.5 Mb */
+                       36100, 16, 16 }, /* 40.5 Mb */
                [57] = {  RC_INVALID, WLAN_RC_PHY_HT_40_TS, 81000,
-                       72900, 17, 17, 2, 57, 57, 57 }, /* 81 Mb */
+                       72900, 17, 17 }, /* 81 Mb */
                [58] = {  RC_INVALID, WLAN_RC_PHY_HT_40_TS, 121500,
-                       108300, 18, 18, 2, 58, 58, 58 }, /* 121.5 Mb */
+                       108300, 18, 18 }, /* 121.5 Mb */
                [59] = {  RC_INVALID, WLAN_RC_PHY_HT_40_TS, 162000,
-                       142000, 19, 19, 4, 59, 59, 59 }, /*  162 Mb */
+                       142000, 19, 19 }, /*  162 Mb */
                [60] = {  RC_INVALID, WLAN_RC_PHY_HT_40_TS, 243000,
-                       205100, 20, 20, 4, 60, 61, 61 }, /*  243 Mb */
+                       205100, 20, 20 }, /*  243 Mb */
                [61] = {  RC_INVALID, WLAN_RC_PHY_HT_40_TS_HGI, 270000,
-                       224700, 20, 20, 4, 60, 61, 61 }, /*  270 Mb */
+                       224700, 20, 20 }, /*  270 Mb */
                [62] = {  RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 324000,
-                       263100, 21, 21, 4, 62, 63, 63 }, /*  324 Mb */
+                       263100, 21, 21 }, /*  324 Mb */
                [63] = {  RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 360000,
-                       288000, 21, 21, 4, 62, 63, 63 }, /*  360 Mb */
+                       288000, 21, 21 }, /*  360 Mb */
                [64] = {  RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 364500,
-                       290700, 22, 22, 4, 64, 65, 65 }, /* 364.5 Mb */
+                       290700, 22, 22 }, /* 364.5 Mb */
                [65] = {  RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 405000,
-                       317200, 22, 22, 4, 64, 65, 65 }, /* 405 Mb */
+                       317200, 22, 22 }, /* 405 Mb */
                [66] = {  RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 405000,
-                       317200, 23, 23, 4, 66, 67, 67 }, /* 405 Mb */
+                       317200, 23, 23 }, /* 405 Mb */
                [67] = {  RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 450000,
-                       346400, 23, 23, 4, 66, 67, 67 }, /* 450 Mb */
+                       346400, 23, 23 }, /* 450 Mb */
        },
        50,  /* probe interval */
        WLAN_RC_HT_FLAG,  /* Phy rates allowed initially */
@@ -173,149 +173,149 @@ static const struct ath_rate_table ar5416_11ng_ratetable = {
        12, /* MCS start */
        {
                [0] = { RC_ALL, WLAN_RC_PHY_CCK, 1000,
-                       900, 0, 2, 0, 0, 0, 0 }, /* 1 Mb */
+                       900, 0, 2 }, /* 1 Mb */
                [1] = { RC_ALL, WLAN_RC_PHY_CCK, 2000,
-                       1900, 1, 4, 1, 1, 1, 1 }, /* 2 Mb */
+                       1900, 1, 4 }, /* 2 Mb */
                [2] = { RC_ALL, WLAN_RC_PHY_CCK, 5500,
-                       4900, 2, 11, 2, 2, 2, 2 }, /* 5.5 Mb */
+                       4900, 2, 11 }, /* 5.5 Mb */
                [3] = { RC_ALL, WLAN_RC_PHY_CCK, 11000,
-                       8100, 3, 22, 3, 3, 3, 3 }, /* 11 Mb */
+                       8100, 3, 22 }, /* 11 Mb */
                [4] = { RC_INVALID, WLAN_RC_PHY_OFDM, 6000,
-                       5400, 4, 12, 4, 4, 4, 4 }, /* 6 Mb */
+                       5400, 4, 12 }, /* 6 Mb */
                [5] = { RC_INVALID, WLAN_RC_PHY_OFDM, 9000,
-                       7800, 5, 18, 4, 5, 5, 5 }, /* 9 Mb */
+                       7800, 5, 18 }, /* 9 Mb */
                [6] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 12000,
-                       10100, 6, 24, 6, 6, 6, 6 }, /* 12 Mb */
+                       10100, 6, 24 }, /* 12 Mb */
                [7] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 18000,
-                       14100, 7, 36, 6, 7, 7, 7 }, /* 18 Mb */
+                       14100, 7, 36 }, /* 18 Mb */
                [8] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 24000,
-                       17700, 8, 48, 8, 8, 8, 8 }, /* 24 Mb */
+                       17700, 8, 48 }, /* 24 Mb */
                [9] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 36000,
-                       23700, 9, 72, 8, 9, 9, 9 }, /* 36 Mb */
+                       23700, 9, 72 }, /* 36 Mb */
                [10] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 48000,
-                       27400, 10, 96, 8, 10, 10, 10 }, /* 48 Mb */
+                       27400, 10, 96 }, /* 48 Mb */
                [11] = { RC_L_SDT, WLAN_RC_PHY_OFDM, 54000,
-                       30900, 11, 108, 8, 11, 11, 11 }, /* 54 Mb */
+                       30900, 11, 108 }, /* 54 Mb */
                [12] = { RC_INVALID, WLAN_RC_PHY_HT_20_SS, 6500,
-                       6400, 0, 0, 4, 42, 12, 42 }, /* 6.5 Mb */
+                       6400, 0, 0 }, /* 6.5 Mb */
                [13] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 13000,
-                       12700, 1, 1, 6, 43, 13, 43 }, /* 13 Mb */
+                       12700, 1, 1 }, /* 13 Mb */
                [14] = { RC_HT_SDT_20, WLAN_RC_PHY_HT_20_SS, 19500,
-                       18800, 2, 2, 6, 44, 14, 44 }, /* 19.5 Mb*/
+                       18800, 2, 2 }, /* 19.5 Mb*/
                [15] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 26000,
-                       25000, 3, 3, 8, 45, 15, 45 }, /* 26 Mb */
+                       25000, 3, 3 }, /* 26 Mb */
                [16] = { RC_HT_SD_20, WLAN_RC_PHY_HT_20_SS, 39000,
-                       36700, 4, 4, 8, 46, 16, 46 }, /* 39 Mb */
+                       36700, 4, 4 }, /* 39 Mb */
                [17] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 52000,
-                       48100, 5, 5, 8, 47, 17, 47 }, /* 52 Mb */
+                       48100, 5, 5 }, /* 52 Mb */
                [18] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 58500,
-                       53500, 6, 6, 8, 48, 18, 48 }, /* 58.5 Mb */
+                       53500, 6, 6 }, /* 58.5 Mb */
                [19] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS, 65000,
-                       59000, 7, 7, 8, 49, 20, 50 }, /* 65 Mb */
+                       59000, 7, 7 }, /* 65 Mb */
                [20] = { RC_HT_S_20, WLAN_RC_PHY_HT_20_SS_HGI, 72200,
-                       65400, 7, 7, 8, 49, 20, 50 }, /* 65 Mb*/
+                       65400, 7, 7 }, /* 65 Mb*/
                [21] = { RC_INVALID, WLAN_RC_PHY_HT_20_DS, 13000,
-                       12700, 8, 8, 4, 51, 21, 51 }, /* 13 Mb */
+                       12700, 8, 8 }, /* 13 Mb */
                [22] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 26000,
-                       24800, 9, 9, 6, 52, 22, 52 }, /* 26 Mb */
+                       24800, 9, 9 }, /* 26 Mb */
                [23] = { RC_HT_T_20, WLAN_RC_PHY_HT_20_DS, 39000,
-                       36600, 10, 10, 6, 53, 23, 53 }, /* 39 Mb */
+                       36600, 10, 10 }, /* 39 Mb */
                [24] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 52000,
-                       48100, 11, 11, 8, 54, 24, 54 }, /* 52 Mb */
+                       48100, 11, 11 }, /* 52 Mb */
                [25] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 78000,
-                       69500, 12, 12, 8, 55, 25, 55 }, /* 78 Mb */
+                       69500, 12, 12 }, /* 78 Mb */
                [26] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 104000,
-                       89500, 13, 13, 8, 56, 26, 56 }, /* 104 Mb */
+                       89500, 13, 13 }, /* 104 Mb */
                [27] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 117000,
-                       98900, 14, 14, 8, 57, 27, 57 }, /* 117 Mb */
+                       98900, 14, 14 }, /* 117 Mb */
                [28] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS, 130000,
-                       108300, 15, 15, 8, 58, 29, 59 }, /* 130 Mb */
+                       108300, 15, 15 }, /* 130 Mb */
                [29] = { RC_HT_DT_20, WLAN_RC_PHY_HT_20_DS_HGI, 144400,
-                       120000, 15, 15, 8, 58, 29, 59 }, /* 144.4 Mb */
+                       120000, 15, 15 }, /* 144.4 Mb */
                [30] = {  RC_INVALID, WLAN_RC_PHY_HT_20_TS, 19500,
-                       17400, 16, 16, 4, 60, 30, 60 }, /* 19.5 Mb */
+                       17400, 16, 16 }, /* 19.5 Mb */
                [31] = {  RC_INVALID, WLAN_RC_PHY_HT_20_TS, 39000,
-                       35100, 17, 17, 6, 61, 31, 61 }, /* 39 Mb */
+                       35100, 17, 17 }, /* 39 Mb */
                [32] = {  RC_INVALID, WLAN_RC_PHY_HT_20_TS, 58500,
-                       52600, 18, 18, 6, 62, 32, 62 }, /* 58.5 Mb */
+                       52600, 18, 18 }, /* 58.5 Mb */
                [33] = {  RC_INVALID, WLAN_RC_PHY_HT_20_TS, 78000,
-                       70400, 19, 19, 8, 63, 33, 63 }, /* 78 Mb */
+                       70400, 19, 19 }, /* 78 Mb */
                [34] = {  RC_INVALID, WLAN_RC_PHY_HT_20_TS, 117000,
-                       104900, 20, 20, 8, 64, 35, 65 }, /* 117 Mb */
+                       104900, 20, 20 }, /* 117 Mb */
                [35] = {  RC_INVALID, WLAN_RC_PHY_HT_20_TS_HGI, 130000,
-                       115800, 20, 20, 8, 64, 35, 65 }, /* 130 Mb */
+                       115800, 20, 20 }, /* 130 Mb */
                [36] = {  RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 156000,
-                       137200, 21, 21, 8, 66, 37, 67 }, /* 156 Mb */
+                       137200, 21, 21 }, /* 156 Mb */
                [37] = {  RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 173300,
-                       151100, 21, 21, 8, 66, 37, 67 }, /* 173.3 Mb */
+                       151100, 21, 21 }, /* 173.3 Mb */
                [38] = {  RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 175500,
-                       152800, 22, 22, 8, 68, 39, 69 }, /* 175.5 Mb */
+                       152800, 22, 22 }, /* 175.5 Mb */
                [39] = {  RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 195000,
-                       168400, 22, 22, 8, 68, 39, 69 }, /* 195 Mb */
+                       168400, 22, 22 }, /* 195 Mb */
                [40] = {  RC_HT_T_20, WLAN_RC_PHY_HT_20_TS, 195000,
-                       168400, 23, 23, 8, 70, 41, 71 }, /* 195 Mb */
+                       168400, 23, 23 }, /* 195 Mb */
                [41] = {  RC_HT_T_20, WLAN_RC_PHY_HT_20_TS_HGI, 216700,
-                       185000, 23, 23, 8, 70, 41, 71 }, /* 216.7 Mb */
+                       185000, 23, 23 }, /* 216.7 Mb */
                [42] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 13500,
-                       13200, 0, 0, 8, 42, 42, 42 }, /* 13.5 Mb */
+                       13200, 0, 0 }, /* 13.5 Mb */
                [43] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 27500,
-                       25900, 1, 1, 8, 43, 43, 43 }, /* 27.0 Mb */
+                       25900, 1, 1 }, /* 27.0 Mb */
                [44] = { RC_HT_SDT_40, WLAN_RC_PHY_HT_40_SS, 40500,
-                       38600, 2, 2, 8, 44, 44, 44 }, /* 40.5 Mb */
+                       38600, 2, 2 }, /* 40.5 Mb */
                [45] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 54000,
-                       49800, 3, 3, 8, 45, 45, 45 }, /* 54 Mb */
+                       49800, 3, 3 }, /* 54 Mb */
                [46] = { RC_HT_SD_40, WLAN_RC_PHY_HT_40_SS, 81500,
-                       72200, 4, 4, 8, 46, 46, 46 }, /* 81 Mb */
+                       72200, 4, 4 }, /* 81 Mb */
                [47] = { RC_HT_S_40 , WLAN_RC_PHY_HT_40_SS, 108000,
-                       92900, 5, 5, 8, 47, 47, 47 }, /* 108 Mb */
+                       92900, 5, 5 }, /* 108 Mb */
                [48] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 121500,
-                       102700, 6, 6, 8, 48, 48, 48 }, /* 121.5 Mb */
+                       102700, 6, 6 }, /* 121.5 Mb */
                [49] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS, 135000,
-                       112000, 7, 7, 8, 49, 50, 50 }, /* 135 Mb */
+                       112000, 7, 7 }, /* 135 Mb */
                [50] = { RC_HT_S_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000,
-                       122000, 7, 7, 8, 49, 50, 50 }, /* 150 Mb */
+                       122000, 7, 7 }, /* 150 Mb */
                [51] = { RC_INVALID, WLAN_RC_PHY_HT_40_DS, 27000,
-                       25800, 8, 8, 8, 51, 51, 51 }, /* 27 Mb */
+                       25800, 8, 8 }, /* 27 Mb */
                [52] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 54000,
-                       49800, 9, 9, 8, 52, 52, 52 }, /* 54 Mb */
+                       49800, 9, 9 }, /* 54 Mb */
                [53] = { RC_HT_T_40, WLAN_RC_PHY_HT_40_DS, 81000,
-                       71900, 10, 10, 8, 53, 53, 53 }, /* 81 Mb */
+                       71900, 10, 10 }, /* 81 Mb */
                [54] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 108000,
-                       92500, 11, 11, 8, 54, 54, 54 }, /* 108 Mb */
+                       92500, 11, 11 }, /* 108 Mb */
                [55] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 162000,
-                       130300, 12, 12, 8, 55, 55, 55 }, /* 162 Mb */
+                       130300, 12, 12 }, /* 162 Mb */
                [56] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 216000,
-                       162800, 13, 13, 8, 56, 56, 56 }, /* 216 Mb */
+                       162800, 13, 13 }, /* 216 Mb */
                [57] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 243000,
-                       178200, 14, 14, 8, 57, 57, 57 }, /* 243 Mb */
+                       178200, 14, 14 }, /* 243 Mb */
                [58] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS, 270000,
-                       192100, 15, 15, 8, 58, 59, 59 }, /* 270 Mb */
+                       192100, 15, 15 }, /* 270 Mb */
                [59] = { RC_HT_DT_40, WLAN_RC_PHY_HT_40_DS_HGI, 300000,
-                       207000, 15, 15, 8, 58, 59, 59 }, /* 300 Mb */
+                       207000, 15, 15 }, /* 300 Mb */
                [60] = {  RC_INVALID, WLAN_RC_PHY_HT_40_TS, 40500,
-                       36100, 16, 16, 8, 60, 60, 60 }, /* 40.5 Mb */
+                       36100, 16, 16 }, /* 40.5 Mb */
                [61] = {  RC_INVALID, WLAN_RC_PHY_HT_40_TS, 81000,
-                       72900, 17, 17, 8, 61, 61, 61 }, /* 81 Mb */
+                       72900, 17, 17 }, /* 81 Mb */
                [62] = {  RC_INVALID, WLAN_RC_PHY_HT_40_TS, 121500,
-                       108300, 18, 18, 8, 62, 62, 62 }, /* 121.5 Mb */
+                       108300, 18, 18 }, /* 121.5 Mb */
                [63] = {  RC_INVALID, WLAN_RC_PHY_HT_40_TS, 162000,
-                       142000, 19, 19, 8, 63, 63, 63 }, /* 162 Mb */
+                       142000, 19, 19 }, /* 162 Mb */
                [64] = {  RC_INVALID, WLAN_RC_PHY_HT_40_TS, 243000,
-                       205100, 20, 20, 8, 64, 65, 65 }, /* 243 Mb */
+                       205100, 20, 20 }, /* 243 Mb */
                [65] = {  RC_INVALID, WLAN_RC_PHY_HT_40_TS_HGI, 270000,
-                       224700, 20, 20, 8, 64, 65, 65 }, /* 270 Mb */
+                       224700, 20, 20 }, /* 270 Mb */
                [66] = {  RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 324000,
-                       263100, 21, 21, 8, 66, 67, 67 }, /* 324 Mb */
+                       263100, 21, 21 }, /* 324 Mb */
                [67] = {  RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 360000,
-                       288000, 21, 21, 8, 66, 67, 67 }, /* 360 Mb */
+                       288000, 21, 21 }, /* 360 Mb */
                [68] = {  RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 364500,
-                       290700, 22, 22, 8, 68, 69, 69 }, /* 364.5 Mb */
+                       290700, 22, 22 }, /* 364.5 Mb */
                [69] = {  RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 405000,
-                       317200, 22, 22, 8, 68, 69, 69 }, /* 405 Mb */
+                       317200, 22, 22 }, /* 405 Mb */
                [70] = {  RC_HT_T_40, WLAN_RC_PHY_HT_40_TS, 405000,
-                       317200, 23, 23, 8, 70, 71, 71 }, /* 405 Mb */
+                       317200, 23, 23 }, /* 405 Mb */
                [71] = {  RC_HT_T_40, WLAN_RC_PHY_HT_40_TS_HGI, 450000,
-                       346400, 23, 23, 8, 70, 71, 71 }, /* 450 Mb */
+                       346400, 23, 23 }, /* 450 Mb */
        },
        50,  /* probe interval */
        WLAN_RC_HT_FLAG,  /* Phy rates allowed initially */
@@ -326,21 +326,21 @@ static const struct ath_rate_table ar5416_11a_ratetable = {
        0,
        {
                { RC_L_SDT, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
-                       5400, 0, 12, 0},
+                       5400, 0, 12},
                { RC_L_SDT, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
-                       7800,  1, 18, 0},
+                       7800,  1, 18},
                { RC_L_SDT, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
-                       10000, 2, 24, 2},
+                       10000, 2, 24},
                { RC_L_SDT, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
-                       13900, 3, 36, 2},
+                       13900, 3, 36},
                { RC_L_SDT, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
-                       17300, 4, 48, 4},
+                       17300, 4, 48},
                { RC_L_SDT, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
-                       23000, 5, 72, 4},
+                       23000, 5, 72},
                { RC_L_SDT, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
-                       27400, 6, 96, 4},
+                       27400, 6, 96},
                { RC_L_SDT, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
-                       29300, 7, 108, 4},
+                       29300, 7, 108},
        },
        50,  /* probe interval */
        0,   /* Phy rates allowed initially */
@@ -351,63 +351,62 @@ static const struct ath_rate_table ar5416_11g_ratetable = {
        0,
        {
                { RC_L_SDT, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */
-                       900, 0, 2, 0},
+                       900, 0, 2},
                { RC_L_SDT, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */
-                       1900, 1, 4, 1},
+                       1900, 1, 4},
                { RC_L_SDT, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */
-                       4900, 2, 11, 2},
+                       4900, 2, 11},
                { RC_L_SDT, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */
-                       8100, 3, 22, 3},
+                       8100, 3, 22},
                { RC_INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */
-                       5400, 4, 12, 4},
+                       5400, 4, 12},
                { RC_INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */
-                       7800, 5, 18, 4},
+                       7800, 5, 18},
                { RC_L_SDT, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */
-                       10000, 6, 24, 6},
+                       10000, 6, 24},
                { RC_L_SDT, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */
-                       13900, 7, 36, 6},
+                       13900, 7, 36},
                { RC_L_SDT, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */
-                       17300, 8, 48, 8},
+                       17300, 8, 48},
                { RC_L_SDT, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */
-                       23000, 9, 72, 8},
+                       23000, 9, 72},
                { RC_L_SDT, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */
-                       27400, 10, 96, 8},
+                       27400, 10, 96},
                { RC_L_SDT, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */
-                       29300, 11, 108, 8},
+                       29300, 11, 108},
        },
        50,  /* probe interval */
        0,   /* Phy rates allowed initially */
 };
 
-static int ath_rc_get_rateindex(const struct ath_rate_table *rate_table,
+static int ath_rc_get_rateindex(struct ath_rate_priv *ath_rc_priv,
                                struct ieee80211_tx_rate *rate)
 {
-       int rix = 0, i = 0;
-       static const int mcs_rix_off[] = { 7, 15, 20, 21, 22, 23 };
+       const struct ath_rate_table *rate_table = ath_rc_priv->rate_table;
+       int rix, i, idx = 0;
 
        if (!(rate->flags & IEEE80211_TX_RC_MCS))
                return rate->idx;
 
-       while (i < ARRAY_SIZE(mcs_rix_off) && rate->idx > mcs_rix_off[i]) {
-               rix++; i++;
+       for (i = 0; i < ath_rc_priv->max_valid_rate; i++) {
+               idx = ath_rc_priv->valid_rate_index[i];
+
+               if (WLAN_RC_PHY_HT(rate_table->info[idx].phy) &&
+                   rate_table->info[idx].ratecode == rate->idx)
+                       break;
        }
 
-       rix += rate->idx + rate_table->mcs_start;
+       rix = idx;
 
-       if ((rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) &&
-           (rate->flags & IEEE80211_TX_RC_SHORT_GI))
-               rix = rate_table->info[rix].ht_index;
-       else if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
-               rix = rate_table->info[rix].sgi_index;
-       else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
-               rix = rate_table->info[rix].cw40index;
+       if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
+               rix++;
 
        return rix;
 }
 
-static void ath_rc_sort_validrates(const struct ath_rate_table *rate_table,
-                                  struct ath_rate_priv *ath_rc_priv)
+static void ath_rc_sort_validrates(struct ath_rate_priv *ath_rc_priv)
 {
+       const struct ath_rate_table *rate_table = ath_rc_priv->rate_table;
        u8 i, j, idx, idx_next;
 
        for (i = ath_rc_priv->max_valid_rate - 1; i > 0; i--) {
@@ -424,21 +423,6 @@ static void ath_rc_sort_validrates(const struct ath_rate_table *rate_table,
        }
 }
 
-static void ath_rc_init_valid_rate_idx(struct ath_rate_priv *ath_rc_priv)
-{
-       u8 i;
-
-       for (i = 0; i < ath_rc_priv->rate_table_size; i++)
-               ath_rc_priv->valid_rate_index[i] = 0;
-}
-
-static inline void ath_rc_set_valid_rate_idx(struct ath_rate_priv *ath_rc_priv,
-                                          u8 index, int valid_tx_rate)
-{
-       BUG_ON(index > ath_rc_priv->rate_table_size);
-       ath_rc_priv->valid_rate_index[index] = !!valid_tx_rate;
-}
-
 static inline
 int ath_rc_get_nextvalid_txrate(const struct ath_rate_table *rate_table,
                                struct ath_rate_priv *ath_rc_priv,
@@ -479,8 +463,7 @@ static int ath_rc_valid_phyrate(u32 phy, u32 capflag, int ignore_cw)
 }
 
 static inline int
-ath_rc_get_lower_rix(const struct ath_rate_table *rate_table,
-                    struct ath_rate_priv *ath_rc_priv,
+ath_rc_get_lower_rix(struct ath_rate_priv *ath_rc_priv,
                     u8 cur_valid_txrate, u8 *next_idx)
 {
        int8_t i;
@@ -495,10 +478,9 @@ ath_rc_get_lower_rix(const struct ath_rate_table *rate_table,
        return 0;
 }
 
-static u8 ath_rc_init_validrates(struct ath_rate_priv *ath_rc_priv,
-                                const struct ath_rate_table *rate_table,
-                                u32 capflag)
+static u8 ath_rc_init_validrates(struct ath_rate_priv *ath_rc_priv)
 {
+       const struct ath_rate_table *rate_table = ath_rc_priv->rate_table;
        u8 i, hi = 0;
 
        for (i = 0; i < rate_table->rate_cnt; i++) {
@@ -506,14 +488,14 @@ static u8 ath_rc_init_validrates(struct ath_rate_priv *ath_rc_priv,
                        u32 phy = rate_table->info[i].phy;
                        u8 valid_rate_count = 0;
 
-                       if (!ath_rc_valid_phyrate(phy, capflag, 0))
+                       if (!ath_rc_valid_phyrate(phy, ath_rc_priv->ht_cap, 0))
                                continue;
 
                        valid_rate_count = ath_rc_priv->valid_phy_ratecnt[phy];
 
                        ath_rc_priv->valid_phy_rateidx[phy][valid_rate_count] = i;
                        ath_rc_priv->valid_phy_ratecnt[phy] += 1;
-                       ath_rc_set_valid_rate_idx(ath_rc_priv, i, 1);
+                       ath_rc_priv->valid_rate_index[i] = true;
                        hi = i;
                }
        }
@@ -521,76 +503,73 @@ static u8 ath_rc_init_validrates(struct ath_rate_priv *ath_rc_priv,
        return hi;
 }
 
-static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv,
-                               const struct ath_rate_table *rate_table,
-                               struct ath_rateset *rateset,
-                               u32 capflag)
+static inline bool ath_rc_check_legacy(u8 rate, u8 dot11rate, u16 rate_flags,
+                                      u32 phy, u32 capflag)
 {
-       u8 i, j, hi = 0;
+       if (rate != dot11rate || WLAN_RC_PHY_HT(phy))
+               return false;
 
-       /* Use intersection of working rates and valid rates */
-       for (i = 0; i < rateset->rs_nrates; i++) {
-               for (j = 0; j < rate_table->rate_cnt; j++) {
-                       u32 phy = rate_table->info[j].phy;
-                       u16 rate_flags = rate_table->info[j].rate_flags;
-                       u8 rate = rateset->rs_rates[i];
-                       u8 dot11rate = rate_table->info[j].dot11rate;
-
-                       /* We allow a rate only if its valid and the
-                        * capflag matches one of the validity
-                        * (VALID/VALID_20/VALID_40) flags */
-
-                       if ((rate == dot11rate) &&
-                           (rate_flags & WLAN_RC_CAP_MODE(capflag)) ==
-                           WLAN_RC_CAP_MODE(capflag) &&
-                           (rate_flags & WLAN_RC_CAP_STREAM(capflag)) &&
-                           !WLAN_RC_PHY_HT(phy)) {
-                               u8 valid_rate_count = 0;
-
-                               if (!ath_rc_valid_phyrate(phy, capflag, 0))
-                                       continue;
-
-                               valid_rate_count =
-                                       ath_rc_priv->valid_phy_ratecnt[phy];
-
-                               ath_rc_priv->valid_phy_rateidx[phy]
-                                       [valid_rate_count] = j;
-                               ath_rc_priv->valid_phy_ratecnt[phy] += 1;
-                               ath_rc_set_valid_rate_idx(ath_rc_priv, j, 1);
-                               hi = max(hi, j);
-                       }
-               }
-       }
+       if ((rate_flags & WLAN_RC_CAP_MODE(capflag)) != WLAN_RC_CAP_MODE(capflag))
+               return false;
 
-       return hi;
+       if (!(rate_flags & WLAN_RC_CAP_STREAM(capflag)))
+               return false;
+
+       return true;
 }
 
-static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv,
-                                 const struct ath_rate_table *rate_table,
-                                 struct ath_rateset *rateset, u32 capflag)
+static inline bool ath_rc_check_ht(u8 rate, u8 dot11rate, u16 rate_flags,
+                                  u32 phy, u32 capflag)
 {
-       u8 i, j, hi = 0;
+       if (rate != dot11rate || !WLAN_RC_PHY_HT(phy))
+               return false;
+
+       if (!WLAN_RC_PHY_HT_VALID(rate_flags, capflag))
+               return false;
+
+       if (!(rate_flags & WLAN_RC_CAP_STREAM(capflag)))
+               return false;
+
+       return true;
+}
+
+static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv, bool legacy)
+{
+       const struct ath_rate_table *rate_table = ath_rc_priv->rate_table;
+       struct ath_rateset *rateset;
+       u32 phy, capflag = ath_rc_priv->ht_cap;
+       u16 rate_flags;
+       u8 i, j, hi = 0, rate, dot11rate, valid_rate_count;
+
+       if (legacy)
+               rateset = &ath_rc_priv->neg_rates;
+       else
+               rateset = &ath_rc_priv->neg_ht_rates;
 
-       /* Use intersection of working rates and valid rates */
        for (i = 0; i < rateset->rs_nrates; i++) {
                for (j = 0; j < rate_table->rate_cnt; j++) {
-                       u32 phy = rate_table->info[j].phy;
-                       u16 rate_flags = rate_table->info[j].rate_flags;
-                       u8 rate = rateset->rs_rates[i];
-                       u8 dot11rate = rate_table->info[j].dot11rate;
-
-                       if ((rate != dot11rate) || !WLAN_RC_PHY_HT(phy) ||
-                           !(rate_flags & WLAN_RC_CAP_STREAM(capflag)) ||
-                           !WLAN_RC_PHY_HT_VALID(rate_flags, capflag))
+                       phy = rate_table->info[j].phy;
+                       rate_flags = rate_table->info[j].rate_flags;
+                       rate = rateset->rs_rates[i];
+                       dot11rate = rate_table->info[j].dot11rate;
+
+                       if (legacy &&
+                           !ath_rc_check_legacy(rate, dot11rate,
+                                                rate_flags, phy, capflag))
+                               continue;
+
+                       if (!legacy &&
+                           !ath_rc_check_ht(rate, dot11rate,
+                                            rate_flags, phy, capflag))
                                continue;
 
                        if (!ath_rc_valid_phyrate(phy, capflag, 0))
                                continue;
 
-                       ath_rc_priv->valid_phy_rateidx[phy]
-                               [ath_rc_priv->valid_phy_ratecnt[phy]] = j;
+                       valid_rate_count = ath_rc_priv->valid_phy_ratecnt[phy];
+                       ath_rc_priv->valid_phy_rateidx[phy][valid_rate_count] = j;
                        ath_rc_priv->valid_phy_ratecnt[phy] += 1;
-                       ath_rc_set_valid_rate_idx(ath_rc_priv, j, 1);
+                       ath_rc_priv->valid_rate_index[j] = true;
                        hi = max(hi, j);
                }
        }
@@ -598,13 +577,10 @@ static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv,
        return hi;
 }
 
-/* Finds the highest rate index we can use */
-static u8 ath_rc_get_highest_rix(struct ath_softc *sc,
-                                struct ath_rate_priv *ath_rc_priv,
-                                const struct ath_rate_table *rate_table,
-                                int *is_probing,
-                                bool legacy)
+static u8 ath_rc_get_highest_rix(struct ath_rate_priv *ath_rc_priv,
+                                int *is_probing)
 {
+       const struct ath_rate_table *rate_table = ath_rc_priv->rate_table;
        u32 best_thruput, this_thruput, now_msec;
        u8 rate, next_rate, best_rate, maxindex, minindex;
        int8_t index = 0;
@@ -624,8 +600,6 @@ static u8 ath_rc_get_highest_rix(struct ath_softc *sc,
                u8 per_thres;
 
                rate = ath_rc_priv->valid_rate_index[index];
-               if (legacy && !(rate_table->info[rate].rate_flags & RC_LEGACY))
-                       continue;
                if (rate > ath_rc_priv->rate_max_phy)
                        continue;
 
@@ -707,8 +681,6 @@ static void ath_rc_rate_set_series(const struct ath_rate_table *rate_table,
        rate->count = tries;
        rate->idx = rate_table->info[rix].ratecode;
 
-       if (txrc->short_preamble)
-               rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE;
        if (txrc->rts || rtsctsenable)
                rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS;
 
@@ -726,37 +698,25 @@ static void ath_rc_rate_set_rtscts(struct ath_softc *sc,
                                   const struct ath_rate_table *rate_table,
                                   struct ieee80211_tx_info *tx_info)
 {
-       struct ieee80211_tx_rate *rates = tx_info->control.rates;
-       int i = 0, rix = 0, cix, enable_g_protection = 0;
+       struct ieee80211_bss_conf *bss_conf;
 
-       /* get the cix for the lowest valid rix */
-       for (i = 3; i >= 0; i--) {
-               if (rates[i].count && (rates[i].idx >= 0)) {
-                       rix = ath_rc_get_rateindex(rate_table, &rates[i]);
-                       break;
-               }
-       }
-       cix = rate_table->info[rix].ctrl_rate;
+       if (!tx_info->control.vif)
+               return;
+       /*
+        * For legacy frames, mac80211 takes care of CTS protection.
+        */
+       if (!(tx_info->control.rates[0].flags & IEEE80211_TX_RC_MCS))
+               return;
 
-       /* All protection frames are transmited at 2Mb/s for 802.11g,
-        * otherwise we transmit them at 1Mb/s */
-       if (sc->hw->conf.channel->band == IEEE80211_BAND_2GHZ &&
-           !conf_is_ht(&sc->hw->conf))
-               enable_g_protection = 1;
+       bss_conf = &tx_info->control.vif->bss_conf;
+
+       if (!bss_conf->basic_rates)
+               return;
 
        /*
-        * If 802.11g protection is enabled, determine whether to use RTS/CTS or
-        * just CTS.  Note that this is only done for OFDM/HT unicast frames.
+        * For now, use the lowest allowed basic rate for HT frames.
         */
-       if ((tx_info->control.vif &&
-            tx_info->control.vif->bss_conf.use_cts_prot) &&
-           (rate_table->info[rix].phy == WLAN_RC_PHY_OFDM ||
-            WLAN_RC_PHY_HT(rate_table->info[rix].phy))) {
-               rates[0].flags |= IEEE80211_TX_RC_USE_CTS_PROTECT;
-               cix = rate_table->info[enable_g_protection].ctrl_rate;
-       }
-
-       tx_info->control.rts_cts_rate_idx = cix;
+       tx_info->control.rts_cts_rate_idx = __ffs(bss_conf->basic_rates);
 }
 
 static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
@@ -789,14 +749,8 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
        try_per_rate = 4;
 
        rate_table = ath_rc_priv->rate_table;
-       rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table,
-                                    &is_probe, false);
+       rix = ath_rc_get_highest_rix(ath_rc_priv, &is_probe);
 
-       /*
-        * If we're in HT mode and both us and our peer supports LDPC.
-        * We don't need to check our own device's capabilities as our own
-        * ht capabilities would have already been intersected with our peer's.
-        */
        if (conf_is_ht(&sc->hw->conf) &&
            (sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING))
                tx_info->flags |= IEEE80211_TX_CTL_LDPC;
@@ -806,52 +760,45 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
                tx_info->flags |= (1 << IEEE80211_TX_CTL_STBC_SHIFT);
 
        if (is_probe) {
-               /* set one try for probe rates. For the
-                * probes don't enable rts */
+               /*
+                * Set one try for probe rates. For the
+                * probes don't enable RTS.
+                */
                ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
                                       1, rix, 0);
-
-               /* Get the next tried/allowed rate. No RTS for the next series
-                * after the probe rate
+               /*
+                * Get the next tried/allowed rate.
+                * No RTS for the next series after the probe rate.
                 */
-               ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &rix);
+               ath_rc_get_lower_rix(ath_rc_priv, rix, &rix);
                ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
                                       try_per_rate, rix, 0);
 
                tx_info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE;
        } else {
-               /* Set the chosen rate. No RTS for first series entry. */
+               /*
+                * Set the chosen rate. No RTS for first series entry.
+                */
                ath_rc_rate_set_series(rate_table, &rates[i++], txrc,
                                       try_per_rate, rix, 0);
        }
 
-       /* Fill in the other rates for multirate retry */
-       for ( ; i < 3; i++) {
+       for ( ; i < 4; i++) {
+               /*
+                * Use twice the number of tries for the last MRR segment.
+                */
+               if (i + 1 == 4)
+                       try_per_rate = 8;
+
+               ath_rc_get_lower_rix(ath_rc_priv, rix, &rix);
 
-               ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &rix);
-               /* All other rates in the series have RTS enabled */
+               /*
+                * All other rates in the series have RTS enabled.
+                */
                ath_rc_rate_set_series(rate_table, &rates[i], txrc,
                                       try_per_rate, rix, 1);
        }
 
-       /* Use twice the number of tries for the last MRR segment. */
-       try_per_rate = 8;
-
-       /*
-        * If the last rate in the rate series is MCS and has
-        * more than 80% of per thresh, then use a legacy rate
-        * as last retry to ensure that the frame is tried in both
-        * MCS and legacy rate.
-        */
-       ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &rix);
-       if (WLAN_RC_PHY_HT(rate_table->info[rix].phy) &&
-           (ath_rc_priv->per[rix] > 45))
-               rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table,
-                               &is_probe, true);
-
-       /* All other rates in the series have RTS enabled */
-       ath_rc_rate_set_series(rate_table, &rates[i], txrc,
-                              try_per_rate, rix, 1);
        /*
         * NB:Change rate series to enable aggregation when operating
         * at lower MCS rates. When first rate in series is MCS2
@@ -893,7 +840,6 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
                rates[0].count = ATH_TXMAXTRY;
        }
 
-       /* Setup RTS/CTS */
        ath_rc_rate_set_rtscts(sc, rate_table, tx_info);
 }
 
@@ -1046,9 +992,6 @@ static void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix,
        stats->per = per;
 }
 
-/* Update PER, RSSI and whatever else that the code thinks it is doing.
-   If you can make sense of all this, you really need to go out more. */
-
 static void ath_rc_update_ht(struct ath_softc *sc,
                             struct ath_rate_priv *ath_rc_priv,
                             struct ieee80211_tx_info *tx_info,
@@ -1077,8 +1020,8 @@ static void ath_rc_update_ht(struct ath_softc *sc,
        if (ath_rc_priv->per[tx_rate] >= 55 && tx_rate > 0 &&
            rate_table->info[tx_rate].ratekbps <=
            rate_table->info[ath_rc_priv->rate_max_phy].ratekbps) {
-               ath_rc_get_lower_rix(rate_table, ath_rc_priv,
-                                    (u8)tx_rate, &ath_rc_priv->rate_max_phy);
+               ath_rc_get_lower_rix(ath_rc_priv, (u8)tx_rate,
+                                    &ath_rc_priv->rate_max_phy);
 
                /* Don't probe for a little while. */
                ath_rc_priv->probe_time = now_msec;
@@ -1122,25 +1065,42 @@ static void ath_rc_update_ht(struct ath_softc *sc,
 
 }
 
+static void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate)
+{
+       struct ath_rc_stats *stats;
+
+       stats = &rc->rcstats[final_rate];
+       stats->success++;
+}
 
 static void ath_rc_tx_status(struct ath_softc *sc,
                             struct ath_rate_priv *ath_rc_priv,
-                            struct ieee80211_tx_info *tx_info,
-                            int final_ts_idx, int xretries, int long_retry)
+                            struct sk_buff *skb)
 {
-       const struct ath_rate_table *rate_table;
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
        struct ieee80211_tx_rate *rates = tx_info->status.rates;
+       struct ieee80211_tx_rate *rate;
+       int final_ts_idx = 0, xretries = 0, long_retry = 0;
        u8 flags;
        u32 i = 0, rix;
 
-       rate_table = ath_rc_priv->rate_table;
+       for (i = 0; i < sc->hw->max_rates; i++) {
+               rate = &tx_info->status.rates[i];
+               if (rate->idx < 0 || !rate->count)
+                       break;
+
+               final_ts_idx = i;
+               long_retry = rate->count - 1;
+       }
+
+       if (!(tx_info->flags & IEEE80211_TX_STAT_ACK))
+               xretries = 1;
 
        /*
         * If the first rate is not the final index, there
         * are intermediate rate failures to be processed.
         */
        if (final_ts_idx != 0) {
-               /* Process intermediate rates that failed.*/
                for (i = 0; i < final_ts_idx ; i++) {
                        if (rates[i].count != 0 && (rates[i].idx >= 0)) {
                                flags = rates[i].flags;
@@ -1152,32 +1112,24 @@ static void ath_rc_tx_status(struct ath_softc *sc,
                                    !(ath_rc_priv->ht_cap & WLAN_RC_40_FLAG))
                                        return;
 
-                               rix = ath_rc_get_rateindex(rate_table, &rates[i]);
+                               rix = ath_rc_get_rateindex(ath_rc_priv, &rates[i]);
                                ath_rc_update_ht(sc, ath_rc_priv, tx_info,
-                                               rix, xretries ? 1 : 2,
-                                               rates[i].count);
+                                                rix, xretries ? 1 : 2,
+                                                rates[i].count);
                        }
                }
-       } else {
-               /*
-                * Handle the special case of MIMO PS burst, where the second
-                * aggregate is sent out with only one rate and one try.
-                * Treating it as an excessive retry penalizes the rate
-                * inordinately.
-                */
-               if (rates[0].count == 1 && xretries == 1)
-                       xretries = 2;
        }
 
-       flags = rates[i].flags;
+       flags = rates[final_ts_idx].flags;
 
        /* If HT40 and we have switched mode from 40 to 20 => don't update */
        if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) &&
            !(ath_rc_priv->ht_cap & WLAN_RC_40_FLAG))
                return;
 
-       rix = ath_rc_get_rateindex(rate_table, &rates[i]);
+       rix = ath_rc_get_rateindex(ath_rc_priv, &rates[final_ts_idx]);
        ath_rc_update_ht(sc, ath_rc_priv, tx_info, rix, xretries, long_retry);
+       ath_debug_stat_rc(ath_rc_priv, rix);
 }
 
 static const
@@ -1185,8 +1137,6 @@ struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc,
                                             enum ieee80211_band band,
                                             bool is_ht)
 {
-       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-
        switch(band) {
        case IEEE80211_BAND_2GHZ:
                if (is_ht)
@@ -1197,34 +1147,25 @@ struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc,
                        return &ar5416_11na_ratetable;
                return &ar5416_11a_ratetable;
        default:
-               ath_dbg(common, CONFIG, "Invalid band\n");
                return NULL;
        }
 }
 
 static void ath_rc_init(struct ath_softc *sc,
-                       struct ath_rate_priv *ath_rc_priv,
-                       struct ieee80211_supported_band *sband,
-                       struct ieee80211_sta *sta,
-                       const struct ath_rate_table *rate_table)
+                       struct ath_rate_priv *ath_rc_priv)
 {
+       const struct ath_rate_table *rate_table = ath_rc_priv->rate_table;
        struct ath_rateset *rateset = &ath_rc_priv->neg_rates;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-       struct ath_rateset *ht_mcs = &ath_rc_priv->neg_ht_rates;
        u8 i, j, k, hi = 0, hthi = 0;
 
-       /* Initial rate table size. Will change depending
-        * on the working rate set */
        ath_rc_priv->rate_table_size = RATE_TABLE_SIZE;
 
-       /* Initialize thresholds according to the global rate table */
        for (i = 0 ; i < ath_rc_priv->rate_table_size; i++) {
                ath_rc_priv->per[i] = 0;
+               ath_rc_priv->valid_rate_index[i] = 0;
        }
 
-       /* Determine the valid rates */
-       ath_rc_init_valid_rate_idx(ath_rc_priv);
-
        for (i = 0; i < WLAN_RC_PHY_MAX; i++) {
                for (j = 0; j < RATE_TABLE_SIZE; j++)
                        ath_rc_priv->valid_phy_rateidx[i][j] = 0;
@@ -1232,25 +1173,19 @@ static void ath_rc_init(struct ath_softc *sc,
        }
 
        if (!rateset->rs_nrates) {
-               /* No working rate, just initialize valid rates */
-               hi = ath_rc_init_validrates(ath_rc_priv, rate_table,
-                                           ath_rc_priv->ht_cap);
+               hi = ath_rc_init_validrates(ath_rc_priv);
        } else {
-               /* Use intersection of working rates and valid rates */
-               hi = ath_rc_setvalid_rates(ath_rc_priv, rate_table,
-                                          rateset, ath_rc_priv->ht_cap);
-               if (ath_rc_priv->ht_cap & WLAN_RC_HT_FLAG) {
-                       hthi = ath_rc_setvalid_htrates(ath_rc_priv,
-                                                      rate_table,
-                                                      ht_mcs,
-                                                      ath_rc_priv->ht_cap);
-               }
+               hi = ath_rc_setvalid_rates(ath_rc_priv, true);
+
+               if (ath_rc_priv->ht_cap & WLAN_RC_HT_FLAG)
+                       hthi = ath_rc_setvalid_rates(ath_rc_priv, false);
+
                hi = max(hi, hthi);
        }
 
        ath_rc_priv->rate_table_size = hi + 1;
        ath_rc_priv->rate_max_phy = 0;
-       BUG_ON(ath_rc_priv->rate_table_size > RATE_TABLE_SIZE);
+       WARN_ON(ath_rc_priv->rate_table_size > RATE_TABLE_SIZE);
 
        for (i = 0, k = 0; i < WLAN_RC_PHY_MAX; i++) {
                for (j = 0; j < ath_rc_priv->valid_phy_ratecnt[i]; j++) {
@@ -1258,28 +1193,26 @@ static void ath_rc_init(struct ath_softc *sc,
                                ath_rc_priv->valid_phy_rateidx[i][j];
                }
 
-               if (!ath_rc_valid_phyrate(i, rate_table->initial_ratemax, 1)
-                   || !ath_rc_priv->valid_phy_ratecnt[i])
+               if (!ath_rc_valid_phyrate(i, rate_table->initial_ratemax, 1) ||
+                   !ath_rc_priv->valid_phy_ratecnt[i])
                        continue;
 
                ath_rc_priv->rate_max_phy = ath_rc_priv->valid_phy_rateidx[i][j-1];
        }
-       BUG_ON(ath_rc_priv->rate_table_size > RATE_TABLE_SIZE);
-       BUG_ON(k > RATE_TABLE_SIZE);
+       WARN_ON(ath_rc_priv->rate_table_size > RATE_TABLE_SIZE);
+       WARN_ON(k > RATE_TABLE_SIZE);
 
        ath_rc_priv->max_valid_rate = k;
-       ath_rc_sort_validrates(rate_table, ath_rc_priv);
+       ath_rc_sort_validrates(ath_rc_priv);
        ath_rc_priv->rate_max_phy = (k > 4) ?
-                                       ath_rc_priv->valid_rate_index[k-4] :
-                                       ath_rc_priv->valid_rate_index[k-1];
-       ath_rc_priv->rate_table = rate_table;
+               ath_rc_priv->valid_rate_index[k-4] :
+               ath_rc_priv->valid_rate_index[k-1];
 
        ath_dbg(common, CONFIG, "RC Initialized with capabilities: 0x%x\n",
                ath_rc_priv->ht_cap);
 }
 
-static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta,
-                              bool is_cw40, bool is_sgi)
+static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta)
 {
        u8 caps = 0;
 
@@ -1289,9 +1222,10 @@ static u8 ath_rc_build_ht_caps(struct ath_softc *sc, struct ieee80211_sta *sta,
                        caps |= WLAN_RC_TS_FLAG | WLAN_RC_DS_FLAG;
                else if (sta->ht_cap.mcs.rx_mask[1])
                        caps |= WLAN_RC_DS_FLAG;
-               if (is_cw40)
+               if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
                        caps |= WLAN_RC_40_FLAG;
-               if (is_sgi)
+               if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40 ||
+                   sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20)
                        caps |= WLAN_RC_SGI_FLAG;
        }
 
@@ -1319,15 +1253,6 @@ static bool ath_tx_aggr_check(struct ath_softc *sc, struct ieee80211_sta *sta,
 /* mac80211 Rate Control callbacks */
 /***********************************/
 
-static void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate)
-{
-       struct ath_rc_stats *stats;
-
-       stats = &rc->rcstats[final_rate];
-       stats->success++;
-}
-
-
 static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
                          struct ieee80211_sta *sta, void *priv_sta,
                          struct sk_buff *skb)
@@ -1335,22 +1260,8 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
        struct ath_softc *sc = priv;
        struct ath_rate_priv *ath_rc_priv = priv_sta;
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
-       struct ieee80211_hdr *hdr;
-       int final_ts_idx = 0, tx_status = 0;
-       int long_retry = 0;
-       __le16 fc;
-       int i;
-
-       hdr = (struct ieee80211_hdr *)skb->data;
-       fc = hdr->frame_control;
-       for (i = 0; i < sc->hw->max_rates; i++) {
-               struct ieee80211_tx_rate *rate = &tx_info->status.rates[i];
-               if (rate->idx < 0 || !rate->count)
-                       break;
-
-               final_ts_idx = i;
-               long_retry = rate->count - 1;
-       }
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       __le16 fc = hdr->frame_control;
 
        if (!priv_sta || !ieee80211_is_data(fc))
                return;
@@ -1363,11 +1274,7 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
        if (tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED)
                return;
 
-       if (!(tx_info->flags & IEEE80211_TX_STAT_ACK))
-               tx_status = 1;
-
-       ath_rc_tx_status(sc, ath_rc_priv, tx_info, final_ts_idx, tx_status,
-                        long_retry);
+       ath_rc_tx_status(sc, ath_rc_priv, skb);
 
        /* Check if aggregation has to be enabled for this tid */
        if (conf_is_ht(&sc->hw->conf) &&
@@ -1383,19 +1290,14 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
                                ieee80211_start_tx_ba_session(sta, tid, 0);
                }
        }
-
-       ath_debug_stat_rc(ath_rc_priv,
-               ath_rc_get_rateindex(ath_rc_priv->rate_table,
-                       &tx_info->status.rates[final_ts_idx]));
 }
 
 static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
                           struct ieee80211_sta *sta, void *priv_sta)
 {
        struct ath_softc *sc = priv;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_rate_priv *ath_rc_priv = priv_sta;
-       const struct ath_rate_table *rate_table;
-       bool is_cw40, is_sgi = false;
        int i, j = 0;
 
        for (i = 0; i < sband->n_bitrates; i++) {
@@ -1417,20 +1319,15 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
                ath_rc_priv->neg_ht_rates.rs_nrates = j;
        }
 
-       is_cw40 = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40);
-
-       if (is_cw40)
-               is_sgi = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40);
-       else if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20)
-               is_sgi = !!(sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20);
-
-       /* Choose rate table first */
-
-       rate_table = ath_choose_rate_table(sc, sband->band,
-                             sta->ht_cap.ht_supported);
+       ath_rc_priv->rate_table = ath_choose_rate_table(sc, sband->band,
+                                                       sta->ht_cap.ht_supported);
+       if (!ath_rc_priv->rate_table) {
+               ath_err(common, "No rate table chosen\n");
+               return;
+       }
 
-       ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta, is_cw40, is_sgi);
-       ath_rc_init(sc, priv_sta, sband, sta, rate_table);
+       ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta);
+       ath_rc_init(sc, priv_sta);
 }
 
 static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband,
@@ -1439,40 +1336,14 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband,
 {
        struct ath_softc *sc = priv;
        struct ath_rate_priv *ath_rc_priv = priv_sta;
-       const struct ath_rate_table *rate_table = NULL;
-       bool oper_cw40 = false, oper_sgi;
-       bool local_cw40 = !!(ath_rc_priv->ht_cap & WLAN_RC_40_FLAG);
-       bool local_sgi = !!(ath_rc_priv->ht_cap & WLAN_RC_SGI_FLAG);
-
-       /* FIXME: Handle AP mode later when we support CWM */
 
        if (changed & IEEE80211_RC_BW_CHANGED) {
-               if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION)
-                       return;
+               ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta);
+               ath_rc_init(sc, priv_sta);
 
-               if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
-                       oper_cw40 = true;
-
-               if (oper_cw40)
-                       oper_sgi = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
-                                  true : false;
-               else if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_SGI_20)
-                       oper_sgi = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
-                                  true : false;
-               else
-                       oper_sgi = false;
-
-               if ((local_cw40 != oper_cw40) || (local_sgi != oper_sgi)) {
-                       rate_table = ath_choose_rate_table(sc, sband->band,
-                                                  sta->ht_cap.ht_supported);
-                       ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta,
-                                                  oper_cw40, oper_sgi);
-                       ath_rc_init(sc, priv_sta, sband, sta, rate_table);
-
-                       ath_dbg(ath9k_hw_common(sc->sc_ah), CONFIG,
-                               "Operating HT Bandwidth changed to: %d\n",
-                               sc->hw->conf.channel_type);
-               }
+               ath_dbg(ath9k_hw_common(sc->sc_ah), CONFIG,
+                       "Operating HT Bandwidth changed to: %d\n",
+                       sc->hw->conf.channel_type);
        }
 }
 
@@ -1484,7 +1355,7 @@ static ssize_t read_file_rcstat(struct file *file, char __user *user_buf,
        struct ath_rate_priv *rc = file->private_data;
        char *buf;
        unsigned int len = 0, max;
-       int i = 0;
+       int rix;
        ssize_t retval;
 
        if (rc->rate_table == NULL)
@@ -1500,7 +1371,8 @@ static ssize_t read_file_rcstat(struct file *file, char __user *user_buf,
                       "HT", "MCS", "Rate",
                       "Success", "Retries", "XRetries", "PER");
 
-       for (i = 0; i < rc->rate_table_size; i++) {
+       for (rix = 0; rix < rc->max_valid_rate; rix++) {
+               u8 i = rc->valid_rate_index[rix];
                u32 ratekbps = rc->rate_table->info[i].ratekbps;
                struct ath_rc_stats *stats = &rc->rcstats[i];
                char mcs[5];
index 75f8e9b06b2859d2866f16653c3a22913ee6baf5..268e67dc5fb2d945a26a332081b32167d9e133dc 100644 (file)
@@ -160,10 +160,6 @@ struct ath_rate_table {
                u32 user_ratekbps;
                u8 ratecode;
                u8 dot11rate;
-               u8 ctrl_rate;
-               u8 cw40index;
-               u8 sgi_index;
-               u8 ht_index;
        } info[RATE_TABLE_SIZE];
        u32 probe_interval;
        u8 initial_ratemax;
index 12aca02228c22e9c8f5c62db20687c03f5992959..4480c0cc655f6f6ffca73774b2178e748936155e 100644 (file)
@@ -1044,7 +1044,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
        struct ieee80211_hw *hw = sc->hw;
        struct ieee80211_hdr *hdr;
        int retval;
-       bool decrypt_error = false;
        struct ath_rx_status rs;
        enum ath9k_rx_qtype qtype;
        bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);
@@ -1066,6 +1065,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
        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;
index c5ca6f1f5836c26f1360fde607e02decaca340d0..24ac2876a7337ad2a015f69a4f273165d3d8d7f0 100644 (file)
@@ -341,6 +341,7 @@ 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);
                }
        }
index 53415bfd8bef7e673749904369775520ff74beae..f8676280dc36669fcd5775468beefc8378823753 100644 (file)
@@ -318,10 +318,10 @@ int carl9170_set_operating_mode(struct ar9170 *ar)
                bssid = common->curbssid;
 
                switch (vif->type) {
-               case NL80211_IFTYPE_MESH_POINT:
                case NL80211_IFTYPE_ADHOC:
                        cam_mode |= AR9170_MAC_CAM_IBSS;
                        break;
+               case NL80211_IFTYPE_MESH_POINT:
                case NL80211_IFTYPE_AP:
                        cam_mode |= AR9170_MAC_CAM_AP;
 
index 858e58dfc4dc67176f7d9693d7babb598ea6980e..18554ab76733cb591fccbebc8200feceeff2eac7 100644 (file)
@@ -616,10 +616,12 @@ static int carl9170_op_add_interface(struct ieee80211_hw *hw,
 
                        goto unlock;
 
+               case NL80211_IFTYPE_MESH_POINT:
                case NL80211_IFTYPE_AP:
                        if ((vif->type == NL80211_IFTYPE_STATION) ||
                            (vif->type == NL80211_IFTYPE_WDS) ||
-                           (vif->type == NL80211_IFTYPE_AP))
+                           (vif->type == NL80211_IFTYPE_AP) ||
+                           (vif->type == NL80211_IFTYPE_MESH_POINT))
                                break;
 
                        err = -EBUSY;
index 6f6a34155667d0da84fdb5c9d63824ce7d1ac37b..b813f43061f5040b485c9ae82a0519e34386e08d 100644 (file)
@@ -206,6 +206,7 @@ void carl9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
 
                case NL80211_IFTYPE_AP:
                case NL80211_IFTYPE_ADHOC:
+               case NL80211_IFTYPE_MESH_POINT:
                        carl9170_update_beacon(ar, true);
                        break;
 
index 4648bbf76abcb617d97d5a40aa4a4255b1228c74..098fe9ee7096958a73093c2cbe18d7b37216e556 100644 (file)
@@ -4,6 +4,7 @@ b43-y                           += tables.o
 b43-$(CONFIG_B43_PHY_N)                += tables_nphy.o
 b43-$(CONFIG_B43_PHY_N)                += radio_2055.o
 b43-$(CONFIG_B43_PHY_N)                += radio_2056.o
+b43-$(CONFIG_B43_PHY_N)                += radio_2057.o
 b43-y                          += phy_common.o
 b43-y                          += phy_g.o
 b43-y                          += phy_a.o
index 7c899fc7ddd0ea1bced38d801b4eb18d0e1341f6..b298e5d68be2f0a58cf02d45d2ccd9a1e1e464bd 100644 (file)
@@ -241,16 +241,18 @@ enum {
 #define B43_SHM_SH_PHYVER              0x0050  /* PHY version */
 #define B43_SHM_SH_PHYTYPE             0x0052  /* PHY type */
 #define B43_SHM_SH_ANTSWAP             0x005C  /* Antenna swap threshold */
-#define B43_SHM_SH_HOSTFLO             0x005E  /* Hostflags for ucode options (low) */
-#define B43_SHM_SH_HOSTFMI             0x0060  /* Hostflags for ucode options (middle) */
-#define B43_SHM_SH_HOSTFHI             0x0062  /* Hostflags for ucode options (high) */
+#define B43_SHM_SH_HOSTF1              0x005E  /* Hostflags 1 for ucode options */
+#define B43_SHM_SH_HOSTF2              0x0060  /* Hostflags 2 for ucode options */
+#define B43_SHM_SH_HOSTF3              0x0062  /* Hostflags 3 for ucode options */
 #define B43_SHM_SH_RFATT               0x0064  /* Current radio attenuation value */
 #define B43_SHM_SH_RADAR               0x0066  /* Radar register */
 #define B43_SHM_SH_PHYTXNOI            0x006E  /* PHY noise directly after TX (lower 8bit only) */
 #define B43_SHM_SH_RFRXSP1             0x0072  /* RF RX SP Register 1 */
+#define B43_SHM_SH_HOSTF4              0x0078  /* Hostflags 4 for ucode options */
 #define B43_SHM_SH_CHAN                        0x00A0  /* Current channel (low 8bit only) */
 #define  B43_SHM_SH_CHAN_5GHZ          0x0100  /* Bit set, if 5 Ghz channel */
 #define  B43_SHM_SH_CHAN_40MHZ         0x0200  /* Bit set, if 40 Mhz channel width */
+#define B43_SHM_SH_HOSTF5              0x00D4  /* Hostflags 5 for ucode options */
 #define B43_SHM_SH_BCMCFIFOID          0x0108  /* Last posted cookie to the bcast/mcast FIFO */
 /* TSSI information */
 #define B43_SHM_SH_TSSI_CCK            0x0058  /* TSSI for last 4 CCK frames (32bit) */
@@ -415,6 +417,8 @@ enum {
 #define B43_PHYTYPE_HT                 0x07
 #define B43_PHYTYPE_LCN                        0x08
 #define B43_PHYTYPE_LCNXN              0x09
+#define B43_PHYTYPE_LCN40              0x0a
+#define B43_PHYTYPE_AC                 0x0b
 
 /* PHYRegisters */
 #define B43_PHY_ILT_A_CTRL             0x0072
index b80352b308d54dabbc414c0d765122470f888c47..d97a95b1addbb92f58912c5f27de693636055afc 100644 (file)
@@ -533,11 +533,11 @@ u64 b43_hf_read(struct b43_wldev *dev)
 {
        u64 ret;
 
-       ret = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFHI);
+       ret = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF3);
        ret <<= 16;
-       ret |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFMI);
+       ret |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF2);
        ret <<= 16;
-       ret |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFLO);
+       ret |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF1);
 
        return ret;
 }
@@ -550,9 +550,9 @@ void b43_hf_write(struct b43_wldev *dev, u64 value)
        lo = (value & 0x00000000FFFFULL);
        mi = (value & 0x0000FFFF0000ULL) >> 16;
        hi = (value & 0xFFFF00000000ULL) >> 32;
-       b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFLO, lo);
-       b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFMI, mi);
-       b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFHI, hi);
+       b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF1, lo);
+       b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF2, mi);
+       b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF3, hi);
 }
 
 /* Read the firmware capabilities bitmask (Opensource firmware only) */
@@ -2719,32 +2719,37 @@ static int b43_gpio_init(struct b43_wldev *dev)
        if (dev->dev->chip_id == 0x4301) {
                mask |= 0x0060;
                set |= 0x0060;
+       } else if (dev->dev->chip_id == 0x5354) {
+               /* Don't allow overtaking buttons GPIOs */
+               set &= 0x2; /* 0x2 is LED GPIO on BCM5354 */
        }
-       if (dev->dev->chip_id == 0x5354)
-               set &= 0xff02;
+
        if (0 /* FIXME: conditional unknown */ ) {
                b43_write16(dev, B43_MMIO_GPIO_MASK,
                            b43_read16(dev, B43_MMIO_GPIO_MASK)
                            | 0x0100);
-               mask |= 0x0180;
-               set |= 0x0180;
+               /* BT Coexistance Input */
+               mask |= 0x0080;
+               set |= 0x0080;
+               /* BT Coexistance Out */
+               mask |= 0x0100;
+               set |= 0x0100;
        }
        if (dev->dev->bus_sprom->boardflags_lo & B43_BFL_PACTRL) {
+               /* PA is controlled by gpio 9, let ucode handle it */
                b43_write16(dev, B43_MMIO_GPIO_MASK,
                            b43_read16(dev, B43_MMIO_GPIO_MASK)
                            | 0x0200);
                mask |= 0x0200;
                set |= 0x0200;
        }
-       if (dev->dev->core_rev >= 2)
-               mask |= 0x0010; /* FIXME: This is redundant. */
 
        switch (dev->dev->bus_type) {
 #ifdef CONFIG_B43_BCMA
        case B43_BUS_BCMA:
                bcma_cc_write32(&dev->dev->bdev->bus->drv_cc, BCMA_CC_GPIOCTL,
                                (bcma_cc_read32(&dev->dev->bdev->bus->drv_cc,
-                                       BCMA_CC_GPIOCTL) & mask) | set);
+                                       BCMA_CC_GPIOCTL) & ~mask) | set);
                break;
 #endif
 #ifdef CONFIG_B43_SSB
@@ -2753,7 +2758,7 @@ static int b43_gpio_init(struct b43_wldev *dev)
                if (gpiodev)
                        ssb_write32(gpiodev, B43_GPIO_CONTROL,
                                    (ssb_read32(gpiodev, B43_GPIO_CONTROL)
-                                   & mask) | set);
+                                   & ~mask) | set);
                break;
 #endif
        }
@@ -4277,6 +4282,35 @@ out:
        return err;
 }
 
+static char *b43_phy_name(struct b43_wldev *dev, u8 phy_type)
+{
+       switch (phy_type) {
+       case B43_PHYTYPE_A:
+               return "A";
+       case B43_PHYTYPE_B:
+               return "B";
+       case B43_PHYTYPE_G:
+               return "G";
+       case B43_PHYTYPE_N:
+               return "N";
+       case B43_PHYTYPE_LP:
+               return "LP";
+       case B43_PHYTYPE_SSLPN:
+               return "SSLPN";
+       case B43_PHYTYPE_HT:
+               return "HT";
+       case B43_PHYTYPE_LCN:
+               return "LCN";
+       case B43_PHYTYPE_LCNXN:
+               return "LCNXN";
+       case B43_PHYTYPE_LCN40:
+               return "LCN40";
+       case B43_PHYTYPE_AC:
+               return "AC";
+       }
+       return "UNKNOWN";
+}
+
 /* Get PHY and RADIO versioning numbers */
 static int b43_phy_versioning(struct b43_wldev *dev)
 {
@@ -4337,13 +4371,13 @@ static int b43_phy_versioning(struct b43_wldev *dev)
                unsupported = 1;
        }
        if (unsupported) {
-               b43err(dev->wl, "FOUND UNSUPPORTED PHY "
-                      "(Analog %u, Type %u, Revision %u)\n",
-                      analog_type, phy_type, phy_rev);
+               b43err(dev->wl, "FOUND UNSUPPORTED PHY (Analog %u, Type %d (%s), Revision %u)\n",
+                      analog_type, phy_type, b43_phy_name(dev, phy_type),
+                      phy_rev);
                return -EOPNOTSUPP;
        }
-       b43dbg(dev->wl, "Found PHY: Analog %u, Type %u, Revision %u\n",
-              analog_type, phy_type, phy_rev);
+       b43info(dev->wl, "Found PHY: Analog %u, Type %d (%s), Revision %u\n",
+               analog_type, phy_type, b43_phy_name(dev, phy_type), phy_rev);
 
        /* Get RADIO versioning */
        if (dev->dev->core_rev >= 24) {
index 3f8883b14d9cc98ca334890541320aa50836d36e..f01676ac481b25071e9f7aae9ad790dbd5836ff0 100644 (file)
@@ -240,6 +240,21 @@ void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set)
                          (b43_radio_read16(dev, offset) & mask) | set);
 }
 
+bool b43_radio_wait_value(struct b43_wldev *dev, u16 offset, u16 mask,
+                         u16 value, int delay, int timeout)
+{
+       u16 val;
+       int i;
+
+       for (i = 0; i < timeout; i += delay) {
+               val = b43_radio_read(dev, offset);
+               if ((val & mask) == value)
+                       return true;
+               udelay(delay);
+       }
+       return false;
+}
+
 u16 b43_phy_read(struct b43_wldev *dev, u16 reg)
 {
        assert_mac_suspended(dev);
@@ -428,7 +443,7 @@ int b43_phy_shm_tssi_read(struct b43_wldev *dev, u16 shm_offset)
        average = (a + b + c + d + 2) / 4;
        if (is_ofdm) {
                /* Adjust for CCK-boost */
-               if (b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFLO)
+               if (b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF1)
                    & B43_HF_CCKBOOST)
                        average = (average >= 13) ? (average - 13) : 0;
        }
index 9233b13fc16d8a205eb474a3870f59bc3b6b7e8c..f1b999349876bbfc8cad799858434f5e64a14b37 100644 (file)
@@ -364,6 +364,12 @@ void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set);
  */
 void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set);
 
+/**
+ * b43_radio_wait_value - Waits for a given value in masked register read
+ */
+bool b43_radio_wait_value(struct b43_wldev *dev, u16 offset, u16 mask,
+                         u16 value, int delay, int timeout);
+
 /**
  * b43_radio_lock - Lock firmware radio register access
  */
index b92bb9c92ad1bb3a228f9e0fbf806da9686c6a5f..3c35382ee6c23ebfbaed8d1dcfdf33e804faec96 100644 (file)
@@ -32,6 +32,7 @@
 #include "tables_nphy.h"
 #include "radio_2055.h"
 #include "radio_2056.h"
+#include "radio_2057.h"
 #include "main.h"
 
 struct nphy_txgains {
@@ -126,6 +127,46 @@ ok:
        b43_phy_write(dev, B43_NPHY_RFSEQMODE, seq_mode);
 }
 
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverrideRev7 */
+static void b43_nphy_rf_control_override_rev7(struct b43_wldev *dev, u16 field,
+                                             u16 value, u8 core, bool off,
+                                             u8 override)
+{
+       const struct nphy_rf_control_override_rev7 *e;
+       u16 en_addrs[3][2] = {
+               { 0x0E7, 0x0EC }, { 0x342, 0x343 }, { 0x346, 0x347 }
+       };
+       u16 en_addr;
+       u16 en_mask = field;
+       u16 val_addr;
+       u8 i;
+
+       /* Remember: we can get NULL! */
+       e = b43_nphy_get_rf_ctl_over_rev7(dev, field, override);
+
+       for (i = 0; i < 2; i++) {
+               if (override >= ARRAY_SIZE(en_addrs)) {
+                       b43err(dev->wl, "Invalid override value %d\n", override);
+                       return;
+               }
+               en_addr = en_addrs[override][i];
+
+               val_addr = (i == 0) ? e->val_addr_core0 : e->val_addr_core1;
+
+               if (off) {
+                       b43_phy_mask(dev, en_addr, ~en_mask);
+                       if (e) /* Do it safer, better than wl */
+                               b43_phy_mask(dev, val_addr, ~e->val_mask);
+               } else {
+                       if (!core || (core & (1 << i))) {
+                               b43_phy_set(dev, en_addr, en_mask);
+                               if (e)
+                                       b43_phy_maskset(dev, val_addr, ~e->val_mask, (value << e->val_shift));
+                       }
+               }
+       }
+}
+
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverride */
 static void b43_nphy_rf_control_override(struct b43_wldev *dev, u16 field,
                                                u16 value, u8 core, bool off)
@@ -458,6 +499,137 @@ static void b43_nphy_set_rf_sequence(struct b43_wldev *dev, u8 cmd,
                b43_nphy_stay_in_carrier_search(dev, false);
 }
 
+/**************************************************
+ * Radio 0x2057
+ **************************************************/
+
+/* http://bcm-v4.sipsolutions.net/PHY/radio2057_rcal */
+static u8 b43_radio_2057_rcal(struct b43_wldev *dev)
+{
+       struct b43_phy *phy = &dev->phy;
+       u16 tmp;
+
+       if (phy->radio_rev == 5) {
+               b43_phy_mask(dev, 0x342, ~0x2);
+               udelay(10);
+               b43_radio_set(dev, R2057_IQTEST_SEL_PU, 0x1);
+               b43_radio_maskset(dev, 0x1ca, ~0x2, 0x1);
+       }
+
+       b43_radio_set(dev, R2057_RCAL_CONFIG, 0x1);
+       udelay(10);
+       b43_radio_set(dev, R2057_RCAL_CONFIG, 0x3);
+       if (!b43_radio_wait_value(dev, R2057_RCCAL_N1_1, 1, 1, 100, 1000000)) {
+               b43err(dev->wl, "Radio 0x2057 rcal timeout\n");
+               return 0;
+       }
+       b43_radio_mask(dev, R2057_RCAL_CONFIG, ~0x2);
+       tmp = b43_radio_read(dev, R2057_RCAL_STATUS) & 0x3E;
+       b43_radio_mask(dev, R2057_RCAL_CONFIG, ~0x1);
+
+       if (phy->radio_rev == 5) {
+               b43_radio_mask(dev, R2057_IPA2G_CASCONV_CORE0, ~0x1);
+               b43_radio_mask(dev, 0x1ca, ~0x2);
+       }
+       if (phy->radio_rev <= 4 || phy->radio_rev == 6) {
+               b43_radio_maskset(dev, R2057_TEMPSENSE_CONFIG, ~0x3C, tmp);
+               b43_radio_maskset(dev, R2057_BANDGAP_RCAL_TRIM, ~0xF0,
+                                 tmp << 2);
+       }
+
+       return tmp & 0x3e;
+}
+
+/* http://bcm-v4.sipsolutions.net/PHY/radio2057_rccal */
+static u16 b43_radio_2057_rccal(struct b43_wldev *dev)
+{
+       struct b43_phy *phy = &dev->phy;
+       bool special = (phy->radio_rev == 3 || phy->radio_rev == 4 ||
+                       phy->radio_rev == 6);
+       u16 tmp;
+
+       if (special) {
+               b43_radio_write(dev, R2057_RCCAL_MASTER, 0x61);
+               b43_radio_write(dev, R2057_RCCAL_TRC0, 0xC0);
+       } else {
+               b43_radio_write(dev, 0x1AE, 0x61);
+               b43_radio_write(dev, R2057_RCCAL_TRC0, 0xE1);
+       }
+       b43_radio_write(dev, R2057_RCCAL_X1, 0x6E);
+       b43_radio_write(dev, R2057_RCCAL_START_R1_Q1_P1, 0x55);
+       if (!b43_radio_wait_value(dev, R2057_RCCAL_DONE_OSCCAP, 1, 1, 500,
+                                 5000000))
+               b43dbg(dev->wl, "Radio 0x2057 rccal timeout\n");
+       b43_radio_write(dev, R2057_RCCAL_START_R1_Q1_P1, 0x15);
+       if (special) {
+               b43_radio_write(dev, R2057_RCCAL_MASTER, 0x69);
+               b43_radio_write(dev, R2057_RCCAL_TRC0, 0xB0);
+       } else {
+               b43_radio_write(dev, 0x1AE, 0x69);
+               b43_radio_write(dev, R2057_RCCAL_TRC0, 0xD5);
+       }
+       b43_radio_write(dev, R2057_RCCAL_X1, 0x6E);
+       b43_radio_write(dev, R2057_RCCAL_START_R1_Q1_P1, 0x55);
+       if (!b43_radio_wait_value(dev, R2057_RCCAL_DONE_OSCCAP, 1, 1, 500,
+                                 5000000))
+               b43dbg(dev->wl, "Radio 0x2057 rccal timeout\n");
+       b43_radio_write(dev, R2057_RCCAL_START_R1_Q1_P1, 0x15);
+       if (special) {
+               b43_radio_write(dev, R2057_RCCAL_MASTER, 0x73);
+               b43_radio_write(dev, R2057_RCCAL_X1, 0x28);
+               b43_radio_write(dev, R2057_RCCAL_TRC0, 0xB0);
+       } else {
+               b43_radio_write(dev, 0x1AE, 0x73);
+               b43_radio_write(dev, R2057_RCCAL_X1, 0x6E);
+               b43_radio_write(dev, R2057_RCCAL_TRC0, 0x99);
+       }
+       b43_radio_write(dev, R2057_RCCAL_START_R1_Q1_P1, 0x55);
+       if (!b43_radio_wait_value(dev, R2057_RCCAL_DONE_OSCCAP, 1, 1, 500,
+                                 5000000)) {
+               b43err(dev->wl, "Radio 0x2057 rcal timeout\n");
+               return 0;
+       }
+       tmp = b43_radio_read(dev, R2057_RCCAL_DONE_OSCCAP);
+       b43_radio_write(dev, R2057_RCCAL_START_R1_Q1_P1, 0x15);
+       return tmp;
+}
+
+static void b43_radio_2057_init_pre(struct b43_wldev *dev)
+{
+       b43_phy_mask(dev, B43_NPHY_RFCTL_CMD, ~B43_NPHY_RFCTL_CMD_CHIP0PU);
+       /* Maybe wl meant to reset and set (order?) RFCTL_CMD_OEPORFORCE? */
+       b43_phy_mask(dev, B43_NPHY_RFCTL_CMD, B43_NPHY_RFCTL_CMD_OEPORFORCE);
+       b43_phy_set(dev, B43_NPHY_RFCTL_CMD, ~B43_NPHY_RFCTL_CMD_OEPORFORCE);
+       b43_phy_set(dev, B43_NPHY_RFCTL_CMD, B43_NPHY_RFCTL_CMD_CHIP0PU);
+}
+
+static void b43_radio_2057_init_post(struct b43_wldev *dev)
+{
+       b43_radio_set(dev, R2057_XTALPUOVR_PINCTRL, 0x1);
+
+       b43_radio_set(dev, R2057_RFPLL_MISC_CAL_RESETN, 0x78);
+       b43_radio_set(dev, R2057_XTAL_CONFIG2, 0x80);
+       mdelay(2);
+       b43_radio_mask(dev, R2057_RFPLL_MISC_CAL_RESETN, ~0x78);
+       b43_radio_mask(dev, R2057_XTAL_CONFIG2, ~0x80);
+
+       if (dev->phy.n->init_por) {
+               b43_radio_2057_rcal(dev);
+               b43_radio_2057_rccal(dev);
+       }
+       b43_radio_mask(dev, R2057_RFPLL_MASTER, ~0x8);
+
+       dev->phy.n->init_por = false;
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/Radio/2057/Init */
+static void b43_radio_2057_init(struct b43_wldev *dev)
+{
+       b43_radio_2057_init_pre(dev);
+       r2057_upload_inittabs(dev);
+       b43_radio_2057_init_post(dev);
+}
+
 /**************************************************
  * Radio 0x2056
  **************************************************/
@@ -545,7 +717,9 @@ static void b43_radio_2056_setup(struct b43_wldev *dev,
        enum ieee80211_band band = b43_current_band(dev->wl);
        u16 offset;
        u8 i;
-       u16 bias, cbias, pag_boost, pgag_boost, mixg_boost, padg_boost;
+       u16 bias, cbias;
+       u16 pag_boost, padg_boost, pgag_boost, mixg_boost;
+       u16 paa_boost, pada_boost, pgaa_boost, mixa_boost;
 
        B43_WARN_ON(dev->phy.rev < 3);
 
@@ -630,7 +804,56 @@ static void b43_radio_2056_setup(struct b43_wldev *dev,
                        b43_radio_write(dev, offset | B2056_TX_PA_SPARE1, 0xee);
                }
        } else if (dev->phy.n->ipa5g_on && band == IEEE80211_BAND_5GHZ) {
-               /* TODO */
+               u16 freq = dev->phy.channel_freq;
+               if (freq < 5100) {
+                       paa_boost = 0xA;
+                       pada_boost = 0x77;
+                       pgaa_boost = 0xF;
+                       mixa_boost = 0xF;
+               } else if (freq < 5340) {
+                       paa_boost = 0x8;
+                       pada_boost = 0x77;
+                       pgaa_boost = 0xFB;
+                       mixa_boost = 0xF;
+               } else if (freq < 5650) {
+                       paa_boost = 0x0;
+                       pada_boost = 0x77;
+                       pgaa_boost = 0xB;
+                       mixa_boost = 0xF;
+               } else {
+                       paa_boost = 0x0;
+                       pada_boost = 0x77;
+                       if (freq != 5825)
+                               pgaa_boost = -(freq - 18) / 36 + 168;
+                       else
+                               pgaa_boost = 6;
+                       mixa_boost = 0xF;
+               }
+
+               for (i = 0; i < 2; i++) {
+                       offset = i ? B2056_TX1 : B2056_TX0;
+
+                       b43_radio_write(dev,
+                               offset | B2056_TX_INTPAA_BOOST_TUNE, paa_boost);
+                       b43_radio_write(dev,
+                               offset | B2056_TX_PADA_BOOST_TUNE, pada_boost);
+                       b43_radio_write(dev,
+                               offset | B2056_TX_PGAA_BOOST_TUNE, pgaa_boost);
+                       b43_radio_write(dev,
+                               offset | B2056_TX_MIXA_BOOST_TUNE, mixa_boost);
+                       b43_radio_write(dev,
+                               offset | B2056_TX_TXSPARE1, 0x30);
+                       b43_radio_write(dev,
+                               offset | B2056_TX_PA_SPARE2, 0xee);
+                       b43_radio_write(dev,
+                               offset | B2056_TX_PADA_CASCBIAS, 0x03);
+                       b43_radio_write(dev,
+                               offset | B2056_TX_INTPAA_IAUX_STAT, 0x50);
+                       b43_radio_write(dev,
+                               offset | B2056_TX_INTPAA_IMAIN_STAT, 0x50);
+                       b43_radio_write(dev,
+                               offset | B2056_TX_INTPAA_CASCBIAS, 0x30);
+               }
        }
 
        udelay(50);
@@ -643,6 +866,37 @@ static void b43_radio_2056_setup(struct b43_wldev *dev,
        udelay(300);
 }
 
+static u8 b43_radio_2056_rcal(struct b43_wldev *dev)
+{
+       struct b43_phy *phy = &dev->phy;
+       u16 mast2, tmp;
+
+       if (phy->rev != 3)
+               return 0;
+
+       mast2 = b43_radio_read(dev, B2056_SYN_PLL_MAST2);
+       b43_radio_write(dev, B2056_SYN_PLL_MAST2, mast2 | 0x7);
+
+       udelay(10);
+       b43_radio_write(dev, B2056_SYN_RCAL_MASTER, 0x01);
+       udelay(10);
+       b43_radio_write(dev, B2056_SYN_RCAL_MASTER, 0x09);
+
+       if (!b43_radio_wait_value(dev, B2056_SYN_RCAL_CODE_OUT, 0x80, 0x80, 100,
+                                 1000000)) {
+               b43err(dev->wl, "Radio recalibration timeout\n");
+               return 0;
+       }
+
+       b43_radio_write(dev, B2056_SYN_RCAL_MASTER, 0x01);
+       tmp = b43_radio_read(dev, B2056_SYN_RCAL_CODE_OUT);
+       b43_radio_write(dev, B2056_SYN_RCAL_MASTER, 0x00);
+
+       b43_radio_write(dev, B2056_SYN_PLL_MAST2, mast2);
+
+       return tmp & 0x1f;
+}
+
 static void b43_radio_init2056_pre(struct b43_wldev *dev)
 {
        b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
@@ -665,10 +919,8 @@ static void b43_radio_init2056_post(struct b43_wldev *dev)
        b43_radio_mask(dev, B2056_SYN_COM_RESET, ~0x2);
        b43_radio_mask(dev, B2056_SYN_PLL_MAST2, ~0xFC);
        b43_radio_mask(dev, B2056_SYN_RCCAL_CTRL0, ~0x1);
-       /*
-       if (nphy->init_por)
-               Call Radio 2056 Recalibrate
-       */
+       if (dev->phy.n->init_por)
+               b43_radio_2056_rcal(dev);
 }
 
 /*
@@ -680,6 +932,8 @@ static void b43_radio_init2056(struct b43_wldev *dev)
        b43_radio_init2056_pre(dev);
        b2056_upload_inittabs(dev, 0, 0);
        b43_radio_init2056_post(dev);
+
+       dev->phy.n->init_por = false;
 }
 
 /**************************************************
@@ -753,8 +1007,6 @@ static void b43_radio_init2055_post(struct b43_wldev *dev)
 {
        struct b43_phy_n *nphy = dev->phy.n;
        struct ssb_sprom *sprom = dev->dev->bus_sprom;
-       int i;
-       u16 val;
        bool workaround = false;
 
        if (sprom->revision < 4)
@@ -777,15 +1029,7 @@ static void b43_radio_init2055_post(struct b43_wldev *dev)
        b43_radio_set(dev, B2055_CAL_MISC, 0x1);
        msleep(1);
        b43_radio_set(dev, B2055_CAL_MISC, 0x40);
-       for (i = 0; i < 200; i++) {
-               val = b43_radio_read(dev, B2055_CAL_COUT2);
-               if (val & 0x80) {
-                       i = 0;
-                       break;
-               }
-               udelay(10);
-       }
-       if (i)
+       if (!b43_radio_wait_value(dev, B2055_CAL_COUT2, 0x80, 0x80, 10, 2000))
                b43err(dev->wl, "radio post init timeout\n");
        b43_radio_mask(dev, B2055_CAL_LPOCTL, 0xFF7F);
        b43_switch_channel(dev, dev->phy.channel);
@@ -1860,12 +2104,334 @@ static void b43_nphy_gain_ctl_workarounds_rev1_2(struct b43_wldev *dev)
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/WorkaroundsGainCtrl */
 static void b43_nphy_gain_ctl_workarounds(struct b43_wldev *dev)
 {
-       if (dev->phy.rev >= 3)
+       if (dev->phy.rev >= 7)
+               ; /* TODO */
+       else if (dev->phy.rev >= 3)
                b43_nphy_gain_ctl_workarounds_rev3plus(dev);
        else
                b43_nphy_gain_ctl_workarounds_rev1_2(dev);
 }
 
+/* http://bcm-v4.sipsolutions.net/PHY/N/Read_Lpf_Bw_Ctl */
+static u16 b43_nphy_read_lpf_ctl(struct b43_wldev *dev, u16 offset)
+{
+       if (!offset)
+               offset = (dev->phy.is_40mhz) ? 0x159 : 0x154;
+       return b43_ntab_read(dev, B43_NTAB16(7, offset)) & 0x7;
+}
+
+static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev)
+{
+       struct ssb_sprom *sprom = dev->dev->bus_sprom;
+       struct b43_phy *phy = &dev->phy;
+
+       u8 rx2tx_events_ipa[9] = { 0x0, 0x1, 0x2, 0x8, 0x5, 0x6, 0xF, 0x3,
+                                       0x1F };
+       u8 rx2tx_delays_ipa[9] = { 8, 6, 6, 4, 4, 16, 43, 1, 1 };
+
+       u16 ntab7_15e_16e[] = { 0x10f, 0x10f };
+       u8 ntab7_138_146[] = { 0x11, 0x11 };
+       u8 ntab7_133[] = { 0x77, 0x11, 0x11 };
+
+       u16 lpf_20, lpf_40, lpf_11b;
+       u16 bcap_val, bcap_val_11b, bcap_val_11n_20, bcap_val_11n_40;
+       u16 scap_val, scap_val_11b, scap_val_11n_20, scap_val_11n_40;
+       bool rccal_ovrd = false;
+
+       u16 rx2tx_lut_20_11b, rx2tx_lut_20_11n, rx2tx_lut_40_11n;
+       u16 bias, conv, filt;
+
+       u32 tmp32;
+       u8 core;
+
+       if (phy->rev == 7) {
+               b43_phy_set(dev, B43_NPHY_FINERX2_CGC, 0x10);
+               b43_phy_maskset(dev, B43_NPHY_FREQGAIN0, 0xFF80, 0x0020);
+               b43_phy_maskset(dev, B43_NPHY_FREQGAIN0, 0x80FF, 0x2700);
+               b43_phy_maskset(dev, B43_NPHY_FREQGAIN1, 0xFF80, 0x002E);
+               b43_phy_maskset(dev, B43_NPHY_FREQGAIN1, 0x80FF, 0x3300);
+               b43_phy_maskset(dev, B43_NPHY_FREQGAIN2, 0xFF80, 0x0037);
+               b43_phy_maskset(dev, B43_NPHY_FREQGAIN2, 0x80FF, 0x3A00);
+               b43_phy_maskset(dev, B43_NPHY_FREQGAIN3, 0xFF80, 0x003C);
+               b43_phy_maskset(dev, B43_NPHY_FREQGAIN3, 0x80FF, 0x3E00);
+               b43_phy_maskset(dev, B43_NPHY_FREQGAIN4, 0xFF80, 0x003E);
+               b43_phy_maskset(dev, B43_NPHY_FREQGAIN4, 0x80FF, 0x3F00);
+               b43_phy_maskset(dev, B43_NPHY_FREQGAIN5, 0xFF80, 0x0040);
+               b43_phy_maskset(dev, B43_NPHY_FREQGAIN5, 0x80FF, 0x4000);
+               b43_phy_maskset(dev, B43_NPHY_FREQGAIN6, 0xFF80, 0x0040);
+               b43_phy_maskset(dev, B43_NPHY_FREQGAIN6, 0x80FF, 0x4000);
+               b43_phy_maskset(dev, B43_NPHY_FREQGAIN7, 0xFF80, 0x0040);
+               b43_phy_maskset(dev, B43_NPHY_FREQGAIN7, 0x80FF, 0x4000);
+       }
+       if (phy->rev <= 8) {
+               b43_phy_write(dev, 0x23F, 0x1B0);
+               b43_phy_write(dev, 0x240, 0x1B0);
+       }
+       if (phy->rev >= 8)
+               b43_phy_maskset(dev, B43_NPHY_TXTAILCNT, ~0xFF, 0x72);
+
+       b43_ntab_write(dev, B43_NTAB16(8, 0x00), 2);
+       b43_ntab_write(dev, B43_NTAB16(8, 0x10), 2);
+       tmp32 = b43_ntab_read(dev, B43_NTAB32(30, 0));
+       tmp32 &= 0xffffff;
+       b43_ntab_write(dev, B43_NTAB32(30, 0), tmp32);
+       b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x15e), 2, ntab7_15e_16e);
+       b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x16e), 2, ntab7_15e_16e);
+
+       if (b43_nphy_ipa(dev))
+               b43_nphy_set_rf_sequence(dev, 0, rx2tx_events_ipa,
+                               rx2tx_delays_ipa, ARRAY_SIZE(rx2tx_events_ipa));
+
+       b43_phy_maskset(dev, 0x299, 0x3FFF, 0x4000);
+       b43_phy_maskset(dev, 0x29D, 0x3FFF, 0x4000);
+
+       lpf_20 = b43_nphy_read_lpf_ctl(dev, 0x154);
+       lpf_40 = b43_nphy_read_lpf_ctl(dev, 0x159);
+       lpf_11b = b43_nphy_read_lpf_ctl(dev, 0x152);
+       if (b43_nphy_ipa(dev)) {
+               if ((phy->radio_rev == 5 && phy->is_40mhz) ||
+                   phy->radio_rev == 7 || phy->radio_rev == 8) {
+                       bcap_val = b43_radio_read(dev, 0x16b);
+                       scap_val = b43_radio_read(dev, 0x16a);
+                       scap_val_11b = scap_val;
+                       bcap_val_11b = bcap_val;
+                       if (phy->radio_rev == 5 && phy->is_40mhz) {
+                               scap_val_11n_20 = scap_val;
+                               bcap_val_11n_20 = bcap_val;
+                               scap_val_11n_40 = bcap_val_11n_40 = 0xc;
+                               rccal_ovrd = true;
+                       } else { /* Rev 7/8 */
+                               lpf_20 = 4;
+                               lpf_11b = 1;
+                               if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+                                       scap_val_11n_20 = 0xc;
+                                       bcap_val_11n_20 = 0xc;
+                                       scap_val_11n_40 = 0xa;
+                                       bcap_val_11n_40 = 0xa;
+                               } else {
+                                       scap_val_11n_20 = 0x14;
+                                       bcap_val_11n_20 = 0x14;
+                                       scap_val_11n_40 = 0xf;
+                                       bcap_val_11n_40 = 0xf;
+                               }
+                               rccal_ovrd = true;
+                       }
+               }
+       } else {
+               if (phy->radio_rev == 5) {
+                       lpf_20 = 1;
+                       lpf_40 = 3;
+                       bcap_val = b43_radio_read(dev, 0x16b);
+                       scap_val = b43_radio_read(dev, 0x16a);
+                       scap_val_11b = scap_val;
+                       bcap_val_11b = bcap_val;
+                       scap_val_11n_20 = 0x11;
+                       scap_val_11n_40 = 0x11;
+                       bcap_val_11n_20 = 0x13;
+                       bcap_val_11n_40 = 0x13;
+                       rccal_ovrd = true;
+               }
+       }
+       if (rccal_ovrd) {
+               rx2tx_lut_20_11b = (bcap_val_11b << 8) |
+                                  (scap_val_11b << 3) |
+                                  lpf_11b;
+               rx2tx_lut_20_11n = (bcap_val_11n_20 << 8) |
+                                  (scap_val_11n_20 << 3) |
+                                  lpf_20;
+               rx2tx_lut_40_11n = (bcap_val_11n_40 << 8) |
+                                  (scap_val_11n_40 << 3) |
+                                  lpf_40;
+               for (core = 0; core < 2; core++) {
+                       b43_ntab_write(dev, B43_NTAB16(7, 0x152 + core * 16),
+                                      rx2tx_lut_20_11b);
+                       b43_ntab_write(dev, B43_NTAB16(7, 0x153 + core * 16),
+                                      rx2tx_lut_20_11n);
+                       b43_ntab_write(dev, B43_NTAB16(7, 0x154 + core * 16),
+                                      rx2tx_lut_20_11n);
+                       b43_ntab_write(dev, B43_NTAB16(7, 0x155 + core * 16),
+                                      rx2tx_lut_40_11n);
+                       b43_ntab_write(dev, B43_NTAB16(7, 0x156 + core * 16),
+                                      rx2tx_lut_40_11n);
+                       b43_ntab_write(dev, B43_NTAB16(7, 0x157 + core * 16),
+                                      rx2tx_lut_40_11n);
+                       b43_ntab_write(dev, B43_NTAB16(7, 0x158 + core * 16),
+                                      rx2tx_lut_40_11n);
+                       b43_ntab_write(dev, B43_NTAB16(7, 0x159 + core * 16),
+                                      rx2tx_lut_40_11n);
+               }
+               b43_nphy_rf_control_override_rev7(dev, 16, 1, 3, false, 2);
+       }
+       b43_phy_write(dev, 0x32F, 0x3);
+       if (phy->radio_rev == 4 || phy->radio_rev == 6)
+               b43_nphy_rf_control_override_rev7(dev, 4, 1, 3, false, 0);
+
+       if (phy->radio_rev == 3 || phy->radio_rev == 4 || phy->radio_rev == 6) {
+               if (sprom->revision &&
+                   sprom->boardflags2_hi & B43_BFH2_IPALVLSHIFT_3P3) {
+                       b43_radio_write(dev, 0x5, 0x05);
+                       b43_radio_write(dev, 0x6, 0x30);
+                       b43_radio_write(dev, 0x7, 0x00);
+                       b43_radio_set(dev, 0x4f, 0x1);
+                       b43_radio_set(dev, 0xd4, 0x1);
+                       bias = 0x1f;
+                       conv = 0x6f;
+                       filt = 0xaa;
+               } else {
+                       bias = 0x2b;
+                       conv = 0x7f;
+                       filt = 0xee;
+               }
+               if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+                       for (core = 0; core < 2; core++) {
+                               if (core == 0) {
+                                       b43_radio_write(dev, 0x5F, bias);
+                                       b43_radio_write(dev, 0x64, conv);
+                                       b43_radio_write(dev, 0x66, filt);
+                               } else {
+                                       b43_radio_write(dev, 0xE8, bias);
+                                       b43_radio_write(dev, 0xE9, conv);
+                                       b43_radio_write(dev, 0xEB, filt);
+                               }
+                       }
+               }
+       }
+
+       if (b43_nphy_ipa(dev)) {
+               if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+                       if (phy->radio_rev == 3 || phy->radio_rev == 4 ||
+                           phy->radio_rev == 6) {
+                               for (core = 0; core < 2; core++) {
+                                       if (core == 0)
+                                               b43_radio_write(dev, 0x51,
+                                                               0x7f);
+                                       else
+                                               b43_radio_write(dev, 0xd6,
+                                                               0x7f);
+                               }
+                       }
+                       if (phy->radio_rev == 3) {
+                               for (core = 0; core < 2; core++) {
+                                       if (core == 0) {
+                                               b43_radio_write(dev, 0x64,
+                                                               0x13);
+                                               b43_radio_write(dev, 0x5F,
+                                                               0x1F);
+                                               b43_radio_write(dev, 0x66,
+                                                               0xEE);
+                                               b43_radio_write(dev, 0x59,
+                                                               0x8A);
+                                               b43_radio_write(dev, 0x80,
+                                                               0x3E);
+                                       } else {
+                                               b43_radio_write(dev, 0x69,
+                                                               0x13);
+                                               b43_radio_write(dev, 0xE8,
+                                                               0x1F);
+                                               b43_radio_write(dev, 0xEB,
+                                                               0xEE);
+                                               b43_radio_write(dev, 0xDE,
+                                                               0x8A);
+                                               b43_radio_write(dev, 0x105,
+                                                               0x3E);
+                                       }
+                               }
+                       } else if (phy->radio_rev == 7 || phy->radio_rev == 8) {
+                               if (!phy->is_40mhz) {
+                                       b43_radio_write(dev, 0x5F, 0x14);
+                                       b43_radio_write(dev, 0xE8, 0x12);
+                               } else {
+                                       b43_radio_write(dev, 0x5F, 0x16);
+                                       b43_radio_write(dev, 0xE8, 0x16);
+                               }
+                       }
+               } else {
+                       u16 freq = phy->channel_freq;
+                       if ((freq >= 5180 && freq <= 5230) ||
+                           (freq >= 5745 && freq <= 5805)) {
+                               b43_radio_write(dev, 0x7D, 0xFF);
+                               b43_radio_write(dev, 0xFE, 0xFF);
+                       }
+               }
+       } else {
+               if (phy->radio_rev != 5) {
+                       for (core = 0; core < 2; core++) {
+                               if (core == 0) {
+                                       b43_radio_write(dev, 0x5c, 0x61);
+                                       b43_radio_write(dev, 0x51, 0x70);
+                               } else {
+                                       b43_radio_write(dev, 0xe1, 0x61);
+                                       b43_radio_write(dev, 0xd6, 0x70);
+                               }
+                       }
+               }
+       }
+
+       if (phy->radio_rev == 4) {
+               b43_ntab_write(dev, B43_NTAB16(8, 0x05), 0x20);
+               b43_ntab_write(dev, B43_NTAB16(8, 0x15), 0x20);
+               for (core = 0; core < 2; core++) {
+                       if (core == 0) {
+                               b43_radio_write(dev, 0x1a1, 0x00);
+                               b43_radio_write(dev, 0x1a2, 0x3f);
+                               b43_radio_write(dev, 0x1a6, 0x3f);
+                       } else {
+                               b43_radio_write(dev, 0x1a7, 0x00);
+                               b43_radio_write(dev, 0x1ab, 0x3f);
+                               b43_radio_write(dev, 0x1ac, 0x3f);
+                       }
+               }
+       } else {
+               b43_phy_set(dev, B43_NPHY_AFECTL_C1, 0x4);
+               b43_phy_set(dev, B43_NPHY_AFECTL_OVER1, 0x4);
+               b43_phy_set(dev, B43_NPHY_AFECTL_C2, 0x4);
+               b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x4);
+
+               b43_phy_mask(dev, B43_NPHY_AFECTL_C1, ~0x1);
+               b43_phy_set(dev, B43_NPHY_AFECTL_OVER1, 0x1);
+               b43_phy_mask(dev, B43_NPHY_AFECTL_C2, ~0x1);
+               b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x1);
+               b43_ntab_write(dev, B43_NTAB16(8, 0x05), 0x20);
+               b43_ntab_write(dev, B43_NTAB16(8, 0x15), 0x20);
+
+               b43_phy_mask(dev, B43_NPHY_AFECTL_C1, ~0x4);
+               b43_phy_mask(dev, B43_NPHY_AFECTL_OVER1, ~0x4);
+               b43_phy_mask(dev, B43_NPHY_AFECTL_C2, ~0x4);
+               b43_phy_mask(dev, B43_NPHY_AFECTL_OVER, ~0x4);
+       }
+
+       b43_phy_write(dev, B43_NPHY_ENDROP_TLEN, 0x2);
+
+       b43_ntab_write(dev, B43_NTAB32(16, 0x100), 20);
+       b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x138), 2, ntab7_138_146);
+       b43_ntab_write(dev, B43_NTAB16(7, 0x141), 0x77);
+       b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x133), 3, ntab7_133);
+       b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x146), 2, ntab7_138_146);
+       b43_ntab_write(dev, B43_NTAB16(7, 0x123), 0x77);
+       b43_ntab_write(dev, B43_NTAB16(7, 0x12A), 0x77);
+
+       if (!phy->is_40mhz) {
+               b43_ntab_write(dev, B43_NTAB32(16, 0x03), 0x18D);
+               b43_ntab_write(dev, B43_NTAB32(16, 0x7F), 0x18D);
+       } else {
+               b43_ntab_write(dev, B43_NTAB32(16, 0x03), 0x14D);
+               b43_ntab_write(dev, B43_NTAB32(16, 0x7F), 0x14D);
+       }
+
+       b43_nphy_gain_ctl_workarounds(dev);
+
+       /* TODO
+       b43_ntab_write_bulk(dev, B43_NTAB16(8, 0x08), 4,
+                           aux_adc_vmid_rev7_core0);
+       b43_ntab_write_bulk(dev, B43_NTAB16(8, 0x18), 4,
+                           aux_adc_vmid_rev7_core1);
+       b43_ntab_write_bulk(dev, B43_NTAB16(8, 0x0C), 4,
+                           aux_adc_gain_rev7);
+       b43_ntab_write_bulk(dev, B43_NTAB16(8, 0x1C), 4,
+                           aux_adc_gain_rev7);
+       */
+}
+
 static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev)
 {
        struct b43_phy_n *nphy = dev->phy.n;
@@ -1916,7 +2482,7 @@ static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev)
                        rx2tx_delays[6] = 1;
                        rx2tx_events[7] = 0x1F;
                }
-               b43_nphy_set_rf_sequence(dev, 1, rx2tx_events, rx2tx_delays,
+               b43_nphy_set_rf_sequence(dev, 0, rx2tx_events, rx2tx_delays,
                                         ARRAY_SIZE(rx2tx_events));
        }
 
@@ -1926,8 +2492,13 @@ static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev)
 
        b43_phy_maskset(dev, 0x294, 0xF0FF, 0x0700);
 
-       b43_ntab_write(dev, B43_NTAB32(16, 3), 0x18D);
-       b43_ntab_write(dev, B43_NTAB32(16, 127), 0x18D);
+       if (!dev->phy.is_40mhz) {
+               b43_ntab_write(dev, B43_NTAB32(16, 3), 0x18D);
+               b43_ntab_write(dev, B43_NTAB32(16, 127), 0x18D);
+       } else {
+               b43_ntab_write(dev, B43_NTAB32(16, 3), 0x14D);
+               b43_ntab_write(dev, B43_NTAB32(16, 127), 0x14D);
+       }
 
        b43_nphy_gain_ctl_workarounds(dev);
 
@@ -1963,13 +2534,14 @@ static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev)
        b43_ntab_write(dev, B43_NTAB32(30, 3), tmp32);
 
        if (dev->phy.rev == 4 &&
-               b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
+           b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
                b43_radio_write(dev, B2056_TX0 | B2056_TX_GMBB_IDAC,
                                0x70);
                b43_radio_write(dev, B2056_TX1 | B2056_TX_GMBB_IDAC,
                                0x70);
        }
 
+       /* Dropped probably-always-true condition */
        b43_phy_write(dev, 0x224, 0x03eb);
        b43_phy_write(dev, 0x225, 0x03eb);
        b43_phy_write(dev, 0x226, 0x0341);
@@ -1982,6 +2554,9 @@ static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev)
        b43_phy_write(dev, 0x22d, 0x042b);
        b43_phy_write(dev, 0x22e, 0x0381);
        b43_phy_write(dev, 0x22f, 0x0381);
+
+       if (dev->phy.rev >= 6 && sprom->boardflags2_lo & B43_BFL2_SINGLEANT_CCK)
+               ; /* TODO: 0x0080000000000000 HF */
 }
 
 static void b43_nphy_workarounds_rev1_2(struct b43_wldev *dev)
@@ -1996,6 +2571,12 @@ static void b43_nphy_workarounds_rev1_2(struct b43_wldev *dev)
        u8 events2[7] = { 0x0, 0x3, 0x5, 0x4, 0x2, 0x1, 0x8 };
        u8 delays2[7] = { 0x8, 0x6, 0x2, 0x4, 0x4, 0x6, 0x1 };
 
+       if (sprom->boardflags2_lo & B43_BFL2_SKWRKFEM_BRD ||
+           dev->dev->board_type == 0x8B) {
+               delays1[0] = 0x1;
+               delays1[5] = 0x14;
+       }
+
        if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ &&
            nphy->band5g_pwrgain) {
                b43_radio_mask(dev, B2055_C1_TX_RF_SPARE, ~0x8);
@@ -2007,8 +2588,10 @@ static void b43_nphy_workarounds_rev1_2(struct b43_wldev *dev)
 
        b43_ntab_write(dev, B43_NTAB16(8, 0x00), 0x000A);
        b43_ntab_write(dev, B43_NTAB16(8, 0x10), 0x000A);
-       b43_ntab_write(dev, B43_NTAB16(8, 0x02), 0xCDAA);
-       b43_ntab_write(dev, B43_NTAB16(8, 0x12), 0xCDAA);
+       if (dev->phy.rev < 3) {
+               b43_ntab_write(dev, B43_NTAB16(8, 0x02), 0xCDAA);
+               b43_ntab_write(dev, B43_NTAB16(8, 0x12), 0xCDAA);
+       }
 
        if (dev->phy.rev < 2) {
                b43_ntab_write(dev, B43_NTAB16(8, 0x08), 0x0000);
@@ -2024,11 +2607,6 @@ static void b43_nphy_workarounds_rev1_2(struct b43_wldev *dev)
        b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8);
        b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0x301);
 
-       if (sprom->boardflags2_lo & B43_BFL2_SKWRKFEM_BRD &&
-           dev->dev->board_type == 0x8B) {
-               delays1[0] = 0x1;
-               delays1[5] = 0x14;
-       }
        b43_nphy_set_rf_sequence(dev, 0, events1, delays1, 7);
        b43_nphy_set_rf_sequence(dev, 1, events2, delays2, 7);
 
@@ -2055,11 +2633,13 @@ static void b43_nphy_workarounds_rev1_2(struct b43_wldev *dev)
        b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0xCD);
        b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20);
 
-       b43_phy_mask(dev, B43_NPHY_PIL_DW1,
-                       ~B43_NPHY_PIL_DW_64QAM & 0xFFFF);
-       b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B1, 0xB5);
-       b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B2, 0xA4);
-       b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B3, 0x00);
+       if (dev->phy.rev < 3) {
+               b43_phy_mask(dev, B43_NPHY_PIL_DW1,
+                            ~B43_NPHY_PIL_DW_64QAM & 0xFFFF);
+               b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B1, 0xB5);
+               b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B2, 0xA4);
+               b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B3, 0x00);
+       }
 
        if (dev->phy.rev == 2)
                b43_phy_set(dev, B43_NPHY_FINERX2_CGC,
@@ -2083,7 +2663,9 @@ static void b43_nphy_workarounds(struct b43_wldev *dev)
        b43_phy_set(dev, B43_NPHY_IQFLIP,
                    B43_NPHY_IQFLIP_ADC1 | B43_NPHY_IQFLIP_ADC2);
 
-       if (dev->phy.rev >= 3)
+       if (dev->phy.rev >= 7)
+               b43_nphy_workarounds_rev7plus(dev);
+       else if (dev->phy.rev >= 3)
                b43_nphy_workarounds_rev3plus(dev);
        else
                b43_nphy_workarounds_rev1_2(dev);
@@ -2542,7 +3124,7 @@ static void b43_nphy_tx_power_ctl_idle_tssi(struct b43_wldev *dev)
                b43_nphy_ipa_internal_tssi_setup(dev);
 
        if (phy->rev >= 7)
-               ; /* TODO: Override Rev7 with 0x2000, 0, 3, 0, 0 as arguments */
+               b43_nphy_rf_control_override_rev7(dev, 0x2000, 0, 3, false, 0);
        else if (phy->rev >= 3)
                b43_nphy_rf_control_override(dev, 0x2000, 0, 3, false);
 
@@ -2554,7 +3136,7 @@ static void b43_nphy_tx_power_ctl_idle_tssi(struct b43_wldev *dev)
        b43_nphy_rssi_select(dev, 0, 0);
 
        if (phy->rev >= 7)
-               ; /* TODO: Override Rev7 with 0x2000, 0, 3, 1, 0 as arguments */
+               b43_nphy_rf_control_override_rev7(dev, 0x2000, 0, 3, true, 0);
        else if (phy->rev >= 3)
                b43_nphy_rf_control_override(dev, 0x2000, 0, 3, true);
 
@@ -4761,6 +5343,7 @@ static void b43_nphy_op_prepare_structs(struct b43_wldev *dev)
        nphy->hang_avoid = (phy->rev == 3 || phy->rev == 4);
        nphy->spur_avoid = (phy->rev >= 3) ?
                                B43_SPUR_AVOID_AUTO : B43_SPUR_AVOID_DISABLE;
+       nphy->init_por = true;
        nphy->gain_boost = true; /* this way we follow wl, assume it is true */
        nphy->txrx_chain = 2; /* sth different than 0 and 1 for now */
        nphy->phyrxchain = 3; /* to avoid b43_nphy_set_rx_core_state like wl */
@@ -4801,6 +5384,8 @@ static void b43_nphy_op_prepare_structs(struct b43_wldev *dev)
                nphy->ipa2g_on = sprom->fem.ghz2.extpa_gain == 2;
                nphy->ipa5g_on = sprom->fem.ghz5.extpa_gain == 2;
        }
+
+       nphy->init_por = true;
 }
 
 static void b43_nphy_op_free(struct b43_wldev *dev)
@@ -4887,7 +5472,9 @@ static void b43_nphy_op_software_rfkill(struct b43_wldev *dev,
        if (blocked) {
                b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
                                ~B43_NPHY_RFCTL_CMD_CHIP0PU);
-               if (dev->phy.rev >= 3) {
+               if (dev->phy.rev >= 7) {
+                       /* TODO */
+               } else if (dev->phy.rev >= 3) {
                        b43_radio_mask(dev, 0x09, ~0x2);
 
                        b43_radio_write(dev, 0x204D, 0);
@@ -4905,7 +5492,10 @@ static void b43_nphy_op_software_rfkill(struct b43_wldev *dev,
                        b43_radio_write(dev, 0x3064, 0);
                }
        } else {
-               if (dev->phy.rev >= 3) {
+               if (dev->phy.rev >= 7) {
+                       b43_radio_2057_init(dev);
+                       b43_switch_channel(dev, dev->phy.channel);
+               } else if (dev->phy.rev >= 3) {
                        b43_radio_init2056(dev);
                        b43_switch_channel(dev, dev->phy.channel);
                } else {
index fd12b386fea1cc5a1c0796589b650d12e6917fcf..092c0140c2490d777056399db075cfcbb24a2855 100644 (file)
@@ -785,6 +785,7 @@ struct b43_phy_n {
        u16 papd_epsilon_offset[2];
        s32 preamble_override;
        u32 bb_mult_save;
+       bool init_por;
 
        bool gain_boost;
        bool elna_gain_config;
diff --git a/drivers/net/wireless/b43/radio_2057.c b/drivers/net/wireless/b43/radio_2057.c
new file mode 100644 (file)
index 0000000..d61d683
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+
+  Broadcom B43 wireless driver
+  IEEE 802.11n 2057 radio device data tables
+
+  Copyright (c) 2010 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 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; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43.h"
+#include "radio_2057.h"
+#include "phy_common.h"
+
+static u16 r2057_rev4_init[42][2] = {
+       { 0x0E, 0x20 }, { 0x31, 0x00 }, { 0x32, 0x00 }, { 0x33, 0x00 },
+       { 0x35, 0x26 }, { 0x3C, 0xff }, { 0x3D, 0xff }, { 0x3E, 0xff },
+       { 0x3F, 0xff }, { 0x62, 0x33 }, { 0x8A, 0xf0 }, { 0x8B, 0x10 },
+       { 0x8C, 0xf0 }, { 0x91, 0x3f }, { 0x92, 0x36 }, { 0xA4, 0x8c },
+       { 0xA8, 0x55 }, { 0xAF, 0x01 }, { 0x10F, 0xf0 }, { 0x110, 0x10 },
+       { 0x111, 0xf0 }, { 0x116, 0x3f }, { 0x117, 0x36 }, { 0x129, 0x8c },
+       { 0x12D, 0x55 }, { 0x134, 0x01 }, { 0x15E, 0x00 }, { 0x15F, 0x00 },
+       { 0x160, 0x00 }, { 0x161, 0x00 }, { 0x162, 0x00 }, { 0x163, 0x00 },
+       { 0x169, 0x02 }, { 0x16A, 0x00 }, { 0x16B, 0x00 }, { 0x16C, 0x00 },
+       { 0x1A4, 0x00 }, { 0x1A5, 0x00 }, { 0x1A6, 0x00 }, { 0x1AA, 0x00 },
+       { 0x1AB, 0x00 }, { 0x1AC, 0x00 },
+};
+
+static u16 r2057_rev5_init[44][2] = {
+       { 0x00, 0x00 }, { 0x01, 0x57 }, { 0x02, 0x20 }, { 0x23, 0x6 },
+       { 0x31, 0x00 }, { 0x32, 0x00 }, { 0x33, 0x00 }, { 0x51, 0x70 },
+       { 0x59, 0x88 }, { 0x5C, 0x20 }, { 0x62, 0x33 }, { 0x63, 0x0f },
+       { 0x64, 0x0f }, { 0x81, 0x01 }, { 0x91, 0x3f }, { 0x92, 0x36 },
+       { 0xA1, 0x20 }, { 0xD6, 0x70 }, { 0xDE, 0x88 }, { 0xE1, 0x20 },
+       { 0xE8, 0x0f }, { 0xE9, 0x0f }, { 0x106, 0x01 }, { 0x116, 0x3f },
+       { 0x117, 0x36 }, { 0x126, 0x20 }, { 0x15E, 0x00 }, { 0x15F, 0x00 },
+       { 0x160, 0x00 }, { 0x161, 0x00 }, { 0x162, 0x00 }, { 0x163, 0x00 },
+       { 0x16A, 0x00 }, { 0x16B, 0x00 }, { 0x16C, 0x00 }, { 0x1A4, 0x00 },
+       { 0x1A5, 0x00 }, { 0x1A6, 0x00 }, { 0x1AA, 0x00 }, { 0x1AB, 0x00 },
+       { 0x1AC, 0x00 }, { 0x1B7, 0x0c }, { 0x1C1, 0x01 }, { 0x1C2, 0x80 },
+};
+
+static u16 r2057_rev5a_init[45][2] = {
+       { 0x00, 0x15 }, { 0x01, 0x57 }, { 0x02, 0x20 }, { 0x23, 0x6 },
+       { 0x31, 0x00 }, { 0x32, 0x00 }, { 0x33, 0x00 }, { 0x51, 0x70 },
+       { 0x59, 0x88 }, { 0x5C, 0x20 }, { 0x62, 0x33 }, { 0x63, 0x0f },
+       { 0x64, 0x0f }, { 0x81, 0x01 }, { 0x91, 0x3f }, { 0x92, 0x36 },
+       { 0xC9, 0x01 }, { 0xD6, 0x70 }, { 0xDE, 0x88 }, { 0xE1, 0x20 },
+       { 0xE8, 0x0f }, { 0xE9, 0x0f }, { 0x106, 0x01 }, { 0x116, 0x3f },
+       { 0x117, 0x36 }, { 0x126, 0x20 }, { 0x14E, 0x01 }, { 0x15E, 0x00 },
+       { 0x15F, 0x00 }, { 0x160, 0x00 }, { 0x161, 0x00 }, { 0x162, 0x00 },
+       { 0x163, 0x00 }, { 0x16A, 0x00 }, { 0x16B, 0x00 }, { 0x16C, 0x00 },
+       { 0x1A4, 0x00 }, { 0x1A5, 0x00 }, { 0x1A6, 0x00 }, { 0x1AA, 0x00 },
+       { 0x1AB, 0x00 }, { 0x1AC, 0x00 }, { 0x1B7, 0x0c }, { 0x1C1, 0x01 },
+       { 0x1C2, 0x80 },
+};
+
+static u16 r2057_rev7_init[54][2] = {
+       { 0x00, 0x00 }, { 0x01, 0x57 }, { 0x02, 0x20 }, { 0x31, 0x00 },
+       { 0x32, 0x00 }, { 0x33, 0x00 }, { 0x51, 0x70 }, { 0x59, 0x88 },
+       { 0x5C, 0x20 }, { 0x62, 0x33 }, { 0x63, 0x0f }, { 0x64, 0x13 },
+       { 0x66, 0xee }, { 0x6E, 0x58 }, { 0x75, 0x13 }, { 0x7B, 0x13 },
+       { 0x7C, 0x14 }, { 0x7D, 0xee }, { 0x81, 0x01 }, { 0x91, 0x3f },
+       { 0x92, 0x36 }, { 0xA1, 0x20 }, { 0xD6, 0x70 }, { 0xDE, 0x88 },
+       { 0xE1, 0x20 }, { 0xE8, 0x0f }, { 0xE9, 0x13 }, { 0xEB, 0xee },
+       { 0xF3, 0x58 }, { 0xFA, 0x13 }, { 0x100, 0x13 }, { 0x101, 0x14 },
+       { 0x102, 0xee }, { 0x106, 0x01 }, { 0x116, 0x3f }, { 0x117, 0x36 },
+       { 0x126, 0x20 }, { 0x15E, 0x00 }, { 0x15F, 0x00 }, { 0x160, 0x00 },
+       { 0x161, 0x00 }, { 0x162, 0x00 }, { 0x163, 0x00 }, { 0x16A, 0x00 },
+       { 0x16B, 0x00 }, { 0x16C, 0x00 }, { 0x1A4, 0x00 }, { 0x1A5, 0x00 },
+       { 0x1A6, 0x00 }, { 0x1AA, 0x00 }, { 0x1AB, 0x00 }, { 0x1AC, 0x00 },
+       { 0x1B7, 0x05 }, { 0x1C2, 0xa0 },
+};
+
+static u16 r2057_rev8_init[54][2] = {
+       { 0x00, 0x08 }, { 0x01, 0x57 }, { 0x02, 0x20 }, { 0x31, 0x00 },
+       { 0x32, 0x00 }, { 0x33, 0x00 }, { 0x51, 0x70 }, { 0x59, 0x88 },
+       { 0x5C, 0x20 }, { 0x62, 0x33 }, { 0x63, 0x0f }, { 0x64, 0x0f },
+       { 0x6E, 0x58 }, { 0x75, 0x13 }, { 0x7B, 0x13 }, { 0x7C, 0x0f },
+       { 0x7D, 0xee }, { 0x81, 0x01 }, { 0x91, 0x3f }, { 0x92, 0x36 },
+       { 0xA1, 0x20 }, { 0xC9, 0x01 }, { 0xD6, 0x70 }, { 0xDE, 0x88 },
+       { 0xE1, 0x20 }, { 0xE8, 0x0f }, { 0xE9, 0x0f }, { 0xF3, 0x58 },
+       { 0xFA, 0x13 }, { 0x100, 0x13 }, { 0x101, 0x0f }, { 0x102, 0xee },
+       { 0x106, 0x01 }, { 0x116, 0x3f }, { 0x117, 0x36 }, { 0x126, 0x20 },
+       { 0x14E, 0x01 }, { 0x15E, 0x00 }, { 0x15F, 0x00 }, { 0x160, 0x00 },
+       { 0x161, 0x00 }, { 0x162, 0x00 }, { 0x163, 0x00 }, { 0x16A, 0x00 },
+       { 0x16B, 0x00 }, { 0x16C, 0x00 }, { 0x1A4, 0x00 }, { 0x1A5, 0x00 },
+       { 0x1A6, 0x00 }, { 0x1AA, 0x00 }, { 0x1AB, 0x00 }, { 0x1AC, 0x00 },
+       { 0x1B7, 0x05 }, { 0x1C2, 0xa0 },
+};
+
+void r2057_upload_inittabs(struct b43_wldev *dev)
+{
+       struct b43_phy *phy = &dev->phy;
+       u16 *table = NULL;
+       u16 size, i;
+
+       if (phy->rev == 7) {
+               table = r2057_rev4_init[0];
+               size = ARRAY_SIZE(r2057_rev4_init);
+       } else if (phy->rev == 8 || phy->rev == 9) {
+               if (phy->radio_rev == 5) {
+                       if (phy->radio_rev == 8) {
+                               table = r2057_rev5_init[0];
+                               size = ARRAY_SIZE(r2057_rev5_init);
+                       } else {
+                               table = r2057_rev5a_init[0];
+                               size = ARRAY_SIZE(r2057_rev5a_init);
+                       }
+               } else if (phy->radio_rev == 7) {
+                       table = r2057_rev7_init[0];
+                       size = ARRAY_SIZE(r2057_rev7_init);
+               } else if (phy->radio_rev == 9) {
+                       table = r2057_rev8_init[0];
+                       size = ARRAY_SIZE(r2057_rev8_init);
+               }
+       }
+
+       if (table) {
+               for (i = 0; i < 10; i++) {
+                       pr_info("radio_write 0x%X ", *table);
+                       table++;
+                       pr_info("0x%X\n", *table);
+                       table++;
+               }
+       }
+}
diff --git a/drivers/net/wireless/b43/radio_2057.h b/drivers/net/wireless/b43/radio_2057.h
new file mode 100644 (file)
index 0000000..eeebd8f
--- /dev/null
@@ -0,0 +1,430 @@
+#ifndef B43_RADIO_2057_H_
+#define B43_RADIO_2057_H_
+
+#include <linux/types.h>
+
+#include "tables_nphy.h"
+
+#define R2057_DACBUF_VINCM_CORE0               0x000
+#define R2057_IDCODE                           0x001
+#define R2057_RCCAL_MASTER                     0x002
+#define R2057_RCCAL_CAP_SIZE                   0x003
+#define R2057_RCAL_CONFIG                      0x004
+#define R2057_GPAIO_CONFIG                     0x005
+#define R2057_GPAIO_SEL1                       0x006
+#define R2057_GPAIO_SEL0                       0x007
+#define R2057_CLPO_CONFIG                      0x008
+#define R2057_BANDGAP_CONFIG                   0x009
+#define R2057_BANDGAP_RCAL_TRIM                        0x00a
+#define R2057_AFEREG_CONFIG                    0x00b
+#define R2057_TEMPSENSE_CONFIG                 0x00c
+#define R2057_XTAL_CONFIG1                     0x00d
+#define R2057_XTAL_ICORE_SIZE                  0x00e
+#define R2057_XTAL_BUF_SIZE                    0x00f
+#define R2057_XTAL_PULLCAP_SIZE                        0x010
+#define R2057_RFPLL_MASTER                     0x011
+#define R2057_VCOMONITOR_VTH_L                 0x012
+#define R2057_VCOMONITOR_VTH_H                 0x013
+#define R2057_VCOCAL_BIASRESET_RFPLLREG_VOUT   0x014
+#define R2057_VCO_VARCSIZE_IDAC                        0x015
+#define R2057_VCOCAL_COUNTVAL0                 0x016
+#define R2057_VCOCAL_COUNTVAL1                 0x017
+#define R2057_VCOCAL_INTCLK_COUNT              0x018
+#define R2057_VCOCAL_MASTER                    0x019
+#define R2057_VCOCAL_NUMCAPCHANGE              0x01a
+#define R2057_VCOCAL_WINSIZE                   0x01b
+#define R2057_VCOCAL_DELAY_AFTER_REFRESH       0x01c
+#define R2057_VCOCAL_DELAY_AFTER_CLOSELOOP     0x01d
+#define R2057_VCOCAL_DELAY_AFTER_OPENLOOP      0x01e
+#define R2057_VCOCAL_DELAY_BEFORE_OPENLOOP     0x01f
+#define R2057_VCO_FORCECAPEN_FORCECAP1         0x020
+#define R2057_VCO_FORCECAP0                    0x021
+#define R2057_RFPLL_REFMASTER_SPAREXTALSIZE    0x022
+#define R2057_RFPLL_PFD_RESET_PW               0x023
+#define R2057_RFPLL_LOOPFILTER_R2              0x024
+#define R2057_RFPLL_LOOPFILTER_R1              0x025
+#define R2057_RFPLL_LOOPFILTER_C3              0x026
+#define R2057_RFPLL_LOOPFILTER_C2              0x027
+#define R2057_RFPLL_LOOPFILTER_C1              0x028
+#define R2057_CP_KPD_IDAC                      0x029
+#define R2057_RFPLL_IDACS                      0x02a
+#define R2057_RFPLL_MISC_EN                    0x02b
+#define R2057_RFPLL_MMD0                       0x02c
+#define R2057_RFPLL_MMD1                       0x02d
+#define R2057_RFPLL_MISC_CAL_RESETN            0x02e
+#define R2057_JTAGXTAL_SIZE_CPBIAS_FILTRES     0x02f
+#define R2057_VCO_ALCREF_BBPLLXTAL_SIZE                0x030
+#define R2057_VCOCAL_READCAP0                  0x031
+#define R2057_VCOCAL_READCAP1                  0x032
+#define R2057_VCOCAL_STATUS                    0x033
+#define R2057_LOGEN_PUS                                0x034
+#define R2057_LOGEN_PTAT_RESETS                        0x035
+#define R2057_VCOBUF_IDACS                     0x036
+#define R2057_VCOBUF_TUNE                      0x037
+#define R2057_CMOSBUF_TX2GQ_IDACS              0x038
+#define R2057_CMOSBUF_TX2GI_IDACS              0x039
+#define R2057_CMOSBUF_TX5GQ_IDACS              0x03a
+#define R2057_CMOSBUF_TX5GI_IDACS              0x03b
+#define R2057_CMOSBUF_RX2GQ_IDACS              0x03c
+#define R2057_CMOSBUF_RX2GI_IDACS              0x03d
+#define R2057_CMOSBUF_RX5GQ_IDACS              0x03e
+#define R2057_CMOSBUF_RX5GI_IDACS              0x03f
+#define R2057_LOGEN_MX2G_IDACS                 0x040
+#define R2057_LOGEN_MX2G_TUNE                  0x041
+#define R2057_LOGEN_MX5G_IDACS                 0x042
+#define R2057_LOGEN_MX5G_TUNE                  0x043
+#define R2057_LOGEN_MX5G_RCCR                  0x044
+#define R2057_LOGEN_INDBUF2G_IDAC              0x045
+#define R2057_LOGEN_INDBUF2G_IBOOST            0x046
+#define R2057_LOGEN_INDBUF2G_TUNE              0x047
+#define R2057_LOGEN_INDBUF5G_IDAC              0x048
+#define R2057_LOGEN_INDBUF5G_IBOOST            0x049
+#define R2057_LOGEN_INDBUF5G_TUNE              0x04a
+#define R2057_CMOSBUF_TX_RCCR                  0x04b
+#define R2057_CMOSBUF_RX_RCCR                  0x04c
+#define R2057_LOGEN_SEL_PKDET                  0x04d
+#define R2057_CMOSBUF_SHAREIQ_PTAT             0x04e
+#define R2057_RXTXBIAS_CONFIG_CORE0            0x04f
+#define R2057_TXGM_TXRF_PUS_CORE0              0x050
+#define R2057_TXGM_IDAC_BLEED_CORE0            0x051
+#define R2057_TXGM_GAIN_CORE0                  0x056
+#define R2057_TXGM2G_PKDET_PUS_CORE0           0x057
+#define R2057_PAD2G_PTATS_CORE0                        0x058
+#define R2057_PAD2G_IDACS_CORE0                        0x059
+#define R2057_PAD2G_BOOST_PU_CORE0             0x05a
+#define R2057_PAD2G_CASCV_GAIN_CORE0           0x05b
+#define R2057_TXMIX2G_TUNE_BOOST_PU_CORE0      0x05c
+#define R2057_TXMIX2G_LODC_CORE0               0x05d
+#define R2057_PAD2G_TUNE_PUS_CORE0             0x05e
+#define R2057_IPA2G_GAIN_CORE0                 0x05f
+#define R2057_TSSI2G_SPARE1_CORE0              0x060
+#define R2057_TSSI2G_SPARE2_CORE0              0x061
+#define R2057_IPA2G_TUNEV_CASCV_PTAT_CORE0     0x062
+#define R2057_IPA2G_IMAIN_CORE0                        0x063
+#define R2057_IPA2G_CASCONV_CORE0              0x064
+#define R2057_IPA2G_CASCOFFV_CORE0             0x065
+#define R2057_IPA2G_BIAS_FILTER_CORE0          0x066
+#define R2057_TX5G_PKDET_CORE0                 0x069
+#define R2057_PGA_PTAT_TXGM5G_PU_CORE0         0x06a
+#define R2057_PAD5G_PTATS1_CORE0               0x06b
+#define R2057_PAD5G_CLASS_PTATS2_CORE0         0x06c
+#define R2057_PGA_BOOSTPTAT_IMAIN_CORE0                0x06d
+#define R2057_PAD5G_CASCV_IMAIN_CORE0          0x06e
+#define R2057_TXMIX5G_IBOOST_PAD_IAUX_CORE0    0x06f
+#define R2057_PGA_BOOST_TUNE_CORE0             0x070
+#define R2057_PGA_GAIN_CORE0                   0x071
+#define R2057_PAD5G_CASCOFFV_GAIN_PUS_CORE0    0x072
+#define R2057_TXMIX5G_BOOST_TUNE_CORE0         0x073
+#define R2057_PAD5G_TUNE_MISC_PUS_CORE0                0x074
+#define R2057_IPA5G_IAUX_CORE0                 0x075
+#define R2057_IPA5G_GAIN_CORE0                 0x076
+#define R2057_TSSI5G_SPARE1_CORE0              0x077
+#define R2057_TSSI5G_SPARE2_CORE0              0x078
+#define R2057_IPA5G_CASCOFFV_PU_CORE0          0x079
+#define R2057_IPA5G_PTAT_CORE0                 0x07a
+#define R2057_IPA5G_IMAIN_CORE0                        0x07b
+#define R2057_IPA5G_CASCONV_CORE0              0x07c
+#define R2057_IPA5G_BIAS_FILTER_CORE0          0x07d
+#define R2057_PAD_BIAS_FILTER_BWS_CORE0                0x080
+#define R2057_TR2G_CONFIG1_CORE0_NU            0x081
+#define R2057_TR2G_CONFIG2_CORE0_NU            0x082
+#define R2057_LNA5G_RFEN_CORE0                 0x083
+#define R2057_TR5G_CONFIG2_CORE0_NU            0x084
+#define R2057_RXRFBIAS_IBOOST_PU_CORE0         0x085
+#define R2057_RXRF_IABAND_RXGM_IMAIN_PTAT_CORE0        0x086
+#define R2057_RXGM_CMFBITAIL_AUXPTAT_CORE0     0x087
+#define R2057_RXMIX_ICORE_RXGM_IAUX_CORE0      0x088
+#define R2057_RXMIX_CMFBITAIL_PU_CORE0         0x089
+#define R2057_LNA2_IMAIN_PTAT_PU_CORE0         0x08a
+#define R2057_LNA2_IAUX_PTAT_CORE0             0x08b
+#define R2057_LNA1_IMAIN_PTAT_PU_CORE0         0x08c
+#define R2057_LNA15G_INPUT_MATCH_TUNE_CORE0    0x08d
+#define R2057_RXRFBIAS_BANDSEL_CORE0           0x08e
+#define R2057_TIA_CONFIG_CORE0                 0x08f
+#define R2057_TIA_IQGAIN_CORE0                 0x090
+#define R2057_TIA_IBIAS2_CORE0                 0x091
+#define R2057_TIA_IBIAS1_CORE0                 0x092
+#define R2057_TIA_SPARE_Q_CORE0                        0x093
+#define R2057_TIA_SPARE_I_CORE0                        0x094
+#define R2057_RXMIX2G_PUS_CORE0                        0x095
+#define R2057_RXMIX2G_VCMREFS_CORE0            0x096
+#define R2057_RXMIX2G_LODC_QI_CORE0            0x097
+#define R2057_W12G_BW_LNA2G_PUS_CORE0          0x098
+#define R2057_LNA2G_GAIN_CORE0                 0x099
+#define R2057_LNA2G_TUNE_CORE0                 0x09a
+#define R2057_RXMIX5G_PUS_CORE0                        0x09b
+#define R2057_RXMIX5G_VCMREFS_CORE0            0x09c
+#define R2057_RXMIX5G_LODC_QI_CORE0            0x09d
+#define R2057_W15G_BW_LNA5G_PUS_CORE0          0x09e
+#define R2057_LNA5G_GAIN_CORE0                 0x09f
+#define R2057_LNA5G_TUNE_CORE0                 0x0a0
+#define R2057_LPFSEL_TXRX_RXBB_PUS_CORE0       0x0a1
+#define R2057_RXBB_BIAS_MASTER_CORE0           0x0a2
+#define R2057_RXBB_VGABUF_IDACS_CORE0          0x0a3
+#define R2057_LPF_VCMREF_TXBUF_VCMREF_CORE0    0x0a4
+#define R2057_TXBUF_VINCM_CORE0                        0x0a5
+#define R2057_TXBUF_IDACS_CORE0                        0x0a6
+#define R2057_LPF_RESP_RXBUF_BW_CORE0          0x0a7
+#define R2057_RXBB_CC_CORE0                    0x0a8
+#define R2057_RXBB_SPARE3_CORE0                        0x0a9
+#define R2057_RXBB_RCCAL_HPC_CORE0             0x0aa
+#define R2057_LPF_IDACS_CORE0                  0x0ab
+#define R2057_LPFBYP_DCLOOP_BYP_IDAC_CORE0     0x0ac
+#define R2057_TXBUF_GAIN_CORE0                 0x0ad
+#define R2057_AFELOOPBACK_AACI_RESP_CORE0      0x0ae
+#define R2057_RXBUF_DEGEN_CORE0                        0x0af
+#define R2057_RXBB_SPARE2_CORE0                        0x0b0
+#define R2057_RXBB_SPARE1_CORE0                        0x0b1
+#define R2057_RSSI_MASTER_CORE0                        0x0b2
+#define R2057_W2_MASTER_CORE0                  0x0b3
+#define R2057_NB_MASTER_CORE0                  0x0b4
+#define R2057_W2_IDACS0_Q_CORE0                        0x0b5
+#define R2057_W2_IDACS1_Q_CORE0                        0x0b6
+#define R2057_W2_IDACS0_I_CORE0                        0x0b7
+#define R2057_W2_IDACS1_I_CORE0                        0x0b8
+#define R2057_RSSI_GPAIOSEL_W1_IDACS_CORE0     0x0b9
+#define R2057_NB_IDACS_Q_CORE0                 0x0ba
+#define R2057_NB_IDACS_I_CORE0                 0x0bb
+#define R2057_BACKUP4_CORE0                    0x0c1
+#define R2057_BACKUP3_CORE0                    0x0c2
+#define R2057_BACKUP2_CORE0                    0x0c3
+#define R2057_BACKUP1_CORE0                    0x0c4
+#define R2057_SPARE16_CORE0                    0x0c5
+#define R2057_SPARE15_CORE0                    0x0c6
+#define R2057_SPARE14_CORE0                    0x0c7
+#define R2057_SPARE13_CORE0                    0x0c8
+#define R2057_SPARE12_CORE0                    0x0c9
+#define R2057_SPARE11_CORE0                    0x0ca
+#define R2057_TX2G_BIAS_RESETS_CORE0           0x0cb
+#define R2057_TX5G_BIAS_RESETS_CORE0           0x0cc
+#define R2057_IQTEST_SEL_PU                    0x0cd
+#define R2057_XTAL_CONFIG2                     0x0ce
+#define R2057_BUFS_MISC_LPFBW_CORE0            0x0cf
+#define R2057_TXLPF_RCCAL_CORE0                        0x0d0
+#define R2057_RXBB_GPAIOSEL_RXLPF_RCCAL_CORE0  0x0d1
+#define R2057_LPF_GAIN_CORE0                   0x0d2
+#define R2057_DACBUF_IDACS_BW_CORE0            0x0d3
+#define R2057_RXTXBIAS_CONFIG_CORE1            0x0d4
+#define R2057_TXGM_TXRF_PUS_CORE1              0x0d5
+#define R2057_TXGM_IDAC_BLEED_CORE1            0x0d6
+#define R2057_TXGM_GAIN_CORE1                  0x0db
+#define R2057_TXGM2G_PKDET_PUS_CORE1           0x0dc
+#define R2057_PAD2G_PTATS_CORE1                        0x0dd
+#define R2057_PAD2G_IDACS_CORE1                        0x0de
+#define R2057_PAD2G_BOOST_PU_CORE1             0x0df
+#define R2057_PAD2G_CASCV_GAIN_CORE1           0x0e0
+#define R2057_TXMIX2G_TUNE_BOOST_PU_CORE1      0x0e1
+#define R2057_TXMIX2G_LODC_CORE1               0x0e2
+#define R2057_PAD2G_TUNE_PUS_CORE1             0x0e3
+#define R2057_IPA2G_GAIN_CORE1                 0x0e4
+#define R2057_TSSI2G_SPARE1_CORE1              0x0e5
+#define R2057_TSSI2G_SPARE2_CORE1              0x0e6
+#define R2057_IPA2G_TUNEV_CASCV_PTAT_CORE1     0x0e7
+#define R2057_IPA2G_IMAIN_CORE1                        0x0e8
+#define R2057_IPA2G_CASCONV_CORE1              0x0e9
+#define R2057_IPA2G_CASCOFFV_CORE1             0x0ea
+#define R2057_IPA2G_BIAS_FILTER_CORE1          0x0eb
+#define R2057_TX5G_PKDET_CORE1                 0x0ee
+#define R2057_PGA_PTAT_TXGM5G_PU_CORE1         0x0ef
+#define R2057_PAD5G_PTATS1_CORE1               0x0f0
+#define R2057_PAD5G_CLASS_PTATS2_CORE1         0x0f1
+#define R2057_PGA_BOOSTPTAT_IMAIN_CORE1                0x0f2
+#define R2057_PAD5G_CASCV_IMAIN_CORE1          0x0f3
+#define R2057_TXMIX5G_IBOOST_PAD_IAUX_CORE1    0x0f4
+#define R2057_PGA_BOOST_TUNE_CORE1             0x0f5
+#define R2057_PGA_GAIN_CORE1                   0x0f6
+#define R2057_PAD5G_CASCOFFV_GAIN_PUS_CORE1    0x0f7
+#define R2057_TXMIX5G_BOOST_TUNE_CORE1         0x0f8
+#define R2057_PAD5G_TUNE_MISC_PUS_CORE1                0x0f9
+#define R2057_IPA5G_IAUX_CORE1                 0x0fa
+#define R2057_IPA5G_GAIN_CORE1                 0x0fb
+#define R2057_TSSI5G_SPARE1_CORE1              0x0fc
+#define R2057_TSSI5G_SPARE2_CORE1              0x0fd
+#define R2057_IPA5G_CASCOFFV_PU_CORE1          0x0fe
+#define R2057_IPA5G_PTAT_CORE1                 0x0ff
+#define R2057_IPA5G_IMAIN_CORE1                        0x100
+#define R2057_IPA5G_CASCONV_CORE1              0x101
+#define R2057_IPA5G_BIAS_FILTER_CORE1          0x102
+#define R2057_PAD_BIAS_FILTER_BWS_CORE1                0x105
+#define R2057_TR2G_CONFIG1_CORE1_NU            0x106
+#define R2057_TR2G_CONFIG2_CORE1_NU            0x107
+#define R2057_LNA5G_RFEN_CORE1                 0x108
+#define R2057_TR5G_CONFIG2_CORE1_NU            0x109
+#define R2057_RXRFBIAS_IBOOST_PU_CORE1         0x10a
+#define R2057_RXRF_IABAND_RXGM_IMAIN_PTAT_CORE1        0x10b
+#define R2057_RXGM_CMFBITAIL_AUXPTAT_CORE1     0x10c
+#define R2057_RXMIX_ICORE_RXGM_IAUX_CORE1      0x10d
+#define R2057_RXMIX_CMFBITAIL_PU_CORE1         0x10e
+#define R2057_LNA2_IMAIN_PTAT_PU_CORE1         0x10f
+#define R2057_LNA2_IAUX_PTAT_CORE1             0x110
+#define R2057_LNA1_IMAIN_PTAT_PU_CORE1         0x111
+#define R2057_LNA15G_INPUT_MATCH_TUNE_CORE1    0x112
+#define R2057_RXRFBIAS_BANDSEL_CORE1           0x113
+#define R2057_TIA_CONFIG_CORE1                 0x114
+#define R2057_TIA_IQGAIN_CORE1                 0x115
+#define R2057_TIA_IBIAS2_CORE1                 0x116
+#define R2057_TIA_IBIAS1_CORE1                 0x117
+#define R2057_TIA_SPARE_Q_CORE1                        0x118
+#define R2057_TIA_SPARE_I_CORE1                        0x119
+#define R2057_RXMIX2G_PUS_CORE1                        0x11a
+#define R2057_RXMIX2G_VCMREFS_CORE1            0x11b
+#define R2057_RXMIX2G_LODC_QI_CORE1            0x11c
+#define R2057_W12G_BW_LNA2G_PUS_CORE1          0x11d
+#define R2057_LNA2G_GAIN_CORE1                 0x11e
+#define R2057_LNA2G_TUNE_CORE1                 0x11f
+#define R2057_RXMIX5G_PUS_CORE1                        0x120
+#define R2057_RXMIX5G_VCMREFS_CORE1            0x121
+#define R2057_RXMIX5G_LODC_QI_CORE1            0x122
+#define R2057_W15G_BW_LNA5G_PUS_CORE1          0x123
+#define R2057_LNA5G_GAIN_CORE1                 0x124
+#define R2057_LNA5G_TUNE_CORE1                 0x125
+#define R2057_LPFSEL_TXRX_RXBB_PUS_CORE1       0x126
+#define R2057_RXBB_BIAS_MASTER_CORE1           0x127
+#define R2057_RXBB_VGABUF_IDACS_CORE1          0x128
+#define R2057_LPF_VCMREF_TXBUF_VCMREF_CORE1    0x129
+#define R2057_TXBUF_VINCM_CORE1                        0x12a
+#define R2057_TXBUF_IDACS_CORE1                        0x12b
+#define R2057_LPF_RESP_RXBUF_BW_CORE1          0x12c
+#define R2057_RXBB_CC_CORE1                    0x12d
+#define R2057_RXBB_SPARE3_CORE1                        0x12e
+#define R2057_RXBB_RCCAL_HPC_CORE1             0x12f
+#define R2057_LPF_IDACS_CORE1                  0x130
+#define R2057_LPFBYP_DCLOOP_BYP_IDAC_CORE1     0x131
+#define R2057_TXBUF_GAIN_CORE1                 0x132
+#define R2057_AFELOOPBACK_AACI_RESP_CORE1      0x133
+#define R2057_RXBUF_DEGEN_CORE1                        0x134
+#define R2057_RXBB_SPARE2_CORE1                        0x135
+#define R2057_RXBB_SPARE1_CORE1                        0x136
+#define R2057_RSSI_MASTER_CORE1                        0x137
+#define R2057_W2_MASTER_CORE1                  0x138
+#define R2057_NB_MASTER_CORE1                  0x139
+#define R2057_W2_IDACS0_Q_CORE1                        0x13a
+#define R2057_W2_IDACS1_Q_CORE1                        0x13b
+#define R2057_W2_IDACS0_I_CORE1                        0x13c
+#define R2057_W2_IDACS1_I_CORE1                        0x13d
+#define R2057_RSSI_GPAIOSEL_W1_IDACS_CORE1     0x13e
+#define R2057_NB_IDACS_Q_CORE1                 0x13f
+#define R2057_NB_IDACS_I_CORE1                 0x140
+#define R2057_BACKUP4_CORE1                    0x146
+#define R2057_BACKUP3_CORE1                    0x147
+#define R2057_BACKUP2_CORE1                    0x148
+#define R2057_BACKUP1_CORE1                    0x149
+#define R2057_SPARE16_CORE1                    0x14a
+#define R2057_SPARE15_CORE1                    0x14b
+#define R2057_SPARE14_CORE1                    0x14c
+#define R2057_SPARE13_CORE1                    0x14d
+#define R2057_SPARE12_CORE1                    0x14e
+#define R2057_SPARE11_CORE1                    0x14f
+#define R2057_TX2G_BIAS_RESETS_CORE1           0x150
+#define R2057_TX5G_BIAS_RESETS_CORE1           0x151
+#define R2057_SPARE8_CORE1                     0x152
+#define R2057_SPARE7_CORE1                     0x153
+#define R2057_BUFS_MISC_LPFBW_CORE1            0x154
+#define R2057_TXLPF_RCCAL_CORE1                        0x155
+#define R2057_RXBB_GPAIOSEL_RXLPF_RCCAL_CORE1  0x156
+#define R2057_LPF_GAIN_CORE1                   0x157
+#define R2057_DACBUF_IDACS_BW_CORE1            0x158
+#define R2057_DACBUF_VINCM_CORE1               0x159
+#define R2057_RCCAL_START_R1_Q1_P1             0x15a
+#define R2057_RCCAL_X1                         0x15b
+#define R2057_RCCAL_TRC0                       0x15c
+#define R2057_RCCAL_TRC1                       0x15d
+#define R2057_RCCAL_DONE_OSCCAP                        0x15e
+#define R2057_RCCAL_N0_0                       0x15f
+#define R2057_RCCAL_N0_1                       0x160
+#define R2057_RCCAL_N1_0                       0x161
+#define R2057_RCCAL_N1_1                       0x162
+#define R2057_RCAL_STATUS                      0x163
+#define R2057_XTALPUOVR_PINCTRL                        0x164
+#define R2057_OVR_REG0                         0x165
+#define R2057_OVR_REG1                         0x166
+#define R2057_OVR_REG2                         0x167
+#define R2057_OVR_REG3                         0x168
+#define R2057_OVR_REG4                         0x169
+#define R2057_RCCAL_SCAP_VAL                   0x16a
+#define R2057_RCCAL_BCAP_VAL                   0x16b
+#define R2057_RCCAL_HPC_VAL                    0x16c
+#define R2057_RCCAL_OVERRIDES                  0x16d
+#define R2057_TX0_IQCAL_GAIN_BW                        0x170
+#define R2057_TX0_LOFT_FINE_I                  0x171
+#define R2057_TX0_LOFT_FINE_Q                  0x172
+#define R2057_TX0_LOFT_COARSE_I                        0x173
+#define R2057_TX0_LOFT_COARSE_Q                        0x174
+#define R2057_TX0_TX_SSI_MASTER                        0x175
+#define R2057_TX0_IQCAL_VCM_HG                 0x176
+#define R2057_TX0_IQCAL_IDAC                   0x177
+#define R2057_TX0_TSSI_VCM                     0x178
+#define R2057_TX0_TX_SSI_MUX                   0x179
+#define R2057_TX0_TSSIA                                0x17a
+#define R2057_TX0_TSSIG                                0x17b
+#define R2057_TX0_TSSI_MISC1                   0x17c
+#define R2057_TX0_TXRXCOUPLE_2G_ATTEN          0x17d
+#define R2057_TX0_TXRXCOUPLE_2G_PWRUP          0x17e
+#define R2057_TX0_TXRXCOUPLE_5G_ATTEN          0x17f
+#define R2057_TX0_TXRXCOUPLE_5G_PWRUP          0x180
+#define R2057_TX1_IQCAL_GAIN_BW                        0x190
+#define R2057_TX1_LOFT_FINE_I                  0x191
+#define R2057_TX1_LOFT_FINE_Q                  0x192
+#define R2057_TX1_LOFT_COARSE_I                        0x193
+#define R2057_TX1_LOFT_COARSE_Q                        0x194
+#define R2057_TX1_TX_SSI_MASTER                        0x195
+#define R2057_TX1_IQCAL_VCM_HG                 0x196
+#define R2057_TX1_IQCAL_IDAC                   0x197
+#define R2057_TX1_TSSI_VCM                     0x198
+#define R2057_TX1_TX_SSI_MUX                   0x199
+#define R2057_TX1_TSSIA                                0x19a
+#define R2057_TX1_TSSIG                                0x19b
+#define R2057_TX1_TSSI_MISC1                   0x19c
+#define R2057_TX1_TXRXCOUPLE_2G_ATTEN          0x19d
+#define R2057_TX1_TXRXCOUPLE_2G_PWRUP          0x19e
+#define R2057_TX1_TXRXCOUPLE_5G_ATTEN          0x19f
+#define R2057_TX1_TXRXCOUPLE_5G_PWRUP          0x1a0
+#define R2057_AFE_VCM_CAL_MASTER_CORE0         0x1a1
+#define R2057_AFE_SET_VCM_I_CORE0              0x1a2
+#define R2057_AFE_SET_VCM_Q_CORE0              0x1a3
+#define R2057_AFE_STATUS_VCM_IQADC_CORE0       0x1a4
+#define R2057_AFE_STATUS_VCM_I_CORE0           0x1a5
+#define R2057_AFE_STATUS_VCM_Q_CORE0           0x1a6
+#define R2057_AFE_VCM_CAL_MASTER_CORE1         0x1a7
+#define R2057_AFE_SET_VCM_I_CORE1              0x1a8
+#define R2057_AFE_SET_VCM_Q_CORE1              0x1a9
+#define R2057_AFE_STATUS_VCM_IQADC_CORE1       0x1aa
+#define R2057_AFE_STATUS_VCM_I_CORE1           0x1ab
+#define R2057_AFE_STATUS_VCM_Q_CORE1           0x1ac
+
+#define R2057v7_DACBUF_VINCM_CORE0             0x1ad
+#define R2057v7_RCCAL_MASTER                   0x1ae
+#define R2057v7_TR2G_CONFIG3_CORE0_NU          0x1af
+#define R2057v7_TR2G_CONFIG3_CORE1_NU          0x1b0
+#define R2057v7_LOGEN_PUS1                     0x1b1
+#define R2057v7_OVR_REG5                       0x1b2
+#define R2057v7_OVR_REG6                       0x1b3
+#define R2057v7_OVR_REG7                       0x1b4
+#define R2057v7_OVR_REG8                       0x1b5
+#define R2057v7_OVR_REG9                       0x1b6
+#define R2057v7_OVR_REG10                      0x1b7
+#define R2057v7_OVR_REG11                      0x1b8
+#define R2057v7_OVR_REG12                      0x1b9
+#define R2057v7_OVR_REG13                      0x1ba
+#define R2057v7_OVR_REG14                      0x1bb
+#define R2057v7_OVR_REG15                      0x1bc
+#define R2057v7_OVR_REG16                      0x1bd
+#define R2057v7_OVR_REG1                       0x1be
+#define R2057v7_OVR_REG18                      0x1bf
+#define R2057v7_OVR_REG19                      0x1c0
+#define R2057v7_OVR_REG20                      0x1c1
+#define R2057v7_OVR_REG21                      0x1c2
+#define R2057v7_OVR_REG2                       0x1c3
+#define R2057v7_OVR_REG23                      0x1c4
+#define R2057v7_OVR_REG24                      0x1c5
+#define R2057v7_OVR_REG25                      0x1c6
+#define R2057v7_OVR_REG26                      0x1c7
+#define R2057v7_OVR_REG27                      0x1c8
+#define R2057v7_OVR_REG28                      0x1c9
+#define R2057v7_IQTEST_SEL_PU2                 0x1ca
+
+#define R2057_VCM_MASK                         0x7
+
+void r2057_upload_inittabs(struct b43_wldev *dev);
+
+#endif /* B43_RADIO_2057_H_ */
index f0d8377429c695dc6d5cbe4342d49a4bc513ef5d..97d4e27bf36f3c3f14b336086efe770dbf671f77 100644 (file)
@@ -2757,6 +2757,49 @@ const struct nphy_rf_control_override_rev3 tbl_rf_control_override_rev3[] = {
        { 0x00C0,  6, 0xE7, 0xF9, 0xEC, 0xFB }  /* field == 0x4000 (fls 15) */
 };
 
+/* field, val_addr_core0, val_addr_core1, val_mask, val_shift */
+static const struct nphy_rf_control_override_rev7
+                       tbl_rf_control_override_rev7_over0[] = {
+       { 0x0004, 0x07A, 0x07D, 0x0002, 1 },
+       { 0x0008, 0x07A, 0x07D, 0x0004, 2 },
+       { 0x0010, 0x07A, 0x07D, 0x0010, 4 },
+       { 0x0020, 0x07A, 0x07D, 0x0020, 5 },
+       { 0x0040, 0x07A, 0x07D, 0x0040, 6 },
+       { 0x0080, 0x0F8, 0x0FA, 0x0080, 7 },
+       { 0x0400, 0x0F8, 0x0FA, 0x0070, 4 },
+       { 0x0800, 0x07B, 0x07E, 0xFFFF, 0 },
+       { 0x1000, 0x07C, 0x07F, 0xFFFF, 0 },
+       { 0x6000, 0x348, 0x349, 0xFFFF, 0 },
+       { 0x2000, 0x348, 0x349, 0x000F, 0 },
+};
+
+/* field, val_addr_core0, val_addr_core1, val_mask, val_shift */
+static const struct nphy_rf_control_override_rev7
+                       tbl_rf_control_override_rev7_over1[] = {
+       { 0x0002, 0x340, 0x341, 0x0002, 1 },
+       { 0x0008, 0x340, 0x341, 0x0008, 3 },
+       { 0x0020, 0x340, 0x341, 0x0020, 5 },
+       { 0x0010, 0x340, 0x341, 0x0010, 4 },
+       { 0x0004, 0x340, 0x341, 0x0004, 2 },
+       { 0x0080, 0x340, 0x341, 0x0700, 8 },
+       { 0x0800, 0x340, 0x341, 0x4000, 14 },
+       { 0x0400, 0x340, 0x341, 0x2000, 13 },
+       { 0x0200, 0x340, 0x341, 0x0800, 12 },
+       { 0x0100, 0x340, 0x341, 0x0100, 11 },
+       { 0x0040, 0x340, 0x341, 0x0040, 6 },
+       { 0x0001, 0x340, 0x341, 0x0001, 0 },
+};
+
+/* field, val_addr_core0, val_addr_core1, val_mask, val_shift */
+static const struct nphy_rf_control_override_rev7
+                       tbl_rf_control_override_rev7_over2[] = {
+       { 0x0008, 0x344, 0x345, 0x0008, 3 },
+       { 0x0002, 0x344, 0x345, 0x0002, 1 },
+       { 0x0001, 0x344, 0x345, 0x0001, 0 },
+       { 0x0004, 0x344, 0x345, 0x0004, 2 },
+       { 0x0010, 0x344, 0x345, 0x0010, 4 },
+};
+
 struct nphy_gain_ctl_workaround_entry nphy_gain_ctl_wa_phy6_radio11_ghz2 = {
        { 10, 14, 19, 27 },
        { -5, 6, 10, 15 },
@@ -3248,3 +3291,35 @@ struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent(
 
        return e;
 }
+
+const struct nphy_rf_control_override_rev7 *b43_nphy_get_rf_ctl_over_rev7(
+       struct b43_wldev *dev, u16 field, u8 override)
+{
+       const struct nphy_rf_control_override_rev7 *e;
+       u8 size, i;
+
+       switch (override) {
+       case 0:
+               e = tbl_rf_control_override_rev7_over0;
+               size = ARRAY_SIZE(tbl_rf_control_override_rev7_over0);
+               break;
+       case 1:
+               e = tbl_rf_control_override_rev7_over1;
+               size = ARRAY_SIZE(tbl_rf_control_override_rev7_over1);
+               break;
+       case 2:
+               e = tbl_rf_control_override_rev7_over2;
+               size = ARRAY_SIZE(tbl_rf_control_override_rev7_over2);
+               break;
+       default:
+               b43err(dev->wl, "Invalid override value %d\n", override);
+               return NULL;
+       }
+
+       for (i = 0; i < size; i++) {
+               if (e[i].field == field)
+                       return &e[i];
+       }
+
+       return NULL;
+}
index f348953c02308b5c29f4048f5e4e87ebff8a37cb..c600700ceedc05ae9cae24e0f221d927b5310fa7 100644 (file)
@@ -35,6 +35,14 @@ struct nphy_rf_control_override_rev3 {
        u8 val_addr1;
 };
 
+struct nphy_rf_control_override_rev7 {
+       u16 field;
+       u16 val_addr_core0;
+       u16 val_addr_core1;
+       u16 val_mask;
+       u8 val_shift;
+};
+
 struct nphy_gain_ctl_workaround_entry {
        s8 lna1_gain[4];
        s8 lna2_gain[4];
@@ -202,5 +210,7 @@ extern const struct nphy_rf_control_override_rev2
        tbl_rf_control_override_rev2[];
 extern const struct nphy_rf_control_override_rev3
        tbl_rf_control_override_rev3[];
+const struct nphy_rf_control_override_rev7 *b43_nphy_get_rf_ctl_over_rev7(
+       struct b43_wldev *dev, u16 field, u8 override);
 
 #endif /* B43_TABLES_NPHY_H_ */
index 8156135a0590775311baa7936f723f6f28242ff1..3ea1a85d38d1b14d4b7dede07f36604385e67fcd 100644 (file)
@@ -1920,7 +1920,7 @@ static int b43legacy_gpio_init(struct b43legacy_wldev *dev)
                return 0;
        ssb_write32(gpiodev, B43legacy_GPIO_CONTROL,
                    (ssb_read32(gpiodev, B43legacy_GPIO_CONTROL)
-                    & mask) | set);
+                    & ~mask) | set);
 
        return 0;
 }
index 9a4c63f927cb1817ee666cc070f14d1a810083c0..7ed7d7577024628d228a78f6e94433c810295bc2 100644 (file)
@@ -382,9 +382,7 @@ brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, u16 chanspec,
 {
        struct brcms_c_info *wlc = wlc_cm->wlc;
        struct ieee80211_channel *ch = wlc->pub->ieee_hw->conf.channel;
-       const struct ieee80211_reg_rule *reg_rule;
        struct txpwr_limits txpwr;
-       int ret;
 
        brcms_c_channel_reg_limits(wlc_cm, chanspec, &txpwr);
 
@@ -393,8 +391,7 @@ brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, u16 chanspec,
        );
 
        /* set or restore gmode as required by regulatory */
-       ret = freq_reg_info(wlc->wiphy, ch->center_freq, 0, &reg_rule);
-       if (!ret && (reg_rule->flags & NL80211_RRF_NO_OFDM))
+       if (ch->flags & IEEE80211_CHAN_NO_OFDM)
                brcms_c_set_gmode(wlc, GMODE_LEGACY_B, false);
        else
                brcms_c_set_gmode(wlc, wlc->protection->gmode_user, false);
index 9e79d47e077f34e8b980dc6a8689c0735bba93bc..1c70defba6c308401cc685c73cdcd97c978caf4a 100644 (file)
@@ -86,7 +86,9 @@ MODULE_AUTHOR("Broadcom Corporation");
 MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN driver.");
 MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN cards");
 MODULE_LICENSE("Dual BSD/GPL");
-
+/* This needs to be adjusted when brcms_firmwares changes */
+MODULE_FIRMWARE("brcm/bcm43xx-0.fw");
+MODULE_FIRMWARE("brcm/bcm43xx_hdr-0.fw");
 
 /* recognized BCMA Core IDs */
 static struct bcma_device_id brcms_coreid_table[] = {
@@ -121,7 +123,8 @@ static struct ieee80211_channel brcms_2ghz_chantable[] = {
                 IEEE80211_CHAN_NO_HT40PLUS),
        CHAN2GHZ(14, 2484,
                 IEEE80211_CHAN_PASSIVE_SCAN | IEEE80211_CHAN_NO_IBSS |
-                IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS)
+                IEEE80211_CHAN_NO_HT40PLUS | IEEE80211_CHAN_NO_HT40MINUS |
+                IEEE80211_CHAN_NO_OFDM)
 };
 
 static struct ieee80211_channel brcms_5ghz_nphy_chantable[] = {
index 03ca65324845f39f1e8e48b2669a243bddf7ce5c..75086b37c817b747fe5482bb097a66a859c14214 100644 (file)
@@ -7512,15 +7512,10 @@ prep_mac80211_status(struct brcms_c_info *wlc, struct d11rxhdr *rxh,
 
        channel = BRCMS_CHAN_CHANNEL(rxh->RxChan);
 
-       if (channel > 14) {
-               rx_status->band = IEEE80211_BAND_5GHZ;
-               rx_status->freq = ieee80211_ofdm_chan_to_freq(
-                                       WF_CHAN_FACTOR_5_G/2, channel);
-
-       } else {
-               rx_status->band = IEEE80211_BAND_2GHZ;
-               rx_status->freq = ieee80211_dsss_chan_to_freq(channel);
-       }
+       rx_status->band =
+               channel > 14 ? IEEE80211_BAND_5GHZ : IEEE80211_BAND_2GHZ;
+       rx_status->freq =
+               ieee80211_channel_to_frequency(channel, rx_status->band);
 
        rx_status->signal = wlc_phy_rssi_compute(wlc->hw->band->pi, rxh);
 
index f10d30274c23ade434cc8149ebcaebaadedf8584..c11a290a1edf6c07e38cfd1035f783ddb9918ac2 100644 (file)
 #define WL_CHANSPEC_BAND_2G            0x2000
 #define INVCHANSPEC                    255
 
-/* used to calculate the chan_freq = chan_factor * 500Mhz + 5 * chan_number */
-#define WF_CHAN_FACTOR_2_4_G           4814    /* 2.4 GHz band, 2407 MHz */
-#define WF_CHAN_FACTOR_5_G             10000   /* 5   GHz band, 5000 MHz */
-#define WF_CHAN_FACTOR_4_G             8000    /* 4.9 GHz band for Japan */
-
 #define CHSPEC_CHANNEL(chspec) ((u8)((chspec) & WL_CHANSPEC_CHAN_MASK))
 #define CHSPEC_BAND(chspec)    ((chspec) & WL_CHANSPEC_BAND_MASK)
 
index 95aa8e1683ecb4bdeb663e0cf605d699407b96f0..8a3420257eeb882719a6a5371ffe5a4957d0c0d9 100644 (file)
@@ -2180,8 +2180,7 @@ static void isr_indicate_rf_kill(struct ipw2100_priv *priv, u32 status)
 
        /* Make sure the RF Kill check timer is running */
        priv->stop_rf_kill = 0;
-       cancel_delayed_work(&priv->rf_kill);
-       schedule_delayed_work(&priv->rf_kill, round_jiffies_relative(HZ));
+       mod_delayed_work(system_wq, &priv->rf_kill, round_jiffies_relative(HZ));
 }
 
 static void send_scan_event(void *data)
@@ -4321,9 +4320,8 @@ static int ipw_radio_kill_sw(struct ipw2100_priv *priv, int disable_radio)
                                          "disabled by HW switch\n");
                        /* Make sure the RF_KILL check timer is running */
                        priv->stop_rf_kill = 0;
-                       cancel_delayed_work(&priv->rf_kill);
-                       schedule_delayed_work(&priv->rf_kill,
-                                             round_jiffies_relative(HZ));
+                       mod_delayed_work(system_wq, &priv->rf_kill,
+                                        round_jiffies_relative(HZ));
                } else
                        schedule_reset(priv);
        }
index 0370403fd0bd5d2345704f8fc766c5ad2260a7dc..eb9987520d611f5e4a1d3851b1f57186fa8ab948 100644 (file)
@@ -4860,7 +4860,7 @@ EXPORT_SYMBOL(il_add_beacon_time);
 
 #ifdef CONFIG_PM
 
-int
+static int
 il_pci_suspend(struct device *device)
 {
        struct pci_dev *pdev = to_pci_dev(device);
@@ -4877,9 +4877,8 @@ il_pci_suspend(struct device *device)
 
        return 0;
 }
-EXPORT_SYMBOL(il_pci_suspend);
 
-int
+static int
 il_pci_resume(struct device *device)
 {
        struct pci_dev *pdev = to_pci_dev(device);
@@ -4906,16 +4905,8 @@ il_pci_resume(struct device *device)
 
        return 0;
 }
-EXPORT_SYMBOL(il_pci_resume);
 
-const struct dev_pm_ops il_pm_ops = {
-       .suspend = il_pci_suspend,
-       .resume = il_pci_resume,
-       .freeze = il_pci_suspend,
-       .thaw = il_pci_resume,
-       .poweroff = il_pci_suspend,
-       .restore = il_pci_resume,
-};
+SIMPLE_DEV_PM_OPS(il_pm_ops, il_pci_suspend, il_pci_resume);
 EXPORT_SYMBOL(il_pm_ops);
 
 #endif /* CONFIG_PM */
index 5f5017767b9990b54096b705c23310e866ff2d92..3d3135ed62d737e0eadd4dccb4f179d778aba76d 100644 (file)
@@ -1845,8 +1845,6 @@ __le32 il_add_beacon_time(struct il_priv *il, u32 base, u32 addon,
                          u32 beacon_interval);
 
 #ifdef CONFIG_PM
-int il_pci_suspend(struct device *device);
-int il_pci_resume(struct device *device);
 extern const struct dev_pm_ops il_pm_ops;
 
 #define IL_LEGACY_PM_OPS       (&il_pm_ops)
index 6fddd2785e6e1fc9e846cc7099c1bf6a6414804c..a82f46c10f5ec036ca07ae6bbfa139bb50ab8052 100644 (file)
@@ -707,11 +707,14 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags,
  */
 static bool rs_use_green(struct ieee80211_sta *sta)
 {
-       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
-       struct iwl_rxon_context *ctx = sta_priv->ctx;
-
-       return (sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) &&
-               !(ctx->ht.non_gf_sta_present);
+       /*
+        * There's a bug somewhere in this code that causes the
+        * scaling to get stuck because GF+SGI can't be combined
+        * in SISO rates. Until we find that bug, disable GF, it
+        * has only limited benefit and we still interoperate with
+        * GF APs since we can always receive GF transmissions.
+        */
+       return false;
 }
 
 /**
index eb5de800ed9038109e9a80bfc9cd15863d3491e4..1c10b542ab231a45e5134a58ceb858c8ab82d331 100644 (file)
@@ -1254,6 +1254,7 @@ static int lbs_associate(struct lbs_private *priv,
                        netif_tx_wake_all_queues(priv->dev);
        }
 
+       kfree(cmd);
 done:
        lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
        return ret;
index 76caebaa43977f722cbd707d666f1f014002792e..e970897f6ab52370a632a64a62cc10bb3c39a3c6 100644 (file)
@@ -1314,6 +1314,7 @@ static void if_sdio_remove(struct sdio_func *func)
                kfree(packet);
        }
 
+       kfree(card);
        lbs_deb_leave(LBS_DEB_SDIO);
 }
 
index 58048189bd24475f3ca18960822b6b18219e637c..fe1ea43c5149ef03e9ed0e2809695773fa2a576d 100644 (file)
@@ -571,7 +571,10 @@ static int lbs_thread(void *data)
                        netdev_info(dev, "Timeout submitting command 0x%04x\n",
                                    le16_to_cpu(cmdnode->cmdbuf->command));
                        lbs_complete_command(priv, cmdnode, -ETIMEDOUT);
-                       if (priv->reset_card)
+
+                       /* Reset card, but only when it isn't in the process
+                        * of being shutdown anyway. */
+                       if (!dev->dismantle && priv->reset_card)
                                priv->reset_card(priv);
                }
                priv->cmd_timed_out = 0;
index e535c937628b4575d87ebb8435c7362367634c73..d2732736f8643ef367ff210ae207cfe16c2f1399 100644 (file)
@@ -726,3 +726,29 @@ int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv,
 
        return count;
 }
+
+/*
+ * This function retrieves the entry for specific tx BA stream table by RA and
+ * deletes it.
+ */
+void mwifiex_del_tx_ba_stream_tbl_by_ra(struct mwifiex_private *priv, u8 *ra)
+{
+       struct mwifiex_tx_ba_stream_tbl *tbl, *tmp;
+       unsigned long flags;
+
+       if (!ra)
+               return;
+
+       spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
+       list_for_each_entry_safe(tbl, tmp, &priv->tx_ba_stream_tbl_ptr, list) {
+               if (!memcmp(tbl->ra, ra, ETH_ALEN)) {
+                       spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock,
+                                              flags);
+                       mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, tbl);
+                       spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
+               }
+       }
+       spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
+
+       return;
+}
index 28366e9211fbb8773f1eae98441401aea6473ca1..67c087cf9dc768064e7597d593b9942df3c8ae8a 100644 (file)
@@ -69,6 +69,7 @@ int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv,
 int mwifiex_cmd_amsdu_aggr_ctrl(struct host_cmd_ds_command *cmd,
                                int cmd_action,
                                struct mwifiex_ds_11n_amsdu_aggr_ctrl *aa_ctrl);
+void mwifiex_del_tx_ba_stream_tbl_by_ra(struct mwifiex_private *priv, u8 *ra);
 
 /*
  * This function checks whether AMPDU is allowed or not for a particular TID.
@@ -157,4 +158,18 @@ mwifiex_is_ba_stream_setup(struct mwifiex_private *priv,
 
        return false;
 }
+
+/*
+ * This function checks whether associated station is 11n enabled
+ */
+static inline int mwifiex_is_sta_11n_enabled(struct mwifiex_private *priv,
+                                            struct mwifiex_sta_node *node)
+{
+
+       if (!node || (priv->bss_role != MWIFIEX_BSS_ROLE_UAP) ||
+           !priv->ap_11n_enabled)
+               return 0;
+
+       return node->is_11n_enabled;
+}
 #endif /* !_MWIFIEX_11N_H_ */
index ab84eb94374905c166d6bdcd6c745db1992574fe..395f1bfd41027f788901b62b5ef4621ac019956d 100644 (file)
@@ -62,9 +62,7 @@ mwifiex_11n_form_amsdu_pkt(struct sk_buff *skb_aggr,
        };
        struct tx_packet_hdr *tx_header;
 
-       skb_put(skb_aggr, sizeof(*tx_header));
-
-       tx_header = (struct tx_packet_hdr *) skb_aggr->data;
+       tx_header = (void *)skb_put(skb_aggr, sizeof(*tx_header));
 
        /* Copy DA and SA */
        dt_offset = 2 * ETH_ALEN;
@@ -82,12 +80,10 @@ mwifiex_11n_form_amsdu_pkt(struct sk_buff *skb_aggr,
        tx_header->eth803_hdr.h_proto = htons(skb_src->len + LLC_SNAP_LEN);
 
        /* Add payload */
-       skb_put(skb_aggr, skb_src->len);
-       memcpy(skb_aggr->data + sizeof(*tx_header), skb_src->data,
-              skb_src->len);
-       *pad = (((skb_src->len + LLC_SNAP_LEN) & 3)) ? (4 - (((skb_src->len +
-                                                     LLC_SNAP_LEN)) & 3)) : 0;
-       skb_put(skb_aggr, *pad);
+       memcpy(skb_put(skb_aggr, skb_src->len), skb_src->data, skb_src->len);
+
+       /* Add padding for new MSDU to start from 4 byte boundary */
+       *pad = (4 - ((unsigned long)skb_aggr->tail & 0x3)) % 4;
 
        return skb_aggr->len + *pad;
 }
index 591ccd33f83c5482340c6667cf76660e24ac00d7..24e2582b467cd309f16b45a3b89d341eb959cd44 100644 (file)
@@ -54,8 +54,13 @@ mwifiex_11n_dispatch_pkt(struct mwifiex_private *priv,
                        tbl->rx_reorder_ptr[i] = NULL;
                }
                spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
-               if (rx_tmp_ptr)
-                       mwifiex_process_rx_packet(priv->adapter, rx_tmp_ptr);
+               if (rx_tmp_ptr) {
+                       if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
+                               mwifiex_handle_uap_rx_forward(priv, rx_tmp_ptr);
+                       else
+                               mwifiex_process_rx_packet(priv->adapter,
+                                                         rx_tmp_ptr);
+               }
        }
 
        spin_lock_irqsave(&priv->rx_pkt_lock, flags);
@@ -97,7 +102,11 @@ mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv,
                rx_tmp_ptr = tbl->rx_reorder_ptr[i];
                tbl->rx_reorder_ptr[i] = NULL;
                spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
-               mwifiex_process_rx_packet(priv->adapter, rx_tmp_ptr);
+
+               if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
+                       mwifiex_handle_uap_rx_forward(priv, rx_tmp_ptr);
+               else
+                       mwifiex_process_rx_packet(priv->adapter, rx_tmp_ptr);
        }
 
        spin_lock_irqsave(&priv->rx_pkt_lock, flags);
@@ -148,7 +157,7 @@ mwifiex_del_rx_reorder_entry(struct mwifiex_private *priv,
  * This function returns the pointer to an entry in Rx reordering
  * table which matches the given TA/TID pair.
  */
-static struct mwifiex_rx_reorder_tbl *
+struct mwifiex_rx_reorder_tbl *
 mwifiex_11n_get_rx_reorder_tbl(struct mwifiex_private *priv, int tid, u8 *ta)
 {
        struct mwifiex_rx_reorder_tbl *tbl;
@@ -167,6 +176,31 @@ mwifiex_11n_get_rx_reorder_tbl(struct mwifiex_private *priv, int tid, u8 *ta)
        return NULL;
 }
 
+/* This function retrieves the pointer to an entry in Rx reordering
+ * table which matches the given TA and deletes it.
+ */
+void mwifiex_11n_del_rx_reorder_tbl_by_ta(struct mwifiex_private *priv, u8 *ta)
+{
+       struct mwifiex_rx_reorder_tbl *tbl, *tmp;
+       unsigned long flags;
+
+       if (!ta)
+               return;
+
+       spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
+       list_for_each_entry_safe(tbl, tmp, &priv->rx_reorder_tbl_ptr, list) {
+               if (!memcmp(tbl->ta, ta, ETH_ALEN)) {
+                       spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock,
+                                              flags);
+                       mwifiex_del_rx_reorder_entry(priv, tbl);
+                       spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
+               }
+       }
+       spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
+
+       return;
+}
+
 /*
  * This function finds the last sequence number used in the packets
  * buffered in Rx reordering table.
@@ -226,6 +260,7 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
        struct mwifiex_rx_reorder_tbl *tbl, *new_node;
        u16 last_seq = 0;
        unsigned long flags;
+       struct mwifiex_sta_node *node;
 
        /*
         * If we get a TID, ta pair which is already present dispatch all the
@@ -248,13 +283,19 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
        new_node->tid = tid;
        memcpy(new_node->ta, ta, ETH_ALEN);
        new_node->start_win = seq_num;
-       if (mwifiex_queuing_ra_based(priv))
-               /* TODO for adhoc */
+
+       if (mwifiex_queuing_ra_based(priv)) {
                dev_dbg(priv->adapter->dev,
-                       "info: ADHOC:last_seq=%d start_win=%d\n",
+                       "info: AP/ADHOC:last_seq=%d start_win=%d\n",
                        last_seq, new_node->start_win);
-       else
+               if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) {
+                       node = mwifiex_get_sta_entry(priv, ta);
+                       if (node)
+                               last_seq = node->rx_seq[tid];
+               }
+       } else {
                last_seq = priv->rx_seq[tid];
+       }
 
        if (last_seq != MWIFIEX_DEF_11N_RX_SEQ_NUM &&
            last_seq >= new_node->start_win)
@@ -396,8 +437,13 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
 
        tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta);
        if (!tbl) {
-               if (pkt_type != PKT_TYPE_BAR)
-                       mwifiex_process_rx_packet(priv->adapter, payload);
+               if (pkt_type != PKT_TYPE_BAR) {
+                       if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
+                               mwifiex_handle_uap_rx_forward(priv, payload);
+                       else
+                               mwifiex_process_rx_packet(priv->adapter,
+                                                         payload);
+               }
                return 0;
        }
        start_win = tbl->start_win;
index 6c9815a0f5d8b0d7aebcb5d6a9953a24819ad45a..72848591691a973ac83a5b6efd2481c79ae5354d 100644 (file)
@@ -38,6 +38,8 @@
 #define ADDBA_RSP_STATUS_ACCEPT 0
 
 #define MWIFIEX_DEF_11N_RX_SEQ_NUM     0xffff
+#define BA_SETUP_MAX_PACKET_THRESHOLD  16
+#define BA_SETUP_PACKET_OFFSET         16
 
 static inline void mwifiex_reset_11n_rx_seq_num(struct mwifiex_private *priv)
 {
@@ -68,5 +70,8 @@ struct mwifiex_rx_reorder_tbl *mwifiex_11n_get_rxreorder_tbl(struct
                                                           mwifiex_private
                                                           *priv, int tid,
                                                           u8 *ta);
+struct mwifiex_rx_reorder_tbl *
+mwifiex_11n_get_rx_reorder_tbl(struct mwifiex_private *priv, int tid, u8 *ta);
+void mwifiex_11n_del_rx_reorder_tbl_by_ta(struct mwifiex_private *priv, u8 *ta);
 
 #endif /* _MWIFIEX_11N_RXREORDER_H_ */
index 3f66ebb0a630813d3bc836c4412233a3f8883f7b..dd0410d2d465d8e279ec1104ea5ee51831fed97c 100644 (file)
@@ -33,8 +33,10 @@ mwifiex-y += uap_cmd.o
 mwifiex-y += ie.o
 mwifiex-y += sta_cmdresp.o
 mwifiex-y += sta_event.o
+mwifiex-y += uap_event.o
 mwifiex-y += sta_tx.o
 mwifiex-y += sta_rx.o
+mwifiex-y += uap_txrx.o
 mwifiex-y += cfg80211.o
 mwifiex-$(CONFIG_DEBUG_FS) += debugfs.o
 obj-$(CONFIG_MWIFIEX) += mwifiex.o
index fe42137384da0bbae54ee0e656bf51a50cb58e68..e57f543413de010fcf435704abfe7d915a08e03a 100644 (file)
@@ -99,7 +99,7 @@ mwifiex_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev,
        const u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
        const u8 *peer_mac = pairwise ? mac_addr : bc_mac;
 
-       if (mwifiex_set_encode(priv, NULL, 0, key_index, peer_mac, 1)) {
+       if (mwifiex_set_encode(priv, NULL, NULL, 0, key_index, peer_mac, 1)) {
                wiphy_err(wiphy, "deleting the crypto keys\n");
                return -EFAULT;
        }
@@ -171,7 +171,8 @@ mwifiex_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
 
        if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP) {
                priv->wep_key_curr_index = key_index;
-       } else if (mwifiex_set_encode(priv, NULL, 0, key_index, NULL, 0)) {
+       } else if (mwifiex_set_encode(priv, NULL, NULL, 0, key_index,
+                                     NULL, 0)) {
                wiphy_err(wiphy, "set default Tx key index\n");
                return -EFAULT;
        }
@@ -207,7 +208,7 @@ mwifiex_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev,
                return 0;
        }
 
-       if (mwifiex_set_encode(priv, params->key, params->key_len,
+       if (mwifiex_set_encode(priv, params, params->key, params->key_len,
                               key_index, peer_mac, 0)) {
                wiphy_err(wiphy, "crypto keys added\n");
                return -EFAULT;
@@ -748,6 +749,7 @@ static const u32 mwifiex_cipher_suites[] = {
        WLAN_CIPHER_SUITE_WEP104,
        WLAN_CIPHER_SUITE_TKIP,
        WLAN_CIPHER_SUITE_CCMP,
+       WLAN_CIPHER_SUITE_AES_CMAC,
 };
 
 /*
@@ -906,6 +908,8 @@ static int mwifiex_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
        if (mwifiex_del_mgmt_ies(priv))
                wiphy_err(wiphy, "Failed to delete mgmt IEs!\n");
 
+       priv->ap_11n_enabled = 0;
+
        if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP,
                                  HostCmd_ACT_GEN_SET, 0, NULL)) {
                wiphy_err(wiphy, "Failed to stop the BSS\n");
@@ -1159,7 +1163,7 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid,
        priv->wep_key_curr_index = 0;
        priv->sec_info.encryption_mode = 0;
        priv->sec_info.is_authtype_auto = 0;
-       ret = mwifiex_set_encode(priv, NULL, 0, 0, NULL, 1);
+       ret = mwifiex_set_encode(priv, NULL, NULL, 0, 0, NULL, 1);
 
        if (mode == NL80211_IFTYPE_ADHOC) {
                /* "privacy" is set only for ad-hoc mode */
@@ -1206,8 +1210,9 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid,
                                "info: setting wep encryption"
                                " with key len %d\n", sme->key_len);
                        priv->wep_key_curr_index = sme->key_idx;
-                       ret = mwifiex_set_encode(priv, sme->key, sme->key_len,
-                                                sme->key_idx, NULL, 0);
+                       ret = mwifiex_set_encode(priv, NULL, sme->key,
+                                                sme->key_len, sme->key_idx,
+                                                NULL, 0);
                }
        }
 done:
index c68adec3cc8b6522678c98582c7781b885193849..c229dddcf1c24d846d61c6d65061aff9dbf67134 100644 (file)
@@ -447,7 +447,10 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter)
                        priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
        }
 
-       ret = mwifiex_process_sta_event(priv);
+       if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
+               ret = mwifiex_process_uap_event(priv);
+       else
+               ret = mwifiex_process_sta_event(priv);
 
        adapter->event_cause = 0;
        adapter->event_skb = NULL;
index 070ef25f51867a1bb0d3baf3279d0eb02b2ba3d6..400d360ac91f010131e3f438615ddfe5d44198a1 100644 (file)
@@ -60,6 +60,9 @@
 #define MWIFIEX_SDIO_BLOCK_SIZE            256
 
 #define MWIFIEX_BUF_FLAG_REQUEUED_PKT      BIT(0)
+#define MWIFIEX_BUF_FLAG_BRIDGED_PKT      BIT(1)
+
+#define MWIFIEX_BRIDGED_PKTS_THRESHOLD     1024
 
 enum mwifiex_bss_type {
        MWIFIEX_BSS_TYPE_STA = 0,
index e831b440a24a3f2c654e8ad04e17701fb0e1b85f..ae06f31c6838cbd0aed3a85c671550ca0c38bf37 100644 (file)
@@ -65,10 +65,12 @@ enum KEY_TYPE_ID {
        KEY_TYPE_ID_TKIP,
        KEY_TYPE_ID_AES,
        KEY_TYPE_ID_WAPI,
+       KEY_TYPE_ID_AES_CMAC,
 };
 #define KEY_MCAST      BIT(0)
 #define KEY_UNICAST    BIT(1)
 #define KEY_ENABLED    BIT(2)
+#define KEY_IGTK       BIT(10)
 
 #define WAPI_KEY_LEN                   50
 
@@ -424,10 +426,10 @@ struct txpd {
 struct rxpd {
        u8 bss_type;
        u8 bss_num;
-       u16 rx_pkt_length;
-       u16 rx_pkt_offset;
-       u16 rx_pkt_type;
-       u16 seq_num;
+       __le16 rx_pkt_length;
+       __le16 rx_pkt_offset;
+       __le16 rx_pkt_type;
+       __le16 seq_num;
        u8 priority;
        u8 rx_rate;
        s8 snr;
@@ -439,6 +441,31 @@ struct rxpd {
        u8 reserved;
 } __packed;
 
+struct uap_txpd {
+       u8 bss_type;
+       u8 bss_num;
+       __le16 tx_pkt_length;
+       __le16 tx_pkt_offset;
+       __le16 tx_pkt_type;
+       __le32 tx_control;
+       u8 priority;
+       u8 flags;
+       u8 pkt_delay_2ms;
+       u8 reserved1;
+       __le32 reserved2;
+};
+
+struct uap_rxpd {
+       u8 bss_type;
+       u8 bss_num;
+       __le16 rx_pkt_length;
+       __le16 rx_pkt_offset;
+       __le16 rx_pkt_type;
+       __le16 seq_num;
+       u8 priority;
+       u8 reserved1;
+};
+
 enum mwifiex_chan_scan_mode_bitmasks {
        MWIFIEX_PASSIVE_SCAN = BIT(0),
        MWIFIEX_DISABLE_CHAN_FILT = BIT(1),
@@ -558,6 +585,13 @@ struct mwifiex_ie_type_key_param_set {
        u8 key[50];
 } __packed;
 
+#define IGTK_PN_LEN            8
+
+struct mwifiex_cmac_param {
+       u8 ipn[IGTK_PN_LEN];
+       u8 key[WLAN_KEY_LEN_AES_CMAC];
+} __packed;
+
 struct host_cmd_ds_802_11_key_material {
        __le16 action;
        struct mwifiex_ie_type_key_param_set key_param_set;
index 21fdc6c02775b4f9b119afbab1de01420062c28f..fad2c8d2bddedb69c84dcc2bf0d3fd16c89e1bca 100644 (file)
@@ -64,60 +64,72 @@ static void scan_delay_timer_fn(unsigned long data)
        struct cmd_ctrl_node *cmd_node, *tmp_node;
        unsigned long flags;
 
-       if (!mwifiex_wmm_lists_empty(adapter)) {
-               if (adapter->scan_delay_cnt == MWIFIEX_MAX_SCAN_DELAY_CNT) {
+       if (adapter->scan_delay_cnt == MWIFIEX_MAX_SCAN_DELAY_CNT) {
+               /*
+                * Abort scan operation by cancelling all pending scan
+                * commands
+                */
+               spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
+               list_for_each_entry_safe(cmd_node, tmp_node,
+                                        &adapter->scan_pending_q, list) {
+                       list_del(&cmd_node->list);
+                       cmd_node->wait_q_enabled = false;
+                       mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+               }
+               spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
+
+               spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
+               adapter->scan_processing = false;
+               adapter->scan_delay_cnt = 0;
+               adapter->empty_tx_q_cnt = 0;
+               spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
+
+               if (priv->user_scan_cfg) {
+                       dev_dbg(priv->adapter->dev,
+                               "info: %s: scan aborted\n", __func__);
+                       cfg80211_scan_done(priv->scan_request, 1);
+                       priv->scan_request = NULL;
+                       kfree(priv->user_scan_cfg);
+                       priv->user_scan_cfg = NULL;
+               }
+               goto done;
+       }
+
+       if (!atomic_read(&priv->adapter->is_tx_received)) {
+               adapter->empty_tx_q_cnt++;
+               if (adapter->empty_tx_q_cnt == MWIFIEX_MAX_EMPTY_TX_Q_CNT) {
                        /*
-                        * Abort scan operation by cancelling all pending scan
-                        * command
+                        * No Tx traffic for 200msec. Get scan command from
+                        * scan pending queue and put to cmd pending queue to
+                        * resume scan operation
                         */
+                       adapter->scan_delay_cnt = 0;
+                       adapter->empty_tx_q_cnt = 0;
                        spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
-                       list_for_each_entry_safe(cmd_node, tmp_node,
-                                                &adapter->scan_pending_q,
-                                                list) {
-                               list_del(&cmd_node->list);
-                               cmd_node->wait_q_enabled = false;
-                               mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
-                       }
+                       cmd_node = list_first_entry(&adapter->scan_pending_q,
+                                                   struct cmd_ctrl_node, list);
+                       list_del(&cmd_node->list);
                        spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
                                               flags);
 
-                       spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
-                       adapter->scan_processing = false;
-                       spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock,
-                                              flags);
-
-                       if (priv->user_scan_cfg) {
-                               dev_dbg(priv->adapter->dev,
-                                       "info: %s: scan aborted\n", __func__);
-                               cfg80211_scan_done(priv->scan_request, 1);
-                               priv->scan_request = NULL;
-                               kfree(priv->user_scan_cfg);
-                               priv->user_scan_cfg = NULL;
-                       }
-               } else {
-                       /*
-                        * Tx data queue is still not empty, delay scan
-                        * operation further by 20msec.
-                        */
-                       mod_timer(&priv->scan_delay_timer, jiffies +
-                                 msecs_to_jiffies(MWIFIEX_SCAN_DELAY_MSEC));
-                       adapter->scan_delay_cnt++;
+                       mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,
+                                                       true);
+                       goto done;
                }
-               queue_work(priv->adapter->workqueue, &priv->adapter->main_work);
        } else {
-               /*
-                * Tx data queue is empty. Get scan command from scan_pending_q
-                * and put to cmd_pending_q to resume scan operation
-                */
-               adapter->scan_delay_cnt = 0;
-               spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
-               cmd_node = list_first_entry(&adapter->scan_pending_q,
-                                           struct cmd_ctrl_node, list);
-               list_del(&cmd_node->list);
-               spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
-
-               mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true);
+               adapter->empty_tx_q_cnt = 0;
        }
+
+       /* Delay scan operation further by 20msec */
+       mod_timer(&priv->scan_delay_timer, jiffies +
+                 msecs_to_jiffies(MWIFIEX_SCAN_DELAY_MSEC));
+       adapter->scan_delay_cnt++;
+
+done:
+       if (atomic_read(&priv->adapter->is_tx_received))
+               atomic_set(&priv->adapter->is_tx_received, false);
+
+       return;
 }
 
 /*
@@ -196,6 +208,7 @@ static int mwifiex_init_priv(struct mwifiex_private *priv)
        priv->curr_bcn_size = 0;
        priv->wps_ie = NULL;
        priv->wps_ie_len = 0;
+       priv->ap_11n_enabled = 0;
 
        priv->scan_block = false;
 
@@ -345,6 +358,7 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
        memset(&adapter->arp_filter, 0, sizeof(adapter->arp_filter));
        adapter->arp_filter_size = 0;
        adapter->max_mgmt_ie_index = MAX_MGMT_IE_INDEX;
+       adapter->empty_tx_q_cnt = 0;
 }
 
 /*
@@ -410,6 +424,7 @@ static void mwifiex_free_lock_list(struct mwifiex_adapter *adapter)
                                list_del(&priv->wmm.tid_tbl_ptr[j].ra_list);
                        list_del(&priv->tx_ba_stream_tbl_ptr);
                        list_del(&priv->rx_reorder_tbl_ptr);
+                       list_del(&priv->sta_list);
                }
        }
 }
@@ -472,6 +487,7 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter)
                        spin_lock_init(&priv->rx_pkt_lock);
                        spin_lock_init(&priv->wmm.ra_list_spinlock);
                        spin_lock_init(&priv->curr_bcn_buf_lock);
+                       spin_lock_init(&priv->sta_list_spinlock);
                }
        }
 
@@ -504,6 +520,7 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter)
                }
                INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr);
                INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr);
+               INIT_LIST_HEAD(&priv->sta_list);
 
                spin_lock_init(&priv->tx_ba_stream_tbl_lock);
                spin_lock_init(&priv->rx_reorder_tbl_lock);
index 50191539bb322ed206bc46f11cfa6154cbda2ad4..6a5eded3be10e6e84d8d8f02dfc5b08f3b6c8b21 100644 (file)
@@ -213,7 +213,7 @@ struct mwifiex_debug_info {
 };
 
 #define MWIFIEX_KEY_INDEX_UNICAST      0x40000000
-#define WAPI_RXPN_LEN                  16
+#define PN_LEN                         16
 
 struct mwifiex_ds_encrypt_key {
        u32 key_disable;
@@ -222,7 +222,8 @@ struct mwifiex_ds_encrypt_key {
        u8 key_material[WLAN_MAX_KEY_LEN];
        u8 mac_addr[ETH_ALEN];
        u32 is_wapi_key;
-       u8 wapi_rxpn[WAPI_RXPN_LEN];
+       u8 pn[PN_LEN];          /* packet number */
+       u8 is_igtk_key;
 };
 
 struct mwifiex_power_cfg {
index 46803621d01511dad87b91b59ef2b6fb8a38a9ef..cb1155286e0fb65ace438688de95938039144367 100644 (file)
@@ -520,6 +520,9 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
        mwifiex_wmm_add_buf_txqueue(priv, skb);
        atomic_inc(&priv->adapter->tx_pending);
 
+       if (priv->adapter->scan_delay_cnt)
+               atomic_set(&priv->adapter->is_tx_received, true);
+
        if (atomic_read(&priv->adapter->tx_pending) >= MAX_TX_PENDING) {
                mwifiex_set_trans_start(dev);
                mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter);
index e7c2a82fd6106481d63d7beb9df0388d1a0798c2..994bc4fc263ef7aca64c87fe6109b5dd9548b6fe 100644 (file)
@@ -88,6 +88,7 @@ enum {
 #define MWIFIEX_MAX_TOTAL_SCAN_TIME    (MWIFIEX_TIMER_10S - MWIFIEX_TIMER_1S)
 
 #define MWIFIEX_MAX_SCAN_DELAY_CNT                     50
+#define MWIFIEX_MAX_EMPTY_TX_Q_CNT                     10
 #define MWIFIEX_SCAN_DELAY_MSEC                                20
 
 #define RSN_GTK_OUI_OFFSET                             2
@@ -199,6 +200,9 @@ struct mwifiex_ra_list_tbl {
        u8 ra[ETH_ALEN];
        u32 total_pkts_size;
        u32 is_11n_enabled;
+       u16 max_amsdu;
+       u16 pkt_count;
+       u8 ba_packet_thr;
 };
 
 struct mwifiex_tid_tbl {
@@ -431,6 +435,9 @@ struct mwifiex_private {
        u8 wmm_enabled;
        u8 wmm_qosinfo;
        struct mwifiex_wmm_desc wmm;
+       struct list_head sta_list;
+       /* spin lock for associated station list */
+       spinlock_t sta_list_spinlock;
        struct list_head tx_ba_stream_tbl_ptr;
        /* spin lock for tx_ba_stream_tbl_ptr queue */
        spinlock_t tx_ba_stream_tbl_lock;
@@ -486,6 +493,7 @@ struct mwifiex_private {
        u16 assocresp_idx;
        u16 rsn_idx;
        struct timer_list scan_delay_timer;
+       u8 ap_11n_enabled;
 };
 
 enum mwifiex_ba_status {
@@ -550,6 +558,19 @@ struct mwifiex_bss_priv {
        u64 fw_tsf;
 };
 
+/* This is AP specific structure which stores information
+ * about associated STA
+ */
+struct mwifiex_sta_node {
+       struct list_head list;
+       u8 mac_addr[ETH_ALEN];
+       u8 is_wmm_enabled;
+       u8 is_11n_enabled;
+       u8 ampdu_sta[MAX_NUM_TID];
+       u16 rx_seq[MAX_NUM_TID];
+       u16 max_amsdu;
+};
+
 struct mwifiex_if_ops {
        int (*init_if) (struct mwifiex_adapter *);
        void (*cleanup_if) (struct mwifiex_adapter *);
@@ -690,6 +711,9 @@ struct mwifiex_adapter {
        u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
        u16 max_mgmt_ie_index;
        u8 scan_delay_cnt;
+       u8 empty_tx_q_cnt;
+       atomic_t is_tx_received;
+       atomic_t pending_bridged_pkts;
 };
 
 int mwifiex_init_lock_list(struct mwifiex_adapter *adapter);
@@ -780,7 +804,15 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *, u16 cmdresp_no,
                                struct host_cmd_ds_command *resp);
 int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *,
                                  struct sk_buff *skb);
+int mwifiex_process_uap_rx_packet(struct mwifiex_adapter *adapter,
+                                 struct sk_buff *skb);
+int mwifiex_handle_uap_rx_forward(struct mwifiex_private *priv,
+                                 struct sk_buff *skb);
 int mwifiex_process_sta_event(struct mwifiex_private *);
+int mwifiex_process_uap_event(struct mwifiex_private *);
+struct mwifiex_sta_node *
+mwifiex_get_sta_entry(struct mwifiex_private *priv, u8 *mac);
+void mwifiex_delete_all_station_list(struct mwifiex_private *priv);
 void *mwifiex_process_sta_txpd(struct mwifiex_private *, struct sk_buff *skb);
 int mwifiex_sta_init_cmd(struct mwifiex_private *, u8 first_sta);
 int mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd,
@@ -949,9 +981,9 @@ int mwifiex_scan_networks(struct mwifiex_private *priv,
                          const struct mwifiex_user_scan_cfg *user_scan_in);
 int mwifiex_set_radio(struct mwifiex_private *priv, u8 option);
 
-int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key,
-                      int key_len, u8 key_index, const u8 *mac_addr,
-                      int disable);
+int mwifiex_set_encode(struct mwifiex_private *priv, struct key_params *kp,
+                      const u8 *key, int key_len, u8 key_index,
+                      const u8 *mac_addr, int disable);
 
 int mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len);
 
index 04dc7ca4ac221a3b2c54d644f2b04fed8c180852..215d07e6c462656faa79845dd7ba4bc94ddbf4bb 100644 (file)
@@ -989,6 +989,8 @@ mwifiex_config_scan(struct mwifiex_private *priv,
                        *max_chan_per_scan = 2;
                else if (chan_num < MWIFIEX_LIMIT_3_CHANNELS_PER_SCAN_CMD)
                        *max_chan_per_scan = 3;
+               else
+                       *max_chan_per_scan = 4;
        }
 }
 
@@ -1433,9 +1435,9 @@ int mwifiex_check_network_compatibility(struct mwifiex_private *priv,
                        if (ret)
                                dev_err(priv->adapter->dev, "cannot find ssid "
                                        "%s\n", bss_desc->ssid.ssid);
-                               break;
+                       break;
                default:
-                               ret = 0;
+                       ret = 0;
                }
        }
 
index df3a33c530cf1a30f9a4058b2bb01d3b24777d0a..0cc3406050dc5d11ac20e26482d609dc54ffeb89 100644 (file)
@@ -610,7 +610,7 @@ mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv,
                memcpy(&key_material->key_param_set.key[2],
                       enc_key->key_material, enc_key->key_len);
                memcpy(&key_material->key_param_set.key[2 + enc_key->key_len],
-                      enc_key->wapi_rxpn, WAPI_RXPN_LEN);
+                      enc_key->pn, PN_LEN);
                key_material->key_param_set.length =
                        cpu_to_le16(WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN);
 
@@ -621,23 +621,38 @@ mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv,
                return ret;
        }
        if (enc_key->key_len == WLAN_KEY_LEN_CCMP) {
-               dev_dbg(priv->adapter->dev, "cmd: WPA_AES\n");
-               key_material->key_param_set.key_type_id =
+               if (enc_key->is_igtk_key) {
+                       dev_dbg(priv->adapter->dev, "cmd: CMAC_AES\n");
+                       key_material->key_param_set.key_type_id =
+                                       cpu_to_le16(KEY_TYPE_ID_AES_CMAC);
+                       if (cmd_oid == KEY_INFO_ENABLED)
+                               key_material->key_param_set.key_info =
+                                               cpu_to_le16(KEY_ENABLED);
+                       else
+                               key_material->key_param_set.key_info =
+                                               cpu_to_le16(!KEY_ENABLED);
+
+                       key_material->key_param_set.key_info |=
+                                                       cpu_to_le16(KEY_IGTK);
+               } else {
+                       dev_dbg(priv->adapter->dev, "cmd: WPA_AES\n");
+                       key_material->key_param_set.key_type_id =
                                                cpu_to_le16(KEY_TYPE_ID_AES);
-               if (cmd_oid == KEY_INFO_ENABLED)
-                       key_material->key_param_set.key_info =
+                       if (cmd_oid == KEY_INFO_ENABLED)
+                               key_material->key_param_set.key_info =
                                                cpu_to_le16(KEY_ENABLED);
-               else
-                       key_material->key_param_set.key_info =
+                       else
+                               key_material->key_param_set.key_info =
                                                cpu_to_le16(!KEY_ENABLED);
 
-               if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST)
+                       if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST)
                                /* AES pairwise key: unicast */
-                       key_material->key_param_set.key_info |=
+                               key_material->key_param_set.key_info |=
                                                cpu_to_le16(KEY_UNICAST);
-               else            /* AES group key: multicast */
-                       key_material->key_param_set.key_info |=
+                       else    /* AES group key: multicast */
+                               key_material->key_param_set.key_info |=
                                                        cpu_to_le16(KEY_MCAST);
+               }
        } else if (enc_key->key_len == WLAN_KEY_LEN_TKIP) {
                dev_dbg(priv->adapter->dev, "cmd: WPA_TKIP\n");
                key_material->key_param_set.key_type_id =
@@ -668,6 +683,24 @@ mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv,
                key_param_len = (u16)(enc_key->key_len + KEYPARAMSET_FIXED_LEN)
                                + sizeof(struct mwifiex_ie_types_header);
 
+               if (le16_to_cpu(key_material->key_param_set.key_type_id) ==
+                                                       KEY_TYPE_ID_AES_CMAC) {
+                       struct mwifiex_cmac_param *param =
+                                       (void *)key_material->key_param_set.key;
+
+                       memcpy(param->ipn, enc_key->pn, IGTK_PN_LEN);
+                       memcpy(param->key, enc_key->key_material,
+                              WLAN_KEY_LEN_AES_CMAC);
+
+                       key_param_len = sizeof(struct mwifiex_cmac_param);
+                       key_material->key_param_set.key_len =
+                                               cpu_to_le16(key_param_len);
+                       key_param_len += KEYPARAMSET_FIXED_LEN;
+                       key_material->key_param_set.length =
+                                               cpu_to_le16(key_param_len);
+                       key_param_len += sizeof(struct mwifiex_ie_types_header);
+               }
+
                cmd->size = cpu_to_le16(sizeof(key_material->action) + S_DS_GEN
                                        + key_param_len);
 
index b8614a82546072a25099994768ade4bcad28e02a..dff51d55271c20267097245b079235f5882a1522 100644 (file)
@@ -184,10 +184,9 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv)
 int mwifiex_process_sta_event(struct mwifiex_private *priv)
 {
        struct mwifiex_adapter *adapter = priv->adapter;
-       int len, ret = 0;
+       int ret = 0;
        u32 eventcause = adapter->event_cause;
-       struct station_info sinfo;
-       struct mwifiex_assoc_event *event;
+       u16 ctrl;
 
        switch (eventcause) {
        case EVENT_DUMMY_HOST_WAKEUP_SIGNAL:
@@ -279,10 +278,16 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
 
        case EVENT_MIC_ERR_UNICAST:
                dev_dbg(adapter->dev, "event: UNICAST MIC ERROR\n");
+               cfg80211_michael_mic_failure(priv->netdev, priv->cfg_bssid,
+                                            NL80211_KEYTYPE_PAIRWISE,
+                                            -1, NULL, GFP_KERNEL);
                break;
 
        case EVENT_MIC_ERR_MULTICAST:
                dev_dbg(adapter->dev, "event: MULTICAST MIC ERROR\n");
+               cfg80211_michael_mic_failure(priv->netdev, priv->cfg_bssid,
+                                            NL80211_KEYTYPE_GROUP,
+                                            -1, NULL, GFP_KERNEL);
                break;
        case EVENT_MIB_CHANGED:
        case EVENT_INIT_DONE:
@@ -384,11 +389,11 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
                                              adapter->event_body);
                break;
        case EVENT_AMSDU_AGGR_CTRL:
-               dev_dbg(adapter->dev, "event:  AMSDU_AGGR_CTRL %d\n",
-                       *(u16 *) adapter->event_body);
+               ctrl = le16_to_cpu(*(__le16 *)adapter->event_body);
+               dev_dbg(adapter->dev, "event: AMSDU_AGGR_CTRL %d\n", ctrl);
+
                adapter->tx_buf_size =
-                       min(adapter->curr_tx_buf_size,
-                           le16_to_cpu(*(__le16 *) adapter->event_body));
+                               min_t(u16, adapter->curr_tx_buf_size, ctrl);
                dev_dbg(adapter->dev, "event: tx_buf_size %d\n",
                        adapter->tx_buf_size);
                break;
@@ -405,51 +410,6 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
                dev_dbg(adapter->dev, "event: HOSTWAKE_STAIE %d\n", eventcause);
                break;
 
-       case EVENT_UAP_STA_ASSOC:
-               memset(&sinfo, 0, sizeof(sinfo));
-               event = (struct mwifiex_assoc_event *)
-                       (adapter->event_body + MWIFIEX_UAP_EVENT_EXTRA_HEADER);
-               if (le16_to_cpu(event->type) == TLV_TYPE_UAP_MGMT_FRAME) {
-                       len = -1;
-
-                       if (ieee80211_is_assoc_req(event->frame_control))
-                               len = 0;
-                       else if (ieee80211_is_reassoc_req(event->frame_control))
-                               /* There will be ETH_ALEN bytes of
-                                * current_ap_addr before the re-assoc ies.
-                                */
-                               len = ETH_ALEN;
-
-                       if (len != -1) {
-                               sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
-                               sinfo.assoc_req_ies = &event->data[len];
-                               len = (u8 *)sinfo.assoc_req_ies -
-                                     (u8 *)&event->frame_control;
-                               sinfo.assoc_req_ies_len =
-                                       le16_to_cpu(event->len) - (u16)len;
-                       }
-               }
-               cfg80211_new_sta(priv->netdev, event->sta_addr, &sinfo,
-                                GFP_KERNEL);
-               break;
-       case EVENT_UAP_STA_DEAUTH:
-               cfg80211_del_sta(priv->netdev, adapter->event_body +
-                                MWIFIEX_UAP_EVENT_EXTRA_HEADER, GFP_KERNEL);
-               break;
-       case EVENT_UAP_BSS_IDLE:
-               priv->media_connected = false;
-               break;
-       case EVENT_UAP_BSS_ACTIVE:
-               priv->media_connected = true;
-               break;
-       case EVENT_UAP_BSS_START:
-               dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause);
-               memcpy(priv->netdev->dev_addr, adapter->event_body+2, ETH_ALEN);
-               break;
-       case EVENT_UAP_MIC_COUNTERMEASURES:
-               /* For future development */
-               dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause);
-               break;
        default:
                dev_dbg(adapter->dev, "event: unknown event id: %#x\n",
                        eventcause);
index fb2136089a2241318a0a697461dc02e0ec240dd6..3f025976f79a528be6b5e82cd29a70937246756d 100644 (file)
@@ -942,20 +942,26 @@ mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter, char *version,
  * This function allocates the IOCTL request buffer, fills it
  * with requisite parameters and calls the IOCTL handler.
  */
-int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key,
-                       int key_len, u8 key_index,
-                       const u8 *mac_addr, int disable)
+int mwifiex_set_encode(struct mwifiex_private *priv, struct key_params *kp,
+                      const u8 *key, int key_len, u8 key_index,
+                      const u8 *mac_addr, int disable)
 {
        struct mwifiex_ds_encrypt_key encrypt_key;
 
        memset(&encrypt_key, 0, sizeof(struct mwifiex_ds_encrypt_key));
        encrypt_key.key_len = key_len;
+
+       if (kp && kp->cipher == WLAN_CIPHER_SUITE_AES_CMAC)
+               encrypt_key.is_igtk_key = true;
+
        if (!disable) {
                encrypt_key.key_index = key_index;
                if (key_len)
                        memcpy(encrypt_key.key_material, key, key_len);
                if (mac_addr)
                        memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN);
+               if (kp && kp->seq && kp->seq_len)
+                       memcpy(encrypt_key.pn, kp->seq, kp->seq_len);
        } else {
                encrypt_key.key_disable = true;
                if (mac_addr)
index 02ce3b77d3e772c4e4cde5615e806be500c4ef43..d91d5c08c73adbb1c6cfd31c69f27366de1c7a21 100644 (file)
@@ -54,8 +54,8 @@ int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter,
 
        local_rx_pd = (struct rxpd *) (skb->data);
 
-       rx_pkt_hdr = (struct rx_packet_hdr *) ((u8 *) local_rx_pd +
-                               local_rx_pd->rx_pkt_offset);
+       rx_pkt_hdr = (void *)local_rx_pd +
+                    le16_to_cpu(local_rx_pd->rx_pkt_offset);
 
        if (!memcmp(&rx_pkt_hdr->rfc1042_hdr,
                    rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr))) {
@@ -125,7 +125,7 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter,
        struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
        struct rx_packet_hdr *rx_pkt_hdr;
        u8 ta[ETH_ALEN];
-       u16 rx_pkt_type;
+       u16 rx_pkt_type, rx_pkt_offset, rx_pkt_length, seq_num;
        struct mwifiex_private *priv =
                        mwifiex_get_priv_by_id(adapter, rx_info->bss_num,
                                               rx_info->bss_type);
@@ -134,16 +134,17 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter,
                return -1;
 
        local_rx_pd = (struct rxpd *) (skb->data);
-       rx_pkt_type = local_rx_pd->rx_pkt_type;
+       rx_pkt_type = le16_to_cpu(local_rx_pd->rx_pkt_type);
+       rx_pkt_offset = le16_to_cpu(local_rx_pd->rx_pkt_offset);
+       rx_pkt_length = le16_to_cpu(local_rx_pd->rx_pkt_length);
+       seq_num = le16_to_cpu(local_rx_pd->seq_num);
 
-       rx_pkt_hdr = (struct rx_packet_hdr *) ((u8 *) local_rx_pd +
-                                       local_rx_pd->rx_pkt_offset);
+       rx_pkt_hdr = (void *)local_rx_pd + rx_pkt_offset;
 
-       if ((local_rx_pd->rx_pkt_offset + local_rx_pd->rx_pkt_length) >
-           (u16) skb->len) {
-               dev_err(adapter->dev, "wrong rx packet: len=%d,"
-                       " rx_pkt_offset=%d, rx_pkt_length=%d\n", skb->len,
-                      local_rx_pd->rx_pkt_offset, local_rx_pd->rx_pkt_length);
+       if ((rx_pkt_offset + rx_pkt_length) > (u16) skb->len) {
+               dev_err(adapter->dev,
+                       "wrong rx packet: len=%d, rx_pkt_offset=%d, rx_pkt_length=%d\n",
+                       skb->len, rx_pkt_offset, rx_pkt_length);
                priv->stats.rx_dropped++;
 
                if (adapter->if_ops.data_complete)
@@ -154,14 +155,14 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter,
                return ret;
        }
 
-       if (local_rx_pd->rx_pkt_type == PKT_TYPE_AMSDU) {
+       if (rx_pkt_type == PKT_TYPE_AMSDU) {
                struct sk_buff_head list;
                struct sk_buff *rx_skb;
 
                __skb_queue_head_init(&list);
 
-               skb_pull(skb, local_rx_pd->rx_pkt_offset);
-               skb_trim(skb, local_rx_pd->rx_pkt_length);
+               skb_pull(skb, rx_pkt_offset);
+               skb_trim(skb, rx_pkt_length);
 
                ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr,
                                         priv->wdev->iftype, 0, false);
@@ -189,17 +190,14 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter,
                memcpy(ta, rx_pkt_hdr->eth803_hdr.h_source, ETH_ALEN);
        } else {
                if (rx_pkt_type != PKT_TYPE_BAR)
-                       priv->rx_seq[local_rx_pd->priority] =
-                                               local_rx_pd->seq_num;
+                       priv->rx_seq[local_rx_pd->priority] = seq_num;
                memcpy(ta, priv->curr_bss_params.bss_descriptor.mac_address,
                       ETH_ALEN);
        }
 
        /* Reorder and send to OS */
-       ret = mwifiex_11n_rx_reorder_pkt(priv, local_rx_pd->seq_num,
-                                            local_rx_pd->priority, ta,
-                                            (u8) local_rx_pd->rx_pkt_type,
-                                            skb);
+       ret = mwifiex_11n_rx_reorder_pkt(priv, seq_num, local_rx_pd->priority,
+                                        ta, (u8) rx_pkt_type, skb);
 
        if (ret || (rx_pkt_type == PKT_TYPE_BAR)) {
                if (adapter->if_ops.data_complete)
index cecb27283196150afdcecc56c451fa396456891f..985073d0df1a17ea9429c82bd0632887182fbec4 100644 (file)
@@ -51,6 +51,9 @@ int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter,
        rx_info->bss_num = priv->bss_num;
        rx_info->bss_type = priv->bss_type;
 
+       if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
+               return mwifiex_process_uap_rx_packet(adapter, skb);
+
        return mwifiex_process_sta_rx_packet(adapter, skb);
 }
 EXPORT_SYMBOL_GPL(mwifiex_handle_rx_packet);
@@ -157,6 +160,8 @@ int mwifiex_write_data_complete(struct mwifiex_adapter *adapter,
                priv->stats.tx_errors++;
        }
 
+       if (tx_info->flags & MWIFIEX_BUF_FLAG_BRIDGED_PKT)
+               atomic_dec_return(&adapter->pending_bridged_pkts);
        if (atomic_dec_return(&adapter->tx_pending) >= LOW_TX_PENDING)
                goto done;
 
index f40e93fe894aca64702219b8223c464a526c92bf..c10aac04be6ad291fc6f247da7f005067091ab52 100644 (file)
@@ -167,6 +167,7 @@ mwifiex_set_ht_params(struct mwifiex_private *priv,
        if (ht_ie) {
                memcpy(&bss_cfg->ht_cap, ht_ie + 2,
                       sizeof(struct ieee80211_ht_cap));
+               priv->ap_11n_enabled = 1;
        } else {
                memset(&bss_cfg->ht_cap , 0, sizeof(struct ieee80211_ht_cap));
                bss_cfg->ht_cap.cap_info = cpu_to_le16(MWIFIEX_DEF_HT_CAP);
diff --git a/drivers/net/wireless/mwifiex/uap_event.c b/drivers/net/wireless/mwifiex/uap_event.c
new file mode 100644 (file)
index 0000000..a33fa39
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ * Marvell Wireless LAN device driver: AP event handling
+ *
+ * Copyright (C) 2012, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "main.h"
+#include "11n.h"
+
+/*
+ * This function will return the pointer to station entry in station list
+ * table which matches specified mac address.
+ * This function should be called after acquiring RA list spinlock.
+ * NULL is returned if station entry is not found in associated STA list.
+ */
+struct mwifiex_sta_node *
+mwifiex_get_sta_entry(struct mwifiex_private *priv, u8 *mac)
+{
+       struct mwifiex_sta_node *node;
+
+       if (!mac)
+               return NULL;
+
+       list_for_each_entry(node, &priv->sta_list, list) {
+               if (!memcmp(node->mac_addr, mac, ETH_ALEN))
+                       return node;
+       }
+
+       return NULL;
+}
+
+/*
+ * This function will add a sta_node entry to associated station list
+ * table with the given mac address.
+ * If entry exist already, existing entry is returned.
+ * If received mac address is NULL, NULL is returned.
+ */
+static struct mwifiex_sta_node *
+mwifiex_add_sta_entry(struct mwifiex_private *priv, u8 *mac)
+{
+       struct mwifiex_sta_node *node;
+       unsigned long flags;
+
+       if (!mac)
+               return NULL;
+
+       spin_lock_irqsave(&priv->sta_list_spinlock, flags);
+       node = mwifiex_get_sta_entry(priv, mac);
+       if (node)
+               goto done;
+
+       node = kzalloc(sizeof(struct mwifiex_sta_node), GFP_ATOMIC);
+       if (!node)
+               goto done;
+
+       memcpy(node->mac_addr, mac, ETH_ALEN);
+       list_add_tail(&node->list, &priv->sta_list);
+
+done:
+       spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
+       return node;
+}
+
+/*
+ * This function will search for HT IE in association request IEs
+ * and set station HT parameters accordingly.
+ */
+static void
+mwifiex_set_sta_ht_cap(struct mwifiex_private *priv, const u8 *ies,
+                      int ies_len, struct mwifiex_sta_node *node)
+{
+       const struct ieee80211_ht_cap *ht_cap;
+
+       if (!ies)
+               return;
+
+       ht_cap = (void *)cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies, ies_len);
+       if (ht_cap) {
+               node->is_11n_enabled = 1;
+               node->max_amsdu = le16_to_cpu(ht_cap->cap_info) &
+                                 IEEE80211_HT_CAP_MAX_AMSDU ?
+                                 MWIFIEX_TX_DATA_BUF_SIZE_8K :
+                                 MWIFIEX_TX_DATA_BUF_SIZE_4K;
+       } else {
+               node->is_11n_enabled = 0;
+       }
+
+       return;
+}
+
+/*
+ * This function will delete a station entry from station list
+ */
+static void mwifiex_del_sta_entry(struct mwifiex_private *priv, u8 *mac)
+{
+       struct mwifiex_sta_node *node, *tmp;
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->sta_list_spinlock, flags);
+
+       node = mwifiex_get_sta_entry(priv, mac);
+       if (node) {
+               list_for_each_entry_safe(node, tmp, &priv->sta_list,
+                                        list) {
+                       list_del(&node->list);
+                       kfree(node);
+               }
+       }
+
+       spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
+       return;
+}
+
+/*
+ * This function will delete all stations from associated station list.
+ */
+static void mwifiex_del_all_sta_list(struct mwifiex_private *priv)
+{
+       struct mwifiex_sta_node *node, *tmp;
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->sta_list_spinlock, flags);
+
+       list_for_each_entry_safe(node, tmp, &priv->sta_list, list) {
+               list_del(&node->list);
+               kfree(node);
+       }
+
+       INIT_LIST_HEAD(&priv->sta_list);
+       spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
+       return;
+}
+
+/*
+ * This function handles AP interface specific events generated by firmware.
+ *
+ * Event specific routines are called by this function based
+ * upon the generated event cause.
+ *
+ *
+ * Events supported for AP -
+ *      - EVENT_UAP_STA_ASSOC
+ *      - EVENT_UAP_STA_DEAUTH
+ *      - EVENT_UAP_BSS_ACTIVE
+ *      - EVENT_UAP_BSS_START
+ *      - EVENT_UAP_BSS_IDLE
+ *      - EVENT_UAP_MIC_COUNTERMEASURES:
+ */
+int mwifiex_process_uap_event(struct mwifiex_private *priv)
+{
+       struct mwifiex_adapter *adapter = priv->adapter;
+       int len, i;
+       u32 eventcause = adapter->event_cause;
+       struct station_info sinfo;
+       struct mwifiex_assoc_event *event;
+       struct mwifiex_sta_node *node;
+       u8 *deauth_mac;
+       struct host_cmd_ds_11n_batimeout *ba_timeout;
+       u16 ctrl;
+
+       switch (eventcause) {
+       case EVENT_UAP_STA_ASSOC:
+               memset(&sinfo, 0, sizeof(sinfo));
+               event = (struct mwifiex_assoc_event *)
+                       (adapter->event_body + MWIFIEX_UAP_EVENT_EXTRA_HEADER);
+               if (le16_to_cpu(event->type) == TLV_TYPE_UAP_MGMT_FRAME) {
+                       len = -1;
+
+                       if (ieee80211_is_assoc_req(event->frame_control))
+                               len = 0;
+                       else if (ieee80211_is_reassoc_req(event->frame_control))
+                               /* There will be ETH_ALEN bytes of
+                                * current_ap_addr before the re-assoc ies.
+                                */
+                               len = ETH_ALEN;
+
+                       if (len != -1) {
+                               sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
+                               sinfo.assoc_req_ies = &event->data[len];
+                               len = (u8 *)sinfo.assoc_req_ies -
+                                     (u8 *)&event->frame_control;
+                               sinfo.assoc_req_ies_len =
+                                       le16_to_cpu(event->len) - (u16)len;
+                       }
+               }
+               cfg80211_new_sta(priv->netdev, event->sta_addr, &sinfo,
+                                GFP_KERNEL);
+
+               node = mwifiex_add_sta_entry(priv, event->sta_addr);
+               if (!node) {
+                       dev_warn(adapter->dev,
+                                "could not create station entry!\n");
+                       return -1;
+               }
+
+               if (!priv->ap_11n_enabled)
+                       break;
+
+               mwifiex_set_sta_ht_cap(priv, sinfo.assoc_req_ies,
+                                      sinfo.assoc_req_ies_len, node);
+
+               for (i = 0; i < MAX_NUM_TID; i++) {
+                       if (node->is_11n_enabled)
+                               node->ampdu_sta[i] =
+                                             priv->aggr_prio_tbl[i].ampdu_user;
+                       else
+                               node->ampdu_sta[i] = BA_STREAM_NOT_ALLOWED;
+               }
+               memset(node->rx_seq, 0xff, sizeof(node->rx_seq));
+               break;
+       case EVENT_UAP_STA_DEAUTH:
+               deauth_mac = adapter->event_body +
+                            MWIFIEX_UAP_EVENT_EXTRA_HEADER;
+               cfg80211_del_sta(priv->netdev, deauth_mac, GFP_KERNEL);
+
+               if (priv->ap_11n_enabled) {
+                       mwifiex_11n_del_rx_reorder_tbl_by_ta(priv, deauth_mac);
+                       mwifiex_del_tx_ba_stream_tbl_by_ra(priv, deauth_mac);
+               }
+               mwifiex_del_sta_entry(priv, deauth_mac);
+               break;
+       case EVENT_UAP_BSS_IDLE:
+               priv->media_connected = false;
+               mwifiex_clean_txrx(priv);
+               mwifiex_del_all_sta_list(priv);
+               break;
+       case EVENT_UAP_BSS_ACTIVE:
+               priv->media_connected = true;
+               break;
+       case EVENT_UAP_BSS_START:
+               dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause);
+               memcpy(priv->netdev->dev_addr, adapter->event_body + 2,
+                      ETH_ALEN);
+               break;
+       case EVENT_UAP_MIC_COUNTERMEASURES:
+               /* For future development */
+               dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause);
+               break;
+       case EVENT_AMSDU_AGGR_CTRL:
+               ctrl = le16_to_cpu(*(__le16 *)adapter->event_body);
+               dev_dbg(adapter->dev, "event: AMSDU_AGGR_CTRL %d\n", ctrl);
+
+               if (priv->media_connected) {
+                       adapter->tx_buf_size =
+                               min_t(u16, adapter->curr_tx_buf_size, ctrl);
+                       dev_dbg(adapter->dev, "event: tx_buf_size %d\n",
+                               adapter->tx_buf_size);
+               }
+               break;
+       case EVENT_ADDBA:
+               dev_dbg(adapter->dev, "event: ADDBA Request\n");
+               if (priv->media_connected)
+                       mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_ADDBA_RSP,
+                                              HostCmd_ACT_GEN_SET, 0,
+                                              adapter->event_body);
+               break;
+       case EVENT_DELBA:
+               dev_dbg(adapter->dev, "event: DELBA Request\n");
+               if (priv->media_connected)
+                       mwifiex_11n_delete_ba_stream(priv, adapter->event_body);
+               break;
+       case EVENT_BA_STREAM_TIEMOUT:
+               dev_dbg(adapter->dev, "event:  BA Stream timeout\n");
+               if (priv->media_connected) {
+                       ba_timeout = (void *)adapter->event_body;
+                       mwifiex_11n_ba_stream_timeout(priv, ba_timeout);
+               }
+               break;
+       default:
+               dev_dbg(adapter->dev, "event: unknown event id: %#x\n",
+                       eventcause);
+               break;
+       }
+
+       return 0;
+}
diff --git a/drivers/net/wireless/mwifiex/uap_txrx.c b/drivers/net/wireless/mwifiex/uap_txrx.c
new file mode 100644 (file)
index 0000000..6d814f0
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * Marvell Wireless LAN device driver: AP TX and RX data handling
+ *
+ * Copyright (C) 2012, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available by writing to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
+ * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include "decl.h"
+#include "ioctl.h"
+#include "main.h"
+#include "wmm.h"
+#include "11n_aggr.h"
+#include "11n_rxreorder.h"
+
+static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv,
+                                        struct sk_buff *skb)
+{
+       struct mwifiex_adapter *adapter = priv->adapter;
+       struct uap_rxpd *uap_rx_pd;
+       struct rx_packet_hdr *rx_pkt_hdr;
+       struct sk_buff *new_skb;
+       struct mwifiex_txinfo *tx_info;
+       int hdr_chop;
+       struct timeval tv;
+       u8 rfc1042_eth_hdr[ETH_ALEN] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+
+       uap_rx_pd = (struct uap_rxpd *)(skb->data);
+       rx_pkt_hdr = (void *)uap_rx_pd + le16_to_cpu(uap_rx_pd->rx_pkt_offset);
+
+       if ((atomic_read(&adapter->pending_bridged_pkts) >=
+                                            MWIFIEX_BRIDGED_PKTS_THRESHOLD)) {
+               dev_err(priv->adapter->dev,
+                       "Tx: Bridge packet limit reached. Drop packet!\n");
+               kfree_skb(skb);
+               return;
+       }
+
+       if (!memcmp(&rx_pkt_hdr->rfc1042_hdr,
+                   rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)))
+               /* Chop off the rxpd + the excess memory from
+                * 802.2/llc/snap header that was removed.
+                */
+               hdr_chop = (u8 *)eth_hdr - (u8 *)uap_rx_pd;
+       else
+               /* Chop off the rxpd */
+               hdr_chop = (u8 *)&rx_pkt_hdr->eth803_hdr - (u8 *)uap_rx_pd;
+
+       /* Chop off the leading header bytes so the it points
+        * to the start of either the reconstructed EthII frame
+        * or the 802.2/llc/snap frame.
+        */
+       skb_pull(skb, hdr_chop);
+
+       if (skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN) {
+               dev_dbg(priv->adapter->dev,
+                       "data: Tx: insufficient skb headroom %d\n",
+                       skb_headroom(skb));
+               /* Insufficient skb headroom - allocate a new skb */
+               new_skb =
+                       skb_realloc_headroom(skb, MWIFIEX_MIN_DATA_HEADER_LEN);
+               if (unlikely(!new_skb)) {
+                       dev_err(priv->adapter->dev,
+                               "Tx: cannot allocate new_skb\n");
+                       kfree_skb(skb);
+                       priv->stats.tx_dropped++;
+                       return;
+               }
+
+               kfree_skb(skb);
+               skb = new_skb;
+               dev_dbg(priv->adapter->dev, "info: new skb headroom %d\n",
+                       skb_headroom(skb));
+       }
+
+       tx_info = MWIFIEX_SKB_TXCB(skb);
+       tx_info->bss_num = priv->bss_num;
+       tx_info->bss_type = priv->bss_type;
+       tx_info->flags |= MWIFIEX_BUF_FLAG_BRIDGED_PKT;
+
+       do_gettimeofday(&tv);
+       skb->tstamp = timeval_to_ktime(tv);
+       mwifiex_wmm_add_buf_txqueue(priv, skb);
+       atomic_inc(&adapter->tx_pending);
+       atomic_inc(&adapter->pending_bridged_pkts);
+
+       if ((atomic_read(&adapter->tx_pending) >= MAX_TX_PENDING)) {
+               mwifiex_set_trans_start(priv->netdev);
+               mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter);
+       }
+       return;
+}
+
+/*
+ * This function contains logic for AP packet forwarding.
+ *
+ * If a packet is multicast/broadcast, it is sent to kernel/upper layer
+ * as well as queued back to AP TX queue so that it can be sent to other
+ * associated stations.
+ * If a packet is unicast and RA is present in associated station list,
+ * it is again requeued into AP TX queue.
+ * If a packet is unicast and RA is not in associated station list,
+ * packet is forwarded to kernel to handle routing logic.
+ */
+int mwifiex_handle_uap_rx_forward(struct mwifiex_private *priv,
+                                 struct sk_buff *skb)
+{
+       struct mwifiex_adapter *adapter = priv->adapter;
+       struct uap_rxpd *uap_rx_pd;
+       struct rx_packet_hdr *rx_pkt_hdr;
+       u8 ra[ETH_ALEN];
+       struct sk_buff *skb_uap;
+
+       uap_rx_pd = (struct uap_rxpd *)(skb->data);
+       rx_pkt_hdr = (void *)uap_rx_pd + le16_to_cpu(uap_rx_pd->rx_pkt_offset);
+
+       /* don't do packet forwarding in disconnected state */
+       if (!priv->media_connected) {
+               dev_err(adapter->dev, "drop packet in disconnected state.\n");
+               dev_kfree_skb_any(skb);
+               return 0;
+       }
+
+       memcpy(ra, rx_pkt_hdr->eth803_hdr.h_dest, ETH_ALEN);
+
+       if (is_multicast_ether_addr(ra)) {
+               skb_uap = skb_copy(skb, GFP_ATOMIC);
+               mwifiex_uap_queue_bridged_pkt(priv, skb_uap);
+       } else {
+               if (mwifiex_get_sta_entry(priv, ra)) {
+                       /* Requeue Intra-BSS packet */
+                       mwifiex_uap_queue_bridged_pkt(priv, skb);
+                       return 0;
+               }
+       }
+
+       /* Forward unicat/Inter-BSS packets to kernel. */
+       return mwifiex_process_rx_packet(adapter, skb);
+}
+
+/*
+ * This function processes the packet received on AP interface.
+ *
+ * The function looks into the RxPD and performs sanity tests on the
+ * received buffer to ensure its a valid packet before processing it
+ * further. If the packet is determined to be aggregated, it is
+ * de-aggregated accordingly. Then skb is passed to AP packet forwarding logic.
+ *
+ * The completion callback is called after processing is complete.
+ */
+int mwifiex_process_uap_rx_packet(struct mwifiex_adapter *adapter,
+                                 struct sk_buff *skb)
+{
+       int ret;
+       struct uap_rxpd *uap_rx_pd;
+       struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
+       struct rx_packet_hdr *rx_pkt_hdr;
+       u16 rx_pkt_type;
+       u8 ta[ETH_ALEN], pkt_type;
+       struct mwifiex_sta_node *node;
+
+       struct mwifiex_private *priv =
+                       mwifiex_get_priv_by_id(adapter, rx_info->bss_num,
+                                              rx_info->bss_type);
+
+       if (!priv)
+               return -1;
+
+       uap_rx_pd = (struct uap_rxpd *)(skb->data);
+       rx_pkt_type = le16_to_cpu(uap_rx_pd->rx_pkt_type);
+       rx_pkt_hdr = (void *)uap_rx_pd + le16_to_cpu(uap_rx_pd->rx_pkt_offset);
+
+       if ((le16_to_cpu(uap_rx_pd->rx_pkt_offset) +
+            le16_to_cpu(uap_rx_pd->rx_pkt_length)) > (u16) skb->len) {
+               dev_err(adapter->dev,
+                       "wrong rx packet: len=%d, offset=%d, length=%d\n",
+                       skb->len, le16_to_cpu(uap_rx_pd->rx_pkt_offset),
+                       le16_to_cpu(uap_rx_pd->rx_pkt_length));
+               priv->stats.rx_dropped++;
+
+               if (adapter->if_ops.data_complete)
+                       adapter->if_ops.data_complete(adapter, skb);
+               else
+                       dev_kfree_skb_any(skb);
+
+               return 0;
+       }
+
+       if (le16_to_cpu(uap_rx_pd->rx_pkt_type) == PKT_TYPE_AMSDU) {
+               struct sk_buff_head list;
+               struct sk_buff *rx_skb;
+
+               __skb_queue_head_init(&list);
+               skb_pull(skb, le16_to_cpu(uap_rx_pd->rx_pkt_offset));
+               skb_trim(skb, le16_to_cpu(uap_rx_pd->rx_pkt_length));
+
+               ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr,
+                                        priv->wdev->iftype, 0, false);
+
+               while (!skb_queue_empty(&list)) {
+                       rx_skb = __skb_dequeue(&list);
+                       ret = mwifiex_recv_packet(adapter, rx_skb);
+                       if (ret)
+                               dev_err(adapter->dev,
+                                       "AP:Rx A-MSDU failed");
+               }
+
+               return 0;
+       }
+
+       memcpy(ta, rx_pkt_hdr->eth803_hdr.h_source, ETH_ALEN);
+
+       if (rx_pkt_type != PKT_TYPE_BAR && uap_rx_pd->priority < MAX_NUM_TID) {
+               node = mwifiex_get_sta_entry(priv, ta);
+               if (node)
+                       node->rx_seq[uap_rx_pd->priority] =
+                                               le16_to_cpu(uap_rx_pd->seq_num);
+       }
+
+       if (!priv->ap_11n_enabled ||
+           (!mwifiex_11n_get_rx_reorder_tbl(priv, uap_rx_pd->priority, ta) &&
+           (le16_to_cpu(uap_rx_pd->rx_pkt_type) != PKT_TYPE_AMSDU))) {
+               ret = mwifiex_handle_uap_rx_forward(priv, skb);
+               return ret;
+       }
+
+       /* Reorder and send to kernel */
+       pkt_type = (u8)le16_to_cpu(uap_rx_pd->rx_pkt_type);
+       ret = mwifiex_11n_rx_reorder_pkt(priv, le16_to_cpu(uap_rx_pd->seq_num),
+                                        uap_rx_pd->priority, ta, pkt_type,
+                                        skb);
+
+       if (ret || (rx_pkt_type == PKT_TYPE_BAR)) {
+               if (adapter->if_ops.data_complete)
+                       adapter->if_ops.data_complete(adapter, skb);
+               else
+                       dev_kfree_skb_any(skb);
+       }
+
+       if (ret)
+               priv->stats.rx_dropped++;
+
+       return ret;
+}
index 3fa4d417699381225e853a56238e0d8506a2f99b..8ccd6999fa9f1972bccf8692337cd22b1b58f892 100644 (file)
@@ -127,6 +127,29 @@ mwifiex_wmm_allocate_ralist_node(struct mwifiex_adapter *adapter, u8 *ra)
        return ra_list;
 }
 
+/* This function returns random no between 16 and 32 to be used as threshold
+ * for no of packets after which BA setup is initiated.
+ */
+static u8 mwifiex_get_random_ba_threshold(void)
+{
+       u32 sec, usec;
+       struct timeval ba_tstamp;
+       u8 ba_threshold;
+
+       /* setup ba_packet_threshold here random number between
+        * [BA_SETUP_PACKET_OFFSET,
+        * BA_SETUP_PACKET_OFFSET+BA_SETUP_MAX_PACKET_THRESHOLD-1]
+        */
+
+       do_gettimeofday(&ba_tstamp);
+       sec = (ba_tstamp.tv_sec & 0xFFFF) + (ba_tstamp.tv_sec >> 16);
+       usec = (ba_tstamp.tv_usec & 0xFFFF) + (ba_tstamp.tv_usec >> 16);
+       ba_threshold = (((sec << 16) + usec) % BA_SETUP_MAX_PACKET_THRESHOLD)
+                                                     + BA_SETUP_PACKET_OFFSET;
+
+       return ba_threshold;
+}
+
 /*
  * This function allocates and adds a RA list for all TIDs
  * with the given RA.
@@ -137,6 +160,12 @@ mwifiex_ralist_add(struct mwifiex_private *priv, u8 *ra)
        int i;
        struct mwifiex_ra_list_tbl *ra_list;
        struct mwifiex_adapter *adapter = priv->adapter;
+       struct mwifiex_sta_node *node;
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->sta_list_spinlock, flags);
+       node = mwifiex_get_sta_entry(priv, ra);
+       spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
 
        for (i = 0; i < MAX_NUM_TID; ++i) {
                ra_list = mwifiex_wmm_allocate_ralist_node(adapter, ra);
@@ -145,14 +174,24 @@ mwifiex_ralist_add(struct mwifiex_private *priv, u8 *ra)
                if (!ra_list)
                        break;
 
-               if (!mwifiex_queuing_ra_based(priv))
+               ra_list->is_11n_enabled = 0;
+               if (!mwifiex_queuing_ra_based(priv)) {
                        ra_list->is_11n_enabled = IS_11N_ENABLED(priv);
-               else
-                       ra_list->is_11n_enabled = false;
+               } else {
+                       ra_list->is_11n_enabled =
+                                     mwifiex_is_sta_11n_enabled(priv, node);
+                       if (ra_list->is_11n_enabled)
+                               ra_list->max_amsdu = node->max_amsdu;
+               }
 
                dev_dbg(adapter->dev, "data: ralist %p: is_11n_enabled=%d\n",
                        ra_list, ra_list->is_11n_enabled);
 
+               if (ra_list->is_11n_enabled) {
+                       ra_list->pkt_count = 0;
+                       ra_list->ba_packet_thr =
+                                             mwifiex_get_random_ba_threshold();
+               }
                list_add_tail(&ra_list->list,
                              &priv->wmm.tid_tbl_ptr[i].ra_list);
 
@@ -647,6 +686,7 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv,
        skb_queue_tail(&ra_list->skb_head, skb);
 
        ra_list->total_pkts_size += skb->len;
+       ra_list->pkt_count++;
 
        atomic_inc(&priv->wmm.tx_pkts_queued);
 
@@ -986,10 +1026,17 @@ mwifiex_is_11n_aggragation_possible(struct mwifiex_private *priv,
 {
        int count = 0, total_size = 0;
        struct sk_buff *skb, *tmp;
+       int max_amsdu_size;
+
+       if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP && priv->ap_11n_enabled &&
+           ptr->is_11n_enabled)
+               max_amsdu_size = min_t(int, ptr->max_amsdu, max_buf_size);
+       else
+               max_amsdu_size = max_buf_size;
 
        skb_queue_walk_safe(&ptr->skb_head, skb, tmp) {
                total_size += skb->len;
-               if (total_size >= max_buf_size)
+               if (total_size >= max_amsdu_size)
                        break;
                if (++count >= MIN_NUM_AMSDU)
                        return true;
@@ -1050,6 +1097,7 @@ mwifiex_send_single_packet(struct mwifiex_private *priv,
                skb_queue_tail(&ptr->skb_head, skb);
 
                ptr->total_pkts_size += skb->len;
+               ptr->pkt_count++;
                tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT;
                spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
                                       ra_list_flags);
@@ -1231,7 +1279,8 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter)
                /* ra_list_spinlock has been freed in
                   mwifiex_send_single_packet() */
        } else {
-               if (mwifiex_is_ampdu_allowed(priv, tid)) {
+               if (mwifiex_is_ampdu_allowed(priv, tid) &&
+                   ptr->pkt_count > ptr->ba_packet_thr) {
                        if (mwifiex_space_avail_for_new_ba_stream(adapter)) {
                                mwifiex_create_ba_tbl(priv, ptr->ra, tid,
                                                      BA_SETUP_INPROGRESS);
index 14037092ba89da99ddf5481a56f730ac6866aa25..1ef1bfe6a9d7845822cef3413e680de03c2774c9 100644 (file)
@@ -76,6 +76,7 @@ struct p54_channel_entry {
        u16 freq;
        u16 data;
        int index;
+       int max_power;
        enum ieee80211_band band;
 };
 
@@ -173,6 +174,7 @@ static int p54_generate_band(struct ieee80211_hw *dev,
        for (i = 0, j = 0; (j < list->band_channel_num[band]) &&
                           (i < list->entries); i++) {
                struct p54_channel_entry *chan = &list->channels[i];
+               struct ieee80211_channel *dest = &tmp->channels[j];
 
                if (chan->band != band)
                        continue;
@@ -190,14 +192,15 @@ static int p54_generate_band(struct ieee80211_hw *dev,
                        continue;
                }
 
-               tmp->channels[j].band = chan->band;
-               tmp->channels[j].center_freq = chan->freq;
+               dest->band = chan->band;
+               dest->center_freq = chan->freq;
+               dest->max_power = chan->max_power;
                priv->survey[*chan_num].channel = &tmp->channels[j];
                priv->survey[*chan_num].filled = SURVEY_INFO_NOISE_DBM |
                        SURVEY_INFO_CHANNEL_TIME |
                        SURVEY_INFO_CHANNEL_TIME_BUSY |
                        SURVEY_INFO_CHANNEL_TIME_TX;
-               tmp->channels[j].hw_value = (*chan_num);
+               dest->hw_value = (*chan_num);
                j++;
                (*chan_num)++;
        }
@@ -229,10 +232,11 @@ err_out:
        return ret;
 }
 
-static void p54_update_channel_param(struct p54_channel_list *list,
-                                    u16 freq, u16 data)
+static struct p54_channel_entry *p54_update_channel_param(struct p54_channel_list *list,
+                                                         u16 freq, u16 data)
 {
-       int band, i;
+       int i;
+       struct p54_channel_entry *entry = NULL;
 
        /*
         * usually all lists in the eeprom are mostly sorted.
@@ -241,30 +245,78 @@ static void p54_update_channel_param(struct p54_channel_list *list,
         */
        for (i = list->entries; i >= 0; i--) {
                if (freq == list->channels[i].freq) {
-                       list->channels[i].data |= data;
+                       entry = &list->channels[i];
                        break;
                }
        }
 
        if ((i < 0) && (list->entries < list->max_entries)) {
                /* entry does not exist yet. Initialize a new one. */
-               band = p54_get_band_from_freq(freq);
+               int band = p54_get_band_from_freq(freq);
 
                /*
                 * filter out frequencies which don't belong into
                 * any supported band.
                 */
-               if (band < 0)
-                       return ;
+               if (band >= 0) {
+                       i = list->entries++;
+                       list->band_channel_num[band]++;
+
+                       entry = &list->channels[i];
+                       entry->freq = freq;
+                       entry->band = band;
+                       entry->index = ieee80211_frequency_to_channel(freq);
+                       entry->max_power = 0;
+                       entry->data = 0;
+               }
+       }
 
-               i = list->entries++;
-               list->band_channel_num[band]++;
+       if (entry)
+               entry->data |= data;
 
-               list->channels[i].freq = freq;
-               list->channels[i].data = data;
-               list->channels[i].band = band;
-               list->channels[i].index = ieee80211_frequency_to_channel(freq);
-               /* TODO: parse output_limit and fill max_power */
+       return entry;
+}
+
+static int p54_get_maxpower(struct p54_common *priv, void *data)
+{
+       switch (priv->rxhw & PDR_SYNTH_FRONTEND_MASK) {
+       case PDR_SYNTH_FRONTEND_LONGBOW: {
+               struct pda_channel_output_limit_longbow *pda = data;
+               int j;
+               u16 rawpower = 0;
+               pda = data;
+               for (j = 0; j < ARRAY_SIZE(pda->point); j++) {
+                       struct pda_channel_output_limit_point_longbow *point =
+                               &pda->point[j];
+                       rawpower = max_t(u16,
+                               rawpower, le16_to_cpu(point->val_qpsk));
+                       rawpower = max_t(u16,
+                               rawpower, le16_to_cpu(point->val_bpsk));
+                       rawpower = max_t(u16,
+                               rawpower, le16_to_cpu(point->val_16qam));
+                       rawpower = max_t(u16,
+                               rawpower, le16_to_cpu(point->val_64qam));
+               }
+               /* longbow seems to use 1/16 dBm units */
+               return rawpower / 16;
+               }
+
+       case PDR_SYNTH_FRONTEND_DUETTE3:
+       case PDR_SYNTH_FRONTEND_DUETTE2:
+       case PDR_SYNTH_FRONTEND_FRISBEE:
+       case PDR_SYNTH_FRONTEND_XBOW: {
+               struct pda_channel_output_limit *pda = data;
+               u8 rawpower = 0;
+               rawpower = max(rawpower, pda->val_qpsk);
+               rawpower = max(rawpower, pda->val_bpsk);
+               rawpower = max(rawpower, pda->val_16qam);
+               rawpower = max(rawpower, pda->val_64qam);
+               /* raw values are in 1/4 dBm units */
+               return rawpower / 4;
+               }
+
+       default:
+               return 20;
        }
 }
 
@@ -315,12 +367,19 @@ static int p54_generate_channel_lists(struct ieee80211_hw *dev)
                }
 
                if (i < priv->output_limit->entries) {
-                       freq = le16_to_cpup((__le16 *) (i *
-                                           priv->output_limit->entry_size +
-                                           priv->output_limit->offset +
-                                           priv->output_limit->data));
-
-                       p54_update_channel_param(list, freq, CHAN_HAS_LIMIT);
+                       struct p54_channel_entry *tmp;
+
+                       void *data = (void *) ((unsigned long) i *
+                               priv->output_limit->entry_size +
+                               priv->output_limit->offset +
+                               priv->output_limit->data);
+
+                       freq = le16_to_cpup((__le16 *) data);
+                       tmp = p54_update_channel_param(list, freq,
+                                                      CHAN_HAS_LIMIT);
+                       if (tmp) {
+                               tmp->max_power = p54_get_maxpower(priv, data);
+                       }
                }
 
                if (i < priv->curve_data->entries) {
@@ -834,11 +893,12 @@ good_eeprom:
                goto err;
        }
 
+       priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK;
+
        err = p54_generate_channel_lists(dev);
        if (err)
                goto err;
 
-       priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK;
        if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW)
                p54_init_xbow_synth(priv);
        if (!(synth & PDR_SYNTH_24_GHZ_DISABLED))
index afde72b8460652dfa1fa3a475b1d35d9f50a04c4..20ebe39a3f4e8714d49cf8ff58478f87f6e4dbde 100644 (file)
@@ -57,6 +57,18 @@ struct pda_channel_output_limit {
        u8 rate_set_size;
 } __packed;
 
+struct pda_channel_output_limit_point_longbow {
+       __le16 val_bpsk;
+       __le16 val_qpsk;
+       __le16 val_16qam;
+       __le16 val_64qam;
+} __packed;
+
+struct pda_channel_output_limit_longbow {
+       __le16 freq;
+       struct pda_channel_output_limit_point_longbow point[3];
+} __packed;
+
 struct pda_pa_curve_data_sample_rev0 {
        u8 rf_power;
        u8 pa_detector;
index 89318adc8c7f0427ec8e95caed78a36312a934b8..b4390797d78c1c6917d4ea81e0ddf2f269fbc46f 100644 (file)
@@ -488,6 +488,58 @@ static int p54p_open(struct ieee80211_hw *dev)
        return 0;
 }
 
+static void p54p_firmware_step2(const struct firmware *fw,
+                               void *context)
+{
+       struct p54p_priv *priv = context;
+       struct ieee80211_hw *dev = priv->common.hw;
+       struct pci_dev *pdev = priv->pdev;
+       int err;
+
+       if (!fw) {
+               dev_err(&pdev->dev, "Cannot find firmware (isl3886pci)\n");
+               err = -ENOENT;
+               goto out;
+       }
+
+       priv->firmware = fw;
+
+       err = p54p_open(dev);
+       if (err)
+               goto out;
+       err = p54_read_eeprom(dev);
+       p54p_stop(dev);
+       if (err)
+               goto out;
+
+       err = p54_register_common(dev, &pdev->dev);
+       if (err)
+               goto out;
+
+out:
+
+       complete(&priv->fw_loaded);
+
+       if (err) {
+               struct device *parent = pdev->dev.parent;
+
+               if (parent)
+                       device_lock(parent);
+
+               /*
+                * This will indirectly result in a call to p54p_remove.
+                * Hence, we don't need to bother with freeing any
+                * allocated ressources at all.
+                */
+               device_release_driver(&pdev->dev);
+
+               if (parent)
+                       device_unlock(parent);
+       }
+
+       pci_dev_put(pdev);
+}
+
 static int __devinit p54p_probe(struct pci_dev *pdev,
                                const struct pci_device_id *id)
 {
@@ -496,6 +548,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
        unsigned long mem_addr, mem_len;
        int err;
 
+       pci_dev_get(pdev);
        err = pci_enable_device(pdev);
        if (err) {
                dev_err(&pdev->dev, "Cannot enable new PCI device\n");
@@ -537,6 +590,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
        priv = dev->priv;
        priv->pdev = pdev;
 
+       init_completion(&priv->fw_loaded);
        SET_IEEE80211_DEV(dev, &pdev->dev);
        pci_set_drvdata(pdev, dev);
 
@@ -561,32 +615,12 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
        spin_lock_init(&priv->lock);
        tasklet_init(&priv->tasklet, p54p_tasklet, (unsigned long)dev);
 
-       err = request_firmware(&priv->firmware, "isl3886pci",
-                              &priv->pdev->dev);
-       if (err) {
-               dev_err(&pdev->dev, "Cannot find firmware (isl3886pci)\n");
-               err = request_firmware(&priv->firmware, "isl3886",
-                                      &priv->pdev->dev);
-               if (err)
-                       goto err_free_common;
-       }
-
-       err = p54p_open(dev);
-       if (err)
-               goto err_free_common;
-       err = p54_read_eeprom(dev);
-       p54p_stop(dev);
-       if (err)
-               goto err_free_common;
-
-       err = p54_register_common(dev, &pdev->dev);
-       if (err)
-               goto err_free_common;
-
-       return 0;
+       err = request_firmware_nowait(THIS_MODULE, 1, "isl3886pci",
+                                     &priv->pdev->dev, GFP_KERNEL,
+                                     priv, p54p_firmware_step2);
+       if (!err)
+               return 0;
 
- err_free_common:
-       release_firmware(priv->firmware);
        pci_free_consistent(pdev, sizeof(*priv->ring_control),
                            priv->ring_control, priv->ring_control_dma);
 
@@ -601,6 +635,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
        pci_release_regions(pdev);
  err_disable_dev:
        pci_disable_device(pdev);
+       pci_dev_put(pdev);
        return err;
 }
 
@@ -612,8 +647,9 @@ static void __devexit p54p_remove(struct pci_dev *pdev)
        if (!dev)
                return;
 
-       p54_unregister_common(dev);
        priv = dev->priv;
+       wait_for_completion(&priv->fw_loaded);
+       p54_unregister_common(dev);
        release_firmware(priv->firmware);
        pci_free_consistent(pdev, sizeof(*priv->ring_control),
                            priv->ring_control, priv->ring_control_dma);
index 7aa509f7e387c052c31ca56d9a159b0dbc8d1743..68405c142f973d356a8847c72cafb5d3fdc6f6fe 100644 (file)
@@ -105,6 +105,7 @@ struct p54p_priv {
        struct sk_buff *tx_buf_data[32];
        struct sk_buff *tx_buf_mgmt[4];
        struct completion boot_comp;
+       struct completion fw_loaded;
 };
 
 #endif /* P54USB_H */
index 241162e8111d2584f0fca6f47819cf924cdf1157..7a4ae9ee1c63057b78d582fd3a94964a6fdea264 100644 (file)
@@ -1803,6 +1803,7 @@ static struct ndis_80211_pmkid *update_pmkid(struct usbnet *usbdev,
                                                struct cfg80211_pmksa *pmksa,
                                                int max_pmkids)
 {
+       struct ndis_80211_pmkid *new_pmkids;
        int i, err, newlen;
        unsigned int count;
 
@@ -1833,11 +1834,12 @@ static struct ndis_80211_pmkid *update_pmkid(struct usbnet *usbdev,
        /* add new pmkid */
        newlen = sizeof(*pmkids) + (count + 1) * sizeof(pmkids->bssid_info[0]);
 
-       pmkids = krealloc(pmkids, newlen, GFP_KERNEL);
-       if (!pmkids) {
+       new_pmkids = krealloc(pmkids, newlen, GFP_KERNEL);
+       if (!new_pmkids) {
                err = -ENOMEM;
                goto error;
        }
+       pmkids = new_pmkids;
 
        pmkids->length = cpu_to_le32(newlen);
        pmkids->bssid_info_count = cpu_to_le32(count + 1);
index 88455b1b9fe05b299aff2cc667d3d90e7822855a..cb8c2aca54e4dfdac4a7e223a8070f4e4543399e 100644 (file)
@@ -221,6 +221,67 @@ static void rt2800_rf_write(struct rt2x00_dev *rt2x00dev,
        mutex_unlock(&rt2x00dev->csr_mutex);
 }
 
+static int rt2800_enable_wlan_rt3290(struct rt2x00_dev *rt2x00dev)
+{
+       u32 reg;
+       int i, count;
+
+       rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, &reg);
+       if (rt2x00_get_field32(reg, WLAN_EN))
+               return 0;
+
+       rt2x00_set_field32(&reg, WLAN_GPIO_OUT_OE_BIT_ALL, 0xff);
+       rt2x00_set_field32(&reg, FRC_WL_ANT_SET, 1);
+       rt2x00_set_field32(&reg, WLAN_CLK_EN, 0);
+       rt2x00_set_field32(&reg, WLAN_EN, 1);
+       rt2800_register_write(rt2x00dev, WLAN_FUN_CTRL, reg);
+
+       udelay(REGISTER_BUSY_DELAY);
+
+       count = 0;
+       do {
+               /*
+                * Check PLL_LD & XTAL_RDY.
+                */
+               for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+                       rt2800_register_read(rt2x00dev, CMB_CTRL, &reg);
+                       if (rt2x00_get_field32(reg, PLL_LD) &&
+                           rt2x00_get_field32(reg, XTAL_RDY))
+                               break;
+                       udelay(REGISTER_BUSY_DELAY);
+               }
+
+               if (i >= REGISTER_BUSY_COUNT) {
+
+                       if (count >= 10)
+                               return -EIO;
+
+                       rt2800_register_write(rt2x00dev, 0x58, 0x018);
+                       udelay(REGISTER_BUSY_DELAY);
+                       rt2800_register_write(rt2x00dev, 0x58, 0x418);
+                       udelay(REGISTER_BUSY_DELAY);
+                       rt2800_register_write(rt2x00dev, 0x58, 0x618);
+                       udelay(REGISTER_BUSY_DELAY);
+                       count++;
+               } else {
+                       count = 0;
+               }
+
+               rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, &reg);
+               rt2x00_set_field32(&reg, PCIE_APP0_CLK_REQ, 0);
+               rt2x00_set_field32(&reg, WLAN_CLK_EN, 1);
+               rt2x00_set_field32(&reg, WLAN_RESET, 1);
+               rt2800_register_write(rt2x00dev, WLAN_FUN_CTRL, reg);
+               udelay(10);
+               rt2x00_set_field32(&reg, WLAN_RESET, 0);
+               rt2800_register_write(rt2x00dev, WLAN_FUN_CTRL, reg);
+               udelay(10);
+               rt2800_register_write(rt2x00dev, INT_SOURCE_CSR, 0x7fffffff);
+       } while (count != 0);
+
+       return 0;
+}
+
 void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
                        const u8 command, const u8 token,
                        const u8 arg0, const u8 arg1)
@@ -400,6 +461,13 @@ int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev,
 {
        unsigned int i;
        u32 reg;
+       int retval;
+
+       if (rt2x00_rt(rt2x00dev, RT3290)) {
+               retval = rt2800_enable_wlan_rt3290(rt2x00dev);
+               if (retval)
+                       return -EBUSY;
+       }
 
        /*
         * If driver doesn't wake up firmware here,
index 235376e9cb04c0066032493f2d86b008d604c14c..98aa426a35649828e3c70c0f2bab0acf24e49381 100644 (file)
@@ -980,66 +980,6 @@ static int rt2800pci_validate_eeprom(struct rt2x00_dev *rt2x00dev)
        return rt2800_validate_eeprom(rt2x00dev);
 }
 
-static int rt2800_enable_wlan_rt3290(struct rt2x00_dev *rt2x00dev)
-{
-       u32 reg;
-       int i, count;
-
-       rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, &reg);
-       if (rt2x00_get_field32(reg, WLAN_EN))
-               return 0;
-
-       rt2x00_set_field32(&reg, WLAN_GPIO_OUT_OE_BIT_ALL, 0xff);
-       rt2x00_set_field32(&reg, FRC_WL_ANT_SET, 1);
-       rt2x00_set_field32(&reg, WLAN_CLK_EN, 0);
-       rt2x00_set_field32(&reg, WLAN_EN, 1);
-       rt2800_register_write(rt2x00dev, WLAN_FUN_CTRL, reg);
-
-       udelay(REGISTER_BUSY_DELAY);
-
-       count = 0;
-       do {
-               /*
-                * Check PLL_LD & XTAL_RDY.
-                */
-               for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
-                       rt2800_register_read(rt2x00dev, CMB_CTRL, &reg);
-                       if (rt2x00_get_field32(reg, PLL_LD) &&
-                           rt2x00_get_field32(reg, XTAL_RDY))
-                               break;
-                       udelay(REGISTER_BUSY_DELAY);
-               }
-
-               if (i >= REGISTER_BUSY_COUNT) {
-
-                       if (count >= 10)
-                               return -EIO;
-
-                       rt2800_register_write(rt2x00dev, 0x58, 0x018);
-                       udelay(REGISTER_BUSY_DELAY);
-                       rt2800_register_write(rt2x00dev, 0x58, 0x418);
-                       udelay(REGISTER_BUSY_DELAY);
-                       rt2800_register_write(rt2x00dev, 0x58, 0x618);
-                       udelay(REGISTER_BUSY_DELAY);
-                       count++;
-               } else {
-                       count = 0;
-               }
-
-               rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, &reg);
-               rt2x00_set_field32(&reg, PCIE_APP0_CLK_REQ, 0);
-               rt2x00_set_field32(&reg, WLAN_CLK_EN, 1);
-               rt2x00_set_field32(&reg, WLAN_RESET, 1);
-               rt2800_register_write(rt2x00dev, WLAN_FUN_CTRL, reg);
-               udelay(10);
-               rt2x00_set_field32(&reg, WLAN_RESET, 0);
-               rt2800_register_write(rt2x00dev, WLAN_FUN_CTRL, reg);
-               udelay(10);
-               rt2800_register_write(rt2x00dev, INT_SOURCE_CSR, 0x7fffffff);
-       } while (count != 0);
-
-       return 0;
-}
 static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
 {
        int retval;
@@ -1062,17 +1002,6 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
        if (retval)
                return retval;
 
-       /*
-        * In probe phase call rt2800_enable_wlan_rt3290 to enable wlan
-        * clk for rt3290. That avoid the MCU fail in start phase.
-        */
-       if (rt2x00_rt(rt2x00dev, RT3290)) {
-               retval = rt2800_enable_wlan_rt3290(rt2x00dev);
-
-               if (retval)
-                       return retval;
-       }
-
        /*
         * This device has multiple filters for control frames
         * and has a separate filter for PS Poll frames.
index f32259686b45778b77630328e54e2c1298b18a84..3f7bc5cadf9a8a7a433688e8d480d76de3c1ab82 100644 (file)
@@ -2243,8 +2243,7 @@ static void rt61pci_txdone(struct rt2x00_dev *rt2x00dev)
 
 static void rt61pci_wakeup(struct rt2x00_dev *rt2x00dev)
 {
-       struct ieee80211_conf conf = { .flags = 0 };
-       struct rt2x00lib_conf libconf = { .conf = &conf };
+       struct rt2x00lib_conf libconf = { .conf = &rt2x00dev->hw->conf };
 
        rt61pci_config(rt2x00dev, &libconf, IEEE80211_CONF_CHANGE_PS);
 }
index af83c43bcdb1ebe7d08c27ec6f6d85e13f4cf954..ef2b171e351479f5d9268a00e360d4e3ff525d1b 100644 (file)
@@ -1164,8 +1164,7 @@ void zd_usb_reset_rx_idle_timer(struct zd_usb *usb)
 {
        struct zd_usb_rx *rx = &usb->rx;
 
-       cancel_delayed_work(&rx->idle_work);
-       queue_delayed_work(zd_workqueue, &rx->idle_work, ZD_RX_IDLE_INTERVAL);
+       mod_delayed_work(zd_workqueue, &rx->idle_work, ZD_RX_IDLE_INTERVAL);
 }
 
 static inline void init_usb_interrupt(struct zd_usb *usb)
index 30899901aef56b00e05c5f062c86cabcb54127d8..39afd37e62b366b9701240c83eba7b8b9381979d 100644 (file)
@@ -1731,7 +1731,7 @@ static void netback_changed(struct xenbus_device *dev,
                break;
 
        case XenbusStateConnected:
-               netif_notify_peers(netdev);
+               netdev_notify_peers(netdev);
                break;
 
        case XenbusStateClosing:
index 7e262a6124c5919a495545bb1f7402ae4350295a..7a07751428de44c06a75389749d6bfa7d8ad2ac3 100644 (file)
@@ -9,8 +9,8 @@
 
 /* Max address size we deal with */
 #define OF_MAX_ADDR_CELLS      4
-#define OF_CHECK_COUNTS(na, ns)        ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \
-                       (ns) > 0)
+#define OF_CHECK_ADDR_COUNT(na)        ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS)
+#define OF_CHECK_COUNTS(na, ns)        (OF_CHECK_ADDR_COUNT(na) && (ns) > 0)
 
 static struct of_bus *of_match_bus(struct device_node *np);
 static int __of_address_to_resource(struct device_node *dev,
@@ -182,7 +182,7 @@ const __be32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
        }
        bus->count_cells(dev, &na, &ns);
        of_node_put(parent);
-       if (!OF_CHECK_COUNTS(na, ns))
+       if (!OF_CHECK_ADDR_COUNT(na))
                return NULL;
 
        /* Get "reg" or "assigned-addresses" property */
@@ -490,6 +490,25 @@ u64 of_translate_dma_address(struct device_node *dev, const __be32 *in_addr)
 }
 EXPORT_SYMBOL(of_translate_dma_address);
 
+bool of_can_translate_address(struct device_node *dev)
+{
+       struct device_node *parent;
+       struct of_bus *bus;
+       int na, ns;
+
+       parent = of_get_parent(dev);
+       if (parent == NULL)
+               return false;
+
+       bus = of_match_bus(parent);
+       bus->count_cells(dev, &na, &ns);
+
+       of_node_put(parent);
+
+       return OF_CHECK_COUNTS(na, ns);
+}
+EXPORT_SYMBOL(of_can_translate_address);
+
 const __be32 *of_get_address(struct device_node *dev, int index, u64 *size,
                    unsigned int *flags)
 {
@@ -506,7 +525,7 @@ const __be32 *of_get_address(struct device_node *dev, int index, u64 *size,
        bus = of_match_bus(parent);
        bus->count_cells(dev, &na, &ns);
        of_node_put(parent);
-       if (!OF_CHECK_COUNTS(na, ns))
+       if (!OF_CHECK_ADDR_COUNT(na))
                return NULL;
 
        /* Get "reg" or "assigned-addresses" property */
index c181b94abc363b64a4a38c2e39625b7564dc2267..2f84e709e360a4840f5e15910deb133d9dea5b11 100644 (file)
@@ -961,6 +961,8 @@ int of_parse_phandle_with_args(struct device_node *np, const char *list_name,
                                out_args->args_count = count;
                                for (i = 0; i < count; i++)
                                        out_args->args[i] = be32_to_cpup(list++);
+                       } else {
+                               of_node_put(node);
                        }
                        return 0;
                }
index e44f8c2d239d253afc045164834f0476b94cf932..9bdeaf30b17dd5a197f373f9baa18401338ef3d8 100644 (file)
@@ -78,6 +78,7 @@ void of_device_make_bus_id(struct device *dev)
        struct device_node *node = dev->of_node;
        const u32 *reg;
        u64 addr;
+       const __be32 *addrp;
        int magic;
 
 #ifdef CONFIG_PPC_DCR
@@ -105,7 +106,15 @@ void of_device_make_bus_id(struct device *dev)
         */
        reg = of_get_property(node, "reg", NULL);
        if (reg) {
-               addr = of_translate_address(node, reg);
+               if (of_can_translate_address(node)) {
+                       addr = of_translate_address(node, reg);
+               } else {
+                       addrp = of_get_address(node, 0, NULL, NULL);
+                       if (addrp)
+                               addr = of_read_number(addrp, 1);
+                       else
+                               addr = OF_BAD_ADDR;
+               }
                if (addr != OF_BAD_ADDR) {
                        dev_set_name(dev, "%llx.%s",
                                     (unsigned long long)addr, node->name);
@@ -140,8 +149,9 @@ struct platform_device *of_device_alloc(struct device_node *np,
                return NULL;
 
        /* count the io and irq resources */
-       while (of_address_to_resource(np, num_reg, &temp_res) == 0)
-               num_reg++;
+       if (of_can_translate_address(np))
+               while (of_address_to_resource(np, num_reg, &temp_res) == 0)
+                       num_reg++;
        num_irq = of_irq_count(np);
 
        /* Populate the resource table */
index fbf7b26c7c8a5119c527c00a15a35539b4aa3a2b..c5792d622dc4528ba572632d39c7c1f1d7ae438d 100644 (file)
@@ -266,8 +266,8 @@ static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)
        }
 
        if (!error)
-               dev_printk(KERN_INFO, &dev->dev,
-                               "power state changed by ACPI to D%d\n", state);
+               dev_info(&dev->dev, "power state changed by ACPI to %s\n",
+                        pci_power_name(state));
 
        return error;
 }
index 185be37033430adf53d8a390fd34a4c9dfd6e446..5270f1a99328d678396739781c7b0d4a87a586ef 100644 (file)
@@ -959,6 +959,13 @@ static int pci_pm_poweroff_noirq(struct device *dev)
        if (!pci_dev->state_saved && !pci_is_bridge(pci_dev))
                pci_prepare_to_sleep(pci_dev);
 
+       /*
+        * The reason for doing this here is the same as for the analogous code
+        * in pci_pm_suspend_noirq().
+        */
+       if (pci_dev->class == PCI_CLASS_SERIAL_USB_EHCI)
+               pci_write_config_word(pci_dev, PCI_COMMAND, 0);
+
        return 0;
 }
 
index 0ca053538146b92d9a80d7e306d05b52a5b3bfc3..70758881480b095db5416753584fef11d3cf7f9a 100644 (file)
@@ -540,14 +540,12 @@ static void do_recovery(struct pci_dev *dev, int severity)
                                "resume",
                                report_resume);
 
-       dev_printk(KERN_DEBUG, &dev->dev,
-               "AER driver successfully recovered\n");
+       dev_info(&dev->dev, "AER: Device recovery successful\n");
        return;
 
 failed:
        /* TODO: Should kernel panic here? */
-       dev_printk(KERN_DEBUG, &dev->dev,
-               "AER driver didn't recover\n");
+       dev_info(&dev->dev, "AER: Device recovery failed\n");
 }
 
 /**
index eb219a1d16f760f4596dded6e9811b006946586d..270ae7b971203108aa396cbd561f87013a78bb43 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/cache.h>
 
 
-static void __init
+static void
 pdev_fixup_irq(struct pci_dev *dev,
               u8 (*swizzle)(struct pci_dev *, u8 *),
               int (*map_irq)(const struct pci_dev *, u8, u8))
@@ -54,7 +54,7 @@ pdev_fixup_irq(struct pci_dev *dev,
        pcibios_update_irq(dev, irq);
 }
 
-void __init
+void
 pci_fixup_irqs(u8 (*swizzle)(struct pci_dev *, u8 *),
               int (*map_irq)(const struct pci_dev *, u8, u8))
 {
index 54e3588bef62ab73ef75cbc6f8878d84c72e43ec..73aafd96271fea082b9261b16e46960847f14bbe 100644 (file)
@@ -31,6 +31,14 @@ config PINCTRL_IMX
        select PINMUX
        select PINCONF
 
+config PINCTRL_IMX35
+       bool "IMX35 pinctrl driver"
+       depends on OF
+       depends on SOC_IMX35
+       select PINCTRL_IMX
+       help
+         Say Y here to enable the imx35 pinctrl driver
+
 config PINCTRL_IMX51
        bool "IMX51 pinctrl driver"
        depends on OF
@@ -86,10 +94,18 @@ config PINCTRL_NOMADIK
        select PINMUX
        select PINCONF
 
+config PINCTRL_STN8815
+       bool "STN8815 pin controller driver"
+       depends on PINCTRL_NOMADIK && ARCH_NOMADIK
+
 config PINCTRL_DB8500
        bool "DB8500 pin controller driver"
        depends on PINCTRL_NOMADIK && ARCH_U8500
 
+config PINCTRL_DB8540
+       bool "DB8540 pin controller driver"
+       depends on PINCTRL_NOMADIK && ARCH_U8500
+
 config PINCTRL_PXA168
        bool "PXA168 pin controller driver"
        depends on ARCH_MMP
index f40b1f81ff2ceea2f7421bc8d9761f7bb990bb11..cda3984951e28c4f465623cdca3922e68eab4c17 100644 (file)
@@ -10,6 +10,7 @@ obj-$(CONFIG_PINCTRL)         += devicetree.o
 endif
 obj-$(CONFIG_GENERIC_PINCONF)  += pinconf-generic.o
 obj-$(CONFIG_PINCTRL_IMX)      += pinctrl-imx.o
+obj-$(CONFIG_PINCTRL_IMX35)    += pinctrl-imx35.o
 obj-$(CONFIG_PINCTRL_IMX51)    += pinctrl-imx51.o
 obj-$(CONFIG_PINCTRL_IMX53)    += pinctrl-imx53.o
 obj-$(CONFIG_PINCTRL_IMX6Q)    += pinctrl-imx6q.o
@@ -19,7 +20,9 @@ obj-$(CONFIG_PINCTRL_MXS)     += pinctrl-mxs.o
 obj-$(CONFIG_PINCTRL_IMX23)    += pinctrl-imx23.o
 obj-$(CONFIG_PINCTRL_IMX28)    += pinctrl-imx28.o
 obj-$(CONFIG_PINCTRL_NOMADIK)  += pinctrl-nomadik.o
+obj-$(CONFIG_PINCTRL_STN8815)  += pinctrl-nomadik-stn8815.o
 obj-$(CONFIG_PINCTRL_DB8500)   += pinctrl-nomadik-db8500.o
+obj-$(CONFIG_PINCTRL_DB8540)   += pinctrl-nomadik-db8540.o
 obj-$(CONFIG_PINCTRL_PXA168)   += pinctrl-pxa168.o
 obj-$(CONFIG_PINCTRL_PXA910)   += pinctrl-pxa910.o
 obj-$(CONFIG_PINCTRL_SINGLE)   += pinctrl-single.o
index fb7f3bebdc69dadec1451773c596c9b901821265..dc5c126e398a0ac84fc13fa5f564d832ade0831e 100644 (file)
@@ -657,11 +657,7 @@ static struct pinctrl *pinctrl_get_locked(struct device *dev)
        if (p != NULL)
                return ERR_PTR(-EBUSY);
 
-       p = create_pinctrl(dev);
-       if (IS_ERR(p))
-               return p;
-
-       return p;
+       return create_pinctrl(dev);
 }
 
 /**
@@ -738,11 +734,8 @@ static struct pinctrl_state *pinctrl_lookup_state_locked(struct pinctrl *p,
                        dev_dbg(p->dev, "using pinctrl dummy state (%s)\n",
                                name);
                        state = create_state(p, name);
-                       if (IS_ERR(state))
-                               return state;
-               } else {
-                       return ERR_PTR(-ENODEV);
-               }
+               } else
+                       state = ERR_PTR(-ENODEV);
        }
 
        return state;
index cc0f00d73d15512a5d93906088e78d7635971af1..b446c9641212884f8cb2ff5e7df0d81aa032dca3 100644 (file)
@@ -1,11 +1,8 @@
 /*
  * U300 GPIO module.
  *
- * Copyright (C) 2007-2011 ST-Ericsson AB
+ * Copyright (C) 2007-2012 ST-Ericsson AB
  * License terms: GNU General Public License (GPL) version 2
- * This can driver either of the two basic GPIO cores
- * available in the U300 platforms:
- * COH 901 335   - Used in DB3150 (U300 1.0) and DB3200 (U330 1.0)
  * COH 901 571/3 - Used in DB3210 (U365 2.0) and DB3350 (U335 1.0)
  * Author: Linus Walleij <linus.walleij@linaro.org>
  * Author: Jonas Aaberg <jonas.aberg@stericsson.com>
 #include <linux/slab.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/pinctrl/pinconf-generic.h>
-#include <mach/gpio-u300.h>
+#include <linux/platform_data/pinctrl-coh901.h>
 #include "pinctrl-coh901.h"
 
+#define U300_GPIO_PORT_STRIDE                          (0x30)
 /*
- * Register definitions for COH 901 335 variant
+ * Control Register 32bit (R/W)
+ * bit 15-9 (mask 0x0000FE00) contains the number of cores. 8*cores
+ * gives the number of GPIO pins.
+ * bit 8-2  (mask 0x000001FC) contains the core version ID.
  */
-#define U300_335_PORT_STRIDE                           (0x1C)
-/* Port X Pin Data Register 32bit, this is both input and output (R/W) */
-#define U300_335_PXPDIR                                        (0x00)
-#define U300_335_PXPDOR                                        (0x00)
-/* Port X Pin Config Register 32bit (R/W) */
-#define U300_335_PXPCR                                 (0x04)
-/* This register layout is the same in both blocks */
+#define U300_GPIO_CR                                   (0x00)
+#define U300_GPIO_CR_SYNC_SEL_ENABLE                   (0x00000002UL)
+#define U300_GPIO_CR_BLOCK_CLKRQ_ENABLE                        (0x00000001UL)
+#define U300_GPIO_PXPDIR                               (0x04)
+#define U300_GPIO_PXPDOR                               (0x08)
+#define U300_GPIO_PXPCR                                        (0x0C)
 #define U300_GPIO_PXPCR_ALL_PINS_MODE_MASK             (0x0000FFFFUL)
 #define U300_GPIO_PXPCR_PIN_MODE_MASK                  (0x00000003UL)
 #define U300_GPIO_PXPCR_PIN_MODE_SHIFT                 (0x00000002UL)
 #define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL      (0x00000001UL)
 #define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_DRAIN     (0x00000002UL)
 #define U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_SOURCE    (0x00000003UL)
-/* Port X Interrupt Event Register 32bit (R/W) */
-#define U300_335_PXIEV                                 (0x08)
-/* Port X Interrupt Enable Register 32bit (R/W) */
-#define U300_335_PXIEN                                 (0x0C)
-/* Port X Interrupt Force Register 32bit (R/W) */
-#define U300_335_PXIFR                                 (0x10)
-/* Port X Interrupt Config Register 32bit (R/W) */
-#define U300_335_PXICR                                 (0x14)
-/* This register layout is the same in both blocks */
+#define U300_GPIO_PXPER                                        (0x10)
+#define U300_GPIO_PXPER_ALL_PULL_UP_DISABLE_MASK       (0x000000FFUL)
+#define U300_GPIO_PXPER_PULL_UP_DISABLE                        (0x00000001UL)
+#define U300_GPIO_PXIEV                                        (0x14)
+#define U300_GPIO_PXIEN                                        (0x18)
+#define U300_GPIO_PXIFR                                        (0x1C)
+#define U300_GPIO_PXICR                                        (0x20)
 #define U300_GPIO_PXICR_ALL_IRQ_CONFIG_MASK            (0x000000FFUL)
 #define U300_GPIO_PXICR_IRQ_CONFIG_MASK                        (0x00000001UL)
 #define U300_GPIO_PXICR_IRQ_CONFIG_FALLING_EDGE                (0x00000000UL)
 #define U300_GPIO_PXICR_IRQ_CONFIG_RISING_EDGE         (0x00000001UL)
-/* Port X Pull-up Enable Register 32bit (R/W) */
-#define U300_335_PXPER                                 (0x18)
-/* This register layout is the same in both blocks */
-#define U300_GPIO_PXPER_ALL_PULL_UP_DISABLE_MASK       (0x000000FFUL)
-#define U300_GPIO_PXPER_PULL_UP_DISABLE                        (0x00000001UL)
-/* Control Register 32bit (R/W) */
-#define U300_335_CR                                    (0x54)
-#define U300_335_CR_BLOCK_CLOCK_ENABLE                 (0x00000001UL)
-
-/*
- * Register definitions for COH 901 571 / 3 variant
- */
-#define U300_571_PORT_STRIDE                           (0x30)
-/*
- * Control Register 32bit (R/W)
- * bit 15-9 (mask 0x0000FE00) contains the number of cores. 8*cores
- * gives the number of GPIO pins.
- * bit 8-2  (mask 0x000001FC) contains the core version ID.
- */
-#define U300_571_CR                                    (0x00)
-#define U300_571_CR_SYNC_SEL_ENABLE                    (0x00000002UL)
-#define U300_571_CR_BLOCK_CLKRQ_ENABLE                 (0x00000001UL)
-/*
- * These registers have the same layout and function as the corresponding
- * COH 901 335 registers, just at different offset.
- */
-#define U300_571_PXPDIR                                        (0x04)
-#define U300_571_PXPDOR                                        (0x08)
-#define U300_571_PXPCR                                 (0x0C)
-#define U300_571_PXPER                                 (0x10)
-#define U300_571_PXIEV                                 (0x14)
-#define U300_571_PXIEN                                 (0x18)
-#define U300_571_PXIFR                                 (0x1C)
-#define U300_571_PXICR                                 (0x20)
 
 /* 8 bits per port, no version has more than 7 ports */
 #define U300_GPIO_PINS_PER_PORT 8
@@ -149,8 +113,6 @@ struct u300_gpio_confdata {
 
 /* BS335 has seven ports of 8 bits each = GPIO pins 0..55 */
 #define BS335_GPIO_NUM_PORTS 7
-/* BS365 has five ports of 8 bits each = GPIO pins 0..39 */
-#define BS365_GPIO_NUM_PORTS 5
 
 #define U300_FLOATING_INPUT { \
        .bias_mode = PIN_CONFIG_BIAS_HIGH_IMPEDANCE, \
@@ -172,7 +134,6 @@ struct u300_gpio_confdata {
        .outval = 1, \
 }
 
-
 /* Initial configuration */
 static const struct __initconst u300_gpio_confdata
 bs335_gpio_config[BS335_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = {
@@ -255,66 +216,6 @@ bs335_gpio_config[BS335_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = {
        }
 };
 
-static const struct __initconst u300_gpio_confdata
-bs365_gpio_config[BS365_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = {
-       /* Port 0, pins 0-7 */
-       {
-               U300_FLOATING_INPUT,
-               U300_OUTPUT_LOW,
-               U300_FLOATING_INPUT,
-               U300_OUTPUT_LOW,
-               U300_OUTPUT_LOW,
-               U300_OUTPUT_LOW,
-               U300_PULL_UP_INPUT,
-               U300_FLOATING_INPUT,
-       },
-       /* Port 1, pins 0-7 */
-       {
-               U300_OUTPUT_LOW,
-               U300_FLOATING_INPUT,
-               U300_OUTPUT_LOW,
-               U300_FLOATING_INPUT,
-               U300_FLOATING_INPUT,
-               U300_OUTPUT_HIGH,
-               U300_OUTPUT_LOW,
-               U300_OUTPUT_LOW,
-       },
-       /* Port 2, pins 0-7 */
-       {
-               U300_FLOATING_INPUT,
-               U300_PULL_UP_INPUT,
-               U300_OUTPUT_LOW,
-               U300_OUTPUT_LOW,
-               U300_PULL_UP_INPUT,
-               U300_PULL_UP_INPUT,
-               U300_PULL_UP_INPUT,
-               U300_PULL_UP_INPUT,
-       },
-       /* Port 3, pins 0-7 */
-       {
-               U300_PULL_UP_INPUT,
-               U300_PULL_UP_INPUT,
-               U300_PULL_UP_INPUT,
-               U300_PULL_UP_INPUT,
-               U300_PULL_UP_INPUT,
-               U300_PULL_UP_INPUT,
-               U300_PULL_UP_INPUT,
-               U300_PULL_UP_INPUT,
-       },
-       /* Port 4, pins 0-7 */
-       {
-               U300_PULL_UP_INPUT,
-               U300_PULL_UP_INPUT,
-               U300_PULL_UP_INPUT,
-               U300_PULL_UP_INPUT,
-               /* These 4 pins doesn't exist on DB3210 */
-               U300_OUTPUT_LOW,
-               U300_OUTPUT_LOW,
-               U300_OUTPUT_LOW,
-               U300_OUTPUT_LOW,
-       }
-};
-
 /**
  * to_u300_gpio() - get the pointer to u300_gpio
  * @chip: the gpio chip member of the structure u300_gpio
@@ -716,13 +617,7 @@ static void __init u300_gpio_init_coh901571(struct u300_gpio *gpio,
                        const struct u300_gpio_confdata *conf;
                        int offset = (i*8) + j;
 
-                       if (plat->variant == U300_GPIO_COH901571_3_BS335)
-                               conf = &bs335_gpio_config[i][j];
-                       else if (plat->variant == U300_GPIO_COH901571_3_BS365)
-                               conf = &bs365_gpio_config[i][j];
-                       else
-                               break;
-
+                       conf = &bs335_gpio_config[i][j];
                        u300_gpio_init_pin(gpio, offset, conf);
                }
        }
@@ -796,50 +691,27 @@ static int __init u300_gpio_probe(struct platform_device *pdev)
                goto err_no_ioremap;
        }
 
-       if (plat->variant == U300_GPIO_COH901335) {
-               dev_info(gpio->dev,
-                        "initializing GPIO Controller COH 901 335\n");
-               gpio->stride = U300_335_PORT_STRIDE;
-               gpio->pcr = U300_335_PXPCR;
-               gpio->dor = U300_335_PXPDOR;
-               gpio->dir = U300_335_PXPDIR;
-               gpio->per = U300_335_PXPER;
-               gpio->icr = U300_335_PXICR;
-               gpio->ien = U300_335_PXIEN;
-               gpio->iev = U300_335_PXIEV;
-               ifr = U300_335_PXIFR;
-
-               /* Turn on the GPIO block */
-               writel(U300_335_CR_BLOCK_CLOCK_ENABLE,
-                      gpio->base + U300_335_CR);
-       } else if (plat->variant == U300_GPIO_COH901571_3_BS335 ||
-                  plat->variant == U300_GPIO_COH901571_3_BS365) {
-               dev_info(gpio->dev,
-                        "initializing GPIO Controller COH 901 571/3\n");
-               gpio->stride = U300_571_PORT_STRIDE;
-               gpio->pcr = U300_571_PXPCR;
-               gpio->dor = U300_571_PXPDOR;
-               gpio->dir = U300_571_PXPDIR;
-               gpio->per = U300_571_PXPER;
-               gpio->icr = U300_571_PXICR;
-               gpio->ien = U300_571_PXIEN;
-               gpio->iev = U300_571_PXIEV;
-               ifr = U300_571_PXIFR;
-
-               val = readl(gpio->base + U300_571_CR);
-               dev_info(gpio->dev, "COH901571/3 block version: %d, " \
-                        "number of cores: %d totalling %d pins\n",
-                        ((val & 0x000001FC) >> 2),
-                        ((val & 0x0000FE00) >> 9),
-                        ((val & 0x0000FE00) >> 9) * 8);
-               writel(U300_571_CR_BLOCK_CLKRQ_ENABLE,
-                      gpio->base + U300_571_CR);
-               u300_gpio_init_coh901571(gpio, plat);
-       } else {
-               dev_err(gpio->dev, "unknown block variant\n");
-               err = -ENODEV;
-               goto err_unknown_variant;
-       }
+       dev_info(gpio->dev,
+                "initializing GPIO Controller COH 901 571/3\n");
+       gpio->stride = U300_GPIO_PORT_STRIDE;
+       gpio->pcr = U300_GPIO_PXPCR;
+       gpio->dor = U300_GPIO_PXPDOR;
+       gpio->dir = U300_GPIO_PXPDIR;
+       gpio->per = U300_GPIO_PXPER;
+       gpio->icr = U300_GPIO_PXICR;
+       gpio->ien = U300_GPIO_PXIEN;
+       gpio->iev = U300_GPIO_PXIEV;
+       ifr = U300_GPIO_PXIFR;
+
+       val = readl(gpio->base + U300_GPIO_CR);
+       dev_info(gpio->dev, "COH901571/3 block version: %d, " \
+                "number of cores: %d totalling %d pins\n",
+                ((val & 0x000001FC) >> 2),
+                ((val & 0x0000FE00) >> 9),
+                ((val & 0x0000FE00) >> 9) * 8);
+       writel(U300_GPIO_CR_BLOCK_CLKRQ_ENABLE,
+              gpio->base + U300_GPIO_CR);
+       u300_gpio_init_coh901571(gpio, plat);
 
        /* Add each port with its IRQ separately */
        INIT_LIST_HEAD(&gpio->port_list);
@@ -906,7 +778,6 @@ err_no_pinctrl:
 err_no_chip:
 err_no_port:
        u300_gpio_free_ports(gpio);
-err_unknown_variant:
        iounmap(gpio->base);
 err_no_ioremap:
        release_mem_region(gpio->memres->start, resource_size(gpio->memres));
@@ -923,16 +794,11 @@ err_no_clk:
 
 static int __exit u300_gpio_remove(struct platform_device *pdev)
 {
-       struct u300_gpio_platform *plat = dev_get_platdata(&pdev->dev);
        struct u300_gpio *gpio = platform_get_drvdata(pdev);
        int err;
 
        /* Turn off the GPIO block */
-       if (plat->variant == U300_GPIO_COH901335)
-               writel(0x00000000U, gpio->base + U300_335_CR);
-       if (plat->variant == U300_GPIO_COH901571_3_BS335 ||
-           plat->variant == U300_GPIO_COH901571_3_BS365)
-               writel(0x00000000U, gpio->base + U300_571_CR);
+       writel(0x00000000U, gpio->base + U300_GPIO_CR);
 
        err = gpiochip_remove(&gpio->chip);
        if (err < 0) {
index 75d3eff94296823e4959e63b6ec8c0531a129440..3674d877ed7c1db935b8e3831d60ea7b3e505c7f 100644 (file)
@@ -292,7 +292,7 @@ static int __init imx23_pinctrl_init(void)
 {
        return platform_driver_register(&imx23_pinctrl_driver);
 }
-arch_initcall(imx23_pinctrl_init);
+postcore_initcall(imx23_pinctrl_init);
 
 static void __exit imx23_pinctrl_exit(void)
 {
index b973026811a269978244a02177238d2f780726cf..0f5b2122b1bae358c8da2c1de90879a57a2a3911 100644 (file)
@@ -408,7 +408,7 @@ static int __init imx28_pinctrl_init(void)
 {
        return platform_driver_register(&imx28_pinctrl_driver);
 }
-arch_initcall(imx28_pinctrl_init);
+postcore_initcall(imx28_pinctrl_init);
 
 static void __exit imx28_pinctrl_exit(void)
 {
diff --git a/drivers/pinctrl/pinctrl-imx35.c b/drivers/pinctrl/pinctrl-imx35.c
new file mode 100644 (file)
index 0000000..82f109e
--- /dev/null
@@ -0,0 +1,1595 @@
+/*
+ * imx35 pinctrl driver.
+ *
+ * This driver was mostly copied from the imx51 pinctrl driver which has:
+ *
+ * Copyright (C) 2012 Freescale Semiconductor, Inc.
+ * Copyright (C) 2012 Linaro, Inc.
+ *
+ * Author: Dong Aisheng <dong.aisheng@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-imx.h"
+
+enum imx35_pads {
+       MX35_PAD_CAPTURE = 0,
+       MX35_PAD_COMPARE = 1,
+       MX35_PAD_WDOG_RST = 2,
+       MX35_PAD_GPIO1_0 = 3,
+       MX35_PAD_GPIO1_1 = 4,
+       MX35_PAD_GPIO2_0 = 5,
+       MX35_PAD_GPIO3_0 = 6,
+       MX35_PAD_RESET_IN_B = 7,
+       MX35_PAD_POR_B = 8,
+       MX35_PAD_CLKO = 9,
+       MX35_PAD_BOOT_MODE0 = 10,
+       MX35_PAD_BOOT_MODE1 = 11,
+       MX35_PAD_CLK_MODE0 = 12,
+       MX35_PAD_CLK_MODE1 = 13,
+       MX35_PAD_POWER_FAIL = 14,
+       MX35_PAD_VSTBY = 15,
+       MX35_PAD_A0 = 16,
+       MX35_PAD_A1 = 17,
+       MX35_PAD_A2 = 18,
+       MX35_PAD_A3 = 19,
+       MX35_PAD_A4 = 20,
+       MX35_PAD_A5 = 21,
+       MX35_PAD_A6 = 22,
+       MX35_PAD_A7 = 23,
+       MX35_PAD_A8 = 24,
+       MX35_PAD_A9 = 25,
+       MX35_PAD_A10 = 26,
+       MX35_PAD_MA10 = 27,
+       MX35_PAD_A11 = 28,
+       MX35_PAD_A12 = 29,
+       MX35_PAD_A13 = 30,
+       MX35_PAD_A14 = 31,
+       MX35_PAD_A15 = 32,
+       MX35_PAD_A16 = 33,
+       MX35_PAD_A17 = 34,
+       MX35_PAD_A18 = 35,
+       MX35_PAD_A19 = 36,
+       MX35_PAD_A20 = 37,
+       MX35_PAD_A21 = 38,
+       MX35_PAD_A22 = 39,
+       MX35_PAD_A23 = 40,
+       MX35_PAD_A24 = 41,
+       MX35_PAD_A25 = 42,
+       MX35_PAD_SDBA1 = 43,
+       MX35_PAD_SDBA0 = 44,
+       MX35_PAD_SD0 = 45,
+       MX35_PAD_SD1 = 46,
+       MX35_PAD_SD2 = 47,
+       MX35_PAD_SD3 = 48,
+       MX35_PAD_SD4 = 49,
+       MX35_PAD_SD5 = 50,
+       MX35_PAD_SD6 = 51,
+       MX35_PAD_SD7 = 52,
+       MX35_PAD_SD8 = 53,
+       MX35_PAD_SD9 = 54,
+       MX35_PAD_SD10 = 55,
+       MX35_PAD_SD11 = 56,
+       MX35_PAD_SD12 = 57,
+       MX35_PAD_SD13 = 58,
+       MX35_PAD_SD14 = 59,
+       MX35_PAD_SD15 = 60,
+       MX35_PAD_SD16 = 61,
+       MX35_PAD_SD17 = 62,
+       MX35_PAD_SD18 = 63,
+       MX35_PAD_SD19 = 64,
+       MX35_PAD_SD20 = 65,
+       MX35_PAD_SD21 = 66,
+       MX35_PAD_SD22 = 67,
+       MX35_PAD_SD23 = 68,
+       MX35_PAD_SD24 = 69,
+       MX35_PAD_SD25 = 70,
+       MX35_PAD_SD26 = 71,
+       MX35_PAD_SD27 = 72,
+       MX35_PAD_SD28 = 73,
+       MX35_PAD_SD29 = 74,
+       MX35_PAD_SD30 = 75,
+       MX35_PAD_SD31 = 76,
+       MX35_PAD_DQM0 = 77,
+       MX35_PAD_DQM1 = 78,
+       MX35_PAD_DQM2 = 79,
+       MX35_PAD_DQM3 = 80,
+       MX35_PAD_EB0 = 81,
+       MX35_PAD_EB1 = 82,
+       MX35_PAD_OE = 83,
+       MX35_PAD_CS0 = 84,
+       MX35_PAD_CS1 = 85,
+       MX35_PAD_CS2 = 86,
+       MX35_PAD_CS3 = 87,
+       MX35_PAD_CS4 = 88,
+       MX35_PAD_CS5 = 89,
+       MX35_PAD_NF_CE0 = 90,
+       MX35_PAD_ECB = 91,
+       MX35_PAD_LBA = 92,
+       MX35_PAD_BCLK = 93,
+       MX35_PAD_RW = 94,
+       MX35_PAD_RAS = 95,
+       MX35_PAD_CAS = 96,
+       MX35_PAD_SDWE = 97,
+       MX35_PAD_SDCKE0 = 98,
+       MX35_PAD_SDCKE1 = 99,
+       MX35_PAD_SDCLK = 100,
+       MX35_PAD_SDQS0 = 101,
+       MX35_PAD_SDQS1 = 102,
+       MX35_PAD_SDQS2 = 103,
+       MX35_PAD_SDQS3 = 104,
+       MX35_PAD_NFWE_B = 105,
+       MX35_PAD_NFRE_B = 106,
+       MX35_PAD_NFALE = 107,
+       MX35_PAD_NFCLE = 108,
+       MX35_PAD_NFWP_B = 109,
+       MX35_PAD_NFRB = 110,
+       MX35_PAD_D15 = 111,
+       MX35_PAD_D14 = 112,
+       MX35_PAD_D13 = 113,
+       MX35_PAD_D12 = 114,
+       MX35_PAD_D11 = 115,
+       MX35_PAD_D10 = 116,
+       MX35_PAD_D9 = 117,
+       MX35_PAD_D8 = 118,
+       MX35_PAD_D7 = 119,
+       MX35_PAD_D6 = 120,
+       MX35_PAD_D5 = 121,
+       MX35_PAD_D4 = 122,
+       MX35_PAD_D3 = 123,
+       MX35_PAD_D2 = 124,
+       MX35_PAD_D1 = 125,
+       MX35_PAD_D0 = 126,
+       MX35_PAD_CSI_D8 = 127,
+       MX35_PAD_CSI_D9 = 128,
+       MX35_PAD_CSI_D10 = 129,
+       MX35_PAD_CSI_D11 = 130,
+       MX35_PAD_CSI_D12 = 131,
+       MX35_PAD_CSI_D13 = 132,
+       MX35_PAD_CSI_D14 = 133,
+       MX35_PAD_CSI_D15 = 134,
+       MX35_PAD_CSI_MCLK = 135,
+       MX35_PAD_CSI_VSYNC = 136,
+       MX35_PAD_CSI_HSYNC = 137,
+       MX35_PAD_CSI_PIXCLK = 138,
+       MX35_PAD_I2C1_CLK = 139,
+       MX35_PAD_I2C1_DAT = 140,
+       MX35_PAD_I2C2_CLK = 141,
+       MX35_PAD_I2C2_DAT = 142,
+       MX35_PAD_STXD4 = 143,
+       MX35_PAD_SRXD4 = 144,
+       MX35_PAD_SCK4 = 145,
+       MX35_PAD_STXFS4 = 146,
+       MX35_PAD_STXD5 = 147,
+       MX35_PAD_SRXD5 = 148,
+       MX35_PAD_SCK5 = 149,
+       MX35_PAD_STXFS5 = 150,
+       MX35_PAD_SCKR = 151,
+       MX35_PAD_FSR = 152,
+       MX35_PAD_HCKR = 153,
+       MX35_PAD_SCKT = 154,
+       MX35_PAD_FST = 155,
+       MX35_PAD_HCKT = 156,
+       MX35_PAD_TX5_RX0 = 157,
+       MX35_PAD_TX4_RX1 = 158,
+       MX35_PAD_TX3_RX2 = 159,
+       MX35_PAD_TX2_RX3 = 160,
+       MX35_PAD_TX1 = 161,
+       MX35_PAD_TX0 = 162,
+       MX35_PAD_CSPI1_MOSI = 163,
+       MX35_PAD_CSPI1_MISO = 164,
+       MX35_PAD_CSPI1_SS0 = 165,
+       MX35_PAD_CSPI1_SS1 = 166,
+       MX35_PAD_CSPI1_SCLK = 167,
+       MX35_PAD_CSPI1_SPI_RDY = 168,
+       MX35_PAD_RXD1 = 169,
+       MX35_PAD_TXD1 = 170,
+       MX35_PAD_RTS1 = 171,
+       MX35_PAD_CTS1 = 172,
+       MX35_PAD_RXD2 = 173,
+       MX35_PAD_TXD2 = 174,
+       MX35_PAD_RTS2 = 175,
+       MX35_PAD_CTS2 = 176,
+       MX35_PAD_RTCK = 177,
+       MX35_PAD_TCK = 178,
+       MX35_PAD_TMS = 179,
+       MX35_PAD_TDI = 180,
+       MX35_PAD_TDO = 181,
+       MX35_PAD_TRSTB = 182,
+       MX35_PAD_DE_B = 183,
+       MX35_PAD_SJC_MOD = 184,
+       MX35_PAD_USBOTG_PWR = 185,
+       MX35_PAD_USBOTG_OC = 186,
+       MX35_PAD_LD0 = 187,
+       MX35_PAD_LD1 = 188,
+       MX35_PAD_LD2 = 189,
+       MX35_PAD_LD3 = 190,
+       MX35_PAD_LD4 = 191,
+       MX35_PAD_LD5 = 192,
+       MX35_PAD_LD6 = 193,
+       MX35_PAD_LD7 = 194,
+       MX35_PAD_LD8 = 195,
+       MX35_PAD_LD9 = 196,
+       MX35_PAD_LD10 = 197,
+       MX35_PAD_LD11 = 198,
+       MX35_PAD_LD12 = 199,
+       MX35_PAD_LD13 = 200,
+       MX35_PAD_LD14 = 201,
+       MX35_PAD_LD15 = 202,
+       MX35_PAD_LD16 = 203,
+       MX35_PAD_LD17 = 204,
+       MX35_PAD_LD18 = 205,
+       MX35_PAD_LD19 = 206,
+       MX35_PAD_LD20 = 207,
+       MX35_PAD_LD21 = 208,
+       MX35_PAD_LD22 = 209,
+       MX35_PAD_LD23 = 210,
+       MX35_PAD_D3_HSYNC = 211,
+       MX35_PAD_D3_FPSHIFT = 212,
+       MX35_PAD_D3_DRDY = 213,
+       MX35_PAD_CONTRAST = 214,
+       MX35_PAD_D3_VSYNC = 215,
+       MX35_PAD_D3_REV = 216,
+       MX35_PAD_D3_CLS = 217,
+       MX35_PAD_D3_SPL = 218,
+       MX35_PAD_SD1_CMD = 219,
+       MX35_PAD_SD1_CLK = 220,
+       MX35_PAD_SD1_DATA0 = 221,
+       MX35_PAD_SD1_DATA1 = 222,
+       MX35_PAD_SD1_DATA2 = 223,
+       MX35_PAD_SD1_DATA3 = 224,
+       MX35_PAD_SD2_CMD = 225,
+       MX35_PAD_SD2_CLK = 226,
+       MX35_PAD_SD2_DATA0 = 227,
+       MX35_PAD_SD2_DATA1 = 228,
+       MX35_PAD_SD2_DATA2 = 229,
+       MX35_PAD_SD2_DATA3 = 230,
+       MX35_PAD_ATA_CS0 = 231,
+       MX35_PAD_ATA_CS1 = 232,
+       MX35_PAD_ATA_DIOR = 233,
+       MX35_PAD_ATA_DIOW = 234,
+       MX35_PAD_ATA_DMACK = 235,
+       MX35_PAD_ATA_RESET_B = 236,
+       MX35_PAD_ATA_IORDY = 237,
+       MX35_PAD_ATA_DATA0 = 238,
+       MX35_PAD_ATA_DATA1 = 239,
+       MX35_PAD_ATA_DATA2 = 240,
+       MX35_PAD_ATA_DATA3 = 241,
+       MX35_PAD_ATA_DATA4 = 242,
+       MX35_PAD_ATA_DATA5 = 243,
+       MX35_PAD_ATA_DATA6 = 244,
+       MX35_PAD_ATA_DATA7 = 245,
+       MX35_PAD_ATA_DATA8 = 246,
+       MX35_PAD_ATA_DATA9 = 247,
+       MX35_PAD_ATA_DATA10 = 248,
+       MX35_PAD_ATA_DATA11 = 249,
+       MX35_PAD_ATA_DATA12 = 250,
+       MX35_PAD_ATA_DATA13 = 251,
+       MX35_PAD_ATA_DATA14 = 252,
+       MX35_PAD_ATA_DATA15 = 253,
+       MX35_PAD_ATA_INTRQ = 254,
+       MX35_PAD_ATA_BUFF_EN = 255,
+       MX35_PAD_ATA_DMARQ = 256,
+       MX35_PAD_ATA_DA0 = 257,
+       MX35_PAD_ATA_DA1 = 258,
+       MX35_PAD_ATA_DA2 = 259,
+       MX35_PAD_MLB_CLK = 260,
+       MX35_PAD_MLB_DAT = 261,
+       MX35_PAD_MLB_SIG = 262,
+       MX35_PAD_FEC_TX_CLK = 263,
+       MX35_PAD_FEC_RX_CLK = 264,
+       MX35_PAD_FEC_RX_DV = 265,
+       MX35_PAD_FEC_COL = 266,
+       MX35_PAD_FEC_RDATA0 = 267,
+       MX35_PAD_FEC_TDATA0 = 268,
+       MX35_PAD_FEC_TX_EN = 269,
+       MX35_PAD_FEC_MDC = 270,
+       MX35_PAD_FEC_MDIO = 271,
+       MX35_PAD_FEC_TX_ERR = 272,
+       MX35_PAD_FEC_RX_ERR = 273,
+       MX35_PAD_FEC_CRS = 274,
+       MX35_PAD_FEC_RDATA1 = 275,
+       MX35_PAD_FEC_TDATA1 = 276,
+       MX35_PAD_FEC_RDATA2 = 277,
+       MX35_PAD_FEC_TDATA2 = 278,
+       MX35_PAD_FEC_RDATA3 = 279,
+       MX35_PAD_FEC_TDATA3 = 280,
+       MX35_PAD_EXT_ARMCLK = 281,
+       MX35_PAD_TEST_MODE = 282,
+};
+
+/* imx35 register maps */
+static struct imx_pin_reg imx35_pin_regs[] = {
+       [0] = IMX_PIN_REG(MX35_PAD_CAPTURE, 0x328, 0x004, 0, 0x0, 0), /* MX35_PAD_CAPTURE__GPT_CAPIN1 */
+       [1] = IMX_PIN_REG(MX35_PAD_CAPTURE, 0x328, 0x004, 1, 0x0, 0), /* MX35_PAD_CAPTURE__GPT_CMPOUT2 */
+       [2] = IMX_PIN_REG(MX35_PAD_CAPTURE, 0x328, 0x004, 2, 0x7f4, 0), /* MX35_PAD_CAPTURE__CSPI2_SS1 */
+       [3] = IMX_PIN_REG(MX35_PAD_CAPTURE, 0x328, 0x004, 3, 0x0, 0), /* MX35_PAD_CAPTURE__EPIT1_EPITO */
+       [4] = IMX_PIN_REG(MX35_PAD_CAPTURE, 0x328, 0x004, 4, 0x7d0, 0), /* MX35_PAD_CAPTURE__CCM_CLK32K */
+       [5] = IMX_PIN_REG(MX35_PAD_CAPTURE, 0x328, 0x004, 5, 0x850, 0), /* MX35_PAD_CAPTURE__GPIO1_4 */
+       [6] = IMX_PIN_REG(MX35_PAD_COMPARE, 0x32c, 0x008, 0, 0x0, 0), /* MX35_PAD_COMPARE__GPT_CMPOUT1 */
+       [7] = IMX_PIN_REG(MX35_PAD_COMPARE, 0x32c, 0x008, 1, 0x0, 0), /* MX35_PAD_COMPARE__GPT_CAPIN2 */
+       [8] = IMX_PIN_REG(MX35_PAD_COMPARE, 0x32c, 0x008, 2, 0x0, 0), /* MX35_PAD_COMPARE__GPT_CMPOUT3 */
+       [9] = IMX_PIN_REG(MX35_PAD_COMPARE, 0x32c, 0x008, 3, 0x0, 0), /* MX35_PAD_COMPARE__EPIT2_EPITO */
+       [10] = IMX_PIN_REG(MX35_PAD_COMPARE, 0x32c, 0x008, 5, 0x854, 0), /* MX35_PAD_COMPARE__GPIO1_5 */
+       [11] = IMX_PIN_REG(MX35_PAD_COMPARE, 0x32c, 0x008, 7, 0x0, 0), /* MX35_PAD_COMPARE__SDMA_EXTDMA_2 */
+       [12] = IMX_PIN_REG(MX35_PAD_WDOG_RST, 0x330, 0x00c, 0, 0x0, 0), /* MX35_PAD_WDOG_RST__WDOG_WDOG_B */
+       [13] = IMX_PIN_REG(MX35_PAD_WDOG_RST, 0x330, 0x00c, 3, 0x0, 0), /* MX35_PAD_WDOG_RST__IPU_FLASH_STROBE */
+       [14] = IMX_PIN_REG(MX35_PAD_WDOG_RST, 0x330, 0x00c, 5, 0x858, 0), /* MX35_PAD_WDOG_RST__GPIO1_6 */
+       [15] = IMX_PIN_REG(MX35_PAD_GPIO1_0, 0x334, 0x010, 0, 0x82c, 0), /* MX35_PAD_GPIO1_0__GPIO1_0 */
+       [16] = IMX_PIN_REG(MX35_PAD_GPIO1_0, 0x334, 0x010, 1, 0x7d4, 0), /* MX35_PAD_GPIO1_0__CCM_PMIC_RDY */
+       [17] = IMX_PIN_REG(MX35_PAD_GPIO1_0, 0x334, 0x010, 2, 0x990, 0), /* MX35_PAD_GPIO1_0__OWIRE_LINE */
+       [18] = IMX_PIN_REG(MX35_PAD_GPIO1_0, 0x334, 0x010, 7, 0x0, 0), /* MX35_PAD_GPIO1_0__SDMA_EXTDMA_0 */
+       [19] = IMX_PIN_REG(MX35_PAD_GPIO1_1, 0x338, 0x014, 0, 0x838, 0), /* MX35_PAD_GPIO1_1__GPIO1_1 */
+       [20] = IMX_PIN_REG(MX35_PAD_GPIO1_1, 0x338, 0x014, 2, 0x0, 0), /* MX35_PAD_GPIO1_1__PWM_PWMO */
+       [21] = IMX_PIN_REG(MX35_PAD_GPIO1_1, 0x338, 0x014, 3, 0x7d8, 0), /* MX35_PAD_GPIO1_1__CSPI1_SS2 */
+       [22] = IMX_PIN_REG(MX35_PAD_GPIO1_1, 0x338, 0x014, 6, 0x0, 0), /* MX35_PAD_GPIO1_1__SCC_TAMPER_DETECT */
+       [23] = IMX_PIN_REG(MX35_PAD_GPIO1_1, 0x338, 0x014, 7, 0x0, 0), /* MX35_PAD_GPIO1_1__SDMA_EXTDMA_1 */
+       [24] = IMX_PIN_REG(MX35_PAD_GPIO2_0, 0x33c, 0x018, 0, 0x868, 0), /* MX35_PAD_GPIO2_0__GPIO2_0 */
+       [25] = IMX_PIN_REG(MX35_PAD_GPIO2_0, 0x33c, 0x018, 1, 0x0, 0), /* MX35_PAD_GPIO2_0__USB_TOP_USBOTG_CLK */
+       [26] = IMX_PIN_REG(MX35_PAD_GPIO3_0, 0x340, 0x01c, 0, 0x8e8, 0), /* MX35_PAD_GPIO3_0__GPIO3_0 */
+       [27] = IMX_PIN_REG(MX35_PAD_GPIO3_0, 0x340, 0x01c, 1, 0x0, 0), /* MX35_PAD_GPIO3_0__USB_TOP_USBH2_CLK */
+       [28] = IMX_PIN_REG(MX35_PAD_RESET_IN_B, 0x344, 0x0, 0, 0x0, 0), /* MX35_PAD_RESET_IN_B__CCM_RESET_IN_B */
+       [29] = IMX_PIN_REG(MX35_PAD_POR_B, 0x348, 0x0, 0, 0x0, 0), /* MX35_PAD_POR_B__CCM_POR_B */
+       [30] = IMX_PIN_REG(MX35_PAD_CLKO, 0x34c, 0x020, 0, 0x0, 0), /* MX35_PAD_CLKO__CCM_CLKO */
+       [31] = IMX_PIN_REG(MX35_PAD_CLKO, 0x34c, 0x020, 5, 0x860, 0), /* MX35_PAD_CLKO__GPIO1_8 */
+       [32] = IMX_PIN_REG(MX35_PAD_BOOT_MODE0, 0x350, 0x0, 0, 0x0, 0), /* MX35_PAD_BOOT_MODE0__CCM_BOOT_MODE_0 */
+       [33] = IMX_PIN_REG(MX35_PAD_BOOT_MODE1, 0x354, 0x0, 0, 0x0, 0), /* MX35_PAD_BOOT_MODE1__CCM_BOOT_MODE_1 */
+       [34] = IMX_PIN_REG(MX35_PAD_CLK_MODE0, 0x358, 0x0, 0, 0x0, 0), /* MX35_PAD_CLK_MODE0__CCM_CLK_MODE_0 */
+       [35] = IMX_PIN_REG(MX35_PAD_CLK_MODE1, 0x35c, 0x0, 0, 0x0, 0), /* MX35_PAD_CLK_MODE1__CCM_CLK_MODE_1 */
+       [36] = IMX_PIN_REG(MX35_PAD_POWER_FAIL, 0x360, 0x0, 0, 0x0, 0), /* MX35_PAD_POWER_FAIL__CCM_DSM_WAKEUP_INT_26 */
+       [37] = IMX_PIN_REG(MX35_PAD_VSTBY, 0x364, 0x024, 0, 0x0, 0), /* MX35_PAD_VSTBY__CCM_VSTBY */
+       [38] = IMX_PIN_REG(MX35_PAD_VSTBY, 0x364, 0x024, 5, 0x85c, 0), /* MX35_PAD_VSTBY__GPIO1_7 */
+       [39] = IMX_PIN_REG(MX35_PAD_A0, 0x368, 0x028, 0, 0x0, 0), /* MX35_PAD_A0__EMI_EIM_DA_L_0 */
+       [40] = IMX_PIN_REG(MX35_PAD_A1, 0x36c, 0x02c, 0, 0x0, 0), /* MX35_PAD_A1__EMI_EIM_DA_L_1 */
+       [41] = IMX_PIN_REG(MX35_PAD_A2, 0x370, 0x030, 0, 0x0, 0), /* MX35_PAD_A2__EMI_EIM_DA_L_2 */
+       [42] = IMX_PIN_REG(MX35_PAD_A3, 0x374, 0x034, 0, 0x0, 0), /* MX35_PAD_A3__EMI_EIM_DA_L_3 */
+       [43] = IMX_PIN_REG(MX35_PAD_A4, 0x378, 0x038, 0, 0x0, 0), /* MX35_PAD_A4__EMI_EIM_DA_L_4 */
+       [44] = IMX_PIN_REG(MX35_PAD_A5, 0x37c, 0x03c, 0, 0x0, 0), /* MX35_PAD_A5__EMI_EIM_DA_L_5 */
+       [45] = IMX_PIN_REG(MX35_PAD_A6, 0x380, 0x040, 0, 0x0, 0), /* MX35_PAD_A6__EMI_EIM_DA_L_6 */
+       [46] = IMX_PIN_REG(MX35_PAD_A7, 0x384, 0x044, 0, 0x0, 0), /* MX35_PAD_A7__EMI_EIM_DA_L_7 */
+       [47] = IMX_PIN_REG(MX35_PAD_A8, 0x388, 0x048, 0, 0x0, 0), /* MX35_PAD_A8__EMI_EIM_DA_H_8 */
+       [48] = IMX_PIN_REG(MX35_PAD_A9, 0x38c, 0x04c, 0, 0x0, 0), /* MX35_PAD_A9__EMI_EIM_DA_H_9 */
+       [49] = IMX_PIN_REG(MX35_PAD_A10, 0x390, 0x050, 0, 0x0, 0), /* MX35_PAD_A10__EMI_EIM_DA_H_10 */
+       [50] = IMX_PIN_REG(MX35_PAD_MA10, 0x394, 0x054, 0, 0x0, 0), /* MX35_PAD_MA10__EMI_MA10 */
+       [51] = IMX_PIN_REG(MX35_PAD_A11, 0x398, 0x058, 0, 0x0, 0), /* MX35_PAD_A11__EMI_EIM_DA_H_11 */
+       [52] = IMX_PIN_REG(MX35_PAD_A12, 0x39c, 0x05c, 0, 0x0, 0), /* MX35_PAD_A12__EMI_EIM_DA_H_12 */
+       [53] = IMX_PIN_REG(MX35_PAD_A13, 0x3a0, 0x060, 0, 0x0, 0), /* MX35_PAD_A13__EMI_EIM_DA_H_13 */
+       [54] = IMX_PIN_REG(MX35_PAD_A14, 0x3a4, 0x064, 0, 0x0, 0), /* MX35_PAD_A14__EMI_EIM_DA_H2_14 */
+       [55] = IMX_PIN_REG(MX35_PAD_A15, 0x3a8, 0x068, 0, 0x0, 0), /* MX35_PAD_A15__EMI_EIM_DA_H2_15 */
+       [56] = IMX_PIN_REG(MX35_PAD_A16, 0x3ac, 0x06c, 0, 0x0, 0), /* MX35_PAD_A16__EMI_EIM_A_16 */
+       [57] = IMX_PIN_REG(MX35_PAD_A17, 0x3b0, 0x070, 0, 0x0, 0), /* MX35_PAD_A17__EMI_EIM_A_17 */
+       [58] = IMX_PIN_REG(MX35_PAD_A18, 0x3b4, 0x074, 0, 0x0, 0), /* MX35_PAD_A18__EMI_EIM_A_18 */
+       [59] = IMX_PIN_REG(MX35_PAD_A19, 0x3b8, 0x078, 0, 0x0, 0), /* MX35_PAD_A19__EMI_EIM_A_19 */
+       [60] = IMX_PIN_REG(MX35_PAD_A20, 0x3bc, 0x07c, 0, 0x0, 0), /* MX35_PAD_A20__EMI_EIM_A_20 */
+       [61] = IMX_PIN_REG(MX35_PAD_A21, 0x3c0, 0x080, 0, 0x0, 0), /* MX35_PAD_A21__EMI_EIM_A_21 */
+       [62] = IMX_PIN_REG(MX35_PAD_A22, 0x3c4, 0x084, 0, 0x0, 0), /* MX35_PAD_A22__EMI_EIM_A_22 */
+       [63] = IMX_PIN_REG(MX35_PAD_A23, 0x3c8, 0x088, 0, 0x0, 0), /* MX35_PAD_A23__EMI_EIM_A_23 */
+       [64] = IMX_PIN_REG(MX35_PAD_A24, 0x3cc, 0x08c, 0, 0x0, 0), /* MX35_PAD_A24__EMI_EIM_A_24 */
+       [65] = IMX_PIN_REG(MX35_PAD_A25, 0x3d0, 0x090, 0, 0x0, 0), /* MX35_PAD_A25__EMI_EIM_A_25 */
+       [66] = IMX_PIN_REG(MX35_PAD_SDBA1, 0x3d4, 0x0, 0, 0x0, 0), /* MX35_PAD_SDBA1__EMI_EIM_SDBA1 */
+       [67] = IMX_PIN_REG(MX35_PAD_SDBA0, 0x3d8, 0x0, 0, 0x0, 0), /* MX35_PAD_SDBA0__EMI_EIM_SDBA0 */
+       [68] = IMX_PIN_REG(MX35_PAD_SD0, 0x3dc, 0x0, 0, 0x0, 0), /* MX35_PAD_SD0__EMI_DRAM_D_0 */
+       [69] = IMX_PIN_REG(MX35_PAD_SD1, 0x3e0, 0x0, 0, 0x0, 0), /* MX35_PAD_SD1__EMI_DRAM_D_1 */
+       [70] = IMX_PIN_REG(MX35_PAD_SD2, 0x3e4, 0x0, 0, 0x0, 0), /* MX35_PAD_SD2__EMI_DRAM_D_2 */
+       [71] = IMX_PIN_REG(MX35_PAD_SD3, 0x3e8, 0x0, 0, 0x0, 0), /* MX35_PAD_SD3__EMI_DRAM_D_3 */
+       [72] = IMX_PIN_REG(MX35_PAD_SD4, 0x3ec, 0x0, 0, 0x0, 0), /* MX35_PAD_SD4__EMI_DRAM_D_4 */
+       [73] = IMX_PIN_REG(MX35_PAD_SD5, 0x3f0, 0x0, 0, 0x0, 0), /* MX35_PAD_SD5__EMI_DRAM_D_5 */
+       [74] = IMX_PIN_REG(MX35_PAD_SD6, 0x3f4, 0x0, 0, 0x0, 0), /* MX35_PAD_SD6__EMI_DRAM_D_6 */
+       [75] = IMX_PIN_REG(MX35_PAD_SD7, 0x3f8, 0x0, 0, 0x0, 0), /* MX35_PAD_SD7__EMI_DRAM_D_7 */
+       [76] = IMX_PIN_REG(MX35_PAD_SD8, 0x3fc, 0x0, 0, 0x0, 0), /* MX35_PAD_SD8__EMI_DRAM_D_8 */
+       [77] = IMX_PIN_REG(MX35_PAD_SD9, 0x400, 0x0, 0, 0x0, 0), /* MX35_PAD_SD9__EMI_DRAM_D_9 */
+       [78] = IMX_PIN_REG(MX35_PAD_SD10, 0x404, 0x0, 0, 0x0, 0), /* MX35_PAD_SD10__EMI_DRAM_D_10 */
+       [79] = IMX_PIN_REG(MX35_PAD_SD11, 0x408, 0x0, 0, 0x0, 0), /* MX35_PAD_SD11__EMI_DRAM_D_11 */
+       [80] = IMX_PIN_REG(MX35_PAD_SD12, 0x40c, 0x0, 0, 0x0, 0), /* MX35_PAD_SD12__EMI_DRAM_D_12 */
+       [81] = IMX_PIN_REG(MX35_PAD_SD13, 0x410, 0x0, 0, 0x0, 0), /* MX35_PAD_SD13__EMI_DRAM_D_13 */
+       [82] = IMX_PIN_REG(MX35_PAD_SD14, 0x414, 0x0, 0, 0x0, 0), /* MX35_PAD_SD14__EMI_DRAM_D_14 */
+       [83] = IMX_PIN_REG(MX35_PAD_SD15, 0x418, 0x0, 0, 0x0, 0), /* MX35_PAD_SD15__EMI_DRAM_D_15 */
+       [84] = IMX_PIN_REG(MX35_PAD_SD16, 0x41c, 0x0, 0, 0x0, 0), /* MX35_PAD_SD16__EMI_DRAM_D_16 */
+       [85] = IMX_PIN_REG(MX35_PAD_SD17, 0x420, 0x0, 0, 0x0, 0), /* MX35_PAD_SD17__EMI_DRAM_D_17 */
+       [86] = IMX_PIN_REG(MX35_PAD_SD18, 0x424, 0x0, 0, 0x0, 0), /* MX35_PAD_SD18__EMI_DRAM_D_18 */
+       [87] = IMX_PIN_REG(MX35_PAD_SD19, 0x428, 0x0, 0, 0x0, 0), /* MX35_PAD_SD19__EMI_DRAM_D_19 */
+       [88] = IMX_PIN_REG(MX35_PAD_SD20, 0x42c, 0x0, 0, 0x0, 0), /* MX35_PAD_SD20__EMI_DRAM_D_20 */
+       [89] = IMX_PIN_REG(MX35_PAD_SD21, 0x430, 0x0, 0, 0x0, 0), /* MX35_PAD_SD21__EMI_DRAM_D_21 */
+       [90] = IMX_PIN_REG(MX35_PAD_SD22, 0x434, 0x0, 0, 0x0, 0), /* MX35_PAD_SD22__EMI_DRAM_D_22 */
+       [91] = IMX_PIN_REG(MX35_PAD_SD23, 0x438, 0x0, 0, 0x0, 0), /* MX35_PAD_SD23__EMI_DRAM_D_23 */
+       [92] = IMX_PIN_REG(MX35_PAD_SD24, 0x43c, 0x0, 0, 0x0, 0), /* MX35_PAD_SD24__EMI_DRAM_D_24 */
+       [93] = IMX_PIN_REG(MX35_PAD_SD25, 0x440, 0x0, 0, 0x0, 0), /* MX35_PAD_SD25__EMI_DRAM_D_25 */
+       [94] = IMX_PIN_REG(MX35_PAD_SD26, 0x444, 0x0, 0, 0x0, 0), /* MX35_PAD_SD26__EMI_DRAM_D_26 */
+       [95] = IMX_PIN_REG(MX35_PAD_SD27, 0x448, 0x0, 0, 0x0, 0), /* MX35_PAD_SD27__EMI_DRAM_D_27 */
+       [96] = IMX_PIN_REG(MX35_PAD_SD28, 0x44c, 0x0, 0, 0x0, 0), /* MX35_PAD_SD28__EMI_DRAM_D_28 */
+       [97] = IMX_PIN_REG(MX35_PAD_SD29, 0x450, 0x0, 0, 0x0, 0), /* MX35_PAD_SD29__EMI_DRAM_D_29 */
+       [98] = IMX_PIN_REG(MX35_PAD_SD30, 0x454, 0x0, 0, 0x0, 0), /* MX35_PAD_SD30__EMI_DRAM_D_30 */
+       [99] = IMX_PIN_REG(MX35_PAD_SD31, 0x458, 0x0, 0, 0x0, 0), /* MX35_PAD_SD31__EMI_DRAM_D_31 */
+       [100] = IMX_PIN_REG(MX35_PAD_DQM0, 0x45c, 0x0, 0, 0x0, 0), /* MX35_PAD_DQM0__EMI_DRAM_DQM_0 */
+       [101] = IMX_PIN_REG(MX35_PAD_DQM1, 0x460, 0x0, 0, 0x0, 0), /* MX35_PAD_DQM1__EMI_DRAM_DQM_1 */
+       [102] = IMX_PIN_REG(MX35_PAD_DQM2, 0x464, 0x0, 0, 0x0, 0), /* MX35_PAD_DQM2__EMI_DRAM_DQM_2 */
+       [103] = IMX_PIN_REG(MX35_PAD_DQM3, 0x468, 0x0, 0, 0x0, 0), /* MX35_PAD_DQM3__EMI_DRAM_DQM_3 */
+       [104] = IMX_PIN_REG(MX35_PAD_EB0, 0x46c, 0x094, 0, 0x0, 0), /* MX35_PAD_EB0__EMI_EIM_EB0_B */
+       [105] = IMX_PIN_REG(MX35_PAD_EB1, 0x470, 0x098, 0, 0x0, 0), /* MX35_PAD_EB1__EMI_EIM_EB1_B */
+       [106] = IMX_PIN_REG(MX35_PAD_OE, 0x474, 0x09c, 0, 0x0, 0), /* MX35_PAD_OE__EMI_EIM_OE */
+       [107] = IMX_PIN_REG(MX35_PAD_CS0, 0x478, 0x0a0, 0, 0x0, 0), /* MX35_PAD_CS0__EMI_EIM_CS0 */
+       [108] = IMX_PIN_REG(MX35_PAD_CS1, 0x47c, 0x0a4, 0, 0x0, 0), /* MX35_PAD_CS1__EMI_EIM_CS1 */
+       [109] = IMX_PIN_REG(MX35_PAD_CS1, 0x47c, 0x0a4, 3, 0x0, 0), /* MX35_PAD_CS1__EMI_NANDF_CE3 */
+       [110] = IMX_PIN_REG(MX35_PAD_CS2, 0x480, 0x0a8, 0, 0x0, 0), /* MX35_PAD_CS2__EMI_EIM_CS2 */
+       [111] = IMX_PIN_REG(MX35_PAD_CS3, 0x484, 0x0ac, 0, 0x0, 0), /* MX35_PAD_CS3__EMI_EIM_CS3 */
+       [112] = IMX_PIN_REG(MX35_PAD_CS4, 0x488, 0x0b0, 0, 0x0, 0), /* MX35_PAD_CS4__EMI_EIM_CS4 */
+       [113] = IMX_PIN_REG(MX35_PAD_CS4, 0x488, 0x0b0, 1, 0x800, 0), /* MX35_PAD_CS4__EMI_DTACK_B */
+       [114] = IMX_PIN_REG(MX35_PAD_CS4, 0x488, 0x0b0, 3, 0x0, 0), /* MX35_PAD_CS4__EMI_NANDF_CE1 */
+       [115] = IMX_PIN_REG(MX35_PAD_CS4, 0x488, 0x0b0, 5, 0x83c, 0), /* MX35_PAD_CS4__GPIO1_20 */
+       [116] = IMX_PIN_REG(MX35_PAD_CS5, 0x48c, 0x0b4, 0, 0x0, 0), /* MX35_PAD_CS5__EMI_EIM_CS5 */
+       [117] = IMX_PIN_REG(MX35_PAD_CS5, 0x48c, 0x0b4, 1, 0x7f8, 0), /* MX35_PAD_CS5__CSPI2_SS2 */
+       [118] = IMX_PIN_REG(MX35_PAD_CS5, 0x48c, 0x0b4, 2, 0x7d8, 1), /* MX35_PAD_CS5__CSPI1_SS2 */
+       [119] = IMX_PIN_REG(MX35_PAD_CS5, 0x48c, 0x0b4, 3, 0x0, 0), /* MX35_PAD_CS5__EMI_NANDF_CE2 */
+       [120] = IMX_PIN_REG(MX35_PAD_CS5, 0x48c, 0x0b4, 5, 0x840, 0), /* MX35_PAD_CS5__GPIO1_21 */
+       [121] = IMX_PIN_REG(MX35_PAD_NF_CE0, 0x490, 0x0b8, 0, 0x0, 0), /* MX35_PAD_NF_CE0__EMI_NANDF_CE0 */
+       [122] = IMX_PIN_REG(MX35_PAD_NF_CE0, 0x490, 0x0b8, 5, 0x844, 0), /* MX35_PAD_NF_CE0__GPIO1_22 */
+       [123] = IMX_PIN_REG(MX35_PAD_ECB, 0x494, 0x0, 0, 0x0, 0), /* MX35_PAD_ECB__EMI_EIM_ECB */
+       [124] = IMX_PIN_REG(MX35_PAD_LBA, 0x498, 0x0bc, 0, 0x0, 0), /* MX35_PAD_LBA__EMI_EIM_LBA */
+       [125] = IMX_PIN_REG(MX35_PAD_BCLK, 0x49c, 0x0c0, 0, 0x0, 0), /* MX35_PAD_BCLK__EMI_EIM_BCLK */
+       [126] = IMX_PIN_REG(MX35_PAD_RW, 0x4a0, 0x0c4, 0, 0x0, 0), /* MX35_PAD_RW__EMI_EIM_RW */
+       [127] = IMX_PIN_REG(MX35_PAD_RAS, 0x4a4, 0x0, 0, 0x0, 0), /* MX35_PAD_RAS__EMI_DRAM_RAS */
+       [128] = IMX_PIN_REG(MX35_PAD_CAS, 0x4a8, 0x0, 0, 0x0, 0), /* MX35_PAD_CAS__EMI_DRAM_CAS */
+       [129] = IMX_PIN_REG(MX35_PAD_SDWE, 0x4ac, 0x0, 0, 0x0, 0), /* MX35_PAD_SDWE__EMI_DRAM_SDWE */
+       [130] = IMX_PIN_REG(MX35_PAD_SDCKE0, 0x4b0, 0x0, 0, 0x0, 0), /* MX35_PAD_SDCKE0__EMI_DRAM_SDCKE_0 */
+       [131] = IMX_PIN_REG(MX35_PAD_SDCKE1, 0x4b4, 0x0, 0, 0x0, 0), /* MX35_PAD_SDCKE1__EMI_DRAM_SDCKE_1 */
+       [132] = IMX_PIN_REG(MX35_PAD_SDCLK, 0x4b8, 0x0, 0, 0x0, 0), /* MX35_PAD_SDCLK__EMI_DRAM_SDCLK */
+       [133] = IMX_PIN_REG(MX35_PAD_SDQS0, 0x4bc, 0x0, 0, 0x0, 0), /* MX35_PAD_SDQS0__EMI_DRAM_SDQS_0 */
+       [134] = IMX_PIN_REG(MX35_PAD_SDQS1, 0x4c0, 0x0, 0, 0x0, 0), /* MX35_PAD_SDQS1__EMI_DRAM_SDQS_1 */
+       [135] = IMX_PIN_REG(MX35_PAD_SDQS2, 0x4c4, 0x0, 0, 0x0, 0), /* MX35_PAD_SDQS2__EMI_DRAM_SDQS_2 */
+       [136] = IMX_PIN_REG(MX35_PAD_SDQS3, 0x4c8, 0x0, 0, 0x0, 0), /* MX35_PAD_SDQS3__EMI_DRAM_SDQS_3 */
+       [137] = IMX_PIN_REG(MX35_PAD_NFWE_B, 0x4cc, 0x0c8, 0, 0x0, 0), /* MX35_PAD_NFWE_B__EMI_NANDF_WE_B */
+       [138] = IMX_PIN_REG(MX35_PAD_NFWE_B, 0x4cc, 0x0c8, 1, 0x9d8, 0), /* MX35_PAD_NFWE_B__USB_TOP_USBH2_DATA_3 */
+       [139] = IMX_PIN_REG(MX35_PAD_NFWE_B, 0x4cc, 0x0c8, 2, 0x924, 0), /* MX35_PAD_NFWE_B__IPU_DISPB_D0_VSYNC */
+       [140] = IMX_PIN_REG(MX35_PAD_NFWE_B, 0x4cc, 0x0c8, 5, 0x88c, 0), /* MX35_PAD_NFWE_B__GPIO2_18 */
+       [141] = IMX_PIN_REG(MX35_PAD_NFWE_B, 0x4cc, 0x0c8, 7, 0x0, 0), /* MX35_PAD_NFWE_B__ARM11P_TOP_TRACE_0 */
+       [142] = IMX_PIN_REG(MX35_PAD_NFRE_B, 0x4d0, 0x0cc, 0, 0x0, 0), /* MX35_PAD_NFRE_B__EMI_NANDF_RE_B */
+       [143] = IMX_PIN_REG(MX35_PAD_NFRE_B, 0x4d0, 0x0cc, 1, 0x9ec, 0), /* MX35_PAD_NFRE_B__USB_TOP_USBH2_DIR */
+       [144] = IMX_PIN_REG(MX35_PAD_NFRE_B, 0x4d0, 0x0cc, 2, 0x0, 0), /* MX35_PAD_NFRE_B__IPU_DISPB_BCLK */
+       [145] = IMX_PIN_REG(MX35_PAD_NFRE_B, 0x4d0, 0x0cc, 5, 0x890, 0), /* MX35_PAD_NFRE_B__GPIO2_19 */
+       [146] = IMX_PIN_REG(MX35_PAD_NFRE_B, 0x4d0, 0x0cc, 7, 0x0, 0), /* MX35_PAD_NFRE_B__ARM11P_TOP_TRACE_1 */
+       [147] = IMX_PIN_REG(MX35_PAD_NFALE, 0x4d4, 0x0d0, 0, 0x0, 0), /* MX35_PAD_NFALE__EMI_NANDF_ALE */
+       [148] = IMX_PIN_REG(MX35_PAD_NFALE, 0x4d4, 0x0d0, 1, 0x0, 0), /* MX35_PAD_NFALE__USB_TOP_USBH2_STP */
+       [149] = IMX_PIN_REG(MX35_PAD_NFALE, 0x4d4, 0x0d0, 2, 0x0, 0), /* MX35_PAD_NFALE__IPU_DISPB_CS0 */
+       [150] = IMX_PIN_REG(MX35_PAD_NFALE, 0x4d4, 0x0d0, 5, 0x898, 0), /* MX35_PAD_NFALE__GPIO2_20 */
+       [151] = IMX_PIN_REG(MX35_PAD_NFALE, 0x4d4, 0x0d0, 7, 0x0, 0), /* MX35_PAD_NFALE__ARM11P_TOP_TRACE_2 */
+       [152] = IMX_PIN_REG(MX35_PAD_NFCLE, 0x4d8, 0x0d4, 0, 0x0, 0), /* MX35_PAD_NFCLE__EMI_NANDF_CLE */
+       [153] = IMX_PIN_REG(MX35_PAD_NFCLE, 0x4d8, 0x0d4, 1, 0x9f0, 0), /* MX35_PAD_NFCLE__USB_TOP_USBH2_NXT */
+       [154] = IMX_PIN_REG(MX35_PAD_NFCLE, 0x4d8, 0x0d4, 2, 0x0, 0), /* MX35_PAD_NFCLE__IPU_DISPB_PAR_RS */
+       [155] = IMX_PIN_REG(MX35_PAD_NFCLE, 0x4d8, 0x0d4, 5, 0x89c, 0), /* MX35_PAD_NFCLE__GPIO2_21 */
+       [156] = IMX_PIN_REG(MX35_PAD_NFCLE, 0x4d8, 0x0d4, 7, 0x0, 0), /* MX35_PAD_NFCLE__ARM11P_TOP_TRACE_3 */
+       [157] = IMX_PIN_REG(MX35_PAD_NFWP_B, 0x4dc, 0x0d8, 0, 0x0, 0), /* MX35_PAD_NFWP_B__EMI_NANDF_WP_B */
+       [158] = IMX_PIN_REG(MX35_PAD_NFWP_B, 0x4dc, 0x0d8, 1, 0x9e8, 0), /* MX35_PAD_NFWP_B__USB_TOP_USBH2_DATA_7 */
+       [159] = IMX_PIN_REG(MX35_PAD_NFWP_B, 0x4dc, 0x0d8, 2, 0x0, 0), /* MX35_PAD_NFWP_B__IPU_DISPB_WR */
+       [160] = IMX_PIN_REG(MX35_PAD_NFWP_B, 0x4dc, 0x0d8, 5, 0x8a0, 0), /* MX35_PAD_NFWP_B__GPIO2_22 */
+       [161] = IMX_PIN_REG(MX35_PAD_NFWP_B, 0x4dc, 0x0d8, 7, 0x0, 0), /* MX35_PAD_NFWP_B__ARM11P_TOP_TRCTL */
+       [162] = IMX_PIN_REG(MX35_PAD_NFRB, 0x4e0, 0x0dc, 0, 0x0, 0), /* MX35_PAD_NFRB__EMI_NANDF_RB */
+       [163] = IMX_PIN_REG(MX35_PAD_NFRB, 0x4e0, 0x0dc, 2, 0x0, 0), /* MX35_PAD_NFRB__IPU_DISPB_RD */
+       [164] = IMX_PIN_REG(MX35_PAD_NFRB, 0x4e0, 0x0dc, 5, 0x8a4, 0), /* MX35_PAD_NFRB__GPIO2_23 */
+       [165] = IMX_PIN_REG(MX35_PAD_NFRB, 0x4e0, 0x0dc, 7, 0x0, 0), /* MX35_PAD_NFRB__ARM11P_TOP_TRCLK */
+       [166] = IMX_PIN_REG(MX35_PAD_D15, 0x4e4, 0x0, 0, 0x0, 0), /* MX35_PAD_D15__EMI_EIM_D_15 */
+       [167] = IMX_PIN_REG(MX35_PAD_D14, 0x4e8, 0x0, 0, 0x0, 0), /* MX35_PAD_D14__EMI_EIM_D_14 */
+       [168] = IMX_PIN_REG(MX35_PAD_D13, 0x4ec, 0x0, 0, 0x0, 0), /* MX35_PAD_D13__EMI_EIM_D_13 */
+       [169] = IMX_PIN_REG(MX35_PAD_D12, 0x4f0, 0x0, 0, 0x0, 0), /* MX35_PAD_D12__EMI_EIM_D_12 */
+       [170] = IMX_PIN_REG(MX35_PAD_D11, 0x4f4, 0x0, 0, 0x0, 0), /* MX35_PAD_D11__EMI_EIM_D_11 */
+       [171] = IMX_PIN_REG(MX35_PAD_D10, 0x4f8, 0x0, 0, 0x0, 0), /* MX35_PAD_D10__EMI_EIM_D_10 */
+       [172] = IMX_PIN_REG(MX35_PAD_D9, 0x4fc, 0x0, 0, 0x0, 0), /* MX35_PAD_D9__EMI_EIM_D_9 */
+       [173] = IMX_PIN_REG(MX35_PAD_D8, 0x500, 0x0, 0, 0x0, 0), /* MX35_PAD_D8__EMI_EIM_D_8 */
+       [174] = IMX_PIN_REG(MX35_PAD_D7, 0x504, 0x0, 0, 0x0, 0), /* MX35_PAD_D7__EMI_EIM_D_7 */
+       [175] = IMX_PIN_REG(MX35_PAD_D6, 0x508, 0x0, 0, 0x0, 0), /* MX35_PAD_D6__EMI_EIM_D_6 */
+       [176] = IMX_PIN_REG(MX35_PAD_D5, 0x50c, 0x0, 0, 0x0, 0), /* MX35_PAD_D5__EMI_EIM_D_5 */
+       [177] = IMX_PIN_REG(MX35_PAD_D4, 0x510, 0x0, 0, 0x0, 0), /* MX35_PAD_D4__EMI_EIM_D_4 */
+       [178] = IMX_PIN_REG(MX35_PAD_D3, 0x514, 0x0, 0, 0x0, 0), /* MX35_PAD_D3__EMI_EIM_D_3 */
+       [179] = IMX_PIN_REG(MX35_PAD_D2, 0x518, 0x0, 0, 0x0, 0), /* MX35_PAD_D2__EMI_EIM_D_2 */
+       [180] = IMX_PIN_REG(MX35_PAD_D1, 0x51c, 0x0, 0, 0x0, 0), /* MX35_PAD_D1__EMI_EIM_D_1 */
+       [181] = IMX_PIN_REG(MX35_PAD_D0, 0x520, 0x0, 0, 0x0, 0), /* MX35_PAD_D0__EMI_EIM_D_0 */
+       [182] = IMX_PIN_REG(MX35_PAD_CSI_D8, 0x524, 0x0e0, 0, 0x0, 0), /* MX35_PAD_CSI_D8__IPU_CSI_D_8 */
+       [183] = IMX_PIN_REG(MX35_PAD_CSI_D8, 0x524, 0x0e0, 1, 0x950, 0), /* MX35_PAD_CSI_D8__KPP_COL_0 */
+       [184] = IMX_PIN_REG(MX35_PAD_CSI_D8, 0x524, 0x0e0, 5, 0x83c, 1), /* MX35_PAD_CSI_D8__GPIO1_20 */
+       [185] = IMX_PIN_REG(MX35_PAD_CSI_D8, 0x524, 0x0e0, 7, 0x0, 0), /* MX35_PAD_CSI_D8__ARM11P_TOP_EVNTBUS_13 */
+       [186] = IMX_PIN_REG(MX35_PAD_CSI_D9, 0x528, 0x0e4, 0, 0x0, 0), /* MX35_PAD_CSI_D9__IPU_CSI_D_9 */
+       [187] = IMX_PIN_REG(MX35_PAD_CSI_D9, 0x528, 0x0e4, 1, 0x954, 0), /* MX35_PAD_CSI_D9__KPP_COL_1 */
+       [188] = IMX_PIN_REG(MX35_PAD_CSI_D9, 0x528, 0x0e4, 5, 0x840, 1), /* MX35_PAD_CSI_D9__GPIO1_21 */
+       [189] = IMX_PIN_REG(MX35_PAD_CSI_D9, 0x528, 0x0e4, 7, 0x0, 0), /* MX35_PAD_CSI_D9__ARM11P_TOP_EVNTBUS_14 */
+       [190] = IMX_PIN_REG(MX35_PAD_CSI_D10, 0x52c, 0x0e8, 0, 0x0, 0), /* MX35_PAD_CSI_D10__IPU_CSI_D_10 */
+       [191] = IMX_PIN_REG(MX35_PAD_CSI_D10, 0x52c, 0x0e8, 1, 0x958, 0), /* MX35_PAD_CSI_D10__KPP_COL_2 */
+       [192] = IMX_PIN_REG(MX35_PAD_CSI_D10, 0x52c, 0x0e8, 5, 0x844, 1), /* MX35_PAD_CSI_D10__GPIO1_22 */
+       [193] = IMX_PIN_REG(MX35_PAD_CSI_D10, 0x52c, 0x0e8, 7, 0x0, 0), /* MX35_PAD_CSI_D10__ARM11P_TOP_EVNTBUS_15 */
+       [194] = IMX_PIN_REG(MX35_PAD_CSI_D11, 0x530, 0x0ec, 0, 0x0, 0), /* MX35_PAD_CSI_D11__IPU_CSI_D_11 */
+       [195] = IMX_PIN_REG(MX35_PAD_CSI_D11, 0x530, 0x0ec, 1, 0x95c, 0), /* MX35_PAD_CSI_D11__KPP_COL_3 */
+       [196] = IMX_PIN_REG(MX35_PAD_CSI_D11, 0x530, 0x0ec, 5, 0x0, 0), /* MX35_PAD_CSI_D11__GPIO1_23 */
+       [197] = IMX_PIN_REG(MX35_PAD_CSI_D12, 0x534, 0x0f0, 0, 0x0, 0), /* MX35_PAD_CSI_D12__IPU_CSI_D_12 */
+       [198] = IMX_PIN_REG(MX35_PAD_CSI_D12, 0x534, 0x0f0, 1, 0x970, 0), /* MX35_PAD_CSI_D12__KPP_ROW_0 */
+       [199] = IMX_PIN_REG(MX35_PAD_CSI_D12, 0x534, 0x0f0, 5, 0x0, 0), /* MX35_PAD_CSI_D12__GPIO1_24 */
+       [200] = IMX_PIN_REG(MX35_PAD_CSI_D13, 0x538, 0x0f4, 0, 0x0, 0), /* MX35_PAD_CSI_D13__IPU_CSI_D_13 */
+       [201] = IMX_PIN_REG(MX35_PAD_CSI_D13, 0x538, 0x0f4, 1, 0x974, 0), /* MX35_PAD_CSI_D13__KPP_ROW_1 */
+       [202] = IMX_PIN_REG(MX35_PAD_CSI_D13, 0x538, 0x0f4, 5, 0x0, 0), /* MX35_PAD_CSI_D13__GPIO1_25 */
+       [203] = IMX_PIN_REG(MX35_PAD_CSI_D14, 0x53c, 0x0f8, 0, 0x0, 0), /* MX35_PAD_CSI_D14__IPU_CSI_D_14 */
+       [204] = IMX_PIN_REG(MX35_PAD_CSI_D14, 0x53c, 0x0f8, 1, 0x978, 0), /* MX35_PAD_CSI_D14__KPP_ROW_2 */
+       [205] = IMX_PIN_REG(MX35_PAD_CSI_D14, 0x53c, 0x0f8, 5, 0x0, 0), /* MX35_PAD_CSI_D14__GPIO1_26 */
+       [206] = IMX_PIN_REG(MX35_PAD_CSI_D15, 0x540, 0x0fc, 0, 0x97c, 0), /* MX35_PAD_CSI_D15__IPU_CSI_D_15 */
+       [207] = IMX_PIN_REG(MX35_PAD_CSI_D15, 0x540, 0x0fc, 1, 0x0, 0), /* MX35_PAD_CSI_D15__KPP_ROW_3 */
+       [208] = IMX_PIN_REG(MX35_PAD_CSI_D15, 0x540, 0x0fc, 5, 0x0, 0), /* MX35_PAD_CSI_D15__GPIO1_27 */
+       [209] = IMX_PIN_REG(MX35_PAD_CSI_MCLK, 0x544, 0x100, 0, 0x0, 0), /* MX35_PAD_CSI_MCLK__IPU_CSI_MCLK */
+       [210] = IMX_PIN_REG(MX35_PAD_CSI_MCLK, 0x544, 0x100, 5, 0x0, 0), /* MX35_PAD_CSI_MCLK__GPIO1_28 */
+       [211] = IMX_PIN_REG(MX35_PAD_CSI_VSYNC, 0x548, 0x104, 0, 0x0, 0), /* MX35_PAD_CSI_VSYNC__IPU_CSI_VSYNC */
+       [212] = IMX_PIN_REG(MX35_PAD_CSI_VSYNC, 0x548, 0x104, 5, 0x0, 0), /* MX35_PAD_CSI_VSYNC__GPIO1_29 */
+       [213] = IMX_PIN_REG(MX35_PAD_CSI_HSYNC, 0x54c, 0x108, 0, 0x0, 0), /* MX35_PAD_CSI_HSYNC__IPU_CSI_HSYNC */
+       [214] = IMX_PIN_REG(MX35_PAD_CSI_HSYNC, 0x54c, 0x108, 5, 0x0, 0), /* MX35_PAD_CSI_HSYNC__GPIO1_30 */
+       [215] = IMX_PIN_REG(MX35_PAD_CSI_PIXCLK, 0x550, 0x10c, 0, 0x0, 0), /* MX35_PAD_CSI_PIXCLK__IPU_CSI_PIXCLK */
+       [216] = IMX_PIN_REG(MX35_PAD_CSI_PIXCLK, 0x550, 0x10c, 5, 0x0, 0), /* MX35_PAD_CSI_PIXCLK__GPIO1_31 */
+       [217] = IMX_PIN_REG(MX35_PAD_I2C1_CLK, 0x554, 0x110, 0, 0x0, 0), /* MX35_PAD_I2C1_CLK__I2C1_SCL */
+       [218] = IMX_PIN_REG(MX35_PAD_I2C1_CLK, 0x554, 0x110, 5, 0x8a8, 0), /* MX35_PAD_I2C1_CLK__GPIO2_24 */
+       [219] = IMX_PIN_REG(MX35_PAD_I2C1_CLK, 0x554, 0x110, 6, 0x0, 0), /* MX35_PAD_I2C1_CLK__CCM_USB_BYP_CLK */
+       [220] = IMX_PIN_REG(MX35_PAD_I2C1_DAT, 0x558, 0x114, 0, 0x0, 0), /* MX35_PAD_I2C1_DAT__I2C1_SDA */
+       [221] = IMX_PIN_REG(MX35_PAD_I2C1_DAT, 0x558, 0x114, 5, 0x8ac, 0), /* MX35_PAD_I2C1_DAT__GPIO2_25 */
+       [222] = IMX_PIN_REG(MX35_PAD_I2C2_CLK, 0x55c, 0x118, 0, 0x0, 0), /* MX35_PAD_I2C2_CLK__I2C2_SCL */
+       [223] = IMX_PIN_REG(MX35_PAD_I2C2_CLK, 0x55c, 0x118, 1, 0x0, 0), /* MX35_PAD_I2C2_CLK__CAN1_TXCAN */
+       [224] = IMX_PIN_REG(MX35_PAD_I2C2_CLK, 0x55c, 0x118, 2, 0x0, 0), /* MX35_PAD_I2C2_CLK__USB_TOP_USBH2_PWR */
+       [225] = IMX_PIN_REG(MX35_PAD_I2C2_CLK, 0x55c, 0x118, 5, 0x8b0, 0), /* MX35_PAD_I2C2_CLK__GPIO2_26 */
+       [226] = IMX_PIN_REG(MX35_PAD_I2C2_CLK, 0x55c, 0x118, 6, 0x0, 0), /* MX35_PAD_I2C2_CLK__SDMA_DEBUG_BUS_DEVICE_2 */
+       [227] = IMX_PIN_REG(MX35_PAD_I2C2_DAT, 0x560, 0x11c, 0, 0x0, 0), /* MX35_PAD_I2C2_DAT__I2C2_SDA */
+       [228] = IMX_PIN_REG(MX35_PAD_I2C2_DAT, 0x560, 0x11c, 1, 0x7c8, 0), /* MX35_PAD_I2C2_DAT__CAN1_RXCAN */
+       [229] = IMX_PIN_REG(MX35_PAD_I2C2_DAT, 0x560, 0x11c, 2, 0x9f4, 0), /* MX35_PAD_I2C2_DAT__USB_TOP_USBH2_OC */
+       [230] = IMX_PIN_REG(MX35_PAD_I2C2_DAT, 0x560, 0x11c, 5, 0x8b4, 0), /* MX35_PAD_I2C2_DAT__GPIO2_27 */
+       [231] = IMX_PIN_REG(MX35_PAD_I2C2_DAT, 0x560, 0x11c, 6, 0x0, 0), /* MX35_PAD_I2C2_DAT__SDMA_DEBUG_BUS_DEVICE_3 */
+       [232] = IMX_PIN_REG(MX35_PAD_STXD4, 0x564, 0x120, 0, 0x0, 0), /* MX35_PAD_STXD4__AUDMUX_AUD4_TXD */
+       [233] = IMX_PIN_REG(MX35_PAD_STXD4, 0x564, 0x120, 5, 0x8b8, 0), /* MX35_PAD_STXD4__GPIO2_28 */
+       [234] = IMX_PIN_REG(MX35_PAD_STXD4, 0x564, 0x120, 7, 0x0, 0), /* MX35_PAD_STXD4__ARM11P_TOP_ARM_COREASID0 */
+       [235] = IMX_PIN_REG(MX35_PAD_SRXD4, 0x568, 0x124, 0, 0x0, 0), /* MX35_PAD_SRXD4__AUDMUX_AUD4_RXD */
+       [236] = IMX_PIN_REG(MX35_PAD_SRXD4, 0x568, 0x124, 5, 0x8bc, 0), /* MX35_PAD_SRXD4__GPIO2_29 */
+       [237] = IMX_PIN_REG(MX35_PAD_SRXD4, 0x568, 0x124, 7, 0x0, 0), /* MX35_PAD_SRXD4__ARM11P_TOP_ARM_COREASID1 */
+       [238] = IMX_PIN_REG(MX35_PAD_SCK4, 0x56c, 0x128, 0, 0x0, 0), /* MX35_PAD_SCK4__AUDMUX_AUD4_TXC */
+       [239] = IMX_PIN_REG(MX35_PAD_SCK4, 0x56c, 0x128, 5, 0x8c4, 0), /* MX35_PAD_SCK4__GPIO2_30 */
+       [240] = IMX_PIN_REG(MX35_PAD_SCK4, 0x56c, 0x128, 7, 0x0, 0), /* MX35_PAD_SCK4__ARM11P_TOP_ARM_COREASID2 */
+       [241] = IMX_PIN_REG(MX35_PAD_STXFS4, 0x570, 0x12c, 0, 0x0, 0), /* MX35_PAD_STXFS4__AUDMUX_AUD4_TXFS */
+       [242] = IMX_PIN_REG(MX35_PAD_STXFS4, 0x570, 0x12c, 5, 0x8c8, 0), /* MX35_PAD_STXFS4__GPIO2_31 */
+       [243] = IMX_PIN_REG(MX35_PAD_STXFS4, 0x570, 0x12c, 7, 0x0, 0), /* MX35_PAD_STXFS4__ARM11P_TOP_ARM_COREASID3 */
+       [244] = IMX_PIN_REG(MX35_PAD_STXD5, 0x574, 0x130, 0, 0x0, 0), /* MX35_PAD_STXD5__AUDMUX_AUD5_TXD */
+       [245] = IMX_PIN_REG(MX35_PAD_STXD5, 0x574, 0x130, 1, 0x0, 0), /* MX35_PAD_STXD5__SPDIF_SPDIF_OUT1 */
+       [246] = IMX_PIN_REG(MX35_PAD_STXD5, 0x574, 0x130, 2, 0x7ec, 0), /* MX35_PAD_STXD5__CSPI2_MOSI */
+       [247] = IMX_PIN_REG(MX35_PAD_STXD5, 0x574, 0x130, 5, 0x82c, 1), /* MX35_PAD_STXD5__GPIO1_0 */
+       [248] = IMX_PIN_REG(MX35_PAD_STXD5, 0x574, 0x130, 7, 0x0, 0), /* MX35_PAD_STXD5__ARM11P_TOP_ARM_COREASID4 */
+       [249] = IMX_PIN_REG(MX35_PAD_SRXD5, 0x578, 0x134, 0, 0x0, 0), /* MX35_PAD_SRXD5__AUDMUX_AUD5_RXD */
+       [250] = IMX_PIN_REG(MX35_PAD_SRXD5, 0x578, 0x134, 1, 0x998, 0), /* MX35_PAD_SRXD5__SPDIF_SPDIF_IN1 */
+       [251] = IMX_PIN_REG(MX35_PAD_SRXD5, 0x578, 0x134, 2, 0x7e8, 0), /* MX35_PAD_SRXD5__CSPI2_MISO */
+       [252] = IMX_PIN_REG(MX35_PAD_SRXD5, 0x578, 0x134, 5, 0x838, 1), /* MX35_PAD_SRXD5__GPIO1_1 */
+       [253] = IMX_PIN_REG(MX35_PAD_SRXD5, 0x578, 0x134, 7, 0x0, 0), /* MX35_PAD_SRXD5__ARM11P_TOP_ARM_COREASID5 */
+       [254] = IMX_PIN_REG(MX35_PAD_SCK5, 0x57c, 0x138, 0, 0x0, 0), /* MX35_PAD_SCK5__AUDMUX_AUD5_TXC */
+       [255] = IMX_PIN_REG(MX35_PAD_SCK5, 0x57c, 0x138, 1, 0x994, 0), /* MX35_PAD_SCK5__SPDIF_SPDIF_EXTCLK */
+       [256] = IMX_PIN_REG(MX35_PAD_SCK5, 0x57c, 0x138, 2, 0x7e0, 0), /* MX35_PAD_SCK5__CSPI2_SCLK */
+       [257] = IMX_PIN_REG(MX35_PAD_SCK5, 0x57c, 0x138, 5, 0x848, 0), /* MX35_PAD_SCK5__GPIO1_2 */
+       [258] = IMX_PIN_REG(MX35_PAD_SCK5, 0x57c, 0x138, 7, 0x0, 0), /* MX35_PAD_SCK5__ARM11P_TOP_ARM_COREASID6 */
+       [259] = IMX_PIN_REG(MX35_PAD_STXFS5, 0x580, 0x13c, 0, 0x0, 0), /* MX35_PAD_STXFS5__AUDMUX_AUD5_TXFS */
+       [260] = IMX_PIN_REG(MX35_PAD_STXFS5, 0x580, 0x13c, 2, 0x7e4, 0), /* MX35_PAD_STXFS5__CSPI2_RDY */
+       [261] = IMX_PIN_REG(MX35_PAD_STXFS5, 0x580, 0x13c, 5, 0x84c, 0), /* MX35_PAD_STXFS5__GPIO1_3 */
+       [262] = IMX_PIN_REG(MX35_PAD_STXFS5, 0x580, 0x13c, 7, 0x0, 0), /* MX35_PAD_STXFS5__ARM11P_TOP_ARM_COREASID7 */
+       [263] = IMX_PIN_REG(MX35_PAD_SCKR, 0x584, 0x140, 0, 0x0, 0), /* MX35_PAD_SCKR__ESAI_SCKR */
+       [264] = IMX_PIN_REG(MX35_PAD_SCKR, 0x584, 0x140, 5, 0x850, 1), /* MX35_PAD_SCKR__GPIO1_4 */
+       [265] = IMX_PIN_REG(MX35_PAD_SCKR, 0x584, 0x140, 7, 0x0, 0), /* MX35_PAD_SCKR__ARM11P_TOP_EVNTBUS_10 */
+       [266] = IMX_PIN_REG(MX35_PAD_FSR, 0x588, 0x144, 0, 0x0, 0), /* MX35_PAD_FSR__ESAI_FSR */
+       [267] = IMX_PIN_REG(MX35_PAD_FSR, 0x588, 0x144, 5, 0x854, 1), /* MX35_PAD_FSR__GPIO1_5 */
+       [268] = IMX_PIN_REG(MX35_PAD_FSR, 0x588, 0x144, 7, 0x0, 0), /* MX35_PAD_FSR__ARM11P_TOP_EVNTBUS_11 */
+       [269] = IMX_PIN_REG(MX35_PAD_HCKR, 0x58c, 0x148, 0, 0x0, 0), /* MX35_PAD_HCKR__ESAI_HCKR */
+       [270] = IMX_PIN_REG(MX35_PAD_HCKR, 0x58c, 0x148, 1, 0x0, 0), /* MX35_PAD_HCKR__AUDMUX_AUD5_RXFS */
+       [271] = IMX_PIN_REG(MX35_PAD_HCKR, 0x58c, 0x148, 2, 0x7f0, 0), /* MX35_PAD_HCKR__CSPI2_SS0 */
+       [272] = IMX_PIN_REG(MX35_PAD_HCKR, 0x58c, 0x148, 3, 0x0, 0), /* MX35_PAD_HCKR__IPU_FLASH_STROBE */
+       [273] = IMX_PIN_REG(MX35_PAD_HCKR, 0x58c, 0x148, 5, 0x858, 1), /* MX35_PAD_HCKR__GPIO1_6 */
+       [274] = IMX_PIN_REG(MX35_PAD_HCKR, 0x58c, 0x148, 7, 0x0, 0), /* MX35_PAD_HCKR__ARM11P_TOP_EVNTBUS_12 */
+       [275] = IMX_PIN_REG(MX35_PAD_SCKT, 0x590, 0x14c, 0, 0x0, 0), /* MX35_PAD_SCKT__ESAI_SCKT */
+       [276] = IMX_PIN_REG(MX35_PAD_SCKT, 0x590, 0x14c, 5, 0x85c, 1), /* MX35_PAD_SCKT__GPIO1_7 */
+       [277] = IMX_PIN_REG(MX35_PAD_SCKT, 0x590, 0x14c, 6, 0x930, 0), /* MX35_PAD_SCKT__IPU_CSI_D_0 */
+       [278] = IMX_PIN_REG(MX35_PAD_SCKT, 0x590, 0x14c, 7, 0x978, 1), /* MX35_PAD_SCKT__KPP_ROW_2 */
+       [279] = IMX_PIN_REG(MX35_PAD_FST, 0x594, 0x150, 0, 0x0, 0), /* MX35_PAD_FST__ESAI_FST */
+       [280] = IMX_PIN_REG(MX35_PAD_FST, 0x594, 0x150, 5, 0x860, 1), /* MX35_PAD_FST__GPIO1_8 */
+       [281] = IMX_PIN_REG(MX35_PAD_FST, 0x594, 0x150, 6, 0x934, 0), /* MX35_PAD_FST__IPU_CSI_D_1 */
+       [282] = IMX_PIN_REG(MX35_PAD_FST, 0x594, 0x150, 7, 0x97c, 1), /* MX35_PAD_FST__KPP_ROW_3 */
+       [283] = IMX_PIN_REG(MX35_PAD_HCKT, 0x598, 0x154, 0, 0x0, 0), /* MX35_PAD_HCKT__ESAI_HCKT */
+       [284] = IMX_PIN_REG(MX35_PAD_HCKT, 0x598, 0x154, 1, 0x7a8, 0), /* MX35_PAD_HCKT__AUDMUX_AUD5_RXC */
+       [285] = IMX_PIN_REG(MX35_PAD_HCKT, 0x598, 0x154, 5, 0x864, 0), /* MX35_PAD_HCKT__GPIO1_9 */
+       [286] = IMX_PIN_REG(MX35_PAD_HCKT, 0x598, 0x154, 6, 0x938, 0), /* MX35_PAD_HCKT__IPU_CSI_D_2 */
+       [287] = IMX_PIN_REG(MX35_PAD_HCKT, 0x598, 0x154, 7, 0x95c, 1), /* MX35_PAD_HCKT__KPP_COL_3 */
+       [288] = IMX_PIN_REG(MX35_PAD_TX5_RX0, 0x59c, 0x158, 0, 0x0, 0), /* MX35_PAD_TX5_RX0__ESAI_TX5_RX0 */
+       [289] = IMX_PIN_REG(MX35_PAD_TX5_RX0, 0x59c, 0x158, 1, 0x0, 0), /* MX35_PAD_TX5_RX0__AUDMUX_AUD4_RXC */
+       [290] = IMX_PIN_REG(MX35_PAD_TX5_RX0, 0x59c, 0x158, 2, 0x7f8, 1), /* MX35_PAD_TX5_RX0__CSPI2_SS2 */
+       [291] = IMX_PIN_REG(MX35_PAD_TX5_RX0, 0x59c, 0x158, 3, 0x0, 0), /* MX35_PAD_TX5_RX0__CAN2_TXCAN */
+       [292] = IMX_PIN_REG(MX35_PAD_TX5_RX0, 0x59c, 0x158, 4, 0x0, 0), /* MX35_PAD_TX5_RX0__UART2_DTR */
+       [293] = IMX_PIN_REG(MX35_PAD_TX5_RX0, 0x59c, 0x158, 5, 0x830, 0), /* MX35_PAD_TX5_RX0__GPIO1_10 */
+       [294] = IMX_PIN_REG(MX35_PAD_TX5_RX0, 0x59c, 0x158, 7, 0x0, 0), /* MX35_PAD_TX5_RX0__EMI_M3IF_CHOSEN_MASTER_0 */
+       [295] = IMX_PIN_REG(MX35_PAD_TX4_RX1, 0x5a0, 0x15c, 0, 0x0, 0), /* MX35_PAD_TX4_RX1__ESAI_TX4_RX1 */
+       [296] = IMX_PIN_REG(MX35_PAD_TX4_RX1, 0x5a0, 0x15c, 1, 0x0, 0), /* MX35_PAD_TX4_RX1__AUDMUX_AUD4_RXFS */
+       [297] = IMX_PIN_REG(MX35_PAD_TX4_RX1, 0x5a0, 0x15c, 2, 0x7fc, 0), /* MX35_PAD_TX4_RX1__CSPI2_SS3 */
+       [298] = IMX_PIN_REG(MX35_PAD_TX4_RX1, 0x5a0, 0x15c, 3, 0x7cc, 0), /* MX35_PAD_TX4_RX1__CAN2_RXCAN */
+       [299] = IMX_PIN_REG(MX35_PAD_TX4_RX1, 0x5a0, 0x15c, 4, 0x0, 0), /* MX35_PAD_TX4_RX1__UART2_DSR */
+       [300] = IMX_PIN_REG(MX35_PAD_TX4_RX1, 0x5a0, 0x15c, 5, 0x834, 0), /* MX35_PAD_TX4_RX1__GPIO1_11 */
+       [301] = IMX_PIN_REG(MX35_PAD_TX4_RX1, 0x5a0, 0x15c, 6, 0x93c, 0), /* MX35_PAD_TX4_RX1__IPU_CSI_D_3 */
+       [302] = IMX_PIN_REG(MX35_PAD_TX4_RX1, 0x5a0, 0x15c, 7, 0x970, 1), /* MX35_PAD_TX4_RX1__KPP_ROW_0 */
+       [303] = IMX_PIN_REG(MX35_PAD_TX3_RX2, 0x5a4, 0x160, 0, 0x0, 0), /* MX35_PAD_TX3_RX2__ESAI_TX3_RX2 */
+       [304] = IMX_PIN_REG(MX35_PAD_TX3_RX2, 0x5a4, 0x160, 1, 0x91c, 0), /* MX35_PAD_TX3_RX2__I2C3_SCL */
+       [305] = IMX_PIN_REG(MX35_PAD_TX3_RX2, 0x5a4, 0x160, 3, 0x0, 0), /* MX35_PAD_TX3_RX2__EMI_NANDF_CE1 */
+       [306] = IMX_PIN_REG(MX35_PAD_TX3_RX2, 0x5a4, 0x160, 5, 0x0, 0), /* MX35_PAD_TX3_RX2__GPIO1_12 */
+       [307] = IMX_PIN_REG(MX35_PAD_TX3_RX2, 0x5a4, 0x160, 6, 0x940, 0), /* MX35_PAD_TX3_RX2__IPU_CSI_D_4 */
+       [308] = IMX_PIN_REG(MX35_PAD_TX3_RX2, 0x5a4, 0x160, 7, 0x974, 1), /* MX35_PAD_TX3_RX2__KPP_ROW_1 */
+       [309] = IMX_PIN_REG(MX35_PAD_TX2_RX3, 0x5a8, 0x164, 0, 0x0, 0), /* MX35_PAD_TX2_RX3__ESAI_TX2_RX3 */
+       [310] = IMX_PIN_REG(MX35_PAD_TX2_RX3, 0x5a8, 0x164, 1, 0x920, 0), /* MX35_PAD_TX2_RX3__I2C3_SDA */
+       [311] = IMX_PIN_REG(MX35_PAD_TX2_RX3, 0x5a8, 0x164, 3, 0x0, 0), /* MX35_PAD_TX2_RX3__EMI_NANDF_CE2 */
+       [312] = IMX_PIN_REG(MX35_PAD_TX2_RX3, 0x5a8, 0x164, 5, 0x0, 0), /* MX35_PAD_TX2_RX3__GPIO1_13 */
+       [313] = IMX_PIN_REG(MX35_PAD_TX2_RX3, 0x5a8, 0x164, 6, 0x944, 0), /* MX35_PAD_TX2_RX3__IPU_CSI_D_5 */
+       [314] = IMX_PIN_REG(MX35_PAD_TX2_RX3, 0x5a8, 0x164, 7, 0x950, 1), /* MX35_PAD_TX2_RX3__KPP_COL_0 */
+       [315] = IMX_PIN_REG(MX35_PAD_TX1, 0x5ac, 0x168, 0, 0x0, 0), /* MX35_PAD_TX1__ESAI_TX1 */
+       [316] = IMX_PIN_REG(MX35_PAD_TX1, 0x5ac, 0x168, 1, 0x7d4, 1), /* MX35_PAD_TX1__CCM_PMIC_RDY */
+       [317] = IMX_PIN_REG(MX35_PAD_TX1, 0x5ac, 0x168, 2, 0x7d8, 2), /* MX35_PAD_TX1__CSPI1_SS2 */
+       [318] = IMX_PIN_REG(MX35_PAD_TX1, 0x5ac, 0x168, 3, 0x0, 0), /* MX35_PAD_TX1__EMI_NANDF_CE3 */
+       [319] = IMX_PIN_REG(MX35_PAD_TX1, 0x5ac, 0x168, 4, 0x0, 0), /* MX35_PAD_TX1__UART2_RI */
+       [320] = IMX_PIN_REG(MX35_PAD_TX1, 0x5ac, 0x168, 5, 0x0, 0), /* MX35_PAD_TX1__GPIO1_14 */
+       [321] = IMX_PIN_REG(MX35_PAD_TX1, 0x5ac, 0x168, 6, 0x948, 0), /* MX35_PAD_TX1__IPU_CSI_D_6 */
+       [322] = IMX_PIN_REG(MX35_PAD_TX1, 0x5ac, 0x168, 7, 0x954, 1), /* MX35_PAD_TX1__KPP_COL_1 */
+       [323] = IMX_PIN_REG(MX35_PAD_TX0, 0x5b0, 0x16c, 0, 0x0, 0), /* MX35_PAD_TX0__ESAI_TX0 */
+       [324] = IMX_PIN_REG(MX35_PAD_TX0, 0x5b0, 0x16c, 1, 0x994, 1), /* MX35_PAD_TX0__SPDIF_SPDIF_EXTCLK */
+       [325] = IMX_PIN_REG(MX35_PAD_TX0, 0x5b0, 0x16c, 2, 0x7dc, 0), /* MX35_PAD_TX0__CSPI1_SS3 */
+       [326] = IMX_PIN_REG(MX35_PAD_TX0, 0x5b0, 0x16c, 3, 0x800, 1), /* MX35_PAD_TX0__EMI_DTACK_B */
+       [327] = IMX_PIN_REG(MX35_PAD_TX0, 0x5b0, 0x16c, 4, 0x0, 0), /* MX35_PAD_TX0__UART2_DCD */
+       [328] = IMX_PIN_REG(MX35_PAD_TX0, 0x5b0, 0x16c, 5, 0x0, 0), /* MX35_PAD_TX0__GPIO1_15 */
+       [329] = IMX_PIN_REG(MX35_PAD_TX0, 0x5b0, 0x16c, 6, 0x94c, 0), /* MX35_PAD_TX0__IPU_CSI_D_7 */
+       [330] = IMX_PIN_REG(MX35_PAD_TX0, 0x5b0, 0x16c, 7, 0x958, 1), /* MX35_PAD_TX0__KPP_COL_2 */
+       [331] = IMX_PIN_REG(MX35_PAD_CSPI1_MOSI, 0x5b4, 0x170, 0, 0x0, 0), /* MX35_PAD_CSPI1_MOSI__CSPI1_MOSI */
+       [332] = IMX_PIN_REG(MX35_PAD_CSPI1_MOSI, 0x5b4, 0x170, 5, 0x0, 0), /* MX35_PAD_CSPI1_MOSI__GPIO1_16 */
+       [333] = IMX_PIN_REG(MX35_PAD_CSPI1_MOSI, 0x5b4, 0x170, 7, 0x0, 0), /* MX35_PAD_CSPI1_MOSI__ECT_CTI_TRIG_OUT1_2 */
+       [334] = IMX_PIN_REG(MX35_PAD_CSPI1_MISO, 0x5b8, 0x174, 0, 0x0, 0), /* MX35_PAD_CSPI1_MISO__CSPI1_MISO */
+       [335] = IMX_PIN_REG(MX35_PAD_CSPI1_MISO, 0x5b8, 0x174, 5, 0x0, 0), /* MX35_PAD_CSPI1_MISO__GPIO1_17 */
+       [336] = IMX_PIN_REG(MX35_PAD_CSPI1_MISO, 0x5b8, 0x174, 7, 0x0, 0), /* MX35_PAD_CSPI1_MISO__ECT_CTI_TRIG_OUT1_3 */
+       [337] = IMX_PIN_REG(MX35_PAD_CSPI1_SS0, 0x5bc, 0x178, 0, 0x0, 0), /* MX35_PAD_CSPI1_SS0__CSPI1_SS0 */
+       [338] = IMX_PIN_REG(MX35_PAD_CSPI1_SS0, 0x5bc, 0x178, 1, 0x990, 1), /* MX35_PAD_CSPI1_SS0__OWIRE_LINE */
+       [339] = IMX_PIN_REG(MX35_PAD_CSPI1_SS0, 0x5bc, 0x178, 2, 0x7fc, 1), /* MX35_PAD_CSPI1_SS0__CSPI2_SS3 */
+       [340] = IMX_PIN_REG(MX35_PAD_CSPI1_SS0, 0x5bc, 0x178, 5, 0x0, 0), /* MX35_PAD_CSPI1_SS0__GPIO1_18 */
+       [341] = IMX_PIN_REG(MX35_PAD_CSPI1_SS0, 0x5bc, 0x178, 7, 0x0, 0), /* MX35_PAD_CSPI1_SS0__ECT_CTI_TRIG_OUT1_4 */
+       [342] = IMX_PIN_REG(MX35_PAD_CSPI1_SS1, 0x5c0, 0x17c, 0, 0x0, 0), /* MX35_PAD_CSPI1_SS1__CSPI1_SS1 */
+       [343] = IMX_PIN_REG(MX35_PAD_CSPI1_SS1, 0x5c0, 0x17c, 1, 0x0, 0), /* MX35_PAD_CSPI1_SS1__PWM_PWMO */
+       [344] = IMX_PIN_REG(MX35_PAD_CSPI1_SS1, 0x5c0, 0x17c, 2, 0x7d0, 1), /* MX35_PAD_CSPI1_SS1__CCM_CLK32K */
+       [345] = IMX_PIN_REG(MX35_PAD_CSPI1_SS1, 0x5c0, 0x17c, 5, 0x0, 0), /* MX35_PAD_CSPI1_SS1__GPIO1_19 */
+       [346] = IMX_PIN_REG(MX35_PAD_CSPI1_SS1, 0x5c0, 0x17c, 6, 0x0, 0), /* MX35_PAD_CSPI1_SS1__IPU_DIAGB_29 */
+       [347] = IMX_PIN_REG(MX35_PAD_CSPI1_SS1, 0x5c0, 0x17c, 7, 0x0, 0), /* MX35_PAD_CSPI1_SS1__ECT_CTI_TRIG_OUT1_5 */
+       [348] = IMX_PIN_REG(MX35_PAD_CSPI1_SCLK, 0x5c4, 0x180, 0, 0x0, 0), /* MX35_PAD_CSPI1_SCLK__CSPI1_SCLK */
+       [349] = IMX_PIN_REG(MX35_PAD_CSPI1_SCLK, 0x5c4, 0x180, 5, 0x904, 0), /* MX35_PAD_CSPI1_SCLK__GPIO3_4 */
+       [350] = IMX_PIN_REG(MX35_PAD_CSPI1_SCLK, 0x5c4, 0x180, 6, 0x0, 0), /* MX35_PAD_CSPI1_SCLK__IPU_DIAGB_30 */
+       [351] = IMX_PIN_REG(MX35_PAD_CSPI1_SCLK, 0x5c4, 0x180, 7, 0x0, 0), /* MX35_PAD_CSPI1_SCLK__EMI_M3IF_CHOSEN_MASTER_1 */
+       [352] = IMX_PIN_REG(MX35_PAD_CSPI1_SPI_RDY, 0x5c8, 0x184, 0, 0x0, 0), /* MX35_PAD_CSPI1_SPI_RDY__CSPI1_RDY */
+       [353] = IMX_PIN_REG(MX35_PAD_CSPI1_SPI_RDY, 0x5c8, 0x184, 5, 0x908, 0), /* MX35_PAD_CSPI1_SPI_RDY__GPIO3_5 */
+       [354] = IMX_PIN_REG(MX35_PAD_CSPI1_SPI_RDY, 0x5c8, 0x184, 6, 0x0, 0), /* MX35_PAD_CSPI1_SPI_RDY__IPU_DIAGB_31 */
+       [355] = IMX_PIN_REG(MX35_PAD_CSPI1_SPI_RDY, 0x5c8, 0x184, 7, 0x0, 0), /* MX35_PAD_CSPI1_SPI_RDY__EMI_M3IF_CHOSEN_MASTER_2 */
+       [356] = IMX_PIN_REG(MX35_PAD_RXD1, 0x5cc, 0x188, 0, 0x0, 0), /* MX35_PAD_RXD1__UART1_RXD_MUX */
+       [357] = IMX_PIN_REG(MX35_PAD_RXD1, 0x5cc, 0x188, 1, 0x7ec, 1), /* MX35_PAD_RXD1__CSPI2_MOSI */
+       [358] = IMX_PIN_REG(MX35_PAD_RXD1, 0x5cc, 0x188, 4, 0x960, 0), /* MX35_PAD_RXD1__KPP_COL_4 */
+       [359] = IMX_PIN_REG(MX35_PAD_RXD1, 0x5cc, 0x188, 5, 0x90c, 0), /* MX35_PAD_RXD1__GPIO3_6 */
+       [360] = IMX_PIN_REG(MX35_PAD_RXD1, 0x5cc, 0x188, 7, 0x0, 0), /* MX35_PAD_RXD1__ARM11P_TOP_EVNTBUS_16 */
+       [361] = IMX_PIN_REG(MX35_PAD_TXD1, 0x5d0, 0x18c, 0, 0x0, 0), /* MX35_PAD_TXD1__UART1_TXD_MUX */
+       [362] = IMX_PIN_REG(MX35_PAD_TXD1, 0x5d0, 0x18c, 1, 0x7e8, 1), /* MX35_PAD_TXD1__CSPI2_MISO */
+       [363] = IMX_PIN_REG(MX35_PAD_TXD1, 0x5d0, 0x18c, 4, 0x964, 0), /* MX35_PAD_TXD1__KPP_COL_5 */
+       [364] = IMX_PIN_REG(MX35_PAD_TXD1, 0x5d0, 0x18c, 5, 0x910, 0), /* MX35_PAD_TXD1__GPIO3_7 */
+       [365] = IMX_PIN_REG(MX35_PAD_TXD1, 0x5d0, 0x18c, 7, 0x0, 0), /* MX35_PAD_TXD1__ARM11P_TOP_EVNTBUS_17 */
+       [366] = IMX_PIN_REG(MX35_PAD_RTS1, 0x5d4, 0x190, 0, 0x0, 0), /* MX35_PAD_RTS1__UART1_RTS */
+       [367] = IMX_PIN_REG(MX35_PAD_RTS1, 0x5d4, 0x190, 1, 0x7e0, 1), /* MX35_PAD_RTS1__CSPI2_SCLK */
+       [368] = IMX_PIN_REG(MX35_PAD_RTS1, 0x5d4, 0x190, 2, 0x91c, 1), /* MX35_PAD_RTS1__I2C3_SCL */
+       [369] = IMX_PIN_REG(MX35_PAD_RTS1, 0x5d4, 0x190, 3, 0x930, 1), /* MX35_PAD_RTS1__IPU_CSI_D_0 */
+       [370] = IMX_PIN_REG(MX35_PAD_RTS1, 0x5d4, 0x190, 4, 0x968, 0), /* MX35_PAD_RTS1__KPP_COL_6 */
+       [371] = IMX_PIN_REG(MX35_PAD_RTS1, 0x5d4, 0x190, 5, 0x914, 0), /* MX35_PAD_RTS1__GPIO3_8 */
+       [372] = IMX_PIN_REG(MX35_PAD_RTS1, 0x5d4, 0x190, 6, 0x0, 0), /* MX35_PAD_RTS1__EMI_NANDF_CE1 */
+       [373] = IMX_PIN_REG(MX35_PAD_RTS1, 0x5d4, 0x190, 7, 0x0, 0), /* MX35_PAD_RTS1__ARM11P_TOP_EVNTBUS_18 */
+       [374] = IMX_PIN_REG(MX35_PAD_CTS1, 0x5d8, 0x194, 0, 0x0, 0), /* MX35_PAD_CTS1__UART1_CTS */
+       [375] = IMX_PIN_REG(MX35_PAD_CTS1, 0x5d8, 0x194, 1, 0x7e4, 1), /* MX35_PAD_CTS1__CSPI2_RDY */
+       [376] = IMX_PIN_REG(MX35_PAD_CTS1, 0x5d8, 0x194, 2, 0x920, 1), /* MX35_PAD_CTS1__I2C3_SDA */
+       [377] = IMX_PIN_REG(MX35_PAD_CTS1, 0x5d8, 0x194, 3, 0x934, 1), /* MX35_PAD_CTS1__IPU_CSI_D_1 */
+       [378] = IMX_PIN_REG(MX35_PAD_CTS1, 0x5d8, 0x194, 4, 0x96c, 0), /* MX35_PAD_CTS1__KPP_COL_7 */
+       [379] = IMX_PIN_REG(MX35_PAD_CTS1, 0x5d8, 0x194, 5, 0x918, 0), /* MX35_PAD_CTS1__GPIO3_9 */
+       [380] = IMX_PIN_REG(MX35_PAD_CTS1, 0x5d8, 0x194, 6, 0x0, 0), /* MX35_PAD_CTS1__EMI_NANDF_CE2 */
+       [381] = IMX_PIN_REG(MX35_PAD_CTS1, 0x5d8, 0x194, 7, 0x0, 0), /* MX35_PAD_CTS1__ARM11P_TOP_EVNTBUS_19 */
+       [382] = IMX_PIN_REG(MX35_PAD_RXD2, 0x5dc, 0x198, 0, 0x0, 0), /* MX35_PAD_RXD2__UART2_RXD_MUX */
+       [383] = IMX_PIN_REG(MX35_PAD_RXD2, 0x5dc, 0x198, 4, 0x980, 0), /* MX35_PAD_RXD2__KPP_ROW_4 */
+       [384] = IMX_PIN_REG(MX35_PAD_RXD2, 0x5dc, 0x198, 5, 0x8ec, 0), /* MX35_PAD_RXD2__GPIO3_10 */
+       [385] = IMX_PIN_REG(MX35_PAD_TXD2, 0x5e0, 0x19c, 0, 0x0, 0), /* MX35_PAD_TXD2__UART2_TXD_MUX */
+       [386] = IMX_PIN_REG(MX35_PAD_TXD2, 0x5e0, 0x19c, 1, 0x994, 2), /* MX35_PAD_TXD2__SPDIF_SPDIF_EXTCLK */
+       [387] = IMX_PIN_REG(MX35_PAD_TXD2, 0x5e0, 0x19c, 4, 0x984, 0), /* MX35_PAD_TXD2__KPP_ROW_5 */
+       [388] = IMX_PIN_REG(MX35_PAD_TXD2, 0x5e0, 0x19c, 5, 0x8f0, 0), /* MX35_PAD_TXD2__GPIO3_11 */
+       [389] = IMX_PIN_REG(MX35_PAD_RTS2, 0x5e4, 0x1a0, 0, 0x0, 0), /* MX35_PAD_RTS2__UART2_RTS */
+       [390] = IMX_PIN_REG(MX35_PAD_RTS2, 0x5e4, 0x1a0, 1, 0x998, 1), /* MX35_PAD_RTS2__SPDIF_SPDIF_IN1 */
+       [391] = IMX_PIN_REG(MX35_PAD_RTS2, 0x5e4, 0x1a0, 2, 0x7cc, 1), /* MX35_PAD_RTS2__CAN2_RXCAN */
+       [392] = IMX_PIN_REG(MX35_PAD_RTS2, 0x5e4, 0x1a0, 3, 0x938, 1), /* MX35_PAD_RTS2__IPU_CSI_D_2 */
+       [393] = IMX_PIN_REG(MX35_PAD_RTS2, 0x5e4, 0x1a0, 4, 0x988, 0), /* MX35_PAD_RTS2__KPP_ROW_6 */
+       [394] = IMX_PIN_REG(MX35_PAD_RTS2, 0x5e4, 0x1a0, 5, 0x8f4, 0), /* MX35_PAD_RTS2__GPIO3_12 */
+       [395] = IMX_PIN_REG(MX35_PAD_RTS2, 0x5e4, 0x1a0, 6, 0x0, 0), /* MX35_PAD_RTS2__AUDMUX_AUD5_RXC */
+       [396] = IMX_PIN_REG(MX35_PAD_RTS2, 0x5e4, 0x1a0, 7, 0x9a0, 0), /* MX35_PAD_RTS2__UART3_RXD_MUX */
+       [397] = IMX_PIN_REG(MX35_PAD_CTS2, 0x5e8, 0x1a4, 0, 0x0, 0), /* MX35_PAD_CTS2__UART2_CTS */
+       [398] = IMX_PIN_REG(MX35_PAD_CTS2, 0x5e8, 0x1a4, 1, 0x0, 0), /* MX35_PAD_CTS2__SPDIF_SPDIF_OUT1 */
+       [399] = IMX_PIN_REG(MX35_PAD_CTS2, 0x5e8, 0x1a4, 2, 0x0, 0), /* MX35_PAD_CTS2__CAN2_TXCAN */
+       [400] = IMX_PIN_REG(MX35_PAD_CTS2, 0x5e8, 0x1a4, 3, 0x93c, 1), /* MX35_PAD_CTS2__IPU_CSI_D_3 */
+       [401] = IMX_PIN_REG(MX35_PAD_CTS2, 0x5e8, 0x1a4, 4, 0x98c, 0), /* MX35_PAD_CTS2__KPP_ROW_7 */
+       [402] = IMX_PIN_REG(MX35_PAD_CTS2, 0x5e8, 0x1a4, 5, 0x8f8, 0), /* MX35_PAD_CTS2__GPIO3_13 */
+       [403] = IMX_PIN_REG(MX35_PAD_CTS2, 0x5e8, 0x1a4, 6, 0x0, 0), /* MX35_PAD_CTS2__AUDMUX_AUD5_RXFS */
+       [404] = IMX_PIN_REG(MX35_PAD_CTS2, 0x5e8, 0x1a4, 7, 0x0, 0), /* MX35_PAD_CTS2__UART3_TXD_MUX */
+       [405] = IMX_PIN_REG(MX35_PAD_RTCK, 0x5ec, 0x0, 0, 0x0, 0), /* MX35_PAD_RTCK__ARM11P_TOP_RTCK */
+       [406] = IMX_PIN_REG(MX35_PAD_TCK, 0x5f0, 0x0, 0, 0x0, 0), /* MX35_PAD_TCK__SJC_TCK */
+       [407] = IMX_PIN_REG(MX35_PAD_TMS, 0x5f4, 0x0, 0, 0x0, 0), /* MX35_PAD_TMS__SJC_TMS */
+       [408] = IMX_PIN_REG(MX35_PAD_TDI, 0x5f8, 0x0, 0, 0x0, 0), /* MX35_PAD_TDI__SJC_TDI */
+       [409] = IMX_PIN_REG(MX35_PAD_TDO, 0x5fc, 0x0, 0, 0x0, 0), /* MX35_PAD_TDO__SJC_TDO */
+       [410] = IMX_PIN_REG(MX35_PAD_TRSTB, 0x600, 0x0, 0, 0x0, 0), /* MX35_PAD_TRSTB__SJC_TRSTB */
+       [411] = IMX_PIN_REG(MX35_PAD_DE_B, 0x604, 0x0, 0, 0x0, 0), /* MX35_PAD_DE_B__SJC_DE_B */
+       [412] = IMX_PIN_REG(MX35_PAD_SJC_MOD, 0x608, 0x0, 0, 0x0, 0), /* MX35_PAD_SJC_MOD__SJC_MOD */
+       [413] = IMX_PIN_REG(MX35_PAD_USBOTG_PWR, 0x60c, 0x1a8, 0, 0x0, 0), /* MX35_PAD_USBOTG_PWR__USB_TOP_USBOTG_PWR */
+       [414] = IMX_PIN_REG(MX35_PAD_USBOTG_PWR, 0x60c, 0x1a8, 1, 0x0, 0), /* MX35_PAD_USBOTG_PWR__USB_TOP_USBH2_PWR */
+       [415] = IMX_PIN_REG(MX35_PAD_USBOTG_PWR, 0x60c, 0x1a8, 5, 0x8fc, 0), /* MX35_PAD_USBOTG_PWR__GPIO3_14 */
+       [416] = IMX_PIN_REG(MX35_PAD_USBOTG_OC, 0x610, 0x1ac, 0, 0x0, 0), /* MX35_PAD_USBOTG_OC__USB_TOP_USBOTG_OC */
+       [417] = IMX_PIN_REG(MX35_PAD_USBOTG_OC, 0x610, 0x1ac, 1, 0x9f4, 1), /* MX35_PAD_USBOTG_OC__USB_TOP_USBH2_OC */
+       [418] = IMX_PIN_REG(MX35_PAD_USBOTG_OC, 0x610, 0x1ac, 5, 0x900, 0), /* MX35_PAD_USBOTG_OC__GPIO3_15 */
+       [419] = IMX_PIN_REG(MX35_PAD_LD0, 0x614, 0x1b0, 0, 0x0, 0), /* MX35_PAD_LD0__IPU_DISPB_DAT_0 */
+       [420] = IMX_PIN_REG(MX35_PAD_LD0, 0x614, 0x1b0, 5, 0x868, 1), /* MX35_PAD_LD0__GPIO2_0 */
+       [421] = IMX_PIN_REG(MX35_PAD_LD0, 0x614, 0x1b0, 6, 0x0, 0), /* MX35_PAD_LD0__SDMA_SDMA_DEBUG_PC_0 */
+       [422] = IMX_PIN_REG(MX35_PAD_LD1, 0x618, 0x1b4, 0, 0x0, 0), /* MX35_PAD_LD1__IPU_DISPB_DAT_1 */
+       [423] = IMX_PIN_REG(MX35_PAD_LD1, 0x618, 0x1b4, 5, 0x894, 0), /* MX35_PAD_LD1__GPIO2_1 */
+       [424] = IMX_PIN_REG(MX35_PAD_LD1, 0x618, 0x1b4, 6, 0x0, 0), /* MX35_PAD_LD1__SDMA_SDMA_DEBUG_PC_1 */
+       [425] = IMX_PIN_REG(MX35_PAD_LD2, 0x61c, 0x1b8, 0, 0x0, 0), /* MX35_PAD_LD2__IPU_DISPB_DAT_2 */
+       [426] = IMX_PIN_REG(MX35_PAD_LD2, 0x61c, 0x1b8, 5, 0x8c0, 0), /* MX35_PAD_LD2__GPIO2_2 */
+       [427] = IMX_PIN_REG(MX35_PAD_LD2, 0x61c, 0x1b8, 6, 0x0, 0), /* MX35_PAD_LD2__SDMA_SDMA_DEBUG_PC_2 */
+       [428] = IMX_PIN_REG(MX35_PAD_LD3, 0x620, 0x1bc, 0, 0x0, 0), /* MX35_PAD_LD3__IPU_DISPB_DAT_3 */
+       [429] = IMX_PIN_REG(MX35_PAD_LD3, 0x620, 0x1bc, 5, 0x8cc, 0), /* MX35_PAD_LD3__GPIO2_3 */
+       [430] = IMX_PIN_REG(MX35_PAD_LD3, 0x620, 0x1bc, 6, 0x0, 0), /* MX35_PAD_LD3__SDMA_SDMA_DEBUG_PC_3 */
+       [431] = IMX_PIN_REG(MX35_PAD_LD4, 0x624, 0x1c0, 0, 0x0, 0), /* MX35_PAD_LD4__IPU_DISPB_DAT_4 */
+       [432] = IMX_PIN_REG(MX35_PAD_LD4, 0x624, 0x1c0, 5, 0x8d0, 0), /* MX35_PAD_LD4__GPIO2_4 */
+       [433] = IMX_PIN_REG(MX35_PAD_LD4, 0x624, 0x1c0, 6, 0x0, 0), /* MX35_PAD_LD4__SDMA_SDMA_DEBUG_PC_4 */
+       [434] = IMX_PIN_REG(MX35_PAD_LD5, 0x628, 0x1c4, 0, 0x0, 0), /* MX35_PAD_LD5__IPU_DISPB_DAT_5 */
+       [435] = IMX_PIN_REG(MX35_PAD_LD5, 0x628, 0x1c4, 5, 0x8d4, 0), /* MX35_PAD_LD5__GPIO2_5 */
+       [436] = IMX_PIN_REG(MX35_PAD_LD5, 0x628, 0x1c4, 6, 0x0, 0), /* MX35_PAD_LD5__SDMA_SDMA_DEBUG_PC_5 */
+       [437] = IMX_PIN_REG(MX35_PAD_LD6, 0x62c, 0x1c8, 0, 0x0, 0), /* MX35_PAD_LD6__IPU_DISPB_DAT_6 */
+       [438] = IMX_PIN_REG(MX35_PAD_LD6, 0x62c, 0x1c8, 5, 0x8d8, 0), /* MX35_PAD_LD6__GPIO2_6 */
+       [439] = IMX_PIN_REG(MX35_PAD_LD6, 0x62c, 0x1c8, 6, 0x0, 0), /* MX35_PAD_LD6__SDMA_SDMA_DEBUG_PC_6 */
+       [440] = IMX_PIN_REG(MX35_PAD_LD7, 0x630, 0x1cc, 0, 0x0, 0), /* MX35_PAD_LD7__IPU_DISPB_DAT_7 */
+       [441] = IMX_PIN_REG(MX35_PAD_LD7, 0x630, 0x1cc, 5, 0x8dc, 0), /* MX35_PAD_LD7__GPIO2_7 */
+       [442] = IMX_PIN_REG(MX35_PAD_LD7, 0x630, 0x1cc, 6, 0x0, 0), /* MX35_PAD_LD7__SDMA_SDMA_DEBUG_PC_7 */
+       [443] = IMX_PIN_REG(MX35_PAD_LD8, 0x634, 0x1d0, 0, 0x0, 0), /* MX35_PAD_LD8__IPU_DISPB_DAT_8 */
+       [444] = IMX_PIN_REG(MX35_PAD_LD8, 0x634, 0x1d0, 5, 0x8e0, 0), /* MX35_PAD_LD8__GPIO2_8 */
+       [445] = IMX_PIN_REG(MX35_PAD_LD8, 0x634, 0x1d0, 6, 0x0, 0), /* MX35_PAD_LD8__SDMA_SDMA_DEBUG_PC_8 */
+       [446] = IMX_PIN_REG(MX35_PAD_LD9, 0x638, 0x1d4, 0, 0x0, 0), /* MX35_PAD_LD9__IPU_DISPB_DAT_9 */
+       [447] = IMX_PIN_REG(MX35_PAD_LD9, 0x638, 0x1d4, 5, 0x8e4, 0), /* MX35_PAD_LD9__GPIO2_9 */
+       [448] = IMX_PIN_REG(MX35_PAD_LD9, 0x638, 0x1d4, 6, 0x0, 0), /* MX35_PAD_LD9__SDMA_SDMA_DEBUG_PC_9 */
+       [449] = IMX_PIN_REG(MX35_PAD_LD10, 0x63c, 0x1d8, 0, 0x0, 0), /* MX35_PAD_LD10__IPU_DISPB_DAT_10 */
+       [450] = IMX_PIN_REG(MX35_PAD_LD10, 0x63c, 0x1d8, 5, 0x86c, 0), /* MX35_PAD_LD10__GPIO2_10 */
+       [451] = IMX_PIN_REG(MX35_PAD_LD10, 0x63c, 0x1d8, 6, 0x0, 0), /* MX35_PAD_LD10__SDMA_SDMA_DEBUG_PC_10 */
+       [452] = IMX_PIN_REG(MX35_PAD_LD11, 0x640, 0x1dc, 0, 0x0, 0), /* MX35_PAD_LD11__IPU_DISPB_DAT_11 */
+       [453] = IMX_PIN_REG(MX35_PAD_LD11, 0x640, 0x1dc, 5, 0x870, 0), /* MX35_PAD_LD11__GPIO2_11 */
+       [454] = IMX_PIN_REG(MX35_PAD_LD11, 0x640, 0x1dc, 6, 0x0, 0), /* MX35_PAD_LD11__SDMA_SDMA_DEBUG_PC_11 */
+       [455] = IMX_PIN_REG(MX35_PAD_LD11, 0x640, 0x1dc, 7, 0x0, 0), /* MX35_PAD_LD11__ARM11P_TOP_TRACE_4 */
+       [456] = IMX_PIN_REG(MX35_PAD_LD12, 0x644, 0x1e0, 0, 0x0, 0), /* MX35_PAD_LD12__IPU_DISPB_DAT_12 */
+       [457] = IMX_PIN_REG(MX35_PAD_LD12, 0x644, 0x1e0, 5, 0x874, 0), /* MX35_PAD_LD12__GPIO2_12 */
+       [458] = IMX_PIN_REG(MX35_PAD_LD12, 0x644, 0x1e0, 6, 0x0, 0), /* MX35_PAD_LD12__SDMA_SDMA_DEBUG_PC_12 */
+       [459] = IMX_PIN_REG(MX35_PAD_LD12, 0x644, 0x1e0, 7, 0x0, 0), /* MX35_PAD_LD12__ARM11P_TOP_TRACE_5 */
+       [460] = IMX_PIN_REG(MX35_PAD_LD13, 0x648, 0x1e4, 0, 0x0, 0), /* MX35_PAD_LD13__IPU_DISPB_DAT_13 */
+       [461] = IMX_PIN_REG(MX35_PAD_LD13, 0x648, 0x1e4, 5, 0x878, 0), /* MX35_PAD_LD13__GPIO2_13 */
+       [462] = IMX_PIN_REG(MX35_PAD_LD13, 0x648, 0x1e4, 6, 0x0, 0), /* MX35_PAD_LD13__SDMA_SDMA_DEBUG_PC_13 */
+       [463] = IMX_PIN_REG(MX35_PAD_LD13, 0x648, 0x1e4, 7, 0x0, 0), /* MX35_PAD_LD13__ARM11P_TOP_TRACE_6 */
+       [464] = IMX_PIN_REG(MX35_PAD_LD14, 0x64c, 0x1e8, 0, 0x0, 0), /* MX35_PAD_LD14__IPU_DISPB_DAT_14 */
+       [465] = IMX_PIN_REG(MX35_PAD_LD14, 0x64c, 0x1e8, 5, 0x87c, 0), /* MX35_PAD_LD14__GPIO2_14 */
+       [466] = IMX_PIN_REG(MX35_PAD_LD14, 0x64c, 0x1e8, 6, 0x0, 0), /* MX35_PAD_LD14__SDMA_SDMA_DEBUG_EVENT_CHANNEL_0 */
+       [467] = IMX_PIN_REG(MX35_PAD_LD14, 0x64c, 0x1e8, 7, 0x0, 0), /* MX35_PAD_LD14__ARM11P_TOP_TRACE_7 */
+       [468] = IMX_PIN_REG(MX35_PAD_LD15, 0x650, 0x1ec, 0, 0x0, 0), /* MX35_PAD_LD15__IPU_DISPB_DAT_15 */
+       [469] = IMX_PIN_REG(MX35_PAD_LD15, 0x650, 0x1ec, 5, 0x880, 0), /* MX35_PAD_LD15__GPIO2_15 */
+       [470] = IMX_PIN_REG(MX35_PAD_LD15, 0x650, 0x1ec, 6, 0x0, 0), /* MX35_PAD_LD15__SDMA_SDMA_DEBUG_EVENT_CHANNEL_1 */
+       [471] = IMX_PIN_REG(MX35_PAD_LD15, 0x650, 0x1ec, 7, 0x0, 0), /* MX35_PAD_LD15__ARM11P_TOP_TRACE_8 */
+       [472] = IMX_PIN_REG(MX35_PAD_LD16, 0x654, 0x1f0, 0, 0x0, 0), /* MX35_PAD_LD16__IPU_DISPB_DAT_16 */
+       [473] = IMX_PIN_REG(MX35_PAD_LD16, 0x654, 0x1f0, 2, 0x928, 0), /* MX35_PAD_LD16__IPU_DISPB_D12_VSYNC */
+       [474] = IMX_PIN_REG(MX35_PAD_LD16, 0x654, 0x1f0, 5, 0x884, 0), /* MX35_PAD_LD16__GPIO2_16 */
+       [475] = IMX_PIN_REG(MX35_PAD_LD16, 0x654, 0x1f0, 6, 0x0, 0), /* MX35_PAD_LD16__SDMA_SDMA_DEBUG_EVENT_CHANNEL_2 */
+       [476] = IMX_PIN_REG(MX35_PAD_LD16, 0x654, 0x1f0, 7, 0x0, 0), /* MX35_PAD_LD16__ARM11P_TOP_TRACE_9 */
+       [477] = IMX_PIN_REG(MX35_PAD_LD17, 0x658, 0x1f4, 0, 0x0, 0), /* MX35_PAD_LD17__IPU_DISPB_DAT_17 */
+       [478] = IMX_PIN_REG(MX35_PAD_LD17, 0x658, 0x1f4, 2, 0x0, 0), /* MX35_PAD_LD17__IPU_DISPB_CS2 */
+       [479] = IMX_PIN_REG(MX35_PAD_LD17, 0x658, 0x1f4, 5, 0x888, 0), /* MX35_PAD_LD17__GPIO2_17 */
+       [480] = IMX_PIN_REG(MX35_PAD_LD17, 0x658, 0x1f4, 6, 0x0, 0), /* MX35_PAD_LD17__SDMA_SDMA_DEBUG_EVENT_CHANNEL_3 */
+       [481] = IMX_PIN_REG(MX35_PAD_LD17, 0x658, 0x1f4, 7, 0x0, 0), /* MX35_PAD_LD17__ARM11P_TOP_TRACE_10 */
+       [482] = IMX_PIN_REG(MX35_PAD_LD18, 0x65c, 0x1f8, 0, 0x0, 0), /* MX35_PAD_LD18__IPU_DISPB_DAT_18 */
+       [483] = IMX_PIN_REG(MX35_PAD_LD18, 0x65c, 0x1f8, 1, 0x924, 1), /* MX35_PAD_LD18__IPU_DISPB_D0_VSYNC */
+       [484] = IMX_PIN_REG(MX35_PAD_LD18, 0x65c, 0x1f8, 2, 0x928, 1), /* MX35_PAD_LD18__IPU_DISPB_D12_VSYNC */
+       [485] = IMX_PIN_REG(MX35_PAD_LD18, 0x65c, 0x1f8, 3, 0x818, 0), /* MX35_PAD_LD18__ESDHC3_CMD */
+       [486] = IMX_PIN_REG(MX35_PAD_LD18, 0x65c, 0x1f8, 4, 0x9b0, 0), /* MX35_PAD_LD18__USB_TOP_USBOTG_DATA_3 */
+       [487] = IMX_PIN_REG(MX35_PAD_LD18, 0x65c, 0x1f8, 5, 0x0, 0), /* MX35_PAD_LD18__GPIO3_24 */
+       [488] = IMX_PIN_REG(MX35_PAD_LD18, 0x65c, 0x1f8, 6, 0x0, 0), /* MX35_PAD_LD18__SDMA_SDMA_DEBUG_EVENT_CHANNEL_4 */
+       [489] = IMX_PIN_REG(MX35_PAD_LD18, 0x65c, 0x1f8, 7, 0x0, 0), /* MX35_PAD_LD18__ARM11P_TOP_TRACE_11 */
+       [490] = IMX_PIN_REG(MX35_PAD_LD19, 0x660, 0x1fc, 0, 0x0, 0), /* MX35_PAD_LD19__IPU_DISPB_DAT_19 */
+       [491] = IMX_PIN_REG(MX35_PAD_LD19, 0x660, 0x1fc, 1, 0x0, 0), /* MX35_PAD_LD19__IPU_DISPB_BCLK */
+       [492] = IMX_PIN_REG(MX35_PAD_LD19, 0x660, 0x1fc, 2, 0x0, 0), /* MX35_PAD_LD19__IPU_DISPB_CS1 */
+       [493] = IMX_PIN_REG(MX35_PAD_LD19, 0x660, 0x1fc, 3, 0x814, 0), /* MX35_PAD_LD19__ESDHC3_CLK */
+       [494] = IMX_PIN_REG(MX35_PAD_LD19, 0x660, 0x1fc, 4, 0x9c4, 0), /* MX35_PAD_LD19__USB_TOP_USBOTG_DIR */
+       [495] = IMX_PIN_REG(MX35_PAD_LD19, 0x660, 0x1fc, 5, 0x0, 0), /* MX35_PAD_LD19__GPIO3_25 */
+       [496] = IMX_PIN_REG(MX35_PAD_LD19, 0x660, 0x1fc, 6, 0x0, 0), /* MX35_PAD_LD19__SDMA_SDMA_DEBUG_EVENT_CHANNEL_5 */
+       [497] = IMX_PIN_REG(MX35_PAD_LD19, 0x660, 0x1fc, 7, 0x0, 0), /* MX35_PAD_LD19__ARM11P_TOP_TRACE_12 */
+       [498] = IMX_PIN_REG(MX35_PAD_LD20, 0x664, 0x200, 0, 0x0, 0), /* MX35_PAD_LD20__IPU_DISPB_DAT_20 */
+       [499] = IMX_PIN_REG(MX35_PAD_LD20, 0x664, 0x200, 1, 0x0, 0), /* MX35_PAD_LD20__IPU_DISPB_CS0 */
+       [500] = IMX_PIN_REG(MX35_PAD_LD20, 0x664, 0x200, 2, 0x0, 0), /* MX35_PAD_LD20__IPU_DISPB_SD_CLK */
+       [501] = IMX_PIN_REG(MX35_PAD_LD20, 0x664, 0x200, 3, 0x81c, 0), /* MX35_PAD_LD20__ESDHC3_DAT0 */
+       [502] = IMX_PIN_REG(MX35_PAD_LD20, 0x664, 0x200, 5, 0x0, 0), /* MX35_PAD_LD20__GPIO3_26 */
+       [503] = IMX_PIN_REG(MX35_PAD_LD20, 0x664, 0x200, 6, 0x0, 0), /* MX35_PAD_LD20__SDMA_SDMA_DEBUG_CORE_STATUS_3 */
+       [504] = IMX_PIN_REG(MX35_PAD_LD20, 0x664, 0x200, 7, 0x0, 0), /* MX35_PAD_LD20__ARM11P_TOP_TRACE_13 */
+       [505] = IMX_PIN_REG(MX35_PAD_LD21, 0x668, 0x204, 0, 0x0, 0), /* MX35_PAD_LD21__IPU_DISPB_DAT_21 */
+       [506] = IMX_PIN_REG(MX35_PAD_LD21, 0x668, 0x204, 1, 0x0, 0), /* MX35_PAD_LD21__IPU_DISPB_PAR_RS */
+       [507] = IMX_PIN_REG(MX35_PAD_LD21, 0x668, 0x204, 2, 0x0, 0), /* MX35_PAD_LD21__IPU_DISPB_SER_RS */
+       [508] = IMX_PIN_REG(MX35_PAD_LD21, 0x668, 0x204, 3, 0x820, 0), /* MX35_PAD_LD21__ESDHC3_DAT1 */
+       [509] = IMX_PIN_REG(MX35_PAD_LD21, 0x668, 0x204, 4, 0x0, 0), /* MX35_PAD_LD21__USB_TOP_USBOTG_STP */
+       [510] = IMX_PIN_REG(MX35_PAD_LD21, 0x668, 0x204, 5, 0x0, 0), /* MX35_PAD_LD21__GPIO3_27 */
+       [511] = IMX_PIN_REG(MX35_PAD_LD21, 0x668, 0x204, 6, 0x0, 0), /* MX35_PAD_LD21__SDMA_DEBUG_EVENT_CHANNEL_SEL */
+       [512] = IMX_PIN_REG(MX35_PAD_LD21, 0x668, 0x204, 7, 0x0, 0), /* MX35_PAD_LD21__ARM11P_TOP_TRACE_14 */
+       [513] = IMX_PIN_REG(MX35_PAD_LD22, 0x66c, 0x208, 0, 0x0, 0), /* MX35_PAD_LD22__IPU_DISPB_DAT_22 */
+       [514] = IMX_PIN_REG(MX35_PAD_LD22, 0x66c, 0x208, 1, 0x0, 0), /* MX35_PAD_LD22__IPU_DISPB_WR */
+       [515] = IMX_PIN_REG(MX35_PAD_LD22, 0x66c, 0x208, 2, 0x92c, 0), /* MX35_PAD_LD22__IPU_DISPB_SD_D_I */
+       [516] = IMX_PIN_REG(MX35_PAD_LD22, 0x66c, 0x208, 3, 0x824, 0), /* MX35_PAD_LD22__ESDHC3_DAT2 */
+       [517] = IMX_PIN_REG(MX35_PAD_LD22, 0x66c, 0x208, 4, 0x9c8, 0), /* MX35_PAD_LD22__USB_TOP_USBOTG_NXT */
+       [518] = IMX_PIN_REG(MX35_PAD_LD22, 0x66c, 0x208, 5, 0x0, 0), /* MX35_PAD_LD22__GPIO3_28 */
+       [519] = IMX_PIN_REG(MX35_PAD_LD22, 0x66c, 0x208, 6, 0x0, 0), /* MX35_PAD_LD22__SDMA_DEBUG_BUS_ERROR */
+       [520] = IMX_PIN_REG(MX35_PAD_LD22, 0x66c, 0x208, 7, 0x0, 0), /* MX35_PAD_LD22__ARM11P_TOP_TRCTL */
+       [521] = IMX_PIN_REG(MX35_PAD_LD23, 0x670, 0x20c, 0, 0x0, 0), /* MX35_PAD_LD23__IPU_DISPB_DAT_23 */
+       [522] = IMX_PIN_REG(MX35_PAD_LD23, 0x670, 0x20c, 1, 0x0, 0), /* MX35_PAD_LD23__IPU_DISPB_RD */
+       [523] = IMX_PIN_REG(MX35_PAD_LD23, 0x670, 0x20c, 2, 0x92c, 1), /* MX35_PAD_LD23__IPU_DISPB_SD_D_IO */
+       [524] = IMX_PIN_REG(MX35_PAD_LD23, 0x670, 0x20c, 3, 0x828, 0), /* MX35_PAD_LD23__ESDHC3_DAT3 */
+       [525] = IMX_PIN_REG(MX35_PAD_LD23, 0x670, 0x20c, 4, 0x9c0, 0), /* MX35_PAD_LD23__USB_TOP_USBOTG_DATA_7 */
+       [526] = IMX_PIN_REG(MX35_PAD_LD23, 0x670, 0x20c, 5, 0x0, 0), /* MX35_PAD_LD23__GPIO3_29 */
+       [527] = IMX_PIN_REG(MX35_PAD_LD23, 0x670, 0x20c, 6, 0x0, 0), /* MX35_PAD_LD23__SDMA_DEBUG_MATCHED_DMBUS */
+       [528] = IMX_PIN_REG(MX35_PAD_LD23, 0x670, 0x20c, 7, 0x0, 0), /* MX35_PAD_LD23__ARM11P_TOP_TRCLK */
+       [529] = IMX_PIN_REG(MX35_PAD_D3_HSYNC, 0x674, 0x210, 0, 0x0, 0), /* MX35_PAD_D3_HSYNC__IPU_DISPB_D3_HSYNC */
+       [530] = IMX_PIN_REG(MX35_PAD_D3_HSYNC, 0x674, 0x210, 2, 0x92c, 2), /* MX35_PAD_D3_HSYNC__IPU_DISPB_SD_D_IO */
+       [531] = IMX_PIN_REG(MX35_PAD_D3_HSYNC, 0x674, 0x210, 5, 0x0, 0), /* MX35_PAD_D3_HSYNC__GPIO3_30 */
+       [532] = IMX_PIN_REG(MX35_PAD_D3_HSYNC, 0x674, 0x210, 6, 0x0, 0), /* MX35_PAD_D3_HSYNC__SDMA_DEBUG_RTBUFFER_WRITE */
+       [533] = IMX_PIN_REG(MX35_PAD_D3_HSYNC, 0x674, 0x210, 7, 0x0, 0), /* MX35_PAD_D3_HSYNC__ARM11P_TOP_TRACE_15 */
+       [534] = IMX_PIN_REG(MX35_PAD_D3_FPSHIFT, 0x678, 0x214, 0, 0x0, 0), /* MX35_PAD_D3_FPSHIFT__IPU_DISPB_D3_CLK */
+       [535] = IMX_PIN_REG(MX35_PAD_D3_FPSHIFT, 0x678, 0x214, 2, 0x0, 0), /* MX35_PAD_D3_FPSHIFT__IPU_DISPB_SD_CLK */
+       [536] = IMX_PIN_REG(MX35_PAD_D3_FPSHIFT, 0x678, 0x214, 5, 0x0, 0), /* MX35_PAD_D3_FPSHIFT__GPIO3_31 */
+       [537] = IMX_PIN_REG(MX35_PAD_D3_FPSHIFT, 0x678, 0x214, 6, 0x0, 0), /* MX35_PAD_D3_FPSHIFT__SDMA_SDMA_DEBUG_CORE_STATUS_0 */
+       [538] = IMX_PIN_REG(MX35_PAD_D3_FPSHIFT, 0x678, 0x214, 7, 0x0, 0), /* MX35_PAD_D3_FPSHIFT__ARM11P_TOP_TRACE_16 */
+       [539] = IMX_PIN_REG(MX35_PAD_D3_DRDY, 0x67c, 0x218, 0, 0x0, 0), /* MX35_PAD_D3_DRDY__IPU_DISPB_D3_DRDY */
+       [540] = IMX_PIN_REG(MX35_PAD_D3_DRDY, 0x67c, 0x218, 2, 0x0, 0), /* MX35_PAD_D3_DRDY__IPU_DISPB_SD_D_O */
+       [541] = IMX_PIN_REG(MX35_PAD_D3_DRDY, 0x67c, 0x218, 5, 0x82c, 2), /* MX35_PAD_D3_DRDY__GPIO1_0 */
+       [542] = IMX_PIN_REG(MX35_PAD_D3_DRDY, 0x67c, 0x218, 6, 0x0, 0), /* MX35_PAD_D3_DRDY__SDMA_SDMA_DEBUG_CORE_STATUS_1 */
+       [543] = IMX_PIN_REG(MX35_PAD_D3_DRDY, 0x67c, 0x218, 7, 0x0, 0), /* MX35_PAD_D3_DRDY__ARM11P_TOP_TRACE_17 */
+       [544] = IMX_PIN_REG(MX35_PAD_CONTRAST, 0x680, 0x21c, 0, 0x0, 0), /* MX35_PAD_CONTRAST__IPU_DISPB_CONTR */
+       [545] = IMX_PIN_REG(MX35_PAD_CONTRAST, 0x680, 0x21c, 5, 0x838, 2), /* MX35_PAD_CONTRAST__GPIO1_1 */
+       [546] = IMX_PIN_REG(MX35_PAD_CONTRAST, 0x680, 0x21c, 6, 0x0, 0), /* MX35_PAD_CONTRAST__SDMA_SDMA_DEBUG_CORE_STATUS_2 */
+       [547] = IMX_PIN_REG(MX35_PAD_CONTRAST, 0x680, 0x21c, 7, 0x0, 0), /* MX35_PAD_CONTRAST__ARM11P_TOP_TRACE_18 */
+       [548] = IMX_PIN_REG(MX35_PAD_D3_VSYNC, 0x684, 0x220, 0, 0x0, 0), /* MX35_PAD_D3_VSYNC__IPU_DISPB_D3_VSYNC */
+       [549] = IMX_PIN_REG(MX35_PAD_D3_VSYNC, 0x684, 0x220, 2, 0x0, 0), /* MX35_PAD_D3_VSYNC__IPU_DISPB_CS1 */
+       [550] = IMX_PIN_REG(MX35_PAD_D3_VSYNC, 0x684, 0x220, 5, 0x848, 1), /* MX35_PAD_D3_VSYNC__GPIO1_2 */
+       [551] = IMX_PIN_REG(MX35_PAD_D3_VSYNC, 0x684, 0x220, 6, 0x0, 0), /* MX35_PAD_D3_VSYNC__SDMA_DEBUG_YIELD */
+       [552] = IMX_PIN_REG(MX35_PAD_D3_VSYNC, 0x684, 0x220, 7, 0x0, 0), /* MX35_PAD_D3_VSYNC__ARM11P_TOP_TRACE_19 */
+       [553] = IMX_PIN_REG(MX35_PAD_D3_REV, 0x688, 0x224, 0, 0x0, 0), /* MX35_PAD_D3_REV__IPU_DISPB_D3_REV */
+       [554] = IMX_PIN_REG(MX35_PAD_D3_REV, 0x688, 0x224, 2, 0x0, 0), /* MX35_PAD_D3_REV__IPU_DISPB_SER_RS */
+       [555] = IMX_PIN_REG(MX35_PAD_D3_REV, 0x688, 0x224, 5, 0x84c, 1), /* MX35_PAD_D3_REV__GPIO1_3 */
+       [556] = IMX_PIN_REG(MX35_PAD_D3_REV, 0x688, 0x224, 6, 0x0, 0), /* MX35_PAD_D3_REV__SDMA_DEBUG_BUS_RWB */
+       [557] = IMX_PIN_REG(MX35_PAD_D3_REV, 0x688, 0x224, 7, 0x0, 0), /* MX35_PAD_D3_REV__ARM11P_TOP_TRACE_20 */
+       [558] = IMX_PIN_REG(MX35_PAD_D3_CLS, 0x68c, 0x228, 0, 0x0, 0), /* MX35_PAD_D3_CLS__IPU_DISPB_D3_CLS */
+       [559] = IMX_PIN_REG(MX35_PAD_D3_CLS, 0x68c, 0x228, 2, 0x0, 0), /* MX35_PAD_D3_CLS__IPU_DISPB_CS2 */
+       [560] = IMX_PIN_REG(MX35_PAD_D3_CLS, 0x68c, 0x228, 5, 0x850, 2), /* MX35_PAD_D3_CLS__GPIO1_4 */
+       [561] = IMX_PIN_REG(MX35_PAD_D3_CLS, 0x68c, 0x228, 6, 0x0, 0), /* MX35_PAD_D3_CLS__SDMA_DEBUG_BUS_DEVICE_0 */
+       [562] = IMX_PIN_REG(MX35_PAD_D3_CLS, 0x68c, 0x228, 7, 0x0, 0), /* MX35_PAD_D3_CLS__ARM11P_TOP_TRACE_21 */
+       [563] = IMX_PIN_REG(MX35_PAD_D3_SPL, 0x690, 0x22c, 0, 0x0, 0), /* MX35_PAD_D3_SPL__IPU_DISPB_D3_SPL */
+       [564] = IMX_PIN_REG(MX35_PAD_D3_SPL, 0x690, 0x22c, 2, 0x928, 2), /* MX35_PAD_D3_SPL__IPU_DISPB_D12_VSYNC */
+       [565] = IMX_PIN_REG(MX35_PAD_D3_SPL, 0x690, 0x22c, 5, 0x854, 2), /* MX35_PAD_D3_SPL__GPIO1_5 */
+       [566] = IMX_PIN_REG(MX35_PAD_D3_SPL, 0x690, 0x22c, 6, 0x0, 0), /* MX35_PAD_D3_SPL__SDMA_DEBUG_BUS_DEVICE_1 */
+       [567] = IMX_PIN_REG(MX35_PAD_D3_SPL, 0x690, 0x22c, 7, 0x0, 0), /* MX35_PAD_D3_SPL__ARM11P_TOP_TRACE_22 */
+       [568] = IMX_PIN_REG(MX35_PAD_SD1_CMD, 0x694, 0x230, 0, 0x0, 0), /* MX35_PAD_SD1_CMD__ESDHC1_CMD */
+       [569] = IMX_PIN_REG(MX35_PAD_SD1_CMD, 0x694, 0x230, 1, 0x0, 0), /* MX35_PAD_SD1_CMD__MSHC_SCLK */
+       [570] = IMX_PIN_REG(MX35_PAD_SD1_CMD, 0x694, 0x230, 3, 0x924, 2), /* MX35_PAD_SD1_CMD__IPU_DISPB_D0_VSYNC */
+       [571] = IMX_PIN_REG(MX35_PAD_SD1_CMD, 0x694, 0x230, 4, 0x9b4, 0), /* MX35_PAD_SD1_CMD__USB_TOP_USBOTG_DATA_4 */
+       [572] = IMX_PIN_REG(MX35_PAD_SD1_CMD, 0x694, 0x230, 5, 0x858, 2), /* MX35_PAD_SD1_CMD__GPIO1_6 */
+       [573] = IMX_PIN_REG(MX35_PAD_SD1_CMD, 0x694, 0x230, 7, 0x0, 0), /* MX35_PAD_SD1_CMD__ARM11P_TOP_TRCTL */
+       [574] = IMX_PIN_REG(MX35_PAD_SD1_CLK, 0x698, 0x234, 0, 0x0, 0), /* MX35_PAD_SD1_CLK__ESDHC1_CLK */
+       [575] = IMX_PIN_REG(MX35_PAD_SD1_CLK, 0x698, 0x234, 1, 0x0, 0), /* MX35_PAD_SD1_CLK__MSHC_BS */
+       [576] = IMX_PIN_REG(MX35_PAD_SD1_CLK, 0x698, 0x234, 3, 0x0, 0), /* MX35_PAD_SD1_CLK__IPU_DISPB_BCLK */
+       [577] = IMX_PIN_REG(MX35_PAD_SD1_CLK, 0x698, 0x234, 4, 0x9b8, 0), /* MX35_PAD_SD1_CLK__USB_TOP_USBOTG_DATA_5 */
+       [578] = IMX_PIN_REG(MX35_PAD_SD1_CLK, 0x698, 0x234, 5, 0x85c, 2), /* MX35_PAD_SD1_CLK__GPIO1_7 */
+       [579] = IMX_PIN_REG(MX35_PAD_SD1_CLK, 0x698, 0x234, 7, 0x0, 0), /* MX35_PAD_SD1_CLK__ARM11P_TOP_TRCLK */
+       [580] = IMX_PIN_REG(MX35_PAD_SD1_DATA0, 0x69c, 0x238, 0, 0x0, 0), /* MX35_PAD_SD1_DATA0__ESDHC1_DAT0 */
+       [581] = IMX_PIN_REG(MX35_PAD_SD1_DATA0, 0x69c, 0x238, 1, 0x0, 0), /* MX35_PAD_SD1_DATA0__MSHC_DATA_0 */
+       [582] = IMX_PIN_REG(MX35_PAD_SD1_DATA0, 0x69c, 0x238, 3, 0x0, 0), /* MX35_PAD_SD1_DATA0__IPU_DISPB_CS0 */
+       [583] = IMX_PIN_REG(MX35_PAD_SD1_DATA0, 0x69c, 0x238, 4, 0x9bc, 0), /* MX35_PAD_SD1_DATA0__USB_TOP_USBOTG_DATA_6 */
+       [584] = IMX_PIN_REG(MX35_PAD_SD1_DATA0, 0x69c, 0x238, 5, 0x860, 2), /* MX35_PAD_SD1_DATA0__GPIO1_8 */
+       [585] = IMX_PIN_REG(MX35_PAD_SD1_DATA0, 0x69c, 0x238, 7, 0x0, 0), /* MX35_PAD_SD1_DATA0__ARM11P_TOP_TRACE_23 */
+       [586] = IMX_PIN_REG(MX35_PAD_SD1_DATA1, 0x6a0, 0x23c, 0, 0x0, 0), /* MX35_PAD_SD1_DATA1__ESDHC1_DAT1 */
+       [587] = IMX_PIN_REG(MX35_PAD_SD1_DATA1, 0x6a0, 0x23c, 1, 0x0, 0), /* MX35_PAD_SD1_DATA1__MSHC_DATA_1 */
+       [588] = IMX_PIN_REG(MX35_PAD_SD1_DATA1, 0x6a0, 0x23c, 3, 0x0, 0), /* MX35_PAD_SD1_DATA1__IPU_DISPB_PAR_RS */
+       [589] = IMX_PIN_REG(MX35_PAD_SD1_DATA1, 0x6a0, 0x23c, 4, 0x9a4, 0), /* MX35_PAD_SD1_DATA1__USB_TOP_USBOTG_DATA_0 */
+       [590] = IMX_PIN_REG(MX35_PAD_SD1_DATA1, 0x6a0, 0x23c, 5, 0x864, 1), /* MX35_PAD_SD1_DATA1__GPIO1_9 */
+       [591] = IMX_PIN_REG(MX35_PAD_SD1_DATA1, 0x6a0, 0x23c, 7, 0x0, 0), /* MX35_PAD_SD1_DATA1__ARM11P_TOP_TRACE_24 */
+       [592] = IMX_PIN_REG(MX35_PAD_SD1_DATA2, 0x6a4, 0x240, 0, 0x0, 0), /* MX35_PAD_SD1_DATA2__ESDHC1_DAT2 */
+       [593] = IMX_PIN_REG(MX35_PAD_SD1_DATA2, 0x6a4, 0x240, 1, 0x0, 0), /* MX35_PAD_SD1_DATA2__MSHC_DATA_2 */
+       [594] = IMX_PIN_REG(MX35_PAD_SD1_DATA2, 0x6a4, 0x240, 3, 0x0, 0), /* MX35_PAD_SD1_DATA2__IPU_DISPB_WR */
+       [595] = IMX_PIN_REG(MX35_PAD_SD1_DATA2, 0x6a4, 0x240, 4, 0x9a8, 0), /* MX35_PAD_SD1_DATA2__USB_TOP_USBOTG_DATA_1 */
+       [596] = IMX_PIN_REG(MX35_PAD_SD1_DATA2, 0x6a4, 0x240, 5, 0x830, 1), /* MX35_PAD_SD1_DATA2__GPIO1_10 */
+       [597] = IMX_PIN_REG(MX35_PAD_SD1_DATA2, 0x6a4, 0x240, 7, 0x0, 0), /* MX35_PAD_SD1_DATA2__ARM11P_TOP_TRACE_25 */
+       [598] = IMX_PIN_REG(MX35_PAD_SD1_DATA3, 0x6a8, 0x244, 0, 0x0, 0), /* MX35_PAD_SD1_DATA3__ESDHC1_DAT3 */
+       [599] = IMX_PIN_REG(MX35_PAD_SD1_DATA3, 0x6a8, 0x244, 1, 0x0, 0), /* MX35_PAD_SD1_DATA3__MSHC_DATA_3 */
+       [600] = IMX_PIN_REG(MX35_PAD_SD1_DATA3, 0x6a8, 0x244, 3, 0x0, 0), /* MX35_PAD_SD1_DATA3__IPU_DISPB_RD */
+       [601] = IMX_PIN_REG(MX35_PAD_SD1_DATA3, 0x6a8, 0x244, 4, 0x9ac, 0), /* MX35_PAD_SD1_DATA3__USB_TOP_USBOTG_DATA_2 */
+       [602] = IMX_PIN_REG(MX35_PAD_SD1_DATA3, 0x6a8, 0x244, 5, 0x834, 1), /* MX35_PAD_SD1_DATA3__GPIO1_11 */
+       [603] = IMX_PIN_REG(MX35_PAD_SD1_DATA3, 0x6a8, 0x244, 7, 0x0, 0), /* MX35_PAD_SD1_DATA3__ARM11P_TOP_TRACE_26 */
+       [604] = IMX_PIN_REG(MX35_PAD_SD2_CMD, 0x6ac, 0x248, 0, 0x0, 0), /* MX35_PAD_SD2_CMD__ESDHC2_CMD */
+       [605] = IMX_PIN_REG(MX35_PAD_SD2_CMD, 0x6ac, 0x248, 1, 0x91c, 2), /* MX35_PAD_SD2_CMD__I2C3_SCL */
+       [606] = IMX_PIN_REG(MX35_PAD_SD2_CMD, 0x6ac, 0x248, 2, 0x804, 0), /* MX35_PAD_SD2_CMD__ESDHC1_DAT4 */
+       [607] = IMX_PIN_REG(MX35_PAD_SD2_CMD, 0x6ac, 0x248, 3, 0x938, 2), /* MX35_PAD_SD2_CMD__IPU_CSI_D_2 */
+       [608] = IMX_PIN_REG(MX35_PAD_SD2_CMD, 0x6ac, 0x248, 4, 0x9dc, 0), /* MX35_PAD_SD2_CMD__USB_TOP_USBH2_DATA_4 */
+       [609] = IMX_PIN_REG(MX35_PAD_SD2_CMD, 0x6ac, 0x248, 5, 0x868, 2), /* MX35_PAD_SD2_CMD__GPIO2_0 */
+       [610] = IMX_PIN_REG(MX35_PAD_SD2_CMD, 0x6ac, 0x248, 6, 0x0, 0), /* MX35_PAD_SD2_CMD__SPDIF_SPDIF_OUT1 */
+       [611] = IMX_PIN_REG(MX35_PAD_SD2_CMD, 0x6ac, 0x248, 7, 0x928, 3), /* MX35_PAD_SD2_CMD__IPU_DISPB_D12_VSYNC */
+       [612] = IMX_PIN_REG(MX35_PAD_SD2_CLK, 0x6b0, 0x24c, 0, 0x0, 0), /* MX35_PAD_SD2_CLK__ESDHC2_CLK */
+       [613] = IMX_PIN_REG(MX35_PAD_SD2_CLK, 0x6b0, 0x24c, 1, 0x920, 2), /* MX35_PAD_SD2_CLK__I2C3_SDA */
+       [614] = IMX_PIN_REG(MX35_PAD_SD2_CLK, 0x6b0, 0x24c, 2, 0x808, 0), /* MX35_PAD_SD2_CLK__ESDHC1_DAT5 */
+       [615] = IMX_PIN_REG(MX35_PAD_SD2_CLK, 0x6b0, 0x24c, 3, 0x93c, 2), /* MX35_PAD_SD2_CLK__IPU_CSI_D_3 */
+       [616] = IMX_PIN_REG(MX35_PAD_SD2_CLK, 0x6b0, 0x24c, 4, 0x9e0, 0), /* MX35_PAD_SD2_CLK__USB_TOP_USBH2_DATA_5 */
+       [617] = IMX_PIN_REG(MX35_PAD_SD2_CLK, 0x6b0, 0x24c, 5, 0x894, 1), /* MX35_PAD_SD2_CLK__GPIO2_1 */
+       [618] = IMX_PIN_REG(MX35_PAD_SD2_CLK, 0x6b0, 0x24c, 6, 0x998, 2), /* MX35_PAD_SD2_CLK__SPDIF_SPDIF_IN1 */
+       [619] = IMX_PIN_REG(MX35_PAD_SD2_CLK, 0x6b0, 0x24c, 7, 0x0, 0), /* MX35_PAD_SD2_CLK__IPU_DISPB_CS2 */
+       [620] = IMX_PIN_REG(MX35_PAD_SD2_DATA0, 0x6b4, 0x250, 0, 0x0, 0), /* MX35_PAD_SD2_DATA0__ESDHC2_DAT0 */
+       [621] = IMX_PIN_REG(MX35_PAD_SD2_DATA0, 0x6b4, 0x250, 1, 0x9a0, 1), /* MX35_PAD_SD2_DATA0__UART3_RXD_MUX */
+       [622] = IMX_PIN_REG(MX35_PAD_SD2_DATA0, 0x6b4, 0x250, 2, 0x80c, 0), /* MX35_PAD_SD2_DATA0__ESDHC1_DAT6 */
+       [623] = IMX_PIN_REG(MX35_PAD_SD2_DATA0, 0x6b4, 0x250, 3, 0x940, 1), /* MX35_PAD_SD2_DATA0__IPU_CSI_D_4 */
+       [624] = IMX_PIN_REG(MX35_PAD_SD2_DATA0, 0x6b4, 0x250, 4, 0x9e4, 0), /* MX35_PAD_SD2_DATA0__USB_TOP_USBH2_DATA_6 */
+       [625] = IMX_PIN_REG(MX35_PAD_SD2_DATA0, 0x6b4, 0x250, 5, 0x8c0, 1), /* MX35_PAD_SD2_DATA0__GPIO2_2 */
+       [626] = IMX_PIN_REG(MX35_PAD_SD2_DATA0, 0x6b4, 0x250, 6, 0x994, 3), /* MX35_PAD_SD2_DATA0__SPDIF_SPDIF_EXTCLK */
+       [627] = IMX_PIN_REG(MX35_PAD_SD2_DATA1, 0x6b8, 0x254, 0, 0x0, 0), /* MX35_PAD_SD2_DATA1__ESDHC2_DAT1 */
+       [628] = IMX_PIN_REG(MX35_PAD_SD2_DATA1, 0x6b8, 0x254, 1, 0x0, 0), /* MX35_PAD_SD2_DATA1__UART3_TXD_MUX */
+       [629] = IMX_PIN_REG(MX35_PAD_SD2_DATA1, 0x6b8, 0x254, 2, 0x810, 0), /* MX35_PAD_SD2_DATA1__ESDHC1_DAT7 */
+       [630] = IMX_PIN_REG(MX35_PAD_SD2_DATA1, 0x6b8, 0x254, 3, 0x944, 1), /* MX35_PAD_SD2_DATA1__IPU_CSI_D_5 */
+       [631] = IMX_PIN_REG(MX35_PAD_SD2_DATA1, 0x6b8, 0x254, 4, 0x9cc, 0), /* MX35_PAD_SD2_DATA1__USB_TOP_USBH2_DATA_0 */
+       [632] = IMX_PIN_REG(MX35_PAD_SD2_DATA1, 0x6b8, 0x254, 5, 0x8cc, 1), /* MX35_PAD_SD2_DATA1__GPIO2_3 */
+       [633] = IMX_PIN_REG(MX35_PAD_SD2_DATA2, 0x6bc, 0x258, 0, 0x0, 0), /* MX35_PAD_SD2_DATA2__ESDHC2_DAT2 */
+       [634] = IMX_PIN_REG(MX35_PAD_SD2_DATA2, 0x6bc, 0x258, 1, 0x99c, 0), /* MX35_PAD_SD2_DATA2__UART3_RTS */
+       [635] = IMX_PIN_REG(MX35_PAD_SD2_DATA2, 0x6bc, 0x258, 2, 0x7c8, 1), /* MX35_PAD_SD2_DATA2__CAN1_RXCAN */
+       [636] = IMX_PIN_REG(MX35_PAD_SD2_DATA2, 0x6bc, 0x258, 3, 0x948, 1), /* MX35_PAD_SD2_DATA2__IPU_CSI_D_6 */
+       [637] = IMX_PIN_REG(MX35_PAD_SD2_DATA2, 0x6bc, 0x258, 4, 0x9d0, 0), /* MX35_PAD_SD2_DATA2__USB_TOP_USBH2_DATA_1 */
+       [638] = IMX_PIN_REG(MX35_PAD_SD2_DATA2, 0x6bc, 0x258, 5, 0x8d0, 1), /* MX35_PAD_SD2_DATA2__GPIO2_4 */
+       [639] = IMX_PIN_REG(MX35_PAD_SD2_DATA3, 0x6c0, 0x25c, 0, 0x0, 0), /* MX35_PAD_SD2_DATA3__ESDHC2_DAT3 */
+       [640] = IMX_PIN_REG(MX35_PAD_SD2_DATA3, 0x6c0, 0x25c, 1, 0x0, 0), /* MX35_PAD_SD2_DATA3__UART3_CTS */
+       [641] = IMX_PIN_REG(MX35_PAD_SD2_DATA3, 0x6c0, 0x25c, 2, 0x0, 0), /* MX35_PAD_SD2_DATA3__CAN1_TXCAN */
+       [642] = IMX_PIN_REG(MX35_PAD_SD2_DATA3, 0x6c0, 0x25c, 3, 0x94c, 1), /* MX35_PAD_SD2_DATA3__IPU_CSI_D_7 */
+       [643] = IMX_PIN_REG(MX35_PAD_SD2_DATA3, 0x6c0, 0x25c, 4, 0x9d4, 0), /* MX35_PAD_SD2_DATA3__USB_TOP_USBH2_DATA_2 */
+       [644] = IMX_PIN_REG(MX35_PAD_SD2_DATA3, 0x6c0, 0x25c, 5, 0x8d4, 1), /* MX35_PAD_SD2_DATA3__GPIO2_5 */
+       [645] = IMX_PIN_REG(MX35_PAD_ATA_CS0, 0x6c4, 0x260, 0, 0x0, 0), /* MX35_PAD_ATA_CS0__ATA_CS0 */
+       [646] = IMX_PIN_REG(MX35_PAD_ATA_CS0, 0x6c4, 0x260, 1, 0x7dc, 1), /* MX35_PAD_ATA_CS0__CSPI1_SS3 */
+       [647] = IMX_PIN_REG(MX35_PAD_ATA_CS0, 0x6c4, 0x260, 3, 0x0, 0), /* MX35_PAD_ATA_CS0__IPU_DISPB_CS1 */
+       [648] = IMX_PIN_REG(MX35_PAD_ATA_CS0, 0x6c4, 0x260, 5, 0x8d8, 1), /* MX35_PAD_ATA_CS0__GPIO2_6 */
+       [649] = IMX_PIN_REG(MX35_PAD_ATA_CS0, 0x6c4, 0x260, 6, 0x0, 0), /* MX35_PAD_ATA_CS0__IPU_DIAGB_0 */
+       [650] = IMX_PIN_REG(MX35_PAD_ATA_CS0, 0x6c4, 0x260, 7, 0x0, 0), /* MX35_PAD_ATA_CS0__ARM11P_TOP_MAX1_HMASTER_0 */
+       [651] = IMX_PIN_REG(MX35_PAD_ATA_CS1, 0x6c8, 0x264, 0, 0x0, 0), /* MX35_PAD_ATA_CS1__ATA_CS1 */
+       [652] = IMX_PIN_REG(MX35_PAD_ATA_CS1, 0x6c8, 0x264, 3, 0x0, 0), /* MX35_PAD_ATA_CS1__IPU_DISPB_CS2 */
+       [653] = IMX_PIN_REG(MX35_PAD_ATA_CS1, 0x6c8, 0x264, 4, 0x7f0, 1), /* MX35_PAD_ATA_CS1__CSPI2_SS0 */
+       [654] = IMX_PIN_REG(MX35_PAD_ATA_CS1, 0x6c8, 0x264, 5, 0x8dc, 1), /* MX35_PAD_ATA_CS1__GPIO2_7 */
+       [655] = IMX_PIN_REG(MX35_PAD_ATA_CS1, 0x6c8, 0x264, 6, 0x0, 0), /* MX35_PAD_ATA_CS1__IPU_DIAGB_1 */
+       [656] = IMX_PIN_REG(MX35_PAD_ATA_CS1, 0x6c8, 0x264, 7, 0x0, 0), /* MX35_PAD_ATA_CS1__ARM11P_TOP_MAX1_HMASTER_1 */
+       [657] = IMX_PIN_REG(MX35_PAD_ATA_DIOR, 0x6cc, 0x268, 0, 0x0, 0), /* MX35_PAD_ATA_DIOR__ATA_DIOR */
+       [658] = IMX_PIN_REG(MX35_PAD_ATA_DIOR, 0x6cc, 0x268, 1, 0x81c, 1), /* MX35_PAD_ATA_DIOR__ESDHC3_DAT0 */
+       [659] = IMX_PIN_REG(MX35_PAD_ATA_DIOR, 0x6cc, 0x268, 2, 0x9c4, 1), /* MX35_PAD_ATA_DIOR__USB_TOP_USBOTG_DIR */
+       [660] = IMX_PIN_REG(MX35_PAD_ATA_DIOR, 0x6cc, 0x268, 3, 0x0, 0), /* MX35_PAD_ATA_DIOR__IPU_DISPB_BE0 */
+       [661] = IMX_PIN_REG(MX35_PAD_ATA_DIOR, 0x6cc, 0x268, 4, 0x7f4, 1), /* MX35_PAD_ATA_DIOR__CSPI2_SS1 */
+       [662] = IMX_PIN_REG(MX35_PAD_ATA_DIOR, 0x6cc, 0x268, 5, 0x8e0, 1), /* MX35_PAD_ATA_DIOR__GPIO2_8 */
+       [663] = IMX_PIN_REG(MX35_PAD_ATA_DIOR, 0x6cc, 0x268, 6, 0x0, 0), /* MX35_PAD_ATA_DIOR__IPU_DIAGB_2 */
+       [664] = IMX_PIN_REG(MX35_PAD_ATA_DIOR, 0x6cc, 0x268, 7, 0x0, 0), /* MX35_PAD_ATA_DIOR__ARM11P_TOP_MAX1_HMASTER_2 */
+       [665] = IMX_PIN_REG(MX35_PAD_ATA_DIOW, 0x6d0, 0x26c, 0, 0x0, 0), /* MX35_PAD_ATA_DIOW__ATA_DIOW */
+       [666] = IMX_PIN_REG(MX35_PAD_ATA_DIOW, 0x6d0, 0x26c, 1, 0x820, 1), /* MX35_PAD_ATA_DIOW__ESDHC3_DAT1 */
+       [667] = IMX_PIN_REG(MX35_PAD_ATA_DIOW, 0x6d0, 0x26c, 2, 0x0, 0), /* MX35_PAD_ATA_DIOW__USB_TOP_USBOTG_STP */
+       [668] = IMX_PIN_REG(MX35_PAD_ATA_DIOW, 0x6d0, 0x26c, 3, 0x0, 0), /* MX35_PAD_ATA_DIOW__IPU_DISPB_BE1 */
+       [669] = IMX_PIN_REG(MX35_PAD_ATA_DIOW, 0x6d0, 0x26c, 4, 0x7ec, 2), /* MX35_PAD_ATA_DIOW__CSPI2_MOSI */
+       [670] = IMX_PIN_REG(MX35_PAD_ATA_DIOW, 0x6d0, 0x26c, 5, 0x8e4, 1), /* MX35_PAD_ATA_DIOW__GPIO2_9 */
+       [671] = IMX_PIN_REG(MX35_PAD_ATA_DIOW, 0x6d0, 0x26c, 6, 0x0, 0), /* MX35_PAD_ATA_DIOW__IPU_DIAGB_3 */
+       [672] = IMX_PIN_REG(MX35_PAD_ATA_DIOW, 0x6d0, 0x26c, 7, 0x0, 0), /* MX35_PAD_ATA_DIOW__ARM11P_TOP_MAX1_HMASTER_3 */
+       [673] = IMX_PIN_REG(MX35_PAD_ATA_DMACK, 0x6d4, 0x270, 0, 0x0, 0), /* MX35_PAD_ATA_DMACK__ATA_DMACK */
+       [674] = IMX_PIN_REG(MX35_PAD_ATA_DMACK, 0x6d4, 0x270, 1, 0x824, 1), /* MX35_PAD_ATA_DMACK__ESDHC3_DAT2 */
+       [675] = IMX_PIN_REG(MX35_PAD_ATA_DMACK, 0x6d4, 0x270, 2, 0x9c8, 1), /* MX35_PAD_ATA_DMACK__USB_TOP_USBOTG_NXT */
+       [676] = IMX_PIN_REG(MX35_PAD_ATA_DMACK, 0x6d4, 0x270, 4, 0x7e8, 2), /* MX35_PAD_ATA_DMACK__CSPI2_MISO */
+       [677] = IMX_PIN_REG(MX35_PAD_ATA_DMACK, 0x6d4, 0x270, 5, 0x86c, 1), /* MX35_PAD_ATA_DMACK__GPIO2_10 */
+       [678] = IMX_PIN_REG(MX35_PAD_ATA_DMACK, 0x6d4, 0x270, 6, 0x0, 0), /* MX35_PAD_ATA_DMACK__IPU_DIAGB_4 */
+       [679] = IMX_PIN_REG(MX35_PAD_ATA_DMACK, 0x6d4, 0x270, 7, 0x0, 0), /* MX35_PAD_ATA_DMACK__ARM11P_TOP_MAX0_HMASTER_0 */
+       [680] = IMX_PIN_REG(MX35_PAD_ATA_RESET_B, 0x6d8, 0x274, 0, 0x0, 0), /* MX35_PAD_ATA_RESET_B__ATA_RESET_B */
+       [681] = IMX_PIN_REG(MX35_PAD_ATA_RESET_B, 0x6d8, 0x274, 1, 0x828, 1), /* MX35_PAD_ATA_RESET_B__ESDHC3_DAT3 */
+       [682] = IMX_PIN_REG(MX35_PAD_ATA_RESET_B, 0x6d8, 0x274, 2, 0x9a4, 1), /* MX35_PAD_ATA_RESET_B__USB_TOP_USBOTG_DATA_0 */
+       [683] = IMX_PIN_REG(MX35_PAD_ATA_RESET_B, 0x6d8, 0x274, 3, 0x0, 0), /* MX35_PAD_ATA_RESET_B__IPU_DISPB_SD_D_O */
+       [684] = IMX_PIN_REG(MX35_PAD_ATA_RESET_B, 0x6d8, 0x274, 4, 0x7e4, 2), /* MX35_PAD_ATA_RESET_B__CSPI2_RDY */
+       [685] = IMX_PIN_REG(MX35_PAD_ATA_RESET_B, 0x6d8, 0x274, 5, 0x870, 1), /* MX35_PAD_ATA_RESET_B__GPIO2_11 */
+       [686] = IMX_PIN_REG(MX35_PAD_ATA_RESET_B, 0x6d8, 0x274, 6, 0x0, 0), /* MX35_PAD_ATA_RESET_B__IPU_DIAGB_5 */
+       [687] = IMX_PIN_REG(MX35_PAD_ATA_RESET_B, 0x6d8, 0x274, 7, 0x0, 0), /* MX35_PAD_ATA_RESET_B__ARM11P_TOP_MAX0_HMASTER_1 */
+       [688] = IMX_PIN_REG(MX35_PAD_ATA_IORDY, 0x6dc, 0x278, 0, 0x0, 0), /* MX35_PAD_ATA_IORDY__ATA_IORDY */
+       [689] = IMX_PIN_REG(MX35_PAD_ATA_IORDY, 0x6dc, 0x278, 1, 0x0, 0), /* MX35_PAD_ATA_IORDY__ESDHC3_DAT4 */
+       [690] = IMX_PIN_REG(MX35_PAD_ATA_IORDY, 0x6dc, 0x278, 2, 0x9a8, 1), /* MX35_PAD_ATA_IORDY__USB_TOP_USBOTG_DATA_1 */
+       [691] = IMX_PIN_REG(MX35_PAD_ATA_IORDY, 0x6dc, 0x278, 3, 0x92c, 3), /* MX35_PAD_ATA_IORDY__IPU_DISPB_SD_D_IO */
+       [692] = IMX_PIN_REG(MX35_PAD_ATA_IORDY, 0x6dc, 0x278, 4, 0x0, 0), /* MX35_PAD_ATA_IORDY__ESDHC2_DAT4 */
+       [693] = IMX_PIN_REG(MX35_PAD_ATA_IORDY, 0x6dc, 0x278, 5, 0x874, 1), /* MX35_PAD_ATA_IORDY__GPIO2_12 */
+       [694] = IMX_PIN_REG(MX35_PAD_ATA_IORDY, 0x6dc, 0x278, 6, 0x0, 0), /* MX35_PAD_ATA_IORDY__IPU_DIAGB_6 */
+       [695] = IMX_PIN_REG(MX35_PAD_ATA_IORDY, 0x6dc, 0x278, 7, 0x0, 0), /* MX35_PAD_ATA_IORDY__ARM11P_TOP_MAX0_HMASTER_2 */
+       [696] = IMX_PIN_REG(MX35_PAD_ATA_DATA0, 0x6e0, 0x27c, 0, 0x0, 0), /* MX35_PAD_ATA_DATA0__ATA_DATA_0 */
+       [697] = IMX_PIN_REG(MX35_PAD_ATA_DATA0, 0x6e0, 0x27c, 1, 0x0, 0), /* MX35_PAD_ATA_DATA0__ESDHC3_DAT5 */
+       [698] = IMX_PIN_REG(MX35_PAD_ATA_DATA0, 0x6e0, 0x27c, 2, 0x9ac, 1), /* MX35_PAD_ATA_DATA0__USB_TOP_USBOTG_DATA_2 */
+       [699] = IMX_PIN_REG(MX35_PAD_ATA_DATA0, 0x6e0, 0x27c, 3, 0x928, 4), /* MX35_PAD_ATA_DATA0__IPU_DISPB_D12_VSYNC */
+       [700] = IMX_PIN_REG(MX35_PAD_ATA_DATA0, 0x6e0, 0x27c, 4, 0x0, 0), /* MX35_PAD_ATA_DATA0__ESDHC2_DAT5 */
+       [701] = IMX_PIN_REG(MX35_PAD_ATA_DATA0, 0x6e0, 0x27c, 5, 0x878, 1), /* MX35_PAD_ATA_DATA0__GPIO2_13 */
+       [702] = IMX_PIN_REG(MX35_PAD_ATA_DATA0, 0x6e0, 0x27c, 6, 0x0, 0), /* MX35_PAD_ATA_DATA0__IPU_DIAGB_7 */
+       [703] = IMX_PIN_REG(MX35_PAD_ATA_DATA0, 0x6e0, 0x27c, 7, 0x0, 0), /* MX35_PAD_ATA_DATA0__ARM11P_TOP_MAX0_HMASTER_3 */
+       [704] = IMX_PIN_REG(MX35_PAD_ATA_DATA1, 0x6e4, 0x280, 0, 0x0, 0), /* MX35_PAD_ATA_DATA1__ATA_DATA_1 */
+       [705] = IMX_PIN_REG(MX35_PAD_ATA_DATA1, 0x6e4, 0x280, 1, 0x0, 0), /* MX35_PAD_ATA_DATA1__ESDHC3_DAT6 */
+       [706] = IMX_PIN_REG(MX35_PAD_ATA_DATA1, 0x6e4, 0x280, 2, 0x9b0, 1), /* MX35_PAD_ATA_DATA1__USB_TOP_USBOTG_DATA_3 */
+       [707] = IMX_PIN_REG(MX35_PAD_ATA_DATA1, 0x6e4, 0x280, 3, 0x0, 0), /* MX35_PAD_ATA_DATA1__IPU_DISPB_SD_CLK */
+       [708] = IMX_PIN_REG(MX35_PAD_ATA_DATA1, 0x6e4, 0x280, 4, 0x0, 0), /* MX35_PAD_ATA_DATA1__ESDHC2_DAT6 */
+       [709] = IMX_PIN_REG(MX35_PAD_ATA_DATA1, 0x6e4, 0x280, 5, 0x87c, 1), /* MX35_PAD_ATA_DATA1__GPIO2_14 */
+       [710] = IMX_PIN_REG(MX35_PAD_ATA_DATA1, 0x6e4, 0x280, 6, 0x0, 0), /* MX35_PAD_ATA_DATA1__IPU_DIAGB_8 */
+       [711] = IMX_PIN_REG(MX35_PAD_ATA_DATA1, 0x6e4, 0x280, 7, 0x0, 0), /* MX35_PAD_ATA_DATA1__ARM11P_TOP_TRACE_27 */
+       [712] = IMX_PIN_REG(MX35_PAD_ATA_DATA2, 0x6e8, 0x284, 0, 0x0, 0), /* MX35_PAD_ATA_DATA2__ATA_DATA_2 */
+       [713] = IMX_PIN_REG(MX35_PAD_ATA_DATA2, 0x6e8, 0x284, 1, 0x0, 0), /* MX35_PAD_ATA_DATA2__ESDHC3_DAT7 */
+       [714] = IMX_PIN_REG(MX35_PAD_ATA_DATA2, 0x6e8, 0x284, 2, 0x9b4, 1), /* MX35_PAD_ATA_DATA2__USB_TOP_USBOTG_DATA_4 */
+       [715] = IMX_PIN_REG(MX35_PAD_ATA_DATA2, 0x6e8, 0x284, 3, 0x0, 0), /* MX35_PAD_ATA_DATA2__IPU_DISPB_SER_RS */
+       [716] = IMX_PIN_REG(MX35_PAD_ATA_DATA2, 0x6e8, 0x284, 4, 0x0, 0), /* MX35_PAD_ATA_DATA2__ESDHC2_DAT7 */
+       [717] = IMX_PIN_REG(MX35_PAD_ATA_DATA2, 0x6e8, 0x284, 5, 0x880, 1), /* MX35_PAD_ATA_DATA2__GPIO2_15 */
+       [718] = IMX_PIN_REG(MX35_PAD_ATA_DATA2, 0x6e8, 0x284, 6, 0x0, 0), /* MX35_PAD_ATA_DATA2__IPU_DIAGB_9 */
+       [719] = IMX_PIN_REG(MX35_PAD_ATA_DATA2, 0x6e8, 0x284, 7, 0x0, 0), /* MX35_PAD_ATA_DATA2__ARM11P_TOP_TRACE_28 */
+       [720] = IMX_PIN_REG(MX35_PAD_ATA_DATA3, 0x6ec, 0x288, 0, 0x0, 0), /* MX35_PAD_ATA_DATA3__ATA_DATA_3 */
+       [721] = IMX_PIN_REG(MX35_PAD_ATA_DATA3, 0x6ec, 0x288, 1, 0x814, 1), /* MX35_PAD_ATA_DATA3__ESDHC3_CLK */
+       [722] = IMX_PIN_REG(MX35_PAD_ATA_DATA3, 0x6ec, 0x288, 2, 0x9b8, 1), /* MX35_PAD_ATA_DATA3__USB_TOP_USBOTG_DATA_5 */
+       [723] = IMX_PIN_REG(MX35_PAD_ATA_DATA3, 0x6ec, 0x288, 4, 0x7e0, 2), /* MX35_PAD_ATA_DATA3__CSPI2_SCLK */
+       [724] = IMX_PIN_REG(MX35_PAD_ATA_DATA3, 0x6ec, 0x288, 5, 0x884, 1), /* MX35_PAD_ATA_DATA3__GPIO2_16 */
+       [725] = IMX_PIN_REG(MX35_PAD_ATA_DATA3, 0x6ec, 0x288, 6, 0x0, 0), /* MX35_PAD_ATA_DATA3__IPU_DIAGB_10 */
+       [726] = IMX_PIN_REG(MX35_PAD_ATA_DATA3, 0x6ec, 0x288, 7, 0x0, 0), /* MX35_PAD_ATA_DATA3__ARM11P_TOP_TRACE_29 */
+       [727] = IMX_PIN_REG(MX35_PAD_ATA_DATA4, 0x6f0, 0x28c, 0, 0x0, 0), /* MX35_PAD_ATA_DATA4__ATA_DATA_4 */
+       [728] = IMX_PIN_REG(MX35_PAD_ATA_DATA4, 0x6f0, 0x28c, 1, 0x818, 1), /* MX35_PAD_ATA_DATA4__ESDHC3_CMD */
+       [729] = IMX_PIN_REG(MX35_PAD_ATA_DATA4, 0x6f0, 0x28c, 2, 0x9bc, 1), /* MX35_PAD_ATA_DATA4__USB_TOP_USBOTG_DATA_6 */
+       [730] = IMX_PIN_REG(MX35_PAD_ATA_DATA4, 0x6f0, 0x28c, 5, 0x888, 1), /* MX35_PAD_ATA_DATA4__GPIO2_17 */
+       [731] = IMX_PIN_REG(MX35_PAD_ATA_DATA4, 0x6f0, 0x28c, 6, 0x0, 0), /* MX35_PAD_ATA_DATA4__IPU_DIAGB_11 */
+       [732] = IMX_PIN_REG(MX35_PAD_ATA_DATA4, 0x6f0, 0x28c, 7, 0x0, 0), /* MX35_PAD_ATA_DATA4__ARM11P_TOP_TRACE_30 */
+       [733] = IMX_PIN_REG(MX35_PAD_ATA_DATA5, 0x6f4, 0x290, 0, 0x0, 0), /* MX35_PAD_ATA_DATA5__ATA_DATA_5 */
+       [734] = IMX_PIN_REG(MX35_PAD_ATA_DATA5, 0x6f4, 0x290, 2, 0x9c0, 1), /* MX35_PAD_ATA_DATA5__USB_TOP_USBOTG_DATA_7 */
+       [735] = IMX_PIN_REG(MX35_PAD_ATA_DATA5, 0x6f4, 0x290, 5, 0x88c, 1), /* MX35_PAD_ATA_DATA5__GPIO2_18 */
+       [736] = IMX_PIN_REG(MX35_PAD_ATA_DATA5, 0x6f4, 0x290, 6, 0x0, 0), /* MX35_PAD_ATA_DATA5__IPU_DIAGB_12 */
+       [737] = IMX_PIN_REG(MX35_PAD_ATA_DATA5, 0x6f4, 0x290, 7, 0x0, 0), /* MX35_PAD_ATA_DATA5__ARM11P_TOP_TRACE_31 */
+       [738] = IMX_PIN_REG(MX35_PAD_ATA_DATA6, 0x6f8, 0x294, 0, 0x0, 0), /* MX35_PAD_ATA_DATA6__ATA_DATA_6 */
+       [739] = IMX_PIN_REG(MX35_PAD_ATA_DATA6, 0x6f8, 0x294, 1, 0x0, 0), /* MX35_PAD_ATA_DATA6__CAN1_TXCAN */
+       [740] = IMX_PIN_REG(MX35_PAD_ATA_DATA6, 0x6f8, 0x294, 2, 0x0, 0), /* MX35_PAD_ATA_DATA6__UART1_DTR */
+       [741] = IMX_PIN_REG(MX35_PAD_ATA_DATA6, 0x6f8, 0x294, 3, 0x7b4, 0), /* MX35_PAD_ATA_DATA6__AUDMUX_AUD6_TXD */
+       [742] = IMX_PIN_REG(MX35_PAD_ATA_DATA6, 0x6f8, 0x294, 5, 0x890, 1), /* MX35_PAD_ATA_DATA6__GPIO2_19 */
+       [743] = IMX_PIN_REG(MX35_PAD_ATA_DATA6, 0x6f8, 0x294, 6, 0x0, 0), /* MX35_PAD_ATA_DATA6__IPU_DIAGB_13 */
+       [744] = IMX_PIN_REG(MX35_PAD_ATA_DATA7, 0x6fc, 0x298, 0, 0x0, 0), /* MX35_PAD_ATA_DATA7__ATA_DATA_7 */
+       [745] = IMX_PIN_REG(MX35_PAD_ATA_DATA7, 0x6fc, 0x298, 1, 0x7c8, 2), /* MX35_PAD_ATA_DATA7__CAN1_RXCAN */
+       [746] = IMX_PIN_REG(MX35_PAD_ATA_DATA7, 0x6fc, 0x298, 2, 0x0, 0), /* MX35_PAD_ATA_DATA7__UART1_DSR */
+       [747] = IMX_PIN_REG(MX35_PAD_ATA_DATA7, 0x6fc, 0x298, 3, 0x7b0, 0), /* MX35_PAD_ATA_DATA7__AUDMUX_AUD6_RXD */
+       [748] = IMX_PIN_REG(MX35_PAD_ATA_DATA7, 0x6fc, 0x298, 5, 0x898, 1), /* MX35_PAD_ATA_DATA7__GPIO2_20 */
+       [749] = IMX_PIN_REG(MX35_PAD_ATA_DATA7, 0x6fc, 0x298, 6, 0x0, 0), /* MX35_PAD_ATA_DATA7__IPU_DIAGB_14 */
+       [750] = IMX_PIN_REG(MX35_PAD_ATA_DATA8, 0x700, 0x29c, 0, 0x0, 0), /* MX35_PAD_ATA_DATA8__ATA_DATA_8 */
+       [751] = IMX_PIN_REG(MX35_PAD_ATA_DATA8, 0x700, 0x29c, 1, 0x99c, 1), /* MX35_PAD_ATA_DATA8__UART3_RTS */
+       [752] = IMX_PIN_REG(MX35_PAD_ATA_DATA8, 0x700, 0x29c, 2, 0x0, 0), /* MX35_PAD_ATA_DATA8__UART1_RI */
+       [753] = IMX_PIN_REG(MX35_PAD_ATA_DATA8, 0x700, 0x29c, 3, 0x7c0, 0), /* MX35_PAD_ATA_DATA8__AUDMUX_AUD6_TXC */
+       [754] = IMX_PIN_REG(MX35_PAD_ATA_DATA8, 0x700, 0x29c, 5, 0x89c, 1), /* MX35_PAD_ATA_DATA8__GPIO2_21 */
+       [755] = IMX_PIN_REG(MX35_PAD_ATA_DATA8, 0x700, 0x29c, 6, 0x0, 0), /* MX35_PAD_ATA_DATA8__IPU_DIAGB_15 */
+       [756] = IMX_PIN_REG(MX35_PAD_ATA_DATA9, 0x704, 0x2a0, 0, 0x0, 0), /* MX35_PAD_ATA_DATA9__ATA_DATA_9 */
+       [757] = IMX_PIN_REG(MX35_PAD_ATA_DATA9, 0x704, 0x2a0, 1, 0x0, 0), /* MX35_PAD_ATA_DATA9__UART3_CTS */
+       [758] = IMX_PIN_REG(MX35_PAD_ATA_DATA9, 0x704, 0x2a0, 2, 0x0, 0), /* MX35_PAD_ATA_DATA9__UART1_DCD */
+       [759] = IMX_PIN_REG(MX35_PAD_ATA_DATA9, 0x704, 0x2a0, 3, 0x7c4, 0), /* MX35_PAD_ATA_DATA9__AUDMUX_AUD6_TXFS */
+       [760] = IMX_PIN_REG(MX35_PAD_ATA_DATA9, 0x704, 0x2a0, 5, 0x8a0, 1), /* MX35_PAD_ATA_DATA9__GPIO2_22 */
+       [761] = IMX_PIN_REG(MX35_PAD_ATA_DATA9, 0x704, 0x2a0, 6, 0x0, 0), /* MX35_PAD_ATA_DATA9__IPU_DIAGB_16 */
+       [762] = IMX_PIN_REG(MX35_PAD_ATA_DATA10, 0x708, 0x2a4, 0, 0x0, 0), /* MX35_PAD_ATA_DATA10__ATA_DATA_10 */
+       [763] = IMX_PIN_REG(MX35_PAD_ATA_DATA10, 0x708, 0x2a4, 1, 0x9a0, 2), /* MX35_PAD_ATA_DATA10__UART3_RXD_MUX */
+       [764] = IMX_PIN_REG(MX35_PAD_ATA_DATA10, 0x708, 0x2a4, 3, 0x7b8, 0), /* MX35_PAD_ATA_DATA10__AUDMUX_AUD6_RXC */
+       [765] = IMX_PIN_REG(MX35_PAD_ATA_DATA10, 0x708, 0x2a4, 5, 0x8a4, 1), /* MX35_PAD_ATA_DATA10__GPIO2_23 */
+       [766] = IMX_PIN_REG(MX35_PAD_ATA_DATA10, 0x708, 0x2a4, 6, 0x0, 0), /* MX35_PAD_ATA_DATA10__IPU_DIAGB_17 */
+       [767] = IMX_PIN_REG(MX35_PAD_ATA_DATA11, 0x70c, 0x2a8, 0, 0x0, 0), /* MX35_PAD_ATA_DATA11__ATA_DATA_11 */
+       [768] = IMX_PIN_REG(MX35_PAD_ATA_DATA11, 0x70c, 0x2a8, 1, 0x0, 0), /* MX35_PAD_ATA_DATA11__UART3_TXD_MUX */
+       [769] = IMX_PIN_REG(MX35_PAD_ATA_DATA11, 0x70c, 0x2a8, 3, 0x7bc, 0), /* MX35_PAD_ATA_DATA11__AUDMUX_AUD6_RXFS */
+       [770] = IMX_PIN_REG(MX35_PAD_ATA_DATA11, 0x70c, 0x2a8, 5, 0x8a8, 1), /* MX35_PAD_ATA_DATA11__GPIO2_24 */
+       [771] = IMX_PIN_REG(MX35_PAD_ATA_DATA11, 0x70c, 0x2a8, 6, 0x0, 0), /* MX35_PAD_ATA_DATA11__IPU_DIAGB_18 */
+       [772] = IMX_PIN_REG(MX35_PAD_ATA_DATA12, 0x710, 0x2ac, 0, 0x0, 0), /* MX35_PAD_ATA_DATA12__ATA_DATA_12 */
+       [773] = IMX_PIN_REG(MX35_PAD_ATA_DATA12, 0x710, 0x2ac, 1, 0x91c, 3), /* MX35_PAD_ATA_DATA12__I2C3_SCL */
+       [774] = IMX_PIN_REG(MX35_PAD_ATA_DATA12, 0x710, 0x2ac, 5, 0x8ac, 1), /* MX35_PAD_ATA_DATA12__GPIO2_25 */
+       [775] = IMX_PIN_REG(MX35_PAD_ATA_DATA12, 0x710, 0x2ac, 6, 0x0, 0), /* MX35_PAD_ATA_DATA12__IPU_DIAGB_19 */
+       [776] = IMX_PIN_REG(MX35_PAD_ATA_DATA13, 0x714, 0x2b0, 0, 0x0, 0), /* MX35_PAD_ATA_DATA13__ATA_DATA_13 */
+       [777] = IMX_PIN_REG(MX35_PAD_ATA_DATA13, 0x714, 0x2b0, 1, 0x920, 3), /* MX35_PAD_ATA_DATA13__I2C3_SDA */
+       [778] = IMX_PIN_REG(MX35_PAD_ATA_DATA13, 0x714, 0x2b0, 5, 0x8b0, 1), /* MX35_PAD_ATA_DATA13__GPIO2_26 */
+       [779] = IMX_PIN_REG(MX35_PAD_ATA_DATA13, 0x714, 0x2b0, 6, 0x0, 0), /* MX35_PAD_ATA_DATA13__IPU_DIAGB_20 */
+       [780] = IMX_PIN_REG(MX35_PAD_ATA_DATA14, 0x718, 0x2b4, 0, 0x0, 0), /* MX35_PAD_ATA_DATA14__ATA_DATA_14 */
+       [781] = IMX_PIN_REG(MX35_PAD_ATA_DATA14, 0x718, 0x2b4, 1, 0x930, 2), /* MX35_PAD_ATA_DATA14__IPU_CSI_D_0 */
+       [782] = IMX_PIN_REG(MX35_PAD_ATA_DATA14, 0x718, 0x2b4, 3, 0x970, 2), /* MX35_PAD_ATA_DATA14__KPP_ROW_0 */
+       [783] = IMX_PIN_REG(MX35_PAD_ATA_DATA14, 0x718, 0x2b4, 5, 0x8b4, 1), /* MX35_PAD_ATA_DATA14__GPIO2_27 */
+       [784] = IMX_PIN_REG(MX35_PAD_ATA_DATA14, 0x718, 0x2b4, 6, 0x0, 0), /* MX35_PAD_ATA_DATA14__IPU_DIAGB_21 */
+       [785] = IMX_PIN_REG(MX35_PAD_ATA_DATA15, 0x71c, 0x2b8, 0, 0x0, 0), /* MX35_PAD_ATA_DATA15__ATA_DATA_15 */
+       [786] = IMX_PIN_REG(MX35_PAD_ATA_DATA15, 0x71c, 0x2b8, 1, 0x934, 2), /* MX35_PAD_ATA_DATA15__IPU_CSI_D_1 */
+       [787] = IMX_PIN_REG(MX35_PAD_ATA_DATA15, 0x71c, 0x2b8, 3, 0x974, 2), /* MX35_PAD_ATA_DATA15__KPP_ROW_1 */
+       [788] = IMX_PIN_REG(MX35_PAD_ATA_DATA15, 0x71c, 0x2b8, 5, 0x8b8, 1), /* MX35_PAD_ATA_DATA15__GPIO2_28 */
+       [789] = IMX_PIN_REG(MX35_PAD_ATA_DATA15, 0x71c, 0x2b8, 6, 0x0, 0), /* MX35_PAD_ATA_DATA15__IPU_DIAGB_22 */
+       [790] = IMX_PIN_REG(MX35_PAD_ATA_INTRQ, 0x720, 0x2bc, 0, 0x0, 0), /* MX35_PAD_ATA_INTRQ__ATA_INTRQ */
+       [791] = IMX_PIN_REG(MX35_PAD_ATA_INTRQ, 0x720, 0x2bc, 1, 0x938, 3), /* MX35_PAD_ATA_INTRQ__IPU_CSI_D_2 */
+       [792] = IMX_PIN_REG(MX35_PAD_ATA_INTRQ, 0x720, 0x2bc, 3, 0x978, 2), /* MX35_PAD_ATA_INTRQ__KPP_ROW_2 */
+       [793] = IMX_PIN_REG(MX35_PAD_ATA_INTRQ, 0x720, 0x2bc, 5, 0x8bc, 1), /* MX35_PAD_ATA_INTRQ__GPIO2_29 */
+       [794] = IMX_PIN_REG(MX35_PAD_ATA_INTRQ, 0x720, 0x2bc, 6, 0x0, 0), /* MX35_PAD_ATA_INTRQ__IPU_DIAGB_23 */
+       [795] = IMX_PIN_REG(MX35_PAD_ATA_BUFF_EN, 0x724, 0x2c0, 0, 0x0, 0), /* MX35_PAD_ATA_BUFF_EN__ATA_BUFFER_EN */
+       [796] = IMX_PIN_REG(MX35_PAD_ATA_BUFF_EN, 0x724, 0x2c0, 1, 0x93c, 3), /* MX35_PAD_ATA_BUFF_EN__IPU_CSI_D_3 */
+       [797] = IMX_PIN_REG(MX35_PAD_ATA_BUFF_EN, 0x724, 0x2c0, 3, 0x97c, 2), /* MX35_PAD_ATA_BUFF_EN__KPP_ROW_3 */
+       [798] = IMX_PIN_REG(MX35_PAD_ATA_BUFF_EN, 0x724, 0x2c0, 5, 0x8c4, 1), /* MX35_PAD_ATA_BUFF_EN__GPIO2_30 */
+       [799] = IMX_PIN_REG(MX35_PAD_ATA_BUFF_EN, 0x724, 0x2c0, 6, 0x0, 0), /* MX35_PAD_ATA_BUFF_EN__IPU_DIAGB_24 */
+       [800] = IMX_PIN_REG(MX35_PAD_ATA_DMARQ, 0x728, 0x2c4, 0, 0x0, 0), /* MX35_PAD_ATA_DMARQ__ATA_DMARQ */
+       [801] = IMX_PIN_REG(MX35_PAD_ATA_DMARQ, 0x728, 0x2c4, 1, 0x940, 2), /* MX35_PAD_ATA_DMARQ__IPU_CSI_D_4 */
+       [802] = IMX_PIN_REG(MX35_PAD_ATA_DMARQ, 0x728, 0x2c4, 3, 0x950, 2), /* MX35_PAD_ATA_DMARQ__KPP_COL_0 */
+       [803] = IMX_PIN_REG(MX35_PAD_ATA_DMARQ, 0x728, 0x2c4, 5, 0x8c8, 1), /* MX35_PAD_ATA_DMARQ__GPIO2_31 */
+       [804] = IMX_PIN_REG(MX35_PAD_ATA_DMARQ, 0x728, 0x2c4, 6, 0x0, 0), /* MX35_PAD_ATA_DMARQ__IPU_DIAGB_25 */
+       [805] = IMX_PIN_REG(MX35_PAD_ATA_DMARQ, 0x728, 0x2c4, 7, 0x0, 0), /* MX35_PAD_ATA_DMARQ__ECT_CTI_TRIG_IN1_4 */
+       [806] = IMX_PIN_REG(MX35_PAD_ATA_DA0, 0x72c, 0x2c8, 0, 0x0, 0), /* MX35_PAD_ATA_DA0__ATA_DA_0 */
+       [807] = IMX_PIN_REG(MX35_PAD_ATA_DA0, 0x72c, 0x2c8, 1, 0x944, 2), /* MX35_PAD_ATA_DA0__IPU_CSI_D_5 */
+       [808] = IMX_PIN_REG(MX35_PAD_ATA_DA0, 0x72c, 0x2c8, 3, 0x954, 2), /* MX35_PAD_ATA_DA0__KPP_COL_1 */
+       [809] = IMX_PIN_REG(MX35_PAD_ATA_DA0, 0x72c, 0x2c8, 5, 0x8e8, 1), /* MX35_PAD_ATA_DA0__GPIO3_0 */
+       [810] = IMX_PIN_REG(MX35_PAD_ATA_DA0, 0x72c, 0x2c8, 6, 0x0, 0), /* MX35_PAD_ATA_DA0__IPU_DIAGB_26 */
+       [811] = IMX_PIN_REG(MX35_PAD_ATA_DA0, 0x72c, 0x2c8, 7, 0x0, 0), /* MX35_PAD_ATA_DA0__ECT_CTI_TRIG_IN1_5 */
+       [812] = IMX_PIN_REG(MX35_PAD_ATA_DA1, 0x730, 0x2cc, 0, 0x0, 0), /* MX35_PAD_ATA_DA1__ATA_DA_1 */
+       [813] = IMX_PIN_REG(MX35_PAD_ATA_DA1, 0x730, 0x2cc, 1, 0x948, 2), /* MX35_PAD_ATA_DA1__IPU_CSI_D_6 */
+       [814] = IMX_PIN_REG(MX35_PAD_ATA_DA1, 0x730, 0x2cc, 3, 0x958, 2), /* MX35_PAD_ATA_DA1__KPP_COL_2 */
+       [815] = IMX_PIN_REG(MX35_PAD_ATA_DA1, 0x730, 0x2cc, 5, 0x0, 0), /* MX35_PAD_ATA_DA1__GPIO3_1 */
+       [816] = IMX_PIN_REG(MX35_PAD_ATA_DA1, 0x730, 0x2cc, 6, 0x0, 0), /* MX35_PAD_ATA_DA1__IPU_DIAGB_27 */
+       [817] = IMX_PIN_REG(MX35_PAD_ATA_DA1, 0x730, 0x2cc, 7, 0x0, 0), /* MX35_PAD_ATA_DA1__ECT_CTI_TRIG_IN1_6 */
+       [818] = IMX_PIN_REG(MX35_PAD_ATA_DA2, 0x734, 0x2d0, 0, 0x0, 0), /* MX35_PAD_ATA_DA2__ATA_DA_2 */
+       [819] = IMX_PIN_REG(MX35_PAD_ATA_DA2, 0x734, 0x2d0, 1, 0x94c, 2), /* MX35_PAD_ATA_DA2__IPU_CSI_D_7 */
+       [820] = IMX_PIN_REG(MX35_PAD_ATA_DA2, 0x734, 0x2d0, 3, 0x95c, 2), /* MX35_PAD_ATA_DA2__KPP_COL_3 */
+       [821] = IMX_PIN_REG(MX35_PAD_ATA_DA2, 0x734, 0x2d0, 5, 0x0, 0), /* MX35_PAD_ATA_DA2__GPIO3_2 */
+       [822] = IMX_PIN_REG(MX35_PAD_ATA_DA2, 0x734, 0x2d0, 6, 0x0, 0), /* MX35_PAD_ATA_DA2__IPU_DIAGB_28 */
+       [823] = IMX_PIN_REG(MX35_PAD_ATA_DA2, 0x734, 0x2d0, 7, 0x0, 0), /* MX35_PAD_ATA_DA2__ECT_CTI_TRIG_IN1_7 */
+       [824] = IMX_PIN_REG(MX35_PAD_MLB_CLK, 0x738, 0x2d4, 0, 0x0, 0), /* MX35_PAD_MLB_CLK__MLB_MLBCLK */
+       [825] = IMX_PIN_REG(MX35_PAD_MLB_CLK, 0x738, 0x2d4, 5, 0x0, 0), /* MX35_PAD_MLB_CLK__GPIO3_3 */
+       [826] = IMX_PIN_REG(MX35_PAD_MLB_DAT, 0x73c, 0x2d8, 0, 0x0, 0), /* MX35_PAD_MLB_DAT__MLB_MLBDAT */
+       [827] = IMX_PIN_REG(MX35_PAD_MLB_DAT, 0x73c, 0x2d8, 5, 0x904, 1), /* MX35_PAD_MLB_DAT__GPIO3_4 */
+       [828] = IMX_PIN_REG(MX35_PAD_MLB_SIG, 0x740, 0x2dc, 0, 0x0, 0), /* MX35_PAD_MLB_SIG__MLB_MLBSIG */
+       [829] = IMX_PIN_REG(MX35_PAD_MLB_SIG, 0x740, 0x2dc, 5, 0x908, 1), /* MX35_PAD_MLB_SIG__GPIO3_5 */
+       [830] = IMX_PIN_REG(MX35_PAD_FEC_TX_CLK, 0x744, 0x2e0, 0, 0x0, 0), /* MX35_PAD_FEC_TX_CLK__FEC_TX_CLK */
+       [831] = IMX_PIN_REG(MX35_PAD_FEC_TX_CLK, 0x744, 0x2e0, 1, 0x804, 1), /* MX35_PAD_FEC_TX_CLK__ESDHC1_DAT4 */
+       [832] = IMX_PIN_REG(MX35_PAD_FEC_TX_CLK, 0x744, 0x2e0, 2, 0x9a0, 3), /* MX35_PAD_FEC_TX_CLK__UART3_RXD_MUX */
+       [833] = IMX_PIN_REG(MX35_PAD_FEC_TX_CLK, 0x744, 0x2e0, 3, 0x9ec, 1), /* MX35_PAD_FEC_TX_CLK__USB_TOP_USBH2_DIR */
+       [834] = IMX_PIN_REG(MX35_PAD_FEC_TX_CLK, 0x744, 0x2e0, 4, 0x7ec, 3), /* MX35_PAD_FEC_TX_CLK__CSPI2_MOSI */
+       [835] = IMX_PIN_REG(MX35_PAD_FEC_TX_CLK, 0x744, 0x2e0, 5, 0x90c, 1), /* MX35_PAD_FEC_TX_CLK__GPIO3_6 */
+       [836] = IMX_PIN_REG(MX35_PAD_FEC_TX_CLK, 0x744, 0x2e0, 6, 0x928, 5), /* MX35_PAD_FEC_TX_CLK__IPU_DISPB_D12_VSYNC */
+       [837] = IMX_PIN_REG(MX35_PAD_FEC_TX_CLK, 0x744, 0x2e0, 7, 0x0, 0), /* MX35_PAD_FEC_TX_CLK__ARM11P_TOP_EVNTBUS_0 */
+       [838] = IMX_PIN_REG(MX35_PAD_FEC_RX_CLK, 0x748, 0x2e4, 0, 0x0, 0), /* MX35_PAD_FEC_RX_CLK__FEC_RX_CLK */
+       [839] = IMX_PIN_REG(MX35_PAD_FEC_RX_CLK, 0x748, 0x2e4, 1, 0x808, 1), /* MX35_PAD_FEC_RX_CLK__ESDHC1_DAT5 */
+       [840] = IMX_PIN_REG(MX35_PAD_FEC_RX_CLK, 0x748, 0x2e4, 2, 0x0, 0), /* MX35_PAD_FEC_RX_CLK__UART3_TXD_MUX */
+       [841] = IMX_PIN_REG(MX35_PAD_FEC_RX_CLK, 0x748, 0x2e4, 3, 0x0, 0), /* MX35_PAD_FEC_RX_CLK__USB_TOP_USBH2_STP */
+       [842] = IMX_PIN_REG(MX35_PAD_FEC_RX_CLK, 0x748, 0x2e4, 4, 0x7e8, 3), /* MX35_PAD_FEC_RX_CLK__CSPI2_MISO */
+       [843] = IMX_PIN_REG(MX35_PAD_FEC_RX_CLK, 0x748, 0x2e4, 5, 0x910, 1), /* MX35_PAD_FEC_RX_CLK__GPIO3_7 */
+       [844] = IMX_PIN_REG(MX35_PAD_FEC_RX_CLK, 0x748, 0x2e4, 6, 0x92c, 4), /* MX35_PAD_FEC_RX_CLK__IPU_DISPB_SD_D_I */
+       [845] = IMX_PIN_REG(MX35_PAD_FEC_RX_CLK, 0x748, 0x2e4, 7, 0x0, 0), /* MX35_PAD_FEC_RX_CLK__ARM11P_TOP_EVNTBUS_1 */
+       [846] = IMX_PIN_REG(MX35_PAD_FEC_RX_DV, 0x74c, 0x2e8, 0, 0x0, 0), /* MX35_PAD_FEC_RX_DV__FEC_RX_DV */
+       [847] = IMX_PIN_REG(MX35_PAD_FEC_RX_DV, 0x74c, 0x2e8, 1, 0x80c, 1), /* MX35_PAD_FEC_RX_DV__ESDHC1_DAT6 */
+       [848] = IMX_PIN_REG(MX35_PAD_FEC_RX_DV, 0x74c, 0x2e8, 2, 0x99c, 2), /* MX35_PAD_FEC_RX_DV__UART3_RTS */
+       [849] = IMX_PIN_REG(MX35_PAD_FEC_RX_DV, 0x74c, 0x2e8, 3, 0x9f0, 1), /* MX35_PAD_FEC_RX_DV__USB_TOP_USBH2_NXT */
+       [850] = IMX_PIN_REG(MX35_PAD_FEC_RX_DV, 0x74c, 0x2e8, 4, 0x7e0, 3), /* MX35_PAD_FEC_RX_DV__CSPI2_SCLK */
+       [851] = IMX_PIN_REG(MX35_PAD_FEC_RX_DV, 0x74c, 0x2e8, 5, 0x914, 1), /* MX35_PAD_FEC_RX_DV__GPIO3_8 */
+       [852] = IMX_PIN_REG(MX35_PAD_FEC_RX_DV, 0x74c, 0x2e8, 6, 0x0, 0), /* MX35_PAD_FEC_RX_DV__IPU_DISPB_SD_CLK */
+       [853] = IMX_PIN_REG(MX35_PAD_FEC_RX_DV, 0x74c, 0x2e8, 7, 0x0, 0), /* MX35_PAD_FEC_RX_DV__ARM11P_TOP_EVNTBUS_2 */
+       [854] = IMX_PIN_REG(MX35_PAD_FEC_COL, 0x750, 0x2ec, 0, 0x0, 0), /* MX35_PAD_FEC_COL__FEC_COL */
+       [855] = IMX_PIN_REG(MX35_PAD_FEC_COL, 0x750, 0x2ec, 1, 0x810, 1), /* MX35_PAD_FEC_COL__ESDHC1_DAT7 */
+       [856] = IMX_PIN_REG(MX35_PAD_FEC_COL, 0x750, 0x2ec, 2, 0x0, 0), /* MX35_PAD_FEC_COL__UART3_CTS */
+       [857] = IMX_PIN_REG(MX35_PAD_FEC_COL, 0x750, 0x2ec, 3, 0x9cc, 1), /* MX35_PAD_FEC_COL__USB_TOP_USBH2_DATA_0 */
+       [858] = IMX_PIN_REG(MX35_PAD_FEC_COL, 0x750, 0x2ec, 4, 0x7e4, 3), /* MX35_PAD_FEC_COL__CSPI2_RDY */
+       [859] = IMX_PIN_REG(MX35_PAD_FEC_COL, 0x750, 0x2ec, 5, 0x918, 1), /* MX35_PAD_FEC_COL__GPIO3_9 */
+       [860] = IMX_PIN_REG(MX35_PAD_FEC_COL, 0x750, 0x2ec, 6, 0x0, 0), /* MX35_PAD_FEC_COL__IPU_DISPB_SER_RS */
+       [861] = IMX_PIN_REG(MX35_PAD_FEC_COL, 0x750, 0x2ec, 7, 0x0, 0), /* MX35_PAD_FEC_COL__ARM11P_TOP_EVNTBUS_3 */
+       [862] = IMX_PIN_REG(MX35_PAD_FEC_RDATA0, 0x754, 0x2f0, 0, 0x0, 0), /* MX35_PAD_FEC_RDATA0__FEC_RDATA_0 */
+       [863] = IMX_PIN_REG(MX35_PAD_FEC_RDATA0, 0x754, 0x2f0, 1, 0x0, 0), /* MX35_PAD_FEC_RDATA0__PWM_PWMO */
+       [864] = IMX_PIN_REG(MX35_PAD_FEC_RDATA0, 0x754, 0x2f0, 2, 0x0, 0), /* MX35_PAD_FEC_RDATA0__UART3_DTR */
+       [865] = IMX_PIN_REG(MX35_PAD_FEC_RDATA0, 0x754, 0x2f0, 3, 0x9d0, 1), /* MX35_PAD_FEC_RDATA0__USB_TOP_USBH2_DATA_1 */
+       [866] = IMX_PIN_REG(MX35_PAD_FEC_RDATA0, 0x754, 0x2f0, 4, 0x7f0, 2), /* MX35_PAD_FEC_RDATA0__CSPI2_SS0 */
+       [867] = IMX_PIN_REG(MX35_PAD_FEC_RDATA0, 0x754, 0x2f0, 5, 0x8ec, 1), /* MX35_PAD_FEC_RDATA0__GPIO3_10 */
+       [868] = IMX_PIN_REG(MX35_PAD_FEC_RDATA0, 0x754, 0x2f0, 6, 0x0, 0), /* MX35_PAD_FEC_RDATA0__IPU_DISPB_CS1 */
+       [869] = IMX_PIN_REG(MX35_PAD_FEC_RDATA0, 0x754, 0x2f0, 7, 0x0, 0), /* MX35_PAD_FEC_RDATA0__ARM11P_TOP_EVNTBUS_4 */
+       [870] = IMX_PIN_REG(MX35_PAD_FEC_TDATA0, 0x758, 0x2f4, 0, 0x0, 0), /* MX35_PAD_FEC_TDATA0__FEC_TDATA_0 */
+       [871] = IMX_PIN_REG(MX35_PAD_FEC_TDATA0, 0x758, 0x2f4, 1, 0x0, 0), /* MX35_PAD_FEC_TDATA0__SPDIF_SPDIF_OUT1 */
+       [872] = IMX_PIN_REG(MX35_PAD_FEC_TDATA0, 0x758, 0x2f4, 2, 0x0, 0), /* MX35_PAD_FEC_TDATA0__UART3_DSR */
+       [873] = IMX_PIN_REG(MX35_PAD_FEC_TDATA0, 0x758, 0x2f4, 3, 0x9d4, 1), /* MX35_PAD_FEC_TDATA0__USB_TOP_USBH2_DATA_2 */
+       [874] = IMX_PIN_REG(MX35_PAD_FEC_TDATA0, 0x758, 0x2f4, 4, 0x7f4, 2), /* MX35_PAD_FEC_TDATA0__CSPI2_SS1 */
+       [875] = IMX_PIN_REG(MX35_PAD_FEC_TDATA0, 0x758, 0x2f4, 5, 0x8f0, 1), /* MX35_PAD_FEC_TDATA0__GPIO3_11 */
+       [876] = IMX_PIN_REG(MX35_PAD_FEC_TDATA0, 0x758, 0x2f4, 6, 0x0, 0), /* MX35_PAD_FEC_TDATA0__IPU_DISPB_CS0 */
+       [877] = IMX_PIN_REG(MX35_PAD_FEC_TDATA0, 0x758, 0x2f4, 7, 0x0, 0), /* MX35_PAD_FEC_TDATA0__ARM11P_TOP_EVNTBUS_5 */
+       [878] = IMX_PIN_REG(MX35_PAD_FEC_TX_EN, 0x75c, 0x2f8, 0, 0x0, 0), /* MX35_PAD_FEC_TX_EN__FEC_TX_EN */
+       [879] = IMX_PIN_REG(MX35_PAD_FEC_TX_EN, 0x75c, 0x2f8, 1, 0x998, 3), /* MX35_PAD_FEC_TX_EN__SPDIF_SPDIF_IN1 */
+       [880] = IMX_PIN_REG(MX35_PAD_FEC_TX_EN, 0x75c, 0x2f8, 2, 0x0, 0), /* MX35_PAD_FEC_TX_EN__UART3_RI */
+       [881] = IMX_PIN_REG(MX35_PAD_FEC_TX_EN, 0x75c, 0x2f8, 3, 0x9d8, 1), /* MX35_PAD_FEC_TX_EN__USB_TOP_USBH2_DATA_3 */
+       [882] = IMX_PIN_REG(MX35_PAD_FEC_TX_EN, 0x75c, 0x2f8, 5, 0x8f4, 1), /* MX35_PAD_FEC_TX_EN__GPIO3_12 */
+       [883] = IMX_PIN_REG(MX35_PAD_FEC_TX_EN, 0x75c, 0x2f8, 6, 0x0, 0), /* MX35_PAD_FEC_TX_EN__IPU_DISPB_PAR_RS */
+       [884] = IMX_PIN_REG(MX35_PAD_FEC_TX_EN, 0x75c, 0x2f8, 7, 0x0, 0), /* MX35_PAD_FEC_TX_EN__ARM11P_TOP_EVNTBUS_6 */
+       [885] = IMX_PIN_REG(MX35_PAD_FEC_MDC, 0x760, 0x2fc, 0, 0x0, 0), /* MX35_PAD_FEC_MDC__FEC_MDC */
+       [886] = IMX_PIN_REG(MX35_PAD_FEC_MDC, 0x760, 0x2fc, 1, 0x0, 0), /* MX35_PAD_FEC_MDC__CAN2_TXCAN */
+       [887] = IMX_PIN_REG(MX35_PAD_FEC_MDC, 0x760, 0x2fc, 2, 0x0, 0), /* MX35_PAD_FEC_MDC__UART3_DCD */
+       [888] = IMX_PIN_REG(MX35_PAD_FEC_MDC, 0x760, 0x2fc, 3, 0x9dc, 1), /* MX35_PAD_FEC_MDC__USB_TOP_USBH2_DATA_4 */
+       [889] = IMX_PIN_REG(MX35_PAD_FEC_MDC, 0x760, 0x2fc, 5, 0x8f8, 1), /* MX35_PAD_FEC_MDC__GPIO3_13 */
+       [890] = IMX_PIN_REG(MX35_PAD_FEC_MDC, 0x760, 0x2fc, 6, 0x0, 0), /* MX35_PAD_FEC_MDC__IPU_DISPB_WR */
+       [891] = IMX_PIN_REG(MX35_PAD_FEC_MDC, 0x760, 0x2fc, 7, 0x0, 0), /* MX35_PAD_FEC_MDC__ARM11P_TOP_EVNTBUS_7 */
+       [892] = IMX_PIN_REG(MX35_PAD_FEC_MDIO, 0x764, 0x300, 0, 0x0, 0), /* MX35_PAD_FEC_MDIO__FEC_MDIO */
+       [893] = IMX_PIN_REG(MX35_PAD_FEC_MDIO, 0x764, 0x300, 1, 0x7cc, 2), /* MX35_PAD_FEC_MDIO__CAN2_RXCAN */
+       [894] = IMX_PIN_REG(MX35_PAD_FEC_MDIO, 0x764, 0x300, 3, 0x9e0, 1), /* MX35_PAD_FEC_MDIO__USB_TOP_USBH2_DATA_5 */
+       [895] = IMX_PIN_REG(MX35_PAD_FEC_MDIO, 0x764, 0x300, 5, 0x8fc, 1), /* MX35_PAD_FEC_MDIO__GPIO3_14 */
+       [896] = IMX_PIN_REG(MX35_PAD_FEC_MDIO, 0x764, 0x300, 6, 0x0, 0), /* MX35_PAD_FEC_MDIO__IPU_DISPB_RD */
+       [897] = IMX_PIN_REG(MX35_PAD_FEC_MDIO, 0x764, 0x300, 7, 0x0, 0), /* MX35_PAD_FEC_MDIO__ARM11P_TOP_EVNTBUS_8 */
+       [898] = IMX_PIN_REG(MX35_PAD_FEC_TX_ERR, 0x768, 0x304, 0, 0x0, 0), /* MX35_PAD_FEC_TX_ERR__FEC_TX_ERR */
+       [899] = IMX_PIN_REG(MX35_PAD_FEC_TX_ERR, 0x768, 0x304, 1, 0x990, 2), /* MX35_PAD_FEC_TX_ERR__OWIRE_LINE */
+       [900] = IMX_PIN_REG(MX35_PAD_FEC_TX_ERR, 0x768, 0x304, 2, 0x994, 4), /* MX35_PAD_FEC_TX_ERR__SPDIF_SPDIF_EXTCLK */
+       [901] = IMX_PIN_REG(MX35_PAD_FEC_TX_ERR, 0x768, 0x304, 3, 0x9e4, 1), /* MX35_PAD_FEC_TX_ERR__USB_TOP_USBH2_DATA_6 */
+       [902] = IMX_PIN_REG(MX35_PAD_FEC_TX_ERR, 0x768, 0x304, 5, 0x900, 1), /* MX35_PAD_FEC_TX_ERR__GPIO3_15 */
+       [903] = IMX_PIN_REG(MX35_PAD_FEC_TX_ERR, 0x768, 0x304, 6, 0x924, 3), /* MX35_PAD_FEC_TX_ERR__IPU_DISPB_D0_VSYNC */
+       [904] = IMX_PIN_REG(MX35_PAD_FEC_TX_ERR, 0x768, 0x304, 7, 0x0, 0), /* MX35_PAD_FEC_TX_ERR__ARM11P_TOP_EVNTBUS_9 */
+       [905] = IMX_PIN_REG(MX35_PAD_FEC_RX_ERR, 0x76c, 0x308, 0, 0x0, 0), /* MX35_PAD_FEC_RX_ERR__FEC_RX_ERR */
+       [906] = IMX_PIN_REG(MX35_PAD_FEC_RX_ERR, 0x76c, 0x308, 1, 0x930, 3), /* MX35_PAD_FEC_RX_ERR__IPU_CSI_D_0 */
+       [907] = IMX_PIN_REG(MX35_PAD_FEC_RX_ERR, 0x76c, 0x308, 3, 0x9e8, 1), /* MX35_PAD_FEC_RX_ERR__USB_TOP_USBH2_DATA_7 */
+       [908] = IMX_PIN_REG(MX35_PAD_FEC_RX_ERR, 0x76c, 0x308, 4, 0x960, 1), /* MX35_PAD_FEC_RX_ERR__KPP_COL_4 */
+       [909] = IMX_PIN_REG(MX35_PAD_FEC_RX_ERR, 0x76c, 0x308, 5, 0x0, 0), /* MX35_PAD_FEC_RX_ERR__GPIO3_16 */
+       [910] = IMX_PIN_REG(MX35_PAD_FEC_RX_ERR, 0x76c, 0x308, 6, 0x92c, 5), /* MX35_PAD_FEC_RX_ERR__IPU_DISPB_SD_D_IO */
+       [911] = IMX_PIN_REG(MX35_PAD_FEC_CRS, 0x770, 0x30c, 0, 0x0, 0), /* MX35_PAD_FEC_CRS__FEC_CRS */
+       [912] = IMX_PIN_REG(MX35_PAD_FEC_CRS, 0x770, 0x30c, 1, 0x934, 3), /* MX35_PAD_FEC_CRS__IPU_CSI_D_1 */
+       [913] = IMX_PIN_REG(MX35_PAD_FEC_CRS, 0x770, 0x30c, 3, 0x0, 0), /* MX35_PAD_FEC_CRS__USB_TOP_USBH2_PWR */
+       [914] = IMX_PIN_REG(MX35_PAD_FEC_CRS, 0x770, 0x30c, 4, 0x964, 1), /* MX35_PAD_FEC_CRS__KPP_COL_5 */
+       [915] = IMX_PIN_REG(MX35_PAD_FEC_CRS, 0x770, 0x30c, 5, 0x0, 0), /* MX35_PAD_FEC_CRS__GPIO3_17 */
+       [916] = IMX_PIN_REG(MX35_PAD_FEC_CRS, 0x770, 0x30c, 6, 0x0, 0), /* MX35_PAD_FEC_CRS__IPU_FLASH_STROBE */
+       [917] = IMX_PIN_REG(MX35_PAD_FEC_RDATA1, 0x774, 0x310, 0, 0x0, 0), /* MX35_PAD_FEC_RDATA1__FEC_RDATA_1 */
+       [918] = IMX_PIN_REG(MX35_PAD_FEC_RDATA1, 0x774, 0x310, 1, 0x938, 4), /* MX35_PAD_FEC_RDATA1__IPU_CSI_D_2 */
+       [919] = IMX_PIN_REG(MX35_PAD_FEC_RDATA1, 0x774, 0x310, 2, 0x0, 0), /* MX35_PAD_FEC_RDATA1__AUDMUX_AUD6_RXC */
+       [920] = IMX_PIN_REG(MX35_PAD_FEC_RDATA1, 0x774, 0x310, 3, 0x9f4, 2), /* MX35_PAD_FEC_RDATA1__USB_TOP_USBH2_OC */
+       [921] = IMX_PIN_REG(MX35_PAD_FEC_RDATA1, 0x774, 0x310, 4, 0x968, 1), /* MX35_PAD_FEC_RDATA1__KPP_COL_6 */
+       [922] = IMX_PIN_REG(MX35_PAD_FEC_RDATA1, 0x774, 0x310, 5, 0x0, 0), /* MX35_PAD_FEC_RDATA1__GPIO3_18 */
+       [923] = IMX_PIN_REG(MX35_PAD_FEC_RDATA1, 0x774, 0x310, 6, 0x0, 0), /* MX35_PAD_FEC_RDATA1__IPU_DISPB_BE0 */
+       [924] = IMX_PIN_REG(MX35_PAD_FEC_TDATA1, 0x778, 0x314, 0, 0x0, 0), /* MX35_PAD_FEC_TDATA1__FEC_TDATA_1 */
+       [925] = IMX_PIN_REG(MX35_PAD_FEC_TDATA1, 0x778, 0x314, 1, 0x93c, 4), /* MX35_PAD_FEC_TDATA1__IPU_CSI_D_3 */
+       [926] = IMX_PIN_REG(MX35_PAD_FEC_TDATA1, 0x778, 0x314, 2, 0x7bc, 1), /* MX35_PAD_FEC_TDATA1__AUDMUX_AUD6_RXFS */
+       [927] = IMX_PIN_REG(MX35_PAD_FEC_TDATA1, 0x778, 0x314, 4, 0x96c, 1), /* MX35_PAD_FEC_TDATA1__KPP_COL_7 */
+       [928] = IMX_PIN_REG(MX35_PAD_FEC_TDATA1, 0x778, 0x314, 5, 0x0, 0), /* MX35_PAD_FEC_TDATA1__GPIO3_19 */
+       [929] = IMX_PIN_REG(MX35_PAD_FEC_TDATA1, 0x778, 0x314, 6, 0x0, 0), /* MX35_PAD_FEC_TDATA1__IPU_DISPB_BE1 */
+       [930] = IMX_PIN_REG(MX35_PAD_FEC_RDATA2, 0x77c, 0x318, 0, 0x0, 0), /* MX35_PAD_FEC_RDATA2__FEC_RDATA_2 */
+       [931] = IMX_PIN_REG(MX35_PAD_FEC_RDATA2, 0x77c, 0x318, 1, 0x940, 3), /* MX35_PAD_FEC_RDATA2__IPU_CSI_D_4 */
+       [932] = IMX_PIN_REG(MX35_PAD_FEC_RDATA2, 0x77c, 0x318, 2, 0x7b4, 1), /* MX35_PAD_FEC_RDATA2__AUDMUX_AUD6_TXD */
+       [933] = IMX_PIN_REG(MX35_PAD_FEC_RDATA2, 0x77c, 0x318, 4, 0x980, 1), /* MX35_PAD_FEC_RDATA2__KPP_ROW_4 */
+       [934] = IMX_PIN_REG(MX35_PAD_FEC_RDATA2, 0x77c, 0x318, 5, 0x0, 0), /* MX35_PAD_FEC_RDATA2__GPIO3_20 */
+       [935] = IMX_PIN_REG(MX35_PAD_FEC_TDATA2, 0x780, 0x31c, 0, 0x0, 0), /* MX35_PAD_FEC_TDATA2__FEC_TDATA_2 */
+       [936] = IMX_PIN_REG(MX35_PAD_FEC_TDATA2, 0x780, 0x31c, 1, 0x944, 3), /* MX35_PAD_FEC_TDATA2__IPU_CSI_D_5 */
+       [937] = IMX_PIN_REG(MX35_PAD_FEC_TDATA2, 0x780, 0x31c, 2, 0x7b0, 1), /* MX35_PAD_FEC_TDATA2__AUDMUX_AUD6_RXD */
+       [938] = IMX_PIN_REG(MX35_PAD_FEC_TDATA2, 0x780, 0x31c, 4, 0x984, 1), /* MX35_PAD_FEC_TDATA2__KPP_ROW_5 */
+       [939] = IMX_PIN_REG(MX35_PAD_FEC_TDATA2, 0x780, 0x31c, 5, 0x0, 0), /* MX35_PAD_FEC_TDATA2__GPIO3_21 */
+       [940] = IMX_PIN_REG(MX35_PAD_FEC_RDATA3, 0x784, 0x320, 0, 0x0, 0), /* MX35_PAD_FEC_RDATA3__FEC_RDATA_3 */
+       [941] = IMX_PIN_REG(MX35_PAD_FEC_RDATA3, 0x784, 0x320, 1, 0x948, 3), /* MX35_PAD_FEC_RDATA3__IPU_CSI_D_6 */
+       [942] = IMX_PIN_REG(MX35_PAD_FEC_RDATA3, 0x784, 0x320, 2, 0x7c0, 1), /* MX35_PAD_FEC_RDATA3__AUDMUX_AUD6_TXC */
+       [943] = IMX_PIN_REG(MX35_PAD_FEC_RDATA3, 0x784, 0x320, 4, 0x988, 1), /* MX35_PAD_FEC_RDATA3__KPP_ROW_6 */
+       [944] = IMX_PIN_REG(MX35_PAD_FEC_RDATA3, 0x784, 0x320, 6, 0x0, 0), /* MX35_PAD_FEC_RDATA3__GPIO3_22 */
+       [945] = IMX_PIN_REG(MX35_PAD_FEC_TDATA3, 0x788, 0x324, 0, 0x0, 0), /* MX35_PAD_FEC_TDATA3__FEC_TDATA_3 */
+       [946] = IMX_PIN_REG(MX35_PAD_FEC_TDATA3, 0x788, 0x324, 1, 0x94c, 3), /* MX35_PAD_FEC_TDATA3__IPU_CSI_D_7 */
+       [947] = IMX_PIN_REG(MX35_PAD_FEC_TDATA3, 0x788, 0x324, 2, 0x7c4, 1), /* MX35_PAD_FEC_TDATA3__AUDMUX_AUD6_TXFS */
+       [948] = IMX_PIN_REG(MX35_PAD_FEC_TDATA3, 0x788, 0x324, 4, 0x98c, 1), /* MX35_PAD_FEC_TDATA3__KPP_ROW_7 */
+       [949] = IMX_PIN_REG(MX35_PAD_FEC_TDATA3, 0x788, 0x324, 5, 0x0, 0), /* MX35_PAD_FEC_TDATA3__GPIO3_23 */
+       [950] = IMX_PIN_REG(MX35_PAD_EXT_ARMCLK, 0x78c, 0x0, 0, 0x0, 0), /* MX35_PAD_EXT_ARMCLK__CCM_EXT_ARMCLK */
+       [951] = IMX_PIN_REG(MX35_PAD_TEST_MODE, 0x790, 0x0, 0, 0x0, 0), /* MX35_PAD_TEST_MODE__TCU_TEST_MODE */
+};
+
+/* Pad names for the pinmux subsystem */
+static const struct pinctrl_pin_desc imx35_pinctrl_pads[] = {
+       IMX_PINCTRL_PIN(MX35_PAD_CAPTURE),
+       IMX_PINCTRL_PIN(MX35_PAD_COMPARE),
+       IMX_PINCTRL_PIN(MX35_PAD_WDOG_RST),
+       IMX_PINCTRL_PIN(MX35_PAD_GPIO1_0),
+       IMX_PINCTRL_PIN(MX35_PAD_GPIO1_1),
+       IMX_PINCTRL_PIN(MX35_PAD_GPIO2_0),
+       IMX_PINCTRL_PIN(MX35_PAD_GPIO3_0),
+       IMX_PINCTRL_PIN(MX35_PAD_RESET_IN_B),
+       IMX_PINCTRL_PIN(MX35_PAD_POR_B),
+       IMX_PINCTRL_PIN(MX35_PAD_CLKO),
+       IMX_PINCTRL_PIN(MX35_PAD_BOOT_MODE0),
+       IMX_PINCTRL_PIN(MX35_PAD_BOOT_MODE1),
+       IMX_PINCTRL_PIN(MX35_PAD_CLK_MODE0),
+       IMX_PINCTRL_PIN(MX35_PAD_CLK_MODE1),
+       IMX_PINCTRL_PIN(MX35_PAD_POWER_FAIL),
+       IMX_PINCTRL_PIN(MX35_PAD_VSTBY),
+       IMX_PINCTRL_PIN(MX35_PAD_A0),
+       IMX_PINCTRL_PIN(MX35_PAD_A1),
+       IMX_PINCTRL_PIN(MX35_PAD_A2),
+       IMX_PINCTRL_PIN(MX35_PAD_A3),
+       IMX_PINCTRL_PIN(MX35_PAD_A4),
+       IMX_PINCTRL_PIN(MX35_PAD_A5),
+       IMX_PINCTRL_PIN(MX35_PAD_A6),
+       IMX_PINCTRL_PIN(MX35_PAD_A7),
+       IMX_PINCTRL_PIN(MX35_PAD_A8),
+       IMX_PINCTRL_PIN(MX35_PAD_A9),
+       IMX_PINCTRL_PIN(MX35_PAD_A10),
+       IMX_PINCTRL_PIN(MX35_PAD_MA10),
+       IMX_PINCTRL_PIN(MX35_PAD_A11),
+       IMX_PINCTRL_PIN(MX35_PAD_A12),
+       IMX_PINCTRL_PIN(MX35_PAD_A13),
+       IMX_PINCTRL_PIN(MX35_PAD_A14),
+       IMX_PINCTRL_PIN(MX35_PAD_A15),
+       IMX_PINCTRL_PIN(MX35_PAD_A16),
+       IMX_PINCTRL_PIN(MX35_PAD_A17),
+       IMX_PINCTRL_PIN(MX35_PAD_A18),
+       IMX_PINCTRL_PIN(MX35_PAD_A19),
+       IMX_PINCTRL_PIN(MX35_PAD_A20),
+       IMX_PINCTRL_PIN(MX35_PAD_A21),
+       IMX_PINCTRL_PIN(MX35_PAD_A22),
+       IMX_PINCTRL_PIN(MX35_PAD_A23),
+       IMX_PINCTRL_PIN(MX35_PAD_A24),
+       IMX_PINCTRL_PIN(MX35_PAD_A25),
+       IMX_PINCTRL_PIN(MX35_PAD_SDBA1),
+       IMX_PINCTRL_PIN(MX35_PAD_SDBA0),
+       IMX_PINCTRL_PIN(MX35_PAD_SD0),
+       IMX_PINCTRL_PIN(MX35_PAD_SD1),
+       IMX_PINCTRL_PIN(MX35_PAD_SD2),
+       IMX_PINCTRL_PIN(MX35_PAD_SD3),
+       IMX_PINCTRL_PIN(MX35_PAD_SD4),
+       IMX_PINCTRL_PIN(MX35_PAD_SD5),
+       IMX_PINCTRL_PIN(MX35_PAD_SD6),
+       IMX_PINCTRL_PIN(MX35_PAD_SD7),
+       IMX_PINCTRL_PIN(MX35_PAD_SD8),
+       IMX_PINCTRL_PIN(MX35_PAD_SD9),
+       IMX_PINCTRL_PIN(MX35_PAD_SD10),
+       IMX_PINCTRL_PIN(MX35_PAD_SD11),
+       IMX_PINCTRL_PIN(MX35_PAD_SD12),
+       IMX_PINCTRL_PIN(MX35_PAD_SD13),
+       IMX_PINCTRL_PIN(MX35_PAD_SD14),
+       IMX_PINCTRL_PIN(MX35_PAD_SD15),
+       IMX_PINCTRL_PIN(MX35_PAD_SD16),
+       IMX_PINCTRL_PIN(MX35_PAD_SD17),
+       IMX_PINCTRL_PIN(MX35_PAD_SD18),
+       IMX_PINCTRL_PIN(MX35_PAD_SD19),
+       IMX_PINCTRL_PIN(MX35_PAD_SD20),
+       IMX_PINCTRL_PIN(MX35_PAD_SD21),
+       IMX_PINCTRL_PIN(MX35_PAD_SD22),
+       IMX_PINCTRL_PIN(MX35_PAD_SD23),
+       IMX_PINCTRL_PIN(MX35_PAD_SD24),
+       IMX_PINCTRL_PIN(MX35_PAD_SD25),
+       IMX_PINCTRL_PIN(MX35_PAD_SD26),
+       IMX_PINCTRL_PIN(MX35_PAD_SD27),
+       IMX_PINCTRL_PIN(MX35_PAD_SD28),
+       IMX_PINCTRL_PIN(MX35_PAD_SD29),
+       IMX_PINCTRL_PIN(MX35_PAD_SD30),
+       IMX_PINCTRL_PIN(MX35_PAD_SD31),
+       IMX_PINCTRL_PIN(MX35_PAD_DQM0),
+       IMX_PINCTRL_PIN(MX35_PAD_DQM1),
+       IMX_PINCTRL_PIN(MX35_PAD_DQM2),
+       IMX_PINCTRL_PIN(MX35_PAD_DQM3),
+       IMX_PINCTRL_PIN(MX35_PAD_EB0),
+       IMX_PINCTRL_PIN(MX35_PAD_EB1),
+       IMX_PINCTRL_PIN(MX35_PAD_OE),
+       IMX_PINCTRL_PIN(MX35_PAD_CS0),
+       IMX_PINCTRL_PIN(MX35_PAD_CS1),
+       IMX_PINCTRL_PIN(MX35_PAD_CS2),
+       IMX_PINCTRL_PIN(MX35_PAD_CS3),
+       IMX_PINCTRL_PIN(MX35_PAD_CS4),
+       IMX_PINCTRL_PIN(MX35_PAD_CS5),
+       IMX_PINCTRL_PIN(MX35_PAD_NF_CE0),
+       IMX_PINCTRL_PIN(MX35_PAD_ECB),
+       IMX_PINCTRL_PIN(MX35_PAD_LBA),
+       IMX_PINCTRL_PIN(MX35_PAD_BCLK),
+       IMX_PINCTRL_PIN(MX35_PAD_RW),
+       IMX_PINCTRL_PIN(MX35_PAD_RAS),
+       IMX_PINCTRL_PIN(MX35_PAD_CAS),
+       IMX_PINCTRL_PIN(MX35_PAD_SDWE),
+       IMX_PINCTRL_PIN(MX35_PAD_SDCKE0),
+       IMX_PINCTRL_PIN(MX35_PAD_SDCKE1),
+       IMX_PINCTRL_PIN(MX35_PAD_SDCLK),
+       IMX_PINCTRL_PIN(MX35_PAD_SDQS0),
+       IMX_PINCTRL_PIN(MX35_PAD_SDQS1),
+       IMX_PINCTRL_PIN(MX35_PAD_SDQS2),
+       IMX_PINCTRL_PIN(MX35_PAD_SDQS3),
+       IMX_PINCTRL_PIN(MX35_PAD_NFWE_B),
+       IMX_PINCTRL_PIN(MX35_PAD_NFRE_B),
+       IMX_PINCTRL_PIN(MX35_PAD_NFALE),
+       IMX_PINCTRL_PIN(MX35_PAD_NFCLE),
+       IMX_PINCTRL_PIN(MX35_PAD_NFWP_B),
+       IMX_PINCTRL_PIN(MX35_PAD_NFRB),
+       IMX_PINCTRL_PIN(MX35_PAD_D15),
+       IMX_PINCTRL_PIN(MX35_PAD_D14),
+       IMX_PINCTRL_PIN(MX35_PAD_D13),
+       IMX_PINCTRL_PIN(MX35_PAD_D12),
+       IMX_PINCTRL_PIN(MX35_PAD_D11),
+       IMX_PINCTRL_PIN(MX35_PAD_D10),
+       IMX_PINCTRL_PIN(MX35_PAD_D9),
+       IMX_PINCTRL_PIN(MX35_PAD_D8),
+       IMX_PINCTRL_PIN(MX35_PAD_D7),
+       IMX_PINCTRL_PIN(MX35_PAD_D6),
+       IMX_PINCTRL_PIN(MX35_PAD_D5),
+       IMX_PINCTRL_PIN(MX35_PAD_D4),
+       IMX_PINCTRL_PIN(MX35_PAD_D3),
+       IMX_PINCTRL_PIN(MX35_PAD_D2),
+       IMX_PINCTRL_PIN(MX35_PAD_D1),
+       IMX_PINCTRL_PIN(MX35_PAD_D0),
+       IMX_PINCTRL_PIN(MX35_PAD_CSI_D8),
+       IMX_PINCTRL_PIN(MX35_PAD_CSI_D9),
+       IMX_PINCTRL_PIN(MX35_PAD_CSI_D10),
+       IMX_PINCTRL_PIN(MX35_PAD_CSI_D11),
+       IMX_PINCTRL_PIN(MX35_PAD_CSI_D12),
+       IMX_PINCTRL_PIN(MX35_PAD_CSI_D13),
+       IMX_PINCTRL_PIN(MX35_PAD_CSI_D14),
+       IMX_PINCTRL_PIN(MX35_PAD_CSI_D15),
+       IMX_PINCTRL_PIN(MX35_PAD_CSI_MCLK),
+       IMX_PINCTRL_PIN(MX35_PAD_CSI_VSYNC),
+       IMX_PINCTRL_PIN(MX35_PAD_CSI_HSYNC),
+       IMX_PINCTRL_PIN(MX35_PAD_CSI_PIXCLK),
+       IMX_PINCTRL_PIN(MX35_PAD_I2C1_CLK),
+       IMX_PINCTRL_PIN(MX35_PAD_I2C1_DAT),
+       IMX_PINCTRL_PIN(MX35_PAD_I2C2_CLK),
+       IMX_PINCTRL_PIN(MX35_PAD_I2C2_DAT),
+       IMX_PINCTRL_PIN(MX35_PAD_STXD4),
+       IMX_PINCTRL_PIN(MX35_PAD_SRXD4),
+       IMX_PINCTRL_PIN(MX35_PAD_SCK4),
+       IMX_PINCTRL_PIN(MX35_PAD_STXFS4),
+       IMX_PINCTRL_PIN(MX35_PAD_STXD5),
+       IMX_PINCTRL_PIN(MX35_PAD_SRXD5),
+       IMX_PINCTRL_PIN(MX35_PAD_SCK5),
+       IMX_PINCTRL_PIN(MX35_PAD_STXFS5),
+       IMX_PINCTRL_PIN(MX35_PAD_SCKR),
+       IMX_PINCTRL_PIN(MX35_PAD_FSR),
+       IMX_PINCTRL_PIN(MX35_PAD_HCKR),
+       IMX_PINCTRL_PIN(MX35_PAD_SCKT),
+       IMX_PINCTRL_PIN(MX35_PAD_FST),
+       IMX_PINCTRL_PIN(MX35_PAD_HCKT),
+       IMX_PINCTRL_PIN(MX35_PAD_TX5_RX0),
+       IMX_PINCTRL_PIN(MX35_PAD_TX4_RX1),
+       IMX_PINCTRL_PIN(MX35_PAD_TX3_RX2),
+       IMX_PINCTRL_PIN(MX35_PAD_TX2_RX3),
+       IMX_PINCTRL_PIN(MX35_PAD_TX1),
+       IMX_PINCTRL_PIN(MX35_PAD_TX0),
+       IMX_PINCTRL_PIN(MX35_PAD_CSPI1_MOSI),
+       IMX_PINCTRL_PIN(MX35_PAD_CSPI1_MISO),
+       IMX_PINCTRL_PIN(MX35_PAD_CSPI1_SS0),
+       IMX_PINCTRL_PIN(MX35_PAD_CSPI1_SS1),
+       IMX_PINCTRL_PIN(MX35_PAD_CSPI1_SCLK),
+       IMX_PINCTRL_PIN(MX35_PAD_CSPI1_SPI_RDY),
+       IMX_PINCTRL_PIN(MX35_PAD_RXD1),
+       IMX_PINCTRL_PIN(MX35_PAD_TXD1),
+       IMX_PINCTRL_PIN(MX35_PAD_RTS1),
+       IMX_PINCTRL_PIN(MX35_PAD_CTS1),
+       IMX_PINCTRL_PIN(MX35_PAD_RXD2),
+       IMX_PINCTRL_PIN(MX35_PAD_TXD2),
+       IMX_PINCTRL_PIN(MX35_PAD_RTS2),
+       IMX_PINCTRL_PIN(MX35_PAD_CTS2),
+       IMX_PINCTRL_PIN(MX35_PAD_RTCK),
+       IMX_PINCTRL_PIN(MX35_PAD_TCK),
+       IMX_PINCTRL_PIN(MX35_PAD_TMS),
+       IMX_PINCTRL_PIN(MX35_PAD_TDI),
+       IMX_PINCTRL_PIN(MX35_PAD_TDO),
+       IMX_PINCTRL_PIN(MX35_PAD_TRSTB),
+       IMX_PINCTRL_PIN(MX35_PAD_DE_B),
+       IMX_PINCTRL_PIN(MX35_PAD_SJC_MOD),
+       IMX_PINCTRL_PIN(MX35_PAD_USBOTG_PWR),
+       IMX_PINCTRL_PIN(MX35_PAD_USBOTG_OC),
+       IMX_PINCTRL_PIN(MX35_PAD_LD0),
+       IMX_PINCTRL_PIN(MX35_PAD_LD1),
+       IMX_PINCTRL_PIN(MX35_PAD_LD2),
+       IMX_PINCTRL_PIN(MX35_PAD_LD3),
+       IMX_PINCTRL_PIN(MX35_PAD_LD4),
+       IMX_PINCTRL_PIN(MX35_PAD_LD5),
+       IMX_PINCTRL_PIN(MX35_PAD_LD6),
+       IMX_PINCTRL_PIN(MX35_PAD_LD7),
+       IMX_PINCTRL_PIN(MX35_PAD_LD8),
+       IMX_PINCTRL_PIN(MX35_PAD_LD9),
+       IMX_PINCTRL_PIN(MX35_PAD_LD10),
+       IMX_PINCTRL_PIN(MX35_PAD_LD11),
+       IMX_PINCTRL_PIN(MX35_PAD_LD12),
+       IMX_PINCTRL_PIN(MX35_PAD_LD13),
+       IMX_PINCTRL_PIN(MX35_PAD_LD14),
+       IMX_PINCTRL_PIN(MX35_PAD_LD15),
+       IMX_PINCTRL_PIN(MX35_PAD_LD16),
+       IMX_PINCTRL_PIN(MX35_PAD_LD17),
+       IMX_PINCTRL_PIN(MX35_PAD_LD18),
+       IMX_PINCTRL_PIN(MX35_PAD_LD19),
+       IMX_PINCTRL_PIN(MX35_PAD_LD20),
+       IMX_PINCTRL_PIN(MX35_PAD_LD21),
+       IMX_PINCTRL_PIN(MX35_PAD_LD22),
+       IMX_PINCTRL_PIN(MX35_PAD_LD23),
+       IMX_PINCTRL_PIN(MX35_PAD_D3_HSYNC),
+       IMX_PINCTRL_PIN(MX35_PAD_D3_FPSHIFT),
+       IMX_PINCTRL_PIN(MX35_PAD_D3_DRDY),
+       IMX_PINCTRL_PIN(MX35_PAD_CONTRAST),
+       IMX_PINCTRL_PIN(MX35_PAD_D3_VSYNC),
+       IMX_PINCTRL_PIN(MX35_PAD_D3_REV),
+       IMX_PINCTRL_PIN(MX35_PAD_D3_CLS),
+       IMX_PINCTRL_PIN(MX35_PAD_D3_SPL),
+       IMX_PINCTRL_PIN(MX35_PAD_SD1_CMD),
+       IMX_PINCTRL_PIN(MX35_PAD_SD1_CLK),
+       IMX_PINCTRL_PIN(MX35_PAD_SD1_DATA0),
+       IMX_PINCTRL_PIN(MX35_PAD_SD1_DATA1),
+       IMX_PINCTRL_PIN(MX35_PAD_SD1_DATA2),
+       IMX_PINCTRL_PIN(MX35_PAD_SD1_DATA3),
+       IMX_PINCTRL_PIN(MX35_PAD_SD2_CMD),
+       IMX_PINCTRL_PIN(MX35_PAD_SD2_CLK),
+       IMX_PINCTRL_PIN(MX35_PAD_SD2_DATA0),
+       IMX_PINCTRL_PIN(MX35_PAD_SD2_DATA1),
+       IMX_PINCTRL_PIN(MX35_PAD_SD2_DATA2),
+       IMX_PINCTRL_PIN(MX35_PAD_SD2_DATA3),
+       IMX_PINCTRL_PIN(MX35_PAD_ATA_CS0),
+       IMX_PINCTRL_PIN(MX35_PAD_ATA_CS1),
+       IMX_PINCTRL_PIN(MX35_PAD_ATA_DIOR),
+       IMX_PINCTRL_PIN(MX35_PAD_ATA_DIOW),
+       IMX_PINCTRL_PIN(MX35_PAD_ATA_DMACK),
+       IMX_PINCTRL_PIN(MX35_PAD_ATA_RESET_B),
+       IMX_PINCTRL_PIN(MX35_PAD_ATA_IORDY),
+       IMX_PINCTRL_PIN(MX35_PAD_ATA_DATA0),
+       IMX_PINCTRL_PIN(MX35_PAD_ATA_DATA1),
+       IMX_PINCTRL_PIN(MX35_PAD_ATA_DATA2),
+       IMX_PINCTRL_PIN(MX35_PAD_ATA_DATA3),
+       IMX_PINCTRL_PIN(MX35_PAD_ATA_DATA4),
+       IMX_PINCTRL_PIN(MX35_PAD_ATA_DATA5),
+       IMX_PINCTRL_PIN(MX35_PAD_ATA_DATA6),
+       IMX_PINCTRL_PIN(MX35_PAD_ATA_DATA7),
+       IMX_PINCTRL_PIN(MX35_PAD_ATA_DATA8),
+       IMX_PINCTRL_PIN(MX35_PAD_ATA_DATA9),
+       IMX_PINCTRL_PIN(MX35_PAD_ATA_DATA10),
+       IMX_PINCTRL_PIN(MX35_PAD_ATA_DATA11),
+       IMX_PINCTRL_PIN(MX35_PAD_ATA_DATA12),
+       IMX_PINCTRL_PIN(MX35_PAD_ATA_DATA13),
+       IMX_PINCTRL_PIN(MX35_PAD_ATA_DATA14),
+       IMX_PINCTRL_PIN(MX35_PAD_ATA_DATA15),
+       IMX_PINCTRL_PIN(MX35_PAD_ATA_INTRQ),
+       IMX_PINCTRL_PIN(MX35_PAD_ATA_BUFF_EN),
+       IMX_PINCTRL_PIN(MX35_PAD_ATA_DMARQ),
+       IMX_PINCTRL_PIN(MX35_PAD_ATA_DA0),
+       IMX_PINCTRL_PIN(MX35_PAD_ATA_DA1),
+       IMX_PINCTRL_PIN(MX35_PAD_ATA_DA2),
+       IMX_PINCTRL_PIN(MX35_PAD_MLB_CLK),
+       IMX_PINCTRL_PIN(MX35_PAD_MLB_DAT),
+       IMX_PINCTRL_PIN(MX35_PAD_MLB_SIG),
+       IMX_PINCTRL_PIN(MX35_PAD_FEC_TX_CLK),
+       IMX_PINCTRL_PIN(MX35_PAD_FEC_RX_CLK),
+       IMX_PINCTRL_PIN(MX35_PAD_FEC_RX_DV),
+       IMX_PINCTRL_PIN(MX35_PAD_FEC_COL),
+       IMX_PINCTRL_PIN(MX35_PAD_FEC_RDATA0),
+       IMX_PINCTRL_PIN(MX35_PAD_FEC_TDATA0),
+       IMX_PINCTRL_PIN(MX35_PAD_FEC_TX_EN),
+       IMX_PINCTRL_PIN(MX35_PAD_FEC_MDC),
+       IMX_PINCTRL_PIN(MX35_PAD_FEC_MDIO),
+       IMX_PINCTRL_PIN(MX35_PAD_FEC_TX_ERR),
+       IMX_PINCTRL_PIN(MX35_PAD_FEC_RX_ERR),
+       IMX_PINCTRL_PIN(MX35_PAD_FEC_CRS),
+       IMX_PINCTRL_PIN(MX35_PAD_FEC_RDATA1),
+       IMX_PINCTRL_PIN(MX35_PAD_FEC_TDATA1),
+       IMX_PINCTRL_PIN(MX35_PAD_FEC_RDATA2),
+       IMX_PINCTRL_PIN(MX35_PAD_FEC_TDATA2),
+       IMX_PINCTRL_PIN(MX35_PAD_FEC_RDATA3),
+       IMX_PINCTRL_PIN(MX35_PAD_FEC_TDATA3),
+       IMX_PINCTRL_PIN(MX35_PAD_EXT_ARMCLK),
+       IMX_PINCTRL_PIN(MX35_PAD_TEST_MODE),
+};
+
+static struct imx_pinctrl_soc_info imx35_pinctrl_info = {
+       .pins = imx35_pinctrl_pads,
+       .npins = ARRAY_SIZE(imx35_pinctrl_pads),
+       .pin_regs = imx35_pin_regs,
+       .npin_regs = ARRAY_SIZE(imx35_pin_regs),
+};
+
+static struct of_device_id imx35_pinctrl_of_match[] __devinitdata = {
+       { .compatible = "fsl,imx35-iomuxc", },
+       { /* sentinel */ }
+};
+
+static int __devinit imx35_pinctrl_probe(struct platform_device *pdev)
+{
+       return imx_pinctrl_probe(pdev, &imx35_pinctrl_info);
+}
+
+static struct platform_driver imx35_pinctrl_driver = {
+       .driver = {
+               .name = "imx35-pinctrl",
+               .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(imx35_pinctrl_of_match),
+       },
+       .probe = imx35_pinctrl_probe,
+       .remove = __devexit_p(imx_pinctrl_remove),
+};
+
+static int __init imx35_pinctrl_init(void)
+{
+       return platform_driver_register(&imx35_pinctrl_driver);
+}
+arch_initcall(imx35_pinctrl_init);
+
+static void __exit imx35_pinctrl_exit(void)
+{
+       platform_driver_unregister(&imx35_pinctrl_driver);
+}
+module_exit(imx35_pinctrl_exit);
+MODULE_AUTHOR("Dong Aisheng <dong.aisheng@linaro.org>");
+MODULE_DESCRIPTION("Freescale IMX35 pinctrl driver");
+MODULE_LICENSE("GPL v2");
index 689b3c88dd2e723be68c5fd83a8bca99e9be78e8..fb846896677972f09e7a69661a469ea390d397c7 100644 (file)
 #include "pinctrl-imx.h"
 
 enum imx51_pads {
-       MX51_PAD_EIM_D16 = 1,
-       MX51_PAD_EIM_D17 = 2,
-       MX51_PAD_EIM_D18 = 3,
-       MX51_PAD_EIM_D19 = 4,
-       MX51_PAD_EIM_D20 = 5,
-       MX51_PAD_EIM_D21 = 6,
-       MX51_PAD_EIM_D22 = 7,
-       MX51_PAD_EIM_D23 = 8,
-       MX51_PAD_EIM_D24 = 9,
-       MX51_PAD_EIM_D25 = 10,
-       MX51_PAD_EIM_D26 = 11,
-       MX51_PAD_EIM_D27 = 12,
-       MX51_PAD_EIM_D28 = 13,
-       MX51_PAD_EIM_D29 = 14,
-       MX51_PAD_EIM_D30 = 15,
-       MX51_PAD_EIM_D31 = 16,
-       MX51_PAD_EIM_A16 = 17,
-       MX51_PAD_EIM_A17 = 18,
-       MX51_PAD_EIM_A18 = 19,
-       MX51_PAD_EIM_A19 = 20,
-       MX51_PAD_EIM_A20 = 21,
-       MX51_PAD_EIM_A21 = 22,
-       MX51_PAD_EIM_A22 = 23,
-       MX51_PAD_EIM_A23 = 24,
-       MX51_PAD_EIM_A24 = 25,
-       MX51_PAD_EIM_A25 = 26,
-       MX51_PAD_EIM_A26 = 27,
-       MX51_PAD_EIM_A27 = 28,
-       MX51_PAD_EIM_EB0 = 29,
-       MX51_PAD_EIM_EB1 = 30,
-       MX51_PAD_EIM_EB2 = 31,
-       MX51_PAD_EIM_EB3 = 32,
-       MX51_PAD_EIM_OE = 33,
-       MX51_PAD_EIM_CS0 = 34,
-       MX51_PAD_EIM_CS1 = 35,
-       MX51_PAD_EIM_CS2 = 36,
-       MX51_PAD_EIM_CS3 = 37,
-       MX51_PAD_EIM_CS4 = 38,
-       MX51_PAD_EIM_CS5 = 39,
-       MX51_PAD_EIM_DTACK = 40,
-       MX51_PAD_EIM_LBA = 41,
-       MX51_PAD_EIM_CRE = 42,
-       MX51_PAD_DRAM_CS1 = 43,
-       MX51_PAD_NANDF_WE_B = 44,
-       MX51_PAD_NANDF_RE_B = 45,
-       MX51_PAD_NANDF_ALE = 46,
-       MX51_PAD_NANDF_CLE = 47,
-       MX51_PAD_NANDF_WP_B = 48,
-       MX51_PAD_NANDF_RB0 = 49,
-       MX51_PAD_NANDF_RB1 = 50,
-       MX51_PAD_NANDF_RB2 = 51,
-       MX51_PAD_NANDF_RB3 = 52,
-       MX51_PAD_GPIO_NAND = 53,
-       MX51_PAD_NANDF_CS0 = 54,
-       MX51_PAD_NANDF_CS1 = 55,
-       MX51_PAD_NANDF_CS2 = 56,
-       MX51_PAD_NANDF_CS3 = 57,
-       MX51_PAD_NANDF_CS4 = 58,
-       MX51_PAD_NANDF_CS5 = 59,
-       MX51_PAD_NANDF_CS6 = 60,
-       MX51_PAD_NANDF_CS7 = 61,
-       MX51_PAD_NANDF_RDY_INT = 62,
-       MX51_PAD_NANDF_D15 = 63,
-       MX51_PAD_NANDF_D14 = 64,
-       MX51_PAD_NANDF_D13 = 65,
-       MX51_PAD_NANDF_D12 = 66,
-       MX51_PAD_NANDF_D11 = 67,
-       MX51_PAD_NANDF_D10 = 68,
-       MX51_PAD_NANDF_D9 = 69,
-       MX51_PAD_NANDF_D8 = 70,
-       MX51_PAD_NANDF_D7 = 71,
-       MX51_PAD_NANDF_D6 = 72,
-       MX51_PAD_NANDF_D5 = 73,
-       MX51_PAD_NANDF_D4 = 74,
-       MX51_PAD_NANDF_D3 = 75,
-       MX51_PAD_NANDF_D2 = 76,
-       MX51_PAD_NANDF_D1 = 77,
-       MX51_PAD_NANDF_D0 = 78,
-       MX51_PAD_CSI1_D8 = 79,
-       MX51_PAD_CSI1_D9 = 80,
-       MX51_PAD_CSI1_D10 = 81,
-       MX51_PAD_CSI1_D11 = 82,
-       MX51_PAD_CSI1_D12 = 83,
-       MX51_PAD_CSI1_D13 = 84,
-       MX51_PAD_CSI1_D14 = 85,
-       MX51_PAD_CSI1_D15 = 86,
-       MX51_PAD_CSI1_D16 = 87,
-       MX51_PAD_CSI1_D17 = 88,
-       MX51_PAD_CSI1_D18 = 89,
-       MX51_PAD_CSI1_D19 = 90,
-       MX51_PAD_CSI1_VSYNC = 91,
-       MX51_PAD_CSI1_HSYNC = 92,
-       MX51_PAD_CSI1_PIXCLK = 93,
-       MX51_PAD_CSI1_MCLK = 94,
-       MX51_PAD_CSI2_D12 = 95,
-       MX51_PAD_CSI2_D13 = 96,
-       MX51_PAD_CSI2_D14 = 97,
-       MX51_PAD_CSI2_D15 = 98,
-       MX51_PAD_CSI2_D16 = 99,
-       MX51_PAD_CSI2_D17 = 100,
-       MX51_PAD_CSI2_D18 = 101,
-       MX51_PAD_CSI2_D19 = 102,
-       MX51_PAD_CSI2_VSYNC = 103,
-       MX51_PAD_CSI2_HSYNC = 104,
-       MX51_PAD_CSI2_PIXCLK = 105,
-       MX51_PAD_I2C1_CLK = 106,
-       MX51_PAD_I2C1_DAT = 107,
-       MX51_PAD_AUD3_BB_TXD = 108,
-       MX51_PAD_AUD3_BB_RXD = 109,
-       MX51_PAD_AUD3_BB_CK = 110,
-       MX51_PAD_AUD3_BB_FS = 111,
-       MX51_PAD_CSPI1_MOSI = 112,
-       MX51_PAD_CSPI1_MISO = 113,
-       MX51_PAD_CSPI1_SS0 = 114,
-       MX51_PAD_CSPI1_SS1 = 115,
-       MX51_PAD_CSPI1_RDY = 116,
-       MX51_PAD_CSPI1_SCLK = 117,
-       MX51_PAD_UART1_RXD = 118,
-       MX51_PAD_UART1_TXD = 119,
-       MX51_PAD_UART1_RTS = 120,
-       MX51_PAD_UART1_CTS = 121,
-       MX51_PAD_UART2_RXD = 122,
-       MX51_PAD_UART2_TXD = 123,
-       MX51_PAD_UART3_RXD = 124,
-       MX51_PAD_UART3_TXD = 125,
-       MX51_PAD_OWIRE_LINE = 126,
-       MX51_PAD_KEY_ROW0 = 127,
-       MX51_PAD_KEY_ROW1 = 128,
-       MX51_PAD_KEY_ROW2 = 129,
-       MX51_PAD_KEY_ROW3 = 130,
-       MX51_PAD_KEY_COL0 = 131,
-       MX51_PAD_KEY_COL1 = 132,
-       MX51_PAD_KEY_COL2 = 133,
-       MX51_PAD_KEY_COL3 = 134,
-       MX51_PAD_KEY_COL4 = 135,
-       MX51_PAD_KEY_COL5 = 136,
-       MX51_PAD_USBH1_CLK = 137,
-       MX51_PAD_USBH1_DIR = 138,
-       MX51_PAD_USBH1_STP = 139,
-       MX51_PAD_USBH1_NXT = 140,
-       MX51_PAD_USBH1_DATA0 = 141,
-       MX51_PAD_USBH1_DATA1 = 142,
-       MX51_PAD_USBH1_DATA2 = 143,
-       MX51_PAD_USBH1_DATA3 = 144,
-       MX51_PAD_USBH1_DATA4 = 145,
-       MX51_PAD_USBH1_DATA5 = 146,
-       MX51_PAD_USBH1_DATA6 = 147,
-       MX51_PAD_USBH1_DATA7 = 148,
-       MX51_PAD_DI1_PIN11 = 149,
-       MX51_PAD_DI1_PIN12 = 150,
-       MX51_PAD_DI1_PIN13 = 151,
-       MX51_PAD_DI1_D0_CS = 152,
-       MX51_PAD_DI1_D1_CS = 153,
-       MX51_PAD_DISPB2_SER_DIN = 154,
-       MX51_PAD_DISPB2_SER_DIO = 155,
-       MX51_PAD_DISPB2_SER_CLK = 156,
-       MX51_PAD_DISPB2_SER_RS = 157,
-       MX51_PAD_DISP1_DAT0 = 158,
-       MX51_PAD_DISP1_DAT1 = 159,
-       MX51_PAD_DISP1_DAT2 = 160,
-       MX51_PAD_DISP1_DAT3 = 161,
-       MX51_PAD_DISP1_DAT4 = 162,
-       MX51_PAD_DISP1_DAT5 = 163,
-       MX51_PAD_DISP1_DAT6 = 164,
-       MX51_PAD_DISP1_DAT7 = 165,
-       MX51_PAD_DISP1_DAT8 = 166,
-       MX51_PAD_DISP1_DAT9 = 167,
-       MX51_PAD_DISP1_DAT10 = 168,
-       MX51_PAD_DISP1_DAT11 = 169,
-       MX51_PAD_DISP1_DAT12 = 170,
-       MX51_PAD_DISP1_DAT13 = 171,
-       MX51_PAD_DISP1_DAT14 = 172,
-       MX51_PAD_DISP1_DAT15 = 173,
-       MX51_PAD_DISP1_DAT16 = 174,
-       MX51_PAD_DISP1_DAT17 = 175,
-       MX51_PAD_DISP1_DAT18 = 176,
-       MX51_PAD_DISP1_DAT19 = 177,
-       MX51_PAD_DISP1_DAT20 = 178,
-       MX51_PAD_DISP1_DAT21 = 179,
-       MX51_PAD_DISP1_DAT22 = 180,
-       MX51_PAD_DISP1_DAT23 = 181,
-       MX51_PAD_DI1_PIN3 = 182,
-       MX51_PAD_DI1_PIN2 = 183,
-       MX51_PAD_DI_GP2 = 184,
-       MX51_PAD_DI_GP3 = 185,
-       MX51_PAD_DI2_PIN4 = 186,
-       MX51_PAD_DI2_PIN2 = 187,
-       MX51_PAD_DI2_PIN3 = 188,
-       MX51_PAD_DI2_DISP_CLK = 189,
-       MX51_PAD_DI_GP4 = 190,
-       MX51_PAD_DISP2_DAT0 = 191,
-       MX51_PAD_DISP2_DAT1 = 192,
-       MX51_PAD_DISP2_DAT2 = 193,
-       MX51_PAD_DISP2_DAT3 = 194,
-       MX51_PAD_DISP2_DAT4 = 195,
-       MX51_PAD_DISP2_DAT5 = 196,
-       MX51_PAD_DISP2_DAT6 = 197,
-       MX51_PAD_DISP2_DAT7 = 198,
-       MX51_PAD_DISP2_DAT8 = 199,
-       MX51_PAD_DISP2_DAT9 = 200,
-       MX51_PAD_DISP2_DAT10 = 201,
-       MX51_PAD_DISP2_DAT11 = 202,
-       MX51_PAD_DISP2_DAT12 = 203,
-       MX51_PAD_DISP2_DAT13 = 204,
-       MX51_PAD_DISP2_DAT14 = 205,
-       MX51_PAD_DISP2_DAT15 = 206,
-       MX51_PAD_SD1_CMD = 207,
-       MX51_PAD_SD1_CLK = 208,
-       MX51_PAD_SD1_DATA0 = 209,
-       MX51_PAD_EIM_DA0 = 210,
-       MX51_PAD_EIM_DA1 = 211,
-       MX51_PAD_EIM_DA2 = 212,
-       MX51_PAD_EIM_DA3 = 213,
-       MX51_PAD_SD1_DATA1 = 214,
-       MX51_PAD_EIM_DA4 = 215,
-       MX51_PAD_EIM_DA5 = 216,
-       MX51_PAD_EIM_DA6 = 217,
-       MX51_PAD_EIM_DA7 = 218,
-       MX51_PAD_SD1_DATA2 = 219,
-       MX51_PAD_EIM_DA10 = 220,
-       MX51_PAD_EIM_DA11 = 221,
-       MX51_PAD_EIM_DA8 = 222,
-       MX51_PAD_EIM_DA9 = 223,
-       MX51_PAD_SD1_DATA3 = 224,
-       MX51_PAD_GPIO1_0 = 225,
-       MX51_PAD_GPIO1_1 = 226,
-       MX51_PAD_EIM_DA12 = 227,
-       MX51_PAD_EIM_DA13 = 228,
-       MX51_PAD_EIM_DA14 = 229,
-       MX51_PAD_EIM_DA15 = 230,
-       MX51_PAD_SD2_CMD = 231,
-       MX51_PAD_SD2_CLK = 232,
-       MX51_PAD_SD2_DATA0 = 233,
-       MX51_PAD_SD2_DATA1 = 234,
-       MX51_PAD_SD2_DATA2 = 235,
-       MX51_PAD_SD2_DATA3 = 236,
-       MX51_PAD_GPIO1_2 = 237,
-       MX51_PAD_GPIO1_3 = 238,
-       MX51_PAD_PMIC_INT_REQ = 239,
-       MX51_PAD_GPIO1_4 = 240,
-       MX51_PAD_GPIO1_5 = 241,
-       MX51_PAD_GPIO1_6 = 242,
-       MX51_PAD_GPIO1_7 = 243,
-       MX51_PAD_GPIO1_8 = 244,
-       MX51_PAD_GPIO1_9 = 245,
+       MX51_PAD_EIM_D16 = 0,
+       MX51_PAD_EIM_D17 = 1,
+       MX51_PAD_EIM_D18 = 2,
+       MX51_PAD_EIM_D19 = 3,
+       MX51_PAD_EIM_D20 = 4,
+       MX51_PAD_EIM_D21 = 5,
+       MX51_PAD_EIM_D22 = 6,
+       MX51_PAD_EIM_D23 = 7,
+       MX51_PAD_EIM_D24 = 8,
+       MX51_PAD_EIM_D25 = 9,
+       MX51_PAD_EIM_D26 = 10,
+       MX51_PAD_EIM_D27 = 11,
+       MX51_PAD_EIM_D28 = 12,
+       MX51_PAD_EIM_D29 = 13,
+       MX51_PAD_EIM_D30 = 14,
+       MX51_PAD_EIM_D31 = 15,
+       MX51_PAD_EIM_A16 = 16,
+       MX51_PAD_EIM_A17 = 17,
+       MX51_PAD_EIM_A18 = 18,
+       MX51_PAD_EIM_A19 = 19,
+       MX51_PAD_EIM_A20 = 20,
+       MX51_PAD_EIM_A21 = 21,
+       MX51_PAD_EIM_A22 = 22,
+       MX51_PAD_EIM_A23 = 23,
+       MX51_PAD_EIM_A24 = 24,
+       MX51_PAD_EIM_A25 = 25,
+       MX51_PAD_EIM_A26 = 26,
+       MX51_PAD_EIM_A27 = 27,
+       MX51_PAD_EIM_EB0 = 28,
+       MX51_PAD_EIM_EB1 = 29,
+       MX51_PAD_EIM_EB2 = 30,
+       MX51_PAD_EIM_EB3 = 31,
+       MX51_PAD_EIM_OE = 32,
+       MX51_PAD_EIM_CS0 = 33,
+       MX51_PAD_EIM_CS1 = 34,
+       MX51_PAD_EIM_CS2 = 35,
+       MX51_PAD_EIM_CS3 = 36,
+       MX51_PAD_EIM_CS4 = 37,
+       MX51_PAD_EIM_CS5 = 38,
+       MX51_PAD_EIM_DTACK = 39,
+       MX51_PAD_EIM_LBA = 40,
+       MX51_PAD_EIM_CRE = 41,
+       MX51_PAD_DRAM_CS1 = 42,
+       MX51_PAD_NANDF_WE_B = 43,
+       MX51_PAD_NANDF_RE_B = 44,
+       MX51_PAD_NANDF_ALE = 45,
+       MX51_PAD_NANDF_CLE = 46,
+       MX51_PAD_NANDF_WP_B = 47,
+       MX51_PAD_NANDF_RB0 = 48,
+       MX51_PAD_NANDF_RB1 = 49,
+       MX51_PAD_NANDF_RB2 = 50,
+       MX51_PAD_NANDF_RB3 = 51,
+       MX51_PAD_GPIO_NAND = 52,
+       MX51_PAD_NANDF_CS0 = 53,
+       MX51_PAD_NANDF_CS1 = 54,
+       MX51_PAD_NANDF_CS2 = 55,
+       MX51_PAD_NANDF_CS3 = 56,
+       MX51_PAD_NANDF_CS4 = 57,
+       MX51_PAD_NANDF_CS5 = 58,
+       MX51_PAD_NANDF_CS6 = 59,
+       MX51_PAD_NANDF_CS7 = 60,
+       MX51_PAD_NANDF_RDY_INT = 61,
+       MX51_PAD_NANDF_D15 = 62,
+       MX51_PAD_NANDF_D14 = 63,
+       MX51_PAD_NANDF_D13 = 64,
+       MX51_PAD_NANDF_D12 = 65,
+       MX51_PAD_NANDF_D11 = 66,
+       MX51_PAD_NANDF_D10 = 67,
+       MX51_PAD_NANDF_D9 = 68,
+       MX51_PAD_NANDF_D8 = 69,
+       MX51_PAD_NANDF_D7 = 70,
+       MX51_PAD_NANDF_D6 = 71,
+       MX51_PAD_NANDF_D5 = 72,
+       MX51_PAD_NANDF_D4 = 73,
+       MX51_PAD_NANDF_D3 = 74,
+       MX51_PAD_NANDF_D2 = 75,
+       MX51_PAD_NANDF_D1 = 76,
+       MX51_PAD_NANDF_D0 = 77,
+       MX51_PAD_CSI1_D8 = 78,
+       MX51_PAD_CSI1_D9 = 79,
+       MX51_PAD_CSI1_D10 = 80,
+       MX51_PAD_CSI1_D11 = 81,
+       MX51_PAD_CSI1_D12 = 82,
+       MX51_PAD_CSI1_D13 = 83,
+       MX51_PAD_CSI1_D14 = 84,
+       MX51_PAD_CSI1_D15 = 85,
+       MX51_PAD_CSI1_D16 = 86,
+       MX51_PAD_CSI1_D17 = 87,
+       MX51_PAD_CSI1_D18 = 88,
+       MX51_PAD_CSI1_D19 = 89,
+       MX51_PAD_CSI1_VSYNC = 90,
+       MX51_PAD_CSI1_HSYNC = 91,
+       MX51_PAD_CSI1_PIXCLK = 92,
+       MX51_PAD_CSI1_MCLK = 93,
+       MX51_PAD_CSI2_D12 = 94,
+       MX51_PAD_CSI2_D13 = 95,
+       MX51_PAD_CSI2_D14 = 96,
+       MX51_PAD_CSI2_D15 = 97,
+       MX51_PAD_CSI2_D16 = 98,
+       MX51_PAD_CSI2_D17 = 99,
+       MX51_PAD_CSI2_D18 = 100,
+       MX51_PAD_CSI2_D19 = 101,
+       MX51_PAD_CSI2_VSYNC = 102,
+       MX51_PAD_CSI2_HSYNC = 103,
+       MX51_PAD_CSI2_PIXCLK = 104,
+       MX51_PAD_I2C1_CLK = 105,
+       MX51_PAD_I2C1_DAT = 106,
+       MX51_PAD_AUD3_BB_TXD = 107,
+       MX51_PAD_AUD3_BB_RXD = 108,
+       MX51_PAD_AUD3_BB_CK = 109,
+       MX51_PAD_AUD3_BB_FS = 110,
+       MX51_PAD_CSPI1_MOSI = 111,
+       MX51_PAD_CSPI1_MISO = 112,
+       MX51_PAD_CSPI1_SS0 = 113,
+       MX51_PAD_CSPI1_SS1 = 114,
+       MX51_PAD_CSPI1_RDY = 115,
+       MX51_PAD_CSPI1_SCLK = 116,
+       MX51_PAD_UART1_RXD = 117,
+       MX51_PAD_UART1_TXD = 118,
+       MX51_PAD_UART1_RTS = 119,
+       MX51_PAD_UART1_CTS = 120,
+       MX51_PAD_UART2_RXD = 121,
+       MX51_PAD_UART2_TXD = 122,
+       MX51_PAD_UART3_RXD = 123,
+       MX51_PAD_UART3_TXD = 124,
+       MX51_PAD_OWIRE_LINE = 125,
+       MX51_PAD_KEY_ROW0 = 126,
+       MX51_PAD_KEY_ROW1 = 127,
+       MX51_PAD_KEY_ROW2 = 128,
+       MX51_PAD_KEY_ROW3 = 129,
+       MX51_PAD_KEY_COL0 = 130,
+       MX51_PAD_KEY_COL1 = 131,
+       MX51_PAD_KEY_COL2 = 132,
+       MX51_PAD_KEY_COL3 = 133,
+       MX51_PAD_KEY_COL4 = 134,
+       MX51_PAD_KEY_COL5 = 135,
+       MX51_PAD_USBH1_CLK = 136,
+       MX51_PAD_USBH1_DIR = 137,
+       MX51_PAD_USBH1_STP = 138,
+       MX51_PAD_USBH1_NXT = 139,
+       MX51_PAD_USBH1_DATA0 = 140,
+       MX51_PAD_USBH1_DATA1 = 141,
+       MX51_PAD_USBH1_DATA2 = 142,
+       MX51_PAD_USBH1_DATA3 = 143,
+       MX51_PAD_USBH1_DATA4 = 144,
+       MX51_PAD_USBH1_DATA5 = 145,
+       MX51_PAD_USBH1_DATA6 = 146,
+       MX51_PAD_USBH1_DATA7 = 147,
+       MX51_PAD_DI1_PIN11 = 148,
+       MX51_PAD_DI1_PIN12 = 149,
+       MX51_PAD_DI1_PIN13 = 150,
+       MX51_PAD_DI1_D0_CS = 151,
+       MX51_PAD_DI1_D1_CS = 152,
+       MX51_PAD_DISPB2_SER_DIN = 153,
+       MX51_PAD_DISPB2_SER_DIO = 154,
+       MX51_PAD_DISPB2_SER_CLK = 155,
+       MX51_PAD_DISPB2_SER_RS = 156,
+       MX51_PAD_DISP1_DAT0 = 157,
+       MX51_PAD_DISP1_DAT1 = 158,
+       MX51_PAD_DISP1_DAT2 = 159,
+       MX51_PAD_DISP1_DAT3 = 160,
+       MX51_PAD_DISP1_DAT4 = 161,
+       MX51_PAD_DISP1_DAT5 = 162,
+       MX51_PAD_DISP1_DAT6 = 163,
+       MX51_PAD_DISP1_DAT7 = 164,
+       MX51_PAD_DISP1_DAT8 = 165,
+       MX51_PAD_DISP1_DAT9 = 166,
+       MX51_PAD_DISP1_DAT10 = 167,
+       MX51_PAD_DISP1_DAT11 = 168,
+       MX51_PAD_DISP1_DAT12 = 169,
+       MX51_PAD_DISP1_DAT13 = 170,
+       MX51_PAD_DISP1_DAT14 = 171,
+       MX51_PAD_DISP1_DAT15 = 172,
+       MX51_PAD_DISP1_DAT16 = 173,
+       MX51_PAD_DISP1_DAT17 = 174,
+       MX51_PAD_DISP1_DAT18 = 175,
+       MX51_PAD_DISP1_DAT19 = 176,
+       MX51_PAD_DISP1_DAT20 = 177,
+       MX51_PAD_DISP1_DAT21 = 178,
+       MX51_PAD_DISP1_DAT22 = 179,
+       MX51_PAD_DISP1_DAT23 = 180,
+       MX51_PAD_DI1_PIN3 = 181,
+       MX51_PAD_DI1_PIN2 = 182,
+       MX51_PAD_DI_GP2 = 183,
+       MX51_PAD_DI_GP3 = 184,
+       MX51_PAD_DI2_PIN4 = 185,
+       MX51_PAD_DI2_PIN2 = 186,
+       MX51_PAD_DI2_PIN3 = 187,
+       MX51_PAD_DI2_DISP_CLK = 188,
+       MX51_PAD_DI_GP4 = 189,
+       MX51_PAD_DISP2_DAT0 = 190,
+       MX51_PAD_DISP2_DAT1 = 191,
+       MX51_PAD_DISP2_DAT2 = 192,
+       MX51_PAD_DISP2_DAT3 = 193,
+       MX51_PAD_DISP2_DAT4 = 194,
+       MX51_PAD_DISP2_DAT5 = 195,
+       MX51_PAD_DISP2_DAT6 = 196,
+       MX51_PAD_DISP2_DAT7 = 197,
+       MX51_PAD_DISP2_DAT8 = 198,
+       MX51_PAD_DISP2_DAT9 = 199,
+       MX51_PAD_DISP2_DAT10 = 200,
+       MX51_PAD_DISP2_DAT11 = 201,
+       MX51_PAD_DISP2_DAT12 = 202,
+       MX51_PAD_DISP2_DAT13 = 203,
+       MX51_PAD_DISP2_DAT14 = 204,
+       MX51_PAD_DISP2_DAT15 = 205,
+       MX51_PAD_SD1_CMD = 206,
+       MX51_PAD_SD1_CLK = 207,
+       MX51_PAD_SD1_DATA0 = 208,
+       MX51_PAD_EIM_DA0 = 209,
+       MX51_PAD_EIM_DA1 = 210,
+       MX51_PAD_EIM_DA2 = 211,
+       MX51_PAD_EIM_DA3 = 212,
+       MX51_PAD_SD1_DATA1 = 213,
+       MX51_PAD_EIM_DA4 = 214,
+       MX51_PAD_EIM_DA5 = 215,
+       MX51_PAD_EIM_DA6 = 216,
+       MX51_PAD_EIM_DA7 = 217,
+       MX51_PAD_SD1_DATA2 = 218,
+       MX51_PAD_EIM_DA10 = 219,
+       MX51_PAD_EIM_DA11 = 220,
+       MX51_PAD_EIM_DA8 = 221,
+       MX51_PAD_EIM_DA9 = 222,
+       MX51_PAD_SD1_DATA3 = 223,
+       MX51_PAD_GPIO1_0 = 224,
+       MX51_PAD_GPIO1_1 = 225,
+       MX51_PAD_EIM_DA12 = 226,
+       MX51_PAD_EIM_DA13 = 227,
+       MX51_PAD_EIM_DA14 = 228,
+       MX51_PAD_EIM_DA15 = 229,
+       MX51_PAD_SD2_CMD = 230,
+       MX51_PAD_SD2_CLK = 231,
+       MX51_PAD_SD2_DATA0 = 232,
+       MX51_PAD_SD2_DATA1 = 233,
+       MX51_PAD_SD2_DATA2 = 234,
+       MX51_PAD_SD2_DATA3 = 235,
+       MX51_PAD_GPIO1_2 = 236,
+       MX51_PAD_GPIO1_3 = 237,
+       MX51_PAD_PMIC_INT_REQ = 238,
+       MX51_PAD_GPIO1_4 = 239,
+       MX51_PAD_GPIO1_5 = 240,
+       MX51_PAD_GPIO1_6 = 241,
+       MX51_PAD_GPIO1_7 = 242,
+       MX51_PAD_GPIO1_8 = 243,
+       MX51_PAD_GPIO1_9 = 244,
 };
 
 /* imx51 register maps */
@@ -974,7 +974,7 @@ static struct imx_pin_reg imx51_pin_regs[] = {
        IMX_PIN_REG(MX51_PAD_EIM_DA13, NO_PAD, 0x050, 0, 0x000, 0), /* MX51_PAD_EIM_DA13__EIM_DA13 */
        IMX_PIN_REG(MX51_PAD_EIM_DA14, NO_PAD, 0x054, 0, 0x000, 0), /* MX51_PAD_EIM_DA14__EIM_DA14 */
        IMX_PIN_REG(MX51_PAD_EIM_DA15, NO_PAD, 0x058, 0, 0x000, 0), /* MX51_PAD_EIM_DA15__EIM_DA15 */
-       IMX_PIN_REG(MX51_PAD_SD2_CMD, NO_PAD, 0x3b4, 2, 0x91c, 3), /* MX51_PAD_SD2_CMD__CSPI_MOSI */
+       IMX_PIN_REG(MX51_PAD_SD2_CMD, 0x7bc, 0x3b4, 2, 0x91c, 3), /* MX51_PAD_SD2_CMD__CSPI_MOSI */
        IMX_PIN_REG(MX51_PAD_SD2_CMD, 0x7bc, 0x3b4, 1, 0x9b0, 2), /* MX51_PAD_SD2_CMD__I2C1_SCL */
        IMX_PIN_REG(MX51_PAD_SD2_CMD, 0x7bc, 0x3b4, 0, 0x000, 0), /* MX51_PAD_SD2_CMD__SD2_CMD */
        IMX_PIN_REG(MX51_PAD_SD2_CLK, 0x7c0, 0x3b8, 2, 0x914, 3), /* MX51_PAD_SD2_CLK__CSPI_SCLK */
index 1f49e16a9bcd6afd31fe5282b267404f2d6ee22a..783feb1ce064ef50bfc498f29045b5589498c7de 100644 (file)
 #include "pinctrl-imx.h"
 
 enum imx53_pads {
-       MX53_PAD_GPIO_19 = 1,
-       MX53_PAD_KEY_COL0 = 2,
-       MX53_PAD_KEY_ROW0 = 3,
-       MX53_PAD_KEY_COL1 = 4,
-       MX53_PAD_KEY_ROW1 = 5,
-       MX53_PAD_KEY_COL2 = 6,
-       MX53_PAD_KEY_ROW2 = 7,
-       MX53_PAD_KEY_COL3 = 8,
-       MX53_PAD_KEY_ROW3 = 9,
-       MX53_PAD_KEY_COL4 = 10,
-       MX53_PAD_KEY_ROW4 = 11,
-       MX53_PAD_DI0_DISP_CLK = 12,
-       MX53_PAD_DI0_PIN15 = 13,
-       MX53_PAD_DI0_PIN2 = 14,
-       MX53_PAD_DI0_PIN3 = 15,
-       MX53_PAD_DI0_PIN4 = 16,
-       MX53_PAD_DISP0_DAT0 = 17,
-       MX53_PAD_DISP0_DAT1 = 18,
-       MX53_PAD_DISP0_DAT2 = 19,
-       MX53_PAD_DISP0_DAT3 = 20,
-       MX53_PAD_DISP0_DAT4 = 21,
-       MX53_PAD_DISP0_DAT5 = 22,
-       MX53_PAD_DISP0_DAT6 = 23,
-       MX53_PAD_DISP0_DAT7 = 24,
-       MX53_PAD_DISP0_DAT8 = 25,
-       MX53_PAD_DISP0_DAT9 = 26,
-       MX53_PAD_DISP0_DAT10 = 27,
-       MX53_PAD_DISP0_DAT11 = 28,
-       MX53_PAD_DISP0_DAT12 = 29,
-       MX53_PAD_DISP0_DAT13 = 30,
-       MX53_PAD_DISP0_DAT14 = 31,
-       MX53_PAD_DISP0_DAT15 = 32,
-       MX53_PAD_DISP0_DAT16 = 33,
-       MX53_PAD_DISP0_DAT17 = 34,
-       MX53_PAD_DISP0_DAT18 = 35,
-       MX53_PAD_DISP0_DAT19 = 36,
-       MX53_PAD_DISP0_DAT20 = 37,
-       MX53_PAD_DISP0_DAT21 = 38,
-       MX53_PAD_DISP0_DAT22 = 39,
-       MX53_PAD_DISP0_DAT23 = 40,
-       MX53_PAD_CSI0_PIXCLK = 41,
-       MX53_PAD_CSI0_MCLK = 42,
-       MX53_PAD_CSI0_DATA_EN = 43,
-       MX53_PAD_CSI0_VSYNC = 44,
-       MX53_PAD_CSI0_DAT4 = 45,
-       MX53_PAD_CSI0_DAT5 = 46,
-       MX53_PAD_CSI0_DAT6 = 47,
-       MX53_PAD_CSI0_DAT7 = 48,
-       MX53_PAD_CSI0_DAT8 = 49,
-       MX53_PAD_CSI0_DAT9 = 50,
-       MX53_PAD_CSI0_DAT10 = 51,
-       MX53_PAD_CSI0_DAT11 = 52,
-       MX53_PAD_CSI0_DAT12 = 53,
-       MX53_PAD_CSI0_DAT13 = 54,
-       MX53_PAD_CSI0_DAT14 = 55,
-       MX53_PAD_CSI0_DAT15 = 56,
-       MX53_PAD_CSI0_DAT16 = 57,
-       MX53_PAD_CSI0_DAT17 = 58,
-       MX53_PAD_CSI0_DAT18 = 59,
-       MX53_PAD_CSI0_DAT19 = 60,
-       MX53_PAD_EIM_A25 = 61,
-       MX53_PAD_EIM_EB2 = 62,
-       MX53_PAD_EIM_D16 = 63,
-       MX53_PAD_EIM_D17 = 64,
-       MX53_PAD_EIM_D18 = 65,
-       MX53_PAD_EIM_D19 = 66,
-       MX53_PAD_EIM_D20 = 67,
-       MX53_PAD_EIM_D21 = 68,
-       MX53_PAD_EIM_D22 = 69,
-       MX53_PAD_EIM_D23 = 70,
-       MX53_PAD_EIM_EB3 = 71,
-       MX53_PAD_EIM_D24 = 72,
-       MX53_PAD_EIM_D25 = 73,
-       MX53_PAD_EIM_D26 = 74,
-       MX53_PAD_EIM_D27 = 75,
-       MX53_PAD_EIM_D28 = 76,
-       MX53_PAD_EIM_D29 = 77,
-       MX53_PAD_EIM_D30 = 78,
-       MX53_PAD_EIM_D31 = 79,
-       MX53_PAD_EIM_A24 = 80,
-       MX53_PAD_EIM_A23 = 81,
-       MX53_PAD_EIM_A22 = 82,
-       MX53_PAD_EIM_A21 = 83,
-       MX53_PAD_EIM_A20 = 84,
-       MX53_PAD_EIM_A19 = 85,
-       MX53_PAD_EIM_A18 = 86,
-       MX53_PAD_EIM_A17 = 87,
-       MX53_PAD_EIM_A16 = 88,
-       MX53_PAD_EIM_CS0 = 89,
-       MX53_PAD_EIM_CS1 = 90,
-       MX53_PAD_EIM_OE = 91,
-       MX53_PAD_EIM_RW = 92,
-       MX53_PAD_EIM_LBA = 93,
-       MX53_PAD_EIM_EB0 = 94,
-       MX53_PAD_EIM_EB1 = 95,
-       MX53_PAD_EIM_DA0 = 96,
-       MX53_PAD_EIM_DA1 = 97,
-       MX53_PAD_EIM_DA2 = 98,
-       MX53_PAD_EIM_DA3 = 99,
-       MX53_PAD_EIM_DA4 = 100,
-       MX53_PAD_EIM_DA5 = 101,
-       MX53_PAD_EIM_DA6 = 102,
-       MX53_PAD_EIM_DA7 = 103,
-       MX53_PAD_EIM_DA8 = 104,
-       MX53_PAD_EIM_DA9 = 105,
-       MX53_PAD_EIM_DA10 = 106,
-       MX53_PAD_EIM_DA11 = 107,
-       MX53_PAD_EIM_DA12 = 108,
-       MX53_PAD_EIM_DA13 = 109,
-       MX53_PAD_EIM_DA14 = 110,
-       MX53_PAD_EIM_DA15 = 111,
-       MX53_PAD_NANDF_WE_B = 112,
-       MX53_PAD_NANDF_RE_B = 113,
-       MX53_PAD_EIM_WAIT = 114,
-       MX53_PAD_LVDS1_TX3_P = 115,
-       MX53_PAD_LVDS1_TX2_P = 116,
-       MX53_PAD_LVDS1_CLK_P = 117,
-       MX53_PAD_LVDS1_TX1_P = 118,
-       MX53_PAD_LVDS1_TX0_P = 119,
-       MX53_PAD_LVDS0_TX3_P = 120,
-       MX53_PAD_LVDS0_CLK_P = 121,
-       MX53_PAD_LVDS0_TX2_P = 122,
-       MX53_PAD_LVDS0_TX1_P = 123,
-       MX53_PAD_LVDS0_TX0_P = 124,
-       MX53_PAD_GPIO_10 = 125,
-       MX53_PAD_GPIO_11 = 126,
-       MX53_PAD_GPIO_12 = 127,
-       MX53_PAD_GPIO_13 = 128,
-       MX53_PAD_GPIO_14 = 129,
-       MX53_PAD_NANDF_CLE = 130,
-       MX53_PAD_NANDF_ALE = 131,
-       MX53_PAD_NANDF_WP_B = 132,
-       MX53_PAD_NANDF_RB0 = 133,
-       MX53_PAD_NANDF_CS0 = 134,
-       MX53_PAD_NANDF_CS1 = 135,
-       MX53_PAD_NANDF_CS2 = 136,
-       MX53_PAD_NANDF_CS3 = 137,
-       MX53_PAD_FEC_MDIO = 138,
-       MX53_PAD_FEC_REF_CLK = 139,
-       MX53_PAD_FEC_RX_ER = 140,
-       MX53_PAD_FEC_CRS_DV = 141,
-       MX53_PAD_FEC_RXD1 = 142,
-       MX53_PAD_FEC_RXD0 = 143,
-       MX53_PAD_FEC_TX_EN = 144,
-       MX53_PAD_FEC_TXD1 = 145,
-       MX53_PAD_FEC_TXD0 = 146,
-       MX53_PAD_FEC_MDC = 147,
-       MX53_PAD_PATA_DIOW = 148,
-       MX53_PAD_PATA_DMACK = 149,
-       MX53_PAD_PATA_DMARQ = 150,
-       MX53_PAD_PATA_BUFFER_EN = 151,
-       MX53_PAD_PATA_INTRQ = 152,
-       MX53_PAD_PATA_DIOR = 153,
-       MX53_PAD_PATA_RESET_B = 154,
-       MX53_PAD_PATA_IORDY = 155,
-       MX53_PAD_PATA_DA_0 = 156,
-       MX53_PAD_PATA_DA_1 = 157,
-       MX53_PAD_PATA_DA_2 = 158,
-       MX53_PAD_PATA_CS_0 = 159,
-       MX53_PAD_PATA_CS_1 = 160,
-       MX53_PAD_PATA_DATA0 = 161,
-       MX53_PAD_PATA_DATA1 = 162,
-       MX53_PAD_PATA_DATA2 = 163,
-       MX53_PAD_PATA_DATA3 = 164,
-       MX53_PAD_PATA_DATA4 = 165,
-       MX53_PAD_PATA_DATA5 = 166,
-       MX53_PAD_PATA_DATA6 = 167,
-       MX53_PAD_PATA_DATA7 = 168,
-       MX53_PAD_PATA_DATA8 = 169,
-       MX53_PAD_PATA_DATA9 = 170,
-       MX53_PAD_PATA_DATA10 = 171,
-       MX53_PAD_PATA_DATA11 = 172,
-       MX53_PAD_PATA_DATA12 = 173,
-       MX53_PAD_PATA_DATA13 = 174,
-       MX53_PAD_PATA_DATA14 = 175,
-       MX53_PAD_PATA_DATA15 = 176,
-       MX53_PAD_SD1_DATA0 = 177,
-       MX53_PAD_SD1_DATA1 = 178,
-       MX53_PAD_SD1_CMD = 179,
-       MX53_PAD_SD1_DATA2 = 180,
-       MX53_PAD_SD1_CLK = 181,
-       MX53_PAD_SD1_DATA3 = 182,
-       MX53_PAD_SD2_CLK = 183,
-       MX53_PAD_SD2_CMD = 184,
-       MX53_PAD_SD2_DATA3 = 185,
-       MX53_PAD_SD2_DATA2 = 186,
-       MX53_PAD_SD2_DATA1 = 187,
-       MX53_PAD_SD2_DATA0 = 188,
-       MX53_PAD_GPIO_0 = 189,
-       MX53_PAD_GPIO_1 = 190,
-       MX53_PAD_GPIO_9 = 191,
-       MX53_PAD_GPIO_3 = 192,
-       MX53_PAD_GPIO_6 = 193,
-       MX53_PAD_GPIO_2 = 194,
-       MX53_PAD_GPIO_4 = 195,
-       MX53_PAD_GPIO_5 = 196,
-       MX53_PAD_GPIO_7 = 197,
-       MX53_PAD_GPIO_8 = 198,
-       MX53_PAD_GPIO_16 = 199,
-       MX53_PAD_GPIO_17 = 200,
-       MX53_PAD_GPIO_18 = 201,
+       MX53_PAD_GPIO_19 = 0,
+       MX53_PAD_KEY_COL0 = 1,
+       MX53_PAD_KEY_ROW0 = 2,
+       MX53_PAD_KEY_COL1 = 3,
+       MX53_PAD_KEY_ROW1 = 4,
+       MX53_PAD_KEY_COL2 = 5,
+       MX53_PAD_KEY_ROW2 = 6,
+       MX53_PAD_KEY_COL3 = 7,
+       MX53_PAD_KEY_ROW3 = 8,
+       MX53_PAD_KEY_COL4 = 9,
+       MX53_PAD_KEY_ROW4 = 10,
+       MX53_PAD_DI0_DISP_CLK = 11,
+       MX53_PAD_DI0_PIN15 = 12,
+       MX53_PAD_DI0_PIN2 = 13,
+       MX53_PAD_DI0_PIN3 = 14,
+       MX53_PAD_DI0_PIN4 = 15,
+       MX53_PAD_DISP0_DAT0 = 16,
+       MX53_PAD_DISP0_DAT1 = 17,
+       MX53_PAD_DISP0_DAT2 = 18,
+       MX53_PAD_DISP0_DAT3 = 19,
+       MX53_PAD_DISP0_DAT4 = 20,
+       MX53_PAD_DISP0_DAT5 = 21,
+       MX53_PAD_DISP0_DAT6 = 22,
+       MX53_PAD_DISP0_DAT7 = 23,
+       MX53_PAD_DISP0_DAT8 = 24,
+       MX53_PAD_DISP0_DAT9 = 25,
+       MX53_PAD_DISP0_DAT10 = 26,
+       MX53_PAD_DISP0_DAT11 = 27,
+       MX53_PAD_DISP0_DAT12 = 28,
+       MX53_PAD_DISP0_DAT13 = 29,
+       MX53_PAD_DISP0_DAT14 = 30,
+       MX53_PAD_DISP0_DAT15 = 31,
+       MX53_PAD_DISP0_DAT16 = 32,
+       MX53_PAD_DISP0_DAT17 = 33,
+       MX53_PAD_DISP0_DAT18 = 34,
+       MX53_PAD_DISP0_DAT19 = 35,
+       MX53_PAD_DISP0_DAT20 = 36,
+       MX53_PAD_DISP0_DAT21 = 37,
+       MX53_PAD_DISP0_DAT22 = 38,
+       MX53_PAD_DISP0_DAT23 = 39,
+       MX53_PAD_CSI0_PIXCLK = 40,
+       MX53_PAD_CSI0_MCLK = 41,
+       MX53_PAD_CSI0_DATA_EN = 42,
+       MX53_PAD_CSI0_VSYNC = 43,
+       MX53_PAD_CSI0_DAT4 = 44,
+       MX53_PAD_CSI0_DAT5 = 45,
+       MX53_PAD_CSI0_DAT6 = 46,
+       MX53_PAD_CSI0_DAT7 = 47,
+       MX53_PAD_CSI0_DAT8 = 48,
+       MX53_PAD_CSI0_DAT9 = 49,
+       MX53_PAD_CSI0_DAT10 = 50,
+       MX53_PAD_CSI0_DAT11 = 51,
+       MX53_PAD_CSI0_DAT12 = 52,
+       MX53_PAD_CSI0_DAT13 = 53,
+       MX53_PAD_CSI0_DAT14 = 54,
+       MX53_PAD_CSI0_DAT15 = 55,
+       MX53_PAD_CSI0_DAT16 = 56,
+       MX53_PAD_CSI0_DAT17 = 57,
+       MX53_PAD_CSI0_DAT18 = 58,
+       MX53_PAD_CSI0_DAT19 = 59,
+       MX53_PAD_EIM_A25 = 60,
+       MX53_PAD_EIM_EB2 = 61,
+       MX53_PAD_EIM_D16 = 62,
+       MX53_PAD_EIM_D17 = 63,
+       MX53_PAD_EIM_D18 = 64,
+       MX53_PAD_EIM_D19 = 65,
+       MX53_PAD_EIM_D20 = 66,
+       MX53_PAD_EIM_D21 = 67,
+       MX53_PAD_EIM_D22 = 68,
+       MX53_PAD_EIM_D23 = 69,
+       MX53_PAD_EIM_EB3 = 70,
+       MX53_PAD_EIM_D24 = 71,
+       MX53_PAD_EIM_D25 = 72,
+       MX53_PAD_EIM_D26 = 73,
+       MX53_PAD_EIM_D27 = 74,
+       MX53_PAD_EIM_D28 = 75,
+       MX53_PAD_EIM_D29 = 76,
+       MX53_PAD_EIM_D30 = 77,
+       MX53_PAD_EIM_D31 = 78,
+       MX53_PAD_EIM_A24 = 79,
+       MX53_PAD_EIM_A23 = 80,
+       MX53_PAD_EIM_A22 = 81,
+       MX53_PAD_EIM_A21 = 82,
+       MX53_PAD_EIM_A20 = 83,
+       MX53_PAD_EIM_A19 = 84,
+       MX53_PAD_EIM_A18 = 85,
+       MX53_PAD_EIM_A17 = 86,
+       MX53_PAD_EIM_A16 = 87,
+       MX53_PAD_EIM_CS0 = 88,
+       MX53_PAD_EIM_CS1 = 89,
+       MX53_PAD_EIM_OE = 90,
+       MX53_PAD_EIM_RW = 91,
+       MX53_PAD_EIM_LBA = 92,
+       MX53_PAD_EIM_EB0 = 93,
+       MX53_PAD_EIM_EB1 = 94,
+       MX53_PAD_EIM_DA0 = 95,
+       MX53_PAD_EIM_DA1 = 96,
+       MX53_PAD_EIM_DA2 = 97,
+       MX53_PAD_EIM_DA3 = 98,
+       MX53_PAD_EIM_DA4 = 99,
+       MX53_PAD_EIM_DA5 = 100,
+       MX53_PAD_EIM_DA6 = 101,
+       MX53_PAD_EIM_DA7 = 102,
+       MX53_PAD_EIM_DA8 = 103,
+       MX53_PAD_EIM_DA9 = 104,
+       MX53_PAD_EIM_DA10 = 105,
+       MX53_PAD_EIM_DA11 = 106,
+       MX53_PAD_EIM_DA12 = 107,
+       MX53_PAD_EIM_DA13 = 108,
+       MX53_PAD_EIM_DA14 = 109,
+       MX53_PAD_EIM_DA15 = 110,
+       MX53_PAD_NANDF_WE_B = 111,
+       MX53_PAD_NANDF_RE_B = 112,
+       MX53_PAD_EIM_WAIT = 113,
+       MX53_PAD_LVDS1_TX3_P = 114,
+       MX53_PAD_LVDS1_TX2_P = 115,
+       MX53_PAD_LVDS1_CLK_P = 116,
+       MX53_PAD_LVDS1_TX1_P = 117,
+       MX53_PAD_LVDS1_TX0_P = 118,
+       MX53_PAD_LVDS0_TX3_P = 119,
+       MX53_PAD_LVDS0_CLK_P = 120,
+       MX53_PAD_LVDS0_TX2_P = 121,
+       MX53_PAD_LVDS0_TX1_P = 122,
+       MX53_PAD_LVDS0_TX0_P = 123,
+       MX53_PAD_GPIO_10 = 124,
+       MX53_PAD_GPIO_11 = 125,
+       MX53_PAD_GPIO_12 = 126,
+       MX53_PAD_GPIO_13 = 127,
+       MX53_PAD_GPIO_14 = 128,
+       MX53_PAD_NANDF_CLE = 129,
+       MX53_PAD_NANDF_ALE = 130,
+       MX53_PAD_NANDF_WP_B = 131,
+       MX53_PAD_NANDF_RB0 = 132,
+       MX53_PAD_NANDF_CS0 = 133,
+       MX53_PAD_NANDF_CS1 = 134,
+       MX53_PAD_NANDF_CS2 = 135,
+       MX53_PAD_NANDF_CS3 = 136,
+       MX53_PAD_FEC_MDIO = 137,
+       MX53_PAD_FEC_REF_CLK = 138,
+       MX53_PAD_FEC_RX_ER = 139,
+       MX53_PAD_FEC_CRS_DV = 140,
+       MX53_PAD_FEC_RXD1 = 141,
+       MX53_PAD_FEC_RXD0 = 142,
+       MX53_PAD_FEC_TX_EN = 143,
+       MX53_PAD_FEC_TXD1 = 144,
+       MX53_PAD_FEC_TXD0 = 145,
+       MX53_PAD_FEC_MDC = 146,
+       MX53_PAD_PATA_DIOW = 147,
+       MX53_PAD_PATA_DMACK = 148,
+       MX53_PAD_PATA_DMARQ = 149,
+       MX53_PAD_PATA_BUFFER_EN = 150,
+       MX53_PAD_PATA_INTRQ = 151,
+       MX53_PAD_PATA_DIOR = 152,
+       MX53_PAD_PATA_RESET_B = 153,
+       MX53_PAD_PATA_IORDY = 154,
+       MX53_PAD_PATA_DA_0 = 155,
+       MX53_PAD_PATA_DA_1 = 156,
+       MX53_PAD_PATA_DA_2 = 157,
+       MX53_PAD_PATA_CS_0 = 158,
+       MX53_PAD_PATA_CS_1 = 159,
+       MX53_PAD_PATA_DATA0 = 160,
+       MX53_PAD_PATA_DATA1 = 161,
+       MX53_PAD_PATA_DATA2 = 162,
+       MX53_PAD_PATA_DATA3 = 163,
+       MX53_PAD_PATA_DATA4 = 164,
+       MX53_PAD_PATA_DATA5 = 165,
+       MX53_PAD_PATA_DATA6 = 166,
+       MX53_PAD_PATA_DATA7 = 167,
+       MX53_PAD_PATA_DATA8 = 168,
+       MX53_PAD_PATA_DATA9 = 169,
+       MX53_PAD_PATA_DATA10 = 170,
+       MX53_PAD_PATA_DATA11 = 171,
+       MX53_PAD_PATA_DATA12 = 172,
+       MX53_PAD_PATA_DATA13 = 173,
+       MX53_PAD_PATA_DATA14 = 174,
+       MX53_PAD_PATA_DATA15 = 175,
+       MX53_PAD_SD1_DATA0 = 176,
+       MX53_PAD_SD1_DATA1 = 177,
+       MX53_PAD_SD1_CMD = 178,
+       MX53_PAD_SD1_DATA2 = 179,
+       MX53_PAD_SD1_CLK = 180,
+       MX53_PAD_SD1_DATA3 = 181,
+       MX53_PAD_SD2_CLK = 182,
+       MX53_PAD_SD2_CMD = 183,
+       MX53_PAD_SD2_DATA3 = 184,
+       MX53_PAD_SD2_DATA2 = 185,
+       MX53_PAD_SD2_DATA1 = 186,
+       MX53_PAD_SD2_DATA0 = 187,
+       MX53_PAD_GPIO_0 = 188,
+       MX53_PAD_GPIO_1 = 189,
+       MX53_PAD_GPIO_9 = 190,
+       MX53_PAD_GPIO_3 = 191,
+       MX53_PAD_GPIO_6 = 192,
+       MX53_PAD_GPIO_2 = 193,
+       MX53_PAD_GPIO_4 = 194,
+       MX53_PAD_GPIO_5 = 195,
+       MX53_PAD_GPIO_7 = 196,
+       MX53_PAD_GPIO_8 = 197,
+       MX53_PAD_GPIO_16 = 198,
+       MX53_PAD_GPIO_17 = 199,
+       MX53_PAD_GPIO_18 = 200,
 };
 
 /* imx53 register maps */
index 6f99769c6733a946ad3a67311e23b246ad0aae74..a39fb7a6fc5142b86a65630bd5a208c84b94cd9a 100644 (file)
@@ -505,6 +505,8 @@ static const unsigned kp_b_1_pins[] = { DB8500_PIN_F3, DB8500_PIN_F1,
        DB8500_PIN_J3, DB8500_PIN_H2, DB8500_PIN_J2, DB8500_PIN_H1,
        DB8500_PIN_F4, DB8500_PIN_E3, DB8500_PIN_E4, DB8500_PIN_D2,
        DB8500_PIN_C1, DB8500_PIN_D3, DB8500_PIN_C2, DB8500_PIN_D5 };
+static const unsigned kp_b_2_pins[] = { DB8500_PIN_F3, DB8500_PIN_F1,
+       DB8500_PIN_G3, DB8500_PIN_G2, DB8500_PIN_F4, DB8500_PIN_E3};
 static const unsigned sm_b_1_pins[] = { DB8500_PIN_C6, DB8500_PIN_B3,
        DB8500_PIN_C4, DB8500_PIN_E6, DB8500_PIN_A3, DB8500_PIN_B6,
        DB8500_PIN_D6, DB8500_PIN_B7, DB8500_PIN_D7, DB8500_PIN_D8,
@@ -662,6 +664,7 @@ static const struct nmk_pingroup nmk_db8500_groups[] = {
        DB8500_PIN_GROUP(spi3_b_1, NMK_GPIO_ALT_B),
        DB8500_PIN_GROUP(msp1txrx_b_1, NMK_GPIO_ALT_B),
        DB8500_PIN_GROUP(kp_b_1, NMK_GPIO_ALT_B),
+       DB8500_PIN_GROUP(kp_b_2, NMK_GPIO_ALT_B),
        DB8500_PIN_GROUP(sm_b_1, NMK_GPIO_ALT_B),
        DB8500_PIN_GROUP(smcs0_b_1, NMK_GPIO_ALT_B),
        DB8500_PIN_GROUP(smcs1_b_1, NMK_GPIO_ALT_B),
@@ -751,7 +754,7 @@ DB8500_FUNC_GROUPS(msp1, "msp1txrx_a_1", "msp1_a_1", "msp1txrx_b_1");
 DB8500_FUNC_GROUPS(lcdb, "lcdb_a_1");
 DB8500_FUNC_GROUPS(lcd, "lcdvsi0_a_1", "lcdvsi1_a_1", "lcd_d0_d7_a_1",
        "lcd_d8_d11_a_1", "lcd_d12_d23_a_1", "lcd_b_1");
-DB8500_FUNC_GROUPS(kp, "kp_a_1", "kp_b_1", "kp_c_1", "kp_oc1_1");
+DB8500_FUNC_GROUPS(kp, "kp_a_1", "kp_b_1", "kp_b_2", "kp_c_1", "kp_oc1_1");
 DB8500_FUNC_GROUPS(mc2, "mc2_a_1", "mc2rstn_c_1");
 DB8500_FUNC_GROUPS(ssp1, "ssp1_a_1");
 DB8500_FUNC_GROUPS(ssp0, "ssp0_a_1");
@@ -766,7 +769,7 @@ DB8500_FUNC_GROUPS(ipgpio, "ipgpio0_a_1", "ipgpio1_a_1", "ipgpio7_b_1",
 DB8500_FUNC_GROUPS(msp2, "msp2sck_a_1", "msp2_a_1");
 DB8500_FUNC_GROUPS(mc4, "mc4_a_1", "mc4rstn_c_1");
 DB8500_FUNC_GROUPS(mc1, "mc1_a_1", "mc1dir_a_1");
-DB8500_FUNC_GROUPS(hsi, "hsir1_a_1", "hsit1_a_1", "hsit_a_2");
+DB8500_FUNC_GROUPS(hsi, "hsir_a_1", "hsit_a_1", "hsit_a_2");
 DB8500_FUNC_GROUPS(clkout, "clkout_a_1", "clkout_a_2", "clkout_c_1");
 DB8500_FUNC_GROUPS(usb, "usb_a_1");
 DB8500_FUNC_GROUPS(trig, "trig_b_1");
diff --git a/drivers/pinctrl/pinctrl-nomadik-db8540.c b/drivers/pinctrl/pinctrl-nomadik-db8540.c
new file mode 100644 (file)
index 0000000..3daf665
--- /dev/null
@@ -0,0 +1,999 @@
+#include <linux/kernel.h>
+#include <linux/pinctrl/pinctrl.h>
+#include "pinctrl-nomadik.h"
+
+/* All the pins that can be used for GPIO and some other functions */
+#define _GPIO(offset)          (offset)
+
+#define DB8540_PIN_AH6         _GPIO(0)
+#define DB8540_PIN_AG7         _GPIO(1)
+#define DB8540_PIN_AF2         _GPIO(2)
+#define DB8540_PIN_AD3         _GPIO(3)
+#define DB8540_PIN_AF6         _GPIO(4)
+#define DB8540_PIN_AG6         _GPIO(5)
+#define DB8540_PIN_AD5         _GPIO(6)
+#define DB8540_PIN_AF7         _GPIO(7)
+#define DB8540_PIN_AG5         _GPIO(8)
+#define DB8540_PIN_AH5         _GPIO(9)
+#define DB8540_PIN_AE4         _GPIO(10)
+#define DB8540_PIN_AD1         _GPIO(11)
+#define DB8540_PIN_AD2         _GPIO(12)
+#define DB8540_PIN_AC2         _GPIO(13)
+#define DB8540_PIN_AC4         _GPIO(14)
+#define DB8540_PIN_AC3         _GPIO(15)
+#define DB8540_PIN_AH7         _GPIO(16)
+#define DB8540_PIN_AE7         _GPIO(17)
+/* Hole */
+#define DB8540_PIN_AF8         _GPIO(22)
+#define DB8540_PIN_AH11                _GPIO(23)
+#define DB8540_PIN_AG11                _GPIO(24)
+#define DB8540_PIN_AF11                _GPIO(25)
+#define DB8540_PIN_AH10                _GPIO(26)
+#define DB8540_PIN_AG10                _GPIO(27)
+#define DB8540_PIN_AF10                _GPIO(28)
+/* Hole */
+#define DB8540_PIN_AD4         _GPIO(33)
+#define DB8540_PIN_AF3         _GPIO(34)
+#define DB8540_PIN_AF5         _GPIO(35)
+#define DB8540_PIN_AG4         _GPIO(36)
+#define DB8540_PIN_AF9         _GPIO(37)
+#define DB8540_PIN_AE8         _GPIO(38)
+/* Hole */
+#define DB8540_PIN_M26         _GPIO(64)
+#define DB8540_PIN_M25         _GPIO(65)
+#define DB8540_PIN_M27         _GPIO(66)
+#define DB8540_PIN_N25         _GPIO(67)
+/* Hole */
+#define DB8540_PIN_M28         _GPIO(70)
+#define DB8540_PIN_N26         _GPIO(71)
+#define DB8540_PIN_M22         _GPIO(72)
+#define DB8540_PIN_N22         _GPIO(73)
+#define DB8540_PIN_N27         _GPIO(74)
+#define DB8540_PIN_N28         _GPIO(75)
+#define DB8540_PIN_P22         _GPIO(76)
+#define DB8540_PIN_P28         _GPIO(77)
+#define DB8540_PIN_P26         _GPIO(78)
+#define DB8540_PIN_T22         _GPIO(79)
+#define DB8540_PIN_R27         _GPIO(80)
+#define DB8540_PIN_P27         _GPIO(81)
+#define DB8540_PIN_R26         _GPIO(82)
+#define DB8540_PIN_R25         _GPIO(83)
+#define DB8540_PIN_U22         _GPIO(84)
+#define DB8540_PIN_T27         _GPIO(85)
+#define DB8540_PIN_T25         _GPIO(86)
+#define DB8540_PIN_T26         _GPIO(87)
+/* Hole */
+#define DB8540_PIN_AF20                _GPIO(116)
+#define DB8540_PIN_AG21                _GPIO(117)
+#define DB8540_PIN_AH19                _GPIO(118)
+#define DB8540_PIN_AE19                _GPIO(119)
+#define DB8540_PIN_AG18                _GPIO(120)
+#define DB8540_PIN_AH17                _GPIO(121)
+#define DB8540_PIN_AF19                _GPIO(122)
+#define DB8540_PIN_AF18                _GPIO(123)
+#define DB8540_PIN_AE18                _GPIO(124)
+#define DB8540_PIN_AG17                _GPIO(125)
+#define DB8540_PIN_AF17                _GPIO(126)
+#define DB8540_PIN_AE17                _GPIO(127)
+#define DB8540_PIN_AC27                _GPIO(128)
+#define DB8540_PIN_AD27                _GPIO(129)
+#define DB8540_PIN_AE28                _GPIO(130)
+#define DB8540_PIN_AG26                _GPIO(131)
+#define DB8540_PIN_AF25                _GPIO(132)
+#define DB8540_PIN_AE27                _GPIO(133)
+#define DB8540_PIN_AF27                _GPIO(134)
+#define DB8540_PIN_AG28                _GPIO(135)
+#define DB8540_PIN_AF28                _GPIO(136)
+#define DB8540_PIN_AG25                _GPIO(137)
+#define DB8540_PIN_AG24                _GPIO(138)
+#define DB8540_PIN_AD25                _GPIO(139)
+#define DB8540_PIN_AH25                _GPIO(140)
+#define DB8540_PIN_AF26                _GPIO(141)
+#define DB8540_PIN_AF23                _GPIO(142)
+#define DB8540_PIN_AG23                _GPIO(143)
+#define DB8540_PIN_AE25                _GPIO(144)
+#define DB8540_PIN_AH24                _GPIO(145)
+#define DB8540_PIN_AJ25                _GPIO(146)
+#define DB8540_PIN_AG27                _GPIO(147)
+#define DB8540_PIN_AH23                _GPIO(148)
+#define DB8540_PIN_AE26                _GPIO(149)
+#define DB8540_PIN_AE24                _GPIO(150)
+#define DB8540_PIN_AJ24                _GPIO(151)
+#define DB8540_PIN_AE21                _GPIO(152)
+#define DB8540_PIN_AG22                _GPIO(153)
+#define DB8540_PIN_AF21                _GPIO(154)
+#define DB8540_PIN_AF24                _GPIO(155)
+#define DB8540_PIN_AH22                _GPIO(156)
+#define DB8540_PIN_AJ23                _GPIO(157)
+#define DB8540_PIN_AH21                _GPIO(158)
+#define DB8540_PIN_AG20                _GPIO(159)
+#define DB8540_PIN_AE23                _GPIO(160)
+#define DB8540_PIN_AH20                _GPIO(161)
+#define DB8540_PIN_AG19                _GPIO(162)
+#define DB8540_PIN_AF22                _GPIO(163)
+#define DB8540_PIN_AJ21                _GPIO(164)
+#define DB8540_PIN_AD26                _GPIO(165)
+#define DB8540_PIN_AD28                _GPIO(166)
+#define DB8540_PIN_AC28                _GPIO(167)
+#define DB8540_PIN_AC26                _GPIO(168)
+/* Hole */
+#define DB8540_PIN_J3          _GPIO(192)
+#define DB8540_PIN_H1          _GPIO(193)
+#define DB8540_PIN_J2          _GPIO(194)
+#define DB8540_PIN_H2          _GPIO(195)
+#define DB8540_PIN_H3          _GPIO(196)
+#define DB8540_PIN_H4          _GPIO(197)
+#define DB8540_PIN_G2          _GPIO(198)
+#define DB8540_PIN_G3          _GPIO(199)
+#define DB8540_PIN_G4          _GPIO(200)
+#define DB8540_PIN_F2          _GPIO(201)
+#define DB8540_PIN_C6          _GPIO(202)
+#define DB8540_PIN_B6          _GPIO(203)
+#define DB8540_PIN_B7          _GPIO(204)
+#define DB8540_PIN_A7          _GPIO(205)
+#define DB8540_PIN_D7          _GPIO(206)
+#define DB8540_PIN_D8          _GPIO(207)
+#define DB8540_PIN_F3          _GPIO(208)
+#define DB8540_PIN_E2          _GPIO(209)
+#define DB8540_PIN_C7          _GPIO(210)
+#define DB8540_PIN_B8          _GPIO(211)
+#define DB8540_PIN_C10         _GPIO(212)
+#define DB8540_PIN_C8          _GPIO(213)
+#define DB8540_PIN_C9          _GPIO(214)
+/* Hole */
+#define DB8540_PIN_B9          _GPIO(219)
+#define DB8540_PIN_A10         _GPIO(220)
+#define DB8540_PIN_D9          _GPIO(221)
+#define DB8540_PIN_B11         _GPIO(222)
+#define DB8540_PIN_B10         _GPIO(223)
+#define DB8540_PIN_E10         _GPIO(224)
+#define DB8540_PIN_B12         _GPIO(225)
+#define DB8540_PIN_D10         _GPIO(226)
+#define DB8540_PIN_D11         _GPIO(227)
+#define DB8540_PIN_AJ6         _GPIO(228)
+#define DB8540_PIN_B13         _GPIO(229)
+#define DB8540_PIN_C12         _GPIO(230)
+#define DB8540_PIN_B14         _GPIO(231)
+#define DB8540_PIN_E11         _GPIO(232)
+/* Hole */
+#define DB8540_PIN_D12         _GPIO(256)
+#define DB8540_PIN_D15         _GPIO(257)
+#define DB8540_PIN_C13         _GPIO(258)
+#define DB8540_PIN_C14         _GPIO(259)
+#define DB8540_PIN_C18         _GPIO(260)
+#define DB8540_PIN_C16         _GPIO(261)
+#define DB8540_PIN_B16         _GPIO(262)
+#define DB8540_PIN_D18         _GPIO(263)
+#define DB8540_PIN_C15         _GPIO(264)
+#define DB8540_PIN_C17         _GPIO(265)
+#define DB8540_PIN_B17         _GPIO(266)
+#define DB8540_PIN_D17         _GPIO(267)
+
+/*
+ * The names of the pins are denoted by GPIO number and ball name, even
+ * though they can be used for other things than GPIO, this is the first
+ * column in the table of the data sheet and often used on schematics and
+ * such.
+ */
+static const struct pinctrl_pin_desc nmk_db8540_pins[] = {
+       PINCTRL_PIN(DB8540_PIN_AH6, "GPIO0_AH6"),
+       PINCTRL_PIN(DB8540_PIN_AG7, "GPIO1_AG7"),
+       PINCTRL_PIN(DB8540_PIN_AF2, "GPIO2_AF2"),
+       PINCTRL_PIN(DB8540_PIN_AD3, "GPIO3_AD3"),
+       PINCTRL_PIN(DB8540_PIN_AF6, "GPIO4_AF6"),
+       PINCTRL_PIN(DB8540_PIN_AG6, "GPIO5_AG6"),
+       PINCTRL_PIN(DB8540_PIN_AD5, "GPIO6_AD5"),
+       PINCTRL_PIN(DB8540_PIN_AF7, "GPIO7_AF7"),
+       PINCTRL_PIN(DB8540_PIN_AG5, "GPIO8_AG5"),
+       PINCTRL_PIN(DB8540_PIN_AH5, "GPIO9_AH5"),
+       PINCTRL_PIN(DB8540_PIN_AE4, "GPIO10_AE4"),
+       PINCTRL_PIN(DB8540_PIN_AD1, "GPIO11_AD1"),
+       PINCTRL_PIN(DB8540_PIN_AD2, "GPIO12_AD2"),
+       PINCTRL_PIN(DB8540_PIN_AC2, "GPIO13_AC2"),
+       PINCTRL_PIN(DB8540_PIN_AC4, "GPIO14_AC4"),
+       PINCTRL_PIN(DB8540_PIN_AC3, "GPIO15_AC3"),
+       PINCTRL_PIN(DB8540_PIN_AH7, "GPIO16_AH7"),
+       PINCTRL_PIN(DB8540_PIN_AE7, "GPIO17_AE7"),
+       /* Hole */
+       PINCTRL_PIN(DB8540_PIN_AF8, "GPIO22_AF8"),
+       PINCTRL_PIN(DB8540_PIN_AH11, "GPIO23_AH11"),
+       PINCTRL_PIN(DB8540_PIN_AG11, "GPIO24_AG11"),
+       PINCTRL_PIN(DB8540_PIN_AF11, "GPIO25_AF11"),
+       PINCTRL_PIN(DB8540_PIN_AH10, "GPIO26_AH10"),
+       PINCTRL_PIN(DB8540_PIN_AG10, "GPIO27_AG10"),
+       PINCTRL_PIN(DB8540_PIN_AF10, "GPIO28_AF10"),
+       /* Hole */
+       PINCTRL_PIN(DB8540_PIN_AD4, "GPIO33_AD4"),
+       PINCTRL_PIN(DB8540_PIN_AF3, "GPIO34_AF3"),
+       PINCTRL_PIN(DB8540_PIN_AF5, "GPIO35_AF5"),
+       PINCTRL_PIN(DB8540_PIN_AG4, "GPIO36_AG4"),
+       PINCTRL_PIN(DB8540_PIN_AF9, "GPIO37_AF9"),
+       PINCTRL_PIN(DB8540_PIN_AE8, "GPIO38_AE8"),
+       /* Hole */
+       PINCTRL_PIN(DB8540_PIN_M26, "GPIO64_M26"),
+       PINCTRL_PIN(DB8540_PIN_M25, "GPIO65_M25"),
+       PINCTRL_PIN(DB8540_PIN_M27, "GPIO66_M27"),
+       PINCTRL_PIN(DB8540_PIN_N25, "GPIO67_N25"),
+       /* Hole */
+       PINCTRL_PIN(DB8540_PIN_M28, "GPIO70_M28"),
+       PINCTRL_PIN(DB8540_PIN_N26, "GPIO71_N26"),
+       PINCTRL_PIN(DB8540_PIN_M22, "GPIO72_M22"),
+       PINCTRL_PIN(DB8540_PIN_N22, "GPIO73_N22"),
+       PINCTRL_PIN(DB8540_PIN_N27, "GPIO74_N27"),
+       PINCTRL_PIN(DB8540_PIN_N28, "GPIO75_N28"),
+       PINCTRL_PIN(DB8540_PIN_P22, "GPIO76_P22"),
+       PINCTRL_PIN(DB8540_PIN_P28, "GPIO77_P28"),
+       PINCTRL_PIN(DB8540_PIN_P26, "GPIO78_P26"),
+       PINCTRL_PIN(DB8540_PIN_T22, "GPIO79_T22"),
+       PINCTRL_PIN(DB8540_PIN_R27, "GPIO80_R27"),
+       PINCTRL_PIN(DB8540_PIN_P27, "GPIO81_P27"),
+       PINCTRL_PIN(DB8540_PIN_R26, "GPIO82_R26"),
+       PINCTRL_PIN(DB8540_PIN_R25, "GPIO83_R25"),
+       PINCTRL_PIN(DB8540_PIN_U22, "GPIO84_U22"),
+       PINCTRL_PIN(DB8540_PIN_T27, "GPIO85_T27"),
+       PINCTRL_PIN(DB8540_PIN_T25, "GPIO86_T25"),
+       PINCTRL_PIN(DB8540_PIN_T26, "GPIO87_T26"),
+       /* Hole */
+       PINCTRL_PIN(DB8540_PIN_AF20, "GPIO116_AF20"),
+       PINCTRL_PIN(DB8540_PIN_AG21, "GPIO117_AG21"),
+       PINCTRL_PIN(DB8540_PIN_AH19, "GPIO118_AH19"),
+       PINCTRL_PIN(DB8540_PIN_AE19, "GPIO119_AE19"),
+       PINCTRL_PIN(DB8540_PIN_AG18, "GPIO120_AG18"),
+       PINCTRL_PIN(DB8540_PIN_AH17, "GPIO121_AH17"),
+       PINCTRL_PIN(DB8540_PIN_AF19, "GPIO122_AF19"),
+       PINCTRL_PIN(DB8540_PIN_AF18, "GPIO123_AF18"),
+       PINCTRL_PIN(DB8540_PIN_AE18, "GPIO124_AE18"),
+       PINCTRL_PIN(DB8540_PIN_AG17, "GPIO125_AG17"),
+       PINCTRL_PIN(DB8540_PIN_AF17, "GPIO126_AF17"),
+       PINCTRL_PIN(DB8540_PIN_AE17, "GPIO127_AE17"),
+       PINCTRL_PIN(DB8540_PIN_AC27, "GPIO128_AC27"),
+       PINCTRL_PIN(DB8540_PIN_AD27, "GPIO129_AD27"),
+       PINCTRL_PIN(DB8540_PIN_AE28, "GPIO130_AE28"),
+       PINCTRL_PIN(DB8540_PIN_AG26, "GPIO131_AG26"),
+       PINCTRL_PIN(DB8540_PIN_AF25, "GPIO132_AF25"),
+       PINCTRL_PIN(DB8540_PIN_AE27, "GPIO133_AE27"),
+       PINCTRL_PIN(DB8540_PIN_AF27, "GPIO134_AF27"),
+       PINCTRL_PIN(DB8540_PIN_AG28, "GPIO135_AG28"),
+       PINCTRL_PIN(DB8540_PIN_AF28, "GPIO136_AF28"),
+       PINCTRL_PIN(DB8540_PIN_AG25, "GPIO137_AG25"),
+       PINCTRL_PIN(DB8540_PIN_AG24, "GPIO138_AG24"),
+       PINCTRL_PIN(DB8540_PIN_AD25, "GPIO139_AD25"),
+       PINCTRL_PIN(DB8540_PIN_AH25, "GPIO140_AH25"),
+       PINCTRL_PIN(DB8540_PIN_AF26, "GPIO141_AF26"),
+       PINCTRL_PIN(DB8540_PIN_AF23, "GPIO142_AF23"),
+       PINCTRL_PIN(DB8540_PIN_AG23, "GPIO143_AG23"),
+       PINCTRL_PIN(DB8540_PIN_AE25, "GPIO144_AE25"),
+       PINCTRL_PIN(DB8540_PIN_AH24, "GPIO145_AH24"),
+       PINCTRL_PIN(DB8540_PIN_AJ25, "GPIO146_AJ25"),
+       PINCTRL_PIN(DB8540_PIN_AG27, "GPIO147_AG27"),
+       PINCTRL_PIN(DB8540_PIN_AH23, "GPIO148_AH23"),
+       PINCTRL_PIN(DB8540_PIN_AE26, "GPIO149_AE26"),
+       PINCTRL_PIN(DB8540_PIN_AE24, "GPIO150_AE24"),
+       PINCTRL_PIN(DB8540_PIN_AJ24, "GPIO151_AJ24"),
+       PINCTRL_PIN(DB8540_PIN_AE21, "GPIO152_AE21"),
+       PINCTRL_PIN(DB8540_PIN_AG22, "GPIO153_AG22"),
+       PINCTRL_PIN(DB8540_PIN_AF21, "GPIO154_AF21"),
+       PINCTRL_PIN(DB8540_PIN_AF24, "GPIO155_AF24"),
+       PINCTRL_PIN(DB8540_PIN_AH22, "GPIO156_AH22"),
+       PINCTRL_PIN(DB8540_PIN_AJ23, "GPIO157_AJ23"),
+       PINCTRL_PIN(DB8540_PIN_AH21, "GPIO158_AH21"),
+       PINCTRL_PIN(DB8540_PIN_AG20, "GPIO159_AG20"),
+       PINCTRL_PIN(DB8540_PIN_AE23, "GPIO160_AE23"),
+       PINCTRL_PIN(DB8540_PIN_AH20, "GPIO161_AH20"),
+       PINCTRL_PIN(DB8540_PIN_AG19, "GPIO162_AG19"),
+       PINCTRL_PIN(DB8540_PIN_AF22, "GPIO163_AF22"),
+       PINCTRL_PIN(DB8540_PIN_AJ21, "GPIO164_AJ21"),
+       PINCTRL_PIN(DB8540_PIN_AD26, "GPIO165_AD26"),
+       PINCTRL_PIN(DB8540_PIN_AD28, "GPIO166_AD28"),
+       PINCTRL_PIN(DB8540_PIN_AC28, "GPIO167_AC28"),
+       PINCTRL_PIN(DB8540_PIN_AC26, "GPIO168_AC26"),
+       /* Hole */
+       PINCTRL_PIN(DB8540_PIN_J3, "GPIO192_J3"),
+       PINCTRL_PIN(DB8540_PIN_H1, "GPIO193_H1"),
+       PINCTRL_PIN(DB8540_PIN_J2, "GPIO194_J2"),
+       PINCTRL_PIN(DB8540_PIN_H2, "GPIO195_H2"),
+       PINCTRL_PIN(DB8540_PIN_H3, "GPIO196_H3"),
+       PINCTRL_PIN(DB8540_PIN_H4, "GPIO197_H4"),
+       PINCTRL_PIN(DB8540_PIN_G2, "GPIO198_G2"),
+       PINCTRL_PIN(DB8540_PIN_G3, "GPIO199_G3"),
+       PINCTRL_PIN(DB8540_PIN_G4, "GPIO200_G4"),
+       PINCTRL_PIN(DB8540_PIN_F2, "GPIO201_F2"),
+       PINCTRL_PIN(DB8540_PIN_C6, "GPIO202_C6"),
+       PINCTRL_PIN(DB8540_PIN_B6, "GPIO203_B6"),
+       PINCTRL_PIN(DB8540_PIN_B7, "GPIO204_B7"),
+       PINCTRL_PIN(DB8540_PIN_A7, "GPIO205_A7"),
+       PINCTRL_PIN(DB8540_PIN_D7, "GPIO206_D7"),
+       PINCTRL_PIN(DB8540_PIN_D8, "GPIO207_D8"),
+       PINCTRL_PIN(DB8540_PIN_F3, "GPIO208_F3"),
+       PINCTRL_PIN(DB8540_PIN_E2, "GPIO209_E2"),
+       PINCTRL_PIN(DB8540_PIN_C7, "GPIO210_C7"),
+       PINCTRL_PIN(DB8540_PIN_B8, "GPIO211_B8"),
+       PINCTRL_PIN(DB8540_PIN_C10, "GPIO212_C10"),
+       PINCTRL_PIN(DB8540_PIN_C8, "GPIO213_C8"),
+       PINCTRL_PIN(DB8540_PIN_C9, "GPIO214_C9"),
+       /* Hole */
+       PINCTRL_PIN(DB8540_PIN_B9, "GPIO219_B9"),
+       PINCTRL_PIN(DB8540_PIN_A10, "GPIO220_A10"),
+       PINCTRL_PIN(DB8540_PIN_D9, "GPIO221_D9"),
+       PINCTRL_PIN(DB8540_PIN_B11, "GPIO222_B11"),
+       PINCTRL_PIN(DB8540_PIN_B10, "GPIO223_B10"),
+       PINCTRL_PIN(DB8540_PIN_E10, "GPIO224_E10"),
+       PINCTRL_PIN(DB8540_PIN_B12, "GPIO225_B12"),
+       PINCTRL_PIN(DB8540_PIN_D10, "GPIO226_D10"),
+       PINCTRL_PIN(DB8540_PIN_D11, "GPIO227_D11"),
+       PINCTRL_PIN(DB8540_PIN_AJ6, "GPIO228_AJ6"),
+       PINCTRL_PIN(DB8540_PIN_B13, "GPIO229_B13"),
+       PINCTRL_PIN(DB8540_PIN_C12, "GPIO230_C12"),
+       PINCTRL_PIN(DB8540_PIN_B14, "GPIO231_B14"),
+       PINCTRL_PIN(DB8540_PIN_E11, "GPIO232_E11"),
+       /* Hole */
+       PINCTRL_PIN(DB8540_PIN_D12, "GPIO256_D12"),
+       PINCTRL_PIN(DB8540_PIN_D15, "GPIO257_D15"),
+       PINCTRL_PIN(DB8540_PIN_C13, "GPIO258_C13"),
+       PINCTRL_PIN(DB8540_PIN_C14, "GPIO259_C14"),
+       PINCTRL_PIN(DB8540_PIN_C18, "GPIO260_C18"),
+       PINCTRL_PIN(DB8540_PIN_C16, "GPIO261_C16"),
+       PINCTRL_PIN(DB8540_PIN_B16, "GPIO262_B16"),
+       PINCTRL_PIN(DB8540_PIN_D18, "GPIO263_D18"),
+       PINCTRL_PIN(DB8540_PIN_C15, "GPIO264_C15"),
+       PINCTRL_PIN(DB8540_PIN_C17, "GPIO265_C17"),
+       PINCTRL_PIN(DB8540_PIN_B17, "GPIO266_B17"),
+       PINCTRL_PIN(DB8540_PIN_D17, "GPIO267_D17"),
+};
+
+#define DB8540_GPIO_RANGE(a, b, c) { .name = "db8540", .id = a, .base = b, \
+                       .pin_base = b, .npins = c }
+
+/*
+ * This matches the 32-pin gpio chips registered by the GPIO portion. This
+ * cannot be const since we assign the struct gpio_chip * pointer at runtime.
+ */
+static struct pinctrl_gpio_range nmk_db8540_ranges[] = {
+       DB8540_GPIO_RANGE(0, 0, 18),
+       DB8540_GPIO_RANGE(0, 22, 7),
+       DB8540_GPIO_RANGE(1, 33, 6),
+       DB8540_GPIO_RANGE(2, 64, 4),
+       DB8540_GPIO_RANGE(2, 70, 18),
+       DB8540_GPIO_RANGE(3, 116, 12),
+       DB8540_GPIO_RANGE(4, 128, 32),
+       DB8540_GPIO_RANGE(5, 160, 9),
+       DB8540_GPIO_RANGE(6, 192, 23),
+       DB8540_GPIO_RANGE(6, 219, 5),
+       DB8540_GPIO_RANGE(7, 224, 9),
+       DB8540_GPIO_RANGE(8, 256, 12),
+};
+
+/*
+ * Read the pin group names like this:
+ * u0_a_1    = first groups of pins for uart0 on alt function a
+ * i2c2_b_2  = second group of pins for i2c2 on alt function b
+ *
+ * The groups are arranged as sets per altfunction column, so we can
+ * mux in one group at a time by selecting the same altfunction for them
+ * all. When functions require pins on different altfunctions, you need
+ * to combine several groups.
+ */
+
+/* Altfunction A column */
+static const unsigned u0_a_1_pins[] = { DB8540_PIN_AH6, DB8540_PIN_AG7,
+                                       DB8540_PIN_AF2, DB8540_PIN_AD3 };
+static const unsigned u1rxtx_a_1_pins[] = { DB8540_PIN_AF6, DB8540_PIN_AG6 };
+static const unsigned u1ctsrts_a_1_pins[] = { DB8540_PIN_AD5, DB8540_PIN_AF7 };
+/* Image processor I2C line, this is driven by image processor firmware */
+static const unsigned ipi2c_a_1_pins[] = { DB8540_PIN_AG5, DB8540_PIN_AH5 };
+static const unsigned ipi2c_a_2_pins[] = { DB8540_PIN_AE4, DB8540_PIN_AD1 };
+/* MSP0 can only be on these pins, but TXD and RXD can be flipped */
+static const unsigned msp0txrx_a_1_pins[] = { DB8540_PIN_AD2, DB8540_PIN_AC3 };
+static const unsigned msp0tfstck_a_1_pins[] = { DB8540_PIN_AC2,
+       DB8540_PIN_AC4 };
+static const unsigned msp0rfsrck_a_1_pins[] = { DB8540_PIN_AH7,
+       DB8540_PIN_AE7 };
+/* Basic pins of the MMC/SD card 0 interface */
+static const unsigned mc0_a_1_pins[] = { DB8540_PIN_AH11, DB8540_PIN_AG11,
+       DB8540_PIN_AF11, DB8540_PIN_AH10, DB8540_PIN_AG10, DB8540_PIN_AF10};
+/* MSP1 can only be on these pins, but TXD and RXD can be flipped */
+static const unsigned msp1txrx_a_1_pins[] = { DB8540_PIN_AD4, DB8540_PIN_AG4 };
+static const unsigned msp1_a_1_pins[] = { DB8540_PIN_AF3, DB8540_PIN_AF5 };
+
+static const unsigned modobsclk_a_1_pins[] = { DB8540_PIN_AF9 };
+static const unsigned clkoutreq_a_1_pins[] = { DB8540_PIN_AE8 };
+/* LCD interface */
+static const unsigned lcdb_a_1_pins[] = { DB8540_PIN_M26, DB8540_PIN_M25,
+       DB8540_PIN_M27, DB8540_PIN_N25 };
+static const unsigned lcdvsi0_a_1_pins[] = { DB8540_PIN_AJ24 };
+static const unsigned lcdvsi1_a_1_pins[] = { DB8540_PIN_AE21 };
+static const unsigned lcd_d0_d7_a_1_pins[] = { DB8540_PIN_M28, DB8540_PIN_N26,
+       DB8540_PIN_M22, DB8540_PIN_N22, DB8540_PIN_N27, DB8540_PIN_N28,
+       DB8540_PIN_P22, DB8540_PIN_P28 };
+/* D8 thru D11 often used as TVOUT lines */
+static const unsigned lcd_d8_d11_a_1_pins[] = { DB8540_PIN_P26, DB8540_PIN_T22,
+       DB8540_PIN_R27, DB8540_PIN_P27 };
+static const unsigned lcd_d12_d23_a_1_pins[] = { DB8540_PIN_R26, DB8540_PIN_R25,
+       DB8540_PIN_U22, DB8540_PIN_T27, DB8540_PIN_AG22, DB8540_PIN_AF21,
+       DB8540_PIN_AF24, DB8540_PIN_AH22, DB8540_PIN_AJ23, DB8540_PIN_AH21,
+       DB8540_PIN_AG20, DB8540_PIN_AE23 };
+static const unsigned kp_a_1_pins[] = { DB8540_PIN_AH20, DB8540_PIN_AG19,
+       DB8540_PIN_AF22, DB8540_PIN_AJ21, DB8540_PIN_T25, DB8540_PIN_T26 };
+/* MC2 has 8 data lines and no direction control, so only for (e)MMC */
+static const unsigned mc2_a_1_pins[] = { DB8540_PIN_AC27, DB8540_PIN_AD27,
+       DB8540_PIN_AE28, DB8540_PIN_AG26, DB8540_PIN_AF25, DB8540_PIN_AE27,
+       DB8540_PIN_AF27, DB8540_PIN_AG28, DB8540_PIN_AF28, DB8540_PIN_AG25,
+       DB8540_PIN_AG24 };
+static const unsigned ssp1_a_1_pins[] = {  DB8540_PIN_AD25, DB8540_PIN_AH25,
+       DB8540_PIN_AF26, DB8540_PIN_AF23 };
+static const unsigned ssp0_a_1_pins[] = { DB8540_PIN_AG23, DB8540_PIN_AE25,
+       DB8540_PIN_AH24, DB8540_PIN_AJ25 };
+static const unsigned i2c0_a_1_pins[] = { DB8540_PIN_AG27, DB8540_PIN_AH23 };
+/*
+ * Image processor GPIO pins are named "ipgpio" and have their own
+ * numberspace
+ */
+static const unsigned ipgpio0_a_1_pins[] = { DB8540_PIN_AE26 };
+static const unsigned ipgpio1_a_1_pins[] = { DB8540_PIN_AE24 };
+/* modem i2s interface */
+static const unsigned modi2s_a_1_pins[] = { DB8540_PIN_AD26, DB8540_PIN_AD28,
+       DB8540_PIN_AC28, DB8540_PIN_AC26 };
+static const unsigned spi2_a_1_pins[] = { DB8540_PIN_AF20, DB8540_PIN_AG21,
+       DB8540_PIN_AH19, DB8540_PIN_AE19 };
+static const unsigned u2txrx_a_1_pins[] = { DB8540_PIN_AG18, DB8540_PIN_AH17 };
+static const unsigned u2ctsrts_a_1_pins[] = { DB8540_PIN_AF19,
+       DB8540_PIN_AF18 };
+static const unsigned modsmb_a_1_pins[] = { DB8540_PIN_AF17, DB8540_PIN_AE17 };
+static const unsigned msp2sck_a_1_pins[] = { DB8540_PIN_J3 };
+static const unsigned msp2txdtcktfs_a_1_pins[] = { DB8540_PIN_H1, DB8540_PIN_J2,
+       DB8540_PIN_H2 };
+static const unsigned msp2rxd_a_1_pins[] = { DB8540_PIN_H3 };
+static const unsigned mc4_a_1_pins[] = { DB8540_PIN_H4, DB8540_PIN_G2,
+       DB8540_PIN_G3, DB8540_PIN_G4, DB8540_PIN_F2, DB8540_PIN_C6,
+       DB8540_PIN_B6, DB8540_PIN_B7, DB8540_PIN_A7, DB8540_PIN_D7,
+       DB8540_PIN_D8 };
+static const unsigned mc1_a_1_pins[] = { DB8540_PIN_F3, DB8540_PIN_E2,
+       DB8540_PIN_C7, DB8540_PIN_B8, DB8540_PIN_C10, DB8540_PIN_C8,
+       DB8540_PIN_C9 };
+/* mc1_a_2_pins exclude MC1_FBCLK */
+static const unsigned mc1_a_2_pins[] = { DB8540_PIN_F3,        DB8540_PIN_C7,
+       DB8540_PIN_B8, DB8540_PIN_C10, DB8540_PIN_C8,
+       DB8540_PIN_C9 };
+static const unsigned hsir_a_1_pins[] = { DB8540_PIN_B9, DB8540_PIN_A10,
+       DB8540_PIN_D9 };
+static const unsigned hsit_a_1_pins[] = { DB8540_PIN_B11, DB8540_PIN_B10,
+       DB8540_PIN_E10, DB8540_PIN_B12, DB8540_PIN_D10 };
+static const unsigned hsit_a_2_pins[] = { DB8540_PIN_B11, DB8540_PIN_B10,
+       DB8540_PIN_E10, DB8540_PIN_B12 };
+static const unsigned clkout_a_1_pins[] = { DB8540_PIN_D11, DB8540_PIN_AJ6 };
+static const unsigned clkout_a_2_pins[] = { DB8540_PIN_B13, DB8540_PIN_C12 };
+static const unsigned msp4_a_1_pins[] = { DB8540_PIN_B14, DB8540_PIN_E11 };
+static const unsigned usb_a_1_pins[] = { DB8540_PIN_D12, DB8540_PIN_D15,
+       DB8540_PIN_C13, DB8540_PIN_C14, DB8540_PIN_C18, DB8540_PIN_C16,
+       DB8540_PIN_B16, DB8540_PIN_D18, DB8540_PIN_C15, DB8540_PIN_C17,
+       DB8540_PIN_B17, DB8540_PIN_D17 };
+/* Altfunction B colum */
+static const unsigned apetrig_b_1_pins[] = { DB8540_PIN_AH6, DB8540_PIN_AG7 };
+static const unsigned modtrig_b_1_pins[] = { DB8540_PIN_AF2, DB8540_PIN_AD3 };
+static const unsigned i2c4_b_1_pins[] = { DB8540_PIN_AF6, DB8540_PIN_AG6 };
+static const unsigned i2c1_b_1_pins[] = { DB8540_PIN_AD5, DB8540_PIN_AF7 };
+static const unsigned i2c2_b_1_pins[] = { DB8540_PIN_AG5, DB8540_PIN_AH5 };
+static const unsigned i2c2_b_2_pins[] = { DB8540_PIN_AE4, DB8540_PIN_AD1 };
+static const unsigned msp0txrx_b_1_pins[] = { DB8540_PIN_AD2, DB8540_PIN_AC3 };
+static const unsigned i2c1_b_2_pins[] = { DB8540_PIN_AH7, DB8540_PIN_AE7 };
+static const unsigned stmmod_b_1_pins[] = { DB8540_PIN_AH11, DB8540_PIN_AF11,
+       DB8540_PIN_AH10, DB8540_PIN_AG10, DB8540_PIN_AF10 };
+static const unsigned moduartstmmux_b_1_pins[] = { DB8540_PIN_AG11 };
+static const unsigned msp1txrx_b_1_pins[] = { DB8540_PIN_AD4, DB8540_PIN_AG4 };
+static const unsigned kp_b_1_pins[] = { DB8540_PIN_AJ24, DB8540_PIN_AE21,
+       DB8540_PIN_M26, DB8540_PIN_M25, DB8540_PIN_M27, DB8540_PIN_N25,
+       DB8540_PIN_M28, DB8540_PIN_N26, DB8540_PIN_M22, DB8540_PIN_N22,
+       DB8540_PIN_N27, DB8540_PIN_N28, DB8540_PIN_P22, DB8540_PIN_P28,
+       DB8540_PIN_P26, DB8540_PIN_T22, DB8540_PIN_R27, DB8540_PIN_P27,
+       DB8540_PIN_R26, DB8540_PIN_R25 };
+static const unsigned u2txrx_b_1_pins[] = { DB8540_PIN_U22, DB8540_PIN_T27 };
+static const unsigned sm_b_1_pins[] = { DB8540_PIN_AG22, DB8540_PIN_AF21,
+       DB8540_PIN_AF24, DB8540_PIN_AH22, DB8540_PIN_AJ23, DB8540_PIN_AH21,
+       DB8540_PIN_AG20, DB8540_PIN_AE23, DB8540_PIN_AH20, DB8540_PIN_AF22,
+       DB8540_PIN_AJ21, DB8540_PIN_AC27, DB8540_PIN_AD27, DB8540_PIN_AE28,
+       DB8540_PIN_AG26, DB8540_PIN_AF25, DB8540_PIN_AE27, DB8540_PIN_AF27,
+       DB8540_PIN_AG28, DB8540_PIN_AF28, DB8540_PIN_AG25, DB8540_PIN_AG24,
+       DB8540_PIN_AD25 };
+static const unsigned smcs0_b_1_pins[] = { DB8540_PIN_AG19 };
+static const unsigned smcs1_b_1_pins[] = { DB8540_PIN_AE26 };
+static const unsigned ipgpio7_b_1_pins[] = { DB8540_PIN_AH25 };
+static const unsigned ipgpio2_b_1_pins[] = { DB8540_PIN_AF26 };
+static const unsigned ipgpio3_b_1_pins[] = { DB8540_PIN_AF23 };
+static const unsigned i2c6_b_1_pins[] = { DB8540_PIN_AG23, DB8540_PIN_AE25 };
+static const unsigned i2c5_b_1_pins[] = { DB8540_PIN_AH24, DB8540_PIN_AJ25 };
+static const unsigned u3txrx_b_1_pins[] = { DB8540_PIN_AF20, DB8540_PIN_AG21 };
+static const unsigned u3ctsrts_b_1_pins[] = { DB8540_PIN_AH19,
+       DB8540_PIN_AE19 };
+static const unsigned i2c5_b_2_pins[] = { DB8540_PIN_AG18, DB8540_PIN_AH17 };
+static const unsigned i2c4_b_2_pins[] = { DB8540_PIN_AF19, DB8540_PIN_AF18 };
+static const unsigned u4txrx_b_1_pins[] = { DB8540_PIN_AE18, DB8540_PIN_AG17 };
+static const unsigned u4ctsrts_b_1_pins[] = { DB8540_PIN_AF17,
+       DB8540_PIN_AE17 };
+static const unsigned ddrtrig_b_1_pins[] = { DB8540_PIN_J3 };
+static const unsigned msp4_b_1_pins[] = { DB8540_PIN_H3 };
+static const unsigned pwl_b_1_pins[] = { DB8540_PIN_C6 };
+static const unsigned spi1_b_1_pins[] = { DB8540_PIN_E2, DB8540_PIN_C10,
+       DB8540_PIN_C8, DB8540_PIN_C9 };
+static const unsigned mc3_b_1_pins[] = { DB8540_PIN_B9, DB8540_PIN_A10,
+       DB8540_PIN_D9, DB8540_PIN_B11, DB8540_PIN_B10, DB8540_PIN_E10,
+       DB8540_PIN_B12 };
+static const unsigned pwl_b_2_pins[] = { DB8540_PIN_D10 };
+static const unsigned pwl_b_3_pins[] = { DB8540_PIN_B13 };
+static const unsigned pwl_b_4_pins[] = { DB8540_PIN_C12 };
+static const unsigned u2txrx_b_2_pins[] = { DB8540_PIN_B17, DB8540_PIN_D17 };
+
+/* Altfunction C column */
+static const unsigned ipgpio6_c_1_pins[] = { DB8540_PIN_AG6 };
+static const unsigned ipgpio0_c_1_pins[] = { DB8540_PIN_AD5 };
+static const unsigned ipgpio1_c_1_pins[] = { DB8540_PIN_AF7 };
+static const unsigned ipgpio3_c_1_pins[] = { DB8540_PIN_AE4 };
+static const unsigned ipgpio2_c_1_pins[] = { DB8540_PIN_AD1 };
+static const unsigned u0_c_1_pins[] = { DB8540_PIN_AD4, DB8540_PIN_AF3,
+       DB8540_PIN_AF5, DB8540_PIN_AG4 };
+static const unsigned smcleale_c_1_pins[] = { DB8540_PIN_AJ24,
+       DB8540_PIN_AE21 };
+static const unsigned ipgpio4_c_1_pins[] = { DB8540_PIN_M26 };
+static const unsigned ipgpio5_c_1_pins[] = { DB8540_PIN_M25 };
+static const unsigned ipgpio6_c_2_pins[] = { DB8540_PIN_M27 };
+static const unsigned ipgpio7_c_1_pins[] = { DB8540_PIN_N25 };
+static const unsigned stmape_c_1_pins[] = { DB8540_PIN_M28, DB8540_PIN_N26,
+       DB8540_PIN_M22, DB8540_PIN_N22, DB8540_PIN_N27 };
+static const unsigned u2rxtx_c_1_pins[] = { DB8540_PIN_N28, DB8540_PIN_P22 };
+static const unsigned modobsresout_c_1_pins[] = { DB8540_PIN_P28 };
+static const unsigned ipgpio2_c_2_pins[] = { DB8540_PIN_P26 };
+static const unsigned ipgpio3_c_2_pins[] = { DB8540_PIN_T22 };
+static const unsigned ipgpio4_c_2_pins[] = { DB8540_PIN_R27 };
+static const unsigned ipgpio5_c_2_pins[] = { DB8540_PIN_P27 };
+static const unsigned modaccgpo_c_1_pins[] = { DB8540_PIN_R26, DB8540_PIN_R25,
+       DB8540_PIN_U22 };
+static const unsigned modobspwrrst_c_1_pins[] = { DB8540_PIN_T27 };
+static const unsigned mc5_c_1_pins[] = { DB8540_PIN_AG22, DB8540_PIN_AF21,
+       DB8540_PIN_AF24, DB8540_PIN_AH22, DB8540_PIN_AJ23, DB8540_PIN_AH21,
+       DB8540_PIN_AG20, DB8540_PIN_AE23, DB8540_PIN_AH20, DB8540_PIN_AF22,
+       DB8540_PIN_AJ21};
+static const unsigned smps0_c_1_pins[] = { DB8540_PIN_AG19 };
+static const unsigned moduart1_c_1_pins[] = { DB8540_PIN_T25, DB8540_PIN_T26 };
+static const unsigned mc2rstn_c_1_pins[] = { DB8540_PIN_AE28 };
+static const unsigned i2c5_c_1_pins[] = { DB8540_PIN_AG28, DB8540_PIN_AF28 };
+static const unsigned ipgpio0_c_2_pins[] = { DB8540_PIN_AG25 };
+static const unsigned ipgpio1_c_2_pins[] = { DB8540_PIN_AG24 };
+static const unsigned kp_c_1_pins[] = { DB8540_PIN_AD25, DB8540_PIN_AH25,
+       DB8540_PIN_AF26, DB8540_PIN_AF23 };
+static const unsigned modrf_c_1_pins[] = { DB8540_PIN_AG23, DB8540_PIN_AE25,
+       DB8540_PIN_AH24 };
+static const unsigned smps1_c_1_pins[] = { DB8540_PIN_AE26 };
+static const unsigned i2c5_c_2_pins[] = { DB8540_PIN_AH19, DB8540_PIN_AE19 };
+static const unsigned u4ctsrts_c_1_pins[] = { DB8540_PIN_AG18,
+       DB8540_PIN_AH17 };
+static const unsigned u3rxtx_c_1_pins[] = { DB8540_PIN_AF19, DB8540_PIN_AF18 };
+static const unsigned msp4_c_1_pins[] = { DB8540_PIN_J3 };
+static const unsigned mc4rstn_c_1_pins[] = { DB8540_PIN_C6 };
+static const unsigned spi0_c_1_pins[] = { DB8540_PIN_A10, DB8540_PIN_B10,
+       DB8540_PIN_E10, DB8540_PIN_B12 };
+static const unsigned i2c3_c_1_pins[] = { DB8540_PIN_B13, DB8540_PIN_C12 };
+
+/* Other alt C1 column */
+static const unsigned spi3_oc1_1_pins[] = { DB8540_PIN_AG5, DB8540_PIN_AH5,
+       DB8540_PIN_AE4, DB8540_PIN_AD1 };
+static const unsigned stmape_oc1_1_pins[] = { DB8540_PIN_AH11, DB8540_PIN_AF11,
+       DB8540_PIN_AH10, DB8540_PIN_AG10, DB8540_PIN_AF10 };
+static const unsigned u2_oc1_1_pins[] = { DB8540_PIN_AG11 };
+static const unsigned remap0_oc1_1_pins[] = { DB8540_PIN_AJ24 };
+static const unsigned remap1_oc1_1_pins[] = { DB8540_PIN_AE21 };
+static const unsigned modobsrefclk_oc1_1_pins[] = { DB8540_PIN_M26 };
+static const unsigned modobspwrctrl_oc1_1_pins[] = { DB8540_PIN_M25 };
+static const unsigned modobsclkout_oc1_1_pins[] = { DB8540_PIN_M27 };
+static const unsigned moduart1_oc1_1_pins[] = { DB8540_PIN_N25 };
+static const unsigned modprcmudbg_oc1_1_pins[] = { DB8540_PIN_M28,
+       DB8540_PIN_N26, DB8540_PIN_M22, DB8540_PIN_N22, DB8540_PIN_N27,
+       DB8540_PIN_P22, DB8540_PIN_P28, DB8540_PIN_P26, DB8540_PIN_T22,
+       DB8540_PIN_R26, DB8540_PIN_R25, DB8540_PIN_U22, DB8540_PIN_T27,
+       DB8540_PIN_AH20, DB8540_PIN_AG19, DB8540_PIN_AF22, DB8540_PIN_AJ21,
+       DB8540_PIN_T25};
+static const unsigned modobsresout_oc1_1_pins[] = { DB8540_PIN_N28 };
+static const unsigned modaccgpo_oc1_1_pins[] = { DB8540_PIN_R27, DB8540_PIN_P27,
+       DB8540_PIN_T26 };
+static const unsigned kp_oc1_1_pins[] = { DB8540_PIN_AG22, DB8540_PIN_AF21,
+       DB8540_PIN_AF24, DB8540_PIN_AH22, DB8540_PIN_AJ23, DB8540_PIN_AH21,
+       DB8540_PIN_AG20, DB8540_PIN_AE23 };
+static const unsigned modxmip_oc1_1_pins[] = { DB8540_PIN_AD25, DB8540_PIN_AH25,
+       DB8540_PIN_AG23, DB8540_PIN_AE25 };
+static const unsigned i2c6_oc1_1_pins[] = { DB8540_PIN_AE26, DB8540_PIN_AE24 };
+static const unsigned u2txrx_oc1_1_pins[] = { DB8540_PIN_B7, DB8540_PIN_A7 };
+static const unsigned u2ctsrts_oc1_1_pins[] = { DB8540_PIN_D7, DB8540_PIN_D8 };
+
+/* Other alt C2 column */
+static const unsigned sbag_oc2_1_pins[] = { DB8540_PIN_AH11, DB8540_PIN_AG11,
+       DB8540_PIN_AF11, DB8540_PIN_AH10, DB8540_PIN_AG10, DB8540_PIN_AF10 };
+static const unsigned hxclk_oc2_1_pins[] = { DB8540_PIN_M25 };
+static const unsigned modaccuart_oc2_1_pins[] = { DB8540_PIN_N25 };
+static const unsigned stmmod_oc2_1_pins[] = { DB8540_PIN_M28, DB8540_PIN_N26,
+       DB8540_PIN_M22, DB8540_PIN_N22, DB8540_PIN_N27 };
+static const unsigned moduartstmmux_oc2_1_pins[] = { DB8540_PIN_N28 };
+static const unsigned hxgpio_oc2_1_pins[] = { DB8540_PIN_P22, DB8540_PIN_P28,
+       DB8540_PIN_P26, DB8540_PIN_T22, DB8540_PIN_R27, DB8540_PIN_P27,
+       DB8540_PIN_R26, DB8540_PIN_R25 };
+static const unsigned sbag_oc2_2_pins[] = { DB8540_PIN_U22, DB8540_PIN_T27,
+       DB8540_PIN_AG22, DB8540_PIN_AF21, DB8540_PIN_AF24, DB8540_PIN_AH22 };
+static const unsigned modobsservice_oc2_1_pins[] = { DB8540_PIN_AJ23 };
+static const unsigned moduart0_oc2_1_pins[] = { DB8540_PIN_AG20,
+       DB8540_PIN_AE23 };
+static const unsigned stmape_oc2_1_pins[] = { DB8540_PIN_AH20, DB8540_PIN_AG19,
+       DB8540_PIN_AF22, DB8540_PIN_AJ21, DB8540_PIN_T25 };
+static const unsigned u2_oc2_1_pins[] = { DB8540_PIN_T26, DB8540_PIN_AH21 };
+static const unsigned modxmip_oc2_1_pins[] = { DB8540_PIN_AE26,
+       DB8540_PIN_AE24 };
+
+/* Other alt C3 column */
+static const unsigned modaccgpo_oc3_1_pins[] = { DB8540_PIN_AG11 };
+static const unsigned tpui_oc3_1_pins[] = { DB8540_PIN_M26, DB8540_PIN_M25,
+       DB8540_PIN_M27, DB8540_PIN_N25, DB8540_PIN_M28, DB8540_PIN_N26,
+       DB8540_PIN_M22, DB8540_PIN_N22, DB8540_PIN_N27, DB8540_PIN_N28,
+       DB8540_PIN_P22, DB8540_PIN_P28, DB8540_PIN_P26, DB8540_PIN_T22,
+       DB8540_PIN_R27, DB8540_PIN_P27, DB8540_PIN_R26, DB8540_PIN_R25,
+       DB8540_PIN_U22, DB8540_PIN_T27, DB8540_PIN_AG22, DB8540_PIN_AF21,
+       DB8540_PIN_AF24, DB8540_PIN_AH22, DB8540_PIN_AJ23, DB8540_PIN_AH21,
+       DB8540_PIN_AG20, DB8540_PIN_AE23, DB8540_PIN_AH20, DB8540_PIN_AG19,
+       DB8540_PIN_AF22, DB8540_PIN_AJ21, DB8540_PIN_T25, DB8540_PIN_T26 };
+
+/* Other alt C4 column */
+static const unsigned hwobs_oc4_1_pins[] = { DB8540_PIN_M26, DB8540_PIN_M25,
+       DB8540_PIN_M27, DB8540_PIN_N25, DB8540_PIN_M28, DB8540_PIN_N26,
+       DB8540_PIN_M22, DB8540_PIN_N22, DB8540_PIN_N27, DB8540_PIN_N28,
+       DB8540_PIN_P22, DB8540_PIN_P28, DB8540_PIN_P26, DB8540_PIN_T22,
+       DB8540_PIN_R27, DB8540_PIN_P27, DB8540_PIN_R26, DB8540_PIN_R25 };
+static const unsigned moduart1txrx_oc4_1_pins[] = { DB8540_PIN_U22,
+       DB8540_PIN_T27 };
+static const unsigned moduart1rtscts_oc4_1_pins[] = { DB8540_PIN_AG22,
+       DB8540_PIN_AF21 };
+static const unsigned modaccuarttxrx_oc4_1_pins[] = { DB8540_PIN_AF24,
+       DB8540_PIN_AH22 };
+static const unsigned modaccuartrtscts_oc4_1_pins[] = { DB8540_PIN_AJ23,
+       DB8540_PIN_AH21 };
+static const unsigned stmmod_oc4_1_pins[] = { DB8540_PIN_AH20, DB8540_PIN_AG19,
+       DB8540_PIN_AF22, DB8540_PIN_AJ21, DB8540_PIN_T25 };
+static const unsigned moduartstmmux_oc4_1_pins[] = { DB8540_PIN_T26 };
+
+#define DB8540_PIN_GROUP(a, b) { .name = #a, .pins = a##_pins,         \
+                       .npins = ARRAY_SIZE(a##_pins), .altsetting = b }
+
+static const struct nmk_pingroup nmk_db8540_groups[] = {
+       /* Altfunction A column */
+       DB8540_PIN_GROUP(u0_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(u1rxtx_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(u1ctsrts_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(ipi2c_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(ipi2c_a_2, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(msp0txrx_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(msp0tfstck_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(msp0rfsrck_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(mc0_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(msp1txrx_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(msp1_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(modobsclk_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(clkoutreq_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(lcdb_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(lcdvsi0_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(lcdvsi1_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(lcd_d0_d7_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(lcd_d8_d11_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(lcd_d12_d23_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(kp_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(mc2_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(ssp1_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(ssp0_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(i2c0_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(ipgpio0_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(ipgpio1_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(modi2s_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(spi2_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(u2txrx_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(u2ctsrts_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(modsmb_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(msp2sck_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(msp2txdtcktfs_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(msp2rxd_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(mc4_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(mc1_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(hsir_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(hsit_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(hsit_a_2, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(clkout_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(clkout_a_2, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(msp4_a_1, NMK_GPIO_ALT_A),
+       DB8540_PIN_GROUP(usb_a_1, NMK_GPIO_ALT_A),
+       /* Altfunction B column */
+       DB8540_PIN_GROUP(apetrig_b_1, NMK_GPIO_ALT_B),
+       DB8540_PIN_GROUP(modtrig_b_1, NMK_GPIO_ALT_B),
+       DB8540_PIN_GROUP(i2c4_b_1, NMK_GPIO_ALT_B),
+       DB8540_PIN_GROUP(i2c1_b_1, NMK_GPIO_ALT_B),
+       DB8540_PIN_GROUP(i2c2_b_1, NMK_GPIO_ALT_B),
+       DB8540_PIN_GROUP(i2c2_b_2, NMK_GPIO_ALT_B),
+       DB8540_PIN_GROUP(msp0txrx_b_1, NMK_GPIO_ALT_B),
+       DB8540_PIN_GROUP(i2c1_b_2, NMK_GPIO_ALT_B),
+       DB8540_PIN_GROUP(stmmod_b_1, NMK_GPIO_ALT_B),
+       DB8540_PIN_GROUP(moduartstmmux_b_1, NMK_GPIO_ALT_B),
+       DB8540_PIN_GROUP(msp1txrx_b_1, NMK_GPIO_ALT_B),
+       DB8540_PIN_GROUP(kp_b_1, NMK_GPIO_ALT_B),
+       DB8540_PIN_GROUP(u2txrx_b_1, NMK_GPIO_ALT_B),
+       DB8540_PIN_GROUP(sm_b_1, NMK_GPIO_ALT_B),
+       DB8540_PIN_GROUP(smcs0_b_1, NMK_GPIO_ALT_B),
+       DB8540_PIN_GROUP(smcs1_b_1, NMK_GPIO_ALT_B),
+       DB8540_PIN_GROUP(ipgpio7_b_1, NMK_GPIO_ALT_B),
+       DB8540_PIN_GROUP(ipgpio2_b_1, NMK_GPIO_ALT_B),
+       DB8540_PIN_GROUP(ipgpio3_b_1, NMK_GPIO_ALT_B),
+       DB8540_PIN_GROUP(i2c6_b_1, NMK_GPIO_ALT_B),
+       DB8540_PIN_GROUP(i2c5_b_1, NMK_GPIO_ALT_B),
+       DB8540_PIN_GROUP(u3txrx_b_1, NMK_GPIO_ALT_B),
+       DB8540_PIN_GROUP(u3ctsrts_b_1, NMK_GPIO_ALT_B),
+       DB8540_PIN_GROUP(i2c5_b_2, NMK_GPIO_ALT_B),
+       DB8540_PIN_GROUP(i2c4_b_2, NMK_GPIO_ALT_B),
+       DB8540_PIN_GROUP(u4txrx_b_1, NMK_GPIO_ALT_B),
+       DB8540_PIN_GROUP(u4ctsrts_b_1, NMK_GPIO_ALT_B),
+       DB8540_PIN_GROUP(ddrtrig_b_1, NMK_GPIO_ALT_B),
+       DB8540_PIN_GROUP(msp4_b_1, NMK_GPIO_ALT_B),
+       DB8540_PIN_GROUP(pwl_b_1, NMK_GPIO_ALT_B),
+       DB8540_PIN_GROUP(spi1_b_1, NMK_GPIO_ALT_B),
+       DB8540_PIN_GROUP(mc3_b_1, NMK_GPIO_ALT_B),
+       DB8540_PIN_GROUP(pwl_b_2, NMK_GPIO_ALT_B),
+       DB8540_PIN_GROUP(pwl_b_3, NMK_GPIO_ALT_B),
+       DB8540_PIN_GROUP(pwl_b_4, NMK_GPIO_ALT_B),
+       DB8540_PIN_GROUP(u2txrx_b_2, NMK_GPIO_ALT_B),
+       /* Altfunction C column */
+       DB8540_PIN_GROUP(ipgpio6_c_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(ipgpio0_c_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(ipgpio1_c_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(ipgpio3_c_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(ipgpio2_c_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(u0_c_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(smcleale_c_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(ipgpio4_c_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(ipgpio5_c_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(ipgpio6_c_2, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(ipgpio7_c_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(stmape_c_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(u2rxtx_c_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(modobsresout_c_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(ipgpio2_c_2, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(ipgpio3_c_2, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(ipgpio4_c_2, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(ipgpio5_c_2, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(modaccgpo_c_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(modobspwrrst_c_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(mc5_c_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(smps0_c_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(moduart1_c_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(mc2rstn_c_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(i2c5_c_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(ipgpio0_c_2, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(ipgpio1_c_2, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(kp_c_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(modrf_c_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(smps1_c_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(i2c5_c_2, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(u4ctsrts_c_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(u3rxtx_c_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(msp4_c_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(mc4rstn_c_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(spi0_c_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(i2c3_c_1, NMK_GPIO_ALT_C),
+
+       /* Other alt C1 column, these are still configured as alt C */
+       DB8540_PIN_GROUP(spi3_oc1_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(stmape_oc1_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(u2_oc1_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(remap0_oc1_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(remap1_oc1_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(modobsrefclk_oc1_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(modobspwrctrl_oc1_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(modobsclkout_oc1_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(moduart1_oc1_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(modprcmudbg_oc1_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(modobsresout_oc1_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(modaccgpo_oc1_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(kp_oc1_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(modxmip_oc1_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(i2c6_oc1_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(u2txrx_oc1_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(u2ctsrts_oc1_1, NMK_GPIO_ALT_C),
+
+       /* Other alt C2 column, these are still configured as alt C */
+       DB8540_PIN_GROUP(sbag_oc2_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(hxclk_oc2_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(modaccuart_oc2_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(stmmod_oc2_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(moduartstmmux_oc2_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(hxgpio_oc2_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(sbag_oc2_2, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(modobsservice_oc2_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(moduart0_oc2_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(stmape_oc2_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(u2_oc2_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(modxmip_oc2_1, NMK_GPIO_ALT_C),
+
+       /* Other alt C3 column, these are still configured as alt C */
+       DB8540_PIN_GROUP(modaccgpo_oc3_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(tpui_oc3_1, NMK_GPIO_ALT_C),
+
+       /* Other alt C4 column, these are still configured as alt C */
+       DB8540_PIN_GROUP(hwobs_oc4_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(moduart1txrx_oc4_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(moduart1rtscts_oc4_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(modaccuarttxrx_oc4_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(modaccuartrtscts_oc4_1, NMK_GPIO_ALT_C),
+       DB8540_PIN_GROUP(stmmod_oc4_1, NMK_GPIO_ALT_C),
+
+};
+
+/* We use this macro to define the groups applicable to a function */
+#define DB8540_FUNC_GROUPS(a, b...)       \
+static const char * const a##_groups[] = { b };
+
+DB8540_FUNC_GROUPS(apetrig, "apetrig_b_1");
+DB8540_FUNC_GROUPS(clkout, "clkoutreq_a_1", "clkout_a_1", "clkout_a_2");
+DB8540_FUNC_GROUPS(ddrtrig, "ddrtrig_b_1");
+DB8540_FUNC_GROUPS(hsi, "hsir_a_1", "hsit_a_1", "hsit_a_2");
+DB8540_FUNC_GROUPS(hwobs, "hwobs_oc4_1");
+DB8540_FUNC_GROUPS(hx, "hxclk_oc2_1", "hxgpio_oc2_1");
+DB8540_FUNC_GROUPS(i2c0, "i2c0_a_1");
+DB8540_FUNC_GROUPS(i2c1, "i2c1_b_1", "i2c1_b_2");
+DB8540_FUNC_GROUPS(i2c2, "i2c2_b_1", "i2c2_b_2");
+DB8540_FUNC_GROUPS(i2c3, "i2c3_c_1", "i2c4_b_1");
+DB8540_FUNC_GROUPS(i2c4, "i2c4_b_2");
+DB8540_FUNC_GROUPS(i2c5, "i2c5_b_1", "i2c5_b_2", "i2c5_c_1", "i2c5_c_2");
+DB8540_FUNC_GROUPS(i2c6, "i2c6_b_1", "i2c6_oc1_1");
+/* The image processor has 8 GPIO pins that can be muxed out */
+DB8540_FUNC_GROUPS(ipgpio, "ipgpio0_a_1", "ipgpio0_c_1", "ipgpio0_c_2",
+               "ipgpio1_a_1", "ipgpio1_c_1", "ipgpio1_c_2",
+               "ipgpio2_b_1", "ipgpio2_c_1", "ipgpio2_c_2",
+               "ipgpio3_b_1", "ipgpio3_c_1", "ipgpio3_c_2",
+               "ipgpio4_c_1", "ipgpio4_c_2",
+               "ipgpio5_c_1", "ipgpio5_c_2",
+               "ipgpio6_c_1", "ipgpio6_c_2",
+               "ipgpio7_b_1", "ipgpio7_c_1");
+DB8540_FUNC_GROUPS(ipi2c, "ipi2c_a_1", "ipi2c_a_2");
+DB8540_FUNC_GROUPS(kp, "kp_a_1", "kp_b_1", "kp_c_1", "kp_oc1_1");
+DB8540_FUNC_GROUPS(lcd, "lcd_d0_d7_a_1", "lcd_d12_d23_a_1", "lcd_d8_d11_a_1",
+               "lcdvsi0_a_1", "lcdvsi1_a_1");
+DB8540_FUNC_GROUPS(lcdb, "lcdb_a_1");
+DB8540_FUNC_GROUPS(mc0, "mc0_a_1");
+DB8540_FUNC_GROUPS(mc1, "mc1_a_1", "mc1_a_2");
+DB8540_FUNC_GROUPS(mc2, "mc2_a_1", "mc2rstn_c_1");
+DB8540_FUNC_GROUPS(mc3, "mc3_b_1");
+DB8540_FUNC_GROUPS(mc4, "mc4_a_1", "mc4rstn_c_1");
+DB8540_FUNC_GROUPS(mc5, "mc5_c_1");
+DB8540_FUNC_GROUPS(modaccgpo, "modaccgpo_c_1", "modaccgpo_oc1_1",
+               "modaccgpo_oc3_1");
+DB8540_FUNC_GROUPS(modaccuart, "modaccuart_oc2_1", "modaccuarttxrx_oc4_1",
+               "modaccuartrtccts_oc4_1");
+DB8540_FUNC_GROUPS(modi2s, "modi2s_a_1");
+DB8540_FUNC_GROUPS(modobs, "modobsclk_a_1", "modobsclkout_oc1_1",
+               "modobspwrctrl_oc1_1", "modobspwrrst_c_1",
+               "modobsrefclk_oc1_1", "modobsresout_c_1",
+               "modobsresout_oc1_1", "modobsservice_oc2_1");
+DB8540_FUNC_GROUPS(modprcmudbg, "modprcmudbg_oc1_1");
+DB8540_FUNC_GROUPS(modrf, "modrf_c_1");
+DB8540_FUNC_GROUPS(modsmb, "modsmb_a_1");
+DB8540_FUNC_GROUPS(modtrig, "modtrig_b_1");
+DB8540_FUNC_GROUPS(moduart, "moduart1_c_1", "moduart1_oc1_1",
+               "moduart1txrx_oc4_1", "moduart1rtscts_oc4_1", "moduart0_oc2_1");
+DB8540_FUNC_GROUPS(moduartstmmux, "moduartstmmux_b_1", "moduartstmmux_oc2_1",
+               "moduartstmmux_oc4_1");
+DB8540_FUNC_GROUPS(modxmip, "modxmip_oc1_1", "modxmip_oc2_1");
+/*
+ * MSP0 can only be on a certain set of pins, but the TX/RX pins can be
+ * switched around by selecting the altfunction A or B.
+ */
+DB8540_FUNC_GROUPS(msp0, "msp0rfsrck_a_1", "msp0tfstck_a_1", "msp0txrx_a_1",
+               "msp0txrx_b_1");
+DB8540_FUNC_GROUPS(msp1, "msp1_a_1", "msp1txrx_a_1", "msp1txrx_b_1");
+DB8540_FUNC_GROUPS(msp2, "msp2sck_a_1", "msp2txdtcktfs_a_1", "msp2rxd_a_1");
+DB8540_FUNC_GROUPS(msp4, "msp4_a_1", "msp4_b_1", "msp4_c_1");
+DB8540_FUNC_GROUPS(pwl, "pwl_b_1", "pwl_b_2", "pwl_b_3", "pwl_b_4");
+DB8540_FUNC_GROUPS(remap, "remap0_oc1_1", "remap1_oc1_1");
+DB8540_FUNC_GROUPS(sbag, "sbag_oc2_1", "sbag_oc2_2");
+/* Select between CS0 on alt B or PS1 on alt C */
+DB8540_FUNC_GROUPS(sm, "sm_b_1", "smcleale_c_1", "smcs0_b_1", "smcs1_b_1",
+               "smps0_c_1", "smps1_c_1");
+DB8540_FUNC_GROUPS(spi0, "spi0_c_1");
+DB8540_FUNC_GROUPS(spi1, "spi1_b_1");
+DB8540_FUNC_GROUPS(spi2, "spi2_a_1");
+DB8540_FUNC_GROUPS(spi3, "spi3_oc1_1");
+DB8540_FUNC_GROUPS(ssp0, "ssp0_a_1");
+DB8540_FUNC_GROUPS(ssp1, "ssp1_a_1");
+DB8540_FUNC_GROUPS(stmape, "stmape_c_1", "stmape_oc1_1", "stmape_oc2_1");
+DB8540_FUNC_GROUPS(stmmod, "stmmod_b_1", "stmmod_oc2_1", "stmmod_oc4_1");
+DB8540_FUNC_GROUPS(tpui, "tpui_oc3_1");
+DB8540_FUNC_GROUPS(u0, "u0_a_1", "u0_c_1");
+DB8540_FUNC_GROUPS(u1, "u1ctsrts_a_1", "u1rxtx_a_1");
+DB8540_FUNC_GROUPS(u2, "u2_oc1_1", "u2_oc2_1", "u2ctsrts_a_1", "u2ctsrts_oc1_1",
+               "u2rxtx_c_1", "u2txrx_a_1", "u2txrx_b_1", "u2txrx_b_2",
+               "u2txrx_oc1_1");
+DB8540_FUNC_GROUPS(u3, "u3ctsrts_b_1", "u3rxtx_c_1", "u3txrxa_b_1");
+DB8540_FUNC_GROUPS(u4, "u4ctsrts_b_1", "u4ctsrts_c_1", "u4txrx_b_1");
+DB8540_FUNC_GROUPS(usb, "usb_a_1");
+
+
+#define FUNCTION(fname)                                        \
+       {                                               \
+               .name = #fname,                         \
+               .groups = fname##_groups,               \
+               .ngroups = ARRAY_SIZE(fname##_groups),  \
+       }
+
+static const struct nmk_function nmk_db8540_functions[] = {
+       FUNCTION(apetrig),
+       FUNCTION(clkout),
+       FUNCTION(ddrtrig),
+       FUNCTION(hsi),
+       FUNCTION(hwobs),
+       FUNCTION(hx),
+       FUNCTION(i2c0),
+       FUNCTION(i2c1),
+       FUNCTION(i2c2),
+       FUNCTION(i2c3),
+       FUNCTION(i2c4),
+       FUNCTION(i2c5),
+       FUNCTION(i2c6),
+       FUNCTION(ipgpio),
+       FUNCTION(ipi2c),
+       FUNCTION(kp),
+       FUNCTION(lcd),
+       FUNCTION(lcdb),
+       FUNCTION(mc0),
+       FUNCTION(mc1),
+       FUNCTION(mc2),
+       FUNCTION(mc3),
+       FUNCTION(mc4),
+       FUNCTION(mc5),
+       FUNCTION(modaccgpo),
+       FUNCTION(modaccuart),
+       FUNCTION(modi2s),
+       FUNCTION(modobs),
+       FUNCTION(modprcmudbg),
+       FUNCTION(modrf),
+       FUNCTION(modsmb),
+       FUNCTION(modtrig),
+       FUNCTION(moduart),
+       FUNCTION(modxmip),
+       FUNCTION(msp0),
+       FUNCTION(msp1),
+       FUNCTION(msp2),
+       FUNCTION(msp4),
+       FUNCTION(pwl),
+       FUNCTION(remap),
+       FUNCTION(sbag),
+       FUNCTION(sm),
+       FUNCTION(spi0),
+       FUNCTION(spi1),
+       FUNCTION(spi2),
+       FUNCTION(spi3),
+       FUNCTION(ssp0),
+       FUNCTION(ssp1),
+       FUNCTION(stmape),
+       FUNCTION(stmmod),
+       FUNCTION(tpui),
+       FUNCTION(u0),
+       FUNCTION(u1),
+       FUNCTION(u2),
+       FUNCTION(u3),
+       FUNCTION(u4),
+       FUNCTION(usb)
+};
+
+static const struct nmk_pinctrl_soc_data nmk_db8540_soc = {
+       .gpio_ranges = nmk_db8540_ranges,
+       .gpio_num_ranges = ARRAY_SIZE(nmk_db8540_ranges),
+       .pins = nmk_db8540_pins,
+       .npins = ARRAY_SIZE(nmk_db8540_pins),
+       .functions = nmk_db8540_functions,
+       .nfunctions = ARRAY_SIZE(nmk_db8540_functions),
+       .groups = nmk_db8540_groups,
+       .ngroups = ARRAY_SIZE(nmk_db8540_groups),
+};
+
+void __devinit
+nmk_pinctrl_db8540_init(const struct nmk_pinctrl_soc_data **soc)
+{
+       *soc = &nmk_db8540_soc;
+}
diff --git a/drivers/pinctrl/pinctrl-nomadik-stn8815.c b/drivers/pinctrl/pinctrl-nomadik-stn8815.c
new file mode 100644 (file)
index 0000000..7d432c3
--- /dev/null
@@ -0,0 +1,357 @@
+#include <linux/kernel.h>
+#include <linux/pinctrl/pinctrl.h>
+#include "pinctrl-nomadik.h"
+
+/* All the pins that can be used for GPIO and some other functions */
+#define _GPIO(offset)          (offset)
+
+#define STN8815_PIN_B4         _GPIO(0)
+#define STN8815_PIN_D5         _GPIO(1)
+#define STN8815_PIN_C5         _GPIO(2)
+#define STN8815_PIN_A4         _GPIO(3)
+#define STN8815_PIN_B5         _GPIO(4)
+#define STN8815_PIN_D6         _GPIO(5)
+#define STN8815_PIN_C6         _GPIO(6)
+#define STN8815_PIN_B6         _GPIO(7)
+#define STN8815_PIN_B10                _GPIO(8)
+#define STN8815_PIN_A10                _GPIO(9)
+#define STN8815_PIN_C11                _GPIO(10)
+#define STN8815_PIN_B11                _GPIO(11)
+#define STN8815_PIN_A11                _GPIO(12)
+#define STN8815_PIN_C12                _GPIO(13)
+#define STN8815_PIN_B12                _GPIO(14)
+#define STN8815_PIN_A12                _GPIO(15)
+#define STN8815_PIN_C13                _GPIO(16)
+#define STN8815_PIN_B13                _GPIO(17)
+#define STN8815_PIN_A13                _GPIO(18)
+#define STN8815_PIN_D13                _GPIO(19)
+#define STN8815_PIN_C14                _GPIO(20)
+#define STN8815_PIN_B14                _GPIO(21)
+#define STN8815_PIN_A14                _GPIO(22)
+#define STN8815_PIN_D15                _GPIO(23)
+#define STN8815_PIN_C15                _GPIO(24)
+#define STN8815_PIN_B15                _GPIO(25)
+#define STN8815_PIN_A15                _GPIO(26)
+#define STN8815_PIN_C16                _GPIO(27)
+#define STN8815_PIN_B16                _GPIO(28)
+#define STN8815_PIN_A16                _GPIO(29)
+#define STN8815_PIN_D17                _GPIO(30)
+#define STN8815_PIN_C17                _GPIO(31)
+#define STN8815_PIN_AB6                _GPIO(32)
+#define STN8815_PIN_AA6                _GPIO(33)
+#define STN8815_PIN_Y6         _GPIO(34)
+#define STN8815_PIN_Y5         _GPIO(35)
+#define STN8815_PIN_AA5                _GPIO(36)
+#define STN8815_PIN_AB5                _GPIO(37)
+#define STN8815_PIN_AB4                _GPIO(38)
+#define STN8815_PIN_Y4         _GPIO(39)
+#define STN8815_PIN_R1         _GPIO(40)
+#define STN8815_PIN_R2         _GPIO(41)
+#define STN8815_PIN_R3         _GPIO(42)
+#define STN8815_PIN_P1         _GPIO(43)
+#define STN8815_PIN_P2         _GPIO(44)
+#define STN8815_PIN_P3         _GPIO(45)
+#define STN8815_PIN_N1         _GPIO(46)
+#define STN8815_PIN_N2         _GPIO(47)
+#define STN8815_PIN_N3         _GPIO(48)
+#define STN8815_PIN_M1         _GPIO(49)
+#define STN8815_PIN_M3         _GPIO(50)
+#define STN8815_PIN_M2         _GPIO(51)
+#define STN8815_PIN_L1         _GPIO(52)
+#define STN8815_PIN_L4         _GPIO(53)
+#define STN8815_PIN_L3         _GPIO(54)
+#define STN8815_PIN_L2         _GPIO(55)
+#define STN8815_PIN_F3         _GPIO(56)
+#define STN8815_PIN_F2         _GPIO(57)
+#define STN8815_PIN_E1         _GPIO(58)
+#define STN8815_PIN_E3         _GPIO(59)
+#define STN8815_PIN_E2         _GPIO(60)
+#define STN8815_PIN_E4         _GPIO(61)
+#define STN8815_PIN_D3         _GPIO(62)
+#define STN8815_PIN_D2         _GPIO(63)
+#define STN8815_PIN_F21                _GPIO(64)
+#define STN8815_PIN_F20                _GPIO(65)
+#define STN8815_PIN_E22                _GPIO(66)
+#define STN8815_PIN_D22                _GPIO(67)
+#define STN8815_PIN_E21                _GPIO(68)
+#define STN8815_PIN_E20                _GPIO(69)
+#define STN8815_PIN_C22                _GPIO(70)
+#define STN8815_PIN_D21                _GPIO(71)
+#define STN8815_PIN_D20                _GPIO(72)
+#define STN8815_PIN_C21                _GPIO(73)
+#define STN8815_PIN_C20                _GPIO(74)
+#define STN8815_PIN_C19                _GPIO(75)
+#define STN8815_PIN_B20                _GPIO(76)
+#define STN8815_PIN_B8         _GPIO(77)
+#define STN8815_PIN_A8         _GPIO(78)
+#define STN8815_PIN_C9         _GPIO(79)
+#define STN8815_PIN_B9         _GPIO(80)
+#define STN8815_PIN_A9         _GPIO(81)
+#define STN8815_PIN_C10                _GPIO(82)
+#define STN8815_PIN_K1         _GPIO(83)
+#define STN8815_PIN_K3         _GPIO(84)
+#define STN8815_PIN_K2         _GPIO(85)
+#define STN8815_PIN_J1         _GPIO(86)
+#define STN8815_PIN_J3         _GPIO(87)
+#define STN8815_PIN_J2         _GPIO(88)
+#define STN8815_PIN_H1         _GPIO(89)
+#define STN8815_PIN_H3         _GPIO(90)
+#define STN8815_PIN_H2         _GPIO(91)
+#define STN8815_PIN_G1         _GPIO(92)
+#define STN8815_PIN_G3         _GPIO(93)
+#define STN8815_PIN_G2         _GPIO(94)
+#define STN8815_PIN_F1         _GPIO(95)
+#define STN8815_PIN_T20                _GPIO(96)
+#define STN8815_PIN_R21                _GPIO(97)
+#define STN8815_PIN_R20                _GPIO(98)
+#define STN8815_PIN_U22                _GPIO(99)
+#define STN8815_PIN_N21                _GPIO(100)
+#define STN8815_PIN_N20                _GPIO(101)
+#define STN8815_PIN_P22                _GPIO(102)
+#define STN8815_PIN_N22                _GPIO(103)
+#define STN8815_PIN_V22                _GPIO(104)
+#define STN8815_PIN_V21                _GPIO(105)
+#define STN8815_PIN_K22                _GPIO(106)
+#define STN8815_PIN_K21                _GPIO(107)
+#define STN8815_PIN_H20                _GPIO(108)
+#define STN8815_PIN_G20                _GPIO(109)
+#define STN8815_PIN_L21                _GPIO(110)
+#define STN8815_PIN_H21                _GPIO(111)
+#define STN8815_PIN_J21                _GPIO(112)
+#define STN8815_PIN_H22                _GPIO(113)
+#define STN8815_PIN_K20                _GPIO(114)
+#define STN8815_PIN_L22                _GPIO(115)
+#define STN8815_PIN_G21                _GPIO(116)
+#define STN8815_PIN_J20                _GPIO(117)
+#define STN8815_PIN_G22                _GPIO(118)
+#define STN8815_PIN_U19                _GPIO(119)
+#define STN8815_PIN_G19                _GPIO(120)
+#define STN8815_PIN_M22                _GPIO(121)
+#define STN8815_PIN_M19                _GPIO(122)
+#define STN8815_PIN_J22                _GPIO(123)
+/* GPIOs 124-127 not routed to pins */
+
+/*
+ * The names of the pins are denoted by GPIO number and ball name, even
+ * though they can be used for other things than GPIO, this is the first
+ * column in the table of the data sheet and often used on schematics and
+ * such.
+ */
+static const struct pinctrl_pin_desc nmk_stn8815_pins[] = {
+       PINCTRL_PIN(STN8815_PIN_B4, "GPIO0_B4"),
+       PINCTRL_PIN(STN8815_PIN_D5, "GPIO1_D5"),
+       PINCTRL_PIN(STN8815_PIN_C5, "GPIO2_C5"),
+       PINCTRL_PIN(STN8815_PIN_A4, "GPIO3_A4"),
+       PINCTRL_PIN(STN8815_PIN_B5, "GPIO4_B5"),
+       PINCTRL_PIN(STN8815_PIN_D6, "GPIO5_D6"),
+       PINCTRL_PIN(STN8815_PIN_C6, "GPIO6_C6"),
+       PINCTRL_PIN(STN8815_PIN_B6, "GPIO7_B6"),
+       PINCTRL_PIN(STN8815_PIN_B10, "GPIO8_B10"),
+       PINCTRL_PIN(STN8815_PIN_A10, "GPIO9_A10"),
+       PINCTRL_PIN(STN8815_PIN_C11, "GPIO10_C11"),
+       PINCTRL_PIN(STN8815_PIN_B11, "GPIO11_B11"),
+       PINCTRL_PIN(STN8815_PIN_A11, "GPIO12_A11"),
+       PINCTRL_PIN(STN8815_PIN_C12, "GPIO13_C12"),
+       PINCTRL_PIN(STN8815_PIN_B12, "GPIO14_B12"),
+       PINCTRL_PIN(STN8815_PIN_A12, "GPIO15_A12"),
+       PINCTRL_PIN(STN8815_PIN_C13, "GPIO16_C13"),
+       PINCTRL_PIN(STN8815_PIN_B13, "GPIO17_B13"),
+       PINCTRL_PIN(STN8815_PIN_A13, "GPIO18_A13"),
+       PINCTRL_PIN(STN8815_PIN_D13, "GPIO19_D13"),
+       PINCTRL_PIN(STN8815_PIN_C14, "GPIO20_C14"),
+       PINCTRL_PIN(STN8815_PIN_B14, "GPIO21_B14"),
+       PINCTRL_PIN(STN8815_PIN_A14, "GPIO22_A14"),
+       PINCTRL_PIN(STN8815_PIN_D15, "GPIO23_D15"),
+       PINCTRL_PIN(STN8815_PIN_C15, "GPIO24_C15"),
+       PINCTRL_PIN(STN8815_PIN_B15, "GPIO25_B15"),
+       PINCTRL_PIN(STN8815_PIN_A15, "GPIO26_A15"),
+       PINCTRL_PIN(STN8815_PIN_C16, "GPIO27_C16"),
+       PINCTRL_PIN(STN8815_PIN_B16, "GPIO28_B16"),
+       PINCTRL_PIN(STN8815_PIN_A16, "GPIO29_A16"),
+       PINCTRL_PIN(STN8815_PIN_D17, "GPIO30_D17"),
+       PINCTRL_PIN(STN8815_PIN_C17, "GPIO31_C17"),
+       PINCTRL_PIN(STN8815_PIN_AB6, "GPIO32_AB6"),
+       PINCTRL_PIN(STN8815_PIN_AA6, "GPIO33_AA6"),
+       PINCTRL_PIN(STN8815_PIN_Y6, "GPIO34_Y6"),
+       PINCTRL_PIN(STN8815_PIN_Y5, "GPIO35_Y5"),
+       PINCTRL_PIN(STN8815_PIN_AA5, "GPIO36_AA5"),
+       PINCTRL_PIN(STN8815_PIN_AB5, "GPIO37_AB5"),
+       PINCTRL_PIN(STN8815_PIN_AB4, "GPIO38_AB4"),
+       PINCTRL_PIN(STN8815_PIN_Y4, "GPIO39_Y4"),
+       PINCTRL_PIN(STN8815_PIN_R1, "GPIO40_R1"),
+       PINCTRL_PIN(STN8815_PIN_R2, "GPIO41_R2"),
+       PINCTRL_PIN(STN8815_PIN_R3, "GPIO42_R3"),
+       PINCTRL_PIN(STN8815_PIN_P1, "GPIO43_P1"),
+       PINCTRL_PIN(STN8815_PIN_P2, "GPIO44_P2"),
+       PINCTRL_PIN(STN8815_PIN_P3, "GPIO45_P3"),
+       PINCTRL_PIN(STN8815_PIN_N1, "GPIO46_N1"),
+       PINCTRL_PIN(STN8815_PIN_N2, "GPIO47_N2"),
+       PINCTRL_PIN(STN8815_PIN_N3, "GPIO48_N3"),
+       PINCTRL_PIN(STN8815_PIN_M1, "GPIO49_M1"),
+       PINCTRL_PIN(STN8815_PIN_M3, "GPIO50_M3"),
+       PINCTRL_PIN(STN8815_PIN_M2, "GPIO51_M2"),
+       PINCTRL_PIN(STN8815_PIN_L1, "GPIO52_L1"),
+       PINCTRL_PIN(STN8815_PIN_L4, "GPIO53_L4"),
+       PINCTRL_PIN(STN8815_PIN_L3, "GPIO54_L3"),
+       PINCTRL_PIN(STN8815_PIN_L2, "GPIO55_L2"),
+       PINCTRL_PIN(STN8815_PIN_F3, "GPIO56_F3"),
+       PINCTRL_PIN(STN8815_PIN_F2, "GPIO57_F2"),
+       PINCTRL_PIN(STN8815_PIN_E1, "GPIO58_E1"),
+       PINCTRL_PIN(STN8815_PIN_E3, "GPIO59_E3"),
+       PINCTRL_PIN(STN8815_PIN_E2, "GPIO60_E2"),
+       PINCTRL_PIN(STN8815_PIN_E4, "GPIO61_E4"),
+       PINCTRL_PIN(STN8815_PIN_D3, "GPIO62_D3"),
+       PINCTRL_PIN(STN8815_PIN_D2, "GPIO63_D2"),
+       PINCTRL_PIN(STN8815_PIN_F21, "GPIO64_F21"),
+       PINCTRL_PIN(STN8815_PIN_F20, "GPIO65_F20"),
+       PINCTRL_PIN(STN8815_PIN_E22, "GPIO66_E22"),
+       PINCTRL_PIN(STN8815_PIN_D22, "GPIO67_D22"),
+       PINCTRL_PIN(STN8815_PIN_E21, "GPIO68_E21"),
+       PINCTRL_PIN(STN8815_PIN_E20, "GPIO69_E20"),
+       PINCTRL_PIN(STN8815_PIN_C22, "GPIO70_C22"),
+       PINCTRL_PIN(STN8815_PIN_D21, "GPIO71_D21"),
+       PINCTRL_PIN(STN8815_PIN_D20, "GPIO72_D20"),
+       PINCTRL_PIN(STN8815_PIN_C21, "GPIO73_C21"),
+       PINCTRL_PIN(STN8815_PIN_C20, "GPIO74_C20"),
+       PINCTRL_PIN(STN8815_PIN_C19, "GPIO75_C19"),
+       PINCTRL_PIN(STN8815_PIN_B20, "GPIO76_B20"),
+       PINCTRL_PIN(STN8815_PIN_B8, "GPIO77_B8"),
+       PINCTRL_PIN(STN8815_PIN_A8, "GPIO78_A8"),
+       PINCTRL_PIN(STN8815_PIN_C9, "GPIO79_C9"),
+       PINCTRL_PIN(STN8815_PIN_B9, "GPIO80_B9"),
+       PINCTRL_PIN(STN8815_PIN_A9, "GPIO81_A9"),
+       PINCTRL_PIN(STN8815_PIN_C10, "GPIO82_C10"),
+       PINCTRL_PIN(STN8815_PIN_K1, "GPIO83_K1"),
+       PINCTRL_PIN(STN8815_PIN_K3, "GPIO84_K3"),
+       PINCTRL_PIN(STN8815_PIN_K2, "GPIO85_K2"),
+       PINCTRL_PIN(STN8815_PIN_J1, "GPIO86_J1"),
+       PINCTRL_PIN(STN8815_PIN_J3, "GPIO87_J3"),
+       PINCTRL_PIN(STN8815_PIN_J2, "GPIO88_J2"),
+       PINCTRL_PIN(STN8815_PIN_H1, "GPIO89_H1"),
+       PINCTRL_PIN(STN8815_PIN_H3, "GPIO90_H3"),
+       PINCTRL_PIN(STN8815_PIN_H2, "GPIO91_H2"),
+       PINCTRL_PIN(STN8815_PIN_G1, "GPIO92_G1"),
+       PINCTRL_PIN(STN8815_PIN_G3, "GPIO93_G3"),
+       PINCTRL_PIN(STN8815_PIN_G2, "GPIO94_G2"),
+       PINCTRL_PIN(STN8815_PIN_F1, "GPIO95_F1"),
+       PINCTRL_PIN(STN8815_PIN_T20, "GPIO96_T20"),
+       PINCTRL_PIN(STN8815_PIN_R21, "GPIO97_R21"),
+       PINCTRL_PIN(STN8815_PIN_R20, "GPIO98_R20"),
+       PINCTRL_PIN(STN8815_PIN_U22, "GPIO99_U22"),
+       PINCTRL_PIN(STN8815_PIN_N21, "GPIO100_N21"),
+       PINCTRL_PIN(STN8815_PIN_N20, "GPIO101_N20"),
+       PINCTRL_PIN(STN8815_PIN_P22, "GPIO102_P22"),
+       PINCTRL_PIN(STN8815_PIN_N22, "GPIO103_N22"),
+       PINCTRL_PIN(STN8815_PIN_V22, "GPIO104_V22"),
+       PINCTRL_PIN(STN8815_PIN_V21, "GPIO105_V21"),
+       PINCTRL_PIN(STN8815_PIN_K22, "GPIO106_K22"),
+       PINCTRL_PIN(STN8815_PIN_K21, "GPIO107_K21"),
+       PINCTRL_PIN(STN8815_PIN_H20, "GPIO108_H20"),
+       PINCTRL_PIN(STN8815_PIN_G20, "GPIO109_G20"),
+       PINCTRL_PIN(STN8815_PIN_L21, "GPIO110_L21"),
+       PINCTRL_PIN(STN8815_PIN_H21, "GPIO111_H21"),
+       PINCTRL_PIN(STN8815_PIN_J21, "GPIO112_J21"),
+       PINCTRL_PIN(STN8815_PIN_H22, "GPIO113_H22"),
+       PINCTRL_PIN(STN8815_PIN_K20, "GPIO114_K20"),
+       PINCTRL_PIN(STN8815_PIN_L22, "GPIO115_L22"),
+       PINCTRL_PIN(STN8815_PIN_G21, "GPIO116_G21"),
+       PINCTRL_PIN(STN8815_PIN_J20, "GPIO117_J20"),
+       PINCTRL_PIN(STN8815_PIN_G22, "GPIO118_G22"),
+       PINCTRL_PIN(STN8815_PIN_U19, "GPIO119_U19"),
+       PINCTRL_PIN(STN8815_PIN_G19, "GPIO120_G19"),
+       PINCTRL_PIN(STN8815_PIN_M22, "GPIO121_M22"),
+       PINCTRL_PIN(STN8815_PIN_M19, "GPIO122_M19"),
+       PINCTRL_PIN(STN8815_PIN_J22, "GPIO123_J22"),
+};
+
+#define STN8815_GPIO_RANGE(a, b, c) { .name = "STN8815", .id = a, .base = b, \
+                       .pin_base = b, .npins = c }
+
+/*
+ * This matches the 32-pin gpio chips registered by the GPIO portion. This
+ * cannot be const since we assign the struct gpio_chip * pointer at runtime.
+ */
+static struct pinctrl_gpio_range nmk_stn8815_ranges[] = {
+       STN8815_GPIO_RANGE(0, 0, 32),
+       STN8815_GPIO_RANGE(1, 32, 32),
+       STN8815_GPIO_RANGE(2, 64, 32),
+       STN8815_GPIO_RANGE(3, 96, 28),
+};
+
+/*
+ * Read the pin group names like this:
+ * u0_a_1    = first groups of pins for uart0 on alt function a
+ * i2c2_b_2  = second group of pins for i2c2 on alt function b
+ */
+
+/* Altfunction A */
+static const unsigned u0_a_1_pins[] = { STN8815_PIN_B4, STN8815_PIN_D5,
+       STN8815_PIN_C5, STN8815_PIN_A4, STN8815_PIN_B5, STN8815_PIN_D6,
+       STN8815_PIN_C6, STN8815_PIN_B6 };
+static const unsigned mmcsd_a_1_pins[] = { STN8815_PIN_B10, STN8815_PIN_A10,
+       STN8815_PIN_C11, STN8815_PIN_B11, STN8815_PIN_A11, STN8815_PIN_C12,
+       STN8815_PIN_B12, STN8815_PIN_A12, STN8815_PIN_C13, STN8815_PIN_C15 };
+static const unsigned u1_a_1_pins[] = { STN8815_PIN_M2, STN8815_PIN_L1,
+                                       STN8815_PIN_F3, STN8815_PIN_F2 };
+static const unsigned i2c1_a_1_pins[] = { STN8815_PIN_L4, STN8815_PIN_L3 };
+static const unsigned i2c0_a_1_pins[] = { STN8815_PIN_D3, STN8815_PIN_D2 };
+/* Altfunction B */
+static const unsigned u1_b_1_pins[] = { STN8815_PIN_B16, STN8815_PIN_A16 };
+static const unsigned i2cusb_b_1_pins[] = { STN8815_PIN_C21, STN8815_PIN_C20 };
+
+#define STN8815_PIN_GROUP(a,b) { .name = #a, .pins = a##_pins,         \
+                       .npins = ARRAY_SIZE(a##_pins), .altsetting = b }
+
+static const struct nmk_pingroup nmk_stn8815_groups[] = {
+       STN8815_PIN_GROUP(u0_a_1, NMK_GPIO_ALT_A),
+       STN8815_PIN_GROUP(mmcsd_a_1, NMK_GPIO_ALT_A),
+       STN8815_PIN_GROUP(u1_a_1, NMK_GPIO_ALT_A),
+       STN8815_PIN_GROUP(i2c1_a_1, NMK_GPIO_ALT_A),
+       STN8815_PIN_GROUP(i2c0_a_1, NMK_GPIO_ALT_A),
+       STN8815_PIN_GROUP(u1_b_1, NMK_GPIO_ALT_B),
+       STN8815_PIN_GROUP(i2cusb_b_1, NMK_GPIO_ALT_B),
+};
+
+/* We use this macro to define the groups applicable to a function */
+#define STN8815_FUNC_GROUPS(a, b...)      \
+static const char * const a##_groups[] = { b };
+
+STN8815_FUNC_GROUPS(u0, "u0_a_1");
+STN8815_FUNC_GROUPS(mmcsd, "mmcsd_a_1");
+STN8815_FUNC_GROUPS(u1, "u1_a_1", "u1_b_1");
+STN8815_FUNC_GROUPS(i2c1, "i2c1_a_1");
+STN8815_FUNC_GROUPS(i2c0, "i2c0_a_1");
+STN8815_FUNC_GROUPS(i2cusb, "i2cusb_b_1");
+
+#define FUNCTION(fname)                                        \
+       {                                               \
+               .name = #fname,                         \
+               .groups = fname##_groups,               \
+               .ngroups = ARRAY_SIZE(fname##_groups),  \
+       }
+
+static const struct nmk_function nmk_stn8815_functions[] = {
+       FUNCTION(u0),
+       FUNCTION(mmcsd),
+       FUNCTION(u1),
+       FUNCTION(i2c1),
+       FUNCTION(i2c0),
+       FUNCTION(i2cusb),
+};
+
+static const struct nmk_pinctrl_soc_data nmk_stn8815_soc = {
+       .gpio_ranges = nmk_stn8815_ranges,
+       .gpio_num_ranges = ARRAY_SIZE(nmk_stn8815_ranges),
+       .pins = nmk_stn8815_pins,
+       .npins = ARRAY_SIZE(nmk_stn8815_pins),
+       .functions = nmk_stn8815_functions,
+       .nfunctions = ARRAY_SIZE(nmk_stn8815_functions),
+       .groups = nmk_stn8815_groups,
+       .ngroups = ARRAY_SIZE(nmk_stn8815_groups),
+};
+
+void __devinit
+nmk_pinctrl_stn8815_init(const struct nmk_pinctrl_soc_data **soc)
+{
+       *soc = &nmk_stn8815_soc;
+}
index 53b0d49a7a1c817a7316fc25e57fff3a5c5341bb..d12df0227561d8f3de347dc57c4f9f171938c32a 100644 (file)
@@ -1292,7 +1292,7 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev)
                                                NOMADIK_GPIO_TO_IRQ(pdata->first_gpio),
                                                0, &nmk_gpio_irq_simple_ops, nmk_chip);
        if (!nmk_chip->domain) {
-               pr_err("%s: Failed to create irqdomain\n", np->full_name);
+               dev_err(&dev->dev, "failed to create irqdomain\n");
                ret = -ENOSYS;
                goto out;
        }
@@ -1720,8 +1720,12 @@ static int __devinit nmk_pinctrl_probe(struct platform_device *pdev)
                        of_match_device(nmk_pinctrl_match, &pdev->dev)->data;
 
        /* Poke in other ASIC variants here */
+       if (version == PINCTRL_NMK_STN8815)
+               nmk_pinctrl_stn8815_init(&npct->soc);
        if (version == PINCTRL_NMK_DB8500)
                nmk_pinctrl_db8500_init(&npct->soc);
+       if (version == PINCTRL_NMK_DB8540)
+               nmk_pinctrl_db8540_init(&npct->soc);
 
        /*
         * We need all the GPIO drivers to probe FIRST, or we will not be able
@@ -1731,7 +1735,6 @@ static int __devinit nmk_pinctrl_probe(struct platform_device *pdev)
        for (i = 0; i < npct->soc->gpio_num_ranges; i++) {
                if (!nmk_gpio_chips[i]) {
                        dev_warn(&pdev->dev, "GPIO chip %d not registered yet\n", i);
-                       devm_kfree(&pdev->dev, npct);
                        return -EPROBE_DEFER;
                }
                npct->soc->gpio_ranges[i].gc = &nmk_gpio_chips[i]->chip;
@@ -1773,6 +1776,7 @@ static struct platform_driver nmk_gpio_driver = {
 static const struct platform_device_id nmk_pinctrl_id[] = {
        { "pinctrl-stn8815", PINCTRL_NMK_STN8815 },
        { "pinctrl-db8500", PINCTRL_NMK_DB8500 },
+       { "pinctrl-db8540", PINCTRL_NMK_DB8540 },
 };
 
 static struct platform_driver nmk_pinctrl_driver = {
index bc91aed7185db0bb46d731523819d6fa0dcbf8e6..5c99f1c62dfd1a1524f3d833b37d36c83c96a3c1 100644 (file)
@@ -6,6 +6,7 @@
 /* Package definitions */
 #define PINCTRL_NMK_STN8815    0
 #define PINCTRL_NMK_DB8500     1
+#define PINCTRL_NMK_DB8540     2
 
 /**
  * struct nmk_function - Nomadik pinctrl mux function
@@ -61,6 +62,19 @@ struct nmk_pinctrl_soc_data {
        unsigned ngroups;
 };
 
+#ifdef CONFIG_PINCTRL_STN8815
+
+void nmk_pinctrl_stn8815_init(const struct nmk_pinctrl_soc_data **soc);
+
+#else
+
+static inline void
+nmk_pinctrl_stn8815_init(const struct nmk_pinctrl_soc_data **soc)
+{
+}
+
+#endif
+
 #ifdef CONFIG_PINCTRL_DB8500
 
 void nmk_pinctrl_db8500_init(const struct nmk_pinctrl_soc_data **soc);
@@ -74,4 +88,17 @@ nmk_pinctrl_db8500_init(const struct nmk_pinctrl_soc_data **soc)
 
 #endif
 
+#ifdef CONFIG_PINCTRL_DB8540
+
+void nmk_pinctrl_db8540_init(const struct nmk_pinctrl_soc_data **soc);
+
+#else
+
+static inline void
+nmk_pinctrl_db8540_init(const struct nmk_pinctrl_soc_data **soc)
+{
+}
+
+#endif
+
 #endif /* PINCTRL_PINCTRL_NOMADIK_H */
index 2aae8a8978e99b4224ef0f0baff84b5745e913dd..7fca6ce5952b94a0f398bd1bca35795e20ba62e0 100644 (file)
@@ -1217,7 +1217,6 @@ out_no_rsc_remap:
        iounmap(spmx->gpio_virtbase);
 out_no_gpio_remap:
        platform_set_drvdata(pdev, NULL);
-       devm_kfree(&pdev->dev, spmx);
        return ret;
 }
 
index a7ad8c112d91e21c9e0c930082a451d4b4921798..309f5b9a70ec74d4b5e1cca07b6e8e31836f53fa 100644 (file)
@@ -1121,10 +1121,8 @@ static int __devinit u300_pmx_probe(struct platform_device *pdev)
        upmx->dev = &pdev->dev;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               ret = -ENOENT;
-               goto out_no_resource;
-       }
+       if (!res)
+               return -ENOENT;
        upmx->phybase = res->start;
        upmx->physize = resource_size(res);
 
@@ -1165,8 +1163,6 @@ out_no_remap:
        platform_set_drvdata(pdev, NULL);
 out_no_memregion:
        release_mem_region(upmx->phybase, upmx->physize);
-out_no_resource:
-       devm_kfree(&pdev->dev, upmx);
        return ret;
 }
 
index 39abb150bdd4d9f28469b7c7aff5e561dd11d207..84c56881ba805c1fa387728b64601a1a471769eb 100644 (file)
@@ -329,7 +329,8 @@ static int acerhdf_bind(struct thermal_zone_device *thermal,
        if (cdev != cl_dev)
                return 0;
 
-       if (thermal_zone_bind_cooling_device(thermal, 0, cdev)) {
+       if (thermal_zone_bind_cooling_device(thermal, 0, cdev,
+                       THERMAL_NO_LIMIT, THERMAL_NO_LIMIT)) {
                pr_err("error binding cooling dev\n");
                return -EINVAL;
        }
@@ -661,7 +662,7 @@ static int acerhdf_register_thermal(void)
                return -EINVAL;
 
        thz_dev = thermal_zone_device_register("acerhdf", 1, 0, NULL,
-                                             &acerhdf_dev_ops, 0, 0, 0,
+                                             &acerhdf_dev_ops, 0,
                                              (kernelmode) ? interval*1000 : 0);
        if (IS_ERR(thz_dev))
                return -EINVAL;
index 2ca7dd1ab3e452e49eb0c25561274cea435acbcf..cd33add118cea686242d5a63d6158b2e7f3af7e1 100644 (file)
@@ -350,6 +350,7 @@ static void cmpc_accel_idev_init_v4(struct input_dev *inputdev)
        inputdev->close = cmpc_accel_close_v4;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int cmpc_accel_suspend_v4(struct device *dev)
 {
        struct input_dev *inputdev;
@@ -384,6 +385,7 @@ static int cmpc_accel_resume_v4(struct device *dev)
 
        return 0;
 }
+#endif
 
 static int cmpc_accel_add_v4(struct acpi_device *acpi)
 {
@@ -752,6 +754,7 @@ static int cmpc_tablet_remove(struct acpi_device *acpi, int type)
        return cmpc_remove_acpi_notify_device(acpi);
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int cmpc_tablet_resume(struct device *dev)
 {
        struct input_dev *inputdev = dev_get_drvdata(dev);
@@ -761,6 +764,7 @@ static int cmpc_tablet_resume(struct device *dev)
                input_report_switch(inputdev, SW_TABLET_MODE, !val);
        return 0;
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(cmpc_tablet_pm, NULL, cmpc_tablet_resume);
 
index d2e41735a47b2d6178ef290211e0d13373ece570..7acae3f85f3b180cfe57865e08bb4fbf08bde40d 100644 (file)
@@ -440,11 +440,13 @@ static int __devexit acpi_fujitsu_remove(struct acpi_device *adev, int type)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int acpi_fujitsu_resume(struct device *dev)
 {
        fujitsu_reset();
        return 0;
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(acpi_fujitsu_pm, NULL, acpi_fujitsu_resume);
 
index d9ab6f64dcec0185148075dca8f4ef8fda1319bf..777c7e3dda51ccb73dd6939717d95904ae5753cc 100644 (file)
@@ -305,10 +305,12 @@ static int hdaps_probe(struct platform_device *dev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int hdaps_resume(struct device *dev)
 {
        return hdaps_device_init();
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(hdaps_pm, NULL, hdaps_resume);
 
index f4d91154ad67cca5d260cc681c5f7464dea0e87c..6b9af989632b72a9f2c0b1641a5fdd5600844de0 100644 (file)
@@ -352,7 +352,7 @@ static int lis3lv02d_remove(struct acpi_device *device, int type)
 }
 
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int lis3lv02d_suspend(struct device *dev)
 {
        /* make sure the device is off when we suspend */
index 3a27113deda9ff71a8139d6fb603165f93a71b14..c8097616dd62fe89a135f5be607ee0f8c48d70a7 100644 (file)
@@ -502,7 +502,7 @@ static int mid_thermal_probe(struct platform_device *pdev)
                        goto err;
                }
                pinfo->tzd[i] = thermal_zone_device_register(name[i],
-                               0, 0, td_info, &tzd_ops, 0, 0, 0, 0);
+                               0, 0, td_info, &tzd_ops, 0, 0);
                if (IS_ERR(pinfo->tzd[i])) {
                        kfree(td_info);
                        ret = PTR_ERR(pinfo->tzd[i]);
index f64441844317f513c6ec8db521fb0bad37afbda8..2111dbb7e1e380263b6118218b619089298a39a2 100644 (file)
@@ -85,7 +85,9 @@
 #define MSI_STANDARD_EC_TOUCHPAD_ADDRESS       0xe4
 #define MSI_STANDARD_EC_TOUCHPAD_MASK          (1 << 4)
 
+#ifdef CONFIG_PM_SLEEP
 static int msi_laptop_resume(struct device *device);
+#endif
 static SIMPLE_DEV_PM_OPS(msi_laptop_pm, NULL, msi_laptop_resume);
 
 #define MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS 0x2f
@@ -753,6 +755,7 @@ err_bluetooth:
        return retval;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int msi_laptop_resume(struct device *device)
 {
        u8 data;
@@ -773,6 +776,7 @@ static int msi_laptop_resume(struct device *device)
 
        return 0;
 }
+#endif
 
 static int __init msi_laptop_input_setup(void)
 {
index 24480074bcf047c40b219dcf5b055ce829d865d7..8e8caa767d6aec521e65cd42475e3b2950c32907 100644 (file)
@@ -188,7 +188,9 @@ static const struct acpi_device_id pcc_device_ids[] = {
 };
 MODULE_DEVICE_TABLE(acpi, pcc_device_ids);
 
+#ifdef CONFIG_PM_SLEEP
 static int acpi_pcc_hotkey_resume(struct device *dev);
+#endif
 static SIMPLE_DEV_PM_OPS(acpi_pcc_hotkey_pm, NULL, acpi_pcc_hotkey_resume);
 
 static struct acpi_driver acpi_pcc_driver = {
@@ -540,6 +542,7 @@ static void acpi_pcc_destroy_input(struct pcc_acpi *pcc)
 
 /* kernel module interface */
 
+#ifdef CONFIG_PM_SLEEP
 static int acpi_pcc_hotkey_resume(struct device *dev)
 {
        struct pcc_acpi *pcc;
@@ -556,6 +559,7 @@ static int acpi_pcc_hotkey_resume(struct device *dev)
 
        return acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, pcc->sticky_mode);
 }
+#endif
 
 static int acpi_pcc_hotkey_add(struct acpi_device *device)
 {
index 9363969ad07adf65cefe1a6aa918ca47363ca907..daaddec68def7e1c7cb11e4fe6d54e4193943c55 100644 (file)
@@ -140,7 +140,10 @@ MODULE_PARM_DESC(kbd_backlight_timeout,
                 "1 for 30 seconds, 2 for 60 seconds and 3 to disable timeout "
                 "(default: 0)");
 
+#ifdef CONFIG_PM_SLEEP
 static void sony_nc_kbd_backlight_resume(void);
+static void sony_nc_thermal_resume(void);
+#endif
 static int sony_nc_kbd_backlight_setup(struct platform_device *pd,
                unsigned int handle);
 static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd);
@@ -151,7 +154,6 @@ static void sony_nc_battery_care_cleanup(struct platform_device *pd);
 
 static int sony_nc_thermal_setup(struct platform_device *pd);
 static void sony_nc_thermal_cleanup(struct platform_device *pd);
-static void sony_nc_thermal_resume(void);
 
 static int sony_nc_lid_resume_setup(struct platform_device *pd);
 static void sony_nc_lid_resume_cleanup(struct platform_device *pd);
@@ -1431,6 +1433,7 @@ static void sony_nc_function_cleanup(struct platform_device *pd)
        sony_nc_handles_cleanup(pd);
 }
 
+#ifdef CONFIG_PM_SLEEP
 static void sony_nc_function_resume(void)
 {
        unsigned int i, result, bitmask, arg;
@@ -1508,6 +1511,7 @@ static int sony_nc_resume(struct device *dev)
 
        return 0;
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(sony_nc_pm, NULL, sony_nc_resume);
 
@@ -1872,6 +1876,7 @@ static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd)
        }
 }
 
+#ifdef CONFIG_PM_SLEEP
 static void sony_nc_kbd_backlight_resume(void)
 {
        int ignore = 0;
@@ -1888,6 +1893,7 @@ static void sony_nc_kbd_backlight_resume(void)
                                (kbdbl_ctl->base + 0x200) |
                                (kbdbl_ctl->timeout << 0x10), &ignore);
 }
+#endif
 
 struct battery_care_control {
        struct device_attribute attrs[2];
@@ -2210,6 +2216,7 @@ static void sony_nc_thermal_cleanup(struct platform_device *pd)
        }
 }
 
+#ifdef CONFIG_PM_SLEEP
 static void sony_nc_thermal_resume(void)
 {
        unsigned int status = sony_nc_thermal_mode_get();
@@ -2217,6 +2224,7 @@ static void sony_nc_thermal_resume(void)
        if (status != th_handle->mode)
                sony_nc_thermal_mode_set(th_handle->mode);
 }
+#endif
 
 /* resume on LID open */
 struct snc_lid_resume_control {
@@ -4287,6 +4295,7 @@ err_free_resources:
        return result;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int sony_pic_suspend(struct device *dev)
 {
        if (sony_pic_disable(to_acpi_device(dev)))
@@ -4300,6 +4309,7 @@ static int sony_pic_resume(struct device *dev)
                        spic_dev.cur_ioport, spic_dev.cur_irq);
        return 0;
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(sony_pic_pm, sony_pic_suspend, sony_pic_resume);
 
index e7f73287636cd9bdabb3f0b32104d4b7257e5e69..df3016be987e6695d82e4f6ad09868b63c80b9a8 100644 (file)
@@ -922,6 +922,7 @@ static struct input_dev *tpacpi_inputdev;
 static struct mutex tpacpi_inputdev_send_mutex;
 static LIST_HEAD(tpacpi_all_drivers);
 
+#ifdef CONFIG_PM_SLEEP
 static int tpacpi_suspend_handler(struct device *dev)
 {
        struct ibm_struct *ibm, *itmp;
@@ -949,6 +950,7 @@ static int tpacpi_resume_handler(struct device *dev)
 
        return 0;
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(tpacpi_pm,
                         tpacpi_suspend_handler, tpacpi_resume_handler);
@@ -7682,25 +7684,15 @@ static int fan_set_speed(int speed)
 
 static void fan_watchdog_reset(void)
 {
-       static int fan_watchdog_active;
-
        if (fan_control_access_mode == TPACPI_FAN_WR_NONE)
                return;
 
-       if (fan_watchdog_active)
-               cancel_delayed_work(&fan_watchdog_task);
-
        if (fan_watchdog_maxinterval > 0 &&
-           tpacpi_lifecycle != TPACPI_LIFE_EXITING) {
-               fan_watchdog_active = 1;
-               if (!queue_delayed_work(tpacpi_wq, &fan_watchdog_task,
-                               msecs_to_jiffies(fan_watchdog_maxinterval
-                                                * 1000))) {
-                       pr_err("failed to queue the fan watchdog, "
-                              "watchdog will not trigger\n");
-               }
-       } else
-               fan_watchdog_active = 0;
+           tpacpi_lifecycle != TPACPI_LIFE_EXITING)
+               mod_delayed_work(tpacpi_wq, &fan_watchdog_task,
+                       msecs_to_jiffies(fan_watchdog_maxinterval * 1000));
+       else
+               cancel_delayed_work(&fan_watchdog_task);
 }
 
 static void fan_watchdog_fire(struct work_struct *ignored)
index c13ba5bac93f1c594f22ecb1b6e701586793a081..5f1256d5e9332cf45dbdd2031987ea41fe0212cf 100644 (file)
@@ -1296,6 +1296,7 @@ static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event)
        }
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int toshiba_acpi_suspend(struct device *device)
 {
        struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device));
@@ -1317,6 +1318,7 @@ static int toshiba_acpi_resume(struct device *device)
 
        return 0;
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(toshiba_acpi_pm,
                         toshiba_acpi_suspend, toshiba_acpi_resume);
index 715a43cb5e3c49020c24a07c302ec3792fcce84a..5e5d6317d690095b9f95ff761b2c5d5d0cb5a7d4 100644 (file)
@@ -41,7 +41,9 @@ static const struct acpi_device_id bt_device_ids[] = {
 };
 MODULE_DEVICE_TABLE(acpi, bt_device_ids);
 
+#ifdef CONFIG_PM_SLEEP
 static int toshiba_bt_resume(struct device *dev);
+#endif
 static SIMPLE_DEV_PM_OPS(toshiba_bt_pm, NULL, toshiba_bt_resume);
 
 static struct acpi_driver toshiba_bt_rfkill_driver = {
@@ -90,10 +92,12 @@ static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event)
        toshiba_bluetooth_enable(device->handle);
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int toshiba_bt_resume(struct device *dev)
 {
        return toshiba_bluetooth_enable(to_acpi_device(dev)->handle);
 }
+#endif
 
 static int toshiba_bt_rfkill_add(struct acpi_device *device)
 {
index 849c07c13bf6cae790c3e99dfb402f55b88a2a1f..38ba39d7ca7de5cebd5f45163f55035b4f303d6e 100644 (file)
@@ -77,10 +77,12 @@ static void ebook_switch_notify(struct acpi_device *device, u32 event)
        }
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int ebook_switch_resume(struct device *dev)
 {
        return ebook_send_state(to_acpi_device(dev));
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(ebook_switch_pm, NULL, ebook_switch_resume);
 
index 526e5c9312945bdf480f57a4673b478d22250be8..7ff83cf43c8c1ad5d06407b9eba1358f0bdb9053 100644 (file)
@@ -509,9 +509,8 @@ static void _setup_polling(struct work_struct *work)
        if (!delayed_work_pending(&cm_monitor_work) ||
            (delayed_work_pending(&cm_monitor_work) &&
             time_after(next_polling, _next_polling))) {
-               cancel_delayed_work_sync(&cm_monitor_work);
                next_polling = jiffies + polling_jiffy;
-               queue_delayed_work(cm_wq, &cm_monitor_work, polling_jiffy);
+               mod_delayed_work(cm_wq, &cm_monitor_work, polling_jiffy);
        }
 
 out:
@@ -546,10 +545,8 @@ static void fullbatt_handler(struct charger_manager *cm)
        if (cm_suspended)
                device_set_wakeup_capable(cm->dev, true);
 
-       if (delayed_work_pending(&cm->fullbatt_vchk_work))
-               cancel_delayed_work(&cm->fullbatt_vchk_work);
-       queue_delayed_work(cm_wq, &cm->fullbatt_vchk_work,
-                          msecs_to_jiffies(desc->fullbatt_vchkdrop_ms));
+       mod_delayed_work(cm_wq, &cm->fullbatt_vchk_work,
+                        msecs_to_jiffies(desc->fullbatt_vchkdrop_ms));
        cm->fullbatt_vchk_jiffies_at = jiffies + msecs_to_jiffies(
                                       desc->fullbatt_vchkdrop_ms);
 
index 076e211a40b7111e864d591cba0400ff7042b6ad..704e652072be08acb238f8a3b8965beb90cdf10b 100644 (file)
@@ -355,8 +355,7 @@ static void ds2760_battery_external_power_changed(struct power_supply *psy)
 
        dev_dbg(di->dev, "%s\n", __func__);
 
-       cancel_delayed_work(&di->monitor_work);
-       queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ/10);
+       mod_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ/10);
 }
 
 
@@ -401,8 +400,7 @@ static void ds2760_battery_set_charged(struct power_supply *psy)
 
        /* postpone the actual work by 20 secs. This is for debouncing GPIO
         * signals and to let the current value settle. See AN4188. */
-       cancel_delayed_work(&di->set_charged_work);
-       queue_delayed_work(di->monitor_wqueue, &di->set_charged_work, HZ * 20);
+       mod_delayed_work(di->monitor_wqueue, &di->set_charged_work, HZ * 20);
 }
 
 static int ds2760_battery_get_property(struct power_supply *psy,
@@ -616,8 +614,7 @@ static int ds2760_battery_resume(struct platform_device *pdev)
        di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
        power_supply_changed(&di->bat);
 
-       cancel_delayed_work(&di->monitor_work);
-       queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ);
+       mod_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ);
 
        return 0;
 }
index 8dbc7bfaab14d40422c8bb17db3a4c43cf695abe..ffbed5e5b9456e9dd763ce683b27b7cab6eaf1b1 100644 (file)
@@ -173,16 +173,14 @@ static void jz_battery_external_power_changed(struct power_supply *psy)
 {
        struct jz_battery *jz_battery = psy_to_jz_battery(psy);
 
-       cancel_delayed_work(&jz_battery->work);
-       schedule_delayed_work(&jz_battery->work, 0);
+       mod_delayed_work(system_wq, &jz_battery->work, 0);
 }
 
 static irqreturn_t jz_battery_charge_irq(int irq, void *data)
 {
        struct jz_battery *jz_battery = data;
 
-       cancel_delayed_work(&jz_battery->work);
-       schedule_delayed_work(&jz_battery->work, 0);
+       mod_delayed_work(system_wq, &jz_battery->work, 0);
 
        return IRQ_HANDLED;
 }
index 08cc8a3c15afb29b8147c1184c3477e543fdc01e..2436f13500132c7bf0e2f997ab8feb9c996767de 100644 (file)
@@ -201,7 +201,7 @@ static int psy_register_thermal(struct power_supply *psy)
        for (i = 0; i < psy->num_properties; i++) {
                if (psy->properties[i] == POWER_SUPPLY_PROP_TEMP) {
                        psy->tzd = thermal_zone_device_register(psy->name, 0, 0,
-                                       psy, &psy_tzd_ops, 0, 0, 0, 0);
+                                       psy, &psy_tzd_ops, 0, 0);
                        if (IS_ERR(psy->tzd))
                                return PTR_ERR(psy->tzd);
                        break;
index 4e932cc695e9311e811c9be2942798c4ecad5077..129c82706c9f286100bd5f7910f9699156d4595e 100644 (file)
@@ -33,9 +33,8 @@ config REGULATOR_DUMMY
        help
          If this option is enabled then when a regulator lookup fails
          and the board has not specified that it has provided full
-         constraints then the regulator core will provide an always
-         enabled dummy regulator will be provided, allowing consumer
-         drivers to continue.
+         constraints the regulator core will provide an always
+         enabled dummy regulator, allowing consumer drivers to continue.
 
          A warning will be generated when this substitution is done.
 
@@ -50,11 +49,11 @@ config REGULATOR_VIRTUAL_CONSUMER
        tristate "Virtual regulator consumer support"
        help
          This driver provides a virtual consumer for the voltage and
-          current regulator API which provides sysfs controls for
-          configuring the supplies requested.  This is mainly useful
-          for test purposes.
+         current regulator API which provides sysfs controls for
+         configuring the supplies requested.  This is mainly useful
+         for test purposes.
 
-          If unsure, say no.
+         If unsure, say no.
 
 config REGULATOR_USERSPACE_CONSUMER
        tristate "Userspace regulator consumer support"
@@ -63,7 +62,7 @@ config REGULATOR_USERSPACE_CONSUMER
          from user space. Userspace consumer driver provides ability to
          control power supplies for such devices.
 
-          If unsure, say no.
+         If unsure, say no.
 
 config REGULATOR_GPIO
        tristate "GPIO regulator support"
@@ -172,6 +171,14 @@ config REGULATOR_MAX8660
          This driver controls a Maxim 8660/8661 voltage output
          regulator via I2C bus.
 
+config REGULATOR_MAX8907
+       tristate "Maxim 8907 voltage regulator"
+       depends on MFD_MAX8907
+       help
+         This driver controls a Maxim 8907 voltage output regulator
+         via I2C bus. The provided regulator is suitable for Tegra
+         chip to control Step-Down DC-DC and LDOs.
+
 config REGULATOR_MAX8925
        tristate "Maxim MAX8925 Power Management IC"
        depends on MFD_MAX8925
@@ -247,7 +254,7 @@ config REGULATOR_LP8788
 
 config REGULATOR_PCF50633
        tristate "NXP PCF50633 regulator driver"
-        depends on MFD_PCF50633
+       depends on MFD_PCF50633
        help
         Say Y here to support the voltage regulators and convertors
         on PCF50633
@@ -416,7 +423,7 @@ config REGULATOR_WM8350
        depends on MFD_WM8350
        help
          This driver provides support for the voltage and current regulators
-          of the WM8350 AudioPlus PMIC.
+         of the WM8350 AudioPlus PMIC.
 
 config REGULATOR_WM8400
        tristate "Wolfson Microelectronics WM8400 AudioPlus PMIC"
index 3342615cf25e165b50ff8a1ab56f3a556207f41b..3a0dbc5de66ef48042ec8604fe310f22252ac24a 100644 (file)
@@ -30,6 +30,7 @@ obj-$(CONFIG_REGULATOR_LP8788) += lp8788-ldo.o
 obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o
 obj-$(CONFIG_REGULATOR_MAX8649)        += max8649.o
 obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o
+obj-$(CONFIG_REGULATOR_MAX8907) += max8907-regulator.o
 obj-$(CONFIG_REGULATOR_MAX8925) += max8925-regulator.o
 obj-$(CONFIG_REGULATOR_MAX8952) += max8952.o
 obj-$(CONFIG_REGULATOR_MAX8997) += max8997.o
index 182b553059c9c82a15f8ff164d64c5d37e708c52..65ad2b36ce364c39b965fb202794a019b8673ae3 100644 (file)
@@ -347,17 +347,11 @@ static int ab3100_get_voltage_regulator_external(struct regulator_dev *reg)
        return abreg->plfdata->external_voltage;
 }
 
-static int ab3100_get_fixed_voltage_regulator(struct regulator_dev *reg)
-{
-       return reg->desc->min_uV;
-}
-
 static struct regulator_ops regulator_ops_fixed = {
        .list_voltage = regulator_list_voltage_linear,
        .enable      = ab3100_enable_regulator,
        .disable     = ab3100_disable_regulator,
        .is_enabled  = ab3100_is_enabled_regulator,
-       .get_voltage = ab3100_get_fixed_voltage_regulator,
 };
 
 static struct regulator_ops regulator_ops_variable = {
@@ -486,6 +480,7 @@ ab3100_regulator_desc[AB3100_NUM_REGULATORS] = {
                .id   = AB3100_BUCK,
                .ops  = &regulator_ops_variable_sleepable,
                .n_voltages = ARRAY_SIZE(ldo_e_buck_typ_voltages),
+               .volt_table = ldo_e_buck_typ_voltages,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
                .enable_time = 1000,
index 10f2f4d4d190254cfa9602aa19223984c38fa691..c884a5c4b4735b776dc14580bf7e0055c108cfba 100644 (file)
@@ -238,13 +238,6 @@ static int ab8500_regulator_set_voltage_sel(struct regulator_dev *rdev,
        return ret;
 }
 
-static int ab8500_regulator_enable_time(struct regulator_dev *rdev)
-{
-       struct ab8500_regulator_info *info = rdev_get_drvdata(rdev);
-
-       return info->delay;
-}
-
 static int ab8500_regulator_set_voltage_time_sel(struct regulator_dev *rdev,
                                             unsigned int old_sel,
                                             unsigned int new_sel)
@@ -261,22 +254,14 @@ static struct regulator_ops ab8500_regulator_ops = {
        .get_voltage_sel = ab8500_regulator_get_voltage_sel,
        .set_voltage_sel = ab8500_regulator_set_voltage_sel,
        .list_voltage   = regulator_list_voltage_table,
-       .enable_time    = ab8500_regulator_enable_time,
        .set_voltage_time_sel = ab8500_regulator_set_voltage_time_sel,
 };
 
-static int ab8500_fixed_get_voltage(struct regulator_dev *rdev)
-{
-       return rdev->desc->min_uV;
-}
-
 static struct regulator_ops ab8500_regulator_fixed_ops = {
        .enable         = ab8500_regulator_enable,
        .disable        = ab8500_regulator_disable,
        .is_enabled     = ab8500_regulator_is_enabled,
-       .get_voltage    = ab8500_fixed_get_voltage,
        .list_voltage   = regulator_list_voltage_linear,
-       .enable_time    = ab8500_regulator_enable_time,
 };
 
 static struct ab8500_regulator_info
@@ -374,6 +359,7 @@ static struct ab8500_regulator_info
                        .owner          = THIS_MODULE,
                        .n_voltages     = 1,
                        .min_uV         = 2000000,
+                       .enable_time    = 10000,
                },
                .delay                  = 10000,
                .update_bank            = 0x03,
index e9c2085f9dfbe0993c6931c573efb52a660f06a0..ce0fe72a428e811418aa8190c7f534ce1009d5a4 100644 (file)
@@ -64,14 +64,15 @@ static int anatop_set_voltage_sel(struct regulator_dev *reg, unsigned selector)
 static int anatop_get_voltage_sel(struct regulator_dev *reg)
 {
        struct anatop_regulator *anatop_reg = rdev_get_drvdata(reg);
-       u32 val;
+       u32 val, mask;
 
        if (!anatop_reg->control_reg)
                return -ENOTSUPP;
 
        val = anatop_read_reg(anatop_reg->mfd, anatop_reg->control_reg);
-       val = (val & ((1 << anatop_reg->vol_bit_width) - 1)) >>
+       mask = ((1 << anatop_reg->vol_bit_width) - 1) <<
                anatop_reg->vol_bit_shift;
+       val = (val & mask) >> anatop_reg->vol_bit_shift;
 
        return val - anatop_reg->min_bit_val;
 }
index f092588a078c65b3d3951a55a8ef861a44a50146..0fffeae8222f24e425d7612b37e5f6cd16e2a5a4 100644 (file)
@@ -778,6 +778,9 @@ static void print_constraints(struct regulator_dev *rdev)
        if (constraints->valid_modes_mask & REGULATOR_MODE_STANDBY)
                count += sprintf(buf + count, "standby");
 
+       if (!count)
+               sprintf(buf, "no parameters");
+
        rdev_info(rdev, "%s\n", buf);
 
        if ((constraints->min_uV != constraints->max_uV) &&
@@ -974,6 +977,7 @@ static int set_supply(struct regulator_dev *rdev,
                err = -ENOMEM;
                return err;
        }
+       supply_rdev->open_count++;
 
        return 0;
 }
@@ -2178,9 +2182,12 @@ static int _regulator_do_set_voltage(struct regulator_dev *rdev,
                }
        }
 
-       if (ret == 0 && best_val >= 0)
+       if (ret == 0 && best_val >= 0) {
+               unsigned long data = best_val;
+
                _notifier_call_chain(rdev, REGULATOR_EVENT_VOLTAGE_CHANGE,
-                                    (void *)best_val);
+                                    (void *)data);
+       }
 
        trace_regulator_set_voltage_complete(rdev_get_name(rdev), best_val);
 
@@ -2388,6 +2395,8 @@ static int _regulator_get_voltage(struct regulator_dev *rdev)
                ret = rdev->desc->ops->list_voltage(rdev, sel);
        } else if (rdev->desc->ops->get_voltage) {
                ret = rdev->desc->ops->get_voltage(rdev);
+       } else if (rdev->desc->ops->list_voltage) {
+               ret = rdev->desc->ops->list_voltage(rdev, 0);
        } else {
                return -EINVAL;
        }
@@ -3217,7 +3226,7 @@ regulator_register(const struct regulator_desc *regulator_desc,
 
        dev_set_drvdata(&rdev->dev, rdev);
 
-       if (config->ena_gpio) {
+       if (config->ena_gpio && gpio_is_valid(config->ena_gpio)) {
                ret = gpio_request_one(config->ena_gpio,
                                       GPIOF_DIR_OUT | config->ena_gpio_flags,
                                       rdev_get_name(rdev));
index 903299cf15cfe8c9716d583fc3c49d76d4ac2d04..27355b1199e571ed090f24c5799dce5511d2cc94 100644 (file)
@@ -133,8 +133,8 @@ static int da9052_dcdc_set_current_limit(struct regulator_dev *rdev, int min_uA,
            max_uA < da9052_current_limits[row][DA9052_MIN_UA])
                return -EINVAL;
 
-       for (i = 0; i < DA9052_CURRENT_RANGE; i++) {
-               if (min_uA <= da9052_current_limits[row][i]) {
+       for (i = DA9052_CURRENT_RANGE - 1; i >= 0; i--) {
+               if (da9052_current_limits[row][i] <= max_uA) {
                        reg_val = i;
                        break;
                }
index 86f655c7f7a14ac5df494bcb5dcf3fb4b7e83955..03a1d7c11ef2b5c9ce0d07c91517673cf83d30bb 100644 (file)
@@ -30,7 +30,7 @@ static struct regulator_init_data dummy_initdata;
 static struct regulator_ops dummy_ops;
 
 static struct regulator_desc dummy_desc = {
-       .name = "dummy",
+       .name = "regulator-dummy",
        .id = -1,
        .type = REGULATOR_VOLTAGE,
        .owner = THIS_MODULE,
index 34b67bee9323ce00a49b30bb0cf7d9256660b6f8..8b5944f2d7d1ddd36e82e92d786770e469743dfe 100644 (file)
@@ -57,16 +57,17 @@ static int gpio_regulator_get_value(struct regulator_dev *dev)
        return -EINVAL;
 }
 
-static int gpio_regulator_set_value(struct regulator_dev *dev,
-                                       int min, int max, unsigned *selector)
+static int gpio_regulator_set_voltage(struct regulator_dev *dev,
+                                       int min_uV, int max_uV,
+                                       unsigned *selector)
 {
        struct gpio_regulator_data *data = rdev_get_drvdata(dev);
        int ptr, target = 0, state, best_val = INT_MAX;
 
        for (ptr = 0; ptr < data->nr_states; ptr++)
                if (data->states[ptr].value < best_val &&
-                   data->states[ptr].value >= min &&
-                   data->states[ptr].value <= max) {
+                   data->states[ptr].value >= min_uV &&
+                   data->states[ptr].value <= max_uV) {
                        target = data->states[ptr].gpios;
                        best_val = data->states[ptr].value;
                        if (selector)
@@ -85,13 +86,6 @@ static int gpio_regulator_set_value(struct regulator_dev *dev,
        return 0;
 }
 
-static int gpio_regulator_set_voltage(struct regulator_dev *dev,
-                                       int min_uV, int max_uV,
-                                       unsigned *selector)
-{
-       return gpio_regulator_set_value(dev, min_uV, max_uV, selector);
-}
-
 static int gpio_regulator_list_voltage(struct regulator_dev *dev,
                                      unsigned selector)
 {
@@ -106,7 +100,27 @@ static int gpio_regulator_list_voltage(struct regulator_dev *dev,
 static int gpio_regulator_set_current_limit(struct regulator_dev *dev,
                                        int min_uA, int max_uA)
 {
-       return gpio_regulator_set_value(dev, min_uA, max_uA, NULL);
+       struct gpio_regulator_data *data = rdev_get_drvdata(dev);
+       int ptr, target = 0, state, best_val = 0;
+
+       for (ptr = 0; ptr < data->nr_states; ptr++)
+               if (data->states[ptr].value > best_val &&
+                   data->states[ptr].value >= min_uA &&
+                   data->states[ptr].value <= max_uA) {
+                       target = data->states[ptr].gpios;
+                       best_val = data->states[ptr].value;
+               }
+
+       if (best_val == 0)
+               return -EINVAL;
+
+       for (ptr = 0; ptr < data->nr_gpios; ptr++) {
+               state = (target & (1 << ptr)) >> ptr;
+               gpio_set_value(data->gpios[ptr].gpio, state);
+       }
+       data->state = target;
+
+       return 0;
 }
 
 static struct regulator_ops gpio_regulator_voltage_ops = {
index 1d145a07ada940d0308e1197eb4a961a9e988b9a..d8ecf49a5777e383876aae1f5894adc43d0bf741 100644 (file)
@@ -73,13 +73,7 @@ static struct regulator_ops isl_core_ops = {
        .map_voltage    = regulator_map_voltage_linear,
 };
 
-static int isl6271a_get_fixed_voltage(struct regulator_dev *dev)
-{
-       return dev->desc->min_uV;
-}
-
 static struct regulator_ops isl_fixed_ops = {
-       .get_voltage    = isl6271a_get_fixed_voltage,
        .list_voltage   = regulator_list_voltage_linear,
 };
 
index 212c38eaba700d857767a89c2ccfc3d5006018e6..6199d0f6cca1309434488f2bcdac68501a4317c8 100644 (file)
@@ -374,8 +374,8 @@ static int lp8725_buck_set_current_limit(struct regulator_dev *rdev,
 {
        struct lp872x *lp = rdev_get_drvdata(rdev);
        enum lp872x_regulator_id buck = rdev_get_id(rdev);
-       int i, max = ARRAY_SIZE(lp8725_buck_uA);
-       u8 addr, val;
+       int i;
+       u8 addr;
 
        switch (buck) {
        case LP8725_ID_BUCK1:
@@ -388,17 +388,15 @@ static int lp8725_buck_set_current_limit(struct regulator_dev *rdev,
                return -EINVAL;
        }
 
-       for (i = 0 ; i < max ; i++)
+       for (i = ARRAY_SIZE(lp8725_buck_uA) - 1 ; i >= 0; i--) {
                if (lp8725_buck_uA[i] >= min_uA &&
                        lp8725_buck_uA[i] <= max_uA)
-                       break;
-
-       if (i == max)
-               return -EINVAL;
-
-       val = i << LP8725_BUCK_CL_S;
+                       return lp872x_update_bits(lp, addr,
+                                                 LP8725_BUCK_CL_M,
+                                                 i << LP8725_BUCK_CL_S);
+       }
 
-       return lp872x_update_bits(lp, addr, LP8725_BUCK_CL_M, val);
+       return -EINVAL;
 }
 
 static int lp8725_buck_get_current_limit(struct regulator_dev *rdev)
index 6356e821400f0f77e804cacb58fa0bc359a77962..ba3e0aa402de84a67cfcb3ac15ee8c0555f2eb1b 100644 (file)
@@ -69,6 +69,9 @@
 #define PIN_HIGH                       1
 #define ENABLE_TIME_USEC               32
 
+#define BUCK_FPWM_MASK(x)              (1 << (x))
+#define BUCK_FPWM_SHIFT(x)             (x)
+
 enum lp8788_dvs_state {
        DVS_LOW  = GPIOF_OUT_INIT_LOW,
        DVS_HIGH = GPIOF_OUT_INIT_HIGH,
@@ -86,15 +89,9 @@ enum lp8788_buck_id {
        BUCK4,
 };
 
-struct lp8788_pwm_map {
-       u8 mask;
-       u8 shift;
-};
-
 struct lp8788_buck {
        struct lp8788 *lp;
        struct regulator_dev *regulator;
-       struct lp8788_pwm_map *pmap;
        void *dvs;
 };
 
@@ -106,29 +103,6 @@ static const int lp8788_buck_vtbl[] = {
        1950000, 2000000,
 };
 
-/* buck pwm mode selection : used for set/get_mode in regulator ops
- * @forced pwm : fast mode
- * @auto pwm   : normal mode
- */
-static struct lp8788_pwm_map buck_pmap[] = {
-       [BUCK1] = {
-               .mask = LP8788_FPWM_BUCK1_M,
-               .shift = LP8788_FPWM_BUCK1_S,
-       },
-       [BUCK2] = {
-               .mask = LP8788_FPWM_BUCK2_M,
-               .shift = LP8788_FPWM_BUCK2_S,
-       },
-       [BUCK3] = {
-               .mask = LP8788_FPWM_BUCK3_M,
-               .shift = LP8788_FPWM_BUCK3_S,
-       },
-       [BUCK4] = {
-               .mask = LP8788_FPWM_BUCK4_M,
-               .shift = LP8788_FPWM_BUCK4_S,
-       },
-};
-
 static const u8 buck1_vout_addr[] = {
        LP8788_BUCK1_VOUT0, LP8788_BUCK1_VOUT1,
        LP8788_BUCK1_VOUT2, LP8788_BUCK1_VOUT3,
@@ -347,41 +321,37 @@ static int lp8788_buck_enable_time(struct regulator_dev *rdev)
 static int lp8788_buck_set_mode(struct regulator_dev *rdev, unsigned int mode)
 {
        struct lp8788_buck *buck = rdev_get_drvdata(rdev);
-       struct lp8788_pwm_map *pmap = buck->pmap;
-       u8 val;
-
-       if (!pmap)
-               return -EINVAL;
+       enum lp8788_buck_id id = rdev_get_id(rdev);
+       u8 mask, val;
 
+       mask = BUCK_FPWM_MASK(id);
        switch (mode) {
        case REGULATOR_MODE_FAST:
-               val = LP8788_FORCE_PWM << pmap->shift;
+               val = LP8788_FORCE_PWM << BUCK_FPWM_SHIFT(id);
                break;
        case REGULATOR_MODE_NORMAL:
-               val = LP8788_AUTO_PWM << pmap->shift;
+               val = LP8788_AUTO_PWM << BUCK_FPWM_SHIFT(id);
                break;
        default:
                return -EINVAL;
        }
 
-       return lp8788_update_bits(buck->lp, LP8788_BUCK_PWM, pmap->mask, val);
+       return lp8788_update_bits(buck->lp, LP8788_BUCK_PWM, mask, val);
 }
 
 static unsigned int lp8788_buck_get_mode(struct regulator_dev *rdev)
 {
        struct lp8788_buck *buck = rdev_get_drvdata(rdev);
-       struct lp8788_pwm_map *pmap = buck->pmap;
+       enum lp8788_buck_id id = rdev_get_id(rdev);
        u8 val;
        int ret;
 
-       if (!pmap)
-               return -EINVAL;
-
        ret = lp8788_read_byte(buck->lp, LP8788_BUCK_PWM, &val);
        if (ret)
                return ret;
 
-       return val & pmap->mask ? REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL;
+       return val & BUCK_FPWM_MASK(id) ?
+                               REGULATOR_MODE_FAST : REGULATOR_MODE_NORMAL;
 }
 
 static struct regulator_ops lp8788_buck12_ops = {
@@ -459,27 +429,6 @@ static struct regulator_desc lp8788_buck_desc[] = {
        },
 };
 
-static int lp8788_set_default_dvs_ctrl_mode(struct lp8788 *lp,
-                                       enum lp8788_buck_id id)
-{
-       u8 mask, val;
-
-       switch (id) {
-       case BUCK1:
-               mask = LP8788_BUCK1_DVS_SEL_M;
-               val  = LP8788_BUCK1_DVS_I2C;
-               break;
-       case BUCK2:
-               mask = LP8788_BUCK2_DVS_SEL_M;
-               val  = LP8788_BUCK2_DVS_I2C;
-               break;
-       default:
-               return 0;
-       }
-
-       return lp8788_update_bits(lp, LP8788_BUCK_DVS_SEL, mask, val);
-}
-
 static int _gpio_request(struct lp8788_buck *buck, int gpio, char *name)
 {
        struct device *dev = buck->lp->dev;
@@ -530,6 +479,7 @@ static int lp8788_init_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id)
        struct lp8788_platform_data *pdata = buck->lp->pdata;
        u8 mask[] = { LP8788_BUCK1_DVS_SEL_M, LP8788_BUCK2_DVS_SEL_M };
        u8 val[]  = { LP8788_BUCK1_DVS_PIN, LP8788_BUCK2_DVS_PIN };
+       u8 default_dvs_mode[] = { LP8788_BUCK1_DVS_I2C, LP8788_BUCK2_DVS_I2C };
 
        /* no dvs for buck3, 4 */
        if (id == BUCK3 || id == BUCK4)
@@ -550,7 +500,8 @@ static int lp8788_init_dvs(struct lp8788_buck *buck, enum lp8788_buck_id id)
                                val[id]);
 
 set_default_dvs_mode:
-       return lp8788_set_default_dvs_ctrl_mode(buck->lp, id);
+       return lp8788_update_bits(buck->lp, LP8788_BUCK_DVS_SEL, mask[id],
+                                 default_dvs_mode[id]);
 }
 
 static __devinit int lp8788_buck_probe(struct platform_device *pdev)
@@ -567,7 +518,6 @@ static __devinit int lp8788_buck_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        buck->lp = lp;
-       buck->pmap = &buck_pmap[id];
 
        ret = lp8788_init_dvs(buck, id);
        if (ret)
index d2122e41a96df26911cc5219a52b3a485b63bc2e..6796eeb47dc6f65b1997f75cacc1f04cb8e7d6cf 100644 (file)
@@ -496,6 +496,7 @@ static struct regulator_desc lp8788_dldo_desc[] = {
                .name = "dldo12",
                .id = DLDO12,
                .ops = &lp8788_ldo_voltage_fixed_ops,
+               .n_voltages = 1,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
                .enable_reg = LP8788_EN_LDO_B,
@@ -521,6 +522,7 @@ static struct regulator_desc lp8788_aldo_desc[] = {
                .name = "aldo2",
                .id = ALDO2,
                .ops = &lp8788_ldo_voltage_fixed_ops,
+               .n_voltages = 1,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
                .enable_reg = LP8788_EN_LDO_B,
@@ -530,6 +532,7 @@ static struct regulator_desc lp8788_aldo_desc[] = {
                .name = "aldo3",
                .id = ALDO3,
                .ops = &lp8788_ldo_voltage_fixed_ops,
+               .n_voltages = 1,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
                .enable_reg = LP8788_EN_LDO_B,
@@ -539,6 +542,7 @@ static struct regulator_desc lp8788_aldo_desc[] = {
                .name = "aldo4",
                .id = ALDO4,
                .ops = &lp8788_ldo_voltage_fixed_ops,
+               .n_voltages = 1,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
                .enable_reg = LP8788_EN_LDO_B,
@@ -548,6 +552,7 @@ static struct regulator_desc lp8788_aldo_desc[] = {
                .name = "aldo5",
                .id = ALDO5,
                .ops = &lp8788_ldo_voltage_fixed_ops,
+               .n_voltages = 1,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
                .enable_reg = LP8788_EN_LDO_C,
@@ -583,6 +588,7 @@ static struct regulator_desc lp8788_aldo_desc[] = {
                .name = "aldo8",
                .id = ALDO8,
                .ops = &lp8788_ldo_voltage_fixed_ops,
+               .n_voltages = 1,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
                .enable_reg = LP8788_EN_LDO_C,
@@ -592,6 +598,7 @@ static struct regulator_desc lp8788_aldo_desc[] = {
                .name = "aldo9",
                .id = ALDO9,
                .ops = &lp8788_ldo_voltage_fixed_ops,
+               .n_voltages = 1,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
                .enable_reg = LP8788_EN_LDO_C,
@@ -601,6 +608,7 @@ static struct regulator_desc lp8788_aldo_desc[] = {
                .name = "aldo10",
                .id = ALDO10,
                .ops = &lp8788_ldo_voltage_fixed_ops,
+               .n_voltages = 1,
                .type = REGULATOR_VOLTAGE,
                .owner = THIS_MODULE,
                .enable_reg = LP8788_EN_LDO_C,
index c564af6f05a360c92f18be7cad558b1b73723c2f..2a67d08658add7dfcabbc1c00d4a0a02b9b70a0d 100644 (file)
@@ -66,7 +66,7 @@ enum max77686_ramp_rate {
 };
 
 struct max77686_data {
-       struct regulator_dev **rdev;
+       struct regulator_dev *rdev[MAX77686_REGULATORS];
 };
 
 static int max77686_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
@@ -265,6 +265,7 @@ static int max77686_pmic_dt_parse_pdata(struct max77686_dev *iodev,
                rmatch.of_node = NULL;
                of_regulator_match(iodev->dev, regulators_np, &rmatch, 1);
                rdata[i].initdata = rmatch.init_data;
+               rdata[i].of_node = rmatch.of_node;
        }
 
        pdata->regulators = rdata;
@@ -283,10 +284,8 @@ static __devinit int max77686_pmic_probe(struct platform_device *pdev)
 {
        struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent);
        struct max77686_platform_data *pdata = dev_get_platdata(iodev->dev);
-       struct regulator_dev **rdev;
        struct max77686_data *max77686;
-       int i,  size;
-       int ret = 0;
+       int i, ret = 0;
        struct regulator_config config = { };
 
        dev_dbg(&pdev->dev, "%s\n", __func__);
@@ -313,45 +312,38 @@ static __devinit int max77686_pmic_probe(struct platform_device *pdev)
        if (!max77686)
                return -ENOMEM;
 
-       size = sizeof(struct regulator_dev *) * MAX77686_REGULATORS;
-       max77686->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
-       if (!max77686->rdev)
-               return -ENOMEM;
-
-       rdev = max77686->rdev;
        config.dev = &pdev->dev;
        config.regmap = iodev->regmap;
        platform_set_drvdata(pdev, max77686);
 
        for (i = 0; i < MAX77686_REGULATORS; i++) {
                config.init_data = pdata->regulators[i].initdata;
+               config.of_node = pdata->regulators[i].of_node;
 
-               rdev[i] = regulator_register(&regulators[i], &config);
-               if (IS_ERR(rdev[i])) {
-                       ret = PTR_ERR(rdev[i]);
+               max77686->rdev[i] = regulator_register(&regulators[i], &config);
+               if (IS_ERR(max77686->rdev[i])) {
+                       ret = PTR_ERR(max77686->rdev[i]);
                        dev_err(&pdev->dev,
                                "regulator init failed for %d\n", i);
-                               rdev[i] = NULL;
-                               goto err;
+                       max77686->rdev[i] = NULL;
+                       goto err;
                }
        }
 
        return 0;
 err:
        while (--i >= 0)
-               regulator_unregister(rdev[i]);
+               regulator_unregister(max77686->rdev[i]);
        return ret;
 }
 
 static int __devexit max77686_pmic_remove(struct platform_device *pdev)
 {
        struct max77686_data *max77686 = platform_get_drvdata(pdev);
-       struct regulator_dev **rdev = max77686->rdev;
        int i;
 
        for (i = 0; i < MAX77686_REGULATORS; i++)
-               if (rdev[i])
-                       regulator_unregister(rdev[i]);
+               regulator_unregister(max77686->rdev[i]);
 
        return 0;
 }
diff --git a/drivers/regulator/max8907-regulator.c b/drivers/regulator/max8907-regulator.c
new file mode 100644 (file)
index 0000000..bd3b28b
--- /dev/null
@@ -0,0 +1,383 @@
+/*
+ * max8907-regulator.c -- support regulators in max8907
+ *
+ * Copyright (C) 2010 Gyungoh Yoo <jack.yoo@maxim-ic.com>
+ * Copyright (C) 2010-2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Portions based on drivers/regulator/tps65910-regulator.c,
+ *     Copyright 2010 Texas Instruments Inc.
+ *     Author: Graeme Gregory <gg@slimlogic.co.uk>
+ *     Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>
+ *
+ * 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/err.h>
+#include <linux/init.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/max8907.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#define MAX8907_II2RR_VERSION_MASK     0xF0
+#define MAX8907_II2RR_VERSION_REV_A    0x00
+#define MAX8907_II2RR_VERSION_REV_B    0x10
+#define MAX8907_II2RR_VERSION_REV_C    0x30
+
+struct max8907_regulator {
+       struct regulator_desc desc[MAX8907_NUM_REGULATORS];
+       struct regulator_dev *rdev[MAX8907_NUM_REGULATORS];
+};
+
+#define REG_MBATT() \
+       [MAX8907_MBATT] = { \
+               .name = "MBATT", \
+               .supply_name = "mbatt", \
+               .id = MAX8907_MBATT, \
+               .ops = &max8907_mbatt_ops, \
+               .type = REGULATOR_VOLTAGE, \
+               .owner = THIS_MODULE, \
+       }
+
+#define REG_LDO(ids, supply, base, min, max, step) \
+       [MAX8907_##ids] = { \
+               .name = #ids, \
+               .supply_name = supply, \
+               .id = MAX8907_##ids, \
+               .n_voltages = ((max) - (min)) / (step) + 1, \
+               .ops = &max8907_ldo_ops, \
+               .type = REGULATOR_VOLTAGE, \
+               .owner = THIS_MODULE, \
+               .min_uV = (min), \
+               .uV_step = (step), \
+               .vsel_reg = (base) + MAX8907_VOUT, \
+               .vsel_mask = 0x3f, \
+               .enable_reg = (base) + MAX8907_CTL, \
+               .enable_mask = MAX8907_MASK_LDO_EN, \
+       }
+
+#define REG_FIXED(ids, supply, voltage) \
+       [MAX8907_##ids] = { \
+               .name = #ids, \
+               .supply_name = supply, \
+               .id = MAX8907_##ids, \
+               .n_voltages = 1, \
+               .ops = &max8907_fixed_ops, \
+               .type = REGULATOR_VOLTAGE, \
+               .owner = THIS_MODULE, \
+               .min_uV = (voltage), \
+       }
+
+#define REG_OUT5V(ids, supply, base, voltage) \
+       [MAX8907_##ids] = { \
+               .name = #ids, \
+               .supply_name = supply, \
+               .id = MAX8907_##ids, \
+               .n_voltages = 1, \
+               .ops = &max8907_out5v_ops, \
+               .type = REGULATOR_VOLTAGE, \
+               .owner = THIS_MODULE, \
+               .min_uV = (voltage), \
+               .enable_reg = (base), \
+               .enable_mask = MAX8907_MASK_OUT5V_EN, \
+       }
+
+#define REG_BBAT(ids, supply, base, min, max, step) \
+       [MAX8907_##ids] = { \
+               .name = #ids, \
+               .supply_name = supply, \
+               .id = MAX8907_##ids, \
+               .n_voltages = ((max) - (min)) / (step) + 1, \
+               .ops = &max8907_bbat_ops, \
+               .type = REGULATOR_VOLTAGE, \
+               .owner = THIS_MODULE, \
+               .min_uV = (min), \
+               .uV_step = (step), \
+               .vsel_reg = (base), \
+               .vsel_mask = MAX8907_MASK_VBBATTCV, \
+       }
+
+#define LDO_750_50(id, supply, base) REG_LDO(id, supply, (base), \
+                       750000, 3900000, 50000)
+#define LDO_650_25(id, supply, base) REG_LDO(id, supply, (base), \
+                       650000, 2225000, 25000)
+
+static struct regulator_ops max8907_mbatt_ops = {
+};
+
+static struct regulator_ops max8907_ldo_ops = {
+       .list_voltage = regulator_list_voltage_linear,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+};
+
+static struct regulator_ops max8907_ldo_hwctl_ops = {
+       .list_voltage = regulator_list_voltage_linear,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+};
+
+static struct regulator_ops max8907_fixed_ops = {
+       .list_voltage = regulator_list_voltage_linear,
+};
+
+static struct regulator_ops max8907_out5v_ops = {
+       .list_voltage = regulator_list_voltage_linear,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+       .is_enabled = regulator_is_enabled_regmap,
+};
+
+static struct regulator_ops max8907_out5v_hwctl_ops = {
+       .list_voltage = regulator_list_voltage_linear,
+};
+
+static struct regulator_ops max8907_bbat_ops = {
+       .list_voltage = regulator_list_voltage_linear,
+       .set_voltage_sel = regulator_set_voltage_sel_regmap,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
+};
+
+static struct regulator_desc max8907_regulators[] = {
+       REG_MBATT(),
+       REG_LDO(SD1, "in-v1", MAX8907_REG_SDCTL1, 650000, 2225000, 25000),
+       REG_LDO(SD2, "in-v2", MAX8907_REG_SDCTL2, 637500, 1425000, 12500),
+       REG_LDO(SD3, "in-v3", MAX8907_REG_SDCTL3, 750000, 3900000, 50000),
+       LDO_750_50(LDO1, "in1", MAX8907_REG_LDOCTL1),
+       LDO_650_25(LDO2, "in2", MAX8907_REG_LDOCTL2),
+       LDO_650_25(LDO3, "in3", MAX8907_REG_LDOCTL3),
+       LDO_750_50(LDO4, "in4", MAX8907_REG_LDOCTL4),
+       LDO_750_50(LDO5, "in5", MAX8907_REG_LDOCTL5),
+       LDO_750_50(LDO6, "in6", MAX8907_REG_LDOCTL6),
+       LDO_750_50(LDO7, "in7", MAX8907_REG_LDOCTL7),
+       LDO_750_50(LDO8, "in8", MAX8907_REG_LDOCTL8),
+       LDO_750_50(LDO9, "in9", MAX8907_REG_LDOCTL9),
+       LDO_750_50(LDO10, "in10", MAX8907_REG_LDOCTL10),
+       LDO_750_50(LDO11, "in11", MAX8907_REG_LDOCTL11),
+       LDO_750_50(LDO12, "in12", MAX8907_REG_LDOCTL12),
+       LDO_750_50(LDO13, "in13", MAX8907_REG_LDOCTL13),
+       LDO_750_50(LDO14, "in14", MAX8907_REG_LDOCTL14),
+       LDO_750_50(LDO15, "in15", MAX8907_REG_LDOCTL15),
+       LDO_750_50(LDO16, "in16", MAX8907_REG_LDOCTL16),
+       LDO_650_25(LDO17, "in17", MAX8907_REG_LDOCTL17),
+       LDO_650_25(LDO18, "in18", MAX8907_REG_LDOCTL18),
+       LDO_750_50(LDO19, "in19", MAX8907_REG_LDOCTL19),
+       LDO_750_50(LDO20, "in20", MAX8907_REG_LDOCTL20),
+       REG_OUT5V(OUT5V, "mbatt", MAX8907_REG_OUT5VEN, 5000000),
+       REG_OUT5V(OUT33V, "mbatt",  MAX8907_REG_OUT33VEN, 3300000),
+       REG_BBAT(BBAT, "MBATT", MAX8907_REG_BBAT_CNFG,
+                                               2400000, 3000000, 200000),
+       REG_FIXED(SDBY, "MBATT", 1200000),
+       REG_FIXED(VRTC, "MBATT", 3300000),
+};
+
+#ifdef CONFIG_OF
+
+#define MATCH(_name, _id) \
+       [MAX8907_##_id] = { \
+               .name = #_name, \
+               .driver_data = (void *)&max8907_regulators[MAX8907_##_id], \
+       }
+
+static struct of_regulator_match max8907_matches[] = {
+       MATCH(mbatt, MBATT),
+       MATCH(sd1, SD1),
+       MATCH(sd2, SD2),
+       MATCH(sd3, SD3),
+       MATCH(ldo1, LDO1),
+       MATCH(ldo2, LDO2),
+       MATCH(ldo3, LDO3),
+       MATCH(ldo4, LDO4),
+       MATCH(ldo5, LDO5),
+       MATCH(ldo6, LDO6),
+       MATCH(ldo7, LDO7),
+       MATCH(ldo8, LDO8),
+       MATCH(ldo9, LDO9),
+       MATCH(ldo10, LDO10),
+       MATCH(ldo11, LDO11),
+       MATCH(ldo12, LDO12),
+       MATCH(ldo13, LDO13),
+       MATCH(ldo14, LDO14),
+       MATCH(ldo15, LDO15),
+       MATCH(ldo16, LDO16),
+       MATCH(ldo17, LDO17),
+       MATCH(ldo18, LDO18),
+       MATCH(ldo19, LDO19),
+       MATCH(ldo20, LDO20),
+       MATCH(out5v, OUT5V),
+       MATCH(out33v, OUT33V),
+       MATCH(bbat, BBAT),
+       MATCH(sdby, SDBY),
+       MATCH(vrtc, VRTC),
+};
+
+static int max8907_regulator_parse_dt(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.parent->of_node;
+       struct device_node *regulators;
+       int ret;
+
+       if (!pdev->dev.parent->of_node)
+               return 0;
+
+       regulators = of_find_node_by_name(np, "regulators");
+       if (!regulators) {
+               dev_err(&pdev->dev, "regulators node not found\n");
+               return -EINVAL;
+       }
+
+       ret = of_regulator_match(pdev->dev.parent, regulators,
+                                max8907_matches,
+                                ARRAY_SIZE(max8907_matches));
+       if (ret < 0) {
+               dev_err(&pdev->dev, "Error parsing regulator init data: %d\n",
+                       ret);
+               return ret;
+       }
+
+       return 0;
+}
+#else
+static int max8907_regulator_parse_dt(struct platform_device *pdev)
+{
+       return 0;
+}
+#endif
+
+static __devinit int max8907_regulator_probe(struct platform_device *pdev)
+{
+       struct max8907 *max8907 = dev_get_drvdata(pdev->dev.parent);
+       struct max8907_platform_data *pdata = dev_get_platdata(max8907->dev);
+       int ret;
+       struct max8907_regulator *pmic;
+       unsigned int val;
+       int i;
+       struct regulator_config config = {};
+       struct regulator_init_data *idata;
+       const char *mbatt_rail_name = NULL;
+
+       ret = max8907_regulator_parse_dt(pdev);
+       if (ret)
+               return ret;
+
+       pmic = devm_kzalloc(&pdev->dev, sizeof(*pmic), GFP_KERNEL);
+       if (!pmic) {
+               dev_err(&pdev->dev, "Failed to alloc pmic\n");
+               return -ENOMEM;
+       }
+       platform_set_drvdata(pdev, pmic);
+
+       memcpy(pmic->desc, max8907_regulators, sizeof(pmic->desc));
+
+       /* Backwards compatibility with MAX8907B; SD1 uses different voltages */
+       regmap_read(max8907->regmap_gen, MAX8907_REG_II2RR, &val);
+       if ((val & MAX8907_II2RR_VERSION_MASK) ==
+           MAX8907_II2RR_VERSION_REV_B) {
+               pmic->desc[MAX8907_SD1].min_uV = 637500;
+               pmic->desc[MAX8907_SD1].uV_step = 12500;
+               pmic->desc[MAX8907_SD1].n_voltages = (1425000 - 637500) / 12500;
+       }
+
+       for (i = 0; i < MAX8907_NUM_REGULATORS; i++) {
+               config.dev = pdev->dev.parent;
+               if (pdata)
+                       idata = pdata->init_data[i];
+               else
+                       idata = max8907_matches[i].init_data;
+               config.init_data = idata;
+               config.driver_data = pmic;
+               config.regmap = max8907->regmap_gen;
+               config.of_node = max8907_matches[i].of_node;
+
+               switch (pmic->desc[i].id) {
+               case MAX8907_MBATT:
+                       mbatt_rail_name = idata->constraints.name;
+                       break;
+               case MAX8907_BBAT:
+               case MAX8907_SDBY:
+               case MAX8907_VRTC:
+                       idata->supply_regulator = mbatt_rail_name;
+                       break;
+               }
+
+               if (pmic->desc[i].ops == &max8907_ldo_ops) {
+                       regmap_read(config.regmap, pmic->desc[i].enable_reg,
+                                   &val);
+                       if ((val & MAX8907_MASK_LDO_SEQ) !=
+                           MAX8907_MASK_LDO_SEQ)
+                               pmic->desc[i].ops = &max8907_ldo_hwctl_ops;
+               } else if (pmic->desc[i].ops == &max8907_out5v_ops) {
+                       regmap_read(config.regmap, pmic->desc[i].enable_reg,
+                                   &val);
+                       if ((val & (MAX8907_MASK_OUT5V_VINEN |
+                                               MAX8907_MASK_OUT5V_ENSRC)) !=
+                           MAX8907_MASK_OUT5V_ENSRC)
+                               pmic->desc[i].ops = &max8907_out5v_hwctl_ops;
+               }
+
+               pmic->rdev[i] = regulator_register(&pmic->desc[i], &config);
+               if (IS_ERR(pmic->rdev[i])) {
+                       dev_err(&pdev->dev,
+                               "failed to register %s regulator\n",
+                               pmic->desc[i].name);
+                       ret = PTR_ERR(pmic->rdev[i]);
+                       goto err_unregister_regulator;
+               }
+       }
+
+       return 0;
+
+err_unregister_regulator:
+       while (--i >= 0)
+               regulator_unregister(pmic->rdev[i]);
+       return ret;
+}
+
+static __devexit int max8907_regulator_remove(struct platform_device *pdev)
+{
+       struct max8907_regulator *pmic;
+       int i;
+
+       for (i = 0; i < MAX8907_NUM_REGULATORS; i++)
+               regulator_unregister(pmic->rdev[i]);
+
+       return 0;
+}
+
+static struct platform_driver max8907_regulator_driver = {
+       .driver = {
+                  .name = "max8907-regulator",
+                  .owner = THIS_MODULE,
+                  },
+       .probe = max8907_regulator_probe,
+       .remove = __devexit_p(max8907_regulator_remove),
+};
+
+static int __init max8907_regulator_init(void)
+{
+       return platform_driver_register(&max8907_regulator_driver);
+}
+
+subsys_initcall(max8907_regulator_init);
+
+static void __exit max8907_reg_exit(void)
+{
+       platform_driver_unregister(&max8907_regulator_driver);
+}
+
+module_exit(max8907_reg_exit);
+
+MODULE_DESCRIPTION("MAX8907 regulator driver");
+MODULE_AUTHOR("Gyungoh Yoo <jack.yoo@maxim-ic.com>");
+MODULE_LICENSE("GPL v2");
index 4932e3449fe145fc4e27f422df1d1816d7cb99c2..4977b199c86b87de47e3af8711a95fbfe02113f7 100644 (file)
@@ -238,9 +238,10 @@ static int mc13783_powermisc_rmw(struct mc13xxx_regulator_priv *priv, u32 mask,
 
        BUG_ON(val & ~mask);
 
+       mc13xxx_lock(priv->mc13xxx);
        ret = mc13xxx_reg_read(mc13783, MC13783_REG_POWERMISC, &valread);
        if (ret)
-               return ret;
+               goto out;
 
        /* Update the stored state for Power Gates. */
        priv->powermisc_pwgt_state =
@@ -253,7 +254,10 @@ static int mc13783_powermisc_rmw(struct mc13xxx_regulator_priv *priv, u32 mask,
        valread = (valread & ~MC13783_REG_POWERMISC_PWGTSPI_M) |
                                                priv->powermisc_pwgt_state;
 
-       return mc13xxx_reg_write(mc13783, MC13783_REG_POWERMISC, valread);
+       ret = mc13xxx_reg_write(mc13783, MC13783_REG_POWERMISC, valread);
+out:
+       mc13xxx_unlock(priv->mc13xxx);
+       return ret;
 }
 
 static int mc13783_gpo_regulator_enable(struct regulator_dev *rdev)
@@ -261,7 +265,6 @@ static int mc13783_gpo_regulator_enable(struct regulator_dev *rdev)
        struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
        struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
        int id = rdev_get_id(rdev);
-       int ret;
        u32 en_val = mc13xxx_regulators[id].enable_bit;
 
        dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
@@ -271,12 +274,8 @@ static int mc13783_gpo_regulator_enable(struct regulator_dev *rdev)
            id == MC13783_REG_PWGT2SPI)
                en_val = 0;
 
-       mc13xxx_lock(priv->mc13xxx);
-       ret = mc13783_powermisc_rmw(priv, mc13xxx_regulators[id].enable_bit,
+       return mc13783_powermisc_rmw(priv, mc13xxx_regulators[id].enable_bit,
                                        en_val);
-       mc13xxx_unlock(priv->mc13xxx);
-
-       return ret;
 }
 
 static int mc13783_gpo_regulator_disable(struct regulator_dev *rdev)
@@ -284,7 +283,6 @@ static int mc13783_gpo_regulator_disable(struct regulator_dev *rdev)
        struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
        struct mc13xxx_regulator *mc13xxx_regulators = priv->mc13xxx_regulators;
        int id = rdev_get_id(rdev);
-       int ret;
        u32 dis_val = 0;
 
        dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
@@ -294,12 +292,8 @@ static int mc13783_gpo_regulator_disable(struct regulator_dev *rdev)
            id == MC13783_REG_PWGT2SPI)
                dis_val = mc13xxx_regulators[id].enable_bit;
 
-       mc13xxx_lock(priv->mc13xxx);
-       ret = mc13783_powermisc_rmw(priv, mc13xxx_regulators[id].enable_bit,
+       return mc13783_powermisc_rmw(priv, mc13xxx_regulators[id].enable_bit,
                                        dis_val);
-       mc13xxx_unlock(priv->mc13xxx);
-
-       return ret;
 }
 
 static int mc13783_gpo_regulator_is_enabled(struct regulator_dev *rdev)
@@ -330,7 +324,6 @@ static struct regulator_ops mc13783_gpo_regulator_ops = {
        .is_enabled = mc13783_gpo_regulator_is_enabled,
        .list_voltage = regulator_list_voltage_table,
        .set_voltage = mc13xxx_fixed_regulator_set_voltage,
-       .get_voltage = mc13xxx_fixed_regulator_get_voltage,
 };
 
 static int __devinit mc13783_regulator_probe(struct platform_device *pdev)
index b388b746452e024952cbfc6443adb2ec6bc4751b..1fa63812f7ace6070dcfda38a14cd5aab0466b69 100644 (file)
@@ -305,9 +305,10 @@ static int mc13892_powermisc_rmw(struct mc13xxx_regulator_priv *priv, u32 mask,
 
        BUG_ON(val & ~mask);
 
+       mc13xxx_lock(priv->mc13xxx);
        ret = mc13xxx_reg_read(mc13892, MC13892_POWERMISC, &valread);
        if (ret)
-               return ret;
+               goto out;
 
        /* Update the stored state for Power Gates. */
        priv->powermisc_pwgt_state =
@@ -320,14 +321,16 @@ static int mc13892_powermisc_rmw(struct mc13xxx_regulator_priv *priv, u32 mask,
        valread = (valread & ~MC13892_POWERMISC_PWGTSPI_M) |
                priv->powermisc_pwgt_state;
 
-       return mc13xxx_reg_write(mc13892, MC13892_POWERMISC, valread);
+       ret = mc13xxx_reg_write(mc13892, MC13892_POWERMISC, valread);
+out:
+       mc13xxx_unlock(priv->mc13xxx);
+       return ret;
 }
 
 static int mc13892_gpo_regulator_enable(struct regulator_dev *rdev)
 {
        struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
        int id = rdev_get_id(rdev);
-       int ret;
        u32 en_val = mc13892_regulators[id].enable_bit;
        u32 mask = mc13892_regulators[id].enable_bit;
 
@@ -340,18 +343,13 @@ static int mc13892_gpo_regulator_enable(struct regulator_dev *rdev)
        if (id == MC13892_GPO4)
                mask |= MC13892_POWERMISC_GPO4ADINEN;
 
-       mc13xxx_lock(priv->mc13xxx);
-       ret = mc13892_powermisc_rmw(priv, mask, en_val);
-       mc13xxx_unlock(priv->mc13xxx);
-
-       return ret;
+       return mc13892_powermisc_rmw(priv, mask, en_val);
 }
 
 static int mc13892_gpo_regulator_disable(struct regulator_dev *rdev)
 {
        struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
        int id = rdev_get_id(rdev);
-       int ret;
        u32 dis_val = 0;
 
        dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
@@ -360,12 +358,8 @@ static int mc13892_gpo_regulator_disable(struct regulator_dev *rdev)
        if (id == MC13892_PWGT1SPI || id == MC13892_PWGT2SPI)
                dis_val = mc13892_regulators[id].enable_bit;
 
-       mc13xxx_lock(priv->mc13xxx);
-       ret = mc13892_powermisc_rmw(priv, mc13892_regulators[id].enable_bit,
+       return mc13892_powermisc_rmw(priv, mc13892_regulators[id].enable_bit,
                dis_val);
-       mc13xxx_unlock(priv->mc13xxx);
-
-       return ret;
 }
 
 static int mc13892_gpo_regulator_is_enabled(struct regulator_dev *rdev)
@@ -396,14 +390,13 @@ static struct regulator_ops mc13892_gpo_regulator_ops = {
        .is_enabled = mc13892_gpo_regulator_is_enabled,
        .list_voltage = regulator_list_voltage_table,
        .set_voltage = mc13xxx_fixed_regulator_set_voltage,
-       .get_voltage = mc13xxx_fixed_regulator_get_voltage,
 };
 
-static int mc13892_sw_regulator_get_voltage(struct regulator_dev *rdev)
+static int mc13892_sw_regulator_get_voltage_sel(struct regulator_dev *rdev)
 {
        struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
        int ret, id = rdev_get_id(rdev);
-       unsigned int val, hi;
+       unsigned int val;
 
        dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
 
@@ -414,17 +407,11 @@ static int mc13892_sw_regulator_get_voltage(struct regulator_dev *rdev)
        if (ret)
                return ret;
 
-       hi  = val & MC13892_SWITCHERS0_SWxHI;
        val = (val & mc13892_regulators[id].vsel_mask)
                >> mc13892_regulators[id].vsel_shift;
 
        dev_dbg(rdev_get_dev(rdev), "%s id: %d val: %d\n", __func__, id, val);
 
-       if (hi)
-               val = (25000 * val) + 1100000;
-       else
-               val = (25000 * val) + 600000;
-
        return val;
 }
 
@@ -432,37 +419,25 @@ static int mc13892_sw_regulator_set_voltage_sel(struct regulator_dev *rdev,
                                                unsigned selector)
 {
        struct mc13xxx_regulator_priv *priv = rdev_get_drvdata(rdev);
-       int hi, value, mask, id = rdev_get_id(rdev);
-       u32 valread;
+       int volt, mask, id = rdev_get_id(rdev);
+       u32 reg_value;
        int ret;
 
-       value = rdev->desc->volt_table[selector];
+       volt = rdev->desc->volt_table[selector];
+       mask = mc13892_regulators[id].vsel_mask;
+       reg_value = selector << mc13892_regulators[id].vsel_shift;
+
+       if (volt > 1375000) {
+               mask |= MC13892_SWITCHERS0_SWxHI;
+               reg_value |= MC13892_SWITCHERS0_SWxHI;
+       } else if (volt < 1100000) {
+               mask |= MC13892_SWITCHERS0_SWxHI;
+               reg_value &= ~MC13892_SWITCHERS0_SWxHI;
+       }
 
        mc13xxx_lock(priv->mc13xxx);
-       ret = mc13xxx_reg_read(priv->mc13xxx,
-               mc13892_regulators[id].vsel_reg, &valread);
-       if (ret)
-               goto err;
-
-       if (value > 1375000)
-               hi = 1;
-       else if (value < 1100000)
-               hi = 0;
-       else
-               hi = valread & MC13892_SWITCHERS0_SWxHI;
-
-       if (hi) {
-               value = (value - 1100000) / 25000;
-               value |= MC13892_SWITCHERS0_SWxHI;
-       } else
-               value = (value - 600000) / 25000;
-
-       mask = mc13892_regulators[id].vsel_mask | MC13892_SWITCHERS0_SWxHI;
-       valread = (valread & ~mask) |
-                       (value << mc13892_regulators[id].vsel_shift);
-       ret = mc13xxx_reg_write(priv->mc13xxx, mc13892_regulators[id].vsel_reg,
-                       valread);
-err:
+       ret = mc13xxx_reg_rmw(priv->mc13xxx, mc13892_regulators[id].reg, mask,
+                             reg_value);
        mc13xxx_unlock(priv->mc13xxx);
 
        return ret;
@@ -471,7 +446,7 @@ err:
 static struct regulator_ops mc13892_sw_regulator_ops = {
        .list_voltage = regulator_list_voltage_table,
        .set_voltage_sel = mc13892_sw_regulator_set_voltage_sel,
-       .get_voltage = mc13892_sw_regulator_get_voltage,
+       .get_voltage_sel = mc13892_sw_regulator_get_voltage_sel,
 };
 
 static int mc13892_vcam_set_mode(struct regulator_dev *rdev, unsigned int mode)
index d6eda28ca5d02dbf4f06498a7787d177304d03f0..88cbb832d555207b4e7fc124aa05b4afcbcbb3f1 100644 (file)
@@ -143,30 +143,21 @@ int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev, int min_uV,
                __func__, id, min_uV, max_uV);
 
        if (min_uV <= rdev->desc->volt_table[0] &&
-           rdev->desc->volt_table[0] <= max_uV)
+           rdev->desc->volt_table[0] <= max_uV) {
+               *selector = 0;
                return 0;
-       else
+       } else {
                return -EINVAL;
+       }
 }
 EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_set_voltage);
 
-int mc13xxx_fixed_regulator_get_voltage(struct regulator_dev *rdev)
-{
-       int id = rdev_get_id(rdev);
-
-       dev_dbg(rdev_get_dev(rdev), "%s id: %d\n", __func__, id);
-
-       return rdev->desc->volt_table[0];
-}
-EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_get_voltage);
-
 struct regulator_ops mc13xxx_fixed_regulator_ops = {
        .enable = mc13xxx_regulator_enable,
        .disable = mc13xxx_regulator_disable,
        .is_enabled = mc13xxx_regulator_is_enabled,
        .list_voltage = regulator_list_voltage_table,
        .set_voltage = mc13xxx_fixed_regulator_set_voltage,
-       .get_voltage = mc13xxx_fixed_regulator_get_voltage,
 };
 EXPORT_SYMBOL_GPL(mc13xxx_fixed_regulator_ops);
 
index eaff5510b6df62cc6096c1e6683a4601cdb50240..06c8903f182a680e7c0bb8464f227f3945cbc11f 100644 (file)
@@ -34,7 +34,6 @@ struct mc13xxx_regulator_priv {
 
 extern int mc13xxx_fixed_regulator_set_voltage(struct regulator_dev *rdev,
                int min_uV, int max_uV, unsigned *selector);
-extern int mc13xxx_fixed_regulator_get_voltage(struct regulator_dev *rdev);
 
 #ifdef CONFIG_OF
 extern int mc13xxx_get_num_regulators_dt(struct platform_device *pdev);
index 17d19fbbc490156c8507301808863411a5f3135f..2ba7502fa3b2563731893cb327249cf7d33a8433 100644 (file)
@@ -443,52 +443,17 @@ static int palmas_list_voltage_ldo(struct regulator_dev *dev,
        return  850000 + (selector * 50000);
 }
 
-static int palmas_get_voltage_ldo_sel(struct regulator_dev *dev)
-{
-       struct palmas_pmic *pmic = rdev_get_drvdata(dev);
-       int id = rdev_get_id(dev);
-       int selector;
-       unsigned int reg;
-       unsigned int addr;
-
-       addr = palmas_regs_info[id].vsel_addr;
-
-       palmas_ldo_read(pmic->palmas, addr, &reg);
-
-       selector = reg & PALMAS_LDO1_VOLTAGE_VSEL_MASK;
-
-       /* Adjust selector to match list_voltage ranges */
-       if (selector > 49)
-               selector = 49;
-
-       return selector;
-}
-
-static int palmas_set_voltage_ldo_sel(struct regulator_dev *dev,
-               unsigned selector)
-{
-       struct palmas_pmic *pmic = rdev_get_drvdata(dev);
-       int id = rdev_get_id(dev);
-       unsigned int reg = 0;
-       unsigned int addr;
-
-       addr = palmas_regs_info[id].vsel_addr;
-
-       reg = selector;
-
-       palmas_ldo_write(pmic->palmas, addr, reg);
-
-       return 0;
-}
-
 static int palmas_map_voltage_ldo(struct regulator_dev *rdev,
                int min_uV, int max_uV)
 {
        int ret, voltage;
 
-       ret = ((min_uV - 900000) / 50000) + 1;
-       if (ret < 0)
-               return ret;
+       if (min_uV == 0)
+               return 0;
+
+       if (min_uV < 900000)
+               min_uV = 900000;
+       ret = DIV_ROUND_UP(min_uV - 900000, 50000) + 1;
 
        /* Map back into a voltage to verify we're still in bounds */
        voltage = palmas_list_voltage_ldo(rdev, ret);
@@ -502,8 +467,8 @@ static struct regulator_ops palmas_ops_ldo = {
        .is_enabled             = palmas_is_enabled_ldo,
        .enable                 = regulator_enable_regmap,
        .disable                = regulator_disable_regmap,
-       .get_voltage_sel        = palmas_get_voltage_ldo_sel,
-       .set_voltage_sel        = palmas_set_voltage_ldo_sel,
+       .get_voltage_sel        = regulator_get_voltage_sel_regmap,
+       .set_voltage_sel        = regulator_set_voltage_sel_regmap,
        .list_voltage           = palmas_list_voltage_ldo,
        .map_voltage            = palmas_map_voltage_ldo,
 };
@@ -586,7 +551,7 @@ static int palmas_ldo_init(struct palmas *palmas, int id,
 
        addr = palmas_regs_info[id].ctrl_addr;
 
-       ret = palmas_smps_read(palmas, addr, &reg);
+       ret = palmas_ldo_read(palmas, addr, &reg);
        if (ret)
                return ret;
 
@@ -596,7 +561,7 @@ static int palmas_ldo_init(struct palmas *palmas, int id,
        if (reg_init->mode_sleep)
                reg |= PALMAS_LDO1_CTRL_MODE_SLEEP;
 
-       ret = palmas_smps_write(palmas, addr, reg);
+       ret = palmas_ldo_write(palmas, addr, reg);
        if (ret)
                return ret;
 
@@ -630,7 +595,7 @@ static __devinit int palmas_probe(struct platform_device *pdev)
 
        ret = palmas_smps_read(palmas, PALMAS_SMPS_CTRL, &reg);
        if (ret)
-               goto err_unregister_regulator;
+               return ret;
 
        if (reg & PALMAS_SMPS_CTRL_SMPS12_SMPS123_EN)
                pmic->smps123 = 1;
@@ -676,7 +641,9 @@ static __devinit int palmas_probe(struct platform_device *pdev)
                case PALMAS_REG_SMPS10:
                        pmic->desc[id].n_voltages = PALMAS_SMPS10_NUM_VOLTAGES;
                        pmic->desc[id].ops = &palmas_ops_smps10;
-                       pmic->desc[id].vsel_reg = PALMAS_SMPS10_CTRL;
+                       pmic->desc[id].vsel_reg =
+                                       PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE,
+                                                       PALMAS_SMPS10_CTRL);
                        pmic->desc[id].vsel_mask = SMPS10_VSEL;
                        pmic->desc[id].enable_reg =
                                        PALMAS_BASE_TO_REG(PALMAS_SMPS_BASE,
@@ -752,6 +719,9 @@ static __devinit int palmas_probe(struct platform_device *pdev)
 
                pmic->desc[id].type = REGULATOR_VOLTAGE;
                pmic->desc[id].owner = THIS_MODULE;
+               pmic->desc[id].vsel_reg = PALMAS_BASE_TO_REG(PALMAS_LDO_BASE,
+                                               palmas_regs_info[id].vsel_addr);
+               pmic->desc[id].vsel_mask = PALMAS_LDO1_VOLTAGE_VSEL_MASK;
                pmic->desc[id].enable_reg = PALMAS_BASE_TO_REG(PALMAS_LDO_BASE,
                                                palmas_regs_info[id].ctrl_addr);
                pmic->desc[id].enable_mask = PALMAS_LDO1_CTRL_MODE_ACTIVE;
@@ -778,8 +748,10 @@ static __devinit int palmas_probe(struct platform_device *pdev)
                        reg_init = pdata->reg_init[id];
                        if (reg_init) {
                                ret = palmas_ldo_init(palmas, id, reg_init);
-                               if (ret)
+                               if (ret) {
+                                       regulator_unregister(pmic->rdev[id]);
                                        goto err_unregister_regulator;
+                               }
                        }
                }
        }
index 4669dc9ac74a3b90afbd68397aa45fb79b409e9f..926f9c8f2facde5b415b0e4bdc71b5fd2dc53fe6 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/mfd/samsung/s2mps11.h>
 
 struct s2mps11_info {
-       struct regulator_dev **rdev;
+       struct regulator_dev *rdev[S2MPS11_REGULATOR_MAX];
 
        int ramp_delay2;
        int ramp_delay34;
@@ -236,9 +236,8 @@ static __devinit int s2mps11_pmic_probe(struct platform_device *pdev)
        struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
        struct sec_platform_data *pdata = dev_get_platdata(iodev->dev);
        struct regulator_config config = { };
-       struct regulator_dev **rdev;
        struct s2mps11_info *s2mps11;
-       int i, ret, size;
+       int i, ret;
        unsigned char ramp_enable, ramp_reg = 0;
 
        if (!pdata) {
@@ -251,13 +250,6 @@ static __devinit int s2mps11_pmic_probe(struct platform_device *pdev)
        if (!s2mps11)
                return -ENOMEM;
 
-       size = sizeof(struct regulator_dev *) * S2MPS11_REGULATOR_MAX;
-       s2mps11->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
-       if (!s2mps11->rdev) {
-               return -ENOMEM;
-       }
-
-       rdev = s2mps11->rdev;
        platform_set_drvdata(pdev, s2mps11);
 
        s2mps11->ramp_delay2 = pdata->buck2_ramp_delay;
@@ -297,12 +289,12 @@ static __devinit int s2mps11_pmic_probe(struct platform_device *pdev)
                config.init_data = pdata->regulators[i].initdata;
                config.driver_data = s2mps11;
 
-               rdev[i] = regulator_register(&regulators[i], &config);
-               if (IS_ERR(rdev[i])) {
-                       ret = PTR_ERR(rdev[i]);
+               s2mps11->rdev[i] = regulator_register(&regulators[i], &config);
+               if (IS_ERR(s2mps11->rdev[i])) {
+                       ret = PTR_ERR(s2mps11->rdev[i]);
                        dev_err(&pdev->dev, "regulator init failed for %d\n",
                                i);
-                       rdev[i] = NULL;
+                       s2mps11->rdev[i] = NULL;
                        goto err;
                }
        }
@@ -310,8 +302,7 @@ static __devinit int s2mps11_pmic_probe(struct platform_device *pdev)
        return 0;
 err:
        for (i = 0; i < S2MPS11_REGULATOR_MAX; i++)
-               if (rdev[i])
-                       regulator_unregister(rdev[i]);
+               regulator_unregister(s2mps11->rdev[i]);
 
        return ret;
 }
@@ -319,12 +310,10 @@ err:
 static int __devexit s2mps11_pmic_remove(struct platform_device *pdev)
 {
        struct s2mps11_info *s2mps11 = platform_get_drvdata(pdev);
-       struct regulator_dev **rdev = s2mps11->rdev;
        int i;
 
        for (i = 0; i < S2MPS11_REGULATOR_MAX; i++)
-               if (rdev[i])
-                       regulator_unregister(rdev[i]);
+               regulator_unregister(s2mps11->rdev[i]);
 
        return 0;
 }
index 947ece933d901fa75ef54e286979d12f02dea7ce..058d2f2675e902c8d2856b83b3ee5a6b4c7c5503 100644 (file)
@@ -502,15 +502,13 @@ static int set_current_limit(struct regulator_dev *rdev, int min_uA,
        if (info->n_ilimsels == 1)
                return -EINVAL;
 
-       for (i = 0; i < info->n_ilimsels; i++)
+       for (i = info->n_ilimsels - 1; i >= 0; i--) {
                if (min_uA <= info->ilimsels[i] &&
                    max_uA >= info->ilimsels[i])
-                       break;
-
-       if (i >= info->n_ilimsels)
-               return -EINVAL;
+                       return write_field(hw, &info->ilimsel, i);
+       }
 
-       return write_field(hw, &info->ilimsel, i);
+       return -EINVAL;
 }
 
 static int get_current_limit(struct regulator_dev *rdev)
index e6da90ab5153dedd64ebd96137776f652af7d152..ce1e7cb8d513f13a8463a84b2de39d1a61cb180c 100644 (file)
@@ -57,9 +57,6 @@
 struct tps6586x_regulator {
        struct regulator_desc desc;
 
-       int volt_reg;
-       int volt_shift;
-       int volt_nbits;
        int enable_bit[2];
        int enable_reg[2];
 
@@ -81,10 +78,10 @@ static int tps6586x_set_voltage_sel(struct regulator_dev *rdev,
        int ret, val, rid = rdev_get_id(rdev);
        uint8_t mask;
 
-       val = selector << ri->volt_shift;
-       mask = ((1 << ri->volt_nbits) - 1) << ri->volt_shift;
+       val = selector << (ffs(rdev->desc->vsel_mask) - 1);
+       mask = rdev->desc->vsel_mask;
 
-       ret = tps6586x_update(parent, ri->volt_reg, val, mask);
+       ret = tps6586x_update(parent, rdev->desc->vsel_reg, val, mask);
        if (ret)
                return ret;
 
@@ -100,66 +97,17 @@ static int tps6586x_set_voltage_sel(struct regulator_dev *rdev,
        return ret;
 }
 
-static int tps6586x_get_voltage_sel(struct regulator_dev *rdev)
-{
-       struct tps6586x_regulator *ri = rdev_get_drvdata(rdev);
-       struct device *parent = to_tps6586x_dev(rdev);
-       uint8_t val, mask;
-       int ret;
-
-       ret = tps6586x_read(parent, ri->volt_reg, &val);
-       if (ret)
-               return ret;
-
-       mask = ((1 << ri->volt_nbits) - 1) << ri->volt_shift;
-       val = (val & mask) >> ri->volt_shift;
-
-       if (val >= ri->desc.n_voltages)
-               BUG();
-
-       return val;
-}
-
-static int tps6586x_regulator_enable(struct regulator_dev *rdev)
-{
-       struct tps6586x_regulator *ri = rdev_get_drvdata(rdev);
-       struct device *parent = to_tps6586x_dev(rdev);
-
-       return tps6586x_set_bits(parent, ri->enable_reg[0],
-                                1 << ri->enable_bit[0]);
-}
-
-static int tps6586x_regulator_disable(struct regulator_dev *rdev)
-{
-       struct tps6586x_regulator *ri = rdev_get_drvdata(rdev);
-       struct device *parent = to_tps6586x_dev(rdev);
-
-       return tps6586x_clr_bits(parent, ri->enable_reg[0],
-                                1 << ri->enable_bit[0]);
-}
-
-static int tps6586x_regulator_is_enabled(struct regulator_dev *rdev)
-{
-       struct tps6586x_regulator *ri = rdev_get_drvdata(rdev);
-       struct device *parent = to_tps6586x_dev(rdev);
-       uint8_t reg_val;
-       int ret;
-
-       ret = tps6586x_read(parent, ri->enable_reg[0], &reg_val);
-       if (ret)
-               return ret;
-
-       return !!(reg_val & (1 << ri->enable_bit[0]));
-}
-
 static struct regulator_ops tps6586x_regulator_ops = {
        .list_voltage = regulator_list_voltage_table,
-       .get_voltage_sel = tps6586x_get_voltage_sel,
+       .get_voltage_sel = regulator_get_voltage_sel_regmap,
        .set_voltage_sel = tps6586x_set_voltage_sel,
 
-       .is_enabled = tps6586x_regulator_is_enabled,
-       .enable = tps6586x_regulator_enable,
-       .disable = tps6586x_regulator_disable,
+       .is_enabled = regulator_is_enabled_regmap,
+       .enable = regulator_enable_regmap,
+       .disable = regulator_disable_regmap,
+};
+
+static struct regulator_ops tps6586x_sys_regulator_ops = {
 };
 
 static const unsigned int tps6586x_ldo0_voltages[] = {
@@ -202,10 +150,11 @@ static const unsigned int tps6586x_dvm_voltages[] = {
                .n_voltages = ARRAY_SIZE(tps6586x_##vdata##_voltages),  \
                .volt_table = tps6586x_##vdata##_voltages,              \
                .owner  = THIS_MODULE,                                  \
+               .enable_reg = TPS6586X_SUPPLY##ereg0,                   \
+               .enable_mask = 1 << (ebit0),                            \
+               .vsel_reg = TPS6586X_##vreg,                            \
+               .vsel_mask = ((1 << (nbits)) - 1) << (shift),           \
        },                                                              \
-       .volt_reg       = TPS6586X_##vreg,                              \
-       .volt_shift     = (shift),                                      \
-       .volt_nbits     = (nbits),                                      \
        .enable_reg[0]  = TPS6586X_SUPPLY##ereg0,                       \
        .enable_bit[0]  = (ebit0),                                      \
        .enable_reg[1]  = TPS6586X_SUPPLY##ereg1,                       \
@@ -230,24 +179,39 @@ static const unsigned int tps6586x_dvm_voltages[] = {
        TPS6586X_REGULATOR_DVM_GOREG(goreg, gobit)                      \
 }
 
+#define TPS6586X_SYS_REGULATOR()                                       \
+{                                                                      \
+       .desc   = {                                                     \
+               .supply_name = "sys",                                   \
+               .name   = "REG-SYS",                                    \
+               .ops    = &tps6586x_sys_regulator_ops,                  \
+               .type   = REGULATOR_VOLTAGE,                            \
+               .id     = TPS6586X_ID_SYS,                              \
+               .owner  = THIS_MODULE,                                  \
+       },                                                              \
+}
+
 static struct tps6586x_regulator tps6586x_regulator[] = {
+       TPS6586X_SYS_REGULATOR(),
        TPS6586X_LDO(LDO_0, "vinldo01", ldo0, SUPPLYV1, 5, 3, ENC, 0, END, 0),
        TPS6586X_LDO(LDO_3, "vinldo23", ldo, SUPPLYV4, 0, 3, ENC, 2, END, 2),
-       TPS6586X_LDO(LDO_5, NULL, ldo, SUPPLYV6, 0, 3, ENE, 6, ENE, 6),
+       TPS6586X_LDO(LDO_5, "REG-SYS", ldo, SUPPLYV6, 0, 3, ENE, 6, ENE, 6),
        TPS6586X_LDO(LDO_6, "vinldo678", ldo, SUPPLYV3, 0, 3, ENC, 4, END, 4),
        TPS6586X_LDO(LDO_7, "vinldo678", ldo, SUPPLYV3, 3, 3, ENC, 5, END, 5),
        TPS6586X_LDO(LDO_8, "vinldo678", ldo, SUPPLYV2, 5, 3, ENC, 6, END, 6),
        TPS6586X_LDO(LDO_9, "vinldo9", ldo, SUPPLYV6, 3, 3, ENE, 7, ENE, 7),
-       TPS6586X_LDO(LDO_RTC, NULL, ldo, SUPPLYV4, 3, 3, V4, 7, V4, 7),
+       TPS6586X_LDO(LDO_RTC, "REG-SYS", ldo, SUPPLYV4, 3, 3, V4, 7, V4, 7),
        TPS6586X_LDO(LDO_1, "vinldo01", dvm, SUPPLYV1, 0, 5, ENC, 1, END, 1),
-       TPS6586X_LDO(SM_2, "sm2", sm2, SUPPLYV2, 0, 5, ENC, 7, END, 7),
+       TPS6586X_LDO(SM_2, "vin-sm2", sm2, SUPPLYV2, 0, 5, ENC, 7, END, 7),
 
        TPS6586X_DVM(LDO_2, "vinldo23", dvm, LDO2BV1, 0, 5, ENA, 3,
                                        ENB, 3, VCC2, 6),
        TPS6586X_DVM(LDO_4, "vinldo4", ldo4, LDO4V1, 0, 5, ENC, 3,
                                        END, 3, VCC1, 6),
-       TPS6586X_DVM(SM_0, "sm0", dvm, SM0V1, 0, 5, ENA, 1, ENB, 1, VCC1, 2),
-       TPS6586X_DVM(SM_1, "sm1", dvm, SM1V1, 0, 5, ENA, 0, ENB, 0, VCC1, 0),
+       TPS6586X_DVM(SM_0, "vin-sm0", dvm, SM0V1, 0, 5, ENA, 1,
+                                       ENB, 1, VCC1, 2),
+       TPS6586X_DVM(SM_1, "vin-sm1", dvm, SM1V1, 0, 5, ENA, 0,
+                                       ENB, 0, VCC1, 0),
 };
 
 /*
index 242fe90dc56502ad5c5e1cc0ced284561b0e6df9..564acae3eae8eabd3de00f15d140ba53177396a7 100644 (file)
@@ -10,6 +10,8 @@
  */
 
 #include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/platform_device.h>
@@ -624,18 +626,9 @@ static int twlfixed_list_voltage(struct regulator_dev *rdev, unsigned index)
        return info->min_mV * 1000;
 }
 
-static int twlfixed_get_voltage(struct regulator_dev *rdev)
-{
-       struct twlreg_info      *info = rdev_get_drvdata(rdev);
-
-       return info->min_mV * 1000;
-}
-
 static struct regulator_ops twl4030fixed_ops = {
        .list_voltage   = twlfixed_list_voltage,
 
-       .get_voltage    = twlfixed_get_voltage,
-
        .enable         = twl4030reg_enable,
        .disable        = twl4030reg_disable,
        .is_enabled     = twl4030reg_is_enabled,
@@ -648,8 +641,6 @@ static struct regulator_ops twl4030fixed_ops = {
 static struct regulator_ops twl6030fixed_ops = {
        .list_voltage   = twlfixed_list_voltage,
 
-       .get_voltage    = twlfixed_get_voltage,
-
        .enable         = twl6030reg_enable,
        .disable        = twl6030reg_disable,
        .is_enabled     = twl6030reg_is_enabled,
@@ -757,37 +748,32 @@ static int twl6030smps_list_voltage(struct regulator_dev *rdev, unsigned index)
        return voltage;
 }
 
-static int
-twl6030smps_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
-                       unsigned int *selector)
+static int twl6030smps_map_voltage(struct regulator_dev *rdev, int min_uV,
+                                  int max_uV)
 {
-       struct twlreg_info      *info = rdev_get_drvdata(rdev);
-       int     vsel = 0;
+       struct twlreg_info *info = rdev_get_drvdata(rdev);
+       int vsel = 0;
 
        switch (info->flags) {
        case 0:
                if (min_uV == 0)
                        vsel = 0;
                else if ((min_uV >= 600000) && (min_uV <= 1300000)) {
-                       int calc_uV;
                        vsel = DIV_ROUND_UP(min_uV - 600000, 12500);
                        vsel++;
-                       calc_uV = twl6030smps_list_voltage(rdev, vsel);
-                       if (calc_uV > max_uV)
-                               return -EINVAL;
                }
                /* Values 1..57 for vsel are linear and can be calculated
                 * values 58..62 are non linear.
                 */
-               else if ((min_uV > 1900000) && (max_uV >= 2100000))
+               else if ((min_uV > 1900000) && (min_uV <= 2100000))
                        vsel = 62;
-               else if ((min_uV > 1800000) && (max_uV >= 1900000))
+               else if ((min_uV > 1800000) && (min_uV <= 1900000))
                        vsel = 61;
-               else if ((min_uV > 1500000) && (max_uV >= 1800000))
+               else if ((min_uV > 1500000) && (min_uV <= 1800000))
                        vsel = 60;
-               else if ((min_uV > 1350000) && (max_uV >= 1500000))
+               else if ((min_uV > 1350000) && (min_uV <= 1500000))
                        vsel = 59;
-               else if ((min_uV > 1300000) && (max_uV >= 1350000))
+               else if ((min_uV > 1300000) && (min_uV <= 1350000))
                        vsel = 58;
                else
                        return -EINVAL;
@@ -796,25 +782,21 @@ twl6030smps_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
                if (min_uV == 0)
                        vsel = 0;
                else if ((min_uV >= 700000) && (min_uV <= 1420000)) {
-                       int calc_uV;
                        vsel = DIV_ROUND_UP(min_uV - 700000, 12500);
                        vsel++;
-                       calc_uV = twl6030smps_list_voltage(rdev, vsel);
-                       if (calc_uV > max_uV)
-                               return -EINVAL;
                }
                /* Values 1..57 for vsel are linear and can be calculated
                 * values 58..62 are non linear.
                 */
-               else if ((min_uV > 1900000) && (max_uV >= 2100000))
+               else if ((min_uV > 1900000) && (min_uV <= 2100000))
                        vsel = 62;
-               else if ((min_uV > 1800000) && (max_uV >= 1900000))
+               else if ((min_uV > 1800000) && (min_uV <= 1900000))
                        vsel = 61;
-               else if ((min_uV > 1350000) && (max_uV >= 1800000))
+               else if ((min_uV > 1350000) && (min_uV <= 1800000))
                        vsel = 60;
-               else if ((min_uV > 1350000) && (max_uV >= 1500000))
+               else if ((min_uV > 1350000) && (min_uV <= 1500000))
                        vsel = 59;
-               else if ((min_uV > 1300000) && (max_uV >= 1350000))
+               else if ((min_uV > 1300000) && (min_uV <= 1350000))
                        vsel = 58;
                else
                        return -EINVAL;
@@ -830,17 +812,23 @@ twl6030smps_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV,
        case SMPS_OFFSET_EN|SMPS_EXTENDED_EN:
                if (min_uV == 0) {
                        vsel = 0;
-               } else if ((min_uV >= 2161000) && (max_uV <= 4321000)) {
+               } else if ((min_uV >= 2161000) && (min_uV <= 4321000)) {
                        vsel = DIV_ROUND_UP(min_uV - 2161000, 38600);
                        vsel++;
                }
                break;
        }
 
-       *selector = vsel;
+       return vsel;
+}
+
+static int twl6030smps_set_voltage_sel(struct regulator_dev *rdev,
+                                      unsigned int selector)
+{
+       struct twlreg_info *info = rdev_get_drvdata(rdev);
 
        return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE_SMPS,
-                                                       vsel);
+                           selector);
 }
 
 static int twl6030smps_get_voltage_sel(struct regulator_dev *rdev)
@@ -852,8 +840,9 @@ static int twl6030smps_get_voltage_sel(struct regulator_dev *rdev)
 
 static struct regulator_ops twlsmps_ops = {
        .list_voltage           = twl6030smps_list_voltage,
+       .map_voltage            = twl6030smps_map_voltage,
 
-       .set_voltage            = twl6030smps_set_voltage,
+       .set_voltage_sel        = twl6030smps_set_voltage_sel,
        .get_voltage_sel        = twl6030smps_get_voltage_sel,
 
        .enable                 = twl6030reg_enable,
@@ -876,7 +865,7 @@ static struct regulator_ops twlsmps_ops = {
                        0x0, TWL6030, twl6030fixed_ops)
 
 #define TWL4030_ADJUSTABLE_LDO(label, offset, num, turnon_delay, remap_conf) \
-static struct twlreg_info TWL4030_INFO_##label = { \
+static const struct twlreg_info TWL4030_INFO_##label = { \
        .base = offset, \
        .id = num, \
        .table_len = ARRAY_SIZE(label##_VSEL_table), \
@@ -894,7 +883,7 @@ static struct twlreg_info TWL4030_INFO_##label = { \
        }
 
 #define TWL4030_ADJUSTABLE_SMPS(label, offset, num, turnon_delay, remap_conf) \
-static struct twlreg_info TWL4030_INFO_##label = { \
+static const struct twlreg_info TWL4030_INFO_##label = { \
        .base = offset, \
        .id = num, \
        .remap = remap_conf, \
@@ -909,7 +898,7 @@ static struct twlreg_info TWL4030_INFO_##label = { \
        }
 
 #define TWL6030_ADJUSTABLE_SMPS(label) \
-static struct twlreg_info TWL6030_INFO_##label = { \
+static const struct twlreg_info TWL6030_INFO_##label = { \
        .desc = { \
                .name = #label, \
                .id = TWL6030_REG_##label, \
@@ -920,7 +909,7 @@ static struct twlreg_info TWL6030_INFO_##label = { \
        }
 
 #define TWL6030_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts) \
-static struct twlreg_info TWL6030_INFO_##label = { \
+static const struct twlreg_info TWL6030_INFO_##label = { \
        .base = offset, \
        .min_mV = min_mVolts, \
        .max_mV = max_mVolts, \
@@ -935,7 +924,7 @@ static struct twlreg_info TWL6030_INFO_##label = { \
        }
 
 #define TWL6025_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts) \
-static struct twlreg_info TWL6025_INFO_##label = { \
+static const struct twlreg_info TWL6025_INFO_##label = { \
        .base = offset, \
        .min_mV = min_mVolts, \
        .max_mV = max_mVolts, \
@@ -951,7 +940,7 @@ static struct twlreg_info TWL6025_INFO_##label = { \
 
 #define TWL_FIXED_LDO(label, offset, mVolts, num, turnon_delay, remap_conf, \
                family, operations) \
-static struct twlreg_info TWLFIXED_INFO_##label = { \
+static const struct twlreg_info TWLFIXED_INFO_##label = { \
        .base = offset, \
        .id = num, \
        .min_mV = mVolts, \
@@ -981,7 +970,7 @@ static struct twlreg_info TWLRES_INFO_##label = { \
        }
 
 #define TWL6025_ADJUSTABLE_SMPS(label, offset) \
-static struct twlreg_info TWLSMPS_INFO_##label = { \
+static const struct twlreg_info TWLSMPS_INFO_##label = { \
        .base = offset, \
        .min_mV = 600, \
        .max_mV = 2100, \
@@ -1037,7 +1026,7 @@ TWL6025_ADJUSTABLE_LDO(LDO7, 0x74, 1000, 3300);
 TWL6025_ADJUSTABLE_LDO(LDO6, 0x60, 1000, 3300);
 TWL6025_ADJUSTABLE_LDO(LDOLN, 0x64, 1000, 3300);
 TWL6025_ADJUSTABLE_LDO(LDOUSB, 0x70, 1000, 3300);
-TWL4030_FIXED_LDO(VINTANA2, 0x3f, 1500, 11, 100, 0x08);
+TWL4030_FIXED_LDO(VINTANA1, 0x3f, 1500, 11, 100, 0x08);
 TWL4030_FIXED_LDO(VINTDIG, 0x47, 1500, 13, 100, 0x08);
 TWL4030_FIXED_LDO(VUSB1V5, 0x71, 1500, 17, 100, 0x08);
 TWL4030_FIXED_LDO(VUSB1V8, 0x74, 1800, 18, 100, 0x08);
@@ -1048,7 +1037,6 @@ TWL6030_FIXED_LDO(VDAC, 0x64, 1800, 0);
 TWL6030_FIXED_LDO(VUSB, 0x70, 3300, 0);
 TWL6030_FIXED_LDO(V1V8, 0x16, 1800, 0);
 TWL6030_FIXED_LDO(V2V1, 0x1c, 2100, 0);
-TWL6030_FIXED_RESOURCE(CLK32KG, 0x8C, 0);
 TWL6025_ADJUSTABLE_SMPS(SMPS3, 0x34);
 TWL6025_ADJUSTABLE_SMPS(SMPS4, 0x10);
 TWL6025_ADJUSTABLE_SMPS(VIO, 0x16);
@@ -1117,7 +1105,7 @@ static const struct of_device_id twl_of_match[] __devinitconst = {
        TWL6025_OF_MATCH("ti,twl6025-ldo6", LDO6),
        TWL6025_OF_MATCH("ti,twl6025-ldoln", LDOLN),
        TWL6025_OF_MATCH("ti,twl6025-ldousb", LDOUSB),
-       TWLFIXED_OF_MATCH("ti,twl4030-vintana2", VINTANA2),
+       TWLFIXED_OF_MATCH("ti,twl4030-vintana1", VINTANA1),
        TWLFIXED_OF_MATCH("ti,twl4030-vintdig", VINTDIG),
        TWLFIXED_OF_MATCH("ti,twl4030-vusb1v5", VUSB1V5),
        TWLFIXED_OF_MATCH("ti,twl4030-vusb1v8", VUSB1V8),
@@ -1139,6 +1127,7 @@ static int __devinit twlreg_probe(struct platform_device *pdev)
 {
        int                             i, id;
        struct twlreg_info              *info;
+       const struct twlreg_info        *template;
        struct regulator_init_data      *initdata;
        struct regulation_constraints   *c;
        struct regulator_dev            *rdev;
@@ -1148,17 +1137,17 @@ static int __devinit twlreg_probe(struct platform_device *pdev)
 
        match = of_match_device(twl_of_match, &pdev->dev);
        if (match) {
-               info = match->data;
-               id = info->desc.id;
+               template = match->data;
+               id = template->desc.id;
                initdata = of_get_regulator_init_data(&pdev->dev,
                                                      pdev->dev.of_node);
                drvdata = NULL;
        } else {
                id = pdev->id;
                initdata = pdev->dev.platform_data;
-               for (i = 0, info = NULL; i < ARRAY_SIZE(twl_of_match); i++) {
-                       info = twl_of_match[i].data;
-                       if (info && info->desc.id == id)
+               for (i = 0, template = NULL; i < ARRAY_SIZE(twl_of_match); i++) {
+                       template = twl_of_match[i].data;
+                       if (template && template->desc.id == id)
                                break;
                }
                if (i == ARRAY_SIZE(twl_of_match))
@@ -1169,12 +1158,16 @@ static int __devinit twlreg_probe(struct platform_device *pdev)
                        return -EINVAL;
        }
 
-       if (!info)
+       if (!template)
                return -ENODEV;
 
        if (!initdata)
                return -EINVAL;
 
+       info = kmemdup(template, sizeof (*info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
        if (drvdata) {
                /* copy the driver data into regulator data */
                info->features = drvdata->features;
@@ -1235,6 +1228,7 @@ static int __devinit twlreg_probe(struct platform_device *pdev)
        if (IS_ERR(rdev)) {
                dev_err(&pdev->dev, "can't register %s, %ld\n",
                                info->desc.name, PTR_ERR(rdev));
+               kfree(info);
                return PTR_ERR(rdev);
        }
        platform_set_drvdata(pdev, rdev);
@@ -1256,7 +1250,11 @@ static int __devinit twlreg_probe(struct platform_device *pdev)
 
 static int __devexit twlreg_remove(struct platform_device *pdev)
 {
-       regulator_unregister(platform_get_drvdata(pdev));
+       struct regulator_dev *rdev = platform_get_drvdata(pdev);
+       struct twlreg_info *info = rdev->reg_data;
+
+       regulator_unregister(rdev);
+       kfree(info);
        return 0;
 }
 
index 7413885be01ba5907117c4c95d89df1a4129924b..90cbcc683704b748c032653f5827e2704b95e8f2 100644 (file)
@@ -339,16 +339,15 @@ static int wm831x_buckv_set_current_limit(struct regulator_dev *rdev,
        u16 reg = dcdc->base + WM831X_DCDC_CONTROL_2;
        int i;
 
-       for (i = 0; i < ARRAY_SIZE(wm831x_dcdc_ilim); i++) {
+       for (i = ARRAY_SIZE(wm831x_dcdc_ilim) - 1; i >= 0; i--) {
                if ((min_uA <= wm831x_dcdc_ilim[i]) &&
                    (wm831x_dcdc_ilim[i] <= max_uA))
-                       break;
+                       return wm831x_set_bits(wm831x, reg,
+                                              WM831X_DC1_HC_THR_MASK,
+                                               i << WM831X_DC1_HC_THR_SHIFT);
        }
-       if (i == ARRAY_SIZE(wm831x_dcdc_ilim))
-               return -EINVAL;
 
-       return wm831x_set_bits(wm831x, reg, WM831X_DC1_HC_THR_MASK,
-                              i << WM831X_DC1_HC_THR_SHIFT);
+       return -EINVAL;
 }
 
 static int wm831x_buckv_get_current_limit(struct regulator_dev *rdev)
index 5cb70ca1e98d1f1843347fe14d7291d7a041eceb..56a6de3dd8834022fd68add8feea2fa43ce283f2 100644 (file)
@@ -205,6 +205,8 @@ static int wm831x_gp_ldo_get_status(struct regulator_dev *rdev)
 
        /* Is it reporting under voltage? */
        ret = wm831x_reg_read(wm831x, WM831X_LDO_UV_STATUS);
+       if (ret < 0)
+               return ret;
        if (ret & mask)
                return REGULATOR_STATUS_ERROR;
 
@@ -469,6 +471,8 @@ static int wm831x_aldo_get_status(struct regulator_dev *rdev)
 
        /* Is it reporting under voltage? */
        ret = wm831x_reg_read(wm831x, WM831X_LDO_UV_STATUS);
+       if (ret < 0)
+               return ret;
        if (ret & mask)
                return REGULATOR_STATUS_ERROR;
 
index 9035dd0536118df253769b6e7e5847621ebd9a5e..27c746ef06364d2f02e95b8928ed748a31de6b1d 100644 (file)
@@ -120,13 +120,8 @@ static int wm8400_dcdc_set_mode(struct regulator_dev *dev, unsigned int mode)
 
        case REGULATOR_MODE_IDLE:
                /* Datasheet: standby */
-               ret = wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
-                                     WM8400_DC1_ACTIVE, 0);
-               if (ret != 0)
-                       return ret;
                return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
-                                      WM8400_DC1_SLEEP, 0);
-
+                                      WM8400_DC1_ACTIVE | WM8400_DC1_SLEEP, 0);
        default:
                return -EINVAL;
        }
index eb415bd7649418f1d91b5c45b98fe9411f5171d3..9592b936b71bca1987d19aceba0f6e8b20b165b9 100644 (file)
@@ -582,6 +582,7 @@ enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer)
 void rtc_update_irq(struct rtc_device *rtc,
                unsigned long num, unsigned long events)
 {
+       pm_stay_awake(rtc->dev.parent);
        schedule_work(&rtc->irqwork);
 }
 EXPORT_SYMBOL_GPL(rtc_update_irq);
@@ -844,6 +845,7 @@ void rtc_timer_do_work(struct work_struct *work)
 
        mutex_lock(&rtc->ops_lock);
 again:
+       pm_relax(rtc->dev.parent);
        __rtc_read_time(rtc, &tm);
        now = rtc_tm_to_ktime(tm);
        while ((next = timerqueue_getnext(&rtc->timerqueue))) {
index 132333d754085d6b06a9c096444a95b708e45893..4267789ca9959413e90df5ea053154e07481d3ce 100644 (file)
@@ -568,7 +568,6 @@ static irqreturn_t cmos_interrupt(int irq, void *p)
                hpet_mask_rtc_irq_bit(RTC_AIE);
 
                CMOS_READ(RTC_INTR_FLAGS);
-               pm_wakeup_event(cmos_rtc.dev, 0);
        }
        spin_unlock(&rtc_lock);
 
index 0075c8fd93d81399f2ad59ab6cd86e0560c228a8..f771b2ee4b180e6a046d947c147a54276eb45188 100644 (file)
@@ -27,6 +27,8 @@
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <mach/hardware.h>
 
@@ -396,6 +398,14 @@ static int __exit pxa_rtc_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_OF
+static struct of_device_id pxa_rtc_dt_ids[] = {
+       { .compatible = "marvell,pxa-rtc" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, pxa_rtc_dt_ids);
+#endif
+
 #ifdef CONFIG_PM
 static int pxa_rtc_suspend(struct device *dev)
 {
@@ -425,6 +435,7 @@ static struct platform_driver pxa_rtc_driver = {
        .remove         = __exit_p(pxa_rtc_remove),
        .driver         = {
                .name   = "pxa-rtc",
+               .of_match_table = of_match_ptr(pxa_rtc_dt_ids),
 #ifdef CONFIG_PM
                .pm     = &pxa_rtc_pm_ops,
 #endif
index 6c0116d48c74e386ff2de99d9cc86076c69b6bff..9ffb6d5f17aa0523473215db57edeccda1391a70 100644 (file)
@@ -716,10 +716,17 @@ static int raw3215_probe (struct ccw_device *cdev)
 static void raw3215_remove (struct ccw_device *cdev)
 {
        struct raw3215_info *raw;
+       unsigned int line;
 
        ccw_device_set_offline(cdev);
        raw = dev_get_drvdata(&cdev->dev);
        if (raw) {
+               spin_lock(&raw3215_device_lock);
+               for (line = 0; line < NR_3215; line++)
+                       if (raw3215[line] == raw)
+                               break;
+               raw3215[line] = NULL;
+               spin_unlock(&raw3215_device_lock);
                dev_set_drvdata(&cdev->dev, NULL);
                raw3215_free_info(raw);
        }
@@ -935,6 +942,19 @@ static int __init con3215_init(void)
 console_initcall(con3215_init);
 #endif
 
+static int tty3215_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+       struct raw3215_info *raw;
+
+       raw = raw3215[tty->index];
+       if (raw == NULL)
+               return -ENODEV;
+
+       tty->driver_data = raw;
+
+       return tty_port_install(&raw->port, driver, tty);
+}
+
 /*
  * tty3215_open
  *
@@ -942,14 +962,9 @@ console_initcall(con3215_init);
  */
 static int tty3215_open(struct tty_struct *tty, struct file * filp)
 {
-       struct raw3215_info *raw;
+       struct raw3215_info *raw = tty->driver_data;
        int retval;
 
-       raw = raw3215[tty->index];
-       if (raw == NULL)
-               return -ENODEV;
-
-       tty->driver_data = raw;
        tty_port_tty_set(&raw->port, tty);
 
        tty->low_latency = 0;  /* don't use bottom half for pushing chars */
@@ -1110,6 +1125,7 @@ static void tty3215_start(struct tty_struct *tty)
 }
 
 static const struct tty_operations tty3215_ops = {
+       .install = tty3215_install,
        .open = tty3215_open,
        .close = tty3215_close,
        .write = tty3215_write,
index 6a6f76bf6e3dad4fae79fedc125bb39b7678b79a..b1032931a1c41237766eaf6c38d7e5032e71e33d 100644 (file)
@@ -242,11 +242,13 @@ int sclp_sdias_copy(void *dest, int start_blk, int nr_blks)
        switch (sdias_evbuf.event_status) {
                case EVSTATE_ALL_STORED:
                        TRACE("all stored\n");
+                       break;
                case EVSTATE_PART_STORED:
                        TRACE("part stored: %i\n", sdias_evbuf.blk_cnt);
                        break;
                case EVSTATE_NO_DATA:
                        TRACE("no data\n");
+                       /* fall through */
                default:
                        pr_err("Error from SCLP while copying hsa. "
                               "Event status = %x\n",
index 0792c85baafebdefcad5888423ff5b0bc19bee35..30ec09e3d037c7c25cfb382fd89d7c1c742f038a 100644 (file)
@@ -567,6 +567,7 @@ sclp_tty_init(void)
        driver->init_termios.c_lflag = ISIG | ECHO;
        driver->flags = TTY_DRIVER_REAL_RAW;
        tty_set_operations(driver, &sclp_ops);
+       tty_port_link_device(&sclp_port, driver, 0);
        rc = tty_register_driver(driver);
        if (rc) {
                put_tty_driver(driver);
index edfc0fd73dc682753ab3b1ac09c43fc8b0509de8..7e60f3d2f3f9cf27de4e5c4c4ae9d743503a68ce 100644 (file)
@@ -691,6 +691,7 @@ static int __init sclp_vt220_tty_init(void)
        driver->init_termios = tty_std_termios;
        driver->flags = TTY_DRIVER_REAL_RAW;
        tty_set_operations(driver, &sclp_vt220_ops);
+       tty_port_link_device(&sclp_vt220_port, driver, 0);
 
        rc = tty_register_driver(driver);
        if (rc)
index 1928f3458d10f197bb15b7a75da7d685b33da4e1..482ee028f842032337186c33775471103e61b969 100644 (file)
@@ -842,17 +842,14 @@ static struct raw3270_fn tty3270_fn = {
 };
 
 /*
- * This routine is called whenever a 3270 tty is opened.
+ * This routine is called whenever a 3270 tty is opened first time.
  */
-static int
-tty3270_open(struct tty_struct *tty, struct file * filp)
+static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty)
 {
        struct raw3270_view *view;
        struct tty3270 *tp;
        int i, rc;
 
-       if (tty->count > 1)
-               return 0;
        /* Check if the tty3270 is already there. */
        view = raw3270_find_view(&tty3270_fn,
                                  tty->index + RAW3270_FIRSTMINOR);
@@ -865,7 +862,7 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
                /* why to reassign? */
                tty_port_tty_set(&tp->port, tty);
                tp->inattr = TF_INPUT;
-               return 0;
+               return tty_port_install(&tp->port, driver, tty);
        }
        if (tty3270_max_index < tty->index + 1)
                tty3270_max_index = tty->index + 1;
@@ -895,7 +892,6 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
 
        tty_port_tty_set(&tp->port, tty);
        tty->low_latency = 0;
-       tty->driver_data = tp;
        tty->winsize.ws_row = tp->view.rows - 2;
        tty->winsize.ws_col = tp->view.cols;
 
@@ -915,6 +911,15 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
        kbd_ascebc(tp->kbd, tp->view.ascebc);
 
        raw3270_activate_view(&tp->view);
+
+       rc = tty_port_install(&tp->port, driver, tty);
+       if (rc) {
+               raw3270_put_view(&tp->view);
+               return rc;
+       }
+
+       tty->driver_data = tp;
+
        return 0;
 }
 
@@ -932,10 +937,17 @@ tty3270_close(struct tty_struct *tty, struct file * filp)
        if (tp) {
                tty->driver_data = NULL;
                tty_port_tty_set(&tp->port, NULL);
-               raw3270_put_view(&tp->view);
        }
 }
 
+static void tty3270_cleanup(struct tty_struct *tty)
+{
+       struct tty3270 *tp = tty->driver_data;
+
+       if (tp)
+               raw3270_put_view(&tp->view);
+}
+
 /*
  * We always have room.
  */
@@ -1737,7 +1749,8 @@ static long tty3270_compat_ioctl(struct tty_struct *tty,
 #endif
 
 static const struct tty_operations tty3270_ops = {
-       .open = tty3270_open,
+       .install = tty3270_install,
+       .cleanup = tty3270_cleanup,
        .close = tty3270_close,
        .write = tty3270_write,
        .put_char = tty3270_put_char,
@@ -1781,7 +1794,7 @@ static int __init tty3270_init(void)
        driver->type = TTY_DRIVER_TYPE_SYSTEM;
        driver->subtype = SYSTEM_TYPE_TTY;
        driver->init_termios = tty_std_termios;
-       driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_DYNAMIC_DEV;
+       driver->flags = TTY_DRIVER_RESET_TERMIOS;
        tty_set_operations(driver, &tty3270_ops);
        ret = tty_register_driver(driver);
        if (ret) {
@@ -1800,6 +1813,7 @@ tty3270_exit(void)
        driver = tty3270_driver;
        tty3270_driver = NULL;
        tty_unregister_driver(driver);
+       put_tty_driver(driver);
        tty3270_del_views();
 }
 
index 467dc38246f93317221239e45a798c867bd1cdb0..07b14ba6906ab53578fc5c1a28d2b0464ec68b83 100644 (file)
@@ -565,6 +565,23 @@ static void ipr_trc_hook(struct ipr_cmnd *ipr_cmd,
 #define ipr_trc_hook(ipr_cmd, type, add_data) do { } while(0)
 #endif
 
+/**
+ * ipr_lock_and_done - Acquire lock and complete command
+ * @ipr_cmd:   ipr command struct
+ *
+ * Return value:
+ *     none
+ **/
+static void ipr_lock_and_done(struct ipr_cmnd *ipr_cmd)
+{
+       unsigned long lock_flags;
+       struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+
+       spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+       ipr_cmd->done(ipr_cmd);
+       spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+}
+
 /**
  * ipr_reinit_ipr_cmnd - Re-initialize an IPR Cmnd block for reuse
  * @ipr_cmd:   ipr command struct
@@ -611,33 +628,49 @@ static void ipr_reinit_ipr_cmnd(struct ipr_cmnd *ipr_cmd)
  * Return value:
  *     none
  **/
-static void ipr_init_ipr_cmnd(struct ipr_cmnd *ipr_cmd)
+static void ipr_init_ipr_cmnd(struct ipr_cmnd *ipr_cmd,
+                             void (*fast_done) (struct ipr_cmnd *))
 {
        ipr_reinit_ipr_cmnd(ipr_cmd);
        ipr_cmd->u.scratch = 0;
        ipr_cmd->sibling = NULL;
+       ipr_cmd->fast_done = fast_done;
        init_timer(&ipr_cmd->timer);
 }
 
 /**
- * ipr_get_free_ipr_cmnd - Get a free IPR Cmnd block
+ * __ipr_get_free_ipr_cmnd - Get a free IPR Cmnd block
  * @ioa_cfg:   ioa config struct
  *
  * Return value:
  *     pointer to ipr command struct
  **/
 static
-struct ipr_cmnd *ipr_get_free_ipr_cmnd(struct ipr_ioa_cfg *ioa_cfg)
+struct ipr_cmnd *__ipr_get_free_ipr_cmnd(struct ipr_ioa_cfg *ioa_cfg)
 {
        struct ipr_cmnd *ipr_cmd;
 
        ipr_cmd = list_entry(ioa_cfg->free_q.next, struct ipr_cmnd, queue);
        list_del(&ipr_cmd->queue);
-       ipr_init_ipr_cmnd(ipr_cmd);
 
        return ipr_cmd;
 }
 
+/**
+ * ipr_get_free_ipr_cmnd - Get a free IPR Cmnd block and initialize it
+ * @ioa_cfg:   ioa config struct
+ *
+ * Return value:
+ *     pointer to ipr command struct
+ **/
+static
+struct ipr_cmnd *ipr_get_free_ipr_cmnd(struct ipr_ioa_cfg *ioa_cfg)
+{
+       struct ipr_cmnd *ipr_cmd = __ipr_get_free_ipr_cmnd(ioa_cfg);
+       ipr_init_ipr_cmnd(ipr_cmd, ipr_lock_and_done);
+       return ipr_cmd;
+}
+
 /**
  * ipr_mask_and_clear_interrupts - Mask all and clear specified interrupts
  * @ioa_cfg:   ioa config struct
@@ -5116,8 +5149,9 @@ static irqreturn_t ipr_isr(int irq, void *devp)
        u16 cmd_index;
        int num_hrrq = 0;
        int irq_none = 0;
-       struct ipr_cmnd *ipr_cmd;
+       struct ipr_cmnd *ipr_cmd, *temp;
        irqreturn_t rc = IRQ_NONE;
+       LIST_HEAD(doneq);
 
        spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
 
@@ -5138,8 +5172,8 @@ static irqreturn_t ipr_isr(int irq, void *devp)
 
                        if (unlikely(cmd_index >= IPR_NUM_CMD_BLKS)) {
                                ipr_isr_eh(ioa_cfg, "Invalid response handle from IOA");
-                               spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
-                               return IRQ_HANDLED;
+                               rc = IRQ_HANDLED;
+                               goto unlock_out;
                        }
 
                        ipr_cmd = ioa_cfg->ipr_cmnd_list[cmd_index];
@@ -5148,9 +5182,7 @@ static irqreturn_t ipr_isr(int irq, void *devp)
 
                        ipr_trc_hook(ipr_cmd, IPR_TRACE_FINISH, ioasc);
 
-                       list_del(&ipr_cmd->queue);
-                       del_timer(&ipr_cmd->timer);
-                       ipr_cmd->done(ipr_cmd);
+                       list_move_tail(&ipr_cmd->queue, &doneq);
 
                        rc = IRQ_HANDLED;
 
@@ -5180,8 +5212,8 @@ static irqreturn_t ipr_isr(int irq, void *devp)
                } else if (num_hrrq == IPR_MAX_HRRQ_RETRIES &&
                           int_reg & IPR_PCII_HRRQ_UPDATED) {
                        ipr_isr_eh(ioa_cfg, "Error clearing HRRQ");
-                       spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
-                       return IRQ_HANDLED;
+                       rc = IRQ_HANDLED;
+                       goto unlock_out;
                } else
                        break;
        }
@@ -5189,7 +5221,14 @@ static irqreturn_t ipr_isr(int irq, void *devp)
        if (unlikely(rc == IRQ_NONE))
                rc = ipr_handle_other_interrupt(ioa_cfg, int_reg);
 
+unlock_out:
        spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+       list_for_each_entry_safe(ipr_cmd, temp, &doneq, queue) {
+               list_del(&ipr_cmd->queue);
+               del_timer(&ipr_cmd->timer);
+               ipr_cmd->fast_done(ipr_cmd);
+       }
+
        return rc;
 }
 
@@ -5770,21 +5809,28 @@ static void ipr_scsi_done(struct ipr_cmnd *ipr_cmd)
        struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
        struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd;
        u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc);
+       unsigned long lock_flags;
 
        scsi_set_resid(scsi_cmd, be32_to_cpu(ipr_cmd->s.ioasa.hdr.residual_data_len));
 
        if (likely(IPR_IOASC_SENSE_KEY(ioasc) == 0)) {
-               scsi_dma_unmap(ipr_cmd->scsi_cmd);
+               scsi_dma_unmap(scsi_cmd);
+
+               spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
                list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
                scsi_cmd->scsi_done(scsi_cmd);
-       } else
+               spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+       } else {
+               spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
                ipr_erp_start(ioa_cfg, ipr_cmd);
+               spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+       }
 }
 
 /**
  * ipr_queuecommand - Queue a mid-layer request
+ * @shost:             scsi host struct
  * @scsi_cmd:  scsi command struct
- * @done:              done function
  *
  * This function queues a request generated by the mid-layer.
  *
@@ -5793,61 +5839,58 @@ static void ipr_scsi_done(struct ipr_cmnd *ipr_cmd)
  *     SCSI_MLQUEUE_DEVICE_BUSY if device is busy
  *     SCSI_MLQUEUE_HOST_BUSY if host is busy
  **/
-static int ipr_queuecommand_lck(struct scsi_cmnd *scsi_cmd,
-                           void (*done) (struct scsi_cmnd *))
+static int ipr_queuecommand(struct Scsi_Host *shost,
+                           struct scsi_cmnd *scsi_cmd)
 {
        struct ipr_ioa_cfg *ioa_cfg;
        struct ipr_resource_entry *res;
        struct ipr_ioarcb *ioarcb;
        struct ipr_cmnd *ipr_cmd;
+       unsigned long lock_flags;
        int rc = 0;
 
-       scsi_cmd->scsi_done = done;
-       ioa_cfg = (struct ipr_ioa_cfg *)scsi_cmd->device->host->hostdata;
-       res = scsi_cmd->device->hostdata;
+       ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata;
+
+       spin_lock_irqsave(shost->host_lock, lock_flags);
        scsi_cmd->result = (DID_OK << 16);
+       res = scsi_cmd->device->hostdata;
 
        /*
         * We are currently blocking all devices due to a host reset
         * We have told the host to stop giving us new requests, but
         * ERP ops don't count. FIXME
         */
-       if (unlikely(!ioa_cfg->allow_cmds && !ioa_cfg->ioa_is_dead))
+       if (unlikely(!ioa_cfg->allow_cmds && !ioa_cfg->ioa_is_dead)) {
+               spin_unlock_irqrestore(shost->host_lock, lock_flags);
                return SCSI_MLQUEUE_HOST_BUSY;
+       }
 
        /*
         * FIXME - Create scsi_set_host_offline interface
         *  and the ioa_is_dead check can be removed
         */
        if (unlikely(ioa_cfg->ioa_is_dead || !res)) {
-               memset(scsi_cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
-               scsi_cmd->result = (DID_NO_CONNECT << 16);
-               scsi_cmd->scsi_done(scsi_cmd);
-               return 0;
+               spin_unlock_irqrestore(shost->host_lock, lock_flags);
+               goto err_nodev;
        }
 
        if (ipr_is_gata(res) && res->sata_port)
                return ata_sas_queuecmd(scsi_cmd, res->sata_port->ap);
 
-       ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
+       ipr_cmd = __ipr_get_free_ipr_cmnd(ioa_cfg);
+       spin_unlock_irqrestore(shost->host_lock, lock_flags);
+
+       ipr_init_ipr_cmnd(ipr_cmd, ipr_scsi_done);
        ioarcb = &ipr_cmd->ioarcb;
-       list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q);
 
        memcpy(ioarcb->cmd_pkt.cdb, scsi_cmd->cmnd, scsi_cmd->cmd_len);
        ipr_cmd->scsi_cmd = scsi_cmd;
-       ioarcb->res_handle = res->res_handle;
-       ipr_cmd->done = ipr_scsi_done;
-       ipr_trc_hook(ipr_cmd, IPR_TRACE_START, IPR_GET_RES_PHYS_LOC(res));
+       ipr_cmd->done = ipr_scsi_eh_done;
 
        if (ipr_is_gscsi(res) || ipr_is_vset_device(res)) {
                if (scsi_cmd->underflow == 0)
                        ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_ULEN_CHK;
 
-               if (res->needs_sync_complete) {
-                       ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_SYNC_COMPLETE;
-                       res->needs_sync_complete = 0;
-               }
-
                ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_LINK_DESC;
                if (ipr_is_gscsi(res))
                        ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_DELAY_AFTER_RST;
@@ -5866,16 +5909,41 @@ static int ipr_queuecommand_lck(struct scsi_cmnd *scsi_cmd,
                        rc = ipr_build_ioadl(ioa_cfg, ipr_cmd);
        }
 
-       if (unlikely(rc != 0)) {
-               list_move_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
+       spin_lock_irqsave(shost->host_lock, lock_flags);
+       if (unlikely(rc || (!ioa_cfg->allow_cmds && !ioa_cfg->ioa_is_dead))) {
+               list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
+               spin_unlock_irqrestore(shost->host_lock, lock_flags);
+               if (!rc)
+                       scsi_dma_unmap(scsi_cmd);
                return SCSI_MLQUEUE_HOST_BUSY;
        }
 
+       if (unlikely(ioa_cfg->ioa_is_dead)) {
+               list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
+               spin_unlock_irqrestore(shost->host_lock, lock_flags);
+               scsi_dma_unmap(scsi_cmd);
+               goto err_nodev;
+       }
+
+       ioarcb->res_handle = res->res_handle;
+       if (res->needs_sync_complete) {
+               ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_SYNC_COMPLETE;
+               res->needs_sync_complete = 0;
+       }
+       list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q);
+       ipr_trc_hook(ipr_cmd, IPR_TRACE_START, IPR_GET_RES_PHYS_LOC(res));
        ipr_send_command(ipr_cmd);
+       spin_unlock_irqrestore(shost->host_lock, lock_flags);
        return 0;
-}
 
-static DEF_SCSI_QCMD(ipr_queuecommand)
+err_nodev:
+       spin_lock_irqsave(shost->host_lock, lock_flags);
+       memset(scsi_cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+       scsi_cmd->result = (DID_NO_CONNECT << 16);
+       scsi_cmd->scsi_done(scsi_cmd);
+       spin_unlock_irqrestore(shost->host_lock, lock_flags);
+       return 0;
+}
 
 /**
  * ipr_ioctl - IOCTL handler
@@ -8775,8 +8843,7 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
 
        ioa_cfg = (struct ipr_ioa_cfg *)host->hostdata;
        memset(ioa_cfg, 0, sizeof(struct ipr_ioa_cfg));
-       ata_host_init(&ioa_cfg->ata_host, &pdev->dev,
-                     sata_port_info.flags, &ipr_sata_ops);
+       ata_host_init(&ioa_cfg->ata_host, &pdev->dev, &ipr_sata_ops);
 
        ioa_cfg->ipr_chip = ipr_get_chip_info(dev_id);
 
index 153b8bd91d1ef825952ec70fec861fea0e8d5fea..c8a137f83bb13e1dbd9d3ceb1478c7fa29e76177 100644 (file)
@@ -38,8 +38,8 @@
 /*
  * Literals
  */
-#define IPR_DRIVER_VERSION "2.5.3"
-#define IPR_DRIVER_DATE "(March 10, 2012)"
+#define IPR_DRIVER_VERSION "2.5.4"
+#define IPR_DRIVER_DATE "(July 11, 2012)"
 
 /*
  * IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding
@@ -1525,6 +1525,7 @@ struct ipr_cmnd {
        struct ata_queued_cmd *qc;
        struct completion completion;
        struct timer_list timer;
+       void (*fast_done) (struct ipr_cmnd *);
        void (*done) (struct ipr_cmnd *);
        int (*job_step) (struct ipr_cmnd *);
        int (*job_step_failed) (struct ipr_cmnd *);
index 45385f531649d7c4724e85145c0549e703098588..4a095f3a595060243e85ee69d3ef10165c007fb3 100644 (file)
@@ -1044,7 +1044,7 @@ static enum sci_status sci_controller_start(struct isci_host *ihost,
        return SCI_SUCCESS;
 }
 
-void isci_host_scan_start(struct Scsi_Host *shost)
+void isci_host_start(struct Scsi_Host *shost)
 {
        struct isci_host *ihost = SHOST_TO_SAS_HA(shost)->lldd_ha;
        unsigned long tmo = sci_controller_get_suggested_start_timeout(ihost);
@@ -1973,7 +1973,7 @@ static void sci_controller_afe_initialization(struct isci_host *ihost)
        }
 
        for (phy_id = 0; phy_id < SCI_MAX_PHYS; phy_id++) {
-               struct scu_afe_transceiver *xcvr = &afe->scu_afe_xcvr[phy_id];
+               struct scu_afe_transceiver __iomem *xcvr = &afe->scu_afe_xcvr[phy_id];
                const struct sci_phy_oem_params *oem_phy = &oem->phys[phy_id];
                int cable_length_long =
                        is_long_cable(phy_id, cable_selection_mask);
index 9ab58e0540e7df4caf596e9621a5fcee62e86fba..4911310a38f5e42fd9d292b89de93b57369c7419 100644 (file)
@@ -473,7 +473,7 @@ void sci_controller_remote_device_stopped(struct isci_host *ihost,
 
 enum sci_status sci_controller_continue_io(struct isci_request *ireq);
 int isci_host_scan_finished(struct Scsi_Host *, unsigned long);
-void isci_host_scan_start(struct Scsi_Host *);
+void isci_host_start(struct Scsi_Host *);
 u16 isci_alloc_tag(struct isci_host *ihost);
 enum sci_status isci_free_tag(struct isci_host *ihost, u16 io_tag);
 void isci_tci_free(struct isci_host *ihost, u16 tci);
index 92c1d86d1fc6478471cd88a318bd9e72e9bd65d6..5ed4e608f20001091bcda1adec983a3e6b9cb999 100644 (file)
@@ -156,7 +156,7 @@ static struct scsi_host_template isci_sht = {
        .target_alloc                   = sas_target_alloc,
        .slave_configure                = sas_slave_configure,
        .scan_finished                  = isci_host_scan_finished,
-       .scan_start                     = isci_host_scan_start,
+       .scan_start                     = isci_host_start,
        .change_queue_depth             = sas_change_queue_depth,
        .change_queue_type              = sas_change_queue_type,
        .bios_param                     = sas_bios_param,
@@ -644,7 +644,6 @@ static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_devic
                                                orom->hdr.version)) {
                        dev_warn(&pdev->dev,
                                 "[%d]: invalid oem parameters detected, falling back to firmware\n", i);
-                       devm_kfree(&pdev->dev, orom);
                        orom = NULL;
                        break;
                }
@@ -722,11 +721,67 @@ static void __devexit isci_pci_remove(struct pci_dev *pdev)
        }
 }
 
+#ifdef CONFIG_PM
+static int isci_suspend(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct isci_host *ihost;
+       int i;
+
+       for_each_isci_host(i, ihost, pdev) {
+               sas_suspend_ha(&ihost->sas_ha);
+               isci_host_deinit(ihost);
+       }
+
+       pci_save_state(pdev);
+       pci_disable_device(pdev);
+       pci_set_power_state(pdev, PCI_D3hot);
+
+       return 0;
+}
+
+static int isci_resume(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct isci_host *ihost;
+       int rc, i;
+
+       pci_set_power_state(pdev, PCI_D0);
+       pci_restore_state(pdev);
+
+       rc = pcim_enable_device(pdev);
+       if (rc) {
+               dev_err(&pdev->dev,
+                       "enabling device failure after resume(%d)\n", rc);
+               return rc;
+       }
+
+       pci_set_master(pdev);
+
+       for_each_isci_host(i, ihost, pdev) {
+               sas_prep_resume_ha(&ihost->sas_ha);
+
+               isci_host_init(ihost);
+               isci_host_start(ihost->sas_ha.core.shost);
+               wait_for_start(ihost);
+
+               sas_resume_ha(&ihost->sas_ha);
+       }
+
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(isci_pm_ops, isci_suspend, isci_resume);
+#endif
+
 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),
+#ifdef CONFIG_PM
+       .driver.pm      = &isci_pm_ops,
+#endif
 };
 
 static __init int isci_init(void)
index 18f43d4c30baf8e37177eac41c8b817d7c8bcb1d..cb87b2ef7c92ab2ab5b25cbedbb594e85956eb05 100644 (file)
@@ -169,7 +169,7 @@ sci_phy_link_layer_initialization(struct isci_phy *iphy,
        phy_cap.gen1_no_ssc = 1;
        if (ihost->oem_parameters.controller.do_enable_ssc) {
                struct scu_afe_registers __iomem *afe = &ihost->scu_registers->afe;
-               struct scu_afe_transceiver *xcvr = &afe->scu_afe_xcvr[phy_idx];
+               struct scu_afe_transceiver __iomem *xcvr = &afe->scu_afe_xcvr[phy_idx];
                struct isci_pci_info *pci_info = to_pci_info(ihost->pdev);
                bool en_sas = false;
                bool en_sata = false;
@@ -1205,6 +1205,7 @@ static void scu_link_layer_start_oob(struct isci_phy *iphy)
        /** Reset OOB sequence - start */
        val = readl(&ll->phy_configuration);
        val &= ~(SCU_SAS_PCFG_GEN_BIT(OOB_RESET) |
+                SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE) |
                 SCU_SAS_PCFG_GEN_BIT(HARD_RESET));
        writel(val, &ll->phy_configuration);
        readl(&ll->phy_configuration); /* flush */
@@ -1236,6 +1237,7 @@ static void scu_link_layer_tx_hard_reset(
         * to the starting state. */
        phy_configuration_value =
                readl(&iphy->link_layer_registers->phy_configuration);
+       phy_configuration_value &= ~(SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE));
        phy_configuration_value |=
                (SCU_SAS_PCFG_GEN_BIT(HARD_RESET) |
                 SCU_SAS_PCFG_GEN_BIT(OOB_RESET));
index 4d95654c3fd4852ebeaff740e11bbe2492d4c4a5..8ac646e5eddc9476603fb98c8ce5bd2a7b0be224 100644 (file)
@@ -104,7 +104,6 @@ struct isci_orom *isci_request_oprom(struct pci_dev *pdev)
 
        if (i >= len) {
                dev_err(&pdev->dev, "oprom parse error\n");
-               devm_kfree(&pdev->dev, rom);
                rom = NULL;
        }
        pci_unmap_biosrom(oprom);
index a703b9ce0c2c211c984a877179b724a624ebf4fc..c7ee81d011253487055b982942dff0620c635a17 100644 (file)
@@ -212,7 +212,7 @@ enum sci_status sci_remote_node_context_destruct(struct sci_remote_node_context
                                                      scics_sds_remote_node_context_callback callback,
                                                      void *callback_parameter);
 enum sci_status sci_remote_node_context_suspend(struct sci_remote_node_context *sci_rnc,
-                                                    u32 suspend_type,
+                                                    enum sci_remote_node_suspension_reasons reason,
                                                     u32 suspension_code);
 enum sci_status sci_remote_node_context_resume(struct sci_remote_node_context *sci_rnc,
                                                    scics_sds_remote_node_context_callback cb_fn,
index a59fcdc8fd6331e929c65f69afd2763819da33e0..bdb81cda84013f0d132aa1972bd409dcb9903f6b 100644 (file)
@@ -580,10 +580,7 @@ int sas_ata_init(struct domain_device *found_dev)
        struct ata_port *ap;
        int rc;
 
-       ata_host_init(&found_dev->sata_dev.ata_host,
-                     ha->dev,
-                     sata_port_info.flags,
-                     &sas_sata_ops);
+       ata_host_init(&found_dev->sata_dev.ata_host, ha->dev, &sas_sata_ops);
        ap = ata_sas_port_alloc(&found_dev->sata_dev.ata_host,
                                &sata_port_info,
                                shost);
@@ -700,6 +697,92 @@ void sas_probe_sata(struct asd_sas_port *port)
                if (ata_dev_disabled(sas_to_ata_dev(dev)))
                        sas_fail_probe(dev, __func__, -ENODEV);
        }
+
+}
+
+static bool sas_ata_flush_pm_eh(struct asd_sas_port *port, const char *func)
+{
+       struct domain_device *dev, *n;
+       bool retry = false;
+
+       list_for_each_entry_safe(dev, n, &port->dev_list, dev_list_node) {
+               int rc;
+
+               if (!dev_is_sata(dev))
+                       continue;
+
+               sas_ata_wait_eh(dev);
+               rc = dev->sata_dev.pm_result;
+               if (rc == -EAGAIN)
+                       retry = true;
+               else if (rc) {
+                       /* since we don't have a
+                        * ->port_{suspend|resume} routine in our
+                        *  ata_port ops, and no entanglements with
+                        *  acpi, suspend should just be mechanical trip
+                        *  through eh, catch cases where these
+                        *  assumptions are invalidated
+                        */
+                       WARN_ONCE(1, "failed %s %s error: %d\n", func,
+                                dev_name(&dev->rphy->dev), rc);
+               }
+
+               /* if libata failed to power manage the device, tear it down */
+               if (ata_dev_disabled(sas_to_ata_dev(dev)))
+                       sas_fail_probe(dev, func, -ENODEV);
+       }
+
+       return retry;
+}
+
+void sas_suspend_sata(struct asd_sas_port *port)
+{
+       struct domain_device *dev;
+
+ retry:
+       mutex_lock(&port->ha->disco_mutex);
+       list_for_each_entry(dev, &port->dev_list, dev_list_node) {
+               struct sata_device *sata;
+
+               if (!dev_is_sata(dev))
+                       continue;
+
+               sata = &dev->sata_dev;
+               if (sata->ap->pm_mesg.event == PM_EVENT_SUSPEND)
+                       continue;
+
+               sata->pm_result = -EIO;
+               ata_sas_port_async_suspend(sata->ap, &sata->pm_result);
+       }
+       mutex_unlock(&port->ha->disco_mutex);
+
+       if (sas_ata_flush_pm_eh(port, __func__))
+               goto retry;
+}
+
+void sas_resume_sata(struct asd_sas_port *port)
+{
+       struct domain_device *dev;
+
+ retry:
+       mutex_lock(&port->ha->disco_mutex);
+       list_for_each_entry(dev, &port->dev_list, dev_list_node) {
+               struct sata_device *sata;
+
+               if (!dev_is_sata(dev))
+                       continue;
+
+               sata = &dev->sata_dev;
+               if (sata->ap->pm_mesg.event == PM_EVENT_ON)
+                       continue;
+
+               sata->pm_result = -EIO;
+               ata_sas_port_async_resume(sata->ap, &sata->pm_result);
+       }
+       mutex_unlock(&port->ha->disco_mutex);
+
+       if (sas_ata_flush_pm_eh(port, __func__))
+               goto retry;
 }
 
 /**
index 3e9dc1a84358a540dd5ad4324b63fd4f9bf98039..a0c3003e0c7d2f6b5e1a89147ab29d58b1609aaa 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <linux/scatterlist.h>
 #include <linux/slab.h>
+#include <linux/async.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_eh.h>
 #include "sas_internal.h"
@@ -180,16 +181,18 @@ int sas_notify_lldd_dev_found(struct domain_device *dev)
        struct Scsi_Host *shost = sas_ha->core.shost;
        struct sas_internal *i = to_sas_internal(shost->transportt);
 
-       if (i->dft->lldd_dev_found) {
-               res = i->dft->lldd_dev_found(dev);
-               if (res) {
-                       printk("sas: driver on pcidev %s cannot handle "
-                              "device %llx, error:%d\n",
-                              dev_name(sas_ha->dev),
-                              SAS_ADDR(dev->sas_addr), res);
-               }
-               kref_get(&dev->kref);
+       if (!i->dft->lldd_dev_found)
+               return 0;
+
+       res = i->dft->lldd_dev_found(dev);
+       if (res) {
+               printk("sas: driver on pcidev %s cannot handle "
+                      "device %llx, error:%d\n",
+                      dev_name(sas_ha->dev),
+                      SAS_ADDR(dev->sas_addr), res);
        }
+       set_bit(SAS_DEV_FOUND, &dev->state);
+       kref_get(&dev->kref);
        return res;
 }
 
@@ -200,7 +203,10 @@ void sas_notify_lldd_dev_gone(struct domain_device *dev)
        struct Scsi_Host *shost = sas_ha->core.shost;
        struct sas_internal *i = to_sas_internal(shost->transportt);
 
-       if (i->dft->lldd_dev_gone) {
+       if (!i->dft->lldd_dev_gone)
+               return;
+
+       if (test_and_clear_bit(SAS_DEV_FOUND, &dev->state)) {
                i->dft->lldd_dev_gone(dev);
                sas_put_device(dev);
        }
@@ -234,6 +240,47 @@ static void sas_probe_devices(struct work_struct *work)
        }
 }
 
+static void sas_suspend_devices(struct work_struct *work)
+{
+       struct asd_sas_phy *phy;
+       struct domain_device *dev;
+       struct sas_discovery_event *ev = to_sas_discovery_event(work);
+       struct asd_sas_port *port = ev->port;
+       struct Scsi_Host *shost = port->ha->core.shost;
+       struct sas_internal *si = to_sas_internal(shost->transportt);
+
+       clear_bit(DISCE_SUSPEND, &port->disc.pending);
+
+       sas_suspend_sata(port);
+
+       /* lldd is free to forget the domain_device across the
+        * suspension, we force the issue here to keep the reference
+        * counts aligned
+        */
+       list_for_each_entry(dev, &port->dev_list, dev_list_node)
+               sas_notify_lldd_dev_gone(dev);
+
+       /* we are suspending, so we know events are disabled and
+        * phy_list is not being mutated
+        */
+       list_for_each_entry(phy, &port->phy_list, port_phy_el) {
+               if (si->dft->lldd_port_formed)
+                       si->dft->lldd_port_deformed(phy);
+               phy->suspended = 1;
+               port->suspended = 1;
+       }
+}
+
+static void sas_resume_devices(struct work_struct *work)
+{
+       struct sas_discovery_event *ev = to_sas_discovery_event(work);
+       struct asd_sas_port *port = ev->port;
+
+       clear_bit(DISCE_RESUME, &port->disc.pending);
+
+       sas_resume_sata(port);
+}
+
 /**
  * sas_discover_end_dev -- discover an end device (SSP, etc)
  * @end: pointer to domain device of interest
@@ -530,6 +577,8 @@ void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *port)
                [DISCE_DISCOVER_DOMAIN] = sas_discover_domain,
                [DISCE_REVALIDATE_DOMAIN] = sas_revalidate_domain,
                [DISCE_PROBE] = sas_probe_devices,
+               [DISCE_SUSPEND] = sas_suspend_devices,
+               [DISCE_RESUME] = sas_resume_devices,
                [DISCE_DESTRUCT] = sas_destruct_devices,
        };
 
index fc460933575c76e57d4433a40801cf4403333506..cd6f99c1ae7e1740fb5e69613806c36c2a7c137f 100644 (file)
@@ -41,6 +41,7 @@ static const char *sas_phye_str[] = {
        [1] = "PHYE_OOB_DONE",
        [2] = "PHYE_OOB_ERROR",
        [3] = "PHYE_SPINUP_HOLD",
+       [4] = "PHYE_RESUME_TIMEOUT",
 };
 
 void sas_dprint_porte(int phyid, enum port_event pe)
index 789c4d8bb7a7d8d7ef9310172c4b44795a2fee81..aadbd5314c5cce3e2a91b3b323aaffb4ab98fa06 100644 (file)
@@ -134,7 +134,7 @@ static void notify_port_event(struct asd_sas_phy *phy, enum port_event event)
                        &phy->port_events[event].work, ha);
 }
 
-static void notify_phy_event(struct asd_sas_phy *phy, enum phy_event event)
+void sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event)
 {
        struct sas_ha_struct *ha = phy->ha;
 
@@ -159,7 +159,7 @@ int sas_init_events(struct sas_ha_struct *sas_ha)
 
        sas_ha->notify_ha_event = notify_ha_event;
        sas_ha->notify_port_event = notify_port_event;
-       sas_ha->notify_phy_event = notify_phy_event;
+       sas_ha->notify_phy_event = sas_notify_phy_event;
 
        return 0;
 }
index 014297c05880d8e2fdd3e889550f3536b3cab30e..dbc8a793fd867dcd1f24e55e1d79aab836530b0f 100644 (file)
@@ -178,7 +178,7 @@ Undo_phys:
        return error;
 }
 
-int sas_unregister_ha(struct sas_ha_struct *sas_ha)
+static void sas_disable_events(struct sas_ha_struct *sas_ha)
 {
        /* Set the state to unregistered to avoid further unchained
         * events to be queued, and flush any in-progress drainers
@@ -189,7 +189,11 @@ int sas_unregister_ha(struct sas_ha_struct *sas_ha)
        spin_unlock_irq(&sas_ha->lock);
        __sas_drain_work(sas_ha);
        mutex_unlock(&sas_ha->drain_mutex);
+}
 
+int sas_unregister_ha(struct sas_ha_struct *sas_ha)
+{
+       sas_disable_events(sas_ha);
        sas_unregister_ports(sas_ha);
 
        /* flush unregistration work */
@@ -381,6 +385,90 @@ int sas_set_phy_speed(struct sas_phy *phy,
        return ret;
 }
 
+void sas_prep_resume_ha(struct sas_ha_struct *ha)
+{
+       int i;
+
+       set_bit(SAS_HA_REGISTERED, &ha->state);
+
+       /* clear out any stale link events/data from the suspension path */
+       for (i = 0; i < ha->num_phys; i++) {
+               struct asd_sas_phy *phy = ha->sas_phy[i];
+
+               memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
+               phy->port_events_pending = 0;
+               phy->phy_events_pending = 0;
+               phy->frame_rcvd_size = 0;
+       }
+}
+EXPORT_SYMBOL(sas_prep_resume_ha);
+
+static int phys_suspended(struct sas_ha_struct *ha)
+{
+       int i, rc = 0;
+
+       for (i = 0; i < ha->num_phys; i++) {
+               struct asd_sas_phy *phy = ha->sas_phy[i];
+
+               if (phy->suspended)
+                       rc++;
+       }
+
+       return rc;
+}
+
+void sas_resume_ha(struct sas_ha_struct *ha)
+{
+       const unsigned long tmo = msecs_to_jiffies(25000);
+       int i;
+
+       /* deform ports on phys that did not resume
+        * at this point we may be racing the phy coming back (as posted
+        * by the lldd).  So we post the event and once we are in the
+        * libsas context check that the phy remains suspended before
+        * tearing it down.
+        */
+       i = phys_suspended(ha);
+       if (i)
+               dev_info(ha->dev, "waiting up to 25 seconds for %d phy%s to resume\n",
+                        i, i > 1 ? "s" : "");
+       wait_event_timeout(ha->eh_wait_q, phys_suspended(ha) == 0, tmo);
+       for (i = 0; i < ha->num_phys; i++) {
+               struct asd_sas_phy *phy = ha->sas_phy[i];
+
+               if (phy->suspended) {
+                       dev_warn(&phy->phy->dev, "resume timeout\n");
+                       sas_notify_phy_event(phy, PHYE_RESUME_TIMEOUT);
+               }
+       }
+
+       /* all phys are back up or timed out, turn on i/o so we can
+        * flush out disks that did not return
+        */
+       scsi_unblock_requests(ha->core.shost);
+       sas_drain_work(ha);
+}
+EXPORT_SYMBOL(sas_resume_ha);
+
+void sas_suspend_ha(struct sas_ha_struct *ha)
+{
+       int i;
+
+       sas_disable_events(ha);
+       scsi_block_requests(ha->core.shost);
+       for (i = 0; i < ha->num_phys; i++) {
+               struct asd_sas_port *port = ha->sas_port[i];
+
+               sas_discover_event(port, DISCE_SUSPEND);
+       }
+
+       /* flush suspend events while unregistered */
+       mutex_lock(&ha->drain_mutex);
+       __sas_drain_work(ha);
+       mutex_unlock(&ha->drain_mutex);
+}
+EXPORT_SYMBOL(sas_suspend_ha);
+
 static void sas_phy_release(struct sas_phy *phy)
 {
        kfree(phy->hostdata);
index 507e4cf12e56cef87cd3b80af00215cc62db6078..1de67964e5a1e39ffa10151c79489078826e2536 100644 (file)
@@ -89,6 +89,7 @@ int sas_smp_phy_control(struct domain_device *dev, int phy_id,
                        enum phy_func phy_func, struct sas_phy_linkrates *);
 int sas_smp_get_phy_events(struct sas_phy *phy);
 
+void sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event);
 void sas_device_set_phy(struct domain_device *dev, struct sas_port *port);
 struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy);
 struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id);
index 521422e857ab330ee3a659ad11dae2dd02aee9f0..cdee446c29e1319078999d67176b3f9a2af8915f 100644 (file)
@@ -94,6 +94,25 @@ static void sas_phye_spinup_hold(struct work_struct *work)
        i->dft->lldd_control_phy(phy, PHY_FUNC_RELEASE_SPINUP_HOLD, NULL);
 }
 
+static void sas_phye_resume_timeout(struct work_struct *work)
+{
+       struct asd_sas_event *ev = to_asd_sas_event(work);
+       struct asd_sas_phy *phy = ev->phy;
+
+       clear_bit(PHYE_RESUME_TIMEOUT, &phy->phy_events_pending);
+
+       /* phew, lldd got the phy back in the nick of time */
+       if (!phy->suspended) {
+               dev_info(&phy->phy->dev, "resume timeout cancelled\n");
+               return;
+       }
+
+       phy->error = 0;
+       phy->suspended = 0;
+       sas_deform_port(phy, 1);
+}
+
+
 /* ---------- Phy class registration ---------- */
 
 int sas_register_phys(struct sas_ha_struct *sas_ha)
@@ -105,6 +124,8 @@ int sas_register_phys(struct sas_ha_struct *sas_ha)
                [PHYE_OOB_DONE] = sas_phye_oob_done,
                [PHYE_OOB_ERROR] = sas_phye_oob_error,
                [PHYE_SPINUP_HOLD] = sas_phye_spinup_hold,
+               [PHYE_RESUME_TIMEOUT] = sas_phye_resume_timeout,
+
        };
 
        static const work_func_t sas_port_event_fns[PORT_NUM_EVENTS] = {
index e884a8c58a0ccb181424051281fda4b4a45fc1a9..1398b714c01836ee3789199cf3cd627ac4fa4021 100644 (file)
@@ -39,6 +39,49 @@ static bool phy_is_wideport_member(struct asd_sas_port *port, struct asd_sas_phy
        return true;
 }
 
+static void sas_resume_port(struct asd_sas_phy *phy)
+{
+       struct domain_device *dev;
+       struct asd_sas_port *port = phy->port;
+       struct sas_ha_struct *sas_ha = phy->ha;
+       struct sas_internal *si = to_sas_internal(sas_ha->core.shost->transportt);
+
+       if (si->dft->lldd_port_formed)
+               si->dft->lldd_port_formed(phy);
+
+       if (port->suspended)
+               port->suspended = 0;
+       else {
+               /* we only need to handle "link returned" actions once */
+               return;
+       }
+
+       /* if the port came back:
+        * 1/ presume every device came back
+        * 2/ force the next revalidation to check all expander phys
+        */
+       list_for_each_entry(dev, &port->dev_list, dev_list_node) {
+               int i, rc;
+
+               rc = sas_notify_lldd_dev_found(dev);
+               if (rc) {
+                       sas_unregister_dev(port, dev);
+                       continue;
+               }
+
+               if (dev->dev_type == EDGE_DEV || dev->dev_type == FANOUT_DEV) {
+                       dev->ex_dev.ex_change_count = -1;
+                       for (i = 0; i < dev->ex_dev.num_phys; i++) {
+                               struct ex_phy *phy = &dev->ex_dev.ex_phy[i];
+
+                               phy->phy_change_count = -1;
+                       }
+               }
+       }
+
+       sas_discover_event(port, DISCE_RESUME);
+}
+
 /**
  * sas_form_port -- add this phy to a port
  * @phy: the phy of interest
@@ -58,7 +101,14 @@ static void sas_form_port(struct asd_sas_phy *phy)
        if (port) {
                if (!phy_is_wideport_member(port, phy))
                        sas_deform_port(phy, 0);
-               else {
+               else if (phy->suspended) {
+                       phy->suspended = 0;
+                       sas_resume_port(phy);
+
+                       /* phy came back, try to cancel the timeout */
+                       wake_up(&sas_ha->eh_wait_q);
+                       return;
+               } else {
                        SAS_DPRINTK("%s: phy%d belongs to port%d already(%d)!\n",
                                    __func__, phy->id, phy->port->id,
                                    phy->port->num_phys);
index e8f89264768109f69b075d83ce019f40f8967471..fcb005fa4bd136480367d7fe92bdd55b30a5f7df 100644 (file)
@@ -33,9 +33,9 @@
 /*
  * MegaRAID SAS Driver meta data
  */
-#define MEGASAS_VERSION                                "00.00.06.15-rc1"
-#define MEGASAS_RELDATE                                "Mar. 19, 2012"
-#define MEGASAS_EXT_VERSION                    "Mon. Mar. 19 17:00:00 PDT 2012"
+#define MEGASAS_VERSION                                "00.00.06.18-rc1"
+#define MEGASAS_RELDATE                                "Jun. 17, 2012"
+#define MEGASAS_EXT_VERSION                    "Tue. Jun. 17 17:00:00 PDT 2012"
 
 /*
  * Device IDs
@@ -747,6 +747,7 @@ struct megasas_ctrl_info {
 #define        MEGASAS_RESET_NOTICE_INTERVAL           5
 #define MEGASAS_IOCTL_CMD                      0
 #define MEGASAS_DEFAULT_CMD_TIMEOUT            90
+#define MEGASAS_THROTTLE_QUEUE_DEPTH           16
 
 /*
  * FW reports the maximum of number of commands that it can accept (maximum
@@ -1364,6 +1365,7 @@ struct megasas_instance {
        unsigned long bar;
        long reset_flags;
        struct mutex reset_mutex;
+       int throttlequeuedepth;
 };
 
 enum {
index dc27598785e5d781ff9790697f8b3a5960921d85..0393ec478cdf41257aebbf2e7e2cee7a244583eb 100644 (file)
@@ -18,7 +18,7 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  *  FILE: megaraid_sas_base.c
- *  Version : v00.00.06.15-rc1
+ *  Version : v00.00.06.18-rc1
  *
  *  Authors: LSI Corporation
  *           Sreenivas Bagalkote
@@ -71,6 +71,16 @@ static int msix_disable;
 module_param(msix_disable, int, S_IRUGO);
 MODULE_PARM_DESC(msix_disable, "Disable MSI-X interrupt handling. Default: 0");
 
+static int throttlequeuedepth = MEGASAS_THROTTLE_QUEUE_DEPTH;
+module_param(throttlequeuedepth, int, S_IRUGO);
+MODULE_PARM_DESC(throttlequeuedepth,
+       "Adapter queue depth when throttled due to I/O timeout. Default: 16");
+
+int resetwaittime = MEGASAS_RESET_WAIT_TIME;
+module_param(resetwaittime, int, S_IRUGO);
+MODULE_PARM_DESC(resetwaittime, "Wait time in seconds after I/O timeout "
+                "before resetting adapter. Default: 180");
+
 MODULE_LICENSE("GPL");
 MODULE_VERSION(MEGASAS_VERSION);
 MODULE_AUTHOR("megaraidlinux@lsi.com");
@@ -1595,8 +1605,9 @@ megasas_check_and_restore_queue_depth(struct megasas_instance *instance)
 {
        unsigned long flags;
        if (instance->flag & MEGASAS_FW_BUSY
-               && time_after(jiffies, instance->last_time + 5 * HZ)
-               && atomic_read(&instance->fw_outstanding) < 17) {
+           && time_after(jiffies, instance->last_time + 5 * HZ)
+           && atomic_read(&instance->fw_outstanding) <
+           instance->throttlequeuedepth + 1) {
 
                spin_lock_irqsave(instance->host->host_lock, flags);
                instance->flag &= ~MEGASAS_FW_BUSY;
@@ -1772,7 +1783,7 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
                return SUCCESS;
        }
 
-       for (i = 0; i < wait_time; i++) {
+       for (i = 0; i < resetwaittime; i++) {
 
                int outstanding = atomic_read(&instance->fw_outstanding);
 
@@ -1914,7 +1925,7 @@ blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
                /* FW is busy, throttle IO */
                spin_lock_irqsave(instance->host->host_lock, flags);
 
-               instance->host->can_queue = 16;
+               instance->host->can_queue = instance->throttlequeuedepth;
                instance->last_time = jiffies;
                instance->flag |= MEGASAS_FW_BUSY;
 
@@ -3577,6 +3588,24 @@ static int megasas_init_fw(struct megasas_instance *instance)
 
        kfree(ctrl_info);
 
+       /* Check for valid throttlequeuedepth module parameter */
+       if (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY ||
+           instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) {
+               if (throttlequeuedepth > (instance->max_fw_cmds -
+                                         MEGASAS_SKINNY_INT_CMDS))
+                       instance->throttlequeuedepth =
+                               MEGASAS_THROTTLE_QUEUE_DEPTH;
+               else
+                       instance->throttlequeuedepth = throttlequeuedepth;
+       } else {
+               if (throttlequeuedepth > (instance->max_fw_cmds -
+                                         MEGASAS_INT_CMDS))
+                       instance->throttlequeuedepth =
+                               MEGASAS_THROTTLE_QUEUE_DEPTH;
+               else
+                       instance->throttlequeuedepth = throttlequeuedepth;
+       }
+
         /*
        * Setup tasklet for cmd completion
        */
@@ -4066,7 +4095,6 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        spin_lock_init(&instance->cmd_pool_lock);
        spin_lock_init(&instance->hba_lock);
        spin_lock_init(&instance->completion_lock);
-       spin_lock_init(&poll_aen_lock);
 
        mutex_init(&instance->aen_mutex);
        mutex_init(&instance->reset_mutex);
@@ -5392,6 +5420,8 @@ static int __init megasas_init(void)
        printk(KERN_INFO "megasas: %s %s\n", MEGASAS_VERSION,
               MEGASAS_EXT_VERSION);
 
+       spin_lock_init(&poll_aen_lock);
+
        support_poll_for_event = 2;
        support_device_change = 1;
 
index a610cf1d48473301f60a805fc2636bdd3d0d7714..788115b72b2292ee6868d3fa528108d3a3d9e279 100644 (file)
@@ -94,6 +94,7 @@ int megasas_transition_to_ready(struct megasas_instance *instance, int ocr);
 void megaraid_sas_kill_hba(struct megasas_instance *instance);
 
 extern u32 megasas_dbg_lvl;
+extern int resetwaittime;
 
 /**
  * megasas_enable_intr_fusion -        Enables interrupts
@@ -2063,9 +2064,9 @@ megasas_check_reset_fusion(struct megasas_instance *instance,
 int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance)
 {
        int i, outstanding, retval = 0;
-       u32 fw_state, wait_time = MEGASAS_RESET_WAIT_TIME;
+       u32 fw_state;
 
-       for (i = 0; i < wait_time; i++) {
+       for (i = 0; i < resetwaittime; i++) {
                /* Check if firmware is in fault state */
                fw_state = instance->instancet->read_fw_status_reg(
                        instance->reg_set) & MFI_STATE_MASK;
index bbb7e4bf30a3af61d764a2507734420e0e85828d..39f08dd20556ade6703cd9b47f99d685c64d2fc6 100644 (file)
@@ -2,7 +2,7 @@
 # Kernel configuration file for the MPT2SAS
 #
 # This code is based on drivers/scsi/mpt2sas/Kconfig
-# Copyright (C) 2007-2010  LSI Corporation
+# Copyright (C) 2007-2012  LSI Corporation
 #  (mailto:DL-MPTFusionLinux@lsi.com)
 
 # This program is free software; you can redistribute it and/or
index a80f3220c641b8e45e9bc558dfe8596dc1dd4c8b..e960f9625c78e8020424d0d9c42fcad534f19a1f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  Copyright (c) 2000-2011 LSI Corporation.
+ *  Copyright (c) 2000-2012 LSI Corporation.
  *
  *
  *           Name:  mpi2.h
@@ -8,7 +8,7 @@
  *                  scatter/gather formats.
  *  Creation Date:  June 21, 2006
  *
- *  mpi2.h Version:  02.00.23
+ *  mpi2.h Version:  02.00.25
  *
  *  Version History
  *  ---------------
@@ -72,6 +72,9 @@
  *  05-25-11  02.00.21  Bumped MPI2_HEADER_VERSION_UNIT.
  *  08-24-11  02.00.22  Bumped MPI2_HEADER_VERSION_UNIT.
  *  11-18-11  02.00.23  Bumped MPI2_HEADER_VERSION_UNIT.
+ *  02-06-12  02.00.24  Bumped MPI2_HEADER_VERSION_UNIT.
+ *  03-29-12  02.00.25  Bumped MPI2_HEADER_VERSION_UNIT.
+ *                      Added Hard Reset delay timings.
  *  --------------------------------------------------------------------------
  */
 
 #define MPI2_VERSION_02_00                  (0x0200)
 
 /* versioning for this MPI header set */
-#define MPI2_HEADER_VERSION_UNIT            (0x17)
+#define MPI2_HEADER_VERSION_UNIT            (0x19)
 #define MPI2_HEADER_VERSION_DEV             (0x00)
 #define MPI2_HEADER_VERSION_UNIT_MASK       (0xFF00)
 #define MPI2_HEADER_VERSION_UNIT_SHIFT      (8)
@@ -275,6 +278,11 @@ typedef volatile struct _MPI2_SYSTEM_INTERFACE_REGS
 #define MPI2_REQUEST_DESCRIPTOR_POST_HIGH_OFFSET    (0x000000C4)
 
 
+/* Hard Reset delay timings */
+#define MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC     (50000)
+#define MPI2_HARD_RESET_PCIE_RESET_READ_WINDOW_MICRO_SEC    (255000)
+#define MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC    (256000)
+
 /*****************************************************************************
 *
 *        Message Descriptors
index de90162413c23e2c720df8c2eed8207acf58f235..38c5da398143a83aca39b6e09e1429a0b05177a8 100644 (file)
@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2010 LSI Corporation.
+ *  Copyright (c) 2000-2012 LSI Corporation.
  *
  *
  *           Name:  mpi2_init.h
  *          Title:  MPI SCSI initiator mode messages and structures
  *  Creation Date:  June 23, 2006
  *
- *    mpi2_init.h Version:  02.00.11
+ *    mpi2_init.h Version:  02.00.13
  *
  *  Version History
  *  ---------------
@@ -34,6 +34,8 @@
  *  02-10-10  02.00.09  Removed unused structure that had "#if 0" around it.
  *  05-12-10  02.00.10  Added optional vendor-unique region to SCSI IO Request.
  *  11-10-10  02.00.11  Added MPI2_SCSIIO_NUM_SGLOFFSETS define.
+ *  02-06-12  02.00.13  Added alternate defines for Task Priority / Command
+ *                      Priority to match SAM-4.
  *  --------------------------------------------------------------------------
  */
 
@@ -194,6 +196,9 @@ typedef struct _MPI2_SCSI_IO_REQUEST
 
 #define MPI2_SCSIIO_CONTROL_TASKPRI_MASK        (0x00007800)
 #define MPI2_SCSIIO_CONTROL_TASKPRI_SHIFT       (11)
+/* alternate name for the previous field; called Command Priority in SAM-4 */
+#define MPI2_SCSIIO_CONTROL_CMDPRI_MASK         (0x00007800)
+#define MPI2_SCSIIO_CONTROL_CMDPRI_SHIFT        (11)
 
 #define MPI2_SCSIIO_CONTROL_TASKATTRIBUTE_MASK  (0x00000700)
 #define MPI2_SCSIIO_CONTROL_SIMPLEQ             (0x00000000)
index 9a925c07a9ec0c6e4f6c13b71b2654efc7099e95..b0d4760bb17dd843ea1ecccfed650d9613b88d79 100644 (file)
@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2011 LSI Corporation.
+ *  Copyright (c) 2000-2012 LSI Corporation.
  *
  *
  *           Name:  mpi2_ioc.h
  *          Title:  MPI IOC, Port, Event, FW Download, and FW Upload messages
  *  Creation Date:  October 11, 2006
  *
- *  mpi2_ioc.h Version:  02.00.19
+ *  mpi2_ioc.h Version:  02.00.21
  *
  *  Version History
  *  ---------------
  *  08-24-11  02.00.19  Added PhysicalPort field to
  *                      MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE structure.
  *                      Marked MPI2_PM_CONTROL_FEATURE_PCIE_LINK as obsolete.
+ *  03-29-12  02.00.21  Added a product specific range to event values.
  *  --------------------------------------------------------------------------
  */
 
@@ -492,7 +493,8 @@ typedef struct _MPI2_EVENT_NOTIFICATION_REPLY
 #define MPI2_EVENT_SAS_NOTIFY_PRIMITIVE             (0x0026)
 #define MPI2_EVENT_TEMP_THRESHOLD                   (0x0027)
 #define MPI2_EVENT_HOST_MESSAGE                     (0x0028)
-
+#define MPI2_EVENT_MIN_PRODUCT_SPECIFIC             (0x006E)
+#define MPI2_EVENT_MAX_PRODUCT_SPECIFIC             (0x007F)
 
 /* Log Entry Added Event data */
 
index 0601612b875add889302ae2630919c6851672d5a..2b38af213beb079d8060d0c588cdafca73da670f 100644 (file)
@@ -1,12 +1,12 @@
 /*
- *  Copyright (c) 2000-2010 LSI Corporation.
+ *  Copyright (c) 2000-2012 LSI Corporation.
  *
  *
  *           Name:  mpi2_raid.h
  *          Title:  MPI Integrated RAID messages and structures
  *  Creation Date:  April 26, 2007
  *
- *    mpi2_raid.h Version:  02.00.06
+ *    mpi2_raid.h Version:  02.00.08
  *
  *  Version History
  *  ---------------
@@ -26,7 +26,7 @@
  *  08-24-10  02.00.06  Added MPI2_RAID_ACTION_COMPATIBILITY_CHECK along with
  *                      related structures and defines.
  *                      Added product-specific range to RAID Action values.
-
+ *  02-06-12  02.00.08  Added MPI2_RAID_ACTION_PHYSDISK_HIDDEN.
  *  --------------------------------------------------------------------------
  */
 
@@ -181,6 +181,7 @@ typedef struct _MPI2_RAID_ACTION_REQUEST
 #define MPI2_RAID_ACTION_START_RAID_FUNCTION        (0x21)
 #define MPI2_RAID_ACTION_STOP_RAID_FUNCTION         (0x22)
 #define MPI2_RAID_ACTION_COMPATIBILITY_CHECK        (0x23)
+#define MPI2_RAID_ACTION_PHYSDISK_HIDDEN            (0x24)
 #define MPI2_RAID_ACTION_MIN_PRODUCT_SPECIFIC       (0x80)
 #define MPI2_RAID_ACTION_MAX_PRODUCT_SPECIFIC       (0xFF)
 
index 9d46fcbe7755fd2aa258e3de91c5a8cd76e3079c..db5960855cdf0da88550d81c574819b564039ce5 100644 (file)
@@ -3,7 +3,7 @@
  * for access to MPT (Message Passing Technology) firmware.
  *
  * This code is based on drivers/scsi/mpt2sas/mpt2_base.c
- * Copyright (C) 2007-2010  LSI Corporation
+ * Copyright (C) 2007-2012  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -1971,9 +1971,9 @@ _base_display_intel_branding(struct MPT2SAS_ADAPTER *ioc)
                        printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
                            MPT2SAS_INTEL_RMS2LL040_BRANDING);
                        break;
-               case MPT2SAS_INTEL_RAMSDALE_SSDID:
+               case MPT2SAS_INTEL_SSD910_SSDID:
                        printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
-                           MPT2SAS_INTEL_RAMSDALE_BRANDING);
+                           MPT2SAS_INTEL_SSD910_BRANDING);
                        break;
                default:
                        break;
@@ -2424,10 +2424,13 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc,  int sleep_flag)
        }
 
        /* command line tunables  for max controller queue depth */
-       if (max_queue_depth != -1)
-               max_request_credit = (max_queue_depth < facts->RequestCredit)
-                   ? max_queue_depth : facts->RequestCredit;
-       else
+       if (max_queue_depth != -1 && max_queue_depth != 0) {
+               max_request_credit = min_t(u16, max_queue_depth +
+                       ioc->hi_priority_depth + ioc->internal_depth,
+                       facts->RequestCredit);
+               if (max_request_credit > MAX_HBA_QUEUE_DEPTH)
+                       max_request_credit =  MAX_HBA_QUEUE_DEPTH;
+       } else
                max_request_credit = min_t(u16, facts->RequestCredit,
                    MAX_HBA_QUEUE_DEPTH);
 
@@ -2502,7 +2505,7 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc,  int sleep_flag)
        /* set the scsi host can_queue depth
         * with some internal commands that could be outstanding
         */
-       ioc->shost->can_queue = ioc->scsiio_depth - (2);
+       ioc->shost->can_queue = ioc->scsiio_depth;
        dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scsi host: "
            "can_queue depth (%d)\n", ioc->name, ioc->shost->can_queue));
 
index b3a1a30055d610419da7ef3389b0898db7154868..543d8d637479d4a983a80174412fe0f2f05e990a 100644 (file)
@@ -3,7 +3,7 @@
  * for access to MPT (Message Passing Technology) firmware.
  *
  * This code is based on drivers/scsi/mpt2sas/mpt2_base.h
- * Copyright (C) 2007-2010  LSI Corporation
+ * Copyright (C) 2007-2012  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -69,8 +69,8 @@
 #define MPT2SAS_DRIVER_NAME            "mpt2sas"
 #define MPT2SAS_AUTHOR "LSI Corporation <DL-MPTFusionLinux@lsi.com>"
 #define MPT2SAS_DESCRIPTION    "LSI MPT Fusion SAS 2.0 Device Driver"
-#define MPT2SAS_DRIVER_VERSION         "13.100.00.00"
-#define MPT2SAS_MAJOR_VERSION          13
+#define MPT2SAS_DRIVER_VERSION         "14.100.00.00"
+#define MPT2SAS_MAJOR_VERSION          14
 #define MPT2SAS_MINOR_VERSION          100
 #define MPT2SAS_BUILD_VERSION          00
 #define MPT2SAS_RELEASE_VERSION                00
                                "Intel Integrated RAID Module RMS2LL040"
 #define MPT2SAS_INTEL_RS25GB008_BRANDING       \
                                "Intel(R) RAID Controller RS25GB008"
-#define MPT2SAS_INTEL_RAMSDALE_BRANDING        \
-                               "Intel 720 Series SSD"
+#define MPT2SAS_INTEL_SSD910_BRANDING          \
+                               "Intel(R) SSD 910 Series"
 /*
  * Intel HBA SSDIDs
  */
 #define MPT2SAS_INTEL_RMS2LL080_SSDID          0x350E
 #define MPT2SAS_INTEL_RMS2LL040_SSDID          0x350F
 #define MPT2SAS_INTEL_RS25GB008_SSDID          0x3000
-#define MPT2SAS_INTEL_RAMSDALE_SSDID           0x3700
+#define MPT2SAS_INTEL_SSD910_SSDID             0x3700
 
 /*
  * HP HBA branding
@@ -1096,6 +1096,8 @@ int mpt2sas_config_get_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
     *mpi_reply, Mpi2IOUnitPage1_t *config_page);
 int mpt2sas_config_set_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
     *mpi_reply, Mpi2IOUnitPage1_t *config_page);
+int mpt2sas_config_get_iounit_pg3(struct MPT2SAS_ADAPTER *ioc,
+       Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage3_t *config_page, u16 sz);
 int mpt2sas_config_get_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
     *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz);
 int mpt2sas_config_set_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc,
index 2b4d37613d325416b606cee8a096e961a62ce42a..863778071a9dd3b25e85cc9201f9f659763aa393 100644 (file)
@@ -2,7 +2,7 @@
  * This module provides common API for accessing firmware configuration pages
  *
  * This code is based on drivers/scsi/mpt2sas/mpt2_base.c
- * Copyright (C) 2007-2010  LSI Corporation
+ * Copyright (C) 2007-2012  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -682,6 +682,42 @@ mpt2sas_config_set_iounit_pg1(struct MPT2SAS_ADAPTER *ioc,
        return r;
 }
 
+/**
+ * mpt2sas_config_get_iounit_pg3 - obtain iounit page 3
+ * @ioc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * @sz: size of buffer passed in config_page
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpt2sas_config_get_iounit_pg3(struct MPT2SAS_ADAPTER *ioc,
+       Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage3_t *config_page, u16 sz)
+{
+       Mpi2ConfigRequest_t mpi_request;
+       int r;
+
+       memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
+       mpi_request.Function = MPI2_FUNCTION_CONFIG;
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+       mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT;
+       mpi_request.Header.PageNumber = 3;
+       mpi_request.Header.PageVersion = MPI2_IOUNITPAGE3_PAGEVERSION;
+       mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
+       if (r)
+               goto out;
+
+       mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+       r = _config_request(ioc, &mpi_request, mpi_reply,
+           MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz);
+ out:
+       return r;
+}
+
 /**
  * mpt2sas_config_get_ioc_pg8 - obtain ioc page 8
  * @ioc: per adapter object
index 49bdd2dc8452bb27c79644ec1b5e4a1f30e3ad9b..64254416a178899677d1470c36bb8efee06c72ce 100644 (file)
@@ -3,7 +3,7 @@
  * controllers
  *
  * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.c
- * Copyright (C) 2007-2010  LSI Corporation
+ * Copyright (C) 2007-2012  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -2690,6 +2690,75 @@ _ctl_ioc_reply_queue_count_show(struct device *cdev,
 static DEVICE_ATTR(reply_queue_count, S_IRUGO,
         _ctl_ioc_reply_queue_count_show, NULL);
 
+/**
+ * _ctl_BRM_status_show - Backup Rail Monitor Status
+ * @cdev - pointer to embedded class device
+ * @buf - the buffer returned
+ *
+ * This is number of reply queues
+ *
+ * A sysfs 'read-only' shost attribute.
+ */
+static ssize_t
+_ctl_BRM_status_show(struct device *cdev, struct device_attribute *attr,
+       char *buf)
+{
+       struct Scsi_Host *shost = class_to_shost(cdev);
+       struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
+       Mpi2IOUnitPage3_t *io_unit_pg3 = NULL;
+       Mpi2ConfigReply_t mpi_reply;
+       u16 backup_rail_monitor_status = 0;
+       u16 ioc_status;
+       int sz;
+       ssize_t rc = 0;
+
+       if (!ioc->is_warpdrive) {
+               printk(MPT2SAS_ERR_FMT "%s: BRM attribute is only for"\
+                   "warpdrive\n", ioc->name, __func__);
+               goto out;
+       }
+
+       /* allocate upto GPIOVal 36 entries */
+       sz = offsetof(Mpi2IOUnitPage3_t, GPIOVal) + (sizeof(u16) * 36);
+       io_unit_pg3 = kzalloc(sz, GFP_KERNEL);
+       if (!io_unit_pg3) {
+               printk(MPT2SAS_ERR_FMT "%s: failed allocating memory"\
+                   "for iounit_pg3: (%d) bytes\n", ioc->name, __func__, sz);
+               goto out;
+       }
+
+       if (mpt2sas_config_get_iounit_pg3(ioc, &mpi_reply, io_unit_pg3, sz) !=
+           0) {
+               printk(MPT2SAS_ERR_FMT
+                   "%s: failed reading iounit_pg3\n", ioc->name,
+                   __func__);
+               goto out;
+       }
+
+       ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
+       if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+               printk(MPT2SAS_ERR_FMT "%s: iounit_pg3 failed with"\
+                   "ioc_status(0x%04x)\n", ioc->name, __func__, ioc_status);
+               goto out;
+       }
+
+       if (io_unit_pg3->GPIOCount < 25) {
+               printk(MPT2SAS_ERR_FMT "%s: iounit_pg3->GPIOCount less than"\
+                    "25 entries, detected (%d) entries\n", ioc->name, __func__,
+                   io_unit_pg3->GPIOCount);
+               goto out;
+       }
+
+       /* BRM status is in bit zero of GPIOVal[24] */
+       backup_rail_monitor_status = le16_to_cpu(io_unit_pg3->GPIOVal[24]);
+       rc = snprintf(buf, PAGE_SIZE, "%d\n", (backup_rail_monitor_status & 1));
+
+ out:
+       kfree(io_unit_pg3);
+       return rc;
+}
+static DEVICE_ATTR(BRM_status, S_IRUGO, _ctl_BRM_status_show, NULL);
+
 struct DIAG_BUFFER_START {
        __le32 Size;
        __le32 DiagVersion;
@@ -2901,6 +2970,7 @@ struct device_attribute *mpt2sas_host_attrs[] = {
        &dev_attr_host_trace_buffer,
        &dev_attr_host_trace_buffer_enable,
        &dev_attr_reply_queue_count,
+       &dev_attr_BRM_status,
        NULL,
 };
 
index 11ff1d5fb8f0dfe6a1c691421c003c07f4ddef1e..b5eb0d1b8ea6517bb91209d4f1d69e746ebc010d 100644 (file)
@@ -3,7 +3,7 @@
  * controllers
  *
  * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.h
- * Copyright (C) 2007-2010  LSI Corporation
+ * Copyright (C) 2007-2012  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
index 9731f8e661bf8a909237271946a02af2104cdefe..69cc7d0c112cb75f2df3533fb9c2eb49a9ad41f3 100644 (file)
@@ -2,7 +2,7 @@
  * Logging Support for MPT (Message Passing Technology) based controllers
  *
  * This code is based on drivers/scsi/mpt2sas/mpt2_debug.c
- * Copyright (C) 2007-2010  LSI Corporation
+ * Copyright (C) 2007-2012  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
index b1ebd6f8dab3b24d0894d149c26614b4a1e93932..7d774c5ffceef522cb2201294c68901ed9d78a86 100644 (file)
@@ -2,7 +2,7 @@
  * Scsi Host Layer for MPT (Message Passing Technology) based controllers
  *
  * This code is based on drivers/scsi/mpt2sas/mpt2_scsih.c
- * Copyright (C) 2007-2010  LSI Corporation
+ * Copyright (C) 2007-2012  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -119,6 +119,10 @@ module_param(diag_buffer_enable, int, 0);
 MODULE_PARM_DESC(diag_buffer_enable, " post diag buffers "
        "(TRACE=1/SNAPSHOT=2/EXTENDED=4/default=0)");
 
+static int disable_discovery = -1;
+module_param(disable_discovery, int, 0);
+MODULE_PARM_DESC(disable_discovery, " disable discovery ");
+
 /**
  * struct sense_info - common structure for obtaining sense keys
  * @skey: sense key
@@ -5973,8 +5977,14 @@ _scsih_sas_discovery_event(struct MPT2SAS_ADAPTER *ioc,
 #endif
 
        if (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED &&
-           !ioc->sas_hba.num_phys)
+           !ioc->sas_hba.num_phys) {
+               if (disable_discovery > 0 && ioc->shost_recovery) {
+                       /* Wait for the reset to complete */
+                       while (ioc->shost_recovery)
+                               ssleep(1);
+               }
                _scsih_sas_host_add(ioc);
+       }
 }
 
 /**
@@ -7254,7 +7264,8 @@ mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
                _scsih_search_responding_sas_devices(ioc);
                _scsih_search_responding_raid_devices(ioc);
                _scsih_search_responding_expanders(ioc);
-               if (!ioc->is_driver_loading) {
+               if ((!ioc->is_driver_loading) && !(disable_discovery > 0 &&
+                   !ioc->sas_hba.num_phys)) {
                        _scsih_prep_device_scan(ioc);
                        _scsih_search_responding_sas_devices(ioc);
                        _scsih_search_responding_raid_devices(ioc);
@@ -7929,6 +7940,9 @@ _scsih_scan_start(struct Scsi_Host *shost)
        if (diag_buffer_enable != -1 && diag_buffer_enable != 0)
                mpt2sas_enable_diag_buffer(ioc, diag_buffer_enable);
 
+       if (disable_discovery > 0)
+               return;
+
        ioc->start_scan = 1;
        rc = mpt2sas_port_enable(ioc);
 
@@ -7950,6 +7964,12 @@ _scsih_scan_finished(struct Scsi_Host *shost, unsigned long time)
 {
        struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
 
+       if (disable_discovery > 0) {
+               ioc->is_driver_loading = 0;
+               ioc->wait_for_discovery_to_complete = 0;
+               return 1;
+       }
+
        if (time >= (300 * HZ)) {
                ioc->base_cmds.status = MPT2_CMD_NOT_USED;
                printk(MPT2SAS_INFO_FMT "port enable: FAILED with timeout "
@@ -8055,8 +8075,8 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        if (max_sectors != 0xFFFF) {
                if (max_sectors < 64) {
                        shost->max_sectors = 64;
-                       printk(MPT2SAS_WARN_FMT "Invalid value %d passed "
-                           "for max_sectors, range is 64 to 8192. Assigning "
+                       printk(MPT2SAS_WARN_FMT "Invalid value %d passed "\
+                           "for max_sectors, range is 64 to 32767. Assigning "\
                            "value of 64.\n", ioc->name, max_sectors);
                } else if (max_sectors > 32767) {
                        shost->max_sectors = 32767;
index c6cf20f60720bfc6dd2a59b96fe951ae6139c48a..8c2ffbe6af0f1dbd67e724507101eabe5e0ceca6 100644 (file)
@@ -2,7 +2,7 @@
  * SAS Transport Layer for MPT (Message Passing Technology) based controllers
  *
  * This code is based on drivers/scsi/mpt2sas/mpt2_transport.c
- * Copyright (C) 2007-2010  LSI Corporation
+ * Copyright (C) 2007-2012  LSI Corporation
  *  (mailto:DL-MPTFusionLinux@lsi.com)
  *
  * This program is free software; you can redistribute it and/or
index ffd77739ae3e2bc4bf793fe7b4bb0ed37c3ca8f4..faa790fba1347fc61b0869015e2a28bad4f113f2 100644 (file)
@@ -776,7 +776,6 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
        }
 
        if (req->cmd_type == REQ_TYPE_BLOCK_PC) { /* SG_IO ioctl from block level */
-               req->errors = result;
                if (result) {
                        if (sense_valid && req->sense) {
                                /*
@@ -792,6 +791,10 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
                        if (!sense_deferred)
                                error = __scsi_error_from_host_byte(cmd, result);
                }
+               /*
+                * __scsi_error_from_host_byte may have reset the host_byte
+                */
+               req->errors = cmd->result;
 
                req->resid_len = scsi_get_resid(cmd);
 
index 2374468615ed57c147d9ba24489818268765ee70..32c26d795ed06d3a58c43bf3d295d8f75dcf676f 100644 (file)
@@ -324,8 +324,16 @@ int __init register_intc_controller(struct intc_desc *desc)
 
                res = irq_create_identity_mapping(d->domain, irq);
                if (unlikely(res)) {
-                       pr_err("can't get irq_desc for %d\n", irq);
-                       continue;
+                       if (res == -EEXIST) {
+                               res = irq_domain_associate(d->domain, irq, irq);
+                               if (unlikely(res)) {
+                                       pr_err("domain association failure\n");
+                                       continue;
+                               }
+                       } else {
+                               pr_err("can't identity map IRQ %d\n", irq);
+                               continue;
+                       }
                }
 
                intc_irq_xlate_set(irq, vect->enum_id, d);
@@ -345,8 +353,19 @@ int __init register_intc_controller(struct intc_desc *desc)
                         */
                        res = irq_create_identity_mapping(d->domain, irq2);
                        if (unlikely(res)) {
-                               pr_err("can't get irq_desc for %d\n", irq2);
-                               continue;
+                               if (res == -EEXIST) {
+                                       res = irq_domain_associate(d->domain,
+                                                                  irq, irq);
+                                       if (unlikely(res)) {
+                                               pr_err("domain association "
+                                                      "failure\n");
+                                               continue;
+                                       }
+                               } else {
+                                       pr_err("can't identity map IRQ %d\n",
+                                              irq);
+                                       continue;
+                               }
                        }
 
                        vect2->enum_id = 0;
index c00d00e96ee43784d8cd37715258f760a54bcbf8..f1fec2a19d101b110ec3da178299400afb2a1e29 100644 (file)
@@ -307,8 +307,6 @@ static const struct of_device_id altera_spi_match[] = {
        {},
 };
 MODULE_DEVICE_TABLE(of, altera_spi_match);
-#else /* CONFIG_OF */
-#define altera_spi_match NULL
 #endif /* CONFIG_OF */
 
 static struct platform_driver altera_spi_driver = {
@@ -318,7 +316,7 @@ static struct platform_driver altera_spi_driver = {
                .name = DRV_NAME,
                .owner = THIS_MODULE,
                .pm = NULL,
-               .of_match_table = altera_spi_match,
+               .of_match_table = of_match_ptr(altera_spi_match),
        },
 };
 module_platform_driver(altera_spi_driver);
index 6e25ef1bce91f98549e5b514c051fd065deb6fbc..6d97047d9242dbe495a2d209255f47fa98f24208 100644 (file)
@@ -36,7 +36,6 @@
 #include <bcm63xx_dev_spi.h>
 
 #define PFX            KBUILD_MODNAME
-#define DRV_VER                "0.1.2"
 
 struct bcm63xx_spi {
        struct completion       done;
@@ -47,6 +46,8 @@ struct bcm63xx_spi {
        /* Platform data */
        u32                     speed_hz;
        unsigned                fifo_size;
+       unsigned int            msg_type_shift;
+       unsigned int            msg_ctl_width;
 
        /* Data buffers */
        const unsigned char     *tx_ptr;
@@ -168,13 +169,6 @@ static int bcm63xx_spi_setup(struct spi_device *spi)
                return -EINVAL;
        }
 
-       ret = bcm63xx_spi_check_transfer(spi, NULL);
-       if (ret < 0) {
-               dev_err(&spi->dev, "setup: unsupported mode bits %x\n",
-                       spi->mode & ~MODEBITS);
-               return ret;
-       }
-
        dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec/bit\n",
                __func__, spi->mode & MODEBITS, spi->bits_per_word, 0);
 
@@ -221,13 +215,20 @@ static unsigned int bcm63xx_txrx_bufs(struct spi_device *spi,
        msg_ctl = (t->len << SPI_BYTE_CNT_SHIFT);
 
        if (t->rx_buf && t->tx_buf)
-               msg_ctl |= (SPI_FD_RW << SPI_MSG_TYPE_SHIFT);
+               msg_ctl |= (SPI_FD_RW << bs->msg_type_shift);
        else if (t->rx_buf)
-               msg_ctl |= (SPI_HD_R << SPI_MSG_TYPE_SHIFT);
+               msg_ctl |= (SPI_HD_R << bs->msg_type_shift);
        else if (t->tx_buf)
-               msg_ctl |= (SPI_HD_W << SPI_MSG_TYPE_SHIFT);
-
-       bcm_spi_writew(bs, msg_ctl, SPI_MSG_CTL);
+               msg_ctl |= (SPI_HD_W << bs->msg_type_shift);
+
+       switch (bs->msg_ctl_width) {
+       case 8:
+               bcm_spi_writeb(bs, msg_ctl, SPI_MSG_CTL);
+               break;
+       case 16:
+               bcm_spi_writew(bs, msg_ctl, SPI_MSG_CTL);
+               break;
+       }
 
        /* Issue the transfer */
        cmd = SPI_CMD_START_IMMEDIATE;
@@ -406,9 +407,21 @@ static int __devinit bcm63xx_spi_probe(struct platform_device *pdev)
        master->transfer_one_message = bcm63xx_spi_transfer_one;
        master->mode_bits = MODEBITS;
        bs->speed_hz = pdata->speed_hz;
+       bs->msg_type_shift = pdata->msg_type_shift;
+       bs->msg_ctl_width = pdata->msg_ctl_width;
        bs->tx_io = (u8 *)(bs->regs + bcm63xx_spireg(SPI_MSG_DATA));
        bs->rx_io = (const u8 *)(bs->regs + bcm63xx_spireg(SPI_RX_DATA));
 
+       switch (bs->msg_ctl_width) {
+       case 8:
+       case 16:
+               break;
+       default:
+               dev_err(dev, "unsupported MSG_CTL width: %d\n",
+                        bs->msg_ctl_width);
+               goto out_clk_disable;
+       }
+
        /* Initialize hardware */
        clk_enable(bs->clk);
        bcm_spi_writeb(bs, SPI_INTR_CLEAR_ALL, SPI_INT_STATUS);
@@ -420,8 +433,8 @@ static int __devinit bcm63xx_spi_probe(struct platform_device *pdev)
                goto out_clk_disable;
        }
 
-       dev_info(dev, "at 0x%08x (irq %d, FIFOs size %d) v%s\n",
-                r->start, irq, bs->fifo_size, DRV_VER);
+       dev_info(dev, "at 0x%08x (irq %d, FIFOs size %d)\n",
+                r->start, irq, bs->fifo_size);
 
        return 0;
 
@@ -438,7 +451,7 @@ out:
 
 static int __devexit bcm63xx_spi_remove(struct platform_device *pdev)
 {
-       struct spi_master *master = platform_get_drvdata(pdev);
+       struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
        struct bcm63xx_spi *bs = spi_master_get_devdata(master);
 
        spi_unregister_master(master);
@@ -452,6 +465,8 @@ static int __devexit bcm63xx_spi_remove(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, 0);
 
+       spi_master_put(master);
+
        return 0;
 }
 
@@ -462,6 +477,8 @@ static int bcm63xx_spi_suspend(struct device *dev)
                        platform_get_drvdata(to_platform_device(dev));
        struct bcm63xx_spi *bs = spi_master_get_devdata(master);
 
+       spi_master_suspend(master);
+
        clk_disable(bs->clk);
 
        return 0;
@@ -475,6 +492,8 @@ static int bcm63xx_spi_resume(struct device *dev)
 
        clk_enable(bs->clk);
 
+       spi_master_resume(master);
+
        return 0;
 }
 
index e834ff8c0188281dc0fe25304c31df4294afde5f..3bd9c691b796d181557a8bd71dc645a586da9391 100644 (file)
@@ -97,7 +97,7 @@ struct spi_imx_data {
        const void *tx_buf;
        unsigned int txfifo; /* number of words pushed in tx FIFO */
 
-       struct spi_imx_devtype_data *devtype_data;
+       const struct spi_imx_devtype_data *devtype_data;
        int chipselect[0];
 };
 
index bc4778175e343c6a9ebeceac09b0cc543c935bc2..569714ebffe073c888698bb349b1f57a688d75d2 100644 (file)
@@ -1116,7 +1116,7 @@ MODULE_DEVICE_TABLE(of, omap_mcspi_of_match);
 static int __devinit omap2_mcspi_probe(struct platform_device *pdev)
 {
        struct spi_master       *master;
-       struct omap2_mcspi_platform_config *pdata;
+       const struct omap2_mcspi_platform_config *pdata;
        struct omap2_mcspi      *mcspi;
        struct resource         *r;
        int                     status = 0, i;
@@ -1228,18 +1228,16 @@ static int __devinit omap2_mcspi_probe(struct platform_device *pdev)
 
        status = spi_register_master(master);
        if (status < 0)
-               goto err_spi_register;
+               goto disable_pm;
 
        return status;
 
-err_spi_register:
-       spi_master_put(master);
 disable_pm:
        pm_runtime_disable(&pdev->dev);
 dma_chnl_free:
        kfree(mcspi->dma_channels);
 free_master:
-       kfree(master);
+       spi_master_put(master);
        platform_set_drvdata(pdev, NULL);
        return status;
 }
index 9b0caddce5037b5b347615969ae9c6bd22eaf8f7..b17c09cf0a054c271cbd2f9e4c0841a0364d2706 100644 (file)
 #define ORION_SPI_CLK_PRESCALE_MASK    0x1F
 
 struct orion_spi {
-       struct work_struct      work;
-
-       /* Lock access to transfer list.        */
-       spinlock_t              lock;
-
-       struct list_head        msg_queue;
        struct spi_master       *master;
        void __iomem            *base;
        unsigned int            max_speed;
@@ -49,8 +43,6 @@ struct orion_spi {
        struct clk              *clk;
 };
 
-static struct workqueue_struct *orion_spi_wq;
-
 static inline void __iomem *spi_reg(struct orion_spi *orion_spi, u32 reg)
 {
        return orion_spi->base + reg;
@@ -277,73 +269,78 @@ out:
 }
 
 
-static void orion_spi_work(struct work_struct *work)
+static int orion_spi_transfer_one_message(struct spi_master *master,
+                                          struct spi_message *m)
 {
-       struct orion_spi *orion_spi =
-               container_of(work, struct orion_spi, work);
-
-       spin_lock_irq(&orion_spi->lock);
-       while (!list_empty(&orion_spi->msg_queue)) {
-               struct spi_message *m;
-               struct spi_device *spi;
-               struct spi_transfer *t = NULL;
-               int par_override = 0;
-               int status = 0;
-               int cs_active = 0;
-
-               m = container_of(orion_spi->msg_queue.next, struct spi_message,
-                                queue);
+       struct orion_spi *orion_spi = spi_master_get_devdata(master);
+       struct spi_device *spi = m->spi;
+       struct spi_transfer *t = NULL;
+       int par_override = 0;
+       int status = 0;
+       int cs_active = 0;
 
-               list_del_init(&m->queue);
-               spin_unlock_irq(&orion_spi->lock);
+       /* Load defaults */
+       status = orion_spi_setup_transfer(spi, NULL);
 
-               spi = m->spi;
+       if (status < 0)
+               goto msg_done;
 
-               /* Load defaults */
-               status = orion_spi_setup_transfer(spi, NULL);
+       list_for_each_entry(t, &m->transfers, transfer_list) {
+               /* make sure buffer length is even when working in 16
+                * bit mode*/
+               if ((t->bits_per_word == 16) && (t->len & 1)) {
+                       dev_err(&spi->dev,
+                               "message rejected : "
+                               "odd data length %d while in 16 bit mode\n",
+                               t->len);
+                       status = -EIO;
+                       goto msg_done;
+               }
 
-               if (status < 0)
+               if (t->speed_hz && t->speed_hz < orion_spi->min_speed) {
+                       dev_err(&spi->dev,
+                               "message rejected : "
+                               "device min speed (%d Hz) exceeds "
+                               "required transfer speed (%d Hz)\n",
+                               orion_spi->min_speed, t->speed_hz);
+                       status = -EIO;
                        goto msg_done;
+               }
 
-               list_for_each_entry(t, &m->transfers, transfer_list) {
-                       if (par_override || t->speed_hz || t->bits_per_word) {
-                               par_override = 1;
-                               status = orion_spi_setup_transfer(spi, t);
-                               if (status < 0)
-                                       break;
-                               if (!t->speed_hz && !t->bits_per_word)
-                                       par_override = 0;
-                       }
-
-                       if (!cs_active) {
-                               orion_spi_set_cs(orion_spi, 1);
-                               cs_active = 1;
-                       }
-
-                       if (t->len)
-                               m->actual_length +=
-                                       orion_spi_write_read(spi, t);
-
-                       if (t->delay_usecs)
-                               udelay(t->delay_usecs);
-
-                       if (t->cs_change) {
-                               orion_spi_set_cs(orion_spi, 0);
-                               cs_active = 0;
-                       }
+               if (par_override || t->speed_hz || t->bits_per_word) {
+                       par_override = 1;
+                       status = orion_spi_setup_transfer(spi, t);
+                       if (status < 0)
+                               break;
+                       if (!t->speed_hz && !t->bits_per_word)
+                               par_override = 0;
                }
 
-msg_done:
-               if (cs_active)
-                       orion_spi_set_cs(orion_spi, 0);
+               if (!cs_active) {
+                       orion_spi_set_cs(orion_spi, 1);
+                       cs_active = 1;
+               }
 
-               m->status = status;
-               m->complete(m->context);
+               if (t->len)
+                       m->actual_length += orion_spi_write_read(spi, t);
 
-               spin_lock_irq(&orion_spi->lock);
+               if (t->delay_usecs)
+                       udelay(t->delay_usecs);
+
+               if (t->cs_change) {
+                       orion_spi_set_cs(orion_spi, 0);
+                       cs_active = 0;
+               }
        }
 
-       spin_unlock_irq(&orion_spi->lock);
+msg_done:
+       if (cs_active)
+               orion_spi_set_cs(orion_spi, 0);
+
+       m->status = status;
+       spi_finalize_current_message(master);
+
+       return 0;
 }
 
 static int __init orion_spi_reset(struct orion_spi *orion_spi)
@@ -376,75 +373,6 @@ static int orion_spi_setup(struct spi_device *spi)
        return 0;
 }
 
-static int orion_spi_transfer(struct spi_device *spi, struct spi_message *m)
-{
-       struct orion_spi *orion_spi;
-       struct spi_transfer *t = NULL;
-       unsigned long flags;
-
-       m->actual_length = 0;
-       m->status = 0;
-
-       /* reject invalid messages and transfers */
-       if (list_empty(&m->transfers) || !m->complete)
-               return -EINVAL;
-
-       orion_spi = spi_master_get_devdata(spi->master);
-
-       list_for_each_entry(t, &m->transfers, transfer_list) {
-               unsigned int bits_per_word = spi->bits_per_word;
-
-               if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
-                       dev_err(&spi->dev,
-                               "message rejected : "
-                               "invalid transfer data buffers\n");
-                       goto msg_rejected;
-               }
-
-               if (t->bits_per_word)
-                       bits_per_word = t->bits_per_word;
-
-               if ((bits_per_word != 8) && (bits_per_word != 16)) {
-                       dev_err(&spi->dev,
-                               "message rejected : "
-                               "invalid transfer bits_per_word (%d bits)\n",
-                               bits_per_word);
-                       goto msg_rejected;
-               }
-               /*make sure buffer length is even when working in 16 bit mode*/
-               if ((t->bits_per_word == 16) && (t->len & 1)) {
-                       dev_err(&spi->dev,
-                               "message rejected : "
-                               "odd data length (%d) while in 16 bit mode\n",
-                               t->len);
-                       goto msg_rejected;
-               }
-
-               if (t->speed_hz && t->speed_hz < orion_spi->min_speed) {
-                       dev_err(&spi->dev,
-                               "message rejected : "
-                               "device min speed (%d Hz) exceeds "
-                               "required transfer speed (%d Hz)\n",
-                               orion_spi->min_speed, t->speed_hz);
-                       goto msg_rejected;
-               }
-       }
-
-
-       spin_lock_irqsave(&orion_spi->lock, flags);
-       list_add_tail(&m->queue, &orion_spi->msg_queue);
-       queue_work(orion_spi_wq, &orion_spi->work);
-       spin_unlock_irqrestore(&orion_spi->lock, flags);
-
-       return 0;
-msg_rejected:
-       /* Message rejected and not queued */
-       m->status = -EINVAL;
-       if (m->complete)
-               m->complete(m->context);
-       return -EINVAL;
-}
-
 static int __init orion_spi_probe(struct platform_device *pdev)
 {
        struct spi_master *master;
@@ -474,7 +402,7 @@ static int __init orion_spi_probe(struct platform_device *pdev)
        master->mode_bits = 0;
 
        master->setup = orion_spi_setup;
-       master->transfer = orion_spi_transfer;
+       master->transfer_one_message = orion_spi_transfer_one_message;
        master->num_chipselect = ORION_NUM_CHIPSELECTS;
 
        dev_set_drvdata(&pdev->dev, master);
@@ -507,11 +435,6 @@ static int __init orion_spi_probe(struct platform_device *pdev)
        }
        spi->base = ioremap(r->start, SZ_1K);
 
-       INIT_WORK(&spi->work, orion_spi_work);
-
-       spin_lock_init(&spi->lock);
-       INIT_LIST_HEAD(&spi->msg_queue);
-
        if (orion_spi_reset(spi) < 0)
                goto out_rel_mem;
 
@@ -536,14 +459,12 @@ out:
 static int __exit orion_spi_remove(struct platform_device *pdev)
 {
        struct spi_master *master;
-       struct orion_spi *spi;
        struct resource *r;
+       struct orion_spi *spi;
 
        master = dev_get_drvdata(&pdev->dev);
        spi = spi_master_get_devdata(master);
 
-       cancel_work_sync(&spi->work);
-
        clk_disable_unprepare(spi->clk);
        clk_put(spi->clk);
 
@@ -574,21 +495,13 @@ static struct platform_driver orion_spi_driver = {
 
 static int __init orion_spi_init(void)
 {
-       orion_spi_wq = create_singlethread_workqueue(
-                               orion_spi_driver.driver.name);
-       if (orion_spi_wq == NULL)
-               return -ENOMEM;
-
        return platform_driver_probe(&orion_spi_driver, orion_spi_probe);
 }
 module_init(orion_spi_init);
 
 static void __exit orion_spi_exit(void)
 {
-       flush_workqueue(orion_spi_wq);
        platform_driver_unregister(&orion_spi_driver);
-
-       destroy_workqueue(orion_spi_wq);
 }
 module_exit(orion_spi_exit);
 
index 646a7657fe62fbb545f95fc771b406d0cad6e5f9..c36abe4e6ef1623f6470b60038dc7a3820f4c3aa 100644 (file)
@@ -214,6 +214,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;
@@ -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;
@@ -826,7 +824,7 @@ static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata(
                                struct spi_device *spi)
 {
        struct s3c64xx_spi_csinfo *cs;
-       struct device_node *slave_np, *data_np;
+       struct device_node *slave_np, *data_np = NULL;
        u32 fb_delay = 0;
 
        slave_np = spi->dev.of_node;
@@ -1479,40 +1477,40 @@ static const struct dev_pm_ops s3c64xx_spi_pm = {
                           s3c64xx_spi_runtime_resume, NULL)
 };
 
-struct s3c64xx_spi_port_config s3c2443_spi_port_config = {
+static struct s3c64xx_spi_port_config s3c2443_spi_port_config = {
        .fifo_lvl_mask  = { 0x7f },
        .rx_lvl_offset  = 13,
        .tx_st_done     = 21,
        .high_speed     = true,
 };
 
-struct s3c64xx_spi_port_config s3c6410_spi_port_config = {
+static struct s3c64xx_spi_port_config s3c6410_spi_port_config = {
        .fifo_lvl_mask  = { 0x7f, 0x7F },
        .rx_lvl_offset  = 13,
        .tx_st_done     = 21,
 };
 
-struct s3c64xx_spi_port_config s5p64x0_spi_port_config = {
+static struct s3c64xx_spi_port_config s5p64x0_spi_port_config = {
        .fifo_lvl_mask  = { 0x1ff, 0x7F },
        .rx_lvl_offset  = 15,
        .tx_st_done     = 25,
 };
 
-struct s3c64xx_spi_port_config s5pc100_spi_port_config = {
+static struct s3c64xx_spi_port_config s5pc100_spi_port_config = {
        .fifo_lvl_mask  = { 0x7f, 0x7F },
        .rx_lvl_offset  = 13,
        .tx_st_done     = 21,
        .high_speed     = true,
 };
 
-struct s3c64xx_spi_port_config s5pv210_spi_port_config = {
+static struct s3c64xx_spi_port_config s5pv210_spi_port_config = {
        .fifo_lvl_mask  = { 0x1ff, 0x7F },
        .rx_lvl_offset  = 15,
        .tx_st_done     = 25,
        .high_speed     = true,
 };
 
-struct s3c64xx_spi_port_config exynos4_spi_port_config = {
+static struct s3c64xx_spi_port_config exynos4_spi_port_config = {
        .fifo_lvl_mask  = { 0x1ff, 0x7F, 0x7F },
        .rx_lvl_offset  = 15,
        .tx_st_done     = 25,
index 84c2861d6f4dde2a602e44f292c6efbd248c602b..fc0da392c424873b2c00b288e7b98cd264165d44 100644 (file)
@@ -813,6 +813,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;
 
@@ -874,7 +875,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 7e2ddc042f5bff19954bc4d61200a36bf6523609..c6250867a95d4cb0de8ec92e498b995aaf84d99f 100644 (file)
@@ -190,16 +190,30 @@ static void ssb_mips_flash_detect(struct ssb_mipscore *mcore)
 {
        struct ssb_bus *bus = mcore->dev->bus;
 
-       mcore->flash_buswidth = 2;
-       if (bus->chipco.dev) {
-               mcore->flash_window = 0x1c000000;
-               mcore->flash_window_size = 0x02000000;
+       /* When there is no chipcommon on the bus there is 4MB flash */
+       if (!bus->chipco.dev) {
+               mcore->flash_buswidth = 2;
+               mcore->flash_window = SSB_FLASH1;
+               mcore->flash_window_size = SSB_FLASH1_SZ;
+               return;
+       }
+
+       /* There is ChipCommon, so use it to read info about flash */
+       switch (bus->chipco.capabilities & SSB_CHIPCO_CAP_FLASHT) {
+       case SSB_CHIPCO_FLASHT_STSER:
+       case SSB_CHIPCO_FLASHT_ATSER:
+               pr_err("Serial flash not supported\n");
+               break;
+       case SSB_CHIPCO_FLASHT_PARA:
+               pr_debug("Found parallel flash\n");
+               mcore->flash_window = SSB_FLASH2;
+               mcore->flash_window_size = SSB_FLASH2_SZ;
                if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG)
                               & SSB_CHIPCO_CFG_DS16) == 0)
                        mcore->flash_buswidth = 1;
-       } else {
-               mcore->flash_window = 0x1fc00000;
-               mcore->flash_window_size = 0x00400000;
+               else
+                       mcore->flash_buswidth = 2;
+               break;
        }
 }
 
index 69cf2db1d69cdc380b3c9b8af87d5e617a99b11d..94a740d2883dde4cce85a2e4859a0e94a949d436 100644 (file)
@@ -1,20 +1,20 @@
 /* mm/ashmem.c
-**
-** Anonymous Shared Memory Subsystem, ashmem
-**
-** Copyright (C) 2008 Google, Inc.
-**
-** Robert Love <rlove@google.com>
-**
-** 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.
-*/
+ *
+ * Anonymous Shared Memory Subsystem, ashmem
+ *
+ * Copyright (C) 2008 Google, Inc.
+ *
+ * Robert Love <rlove@google.com>
+ *
+ * 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.
+ */
 
 #define pr_fmt(fmt) "ashmem: " fmt
 
index f7b8237d5be74bd284c2fe561defb3b9902b224d..1d5ed475364b34541c513e7dccb5eaa66cfeeeb4 100644 (file)
 
 #include <asm/ioctls.h>
 
-/*
+/**
  * struct logger_log - represents a specific log, such as 'main' or 'radio'
+ * @buffer:    The actual ring buffer
+ * @misc:      The "misc" device representing the log
+ * @wq:                The wait queue for @readers
+ * @readers:   This log's readers
+ * @mutex:     The mutex that protects the @buffer
+ * @w_off:     The current write head offset
+ * @head:      The head, or location that readers start reading at.
+ * @size:      The size of the log
+ * @logs:      The list of log channels
  *
  * This structure lives from module insertion until module removal, so it does
  * not need additional reference counting. The structure is protected by the
  * mutex 'mutex'.
  */
 struct logger_log {
-       unsigned char           *buffer;/* the ring buffer itself */
-       struct miscdevice       misc;   /* misc device representing the log */
-       wait_queue_head_t       wq;     /* wait queue for readers */
-       struct list_head        readers; /* this log's readers */
-       struct mutex            mutex;  /* mutex protecting buffer */
-       size_t                  w_off;  /* current write head offset */
-       size_t                  head;   /* new readers start here */
-       size_t                  size;   /* size of the log */
-       struct list_head        logs;   /* list of log channels (myself)*/
+       unsigned char           *buffer;
+       struct miscdevice       misc;
+       wait_queue_head_t       wq;
+       struct list_head        readers;
+       struct mutex            mutex;
+       size_t                  w_off;
+       size_t                  head;
+       size_t                  size;
+       struct list_head        logs;
 };
 
 static LIST_HEAD(log_list);
 
 
-/*
+/**
  * struct logger_reader - a logging device open for reading
+ * @log:       The associated log
+ * @list:      The associated entry in @logger_log's list
+ * @r_off:     The current read head offset.
  *
  * This object lives from open to release, so we don't need additional
  * reference counting. The structure is protected by log->mutex.
  */
 struct logger_reader {
-       struct logger_log       *log;   /* associated log */
-       struct list_head        list;   /* entry in logger_log's list */
-       size_t                  r_off;  /* current read head offset */
+       struct logger_log       *log;
+       struct list_head        list;
+       size_t                  r_off;
 };
 
 /* logger_offset - returns index 'n' into the log via (optimized) modulus */
index 2cb06e9d8f9821ea6aa98b63d2a79b4e3b171578..9b929a8c7468b37dadfc0d30db6c644be03b0991 100644 (file)
 #include <linux/types.h>
 #include <linux/ioctl.h>
 
+/**
+ * struct logger_entry - defines a single entry that is given to a logger
+ * @len:       The length of the payload
+ * @__pad:     Two bytes of padding that appear to be required
+ * @pid:       The generating process' process ID
+ * @tid:       The generating process' thread ID
+ * @sec:       The number of seconds that have elapsed since the Epoch
+ * @nsec:      The number of nanoseconds that have elapsed since @sec
+ * @msg:       The message that is to be logged
+ */
 struct logger_entry {
-       __u16           len;    /* length of the payload */
-       __u16           __pad;  /* no matter what, we get 2 bytes of padding */
-       __s32           pid;    /* generating process's pid */
-       __s32           tid;    /* generating process's tid */
-       __s32           sec;    /* seconds since Epoch */
-       __s32           nsec;   /* nanoseconds */
-       char            msg[0]; /* the entry's payload */
+       __u16           len;
+       __u16           __pad;
+       __s32           pid;
+       __s32           tid;
+       __s32           sec;
+       __s32           nsec;
+       char            msg[0];
 };
 
 #define LOGGER_LOG_RADIO       "log_radio"     /* radio-related messages */
index 45c522cbe78446e0b0eb5e72fbf14e4a26f1d8b1..e81451425c012c42b7e032cfeb5455a17b6535b0 100644 (file)
@@ -161,18 +161,7 @@ static struct platform_driver timed_gpio_driver = {
        },
 };
 
-static int __init timed_gpio_init(void)
-{
-       return platform_driver_register(&timed_gpio_driver);
-}
-
-static void __exit timed_gpio_exit(void)
-{
-       platform_driver_unregister(&timed_gpio_driver);
-}
-
-module_init(timed_gpio_init);
-module_exit(timed_gpio_exit);
+module_platform_driver(timed_gpio_driver);
 
 MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
 MODULE_DESCRIPTION("timed gpio driver");
index f63c1d3aeb640b04c91e9c27efb7fffd71969f8f..42a5e7ab5122557ff9b293a4d0ab5c4e02ba7041 100644 (file)
@@ -42,8 +42,6 @@
 #define ASUS_OLED_NAME                 "asus-oled"
 #define ASUS_OLED_UNDERSCORE_NAME      "asus_oled"
 
-#define ASUS_OLED_ERROR                        "Asus OLED Display Error: "
-
 #define ASUS_OLED_STATIC               's'
 #define ASUS_OLED_ROLL                 'r'
 #define ASUS_OLED_FLASH                        'f'
@@ -57,8 +55,9 @@
 #define USB_DEVICE_ID_ASUS_LCM2     0x175b
 
 MODULE_AUTHOR("Jakub Schmidtke, sjakub@gmail.com");
-MODULE_DESCRIPTION("Asus OLED Driver v" ASUS_OLED_VERSION);
+MODULE_DESCRIPTION("Asus OLED Driver");
 MODULE_LICENSE("GPL");
+MODULE_VERSION(ASUS_OLED_VERSION);
 
 static struct class *oled_class;
 static int oled_num;
@@ -383,13 +382,13 @@ static int append_values(struct asus_oled_dev *odev, uint8_t val, size_t count)
 
                default:
                        i = 0;
-                       printk(ASUS_OLED_ERROR "Unknown OLED Pack Mode: %d!\n",
+                       dev_err(odev->dev, "Unknown OLED Pack Mode: %d!\n",
                               odev->pack_mode);
                        break;
                }
 
                if (i >= odev->buf_size) {
-                       printk(ASUS_OLED_ERROR "Buffer overflow! Report a bug:"
+                       dev_err(odev->dev, "Buffer overflow! Report a bug:"
                               "offs: %d >= %d i: %d (x: %d y: %d)\n",
                               (int) odev->buf_offs, (int) odev->buf_size,
                               (int) i, (int) x, (int) y);
@@ -435,7 +434,7 @@ static ssize_t odev_set_picture(struct asus_oled_dev *odev,
                odev->buf = kmalloc(odev->buf_size, GFP_KERNEL);
                if (odev->buf == NULL) {
                        odev->buf_size = 0;
-                       printk(ASUS_OLED_ERROR "Out of memory!\n");
+                       dev_err(odev->dev, "Out of memory!\n");
                        return -ENOMEM;
                }
 
@@ -473,7 +472,7 @@ static ssize_t odev_set_picture(struct asus_oled_dev *odev,
                        odev->pic_mode = buf[1];
                        break;
                default:
-                       printk(ASUS_OLED_ERROR "Wrong picture mode: '%c'.\n",
+                       dev_err(odev->dev, "Wrong picture mode: '%c'.\n",
                               buf[1]);
                        return -EIO;
                        break;
@@ -533,7 +532,7 @@ static ssize_t odev_set_picture(struct asus_oled_dev *odev,
 
                if (odev->buf == NULL) {
                        odev->buf_size = 0;
-                       printk(ASUS_OLED_ERROR "Out of memory!\n");
+                       dev_err(odev->dev, "Out of memory!\n");
                        return -ENOMEM;
                }
 
@@ -593,15 +592,15 @@ static ssize_t odev_set_picture(struct asus_oled_dev *odev,
        return count;
 
 error_width:
-       printk(ASUS_OLED_ERROR "Wrong picture width specified.\n");
+       dev_err(odev->dev, "Wrong picture width specified.\n");
        return -EIO;
 
 error_height:
-       printk(ASUS_OLED_ERROR "Wrong picture height specified.\n");
+       dev_err(odev->dev, "Wrong picture height specified.\n");
        return -EIO;
 
 error_header:
-       printk(ASUS_OLED_ERROR "Wrong picture header.\n");
+       dev_err(odev->dev, "Wrong picture header.\n");
        return -EIO;
 }
 
index b54ec974477fbe46cc1cb974dec213f7bf43bdc0..b6c20a92cbf880553930771b6e190c025d51341e 100644 (file)
@@ -999,13 +999,10 @@ static VOID DumpCmControlPacket(PVOID pvBuffer)
 #ifdef VERSION_D5
                BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPv6FlowLableLength: 0x%X ",
                                psfCSType->cCPacketClassificationRule.u8IPv6FlowLableLength);
-               BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPv6FlowLable[6]: 0x %02X %02X %02X %02X %02X %02X ",
-                               psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[0],
-                               psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[1],
-                               psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[2],
-                               psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[3],
-                               psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[4],
-                               psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[5]);
+               BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL,
+                               DBG_LVL_ALL, "u8IPv6FlowLable[6]: 0x%*ph ",
+                               6, psfCSType->cCPacketClassificationRule.
+                                             u8IPv6FlowLable);
 #endif
        }
 
@@ -1015,13 +1012,9 @@ static VOID DumpCmControlPacket(PVOID pvBuffer)
        BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16CID: 0x%X", pstAddIndication->sfAdmittedSet.u16CID);
        BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ServiceClassNameLength: 0x%X",
                        pstAddIndication->sfAdmittedSet.u8ServiceClassNameLength);
-       BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ServiceClassName: 0x %02X %02X %02X %02X %02X %02X",
-                       pstAddIndication->sfAdmittedSet.u8ServiceClassName[0],
-                       pstAddIndication->sfAdmittedSet.u8ServiceClassName[1],
-                       pstAddIndication->sfAdmittedSet.u8ServiceClassName[2],
-                       pstAddIndication->sfAdmittedSet.u8ServiceClassName[3],
-                       pstAddIndication->sfAdmittedSet.u8ServiceClassName[4],
-                       pstAddIndication->sfAdmittedSet.u8ServiceClassName[5]);
+       BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,
+                       "u8ServiceClassName: 0x%*ph",
+                       6, pstAddIndication->sfAdmittedSet.u8ServiceClassName);
 
        BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8MBSService: 0x%02X", pstAddIndication->sfAdmittedSet.u8MBSService);
        BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8QosParamSet: 0x%02X", pstAddIndication->sfAdmittedSet.u8QosParamSet);
@@ -1074,10 +1067,10 @@ static VOID DumpCmControlPacket(PVOID pvBuffer)
                                psfCSType->cCPacketClassificationRule.u8ClassifierRulePriority);
                BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPTypeOfServiceLength: 0x%02X",
                                psfCSType->cCPacketClassificationRule.u8IPTypeOfServiceLength);
-               BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPTypeOfService[3]: 0x%02X %02X %02X",
-                               psfCSType->cCPacketClassificationRule.u8IPTypeOfService[0],
-                               psfCSType->cCPacketClassificationRule.u8IPTypeOfService[1],
-                               psfCSType->cCPacketClassificationRule.u8IPTypeOfService[2]);
+               BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL,
+                               DBG_LVL_ALL, "u8IPTypeOfService[3]: 0x%*ph",
+                               3, psfCSType->cCPacketClassificationRule.
+                                             u8IPTypeOfService);
                for (uiLoopIndex = 0; uiLoopIndex < 1; uiLoopIndex++)
                        BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8Protocol: 0x%02X ", psfCSType->cCPacketClassificationRule.u8Protocol);
 
@@ -1098,20 +1091,20 @@ static VOID DumpCmControlPacket(PVOID pvBuffer)
                BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ProtocolSourcePortRangeLength: 0x%02X ",
                                psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRangeLength);
 
-               BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ProtocolSourcePortRange[4]: 0x %02X %02X %02X %02X ",
-                               psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[0],
-                               psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[1],
-                               psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[2],
-                               psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[3]);
+               BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL,
+                               DBG_LVL_ALL, "u8ProtocolSourcePortRange[4]: "
+                               "0x%*ph ", 4, psfCSType->
+                                               cCPacketClassificationRule.
+                                               u8ProtocolSourcePortRange);
 
                BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ProtocolDestPortRangeLength: 0x%02X ",
                                psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRangeLength);
 
-               BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ProtocolDestPortRange[4]: 0x %02X %02X %02X %02X ",
-                               psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[0],
-                               psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[1],
-                               psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[2],
-                               psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[3]);
+               BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL,
+                               DBG_LVL_ALL, "u8ProtocolDestPortRange[4]: "
+                               "0x%*ph ", 4, psfCSType->
+                                               cCPacketClassificationRule.
+                                               u8ProtocolDestPortRange);
 
                BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8EthernetDestMacAddressLength: 0x%02X ",
                                psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddressLength);
@@ -1130,10 +1123,10 @@ static VOID DumpCmControlPacket(PVOID pvBuffer)
                                                u8EthernetSourceMACAddress);
 
                BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8EthertypeLength: 0x%02X ", psfCSType->cCPacketClassificationRule.u8EthertypeLength);
-               BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8Ethertype[3]: 0x%02X %02X %02X",
-                               psfCSType->cCPacketClassificationRule.u8Ethertype[0],
-                               psfCSType->cCPacketClassificationRule.u8Ethertype[1],
-                               psfCSType->cCPacketClassificationRule.u8Ethertype[2]);
+               BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL,
+                               DBG_LVL_ALL, "u8Ethertype[3]: 0x%*ph",
+                               3, psfCSType->cCPacketClassificationRule.
+                                             u8Ethertype);
 
                BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16UserPriority: 0x%X ", psfCSType->cCPacketClassificationRule.u16UserPriority);
                BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16VLANID: 0x%X ", psfCSType->cCPacketClassificationRule.u16VLANID);
@@ -1147,13 +1140,10 @@ static VOID DumpCmControlPacket(PVOID pvBuffer)
 #ifdef VERSION_D5
                BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPv6FlowLableLength: 0x%X ",
                                psfCSType->cCPacketClassificationRule.u8IPv6FlowLableLength);
-               BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPv6FlowLable[6]: 0x %02X %02X %02X %02X %02X %02X ",
-                               psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[0],
-                               psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[1],
-                               psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[2],
-                               psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[3],
-                               psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[4],
-                               psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[5]);
+               BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL,
+                               DBG_LVL_ALL, "u8IPv6FlowLable[6]: 0x%*ph ",
+                               6, psfCSType->cCPacketClassificationRule.
+                                             u8IPv6FlowLable);
 #endif
        }
 
@@ -1162,13 +1152,9 @@ static VOID DumpCmControlPacket(PVOID pvBuffer)
        BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32SFID: 0x%X", pstAddIndication->sfActiveSet.u32SFID);
        BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16CID: 0x%X", pstAddIndication->sfActiveSet.u16CID);
        BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ServiceClassNameLength: 0x%X", pstAddIndication->sfActiveSet.u8ServiceClassNameLength);
-       BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ServiceClassName: 0x %02X %02X %02X %02X %02X %02X",
-                       pstAddIndication->sfActiveSet.u8ServiceClassName[0],
-                       pstAddIndication->sfActiveSet.u8ServiceClassName[1],
-                       pstAddIndication->sfActiveSet.u8ServiceClassName[2],
-                       pstAddIndication->sfActiveSet.u8ServiceClassName[3],
-                       pstAddIndication->sfActiveSet.u8ServiceClassName[4],
-                       pstAddIndication->sfActiveSet.u8ServiceClassName[5]);
+       BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL,
+                       "u8ServiceClassName: 0x%*ph",
+                       6, pstAddIndication->sfActiveSet.u8ServiceClassName);
 
        BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8MBSService: 0x%02X", pstAddIndication->sfActiveSet.u8MBSService);
        BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8QosParamSet: 0x%02X", pstAddIndication->sfActiveSet.u8QosParamSet);
index f545716c666d06fac279d87bf8cfe69664eb595e..f13a9582a82f0007406f564a77d0ef444dbd0c91 100644 (file)
@@ -752,7 +752,10 @@ VOID DumpPackInfo(struct bcm_mini_adapter *Adapter)
                BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "AuthzSet: %x\n", Adapter->PackInfo[uiLoopIndex].bAuthorizedSet);
                BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "ClassifyPrority: %x\n", Adapter->PackInfo[uiLoopIndex].bClassifierPriority);
                BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "uiMaxLatency: %x\n", Adapter->PackInfo[uiLoopIndex].uiMaxLatency);
-               BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "ServiceClassName: %x %x %x %x\n", Adapter->PackInfo[uiLoopIndex].ucServiceClassName[0], Adapter->PackInfo[uiLoopIndex].ucServiceClassName[1], Adapter->PackInfo[uiLoopIndex].ucServiceClassName[2], Adapter->PackInfo[uiLoopIndex].ucServiceClassName[3]);
+               BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO,
+                               DBG_LVL_ALL, "ServiceClassName: %*ph\n",
+                               4, Adapter->PackInfo[uiLoopIndex].
+                                           ucServiceClassName);
 /* BCM_DEBUG_PRINT (Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "bHeaderSuppressionEnabled :%X\n", Adapter->PackInfo[uiLoopIndex].bHeaderSuppressionEnabled);
  * BCM_DEBUG_PRINT (Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "uiTotalTxBytes:%X\n", Adapter->PackInfo[uiLoopIndex].uiTotalTxBytes);
  * BCM_DEBUG_PRINT (Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "uiTotalRxBytes:%X\n", Adapter->PackInfo[uiLoopIndex].uiTotalRxBytes);
index 6a7aab8d9bf5bdaed15f4d9164795f5dbb59e9c9..81ac6bbba55f5a8ce892499ae2b5bbcd9e4ffdaf 100644 (file)
@@ -728,7 +728,7 @@ static int mass_storage_function_init(struct ccg_usb_function *f,
        struct fsg_common *common;
        int err;
 
-       memset(&fsg, 0, sizeof fsg);
+       memset(&fsg, 0, sizeof(fsg));
        fsg.nluns = 1;
        fsg.luns[0].removable = 1;
        fsg.vendor_name = iManufacturer;
index 6cee7855b019aabf447c3b53bb86db17d9d56e6b..d36486e51a9d1334e1ef7c416411e1e546625a75 100644 (file)
@@ -676,31 +676,28 @@ config COMEDI_ADL_PCI6208
          To compile this driver as a module, choose M here: the module will be
          called adl_pci6208.
 
-config COMEDI_ADL_PCI7230
-       tristate "ADLink PCI-7230 digital io board support"
+config COMEDI_ADL_PCI7X3X
+       tristate "ADLink PCI-723X/743X isolated digital i/o board support"
        ---help---
-         Enable support for ADlink PCI-7230 digital io board support
+         Enable support for ADlink PCI-723X/743X isolated digital i/o boards.
+         Supported boards include the 32-channel PCI-7230 (16 in/16 out),
+         PCI-7233 (32 in), and PCI-7234 (32 out) as well as the 64-channel
+         PCI-7432 (32 in/32 out), PCI-7433 (64 in), and PCI-7434 (64 out).
 
          To compile this driver as a module, choose M here: the module will be
-         called adl_pci7230.
+         called adl_pci7x3x.
 
 config COMEDI_ADL_PCI7296
-       tristate "ADLink PCI-7296 96 ch. digital io board support"
+       tristate "ADLink PCI-72xx opto-22 compatible digital i/o board support"
        select COMEDI_8255
        ---help---
-         Enable support for ADlink PCI-7296 96 ch. digital io board support
+         Enable support for ADlink PCI-72xx opto-22 compatible digital i/o
+         boards. Supported boards include the 24-channel PCI-7224, 48-channel
+         PCI-7248, and 96-channel PCI-7296.
 
          To compile this driver as a module, choose M here: the module will be
          called adl_pci7296.
 
-config COMEDI_ADL_PCI7432
-       tristate "ADLink PCI-7432 64 ch. isolated digital io board support"
-       ---help---
-         Enable support for ADlink PCI-7432 64 ch. isolated digital io board
-
-         To compile this driver as a module, choose M here: the module will be
-         called adl_pci7432.
-
 config COMEDI_ADL_PCI8164
        tristate "ADLink PCI-8164 4 Axes Motion Control board support"
        ---help---
index e82126407e95595d5e1a878117b108fd43478acd..7a76f9c07afd2d8e585d78a1d2128c44f8c30890 100644 (file)
@@ -882,14 +882,12 @@ static int check_insn_config_length(struct comedi_insn *insn,
                /* by default we allow the insn since we don't have checks for
                 * all possible cases yet */
        default:
-               printk(KERN_WARNING
-                      "comedi: no check for data length of config insn id "
-                      "%i is implemented.\n"
-                      " Add a check to %s in %s.\n"
-                      " Assuming n=%i is correct.\n", data[0], __func__,
-                      __FILE__, insn->n);
+               pr_warn("comedi: No check for data length of config insn id %i is implemented.\n",
+                       data[0]);
+               pr_warn("comedi: Add a check to %s in %s.\n",
+                       __func__, __FILE__);
+               pr_warn("comedi: Assuming n=%i is correct.\n", insn->n);
                return 0;
-               break;
        }
        return -EINVAL;
 }
@@ -2034,8 +2032,8 @@ void do_become_nonbusy(struct comedi_device *dev, struct comedi_subdevice *s)
                comedi_reset_async_buf(async);
                async->inttrig = NULL;
        } else {
-               printk(KERN_ERR
-                      "BUG: (?) do_become_nonbusy called with async=0\n");
+               dev_err(dev->class_dev,
+                       "BUG: (?) do_become_nonbusy called with async=NULL\n");
        }
 
        s->busy = NULL;
@@ -2211,14 +2209,12 @@ static int __init comedi_init(void)
        int i;
        int retval;
 
-       printk(KERN_INFO "comedi: version " COMEDI_RELEASE
-              " - http://www.comedi.org\n");
+       pr_info("comedi: version " COMEDI_RELEASE " - http://www.comedi.org\n");
 
        if (comedi_num_legacy_minors < 0 ||
            comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) {
-               printk(KERN_ERR "comedi: error: invalid value for module "
-                      "parameter \"comedi_num_legacy_minors\".  Valid values "
-                      "are 0 through %i.\n", COMEDI_NUM_BOARD_MINORS);
+               pr_err("comedi: error: invalid value for module parameter \"comedi_num_legacy_minors\".  Valid values are 0 through %i.\n",
+                      COMEDI_NUM_BOARD_MINORS);
                return -EINVAL;
        }
 
@@ -2247,7 +2243,7 @@ static int __init comedi_init(void)
        }
        comedi_class = class_create(THIS_MODULE, "comedi");
        if (IS_ERR(comedi_class)) {
-               printk(KERN_ERR "comedi: failed to create class");
+               pr_err("comedi: failed to create class\n");
                cdev_del(&comedi_cdev);
                unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0),
                                         COMEDI_NUM_MINORS);
@@ -2295,8 +2291,7 @@ module_exit(comedi_cleanup);
 
 void comedi_error(const struct comedi_device *dev, const char *s)
 {
-       printk(KERN_ERR "comedi%d: %s: %s\n", dev->minor,
-              dev->driver->driver_name, s);
+       dev_err(dev->class_dev, "%s: %s\n", dev->driver->driver_name, s);
 }
 EXPORT_SYMBOL(comedi_error);
 
@@ -2420,9 +2415,7 @@ int comedi_alloc_board_minor(struct device *hardware_device)
                comedi_device_cleanup(info->device);
                kfree(info->device);
                kfree(info);
-               printk(KERN_ERR
-                      "comedi: error: "
-                      "ran out of minor numbers for board device files.\n");
+               pr_err("comedi: error: ran out of minor numbers for board device files.\n");
                return -EBUSY;
        }
        info->device->minor = i;
@@ -2499,9 +2492,7 @@ int comedi_alloc_subdevice_minor(struct comedi_device *dev,
        spin_unlock(&comedi_file_info_table_lock);
        if (i == COMEDI_NUM_MINORS) {
                kfree(info);
-               printk(KERN_ERR
-                      "comedi: error: "
-                      "ran out of minor numbers for board device files.\n");
+               pr_err("comedi: error: ran out of minor numbers for board device files.\n");
                return -EBUSY;
        }
        s->minor = i;
index f713783ef6246a1a72af55c728269a97b27d700a..cb67a5cb9c824fd5e1fba9c701ae2a1a628618c1 100644 (file)
@@ -46,7 +46,7 @@
 
 #define DPRINTK(format, args...)       do {            \
        if (comedi_debug)                               \
-               printk(KERN_DEBUG "comedi: " format , ## args); \
+               pr_debug("comedi: " format, ## args);   \
 } while (0)
 
 #define COMEDI_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
index c0fdb00783edbf8583e1e0e0a7f5ab32dbf56dda..3153388ab810320bf04f069ac5b7f74941f92de2 100644 (file)
@@ -119,8 +119,8 @@ static void __comedi_device_detach(struct comedi_device *dev)
        if (dev->driver)
                dev->driver->detach(dev);
        else
-               printk(KERN_WARNING
-                      "BUG: dev->driver=NULL in comedi_device_detach()\n");
+               dev_warn(dev->class_dev,
+                        "BUG: dev->driver=NULL in comedi_device_detach()\n");
        cleanup_device(dev);
 }
 
@@ -142,8 +142,7 @@ static int comedi_device_postconfig(struct comedi_device *dev)
                return ret;
        }
        if (!dev->board_name) {
-               printk(KERN_WARNING "BUG: dev->board_name=<%p>\n",
-                      dev->board_name);
+               dev_warn(dev->class_dev, "BUG: dev->board_name=NULL\n");
                dev->board_name = "BUG";
        }
        smp_wmb();
@@ -161,14 +160,13 @@ int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 
        for (driv = comedi_drivers; driv; driv = driv->next) {
                if (!try_module_get(driv->module)) {
-                       printk(KERN_INFO "comedi: failed to increment module count, skipping\n");
                        continue;
                }
                if (driv->num_names) {
                        dev->board_ptr = comedi_recognize(driv, it->board_name);
                        if (dev->board_ptr)
                                break;
-               } else if (strcmp(driv->driver_name, it->board_name))
+               } else if (strcmp(driv->driver_name, it->board_name) == 0)
                        break;
                module_put(driv->module);
        }
@@ -177,8 +175,6 @@ int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it)
                /*  report valid board names before returning error */
                for (driv = comedi_drivers; driv; driv = driv->next) {
                        if (!try_module_get(driv->module)) {
-                               printk(KERN_INFO
-                                      "comedi: failed to increment module count\n");
                                continue;
                        }
                        comedi_report_boards(driv);
@@ -186,6 +182,14 @@ int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it)
                }
                return -EIO;
        }
+       if (driv->attach == NULL) {
+               /* driver does not support manual configuration */
+               dev_warn(dev->class_dev,
+                        "driver '%s' does not support attach using comedi_config\n",
+                        driv->driver_name);
+               module_put(driv->module);
+               return -ENOSYS;
+       }
        /* initialize dev->driver here so
         * comedi_error() can be called from attach */
        dev->driver = driv;
@@ -225,8 +229,9 @@ int comedi_driver_unregister(struct comedi_driver *driver)
                mutex_lock(&dev->mutex);
                if (dev->attached && dev->driver == driver) {
                        if (dev->use_count)
-                               printk(KERN_WARNING "BUG! detaching device with use_count=%d\n",
-                                               dev->use_count);
+                               dev_warn(dev->class_dev,
+                                        "BUG! detaching device with use_count=%d\n",
+                                        dev->use_count);
                        comedi_device_detach(dev);
                }
                mutex_unlock(&dev->mutex);
@@ -273,8 +278,8 @@ static int postconfig(struct comedi_device *dev)
                        async =
                            kzalloc(sizeof(struct comedi_async), GFP_KERNEL);
                        if (async == NULL) {
-                               printk(KERN_INFO
-                                      "failed to allocate async struct\n");
+                               dev_warn(dev->class_dev,
+                                        "failed to allocate async struct\n");
                                return -ENOMEM;
                        }
                        init_waitqueue_head(&async->wait_head);
@@ -290,7 +295,8 @@ static int postconfig(struct comedi_device *dev)
                        async->prealloc_buf = NULL;
                        async->prealloc_bufsz = 0;
                        if (comedi_buf_alloc(dev, s, buf_size) < 0) {
-                               printk(KERN_INFO "Buffer allocation failed\n");
+                               dev_warn(dev->class_dev,
+                                        "Buffer allocation failed\n");
                                return -ENOMEM;
                        }
                        if (s->buf_change) {
@@ -370,17 +376,17 @@ static void comedi_report_boards(struct comedi_driver *driv)
        unsigned int i;
        const char *const *name_ptr;
 
-       printk(KERN_INFO "comedi: valid board names for %s driver are:\n",
-              driv->driver_name);
+       pr_info("comedi: valid board names for %s driver are:\n",
+               driv->driver_name);
 
        name_ptr = driv->board_name;
        for (i = 0; i < driv->num_names; i++) {
-               printk(KERN_INFO " %s\n", *name_ptr);
+               pr_info(" %s\n", *name_ptr);
                name_ptr = (const char **)((char *)name_ptr + driv->offset);
        }
 
        if (driv->num_names == 0)
-               printk(KERN_INFO " %s\n", driv->driver_name);
+               pr_info(" %s\n", driv->driver_name);
 }
 
 static int poll_invalid(struct comedi_device *dev, struct comedi_subdevice *s)
@@ -584,9 +590,9 @@ static unsigned int comedi_buf_munge(struct comedi_async *async,
 
                block_size = num_bytes - count;
                if (block_size < 0) {
-                       printk(KERN_WARNING
-                              "%s: %s: bug! block_size is negative\n",
-                              __FILE__, __func__);
+                       dev_warn(s->device->class_dev,
+                                "%s: %s: bug! block_size is negative\n",
+                                __FILE__, __func__);
                        break;
                }
                if ((int)(async->munge_ptr + block_size -
@@ -667,7 +673,8 @@ unsigned comedi_buf_write_free(struct comedi_async *async, unsigned int nbytes)
 {
        if ((int)(async->buf_write_count + nbytes -
                  async->buf_write_alloc_count) > 0) {
-               printk(KERN_INFO "comedi: attempted to write-free more bytes than have been write-allocated.\n");
+               dev_info(async->subdevice->device->class_dev,
+                        "attempted to write-free more bytes than have been write-allocated.\n");
                nbytes = async->buf_write_alloc_count - async->buf_write_count;
        }
        async->buf_write_count += nbytes;
@@ -703,8 +710,8 @@ unsigned comedi_buf_read_free(struct comedi_async *async, unsigned int nbytes)
        smp_mb();
        if ((int)(async->buf_read_count + nbytes -
                  async->buf_read_alloc_count) > 0) {
-               printk(KERN_INFO
-                      "comedi: attempted to read-free more bytes than have been read-allocated.\n");
+               dev_info(async->subdevice->device->class_dev,
+                        "attempted to read-free more bytes than have been read-allocated.\n");
                nbytes = async->buf_read_alloc_count - async->buf_read_count;
        }
        async->buf_read_count += nbytes;
@@ -853,10 +860,9 @@ comedi_auto_config_helper(struct device *hardware_device,
        mutex_lock(&comedi_dev->mutex);
        if (comedi_dev->attached)
                ret = -EBUSY;
-       else if (!try_module_get(driver->module)) {
-               printk(KERN_INFO "comedi: failed to increment module count\n");
+       else if (!try_module_get(driver->module))
                ret = -EIO;
-       else {
+       else {
                /* set comedi_dev->driver here for attach wrapper */
                comedi_dev->driver = driver;
                ret = (*attach_wrapper)(comedi_dev, context);
@@ -884,14 +890,19 @@ static int comedi_auto_config_wrapper(struct comedi_device *dev, void *context)
                 * has already been copied to it->board_name */
                dev->board_ptr = comedi_recognize(driv, it->board_name);
                if (dev->board_ptr == NULL) {
-                       printk(KERN_WARNING
-                              "comedi: auto config failed to find board entry"
-                              " '%s' for driver '%s'\n", it->board_name,
-                              driv->driver_name);
+                       dev_warn(dev->class_dev,
+                                "auto config failed to find board entry '%s' for driver '%s'\n",
+                                it->board_name, driv->driver_name);
                        comedi_report_boards(driv);
                        return -EINVAL;
                }
        }
+       if (!driv->attach) {
+               dev_warn(dev->class_dev,
+                        "BUG! driver '%s' using old-style auto config but has no attach handler\n",
+                        driv->driver_name);
+               return -EINVAL;
+       }
        return driv->attach(dev, it);
 }
 
index 57b19e44d867d2a2a0b836f7f82be0509c2a7186..849ea7fb0ab7a7161a8add51329899152925a5f5 100644 (file)
@@ -69,9 +69,8 @@ obj-$(CONFIG_COMEDI_ADDI_APCI_3120)   += addi_apci_3120.o
 obj-$(CONFIG_COMEDI_ADDI_APCI_3501)    += addi_apci_3501.o
 obj-$(CONFIG_COMEDI_ADDI_APCI_3XXX)    += addi_apci_3xxx.o
 obj-$(CONFIG_COMEDI_ADL_PCI6208)       += adl_pci6208.o
-obj-$(CONFIG_COMEDI_ADL_PCI7230)       += adl_pci7230.o
+obj-$(CONFIG_COMEDI_ADL_PCI7X3X)       += adl_pci7x3x.o
 obj-$(CONFIG_COMEDI_ADL_PCI7296)       += adl_pci7296.o
-obj-$(CONFIG_COMEDI_ADL_PCI7432)       += adl_pci7432.o
 obj-$(CONFIG_COMEDI_ADL_PCI8164)       += adl_pci8164.o
 obj-$(CONFIG_COMEDI_ADL_PCI9111)       += adl_pci9111.o
 obj-$(CONFIG_COMEDI_ADL_PCI9118)       += adl_pci9118.o
index 3bec0f6e4a8cbcb71b912d2efa461b51607ef14c..3abff556b84647bc3dd58072c2653ddb17b81cc7 100644 (file)
 */
 /*
 Driver: adl_pci6208
-Description: ADLink PCI-6208A
-Devices: [ADLink] PCI-6208A (adl_pci6208)
+Description: ADLink PCI-6208/6216 Series Multi-channel Analog Output Cards
+Devices: (ADLink) PCI-6208 [adl_pci6208]
+        (ADLink) PCI-6216 [adl_pci6216]
 Author: nsyeow <nsyeow@pd.jaring.my>
 Updated: Fri, 30 Jan 2004 14:44:27 +0800
 Status: untested
 
-Configuration Options:
-  none
+Configuration Options: not applicable, uses PCI auto config
 
 References:
        - ni_660x.c
@@ -44,6 +44,12 @@ References:
 
 #include "../comedidev.h"
 
+/*
+ * ADLINK PCI Device ID's supported by this driver
+ */
+#define PCI_DEVICE_ID_PCI6208          0x6208
+#define PCI_DEVICE_ID_PCI6216          0x6216
+
 /*
  * PCI-6208/6216-GL register map
  */
@@ -56,7 +62,7 @@ References:
 #define PCI6208_DIO_DI_MASK            (0xf0)
 #define PCI6208_DIO_DI_SHIFT           (4)
 
-#define PCI6208_MAX_AO_CHANNELS                8
+#define PCI6208_MAX_AO_CHANNELS                16
 
 struct pci6208_board {
        const char *name;
@@ -66,9 +72,13 @@ struct pci6208_board {
 
 static const struct pci6208_board pci6208_boards[] = {
        {
-               .name           = "pci6208a",
-               .dev_id         = 0x6208,
+               .name           = "adl_pci6208",
+               .dev_id         = PCI_DEVICE_ID_PCI6208,
                .ao_chans       = 8,
+       }, {
+               .name           = "adl_pci6216",
+               .dev_id         = PCI_DEVICE_ID_PCI6216,
+               .ao_chans       = 16,
        },
 };
 
@@ -115,116 +125,83 @@ static int pci6208_ao_rinsn(struct comedi_device *dev,
        return insn->n;
 }
 
-static int pci6208_dio_insn_bits(struct comedi_device *dev,
-                                struct comedi_subdevice *s,
-                                struct comedi_insn *insn,
-                                unsigned int *data)
+static int pci6208_di_insn_bits(struct comedi_device *dev,
+                               struct comedi_subdevice *s,
+                               struct comedi_insn *insn,
+                               unsigned int *data)
+{
+       unsigned int val;
+
+       val = inw(dev->iobase + PCI6208_DIO);
+       val = (val & PCI6208_DIO_DI_MASK) >> PCI6208_DIO_DI_SHIFT;
+
+       data[1] = val;
+
+       return insn->n;
+}
+
+static int pci6208_do_insn_bits(struct comedi_device *dev,
+                               struct comedi_subdevice *s,
+                               struct comedi_insn *insn,
+                               unsigned int *data)
 {
-       unsigned int mask = data[0] & PCI6208_DIO_DO_MASK;
+       unsigned int mask = data[0];
        unsigned int bits = data[1];
 
        if (mask) {
                s->state &= ~mask;
-               s->state |= bits & mask;
+               s->state |= (bits & mask);
 
                outw(s->state, dev->iobase + PCI6208_DIO);
        }
 
-       s->state = inw(dev->iobase + PCI6208_DIO);
        data[1] = s->state;
 
        return insn->n;
 }
 
-static int pci6208_dio_insn_config(struct comedi_device *dev,
-                                  struct comedi_subdevice *s,
-                                  struct comedi_insn *insn,
-                                  unsigned int *data)
+static const void *pci6208_find_boardinfo(struct comedi_device *dev,
+                                         struct pci_dev *pcidev)
 {
-       int chan = CR_CHAN(insn->chanspec);
-       unsigned int mask = 1 << chan;
-
-       switch (data[0]) {
-       case INSN_CONFIG_DIO_QUERY:
-               data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT;
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return insn->n;
-}
-
-static struct pci_dev *pci6208_find_device(struct comedi_device *dev,
-                                          struct comedi_devconfig *it)
-{
-       const struct pci6208_board *thisboard;
-       struct pci_dev *pci_dev = NULL;
-       int bus = it->options[0];
-       int slot = it->options[1];
+       const struct pci6208_board *boardinfo;
        int i;
 
-       for_each_pci_dev(pci_dev) {
-               if (pci_dev->vendor != PCI_VENDOR_ID_ADLINK)
-                       continue;
-               for (i = 0; i < ARRAY_SIZE(pci6208_boards); i++) {
-                       thisboard = &pci6208_boards[i];
-                       if (thisboard->dev_id != pci_dev->device)
-                               continue;
-                       /* was a particular bus/slot requested? */
-                       if (bus || slot) {
-                               /* are we on the wrong bus/slot? */
-                               if (pci_dev->bus->number != bus ||
-                                   PCI_SLOT(pci_dev->devfn) != slot)
-                                       continue;
-                       }
-                       dev_dbg(dev->class_dev,
-                               "Found %s on bus %d, slot, %d, irq=%d\n",
-                               thisboard->name,
-                               pci_dev->bus->number,
-                               PCI_SLOT(pci_dev->devfn),
-                               pci_dev->irq);
-                       dev->board_ptr = thisboard;
-                       return pci_dev;
-               }
+       for (i = 0; i < ARRAY_SIZE(pci6208_boards); i++) {
+               boardinfo = &pci6208_boards[i];
+               if (boardinfo->dev_id == pcidev->device)
+                       return boardinfo;
        }
-       dev_err(dev->class_dev,
-               "No supported board found! (req. bus %d, slot %d)\n",
-               bus, slot);
        return NULL;
 }
 
-static int pci6208_attach(struct comedi_device *dev,
-                         struct comedi_devconfig *it)
+static int pci6208_attach_pci(struct comedi_device *dev,
+                             struct pci_dev *pcidev)
 {
-       const struct pci6208_board *thisboard;
+       const struct pci6208_board *boardinfo;
        struct pci6208_private *devpriv;
-       struct pci_dev *pcidev;
        struct comedi_subdevice *s;
+       unsigned int val;
        int ret;
 
+       comedi_set_hw_dev(dev, &pcidev->dev);
+
+       boardinfo = pci6208_find_boardinfo(dev, pcidev);
+       if (!boardinfo)
+               return -ENODEV;
+       dev->board_ptr = boardinfo;
+       dev->board_name = boardinfo->name;
+
        ret = alloc_private(dev, sizeof(*devpriv));
        if (ret < 0)
                return ret;
        devpriv = dev->private;
 
-       pcidev = pci6208_find_device(dev, it);
-       if (!pcidev)
-               return -EIO;
-       comedi_set_hw_dev(dev, &pcidev->dev);
-       thisboard = comedi_board(dev);
-
-       dev->board_name = thisboard->name;
-
-       ret = comedi_pci_enable(pcidev, dev->driver->driver_name);
-       if (ret) {
-               dev_err(dev->class_dev,
-                       "Failed to enable PCI device and request regions\n");
+       ret = comedi_pci_enable(pcidev, dev->board_name);
+       if (ret)
                return ret;
-       }
        dev->iobase = pci_resource_start(pcidev, 2);
 
-       ret = comedi_alloc_subdevices(dev, 2);
+       ret = comedi_alloc_subdevices(dev, 3);
        if (ret)
                return ret;
 
@@ -232,24 +209,38 @@ static int pci6208_attach(struct comedi_device *dev,
        /* analog output subdevice */
        s->type         = COMEDI_SUBD_AO;
        s->subdev_flags = SDF_WRITABLE;
-       s->n_chan       = thisboard->ao_chans;
+       s->n_chan       = boardinfo->ao_chans;
        s->maxdata      = 0xffff;
        s->range_table  = &range_bipolar10;
        s->insn_write   = pci6208_ao_winsn;
        s->insn_read    = pci6208_ao_rinsn;
 
        s = dev->subdevices + 1;
-       /* digital i/o subdevice */
-       s->type         = COMEDI_SUBD_DIO;
-       s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-       s->n_chan       = 8;
+       /* digital input subdevice */
+       s->type         = COMEDI_SUBD_DI;
+       s->subdev_flags = SDF_READABLE;
+       s->n_chan       = 4;
        s->maxdata      = 1;
        s->range_table  = &range_digital;
-       s->insn_bits    = pci6208_dio_insn_bits;
-       s->insn_config  = pci6208_dio_insn_config;
+       s->insn_bits    = pci6208_di_insn_bits;
 
+       s = dev->subdevices + 2;
+       /* digital output subdevice */
+       s->type         = COMEDI_SUBD_DO;
+       s->subdev_flags = SDF_WRITABLE;
+       s->n_chan       = 4;
+       s->maxdata      = 1;
+       s->range_table  = &range_digital;
+       s->insn_bits    = pci6208_do_insn_bits;
+
+       /*
+        * Get the read back signals from the digital outputs
+        * and save it as the initial state for the subdevice.
+        */
+       val = inw(dev->iobase + PCI6208_DIO);
+       val = (val & PCI6208_DIO_DO_MASK) >> PCI6208_DIO_DO_SHIFT;
+       s->state        = val;
        s->io_bits      = 0x0f;
-       s->state        = inw(dev->iobase + PCI6208_DIO);
 
        dev_info(dev->class_dev, "%s: %s, I/O base=0x%04lx\n",
                dev->driver->driver_name, dev->board_name, dev->iobase);
@@ -257,6 +248,15 @@ static int pci6208_attach(struct comedi_device *dev,
        return 0;
 }
 
+static int pci6208_attach(struct comedi_device *dev,
+                         struct comedi_devconfig *it)
+{
+       dev_warn(dev->class_dev,
+               "This driver does not support attach using comedi_config\n");
+
+       return -ENOSYS;
+}
+
 static void pci6208_detach(struct comedi_device *dev)
 {
        struct pci_dev *pcidev = comedi_to_pci_dev(dev);
@@ -264,7 +264,6 @@ static void pci6208_detach(struct comedi_device *dev)
        if (pcidev) {
                if (dev->iobase)
                        comedi_pci_disable(pcidev);
-               pci_dev_put(pcidev);
        }
 }
 
@@ -272,6 +271,7 @@ static struct comedi_driver adl_pci6208_driver = {
        .driver_name    = "adl_pci6208",
        .module         = THIS_MODULE,
        .attach         = pci6208_attach,
+       .attach_pci     = pci6208_attach_pci,
        .detach         = pci6208_detach,
 };
 
@@ -287,7 +287,8 @@ static void __devexit adl_pci6208_pci_remove(struct pci_dev *dev)
 }
 
 static DEFINE_PCI_DEVICE_TABLE(adl_pci6208_pci_table) = {
-       { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, 0x6208) },
+       { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI6208) },
+       { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI6216) },
        { 0 }
 };
 MODULE_DEVICE_TABLE(pci, adl_pci6208_pci_table);
diff --git a/drivers/staging/comedi/drivers/adl_pci7230.c b/drivers/staging/comedi/drivers/adl_pci7230.c
deleted file mode 100644 (file)
index 7df4c96..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
-    comedi/drivers/adl_pci7230.c
-
-    Hardware comedi driver fot PCI7230 Adlink card
-    Copyright (C) 2010 David Fernandez <dfcastelao@gmail.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., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-/*
-Driver: adl_pci7230
-Description: Driver for the Adlink PCI-7230 32 ch. isolated digital io board
-Devices: [ADLink] PCI-7230 (adl_pci7230)
-Author: David Fernandez <dfcastelao@gmail.com>
-Status: experimental
-Updated: Mon, 14 Apr 2008 15:08:14 +0100
-
-Configuration Options:
-  [0] - PCI bus of device (optional)
-  [1] - PCI slot of device (optional)
-  If bus/slot is not specified, the first supported
-  PCI device found will be used.
-*/
-
-#include "../comedidev.h"
-#include <linux/kernel.h>
-
-#define PCI7230_DI      0x00
-#define PCI7230_DO         0x00
-
-#define PCI_DEVICE_ID_PCI7230 0x7230
-
-static int adl_pci7230_do_insn_bits(struct comedi_device *dev,
-       struct comedi_subdevice *s,
-       struct comedi_insn *insn,
-       unsigned int *data)
-{
-       if (data[0]) {
-               s->state &= ~data[0];
-               s->state |= (data[0] & data[1]);
-
-               outl((s->state  << 16) & 0xffffffff, dev->iobase + PCI7230_DO);
-       }
-
-       return insn->n;
-}
-
-static int adl_pci7230_di_insn_bits(struct comedi_device *dev,
-       struct comedi_subdevice *s,
-       struct comedi_insn *insn,
-       unsigned int *data)
-{
-       data[1] = inl(dev->iobase + PCI7230_DI) & 0xffffffff;
-
-       return insn->n;
-}
-
-static struct pci_dev *adl_pci7230_find_pci(struct comedi_device *dev,
-       struct comedi_devconfig *it)
-{
-       struct pci_dev *pcidev = NULL;
-       int bus = it->options[0];
-       int slot = it->options[1];
-
-       for_each_pci_dev(pcidev) {
-               if (pcidev->vendor != PCI_VENDOR_ID_ADLINK ||
-                   pcidev->device != PCI_DEVICE_ID_PCI7230)
-                       continue;
-               if (bus || slot) {
-                       /* requested particular bus/slot */
-                       if (pcidev->bus->number != bus ||
-                           PCI_SLOT(pcidev->devfn) != slot)
-                               continue;
-               }
-               return pcidev;
-       }
-       printk(KERN_ERR "comedi%d: no supported board found! (req. bus/slot : %d/%d)\n",
-               dev->minor, bus, slot);
-       return NULL;
-}
-
-static int adl_pci7230_attach(struct comedi_device *dev,
-       struct comedi_devconfig *it)
-{
-       struct comedi_subdevice *s;
-       struct pci_dev *pcidev;
-       int ret;
-
-       printk(KERN_INFO "comedi%d: adl_pci7230\n", dev->minor);
-
-       dev->board_name = "pci7230";
-
-       ret = comedi_alloc_subdevices(dev, 2);
-       if (ret)
-               return ret;
-
-       pcidev = adl_pci7230_find_pci(dev, it);
-       if (!pcidev)
-               return -EIO;
-       comedi_set_hw_dev(dev, &pcidev->dev);
-
-       if (comedi_pci_enable(pcidev, "adl_pci7230") < 0) {
-               printk(KERN_ERR "comedi%d: Failed to enable PCI device and request regions\n",
-                       dev->minor);
-               return -EIO;
-       }
-       dev->iobase = pci_resource_start(pcidev, 2);
-       printk(KERN_DEBUG "comedi: base addr %4lx\n", dev->iobase);
-
-       s = dev->subdevices + 0;
-       /* Isolated do */
-       s->type = COMEDI_SUBD_DO;
-       s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
-       s->n_chan = 16;
-       s->maxdata = 1;
-       s->range_table = &range_digital;
-       s->insn_bits = adl_pci7230_do_insn_bits;
-
-       s = dev->subdevices + 1;
-       /* Isolated di */
-       s->type = COMEDI_SUBD_DI;
-       s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
-       s->n_chan = 16;
-       s->maxdata = 1;
-       s->range_table = &range_digital;
-       s->insn_bits = adl_pci7230_di_insn_bits;
-
-       printk(KERN_DEBUG "comedi: attached\n");
-
-       return 1;
-}
-
-static void adl_pci7230_detach(struct comedi_device *dev)
-{
-       struct pci_dev *pcidev = comedi_to_pci_dev(dev);
-
-       if (pcidev) {
-               if (dev->iobase)
-                       comedi_pci_disable(pcidev);
-               pci_dev_put(pcidev);
-       }
-}
-
-static struct comedi_driver adl_pci7230_driver = {
-       .driver_name    = "adl_pci7230",
-       .module         = THIS_MODULE,
-       .attach         = adl_pci7230_attach,
-       .detach         = adl_pci7230_detach,
-};
-
-static int __devinit adl_pci7230_pci_probe(struct pci_dev *dev,
-                                          const struct pci_device_id *ent)
-{
-       return comedi_pci_auto_config(dev, &adl_pci7230_driver);
-}
-
-static void __devexit adl_pci7230_pci_remove(struct pci_dev *dev)
-{
-       comedi_pci_auto_unconfig(dev);
-}
-
-static DEFINE_PCI_DEVICE_TABLE(adl_pci7230_pci_table) = {
-       { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7230) },
-       { 0 }
-};
-MODULE_DEVICE_TABLE(pci, adl_pci7230_pci_table);
-
-static struct pci_driver adl_pci7230_pci_driver = {
-       .name           = "adl_pci7230",
-       .id_table       = adl_pci7230_pci_table,
-       .probe          = adl_pci7230_pci_probe,
-       .remove         = __devexit_p(adl_pci7230_pci_remove),
-};
-module_comedi_pci_driver(adl_pci7230_driver, adl_pci7230_pci_driver);
-
-MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
-MODULE_LICENSE("GPL");
index 19b47af9c10e50729558663e36fff54e5a36139e..1b9ea543a8229ea4d4d260273e47c2aca31a8a60 100644 (file)
 /*
-    comedi/drivers/adl_pci7296.c
+ * COMEDI driver for the ADLINK PCI-72xx series boards.
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2000 David A. Schleef <ds@schleef.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
 
-    COMEDI - Linux Control and Measurement Device Interface
-    Copyright (C) 2000 David A. Schleef <ds@schleef.org>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
 /*
 Driver: adl_pci7296
-Description: Driver for the Adlink PCI-7296 96 ch. digital io board
-Devices: [ADLink] PCI-7296 (adl_pci7296)
+Description: 24/48/96-Channel Opto-22 Compatible Digital I/O Boards
+Devices: (ADLink) PCI-7224 [adl_pci7224] - 24 channels
+        (ADLink) PCI-7248 [adl_pci7248] - 48 channels
+        (ADLink) PCI-7296 [adl_pci7296] - 96 channels
 Author: Jon Grierson <jd@renko.co.uk>
 Updated: Mon, 14 Apr 2008 15:05:56 +0100
 Status: testing
 
-Configuration Options:
-  [0] - PCI bus of device (optional)
-  [1] - PCI slot of device (optional)
-  If bus/slot is not specified, the first supported
-  PCI device found will be used.
+This driver only attaches using the PCI PnP auto config support
+in the comedi core. The module parameter 'comedi_autoconfig'
+must be 1 (default) to enable this feature. The COMEDI_DEVCONFIG
+ioctl, used by the comedi_config utility, is not supported by
+this driver.
+
+These boards also have an 8254 programmable timer/counter chip.
+This chip is not currently supported by this driver.
+
+Interrupt support for these boards is also not currently supported.
+
+Configuration Options: not applicable
 */
 
 #include "../comedidev.h"
-#include <linux/kernel.h>
 
 #include "8255.h"
-/* #include "8253.h" */
 
-#define PORT1A 0
-#define PORT2A 4
-#define PORT3A 8
-#define PORT4A 12
+/*
+ * PCI Device ID's supported by this driver
+ */
+#define PCI_DEVICE_ID_PCI7224  0x7224
+#define PCI_DEVICE_ID_PCI7248  0x7248
+#define PCI_DEVICE_ID_PCI7296  0x7296
+
+struct adl_pci7296_boardinfo {
+       const char *name;
+       unsigned short device;
+       int nsubdevs;
+};
 
-#define PCI_DEVICE_ID_PCI7296 0x7296
+static const struct adl_pci7296_boardinfo adl_pci7296_boards[] = {
+       {
+               .name           = "adl_pci7224",
+               .device         = PCI_DEVICE_ID_PCI7224,
+               .nsubdevs       = 1,
+       }, {
+               .name           = "adl_pci7248",
+               .device         = PCI_DEVICE_ID_PCI7248,
+               .nsubdevs       = 2,
+       }, {
+               .name           = "adl_pci7296",
+               .device         = PCI_DEVICE_ID_PCI7296,
+               .nsubdevs       = 4,
+       },
+};
 
-static struct pci_dev *adl_pci7296_find_pci(struct comedi_device *dev,
-                                           struct comedi_devconfig *it)
+static const void *adl_pci7296_find_boardinfo(struct comedi_device *dev,
+                                             struct pci_dev *pcidev)
 {
-       struct pci_dev *pcidev = NULL;
-       int bus = it->options[0];
-       int slot = it->options[1];
-
-       for_each_pci_dev(pcidev) {
-               if (pcidev->vendor != PCI_VENDOR_ID_ADLINK ||
-                   pcidev->device != PCI_DEVICE_ID_PCI7296)
-                       continue;
-               if (bus || slot) {
-                       /* requested particular bus/slot */
-                       if (pcidev->bus->number != bus ||
-                           PCI_SLOT(pcidev->devfn) != slot)
-                               continue;
-               }
-               return pcidev;
+       const struct adl_pci7296_boardinfo *board;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(adl_pci7296_boards); i++) {
+               board = &adl_pci7296_boards[i];
+               if (pcidev->device == board->device)
+                       return board;
        }
-       printk(KERN_ERR
-               "comedi%d: no supported board found! (req. bus/slot : %d/%d)\n",
-              dev->minor, bus, slot);
        return NULL;
 }
 
-static int adl_pci7296_attach(struct comedi_device *dev,
-                             struct comedi_devconfig *it)
+static int adl_pci7296_attach_pci(struct comedi_device *dev,
+                                 struct pci_dev *pcidev)
 {
-       struct pci_dev *pcidev;
+       const struct adl_pci7296_boardinfo *board;
        struct comedi_subdevice *s;
        int ret;
+       int i;
 
-       printk(KERN_INFO "comedi%d: attach adl_pci7432\n", dev->minor);
+       comedi_set_hw_dev(dev, &pcidev->dev);
 
-       dev->board_name = "pci7432";
+       board = adl_pci7296_find_boardinfo(dev, pcidev);
+       if (!board)
+               return -ENODEV;
+       dev->board_ptr = board;
+       dev->board_name = board->name;
 
-       ret = comedi_alloc_subdevices(dev, 4);
+       ret = comedi_pci_enable(pcidev, dev->board_name);
        if (ret)
                return ret;
-
-       pcidev = adl_pci7296_find_pci(dev, it);
-       if (!pcidev)
-               return -EIO;
-       comedi_set_hw_dev(dev, &pcidev->dev);
-
-       if (comedi_pci_enable(pcidev, "adl_pci7296") < 0) {
-               printk(KERN_ERR
-                       "comedi%d: Failed to enable PCI device and request regions\n",
-                       dev->minor);
-               return -EIO;
-       }
-
        dev->iobase = pci_resource_start(pcidev, 2);
-       printk(KERN_INFO "comedi: base addr %4lx\n", dev->iobase);
-
-       /*  four 8255 digital io subdevices */
-       s = dev->subdevices + 0;
-       subdev_8255_init(dev, s, NULL, (unsigned long)(dev->iobase));
 
-       s = dev->subdevices + 1;
-       ret = subdev_8255_init(dev, s, NULL,
-                               (unsigned long)(dev->iobase + PORT2A));
-       if (ret < 0)
-               return ret;
-
-       s = dev->subdevices + 2;
-       ret = subdev_8255_init(dev, s, NULL,
-                               (unsigned long)(dev->iobase + PORT3A));
-       if (ret < 0)
+       /*
+        * One, two, or four subdevices are setup by this driver depending
+        * on the number of channels provided by the board. Each subdevice
+        * has 24 channels supported by the 8255 module.
+        */
+       ret = comedi_alloc_subdevices(dev, board->nsubdevs);
+       if (ret)
                return ret;
 
-       s = dev->subdevices + 3;
-       ret = subdev_8255_init(dev, s, NULL,
-                               (unsigned long)(dev->iobase + PORT4A));
-       if (ret < 0)
-               return ret;
+       for (i = 0; i < board->nsubdevs; i++) {
+               s = dev->subdevices + i;
+               ret = subdev_8255_init(dev, s, NULL, dev->iobase + (i * 4));
+               if (ret)
+                       return ret;
+       }
 
-       printk(KERN_DEBUG "comedi%d: adl_pci7432 attached\n", dev->minor);
+       dev_info(dev->class_dev, "%s attached (%d digital i/o channels)\n",
+               dev->board_name, board->nsubdevs * 24);
 
        return 0;
 }
 
+static int adl_pci7296_attach(struct comedi_device *dev,
+                             struct comedi_devconfig *it)
+{
+       dev_warn(dev->class_dev,
+               "This driver does not support attach using comedi_config\n");
+
+       return -ENOSYS;
+}
+
 static void adl_pci7296_detach(struct comedi_device *dev)
 {
        struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+       const struct adl_pci7296_boardinfo *board = comedi_board(dev);
+       struct comedi_subdevice *s;
+       int i;
 
+       if (dev->subdevices) {
+               for (i = 0; i < board->nsubdevs; i++) {
+                       s = dev->subdevices + i;
+                       subdev_8255_cleanup(dev, s);
+               }
+       }
        if (pcidev) {
                if (dev->iobase)
                        comedi_pci_disable(pcidev);
-               pci_dev_put(pcidev);
-       }
-       if (dev->subdevices) {
-               subdev_8255_cleanup(dev, dev->subdevices + 0);
-               subdev_8255_cleanup(dev, dev->subdevices + 1);
-               subdev_8255_cleanup(dev, dev->subdevices + 2);
-               subdev_8255_cleanup(dev, dev->subdevices + 3);
        }
 }
 
@@ -150,6 +165,7 @@ static struct comedi_driver adl_pci7296_driver = {
        .driver_name    = "adl_pci7296",
        .module         = THIS_MODULE,
        .attach         = adl_pci7296_attach,
+       .attach_pci     = adl_pci7296_attach_pci,
        .detach         = adl_pci7296_detach,
 };
 
@@ -165,6 +181,8 @@ static void __devexit adl_pci7296_pci_remove(struct pci_dev *dev)
 }
 
 static DEFINE_PCI_DEVICE_TABLE(adl_pci7296_pci_table) = {
+       { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7224) },
+       { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7248) },
        { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7296) },
        { 0 }
 };
@@ -178,6 +196,6 @@ static struct pci_driver adl_pci7296_pci_driver = {
 };
 module_comedi_pci_driver(adl_pci7296_driver, adl_pci7296_pci_driver);
 
+MODULE_DESCRIPTION("ADLINK PCI-72xx Opto-22 Compatible Digital I/O Boards");
 MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/adl_pci7432.c b/drivers/staging/comedi/drivers/adl_pci7432.c
deleted file mode 100644 (file)
index 6b8d940..0000000
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
-    comedi/drivers/adl_pci7432.c
-
-    Hardware comedi driver fot PCI7432 Adlink card
-    Copyright (C) 2004 Michel Lachine <mike@mikelachaine.ca>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-/*
-Driver: adl_pci7432
-Description: Driver for the Adlink PCI-7432 64 ch. isolated digital io board
-Devices: [ADLink] PCI-7432 (adl_pci7432)
-Author: Michel Lachaine <mike@mikelachaine.ca>
-Status: experimental
-Updated: Mon, 14 Apr 2008 15:08:14 +0100
-
-Configuration Options:
-  [0] - PCI bus of device (optional)
-  [1] - PCI slot of device (optional)
-  If bus/slot is not specified, the first supported
-  PCI device found will be used.
-*/
-
-#include "../comedidev.h"
-#include <linux/kernel.h>
-
-#define PCI7432_DI      0x00
-#define PCI7432_DO         0x00
-
-#define PCI_DEVICE_ID_PCI7432 0x7432
-
-static int adl_pci7432_do_insn_bits(struct comedi_device *dev,
-                                   struct comedi_subdevice *s,
-                                   struct comedi_insn *insn,
-                                   unsigned int *data)
-{
-       printk(KERN_DEBUG "comedi: pci7432_do_insn_bits called\n");
-       printk(KERN_DEBUG "comedi: data0: %8x data1: %8x\n", data[0], data[1]);
-
-       if (data[0]) {
-               s->state &= ~data[0];
-               s->state |= (data[0] & data[1]);
-
-               printk(KERN_DEBUG "comedi: out: %8x on iobase %4lx\n", s->state,
-                      dev->iobase + PCI7432_DO);
-               outl(s->state & 0xffffffff, dev->iobase + PCI7432_DO);
-       }
-       return insn->n;
-}
-
-static int adl_pci7432_di_insn_bits(struct comedi_device *dev,
-                                   struct comedi_subdevice *s,
-                                   struct comedi_insn *insn,
-                                   unsigned int *data)
-{
-       printk(KERN_DEBUG "comedi: pci7432_di_insn_bits called\n");
-       printk(KERN_DEBUG "comedi: data0: %8x data1: %8x\n", data[0], data[1]);
-
-       data[1] = inl(dev->iobase + PCI7432_DI) & 0xffffffff;
-       printk(KERN_DEBUG "comedi: data1 %8x\n", data[1]);
-
-       return insn->n;
-}
-
-static struct pci_dev *adl_pci7432_find_pci(struct comedi_device *dev,
-                                           struct comedi_devconfig *it)
-{
-       struct pci_dev *pcidev = NULL;
-       int bus = it->options[0];
-       int slot = it->options[1];
-
-       for_each_pci_dev(pcidev) {
-               if (pcidev->vendor != PCI_VENDOR_ID_ADLINK ||
-                   pcidev->device != PCI_DEVICE_ID_PCI7432)
-                       continue;
-               if (bus || slot) {
-                       /* requested particular bus/slot */
-                       if (pcidev->bus->number != bus ||
-                           PCI_SLOT(pcidev->devfn) != slot)
-                               continue;
-               }
-               return pcidev;
-       }
-       printk(KERN_ERR
-               "comedi%d: no supported board found! (req. bus/slot : %d/%d)\n",
-              dev->minor, bus, slot);
-       return NULL;
-}
-
-static int adl_pci7432_attach(struct comedi_device *dev,
-                             struct comedi_devconfig *it)
-{
-       struct pci_dev *pcidev;
-       struct comedi_subdevice *s;
-       int ret;
-
-       printk(KERN_INFO "comedi%d: attach adl_pci7432\n", dev->minor);
-
-       dev->board_name = "pci7432";
-
-       ret = comedi_alloc_subdevices(dev, 2);
-       if (ret)
-               return ret;
-
-       pcidev = adl_pci7432_find_pci(dev, it);
-       if (!pcidev)
-               return -EIO;
-       comedi_set_hw_dev(dev, &pcidev->dev);
-
-       if (comedi_pci_enable(pcidev, "adl_pci7432") < 0) {
-               printk(KERN_ERR "comedi%d: Failed to enable PCI device and request regions\n",
-                       dev->minor);
-               return -EIO;
-       }
-       dev->iobase = pci_resource_start(pcidev, 2);
-       printk(KERN_INFO "comedi: base addr %4lx\n", dev->iobase);
-
-       s = dev->subdevices + 0;
-       s->type = COMEDI_SUBD_DI;
-       s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON;
-       s->n_chan = 32;
-       s->maxdata = 1;
-       s->len_chanlist = 32;
-       s->io_bits = 0x00000000;
-       s->range_table = &range_digital;
-       s->insn_bits = adl_pci7432_di_insn_bits;
-
-       s = dev->subdevices + 1;
-       s->type = COMEDI_SUBD_DO;
-       s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
-       s->n_chan = 32;
-       s->maxdata = 1;
-       s->len_chanlist = 32;
-       s->io_bits = 0xffffffff;
-       s->range_table = &range_digital;
-       s->insn_bits = adl_pci7432_do_insn_bits;
-
-       printk(KERN_DEBUG "comedi%d: adl_pci7432 attached\n", dev->minor);
-       return 0;
-}
-
-static void adl_pci7432_detach(struct comedi_device *dev)
-{
-       struct pci_dev *pcidev = comedi_to_pci_dev(dev);
-
-       if (pcidev) {
-               if (dev->iobase)
-                       comedi_pci_disable(pcidev);
-               pci_dev_put(pcidev);
-       }
-}
-
-static struct comedi_driver adl_pci7432_driver = {
-       .driver_name    = "adl_pci7432",
-       .module         = THIS_MODULE,
-       .attach         = adl_pci7432_attach,
-       .detach         = adl_pci7432_detach,
-};
-
-static int __devinit adl_pci7432_pci_probe(struct pci_dev *dev,
-                                          const struct pci_device_id *ent)
-{
-       return comedi_pci_auto_config(dev, &adl_pci7432_driver);
-}
-
-static void __devexit adl_pci7432_pci_remove(struct pci_dev *dev)
-{
-       comedi_pci_auto_unconfig(dev);
-}
-
-static DEFINE_PCI_DEVICE_TABLE(adl_pci7432_pci_table) = {
-       { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7432) },
-       { 0 }
-};
-MODULE_DEVICE_TABLE(pci, adl_pci7432_pci_table);
-
-static struct pci_driver adl_pci7432_pci_driver = {
-       .name           = "adl_pci7432",
-       .id_table       = adl_pci7432_pci_table,
-       .probe          = adl_pci7432_pci_probe,
-       .remove         = __devexit_p(adl_pci7432_pci_remove),
-};
-module_comedi_pci_driver(adl_pci7432_driver, adl_pci7432_pci_driver);
-
-MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/adl_pci7x3x.c b/drivers/staging/comedi/drivers/adl_pci7x3x.c
new file mode 100644 (file)
index 0000000..41963fb
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+ * COMEDI driver for the ADLINK PCI-723x/743x series boards.
+ * Copyright (C) 2012 H Hartley Sweeten <hsweeten@visionengravers.com>
+ *
+ * Based on the adl_pci7230 driver written by:
+ *     David Fernandez <dfcastelao@gmail.com>
+ * and the adl_pci7432 driver written by:
+ *     Michel Lachaine <mike@mikelachaine.ca>
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2000 David A. Schleef <ds@schleef.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+Driver: adl_pci7x3x
+Description: 32/64-Channel Isolated Digital I/O Boards
+Devices: (ADLink) PCI-7230 [adl_pci7230] - 16 input / 16 output
+        (ADLink) PCI-7233 [adl_pci7233] - 32 input
+        (ADLink) PCI-7234 [adl_pci7234] - 32 output
+        (ADLink) PCI-7432 [adl_pci7432] - 32 input / 32 output
+        (ADLink) PCI-7433 [adl_pci7433] - 64 input
+        (ADLink) PCI-7434 [adl_pci7434] - 64 output
+Author: H Hartley Sweeten <hsweeten@visionengravers.com>
+Updated: Thu, 02 Aug 2012 14:27:46 -0700
+Status: untested
+
+This driver only attaches using the PCI PnP auto config support
+in the comedi core. The module parameter 'comedi_autoconfig'
+must be 1 (default) to enable this feature. The COMEDI_DEVCONFIG
+ioctl, used by the comedi_config utility, is not supported by
+this driver.
+
+The PCI-7230, PCI-7432 and PCI-7433 boards also support external
+interrupt signals on digital input channels 0 and 1. The PCI-7233
+has dual-interrupt sources for change-of-state (COS) on any 16
+digital input channels of LSB and for COS on any 16 digital input
+lines of MSB. Interrupts are not currently supported by this
+driver.
+
+Configuration Options: not applicable
+*/
+
+#include "../comedidev.h"
+
+/*
+ * PCI Device ID's supported by this driver
+ */
+#define PCI_DEVICE_ID_PCI7230  0x7230
+#define PCI_DEVICE_ID_PCI7233  0x7233
+#define PCI_DEVICE_ID_PCI7234  0x7234
+#define PCI_DEVICE_ID_PCI7432  0x7432
+#define PCI_DEVICE_ID_PCI7433  0x7433
+#define PCI_DEVICE_ID_PCI7434  0x7434
+
+/*
+ * Register I/O map (32-bit access only)
+ */
+#define PCI7X3X_DIO_REG                0x00
+#define PCI743X_DIO_REG                0x04
+
+struct adl_pci7x3x_boardinfo {
+       const char *name;
+       unsigned short device;
+       int nsubdevs;
+       int di_nchan;
+       int do_nchan;
+};
+
+static const struct adl_pci7x3x_boardinfo adl_pci7x3x_boards[] = {
+       {
+               .name           = "adl_pci7230",
+               .device         = PCI_DEVICE_ID_PCI7230,
+               .nsubdevs       = 2,
+               .di_nchan       = 16,
+               .do_nchan       = 16,
+       }, {
+               .name           = "adl_pci7233",
+               .device         = PCI_DEVICE_ID_PCI7233,
+               .nsubdevs       = 1,
+               .di_nchan       = 32,
+       }, {
+               .name           = "adl_pci7234",
+               .device         = PCI_DEVICE_ID_PCI7234,
+               .nsubdevs       = 1,
+               .do_nchan       = 32,
+       }, {
+               .name           = "adl_pci7432",
+               .device         = PCI_DEVICE_ID_PCI7432,
+               .nsubdevs       = 2,
+               .di_nchan       = 32,
+               .do_nchan       = 32,
+       }, {
+               .name           = "adl_pci7433",
+               .device         = PCI_DEVICE_ID_PCI7433,
+               .nsubdevs       = 2,
+               .di_nchan       = 64,
+       }, {
+               .name           = "adl_pci7434",
+               .device         = PCI_DEVICE_ID_PCI7434,
+               .nsubdevs       = 2,
+               .do_nchan       = 64,
+       }
+};
+
+static int adl_pci7x3x_do_insn_bits(struct comedi_device *dev,
+                                   struct comedi_subdevice *s,
+                                   struct comedi_insn *insn,
+                                   unsigned int *data)
+{
+       unsigned long reg = (unsigned long)s->private;
+       unsigned int mask = data[0];
+       unsigned int bits = data[1];
+
+       if (mask) {
+               s->state &= ~mask;
+               s->state |= (bits & mask);
+
+               outl(s->state, dev->iobase + reg);
+       }
+
+       /*
+        * NOTE: The output register is not readable.
+        * This returned state will not be correct until all the
+        * outputs have been updated.
+        */
+       data[1] = s->state;
+
+       return insn->n;
+}
+
+static int adl_pci7x3x_di_insn_bits(struct comedi_device *dev,
+                                   struct comedi_subdevice *s,
+                                   struct comedi_insn *insn,
+                                   unsigned int *data)
+{
+       unsigned long reg = (unsigned long)s->private;
+
+       data[1] = inl(dev->iobase + reg);
+
+       return insn->n;
+}
+
+static const void *adl_pci7x3x_find_boardinfo(struct comedi_device *dev,
+                                             struct pci_dev *pcidev)
+{
+       const struct adl_pci7x3x_boardinfo *board;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(adl_pci7x3x_boards); i++) {
+               board = &adl_pci7x3x_boards[i];
+               if (pcidev->device == board->device)
+                       return board;
+       }
+       return NULL;
+}
+
+static int adl_pci7x3x_attach_pci(struct comedi_device *dev,
+                                 struct pci_dev *pcidev)
+{
+       const struct adl_pci7x3x_boardinfo *board;
+       struct comedi_subdevice *s;
+       int subdev;
+       int nchan;
+       int ret;
+
+       comedi_set_hw_dev(dev, &pcidev->dev);
+
+       board = adl_pci7x3x_find_boardinfo(dev, pcidev);
+       if (!board)
+               return -ENODEV;
+       dev->board_ptr = board;
+       dev->board_name = board->name;
+
+       ret = comedi_pci_enable(pcidev, dev->board_name);
+       if (ret)
+               return ret;
+       dev->iobase = pci_resource_start(pcidev, 2);
+
+       /*
+        * One or two subdevices are setup by this driver depending on
+        * the number of digital inputs and/or outputs provided by the
+        * board. Each subdevice has a maximum of 32 channels.
+        *
+        *      PCI-7230 - 2 subdevices: 0 - 16 input, 1 - 16 output
+        *      PCI-7233 - 1 subdevice: 0 - 32 input
+        *      PCI-7234 - 1 subdevice: 0 - 32 output
+        *      PCI-7432 - 2 subdevices: 0 - 32 input, 1 - 32 output
+        *      PCI-7433 - 2 subdevices: 0 - 32 input, 1 - 32 input
+        *      PCI-7434 - 2 subdevices: 0 - 32 output, 1 - 32 output
+        */
+       ret = comedi_alloc_subdevices(dev, board->nsubdevs);
+       if (ret)
+               return ret;
+
+       subdev = 0;
+
+       if (board->di_nchan) {
+               nchan = min(board->di_nchan, 32);
+
+               s = dev->subdevices + subdev;
+               /* Isolated digital inputs 0 to 15/31 */
+               s->type         = COMEDI_SUBD_DI;
+               s->subdev_flags = SDF_READABLE;
+               s->n_chan       = nchan;
+               s->maxdata      = 1;
+               s->insn_bits    = adl_pci7x3x_di_insn_bits;
+               s->range_table  = &range_digital;
+
+               s->private      = (void *)PCI7X3X_DIO_REG;
+
+               subdev++;
+
+               nchan = board->di_nchan - nchan;
+               if (nchan) {
+                       s = dev->subdevices + subdev;
+                       /* Isolated digital inputs 32 to 63 */
+                       s->type         = COMEDI_SUBD_DI;
+                       s->subdev_flags = SDF_READABLE;
+                       s->n_chan       = nchan;
+                       s->maxdata      = 1;
+                       s->insn_bits    = adl_pci7x3x_di_insn_bits;
+                       s->range_table  = &range_digital;
+
+                       s->private      = (void *)PCI743X_DIO_REG;
+
+                       subdev++;
+               }
+       }
+
+       if (board->do_nchan) {
+               nchan = min(board->do_nchan, 32);
+
+               s = dev->subdevices + subdev;
+               /* Isolated digital outputs 0 to 15/31 */
+               s->type         = COMEDI_SUBD_DO;
+               s->subdev_flags = SDF_WRITABLE;
+               s->n_chan       = nchan;
+               s->maxdata      = 1;
+               s->insn_bits    = adl_pci7x3x_do_insn_bits;
+               s->range_table  = &range_digital;
+
+               s->private      = (void *)PCI7X3X_DIO_REG;
+
+               subdev++;
+
+               nchan = board->do_nchan - nchan;
+               if (nchan) {
+                       s = dev->subdevices + subdev;
+                       /* Isolated digital outputs 32 to 63 */
+                       s->type         = COMEDI_SUBD_DO;
+                       s->subdev_flags = SDF_WRITABLE;
+                       s->n_chan       = nchan;
+                       s->maxdata      = 1;
+                       s->insn_bits    = adl_pci7x3x_do_insn_bits;
+                       s->range_table  = &range_digital;
+
+                       s->private      = (void *)PCI743X_DIO_REG;
+
+                       subdev++;
+               }
+       }
+
+       dev_info(dev->class_dev, "%s attached (%d inputs/%d outputs)\n",
+               dev->board_name, board->di_nchan, board->do_nchan);
+
+       return 0;
+}
+
+static int adl_pci7x3x_attach(struct comedi_device *dev,
+                             struct comedi_devconfig *it)
+{
+       dev_warn(dev->class_dev,
+               "This driver does not support attach using comedi_config\n");
+
+       return -ENOSYS;
+}
+
+static void adl_pci7x3x_detach(struct comedi_device *dev)
+{
+       struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+
+       if (pcidev) {
+               if (dev->iobase)
+                       comedi_pci_disable(pcidev);
+       }
+}
+
+static struct comedi_driver adl_pci7x3x_driver = {
+       .driver_name    = "adl_pci7x3x",
+       .module         = THIS_MODULE,
+       .attach         = adl_pci7x3x_attach,
+       .attach_pci     = adl_pci7x3x_attach_pci,
+       .detach         = adl_pci7x3x_detach,
+};
+
+static int __devinit adl_pci7x3x_pci_probe(struct pci_dev *dev,
+                                          const struct pci_device_id *ent)
+{
+       return comedi_pci_auto_config(dev, &adl_pci7x3x_driver);
+}
+
+static void __devexit adl_pci7x3x_pci_remove(struct pci_dev *dev)
+{
+       comedi_pci_auto_unconfig(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(adl_pci7x3x_pci_table) = {
+       { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7230) },
+       { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7233) },
+       { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7234) },
+       { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7432) },
+       { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7433) },
+       { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7434) },
+       { 0 }
+};
+MODULE_DEVICE_TABLE(pci, adl_pci7x3x_pci_table);
+
+static struct pci_driver adl_pci7x3x_pci_driver = {
+       .name           = "adl_pci7x3x",
+       .id_table       = adl_pci7x3x_pci_table,
+       .probe          = adl_pci7x3x_pci_probe,
+       .remove         = __devexit_p(adl_pci7x3x_pci_remove),
+};
+module_comedi_pci_driver(adl_pci7x3x_driver, adl_pci7x3x_pci_driver);
+
+MODULE_DESCRIPTION("ADLINK PCI-723x/743x Isolated Digital I/O boards");
+MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>");
+MODULE_LICENSE("GPL");
index 31986608eaf1e932f25f77bcde3685ef66a891a2..6b4d0d68e6372ea1c4d51ac0ebc71e7b78522875 100644 (file)
@@ -1349,9 +1349,6 @@ static struct pci_dev *pci1710_find_pci_dev(struct comedi_device *dev,
                }
                if (pcidev->vendor != PCI_VENDOR_ID_ADVANTECH)
                        continue;
-               if (pci_is_enabled(pcidev))
-                       continue;
-
                if (strcmp(this_board->name, DRV_NAME) == 0) {
                        for (i = 0; i < ARRAY_SIZE(boardtypes); ++i) {
                                if (pcidev->device == boardtypes[i].device_id) {
index da5ee69d2c9da856d2c46740288f72812ac41eef..dfde0f6328dd82b29403c54aba0b5a73d4f603e2 100644 (file)
@@ -301,8 +301,6 @@ static struct pci_dev *pci1723_find_pci_dev(struct comedi_device *dev,
                }
                if (pcidev->vendor != PCI_VENDOR_ID_ADVANTECH)
                        continue;
-               if (pci_is_enabled(pcidev))
-                       continue;
                return pcidev;
        }
        dev_err(dev->class_dev,
index 97f06dc8e48d002e00d053f068dccdad69310bbe..2d4cb7f638b2a0eeb6df6c371367ba3ac084b9a4 100644 (file)
@@ -1064,8 +1064,6 @@ static struct pci_dev *pci_dio_find_pci_dev(struct comedi_device *dev,
                            slot != PCI_SLOT(pcidev->devfn))
                                continue;
                }
-               if (pci_is_enabled(pcidev))
-                       continue;
                for (i = 0; i < ARRAY_SIZE(boardtypes); ++i) {
                        if (boardtypes[i].vendor_id != pcidev->vendor)
                                continue;
index 6c81e377262c204ca8a9354743f344ff824267d5..9c8fbf1b15f06025817cde9d871076fe208ad05d 100644 (file)
@@ -215,6 +215,9 @@ order they appear in the channel list.
 
 #define DIO200_DRIVER_NAME     "amplc_dio200"
 
+#define DO_ISA IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA)
+#define DO_PCI IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_PCI)
+
 /* PCI IDs */
 #define PCI_VENDOR_ID_AMPLICON 0x14dc
 #define PCI_DEVICE_ID_AMPLICON_PCI272 0x000a
@@ -272,12 +275,12 @@ enum dio200_model {
 };
 
 enum dio200_layout {
-#if IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA)
+#if DO_ISA
        pc212_layout,
        pc214_layout,
 #endif
        pc215_layout,
-#if IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA)
+#if DO_ISA
        pc218_layout,
 #endif
        pc272_layout
@@ -292,7 +295,7 @@ struct dio200_board {
 };
 
 static const struct dio200_board dio200_boards[] = {
-#if IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA)
+#if DO_ISA
        {
         .name = "pc212e",
         .bustype = isa_bustype,
@@ -324,7 +327,7 @@ static const struct dio200_board dio200_boards[] = {
         .layout = pc272_layout,
         },
 #endif
-#if IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_PCI)
+#if DO_PCI
        {
         .name = "pci215",
         .devid = PCI_DEVICE_ID_AMPLICON_PCI215,
@@ -367,7 +370,7 @@ struct dio200_layout_struct {
 };
 
 static const struct dio200_layout_struct dio200_layouts[] = {
-#if IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA)
+#if DO_ISA
        [pc212_layout] = {
                          .n_subdevs = 6,
                          .sdtype = {sd_8255, sd_8254, sd_8254, sd_8254,
@@ -396,7 +399,7 @@ static const struct dio200_layout_struct dio200_layouts[] = {
                          .has_int_sce = 1,
                          .has_clk_gat_sce = 1,
                          },
-#if IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA)
+#if DO_ISA
        [pc218_layout] = {
                          .n_subdevs = 7,
                          .sdtype = {sd_8254, sd_8254, sd_8255, sd_8254,
@@ -449,6 +452,16 @@ struct dio200_subdev_intr {
        int continuous;
 };
 
+static inline bool is_pci_board(const struct dio200_board *board)
+{
+       return DO_PCI && board->bustype == pci_bustype;
+}
+
+static inline bool is_isa_board(const struct dio200_board *board)
+{
+       return DO_ISA && board->bustype == isa_bustype;
+}
+
 /*
  * This function looks for a board matching the supplied PCI device.
  */
@@ -458,7 +471,7 @@ dio200_find_pci_board(struct pci_dev *pci_dev)
        unsigned int i;
 
        for (i = 0; i < ARRAY_SIZE(dio200_boards); i++)
-               if (dio200_boards[i].bustype == pci_bustype &&
+               if (is_pci_board(&dio200_boards[i]) &&
                    pci_dev->device == dio200_boards[i].devid)
                        return &dio200_boards[i];
        return NULL;
@@ -1228,12 +1241,10 @@ static void dio200_report_attach(struct comedi_device *dev, unsigned int irq)
        char tmpbuf[60];
        int tmplen;
 
-       if (IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA) &&
-           thisboard->bustype == isa_bustype)
+       if (is_isa_board(thisboard))
                tmplen = scnprintf(tmpbuf, sizeof(tmpbuf),
                                   "(base %#lx) ", dev->iobase);
-       else if (IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_PCI) &&
-                thisboard->bustype == pci_bustype)
+       else if (is_pci_board(thisboard))
                tmplen = scnprintf(tmpbuf, sizeof(tmpbuf),
                                   "(pci %s) ", pci_name(pcidev));
        else
@@ -1361,8 +1372,7 @@ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it)
        }
 
        /* Process options and reserve resources according to bus type. */
-       if (IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA) &&
-           thisboard->bustype == isa_bustype) {
+       if (is_isa_board(thisboard)) {
                unsigned long iobase;
                unsigned int irq;
 
@@ -1372,8 +1382,7 @@ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it)
                if (ret < 0)
                        return ret;
                return dio200_common_attach(dev, iobase, irq, 0);
-       } else if (IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_PCI) &&
-                  thisboard->bustype == pci_bustype) {
+       } else if (is_pci_board(thisboard)) {
                struct pci_dev *pci_dev;
 
                pci_dev = dio200_find_pci_dev(dev, it);
@@ -1397,7 +1406,7 @@ static int __devinit dio200_attach_pci(struct comedi_device *dev,
 {
        int ret;
 
-       if (!IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_PCI))
+       if (!DO_PCI)
                return -EINVAL;
 
        dev_info(dev->class_dev, DIO200_DRIVER_NAME ": attach pci %s\n",
@@ -1418,7 +1427,6 @@ static int __devinit dio200_attach_pci(struct comedi_device *dev,
 static void dio200_detach(struct comedi_device *dev)
 {
        const struct dio200_board *thisboard = comedi_board(dev);
-       struct pci_dev *pcidev = comedi_to_pci_dev(dev);
        const struct dio200_layout_struct *layout;
        unsigned n;
 
@@ -1443,13 +1451,16 @@ static void dio200_detach(struct comedi_device *dev)
                        }
                }
        }
-       if (pcidev) {
-               if (dev->iobase)
-                       comedi_pci_disable(pcidev);
-               pci_dev_put(pcidev);
-       } else {
+       if (is_isa_board(thisboard)) {
                if (dev->iobase)
                        release_region(dev->iobase, DIO200_IO_SIZE);
+       } else if (is_pci_board(thisboard)) {
+               struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+               if (pcidev) {
+                       if (dev->iobase)
+                               comedi_pci_disable(pcidev);
+                       pci_dev_put(pcidev);
+               }
        }
 }
 
@@ -1470,7 +1481,7 @@ static struct comedi_driver amplc_dio200_driver = {
        .num_names = ARRAY_SIZE(dio200_boards),
 };
 
-#if IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_PCI)
+#if DO_PCI
 static DEFINE_PCI_DEVICE_TABLE(dio200_pci_table) = {
        { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI215) },
        { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI272) },
index aabba9886b7d9276eb1c4233c89ce894685fbd58..c64438580b219f0ebf6e77054c27e123c2fc18f0 100644 (file)
@@ -61,6 +61,9 @@ unused.
 
 #define PC236_DRIVER_NAME      "amplc_pc236"
 
+#define DO_ISA IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_ISA)
+#define DO_PCI IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI)
+
 /* PCI236 PCI configuration register information */
 #define PCI_VENDOR_ID_AMPLICON 0x14dc
 #define PCI_DEVICE_ID_AMPLICON_PCI236 0x0009
@@ -103,14 +106,14 @@ struct pc236_board {
        enum pc236_model model;
 };
 static const struct pc236_board pc236_boards[] = {
-#if IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_ISA)
+#if DO_ISA
        {
                .name = "pc36at",
                .bustype = isa_bustype,
                .model = pc36at_model,
        },
 #endif
-#if IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI)
+#if DO_PCI
        {
                .name = "pci236",
                .devid = PCI_DEVICE_ID_AMPLICON_PCI236,
@@ -135,6 +138,18 @@ struct pc236_private {
        int enable_irq;
 };
 
+/* test if ISA supported and this is an ISA board */
+static inline bool is_isa_board(const struct pc236_board *board)
+{
+       return DO_ISA && board->bustype == isa_bustype;
+}
+
+/* test if PCI supported and this is a PCI board */
+static inline bool is_pci_board(const struct pc236_board *board)
+{
+       return DO_PCI && board->bustype == pci_bustype;
+}
+
 /*
  * This function looks for a board matching the supplied PCI device.
  */
@@ -143,7 +158,7 @@ static const struct pc236_board *pc236_find_pci_board(struct pci_dev *pci_dev)
        unsigned int i;
 
        for (i = 0; i < ARRAY_SIZE(pc236_boards); i++)
-               if (pc236_boards[i].bustype == pci_bustype &&
+               if (is_pci_board(&pc236_boards[i]) &&
                    pci_dev->device == pc236_boards[i].devid)
                        return &pc236_boards[i];
        return NULL;
@@ -214,12 +229,13 @@ static int pc236_request_region(struct comedi_device *dev, unsigned long from,
  */
 static void pc236_intr_disable(struct comedi_device *dev)
 {
+       const struct pc236_board *thisboard = comedi_board(dev);
        struct pc236_private *devpriv = dev->private;
        unsigned long flags;
 
        spin_lock_irqsave(&dev->spinlock, flags);
        devpriv->enable_irq = 0;
-       if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI) && devpriv->lcr_iobase)
+       if (is_pci_board(thisboard))
                outl(PCI236_INTR_DISABLE, devpriv->lcr_iobase + PLX9052_INTCSR);
        spin_unlock_irqrestore(&dev->spinlock, flags);
 }
@@ -231,12 +247,13 @@ static void pc236_intr_disable(struct comedi_device *dev)
  */
 static void pc236_intr_enable(struct comedi_device *dev)
 {
+       const struct pc236_board *thisboard = comedi_board(dev);
        struct pc236_private *devpriv = dev->private;
        unsigned long flags;
 
        spin_lock_irqsave(&dev->spinlock, flags);
        devpriv->enable_irq = 1;
-       if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI) && devpriv->lcr_iobase)
+       if (is_pci_board(thisboard))
                outl(PCI236_INTR_ENABLE, devpriv->lcr_iobase + PLX9052_INTCSR);
        spin_unlock_irqrestore(&dev->spinlock, flags);
 }
@@ -250,6 +267,7 @@ static void pc236_intr_enable(struct comedi_device *dev)
  */
 static int pc236_intr_check(struct comedi_device *dev)
 {
+       const struct pc236_board *thisboard = comedi_board(dev);
        struct pc236_private *devpriv = dev->private;
        int retval = 0;
        unsigned long flags;
@@ -257,8 +275,7 @@ static int pc236_intr_check(struct comedi_device *dev)
        spin_lock_irqsave(&dev->spinlock, flags);
        if (devpriv->enable_irq) {
                retval = 1;
-               if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI) &&
-                   devpriv->lcr_iobase) {
+               if (is_pci_board(thisboard)) {
                        if ((inl(devpriv->lcr_iobase + PLX9052_INTCSR)
                             & PLX9052_INTCSR_LI1STAT_MASK)
                            == PLX9052_INTCSR_LI1STAT_INACTIVE) {
@@ -414,15 +431,13 @@ static void pc236_report_attach(struct comedi_device *dev, unsigned int irq)
        char tmpbuf[60];
        int tmplen;
 
-       if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_ISA) &&
-           thisboard->bustype == isa_bustype)
+       if (is_isa_board(thisboard))
                tmplen = scnprintf(tmpbuf, sizeof(tmpbuf),
                                   "(base %#lx) ", dev->iobase);
-       else if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI) &&
-                thisboard->bustype == pci_bustype) {
+       else if (is_pci_board(thisboard))
                tmplen = scnprintf(tmpbuf, sizeof(tmpbuf),
                                   "(pci %s) ", pci_name(pcidev));
-       else
+       else
                tmplen = 0;
        if (irq)
                tmplen += scnprintf(&tmpbuf[tmplen], sizeof(tmpbuf) - tmplen,
@@ -517,16 +532,14 @@ static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it)
                return ret;
        }
        /* Process options according to bus type. */
-       if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_ISA) &&
-           thisboard->bustype == isa_bustype) {
+       if (is_isa_board(thisboard)) {
                unsigned long iobase = it->options[0];
                unsigned int irq = it->options[1];
                ret = pc236_request_region(dev, iobase, PC236_IO_SIZE);
                if (ret < 0)
                        return ret;
                return pc236_common_attach(dev, iobase, irq, 0);
-       } else if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI) &&
-                  thisboard->bustype == pci_bustype) {
+       } else if (is_pci_board(thisboard)) {
                struct pci_dev *pci_dev;
 
                pci_dev = pc236_find_pci_dev(dev, it);
@@ -550,7 +563,7 @@ static int __devinit pc236_attach_pci(struct comedi_device *dev,
 {
        int ret;
 
-       if (!IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI))
+       if (!DO_PCI)
                return -EINVAL;
 
        dev_info(dev->class_dev, PC236_DRIVER_NAME ": attach pci %s\n",
@@ -570,8 +583,8 @@ static int __devinit pc236_attach_pci(struct comedi_device *dev,
 
 static void pc236_detach(struct comedi_device *dev)
 {
+       const struct pc236_board *thisboard = comedi_board(dev);
        struct pc236_private *devpriv = dev->private;
-       struct pci_dev *pcidev = comedi_to_pci_dev(dev);
 
        if (devpriv)
                pc236_intr_disable(dev);
@@ -579,13 +592,16 @@ static void pc236_detach(struct comedi_device *dev)
                free_irq(dev->irq, dev);
        if (dev->subdevices)
                subdev_8255_cleanup(dev, dev->subdevices + 0);
-       if (pcidev) {
-               if (dev->iobase)
-                       comedi_pci_disable(pcidev);
-               pci_dev_put(pcidev);
-       } else {
+       if (is_isa_board(thisboard)) {
                if (dev->iobase)
                        release_region(dev->iobase, PC236_IO_SIZE);
+       } else if (is_pci_board(thisboard)) {
+               struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+               if (pcidev) {
+                       if (dev->iobase)
+                               comedi_pci_disable(pcidev);
+                       pci_dev_put(pcidev);
+               }
        }
 }
 
@@ -606,7 +622,7 @@ static struct comedi_driver amplc_pc236_driver = {
        .num_names = ARRAY_SIZE(pc236_boards),
 };
 
-#if IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI)
+#if DO_PCI
 static DEFINE_PCI_DEVICE_TABLE(pc236_pci_table) = {
        { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI236) },
        {0}
index 40ec1ffebba651fda62f23af21ff7b0e3ef097a4..148c9d3acf64d14d89e480d46f8c09cb624b2feb 100644 (file)
@@ -48,6 +48,9 @@ The state of the outputs can be read.
 
 #define PC263_DRIVER_NAME      "amplc_pc263"
 
+#define DO_ISA IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_ISA)
+#define DO_PCI IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_PCI)
+
 /* PCI263 PCI configuration register information */
 #define PCI_VENDOR_ID_AMPLICON 0x14dc
 #define PCI_DEVICE_ID_AMPLICON_PCI263 0x000c
@@ -70,14 +73,14 @@ struct pc263_board {
        enum pc263_model model;
 };
 static const struct pc263_board pc263_boards[] = {
-#if IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_ISA)
+#if DO_ISA
        {
                .name = "pc263",
                .bustype = isa_bustype,
                .model = pc263_model,
        },
 #endif
-#if IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_PCI)
+#if DO_PCI
        {
                .name = "pci263",
                .devid = PCI_DEVICE_ID_AMPLICON_PCI263,
@@ -93,6 +96,18 @@ static const struct pc263_board pc263_boards[] = {
 #endif
 };
 
+/* test if ISA supported and this is an ISA board */
+static inline bool is_isa_board(const struct pc263_board *board)
+{
+       return DO_ISA && board->bustype == isa_bustype;
+}
+
+/* test if PCI supported and this is a PCI board */
+static inline bool is_pci_board(const struct pc263_board *board)
+{
+       return DO_PCI && board->bustype == pci_bustype;
+}
+
 /*
  * This function looks for a board matching the supplied PCI device.
  */
@@ -101,7 +116,7 @@ static const struct pc263_board *pc263_find_pci_board(struct pci_dev *pci_dev)
        unsigned int i;
 
        for (i = 0; i < ARRAY_SIZE(pc263_boards); i++)
-               if (pc263_boards[i].bustype == pci_bustype &&
+               if (is_pci_board(&pc263_boards[i]) &&
                    pci_dev->device == pc263_boards[i].devid)
                        return &pc263_boards[i];
        return NULL;
@@ -187,11 +202,9 @@ static void pc263_report_attach(struct comedi_device *dev)
        struct pci_dev *pcidev = comedi_to_pci_dev(dev);
        char tmpbuf[40];
 
-       if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_ISA) &&
-           thisboard->bustype == isa_bustype)
+       if (is_isa_board(thisboard))
                snprintf(tmpbuf, sizeof(tmpbuf), "(base %#lx) ", dev->iobase);
-       else if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_PCI) &&
-                thisboard->bustype == pci_bustype)
+       else if (is_pci_board(thisboard))
                snprintf(tmpbuf, sizeof(tmpbuf), "(pci %s) ",
                         pci_name(pcidev));
        else
@@ -259,15 +272,13 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it)
        dev_info(dev->class_dev, PC263_DRIVER_NAME ": attach\n");
 
        /* Process options and reserve resources according to bus type. */
-       if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_ISA) &&
-           thisboard->bustype == isa_bustype) {
+       if (is_isa_board(thisboard)) {
                unsigned long iobase = it->options[0];
                ret = pc263_request_region(dev, iobase, PC263_IO_SIZE);
                if (ret < 0)
                        return ret;
                return pc263_common_attach(dev, iobase);
-       } else if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_PCI) &&
-                  thisboard->bustype == pci_bustype) {
+       } else if (is_pci_board(thisboard)) {
                struct pci_dev *pci_dev;
 
                pci_dev = pc263_find_pci_dev(dev, it);
@@ -288,7 +299,7 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 static int __devinit pc263_attach_pci(struct comedi_device *dev,
                                      struct pci_dev *pci_dev)
 {
-       if (!IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_PCI))
+       if (!DO_PCI)
                return -EINVAL;
 
        dev_info(dev->class_dev, PC263_DRIVER_NAME ": attach pci %s\n",
@@ -303,15 +314,18 @@ static int __devinit pc263_attach_pci(struct comedi_device *dev,
 
 static void pc263_detach(struct comedi_device *dev)
 {
-       struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+       const struct pc263_board *thisboard = comedi_board(dev);
 
-       if (pcidev) {
-               if (dev->iobase)
-                       comedi_pci_disable(pcidev);
-               pci_dev_put(pcidev);
-       } else {
+       if (is_isa_board(thisboard)) {
                if (dev->iobase)
                        release_region(dev->iobase, PC263_IO_SIZE);
+       } else if (is_pci_board(thisboard)) {
+               struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+               if (pcidev) {
+                       if (dev->iobase)
+                               comedi_pci_disable(pcidev);
+                       pci_dev_put(pcidev);
+               }
        }
 }
 
@@ -332,7 +346,7 @@ static struct comedi_driver amplc_pc263_driver = {
        .num_names = ARRAY_SIZE(pc263_boards),
 };
 
-#if IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_PCI)
+#if DO_PCI
 static DEFINE_PCI_DEVICE_TABLE(pc263_pci_table) = {
        { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI263) },
        {0}
index 944cfeeb2b2d5bb06fbcad0d229d52d785e3e1bb..12ad9fa32f5679befc1a187bb3b65ff706eff612 100644 (file)
@@ -27,51 +27,35 @@ Author: Stefano Rivoir <s.rivoir@gts.it>
 Updated: Wed, 27 Jun 2007 13:00:06 +0100
 Status: works
 
-Configuration Options:
-  [0] - PCI bus of device (optional)
-  [1] - PCI slot of device (optional)
-  If bus/slot is not specified, the first supported
-  PCI device found will be used.
+Configuration Options: not applicable, uses comedi PCI auto config
 */
 
 #include "../comedidev.h"
 
-enum contec_model {
-       PIO1616L = 0,
-};
-
-struct contec_board {
-       const char *name;
-       int model;
-       int in_ports;
-       int out_ports;
-       int in_offs;
-       int out_offs;
-       int out_boffs;
-};
-static const struct contec_board contec_boards[] = {
-       {"PIO1616L", PIO1616L, 16, 16, 0, 2, 10},
-};
-
 #define PCI_DEVICE_ID_PIO1616L 0x8172
 
-#define thisboard ((const struct contec_board *)dev->board_ptr)
+/*
+ * Register map
+ */
+#define PIO1616L_DI_REG                0x00
+#define PIO1616L_DO_REG                0x02
 
 static int contec_do_insn_bits(struct comedi_device *dev,
                               struct comedi_subdevice *s,
                               struct comedi_insn *insn, unsigned int *data)
 {
+       unsigned int mask = data[0];
+       unsigned int bits = data[1];
 
-       dev_dbg(dev->class_dev, "contec_do_insn_bits called\n");
-       dev_dbg(dev->class_dev, "data: %d %d\n", data[0], data[1]);
+       if (mask) {
+               s->state &= ~mask;
+               s->state |= (bits & mask);
 
-       if (data[0]) {
-               s->state &= ~data[0];
-               s->state |= data[0] & data[1];
-               dev_dbg(dev->class_dev, "out: %d on %lx\n", s->state,
-                       dev->iobase + thisboard->out_offs);
-               outw(s->state, dev->iobase + thisboard->out_offs);
+               outw(s->state, dev->iobase + PIO1616L_DO_REG);
        }
+
+       data[1] = s->state;
+
        return insn->n;
 }
 
@@ -79,87 +63,58 @@ static int contec_di_insn_bits(struct comedi_device *dev,
                               struct comedi_subdevice *s,
                               struct comedi_insn *insn, unsigned int *data)
 {
-
-       dev_dbg(dev->class_dev, "contec_di_insn_bits called\n");
-       dev_dbg(dev->class_dev, "data: %d %d\n", data[0], data[1]);
-
-       data[1] = inw(dev->iobase + thisboard->in_offs);
+       data[1] = inw(dev->iobase + PIO1616L_DI_REG);
 
        return insn->n;
 }
 
-static struct pci_dev *contec_find_pci_dev(struct comedi_device *dev,
-                                          struct comedi_devconfig *it)
+static int contec_attach_pci(struct comedi_device *dev,
+                            struct pci_dev *pcidev)
 {
-       struct pci_dev *pcidev = NULL;
-       int bus = it->options[0];
-       int slot = it->options[1];
-
-       for_each_pci_dev(pcidev) {
-               if (bus || slot) {
-                       if (bus != pcidev->bus->number ||
-                               slot != PCI_SLOT(pcidev->devfn))
-                               continue;
-               }
-               if (pcidev->vendor != PCI_VENDOR_ID_CONTEC ||
-                   pcidev->device != PCI_DEVICE_ID_PIO1616L)
-                       continue;
-
-               dev->board_ptr = contec_boards + 0;
-               return pcidev;
-       }
-       dev_err(dev->class_dev,
-               "No supported board found! (req. bus %d, slot %d)\n",
-               bus, slot);
-       return NULL;
-}
-
-static int contec_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{
-       struct pci_dev *pcidev;
        struct comedi_subdevice *s;
        int ret;
 
-       printk("comedi%d: contec: ", dev->minor);
+       comedi_set_hw_dev(dev, &pcidev->dev);
 
-       dev->board_name = thisboard->name;
+       dev->board_name = dev->driver->driver_name;
 
-       ret = comedi_alloc_subdevices(dev, 2);
+       ret = comedi_pci_enable(pcidev, dev->board_name);
        if (ret)
                return ret;
-
-       pcidev = contec_find_pci_dev(dev, it);
-       if (!pcidev)
-               return -EIO;
-       comedi_set_hw_dev(dev, &pcidev->dev);
-
-       if (comedi_pci_enable(pcidev, "contec_pci_dio")) {
-               printk("error enabling PCI device and request regions!\n");
-               return -EIO;
-       }
        dev->iobase = pci_resource_start(pcidev, 0);
-       printk(" base addr %lx ", dev->iobase);
 
-       s = dev->subdevices + 0;
+       ret = comedi_alloc_subdevices(dev, 2);
+       if (ret)
+               return ret;
 
-       s->type = COMEDI_SUBD_DI;
-       s->subdev_flags = SDF_READABLE;
-       s->n_chan = 16;
-       s->maxdata = 1;
-       s->range_table = &range_digital;
-       s->insn_bits = contec_di_insn_bits;
+       s = dev->subdevices + 0;
+       s->type         = COMEDI_SUBD_DI;
+       s->subdev_flags = SDF_READABLE;
+       s->n_chan       = 16;
+       s->maxdata      = 1;
+       s->range_table  = &range_digital;
+       s->insn_bits    = contec_di_insn_bits;
 
        s = dev->subdevices + 1;
-       s->type = COMEDI_SUBD_DO;
-       s->subdev_flags = SDF_WRITABLE;
-       s->n_chan = 16;
-       s->maxdata = 1;
-       s->range_table = &range_digital;
-       s->insn_bits = contec_do_insn_bits;
+       s->type         = COMEDI_SUBD_DO;
+       s->subdev_flags = SDF_WRITABLE;
+       s->n_chan       = 16;
+       s->maxdata      = 1;
+       s->range_table  = &range_digital;
+       s->insn_bits    = contec_do_insn_bits;
+
+       dev_info(dev->class_dev, "%s attached\n", dev->board_name);
 
-       printk("attached\n");
+       return 0;
+}
+
+static int contec_attach(struct comedi_device *dev,
+                        struct comedi_devconfig *it)
+{
+       dev_warn(dev->class_dev,
+               "This driver does not support attach using comedi_config\n");
 
-       return 1;
+       return -ENOSYS;
 }
 
 static void contec_detach(struct comedi_device *dev)
@@ -169,7 +124,6 @@ static void contec_detach(struct comedi_device *dev)
        if (pcidev) {
                if (dev->iobase)
                        comedi_pci_disable(pcidev);
-               pci_dev_put(pcidev);
        }
 }
 
@@ -177,6 +131,7 @@ static struct comedi_driver contec_pci_dio_driver = {
        .driver_name    = "contec_pci_dio",
        .module         = THIS_MODULE,
        .attach         = contec_attach,
+       .attach_pci     = contec_attach_pci,
        .detach         = contec_detach,
 };
 
@@ -192,8 +147,7 @@ static void __devexit contec_pci_dio_pci_remove(struct pci_dev *dev)
 }
 
 static DEFINE_PCI_DEVICE_TABLE(contec_pci_dio_pci_table) = {
-       { PCI_DEVICE(PCI_VENDOR_ID_CONTEC, PCI_DEVICE_ID_PIO1616L),
-               .driver_data = PIO1616L },
+       { PCI_DEVICE(PCI_VENDOR_ID_CONTEC, PCI_DEVICE_ID_PIO1616L) },
        { 0 }
 };
 MODULE_DEVICE_TABLE(pci, contec_pci_dio_pci_table);
index ef28385c14825808a88181ec2e3ad8cee7cbca10..cad559a1a730775c1d3d1589b995f6381ac28cb7 100644 (file)
@@ -718,7 +718,8 @@ static struct pci_dev *daqboard2000_find_pci_dev(struct comedi_device *dev,
                                continue;
                }
                if (pcidev->vendor != PCI_VENDOR_ID_IOTECH ||
-                   pcidev->device != 0x0409)
+                   pcidev->device != 0x0409 ||
+                   pcidev->subsystem_device != PCI_VENDOR_ID_IOTECH)
                        continue;
 
                for (i = 0; i < ARRAY_SIZE(boardtypes); i++) {
@@ -739,6 +740,7 @@ static int daqboard2000_attach(struct comedi_device *dev,
 {
        struct pci_dev *pcidev;
        struct comedi_subdevice *s;
+       resource_size_t pci_base;
        void *aux_data;
        unsigned int aux_len;
        int result;
@@ -758,11 +760,12 @@ static int daqboard2000_attach(struct comedi_device *dev,
                        "failed to enable PCI device and request regions\n");
                return -EIO;
        }
-       dev->iobase = pci_resource_start(pcidev, 2);
+       dev->iobase = 1;        /* the "detach" needs this */
 
-       devpriv->plx =
-           ioremap(pci_resource_start(pcidev, 0), DAQBOARD2000_PLX_SIZE);
-       devpriv->daq = ioremap(dev->iobase, DAQBOARD2000_DAQ_SIZE);
+       pci_base = pci_resource_start(pcidev, 0);
+       devpriv->plx = ioremap(pci_base, DAQBOARD2000_PLX_SIZE);
+       pci_base = pci_resource_start(pcidev, 2);
+       devpriv->daq = ioremap(pci_base, DAQBOARD2000_DAQ_SIZE);
        if (!devpriv->plx || !devpriv->daq)
                return -ENOMEM;
 
@@ -799,8 +802,6 @@ static int daqboard2000_attach(struct comedi_device *dev,
           printk("Interrupt after is: %x\n", interrupt);
         */
 
-       dev->iobase = (unsigned long)devpriv->daq;
-
        dev->board_name = this_board->name;
 
        s = dev->subdevices + 0;
@@ -824,7 +825,7 @@ static int daqboard2000_attach(struct comedi_device *dev,
 
        s = dev->subdevices + 2;
        result = subdev_8255_init(dev, s, daqboard2000_8255_cb,
-                                 (unsigned long)(dev->iobase + 0x40));
+                                 (unsigned long)(devpriv->daq + 0x40));
 
 out:
        return result;
index a6fe6c9be87eb1599e59f995245f0958095be5a5..3476cda0fff04e8e7df1f3f716f94a2406c799e5 100644 (file)
@@ -804,6 +804,7 @@ static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 {
        struct pci_dev *pcidev;
        struct comedi_subdevice *s;
+       resource_size_t pci_base;
        int ret = 0;
 
        dev_dbg(dev->class_dev, "dt3000:\n");
@@ -820,9 +821,10 @@ static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it)
        ret = comedi_pci_enable(pcidev, "dt3000");
        if (ret < 0)
                return ret;
+       dev->iobase = 1;        /* the "detach" needs this */
 
-       dev->iobase = pci_resource_start(pcidev, 0);
-       devpriv->io_addr = ioremap(dev->iobase, DT3000_SIZE);
+       pci_base  = pci_resource_start(pcidev, 0);
+       devpriv->io_addr = ioremap(pci_base, DT3000_SIZE);
        if (!devpriv->io_addr)
                return -ENOMEM;
 
index 064be9aae3aaeaa853584e36a9f16ae117483a6c..e852808c6314842bdc14541a94ac4af3559692c6 100644 (file)
@@ -41,7 +41,6 @@
 #include <linux/mutex.h>
 
 #define PCI_VENDOR_ID_DYNALOG          0x10b5
-#define DRV_NAME                       "dyna_pci10xx"
 
 #define READ_TIMEOUT 50
 
@@ -54,59 +53,11 @@ static const struct comedi_lrange range_pci1050_ai = { 3, {
 
 static const char range_codes_pci1050_ai[] = { 0x00, 0x10, 0x30 };
 
-static const struct comedi_lrange range_pci1050_ao = { 1, {
-                                                         UNI_RANGE(10)
-                                                         }
-};
-
-static const char range_codes_pci1050_ao[] = { 0x00 };
-
-struct boardtype {
-       const char *name;
-       int device_id;
-       int ai_chans;
-       int ai_bits;
-       int ao_chans;
-       int ao_bits;
-       int di_chans;
-       int di_bits;
-       int do_chans;
-       int do_bits;
-       const struct comedi_lrange *range_ai;
-       const char *range_codes_ai;
-       const struct comedi_lrange *range_ao;
-       const char *range_codes_ao;
-};
-
-static const struct boardtype boardtypes[] = {
-       {
-       .name = "dyna_pci1050",
-       .device_id = 0x1050,
-       .ai_chans = 16,
-       .ai_bits = 12,
-       .ao_chans = 16,
-       .ao_bits = 12,
-       .di_chans = 16,
-       .di_bits = 16,
-       .do_chans = 16,
-       .do_bits = 16,
-       .range_ai = &range_pci1050_ai,
-       .range_codes_ai = range_codes_pci1050_ai,
-       .range_ao = &range_pci1050_ao,
-       .range_codes_ao = range_codes_pci1050_ao,
-       },
-       /*  dummy entry corresponding to driver name */
-       {.name = DRV_NAME},
-};
-
 struct dyna_pci10xx_private {
        struct mutex mutex;
        unsigned long BADR3;
 };
 
-#define thisboard ((const struct boardtype *)dev->board_ptr)
-#define devpriv ((struct dyna_pci10xx_private *)dev->private)
-
 /******************************************************************************/
 /************************** READ WRITE FUNCTIONS ******************************/
 /******************************************************************************/
@@ -116,13 +67,14 @@ static int dyna_pci10xx_insn_read_ai(struct comedi_device *dev,
                        struct comedi_subdevice *s,
                        struct comedi_insn *insn, unsigned int *data)
 {
+       struct dyna_pci10xx_private *devpriv = dev->private;
        int n, counter;
        u16 d = 0;
        unsigned int chan, range;
 
        /* get the channel number and range */
        chan = CR_CHAN(insn->chanspec);
-       range = thisboard->range_codes_ai[CR_RANGE((insn->chanspec))];
+       range = range_codes_pci1050_ai[CR_RANGE((insn->chanspec))];
 
        mutex_lock(&devpriv->mutex);
        /* convert n samples */
@@ -159,11 +111,12 @@ static int dyna_pci10xx_insn_write_ao(struct comedi_device *dev,
                                 struct comedi_subdevice *s,
                                 struct comedi_insn *insn, unsigned int *data)
 {
+       struct dyna_pci10xx_private *devpriv = dev->private;
        int n;
        unsigned int chan, range;
 
        chan = CR_CHAN(insn->chanspec);
-       range = thisboard->range_codes_ai[CR_RANGE((insn->chanspec))];
+       range = range_codes_pci1050_ai[CR_RANGE((insn->chanspec))];
 
        mutex_lock(&devpriv->mutex);
        for (n = 0; n < insn->n; n++) {
@@ -181,6 +134,7 @@ static int dyna_pci10xx_di_insn_bits(struct comedi_device *dev,
                              struct comedi_subdevice *s,
                              struct comedi_insn *insn, unsigned int *data)
 {
+       struct dyna_pci10xx_private *devpriv = dev->private;
        u16 d = 0;
 
        mutex_lock(&devpriv->mutex);
@@ -200,6 +154,8 @@ static int dyna_pci10xx_do_insn_bits(struct comedi_device *dev,
                              struct comedi_subdevice *s,
                              struct comedi_insn *insn, unsigned int *data)
 {
+       struct dyna_pci10xx_private *devpriv = dev->private;
+
        /* The insn data is a mask in data[0] and the new data
         * in data[1], each channel cooresponding to a bit.
         * s->state contains the previous write data
@@ -223,71 +179,30 @@ static int dyna_pci10xx_do_insn_bits(struct comedi_device *dev,
        return insn->n;
 }
 
-static struct pci_dev *dyna_pci10xx_find_pci_dev(struct comedi_device *dev,
-                                                struct comedi_devconfig *it)
-{
-       struct pci_dev *pcidev = NULL;
-       int bus = it->options[0];
-       int slot = it->options[1];
-       int i;
-
-       for_each_pci_dev(pcidev) {
-               if (bus || slot) {
-                       if (bus != pcidev->bus->number ||
-                           slot != PCI_SLOT(pcidev->devfn))
-                               continue;
-               }
-               if (pcidev->vendor != PCI_VENDOR_ID_DYNALOG)
-                       continue;
-
-               for (i = 0; i < ARRAY_SIZE(boardtypes); ++i) {
-                       if (pcidev->device != boardtypes[i].device_id)
-                               continue;
-
-                       dev->board_ptr = &boardtypes[i];
-                       return pcidev;
-               }
-       }
-       dev_err(dev->class_dev,
-               "No supported board found! (req. bus %d, slot %d)\n",
-               bus, slot);
-       return NULL;
-}
-
-static int dyna_pci10xx_attach(struct comedi_device *dev,
-                         struct comedi_devconfig *it)
+static int dyna_pci10xx_attach_pci(struct comedi_device *dev,
+                                  struct pci_dev *pcidev)
 {
-       struct pci_dev *pcidev;
+       struct dyna_pci10xx_private *devpriv;
        struct comedi_subdevice *s;
        int ret;
 
-       if (alloc_private(dev, sizeof(struct dyna_pci10xx_private)) < 0) {
-               printk(KERN_ERR "comedi: dyna_pci10xx: "
-                       "failed to allocate memory!\n");
-               return -ENOMEM;
-       }
-
-       pcidev = dyna_pci10xx_find_pci_dev(dev, it);
-       if (!pcidev)
-               return -EIO;
        comedi_set_hw_dev(dev, &pcidev->dev);
 
-       dev->board_name = thisboard->name;
-       dev->irq = 0;
-
-       if (comedi_pci_enable(pcidev, DRV_NAME)) {
-               printk(KERN_ERR "comedi: dyna_pci10xx: "
-                       "failed to enable PCI device and request regions!");
-               return -EIO;
-       }
-
-       mutex_init(&devpriv->mutex);
+       dev->board_name = dev->driver->driver_name;
 
-       printk(KERN_INFO "comedi: dyna_pci10xx: device found!\n");
+       ret = alloc_private(dev, sizeof(*devpriv));
+       if (ret)
+               return ret;
+       devpriv = dev->private;
 
+       ret = comedi_pci_enable(pcidev, dev->board_name);
+       if (ret)
+               return ret;
        dev->iobase = pci_resource_start(pcidev, 2);
        devpriv->BADR3 = pci_resource_start(pcidev, 3);
 
+       mutex_init(&devpriv->mutex);
+
        ret = comedi_alloc_subdevices(dev, 4);
        if (ret)
                return ret;
@@ -296,9 +211,9 @@ static int dyna_pci10xx_attach(struct comedi_device *dev,
        s = dev->subdevices + 0;
        s->type = COMEDI_SUBD_AI;
        s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
-       s->n_chan = thisboard->ai_chans;
+       s->n_chan = 16;
        s->maxdata = 0x0FFF;
-       s->range_table = thisboard->range_ai;
+       s->range_table = &range_pci1050_ai;
        s->len_chanlist = 16;
        s->insn_read = dyna_pci10xx_insn_read_ai;
 
@@ -306,9 +221,9 @@ static int dyna_pci10xx_attach(struct comedi_device *dev,
        s = dev->subdevices + 1;
        s->type = COMEDI_SUBD_AO;
        s->subdev_flags = SDF_WRITABLE;
-       s->n_chan = thisboard->ao_chans;
+       s->n_chan = 16;
        s->maxdata = 0x0FFF;
-       s->range_table = thisboard->range_ao;
+       s->range_table = &range_unipolar10;
        s->len_chanlist = 16;
        s->insn_write = dyna_pci10xx_insn_write_ao;
 
@@ -316,39 +231,47 @@ static int dyna_pci10xx_attach(struct comedi_device *dev,
        s = dev->subdevices + 2;
        s->type = COMEDI_SUBD_DI;
        s->subdev_flags = SDF_READABLE | SDF_GROUND;
-       s->n_chan = thisboard->di_chans;
+       s->n_chan = 16;
        s->maxdata = 1;
        s->range_table = &range_digital;
-       s->len_chanlist = thisboard->di_chans;
+       s->len_chanlist = 16;
        s->insn_bits = dyna_pci10xx_di_insn_bits;
 
        /* digital output */
        s = dev->subdevices + 3;
        s->type = COMEDI_SUBD_DO;
        s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
-       s->n_chan = thisboard->do_chans;
+       s->n_chan = 16;
        s->maxdata = 1;
        s->range_table = &range_digital;
-       s->len_chanlist = thisboard->do_chans;
+       s->len_chanlist = 16;
        s->state = 0;
        s->insn_bits = dyna_pci10xx_do_insn_bits;
 
-       printk(KERN_INFO "comedi: dyna_pci10xx: %s - device setup completed!\n",
-               thisboard->name);
+       dev_info(dev->class_dev, "%s attached\n", dev->board_name);
+
+       return 0;
+}
+
+static int dyna_pci10xx_attach(struct comedi_device *dev,
+                              struct comedi_devconfig *it)
+{
+       dev_warn(dev->class_dev,
+               "This driver does not support attach using comedi_config\n");
 
-       return 1;
+       return -ENOSYS;
 }
 
 static void dyna_pci10xx_detach(struct comedi_device *dev)
 {
        struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+       struct dyna_pci10xx_private *devpriv = dev->private;
 
        if (devpriv)
                mutex_destroy(&devpriv->mutex);
        if (pcidev) {
                if (dev->iobase)
                        comedi_pci_disable(pcidev);
-               pci_dev_put(pcidev);
        }
 }
 
@@ -356,10 +279,8 @@ static struct comedi_driver dyna_pci10xx_driver = {
        .driver_name    = "dyna_pci10xx",
        .module         = THIS_MODULE,
        .attach         = dyna_pci10xx_attach,
+       .attach_pci     = dyna_pci10xx_attach_pci,
        .detach         = dyna_pci10xx_detach,
-       .board_name     = &boardtypes[0].name,
-       .offset         = sizeof(struct boardtype),
-       .num_names      = ARRAY_SIZE(boardtypes),
 };
 
 static int __devinit dyna_pci10xx_pci_probe(struct pci_dev *dev,
index 112fdc3e9c69dddcf64c322194b3d4a3d275b6bf..5aa8be1e7b9217cb6027d3652e134a3f17f1b300 100644 (file)
@@ -1619,9 +1619,8 @@ static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it)
        struct rtdPrivate *devpriv;
        struct pci_dev *pcidev;
        struct comedi_subdevice *s;
+       resource_size_t pci_base;
        int ret;
-       resource_size_t physLas1;       /* data area */
-       resource_size_t physLcfg;       /* PLX9080 */
 #ifdef USE_DMA
        int index;
 #endif
@@ -1655,20 +1654,15 @@ static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it)
                printk(KERN_INFO "Failed to enable PCI device and request regions.\n");
                return ret;
        }
-
-       /*
-        * Initialize base addresses
-        */
-       /* Get the physical address from PCI config */
-       dev->iobase = pci_resource_start(pcidev, LAS0_PCIINDEX);
-       physLas1 = pci_resource_start(pcidev, LAS1_PCIINDEX);
-       physLcfg = pci_resource_start(pcidev, LCFG_PCIINDEX);
-       /* Now have the kernel map this into memory */
-       /* ASSUME page aligned */
-       devpriv->las0 = ioremap_nocache(dev->iobase, LAS0_PCISIZE);
-       devpriv->las1 = ioremap_nocache(physLas1, LAS1_PCISIZE);
-       devpriv->lcfg = ioremap_nocache(physLcfg, LCFG_PCISIZE);
-
+       dev->iobase = 1;        /* the "detach" needs this */
+
+       /* Initialize the base addresses */
+       pci_base = pci_resource_start(pcidev, LAS0_PCIINDEX);
+       devpriv->las0 = ioremap_nocache(pci_base, LAS0_PCISIZE);
+       pci_base = pci_resource_start(pcidev, LAS1_PCIINDEX);
+       devpriv->las1 = ioremap_nocache(pci_base, LAS1_PCISIZE);
+       pci_base = pci_resource_start(pcidev, LCFG_PCIINDEX);
+       devpriv->lcfg = ioremap_nocache(pci_base, LCFG_PCISIZE);
        if (!devpriv->las0 || !devpriv->las1 || !devpriv->lcfg)
                return -ENOMEM;
 
index 84b9f2a4280b6450fdc7da54bc166f0bf88694e7..d1f5118c3afa2b71bca68b598ba2f91240e68a97 100644 (file)
@@ -177,8 +177,6 @@ static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it)
        struct comedi_subdevice *s;
        int ret;
 
-       printk(KERN_INFO "comedi%d: dnp: ", dev->minor);
-
        dev->board_name = board->name;
 
        ret = comedi_alloc_subdevices(dev, 1);
@@ -195,8 +193,6 @@ static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it)
        s->insn_bits = dnp_dio_insn_bits;
        s->insn_config = dnp_dio_insn_config;
 
-       printk("attached\n");
-
        /* We use the I/O ports 0x22,0x23 and 0xa3-0xa9, which are always
         * allocated for the primary 8259, so we don't need to allocate them
         * ourselves. */
@@ -209,6 +205,7 @@ static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it)
        outb(PCMR, CSCIR);
        outb((inb(CSCDR) & 0xAA), CSCDR);
 
+       dev_info(dev->class_dev, "%s: attached\n", dev->board_name);
        return 1;
 }
 
index 848c7ec06976dfdebb68fdea580e6fc1333ede33..11ee83681da7744fc7efdf2cd62063ed0c514311 100644 (file)
@@ -102,6 +102,7 @@ sampling rate. If you sample two channels you get 4kHz and so on.
 #define BULK_TIMEOUT 1000
 
 /* constants for "firmware" upload and download */
+#define FIRMWARE "usbdux_firmware.bin"
 #define USBDUXSUB_FIRMWARE 0xA0
 #define VENDOR_DIR_IN  0xC0
 #define VENDOR_DIR_OUT 0x40
@@ -2791,7 +2792,7 @@ static int usbdux_usb_probe(struct usb_interface *uinterf,
 
        ret = request_firmware_nowait(THIS_MODULE,
                                      FW_ACTION_HOTPLUG,
-                                     "usbdux_firmware.bin",
+                                     FIRMWARE,
                                      &udev->dev,
                                      GFP_KERNEL,
                                      usbduxsub + index,
@@ -2850,3 +2851,4 @@ module_comedi_usb_driver(usbdux_driver, usbdux_usb_driver);
 MODULE_AUTHOR("Bernd Porr, BerndPorr@f2s.com");
 MODULE_DESCRIPTION("Stirling/ITL USB-DUX -- Bernd.Porr@f2s.com");
 MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(FIRMWARE);
index d9911588c10a9f2ecad8cd528a795270071e54f1..8eb41257c6ceca4dd9be11e997f95853dafdcdf2 100644 (file)
@@ -57,6 +57,7 @@
 /*
  * constants for "firmware" upload and download
  */
+#define FIRMWARE               "usbduxfast_firmware.bin"
 #define USBDUXFASTSUB_FIRMWARE 0xA0
 #define VENDOR_DIR_IN          0xC0
 #define VENDOR_DIR_OUT         0x40
@@ -1706,7 +1707,7 @@ static int usbduxfast_usb_probe(struct usb_interface *uinterf,
 
        ret = request_firmware_nowait(THIS_MODULE,
                                      FW_ACTION_HOTPLUG,
-                                     "usbduxfast_firmware.bin",
+                                     FIRMWARE,
                                      &udev->dev,
                                      GFP_KERNEL,
                                      usbduxfastsub + index,
@@ -1774,3 +1775,4 @@ module_comedi_usb_driver(usbduxfast_driver, usbduxfast_usb_driver);
 MODULE_AUTHOR("Bernd Porr, BerndPorr@f2s.com");
 MODULE_DESCRIPTION("USB-DUXfast, BerndPorr@f2s.com");
 MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(FIRMWARE);
index 543e604791e2719c16378a05ef8ad31a9ce7208b..f54ab8c2fcfd3604935fac8dd76f18b0f19bd034 100644 (file)
@@ -63,6 +63,7 @@ Status: testing
 #define BULK_TIMEOUT 1000
 
 /* constants for "firmware" upload and download */
+#define FIRMWARE "usbduxsigma_firmware.bin"
 #define USBDUXSUB_FIRMWARE 0xA0
 #define VENDOR_DIR_IN  0xC0
 #define VENDOR_DIR_OUT 0x40
@@ -2780,7 +2781,7 @@ static int usbduxsigma_usb_probe(struct usb_interface *uinterf,
 
        ret = request_firmware_nowait(THIS_MODULE,
                                      FW_ACTION_HOTPLUG,
-                                     "usbduxsigma_firmware.bin",
+                                     FIRMWARE,
                                      &udev->dev,
                                      GFP_KERNEL,
                                      usbduxsub + index,
@@ -2845,3 +2846,4 @@ module_comedi_usb_driver(usbduxsigma_driver, usbduxsigma_usb_driver);
 MODULE_AUTHOR("Bernd Porr, BerndPorr@f2s.com");
 MODULE_DESCRIPTION("Stirling/ITL USB-DUX SIGMA -- Bernd.Porr@f2s.com");
 MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(FIRMWARE);
index 41f95237789d28d64558a104d93283491ee72dde..5a6b6df0751392b98ae8c213b7a5bf9e76b20f9b 100644 (file)
@@ -131,6 +131,7 @@ static int aref_invalid(struct comedi_subdevice *s, unsigned int chanspec)
 int comedi_check_chanlist(struct comedi_subdevice *s, int n,
                          unsigned int *chanlist)
 {
+       struct comedi_device *dev = s->device;
        int i;
        int chan;
 
@@ -139,10 +140,10 @@ int comedi_check_chanlist(struct comedi_subdevice *s, int n,
                        if (CR_CHAN(chanlist[i]) >= s->n_chan ||
                            CR_RANGE(chanlist[i]) >= s->range_table->length
                            || aref_invalid(s, chanlist[i])) {
-                               printk(KERN_ERR "bad chanlist[%d]=0x%08x "
-                                      "in_chan=%d range length=%d\n", i,
-                                      chanlist[i], s->n_chan,
-                                      s->range_table->length);
+                               dev_warn(dev->class_dev,
+                                        "bad chanlist[%d]=0x%08x in_chan=%d range length=%d\n",
+                                        i, chanlist[i], s->n_chan,
+                                        s->range_table->length);
                                return -EINVAL;
                        }
        } else if (s->range_table_list) {
@@ -152,13 +153,14 @@ int comedi_check_chanlist(struct comedi_subdevice *s, int n,
                            CR_RANGE(chanlist[i]) >=
                            s->range_table_list[chan]->length
                            || aref_invalid(s, chanlist[i])) {
-                               printk(KERN_ERR "bad chanlist[%d]=0x%08x\n",
-                                      i, chanlist[i]);
+                               dev_warn(dev->class_dev,
+                                        "bad chanlist[%d]=0x%08x\n",
+                                        i, chanlist[i]);
                                return -EINVAL;
                        }
                }
        } else {
-               printk(KERN_ERR "comedi: (bug) no range type list!\n");
+               dev_err(dev->class_dev, "(bug) no range type list!\n");
                return -EINVAL;
        }
        return 0;
index d9e3d618f7f4de52bfb3928cf4d42b12aa68da73..5909d8d1b4d54b375b3018c15934e007646d2059 100644 (file)
@@ -373,13 +373,15 @@ static int __devinit chd_dec_init_chdev(struct crystalhd_adp *adp)
        /* register crystalhd class */
        crystalhd_class = class_create(THIS_MODULE, "crystalhd");
        if (IS_ERR(crystalhd_class)) {
+               rc = PTR_ERR(crystalhd_class);
                BCMLOG_ERR("failed to create class\n");
-               goto fail;
+               goto class_create_fail;
        }
 
        dev = device_create(crystalhd_class, NULL, MKDEV(adp->chd_dec_major, 0),
                            NULL, "crystalhd");
        if (IS_ERR(dev)) {
+               rc = PTR_ERR(crystalhd_class);
                BCMLOG_ERR("failed to create device\n");
                goto device_create_fail;
        }
@@ -410,6 +412,8 @@ elem_pool_fail:
        device_destroy(crystalhd_class, MKDEV(adp->chd_dec_major, 0));
 device_create_fail:
        class_destroy(crystalhd_class);
+class_create_fail:
+       unregister_chrdev(adp->chd_dec_major, CRYSTALHD_API_NAME);
 fail:
        return rc;
 }
index cee8d48d2af91337006f8b852deddf8614d1adaa..ad2a1096e920c4008a7314f10691aadf4fddfcd9 100644 (file)
@@ -1,6 +1,6 @@
 config CSR_WIFI
        tristate "CSR wireless driver"
-       depends on MMC && CFG80211_WEXT
+       depends on MMC && CFG80211_WEXT && INET
        select WIRELESS_EXT
        select WEXT_PRIV
        help
index afda44b0a9255b605a0cbc1a6e8da3a70beb416b..ab626edc5ba43d7fb4084ed8023d4a582cf589f5 100644 (file)
@@ -25,7 +25,6 @@ csr_wifi-y := bh.o                            \
                unifi_event.o                   \
                unifi_pdu_processing.o          \
                unifi_sme.o                     \
-               csr_formatted_io.o              \
                csr_wifi_hip_card_sdio.o        \
                csr_wifi_hip_card_sdio_intr.o   \
                csr_wifi_hip_card_sdio_mem.o    \
index b089c28d56109313aff4fdc0f75fc827f4b61ca1..addee05a45160e252b9d6a462e1fb558a0d6b0a1 100644 (file)
  *      0 on success or else a Linux error code.
  * ---------------------------------------------------------------------------
  */
-int
-uf_start_thread(unifi_priv_t *priv, struct uf_thread *thread, int (*func)(void *))
+int uf_start_thread(unifi_priv_t *priv,
+                   struct uf_thread *thread, int (*func)(void *))
 {
-    if (thread->thread_task != NULL) {
-        unifi_error(priv, "%s thread already started\n", thread->name);
-        return 0;
-    }
-
-    /* Start the kernel thread that handles all h/w accesses. */
-    thread->thread_task = kthread_run(func, priv, "%s", thread->name);
-    if (IS_ERR(thread->thread_task)) {
-        return PTR_ERR(thread->thread_task);
-    }
-
-    /* Module parameter overides the thread priority */
-    if (bh_priority != -1) {
-        if (bh_priority >= 0 && bh_priority <= MAX_RT_PRIO) {
-            struct sched_param param;
-            priv->bh_thread.prio = bh_priority;
-            unifi_trace(priv, UDBG1, "%s thread (RT) priority = %d\n",
-                        thread->name, bh_priority);
-            param.sched_priority = bh_priority;
-            sched_setscheduler(thread->thread_task, SCHED_FIFO, &param);
-        } else if (bh_priority > MAX_RT_PRIO && bh_priority <= MAX_PRIO) {
-            priv->bh_thread.prio = bh_priority;
-            unifi_trace(priv, UDBG1, "%s thread priority = %d\n",
-                        thread->name, PRIO_TO_NICE(bh_priority));
-            set_user_nice(thread->thread_task, PRIO_TO_NICE(bh_priority));
-        } else {
-            priv->bh_thread.prio = DEFAULT_PRIO;
-            unifi_warning(priv, "%s thread unsupported (%d) priority\n",
-                          thread->name, bh_priority);
-        }
-    } else {
-        priv->bh_thread.prio = DEFAULT_PRIO;
-    }
-    unifi_trace(priv, UDBG2, "Started %s thread\n", thread->name);
-
-    return 0;
+       if (thread->thread_task != NULL) {
+               unifi_error(priv, "%s thread already started\n", thread->name);
+               return 0;
+       }
+
+       /* Start the kernel thread that handles all h/w accesses. */
+       thread->thread_task = kthread_run(func, priv, "%s", thread->name);
+       if (IS_ERR(thread->thread_task))
+               return PTR_ERR(thread->thread_task);
+
+       /* Module parameter overides the thread priority */
+       if (bh_priority != -1) {
+               if (bh_priority >= 0 && bh_priority <= MAX_RT_PRIO) {
+                       struct sched_param param;
+                       priv->bh_thread.prio = bh_priority;
+                       unifi_trace(priv, UDBG1,
+                               "%s thread (RT) priority = %d\n",
+                               thread->name, bh_priority);
+                       param.sched_priority = bh_priority;
+                       sched_setscheduler(thread->thread_task,
+                                          SCHED_FIFO, &param);
+               } else if (bh_priority > MAX_RT_PRIO &&
+                          bh_priority <= MAX_PRIO) {
+                       priv->bh_thread.prio = bh_priority;
+                       unifi_trace(priv, UDBG1, "%s thread priority = %d\n",
+                                       thread->name,
+                                       PRIO_TO_NICE(bh_priority));
+                       set_user_nice(thread->thread_task,
+                                     PRIO_TO_NICE(bh_priority));
+               } else {
+                       priv->bh_thread.prio = DEFAULT_PRIO;
+                       unifi_warning(priv,
+                                     "%s thread unsupported (%d) priority\n",
+                                     thread->name, bh_priority);
+               }
+       } else
+               priv->bh_thread.prio = DEFAULT_PRIO;
+       unifi_trace(priv, UDBG2, "Started %s thread\n", thread->name);
+
+       return 0;
 } /* uf_start_thread() */
 
 
@@ -88,18 +92,18 @@ uf_start_thread(unifi_priv_t *priv, struct uf_thread *thread, int (*func)(void *
  *
  * ---------------------------------------------------------------------------
  */
-    void
-uf_stop_thread(unifi_priv_t *priv, struct uf_thread *thread)
+void uf_stop_thread(unifi_priv_t *priv, struct uf_thread *thread)
 {
-    if (!thread->thread_task) {
-        unifi_notice(priv, "%s thread is already stopped\n", thread->name);
-        return;
-    }
+       if (!thread->thread_task) {
+               unifi_notice(priv, "%s thread is already stopped\n",
+                                                       thread->name);
+               return;
+       }
 
-    unifi_trace(priv, UDBG2, "Stopping %s thread\n", thread->name);
+       unifi_trace(priv, UDBG2, "Stopping %s thread\n", thread->name);
 
-    kthread_stop(thread->thread_task);
-    thread->thread_task = NULL;
+       kthread_stop(thread->thread_task);
+       thread->thread_task = NULL;
 
 } /* uf_stop_thread() */
 
@@ -118,23 +122,24 @@ uf_stop_thread(unifi_priv_t *priv, struct uf_thread *thread)
  *
  * ---------------------------------------------------------------------------
  */
-    void
+void
 uf_wait_for_thread_to_stop(unifi_priv_t *priv, struct uf_thread *thread)
 {
-    /*
-     * kthread_stop() cannot handle the thread exiting while
-     * kthread_should_stop() is false, so sleep until kthread_stop()
-     * wakes us up.
-     */
-    unifi_trace(priv, UDBG2, "%s waiting for the stop signal.\n", thread->name);
-    set_current_state(TASK_INTERRUPTIBLE);
-    if (!kthread_should_stop()) {
-        unifi_trace(priv, UDBG2, "%s schedule....\n", thread->name);
-        schedule();
-    }
-
-    thread->thread_task = NULL;
-    unifi_trace(priv, UDBG2, "%s exiting....\n", thread->name);
+       /*
+        * kthread_stop() cannot handle the thread exiting while
+        * kthread_should_stop() is false, so sleep until kthread_stop()
+        * wakes us up
+        */
+       unifi_trace(priv, UDBG2, "%s waiting for the stop signal.\n",
+                                                       thread->name);
+       set_current_state(TASK_INTERRUPTIBLE);
+       if (!kthread_should_stop()) {
+               unifi_trace(priv, UDBG2, "%s schedule....\n", thread->name);
+               schedule();
+       }
+
+       thread->thread_task = NULL;
+       unifi_trace(priv, UDBG2, "%s exiting....\n", thread->name);
 } /* uf_wait_for_thread_to_stop() */
 
 
@@ -155,39 +160,41 @@ uf_wait_for_thread_to_stop(unifi_priv_t *priv, struct uf_thread *thread)
  *      None.
  * ---------------------------------------------------------------------------
  */
-    static void
+static void
 handle_bh_error(unifi_priv_t *priv)
 {
-    u8 conf_param = CONFIG_IND_ERROR;
-    u8 interfaceTag = 0; /* used as a loop counter */
+       netInterface_priv_t *interfacePriv;
+       u8 conf_param = CONFIG_IND_ERROR;
+       u8 interfaceTag;
 
 
-    /* Block unifi_run_bh() until the error has been handled. */
-    priv->bh_thread.block_thread = 1;
+       /* Block unifi_run_bh() until the error has been handled. */
+       priv->bh_thread.block_thread = 1;
 
-    /* Consider UniFi to be uninitialised */
-    priv->init_progress = UNIFI_INIT_NONE;
+       /* Consider UniFi to be uninitialised */
+       priv->init_progress = UNIFI_INIT_NONE;
 
-    /* Stop the network traffic */
-    for( interfaceTag =0; interfaceTag <CSR_WIFI_NUM_INTERFACES;interfaceTag ++) {
-        netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
-        if (interfacePriv->netdev_registered == 1) {
-            netif_carrier_off(priv->netdev[interfaceTag]);
-        }
-    }
+       /* Stop the network traffic */
+       for (interfaceTag = 0;
+            interfaceTag < CSR_WIFI_NUM_INTERFACES; interfaceTag++) {
+               interfacePriv = priv->interfacePriv[interfaceTag];
+               if (interfacePriv->netdev_registered)
+                       netif_carrier_off(priv->netdev[interfaceTag]);
+       }
 
 #ifdef CSR_NATIVE_LINUX
-    /* Force any client waiting on an mlme_wait_for_reply() to abort. */
-    uf_abort_mlme(priv);
+       /* Force any client waiting on an mlme_wait_for_reply() to abort. */
+       uf_abort_mlme(priv);
 
-    /* Cancel any pending workqueue tasks */
-    flush_workqueue(priv->unifi_workqueue);
+       /* Cancel any pending workqueue tasks */
+       flush_workqueue(priv->unifi_workqueue);
 
 #endif /* CSR_NATIVE_LINUX */
 
-    unifi_error(priv, "handle_bh_error: fatal error is reported to the SME.\n");
-    /* Notify the clients (SME or unifi_manager) for the error. */
-    ul_log_config_ind(priv, &conf_param, sizeof(u8));
+       unifi_error(priv,
+               "handle_bh_error: fatal error is reported to the SME.\n");
+       /* Notify the clients (SME or unifi_manager) for the error. */
+       ul_log_config_ind(priv, &conf_param, sizeof(u8));
 
 } /* handle_bh_error() */
 
diff --git a/drivers/staging/csr/csr_formatted_io.c b/drivers/staging/csr/csr_formatted_io.c
deleted file mode 100644 (file)
index 7213cc8..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*****************************************************************************
-
-            (c) Cambridge Silicon Radio Limited 2010
-            All rights reserved and confidential information of CSR
-
-            Refer to LICENSE.txt included with this source for details
-            on the license terms.
-
-*****************************************************************************/
-#include <linux/kernel.h>
-#include "csr_formatted_io.h"
-
-s32 CsrSnprintf(char *dest, size_t n, const char *fmt, ...)
-{
-    s32 r;
-    va_list args;
-    va_start(args, fmt);
-    r = vsnprintf(dest, n, fmt, args);
-    va_end(args);
-
-    if (dest && (n > 0))
-    {
-        dest[n - 1] = '\0';
-    }
-
-    return r;
-}
diff --git a/drivers/staging/csr/csr_formatted_io.h b/drivers/staging/csr/csr_formatted_io.h
deleted file mode 100644 (file)
index 2e238cb..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef CSR_FORMATTED_IO_H__
-#define CSR_FORMATTED_IO_H__
-/*****************************************************************************
-
-            (c) Cambridge Silicon Radio Limited 2010
-            All rights reserved and confidential information of CSR
-
-            Refer to LICENSE.txt included with this source for details
-            on the license terms.
-
-*****************************************************************************/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <linux/types.h>
-
-s32 CsrSnprintf(char *dest, size_t n, const char *fmt, ...);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
index 353a829bb74c9f9b05c82a1f9733d435f4e7f7e6..095f7fa3ae2c99b0883b164a592217426e796dfd 100644 (file)
@@ -9,7 +9,6 @@
 *****************************************************************************/
 
 #include <linux/kernel.h>
-#include <linux/version.h>
 #include <linux/module.h>
 
 #include "csr_panic.h"
index 83586ca34e8c55bc59c1830977153ed7b77e9923..2043f253ae4c9272126eab064ae69e2eab25d4d5 100644 (file)
 
 CsrTime CsrTimeGet(CsrTime *high)
 {
-    struct timespec ts;
-    u64 time;
-    CsrTime low;
+       struct timespec ts;
+       u64 time;
+       CsrTime low;
 
-    ts = current_kernel_time();
-    time = (u64) ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
+       ts = current_kernel_time();
+       time = (u64) ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
 
-    if (high != NULL)
-    {
-        *high = (CsrTime) ((time >> 32) & 0xFFFFFFFF);
-    }
+       if (high != NULL)
+               *high = (CsrTime) ((time >> 32) & 0xFFFFFFFF);
 
-    low = (CsrTime) (time & 0xFFFFFFFF);
+       low = (CsrTime) (time & 0xFFFFFFFF);
 
-    return low;
+       return low;
 }
 EXPORT_SYMBOL_GPL(CsrTimeGet);
index 44ab00c53fec94344dee693ba3cf282dfdf55dc4..cf148a0fec6a9bac96d6de75f3610e11e4f6d93b 100644 (file)
@@ -1612,13 +1612,13 @@ static CsrResult card_allocate_memory_resources(card_t *card)
     /* Reset any state carried forward from a previous life */
     card->fh_command_queue.q_rd_ptr = 0;
     card->fh_command_queue.q_wr_ptr = 0;
-    (void)CsrSnprintf(card->fh_command_queue.name, UNIFI_QUEUE_NAME_MAX_LENGTH,
+    (void)scnprintf(card->fh_command_queue.name, UNIFI_QUEUE_NAME_MAX_LENGTH,
                       "fh_cmd_q");
     for (i = 0; i < UNIFI_NO_OF_TX_QS; i++)
     {
         card->fh_traffic_queue[i].q_rd_ptr = 0;
         card->fh_traffic_queue[i].q_wr_ptr = 0;
-        (void)CsrSnprintf(card->fh_traffic_queue[i].name,
+        (void)scnprintf(card->fh_traffic_queue[i].name,
                           UNIFI_QUEUE_NAME_MAX_LENGTH, "fh_data_q%d", i);
     }
 #ifndef CSR_WIFI_HIP_TA_DISABLE
@@ -1826,13 +1826,13 @@ static void card_init_soft_queues(card_t *card)
     /* Reset any state carried forward from a previous life */
     card->fh_command_queue.q_rd_ptr = 0;
     card->fh_command_queue.q_wr_ptr = 0;
-    (void)CsrSnprintf(card->fh_command_queue.name, UNIFI_QUEUE_NAME_MAX_LENGTH,
+    (void)scnprintf(card->fh_command_queue.name, UNIFI_QUEUE_NAME_MAX_LENGTH,
                       "fh_cmd_q");
     for (i = 0; i < UNIFI_NO_OF_TX_QS; i++)
     {
         card->fh_traffic_queue[i].q_rd_ptr = 0;
         card->fh_traffic_queue[i].q_wr_ptr = 0;
-        (void)CsrSnprintf(card->fh_traffic_queue[i].name,
+        (void)scnprintf(card->fh_traffic_queue[i].name,
                           UNIFI_QUEUE_NAME_MAX_LENGTH, "fh_data_q%d", i);
     }
 #ifndef CSR_WIFI_HIP_TA_DISABLE
index 684d30459d756f4edfcb6e253b489d8849032098..86aa23cefe306f2787e931f4f2ebf348b2d0e00b 100644 (file)
@@ -172,13 +172,8 @@ static CsrResult send_signal(card_t *card, const u8 *sigptr, u32 siglen,
     {
         const u8 *sig = sigptr;
 
-        unifi_error(card->ospriv, "Signal(%d): %02x %02x %02x %02x %02x %02x %02x %02x"
-                    " %02x %02x %02x %02x %02x %02x %02x %02x\n",
-                    siglen,
-                    sig[0], sig[1], sig[2], sig[3],
-                    sig[4], sig[5], sig[6], sig[7],
-                    sig[8], sig[9], sig[10], sig[11],
-                    sig[12], sig[13], sig[14], sig[15]);
+               unifi_error(card->ospriv, "Signal(%d): %*ph\n", siglen,
+                                         16, sig);
         unifi_error(card->ospriv, "Bulkdata pointer %p(%d), %p(%d)\n",
                     bulkdata != NULL?bulkdata->d[0].os_data_ptr : NULL,
                     bulkdata != NULL?bulkdata->d[0].data_length : 0,
index 07cfd36c49715863b6a0a818e0273e6ac0bdbd57..31a27cc60995f07b5eeccd16d0a1503db3029a24 100644 (file)
@@ -64,104 +64,104 @@ s32 unifi_print_status(card_t *card, char *str, s32 *remain)
     }
 
     i = n = 0;
-    written = CsrSnprintf(p, remaining, "Chip ID %u\n",
+    written = scnprintf(p, remaining, "Chip ID %u\n",
                           (u16)card->chip_id);
     UNIFI_SNPRINTF_RET(p, remaining, written);
-    written = CsrSnprintf(p, remaining, "Chip Version %04X\n",
+    written = scnprintf(p, remaining, "Chip Version %04X\n",
                           card->chip_version);
     UNIFI_SNPRINTF_RET(p, remaining, written);
-    written = CsrSnprintf(p, remaining, "HIP v%u.%u\n",
+    written = scnprintf(p, remaining, "HIP v%u.%u\n",
                           (card->config_data.version >> 8) & 0xFF,
                           card->config_data.version & 0xFF);
     UNIFI_SNPRINTF_RET(p, remaining, written);
-    written = CsrSnprintf(p, remaining, "Build %lu: %s\n",
+    written = scnprintf(p, remaining, "Build %u: %s\n",
                           card->build_id, card->build_id_string);
     UNIFI_SNPRINTF_RET(p, remaining, written);
 
     cfg = &card->config_data;
 
-    written = CsrSnprintf(p, remaining, "sdio ctrl offset          %u\n",
+    written = scnprintf(p, remaining, "sdio ctrl offset          %u\n",
                           cfg->sdio_ctrl_offset);
     UNIFI_SNPRINTF_RET(p, remaining, written);
-    written = CsrSnprintf(p, remaining, "fromhost sigbuf handle    %u\n",
+    written = scnprintf(p, remaining, "fromhost sigbuf handle    %u\n",
                           cfg->fromhost_sigbuf_handle);
     UNIFI_SNPRINTF_RET(p, remaining, written);
-    written = CsrSnprintf(p, remaining, "tohost_sigbuf_handle      %u\n",
+    written = scnprintf(p, remaining, "tohost_sigbuf_handle      %u\n",
                           cfg->tohost_sigbuf_handle);
     UNIFI_SNPRINTF_RET(p, remaining, written);
-    written = CsrSnprintf(p, remaining, "num_fromhost_sig_frags    %u\n",
+    written = scnprintf(p, remaining, "num_fromhost_sig_frags    %u\n",
                           cfg->num_fromhost_sig_frags);
     UNIFI_SNPRINTF_RET(p, remaining, written);
-    written = CsrSnprintf(p, remaining, "num_tohost_sig_frags      %u\n",
+    written = scnprintf(p, remaining, "num_tohost_sig_frags      %u\n",
                           cfg->num_tohost_sig_frags);
     UNIFI_SNPRINTF_RET(p, remaining, written);
-    written = CsrSnprintf(p, remaining, "num_fromhost_data_slots   %u\n",
+    written = scnprintf(p, remaining, "num_fromhost_data_slots   %u\n",
                           cfg->num_fromhost_data_slots);
     UNIFI_SNPRINTF_RET(p, remaining, written);
-    written = CsrSnprintf(p, remaining, "num_tohost_data_slots     %u\n",
+    written = scnprintf(p, remaining, "num_tohost_data_slots     %u\n",
                           cfg->num_tohost_data_slots);
     UNIFI_SNPRINTF_RET(p, remaining, written);
-    written = CsrSnprintf(p, remaining, "data_slot_size            %u\n",
+    written = scnprintf(p, remaining, "data_slot_size            %u\n",
                           cfg->data_slot_size);
     UNIFI_SNPRINTF_RET(p, remaining, written);
 
     /* Added by protocol version 0x0001 */
-    written = CsrSnprintf(p, remaining, "overlay_size              %u\n",
+    written = scnprintf(p, remaining, "overlay_size              %u\n",
                           (u16)cfg->overlay_size);
     UNIFI_SNPRINTF_RET(p, remaining, written);
 
     /* Added by protocol version 0x0300 */
-    written = CsrSnprintf(p, remaining, "data_slot_round           %u\n",
+    written = scnprintf(p, remaining, "data_slot_round           %u\n",
                           cfg->data_slot_round);
     UNIFI_SNPRINTF_RET(p, remaining, written);
-    written = CsrSnprintf(p, remaining, "sig_frag_size             %u\n",
+    written = scnprintf(p, remaining, "sig_frag_size             %u\n",
                           cfg->sig_frag_size);
     UNIFI_SNPRINTF_RET(p, remaining, written);
 
     /* Added by protocol version 0x0300 */
-    written = CsrSnprintf(p, remaining, "tohost_sig_pad            %u\n",
+    written = scnprintf(p, remaining, "tohost_sig_pad            %u\n",
                           cfg->tohost_signal_padding);
     UNIFI_SNPRINTF_RET(p, remaining, written);
 
-    written = CsrSnprintf(p, remaining, "\nInternal state:\n");
+    written = scnprintf(p, remaining, "\nInternal state:\n");
     UNIFI_SNPRINTF_RET(p, remaining, written);
 
-    written = CsrSnprintf(p, remaining, "Last PHY PANIC: %04x:%04x\n",
+    written = scnprintf(p, remaining, "Last PHY PANIC: %04x:%04x\n",
                           card->last_phy_panic_code, card->last_phy_panic_arg);
     UNIFI_SNPRINTF_RET(p, remaining, written);
-    written = CsrSnprintf(p, remaining, "Last MAC PANIC: %04x:%04x\n",
+    written = scnprintf(p, remaining, "Last MAC PANIC: %04x:%04x\n",
                           card->last_mac_panic_code, card->last_mac_panic_arg);
     UNIFI_SNPRINTF_RET(p, remaining, written);
 
-    written = CsrSnprintf(p, remaining, "fhsr: %u\n",
+    written = scnprintf(p, remaining, "fhsr: %u\n",
                           (u16)card->from_host_signals_r);
     UNIFI_SNPRINTF_RET(p, remaining, written);
-    written = CsrSnprintf(p, remaining, "fhsw: %u\n",
+    written = scnprintf(p, remaining, "fhsw: %u\n",
                           (u16)card->from_host_signals_w);
     UNIFI_SNPRINTF_RET(p, remaining, written);
-    written = CsrSnprintf(p, remaining, "thsr: %u\n",
+    written = scnprintf(p, remaining, "thsr: %u\n",
                           (u16)card->to_host_signals_r);
     UNIFI_SNPRINTF_RET(p, remaining, written);
-    written = CsrSnprintf(p, remaining, "thsw: %u\n",
+    written = scnprintf(p, remaining, "thsw: %u\n",
                           (u16)card->to_host_signals_w);
     UNIFI_SNPRINTF_RET(p, remaining, written);
-    written = CsrSnprintf(p, remaining,
-                          "fh buffer contains: %u signals, %u bytes\n",
+    written = scnprintf(p, remaining,
+                          "fh buffer contains: %d signals, %ld bytes\n",
                           card->fh_buffer.count,
                           card->fh_buffer.ptr - card->fh_buffer.buf);
     UNIFI_SNPRINTF_RET(p, remaining, written);
 
-    written = CsrSnprintf(p, remaining, "paused: ");
+    written = scnprintf(p, remaining, "paused: ");
     UNIFI_SNPRINTF_RET(p, remaining, written);
     for (i = 0; i < sizeof(card->tx_q_paused_flag) / sizeof(card->tx_q_paused_flag[0]); i++)
     {
-        written = CsrSnprintf(p, remaining, card->tx_q_paused_flag[i]?"1" : "0");
+        written = scnprintf(p, remaining, card->tx_q_paused_flag[i]?"1" : "0");
         UNIFI_SNPRINTF_RET(p, remaining, written);
     }
-    written = CsrSnprintf(p, remaining, "\n");
+    written = scnprintf(p, remaining, "\n");
     UNIFI_SNPRINTF_RET(p, remaining, written);
 
-    written = CsrSnprintf(p, remaining,
+    written = scnprintf(p, remaining,
                           "fh command q: %u waiting, %u free of %u:\n",
                           CSR_WIFI_HIP_Q_SLOTS_USED(&card->fh_command_queue),
                           CSR_WIFI_HIP_Q_SLOTS_FREE(&card->fh_command_queue),
@@ -169,7 +169,7 @@ s32 unifi_print_status(card_t *card, char *str, s32 *remain)
     UNIFI_SNPRINTF_RET(p, remaining, written);
     for (i = 0; i < UNIFI_NO_OF_TX_QS; i++)
     {
-        written = CsrSnprintf(p, remaining,
+        written = scnprintf(p, remaining,
                               "fh traffic q[%u]: %u waiting, %u free of %u:\n",
                               i,
                               CSR_WIFI_HIP_Q_SLOTS_USED(&card->fh_traffic_queue[i]),
@@ -178,58 +178,58 @@ s32 unifi_print_status(card_t *card, char *str, s32 *remain)
         UNIFI_SNPRINTF_RET(p, remaining, written);
     }
 
-    written = CsrSnprintf(p, remaining, "fh data slots free: %u\n",
+    written = scnprintf(p, remaining, "fh data slots free: %u\n",
                           card->from_host_data?CardGetFreeFromHostDataSlots(card) : 0);
     UNIFI_SNPRINTF_RET(p, remaining, written);
 
 
-    written = CsrSnprintf(p, remaining, "From host data slots:");
+    written = scnprintf(p, remaining, "From host data slots:");
     UNIFI_SNPRINTF_RET(p, remaining, written);
     n = card->config_data.num_fromhost_data_slots;
     for (i = 0; i < n && card->from_host_data; i++)
     {
-        written = CsrSnprintf(p, remaining, " %u",
+        written = scnprintf(p, remaining, " %u",
                               (u16)card->from_host_data[i].bd.data_length);
         UNIFI_SNPRINTF_RET(p, remaining, written);
     }
-    written = CsrSnprintf(p, remaining, "\n");
+    written = scnprintf(p, remaining, "\n");
     UNIFI_SNPRINTF_RET(p, remaining, written);
 
-    written = CsrSnprintf(p, remaining, "To host data slots:");
+    written = scnprintf(p, remaining, "To host data slots:");
     UNIFI_SNPRINTF_RET(p, remaining, written);
     n = card->config_data.num_tohost_data_slots;
     for (i = 0; i < n && card->to_host_data; i++)
     {
-        written = CsrSnprintf(p, remaining, " %u",
+        written = scnprintf(p, remaining, " %u",
                               (u16)card->to_host_data[i].data_length);
         UNIFI_SNPRINTF_RET(p, remaining, written);
     }
 
-    written = CsrSnprintf(p, remaining, "\n");
+    written = scnprintf(p, remaining, "\n");
     UNIFI_SNPRINTF_RET(p, remaining, written);
 
 #ifdef CSR_UNSAFE_SDIO_ACCESS
-    written = CsrSnprintf(p, remaining, "Host State: %s\n", states[card->host_state]);
+    written = scnprintf(p, remaining, "Host State: %s\n", states[card->host_state]);
     UNIFI_SNPRINTF_RET(p, remaining, written);
 
     r = unifi_check_io_status(card, &iostate);
     if (iostate == 1)
     {
-        written = CsrSnprintf(p, remaining, "I/O Check: F1 disabled\n");
+        written = scnprintf(p, remaining, "I/O Check: F1 disabled\n");
         UNIFI_SNPRINTF_RET(p, remaining, written);
     }
     else
     {
         if (iostate == 1)
         {
-            written = CsrSnprintf(p, remaining, "I/O Check: pending interrupt\n");
+            written = scnprintf(p, remaining, "I/O Check: pending interrupt\n");
             UNIFI_SNPRINTF_RET(p, remaining, written);
         }
 
-        written = CsrSnprintf(p, remaining, "BH reason interrupt = %d\n",
+        written = scnprintf(p, remaining, "BH reason interrupt = %d\n",
                               card->bh_reason_unifi);
         UNIFI_SNPRINTF_RET(p, remaining, written);
-        written = CsrSnprintf(p, remaining, "BH reason host      = %d\n",
+        written = scnprintf(p, remaining, "BH reason host      = %d\n",
                               card->bh_reason_host);
         UNIFI_SNPRINTF_RET(p, remaining, written);
 
@@ -238,26 +238,26 @@ s32 unifi_print_status(card_t *card, char *str, s32 *remain)
             r = unifi_read_8_or_16(card, card->sdio_ctrl_addr + 2, &b);
             if ((r == CSR_RESULT_SUCCESS) && (!(b & 0x80)))
             {
-                written = CsrSnprintf(p, remaining, "fhsr: %u (driver thinks is %u)\n",
+                written = scnprintf(p, remaining, "fhsr: %u (driver thinks is %u)\n",
                                       b, card->from_host_signals_r);
                 UNIFI_SNPRINTF_RET(p, remaining, written);
                 break;
             }
         }
         iostate = unifi_read_shared_count(card, card->sdio_ctrl_addr + 4);
-        written = CsrSnprintf(p, remaining, "thsw: %u (driver thinks is %u)\n",
+        written = scnprintf(p, remaining, "thsw: %u (driver thinks is %u)\n",
                               iostate, card->to_host_signals_w);
         UNIFI_SNPRINTF_RET(p, remaining, written);
     }
 #endif
 
-    written = CsrSnprintf(p, remaining, "\nStats:\n");
+    written = scnprintf(p, remaining, "\nStats:\n");
     UNIFI_SNPRINTF_RET(p, remaining, written);
-    written = CsrSnprintf(p, remaining, "Total SDIO bytes: R=%lu W=%lu\n",
+    written = scnprintf(p, remaining, "Total SDIO bytes: R=%u W=%u\n",
                           card->sdio_bytes_read, card->sdio_bytes_written);
 
     UNIFI_SNPRINTF_RET(p, remaining, written);
-    written = CsrSnprintf(p, remaining, "Interrupts generated on card: %lu\n",
+    written = scnprintf(p, remaining, "Interrupts generated on card: %u\n",
                           card->unifi_interrupt_seq);
     UNIFI_SNPRINTF_RET(p, remaining, written);
 
index dc3c60b49702de9bcd239c1f7795e4bbc8212193..2923e2ef12f2a107175b9d5c92bc688a5060eddf 100644 (file)
@@ -98,7 +98,6 @@ extern "C" {
 #include "csr_framework_ext.h"  /* from the synergy porting folder */
 #include "csr_sdio.h"           /* from the synergy porting folder */
 #include "csr_macro.h"          /* from the synergy porting folder */
-#include "csr_formatted_io.h"   /* from the synergy gsp folder */
 #include "csr_wifi_result.h"
 
 /* Utility MACROS. Note that UNIFI_MAC_ADDRESS_CMP returns TRUE on success */
index b2c27f4f03d4dba1e03d4ce8d38797a160c99b6b..9834d92b1c38708cd87421fb99f5812a07d131af 100644 (file)
@@ -15,8 +15,6 @@
  * ---------------------------------------------------------------------------
  */
 
-
-
 /*
  * Porting Notes:
  * Part of this file contains an example for how to glue the OS layer
@@ -37,6 +35,7 @@
 #include <linux/poll.h>
 #include <asm/uaccess.h>
 #include <linux/jiffies.h>
+#include <linux/version.h>
 
 #include "csr_wifi_hip_unifiversion.h"
 #include "unifi_priv.h"
index d14e11839618e92cead591160100aca3dc1e6b4d..dc6a04db265a4e6c99ad899477edaf0849d23697 100644 (file)
@@ -402,9 +402,7 @@ int uf_release_firmware_files(unifi_priv_t *priv)
 int uf_release_firmware(unifi_priv_t *priv, struct dlpriv *to_free)
 {
     if (to_free != NULL) {
-        if (to_free->fw_desc != NULL) {
-            release_firmware((const struct firmware *)to_free->fw_desc);
-        }
+        release_firmware((const struct firmware *)to_free->fw_desc);
         to_free->fw_desc = NULL;
         to_free->dl_data = NULL;
         to_free->dl_len = 0;
index e6503d9620a4310152cc8045389a58e5f18b9fca..4774dc8528162553f770a7f9d006537265d0c3b5 100644 (file)
@@ -31,6 +31,7 @@
  * ---------------------------------------------------------------------------
  */
 #include <linux/proc_fs.h>
+#include <linux/version.h>
 
 #include "csr_wifi_hip_unifi.h"
 #include "csr_wifi_hip_unifiversion.h"
@@ -38,7 +39,6 @@
 #include "unifiio.h"
 #include "unifi_priv.h"
 
-
 /*
  * Array of pointers to context structs for unifi devices that are present.
  * The index in the array corresponds to the wlan interface number
@@ -347,7 +347,7 @@ register_unifi_sdio(CsrSdioFunction *sdio_dev, int bus_id, struct device *dev)
     /*
      * We use the slot number as unifi device index.
      */
-    snprintf(priv->proc_entry_name, 64, "driver/unifi%d", priv->instance);
+    scnprintf(priv->proc_entry_name, 64, "driver/unifi%d", priv->instance);
     /*
      * The following complex casting is in place in order to eliminate 64-bit compilation warning
      * "cast to/from pointer from/to integer of different size"
@@ -904,54 +904,54 @@ uf_read_proc(char *page, char **start, off_t offset, int count,
 
     orig_p = p;
 
-    written = CsrSnprintf(p, remain, "UniFi SDIO Driver: %s %s %s\n",
+    written = scnprintf(p, remain, "UniFi SDIO Driver: %s %s %s\n",
             CSR_WIFI_VERSION, __DATE__, __TIME__);
     UNIFI_SNPRINTF_RET(p, remain, written);
 #ifdef CSR_SME_USERSPACE
-    written = CsrSnprintf(p, remain, "SME: CSR userspace ");
+    written = scnprintf(p, remain, "SME: CSR userspace ");
     UNIFI_SNPRINTF_RET(p, remain, written);
 #ifdef CSR_SUPPORT_WEXT
-    written = CsrSnprintf(p, remain, "with WEXT support\n");
+    written = scnprintf(p, remain, "with WEXT support\n");
 #else
-    written = CsrSnprintf(p, remain, "\n");
+    written = scnprintf(p, remain, "\n");
 #endif /* CSR_SUPPORT_WEXT */
     UNIFI_SNPRINTF_RET(p, remain, written);
 #endif /* CSR_SME_USERSPACE */
 #ifdef CSR_NATIVE_LINUX
-    written = CsrSnprintf(p, remain, "SME: native\n");
+    written = scnprintf(p, remain, "SME: native\n");
     UNIFI_SNPRINTF_RET(p, remain, written);
 #endif
 
 #ifdef CSR_SUPPORT_SME
-    written = CsrSnprintf(p, remain,
-            "Firmware (ROM) build:%lu, Patch:%lu\n",
+    written = scnprintf(p, remain,
+            "Firmware (ROM) build:%u, Patch:%u\n",
             priv->card_info.fw_build,
             priv->sme_versions.firmwarePatch);
     UNIFI_SNPRINTF_RET(p, remain, written);
 #endif
     p += unifi_print_status(priv->card, p, &remain);
 
-    written = CsrSnprintf(p, remain, "Last dbg str: %s\n",
+    written = scnprintf(p, remain, "Last dbg str: %s\n",
             priv->last_debug_string);
     UNIFI_SNPRINTF_RET(p, remain, written);
 
-    written = CsrSnprintf(p, remain, "Last dbg16:");
+    written = scnprintf(p, remain, "Last dbg16:");
     UNIFI_SNPRINTF_RET(p, remain, written);
     for (i = 0; i < 8; i++) {
-        written = CsrSnprintf(p, remain, " %04X",
+        written = scnprintf(p, remain, " %04X",
                 priv->last_debug_word16[i]);
         UNIFI_SNPRINTF_RET(p, remain, written);
     }
-    written = CsrSnprintf(p, remain, "\n");
+    written = scnprintf(p, remain, "\n");
     UNIFI_SNPRINTF_RET(p, remain, written);
-    written = CsrSnprintf(p, remain, "           ");
+    written = scnprintf(p, remain, "           ");
     UNIFI_SNPRINTF_RET(p, remain, written);
     for (; i < 16; i++) {
-        written = CsrSnprintf(p, remain, " %04X",
+        written = scnprintf(p, remain, " %04X",
                 priv->last_debug_word16[i]);
         UNIFI_SNPRINTF_RET(p, remain, written);
     }
-    written = CsrSnprintf(p, remain, "\n");
+    written = scnprintf(p, remain, "\n");
     UNIFI_SNPRINTF_RET(p, remain, written);
     *start = page;
 
index 628782ad641e4ee62534b542869a13db4d8af399..ca7559b97545dec85ece647ed0a23461a74b6296 100644 (file)
@@ -10,6 +10,7 @@
  * ---------------------------------------------------------------------------
  */
 
+#include <linux/version.h>
 #include "unifi_priv.h"
 
 #ifdef UNIFI_SNIFF_ARPHRD
@@ -23,8 +24,6 @@
 #define ETH_P_80211_RAW ETH_P_ALL
 #endif
 
-
-
 /*
  * ---------------------------------------------------------------------------
  *  uf_start_sniff
index 1e6e111a8e159c38d17e95e80d1834d9bc6143aa..0e3402044b4a906cb8e4b75a33c236c185a5d9f4 100644 (file)
@@ -15,7 +15,6 @@
  * ---------------------------------------------------------------------------
  */
 
-
 /*
  * Porting Notes:
  * This file implements the data plane of the UniFi linux driver.
@@ -48,7 +47,7 @@
 #include <linux/etherdevice.h>
 #include <linux/mutex.h>
 #include <linux/semaphore.h>
-
+#include <linux/version.h>
 #include <linux/vmalloc.h>
 #include "csr_wifi_hip_unifi.h"
 #include "csr_wifi_hip_conversions.h"
index d3fd57cdde0b8139e2201ea9c858513d76a06b96..dd82ea4aba16ed5a87a4e02b5abefc08f3f24201 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/kernel.h>
 #include <linux/mutex.h>
 #include <linux/gfp.h>
-
+#include <linux/version.h>
 #include <linux/mmc/core.h>
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
@@ -845,19 +845,18 @@ uf_glue_sdio_int_handler(struct sdio_func *func)
  *      Status of the removal.
  * ---------------------------------------------------------------------------
  */
-int
-csr_sdio_linux_remove_irq(CsrSdioFunction *function)
+int csr_sdio_linux_remove_irq(CsrSdioFunction *function)
 {
-    struct sdio_func *func = (struct sdio_func *)function->priv;
-    int r;
+       struct sdio_func *func = (struct sdio_func *)function->priv;
+       int r;
 
-    unifi_trace(NULL, UDBG1, "csr_sdio_linux_remove_irq\n");
+       unifi_trace(NULL, UDBG1, "csr_sdio_linux_remove_irq\n");
 
-    sdio_claim_host(func);
-    r = sdio_release_irq(func);
-    sdio_release_host(func);
+       sdio_claim_host(func);
+       r = sdio_release_irq(func);
+       sdio_release_host(func);
 
-    return r;
+       return r;
 
 } /* csr_sdio_linux_remove_irq() */
 
@@ -876,25 +875,23 @@ csr_sdio_linux_remove_irq(CsrSdioFunction *function)
  *      Status of the removal.
  * ---------------------------------------------------------------------------
  */
-int
-csr_sdio_linux_install_irq(CsrSdioFunction *function)
+int csr_sdio_linux_install_irq(CsrSdioFunction *function)
 {
-    struct sdio_func *func = (struct sdio_func *)function->priv;
-    int r;
+       struct sdio_func *func = (struct sdio_func *)function->priv;
+       int r;
 
-    unifi_trace(NULL, UDBG1, "csr_sdio_linux_install_irq\n");
+       unifi_trace(NULL, UDBG1, "csr_sdio_linux_install_irq\n");
 
-    /* Register our interrupt handle */
-    sdio_claim_host(func);
-    r = sdio_claim_irq(func, uf_glue_sdio_int_handler);
-    sdio_release_host(func);
+       /* Register our interrupt handle */
+       sdio_claim_host(func);
+       r = sdio_claim_irq(func, uf_glue_sdio_int_handler);
+       sdio_release_host(func);
 
-    /* If the interrupt was installed earlier, is fine */
-    if (r == -EBUSY) {
-        r = 0;
-    }
+       /* If the interrupt was installed earlier, is fine */
+       if (r == -EBUSY)
+               r = 0;
 
-    return r;
+       return r;
 } /* csr_sdio_linux_install_irq() */
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
index 229268fd746c15863ec4136946b5531930f115fd..845b654878defc9a21ddcbcd512d7282ee785f0d 100644 (file)
@@ -12,7 +12,7 @@
  */
 
 #include <linux/netdevice.h>
-
+#include <linux/version.h>
 #include "unifi_priv.h"
 #include "csr_wifi_hip_unifi.h"
 #include "csr_wifi_hip_conversions.h"
index 99de27e678d2e4ead621b00c7b29e849ca77ef81..7ff3f432d00e868403b2c043749c129f8a927b5e 100644 (file)
@@ -14,6 +14,7 @@
  * ---------------------------------------------------------------------------
  */
 
+#include <linux/version.h>
 #include "csr_wifi_hip_unifiversion.h"
 #include "unifi_priv.h"
 #include "csr_wifi_hip_conversions.h"
@@ -21,7 +22,6 @@
 #include "csr_wifi_sme_sef.h"
 #endif
 
-
 /*
  * This file implements the SME SYS API and contains the following functions:
  * CsrWifiRouterCtrlMediaStatusReqHandler()
index 7e85907e29a3ecc9edb49495a10ee45e1f62b835..568912328e9c7585de7a70d4304d3b6a92471828 100644 (file)
@@ -3043,8 +3043,8 @@ _unifi_siwencodeext(struct net_device *dev, struct iw_request_info *info,
     memcpy(sme_key.address.a, ext->addr.sa_data, ETH_ALEN);
     if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
 
-        unifi_trace(priv, UDBG5, "RSC first 6 bytes = %02X:%02X:%02X:%02X:%02X:%02X\n",
-                    ext->rx_seq[0], ext->rx_seq[1], ext->rx_seq[2], ext->rx_seq[3], ext->rx_seq[4], ext->rx_seq[5]);
+               unifi_trace(priv, UDBG5, "RSC first 6 bytes = %*phC\n",
+                                        6, ext->rx_seq);
 
         /* memcpy((u8*)(&sme_key.keyRsc), ext->rx_seq, 8); */
         sme_key.keyRsc[0] = ext->rx_seq[1] << 8 | ext->rx_seq[0];
index 46d3507fd8f14c90336dcd9bdebe412ebbb88539..819690d0fdc9ede62fcbcd465f24ec4fda522f85 100644 (file)
@@ -12,6 +12,7 @@
  *
  * ***************************************************************************
  */
+#include <linux/version.h>
 #include "csr_wifi_hip_unifi.h"
 #include "csr_wifi_hip_conversions.h"
 #include "unifi_priv.h"
index 7c7e8d49ae4207f82ef6eea6eb9d693fbfb34fe2..c28f4dd697fdd859c6996f3bec57ac24c2d1b612 100644 (file)
@@ -14,7 +14,7 @@
  * ---------------------------------------------------------------------------
  */
 
-
+#include <linux/version.h>
 #include <linux/types.h>
 #include <linux/etherdevice.h>
 #include <linux/vmalloc.h>
index 6d7a99595083a5b79923562257536c39442e57a1..fc0a06a59cf6d7fa1024f549cf37e982e378c8cf 100644 (file)
@@ -16,6 +16,7 @@
 #define __LINUX_UNIFI_WEXT_H__ 1
 
 #include <linux/kernel.h>
+#include <linux/version.h>
 #include <net/iw_handler.h>
 #include "csr_wifi_sme_prim.h"
 
index d356887ac4c603d02cf229a0388f08f5e3b7e1cc..9860ea30da2504ae301d8ff7eb382a60078b8066 100644 (file)
@@ -194,11 +194,9 @@ _send_michaelmicfailure_event(struct net_device *dev,
     union iwreq_data wrqu;
     char buf[128];
 
-    sprintf(buf,
-            "MLME-MICHAELMICFAILURE.indication(keyid=%d %scast addr=%02x:%02x:%02x:%02x:%02x:%02x)",
-            key_idx, (key_type == CSR_GROUP) ? "broad" : "uni",
-            macaddr[0], macaddr[1], macaddr[2],
-            macaddr[3], macaddr[4], macaddr[5]);
+       sprintf(buf,
+               "MLME-MICHAELMICFAILURE.indication(keyid=%d %scast addr=%pM)",
+               key_idx, (key_type == CSR_GROUP) ? "broad" : "uni", macaddr);
     memset(&wrqu, 0, sizeof(wrqu));
     wrqu.data.length = strlen(buf);
     wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf);
index 31929ef5332d3141c9559a53c744d3e5947b5314..809fa4886961ac87768a18ff0bd4be86e8b8209f 100644 (file)
@@ -73,7 +73,7 @@ static int ft1000_control(struct ft1000_device *ft1000dev, unsigned int pipe,
        }
 
        ret = usb_control_msg(ft1000dev->dev, pipe, request, requesttype,
-                             value, index, data, size, LARGE_TIMEOUT);
+                             value, index, data, size, timeout);
 
        if (ret > 0)
                ret = 0;
@@ -110,7 +110,7 @@ int ft1000_read_register(struct ft1000_device *ft1000dev, u16* Data,
                             nRegIndx,
                             Data,
                             2,
-                            LARGE_TIMEOUT);
+                            USB_CTRL_GET_TIMEOUT);
 
        return ret;
 }
@@ -143,7 +143,7 @@ int ft1000_write_register(struct ft1000_device *ft1000dev, u16 value,
                             nRegIndx,
                             NULL,
                             0,
-                            LARGE_TIMEOUT);
+                            USB_CTRL_SET_TIMEOUT);
 
        return ret;
 }
@@ -178,7 +178,7 @@ int ft1000_read_dpram32(struct ft1000_device *ft1000dev, u16 indx, u8 *buffer,
                             indx,
                             buffer,
                             cnt,
-                            LARGE_TIMEOUT);
+                            USB_CTRL_GET_TIMEOUT);
 
        return ret;
 }
@@ -215,7 +215,7 @@ int ft1000_write_dpram32(struct ft1000_device *ft1000dev, u16 indx, u8 *buffer,
                             indx,
                             buffer,
                             cnt,
-                            LARGE_TIMEOUT);
+                            USB_CTRL_SET_TIMEOUT);
 
        return ret;
 }
@@ -255,7 +255,7 @@ int ft1000_read_dpram16(struct ft1000_device *ft1000dev, u16 indx, u8 *buffer,
                             indx,
                             buffer,
                             2,
-                            LARGE_TIMEOUT);
+                            USB_CTRL_GET_TIMEOUT);
 
        return ret;
 }
@@ -294,7 +294,7 @@ int ft1000_write_dpram16(struct ft1000_device *ft1000dev, u16 indx, u16 value, u
                             indx,
                             NULL,
                             0,
-                            LARGE_TIMEOUT);
+                            USB_CTRL_SET_TIMEOUT);
 
        return ret;
 }
index 642bb89942f572ecb9140162f2e58048297430cf..2aa6a1c7fd38046d67c07905a8a7efb8d3ab9032 100644 (file)
@@ -36,8 +36,6 @@ struct app_info_block {
 
 #define FT1000_STATUS_CLOSING  0x01
 
-#define LARGE_TIMEOUT   5000
-
 #define DSPBCMSGID              0x10
 
 /* Electrabuzz specific DPRAM mapping */
index 0716efc1817de39a0c2711272a4a1312347c92ba..6cb810701a3e87b31733555b97dbae60ea7673f3 100644 (file)
@@ -258,12 +258,16 @@ static int gdm_wimax_event_init(void)
        if (!wm_event.ref_cnt) {
                wm_event.sock = netlink_init(NETLINK_WIMAX,
                                                gdm_wimax_event_rcv);
-               if (wm_event.sock)
-                       wm_event.ref_cnt++;
-               INIT_LIST_HEAD(&wm_event.evtq);
-               INIT_LIST_HEAD(&wm_event.freeq);
-               INIT_WORK(&wm_event.ws, __gdm_wimax_event_send);
-               spin_lock_init(&wm_event.evt_lock);
+               if (wm_event.sock) {
+                       INIT_LIST_HEAD(&wm_event.evtq);
+                       INIT_LIST_HEAD(&wm_event.freeq);
+                       INIT_WORK(&wm_event.ws, __gdm_wimax_event_send);
+                       spin_lock_init(&wm_event.evt_lock);
+               }
+       }
+
+       if (wm_event.sock) {
+               wm_event.ref_cnt++;
                return 0;
        }
 
index 827e92de8e30a83485a334344f75bfb60ee5dfa1..40d0ecac047f5a4511ae99a4fb250d2a8ebb3196 100644 (file)
@@ -104,6 +104,16 @@ void process_scan(char *data,
                        print2byte(*(uint16_t *)(data + channels[k].location),
                                   &channels[k]);
                        break;
+               case 4:
+                       if (!channels[k].is_signed) {
+                               uint32_t val = *(uint32_t *)
+                                       (data + channels[k].location);
+                               printf("%05f ", ((float)val +
+                                                channels[k].offset)*
+                                      channels[k].scale);
+
+                       }
+                       break;
                case 8:
                        if (channels[k].is_signed) {
                                int64_t val = *(int64_t *)
index 204106b72d2418649974cfb91aeae9cc2df693bc..ec2332f568fac86c80a2c21cc31ee3899bb20d7a 100644 (file)
@@ -390,7 +390,7 @@ static int adis16201_write_raw(struct iio_dev *indio_dev,
        return -EINVAL;
 }
 
-static struct iio_chan_spec adis16201_channels[] = {
+static const struct iio_chan_spec adis16201_channels[] = {
        {
                .type = IIO_VOLTAGE,
                .indexed = 1,
index 22085e9dfd16f45e7ba0b55c34dce055fd71656b..34b76c51c78bdf49b8d1384e3ce02ecb8224a8e6 100644 (file)
@@ -355,7 +355,7 @@ static int adis16203_read_raw(struct iio_dev *indio_dev,
        }
 }
 
-static struct iio_chan_spec adis16203_channels[] = {
+static const struct iio_chan_spec adis16203_channels[] = {
        {
                .type = IIO_VOLTAGE,
                .indexed = 1,
index 5f2e5f11c5437bb514aed98a2953c85fca6cfc88..02fb101aca93f873ae7f0b33ea18fe408d2c6e92 100644 (file)
@@ -397,7 +397,7 @@ static int adis16204_write_raw(struct iio_dev *indio_dev,
        return -EINVAL;
 }
 
-static struct iio_chan_spec adis16204_channels[] = {
+static const struct iio_chan_spec adis16204_channels[] = {
        {
                .type = IIO_VOLTAGE,
                .indexed = 1, /* Note was not previously indexed */
index 494570508c364d3639474050adbef7ceed673d72..4fa2229d8736ff4281a82abd30c7ce99abb9b34d 100644 (file)
@@ -390,7 +390,7 @@ static int adis16209_read_raw(struct iio_dev *indio_dev,
        return -EINVAL;
 }
 
-static struct iio_chan_spec adis16209_channels[] = {
+static const struct iio_chan_spec adis16209_channels[] = {
        {
                .type = IIO_VOLTAGE,
                .indexed = 1,
index 575f1af25d5d2dafdaaa04df7347a7b92bf18029..c31e1ec2e66a15a6846c7ad218639f3bd5ff578f 100644 (file)
@@ -372,8 +372,7 @@ static ssize_t adis16220_accel_bin_read(struct file *filp, struct kobject *kobj,
                                        loff_t off,
                                        size_t count)
 {
-       struct device *dev = container_of(kobj, struct device, kobj);
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct iio_dev *indio_dev = dev_to_iio_dev(kobj_to_dev(kobj));
 
        return adis16220_capture_buffer_read(indio_dev, buf,
                                        off, count,
@@ -394,8 +393,7 @@ static ssize_t adis16220_adc1_bin_read(struct file *filp, struct kobject *kobj,
                                char *buf, loff_t off,
                                size_t count)
 {
-       struct device *dev = container_of(kobj, struct device, kobj);
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct iio_dev *indio_dev = dev_to_iio_dev(kobj_to_dev(kobj));
 
        return adis16220_capture_buffer_read(indio_dev, buf,
                                        off, count,
@@ -416,8 +414,7 @@ static ssize_t adis16220_adc2_bin_read(struct file *filp, struct kobject *kobj,
                                char *buf, loff_t off,
                                size_t count)
 {
-       struct device *dev = container_of(kobj, struct device, kobj);
-       struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+       struct iio_dev *indio_dev = dev_to_iio_dev(kobj_to_dev(kobj));
 
        return adis16220_capture_buffer_read(indio_dev, buf,
                                        off, count,
index b30b7874ffb09f434231bd43a48b5f8a8128e3e2..dafc0d8cbf63107d163d14559ad9eb4b3f1bbcea 100644 (file)
@@ -448,7 +448,7 @@ static int adis16240_write_raw(struct iio_dev *indio_dev,
        return -EINVAL;
 }
 
-static struct iio_chan_spec adis16240_channels[] = {
+static const struct iio_chan_spec adis16240_channels[] = {
        {
                .type = IIO_VOLTAGE,
                .indexed = 1,
index 8cf7cd943c90957166637e3a9cde38235f5c7e2a..713469fd2ac02984051b8d1b3984b05cf20f4a8e 100644 (file)
@@ -186,7 +186,7 @@ error_ret:
                .address = KXSD9_REG_##axis,                            \
        }
 
-static struct iio_chan_spec kxsd9_channels[] = {
+static const struct iio_chan_spec kxsd9_channels[] = {
        KXSD9_ACCEL_CHAN(X), KXSD9_ACCEL_CHAN(Y), KXSD9_ACCEL_CHAN(Z),
        {
                .type = IIO_VOLTAGE,
index 9d263484fb869bd4df3a8d3ace8e1e9ae3758d62..0c2b4bae0a9b433c201de489d247e48f50c880ba 100644 (file)
@@ -538,7 +538,7 @@ static irqreturn_t lis3l02dq_event_handler(int irq, void *private)
                .event_mask = LIS3L02DQ_EVENT_MASK,             \
         }
 
-static struct iio_chan_spec lis3l02dq_channels[] = {
+static const struct iio_chan_spec lis3l02dq_channels[] = {
        LIS3L02DQ_CHAN(0, IIO_MOD_X),
        LIS3L02DQ_CHAN(1, IIO_MOD_Y),
        LIS3L02DQ_CHAN(2, IIO_MOD_Z),
index c218d71abf1fcb12a4374864e0c8abf8791afa83..cc040e14adba2c146c4c52fa533cb51bdbb74c27 100644 (file)
@@ -450,7 +450,7 @@ static IIO_DEVICE_ATTR(revision, S_IRUGO, sca3000_show_rev, NULL, 0);
                .event_mask = SCA3000_EVENT_MASK,               \
         }
 
-static struct iio_chan_spec sca3000_channels[] = {
+static const struct iio_chan_spec sca3000_channels[] = {
        SCA3000_CHAN(0, IIO_MOD_X),
        SCA3000_CHAN(1, IIO_MOD_Y),
        SCA3000_CHAN(2, IIO_MOD_Z),
index 67711b7d718a759523f0c9cbfd985e9f55601a94..845fb6c70ca340053c003cd5b0bfb1e85eeabb23 100644 (file)
@@ -200,6 +200,18 @@ config LPC32XX_ADC
          activate only one via device tree selection.  Provides direct access
          via sysfs.
 
+config MXS_LRADC
+       tristate "Freescale i.MX28 LRADC"
+       depends on ARCH_MXS
+       select IIO_BUFFER
+       select IIO_TRIGGERED_BUFFER
+       help
+         Say yes here to build support for i.MX28 LRADC convertor
+         built into these chips.
+
+         To compile this driver as a module, choose M here: the
+         module will be called mxs-lradc.
+
 config SPEAR_ADC
        tristate "ST SPEAr ADC"
        depends on PLAT_SPEAR
index 14e98b62b70a26bc3b2399477d40a9f5e3b2be98..ecac9a0bb35851d2add632b263c82b5879f232bd 100644 (file)
@@ -38,4 +38,5 @@ obj-$(CONFIG_ADT7310) += adt7310.o
 obj-$(CONFIG_ADT7410) += adt7410.o
 obj-$(CONFIG_AD7280) += ad7280a.o
 obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o
+obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o
 obj-$(CONFIG_SPEAR_ADC) += spear_adc.o
index 22c3923d55eb34fc31c1313a570498d31dcb95a1..405d9a8d7b6db1082cbba722997247509863c2f1 100644 (file)
@@ -754,7 +754,7 @@ static ssize_t ad7192_set(struct device *dev,
                else
                        st->mode &= ~AD7192_MODE_ACX;
 
-               ad7192_write_reg(st, AD7192_REG_GPOCON, 3, st->mode);
+               ad7192_write_reg(st, AD7192_REG_MODE, 3, st->mode);
                break;
        default:
                ret = -EINVAL;
@@ -798,6 +798,11 @@ static const struct attribute_group ad7195_attribute_group = {
        .attrs = ad7195_attributes,
 };
 
+static unsigned int ad7192_get_temp_scale(bool unipolar)
+{
+       return unipolar ? 2815 * 2 : 2815;
+}
+
 static int ad7192_read_raw(struct iio_dev *indio_dev,
                           struct iio_chan_spec const *chan,
                           int *val,
@@ -824,19 +829,6 @@ static int ad7192_read_raw(struct iio_dev *indio_dev,
                *val = (smpl >> chan->scan_type.shift) &
                        ((1 << (chan->scan_type.realbits)) - 1);
 
-               switch (chan->type) {
-               case IIO_VOLTAGE:
-                       if (!unipolar)
-                               *val -= (1 << (chan->scan_type.realbits - 1));
-                       break;
-               case IIO_TEMP:
-                       *val -= 0x800000;
-                       *val /= 2815; /* temp Kelvin */
-                       *val -= 273; /* temp Celsius */
-                       break;
-               default:
-                       return -EINVAL;
-               }
                return IIO_VAL_INT;
 
        case IIO_CHAN_INFO_SCALE:
@@ -848,11 +840,21 @@ static int ad7192_read_raw(struct iio_dev *indio_dev,
                        mutex_unlock(&indio_dev->mlock);
                        return IIO_VAL_INT_PLUS_NANO;
                case IIO_TEMP:
-                       *val =  1000;
-                       return IIO_VAL_INT;
+                       *val = 0;
+                       *val2 = 1000000000 / ad7192_get_temp_scale(unipolar);
+                       return IIO_VAL_INT_PLUS_NANO;
                default:
                        return -EINVAL;
                }
+       case IIO_CHAN_INFO_OFFSET:
+               if (!unipolar)
+                       *val = -(1 << (chan->scan_type.realbits - 1));
+               else
+                       *val = 0;
+               /* Kelvin to Celsius */
+               if (chan->type == IIO_TEMP)
+                       *val -= 273 * ad7192_get_temp_scale(unipolar);
+               return IIO_VAL_INT;
        }
 
        return -EINVAL;
@@ -890,7 +892,7 @@ static int ad7192_write_raw(struct iio_dev *indio_dev,
                                }
                                ret = 0;
                        }
-
+               break;
        default:
                ret = -EINVAL;
        }
@@ -942,20 +944,22 @@ static const struct iio_info ad7195_info = {
          .channel = _chan,                                             \
          .channel2 = _chan2,                                           \
          .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |                 \
-         IIO_CHAN_INFO_SCALE_SHARED_BIT,                               \
+         IIO_CHAN_INFO_SCALE_SHARED_BIT |                              \
+         IIO_CHAN_INFO_OFFSET_SHARED_BIT,                              \
          .address = _address,                                          \
          .scan_index = _si,                                            \
-         .scan_type =  IIO_ST('s', 24, 32, 0)}
+         .scan_type =  IIO_ST('u', 24, 32, 0)}
 
 #define AD7192_CHAN(_chan, _address, _si)                              \
        { .type = IIO_VOLTAGE,                                          \
          .indexed = 1,                                                 \
          .channel = _chan,                                             \
          .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |                 \
-         IIO_CHAN_INFO_SCALE_SHARED_BIT,                               \
+         IIO_CHAN_INFO_SCALE_SHARED_BIT |                              \
+         IIO_CHAN_INFO_OFFSET_SHARED_BIT,                              \
          .address = _address,                                          \
          .scan_index = _si,                                            \
-         .scan_type =  IIO_ST('s', 24, 32, 0)}
+         .scan_type =  IIO_ST('u', 24, 32, 0)}
 
 #define AD7192_CHAN_TEMP(_chan, _address, _si)                         \
        { .type = IIO_TEMP,                                             \
@@ -965,9 +969,9 @@ static const struct iio_info ad7195_info = {
          IIO_CHAN_INFO_SCALE_SEPARATE_BIT,                             \
          .address = _address,                                          \
          .scan_index = _si,                                            \
-         .scan_type =  IIO_ST('s', 24, 32, 0)}
+         .scan_type =  IIO_ST('u', 24, 32, 0)}
 
-static struct iio_chan_spec ad7192_channels[] = {
+static const struct iio_chan_spec ad7192_channels[] = {
        AD7192_CHAN_DIFF(1, 2, NULL, AD7192_CH_AIN1P_AIN2M, 0),
        AD7192_CHAN_DIFF(3, 4, NULL, AD7192_CH_AIN3P_AIN4M, 1),
        AD7192_CHAN_TEMP(0, AD7192_CH_TEMP, 2),
index 6141f4a70cfa53686d3c99c25fe0dd0f1af62577..4c75114e7d7cbb6d4890acafc74f50e5a0ab17af 100644 (file)
@@ -38,7 +38,7 @@
                },                                                      \
        }
 
-static struct iio_chan_spec ad7298_channels[] = {
+static const struct iio_chan_spec ad7298_channels[] = {
        {
                .type = IIO_TEMP,
                .indexed = 1,
index fd1d855ff57a1c5e2b3786afbc67f5303767a76e..506016f01593c6bdd7a68279f19fa1363b2d21f8 100644 (file)
@@ -76,7 +76,7 @@ static irqreturn_t ad7298_trigger_handler(int irq, void *p)
        struct iio_dev *indio_dev = pf->indio_dev;
        struct ad7298_state *st = iio_priv(indio_dev);
        struct iio_buffer *ring = indio_dev->buffer;
-       s64 time_ns;
+       s64 time_ns = 0;
        __u16 buf[16];
        int b_sent, i;
 
index 10f59896597f95742d1951cf52c9f9d58c3e5ad4..9221a74efd18a00cf31c24c79b3e271a7a181d85 100644 (file)
@@ -51,7 +51,7 @@ struct ad7606_platform_data {
 struct ad7606_chip_info {
        const char                      *name;
        u16                             int_vref_mv;
-       struct iio_chan_spec            *channels;
+       const struct iio_chan_spec      *channels;
        unsigned                        num_channels;
 };
 
index ccb97fecdea792d6252cf3176b9dbce13fd2611b..bae61cbe921259cbc9eb0a71136534f36b2da97f 100644 (file)
@@ -241,7 +241,7 @@ static const struct attribute_group ad7606_attribute_group_range = {
                .scan_type = IIO_ST('s', 16, 16, 0),            \
        }
 
-static struct iio_chan_spec ad7606_8_channels[] = {
+static const struct iio_chan_spec ad7606_8_channels[] = {
        AD7606_CHANNEL(0),
        AD7606_CHANNEL(1),
        AD7606_CHANNEL(2),
@@ -253,7 +253,7 @@ static struct iio_chan_spec ad7606_8_channels[] = {
        IIO_CHAN_SOFT_TIMESTAMP(8),
 };
 
-static struct iio_chan_spec ad7606_6_channels[] = {
+static const struct iio_chan_spec ad7606_6_channels[] = {
        AD7606_CHANNEL(0),
        AD7606_CHANNEL(1),
        AD7606_CHANNEL(2),
@@ -263,7 +263,7 @@ static struct iio_chan_spec ad7606_6_channels[] = {
        IIO_CHAN_SOFT_TIMESTAMP(6),
 };
 
-static struct iio_chan_spec ad7606_4_channels[] = {
+static const struct iio_chan_spec ad7606_4_channels[] = {
        AD7606_CHANNEL(0),
        AD7606_CHANNEL(1),
        AD7606_CHANNEL(2),
index 1ece2ac8de56965ea0af82c378244da50bdfdece..19ee49c95de49725e4dfdb62c0e4805a9215cce4 100644 (file)
@@ -131,9 +131,10 @@ static const struct ad7780_chip_info ad7780_chip_info_tbl[] = {
                        .indexed = 1,
                        .channel = 0,
                        .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-                       IIO_CHAN_INFO_SCALE_SHARED_BIT,
+                       IIO_CHAN_INFO_SCALE_SHARED_BIT |
+                       IIO_CHAN_INFO_OFFSET_SHARED_BIT,
                        .scan_type = {
-                               .sign = 's',
+                               .sign = 'u',
                                .realbits = 24,
                                .storagebits = 32,
                                .shift = 8,
@@ -146,9 +147,10 @@ static const struct ad7780_chip_info ad7780_chip_info_tbl[] = {
                        .indexed = 1,
                        .channel = 0,
                        .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-                       IIO_CHAN_INFO_SCALE_SHARED_BIT,
+                       IIO_CHAN_INFO_SCALE_SHARED_BIT |
+                       IIO_CHAN_INFO_OFFSET_SHARED_BIT,
                        .scan_type = {
-                               .sign = 's',
+                               .sign = 'u',
                                .realbits = 20,
                                .storagebits = 32,
                                .shift = 12,
index 76fdd7145fc5d855544c977560dfc3803baa7b95..112e2b7b5bc4a5b1c459081ec23f624b3eed5f9f 100644 (file)
@@ -563,8 +563,9 @@ static ssize_t ad7793_show_scale_available(struct device *dev,
        return len;
 }
 
-static IIO_DEVICE_ATTR_NAMED(in_m_in_scale_available, in-in_scale_available,
-                            S_IRUGO, ad7793_show_scale_available, NULL, 0);
+static IIO_DEVICE_ATTR_NAMED(in_m_in_scale_available,
+               in_voltage-voltage_scale_available, S_IRUGO,
+               ad7793_show_scale_available, NULL, 0);
 
 static struct attribute *ad7793_attributes[] = {
        &iio_dev_attr_sampling_frequency.dev_attr.attr,
@@ -604,9 +605,6 @@ static int ad7793_read_raw(struct iio_dev *indio_dev,
                *val = (smpl >> chan->scan_type.shift) &
                        ((1 << (chan->scan_type.realbits)) - 1);
 
-               if (!unipolar)
-                       *val -= (1 << (chan->scan_type.realbits - 1));
-
                return IIO_VAL_INT;
 
        case IIO_CHAN_INFO_SCALE:
@@ -620,25 +618,38 @@ static int ad7793_read_raw(struct iio_dev *indio_dev,
                                return IIO_VAL_INT_PLUS_NANO;
                        } else {
                                /* 1170mV / 2^23 * 6 */
-                               scale_uv = (1170ULL * 100000000ULL * 6ULL)
-                                       >> (chan->scan_type.realbits -
-                                           (unipolar ? 0 : 1));
+                               scale_uv = (1170ULL * 100000000ULL * 6ULL);
                        }
                        break;
                case IIO_TEMP:
-                       /* Always uses unity gain and internal ref */
-                       scale_uv = (2500ULL * 100000000ULL)
-                               >> (chan->scan_type.realbits -
-                               (unipolar ? 0 : 1));
+                               /* 1170mV / 0.81 mV/C / 2^23 */
+                               scale_uv = 1444444444444ULL;
                        break;
                default:
                        return -EINVAL;
                }
 
-               *val2 = do_div(scale_uv, 100000000) * 10;
-               *val =  scale_uv;
-
+               scale_uv >>= (chan->scan_type.realbits - (unipolar ? 0 : 1));
+               *val = 0;
+               *val2 = scale_uv;
                return IIO_VAL_INT_PLUS_NANO;
+       case IIO_CHAN_INFO_OFFSET:
+               if (!unipolar)
+                       *val = -(1 << (chan->scan_type.realbits - 1));
+               else
+                       *val = 0;
+
+               /* Kelvin to Celsius */
+               if (chan->type == IIO_TEMP) {
+                       unsigned long long offset;
+                       unsigned int shift;
+
+                       shift = chan->scan_type.realbits - (unipolar ? 0 : 1);
+                       offset = 273ULL << shift;
+                       do_div(offset, 1444);
+                       *val -= offset;
+               }
+               return IIO_VAL_INT;
        }
        return -EINVAL;
 }
@@ -676,7 +687,7 @@ static int ad7793_write_raw(struct iio_dev *indio_dev,
                                }
                                ret = 0;
                        }
-
+               break;
        default:
                ret = -EINVAL;
        }
@@ -720,9 +731,10 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
                        .channel2 = 0,
                        .address = AD7793_CH_AIN1P_AIN1M,
                        .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-                       IIO_CHAN_INFO_SCALE_SHARED_BIT,
+                       IIO_CHAN_INFO_SCALE_SHARED_BIT |
+                       IIO_CHAN_INFO_OFFSET_SHARED_BIT,
                        .scan_index = 0,
-                       .scan_type = IIO_ST('s', 24, 32, 0)
+                       .scan_type = IIO_ST('u', 24, 32, 0)
                },
                .channel[1] = {
                        .type = IIO_VOLTAGE,
@@ -732,9 +744,10 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
                        .channel2 = 1,
                        .address = AD7793_CH_AIN2P_AIN2M,
                        .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-                       IIO_CHAN_INFO_SCALE_SHARED_BIT,
+                       IIO_CHAN_INFO_SCALE_SHARED_BIT |
+                       IIO_CHAN_INFO_OFFSET_SHARED_BIT,
                        .scan_index = 1,
-                       .scan_type = IIO_ST('s', 24, 32, 0)
+                       .scan_type = IIO_ST('u', 24, 32, 0)
                },
                .channel[2] = {
                        .type = IIO_VOLTAGE,
@@ -744,9 +757,10 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
                        .channel2 = 2,
                        .address = AD7793_CH_AIN3P_AIN3M,
                        .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-                       IIO_CHAN_INFO_SCALE_SHARED_BIT,
+                       IIO_CHAN_INFO_SCALE_SHARED_BIT |
+                       IIO_CHAN_INFO_OFFSET_SHARED_BIT,
                        .scan_index = 2,
-                       .scan_type = IIO_ST('s', 24, 32, 0)
+                       .scan_type = IIO_ST('u', 24, 32, 0)
                },
                .channel[3] = {
                        .type = IIO_VOLTAGE,
@@ -757,9 +771,10 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
                        .channel2 = 2,
                        .address = AD7793_CH_AIN1M_AIN1M,
                        .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-                       IIO_CHAN_INFO_SCALE_SHARED_BIT,
+                       IIO_CHAN_INFO_SCALE_SHARED_BIT |
+                       IIO_CHAN_INFO_OFFSET_SHARED_BIT,
                        .scan_index = 3,
-                       .scan_type = IIO_ST('s', 24, 32, 0)
+                       .scan_type = IIO_ST('u', 24, 32, 0)
                },
                .channel[4] = {
                        .type = IIO_TEMP,
@@ -769,7 +784,7 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
                        .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
                        IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
                        .scan_index = 4,
-                       .scan_type = IIO_ST('s', 24, 32, 0),
+                       .scan_type = IIO_ST('u', 24, 32, 0),
                },
                .channel[5] = {
                        .type = IIO_VOLTAGE,
@@ -778,9 +793,10 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
                        .channel = 4,
                        .address = AD7793_CH_AVDD_MONITOR,
                        .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-                       IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+                       IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
+                       IIO_CHAN_INFO_OFFSET_SHARED_BIT,
                        .scan_index = 5,
-                       .scan_type = IIO_ST('s', 24, 32, 0),
+                       .scan_type = IIO_ST('u', 24, 32, 0),
                },
                .channel[6] = IIO_CHAN_SOFT_TIMESTAMP(6),
        },
@@ -793,9 +809,10 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
                        .channel2 = 0,
                        .address = AD7793_CH_AIN1P_AIN1M,
                        .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-                       IIO_CHAN_INFO_SCALE_SHARED_BIT,
+                       IIO_CHAN_INFO_SCALE_SHARED_BIT |
+                       IIO_CHAN_INFO_OFFSET_SHARED_BIT,
                        .scan_index = 0,
-                       .scan_type = IIO_ST('s', 16, 32, 0)
+                       .scan_type = IIO_ST('u', 16, 32, 0)
                },
                .channel[1] = {
                        .type = IIO_VOLTAGE,
@@ -805,9 +822,10 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
                        .channel2 = 1,
                        .address = AD7793_CH_AIN2P_AIN2M,
                        .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-                       IIO_CHAN_INFO_SCALE_SHARED_BIT,
+                       IIO_CHAN_INFO_SCALE_SHARED_BIT |
+                       IIO_CHAN_INFO_OFFSET_SHARED_BIT,
                        .scan_index = 1,
-                       .scan_type = IIO_ST('s', 16, 32, 0)
+                       .scan_type = IIO_ST('u', 16, 32, 0)
                },
                .channel[2] = {
                        .type = IIO_VOLTAGE,
@@ -817,9 +835,10 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
                        .channel2 = 2,
                        .address = AD7793_CH_AIN3P_AIN3M,
                        .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-                       IIO_CHAN_INFO_SCALE_SHARED_BIT,
+                       IIO_CHAN_INFO_SCALE_SHARED_BIT |
+                       IIO_CHAN_INFO_OFFSET_SHARED_BIT,
                        .scan_index = 2,
-                       .scan_type = IIO_ST('s', 16, 32, 0)
+                       .scan_type = IIO_ST('u', 16, 32, 0)
                },
                .channel[3] = {
                        .type = IIO_VOLTAGE,
@@ -830,9 +849,10 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
                        .channel2 = 2,
                        .address = AD7793_CH_AIN1M_AIN1M,
                        .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-                       IIO_CHAN_INFO_SCALE_SHARED_BIT,
+                       IIO_CHAN_INFO_SCALE_SHARED_BIT |
+                       IIO_CHAN_INFO_OFFSET_SHARED_BIT,
                        .scan_index = 3,
-                       .scan_type = IIO_ST('s', 16, 32, 0)
+                       .scan_type = IIO_ST('u', 16, 32, 0)
                },
                .channel[4] = {
                        .type = IIO_TEMP,
@@ -842,7 +862,7 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
                        .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
                        IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
                        .scan_index = 4,
-                       .scan_type = IIO_ST('s', 16, 32, 0),
+                       .scan_type = IIO_ST('u', 16, 32, 0),
                },
                .channel[5] = {
                        .type = IIO_VOLTAGE,
@@ -851,9 +871,10 @@ static const struct ad7793_chip_info ad7793_chip_info_tbl[] = {
                        .channel = 4,
                        .address = AD7793_CH_AVDD_MONITOR,
                        .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
-                       IIO_CHAN_INFO_SCALE_SEPARATE_BIT,
+                       IIO_CHAN_INFO_SCALE_SEPARATE_BIT |
+                       IIO_CHAN_INFO_OFFSET_SHARED_BIT,
                        .scan_index = 5,
-                       .scan_type = IIO_ST('s', 16, 32, 0),
+                       .scan_type = IIO_ST('u', 16, 32, 0),
                },
                .channel[6] = IIO_CHAN_SOFT_TIMESTAMP(6),
        },
@@ -901,7 +922,7 @@ static int __devinit ad7793_probe(struct spi_device *spi)
        else if (voltage_uv)
                st->int_vref_mv = voltage_uv / 1000;
        else
-               st->int_vref_mv = 2500; /* Build-in ref */
+               st->int_vref_mv = 1170; /* Build-in ref */
 
        spi_set_drvdata(spi, indio_dev);
        st->spi = spi;
index 348d051fc2f8a567ec26c113fcc3eda668cb9c6d..7e9bd0001cc7f9d1c239faf578e8b557d7c2cb01 100644 (file)
@@ -108,7 +108,7 @@ static const struct iio_info lpc32xx_adc_iio_info = {
        .scan_index = _index,                           \
 }
 
-static struct iio_chan_spec lpc32xx_adc_iio_channels[] = {
+static const struct iio_chan_spec lpc32xx_adc_iio_channels[] = {
        LPC32XX_ADC_CHANNEL(0),
        LPC32XX_ADC_CHANNEL(1),
        LPC32XX_ADC_CHANNEL(2),
index 2cd0112067b21fb3ca1df3c070208fbbf0987ac9..c746918683f14aa5b922797ba939943c8035de04 100644 (file)
@@ -100,7 +100,7 @@ enum max1363_modes {
  */
 struct max1363_chip_info {
        const struct iio_info           *info;
-       struct iio_chan_spec *channels;
+       const struct iio_chan_spec *channels;
        int num_channels;
        const enum max1363_modes        *mode_list;
        enum max1363_modes              default_mode;
index 6799ce23a395391c17a0347061b04376d91a0487..816bb2c2e0c5210a4b8aee2b590849aad13537f0 100644 (file)
@@ -335,12 +335,12 @@ static const enum max1363_modes max1363_mode_list[] = {
        IIO_CHAN_SOFT_TIMESTAMP(8)                      \
        }
 
-static struct iio_chan_spec max1036_channels[] = MAX1363_4X_CHANS(8, 0);
-static struct iio_chan_spec max1136_channels[] = MAX1363_4X_CHANS(10, 0);
-static struct iio_chan_spec max1236_channels[] = MAX1363_4X_CHANS(12, 0);
-static struct iio_chan_spec max1361_channels[] =
+static const struct iio_chan_spec max1036_channels[] = MAX1363_4X_CHANS(8, 0);
+static const struct iio_chan_spec max1136_channels[] = MAX1363_4X_CHANS(10, 0);
+static const struct iio_chan_spec max1236_channels[] = MAX1363_4X_CHANS(12, 0);
+static const struct iio_chan_spec max1361_channels[] =
        MAX1363_4X_CHANS(10, MAX1363_EV_M);
-static struct iio_chan_spec max1363_channels[] =
+static const struct iio_chan_spec max1363_channels[] =
        MAX1363_4X_CHANS(12, MAX1363_EV_M);
 
 /* Applies to max1236, max1237 */
@@ -392,9 +392,9 @@ static const enum max1363_modes max1238_mode_list[] = {
        MAX1363_CHAN_B(11, 10, d11m10, 23, bits, 0),    \
        IIO_CHAN_SOFT_TIMESTAMP(24)                     \
        }
-static struct iio_chan_spec max1038_channels[] = MAX1363_12X_CHANS(8);
-static struct iio_chan_spec max1138_channels[] = MAX1363_12X_CHANS(10);
-static struct iio_chan_spec max1238_channels[] = MAX1363_12X_CHANS(12);
+static const struct iio_chan_spec max1038_channels[] = MAX1363_12X_CHANS(8);
+static const struct iio_chan_spec max1138_channels[] = MAX1363_12X_CHANS(10);
+static const struct iio_chan_spec max1238_channels[] = MAX1363_12X_CHANS(12);
 
 static const enum max1363_modes max11607_mode_list[] = {
        _s0, _s1, _s2, _s3,
@@ -433,9 +433,9 @@ static const enum max1363_modes max11608_mode_list[] = {
        MAX1363_CHAN_B(7, 6, d7m6, 15, bits, 0),        \
        IIO_CHAN_SOFT_TIMESTAMP(16)                     \
 }
-static struct iio_chan_spec max11602_channels[] = MAX1363_8X_CHANS(8);
-static struct iio_chan_spec max11608_channels[] = MAX1363_8X_CHANS(10);
-static struct iio_chan_spec max11614_channels[] = MAX1363_8X_CHANS(12);
+static const struct iio_chan_spec max11602_channels[] = MAX1363_8X_CHANS(8);
+static const struct iio_chan_spec max11608_channels[] = MAX1363_8X_CHANS(10);
+static const struct iio_chan_spec max11614_channels[] = MAX1363_8X_CHANS(12);
 
 static const enum max1363_modes max11644_mode_list[] = {
        _s0, _s1, s0to1, d0m1, d1m0,
@@ -449,8 +449,8 @@ static const enum max1363_modes max11644_mode_list[] = {
        IIO_CHAN_SOFT_TIMESTAMP(4)                      \
        }
 
-static struct iio_chan_spec max11646_channels[] = MAX1363_2X_CHANS(10);
-static struct iio_chan_spec max11644_channels[] = MAX1363_2X_CHANS(12);
+static const struct iio_chan_spec max11646_channels[] = MAX1363_2X_CHANS(10);
+static const struct iio_chan_spec max11644_channels[] = MAX1363_2X_CHANS(12);
 
 enum { max1361,
        max1362,
diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c
new file mode 100644 (file)
index 0000000..ae549e5
--- /dev/null
@@ -0,0 +1,590 @@
+/*
+ * Freescale i.MX28 LRADC driver
+ *
+ * Copyright (c) 2012 DENX Software Engineering, GmbH.
+ * Marek Vasut <marex@denx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/sysfs.h>
+#include <linux/list.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/stmp_device.h>
+#include <linux/bitops.h>
+#include <linux/completion.h>
+
+#include <mach/mxs.h>
+#include <mach/common.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#define DRIVER_NAME            "mxs-lradc"
+
+#define LRADC_MAX_DELAY_CHANS  4
+#define LRADC_MAX_MAPPED_CHANS 8
+#define LRADC_MAX_TOTAL_CHANS  16
+
+#define LRADC_DELAY_TIMER_HZ   2000
+
+/*
+ * Make this runtime configurable if necessary. Currently, if the buffered mode
+ * is enabled, the LRADC takes LRADC_DELAY_TIMER_LOOP samples of data before
+ * triggering IRQ. The sampling happens every (LRADC_DELAY_TIMER_PER / 2000)
+ * seconds. The result is that the samples arrive every 500mS.
+ */
+#define LRADC_DELAY_TIMER_PER  200
+#define LRADC_DELAY_TIMER_LOOP 5
+
+static const char * const mxs_lradc_irq_name[] = {
+       "mxs-lradc-touchscreen",
+       "mxs-lradc-thresh0",
+       "mxs-lradc-thresh1",
+       "mxs-lradc-channel0",
+       "mxs-lradc-channel1",
+       "mxs-lradc-channel2",
+       "mxs-lradc-channel3",
+       "mxs-lradc-channel4",
+       "mxs-lradc-channel5",
+       "mxs-lradc-channel6",
+       "mxs-lradc-channel7",
+       "mxs-lradc-button0",
+       "mxs-lradc-button1",
+};
+
+struct mxs_lradc_chan {
+       uint8_t                         slot;
+       uint8_t                         flags;
+};
+
+struct mxs_lradc {
+       struct device           *dev;
+       void __iomem            *base;
+       int                     irq[13];
+
+       uint32_t                *buffer;
+       struct iio_trigger      *trig;
+
+       struct mutex            lock;
+
+       uint8_t                 enable;
+
+       struct completion       completion;
+};
+
+#define        LRADC_CTRL0                             0x00
+#define LRADC_CTRL0_TOUCH_DETECT_ENABLE                (1 << 23)
+#define LRADC_CTRL0_TOUCH_SCREEN_TYPE          (1 << 22)
+
+#define        LRADC_CTRL1                             0x10
+#define        LRADC_CTRL1_LRADC_IRQ(n)                (1 << (n))
+#define        LRADC_CTRL1_LRADC_IRQ_MASK              0x1fff
+#define        LRADC_CTRL1_LRADC_IRQ_EN(n)             (1 << ((n) + 16))
+#define        LRADC_CTRL1_LRADC_IRQ_EN_MASK           (0x1fff << 16)
+
+#define        LRADC_CTRL2                             0x20
+#define        LRADC_CTRL2_TEMPSENSE_PWD               (1 << 15)
+
+#define        LRADC_CH(n)                             (0x50 + (0x10 * (n)))
+#define        LRADC_CH_ACCUMULATE                     (1 << 29)
+#define        LRADC_CH_NUM_SAMPLES_MASK               (0x1f << 24)
+#define        LRADC_CH_NUM_SAMPLES_OFFSET             24
+#define        LRADC_CH_VALUE_MASK                     0x3ffff
+#define        LRADC_CH_VALUE_OFFSET                   0
+
+#define        LRADC_DELAY(n)                          (0xd0 + (0x10 * (n)))
+#define        LRADC_DELAY_TRIGGER_LRADCS_MASK         (0xff << 24)
+#define        LRADC_DELAY_TRIGGER_LRADCS_OFFSET       24
+#define        LRADC_DELAY_KICK                        (1 << 20)
+#define        LRADC_DELAY_TRIGGER_DELAYS_MASK         (0xf << 16)
+#define        LRADC_DELAY_TRIGGER_DELAYS_OFFSET       16
+#define        LRADC_DELAY_LOOP_COUNT_MASK             (0x1f << 11)
+#define        LRADC_DELAY_LOOP_COUNT_OFFSET           11
+#define        LRADC_DELAY_DELAY_MASK                  0x7ff
+#define        LRADC_DELAY_DELAY_OFFSET                0
+
+#define        LRADC_CTRL4                             0x140
+#define        LRADC_CTRL4_LRADCSELECT_MASK(n)         (0xf << ((n) * 4))
+#define        LRADC_CTRL4_LRADCSELECT_OFFSET(n)       ((n) * 4)
+
+/*
+ * Raw I/O operations
+ */
+static int mxs_lradc_read_raw(struct iio_dev *iio_dev,
+                       const struct iio_chan_spec *chan,
+                       int *val, int *val2, long m)
+{
+       struct mxs_lradc *lradc = iio_priv(iio_dev);
+       int ret;
+
+       if (m != IIO_CHAN_INFO_RAW)
+               return -EINVAL;
+
+       /* Check for invalid channel */
+       if (chan->channel > LRADC_MAX_TOTAL_CHANS)
+               return -EINVAL;
+
+       /*
+        * See if there is no buffered operation in progess. If there is, simply
+        * bail out. This can be improved to support both buffered and raw IO at
+        * the same time, yet the code becomes horribly complicated. Therefore I
+        * applied KISS principle here.
+        */
+       ret = mutex_trylock(&lradc->lock);
+       if (!ret)
+               return -EBUSY;
+
+       INIT_COMPLETION(lradc->completion);
+
+       /*
+        * No buffered operation in progress, map the channel and trigger it.
+        * Virtual channel 0 is always used here as the others are always not
+        * used if doing raw sampling.
+        */
+       writel(LRADC_CTRL1_LRADC_IRQ_EN_MASK,
+               lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+       writel(0xff, lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR);
+
+       writel(chan->channel, lradc->base + LRADC_CTRL4);
+       writel(0, lradc->base + LRADC_CH(0));
+
+       /* Enable the IRQ and start sampling the channel. */
+       writel(LRADC_CTRL1_LRADC_IRQ_EN(0),
+               lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_SET);
+       writel(1 << 0, lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET);
+
+       /* Wait for completion on the channel, 1 second max. */
+       ret = wait_for_completion_killable_timeout(&lradc->completion, HZ);
+       if (!ret)
+               ret = -ETIMEDOUT;
+       if (ret < 0)
+               goto err;
+
+       /* Read the data. */
+       *val = readl(lradc->base + LRADC_CH(0)) & LRADC_CH_VALUE_MASK;
+       ret = IIO_VAL_INT;
+
+err:
+       writel(LRADC_CTRL1_LRADC_IRQ_EN(0),
+               lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+
+       mutex_unlock(&lradc->lock);
+
+       return ret;
+}
+
+static const struct iio_info mxs_lradc_iio_info = {
+       .driver_module          = THIS_MODULE,
+       .read_raw               = mxs_lradc_read_raw,
+};
+
+/*
+ * IRQ Handling
+ */
+static irqreturn_t mxs_lradc_handle_irq(int irq, void *data)
+{
+       struct iio_dev *iio = data;
+       struct mxs_lradc *lradc = iio_priv(iio);
+       unsigned long reg = readl(lradc->base + LRADC_CTRL1);
+
+       if (!(reg & LRADC_CTRL1_LRADC_IRQ_MASK))
+               return IRQ_NONE;
+
+       /*
+        * Touchscreen IRQ handling code shall probably have priority
+        * and therefore shall be placed here.
+        */
+
+       if (iio_buffer_enabled(iio))
+               iio_trigger_poll(iio->trig, iio_get_time_ns());
+       else if (reg & LRADC_CTRL1_LRADC_IRQ(0))
+               complete(&lradc->completion);
+
+       writel(reg & LRADC_CTRL1_LRADC_IRQ_MASK,
+               lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * Trigger handling
+ */
+static irqreturn_t mxs_lradc_trigger_handler(int irq, void *p)
+{
+       struct iio_poll_func *pf = p;
+       struct iio_dev *iio = pf->indio_dev;
+       struct mxs_lradc *lradc = iio_priv(iio);
+       struct iio_buffer *buffer = iio->buffer;
+       const uint32_t chan_value = LRADC_CH_ACCUMULATE |
+               ((LRADC_DELAY_TIMER_LOOP - 1) << LRADC_CH_NUM_SAMPLES_OFFSET);
+       int i, j = 0;
+
+       for_each_set_bit(i, iio->active_scan_mask, iio->masklength) {
+               lradc->buffer[j] = readl(lradc->base + LRADC_CH(j));
+               writel(chan_value, lradc->base + LRADC_CH(j));
+               lradc->buffer[j] &= LRADC_CH_VALUE_MASK;
+               lradc->buffer[j] /= LRADC_DELAY_TIMER_LOOP;
+               j++;
+       }
+
+       if (iio->scan_timestamp) {
+               s64 *timestamp = (s64 *)((u8 *)lradc->buffer +
+                                       ALIGN(j, sizeof(s64)));
+               *timestamp = pf->timestamp;
+       }
+
+       iio_push_to_buffer(buffer, (u8 *)lradc->buffer, pf->timestamp);
+
+       iio_trigger_notify_done(iio->trig);
+
+       return IRQ_HANDLED;
+}
+
+static int mxs_lradc_configure_trigger(struct iio_trigger *trig, bool state)
+{
+       struct iio_dev *iio = trig->private_data;
+       struct mxs_lradc *lradc = iio_priv(iio);
+       const uint32_t st = state ? STMP_OFFSET_REG_SET : STMP_OFFSET_REG_CLR;
+
+       writel(LRADC_DELAY_KICK, lradc->base + LRADC_DELAY(0) + st);
+
+       return 0;
+}
+
+static const struct iio_trigger_ops mxs_lradc_trigger_ops = {
+       .owner = THIS_MODULE,
+       .set_trigger_state = &mxs_lradc_configure_trigger,
+};
+
+static int mxs_lradc_trigger_init(struct iio_dev *iio)
+{
+       int ret;
+       struct iio_trigger *trig;
+
+       trig = iio_trigger_alloc("%s-dev%i", iio->name, iio->id);
+       if (trig == NULL)
+               return -ENOMEM;
+
+       trig->dev.parent = iio->dev.parent;
+       trig->private_data = iio;
+       trig->ops = &mxs_lradc_trigger_ops;
+
+       ret = iio_trigger_register(trig);
+       if (ret) {
+               iio_trigger_free(trig);
+               return ret;
+       }
+
+       iio->trig = trig;
+
+       return 0;
+}
+
+static void mxs_lradc_trigger_remove(struct iio_dev *iio)
+{
+       iio_trigger_unregister(iio->trig);
+       iio_trigger_free(iio->trig);
+}
+
+static int mxs_lradc_buffer_preenable(struct iio_dev *iio)
+{
+       struct mxs_lradc *lradc = iio_priv(iio);
+       struct iio_buffer *buffer = iio->buffer;
+       int ret = 0, chan, ofs = 0, enable = 0;
+       uint32_t ctrl4 = 0;
+       uint32_t ctrl1_irq = 0;
+       const uint32_t chan_value = LRADC_CH_ACCUMULATE |
+               ((LRADC_DELAY_TIMER_LOOP - 1) << LRADC_CH_NUM_SAMPLES_OFFSET);
+       const int len = bitmap_weight(buffer->scan_mask, LRADC_MAX_TOTAL_CHANS);
+
+       if (!len)
+               return -EINVAL;
+
+       /*
+        * Lock the driver so raw access can not be done during buffered
+        * operation. This simplifies the code a lot.
+        */
+       ret = mutex_trylock(&lradc->lock);
+       if (!ret)
+               return -EBUSY;
+
+       lradc->buffer = kmalloc(len * sizeof(*lradc->buffer), GFP_KERNEL);
+       if (!lradc->buffer) {
+               ret = -ENOMEM;
+               goto err_mem;
+       }
+
+       ret = iio_sw_buffer_preenable(iio);
+       if (ret < 0)
+               goto err_buf;
+
+       writel(LRADC_CTRL1_LRADC_IRQ_EN_MASK,
+               lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+       writel(0xff, lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR);
+
+       for_each_set_bit(chan, buffer->scan_mask, LRADC_MAX_TOTAL_CHANS) {
+               ctrl4 |= chan << LRADC_CTRL4_LRADCSELECT_OFFSET(ofs);
+               ctrl1_irq |= LRADC_CTRL1_LRADC_IRQ_EN(ofs);
+               writel(chan_value, lradc->base + LRADC_CH(ofs));
+               enable |= 1 << ofs;
+               ofs++;
+       };
+
+       writel(LRADC_DELAY_TRIGGER_LRADCS_MASK | LRADC_DELAY_KICK,
+               lradc->base + LRADC_DELAY(0) + STMP_OFFSET_REG_CLR);
+
+       writel(ctrl4, lradc->base + LRADC_CTRL4);
+       writel(ctrl1_irq, lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_SET);
+
+       writel(enable << LRADC_DELAY_TRIGGER_LRADCS_OFFSET,
+               lradc->base + LRADC_DELAY(0) + STMP_OFFSET_REG_SET);
+
+       return 0;
+
+err_buf:
+       kfree(lradc->buffer);
+err_mem:
+       mutex_unlock(&lradc->lock);
+       return ret;
+}
+
+static int mxs_lradc_buffer_postdisable(struct iio_dev *iio)
+{
+       struct mxs_lradc *lradc = iio_priv(iio);
+
+       writel(LRADC_DELAY_TRIGGER_LRADCS_MASK | LRADC_DELAY_KICK,
+               lradc->base + LRADC_DELAY(0) + STMP_OFFSET_REG_CLR);
+
+       writel(0xff, lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR);
+       writel(LRADC_CTRL1_LRADC_IRQ_EN_MASK,
+               lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+
+       kfree(lradc->buffer);
+       mutex_unlock(&lradc->lock);
+
+       return 0;
+}
+
+static bool mxs_lradc_validate_scan_mask(struct iio_dev *iio,
+                                       const unsigned long *mask)
+{
+       const int mw = bitmap_weight(mask, iio->masklength);
+
+       return mw <= LRADC_MAX_MAPPED_CHANS;
+}
+
+static const struct iio_buffer_setup_ops mxs_lradc_buffer_ops = {
+       .preenable = &mxs_lradc_buffer_preenable,
+       .postenable = &iio_triggered_buffer_postenable,
+       .predisable = &iio_triggered_buffer_predisable,
+       .postdisable = &mxs_lradc_buffer_postdisable,
+       .validate_scan_mask = &mxs_lradc_validate_scan_mask,
+};
+
+/*
+ * Driver initialization
+ */
+
+#define MXS_ADC_CHAN(idx, chan_type) {                         \
+       .type = (chan_type),                                    \
+       .indexed = 1,                                           \
+       .scan_index = (idx),                                    \
+       .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,            \
+       .channel = (idx),                                       \
+       .scan_type = {                                          \
+               .sign = 'u',                                    \
+               .realbits = 18,                                 \
+               .storagebits = 32,                              \
+       },                                                      \
+}
+
+static const struct iio_chan_spec mxs_lradc_chan_spec[] = {
+       MXS_ADC_CHAN(0, IIO_VOLTAGE),
+       MXS_ADC_CHAN(1, IIO_VOLTAGE),
+       MXS_ADC_CHAN(2, IIO_VOLTAGE),
+       MXS_ADC_CHAN(3, IIO_VOLTAGE),
+       MXS_ADC_CHAN(4, IIO_VOLTAGE),
+       MXS_ADC_CHAN(5, IIO_VOLTAGE),
+       MXS_ADC_CHAN(6, IIO_VOLTAGE),
+       MXS_ADC_CHAN(7, IIO_VOLTAGE),   /* VBATT */
+       MXS_ADC_CHAN(8, IIO_TEMP),      /* Temp sense 0 */
+       MXS_ADC_CHAN(9, IIO_TEMP),      /* Temp sense 1 */
+       MXS_ADC_CHAN(10, IIO_VOLTAGE),  /* VDDIO */
+       MXS_ADC_CHAN(11, IIO_VOLTAGE),  /* VTH */
+       MXS_ADC_CHAN(12, IIO_VOLTAGE),  /* VDDA */
+       MXS_ADC_CHAN(13, IIO_VOLTAGE),  /* VDDD */
+       MXS_ADC_CHAN(14, IIO_VOLTAGE),  /* VBG */
+       MXS_ADC_CHAN(15, IIO_VOLTAGE),  /* VDD5V */
+};
+
+static void mxs_lradc_hw_init(struct mxs_lradc *lradc)
+{
+       int i;
+       const uint32_t cfg =
+               (LRADC_DELAY_TIMER_PER << LRADC_DELAY_DELAY_OFFSET);
+
+       stmp_reset_block(lradc->base);
+
+       for (i = 0; i < LRADC_MAX_DELAY_CHANS; i++)
+               writel(cfg | (1 << (LRADC_DELAY_TRIGGER_DELAYS_OFFSET + i)),
+                       lradc->base + LRADC_DELAY(i));
+
+       /* Start internal temperature sensing. */
+       writel(0, lradc->base + LRADC_CTRL2);
+}
+
+static void mxs_lradc_hw_stop(struct mxs_lradc *lradc)
+{
+       int i;
+
+       writel(LRADC_CTRL1_LRADC_IRQ_EN_MASK,
+               lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR);
+
+       for (i = 0; i < LRADC_MAX_DELAY_CHANS; i++)
+               writel(0, lradc->base + LRADC_DELAY(i));
+}
+
+static int __devinit mxs_lradc_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct mxs_lradc *lradc;
+       struct iio_dev *iio;
+       struct resource *iores;
+       int ret = 0;
+       int i;
+
+       /* Allocate the IIO device. */
+       iio = iio_device_alloc(sizeof(*lradc));
+       if (!iio) {
+               dev_err(dev, "Failed to allocate IIO device\n");
+               return -ENOMEM;
+       }
+
+       lradc = iio_priv(iio);
+
+       /* Grab the memory area */
+       iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       lradc->dev = &pdev->dev;
+       lradc->base = devm_request_and_ioremap(dev, iores);
+       if (!lradc->base) {
+               ret = -EADDRNOTAVAIL;
+               goto err_addr;
+       }
+
+       /* Grab all IRQ sources */
+       for (i = 0; i < 13; i++) {
+               lradc->irq[i] = platform_get_irq(pdev, i);
+               if (lradc->irq[i] < 0) {
+                       ret = -EINVAL;
+                       goto err_addr;
+               }
+
+               ret = devm_request_irq(dev, lradc->irq[i],
+                                       mxs_lradc_handle_irq, 0,
+                                       mxs_lradc_irq_name[i], iio);
+               if (ret)
+                       goto err_addr;
+       }
+
+       platform_set_drvdata(pdev, iio);
+
+       init_completion(&lradc->completion);
+       mutex_init(&lradc->lock);
+
+       iio->name = pdev->name;
+       iio->dev.parent = &pdev->dev;
+       iio->info = &mxs_lradc_iio_info;
+       iio->modes = INDIO_DIRECT_MODE;
+       iio->channels = mxs_lradc_chan_spec;
+       iio->num_channels = ARRAY_SIZE(mxs_lradc_chan_spec);
+
+       ret = iio_triggered_buffer_setup(iio, &iio_pollfunc_store_time,
+                               &mxs_lradc_trigger_handler,
+                               &mxs_lradc_buffer_ops);
+       if (ret)
+               goto err_addr;
+
+       ret = mxs_lradc_trigger_init(iio);
+       if (ret)
+               goto err_trig;
+
+       /* Register IIO device. */
+       ret = iio_device_register(iio);
+       if (ret) {
+               dev_err(dev, "Failed to register IIO device\n");
+               goto err_dev;
+       }
+
+       /* Configure the hardware. */
+       mxs_lradc_hw_init(lradc);
+
+       return 0;
+
+err_dev:
+       mxs_lradc_trigger_remove(iio);
+err_trig:
+       iio_triggered_buffer_cleanup(iio);
+err_addr:
+       iio_device_free(iio);
+       return ret;
+}
+
+static int __devexit mxs_lradc_remove(struct platform_device *pdev)
+{
+       struct iio_dev *iio = platform_get_drvdata(pdev);
+       struct mxs_lradc *lradc = iio_priv(iio);
+
+       mxs_lradc_hw_stop(lradc);
+
+       iio_device_unregister(iio);
+       iio_triggered_buffer_cleanup(iio);
+       mxs_lradc_trigger_remove(iio);
+       iio_device_free(iio);
+
+       return 0;
+}
+
+static const struct of_device_id mxs_lradc_dt_ids[] = {
+       { .compatible = "fsl,imx28-lradc", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mxs_lradc_dt_ids);
+
+static struct platform_driver mxs_lradc_driver = {
+       .driver = {
+               .name   = DRIVER_NAME,
+               .owner  = THIS_MODULE,
+               .of_match_table = mxs_lradc_dt_ids,
+       },
+       .probe  = mxs_lradc_probe,
+       .remove = __devexit_p(mxs_lradc_remove),
+};
+
+module_platform_driver(mxs_lradc_driver);
+
+MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
+MODULE_DESCRIPTION("Freescale i.MX28 LRADC driver");
+MODULE_LICENSE("GPL v2");
index 64d630e6fe293a2e8e38cca6e6bf5c68e2552d0a..675c427c02ade52528676a3a9546347dd03da0b9 100644 (file)
@@ -189,7 +189,7 @@ static int spear_read_raw(struct iio_dev *indio_dev,
        },                                              \
 }
 
-static struct iio_chan_spec spear_adc_iio_channels[] = {
+static const struct iio_chan_spec spear_adc_iio_channels[] = {
        SPEAR_ADC_CHAN(0),
        SPEAR_ADC_CHAN(1),
        SPEAR_ADC_CHAN(2),
index 27d27ec9521fed522e628df2c7c4f31c6933e408..4bb017acbf41c214f19e79dcf55949ddcfe55c8d 100644 (file)
@@ -215,17 +215,7 @@ static struct platform_driver __refdata iio_hwmon_driver = {
        .remove = __devexit_p(iio_hwmon_remove),
 };
 
-static int iio_inkern_init(void)
-{
-       return platform_driver_register(&iio_hwmon_driver);
-}
-module_init(iio_inkern_init);
-
-static void iio_inkern_exit(void)
-{
-       platform_driver_unregister(&iio_hwmon_driver);
-}
-module_exit(iio_inkern_exit);
+module_platform_driver(iio_hwmon_driver);
 
 MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>");
 MODULE_DESCRIPTION("IIO to hwmon driver");
index 155a49a9da7e007a353f0c3ec1704f526a1e6b46..22eea8305ff2adc0cdb2894020e2cc8fcef1f250 100644 (file)
@@ -63,7 +63,7 @@ static const struct iio_dummy_accel_calibscale dummy_scales[] = {
  * This array of structures tells the IIO core about what the device
  * actually provides for a given channel.
  */
-static struct iio_chan_spec iio_dummy_channels[] = {
+static const struct iio_chan_spec iio_dummy_channels[] = {
        /* indexed ADC channel in_voltage0_raw etc */
        {
                .type = IIO_VOLTAGE,
index a8e51bc04439adc78ba87ea2160418f509e37b3d..e239ea91f407186c77811a5b71d8c2d0b486545e 100644 (file)
@@ -108,7 +108,7 @@ static struct ad5933_platform_data ad5933_default_pdata  = {
        .vref_mv = 3300,
 };
 
-static struct iio_chan_spec ad5933_channels[] = {
+static const struct iio_chan_spec ad5933_channels[] = {
        {
                .type = IIO_TEMP,
                .indexed = 1,
index 1f4c17779b5a64e18f48865aa6ecb0e6d49387f4..4ce9e3dbe87c4e9253e38c9be11ef9f0b8e3fbae 100644 (file)
@@ -610,7 +610,7 @@ static int adis16400_read_raw(struct iio_dev *indio_dev,
        }
 }
 
-static struct iio_chan_spec adis16400_channels[] = {
+static const struct iio_chan_spec adis16400_channels[] = {
        {
                .type = IIO_VOLTAGE,
                .indexed = 1,
@@ -740,7 +740,7 @@ static struct iio_chan_spec adis16400_channels[] = {
        IIO_CHAN_SOFT_TIMESTAMP(12)
 };
 
-static struct iio_chan_spec adis16350_channels[] = {
+static const struct iio_chan_spec adis16350_channels[] = {
        {
                .type = IIO_VOLTAGE,
                .indexed = 1,
@@ -865,7 +865,7 @@ static struct iio_chan_spec adis16350_channels[] = {
        IIO_CHAN_SOFT_TIMESTAMP(11)
 };
 
-static struct iio_chan_spec adis16300_channels[] = {
+static const struct iio_chan_spec adis16300_channels[] = {
        {
                .type = IIO_VOLTAGE,
                .indexed = 1,
index ec202b4ecfb2f0e69644dd391ef9a0409b33f342..1e11ad5ae5a462c47b13bfb8739bd5d05605297a 100644 (file)
@@ -122,7 +122,7 @@ struct ade7758_state {
        u8                      *tx;
        u8                      *rx;
        struct mutex            buf_lock;
-       struct iio_chan_spec    *ade7758_ring_channels;
+       const struct iio_chan_spec *ade7758_ring_channels;
        struct spi_transfer     ring_xfer[4];
        struct spi_message      ring_msg;
        /*
index 7014a0078446a95835047e9f19bf8dc53c91db60..6d3725a1cd78b92f34b23e9a026b13abc3ae53ca 100644 (file)
@@ -661,7 +661,7 @@ static const struct attribute_group ade7758_attribute_group = {
        .attrs = ade7758_attributes,
 };
 
-static struct iio_chan_spec ade7758_channels[] = {
+static const struct iio_chan_spec ade7758_channels[] = {
        {
                .type = IIO_VOLTAGE,
                .indexed = 1,
index f313859476c188af4deea1f70c203daaaa3b4d52..4ba4d05ed4233a7ddebc70f62c7e6f0040e3941e 100644 (file)
@@ -575,7 +575,7 @@ static IIO_DEVICE_ATTR(lot_low_thrd, S_IRUGO | S_IWUSR,
                       AD2S1210_REG_LOT_LOW_THRD);
 
 
-static struct iio_chan_spec ad2s1210_channels[] = {
+static const struct iio_chan_spec ad2s1210_channels[] = {
        {
                .type = IIO_ANGL,
                .indexed = 1,
index 2b83fa8e550a6951684b99dd727ff9f3e731e8a7..5831af8f1e8c2745f11b944a992145a5268ae271 100644 (file)
@@ -24,28 +24,20 @@ static int control_reg[] = {
        TPCI200_CONTROL_D_REG
 };
 
-/* Linked list to save the registered devices */
-static LIST_HEAD(tpci200_list);
-
 static int tpci200_slot_unregister(struct ipack_device *dev);
 
 static struct tpci200_board *check_slot(struct ipack_device *dev)
 {
        struct tpci200_board *tpci200;
-       int found = 0;
 
        if (dev == NULL)
                return NULL;
 
-       list_for_each_entry(tpci200, &tpci200_list, list) {
-               if (tpci200->number == dev->bus_nr) {
-                       found = 1;
-                       break;
-               }
-       }
 
-       if (!found) {
-               dev_err(&dev->dev, "Carrier not found\n");
+       tpci200 = dev_get_drvdata(dev->bus->parent);
+
+       if (tpci200 == NULL) {
+               dev_info(&dev->dev, "carrier board not found\n");
                return NULL;
        }
 
@@ -398,15 +390,15 @@ static int tpci200_register(struct tpci200_board *tpci200)
 
        /* Map internal tpci200 driver user space */
        tpci200->info->interface_regs =
-               ioremap(pci_resource_start(tpci200->info->pdev,
+               ioremap_nocache(pci_resource_start(tpci200->info->pdev,
                                           TPCI200_IP_INTERFACE_BAR),
                        TPCI200_IFACE_SIZE);
        tpci200->info->ioidint_space =
-               ioremap(pci_resource_start(tpci200->info->pdev,
+               ioremap_nocache(pci_resource_start(tpci200->info->pdev,
                                           TPCI200_IO_ID_INT_SPACES_BAR),
                        TPCI200_IOIDINT_SIZE);
        tpci200->info->mem8_space =
-               ioremap(pci_resource_start(tpci200->info->pdev,
+               ioremap_nocache(pci_resource_start(tpci200->info->pdev,
                                           TPCI200_MEM8_SPACE_BAR),
                        TPCI200_MEM8_SIZE);
 
@@ -604,8 +596,8 @@ static int tpci200_slot_unregister(struct ipack_device *dev)
        if (mutex_lock_interruptible(&tpci200->mutex))
                return -ERESTARTSYS;
 
-       ipack_device_unregister(dev);
        tpci200->slots[dev->slot].dev = NULL;
+       ipack_device_unregister(dev);
        mutex_unlock(&tpci200->mutex);
 
        return 0;
@@ -685,7 +677,7 @@ static int tpci200_slot_map_space(struct ipack_device *dev,
 
        virt_addr_space->size = size_to_map;
        virt_addr_space->address =
-               ioremap((unsigned long)phys_address, size_to_map);
+               ioremap_nocache((unsigned long)phys_address, size_to_map);
 
 out_unlock:
        mutex_unlock(&tpci200->mutex);
@@ -831,8 +823,6 @@ static int tpci200_pciprobe(struct pci_dev *pdev,
        /* save the bus number given by ipack to logging purpose */
        tpci200->number = tpci200->info->ipack_bus->bus_nr;
        dev_set_drvdata(&pdev->dev, tpci200);
-       /* add the registered device in an internal linked list */
-       list_add_tail(&tpci200->list, &tpci200_list);
 
        /*
         * Give the same IRQ number as the slot number.
@@ -847,7 +837,6 @@ static int tpci200_pciprobe(struct pci_dev *pdev,
 static void __tpci200_pci_remove(struct tpci200_board *tpci200)
 {
        tpci200_uninstall(tpci200);
-       list_del(&tpci200->list);
        ipack_bus_unregister(tpci200->info->ipack_bus);
        kfree(tpci200->info);
        kfree(tpci200);
@@ -855,15 +844,9 @@ static void __tpci200_pci_remove(struct tpci200_board *tpci200)
 
 static void __devexit tpci200_pci_remove(struct pci_dev *dev)
 {
-       struct tpci200_board *tpci200, *next;
+       struct tpci200_board *tpci200 = pci_get_drvdata(dev);
 
-       /* Search the registered device to uninstall it */
-       list_for_each_entry_safe(tpci200, next, &tpci200_list, list) {
-               if (tpci200->info->pdev == dev) {
-                       __tpci200_pci_remove(tpci200);
-                       break;
-               }
-       }
+       __tpci200_pci_remove(tpci200);
 }
 
 static DEFINE_PCI_DEVICE_TABLE(tpci200_idtable) = {
@@ -888,11 +871,6 @@ static int __init tpci200_drvr_init_module(void)
 
 static void __exit tpci200_drvr_exit_module(void)
 {
-       struct tpci200_board *tpci200, *next;
-
-       list_for_each_entry_safe(tpci200, next, &tpci200_list, list)
-               __tpci200_pci_remove(tpci200);
-
        pci_unregister_driver(&tpci200_pci_drv);
 }
 
index fd0e30132ca247565dc05993ed79749100cd9d6a..a68d981c259fe6eb517d85df0667f7d9cad7c96a 100644 (file)
@@ -502,7 +502,7 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr,
                ipoctal->pointer_read[i] = 0;
                ipoctal->pointer_write[i] = 0;
                ipoctal->nb_bytes[i] = 0;
-               tty_register_device(tty, i, NULL);
+               tty_port_register_device(&ipoctal->tty_port[i], tty, i, NULL);
 
                /*
                 * Enable again the RX. TX will be enabled when
@@ -617,7 +617,7 @@ static void ipoctal_set_termios(struct tty_struct *tty,
        struct ipoctal *ipoctal = tty->driver_data;
        speed_t baud;
 
-       cflag = tty->termios->c_cflag;
+       cflag = tty->termios.c_cflag;
 
        /* Disable and reset everything before change the setup */
        ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.cr,
@@ -643,7 +643,7 @@ static void ipoctal_set_termios(struct tty_struct *tty,
        default:
                mr1 |= MR1_CHRL_8_BITS;
                /* By default, select CS8 */
-               tty->termios->c_cflag = (cflag & ~CSIZE) | CS8;
+               tty->termios.c_cflag = (cflag & ~CSIZE) | CS8;
                break;
        }
 
@@ -657,7 +657,7 @@ static void ipoctal_set_termios(struct tty_struct *tty,
                mr1 |= MR1_PARITY_OFF;
 
        /* Mark or space parity is not supported */
-       tty->termios->c_cflag &= ~CMSPAR;
+       tty->termios.c_cflag &= ~CMSPAR;
 
        /* Set stop bits */
        if (cflag & CSTOPB)
@@ -690,10 +690,10 @@ static void ipoctal_set_termios(struct tty_struct *tty,
        }
 
        baud = tty_get_baud_rate(tty);
-       tty_termios_encode_baud_rate(tty->termios, baud, baud);
+       tty_termios_encode_baud_rate(&tty->termios, baud, baud);
 
        /* Set baud rate */
-       switch (tty->termios->c_ospeed) {
+       switch (baud) {
        case 75:
                csr |= TX_CLK_75 | RX_CLK_75;
                break;
@@ -734,7 +734,7 @@ static void ipoctal_set_termios(struct tty_struct *tty,
        default:
                csr |= TX_CLK_38400 | RX_CLK_38400;
                /* In case of default, we establish 38400 bps */
-               tty_termios_encode_baud_rate(tty->termios, 38400, 38400);
+               tty_termios_encode_baud_rate(&tty->termios, 38400, 38400);
                break;
        }
 
index 5e319e3ce68541b6c077578a0d6963ba323e1433..7fe44a6fd0eda32630e230fe82dde2dcf098f328 100644 (file)
@@ -48,7 +48,13 @@ static ssize_t pcm_set_impulse_volume(struct device *dev,
                                      const char *buf, size_t count)
 {
        struct snd_line6_pcm *line6pcm = dev2pcm(dev);
-       int value = simple_strtoul(buf, NULL, 10);
+       int value;
+       int rv;
+
+       rv = kstrtoint(buf, 10, &value);
+       if (rv < 0)
+               return rv;
+
        line6pcm->impulse_volume = value;
 
        if (value > 0)
index bb99ee4919e7e7af0c95d8ff0a8090de5f13615f..f97416b1de5459e8054fcc644245f4a192147d6c 100644 (file)
@@ -353,10 +353,10 @@ static ssize_t variax_set_model(struct device *dev,
 {
        struct usb_line6_variax *variax =
            usb_get_intfdata(to_usb_interface(dev));
-       unsigned long value;
+       u8 value;
        int ret;
 
-       ret = strict_strtoul(buf, 10, &value);
+       ret = kstrtou8(buf, 10, &value);
        if (ret)
                return ret;
 
@@ -387,10 +387,10 @@ static ssize_t variax_set_active(struct device *dev,
 {
        struct usb_line6_variax *variax =
            usb_get_intfdata(to_usb_interface(dev));
-       unsigned long value;
+       u8 value;
        int ret;
 
-       ret = strict_strtoul(buf, 10, &value);
+       ret = kstrtou8(buf, 10, &value);
        if (ret)
                return ret;
 
index 4f4b7d6281a7c0624b63cbf3ba7d41ca4d4f0070..427218b8b10f435e5f9dcd7dbc3751a572b0566f 100644 (file)
@@ -25,8 +25,6 @@ source "drivers/staging/media/cxd2099/Kconfig"
 
 source "drivers/staging/media/dt3155v4l/Kconfig"
 
-source "drivers/staging/media/easycap/Kconfig"
-
 source "drivers/staging/media/go7007/Kconfig"
 
 source "drivers/staging/media/solo6x10/Kconfig"
index c69124cdb0d3af91d022af72bda59627ef9e2062..aec6eb96394033c156a9731a5503f813c9193393 100644 (file)
@@ -1,6 +1,5 @@
 obj-$(CONFIG_DVB_AS102)                += as102/
 obj-$(CONFIG_DVB_CXD2099)      += cxd2099/
-obj-$(CONFIG_EASYCAP)          += easycap/
 obj-$(CONFIG_LIRC_STAGING)     += lirc/
 obj-$(CONFIG_SOLO6X10)         += solo6x10/
 obj-$(CONFIG_VIDEO_DT3155)     += dt3155v4l/
index 1c04185bcfd72d95bfe08a2b426fb9e1c1aaef6e..0ff19724992fbe5de688620d22a4396ea0f381ef 100644 (file)
@@ -683,27 +683,26 @@ struct dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg,
                                      void *priv,
                                      struct i2c_adapter *i2c)
 {
-       struct cxd *ci = 0;
+       struct cxd *ci;
        u8 val;
 
        if (i2c_read_reg(i2c, cfg->adr, 0, &val) < 0) {
                printk(KERN_INFO "No CXD2099 detected at %02x\n", cfg->adr);
-               return 0;
+               return NULL;
        }
 
-       ci = kmalloc(sizeof(struct cxd), GFP_KERNEL);
+       ci = kzalloc(sizeof(struct cxd), GFP_KERNEL);
        if (!ci)
-               return 0;
-       memset(ci, 0, sizeof(*ci));
+               return NULL;
 
        mutex_init(&ci->lock);
-       memcpy(&ci->cfg, cfg, sizeof(struct cxd2099_cfg));
+       ci->cfg = *cfg;
        ci->i2c = i2c;
        ci->lastaddress = 0xff;
        ci->clk_reg_b = 0x4a;
        ci->clk_reg_f = 0x1b;
 
-       memcpy(&ci->en, &en_templ, sizeof(en_templ));
+       ci->en = en_templ;
        ci->en.data = ci;
        init(ci);
        printk(KERN_INFO "Attached CXD2099AR at %02x\n", ci->cfg.adr);
index ebe5a27c06f5b97219f3f306f9f6d16744b402e4..2e7b711c850135053c14a1ff3291ba9d8bac8649 100644 (file)
@@ -381,6 +381,8 @@ dt3155_open(struct file *filp)
        int ret = 0;
        struct dt3155_priv *pd = video_drvdata(filp);
 
+       if (mutex_lock_interruptible(&pd->mux))
+               return -ERESTARTSYS;
        if (!pd->users) {
                pd->q = kzalloc(sizeof(*pd->q), GFP_KERNEL);
                if (!pd->q) {
@@ -411,6 +413,7 @@ err_request_irq:
        kfree(pd->q);
        pd->q = NULL;
 err_alloc_queue:
+       mutex_unlock(&pd->mux);
        return ret;
 }
 
@@ -419,6 +422,7 @@ dt3155_release(struct file *filp)
 {
        struct dt3155_priv *pd = video_drvdata(filp);
 
+       mutex_lock(&pd->mux);
        pd->users--;
        BUG_ON(pd->users < 0);
        if (!pd->users) {
@@ -429,6 +433,7 @@ dt3155_release(struct file *filp)
                kfree(pd->q);
                pd->q = NULL;
        }
+       mutex_unlock(&pd->mux);
        return 0;
 }
 
@@ -436,24 +441,38 @@ static ssize_t
 dt3155_read(struct file *filp, char __user *user, size_t size, loff_t *loff)
 {
        struct dt3155_priv *pd = video_drvdata(filp);
+       ssize_t res;
 
-       return vb2_read(pd->q, user, size, loff, filp->f_flags & O_NONBLOCK);
+       if (mutex_lock_interruptible(&pd->mux))
+               return -ERESTARTSYS;
+       res = vb2_read(pd->q, user, size, loff, filp->f_flags & O_NONBLOCK);
+       mutex_unlock(&pd->mux);
+       return res;
 }
 
 static unsigned int
 dt3155_poll(struct file *filp, struct poll_table_struct *polltbl)
 {
        struct dt3155_priv *pd = video_drvdata(filp);
+       unsigned int res;
 
-       return vb2_poll(pd->q, filp, polltbl);
+       mutex_lock(&pd->mux);
+       res = vb2_poll(pd->q, filp, polltbl);
+       mutex_unlock(&pd->mux);
+       return res;
 }
 
 static int
 dt3155_mmap(struct file *filp, struct vm_area_struct *vma)
 {
        struct dt3155_priv *pd = video_drvdata(filp);
+       int res;
 
-       return vb2_mmap(pd->q, vma);
+       if (mutex_lock_interruptible(&pd->mux))
+               return -ERESTARTSYS;
+       res = vb2_mmap(pd->q, vma);
+       mutex_unlock(&pd->mux);
+       return res;
 }
 
 static const struct v4l2_file_operations dt3155_fops = {
@@ -898,10 +917,6 @@ dt3155_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        INIT_LIST_HEAD(&pd->dmaq);
        mutex_init(&pd->mux);
        pd->vdev->lock = &pd->mux; /* for locking v4l2_file_operations */
-       /* Locking in file operations other than ioctl should be done
-          by the driver, not the V4L2 core.
-          This driver needs auditing so that this flag can be removed. */
-       set_bit(V4L2_FL_LOCK_ALL_FOPS, &pd->vdev->flags);
        spin_lock_init(&pd->lock);
        pd->csr2 = csr2_init;
        pd->config = config_init;
diff --git a/drivers/staging/media/easycap/Kconfig b/drivers/staging/media/easycap/Kconfig
deleted file mode 100644 (file)
index a425a6f..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-config EASYCAP
-       tristate "EasyCAP USB ID 05e1:0408 support"
-       depends on USB && VIDEO_DEV && SND
-       select SND_PCM
-
-       ---help---
-         This is an integrated audio/video driver for EasyCAP cards with
-         USB ID 05e1:0408.  It supports two hardware variants:
-
-         *  EasyCAP USB 2.0 Video Adapter with Audio, Model DC60,
-            having input cables labelled CVBS, S-VIDEO, AUDIO(L), AUDIO(R)
-
-         *  EasyCAP002 4-Channel USB 2.0 DVR, having input cables labelled
-            1, 2, 3, 4 and an unlabelled input cable for a microphone.
-
-         To compile this driver as a module, choose M here: the
-         module will be called easycap
-
-config EASYCAP_DEBUG
-       bool "Enable EasyCAP driver debugging"
-       depends on EASYCAP
-
-       ---help---
-         This option enables debug printouts
-
-         To enable debug, pass the debug level to the debug module
-          parameter:
-
-          modprobe easycap debug=[0..9]
-
diff --git a/drivers/staging/media/easycap/Makefile b/drivers/staging/media/easycap/Makefile
deleted file mode 100644 (file)
index a34e75f..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-easycap-objs := easycap_main.o
-easycap-objs += easycap_low.o
-easycap-objs += easycap_ioctl.o
-easycap-objs += easycap_settings.o
-easycap-objs += easycap_testcard.o
-easycap-objs += easycap_sound.o
-obj-$(CONFIG_EASYCAP) += easycap.o
-
-ccflags-y := -Wall
-
diff --git a/drivers/staging/media/easycap/README b/drivers/staging/media/easycap/README
deleted file mode 100644 (file)
index 796b032..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-
-        ***********************************************************
-        *   EasyCAP USB 2.0 Video Adapter with Audio, Model DC60  *
-        *                            and                          *
-        *             EasyCAP002 4-Channel USB 2.0 DVR            *
-        ***********************************************************
-                     Mike Thomas  <rmthomas@sciolus.org>
-
-
-
-SUPPORTED HARDWARE
-------------------
-
-This driver is intended for use with hardware having USB ID 05e1:0408.
-Two kinds of EasyCAP have this USB ID, namely:
-
-    *  EasyCAP USB 2.0 Video Adapter with Audio, Model DC60,
-       having input cables labelled CVBS, S-VIDEO, AUDIO(L), AUDIO(R)
-
-    *  EasyCAP002 4-Channel USB 2.0 DVR, having input cables labelled
-       1, 2, 3, 4 and an unlabelled input cable for a microphone.
-
-
-BUILD OPTIONS AND DEPENDENCIES
-------------------------------
-
-Unless EASYCAP_DEBUG is defined during compilation it will not be possible
-to select a debug level at the time of module installation.
-
-
-KNOWN RUNTIME ISSUES
---------------------
-
-(1) Intentionally, this driver will not stream material which is unambiguously
-identified by the hardware as copy-protected.  Normal video output will be
-present for about a minute but will then freeze when this situation arises.
-
-(2) The controls for luminance, contrast, saturation, hue and volume may not
-always work properly.
-
-(3) Reduced-resolution S-Video seems to suffer from moire artefacts.
-
-
-INPUT NUMBERING
----------------
-
-For the EasyCAP with S-VIDEO input cable the driver regards a request for
-inputs numbered 0 or 1 as referring to CVBS and a request for input
-numbered 5 as referring to S-VIDEO.
-
-For the EasyCAP with four CVBS inputs the driver expects to be asked for
-any one of inputs numbered 1,2,3,4.  If input 0 is asked for, it is
-interpreted as input 1.
-
-
-MODULE PARAMETERS
------------------
-
-Three module parameters are defined:
-
-debug      the easycap module is configured at diagnostic level n (0 to 9)
-gain       audio gain level n (0 to 31, default is 16)
-bars       whether to display testcard bars when incoming video signal is lost
-           0 => no, 1 => yes (default)
-
-
-SUPPORTED TV STANDARDS AND RESOLUTIONS
---------------------------------------
-
-The following TV standards are natively supported by the hardware and are
-usable as (for example) the "norm=" parameter in the mplayer command:
-
-    PAL_BGHIN,    NTSC_N_443,
-    PAL_Nc,       NTSC_N,
-    SECAM,        NTSC_M,        NTSC_M_JP,
-    PAL_60,       NTSC_443,
-    PAL_M.
-
-In addition, the driver offers "custom" pseudo-standards with a framerate
-which is 20% of the usual framerate.  These pseudo-standards are named:
-
-    PAL_BGHIN_SLOW,    NTSC_N_443_SLOW,
-    PAL_Nc_SLOW,       NTSC_N_SLOW,
-    SECAM_SLOW,        NTSC_M_SLOW,        NTSC_M_JP_SLOW,
-    PAL_60_SLOW,       NTSC_443_SLOW,
-    PAL_M_SLOW.
-
-
-The available picture sizes are:
-
-     at 25 frames per second:   720x576, 704x576, 640x480, 360x288, 320x240;
-     at 30 frames per second:   720x480, 640x480, 360x240, 320x240.
-
-
-WHAT'S TESTED AND WHAT'S NOT
-----------------------------
-
-This driver is known to work with mplayer, mencoder, tvtime, zoneminder,
-xawtv, gstreamer and sufficiently recent versions of vlc.  An interface
-to ffmpeg is implemented, but serious audio-video synchronization problems
-remain.
-
-The driver is designed to support all the TV standards accepted by the
-hardware, but as yet it has actually been tested on only a few of these.
-
-I have been unable to test and calibrate the S-video input myself because I
-do not possess any equipment with S-video output.
-
-
-UDEV RULES
-----------
-
-In order that the special files /dev/easycap0 and /dev/easysnd1 are created
-with conveniently relaxed permissions when the EasyCAP is plugged in, a file
-is preferably to be provided in directory /etc/udev/rules.d with content:
-
-ACTION!="add|change", GOTO="easycap_rules_end"
-ATTRS{idVendor}=="05e1", ATTRS{idProduct}=="0408", \
-       MODE="0666", OWNER="root", GROUP="root"
-LABEL="easycap_rules_end"
-
-
-MODPROBE CONFIGURATION
-----------------------
-
-The easycap module is in competition with the module snd-usb-audio for the
-EasyCAP's audio channel, and its installation can be aided by providing a
-file in directory /etc/modprobe.d with content:
-
-options easycap  gain=16 bars=1
-install easycap /sbin/rmmod snd-usb-audio; /sbin/modprobe --ignore-install easycap
-
-
-ACKNOWLEGEMENTS AND REFERENCES
-------------------------------
-This driver makes use of information contained in the Syntek Semicon DC-1125
-Driver, presently maintained at http://sourceforge.net/projects/syntekdriver/
-by Nicolas Vivien.  Particularly useful has been a patch to the latter driver
-provided by Ivor Hewitt in January 2009.  The NTSC implementation is taken
-from the work of Ben Trask.
-
diff --git a/drivers/staging/media/easycap/easycap.h b/drivers/staging/media/easycap/easycap.h
deleted file mode 100644 (file)
index a007e74..0000000
+++ /dev/null
@@ -1,567 +0,0 @@
-/*****************************************************************************
-*                                                                            *
-*  easycap.h                                                                 *
-*                                                                            *
-*****************************************************************************/
-/*
- *
- *  Copyright (C) 2010 R.M. Thomas  <rmthomas@sciolus.org>
- *
- *
- *  This 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.
- *
- *  The software 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 software; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
-*/
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- *  THE FOLLOWING PARAMETERS ARE UNDEFINED:
- *
- *                EASYCAP_DEBUG
- *
- *  IF REQUIRED THEY MUST BE EXTERNALLY DEFINED, FOR EXAMPLE AS COMPILER
- *  OPTIONS.
- */
-/*---------------------------------------------------------------------------*/
-
-#ifndef __EASYCAP_H__
-#define __EASYCAP_H__
-
-/*---------------------------------------------------------------------------*/
-/*
- *  THESE ARE NORMALLY DEFINED
- */
-/*---------------------------------------------------------------------------*/
-#define  PATIENCE  500
-#define  PERSEVERE
-/*---------------------------------------------------------------------------*/
-/*
- *  THESE ARE FOR MAINTENANCE ONLY - NORMALLY UNDEFINED:
- */
-/*---------------------------------------------------------------------------*/
-#undef  EASYCAP_TESTCARD
-/*---------------------------------------------------------------------------*/
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/kref.h>
-#include <linux/usb.h>
-#include <linux/uaccess.h>
-
-#include <linux/i2c.h>
-#include <linux/workqueue.h>
-#include <linux/poll.h>
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/types.h>
-
-#include <linux/vmalloc.h>
-#include <linux/sound.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/info.h>
-#include <sound/initval.h>
-#include <sound/control.h>
-#include <media/v4l2-dev.h>
-#include <media/v4l2-device.h>
-#include <linux/videodev2.h>
-#include <linux/soundcard.h>
-
-/*---------------------------------------------------------------------------*/
-/*  VENDOR, PRODUCT:  Syntek Semiconductor Co., Ltd
- *
- *      EITHER        EasyCAP USB 2.0 Video Adapter with Audio, Model No. DC60
- *               with input cabling:  AUDIO(L), AUDIO(R), CVBS, S-VIDEO.
- *
- *          OR        EasyCAP 4CHANNEL USB 2.0 DVR, Model No. EasyCAP002
- *               with input cabling:  MICROPHONE, CVBS1, CVBS2, CVBS3, CVBS4.
- */
-/*---------------------------------------------------------------------------*/
-#define USB_EASYCAP_VENDOR_ID  0x05e1
-#define USB_EASYCAP_PRODUCT_ID 0x0408
-
-#define EASYCAP_DRIVER_VERSION "0.9.01"
-#define EASYCAP_DRIVER_DESCRIPTION "easycapdc60"
-
-#define DONGLE_MANY 8
-#define INPUT_MANY 6
-/*---------------------------------------------------------------------------*/
-/*
- *  DEFAULT LUMINANCE, CONTRAST, SATURATION AND HUE
- */
-/*---------------------------------------------------------------------------*/
-#define SAA_0A_DEFAULT 0x7F
-#define SAA_0B_DEFAULT 0x3F
-#define SAA_0C_DEFAULT 0x2F
-#define SAA_0D_DEFAULT 0x00
-/*---------------------------------------------------------------------------*/
-/*
- *  VIDEO STREAMING PARAMETERS:
- *  USB 2.0 PROVIDES FOR HIGH-BANDWIDTH ENDPOINTS WITH AN UPPER LIMIT
- *  OF 3072 BYTES PER MICROFRAME for wMaxPacketSize.
- */
-/*---------------------------------------------------------------------------*/
-#define VIDEO_ISOC_BUFFER_MANY 16
-#define VIDEO_ISOC_ORDER 3
-#define VIDEO_ISOC_FRAMESPERDESC ((unsigned int) 1 << VIDEO_ISOC_ORDER)
-#define USB_2_0_MAXPACKETSIZE 3072
-#if (USB_2_0_MAXPACKETSIZE > PAGE_SIZE)
-#error video_isoc_buffer[.] will not be big enough
-#endif
-#define VIDEO_JUNK_TOLERATE VIDEO_ISOC_BUFFER_MANY
-#define VIDEO_LOST_TOLERATE 50
-/*---------------------------------------------------------------------------*/
-/*
- *  VIDEO BUFFERS
- */
-/*---------------------------------------------------------------------------*/
-#define FIELD_BUFFER_SIZE (203 * PAGE_SIZE)
-#define FRAME_BUFFER_SIZE (405 * PAGE_SIZE)
-#define FIELD_BUFFER_MANY 4
-#define FRAME_BUFFER_MANY 6
-/*---------------------------------------------------------------------------*/
-/*
- *  AUDIO STREAMING PARAMETERS
- */
-/*---------------------------------------------------------------------------*/
-#define AUDIO_ISOC_BUFFER_MANY 16
-#define AUDIO_ISOC_ORDER 1
-#define AUDIO_ISOC_FRAMESPERDESC 32
-#define AUDIO_ISOC_BUFFER_SIZE (PAGE_SIZE << AUDIO_ISOC_ORDER)
-/*---------------------------------------------------------------------------*/
-/*
- *  AUDIO BUFFERS
- */
-/*---------------------------------------------------------------------------*/
-#define AUDIO_FRAGMENT_MANY 32
-#define PAGES_PER_AUDIO_FRAGMENT 4
-/*---------------------------------------------------------------------------*/
-/*
- *  IT IS ESSENTIAL THAT EVEN-NUMBERED STANDARDS ARE 25 FRAMES PER SECOND,
- *                        ODD-NUMBERED STANDARDS ARE 30 FRAMES PER SECOND.
- *  THE NUMBERING OF STANDARDS MUST NOT BE CHANGED WITHOUT DUE CARE.  NOT
- *  ONLY MUST THE PARAMETER
- *                             STANDARD_MANY
- *  BE CHANGED TO CORRESPOND TO THE NEW NUMBER OF STANDARDS, BUT ALSO THE
- *  NUMBERING MUST REMAIN AN UNBROKEN ASCENDING SEQUENCE:  DUMMY STANDARDS
- *  MAY NEED TO BE ADDED.   APPROPRIATE CHANGES WILL ALWAYS BE REQUIRED IN
- *  ROUTINE fillin_formats() AND POSSIBLY ELSEWHERE.  BEWARE.
- */
-/*---------------------------------------------------------------------------*/
-#define  PAL_BGHIN      0
-#define  PAL_Nc         2
-#define  SECAM          4
-#define  NTSC_N         6
-#define  NTSC_N_443     8
-#define  NTSC_M         1
-#define  NTSC_443       3
-#define  NTSC_M_JP      5
-#define  PAL_60         7
-#define  PAL_M          9
-#define  PAL_BGHIN_SLOW    10
-#define  PAL_Nc_SLOW       12
-#define  SECAM_SLOW        14
-#define  NTSC_N_SLOW       16
-#define  NTSC_N_443_SLOW   18
-#define  NTSC_M_SLOW       11
-#define  NTSC_443_SLOW     13
-#define  NTSC_M_JP_SLOW    15
-#define  PAL_60_SLOW       17
-#define  PAL_M_SLOW        19
-#define  STANDARD_MANY 20
-/*---------------------------------------------------------------------------*/
-/*
- *  ENUMS
- */
-/*---------------------------------------------------------------------------*/
-enum {
-       AT_720x576,
-       AT_704x576,
-       AT_640x480,
-       AT_720x480,
-       AT_360x288,
-       AT_320x240,
-       AT_360x240,
-       RESOLUTION_MANY
-};
-enum {
-       FMT_UYVY,
-       FMT_YUY2,
-       FMT_RGB24,
-       FMT_RGB32,
-       FMT_BGR24,
-       FMT_BGR32,
-       PIXELFORMAT_MANY
-};
-enum {
-       FIELD_NONE,
-       FIELD_INTERLACED,
-       INTERLACE_MANY
-};
-#define SETTINGS_MANY  (STANDARD_MANY * \
-                       RESOLUTION_MANY * \
-                       2 * \
-                       PIXELFORMAT_MANY * \
-                       INTERLACE_MANY)
-/*---------------------------------------------------------------------------*/
-/*
- *  STRUCTURE DEFINITIONS
- */
-/*---------------------------------------------------------------------------*/
-struct easycap_dongle {
-       struct easycap *peasycap;
-       struct mutex mutex_video;
-       struct mutex mutex_audio;
-};
-/*---------------------------------------------------------------------------*/
-struct data_buffer {
-       struct list_head list_head;
-       void *pgo;
-       void *pto;
-       u16 kount;
-       u16 input;
-};
-/*---------------------------------------------------------------------------*/
-struct data_urb {
-       struct list_head list_head;
-       struct urb *purb;
-       int isbuf;
-       int length;
-};
-/*---------------------------------------------------------------------------*/
-struct easycap_standard {
-       u16 mask;
-struct v4l2_standard v4l2_standard;
-};
-struct easycap_format {
-       u16 mask;
-       char name[128];
-struct v4l2_format v4l2_format;
-};
-struct inputset {
-       int input;
-       int input_ok;
-       int standard_offset;
-       int standard_offset_ok;
-       int format_offset;
-       int format_offset_ok;
-       int brightness;
-       int brightness_ok;
-       int contrast;
-       int contrast_ok;
-       int saturation;
-       int saturation_ok;
-       int hue;
-       int hue_ok;
-};
-/*---------------------------------------------------------------------------*/
-/*
- *   easycap.ilk == 0   =>  CVBS+S-VIDEO HARDWARE, AUDIO wMaxPacketSize=256
- *   easycap.ilk == 2   =>  CVBS+S-VIDEO HARDWARE, AUDIO wMaxPacketSize=9
- *   easycap.ilk == 3   =>     FOUR-CVBS HARDWARE, AUDIO wMaxPacketSize=9
- */
-/*---------------------------------------------------------------------------*/
-struct easycap {
-       int isdongle;
-       int minor;
-
-       struct video_device video_device;
-       struct v4l2_device v4l2_device;
-
-       int status;
-       unsigned int audio_pages_per_fragment;
-       unsigned int audio_bytes_per_fragment;
-       unsigned int audio_buffer_page_many;
-
-#define UPSAMPLE
-#ifdef UPSAMPLE
-       s16 oldaudio;
-#endif /*UPSAMPLE*/
-
-       int ilk;
-       bool microphone;
-
-       struct usb_device *pusb_device;
-       struct usb_interface *pusb_interface;
-
-       struct kref kref;
-
-       int queued[FRAME_BUFFER_MANY];
-       int done[FRAME_BUFFER_MANY];
-
-       wait_queue_head_t wq_video;
-       wait_queue_head_t wq_audio;
-       wait_queue_head_t wq_trigger;
-
-       int input;
-       int polled;
-       int standard_offset;
-       int format_offset;
-       struct inputset inputset[INPUT_MANY];
-
-       bool ntsc;
-       int fps;
-       int usec;
-       int tolerate;
-       int skip;
-       int skipped;
-       int lost[INPUT_MANY];
-       int merit[180];
-
-       int    video_interface;
-       int    video_altsetting_on;
-       int    video_altsetting_off;
-       int    video_endpointnumber;
-       int    video_isoc_maxframesize;
-       int    video_isoc_buffer_size;
-       int    video_isoc_framesperdesc;
-
-       int    video_isoc_streaming;
-       int    video_isoc_sequence;
-       int    video_idle;
-       int    video_eof;
-       int    video_junk;
-
-       struct data_buffer video_isoc_buffer[VIDEO_ISOC_BUFFER_MANY];
-       struct data_buffer field_buffer[FIELD_BUFFER_MANY]
-                                       [(FIELD_BUFFER_SIZE/PAGE_SIZE)];
-       struct data_buffer frame_buffer[FRAME_BUFFER_MANY]
-                                       [(FRAME_BUFFER_SIZE/PAGE_SIZE)];
-
-       struct list_head urb_video_head;
-       struct list_head *purb_video_head;
-
-       u8 cache[8];
-       u8 *pcache;
-       int video_mt;
-       int audio_mt;
-       u32 isequence;
-
-       int vma_many;
-/*---------------------------------------------------------------------------*/
-/*
- *  BUFFER INDICATORS
- */
-/*---------------------------------------------------------------------------*/
-       int field_fill; /* Field buffer being filled by easycap_complete().  */
-                       /*   Bumped only by easycap_complete().              */
-       int field_page; /* Page of field buffer page being filled by         */
-                       /*   easycap_complete().                             */
-       int field_read; /* Field buffer to be read by field2frame().         */
-                       /*   Bumped only by easycap_complete().              */
-       int frame_fill; /* Frame buffer being filled by field2frame().       */
-                       /*   Bumped only by easycap_dqbuf() when             */
-                       /*   field2frame() has created a complete frame.     */
-       int frame_read; /* Frame buffer offered to user by DQBUF.            */
-                       /*   Set only by easycap_dqbuf() to trail frame_fill.*/
-       int frame_lock; /* Flag set to 1 by DQBUF and cleared by QBUF        */
-/*---------------------------------------------------------------------------*/
-/*
- *  IMAGE PROPERTIES
- */
-/*---------------------------------------------------------------------------*/
-       u32                   pixelformat;
-       int                     width;
-       int                     height;
-       int                     bytesperpixel;
-       bool                    byteswaporder;
-       bool                    decimatepixel;
-       bool                    offerfields;
-       int                     frame_buffer_used;
-       int                     frame_buffer_many;
-       int                     videofieldamount;
-
-       int                     brightness;
-       int                     contrast;
-       int                     saturation;
-       int                     hue;
-
-       int allocation_video_urb;
-       int allocation_video_page;
-       int allocation_video_struct;
-       int registered_video;
-/*---------------------------------------------------------------------------*/
-/*
- *  ALSA
- */
-/*---------------------------------------------------------------------------*/
-       struct snd_pcm_hardware alsa_hardware;
-       struct snd_card *psnd_card;
-       struct snd_pcm *psnd_pcm;
-       struct snd_pcm_substream *psubstream;
-       int dma_fill;
-       int dma_next;
-       int dma_read;
-/*---------------------------------------------------------------------------*/
-/*
- *  SOUND PROPERTIES
- */
-/*---------------------------------------------------------------------------*/
-       int audio_interface;
-       int audio_altsetting_on;
-       int audio_altsetting_off;
-       int audio_endpointnumber;
-       int audio_isoc_maxframesize;
-       int audio_isoc_buffer_size;
-       int audio_isoc_framesperdesc;
-
-       int audio_isoc_streaming;
-       int audio_idle;
-       int audio_eof;
-       int volume;
-       int mute;
-       s8 gain;
-
-       struct data_buffer audio_isoc_buffer[AUDIO_ISOC_BUFFER_MANY];
-
-       struct list_head urb_audio_head;
-       struct list_head *purb_audio_head;
-/*---------------------------------------------------------------------------*/
-/*
- *  BUFFER INDICATORS
- */
-/*---------------------------------------------------------------------------*/
-       int audio_fill; /* Audio buffer being filled by easycap_complete().  */
-                       /*   Bumped only by easycap_complete().              */
-       int audio_read; /* Audio buffer page being read by easycap_read().   */
-                       /*   Set by easycap_read() to trail audio_fill by    */
-                       /*   one fragment.                                   */
-/*---------------------------------------------------------------------------*/
-/*
- *  SOUND PROPERTIES
- */
-/*---------------------------------------------------------------------------*/
-       int allocation_audio_urb;
-       int allocation_audio_page;
-       int allocation_audio_struct;
-       int registered_audio;
-
-       long long int audio_sample;
-       long long int audio_niveau;
-       long long int audio_square;
-
-       struct data_buffer audio_buffer[];
-};
-/*---------------------------------------------------------------------------*/
-/*
- *  VIDEO FUNCTION PROTOTYPES
- */
-/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
-int easycap_newinput(struct easycap *, int);
-void easycap_testcard(struct easycap *, int);
-int easycap_isdongle(struct easycap *);
-
-long easycap_unlocked_ioctl(struct file *, unsigned int, unsigned long);
-
-int easycap_video_dqbuf(struct easycap *, int);
-int easycap_video_submit_urbs(struct easycap *);
-int easycap_video_kill_urbs(struct easycap *);
-int easycap_video_fillin_formats(void);
-
-int adjust_standard(struct easycap *, v4l2_std_id);
-int adjust_format(struct easycap *, u32, u32, u32, int, bool);
-int adjust_brightness(struct easycap *, int);
-int adjust_contrast(struct easycap *, int);
-int adjust_saturation(struct easycap *, int);
-int adjust_hue(struct easycap *, int);
-/*---------------------------------------------------------------------------*/
-/*
- *  AUDIO FUNCTION PROTOTYPES
- */
-/*---------------------------------------------------------------------------*/
-int easycap_alsa_probe(struct easycap *);
-int easycap_audio_kill_urbs(struct easycap *);
-void easycap_alsa_complete(struct urb *);
-/*---------------------------------------------------------------------------*/
-/*
- *  LOW-LEVEL FUNCTION PROTOTYPES
- */
-/*---------------------------------------------------------------------------*/
-int easycap_audio_gainset(struct usb_device *, s8);
-int easycap_audio_setup(struct easycap *);
-
-int easycap_wakeup_device(struct usb_device *);
-
-int setup_stk(struct usb_device *, bool);
-int setup_saa(struct usb_device *, bool);
-int ready_saa(struct usb_device *);
-int merit_saa(struct usb_device *);
-int check_vt(struct usb_device *);
-int select_input(struct usb_device *, int, int);
-int set_resolution(struct usb_device *, u16, u16, u16, u16);
-
-int read_saa(struct usb_device *, u16);
-int write_saa(struct usb_device *, u16, u16);
-int start_100(struct usb_device *);
-int stop_100(struct usb_device *);
-/*---------------------------------------------------------------------------*/
-
-
-/*---------------------------------------------------------------------------*/
-/*
- *  MACROS SAM(...) AND JOM(...) ALLOW DIAGNOSTIC OUTPUT TO BE TAGGED WITH
- *  THE IDENTITY OF THE DONGLE TO WHICH IT APPLIES, BUT IF INVOKED WHEN THE
- *  POINTER peasycap IS INVALID AN Oops IS LIKELY, AND ITS CAUSE MAY NOT BE
- *  IMMEDIATELY OBVIOUS FROM A CASUAL READING OF THE SOURCE CODE.  BEWARE.
-*/
-/*---------------------------------------------------------------------------*/
-const char *strerror(int err);
-
-#define SAY(format, args...) do { \
-       printk(KERN_DEBUG "easycap:: %s: " \
-                       format, __func__, ##args); \
-} while (0)
-#define SAM(format, args...) do { \
-       printk(KERN_DEBUG "easycap::%i%s: " \
-                       format, peasycap->isdongle, __func__, ##args);\
-} while (0)
-
-#ifdef CONFIG_EASYCAP_DEBUG
-extern int easycap_debug;
-#define JOT(n, format, args...) do { \
-       if (n <= easycap_debug) { \
-               printk(KERN_DEBUG "easycap:: %s: " \
-                       format, __func__, ##args);\
-       } \
-} while (0)
-#define JOM(n, format, args...) do { \
-       if (n <= easycap_debug) { \
-               printk(KERN_DEBUG "easycap::%i%s: " \
-                       format, peasycap->isdongle, __func__, ##args);\
-       } \
-} while (0)
-
-#else
-#define JOT(n, format, args...) do {} while (0)
-#define JOM(n, format, args...) do {} while (0)
-#endif /* CONFIG_EASYCAP_DEBUG */
-
-/*---------------------------------------------------------------------------*/
-
-/*---------------------------------------------------------------------------*/
-/* globals
- */
-/*---------------------------------------------------------------------------*/
-
-extern bool easycap_readback;
-extern const struct easycap_standard easycap_standard[];
-extern struct easycap_format easycap_format[];
-extern struct v4l2_queryctrl easycap_control[];
-extern struct easycap_dongle easycapdc60_dongle[];
-
-#endif /* !__EASYCAP_H__  */
diff --git a/drivers/staging/media/easycap/easycap_ioctl.c b/drivers/staging/media/easycap/easycap_ioctl.c
deleted file mode 100644 (file)
index 3cee3cd..0000000
+++ /dev/null
@@ -1,2443 +0,0 @@
-/******************************************************************************
-*                                                                             *
-*  easycap_ioctl.c                                                            *
-*                                                                             *
-******************************************************************************/
-/*
- *
- *  Copyright (C) 2010 R.M. Thomas  <rmthomas@sciolus.org>
- *
- *
- *  This 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.
- *
- *  The software 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 software; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
-*/
-/*****************************************************************************/
-
-#include "easycap.h"
-#include <linux/version.h>
-
-/*--------------------------------------------------------------------------*/
-/*
- *  UNLESS THERE IS A PREMATURE ERROR RETURN THIS ROUTINE UPDATES THE
- *  FOLLOWING:
- *          peasycap->standard_offset
- *          peasycap->inputset[peasycap->input].standard_offset
- *          peasycap->fps
- *          peasycap->usec
- *          peasycap->tolerate
- *          peasycap->skip
- */
-/*---------------------------------------------------------------------------*/
-int adjust_standard(struct easycap *peasycap, v4l2_std_id std_id)
-{
-       struct easycap_standard const *peasycap_standard;
-       u16 reg, set;
-       int ir, rc, need, k;
-       unsigned int itwas, isnow;
-       bool resubmit;
-
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return -EFAULT;
-       }
-       if (!peasycap->pusb_device) {
-               SAM("ERROR: peasycap->pusb_device is NULL\n");
-               return -EFAULT;
-       }
-       peasycap_standard = &easycap_standard[0];
-       while (0xFFFF != peasycap_standard->mask) {
-               if (std_id == peasycap_standard->v4l2_standard.id)
-                       break;
-               peasycap_standard++;
-       }
-       if (0xFFFF == peasycap_standard->mask) {
-               peasycap_standard = &easycap_standard[0];
-               while (0xFFFF != peasycap_standard->mask) {
-                       if (std_id & peasycap_standard->v4l2_standard.id)
-                               break;
-                       peasycap_standard++;
-               }
-       }
-       if (0xFFFF == peasycap_standard->mask) {
-               SAM("ERROR: 0x%08X=std_id: standard not found\n",
-                   (unsigned int)std_id);
-               return -EINVAL;
-       }
-       SAM("selected standard: %s\n",
-           &(peasycap_standard->v4l2_standard.name[0]));
-       if (peasycap->standard_offset == peasycap_standard - easycap_standard) {
-               SAM("requested standard already in effect\n");
-               return 0;
-       }
-       peasycap->standard_offset = peasycap_standard - easycap_standard;
-       for (k = 0; k < INPUT_MANY;  k++) {
-               if (!peasycap->inputset[k].standard_offset_ok) {
-                       peasycap->inputset[k].standard_offset =
-                               peasycap->standard_offset;
-               }
-       }
-       if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
-               peasycap->inputset[peasycap->input].standard_offset =
-                       peasycap->standard_offset;
-               peasycap->inputset[peasycap->input].standard_offset_ok = 1;
-       } else
-               JOM(8, "%i=peasycap->input\n", peasycap->input);
-
-       peasycap->fps = peasycap_standard->v4l2_standard.frameperiod.denominator /
-                       peasycap_standard->v4l2_standard.frameperiod.numerator;
-       switch (peasycap->fps) {
-       case 6:
-       case 30: {
-               peasycap->ntsc = true;
-               break;
-       }
-       case 5:
-       case 25: {
-               peasycap->ntsc = false;
-               break;
-       }
-       default: {
-               SAM("MISTAKE: %i=frames-per-second\n", peasycap->fps);
-               return -ENOENT;
-       }
-       }
-       JOM(8, "%i frames-per-second\n", peasycap->fps);
-       if (0x8000 & peasycap_standard->mask) {
-               peasycap->skip = 5;
-               peasycap->usec = 1000000 / (2 * (5 * peasycap->fps));
-               peasycap->tolerate = 1000 * (25 / (5 * peasycap->fps));
-       } else {
-               peasycap->skip = 0;
-               peasycap->usec = 1000000 / (2 * peasycap->fps);
-               peasycap->tolerate = 1000 * (25 / peasycap->fps);
-       }
-       if (peasycap->video_isoc_streaming) {
-               resubmit = true;
-               easycap_video_kill_urbs(peasycap);
-       } else
-               resubmit = false;
-/*--------------------------------------------------------------------------*/
-/*
- *  SAA7113H DATASHEET PAGE 44, TABLE 42
- */
-/*--------------------------------------------------------------------------*/
-       need = 0;
-       itwas = 0;
-       reg = 0x00;
-       set = 0x00;
-       switch (peasycap_standard->mask & 0x000F) {
-       case NTSC_M_JP: {
-               reg = 0x0A;
-               set = 0x95;
-               ir = read_saa(peasycap->pusb_device, reg);
-               if (0 > ir)
-                       SAM("ERROR: cannot read SAA register 0x%02X\n", reg);
-               else
-                       itwas = (unsigned int)ir;
-               rc = write_saa(peasycap->pusb_device, reg, set);
-               if (rc)
-                       SAM("ERROR: failed to set SAA register "
-                           "0x%02X to 0x%02X for JP standard\n", reg, set);
-               else {
-                       isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
-                       if (0 > ir)
-                               JOM(8, "SAA register 0x%02X changed "
-                                   "to 0x%02X\n", reg, isnow);
-                       else
-                               JOM(8, "SAA register 0x%02X changed "
-                                   "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
-               }
-
-               reg = 0x0B;
-               set = 0x48;
-               ir = read_saa(peasycap->pusb_device, reg);
-               if (0 > ir)
-                       SAM("ERROR: cannot read SAA register 0x%02X\n", reg);
-               else
-                       itwas = (unsigned int)ir;
-               rc = write_saa(peasycap->pusb_device, reg, set);
-               if (rc)
-                       SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X "
-                           "for JP standard\n", reg, set);
-               else {
-                       isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
-                       if (0 > ir)
-                               JOM(8, "SAA register 0x%02X changed "
-                                   "to 0x%02X\n", reg, isnow);
-                       else
-                               JOM(8, "SAA register 0x%02X changed "
-                                   "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
-               }
-/*--------------------------------------------------------------------------*/
-/*
- *  NOTE:  NO break HERE:  RUN ON TO NEXT CASE
- */
-/*--------------------------------------------------------------------------*/
-       }
-       case NTSC_M:
-       case PAL_BGHIN: {
-               reg = 0x0E;
-               set = 0x01;
-               need = 1;
-               break;
-       }
-       case NTSC_N_443:
-       case PAL_60: {
-               reg = 0x0E;
-               set = 0x11;
-               need = 1;
-               break;
-       }
-       case NTSC_443:
-       case PAL_Nc: {
-               reg = 0x0E;
-               set = 0x21;
-               need = 1;
-               break;
-       }
-       case NTSC_N:
-       case PAL_M: {
-               reg = 0x0E;
-               set = 0x31;
-               need = 1;
-               break;
-       }
-       case SECAM: {
-               reg = 0x0E;
-               set = 0x51;
-               need = 1;
-               break;
-       }
-       default:
-               break;
-       }
-/*--------------------------------------------------------------------------*/
-       if (need) {
-               ir = read_saa(peasycap->pusb_device, reg);
-               if (0 > ir)
-                       SAM("ERROR: failed to read SAA register 0x%02X\n", reg);
-               else
-                       itwas = (unsigned int)ir;
-               rc = write_saa(peasycap->pusb_device, reg, set);
-               if (0 != write_saa(peasycap->pusb_device, reg, set)) {
-                       SAM("ERROR: failed to set SAA register "
-                           "0x%02X to 0x%02X for table 42\n", reg, set);
-               } else {
-                       isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
-                       if (0 > ir)
-                               JOM(8, "SAA register 0x%02X changed "
-                                   "to 0x%02X\n", reg, isnow);
-                       else
-                               JOM(8, "SAA register 0x%02X changed "
-                                   "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
-               }
-       }
-/*--------------------------------------------------------------------------*/
-/*
-        *  SAA7113H DATASHEET PAGE 41
-        */
-/*--------------------------------------------------------------------------*/
-       reg = 0x08;
-       ir = read_saa(peasycap->pusb_device, reg);
-       if (0 > ir)
-               SAM("ERROR: failed to read SAA register 0x%02X "
-                   "so cannot reset\n", reg);
-       else {
-               itwas = (unsigned int)ir;
-               if (peasycap_standard->mask & 0x0001)
-                       set = itwas | 0x40 ;
-               else
-                       set = itwas & ~0x40 ;
-               rc  = write_saa(peasycap->pusb_device, reg, set);
-               if (rc)
-                       SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X\n",
-                           reg, set);
-               else {
-                       isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
-                       if (0 > ir)
-                               JOM(8, "SAA register 0x%02X changed to 0x%02X\n",
-                                   reg, isnow);
-                       else
-                               JOM(8, "SAA register 0x%02X changed "
-                                   "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
-               }
-       }
-/*--------------------------------------------------------------------------*/
-/*
- *  SAA7113H DATASHEET PAGE 51, TABLE 57
- */
-/*---------------------------------------------------------------------------*/
-       reg = 0x40;
-       ir = read_saa(peasycap->pusb_device, reg);
-       if (0 > ir)
-               SAM("ERROR: failed to read SAA register 0x%02X "
-                   "so cannot reset\n", reg);
-       else {
-               itwas = (unsigned int)ir;
-               if (peasycap_standard->mask & 0x0001)
-                       set = itwas | 0x80 ;
-               else
-                       set = itwas & ~0x80 ;
-               rc = write_saa(peasycap->pusb_device, reg, set);
-               if (rc)
-                       SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X\n",
-                           reg, set);
-               else {
-                       isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
-                       if (0 > ir)
-                               JOM(8, "SAA register 0x%02X changed to 0x%02X\n",
-                                   reg, isnow);
-                       else
-                               JOM(8, "SAA register 0x%02X changed "
-                                   "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
-               }
-       }
-/*--------------------------------------------------------------------------*/
-/*
-        *  SAA7113H DATASHEET PAGE 53, TABLE 66
-        */
-/*--------------------------------------------------------------------------*/
-       reg = 0x5A;
-       ir = read_saa(peasycap->pusb_device, reg);
-       if (0 > ir)
-               SAM("ERROR: failed to read SAA register 0x%02X but continuing\n", reg);
-       itwas = (unsigned int)ir;
-       if (peasycap_standard->mask & 0x0001)
-               set = 0x0A ;
-       else
-               set = 0x07 ;
-       if (0 != write_saa(peasycap->pusb_device, reg, set))
-               SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X\n",
-                   reg, set);
-       else {
-               isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
-               if (0 > ir)
-                       JOM(8, "SAA register 0x%02X changed "
-                           "to 0x%02X\n", reg, isnow);
-               else
-                       JOM(8, "SAA register 0x%02X changed "
-                           "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
-       }
-       if (resubmit)
-               easycap_video_submit_urbs(peasycap);
-       return 0;
-}
-/*****************************************************************************/
-/*--------------------------------------------------------------------------*/
-/*
- *  THE ALGORITHM FOR RESPONDING TO THE VIDIO_S_FMT IOCTL REQUIRES
- *  A VALID VALUE OF peasycap->standard_offset, OTHERWISE -EBUSY IS RETURNED.
- *
- *  PROVIDED THE ARGUMENT try IS false AND THERE IS NO PREMATURE ERROR RETURN
- *  THIS ROUTINE UPDATES THE FOLLOWING:
- *          peasycap->format_offset
- *          peasycap->inputset[peasycap->input].format_offset
- *          peasycap->pixelformat
- *          peasycap->height
- *          peasycap->width
- *          peasycap->bytesperpixel
- *          peasycap->byteswaporder
- *          peasycap->decimatepixel
- *          peasycap->frame_buffer_used
- *          peasycap->videofieldamount
- *          peasycap->offerfields
- *
- *  IF SUCCESSFUL THE FUNCTION RETURNS THE OFFSET IN easycap_format[]
- *  IDENTIFYING THE FORMAT WHICH IS TO RETURNED TO THE USER.
- *  ERRORS RETURN A NEGATIVE NUMBER.
- */
-/*--------------------------------------------------------------------------*/
-int adjust_format(struct easycap *peasycap,
-                 u32 width, u32 height, u32 pixelformat, int field, bool try)
-{
-       struct easycap_format *peasycap_format, *peasycap_best_format;
-       u16 mask;
-       struct usb_device *p;
-       int miss, multiplier, best, k;
-       char bf[5], fo[32], *pc;
-       u32 uc;
-       bool resubmit;
-
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return -EFAULT;
-       }
-       if (0 > peasycap->standard_offset) {
-               JOM(8, "%i=peasycap->standard_offset\n", peasycap->standard_offset);
-               return -EBUSY;
-       }
-       p = peasycap->pusb_device;
-       if (!p) {
-               SAM("ERROR: peaycap->pusb_device is NULL\n");
-               return -EFAULT;
-       }
-       pc = &bf[0];
-       uc = pixelformat;
-       memcpy((void *)pc, (void *)(&uc), 4);
-       bf[4] = 0;
-       mask = 0xFF & easycap_standard[peasycap->standard_offset].mask;
-       SAM("sought:    %ix%i,%s(0x%08X),%i=field,0x%02X=std mask\n",
-           width, height, pc, pixelformat, field, mask);
-       switch (field) {
-       case V4L2_FIELD_ANY: {
-               strcpy(&fo[0], "V4L2_FIELD_ANY ");
-               break;
-       }
-       case V4L2_FIELD_NONE: {
-               strcpy(&fo[0], "V4L2_FIELD_NONE");
-               break;
-       }
-       case V4L2_FIELD_TOP: {
-               strcpy(&fo[0], "V4L2_FIELD_TOP");
-               break;
-       }
-       case V4L2_FIELD_BOTTOM: {
-               strcpy(&fo[0], "V4L2_FIELD_BOTTOM");
-               break;
-       }
-       case V4L2_FIELD_INTERLACED: {
-               strcpy(&fo[0], "V4L2_FIELD_INTERLACED");
-               break;
-       }
-       case V4L2_FIELD_SEQ_TB: {
-               strcpy(&fo[0], "V4L2_FIELD_SEQ_TB");
-               break;
-       }
-       case V4L2_FIELD_SEQ_BT: {
-               strcpy(&fo[0], "V4L2_FIELD_SEQ_BT");
-               break;
-       }
-       case V4L2_FIELD_ALTERNATE: {
-               strcpy(&fo[0], "V4L2_FIELD_ALTERNATE");
-               break;
-       }
-       case V4L2_FIELD_INTERLACED_TB: {
-               strcpy(&fo[0], "V4L2_FIELD_INTERLACED_TB");
-               break;
-       }
-       case V4L2_FIELD_INTERLACED_BT: {
-               strcpy(&fo[0], "V4L2_FIELD_INTERLACED_BT");
-               break;
-       }
-       default: {
-               strcpy(&fo[0], "V4L2_FIELD_... UNKNOWN  ");
-               break;
-       }
-       }
-       SAM("sought:    %s\n", &fo[0]);
-       if (V4L2_FIELD_ANY == field) {
-               field = V4L2_FIELD_NONE;
-               SAM("prefer:    V4L2_FIELD_NONE=field, was V4L2_FIELD_ANY\n");
-       }
-       peasycap_best_format = NULL;
-       peasycap_format = &easycap_format[0];
-       while (0 != peasycap_format->v4l2_format.fmt.pix.width) {
-               JOM(16, ".> %i %i 0x%08X %ix%i\n",
-                   peasycap_format->mask & 0x01,
-                   peasycap_format->v4l2_format.fmt.pix.field,
-                   peasycap_format->v4l2_format.fmt.pix.pixelformat,
-                   peasycap_format->v4l2_format.fmt.pix.width,
-                   peasycap_format->v4l2_format.fmt.pix.height);
-
-               if (((peasycap_format->mask & 0x1F) == (mask & 0x1F)) &&
-                   (peasycap_format->v4l2_format.fmt.pix.field == field) &&
-                   (peasycap_format->v4l2_format.fmt.pix.pixelformat == pixelformat) &&
-                   (peasycap_format->v4l2_format.fmt.pix.width  == width) &&
-                   (peasycap_format->v4l2_format.fmt.pix.height == height)) {
-
-                       peasycap_best_format = peasycap_format;
-                       break;
-               }
-               peasycap_format++;
-       }
-       if (0 == peasycap_format->v4l2_format.fmt.pix.width) {
-               SAM("cannot do: %ix%i with standard mask 0x%02X\n",
-                   width, height, mask);
-               peasycap_format = &easycap_format[0];
-               best = -1;
-               while (0 != peasycap_format->v4l2_format.fmt.pix.width) {
-                       if (((peasycap_format->mask & 0x1F) == (mask & 0x1F)) &&
-                           (peasycap_format->v4l2_format.fmt.pix.field == field) &&
-                           (peasycap_format->v4l2_format.fmt.pix.pixelformat == pixelformat)) {
-
-                               miss = abs(peasycap_format->v4l2_format.fmt.pix.width  - width);
-                               if ((best > miss) || (best < 0)) {
-                                       best = miss;
-                                       peasycap_best_format = peasycap_format;
-                                       if (!miss)
-                                               break;
-                               }
-                       }
-                       peasycap_format++;
-               }
-               if (-1 == best) {
-                       SAM("cannot do %ix... with standard mask 0x%02X\n",
-                           width, mask);
-                       SAM("cannot do ...x%i with standard mask 0x%02X\n",
-                           height, mask);
-                       SAM("           %ix%i unmatched\n", width, height);
-                       return peasycap->format_offset;
-               }
-       }
-       if (!peasycap_best_format) {
-               SAM("MISTAKE: peasycap_best_format is NULL");
-               return -EINVAL;
-       }
-       peasycap_format = peasycap_best_format;
-
-/*...........................................................................*/
-       if (try)
-               return peasycap_best_format - easycap_format;
-/*...........................................................................*/
-
-       if (false != try) {
-               SAM("MISTAKE: true==try where is should be false\n");
-               return -EINVAL;
-       }
-       SAM("actioning: %ix%i %s\n",
-           peasycap_format->v4l2_format.fmt.pix.width,
-           peasycap_format->v4l2_format.fmt.pix.height,
-           &peasycap_format->name[0]);
-       peasycap->height        = peasycap_format->v4l2_format.fmt.pix.height;
-       peasycap->width         = peasycap_format->v4l2_format.fmt.pix.width;
-       peasycap->pixelformat   = peasycap_format->v4l2_format.fmt.pix.pixelformat;
-       peasycap->format_offset = peasycap_format - easycap_format;
-
-
-       for (k = 0; k < INPUT_MANY; k++) {
-               if (!peasycap->inputset[k].format_offset_ok) {
-                       peasycap->inputset[k].format_offset =
-                               peasycap->format_offset;
-               }
-       }
-       if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
-               peasycap->inputset[peasycap->input].format_offset =
-                       peasycap->format_offset;
-               peasycap->inputset[peasycap->input].format_offset_ok = 1;
-       } else
-               JOM(8, "%i=peasycap->input\n", peasycap->input);
-
-
-
-       peasycap->bytesperpixel = (0x00E0 & peasycap_format->mask) >> 5 ;
-       if (0x0100 & peasycap_format->mask)
-               peasycap->byteswaporder = true;
-       else
-               peasycap->byteswaporder = false;
-       if (0x0200 & peasycap_format->mask)
-               peasycap->skip = 5;
-       else
-               peasycap->skip = 0;
-       if (0x0800 & peasycap_format->mask)
-               peasycap->decimatepixel = true;
-       else
-               peasycap->decimatepixel = false;
-       if (0x1000 & peasycap_format->mask)
-               peasycap->offerfields = true;
-       else
-               peasycap->offerfields = false;
-       if (peasycap->decimatepixel)
-               multiplier = 2;
-       else
-               multiplier = 1;
-       peasycap->videofieldamount =
-               multiplier * peasycap->width * multiplier * peasycap->height;
-       peasycap->frame_buffer_used =
-               peasycap->bytesperpixel * peasycap->width * peasycap->height;
-       if (peasycap->video_isoc_streaming) {
-               resubmit = true;
-               easycap_video_kill_urbs(peasycap);
-       } else
-               resubmit = false;
-/*---------------------------------------------------------------------------*/
-/*
-        *  PAL
-        */
-/*---------------------------------------------------------------------------*/
-       if (0 == (0x01 & peasycap_format->mask)) {
-               if (((720 == peasycap_format->v4l2_format.fmt.pix.width) &&
-                    (576 == peasycap_format->v4l2_format.fmt.pix.height)) ||
-                   ((360 == peasycap_format->v4l2_format.fmt.pix.width) &&
-                    (288 == peasycap_format->v4l2_format.fmt.pix.height))) {
-                       if (set_resolution(p, 0x0000, 0x0001, 0x05A0, 0x0121)) {
-                               SAM("ERROR: set_resolution() failed\n");
-                               return -EINVAL;
-                       }
-               } else if ((704 == peasycap_format->v4l2_format.fmt.pix.width) &&
-                          (576 == peasycap_format->v4l2_format.fmt.pix.height)) {
-                       if (set_resolution(p, 0x0004, 0x0001, 0x0584, 0x0121)) {
-                               SAM("ERROR: set_resolution() failed\n");
-                               return -EINVAL;
-                       }
-               } else if (((640 == peasycap_format->v4l2_format.fmt.pix.width) &&
-                           (480 == peasycap_format->v4l2_format.fmt.pix.height)) ||
-                          ((320 == peasycap_format->v4l2_format.fmt.pix.width) &&
-                           (240 == peasycap_format->v4l2_format.fmt.pix.height))) {
-                       if (set_resolution(p, 0x0014, 0x0020, 0x0514, 0x0110)) {
-                               SAM("ERROR: set_resolution() failed\n");
-                               return -EINVAL;
-                       }
-               } else {
-                       SAM("MISTAKE: bad format, cannot set resolution\n");
-                       return -EINVAL;
-               }
-/*---------------------------------------------------------------------------*/
-/*
- *  NTSC
- */
-/*---------------------------------------------------------------------------*/
-       } else {
-               if (((720 == peasycap_format->v4l2_format.fmt.pix.width) &&
-                    (480 == peasycap_format->v4l2_format.fmt.pix.height)) ||
-                   ((360 == peasycap_format->v4l2_format.fmt.pix.width) &&
-                    (240 == peasycap_format->v4l2_format.fmt.pix.height))) {
-                       if (set_resolution(p, 0x0000, 0x0003, 0x05A0, 0x00F3)) {
-                               SAM("ERROR: set_resolution() failed\n");
-                               return -EINVAL;
-                       }
-               } else if (((640 == peasycap_format->v4l2_format.fmt.pix.width) &&
-                           (480 == peasycap_format->v4l2_format.fmt.pix.height)) ||
-                          ((320 == peasycap_format->v4l2_format.fmt.pix.width) &&
-                           (240 == peasycap_format->v4l2_format.fmt.pix.height))) {
-                       if (set_resolution(p, 0x0014, 0x0003, 0x0514, 0x00F3)) {
-                               SAM("ERROR: set_resolution() failed\n");
-                               return -EINVAL;
-                       }
-               } else {
-                       SAM("MISTAKE: bad format, cannot set resolution\n");
-                       return -EINVAL;
-               }
-       }
-/*---------------------------------------------------------------------------*/
-       if (resubmit)
-               easycap_video_submit_urbs(peasycap);
-
-       return peasycap_best_format - easycap_format;
-}
-/*****************************************************************************/
-int adjust_brightness(struct easycap *peasycap, int value)
-{
-       unsigned int mood;
-       int i1, k;
-
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return -EFAULT;
-       }
-       if (!peasycap->pusb_device) {
-               SAM("ERROR: peasycap->pusb_device is NULL\n");
-               return -EFAULT;
-       }
-       i1 = 0;
-       while (0xFFFFFFFF != easycap_control[i1].id) {
-               if (V4L2_CID_BRIGHTNESS == easycap_control[i1].id) {
-                       if ((easycap_control[i1].minimum > value) ||
-                           (easycap_control[i1].maximum < value))
-                               value = easycap_control[i1].default_value;
-
-                       if ((easycap_control[i1].minimum <= peasycap->brightness) &&
-                           (easycap_control[i1].maximum >= peasycap->brightness)) {
-                               if (peasycap->brightness == value) {
-                                       SAM("unchanged brightness at  0x%02X\n",
-                                           value);
-                                       return 0;
-                               }
-                       }
-                       peasycap->brightness = value;
-                       for (k = 0; k < INPUT_MANY; k++) {
-                               if (!peasycap->inputset[k].brightness_ok)
-                                       peasycap->inputset[k].brightness =
-                                               peasycap->brightness;
-                       }
-                       if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
-                               peasycap->inputset[peasycap->input].brightness =
-                                       peasycap->brightness;
-                               peasycap->inputset[peasycap->input].brightness_ok = 1;
-                       } else
-                               JOM(8, "%i=peasycap->input\n", peasycap->input);
-
-                       mood = 0x00FF & (unsigned int)peasycap->brightness;
-                       if (write_saa(peasycap->pusb_device, 0x0A, mood)) {
-                               SAM("WARNING: failed to adjust brightness "
-                                   "to 0x%02X\n", mood);
-                               return -ENOENT;
-                       }
-                       SAM("adjusting brightness to  0x%02X\n", mood);
-                       return 0;
-               }
-               i1++;
-       }
-       SAM("WARNING: failed to adjust brightness: control not found\n");
-       return -ENOENT;
-}
-/*****************************************************************************/
-int adjust_contrast(struct easycap *peasycap, int value)
-{
-       unsigned int mood;
-       int i1, k;
-
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return -EFAULT;
-       }
-       if (!peasycap->pusb_device) {
-               SAM("ERROR: peasycap->pusb_device is NULL\n");
-               return -EFAULT;
-       }
-       i1 = 0;
-       while (0xFFFFFFFF != easycap_control[i1].id) {
-               if (V4L2_CID_CONTRAST == easycap_control[i1].id) {
-                       if ((easycap_control[i1].minimum > value) ||
-                           (easycap_control[i1].maximum < value))
-                               value = easycap_control[i1].default_value;
-
-
-                       if ((easycap_control[i1].minimum <= peasycap->contrast) &&
-                           (easycap_control[i1].maximum >= peasycap->contrast)) {
-                               if (peasycap->contrast == value) {
-                                       SAM("unchanged contrast at  0x%02X\n", value);
-                                       return 0;
-                               }
-                       }
-                       peasycap->contrast = value;
-                       for (k = 0; k < INPUT_MANY; k++) {
-                               if (!peasycap->inputset[k].contrast_ok)
-                                       peasycap->inputset[k].contrast = peasycap->contrast;
-                       }
-
-                       if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
-                               peasycap->inputset[peasycap->input].contrast =
-                                               peasycap->contrast;
-                               peasycap->inputset[peasycap->input].contrast_ok = 1;
-                       } else
-                               JOM(8, "%i=peasycap->input\n", peasycap->input);
-
-                       mood = 0x00FF & (unsigned int) (peasycap->contrast - 128);
-                       if (write_saa(peasycap->pusb_device, 0x0B, mood)) {
-                               SAM("WARNING: failed to adjust contrast to "
-                                   "0x%02X\n", mood);
-                               return -ENOENT;
-                       }
-                       SAM("adjusting contrast to  0x%02X\n", mood);
-                       return 0;
-               }
-               i1++;
-       }
-       SAM("WARNING: failed to adjust contrast: control not found\n");
-       return -ENOENT;
-}
-/*****************************************************************************/
-int adjust_saturation(struct easycap *peasycap, int value)
-{
-       unsigned int mood;
-       int i1, k;
-
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return -EFAULT;
-       }
-       if (!peasycap->pusb_device) {
-               SAM("ERROR: peasycap->pusb_device is NULL\n");
-               return -EFAULT;
-       }
-       i1 = 0;
-       while (0xFFFFFFFF != easycap_control[i1].id) {
-               if (V4L2_CID_SATURATION == easycap_control[i1].id) {
-                       if ((easycap_control[i1].minimum > value) ||
-                           (easycap_control[i1].maximum < value))
-                               value = easycap_control[i1].default_value;
-
-
-                       if ((easycap_control[i1].minimum <= peasycap->saturation) &&
-                           (easycap_control[i1].maximum >= peasycap->saturation)) {
-                               if (peasycap->saturation == value) {
-                                       SAM("unchanged saturation at  0x%02X\n",
-                                           value);
-                                       return 0;
-                               }
-                       }
-                       peasycap->saturation = value;
-                       for (k = 0; k < INPUT_MANY; k++) {
-                               if (!peasycap->inputset[k].saturation_ok)
-                                       peasycap->inputset[k].saturation =
-                                               peasycap->saturation;
-                       }
-                       if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
-                               peasycap->inputset[peasycap->input].saturation =
-                                       peasycap->saturation;
-                               peasycap->inputset[peasycap->input].saturation_ok = 1;
-                       } else
-                               JOM(8, "%i=peasycap->input\n", peasycap->input);
-                       mood = 0x00FF & (unsigned int) (peasycap->saturation - 128);
-                       if (write_saa(peasycap->pusb_device, 0x0C, mood)) {
-                               SAM("WARNING: failed to adjust saturation to "
-                                   "0x%02X\n", mood);
-                               return -ENOENT;
-                       }
-                       SAM("adjusting saturation to  0x%02X\n", mood);
-                       return 0;
-                       break;
-               }
-               i1++;
-       }
-       SAM("WARNING: failed to adjust saturation: control not found\n");
-       return -ENOENT;
-}
-/*****************************************************************************/
-int adjust_hue(struct easycap *peasycap, int value)
-{
-       unsigned int mood;
-       int i1, i2, k;
-
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return -EFAULT;
-       }
-       if (!peasycap->pusb_device) {
-               SAM("ERROR: peasycap->pusb_device is NULL\n");
-               return -EFAULT;
-       }
-       i1 = 0;
-       while (0xFFFFFFFF != easycap_control[i1].id) {
-               if (V4L2_CID_HUE == easycap_control[i1].id) {
-                       if ((easycap_control[i1].minimum > value) ||
-                           (easycap_control[i1].maximum < value))
-                               value = easycap_control[i1].default_value;
-
-                       if ((easycap_control[i1].minimum <= peasycap->hue) &&
-                           (easycap_control[i1].maximum >= peasycap->hue)) {
-                               if (peasycap->hue == value) {
-                                       SAM("unchanged hue at  0x%02X\n", value);
-                                       return 0;
-                               }
-                       }
-                       peasycap->hue = value;
-                       for (k = 0; k < INPUT_MANY; k++) {
-                               if (!peasycap->inputset[k].hue_ok)
-                                       peasycap->inputset[k].hue = peasycap->hue;
-                       }
-                       if (0 <= peasycap->input && INPUT_MANY > peasycap->input) {
-                               peasycap->inputset[peasycap->input].hue = peasycap->hue;
-                               peasycap->inputset[peasycap->input].hue_ok = 1;
-                       } else
-                               JOM(8, "%i=peasycap->input\n", peasycap->input);
-                       i2 = peasycap->hue - 128;
-                       mood = 0x00FF & ((int) i2);
-                       if (write_saa(peasycap->pusb_device, 0x0D, mood)) {
-                               SAM("WARNING: failed to adjust hue to 0x%02X\n", mood);
-                               return -ENOENT;
-                       }
-                       SAM("adjusting hue to  0x%02X\n", mood);
-                       return 0;
-                       break;
-               }
-               i1++;
-       }
-       SAM("WARNING: failed to adjust hue: control not found\n");
-       return -ENOENT;
-}
-/*****************************************************************************/
-static int adjust_volume(struct easycap *peasycap, int value)
-{
-       s8 mood;
-       int i1;
-
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return -EFAULT;
-       }
-       if (!peasycap->pusb_device) {
-               SAM("ERROR: peasycap->pusb_device is NULL\n");
-               return -EFAULT;
-       }
-       i1 = 0;
-       while (0xFFFFFFFF != easycap_control[i1].id) {
-               if (V4L2_CID_AUDIO_VOLUME == easycap_control[i1].id) {
-                       if ((easycap_control[i1].minimum > value) ||
-                           (easycap_control[i1].maximum < value))
-                               value = easycap_control[i1].default_value;
-
-                       if ((easycap_control[i1].minimum <= peasycap->volume) &&
-                           (easycap_control[i1].maximum >= peasycap->volume)) {
-                               if (peasycap->volume == value) {
-                                       SAM("unchanged volume at  0x%02X\n", value);
-                                       return 0;
-                               }
-                       }
-                       peasycap->volume = value;
-                       mood = (16 > peasycap->volume) ? 16 :
-                               ((31 < peasycap->volume) ? 31 :
-                                 (s8) peasycap->volume);
-                       if (!easycap_audio_gainset(peasycap->pusb_device, mood)) {
-                               SAM("WARNING: failed to adjust volume to "
-                                   "0x%2X\n", mood);
-                               return -ENOENT;
-                       }
-                       SAM("adjusting volume to 0x%02X\n", mood);
-                       return 0;
-               }
-               i1++;
-       }
-       SAM("WARNING: failed to adjust volume: control not found\n");
-       return -ENOENT;
-}
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- *  AN ALTERNATIVE METHOD OF MUTING MIGHT SEEM TO BE:
- *            usb_set_interface(peasycap->pusb_device,
- *                              peasycap->audio_interface,
- *                              peasycap->audio_altsetting_off);
- *  HOWEVER, AFTER THIS COMMAND IS ISSUED ALL SUBSEQUENT URBS RECEIVE STATUS
- *  -ESHUTDOWN.  THE HANDLER ROUTINE easyxxx_complete() DECLINES TO RESUBMIT
- *  THE URB AND THE PIPELINE COLLAPSES IRRETRIEVABLY.  BEWARE.
- */
-/*---------------------------------------------------------------------------*/
-static int adjust_mute(struct easycap *peasycap, int value)
-{
-       int i1;
-
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return -EFAULT;
-       }
-       if (!peasycap->pusb_device) {
-               SAM("ERROR: peasycap->pusb_device is NULL\n");
-               return -EFAULT;
-       }
-       i1 = 0;
-       while (0xFFFFFFFF != easycap_control[i1].id) {
-               if (V4L2_CID_AUDIO_MUTE == easycap_control[i1].id) {
-                       peasycap->mute = value;
-                       switch (peasycap->mute) {
-                       case 1: {
-                               peasycap->audio_idle = 1;
-                               SAM("adjusting mute: %i=peasycap->audio_idle\n",
-                                   peasycap->audio_idle);
-                               return 0;
-                       }
-                       default: {
-                               peasycap->audio_idle = 0;
-                               SAM("adjusting mute: %i=peasycap->audio_idle\n",
-                                   peasycap->audio_idle);
-                               return 0;
-                       }
-                       }
-                       break;
-               }
-               i1++;
-       }
-       SAM("WARNING: failed to adjust mute: control not found\n");
-       return -ENOENT;
-}
-/*---------------------------------------------------------------------------*/
-long easycap_unlocked_ioctl(struct file *file,
-                           unsigned int cmd, unsigned long arg)
-{
-       struct easycap *peasycap;
-       struct usb_device *p;
-       int kd;
-
-       if (!file) {
-               SAY("ERROR:  file is NULL\n");
-               return -ERESTARTSYS;
-       }
-       peasycap = file->private_data;
-       if (!peasycap) {
-               SAY("ERROR:  peasycap is NULL\n");
-               return -1;
-       }
-       p = peasycap->pusb_device;
-       if (!p) {
-               SAM("ERROR: peasycap->pusb_device is NULL\n");
-               return -EFAULT;
-       }
-       kd = easycap_isdongle(peasycap);
-       if (0 <= kd && DONGLE_MANY > kd) {
-               if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_video)) {
-                       SAY("ERROR: cannot lock "
-                           "easycapdc60_dongle[%i].mutex_video\n", kd);
-                       return -ERESTARTSYS;
-               }
-               JOM(4, "locked easycapdc60_dongle[%i].mutex_video\n", kd);
-/*---------------------------------------------------------------------------*/
-/*
- *  MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER peasycap,
- *  IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL.
- *  IF NECESSARY, BAIL OUT.
- */
-/*---------------------------------------------------------------------------*/
-               if (kd != easycap_isdongle(peasycap))
-                       return -ERESTARTSYS;
-               if (!file) {
-                       SAY("ERROR:  file is NULL\n");
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -ERESTARTSYS;
-               }
-               peasycap = file->private_data;
-               if (!peasycap) {
-                       SAY("ERROR:  peasycap is NULL\n");
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -ERESTARTSYS;
-               }
-               if (!peasycap->pusb_device) {
-                       SAM("ERROR: peasycap->pusb_device is NULL\n");
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -ERESTARTSYS;
-               }
-       } else {
-/*---------------------------------------------------------------------------*/
-/*
- *  IF easycap_usb_disconnect() HAS ALREADY FREED POINTER peasycap BEFORE THE
- *  ATTEMPT TO ACQUIRE THE SEMAPHORE, isdongle() WILL HAVE FAILED.  BAIL OUT.
- */
-/*---------------------------------------------------------------------------*/
-               return -ERESTARTSYS;
-       }
-/*---------------------------------------------------------------------------*/
-       switch (cmd) {
-       case VIDIOC_QUERYCAP: {
-               struct v4l2_capability v4l2_capability;
-               char version[16], *p1, *p2;
-               int i, rc, k[3];
-               long lng;
-
-               JOM(8, "VIDIOC_QUERYCAP\n");
-
-               if (16 <= strlen(EASYCAP_DRIVER_VERSION)) {
-                       SAM("ERROR: bad driver version string\n");
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-               strcpy(&version[0], EASYCAP_DRIVER_VERSION);
-               for (i = 0; i < 3; i++)
-                       k[i] = 0;
-               p2 = &version[0];
-               i = 0;
-               while (*p2) {
-                       p1 = p2;
-                       while (*p2 && ('.' != *p2))
-                               p2++;
-                       if (*p2)
-                               *p2++ = 0;
-                       if (3 > i) {
-                               rc = (int) strict_strtol(p1, 10, &lng);
-                               if (rc) {
-                                       SAM("ERROR: %i=strict_strtol(%s,.,,)\n",
-                                           rc, p1);
-                                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                                       return -EINVAL;
-                               }
-                               k[i] = (int)lng;
-                       }
-                       i++;
-               }
-
-               memset(&v4l2_capability, 0, sizeof(struct v4l2_capability));
-               strlcpy(&v4l2_capability.driver[0],
-                       "easycap", sizeof(v4l2_capability.driver));
-
-               v4l2_capability.capabilities = V4L2_CAP_VIDEO_CAPTURE |
-                                               V4L2_CAP_STREAMING |
-                                               V4L2_CAP_AUDIO |
-                                               V4L2_CAP_READWRITE;
-
-               v4l2_capability.version = KERNEL_VERSION(k[0], k[1], k[2]);
-               JOM(8, "v4l2_capability.version=(%i,%i,%i)\n", k[0], k[1], k[2]);
-
-               strlcpy(&v4l2_capability.card[0],
-                       "EasyCAP DC60", sizeof(v4l2_capability.card));
-
-               if (usb_make_path(peasycap->pusb_device,
-                               &v4l2_capability.bus_info[0],
-                               sizeof(v4l2_capability.bus_info)) < 0) {
-
-                       strlcpy(&v4l2_capability.bus_info[0], "EasyCAP bus_info",
-                               sizeof(v4l2_capability.bus_info));
-                       JOM(8, "%s=v4l2_capability.bus_info\n",
-                               &v4l2_capability.bus_info[0]);
-               }
-               if (copy_to_user((void __user *)arg, &v4l2_capability,
-                               sizeof(struct v4l2_capability))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_ENUMINPUT: {
-               struct v4l2_input v4l2_input;
-               u32 index;
-
-               JOM(8, "VIDIOC_ENUMINPUT\n");
-
-               if (copy_from_user(&v4l2_input, (void __user *)arg,
-                                       sizeof(struct v4l2_input))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               index = v4l2_input.index;
-               memset(&v4l2_input, 0, sizeof(struct v4l2_input));
-
-               switch (index) {
-               case 0: {
-                       v4l2_input.index = index;
-                       strcpy(&v4l2_input.name[0], "CVBS0");
-                       v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
-                       v4l2_input.audioset = 0x01;
-                       v4l2_input.tuner = 0;
-                       v4l2_input.std = V4L2_STD_PAL |
-                                       V4L2_STD_SECAM |
-                                       V4L2_STD_NTSC ;
-                       v4l2_input.status = 0;
-                       JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
-                       break;
-               }
-               case 1: {
-                       v4l2_input.index = index;
-                       strcpy(&v4l2_input.name[0], "CVBS1");
-                       v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
-                       v4l2_input.audioset = 0x01;
-                       v4l2_input.tuner = 0;
-                       v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM |
-                                       V4L2_STD_NTSC;
-                       v4l2_input.status = 0;
-                       JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
-                       break;
-               }
-               case 2: {
-                       v4l2_input.index = index;
-                       strcpy(&v4l2_input.name[0], "CVBS2");
-                       v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
-                       v4l2_input.audioset = 0x01;
-                       v4l2_input.tuner = 0;
-                       v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM |
-                                       V4L2_STD_NTSC ;
-                       v4l2_input.status = 0;
-                       JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
-                       break;
-               }
-               case 3: {
-                       v4l2_input.index = index;
-                       strcpy(&v4l2_input.name[0], "CVBS3");
-                       v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
-                       v4l2_input.audioset = 0x01;
-                       v4l2_input.tuner = 0;
-                       v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM |
-                                       V4L2_STD_NTSC ;
-                       v4l2_input.status = 0;
-                       JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
-                       break;
-               }
-               case 4: {
-                       v4l2_input.index = index;
-                       strcpy(&v4l2_input.name[0], "CVBS4");
-                       v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
-                       v4l2_input.audioset = 0x01;
-                       v4l2_input.tuner = 0;
-                       v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM |
-                                       V4L2_STD_NTSC ;
-                       v4l2_input.status = 0;
-                       JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
-                       break;
-               }
-               case 5: {
-                       v4l2_input.index = index;
-                       strcpy(&v4l2_input.name[0], "S-VIDEO");
-                       v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
-                       v4l2_input.audioset = 0x01;
-                       v4l2_input.tuner = 0;
-                       v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM |
-                                       V4L2_STD_NTSC ;
-                       v4l2_input.status = 0;
-                       JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
-                       break;
-               }
-               default: {
-                       JOM(8, "%i=index: exhausts inputs\n", index);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-               }
-
-               if (copy_to_user((void __user *)arg, &v4l2_input,
-                               sizeof(struct v4l2_input))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_G_INPUT: {
-               u32 index;
-
-               JOM(8, "VIDIOC_G_INPUT\n");
-               index = (u32)peasycap->input;
-               JOM(8, "user is told: %i\n", index);
-               if (copy_to_user((void __user *)arg, &index, sizeof(u32))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_S_INPUT:
-       {
-               u32 index;
-               int rc;
-
-               JOM(8, "VIDIOC_S_INPUT\n");
-
-               if (0 != copy_from_user(&index, (void __user *)arg, sizeof(u32))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               JOM(8, "user requests input %i\n", index);
-
-               if ((int)index == peasycap->input) {
-                       SAM("requested input already in effect\n");
-                       break;
-               }
-
-               if ((0 > index) || (INPUT_MANY <= index)) {
-                       JOM(8, "ERROR:  bad requested input: %i\n", index);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-
-               rc = easycap_newinput(peasycap, (int)index);
-               if (0 == rc) {
-                       JOM(8, "newinput(.,%i) OK\n", (int)index);
-               } else {
-                       SAM("ERROR: newinput(.,%i) returned %i\n", (int)index, rc);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_ENUMAUDIO: {
-               JOM(8, "VIDIOC_ENUMAUDIO\n");
-               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-               return -EINVAL;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_ENUMAUDOUT: {
-               struct v4l2_audioout v4l2_audioout;
-
-               JOM(8, "VIDIOC_ENUMAUDOUT\n");
-
-               if (copy_from_user(&v4l2_audioout, (void __user *)arg,
-                                       sizeof(struct v4l2_audioout))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               if (0 != v4l2_audioout.index) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-               memset(&v4l2_audioout, 0, sizeof(struct v4l2_audioout));
-               v4l2_audioout.index = 0;
-               strcpy(&v4l2_audioout.name[0], "Soundtrack");
-
-               if (copy_to_user((void __user *)arg, &v4l2_audioout,
-                               sizeof(struct v4l2_audioout))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_QUERYCTRL: {
-               int i1;
-               struct v4l2_queryctrl v4l2_queryctrl;
-
-               JOM(8, "VIDIOC_QUERYCTRL\n");
-
-               if (0 != copy_from_user(&v4l2_queryctrl, (void __user *)arg,
-                               sizeof(struct v4l2_queryctrl))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               i1 = 0;
-               while (0xFFFFFFFF != easycap_control[i1].id) {
-                       if (easycap_control[i1].id == v4l2_queryctrl.id) {
-                               JOM(8, "VIDIOC_QUERYCTRL  %s=easycap_control[%i]"
-                                   ".name\n", &easycap_control[i1].name[0], i1);
-                               memcpy(&v4l2_queryctrl, &easycap_control[i1],
-                                      sizeof(struct v4l2_queryctrl));
-                               break;
-                       }
-                       i1++;
-               }
-               if (0xFFFFFFFF == easycap_control[i1].id) {
-                       JOM(8, "%i=index: exhausts controls\n", i1);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-               if (copy_to_user((void __user *)arg, &v4l2_queryctrl,
-                               sizeof(struct v4l2_queryctrl))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_QUERYMENU: {
-               JOM(8, "VIDIOC_QUERYMENU unsupported\n");
-               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-               return -EINVAL;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_G_CTRL: {
-               struct v4l2_control *pv4l2_control;
-
-               JOM(8, "VIDIOC_G_CTRL\n");
-               pv4l2_control = memdup_user((void __user *)arg,
-                                           sizeof(struct v4l2_control));
-               if (IS_ERR(pv4l2_control)) {
-                       SAM("ERROR: copy from user failed\n");
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return PTR_ERR(pv4l2_control);
-               }
-
-               switch (pv4l2_control->id) {
-               case V4L2_CID_BRIGHTNESS: {
-                       pv4l2_control->value = peasycap->brightness;
-                       JOM(8, "user enquires brightness: %i\n", pv4l2_control->value);
-                       break;
-               }
-               case V4L2_CID_CONTRAST: {
-                       pv4l2_control->value = peasycap->contrast;
-                       JOM(8, "user enquires contrast: %i\n", pv4l2_control->value);
-                       break;
-               }
-               case V4L2_CID_SATURATION: {
-                       pv4l2_control->value = peasycap->saturation;
-                       JOM(8, "user enquires saturation: %i\n", pv4l2_control->value);
-                       break;
-               }
-               case V4L2_CID_HUE: {
-                       pv4l2_control->value = peasycap->hue;
-                       JOM(8, "user enquires hue: %i\n", pv4l2_control->value);
-                       break;
-               }
-               case V4L2_CID_AUDIO_VOLUME: {
-                       pv4l2_control->value = peasycap->volume;
-                       JOM(8, "user enquires volume: %i\n", pv4l2_control->value);
-                       break;
-               }
-               case V4L2_CID_AUDIO_MUTE: {
-                       if (1 == peasycap->mute)
-                               pv4l2_control->value = true;
-                       else
-                               pv4l2_control->value = false;
-                       JOM(8, "user enquires mute: %i\n", pv4l2_control->value);
-                       break;
-               }
-               default: {
-                       SAM("ERROR: unknown V4L2 control: 0x%08X=id\n",
-                           pv4l2_control->id);
-                       kfree(pv4l2_control);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-               }
-               if (copy_to_user((void __user *)arg, pv4l2_control,
-                               sizeof(struct v4l2_control))) {
-                       kfree(pv4l2_control);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               kfree(pv4l2_control);
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_S_CTRL: {
-               struct v4l2_control v4l2_control;
-
-               JOM(8, "VIDIOC_S_CTRL\n");
-
-               if (0 != copy_from_user(&v4l2_control, (void __user *)arg,
-                               sizeof(struct v4l2_control))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               switch (v4l2_control.id) {
-               case V4L2_CID_BRIGHTNESS: {
-                       JOM(8, "user requests brightness %i\n", v4l2_control.value);
-                       if (0 != adjust_brightness(peasycap, v4l2_control.value))
-                               ;
-                       break;
-               }
-               case V4L2_CID_CONTRAST: {
-                       JOM(8, "user requests contrast %i\n", v4l2_control.value);
-                       if (0 != adjust_contrast(peasycap, v4l2_control.value))
-                               ;
-                       break;
-               }
-               case V4L2_CID_SATURATION: {
-                       JOM(8, "user requests saturation %i\n", v4l2_control.value);
-                       if (0 != adjust_saturation(peasycap, v4l2_control.value))
-                               ;
-                       break;
-               }
-               case V4L2_CID_HUE: {
-                       JOM(8, "user requests hue %i\n", v4l2_control.value);
-                       if (0 != adjust_hue(peasycap, v4l2_control.value))
-                               ;
-                       break;
-               }
-               case V4L2_CID_AUDIO_VOLUME: {
-                       JOM(8, "user requests volume %i\n", v4l2_control.value);
-                       if (0 != adjust_volume(peasycap, v4l2_control.value))
-                               ;
-                       break;
-               }
-               case V4L2_CID_AUDIO_MUTE: {
-                       int mute;
-
-                       JOM(8, "user requests mute %i\n", v4l2_control.value);
-                       if (v4l2_control.value)
-                               mute = 1;
-                       else
-                               mute = 0;
-
-                       if (0 != adjust_mute(peasycap, mute))
-                               SAM("WARNING: failed to adjust mute to %i\n", mute);
-                       break;
-               }
-               default: {
-                       SAM("ERROR: unknown V4L2 control: 0x%08X=id\n",
-                           v4l2_control.id);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-               }
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_S_EXT_CTRLS: {
-               JOM(8, "VIDIOC_S_EXT_CTRLS unsupported\n");
-               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-               return -EINVAL;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_ENUM_FMT: {
-               u32 index;
-               struct v4l2_fmtdesc v4l2_fmtdesc;
-
-               JOM(8, "VIDIOC_ENUM_FMT\n");
-
-               if (0 != copy_from_user(&v4l2_fmtdesc, (void __user *)arg,
-                               sizeof(struct v4l2_fmtdesc))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               index = v4l2_fmtdesc.index;
-               memset(&v4l2_fmtdesc, 0, sizeof(struct v4l2_fmtdesc));
-
-               v4l2_fmtdesc.index = index;
-               v4l2_fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-               switch (index) {
-               case 0: {
-                       v4l2_fmtdesc.flags = 0;
-                       strcpy(&v4l2_fmtdesc.description[0], "uyvy");
-                       v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_UYVY;
-                       JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
-                       break;
-               }
-               case 1: {
-                       v4l2_fmtdesc.flags = 0;
-                       strcpy(&v4l2_fmtdesc.description[0], "yuy2");
-                       v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_YUYV;
-                       JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
-                       break;
-               }
-               case 2: {
-                       v4l2_fmtdesc.flags = 0;
-                       strcpy(&v4l2_fmtdesc.description[0], "rgb24");
-                       v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_RGB24;
-                       JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
-                       break;
-               }
-               case 3: {
-                       v4l2_fmtdesc.flags = 0;
-                       strcpy(&v4l2_fmtdesc.description[0], "rgb32");
-                       v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_RGB32;
-                       JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
-                       break;
-               }
-               case 4: {
-                       v4l2_fmtdesc.flags = 0;
-                       strcpy(&v4l2_fmtdesc.description[0], "bgr24");
-                       v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_BGR24;
-                       JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
-                       break;
-               }
-               case 5: {
-                       v4l2_fmtdesc.flags = 0;
-                       strcpy(&v4l2_fmtdesc.description[0], "bgr32");
-                       v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_BGR32;
-                       JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
-                       break;
-               }
-               default: {
-                       JOM(8, "%i=index: exhausts formats\n", index);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-               }
-               if (copy_to_user((void __user *)arg, &v4l2_fmtdesc,
-                               sizeof(struct v4l2_fmtdesc))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-/*
-        *  THE RESPONSE TO VIDIOC_ENUM_FRAMESIZES MUST BE CONDITIONED ON THE
-        *  THE CURRENT STANDARD, BECAUSE THAT IS WHAT gstreamer EXPECTS.  BEWARE.
-       */
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_ENUM_FRAMESIZES: {
-               u32 index;
-               struct v4l2_frmsizeenum v4l2_frmsizeenum;
-
-               JOM(8, "VIDIOC_ENUM_FRAMESIZES\n");
-
-               if (0 != copy_from_user(&v4l2_frmsizeenum, (void __user *)arg,
-                               sizeof(struct v4l2_frmsizeenum))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               index = v4l2_frmsizeenum.index;
-
-               v4l2_frmsizeenum.type = (u32) V4L2_FRMSIZE_TYPE_DISCRETE;
-
-               if (peasycap->ntsc) {
-                       switch (index) {
-                       case 0: {
-                               v4l2_frmsizeenum.discrete.width = 640;
-                               v4l2_frmsizeenum.discrete.height = 480;
-                               JOM(8, "%i=index: %ix%i\n", index,
-                                   (int)(v4l2_frmsizeenum.
-                                         discrete.width),
-                                   (int)(v4l2_frmsizeenum.
-                                         discrete.height));
-                               break;
-                       }
-                       case 1: {
-                               v4l2_frmsizeenum.discrete.width = 320;
-                               v4l2_frmsizeenum.discrete.height = 240;
-                               JOM(8, "%i=index: %ix%i\n", index,
-                                   (int)(v4l2_frmsizeenum.
-                                         discrete.width),
-                                   (int)(v4l2_frmsizeenum.
-                                         discrete.height));
-                               break;
-                       }
-                       case 2: {
-                               v4l2_frmsizeenum.discrete.width = 720;
-                               v4l2_frmsizeenum.discrete.height = 480;
-                               JOM(8, "%i=index: %ix%i\n", index,
-                                   (int)(v4l2_frmsizeenum.
-                                         discrete.width),
-                                   (int)(v4l2_frmsizeenum.
-                                         discrete.height));
-                               break;
-                       }
-                       case 3: {
-                               v4l2_frmsizeenum.discrete.width = 360;
-                               v4l2_frmsizeenum.discrete.height = 240;
-                               JOM(8, "%i=index: %ix%i\n", index,
-                                   (int)(v4l2_frmsizeenum.
-                                         discrete.width),
-                                   (int)(v4l2_frmsizeenum.
-                                         discrete.height));
-                               break;
-                       }
-                       default: {
-                               JOM(8, "%i=index: exhausts framesizes\n", index);
-                               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                               return -EINVAL;
-                       }
-                       }
-               } else {
-                       switch (index) {
-                       case 0: {
-                               v4l2_frmsizeenum.discrete.width = 640;
-                               v4l2_frmsizeenum.discrete.height = 480;
-                               JOM(8, "%i=index: %ix%i\n", index,
-                                   (int)(v4l2_frmsizeenum.
-                                         discrete.width),
-                                   (int)(v4l2_frmsizeenum.
-                                         discrete.height));
-                               break;
-                       }
-                       case 1: {
-                               v4l2_frmsizeenum.discrete.width = 320;
-                               v4l2_frmsizeenum.discrete.height = 240;
-                               JOM(8, "%i=index: %ix%i\n", index,
-                                   (int)(v4l2_frmsizeenum.
-                                         discrete.width),
-                                   (int)(v4l2_frmsizeenum.
-                                         discrete.height));
-                               break;
-                       }
-                       case 2: {
-                               v4l2_frmsizeenum.discrete.width = 704;
-                               v4l2_frmsizeenum.discrete.height = 576;
-                               JOM(8, "%i=index: %ix%i\n", index,
-                                   (int)(v4l2_frmsizeenum.
-                                         discrete.width),
-                                   (int)(v4l2_frmsizeenum.
-                                         discrete.height));
-                               break;
-                       }
-                       case 3: {
-                               v4l2_frmsizeenum.discrete.width = 720;
-                               v4l2_frmsizeenum.discrete.height = 576;
-                               JOM(8, "%i=index: %ix%i\n", index,
-                                   (int)(v4l2_frmsizeenum.
-                                         discrete.width),
-                                   (int)(v4l2_frmsizeenum.
-                                         discrete.height));
-                               break;
-                       }
-                       case 4: {
-                               v4l2_frmsizeenum.discrete.width = 360;
-                               v4l2_frmsizeenum.discrete.height = 288;
-                               JOM(8, "%i=index: %ix%i\n", index,
-                                   (int)(v4l2_frmsizeenum.
-                                         discrete.width),
-                                   (int)(v4l2_frmsizeenum.
-                                         discrete.height));
-                               break;
-                       }
-                       default: {
-                               JOM(8, "%i=index: exhausts framesizes\n", index);
-                               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                               return -EINVAL;
-                       }
-                       }
-               }
-               if (copy_to_user((void __user *)arg, &v4l2_frmsizeenum,
-                               sizeof(struct v4l2_frmsizeenum))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-/*
-        *  THE RESPONSE TO VIDIOC_ENUM_FRAMEINTERVALS MUST BE CONDITIONED ON THE
-        *  THE CURRENT STANDARD, BECAUSE THAT IS WHAT gstreamer EXPECTS.  BEWARE.
-       */
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_ENUM_FRAMEINTERVALS: {
-               u32 index;
-               int denominator;
-               struct v4l2_frmivalenum v4l2_frmivalenum;
-
-               JOM(8, "VIDIOC_ENUM_FRAMEINTERVALS\n");
-
-               if (peasycap->fps)
-                       denominator = peasycap->fps;
-               else {
-                       if (peasycap->ntsc)
-                               denominator = 30;
-                       else
-                               denominator = 25;
-               }
-
-               if (0 != copy_from_user(&v4l2_frmivalenum, (void __user *)arg,
-                               sizeof(struct v4l2_frmivalenum))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               index = v4l2_frmivalenum.index;
-
-               v4l2_frmivalenum.type = (u32) V4L2_FRMIVAL_TYPE_DISCRETE;
-
-               switch (index) {
-               case 0: {
-                       v4l2_frmivalenum.discrete.numerator = 1;
-                       v4l2_frmivalenum.discrete.denominator = denominator;
-                       JOM(8, "%i=index: %i/%i\n", index,
-                           (int)(v4l2_frmivalenum.discrete.numerator),
-                           (int)(v4l2_frmivalenum.discrete.denominator));
-                       break;
-               }
-               case 1: {
-                       v4l2_frmivalenum.discrete.numerator = 1;
-                       v4l2_frmivalenum.discrete.denominator = denominator/5;
-                       JOM(8, "%i=index: %i/%i\n", index,
-                           (int)(v4l2_frmivalenum.discrete.numerator),
-                           (int)(v4l2_frmivalenum.discrete.denominator));
-                       break;
-               }
-               default: {
-                       JOM(8, "%i=index: exhausts frameintervals\n", index);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-               }
-               if (copy_to_user((void __user *)arg, &v4l2_frmivalenum,
-                                       sizeof(struct v4l2_frmivalenum))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_G_FMT: {
-               struct v4l2_format *pv4l2_format;
-               struct v4l2_pix_format *pv4l2_pix_format;
-
-               JOM(8, "VIDIOC_G_FMT\n");
-               pv4l2_format = kzalloc(sizeof(struct v4l2_format), GFP_KERNEL);
-               if (!pv4l2_format) {
-                       SAM("ERROR: out of memory\n");
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -ENOMEM;
-               }
-               pv4l2_pix_format = kzalloc(sizeof(struct v4l2_pix_format), GFP_KERNEL);
-               if (!pv4l2_pix_format) {
-                       SAM("ERROR: out of memory\n");
-                       kfree(pv4l2_format);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -ENOMEM;
-               }
-               if (0 != copy_from_user(pv4l2_format, (void __user *)arg,
-                                       sizeof(struct v4l2_format))) {
-                       kfree(pv4l2_format);
-                       kfree(pv4l2_pix_format);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               if (pv4l2_format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-                       kfree(pv4l2_format);
-                       kfree(pv4l2_pix_format);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-
-               memset(pv4l2_pix_format, 0, sizeof(struct v4l2_pix_format));
-               pv4l2_format->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               memcpy(&pv4l2_format->fmt.pix,
-                      &easycap_format[peasycap->format_offset]
-                      .v4l2_format.fmt.pix, sizeof(struct v4l2_pix_format));
-               JOM(8, "user is told: %s\n",
-                   &easycap_format[peasycap->format_offset].name[0]);
-
-               if (copy_to_user((void __user *)arg, pv4l2_format,
-                                       sizeof(struct v4l2_format))) {
-                       kfree(pv4l2_format);
-                       kfree(pv4l2_pix_format);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               kfree(pv4l2_format);
-               kfree(pv4l2_pix_format);
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_TRY_FMT:
-       case VIDIOC_S_FMT: {
-               struct v4l2_format v4l2_format;
-               struct v4l2_pix_format v4l2_pix_format;
-               bool try;
-               int best_format;
-
-               if (VIDIOC_TRY_FMT == cmd) {
-                       JOM(8, "VIDIOC_TRY_FMT\n");
-                       try = true;
-               } else {
-                       JOM(8, "VIDIOC_S_FMT\n");
-                       try = false;
-               }
-
-               if (0 != copy_from_user(&v4l2_format, (void __user *)arg,
-                                       sizeof(struct v4l2_format))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               best_format = adjust_format(peasycap,
-                                       v4l2_format.fmt.pix.width,
-                                       v4l2_format.fmt.pix.height,
-                                       v4l2_format.fmt.pix.pixelformat,
-                                       v4l2_format.fmt.pix.field,
-                                       try);
-               if (0 > best_format) {
-                       if (-EBUSY == best_format) {
-                               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                               return -EBUSY;
-                       }
-                       JOM(8, "WARNING: adjust_format() returned %i\n", best_format);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -ENOENT;
-               }
-/*...........................................................................*/
-               memset(&v4l2_pix_format, 0, sizeof(struct v4l2_pix_format));
-               v4l2_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
-               memcpy(&(v4l2_format.fmt.pix),
-                       &(easycap_format[best_format].v4l2_format.fmt.pix),
-                       sizeof(v4l2_pix_format));
-               JOM(8, "user is told: %s\n", &easycap_format[best_format].name[0]);
-
-               if (copy_to_user((void __user *)arg, &v4l2_format,
-                                       sizeof(struct v4l2_format))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_CROPCAP: {
-               struct v4l2_cropcap v4l2_cropcap;
-
-               JOM(8, "VIDIOC_CROPCAP\n");
-
-               if (0 != copy_from_user(&v4l2_cropcap, (void __user *)arg,
-                                       sizeof(struct v4l2_cropcap))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               if (v4l2_cropcap.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
-                       JOM(8, "v4l2_cropcap.type != V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
-
-               memset(&v4l2_cropcap, 0, sizeof(struct v4l2_cropcap));
-               v4l2_cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               v4l2_cropcap.bounds.left      = 0;
-               v4l2_cropcap.bounds.top       = 0;
-               v4l2_cropcap.bounds.width     = peasycap->width;
-               v4l2_cropcap.bounds.height    = peasycap->height;
-               v4l2_cropcap.defrect.left     = 0;
-               v4l2_cropcap.defrect.top      = 0;
-               v4l2_cropcap.defrect.width    = peasycap->width;
-               v4l2_cropcap.defrect.height   = peasycap->height;
-               v4l2_cropcap.pixelaspect.numerator = 1;
-               v4l2_cropcap.pixelaspect.denominator = 1;
-
-               JOM(8, "user is told: %ix%i\n", peasycap->width, peasycap->height);
-
-               if (copy_to_user((void __user *)arg, &v4l2_cropcap,
-                                       sizeof(struct v4l2_cropcap))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_G_CROP:
-       case VIDIOC_S_CROP: {
-               JOM(8, "VIDIOC_G_CROP|VIDIOC_S_CROP  unsupported\n");
-               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-               return -EINVAL;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_QUERYSTD: {
-               JOM(8, "VIDIOC_QUERYSTD: "
-                   "EasyCAP is incapable of detecting standard\n");
-               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-               return -EINVAL;
-               break;
-       }
-       /*-------------------------------------------------------------------*/
-       /*
-        *  THE MANIPULATIONS INVOLVING last0,last1,last2,last3
-        *  CONSTITUTE A WORKAROUND *  FOR WHAT APPEARS TO BE
-        *  A BUG IN 64-BIT mplayer.
-        *  NOT NEEDED, BUT HOPEFULLY HARMLESS, FOR 32-BIT mplayer.
-        */
-       /*------------------------------------------------------------------*/
-       case VIDIOC_ENUMSTD: {
-               int last0 = -1, last1 = -1, last2 = -1, last3 = -1;
-               struct v4l2_standard v4l2_standard;
-               u32 index;
-               struct easycap_standard const *peasycap_standard;
-
-               JOM(8, "VIDIOC_ENUMSTD\n");
-
-               if (0 != copy_from_user(&v4l2_standard, (void __user *)arg,
-                                       sizeof(struct v4l2_standard))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               index = v4l2_standard.index;
-
-               last3 = last2;
-               last2 = last1;
-               last1 = last0;
-               last0 = index;
-               if ((index == last3) && (index == last2) &&
-                   (index == last1) && (index == last0)) {
-                       index++;
-                       last3 = last2;
-                       last2 = last1;
-                       last1 = last0;
-                       last0 = index;
-               }
-
-               memset(&v4l2_standard, 0, sizeof(struct v4l2_standard));
-
-               peasycap_standard = &easycap_standard[0];
-               while (0xFFFF != peasycap_standard->mask) {
-                       if ((int)(peasycap_standard - &easycap_standard[0]) == index)
-                               break;
-                       peasycap_standard++;
-               }
-               if (0xFFFF == peasycap_standard->mask) {
-                       JOM(8, "%i=index: exhausts standards\n", index);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-               JOM(8, "%i=index: %s\n", index,
-                   &(peasycap_standard->v4l2_standard.name[0]));
-               memcpy(&v4l2_standard, &(peasycap_standard->v4l2_standard),
-                      sizeof(struct v4l2_standard));
-
-               v4l2_standard.index = index;
-
-               if (copy_to_user((void __user *)arg, &v4l2_standard,
-                               sizeof(struct v4l2_standard))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_G_STD: {
-               v4l2_std_id std_id;
-               struct easycap_standard const *peasycap_standard;
-
-               JOM(8, "VIDIOC_G_STD\n");
-
-               if (0 > peasycap->standard_offset) {
-                       JOM(8, "%i=peasycap->standard_offset\n",
-                           peasycap->standard_offset);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EBUSY;
-               }
-
-               if (0 != copy_from_user(&std_id, (void __user *)arg,
-                                       sizeof(v4l2_std_id))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               peasycap_standard = &easycap_standard[peasycap->standard_offset];
-               std_id = peasycap_standard->v4l2_standard.id;
-
-               JOM(8, "user is told: %s\n",
-                   &peasycap_standard->v4l2_standard.name[0]);
-
-               if (copy_to_user((void __user *)arg, &std_id,
-                                       sizeof(v4l2_std_id))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_S_STD: {
-               v4l2_std_id std_id;
-               int rc;
-
-               JOM(8, "VIDIOC_S_STD\n");
-
-               if (0 != copy_from_user(&std_id, (void __user *)arg,
-                                       sizeof(v4l2_std_id))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               JOM(8, "User requests standard: 0x%08X%08X\n",
-                   (int)((std_id & (((v4l2_std_id)0xFFFFFFFF) << 32)) >> 32),
-                   (int)(std_id & ((v4l2_std_id)0xFFFFFFFF)));
-
-               rc = adjust_standard(peasycap, std_id);
-               if (0 > rc) {
-                       JOM(8, "WARNING: adjust_standard() returned %i\n", rc);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -ENOENT;
-               }
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_REQBUFS: {
-               int nbuffers;
-               struct v4l2_requestbuffers v4l2_requestbuffers;
-
-               JOM(8, "VIDIOC_REQBUFS\n");
-
-               if (0 != copy_from_user(&v4l2_requestbuffers,
-                                       (void __user *)arg,
-                                       sizeof(struct v4l2_requestbuffers))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               if (v4l2_requestbuffers.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-               if (v4l2_requestbuffers.memory != V4L2_MEMORY_MMAP) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-               nbuffers = v4l2_requestbuffers.count;
-               JOM(8, "                   User requests %i buffers ...\n", nbuffers);
-               if (nbuffers < 2)
-                       nbuffers = 2;
-               if (nbuffers > FRAME_BUFFER_MANY)
-                       nbuffers = FRAME_BUFFER_MANY;
-               if (v4l2_requestbuffers.count == nbuffers) {
-                       JOM(8, "                   ... agree to  %i buffers\n",
-                           nbuffers);
-               } else {
-                       JOM(8, "                  ... insist on  %i buffers\n",
-                           nbuffers);
-                       v4l2_requestbuffers.count = nbuffers;
-               }
-               peasycap->frame_buffer_many = nbuffers;
-
-               if (copy_to_user((void __user *)arg, &v4l2_requestbuffers,
-                                       sizeof(struct v4l2_requestbuffers))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_QUERYBUF: {
-               u32 index;
-               struct v4l2_buffer v4l2_buffer;
-
-               JOM(8, "VIDIOC_QUERYBUF\n");
-
-               if (peasycap->video_eof) {
-                       JOM(8, "returning -EIO because  %i=video_eof\n",
-                           peasycap->video_eof);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EIO;
-               }
-
-               if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg,
-                                       sizeof(struct v4l2_buffer))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-               index = v4l2_buffer.index;
-               if (index < 0 || index >= peasycap->frame_buffer_many)
-                       return -EINVAL;
-               memset(&v4l2_buffer, 0, sizeof(struct v4l2_buffer));
-               v4l2_buffer.index = index;
-               v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               v4l2_buffer.bytesused = peasycap->frame_buffer_used;
-               v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED |
-                                       peasycap->done[index] |
-                                       peasycap->queued[index];
-               v4l2_buffer.field = V4L2_FIELD_NONE;
-               v4l2_buffer.memory = V4L2_MEMORY_MMAP;
-               v4l2_buffer.m.offset = index * FRAME_BUFFER_SIZE;
-               v4l2_buffer.length = FRAME_BUFFER_SIZE;
-
-               JOM(16, "  %10i=index\n", v4l2_buffer.index);
-               JOM(16, "  0x%08X=type\n", v4l2_buffer.type);
-               JOM(16, "  %10i=bytesused\n", v4l2_buffer.bytesused);
-               JOM(16, "  0x%08X=flags\n", v4l2_buffer.flags);
-               JOM(16, "  %10i=field\n", v4l2_buffer.field);
-               JOM(16, "  %10li=timestamp.tv_usec\n",
-                   (long)v4l2_buffer.timestamp.tv_usec);
-               JOM(16, "  %10i=sequence\n", v4l2_buffer.sequence);
-               JOM(16, "  0x%08X=memory\n", v4l2_buffer.memory);
-               JOM(16, "  %10i=m.offset\n", v4l2_buffer.m.offset);
-               JOM(16, "  %10i=length\n", v4l2_buffer.length);
-
-               if (copy_to_user((void __user *)arg, &v4l2_buffer,
-                                       sizeof(struct v4l2_buffer))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_QBUF: {
-               struct v4l2_buffer v4l2_buffer;
-
-               JOM(8, "VIDIOC_QBUF\n");
-
-               if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg,
-                                       sizeof(struct v4l2_buffer))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-               if (v4l2_buffer.memory != V4L2_MEMORY_MMAP) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-               if (v4l2_buffer.index < 0 ||
-                   v4l2_buffer.index >= peasycap->frame_buffer_many) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-               v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED;
-
-               peasycap->done[v4l2_buffer.index]   = 0;
-               peasycap->queued[v4l2_buffer.index] = V4L2_BUF_FLAG_QUEUED;
-
-               if (copy_to_user((void __user *)arg, &v4l2_buffer,
-                                       sizeof(struct v4l2_buffer))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               JOM(8, ".....   user queueing frame buffer %i\n",
-                   (int)v4l2_buffer.index);
-
-               peasycap->frame_lock = 0;
-
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_DQBUF:
-       {
-               struct timeval timeval, timeval2;
-               int i, j;
-               struct v4l2_buffer v4l2_buffer;
-               int rcdq;
-               u16 input;
-
-               JOM(8, "VIDIOC_DQBUF\n");
-
-               if ((peasycap->video_idle) || (peasycap->video_eof)) {
-                       JOM(8, "returning -EIO because  "
-                           "%i=video_idle  %i=video_eof\n",
-                           peasycap->video_idle, peasycap->video_eof);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EIO;
-               }
-
-               if (copy_from_user(&v4l2_buffer, (void __user *)arg,
-                                 sizeof(struct v4l2_buffer))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-
-               if (peasycap->offerfields) {
-                       /*---------------------------------------------------*/
-                       /*
-                        *  IN ITS 50 "fps" MODE tvtime SEEMS ALWAYS TO REQUEST
-                        *  V4L2_FIELD_BOTTOM
-                        */
-                       /*---------------------------------------------------*/
-                       if (V4L2_FIELD_TOP == v4l2_buffer.field)
-                               JOM(8, "user wants V4L2_FIELD_TOP\n");
-                       else if (V4L2_FIELD_BOTTOM == v4l2_buffer.field)
-                               JOM(8, "user wants V4L2_FIELD_BOTTOM\n");
-                       else if (V4L2_FIELD_ANY == v4l2_buffer.field)
-                               JOM(8, "user wants V4L2_FIELD_ANY\n");
-                       else
-                               JOM(8, "user wants V4L2_FIELD_...UNKNOWN: %i\n",
-                                   v4l2_buffer.field);
-               }
-
-               if (!peasycap->video_isoc_streaming) {
-                       JOM(16, "returning -EIO because video urbs not streaming\n");
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EIO;
-               }
-       /*-------------------------------------------------------------------*/
-       /*
-        *  IF THE USER HAS PREVIOUSLY CALLED easycap_poll(),
-        *  AS DETERMINED BY FINDING
-        *  THE FLAG peasycap->polled SET, THERE MUST BE
-        *  NO FURTHER WAIT HERE.  IN THIS
-        *  CASE, JUST CHOOSE THE FRAME INDICATED BY peasycap->frame_read
-        */
-       /*-------------------------------------------------------------------*/
-
-               if (!peasycap->polled) {
-                       do {
-                               rcdq = easycap_video_dqbuf(peasycap, 0);
-                               if (-EIO == rcdq) {
-                                       JOM(8, "returning -EIO because "
-                                           "dqbuf() returned -EIO\n");
-                                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                                       return -EIO;
-                               }
-                       } while (0 != rcdq);
-               } else {
-                       if (peasycap->video_eof) {
-                               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                               return -EIO;
-                       }
-               }
-               if (V4L2_BUF_FLAG_DONE != peasycap->done[peasycap->frame_read]) {
-                       JOM(8, "V4L2_BUF_FLAG_DONE != 0x%08X\n",
-                           peasycap->done[peasycap->frame_read]);
-               }
-               peasycap->polled = 0;
-
-               if (!(peasycap->isequence % 10)) {
-                       for (i = 0; i < 179; i++)
-                               peasycap->merit[i] = peasycap->merit[i+1];
-                       peasycap->merit[179] = merit_saa(peasycap->pusb_device);
-                       j = 0;
-                       for (i = 0; i < 180; i++)
-                               j += peasycap->merit[i];
-                       if (90 < j) {
-                               SAM("easycap driver shutting down "
-                                   "on condition blue\n");
-                               peasycap->video_eof = 1;
-                               peasycap->audio_eof = 1;
-                       }
-               }
-
-               v4l2_buffer.index = peasycap->frame_read;
-               v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-               v4l2_buffer.bytesused = peasycap->frame_buffer_used;
-               v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE;
-               if (peasycap->offerfields)
-                       v4l2_buffer.field = V4L2_FIELD_BOTTOM;
-               else
-                       v4l2_buffer.field = V4L2_FIELD_NONE;
-               do_gettimeofday(&timeval);
-               timeval2 = timeval;
-
-               v4l2_buffer.timestamp = timeval2;
-               v4l2_buffer.sequence = peasycap->isequence++;
-               v4l2_buffer.memory = V4L2_MEMORY_MMAP;
-               v4l2_buffer.m.offset = v4l2_buffer.index * FRAME_BUFFER_SIZE;
-               v4l2_buffer.length = FRAME_BUFFER_SIZE;
-
-               JOM(16, "  %10i=index\n", v4l2_buffer.index);
-               JOM(16, "  0x%08X=type\n", v4l2_buffer.type);
-               JOM(16, "  %10i=bytesused\n", v4l2_buffer.bytesused);
-               JOM(16, "  0x%08X=flags\n", v4l2_buffer.flags);
-               JOM(16, "  %10i=field\n", v4l2_buffer.field);
-               JOM(16, "  %10li=timestamp.tv_sec\n",
-                   (long)v4l2_buffer.timestamp.tv_sec);
-               JOM(16, "  %10li=timestamp.tv_usec\n",
-                   (long)v4l2_buffer.timestamp.tv_usec);
-               JOM(16, "  %10i=sequence\n", v4l2_buffer.sequence);
-               JOM(16, "  0x%08X=memory\n", v4l2_buffer.memory);
-               JOM(16, "  %10i=m.offset\n", v4l2_buffer.m.offset);
-               JOM(16, "  %10i=length\n", v4l2_buffer.length);
-
-               if (copy_to_user((void __user *)arg, &v4l2_buffer,
-                                       sizeof(struct v4l2_buffer))) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               input = peasycap->frame_buffer[peasycap->frame_read][0].input;
-               if (0x08 & input) {
-                       JOM(8, "user is offered frame buffer %i, input %i\n",
-                           peasycap->frame_read, (0x07 & input));
-               } else {
-                       JOM(8, "user is offered frame buffer %i\n",
-                           peasycap->frame_read);
-               }
-               peasycap->frame_lock = 1;
-               JOM(8, "%i=peasycap->frame_fill\n", peasycap->frame_fill);
-               if (peasycap->frame_read == peasycap->frame_fill) {
-                       if (peasycap->frame_lock) {
-                               JOM(8, "WORRY:  filling frame buffer "
-                                   "while offered to user\n");
-                       }
-               }
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_STREAMON: {
-               int i;
-
-               JOM(8, "VIDIOC_STREAMON\n");
-
-               peasycap->isequence = 0;
-               for (i = 0; i < 180; i++)
-                       peasycap->merit[i] = 0;
-               if (!peasycap->pusb_device) {
-                       SAM("ERROR: peasycap->pusb_device is NULL\n");
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               easycap_video_submit_urbs(peasycap);
-               peasycap->video_idle = 0;
-               peasycap->audio_idle = 0;
-               peasycap->video_eof = 0;
-               peasycap->audio_eof = 0;
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_STREAMOFF: {
-               JOM(8, "VIDIOC_STREAMOFF\n");
-
-               if (!peasycap->pusb_device) {
-                       SAM("ERROR: peasycap->pusb_device is NULL\n");
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-
-               peasycap->video_idle = 1;
-               peasycap->audio_idle = 1;
-/*---------------------------------------------------------------------------*/
-/*
- *  IF THE WAIT QUEUES ARE NOT CLEARED IN RESPONSE TO THE STREAMOFF COMMAND
- *  THE USERSPACE PROGRAM, E.G. mplayer, MAY HANG ON EXIT.   BEWARE.
- */
-/*---------------------------------------------------------------------------*/
-               JOM(8, "calling wake_up on wq_video and wq_audio\n");
-               wake_up_interruptible(&(peasycap->wq_video));
-               if (peasycap->psubstream)
-                       snd_pcm_period_elapsed(peasycap->psubstream);
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_G_PARM: {
-               struct v4l2_streamparm *pv4l2_streamparm;
-
-               JOM(8, "VIDIOC_G_PARM\n");
-               pv4l2_streamparm = memdup_user((void __user *)arg,
-                                              sizeof(struct v4l2_streamparm));
-               if (IS_ERR(pv4l2_streamparm)) {
-                       SAM("ERROR: copy from user failed\n");
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return PTR_ERR(pv4l2_streamparm);
-               }
-
-               if (pv4l2_streamparm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-                       kfree(pv4l2_streamparm);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EINVAL;
-               }
-               pv4l2_streamparm->parm.capture.capability = 0;
-               pv4l2_streamparm->parm.capture.capturemode = 0;
-               pv4l2_streamparm->parm.capture.timeperframe.numerator = 1;
-
-               if (peasycap->fps) {
-                       pv4l2_streamparm->parm.capture.timeperframe.
-                       denominator = peasycap->fps;
-               } else {
-                       if (peasycap->ntsc) {
-                               pv4l2_streamparm->parm.capture.timeperframe.
-                               denominator = 30;
-                       } else {
-                               pv4l2_streamparm->parm.capture.timeperframe.
-                               denominator = 25;
-                       }
-               }
-
-               pv4l2_streamparm->parm.capture.readbuffers =
-                       peasycap->frame_buffer_many;
-               pv4l2_streamparm->parm.capture.extendedmode = 0;
-               if (copy_to_user((void __user *)arg,
-                               pv4l2_streamparm,
-                               sizeof(struct v4l2_streamparm))) {
-                       kfree(pv4l2_streamparm);
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -EFAULT;
-               }
-               kfree(pv4l2_streamparm);
-               break;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_S_PARM: {
-               JOM(8, "VIDIOC_S_PARM unsupported\n");
-               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-               return -EINVAL;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_G_AUDIO: {
-               JOM(8, "VIDIOC_G_AUDIO unsupported\n");
-               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-               return -EINVAL;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_S_AUDIO: {
-               JOM(8, "VIDIOC_S_AUDIO unsupported\n");
-               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-               return -EINVAL;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_S_TUNER: {
-               JOM(8, "VIDIOC_S_TUNER unsupported\n");
-               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-               return -EINVAL;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_G_FBUF:
-       case VIDIOC_S_FBUF:
-       case VIDIOC_OVERLAY: {
-               JOM(8, "VIDIOC_G_FBUF|VIDIOC_S_FBUF|VIDIOC_OVERLAY unsupported\n");
-               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-               return -EINVAL;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       case VIDIOC_G_TUNER: {
-               JOM(8, "VIDIOC_G_TUNER unsupported\n");
-               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-               return -EINVAL;
-       }
-       case VIDIOC_G_FREQUENCY:
-       case VIDIOC_S_FREQUENCY: {
-               JOM(8, "VIDIOC_G_FREQUENCY|VIDIOC_S_FREQUENCY unsupported\n");
-               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-               return -EINVAL;
-       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       default: {
-               JOM(8, "ERROR: unrecognized V4L2 IOCTL command: 0x%08X\n", cmd);
-               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-               return -ENOIOCTLCMD;
-       }
-       }
-       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-       JOM(4, "unlocked easycapdc60_dongle[%i].mutex_video\n", kd);
-       return 0;
-}
-/*****************************************************************************/
diff --git a/drivers/staging/media/easycap/easycap_low.c b/drivers/staging/media/easycap/easycap_low.c
deleted file mode 100644 (file)
index 0380bab..0000000
+++ /dev/null
@@ -1,968 +0,0 @@
-/*****************************************************************************
-*                                                                            *
-*                                                                            *
-*  easycap_low.c                                                             *
-*                                                                            *
-*                                                                            *
-*****************************************************************************/
-/*
- *
- *  Copyright (C) 2010 R.M. Thomas  <rmthomas@sciolus.org>
- *
- *
- *  This 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.
- *
- *  The software 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 software; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
-*/
-/*****************************************************************************/
-/*
- *  ACKNOWLEGEMENTS AND REFERENCES
- *  ------------------------------
- *  This driver makes use of register information contained in the Syntek
- *  Semicon DC-1125 driver hosted at
- *               http://sourceforge.net/projects/syntekdriver/.
- *  Particularly useful has been a patch to the latter driver provided by
- *  Ivor Hewitt in January 2009.  The NTSC implementation is taken from the
- *  work of Ben Trask.
-*/
-/****************************************************************************/
-
-#include "easycap.h"
-
-
-#define GET(X, Y, Z) do { \
-       int __rc; \
-       *(Z) = (u16)0; \
-       __rc = regget(X, Y, Z, sizeof(u8)); \
-       if (0 > __rc) { \
-               JOT(8, ":-(%i\n", __LINE__);  return __rc; \
-       } \
-} while (0)
-
-#define SET(X, Y, Z) do { \
-       int __rc; \
-       __rc = regset(X, Y, Z); \
-       if (0 > __rc) { \
-               JOT(8, ":-(%i\n", __LINE__);  return __rc; \
-       } \
-} while (0)
-
-/*--------------------------------------------------------------------------*/
-static const struct stk1160config {
-       u16 reg;
-       u16 set;
-} stk1160configPAL[] = {
-               {0x000, 0x0098},
-               {0x002, 0x0093},
-
-               {0x001, 0x0003},
-               {0x003, 0x0080},
-               {0x00D, 0x0000},
-               {0x00F, 0x0002},
-               {0x018, 0x0010},
-               {0x019, 0x0000},
-               {0x01A, 0x0014},
-               {0x01B, 0x000E},
-               {0x01C, 0x0046},
-
-               {0x100, 0x0033},
-               {0x103, 0x0000},
-               {0x104, 0x0000},
-               {0x105, 0x0000},
-               {0x106, 0x0000},
-
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-/*
- *  RESOLUTION 640x480
-*/
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-               {0x110, 0x0008},
-               {0x111, 0x0000},
-               {0x112, 0x0020},
-               {0x113, 0x0000},
-               {0x114, 0x0508},
-               {0x115, 0x0005},
-               {0x116, 0x0110},
-               {0x117, 0x0001},
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
-               {0x202, 0x000F},
-               {0x203, 0x004A},
-               {0x2FF, 0x0000},
-
-               {0xFFF, 0xFFFF}
-};
-/*--------------------------------------------------------------------------*/
-static const struct stk1160config stk1160configNTSC[] = {
-               {0x000, 0x0098},
-               {0x002, 0x0093},
-
-               {0x001, 0x0003},
-               {0x003, 0x0080},
-               {0x00D, 0x0000},
-               {0x00F, 0x0002},
-               {0x018, 0x0010},
-               {0x019, 0x0000},
-               {0x01A, 0x0014},
-               {0x01B, 0x000E},
-               {0x01C, 0x0046},
-
-               {0x100, 0x0033},
-               {0x103, 0x0000},
-               {0x104, 0x0000},
-               {0x105, 0x0000},
-               {0x106, 0x0000},
-
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-/*
- *  RESOLUTION 640x480
-*/
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-               {0x110, 0x0008},
-               {0x111, 0x0000},
-               {0x112, 0x0003},
-               {0x113, 0x0000},
-               {0x114, 0x0508},
-               {0x115, 0x0005},
-               {0x116, 0x00F3},
-               {0x117, 0x0000},
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
-               {0x202, 0x000F},
-               {0x203, 0x004A},
-               {0x2FF, 0x0000},
-
-               {0xFFF, 0xFFFF}
-};
-/*--------------------------------------------------------------------------*/
-static const struct saa7113config {
-       u8 reg;
-       u8 set;
-} saa7113configPAL[] = {
-               {0x01, 0x08},
-               {0x02, 0x80},
-               {0x03, 0x33},
-               {0x04, 0x00},
-               {0x05, 0x00},
-               {0x06, 0xE9},
-               {0x07, 0x0D},
-               {0x08, 0x38},
-               {0x09, 0x00},
-               {0x0A, SAA_0A_DEFAULT},
-               {0x0B, SAA_0B_DEFAULT},
-               {0x0C, SAA_0C_DEFAULT},
-               {0x0D, SAA_0D_DEFAULT},
-               {0x0E, 0x01},
-               {0x0F, 0x36},
-               {0x10, 0x00},
-               {0x11, 0x0C},
-               {0x12, 0xE7},
-               {0x13, 0x00},
-               {0x15, 0x00},
-               {0x16, 0x00},
-               {0x40, 0x02},
-               {0x41, 0xFF},
-               {0x42, 0xFF},
-               {0x43, 0xFF},
-               {0x44, 0xFF},
-               {0x45, 0xFF},
-               {0x46, 0xFF},
-               {0x47, 0xFF},
-               {0x48, 0xFF},
-               {0x49, 0xFF},
-               {0x4A, 0xFF},
-               {0x4B, 0xFF},
-               {0x4C, 0xFF},
-               {0x4D, 0xFF},
-               {0x4E, 0xFF},
-               {0x4F, 0xFF},
-               {0x50, 0xFF},
-               {0x51, 0xFF},
-               {0x52, 0xFF},
-               {0x53, 0xFF},
-               {0x54, 0xFF},
-               {0x55, 0xFF},
-               {0x56, 0xFF},
-               {0x57, 0xFF},
-               {0x58, 0x40},
-               {0x59, 0x54},
-               {0x5A, 0x07},
-               {0x5B, 0x83},
-
-               {0xFF, 0xFF}
-};
-/*--------------------------------------------------------------------------*/
-static const struct saa7113config saa7113configNTSC[] = {
-               {0x01, 0x08},
-               {0x02, 0x80},
-               {0x03, 0x33},
-               {0x04, 0x00},
-               {0x05, 0x00},
-               {0x06, 0xE9},
-               {0x07, 0x0D},
-               {0x08, 0x78},
-               {0x09, 0x00},
-               {0x0A, SAA_0A_DEFAULT},
-               {0x0B, SAA_0B_DEFAULT},
-               {0x0C, SAA_0C_DEFAULT},
-               {0x0D, SAA_0D_DEFAULT},
-               {0x0E, 0x01},
-               {0x0F, 0x36},
-               {0x10, 0x00},
-               {0x11, 0x0C},
-               {0x12, 0xE7},
-               {0x13, 0x00},
-               {0x15, 0x00},
-               {0x16, 0x00},
-               {0x40, 0x82},
-               {0x41, 0xFF},
-               {0x42, 0xFF},
-               {0x43, 0xFF},
-               {0x44, 0xFF},
-               {0x45, 0xFF},
-               {0x46, 0xFF},
-               {0x47, 0xFF},
-               {0x48, 0xFF},
-               {0x49, 0xFF},
-               {0x4A, 0xFF},
-               {0x4B, 0xFF},
-               {0x4C, 0xFF},
-               {0x4D, 0xFF},
-               {0x4E, 0xFF},
-               {0x4F, 0xFF},
-               {0x50, 0xFF},
-               {0x51, 0xFF},
-               {0x52, 0xFF},
-               {0x53, 0xFF},
-               {0x54, 0xFF},
-               {0x55, 0xFF},
-               {0x56, 0xFF},
-               {0x57, 0xFF},
-               {0x58, 0x40},
-               {0x59, 0x54},
-               {0x5A, 0x0A},
-               {0x5B, 0x83},
-
-               {0xFF, 0xFF}
-};
-
-static int regget(struct usb_device *pusb_device,
-               u16 index, void *reg, int reg_size)
-{
-       int rc;
-
-       if (!pusb_device)
-               return -ENODEV;
-
-       rc = usb_control_msg(pusb_device, usb_rcvctrlpipe(pusb_device, 0),
-                       0x00,
-                       (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE),
-                       0x00,
-                       index, reg, reg_size, 50000);
-
-       return rc;
-}
-
-static int regset(struct usb_device *pusb_device, u16 index, u16 value)
-{
-       int rc;
-
-       if (!pusb_device)
-               return -ENODEV;
-
-       rc = usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0),
-                       0x01,
-                       (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE),
-                       value, index, NULL, 0, 500);
-
-       if (rc < 0)
-               return rc;
-
-       if (easycap_readback) {
-               u16 igot = 0;
-               rc = regget(pusb_device, index, &igot, sizeof(igot));
-               igot = 0xFF & igot;
-               switch (index) {
-               case 0x000:
-               case 0x500:
-               case 0x502:
-               case 0x503:
-               case 0x504:
-               case 0x506:
-               case 0x507:
-                       break;
-
-               case 0x204:
-               case 0x205:
-               case 0x350:
-               case 0x351:
-                       if (igot)
-                               JOT(8, "unexpected 0x%02X "
-                                       "for STK register 0x%03X\n",
-                                       igot, index);
-                       break;
-
-               default:
-                       if ((0xFF & value) != igot)
-                               JOT(8, "unexpected 0x%02X != 0x%02X "
-                                       "for STK register 0x%03X\n",
-                                               igot, value, index);
-                       break;
-               }
-       }
-
-       return rc;
-}
-/*--------------------------------------------------------------------------*/
-/*
- *  FUNCTION wait_i2c() RETURNS 0 ON SUCCESS
-*/
-/*--------------------------------------------------------------------------*/
-static int wait_i2c(struct usb_device *p)
-{
-       u16 get0;
-       u8 igot;
-       const int max = 2;
-       int k;
-
-       if (!p)
-               return -ENODEV;
-
-       for (k = 0;  k < max;  k++) {
-               GET(p, 0x0201, &igot);  get0 = igot;
-               switch (get0) {
-               case 0x04:
-               case 0x01:
-                       return 0;
-               case 0x00:
-                       msleep(20);
-                       continue;
-               default:
-                       return get0 - 1;
-               }
-       }
-       return -1;
-}
-
-/****************************************************************************/
-int write_saa(struct usb_device *p, u16 reg0, u16 set0)
-{
-       if (!p)
-               return -ENODEV;
-       SET(p, 0x200, 0x00);
-       SET(p, 0x204, reg0);
-       SET(p, 0x205, set0);
-       SET(p, 0x200, 0x01);
-       return wait_i2c(p);
-}
-/****************************************************************************/
-/*--------------------------------------------------------------------------*/
-/*
- *  REGISTER 500:  SETTING VALUE TO 0x008B READS FROM VT1612A (?)
- *  REGISTER 500:  SETTING VALUE TO 0x008C WRITES TO  VT1612A
- *  REGISTER 502:  LEAST SIGNIFICANT BYTE OF VALUE TO SET
- *  REGISTER 503:  MOST SIGNIFICANT BYTE OF VALUE TO SET
- *  REGISTER 504:  TARGET ADDRESS ON VT1612A
- */
-/*--------------------------------------------------------------------------*/
-static int write_vt(struct usb_device *p, u16 reg0, u16 set0)
-{
-       u8 igot;
-       u16 got502, got503;
-       u16 set502, set503;
-
-       if (!p)
-               return -ENODEV;
-       SET(p, 0x0504, reg0);
-       SET(p, 0x0500, 0x008B);
-
-       GET(p, 0x0502, &igot);  got502 = (0xFF & igot);
-       GET(p, 0x0503, &igot);  got503 = (0xFF & igot);
-
-       JOT(16, "write_vt(., 0x%04X, 0x%04X): was 0x%04X\n",
-                               reg0, set0, ((got503 << 8) | got502));
-
-       set502 =  (0x00FF & set0);
-       set503 = ((0xFF00 & set0) >> 8);
-
-       SET(p, 0x0504, reg0);
-       SET(p, 0x0502, set502);
-       SET(p, 0x0503, set503);
-       SET(p, 0x0500, 0x008C);
-
-       return 0;
-}
-/****************************************************************************/
-/*--------------------------------------------------------------------------*/
-/*
- *  REGISTER 500:  SETTING VALUE TO 0x008B READS FROM VT1612A (?)
- *  REGISTER 500:  SETTING VALUE TO 0x008C WRITES TO  VT1612A
- *  REGISTER 502:  LEAST SIGNIFICANT BYTE OF VALUE TO GET
- *  REGISTER 503:  MOST SIGNIFICANT BYTE OF VALUE TO GET
- *  REGISTER 504:  TARGET ADDRESS ON VT1612A
- */
-/*--------------------------------------------------------------------------*/
-static int read_vt(struct usb_device *p, u16 reg0)
-{
-       u8 igot;
-       u16 got502, got503;
-
-       if (!p)
-               return -ENODEV;
-       SET(p, 0x0504, reg0);
-       SET(p, 0x0500, 0x008B);
-
-       GET(p, 0x0502, &igot);  got502 = (0xFF & igot);
-       GET(p, 0x0503, &igot);  got503 = (0xFF & igot);
-
-       JOT(16, "read_vt(., 0x%04X): has 0x%04X\n",
-                       reg0, ((got503 << 8) | got502));
-
-       return (got503 << 8) | got502;
-}
-/****************************************************************************/
-/*--------------------------------------------------------------------------*/
-/*
- *  THESE APPEAR TO HAVE NO EFFECT ON EITHER VIDEO OR AUDIO.
- */
-/*--------------------------------------------------------------------------*/
-static int write_300(struct usb_device *p)
-{
-       if (!p)
-               return -ENODEV;
-       SET(p, 0x300, 0x0012);
-       SET(p, 0x350, 0x002D);
-       SET(p, 0x351, 0x0001);
-       SET(p, 0x352, 0x0000);
-       SET(p, 0x353, 0x0000);
-       SET(p, 0x300, 0x0080);
-       return 0;
-}
-/****************************************************************************/
-/****************************************************************************/
-int setup_stk(struct usb_device *p, bool ntsc)
-{
-       int i;
-       const struct stk1160config *cfg;
-       if (!p)
-               return -ENODEV;
-       cfg = (ntsc) ? stk1160configNTSC : stk1160configPAL;
-       for (i = 0; cfg[i].reg != 0xFFF; i++)
-               SET(p, cfg[i].reg, cfg[i].set);
-
-       write_300(p);
-
-       return 0;
-}
-/****************************************************************************/
-int setup_saa(struct usb_device *p, bool ntsc)
-{
-       int i, rc;
-       const struct saa7113config *cfg;
-       if (!p)
-               return -ENODEV;
-       cfg = (ntsc) ?  saa7113configNTSC : saa7113configPAL;
-       for (i = 0; cfg[i].reg != 0xFF; i++) {
-               rc = write_saa(p, cfg[i].reg, cfg[i].set);
-               if (rc)
-                       dev_err(&p->dev,
-                               "Failed to set SAA register %d", cfg[i].reg);
-       }
-       return 0;
-}
-/****************************************************************************/
-int merit_saa(struct usb_device *p)
-{
-       int rc;
-
-       if (!p)
-               return -ENODEV;
-       rc = read_saa(p, 0x1F);
-       return ((0 > rc) || (0x02 & rc)) ? 1 : 0;
-}
-/****************************************************************************/
-int ready_saa(struct usb_device *p)
-{
-       int j, rc, rate;
-       const int max = 5, marktime = PATIENCE/5;
-/*--------------------------------------------------------------------------*/
-/*
- *   RETURNS    0     FOR INTERLACED       50 Hz
- *              1     FOR NON-INTERLACED   50 Hz
- *              2     FOR INTERLACED       60 Hz
- *              3     FOR NON-INTERLACED   60 Hz
-*/
-/*--------------------------------------------------------------------------*/
-       if (!p)
-               return -ENODEV;
-       j = 0;
-       while (max > j) {
-               rc = read_saa(p, 0x1F);
-               if (0 <= rc) {
-                       if (0 == (0x40 & rc))
-                               break;
-                       if (1 == (0x01 & rc))
-                               break;
-               }
-               msleep(marktime);
-               j++;
-       }
-
-       if (max == j)
-               return -1;
-
-       if (0x20 & rc) {
-               rate = 2;
-               JOT(8, "hardware detects 60 Hz\n");
-       } else {
-               rate = 0;
-               JOT(8, "hardware detects 50 Hz\n");
-       }
-       if (0x80 & rc)
-               JOT(8, "hardware detects interlacing\n");
-       else {
-               rate++;
-               JOT(8, "hardware detects no interlacing\n");
-       }
-       return 0;
-}
-/****************************************************************************/
-int read_saa(struct usb_device *p, u16 reg0)
-{
-       u8 igot;
-
-       if (!p)
-               return -ENODEV;
-       SET(p, 0x208, reg0);
-       SET(p, 0x200, 0x20);
-       if (0 != wait_i2c(p))
-               return -1;
-       igot = 0;
-       GET(p, 0x0209, &igot);
-       return igot;
-}
-/****************************************************************************/
-static int read_stk(struct usb_device *p, u32 reg0)
-{
-       u8 igot;
-
-       if (!p)
-               return -ENODEV;
-       igot = 0;
-       GET(p, reg0, &igot);
-       return igot;
-}
-int select_input(struct usb_device *p, int input, int mode)
-{
-       int ir;
-
-       if (!p)
-               return -ENODEV;
-       stop_100(p);
-       switch (input) {
-       case 0:
-       case 1: {
-               if (0 != write_saa(p, 0x02, 0x80))
-                       SAY("ERROR: failed to set SAA register 0x02 "
-                                               "for input %i\n", input);
-
-               SET(p, 0x0000, 0x0098);
-               SET(p, 0x0002, 0x0078);
-               break;
-       }
-       case 2: {
-               if (0 != write_saa(p, 0x02, 0x80))
-                       SAY("ERROR: failed to set SAA register 0x02 "
-                                               "for input %i\n", input);
-
-               SET(p, 0x0000, 0x0090);
-               SET(p, 0x0002, 0x0078);
-               break;
-       }
-       case 3: {
-               if (0 != write_saa(p, 0x02, 0x80))
-                       SAY("ERROR: failed to set SAA register 0x02 "
-                                       " for input %i\n", input);
-
-               SET(p, 0x0000, 0x0088);
-               SET(p, 0x0002, 0x0078);
-               break;
-       }
-       case 4: {
-               if (0 != write_saa(p, 0x02, 0x80)) {
-                       SAY("ERROR: failed to set SAA register 0x02 "
-                                               "for input %i\n", input);
-               }
-               SET(p, 0x0000, 0x0080);
-               SET(p, 0x0002, 0x0078);
-               break;
-       }
-       case 5: {
-               if (9 != mode)
-                       mode = 7;
-               switch (mode) {
-               case 7: {
-                       if (0 != write_saa(p, 0x02, 0x87))
-                               SAY("ERROR: failed to set SAA register 0x02 "
-                                               "for input %i\n", input);
-
-                       if (0 != write_saa(p, 0x05, 0xFF))
-                               SAY("ERROR: failed to set SAA register 0x05 "
-                                               "for input %i\n", input);
-
-                       break;
-               }
-               case 9: {
-                       if (0 != write_saa(p, 0x02, 0x89))
-                               SAY("ERROR: failed to set SAA register 0x02 "
-                                               "for input %i\n", input);
-
-                       if (0 != write_saa(p, 0x05, 0x00))
-                               SAY("ERROR: failed to set SAA register 0x05 "
-                                               "for input %i\n", input);
-
-                       break;
-               }
-               default:
-                       SAY("MISTAKE:  bad mode: %i\n", mode);
-                       return -1;
-               }
-
-               if (0 != write_saa(p, 0x04, 0x00))
-                       SAY("ERROR: failed to set SAA register 0x04 "
-                                       "for input %i\n", input);
-
-               if (0 != write_saa(p, 0x09, 0x80))
-                       SAY("ERROR: failed to set SAA register 0x09 "
-                                               "for input %i\n", input);
-
-               SET(p, 0x0002, 0x0093);
-               break;
-       }
-       default:
-               SAY("ERROR:  bad input: %i\n", input);
-               return -1;
-       }
-
-       ir = read_stk(p, 0x00);
-       JOT(8, "STK register 0x00 has 0x%02X\n", ir);
-       ir = read_saa(p, 0x02);
-       JOT(8, "SAA register 0x02 has 0x%02X\n", ir);
-
-       start_100(p);
-
-       return 0;
-}
-/****************************************************************************/
-int set_resolution(struct usb_device *p,
-                  u16 set0, u16 set1, u16 set2, u16 set3)
-{
-       u16 u0x0111, u0x0113, u0x0115, u0x0117;
-
-       if (!p)
-               return -ENODEV;
-       u0x0111 = ((0xFF00 & set0) >> 8);
-       u0x0113 = ((0xFF00 & set1) >> 8);
-       u0x0115 = ((0xFF00 & set2) >> 8);
-       u0x0117 = ((0xFF00 & set3) >> 8);
-
-       SET(p, 0x0110, (0x00FF & set0));
-       SET(p, 0x0111, u0x0111);
-       SET(p, 0x0112, (0x00FF & set1));
-       SET(p, 0x0113, u0x0113);
-       SET(p, 0x0114, (0x00FF & set2));
-       SET(p, 0x0115, u0x0115);
-       SET(p, 0x0116, (0x00FF & set3));
-       SET(p, 0x0117, u0x0117);
-
-       return 0;
-}
-/****************************************************************************/
-int start_100(struct usb_device *p)
-{
-       u16 get116, get117, get0;
-       u8 igot116, igot117, igot;
-
-       if (!p)
-               return -ENODEV;
-       GET(p, 0x0116, &igot116);
-       get116 = igot116;
-       GET(p, 0x0117, &igot117);
-       get117 = igot117;
-       SET(p, 0x0116, 0x0000);
-       SET(p, 0x0117, 0x0000);
-
-       GET(p, 0x0100, &igot);
-       get0 = igot;
-       SET(p, 0x0100, (0x80 | get0));
-
-       SET(p, 0x0116, get116);
-       SET(p, 0x0117, get117);
-
-       return 0;
-}
-/****************************************************************************/
-int stop_100(struct usb_device *p)
-{
-       u16 get0;
-       u8 igot;
-
-       if (!p)
-               return -ENODEV;
-       GET(p, 0x0100, &igot);
-       get0 = igot;
-       SET(p, 0x0100, (0x7F & get0));
-       return 0;
-}
-/****************************************************************************/
-/****************************************************************************/
-/*****************************************************************************/
-int easycap_wakeup_device(struct usb_device *pusb_device)
-{
-       if (!pusb_device)
-               return -ENODEV;
-
-       return usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0),
-                       USB_REQ_SET_FEATURE,
-                       USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
-                       USB_DEVICE_REMOTE_WAKEUP,
-                       0, NULL, 0, 50000);
-}
-/*****************************************************************************/
-int easycap_audio_setup(struct easycap *peasycap)
-{
-       struct usb_device *pusb_device;
-       u8 buffer[1];
-       int rc, id1, id2;
-/*---------------------------------------------------------------------------*/
-/*
- *                                IMPORTANT:
- *  THE MESSAGE OF TYPE (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)
- *  CAUSES MUTING IF THE VALUE 0x0100 IS SENT.
- *  TO ENABLE AUDIO  THE VALUE 0x0200 MUST BE SENT.
- */
-/*---------------------------------------------------------------------------*/
-       const u8 request = 0x01;
-       const u8 requesttype = USB_DIR_OUT |
-                              USB_TYPE_CLASS |
-                              USB_RECIP_INTERFACE;
-       const u16 value_unmute = 0x0200;
-       const u16 index = 0x0301;
-       const u16 length = 1;
-
-       if (!peasycap)
-               return -EFAULT;
-
-       pusb_device = peasycap->pusb_device;
-       if (!pusb_device)
-               return -ENODEV;
-
-       JOM(8, "%02X %02X %02X %02X %02X %02X %02X %02X\n",
-                               requesttype, request,
-                               (0x00FF & value_unmute),
-                               (0xFF00 & value_unmute) >> 8,
-                               (0x00FF & index),
-                               (0xFF00 & index) >> 8,
-                               (0x00FF & length),
-                               (0xFF00 & length) >> 8);
-
-       buffer[0] = 0x01;
-
-       rc = usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0),
-                               request, requesttype, value_unmute,
-                               index, &buffer[0], length, 50000);
-
-       JOT(8, "0x%02X=buffer\n", buffer[0]);
-       if (rc != (int)length) {
-               switch (rc) {
-               case -EPIPE:
-                       SAY("usb_control_msg returned -EPIPE\n");
-                       break;
-               default:
-                       SAY("ERROR: usb_control_msg returned %i\n", rc);
-                       break;
-               }
-       }
-/*--------------------------------------------------------------------------*/
-/*
- *  REGISTER 500:  SETTING VALUE TO 0x0094 RESETS AUDIO CONFIGURATION ???
- *  REGISTER 506:  ANALOGUE AUDIO ATTENTUATOR ???
- *                 FOR THE CVBS+S-VIDEO HARDWARE:
- *                    SETTING VALUE TO 0x0000 GIVES QUIET SOUND.
- *                    THE UPPER BYTE SEEMS TO HAVE NO EFFECT.
- *                 FOR THE FOUR-CVBS HARDWARE:
- *                    SETTING VALUE TO 0x0000 SEEMS TO HAVE NO EFFECT.
- *  REGISTER 507:  ANALOGUE AUDIO PREAMPLIFIER ON/OFF ???
- *                 FOR THE CVBS-S-VIDEO HARDWARE:
- *                    SETTING VALUE TO 0x0001 GIVES VERY LOUD, DISTORTED SOUND.
- *                    THE UPPER BYTE SEEMS TO HAVE NO EFFECT.
- */
-/*--------------------------------------------------------------------------*/
-       SET(pusb_device, 0x0500, 0x0094);
-       SET(pusb_device, 0x0500, 0x008C);
-       SET(pusb_device, 0x0506, 0x0001);
-       SET(pusb_device, 0x0507, 0x0000);
-       id1 = read_vt(pusb_device, 0x007C);
-       id2 = read_vt(pusb_device, 0x007E);
-       SAM("0x%04X:0x%04X is audio vendor id\n", id1, id2);
-/*---------------------------------------------------------------------------*/
-/*
- *  SELECT AUDIO SOURCE "LINE IN" AND SET THE AUDIO GAIN.
-*/
-/*---------------------------------------------------------------------------*/
-       if (easycap_audio_gainset(pusb_device, peasycap->gain))
-               SAY("ERROR: audio_gainset() failed\n");
-       check_vt(pusb_device);
-       return 0;
-}
-/*****************************************************************************/
-int check_vt(struct usb_device *pusb_device)
-{
-       int igot;
-
-       if (!pusb_device)
-               return -ENODEV;
-       igot = read_vt(pusb_device, 0x0002);
-       if (0 > igot)
-               SAY("ERROR: failed to read VT1612A register 0x02\n");
-       if (0x8000 & igot)
-               SAY("register 0x%02X muted\n", 0x02);
-
-       igot = read_vt(pusb_device, 0x000E);
-       if (0 > igot)
-               SAY("ERROR: failed to read VT1612A register 0x0E\n");
-       if (0x8000 & igot)
-               SAY("register 0x%02X muted\n", 0x0E);
-
-       igot = read_vt(pusb_device, 0x0010);
-       if (0 > igot)
-               SAY("ERROR: failed to read VT1612A register 0x10\n");
-       if (0x8000 & igot)
-               SAY("register 0x%02X muted\n", 0x10);
-
-       igot = read_vt(pusb_device, 0x0012);
-       if (0 > igot)
-               SAY("ERROR: failed to read VT1612A register 0x12\n");
-       if (0x8000 & igot)
-               SAY("register 0x%02X muted\n", 0x12);
-
-       igot = read_vt(pusb_device, 0x0014);
-       if (0 > igot)
-               SAY("ERROR: failed to read VT1612A register 0x14\n");
-       if (0x8000 & igot)
-               SAY("register 0x%02X muted\n", 0x14);
-
-       igot = read_vt(pusb_device, 0x0016);
-       if (0 > igot)
-               SAY("ERROR: failed to read VT1612A register 0x16\n");
-       if (0x8000 & igot)
-               SAY("register 0x%02X muted\n", 0x16);
-
-       igot = read_vt(pusb_device, 0x0018);
-       if (0 > igot)
-               SAY("ERROR: failed to read VT1612A register 0x18\n");
-       if (0x8000 & igot)
-               SAY("register 0x%02X muted\n", 0x18);
-
-       igot = read_vt(pusb_device, 0x001C);
-       if (0 > igot)
-               SAY("ERROR: failed to read VT1612A register 0x1C\n");
-       if (0x8000 & igot)
-               SAY("register 0x%02X muted\n", 0x1C);
-
-       return 0;
-}
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*  NOTE:  THIS DOES INCREASE THE VOLUME DRAMATICALLY:
- *                      audio_gainset(pusb_device, 0x000F);
- *
- *       loud        dB  register 0x10      dB register 0x1C    dB total
- *         0               -34.5                   0             -34.5
- *        ..                ....                   .              ....
- *        15                10.5                   0              10.5
- *        16                12.0                   0              12.0
- *        17                12.0                   1.5            13.5
- *        ..                ....                  ....            ....
- *        31                12.0                  22.5            34.5
-*/
-/*---------------------------------------------------------------------------*/
-int easycap_audio_gainset(struct usb_device *pusb_device, s8 loud)
-{
-       int igot;
-       u8 tmp;
-       u16 mute;
-
-       if (!pusb_device)
-               return -ENODEV;
-       if (0 > loud)
-               loud = 0;
-       if (31 < loud)
-               loud = 31;
-
-       write_vt(pusb_device, 0x0002, 0x8000);
-/*---------------------------------------------------------------------------*/
-       igot = read_vt(pusb_device, 0x000E);
-       if (0 > igot) {
-               SAY("ERROR: failed to read VT1612A register 0x0E\n");
-               mute = 0x0000;
-       } else
-               mute = 0x8000 & ((unsigned int)igot);
-       mute = 0;
-
-       if (16 > loud)
-               tmp = 0x01 | (0x001F & (((u8)(15 - loud)) << 1));
-       else
-               tmp = 0;
-
-       JOT(8, "0x%04X=(mute|tmp) for VT1612A register 0x0E\n", mute | tmp);
-       write_vt(pusb_device, 0x000E, (mute | tmp));
-/*---------------------------------------------------------------------------*/
-       igot = read_vt(pusb_device, 0x0010);
-       if (0 > igot) {
-               SAY("ERROR: failed to read VT1612A register 0x10\n");
-               mute = 0x0000;
-       } else
-               mute = 0x8000 & ((unsigned int)igot);
-       mute = 0;
-
-       JOT(8, "0x%04X=(mute|tmp|(tmp<<8)) for VT1612A register 0x10,...0x18\n",
-                                               mute | tmp | (tmp << 8));
-       write_vt(pusb_device, 0x0010, (mute | tmp | (tmp << 8)));
-       write_vt(pusb_device, 0x0012, (mute | tmp | (tmp << 8)));
-       write_vt(pusb_device, 0x0014, (mute | tmp | (tmp << 8)));
-       write_vt(pusb_device, 0x0016, (mute | tmp | (tmp << 8)));
-       write_vt(pusb_device, 0x0018, (mute | tmp | (tmp << 8)));
-/*---------------------------------------------------------------------------*/
-       igot = read_vt(pusb_device, 0x001C);
-       if (0 > igot) {
-               SAY("ERROR: failed to read VT1612A register 0x1C\n");
-               mute = 0x0000;
-       } else
-               mute = 0x8000 & ((unsigned int)igot);
-       mute = 0;
-
-       if (16 <= loud)
-               tmp = 0x000F & (u8)(loud - 16);
-       else
-               tmp = 0;
-
-       JOT(8, "0x%04X=(mute|tmp|(tmp<<8)) for VT1612A register 0x1C\n",
-                                               mute | tmp | (tmp << 8));
-       write_vt(pusb_device, 0x001C, (mute | tmp | (tmp << 8)));
-       write_vt(pusb_device, 0x001A, 0x0404);
-       write_vt(pusb_device, 0x0002, 0x0000);
-       return 0;
-}
-/*****************************************************************************/
diff --git a/drivers/staging/media/easycap/easycap_main.c b/drivers/staging/media/easycap/easycap_main.c
deleted file mode 100644 (file)
index 8269c77..0000000
+++ /dev/null
@@ -1,4239 +0,0 @@
-/******************************************************************************
-*                                                                             *
-*  easycap_main.c                                                             *
-*                                                                             *
-*  Video driver for EasyCAP USB2.0 Video Capture Device DC60                  *
-*                                                                             *
-*                                                                             *
-******************************************************************************/
-/*
- *
- *  Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>
- *
- *
- *  This 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.
- *
- *  The software 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 software; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
-*/
-/*****************************************************************************/
-
-#include "easycap.h"
-#include <linux/usb/audio.h>
-
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("R.M. Thomas <rmthomas@sciolus.org>");
-MODULE_DESCRIPTION(EASYCAP_DRIVER_DESCRIPTION);
-MODULE_VERSION(EASYCAP_DRIVER_VERSION);
-
-#ifdef CONFIG_EASYCAP_DEBUG
-int easycap_debug;
-module_param_named(debug, easycap_debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug level: 0(default),1,2,...,9");
-#endif /* CONFIG_EASYCAP_DEBUG */
-
-bool easycap_readback;
-module_param_named(readback, easycap_readback, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(readback, "read back written registers: (default false)");
-
-static int easycap_bars = 1;
-module_param_named(bars, easycap_bars, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(bars,
-       "Testcard bars on input signal failure: 0=>no, 1=>yes(default)");
-
-static int easycap_gain = 16;
-module_param_named(gain, easycap_gain, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(gain, "Audio gain: 0,...,16(default),...31");
-
-static bool easycap_ntsc;
-module_param_named(ntsc, easycap_ntsc, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(ntsc, "NTSC default encoding (default PAL)");
-
-
-
-struct easycap_dongle easycapdc60_dongle[DONGLE_MANY];
-static struct mutex mutex_dongle;
-static void easycap_complete(struct urb *purb);
-static int reset(struct easycap *peasycap);
-static int field2frame(struct easycap *peasycap);
-static int redaub(struct easycap *peasycap,
-               void *pad, void *pex, int much, int more,
-               u8 mask, u8 margin, bool isuy);
-
-const char *strerror(int err)
-{
-#define ERRNOSTR(_e) case _e: return # _e
-       switch (err) {
-       case 0: return "OK";
-       ERRNOSTR(ENOMEM);
-       ERRNOSTR(ENODEV);
-       ERRNOSTR(ENXIO);
-       ERRNOSTR(EINVAL);
-       ERRNOSTR(EAGAIN);
-       ERRNOSTR(EFBIG);
-       ERRNOSTR(EPIPE);
-       ERRNOSTR(EMSGSIZE);
-       ERRNOSTR(ENOSPC);
-       ERRNOSTR(EINPROGRESS);
-       ERRNOSTR(ENOSR);
-       ERRNOSTR(EOVERFLOW);
-       ERRNOSTR(EPROTO);
-       ERRNOSTR(EILSEQ);
-       ERRNOSTR(ETIMEDOUT);
-       ERRNOSTR(EOPNOTSUPP);
-       ERRNOSTR(EPFNOSUPPORT);
-       ERRNOSTR(EAFNOSUPPORT);
-       ERRNOSTR(EADDRINUSE);
-       ERRNOSTR(EADDRNOTAVAIL);
-       ERRNOSTR(ENOBUFS);
-       ERRNOSTR(EISCONN);
-       ERRNOSTR(ENOTCONN);
-       ERRNOSTR(ESHUTDOWN);
-       ERRNOSTR(ENOENT);
-       ERRNOSTR(ECONNRESET);
-       ERRNOSTR(ETIME);
-       ERRNOSTR(ECOMM);
-       ERRNOSTR(EREMOTEIO);
-       ERRNOSTR(EXDEV);
-       ERRNOSTR(EPERM);
-       default: return "unknown";
-       }
-
-#undef ERRNOSTR
-}
-
-/****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- *  THIS ROUTINE DOES NOT DETECT DUPLICATE OCCURRENCES OF POINTER peasycap
-*/
-/*---------------------------------------------------------------------------*/
-int easycap_isdongle(struct easycap *peasycap)
-{
-       int k;
-       if (!peasycap)
-               return -2;
-       for (k = 0; k < DONGLE_MANY; k++) {
-               if (easycapdc60_dongle[k].peasycap == peasycap) {
-                       peasycap->isdongle = k;
-                       return k;
-               }
-       }
-       return -1;
-}
-/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
-static int easycap_open(struct inode *inode, struct file *file)
-{
-       struct video_device *pvideo_device;
-       struct easycap *peasycap;
-       int rc;
-
-       JOT(4, "\n");
-       SAY("==========OPEN=========\n");
-
-       pvideo_device = video_devdata(file);
-       if (!pvideo_device) {
-               SAY("ERROR: pvideo_device is NULL.\n");
-               return -EFAULT;
-       }
-       peasycap = (struct easycap *)video_get_drvdata(pvideo_device);
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return -EFAULT;
-       }
-       if (!peasycap->pusb_device) {
-               SAM("ERROR: peasycap->pusb_device is NULL\n");
-               return -EFAULT;
-       }
-
-       JOM(16, "peasycap->pusb_device=%p\n", peasycap->pusb_device);
-
-       file->private_data = peasycap;
-       rc = easycap_wakeup_device(peasycap->pusb_device);
-       if (rc) {
-               SAM("ERROR: wakeup_device() rc = %i\n", rc);
-               if (-ENODEV == rc)
-                       SAM("ERROR: wakeup_device() returned -ENODEV\n");
-               else
-                       SAM("ERROR: wakeup_device() rc = %i\n", rc);
-               return rc;
-       }
-       JOM(8, "wakeup_device() OK\n");
-       peasycap->input = 0;
-       rc = reset(peasycap);
-       if (rc) {
-               SAM("ERROR: reset() rc = %i\n", rc);
-               return -EFAULT;
-       }
-       return 0;
-}
-
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- *  RESET THE HARDWARE TO ITS REFERENCE STATE.
- *
- *  THIS ROUTINE MAY BE CALLED REPEATEDLY IF easycap_complete() DETECTS
- *  A BAD VIDEO FRAME SIZE.
-*/
-/*---------------------------------------------------------------------------*/
-static int reset(struct easycap *peasycap)
-{
-       struct easycap_standard const *peasycap_standard;
-       int fmtidx, input, rate;
-       bool ntsc, other;
-       int rc;
-
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return -EFAULT;
-       }
-       input = peasycap->input;
-
-/*---------------------------------------------------------------------------*/
-/*
- *  IF THE SAA7113H HAS ALREADY ACQUIRED SYNC, USE ITS HARDWARE-DETECTED
- *  FIELD FREQUENCY TO DISTINGUISH NTSC FROM PAL.  THIS IS ESSENTIAL FOR
- *  gstreamer AND OTHER USERSPACE PROGRAMS WHICH MAY NOT ATTEMPT TO INITIATE
- *  A SWITCH BETWEEN PAL AND NTSC.
- *
- *  FUNCTION ready_saa() MAY REQUIRE A SUBSTANTIAL FRACTION OF A SECOND TO
- *  COMPLETE, SO SHOULD NOT BE INVOKED WITHOUT GOOD REASON.
-*/
-/*---------------------------------------------------------------------------*/
-       other = false;
-       JOM(8, "peasycap->ntsc=%d\n", peasycap->ntsc);
-
-       rate = ready_saa(peasycap->pusb_device);
-       if (rate < 0) {
-               JOM(8, "not ready to capture after %i ms ...\n", PATIENCE);
-               ntsc = !peasycap->ntsc;
-               JOM(8, "... trying  %s ..\n", ntsc ? "NTSC" : "PAL");
-               rc = setup_stk(peasycap->pusb_device, ntsc);
-               if (rc) {
-                       SAM("ERROR: setup_stk() rc = %i\n", rc);
-                       return -EFAULT;
-               }
-               rc = setup_saa(peasycap->pusb_device, ntsc);
-               if (rc) {
-                       SAM("ERROR: setup_saa() rc = %i\n", rc);
-                       return -EFAULT;
-               }
-
-               rate = ready_saa(peasycap->pusb_device);
-               if (rate < 0) {
-                       JOM(8, "not ready to capture after %i ms\n", PATIENCE);
-                       JOM(8, "... saa register 0x1F has 0x%02X\n",
-                                       read_saa(peasycap->pusb_device, 0x1F));
-                       ntsc = peasycap->ntsc;
-               } else {
-                       JOM(8, "... success at second try:  %i=rate\n", rate);
-                       ntsc = (0 < (rate/2)) ? true : false ;
-                       other = true;
-               }
-       } else {
-               JOM(8, "... success at first try:  %i=rate\n", rate);
-               ntsc = (0 < rate/2) ? true : false ;
-       }
-       JOM(8, "ntsc=%d\n", ntsc);
-/*---------------------------------------------------------------------------*/
-
-       rc = setup_stk(peasycap->pusb_device, ntsc);
-       if (rc) {
-               SAM("ERROR: setup_stk() rc = %i\n", rc);
-               return -EFAULT;
-       }
-       rc = setup_saa(peasycap->pusb_device, ntsc);
-       if (rc) {
-               SAM("ERROR: setup_saa() rc = %i\n", rc);
-               return -EFAULT;
-       }
-
-       memset(peasycap->merit, 0, sizeof(peasycap->merit));
-
-       peasycap->video_eof = 0;
-       peasycap->audio_eof = 0;
-/*---------------------------------------------------------------------------*/
-/*
- * RESTORE INPUT AND FORCE REFRESH OF STANDARD, FORMAT, ETC.
- *
- * WHILE THIS PROCEDURE IS IN PROGRESS, SOME IOCTL COMMANDS WILL RETURN -EBUSY.
-*/
-/*---------------------------------------------------------------------------*/
-       peasycap->input = -8192;
-       peasycap->standard_offset = -8192;
-       fmtidx = ntsc ? NTSC_M : PAL_BGHIN;
-       if (other) {
-               peasycap_standard = &easycap_standard[0];
-               while (0xFFFF != peasycap_standard->mask) {
-                       if (fmtidx == peasycap_standard->v4l2_standard.index) {
-                               peasycap->inputset[input].standard_offset =
-                                       peasycap_standard - easycap_standard;
-                               break;
-                       }
-                       peasycap_standard++;
-               }
-               if (0xFFFF == peasycap_standard->mask) {
-                       SAM("ERROR: standard not found\n");
-                       return -EINVAL;
-               }
-               JOM(8, "%i=peasycap->inputset[%i].standard_offset\n",
-                       peasycap->inputset[input].standard_offset, input);
-       }
-       peasycap->format_offset = -8192;
-       peasycap->brightness = -8192;
-       peasycap->contrast = -8192;
-       peasycap->saturation = -8192;
-       peasycap->hue = -8192;
-
-       rc = easycap_newinput(peasycap, input);
-
-       if (rc) {
-               SAM("ERROR: newinput(.,%i) rc = %i\n", rc, input);
-               return -EFAULT;
-       }
-       JOM(4, "restored input, standard and format\n");
-
-       JOM(8, "true=peasycap->ntsc %d\n", peasycap->ntsc);
-
-       if (0 > peasycap->input) {
-               SAM("MISTAKE:  %i=peasycap->input\n", peasycap->input);
-               return -ENOENT;
-       }
-       if (0 > peasycap->standard_offset) {
-               SAM("MISTAKE:  %i=peasycap->standard_offset\n",
-                               peasycap->standard_offset);
-               return -ENOENT;
-       }
-       if (0 > peasycap->format_offset) {
-               SAM("MISTAKE:  %i=peasycap->format_offset\n",
-                               peasycap->format_offset);
-               return -ENOENT;
-       }
-       if (0 > peasycap->brightness) {
-               SAM("MISTAKE:  %i=peasycap->brightness\n",
-                               peasycap->brightness);
-               return -ENOENT;
-       }
-       if (0 > peasycap->contrast) {
-               SAM("MISTAKE:  %i=peasycap->contrast\n", peasycap->contrast);
-               return -ENOENT;
-       }
-       if (0 > peasycap->saturation) {
-               SAM("MISTAKE:  %i=peasycap->saturation\n",
-                               peasycap->saturation);
-               return -ENOENT;
-       }
-       if (0 > peasycap->hue) {
-               SAM("MISTAKE:  %i=peasycap->hue\n", peasycap->hue);
-               return -ENOENT;
-       }
-       return 0;
-}
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- *  IF THE REQUESTED INPUT IS THE SAME AS THE EXISTING INPUT, DO NOTHING.
- *  OTHERWISE:
- *      KILL URBS, CLEAR FIELD AND FRAME BUFFERS AND RESET THEIR
- *           _read AND _fill POINTERS.
- *      SELECT THE NEW INPUT.
- *      ADJUST THE STANDARD, FORMAT, BRIGHTNESS, CONTRAST, SATURATION AND HUE
- *          ON THE BASIS OF INFORMATION IN STRUCTURE easycap.inputset[input].
- *      RESUBMIT THE URBS IF STREAMING WAS ALREADY IN PROGRESS.
- *
- *  NOTE:
- *      THIS ROUTINE MAY BE CALLED FREQUENTLY BY ZONEMINDER VIA IOCTL,
- *      SO IT SHOULD WRITE ONLY SPARINGLY TO THE LOGFILE.
-*/
-/*---------------------------------------------------------------------------*/
-int easycap_newinput(struct easycap *peasycap, int input)
-{
-       int rc, k, m, mood, off;
-       int inputnow, video_idlenow, audio_idlenow;
-       bool resubmit;
-
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return -EFAULT;
-       }
-       JOM(8, "%i=input sought\n", input);
-
-       if (0 > input && INPUT_MANY <= input)
-               return -ENOENT;
-       inputnow = peasycap->input;
-       if (input == inputnow)
-               return 0;
-/*---------------------------------------------------------------------------*/
-/*
- *  IF STREAMING IS IN PROGRESS THE URBS ARE KILLED AT THIS
- *  STAGE AND WILL BE RESUBMITTED PRIOR TO EXIT FROM THE ROUTINE.
- *  IF NO STREAMING IS IN PROGRESS NO URBS WILL BE SUBMITTED BY THE
- *  ROUTINE.
-*/
-/*---------------------------------------------------------------------------*/
-       video_idlenow = peasycap->video_idle;
-       audio_idlenow = peasycap->audio_idle;
-
-       peasycap->video_idle = 1;
-       peasycap->audio_idle = 1;
-       if (peasycap->video_isoc_streaming) {
-               resubmit = true;
-               easycap_video_kill_urbs(peasycap);
-       } else {
-               resubmit = false;
-       }
-/*---------------------------------------------------------------------------*/
-       if (!peasycap->pusb_device) {
-               SAM("ERROR: peasycap->pusb_device is NULL\n");
-               return -ENODEV;
-       }
-       rc = usb_set_interface(peasycap->pusb_device,
-                               peasycap->video_interface,
-                               peasycap->video_altsetting_off);
-       if (rc) {
-               SAM("ERROR: usb_set_interface() rc = %i\n", rc);
-               return -EFAULT;
-       }
-       rc = stop_100(peasycap->pusb_device);
-       if (rc) {
-               SAM("ERROR: stop_100() rc = %i\n", rc);
-               return -EFAULT;
-       }
-       for (k = 0; k < FIELD_BUFFER_MANY; k++) {
-               for (m = 0; m < FIELD_BUFFER_SIZE/PAGE_SIZE; m++)
-                       memset(peasycap->field_buffer[k][m].pgo, 0, PAGE_SIZE);
-       }
-       for (k = 0; k < FRAME_BUFFER_MANY; k++) {
-               for (m = 0; m < FRAME_BUFFER_SIZE/PAGE_SIZE; m++)
-                       memset(peasycap->frame_buffer[k][m].pgo, 0, PAGE_SIZE);
-       }
-       peasycap->field_page = 0;
-       peasycap->field_read = 0;
-       peasycap->field_fill = 0;
-
-       peasycap->frame_read = 0;
-       peasycap->frame_fill = 0;
-       for (k = 0; k < peasycap->input; k++) {
-               (peasycap->frame_fill)++;
-               if (peasycap->frame_buffer_many <= peasycap->frame_fill)
-                       peasycap->frame_fill = 0;
-       }
-       peasycap->input = input;
-       select_input(peasycap->pusb_device, peasycap->input, 9);
-/*---------------------------------------------------------------------------*/
-       if (input == peasycap->inputset[input].input) {
-               off = peasycap->inputset[input].standard_offset;
-               if (off != peasycap->standard_offset) {
-                       rc = adjust_standard(peasycap,
-                               easycap_standard[off].v4l2_standard.id);
-                       if (rc) {
-                               SAM("ERROR: adjust_standard() rc = %i\n", rc);
-                               return -EFAULT;
-                       }
-                       JOM(8, "%i=peasycap->standard_offset\n",
-                               peasycap->standard_offset);
-               } else {
-                       JOM(8, "%i=peasycap->standard_offset unchanged\n",
-                                               peasycap->standard_offset);
-               }
-               off = peasycap->inputset[input].format_offset;
-               if (off != peasycap->format_offset) {
-                       struct v4l2_pix_format *pix =
-                               &easycap_format[off].v4l2_format.fmt.pix;
-                       rc = adjust_format(peasycap,
-                               pix->width, pix->height,
-                               pix->pixelformat, pix->field, false);
-                       if (0 > rc) {
-                               SAM("ERROR: adjust_format() rc = %i\n", rc);
-                               return -EFAULT;
-                       }
-                       JOM(8, "%i=peasycap->format_offset\n",
-                                       peasycap->format_offset);
-               } else {
-                       JOM(8, "%i=peasycap->format_offset unchanged\n",
-                                       peasycap->format_offset);
-               }
-               mood = peasycap->inputset[input].brightness;
-               if (mood != peasycap->brightness) {
-                       rc = adjust_brightness(peasycap, mood);
-                       if (rc) {
-                               SAM("ERROR: adjust_brightness rc = %i\n", rc);
-                               return -EFAULT;
-                       }
-                       JOM(8, "%i=peasycap->brightness\n",
-                                       peasycap->brightness);
-               }
-               mood = peasycap->inputset[input].contrast;
-               if (mood != peasycap->contrast) {
-                       rc = adjust_contrast(peasycap, mood);
-                       if (rc) {
-                               SAM("ERROR: adjust_contrast rc = %i\n", rc);
-                               return -EFAULT;
-                       }
-                       JOM(8, "%i=peasycap->contrast\n", peasycap->contrast);
-               }
-               mood = peasycap->inputset[input].saturation;
-               if (mood != peasycap->saturation) {
-                       rc = adjust_saturation(peasycap, mood);
-                       if (rc) {
-                               SAM("ERROR: adjust_saturation rc = %i\n", rc);
-                               return -EFAULT;
-                       }
-                       JOM(8, "%i=peasycap->saturation\n",
-                                       peasycap->saturation);
-               }
-               mood = peasycap->inputset[input].hue;
-               if (mood != peasycap->hue) {
-                       rc = adjust_hue(peasycap, mood);
-                       if (rc) {
-                               SAM("ERROR: adjust_hue rc = %i\n", rc);
-                               return -EFAULT;
-                       }
-                       JOM(8, "%i=peasycap->hue\n", peasycap->hue);
-               }
-       } else {
-               SAM("MISTAKE: easycap.inputset[%i] unpopulated\n", input);
-               return -ENOENT;
-       }
-/*---------------------------------------------------------------------------*/
-       if (!peasycap->pusb_device) {
-               SAM("ERROR: peasycap->pusb_device is NULL\n");
-               return -ENODEV;
-       }
-       rc = usb_set_interface(peasycap->pusb_device,
-                               peasycap->video_interface,
-                               peasycap->video_altsetting_on);
-       if (rc) {
-               SAM("ERROR: usb_set_interface() rc = %i\n", rc);
-               return -EFAULT;
-       }
-       rc = start_100(peasycap->pusb_device);
-       if (rc) {
-               SAM("ERROR: start_100() rc = %i\n", rc);
-               return -EFAULT;
-       }
-       if (resubmit)
-               easycap_video_submit_urbs(peasycap);
-
-       peasycap->video_isoc_sequence = VIDEO_ISOC_BUFFER_MANY - 1;
-       peasycap->video_idle = video_idlenow;
-       peasycap->audio_idle = audio_idlenow;
-       peasycap->video_junk = 0;
-
-       return 0;
-}
-/*****************************************************************************/
-int easycap_video_submit_urbs(struct easycap *peasycap)
-{
-       struct data_urb *pdata_urb;
-       struct urb *purb;
-       struct list_head *plist_head;
-       int j, isbad, nospc, m, rc;
-       int isbuf;
-
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return -EFAULT;
-       }
-
-       if (!peasycap->purb_video_head) {
-               SAY("ERROR: peasycap->urb_video_head uninitialized\n");
-               return -EFAULT;
-       }
-       if (!peasycap->pusb_device) {
-               SAY("ERROR: peasycap->pusb_device is NULL\n");
-               return -ENODEV;
-       }
-       if (!peasycap->video_isoc_streaming) {
-               JOM(4, "submission of all video urbs\n");
-               isbad = 0;  nospc = 0;  m = 0;
-               list_for_each(plist_head, (peasycap->purb_video_head)) {
-                       pdata_urb = list_entry(plist_head,
-                                               struct data_urb, list_head);
-                       if (pdata_urb && pdata_urb->purb) {
-                               purb = pdata_urb->purb;
-                               isbuf = pdata_urb->isbuf;
-                               purb->interval = 1;
-                               purb->dev = peasycap->pusb_device;
-                               purb->pipe =
-                                       usb_rcvisocpipe(peasycap->pusb_device,
-                                       peasycap->video_endpointnumber);
-                               purb->transfer_flags = URB_ISO_ASAP;
-                               purb->transfer_buffer =
-                                       peasycap->video_isoc_buffer[isbuf].pgo;
-                               purb->transfer_buffer_length =
-                                       peasycap->video_isoc_buffer_size;
-                               purb->complete = easycap_complete;
-                               purb->context = peasycap;
-                               purb->start_frame = 0;
-                               purb->number_of_packets =
-                                       peasycap->video_isoc_framesperdesc;
-
-                               for (j = 0;  j < peasycap->video_isoc_framesperdesc; j++) {
-                                       purb->iso_frame_desc[j]. offset =
-                                               j * peasycap->video_isoc_maxframesize;
-                                       purb->iso_frame_desc[j]. length =
-                                               peasycap->video_isoc_maxframesize;
-                               }
-
-                               rc = usb_submit_urb(purb, GFP_KERNEL);
-                               if (rc) {
-                                       isbad++;
-                                       SAM("ERROR: usb_submit_urb() failed "
-                                               "for urb with rc:-%s\n",
-                                                       strerror(rc));
-                                       if (rc == -ENOSPC)
-                                               nospc++;
-                               } else {
-                                       m++;
-                               }
-                       } else {
-                               isbad++;
-                       }
-               }
-               if (nospc) {
-                       SAM("-ENOSPC=usb_submit_urb() for %i urbs\n", nospc);
-                       SAM(".....  possibly inadequate USB bandwidth\n");
-                       peasycap->video_eof = 1;
-               }
-
-               if (isbad)
-                       easycap_video_kill_urbs(peasycap);
-               else
-                       peasycap->video_isoc_streaming = 1;
-       } else {
-               JOM(4, "already streaming video urbs\n");
-       }
-       return 0;
-}
-/*****************************************************************************/
-int easycap_audio_kill_urbs(struct easycap *peasycap)
-{
-       int m;
-       struct list_head *plist_head;
-       struct data_urb *pdata_urb;
-
-       if (!peasycap->audio_isoc_streaming)
-               return 0;
-
-       if (!peasycap->purb_audio_head) {
-               SAM("ERROR: peasycap->purb_audio_head is NULL\n");
-               return -EFAULT;
-       }
-
-       peasycap->audio_isoc_streaming = 0;
-       m = 0;
-       list_for_each(plist_head, peasycap->purb_audio_head) {
-               pdata_urb = list_entry(plist_head, struct data_urb, list_head);
-               if (pdata_urb && pdata_urb->purb) {
-                       usb_kill_urb(pdata_urb->purb);
-                       m++;
-               }
-       }
-
-       JOM(4, "%i audio urbs killed\n", m);
-
-       return 0;
-}
-int easycap_video_kill_urbs(struct easycap *peasycap)
-{
-       int m;
-       struct list_head *plist_head;
-       struct data_urb *pdata_urb;
-
-       if (!peasycap->video_isoc_streaming)
-               return 0;
-
-       if (!peasycap->purb_video_head) {
-               SAM("ERROR: peasycap->purb_video_head is NULL\n");
-               return -EFAULT;
-       }
-
-       peasycap->video_isoc_streaming = 0;
-       JOM(4, "killing video urbs\n");
-       m = 0;
-       list_for_each(plist_head, (peasycap->purb_video_head)) {
-               pdata_urb = list_entry(plist_head, struct data_urb, list_head);
-               if (pdata_urb && pdata_urb->purb) {
-                       usb_kill_urb(pdata_urb->purb);
-                       m++;
-               }
-       }
-       JOM(4, "%i video urbs killed\n", m);
-
-       return 0;
-}
-/****************************************************************************/
-/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
-/*--------------------------------------------------------------------------*/
-static int easycap_open_noinode(struct file *file)
-{
-       return easycap_open(NULL, file);
-}
-
-static int videodev_release(struct video_device *pvideo_device)
-{
-       struct easycap *peasycap;
-
-       peasycap = video_get_drvdata(pvideo_device);
-       if (!peasycap) {
-               SAY("ERROR:  peasycap is NULL\n");
-               SAY("ending unsuccessfully\n");
-               return -EFAULT;
-       }
-       if (easycap_video_kill_urbs(peasycap)) {
-               SAM("ERROR: easycap_video_kill_urbs() failed\n");
-               return -EFAULT;
-       }
-       JOM(4, "ending successfully\n");
-       return 0;
-}
-
-/*****************************************************************************/
-static unsigned int easycap_poll(struct file *file, poll_table *wait)
-{
-       struct easycap *peasycap;
-       int rc, kd;
-
-       JOT(8, "\n");
-
-       if (NULL == ((poll_table *)wait))
-               JOT(8, "WARNING:  poll table pointer is NULL ... continuing\n");
-       if (!file) {
-               SAY("ERROR:  file pointer is NULL\n");
-               return -ERESTARTSYS;
-       }
-       peasycap = file->private_data;
-       if (!peasycap) {
-               SAY("ERROR:  peasycap is NULL\n");
-               return -EFAULT;
-       }
-       if (!peasycap->pusb_device) {
-               SAY("ERROR:  peasycap->pusb_device is NULL\n");
-               return -EFAULT;
-       }
-/*---------------------------------------------------------------------------*/
-       kd = easycap_isdongle(peasycap);
-       if (0 <= kd && DONGLE_MANY > kd) {
-               if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_video)) {
-                       SAY("ERROR: cannot down dongle[%i].mutex_video\n", kd);
-                       return -ERESTARTSYS;
-               }
-               JOM(4, "locked dongle[%i].mutex_video\n", kd);
-       /*
-        *  MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER
-        *  peasycap, IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL.
-        *  IF NECESSARY, BAIL OUT.
-        */
-               if (kd != easycap_isdongle(peasycap)) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -ERESTARTSYS;
-               }
-               if (!file) {
-                       SAY("ERROR:  file is NULL\n");
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -ERESTARTSYS;
-               }
-               peasycap = file->private_data;
-               if (!peasycap) {
-                       SAY("ERROR:  peasycap is NULL\n");
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -ERESTARTSYS;
-               }
-               if (!peasycap->pusb_device) {
-                       SAM("ERROR: peasycap->pusb_device is NULL\n");
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return -ERESTARTSYS;
-               }
-       } else
-       /*
-        *  IF easycap_usb_disconnect() HAS ALREADY FREED POINTER peasycap
-        *  BEFORE THE ATTEMPT TO ACQUIRE THE SEMAPHORE, isdongle() WILL
-        *  HAVE FAILED.  BAIL OUT.
-       */
-               return -ERESTARTSYS;
-/*---------------------------------------------------------------------------*/
-       rc = easycap_video_dqbuf(peasycap, 0);
-       peasycap->polled = 1;
-       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-       if (rc)
-               return POLLERR;
-
-       return POLLIN | POLLRDNORM;
-}
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- *  IF mode IS NONZERO THIS ROUTINE RETURNS -EAGAIN RATHER THAN BLOCKING.
- */
-/*---------------------------------------------------------------------------*/
-int easycap_video_dqbuf(struct easycap *peasycap, int mode)
-{
-       int input, ifield, miss, rc;
-
-
-       if (!peasycap) {
-               SAY("ERROR:  peasycap is NULL\n");
-               return -EFAULT;
-       }
-       if (!peasycap->pusb_device) {
-               SAY("ERROR:  peasycap->pusb_device is NULL\n");
-               return -EFAULT;
-       }
-       ifield = 0;
-       JOM(8, "%i=ifield\n", ifield);
-/*---------------------------------------------------------------------------*/
-/*
- *  CHECK FOR LOST INPUT SIGNAL.
- *
- *  FOR THE FOUR-CVBS EasyCAP, THIS DOES NOT WORK AS EXPECTED.
- *  IF INPUT 0 IS PRESENT AND SYNC ACQUIRED, UNPLUGGING INPUT 4 DOES NOT
- *  RESULT IN SETTING BIT 0x40 ON REGISTER 0x1F, PRESUMABLY BECAUSE THERE
- *  IS FLYWHEELING ON INPUT 0.  THE UPSHOT IS:
- *
- *    INPUT 0   PLUGGED, INPUT 4   PLUGGED => SCREEN 0 OK,   SCREEN 4 OK
- *    INPUT 0   PLUGGED, INPUT 4 UNPLUGGED => SCREEN 0 OK,   SCREEN 4 BLACK
- *    INPUT 0 UNPLUGGED, INPUT 4   PLUGGED => SCREEN 0 BARS, SCREEN 4 OK
- *    INPUT 0 UNPLUGGED, INPUT 4 UNPLUGGED => SCREEN 0 BARS, SCREEN 4 BARS
-*/
-/*---------------------------------------------------------------------------*/
-       input = peasycap->input;
-       if (0 <= input && INPUT_MANY > input) {
-               rc = read_saa(peasycap->pusb_device, 0x1F);
-               if (0 <= rc) {
-                       if (rc & 0x40)
-                               peasycap->lost[input] += 1;
-                       else
-                               peasycap->lost[input] -= 2;
-
-               if (0 > peasycap->lost[input])
-                       peasycap->lost[input] = 0;
-               else if ((2 * VIDEO_LOST_TOLERATE) < peasycap->lost[input])
-                       peasycap->lost[input] = (2 * VIDEO_LOST_TOLERATE);
-               }
-       }
-/*---------------------------------------------------------------------------*/
-/*
- *  WAIT FOR FIELD ifield  (0 => TOP, 1 => BOTTOM)
- */
-/*---------------------------------------------------------------------------*/
-       miss = 0;
-       while ((peasycap->field_read == peasycap->field_fill) ||
-              (0 != (0xFF00 & peasycap->field_buffer
-                                       [peasycap->field_read][0].kount)) ||
-             (ifield != (0x00FF & peasycap->field_buffer
-                                       [peasycap->field_read][0].kount))) {
-               if (mode)
-                       return -EAGAIN;
-
-               JOM(8, "first wait  on wq_video, %i=field_read %i=field_fill\n",
-                               peasycap->field_read, peasycap->field_fill);
-
-               if (0 != (wait_event_interruptible(peasycap->wq_video,
-                               (peasycap->video_idle || peasycap->video_eof  ||
-                               ((peasycap->field_read != peasycap->field_fill) &&
-                               (0 == (0xFF00 & peasycap->field_buffer[peasycap->field_read][0].kount)) &&
-                               (ifield == (0x00FF & peasycap->field_buffer[peasycap->field_read][0].kount))))))) {
-                       SAM("aborted by signal\n");
-                       return -EIO;
-               }
-               if (peasycap->video_idle) {
-                       JOM(8, "%i=peasycap->video_idle returning -EAGAIN\n",
-                                                       peasycap->video_idle);
-                       return -EAGAIN;
-               }
-               if (peasycap->video_eof) {
-                       JOM(8, "%i=peasycap->video_eof\n", peasycap->video_eof);
-                       #if defined(PERSEVERE)
-                       if (1 == peasycap->status) {
-                               JOM(8, "persevering ...\n");
-                               peasycap->video_eof = 0;
-                               peasycap->audio_eof = 0;
-                               if (0 != reset(peasycap)) {
-                                       JOM(8, " ... failed  returning -EIO\n");
-                                       peasycap->video_eof = 1;
-                                       peasycap->audio_eof = 1;
-                                       easycap_video_kill_urbs(peasycap);
-                                       return -EIO;
-                               }
-                               peasycap->status = 0;
-                               JOM(8, " ... OK  returning -EAGAIN\n");
-                               return -EAGAIN;
-                       }
-                       #endif /*PERSEVERE*/
-                       peasycap->video_eof = 1;
-                       peasycap->audio_eof = 1;
-                       easycap_video_kill_urbs(peasycap);
-                       JOM(8, "returning -EIO\n");
-                       return -EIO;
-               }
-               miss++;
-       }
-       JOM(8, "first awakening on wq_video after %i waits\n", miss);
-
-       rc = field2frame(peasycap);
-       if (rc)
-               SAM("ERROR: field2frame() rc = %i\n", rc);
-/*---------------------------------------------------------------------------*/
-/*
- *  WAIT FOR THE OTHER FIELD
- */
-/*---------------------------------------------------------------------------*/
-       if (ifield)
-               ifield = 0;
-       else
-               ifield = 1;
-       miss = 0;
-       while ((peasycap->field_read == peasycap->field_fill) ||
-              (0 != (0xFF00 & peasycap->field_buffer[peasycap->field_read][0].kount)) ||
-              (ifield != (0x00FF & peasycap->field_buffer[peasycap->field_read][0].kount))) {
-               if (mode)
-                       return -EAGAIN;
-
-               JOM(8, "second wait on wq_video %i=field_read  %i=field_fill\n",
-                               peasycap->field_read, peasycap->field_fill);
-               if (0 != (wait_event_interruptible(peasycap->wq_video,
-                       (peasycap->video_idle || peasycap->video_eof  ||
-                       ((peasycap->field_read != peasycap->field_fill) &&
-                        (0 == (0xFF00 & peasycap->field_buffer[peasycap->field_read][0].kount)) &&
-                        (ifield == (0x00FF & peasycap->field_buffer[peasycap->field_read][0].kount))))))) {
-                       SAM("aborted by signal\n");
-                       return -EIO;
-               }
-               if (peasycap->video_idle) {
-                       JOM(8, "%i=peasycap->video_idle returning -EAGAIN\n",
-                                                       peasycap->video_idle);
-                       return -EAGAIN;
-               }
-               if (peasycap->video_eof) {
-                       JOM(8, "%i=peasycap->video_eof\n", peasycap->video_eof);
-#if defined(PERSEVERE)
-                       if (1 == peasycap->status) {
-                               JOM(8, "persevering ...\n");
-                               peasycap->video_eof = 0;
-                               peasycap->audio_eof = 0;
-                               if (0 != reset(peasycap)) {
-                                       JOM(8, " ... failed returning -EIO\n");
-                                       peasycap->video_eof = 1;
-                                       peasycap->audio_eof = 1;
-                                       easycap_video_kill_urbs(peasycap);
-                                       return -EIO;
-                               }
-                               peasycap->status = 0;
-                               JOM(8, " ... OK ... returning -EAGAIN\n");
-                               return -EAGAIN;
-                       }
-#endif /*PERSEVERE*/
-                       peasycap->video_eof = 1;
-                       peasycap->audio_eof = 1;
-                       easycap_video_kill_urbs(peasycap);
-                       JOM(8, "returning -EIO\n");
-                       return -EIO;
-               }
-               miss++;
-       }
-       JOM(8, "second awakening on wq_video after %i waits\n", miss);
-
-       rc = field2frame(peasycap);
-       if (rc)
-               SAM("ERROR: field2frame() rc = %i\n", rc);
-/*---------------------------------------------------------------------------*/
-/*
- *  WASTE THIS FRAME
-*/
-/*---------------------------------------------------------------------------*/
-       if (peasycap->skip) {
-               peasycap->skipped++;
-               if (peasycap->skip != peasycap->skipped)
-                       return peasycap->skip - peasycap->skipped;
-               else
-                       peasycap->skipped = 0;
-       }
-/*---------------------------------------------------------------------------*/
-       peasycap->frame_read = peasycap->frame_fill;
-       peasycap->queued[peasycap->frame_read] = 0;
-       peasycap->done[peasycap->frame_read]   = V4L2_BUF_FLAG_DONE;
-
-       peasycap->frame_fill++;
-       if (peasycap->frame_buffer_many <= peasycap->frame_fill)
-               peasycap->frame_fill = 0;
-
-       if (0x01 & easycap_standard[peasycap->standard_offset].mask)
-               peasycap->frame_buffer[peasycap->frame_read][0].kount =
-                                                       V4L2_FIELD_TOP;
-       else
-               peasycap->frame_buffer[peasycap->frame_read][0].kount =
-                                                       V4L2_FIELD_BOTTOM;
-
-
-       JOM(8, "setting:    %i=peasycap->frame_read\n", peasycap->frame_read);
-       JOM(8, "bumped to:  %i=peasycap->frame_fill\n", peasycap->frame_fill);
-
-       return 0;
-}
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- *  BY DEFINITION, odd IS true  FOR THE FIELD OCCUPYING LINES 1,3,5,...,479
- *                 odd IS false FOR THE FIELD OCCUPYING LINES 0,2,4,...,478
- *
- *  WHEN BOOLEAN PARAMETER decimatepixel IS true, ONLY THE FIELD FOR WHICH
- *  odd==false IS TRANSFERRED TO THE FRAME BUFFER.
- *
- */
-/*---------------------------------------------------------------------------*/
-static int field2frame(struct easycap *peasycap)
-{
-
-       void *pex, *pad;
-       int kex, kad, mex, mad, rex, rad, rad2;
-       int c2, c3, w2, w3, cz, wz;
-       int rc, bytesperpixel, multiplier;
-       int  much, more, over, rump, caches, input;
-       u8 mask, margin;
-       bool odd, isuy, decimatepixel, badinput;
-
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return -EFAULT;
-       }
-
-       badinput = false;
-       input = 0x07 & peasycap->field_buffer[peasycap->field_read][0].input;
-
-       JOM(8, "=====  parity %i, input 0x%02X, field buffer %i --> "
-                                                       "frame buffer %i\n",
-                       peasycap->field_buffer[peasycap->field_read][0].kount,
-                       peasycap->field_buffer[peasycap->field_read][0].input,
-                       peasycap->field_read, peasycap->frame_fill);
-       JOM(8, "=====  %i=bytesperpixel\n", peasycap->bytesperpixel);
-
-/*---------------------------------------------------------------------------*/
-/*
- *  REJECT OR CLEAN BAD FIELDS
- */
-/*---------------------------------------------------------------------------*/
-       if (peasycap->field_read == peasycap->field_fill) {
-               SAM("ERROR: on entry, still filling field buffer %i\n",
-                                               peasycap->field_read);
-               return 0;
-       }
-#ifdef EASYCAP_TESTCARD
-       easycap_testcard(peasycap, peasycap->field_read);
-#else
-       if (0 <= input && INPUT_MANY > input) {
-               if (easycap_bars && VIDEO_LOST_TOLERATE <= peasycap->lost[input])
-                       easycap_testcard(peasycap, peasycap->field_read);
-       }
-#endif /*EASYCAP_TESTCARD*/
-/*---------------------------------------------------------------------------*/
-
-       bytesperpixel = peasycap->bytesperpixel;
-       decimatepixel = peasycap->decimatepixel;
-
-       if ((2 != bytesperpixel) &&
-           (3 != bytesperpixel) &&
-           (4 != bytesperpixel)) {
-               SAM("MISTAKE: %i=bytesperpixel\n", bytesperpixel);
-               return -EFAULT;
-       }
-       if (decimatepixel)
-               multiplier = 2;
-       else
-               multiplier = 1;
-
-       w2 = 2 * multiplier * (peasycap->width);
-       w3 = bytesperpixel * multiplier * (peasycap->width);
-       wz = multiplier * (peasycap->height) *
-               multiplier * (peasycap->width);
-
-       kex = peasycap->field_read;  mex = 0;
-       kad = peasycap->frame_fill;  mad = 0;
-
-       pex = peasycap->field_buffer[kex][0].pgo;  rex = PAGE_SIZE;
-       pad = peasycap->frame_buffer[kad][0].pgo;  rad = PAGE_SIZE;
-       odd = !!(peasycap->field_buffer[kex][0].kount);
-
-       if (odd && (!decimatepixel)) {
-               JOM(8, "initial skipping %4i bytes p.%4i\n",
-                                       w3/multiplier, mad);
-               pad += (w3 / multiplier); rad -= (w3 / multiplier);
-       }
-       isuy = true;
-       mask = 0;  rump = 0;  caches = 0;
-
-       cz = 0;
-       while (cz < wz) {
-               /*
-                *  PROCESS ONE LINE OF FRAME AT FULL RESOLUTION:
-                *  READ   w2   BYTES FROM FIELD BUFFER,
-                *  WRITE  w3   BYTES TO FRAME BUFFER
-                */
-               if (!decimatepixel) {
-                       over = w2;
-                       do {
-                               much = over;  more = 0;
-                               margin = 0;  mask = 0x00;
-                               if (rex < much)
-                                       much = rex;
-                               rump = 0;
-
-                               if (much % 2) {
-                                       SAM("MISTAKE: much is odd\n");
-                                       return -EFAULT;
-                               }
-
-                               more = (bytesperpixel *
-                                               much) / 2;
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-                               if (1 < bytesperpixel) {
-                                       if (rad * 2 < much * bytesperpixel) {
-                                               /*
-                                                * INJUDICIOUS ALTERATION OF
-                                                * THIS STATEMENT BLOCK WILL
-                                                * CAUSE BREAKAGE.  BEWARE.
-                                                */
-                                               rad2 = rad + bytesperpixel - 1;
-                                               much = ((((2 * rad2)/bytesperpixel)/2) * 2);
-                                               rump = ((bytesperpixel * much) / 2) - rad;
-                                               more = rad;
-                                       }
-                                       mask = (u8)rump;
-                                       margin = 0;
-                                       if (much == rex) {
-                                               mask |= 0x04;
-                                               if ((mex + 1) < FIELD_BUFFER_SIZE / PAGE_SIZE)
-                                                       margin = *((u8 *)(peasycap->field_buffer[kex][mex + 1].pgo));
-                                               else
-                                                       mask |= 0x08;
-                                       }
-                               } else {
-                                       SAM("MISTAKE: %i=bytesperpixel\n",
-                                                       bytesperpixel);
-                                       return -EFAULT;
-                               }
-                               if (rump)
-                                       caches++;
-                                       if (badinput) {
-                                               JOM(8, "ERROR: 0x%02X=->field_buffer"
-                                                       "[%i][%i].input, "
-                                                       "0x%02X=(0x08|->input)\n",
-                                                       peasycap->field_buffer
-                                                       [kex][mex].input, kex, mex,
-                                                       (0x08|peasycap->input));
-                                       }
-                               rc = redaub(peasycap, pad, pex, much, more,
-                                                               mask, margin, isuy);
-                               if (0 > rc) {
-                                       SAM("ERROR: redaub() failed\n");
-                                       return -EFAULT;
-                               }
-                               if (much % 4)
-                                       isuy = !isuy;
-
-                               over -= much;   cz += much;
-                               pex  += much;  rex -= much;
-                               if (!rex) {
-                                       mex++;
-                                       pex = peasycap->field_buffer[kex][mex].pgo;
-                                       rex = PAGE_SIZE;
-                                       if (peasycap->field_buffer[kex][mex].input != (0x08|peasycap->input))
-                                               badinput = true;
-                               }
-                               pad  += more;
-                               rad -= more;
-                               if (!rad) {
-                                       mad++;
-                                       pad = peasycap->frame_buffer[kad][mad].pgo;
-                                       rad = PAGE_SIZE;
-                                       if (rump) {
-                                               pad += rump;
-                                               rad -= rump;
-                                       }
-                               }
-                       } while (over);
-/*---------------------------------------------------------------------------*/
-/*
- *  SKIP  w3 BYTES IN TARGET FRAME BUFFER,
- *  UNLESS IT IS THE LAST LINE OF AN ODD FRAME
- */
-/*---------------------------------------------------------------------------*/
-                       if (!odd || (cz != wz)) {
-                               over = w3;
-                               do {
-                                       if (!rad) {
-                                               mad++;
-                                               pad = peasycap->frame_buffer
-                                                       [kad][mad].pgo;
-                                               rad = PAGE_SIZE;
-                                       }
-                                       more = over;
-                                       if (rad < more)
-                                               more = rad;
-                                       over -= more;
-                                       pad  += more;
-                                       rad  -= more;
-                               } while (over);
-                       }
-/*---------------------------------------------------------------------------*/
-/*
- *  PROCESS ONE LINE OF FRAME AT REDUCED RESOLUTION:
- *  ONLY IF false==odd,
- *  READ   w2   BYTES FROM FIELD BUFFER,
- *  WRITE  w3 / 2  BYTES TO FRAME BUFFER
- */
-/*---------------------------------------------------------------------------*/
-               } else if (!odd) {
-                       over = w2;
-                       do {
-                               much = over;  more = 0;  margin = 0;  mask = 0x00;
-                               if (rex < much)
-                                       much = rex;
-                               rump = 0;
-
-                               if (much % 2) {
-                                       SAM("MISTAKE: much is odd\n");
-                                       return -EFAULT;
-                               }
-
-                               more = (bytesperpixel * much) / 4;
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-                               if (1 < bytesperpixel) {
-                                       if (rad * 4 < much * bytesperpixel) {
-                                               /*
-                                                * INJUDICIOUS ALTERATION OF
-                                                * THIS STATEMENT BLOCK
-                                                * WILL CAUSE BREAKAGE.
-                                                * BEWARE.
-                                                */
-                                               rad2 = rad + bytesperpixel - 1;
-                                               much = ((((2 * rad2) / bytesperpixel) / 2) * 4);
-                                               rump = ((bytesperpixel * much) / 4) - rad;
-                                               more = rad;
-                                       }
-                                       mask = (u8)rump;
-                                       margin = 0;
-                                       if (much == rex) {
-                                               mask |= 0x04;
-                                               if ((mex + 1) < FIELD_BUFFER_SIZE / PAGE_SIZE)
-                                                       margin = *((u8 *)(peasycap->field_buffer[kex][mex + 1].pgo));
-                                               else
-                                                       mask |= 0x08;
-                                       }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-                               } else {
-                                       SAM("MISTAKE: %i=bytesperpixel\n",
-                                               bytesperpixel);
-                                       return -EFAULT;
-                               }
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-                               if (rump)
-                                       caches++;
-
-                                       if (badinput) {
-                                               JOM(8, "ERROR: 0x%02X=->field_buffer"
-                                                       "[%i][%i].input, "
-                                                       "0x%02X=(0x08|->input)\n",
-                                                       peasycap->field_buffer
-                                                       [kex][mex].input, kex, mex,
-                                                       (0x08|peasycap->input));
-                                       }
-                               rc = redaub(peasycap, pad, pex, much, more,
-                                                       mask, margin, isuy);
-                               if (0 > rc) {
-                                       SAM("ERROR: redaub() failed\n");
-                                       return -EFAULT;
-                               }
-                               over -= much;   cz += much;
-                               pex  += much;  rex -= much;
-                               if (!rex) {
-                                       mex++;
-                                       pex = peasycap->field_buffer[kex][mex].pgo;
-                                       rex = PAGE_SIZE;
-                                       if (peasycap->field_buffer[kex][mex].input !=
-                                                       (0x08|peasycap->input))
-                                               badinput = true;
-                               }
-                               pad  += more;
-                               rad -= more;
-                               if (!rad) {
-                                       mad++;
-                                       pad = peasycap->frame_buffer[kad][mad].pgo;
-                                       rad = PAGE_SIZE;
-                                       if (rump) {
-                                               pad += rump;
-                                               rad -= rump;
-                                       }
-                               }
-                       } while (over);
-/*---------------------------------------------------------------------------*/
-/*
- *  OTHERWISE JUST
- *  READ   w2   BYTES FROM FIELD BUFFER AND DISCARD THEM
- */
-/*---------------------------------------------------------------------------*/
-               } else {
-                       over = w2;
-                       do {
-                               if (!rex) {
-                                       mex++;
-                                       pex = peasycap->field_buffer[kex][mex].pgo;
-                                       rex = PAGE_SIZE;
-                                       if (peasycap->field_buffer[kex][mex].input !=
-                                                       (0x08|peasycap->input)) {
-                                               JOM(8, "ERROR: 0x%02X=->field_buffer"
-                                                       "[%i][%i].input, "
-                                                       "0x%02X=(0x08|->input)\n",
-                                                       peasycap->field_buffer
-                                                       [kex][mex].input, kex, mex,
-                                                       (0x08|peasycap->input));
-                                               badinput = true;
-                                       }
-                               }
-                               much = over;
-                               if (rex < much)
-                                       much = rex;
-                               over -= much;
-                               cz += much;
-                               pex  += much;
-                               rex -= much;
-                       } while (over);
-               }
-       }
-/*---------------------------------------------------------------------------*/
-/*
- *  SANITY CHECKS
- */
-/*---------------------------------------------------------------------------*/
-       c2 = (mex + 1)*PAGE_SIZE - rex;
-       if (cz != c2)
-               SAM("ERROR: discrepancy %i in bytes read\n", c2 - cz);
-       c3 = (mad + 1)*PAGE_SIZE - rad;
-
-       if (!decimatepixel) {
-               if (bytesperpixel * cz != c3)
-                       SAM("ERROR: discrepancy %i in bytes written\n",
-                                       c3 - (bytesperpixel * cz));
-       } else {
-               if (!odd) {
-                       if (bytesperpixel *
-                               cz != (4 * c3))
-                               SAM("ERROR: discrepancy %i in bytes written\n",
-                                       (2*c3)-(bytesperpixel * cz));
-                       } else {
-                               if (0 != c3)
-                                       SAM("ERROR: discrepancy %i "
-                                           "in bytes written\n", c3);
-                       }
-       }
-       if (rump)
-               SAM("WORRY: undischarged cache at end of line in frame buffer\n");
-
-       JOM(8, "===== field2frame(): %i bytes --> %i bytes (incl skip)\n", c2, c3);
-       JOM(8, "===== field2frame(): %i=mad  %i=rad\n", mad, rad);
-
-       if (odd)
-               JOM(8, "+++++ field2frame():  frame buffer %i is full\n", kad);
-
-       if (peasycap->field_read == peasycap->field_fill)
-               SAM("WARNING: on exit, filling field buffer %i\n",
-                                               peasycap->field_read);
-
-       if (caches)
-               JOM(8, "%i=caches\n", caches);
-       return 0;
-}
-/*---------------------------------------------------------------------------*/
-/*
- *  DECIMATION AND COLOURSPACE CONVERSION.
- *
- *  THIS ROUTINE REQUIRES THAT ALL THE DATA TO BE READ RESIDES ON ONE PAGE
- *  AND THAT ALL THE DATA TO BE WRITTEN RESIDES ON ONE (DIFFERENT) PAGE.
- *  THE CALLING ROUTINE MUST ENSURE THAT THIS REQUIREMENT IS MET, AND MUST
- *  ALSO ENSURE THAT much IS EVEN.
- *
- *  much BYTES ARE READ, AT LEAST (bytesperpixel * much)/2 BYTES ARE WRITTEN
- *  IF THERE IS NO DECIMATION, HALF THIS AMOUNT IF THERE IS DECIMATION.
- *
- *  mask IS ZERO WHEN NO SPECIAL BEHAVIOUR REQUIRED. OTHERWISE IT IS SET THUS:
- *     0x03 & mask =  number of bytes to be written to cache instead of to
- *                    frame buffer
- *     0x04 & mask => use argument margin to set the chrominance for last pixel
- *     0x08 & mask => do not set the chrominance for last pixel
- *
- *  YUV to RGB CONVERSION IS (OR SHOULD BE) ITU-R BT 601.
- *
- *  THERE IS A LOT OF CODE REPETITION IN THIS ROUTINE IN ORDER TO AVOID
- *  INEFFICIENT SWITCHING INSIDE INNER LOOPS.  REARRANGING THE LOGIC TO
- *  REDUCE CODE LENGTH WILL GENERALLY IMPAIR RUNTIME PERFORMANCE.  BEWARE.
- */
-/*---------------------------------------------------------------------------*/
-static int redaub(struct easycap *peasycap,
-               void *pad, void *pex, int much, int more,
-               u8 mask, u8 margin, bool isuy)
-{
-       static s32 ay[256], bu[256], rv[256], gu[256], gv[256];
-       u8 *pcache;
-       u8 r, g, b, y, u, v, c, *p2, *p3, *pz, *pr;
-       int  bytesperpixel;
-       bool byteswaporder, decimatepixel, last;
-       int j, rump;
-       s32 tmp;
-
-       if (much % 2) {
-               SAM("MISTAKE: much is odd\n");
-               return -EFAULT;
-       }
-       bytesperpixel = peasycap->bytesperpixel;
-       byteswaporder = peasycap->byteswaporder;
-       decimatepixel = peasycap->decimatepixel;
-
-/*---------------------------------------------------------------------------*/
-       if (!bu[255]) {
-               for (j = 0; j < 112; j++) {
-                       tmp = (0xFF00 & (453 * j)) >> 8;
-                       bu[j + 128] =  tmp; bu[127 - j] = -tmp;
-                       tmp = (0xFF00 & (359 * j)) >> 8;
-                       rv[j + 128] =  tmp; rv[127 - j] = -tmp;
-                       tmp = (0xFF00 & (88 * j)) >> 8;
-                       gu[j + 128] =  tmp; gu[127 - j] = -tmp;
-                       tmp = (0xFF00 & (183 * j)) >> 8;
-                       gv[j + 128] =  tmp; gv[127 - j] = -tmp;
-               }
-               for (j = 0; j < 16; j++) {
-                       bu[j] = bu[16]; rv[j] = rv[16];
-                       gu[j] = gu[16]; gv[j] = gv[16];
-               }
-               for (j = 240; j < 256; j++) {
-                       bu[j] = bu[239]; rv[j] = rv[239];
-                       gu[j] = gu[239]; gv[j] = gv[239];
-               }
-               for (j =  16; j < 236; j++)
-                       ay[j] = j;
-               for (j =   0; j <  16; j++)
-                       ay[j] = ay[16];
-               for (j = 236; j < 256; j++)
-                       ay[j] = ay[235];
-               JOM(8, "lookup tables are prepared\n");
-       }
-       pcache = peasycap->pcache;
-       if (!pcache)
-               pcache = &peasycap->cache[0];
-/*---------------------------------------------------------------------------*/
-/*
- *  TRANSFER CONTENTS OF CACHE TO THE FRAME BUFFER
- */
-/*---------------------------------------------------------------------------*/
-       if (!pcache) {
-               SAM("MISTAKE: pcache is NULL\n");
-               return -EFAULT;
-       }
-
-       if (pcache != &peasycap->cache[0])
-               JOM(16, "cache has %i bytes\n", (int)(pcache - &peasycap->cache[0]));
-       p2 = &peasycap->cache[0];
-       p3 = (u8 *)pad - (int)(pcache - &peasycap->cache[0]);
-       while (p2 < pcache) {
-               *p3++ = *p2;  p2++;
-       }
-       pcache = &peasycap->cache[0];
-       if (p3 != pad) {
-               SAM("MISTAKE: pointer misalignment\n");
-               return -EFAULT;
-       }
-/*---------------------------------------------------------------------------*/
-       rump = (int)(0x03 & mask);
-       u = 0; v = 0;
-       p2 = (u8 *)pex;  pz = p2 + much;  pr = p3 + more;  last = false;
-       p2++;
-
-       if (isuy)
-               u = *(p2 - 1);
-       else
-               v = *(p2 - 1);
-
-       if (rump)
-               JOM(16, "%4i=much  %4i=more  %i=rump\n", much, more, rump);
-
-/*---------------------------------------------------------------------------*/
-       switch (bytesperpixel) {
-       case 2: {
-               if (!decimatepixel) {
-                       memcpy(pad, pex, (size_t)much);
-                       if (!byteswaporder) {
-                               /* UYVY */
-                               return 0;
-                       } else {
-                               /* YUYV */
-                               p3 = (u8 *)pad;  pz = p3 + much;
-                               while  (pz > p3) {
-                                       c = *p3;
-                                       *p3 = *(p3 + 1);
-                                       *(p3 + 1) = c;
-                                       p3 += 2;
-                               }
-                               return 0;
-                       }
-               } else {
-                       if (!byteswaporder) {
-                               /*  UYVY DECIMATED */
-                               p2 = (u8 *)pex;  p3 = (u8 *)pad;  pz = p2 + much;
-                               while (pz > p2) {
-                                       *p3 = *p2;
-                                       *(p3 + 1) = *(p2 + 1);
-                                       *(p3 + 2) = *(p2 + 2);
-                                       *(p3 + 3) = *(p2 + 3);
-                                       p3 += 4;  p2 += 8;
-                               }
-                               return 0;
-                       } else {
-                               /* YUYV DECIMATED */
-                               p2 = (u8 *)pex;  p3 = (u8 *)pad;  pz = p2 + much;
-                               while (pz > p2) {
-                                       *p3 = *(p2 + 1);
-                                       *(p3 + 1) = *p2;
-                                       *(p3 + 2) = *(p2 + 3);
-                                       *(p3 + 3) = *(p2 + 2);
-                                       p3 += 4;  p2 += 8;
-                               }
-                               return 0;
-                       }
-               }
-               break;
-               }
-       case 3:
-               {
-               if (!decimatepixel) {
-                       if (!byteswaporder) {
-                               /* RGB */
-                               while (pz > p2) {
-                                       if (pr <= (p3 + bytesperpixel))
-                                               last = true;
-                                       else
-                                               last = false;
-                                       y = *p2;
-                                       if (last && (0x0C & mask)) {
-                                               if (0x04 & mask) {
-                                                       if (isuy)
-                                                               v = margin;
-                                                       else
-                                                               u = margin;
-                                               } else
-                                                       if (0x08 & mask)
-                                                               ;
-                                       } else {
-                                               if (isuy)
-                                                       v = *(p2 + 1);
-                                               else
-                                                       u = *(p2 + 1);
-                                       }
-
-                                       tmp = ay[(int)y] + rv[(int)v];
-                                       r = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                               0 : (u8)tmp);
-                                       tmp = ay[(int)y] - gu[(int)u] - gv[(int)v];
-                                       g = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                               0 : (u8)tmp);
-                                       tmp = ay[(int)y] + bu[(int)u];
-                                       b = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                               0 : (u8)tmp);
-
-                                       if (last && rump) {
-                                               pcache = &peasycap->cache[0];
-                                               switch (bytesperpixel - rump) {
-                                               case 1: {
-                                                       *p3 = r;
-                                                       *pcache++ = g;
-                                                       *pcache++ = b;
-                                                       break;
-                                               }
-                                               case 2: {
-                                                       *p3 = r;
-                                                       *(p3 + 1) = g;
-                                                       *pcache++ = b;
-                                                       break;
-                                               }
-                                               default: {
-                                                       SAM("MISTAKE: %i=rump\n",
-                                                               bytesperpixel - rump);
-                                                       return -EFAULT;
-                                               }
-                                               }
-                                       } else {
-                                               *p3 = r;
-                                               *(p3 + 1) = g;
-                                               *(p3 + 2) = b;
-                                       }
-                                       p2 += 2;
-                                       if (isuy)
-                                               isuy = false;
-                                       else
-                                               isuy = true;
-                                       p3 += bytesperpixel;
-                               }
-                               return 0;
-                       } else {
-                               /* BGR */
-                               while (pz > p2) {
-                                       if (pr <= (p3 + bytesperpixel))
-                                               last = true;
-                                       else
-                                               last = false;
-                                       y = *p2;
-                                       if (last && (0x0C & mask)) {
-                                               if (0x04 & mask) {
-                                                       if (isuy)
-                                                               v = margin;
-                                                       else
-                                                               u = margin;
-                                               }
-                                       else
-                                               if (0x08 & mask)
-                                                       ;
-                                       } else {
-                                               if (isuy)
-                                                       v = *(p2 + 1);
-                                               else
-                                                       u = *(p2 + 1);
-                                       }
-
-                                       tmp = ay[(int)y] + rv[(int)v];
-                                       r = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-                                       tmp = ay[(int)y] - gu[(int)u] - gv[(int)v];
-                                       g = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-                                       tmp = ay[(int)y] + bu[(int)u];
-                                       b = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-
-                                       if (last && rump) {
-                                               pcache = &peasycap->cache[0];
-                                               switch (bytesperpixel - rump) {
-                                               case 1: {
-                                                       *p3 = b;
-                                                       *pcache++ = g;
-                                                       *pcache++ = r;
-                                                       break;
-                                               }
-                                               case 2: {
-                                                       *p3 = b;
-                                                       *(p3 + 1) = g;
-                                                       *pcache++ = r;
-                                                       break;
-                                               }
-                                               default: {
-                                                       SAM("MISTAKE: %i=rump\n",
-                                                               bytesperpixel - rump);
-                                                       return -EFAULT;
-                                               }
-                                               }
-                                       } else {
-                                               *p3 = b;
-                                               *(p3 + 1) = g;
-                                               *(p3 + 2) = r;
-                                               }
-                                       p2 += 2;
-                                       if (isuy)
-                                               isuy = false;
-                                       else
-                                               isuy = true;
-                                       p3 += bytesperpixel;
-                                       }
-                               }
-                       return 0;
-               } else {
-                       if (!byteswaporder) {
-                               /*  RGB DECIMATED */
-                               while (pz > p2) {
-                                       if (pr <= (p3 + bytesperpixel))
-                                               last = true;
-                                       else
-                                               last = false;
-                                       y = *p2;
-                                       if (last && (0x0C & mask)) {
-                                               if (0x04 & mask) {
-                                                       if (isuy)
-                                                               v = margin;
-                                                       else
-                                                               u = margin;
-                                               } else
-                                                       if (0x08 & mask)
-                                                               ;
-                                       } else {
-                                               if (isuy)
-                                                       v = *(p2 + 1);
-                                               else
-                                                       u = *(p2 + 1);
-                                       }
-
-                                       if (isuy) {
-                                               tmp = ay[(int)y] + rv[(int)v];
-                                               r = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-                                               tmp = ay[(int)y] - gu[(int)u] -
-                                                                       gv[(int)v];
-                                               g = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-                                               tmp = ay[(int)y] + bu[(int)u];
-                                               b = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-
-                                               if (last && rump) {
-                                                       pcache = &peasycap->cache[0];
-                                                       switch (bytesperpixel - rump) {
-                                                       case 1: {
-                                                               *p3 = r;
-                                                               *pcache++ = g;
-                                                               *pcache++ = b;
-                                                               break;
-                                                       }
-                                                       case 2: {
-                                                               *p3 = r;
-                                                               *(p3 + 1) = g;
-                                                               *pcache++ = b;
-                                                               break;
-                                                       }
-                                                       default: {
-                                                               SAM("MISTAKE: "
-                                                               "%i=rump\n",
-                                                               bytesperpixel - rump);
-                                                               return -EFAULT;
-                                                       }
-                                                       }
-                                               } else {
-                                                       *p3 = r;
-                                                       *(p3 + 1) = g;
-                                                       *(p3 + 2) = b;
-                                               }
-                                               isuy = false;
-                                               p3 += bytesperpixel;
-                                       } else {
-                                               isuy = true;
-                                       }
-                                       p2 += 2;
-                               }
-                               return 0;
-                       } else {
-                               /* BGR DECIMATED */
-                               while (pz > p2) {
-                                       if (pr <= (p3 + bytesperpixel))
-                                               last = true;
-                                       else
-                                               last = false;
-                                       y = *p2;
-                                       if (last && (0x0C & mask)) {
-                                               if (0x04 & mask) {
-                                                       if (isuy)
-                                                               v = margin;
-                                                       else
-                                                               u = margin;
-                                               } else
-                                                       if (0x08 & mask)
-                                                               ;
-                                       } else {
-                                               if (isuy)
-                                                       v = *(p2 + 1);
-                                               else
-                                                       u = *(p2 + 1);
-                                       }
-
-                                       if (isuy) {
-
-                                               tmp = ay[(int)y] + rv[(int)v];
-                                               r = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-                                               tmp = ay[(int)y] - gu[(int)u] -
-                                                                       gv[(int)v];
-                                               g = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-                                               tmp = ay[(int)y] + bu[(int)u];
-                                               b = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-
-                                               if (last && rump) {
-                                                       pcache = &peasycap->cache[0];
-                                                       switch (bytesperpixel - rump) {
-                                                       case 1: {
-                                                               *p3 = b;
-                                                               *pcache++ = g;
-                                                               *pcache++ = r;
-                                                               break;
-                                                       }
-                                                       case 2: {
-                                                               *p3 = b;
-                                                               *(p3 + 1) = g;
-                                                               *pcache++ = r;
-                                                               break;
-                                                       }
-                                                       default: {
-                                                               SAM("MISTAKE: "
-                                                               "%i=rump\n",
-                                                               bytesperpixel - rump);
-                                                               return -EFAULT;
-                                                       }
-                                                       }
-                                               } else {
-                                                       *p3 = b;
-                                                       *(p3 + 1) = g;
-                                                       *(p3 + 2) = r;
-                                                       }
-                                               isuy = false;
-                                               p3 += bytesperpixel;
-                                               }
-                                       else
-                                               isuy = true;
-                                       p2 += 2;
-                                       }
-                               return 0;
-                               }
-                       }
-               break;
-               }
-       case 4:
-               {
-               if (!decimatepixel) {
-                       if (!byteswaporder) {
-                               /* RGBA */
-                               while (pz > p2) {
-                                       if (pr <= (p3 + bytesperpixel))
-                                               last = true;
-                                       else
-                                               last = false;
-                                       y = *p2;
-                                       if (last && (0x0C & mask)) {
-                                               if (0x04 & mask) {
-                                                       if (isuy)
-                                                               v = margin;
-                                                       else
-                                                               u = margin;
-                                               } else
-                                                        if (0x08 & mask)
-                                                               ;
-                                       } else {
-                                               if (isuy)
-                                                       v = *(p2 + 1);
-                                               else
-                                                       u = *(p2 + 1);
-                                       }
-
-                                       tmp = ay[(int)y] + rv[(int)v];
-                                       r = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-                                       tmp = ay[(int)y] - gu[(int)u] - gv[(int)v];
-                                       g = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-                                       tmp = ay[(int)y] + bu[(int)u];
-                                       b = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-
-                                       if (last && rump) {
-                                               pcache = &peasycap->cache[0];
-                                               switch (bytesperpixel - rump) {
-                                               case 1: {
-                                                       *p3 = r;
-                                                       *pcache++ = g;
-                                                       *pcache++ = b;
-                                                       *pcache++ = 0;
-                                                       break;
-                                               }
-                                               case 2: {
-                                                       *p3 = r;
-                                                       *(p3 + 1) = g;
-                                                       *pcache++ = b;
-                                                       *pcache++ = 0;
-                                                       break;
-                                               }
-                                               case 3: {
-                                                       *p3 = r;
-                                                       *(p3 + 1) = g;
-                                                       *(p3 + 2) = b;
-                                                       *pcache++ = 0;
-                                                       break;
-                                               }
-                                               default: {
-                                                       SAM("MISTAKE: %i=rump\n",
-                                                               bytesperpixel - rump);
-                                                       return -EFAULT;
-                                               }
-                                               }
-                                       } else {
-                                               *p3 = r;
-                                               *(p3 + 1) = g;
-                                               *(p3 + 2) = b;
-                                               *(p3 + 3) = 0;
-                                       }
-                                       p2 += 2;
-                                       if (isuy)
-                                               isuy = false;
-                                       else
-                                               isuy = true;
-                                       p3 += bytesperpixel;
-                               }
-                               return 0;
-                       } else {
-                               /*
-                                *  BGRA
-                                */
-                               while (pz > p2) {
-                                       if (pr <= (p3 + bytesperpixel))
-                                               last = true;
-                                       else
-                                               last = false;
-                                       y = *p2;
-                                       if (last && (0x0C & mask)) {
-                                               if (0x04 & mask) {
-                                                       if (isuy)
-                                                               v = margin;
-                                                       else
-                                                               u = margin;
-                                               } else
-                                                        if (0x08 & mask)
-                                                               ;
-                                       } else {
-                                               if (isuy)
-                                                       v = *(p2 + 1);
-                                               else
-                                                       u = *(p2 + 1);
-                                       }
-
-                                       tmp = ay[(int)y] + rv[(int)v];
-                                       r = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-                                       tmp = ay[(int)y] - gu[(int)u] - gv[(int)v];
-                                       g = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-                                       tmp = ay[(int)y] + bu[(int)u];
-                                       b = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-
-                                       if (last && rump) {
-                                               pcache = &peasycap->cache[0];
-                                               switch (bytesperpixel - rump) {
-                                               case 1: {
-                                                       *p3 = b;
-                                                       *pcache++ = g;
-                                                       *pcache++ = r;
-                                                       *pcache++ = 0;
-                                                       break;
-                                               }
-                                               case 2: {
-                                                       *p3 = b;
-                                                       *(p3 + 1) = g;
-                                                       *pcache++ = r;
-                                                       *pcache++ = 0;
-                                                       break;
-                                               }
-                                               case 3: {
-                                                       *p3 = b;
-                                                       *(p3 + 1) = g;
-                                                       *(p3 + 2) = r;
-                                                       *pcache++ = 0;
-                                                       break;
-                                               }
-                                               default:
-                                                       SAM("MISTAKE: %i=rump\n",
-                                                               bytesperpixel - rump);
-                                                       return -EFAULT;
-                                               }
-                                       } else {
-                                               *p3 = b;
-                                               *(p3 + 1) = g;
-                                               *(p3 + 2) = r;
-                                               *(p3 + 3) = 0;
-                                       }
-                                       p2 += 2;
-                                       if (isuy)
-                                               isuy = false;
-                                       else
-                                               isuy = true;
-                                       p3 += bytesperpixel;
-                               }
-                       }
-                       return 0;
-               } else {
-                       if (!byteswaporder) {
-                               /*
-                                *  RGBA DECIMATED
-                                */
-                               while (pz > p2) {
-                                       if (pr <= (p3 + bytesperpixel))
-                                               last = true;
-                                       else
-                                               last = false;
-                                       y = *p2;
-                                       if (last && (0x0C & mask)) {
-                                               if (0x04 & mask) {
-                                                       if (isuy)
-                                                               v = margin;
-                                                       else
-                                                               u = margin;
-                                               } else
-                                                       if (0x08 & mask)
-                                                               ;
-                                       } else {
-                                               if (isuy)
-                                                       v = *(p2 + 1);
-                                               else
-                                                       u = *(p2 + 1);
-                                       }
-
-                                       if (isuy) {
-
-                                               tmp = ay[(int)y] + rv[(int)v];
-                                               r = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-                                               tmp = ay[(int)y] - gu[(int)u] -
-                                                                       gv[(int)v];
-                                               g = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-                                               tmp = ay[(int)y] + bu[(int)u];
-                                               b = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-
-                                               if (last && rump) {
-                                                       pcache = &peasycap->cache[0];
-                                                       switch (bytesperpixel - rump) {
-                                                       case 1: {
-                                                               *p3 = r;
-                                                               *pcache++ = g;
-                                                               *pcache++ = b;
-                                                               *pcache++ = 0;
-                                                               break;
-                                                       }
-                                                       case 2: {
-                                                               *p3 = r;
-                                                               *(p3 + 1) = g;
-                                                               *pcache++ = b;
-                                                               *pcache++ = 0;
-                                                               break;
-                                                       }
-                                                       case 3: {
-                                                               *p3 = r;
-                                                               *(p3 + 1) = g;
-                                                               *(p3 + 2) = b;
-                                                               *pcache++ = 0;
-                                                               break;
-                                                       }
-                                                       default: {
-                                                               SAM("MISTAKE: "
-                                                               "%i=rump\n",
-                                                               bytesperpixel -
-                                                               rump);
-                                                               return -EFAULT;
-                                                               }
-                                                       }
-                                               } else {
-                                                       *p3 = r;
-                                                       *(p3 + 1) = g;
-                                                       *(p3 + 2) = b;
-                                                       *(p3 + 3) = 0;
-                                                       }
-                                               isuy = false;
-                                               p3 += bytesperpixel;
-                                       } else
-                                               isuy = true;
-                                       p2 += 2;
-                               }
-                               return 0;
-                       } else {
-                               /*
-                                *  BGRA DECIMATED
-                                */
-                               while (pz > p2) {
-                                       if (pr <= (p3 + bytesperpixel))
-                                               last = true;
-                                       else
-                                               last = false;
-                                       y = *p2;
-                                       if (last && (0x0C & mask)) {
-                                               if (0x04 & mask) {
-                                                       if (isuy)
-                                                               v = margin;
-                                                       else
-                                                               u = margin;
-                                               } else
-                                                       if (0x08 & mask)
-                                                               ;
-                                       } else {
-                                               if (isuy)
-                                                       v = *(p2 + 1);
-                                               else
-                                                       u = *(p2 + 1);
-                                       }
-
-                                       if (isuy) {
-                                               tmp = ay[(int)y] + rv[(int)v];
-                                               r = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-                                               tmp = ay[(int)y] - gu[(int)u] -
-                                                                       gv[(int)v];
-                                               g = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-                                               tmp = ay[(int)y] + bu[(int)u];
-                                               b = (255 < tmp) ? 255 : ((0 > tmp) ?
-                                                                       0 : (u8)tmp);
-
-                                               if (last && rump) {
-                                                       pcache = &peasycap->cache[0];
-                                                       switch (bytesperpixel - rump) {
-                                                       case 1: {
-                                                               *p3 = b;
-                                                               *pcache++ = g;
-                                                               *pcache++ = r;
-                                                               *pcache++ = 0;
-                                                               break;
-                                                       }
-                                                       case 2: {
-                                                               *p3 = b;
-                                                               *(p3 + 1) = g;
-                                                               *pcache++ = r;
-                                                               *pcache++ = 0;
-                                                               break;
-                                                       }
-                                                       case 3: {
-                                                               *p3 = b;
-                                                               *(p3 + 1) = g;
-                                                               *(p3 + 2) = r;
-                                                               *pcache++ = 0;
-                                                               break;
-                                                       }
-                                                       default: {
-                                                               SAM("MISTAKE: "
-                                                               "%i=rump\n",
-                                                               bytesperpixel - rump);
-                                                               return -EFAULT;
-                                                       }
-                                                       }
-                                               } else {
-                                                       *p3 = b;
-                                                       *(p3 + 1) = g;
-                                                       *(p3 + 2) = r;
-                                                       *(p3 + 3) = 0;
-                                               }
-                                               isuy = false;
-                                               p3 += bytesperpixel;
-                                       } else
-                                               isuy = true;
-                                               p2 += 2;
-                                       }
-                                       return 0;
-                               }
-                       }
-               break;
-               }
-       default: {
-               SAM("MISTAKE: %i=bytesperpixel\n", bytesperpixel);
-               return -EFAULT;
-               }
-       }
-       return 0;
-}
-/*****************************************************************************/
-/*
- *  SEE CORBET ET AL. "LINUX DEVICE DRIVERS", 3rd EDITION, PAGES 430-434
- */
-/*****************************************************************************/
-static void easycap_vma_open(struct vm_area_struct *pvma)
-{
-       struct easycap *peasycap;
-
-       peasycap = pvma->vm_private_data;
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return;
-       }
-       peasycap->vma_many++;
-       JOT(8, "%i=peasycap->vma_many\n", peasycap->vma_many);
-       return;
-}
-/*****************************************************************************/
-static void easycap_vma_close(struct vm_area_struct *pvma)
-{
-       struct easycap *peasycap;
-
-       peasycap = pvma->vm_private_data;
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return;
-       }
-       peasycap->vma_many--;
-       JOT(8, "%i=peasycap->vma_many\n", peasycap->vma_many);
-       return;
-}
-/*****************************************************************************/
-static int easycap_vma_fault(struct vm_area_struct *pvma, struct vm_fault *pvmf)
-{
-       int k, m, retcode;
-       void *pbuf;
-       struct page *page;
-       struct easycap *peasycap;
-
-       retcode = VM_FAULT_NOPAGE;
-
-       if (!pvma) {
-               SAY("pvma is NULL\n");
-               return retcode;
-       }
-       if (!pvmf) {
-               SAY("pvmf is NULL\n");
-               return retcode;
-       }
-
-       k = (pvmf->pgoff) / (FRAME_BUFFER_SIZE/PAGE_SIZE);
-       m = (pvmf->pgoff) % (FRAME_BUFFER_SIZE/PAGE_SIZE);
-
-       if (!m)
-               JOT(4, "%4i=k, %4i=m\n", k, m);
-       else
-               JOT(16, "%4i=k, %4i=m\n", k, m);
-
-       if ((0 > k) || (FRAME_BUFFER_MANY <= k)) {
-               SAY("ERROR: buffer index %i out of range\n", k);
-               return retcode;
-       }
-       if ((0 > m) || (FRAME_BUFFER_SIZE/PAGE_SIZE <= m)) {
-               SAY("ERROR: page number  %i out of range\n", m);
-               return retcode;
-       }
-       peasycap = pvma->vm_private_data;
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return retcode;
-       }
-/*---------------------------------------------------------------------------*/
-       pbuf = peasycap->frame_buffer[k][m].pgo;
-       if (!pbuf) {
-               SAM("ERROR:  pbuf is NULL\n");
-               return retcode;
-       }
-       page = virt_to_page(pbuf);
-       if (!page) {
-               SAM("ERROR:  page is NULL\n");
-               return retcode;
-       }
-       get_page(page);
-/*---------------------------------------------------------------------------*/
-       if (!page) {
-               SAM("ERROR:  page is NULL after get_page(page)\n");
-       } else {
-               pvmf->page = page;
-               retcode = VM_FAULT_MINOR;
-       }
-       return retcode;
-}
-
-static const struct vm_operations_struct easycap_vm_ops = {
-       .open  = easycap_vma_open,
-       .close = easycap_vma_close,
-       .fault = easycap_vma_fault,
-};
-
-static int easycap_mmap(struct file *file, struct vm_area_struct *pvma)
-{
-       JOT(8, "\n");
-
-       pvma->vm_ops = &easycap_vm_ops;
-       pvma->vm_flags |= VM_RESERVED;
-       if (file)
-               pvma->vm_private_data = file->private_data;
-       easycap_vma_open(pvma);
-       return 0;
-}
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- *  ON COMPLETION OF A VIDEO URB ITS DATA IS COPIED TO THE FIELD BUFFERS
- *  PROVIDED peasycap->video_idle IS ZERO.  REGARDLESS OF THIS BEING TRUE,
- *  IT IS RESUBMITTED PROVIDED peasycap->video_isoc_streaming IS NOT ZERO.
- *
- *  THIS FUNCTION IS AN INTERRUPT SERVICE ROUTINE AND MUST NOT SLEEP.
- *
- *  INFORMATION ABOUT THE VALIDITY OF THE CONTENTS OF THE FIELD BUFFER ARE
- *  STORED IN THE TWO-BYTE STATUS PARAMETER
- *        peasycap->field_buffer[peasycap->field_fill][0].kount
- *  NOTICE THAT THE INFORMATION IS STORED ONLY WITH PAGE 0 OF THE FIELD BUFFER.
- *
- *  THE LOWER BYTE CONTAINS THE FIELD PARITY BYTE FURNISHED BY THE SAA7113H
- *  CHIP.
- *
- *  THE UPPER BYTE IS ZERO IF NO PROBLEMS, OTHERWISE:
- *      0 != (kount & 0x8000)   => AT LEAST ONE URB COMPLETED WITH ERRORS
- *      0 != (kount & 0x4000)   => BUFFER HAS TOO MUCH DATA
- *      0 != (kount & 0x2000)   => BUFFER HAS NOT ENOUGH DATA
- *      0 != (kount & 0x1000)   => BUFFER HAS DATA FROM DISPARATE INPUTS
- *      0 != (kount & 0x0400)   => RESERVED
- *      0 != (kount & 0x0200)   => FIELD BUFFER NOT YET CHECKED
- *      0 != (kount & 0x0100)   => BUFFER HAS TWO EXTRA BYTES - WHY?
- */
-/*---------------------------------------------------------------------------*/
-static void easycap_complete(struct urb *purb)
-{
-       struct easycap *peasycap;
-       struct data_buffer *pfield_buffer;
-       char errbuf[16];
-       int i, more, much, leap, rc, last;
-       int videofieldamount;
-       unsigned int override, bad;
-       int framestatus, framelength, frameactual, frameoffset;
-       u8 *pu;
-
-       if (!purb) {
-               SAY("ERROR: easycap_complete(): purb is NULL\n");
-               return;
-       }
-       peasycap = purb->context;
-       if (!peasycap) {
-               SAY("ERROR: easycap_complete(): peasycap is NULL\n");
-               return;
-       }
-       if (peasycap->video_eof)
-               return;
-       for (i = 0; i < VIDEO_ISOC_BUFFER_MANY; i++)
-               if (purb->transfer_buffer == peasycap->video_isoc_buffer[i].pgo)
-                       break;
-       JOM(16, "%2i=urb\n", i);
-       last = peasycap->video_isoc_sequence;
-       if ((((VIDEO_ISOC_BUFFER_MANY - 1) == last) && (0 != i)) ||
-            (((VIDEO_ISOC_BUFFER_MANY - 1) != last) && ((last + 1) != i))) {
-               JOM(16, "ERROR: out-of-order urbs %i,%i ... continuing\n",
-                                               last, i);
-       }
-       peasycap->video_isoc_sequence = i;
-
-       if (peasycap->video_idle) {
-               JOM(16, "%i=video_idle  %i=video_isoc_streaming\n",
-                               peasycap->video_idle, peasycap->video_isoc_streaming);
-               if (peasycap->video_isoc_streaming) {
-                       rc = usb_submit_urb(purb, GFP_ATOMIC);
-                       if (rc) {
-                               SAM("%s:%d ENOMEM\n", strerror(rc), rc);
-                               if (-ENODEV != rc)
-                                       SAM("ERROR: while %i=video_idle, "
-                                                               "usb_submit_urb() "
-                                                               "failed with rc:\n",
-                                                               peasycap->video_idle);
-                       }
-               }
-       return;
-       }
-       override = 0;
-/*---------------------------------------------------------------------------*/
-       if (FIELD_BUFFER_MANY <= peasycap->field_fill) {
-               SAM("ERROR: bad peasycap->field_fill\n");
-               return;
-       }
-       if (purb->status) {
-               if ((-ESHUTDOWN == purb->status) || (-ENOENT == purb->status)) {
-                       JOM(8, "urb status -ESHUTDOWN or -ENOENT\n");
-                       return;
-               }
-
-               (peasycap->field_buffer[peasycap->field_fill][0].kount) |= 0x8000 ;
-               SAM("ERROR: bad urb status -%s: %d\n",
-                               strerror(purb->status), purb->status);
-/*---------------------------------------------------------------------------*/
-       } else {
-               for (i = 0;  i < purb->number_of_packets; i++) {
-                       if (0 != purb->iso_frame_desc[i].status) {
-                               (peasycap->field_buffer
-                                       [peasycap->field_fill][0].kount) |= 0x8000 ;
-                               /* FIXME: 1. missing '-' check boundaries */
-                               strcpy(&errbuf[0],
-                                       strerror(purb->iso_frame_desc[i].status));
-                       }
-                       framestatus = purb->iso_frame_desc[i].status;
-                       framelength = purb->iso_frame_desc[i].length;
-                       frameactual = purb->iso_frame_desc[i].actual_length;
-                       frameoffset = purb->iso_frame_desc[i].offset;
-
-                       JOM(16, "frame[%2i]:"
-                                       "%4i=status "
-                                       "%4i=actual "
-                                       "%4i=length "
-                                       "%5i=offset\n",
-                               i, framestatus, frameactual, framelength, frameoffset);
-                       if (!purb->iso_frame_desc[i].status) {
-                               more = purb->iso_frame_desc[i].actual_length;
-                               pfield_buffer = &peasycap->field_buffer
-                                         [peasycap->field_fill][peasycap->field_page];
-                               videofieldamount = (peasycap->field_page *
-                                       PAGE_SIZE) +
-                                       (int)(pfield_buffer->pto - pfield_buffer->pgo);
-                       if (4 == more)
-                               peasycap->video_mt++;
-                       if (4 < more) {
-                               if (peasycap->video_mt) {
-                                       JOM(8, "%4i empty video urb frames\n",
-                                                               peasycap->video_mt);
-                                       peasycap->video_mt = 0;
-                               }
-                               if (FIELD_BUFFER_MANY <= peasycap->field_fill) {
-                                       SAM("ERROR: bad peasycap->field_fill\n");
-                                       return;
-                               }
-                               if (FIELD_BUFFER_SIZE/PAGE_SIZE <=
-                                                               peasycap->field_page) {
-                                       SAM("ERROR: bad peasycap->field_page\n");
-                                       return;
-                               }
-                               pfield_buffer = &peasycap->field_buffer
-                                       [peasycap->field_fill][peasycap->field_page];
-                               pu = (u8 *)(purb->transfer_buffer +
-                                               purb->iso_frame_desc[i].offset);
-                               if (0x80 & *pu)
-                                       leap = 8;
-                               else
-                                       leap = 4;
-/*--------------------------------------------------------------------------*/
-/*
- *  EIGHT-BYTE END-OF-VIDEOFIELD MARKER.
- *  NOTE:  A SUCCESSION OF URB FRAMES FOLLOWING THIS ARE EMPTY,
- *         CORRESPONDING TO THE FIELD FLYBACK (VERTICAL BLANKING) PERIOD.
- *
- *  PROVIDED THE FIELD BUFFER CONTAINS GOOD DATA AS INDICATED BY A ZERO UPPER
- *  BYTE OF
- *        peasycap->field_buffer[peasycap->field_fill][0].kount
- *  THE CONTENTS OF THE FIELD BUFFER ARE OFFERED TO dqbuf(), field_read IS
- *  UPDATED AND field_fill IS BUMPED.  IF THE FIELD BUFFER CONTAINS BAD DATA
- *  NOTHING IS OFFERED TO dqbuf().
- *
- *  THE DECISION ON WHETHER THE PARITY OF THE OFFERED FIELD BUFFER IS RIGHT
- *  RESTS WITH dqbuf().
- */
-/*---------------------------------------------------------------------------*/
-                               if ((8 == more) || override) {
-                                       if (videofieldamount >
-                                                       peasycap->videofieldamount) {
-                                               if (2 == videofieldamount -
-                                                               peasycap->
-                                                               videofieldamount) {
-                                                       (peasycap->field_buffer
-                                                       [peasycap->field_fill]
-                                                               [0].kount) |= 0x0100;
-                                                       peasycap->video_junk += (1 +
-                                                               VIDEO_JUNK_TOLERATE);
-                                               } else
-                                                       (peasycap->field_buffer
-                                                       [peasycap->field_fill]
-                                                               [0].kount) |= 0x4000;
-                                               } else if (videofieldamount <
-                                                               peasycap->
-                                                               videofieldamount) {
-                                                       (peasycap->field_buffer
-                                                       [peasycap->field_fill]
-                                                               [0].kount) |= 0x2000;
-                                               }
-                                               bad = 0xFF00 & peasycap->field_buffer
-                                                       [peasycap->field_fill]
-                                                       [0].kount;
-                                               if (!bad) {
-                                                       (peasycap->video_junk)--;
-                                                       if (-VIDEO_JUNK_TOLERATE >
-                                                               peasycap->video_junk)
-                                                               peasycap->video_junk =
-                                                               -VIDEO_JUNK_TOLERATE;
-                                                       peasycap->field_read =
-                                                               (peasycap->
-                                                                       field_fill)++;
-                                                       if (FIELD_BUFFER_MANY <=
-                                                                       peasycap->
-                                                                       field_fill)
-                                                               peasycap->
-                                                                       field_fill = 0;
-                                                       peasycap->field_page = 0;
-                                                       pfield_buffer = &peasycap->
-                                                               field_buffer
-                                                               [peasycap->
-                                                               field_fill]
-                                                               [peasycap->
-                                                               field_page];
-                                                       pfield_buffer->pto =
-                                                               pfield_buffer->pgo;
-                                                       JOM(8, "bumped to: %i="
-                                                               "peasycap->"
-                                                               "field_fill  %i="
-                                                               "parity\n",
-                                                               peasycap->field_fill,
-                                                               0x00FF &
-                                                               pfield_buffer->kount);
-                                                       JOM(8, "field buffer %i has "
-                                                               "%i bytes fit to be "
-                                                               "read\n",
-                                                               peasycap->field_read,
-                                                               videofieldamount);
-                                                       JOM(8, "wakeup call to "
-                                                               "wq_video, "
-                                                               "%i=field_read "
-                                                               "%i=field_fill "
-                                                               "%i=parity\n",
-                                                               peasycap->field_read,
-                                                               peasycap->field_fill,
-                                                               0x00FF & peasycap->
-                                                               field_buffer
-                                                               [peasycap->
-                                                               field_read][0].kount);
-                                                       wake_up_interruptible
-                                                               (&(peasycap->
-                                                                        wq_video));
-                                               } else {
-                                               peasycap->video_junk++;
-                                               if (bad & 0x0010)
-                                                       peasycap->video_junk +=
-                                                       (1 + VIDEO_JUNK_TOLERATE/2);
-                                               JOM(8, "field buffer %i had %i "
-                                                       "bytes, now discarded: "
-                                                       "0x%04X\n",
-                                                       peasycap->field_fill,
-                                                       videofieldamount,
-                                                       (0xFF00 &
-                                                       peasycap->field_buffer
-                                                       [peasycap->field_fill][0].
-                                                       kount));
-                                               (peasycap->field_fill)++;
-
-                                               if (FIELD_BUFFER_MANY <=
-                                                               peasycap->field_fill)
-                                                       peasycap->field_fill = 0;
-                                               peasycap->field_page = 0;
-                                               pfield_buffer =
-                                                       &peasycap->field_buffer
-                                                       [peasycap->field_fill]
-                                                       [peasycap->field_page];
-                                               pfield_buffer->pto =
-                                                               pfield_buffer->pgo;
-
-                                               JOM(8, "bumped to: %i=peasycap->"
-                                                       "field_fill  %i=parity\n",
-                                                       peasycap->field_fill,
-                                                       0x00FF & pfield_buffer->kount);
-                                       }
-                                       if (8 == more) {
-                                               JOM(8, "end-of-field: received "
-                                                       "parity byte 0x%02X\n",
-                                                       (0xFF & *pu));
-                                               if (0x40 & *pu)
-                                                       pfield_buffer->kount = 0x0000;
-                                               else
-                                                       pfield_buffer->kount = 0x0001;
-                                               pfield_buffer->input = 0x08 |
-                                                       (0x07 & peasycap->input);
-                                               JOM(8, "end-of-field: 0x%02X=kount\n",
-                                                       0xFF & pfield_buffer->kount);
-                                       }
-                               }
-/*---------------------------------------------------------------------------*/
-/*
- *  COPY more BYTES FROM ISOC BUFFER TO FIELD BUFFER
- */
-/*---------------------------------------------------------------------------*/
-                               pu += leap;
-                               more -= leap;
-
-                               if (FIELD_BUFFER_MANY <= peasycap->field_fill) {
-                                       SAM("ERROR: bad peasycap->field_fill\n");
-                                       return;
-                               }
-                               if (FIELD_BUFFER_SIZE/PAGE_SIZE <= peasycap->field_page) {
-                                       SAM("ERROR: bad peasycap->field_page\n");
-                                       return;
-                               }
-                               pfield_buffer = &peasycap->field_buffer
-                                       [peasycap->field_fill][peasycap->field_page];
-                               while (more) {
-                                       pfield_buffer = &peasycap->field_buffer
-                                                       [peasycap->field_fill]
-                                                       [peasycap->field_page];
-                                       if (PAGE_SIZE < (pfield_buffer->pto -
-                                                               pfield_buffer->pgo)) {
-                                               SAM("ERROR: bad pfield_buffer->pto\n");
-                                               return;
-                                       }
-                                       if (PAGE_SIZE == (pfield_buffer->pto -
-                                                               pfield_buffer->pgo)) {
-                                               (peasycap->field_page)++;
-                                               if (FIELD_BUFFER_SIZE/PAGE_SIZE <=
-                                                               peasycap->field_page) {
-                                                       JOM(16, "wrapping peasycap->"
-                                                               "field_page\n");
-                                                       peasycap->field_page = 0;
-                                               }
-                                               pfield_buffer = &peasycap->
-                                                               field_buffer
-                                                               [peasycap->field_fill]
-                                                               [peasycap->field_page];
-                                               pfield_buffer->pto = pfield_buffer->pgo;
-                                               pfield_buffer->input = 0x08 |
-                                                       (0x07 & peasycap->input);
-                                               if ((peasycap->field_buffer[peasycap->
-                                                               field_fill][0]).
-                                                                       input !=
-                                                               pfield_buffer->input)
-                                                       (peasycap->field_buffer
-                                                               [peasycap->field_fill]
-                                                               [0]).kount |= 0x1000;
-                                       }
-
-                                       much = PAGE_SIZE -
-                                               (int)(pfield_buffer->pto -
-                                                       pfield_buffer->pgo);
-
-                                       if (much > more)
-                                               much = more;
-                                       memcpy(pfield_buffer->pto, pu, much);
-                                       pu += much;
-                                       (pfield_buffer->pto) += much;
-                                       more -= much;
-                                       }
-                               }
-                       }
-               }
-       }
-/*---------------------------------------------------------------------------*/
-/*
- *  RESUBMIT THIS URB, UNLESS A SEVERE PERSISTENT ERROR CONDITION EXISTS.
- *
- *  IF THE WAIT QUEUES ARE NOT CLEARED IN RESPONSE TO AN ERROR CONDITION
- *  THE USERSPACE PROGRAM, E.G. mplayer, MAY HANG ON EXIT.   BEWARE.
- */
-/*---------------------------------------------------------------------------*/
-       if (VIDEO_ISOC_BUFFER_MANY <= peasycap->video_junk) {
-               SAM("easycap driver shutting down on condition green\n");
-               peasycap->status = 1;
-               peasycap->video_eof = 1;
-               peasycap->video_junk = 0;
-               wake_up_interruptible(&peasycap->wq_video);
-#if !defined(PERSEVERE)
-               peasycap->audio_eof = 1;
-               wake_up_interruptible(&peasycap->wq_audio);
-#endif /*PERSEVERE*/
-               return;
-       }
-       if (peasycap->video_isoc_streaming) {
-               rc = usb_submit_urb(purb, GFP_ATOMIC);
-               if (rc) {
-                       SAM("%s: %d\n", strerror(rc), rc);
-                       if (-ENODEV != rc)
-                               SAM("ERROR: while %i=video_idle, "
-                                       "usb_submit_urb() "
-                                       "failed with rc:\n",
-                                       peasycap->video_idle);
-               }
-       }
-       return;
-}
-
-static struct easycap *alloc_easycap(u8 bInterfaceNumber)
-{
-       struct easycap *peasycap;
-       int i;
-
-       peasycap = kzalloc(sizeof(struct easycap), GFP_KERNEL);
-       if (!peasycap) {
-               SAY("ERROR: Could not allocate peasycap\n");
-               return NULL;
-       }
-
-       if (mutex_lock_interruptible(&mutex_dongle)) {
-               SAY("ERROR: cannot lock mutex_dongle\n");
-               kfree(peasycap);
-               return NULL;
-       }
-
-       /* Find a free dongle in easycapdc60_dongle array */
-       for (i = 0; i < DONGLE_MANY; i++) {
-
-               if ((!easycapdc60_dongle[i].peasycap) &&
-                   (!mutex_is_locked(&easycapdc60_dongle[i].mutex_video)) &&
-                   (!mutex_is_locked(&easycapdc60_dongle[i].mutex_audio))) {
-
-                       easycapdc60_dongle[i].peasycap = peasycap;
-                       peasycap->isdongle = i;
-                       JOM(8, "intf[%i]: peasycap-->easycap"
-                               "_dongle[%i].peasycap\n",
-                               bInterfaceNumber, i);
-                       break;
-               }
-       }
-
-       mutex_unlock(&mutex_dongle);
-
-       if (i >= DONGLE_MANY) {
-               SAM("ERROR: too many dongles\n");
-               kfree(peasycap);
-               return NULL;
-       }
-
-       return peasycap;
-}
-
-static void free_easycap(struct easycap *peasycap)
-{
-       int allocation_video_urb;
-       int allocation_video_page;
-       int allocation_video_struct;
-       int allocation_audio_urb;
-       int allocation_audio_page;
-       int allocation_audio_struct;
-       int registered_video, registered_audio;
-       int kd;
-
-       JOM(4, "freeing easycap structure.\n");
-       allocation_video_urb    = peasycap->allocation_video_urb;
-       allocation_video_page   = peasycap->allocation_video_page;
-       allocation_video_struct = peasycap->allocation_video_struct;
-       registered_video        = peasycap->registered_video;
-       allocation_audio_urb    = peasycap->allocation_audio_urb;
-       allocation_audio_page   = peasycap->allocation_audio_page;
-       allocation_audio_struct = peasycap->allocation_audio_struct;
-       registered_audio        = peasycap->registered_audio;
-
-       kd = easycap_isdongle(peasycap);
-       if (0 <= kd && DONGLE_MANY > kd) {
-               if (mutex_lock_interruptible(&mutex_dongle)) {
-                       SAY("ERROR: cannot down mutex_dongle\n");
-               } else {
-                       JOM(4, "locked mutex_dongle\n");
-                       easycapdc60_dongle[kd].peasycap = NULL;
-                       mutex_unlock(&mutex_dongle);
-                       JOM(4, "unlocked mutex_dongle\n");
-                       JOT(4, "   null-->dongle[%i].peasycap\n", kd);
-                       allocation_video_struct -= sizeof(struct easycap);
-               }
-       } else {
-               SAY("ERROR: cannot purge dongle[].peasycap");
-       }
-
-       /* Free device structure */
-       kfree(peasycap);
-
-       SAY("%8i=video urbs    after all deletions\n", allocation_video_urb);
-       SAY("%8i=video pages   after all deletions\n", allocation_video_page);
-       SAY("%8i=video structs after all deletions\n", allocation_video_struct);
-       SAY("%8i=video devices after all deletions\n", registered_video);
-       SAY("%8i=audio urbs    after all deletions\n", allocation_audio_urb);
-       SAY("%8i=audio pages   after all deletions\n", allocation_audio_page);
-       SAY("%8i=audio structs after all deletions\n", allocation_audio_struct);
-       SAY("%8i=audio devices after all deletions\n", registered_audio);
-}
-
-/*
- * FIXME: Identify the appropriate pointer peasycap for interfaces
- * 1 and 2. The address of peasycap->pusb_device is reluctantly used
- * for this purpose.
- */
-static struct easycap *get_easycap(struct usb_device *usbdev,
-                                  u8 bInterfaceNumber)
-{
-       int i;
-       struct easycap *peasycap;
-
-       for (i = 0; i < DONGLE_MANY; i++) {
-               if (easycapdc60_dongle[i].peasycap->pusb_device == usbdev) {
-                       peasycap = easycapdc60_dongle[i].peasycap;
-                       JOT(8, "intf[%i]: dongle[%i].peasycap\n",
-                                       bInterfaceNumber, i);
-                       break;
-               }
-       }
-       if (i >= DONGLE_MANY) {
-               SAY("ERROR: peasycap is unknown when probing interface %i\n",
-                       bInterfaceNumber);
-               return NULL;
-       }
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL when probing interface %i\n",
-                       bInterfaceNumber);
-               return NULL;
-       }
-
-       return peasycap;
-}
-
-static void init_easycap(struct easycap *peasycap,
-                        struct usb_device *usbdev,
-                        struct usb_interface *intf,
-                        u8 bInterfaceNumber)
-{
-       /* Save usb_device and usb_interface */
-       peasycap->pusb_device = usbdev;
-       peasycap->pusb_interface = intf;
-
-       peasycap->minor = -1;
-       kref_init(&peasycap->kref);
-       JOM(8, "intf[%i]: after kref_init(..._video) "
-               "%i=peasycap->kref.refcount.counter\n",
-               bInterfaceNumber, peasycap->kref.refcount.counter);
-
-       /* module params */
-       peasycap->gain = (s8)clamp(easycap_gain, 0, 31);
-
-       init_waitqueue_head(&peasycap->wq_video);
-       init_waitqueue_head(&peasycap->wq_audio);
-       init_waitqueue_head(&peasycap->wq_trigger);
-
-       peasycap->allocation_video_struct = sizeof(struct easycap);
-
-       peasycap->microphone = false;
-
-       peasycap->video_interface = -1;
-       peasycap->video_altsetting_on = -1;
-       peasycap->video_altsetting_off = -1;
-       peasycap->video_endpointnumber = -1;
-       peasycap->video_isoc_maxframesize = -1;
-       peasycap->video_isoc_buffer_size = -1;
-
-       peasycap->audio_interface = -1;
-       peasycap->audio_altsetting_on = -1;
-       peasycap->audio_altsetting_off = -1;
-       peasycap->audio_endpointnumber = -1;
-       peasycap->audio_isoc_maxframesize = -1;
-       peasycap->audio_isoc_buffer_size = -1;
-
-       peasycap->frame_buffer_many = FRAME_BUFFER_MANY;
-
-       peasycap->ntsc = easycap_ntsc;
-       JOM(8, "defaulting initially to %s\n",
-               easycap_ntsc ? "NTSC" : "PAL");
-}
-
-static int populate_inputset(struct easycap *peasycap)
-{
-       struct inputset *inputset;
-       struct easycap_format *peasycap_format;
-       struct v4l2_pix_format *pix;
-       int m, i, k, mask, fmtidx;
-       s32 value;
-
-       inputset = peasycap->inputset;
-
-       fmtidx = peasycap->ntsc ? NTSC_M : PAL_BGHIN;
-
-       m = 0;
-       mask = 0;
-       for (i = 0; easycap_standard[i].mask != 0xffff; i++) {
-               if (fmtidx == easycap_standard[i].v4l2_standard.index) {
-                       m++;
-                       for (k = 0; k < INPUT_MANY; k++)
-                               inputset[k].standard_offset = i;
-                       mask = easycap_standard[i].mask;
-               }
-       }
-
-       if (m != 1) {
-               SAM("ERROR: inputset->standard_offset unpopulated, %i=m\n", m);
-               return -ENOENT;
-       }
-
-       peasycap_format = &easycap_format[0];
-       m = 0;
-       for (i = 0; peasycap_format->v4l2_format.fmt.pix.width; i++) {
-               pix = &peasycap_format->v4l2_format.fmt.pix;
-               if (((peasycap_format->mask & 0x0F) == (mask & 0x0F))
-                       && pix->field == V4L2_FIELD_NONE
-                       && pix->pixelformat == V4L2_PIX_FMT_UYVY
-                       && pix->width  == 640 && pix->height == 480) {
-                       m++;
-                       for (k = 0; k < INPUT_MANY; k++)
-                               inputset[k].format_offset = i;
-                       break;
-               }
-               peasycap_format++;
-       }
-       if (m != 1) {
-               SAM("ERROR: inputset[]->format_offset unpopulated\n");
-               return -ENOENT;
-       }
-
-       m = 0;
-       for (i = 0; easycap_control[i].id != 0xffffffff; i++) {
-               value = easycap_control[i].default_value;
-               if (V4L2_CID_BRIGHTNESS == easycap_control[i].id) {
-                       m++;
-                       for (k = 0; k < INPUT_MANY; k++)
-                               inputset[k].brightness = value;
-               } else if (V4L2_CID_CONTRAST == easycap_control[i].id) {
-                       m++;
-                       for (k = 0; k < INPUT_MANY; k++)
-                               inputset[k].contrast = value;
-               } else if (V4L2_CID_SATURATION == easycap_control[i].id) {
-                       m++;
-                       for (k = 0; k < INPUT_MANY; k++)
-                               inputset[k].saturation = value;
-               } else if (V4L2_CID_HUE == easycap_control[i].id) {
-                       m++;
-                       for (k = 0; k < INPUT_MANY; k++)
-                               inputset[k].hue = value;
-               }
-       }
-
-       if (m != 4) {
-               SAM("ERROR: inputset[]->brightness underpopulated\n");
-               return -ENOENT;
-       }
-
-       for (k = 0; k < INPUT_MANY; k++)
-               inputset[k].input = k;
-       JOM(4, "populated inputset[]\n");
-
-       return 0;
-}
-
-static int alloc_framebuffers(struct easycap *peasycap)
-{
-       int i, j;
-       void *pbuf;
-
-       JOM(4, "allocating %i frame buffers of size %li\n",
-                       FRAME_BUFFER_MANY, (long int)FRAME_BUFFER_SIZE);
-       JOM(4, ".... each scattered over %li pages\n",
-                       FRAME_BUFFER_SIZE/PAGE_SIZE);
-
-       for (i = 0; i < FRAME_BUFFER_MANY; i++) {
-               for (j = 0; j < FRAME_BUFFER_SIZE/PAGE_SIZE; j++) {
-                       if (peasycap->frame_buffer[i][j].pgo)
-                               SAM("attempting to reallocate framebuffers\n");
-                       else {
-                               pbuf = (void *)__get_free_page(GFP_KERNEL);
-                               if (!pbuf) {
-                                       SAM("ERROR: Could not allocate "
-                                       "framebuffer %i page %i\n", i, j);
-                                       return -ENOMEM;
-                               }
-                               peasycap->allocation_video_page += 1;
-                               peasycap->frame_buffer[i][j].pgo = pbuf;
-                       }
-                       peasycap->frame_buffer[i][j].pto =
-                           peasycap->frame_buffer[i][j].pgo;
-               }
-       }
-
-       peasycap->frame_fill = 0;
-       peasycap->frame_read = 0;
-       JOM(4, "allocation of frame buffers done: %i pages\n", i*j);
-
-       return 0;
-}
-
-static void free_framebuffers(struct easycap *peasycap)
-{
-       int k, m, gone;
-
-       JOM(4, "freeing video frame buffers.\n");
-       gone = 0;
-       for (k = 0;  k < FRAME_BUFFER_MANY;  k++) {
-               for (m = 0;  m < FRAME_BUFFER_SIZE/PAGE_SIZE;  m++) {
-                       if (peasycap->frame_buffer[k][m].pgo) {
-                               free_page((unsigned long)
-                                       peasycap->frame_buffer[k][m].pgo);
-                               peasycap->frame_buffer[k][m].pgo = NULL;
-                               peasycap->allocation_video_page -= 1;
-                               gone++;
-                       }
-               }
-       }
-       JOM(4, "video frame buffers freed: %i pages\n", gone);
-}
-
-static int alloc_fieldbuffers(struct easycap *peasycap)
-{
-       int i, j;
-       void *pbuf;
-
-       JOM(4, "allocating %i field buffers of size %li\n",
-                       FIELD_BUFFER_MANY, (long int)FIELD_BUFFER_SIZE);
-       JOM(4, ".... each scattered over %li pages\n",
-                       FIELD_BUFFER_SIZE/PAGE_SIZE);
-
-       for (i = 0; i < FIELD_BUFFER_MANY; i++) {
-               for (j = 0; j < FIELD_BUFFER_SIZE/PAGE_SIZE; j++) {
-                       if (peasycap->field_buffer[i][j].pgo) {
-                               SAM("ERROR: attempting to reallocate "
-                                       "fieldbuffers\n");
-                       } else {
-                               pbuf = (void *) __get_free_page(GFP_KERNEL);
-                               if (!pbuf) {
-                                       SAM("ERROR: Could not allocate "
-                                       "fieldbuffer %i page %i\n", i, j);
-                                       return -ENOMEM;
-                               }
-                               peasycap->allocation_video_page += 1;
-                               peasycap->field_buffer[i][j].pgo = pbuf;
-                       }
-                       peasycap->field_buffer[i][j].pto =
-                               peasycap->field_buffer[i][j].pgo;
-               }
-               /* TODO: Hardcoded 0x0200 meaning? */
-               peasycap->field_buffer[i][0].kount = 0x0200;
-       }
-       peasycap->field_fill = 0;
-       peasycap->field_page = 0;
-       peasycap->field_read = 0;
-       JOM(4, "allocation of field buffers done:  %i pages\n", i*j);
-
-       return 0;
-}
-
-static void free_fieldbuffers(struct easycap *peasycap)
-{
-       int k, m, gone;
-
-       JOM(4, "freeing video field buffers.\n");
-       gone = 0;
-       for (k = 0;  k < FIELD_BUFFER_MANY;  k++) {
-               for (m = 0;  m < FIELD_BUFFER_SIZE/PAGE_SIZE;  m++) {
-                       if (peasycap->field_buffer[k][m].pgo) {
-                               free_page((unsigned long)
-                                         peasycap->field_buffer[k][m].pgo);
-                               peasycap->field_buffer[k][m].pgo = NULL;
-                               peasycap->allocation_video_page -= 1;
-                               gone++;
-                       }
-               }
-       }
-       JOM(4, "video field buffers freed: %i pages\n", gone);
-}
-
-static int alloc_isocbuffers(struct easycap *peasycap)
-{
-       int i;
-       void *pbuf;
-
-       JOM(4, "allocating %i isoc video buffers of size %i\n",
-                       VIDEO_ISOC_BUFFER_MANY,
-                       peasycap->video_isoc_buffer_size);
-       JOM(4, ".... each occupying contiguous memory pages\n");
-
-       for (i = 0; i < VIDEO_ISOC_BUFFER_MANY; i++) {
-               pbuf = (void *)__get_free_pages(GFP_KERNEL,
-                               VIDEO_ISOC_ORDER);
-               if (!pbuf) {
-                       SAM("ERROR: Could not allocate isoc "
-                               "video buffer %i\n", i);
-                       return -ENOMEM;
-               }
-               peasycap->allocation_video_page += BIT(VIDEO_ISOC_ORDER);
-
-               peasycap->video_isoc_buffer[i].pgo = pbuf;
-               peasycap->video_isoc_buffer[i].pto =
-                       pbuf + peasycap->video_isoc_buffer_size;
-               peasycap->video_isoc_buffer[i].kount = i;
-       }
-       JOM(4, "allocation of isoc video buffers done: %i pages\n",
-                       i * (0x01 << VIDEO_ISOC_ORDER));
-       return 0;
-}
-
-static void free_isocbuffers(struct easycap *peasycap)
-{
-       int k, m;
-
-       JOM(4, "freeing video isoc buffers.\n");
-       m = 0;
-       for (k = 0;  k < VIDEO_ISOC_BUFFER_MANY;  k++) {
-               if (peasycap->video_isoc_buffer[k].pgo) {
-                       free_pages((unsigned long)
-                                  peasycap->video_isoc_buffer[k].pgo,
-                                       VIDEO_ISOC_ORDER);
-                       peasycap->video_isoc_buffer[k].pgo = NULL;
-                       peasycap->allocation_video_page -=
-                                               BIT(VIDEO_ISOC_ORDER);
-                       m++;
-               }
-       }
-       JOM(4, "isoc video buffers freed: %i pages\n",
-                       m * (0x01 << VIDEO_ISOC_ORDER));
-}
-
-static int create_video_urbs(struct easycap *peasycap)
-{
-       struct urb *purb;
-       struct data_urb *pdata_urb;
-       int i, j;
-
-       JOM(4, "allocating %i struct urb.\n", VIDEO_ISOC_BUFFER_MANY);
-       JOM(4, "using %i=peasycap->video_isoc_framesperdesc\n",
-                       peasycap->video_isoc_framesperdesc);
-       JOM(4, "using %i=peasycap->video_isoc_maxframesize\n",
-                       peasycap->video_isoc_maxframesize);
-       JOM(4, "using %i=peasycap->video_isoc_buffer_sizen",
-                       peasycap->video_isoc_buffer_size);
-
-       for (i = 0; i < VIDEO_ISOC_BUFFER_MANY; i++) {
-               purb = usb_alloc_urb(peasycap->video_isoc_framesperdesc,
-                               GFP_KERNEL);
-               if (!purb) {
-                       SAM("ERROR: usb_alloc_urb returned NULL for buffer "
-                               "%i\n", i);
-                       return -ENOMEM;
-               }
-
-               peasycap->allocation_video_urb += 1;
-               pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);
-               if (!pdata_urb) {
-                       usb_free_urb(purb);
-                       SAM("ERROR: Could not allocate struct data_urb.\n");
-                       return -ENOMEM;
-               }
-
-               peasycap->allocation_video_struct +=
-                       sizeof(struct data_urb);
-
-               pdata_urb->purb = purb;
-               pdata_urb->isbuf = i;
-               pdata_urb->length = 0;
-               list_add_tail(&(pdata_urb->list_head),
-                               peasycap->purb_video_head);
-
-               if (!i) {
-                       JOM(4, "initializing video urbs thus:\n");
-                       JOM(4, "  purb->interval = 1;\n");
-                       JOM(4, "  purb->dev = peasycap->pusb_device;\n");
-                       JOM(4, "  purb->pipe = usb_rcvisocpipe"
-                                       "(peasycap->pusb_device,%i);\n",
-                                       peasycap->video_endpointnumber);
-                       JOM(4, "  purb->transfer_flags = URB_ISO_ASAP;\n");
-                       JOM(4, "  purb->transfer_buffer = peasycap->"
-                                       "video_isoc_buffer[.].pgo;\n");
-                       JOM(4, "  purb->transfer_buffer_length = %i;\n",
-                                       peasycap->video_isoc_buffer_size);
-                       JOM(4, "  purb->complete = easycap_complete;\n");
-                       JOM(4, "  purb->context = peasycap;\n");
-                       JOM(4, "  purb->start_frame = 0;\n");
-                       JOM(4, "  purb->number_of_packets = %i;\n",
-                                       peasycap->video_isoc_framesperdesc);
-                       JOM(4, "  for (j = 0; j < %i; j++)\n",
-                                       peasycap->video_isoc_framesperdesc);
-                       JOM(4, "    {\n");
-                       JOM(4, "    purb->iso_frame_desc[j].offset = j*%i;\n",
-                                       peasycap->video_isoc_maxframesize);
-                       JOM(4, "    purb->iso_frame_desc[j].length = %i;\n",
-                                       peasycap->video_isoc_maxframesize);
-                       JOM(4, "    }\n");
-               }
-
-               purb->interval = 1;
-               purb->dev = peasycap->pusb_device;
-               purb->pipe = usb_rcvisocpipe(peasycap->pusb_device,
-                               peasycap->video_endpointnumber);
-
-               purb->transfer_flags = URB_ISO_ASAP;
-               purb->transfer_buffer = peasycap->video_isoc_buffer[i].pgo;
-               purb->transfer_buffer_length =
-                       peasycap->video_isoc_buffer_size;
-
-               purb->complete = easycap_complete;
-               purb->context = peasycap;
-               purb->start_frame = 0;
-               purb->number_of_packets = peasycap->video_isoc_framesperdesc;
-
-               for (j = 0; j < peasycap->video_isoc_framesperdesc; j++) {
-                       purb->iso_frame_desc[j].offset =
-                               j * peasycap->video_isoc_maxframesize;
-                       purb->iso_frame_desc[j].length =
-                               peasycap->video_isoc_maxframesize;
-               }
-       }
-       JOM(4, "allocation of %i struct urb done.\n", i);
-       return 0;
-}
-
-static void free_video_urbs(struct easycap *peasycap)
-{
-       struct list_head *plist_head, *plist_next;
-       struct data_urb *pdata_urb;
-       int m;
-
-       if (peasycap->purb_video_head) {
-               m = 0;
-               list_for_each(plist_head, peasycap->purb_video_head) {
-                       pdata_urb = list_entry(plist_head,
-                                       struct data_urb, list_head);
-                       if (pdata_urb && pdata_urb->purb) {
-                               usb_free_urb(pdata_urb->purb);
-                               pdata_urb->purb = NULL;
-                               peasycap->allocation_video_urb--;
-                               m++;
-                       }
-               }
-
-               JOM(4, "%i video urbs freed\n", m);
-               JOM(4, "freeing video data_urb structures.\n");
-               m = 0;
-               list_for_each_safe(plist_head, plist_next,
-                                       peasycap->purb_video_head) {
-                       pdata_urb = list_entry(plist_head,
-                                       struct data_urb, list_head);
-                       if (pdata_urb) {
-                               peasycap->allocation_video_struct -=
-                                       sizeof(struct data_urb);
-                               kfree(pdata_urb);
-                               m++;
-                       }
-               }
-               JOM(4, "%i video data_urb structures freed\n", m);
-               JOM(4, "setting peasycap->purb_video_head=NULL\n");
-               peasycap->purb_video_head = NULL;
-       }
-}
-
-static int alloc_audio_buffers(struct easycap *peasycap)
-{
-       void *pbuf;
-       int k;
-
-       JOM(4, "allocating %i isoc audio buffers of size %i\n",
-               AUDIO_ISOC_BUFFER_MANY,
-               peasycap->audio_isoc_buffer_size);
-       JOM(4, ".... each occupying contiguous memory pages\n");
-
-       for (k = 0;  k < AUDIO_ISOC_BUFFER_MANY;  k++) {
-               pbuf = (void *)__get_free_pages(GFP_KERNEL, AUDIO_ISOC_ORDER);
-               if (!pbuf) {
-                       SAM("ERROR: Could not allocate isoc audio buffer %i\n",
-                           k);
-                               return -ENOMEM;
-               }
-               peasycap->allocation_audio_page += BIT(AUDIO_ISOC_ORDER);
-
-               peasycap->audio_isoc_buffer[k].pgo = pbuf;
-               peasycap->audio_isoc_buffer[k].pto =
-                       pbuf + peasycap->audio_isoc_buffer_size;
-               peasycap->audio_isoc_buffer[k].kount = k;
-       }
-
-       JOM(4, "allocation of isoc audio buffers done.\n");
-       return 0;
-}
-
-static void free_audio_buffers(struct easycap *peasycap)
-{
-       int k, m;
-
-       JOM(4, "freeing audio isoc buffers.\n");
-       m = 0;
-       for (k = 0;  k < AUDIO_ISOC_BUFFER_MANY;  k++) {
-               if (peasycap->audio_isoc_buffer[k].pgo) {
-                       free_pages((unsigned long)
-                                       (peasycap->audio_isoc_buffer[k].pgo),
-                                       AUDIO_ISOC_ORDER);
-                       peasycap->audio_isoc_buffer[k].pgo = NULL;
-                       peasycap->allocation_audio_page -=
-                                       BIT(AUDIO_ISOC_ORDER);
-                       m++;
-               }
-       }
-       JOM(4, "easyoss_delete(): isoc audio buffers freed: %i pages\n",
-                                       m * (0x01 << AUDIO_ISOC_ORDER));
-}
-
-static int create_audio_urbs(struct easycap *peasycap)
-{
-       struct urb *purb;
-       struct data_urb *pdata_urb;
-       int k, j;
-
-       JOM(4, "allocating %i struct urb.\n", AUDIO_ISOC_BUFFER_MANY);
-       JOM(4, "using %i=peasycap->audio_isoc_framesperdesc\n",
-               peasycap->audio_isoc_framesperdesc);
-       JOM(4, "using %i=peasycap->audio_isoc_maxframesize\n",
-               peasycap->audio_isoc_maxframesize);
-       JOM(4, "using %i=peasycap->audio_isoc_buffer_size\n",
-               peasycap->audio_isoc_buffer_size);
-
-       for (k = 0;  k < AUDIO_ISOC_BUFFER_MANY; k++) {
-               purb = usb_alloc_urb(peasycap->audio_isoc_framesperdesc,
-                                    GFP_KERNEL);
-               if (!purb) {
-                       SAM("ERROR: usb_alloc_urb returned NULL for buffer "
-                            "%i\n", k);
-                       return -ENOMEM;
-               }
-               peasycap->allocation_audio_urb += 1 ;
-               pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);
-               if (!pdata_urb) {
-                       usb_free_urb(purb);
-                       SAM("ERROR: Could not allocate struct data_urb.\n");
-                       return -ENOMEM;
-               }
-               peasycap->allocation_audio_struct +=
-                       sizeof(struct data_urb);
-
-               pdata_urb->purb = purb;
-               pdata_urb->isbuf = k;
-               pdata_urb->length = 0;
-               list_add_tail(&(pdata_urb->list_head),
-                               peasycap->purb_audio_head);
-
-               if (!k) {
-                       JOM(4, "initializing audio urbs thus:\n");
-                       JOM(4, "  purb->interval = 1;\n");
-                       JOM(4, "  purb->dev = peasycap->pusb_device;\n");
-                       JOM(4, "  purb->pipe = usb_rcvisocpipe(peasycap->"
-                               "pusb_device,%i);\n",
-                               peasycap->audio_endpointnumber);
-                       JOM(4, "  purb->transfer_flags = URB_ISO_ASAP;\n");
-                       JOM(4, "  purb->transfer_buffer = "
-                               "peasycap->audio_isoc_buffer[.].pgo;\n");
-                       JOM(4, "  purb->transfer_buffer_length = %i;\n",
-                               peasycap->audio_isoc_buffer_size);
-                       JOM(4, "  purb->complete = easycap_alsa_complete;\n");
-                       JOM(4, "  purb->context = peasycap;\n");
-                       JOM(4, "  purb->start_frame = 0;\n");
-                       JOM(4, "  purb->number_of_packets = %i;\n",
-                               peasycap->audio_isoc_framesperdesc);
-                       JOM(4, "  for (j = 0; j < %i; j++)\n",
-                               peasycap->audio_isoc_framesperdesc);
-                       JOM(4, "    {\n");
-                       JOM(4, "    purb->iso_frame_desc[j].offset = j*%i;\n",
-                               peasycap->audio_isoc_maxframesize);
-                       JOM(4, "    purb->iso_frame_desc[j].length = %i;\n",
-                               peasycap->audio_isoc_maxframesize);
-                       JOM(4, "    }\n");
-               }
-
-               purb->interval = 1;
-               purb->dev = peasycap->pusb_device;
-               purb->pipe = usb_rcvisocpipe(peasycap->pusb_device,
-                                            peasycap->audio_endpointnumber);
-               purb->transfer_flags = URB_ISO_ASAP;
-               purb->transfer_buffer = peasycap->audio_isoc_buffer[k].pgo;
-               purb->transfer_buffer_length =
-                       peasycap->audio_isoc_buffer_size;
-               purb->complete = easycap_alsa_complete;
-               purb->context = peasycap;
-               purb->start_frame = 0;
-               purb->number_of_packets = peasycap->audio_isoc_framesperdesc;
-               for (j = 0;  j < peasycap->audio_isoc_framesperdesc; j++) {
-                       purb->iso_frame_desc[j].offset =
-                               j * peasycap->audio_isoc_maxframesize;
-                       purb->iso_frame_desc[j].length =
-                               peasycap->audio_isoc_maxframesize;
-               }
-       }
-       JOM(4, "allocation of %i struct urb done.\n", k);
-       return 0;
-}
-
-static void free_audio_urbs(struct easycap *peasycap)
-{
-       struct list_head *plist_head, *plist_next;
-       struct data_urb *pdata_urb;
-       int m;
-
-       if (peasycap->purb_audio_head) {
-               JOM(4, "freeing audio urbs\n");
-               m = 0;
-               list_for_each(plist_head, (peasycap->purb_audio_head)) {
-                       pdata_urb = list_entry(plist_head,
-                                       struct data_urb, list_head);
-                       if (pdata_urb && pdata_urb->purb) {
-                               usb_free_urb(pdata_urb->purb);
-                               pdata_urb->purb = NULL;
-                               peasycap->allocation_audio_urb--;
-                               m++;
-                       }
-               }
-               JOM(4, "%i audio urbs freed\n", m);
-               JOM(4, "freeing audio data_urb structures.\n");
-               m = 0;
-               list_for_each_safe(plist_head, plist_next,
-                                       peasycap->purb_audio_head) {
-                       pdata_urb = list_entry(plist_head,
-                                       struct data_urb, list_head);
-                       if (pdata_urb) {
-                               peasycap->allocation_audio_struct -=
-                                                       sizeof(struct data_urb);
-                               kfree(pdata_urb);
-                               m++;
-                       }
-               }
-               JOM(4, "%i audio data_urb structures freed\n", m);
-               JOM(4, "setting peasycap->purb_audio_head=NULL\n");
-               peasycap->purb_audio_head = NULL;
-       }
-}
-
-static void config_easycap(struct easycap *peasycap,
-                          u8 bInterfaceNumber,
-                          u8 bInterfaceClass,
-                          u8 bInterfaceSubClass)
-{
-       if ((USB_CLASS_VIDEO == bInterfaceClass) ||
-           (USB_CLASS_VENDOR_SPEC == bInterfaceClass)) {
-               if (-1 == peasycap->video_interface) {
-                       peasycap->video_interface = bInterfaceNumber;
-                       JOM(4, "setting peasycap->video_interface=%i\n",
-                               peasycap->video_interface);
-               } else {
-                       if (peasycap->video_interface != bInterfaceNumber) {
-                               SAM("ERROR: attempting to reset "
-                                   "peasycap->video_interface\n");
-                               SAM("...... continuing with "
-                                   "%i=peasycap->video_interface\n",
-                                   peasycap->video_interface);
-                       }
-               }
-       } else if ((USB_CLASS_AUDIO == bInterfaceClass) &&
-                  (USB_SUBCLASS_AUDIOSTREAMING == bInterfaceSubClass)) {
-               if (-1 == peasycap->audio_interface) {
-                       peasycap->audio_interface = bInterfaceNumber;
-                       JOM(4, "setting peasycap->audio_interface=%i\n",
-                               peasycap->audio_interface);
-               } else {
-                       if (peasycap->audio_interface != bInterfaceNumber) {
-                               SAM("ERROR: attempting to reset "
-                                   "peasycap->audio_interface\n");
-                               SAM("...... continuing with "
-                                   "%i=peasycap->audio_interface\n",
-                                   peasycap->audio_interface);
-                       }
-               }
-       }
-}
-
-/*
- * This function is called from within easycap_usb_disconnect() and is
- * protected by semaphores set and cleared by easycap_usb_disconnect().
- * By this stage the device has already been physically unplugged,
- * so peasycap->pusb_device is no longer valid.
- */
-static void easycap_delete(struct kref *pkref)
-{
-       struct easycap *peasycap;
-
-       peasycap = container_of(pkref, struct easycap, kref);
-       if (!peasycap) {
-               SAM("ERROR: peasycap is NULL: cannot perform deletions\n");
-               return;
-       }
-
-       /* Free video urbs */
-       free_video_urbs(peasycap);
-
-       /* Free video isoc buffers */
-       free_isocbuffers(peasycap);
-
-       /* Free video field buffers */
-       free_fieldbuffers(peasycap);
-
-       /* Free video frame buffers */
-       free_framebuffers(peasycap);
-
-       /* Free audio urbs */
-       free_audio_urbs(peasycap);
-
-       /* Free audio isoc buffers */
-       free_audio_buffers(peasycap);
-
-       free_easycap(peasycap);
-
-       JOT(4, "ending.\n");
-}
-
-static const struct v4l2_file_operations v4l2_fops = {
-       .owner          = THIS_MODULE,
-       .open           = easycap_open_noinode,
-       .unlocked_ioctl = easycap_unlocked_ioctl,
-       .poll           = easycap_poll,
-       .mmap           = easycap_mmap,
-};
-
-static int easycap_register_video(struct easycap *peasycap)
-{
-       /*
-        * FIXME: This is believed to be harmless,
-        * but may well be unnecessary or wrong.
-        */
-       peasycap->video_device.v4l2_dev = NULL;
-
-       strcpy(&peasycap->video_device.name[0], "easycapdc60");
-       peasycap->video_device.fops = &v4l2_fops;
-       peasycap->video_device.minor = -1;
-       peasycap->video_device.release = (void *)(&videodev_release);
-
-       video_set_drvdata(&(peasycap->video_device), (void *)peasycap);
-
-       if (0 != (video_register_device(&(peasycap->video_device),
-                                       VFL_TYPE_GRABBER, -1))) {
-               videodev_release(&(peasycap->video_device));
-               return -ENODEV;
-       }
-
-       peasycap->registered_video++;
-
-       SAM("registered with videodev: %i=minor\n",
-           peasycap->video_device.minor);
-           peasycap->minor = peasycap->video_device.minor;
-
-       return 0;
-}
-
-/*
- * When the device is plugged, this function is called three times,
- * one for each interface.
- */
-static int easycap_usb_probe(struct usb_interface *intf,
-                           const struct usb_device_id *id)
-{
-       struct usb_device *usbdev;
-       struct usb_host_interface *alt;
-       struct usb_endpoint_descriptor *ep;
-       struct usb_interface_descriptor *interface;
-       struct easycap *peasycap;
-       int i, j, rc;
-       u8 bInterfaceNumber;
-       u8 bInterfaceClass;
-       u8 bInterfaceSubClass;
-       int okalt[8], isokalt;
-       int okepn[8];
-       int okmps[8];
-       int maxpacketsize;
-
-       usbdev = interface_to_usbdev(intf);
-
-       alt = usb_altnum_to_altsetting(intf, 0);
-       if (!alt) {
-               SAY("ERROR: usb_host_interface not found\n");
-               return -EFAULT;
-       }
-
-       interface = &alt->desc;
-       if (!interface) {
-               SAY("ERROR: intf_descriptor is NULL\n");
-               return -EFAULT;
-       }
-
-       /* Get properties of probed interface */
-       bInterfaceNumber = interface->bInterfaceNumber;
-       bInterfaceClass = interface->bInterfaceClass;
-       bInterfaceSubClass = interface->bInterfaceSubClass;
-
-       JOT(4, "intf[%i]: num_altsetting=%i\n",
-                       bInterfaceNumber, intf->num_altsetting);
-       JOT(4, "intf[%i]: cur_altsetting - altsetting=%li\n",
-               bInterfaceNumber,
-               (long int)(intf->cur_altsetting - intf->altsetting));
-       JOT(4, "intf[%i]: bInterfaceClass=0x%02X bInterfaceSubClass=0x%02X\n",
-                       bInterfaceNumber, bInterfaceClass, bInterfaceSubClass);
-
-       /*
-        * A new struct easycap is always allocated when interface 0 is probed.
-        * It is not possible here to free any existing struct easycap.
-        * This should have been done by easycap_delete() when the device was
-        * physically unplugged.
-        * The allocated struct easycap is saved for later usage when
-        * interfaces 1 and 2 are probed.
-        */
-       if (0 == bInterfaceNumber) {
-               /*
-                * Alloc structure and save it in a free slot in
-                * easycapdc60_dongle array
-                */
-               peasycap = alloc_easycap(bInterfaceNumber);
-               if (!peasycap)
-                       return -ENOMEM;
-
-               /* Perform basic struct initialization */
-               init_easycap(peasycap, usbdev, intf, bInterfaceNumber);
-
-               /* Dynamically fill in the available formats */
-               rc = easycap_video_fillin_formats();
-               if (0 > rc) {
-                       SAM("ERROR: fillin_formats() rc = %i\n", rc);
-                       return -EFAULT;
-               }
-               JOM(4, "%i formats available\n", rc);
-
-               /* Populate easycap.inputset[] */
-               rc = populate_inputset(peasycap);
-               if (rc < 0)
-                       return rc;
-               JOM(4, "finished initialization\n");
-       } else {
-               peasycap = get_easycap(usbdev, bInterfaceNumber);
-               if (!peasycap)
-                       return -ENODEV;
-       }
-
-       config_easycap(peasycap, bInterfaceNumber,
-                                bInterfaceClass,
-                                bInterfaceSubClass);
-
-       /*
-        * Investigate all altsettings. This is done in detail
-        * because USB device 05e1:0408 has disparate incarnations.
-        */
-       isokalt = 0;
-       for (i = 0; i < intf->num_altsetting; i++) {
-               alt = usb_altnum_to_altsetting(intf, i);
-               if (!alt) {
-                       SAM("ERROR: alt is NULL\n");
-                       return -EFAULT;
-               }
-               interface = &alt->desc;
-               if (!interface) {
-                       SAM("ERROR: intf_descriptor is NULL\n");
-                       return -EFAULT;
-               }
-
-               if (0 == interface->bNumEndpoints)
-                       JOM(4, "intf[%i]alt[%i] has no endpoints\n",
-                                               bInterfaceNumber, i);
-               for (j = 0; j < interface->bNumEndpoints; j++) {
-                       ep = &alt->endpoint[j].desc;
-                       if (!ep) {
-                               SAM("ERROR:  ep is NULL.\n");
-                               SAM("...... skipping\n");
-                               continue;
-                       }
-
-                       if (!usb_endpoint_is_isoc_in(ep)) {
-                               JOM(4, "intf[%i]alt[%i]end[%i] is a %d endpoint\n",
-                                               bInterfaceNumber,
-                                               i, j, ep->bmAttributes);
-                               if (usb_endpoint_dir_out(ep)) {
-                                       SAM("ERROR: OUT endpoint unexpected\n");
-                                       SAM("...... continuing\n");
-                               }
-                               continue;
-                       }
-                       switch (bInterfaceClass) {
-                       case USB_CLASS_VIDEO:
-                       case USB_CLASS_VENDOR_SPEC: {
-                               if (ep->wMaxPacketSize) {
-                                       if (8 > isokalt) {
-                                               okalt[isokalt] = i;
-                                               JOM(4,
-                                               "%i=okalt[%i]\n",
-                                               okalt[isokalt],
-                                               isokalt);
-                                               okepn[isokalt] =
-                                               ep->
-                                               bEndpointAddress &
-                                               0x0F;
-                                               JOM(4,
-                                               "%i=okepn[%i]\n",
-                                               okepn[isokalt],
-                                               isokalt);
-                                               okmps[isokalt] =
-                                               le16_to_cpu(ep->
-                                               wMaxPacketSize);
-                                               JOM(4,
-                                               "%i=okmps[%i]\n",
-                                               okmps[isokalt],
-                                               isokalt);
-                                               isokalt++;
-                                       }
-                               } else {
-                                       if (-1 == peasycap->
-                                               video_altsetting_off) {
-                                               peasycap->
-                                               video_altsetting_off =
-                                                                i;
-                                               JOM(4, "%i=video_"
-                                               "altsetting_off "
-                                                       "<====\n",
-                                               peasycap->
-                                               video_altsetting_off);
-                                       } else {
-                                               SAM("ERROR: peasycap"
-                                               "->video_altsetting_"
-                                               "off already set\n");
-                                               SAM("...... "
-                                               "continuing with "
-                                               "%i=peasycap->video_"
-                                               "altsetting_off\n",
-                                               peasycap->
-                                               video_altsetting_off);
-                                       }
-                               }
-                               break;
-                       }
-                       case USB_CLASS_AUDIO: {
-                               if (bInterfaceSubClass !=
-                                   USB_SUBCLASS_AUDIOSTREAMING)
-                                       break;
-                               if (!peasycap) {
-                                       SAM("MISTAKE: "
-                                       "peasycap is NULL\n");
-                                       return -EFAULT;
-                               }
-                               if (ep->wMaxPacketSize) {
-                                       if (8 > isokalt) {
-                                               okalt[isokalt] = i ;
-                                               JOM(4,
-                                               "%i=okalt[%i]\n",
-                                               okalt[isokalt],
-                                               isokalt);
-                                               okepn[isokalt] =
-                                               ep->
-                                               bEndpointAddress &
-                                               0x0F;
-                                               JOM(4,
-                                               "%i=okepn[%i]\n",
-                                               okepn[isokalt],
-                                               isokalt);
-                                               okmps[isokalt] =
-                                               le16_to_cpu(ep->
-                                               wMaxPacketSize);
-                                               JOM(4,
-                                               "%i=okmps[%i]\n",
-                                               okmps[isokalt],
-                                               isokalt);
-                                               isokalt++;
-                                       }
-                               } else {
-                                       if (-1 == peasycap->
-                                               audio_altsetting_off) {
-                                               peasycap->
-                                               audio_altsetting_off =
-                                                                i;
-                                               JOM(4, "%i=audio_"
-                                               "altsetting_off "
-                                               "<====\n",
-                                               peasycap->
-                                               audio_altsetting_off);
-                                       } else {
-                                               SAM("ERROR: peasycap"
-                                               "->audio_altsetting_"
-                                               "off already set\n");
-                                               SAM("...... "
-                                               "continuing with "
-                                               "%i=peasycap->"
-                                               "audio_altsetting_"
-                                               "off\n",
-                                               peasycap->
-                                               audio_altsetting_off);
-                                       }
-                               }
-                       break;
-                       }
-                       default:
-                               break;
-                       }
-                       if (0 == ep->wMaxPacketSize) {
-                               JOM(4, "intf[%i]alt[%i]end[%i] "
-                                                       "has zero packet size\n",
-                                                       bInterfaceNumber, i, j);
-                       }
-               }
-       }
-
-       /* Perform initialization of the probed interface */
-       JOM(4, "initialization begins for interface %i\n",
-               interface->bInterfaceNumber);
-       switch (bInterfaceNumber) {
-       /* 0: Video interface */
-       case 0: {
-               if (!peasycap) {
-                       SAM("MISTAKE: peasycap is NULL\n");
-                       return -EFAULT;
-               }
-               if (!isokalt) {
-                       SAM("ERROR:  no viable video_altsetting_on\n");
-                       return -ENOENT;
-               }
-               peasycap->video_altsetting_on = okalt[isokalt - 1];
-               JOM(4, "%i=video_altsetting_on <====\n",
-                                       peasycap->video_altsetting_on);
-
-               /* Decide video streaming parameters */
-               peasycap->video_endpointnumber = okepn[isokalt - 1];
-               JOM(4, "%i=video_endpointnumber\n", peasycap->video_endpointnumber);
-               maxpacketsize = okmps[isokalt - 1];
-
-               peasycap->video_isoc_maxframesize =
-                               min(maxpacketsize, USB_2_0_MAXPACKETSIZE);
-               if (0 >= peasycap->video_isoc_maxframesize) {
-                       SAM("ERROR:  bad video_isoc_maxframesize\n");
-                       SAM("        possibly because port is USB 1.1\n");
-                       return -ENOENT;
-               }
-               JOM(4, "%i=video_isoc_maxframesize\n",
-                                       peasycap->video_isoc_maxframesize);
-
-               peasycap->video_isoc_framesperdesc = VIDEO_ISOC_FRAMESPERDESC;
-               JOM(4, "%i=video_isoc_framesperdesc\n",
-                                       peasycap->video_isoc_framesperdesc);
-               if (0 >= peasycap->video_isoc_framesperdesc) {
-                       SAM("ERROR:  bad video_isoc_framesperdesc\n");
-                       return -ENOENT;
-               }
-               peasycap->video_isoc_buffer_size =
-                                       peasycap->video_isoc_maxframesize *
-                                       peasycap->video_isoc_framesperdesc;
-               JOM(4, "%i=video_isoc_buffer_size\n",
-                                       peasycap->video_isoc_buffer_size);
-               if ((PAGE_SIZE << VIDEO_ISOC_ORDER) <
-                                       peasycap->video_isoc_buffer_size) {
-                       SAM("MISTAKE: peasycap->video_isoc_buffer_size too big\n");
-                       return -EFAULT;
-               }
-               if (-1 == peasycap->video_interface) {
-                       SAM("MISTAKE:  video_interface is unset\n");
-                       return -EFAULT;
-               }
-               if (-1 == peasycap->video_altsetting_on) {
-                       SAM("MISTAKE:  video_altsetting_on is unset\n");
-                       return -EFAULT;
-               }
-               if (-1 == peasycap->video_altsetting_off) {
-                       SAM("MISTAKE:  video_interface_off is unset\n");
-                       return -EFAULT;
-               }
-               if (-1 == peasycap->video_endpointnumber) {
-                       SAM("MISTAKE:  video_endpointnumber is unset\n");
-                       return -EFAULT;
-               }
-               if (-1 == peasycap->video_isoc_maxframesize) {
-                       SAM("MISTAKE:  video_isoc_maxframesize is unset\n");
-                       return -EFAULT;
-               }
-               if (-1 == peasycap->video_isoc_buffer_size) {
-                       SAM("MISTAKE:  video_isoc_buffer_size is unset\n");
-                       return -EFAULT;
-               }
-
-               /*
-                * Allocate memory for video buffers.
-                * Lists must be initialized first.
-                */
-               INIT_LIST_HEAD(&(peasycap->urb_video_head));
-               peasycap->purb_video_head = &(peasycap->urb_video_head);
-
-               rc = alloc_framebuffers(peasycap);
-               if (rc < 0)
-                       return rc;
-
-               rc = alloc_fieldbuffers(peasycap);
-               if (rc < 0)
-                       return rc;
-
-               rc = alloc_isocbuffers(peasycap);
-               if (rc < 0)
-                       return rc;
-
-               /* Allocate and initialize video urbs */
-               rc = create_video_urbs(peasycap);
-               if (rc < 0)
-                       return rc;
-
-               /* Save pointer peasycap in this interface */
-               usb_set_intfdata(intf, peasycap);
-
-               /*
-                * It is essential to initialize the hardware before,
-                * rather than after, the device is registered,
-                * because some udev rules triggers easycap_open()
-                * immediately after registration, causing a clash.
-                */
-               rc = reset(peasycap);
-               if (rc) {
-                       SAM("ERROR: reset() rc = %i\n", rc);
-                       return -EFAULT;
-               }
-
-               /* The video device can now be registered */
-               if (v4l2_device_register(&intf->dev, &peasycap->v4l2_device)) {
-                       SAM("v4l2_device_register() failed\n");
-                       return -ENODEV;
-               }
-               JOM(4, "registered device instance: %s\n",
-                       peasycap->v4l2_device.name);
-
-               rc = easycap_register_video(peasycap);
-               if (rc < 0) {
-                       dev_err(&intf->dev,
-                               "Not able to register with videodev\n");
-                       return -ENODEV;
-               }
-               break;
-       }
-       /* 1: Audio control */
-       case 1: {
-               if (!peasycap) {
-                       SAM("MISTAKE: peasycap is NULL\n");
-                       return -EFAULT;
-               }
-               /* Save pointer peasycap in this interface */
-               usb_set_intfdata(intf, peasycap);
-               JOM(4, "no initialization required for interface %i\n",
-                                       interface->bInterfaceNumber);
-               break;
-       }
-       /* 2: Audio streaming */
-       case 2: {
-               if (!peasycap) {
-                       SAM("MISTAKE: peasycap is NULL\n");
-                       return -EFAULT;
-               }
-               if (!isokalt) {
-                       SAM("ERROR:  no viable audio_altsetting_on\n");
-                       return -ENOENT;
-               }
-               peasycap->audio_altsetting_on = okalt[isokalt - 1];
-               JOM(4, "%i=audio_altsetting_on <====\n",
-                                               peasycap->audio_altsetting_on);
-
-               peasycap->audio_endpointnumber = okepn[isokalt - 1];
-               JOM(4, "%i=audio_endpointnumber\n", peasycap->audio_endpointnumber);
-
-               peasycap->audio_isoc_maxframesize = okmps[isokalt - 1];
-               JOM(4, "%i=audio_isoc_maxframesize\n",
-                                               peasycap->audio_isoc_maxframesize);
-               if (0 >= peasycap->audio_isoc_maxframesize) {
-                       SAM("ERROR:  bad audio_isoc_maxframesize\n");
-                       return -ENOENT;
-               }
-               if (9 == peasycap->audio_isoc_maxframesize) {
-                       peasycap->ilk |= 0x02;
-                       SAM("audio hardware is microphone\n");
-                       peasycap->microphone = true;
-                       peasycap->audio_pages_per_fragment =
-                                       PAGES_PER_AUDIO_FRAGMENT;
-               } else if (256 == peasycap->audio_isoc_maxframesize) {
-                       peasycap->ilk &= ~0x02;
-                       SAM("audio hardware is AC'97\n");
-                       peasycap->microphone = false;
-                       peasycap->audio_pages_per_fragment =
-                                       PAGES_PER_AUDIO_FRAGMENT;
-               } else {
-                       SAM("hardware is unidentified:\n");
-                       SAM("%i=audio_isoc_maxframesize\n",
-                               peasycap->audio_isoc_maxframesize);
-                       return -ENOENT;
-               }
-
-               peasycap->audio_bytes_per_fragment =
-                               peasycap->audio_pages_per_fragment * PAGE_SIZE;
-               peasycap->audio_buffer_page_many = (AUDIO_FRAGMENT_MANY *
-                               peasycap->audio_pages_per_fragment);
-
-               JOM(4, "%6i=AUDIO_FRAGMENT_MANY\n", AUDIO_FRAGMENT_MANY);
-               JOM(4, "%6i=audio_pages_per_fragment\n",
-                                               peasycap->audio_pages_per_fragment);
-               JOM(4, "%6i=audio_bytes_per_fragment\n",
-                                               peasycap->audio_bytes_per_fragment);
-               JOM(4, "%6i=audio_buffer_page_many\n",
-                                               peasycap->audio_buffer_page_many);
-
-               peasycap->audio_isoc_framesperdesc = AUDIO_ISOC_FRAMESPERDESC;
-
-               JOM(4, "%i=audio_isoc_framesperdesc\n",
-                                               peasycap->audio_isoc_framesperdesc);
-               if (0 >= peasycap->audio_isoc_framesperdesc) {
-                       SAM("ERROR:  bad audio_isoc_framesperdesc\n");
-                       return -ENOENT;
-               }
-
-               peasycap->audio_isoc_buffer_size =
-                                       peasycap->audio_isoc_maxframesize *
-                                       peasycap->audio_isoc_framesperdesc;
-               JOM(4, "%i=audio_isoc_buffer_size\n",
-                                               peasycap->audio_isoc_buffer_size);
-               if (AUDIO_ISOC_BUFFER_SIZE < peasycap->audio_isoc_buffer_size) {
-                               SAM("MISTAKE:  audio_isoc_buffer_size bigger "
-                               "than %li=AUDIO_ISOC_BUFFER_SIZE\n",
-                                                       AUDIO_ISOC_BUFFER_SIZE);
-                       return -EFAULT;
-               }
-               if (-1 == peasycap->audio_interface) {
-                       SAM("MISTAKE:  audio_interface is unset\n");
-                       return -EFAULT;
-               }
-               if (-1 == peasycap->audio_altsetting_on) {
-                       SAM("MISTAKE:  audio_altsetting_on is unset\n");
-                       return -EFAULT;
-               }
-               if (-1 == peasycap->audio_altsetting_off) {
-                       SAM("MISTAKE:  audio_interface_off is unset\n");
-                       return -EFAULT;
-               }
-               if (-1 == peasycap->audio_endpointnumber) {
-                       SAM("MISTAKE:  audio_endpointnumber is unset\n");
-                       return -EFAULT;
-               }
-               if (-1 == peasycap->audio_isoc_maxframesize) {
-                       SAM("MISTAKE:  audio_isoc_maxframesize is unset\n");
-                       return -EFAULT;
-               }
-               if (-1 == peasycap->audio_isoc_buffer_size) {
-                       SAM("MISTAKE:  audio_isoc_buffer_size is unset\n");
-                       return -EFAULT;
-               }
-
-               /*
-                * Allocate memory for audio buffers.
-                * Lists must be initialized first.
-                */
-               INIT_LIST_HEAD(&(peasycap->urb_audio_head));
-               peasycap->purb_audio_head = &(peasycap->urb_audio_head);
-
-               alloc_audio_buffers(peasycap);
-               if (rc < 0)
-                       return rc;
-
-               /* Allocate and initialize urbs */
-               rc = create_audio_urbs(peasycap);
-               if (rc < 0)
-                       return rc;
-
-               /* Save pointer peasycap in this interface */
-               usb_set_intfdata(intf, peasycap);
-
-               /* The audio device can now be registered */
-               JOM(4, "initializing ALSA card\n");
-
-               rc = easycap_alsa_probe(peasycap);
-               if (rc) {
-                       dev_err(&intf->dev, "easycap_alsa_probe() rc = %i\n",
-                               rc);
-                       return -ENODEV;
-               }
-
-
-               JOM(8, "kref_get() with %i=kref.refcount.counter\n",
-                               peasycap->kref.refcount.counter);
-               kref_get(&peasycap->kref);
-               peasycap->registered_audio++;
-               break;
-       }
-       /* Interfaces other than 0,1,2 are unexpected */
-       default:
-               JOM(4, "ERROR: unexpected interface %i\n", bInterfaceNumber);
-               return -EINVAL;
-       }
-       SAM("ends successfully for interface %i\n", bInterfaceNumber);
-       return 0;
-}
-
-/*
- * When this function is called the device has already been
- * physically unplugged.
- * Hence, peasycap->pusb_device is no longer valid.
- * This function affects alsa.
- */
-static void easycap_usb_disconnect(struct usb_interface *pusb_interface)
-{
-       struct usb_host_interface *pusb_host_interface;
-       struct usb_interface_descriptor *pusb_interface_descriptor;
-       struct easycap *peasycap;
-       int minor, kd;
-       u8 bInterfaceNumber;
-
-       JOT(4, "\n");
-
-       pusb_host_interface = pusb_interface->cur_altsetting;
-       if (!pusb_host_interface) {
-               JOT(4, "ERROR: pusb_host_interface is NULL\n");
-               return;
-       }
-       pusb_interface_descriptor = &(pusb_host_interface->desc);
-       if (!pusb_interface_descriptor) {
-               JOT(4, "ERROR: pusb_interface_descriptor is NULL\n");
-               return;
-       }
-       bInterfaceNumber = pusb_interface_descriptor->bInterfaceNumber;
-       minor = pusb_interface->minor;
-       JOT(4, "intf[%i]: minor=%i\n", bInterfaceNumber, minor);
-
-       /* There is nothing to do for Interface Number 1 */
-       if (1 == bInterfaceNumber)
-               return;
-
-       peasycap = usb_get_intfdata(pusb_interface);
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return;
-       }
-
-       /* If the waitqueues are not cleared a deadlock is possible */
-       peasycap->video_eof = 1;
-       peasycap->audio_eof = 1;
-       wake_up_interruptible(&(peasycap->wq_video));
-       wake_up_interruptible(&(peasycap->wq_audio));
-
-       switch (bInterfaceNumber) {
-       case 0:
-               easycap_video_kill_urbs(peasycap);
-               break;
-       case 2:
-               easycap_audio_kill_urbs(peasycap);
-               break;
-       default:
-               break;
-       }
-
-       /*
-        * Deregister
-        * This procedure will block until easycap_poll(),
-        * video and audio ioctl are all unlocked.
-        * If this is not done an oops can occur when an easycap
-        * is unplugged while the urbs are running.
-        */
-       kd = easycap_isdongle(peasycap);
-       switch (bInterfaceNumber) {
-       case 0: {
-               if (0 <= kd && DONGLE_MANY > kd) {
-                       wake_up_interruptible(&peasycap->wq_video);
-                       JOM(4, "about to lock dongle[%i].mutex_video\n", kd);
-                       if (mutex_lock_interruptible(&easycapdc60_dongle[kd].
-                                                               mutex_video)) {
-                               SAY("ERROR: "
-                                   "cannot lock dongle[%i].mutex_video\n", kd);
-                               return;
-                       }
-                       JOM(4, "locked dongle[%i].mutex_video\n", kd);
-               } else {
-                       SAY("ERROR: %i=kd is bad: cannot lock dongle\n", kd);
-               }
-               if (!peasycap->v4l2_device.name[0]) {
-                       SAM("ERROR: peasycap->v4l2_device.name is empty\n");
-                       if (0 <= kd && DONGLE_MANY > kd)
-                               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       return;
-               }
-               v4l2_device_disconnect(&peasycap->v4l2_device);
-               JOM(4, "v4l2_device_disconnect() OK\n");
-               v4l2_device_unregister(&peasycap->v4l2_device);
-               JOM(4, "v4l2_device_unregister() OK\n");
-
-               video_unregister_device(&peasycap->video_device);
-               JOM(4, "intf[%i]: video_unregister_device() minor=%i\n",
-                               bInterfaceNumber, minor);
-               peasycap->registered_video--;
-
-               if (0 <= kd && DONGLE_MANY > kd) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-                       JOM(4, "unlocked dongle[%i].mutex_video\n", kd);
-               }
-               break;
-       }
-       case 2: {
-               if (0 <= kd && DONGLE_MANY > kd) {
-                       wake_up_interruptible(&peasycap->wq_audio);
-                       JOM(4, "about to lock dongle[%i].mutex_audio\n", kd);
-                       if (mutex_lock_interruptible(&easycapdc60_dongle[kd].
-                                                               mutex_audio)) {
-                               SAY("ERROR: "
-                                   "cannot lock dongle[%i].mutex_audio\n", kd);
-                               return;
-                       }
-                       JOM(4, "locked dongle[%i].mutex_audio\n", kd);
-               } else
-                       SAY("ERROR: %i=kd is bad: cannot lock dongle\n", kd);
-               if (0 != snd_card_free(peasycap->psnd_card)) {
-                       SAY("ERROR: snd_card_free() failed\n");
-               } else {
-                       peasycap->psnd_card = NULL;
-                       (peasycap->registered_audio)--;
-               }
-               if (0 <= kd && DONGLE_MANY > kd) {
-                       mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
-                       JOM(4, "unlocked dongle[%i].mutex_audio\n", kd);
-               }
-               break;
-       }
-       default:
-               break;
-       }
-
-       /*
-        * If no remaining references to peasycap,
-        * call easycap_delete.
-        * (Also when alsa has been in use)
-        */
-       if (!peasycap->kref.refcount.counter) {
-               SAM("ERROR: peasycap->kref.refcount.counter is zero "
-                                                       "so cannot call kref_put()\n");
-               SAM("ending unsuccessfully: may cause memory leak\n");
-               return;
-       }
-       if (0 <= kd && DONGLE_MANY > kd) {
-               JOM(4, "about to lock dongle[%i].mutex_video\n", kd);
-               if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_video)) {
-                       SAY("ERROR: cannot lock dongle[%i].mutex_video\n", kd);
-                       SAM("ending unsuccessfully: may cause memory leak\n");
-                       return;
-               }
-               JOM(4, "locked dongle[%i].mutex_video\n", kd);
-               JOM(4, "about to lock dongle[%i].mutex_audio\n", kd);
-               if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_audio)) {
-                       SAY("ERROR: cannot lock dongle[%i].mutex_audio\n", kd);
-                       mutex_unlock(&(easycapdc60_dongle[kd].mutex_video));
-                       JOM(4, "unlocked dongle[%i].mutex_video\n", kd);
-                       SAM("ending unsuccessfully: may cause memory leak\n");
-                       return;
-               }
-               JOM(4, "locked dongle[%i].mutex_audio\n", kd);
-       }
-       JOM(4, "intf[%i]: %i=peasycap->kref.refcount.counter\n",
-                       bInterfaceNumber, (int)peasycap->kref.refcount.counter);
-       kref_put(&peasycap->kref, easycap_delete);
-       JOT(4, "intf[%i]: kref_put() done.\n", bInterfaceNumber);
-       if (0 <= kd && DONGLE_MANY > kd) {
-               mutex_unlock(&(easycapdc60_dongle[kd].mutex_audio));
-               JOT(4, "unlocked dongle[%i].mutex_audio\n", kd);
-               mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
-               JOT(4, "unlocked dongle[%i].mutex_video\n", kd);
-       }
-       JOM(4, "ends\n");
-       return;
-}
-
-/* Devices supported by this driver */
-static struct usb_device_id easycap_usb_device_id_table[] = {
-       {USB_DEVICE(USB_EASYCAP_VENDOR_ID, USB_EASYCAP_PRODUCT_ID)},
-       { }
-};
-
-MODULE_DEVICE_TABLE(usb, easycap_usb_device_id_table);
-static struct usb_driver easycap_usb_driver = {
-       .name = "easycap",
-       .id_table = easycap_usb_device_id_table,
-       .probe = easycap_usb_probe,
-       .disconnect = easycap_usb_disconnect,
-};
-
-static int __init easycap_module_init(void)
-{
-       int k, rc;
-
-       printk(KERN_INFO "Easycap version: "EASYCAP_DRIVER_VERSION "\n");
-
-       JOT(4, "begins.  %i=debug %i=bars %i=gain\n",
-               easycap_debug, easycap_bars, easycap_gain);
-
-       mutex_init(&mutex_dongle);
-       for (k = 0; k < DONGLE_MANY; k++) {
-               easycapdc60_dongle[k].peasycap = NULL;
-               mutex_init(&easycapdc60_dongle[k].mutex_video);
-               mutex_init(&easycapdc60_dongle[k].mutex_audio);
-       }
-       rc = usb_register(&easycap_usb_driver);
-       if (rc)
-               printk(KERN_ERR "Easycap: usb_register failed rc=%d\n", rc);
-
-       return rc;
-}
-
-static void __exit easycap_module_exit(void)
-{
-       usb_deregister(&easycap_usb_driver);
-}
-
-module_init(easycap_module_init);
-module_exit(easycap_module_exit);
diff --git a/drivers/staging/media/easycap/easycap_settings.c b/drivers/staging/media/easycap/easycap_settings.c
deleted file mode 100644 (file)
index 3f5f5b3..0000000
+++ /dev/null
@@ -1,696 +0,0 @@
-/******************************************************************************
-*                                                                             *
-*  easycap_settings.c                                                         *
-*                                                                             *
-******************************************************************************/
-/*
- *
- *  Copyright (C) 2010 R.M. Thomas  <rmthomas@sciolus.org>
- *
- *
- *  This 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.
- *
- *  The software 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 software; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
-*/
-/*****************************************************************************/
-
-#include "easycap.h"
-
-/*---------------------------------------------------------------------------*/
-/*
- *  THE LEAST SIGNIFICANT BIT OF easycap_standard.mask HAS MEANING:
- *                         0 => 25 fps
- *                         1 => 30 fps
- *
- *  THE MOST  SIGNIFICANT BIT OF easycap_standard.mask HAS MEANING:
- *                         0 => full framerate
- *                         1 => 20%  framerate
- */
-/*---------------------------------------------------------------------------*/
-const struct easycap_standard easycap_standard[] = {
-       {
-               .mask = 0x00FF & PAL_BGHIN ,
-               .v4l2_standard = {
-                       .index = PAL_BGHIN,
-                       .id = (V4L2_STD_PAL_B |
-                               V4L2_STD_PAL_G | V4L2_STD_PAL_H |
-                               V4L2_STD_PAL_I | V4L2_STD_PAL_N),
-                       .name = "PAL_BGHIN",
-                       .frameperiod = {1, 25},
-                       .framelines = 625,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x00FF & NTSC_N_443 ,
-               .v4l2_standard = {
-                       .index = NTSC_N_443,
-                       .id = V4L2_STD_UNKNOWN,
-                       .name = "NTSC_N_443",
-                       .frameperiod = {1, 25},
-                       .framelines = 480,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x00FF & PAL_Nc ,
-               .v4l2_standard = {
-                       .index = PAL_Nc,
-                       .id = V4L2_STD_PAL_Nc,
-                       .name = "PAL_Nc",
-                       .frameperiod = {1, 25},
-                       .framelines = 625,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x00FF & NTSC_N ,
-               .v4l2_standard = {
-                       .index = NTSC_N,
-                       .id = V4L2_STD_UNKNOWN,
-                       .name = "NTSC_N",
-                       .frameperiod = {1, 25},
-                       .framelines = 525,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x00FF & SECAM ,
-               .v4l2_standard = {
-                       .index = SECAM,
-                       .id = V4L2_STD_SECAM,
-                       .name = "SECAM",
-                       .frameperiod = {1, 25},
-                       .framelines = 625,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x00FF & NTSC_M ,
-               .v4l2_standard = {
-                       .index = NTSC_M,
-                       .id = V4L2_STD_NTSC_M,
-                       .name = "NTSC_M",
-                       .frameperiod = {1, 30},
-                       .framelines = 525,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x00FF & NTSC_M_JP ,
-               .v4l2_standard = {
-                       .index = NTSC_M_JP,
-                       .id = V4L2_STD_NTSC_M_JP,
-                       .name = "NTSC_M_JP",
-                       .frameperiod = {1, 30},
-                       .framelines = 525,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x00FF & PAL_60 ,
-               .v4l2_standard = {
-                       .index = PAL_60,
-                       .id = V4L2_STD_PAL_60,
-                       .name = "PAL_60",
-                       .frameperiod = {1, 30},
-                       .framelines = 525,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x00FF & NTSC_443 ,
-               .v4l2_standard = {
-                       .index = NTSC_443,
-                       .id = V4L2_STD_NTSC_443,
-                       .name = "NTSC_443",
-                       .frameperiod = {1, 30},
-                       .framelines = 525,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x00FF & PAL_M ,
-               .v4l2_standard = {
-                       .index = PAL_M,
-                       .id = V4L2_STD_PAL_M,
-                       .name = "PAL_M",
-                       .frameperiod = {1, 30},
-                       .framelines = 525,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x8000 | (0x00FF & PAL_BGHIN_SLOW),
-               .v4l2_standard = {
-                       .index = PAL_BGHIN_SLOW,
-                       .id = (V4L2_STD_PAL_B | V4L2_STD_PAL_G |
-                               V4L2_STD_PAL_H |
-                               V4L2_STD_PAL_I | V4L2_STD_PAL_N |
-                               (((v4l2_std_id)0x01) << 32)),
-                       .name = "PAL_BGHIN_SLOW",
-                       .frameperiod = {1, 5},
-                       .framelines = 625,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x8000 | (0x00FF & NTSC_N_443_SLOW),
-               .v4l2_standard = {
-                       .index = NTSC_N_443_SLOW,
-                       .id = (V4L2_STD_UNKNOWN | (((v4l2_std_id)0x11) << 32)),
-                       .name = "NTSC_N_443_SLOW",
-                       .frameperiod = {1, 5},
-                       .framelines = 480,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x8000 | (0x00FF & PAL_Nc_SLOW),
-               .v4l2_standard = {
-                       .index = PAL_Nc_SLOW,
-                       .id = (V4L2_STD_PAL_Nc | (((v4l2_std_id)0x01) << 32)),
-                       .name = "PAL_Nc_SLOW",
-                       .frameperiod = {1, 5},
-                       .framelines = 625,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x8000 | (0x00FF & NTSC_N_SLOW),
-               .v4l2_standard = {
-                       .index = NTSC_N_SLOW,
-                       .id = (V4L2_STD_UNKNOWN | (((v4l2_std_id)0x21) << 32)),
-                       .name = "NTSC_N_SLOW",
-                       .frameperiod = {1, 5},
-                       .framelines = 525,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x8000 | (0x00FF & SECAM_SLOW),
-               .v4l2_standard = {
-                       .index = SECAM_SLOW,
-                       .id = (V4L2_STD_SECAM | (((v4l2_std_id)0x01) << 32)),
-                       .name = "SECAM_SLOW",
-                       .frameperiod = {1, 5},
-                       .framelines = 625,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x8000 | (0x00FF & NTSC_M_SLOW),
-               .v4l2_standard = {
-                       .index = NTSC_M_SLOW,
-                       .id = (V4L2_STD_NTSC_M | (((v4l2_std_id)0x01) << 32)),
-                       .name = "NTSC_M_SLOW",
-                       .frameperiod = {1, 6},
-                       .framelines = 525,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x8000 | (0x00FF & NTSC_M_JP_SLOW),
-               .v4l2_standard = {
-                       .index = NTSC_M_JP_SLOW,
-                       .id = (V4L2_STD_NTSC_M_JP |
-                               (((v4l2_std_id)0x01) << 32)),
-                       .name = "NTSC_M_JP_SLOW",
-                       .frameperiod = {1, 6},
-                       .framelines = 525,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x8000 | (0x00FF & PAL_60_SLOW),
-               .v4l2_standard = {
-                       .index = PAL_60_SLOW,
-                       .id = (V4L2_STD_PAL_60 | (((v4l2_std_id)0x01) << 32)),
-                       .name = "PAL_60_SLOW",
-                       .frameperiod = {1, 6},
-                       .framelines = 525,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x8000 | (0x00FF & NTSC_443_SLOW),
-               .v4l2_standard = {
-                       .index = NTSC_443_SLOW,
-                       .id = (V4L2_STD_NTSC_443 | (((v4l2_std_id)0x01) << 32)),
-                       .name = "NTSC_443_SLOW",
-                       .frameperiod = {1, 6},
-                       .framelines = 525,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0x8000 | (0x00FF & PAL_M_SLOW),
-               .v4l2_standard = {
-                       .index = PAL_M_SLOW,
-                       .id = (V4L2_STD_PAL_M | (((v4l2_std_id)0x01) << 32)),
-                       .name = "PAL_M_SLOW",
-                       .frameperiod = {1, 6},
-                       .framelines = 525,
-                       .reserved = {0, 0, 0, 0}
-               }
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .mask = 0xFFFF
-       }
-};
-/*---------------------------------------------------------------------------*/
-/*
- *  THE 16-BIT easycap_format.mask HAS MEANING:
- *    (least significant) BIT  0:     0 => PAL, 25 FPS;   1 => NTSC, 30 FPS
- *                        BITS 2-4:   RESERVED FOR DIFFERENTIATING STANDARDS
- *                        BITS 5-7:   NUMBER OF BYTES PER PIXEL
- *                        BIT  8:     0 => NATIVE BYTE ORDER;  1 => SWAPPED
- *                        BITS 9-10:  RESERVED FOR OTHER BYTE PERMUTATIONS
- *                        BIT 11:     0 => UNDECIMATED;    1 => DECIMATED
- *                        BIT 12:     0 => OFFER FRAMES;   1 => OFFER FIELDS
- *                        BIT 13:     0 => FULL FRAMERATE; 1 => REDUCED
- *     (most significant) BITS 14-15: RESERVED FOR OTHER FIELD/FRAME OPTIONS
- *  IT FOLLOWS THAT:
- *     bytesperpixel IS         ((0x00E0 & easycap_format.mask) >> 5)
- *     byteswaporder IS true IF (0 != (0x0100 & easycap_format.mask))
- *
- *     decimatepixel IS true IF (0 != (0x0800 & easycap_format.mask))
- *
- *       offerfields IS true IF (0 != (0x1000 & easycap_format.mask))
- */
-/*---------------------------------------------------------------------------*/
-
-struct easycap_format easycap_format[1 + SETTINGS_MANY];
-
-int easycap_video_fillin_formats(void)
-{
-       const char *name1, *name2, *name3, *name4;
-       struct v4l2_format *fmt;
-       int i, j, k, m, n;
-       u32 width, height, pixelformat, bytesperline, sizeimage;
-       u16 mask1, mask2, mask3, mask4;
-       enum v4l2_field field;
-       enum v4l2_colorspace colorspace;
-
-       for (i = 0, n = 0; i < STANDARD_MANY; i++) {
-               mask1 = 0x0000;
-               switch (i) {
-               case PAL_BGHIN: {
-                       mask1 = 0x1F & PAL_BGHIN;
-                       name1 = "PAL_BGHIN";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
-                       break;
-               }
-               case SECAM: {
-                       mask1 = 0x1F & SECAM;
-                       name1 = "SECAM";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
-                       break;
-               }
-               case PAL_Nc: {
-                       mask1 = 0x1F & PAL_Nc;
-                       name1 = "PAL_Nc";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
-                       break;
-               }
-               case PAL_60: {
-                       mask1 = 0x1F & PAL_60;
-                       name1 = "PAL_60";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
-                       break;
-               }
-               case PAL_M: {
-                       mask1 = 0x1F & PAL_M;
-                       name1 = "PAL_M";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
-                       break;
-               }
-               case NTSC_M: {
-                       mask1 = 0x1F & NTSC_M;
-                       name1 = "NTSC_M";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
-                       break;
-               }
-               case NTSC_443: {
-                       mask1 = 0x1F & NTSC_443;
-                       name1 = "NTSC_443";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
-                       break;
-               }
-               case NTSC_M_JP: {
-                       mask1 = 0x1F & NTSC_M_JP;
-                       name1 = "NTSC_M_JP";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
-                       break;
-               }
-               case NTSC_N: {
-                       mask1 = 0x1F & NTSC_M;
-                       name1 = "NTSC_N";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
-                       break;
-               }
-               case NTSC_N_443: {
-                       mask1 = 0x1F & NTSC_N_443;
-                       name1 = "NTSC_N_443";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
-                       break;
-               }
-               case PAL_BGHIN_SLOW: {
-                       mask1 = 0x001F & PAL_BGHIN_SLOW;
-                       mask1 |= 0x0200;
-                       name1 = "PAL_BGHIN_SLOW";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
-                       break;
-               }
-               case SECAM_SLOW: {
-                       mask1 = 0x001F & SECAM_SLOW;
-                       mask1 |= 0x0200;
-                       name1 = "SECAM_SLOW";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
-                       break;
-               }
-               case PAL_Nc_SLOW: {
-                       mask1 = 0x001F & PAL_Nc_SLOW;
-                       mask1 |= 0x0200;
-                       name1 = "PAL_Nc_SLOW";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
-                       break;
-               }
-               case PAL_60_SLOW: {
-                       mask1 = 0x001F & PAL_60_SLOW;
-                       mask1 |= 0x0200;
-                       name1 = "PAL_60_SLOW";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
-                       break;
-               }
-               case PAL_M_SLOW: {
-                       mask1 = 0x001F & PAL_M_SLOW;
-                       mask1 |= 0x0200;
-                       name1 = "PAL_M_SLOW";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_BG;
-                       break;
-               }
-               case NTSC_M_SLOW: {
-                       mask1 = 0x001F & NTSC_M_SLOW;
-                       mask1 |= 0x0200;
-                       name1 = "NTSC_M_SLOW";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
-                       break;
-               }
-               case NTSC_443_SLOW: {
-                       mask1 = 0x001F & NTSC_443_SLOW;
-                       mask1 |= 0x0200;
-                       name1 = "NTSC_443_SLOW";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
-                       break;
-               }
-               case NTSC_M_JP_SLOW: {
-                       mask1 = 0x001F & NTSC_M_JP_SLOW;
-                       mask1 |= 0x0200;
-                       name1 = "NTSC_M_JP_SLOW";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
-                       break;
-               }
-               case NTSC_N_SLOW: {
-                       mask1 = 0x001F & NTSC_N_SLOW;
-                       mask1 |= 0x0200;
-                       name1 = "NTSC_N_SLOW";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
-                       break;
-               }
-               case NTSC_N_443_SLOW: {
-                       mask1 = 0x001F & NTSC_N_443_SLOW;
-                       mask1 |= 0x0200;
-                       name1 = "NTSC_N_443_SLOW";
-                       colorspace = V4L2_COLORSPACE_470_SYSTEM_M;
-                       break;
-               }
-               default:
-                       return -1;
-               }
-
-               for (j = 0; j < RESOLUTION_MANY; j++) {
-                       mask2 = 0x0000;
-                       switch (j) {
-                       case AT_720x576: {
-                               if (0x1 & mask1)
-                                       continue;
-                               name2 = "_AT_720x576";
-                               width = 720;
-                               height = 576;
-                               break;
-                       }
-                       case AT_704x576: {
-                               if (0x1 & mask1)
-                                       continue;
-                               name2 = "_AT_704x576";
-                               width = 704;
-                               height = 576;
-                               break;
-                       }
-                       case AT_640x480: {
-                               name2 = "_AT_640x480";
-                               width = 640;
-                               height = 480;
-                               break;
-                       }
-                       case AT_720x480: {
-                               if (!(0x1 & mask1))
-                                       continue;
-                               name2 = "_AT_720x480";
-                               width = 720;
-                               height = 480;
-                               break;
-                       }
-                       case AT_360x288: {
-                               if (0x1 & mask1)
-                                       continue;
-                               name2 = "_AT_360x288";
-                               width = 360;
-                               height = 288;
-                               mask2 = 0x0800;
-                               break;
-                       }
-                       case AT_320x240: {
-                               name2 = "_AT_320x240";
-                               width = 320;
-                               height = 240;
-                               mask2 = 0x0800;
-                               break;
-                       }
-                       case AT_360x240: {
-                               if (!(0x1 & mask1))
-                                       continue;
-                               name2 = "_AT_360x240";
-                               width = 360;
-                               height = 240;
-                               mask2 = 0x0800;
-                               break;
-                       }
-                       default:
-                               return -2;
-                       }
-
-                       for (k = 0; k < PIXELFORMAT_MANY; k++) {
-                               mask3 = 0x0000;
-                               switch (k) {
-                               case FMT_UYVY: {
-                                       name3 = __stringify(FMT_UYVY);
-                                       pixelformat = V4L2_PIX_FMT_UYVY;
-                                       mask3 |= (0x02 << 5);
-                                       break;
-                               }
-                               case FMT_YUY2: {
-                                       name3 = __stringify(FMT_YUY2);
-                                       pixelformat = V4L2_PIX_FMT_YUYV;
-                                       mask3 |= (0x02 << 5);
-                                       mask3 |= 0x0100;
-                                       break;
-                               }
-                               case FMT_RGB24: {
-                                       name3 = __stringify(FMT_RGB24);
-                                       pixelformat = V4L2_PIX_FMT_RGB24;
-                                       mask3 |= (0x03 << 5);
-                                       break;
-                               }
-                               case FMT_RGB32: {
-                                       name3 = __stringify(FMT_RGB32);
-                                       pixelformat = V4L2_PIX_FMT_RGB32;
-                                       mask3 |= (0x04 << 5);
-                                       break;
-                               }
-                               case FMT_BGR24: {
-                                       name3 = __stringify(FMT_BGR24);
-                                       pixelformat = V4L2_PIX_FMT_BGR24;
-                                       mask3 |= (0x03 << 5);
-                                       mask3 |= 0x0100;
-                                       break;
-                               }
-                               case FMT_BGR32: {
-                                       name3 = __stringify(FMT_BGR32);
-                                       pixelformat = V4L2_PIX_FMT_BGR32;
-                                       mask3 |= (0x04 << 5);
-                                       mask3 |= 0x0100;
-                                       break;
-                               }
-                               default:
-                                       return -3;
-                               }
-                               bytesperline = width * ((mask3 & 0x00E0) >> 5);
-                               sizeimage =  bytesperline * height;
-
-                               for (m = 0; m < INTERLACE_MANY; m++) {
-                                       mask4 = 0x0000;
-                                       switch (m) {
-                                       case FIELD_NONE: {
-                                               name4 = "-n";
-                                               field = V4L2_FIELD_NONE;
-                                               break;
-                                       }
-                                       case FIELD_INTERLACED: {
-                                               name4 = "-i";
-                                               mask4 |= 0x1000;
-                                               field = V4L2_FIELD_INTERLACED;
-                                               break;
-                                       }
-                                       default:
-                                               return -4;
-                                       }
-                                       if (SETTINGS_MANY <= n)
-                                               return -5;
-
-                                       strcpy(easycap_format[n].name, name1);
-                                       strcat(easycap_format[n].name, name2);
-                                       strcat(easycap_format[n].name, "_");
-                                       strcat(easycap_format[n].name, name3);
-                                       strcat(easycap_format[n].name, name4);
-                                       easycap_format[n].mask =
-                                               mask1 | mask2 | mask3 | mask4;
-                                       fmt = &easycap_format[n].v4l2_format;
-
-                                       fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-                                       fmt->fmt.pix.width = width;
-                                       fmt->fmt.pix.height = height;
-                                       fmt->fmt.pix.pixelformat = pixelformat;
-                                       fmt->fmt.pix.field = field;
-                                       fmt->fmt.pix.bytesperline = bytesperline;
-                                       fmt->fmt.pix.sizeimage = sizeimage;
-                                       fmt->fmt.pix.colorspace = colorspace;
-                                       fmt->fmt.pix.priv = 0;
-                                       n++;
-                               }
-                       }
-               }
-       }
-       if ((1 + SETTINGS_MANY) <= n)
-               return -6;
-       easycap_format[n].mask = 0xFFFF;
-       return n;
-}
-/*---------------------------------------------------------------------------*/
-struct v4l2_queryctrl easycap_control[] = {
-       {
-               .id       = V4L2_CID_BRIGHTNESS,
-               .type     = V4L2_CTRL_TYPE_INTEGER,
-               .name     = "Brightness",
-               .minimum  = 0,
-               .maximum  = 255,
-               .step     =  1,
-               .default_value = SAA_0A_DEFAULT,
-               .flags    = 0,
-               .reserved = {0, 0}
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .id       = V4L2_CID_CONTRAST,
-               .type     = V4L2_CTRL_TYPE_INTEGER,
-               .name     = "Contrast",
-               .minimum  = 0,
-               .maximum  = 255,
-               .step     =   1,
-               .default_value = SAA_0B_DEFAULT + 128,
-               .flags    = 0,
-               .reserved = {0, 0}
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .id       = V4L2_CID_SATURATION,
-               .type     = V4L2_CTRL_TYPE_INTEGER,
-               .name     = "Saturation",
-               .minimum  = 0,
-               .maximum  = 255,
-               .step     =   1,
-               .default_value = SAA_0C_DEFAULT + 128,
-               .flags    = 0,
-               .reserved = {0, 0}
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .id       = V4L2_CID_HUE,
-               .type     = V4L2_CTRL_TYPE_INTEGER,
-               .name     = "Hue",
-               .minimum  = 0,
-               .maximum  = 255,
-               .step     =   1,
-               .default_value = SAA_0D_DEFAULT + 128,
-               .flags    = 0,
-               .reserved = {0, 0}
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .id       = V4L2_CID_AUDIO_VOLUME,
-               .type     = V4L2_CTRL_TYPE_INTEGER,
-               .name     = "Volume",
-               .minimum  = 0,
-               .maximum  = 31,
-               .step     =   1,
-               .default_value = 16,
-               .flags    = 0,
-               .reserved = {0, 0}
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .id       = V4L2_CID_AUDIO_MUTE,
-               .type     = V4L2_CTRL_TYPE_BOOLEAN,
-               .name     = "Mute",
-               .default_value = true,
-               .flags    = 0,
-               .reserved = {0, 0}
-       },
-/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-       {
-               .id = 0xFFFFFFFF
-       }
-};
-/*****************************************************************************/
diff --git a/drivers/staging/media/easycap/easycap_sound.c b/drivers/staging/media/easycap/easycap_sound.c
deleted file mode 100644 (file)
index 8c8bcae..0000000
+++ /dev/null
@@ -1,750 +0,0 @@
-/******************************************************************************
-*                                                                             *
-*  easycap_sound.c                                                            *
-*                                                                             *
-*  Audio driver for EasyCAP USB2.0 Video Capture Device DC60                  *
-*                                                                             *
-*                                                                             *
-******************************************************************************/
-/*
- *
- *  Copyright (C) 2010 R.M. Thomas  <rmthomas@sciolus.org>
- *
- *
- *  This 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.
- *
- *  The software 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 software; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
-*/
-/*****************************************************************************/
-
-#include "easycap.h"
-
-/*--------------------------------------------------------------------------*/
-/*
- *  PARAMETERS USED WHEN REGISTERING THE AUDIO INTERFACE
- */
-/*--------------------------------------------------------------------------*/
-static const struct snd_pcm_hardware alsa_hardware = {
-       .info = SNDRV_PCM_INFO_BLOCK_TRANSFER |
-               SNDRV_PCM_INFO_MMAP           |
-               SNDRV_PCM_INFO_INTERLEAVED    |
-               SNDRV_PCM_INFO_MMAP_VALID,
-       .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
-       .rate_min = 32000,
-       .rate_max = 48000,
-       .channels_min = 2,
-       .channels_max = 2,
-       .buffer_bytes_max = PAGE_SIZE *
-                           PAGES_PER_AUDIO_FRAGMENT *
-                           AUDIO_FRAGMENT_MANY,
-       .period_bytes_min = PAGE_SIZE * PAGES_PER_AUDIO_FRAGMENT,
-       .period_bytes_max = PAGE_SIZE * PAGES_PER_AUDIO_FRAGMENT * 2,
-       .periods_min = AUDIO_FRAGMENT_MANY,
-       .periods_max = AUDIO_FRAGMENT_MANY * 2,
-};
-
-
-/*---------------------------------------------------------------------------*/
-/*
- *  SUBMIT ALL AUDIO URBS.
- */
-/*---------------------------------------------------------------------------*/
-static int easycap_audio_submit_urbs(struct easycap *peasycap)
-{
-       struct data_urb *pdata_urb;
-       struct urb *purb;
-       struct list_head *plist_head;
-       int j, isbad, nospc, m, rc;
-       int isbuf;
-
-       if (!peasycap->purb_audio_head) {
-               SAM("ERROR: peasycap->urb_audio_head uninitialized\n");
-               return -EFAULT;
-       }
-       if (!peasycap->pusb_device) {
-               SAM("ERROR: peasycap->pusb_device is NULL\n");
-               return -EFAULT;
-       }
-
-       if (peasycap->audio_isoc_streaming) {
-               JOM(4, "already streaming audio urbs\n");
-               return 0;
-       }
-
-       JOM(4, "initial submission of all audio urbs\n");
-       rc = usb_set_interface(peasycap->pusb_device,
-                              peasycap->audio_interface,
-                              peasycap->audio_altsetting_on);
-       JOM(8, "usb_set_interface(.,%i,%i) returned %i\n",
-           peasycap->audio_interface,
-           peasycap->audio_altsetting_on, rc);
-
-       isbad = 0;
-       nospc = 0;
-       m = 0;
-       list_for_each(plist_head, peasycap->purb_audio_head) {
-               pdata_urb = list_entry(plist_head, struct data_urb, list_head);
-               if (pdata_urb && pdata_urb->purb) {
-                       purb = pdata_urb->purb;
-                       isbuf = pdata_urb->isbuf;
-
-                       purb->interval = 1;
-                       purb->dev = peasycap->pusb_device;
-                       purb->pipe = usb_rcvisocpipe(peasycap->pusb_device,
-                                       peasycap->audio_endpointnumber);
-                       purb->transfer_flags = URB_ISO_ASAP;
-                       purb->transfer_buffer = peasycap->audio_isoc_buffer[isbuf].pgo;
-                       purb->transfer_buffer_length = peasycap->audio_isoc_buffer_size;
-                       purb->complete = easycap_alsa_complete;
-                       purb->context = peasycap;
-                       purb->start_frame = 0;
-                       purb->number_of_packets = peasycap->audio_isoc_framesperdesc;
-                       for (j = 0;  j < peasycap->audio_isoc_framesperdesc; j++) {
-                               purb->iso_frame_desc[j].offset = j * peasycap->audio_isoc_maxframesize;
-                               purb->iso_frame_desc[j].length = peasycap->audio_isoc_maxframesize;
-                       }
-
-                       rc = usb_submit_urb(purb, GFP_KERNEL);
-                       if (rc) {
-                               isbad++;
-                               SAM("ERROR: usb_submit_urb() failed"
-                                   " for urb with rc: -%s: %d\n",
-                                   strerror(rc), rc);
-                       } else {
-                               m++;
-                       }
-               } else {
-                       isbad++;
-               }
-       }
-       if (nospc) {
-               SAM("-ENOSPC=usb_submit_urb() for %i urbs\n", nospc);
-               SAM(".....  possibly inadequate USB bandwidth\n");
-               peasycap->audio_eof = 1;
-       }
-
-       if (isbad)
-               easycap_audio_kill_urbs(peasycap);
-       else
-               peasycap->audio_isoc_streaming = m;
-
-       return 0;
-}
-/*---------------------------------------------------------------------------*/
-/*
- *  COMMON AUDIO INITIALIZATION
- */
-/*---------------------------------------------------------------------------*/
-static int easycap_sound_setup(struct easycap *peasycap)
-{
-       int rc;
-
-       JOM(4, "starting initialization\n");
-
-       if (!peasycap) {
-               SAY("ERROR:  peasycap is NULL.\n");
-               return -EFAULT;
-       }
-       if (!peasycap->pusb_device) {
-               SAM("ERROR: peasycap->pusb_device is NULL\n");
-               return -ENODEV;
-       }
-       JOM(16, "0x%08lX=peasycap->pusb_device\n", (long int)peasycap->pusb_device);
-
-       rc = easycap_audio_setup(peasycap);
-       JOM(8, "audio_setup() returned %i\n", rc);
-
-       if (!peasycap->pusb_device) {
-               SAM("ERROR: peasycap->pusb_device has become NULL\n");
-               return -ENODEV;
-       }
-/*---------------------------------------------------------------------------*/
-       if (!peasycap->pusb_device) {
-               SAM("ERROR: peasycap->pusb_device has become NULL\n");
-               return -ENODEV;
-       }
-       rc = usb_set_interface(peasycap->pusb_device, peasycap->audio_interface,
-                              peasycap->audio_altsetting_on);
-       JOM(8, "usb_set_interface(.,%i,%i) returned %i\n", peasycap->audio_interface,
-           peasycap->audio_altsetting_on, rc);
-
-       rc = easycap_wakeup_device(peasycap->pusb_device);
-       JOM(8, "wakeup_device() returned %i\n", rc);
-
-       peasycap->audio_eof = 0;
-       peasycap->audio_idle = 0;
-
-       easycap_audio_submit_urbs(peasycap);
-
-       JOM(4, "finished initialization\n");
-       return 0;
-}
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- *  ON COMPLETION OF AN AUDIO URB ITS DATA IS COPIED TO THE DAM BUFFER
- *  PROVIDED peasycap->audio_idle IS ZERO.  REGARDLESS OF THIS BEING TRUE,
- *  IT IS RESUBMITTED PROVIDED peasycap->audio_isoc_streaming IS NOT ZERO.
- */
-/*---------------------------------------------------------------------------*/
-void easycap_alsa_complete(struct urb *purb)
-{
-       struct easycap *peasycap;
-       struct snd_pcm_substream *pss;
-       struct snd_pcm_runtime *prt;
-       int dma_bytes, fragment_bytes;
-       int isfragment;
-       u8 *p1, *p2;
-       s16 tmp;
-       int i, j, more, much, rc;
-#ifdef UPSAMPLE
-       int k;
-       s16 oldaudio, newaudio, delta;
-#endif /*UPSAMPLE*/
-
-       JOT(16, "\n");
-
-       if (!purb) {
-               SAY("ERROR: purb is NULL\n");
-               return;
-       }
-       peasycap = purb->context;
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return;
-       }
-       much = 0;
-       if (peasycap->audio_idle) {
-               JOM(16, "%i=audio_idle  %i=audio_isoc_streaming\n",
-                   peasycap->audio_idle, peasycap->audio_isoc_streaming);
-               if (peasycap->audio_isoc_streaming)
-                       goto resubmit;
-       }
-/*---------------------------------------------------------------------------*/
-       pss = peasycap->psubstream;
-       if (!pss)
-               goto resubmit;
-       prt = pss->runtime;
-       if (!prt)
-               goto resubmit;
-       dma_bytes = (int)prt->dma_bytes;
-       if (0 == dma_bytes)
-               goto resubmit;
-       fragment_bytes = 4 * ((int)prt->period_size);
-       if (0 == fragment_bytes)
-               goto resubmit;
-/* -------------------------------------------------------------------------*/
-       if (purb->status) {
-               if ((-ESHUTDOWN == purb->status) || (-ENOENT == purb->status)) {
-                       JOM(16, "urb status -ESHUTDOWN or -ENOENT\n");
-                       return;
-               }
-               SAM("ERROR: non-zero urb status: -%s: %d\n",
-                   strerror(purb->status), purb->status);
-               goto resubmit;
-       }
-/*---------------------------------------------------------------------------*/
-/*
- *  PROCEED HERE WHEN NO ERROR
- */
-/*---------------------------------------------------------------------------*/
-
-#ifdef UPSAMPLE
-       oldaudio = peasycap->oldaudio;
-#endif /*UPSAMPLE*/
-
-       for (i = 0;  i < purb->number_of_packets; i++) {
-               if (purb->iso_frame_desc[i].status < 0) {
-                       SAM("-%s: %d\n",
-                           strerror(purb->iso_frame_desc[i].status),
-                           purb->iso_frame_desc[i].status);
-               }
-               if (purb->iso_frame_desc[i].status) {
-                       JOM(12, "discarding audio samples because "
-                           "%i=purb->iso_frame_desc[i].status\n",
-                           purb->iso_frame_desc[i].status);
-                       continue;
-               }
-               more = purb->iso_frame_desc[i].actual_length;
-               if (more == 0) {
-                       peasycap->audio_mt++;
-                       continue;
-               }
-               if (0 > more) {
-                       SAM("MISTAKE: more is negative\n");
-                       return;
-               }
-
-               if (peasycap->audio_mt) {
-                       JOM(12, "%4i empty audio urb frames\n",
-                           peasycap->audio_mt);
-                       peasycap->audio_mt = 0;
-               }
-
-               p1 = (u8 *)(purb->transfer_buffer +
-                               purb->iso_frame_desc[i].offset);
-
-               /*
-                *  COPY more BYTES FROM ISOC BUFFER
-                *  TO THE DMA BUFFER, CONVERTING
-                *  8-BIT MONO TO 16-BIT SIGNED
-                *  LITTLE-ENDIAN SAMPLES IF NECESSARY
-                */
-               while (more) {
-                       much = dma_bytes - peasycap->dma_fill;
-                       if (0 > much) {
-                               SAM("MISTAKE: much is negative\n");
-                               return;
-                       }
-                       if (0 == much) {
-                               peasycap->dma_fill = 0;
-                               peasycap->dma_next = fragment_bytes;
-                               JOM(8, "wrapped dma buffer\n");
-                       }
-                       if (!peasycap->microphone) {
-                               if (much > more)
-                                       much = more;
-                               memcpy(prt->dma_area + peasycap->dma_fill,
-                                       p1, much);
-                               p1 += much;
-                               more -= much;
-                       } else {
-#ifdef UPSAMPLE
-                               if (much % 16)
-                                       JOM(8, "MISTAKE? much"
-                                           " is not divisible by 16\n");
-                               if (much > (16 * more))
-                                       much = 16 * more;
-                               p2 = (u8 *)(prt->dma_area + peasycap->dma_fill);
-
-                               for (j = 0;  j < (much / 16);  j++) {
-                                       newaudio =  ((int) *p1) - 128;
-                                       newaudio = 128 * newaudio;
-
-                                       delta = (newaudio - oldaudio) / 4;
-                                       tmp = oldaudio + delta;
-
-                                       for (k = 0;  k < 4;  k++) {
-                                               *p2 = (0x00FF & tmp);
-                                               *(p2 + 1) = (0xFF00 & tmp) >> 8;
-                                               p2 += 2;
-                                               *p2 = (0x00FF & tmp);
-                                               *(p2 + 1) = (0xFF00 & tmp) >> 8;
-                                               p2 += 2;
-                                               tmp += delta;
-                                       }
-                                       p1++;
-                                       more--;
-                                       oldaudio = tmp;
-                               }
-#else /*!UPSAMPLE*/
-                               if (much > (2 * more))
-                                       much = 2 * more;
-                               p2 = (u8 *)(prt->dma_area + peasycap->dma_fill);
-
-                               for (j = 0;  j < (much / 2);  j++) {
-                                       tmp = ((int) *p1) - 128;
-                                       tmp = 128 * tmp;
-                                       *p2 = (0x00FF & tmp);
-                                       *(p2 + 1) = (0xFF00 & tmp) >> 8;
-                                       p1++;
-                                       p2 += 2;
-                                       more--;
-                               }
-#endif /*UPSAMPLE*/
-                       }
-                       peasycap->dma_fill += much;
-                       if (peasycap->dma_fill >= peasycap->dma_next) {
-                               isfragment = peasycap->dma_fill / fragment_bytes;
-                               if (0 > isfragment) {
-                                       SAM("MISTAKE: isfragment is negative\n");
-                                       return;
-                               }
-                               peasycap->dma_read = (isfragment - 1) * fragment_bytes;
-                               peasycap->dma_next = (isfragment + 1) * fragment_bytes;
-                               if (dma_bytes < peasycap->dma_next)
-                                       peasycap->dma_next = fragment_bytes;
-
-                               if (0 <= peasycap->dma_read) {
-                                       JOM(8, "snd_pcm_period_elapsed(), %i="
-                                           "isfragment\n", isfragment);
-                                       snd_pcm_period_elapsed(pss);
-                               }
-                       }
-               }
-
-#ifdef UPSAMPLE
-               peasycap->oldaudio = oldaudio;
-#endif /*UPSAMPLE*/
-
-       }
-/*---------------------------------------------------------------------------*/
-/*
- *  RESUBMIT THIS URB
- */
-/*---------------------------------------------------------------------------*/
-resubmit:
-       if (peasycap->audio_isoc_streaming == 0)
-               return;
-
-       rc = usb_submit_urb(purb, GFP_ATOMIC);
-       if (rc) {
-               if ((-ENODEV != rc) && (-ENOENT != rc)) {
-                       SAM("ERROR: while %i=audio_idle, usb_submit_urb failed "
-                           "with rc: -%s :%d\n",
-                               peasycap->audio_idle, strerror(rc), rc);
-               }
-               if (0 < peasycap->audio_isoc_streaming)
-                       peasycap->audio_isoc_streaming--;
-       }
-       return;
-}
-/*****************************************************************************/
-static int easycap_alsa_open(struct snd_pcm_substream *pss)
-{
-       struct snd_pcm *psnd_pcm;
-       struct snd_card *psnd_card;
-       struct easycap *peasycap;
-
-       JOT(4, "\n");
-       if (!pss) {
-               SAY("ERROR:  pss is NULL\n");
-               return -EFAULT;
-       }
-       psnd_pcm = pss->pcm;
-       if (!psnd_pcm) {
-               SAY("ERROR:  psnd_pcm is NULL\n");
-               return -EFAULT;
-       }
-       psnd_card = psnd_pcm->card;
-       if (!psnd_card) {
-               SAY("ERROR:  psnd_card is NULL\n");
-               return -EFAULT;
-       }
-
-       peasycap = psnd_card->private_data;
-       if (!peasycap) {
-               SAY("ERROR:  peasycap is NULL\n");
-               return -EFAULT;
-       }
-       if (peasycap->psnd_card != psnd_card) {
-               SAM("ERROR: bad peasycap->psnd_card\n");
-               return -EFAULT;
-       }
-       if (peasycap->psubstream) {
-               SAM("ERROR: bad peasycap->psubstream\n");
-               return -EFAULT;
-       }
-       pss->private_data = peasycap;
-       peasycap->psubstream = pss;
-       pss->runtime->hw = peasycap->alsa_hardware;
-       pss->runtime->private_data = peasycap;
-       pss->private_data = peasycap;
-
-       if (0 != easycap_sound_setup(peasycap)) {
-               JOM(4, "ending unsuccessfully\n");
-               return -EFAULT;
-       }
-       JOM(4, "ending successfully\n");
-       return 0;
-}
-/*****************************************************************************/
-static int easycap_alsa_close(struct snd_pcm_substream *pss)
-{
-       struct easycap *peasycap;
-
-       JOT(4, "\n");
-       if (!pss) {
-               SAY("ERROR:  pss is NULL\n");
-               return -EFAULT;
-       }
-       peasycap = snd_pcm_substream_chip(pss);
-       if (!peasycap) {
-               SAY("ERROR:  peasycap is NULL\n");
-               return -EFAULT;
-       }
-       pss->private_data = NULL;
-       peasycap->psubstream = NULL;
-       JOT(4, "ending successfully\n");
-       return 0;
-}
-/*****************************************************************************/
-static int easycap_alsa_vmalloc(struct snd_pcm_substream *pss, size_t sz)
-{
-       struct snd_pcm_runtime *prt;
-       JOT(4, "\n");
-
-       if (!pss) {
-               SAY("ERROR:  pss is NULL\n");
-               return -EFAULT;
-       }
-       prt = pss->runtime;
-       if (!prt) {
-               SAY("ERROR: substream.runtime is NULL\n");
-               return -EFAULT;
-       }
-       if (prt->dma_area) {
-               if (prt->dma_bytes > sz)
-                       return 0;
-               vfree(prt->dma_area);
-       }
-       prt->dma_area = vmalloc(sz);
-       if (!prt->dma_area)
-               return -ENOMEM;
-       prt->dma_bytes = sz;
-       return 0;
-}
-/*****************************************************************************/
-static int easycap_alsa_hw_params(struct snd_pcm_substream *pss,
-                                struct snd_pcm_hw_params *phw)
-{
-       int rc;
-
-       JOT(4, "%i\n", (params_buffer_bytes(phw)));
-       if (!pss) {
-               SAY("ERROR:  pss is NULL\n");
-               return -EFAULT;
-       }
-       rc = easycap_alsa_vmalloc(pss, params_buffer_bytes(phw));
-       if (rc)
-               return rc;
-       return 0;
-}
-/*****************************************************************************/
-static int easycap_alsa_hw_free(struct snd_pcm_substream *pss)
-{
-       struct snd_pcm_runtime *prt;
-       JOT(4, "\n");
-
-       if (!pss) {
-               SAY("ERROR:  pss is NULL\n");
-               return -EFAULT;
-       }
-       prt = pss->runtime;
-       if (!prt) {
-               SAY("ERROR: substream.runtime is NULL\n");
-               return -EFAULT;
-       }
-       if (prt->dma_area) {
-               JOT(8, "prt->dma_area = %p\n", prt->dma_area);
-               vfree(prt->dma_area);
-               prt->dma_area = NULL;
-       } else
-               JOT(8, "dma_area already freed\n");
-       return 0;
-}
-/*****************************************************************************/
-static int easycap_alsa_prepare(struct snd_pcm_substream *pss)
-{
-       struct easycap *peasycap;
-       struct snd_pcm_runtime *prt;
-
-       JOT(4, "\n");
-       if (!pss) {
-               SAY("ERROR:  pss is NULL\n");
-               return -EFAULT;
-       }
-       prt = pss->runtime;
-       peasycap = snd_pcm_substream_chip(pss);
-       if (!peasycap) {
-               SAY("ERROR:  peasycap is NULL\n");
-               return -EFAULT;
-       }
-
-       JOM(16, "ALSA decides %8i Hz=rate\n", pss->runtime->rate);
-       JOM(16, "ALSA decides %8ld =period_size\n", pss->runtime->period_size);
-       JOM(16, "ALSA decides %8i =periods\n", pss->runtime->periods);
-       JOM(16, "ALSA decides %8ld =buffer_size\n", pss->runtime->buffer_size);
-       JOM(16, "ALSA decides %8zd =dma_bytes\n", pss->runtime->dma_bytes);
-       JOM(16, "ALSA decides %8ld =boundary\n", pss->runtime->boundary);
-       JOM(16, "ALSA decides %8i =period_step\n", pss->runtime->period_step);
-       JOM(16, "ALSA decides %8i =sample_bits\n", pss->runtime->sample_bits);
-       JOM(16, "ALSA decides %8i =frame_bits\n", pss->runtime->frame_bits);
-       JOM(16, "ALSA decides %8ld =min_align\n", pss->runtime->min_align);
-       JOM(12, "ALSA decides %8ld =hw_ptr_base\n", pss->runtime->hw_ptr_base);
-       JOM(12, "ALSA decides %8ld =hw_ptr_interrupt\n",
-               pss->runtime->hw_ptr_interrupt);
-
-       if (prt->dma_bytes != 4 * ((int)prt->period_size) * ((int)prt->periods)) {
-               SAY("MISTAKE:  unexpected ALSA parameters\n");
-               return -ENOENT;
-       }
-       return 0;
-}
-/*****************************************************************************/
-static int easycap_alsa_ack(struct snd_pcm_substream *pss)
-{
-       return 0;
-}
-/*****************************************************************************/
-static int easycap_alsa_trigger(struct snd_pcm_substream *pss, int cmd)
-{
-       struct easycap *peasycap;
-
-       JOT(4, "%i=cmd cf %i=START %i=STOP\n", cmd, SNDRV_PCM_TRIGGER_START,
-           SNDRV_PCM_TRIGGER_STOP);
-       if (!pss) {
-               SAY("ERROR:  pss is NULL\n");
-               return -EFAULT;
-       }
-       peasycap = snd_pcm_substream_chip(pss);
-       if (!peasycap) {
-               SAY("ERROR:  peasycap is NULL\n");
-               return -EFAULT;
-       }
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START: {
-               peasycap->audio_idle = 0;
-               break;
-       }
-       case SNDRV_PCM_TRIGGER_STOP: {
-               peasycap->audio_idle = 1;
-               break;
-       }
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-/*****************************************************************************/
-static snd_pcm_uframes_t easycap_alsa_pointer(struct snd_pcm_substream *pss)
-{
-       struct easycap *peasycap;
-       snd_pcm_uframes_t offset;
-
-       JOT(16, "\n");
-       if (!pss) {
-               SAY("ERROR:  pss is NULL\n");
-               return -EFAULT;
-       }
-       peasycap = snd_pcm_substream_chip(pss);
-       if (!peasycap) {
-               SAY("ERROR:  peasycap is NULL\n");
-               return -EFAULT;
-       }
-       if ((0 != peasycap->audio_eof) || (0 != peasycap->audio_idle)) {
-               JOM(8, "returning -EIO because  "
-                   "%i=audio_idle  %i=audio_eof\n",
-                   peasycap->audio_idle, peasycap->audio_eof);
-               return -EIO;
-       }
-/*---------------------------------------------------------------------------*/
-       if (0 > peasycap->dma_read) {
-               JOM(8, "returning -EBUSY\n");
-               return -EBUSY;
-       }
-       offset = ((snd_pcm_uframes_t)peasycap->dma_read)/4;
-       JOM(8, "ALSA decides %8i   =hw_ptr_base\n", (int)pss->runtime->hw_ptr_base);
-       JOM(8, "ALSA decides %8i   =hw_ptr_interrupt\n",
-           (int)pss->runtime->hw_ptr_interrupt);
-       JOM(8, "%7i=offset %7i=dma_read %7i=dma_next\n",
-           (int)offset, peasycap->dma_read, peasycap->dma_next);
-       return offset;
-}
-/*****************************************************************************/
-static struct page *
-easycap_alsa_page(struct snd_pcm_substream *pss, unsigned long offset)
-{
-       return vmalloc_to_page(pss->runtime->dma_area + offset);
-}
-/*****************************************************************************/
-
-static struct snd_pcm_ops easycap_alsa_pcm_ops = {
-       .open      = easycap_alsa_open,
-       .close     = easycap_alsa_close,
-       .ioctl     = snd_pcm_lib_ioctl,
-       .hw_params = easycap_alsa_hw_params,
-       .hw_free   = easycap_alsa_hw_free,
-       .prepare   = easycap_alsa_prepare,
-       .ack       = easycap_alsa_ack,
-       .trigger   = easycap_alsa_trigger,
-       .pointer   = easycap_alsa_pointer,
-       .page      = easycap_alsa_page,
-};
-
-/*****************************************************************************/
-/*---------------------------------------------------------------------------*/
-/*
- *  THE FUNCTION snd_card_create() HAS  THIS_MODULE  AS AN ARGUMENT.  THIS
- *  MEANS MODULE easycap.  BEWARE.
-*/
-/*---------------------------------------------------------------------------*/
-int easycap_alsa_probe(struct easycap *peasycap)
-{
-       int rc;
-       struct snd_card *psnd_card;
-       struct snd_pcm *psnd_pcm;
-
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return -ENODEV;
-       }
-       if (0 > peasycap->minor) {
-               SAY("ERROR: no minor\n");
-               return -ENODEV;
-       }
-
-       peasycap->alsa_hardware = alsa_hardware;
-       if (peasycap->microphone) {
-               peasycap->alsa_hardware.rates = SNDRV_PCM_RATE_32000;
-               peasycap->alsa_hardware.rate_min = 32000;
-               peasycap->alsa_hardware.rate_max = 32000;
-       } else {
-               peasycap->alsa_hardware.rates = SNDRV_PCM_RATE_48000;
-               peasycap->alsa_hardware.rate_min = 48000;
-               peasycap->alsa_hardware.rate_max = 48000;
-       }
-
-       if (0 != snd_card_create(SNDRV_DEFAULT_IDX1, "easycap_alsa",
-                               THIS_MODULE, 0, &psnd_card)) {
-               SAY("ERROR: Cannot do ALSA snd_card_create()\n");
-               return -EFAULT;
-       }
-
-       sprintf(&psnd_card->id[0], "EasyALSA%i", peasycap->minor);
-       strcpy(&psnd_card->driver[0], EASYCAP_DRIVER_DESCRIPTION);
-       strcpy(&psnd_card->shortname[0], "easycap_alsa");
-       sprintf(&psnd_card->longname[0], "%s", &psnd_card->shortname[0]);
-
-       psnd_card->dev = &peasycap->pusb_device->dev;
-       psnd_card->private_data = peasycap;
-       peasycap->psnd_card = psnd_card;
-
-       rc = snd_pcm_new(psnd_card, "easycap_pcm", 0, 0, 1, &psnd_pcm);
-       if (rc) {
-               SAM("ERROR: Cannot do ALSA snd_pcm_new()\n");
-               snd_card_free(psnd_card);
-               return -EFAULT;
-       }
-
-       snd_pcm_set_ops(psnd_pcm, SNDRV_PCM_STREAM_CAPTURE,
-                       &easycap_alsa_pcm_ops);
-       psnd_pcm->info_flags = 0;
-       strcpy(&psnd_pcm->name[0], &psnd_card->id[0]);
-       psnd_pcm->private_data = peasycap;
-       peasycap->psnd_pcm = psnd_pcm;
-       peasycap->psubstream = NULL;
-
-       rc = snd_card_register(psnd_card);
-       if (rc) {
-               SAM("ERROR: Cannot do ALSA snd_card_register()\n");
-               snd_card_free(psnd_card);
-               return -EFAULT;
-       }
-
-       SAM("registered %s\n", &psnd_card->id[0]);
-       return 0;
-}
-
diff --git a/drivers/staging/media/easycap/easycap_testcard.c b/drivers/staging/media/easycap/easycap_testcard.c
deleted file mode 100644 (file)
index 0f71470..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-/******************************************************************************
-*                                                                             *
-*  easycap_testcard.c                                                         *
-*                                                                             *
-******************************************************************************/
-/*
- *
- *  Copyright (C) 2010 R.M. Thomas  <rmthomas@sciolus.org>
- *
- *
- *  This 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.
- *
- *  The software 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 software; if not, write to the Free Software
- *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
-*/
-/*****************************************************************************/
-
-#include "easycap.h"
-
-/*****************************************************************************/
-#define TESTCARD_BYTESPERLINE (2 * 720)
-void
-easycap_testcard(struct easycap *peasycap, int field)
-{
-       int total;
-       int y, u, v, r, g, b;
-       unsigned char uyvy[4];
-       int i1, line, k, m, n, more, much, barwidth, barheight;
-       unsigned char bfbar[TESTCARD_BYTESPERLINE / 8], *p1, *p2;
-       struct data_buffer *pfield_buffer;
-
-       if (!peasycap) {
-               SAY("ERROR: peasycap is NULL\n");
-               return;
-       }
-       JOM(8, "%i=field\n", field);
-       switch (peasycap->width) {
-       case 720:
-       case 360: {
-               barwidth = (2 * 720) / 8;
-               break;
-       }
-       case 704:
-       case 352: {
-               barwidth = (2 * 704) / 8;
-               break;
-       }
-       case 640:
-       case 320: {
-               barwidth = (2 * 640) / 8;
-               break;
-       }
-       default: {
-               SAM("ERROR:  cannot set barwidth\n");
-               return;
-       }
-       }
-       if (TESTCARD_BYTESPERLINE < barwidth) {
-               SAM("ERROR: barwidth is too large\n");
-               return;
-       }
-       switch (peasycap->height) {
-       case 576:
-       case 288: {
-               barheight = 576;
-               break;
-       }
-       case 480:
-       case 240: {
-               barheight = 480;
-               break;
-       }
-       default: {
-               SAM("ERROR: cannot set barheight\n");
-               return;
-       }
-       }
-       total = 0;
-       k = field;
-       m = 0;
-       n = 0;
-
-       for (line = 0;  line < (barheight / 2);  line++) {
-               for (i1 = 0;  i1 < 8;  i1++) {
-                       r = (i1 * 256)/8;
-                       g = (i1 * 256)/8;
-                       b = (i1 * 256)/8;
-
-                       y =  299*r/1000 + 587*g/1000 + 114*b/1000 ;
-                       u = -147*r/1000 - 289*g/1000 + 436*b/1000 ;
-                       u = u + 128;
-                       v =  615*r/1000 - 515*g/1000 - 100*b/1000 ;
-                       v = v + 128;
-
-                       uyvy[0] =  0xFF & u ;
-                       uyvy[1] =  0xFF & y ;
-                       uyvy[2] =  0xFF & v ;
-                       uyvy[3] =  0xFF & y ;
-
-                       p1 = &bfbar[0];
-                       while (p1 < &bfbar[barwidth]) {
-                               *p1++ = uyvy[0] ;
-                               *p1++ = uyvy[1] ;
-                               *p1++ = uyvy[2] ;
-                               *p1++ = uyvy[3] ;
-                               total += 4;
-                       }
-
-                       p1 = &bfbar[0];
-                       more = barwidth;
-
-                       while (more) {
-                               if ((FIELD_BUFFER_SIZE/PAGE_SIZE) <= m) {
-                                       SAM("ERROR:  bad m reached\n");
-                                       return;
-                               }
-                               if (PAGE_SIZE < n) {
-                                       SAM("ERROR:  bad n reached\n");
-                                       return;
-                               }
-
-                               if (0 > more) {
-                                       SAM("ERROR:  internal fault\n");
-                                       return;
-                               }
-
-                               much = PAGE_SIZE - n;
-                               if (much > more)
-                                       much = more;
-                               pfield_buffer = &peasycap->field_buffer[k][m];
-                               p2 = pfield_buffer->pgo + n;
-                               memcpy(p2, p1, much);
-
-                               p1 += much;
-                               n += much;
-                               more -= much;
-                               if (PAGE_SIZE == n) {
-                                       m++;
-                                       n = 0;
-                               }
-                       }
-               }
-       }
-       return;
-}
index 695ea35f75b0831cc8e2d28369d9ef124f8c2da9..fb52fe0d13ce6b462c5aeba4aad03a03dd69125e 100644 (file)
@@ -366,8 +366,7 @@ static void nvec_request_master(struct work_struct *work)
 static int parse_msg(struct nvec_chip *nvec, struct nvec_msg *msg)
 {
        if ((msg->data[0] & 1 << 7) == 0 && msg->data[3]) {
-               dev_err(nvec->dev, "ec responded %02x %02x %02x %02x\n",
-                       msg->data[0], msg->data[1], msg->data[2], msg->data[3]);
+               dev_err(nvec->dev, "ec responded %*ph\n", 4, msg->data);
                return -EINVAL;
        }
 
@@ -737,12 +736,14 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev)
                nvec->gpio = pdata->gpio;
                nvec->i2c_addr = pdata->i2c_addr;
        } else if (nvec->dev->of_node) {
-               nvec->gpio = of_get_named_gpio(nvec->dev->of_node, "request-gpios", 0);
+               nvec->gpio = of_get_named_gpio(nvec->dev->of_node,
+                                       "request-gpios", 0);
                if (nvec->gpio < 0) {
                        dev_err(&pdev->dev, "no gpio specified");
                        return -ENODEV;
                }
-               if (of_property_read_u32(nvec->dev->of_node, "slave-addr", &nvec->i2c_addr)) {
+               if (of_property_read_u32(nvec->dev->of_node,
+                                       "slave-addr", &nvec->i2c_addr)) {
                        dev_err(&pdev->dev, "no i2c address specified");
                        return -ENODEV;
                }
index 0675a5e2f7c8a8413f6f4db75299d44499cc3a03..d543d5c37152847427d4947bab46a1d6bfa9ca00 100644 (file)
@@ -246,7 +246,7 @@ int omap_thermal_expose_sensor(struct omap_bandgap *bg_ptr, int id,
        /* Create thermal zone */
        data->omap_thermal = thermal_zone_device_register(domain,
                                OMAP_TRIP_NUMBER, 0, data, &omap_thermal_ops,
-                               0, FAST_TEMP_MONITORING_RATE, 0, 0);
+                               0, FAST_TEMP_MONITORING_RATE);
        if (IS_ERR_OR_NULL(data->omap_thermal)) {
                dev_err(bg_ptr->dev, "thermal zone device is NULL\n");
                return PTR_ERR(data->omap_thermal);
index 62e0022561bc51679961e83fd7f3045ced437958..98a10bcba0d3287ee84d1a5430a44e1b9d2abe9a 100644 (file)
@@ -191,10 +191,18 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
        return 0;
 }
 
+static int omap_crtc_set_property(struct drm_crtc *crtc,
+               struct drm_property *property, uint64_t val)
+{
+       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+       return omap_plane_set_property(omap_crtc->plane, property, val);
+}
+
 static const struct drm_crtc_funcs omap_crtc_funcs = {
        .set_config = drm_crtc_helper_set_config,
        .destroy = omap_crtc_destroy,
        .page_flip = omap_crtc_page_flip_locked,
+       .set_property = omap_crtc_set_property,
 };
 
 static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = {
@@ -231,6 +239,8 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
        drm_crtc_init(dev, crtc, &omap_crtc_funcs);
        drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs);
 
+       omap_plane_install_properties(omap_crtc->plane, &crtc->base);
+
        return crtc;
 
 fail:
index 86197831f63ec01bc9f42f9979a0b56e941d4dc2..3ae39554df1874662ff7f032186d966e51c7d8d2 100644 (file)
@@ -120,7 +120,7 @@ static int wait_status(struct refill_engine *engine, uint32_t wait_mask)
        return 0;
 }
 
-irqreturn_t omap_dmm_irq_handler(int irq, void *arg)
+static irqreturn_t omap_dmm_irq_handler(int irq, void *arg)
 {
        struct dmm *dmm = arg;
        uint32_t status = readl(dmm->base + DMM_PAT_IRQSTATUS);
@@ -367,7 +367,7 @@ struct tiler_block *tiler_reserve_1d(size_t size)
        int num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
 
        if (!block)
-               return 0;
+               return ERR_PTR(-ENOMEM);
 
        block->fmt = TILFMT_PAGE;
 
@@ -404,8 +404,26 @@ int tiler_release(struct tiler_block *block)
  * Utils
  */
 
-/* calculate the tiler space address of a pixel in a view orientation */
-static u32 tiler_get_address(u32 orient, enum tiler_fmt fmt, u32 x, u32 y)
+/* calculate the tiler space address of a pixel in a view orientation...
+ * below description copied from the display subsystem section of TRM:
+ *
+ * When the TILER is addressed, the bits:
+ *   [28:27] = 0x0 for 8-bit tiled
+ *             0x1 for 16-bit tiled
+ *             0x2 for 32-bit tiled
+ *             0x3 for page mode
+ *   [31:29] = 0x0 for 0-degree view
+ *             0x1 for 180-degree view + mirroring
+ *             0x2 for 0-degree view + mirroring
+ *             0x3 for 180-degree view
+ *             0x4 for 270-degree view + mirroring
+ *             0x5 for 270-degree view
+ *             0x6 for 90-degree view
+ *             0x7 for 90-degree view + mirroring
+ * Otherwise the bits indicated the corresponding bit address to access
+ * the SDRAM.
+ */
+static u32 tiler_get_address(enum tiler_fmt fmt, u32 orient, u32 x, u32 y)
 {
        u32 x_bits, y_bits, tmp, x_mask, y_mask, alignment;
 
@@ -417,8 +435,11 @@ static u32 tiler_get_address(u32 orient, enum tiler_fmt fmt, u32 x, u32 y)
        x_mask = MASK(x_bits);
        y_mask = MASK(y_bits);
 
-       if (x < 0 || x > x_mask || y < 0 || y > y_mask)
+       if (x < 0 || x > x_mask || y < 0 || y > y_mask) {
+               DBG("invalid coords: %u < 0 || %u > %u || %u < 0 || %u > %u",
+                               x, x, x_mask, y, y, y_mask);
                return 0;
+       }
 
        /* account for mirroring */
        if (orient & MASK_X_INVERT)
@@ -439,11 +460,22 @@ dma_addr_t tiler_ssptr(struct tiler_block *block)
 {
        BUG_ON(!validfmt(block->fmt));
 
-       return TILVIEW_8BIT + tiler_get_address(0, block->fmt,
+       return TILVIEW_8BIT + tiler_get_address(block->fmt, 0,
                        block->area.p0.x * geom[block->fmt].slot_w,
                        block->area.p0.y * geom[block->fmt].slot_h);
 }
 
+dma_addr_t tiler_tsptr(struct tiler_block *block, uint32_t orient,
+               uint32_t x, uint32_t y)
+{
+       struct tcm_pt *p = &block->area.p0;
+       BUG_ON(!validfmt(block->fmt));
+
+       return tiler_get_address(block->fmt, orient,
+                       (p->x * geom[block->fmt].slot_w) + x,
+                       (p->y * geom[block->fmt].slot_h) + y);
+}
+
 void tiler_align(enum tiler_fmt fmt, uint16_t *w, uint16_t *h)
 {
        BUG_ON(!validfmt(fmt));
@@ -451,11 +483,14 @@ void tiler_align(enum tiler_fmt fmt, uint16_t *w, uint16_t *h)
        *h = round_up(*h, geom[fmt].slot_h);
 }
 
-uint32_t tiler_stride(enum tiler_fmt fmt)
+uint32_t tiler_stride(enum tiler_fmt fmt, uint32_t orient)
 {
        BUG_ON(!validfmt(fmt));
 
-       return 1 << (CONT_WIDTH_BITS + geom[fmt].y_shft);
+       if (orient & MASK_XY_FLIP)
+               return 1 << (CONT_HEIGHT_BITS + geom[fmt].x_shft);
+       else
+               return 1 << (CONT_WIDTH_BITS + geom[fmt].y_shft);
 }
 
 size_t tiler_size(enum tiler_fmt fmt, uint16_t w, uint16_t h)
index 7b1052a329e46126f82292a6f50fae23e1a00223..740911df5fc3d9842de401aec53d6dae1482bf09 100644 (file)
@@ -54,7 +54,18 @@ struct tiler_block {
 #define TILER_WIDTH             (1 << (CONT_WIDTH_BITS - SLOT_WIDTH_BITS))
 #define TILER_HEIGHT            (1 << (CONT_HEIGHT_BITS - SLOT_HEIGHT_BITS))
 
-/* tiler space addressing bitfields */
+/*
+Table 15-11. Coding and Description of TILER Orientations
+S Y X  Description                             Alternate description
+0 0 0  0-degree view                           Natural view
+0 0 1  0-degree view with vertical mirror      180-degree view with horizontal mirror
+0 1 0  0-degree view with horizontal mirror    180-degree view with vertical mirror
+0 1 1  180-degree view
+1 0 0  90-degree view with vertical mirror     270-degree view with horizontal mirror
+1 0 1  270-degree view
+1 1 0  90-degree view
+1 1 1  90-degree view with horizontal mirror   270-degree view with vertical mirror
+ */
 #define MASK_XY_FLIP           (1 << 31)
 #define MASK_Y_INVERT          (1 << 30)
 #define MASK_X_INVERT          (1 << 29)
@@ -90,7 +101,9 @@ int tiler_release(struct tiler_block *block);
 
 /* utilities */
 dma_addr_t tiler_ssptr(struct tiler_block *block);
-uint32_t tiler_stride(enum tiler_fmt fmt);
+dma_addr_t tiler_tsptr(struct tiler_block *block, uint32_t orient,
+               uint32_t x, uint32_t y);
+uint32_t tiler_stride(enum tiler_fmt fmt, uint32_t orient);
 size_t tiler_size(enum tiler_fmt fmt, uint16_t w, uint16_t h);
 size_t tiler_vsize(enum tiler_fmt fmt, uint16_t w, uint16_t h);
 void tiler_align(enum tiler_fmt fmt, uint16_t *w, uint16_t *h);
index 4beab9447ceb9b7def14b825645181308860f6a4..b8e79eb7cd5e147a887116eba5048fdca6913f6a 100644 (file)
@@ -649,6 +649,8 @@ static int dev_firstopen(struct drm_device *dev)
  */
 static void dev_lastclose(struct drm_device *dev)
 {
+       int i;
+
        /* we don't support vga-switcheroo.. so just make sure the fbdev
         * mode is active
         */
@@ -657,6 +659,21 @@ static void dev_lastclose(struct drm_device *dev)
 
        DBG("lastclose: dev=%p", dev);
 
+       /* need to restore default rotation state.. not sure if there is
+        * a cleaner way to restore properties to default state?  Maybe
+        * a flag that properties should automatically be restored to
+        * default state on lastclose?
+        */
+       for (i = 0; i < priv->num_crtcs; i++) {
+               drm_object_property_set_value(&priv->crtcs[i]->base,
+                               priv->rotation_prop, 0);
+       }
+
+       for (i = 0; i < priv->num_planes; i++) {
+               drm_object_property_set_value(&priv->planes[i]->base,
+                               priv->rotation_prop, 0);
+       }
+
        ret = drm_fb_helper_restore_fbdev_mode(priv->fbdev);
        if (ret)
                DBG("failed to restore crtc mode");
@@ -761,7 +778,6 @@ static struct drm_driver omap_drm_driver = {
                .irq_postinstall = dev_irq_postinstall,
                .irq_uninstall = dev_irq_uninstall,
                .irq_handler = dev_irq_handler,
-               .reclaim_buffers = drm_core_reclaim_buffers,
 #ifdef CONFIG_DEBUG_FS
                .debugfs_init = omap_debugfs_init,
                .debugfs_cleanup = omap_debugfs_cleanup,
index 2092a9167d2925e86c19a728ac7ce6131bf795ba..9dc72d143ff3fd70c7bfcf95721eff42fbe09986 100644 (file)
@@ -59,6 +59,27 @@ struct omap_drm_private {
        struct list_head obj_list;
 
        bool has_dmm;
+
+       /* properties: */
+       struct drm_property *rotation_prop;
+       struct drm_property *zorder_prop;
+};
+
+/* this should probably be in drm-core to standardize amongst drivers */
+#define DRM_ROTATE_0   0
+#define DRM_ROTATE_90  1
+#define DRM_ROTATE_180 2
+#define DRM_ROTATE_270 3
+#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
@@ -87,6 +108,10 @@ int omap_plane_mode_set(struct drm_plane *plane,
                uint32_t src_w, uint32_t src_h);
 void omap_plane_on_endwin(struct drm_plane *plane,
                void (*fxn)(void *), void *arg);
+void omap_plane_install_properties(struct drm_plane *plane,
+               struct drm_mode_object *obj);
+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);
@@ -114,8 +139,8 @@ struct drm_gem_object *omap_framebuffer_bo(struct drm_framebuffer *fb, int p);
 int omap_framebuffer_replace(struct drm_framebuffer *a,
                struct drm_framebuffer *b, void *arg,
                void (*unpin)(void *arg, struct drm_gem_object *bo));
-void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, int x, int y,
-               struct omap_overlay_info *info);
+void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
+               struct omap_drm_window *win, struct omap_overlay_info *info);
 struct drm_connector *omap_framebuffer_get_next_connector(
                struct drm_framebuffer *fb, struct drm_connector *from);
 void omap_framebuffer_flush(struct drm_framebuffer *fb,
@@ -157,8 +182,12 @@ int omap_gem_get_pages(struct drm_gem_object *obj, struct page ***pages,
                bool remap);
 int omap_gem_put_pages(struct drm_gem_object *obj);
 uint32_t omap_gem_flags(struct drm_gem_object *obj);
+int omap_gem_rotated_paddr(struct drm_gem_object *obj, uint32_t orient,
+               int x, int y, dma_addr_t *paddr);
 uint64_t omap_gem_mmap_offset(struct drm_gem_object *obj);
 size_t omap_gem_mmap_size(struct drm_gem_object *obj);
+int omap_gem_tiled_size(struct drm_gem_object *obj, uint16_t *w, uint16_t *h);
+int omap_gem_tiled_stride(struct drm_gem_object *obj, uint32_t orient);
 
 struct dma_buf * omap_gem_prime_export(struct drm_device *dev,
                struct drm_gem_object *obj, int flags);
index 74260f043ab11f248958388fba070168288edf38..446801d63007d7621da0b1227178b4b47d955206 100644 (file)
@@ -18,6 +18,7 @@
  */
 
 #include "omap_drv.h"
+#include "omap_dmm_tiler.h"
 
 #include "drm_crtc.h"
 #include "drm_crtc_helper.h"
@@ -137,30 +138,100 @@ static const struct drm_framebuffer_funcs omap_framebuffer_funcs = {
        .dirty = omap_framebuffer_dirty,
 };
 
+static uint32_t get_linear_addr(struct plane *plane,
+               const struct format *format, int n, int x, int y)
+{
+       uint32_t offset;
+
+       offset = plane->offset +
+                       (x * format->planes[n].stride_bpp) +
+                       (y * plane->pitch / format->planes[n].sub_y);
+
+       return plane->paddr + offset;
+}
+
 /* update ovl info for scanout, handles cases of multi-planar fb's, etc.
  */
-void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, int x, int y,
-               struct omap_overlay_info *info)
+void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
+               struct omap_drm_window *win, struct omap_overlay_info *info)
 {
        struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
        const struct format *format = omap_fb->format;
        struct plane *plane = &omap_fb->planes[0];
-       unsigned int offset;
+       uint32_t x, y, orient = 0;
+
+       info->color_mode = format->dss_format;
+
+       info->pos_x      = win->crtc_x;
+       info->pos_y      = win->crtc_y;
+       info->out_width  = win->crtc_w;
+       info->out_height = win->crtc_h;
+       info->width      = win->src_w;
+       info->height     = win->src_h;
+
+       x = win->src_x;
+       y = win->src_y;
+
+       if (omap_gem_flags(plane->bo) & OMAP_BO_TILED) {
+               uint32_t w = win->src_w;
+               uint32_t h = win->src_h;
+
+               switch (win->rotation & 0xf) {
+               default:
+                       dev_err(fb->dev->dev, "invalid rotation: %02x",
+                                       (uint32_t)win->rotation);
+                       /* fallthru to default to no rotation */
+               case 0:
+               case BIT(DRM_ROTATE_0):
+                       orient = 0;
+                       break;
+               case BIT(DRM_ROTATE_90):
+                       orient = MASK_XY_FLIP | MASK_X_INVERT;
+                       break;
+               case BIT(DRM_ROTATE_180):
+                       orient = MASK_X_INVERT | MASK_Y_INVERT;
+                       break;
+               case BIT(DRM_ROTATE_270):
+                       orient = MASK_XY_FLIP | MASK_Y_INVERT;
+                       break;
+               }
 
-       offset = plane->offset +
-                       (x * format->planes[0].stride_bpp) +
-                       (y * plane->pitch / format->planes[0].sub_y);
+               if (win->rotation & BIT(DRM_REFLECT_X))
+                       orient ^= MASK_X_INVERT;
+
+               if (win->rotation & BIT(DRM_REFLECT_Y))
+                       orient ^= MASK_Y_INVERT;
+
+               /* adjust x,y offset for flip/invert: */
+               if (orient & MASK_XY_FLIP)
+                       swap(w, h);
+               if (orient & MASK_Y_INVERT)
+                       y += h - 1;
+               if (orient & MASK_X_INVERT)
+                       x += w - 1;
 
-       info->color_mode   = format->dss_format;
-       info->paddr        = plane->paddr + offset;
-       info->screen_width = plane->pitch / format->planes[0].stride_bpp;
+               omap_gem_rotated_paddr(plane->bo, orient, x, y, &info->paddr);
+               info->rotation_type = OMAP_DSS_ROT_TILER;
+               info->screen_width  = omap_gem_tiled_stride(plane->bo, orient);
+       } else {
+               info->paddr         = get_linear_addr(plane, format, 0, x, y);
+               info->rotation_type = OMAP_DSS_ROT_DMA;
+               info->screen_width  = plane->pitch;
+       }
+
+       /* convert to pixels: */
+       info->screen_width /= format->planes[0].stride_bpp;
 
        if (format->dss_format == OMAP_DSS_COLOR_NV12) {
                plane = &omap_fb->planes[1];
-               offset = plane->offset +
-                               (x * format->planes[1].stride_bpp) +
-                               (y * plane->pitch / format->planes[1].sub_y);
-               info->p_uv_addr = plane->paddr + offset;
+
+               if (info->rotation_type == OMAP_DSS_ROT_TILER) {
+                       WARN_ON(!(omap_gem_flags(plane->bo) & OMAP_BO_TILED));
+                       omap_gem_rotated_paddr(plane->bo, orient,
+                                       x/2, y/2, &info->p_uv_addr);
+               } else {
+                       info->p_uv_addr = get_linear_addr(plane, format, 1, x, y);
+               }
        } else {
                info->p_uv_addr = 0;
        }
@@ -377,7 +448,7 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
 
                size = pitch * mode_cmd->height / format->planes[i].sub_y;
 
-               if (size > (bos[i]->size - mode_cmd->offsets[i])) {
+               if (size > (omap_gem_mmap_size(bos[i]) - mode_cmd->offsets[i])) {
                        dev_err(dev->dev, "provided buffer object is too small! %d < %d\n",
                                        bos[i]->size - mode_cmd->offsets[i], size);
                        ret = -EINVAL;
index 3a0d035a9e037265f17f4f9e6addb12d524c455c..74082aa35589ee42572ae253d2920eddeeb899cf 100644 (file)
@@ -339,6 +339,17 @@ size_t omap_gem_mmap_size(struct drm_gem_object *obj)
        return size;
 }
 
+/* get tiled size, returns -EINVAL if not tiled buffer */
+int omap_gem_tiled_size(struct drm_gem_object *obj, uint16_t *w, uint16_t *h)
+{
+       struct omap_gem_object *omap_obj = to_omap_bo(obj);
+       if (omap_obj->flags & OMAP_BO_TILED) {
+               *w = omap_obj->width;
+               *h = omap_obj->height;
+               return 0;
+       }
+       return -EINVAL;
+}
 
 /* Normal handling for the case of faulting in non-tiled buffers */
 static int fault_1d(struct drm_gem_object *obj,
@@ -832,6 +843,36 @@ fail:
        return ret;
 }
 
+/* Get rotated scanout address (only valid if already pinned), at the
+ * specified orientation and x,y offset from top-left corner of buffer
+ * (only valid for tiled 2d buffers)
+ */
+int omap_gem_rotated_paddr(struct drm_gem_object *obj, uint32_t orient,
+               int x, int y, dma_addr_t *paddr)
+{
+       struct omap_gem_object *omap_obj = to_omap_bo(obj);
+       int ret = -EINVAL;
+
+       mutex_lock(&obj->dev->struct_mutex);
+       if ((omap_obj->paddr_cnt > 0) && omap_obj->block &&
+                       (omap_obj->flags & OMAP_BO_TILED)) {
+               *paddr = tiler_tsptr(omap_obj->block, orient, x, y);
+               ret = 0;
+       }
+       mutex_unlock(&obj->dev->struct_mutex);
+       return ret;
+}
+
+/* Get tiler stride for the buffer (only valid for 2d tiled buffers) */
+int omap_gem_tiled_stride(struct drm_gem_object *obj, uint32_t orient)
+{
+       struct omap_gem_object *omap_obj = to_omap_bo(obj);
+       int ret = -EINVAL;
+       if (omap_obj->flags & OMAP_BO_TILED)
+               ret = tiler_stride(gem2fmt(omap_obj->flags), orient);
+       return ret;
+}
+
 /* acquire pages when needed (for example, for DMA where physically
  * contiguous buffer is not required
  */
@@ -1402,7 +1443,7 @@ void omap_gem_init(struct drm_device *dev)
                 */
                usergart[i].height = h;
                usergart[i].height_shift = ilog2(h);
-               usergart[i].stride_pfn = tiler_stride(fmts[i]) >> PAGE_SHIFT;
+               usergart[i].stride_pfn = tiler_stride(fmts[i], 0) >> PAGE_SHIFT;
                usergart[i].slot_shift = ilog2((PAGE_SIZE / h) >> i);
                for (j = 0; j < NUM_USERGART_ENTRIES; j++) {
                        struct usergart_entry *entry = &usergart[i].entry[j];
index 7997be74010debcfbea1d8bf7ba5a4e16badafc5..4bde639dd02c21a95b06ba0636134634c74c7d99 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/kfifo.h>
 
 #include "omap_drv.h"
+#include "omap_dmm_tiler.h"
 
 /* some hackery because omapdss has an 'enum omap_plane' (which would be
  * better named omap_plane_id).. and compiler seems unhappy about having
@@ -43,10 +44,9 @@ struct omap_plane {
        struct omap_overlay *ovl;
        struct omap_overlay_info info;
 
-       /* Source values, converted to integers because we don't support
-        * fractional positions:
-        */
-       unsigned int src_x, src_y;
+       /* position/orientation of scanout within the fb: */
+       struct omap_drm_window win;
+
 
        /* last fb that we pinned: */
        struct drm_framebuffer *pinned_fb;
@@ -289,6 +289,7 @@ static void update_scanout(struct drm_plane *plane)
 {
        struct omap_plane *omap_plane = to_omap_plane(plane);
        struct omap_overlay_info *info = &omap_plane->info;
+       struct omap_drm_window *win = &omap_plane->win;
        int ret;
 
        ret = update_pin(plane, plane->fb);
@@ -299,11 +300,10 @@ static void update_scanout(struct drm_plane *plane)
                return;
        }
 
-       omap_framebuffer_update_scanout(plane->fb,
-                       omap_plane->src_x, omap_plane->src_y, info);
+       omap_framebuffer_update_scanout(plane->fb, win, info);
 
        DBG("%s: %d,%d: %08x %08x (%d)", omap_plane->ovl->name,
-                       omap_plane->src_x, omap_plane->src_y,
+                       win->src_x, win->src_y,
                        (u32)info->paddr, (u32)info->p_uv_addr,
                        info->screen_width);
 }
@@ -316,21 +316,18 @@ int omap_plane_mode_set(struct drm_plane *plane,
                uint32_t src_w, uint32_t src_h)
 {
        struct omap_plane *omap_plane = to_omap_plane(plane);
+       struct omap_drm_window *win = &omap_plane->win;
+
+       win->crtc_x = crtc_x;
+       win->crtc_y = crtc_y;
+       win->crtc_w = crtc_w;
+       win->crtc_h = crtc_h;
 
        /* src values are in Q16 fixed point, convert to integer: */
-       src_x = src_x >> 16;
-       src_y = src_y >> 16;
-       src_w = src_w >> 16;
-       src_h = src_h >> 16;
-
-       omap_plane->info.pos_x = crtc_x;
-       omap_plane->info.pos_y = crtc_y;
-       omap_plane->info.out_width = crtc_w;
-       omap_plane->info.out_height = crtc_h;
-       omap_plane->info.width = src_w;
-       omap_plane->info.height = src_h;
-       omap_plane->src_x = src_x;
-       omap_plane->src_y = src_y;
+       win->src_x = src_x >> 16;
+       win->src_y = src_y >> 16;
+       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
@@ -359,6 +356,8 @@ static int omap_plane_update(struct drm_plane *plane,
 
 static int omap_plane_disable(struct drm_plane *plane)
 {
+       struct omap_plane *omap_plane = to_omap_plane(plane);
+       omap_plane->win.rotation = BIT(DRM_ROTATE_0);
        return omap_plane_dpms(plane, DRM_MODE_DPMS_OFF);
 }
 
@@ -409,10 +408,79 @@ void omap_plane_on_endwin(struct drm_plane *plane,
        install_irq(plane);
 }
 
+/* helper to install properties which are common to planes and crtcs */
+void omap_plane_install_properties(struct drm_plane *plane,
+               struct drm_mode_object *obj)
+{
+       struct drm_device *dev = plane->dev;
+       struct omap_drm_private *priv = dev->dev_private;
+       struct drm_property *prop;
+
+       prop = priv->rotation_prop;
+       if (!prop) {
+               const struct drm_prop_enum_list props[] = {
+                               { DRM_ROTATE_0,   "rotate-0" },
+                               { DRM_ROTATE_90,  "rotate-90" },
+                               { DRM_ROTATE_180, "rotate-180" },
+                               { DRM_ROTATE_270, "rotate-270" },
+                               { DRM_REFLECT_X,  "reflect-x" },
+                               { DRM_REFLECT_Y,  "reflect-y" },
+               };
+               prop = drm_property_create_bitmask(dev, 0, "rotation",
+                               props, ARRAY_SIZE(props));
+               if (prop == NULL)
+                       return;
+               priv->rotation_prop = prop;
+       }
+       drm_object_attach_property(obj, prop, 0);
+
+        prop = priv->zorder_prop;
+        if (!prop) {
+               prop = drm_property_create_range(dev, 0, "zorder", 0, 3);
+               if (prop == NULL)
+                       return;
+               priv->zorder_prop = prop;
+       }
+       drm_object_attach_property(obj, prop, 0);
+}
+
+int omap_plane_set_property(struct drm_plane *plane,
+               struct drm_property *property, uint64_t val)
+{
+       struct omap_plane *omap_plane = to_omap_plane(plane);
+       struct omap_drm_private *priv = plane->dev->dev_private;
+       int ret = -EINVAL;
+
+       if (property == priv->rotation_prop) {
+               struct omap_overlay *ovl = omap_plane->ovl;
+
+               DBG("%s: rotation: %02x", ovl->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;
+       } else if (property == priv->zorder_prop) {
+               struct omap_overlay *ovl = omap_plane->ovl;
+
+               DBG("%s: zorder: %d", ovl->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;
+       }
+
+       return ret;
+}
+
 static const struct drm_plane_funcs omap_plane_funcs = {
                .update_plane = omap_plane_update,
                .disable_plane = omap_plane_disable,
                .destroy = omap_plane_destroy,
+               .set_property = omap_plane_set_property,
 };
 
 /* initialize plane */
@@ -455,6 +523,8 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
        drm_plane_init(dev, plane, possible_crtcs, &omap_plane_funcs,
                        omap_plane->formats, omap_plane->nformats, priv);
 
+       omap_plane_install_properties(plane, &plane->base);
+
        /* get our starting configuration, set defaults for parameters
         * we don't currently use, etc:
         */
@@ -463,7 +533,6 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
        omap_plane->info.rotation = OMAP_DSS_ROT_0;
        omap_plane->info.global_alpha = 0xff;
        omap_plane->info.mirror = 0;
-       omap_plane->info.mirror = 0;
 
        /* Set defaults depending on whether we are a CRTC or overlay
         * layer.
index 251f07c39a6bdbaa35f63a355a8ba268edf81b2a..76821cb6d25f5afe0e38a60a55b4561d0d20dc0b 100644 (file)
@@ -414,6 +414,44 @@ static void oz_ep_free(struct oz_port *port, struct oz_endpoint *ep)
        oz_trace("Freeing endpoint memory\n");
        kfree(ep);
 }
+/*------------------------------------------------------------------------------
+ * Context: softirq
+ */
+void oz_complete_buffered_urb(struct oz_port *port, struct oz_endpoint *ep,
+                       struct urb *urb)
+{
+       u8 data_len, available_space, copy_len;
+
+       memcpy(&data_len, &ep->buffer[ep->out_ix], sizeof(u8));
+       if (data_len <= urb->transfer_buffer_length)
+               available_space = data_len;
+       else
+               available_space = urb->transfer_buffer_length;
+
+       if (++ep->out_ix == ep->buffer_size)
+               ep->out_ix = 0;
+       copy_len = ep->buffer_size - ep->out_ix;
+       if (copy_len >= available_space)
+               copy_len = available_space;
+       memcpy(urb->transfer_buffer, &ep->buffer[ep->out_ix], copy_len);
+
+       if (copy_len < available_space) {
+               memcpy((urb->transfer_buffer + copy_len), ep->buffer,
+                                               (available_space - copy_len));
+               ep->out_ix = available_space - copy_len;
+       } else {
+               ep->out_ix += copy_len;
+       }
+       urb->actual_length = available_space;
+       if (ep->out_ix == ep->buffer_size)
+               ep->out_ix = 0;
+
+       ep->buffered_units--;
+       oz_trace("Trying to give back buffered frame of size=%d\n",
+                                               available_space);
+       oz_complete_urb(port->ozhcd->hcd, urb, 0, 0);
+}
+
 /*------------------------------------------------------------------------------
  * Context: softirq
  */
@@ -452,6 +490,18 @@ static int oz_enqueue_ep_urb(struct oz_port *port, u8 ep_addr, int in_dir,
                ep = port->in_ep[ep_addr];
        else
                ep = port->out_ep[ep_addr];
+
+       /*For interrupt endpoint check for buffered data
+       * & complete urb
+       */
+       if (((ep->attrib & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)
+                                                && ep->buffered_units > 0) {
+               oz_free_urb_link(urbl);
+               spin_unlock_bh(&port->ozhcd->hcd_lock);
+               oz_complete_buffered_urb(port, ep, urb);
+               return 0;
+       }
+
        if (ep && port->hpd) {
                list_add_tail(&urbl->link, &ep->urb_list);
                if (!in_dir && ep_addr && (ep->credit < 0)) {
@@ -883,13 +933,14 @@ void oz_hcd_control_cnf(void *hport, u8 req_id, u8 rcode, u8 *data,
        } else {
                int copy_len;
                oz_trace("VENDOR-CLASS - cnf\n");
-               if (data_len <= urb->transfer_buffer_length)
-                       copy_len = data_len;
-               else
-                       copy_len = urb->transfer_buffer_length;
-               if (copy_len)
+               if (data_len) {
+                       if (data_len <= urb->transfer_buffer_length)
+                               copy_len = data_len;
+                       else
+                               copy_len = urb->transfer_buffer_length;
                        memcpy(urb->transfer_buffer, data, copy_len);
-               urb->actual_length = copy_len;
+                       urb->actual_length = copy_len;
+               }
                oz_complete_urb(hcd, urb, 0, 0);
        }
 }
@@ -961,6 +1012,9 @@ void oz_hcd_data_ind(void *hport, u8 endpoint, u8 *data, int data_len)
                        urb->actual_length = copy_len;
                        oz_complete_urb(port->ozhcd->hcd, urb, 0, 0);
                        return;
+               } else {
+                       oz_trace("buffering frame as URB is not available\n");
+                       oz_hcd_buffer_data(ep, data, data_len);
                }
                break;
        case USB_ENDPOINT_XFER_ISOC:
@@ -1000,7 +1054,7 @@ int oz_hcd_heartbeat(void *hport)
                ep = ep_from_link(e);
                if (ep->credit < 0)
                        continue;
-               ep->credit += (now - ep->last_jiffies);
+               ep->credit += jiffies_to_msecs(now - ep->last_jiffies);
                if (ep->credit > ep->credit_ceiling)
                        ep->credit = ep->credit_ceiling;
                oz_event_log(OZ_EVT_EP_CREDIT, ep->ep_num, 0, 0, ep->credit);
@@ -1009,7 +1063,7 @@ int oz_hcd_heartbeat(void *hport)
                        urbl = list_first_entry(&ep->urb_list,
                                struct oz_urb_link, link);
                        urb = urbl->urb;
-                       if (ep->credit < urb->number_of_packets)
+                       if ((ep->credit + 1) < urb->number_of_packets)
                                break;
                        ep->credit -= urb->number_of_packets;
                        oz_event_log(OZ_EVT_EP_CREDIT, ep->ep_num, 0, 0,
@@ -1052,7 +1106,7 @@ int oz_hcd_heartbeat(void *hport)
                        }
                        continue;
                }
-               ep->credit += (now - ep->last_jiffies);
+               ep->credit += jiffies_to_msecs(now - ep->last_jiffies);
                oz_event_log(OZ_EVT_EP_CREDIT, ep->ep_num | USB_DIR_IN,
                        0, 0, ep->credit);
                ep->last_jiffies = now;
@@ -1064,7 +1118,7 @@ int oz_hcd_heartbeat(void *hport)
                        int len = 0;
                        int copy_len;
                        int i;
-                       if (ep->credit < urb->number_of_packets)
+                       if ((ep->credit + 1) < urb->number_of_packets)
                                break;
                        if (ep->buffered_units < urb->number_of_packets)
                                break;
@@ -1167,10 +1221,16 @@ static int oz_build_endpoints_for_interface(struct usb_hcd *hcd,
                int buffer_size = 0;
 
                oz_trace("%d bEndpointAddress = %x\n", i, ep_addr);
-               if ((ep_addr & USB_ENDPOINT_DIR_MASK) &&
-                       ((hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-                       == USB_ENDPOINT_XFER_ISOC)) {
-                       buffer_size = 24*1024;
+               if (ep_addr & USB_ENDPOINT_DIR_MASK) {
+                       switch (hep->desc.bmAttributes &
+                                               USB_ENDPOINT_XFERTYPE_MASK) {
+                       case USB_ENDPOINT_XFER_ISOC:
+                               buffer_size = 24*1024;
+                               break;
+                       case USB_ENDPOINT_XFER_INT:
+                               buffer_size = 128;
+                               break;
+                       }
                }
 
                ep = oz_ep_alloc(mem_flags, buffer_size);
@@ -1458,6 +1518,7 @@ static void oz_process_ep0_urb(struct oz_hcd *ozhcd, struct urb *urb,
                int data_len = 0;
                if ((setup->bRequestType & USB_DIR_IN) == 0)
                        data_len = wlength;
+               urb->actual_length = data_len;
                if (oz_usb_control_req(port->hpd, req_id, setup,
                                urb->transfer_buffer, data_len)) {
                        rc = -ENOMEM;
index c1ed6b2522ec6708c9019d2bee96d478feef7c9f..ef6c5ab753ee4dc9049ccd5d399f8c22c2d86c7d 100644 (file)
@@ -59,6 +59,6 @@ module_exit(ozwpan_exit);
 
 MODULE_AUTHOR("Chris Kelly");
 MODULE_DESCRIPTION("Ozmo Devices USB over WiFi hcd driver");
-MODULE_VERSION("1.0.10");
+MODULE_VERSION("1.0.13");
 MODULE_LICENSE("GPL");
 
index 6c287ac6eaeafba2d04529076736ad542e582f0b..f546b5aee8690b06928ac691a57fb0c2082da44f 100644 (file)
 /*------------------------------------------------------------------------------
  */
 #define OZ_MAX_TX_POOL_SIZE    6
-/* Maximum number of uncompleted isoc frames that can be pending in network.
- */
-#define OZ_MAX_SUBMITTED_ISOC  16
-/* Maximum number of uncompleted isoc frames that can be pending in Tx Queue.
- */
-#define OZ_MAX_TX_QUEUE_ISOC   32
 /*------------------------------------------------------------------------------
  */
 static struct oz_tx_frame *oz_tx_frame_alloc(struct oz_pd *pd);
@@ -854,7 +848,7 @@ int oz_send_isoc_unit(struct oz_pd *pd, u8 ep_num, u8 *data, int len)
                if (!(pd->mode & OZ_F_ISOC_ANYTIME)) {
                        struct oz_tx_frame *isoc_unit = NULL;
                        int nb = pd->nb_queued_isoc_frames;
-                       if (nb >= OZ_MAX_TX_QUEUE_ISOC) {
+                       if (nb >= pd->isoc_latency) {
                                oz_trace2(OZ_TRACE_TX_FRAMES,
                                                "Dropping ISOC Unit nb= %d\n",
                                                                        nb);
index ddf1341b4e674a9f538cc9ea0de0b52dc3fc9cf6..d35b0ea44f67b844485a9cf795aa66b142c81945 100644 (file)
@@ -82,6 +82,7 @@ struct oz_pd {
        u8              heartbeat_requested;
        u8              mode;
        u8              ms_per_isoc;
+       unsigned        isoc_latency;
        unsigned        max_stream_buffering;
        int             nb_queued_frames;
        int             nb_queued_isoc_frames;
index a50ab18a598795a001f3fa808842f0a2c5ab8dc9..cfb5160d1ebedbdbd24ca95f02418c2258feb250 100644 (file)
@@ -220,6 +220,19 @@ static struct oz_pd *oz_connect_req(struct oz_pd *cur_pd, struct oz_elt *elt,
                pd->ms_per_isoc = body->ms_per_isoc;
                if (!pd->ms_per_isoc)
                        pd->ms_per_isoc = 4;
+
+               switch (body->ms_isoc_latency & OZ_LATENCY_MASK) {
+               case OZ_ONE_MS_LATENCY:
+                       pd->isoc_latency = (body->ms_isoc_latency &
+                                       ~OZ_LATENCY_MASK) / pd->ms_per_isoc;
+                       break;
+               case OZ_TEN_MS_LATENCY:
+                       pd->isoc_latency = ((body->ms_isoc_latency &
+                               ~OZ_LATENCY_MASK) * 10) / pd->ms_per_isoc;
+                       break;
+               default:
+                       pd->isoc_latency = OZ_MAX_TX_QUEUE_ISOC;
+               }
        }
        if (body->max_len_div16)
                pd->max_tx_size = ((u16)body->max_len_div16)<<4;
index 89aea28bd8d54ccd93d5661bb672d329ae91d6e5..755a08d0e1ca05436ee911262b3a41b4ac55da9d 100644 (file)
@@ -14,7 +14,7 @@
 
 /* Converts millisecs to jiffies.
  */
-#define oz_ms_to_jiffies(__x)  (((__x)*1000)/HZ)
+#define oz_ms_to_jiffies(__x)  msecs_to_jiffies(__x)
 
 /* Quantum milliseconds.
  */
 /* Maximun sizes of tx frames. */
 #define OZ_MAX_TX_SIZE         1514
 
+/* Maximum number of uncompleted isoc frames that can be pending in network. */
+#define OZ_MAX_SUBMITTED_ISOC  16
+
+/* Maximum number of uncompleted isoc frames that can be pending in Tx Queue. */
+#define OZ_MAX_TX_QUEUE_ISOC   32
+
 /* Application handler functions.
  */
 typedef int (*oz_app_init_fn_t)(void);
index 1e4edbeb61cde6f58f79557a4253ce459eb37a65..17b09b9a5b0869b0442cbc14995ac6cfa6c7fdf4 100644 (file)
@@ -65,6 +65,10 @@ struct oz_hdr {
 
 #define OZ_LAST_PN_HALF_CYCLE  127
 
+#define OZ_LATENCY_MASK                0xc0
+#define OZ_ONE_MS_LATENCY      0x40
+#define OZ_TEN_MS_LATENCY      0x80
+
 /* Connect request data structure.
  */
 struct oz_elt_connect_req {
@@ -73,7 +77,7 @@ struct oz_elt_connect_req {
        u8      pd_info;
        u8      session_id;
        u8      presleep;
-       u8      resv2;
+       u8      ms_isoc_latency;
        u8      host_vendor;
        u8      keep_alive;
        u16     apps;
index 39f9982c2708ccd3ca1e36bdfd13a53ef92fa51f..d9fec5b3faac20e1f63425dac32a6e6ca77adc33 100644 (file)
 #define r_ctr(x)        (parport_read_control((x)->port))
 #define r_dtr(x)        (parport_read_data((x)->port))
 #define r_str(x)        (parport_read_status((x)->port))
-#define w_ctr(x, y)     do { parport_write_control((x)->port, (y)); } while (0)
-#define w_dtr(x, y)     do { parport_write_data((x)->port, (y)); } while (0)
+#define w_ctr(x, y)     (parport_write_control((x)->port, (y)))
+#define w_dtr(x, y)     (parport_write_data((x)->port, (y)))
 
 /* this defines which bits are to be used and which ones to be ignored */
 /* logical or of the output bits involved in the scan matrix */
index b94c48b29302cdee3a712e976017dab4173d229f..5f5a30223d56546b16eb4820e98be47633be52b4 100644 (file)
@@ -1094,7 +1094,7 @@ struct ieee80211_device {
 
        int (*reset_port)(struct net_device *dev);
 
-       /* Softmac-generated frames (mamagement) are TXed via this
+       /* Softmac-generated frames (management) are TXed via this
         * callback if the flag IEEE_SOFTMAC_SINGLE_QUEUE is
         * not set. As some cards may have different HW queues that
         * one might want to use for data and management frames
index fd22b75aea4f1b549bf990ed6ea94371d8efd013..20e5fb58f52f101981413b6cbaafa7d4cb682701 100644 (file)
@@ -2377,7 +2377,7 @@ void rtl8180_wmm_param_update(struct work_struct *work)
                                u8              u1bAIFS;
                                u32             u4bAcParam;
                                pAcParam = (PAC_PARAM)(&AcParam);
-                               /* Retrieve paramters to update. */
+                               /* Retrieve parameters to update. */
                                u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * (((mode&IEEE_G) == IEEE_G) ? 9 : 20) + aSifsTime;
                                u4bAcParam = ((((u32)(pAcParam->f.TXOPLimit))<<AC_PARAM_TXOP_LIMIT_OFFSET)|
                                              (((u32)(pAcParam->f.Ecw.f.ECWmax))<<AC_PARAM_ECW_MAX_OFFSET)|
@@ -2413,7 +2413,7 @@ void rtl8180_wmm_param_update(struct work_struct *work)
                        u8              u1bAIFS;
                        u32             u4bAcParam;
 
-                       /* Retrieve paramters to update. */
+                       /* Retrieve parameters to update. */
                        eACI = pAcParam->f.AciAifsn.f.ACI;
                        /* Mode G/A: slotTimeTimer = 9; Mode B: 20 */
                        u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * (((mode&IEEE_G) == IEEE_G) ? 9 : 20) + aSifsTime;
index 3fca144a56a42eeedf126076a10ac0870798875b..533938123a9767a81e3ad637572fd0bd8cbcdf06 100644 (file)
 /* by amy for power save               */
 /* by amy for antenna                  */
 #define EEPROM_SW_REVD_OFFSET 0x3f
-/*  BIT[8-9] is for SW Antenna Diversity. Only the value EEPROM_SW_AD_ENABLE means enable, other values are diable.                                    */
+
+/*  BIT[8-9] is for SW Antenna Diversity. 
+ *  Only the value EEPROM_SW_AD_ENABLE means enable, other values are disable.
+ */
 #define EEPROM_SW_AD_MASK                      0x0300
 #define EEPROM_SW_AD_ENABLE                    0x0100
 
-/* BIT[10-11] determine if Antenna 1 is the Default Antenna. Only the value EEPROM_DEF_ANT_1 means TRUE, other values are FALSE.       */
+/* BIT[10-11] determine if Antenna 1 is the Default Antenna.
+ * Only the value EEPROM_DEF_ANT_1 means TRUE, other values are FALSE. 
+ */
 #define EEPROM_DEF_ANT_MASK                    0x0C00
 #define EEPROM_DEF_ANT_1                       0x0400
 /*by amy for antenna                                                                                                                                                           */
index 914495783c06e2c23362d7137fec6cd9b55b3d1a..bf343199bd21f4a932c79932531aed1aaa38302b 100644 (file)
@@ -1008,7 +1008,7 @@ void ActUpdateChannelAccessSetting(struct net_device *dev,
                                u8              u1bAIFS;
                                u32             u4bAcParam;
 
-                               /*  Retrieve paramters to update. */
+                               /*  Retrieve parameters to update. */
                                eACI = pAcParam->f.AciAifsn.f.ACI;
                                u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * ChnlAccessSetting->SlotTimeTimer + aSifsTime;
                                u4bAcParam = ((((u32)(pAcParam->f.TXOPLimit)) << AC_PARAM_TXOP_LIMIT_OFFSET)    |
index b526fa428679aa58e125c0bcb4d5afbe2c42d123..dd2a96bfcc0c00126d0b2bab5e6e797859f8dcbe 100644 (file)
@@ -265,10 +265,11 @@ bool init_firmware(struct net_device *dev)
                        case FW_SOURCE_IMG_FILE:
                        {
                                if (pfirmware->firmware_buf_size[init_step] == 0) {
-                                       const char *fw_name[3] = { "RTL8192E/boot.img",
-                                                          "RTL8192E/main.img",
-                                                          "RTL8192E/data.img"
-                                                        };
+                                       const char *fw_name[3] = {
+                                                       RTL8192E_BOOT_IMG_FW,
+                                                       RTL8192E_MAIN_IMG_FW,
+                                                       RTL8192E_DATA_IMG_FW
+                                       };
                                        const struct firmware   *fw_entry;
                                        int rc;
                                        rc = request_firmware(&fw_entry,
index caa878833106d683ac03ec3dd9b30c672e7e9975..06d6abc8345ceea9f8d1fc0b5af3866a3726a356 100644 (file)
 
 #define GET_COMMAND_PACKET_FRAG_THRESHOLD(v)   (4*(v/4) - 8)
 
+#define RTL8192E_BOOT_IMG_FW   "RTL8192E/boot.img"
+#define RTL8192E_MAIN_IMG_FW   "RTL8192E/main.img"
+#define RTL8192E_DATA_IMG_FW   "RTL8192E/data.img"
+
 enum firmware_init_step {
        FW_INIT_STEP0_BOOT = 0,
        FW_INIT_STEP1_MAIN = 1,
index 4f602b227b5070196261e5fb1d6b25b89d5d5e54..42e5c5c495e0164cccadb0de18b48b4d4e24d022 100644 (file)
@@ -3125,6 +3125,9 @@ MODULE_DESCRIPTION("Linux driver for Realtek RTL819x WiFi cards");
 MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
 MODULE_VERSION(DRV_VERSION);
 MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(RTL8192E_BOOT_IMG_FW);
+MODULE_FIRMWARE(RTL8192E_MAIN_IMG_FW);
+MODULE_FIRMWARE(RTL8192E_DATA_IMG_FW);
 
 module_param(ifname, charp, S_IRUGO|S_IWUSR);
 module_param(hwwep, int, S_IRUGO|S_IWUSR);
index 481b1e4d49136ef6e57580537f8c84fc49bc7016..1853665764a019d9777a615e3ae10d7683ec9c5d 100644 (file)
@@ -202,7 +202,7 @@ static void dm_check_ac_dc_power(struct net_device *dev)
 
        if (priv->ResetProgress == RESET_TYPE_SILENT) {
                RT_TRACE((COMP_INIT | COMP_POWER | COMP_RF),
-                        "GPIOChangeRFWorkItemCallBack(): Silent Reseting!!!!!!!\n");
+                        "GPIOChangeRFWorkItemCallBack(): Silent Reset!!!!!!!\n");
                return;
        }
 
index d7460ae3a7653488d0f27faac1626fa20ffb9744..9ac8d8ea4ae8d6841f6861b77e8dab2c3ccc5821 100644 (file)
@@ -2397,12 +2397,12 @@ struct rtllib_device {
                                 struct rtllib_network *network, u16 type);
        int (*is_qos_active)(struct net_device *dev, struct sk_buff *skb);
 
-       /* Softmac-generated frames (mamagement) are TXed via this
+       /* Softmac-generated frames (management) are TXed via this
         * callback if the flag IEEE_SOFTMAC_SINGLE_QUEUE is
         * not set. As some cards may have different HW queues that
         * one might want to use for data and management frames
         * the option to have two callbacks might be useful.
-        * This fucntion can't sleep.
+        * This function can't sleep.
         */
        int (*softmac_hard_start_xmit)(struct sk_buff *skb,
                               struct net_device *dev);
@@ -2441,9 +2441,9 @@ struct rtllib_device {
         * it is called in a work_queue when switching to ad-hoc mode
         * or in behalf of iwlist scan when the card is associated
         * and root user ask for a scan.
-        * the fucntion stop_scan should stop both the syncro and
+        * the function stop_scan should stop both the syncro and
         * background scanning and can sleep.
-        * The fucntion start_scan should initiate the background
+        * The function start_scan should initiate the background
         * scanning and can't sleep.
         */
        void (*scan_syncro)(struct net_device *dev);
index a21b4d91a5966a1579b063d6d192c5b0558c095f..7c95518fb3121ca80d1cb4f1c2bf1309d49d83be 100644 (file)
@@ -1687,7 +1687,7 @@ inline void rtllib_softmac_new_net(struct rtllib_device *ieee,
                 * if the network does broadcast and the user did set essid
                 * check if essid match
                 * if the ap is not set, check that the user set the bssid
-                * and the network does bradcast and that those two bssid match
+                * and the network does broadcast and that those two bssid match
                 */
                if ((apset && apmatch &&
                   ((ssidset && ssidbroad && ssidmatch) ||
@@ -2442,7 +2442,7 @@ inline int rtllib_rx_frame_softmac(struct rtllib_device *ieee,
        return 0;
 }
 
-/* following are for a simplier TX queue management.
+/* following are for a simpler TX queue management.
  * Instead of using netif_[stop/wake]_queue the driver
  * will use these two functions (plus a reset one), that
  * will internally use the kernel netif_* and takes
index 1c0a1db6420f06d1e5a505f37675d9895e9df64f..13f45c3125cea39dca829cb45d8400111b502de0 100644 (file)
@@ -2114,7 +2114,7 @@ struct ieee80211_device {
                                   struct ieee80211_network * network, u16 type);
         int (*is_qos_active) (struct net_device *dev, struct sk_buff *skb);
 
-       /* Softmac-generated frames (mamagement) are TXed via this
+       /* Softmac-generated frames (management) are TXed via this
         * callback if the flag IEEE_SOFTMAC_SINGLE_QUEUE is
         * not set. As some cards may have different HW queues that
         * one might want to use for data and management frames
@@ -2192,7 +2192,7 @@ struct ieee80211_device {
        int (*handle_assoc_response) (struct net_device * dev, struct ieee80211_assoc_response_frame * resp, struct ieee80211_network * network);
 
 
-       /* check whether Tx hw resouce available */
+       /* check whether Tx hw resource available */
        short (*check_nic_enough_desc)(struct net_device *dev, int queue_index);
        //added by wb for HT related
 //     void (*SwChnlByTimerHandler)(struct net_device *dev, int channel);
index f6ff8cff313a40e739c860df27d1c1fa806716b4..a6adfc91629129e0d44dccc55c8367840fbf7e4e 100644 (file)
@@ -1448,7 +1448,7 @@ inline void ieee80211_softmac_new_net(struct ieee80211_device *ieee, struct ieee
                        ( apset && apmatch &&
                                ((ssidset && ssidbroad && ssidmatch) || (ssidbroad && !ssidset) || (!ssidbroad && ssidset)) ) ||
                        /* if the ap is not set, check that the user set the bssid
-                        * and the network does bradcast and that those two bssid matches
+                        * and the network does broadcast and that those two bssid matches
                         */
                        (!apset && ssidset && ssidbroad && ssidmatch)
                        ){
@@ -2520,7 +2520,7 @@ void ieee80211_associate_retry_wq(struct work_struct *work)
 
        /* until we do not set the state to IEEE80211_NOLINK
        * there are no possibility to have someone else trying
-       * to start an association procdure (we get here with
+       * to start an association procedure (we get here with
        * ieee->state = IEEE80211_ASSOCIATING).
        * When we set the state to IEEE80211_NOLINK it is possible
        * that the RX path run an attempt to associate, but
index 27d083a70eb2d7c7ed0f326d4a9d8a06c8dee1a3..1ebea3daea2dbad2cd4a114528bba9fa6bd75159 100644 (file)
@@ -1,6 +1,6 @@
 /********************************************************************************************************************************
  * This file is created to process BA Action Frame. According to 802.11 spec, there are 3 BA action types at all. And as BA is
- * related to TS, this part need some struture defined in QOS side code. Also TX RX is going to be resturctured, so how to send
+ * related to TS, this part need some structure defined in QOS side code. Also TX RX is going to be resturctured, so how to send
  * ADDBAREQ ADDBARSP and DELBA packet is still on consideration. Temporarily use MANAGE QUEUE instead of Normal Queue.
  * WB 2008-05-27
  * *****************************************************************************************************************************/
index 0b1a1fc093918c9368d287fd0150ecef230c0b03..a60b39cdb4723c1972220dfe4a6e6d541517ffaf 100644 (file)
@@ -15,7 +15,7 @@
 #define HT_OPMODE_MIXED                        3
 
 //
-// MIMO Power Save Setings
+// MIMO Power Save Settings
 //
 #define MIMO_PS_STATIC                         0
 #define MIMO_PS_DYNAMIC                        1
@@ -242,7 +242,7 @@ typedef struct _RT_HIGH_THROUGHPUT{
        u8                              bEnableHT;
        u8                              bCurrentHTSupport;
 
-       u8                              bRegBW40MHz;                            // Tx 40MHz channel capablity
+       u8                              bRegBW40MHz;                            // Tx 40MHz channel capability
        u8                              bCurBW40MHz;                            // Tx 40MHz channel capability
 
        u8                              bRegShortGI40MHz;                       // Tx Short GI for 40Mhz
index e88a839b2a91753af3ead5b78b5608e4dd0b2752..ebb523904edc1ce527113995e2e1ee4c85253246 100644 (file)
@@ -912,7 +912,7 @@ u8 HTFilterMCSRate( struct ieee80211_device* ieee, u8* pSupportMCS, u8* pOperate
 
        u8 i=0;
 
-       // filter out operational rate set not supported by AP, the lenth of it is 16
+       // filter out operational rate set not supported by AP, the length of it is 16
        for(i=0;i<=15;i++){
                pOperateMCS[i] = ieee->Regdot11HTOperationalRateSet[i]&pSupportMCS[i];
        }
index e07f8b17a0d6fc9869e06703ca782cf960df68ef..6c1d05e1e820eefb866e23af03e4a04a10f1a348 100644 (file)
@@ -16,7 +16,7 @@
 #define HT_OPMODE_MIXED                        3
 
 //
-// MIMO Power Save Setings
+// MIMO Power Save Settings
 //
 #define MIMO_PS_STATIC                         0
 #define MIMO_PS_DYNAMIC                        1
index 50f24dce8b16771cd56ca3cfe9956453fc199536..cca34c05f6a597c0e7fd6777330b53ebdf208052 100644 (file)
 #define bCCKRxIG                                       0x7f00
 #define bCCKLNAPolarity                        0x800000
 #define bCCKRx1stGain                          0x7f0000
-#define bCCKRFExtend                           0x20000000 //CCK Rx inital gain polarity
+#define bCCKRFExtend                           0x20000000 //CCK Rx initial gain polarity
 #define bCCKRxAGCSatLevel                      0x1f000000
 #define bCCKRxAGCSatCount                      0xe0
 #define bCCKRxRFSettle                         0x1f       //AGCsamp_dly
index 8efbd1fa035f24e2220314471d0e40115add383e..fd9e3fc4c226d5986a7b13715b9ae631b2c4df73 100644 (file)
@@ -41,7 +41,7 @@
 #define RECV_BLK_SZ 512
 #define RECV_BLK_CNT 16
 #define RECV_BLK_TH RECV_BLK_CNT
-#define MAX_RECVBUF_SZ (30720) /* 30K */
+#define MAX_RECVBUF_SZ 9100
 #define RECVBUFF_ALIGN_SZ 512
 #define RSVD_ROOM_SZ (0)
 /*These definition is used for Rx packet reordering.*/
index 0584b8ab43ca381176bce3553ea49ff2cd2b9d72..c9dfb1ea4115794f5222508089afa11a1943a9f1 100644 (file)
@@ -93,35 +93,9 @@ do {                                                                 \
 #endif
 
 #ifdef CONFIG_RTS5139_DEBUG
-static inline void rts51x_dump(u8 *buf, int buf_len)
-{
-       int i;
-       u8 tmp[16] = { 0 };
-       u8 *_ptr = buf;
-
-       for (i = 0; i < ((buf_len) / 16); i++) {
-               RTS51X_DEBUGP("%02x %02x %02x %02x %02x %02x %02x %02x "
-                              "%02x %02x %02x %02x %02x %02x %02x %02x\n",
-                              _ptr[0], _ptr[1], _ptr[2], _ptr[3], _ptr[4],
-                              _ptr[5], _ptr[6], _ptr[7], _ptr[8], _ptr[9],
-                              _ptr[10], _ptr[11], _ptr[12], _ptr[13], _ptr[14],
-                              _ptr[15]);
-               _ptr += 16;
-       }
-       if ((buf_len) % 16) {
-               memcpy(tmp, _ptr, (buf_len) % 16);
-               _ptr = tmp;
-               RTS51X_DEBUGP("%02x %02x %02x %02x %02x %02x %02x %02x "
-                              "%02x %02x %02x %02x %02x %02x %02x %02x\n",
-                              _ptr[0], _ptr[1], _ptr[2], _ptr[3], _ptr[4],
-                              _ptr[5], _ptr[6], _ptr[7], _ptr[8], _ptr[9],
-                              _ptr[10], _ptr[11], _ptr[12], _ptr[13], _ptr[14],
-                              _ptr[15]);
-       }
-}
-
-#define RTS51X_DUMP(buf, buf_len)      \
-               rts51x_dump((u8 *)(buf), (buf_len))
+#define RTS51X_DUMP(buf, buf_len)                                      \
+       print_hex_dump(KERN_DEBUG, RTS51X_TIP, DUMP_PREFIX_NONE,        \
+                               16, 1, (buf), (buf_len), false)
 
 #define CATCH_TRIGGER(chip)                                    \
 do {                                                           \
index bc83b49a4eb4a975cdc286c484b08e4d4698a39e..cf60a1b872b3224cce1d56add6b9db984b173771 100644 (file)
@@ -83,33 +83,9 @@ do {                                                                                                 \
 #endif
 
 #ifdef CONFIG_RTS_PSTOR_DEBUG
-static inline void rtsx_dump(u8 *buf, int buf_len)
-{
-       int i;
-       u8 tmp[16] = {0};
-       u8 *_ptr = buf;
-
-       for (i = 0; i < ((buf_len)/16); i++) {
-               RTSX_DEBUGP("%02x %02x %02x %02x %02x %02x %02x %02x "
-                       "%02x %02x %02x %02x %02x %02x %02x %02x\n",
-                       _ptr[0], _ptr[1], _ptr[2], _ptr[3], _ptr[4], _ptr[5],
-                       _ptr[6], _ptr[7], _ptr[8], _ptr[9], _ptr[10], _ptr[11],
-                       _ptr[12], _ptr[13], _ptr[14], _ptr[15]);
-               _ptr += 16;
-       }
-       if ((buf_len) % 16) {
-               memcpy(tmp, _ptr, (buf_len) % 16);
-               _ptr = tmp;
-               RTSX_DEBUGP("%02x %02x %02x %02x %02x %02x %02x %02x "
-                       "%02x %02x %02x %02x %02x %02x %02x %02x\n",
-                       _ptr[0], _ptr[1], _ptr[2], _ptr[3], _ptr[4], _ptr[5],
-                       _ptr[6], _ptr[7], _ptr[8], _ptr[9], _ptr[10], _ptr[11],
-                       _ptr[12], _ptr[13], _ptr[14], _ptr[15]);
-       }
-}
-
-#define RTSX_DUMP(buf, buf_len)                rtsx_dump((u8 *)(buf), (buf_len))
-
+#define RTSX_DUMP(buf, buf_len)                                        \
+       print_hex_dump(KERN_DEBUG, RTSX_STOR, DUMP_PREFIX_NONE, \
+                               16, 1, (buf), (buf_len), false)
 #else
 #define RTSX_DUMP(buf, buf_len)
 #endif
index 8a362f7af379b4a2cfc6935f50d5a0a5db082fe3..dbce149ebb2f4c8c312a3d97e300d3fbebb0f714 100644 (file)
@@ -247,7 +247,6 @@ static void ProcessLineStatus(struct quatech_port *qt_port,
        qt_port->shadowLSR =
            line_status & (SERIAL_LSR_OE | SERIAL_LSR_PE | SERIAL_LSR_FE |
                           SERIAL_LSR_BI);
-       return;
 }
 
 static void ProcessModemStatus(struct quatech_port *qt_port,
@@ -256,7 +255,6 @@ static void ProcessModemStatus(struct quatech_port *qt_port,
 
        qt_port->shadowMSR = modem_status;
        wake_up_interruptible(&qt_port->wait);
-       return;
 }
 
 static void ProcessRxChar(struct tty_struct *tty, struct usb_serial_port *port,
@@ -315,10 +313,8 @@ static void qt_read_bulk_callback(struct urb *urb)
        }
 
        tty = tty_port_tty_get(&port->port);
-       if (!tty) {
-               dbg("%s - bad tty pointer - exiting", __func__);
+       if (!tty)
                return;
-       }
 
        data = urb->transfer_buffer;
 
@@ -364,7 +360,7 @@ static void qt_read_bulk_callback(struct urb *urb)
                goto exit;
        }
 
-       if (tty && RxCount) {
+       if (RxCount) {
                flag_data = 0;
                for (i = 0; i < RxCount; ++i) {
                        /* Look ahead code here */
@@ -428,7 +424,7 @@ static void qt_read_bulk_callback(struct urb *urb)
                dbg("%s - failed resubmitting read urb, error %d",
                    __func__, result);
        else {
-               if (tty && RxCount) {
+               if (RxCount) {
                        tty_flip_buffer_push(tty);
                        tty_schedule_flip(tty);
                }
@@ -897,8 +893,6 @@ static int qt_open(struct tty_struct *tty,
         * Put this here to make it responsive to stty and defaults set by
         * the tty layer
         */
-       /* FIXME: is this needed? */
-       /* qt_set_termios(tty, port, NULL); */
 
        /*  Check to see if we've set up our endpoint info yet */
        if (port0->open_ports == 1) {
@@ -1195,7 +1189,7 @@ static void qt_set_termios(struct tty_struct *tty,
                           struct usb_serial_port *port,
                           struct ktermios *old_termios)
 {
-       struct ktermios *termios = tty->termios;
+       struct ktermios *termios = &tty->termios;
        unsigned char new_LCR = 0;
        unsigned int cflag = termios->c_cflag;
        unsigned int index;
@@ -1204,7 +1198,7 @@ static void qt_set_termios(struct tty_struct *tty,
 
        index = tty->index - port->serial->minor;
 
-       switch (cflag) {
+       switch (cflag & CSIZE) {
        case CS5:
                new_LCR |= SERIAL_5_DATA;
                break;
@@ -1215,6 +1209,8 @@ static void qt_set_termios(struct tty_struct *tty,
                new_LCR |= SERIAL_7_DATA;
                break;
        default:
+               termios->c_cflag &= ~CSIZE;
+               termios->c_cflag |= CS8;
        case CS8:
                new_LCR |= SERIAL_8_DATA;
                break;
@@ -1301,7 +1297,7 @@ static void qt_set_termios(struct tty_struct *tty,
                        dbg(__FILE__ "BoxSetSW_FlowCtrl (diabling) failed\n");
 
        }
-       tty->termios->c_cflag &= ~CMSPAR;
+       termios->c_cflag &= ~CMSPAR;
        /* FIXME: Error cases should be returning the actual bits changed only */
 }
 
@@ -1412,7 +1408,7 @@ static int qt_tiocmget(struct tty_struct *tty)
        struct usb_serial_port *port = tty->driver_data;
        struct usb_serial *serial = get_usb_serial(port, __func__);
        struct quatech_port *qt_port = qt_get_port_private(port);
-       int retval = -ENODEV;
+       int retval;
 
        if (!serial)
                return -ENODEV;
@@ -1430,7 +1426,7 @@ static int qt_tiocmset(struct tty_struct *tty,
        struct usb_serial_port *port = tty->driver_data;
        struct usb_serial *serial = get_usb_serial(port, __func__);
        struct quatech_port *qt_port = qt_get_port_private(port);
-       int retval = -ENODEV;
+       int retval;
 
        if (!serial)
                return -ENODEV;
@@ -1458,7 +1454,6 @@ static void qt_throttle(struct tty_struct *tty)
        qt_port->RxHolding = 1;
 
        mutex_unlock(&qt_port->lock);
-       return;
 }
 
 static void qt_unthrottle(struct tty_struct *tty)
@@ -1499,8 +1494,6 @@ static void qt_unthrottle(struct tty_struct *tty)
                }
        }
        mutex_unlock(&qt_port->lock);
-       return;
-
 }
 
 static int qt_calc_num_ports(struct usb_serial *serial)
index ca01734d13c5f85e7f52ca38aead5ab97ea146fa..7c1658b971dc768958809e347f17b67ba753e428 100644 (file)
@@ -555,6 +555,7 @@ ssize_t msg_set(enum msg_index_t index, char *text, size_t length)
                        && index <= MSG_FORMATTED_END)
                                && !fmt_validate(speakup_default_msgs[index],
                                newstr)) {
+                               kfree(newstr);
                                return -EINVAL;
                        }
                        spk_lock(flags);
index 12826e2a3aaacf1ddb1ee0199f558835579860d4..ad73cba058ebe4983eb0cf6adb0786aacb6e0386 100644 (file)
@@ -69,7 +69,7 @@ The error codes used by this driver are:
     Invalid pointer or handler.
 
 [EEXIST]
-    Attempted to create a channel manager  when one already exists.
+    Attempted to create a channel manager when one already exists.
 
 [EINVAL]
     Invalid argument.
index 7cb58710397578be0009da4325d38a36a2f690eb..543a127c7d4d63e5b43de81151ec54a382cf03b8 100644 (file)
@@ -219,7 +219,7 @@ static const struct map_l4_peripheral l4_peripheral_table[] = {
 /* MBX_PM_MAX_RESOURCES: CORE 2 Clock Resources. */
 #define MBX_CORE2_RESOURCES 1
 
-/* MBX_PM_MAX_RESOURCES: TOTAL Clock Reosurces. */
+/* MBX_PM_MAX_RESOURCES: TOTAL Clock Resources. */
 #define MBX_PM_MAX_RESOURCES 11
 
 /*  Power Management Commands */
index e0c7e4c470c89bf9c669afda43ab2aca021d4786..f38950ea272896d340262f1d1d058567898db980 100644 (file)
@@ -20,7 +20,7 @@
  *      The lower edge functions must be implemented by the Bridge driver
  *      writer, and are declared in chnl_sm.h.
  *
- *      Care is taken in this code to prevent simulataneous access to channel
+ *      Care is taken in this code to prevent simultaneous access to channel
  *      queues from
  *      1. Threads.
  *      2. io_dpc(), scheduled from the io_isr() as an event.
@@ -34,7 +34,7 @@
  *  Channel Invariant:
  *      There is an important invariant condition which must be maintained per
  *      channel outside of bridge_chnl_get_ioc() and IO_Dispatch(), violation of
- *      which may cause timeouts and/or failure offunction sync_wait_on_event.
+ *      which may cause timeouts and/or failure of function sync_wait_on_event.
  *      This invariant condition is:
  *
  *          list_empty(&pchnl->io_completions) ==> pchnl->sync_event is reset
@@ -602,7 +602,7 @@ int bridge_chnl_get_ioc(struct chnl_object *chnl_obj, u32 timeout,
                /*  Since DSPStream_Reclaim() does not take a timeout
                 *  parameter, we pass the stream's timeout value to
                 *  bridge_chnl_get_ioc. We cannot determine whether or not
-                *  we have waited in User mode. Since the stream's timeout
+                *  we have waited in user mode. Since the stream's timeout
                 *  value may be non-zero, we still have to set the event.
                 *  Therefore, this optimization is taken out.
                 *
index 480a3845a24ce014fa203ce8a0e1297eb8e75b8d..e322fb7aebe1da0de4ebf8ec3c51eddde30a6cb8 100644 (file)
@@ -837,8 +837,8 @@ static void io_dispatch_pm(struct io_mgr *pio_mgr)
 /*
  *  ======== io_dpc ========
  *      Deferred procedure call for shared memory channel driver ISR.  Carries
- *      out the dispatch of I/O as a non-preemptible event.It can only be
- *      pre-empted      by an ISR.
+ *      out the dispatch of I/O as a non-preemptible event. It can only be
+ *      pre-empted by an ISR.
  */
 void io_dpc(unsigned long ref_data)
 {
@@ -877,7 +877,7 @@ void io_dpc(unsigned long ref_data)
                                                  pio_mgr->intr_val);
                        }
                }
-               /* Proc-copy chanel dispatch */
+               /* Proc-copy channel dispatch */
                input_chnl(pio_mgr, NULL, IO_SERVICE);
                output_chnl(pio_mgr, NULL, IO_SERVICE);
 
@@ -938,7 +938,7 @@ int io_mbox_msg(struct notifier_block *self, unsigned long len, void *msg)
 /*
  *  ======== io_request_chnl ========
  *  Purpose:
- *      Request chanenel I/O from the DSP. Sets flags in shared memory, then
+ *      Request channel I/O from the DSP. Sets flags in shared memory, then
  *      interrupts the DSP.
  */
 void io_request_chnl(struct io_mgr *io_manager, struct chnl_object *pchnl,
@@ -2208,7 +2208,7 @@ void dump_dl_modules(struct bridge_dev_context *bridge_context)
                        module_struct->num_sects);
 
                /*
-                * The section name strings start immedialty following
+                * The section name strings start immediately following
                 * the array of dll_sect structures.
                 */
                sect_str = (char *) &module_struct->
index 995986a9d03ba2263f147e7ce7a81a00845c9610..7bb550acaf4a88a4e3a37e6c07d3eaaa27907d38 100644 (file)
@@ -49,7 +49,7 @@ void sync_set_event(struct sync_object *event)
  * @timeout    timeout on waiting for the evetns.
  * @pu_index   index of the event set.
  *
- * This functios will wait until any of the array element is set or until
+ * These functions will wait until any of the array element is set or until
  * timeout. In case of success the function will return 0 and
  * @pu_index will store the index of the array element set or in case
  * of timeout the function will return -ETIME or in case of
index f9609ce2c163bf55b9a6e78bf64a4fa26f69968e..a19bf5ce58b6ff81ef666aceb5e5fa79b5ec75b6 100644 (file)
@@ -328,7 +328,7 @@ static int bridge_brd_read(struct bridge_dev_context *dev_ctxt,
                                           ul_num_bytes, mem_type);
                return status;
        }
-       /* copy the data from  DSP memory, */
+       /* copy the data from DSP memory */
        memcpy(host_buff, (void *)(dsp_base_addr + offset), ul_num_bytes);
        return status;
 }
@@ -1745,7 +1745,7 @@ static int mem_map_vmalloc(struct bridge_dev_context *dev_context,
        pa_next = page_to_phys(page[0]);
        while (!status && (i < num_pages)) {
                /*
-                * Reuse pa_next from the previous iteraion to avoid
+                * Reuse pa_next from the previous iteration to avoid
                 * an extra va2pa call
                 */
                pa_curr = pa_next;
index 16a4aafa86aed19ca0b4cf962529f2788357cd13..58a1d6dcf098c94720ef4789397a8b1f12f25cfe 100644 (file)
@@ -356,7 +356,7 @@ int pre_scale_dsp(struct bridge_dev_context *dev_context, void *pargs)
                dev_dbg(bridge, "OPP: %s IVA in sleep. No message to DSP\n");
                return 0;
        } else if ((dev_context->brd_state == BRD_RUNNING)) {
-               /* Send a prenotificatio to DSP */
+               /* Send a prenotification to DSP */
                dev_dbg(bridge, "OPP: %s sent notification to DSP\n", __func__);
                sm_interrupt_dsp(dev_context, MBX_PM_SETPOINT_PRENOTIFY);
                return 0;
index 60d22ea470556843afb5a48ef9f6ce262e664e44..404af1895980bdc100d09225583b643a7182cd31 100644 (file)
@@ -81,7 +81,7 @@ static u8 priv_h2a(u8 value)
  * Description: Generate a trampoline symbol name (ASCII) using the value
  *       of the symbol.  This places the new name into the user buffer.
  *       The name is fixed in length and of the form: __$dbTR__xxxxxxxx
- *       (where "xxxxxxxx" is the hex value.
+ *       (where "xxxxxxxx" is the hex value).
  */
 static void priv_tramp_sym_gen_name(u32 value, char *dst)
 {
@@ -414,7 +414,7 @@ static int priv_tramp_sym_finalize(struct dload_state *dlthis)
                        /*  Copy the symbol contents into the flat table */
                        *new_sym = cur_sym->sym_info;
 
-                       /*  Now finaize the symbol.  If it is in the tramp
+                       /*  Now finalize the symbol.  If it is in the tramp
                         * section, we need to adjust for the section start.
                         * If it is external then we don't need to adjust at
                         * all.
@@ -773,7 +773,7 @@ static int priv_img_pkt_dup(struct dload_state *dlthis,
        int ret_val = 0;
        struct tramp_img_dup_relo *dup_relo = NULL;
 
-       /*  Determinne if this image packet is already being tracked in the
+       /*  Determine if this image packet is already being tracked in the
           dup list for other trampolines. */
        dup_pkt = priv_dup_find(dlthis, secnn, image_offset);
 
@@ -998,7 +998,7 @@ int dload_tramp_generate(struct dload_state *dlthis, s16 secnn,
 /*
  * Function:   dload_tramp_pkt_update
  * Description: Update the duplicate copy of this image packet, which the
- *       trampoline layer is already tracking.  This is call is critical
+ *       trampoline layer is already tracking.  This call is critical
  *       to make if trampolines were generated anywhere within the
  *       packet and first pass relo continued on the remainder.  The
  *       trampoline layer needs the updates image data so when 2nd
index b44656cf7858ea1ec3f5fb186634ad7fe67019e5..b7d8313d1acb2eec29402988b9f43651b525542a 100644 (file)
 /*  ----------------------------------- This */
 #include <dspbridge/uuidutil.h>
 
-/*
- *  ======== uuid_uuid_to_string ========
- *  Purpose:
- *      Converts a struct dsp_uuid to a string.
- *      Note: snprintf format specifier is:
- *      %[flags] [width] [.precision] [{h | l | I64 | L}]type
- */
-void uuid_uuid_to_string(struct dsp_uuid *uuid_obj, char *sz_uuid,
-                        s32 size)
-{
-       s32 i;                  /* return result from snprintf. */
-
-       i = snprintf(sz_uuid, size,
-                    "%.8X_%.4X_%.4X_%.2X%.2X_%.2X%.2X%.2X%.2X%.2X%.2X",
-                    uuid_obj->data1, uuid_obj->data2, uuid_obj->data3,
-                    uuid_obj->data4, uuid_obj->data5,
-                    uuid_obj->data6[0], uuid_obj->data6[1],
-                    uuid_obj->data6[2], uuid_obj->data6[3],
-                    uuid_obj->data6[4], uuid_obj->data6[5]);
-}
-
 static s32 uuid_hex_to_bin(char *buf, s32 len)
 {
        s32 i;
index 8a93d55ca596e01f52de187eaf185e141686f961..71cb822936499fb23b82f19053337a5159307c87 100644 (file)
@@ -61,7 +61,7 @@ enum hw_mmu_page_size_t {
  *       Type          : hw_status
  *       Description     : 0            -- No errors occurred
  *                      RET_BAD_NULL_PARAM     -- A Pointer
- *                                             Paramater was set to NULL
+ *                                             Parameter was set to NULL
  *
  * PURPOSE:          : Flush the TLB entry pointed by the
  *                     lock counter register
@@ -103,7 +103,7 @@ static hw_status mmu_flush_entry(const void __iomem *base_address);
  *
  *       Type          : hw_status
  *       Description     : 0            -- No errors occurred
- *                      RET_BAD_NULL_PARAM     -- A Pointer Paramater
+ *                      RET_BAD_NULL_PARAM     -- A Pointer Parameter
  *                                                was set to NULL
  *                      RET_PARAM_OUT_OF_RANGE -- Input Parameter out
  *                                                of Range
@@ -148,7 +148,7 @@ static hw_status mmu_set_cam_entry(const void __iomem *base_address,
  *
  *       Type          : hw_status
  *       Description     : 0            -- No errors occurred
- *                      RET_BAD_NULL_PARAM     -- A Pointer Paramater
+ *                      RET_BAD_NULL_PARAM     -- A Pointer Parameter
  *                                                     was set to NULL
  *                      RET_PARAM_OUT_OF_RANGE -- Input Parameter
  *                                                     out of Range
index 0c7ec04448f1fc9f7211fe8bd67e731ffdc35dd1..0fcda19789217a750f0e8f78f6a0d9a14fcae496 100644 (file)
@@ -51,7 +51,7 @@
 #define BRDIOCTL_POSTSCALE_NOTIFY (BRDIOCTL_PWRCONTROL + 0xA)
 #define BRDIOCTL_CONSTRAINT_REQUEST (BRDIOCTL_PWRCONTROL + 0xB)
 
-/* Number of actual DSP-MMU TLB entrries */
+/* Number of actual DSP-MMU TLB entries */
 #define BRDIOCTL_NUMOFMMUTLB        32
 
 struct bridge_ioctl_extproc {
index 7424c888d6377e1ba21525ad92ce492129794237..d4cb3948baba154b64c58e40e5035401508399e7 100644 (file)
@@ -22,7 +22,7 @@
  *  mailbox interrupt's cmd value received. The class value are defined
  *  as a bit (10 thru 15) being set.
  *
- *  Note: Only 16 bits of each  is used. Other 16 bit data reg available.
+ *  Note: Only 16 bits of each is used. Other 16 bit data reg available.
  *
  *   16 bit Mbx bit defns:
  *
index 7397b7a12f7aef4323e1d4acf1047ee0c0f3431b..68ed74a86c95ee5ae37d110c5ae13ae5718fcf7c 100644 (file)
@@ -220,7 +220,7 @@ extern int node_create_mgr(struct node_mgr **node_man,
  *  Parameters:
  *      noderes:              Node resource info handle returned from
  *                                 node_allocate().
- *      pr_ctxt:                Poninter to process context data.
+ *      pr_ctxt:                Pointer to process context data.
  *  Returns:
  *      0:            Success.
  *      -EFAULT:        Invalid hnode.
index cbc8819c61ccc58bd68adb991dc540d700a1d5fe..6bb94d20e99a9f135807b70666f14d70652ec554 100644 (file)
@@ -78,7 +78,7 @@ static inline void ntfy_init(struct ntfy_object *no)
  * ntfy_delete() - delete list of nofy events registered.
  * @ntfy_obj:  Pointer to the ntfy object structure.
  *
- * This function is used to remove all the notify events  registered.
+ * This function is used to remove all the notify events registered.
  * unregister function is not needed in this function, to unregister
  * a ntfy_event please look at ntfy_register function.
  *
index a82380ebc041fd12faf54ba0ad079c897006d9d4..851b356d7a51a24f47ac5959f500bd0fad8a8454 100644 (file)
@@ -263,7 +263,7 @@ extern int proc_get_processor_id(void *proc, u32 * proc_id);
  *  Returns:
  *      0     :   Success.
  *      -EFAULT :   Invalid processor handle.
- *      -EPERM   :   General failure while retireving processor trace
+ *      -EPERM   :   General failure while retrieving processor trace
  *                   Buffer.
  *  Requires:
  *      pbuf is not NULL
index dacf0c234fd1fe5ef98f3ba97e2dfe8bc33acb2f..97aee4c63d2435e635a93bed7dcf10ad6a92f5b5 100644 (file)
@@ -203,7 +203,7 @@ extern int strm_issue(struct strm_object *stream_obj, u8 * pbuf,
  *      index:         Stream index.
  *      pattr:          Pointer to structure containing attributes to be
  *                      applied to stream. Cannot be NULL.
- *      strmres:     Location to store stream resuorce info handle on output.
+ *      strmres:     Location to store stream resource info handle on output.
  *  Returns:
  *      0:        Success.
  *      -EFAULT:    Invalid hnode.
index b1e75eb8847c5bdff0ec4d2899b5e4fcfa30acf9..58a0d5c5543d1617c82a9968c9c479952675892a 100644 (file)
@@ -78,7 +78,7 @@ void sync_set_event(struct sync_object *event);
  * @event:     events to wait for it.
  * @timeout    timeout on waiting for the evetn.
  *
- * This functios will wait until @event is set or until timeout. In case of
+ * This function will wait until @event is set or until timeout. In case of
  * success the function will return 0 and
  * in case of timeout the function will return -ETIME
  * in case of signal the function will return -ERESTARTSYS
@@ -106,7 +106,7 @@ static inline int sync_wait_on_event(struct sync_object *event,
  * @timeout    timeout on waiting for the evetns.
  * @pu_index   index of the event set.
  *
- * This functios will wait until any of the array element is set or until
+ * This function will wait until any of the array element is set or until
  * timeout. In case of success the function will return 0 and
  * @pu_index will store the index of the array element set and in case
  * of timeout the function will return -ETIME.
index 9a994753e9ba143143b677ebc16ea8462b86ddc0..414bf71d652db7bf6c3e080129628987ee9a1050 100644 (file)
 
 #define MAXUUIDLEN  37
 
-/*
- *  ======== uuid_uuid_to_string ========
- *  Purpose:
- *      Converts a dsp_uuid to an ANSI string.
- *  Parameters:
- *      uuid_obj:      Pointer to a dsp_uuid object.
- *      sz_uuid:    Pointer to a buffer to receive a NULL-terminated UUID
- *                  string.
- *      size:      Maximum size of the sz_uuid string.
- *  Returns:
- *  Requires:
- *      uuid_obj & sz_uuid are non-NULL values.
- *  Ensures:
- *      Lenghth of sz_uuid is less than MAXUUIDLEN.
- *  Details:
- *      UUID string limit currently set at MAXUUIDLEN.
- */
-void uuid_uuid_to_string(struct dsp_uuid *uuid_obj, char *sz_uuid,
-                        s32 size);
-
 /*
  *  ======== uuid_uuid_from_string ========
  *  Purpose:
index 12a1d34b39546e93e1b604d3264ac8eef5b71b81..e05670dfeb461569e707ec5484024488fbfdfa22 100644 (file)
@@ -395,7 +395,7 @@ int dcd_get_object_def(struct dcd_manager *hdcd_mgr,
                }
 
                /* Create UUID value to set in registry. */
-               uuid_uuid_to_string(obj_uuid, sz_uuid, MAXUUIDLEN);
+               snprintf(sz_uuid, MAXUUIDLEN, "%pU", obj_uuid);
 
                if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH)
                        strncat(sz_reg_key, sz_uuid, MAXUUIDLEN);
@@ -463,7 +463,7 @@ int dcd_get_object_def(struct dcd_manager *hdcd_mgr,
        status = cod_read_section(lib, sz_sect_name, psz_coff_buf, ul_len);
 #endif
        if (!status) {
-               /* Compres DSP buffer to conform to PC format. */
+               /* Compress DSP buffer to conform to PC format. */
                if (strstr(dcd_key->path, "iva") == NULL) {
                        compress_buf(psz_coff_buf, ul_len, DSPWORDSIZE);
                } else {
index 3cac0149206343bfdacce1ff221f78b8f5dda847..6acea2b56aa47ac6e70d2aed1000c7faaf40cca9 100644 (file)
@@ -613,16 +613,6 @@ static struct platform_driver bridge_driver = {
 #endif
 };
 
-static int __init bridge_init(void)
-{
-       return platform_driver_register(&bridge_driver);
-}
-
-static void __exit bridge_exit(void)
-{
-       platform_driver_unregister(&bridge_driver);
-}
-
 /* To remove all process resources before removing the process from the
  * process context list */
 int drv_remove_all_resources(void *process_ctxt)
@@ -636,6 +626,4 @@ int drv_remove_all_resources(void *process_ctxt)
        return status;
 }
 
-/* Bridge driver initialization and de-initialization functions */
-module_init(bridge_init);
-module_exit(bridge_exit);
+module_platform_driver(bridge_driver);
index dc767b183cdfa99b5b6a2d747c284877bfafb7dd..d460f5823c6b9a645c465db6d8cafe65223981de 100644 (file)
@@ -72,7 +72,7 @@ u32 dsp_init(u32 *init_status)
 
        /* Unwind whatever was loaded */
        if (status) {
-               /* irrespective of the status of dev_remove_device we conitinue
+               /* irrespective of the status of dev_remove_device we continue
                 * unloading. Get the Driver Object iterate through and remove.
                 * Reset the status to E_FAIL to avoid going through
                 * api_init_complete2. */
@@ -92,7 +92,7 @@ u32 dsp_init(u32 *init_status)
 func_cont:
        /* Attempt to Start the Board */
        if (!status) {
-               /* BRD_AutoStart could fail if the dsp execuetable is not the
+               /* BRD_AutoStart could fail if the dsp executable is not the
                 * correct one. We should not propagate that error
                 * into the device loader. */
                (void)api_init_complete2();
index 8a1e9287cff63404b5c932336de69b7cca86daf6..b32ba0ad2a073da9b9447d8686313d7079f3ae0d 100644 (file)
@@ -262,8 +262,8 @@ int mgr_enum_processor_info(u32 processor_id,
                                    IVAPROCTYPE_ARM7)
                                        proc_detect = true;
                        }
-                       /* User applciatiuons aonly check for chip type, so
-                        * this clumsy overwrite */
+                       /* User applications only check for chip type, so
+                        * this is a clumsy overwrite */
                        processor_info->processor_type = DSPTYPE64;
                } else {
                        dev_dbg(bridge, "%s: Failed to get DCD processor info "
index 30d5480fcdcce735ca40a9624638a355cc037810..6309221b64a5d9c1d053619866adee0ada0f3673 100644 (file)
@@ -898,7 +898,7 @@ static int add_ovly_info(void *handle, struct dbll_sect_info *sect_info,
                                nldr_obj->ovly_table[i].execute_sects++;
 
                } else {
-                       /* Put in "other" sectins */
+                       /* Put in "other" sections */
                        status =
                            add_ovly_sect(nldr_obj,
                                          &nldr_obj->
index 7fb426c5251c0d86b9275318e798a3f5954a83a7..f17c128b3d5fbe0f62d9e983c75ba764db59cbea 100644 (file)
@@ -1613,7 +1613,7 @@ int node_get_attr(struct node_object *hnode,
                return -EFAULT;
 
        hnode_mgr = hnode->node_mgr;
-       /* Enter hnode_mgr critical section (since we're accessing
+       /* Enter hnode_mgr critical section since we're accessing
         * data that could be changed by node_change_priority() and
         * node_connect(). */
        mutex_lock(&hnode_mgr->node_mgr_lock);
index 7e4f12f6be42dcee8292893b59d8f718301017a1..5e43938ab7fa758170e34479992820cc361bddd4 100644 (file)
@@ -300,7 +300,7 @@ proc_attach(u32 processor_id,
        if (status)
                goto func_end;
 
-       /* If we made it this far, create the Proceesor object: */
+       /* If we made it this far, create the Processor object: */
        p_proc_object = kzalloc(sizeof(struct proc_object), GFP_KERNEL);
        /* Fill out the Processor Object: */
        if (p_proc_object == NULL) {
index 1d5b3fc62160ff95afddba819e9b91eb2cad26a0..694cfd7596f39d9f6b025dacd6c8cb4f1e06990e 100644 (file)
@@ -155,7 +155,7 @@ static int tweak_set_configuration_cmd(struct urb *urb)
         * eventually reassigned to the device as far as driver matching
         * condition is kept.
         *
-        * Unfortunatelly, an existing usbip connection will be dropped
+        * Unfortunately, an existing usbip connection will be dropped
         * due to this driver unbinding. So, skip here.
         * A user may need to set a special configuration value before
         * exporting the device.
index 12a9a5fbc797e532719921afd0c839169653b993..a5b028d074b87b1112ac263b5659ac2010c18688 100644 (file)
@@ -828,11 +828,11 @@ static void vhci_shutdown_connection(struct usbip_device *ud)
         *      disable endpoints. pending urbs are unlinked(dequeued).
         *
         * NOTE: After calling rh_port_disconnect(), the USB device drivers of a
-        * deteched device should release used urbs in a cleanup function(i.e.
+        * detached device should release used urbs in a cleanup function (i.e.
         * xxx_disconnect()). Therefore, vhci_hcd does not need to release
         * pushed urbs and their private data in this function.
         *
-        * NOTE: vhci_dequeue() must be considered carefully. When shutdowning
+        * NOTE: vhci_dequeue() must be considered carefully. When shutting down
         * a connection, vhci_shutdown_connection() expects vhci_dequeue()
         * gives back pushed urbs and frees their private data by request of
         * the cleanup function of a USB driver. When unlinking a urb with an
index e25645e226e322d00048f9099ab780451d4725ea..0170788fcdeee80a81770b878487f663a8846760 100644 (file)
@@ -64,13 +64,13 @@ static unsigned int bus_num;
  *
  * However the VME driver at http://www.vmelinux.org/ is rather old and doesn't
  * even support the tsi148 chipset (which has 8 master and 8 slave windows).
- * We'll run with this or now as far as possible, however it probably makes
+ * We'll run with this for now as far as possible, however it probably makes
  * sense to get rid of the old mappings and just do everything dynamically.
  *
  * So for now, we'll restrict the driver to providing 4 masters and 4 slaves as
  * defined above and try to support at least some of the interface from
- * http://www.vmelinux.org/ as an alternative drive can be written providing a
- * saner interface later.
+ * http://www.vmelinux.org/ as an alternative the driver can be written
+ * providing a saner interface later.
  *
  * The vmelinux.org driver never supported slave images, the devices reserved
  * for slaves were repurposed to support all 8 master images on the UniverseII!
@@ -242,7 +242,7 @@ static ssize_t resource_to_user(int minor, char __user *buf, size_t count,
 }
 
 /*
- * We are going ot alloc a page during init per window for small transfers.
+ * We are going to alloc a page during init per window for small transfers.
  * Small transfers will go user space -> buffer -> VME. Larger (more than a
  * page) transfers will lock the user space buffer into memory and then
  * transfer the data directly from the user space buffers out to VME.
index ef197efab049de3f87dc34fb42a0d4432e521222..ac15d381c33c68e2836fcad347b2bfe7e169fa9b 100644 (file)
@@ -539,11 +539,8 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq)
                        pMgmt->abyIBSSSuppRates[3] |= BIT7;
                }
 
-               DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Support Rate= %x %x %x %x\n",
-                       pMgmt->abyIBSSSuppRates[2],
-                       pMgmt->abyIBSSSuppRates[3],
-                       pMgmt->abyIBSSSuppRates[4],
-                       pMgmt->abyIBSSSuppRates[5]);
+               DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Support Rate= %*ph\n",
+                               4, pMgmt->abyIBSSSuppRates + 2);
 
                netif_stop_queue(pDevice->dev);
                spin_lock_irq(&pDevice->lock);
index 682002a5b8d7a113dee754b2c725d94b94d8a019..9f2ca17d357fc8f1572699801f1a03c2b5b807ff 100644 (file)
@@ -732,8 +732,8 @@ int vt6656_hostap_ioctl(PSDevice pDevice, struct iw_point *p)
                break;
        case VIAWGET_HOSTAPD_SET_ASSOC_AP_ADDR:
            DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_SET_ASSOC_AP_ADDR \n");
-               return -EOPNOTSUPP;
-               break;
+               ret = -EOPNOTSUPP;
+               goto out;
        case VIAWGET_HOSTAPD_FLUSH:
            DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_FLUSH \n");
         spin_lock_irq(&pDevice->lock);
@@ -777,13 +777,13 @@ int vt6656_hostap_ioctl(PSDevice pDevice, struct iw_point *p)
 
        case VIAWGET_HOSTAPD_STA_CLEAR_STATS:
            DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_STA_CLEAR_STATS \n");
-           return -EOPNOTSUPP;
-
+           ret = -EOPNOTSUPP;
+           goto out;
        default:
            DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "vt6656_hostap_ioctl: unknown cmd=%d\n",
                       (int)param->cmd);
-               return -EOPNOTSUPP;
-               break;
+               ret = -EOPNOTSUPP;
+               goto out;
        }
 
 
index 5b9a84f95185358f69a27640d874f5b49f63d0a9..d67b29f78b4ae908c723315c735b3f7dece11b32 100644 (file)
@@ -526,11 +526,8 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq)
                        pMgmt->abyIBSSSuppRates[3] |= BIT7;
                }
 
-               DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Support Rate= %x %x %x %x\n",
-                       pMgmt->abyIBSSSuppRates[2],
-                       pMgmt->abyIBSSSuppRates[3],
-                       pMgmt->abyIBSSSuppRates[4],
-                       pMgmt->abyIBSSSuppRates[5]);
+               DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Support Rate= %*ph\n",
+                       4, pMgmt->abyIBSSSuppRates + 2);
 
                netif_stop_queue(pDevice->dev);
                spin_lock_irq(&pDevice->lock);
index 3fd0478a9a540f447e2ab657e54b352565ce78c2..c82b3e695b8d232ecf44c45439da53ef8d7534e8 100644 (file)
@@ -26,7 +26,7 @@
  * Date: Feb. 19, 2004
  *
  * Functions:
- *      IFRFbWriteEmbeded      - Embeded write RF register via MAC
+ *      IFRFbWriteEmbeded      - Embedded write RF register via MAC
  *
  * Revision History:
  *
@@ -711,7 +711,7 @@ const BYTE RFaby11aChannelIndex[200] = {
 /*---------------------  Export Functions  --------------------------*/
 
 /*
- * Description: Write to IF/RF, by embeded programming
+ * Description: Write to IF/RF, by embedded programming
  *
  * Parameters:
  *  In:
index bb464527fc1b06e8814b05c23c97e89208cda92e..dd28b9106b481a36cac59c9370a53ad17ced4057 100644 (file)
@@ -987,7 +987,7 @@ s_vFillRTSHead (
         uRTSFrameLen -= 4;
     }
 
-    // Note: So far RTSHead dosen't appear in ATIM & Beacom DMA, so we don't need to take them into account.
+    // Note: So far RTSHead doesn't appear in ATIM & Beacom DMA, so we don't need to take them into account.
     //       Otherwise, we need to modified codes for them.
     if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) {
         if (byFBOption == AUTO_FB_NONE) {
@@ -2770,7 +2770,7 @@ int nsDMA_tx_packet(PSDevice pDevice, unsigned int uDMAIdx, struct sk_buff *skb)
                 pMgmt->abyPSTxMap[0] |= byMask[0];
                 return 0;
             }
-            // muticast/broadcast data rate
+            // multicast/broadcast data rate
 
             if (pDevice->byBBType != BB_TYPE_11A)
                 pDevice->wCurrentRate = RATE_2M;
index 9d2caa819f47418f3e14ecdb84611857d1108803..23ed03c602879e571162890be2bcccd5373c9ee5 100644 (file)
@@ -751,7 +751,7 @@ void vRunCommand(void *hDeviceContext)
                       pDevice->nTxDataTimeCout = 0;
                 }
                 else {
-                  // printk("mike:-->First time triger TimerTxData InSleep\n");
+                  // printk("mike:-->First time trigger TimerTxData InSleep\n");
                 }
                pDevice->IsTxDataTrigger = TRUE;
                 add_timer(&pDevice->sTimerTxData);
index f08e2d15c7b34ed0ac954e771db8d927206e9df3..9469c9e1d31def0309836778f689d97a6361b096 100644 (file)
@@ -54,7 +54,7 @@
  *      bMgrPrepareBeaconToSend - Prepare Beacon frame
  *      s_vMgrLogStatus - Log 802.11 Status
  *      vMgrRxManagePacket - Rcv management frame dispatch function
- *      s_vMgrFormatTIM- Assember TIM field of beacon
+ *      s_vMgrFormatTIM- Assembler TIM field of beacon
  *      vMgrTimerInit- Initial 1-sec and command call back funtions
  *
  * Revision History:
@@ -2032,7 +2032,7 @@ if(ChannelExceedZoneType(pDevice,byCurrChannel)==TRUE)
                 }
 
                 //
-                // Preamble may change dynamiclly
+                // Preamble may change dynamically
                 //
                 byOldPreambleType = pDevice->byPreambleType;
                 if (WLAN_GET_CAP_INFO_SHORTPREAMBLE(pBSSList->wCapInfo)) {
@@ -2044,7 +2044,7 @@ if(ChannelExceedZoneType(pDevice,byCurrChannel)==TRUE)
                 if (pDevice->byPreambleType != byOldPreambleType)
                     CARDvSetRSPINF(pDevice, (BYTE)pDevice->byBBType);
             //
-            // Basic Rate Set may change dynamiclly
+            // Basic Rate Set may change dynamically
             //
             if (pBSSList->eNetworkTypeInUse == PHY_TYPE_11B) {
                 uRateLen = WLAN_RATES_MAXLEN_11B;
index 80c2d3b672bb9e47c471c3c8fb8760ac0af42727..77e50a4aa7e9430c1ff59ea3136f5abf9a50b457 100644 (file)
@@ -134,10 +134,8 @@ int wep_change_key(wlandevice_t *wlandev, int keynum, u8 *key, int keylen)
                return -1;
 
 #ifdef WEP_DEBUG
-       printk(KERN_DEBUG
-              "WEP key %d len %d = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
-              keynum, keylen, key[0], key[1], key[2], key[3], key[4], key[5],
-              key[6], key[7]);
+       printk(KERN_DEBUG "WEP key %d len %d = %*phC\n", keynum, keylen,
+                         8, key);
 #endif
 
        wlandev->wep_keylens[keynum] = keylen;
@@ -184,10 +182,8 @@ int wep_decrypt(wlandevice_t *wlandev, u8 *buf, u32 len, int key_override,
        keylen += 3;            /* add in IV bytes */
 
 #ifdef WEP_DEBUG
-       printk(KERN_DEBUG
-              "D %d: %02x %02x %02x (%d %d) %02x:%02x:%02x:%02x:%02x\n", len,
-              key[0], key[1], key[2], keyidx, keylen, key[3], key[4], key[5],
-              key[6], key[7]);
+       printk(KERN_DEBUG "D %d: %*ph (%d %d) %*phC\n", len, 3, key,
+                         keyidx, keylen, 5, key + 3);
 #endif
 
        /* set up the RC4 state */
@@ -263,10 +259,8 @@ int wep_encrypt(wlandevice_t *wlandev, u8 *buf, u8 *dst, u32 len, int keynum,
        keylen += 3;            /* add in IV bytes */
 
 #ifdef WEP_DEBUG
-       printk(KERN_DEBUG
-              "E %d (%d/%d %d) %02x %02x %02x %02x:%02x:%02x:%02x:%02x\n", len,
-              iv[3], keynum, keylen, key[0], key[1], key[2], key[3], key[4],
-              key[5], key[6], key[7]);
+       printk(KERN_DEBUG "E %d (%d/%d %d) %*ph %*phC\n", len,
+                         iv[3], keynum, keylen, 3, key, 5, key + 3);
 #endif
 
        /* set up the RC4 state */
index 64ffd70eb7dcf2da0eb179bfac4f12b138a3e9b3..0c859aecc225a025cdd4c979906a9b1225375b66 100644 (file)
@@ -913,17 +913,10 @@ static void XGIfb_post_setmode(struct xgifb_video_info *xgifb_info)
                        }
 
                        if ((filter >= 0) && (filter <= 7)) {
-                               pr_debug("FilterTable[%d]-%d: %02x %02x %02x %02x\n",
+                               pr_debug("FilterTable[%d]-%d: %*ph\n",
                                         filter_tb, filter,
-                                        XGI_TV_filter[filter_tb].
-                                               filter[filter][0],
-                                        XGI_TV_filter[filter_tb].
-                                               filter[filter][1],
-                                        XGI_TV_filter[filter_tb].
-                                               filter[filter][2],
-                                        XGI_TV_filter[filter_tb].
-                                               filter[filter][3]
-                               );
+                                        4, XGI_TV_filter[filter_tb].
+                                                  filter[filter]);
                                xgifb_reg_set(
                                        XGIPART2,
                                        0x35,
index 80dba6a425baa75171ec7bc9659a0176bc72d656..fdb7d1a78b3b614d250238cf7da80c161d2cfd6e 100644 (file)
@@ -1269,7 +1269,7 @@ static unsigned char GetXG27FPBits(struct vb_device_info *pVBInfo)
        if (temp <= 2)
                temp &= 0x03;
        else
-               temp = ((temp & 0x04) >> 1) || ((~temp) & 0x01);
+               temp = ((temp & 0x04) >> 1) | ((~temp) & 0x01);
 
        xgifb_reg_set(pVBInfo->P3d4, 0x4A, CR4A);
 
index 8b0bcb626a7f8e3082fa6dce0fbac81c92fde966..09a9d35d436ff6075f256ec02f9e029e9e26a455 100644 (file)
 #include <linux/cpumask.h>
 #include <linux/cpu.h>
 #include <linux/vmalloc.h>
+#include <linux/hardirq.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
 
 #include "zsmalloc.h"
-#include "zsmalloc_int.h"
+
+/*
+ * This must be power of 2 and greater than of equal to sizeof(link_free).
+ * These two conditions ensure that any 'struct link_free' itself doesn't
+ * span more than 1 page which avoids complex case of mapping 2 pages simply
+ * to restore link_free pointer values.
+ */
+#define ZS_ALIGN               8
+
+/*
+ * A single 'zspage' is composed of up to 2^N discontiguous 0-order (single)
+ * pages. ZS_MAX_ZSPAGE_ORDER defines upper limit on N.
+ */
+#define ZS_MAX_ZSPAGE_ORDER 2
+#define ZS_MAX_PAGES_PER_ZSPAGE (_AC(1, UL) << ZS_MAX_ZSPAGE_ORDER)
+
+/*
+ * Object location (<PFN>, <obj_idx>) is encoded as
+ * as single (void *) handle value.
+ *
+ * Note that object index <obj_idx> is relative to system
+ * page <PFN> it is stored in, so for each sub-page belonging
+ * to a zspage, obj_idx starts with 0.
+ *
+ * This is made more complicated by various memory models and PAE.
+ */
+
+#ifndef MAX_PHYSMEM_BITS
+#ifdef CONFIG_HIGHMEM64G
+#define MAX_PHYSMEM_BITS 36
+#else /* !CONFIG_HIGHMEM64G */
+/*
+ * If this definition of MAX_PHYSMEM_BITS is used, OBJ_INDEX_BITS will just
+ * be PAGE_SHIFT
+ */
+#define MAX_PHYSMEM_BITS BITS_PER_LONG
+#endif
+#endif
+#define _PFN_BITS              (MAX_PHYSMEM_BITS - PAGE_SHIFT)
+#define OBJ_INDEX_BITS (BITS_PER_LONG - _PFN_BITS)
+#define OBJ_INDEX_MASK ((_AC(1, UL) << OBJ_INDEX_BITS) - 1)
+
+#define MAX(a, b) ((a) >= (b) ? (a) : (b))
+/* ZS_MIN_ALLOC_SIZE must be multiple of ZS_ALIGN */
+#define ZS_MIN_ALLOC_SIZE \
+       MAX(32, (ZS_MAX_PAGES_PER_ZSPAGE << PAGE_SHIFT >> OBJ_INDEX_BITS))
+#define ZS_MAX_ALLOC_SIZE      PAGE_SIZE
+
+/*
+ * On systems with 4K page size, this gives 254 size classes! There is a
+ * trader-off here:
+ *  - Large number of size classes is potentially wasteful as free page are
+ *    spread across these classes
+ *  - Small number of size classes causes large internal fragmentation
+ *  - Probably its better to use specific size classes (empirically
+ *    determined). NOTE: all those class sizes must be set as multiple of
+ *    ZS_ALIGN to make sure link_free itself never has to span 2 pages.
+ *
+ *  ZS_MIN_ALLOC_SIZE and ZS_SIZE_CLASS_DELTA must be multiple of ZS_ALIGN
+ *  (reason above)
+ */
+#define ZS_SIZE_CLASS_DELTA    16
+#define ZS_SIZE_CLASSES                ((ZS_MAX_ALLOC_SIZE - ZS_MIN_ALLOC_SIZE) / \
+                                       ZS_SIZE_CLASS_DELTA + 1)
+
+/*
+ * We do not maintain any list for completely empty or full pages
+ */
+enum fullness_group {
+       ZS_ALMOST_FULL,
+       ZS_ALMOST_EMPTY,
+       _ZS_NR_FULLNESS_GROUPS,
+
+       ZS_EMPTY,
+       ZS_FULL
+};
+
+/*
+ * We assign a page to ZS_ALMOST_EMPTY fullness group when:
+ *     n <= N / f, where
+ * n = number of allocated objects
+ * N = total number of objects zspage can store
+ * f = 1/fullness_threshold_frac
+ *
+ * Similarly, we assign zspage to:
+ *     ZS_ALMOST_FULL  when n > N / f
+ *     ZS_EMPTY        when n == 0
+ *     ZS_FULL         when n == N
+ *
+ * (see: fix_fullness_group())
+ */
+static const int fullness_threshold_frac = 4;
+
+struct size_class {
+       /*
+        * Size of objects stored in this class. Must be multiple
+        * of ZS_ALIGN.
+        */
+       int size;
+       unsigned int index;
+
+       /* Number of PAGE_SIZE sized pages to combine to form a 'zspage' */
+       int pages_per_zspage;
+
+       spinlock_t lock;
+
+       /* stats */
+       u64 pages_allocated;
+
+       struct page *fullness_list[_ZS_NR_FULLNESS_GROUPS];
+};
+
+/*
+ * Placed within free objects to form a singly linked list.
+ * For every zspage, first_page->freelist gives head of this list.
+ *
+ * This must be power of 2 and less than or equal to ZS_ALIGN
+ */
+struct link_free {
+       /* Handle of next free chunk (encodes <PFN, obj_idx>) */
+       void *next;
+};
+
+struct zs_pool {
+       struct size_class size_class[ZS_SIZE_CLASSES];
+
+       gfp_t flags;    /* allocation flags used when growing pool */
+       const char *name;
+};
 
 /*
  * A zspage's class index and fullness group
 #define CLASS_IDX_MASK ((1 << CLASS_IDX_BITS) - 1)
 #define FULLNESS_MASK  ((1 << FULLNESS_BITS) - 1)
 
+/*
+ * By default, zsmalloc uses a copy-based object mapping method to access
+ * allocations that span two pages. However, if a particular architecture
+ * 1) Implements local_flush_tlb_kernel_range() and 2) Performs VM mapping
+ * faster than copying, then it should be added here so that
+ * USE_PGTABLE_MAPPING is defined. This causes zsmalloc to use page table
+ * mapping rather than copying
+ * for object mapping.
+*/
+#if defined(CONFIG_ARM)
+#define USE_PGTABLE_MAPPING
+#endif
+
+struct mapping_area {
+#ifdef USE_PGTABLE_MAPPING
+       struct vm_struct *vm; /* vm area for mapping object that span pages */
+#else
+       char *vm_buf; /* copy buffer for objects that span pages */
+#endif
+       char *vm_addr; /* address of kmap_atomic()'ed pages */
+       enum zs_mapmode vm_mm; /* mapping mode */
+};
+
+
 /* per-cpu VM mapping areas for zspage accesses that cross page boundaries */
 static DEFINE_PER_CPU(struct mapping_area, zs_map_area);
 
@@ -470,16 +625,83 @@ static struct page *find_get_zspage(struct size_class *class)
        return page;
 }
 
-static void zs_copy_map_object(char *buf, struct page *firstpage,
-                               int off, int size)
+#ifdef USE_PGTABLE_MAPPING
+static inline int __zs_cpu_up(struct mapping_area *area)
+{
+       /*
+        * Make sure we don't leak memory if a cpu UP notification
+        * and zs_init() race and both call zs_cpu_up() on the same cpu
+        */
+       if (area->vm)
+               return 0;
+       area->vm = alloc_vm_area(PAGE_SIZE * 2, NULL);
+       if (!area->vm)
+               return -ENOMEM;
+       return 0;
+}
+
+static inline void __zs_cpu_down(struct mapping_area *area)
+{
+       if (area->vm)
+               free_vm_area(area->vm);
+       area->vm = NULL;
+}
+
+static inline void *__zs_map_object(struct mapping_area *area,
+                               struct page *pages[2], int off, int size)
+{
+       BUG_ON(map_vm_area(area->vm, PAGE_KERNEL, &pages));
+       area->vm_addr = area->vm->addr;
+       return area->vm_addr + off;
+}
+
+static inline void __zs_unmap_object(struct mapping_area *area,
+                               struct page *pages[2], int off, int size)
+{
+       unsigned long addr = (unsigned long)area->vm_addr;
+       unsigned long end = addr + (PAGE_SIZE * 2);
+
+       flush_cache_vunmap(addr, end);
+       unmap_kernel_range_noflush(addr, PAGE_SIZE * 2);
+       local_flush_tlb_kernel_range(addr, end);
+}
+
+#else /* USE_PGTABLE_MAPPING */
+
+static inline int __zs_cpu_up(struct mapping_area *area)
+{
+       /*
+        * Make sure we don't leak memory if a cpu UP notification
+        * and zs_init() race and both call zs_cpu_up() on the same cpu
+        */
+       if (area->vm_buf)
+               return 0;
+       area->vm_buf = (char *)__get_free_page(GFP_KERNEL);
+       if (!area->vm_buf)
+               return -ENOMEM;
+       return 0;
+}
+
+static inline void __zs_cpu_down(struct mapping_area *area)
+{
+       if (area->vm_buf)
+               free_page((unsigned long)area->vm_buf);
+       area->vm_buf = NULL;
+}
+
+static void *__zs_map_object(struct mapping_area *area,
+                       struct page *pages[2], int off, int size)
 {
-       struct page *pages[2];
        int sizes[2];
        void *addr;
+       char *buf = area->vm_buf;
 
-       pages[0] = firstpage;
-       pages[1] = get_next_page(firstpage);
-       BUG_ON(!pages[1]);
+       /* disable page faults to match kmap_atomic() return conditions */
+       pagefault_disable();
+
+       /* no read fastpath */
+       if (area->vm_mm == ZS_MM_WO)
+               goto out;
 
        sizes[0] = PAGE_SIZE - off;
        sizes[1] = size - sizes[0];
@@ -491,18 +713,20 @@ static void zs_copy_map_object(char *buf, struct page *firstpage,
        addr = kmap_atomic(pages[1]);
        memcpy(buf + sizes[0], addr, sizes[1]);
        kunmap_atomic(addr);
+out:
+       return area->vm_buf;
 }
 
-static void zs_copy_unmap_object(char *buf, struct page *firstpage,
-                               int off, int size)
+static void __zs_unmap_object(struct mapping_area *area,
+                       struct page *pages[2], int off, int size)
 {
-       struct page *pages[2];
        int sizes[2];
        void *addr;
+       char *buf = area->vm_buf;
 
-       pages[0] = firstpage;
-       pages[1] = get_next_page(firstpage);
-       BUG_ON(!pages[1]);
+       /* no write fastpath */
+       if (area->vm_mm == ZS_MM_RO)
+               goto out;
 
        sizes[0] = PAGE_SIZE - off;
        sizes[1] = size - sizes[0];
@@ -514,34 +738,31 @@ static void zs_copy_unmap_object(char *buf, struct page *firstpage,
        addr = kmap_atomic(pages[1]);
        memcpy(addr, buf + sizes[0], sizes[1]);
        kunmap_atomic(addr);
+
+out:
+       /* enable page faults to match kunmap_atomic() return conditions */
+       pagefault_enable();
 }
 
+#endif /* USE_PGTABLE_MAPPING */
+
 static int zs_cpu_notifier(struct notifier_block *nb, unsigned long action,
                                void *pcpu)
 {
-       int cpu = (long)pcpu;
+       int ret, cpu = (long)pcpu;
        struct mapping_area *area;
 
        switch (action) {
        case CPU_UP_PREPARE:
                area = &per_cpu(zs_map_area, cpu);
-               /*
-                * Make sure we don't leak memory if a cpu UP notification
-                * and zs_init() race and both call zs_cpu_up() on the same cpu
-                */
-               if (area->vm_buf)
-                       return 0;
-               area->vm_buf = (char *)__get_free_page(GFP_KERNEL);
-               if (!area->vm_buf)
-                       return -ENOMEM;
-               return 0;
+               ret = __zs_cpu_up(area);
+               if (ret)
+                       return notifier_from_errno(ret);
                break;
        case CPU_DEAD:
        case CPU_UP_CANCELED:
                area = &per_cpu(zs_map_area, cpu);
-               if (area->vm_buf)
-                       free_page((unsigned long)area->vm_buf);
-               area->vm_buf = NULL;
+               __zs_cpu_down(area);
                break;
        }
 
@@ -758,28 +979,36 @@ void *zs_map_object(struct zs_pool *pool, unsigned long handle,
        enum fullness_group fg;
        struct size_class *class;
        struct mapping_area *area;
+       struct page *pages[2];
 
        BUG_ON(!handle);
 
+       /*
+        * Because we use per-cpu mapping areas shared among the
+        * pools/users, we can't allow mapping in interrupt context
+        * because it can corrupt another users mappings.
+        */
+       BUG_ON(in_interrupt());
+
        obj_handle_to_location(handle, &page, &obj_idx);
        get_zspage_mapping(get_first_page(page), &class_idx, &fg);
        class = &pool->size_class[class_idx];
        off = obj_idx_to_offset(page, obj_idx, class->size);
 
        area = &get_cpu_var(zs_map_area);
+       area->vm_mm = mm;
        if (off + class->size <= PAGE_SIZE) {
                /* this object is contained entirely within a page */
                area->vm_addr = kmap_atomic(page);
                return area->vm_addr + off;
        }
 
-       /* disable page faults to match kmap_atomic() return conditions */
-       pagefault_disable();
+       /* this object spans two pages */
+       pages[0] = page;
+       pages[1] = get_next_page(page);
+       BUG_ON(!pages[1]);
 
-       if (mm != ZS_MM_WO)
-               zs_copy_map_object(area->vm_buf, page, off, class->size);
-       area->vm_addr = NULL;
-       return area->vm_buf;
+       return __zs_map_object(area, pages, off, class->size);
 }
 EXPORT_SYMBOL_GPL(zs_map_object);
 
@@ -793,17 +1022,6 @@ void zs_unmap_object(struct zs_pool *pool, unsigned long handle)
        struct size_class *class;
        struct mapping_area *area;
 
-       area = &__get_cpu_var(zs_map_area);
-       /* single-page object fastpath */
-       if (area->vm_addr) {
-               kunmap_atomic(area->vm_addr);
-               goto out;
-       }
-
-       /* no write fastpath */
-       if (area->vm_mm == ZS_MM_RO)
-               goto pfenable;
-
        BUG_ON(!handle);
 
        obj_handle_to_location(handle, &page, &obj_idx);
@@ -811,12 +1029,18 @@ void zs_unmap_object(struct zs_pool *pool, unsigned long handle)
        class = &pool->size_class[class_idx];
        off = obj_idx_to_offset(page, obj_idx, class->size);
 
-       zs_copy_unmap_object(area->vm_buf, page, off, class->size);
+       area = &__get_cpu_var(zs_map_area);
+       if (off + class->size <= PAGE_SIZE)
+               kunmap_atomic(area->vm_addr);
+       else {
+               struct page *pages[2];
 
-pfenable:
-       /* enable page faults to match kunmap_atomic() return conditions */
-       pagefault_enable();
-out:
+               pages[0] = page;
+               pages[1] = get_next_page(page);
+               BUG_ON(!pages[1]);
+
+               __zs_unmap_object(area, pages, off, class->size);
+       }
        put_cpu_var(zs_map_area);
 }
 EXPORT_SYMBOL_GPL(zs_unmap_object);
diff --git a/drivers/staging/zsmalloc/zsmalloc_int.h b/drivers/staging/zsmalloc/zsmalloc_int.h
deleted file mode 100644 (file)
index 5280517..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * zsmalloc memory allocator
- *
- * Copyright (C) 2011  Nitin Gupta
- *
- * This code is released using a dual license strategy: BSD/GPL
- * You can choose the license that better fits your requirements.
- *
- * Released under the terms of 3-clause BSD License
- * Released under the terms of GNU General Public License Version 2.0
- */
-
-#ifndef _ZS_MALLOC_INT_H_
-#define _ZS_MALLOC_INT_H_
-
-#include <linux/kernel.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-
-/*
- * This must be power of 2 and greater than of equal to sizeof(link_free).
- * These two conditions ensure that any 'struct link_free' itself doesn't
- * span more than 1 page which avoids complex case of mapping 2 pages simply
- * to restore link_free pointer values.
- */
-#define ZS_ALIGN               8
-
-/*
- * A single 'zspage' is composed of up to 2^N discontiguous 0-order (single)
- * pages. ZS_MAX_ZSPAGE_ORDER defines upper limit on N.
- */
-#define ZS_MAX_ZSPAGE_ORDER 2
-#define ZS_MAX_PAGES_PER_ZSPAGE (_AC(1, UL) << ZS_MAX_ZSPAGE_ORDER)
-
-/*
- * Object location (<PFN>, <obj_idx>) is encoded as
- * as single (void *) handle value.
- *
- * Note that object index <obj_idx> is relative to system
- * page <PFN> it is stored in, so for each sub-page belonging
- * to a zspage, obj_idx starts with 0.
- *
- * This is made more complicated by various memory models and PAE.
- */
-
-#ifndef MAX_PHYSMEM_BITS
-#ifdef CONFIG_HIGHMEM64G
-#define MAX_PHYSMEM_BITS 36
-#else /* !CONFIG_HIGHMEM64G */
-/*
- * If this definition of MAX_PHYSMEM_BITS is used, OBJ_INDEX_BITS will just
- * be PAGE_SHIFT
- */
-#define MAX_PHYSMEM_BITS BITS_PER_LONG
-#endif
-#endif
-#define _PFN_BITS              (MAX_PHYSMEM_BITS - PAGE_SHIFT)
-#define OBJ_INDEX_BITS (BITS_PER_LONG - _PFN_BITS)
-#define OBJ_INDEX_MASK ((_AC(1, UL) << OBJ_INDEX_BITS) - 1)
-
-#define MAX(a, b) ((a) >= (b) ? (a) : (b))
-/* ZS_MIN_ALLOC_SIZE must be multiple of ZS_ALIGN */
-#define ZS_MIN_ALLOC_SIZE \
-       MAX(32, (ZS_MAX_PAGES_PER_ZSPAGE << PAGE_SHIFT >> OBJ_INDEX_BITS))
-#define ZS_MAX_ALLOC_SIZE      PAGE_SIZE
-
-/*
- * On systems with 4K page size, this gives 254 size classes! There is a
- * trader-off here:
- *  - Large number of size classes is potentially wasteful as free page are
- *    spread across these classes
- *  - Small number of size classes causes large internal fragmentation
- *  - Probably its better to use specific size classes (empirically
- *    determined). NOTE: all those class sizes must be set as multiple of
- *    ZS_ALIGN to make sure link_free itself never has to span 2 pages.
- *
- *  ZS_MIN_ALLOC_SIZE and ZS_SIZE_CLASS_DELTA must be multiple of ZS_ALIGN
- *  (reason above)
- */
-#define ZS_SIZE_CLASS_DELTA    16
-#define ZS_SIZE_CLASSES                ((ZS_MAX_ALLOC_SIZE - ZS_MIN_ALLOC_SIZE) / \
-                                       ZS_SIZE_CLASS_DELTA + 1)
-
-/*
- * We do not maintain any list for completely empty or full pages
- */
-enum fullness_group {
-       ZS_ALMOST_FULL,
-       ZS_ALMOST_EMPTY,
-       _ZS_NR_FULLNESS_GROUPS,
-
-       ZS_EMPTY,
-       ZS_FULL
-};
-
-/*
- * We assign a page to ZS_ALMOST_EMPTY fullness group when:
- *     n <= N / f, where
- * n = number of allocated objects
- * N = total number of objects zspage can store
- * f = 1/fullness_threshold_frac
- *
- * Similarly, we assign zspage to:
- *     ZS_ALMOST_FULL  when n > N / f
- *     ZS_EMPTY        when n == 0
- *     ZS_FULL         when n == N
- *
- * (see: fix_fullness_group())
- */
-static const int fullness_threshold_frac = 4;
-
-struct mapping_area {
-       char *vm_buf; /* copy buffer for objects that span pages */
-       char *vm_addr; /* address of kmap_atomic()'ed pages */
-       enum zs_mapmode vm_mm; /* mapping mode */
-};
-
-struct size_class {
-       /*
-        * Size of objects stored in this class. Must be multiple
-        * of ZS_ALIGN.
-        */
-       int size;
-       unsigned int index;
-
-       /* Number of PAGE_SIZE sized pages to combine to form a 'zspage' */
-       int pages_per_zspage;
-
-       spinlock_t lock;
-
-       /* stats */
-       u64 pages_allocated;
-
-       struct page *fullness_list[_ZS_NR_FULLNESS_GROUPS];
-};
-
-/*
- * Placed within free objects to form a singly linked list.
- * For every zspage, first_page->freelist gives head of this list.
- *
- * This must be power of 2 and less than or equal to ZS_ALIGN
- */
-struct link_free {
-       /* Handle of next free chunk (encodes <PFN, obj_idx>) */
-       void *next;
-};
-
-struct zs_pool {
-       struct size_class size_class[ZS_SIZE_CLASSES];
-
-       gfp_t flags;    /* allocation flags used when growing pool */
-       const char *name;
-};
-
-#endif
index 3ab2bd540b547814d80d1e090bf171867c9d7dde..7dd8c34552e17a992b9e71d7dda63ba1ad0ac68e 100644 (file)
@@ -27,3 +27,11 @@ config SPEAR_THERMAL
        help
          Enable this to plug the SPEAr thermal sensor driver into the Linux
          thermal framework
+
+config RCAR_THERMAL
+       tristate "Renesas R-Car thermal driver"
+       depends on THERMAL
+       depends on ARCH_SHMOBILE
+       help
+         Enable this to plug the R-Car thermal sensor driver into the Linux
+         thermal framework
index a9fff0bf4b1486f8754d3168f8b6724752f0553f..fd9369aeb96f2704c7d8819d5da80159e99fab59 100644 (file)
@@ -3,4 +3,5 @@
 #
 
 obj-$(CONFIG_THERMAL)          += thermal_sys.o
-obj-$(CONFIG_SPEAR_THERMAL)            += spear_thermal.o
\ No newline at end of file
+obj-$(CONFIG_SPEAR_THERMAL)            += spear_thermal.o
+obj-$(CONFIG_RCAR_THERMAL)     += rcar_thermal.o
diff --git a/drivers/thermal/rcar_thermal.c b/drivers/thermal/rcar_thermal.c
new file mode 100644 (file)
index 0000000..d445271
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ *  R-Car THS/TSC thermal sensor driver
+ *
+ * Copyright (C) 2012 Renesas Solutions Corp.
+ * Kuninori Morimoto <kuninori.morimoto.gx@renesas.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.
+ *
+ *  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/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/thermal.h>
+
+#define THSCR  0x2c
+#define THSSR  0x30
+
+/* THSCR */
+#define CPTAP  0xf
+
+/* THSSR */
+#define CTEMP  0x3f
+
+
+struct rcar_thermal_priv {
+       void __iomem *base;
+       struct device *dev;
+       spinlock_t lock;
+       u32 comp;
+};
+
+/*
+ *             basic functions
+ */
+static u32 rcar_thermal_read(struct rcar_thermal_priv *priv, u32 reg)
+{
+       unsigned long flags;
+       u32 ret;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       ret = ioread32(priv->base + reg);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+
+       return ret;
+}
+
+#if 0 /* no user at this point */
+static void rcar_thermal_write(struct rcar_thermal_priv *priv,
+                              u32 reg, u32 data)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       iowrite32(data, priv->base + reg);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+}
+#endif
+
+static void rcar_thermal_bset(struct rcar_thermal_priv *priv, u32 reg,
+                             u32 mask, u32 data)
+{
+       unsigned long flags;
+       u32 val;
+
+       spin_lock_irqsave(&priv->lock, flags);
+
+       val = ioread32(priv->base + reg);
+       val &= ~mask;
+       val |= (data & mask);
+       iowrite32(val, priv->base + reg);
+
+       spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+/*
+ *             zone device functions
+ */
+static int rcar_thermal_get_temp(struct thermal_zone_device *zone,
+                          unsigned long *temp)
+{
+       struct rcar_thermal_priv *priv = zone->devdata;
+       int val, min, max, tmp;
+
+       tmp = -200; /* default */
+       while (1) {
+               if (priv->comp < 1 || priv->comp > 12) {
+                       dev_err(priv->dev,
+                               "THSSR invalid data (%d)\n", priv->comp);
+                       priv->comp = 4; /* for next thermal */
+                       return -EINVAL;
+               }
+
+               /*
+                * THS comparator offset and the reference temperature
+                *
+                * Comparator   | reference     | Temperature field
+                * offset       | temperature   | measurement
+                *              | (degrees C)   | (degrees C)
+                * -------------+---------------+-------------------
+                *  1           |  -45          |  -45 to  -30
+                *  2           |  -30          |  -30 to  -15
+                *  3           |  -15          |  -15 to    0
+                *  4           |    0          |    0 to  +15
+                *  5           |  +15          |  +15 to  +30
+                *  6           |  +30          |  +30 to  +45
+                *  7           |  +45          |  +45 to  +60
+                *  8           |  +60          |  +60 to  +75
+                *  9           |  +75          |  +75 to  +90
+                * 10           |  +90          |  +90 to +105
+                * 11           | +105          | +105 to +120
+                * 12           | +120          | +120 to +135
+                */
+
+               /* calculate thermal limitation */
+               min = (priv->comp * 15) - 60;
+               max = min + 15;
+
+               /*
+                * we need to wait 300us after changing comparator offset
+                * to get stable temperature.
+                * see "Usage Notes" on datasheet
+                */
+               rcar_thermal_bset(priv, THSCR, CPTAP, priv->comp);
+               udelay(300);
+
+               /* calculate current temperature */
+               val = rcar_thermal_read(priv, THSSR) & CTEMP;
+               val = (val * 5) - 65;
+
+               dev_dbg(priv->dev, "comp/min/max/val = %d/%d/%d/%d\n",
+                       priv->comp, min, max, val);
+
+               /*
+                * If val is same as min/max, then,
+                * it should try again on next comparator.
+                * But the val might be correct temperature.
+                * Keep it on "tmp" and compare with next val.
+                */
+               if (tmp == val)
+                       break;
+
+               if (val <= min) {
+                       tmp = min;
+                       priv->comp--; /* try again */
+               } else if (val >= max) {
+                       tmp = max;
+                       priv->comp++; /* try again */
+               } else {
+                       tmp = val;
+                       break;
+               }
+       }
+
+       *temp = tmp;
+       return 0;
+}
+
+static struct thermal_zone_device_ops rcar_thermal_zone_ops = {
+       .get_temp = rcar_thermal_get_temp,
+};
+
+/*
+ *             platform functions
+ */
+static int rcar_thermal_probe(struct platform_device *pdev)
+{
+       struct thermal_zone_device *zone;
+       struct rcar_thermal_priv *priv;
+       struct resource *res;
+       int ret;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "Could not get platform resource\n");
+               return -ENODEV;
+       }
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv) {
+               dev_err(&pdev->dev, "Could not allocate priv\n");
+               return -ENOMEM;
+       }
+
+       priv->comp = 4; /* basic setup */
+       priv->dev = &pdev->dev;
+       spin_lock_init(&priv->lock);
+       priv->base = devm_ioremap_nocache(&pdev->dev,
+                                         res->start, resource_size(res));
+       if (!priv->base) {
+               dev_err(&pdev->dev, "Unable to ioremap thermal register\n");
+               ret = -ENOMEM;
+               goto error_free_priv;
+       }
+
+       zone = thermal_zone_device_register("rcar_thermal", 0, priv,
+                                           &rcar_thermal_zone_ops, 0, 0);
+       if (IS_ERR(zone)) {
+               dev_err(&pdev->dev, "thermal zone device is NULL\n");
+               ret = PTR_ERR(zone);
+               goto error_iounmap;
+       }
+
+       platform_set_drvdata(pdev, zone);
+
+       dev_info(&pdev->dev, "proved\n");
+
+       return 0;
+
+error_iounmap:
+       devm_iounmap(&pdev->dev, priv->base);
+error_free_priv:
+       devm_kfree(&pdev->dev, priv);
+
+       return ret;
+}
+
+static int rcar_thermal_remove(struct platform_device *pdev)
+{
+       struct thermal_zone_device *zone = platform_get_drvdata(pdev);
+       struct rcar_thermal_priv *priv = zone->devdata;
+
+       thermal_zone_device_unregister(zone);
+       platform_set_drvdata(pdev, NULL);
+
+       devm_iounmap(&pdev->dev, priv->base);
+       devm_kfree(&pdev->dev, priv);
+
+       return 0;
+}
+
+static struct platform_driver rcar_thermal_driver = {
+       .driver = {
+               .name   = "rcar_thermal",
+       },
+       .probe          = rcar_thermal_probe,
+       .remove         = rcar_thermal_remove,
+};
+module_platform_driver(rcar_thermal_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("R-Car THS/TSC thermal sensor driver");
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
index 5f8ee39f200027c729879e31f4039ae8cd54fd38..9bc969261d011225f603971ed3a0b9a44b64b2a2 100644 (file)
@@ -147,7 +147,7 @@ static int spear_thermal_probe(struct platform_device *pdev)
        writel_relaxed(stdev->flags, stdev->thermal_base);
 
        spear_thermal = thermal_zone_device_register("spear_thermal", 0, 0,
-                               stdev, &ops, 0, 0, 0, 0);
+                               stdev, &ops, 0, 0);
        if (IS_ERR(spear_thermal)) {
                dev_err(&pdev->dev, "thermal zone device is NULL\n");
                ret = PTR_ERR(spear_thermal);
index 2ab31e4f02cc741ee5d7b1c603a9158b34f335c4..d552a96f08cd1bf1abd12f2977a5ffd35eef6da5 100644 (file)
@@ -41,15 +41,25 @@ MODULE_AUTHOR("Zhang Rui");
 MODULE_DESCRIPTION("Generic thermal management sysfs support");
 MODULE_LICENSE("GPL");
 
-struct thermal_cooling_device_instance {
+#define THERMAL_NO_TARGET -1UL
+/*
+ * This structure is used to describe the behavior of
+ * a certain cooling device on a certain trip point
+ * in a certain thermal zone
+ */
+struct thermal_instance {
        int id;
        char name[THERMAL_NAME_LENGTH];
        struct thermal_zone_device *tz;
        struct thermal_cooling_device *cdev;
        int trip;
+       unsigned long upper;    /* Highest cooling state for this trip point */
+       unsigned long lower;    /* Lowest cooling state for this trip point */
+       unsigned long target;   /* expected cooling state */
        char attr_name[THERMAL_NAME_LENGTH];
        struct device_attribute attr;
-       struct list_head node;
+       struct list_head tz_node; /* node in tz->thermal_instances */
+       struct list_head cdev_node; /* node in cdev->thermal_instances */
 };
 
 static DEFINE_IDR(thermal_tz_idr);
@@ -308,8 +318,9 @@ passive_store(struct device *dev, struct device_attribute *attr,
                        if (!strncmp("Processor", cdev->type,
                                     sizeof("Processor")))
                                thermal_zone_bind_cooling_device(tz,
-                                                                THERMAL_TRIPS_NONE,
-                                                                cdev);
+                                               THERMAL_TRIPS_NONE, cdev,
+                                               THERMAL_NO_LIMIT,
+                                               THERMAL_NO_LIMIT);
                }
                mutex_unlock(&thermal_list_lock);
                if (!tz->passive_delay)
@@ -327,9 +338,6 @@ passive_store(struct device *dev, struct device_attribute *attr,
                tz->passive_delay = 0;
        }
 
-       tz->tc1 = 1;
-       tz->tc2 = 1;
-
        tz->forced_passive = state;
 
        thermal_zone_device_update(tz);
@@ -425,10 +433,10 @@ static ssize_t
 thermal_cooling_device_trip_point_show(struct device *dev,
                                       struct device_attribute *attr, char *buf)
 {
-       struct thermal_cooling_device_instance *instance;
+       struct thermal_instance *instance;
 
        instance =
-           container_of(attr, struct thermal_cooling_device_instance, attr);
+           container_of(attr, struct thermal_instance, attr);
 
        if (instance->trip == THERMAL_TRIPS_NONE)
                return sprintf(buf, "-1\n");
@@ -590,7 +598,7 @@ thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
        temp->tz = tz;
        hwmon->count++;
 
-       snprintf(temp->temp_input.name, THERMAL_NAME_LENGTH,
+       snprintf(temp->temp_input.name, sizeof(temp->temp_input.name),
                 "temp%d_input", hwmon->count);
        temp->temp_input.attr.attr.name = temp->temp_input.name;
        temp->temp_input.attr.attr.mode = 0444;
@@ -603,7 +611,8 @@ thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
        if (tz->ops->get_crit_temp) {
                unsigned long temperature;
                if (!tz->ops->get_crit_temp(tz, &temperature)) {
-                       snprintf(temp->temp_crit.name, THERMAL_NAME_LENGTH,
+                       snprintf(temp->temp_crit.name,
+                                sizeof(temp->temp_crit.name),
                                "temp%d_crit", hwmon->count);
                        temp->temp_crit.attr.attr.name = temp->temp_crit.name;
                        temp->temp_crit.attr.attr.mode = 0444;
@@ -694,85 +703,14 @@ thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
 static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
                                            int delay)
 {
-       cancel_delayed_work(&(tz->poll_queue));
-
-       if (!delay)
-               return;
-
        if (delay > 1000)
-               queue_delayed_work(system_freezable_wq, &(tz->poll_queue),
-                                     round_jiffies(msecs_to_jiffies(delay)));
+               mod_delayed_work(system_freezable_wq, &tz->poll_queue,
+                                round_jiffies(msecs_to_jiffies(delay)));
+       else if (delay)
+               mod_delayed_work(system_freezable_wq, &tz->poll_queue,
+                                msecs_to_jiffies(delay));
        else
-               queue_delayed_work(system_freezable_wq, &(tz->poll_queue),
-                                     msecs_to_jiffies(delay));
-}
-
-static void thermal_zone_device_passive(struct thermal_zone_device *tz,
-                                       int temp, int trip_temp, int trip)
-{
-       int trend = 0;
-       struct thermal_cooling_device_instance *instance;
-       struct thermal_cooling_device *cdev;
-       long state, max_state;
-
-       /*
-        * Above Trip?
-        * -----------
-        * Calculate the thermal trend (using the passive cooling equation)
-        * and modify the performance limit for all passive cooling devices
-        * accordingly.  Note that we assume symmetry.
-        */
-       if (temp >= trip_temp) {
-               tz->passive = true;
-
-               trend = (tz->tc1 * (temp - tz->last_temperature)) +
-                       (tz->tc2 * (temp - trip_temp));
-
-               /* Heating up? */
-               if (trend > 0) {
-                       list_for_each_entry(instance, &tz->cooling_devices,
-                                           node) {
-                               if (instance->trip != trip)
-                                       continue;
-                               cdev = instance->cdev;
-                               cdev->ops->get_cur_state(cdev, &state);
-                               cdev->ops->get_max_state(cdev, &max_state);
-                               if (state++ < max_state)
-                                       cdev->ops->set_cur_state(cdev, state);
-                       }
-               } else if (trend < 0) { /* Cooling off? */
-                       list_for_each_entry(instance, &tz->cooling_devices,
-                                           node) {
-                               if (instance->trip != trip)
-                                       continue;
-                               cdev = instance->cdev;
-                               cdev->ops->get_cur_state(cdev, &state);
-                               cdev->ops->get_max_state(cdev, &max_state);
-                               if (state > 0)
-                                       cdev->ops->set_cur_state(cdev, --state);
-                       }
-               }
-               return;
-       }
-
-       /*
-        * Below Trip?
-        * -----------
-        * Implement passive cooling hysteresis to slowly increase performance
-        * and avoid thrashing around the passive trip point.  Note that we
-        * assume symmetry.
-        */
-       list_for_each_entry(instance, &tz->cooling_devices, node) {
-               if (instance->trip != trip)
-                       continue;
-               cdev = instance->cdev;
-               cdev->ops->get_cur_state(cdev, &state);
-               cdev->ops->get_max_state(cdev, &max_state);
-               if (state > 0)
-                       cdev->ops->set_cur_state(cdev, --state);
-               if (state == 0)
-                       tz->passive = false;
-       }
+               cancel_delayed_work(&tz->poll_queue);
 }
 
 static void thermal_zone_device_check(struct work_struct *work)
@@ -794,12 +732,14 @@ static void thermal_zone_device_check(struct work_struct *work)
  */
 int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
                                     int trip,
-                                    struct thermal_cooling_device *cdev)
+                                    struct thermal_cooling_device *cdev,
+                                    unsigned long upper, unsigned long lower)
 {
-       struct thermal_cooling_device_instance *dev;
-       struct thermal_cooling_device_instance *pos;
+       struct thermal_instance *dev;
+       struct thermal_instance *pos;
        struct thermal_zone_device *pos1;
        struct thermal_cooling_device *pos2;
+       unsigned long max_state;
        int result;
 
        if (trip >= tz->trips || (trip < 0 && trip != THERMAL_TRIPS_NONE))
@@ -817,13 +757,26 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
        if (tz != pos1 || cdev != pos2)
                return -EINVAL;
 
+       cdev->ops->get_max_state(cdev, &max_state);
+
+       /* lower default 0, upper default max_state */
+       lower = lower == THERMAL_NO_LIMIT ? 0 : lower;
+       upper = upper == THERMAL_NO_LIMIT ? max_state : upper;
+
+       if (lower > upper || upper > max_state)
+               return -EINVAL;
+
        dev =
-           kzalloc(sizeof(struct thermal_cooling_device_instance), GFP_KERNEL);
+           kzalloc(sizeof(struct thermal_instance), GFP_KERNEL);
        if (!dev)
                return -ENOMEM;
        dev->tz = tz;
        dev->cdev = cdev;
        dev->trip = trip;
+       dev->upper = upper;
+       dev->lower = lower;
+       dev->target = THERMAL_NO_TARGET;
+
        result = get_idr(&tz->idr, &tz->lock, &dev->id);
        if (result)
                goto free_mem;
@@ -844,13 +797,17 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
                goto remove_symbol_link;
 
        mutex_lock(&tz->lock);
-       list_for_each_entry(pos, &tz->cooling_devices, node)
+       mutex_lock(&cdev->lock);
+       list_for_each_entry(pos, &tz->thermal_instances, tz_node)
            if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
                result = -EEXIST;
                break;
        }
-       if (!result)
-               list_add_tail(&dev->node, &tz->cooling_devices);
+       if (!result) {
+               list_add_tail(&dev->tz_node, &tz->thermal_instances);
+               list_add_tail(&dev->cdev_node, &cdev->thermal_instances);
+       }
+       mutex_unlock(&cdev->lock);
        mutex_unlock(&tz->lock);
 
        if (!result)
@@ -880,16 +837,20 @@ int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
                                       int trip,
                                       struct thermal_cooling_device *cdev)
 {
-       struct thermal_cooling_device_instance *pos, *next;
+       struct thermal_instance *pos, *next;
 
        mutex_lock(&tz->lock);
-       list_for_each_entry_safe(pos, next, &tz->cooling_devices, node) {
+       mutex_lock(&cdev->lock);
+       list_for_each_entry_safe(pos, next, &tz->thermal_instances, tz_node) {
                if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
-                       list_del(&pos->node);
+                       list_del(&pos->tz_node);
+                       list_del(&pos->cdev_node);
+                       mutex_unlock(&cdev->lock);
                        mutex_unlock(&tz->lock);
                        goto unbind;
                }
        }
+       mutex_unlock(&cdev->lock);
        mutex_unlock(&tz->lock);
 
        return -ENODEV;
@@ -937,7 +898,7 @@ thermal_cooling_device_register(char *type, void *devdata,
        struct thermal_zone_device *pos;
        int result;
 
-       if (strlen(type) >= THERMAL_NAME_LENGTH)
+       if (type && strlen(type) >= THERMAL_NAME_LENGTH)
                return ERR_PTR(-EINVAL);
 
        if (!ops || !ops->get_max_state || !ops->get_cur_state ||
@@ -954,8 +915,11 @@ thermal_cooling_device_register(char *type, void *devdata,
                return ERR_PTR(result);
        }
 
-       strcpy(cdev->type, type);
+       strcpy(cdev->type, type ? : "");
+       mutex_init(&cdev->lock);
+       INIT_LIST_HEAD(&cdev->thermal_instances);
        cdev->ops = ops;
+       cdev->updated = true;
        cdev->device.class = &thermal_class;
        cdev->devdata = devdata;
        dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
@@ -1047,6 +1011,136 @@ void thermal_cooling_device_unregister(struct
 }
 EXPORT_SYMBOL(thermal_cooling_device_unregister);
 
+static void thermal_cdev_do_update(struct thermal_cooling_device *cdev)
+{
+       struct thermal_instance *instance;
+       unsigned long target = 0;
+
+       /* cooling device is updated*/
+       if (cdev->updated)
+               return;
+
+       mutex_lock(&cdev->lock);
+       /* Make sure cdev enters the deepest cooling state */
+       list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) {
+               if (instance->target == THERMAL_NO_TARGET)
+                       continue;
+               if (instance->target > target)
+                       target = instance->target;
+       }
+       mutex_unlock(&cdev->lock);
+       cdev->ops->set_cur_state(cdev, target);
+       cdev->updated = true;
+}
+
+static void thermal_zone_do_update(struct thermal_zone_device *tz)
+{
+       struct thermal_instance *instance;
+
+       list_for_each_entry(instance, &tz->thermal_instances, tz_node)
+               thermal_cdev_do_update(instance->cdev);
+}
+
+/*
+ * Cooling algorithm for both active and passive cooling
+ *
+ * 1. if the temperature is higher than a trip point,
+ *    a. if the trend is THERMAL_TREND_RAISING, use higher cooling
+ *       state for this trip point
+ *    b. if the trend is THERMAL_TREND_DROPPING, use lower cooling
+ *       state for this trip point
+ *
+ * 2. if the temperature is lower than a trip point, use lower
+ *    cooling state for this trip point
+ *
+ * Note that this behaves the same as the previous passive cooling
+ * algorithm.
+ */
+
+static void thermal_zone_trip_update(struct thermal_zone_device *tz,
+                                    int trip, long temp)
+{
+       struct thermal_instance *instance;
+       struct thermal_cooling_device *cdev = NULL;
+       unsigned long cur_state, max_state;
+       long trip_temp;
+       enum thermal_trip_type trip_type;
+       enum thermal_trend trend;
+
+       if (trip == THERMAL_TRIPS_NONE) {
+               trip_temp = tz->forced_passive;
+               trip_type = THERMAL_TRIPS_NONE;
+       } else {
+               tz->ops->get_trip_temp(tz, trip, &trip_temp);
+               tz->ops->get_trip_type(tz, trip, &trip_type);
+       }
+
+       if (!tz->ops->get_trend || tz->ops->get_trend(tz, trip, &trend)) {
+               /*
+                * compare the current temperature and previous temperature
+                * to get the thermal trend, if no special requirement
+                */
+               if (tz->temperature > tz->last_temperature)
+                       trend = THERMAL_TREND_RAISING;
+               else if (tz->temperature < tz->last_temperature)
+                       trend = THERMAL_TREND_DROPPING;
+               else
+                       trend = THERMAL_TREND_STABLE;
+       }
+
+       if (temp >= trip_temp) {
+               list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
+                       if (instance->trip != trip)
+                               continue;
+
+                       cdev = instance->cdev;
+
+                       cdev->ops->get_cur_state(cdev, &cur_state);
+                       cdev->ops->get_max_state(cdev, &max_state);
+
+                       if (trend == THERMAL_TREND_RAISING) {
+                               cur_state = cur_state < instance->upper ?
+                                           (cur_state + 1) : instance->upper;
+                       } else if (trend == THERMAL_TREND_DROPPING) {
+                               cur_state = cur_state > instance->lower ?
+                                   (cur_state - 1) : instance->lower;
+                       }
+
+                       /* activate a passive thermal instance */
+                       if ((trip_type == THERMAL_TRIP_PASSIVE ||
+                            trip_type == THERMAL_TRIPS_NONE) &&
+                            instance->target == THERMAL_NO_TARGET)
+                               tz->passive++;
+
+                       instance->target = cur_state;
+                       cdev->updated = false; /* cooling device needs update */
+               }
+       } else {        /* below trip */
+               list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
+                       if (instance->trip != trip)
+                               continue;
+
+                       /* Do not use the inactive thermal instance */
+                       if (instance->target == THERMAL_NO_TARGET)
+                               continue;
+                       cdev = instance->cdev;
+                       cdev->ops->get_cur_state(cdev, &cur_state);
+
+                       cur_state = cur_state > instance->lower ?
+                                   (cur_state - 1) : THERMAL_NO_TARGET;
+
+                       /* deactivate a passive thermal instance */
+                       if ((trip_type == THERMAL_TRIP_PASSIVE ||
+                            trip_type == THERMAL_TRIPS_NONE) &&
+                            cur_state == THERMAL_NO_TARGET)
+                               tz->passive--;
+                       instance->target = cur_state;
+                       cdev->updated = false; /* cooling device needs update */
+               }
+       }
+
+       return;
+}
 /**
  * thermal_zone_device_update - force an update of a thermal zone's state
  * @ttz:       the thermal zone to update
@@ -1057,8 +1151,6 @@ void thermal_zone_device_update(struct thermal_zone_device *tz)
        int count, ret = 0;
        long temp, trip_temp;
        enum thermal_trip_type trip_type;
-       struct thermal_cooling_device_instance *instance;
-       struct thermal_cooling_device *cdev;
 
        mutex_lock(&tz->lock);
 
@@ -1068,6 +1160,9 @@ void thermal_zone_device_update(struct thermal_zone_device *tz)
                goto leave;
        }
 
+       tz->last_temperature = tz->temperature;
+       tz->temperature = temp;
+
        for (count = 0; count < tz->trips; count++) {
                tz->ops->get_trip_type(tz, count, &trip_type);
                tz->ops->get_trip_temp(tz, count, &trip_temp);
@@ -1091,32 +1186,18 @@ void thermal_zone_device_update(struct thermal_zone_device *tz)
                                        tz->ops->notify(tz, count, trip_type);
                        break;
                case THERMAL_TRIP_ACTIVE:
-                       list_for_each_entry(instance, &tz->cooling_devices,
-                                           node) {
-                               if (instance->trip != count)
-                                       continue;
-
-                               cdev = instance->cdev;
-
-                               if (temp >= trip_temp)
-                                       cdev->ops->set_cur_state(cdev, 1);
-                               else
-                                       cdev->ops->set_cur_state(cdev, 0);
-                       }
+                       thermal_zone_trip_update(tz, count, temp);
                        break;
                case THERMAL_TRIP_PASSIVE:
                        if (temp >= trip_temp || tz->passive)
-                               thermal_zone_device_passive(tz, temp,
-                                                           trip_temp, count);
+                               thermal_zone_trip_update(tz, count, temp);
                        break;
                }
        }
 
        if (tz->forced_passive)
-               thermal_zone_device_passive(tz, temp, tz->forced_passive,
-                                           THERMAL_TRIPS_NONE);
-
-       tz->last_temperature = temp;
+               thermal_zone_trip_update(tz, THERMAL_TRIPS_NONE, temp);
+       thermal_zone_do_update(tz);
 
 leave:
        if (tz->passive)
@@ -1239,8 +1320,6 @@ static void remove_trip_attrs(struct thermal_zone_device *tz)
  * @mask:      a bit string indicating the writeablility of trip points
  * @devdata:   private device data
  * @ops:       standard thermal zone device callbacks
- * @tc1:       thermal coefficient 1 for passive calculations
- * @tc2:       thermal coefficient 2 for passive calculations
  * @passive_delay: number of milliseconds to wait between polls when
  *                performing passive cooling
  * @polling_delay: number of milliseconds to wait between polls when checking
@@ -1248,13 +1327,12 @@ static void remove_trip_attrs(struct thermal_zone_device *tz)
  *                driven systems)
  *
  * thermal_zone_device_unregister() must be called when the device is no
- * longer needed. The passive cooling formula uses tc1 and tc2 as described in
- * section 11.1.5.1 of the ACPI specification 3.0.
+ * longer needed. The passive cooling depends on the .get_trend() return value.
  */
 struct thermal_zone_device *thermal_zone_device_register(const char *type,
        int trips, int mask, void *devdata,
        const struct thermal_zone_device_ops *ops,
-       int tc1, int tc2, int passive_delay, int polling_delay)
+       int passive_delay, int polling_delay)
 {
        struct thermal_zone_device *tz;
        struct thermal_cooling_device *pos;
@@ -1263,7 +1341,7 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
        int count;
        int passive = 0;
 
-       if (strlen(type) >= THERMAL_NAME_LENGTH)
+       if (type && strlen(type) >= THERMAL_NAME_LENGTH)
                return ERR_PTR(-EINVAL);
 
        if (trips > THERMAL_MAX_TRIPS || trips < 0 || mask >> trips)
@@ -1276,7 +1354,7 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
        if (!tz)
                return ERR_PTR(-ENOMEM);
 
-       INIT_LIST_HEAD(&tz->cooling_devices);
+       INIT_LIST_HEAD(&tz->thermal_instances);
        idr_init(&tz->idr);
        mutex_init(&tz->lock);
        result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
@@ -1285,13 +1363,11 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
                return ERR_PTR(result);
        }
 
-       strcpy(tz->type, type);
+       strcpy(tz->type, type ? : "");
        tz->ops = ops;
        tz->device.class = &thermal_class;
        tz->devdata = devdata;
        tz->trips = trips;
-       tz->tc1 = tc1;
-       tz->tc2 = tc2;
        tz->passive_delay = passive_delay;
        tz->polling_delay = polling_delay;
 
index 830cd62d84925e548cd7480b2d6fb3a4e582a08d..aa99cd26ba8bc4c6ff7ab89e8ecf3357dc4f19a6 100644 (file)
@@ -358,6 +358,7 @@ config TRACE_SINK
 config PPC_EPAPR_HV_BYTECHAN
        tristate "ePAPR hypervisor byte channel driver"
        depends on PPC
+       select EPAPR_PARAVIRT
        help
          This driver creates /dev entries for each ePAPR hypervisor byte
          channel, thereby allowing applications to communicate with byte
index 6cc4358f68c12ad2c779c7837207ce875968cf40..2b7535d42e05fc808d9f3eda9f176b365050c0e9 100644 (file)
@@ -646,7 +646,7 @@ static void shutdown(struct tty_struct *tty, struct serial_state *info)
        custom.adkcon = AC_UARTBRK;
        mb();
 
-       if (tty->termios->c_cflag & HUPCL)
+       if (tty->termios.c_cflag & HUPCL)
                info->MCR &= ~(SER_DTR|SER_RTS);
        rtsdtr_ctrl(info->MCR);
 
@@ -670,7 +670,7 @@ static void change_speed(struct tty_struct *tty, struct serial_state *info,
        int     bits;
        unsigned long   flags;
 
-       cflag = tty->termios->c_cflag;
+       cflag = tty->termios.c_cflag;
 
        /* Byte size is always 8 bits plus parity bit if requested */
 
@@ -707,8 +707,8 @@ static void change_speed(struct tty_struct *tty, struct serial_state *info,
        /* If the quotient is zero refuse the change */
        if (!quot && old_termios) {
                /* FIXME: Will need updating for new tty in the end */
-               tty->termios->c_cflag &= ~CBAUD;
-               tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD);
+               tty->termios.c_cflag &= ~CBAUD;
+               tty->termios.c_cflag |= (old_termios->c_cflag & CBAUD);
                baud = tty_get_baud_rate(tty);
                if (!baud)
                        baud = 9600;
@@ -984,7 +984,7 @@ static void rs_throttle(struct tty_struct * tty)
        if (I_IXOFF(tty))
                rs_send_xchar(tty, STOP_CHAR(tty));
 
-       if (tty->termios->c_cflag & CRTSCTS)
+       if (tty->termios.c_cflag & CRTSCTS)
                info->MCR &= ~SER_RTS;
 
        local_irq_save(flags);
@@ -1012,7 +1012,7 @@ static void rs_unthrottle(struct tty_struct * tty)
                else
                        rs_send_xchar(tty, START_CHAR(tty));
        }
-       if (tty->termios->c_cflag & CRTSCTS)
+       if (tty->termios.c_cflag & CRTSCTS)
                info->MCR |= SER_RTS;
        local_irq_save(flags);
        rtsdtr_ctrl(info->MCR);
@@ -1033,7 +1033,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state,
        if (!retinfo)
                return -EFAULT;
        memset(&tmp, 0, sizeof(tmp));
-       tty_lock();
+       tty_lock(tty);
        tmp.line = tty->index;
        tmp.port = state->port;
        tmp.flags = state->tport.flags;
@@ -1042,7 +1042,7 @@ static int get_serial_info(struct tty_struct *tty, struct serial_state *state,
        tmp.close_delay = state->tport.close_delay;
        tmp.closing_wait = state->tport.closing_wait;
        tmp.custom_divisor = state->custom_divisor;
-       tty_unlock();
+       tty_unlock(tty);
        if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
                return -EFAULT;
        return 0;
@@ -1059,12 +1059,12 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
        if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
                return -EFAULT;
 
-       tty_lock();
+       tty_lock(tty);
        change_spd = ((new_serial.flags ^ port->flags) & ASYNC_SPD_MASK) ||
                new_serial.custom_divisor != state->custom_divisor;
        if (new_serial.irq || new_serial.port != state->port ||
                        new_serial.xmit_fifo_size != state->xmit_fifo_size) {
-               tty_unlock();
+               tty_unlock(tty);
                return -EINVAL;
        }
   
@@ -1074,7 +1074,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
                    (new_serial.xmit_fifo_size != state->xmit_fifo_size) ||
                    ((new_serial.flags & ~ASYNC_USR_MASK) !=
                     (port->flags & ~ASYNC_USR_MASK))) {
-                       tty_unlock();
+                       tty_unlock(tty);
                        return -EPERM;
                }
                port->flags = ((port->flags & ~ASYNC_USR_MASK) |
@@ -1084,7 +1084,7 @@ static int set_serial_info(struct tty_struct *tty, struct serial_state *state,
        }
 
        if (new_serial.baud_base < 9600) {
-               tty_unlock();
+               tty_unlock(tty);
                return -EINVAL;
        }
 
@@ -1116,7 +1116,7 @@ check_and_exit:
                }
        } else
                retval = startup(tty, state);
-       tty_unlock();
+       tty_unlock(tty);
        return retval;
 }
 
@@ -1330,7 +1330,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
 {
        struct serial_state *info = tty->driver_data;
        unsigned long flags;
-       unsigned int cflag = tty->termios->c_cflag;
+       unsigned int cflag = tty->termios.c_cflag;
 
        change_speed(tty, info, old_termios);
 
@@ -1347,7 +1347,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
        if (!(old_termios->c_cflag & CBAUD) &&
            (cflag & CBAUD)) {
                info->MCR |= SER_DTR;
-               if (!(tty->termios->c_cflag & CRTSCTS) || 
+               if (!(tty->termios.c_cflag & CRTSCTS) || 
                    !test_bit(TTY_THROTTLED, &tty->flags)) {
                        info->MCR |= SER_RTS;
                }
@@ -1358,7 +1358,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
 
        /* Handle turning off CRTSCTS */
        if ((old_termios->c_cflag & CRTSCTS) &&
-           !(tty->termios->c_cflag & CRTSCTS)) {
+           !(tty->termios.c_cflag & CRTSCTS)) {
                tty->hw_stopped = 0;
                rs_start(tty);
        }
@@ -1371,7 +1371,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
         * or not.  Hence, this may change.....
         */
        if (!(old_termios->c_cflag & CLOCAL) &&
-           (tty->termios->c_cflag & CLOCAL))
+           (tty->termios.c_cflag & CLOCAL))
                wake_up_interruptible(&info->open_wait);
 #endif
 }
@@ -1710,10 +1710,6 @@ static int __init amiga_serial_probe(struct platform_device *pdev)
        serial_driver->flags = TTY_DRIVER_REAL_RAW;
        tty_set_operations(serial_driver, &serial_ops);
 
-       error = tty_register_driver(serial_driver);
-       if (error)
-               goto fail_put_tty_driver;
-
        state = rs_table;
        state->port = (int)&custom.serdatr; /* Just to give it a value */
        state->custom_divisor = 0;
@@ -1724,6 +1720,11 @@ static int __init amiga_serial_probe(struct platform_device *pdev)
        state->icount.overrun = state->icount.brk = 0;
        tty_port_init(&state->tport);
        state->tport.ops = &amiga_port_ops;
+       tty_port_link_device(&state->tport, serial_driver, 0);
+
+       error = tty_register_driver(serial_driver);
+       if (error)
+               goto fail_put_tty_driver;
 
        printk(KERN_INFO "ttyS0 is the amiga builtin serial port\n");
 
index 61fc74fe17473d56e2f2fe18bca2dee83dd27bac..02b7d3a09696cc6683c51fb9d02866d1ce75999b 100644 (file)
@@ -263,6 +263,7 @@ static int __init bfin_jc_init(void)
        bfin_jc_driver->subtype      = SERIAL_TYPE_NORMAL;
        bfin_jc_driver->init_termios = tty_std_termios;
        tty_set_operations(bfin_jc_driver, &bfin_jc_ops);
+       tty_port_link_device(&port, bfin_jc_driver, 0);
 
        ret = tty_register_driver(bfin_jc_driver);
        if (ret)
index e61cabdd69df36d56ea0c0cd27fcaeadc488f8de..e3954dae50641026943b8497f7eae8a357a54350 100644 (file)
@@ -1459,7 +1459,7 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
                        info->port.xmit_buf = NULL;
                        free_page((unsigned long)temp);
                }
-               if (tty->termios->c_cflag & HUPCL)
+               if (tty->termios.c_cflag & HUPCL)
                        cyy_change_rts_dtr(info, 0, TIOCM_RTS | TIOCM_DTR);
 
                cyy_issue_cmd(info, CyCHAN_CTL | CyDIS_RCVR);
@@ -1488,7 +1488,7 @@ static void cy_shutdown(struct cyclades_port *info, struct tty_struct *tty)
                        free_page((unsigned long)temp);
                }
 
-               if (tty->termios->c_cflag & HUPCL)
+               if (tty->termios.c_cflag & HUPCL)
                        tty_port_lower_dtr_rts(&info->port);
 
                set_bit(TTY_IO_ERROR, &tty->flags);
@@ -1599,7 +1599,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
         * If the port is the middle of closing, bail out now
         */
        if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) {
-               wait_event_interruptible_tty(info->port.close_wait,
+               wait_event_interruptible_tty(tty, info->port.close_wait,
                                !(info->port.flags & ASYNC_CLOSING));
                return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS;
        }
@@ -1999,14 +1999,11 @@ static void cy_set_line_char(struct cyclades_port *info, struct tty_struct *tty)
        int baud, baud_rate = 0;
        int i;
 
-       if (!tty->termios) /* XXX can this happen at all? */
-               return;
-
        if (info->line == -1)
                return;
 
-       cflag = tty->termios->c_cflag;
-       iflag = tty->termios->c_iflag;
+       cflag = tty->termios.c_cflag;
+       iflag = tty->termios.c_iflag;
 
        /*
         * Set up the tty->alt_speed kludge
@@ -2825,7 +2822,7 @@ static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
        cy_set_line_char(info, tty);
 
        if ((old_termios->c_cflag & CRTSCTS) &&
-                       !(tty->termios->c_cflag & CRTSCTS)) {
+                       !(tty->termios.c_cflag & CRTSCTS)) {
                tty->hw_stopped = 0;
                cy_start(tty);
        }
@@ -2837,7 +2834,7 @@ static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
         * or not.  Hence, this may change.....
         */
        if (!(old_termios->c_cflag & CLOCAL) &&
-           (tty->termios->c_cflag & CLOCAL))
+           (tty->termios.c_cflag & CLOCAL))
                wake_up_interruptible(&info->port.open_wait);
 #endif
 }                              /* cy_set_termios */
@@ -2899,7 +2896,7 @@ static void cy_throttle(struct tty_struct *tty)
                        info->throttle = 1;
        }
 
-       if (tty->termios->c_cflag & CRTSCTS) {
+       if (tty->termios.c_cflag & CRTSCTS) {
                if (!cy_is_Z(card)) {
                        spin_lock_irqsave(&card->card_lock, flags);
                        cyy_change_rts_dtr(info, 0, TIOCM_RTS);
@@ -2938,7 +2935,7 @@ static void cy_unthrottle(struct tty_struct *tty)
                        cy_send_xchar(tty, START_CHAR(tty));
        }
 
-       if (tty->termios->c_cflag & CRTSCTS) {
+       if (tty->termios.c_cflag & CRTSCTS) {
                card = info->card;
                if (!cy_is_Z(card)) {
                        spin_lock_irqsave(&card->card_lock, flags);
@@ -3289,9 +3286,10 @@ static unsigned short __devinit cyy_init_card(void __iomem *true_base_addr,
 static int __init cy_detect_isa(void)
 {
 #ifdef CONFIG_ISA
+       struct cyclades_card *card;
        unsigned short cy_isa_irq, nboard;
        void __iomem *cy_isa_address;
-       unsigned short i, j, cy_isa_nchan;
+       unsigned short i, j, k, cy_isa_nchan;
        int isparam = 0;
 
        nboard = 0;
@@ -3349,7 +3347,8 @@ static int __init cy_detect_isa(void)
                }
                /* fill the next cy_card structure available */
                for (j = 0; j < NR_CARDS; j++) {
-                       if (cy_card[j].base_addr == NULL)
+                       card = &cy_card[j];
+                       if (card->base_addr == NULL)
                                break;
                }
                if (j == NR_CARDS) {    /* no more cy_cards available */
@@ -3363,7 +3362,7 @@ static int __init cy_detect_isa(void)
 
                /* allocate IRQ */
                if (request_irq(cy_isa_irq, cyy_interrupt,
-                               0, "Cyclom-Y", &cy_card[j])) {
+                               0, "Cyclom-Y", card)) {
                        printk(KERN_ERR "Cyclom-Y/ISA found at 0x%lx, but "
                                "could not allocate IRQ#%d.\n",
                                (unsigned long)cy_isa_address, cy_isa_irq);
@@ -3372,16 +3371,16 @@ static int __init cy_detect_isa(void)
                }
 
                /* set cy_card */
-               cy_card[j].base_addr = cy_isa_address;
-               cy_card[j].ctl_addr.p9050 = NULL;
-               cy_card[j].irq = (int)cy_isa_irq;
-               cy_card[j].bus_index = 0;
-               cy_card[j].first_line = cy_next_channel;
-               cy_card[j].num_chips = cy_isa_nchan / CyPORTS_PER_CHIP;
-               cy_card[j].nports = cy_isa_nchan;
-               if (cy_init_card(&cy_card[j])) {
-                       cy_card[j].base_addr = NULL;
-                       free_irq(cy_isa_irq, &cy_card[j]);
+               card->base_addr = cy_isa_address;
+               card->ctl_addr.p9050 = NULL;
+               card->irq = (int)cy_isa_irq;
+               card->bus_index = 0;
+               card->first_line = cy_next_channel;
+               card->num_chips = cy_isa_nchan / CyPORTS_PER_CHIP;
+               card->nports = cy_isa_nchan;
+               if (cy_init_card(card)) {
+                       card->base_addr = NULL;
+                       free_irq(cy_isa_irq, card);
                        iounmap(cy_isa_address);
                        continue;
                }
@@ -3393,9 +3392,10 @@ static int __init cy_detect_isa(void)
                        (unsigned long)(cy_isa_address + (CyISA_Ywin - 1)),
                        cy_isa_irq, cy_isa_nchan, cy_next_channel);
 
-               for (j = cy_next_channel;
-                               j < cy_next_channel + cy_isa_nchan; j++)
-                       tty_register_device(cy_serial_driver, j, NULL);
+               for (k = 0, j = cy_next_channel;
+                               j < cy_next_channel + cy_isa_nchan; j++, k++)
+                       tty_port_register_device(&card->ports[k].port,
+                                       cy_serial_driver, j, NULL);
                cy_next_channel += cy_isa_nchan;
        }
        return nboard;
@@ -3695,10 +3695,11 @@ err:
 static int __devinit cy_pci_probe(struct pci_dev *pdev,
                const struct pci_device_id *ent)
 {
+       struct cyclades_card *card;
        void __iomem *addr0 = NULL, *addr2 = NULL;
        char *card_name = NULL;
        u32 uninitialized_var(mailbox);
-       unsigned int device_id, nchan = 0, card_no, i;
+       unsigned int device_id, nchan = 0, card_no, i, j;
        unsigned char plx_ver;
        int retval, irq;
 
@@ -3829,7 +3830,8 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
        }
        /* fill the next cy_card structure available */
        for (card_no = 0; card_no < NR_CARDS; card_no++) {
-               if (cy_card[card_no].base_addr == NULL)
+               card = &cy_card[card_no];
+               if (card->base_addr == NULL)
                        break;
        }
        if (card_no == NR_CARDS) {      /* no more cy_cards available */
@@ -3843,27 +3845,26 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
                        device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
                /* allocate IRQ */
                retval = request_irq(irq, cyy_interrupt,
-                               IRQF_SHARED, "Cyclom-Y", &cy_card[card_no]);
+                               IRQF_SHARED, "Cyclom-Y", card);
                if (retval) {
                        dev_err(&pdev->dev, "could not allocate IRQ\n");
                        goto err_unmap;
                }
-               cy_card[card_no].num_chips = nchan / CyPORTS_PER_CHIP;
+               card->num_chips = nchan / CyPORTS_PER_CHIP;
        } else {
                struct FIRM_ID __iomem *firm_id = addr2 + ID_ADDRESS;
                struct ZFW_CTRL __iomem *zfw_ctrl;
 
                zfw_ctrl = addr2 + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
 
-               cy_card[card_no].hw_ver = mailbox;
-               cy_card[card_no].num_chips = (unsigned int)-1;
-               cy_card[card_no].board_ctrl = &zfw_ctrl->board_ctrl;
+               card->hw_ver = mailbox;
+               card->num_chips = (unsigned int)-1;
+               card->board_ctrl = &zfw_ctrl->board_ctrl;
 #ifdef CONFIG_CYZ_INTR
                /* allocate IRQ only if board has an IRQ */
                if (irq != 0 && irq != 255) {
                        retval = request_irq(irq, cyz_interrupt,
-                                       IRQF_SHARED, "Cyclades-Z",
-                                       &cy_card[card_no]);
+                                       IRQF_SHARED, "Cyclades-Z", card);
                        if (retval) {
                                dev_err(&pdev->dev, "could not allocate IRQ\n");
                                goto err_unmap;
@@ -3873,17 +3874,17 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
        }
 
        /* set cy_card */
-       cy_card[card_no].base_addr = addr2;
-       cy_card[card_no].ctl_addr.p9050 = addr0;
-       cy_card[card_no].irq = irq;
-       cy_card[card_no].bus_index = 1;
-       cy_card[card_no].first_line = cy_next_channel;
-       cy_card[card_no].nports = nchan;
-       retval = cy_init_card(&cy_card[card_no]);
+       card->base_addr = addr2;
+       card->ctl_addr.p9050 = addr0;
+       card->irq = irq;
+       card->bus_index = 1;
+       card->first_line = cy_next_channel;
+       card->nports = nchan;
+       retval = cy_init_card(card);
        if (retval)
                goto err_null;
 
-       pci_set_drvdata(pdev, &cy_card[card_no]);
+       pci_set_drvdata(pdev, card);
 
        if (device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo ||
                        device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) {
@@ -3909,14 +3910,15 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
 
        dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from "
                "port %d.\n", card_name, card_no + 1, nchan, cy_next_channel);
-       for (i = cy_next_channel; i < cy_next_channel + nchan; i++)
-               tty_register_device(cy_serial_driver, i, &pdev->dev);
+       for (j = 0, i = cy_next_channel; i < cy_next_channel + nchan; i++, j++)
+               tty_port_register_device(&card->ports[j].port,
+                               cy_serial_driver, i, &pdev->dev);
        cy_next_channel += nchan;
 
        return 0;
 err_null:
-       cy_card[card_no].base_addr = NULL;
-       free_irq(irq, &cy_card[card_no]);
+       card->base_addr = NULL;
+       free_irq(irq, card);
 err_unmap:
        iounmap(addr0);
        if (addr2)
index 4813684cb634ed2c7cf5fae1f0dc4b946426a099..4ab936b7aac66d342f726b37d58844462fbc142d 100644 (file)
@@ -738,16 +738,17 @@ static int __devinit ehv_bc_tty_probe(struct platform_device *pdev)
                goto error;
        }
 
-       bc->dev = tty_register_device(ehv_bc_driver, i, &pdev->dev);
+       tty_port_init(&bc->port);
+       bc->port.ops = &ehv_bc_tty_port_ops;
+
+       bc->dev = tty_port_register_device(&bc->port, ehv_bc_driver, i,
+                       &pdev->dev);
        if (IS_ERR(bc->dev)) {
                ret = PTR_ERR(bc->dev);
                dev_err(&pdev->dev, "could not register tty (ret=%i)\n", ret);
                goto error;
        }
 
-       tty_port_init(&bc->port);
-       bc->port.ops = &ehv_bc_tty_port_ops;
-
        dev_set_drvdata(&pdev->dev, bc);
 
        dev_info(&pdev->dev, "registered /dev/%s%u for byte channel %u\n",
index 2d691eb7c40aa28f30602834902cc48fc1c52dad..7f80f15681cd3fa6fe743c01def27bb63ec59bff 100644 (file)
@@ -299,20 +299,33 @@ static void hvc_unthrottle(struct tty_struct *tty)
        hvc_kick();
 }
 
+static int hvc_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+       struct hvc_struct *hp;
+       int rc;
+
+       /* Auto increments kref reference if found. */
+       if (!(hp = hvc_get_by_index(tty->index)))
+               return -ENODEV;
+
+       tty->driver_data = hp;
+
+       rc = tty_port_install(&hp->port, driver, tty);
+       if (rc)
+               tty_port_put(&hp->port);
+       return rc;
+}
+
 /*
  * The TTY interface won't be used until after the vio layer has exposed the vty
  * adapter to the kernel.
  */
 static int hvc_open(struct tty_struct *tty, struct file * filp)
 {
-       struct hvc_struct *hp;
+       struct hvc_struct *hp = tty->driver_data;
        unsigned long flags;
        int rc = 0;
 
-       /* Auto increments kref reference if found. */
-       if (!(hp = hvc_get_by_index(tty->index)))
-               return -ENODEV;
-
        spin_lock_irqsave(&hp->port.lock, flags);
        /* Check and then increment for fast path open. */
        if (hp->port.count++ > 0) {
@@ -322,7 +335,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
        } /* else count == 0 */
        spin_unlock_irqrestore(&hp->port.lock, flags);
 
-       tty->driver_data = hp;
        tty_port_tty_set(&hp->port, tty);
 
        if (hp->ops->notifier_add)
@@ -389,6 +401,11 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
                                hp->vtermno, hp->port.count);
                spin_unlock_irqrestore(&hp->port.lock, flags);
        }
+}
+
+static void hvc_cleanup(struct tty_struct *tty)
+{
+       struct hvc_struct *hp = tty->driver_data;
 
        tty_port_put(&hp->port);
 }
@@ -792,8 +809,10 @@ static void hvc_poll_put_char(struct tty_driver *driver, int line, char ch)
 #endif
 
 static const struct tty_operations hvc_ops = {
+       .install = hvc_install,
        .open = hvc_open,
        .close = hvc_close,
+       .cleanup = hvc_cleanup,
        .write = hvc_write,
        .hangup = hvc_hangup,
        .unthrottle = hvc_unthrottle,
index d56788c83974e840f7e2aa469da2b993806fb99d..cab5c7adf8e84314e9ee515465a0db07bb1687e5 100644 (file)
@@ -1102,27 +1102,20 @@ static struct hvcs_struct *hvcs_get_by_index(int index)
        return NULL;
 }
 
-/*
- * This is invoked via the tty_open interface when a user app connects to the
- * /dev node.
- */
-static int hvcs_open(struct tty_struct *tty, struct file *filp)
+static int hvcs_install(struct tty_driver *driver, struct tty_struct *tty)
 {
        struct hvcs_struct *hvcsd;
-       int rc, retval = 0;
-       unsigned long flags;
-       unsigned int irq;
        struct vio_dev *vdev;
-       unsigned long unit_address;
-
-       if (tty->driver_data)
-               goto fast_open;
+       unsigned long unit_address, flags;
+       unsigned int irq;
+       int retval;
 
        /*
         * Is there a vty-server that shares the same index?
         * This function increments the kref index.
         */
-       if (!(hvcsd = hvcs_get_by_index(tty->index))) {
+       hvcsd = hvcs_get_by_index(tty->index);
+       if (!hvcsd) {
                printk(KERN_WARNING "HVCS: open failed, no device associated"
                                " with tty->index %d.\n", tty->index);
                return -ENODEV;
@@ -1130,11 +1123,16 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
 
        spin_lock_irqsave(&hvcsd->lock, flags);
 
-       if (hvcsd->connected == 0)
-               if ((retval = hvcs_partner_connect(hvcsd)))
-                       goto error_release;
+       if (hvcsd->connected == 0) {
+               retval = hvcs_partner_connect(hvcsd);
+               if (retval) {
+                       spin_unlock_irqrestore(&hvcsd->lock, flags);
+                       printk(KERN_WARNING "HVCS: partner connect failed.\n");
+                       goto err_put;
+               }
+       }
 
-       hvcsd->port.count = 1;
+       hvcsd->port.count = 0;
        hvcsd->port.tty = tty;
        tty->driver_data = hvcsd;
 
@@ -1155,37 +1153,48 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
         * This must be done outside of the spinlock because it requests irqs
         * and will grab the spinlock and free the connection if it fails.
         */
-       if (((rc = hvcs_enable_device(hvcsd, unit_address, irq, vdev)))) {
-               tty_port_put(&hvcsd->port);
+       retval = hvcs_enable_device(hvcsd, unit_address, irq, vdev);
+       if (retval) {
                printk(KERN_WARNING "HVCS: enable device failed.\n");
-               return rc;
+               goto err_put;
        }
 
-       goto open_success;
+       retval = tty_port_install(&hvcsd->port, driver, tty);
+       if (retval)
+               goto err_irq;
 
-fast_open:
-       hvcsd = tty->driver_data;
+       return 0;
+err_irq:
+       spin_lock_irqsave(&hvcsd->lock, flags);
+       vio_disable_interrupts(hvcsd->vdev);
+       spin_unlock_irqrestore(&hvcsd->lock, flags);
+       free_irq(irq, hvcsd);
+err_put:
+       tty_port_put(&hvcsd->port);
+
+       return retval;
+}
+
+/*
+ * This is invoked via the tty_open interface when a user app connects to the
+ * /dev node.
+ */
+static int hvcs_open(struct tty_struct *tty, struct file *filp)
+{
+       struct hvcs_struct *hvcsd = tty->driver_data;
+       unsigned long flags;
 
        spin_lock_irqsave(&hvcsd->lock, flags);
-       tty_port_get(&hvcsd->port);
        hvcsd->port.count++;
        hvcsd->todo_mask |= HVCS_SCHED_READ;
        spin_unlock_irqrestore(&hvcsd->lock, flags);
 
-open_success:
        hvcs_kick();
 
        printk(KERN_INFO "HVCS: vty-server@%X connection opened.\n",
                hvcsd->vdev->unit_address );
 
        return 0;
-
-error_release:
-       spin_unlock_irqrestore(&hvcsd->lock, flags);
-       tty_port_put(&hvcsd->port);
-
-       printk(KERN_WARNING "HVCS: partner connect failed.\n");
-       return retval;
 }
 
 static void hvcs_close(struct tty_struct *tty, struct file *filp)
@@ -1236,7 +1245,6 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
                tty->driver_data = NULL;
 
                free_irq(irq, hvcsd);
-               tty_port_put(&hvcsd->port);
                return;
        } else if (hvcsd->port.count < 0) {
                printk(KERN_ERR "HVCS: vty-server@%X open_count: %d"
@@ -1245,6 +1253,12 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp)
        }
 
        spin_unlock_irqrestore(&hvcsd->lock, flags);
+}
+
+static void hvcs_cleanup(struct tty_struct * tty)
+{
+       struct hvcs_struct *hvcsd = tty->driver_data;
+
        tty_port_put(&hvcsd->port);
 }
 
@@ -1431,8 +1445,10 @@ static int hvcs_chars_in_buffer(struct tty_struct *tty)
 }
 
 static const struct tty_operations hvcs_ops = {
+       .install = hvcs_install,
        .open = hvcs_open,
        .close = hvcs_close,
+       .cleanup = hvcs_cleanup,
        .hangup = hvcs_hangup,
        .write = hvcs_write,
        .write_room = hvcs_write_room,
index 6f5bc49c441fa5c806d316c851f376c20914ad4f..0083bc1f63f43a37c8cc5f531da88f6a24729952 100644 (file)
@@ -1080,6 +1080,8 @@ static int __init hvsi_init(void)
                struct hvsi_struct *hp = &hvsi_ports[i];
                int ret = 1;
 
+               tty_port_link_device(&hp->port, hvsi_driver, i);
+
                ret = request_irq(hp->virq, hvsi_interrupt, 0, "hvsi", hp);
                if (ret)
                        printk(KERN_ERR "HVSI: couldn't reserve irq 0x%x (error %i)\n",
index 59c135dd5d2069ecee49e21480e47e52359fec46..3396eb9d57a374770f22dd956d06fa3382196f66 100644 (file)
@@ -400,7 +400,7 @@ void hvsilib_close(struct hvsi_priv *pv, struct hvc_struct *hp)
                spin_unlock_irqrestore(&hp->lock, flags);
 
                /* Clear our own DTR */
-               if (!pv->tty || (pv->tty->termios->c_cflag & HUPCL))
+               if (!pv->tty || (pv->tty->termios.c_cflag & HUPCL))
                        hvsilib_write_mctrl(pv, 0);
 
                /* Tear down the connection */
index f8b5fa0093a3bf3a9f74c3f4b7662a05d89ee547..160f0ad9589d2a17071b9de8f3e6739a022b843f 100644 (file)
@@ -476,7 +476,7 @@ static int add_tty(int j,
        mutex_init(&ttys[j]->ipw_tty_mutex);
        tty_port_init(&ttys[j]->port);
 
-       tty_register_device(ipw_tty_driver, j, NULL);
+       tty_port_register_device(&ttys[j]->port, ipw_tty_driver, j, NULL);
        ipwireless_associate_network_tty(network, channel_idx, ttys[j]);
 
        if (secondary_channel_idx != -1)
index e1235accab740b4bca4eb01c28b0ed76e170ea93..99cf22e5f2b6634bcf809ccecf37e463b4c620ab 100644 (file)
@@ -702,7 +702,7 @@ static void isicom_config_port(struct tty_struct *tty)
 
                /* 1,2,3,4 => 57.6, 115.2, 230, 460 kbps resp. */
                if (baud < 1 || baud > 4)
-                       tty->termios->c_cflag &= ~CBAUDEX;
+                       tty->termios.c_cflag &= ~CBAUDEX;
                else
                        baud += 15;
        }
@@ -1196,8 +1196,8 @@ static void isicom_set_termios(struct tty_struct *tty,
        if (isicom_paranoia_check(port, tty->name, "isicom_set_termios"))
                return;
 
-       if (tty->termios->c_cflag == old_termios->c_cflag &&
-                       tty->termios->c_iflag == old_termios->c_iflag)
+       if (tty->termios.c_cflag == old_termios->c_cflag &&
+                       tty->termios.c_iflag == old_termios->c_iflag)
                return;
 
        spin_lock_irqsave(&port->card->card_lock, flags);
@@ -1205,7 +1205,7 @@ static void isicom_set_termios(struct tty_struct *tty,
        spin_unlock_irqrestore(&port->card->card_lock, flags);
 
        if ((old_termios->c_cflag & CRTSCTS) &&
-                       !(tty->termios->c_cflag & CRTSCTS)) {
+                       !(tty->termios.c_cflag & CRTSCTS)) {
                tty->hw_stopped = 0;
                isicom_start(tty);
        }
@@ -1611,7 +1611,8 @@ static int __devinit isicom_probe(struct pci_dev *pdev,
                goto errunri;
 
        for (index = 0; index < board->port_count; index++)
-               tty_register_device(isicom_normal, board->index * 16 + index,
+               tty_port_register_device(&board->ports[index].port,
+                               isicom_normal, board->index * 16 + index,
                                &pdev->dev);
 
        return 0;
index 324467d28a5497bcca18b2f52d31943d2747f795..56e616b9109a4963eb2d78bcfdb7eed91b973f8e 100644 (file)
@@ -169,6 +169,7 @@ static DEFINE_SPINLOCK(moxa_lock);
 static unsigned long baseaddr[MAX_BOARDS];
 static unsigned int type[MAX_BOARDS];
 static unsigned int numports[MAX_BOARDS];
+static struct tty_port moxa_service_port;
 
 MODULE_AUTHOR("William Chen");
 MODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver");
@@ -367,10 +368,10 @@ static int moxa_ioctl(struct tty_struct *tty,
                                        tmp.dcd = 1;
 
                                ttyp = tty_port_tty_get(&p->port);
-                               if (!ttyp || !ttyp->termios)
+                               if (!ttyp)
                                        tmp.cflag = p->cflag;
                                else
-                                       tmp.cflag = ttyp->termios->c_cflag;
+                                       tmp.cflag = ttyp->termios.c_cflag;
                                tty_kref_put(ttyp);
 copy:
                                if (copy_to_user(argm, &tmp, sizeof(tmp)))
@@ -834,7 +835,7 @@ static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev)
        const struct firmware *fw;
        const char *file;
        struct moxa_port *p;
-       unsigned int i;
+       unsigned int i, first_idx;
        int ret;
 
        brd->ports = kcalloc(MAX_PORTS_PER_BOARD, sizeof(*brd->ports),
@@ -887,6 +888,11 @@ static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev)
                mod_timer(&moxaTimer, jiffies + HZ / 50);
        spin_unlock_bh(&moxa_lock);
 
+       first_idx = (brd - moxa_boards) * MAX_PORTS_PER_BOARD;
+       for (i = 0; i < brd->numPorts; i++)
+               tty_port_register_device(&brd->ports[i].port, moxaDriver,
+                               first_idx + i, dev);
+
        return 0;
 err_free:
        kfree(brd->ports);
@@ -896,7 +902,7 @@ err:
 
 static void moxa_board_deinit(struct moxa_board_conf *brd)
 {
-       unsigned int a, opened;
+       unsigned int a, opened, first_idx;
 
        mutex_lock(&moxa_openlock);
        spin_lock_bh(&moxa_lock);
@@ -925,6 +931,10 @@ static void moxa_board_deinit(struct moxa_board_conf *brd)
                mutex_lock(&moxa_openlock);
        }
 
+       first_idx = (brd - moxa_boards) * MAX_PORTS_PER_BOARD;
+       for (a = 0; a < brd->numPorts; a++)
+               tty_unregister_device(moxaDriver, first_idx + a);
+
        iounmap(brd->basemem);
        brd->basemem = NULL;
        kfree(brd->ports);
@@ -967,6 +977,7 @@ static int __devinit moxa_pci_probe(struct pci_dev *pdev,
        board->basemem = ioremap_nocache(pci_resource_start(pdev, 2), 0x4000);
        if (board->basemem == NULL) {
                dev_err(&pdev->dev, "can't remap io space 2\n");
+               retval = -ENOMEM;
                goto err_reg;
        }
 
@@ -1031,9 +1042,14 @@ static int __init moxa_init(void)
 
        printk(KERN_INFO "MOXA Intellio family driver version %s\n",
                        MOXA_VERSION);
-       moxaDriver = alloc_tty_driver(MAX_PORTS + 1);
-       if (!moxaDriver)
-               return -ENOMEM;
+
+       tty_port_init(&moxa_service_port);
+
+       moxaDriver = tty_alloc_driver(MAX_PORTS + 1,
+                       TTY_DRIVER_REAL_RAW |
+                       TTY_DRIVER_DYNAMIC_DEV);
+       if (IS_ERR(moxaDriver))
+               return PTR_ERR(moxaDriver);
 
        moxaDriver->name = "ttyMX";
        moxaDriver->major = ttymajor;
@@ -1044,8 +1060,9 @@ static int __init moxa_init(void)
        moxaDriver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
        moxaDriver->init_termios.c_ispeed = 9600;
        moxaDriver->init_termios.c_ospeed = 9600;
-       moxaDriver->flags = TTY_DRIVER_REAL_RAW;
        tty_set_operations(moxaDriver, &moxa_ops);
+       /* Having one more port only for ioctls is ugly */
+       tty_port_link_device(&moxa_service_port, moxaDriver, MAX_PORTS);
 
        if (tty_register_driver(moxaDriver)) {
                printk(KERN_ERR "can't register MOXA Smartio tty driver!\n");
@@ -1178,7 +1195,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
        mutex_lock(&ch->port.mutex);
        if (!(ch->port.flags & ASYNC_INITIALIZED)) {
                ch->statusflags = 0;
-               moxa_set_tty_param(tty, tty->termios);
+               moxa_set_tty_param(tty, &tty->termios);
                MoxaPortLineCtrl(ch, 1, 1);
                MoxaPortEnable(ch);
                MoxaSetFifo(ch, ch->type == PORT_16550A);
@@ -1193,7 +1210,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
 static void moxa_close(struct tty_struct *tty, struct file *filp)
 {
        struct moxa_port *ch = tty->driver_data;
-       ch->cflag = tty->termios->c_cflag;
+       ch->cflag = tty->termios.c_cflag;
        tty_port_close(&ch->port, tty, filp);
 }
 
@@ -1464,7 +1481,7 @@ static void moxa_poll(unsigned long ignored)
 
 static void moxa_set_tty_param(struct tty_struct *tty, struct ktermios *old_termios)
 {
-       register struct ktermios *ts = tty->termios;
+       register struct ktermios *ts = &tty->termios;
        struct moxa_port *ch = tty->driver_data;
        int rts, cts, txflow, rxflow, xany, baud;
 
index 90cc680c4f0e7e330f9daa201cb0b30fd2be8aab..bb2da4ca82575bd307bc6452e278ad0e8121f9b0 100644 (file)
@@ -643,7 +643,7 @@ static int mxser_change_speed(struct tty_struct *tty,
        int ret = 0;
        unsigned char status;
 
-       cflag = tty->termios->c_cflag;
+       cflag = tty->termios.c_cflag;
        if (!info->ioaddr)
                return ret;
 
@@ -1520,10 +1520,10 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
                                
                                tty = tty_port_tty_get(port);
 
-                               if (!tty || !tty->termios)
+                               if (!tty)
                                        ms.cflag = ip->normal_termios.c_cflag;
                                else
-                                       ms.cflag = tty->termios->c_cflag;
+                                       ms.cflag = tty->termios.c_cflag;
                                tty_kref_put(tty);
                                spin_lock_irq(&ip->slock);
                                status = inb(ip->ioaddr + UART_MSR);
@@ -1589,13 +1589,13 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp)
 
                                tty = tty_port_tty_get(&ip->port);
 
-                               if (!tty || !tty->termios) {
+                               if (!tty) {
                                        cflag = ip->normal_termios.c_cflag;
                                        iflag = ip->normal_termios.c_iflag;
                                        me->baudrate[p] = tty_termios_baud_rate(&ip->normal_termios);
                                } else {
-                                       cflag = tty->termios->c_cflag;
-                                       iflag = tty->termios->c_iflag;
+                                       cflag = tty->termios.c_cflag;
+                                       iflag = tty->termios.c_iflag;
                                        me->baudrate[p] = tty_get_baud_rate(tty);
                                }
                                tty_kref_put(tty);
@@ -1853,7 +1853,7 @@ static void mxser_stoprx(struct tty_struct *tty)
                }
        }
 
-       if (tty->termios->c_cflag & CRTSCTS) {
+       if (tty->termios.c_cflag & CRTSCTS) {
                info->MCR &= ~UART_MCR_RTS;
                outb(info->MCR, info->ioaddr + UART_MCR);
        }
@@ -1890,7 +1890,7 @@ static void mxser_unthrottle(struct tty_struct *tty)
                }
        }
 
-       if (tty->termios->c_cflag & CRTSCTS) {
+       if (tty->termios.c_cflag & CRTSCTS) {
                info->MCR |= UART_MCR_RTS;
                outb(info->MCR, info->ioaddr + UART_MCR);
        }
@@ -1939,14 +1939,14 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi
        spin_unlock_irqrestore(&info->slock, flags);
 
        if ((old_termios->c_cflag & CRTSCTS) &&
-                       !(tty->termios->c_cflag & CRTSCTS)) {
+                       !(tty->termios.c_cflag & CRTSCTS)) {
                tty->hw_stopped = 0;
                mxser_start(tty);
        }
 
        /* Handle sw stopped */
        if ((old_termios->c_iflag & IXON) &&
-                       !(tty->termios->c_iflag & IXON)) {
+                       !(tty->termios.c_iflag & IXON)) {
                tty->stopped = 0;
 
                if (info->board->chip_flag) {
@@ -2337,11 +2337,36 @@ static struct tty_port_operations mxser_port_ops = {
  * The MOXA Smartio/Industio serial driver boot-time initialization code!
  */
 
+static bool allow_overlapping_vector;
+module_param(allow_overlapping_vector, bool, S_IRUGO);
+MODULE_PARM_DESC(allow_overlapping_vector, "whether we allow ISA cards to be configured such that vector overlabs IO ports (default=no)");
+
+static bool mxser_overlapping_vector(struct mxser_board *brd)
+{
+       return allow_overlapping_vector &&
+               brd->vector >= brd->ports[0].ioaddr &&
+               brd->vector < brd->ports[0].ioaddr + 8 * brd->info->nports;
+}
+
+static int mxser_request_vector(struct mxser_board *brd)
+{
+       if (mxser_overlapping_vector(brd))
+               return 0;
+       return request_region(brd->vector, 1, "mxser(vector)") ? 0 : -EIO;
+}
+
+static void mxser_release_vector(struct mxser_board *brd)
+{
+       if (mxser_overlapping_vector(brd))
+               return;
+       release_region(brd->vector, 1);
+}
+
 static void mxser_release_ISA_res(struct mxser_board *brd)
 {
        free_irq(brd->irq, brd);
        release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
-       release_region(brd->vector, 1);
+       mxser_release_vector(brd);
 }
 
 static int __devinit mxser_initbrd(struct mxser_board *brd,
@@ -2396,7 +2421,7 @@ static int __devinit mxser_initbrd(struct mxser_board *brd,
 
 static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd)
 {
-       int id, i, bits;
+       int id, i, bits, ret;
        unsigned short regs[16], irq;
        unsigned char scratch, scratch2;
 
@@ -2492,13 +2517,15 @@ static int __init mxser_get_ISA_conf(int cap, struct mxser_board *brd)
                                8 * brd->info->nports - 1);
                return -EIO;
        }
-       if (!request_region(brd->vector, 1, "mxser(vector)")) {
+
+       ret = mxser_request_vector(brd);
+       if (ret) {
                release_region(brd->ports[0].ioaddr, 8 * brd->info->nports);
                printk(KERN_ERR "mxser: can't request interrupt vector region: "
                                "0x%.8lx-0x%.8lx\n",
                                brd->ports[0].ioaddr, brd->ports[0].ioaddr +
                                8 * brd->info->nports - 1);
-               return -EIO;
+               return ret;
        }
        return brd->info->nports;
 
@@ -2598,7 +2625,8 @@ static int __devinit mxser_probe(struct pci_dev *pdev,
                goto err_rel3;
 
        for (i = 0; i < brd->info->nports; i++)
-               tty_register_device(mxvar_sdriver, brd->idx + i, &pdev->dev);
+               tty_port_register_device(&brd->ports[i].port, mxvar_sdriver,
+                               brd->idx + i, &pdev->dev);
 
        pci_set_drvdata(pdev, brd);
 
@@ -2695,7 +2723,8 @@ static int __init mxser_module_init(void)
 
                brd->idx = m * MXSER_PORTS_PER_BOARD;
                for (i = 0; i < brd->info->nports; i++)
-                       tty_register_device(mxvar_sdriver, brd->idx + i, NULL);
+                       tty_port_register_device(&brd->ports[i].port,
+                                       mxvar_sdriver, brd->idx + i, NULL);
 
                m++;
        }
index c43b683b6eb811babdb7cbc1a1c6bc75eb7ae413..3e210a430fb38585875a500f971887c4ee7759df 100644 (file)
@@ -108,7 +108,7 @@ struct gsm_mux_net {
  */
 
 struct gsm_msg {
-       struct gsm_msg *next;
+       struct list_head list;
        u8 addr;                /* DLCI address + flags */
        u8 ctrl;                /* Control byte + flags */
        unsigned int len;       /* Length of data block (can be zero) */
@@ -245,8 +245,7 @@ struct gsm_mux {
        unsigned int tx_bytes;          /* TX data outstanding */
 #define TX_THRESH_HI           8192
 #define TX_THRESH_LO           2048
-       struct gsm_msg *tx_head;        /* Pending data packets */
-       struct gsm_msg *tx_tail;
+       struct list_head tx_list;       /* Pending data packets */
 
        /* Control messages */
        struct timer_list t2_timer;     /* Retransmit timer for commands */
@@ -663,7 +662,7 @@ static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len,
        m->len = len;
        m->addr = addr;
        m->ctrl = ctrl;
-       m->next = NULL;
+       INIT_LIST_HEAD(&m->list);
        return m;
 }
 
@@ -673,22 +672,21 @@ static struct gsm_msg *gsm_data_alloc(struct gsm_mux *gsm, u8 addr, int len,
  *
  *     The tty device has called us to indicate that room has appeared in
  *     the transmit queue. Ram more data into the pipe if we have any
+ *     If we have been flow-stopped by a CMD_FCOFF, then we can only
+ *     send messages on DLCI0 until CMD_FCON
  *
  *     FIXME: lock against link layer control transmissions
  */
 
 static void gsm_data_kick(struct gsm_mux *gsm)
 {
-       struct gsm_msg *msg = gsm->tx_head;
+       struct gsm_msg *msg, *nmsg;
        int len;
        int skip_sof = 0;
 
-       /* FIXME: We need to apply this solely to data messages */
-       if (gsm->constipated)
-               return;
-
-       while (gsm->tx_head != NULL) {
-               msg = gsm->tx_head;
+       list_for_each_entry_safe(msg, nmsg, &gsm->tx_list, list) {
+               if (gsm->constipated && msg->addr)
+                       continue;
                if (gsm->encoding != 0) {
                        gsm->txframe[0] = GSM1_SOF;
                        len = gsm_stuff_frame(msg->data,
@@ -711,14 +709,13 @@ static void gsm_data_kick(struct gsm_mux *gsm)
                                                len - skip_sof) < 0)
                        break;
                /* FIXME: Can eliminate one SOF in many more cases */
-               gsm->tx_head = msg->next;
-               if (gsm->tx_head == NULL)
-                       gsm->tx_tail = NULL;
                gsm->tx_bytes -= msg->len;
-               kfree(msg);
                /* For a burst of frames skip the extra SOF within the
                   burst */
                skip_sof = 1;
+
+               list_del(&msg->list);
+               kfree(msg);
        }
 }
 
@@ -768,11 +765,7 @@ static void __gsm_data_queue(struct gsm_dlci *dlci, struct gsm_msg *msg)
        msg->data = dp;
 
        /* Add to the actual output queue */
-       if (gsm->tx_tail)
-               gsm->tx_tail->next = msg;
-       else
-               gsm->tx_head = msg;
-       gsm->tx_tail = msg;
+       list_add_tail(&msg->list, &gsm->tx_list);
        gsm->tx_bytes += msg->len;
        gsm_data_kick(gsm);
 }
@@ -875,7 +868,7 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
 
        /* dlci->skb is locked by tx_lock */
        if (dlci->skb == NULL) {
-               dlci->skb = skb_dequeue(&dlci->skb_list);
+               dlci->skb = skb_dequeue_tail(&dlci->skb_list);
                if (dlci->skb == NULL)
                        return 0;
                first = 1;
@@ -886,7 +879,7 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
        if (len > gsm->mtu) {
                if (dlci->adaption == 3) {
                        /* Over long frame, bin it */
-                       kfree_skb(dlci->skb);
+                       dev_kfree_skb_any(dlci->skb);
                        dlci->skb = NULL;
                        return 0;
                }
@@ -899,8 +892,11 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
 
        /* FIXME: need a timer or something to kick this so it can't
           get stuck with no work outstanding and no buffer free */
-       if (msg == NULL)
+       if (msg == NULL) {
+               skb_queue_tail(&dlci->skb_list, dlci->skb);
+               dlci->skb = NULL;
                return -ENOMEM;
+       }
        dp = msg->data;
 
        if (dlci->adaption == 4) { /* Interruptible framed (Packetised Data) */
@@ -912,7 +908,7 @@ static int gsm_dlci_data_output_framed(struct gsm_mux *gsm,
        skb_pull(dlci->skb, len);
        __gsm_data_queue(dlci, msg);
        if (last) {
-               kfree_skb(dlci->skb);
+               dev_kfree_skb_any(dlci->skb);
                dlci->skb = NULL;
        }
        return size;
@@ -971,16 +967,22 @@ static void gsm_dlci_data_sweep(struct gsm_mux *gsm)
 static void gsm_dlci_data_kick(struct gsm_dlci *dlci)
 {
        unsigned long flags;
+       int sweep;
+
+       if (dlci->constipated) 
+               return;
 
        spin_lock_irqsave(&dlci->gsm->tx_lock, flags);
        /* If we have nothing running then we need to fire up */
+       sweep = (dlci->gsm->tx_bytes < TX_THRESH_LO);
        if (dlci->gsm->tx_bytes == 0) {
                if (dlci->net)
                        gsm_dlci_data_output_framed(dlci->gsm, dlci);
                else
                        gsm_dlci_data_output(dlci->gsm, dlci);
-       } else if (dlci->gsm->tx_bytes < TX_THRESH_LO)
-               gsm_dlci_data_sweep(dlci->gsm);
+       }
+       if (sweep)
+               gsm_dlci_data_sweep(dlci->gsm);
        spin_unlock_irqrestore(&dlci->gsm->tx_lock, flags);
 }
 
@@ -1027,6 +1029,7 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
 {
        int  mlines = 0;
        u8 brk = 0;
+       int fc;
 
        /* The modem status command can either contain one octet (v.24 signals)
           or two octets (v.24 signals + break signals). The length field will
@@ -1038,19 +1041,21 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
        else {
                brk = modem & 0x7f;
                modem = (modem >> 7) & 0x7f;
-       };
+       }
 
        /* Flow control/ready to communicate */
-       if (modem & MDM_FC) {
+       fc = (modem & MDM_FC) || !(modem & MDM_RTR);
+       if (fc && !dlci->constipated) {
                /* Need to throttle our output on this device */
                dlci->constipated = 1;
-       }
-       if (modem & MDM_RTC) {
-               mlines |= TIOCM_DSR | TIOCM_DTR;
+       } else if (!fc && dlci->constipated) {
                dlci->constipated = 0;
                gsm_dlci_data_kick(dlci);
        }
+
        /* Map modem bits */
+       if (modem & MDM_RTC)
+               mlines |= TIOCM_DSR | TIOCM_DTR;
        if (modem & MDM_RTR)
                mlines |= TIOCM_RTS | TIOCM_CTS;
        if (modem & MDM_IC)
@@ -1061,7 +1066,7 @@ static void gsm_process_modem(struct tty_struct *tty, struct gsm_dlci *dlci,
        /* Carrier drop -> hangup */
        if (tty) {
                if ((mlines & TIOCM_CD) == 0 && (dlci->modem_rx & TIOCM_CD))
-                       if (!(tty->termios->c_cflag & CLOCAL))
+                       if (!(tty->termios.c_cflag & CLOCAL))
                                tty_hangup(tty);
                if (brk & 0x01)
                        tty_insert_flip_char(tty, 0, TTY_BREAK);
@@ -1190,6 +1195,8 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command,
                                                        u8 *data, int clen)
 {
        u8 buf[1];
+       unsigned long flags;
+
        switch (command) {
        case CMD_CLD: {
                struct gsm_dlci *dlci = gsm->dlci[0];
@@ -1206,16 +1213,18 @@ static void gsm_control_message(struct gsm_mux *gsm, unsigned int command,
                gsm_control_reply(gsm, CMD_TEST, data, clen);
                break;
        case CMD_FCON:
-               /* Modem wants us to STFU */
-               gsm->constipated = 1;
-               gsm_control_reply(gsm, CMD_FCON, NULL, 0);
-               break;
-       case CMD_FCOFF:
                /* Modem can accept data again */
                gsm->constipated = 0;
-               gsm_control_reply(gsm, CMD_FCOFF, NULL, 0);
+               gsm_control_reply(gsm, CMD_FCON, NULL, 0);
                /* Kick the link in case it is idling */
+               spin_lock_irqsave(&gsm->tx_lock, flags);
                gsm_data_kick(gsm);
+               spin_unlock_irqrestore(&gsm->tx_lock, flags);
+               break;
+       case CMD_FCOFF:
+               /* Modem wants us to STFU */
+               gsm->constipated = 1;
+               gsm_control_reply(gsm, CMD_FCOFF, NULL, 0);
                break;
        case CMD_MSC:
                /* Out of band modem line change indicator for a DLCI */
@@ -1668,7 +1677,7 @@ static void gsm_dlci_free(struct kref *ref)
        dlci->gsm->dlci[dlci->addr] = NULL;
        kfifo_free(dlci->fifo);
        while ((dlci->skb = skb_dequeue(&dlci->skb_list)))
-               kfree_skb(dlci->skb);
+               dev_kfree_skb(dlci->skb);
        kfree(dlci);
 }
 
@@ -2007,7 +2016,7 @@ void gsm_cleanup_mux(struct gsm_mux *gsm)
 {
        int i;
        struct gsm_dlci *dlci = gsm->dlci[0];
-       struct gsm_msg *txq;
+       struct gsm_msg *txq, *ntxq;
        struct gsm_control *gc;
 
        gsm->dead = 1;
@@ -2042,11 +2051,9 @@ void gsm_cleanup_mux(struct gsm_mux *gsm)
                if (gsm->dlci[i])
                        gsm_dlci_release(gsm->dlci[i]);
        /* Now wipe the queues */
-       for (txq = gsm->tx_head; txq != NULL; txq = gsm->tx_head) {
-               gsm->tx_head = txq->next;
+       list_for_each_entry_safe(txq, ntxq, &gsm->tx_list, list)
                kfree(txq);
-       }
-       gsm->tx_tail = NULL;
+       INIT_LIST_HEAD(&gsm->tx_list);
 }
 EXPORT_SYMBOL_GPL(gsm_cleanup_mux);
 
@@ -2157,6 +2164,7 @@ struct gsm_mux *gsm_alloc_mux(void)
        }
        spin_lock_init(&gsm->lock);
        kref_init(&gsm->ref);
+       INIT_LIST_HEAD(&gsm->tx_list);
 
        gsm->t1 = T1;
        gsm->t2 = T2;
@@ -2273,7 +2281,7 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
                        gsm->error(gsm, *dp, flags);
                        break;
                default:
-                       WARN_ONCE("%s: unknown flag %d\n",
+                       WARN_ONCE(1, "%s: unknown flag %d\n",
                               tty_name(tty, buf), flags);
                        break;
                }
@@ -2377,12 +2385,12 @@ static void gsmld_write_wakeup(struct tty_struct *tty)
 
        /* Queue poll */
        clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+       spin_lock_irqsave(&gsm->tx_lock, flags);
        gsm_data_kick(gsm);
        if (gsm->tx_bytes < TX_THRESH_LO) {
-               spin_lock_irqsave(&gsm->tx_lock, flags);
                gsm_dlci_data_sweep(gsm);
-               spin_unlock_irqrestore(&gsm->tx_lock, flags);
        }
+       spin_unlock_irqrestore(&gsm->tx_lock, flags);
 }
 
 /**
@@ -2868,14 +2876,14 @@ static const struct tty_port_operations gsm_port_ops = {
        .dtr_rts = gsm_dtr_rts,
 };
 
-
-static int gsmtty_open(struct tty_struct *tty, struct file *filp)
+static int gsmtty_install(struct tty_driver *driver, struct tty_struct *tty)
 {
        struct gsm_mux *gsm;
        struct gsm_dlci *dlci;
-       struct tty_port *port;
        unsigned int line = tty->index;
        unsigned int mux = line >> 6;
+       bool alloc = false;
+       int ret;
 
        line = line & 0x3F;
 
@@ -2889,14 +2897,35 @@ static int gsmtty_open(struct tty_struct *tty, struct file *filp)
        gsm = gsm_mux[mux];
        if (gsm->dead)
                return -EL2HLT;
+       /* If DLCI 0 is not yet fully open return an error. This is ok from a locking
+          perspective as we don't have to worry about this if DLCI0 is lost */
+       if (gsm->dlci[0] && gsm->dlci[0]->state != DLCI_OPEN) 
+               return -EL2NSYNC;
        dlci = gsm->dlci[line];
-       if (dlci == NULL)
+       if (dlci == NULL) {
+               alloc = true;
                dlci = gsm_dlci_alloc(gsm, line);
+       }
        if (dlci == NULL)
                return -ENOMEM;
-       port = &dlci->port;
-       port->count++;
+       ret = tty_port_install(&dlci->port, driver, tty);
+       if (ret) {
+               if (alloc)
+                       dlci_put(dlci);
+               return ret;
+       }
+
        tty->driver_data = dlci;
+
+       return 0;
+}
+
+static int gsmtty_open(struct tty_struct *tty, struct file *filp)
+{
+       struct gsm_dlci *dlci = tty->driver_data;
+       struct tty_port *port = &dlci->port;
+
+       port->count++;
        dlci_get(dlci);
        dlci_get(dlci->gsm->dlci[0]);
        mux_get(dlci->gsm);
@@ -3043,13 +3072,13 @@ static void gsmtty_set_termios(struct tty_struct *tty, struct ktermios *old)
           the RPN control message. This however rapidly gets nasty as we
           then have to remap modem signals each way according to whether
           our virtual cable is null modem etc .. */
-       tty_termios_copy_hw(tty->termios, old);
+       tty_termios_copy_hw(&tty->termios, old);
 }
 
 static void gsmtty_throttle(struct tty_struct *tty)
 {
        struct gsm_dlci *dlci = tty->driver_data;
-       if (tty->termios->c_cflag & CRTSCTS)
+       if (tty->termios.c_cflag & CRTSCTS)
                dlci->modem_tx &= ~TIOCM_DTR;
        dlci->throttled = 1;
        /* Send an MSC with DTR cleared */
@@ -3059,7 +3088,7 @@ static void gsmtty_throttle(struct tty_struct *tty)
 static void gsmtty_unthrottle(struct tty_struct *tty)
 {
        struct gsm_dlci *dlci = tty->driver_data;
-       if (tty->termios->c_cflag & CRTSCTS)
+       if (tty->termios.c_cflag & CRTSCTS)
                dlci->modem_tx |= TIOCM_DTR;
        dlci->throttled = 0;
        /* Send an MSC with DTR set */
@@ -3085,6 +3114,7 @@ static int gsmtty_break_ctl(struct tty_struct *tty, int state)
 
 /* Virtual ttys for the demux */
 static const struct tty_operations gsmtty_ops = {
+       .install                = gsmtty_install,
        .open                   = gsmtty_open,
        .close                  = gsmtty_close,
        .write                  = gsmtty_write,
index 5c6c31459a2f6618cb7cf9d83c7100cf1a6d86ea..1e6405070ce649e356b24d272a824e9eda737159 100644 (file)
@@ -1065,7 +1065,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
 
        TRACE_L("read()");
 
-       tty_lock();
+       tty_lock(tty);
 
        pClient = findClient(pInfo, task_pid(current));
        if (pClient) {
@@ -1077,7 +1077,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
                                goto unlock;
                        }
                        /* block until there is a message: */
-                       wait_event_interruptible_tty(pInfo->read_wait,
+                       wait_event_interruptible_tty(tty, pInfo->read_wait,
                                        (pMsg = remove_msg(pInfo, pClient)));
                }
 
@@ -1107,7 +1107,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
        }
        ret = -EPERM;
 unlock:
-       tty_unlock();
+       tty_unlock(tty);
        return ret;
 }
 
@@ -1156,7 +1156,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
        pHeader->locks = 0;
        pHeader->owner = NULL;
 
-       tty_lock();
+       tty_lock(tty);
 
        pClient = findClient(pInfo, task_pid(current));
        if (pClient) {
@@ -1175,7 +1175,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
        add_tx_queue(pInfo, pHeader);
        trigger_transmit(pInfo);
 
-       tty_unlock();
+       tty_unlock(tty);
 
        return 0;
 }
index ee1c268f5f9d6582da5b0eeb5121ada945fcd800..8c0b7b42319c44d7038892d0026582797acad95a 100644 (file)
@@ -92,10 +92,18 @@ static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
 
 static void n_tty_set_room(struct tty_struct *tty)
 {
-       /* tty->read_cnt is not read locked ? */
-       int     left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
+       int left;
        int old_left;
 
+       /* tty->read_cnt is not read locked ? */
+       if (I_PARMRK(tty)) {
+               /* Multiply read_cnt by 3, since each byte might take up to
+                * three times as many spaces when PARMRK is set (depending on
+                * its flags, e.g. parity error). */
+               left = N_TTY_BUF_SIZE - tty->read_cnt * 3 - 1;
+       } else
+               left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
+
        /*
         * If we are doing input canonicalization, and there are no
         * pending newlines, let characters through without limit, so
@@ -1432,6 +1440,12 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
         */
        if (tty->receive_room < TTY_THRESHOLD_THROTTLE)
                tty_throttle(tty);
+
+        /* FIXME: there is a tiny race here if the receive room check runs
+           before the other work executes and empties the buffer (upping
+           the receiving room and unthrottling. We then throttle and get
+           stuck. This has been observed and traced down by Vincent Pillet/
+           We need to address this when we sort out out the rx path locking */
 }
 
 int is_ignored(int sig)
@@ -1460,7 +1474,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
        BUG_ON(!tty);
 
        if (old)
-               canon_change = (old->c_lflag ^ tty->termios->c_lflag) & ICANON;
+               canon_change = (old->c_lflag ^ tty->termios.c_lflag) & ICANON;
        if (canon_change) {
                memset(&tty->read_flags, 0, sizeof tty->read_flags);
                tty->canon_head = tty->read_tail;
@@ -1728,7 +1742,8 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
 
 do_it_again:
 
-       BUG_ON(!tty->read_buf);
+       if (WARN_ON(!tty->read_buf))
+               return -EAGAIN;
 
        c = job_control(tty, file);
        if (c < 0)
@@ -1832,13 +1847,13 @@ do_it_again:
 
                if (tty->icanon && !L_EXTPROC(tty)) {
                        /* N.B. avoid overrun if nr == 0 */
+                       spin_lock_irqsave(&tty->read_lock, flags);
                        while (nr && tty->read_cnt) {
                                int eol;
 
                                eol = test_and_clear_bit(tty->read_tail,
                                                tty->read_flags);
                                c = tty->read_buf[tty->read_tail];
-                               spin_lock_irqsave(&tty->read_lock, flags);
                                tty->read_tail = ((tty->read_tail+1) &
                                                  (N_TTY_BUF_SIZE-1));
                                tty->read_cnt--;
@@ -1856,15 +1871,19 @@ do_it_again:
                                        if (tty_put_user(tty, c, b++)) {
                                                retval = -EFAULT;
                                                b--;
+                                               spin_lock_irqsave(&tty->read_lock, flags);
                                                break;
                                        }
                                        nr--;
                                }
                                if (eol) {
                                        tty_audit_push(tty);
+                                       spin_lock_irqsave(&tty->read_lock, flags);
                                        break;
                                }
+                               spin_lock_irqsave(&tty->read_lock, flags);
                        }
+                       spin_unlock_irqrestore(&tty->read_lock, flags);
                        if (retval)
                                break;
                } else {
index e7592f9037daca81455e9b94d7c31d62fdc5c934..b917c942495474dd91c3f600979537a396e6897b 100644 (file)
@@ -1473,8 +1473,8 @@ static int __devinit nozomi_card_init(struct pci_dev *pdev,
                port->dc = dc;
                tty_port_init(&port->port);
                port->port.ops = &noz_tty_port_ops;
-               tty_dev = tty_register_device(ntty_driver, dc->index_start + i,
-                                                       &pdev->dev);
+               tty_dev = tty_port_register_device(&port->port, ntty_driver,
+                               dc->index_start + i, &pdev->dev);
 
                if (IS_ERR(tty_dev)) {
                        ret = PTR_ERR(tty_dev);
index 5505ffc91da4b5780b33af2cac624ea8f696f5e4..2bace847eb3973010f45848b48c8d28da351fd6b 100644 (file)
@@ -47,6 +47,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
        wake_up_interruptible(&tty->read_wait);
        wake_up_interruptible(&tty->write_wait);
        tty->packet = 0;
+       /* Review - krefs on tty_link ?? */
        if (!tty->link)
                return;
        tty->link->packet = 0;
@@ -62,9 +63,9 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
                        mutex_unlock(&devpts_mutex);
                }
 #endif
-               tty_unlock();
+               tty_unlock(tty);
                tty_vhangup(tty->link);
-               tty_lock();
+               tty_lock(tty);
        }
 }
 
@@ -231,8 +232,8 @@ out:
 static void pty_set_termios(struct tty_struct *tty,
                                        struct ktermios *old_termios)
 {
-       tty->termios->c_cflag &= ~(CSIZE | PARENB);
-       tty->termios->c_cflag |= (CS8 | CREAD);
+       tty->termios.c_cflag &= ~(CSIZE | PARENB);
+       tty->termios.c_cflag |= (CS8 | CREAD);
 }
 
 /**
@@ -282,60 +283,110 @@ done:
        return 0;
 }
 
-/* Traditional BSD devices */
-#ifdef CONFIG_LEGACY_PTYS
-
-static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
+/**
+ *     pty_common_install              -       set up the pty pair
+ *     @driver: the pty driver
+ *     @tty: the tty being instantiated
+ *     @bool: legacy, true if this is BSD style
+ *
+ *     Perform the initial set up for the tty/pty pair. Called from the
+ *     tty layer when the port is first opened.
+ *
+ *     Locking: the caller must hold the tty_mutex
+ */
+static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty,
+               bool legacy)
 {
        struct tty_struct *o_tty;
+       struct tty_port *ports[2];
        int idx = tty->index;
-       int retval;
+       int retval = -ENOMEM;
 
        o_tty = alloc_tty_struct();
        if (!o_tty)
-               return -ENOMEM;
+               goto err;
+       ports[0] = kmalloc(sizeof **ports, GFP_KERNEL);
+       ports[1] = kmalloc(sizeof **ports, GFP_KERNEL);
+       if (!ports[0] || !ports[1])
+               goto err_free_tty;
        if (!try_module_get(driver->other->owner)) {
                /* This cannot in fact currently happen */
-               retval = -ENOMEM;
                goto err_free_tty;
        }
        initialize_tty_struct(o_tty, driver->other, idx);
 
-       /* We always use new tty termios data so we can do this
-          the easy way .. */
-       retval = tty_init_termios(tty);
-       if (retval)
-               goto err_deinit_tty;
-
-       retval = tty_init_termios(o_tty);
-       if (retval)
-               goto err_free_termios;
+       if (legacy) {
+               /* We always use new tty termios data so we can do this
+                  the easy way .. */
+               retval = tty_init_termios(tty);
+               if (retval)
+                       goto err_deinit_tty;
+
+               retval = tty_init_termios(o_tty);
+               if (retval)
+                       goto err_free_termios;
+
+               driver->other->ttys[idx] = o_tty;
+               driver->ttys[idx] = tty;
+       } else {
+               memset(&tty->termios_locked, 0, sizeof(tty->termios_locked));
+               tty->termios = driver->init_termios;
+               memset(&o_tty->termios_locked, 0, sizeof(tty->termios_locked));
+               o_tty->termios = driver->other->init_termios;
+       }
 
        /*
         * Everything allocated ... set up the o_tty structure.
         */
-       driver->other->ttys[idx] = o_tty;
        tty_driver_kref_get(driver->other);
        if (driver->subtype == PTY_TYPE_MASTER)
                o_tty->count++;
        /* Establish the links in both directions */
        tty->link   = o_tty;
        o_tty->link = tty;
+       tty_port_init(ports[0]);
+       tty_port_init(ports[1]);
+       o_tty->port = ports[0];
+       tty->port = ports[1];
 
        tty_driver_kref_get(driver);
        tty->count++;
-       driver->ttys[idx] = tty;
        return 0;
 err_free_termios:
-       tty_free_termios(tty);
+       if (legacy)
+               tty_free_termios(tty);
 err_deinit_tty:
        deinitialize_tty_struct(o_tty);
        module_put(o_tty->driver->owner);
 err_free_tty:
+       kfree(ports[0]);
+       kfree(ports[1]);
        free_tty_struct(o_tty);
+err:
        return retval;
 }
 
+static void pty_cleanup(struct tty_struct *tty)
+{
+       kfree(tty->port);
+}
+
+/* Traditional BSD devices */
+#ifdef CONFIG_LEGACY_PTYS
+
+static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+       return pty_common_install(driver, tty, true);
+}
+
+static void pty_remove(struct tty_driver *driver, struct tty_struct *tty)
+{
+       struct tty_struct *pair = tty->link;
+       driver->ttys[tty->index] = NULL;
+       if (pair)
+               pair->driver->ttys[pair->index] = NULL;
+}
+
 static int pty_bsd_ioctl(struct tty_struct *tty,
                         unsigned int cmd, unsigned long arg)
 {
@@ -366,7 +417,9 @@ static const struct tty_operations master_pty_ops_bsd = {
        .unthrottle = pty_unthrottle,
        .set_termios = pty_set_termios,
        .ioctl = pty_bsd_ioctl,
-       .resize = pty_resize
+       .cleanup = pty_cleanup,
+       .resize = pty_resize,
+       .remove = pty_remove
 };
 
 static const struct tty_operations slave_pty_ops_bsd = {
@@ -379,7 +432,9 @@ static const struct tty_operations slave_pty_ops_bsd = {
        .chars_in_buffer = pty_chars_in_buffer,
        .unthrottle = pty_unthrottle,
        .set_termios = pty_set_termios,
-       .resize = pty_resize
+       .cleanup = pty_cleanup,
+       .resize = pty_resize,
+       .remove = pty_remove
 };
 
 static void __init legacy_pty_init(void)
@@ -389,12 +444,18 @@ static void __init legacy_pty_init(void)
        if (legacy_count <= 0)
                return;
 
-       pty_driver = alloc_tty_driver(legacy_count);
-       if (!pty_driver)
+       pty_driver = tty_alloc_driver(legacy_count,
+                       TTY_DRIVER_RESET_TERMIOS |
+                       TTY_DRIVER_REAL_RAW |
+                       TTY_DRIVER_DYNAMIC_ALLOC);
+       if (IS_ERR(pty_driver))
                panic("Couldn't allocate pty driver");
 
-       pty_slave_driver = alloc_tty_driver(legacy_count);
-       if (!pty_slave_driver)
+       pty_slave_driver = tty_alloc_driver(legacy_count,
+                       TTY_DRIVER_RESET_TERMIOS |
+                       TTY_DRIVER_REAL_RAW |
+                       TTY_DRIVER_DYNAMIC_ALLOC);
+       if (IS_ERR(pty_slave_driver))
                panic("Couldn't allocate pty slave driver");
 
        pty_driver->driver_name = "pty_master";
@@ -410,7 +471,6 @@ static void __init legacy_pty_init(void)
        pty_driver->init_termios.c_lflag = 0;
        pty_driver->init_termios.c_ispeed = 38400;
        pty_driver->init_termios.c_ospeed = 38400;
-       pty_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW;
        pty_driver->other = pty_slave_driver;
        tty_set_operations(pty_driver, &master_pty_ops_bsd);
 
@@ -424,8 +484,6 @@ static void __init legacy_pty_init(void)
        pty_slave_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
        pty_slave_driver->init_termios.c_ispeed = 38400;
        pty_slave_driver->init_termios.c_ospeed = 38400;
-       pty_slave_driver->flags = TTY_DRIVER_RESET_TERMIOS |
-                                       TTY_DRIVER_REAL_RAW;
        pty_slave_driver->other = pty_driver;
        tty_set_operations(pty_slave_driver, &slave_pty_ops_bsd);
 
@@ -497,78 +555,22 @@ static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
        return tty;
 }
 
-static void pty_unix98_shutdown(struct tty_struct *tty)
-{
-       tty_driver_remove_tty(tty->driver, tty);
-       /* We have our own method as we don't use the tty index */
-       kfree(tty->termios);
-}
-
 /* We have no need to install and remove our tty objects as devpts does all
    the work for us */
 
 static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
 {
-       struct tty_struct *o_tty;
-       int idx = tty->index;
-
-       o_tty = alloc_tty_struct();
-       if (!o_tty)
-               return -ENOMEM;
-       if (!try_module_get(driver->other->owner)) {
-               /* This cannot in fact currently happen */
-               goto err_free_tty;
-       }
-       initialize_tty_struct(o_tty, driver->other, idx);
-
-       tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
-       if (tty->termios == NULL)
-               goto err_free_mem;
-       *tty->termios = driver->init_termios;
-       tty->termios_locked = tty->termios + 1;
-
-       o_tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
-       if (o_tty->termios == NULL)
-               goto err_free_mem;
-       *o_tty->termios = driver->other->init_termios;
-       o_tty->termios_locked = o_tty->termios + 1;
-
-       tty_driver_kref_get(driver->other);
-       if (driver->subtype == PTY_TYPE_MASTER)
-               o_tty->count++;
-       /* Establish the links in both directions */
-       tty->link   = o_tty;
-       o_tty->link = tty;
-       /*
-        * All structures have been allocated, so now we install them.
-        * Failures after this point use release_tty to clean up, so
-        * there's no need to null out the local pointers.
-        */
-       tty_driver_kref_get(driver);
-       tty->count++;
-       return 0;
-err_free_mem:
-       deinitialize_tty_struct(o_tty);
-       kfree(o_tty->termios);
-       kfree(tty->termios);
-       module_put(o_tty->driver->owner);
-err_free_tty:
-       free_tty_struct(o_tty);
-       return -ENOMEM;
-}
-
-static void ptm_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
-{
+       return pty_common_install(driver, tty, false);
 }
 
-static void pts_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
+static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
 {
 }
 
 static const struct tty_operations ptm_unix98_ops = {
        .lookup = ptm_unix98_lookup,
        .install = pty_unix98_install,
-       .remove = ptm_unix98_remove,
+       .remove = pty_unix98_remove,
        .open = pty_open,
        .close = pty_close,
        .write = pty_write,
@@ -578,14 +580,14 @@ static const struct tty_operations ptm_unix98_ops = {
        .unthrottle = pty_unthrottle,
        .set_termios = pty_set_termios,
        .ioctl = pty_unix98_ioctl,
-       .shutdown = pty_unix98_shutdown,
-       .resize = pty_resize
+       .resize = pty_resize,
+       .cleanup = pty_cleanup
 };
 
 static const struct tty_operations pty_unix98_ops = {
        .lookup = pts_unix98_lookup,
        .install = pty_unix98_install,
-       .remove = pts_unix98_remove,
+       .remove = pty_unix98_remove,
        .open = pty_open,
        .close = pty_close,
        .write = pty_write,
@@ -594,7 +596,7 @@ static const struct tty_operations pty_unix98_ops = {
        .chars_in_buffer = pty_chars_in_buffer,
        .unthrottle = pty_unthrottle,
        .set_termios = pty_set_termios,
-       .shutdown = pty_unix98_shutdown
+       .cleanup = pty_cleanup,
 };
 
 /**
@@ -622,26 +624,27 @@ static int ptmx_open(struct inode *inode, struct file *filp)
                return retval;
 
        /* find a device that is not in use. */
-       tty_lock();
+       mutex_lock(&devpts_mutex);
        index = devpts_new_index(inode);
-       tty_unlock();
        if (index < 0) {
                retval = index;
                goto err_file;
        }
 
+       mutex_unlock(&devpts_mutex);
+
        mutex_lock(&tty_mutex);
-       mutex_lock(&devpts_mutex);
        tty = tty_init_dev(ptm_driver, index);
-       mutex_unlock(&devpts_mutex);
-       tty_lock();
-       mutex_unlock(&tty_mutex);
 
        if (IS_ERR(tty)) {
                retval = PTR_ERR(tty);
                goto out;
        }
 
+       /* The tty returned here is locked so we can safely
+          drop the mutex */
+       mutex_unlock(&tty_mutex);
+
        set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
 
        tty_add_file(tty, filp);
@@ -654,16 +657,17 @@ static int ptmx_open(struct inode *inode, struct file *filp)
        if (retval)
                goto err_release;
 
-       tty_unlock();
+       tty_unlock(tty);
        return 0;
 err_release:
-       tty_unlock();
+       tty_unlock(tty);
        tty_release(inode, filp);
        return retval;
 out:
+       mutex_unlock(&tty_mutex);
        devpts_kill_index(inode, index);
-       tty_unlock();
 err_file:
+        mutex_unlock(&devpts_mutex);
        tty_free_file(filp);
        return retval;
 }
@@ -672,11 +676,21 @@ static struct file_operations ptmx_fops;
 
 static void __init unix98_pty_init(void)
 {
-       ptm_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
-       if (!ptm_driver)
+       ptm_driver = tty_alloc_driver(NR_UNIX98_PTY_MAX,
+                       TTY_DRIVER_RESET_TERMIOS |
+                       TTY_DRIVER_REAL_RAW |
+                       TTY_DRIVER_DYNAMIC_DEV |
+                       TTY_DRIVER_DEVPTS_MEM |
+                       TTY_DRIVER_DYNAMIC_ALLOC);
+       if (IS_ERR(ptm_driver))
                panic("Couldn't allocate Unix98 ptm driver");
-       pts_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
-       if (!pts_driver)
+       pts_driver = tty_alloc_driver(NR_UNIX98_PTY_MAX,
+                       TTY_DRIVER_RESET_TERMIOS |
+                       TTY_DRIVER_REAL_RAW |
+                       TTY_DRIVER_DYNAMIC_DEV |
+                       TTY_DRIVER_DEVPTS_MEM |
+                       TTY_DRIVER_DYNAMIC_ALLOC);
+       if (IS_ERR(pts_driver))
                panic("Couldn't allocate Unix98 pts driver");
 
        ptm_driver->driver_name = "pty_master";
@@ -692,8 +706,6 @@ static void __init unix98_pty_init(void)
        ptm_driver->init_termios.c_lflag = 0;
        ptm_driver->init_termios.c_ispeed = 38400;
        ptm_driver->init_termios.c_ospeed = 38400;
-       ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
-               TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
        ptm_driver->other = pts_driver;
        tty_set_operations(ptm_driver, &ptm_unix98_ops);
 
@@ -707,8 +719,6 @@ static void __init unix98_pty_init(void)
        pts_driver->init_termios.c_cflag = B38400 | CS8 | CREAD;
        pts_driver->init_termios.c_ispeed = 38400;
        pts_driver->init_termios.c_ospeed = 38400;
-       pts_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
-               TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
        pts_driver->other = ptm_driver;
        tty_set_operations(pts_driver, &pty_unix98_ops);
 
index 777d5f9cf6cc13e4d91c3ec175621aa4c16d2456..9700d34b20a3182794d5f6a4ab5eef8ed050321d 100644 (file)
@@ -704,8 +704,8 @@ static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev)
        spin_lock_init(&info->slock);
        mutex_init(&info->write_mtx);
        rp_table[line] = info;
-       tty_register_device(rocket_driver, line, pci_dev ? &pci_dev->dev :
-                       NULL);
+       tty_port_register_device(&info->port, rocket_driver, line,
+                       pci_dev ? &pci_dev->dev : NULL);
 }
 
 /*
@@ -720,7 +720,7 @@ static void configure_r_port(struct tty_struct *tty, struct r_port *info,
        unsigned rocketMode;
        int bits, baud, divisor;
        CHANNEL_t *cp;
-       struct ktermios *t = tty->termios;
+       struct ktermios *t = &tty->termios;
 
        cp = &info->channel;
        cflag = t->c_cflag;
@@ -978,7 +978,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
                        tty->alt_speed = 460800;
 
                configure_r_port(tty, info, NULL);
-               if (tty->termios->c_cflag & CBAUD) {
+               if (tty->termios.c_cflag & CBAUD) {
                        sSetDTR(cp);
                        sSetRTS(cp);
                }
@@ -1089,35 +1089,35 @@ static void rp_set_termios(struct tty_struct *tty,
        if (rocket_paranoia_check(info, "rp_set_termios"))
                return;
 
-       cflag = tty->termios->c_cflag;
+       cflag = tty->termios.c_cflag;
 
        /*
         * This driver doesn't support CS5 or CS6
         */
        if (((cflag & CSIZE) == CS5) || ((cflag & CSIZE) == CS6))
-               tty->termios->c_cflag =
+               tty->termios.c_cflag =
                    ((cflag & ~CSIZE) | (old_termios->c_cflag & CSIZE));
        /* Or CMSPAR */
-       tty->termios->c_cflag &= ~CMSPAR;
+       tty->termios.c_cflag &= ~CMSPAR;
 
        configure_r_port(tty, info, old_termios);
 
        cp = &info->channel;
 
        /* Handle transition to B0 status */
-       if ((old_termios->c_cflag & CBAUD) && !(tty->termios->c_cflag & CBAUD)) {
+       if ((old_termios->c_cflag & CBAUD) && !(tty->termios.c_cflag & CBAUD)) {
                sClrDTR(cp);
                sClrRTS(cp);
        }
 
        /* Handle transition away from B0 status */
-       if (!(old_termios->c_cflag & CBAUD) && (tty->termios->c_cflag & CBAUD)) {
-               if (!tty->hw_stopped || !(tty->termios->c_cflag & CRTSCTS))
+       if (!(old_termios->c_cflag & CBAUD) && (tty->termios.c_cflag & CBAUD)) {
+               if (!tty->hw_stopped || !(tty->termios.c_cflag & CRTSCTS))
                        sSetRTS(cp);
                sSetDTR(cp);
        }
 
-       if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) {
+       if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios.c_cflag & CRTSCTS)) {
                tty->hw_stopped = 0;
                rp_start(tty);
        }
index 3ed20e435e59bad6a5f150a1c3e32bcca83fc7b3..66c38a3f74cebdbaaefc192e2a923827c050d63e 100644 (file)
@@ -515,7 +515,7 @@ static void change_speed(struct m68k_serial *info, struct tty_struct *tty)
        unsigned cflag;
        int     i;
 
-       cflag = tty->termios->c_cflag;
+       cflag = tty->termios.c_cflag;
        if (!(port = info->port))
                return;
 
@@ -617,7 +617,7 @@ static void rs_set_ldisc(struct tty_struct *tty)
        if (serial_paranoia_check(info, tty->name, "rs_set_ldisc"))
                return;
 
-       info->is_cons = (tty->termios->c_line == N_TTY);
+       info->is_cons = (tty->termios.c_line == N_TTY);
        
        printk("ttyS%d console mode %s\n", info->line, info->is_cons ? "on" : "off");
 }
@@ -985,7 +985,7 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
        change_speed(info, tty);
 
        if ((old_termios->c_cflag & CRTSCTS) &&
-           !(tty->termios->c_cflag & CRTSCTS)) {
+           !(tty->termios.c_cflag & CRTSCTS)) {
                tty->hw_stopped = 0;
                rs_start(tty);
        }
@@ -1070,7 +1070,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
                if (tty->ldisc.close)
                        (tty->ldisc.close)(tty);
                tty->ldisc = ldiscs[N_TTY];
-               tty->termios->c_line = N_TTY;
+               tty->termios.c_line = N_TTY;
                if (tty->ldisc.open)
                        (tty->ldisc.open)(tty);
        }
@@ -1189,12 +1189,6 @@ rs68328_init(void)
        serial_driver->flags = TTY_DRIVER_REAL_RAW;
        tty_set_operations(serial_driver, &rs_ops);
 
-       if (tty_register_driver(serial_driver)) {
-               put_tty_driver(serial_driver);
-               printk(KERN_ERR "Couldn't register serial driver\n");
-               return -ENOMEM;
-       }
-
        local_irq_save(flags);
 
        for(i=0;i<NR_PORTS;i++) {
@@ -1224,8 +1218,17 @@ rs68328_init(void)
                            0,
                            "M68328_UART", info))
                 panic("Unable to attach 68328 serial interrupt\n");
+
+           tty_port_link_device(&info->tport, serial_driver, i);
        }
        local_irq_restore(flags);
+
+       if (tty_register_driver(serial_driver)) {
+               put_tty_driver(serial_driver);
+               printk(KERN_ERR "Couldn't register serial driver\n");
+               return -ENOMEM;
+       }
+
        return 0;
 }
 
index 8123f784bcdacf3bf653fc7c2c1c57ba0540609f..44f52c6f15b9870ad499f1fac41478057ecec268 100644 (file)
@@ -2202,6 +2202,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
        unsigned char cval, fcr = 0;
        unsigned long flags;
        unsigned int baud, quot;
+       int fifo_bug = 0;
 
        switch (termios->c_cflag & CSIZE) {
        case CS5:
@@ -2221,8 +2222,11 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
 
        if (termios->c_cflag & CSTOPB)
                cval |= UART_LCR_STOP;
-       if (termios->c_cflag & PARENB)
+       if (termios->c_cflag & PARENB) {
                cval |= UART_LCR_PARITY;
+               if (up->bugs & UART_BUG_PARITY)
+                       fifo_bug = 1;
+       }
        if (!(termios->c_cflag & PARODD))
                cval |= UART_LCR_EPAR;
 #ifdef CMSPAR
@@ -2246,7 +2250,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
 
        if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) {
                fcr = uart_config[port->type].fcr;
-               if (baud < 2400) {
+               if (baud < 2400 || fifo_bug) {
                        fcr &= ~UART_FCR_TRIGGER_MASK;
                        fcr |= UART_FCR_TRIGGER_1;
                }
@@ -2979,36 +2983,36 @@ void serial8250_resume_port(int line)
 static int __devinit serial8250_probe(struct platform_device *dev)
 {
        struct plat_serial8250_port *p = dev->dev.platform_data;
-       struct uart_port port;
+       struct uart_8250_port uart;
        int ret, i, irqflag = 0;
 
-       memset(&port, 0, sizeof(struct uart_port));
+       memset(&uart, 0, sizeof(uart));
 
        if (share_irqs)
                irqflag = IRQF_SHARED;
 
        for (i = 0; p && p->flags != 0; p++, i++) {
-               port.iobase             = p->iobase;
-               port.membase            = p->membase;
-               port.irq                = p->irq;
-               port.irqflags           = p->irqflags;
-               port.uartclk            = p->uartclk;
-               port.regshift           = p->regshift;
-               port.iotype             = p->iotype;
-               port.flags              = p->flags;
-               port.mapbase            = p->mapbase;
-               port.hub6               = p->hub6;
-               port.private_data       = p->private_data;
-               port.type               = p->type;
-               port.serial_in          = p->serial_in;
-               port.serial_out         = p->serial_out;
-               port.handle_irq         = p->handle_irq;
-               port.handle_break       = p->handle_break;
-               port.set_termios        = p->set_termios;
-               port.pm                 = p->pm;
-               port.dev                = &dev->dev;
-               port.irqflags           |= irqflag;
-               ret = serial8250_register_port(&port);
+               uart.port.iobase        = p->iobase;
+               uart.port.membase       = p->membase;
+               uart.port.irq           = p->irq;
+               uart.port.irqflags      = p->irqflags;
+               uart.port.uartclk       = p->uartclk;
+               uart.port.regshift      = p->regshift;
+               uart.port.iotype        = p->iotype;
+               uart.port.flags         = p->flags;
+               uart.port.mapbase       = p->mapbase;
+               uart.port.hub6          = p->hub6;
+               uart.port.private_data  = p->private_data;
+               uart.port.type          = p->type;
+               uart.port.serial_in     = p->serial_in;
+               uart.port.serial_out    = p->serial_out;
+               uart.port.handle_irq    = p->handle_irq;
+               uart.port.handle_break  = p->handle_break;
+               uart.port.set_termios   = p->set_termios;
+               uart.port.pm            = p->pm;
+               uart.port.dev           = &dev->dev;
+               uart.port.irqflags      |= irqflag;
+               ret = serial8250_register_8250_port(&uart);
                if (ret < 0) {
                        dev_err(&dev->dev, "unable to register port at index %d "
                                "(IO%lx MEM%llx IRQ%d): %d\n", i,
@@ -3081,7 +3085,7 @@ static struct platform_driver serial8250_isa_driver = {
 static struct platform_device *serial8250_isa_devs;
 
 /*
- * serial8250_register_port and serial8250_unregister_port allows for
+ * serial8250_register_8250_port and serial8250_unregister_port allows for
  * 16x50 serial ports to be configured at run-time, to support PCMCIA
  * modems and PCI multiport cards.
  */
@@ -3155,6 +3159,7 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
                uart->port.regshift     = up->port.regshift;
                uart->port.iotype       = up->port.iotype;
                uart->port.flags        = up->port.flags | UPF_BOOT_AUTOCONF;
+               uart->bugs              = up->bugs;
                uart->port.mapbase      = up->port.mapbase;
                uart->port.private_data = up->port.private_data;
                if (up->port.dev)
@@ -3197,29 +3202,6 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
 }
 EXPORT_SYMBOL(serial8250_register_8250_port);
 
-/**
- *     serial8250_register_port - register a serial port
- *     @port: serial port template
- *
- *     Configure the serial port specified by the request. If the
- *     port exists and is in use, it is hung up and unregistered
- *     first.
- *
- *     The port is then probed and if necessary the IRQ is autodetected
- *     If this fails an error is returned.
- *
- *     On success the port is ready to use and the line number is returned.
- */
-int serial8250_register_port(struct uart_port *port)
-{
-       struct uart_8250_port up;
-
-       memset(&up, 0, sizeof(up));
-       memcpy(&up.port, port, sizeof(*port));
-       return serial8250_register_8250_port(&up);
-}
-EXPORT_SYMBOL(serial8250_register_port);
-
 /**
  *     serial8250_unregister_port - remove a 16x50 serial port at runtime
  *     @line: serial line number
index f9719d167c8d74f3159d995b09899bc52eab8294..972b5212b58cbc3f28fef7a112fbbda17301606c 100644 (file)
 
 #include <linux/serial_8250.h>
 
-struct uart_8250_port {
-       struct uart_port        port;
-       struct timer_list       timer;          /* "no irq" timer */
-       struct list_head        list;           /* ports on this IRQ */
-       unsigned short          capabilities;   /* port capabilities */
-       unsigned short          bugs;           /* port bugs */
-       unsigned int            tx_loadsz;      /* transmit fifo load size */
-       unsigned char           acr;
-       unsigned char           ier;
-       unsigned char           lcr;
-       unsigned char           mcr;
-       unsigned char           mcr_mask;       /* mask of user bits */
-       unsigned char           mcr_force;      /* mask of forced bits */
-       unsigned char           cur_iotype;     /* Running I/O type */
-
-       /*
-        * Some bits in registers are cleared on a read, so they must
-        * be saved whenever the register is read but the bits will not
-        * be immediately processed.
-        */
-#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS
-       unsigned char           lsr_saved_flags;
-#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
-       unsigned char           msr_saved_flags;
-
-       /* 8250 specific callbacks */
-       int                     (*dl_read)(struct uart_8250_port *);
-       void                    (*dl_write)(struct uart_8250_port *, int);
-};
-
 struct old_serial_port {
        unsigned int uart;
        unsigned int baud_base;
@@ -78,6 +48,7 @@ struct serial8250_config {
 #define UART_BUG_TXEN  (1 << 1)        /* UART has buggy TX IIR status */
 #define UART_BUG_NOMSR (1 << 2)        /* UART has buggy MSR status bits (Au1x00) */
 #define UART_BUG_THRE  (1 << 3)        /* UART has buggy THRE reassertion */
+#define UART_BUG_PARITY        (1 << 4)        /* UART mishandles parity if FIFO enabled */
 
 #define PROBE_RSA      (1 << 0)
 #define PROBE_ANY      (~0)
index b0ce8c56f1a4dcdb8ac077888ed3973756b8f2e6..857498312a9a84146b6c4c3493c224491fc1213d 100644 (file)
@@ -43,7 +43,7 @@ serial_card_probe(struct expansion_card *ec, const struct ecard_id *id)
 {
        struct serial_card_info *info;
        struct serial_card_type *type = id->data;
-       struct uart_port port;
+       struct uart_8250_port uart;
        unsigned long bus_addr;
        unsigned int i;
 
@@ -62,19 +62,19 @@ serial_card_probe(struct expansion_card *ec, const struct ecard_id *id)
 
        ecard_set_drvdata(ec, info);
 
-       memset(&port, 0, sizeof(struct uart_port));
-       port.irq        = ec->irq;
-       port.flags      = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
-       port.uartclk    = type->uartclk;
-       port.iotype     = UPIO_MEM;
-       port.regshift   = 2;
-       port.dev        = &ec->dev;
+       memset(&uart, 0, sizeof(struct uart_8250_port));
+       uart.port.irq   = ec->irq;
+       uart.port.flags = UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
+       uart.port.uartclk       = type->uartclk;
+       uart.port.iotype        = UPIO_MEM;
+       uart.port.regshift      = 2;
+       uart.port.dev   = &ec->dev;
 
        for (i = 0; i < info->num_ports; i ++) {
-               port.membase = info->vaddr + type->offset[i];
-               port.mapbase = bus_addr + type->offset[i];
+               uart.port.membase = info->vaddr + type->offset[i];
+               uart.port.mapbase = bus_addr + type->offset[i];
 
-               info->ports[i] = serial8250_register_port(&port);
+               info->ports[i] = serial8250_register_8250_port(&uart);
        }
 
        return 0;
index f574eef3075f987b41784c635400f970947e9480..c3b2ec0c8c0b7f3a6749f41feedb38fe0af58ac2 100644 (file)
@@ -89,7 +89,7 @@ static int dw8250_handle_irq(struct uart_port *p)
 
 static int __devinit dw8250_probe(struct platform_device *pdev)
 {
-       struct uart_port port = {};
+       struct uart_8250_port uart = {};
        struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        struct device_node *np = pdev->dev.of_node;
@@ -104,28 +104,28 @@ static int __devinit dw8250_probe(struct platform_device *pdev)
        data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;
-       port.private_data = data;
-
-       spin_lock_init(&port.lock);
-       port.mapbase = regs->start;
-       port.irq = irq->start;
-       port.handle_irq = dw8250_handle_irq;
-       port.type = PORT_8250;
-       port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP |
+       uart.port.private_data = data;
+
+       spin_lock_init(&uart.port.lock);
+       uart.port.mapbase = regs->start;
+       uart.port.irq = irq->start;
+       uart.port.handle_irq = dw8250_handle_irq;
+       uart.port.type = PORT_8250;
+       uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP |
                UPF_FIXED_PORT | UPF_FIXED_TYPE;
-       port.dev = &pdev->dev;
+       uart.port.dev = &pdev->dev;
 
-       port.iotype = UPIO_MEM;
-       port.serial_in = dw8250_serial_in;
-       port.serial_out = dw8250_serial_out;
+       uart.port.iotype = UPIO_MEM;
+       uart.port.serial_in = dw8250_serial_in;
+       uart.port.serial_out = dw8250_serial_out;
        if (!of_property_read_u32(np, "reg-io-width", &val)) {
                switch (val) {
                case 1:
                        break;
                case 4:
-                       port.iotype = UPIO_MEM32;
-                       port.serial_in = dw8250_serial_in32;
-                       port.serial_out = dw8250_serial_out32;
+                       uart.port.iotype = UPIO_MEM32;
+                       uart.port.serial_in = dw8250_serial_in32;
+                       uart.port.serial_out = dw8250_serial_out32;
                        break;
                default:
                        dev_err(&pdev->dev, "unsupported reg-io-width (%u)\n",
@@ -135,15 +135,15 @@ static int __devinit dw8250_probe(struct platform_device *pdev)
        }
 
        if (!of_property_read_u32(np, "reg-shift", &val))
-               port.regshift = val;
+               uart.port.regshift = val;
 
        if (of_property_read_u32(np, "clock-frequency", &val)) {
                dev_err(&pdev->dev, "no clock-frequency property set\n");
                return -EINVAL;
        }
-       port.uartclk = val;
+       uart.port.uartclk = val;
 
-       data->line = serial8250_register_port(&port);
+       data->line = serial8250_register_8250_port(&uart);
        if (data->line < 0)
                return data->line;
 
index d8c0ffbfa6e39b53bafaef22f2d090e2739613e9..097dff9c08ad9e4ebec835f20800e6d118931bd0 100644 (file)
@@ -26,7 +26,7 @@
 
 static int __init serial_init_chip(struct parisc_device *dev)
 {
-       struct uart_port port;
+       struct uart_8250_port uart;
        unsigned long address;
        int err;
 
@@ -48,21 +48,21 @@ static int __init serial_init_chip(struct parisc_device *dev)
        if (dev->id.sversion != 0x8d)
                address += 0x800;
 
-       memset(&port, 0, sizeof(port));
-       port.iotype     = UPIO_MEM;
+       memset(&uart, 0, sizeof(uart));
+       uart.port.iotype        = UPIO_MEM;
        /* 7.272727MHz on Lasi.  Assumed the same for Dino, Wax and Timi. */
-       port.uartclk    = 7272727;
-       port.mapbase    = address;
-       port.membase    = ioremap_nocache(address, 16);
-       port.irq        = dev->irq;
-       port.flags      = UPF_BOOT_AUTOCONF;
-       port.dev        = &dev->dev;
-
-       err = serial8250_register_port(&port);
+       uart.port.uartclk       = 7272727;
+       uart.port.mapbase       = address;
+       uart.port.membase       = ioremap_nocache(address, 16);
+       uart.port.irq   = dev->irq;
+       uart.port.flags = UPF_BOOT_AUTOCONF;
+       uart.port.dev   = &dev->dev;
+
+       err = serial8250_register_8250_port(&uart);
        if (err < 0) {
                printk(KERN_WARNING
-                       "serial8250_register_port returned error %d\n", err);
-               iounmap(port.membase);
+                       "serial8250_register_8250_port returned error %d\n", err);
+               iounmap(uart.port.membase);
                return err;
        }
 
index c13438c930129a0b4e736fd67630a1ef9338345b..8f1dd2cc00a8de79ac9538248271d2be376336aa 100644 (file)
@@ -171,7 +171,7 @@ static int __devinit hpdca_init_one(struct dio_dev *d,
                return 0;
        }
 #endif
-       memset(&port, 0, sizeof(struct uart_port));
+       memset(&uart, 0, sizeof(uart));
 
        /* Memory mapped I/O */
        port.iotype = UPIO_MEM;
@@ -182,7 +182,7 @@ static int __devinit hpdca_init_one(struct dio_dev *d,
        port.membase = (char *)(port.mapbase + DIO_VIRADDRBASE);
        port.regshift = 1;
        port.dev = &d->dev;
-       line = serial8250_register_port(&port);
+       line = serial8250_register_8250_port(&uart);
 
        if (line < 0) {
                printk(KERN_NOTICE "8250_hp300: register_serial() DCA scode %d"
@@ -210,7 +210,7 @@ static int __init hp300_8250_init(void)
 #ifdef CONFIG_HPAPCI
        int line;
        unsigned long base;
-       struct uart_port uport;
+       struct uart_8250_port uart;
        struct hp300_port *port;
        int i;
 #endif
@@ -248,26 +248,26 @@ static int __init hp300_8250_init(void)
                if (!port)
                        return -ENOMEM;
 
-               memset(&uport, 0, sizeof(struct uart_port));
+               memset(&uart, 0, sizeof(uart));
 
                base = (FRODO_BASE + FRODO_APCI_OFFSET(i));
 
                /* Memory mapped I/O */
-               uport.iotype = UPIO_MEM;
-               uport.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ \
+               uart.port.iotype = UPIO_MEM;
+               uart.port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ \
                              | UPF_BOOT_AUTOCONF;
                /* XXX - no interrupt support yet */
-               uport.irq = 0;
-               uport.uartclk = HPAPCI_BAUD_BASE * 16;
-               uport.mapbase = base;
-               uport.membase = (char *)(base + DIO_VIRADDRBASE);
-               uport.regshift = 2;
+               uart.port.irq = 0;
+               uart.port.uartclk = HPAPCI_BAUD_BASE * 16;
+               uart.port.mapbase = base;
+               uart.port.membase = (char *)(base + DIO_VIRADDRBASE);
+               uart.port.regshift = 2;
 
-               line = serial8250_register_port(&uport);
+               line = serial8250_register_8250_port(&uart);
 
                if (line < 0) {
                        printk(KERN_NOTICE "8250_hp300: register_serial() APCI"
-                              " %d irq %d failed\n", i, uport.irq);
+                              " %d irq %d failed\n", i, uart.port.irq);
                        kfree(port);
                        continue;
                }
index 28e7c7cce8935acc8257fafaff86121fa55bf6dd..ad4bb8dec36fb86ce9b0c25d74d3516112b1029b 100644 (file)
@@ -44,7 +44,7 @@ struct pci_serial_quirk {
        int     (*init)(struct pci_dev *dev);
        int     (*setup)(struct serial_private *,
                         const struct pciserial_board *,
-                        struct uart_port *, int);
+                        struct uart_8250_port *, int);
        void    (*exit)(struct pci_dev *dev);
 };
 
@@ -59,7 +59,7 @@ struct serial_private {
 };
 
 static int pci_default_setup(struct serial_private*,
-         const struct pciserial_board*, struct uart_port*, int);
+         const struct pciserial_board*, struct uart_8250_port *, int);
 
 static void moan_device(const char *str, struct pci_dev *dev)
 {
@@ -74,7 +74,7 @@ static void moan_device(const char *str, struct pci_dev *dev)
 }
 
 static int
-setup_port(struct serial_private *priv, struct uart_port *port,
+setup_port(struct serial_private *priv, struct uart_8250_port *port,
           int bar, int offset, int regshift)
 {
        struct pci_dev *dev = priv->dev;
@@ -93,17 +93,17 @@ setup_port(struct serial_private *priv, struct uart_port *port,
                if (!priv->remapped_bar[bar])
                        return -ENOMEM;
 
-               port->iotype = UPIO_MEM;
-               port->iobase = 0;
-               port->mapbase = base + offset;
-               port->membase = priv->remapped_bar[bar] + offset;
-               port->regshift = regshift;
+               port->port.iotype = UPIO_MEM;
+               port->port.iobase = 0;
+               port->port.mapbase = base + offset;
+               port->port.membase = priv->remapped_bar[bar] + offset;
+               port->port.regshift = regshift;
        } else {
-               port->iotype = UPIO_PORT;
-               port->iobase = base + offset;
-               port->mapbase = 0;
-               port->membase = NULL;
-               port->regshift = 0;
+               port->port.iotype = UPIO_PORT;
+               port->port.iobase = base + offset;
+               port->port.mapbase = 0;
+               port->port.membase = NULL;
+               port->port.regshift = 0;
        }
        return 0;
 }
@@ -113,7 +113,7 @@ setup_port(struct serial_private *priv, struct uart_port *port,
  */
 static int addidata_apci7800_setup(struct serial_private *priv,
                                const struct pciserial_board *board,
-                               struct uart_port *port, int idx)
+                               struct uart_8250_port *port, int idx)
 {
        unsigned int bar = 0, offset = board->first_offset;
        bar = FL_GET_BASE(board->flags);
@@ -140,7 +140,7 @@ static int addidata_apci7800_setup(struct serial_private *priv,
  */
 static int
 afavlab_setup(struct serial_private *priv, const struct pciserial_board *board,
-             struct uart_port *port, int idx)
+             struct uart_8250_port *port, int idx)
 {
        unsigned int bar, offset = board->first_offset;
 
@@ -195,7 +195,7 @@ static int pci_hp_diva_init(struct pci_dev *dev)
 static int
 pci_hp_diva_setup(struct serial_private *priv,
                const struct pciserial_board *board,
-               struct uart_port *port, int idx)
+               struct uart_8250_port *port, int idx)
 {
        unsigned int offset = board->first_offset;
        unsigned int bar = FL_GET_BASE(board->flags);
@@ -370,7 +370,7 @@ static void __devexit pci_ni8430_exit(struct pci_dev *dev)
 /* SBS Technologies Inc. PMC-OCTPRO and P-OCTAL cards */
 static int
 sbs_setup(struct serial_private *priv, const struct pciserial_board *board,
-               struct uart_port *port, int idx)
+               struct uart_8250_port *port, int idx)
 {
        unsigned int bar, offset = board->first_offset;
 
@@ -525,7 +525,7 @@ static int pci_siig_init(struct pci_dev *dev)
 
 static int pci_siig_setup(struct serial_private *priv,
                          const struct pciserial_board *board,
-                         struct uart_port *port, int idx)
+                         struct uart_8250_port *port, int idx)
 {
        unsigned int bar = FL_GET_BASE(board->flags) + idx, offset = 0;
 
@@ -619,7 +619,7 @@ static int pci_timedia_init(struct pci_dev *dev)
 static int
 pci_timedia_setup(struct serial_private *priv,
                  const struct pciserial_board *board,
-                 struct uart_port *port, int idx)
+                 struct uart_8250_port *port, int idx)
 {
        unsigned int bar = 0, offset = board->first_offset;
 
@@ -653,7 +653,7 @@ pci_timedia_setup(struct serial_private *priv,
 static int
 titan_400l_800l_setup(struct serial_private *priv,
                      const struct pciserial_board *board,
-                     struct uart_port *port, int idx)
+                     struct uart_8250_port *port, int idx)
 {
        unsigned int bar, offset = board->first_offset;
 
@@ -754,7 +754,7 @@ static int pci_ni8430_init(struct pci_dev *dev)
 static int
 pci_ni8430_setup(struct serial_private *priv,
                 const struct pciserial_board *board,
-                struct uart_port *port, int idx)
+                struct uart_8250_port *port, int idx)
 {
        void __iomem *p;
        unsigned long base, len;
@@ -781,7 +781,7 @@ pci_ni8430_setup(struct serial_private *priv,
 
 static int pci_netmos_9900_setup(struct serial_private *priv,
                                const struct pciserial_board *board,
-                               struct uart_port *port, int idx)
+                               struct uart_8250_port *port, int idx)
 {
        unsigned int bar;
 
@@ -1032,10 +1032,17 @@ static int pci_oxsemi_tornado_init(struct pci_dev *dev)
        return number_uarts;
 }
 
-static int
-pci_default_setup(struct serial_private *priv,
+static int pci_asix_setup(struct serial_private *priv,
                  const struct pciserial_board *board,
-                 struct uart_port *port, int idx)
+                 struct uart_8250_port *port, int idx)
+{
+       port->bugs |= UART_BUG_PARITY;
+       return pci_default_setup(priv, board, port, idx);
+}
+
+static int pci_default_setup(struct serial_private *priv,
+                 const struct pciserial_board *board,
+                 struct uart_8250_port *port, int idx)
 {
        unsigned int bar, offset = board->first_offset, maxnr;
 
@@ -1057,15 +1064,15 @@ pci_default_setup(struct serial_private *priv,
 static int
 ce4100_serial_setup(struct serial_private *priv,
                  const struct pciserial_board *board,
-                 struct uart_port *port, int idx)
+                 struct uart_8250_port *port, int idx)
 {
        int ret;
 
        ret = setup_port(priv, port, 0, 0, board->reg_shift);
-       port->iotype = UPIO_MEM32;
-       port->type = PORT_XSCALE;
-       port->flags = (port->flags | UPF_FIXED_PORT | UPF_FIXED_TYPE);
-       port->regshift = 2;
+       port->port.iotype = UPIO_MEM32;
+       port->port.type = PORT_XSCALE;
+       port->port.flags = (port->port.flags | UPF_FIXED_PORT | UPF_FIXED_TYPE);
+       port->port.regshift = 2;
 
        return ret;
 }
@@ -1073,16 +1080,16 @@ ce4100_serial_setup(struct serial_private *priv,
 static int
 pci_omegapci_setup(struct serial_private *priv,
                      const struct pciserial_board *board,
-                     struct uart_port *port, int idx)
+                     struct uart_8250_port *port, int idx)
 {
        return setup_port(priv, port, 2, idx * 8, 0);
 }
 
 static int skip_tx_en_setup(struct serial_private *priv,
                        const struct pciserial_board *board,
-                       struct uart_port *port, int idx)
+                       struct uart_8250_port *port, int idx)
 {
-       port->flags |= UPF_NO_TXEN_TEST;
+       port->port.flags |= UPF_NO_TXEN_TEST;
        printk(KERN_DEBUG "serial8250: skipping TxEn test for device "
                          "[%04x:%04x] subsystem [%04x:%04x]\n",
                          priv->dev->vendor,
@@ -1131,11 +1138,11 @@ static unsigned int kt_serial_in(struct uart_port *p, int offset)
 
 static int kt_serial_setup(struct serial_private *priv,
                           const struct pciserial_board *board,
-                          struct uart_port *port, int idx)
+                          struct uart_8250_port *port, int idx)
 {
-       port->flags |= UPF_BUG_THRE;
-       port->serial_in = kt_serial_in;
-       port->handle_break = kt_handle_break;
+       port->port.flags |= UPF_BUG_THRE;
+       port->port.serial_in = kt_serial_in;
+       port->port.handle_break = kt_handle_break;
        return skip_tx_en_setup(priv, board, port, idx);
 }
 
@@ -1151,9 +1158,9 @@ static int pci_eg20t_init(struct pci_dev *dev)
 static int
 pci_xr17c154_setup(struct serial_private *priv,
                  const struct pciserial_board *board,
-                 struct uart_port *port, int idx)
+                 struct uart_8250_port *port, int idx)
 {
-       port->flags |= UPF_EXAR_EFR;
+       port->port.flags |= UPF_EXAR_EFR;
        return pci_default_setup(priv, board, port, idx);
 }
 
@@ -1187,6 +1194,9 @@ pci_xr17c154_setup(struct serial_private *priv,
 #define PCIE_DEVICE_ID_NEO_2_OX_IBM    0x00F6
 #define PCI_DEVICE_ID_PLX_CRONYX_OMEGA 0xc001
 #define PCI_DEVICE_ID_INTEL_PATSBURG_KT 0x1d3d
+#define PCI_VENDOR_ID_AGESTAR          0x5372
+#define PCI_DEVICE_ID_AGESTAR_9375     0x6872
+#define PCI_VENDOR_ID_ASIX             0x9710
 
 /* Unknown vendors/cards - this should not be in linux/pci_ids.h */
 #define PCI_SUBDEVICE_ID_UNKNOWN_0x1584        0x1584
@@ -1726,7 +1736,17 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
                .subvendor      = PCI_ANY_ID,
                .subdevice      = PCI_ANY_ID,
                .setup          = pci_omegapci_setup,
-        },
+       },
+       /*
+        * ASIX devices with FIFO bug
+        */
+       {
+               .vendor         = PCI_VENDOR_ID_ASIX,
+               .device         = PCI_ANY_ID,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = pci_asix_setup,
+       },
        /*
         * Default "match everything" terminator entry
         */
@@ -1887,7 +1907,6 @@ enum pci_board_num_t {
        pbn_panacom,
        pbn_panacom2,
        pbn_panacom4,
-       pbn_exsys_4055,
        pbn_plx_romulus,
        pbn_oxsemi,
        pbn_oxsemi_1_4000000,
@@ -2393,13 +2412,6 @@ static struct pciserial_board pci_boards[] __devinitdata = {
                .reg_shift      = 7,
        },
 
-       [pbn_exsys_4055] = {
-               .flags          = FL_BASE2,
-               .num_ports      = 4,
-               .base_baud      = 115200,
-               .uart_offset    = 8,
-       },
-
        /* I think this entry is broken - the first_offset looks wrong --rmk */
        [pbn_plx_romulus] = {
                .flags          = FL_BASE2,
@@ -2728,7 +2740,7 @@ serial_pci_matches(const struct pciserial_board *board,
 struct serial_private *
 pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board)
 {
-       struct uart_port serial_port;
+       struct uart_8250_port uart;
        struct serial_private *priv;
        struct pci_serial_quirk *quirk;
        int rc, nr_ports, i;
@@ -2768,22 +2780,22 @@ pciserial_init_ports(struct pci_dev *dev, const struct pciserial_board *board)
        priv->dev = dev;
        priv->quirk = quirk;
 
-       memset(&serial_port, 0, sizeof(struct uart_port));
-       serial_port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
-       serial_port.uartclk = board->base_baud * 16;
-       serial_port.irq = get_pci_irq(dev, board);
-       serial_port.dev = &dev->dev;
+       memset(&uart, 0, sizeof(uart));
+       uart.port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF | UPF_SHARE_IRQ;
+       uart.port.uartclk = board->base_baud * 16;
+       uart.port.irq = get_pci_irq(dev, board);
+       uart.port.dev = &dev->dev;
 
        for (i = 0; i < nr_ports; i++) {
-               if (quirk->setup(priv, board, &serial_port, i))
+               if (quirk->setup(priv, board, &uart, i))
                        break;
 
 #ifdef SERIAL_DEBUG_PCI
                printk(KERN_DEBUG "Setup PCI port: port %lx, irq %d, type %d\n",
-                      serial_port.iobase, serial_port.irq, serial_port.iotype);
+                      uart.port.iobase, uart.port.irq, uart.port.iotype);
 #endif
 
-               priv->line[i] = serial8250_register_port(&serial_port);
+               priv->line[i] = serial8250_register_8250_port(&uart);
                if (priv->line[i] < 0) {
                        printk(KERN_WARNING "Couldn't register serial port %s: %d\n", pci_name(dev), priv->line[i]);
                        break;
@@ -3193,7 +3205,7 @@ static struct pci_device_id serial_pci_tbl[] = {
        {       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
                PCI_SUBVENDOR_ID_EXSYS,
                PCI_SUBDEVICE_ID_EXSYS_4055, 0, 0,
-               pbn_exsys_4055 },
+               pbn_b2_4_115200 },
        /*
         * Megawolf Romulus PCI Serial Card, from Mike Hudson
         * (Exoray@isys.ca)
@@ -4178,6 +4190,12 @@ static struct pci_device_id serial_pci_tbl[] = {
                PCI_ANY_ID, PCI_ANY_ID, 0, 0,
                pbn_omegapci },
 
+       /*
+        * AgeStar as-prs2-009
+        */
+       {       PCI_VENDOR_ID_AGESTAR, PCI_DEVICE_ID_AGESTAR_9375,
+               PCI_ANY_ID, PCI_ANY_ID,
+               0, 0, pbn_b0_bt_2_115200 },
        /*
         * These entries match devices with class COMMUNICATION_SERIAL,
         * COMMUNICATION_MODEM or COMMUNICATION_MULTISERIAL
index a2f236510ff1cd3f7fc92524f6096dc8678946f0..fde5aa60d51e92391dfdb996a7065d25d4f12c00 100644 (file)
@@ -424,7 +424,7 @@ static int __devinit serial_pnp_guess_board(struct pnp_dev *dev, int *flags)
 static int __devinit
 serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
 {
-       struct uart_port port;
+       struct uart_8250_port uart;
        int ret, line, flags = dev_id->driver_data;
 
        if (flags & UNKNOWN_DEV) {
@@ -433,32 +433,32 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
                        return ret;
        }
 
-       memset(&port, 0, sizeof(struct uart_port));
+       memset(&uart, 0, sizeof(uart));
        if (pnp_irq_valid(dev, 0))
-               port.irq = pnp_irq(dev, 0);
+               uart.port.irq = pnp_irq(dev, 0);
        if (pnp_port_valid(dev, 0)) {
-               port.iobase = pnp_port_start(dev, 0);
-               port.iotype = UPIO_PORT;
+               uart.port.iobase = pnp_port_start(dev, 0);
+               uart.port.iotype = UPIO_PORT;
        } else if (pnp_mem_valid(dev, 0)) {
-               port.mapbase = pnp_mem_start(dev, 0);
-               port.iotype = UPIO_MEM;
-               port.flags = UPF_IOREMAP;
+               uart.port.mapbase = pnp_mem_start(dev, 0);
+               uart.port.iotype = UPIO_MEM;
+               uart.port.flags = UPF_IOREMAP;
        } else
                return -ENODEV;
 
 #ifdef SERIAL_DEBUG_PNP
        printk(KERN_DEBUG
                "Setup PNP port: port %x, mem 0x%lx, irq %d, type %d\n",
-                      port.iobase, port.mapbase, port.irq, port.iotype);
+                      uart.port.iobase, uart.port.mapbase, uart.port.irq, uart.port.iotype);
 #endif
 
-       port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
+       uart.port.flags |= UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
        if (pnp_irq_flags(dev, 0) & IORESOURCE_IRQ_SHAREABLE)
-               port.flags |= UPF_SHARE_IRQ;
-       port.uartclk = 1843200;
-       port.dev = &dev->dev;
+               uart.port.flags |= UPF_SHARE_IRQ;
+       uart.port.uartclk = 1843200;
+       uart.port.dev = &dev->dev;
 
-       line = serial8250_register_port(&port);
+       line = serial8250_register_8250_port(&uart);
        if (line < 0)
                return -ENODEV;
 
index 29b695d041ecd45cdfe18914b8c02d10ff7f79a5..b7d48b346393f08e2a44c88fa0e2c99e3a9c652b 100644 (file)
@@ -73,7 +73,7 @@ struct serial_quirk {
        unsigned int prodid;
        int multi;              /* 1 = multifunction, > 1 = # ports */
        void (*config)(struct pcmcia_device *);
-       void (*setup)(struct pcmcia_device *, struct uart_port *);
+       void (*setup)(struct pcmcia_device *, struct uart_8250_port *);
        void (*wakeup)(struct pcmcia_device *);
        int (*post)(struct pcmcia_device *);
 };
@@ -105,9 +105,9 @@ struct serial_cfg_mem {
  * Elan VPU16551 UART with 14.7456MHz oscillator
  * manfid 0x015D, 0x4C45
  */
-static void quirk_setup_brainboxes_0104(struct pcmcia_device *link, struct uart_port *port)
+static void quirk_setup_brainboxes_0104(struct pcmcia_device *link, struct uart_8250_port *uart)
 {
-       port->uartclk = 14745600;
+       uart->port.uartclk = 14745600;
 }
 
 static int quirk_post_ibm(struct pcmcia_device *link)
@@ -343,25 +343,25 @@ static void serial_detach(struct pcmcia_device *link)
 static int setup_serial(struct pcmcia_device *handle, struct serial_info * info,
                        unsigned int iobase, int irq)
 {
-       struct uart_port port;
+       struct uart_8250_port uart;
        int line;
 
-       memset(&port, 0, sizeof (struct uart_port));
-       port.iobase = iobase;
-       port.irq = irq;
-       port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
-       port.uartclk = 1843200;
-       port.dev = &handle->dev;
+       memset(&uart, 0, sizeof(uart));
+       uart.port.iobase = iobase;
+       uart.port.irq = irq;
+       uart.port.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
+       uart.port.uartclk = 1843200;
+       uart.port.dev = &handle->dev;
        if (buggy_uart)
-               port.flags |= UPF_BUGGY_UART;
+               uart.port.flags |= UPF_BUGGY_UART;
 
        if (info->quirk && info->quirk->setup)
-               info->quirk->setup(handle, &port);
+               info->quirk->setup(handle, &uart);
 
-       line = serial8250_register_port(&port);
+       line = serial8250_register_8250_port(&uart);
        if (line < 0) {
-               printk(KERN_NOTICE "serial_cs: serial8250_register_port() at "
-                      "0x%04lx, irq %d failed\n", (u_long)iobase, irq);
+               pr_err("serial_cs: serial8250_register_8250_port() at 0x%04lx, irq %d failed\n",
+                                                       (unsigned long)iobase, irq);
                return -EINVAL;
        }
 
index 070b442c1f81abb08ffee6cd69e3ffe0ab87b209..04b9e13045d7fba2b7a6f74be49edf377877f4cf 100644 (file)
@@ -160,10 +160,12 @@ config SERIAL_KS8695_CONSOLE
 
 config SERIAL_CLPS711X
        tristate "CLPS711X serial port support"
-       depends on ARM && ARCH_CLPS711X
+       depends on ARCH_CLPS711X
        select SERIAL_CORE
+       default y
        help
-         ::: To be written :::
+         This enables the driver for the on-chip UARTs of the Cirrus
+         Logic EP711x/EP721x/EP731x processors.
 
 config SERIAL_CLPS711X_CONSOLE
        bool "Support for console on CLPS711X serial port"
@@ -173,9 +175,7 @@ config SERIAL_CLPS711X_CONSOLE
          Even if you say Y here, the currently visible virtual console
          (/dev/tty0) will still be used as the system console by default, but
          you can alter that using a kernel command line option such as
-         "console=ttyCL1". (Try "man bootparam" or see the documentation of
-         your boot loader (lilo or loadlin) about how to pass options to the
-         kernel at boot time.)
+         "console=ttyCL1".
 
 config SERIAL_SAMSUNG
        tristate "Samsung SoC serial support"
@@ -257,12 +257,19 @@ config SERIAL_MAX3100
        help
          MAX3100 chip support
 
-config SERIAL_MAX3107
-       tristate "MAX3107 support"
+config SERIAL_MAX310X
+       bool "MAX310X support"
        depends on SPI
        select SERIAL_CORE
+       select REGMAP_SPI if SPI
+       default n
        help
-         MAX3107 chip support
+         This selects support for an advanced UART from Maxim (Dallas).
+         Supported ICs are MAX3107, MAX3108.
+         Each IC contains 128 words each of receive and transmit FIFO
+         that can be controlled through I2C or high-speed SPI.
+
+         Say Y here if you want to support this ICs.
 
 config SERIAL_DZ
        bool "DECstation DZ serial driver"
@@ -704,6 +711,25 @@ config SERIAL_PNX8XXX_CONSOLE
          If you have a MIPS-based Philips SoC such as PNX8550 or PNX8330
          and you want to use serial console, say Y. Otherwise, say N.
 
+config SERIAL_HS_LPC32XX
+       tristate "LPC32XX high speed serial port support"
+       depends on ARCH_LPC32XX && OF
+       select SERIAL_CORE
+       help
+         Support for the LPC32XX high speed serial ports (up to 900kbps).
+         Those are UARTs completely different from the Standard UARTs on the
+         LPC32XX SoC.
+         Choose M or Y here to build this driver.
+
+config SERIAL_HS_LPC32XX_CONSOLE
+       bool "Enable LPC32XX high speed UART serial console"
+       depends on SERIAL_HS_LPC32XX
+       select SERIAL_CORE_CONSOLE
+       help
+         If you would like to be able to use one of the high speed serial
+         ports on the LPC32XX as the console, you can do so by answering
+         Y to this option.
+
 config SERIAL_CORE
        tristate
 
index 7257c5d898ae2d36da427c3f6a9e225f1a0741ae..2af9e5279dabd5ce97dc41abb453ed05125dae32 100644 (file)
@@ -28,12 +28,13 @@ obj-$(CONFIG_SERIAL_BFIN) += bfin_uart.o
 obj-$(CONFIG_SERIAL_BFIN_SPORT) += bfin_sport_uart.o
 obj-$(CONFIG_SERIAL_SAMSUNG) += samsung.o
 obj-$(CONFIG_SERIAL_MAX3100) += max3100.o
-obj-$(CONFIG_SERIAL_MAX3107) += max3107.o
+obj-$(CONFIG_SERIAL_MAX310X) += max310x.o
 obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o
 obj-$(CONFIG_SERIAL_MUX) += mux.o
 obj-$(CONFIG_SERIAL_68328) += 68328serial.o
 obj-$(CONFIG_SERIAL_MCF) += mcf.o
 obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o
+obj-$(CONFIG_SERIAL_HS_LPC32XX) += lpc32xx_hs.o
 obj-$(CONFIG_SERIAL_DZ) += dz.o
 obj-$(CONFIG_SERIAL_ZS) += zs.o
 obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o
index d3553b5d3fcabd851d6cce4b6eab6eb6bca80cbc..92b1ac8db63d8e566573cfc87dc96248dae5bc52 100644 (file)
@@ -1215,14 +1215,14 @@ static irqreturn_t pl011_int(int irq, void *dev_id)
        return IRQ_RETVAL(handled);
 }
 
-static unsigned int pl01x_tx_empty(struct uart_port *port)
+static unsigned int pl011_tx_empty(struct uart_port *port)
 {
        struct uart_amba_port *uap = (struct uart_amba_port *)port;
        unsigned int status = readw(uap->port.membase + UART01x_FR);
        return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT;
 }
 
-static unsigned int pl01x_get_mctrl(struct uart_port *port)
+static unsigned int pl011_get_mctrl(struct uart_port *port)
 {
        struct uart_amba_port *uap = (struct uart_amba_port *)port;
        unsigned int result = 0;
@@ -1285,7 +1285,7 @@ static void pl011_break_ctl(struct uart_port *port, int break_state)
 }
 
 #ifdef CONFIG_CONSOLE_POLL
-static int pl010_get_poll_char(struct uart_port *port)
+static int pl011_get_poll_char(struct uart_port *port)
 {
        struct uart_amba_port *uap = (struct uart_amba_port *)port;
        unsigned int status;
@@ -1297,7 +1297,7 @@ static int pl010_get_poll_char(struct uart_port *port)
        return readw(uap->port.membase + UART01x_DR);
 }
 
-static void pl010_put_poll_char(struct uart_port *port,
+static void pl011_put_poll_char(struct uart_port *port,
                         unsigned char ch)
 {
        struct uart_amba_port *uap = (struct uart_amba_port *)port;
@@ -1637,7 +1637,7 @@ static const char *pl011_type(struct uart_port *port)
 /*
  * Release the memory region(s) being used by 'port'
  */
-static void pl010_release_port(struct uart_port *port)
+static void pl011_release_port(struct uart_port *port)
 {
        release_mem_region(port->mapbase, SZ_4K);
 }
@@ -1645,7 +1645,7 @@ static void pl010_release_port(struct uart_port *port)
 /*
  * Request the memory region(s) being used by 'port'
  */
-static int pl010_request_port(struct uart_port *port)
+static int pl011_request_port(struct uart_port *port)
 {
        return request_mem_region(port->mapbase, SZ_4K, "uart-pl011")
                        != NULL ? 0 : -EBUSY;
@@ -1654,18 +1654,18 @@ static int pl010_request_port(struct uart_port *port)
 /*
  * Configure/autoconfigure the port.
  */
-static void pl010_config_port(struct uart_port *port, int flags)
+static void pl011_config_port(struct uart_port *port, int flags)
 {
        if (flags & UART_CONFIG_TYPE) {
                port->type = PORT_AMBA;
-               pl010_request_port(port);
+               pl011_request_port(port);
        }
 }
 
 /*
  * verify the new serial_struct (for TIOCSSERIAL).
  */
-static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser)
+static int pl011_verify_port(struct uart_port *port, struct serial_struct *ser)
 {
        int ret = 0;
        if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA)
@@ -1678,9 +1678,9 @@ static int pl010_verify_port(struct uart_port *port, struct serial_struct *ser)
 }
 
 static struct uart_ops amba_pl011_pops = {
-       .tx_empty       = pl01x_tx_empty,
+       .tx_empty       = pl011_tx_empty,
        .set_mctrl      = pl011_set_mctrl,
-       .get_mctrl      = pl01x_get_mctrl,
+       .get_mctrl      = pl011_get_mctrl,
        .stop_tx        = pl011_stop_tx,
        .start_tx       = pl011_start_tx,
        .stop_rx        = pl011_stop_rx,
@@ -1691,13 +1691,13 @@ static struct uart_ops amba_pl011_pops = {
        .flush_buffer   = pl011_dma_flush_buffer,
        .set_termios    = pl011_set_termios,
        .type           = pl011_type,
-       .release_port   = pl010_release_port,
-       .request_port   = pl010_request_port,
-       .config_port    = pl010_config_port,
-       .verify_port    = pl010_verify_port,
+       .release_port   = pl011_release_port,
+       .request_port   = pl011_request_port,
+       .config_port    = pl011_config_port,
+       .verify_port    = pl011_verify_port,
 #ifdef CONFIG_CONSOLE_POLL
-       .poll_get_char = pl010_get_poll_char,
-       .poll_put_char = pl010_put_poll_char,
+       .poll_get_char = pl011_get_poll_char,
+       .poll_put_char = pl011_put_poll_char,
 #endif
 };
 
index bd97db23985bbc4ae6db1b666ff1900f09afb97d..9242d56ba2670d4aebc21749d9003c4d42986a35 100644 (file)
@@ -182,7 +182,7 @@ static void bfin_serial_start_tx(struct uart_port *port)
         * To avoid losting RX interrupt, we reset IR function
         * before sending data.
         */
-       if (tty->termios->c_line == N_IRDA)
+       if (tty->termios.c_line == N_IRDA)
                bfin_serial_reset_irda(port);
 
 #ifdef CONFIG_SERIAL_BFIN_DMA
index 80b6b1b1f7257d3b1da80f1b58523e7465bdb36b..35ee6a2c6877ef45a599351ff5fd74c8c142fe99 100644 (file)
@@ -955,7 +955,7 @@ static const struct control_pins e100_modem_pins[NR_PORTS] =
 /* Calculate the chartime depending on baudrate, numbor of bits etc. */
 static void update_char_time(struct e100_serial * info)
 {
-       tcflag_t cflags = info->port.tty->termios->c_cflag;
+       tcflag_t cflags = info->port.tty->termios.c_cflag;
        int bits;
 
        /* calc. number of bits / data byte */
@@ -1473,7 +1473,7 @@ rs_stop(struct tty_struct *tty)
                xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char,
                                STOP_CHAR(info->port.tty));
                xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, stop);
-               if (tty->termios->c_iflag & IXON ) {
+               if (tty->termios.c_iflag & IXON ) {
                        xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
                }
 
@@ -1496,7 +1496,7 @@ rs_start(struct tty_struct *tty)
                                         info->xmit.tail,SERIAL_XMIT_SIZE)));
                xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(tty));
                xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
-               if (tty->termios->c_iflag & IXON ) {
+               if (tty->termios.c_iflag & IXON ) {
                        xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
                }
 
@@ -2929,7 +2929,7 @@ shutdown(struct e100_serial * info)
                        descr[i].buf = 0;
                }
 
-       if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) {
+       if (!info->port.tty || (info->port.tty->termios.c_cflag & HUPCL)) {
                /* hang up DTR and RTS if HUPCL is enabled */
                e100_dtr(info, 0);
                e100_rts(info, 0); /* could check CRTSCTS before doing this */
@@ -2953,12 +2953,12 @@ change_speed(struct e100_serial *info)
        unsigned long flags;
        /* first some safety checks */
 
-       if (!info->port.tty || !info->port.tty->termios)
+       if (!info->port.tty)
                return;
        if (!info->ioport)
                return;
 
-       cflag = info->port.tty->termios->c_cflag;
+       cflag = info->port.tty->termios.c_cflag;
 
        /* possibly, the tx/rx should be disabled first to do this safely */
 
@@ -3088,7 +3088,7 @@ change_speed(struct e100_serial *info)
        info->ioport[REG_REC_CTRL] = info->rx_ctrl;
        xoff = IO_FIELD(R_SERIAL0_XOFF, xoff_char, STOP_CHAR(info->port.tty));
        xoff |= IO_STATE(R_SERIAL0_XOFF, tx_stop, enable);
-       if (info->port.tty->termios->c_iflag & IXON ) {
+       if (info->port.tty->termios.c_iflag & IXON ) {
                DFLOW(DEBUG_LOG(info->line, "FLOW XOFF enabled 0x%02X\n",
                                STOP_CHAR(info->port.tty)));
                xoff |= IO_STATE(R_SERIAL0_XOFF, auto_xoff, enable);
@@ -3355,7 +3355,7 @@ rs_throttle(struct tty_struct * tty)
        DFLOW(DEBUG_LOG(info->line,"rs_throttle %lu\n", tty->ldisc.chars_in_buffer(tty)));
 
        /* Do RTS before XOFF since XOFF might take some time */
-       if (tty->termios->c_cflag & CRTSCTS) {
+       if (tty->termios.c_cflag & CRTSCTS) {
                /* Turn off RTS line */
                e100_rts(info, 0);
        }
@@ -3377,7 +3377,7 @@ rs_unthrottle(struct tty_struct * tty)
        DFLOW(DEBUG_LOG(info->line,"rs_unthrottle ldisc %d\n", tty->ldisc.chars_in_buffer(tty)));
        DFLOW(DEBUG_LOG(info->line,"rs_unthrottle flip.count: %i\n", tty->flip.count));
        /* Do RTS before XOFF since XOFF might take some time */
-       if (tty->termios->c_cflag & CRTSCTS) {
+       if (tty->termios.c_cflag & CRTSCTS) {
                /* Assert RTS line  */
                e100_rts(info, 1);
        }
@@ -3748,7 +3748,7 @@ rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
 
        /* Handle turning off CRTSCTS */
        if ((old_termios->c_cflag & CRTSCTS) &&
-           !(tty->termios->c_cflag & CRTSCTS)) {
+           !(tty->termios.c_cflag & CRTSCTS)) {
                tty->hw_stopped = 0;
                rs_start(tty);
        }
@@ -3815,7 +3815,7 @@ rs_close(struct tty_struct *tty, struct file * filp)
         * separate termios for callout and dialin.
         */
        if (info->flags & ASYNC_NORMAL_ACTIVE)
-               info->normal_termios = *tty->termios;
+               info->normal_termios = tty->termios;
        /*
         * Now we wait for the transmit buffer to clear; and we notify
         * the line discipline to only process XON/XOFF characters.
@@ -3976,7 +3976,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
         */
        if (tty_hung_up_p(filp) ||
            (info->flags & ASYNC_CLOSING)) {
-               wait_event_interruptible_tty(info->close_wait,
+               wait_event_interruptible_tty(tty, info->close_wait,
                        !(info->flags & ASYNC_CLOSING));
 #ifdef SERIAL_DO_RESTART
                if (info->flags & ASYNC_HUP_NOTIFY)
@@ -3998,7 +3998,7 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
                return 0;
        }
 
-       if (tty->termios->c_cflag & CLOCAL) {
+       if (tty->termios.c_cflag & CLOCAL) {
                        do_clocal = 1;
        }
 
@@ -4052,9 +4052,9 @@ block_til_ready(struct tty_struct *tty, struct file * filp,
                printk("block_til_ready blocking: ttyS%d, count = %d\n",
                       info->line, info->count);
 #endif
-               tty_unlock();
+               tty_unlock(tty);
                schedule();
-               tty_lock();
+               tty_lock(tty);
        }
        set_current_state(TASK_RUNNING);
        remove_wait_queue(&info->open_wait, &wait);
@@ -4115,7 +4115,7 @@ rs_open(struct tty_struct *tty, struct file * filp)
         */
        if (tty_hung_up_p(filp) ||
            (info->flags & ASYNC_CLOSING)) {
-               wait_event_interruptible_tty(info->close_wait,
+               wait_event_interruptible_tty(tty, info->close_wait,
                        !(info->flags & ASYNC_CLOSING));
 #ifdef SERIAL_DO_RESTART
                return ((info->flags & ASYNC_HUP_NOTIFY) ?
@@ -4219,7 +4219,7 @@ rs_open(struct tty_struct *tty, struct file * filp)
        }
 
        if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
-               *tty->termios = info->normal_termios;
+               tty->termios = info->normal_termios;
                change_speed(info);
        }
 
@@ -4443,14 +4443,12 @@ static int __init rs_init(void)
                B115200 | CS8 | CREAD | HUPCL | CLOCAL; /* is normally B9600 default... */
        driver->init_termios.c_ispeed = 115200;
        driver->init_termios.c_ospeed = 115200;
-       driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
+       driver->flags = TTY_DRIVER_REAL_RAW;
 
        tty_set_operations(driver, &rs_ops);
         serial_driver = driver;
-       if (tty_register_driver(driver))
-               panic("Couldn't register serial driver\n");
-       /* do some initializing for the separate ports */
 
+       /* do some initializing for the separate ports */
        for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) {
                if (info->enabled) {
                        if (cris_request_io_interface(info->io_if,
@@ -4502,7 +4500,12 @@ static int __init rs_init(void)
                        printk(KERN_INFO "%s%d at %p is a builtin UART with DMA\n",
                               serial_driver->name, info->line, info->ioport);
                }
+               tty_port_link_device(&info->port, driver, i);
        }
+
+       if (tty_register_driver(driver))
+               panic("Couldn't register serial driver\n");
+
 #ifdef CONFIG_ETRAX_FAST_TIMER
 #ifdef CONFIG_ETRAX_SERIAL_FAST_TIMER
        memset(fast_timers, 0, sizeof(fast_timers));
index 144cd3987d4cb5c6c108d0488a41a0e1ba8eca73..5b9bc19ed134b2a4d50eb793b5d88717871df3a5 100644 (file)
@@ -800,8 +800,8 @@ static int ifx_spi_create_port(struct ifx_spi_device *ifx_dev)
        tty_port_init(pport);
        pport->ops = &ifx_tty_port_ops;
        ifx_dev->minor = IFX_SPI_TTY_ID;
-       ifx_dev->tty_dev = tty_register_device(tty_drv, ifx_dev->minor,
-                                              &ifx_dev->spi_dev->dev);
+       ifx_dev->tty_dev = tty_port_register_device(pport, tty_drv,
+                       ifx_dev->minor, &ifx_dev->spi_dev->dev);
        if (IS_ERR(ifx_dev->tty_dev)) {
                dev_dbg(&ifx_dev->spi_dev->dev,
                        "%s: registering tty device failed", __func__);
@@ -1331,7 +1331,7 @@ static const struct spi_device_id ifx_id_table[] = {
 MODULE_DEVICE_TABLE(spi, ifx_id_table);
 
 /* spi operations */
-static const struct spi_driver ifx_spi_driver = {
+static struct spi_driver ifx_spi_driver = {
        .driver = {
                .name = DRVNAME,
                .pm = &ifx_spi_pm,
index d5c689d6217e3a2eb46223fa1ffd01b77e15e0df..20e911724027a1db5da67423235f1961f76c0077 100644 (file)
@@ -206,7 +206,7 @@ struct imx_port {
        unsigned short          trcv_delay; /* transceiver delay */
        struct clk              *clk_ipg;
        struct clk              *clk_per;
-       struct imx_uart_data    *devdata;
+       const struct imx_uart_data *devdata;
 };
 
 struct imx_port_ucrs {
index e16894fb2ca3532067bbfe90cffa321ca64d869b..cc5aca78ad9b6344001ec97155a829ddba7a855d 100644 (file)
@@ -1803,7 +1803,7 @@ static inline int ic4_startup_local(struct uart_port *the_port)
        ioc4_set_proto(port, the_port->mapbase);
 
        /* set the speed of the serial port */
-       ioc4_change_speed(the_port, state->port.tty->termios,
+       ioc4_change_speed(the_port, &state->port.tty->termios,
                          (struct ktermios *)0);
 
        return 0;
index 434bd881fcae84dd26386502c4817eaf87dd2c21..71397961773c232413600dd68a69ea7e43d72ec6 100644 (file)
@@ -161,7 +161,7 @@ static void jsm_tty_send_xchar(struct uart_port *port, char ch)
        struct ktermios *termios;
 
        spin_lock_irqsave(&port->lock, lock_flags);
-       termios = port->state->port.tty->termios;
+       termios = &port->state->port.tty->termios;
        if (ch == termios->c_cc[VSTART])
                channel->ch_bd->bd_ops->send_start_character(channel);
 
@@ -250,7 +250,7 @@ static int jsm_tty_open(struct uart_port *port)
        channel->ch_cached_lsr = 0;
        channel->ch_stops_sent = 0;
 
-       termios = port->state->port.tty->termios;
+       termios = &port->state->port.tty->termios;
        channel->ch_c_cflag     = termios->c_cflag;
        channel->ch_c_iflag     = termios->c_iflag;
        channel->ch_c_oflag     = termios->c_oflag;
@@ -283,7 +283,7 @@ static void jsm_tty_close(struct uart_port *port)
        jsm_printk(CLOSE, INFO, &channel->ch_bd->pci_dev, "start\n");
 
        bd = channel->ch_bd;
-       ts = port->state->port.tty->termios;
+       ts = &port->state->port.tty->termios;
 
        channel->ch_flags &= ~(CH_STOPI);
 
@@ -567,7 +567,7 @@ void jsm_input(struct jsm_channel *ch)
         *input data and return immediately.
         */
        if (!tp ||
-               !(tp->termios->c_cflag & CREAD) ) {
+               !(tp->termios.c_cflag & CREAD) ) {
 
                jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
                        "input. dropping %d bytes on port %d...\n", data_len, ch->ch_portnum);
index 2b42a01a81c6984ace5d8b343d6920c4a0ed748a..509e71456d139a5a7b750c89bb0402d42943ac10 100644 (file)
@@ -97,7 +97,8 @@ static void kgdboc_restore_input(void)
 
 static int kgdboc_register_kbd(char **cptr)
 {
-       if (strncmp(*cptr, "kbd", 3) == 0) {
+       if (strncmp(*cptr, "kbd", 3) == 0 ||
+               strncmp(*cptr, "kdb", 3) == 0) {
                if (kdb_poll_idx < KDB_POLL_FUNC_MAX) {
                        kdb_poll_funcs[kdb_poll_idx] = kdb_get_kbd_char;
                        kdb_poll_idx++;
diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c
new file mode 100644 (file)
index 0000000..ba3af3b
--- /dev/null
@@ -0,0 +1,823 @@
+/*
+ * High Speed Serial Ports on NXP LPC32xx SoC
+ *
+ * Authors: Kevin Wells <kevin.wells@nxp.com>
+ *          Roland Stigge <stigge@antcom.de>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ * Copyright (C) 2012 Roland Stigge
+ *
+ * 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/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/nmi.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <mach/platform.h>
+#include <mach/hardware.h>
+
+/*
+ * High Speed UART register offsets
+ */
+#define LPC32XX_HSUART_FIFO(x)                 ((x) + 0x00)
+#define LPC32XX_HSUART_LEVEL(x)                        ((x) + 0x04)
+#define LPC32XX_HSUART_IIR(x)                  ((x) + 0x08)
+#define LPC32XX_HSUART_CTRL(x)                 ((x) + 0x0C)
+#define LPC32XX_HSUART_RATE(x)                 ((x) + 0x10)
+
+#define LPC32XX_HSU_BREAK_DATA                 (1 << 10)
+#define LPC32XX_HSU_ERROR_DATA                 (1 << 9)
+#define LPC32XX_HSU_RX_EMPTY                   (1 << 8)
+
+#define LPC32XX_HSU_TX_LEV(n)                  (((n) >> 8) & 0xFF)
+#define LPC32XX_HSU_RX_LEV(n)                  ((n) & 0xFF)
+
+#define LPC32XX_HSU_TX_INT_SET                 (1 << 6)
+#define LPC32XX_HSU_RX_OE_INT                  (1 << 5)
+#define LPC32XX_HSU_BRK_INT                    (1 << 4)
+#define LPC32XX_HSU_FE_INT                     (1 << 3)
+#define LPC32XX_HSU_RX_TIMEOUT_INT             (1 << 2)
+#define LPC32XX_HSU_RX_TRIG_INT                        (1 << 1)
+#define LPC32XX_HSU_TX_INT                     (1 << 0)
+
+#define LPC32XX_HSU_HRTS_INV                   (1 << 21)
+#define LPC32XX_HSU_HRTS_TRIG_8B               (0x0 << 19)
+#define LPC32XX_HSU_HRTS_TRIG_16B              (0x1 << 19)
+#define LPC32XX_HSU_HRTS_TRIG_32B              (0x2 << 19)
+#define LPC32XX_HSU_HRTS_TRIG_48B              (0x3 << 19)
+#define LPC32XX_HSU_HRTS_EN                    (1 << 18)
+#define LPC32XX_HSU_TMO_DISABLED               (0x0 << 16)
+#define LPC32XX_HSU_TMO_INACT_4B               (0x1 << 16)
+#define LPC32XX_HSU_TMO_INACT_8B               (0x2 << 16)
+#define LPC32XX_HSU_TMO_INACT_16B              (0x3 << 16)
+#define LPC32XX_HSU_HCTS_INV                   (1 << 15)
+#define LPC32XX_HSU_HCTS_EN                    (1 << 14)
+#define LPC32XX_HSU_OFFSET(n)                  ((n) << 9)
+#define LPC32XX_HSU_BREAK                      (1 << 8)
+#define LPC32XX_HSU_ERR_INT_EN                 (1 << 7)
+#define LPC32XX_HSU_RX_INT_EN                  (1 << 6)
+#define LPC32XX_HSU_TX_INT_EN                  (1 << 5)
+#define LPC32XX_HSU_RX_TL1B                    (0x0 << 2)
+#define LPC32XX_HSU_RX_TL4B                    (0x1 << 2)
+#define LPC32XX_HSU_RX_TL8B                    (0x2 << 2)
+#define LPC32XX_HSU_RX_TL16B                   (0x3 << 2)
+#define LPC32XX_HSU_RX_TL32B                   (0x4 << 2)
+#define LPC32XX_HSU_RX_TL48B                   (0x5 << 2)
+#define LPC32XX_HSU_TX_TLEMPTY                 (0x0 << 0)
+#define LPC32XX_HSU_TX_TL0B                    (0x0 << 0)
+#define LPC32XX_HSU_TX_TL4B                    (0x1 << 0)
+#define LPC32XX_HSU_TX_TL8B                    (0x2 << 0)
+#define LPC32XX_HSU_TX_TL16B                   (0x3 << 0)
+
+#define MODNAME "lpc32xx_hsuart"
+
+struct lpc32xx_hsuart_port {
+       struct uart_port port;
+};
+
+#define FIFO_READ_LIMIT 128
+#define MAX_PORTS 3
+#define LPC32XX_TTY_NAME "ttyTX"
+static struct lpc32xx_hsuart_port lpc32xx_hs_ports[MAX_PORTS];
+
+#ifdef CONFIG_SERIAL_HS_LPC32XX_CONSOLE
+static void wait_for_xmit_empty(struct uart_port *port)
+{
+       unsigned int timeout = 10000;
+
+       do {
+               if (LPC32XX_HSU_TX_LEV(readl(LPC32XX_HSUART_LEVEL(
+                                                       port->membase))) == 0)
+                       break;
+               if (--timeout == 0)
+                       break;
+               udelay(1);
+       } while (1);
+}
+
+static void wait_for_xmit_ready(struct uart_port *port)
+{
+       unsigned int timeout = 10000;
+
+       while (1) {
+               if (LPC32XX_HSU_TX_LEV(readl(LPC32XX_HSUART_LEVEL(
+                                                       port->membase))) < 32)
+                       break;
+               if (--timeout == 0)
+                       break;
+               udelay(1);
+       }
+}
+
+static void lpc32xx_hsuart_console_putchar(struct uart_port *port, int ch)
+{
+       wait_for_xmit_ready(port);
+       writel((u32)ch, LPC32XX_HSUART_FIFO(port->membase));
+}
+
+static void lpc32xx_hsuart_console_write(struct console *co, const char *s,
+                                        unsigned int count)
+{
+       struct lpc32xx_hsuart_port *up = &lpc32xx_hs_ports[co->index];
+       unsigned long flags;
+       int locked = 1;
+
+       touch_nmi_watchdog();
+       local_irq_save(flags);
+       if (up->port.sysrq)
+               locked = 0;
+       else if (oops_in_progress)
+               locked = spin_trylock(&up->port.lock);
+       else
+               spin_lock(&up->port.lock);
+
+       uart_console_write(&up->port, s, count, lpc32xx_hsuart_console_putchar);
+       wait_for_xmit_empty(&up->port);
+
+       if (locked)
+               spin_unlock(&up->port.lock);
+       local_irq_restore(flags);
+}
+
+static int __init lpc32xx_hsuart_console_setup(struct console *co,
+                                              char *options)
+{
+       struct uart_port *port;
+       int baud = 115200;
+       int bits = 8;
+       int parity = 'n';
+       int flow = 'n';
+
+       if (co->index >= MAX_PORTS)
+               co->index = 0;
+
+       port = &lpc32xx_hs_ports[co->index].port;
+       if (!port->membase)
+               return -ENODEV;
+
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+       return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver lpc32xx_hsuart_reg;
+static struct console lpc32xx_hsuart_console = {
+       .name           = LPC32XX_TTY_NAME,
+       .write          = lpc32xx_hsuart_console_write,
+       .device         = uart_console_device,
+       .setup          = lpc32xx_hsuart_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+       .data           = &lpc32xx_hsuart_reg,
+};
+
+static int __init lpc32xx_hsuart_console_init(void)
+{
+       register_console(&lpc32xx_hsuart_console);
+       return 0;
+}
+console_initcall(lpc32xx_hsuart_console_init);
+
+#define LPC32XX_HSUART_CONSOLE (&lpc32xx_hsuart_console)
+#else
+#define LPC32XX_HSUART_CONSOLE NULL
+#endif
+
+static struct uart_driver lpc32xx_hs_reg = {
+       .owner          = THIS_MODULE,
+       .driver_name    = MODNAME,
+       .dev_name       = LPC32XX_TTY_NAME,
+       .nr             = MAX_PORTS,
+       .cons           = LPC32XX_HSUART_CONSOLE,
+};
+static int uarts_registered;
+
+static unsigned int __serial_get_clock_div(unsigned long uartclk,
+                                          unsigned long rate)
+{
+       u32 div, goodrate, hsu_rate, l_hsu_rate, comprate;
+       u32 rate_diff;
+
+       /* Find the closest divider to get the desired clock rate */
+       div = uartclk / rate;
+       goodrate = hsu_rate = (div / 14) - 1;
+       if (hsu_rate != 0)
+               hsu_rate--;
+
+       /* Tweak divider */
+       l_hsu_rate = hsu_rate + 3;
+       rate_diff = 0xFFFFFFFF;
+
+       while (hsu_rate < l_hsu_rate) {
+               comprate = uartclk / ((hsu_rate + 1) * 14);
+               if (abs(comprate - rate) < rate_diff) {
+                       goodrate = hsu_rate;
+                       rate_diff = abs(comprate - rate);
+               }
+
+               hsu_rate++;
+       }
+       if (hsu_rate > 0xFF)
+               hsu_rate = 0xFF;
+
+       return goodrate;
+}
+
+static void __serial_uart_flush(struct uart_port *port)
+{
+       u32 tmp;
+       int cnt = 0;
+
+       while ((readl(LPC32XX_HSUART_LEVEL(port->membase)) > 0) &&
+              (cnt++ < FIFO_READ_LIMIT))
+               tmp = readl(LPC32XX_HSUART_FIFO(port->membase));
+}
+
+static void __serial_lpc32xx_rx(struct uart_port *port)
+{
+       unsigned int tmp, flag;
+       struct tty_struct *tty = tty_port_tty_get(&port->state->port);
+
+       if (!tty) {
+               /* Discard data: no tty available */
+               while (!(readl(LPC32XX_HSUART_FIFO(port->membase)) &
+                        LPC32XX_HSU_RX_EMPTY))
+                       ;
+
+               return;
+       }
+
+       /* Read data from FIFO and push into terminal */
+       tmp = readl(LPC32XX_HSUART_FIFO(port->membase));
+       while (!(tmp & LPC32XX_HSU_RX_EMPTY)) {
+               flag = TTY_NORMAL;
+               port->icount.rx++;
+
+               if (tmp & LPC32XX_HSU_ERROR_DATA) {
+                       /* Framing error */
+                       writel(LPC32XX_HSU_FE_INT,
+                              LPC32XX_HSUART_IIR(port->membase));
+                       port->icount.frame++;
+                       flag = TTY_FRAME;
+                       tty_insert_flip_char(tty, 0, TTY_FRAME);
+               }
+
+               tty_insert_flip_char(tty, (tmp & 0xFF), flag);
+
+               tmp = readl(LPC32XX_HSUART_FIFO(port->membase));
+       }
+       tty_flip_buffer_push(tty);
+       tty_kref_put(tty);
+}
+
+static void __serial_lpc32xx_tx(struct uart_port *port)
+{
+       struct circ_buf *xmit = &port->state->xmit;
+       unsigned int tmp;
+
+       if (port->x_char) {
+               writel((u32)port->x_char, LPC32XX_HSUART_FIFO(port->membase));
+               port->icount.tx++;
+               port->x_char = 0;
+               return;
+       }
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+               goto exit_tx;
+
+       /* Transfer data */
+       while (LPC32XX_HSU_TX_LEV(readl(
+               LPC32XX_HSUART_LEVEL(port->membase))) < 64) {
+               writel((u32) xmit->buf[xmit->tail],
+                      LPC32XX_HSUART_FIFO(port->membase));
+               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               port->icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+
+exit_tx:
+       if (uart_circ_empty(xmit)) {
+               tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
+               tmp &= ~LPC32XX_HSU_TX_INT_EN;
+               writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+       }
+}
+
+static irqreturn_t serial_lpc32xx_interrupt(int irq, void *dev_id)
+{
+       struct uart_port *port = dev_id;
+       struct tty_struct *tty = tty_port_tty_get(&port->state->port);
+       u32 status;
+
+       spin_lock(&port->lock);
+
+       /* Read UART status and clear latched interrupts */
+       status = readl(LPC32XX_HSUART_IIR(port->membase));
+
+       if (status & LPC32XX_HSU_BRK_INT) {
+               /* Break received */
+               writel(LPC32XX_HSU_BRK_INT, LPC32XX_HSUART_IIR(port->membase));
+               port->icount.brk++;
+               uart_handle_break(port);
+       }
+
+       /* Framing error */
+       if (status & LPC32XX_HSU_FE_INT)
+               writel(LPC32XX_HSU_FE_INT, LPC32XX_HSUART_IIR(port->membase));
+
+       if (status & LPC32XX_HSU_RX_OE_INT) {
+               /* Receive FIFO overrun */
+               writel(LPC32XX_HSU_RX_OE_INT,
+                      LPC32XX_HSUART_IIR(port->membase));
+               port->icount.overrun++;
+               if (tty) {
+                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+                       tty_schedule_flip(tty);
+               }
+       }
+
+       /* Data received? */
+       if (status & (LPC32XX_HSU_RX_TIMEOUT_INT | LPC32XX_HSU_RX_TRIG_INT)) {
+               __serial_lpc32xx_rx(port);
+               if (tty)
+                       tty_flip_buffer_push(tty);
+       }
+
+       /* Transmit data request? */
+       if ((status & LPC32XX_HSU_TX_INT) && (!uart_tx_stopped(port))) {
+               writel(LPC32XX_HSU_TX_INT, LPC32XX_HSUART_IIR(port->membase));
+               __serial_lpc32xx_tx(port);
+       }
+
+       spin_unlock(&port->lock);
+       tty_kref_put(tty);
+
+       return IRQ_HANDLED;
+}
+
+/* port->lock is not held.  */
+static unsigned int serial_lpc32xx_tx_empty(struct uart_port *port)
+{
+       unsigned int ret = 0;
+
+       if (LPC32XX_HSU_TX_LEV(readl(LPC32XX_HSUART_LEVEL(port->membase))) == 0)
+               ret = TIOCSER_TEMT;
+
+       return ret;
+}
+
+/* port->lock held by caller.  */
+static void serial_lpc32xx_set_mctrl(struct uart_port *port,
+                                    unsigned int mctrl)
+{
+       /* No signals are supported on HS UARTs */
+}
+
+/* port->lock is held by caller and interrupts are disabled.  */
+static unsigned int serial_lpc32xx_get_mctrl(struct uart_port *port)
+{
+       /* No signals are supported on HS UARTs */
+       return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+}
+
+/* port->lock held by caller.  */
+static void serial_lpc32xx_stop_tx(struct uart_port *port)
+{
+       u32 tmp;
+
+       tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
+       tmp &= ~LPC32XX_HSU_TX_INT_EN;
+       writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+}
+
+/* port->lock held by caller.  */
+static void serial_lpc32xx_start_tx(struct uart_port *port)
+{
+       u32 tmp;
+
+       __serial_lpc32xx_tx(port);
+       tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
+       tmp |= LPC32XX_HSU_TX_INT_EN;
+       writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+}
+
+/* port->lock held by caller.  */
+static void serial_lpc32xx_stop_rx(struct uart_port *port)
+{
+       u32 tmp;
+
+       tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
+       tmp &= ~(LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN);
+       writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+
+       writel((LPC32XX_HSU_BRK_INT | LPC32XX_HSU_RX_OE_INT |
+               LPC32XX_HSU_FE_INT), LPC32XX_HSUART_IIR(port->membase));
+}
+
+/* port->lock held by caller.  */
+static void serial_lpc32xx_enable_ms(struct uart_port *port)
+{
+       /* Modem status is not supported */
+}
+
+/* port->lock is not held.  */
+static void serial_lpc32xx_break_ctl(struct uart_port *port,
+                                    int break_state)
+{
+       unsigned long flags;
+       u32 tmp;
+
+       spin_lock_irqsave(&port->lock, flags);
+       tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
+       if (break_state != 0)
+               tmp |= LPC32XX_HSU_BREAK;
+       else
+               tmp &= ~LPC32XX_HSU_BREAK;
+       writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+       spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/* LPC3250 Errata HSUART.1: Hang workaround via loopback mode on inactivity */
+static void lpc32xx_loopback_set(resource_size_t mapbase, int state)
+{
+       int bit;
+       u32 tmp;
+
+       switch (mapbase) {
+       case LPC32XX_HS_UART1_BASE:
+               bit = 0;
+               break;
+       case LPC32XX_HS_UART2_BASE:
+               bit = 1;
+               break;
+       case LPC32XX_HS_UART7_BASE:
+               bit = 6;
+               break;
+       default:
+               WARN(1, "lpc32xx_hs: Warning: Unknown port at %08x\n", mapbase);
+               return;
+       }
+
+       tmp = readl(LPC32XX_UARTCTL_CLOOP);
+       if (state)
+               tmp |= (1 << bit);
+       else
+               tmp &= ~(1 << bit);
+       writel(tmp, LPC32XX_UARTCTL_CLOOP);
+}
+
+/* port->lock is not held.  */
+static int serial_lpc32xx_startup(struct uart_port *port)
+{
+       int retval;
+       unsigned long flags;
+       u32 tmp;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       __serial_uart_flush(port);
+
+       writel((LPC32XX_HSU_TX_INT | LPC32XX_HSU_FE_INT |
+               LPC32XX_HSU_BRK_INT | LPC32XX_HSU_RX_OE_INT),
+              LPC32XX_HSUART_IIR(port->membase));
+
+       writel(0xFF, LPC32XX_HSUART_RATE(port->membase));
+
+       /*
+        * Set receiver timeout, HSU offset of 20, no break, no interrupts,
+        * and default FIFO trigger levels
+        */
+       tmp = LPC32XX_HSU_TX_TL8B | LPC32XX_HSU_RX_TL32B |
+               LPC32XX_HSU_OFFSET(20) | LPC32XX_HSU_TMO_INACT_4B;
+       writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+
+       lpc32xx_loopback_set(port->mapbase, 0); /* get out of loopback mode */
+
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       retval = request_irq(port->irq, serial_lpc32xx_interrupt,
+                            0, MODNAME, port);
+       if (!retval)
+               writel((tmp | LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN),
+                      LPC32XX_HSUART_CTRL(port->membase));
+
+       return retval;
+}
+
+/* port->lock is not held.  */
+static void serial_lpc32xx_shutdown(struct uart_port *port)
+{
+       u32 tmp;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       tmp = LPC32XX_HSU_TX_TL8B | LPC32XX_HSU_RX_TL32B |
+               LPC32XX_HSU_OFFSET(20) | LPC32XX_HSU_TMO_INACT_4B;
+       writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+
+       lpc32xx_loopback_set(port->mapbase, 1); /* go to loopback mode */
+
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       free_irq(port->irq, port);
+}
+
+/* port->lock is not held.  */
+static void serial_lpc32xx_set_termios(struct uart_port *port,
+                                      struct ktermios *termios,
+                                      struct ktermios *old)
+{
+       unsigned long flags;
+       unsigned int baud, quot;
+       u32 tmp;
+
+       /* Always 8-bit, no parity, 1 stop bit */
+       termios->c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD);
+       termios->c_cflag |= CS8;
+
+       termios->c_cflag &= ~(HUPCL | CMSPAR | CLOCAL | CRTSCTS);
+
+       baud = uart_get_baud_rate(port, termios, old, 0,
+                                 port->uartclk / 14);
+
+       quot = __serial_get_clock_div(port->uartclk, baud);
+
+       spin_lock_irqsave(&port->lock, flags);
+
+       /* Ignore characters? */
+       tmp = readl(LPC32XX_HSUART_CTRL(port->membase));
+       if ((termios->c_cflag & CREAD) == 0)
+               tmp &= ~(LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN);
+       else
+               tmp |= LPC32XX_HSU_RX_INT_EN | LPC32XX_HSU_ERR_INT_EN;
+       writel(tmp, LPC32XX_HSUART_CTRL(port->membase));
+
+       writel(quot, LPC32XX_HSUART_RATE(port->membase));
+
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       spin_unlock_irqrestore(&port->lock, flags);
+
+       /* Don't rewrite B0 */
+       if (tty_termios_baud_rate(termios))
+               tty_termios_encode_baud_rate(termios, baud, baud);
+}
+
+static const char *serial_lpc32xx_type(struct uart_port *port)
+{
+       return MODNAME;
+}
+
+static void serial_lpc32xx_release_port(struct uart_port *port)
+{
+       if ((port->iotype == UPIO_MEM32) && (port->mapbase)) {
+               if (port->flags & UPF_IOREMAP) {
+                       iounmap(port->membase);
+                       port->membase = NULL;
+               }
+
+               release_mem_region(port->mapbase, SZ_4K);
+       }
+}
+
+static int serial_lpc32xx_request_port(struct uart_port *port)
+{
+       int ret = -ENODEV;
+
+       if ((port->iotype == UPIO_MEM32) && (port->mapbase)) {
+               ret = 0;
+
+               if (!request_mem_region(port->mapbase, SZ_4K, MODNAME))
+                       ret = -EBUSY;
+               else if (port->flags & UPF_IOREMAP) {
+                       port->membase = ioremap(port->mapbase, SZ_4K);
+                       if (!port->membase) {
+                               release_mem_region(port->mapbase, SZ_4K);
+                               ret = -ENOMEM;
+                       }
+               }
+       }
+
+       return ret;
+}
+
+static void serial_lpc32xx_config_port(struct uart_port *port, int uflags)
+{
+       int ret;
+
+       ret = serial_lpc32xx_request_port(port);
+       if (ret < 0)
+               return;
+       port->type = PORT_UART00;
+       port->fifosize = 64;
+
+       __serial_uart_flush(port);
+
+       writel((LPC32XX_HSU_TX_INT | LPC32XX_HSU_FE_INT |
+               LPC32XX_HSU_BRK_INT | LPC32XX_HSU_RX_OE_INT),
+              LPC32XX_HSUART_IIR(port->membase));
+
+       writel(0xFF, LPC32XX_HSUART_RATE(port->membase));
+
+       /* Set receiver timeout, HSU offset of 20, no break, no interrupts,
+          and default FIFO trigger levels */
+       writel(LPC32XX_HSU_TX_TL8B | LPC32XX_HSU_RX_TL32B |
+              LPC32XX_HSU_OFFSET(20) | LPC32XX_HSU_TMO_INACT_4B,
+              LPC32XX_HSUART_CTRL(port->membase));
+}
+
+static int serial_lpc32xx_verify_port(struct uart_port *port,
+                                     struct serial_struct *ser)
+{
+       int ret = 0;
+
+       if (ser->type != PORT_UART00)
+               ret = -EINVAL;
+
+       return ret;
+}
+
+static struct uart_ops serial_lpc32xx_pops = {
+       .tx_empty       = serial_lpc32xx_tx_empty,
+       .set_mctrl      = serial_lpc32xx_set_mctrl,
+       .get_mctrl      = serial_lpc32xx_get_mctrl,
+       .stop_tx        = serial_lpc32xx_stop_tx,
+       .start_tx       = serial_lpc32xx_start_tx,
+       .stop_rx        = serial_lpc32xx_stop_rx,
+       .enable_ms      = serial_lpc32xx_enable_ms,
+       .break_ctl      = serial_lpc32xx_break_ctl,
+       .startup        = serial_lpc32xx_startup,
+       .shutdown       = serial_lpc32xx_shutdown,
+       .set_termios    = serial_lpc32xx_set_termios,
+       .type           = serial_lpc32xx_type,
+       .release_port   = serial_lpc32xx_release_port,
+       .request_port   = serial_lpc32xx_request_port,
+       .config_port    = serial_lpc32xx_config_port,
+       .verify_port    = serial_lpc32xx_verify_port,
+};
+
+/*
+ * Register a set of serial devices attached to a platform device
+ */
+static int __devinit serial_hs_lpc32xx_probe(struct platform_device *pdev)
+{
+       struct lpc32xx_hsuart_port *p = &lpc32xx_hs_ports[uarts_registered];
+       int ret = 0;
+       struct resource *res;
+
+       if (uarts_registered >= MAX_PORTS) {
+               dev_err(&pdev->dev,
+                       "Error: Number of possible ports exceeded (%d)!\n",
+                       uarts_registered + 1);
+               return -ENXIO;
+       }
+
+       memset(p, 0, sizeof(*p));
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev,
+                       "Error getting mem resource for HS UART port %d\n",
+                       uarts_registered);
+               return -ENXIO;
+       }
+       p->port.mapbase = res->start;
+       p->port.membase = NULL;
+
+       p->port.irq = platform_get_irq(pdev, 0);
+       if (p->port.irq < 0) {
+               dev_err(&pdev->dev, "Error getting irq for HS UART port %d\n",
+                       uarts_registered);
+               return p->port.irq;
+       }
+
+       p->port.iotype = UPIO_MEM32;
+       p->port.uartclk = LPC32XX_MAIN_OSC_FREQ;
+       p->port.regshift = 2;
+       p->port.flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_IOREMAP;
+       p->port.dev = &pdev->dev;
+       p->port.ops = &serial_lpc32xx_pops;
+       p->port.line = uarts_registered++;
+       spin_lock_init(&p->port.lock);
+
+       /* send port to loopback mode by default */
+       lpc32xx_loopback_set(p->port.mapbase, 1);
+
+       ret = uart_add_one_port(&lpc32xx_hs_reg, &p->port);
+
+       platform_set_drvdata(pdev, p);
+
+       return ret;
+}
+
+/*
+ * Remove serial ports registered against a platform device.
+ */
+static int __devexit serial_hs_lpc32xx_remove(struct platform_device *pdev)
+{
+       struct lpc32xx_hsuart_port *p = platform_get_drvdata(pdev);
+
+       uart_remove_one_port(&lpc32xx_hs_reg, &p->port);
+
+       return 0;
+}
+
+
+#ifdef CONFIG_PM
+static int serial_hs_lpc32xx_suspend(struct platform_device *pdev,
+                                    pm_message_t state)
+{
+       struct lpc32xx_hsuart_port *p = platform_get_drvdata(pdev);
+
+       uart_suspend_port(&lpc32xx_hs_reg, &p->port);
+
+       return 0;
+}
+
+static int serial_hs_lpc32xx_resume(struct platform_device *pdev)
+{
+       struct lpc32xx_hsuart_port *p = platform_get_drvdata(pdev);
+
+       uart_resume_port(&lpc32xx_hs_reg, &p->port);
+
+       return 0;
+}
+#else
+#define serial_hs_lpc32xx_suspend      NULL
+#define serial_hs_lpc32xx_resume       NULL
+#endif
+
+static const struct of_device_id serial_hs_lpc32xx_dt_ids[] = {
+       { .compatible = "nxp,lpc3220-hsuart" },
+       { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, serial_hs_lpc32xx_dt_ids);
+
+static struct platform_driver serial_hs_lpc32xx_driver = {
+       .probe          = serial_hs_lpc32xx_probe,
+       .remove         = __devexit_p(serial_hs_lpc32xx_remove),
+       .suspend        = serial_hs_lpc32xx_suspend,
+       .resume         = serial_hs_lpc32xx_resume,
+       .driver         = {
+               .name   = MODNAME,
+               .owner  = THIS_MODULE,
+               .of_match_table = serial_hs_lpc32xx_dt_ids,
+       },
+};
+
+static int __init lpc32xx_hsuart_init(void)
+{
+       int ret;
+
+       ret = uart_register_driver(&lpc32xx_hs_reg);
+       if (ret)
+               return ret;
+
+       ret = platform_driver_register(&serial_hs_lpc32xx_driver);
+       if (ret)
+               uart_unregister_driver(&lpc32xx_hs_reg);
+
+       return ret;
+}
+
+static void __exit lpc32xx_hsuart_exit(void)
+{
+       platform_driver_unregister(&serial_hs_lpc32xx_driver);
+       uart_unregister_driver(&lpc32xx_hs_reg);
+}
+
+module_init(lpc32xx_hsuart_init);
+module_exit(lpc32xx_hsuart_exit);
+
+MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com>");
+MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
+MODULE_DESCRIPTION("NXP LPC32XX High Speed UART driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/max3107.c b/drivers/tty/serial/max3107.c
deleted file mode 100644 (file)
index 17c7ba8..0000000
+++ /dev/null
@@ -1,1215 +0,0 @@
-/*
- *  max3107.c - spi uart protocol driver for Maxim 3107
- *  Based on max3100.c
- *     by Christian Pellegrin <chripell@evolware.org>
- *  and        max3110.c
- *     by Feng Tang <feng.tang@intel.com>
- *
- *  Copyright (C) Aavamobile 2009
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  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/delay.h>
-#include <linux/device.h>
-#include <linux/serial_core.h>
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/gpio.h>
-#include <linux/spi/spi.h>
-#include <linux/freezer.h>
-#include <linux/module.h>
-#include "max3107.h"
-
-static const struct baud_table brg26_ext[] = {
-       { 300,    MAX3107_BRG26_B300 },
-       { 600,    MAX3107_BRG26_B600 },
-       { 1200,   MAX3107_BRG26_B1200 },
-       { 2400,   MAX3107_BRG26_B2400 },
-       { 4800,   MAX3107_BRG26_B4800 },
-       { 9600,   MAX3107_BRG26_B9600 },
-       { 19200,  MAX3107_BRG26_B19200 },
-       { 57600,  MAX3107_BRG26_B57600 },
-       { 115200, MAX3107_BRG26_B115200 },
-       { 230400, MAX3107_BRG26_B230400 },
-       { 460800, MAX3107_BRG26_B460800 },
-       { 921600, MAX3107_BRG26_B921600 },
-       { 0, 0 }
-};
-
-static const struct baud_table brg13_int[] = {
-       { 300,    MAX3107_BRG13_IB300 },
-       { 600,    MAX3107_BRG13_IB600 },
-       { 1200,   MAX3107_BRG13_IB1200 },
-       { 2400,   MAX3107_BRG13_IB2400 },
-       { 4800,   MAX3107_BRG13_IB4800 },
-       { 9600,   MAX3107_BRG13_IB9600 },
-       { 19200,  MAX3107_BRG13_IB19200 },
-       { 57600,  MAX3107_BRG13_IB57600 },
-       { 115200, MAX3107_BRG13_IB115200 },
-       { 230400, MAX3107_BRG13_IB230400 },
-       { 460800, MAX3107_BRG13_IB460800 },
-       { 921600, MAX3107_BRG13_IB921600 },
-       { 0, 0 }
-};
-
-static u32 get_new_brg(int baud, struct max3107_port *s)
-{
-       int i;
-       const struct baud_table *baud_tbl = s->baud_tbl;
-
-       for (i = 0; i < 13; i++) {
-               if (baud == baud_tbl[i].baud)
-                       return baud_tbl[i].new_brg;
-       }
-
-       return 0;
-}
-
-/* Perform SPI transfer for write/read of device register(s) */
-int max3107_rw(struct max3107_port *s, u8 *tx, u8 *rx, int len)
-{
-       struct spi_message spi_msg;
-       struct spi_transfer spi_xfer;
-
-       /* Initialize SPI ,message */
-       spi_message_init(&spi_msg);
-
-       /* Initialize SPI transfer */
-       memset(&spi_xfer, 0, sizeof spi_xfer);
-       spi_xfer.len = len;
-       spi_xfer.tx_buf = tx;
-       spi_xfer.rx_buf = rx;
-       spi_xfer.speed_hz = MAX3107_SPI_SPEED;
-
-       /* Add SPI transfer to SPI message */
-       spi_message_add_tail(&spi_xfer, &spi_msg);
-
-#ifdef DBG_TRACE_SPI_DATA
-       {
-               int i;
-               pr_info("tx len %d:\n", spi_xfer.len);
-               for (i = 0 ; i < spi_xfer.len && i < 32 ; i++)
-                       pr_info(" %x", ((u8 *)spi_xfer.tx_buf)[i]);
-               pr_info("\n");
-       }
-#endif
-
-       /* Perform synchronous SPI transfer */
-       if (spi_sync(s->spi, &spi_msg)) {
-               dev_err(&s->spi->dev, "spi_sync failure\n");
-               return -EIO;
-       }
-
-#ifdef DBG_TRACE_SPI_DATA
-       if (spi_xfer.rx_buf) {
-               int i;
-               pr_info("rx len %d:\n", spi_xfer.len);
-               for (i = 0 ; i < spi_xfer.len && i < 32 ; i++)
-                       pr_info(" %x", ((u8 *)spi_xfer.rx_buf)[i]);
-               pr_info("\n");
-       }
-#endif
-       return 0;
-}
-EXPORT_SYMBOL_GPL(max3107_rw);
-
-/* Puts received data to circular buffer */
-static void put_data_to_circ_buf(struct max3107_port *s, unsigned char *data,
-                                       int len)
-{
-       struct uart_port *port = &s->port;
-       struct tty_struct *tty;
-
-       if (!port->state)
-               return;
-
-       tty = port->state->port.tty;
-       if (!tty)
-               return;
-
-       /* Insert received data */
-       tty_insert_flip_string(tty, data, len);
-       /* Update RX counter */
-       port->icount.rx += len;
-}
-
-/* Handle data receiving */
-static void max3107_handlerx(struct max3107_port *s, u16 rxlvl)
-{
-       int i;
-       int j;
-       int len;                                /* SPI transfer buffer length */
-       u16 *buf;
-       u8 *valid_str;
-
-       if (!s->rx_enabled)
-               /* RX is disabled */
-               return;
-
-       if (rxlvl == 0) {
-               /* RX fifo is empty */
-               return;
-       } else if (rxlvl >= MAX3107_RX_FIFO_SIZE) {
-               dev_warn(&s->spi->dev, "Possible RX FIFO overrun %d\n", rxlvl);
-               /* Ensure sanity of RX level */
-               rxlvl = MAX3107_RX_FIFO_SIZE;
-       }
-       if ((s->rxbuf == 0) || (s->rxstr == 0)) {
-               dev_warn(&s->spi->dev, "Rx buffer/str isn't ready\n");
-               return;
-       }
-       buf = s->rxbuf;
-       valid_str = s->rxstr;
-       while (rxlvl) {
-               pr_debug("rxlvl %d\n", rxlvl);
-               /* Clear buffer */
-               memset(buf, 0, sizeof(u16) * (MAX3107_RX_FIFO_SIZE + 2));
-               len = 0;
-               if (s->irqen_reg & MAX3107_IRQ_RXFIFO_BIT) {
-                       /* First disable RX FIFO interrupt */
-                       pr_debug("Disabling RX INT\n");
-                       buf[0] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG);
-                       s->irqen_reg &= ~MAX3107_IRQ_RXFIFO_BIT;
-                       buf[0] |= s->irqen_reg;
-                       len++;
-               }
-               /* Just increase the length by amount of words in FIFO since
-                * buffer was zeroed and SPI transfer of 0x0000 means reading
-                * from RX FIFO
-                */
-               len += rxlvl;
-               /* Append RX level query */
-               buf[len] = MAX3107_RXFIFOLVL_REG;
-               len++;
-
-               /* Perform the SPI transfer */
-               if (max3107_rw(s, (u8 *)buf, (u8 *)buf, len * 2)) {
-                       dev_err(&s->spi->dev, "SPI transfer for RX h failed\n");
-                       return;
-               }
-
-               /* Skip RX FIFO interrupt disabling word if it was added */
-               j = ((len - 1) - rxlvl);
-               /* Read received words */
-               for (i = 0; i < rxlvl; i++, j++)
-                       valid_str[i] = (u8)buf[j];
-               put_data_to_circ_buf(s, valid_str, rxlvl);
-               /* Get new RX level */
-               rxlvl = (buf[len - 1] & MAX3107_SPI_RX_DATA_MASK);
-       }
-
-       if (s->rx_enabled) {
-               /* RX still enabled, re-enable RX FIFO interrupt */
-               pr_debug("Enabling RX INT\n");
-               buf[0] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG);
-               s->irqen_reg |= MAX3107_IRQ_RXFIFO_BIT;
-               buf[0] |= s->irqen_reg;
-               if (max3107_rw(s, (u8 *)buf, NULL, 2))
-                       dev_err(&s->spi->dev, "RX FIFO INT enabling failed\n");
-       }
-
-       /* Push the received data to receivers */
-       if (s->port.state->port.tty)
-               tty_flip_buffer_push(s->port.state->port.tty);
-}
-
-
-/* Handle data sending */
-static void max3107_handletx(struct max3107_port *s)
-{
-       struct circ_buf *xmit = &s->port.state->xmit;
-       int i;
-       unsigned long flags;
-       int len;                                /* SPI transfer buffer length */
-       u16 *buf;
-
-       if (!s->tx_fifo_empty)
-               /* Don't send more data before previous data is sent */
-               return;
-
-       if (uart_circ_empty(xmit) || uart_tx_stopped(&s->port))
-               /* No data to send or TX is stopped */
-               return;
-
-       if (!s->txbuf) {
-               dev_warn(&s->spi->dev, "Txbuf isn't ready\n");
-               return;
-       }
-       buf = s->txbuf;
-       /* Get length of data pending in circular buffer */
-       len = uart_circ_chars_pending(xmit);
-       if (len) {
-               /* Limit to size of TX FIFO */
-               if (len > MAX3107_TX_FIFO_SIZE)
-                       len = MAX3107_TX_FIFO_SIZE;
-
-               pr_debug("txlen %d\n", len);
-
-               /* Update TX counter */
-               s->port.icount.tx += len;
-
-               /* TX FIFO will no longer be empty */
-               s->tx_fifo_empty = 0;
-
-               i = 0;
-               if (s->irqen_reg & MAX3107_IRQ_TXEMPTY_BIT) {
-                       /* First disable TX empty interrupt */
-                       pr_debug("Disabling TE INT\n");
-                       buf[i] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG);
-                       s->irqen_reg &= ~MAX3107_IRQ_TXEMPTY_BIT;
-                       buf[i] |= s->irqen_reg;
-                       i++;
-                       len++;
-               }
-               /* Add data to send */
-               spin_lock_irqsave(&s->port.lock, flags);
-               for ( ; i < len ; i++) {
-                       buf[i] = (MAX3107_WRITE_BIT | MAX3107_THR_REG);
-                       buf[i] |= ((u16)xmit->buf[xmit->tail] &
-                                               MAX3107_SPI_TX_DATA_MASK);
-                       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
-               }
-               spin_unlock_irqrestore(&s->port.lock, flags);
-               if (!(s->irqen_reg & MAX3107_IRQ_TXEMPTY_BIT)) {
-                       /* Enable TX empty interrupt */
-                       pr_debug("Enabling TE INT\n");
-                       buf[i] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG);
-                       s->irqen_reg |= MAX3107_IRQ_TXEMPTY_BIT;
-                       buf[i] |= s->irqen_reg;
-                       i++;
-                       len++;
-               }
-               if (!s->tx_enabled) {
-                       /* Enable TX */
-                       pr_debug("Enable TX\n");
-                       buf[i] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG);
-                       spin_lock_irqsave(&s->data_lock, flags);
-                       s->mode1_reg &= ~MAX3107_MODE1_TXDIS_BIT;
-                       buf[i] |= s->mode1_reg;
-                       spin_unlock_irqrestore(&s->data_lock, flags);
-                       s->tx_enabled = 1;
-                       i++;
-                       len++;
-               }
-
-               /* Perform the SPI transfer */
-               if (max3107_rw(s, (u8 *)buf, NULL, len*2)) {
-                       dev_err(&s->spi->dev,
-                               "SPI transfer TX handling failed\n");
-                       return;
-               }
-       }
-
-       /* Indicate wake up if circular buffer is getting low on data */
-       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-               uart_write_wakeup(&s->port);
-
-}
-
-/* Handle interrupts
- * Also reads and returns current RX FIFO level
- */
-static u16 handle_interrupt(struct max3107_port *s)
-{
-       u16 buf[4];     /* Buffer for SPI transfers */
-       u8 irq_status;
-       u16 rx_level;
-       unsigned long flags;
-
-       /* Read IRQ status register */
-       buf[0] = MAX3107_IRQSTS_REG;
-       /* Read status IRQ status register */
-       buf[1] = MAX3107_STS_IRQSTS_REG;
-       /* Read LSR IRQ status register */
-       buf[2] = MAX3107_LSR_IRQSTS_REG;
-       /* Query RX level */
-       buf[3] = MAX3107_RXFIFOLVL_REG;
-
-       if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 8)) {
-               dev_err(&s->spi->dev,
-                       "SPI transfer for INTR handling failed\n");
-               return 0;
-       }
-
-       irq_status = (u8)buf[0];
-       pr_debug("IRQSTS %x\n", irq_status);
-       rx_level = (buf[3] & MAX3107_SPI_RX_DATA_MASK);
-
-       if (irq_status & MAX3107_IRQ_LSR_BIT) {
-               /* LSR interrupt */
-               if (buf[2] & MAX3107_LSR_RXTO_BIT)
-                       /* RX timeout interrupt,
-                        * handled by normal RX handling
-                        */
-                       pr_debug("RX TO INT\n");
-       }
-
-       if (irq_status & MAX3107_IRQ_TXEMPTY_BIT) {
-               /* Tx empty interrupt,
-                * disable TX and set tx_fifo_empty flag
-                */
-               pr_debug("TE INT, disabling TX\n");
-               buf[0] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG);
-               spin_lock_irqsave(&s->data_lock, flags);
-               s->mode1_reg |= MAX3107_MODE1_TXDIS_BIT;
-               buf[0] |= s->mode1_reg;
-               spin_unlock_irqrestore(&s->data_lock, flags);
-               if (max3107_rw(s, (u8 *)buf, NULL, 2))
-                       dev_err(&s->spi->dev, "SPI transfer TX dis failed\n");
-               s->tx_enabled = 0;
-               s->tx_fifo_empty = 1;
-       }
-
-       if (irq_status & MAX3107_IRQ_RXFIFO_BIT)
-               /* RX FIFO interrupt,
-                * handled by normal RX handling
-                */
-               pr_debug("RFIFO INT\n");
-
-       /* Return RX level */
-       return rx_level;
-}
-
-/* Trigger work thread*/
-static void max3107_dowork(struct max3107_port *s)
-{
-       if (!work_pending(&s->work) && !freezing(current) && !s->suspended)
-               queue_work(s->workqueue, &s->work);
-       else
-               dev_warn(&s->spi->dev, "interrup isn't serviced normally!\n");
-}
-
-/* Work thread */
-static void max3107_work(struct work_struct *w)
-{
-       struct max3107_port *s = container_of(w, struct max3107_port, work);
-       u16 rxlvl = 0;
-       int len;        /* SPI transfer buffer length */
-       u16 buf[5];     /* Buffer for SPI transfers */
-       unsigned long flags;
-
-       /* Start by reading current RX FIFO level */
-       buf[0] = MAX3107_RXFIFOLVL_REG;
-       if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) {
-               dev_err(&s->spi->dev, "SPI transfer RX lev failed\n");
-               rxlvl = 0;
-       } else {
-               rxlvl = (buf[0] & MAX3107_SPI_RX_DATA_MASK);
-       }
-
-       do {
-               pr_debug("rxlvl %d\n", rxlvl);
-
-               /* Handle RX */
-               max3107_handlerx(s, rxlvl);
-               rxlvl = 0;
-
-               if (s->handle_irq) {
-                       /* Handle pending interrupts
-                        * We also get new RX FIFO level since new data may
-                        * have been received while pushing received data to
-                        * receivers
-                        */
-                       s->handle_irq = 0;
-                       rxlvl = handle_interrupt(s);
-               }
-
-               /* Handle TX */
-               max3107_handletx(s);
-
-               /* Handle configuration changes */
-               len = 0;
-               spin_lock_irqsave(&s->data_lock, flags);
-               if (s->mode1_commit) {
-                       pr_debug("mode1_commit\n");
-                       buf[len] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG);
-                       buf[len++] |= s->mode1_reg;
-                       s->mode1_commit = 0;
-               }
-               if (s->lcr_commit) {
-                       pr_debug("lcr_commit\n");
-                       buf[len] = (MAX3107_WRITE_BIT | MAX3107_LCR_REG);
-                       buf[len++] |= s->lcr_reg;
-                       s->lcr_commit = 0;
-               }
-               if (s->brg_commit) {
-                       pr_debug("brg_commit\n");
-                       buf[len] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVMSB_REG);
-                       buf[len++] |= ((s->brg_cfg >> 16) &
-                                               MAX3107_SPI_TX_DATA_MASK);
-                       buf[len] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVLSB_REG);
-                       buf[len++] |= ((s->brg_cfg >> 8) &
-                                               MAX3107_SPI_TX_DATA_MASK);
-                       buf[len] = (MAX3107_WRITE_BIT | MAX3107_BRGCFG_REG);
-                       buf[len++] |= ((s->brg_cfg) & 0xff);
-                       s->brg_commit = 0;
-               }
-               spin_unlock_irqrestore(&s->data_lock, flags);
-
-               if (len > 0) {
-                       if (max3107_rw(s, (u8 *)buf, NULL, len * 2))
-                               dev_err(&s->spi->dev,
-                                       "SPI transfer config failed\n");
-               }
-
-               /* Reloop if interrupt handling indicated data in RX FIFO */
-       } while (rxlvl);
-
-}
-
-/* Set sleep mode */
-static void max3107_set_sleep(struct max3107_port *s, int mode)
-{
-       u16 buf[1];     /* Buffer for SPI transfer */
-       unsigned long flags;
-       pr_debug("enter, mode %d\n", mode);
-
-       buf[0] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG);
-       spin_lock_irqsave(&s->data_lock, flags);
-       switch (mode) {
-       case MAX3107_DISABLE_FORCED_SLEEP:
-                       s->mode1_reg &= ~MAX3107_MODE1_FORCESLEEP_BIT;
-                       break;
-       case MAX3107_ENABLE_FORCED_SLEEP:
-                       s->mode1_reg |= MAX3107_MODE1_FORCESLEEP_BIT;
-                       break;
-       case MAX3107_DISABLE_AUTOSLEEP:
-                       s->mode1_reg &= ~MAX3107_MODE1_AUTOSLEEP_BIT;
-                       break;
-       case MAX3107_ENABLE_AUTOSLEEP:
-                       s->mode1_reg |= MAX3107_MODE1_AUTOSLEEP_BIT;
-                       break;
-       default:
-               spin_unlock_irqrestore(&s->data_lock, flags);
-               dev_warn(&s->spi->dev, "invalid sleep mode\n");
-               return;
-       }
-       buf[0] |= s->mode1_reg;
-       spin_unlock_irqrestore(&s->data_lock, flags);
-
-       if (max3107_rw(s, (u8 *)buf, NULL, 2))
-               dev_err(&s->spi->dev, "SPI transfer sleep mode failed\n");
-
-       if (mode == MAX3107_DISABLE_AUTOSLEEP ||
-                       mode == MAX3107_DISABLE_FORCED_SLEEP)
-               msleep(MAX3107_WAKEUP_DELAY);
-}
-
-/* Perform full register initialization */
-static void max3107_register_init(struct max3107_port *s)
-{
-       u16 buf[11];    /* Buffer for SPI transfers */
-
-       /* 1. Configure baud rate, 9600 as default */
-       s->baud = 9600;
-       /* the below is default*/
-       if (s->ext_clk) {
-               s->brg_cfg = MAX3107_BRG26_B9600;
-               s->baud_tbl = (struct baud_table *)brg26_ext;
-       } else {
-               s->brg_cfg = MAX3107_BRG13_IB9600;
-               s->baud_tbl = (struct baud_table *)brg13_int;
-       }
-
-       if (s->pdata->init)
-               s->pdata->init(s);
-
-       buf[0] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVMSB_REG)
-               | ((s->brg_cfg >> 16) & MAX3107_SPI_TX_DATA_MASK);
-       buf[1] = (MAX3107_WRITE_BIT | MAX3107_BRGDIVLSB_REG)
-               | ((s->brg_cfg >> 8) & MAX3107_SPI_TX_DATA_MASK);
-       buf[2] = (MAX3107_WRITE_BIT | MAX3107_BRGCFG_REG)
-               | ((s->brg_cfg) & 0xff);
-
-       /* 2. Configure LCR register, 8N1 mode by default */
-       s->lcr_reg = MAX3107_LCR_WORD_LEN_8;
-       buf[3] = (MAX3107_WRITE_BIT | MAX3107_LCR_REG)
-               | s->lcr_reg;
-
-       /* 3. Configure MODE 1 register */
-       s->mode1_reg = 0;
-       /* Enable IRQ pin */
-       s->mode1_reg |= MAX3107_MODE1_IRQSEL_BIT;
-       /* Disable TX */
-       s->mode1_reg |= MAX3107_MODE1_TXDIS_BIT;
-       s->tx_enabled = 0;
-       /* RX is enabled */
-       s->rx_enabled = 1;
-       buf[4] = (MAX3107_WRITE_BIT | MAX3107_MODE1_REG)
-               | s->mode1_reg;
-
-       /* 4. Configure MODE 2 register */
-       buf[5] = (MAX3107_WRITE_BIT | MAX3107_MODE2_REG);
-       if (s->loopback) {
-               /* Enable loopback */
-               buf[5] |= MAX3107_MODE2_LOOPBACK_BIT;
-       }
-       /* Reset FIFOs */
-       buf[5] |= MAX3107_MODE2_FIFORST_BIT;
-       s->tx_fifo_empty = 1;
-
-       /* 5. Configure FIFO trigger level register */
-       buf[6] = (MAX3107_WRITE_BIT | MAX3107_FIFOTRIGLVL_REG);
-       /* RX FIFO trigger for 16 words, TX FIFO trigger not used */
-       buf[6] |= (MAX3107_FIFOTRIGLVL_RX(16) | MAX3107_FIFOTRIGLVL_TX(0));
-
-       /* 6. Configure flow control levels */
-       buf[7] = (MAX3107_WRITE_BIT | MAX3107_FLOWLVL_REG);
-       /* Flow control halt level 96, resume level 48 */
-       buf[7] |= (MAX3107_FLOWLVL_RES(48) | MAX3107_FLOWLVL_HALT(96));
-
-       /* 7. Configure flow control */
-       buf[8] = (MAX3107_WRITE_BIT | MAX3107_FLOWCTRL_REG);
-       /* Enable auto CTS and auto RTS flow control */
-       buf[8] |= (MAX3107_FLOWCTRL_AUTOCTS_BIT | MAX3107_FLOWCTRL_AUTORTS_BIT);
-
-       /* 8. Configure RX timeout register */
-       buf[9] = (MAX3107_WRITE_BIT | MAX3107_RXTO_REG);
-       /* Timeout after 48 character intervals */
-       buf[9] |= 0x0030;
-
-       /* 9. Configure LSR interrupt enable register */
-       buf[10] = (MAX3107_WRITE_BIT | MAX3107_LSR_IRQEN_REG);
-       /* Enable RX timeout interrupt */
-       buf[10] |= MAX3107_LSR_RXTO_BIT;
-
-       /* Perform SPI transfer */
-       if (max3107_rw(s, (u8 *)buf, NULL, 22))
-               dev_err(&s->spi->dev, "SPI transfer for init failed\n");
-
-       /* 10. Clear IRQ status register by reading it */
-       buf[0] = MAX3107_IRQSTS_REG;
-
-       /* 11. Configure interrupt enable register */
-       /* Enable LSR interrupt */
-       s->irqen_reg = MAX3107_IRQ_LSR_BIT;
-       /* Enable RX FIFO interrupt */
-       s->irqen_reg |= MAX3107_IRQ_RXFIFO_BIT;
-       buf[1] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG)
-               | s->irqen_reg;
-
-       /* 12. Clear FIFO reset that was set in step 6 */
-       buf[2] = (MAX3107_WRITE_BIT | MAX3107_MODE2_REG);
-       if (s->loopback) {
-               /* Keep loopback enabled */
-               buf[2] |= MAX3107_MODE2_LOOPBACK_BIT;
-       }
-
-       /* Perform SPI transfer */
-       if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 6))
-               dev_err(&s->spi->dev, "SPI transfer for init failed\n");
-
-}
-
-/* IRQ handler */
-static irqreturn_t max3107_irq(int irqno, void *dev_id)
-{
-       struct max3107_port *s = dev_id;
-
-       if (irqno != s->spi->irq) {
-               /* Unexpected IRQ */
-               return IRQ_NONE;
-       }
-
-       /* Indicate irq */
-       s->handle_irq = 1;
-
-       /* Trigger work thread */
-       max3107_dowork(s);
-
-       return IRQ_HANDLED;
-}
-
-/* HW suspension function
- *
- * Currently autosleep is used to decrease current consumption, alternative
- * approach would be to set the chip to reset mode if UART is not being
- * used but that would mess the GPIOs
- *
- */
-void max3107_hw_susp(struct max3107_port *s, int suspend)
-{
-       pr_debug("enter, suspend %d\n", suspend);
-
-       if (suspend) {
-               /* Suspend requested,
-                * enable autosleep to decrease current consumption
-                */
-               s->suspended = 1;
-               max3107_set_sleep(s, MAX3107_ENABLE_AUTOSLEEP);
-       } else {
-               /* Resume requested,
-                * disable autosleep
-                */
-               s->suspended = 0;
-               max3107_set_sleep(s, MAX3107_DISABLE_AUTOSLEEP);
-       }
-}
-EXPORT_SYMBOL_GPL(max3107_hw_susp);
-
-/* Modem status IRQ enabling */
-static void max3107_enable_ms(struct uart_port *port)
-{
-       /* Modem status not supported */
-}
-
-/* Data send function */
-static void max3107_start_tx(struct uart_port *port)
-{
-       struct max3107_port *s = container_of(port, struct max3107_port, port);
-
-       /* Trigger work thread for sending data */
-       max3107_dowork(s);
-}
-
-/* Function for checking that there is no pending transfers */
-static unsigned int max3107_tx_empty(struct uart_port *port)
-{
-       struct max3107_port *s = container_of(port, struct max3107_port, port);
-
-       pr_debug("returning %d\n",
-                 (s->tx_fifo_empty && uart_circ_empty(&s->port.state->xmit)));
-       return s->tx_fifo_empty && uart_circ_empty(&s->port.state->xmit);
-}
-
-/* Function for stopping RX */
-static void max3107_stop_rx(struct uart_port *port)
-{
-       struct max3107_port *s = container_of(port, struct max3107_port, port);
-       unsigned long flags;
-
-       /* Set RX disabled in MODE 1 register */
-       spin_lock_irqsave(&s->data_lock, flags);
-       s->mode1_reg |= MAX3107_MODE1_RXDIS_BIT;
-       s->mode1_commit = 1;
-       spin_unlock_irqrestore(&s->data_lock, flags);
-       /* Set RX disabled */
-       s->rx_enabled = 0;
-       /* Trigger work thread for doing the actual configuration change */
-       max3107_dowork(s);
-}
-
-/* Function for returning control pin states */
-static unsigned int max3107_get_mctrl(struct uart_port *port)
-{
-       /* DCD and DSR are not wired and CTS/RTS is handled automatically
-        * so just indicate DSR and CAR asserted
-        */
-       return TIOCM_DSR | TIOCM_CAR;
-}
-
-/* Function for setting control pin states */
-static void max3107_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-       /* DCD and DSR are not wired and CTS/RTS is hadnled automatically
-        * so do nothing
-        */
-}
-
-/* Function for configuring UART parameters */
-static void max3107_set_termios(struct uart_port *port,
-                               struct ktermios *termios,
-                               struct ktermios *old)
-{
-       struct max3107_port *s = container_of(port, struct max3107_port, port);
-       struct tty_struct *tty;
-       int baud;
-       u16 new_lcr = 0;
-       u32 new_brg = 0;
-       unsigned long flags;
-
-       if (!port->state)
-               return;
-
-       tty = port->state->port.tty;
-       if (!tty)
-               return;
-
-       /* Get new LCR register values */
-       /* Word size */
-       if ((termios->c_cflag & CSIZE) == CS7)
-               new_lcr |= MAX3107_LCR_WORD_LEN_7;
-       else
-               new_lcr |= MAX3107_LCR_WORD_LEN_8;
-
-       /* Parity */
-       if (termios->c_cflag & PARENB) {
-               new_lcr |= MAX3107_LCR_PARITY_BIT;
-               if (!(termios->c_cflag & PARODD))
-                       new_lcr |= MAX3107_LCR_EVENPARITY_BIT;
-       }
-
-       /* Stop bits */
-       if (termios->c_cflag & CSTOPB) {
-               /* 2 stop bits */
-               new_lcr |= MAX3107_LCR_STOPLEN_BIT;
-       }
-
-       /* Mask termios capabilities we don't support */
-       termios->c_cflag &= ~CMSPAR;
-
-       /* Set status ignore mask */
-       s->port.ignore_status_mask = 0;
-       if (termios->c_iflag & IGNPAR)
-               s->port.ignore_status_mask |= MAX3107_ALL_ERRORS;
-
-       /* Set low latency to immediately handle pushed data */
-       s->port.state->port.tty->low_latency = 1;
-
-       /* Get new baud rate generator configuration */
-       baud = tty_get_baud_rate(tty);
-
-       spin_lock_irqsave(&s->data_lock, flags);
-       new_brg = get_new_brg(baud, s);
-       /* if can't find the corrent config, use previous */
-       if (!new_brg) {
-               baud = s->baud;
-               new_brg = s->brg_cfg;
-       }
-       spin_unlock_irqrestore(&s->data_lock, flags);
-       tty_termios_encode_baud_rate(termios, baud, baud);
-       s->baud = baud;
-
-       /* Update timeout according to new baud rate */
-       uart_update_timeout(port, termios->c_cflag, baud);
-
-       spin_lock_irqsave(&s->data_lock, flags);
-       if (s->lcr_reg != new_lcr) {
-               s->lcr_reg = new_lcr;
-               s->lcr_commit = 1;
-       }
-       if (s->brg_cfg != new_brg) {
-               s->brg_cfg = new_brg;
-               s->brg_commit = 1;
-       }
-       spin_unlock_irqrestore(&s->data_lock, flags);
-
-       /* Trigger work thread for doing the actual configuration change */
-       max3107_dowork(s);
-}
-
-/* Port shutdown function */
-static void max3107_shutdown(struct uart_port *port)
-{
-       struct max3107_port *s = container_of(port, struct max3107_port, port);
-
-       if (s->suspended && s->pdata->hw_suspend)
-               s->pdata->hw_suspend(s, 0);
-
-       /* Free the interrupt */
-       free_irq(s->spi->irq, s);
-
-       if (s->workqueue) {
-               /* Flush and destroy work queue */
-               flush_workqueue(s->workqueue);
-               destroy_workqueue(s->workqueue);
-               s->workqueue = NULL;
-       }
-
-       /* Suspend HW */
-       if (s->pdata->hw_suspend)
-               s->pdata->hw_suspend(s, 1);
-}
-
-/* Port startup function */
-static int max3107_startup(struct uart_port *port)
-{
-       struct max3107_port *s = container_of(port, struct max3107_port, port);
-
-       /* Initialize work queue */
-       s->workqueue = create_freezable_workqueue("max3107");
-       if (!s->workqueue) {
-               dev_err(&s->spi->dev, "Workqueue creation failed\n");
-               return -EBUSY;
-       }
-       INIT_WORK(&s->work, max3107_work);
-
-       /* Setup IRQ */
-       if (request_irq(s->spi->irq, max3107_irq, IRQF_TRIGGER_FALLING,
-                       "max3107", s)) {
-               dev_err(&s->spi->dev, "IRQ reguest failed\n");
-               destroy_workqueue(s->workqueue);
-               s->workqueue = NULL;
-               return -EBUSY;
-       }
-
-       /* Resume HW */
-       if (s->pdata->hw_suspend)
-               s->pdata->hw_suspend(s, 0);
-
-       /* Init registers */
-       max3107_register_init(s);
-
-       return 0;
-}
-
-/* Port type function */
-static const char *max3107_type(struct uart_port *port)
-{
-       struct max3107_port *s = container_of(port, struct max3107_port, port);
-       return s->spi->modalias;
-}
-
-/* Port release function */
-static void max3107_release_port(struct uart_port *port)
-{
-       /* Do nothing */
-}
-
-/* Port request function */
-static int max3107_request_port(struct uart_port *port)
-{
-       /* Do nothing */
-       return 0;
-}
-
-/* Port config function */
-static void max3107_config_port(struct uart_port *port, int flags)
-{
-       struct max3107_port *s = container_of(port, struct max3107_port, port);
-       s->port.type = PORT_MAX3107;
-}
-
-/* Port verify function */
-static int max3107_verify_port(struct uart_port *port,
-                               struct serial_struct *ser)
-{
-       if (ser->type == PORT_UNKNOWN || ser->type == PORT_MAX3107)
-               return 0;
-
-       return -EINVAL;
-}
-
-/* Port stop TX function */
-static void max3107_stop_tx(struct uart_port *port)
-{
-       /* Do nothing */
-}
-
-/* Port break control function */
-static void max3107_break_ctl(struct uart_port *port, int break_state)
-{
-       /* We don't support break control, do nothing */
-}
-
-
-/* Port functions */
-static struct uart_ops max3107_ops = {
-       .tx_empty       = max3107_tx_empty,
-       .set_mctrl      = max3107_set_mctrl,
-       .get_mctrl      = max3107_get_mctrl,
-       .stop_tx        = max3107_stop_tx,
-       .start_tx       = max3107_start_tx,
-       .stop_rx        = max3107_stop_rx,
-       .enable_ms      = max3107_enable_ms,
-       .break_ctl      = max3107_break_ctl,
-       .startup        = max3107_startup,
-       .shutdown       = max3107_shutdown,
-       .set_termios    = max3107_set_termios,
-       .type           = max3107_type,
-       .release_port   = max3107_release_port,
-       .request_port   = max3107_request_port,
-       .config_port    = max3107_config_port,
-       .verify_port    = max3107_verify_port,
-};
-
-/* UART driver data */
-static struct uart_driver max3107_uart_driver = {
-       .owner          = THIS_MODULE,
-       .driver_name    = "ttyMAX",
-       .dev_name       = "ttyMAX",
-       .nr             = 1,
-};
-
-static int driver_registered = 0;
-
-
-
-/* 'Generic' platform data */
-static struct max3107_plat generic_plat_data = {
-       .loopback               = 0,
-       .ext_clk                = 1,
-       .hw_suspend             = max3107_hw_susp,
-       .polled_mode            = 0,
-       .poll_time              = 0,
-};
-
-
-/*******************************************************************/
-
-/**
- *     max3107_probe           -       SPI bus probe entry point
- *     @spi: the spi device
- *
- *     SPI wants us to probe this device and if appropriate claim it.
- *     Perform any platform specific requirements and then initialise
- *     the device.
- */
-
-int max3107_probe(struct spi_device *spi, struct max3107_plat *pdata)
-{
-       struct max3107_port *s;
-       u16 buf[2];     /* Buffer for SPI transfers */
-       int retval;
-
-       pr_info("enter max3107 probe\n");
-
-       /* Allocate port structure */
-       s = kzalloc(sizeof(*s), GFP_KERNEL);
-       if (!s) {
-               pr_err("Allocating port structure failed\n");
-               return -ENOMEM;
-       }
-
-       s->pdata = pdata;
-
-       /* SPI Rx buffer
-        * +2 for RX FIFO interrupt
-        * disabling and RX level query
-        */
-       s->rxbuf = kzalloc(sizeof(u16) * (MAX3107_RX_FIFO_SIZE+2), GFP_KERNEL);
-       if (!s->rxbuf) {
-               pr_err("Allocating RX buffer failed\n");
-               retval = -ENOMEM;
-               goto err_free4;
-       }
-       s->rxstr = kzalloc(sizeof(u8) * MAX3107_RX_FIFO_SIZE, GFP_KERNEL);
-       if (!s->rxstr) {
-               pr_err("Allocating RX buffer failed\n");
-               retval = -ENOMEM;
-               goto err_free3;
-       }
-       /* SPI Tx buffer
-        * SPI transfer buffer
-        * +3 for TX FIFO empty
-        * interrupt disabling and
-        * enabling and TX enabling
-        */
-       s->txbuf = kzalloc(sizeof(u16) * MAX3107_TX_FIFO_SIZE + 3, GFP_KERNEL);
-       if (!s->txbuf) {
-               pr_err("Allocating TX buffer failed\n");
-               retval = -ENOMEM;
-               goto err_free2;
-       }
-       /* Initialize shared data lock */
-       spin_lock_init(&s->data_lock);
-
-       /* SPI intializations */
-       dev_set_drvdata(&spi->dev, s);
-       spi->mode = SPI_MODE_0;
-       spi->dev.platform_data = pdata;
-       spi->bits_per_word = 16;
-       s->ext_clk = pdata->ext_clk;
-       s->loopback = pdata->loopback;
-       spi_setup(spi);
-       s->spi = spi;
-
-       /* Check REV ID to ensure we are talking to what we expect */
-       buf[0] = MAX3107_REVID_REG;
-       if (max3107_rw(s, (u8 *)buf, (u8 *)buf, 2)) {
-               dev_err(&s->spi->dev, "SPI transfer for REVID read failed\n");
-               retval = -EIO;
-               goto err_free1;
-       }
-       if ((buf[0] & MAX3107_SPI_RX_DATA_MASK) != MAX3107_REVID1 &&
-               (buf[0] & MAX3107_SPI_RX_DATA_MASK) != MAX3107_REVID2) {
-               dev_err(&s->spi->dev, "REVID %x does not match\n",
-                               (buf[0] & MAX3107_SPI_RX_DATA_MASK));
-               retval = -ENODEV;
-               goto err_free1;
-       }
-
-       /* Disable all interrupts */
-       buf[0] = (MAX3107_WRITE_BIT | MAX3107_IRQEN_REG | 0x0000);
-       buf[0] |= 0x0000;
-
-       /* Configure clock source */
-       buf[1] = (MAX3107_WRITE_BIT | MAX3107_CLKSRC_REG);
-       if (s->ext_clk) {
-               /* External clock */
-               buf[1] |= MAX3107_CLKSRC_EXTCLK_BIT;
-       }
-
-       /* PLL bypass ON */
-       buf[1] |= MAX3107_CLKSRC_PLLBYP_BIT;
-
-       /* Perform SPI transfer */
-       if (max3107_rw(s, (u8 *)buf, NULL, 4)) {
-               dev_err(&s->spi->dev, "SPI transfer for init failed\n");
-               retval = -EIO;
-               goto err_free1;
-       }
-
-       /* Register UART driver */
-       if (!driver_registered) {
-               retval = uart_register_driver(&max3107_uart_driver);
-               if (retval) {
-                       dev_err(&s->spi->dev, "Registering UART driver failed\n");
-                       goto err_free1;
-               }
-               driver_registered = 1;
-       }
-
-       /* Initialize UART port data */
-       s->port.fifosize = 128;
-       s->port.ops = &max3107_ops;
-       s->port.line = 0;
-       s->port.dev = &spi->dev;
-       s->port.uartclk = 9600;
-       s->port.flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF;
-       s->port.irq = s->spi->irq;
-       s->port.type = PORT_MAX3107;
-
-       /* Add UART port */
-       retval = uart_add_one_port(&max3107_uart_driver, &s->port);
-       if (retval < 0) {
-               dev_err(&s->spi->dev, "Adding UART port failed\n");
-               goto err_free1;
-       }
-
-       if (pdata->configure) {
-               retval = pdata->configure(s);
-               if (retval < 0)
-                       goto err_free1;
-       }
-
-       /* Go to suspend mode */
-       if (pdata->hw_suspend)
-               pdata->hw_suspend(s, 1);
-
-       return 0;
-
-err_free1:
-       kfree(s->txbuf);
-err_free2:
-       kfree(s->rxstr);
-err_free3:
-       kfree(s->rxbuf);
-err_free4:
-       kfree(s);
-       return retval;
-}
-EXPORT_SYMBOL_GPL(max3107_probe);
-
-/* Driver remove function */
-int max3107_remove(struct spi_device *spi)
-{
-       struct max3107_port *s = dev_get_drvdata(&spi->dev);
-
-       pr_info("enter max3107 remove\n");
-
-       /* Remove port */
-       if (uart_remove_one_port(&max3107_uart_driver, &s->port))
-               dev_warn(&s->spi->dev, "Removing UART port failed\n");
-
-
-       /* Free TxRx buffer */
-       kfree(s->rxbuf);
-       kfree(s->rxstr);
-       kfree(s->txbuf);
-
-       /* Free port structure */
-       kfree(s);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(max3107_remove);
-
-/* Driver suspend function */
-int max3107_suspend(struct spi_device *spi, pm_message_t state)
-{
-#ifdef CONFIG_PM
-       struct max3107_port *s = dev_get_drvdata(&spi->dev);
-
-       pr_debug("enter suspend\n");
-
-       /* Suspend UART port */
-       uart_suspend_port(&max3107_uart_driver, &s->port);
-
-       /* Go to suspend mode */
-       if (s->pdata->hw_suspend)
-               s->pdata->hw_suspend(s, 1);
-#endif /* CONFIG_PM */
-       return 0;
-}
-EXPORT_SYMBOL_GPL(max3107_suspend);
-
-/* Driver resume function */
-int max3107_resume(struct spi_device *spi)
-{
-#ifdef CONFIG_PM
-       struct max3107_port *s = dev_get_drvdata(&spi->dev);
-
-       pr_debug("enter resume\n");
-
-       /* Resume from suspend */
-       if (s->pdata->hw_suspend)
-               s->pdata->hw_suspend(s, 0);
-
-       /* Resume UART port */
-       uart_resume_port(&max3107_uart_driver, &s->port);
-#endif /* CONFIG_PM */
-       return 0;
-}
-EXPORT_SYMBOL_GPL(max3107_resume);
-
-static int max3107_probe_generic(struct spi_device *spi)
-{
-       return max3107_probe(spi, &generic_plat_data);
-}
-
-/* Spi driver data */
-static struct spi_driver max3107_driver = {
-       .driver = {
-               .name           = "max3107",
-               .owner          = THIS_MODULE,
-       },
-       .probe          = max3107_probe_generic,
-       .remove         = __devexit_p(max3107_remove),
-       .suspend        = max3107_suspend,
-       .resume         = max3107_resume,
-};
-
-/* Driver init function */
-static int __init max3107_init(void)
-{
-       pr_info("enter max3107 init\n");
-       return spi_register_driver(&max3107_driver);
-}
-
-/* Driver exit function */
-static void __exit max3107_exit(void)
-{
-       pr_info("enter max3107 exit\n");
-       /* Unregister UART driver */
-       if (driver_registered)
-               uart_unregister_driver(&max3107_uart_driver);
-       spi_unregister_driver(&max3107_driver);
-}
-
-module_init(max3107_init);
-module_exit(max3107_exit);
-
-MODULE_DESCRIPTION("MAX3107 driver");
-MODULE_AUTHOR("Aavamobile");
-MODULE_ALIAS("spi:max3107");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/tty/serial/max3107.h b/drivers/tty/serial/max3107.h
deleted file mode 100644 (file)
index 8415fc7..0000000
+++ /dev/null
@@ -1,441 +0,0 @@
-/*
- * max3107.h - spi uart protocol driver header for Maxim 3107
- *
- * Copyright (C) Aavamobile 2009
- * Based on serial_max3100.h by Christian Pellegrin
- *
- * 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 _MAX3107_H
-#define _MAX3107_H
-
-/* Serial error status definitions */
-#define MAX3107_PARITY_ERROR   1
-#define MAX3107_FRAME_ERROR    2
-#define MAX3107_OVERRUN_ERROR  4
-#define MAX3107_ALL_ERRORS     (MAX3107_PARITY_ERROR | \
-                                MAX3107_FRAME_ERROR | \
-                                MAX3107_OVERRUN_ERROR)
-
-/* GPIO definitions */
-#define MAX3107_GPIO_BASE      88
-#define MAX3107_GPIO_COUNT     4
-
-
-/* GPIO connected to chip's reset pin */
-#define MAX3107_RESET_GPIO     87
-
-
-/* Chip reset delay */
-#define MAX3107_RESET_DELAY    10
-
-/* Chip wakeup delay */
-#define MAX3107_WAKEUP_DELAY   50
-
-
-/* Sleep mode definitions */
-#define MAX3107_DISABLE_FORCED_SLEEP   0
-#define MAX3107_ENABLE_FORCED_SLEEP    1
-#define MAX3107_DISABLE_AUTOSLEEP      2
-#define MAX3107_ENABLE_AUTOSLEEP       3
-
-
-/* Definitions for register access with SPI transfers
- *
- * SPI transfer format:
- *
- * Master to slave bits xzzzzzzzyyyyyyyy
- * Slave to master bits aaaaaaaabbbbbbbb
- *
- * where:
- * x = 0 for reads, 1 for writes
- * z = register address
- * y = new register value if write, 0 if read
- * a = unspecified
- * b = register value if read, unspecified if write
- */
-
-/* SPI speed */
-#define MAX3107_SPI_SPEED      (3125000 * 2)
-
-/* Write bit */
-#define MAX3107_WRITE_BIT      (1 << 15)
-
-/* SPI TX data mask */
-#define MAX3107_SPI_RX_DATA_MASK       (0x00ff)
-
-/* SPI RX data mask */
-#define MAX3107_SPI_TX_DATA_MASK       (0x00ff)
-
-/* Register access masks */
-#define MAX3107_RHR_REG                        (0x0000) /* RX FIFO */
-#define MAX3107_THR_REG                        (0x0000) /* TX FIFO */
-#define MAX3107_IRQEN_REG              (0x0100) /* IRQ enable */
-#define MAX3107_IRQSTS_REG             (0x0200) /* IRQ status */
-#define MAX3107_LSR_IRQEN_REG          (0x0300) /* LSR IRQ enable */
-#define MAX3107_LSR_IRQSTS_REG         (0x0400) /* LSR IRQ status */
-#define MAX3107_SPCHR_IRQEN_REG                (0x0500) /* Special char IRQ enable */
-#define MAX3107_SPCHR_IRQSTS_REG       (0x0600) /* Special char IRQ status */
-#define MAX3107_STS_IRQEN_REG          (0x0700) /* Status IRQ enable */
-#define MAX3107_STS_IRQSTS_REG         (0x0800) /* Status IRQ status */
-#define MAX3107_MODE1_REG              (0x0900) /* MODE1 */
-#define MAX3107_MODE2_REG              (0x0a00) /* MODE2 */
-#define MAX3107_LCR_REG                        (0x0b00) /* LCR */
-#define MAX3107_RXTO_REG               (0x0c00) /* RX timeout */
-#define MAX3107_HDPIXDELAY_REG         (0x0d00) /* Auto transceiver delays */
-#define MAX3107_IRDA_REG               (0x0e00) /* IRDA settings */
-#define MAX3107_FLOWLVL_REG            (0x0f00) /* Flow control levels */
-#define MAX3107_FIFOTRIGLVL_REG                (0x1000) /* FIFO IRQ trigger levels */
-#define MAX3107_TXFIFOLVL_REG          (0x1100) /* TX FIFO level */
-#define MAX3107_RXFIFOLVL_REG          (0x1200) /* RX FIFO level */
-#define MAX3107_FLOWCTRL_REG           (0x1300) /* Flow control */
-#define MAX3107_XON1_REG               (0x1400) /* XON1 character */
-#define MAX3107_XON2_REG               (0x1500) /* XON2 character */
-#define MAX3107_XOFF1_REG              (0x1600) /* XOFF1 character */
-#define MAX3107_XOFF2_REG              (0x1700) /* XOFF2 character */
-#define MAX3107_GPIOCFG_REG            (0x1800) /* GPIO config */
-#define MAX3107_GPIODATA_REG           (0x1900) /* GPIO data */
-#define MAX3107_PLLCFG_REG             (0x1a00) /* PLL config */
-#define MAX3107_BRGCFG_REG             (0x1b00) /* Baud rate generator conf */
-#define MAX3107_BRGDIVLSB_REG          (0x1c00) /* Baud rate divisor LSB */
-#define MAX3107_BRGDIVMSB_REG          (0x1d00) /* Baud rate divisor MSB */
-#define MAX3107_CLKSRC_REG             (0x1e00) /* Clock source */
-#define MAX3107_REVID_REG              (0x1f00) /* Revision identification */
-
-/* IRQ register bits */
-#define MAX3107_IRQ_LSR_BIT    (1 << 0) /* LSR interrupt */
-#define MAX3107_IRQ_SPCHR_BIT  (1 << 1) /* Special char interrupt */
-#define MAX3107_IRQ_STS_BIT    (1 << 2) /* Status interrupt */
-#define MAX3107_IRQ_RXFIFO_BIT (1 << 3) /* RX FIFO interrupt */
-#define MAX3107_IRQ_TXFIFO_BIT (1 << 4) /* TX FIFO interrupt */
-#define MAX3107_IRQ_TXEMPTY_BIT        (1 << 5) /* TX FIFO empty interrupt */
-#define MAX3107_IRQ_RXEMPTY_BIT        (1 << 6) /* RX FIFO empty interrupt */
-#define MAX3107_IRQ_CTS_BIT    (1 << 7) /* CTS interrupt */
-
-/* LSR register bits */
-#define MAX3107_LSR_RXTO_BIT   (1 << 0) /* RX timeout */
-#define MAX3107_LSR_RXOVR_BIT  (1 << 1) /* RX overrun */
-#define MAX3107_LSR_RXPAR_BIT  (1 << 2) /* RX parity error */
-#define MAX3107_LSR_FRERR_BIT  (1 << 3) /* Frame error */
-#define MAX3107_LSR_RXBRK_BIT  (1 << 4) /* RX break */
-#define MAX3107_LSR_RXNOISE_BIT        (1 << 5) /* RX noise */
-#define MAX3107_LSR_UNDEF6_BIT (1 << 6) /* Undefined/not used */
-#define MAX3107_LSR_CTS_BIT    (1 << 7) /* CTS pin state */
-
-/* Special character register bits */
-#define MAX3107_SPCHR_XON1_BIT         (1 << 0) /* XON1 character */
-#define MAX3107_SPCHR_XON2_BIT         (1 << 1) /* XON2 character */
-#define MAX3107_SPCHR_XOFF1_BIT                (1 << 2) /* XOFF1 character */
-#define MAX3107_SPCHR_XOFF2_BIT                (1 << 3) /* XOFF2 character */
-#define MAX3107_SPCHR_BREAK_BIT                (1 << 4) /* RX break */
-#define MAX3107_SPCHR_MULTIDROP_BIT    (1 << 5) /* 9-bit multidrop addr char */
-#define MAX3107_SPCHR_UNDEF6_BIT       (1 << 6) /* Undefined/not used */
-#define MAX3107_SPCHR_UNDEF7_BIT       (1 << 7) /* Undefined/not used */
-
-/* Status register bits */
-#define MAX3107_STS_GPIO0_BIT          (1 << 0) /* GPIO 0 interrupt */
-#define MAX3107_STS_GPIO1_BIT          (1 << 1) /* GPIO 1 interrupt */
-#define MAX3107_STS_GPIO2_BIT          (1 << 2) /* GPIO 2 interrupt */
-#define MAX3107_STS_GPIO3_BIT          (1 << 3) /* GPIO 3 interrupt */
-#define MAX3107_STS_UNDEF4_BIT         (1 << 4) /* Undefined/not used */
-#define MAX3107_STS_CLKREADY_BIT       (1 << 5) /* Clock ready */
-#define MAX3107_STS_SLEEP_BIT          (1 << 6) /* Sleep interrupt */
-#define MAX3107_STS_UNDEF7_BIT         (1 << 7) /* Undefined/not used */
-
-/* MODE1 register bits */
-#define MAX3107_MODE1_RXDIS_BIT                (1 << 0) /* RX disable */
-#define MAX3107_MODE1_TXDIS_BIT                (1 << 1) /* TX disable */
-#define MAX3107_MODE1_TXHIZ_BIT                (1 << 2) /* TX pin three-state */
-#define MAX3107_MODE1_RTSHIZ_BIT       (1 << 3) /* RTS pin three-state */
-#define MAX3107_MODE1_TRNSCVCTRL_BIT   (1 << 4) /* Transceiver ctrl enable */
-#define MAX3107_MODE1_FORCESLEEP_BIT   (1 << 5) /* Force sleep mode */
-#define MAX3107_MODE1_AUTOSLEEP_BIT    (1 << 6) /* Auto sleep enable */
-#define MAX3107_MODE1_IRQSEL_BIT       (1 << 7) /* IRQ pin enable */
-
-/* MODE2 register bits */
-#define MAX3107_MODE2_RST_BIT          (1 << 0) /* Chip reset */
-#define MAX3107_MODE2_FIFORST_BIT      (1 << 1) /* FIFO reset */
-#define MAX3107_MODE2_RXTRIGINV_BIT    (1 << 2) /* RX FIFO INT invert */
-#define MAX3107_MODE2_RXEMPTINV_BIT    (1 << 3) /* RX FIFO empty INT invert */
-#define MAX3107_MODE2_SPCHR_BIT                (1 << 4) /* Special chr detect enable */
-#define MAX3107_MODE2_LOOPBACK_BIT     (1 << 5) /* Internal loopback enable */
-#define MAX3107_MODE2_MULTIDROP_BIT    (1 << 6) /* 9-bit multidrop enable */
-#define MAX3107_MODE2_ECHOSUPR_BIT     (1 << 7) /* ECHO suppression enable */
-
-/* LCR register bits */
-#define MAX3107_LCR_LENGTH0_BIT                (1 << 0) /* Word length bit 0 */
-#define MAX3107_LCR_LENGTH1_BIT                (1 << 1) /* Word length bit 1
-                                                 *
-                                                 * Word length bits table:
-                                                 * 00 -> 5 bit words
-                                                 * 01 -> 6 bit words
-                                                 * 10 -> 7 bit words
-                                                 * 11 -> 8 bit words
-                                                 */
-#define MAX3107_LCR_STOPLEN_BIT                (1 << 2) /* STOP length bit
-                                                 *
-                                                 * STOP length bit table:
-                                                 * 0 -> 1 stop bit
-                                                 * 1 -> 1-1.5 stop bits if
-                                                 *      word length is 5,
-                                                 *      2 stop bits otherwise
-                                                 */
-#define MAX3107_LCR_PARITY_BIT         (1 << 3) /* Parity bit enable */
-#define MAX3107_LCR_EVENPARITY_BIT     (1 << 4) /* Even parity bit enable */
-#define MAX3107_LCR_FORCEPARITY_BIT    (1 << 5) /* 9-bit multidrop parity */
-#define MAX3107_LCR_TXBREAK_BIT                (1 << 6) /* TX break enable */
-#define MAX3107_LCR_RTS_BIT            (1 << 7) /* RTS pin control */
-#define MAX3107_LCR_WORD_LEN_5         (0x0000)
-#define MAX3107_LCR_WORD_LEN_6         (0x0001)
-#define MAX3107_LCR_WORD_LEN_7         (0x0002)
-#define MAX3107_LCR_WORD_LEN_8         (0x0003)
-
-
-/* IRDA register bits */
-#define MAX3107_IRDA_IRDAEN_BIT                (1 << 0) /* IRDA mode enable */
-#define MAX3107_IRDA_SIR_BIT           (1 << 1) /* SIR mode enable */
-#define MAX3107_IRDA_SHORTIR_BIT       (1 << 2) /* Short SIR mode enable */
-#define MAX3107_IRDA_MIR_BIT           (1 << 3) /* MIR mode enable */
-#define MAX3107_IRDA_RXINV_BIT         (1 << 4) /* RX logic inversion enable */
-#define MAX3107_IRDA_TXINV_BIT         (1 << 5) /* TX logic inversion enable */
-#define MAX3107_IRDA_UNDEF6_BIT                (1 << 6) /* Undefined/not used */
-#define MAX3107_IRDA_UNDEF7_BIT                (1 << 7) /* Undefined/not used */
-
-/* Flow control trigger level register masks */
-#define MAX3107_FLOWLVL_HALT_MASK      (0x000f) /* Flow control halt level */
-#define MAX3107_FLOWLVL_RES_MASK       (0x00f0) /* Flow control resume level */
-#define MAX3107_FLOWLVL_HALT(words)    ((words/8) & 0x000f)
-#define MAX3107_FLOWLVL_RES(words)     (((words/8) & 0x000f) << 4)
-
-/* FIFO interrupt trigger level register masks */
-#define MAX3107_FIFOTRIGLVL_TX_MASK    (0x000f) /* TX FIFO trigger level */
-#define MAX3107_FIFOTRIGLVL_RX_MASK    (0x00f0) /* RX FIFO trigger level */
-#define MAX3107_FIFOTRIGLVL_TX(words)  ((words/8) & 0x000f)
-#define MAX3107_FIFOTRIGLVL_RX(words)  (((words/8) & 0x000f) << 4)
-
-/* Flow control register bits */
-#define MAX3107_FLOWCTRL_AUTORTS_BIT   (1 << 0) /* Auto RTS flow ctrl enable */
-#define MAX3107_FLOWCTRL_AUTOCTS_BIT   (1 << 1) /* Auto CTS flow ctrl enable */
-#define MAX3107_FLOWCTRL_GPIADDR_BIT   (1 << 2) /* Enables that GPIO inputs
-                                                 * are used in conjunction with
-                                                 * XOFF2 for definition of
-                                                 * special character */
-#define MAX3107_FLOWCTRL_SWFLOWEN_BIT  (1 << 3) /* Auto SW flow ctrl enable */
-#define MAX3107_FLOWCTRL_SWFLOW0_BIT   (1 << 4) /* SWFLOW bit 0 */
-#define MAX3107_FLOWCTRL_SWFLOW1_BIT   (1 << 5) /* SWFLOW bit 1
-                                                 *
-                                                 * SWFLOW bits 1 & 0 table:
-                                                 * 00 -> no transmitter flow
-                                                 *       control
-                                                 * 01 -> receiver compares
-                                                 *       XON2 and XOFF2
-                                                 *       and controls
-                                                 *       transmitter
-                                                 * 10 -> receiver compares
-                                                 *       XON1 and XOFF1
-                                                 *       and controls
-                                                 *       transmitter
-                                                 * 11 -> receiver compares
-                                                 *       XON1, XON2, XOFF1 and
-                                                 *       XOFF2 and controls
-                                                 *       transmitter
-                                                 */
-#define MAX3107_FLOWCTRL_SWFLOW2_BIT   (1 << 6) /* SWFLOW bit 2 */
-#define MAX3107_FLOWCTRL_SWFLOW3_BIT   (1 << 7) /* SWFLOW bit 3
-                                                 *
-                                                 * SWFLOW bits 3 & 2 table:
-                                                 * 00 -> no received flow
-                                                 *       control
-                                                 * 01 -> transmitter generates
-                                                 *       XON2 and XOFF2
-                                                 * 10 -> transmitter generates
-                                                 *       XON1 and XOFF1
-                                                 * 11 -> transmitter generates
-                                                 *       XON1, XON2, XOFF1 and
-                                                 *       XOFF2
-                                                 */
-
-/* GPIO configuration register bits */
-#define MAX3107_GPIOCFG_GP0OUT_BIT     (1 << 0) /* GPIO 0 output enable */
-#define MAX3107_GPIOCFG_GP1OUT_BIT     (1 << 1) /* GPIO 1 output enable */
-#define MAX3107_GPIOCFG_GP2OUT_BIT     (1 << 2) /* GPIO 2 output enable */
-#define MAX3107_GPIOCFG_GP3OUT_BIT     (1 << 3) /* GPIO 3 output enable */
-#define MAX3107_GPIOCFG_GP0OD_BIT      (1 << 4) /* GPIO 0 open-drain enable */
-#define MAX3107_GPIOCFG_GP1OD_BIT      (1 << 5) /* GPIO 1 open-drain enable */
-#define MAX3107_GPIOCFG_GP2OD_BIT      (1 << 6) /* GPIO 2 open-drain enable */
-#define MAX3107_GPIOCFG_GP3OD_BIT      (1 << 7) /* GPIO 3 open-drain enable */
-
-/* GPIO DATA register bits */
-#define MAX3107_GPIODATA_GP0OUT_BIT    (1 << 0) /* GPIO 0 output value */
-#define MAX3107_GPIODATA_GP1OUT_BIT    (1 << 1) /* GPIO 1 output value */
-#define MAX3107_GPIODATA_GP2OUT_BIT    (1 << 2) /* GPIO 2 output value */
-#define MAX3107_GPIODATA_GP3OUT_BIT    (1 << 3) /* GPIO 3 output value */
-#define MAX3107_GPIODATA_GP0IN_BIT     (1 << 4) /* GPIO 0 input value */
-#define MAX3107_GPIODATA_GP1IN_BIT     (1 << 5) /* GPIO 1 input value */
-#define MAX3107_GPIODATA_GP2IN_BIT     (1 << 6) /* GPIO 2 input value */
-#define MAX3107_GPIODATA_GP3IN_BIT     (1 << 7) /* GPIO 3 input value */
-
-/* PLL configuration register masks */
-#define MAX3107_PLLCFG_PREDIV_MASK     (0x003f) /* PLL predivision value */
-#define MAX3107_PLLCFG_PLLFACTOR_MASK  (0x00c0) /* PLL multiplication factor */
-
-/* Baud rate generator configuration register masks and bits */
-#define MAX3107_BRGCFG_FRACT_MASK      (0x000f) /* Fractional portion of
-                                                 * Baud rate generator divisor
-                                                 */
-#define MAX3107_BRGCFG_2XMODE_BIT      (1 << 4) /* Double baud rate */
-#define MAX3107_BRGCFG_4XMODE_BIT      (1 << 5) /* Quadruple baud rate */
-#define MAX3107_BRGCFG_UNDEF6_BIT      (1 << 6) /* Undefined/not used */
-#define MAX3107_BRGCFG_UNDEF7_BIT      (1 << 7) /* Undefined/not used */
-
-/* Clock source register bits */
-#define MAX3107_CLKSRC_INTOSC_BIT      (1 << 0) /* Internal osc enable */
-#define MAX3107_CLKSRC_CRYST_BIT       (1 << 1) /* Crystal osc enable */
-#define MAX3107_CLKSRC_PLL_BIT         (1 << 2) /* PLL enable */
-#define MAX3107_CLKSRC_PLLBYP_BIT      (1 << 3) /* PLL bypass */
-#define MAX3107_CLKSRC_EXTCLK_BIT      (1 << 4) /* External clock enable */
-#define MAX3107_CLKSRC_UNDEF5_BIT      (1 << 5) /* Undefined/not used */
-#define MAX3107_CLKSRC_UNDEF6_BIT      (1 << 6) /* Undefined/not used */
-#define MAX3107_CLKSRC_CLK2RTS_BIT     (1 << 7) /* Baud clk to RTS pin */
-
-
-/* HW definitions */
-#define MAX3107_RX_FIFO_SIZE   128
-#define MAX3107_TX_FIFO_SIZE   128
-#define MAX3107_REVID1         0x00a0
-#define MAX3107_REVID2         0x00a1
-
-
-/* Baud rate generator configuration values for external clock 13MHz */
-#define MAX3107_BRG13_B300     (0x0A9400 | 0x05)
-#define MAX3107_BRG13_B600     (0x054A00 | 0x03)
-#define MAX3107_BRG13_B1200    (0x02A500 | 0x01)
-#define MAX3107_BRG13_B2400    (0x015200 | 0x09)
-#define MAX3107_BRG13_B4800    (0x00A900 | 0x04)
-#define MAX3107_BRG13_B9600    (0x005400 | 0x0A)
-#define MAX3107_BRG13_B19200   (0x002A00 | 0x05)
-#define MAX3107_BRG13_B38400   (0x001500 | 0x03)
-#define MAX3107_BRG13_B57600   (0x000E00 | 0x02)
-#define MAX3107_BRG13_B115200  (0x000700 | 0x01)
-#define MAX3107_BRG13_B230400  (0x000300 | 0x08)
-#define MAX3107_BRG13_B460800  (0x000100 | 0x0c)
-#define MAX3107_BRG13_B921600  (0x000100 | 0x1c)
-
-/* Baud rate generator configuration values for external clock 26MHz */
-#define MAX3107_BRG26_B300     (0x152800 | 0x0A)
-#define MAX3107_BRG26_B600     (0x0A9400 | 0x05)
-#define MAX3107_BRG26_B1200    (0x054A00 | 0x03)
-#define MAX3107_BRG26_B2400    (0x02A500 | 0x01)
-#define MAX3107_BRG26_B4800    (0x015200 | 0x09)
-#define MAX3107_BRG26_B9600    (0x00A900 | 0x04)
-#define MAX3107_BRG26_B19200   (0x005400 | 0x0A)
-#define MAX3107_BRG26_B38400   (0x002A00 | 0x05)
-#define MAX3107_BRG26_B57600   (0x001C00 | 0x03)
-#define MAX3107_BRG26_B115200  (0x000E00 | 0x02)
-#define MAX3107_BRG26_B230400  (0x000700 | 0x01)
-#define MAX3107_BRG26_B460800  (0x000300 | 0x08)
-#define MAX3107_BRG26_B921600  (0x000100 | 0x0C)
-
-/* Baud rate generator configuration values for internal clock */
-#define MAX3107_BRG13_IB300    (0x008000 | 0x00)
-#define MAX3107_BRG13_IB600    (0x004000 | 0x00)
-#define MAX3107_BRG13_IB1200   (0x002000 | 0x00)
-#define MAX3107_BRG13_IB2400   (0x001000 | 0x00)
-#define MAX3107_BRG13_IB4800   (0x000800 | 0x00)
-#define MAX3107_BRG13_IB9600   (0x000400 | 0x00)
-#define MAX3107_BRG13_IB19200  (0x000200 | 0x00)
-#define MAX3107_BRG13_IB38400  (0x000100 | 0x00)
-#define MAX3107_BRG13_IB57600  (0x000000 | 0x0B)
-#define MAX3107_BRG13_IB115200 (0x000000 | 0x05)
-#define MAX3107_BRG13_IB230400 (0x000000 | 0x03)
-#define MAX3107_BRG13_IB460800 (0x000000 | 0x00)
-#define MAX3107_BRG13_IB921600 (0x000000 | 0x00)
-
-
-struct baud_table {
-       int baud;
-       u32 new_brg;
-};
-
-struct max3107_port {
-       /* UART port structure */
-       struct uart_port port;
-
-       /* SPI device structure */
-       struct spi_device *spi;
-
-#if defined(CONFIG_GPIOLIB)
-       /* GPIO chip structure */
-       struct gpio_chip chip;
-#endif
-
-       /* Workqueue that does all the magic */
-       struct workqueue_struct *workqueue;
-       struct work_struct work;
-
-       /* Lock for shared data */
-       spinlock_t data_lock;
-
-       /* Device configuration */
-       int ext_clk;            /* 1 if external clock used */
-       int loopback;           /* Current loopback mode state */
-       int baud;                       /* Current baud rate */
-
-       /* State flags */
-       int suspended;          /* Indicates suspend mode */
-       int tx_fifo_empty;      /* Flag for TX FIFO state */
-       int rx_enabled;         /* Flag for receiver state */
-       int tx_enabled;         /* Flag for transmitter state */
-
-       u16 irqen_reg;          /* Current IRQ enable register value */
-       /* Shared data */
-       u16 mode1_reg;          /* Current mode1 register value*/
-       int mode1_commit;       /* Flag for setting new mode1 register value */
-       u16 lcr_reg;            /* Current LCR register value */
-       int lcr_commit;         /* Flag for setting new LCR register value */
-       u32 brg_cfg;            /* Current Baud rate generator config  */
-       int brg_commit;         /* Flag for setting new baud rate generator
-                                * config
-                                */
-       struct baud_table *baud_tbl;
-       int handle_irq;         /* Indicates that IRQ should be handled */
-
-       /* Rx buffer and str*/
-       u16 *rxbuf;
-       u8  *rxstr;
-       /* Tx buffer*/
-       u16 *txbuf;
-
-       struct max3107_plat *pdata;     /* Platform data */
-};
-
-/* Platform data structure */
-struct max3107_plat {
-       /* Loopback mode enable */
-       int loopback;
-       /* External clock enable */
-       int ext_clk;
-       /* Called during the register initialisation */
-       void (*init)(struct max3107_port *s);
-       /* Called when the port is found and configured */
-       int (*configure)(struct max3107_port *s);
-       /* HW suspend function */
-       void (*hw_suspend) (struct max3107_port *s, int suspend);
-       /* Polling mode enable */
-       int polled_mode;
-       /* Polling period if polling mode enabled */
-       int poll_time;
-};
-
-extern int max3107_rw(struct max3107_port *s, u8 *tx, u8 *rx, int len);
-extern void max3107_hw_susp(struct max3107_port *s, int suspend);
-extern int max3107_probe(struct spi_device *spi, struct max3107_plat *pdata);
-extern int max3107_remove(struct spi_device *spi);
-extern int max3107_suspend(struct spi_device *spi, pm_message_t state);
-extern int max3107_resume(struct spi_device *spi);
-
-#endif /* _LINUX_SERIAL_MAX3107_H */
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
new file mode 100644 (file)
index 0000000..534e448
--- /dev/null
@@ -0,0 +1,1259 @@
+/*
+ *  Maxim (Dallas) MAX3107/8 serial driver
+ *
+ *  Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru>
+ *
+ *  Based on max3100.c, by Christian Pellegrin <chripell@evolware.org>
+ *  Based on max3110.c, by Feng Tang <feng.tang@intel.com>
+ *  Based on max3107.c, by Aavamobile
+ *
+ *  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.
+ */
+
+/* TODO: MAX3109 support (Dual) */
+/* TODO: MAX14830 support (Quad) */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/regmap.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/platform_data/max310x.h>
+
+#define MAX310X_MAJOR                  204
+#define MAX310X_MINOR                  209
+
+/* MAX310X register definitions */
+#define MAX310X_RHR_REG                        (0x00) /* RX FIFO */
+#define MAX310X_THR_REG                        (0x00) /* TX FIFO */
+#define MAX310X_IRQEN_REG              (0x01) /* IRQ enable */
+#define MAX310X_IRQSTS_REG             (0x02) /* IRQ status */
+#define MAX310X_LSR_IRQEN_REG          (0x03) /* LSR IRQ enable */
+#define MAX310X_LSR_IRQSTS_REG         (0x04) /* LSR IRQ status */
+#define MAX310X_SPCHR_IRQEN_REG                (0x05) /* Special char IRQ enable */
+#define MAX310X_SPCHR_IRQSTS_REG       (0x06) /* Special char IRQ status */
+#define MAX310X_STS_IRQEN_REG          (0x07) /* Status IRQ enable */
+#define MAX310X_STS_IRQSTS_REG         (0x08) /* Status IRQ status */
+#define MAX310X_MODE1_REG              (0x09) /* MODE1 */
+#define MAX310X_MODE2_REG              (0x0a) /* MODE2 */
+#define MAX310X_LCR_REG                        (0x0b) /* LCR */
+#define MAX310X_RXTO_REG               (0x0c) /* RX timeout */
+#define MAX310X_HDPIXDELAY_REG         (0x0d) /* Auto transceiver delays */
+#define MAX310X_IRDA_REG               (0x0e) /* IRDA settings */
+#define MAX310X_FLOWLVL_REG            (0x0f) /* Flow control levels */
+#define MAX310X_FIFOTRIGLVL_REG                (0x10) /* FIFO IRQ trigger levels */
+#define MAX310X_TXFIFOLVL_REG          (0x11) /* TX FIFO level */
+#define MAX310X_RXFIFOLVL_REG          (0x12) /* RX FIFO level */
+#define MAX310X_FLOWCTRL_REG           (0x13) /* Flow control */
+#define MAX310X_XON1_REG               (0x14) /* XON1 character */
+#define MAX310X_XON2_REG               (0x15) /* XON2 character */
+#define MAX310X_XOFF1_REG              (0x16) /* XOFF1 character */
+#define MAX310X_XOFF2_REG              (0x17) /* XOFF2 character */
+#define MAX310X_GPIOCFG_REG            (0x18) /* GPIO config */
+#define MAX310X_GPIODATA_REG           (0x19) /* GPIO data */
+#define MAX310X_PLLCFG_REG             (0x1a) /* PLL config */
+#define MAX310X_BRGCFG_REG             (0x1b) /* Baud rate generator conf */
+#define MAX310X_BRGDIVLSB_REG          (0x1c) /* Baud rate divisor LSB */
+#define MAX310X_BRGDIVMSB_REG          (0x1d) /* Baud rate divisor MSB */
+#define MAX310X_CLKSRC_REG             (0x1e) /* Clock source */
+/* Only present in MAX3107 */
+#define MAX3107_REVID_REG              (0x1f) /* Revision identification */
+
+/* IRQ register bits */
+#define MAX310X_IRQ_LSR_BIT            (1 << 0) /* LSR interrupt */
+#define MAX310X_IRQ_SPCHR_BIT          (1 << 1) /* Special char interrupt */
+#define MAX310X_IRQ_STS_BIT            (1 << 2) /* Status interrupt */
+#define MAX310X_IRQ_RXFIFO_BIT         (1 << 3) /* RX FIFO interrupt */
+#define MAX310X_IRQ_TXFIFO_BIT         (1 << 4) /* TX FIFO interrupt */
+#define MAX310X_IRQ_TXEMPTY_BIT                (1 << 5) /* TX FIFO empty interrupt */
+#define MAX310X_IRQ_RXEMPTY_BIT                (1 << 6) /* RX FIFO empty interrupt */
+#define MAX310X_IRQ_CTS_BIT            (1 << 7) /* CTS interrupt */
+
+/* LSR register bits */
+#define MAX310X_LSR_RXTO_BIT           (1 << 0) /* RX timeout */
+#define MAX310X_LSR_RXOVR_BIT          (1 << 1) /* RX overrun */
+#define MAX310X_LSR_RXPAR_BIT          (1 << 2) /* RX parity error */
+#define MAX310X_LSR_FRERR_BIT          (1 << 3) /* Frame error */
+#define MAX310X_LSR_RXBRK_BIT          (1 << 4) /* RX break */
+#define MAX310X_LSR_RXNOISE_BIT                (1 << 5) /* RX noise */
+#define MAX310X_LSR_CTS_BIT            (1 << 7) /* CTS pin state */
+
+/* Special character register bits */
+#define MAX310X_SPCHR_XON1_BIT         (1 << 0) /* XON1 character */
+#define MAX310X_SPCHR_XON2_BIT         (1 << 1) /* XON2 character */
+#define MAX310X_SPCHR_XOFF1_BIT                (1 << 2) /* XOFF1 character */
+#define MAX310X_SPCHR_XOFF2_BIT                (1 << 3) /* XOFF2 character */
+#define MAX310X_SPCHR_BREAK_BIT                (1 << 4) /* RX break */
+#define MAX310X_SPCHR_MULTIDROP_BIT    (1 << 5) /* 9-bit multidrop addr char */
+
+/* Status register bits */
+#define MAX310X_STS_GPIO0_BIT          (1 << 0) /* GPIO 0 interrupt */
+#define MAX310X_STS_GPIO1_BIT          (1 << 1) /* GPIO 1 interrupt */
+#define MAX310X_STS_GPIO2_BIT          (1 << 2) /* GPIO 2 interrupt */
+#define MAX310X_STS_GPIO3_BIT          (1 << 3) /* GPIO 3 interrupt */
+#define MAX310X_STS_CLKREADY_BIT       (1 << 5) /* Clock ready */
+#define MAX310X_STS_SLEEP_BIT          (1 << 6) /* Sleep interrupt */
+
+/* MODE1 register bits */
+#define MAX310X_MODE1_RXDIS_BIT                (1 << 0) /* RX disable */
+#define MAX310X_MODE1_TXDIS_BIT                (1 << 1) /* TX disable */
+#define MAX310X_MODE1_TXHIZ_BIT                (1 << 2) /* TX pin three-state */
+#define MAX310X_MODE1_RTSHIZ_BIT       (1 << 3) /* RTS pin three-state */
+#define MAX310X_MODE1_TRNSCVCTRL_BIT   (1 << 4) /* Transceiver ctrl enable */
+#define MAX310X_MODE1_FORCESLEEP_BIT   (1 << 5) /* Force sleep mode */
+#define MAX310X_MODE1_AUTOSLEEP_BIT    (1 << 6) /* Auto sleep enable */
+#define MAX310X_MODE1_IRQSEL_BIT       (1 << 7) /* IRQ pin enable */
+
+/* MODE2 register bits */
+#define MAX310X_MODE2_RST_BIT          (1 << 0) /* Chip reset */
+#define MAX310X_MODE2_FIFORST_BIT      (1 << 1) /* FIFO reset */
+#define MAX310X_MODE2_RXTRIGINV_BIT    (1 << 2) /* RX FIFO INT invert */
+#define MAX310X_MODE2_RXEMPTINV_BIT    (1 << 3) /* RX FIFO empty INT invert */
+#define MAX310X_MODE2_SPCHR_BIT                (1 << 4) /* Special chr detect enable */
+#define MAX310X_MODE2_LOOPBACK_BIT     (1 << 5) /* Internal loopback enable */
+#define MAX310X_MODE2_MULTIDROP_BIT    (1 << 6) /* 9-bit multidrop enable */
+#define MAX310X_MODE2_ECHOSUPR_BIT     (1 << 7) /* ECHO suppression enable */
+
+/* LCR register bits */
+#define MAX310X_LCR_LENGTH0_BIT                (1 << 0) /* Word length bit 0 */
+#define MAX310X_LCR_LENGTH1_BIT                (1 << 1) /* Word length bit 1
+                                                 *
+                                                 * Word length bits table:
+                                                 * 00 -> 5 bit words
+                                                 * 01 -> 6 bit words
+                                                 * 10 -> 7 bit words
+                                                 * 11 -> 8 bit words
+                                                 */
+#define MAX310X_LCR_STOPLEN_BIT                (1 << 2) /* STOP length bit
+                                                 *
+                                                 * STOP length bit table:
+                                                 * 0 -> 1 stop bit
+                                                 * 1 -> 1-1.5 stop bits if
+                                                 *      word length is 5,
+                                                 *      2 stop bits otherwise
+                                                 */
+#define MAX310X_LCR_PARITY_BIT         (1 << 3) /* Parity bit enable */
+#define MAX310X_LCR_EVENPARITY_BIT     (1 << 4) /* Even parity bit enable */
+#define MAX310X_LCR_FORCEPARITY_BIT    (1 << 5) /* 9-bit multidrop parity */
+#define MAX310X_LCR_TXBREAK_BIT                (1 << 6) /* TX break enable */
+#define MAX310X_LCR_RTS_BIT            (1 << 7) /* RTS pin control */
+#define MAX310X_LCR_WORD_LEN_5         (0x00)
+#define MAX310X_LCR_WORD_LEN_6         (0x01)
+#define MAX310X_LCR_WORD_LEN_7         (0x02)
+#define MAX310X_LCR_WORD_LEN_8         (0x03)
+
+/* IRDA register bits */
+#define MAX310X_IRDA_IRDAEN_BIT                (1 << 0) /* IRDA mode enable */
+#define MAX310X_IRDA_SIR_BIT           (1 << 1) /* SIR mode enable */
+#define MAX310X_IRDA_SHORTIR_BIT       (1 << 2) /* Short SIR mode enable */
+#define MAX310X_IRDA_MIR_BIT           (1 << 3) /* MIR mode enable */
+#define MAX310X_IRDA_RXINV_BIT         (1 << 4) /* RX logic inversion enable */
+#define MAX310X_IRDA_TXINV_BIT         (1 << 5) /* TX logic inversion enable */
+
+/* Flow control trigger level register masks */
+#define MAX310X_FLOWLVL_HALT_MASK      (0x000f) /* Flow control halt level */
+#define MAX310X_FLOWLVL_RES_MASK       (0x00f0) /* Flow control resume level */
+#define MAX310X_FLOWLVL_HALT(words)    ((words / 8) & 0x0f)
+#define MAX310X_FLOWLVL_RES(words)     (((words / 8) & 0x0f) << 4)
+
+/* FIFO interrupt trigger level register masks */
+#define MAX310X_FIFOTRIGLVL_TX_MASK    (0x0f) /* TX FIFO trigger level */
+#define MAX310X_FIFOTRIGLVL_RX_MASK    (0xf0) /* RX FIFO trigger level */
+#define MAX310X_FIFOTRIGLVL_TX(words)  ((words / 8) & 0x0f)
+#define MAX310X_FIFOTRIGLVL_RX(words)  (((words / 8) & 0x0f) << 4)
+
+/* Flow control register bits */
+#define MAX310X_FLOWCTRL_AUTORTS_BIT   (1 << 0) /* Auto RTS flow ctrl enable */
+#define MAX310X_FLOWCTRL_AUTOCTS_BIT   (1 << 1) /* Auto CTS flow ctrl enable */
+#define MAX310X_FLOWCTRL_GPIADDR_BIT   (1 << 2) /* Enables that GPIO inputs
+                                                 * are used in conjunction with
+                                                 * XOFF2 for definition of
+                                                 * special character */
+#define MAX310X_FLOWCTRL_SWFLOWEN_BIT  (1 << 3) /* Auto SW flow ctrl enable */
+#define MAX310X_FLOWCTRL_SWFLOW0_BIT   (1 << 4) /* SWFLOW bit 0 */
+#define MAX310X_FLOWCTRL_SWFLOW1_BIT   (1 << 5) /* SWFLOW bit 1
+                                                 *
+                                                 * SWFLOW bits 1 & 0 table:
+                                                 * 00 -> no transmitter flow
+                                                 *       control
+                                                 * 01 -> receiver compares
+                                                 *       XON2 and XOFF2
+                                                 *       and controls
+                                                 *       transmitter
+                                                 * 10 -> receiver compares
+                                                 *       XON1 and XOFF1
+                                                 *       and controls
+                                                 *       transmitter
+                                                 * 11 -> receiver compares
+                                                 *       XON1, XON2, XOFF1 and
+                                                 *       XOFF2 and controls
+                                                 *       transmitter
+                                                 */
+#define MAX310X_FLOWCTRL_SWFLOW2_BIT   (1 << 6) /* SWFLOW bit 2 */
+#define MAX310X_FLOWCTRL_SWFLOW3_BIT   (1 << 7) /* SWFLOW bit 3
+                                                 *
+                                                 * SWFLOW bits 3 & 2 table:
+                                                 * 00 -> no received flow
+                                                 *       control
+                                                 * 01 -> transmitter generates
+                                                 *       XON2 and XOFF2
+                                                 * 10 -> transmitter generates
+                                                 *       XON1 and XOFF1
+                                                 * 11 -> transmitter generates
+                                                 *       XON1, XON2, XOFF1 and
+                                                 *       XOFF2
+                                                 */
+
+/* GPIO configuration register bits */
+#define MAX310X_GPIOCFG_GP0OUT_BIT     (1 << 0) /* GPIO 0 output enable */
+#define MAX310X_GPIOCFG_GP1OUT_BIT     (1 << 1) /* GPIO 1 output enable */
+#define MAX310X_GPIOCFG_GP2OUT_BIT     (1 << 2) /* GPIO 2 output enable */
+#define MAX310X_GPIOCFG_GP3OUT_BIT     (1 << 3) /* GPIO 3 output enable */
+#define MAX310X_GPIOCFG_GP0OD_BIT      (1 << 4) /* GPIO 0 open-drain enable */
+#define MAX310X_GPIOCFG_GP1OD_BIT      (1 << 5) /* GPIO 1 open-drain enable */
+#define MAX310X_GPIOCFG_GP2OD_BIT      (1 << 6) /* GPIO 2 open-drain enable */
+#define MAX310X_GPIOCFG_GP3OD_BIT      (1 << 7) /* GPIO 3 open-drain enable */
+
+/* GPIO DATA register bits */
+#define MAX310X_GPIODATA_GP0OUT_BIT    (1 << 0) /* GPIO 0 output value */
+#define MAX310X_GPIODATA_GP1OUT_BIT    (1 << 1) /* GPIO 1 output value */
+#define MAX310X_GPIODATA_GP2OUT_BIT    (1 << 2) /* GPIO 2 output value */
+#define MAX310X_GPIODATA_GP3OUT_BIT    (1 << 3) /* GPIO 3 output value */
+#define MAX310X_GPIODATA_GP0IN_BIT     (1 << 4) /* GPIO 0 input value */
+#define MAX310X_GPIODATA_GP1IN_BIT     (1 << 5) /* GPIO 1 input value */
+#define MAX310X_GPIODATA_GP2IN_BIT     (1 << 6) /* GPIO 2 input value */
+#define MAX310X_GPIODATA_GP3IN_BIT     (1 << 7) /* GPIO 3 input value */
+
+/* PLL configuration register masks */
+#define MAX310X_PLLCFG_PREDIV_MASK     (0x3f) /* PLL predivision value */
+#define MAX310X_PLLCFG_PLLFACTOR_MASK  (0xc0) /* PLL multiplication factor */
+
+/* Baud rate generator configuration register bits */
+#define MAX310X_BRGCFG_2XMODE_BIT      (1 << 4) /* Double baud rate */
+#define MAX310X_BRGCFG_4XMODE_BIT      (1 << 5) /* Quadruple baud rate */
+
+/* Clock source register bits */
+#define MAX310X_CLKSRC_CRYST_BIT       (1 << 1) /* Crystal osc enable */
+#define MAX310X_CLKSRC_PLL_BIT         (1 << 2) /* PLL enable */
+#define MAX310X_CLKSRC_PLLBYP_BIT      (1 << 3) /* PLL bypass */
+#define MAX310X_CLKSRC_EXTCLK_BIT      (1 << 4) /* External clock enable */
+#define MAX310X_CLKSRC_CLK2RTS_BIT     (1 << 7) /* Baud clk to RTS pin */
+
+/* Misc definitions */
+#define MAX310X_FIFO_SIZE              (128)
+
+/* MAX3107 specific */
+#define MAX3107_REV_ID                 (0xa0)
+#define MAX3107_REV_MASK               (0xfe)
+
+/* IRQ status bits definitions */
+#define MAX310X_IRQ_TX                 (MAX310X_IRQ_TXFIFO_BIT | \
+                                        MAX310X_IRQ_TXEMPTY_BIT)
+#define MAX310X_IRQ_RX                 (MAX310X_IRQ_RXFIFO_BIT | \
+                                        MAX310X_IRQ_RXEMPTY_BIT)
+
+/* Supported chip types */
+enum {
+       MAX310X_TYPE_MAX3107    = 3107,
+       MAX310X_TYPE_MAX3108    = 3108,
+};
+
+struct max310x_port {
+       struct uart_driver      uart;
+       struct uart_port        port;
+
+       const char              *name;
+       int                     uartclk;
+
+       unsigned int            nr_gpio;
+#ifdef CONFIG_GPIOLIB
+       struct gpio_chip        gpio;
+#endif
+
+       struct regmap           *regmap;
+       struct regmap_config    regcfg;
+
+       struct workqueue_struct *wq;
+       struct work_struct      tx_work;
+
+       struct mutex            max310x_mutex;
+
+       struct max310x_pdata    *pdata;
+};
+
+static bool max3107_8_reg_writeable(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case MAX310X_IRQSTS_REG:
+       case MAX310X_LSR_IRQSTS_REG:
+       case MAX310X_SPCHR_IRQSTS_REG:
+       case MAX310X_STS_IRQSTS_REG:
+       case MAX310X_TXFIFOLVL_REG:
+       case MAX310X_RXFIFOLVL_REG:
+       case MAX3107_REVID_REG: /* Only available on MAX3107 */
+               return false;
+       default:
+               break;
+       }
+
+       return true;
+}
+
+static bool max310x_reg_volatile(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case MAX310X_RHR_REG:
+       case MAX310X_IRQSTS_REG:
+       case MAX310X_LSR_IRQSTS_REG:
+       case MAX310X_SPCHR_IRQSTS_REG:
+       case MAX310X_STS_IRQSTS_REG:
+       case MAX310X_TXFIFOLVL_REG:
+       case MAX310X_RXFIFOLVL_REG:
+       case MAX310X_GPIODATA_REG:
+               return true;
+       default:
+               break;
+       }
+
+       return false;
+}
+
+static bool max310x_reg_precious(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case MAX310X_RHR_REG:
+       case MAX310X_IRQSTS_REG:
+       case MAX310X_SPCHR_IRQSTS_REG:
+       case MAX310X_STS_IRQSTS_REG:
+               return true;
+       default:
+               break;
+       }
+
+       return false;
+}
+
+static void max310x_set_baud(struct max310x_port *s, int baud)
+{
+       unsigned int mode = 0, div = s->uartclk / baud;
+
+       if (!(div / 16)) {
+               /* Mode x2 */
+               mode = MAX310X_BRGCFG_2XMODE_BIT;
+               div = (s->uartclk * 2) / baud;
+       }
+
+       if (!(div / 16)) {
+               /* Mode x4 */
+               mode = MAX310X_BRGCFG_4XMODE_BIT;
+               div = (s->uartclk * 4) / baud;
+       }
+
+       regmap_write(s->regmap, MAX310X_BRGDIVMSB_REG,
+                    ((div / 16) >> 8) & 0xff);
+       regmap_write(s->regmap, MAX310X_BRGDIVLSB_REG, (div / 16) & 0xff);
+       regmap_write(s->regmap, MAX310X_BRGCFG_REG, (div % 16) | mode);
+}
+
+static void max310x_wait_pll(struct max310x_port *s)
+{
+       int tryes = 1000;
+
+       /* Wait for PLL only if crystal is used */
+       if (!(s->pdata->driver_flags & MAX310X_EXT_CLK)) {
+               unsigned int sts = 0;
+
+               while (tryes--) {
+                       regmap_read(s->regmap, MAX310X_STS_IRQSTS_REG, &sts);
+                       if (sts & MAX310X_STS_CLKREADY_BIT)
+                               break;
+               }
+       }
+}
+
+static int __devinit max310x_update_best_err(unsigned long f, long *besterr)
+{
+       /* Use baudrate 115200 for calculate error */
+       long err = f % (115200 * 16);
+
+       if ((*besterr < 0) || (*besterr > err)) {
+               *besterr = err;
+               return 0;
+       }
+
+       return 1;
+}
+
+static int __devinit max310x_set_ref_clk(struct max310x_port *s)
+{
+       unsigned int div, clksrc, pllcfg = 0;
+       long besterr = -1;
+       unsigned long fdiv, fmul, bestfreq = s->pdata->frequency;
+
+       /* First, update error without PLL */
+       max310x_update_best_err(s->pdata->frequency, &besterr);
+
+       /* Try all possible PLL dividers */
+       for (div = 1; (div <= 63) && besterr; div++) {
+               fdiv = DIV_ROUND_CLOSEST(s->pdata->frequency, div);
+
+               /* Try multiplier 6 */
+               fmul = fdiv * 6;
+               if ((fdiv >= 500000) && (fdiv <= 800000))
+                       if (!max310x_update_best_err(fmul, &besterr)) {
+                               pllcfg = (0 << 6) | div;
+                               bestfreq = fmul;
+                       }
+               /* Try multiplier 48 */
+               fmul = fdiv * 48;
+               if ((fdiv >= 850000) && (fdiv <= 1200000))
+                       if (!max310x_update_best_err(fmul, &besterr)) {
+                               pllcfg = (1 << 6) | div;
+                               bestfreq = fmul;
+                       }
+               /* Try multiplier 96 */
+               fmul = fdiv * 96;
+               if ((fdiv >= 425000) && (fdiv <= 1000000))
+                       if (!max310x_update_best_err(fmul, &besterr)) {
+                               pllcfg = (2 << 6) | div;
+                               bestfreq = fmul;
+                       }
+               /* Try multiplier 144 */
+               fmul = fdiv * 144;
+               if ((fdiv >= 390000) && (fdiv <= 667000))
+                       if (!max310x_update_best_err(fmul, &besterr)) {
+                               pllcfg = (3 << 6) | div;
+                               bestfreq = fmul;
+                       }
+       }
+
+       /* Configure clock source */
+       if (s->pdata->driver_flags & MAX310X_EXT_CLK)
+               clksrc = MAX310X_CLKSRC_EXTCLK_BIT;
+       else
+               clksrc = MAX310X_CLKSRC_CRYST_BIT;
+
+       /* Configure PLL */
+       if (pllcfg) {
+               clksrc |= MAX310X_CLKSRC_PLL_BIT;
+               regmap_write(s->regmap, MAX310X_PLLCFG_REG, pllcfg);
+       } else
+               clksrc |= MAX310X_CLKSRC_PLLBYP_BIT;
+
+       regmap_write(s->regmap, MAX310X_CLKSRC_REG, clksrc);
+
+       if (pllcfg)
+               max310x_wait_pll(s);
+
+       dev_dbg(s->port.dev, "Reference clock set to %lu Hz\n", bestfreq);
+
+       return (int)bestfreq;
+}
+
+static void max310x_handle_rx(struct max310x_port *s, unsigned int rxlen)
+{
+       unsigned int sts = 0, ch = 0, flag;
+       struct tty_struct *tty = tty_port_tty_get(&s->port.state->port);
+
+       if (!tty)
+               return;
+
+       if (unlikely(rxlen >= MAX310X_FIFO_SIZE)) {
+               dev_warn(s->port.dev, "Possible RX FIFO overrun %d\n", rxlen);
+               /* Ensure sanity of RX level */
+               rxlen = MAX310X_FIFO_SIZE;
+       }
+
+       dev_dbg(s->port.dev, "RX Len = %u\n", rxlen);
+
+       while (rxlen--) {
+               regmap_read(s->regmap, MAX310X_RHR_REG, &ch);
+               regmap_read(s->regmap, MAX310X_LSR_IRQSTS_REG, &sts);
+
+               sts &= MAX310X_LSR_RXPAR_BIT | MAX310X_LSR_FRERR_BIT |
+                      MAX310X_LSR_RXOVR_BIT | MAX310X_LSR_RXBRK_BIT;
+
+               s->port.icount.rx++;
+               flag = TTY_NORMAL;
+
+               if (unlikely(sts)) {
+                       if (sts & MAX310X_LSR_RXBRK_BIT) {
+                               s->port.icount.brk++;
+                               if (uart_handle_break(&s->port))
+                                       continue;
+                       } else if (sts & MAX310X_LSR_RXPAR_BIT)
+                               s->port.icount.parity++;
+                       else if (sts & MAX310X_LSR_FRERR_BIT)
+                               s->port.icount.frame++;
+                       else if (sts & MAX310X_LSR_RXOVR_BIT)
+                               s->port.icount.overrun++;
+
+                       sts &= s->port.read_status_mask;
+                       if (sts & MAX310X_LSR_RXBRK_BIT)
+                               flag = TTY_BREAK;
+                       else if (sts & MAX310X_LSR_RXPAR_BIT)
+                               flag = TTY_PARITY;
+                       else if (sts & MAX310X_LSR_FRERR_BIT)
+                               flag = TTY_FRAME;
+                       else if (sts & MAX310X_LSR_RXOVR_BIT)
+                               flag = TTY_OVERRUN;
+               }
+
+               if (uart_handle_sysrq_char(s->port, ch))
+                       continue;
+
+               if (sts & s->port.ignore_status_mask)
+                       continue;
+
+               uart_insert_char(&s->port, sts, MAX310X_LSR_RXOVR_BIT,
+                                ch, flag);
+       }
+
+       tty_flip_buffer_push(tty);
+
+       tty_kref_put(tty);
+}
+
+static void max310x_handle_tx(struct max310x_port *s)
+{
+       struct circ_buf *xmit = &s->port.state->xmit;
+       unsigned int txlen = 0, to_send;
+
+       if (unlikely(s->port.x_char)) {
+               regmap_write(s->regmap, MAX310X_THR_REG, s->port.x_char);
+               s->port.icount.tx++;
+               s->port.x_char = 0;
+               return;
+       }
+
+       if (uart_circ_empty(xmit) || uart_tx_stopped(&s->port))
+               return;
+
+       /* Get length of data pending in circular buffer */
+       to_send = uart_circ_chars_pending(xmit);
+       if (likely(to_send)) {
+               /* Limit to size of TX FIFO */
+               regmap_read(s->regmap, MAX310X_TXFIFOLVL_REG, &txlen);
+               txlen = MAX310X_FIFO_SIZE - txlen;
+               to_send = (to_send > txlen) ? txlen : to_send;
+
+               dev_dbg(s->port.dev, "TX Len = %u\n", to_send);
+
+               /* Add data to send */
+               s->port.icount.tx += to_send;
+               while (to_send--) {
+                       regmap_write(s->regmap, MAX310X_THR_REG,
+                                    xmit->buf[xmit->tail]);
+                       xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               };
+       }
+
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(&s->port);
+}
+
+static irqreturn_t max310x_ist(int irq, void *dev_id)
+{
+       struct max310x_port *s = (struct max310x_port *)dev_id;
+       unsigned int ists = 0, lsr = 0, rxlen = 0;
+
+       mutex_lock(&s->max310x_mutex);
+
+       for (;;) {
+               /* Read IRQ status & RX FIFO level */
+               regmap_read(s->regmap, MAX310X_IRQSTS_REG, &ists);
+               regmap_read(s->regmap, MAX310X_LSR_IRQSTS_REG, &lsr);
+               regmap_read(s->regmap, MAX310X_RXFIFOLVL_REG, &rxlen);
+               if (!ists && !(lsr & MAX310X_LSR_RXTO_BIT) && !rxlen)
+                       break;
+
+               dev_dbg(s->port.dev, "IRQ status: 0x%02x\n", ists);
+
+               if (rxlen)
+                       max310x_handle_rx(s, rxlen);
+               if (ists & MAX310X_IRQ_TX)
+                       max310x_handle_tx(s);
+               if (ists & MAX310X_IRQ_CTS_BIT)
+                       uart_handle_cts_change(&s->port,
+                                              !!(lsr & MAX310X_LSR_CTS_BIT));
+       }
+
+       mutex_unlock(&s->max310x_mutex);
+
+       return IRQ_HANDLED;
+}
+
+static void max310x_wq_proc(struct work_struct *ws)
+{
+       struct max310x_port *s = container_of(ws, struct max310x_port, tx_work);
+
+       mutex_lock(&s->max310x_mutex);
+       max310x_handle_tx(s);
+       mutex_unlock(&s->max310x_mutex);
+}
+
+static void max310x_start_tx(struct uart_port *port)
+{
+       struct max310x_port *s = container_of(port, struct max310x_port, port);
+
+       queue_work(s->wq, &s->tx_work);
+}
+
+static void max310x_stop_tx(struct uart_port *port)
+{
+       /* Do nothing */
+}
+
+static void max310x_stop_rx(struct uart_port *port)
+{
+       /* Do nothing */
+}
+
+static unsigned int max310x_tx_empty(struct uart_port *port)
+{
+       unsigned int val = 0;
+       struct max310x_port *s = container_of(port, struct max310x_port, port);
+
+       mutex_lock(&s->max310x_mutex);
+       regmap_read(s->regmap, MAX310X_TXFIFOLVL_REG, &val);
+       mutex_unlock(&s->max310x_mutex);
+
+       return val ? 0 : TIOCSER_TEMT;
+}
+
+static void max310x_enable_ms(struct uart_port *port)
+{
+       /* Modem status not supported */
+}
+
+static unsigned int max310x_get_mctrl(struct uart_port *port)
+{
+       /* DCD and DSR are not wired and CTS/RTS is handled automatically
+        * so just indicate DSR and CAR asserted
+        */
+       return TIOCM_DSR | TIOCM_CAR;
+}
+
+static void max310x_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+       /* DCD and DSR are not wired and CTS/RTS is hadnled automatically
+        * so do nothing
+        */
+}
+
+static void max310x_break_ctl(struct uart_port *port, int break_state)
+{
+       struct max310x_port *s = container_of(port, struct max310x_port, port);
+
+       mutex_lock(&s->max310x_mutex);
+       regmap_update_bits(s->regmap, MAX310X_LCR_REG,
+                          MAX310X_LCR_TXBREAK_BIT,
+                          break_state ? MAX310X_LCR_TXBREAK_BIT : 0);
+       mutex_unlock(&s->max310x_mutex);
+}
+
+static void max310x_set_termios(struct uart_port *port,
+                               struct ktermios *termios,
+                               struct ktermios *old)
+{
+       struct max310x_port *s = container_of(port, struct max310x_port, port);
+       unsigned int lcr, flow = 0;
+       int baud;
+
+       mutex_lock(&s->max310x_mutex);
+
+       /* Mask termios capabilities we don't support */
+       termios->c_cflag &= ~CMSPAR;
+       termios->c_iflag &= ~IXANY;
+
+       /* Word size */
+       switch (termios->c_cflag & CSIZE) {
+       case CS5:
+               lcr = MAX310X_LCR_WORD_LEN_5;
+               break;
+       case CS6:
+               lcr = MAX310X_LCR_WORD_LEN_6;
+               break;
+       case CS7:
+               lcr = MAX310X_LCR_WORD_LEN_7;
+               break;
+       case CS8:
+       default:
+               lcr = MAX310X_LCR_WORD_LEN_8;
+               break;
+       }
+
+       /* Parity */
+       if (termios->c_cflag & PARENB) {
+               lcr |= MAX310X_LCR_PARITY_BIT;
+               if (!(termios->c_cflag & PARODD))
+                       lcr |= MAX310X_LCR_EVENPARITY_BIT;
+       }
+
+       /* Stop bits */
+       if (termios->c_cflag & CSTOPB)
+               lcr |= MAX310X_LCR_STOPLEN_BIT; /* 2 stops */
+
+       /* Update LCR register */
+       regmap_write(s->regmap, MAX310X_LCR_REG, lcr);
+
+       /* Set read status mask */
+       port->read_status_mask = MAX310X_LSR_RXOVR_BIT;
+       if (termios->c_iflag & INPCK)
+               port->read_status_mask |= MAX310X_LSR_RXPAR_BIT |
+                                         MAX310X_LSR_FRERR_BIT;
+       if (termios->c_iflag & (BRKINT | PARMRK))
+               port->read_status_mask |= MAX310X_LSR_RXBRK_BIT;
+
+       /* Set status ignore mask */
+       port->ignore_status_mask = 0;
+       if (termios->c_iflag & IGNBRK)
+               port->ignore_status_mask |= MAX310X_LSR_RXBRK_BIT;
+       if (!(termios->c_cflag & CREAD))
+               port->ignore_status_mask |= MAX310X_LSR_RXPAR_BIT |
+                                           MAX310X_LSR_RXOVR_BIT |
+                                           MAX310X_LSR_FRERR_BIT |
+                                           MAX310X_LSR_RXBRK_BIT;
+
+       /* Configure flow control */
+       regmap_write(s->regmap, MAX310X_XON1_REG, termios->c_cc[VSTART]);
+       regmap_write(s->regmap, MAX310X_XOFF1_REG, termios->c_cc[VSTOP]);
+       if (termios->c_cflag & CRTSCTS)
+               flow |= MAX310X_FLOWCTRL_AUTOCTS_BIT |
+                       MAX310X_FLOWCTRL_AUTORTS_BIT;
+       if (termios->c_iflag & IXON)
+               flow |= MAX310X_FLOWCTRL_SWFLOW3_BIT |
+                       MAX310X_FLOWCTRL_SWFLOWEN_BIT;
+       if (termios->c_iflag & IXOFF)
+               flow |= MAX310X_FLOWCTRL_SWFLOW1_BIT |
+                       MAX310X_FLOWCTRL_SWFLOWEN_BIT;
+       regmap_write(s->regmap, MAX310X_FLOWCTRL_REG, flow);
+
+       /* Get baud rate generator configuration */
+       baud = uart_get_baud_rate(port, termios, old,
+                                 port->uartclk / 16 / 0xffff,
+                                 port->uartclk / 4);
+
+       /* Setup baudrate generator */
+       max310x_set_baud(s, baud);
+
+       /* Update timeout according to new baud rate */
+       uart_update_timeout(port, termios->c_cflag, baud);
+
+       mutex_unlock(&s->max310x_mutex);
+}
+
+static int max310x_startup(struct uart_port *port)
+{
+       unsigned int val, line = port->line;
+       struct max310x_port *s = container_of(port, struct max310x_port, port);
+
+       if (s->pdata->suspend)
+               s->pdata->suspend(0);
+
+       mutex_lock(&s->max310x_mutex);
+
+       /* Configure baud rate, 9600 as default */
+       max310x_set_baud(s, 9600);
+
+       /* Configure LCR register, 8N1 mode by default */
+       val = MAX310X_LCR_WORD_LEN_8;
+       regmap_write(s->regmap, MAX310X_LCR_REG, val);
+
+       /* Configure MODE1 register */
+       regmap_update_bits(s->regmap, MAX310X_MODE1_REG,
+                          MAX310X_MODE1_TRNSCVCTRL_BIT,
+                          (s->pdata->uart_flags[line] & MAX310X_AUTO_DIR_CTRL)
+                          ? MAX310X_MODE1_TRNSCVCTRL_BIT : 0);
+
+       /* Configure MODE2 register */
+       val = MAX310X_MODE2_RXEMPTINV_BIT;
+       if (s->pdata->uart_flags[line] & MAX310X_LOOPBACK)
+               val |= MAX310X_MODE2_LOOPBACK_BIT;
+       if (s->pdata->uart_flags[line] & MAX310X_ECHO_SUPRESS)
+               val |= MAX310X_MODE2_ECHOSUPR_BIT;
+
+       /* Reset FIFOs */
+       val |= MAX310X_MODE2_FIFORST_BIT;
+       regmap_write(s->regmap, MAX310X_MODE2_REG, val);
+
+       /* Configure FIFO trigger level register */
+       /* RX FIFO trigger for 16 words, TX FIFO trigger for 64 words */
+       val = MAX310X_FIFOTRIGLVL_RX(16) | MAX310X_FIFOTRIGLVL_TX(64);
+       regmap_write(s->regmap, MAX310X_FIFOTRIGLVL_REG, val);
+
+       /* Configure flow control levels */
+       /* Flow control halt level 96, resume level 48 */
+       val = MAX310X_FLOWLVL_RES(48) | MAX310X_FLOWLVL_HALT(96);
+       regmap_write(s->regmap, MAX310X_FLOWLVL_REG, val);
+
+       /* Clear timeout register */
+       regmap_write(s->regmap, MAX310X_RXTO_REG, 0);
+
+       /* Configure LSR interrupt enable register */
+       /* Enable RX timeout interrupt */
+       val = MAX310X_LSR_RXTO_BIT;
+       regmap_write(s->regmap, MAX310X_LSR_IRQEN_REG, val);
+
+       /* Clear FIFO reset */
+       regmap_update_bits(s->regmap, MAX310X_MODE2_REG,
+                          MAX310X_MODE2_FIFORST_BIT, 0);
+
+       /* Clear IRQ status register by reading it */
+       regmap_read(s->regmap, MAX310X_IRQSTS_REG, &val);
+
+       /* Configure interrupt enable register */
+       /* Enable CTS change interrupt */
+       val = MAX310X_IRQ_CTS_BIT;
+       /* Enable RX, TX interrupts */
+       val |= MAX310X_IRQ_RX | MAX310X_IRQ_TX;
+       regmap_write(s->regmap, MAX310X_IRQEN_REG, val);
+
+       mutex_unlock(&s->max310x_mutex);
+
+       return 0;
+}
+
+static void max310x_shutdown(struct uart_port *port)
+{
+       struct max310x_port *s = container_of(port, struct max310x_port, port);
+
+       /* Disable all interrupts */
+       mutex_lock(&s->max310x_mutex);
+       regmap_write(s->regmap, MAX310X_IRQEN_REG, 0);
+       mutex_unlock(&s->max310x_mutex);
+
+       if (s->pdata->suspend)
+               s->pdata->suspend(1);
+}
+
+static const char *max310x_type(struct uart_port *port)
+{
+       struct max310x_port *s = container_of(port, struct max310x_port, port);
+
+       return (port->type == PORT_MAX310X) ? s->name : NULL;
+}
+
+static int max310x_request_port(struct uart_port *port)
+{
+       /* Do nothing */
+       return 0;
+}
+
+static void max310x_release_port(struct uart_port *port)
+{
+       /* Do nothing */
+}
+
+static void max310x_config_port(struct uart_port *port, int flags)
+{
+       if (flags & UART_CONFIG_TYPE)
+               port->type = PORT_MAX310X;
+}
+
+static int max310x_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+       if ((ser->type == PORT_UNKNOWN) || (ser->type == PORT_MAX310X))
+               return 0;
+       if (ser->irq == port->irq)
+               return 0;
+
+       return -EINVAL;
+}
+
+static struct uart_ops max310x_ops = {
+       .tx_empty       = max310x_tx_empty,
+       .set_mctrl      = max310x_set_mctrl,
+       .get_mctrl      = max310x_get_mctrl,
+       .stop_tx        = max310x_stop_tx,
+       .start_tx       = max310x_start_tx,
+       .stop_rx        = max310x_stop_rx,
+       .enable_ms      = max310x_enable_ms,
+       .break_ctl      = max310x_break_ctl,
+       .startup        = max310x_startup,
+       .shutdown       = max310x_shutdown,
+       .set_termios    = max310x_set_termios,
+       .type           = max310x_type,
+       .request_port   = max310x_request_port,
+       .release_port   = max310x_release_port,
+       .config_port    = max310x_config_port,
+       .verify_port    = max310x_verify_port,
+};
+
+static int max310x_suspend(struct spi_device *spi, pm_message_t state)
+{
+       int ret;
+       struct max310x_port *s = dev_get_drvdata(&spi->dev);
+
+       dev_dbg(&spi->dev, "Suspend\n");
+
+       ret = uart_suspend_port(&s->uart, &s->port);
+
+       mutex_lock(&s->max310x_mutex);
+
+       /* Enable sleep mode */
+       regmap_update_bits(s->regmap, MAX310X_MODE1_REG,
+                          MAX310X_MODE1_FORCESLEEP_BIT,
+                          MAX310X_MODE1_FORCESLEEP_BIT);
+
+       mutex_unlock(&s->max310x_mutex);
+
+       if (s->pdata->suspend)
+               s->pdata->suspend(1);
+
+       return ret;
+}
+
+static int max310x_resume(struct spi_device *spi)
+{
+       struct max310x_port *s = dev_get_drvdata(&spi->dev);
+
+       dev_dbg(&spi->dev, "Resume\n");
+
+       if (s->pdata->suspend)
+               s->pdata->suspend(0);
+
+       mutex_lock(&s->max310x_mutex);
+
+       /* Disable sleep mode */
+       regmap_update_bits(s->regmap, MAX310X_MODE1_REG,
+                          MAX310X_MODE1_FORCESLEEP_BIT,
+                          0);
+
+       max310x_wait_pll(s);
+
+       mutex_unlock(&s->max310x_mutex);
+
+       return uart_resume_port(&s->uart, &s->port);
+}
+
+#ifdef CONFIG_GPIOLIB
+static int max310x_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+       unsigned int val = 0;
+       struct max310x_port *s = container_of(chip, struct max310x_port, gpio);
+
+       mutex_lock(&s->max310x_mutex);
+       regmap_read(s->regmap, MAX310X_GPIODATA_REG, &val);
+       mutex_unlock(&s->max310x_mutex);
+
+       return !!((val >> 4) & (1 << offset));
+}
+
+static void max310x_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+       struct max310x_port *s = container_of(chip, struct max310x_port, gpio);
+
+       mutex_lock(&s->max310x_mutex);
+       regmap_update_bits(s->regmap, MAX310X_GPIODATA_REG, 1 << offset, value ?
+                                                           1 << offset : 0);
+       mutex_unlock(&s->max310x_mutex);
+}
+
+static int max310x_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+       struct max310x_port *s = container_of(chip, struct max310x_port, gpio);
+
+       mutex_lock(&s->max310x_mutex);
+
+       regmap_update_bits(s->regmap, MAX310X_GPIOCFG_REG, 1 << offset, 0);
+
+       mutex_unlock(&s->max310x_mutex);
+
+       return 0;
+}
+
+static int max310x_gpio_direction_output(struct gpio_chip *chip,
+                                        unsigned offset, int value)
+{
+       struct max310x_port *s = container_of(chip, struct max310x_port, gpio);
+
+       mutex_lock(&s->max310x_mutex);
+
+       regmap_update_bits(s->regmap, MAX310X_GPIOCFG_REG, 1 << offset,
+                                                          1 << offset);
+       regmap_update_bits(s->regmap, MAX310X_GPIODATA_REG, 1 << offset, value ?
+                                                           1 << offset : 0);
+
+       mutex_unlock(&s->max310x_mutex);
+
+       return 0;
+}
+#endif
+
+/* Generic platform data */
+static struct max310x_pdata generic_plat_data = {
+       .driver_flags   = MAX310X_EXT_CLK,
+       .uart_flags[0]  = MAX310X_ECHO_SUPRESS,
+       .frequency      = 26000000,
+};
+
+static int __devinit max310x_probe(struct spi_device *spi)
+{
+       struct max310x_port *s;
+       struct device *dev = &spi->dev;
+       int chiptype = spi_get_device_id(spi)->driver_data;
+       struct max310x_pdata *pdata = dev->platform_data;
+       unsigned int val = 0;
+       int ret;
+
+       /* Check for IRQ */
+       if (spi->irq <= 0) {
+               dev_err(dev, "No IRQ specified\n");
+               return -ENOTSUPP;
+       }
+
+       /* Alloc port structure */
+       s = devm_kzalloc(dev, sizeof(struct max310x_port), GFP_KERNEL);
+       if (!s) {
+               dev_err(dev, "Error allocating port structure\n");
+               return -ENOMEM;
+       }
+       dev_set_drvdata(dev, s);
+
+       if (!pdata) {
+               dev_warn(dev, "No platform data supplied, using defaults\n");
+               pdata = &generic_plat_data;
+       }
+       s->pdata = pdata;
+
+       /* Individual chip settings */
+       switch (chiptype) {
+       case MAX310X_TYPE_MAX3107:
+               s->name = "MAX3107";
+               s->nr_gpio = 4;
+               s->uart.nr = 1;
+               s->regcfg.max_register = 0x1f;
+               break;
+       case MAX310X_TYPE_MAX3108:
+               s->name = "MAX3108";
+               s->nr_gpio = 4;
+               s->uart.nr = 1;
+               s->regcfg.max_register = 0x1e;
+               break;
+       default:
+               dev_err(dev, "Unsupported chip type %i\n", chiptype);
+               return -ENOTSUPP;
+       }
+
+       /* Check input frequency */
+       if ((pdata->driver_flags & MAX310X_EXT_CLK) &&
+          ((pdata->frequency < 500000) || (pdata->frequency > 35000000)))
+               goto err_freq;
+       /* Check frequency for quartz */
+       if (!(pdata->driver_flags & MAX310X_EXT_CLK) &&
+          ((pdata->frequency < 1000000) || (pdata->frequency > 4000000)))
+               goto err_freq;
+
+       mutex_init(&s->max310x_mutex);
+
+       /* Setup SPI bus */
+       spi->mode               = SPI_MODE_0;
+       spi->bits_per_word      = 8;
+       spi->max_speed_hz       = 26000000;
+       spi_setup(spi);
+
+       /* Setup regmap */
+       s->regcfg.reg_bits              = 8;
+       s->regcfg.val_bits              = 8;
+       s->regcfg.read_flag_mask        = 0x00;
+       s->regcfg.write_flag_mask       = 0x80;
+       s->regcfg.cache_type            = REGCACHE_RBTREE;
+       s->regcfg.writeable_reg         = max3107_8_reg_writeable;
+       s->regcfg.volatile_reg          = max310x_reg_volatile;
+       s->regcfg.precious_reg          = max310x_reg_precious;
+       s->regmap = devm_regmap_init_spi(spi, &s->regcfg);
+       if (IS_ERR(s->regmap)) {
+               ret = PTR_ERR(s->regmap);
+               dev_err(dev, "Failed to initialize register map\n");
+               goto err_out;
+       }
+
+       /* Reset chip & check SPI function */
+       ret = regmap_write(s->regmap, MAX310X_MODE2_REG, MAX310X_MODE2_RST_BIT);
+       if (ret) {
+               dev_err(dev, "SPI transfer failed\n");
+               goto err_out;
+       }
+       /* Clear chip reset */
+       regmap_write(s->regmap, MAX310X_MODE2_REG, 0);
+
+       switch (chiptype) {
+       case MAX310X_TYPE_MAX3107:
+               /* Check REV ID to ensure we are talking to what we expect */
+               regmap_read(s->regmap, MAX3107_REVID_REG, &val);
+               if (((val & MAX3107_REV_MASK) != MAX3107_REV_ID)) {
+                       dev_err(dev, "%s ID 0x%02x does not match\n",
+                               s->name, val);
+                       ret = -ENODEV;
+                       goto err_out;
+               }
+               break;
+       case MAX310X_TYPE_MAX3108:
+               /* MAX3108 have not REV ID register, we just check default value
+                * from clocksource register to make sure everything works.
+                */
+               regmap_read(s->regmap, MAX310X_CLKSRC_REG, &val);
+               if (val != (MAX310X_CLKSRC_EXTCLK_BIT |
+                           MAX310X_CLKSRC_PLLBYP_BIT)) {
+                       dev_err(dev, "%s not present\n", s->name);
+                       ret = -ENODEV;
+                       goto err_out;
+               }
+               break;
+       }
+
+       /* Board specific configure */
+       if (pdata->init)
+               pdata->init();
+       if (pdata->suspend)
+               pdata->suspend(0);
+
+       /* Calculate referecne clock */
+       s->uartclk = max310x_set_ref_clk(s);
+
+       /* Disable all interrupts */
+       regmap_write(s->regmap, MAX310X_IRQEN_REG, 0);
+
+       /* Setup MODE1 register */
+       val = MAX310X_MODE1_IRQSEL_BIT; /* Enable IRQ pin */
+       if (pdata->driver_flags & MAX310X_AUTOSLEEP)
+               val = MAX310X_MODE1_AUTOSLEEP_BIT;
+       regmap_write(s->regmap, MAX310X_MODE1_REG, val);
+
+       /* Setup interrupt */
+       ret = devm_request_threaded_irq(dev, spi->irq, NULL, max310x_ist,
+                                       IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                                       dev_name(dev), s);
+       if (ret) {
+               dev_err(dev, "Unable to reguest IRQ %i\n", spi->irq);
+               goto err_out;
+       }
+
+       /* Register UART driver */
+       s->uart.owner           = THIS_MODULE;
+       s->uart.driver_name     = dev_name(dev);
+       s->uart.dev_name        = "ttyMAX";
+       s->uart.major           = MAX310X_MAJOR;
+       s->uart.minor           = MAX310X_MINOR;
+       ret = uart_register_driver(&s->uart);
+       if (ret) {
+               dev_err(dev, "Registering UART driver failed\n");
+               goto err_out;
+       }
+
+       /* Initialize workqueue for start TX */
+       s->wq = create_freezable_workqueue(dev_name(dev));
+       INIT_WORK(&s->tx_work, max310x_wq_proc);
+
+       /* Initialize UART port data */
+       s->port.line            = 0;
+       s->port.dev             = dev;
+       s->port.irq             = spi->irq;
+       s->port.type            = PORT_MAX310X;
+       s->port.fifosize        = MAX310X_FIFO_SIZE;
+       s->port.flags           = UPF_SKIP_TEST | UPF_FIXED_TYPE;
+       s->port.iotype          = UPIO_PORT;
+       s->port.membase         = (void __iomem *)0xffffffff; /* Bogus value */
+       s->port.uartclk         = s->uartclk;
+       s->port.ops             = &max310x_ops;
+       uart_add_one_port(&s->uart, &s->port);
+
+#ifdef CONFIG_GPIOLIB
+       /* Setup GPIO cotroller */
+       if (pdata->gpio_base) {
+               s->gpio.owner           = THIS_MODULE;
+               s->gpio.dev             = dev;
+               s->gpio.label           = dev_name(dev);
+               s->gpio.direction_input = max310x_gpio_direction_input;
+               s->gpio.get             = max310x_gpio_get;
+               s->gpio.direction_output= max310x_gpio_direction_output;
+               s->gpio.set             = max310x_gpio_set;
+               s->gpio.base            = pdata->gpio_base;
+               s->gpio.ngpio           = s->nr_gpio;
+               if (gpiochip_add(&s->gpio)) {
+                       /* Indicate that we should not call gpiochip_remove */
+                       s->gpio.base = 0;
+               }
+       } else
+               dev_info(dev, "GPIO support not enabled\n");
+#endif
+
+       /* Go to suspend mode */
+       if (pdata->suspend)
+               pdata->suspend(1);
+
+       return 0;
+
+err_freq:
+       dev_err(dev, "Frequency parameter incorrect\n");
+       ret = -EINVAL;
+
+err_out:
+       dev_set_drvdata(dev, NULL);
+       devm_kfree(dev, s);
+
+       return ret;
+}
+
+static int __devexit max310x_remove(struct spi_device *spi)
+{
+       struct device *dev = &spi->dev;
+       struct max310x_port *s = dev_get_drvdata(dev);
+
+       dev_dbg(dev, "Removing port\n");
+
+       devm_free_irq(dev, s->port.irq, s);
+
+       destroy_workqueue(s->wq);
+
+       uart_remove_one_port(&s->uart, &s->port);
+
+       uart_unregister_driver(&s->uart);
+
+#ifdef CONFIG_GPIOLIB
+       if (s->pdata->gpio_base)
+               gpiochip_remove(&s->gpio);
+#endif
+
+       dev_set_drvdata(dev, NULL);
+
+       if (s->pdata->suspend)
+               s->pdata->suspend(1);
+       if (s->pdata->exit)
+               s->pdata->exit();
+
+       devm_kfree(dev, s);
+
+       return 0;
+}
+
+static const struct spi_device_id max310x_id_table[] = {
+       { "max3107",    MAX310X_TYPE_MAX3107 },
+       { "max3108",    MAX310X_TYPE_MAX3108 },
+};
+MODULE_DEVICE_TABLE(spi, max310x_id_table);
+
+static struct spi_driver max310x_driver = {
+       .driver = {
+               .name   = "max310x",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = max310x_probe,
+       .remove         = __devexit_p(max310x_remove),
+       .suspend        = max310x_suspend,
+       .resume         = max310x_resume,
+       .id_table       = max310x_id_table,
+};
+module_spi_driver(max310x_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
+MODULE_DESCRIPTION("MAX310X serial driver");
index bedac0d4c9cecf8b13c0e16dc1c69215dc843ecb..b131f2d885d4a56e8d7ec40c59db38723245d1c0 100644 (file)
@@ -598,7 +598,7 @@ static struct psc_ops mpc512x_psc_ops = {
 };
 #endif
 
-static struct psc_ops *psc_ops;
+static const struct psc_ops *psc_ops;
 
 /* ======================================================================== */
 /* UART operations                                                          */
index b25e6ee7144374e258b646608a41978f1d2f1a3b..925d1fa153db328a3d75a45583cfe6415a11f0af 100644 (file)
@@ -223,9 +223,11 @@ static int __init smd_tty_init(void)
                return ret;
 
        for (i = 0; i < smd_tty_channels_len; i++) {
-               tty_port_init(&smd_tty[smd_tty_channels[i].id].port);
-               smd_tty[smd_tty_channels[i].id].port.ops = &smd_tty_port_ops;
-               tty_register_device(smd_tty_driver, smd_tty_channels[i].id, 0);
+               struct tty_port *port = &smd_tty[smd_tty_channels[i].id].port;
+               tty_port_init(port);
+               port->ops = &smd_tty_port_ops;
+               tty_port_register_device(port, smd_tty_driver,
+                               smd_tty_channels[i].id, NULL);
        }
 
        return 0;
index 2e341b81ff891b632e5cbee6d2337aba0f10cfe8..3a667eed63d6086c017c8abcc83a597850ec4966 100644 (file)
@@ -73,6 +73,7 @@
 #define AUART_CTRL0_CLKGATE                    (1 << 30)
 
 #define AUART_CTRL2_CTSEN                      (1 << 15)
+#define AUART_CTRL2_RTSEN                      (1 << 14)
 #define AUART_CTRL2_RTS                                (1 << 11)
 #define AUART_CTRL2_RXE                                (1 << 9)
 #define AUART_CTRL2_TXE                                (1 << 8)
@@ -259,9 +260,12 @@ static void mxs_auart_set_mctrl(struct uart_port *u, unsigned mctrl)
 
        u32 ctrl = readl(u->membase + AUART_CTRL2);
 
-       ctrl &= ~AUART_CTRL2_RTS;
-       if (mctrl & TIOCM_RTS)
-               ctrl |= AUART_CTRL2_RTS;
+       ctrl &= ~AUART_CTRL2_RTSEN;
+       if (mctrl & TIOCM_RTS) {
+               if (u->state->port.flags & ASYNC_CTS_FLOW)
+                       ctrl |= AUART_CTRL2_RTSEN;
+       }
+
        s->ctrl = mctrl;
        writel(ctrl, u->membase + AUART_CTRL2);
 }
@@ -359,9 +363,9 @@ static void mxs_auart_settermios(struct uart_port *u,
 
        /* figure out the hardware flow control settings */
        if (cflag & CRTSCTS)
-               ctrl2 |= AUART_CTRL2_CTSEN;
+               ctrl2 |= AUART_CTRL2_CTSEN | AUART_CTRL2_RTSEN;
        else
-               ctrl2 &= ~AUART_CTRL2_CTSEN;
+               ctrl2 &= ~(AUART_CTRL2_CTSEN | AUART_CTRL2_RTSEN);
 
        /* set baud rate */
        baud = uart_get_baud_rate(u, termios, old, 0, u->uartclk);
index 34e71874a89266db9ebd47cb9a156e89192af7a1..df443b908ca305694c43d9665859c9cca11f3dde 100644 (file)
@@ -105,6 +105,10 @@ static int __devinit of_platform_serial_setup(struct platform_device *ofdev,
        port->uartclk = clk;
        port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP
                | UPF_FIXED_PORT | UPF_FIXED_TYPE;
+
+       if (of_find_property(np, "no-loopback-test", NULL))
+               port->flags |= UPF_SKIP_TEST;
+
        port->dev = &ofdev->dev;
 
        if (type == PORT_TEGRA)
@@ -144,8 +148,15 @@ static int __devinit of_platform_serial_probe(struct platform_device *ofdev)
        switch (port_type) {
 #ifdef CONFIG_SERIAL_8250
        case PORT_8250 ... PORT_MAX_8250:
-               ret = serial8250_register_port(&port);
+       {
+               /* For now the of bindings don't support the extra
+                  8250 specific bits */
+               struct uart_8250_port port8250;
+               memset(&port8250, 0, sizeof(port8250));
+               port8250.port = port;
+               ret = serial8250_register_8250_port(&port8250);
                break;
+       }
 #endif
 #ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
        case PORT_NWPSERIAL:
index d3cda0cb2df0a9e2d7c4536c0d8638a9461abff7..aa603f221c6ad61486f4c5ecbedde63fd957b113 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/irq.h>
 #include <linux/pm_runtime.h>
 #include <linux/of.h>
+#include <linux/gpio.h>
 
 #include <plat/dma.h>
 #include <plat/dmtimer.h>
@@ -507,6 +508,16 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
        up->mcr |= mcr;
        serial_out(up, UART_MCR, up->mcr);
        pm_runtime_put(&up->pdev->dev);
+
+       if (gpio_is_valid(up->DTR_gpio) &&
+           !!(mctrl & TIOCM_DTR) != up->DTR_active) {
+               up->DTR_active = !up->DTR_active;
+               if (gpio_cansleep(up->DTR_gpio))
+                       schedule_work(&up->qos_work);
+               else
+                       gpio_set_value(up->DTR_gpio,
+                                      up->DTR_active != up->DTR_inverted);
+       }
 }
 
 static void serial_omap_break_ctl(struct uart_port *port, int break_state)
@@ -715,6 +726,9 @@ static void serial_omap_uart_qos_work(struct work_struct *work)
                                                qos_work);
 
        pm_qos_update_request(&up->pm_qos_request, up->latency);
+       if (gpio_is_valid(up->DTR_gpio))
+               gpio_set_value_cansleep(up->DTR_gpio,
+                                       up->DTR_active != up->DTR_inverted);
 }
 
 static void
@@ -1435,7 +1449,7 @@ static int serial_omap_probe(struct platform_device *pdev)
        struct uart_omap_port   *up;
        struct resource         *mem, *irq, *dma_tx, *dma_rx;
        struct omap_uart_port_info *omap_up_info = pdev->dev.platform_data;
-       int ret = -ENOSPC;
+       int ret;
 
        if (pdev->dev.of_node)
                omap_up_info = of_get_uart_port_info(&pdev->dev);
@@ -1466,10 +1480,29 @@ static int serial_omap_probe(struct platform_device *pdev)
        if (!dma_tx)
                return -ENXIO;
 
+       if (gpio_is_valid(omap_up_info->DTR_gpio) &&
+           omap_up_info->DTR_present) {
+               ret = gpio_request(omap_up_info->DTR_gpio, "omap-serial");
+               if (ret < 0)
+                       return ret;
+               ret = gpio_direction_output(omap_up_info->DTR_gpio,
+                                           omap_up_info->DTR_inverted);
+               if (ret < 0)
+                       return ret;
+       }
+
        up = devm_kzalloc(&pdev->dev, sizeof(*up), GFP_KERNEL);
        if (!up)
                return -ENOMEM;
 
+       if (gpio_is_valid(omap_up_info->DTR_gpio) &&
+           omap_up_info->DTR_present) {
+               up->DTR_gpio = omap_up_info->DTR_gpio;
+               up->DTR_inverted = omap_up_info->DTR_inverted;
+       } else
+               up->DTR_gpio = -EINVAL;
+       up->DTR_active = 0;
+
        up->pdev = pdev;
        up->port.dev = &pdev->dev;
        up->port.type = PORT_OMAP;
index 558ce8509a9add9dac313e4c74704c824445e080..4cd6c2381528c53127959872a295077849625cba 100644 (file)
@@ -979,6 +979,10 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv)
        priv->tx_dma_use = 1;
 
        priv->sg_tx_p = kzalloc(sizeof(struct scatterlist)*num, GFP_ATOMIC);
+       if (!priv->sg_tx_p) {
+               dev_err(priv->port.dev, "%s:kzalloc Failed\n", __func__);
+               return 0;
+       }
 
        sg_init_table(priv->sg_tx_p, num); /* Initialize SG table */
        sg = priv->sg_tx_p;
index 654755a990dfc30cac559567e260b17978bbc54b..333c8d012b0e32c9e40881fd1defff6cc52b8b10 100644 (file)
@@ -1348,10 +1348,16 @@ static int pmz_verify_port(struct uart_port *port, struct serial_struct *ser)
 static int pmz_poll_get_char(struct uart_port *port)
 {
        struct uart_pmac_port *uap = (struct uart_pmac_port *)port;
+       int tries = 2;
 
-       while ((read_zsreg(uap, R0) & Rx_CH_AV) == 0)
-               udelay(5);
-       return read_zsdata(uap);
+       while (tries) {
+               if ((read_zsreg(uap, R0) & Rx_CH_AV) != 0)
+                       return read_zsdata(uap);
+               if (tries--)
+                       udelay(5);
+       }
+
+       return NO_POLL_CHAR;
 }
 
 static void pmz_poll_put_char(struct uart_port *port, unsigned char c)
index 5847a4b855f74804d327cca6490cade872f673d2..9033fc6e0e4eb31a4fea337eca73634c8eec5109 100644 (file)
@@ -670,9 +670,19 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
 {
        struct uart_pxa_port *up = serial_pxa_ports[co->index];
        unsigned int ier;
+       unsigned long flags;
+       int locked = 1;
 
        clk_prepare_enable(up->clk);
 
+       local_irq_save(flags);
+       if (up->port.sysrq)
+               locked = 0;
+       else if (oops_in_progress)
+               locked = spin_trylock(&up->port.lock);
+       else
+               spin_lock(&up->port.lock);
+
        /*
         *      First save the IER then disable the interrupts
         */
@@ -688,6 +698,10 @@ serial_pxa_console_write(struct console *co, const char *s, unsigned int count)
        wait_for_xmitr(up);
        serial_out(up, UART_IER, ier);
 
+       if (locked)
+               spin_unlock(&up->port.lock);
+       local_irq_restore(flags);
+
        clk_disable_unprepare(up->clk);
 }
 
index 02d07bfcfa8add3f46f0eb9b36a6b821305e8493..5c5e7e09f23e67eda88a4dd7b188eabb5ee46e9a 100644 (file)
@@ -529,7 +529,7 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
 
        switch (level) {
        case 3:
-               if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
+               if (!IS_ERR(ourport->baudclk))
                        clk_disable(ourport->baudclk);
 
                clk_disable(ourport->clk);
@@ -538,7 +538,7 @@ static void s3c24xx_serial_pm(struct uart_port *port, unsigned int level,
        case 0:
                clk_enable(ourport->clk);
 
-               if (!IS_ERR(ourport->baudclk) && ourport->baudclk != NULL)
+               if (!IS_ERR(ourport->baudclk))
                        clk_enable(ourport->baudclk);
 
                break;
@@ -604,7 +604,6 @@ static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport,
        char clkname[MAX_CLK_NAME_LENGTH];
        int calc_deviation, deviation = (1 << 30) - 1;
 
-       *best_clk = NULL;
        clk_sel = (ourport->cfg->clk_sel) ? ourport->cfg->clk_sel :
                        ourport->info->def_clk_sel;
        for (cnt = 0; cnt < info->num_clks; cnt++) {
@@ -613,7 +612,7 @@ static unsigned int s3c24xx_serial_getclk(struct s3c24xx_uart_port *ourport,
 
                sprintf(clkname, "clk_uart_baud%d", cnt);
                clk = clk_get(ourport->port.dev, clkname);
-               if (IS_ERR_OR_NULL(clk))
+               if (IS_ERR(clk))
                        continue;
 
                rate = clk_get_rate(clk);
@@ -684,7 +683,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
 {
        struct s3c2410_uartcfg *cfg = s3c24xx_port_to_cfg(port);
        struct s3c24xx_uart_port *ourport = to_ourport(port);
-       struct clk *clk = NULL;
+       struct clk *clk = ERR_PTR(-EINVAL);
        unsigned long flags;
        unsigned int baud, quot, clk_sel = 0;
        unsigned int ulcon;
@@ -705,7 +704,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
        quot = s3c24xx_serial_getclk(ourport, baud, &clk, &clk_sel);
        if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)
                quot = port->custom_divisor;
-       if (!clk)
+       if (IS_ERR(clk))
                return;
 
        /* check to see if we need  to change clock source */
@@ -713,9 +712,9 @@ static void s3c24xx_serial_set_termios(struct uart_port *port,
        if (ourport->baudclk != clk) {
                s3c24xx_serial_setsource(port, clk_sel);
 
-               if (ourport->baudclk != NULL && !IS_ERR(ourport->baudclk)) {
+               if (!IS_ERR(ourport->baudclk)) {
                        clk_disable(ourport->baudclk);
-                       ourport->baudclk  = NULL;
+                       ourport->baudclk = ERR_PTR(-EINVAL);
                }
 
                clk_enable(clk);
@@ -1036,7 +1035,7 @@ static int s3c24xx_serial_cpufreq_transition(struct notifier_block *nb,
                if (tty == NULL)
                        goto exit;
 
-               termios = tty->termios;
+               termios = &tty->termios;
 
                if (termios == NULL) {
                        printk(KERN_WARNING "%s: no termios?\n", __func__);
@@ -1160,7 +1159,11 @@ static ssize_t s3c24xx_serial_show_clksrc(struct device *dev,
        struct uart_port *port = s3c24xx_dev_to_port(dev);
        struct s3c24xx_uart_port *ourport = to_ourport(port);
 
-       return snprintf(buf, PAGE_SIZE, "* %s\n", ourport->baudclk->name);
+       if (IS_ERR(ourport->baudclk))
+               return -EINVAL;
+
+       return snprintf(buf, PAGE_SIZE, "* %s\n",
+                       ourport->baudclk->name ?: "(null)");
 }
 
 static DEVICE_ATTR(clock_source, S_IRUGO, s3c24xx_serial_show_clksrc, NULL);
@@ -1200,6 +1203,7 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
+       ourport->baudclk = ERR_PTR(-EINVAL);
        ourport->info = ourport->drv_data->info;
        ourport->cfg = (pdev->dev.platform_data) ?
                        (struct s3c2410_uartcfg *)pdev->dev.platform_data :
@@ -1387,7 +1391,7 @@ s3c24xx_serial_get_options(struct uart_port *port, int *baud,
                sprintf(clk_name, "clk_uart_baud%d", clk_sel);
 
                clk = clk_get(port->dev, clk_name);
-               if (!IS_ERR(clk) && clk != NULL)
+               if (!IS_ERR(clk))
                        rate = clk_get_rate(clk);
                else
                        rate = 1;
index e0b4b0a30a5a7b7c145de9682f18859032354497..3992e48b4c71b8d628912459fe116f01bba09848 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/irq.h>
+#include <linux/io.h>
 
 #if defined(CONFIG_MAGIC_SYSRQ)
 #define SUPPORT_SYSRQ
index a21dc8e3b7c0cf56ed808e006499abf4b661a217..5b308c87b68cb8124f04593874123bfd968bfc36 100644 (file)
@@ -159,7 +159,7 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
        retval = uport->ops->startup(uport);
        if (retval == 0) {
                if (uart_console(uport) && uport->cons->cflag) {
-                       tty->termios->c_cflag = uport->cons->cflag;
+                       tty->termios.c_cflag = uport->cons->cflag;
                        uport->cons->cflag = 0;
                }
                /*
@@ -172,7 +172,7 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
                         * Setup the RTS and DTR signals once the
                         * port is open and ready to respond.
                         */
-                       if (tty->termios->c_cflag & CBAUD)
+                       if (tty->termios.c_cflag & CBAUD)
                                uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR);
                }
 
@@ -240,7 +240,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state)
                /*
                 * Turn off DTR and RTS early.
                 */
-               if (!tty || (tty->termios->c_cflag & HUPCL))
+               if (!tty || (tty->termios.c_cflag & HUPCL))
                        uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS);
 
                uart_port_shutdown(port);
@@ -440,10 +440,10 @@ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
         * If we have no tty, termios, or the port does not exist,
         * then we can't set the parameters for this port.
         */
-       if (!tty || !tty->termios || uport->type == PORT_UNKNOWN)
+       if (!tty || uport->type == PORT_UNKNOWN)
                return;
 
-       termios = tty->termios;
+       termios = &tty->termios;
 
        /*
         * Set flags based on termios cflag
@@ -614,7 +614,7 @@ static void uart_throttle(struct tty_struct *tty)
        if (I_IXOFF(tty))
                uart_send_xchar(tty, STOP_CHAR(tty));
 
-       if (tty->termios->c_cflag & CRTSCTS)
+       if (tty->termios.c_cflag & CRTSCTS)
                uart_clear_mctrl(state->uart_port, TIOCM_RTS);
 }
 
@@ -630,7 +630,7 @@ static void uart_unthrottle(struct tty_struct *tty)
                        uart_send_xchar(tty, START_CHAR(tty));
        }
 
-       if (tty->termios->c_cflag & CRTSCTS)
+       if (tty->termios.c_cflag & CRTSCTS)
                uart_set_mctrl(port, TIOCM_RTS);
 }
 
@@ -1187,7 +1187,7 @@ static void uart_set_ldisc(struct tty_struct *tty)
        struct uart_port *uport = state->uart_port;
 
        if (uport->ops->set_ldisc)
-               uport->ops->set_ldisc(uport, tty->termios->c_line);
+               uport->ops->set_ldisc(uport, tty->termios.c_line);
 }
 
 static void uart_set_termios(struct tty_struct *tty,
@@ -1195,7 +1195,7 @@ static void uart_set_termios(struct tty_struct *tty,
 {
        struct uart_state *state = tty->driver_data;
        unsigned long flags;
-       unsigned int cflag = tty->termios->c_cflag;
+       unsigned int cflag = tty->termios.c_cflag;
 
 
        /*
@@ -1206,9 +1206,9 @@ static void uart_set_termios(struct tty_struct *tty,
         */
 #define RELEVANT_IFLAG(iflag)  ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
        if ((cflag ^ old_termios->c_cflag) == 0 &&
-           tty->termios->c_ospeed == old_termios->c_ospeed &&
-           tty->termios->c_ispeed == old_termios->c_ispeed &&
-           RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0) {
+           tty->termios.c_ospeed == old_termios->c_ospeed &&
+           tty->termios.c_ispeed == old_termios->c_ispeed &&
+           RELEVANT_IFLAG(tty->termios.c_iflag ^ old_termios->c_iflag) == 0) {
                return;
        }
 
@@ -1960,8 +1960,8 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
                /*
                 * If that's unset, use the tty termios setting.
                 */
-               if (port->tty && port->tty->termios && termios.c_cflag == 0)
-                       termios = *(port->tty->termios);
+               if (port->tty && termios.c_cflag == 0)
+                       termios = port->tty->termios;
 
                if (console_suspend_enabled)
                        uart_change_pm(state, 0);
@@ -2346,7 +2346,8 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport)
         * Register the port whether it's detected or not.  This allows
         * setserial to be used to alter this ports parameters.
         */
-       tty_dev = tty_register_device(drv->tty_driver, uport->line, uport->dev);
+       tty_dev = tty_port_register_device(port, drv->tty_driver, uport->line,
+                       uport->dev);
        if (likely(!IS_ERR(tty_dev))) {
                device_set_wakeup_capable(tty_dev, 1);
        } else {
index 593d40ad0a6be9b0de161803aa69c9011e2fdab8..666aa1455fc76cdd9fa0bfd5e81c03aada348b3f 100644 (file)
@@ -1840,22 +1840,22 @@ static void shutdown(struct mgsl_struct * info)
        usc_DisableInterrupts(info,RECEIVE_DATA + RECEIVE_STATUS +
                TRANSMIT_DATA + TRANSMIT_STATUS + IO_PIN + MISC );
        usc_DisableDmaInterrupts(info,DICR_MASTER + DICR_TRANSMIT + DICR_RECEIVE);
-       
+
        /* Disable DMAEN (Port 7, Bit 14) */
        /* This disconnects the DMA request signal from the ISA bus */
        /* on the ISA adapter. This has no effect for the PCI adapter */
        usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT15) | BIT14));
-       
+
        /* Disable INTEN (Port 6, Bit12) */
        /* This disconnects the IRQ request signal to the ISA bus */
        /* on the ISA adapter. This has no effect for the PCI adapter */
        usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT13) | BIT12));
-       
-       if (!info->port.tty || info->port.tty->termios->c_cflag & HUPCL) {
+
+       if (!info->port.tty || info->port.tty->termios.c_cflag & HUPCL) {
                info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS);
                usc_set_serial_signals(info);
        }
-       
+
        spin_unlock_irqrestore(&info->irq_spinlock,flags);
 
        mgsl_release_resources(info);   
@@ -1895,7 +1895,7 @@ static void mgsl_program_hw(struct mgsl_struct *info)
        usc_EnableInterrupts(info, IO_PIN);
        usc_get_serial_signals(info);
                
-       if (info->netcount || info->port.tty->termios->c_cflag & CREAD)
+       if (info->netcount || info->port.tty->termios.c_cflag & CREAD)
                usc_start_receiver(info);
                
        spin_unlock_irqrestore(&info->irq_spinlock,flags);
@@ -1908,14 +1908,14 @@ static void mgsl_change_params(struct mgsl_struct *info)
        unsigned cflag;
        int bits_per_char;
 
-       if (!info->port.tty || !info->port.tty->termios)
+       if (!info->port.tty)
                return;
                
        if (debug_level >= DEBUG_LEVEL_INFO)
                printk("%s(%d):mgsl_change_params(%s)\n",
                         __FILE__,__LINE__, info->device_name );
                         
-       cflag = info->port.tty->termios->c_cflag;
+       cflag = info->port.tty->termios.c_cflag;
 
        /* if B0 rate (hangup) specified then negate DTR and RTS */
        /* otherwise assert DTR and RTS */
@@ -2367,8 +2367,8 @@ static void mgsl_throttle(struct tty_struct * tty)
        
        if (I_IXOFF(tty))
                mgsl_send_xchar(tty, STOP_CHAR(tty));
-       if (tty->termios->c_cflag & CRTSCTS) {
+
+       if (tty->termios.c_cflag & CRTSCTS) {
                spin_lock_irqsave(&info->irq_spinlock,flags);
                info->serial_signals &= ~SerialSignal_RTS;
                usc_set_serial_signals(info);
@@ -2401,8 +2401,8 @@ static void mgsl_unthrottle(struct tty_struct * tty)
                else
                        mgsl_send_xchar(tty, START_CHAR(tty));
        }
-       
-       if (tty->termios->c_cflag & CRTSCTS) {
+
+       if (tty->termios.c_cflag & CRTSCTS) {
                spin_lock_irqsave(&info->irq_spinlock,flags);
                info->serial_signals |= SerialSignal_RTS;
                usc_set_serial_signals(info);
@@ -3045,7 +3045,7 @@ static void mgsl_set_termios(struct tty_struct *tty, struct ktermios *old_termio
 
        /* Handle transition to B0 status */
        if (old_termios->c_cflag & CBAUD &&
-           !(tty->termios->c_cflag & CBAUD)) {
+           !(tty->termios.c_cflag & CBAUD)) {
                info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
                spin_lock_irqsave(&info->irq_spinlock,flags);
                usc_set_serial_signals(info);
@@ -3054,9 +3054,9 @@ static void mgsl_set_termios(struct tty_struct *tty, struct ktermios *old_termio
        
        /* Handle transition away from B0 status */
        if (!(old_termios->c_cflag & CBAUD) &&
-           tty->termios->c_cflag & CBAUD) {
+           tty->termios.c_cflag & CBAUD) {
                info->serial_signals |= SerialSignal_DTR;
-               if (!(tty->termios->c_cflag & CRTSCTS) || 
+               if (!(tty->termios.c_cflag & CRTSCTS) || 
                    !test_bit(TTY_THROTTLED, &tty->flags)) {
                        info->serial_signals |= SerialSignal_RTS;
                }
@@ -3067,7 +3067,7 @@ static void mgsl_set_termios(struct tty_struct *tty, struct ktermios *old_termio
        
        /* Handle turning off CRTSCTS */
        if (old_termios->c_cflag & CRTSCTS &&
-           !(tty->termios->c_cflag & CRTSCTS)) {
+           !(tty->termios.c_cflag & CRTSCTS)) {
                tty->hw_stopped = 0;
                mgsl_start(tty);
        }
@@ -3287,7 +3287,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
                return 0;
        }
 
-       if (tty->termios->c_cflag & CLOCAL)
+       if (tty->termios.c_cflag & CLOCAL)
                do_clocal = true;
 
        /* Wait for carrier detect and the line to become
@@ -3313,7 +3313,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
        port->blocked_open++;
        
        while (1) {
-               if (tty->termios->c_cflag & CBAUD)
+               if (tty->termios.c_cflag & CBAUD)
                        tty_port_raise_dtr_rts(port);
                
                set_current_state(TASK_INTERRUPTIBLE);
@@ -3338,9 +3338,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
                        printk("%s(%d):block_til_ready blocking on %s count=%d\n",
                                 __FILE__,__LINE__, tty->driver->name, port->count );
                                 
-               tty_unlock();
+               tty_unlock(tty);
                schedule();
-               tty_lock();
+               tty_lock(tty);
        }
        
        set_current_state(TASK_RUNNING);
@@ -3362,6 +3362,29 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
        
 }      /* end of block_til_ready() */
 
+static int mgsl_install(struct tty_driver *driver, struct tty_struct *tty)
+{
+       struct mgsl_struct *info;
+       int line = tty->index;
+
+       /* verify range of specified line number */
+       if (line >= mgsl_device_count) {
+               printk("%s(%d):mgsl_open with invalid line #%d.\n",
+                       __FILE__, __LINE__, line);
+               return -ENODEV;
+       }
+
+       /* find the info structure for the specified line */
+       info = mgsl_device_list;
+       while (info && info->line != line)
+               info = info->next_device;
+       if (mgsl_paranoia_check(info, tty->name, "mgsl_open"))
+               return -ENODEV;
+       tty->driver_data = info;
+
+       return tty_port_install(&info->port, driver, tty);
+}
+
 /* mgsl_open()
  *
  *     Called when a port is opened.  Init and enable port.
@@ -3374,26 +3397,10 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp,
  */
 static int mgsl_open(struct tty_struct *tty, struct file * filp)
 {
-       struct mgsl_struct      *info;
-       int                     retval, line;
+       struct mgsl_struct *info = tty->driver_data;
        unsigned long flags;
+       int retval;
 
-       /* verify range of specified line number */     
-       line = tty->index;
-       if (line >= mgsl_device_count) {
-               printk("%s(%d):mgsl_open with invalid line #%d.\n",
-                       __FILE__,__LINE__,line);
-               return -ENODEV;
-       }
-
-       /* find the info structure for the specified line */
-       info = mgsl_device_list;
-       while(info && info->line != line)
-               info = info->next_device;
-       if (mgsl_paranoia_check(info, tty->name, "mgsl_open"))
-               return -ENODEV;
-       
-       tty->driver_data = info;
        info->port.tty = tty;
                
        if (debug_level >= DEBUG_LEVEL_INFO)
@@ -4297,6 +4304,7 @@ static struct mgsl_struct* mgsl_allocate_device(void)
 }      /* end of mgsl_allocate_device()*/
 
 static const struct tty_operations mgsl_ops = {
+       .install = mgsl_install,
        .open = mgsl_open,
        .close = mgsl_close,
        .write = mgsl_write,
index aa1debf97cc741e3f5914cb5396c8397bd37f362..45f6136f4e51eb58c91b91455c7292d78e39463d 100644 (file)
@@ -785,7 +785,7 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
 
        /* Handle transition to B0 status */
        if (old_termios->c_cflag & CBAUD &&
-           !(tty->termios->c_cflag & CBAUD)) {
+           !(tty->termios.c_cflag & CBAUD)) {
                info->signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
                spin_lock_irqsave(&info->lock,flags);
                set_signals(info);
@@ -794,9 +794,9 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
 
        /* Handle transition away from B0 status */
        if (!(old_termios->c_cflag & CBAUD) &&
-           tty->termios->c_cflag & CBAUD) {
+           tty->termios.c_cflag & CBAUD) {
                info->signals |= SerialSignal_DTR;
-               if (!(tty->termios->c_cflag & CRTSCTS) ||
+               if (!(tty->termios.c_cflag & CRTSCTS) ||
                    !test_bit(TTY_THROTTLED, &tty->flags)) {
                        info->signals |= SerialSignal_RTS;
                }
@@ -807,7 +807,7 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
 
        /* Handle turning off CRTSCTS */
        if (old_termios->c_cflag & CRTSCTS &&
-           !(tty->termios->c_cflag & CRTSCTS)) {
+           !(tty->termios.c_cflag & CRTSCTS)) {
                tty->hw_stopped = 0;
                tx_release(tty);
        }
@@ -1372,7 +1372,7 @@ static void throttle(struct tty_struct * tty)
        DBGINFO(("%s throttle\n", info->device_name));
        if (I_IXOFF(tty))
                send_xchar(tty, STOP_CHAR(tty));
-       if (tty->termios->c_cflag & CRTSCTS) {
+       if (tty->termios.c_cflag & CRTSCTS) {
                spin_lock_irqsave(&info->lock,flags);
                info->signals &= ~SerialSignal_RTS;
                set_signals(info);
@@ -1397,7 +1397,7 @@ static void unthrottle(struct tty_struct * tty)
                else
                        send_xchar(tty, START_CHAR(tty));
        }
-       if (tty->termios->c_cflag & CRTSCTS) {
+       if (tty->termios.c_cflag & CRTSCTS) {
                spin_lock_irqsave(&info->lock,flags);
                info->signals |= SerialSignal_RTS;
                set_signals(info);
@@ -2493,7 +2493,7 @@ static void shutdown(struct slgt_info *info)
 
        slgt_irq_off(info, IRQ_ALL | IRQ_MASTER);
 
-       if (!info->port.tty || info->port.tty->termios->c_cflag & HUPCL) {
+       if (!info->port.tty || info->port.tty->termios.c_cflag & HUPCL) {
                info->signals &= ~(SerialSignal_DTR + SerialSignal_RTS);
                set_signals(info);
        }
@@ -2534,7 +2534,7 @@ static void program_hw(struct slgt_info *info)
        get_signals(info);
 
        if (info->netcount ||
-           (info->port.tty && info->port.tty->termios->c_cflag & CREAD))
+           (info->port.tty && info->port.tty->termios.c_cflag & CREAD))
                rx_start(info);
 
        spin_unlock_irqrestore(&info->lock,flags);
@@ -2548,11 +2548,11 @@ static void change_params(struct slgt_info *info)
        unsigned cflag;
        int bits_per_char;
 
-       if (!info->port.tty || !info->port.tty->termios)
+       if (!info->port.tty)
                return;
        DBGINFO(("%s change_params\n", info->device_name));
 
-       cflag = info->port.tty->termios->c_cflag;
+       cflag = info->port.tty->termios.c_cflag;
 
        /* if B0 rate (hangup) specified then negate DTR and RTS */
        /* otherwise assert DTR and RTS */
@@ -3292,7 +3292,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
                return 0;
        }
 
-       if (tty->termios->c_cflag & CLOCAL)
+       if (tty->termios.c_cflag & CLOCAL)
                do_clocal = true;
 
        /* Wait for carrier detect and the line to become
@@ -3314,7 +3314,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
        port->blocked_open++;
 
        while (1) {
-               if ((tty->termios->c_cflag & CBAUD))
+               if ((tty->termios.c_cflag & CBAUD))
                        tty_port_raise_dtr_rts(port);
 
                set_current_state(TASK_INTERRUPTIBLE);
@@ -3336,9 +3336,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
                }
 
                DBGINFO(("%s block_til_ready wait\n", tty->driver->name));
-               tty_unlock();
+               tty_unlock(tty);
                schedule();
-               tty_lock();
+               tty_lock(tty);
        }
 
        set_current_state(TASK_RUNNING);
@@ -3689,8 +3689,11 @@ static void device_init(int adapter_num, struct pci_dev *pdev)
                }
        }
 
-       for (i=0; i < port_count; ++i)
-               tty_register_device(serial_driver, port_array[i]->line, &(port_array[i]->pdev->dev));
+       for (i = 0; i < port_count; ++i) {
+               struct slgt_info *info = port_array[i];
+               tty_port_register_device(&info->port, serial_driver, info->line,
+                               &info->pdev->dev);
+       }
 }
 
 static int __devinit init_one(struct pci_dev *dev,
index a3dddc12d2fedc3ec261c2c8f2b3da215f564a20..53429c890a899936b760d59819f011abbacad7d3 100644 (file)
@@ -711,15 +711,11 @@ static void ldisc_receive_buf(struct tty_struct *tty,
 
 /* tty callbacks */
 
-/* Called when a port is opened.  Init and enable port.
- */
-static int open(struct tty_struct *tty, struct file *filp)
+static int install(struct tty_driver *driver, struct tty_struct *tty)
 {
        SLMP_INFO *info;
-       int retval, line;
-       unsigned long flags;
+       int line = tty->index;
 
-       line = tty->index;
        if (line >= synclinkmp_device_count) {
                printk("%s(%d): open with invalid line #%d.\n",
                        __FILE__,__LINE__,line);
@@ -727,17 +723,30 @@ static int open(struct tty_struct *tty, struct file *filp)
        }
 
        info = synclinkmp_device_list;
-       while(info && info->line != line)
+       while (info && info->line != line)
                info = info->next_device;
        if (sanity_check(info, tty->name, "open"))
                return -ENODEV;
-       if ( info->init_error ) {
+       if (info->init_error) {
                printk("%s(%d):%s device is not allocated, init error=%d\n",
-                       __FILE__,__LINE__,info->device_name,info->init_error);
+                       __FILE__, __LINE__, info->device_name,
+                       info->init_error);
                return -ENODEV;
        }
 
        tty->driver_data = info;
+
+       return tty_port_install(&info->port, driver, tty);
+}
+
+/* Called when a port is opened.  Init and enable port.
+ */
+static int open(struct tty_struct *tty, struct file *filp)
+{
+       SLMP_INFO *info = tty->driver_data;
+       unsigned long flags;
+       int retval;
+
        info->port.tty = tty;
 
        if (debug_level >= DEBUG_LEVEL_INFO)
@@ -873,7 +882,7 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
 
        /* Handle transition to B0 status */
        if (old_termios->c_cflag & CBAUD &&
-           !(tty->termios->c_cflag & CBAUD)) {
+           !(tty->termios.c_cflag & CBAUD)) {
                info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
                spin_lock_irqsave(&info->lock,flags);
                set_signals(info);
@@ -882,9 +891,9 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
 
        /* Handle transition away from B0 status */
        if (!(old_termios->c_cflag & CBAUD) &&
-           tty->termios->c_cflag & CBAUD) {
+           tty->termios.c_cflag & CBAUD) {
                info->serial_signals |= SerialSignal_DTR;
-               if (!(tty->termios->c_cflag & CRTSCTS) ||
+               if (!(tty->termios.c_cflag & CRTSCTS) ||
                    !test_bit(TTY_THROTTLED, &tty->flags)) {
                        info->serial_signals |= SerialSignal_RTS;
                }
@@ -895,7 +904,7 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
 
        /* Handle turning off CRTSCTS */
        if (old_termios->c_cflag & CRTSCTS &&
-           !(tty->termios->c_cflag & CRTSCTS)) {
+           !(tty->termios.c_cflag & CRTSCTS)) {
                tty->hw_stopped = 0;
                tx_release(tty);
        }
@@ -1473,7 +1482,7 @@ static void throttle(struct tty_struct * tty)
        if (I_IXOFF(tty))
                send_xchar(tty, STOP_CHAR(tty));
 
-       if (tty->termios->c_cflag & CRTSCTS) {
+       if (tty->termios.c_cflag & CRTSCTS) {
                spin_lock_irqsave(&info->lock,flags);
                info->serial_signals &= ~SerialSignal_RTS;
                set_signals(info);
@@ -1502,7 +1511,7 @@ static void unthrottle(struct tty_struct * tty)
                        send_xchar(tty, START_CHAR(tty));
        }
 
-       if (tty->termios->c_cflag & CRTSCTS) {
+       if (tty->termios.c_cflag & CRTSCTS) {
                spin_lock_irqsave(&info->lock,flags);
                info->serial_signals |= SerialSignal_RTS;
                set_signals(info);
@@ -2708,7 +2717,7 @@ static void shutdown(SLMP_INFO * info)
 
        reset_port(info);
 
-       if (!info->port.tty || info->port.tty->termios->c_cflag & HUPCL) {
+       if (!info->port.tty || info->port.tty->termios.c_cflag & HUPCL) {
                info->serial_signals &= ~(SerialSignal_DTR + SerialSignal_RTS);
                set_signals(info);
        }
@@ -2749,7 +2758,7 @@ static void program_hw(SLMP_INFO *info)
 
        get_signals(info);
 
-       if (info->netcount || (info->port.tty && info->port.tty->termios->c_cflag & CREAD) )
+       if (info->netcount || (info->port.tty && info->port.tty->termios.c_cflag & CREAD) )
                rx_start(info);
 
        spin_unlock_irqrestore(&info->lock,flags);
@@ -2762,14 +2771,14 @@ static void change_params(SLMP_INFO *info)
        unsigned cflag;
        int bits_per_char;
 
-       if (!info->port.tty || !info->port.tty->termios)
+       if (!info->port.tty)
                return;
 
        if (debug_level >= DEBUG_LEVEL_INFO)
                printk("%s(%d):%s change_params()\n",
                         __FILE__,__LINE__, info->device_name );
 
-       cflag = info->port.tty->termios->c_cflag;
+       cflag = info->port.tty->termios.c_cflag;
 
        /* if B0 rate (hangup) specified then negate DTR and RTS */
        /* otherwise assert DTR and RTS */
@@ -3306,7 +3315,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
                return 0;
        }
 
-       if (tty->termios->c_cflag & CLOCAL)
+       if (tty->termios.c_cflag & CLOCAL)
                do_clocal = true;
 
        /* Wait for carrier detect and the line to become
@@ -3332,7 +3341,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
        port->blocked_open++;
 
        while (1) {
-               if (tty->termios->c_cflag & CBAUD)
+               if (tty->termios.c_cflag & CBAUD)
                        tty_port_raise_dtr_rts(port);
 
                set_current_state(TASK_INTERRUPTIBLE);
@@ -3357,9 +3366,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
                        printk("%s(%d):%s block_til_ready() count=%d\n",
                                 __FILE__,__LINE__, tty->driver->name, port->count );
 
-               tty_unlock();
+               tty_unlock(tty);
                schedule();
-               tty_lock();
+               tty_lock(tty);
        }
 
        set_current_state(TASK_RUNNING);
@@ -3881,6 +3890,7 @@ static void device_init(int adapter_num, struct pci_dev *pdev)
 }
 
 static const struct tty_operations ops = {
+       .install = install,
        .open = open,
        .close = close,
        .write = write,
index b425c79675ad96adc187c601e36d65c2bebc3581..28c3e869ebba722c5f30bc4675b127f60889684e 100644 (file)
@@ -181,10 +181,13 @@ struct tty_struct *alloc_tty_struct(void)
 
 void free_tty_struct(struct tty_struct *tty)
 {
+       if (!tty)
+               return;
        if (tty->dev)
                put_device(tty->dev);
        kfree(tty->write_buf);
        tty_buffer_free_all(tty);
+       tty->magic = 0xDEADDEAD;
        kfree(tty);
 }
 
@@ -573,7 +576,7 @@ void __tty_hangup(struct tty_struct *tty)
        }
        spin_unlock(&redirect_lock);
 
-       tty_lock();
+       tty_lock(tty);
 
        /* some functions below drop BTM, so we need this bit */
        set_bit(TTY_HUPPING, &tty->flags);
@@ -666,7 +669,7 @@ void __tty_hangup(struct tty_struct *tty)
        clear_bit(TTY_HUPPING, &tty->flags);
        tty_ldisc_enable(tty);
 
-       tty_unlock();
+       tty_unlock(tty);
 
        if (f)
                fput(f);
@@ -1103,12 +1106,12 @@ void tty_write_message(struct tty_struct *tty, char *msg)
 {
        if (tty) {
                mutex_lock(&tty->atomic_write_lock);
-               tty_lock();
+               tty_lock(tty);
                if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) {
-                       tty_unlock();
+                       tty_unlock(tty);
                        tty->ops->write(tty, msg, strlen(msg));
                } else
-                       tty_unlock();
+                       tty_unlock(tty);
                tty_write_unlock(tty);
        }
        return;
@@ -1213,7 +1216,10 @@ static void pty_line_name(struct tty_driver *driver, int index, char *p)
  */
 static void tty_line_name(struct tty_driver *driver, int index, char *p)
 {
-       sprintf(p, "%s%d", driver->name, index + driver->name_base);
+       if (driver->flags & TTY_DRIVER_UNNUMBERED_NODE)
+               strcpy(p, driver->name);
+       else
+               sprintf(p, "%s%d", driver->name, index + driver->name_base);
 }
 
 /**
@@ -1249,21 +1255,19 @@ int tty_init_termios(struct tty_struct *tty)
        struct ktermios *tp;
        int idx = tty->index;
 
-       tp = tty->driver->termios[idx];
-       if (tp == NULL) {
-               tp = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL);
-               if (tp == NULL)
-                       return -ENOMEM;
-               memcpy(tp, &tty->driver->init_termios,
-                                               sizeof(struct ktermios));
-               tty->driver->termios[idx] = tp;
+       if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS)
+               tty->termios = tty->driver->init_termios;
+       else {
+               /* Check for lazy saved data */
+               tp = tty->driver->termios[idx];
+               if (tp != NULL)
+                       tty->termios = *tp;
+               else
+                       tty->termios = tty->driver->init_termios;
        }
-       tty->termios = tp;
-       tty->termios_locked = tp + 1;
-
        /* Compatibility until drivers always set this */
-       tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
-       tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
+       tty->termios.c_ispeed = tty_termios_input_baud_rate(&tty->termios);
+       tty->termios.c_ospeed = tty_termios_baud_rate(&tty->termios);
        return 0;
 }
 EXPORT_SYMBOL_GPL(tty_init_termios);
@@ -1403,10 +1407,14 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
        }
        initialize_tty_struct(tty, driver, idx);
 
+       tty_lock(tty);
        retval = tty_driver_install_tty(driver, tty);
        if (retval < 0)
                goto err_deinit_tty;
 
+       if (!tty->port)
+               tty->port = driver->ports[idx];
+
        /*
         * Structures all installed ... call the ldisc open routines.
         * If we fail here just call release_tty to clean up.  No need
@@ -1415,9 +1423,11 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx)
        retval = tty_ldisc_setup(tty, tty->link);
        if (retval)
                goto err_release_tty;
+       /* Return the tty locked so that it cannot vanish under the caller */
        return tty;
 
 err_deinit_tty:
+       tty_unlock(tty);
        deinitialize_tty_struct(tty);
        free_tty_struct(tty);
 err_module_put:
@@ -1426,6 +1436,7 @@ err_module_put:
 
        /* call the tty release_tty routine to clean out this slot */
 err_release_tty:
+       tty_unlock(tty);
        printk_ratelimited(KERN_INFO "tty_init_dev: ldisc open failed, "
                                 "clearing slot %d\n", idx);
        release_tty(tty, idx);
@@ -1436,22 +1447,25 @@ void tty_free_termios(struct tty_struct *tty)
 {
        struct ktermios *tp;
        int idx = tty->index;
-       /* Kill this flag and push into drivers for locking etc */
-       if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
-               /* FIXME: Locking on ->termios array */
-               tp = tty->termios;
-               tty->driver->termios[idx] = NULL;
-               kfree(tp);
+
+       /* If the port is going to reset then it has no termios to save */
+       if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS)
+               return;
+
+       /* Stash the termios data */
+       tp = tty->driver->termios[idx];
+       if (tp == NULL) {
+               tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL);
+               if (tp == NULL) {
+                       pr_warn("tty: no memory to save termios state.\n");
+                       return;
+               }
+               tty->driver->termios[idx] = tp;
        }
+       *tp = tty->termios;
 }
 EXPORT_SYMBOL(tty_free_termios);
 
-void tty_shutdown(struct tty_struct *tty)
-{
-       tty_driver_remove_tty(tty->driver, tty);
-       tty_free_termios(tty);
-}
-EXPORT_SYMBOL(tty_shutdown);
 
 /**
  *     release_one_tty         -       release tty structure memory
@@ -1462,7 +1476,6 @@ EXPORT_SYMBOL(tty_shutdown);
  *     in use. It also gets called when setup of a device fails.
  *
  *     Locking:
- *             tty_mutex - sometimes only
  *             takes the file list lock internally when working on the list
  *     of ttys that the driver keeps.
  *
@@ -1495,11 +1508,6 @@ static void queue_release_one_tty(struct kref *kref)
 {
        struct tty_struct *tty = container_of(kref, struct tty_struct, kref);
 
-       if (tty->ops->shutdown)
-               tty->ops->shutdown(tty);
-       else
-               tty_shutdown(tty);
-
        /* The hangup queue is now free so we can reuse it rather than
           waste a chunk of memory for each port */
        INIT_WORK(&tty->hangup_work, release_one_tty);
@@ -1528,16 +1536,20 @@ EXPORT_SYMBOL(tty_kref_put);
  *     and decrement the refcount of the backing module.
  *
  *     Locking:
- *             tty_mutex - sometimes only
+ *             tty_mutex
  *             takes the file list lock internally when working on the list
  *     of ttys that the driver keeps.
- *             FIXME: should we require tty_mutex is held here ??
  *
  */
 static void release_tty(struct tty_struct *tty, int idx)
 {
        /* This should always be true but check for the moment */
        WARN_ON(tty->index != idx);
+       WARN_ON(!mutex_is_locked(&tty_mutex));
+       if (tty->ops->shutdown)
+               tty->ops->shutdown(tty);
+       tty_free_termios(tty);
+       tty_driver_remove_tty(tty->driver, tty);
 
        if (tty->link)
                tty_kref_put(tty->link);
@@ -1572,22 +1584,12 @@ static int tty_release_checks(struct tty_struct *tty, struct tty_struct *o_tty,
                                __func__, idx, tty->name);
                return -1;
        }
-       if (tty->termios != tty->driver->termios[idx]) {
-               printk(KERN_DEBUG "%s: driver.termios[%d] not termios for (%s)\n",
-                               __func__, idx, tty->name);
-               return -1;
-       }
        if (tty->driver->other) {
                if (o_tty != tty->driver->other->ttys[idx]) {
                        printk(KERN_DEBUG "%s: other->table[%d] not o_tty for (%s)\n",
                                        __func__, idx, tty->name);
                        return -1;
                }
-               if (o_tty->termios != tty->driver->other->termios[idx]) {
-                       printk(KERN_DEBUG "%s: other->termios[%d] not o_termios for (%s)\n",
-                                       __func__, idx, tty->name);
-                       return -1;
-               }
                if (o_tty->link != tty) {
                        printk(KERN_DEBUG "%s: bad pty pointers\n", __func__);
                        return -1;
@@ -1628,7 +1630,7 @@ int tty_release(struct inode *inode, struct file *filp)
        if (tty_paranoia_check(tty, inode, __func__))
                return 0;
 
-       tty_lock();
+       tty_lock(tty);
        check_tty_count(tty, __func__);
 
        __tty_fasync(-1, filp, 0);
@@ -1637,10 +1639,11 @@ int tty_release(struct inode *inode, struct file *filp)
        pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
                      tty->driver->subtype == PTY_TYPE_MASTER);
        devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0;
+       /* Review: parallel close */
        o_tty = tty->link;
 
        if (tty_release_checks(tty, o_tty, idx)) {
-               tty_unlock();
+               tty_unlock(tty);
                return 0;
        }
 
@@ -1652,7 +1655,7 @@ int tty_release(struct inode *inode, struct file *filp)
        if (tty->ops->close)
                tty->ops->close(tty, filp);
 
-       tty_unlock();
+       tty_unlock(tty);
        /*
         * Sanity check: if tty->count is going to zero, there shouldn't be
         * any waiters on tty->read_wait or tty->write_wait.  We test the
@@ -1675,7 +1678,7 @@ int tty_release(struct inode *inode, struct file *filp)
                   opens on /dev/tty */
 
                mutex_lock(&tty_mutex);
-               tty_lock();
+               tty_lock_pair(tty, o_tty);
                tty_closing = tty->count <= 1;
                o_tty_closing = o_tty &&
                        (o_tty->count <= (pty_master ? 1 : 0));
@@ -1706,7 +1709,7 @@ int tty_release(struct inode *inode, struct file *filp)
 
                printk(KERN_WARNING "%s: %s: read/write wait queue active!\n",
                                __func__, tty_name(tty, buf));
-               tty_unlock();
+               tty_unlock_pair(tty, o_tty);
                mutex_unlock(&tty_mutex);
                schedule();
        }
@@ -1715,6 +1718,9 @@ int tty_release(struct inode *inode, struct file *filp)
         * The closing flags are now consistent with the open counts on
         * both sides, and we've completed the last operation that could
         * block, so it's safe to proceed with closing.
+        *
+        * We must *not* drop the tty_mutex until we ensure that a further
+        * entry into tty_open can not pick up this tty.
         */
        if (pty_master) {
                if (--o_tty->count < 0) {
@@ -1766,12 +1772,13 @@ int tty_release(struct inode *inode, struct file *filp)
        }
 
        mutex_unlock(&tty_mutex);
+       tty_unlock_pair(tty, o_tty);
+       /* At this point the TTY_CLOSING flag should ensure a dead tty
+          cannot be re-opened by a racing opener */
 
        /* check whether both sides are closing ... */
-       if (!tty_closing || (o_tty && !o_tty_closing)) {
-               tty_unlock();
+       if (!tty_closing || (o_tty && !o_tty_closing))
                return 0;
-       }
 
 #ifdef TTY_DEBUG_HANGUP
        printk(KERN_DEBUG "%s: freeing tty structure...\n", __func__);
@@ -1782,14 +1789,17 @@ int tty_release(struct inode *inode, struct file *filp)
        tty_ldisc_release(tty, o_tty);
        /*
         * The release_tty function takes care of the details of clearing
-        * the slots and preserving the termios structure.
+        * the slots and preserving the termios structure. The tty_unlock_pair
+        * should be safe as we keep a kref while the tty is locked (so the
+        * unlock never unlocks a freed tty).
         */
+       mutex_lock(&tty_mutex);
        release_tty(tty, idx);
+       mutex_unlock(&tty_mutex);
 
        /* Make this pty number available for reallocation */
        if (devpts)
                devpts_kill_index(inode, idx);
-       tty_unlock();
        return 0;
 }
 
@@ -1893,6 +1903,9 @@ static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp,
  *     Locking: tty_mutex protects tty, tty_lookup_driver and tty_init_dev.
  *              tty->count should protect the rest.
  *              ->siglock protects ->signal/->sighand
+ *
+ *     Note: the tty_unlock/lock cases without a ref are only safe due to
+ *     tty_mutex
  */
 
 static int tty_open(struct inode *inode, struct file *filp)
@@ -1916,8 +1929,7 @@ retry_open:
        retval = 0;
 
        mutex_lock(&tty_mutex);
-       tty_lock();
-
+       /* This is protected by the tty_mutex */
        tty = tty_open_current_tty(device, filp);
        if (IS_ERR(tty)) {
                retval = PTR_ERR(tty);
@@ -1938,17 +1950,19 @@ retry_open:
        }
 
        if (tty) {
+               tty_lock(tty);
                retval = tty_reopen(tty);
-               if (retval)
+               if (retval < 0) {
+                       tty_unlock(tty);
                        tty = ERR_PTR(retval);
-       } else
+               }
+       } else  /* Returns with the tty_lock held for now */
                tty = tty_init_dev(driver, index);
 
        mutex_unlock(&tty_mutex);
        if (driver)
                tty_driver_kref_put(driver);
        if (IS_ERR(tty)) {
-               tty_unlock();
                retval = PTR_ERR(tty);
                goto err_file;
        }
@@ -1977,7 +1991,7 @@ retry_open:
                printk(KERN_DEBUG "%s: error %d in opening %s...\n", __func__,
                                retval, tty->name);
 #endif
-               tty_unlock(); /* need to call tty_release without BTM */
+               tty_unlock(tty); /* need to call tty_release without BTM */
                tty_release(inode, filp);
                if (retval != -ERESTARTSYS)
                        return retval;
@@ -1989,17 +2003,15 @@ retry_open:
                /*
                 * Need to reset f_op in case a hangup happened.
                 */
-               tty_lock();
                if (filp->f_op == &hung_up_tty_fops)
                        filp->f_op = &tty_fops;
-               tty_unlock();
                goto retry_open;
        }
-       tty_unlock();
+       tty_unlock(tty);
 
 
        mutex_lock(&tty_mutex);
-       tty_lock();
+       tty_lock(tty);
        spin_lock_irq(&current->sighand->siglock);
        if (!noctty &&
            current->signal->leader &&
@@ -2007,11 +2019,10 @@ retry_open:
            tty->session == NULL)
                __proc_set_tty(current, tty);
        spin_unlock_irq(&current->sighand->siglock);
-       tty_unlock();
+       tty_unlock(tty);
        mutex_unlock(&tty_mutex);
        return 0;
 err_unlock:
-       tty_unlock();
        mutex_unlock(&tty_mutex);
        /* after locks to avoid deadlock */
        if (!IS_ERR_OR_NULL(driver))
@@ -2094,10 +2105,13 @@ out:
 
 static int tty_fasync(int fd, struct file *filp, int on)
 {
+       struct tty_struct *tty = file_tty(filp);
        int retval;
-       tty_lock();
+
+       tty_lock(tty);
        retval = __tty_fasync(fd, filp, on);
-       tty_unlock();
+       tty_unlock(tty);
+
        return retval;
 }
 
@@ -2934,6 +2948,7 @@ void initialize_tty_struct(struct tty_struct *tty,
        tty->pgrp = NULL;
        tty->overrun_time = jiffies;
        tty_buffer_init(tty);
+       mutex_init(&tty->legacy_mutex);
        mutex_init(&tty->termios_mutex);
        mutex_init(&tty->ldisc_mutex);
        init_waitqueue_head(&tty->write_wait);
@@ -2991,6 +3006,15 @@ EXPORT_SYMBOL_GPL(tty_put_char);
 
 struct class *tty_class;
 
+static int tty_cdev_add(struct tty_driver *driver, dev_t dev,
+               unsigned int index, unsigned int count)
+{
+       /* init here, since reused cdevs cause crashes */
+       cdev_init(&driver->cdevs[index], &tty_fops);
+       driver->cdevs[index].owner = driver->owner;
+       return cdev_add(&driver->cdevs[index], dev, count);
+}
+
 /**
  *     tty_register_device - register a tty device
  *     @driver: the tty driver that describes the tty device
@@ -3013,8 +3037,10 @@ struct class *tty_class;
 struct device *tty_register_device(struct tty_driver *driver, unsigned index,
                                   struct device *device)
 {
+       struct device *ret;
        char name[64];
        dev_t dev = MKDEV(driver->major, driver->minor_start) + index;
+       bool cdev = false;
 
        if (index >= driver->num) {
                printk(KERN_ERR "Attempt to register invalid tty line number "
@@ -3027,7 +3053,18 @@ struct device *tty_register_device(struct tty_driver *driver, unsigned index,
        else
                tty_line_name(driver, index, name);
 
-       return device_create(tty_class, device, dev, NULL, name);
+       if (!(driver->flags & TTY_DRIVER_DYNAMIC_ALLOC)) {
+               int error = tty_cdev_add(driver, dev, index, 1);
+               if (error)
+                       return ERR_PTR(error);
+               cdev = true;
+       }
+
+       ret = device_create(tty_class, device, dev, NULL, name);
+       if (IS_ERR(ret) && cdev)
+               cdev_del(&driver->cdevs[index]);
+
+       return ret;
 }
 EXPORT_SYMBOL(tty_register_device);
 
@@ -3046,31 +3083,82 @@ void tty_unregister_device(struct tty_driver *driver, unsigned index)
 {
        device_destroy(tty_class,
                MKDEV(driver->major, driver->minor_start) + index);
+       if (!(driver->flags & TTY_DRIVER_DYNAMIC_ALLOC))
+               cdev_del(&driver->cdevs[index]);
 }
 EXPORT_SYMBOL(tty_unregister_device);
 
-struct tty_driver *__alloc_tty_driver(int lines, struct module *owner)
+/**
+ * __tty_alloc_driver -- allocate tty driver
+ * @lines: count of lines this driver can handle at most
+ * @owner: module which is repsonsible for this driver
+ * @flags: some of TTY_DRIVER_* flags, will be set in driver->flags
+ *
+ * This should not be called directly, some of the provided macros should be
+ * used instead. Use IS_ERR and friends on @retval.
+ */
+struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner,
+               unsigned long flags)
 {
        struct tty_driver *driver;
+       unsigned int cdevs = 1;
+       int err;
+
+       if (!lines || (flags & TTY_DRIVER_UNNUMBERED_NODE && lines > 1))
+               return ERR_PTR(-EINVAL);
 
        driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL);
-       if (driver) {
-               kref_init(&driver->kref);
-               driver->magic = TTY_DRIVER_MAGIC;
-               driver->num = lines;
-               driver->owner = owner;
-               /* later we'll move allocation of tables here */
+       if (!driver)
+               return ERR_PTR(-ENOMEM);
+
+       kref_init(&driver->kref);
+       driver->magic = TTY_DRIVER_MAGIC;
+       driver->num = lines;
+       driver->owner = owner;
+       driver->flags = flags;
+
+       if (!(flags & TTY_DRIVER_DEVPTS_MEM)) {
+               driver->ttys = kcalloc(lines, sizeof(*driver->ttys),
+                               GFP_KERNEL);
+               driver->termios = kcalloc(lines, sizeof(*driver->termios),
+                               GFP_KERNEL);
+               if (!driver->ttys || !driver->termios) {
+                       err = -ENOMEM;
+                       goto err_free_all;
+               }
+       }
+
+       if (!(flags & TTY_DRIVER_DYNAMIC_ALLOC)) {
+               driver->ports = kcalloc(lines, sizeof(*driver->ports),
+                               GFP_KERNEL);
+               if (!driver->ports) {
+                       err = -ENOMEM;
+                       goto err_free_all;
+               }
+               cdevs = lines;
        }
+
+       driver->cdevs = kcalloc(cdevs, sizeof(*driver->cdevs), GFP_KERNEL);
+       if (!driver->cdevs) {
+               err = -ENOMEM;
+               goto err_free_all;
+       }
+
        return driver;
+err_free_all:
+       kfree(driver->ports);
+       kfree(driver->ttys);
+       kfree(driver->termios);
+       kfree(driver);
+       return ERR_PTR(err);
 }
-EXPORT_SYMBOL(__alloc_tty_driver);
+EXPORT_SYMBOL(__tty_alloc_driver);
 
 static void destruct_tty_driver(struct kref *kref)
 {
        struct tty_driver *driver = container_of(kref, struct tty_driver, kref);
        int i;
        struct ktermios *tp;
-       void *p;
 
        if (driver->flags & TTY_DRIVER_INSTALLED) {
                /*
@@ -3087,13 +3175,14 @@ static void destruct_tty_driver(struct kref *kref)
                        if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV))
                                tty_unregister_device(driver, i);
                }
-               p = driver->ttys;
                proc_tty_unregister_driver(driver);
-               driver->ttys = NULL;
-               driver->termios = NULL;
-               kfree(p);
-               cdev_del(&driver->cdev);
+               if (driver->flags & TTY_DRIVER_DYNAMIC_ALLOC)
+                       cdev_del(&driver->cdevs[0]);
        }
+       kfree(driver->cdevs);
+       kfree(driver->ports);
+       kfree(driver->termios);
+       kfree(driver->ttys);
        kfree(driver);
 }
 
@@ -3124,15 +3213,8 @@ int tty_register_driver(struct tty_driver *driver)
        int error;
        int i;
        dev_t dev;
-       void **p = NULL;
        struct device *d;
 
-       if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {
-               p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL);
-               if (!p)
-                       return -ENOMEM;
-       }
-
        if (!driver->major) {
                error = alloc_chrdev_region(&dev, driver->minor_start,
                                                driver->num, driver->name);
@@ -3144,28 +3226,13 @@ int tty_register_driver(struct tty_driver *driver)
                dev = MKDEV(driver->major, driver->minor_start);
                error = register_chrdev_region(dev, driver->num, driver->name);
        }
-       if (error < 0) {
-               kfree(p);
-               return error;
-       }
+       if (error < 0)
+               goto err;
 
-       if (p) {
-               driver->ttys = (struct tty_struct **)p;
-               driver->termios = (struct ktermios **)(p + driver->num);
-       } else {
-               driver->ttys = NULL;
-               driver->termios = NULL;
-       }
-
-       cdev_init(&driver->cdev, &tty_fops);
-       driver->cdev.owner = driver->owner;
-       error = cdev_add(&driver->cdev, dev, driver->num);
-       if (error) {
-               unregister_chrdev_region(dev, driver->num);
-               driver->ttys = NULL;
-               driver->termios = NULL;
-               kfree(p);
-               return error;
+       if (driver->flags & TTY_DRIVER_DYNAMIC_ALLOC) {
+               error = tty_cdev_add(driver, dev, 0, driver->num);
+               if (error)
+                       goto err_unreg_char;
        }
 
        mutex_lock(&tty_mutex);
@@ -3177,7 +3244,7 @@ int tty_register_driver(struct tty_driver *driver)
                        d = tty_register_device(driver, i, NULL);
                        if (IS_ERR(d)) {
                                error = PTR_ERR(d);
-                               goto err;
+                               goto err_unreg_devs;
                        }
                }
        }
@@ -3185,7 +3252,7 @@ int tty_register_driver(struct tty_driver *driver)
        driver->flags |= TTY_DRIVER_INSTALLED;
        return 0;
 
-err:
+err_unreg_devs:
        for (i--; i >= 0; i--)
                tty_unregister_device(driver, i);
 
@@ -3193,13 +3260,11 @@ err:
        list_del(&driver->tty_drivers);
        mutex_unlock(&tty_mutex);
 
+err_unreg_char:
        unregister_chrdev_region(dev, driver->num);
-       driver->ttys = NULL;
-       driver->termios = NULL;
-       kfree(p);
+err:
        return error;
 }
-
 EXPORT_SYMBOL(tty_register_driver);
 
 /*
index a1b9a2f68567e2755871280c555f8a4f52168eb6..12b1fa0f4f867ed014d7a96eac79ccae76053c6d 100644 (file)
@@ -410,7 +410,7 @@ EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate);
 
 void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud)
 {
-       tty_termios_encode_baud_rate(tty->termios, ibaud, obaud);
+       tty_termios_encode_baud_rate(&tty->termios, ibaud, obaud);
 }
 EXPORT_SYMBOL_GPL(tty_encode_baud_rate);
 
@@ -427,7 +427,7 @@ EXPORT_SYMBOL_GPL(tty_encode_baud_rate);
 
 speed_t tty_get_baud_rate(struct tty_struct *tty)
 {
-       speed_t baud = tty_termios_baud_rate(tty->termios);
+       speed_t baud = tty_termios_baud_rate(&tty->termios);
 
        if (baud == 38400 && tty->alt_speed) {
                if (!tty->warned) {
@@ -509,14 +509,14 @@ int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
        /* FIXME: we need to decide on some locking/ordering semantics
           for the set_termios notification eventually */
        mutex_lock(&tty->termios_mutex);
-       old_termios = *tty->termios;
-       *tty->termios = *new_termios;
-       unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
+       old_termios = tty->termios;
+       tty->termios = *new_termios;
+       unset_locked_termios(&tty->termios, &old_termios, &tty->termios_locked);
 
        /* See if packet mode change of state. */
        if (tty->link && tty->link->packet) {
                int extproc = (old_termios.c_lflag & EXTPROC) |
-                               (tty->termios->c_lflag & EXTPROC);
+                               (tty->termios.c_lflag & EXTPROC);
                int old_flow = ((old_termios.c_iflag & IXON) &&
                                (old_termios.c_cc[VSTOP] == '\023') &&
                                (old_termios.c_cc[VSTART] == '\021'));
@@ -542,7 +542,7 @@ int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
        if (tty->ops->set_termios)
                (*tty->ops->set_termios)(tty, &old_termios);
        else
-               tty_termios_copy_hw(tty->termios, &old_termios);
+               tty_termios_copy_hw(&tty->termios, &old_termios);
 
        ld = tty_ldisc_ref(tty);
        if (ld != NULL) {
@@ -578,7 +578,7 @@ static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
                return retval;
 
        mutex_lock(&tty->termios_mutex);
-       memcpy(&tmp_termios, tty->termios, sizeof(struct ktermios));
+       tmp_termios = tty->termios;
        mutex_unlock(&tty->termios_mutex);
 
        if (opt & TERMIOS_TERMIO) {
@@ -632,14 +632,14 @@ static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
 static void copy_termios(struct tty_struct *tty, struct ktermios *kterm)
 {
        mutex_lock(&tty->termios_mutex);
-       memcpy(kterm, tty->termios, sizeof(struct ktermios));
+       *kterm = tty->termios;
        mutex_unlock(&tty->termios_mutex);
 }
 
 static void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm)
 {
        mutex_lock(&tty->termios_mutex);
-       memcpy(kterm, tty->termios_locked, sizeof(struct ktermios));
+       *kterm = tty->termios_locked;
        mutex_unlock(&tty->termios_mutex);
 }
 
@@ -707,16 +707,16 @@ static int get_sgflags(struct tty_struct *tty)
 {
        int flags = 0;
 
-       if (!(tty->termios->c_lflag & ICANON)) {
-               if (tty->termios->c_lflag & ISIG)
+       if (!(tty->termios.c_lflag & ICANON)) {
+               if (tty->termios.c_lflag & ISIG)
                        flags |= 0x02;          /* cbreak */
                else
                        flags |= 0x20;          /* raw */
        }
-       if (tty->termios->c_lflag & ECHO)
+       if (tty->termios.c_lflag & ECHO)
                flags |= 0x08;                  /* echo */
-       if (tty->termios->c_oflag & OPOST)
-               if (tty->termios->c_oflag & ONLCR)
+       if (tty->termios.c_oflag & OPOST)
+               if (tty->termios.c_oflag & ONLCR)
                        flags |= 0x10;          /* crmod */
        return flags;
 }
@@ -726,10 +726,10 @@ static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
        struct sgttyb tmp;
 
        mutex_lock(&tty->termios_mutex);
-       tmp.sg_ispeed = tty->termios->c_ispeed;
-       tmp.sg_ospeed = tty->termios->c_ospeed;
-       tmp.sg_erase = tty->termios->c_cc[VERASE];
-       tmp.sg_kill = tty->termios->c_cc[VKILL];
+       tmp.sg_ispeed = tty->termios.c_ispeed;
+       tmp.sg_ospeed = tty->termios.c_ospeed;
+       tmp.sg_erase = tty->termios.c_cc[VERASE];
+       tmp.sg_kill = tty->termios.c_cc[VKILL];
        tmp.sg_flags = get_sgflags(tty);
        mutex_unlock(&tty->termios_mutex);
 
@@ -787,7 +787,7 @@ static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb)
                return -EFAULT;
 
        mutex_lock(&tty->termios_mutex);
-       termios = *tty->termios;
+       termios = tty->termios;
        termios.c_cc[VERASE] = tmp.sg_erase;
        termios.c_cc[VKILL] = tmp.sg_kill;
        set_sgflags(&termios, tmp.sg_flags);
@@ -808,12 +808,12 @@ static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars)
        struct tchars tmp;
 
        mutex_lock(&tty->termios_mutex);
-       tmp.t_intrc = tty->termios->c_cc[VINTR];
-       tmp.t_quitc = tty->termios->c_cc[VQUIT];
-       tmp.t_startc = tty->termios->c_cc[VSTART];
-       tmp.t_stopc = tty->termios->c_cc[VSTOP];
-       tmp.t_eofc = tty->termios->c_cc[VEOF];
-       tmp.t_brkc = tty->termios->c_cc[VEOL2]; /* what is brkc anyway? */
+       tmp.t_intrc = tty->termios.c_cc[VINTR];
+       tmp.t_quitc = tty->termios.c_cc[VQUIT];
+       tmp.t_startc = tty->termios.c_cc[VSTART];
+       tmp.t_stopc = tty->termios.c_cc[VSTOP];
+       tmp.t_eofc = tty->termios.c_cc[VEOF];
+       tmp.t_brkc = tty->termios.c_cc[VEOL2];  /* what is brkc anyway? */
        mutex_unlock(&tty->termios_mutex);
        return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
 }
@@ -825,12 +825,12 @@ static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars)
        if (copy_from_user(&tmp, tchars, sizeof(tmp)))
                return -EFAULT;
        mutex_lock(&tty->termios_mutex);
-       tty->termios->c_cc[VINTR] = tmp.t_intrc;
-       tty->termios->c_cc[VQUIT] = tmp.t_quitc;
-       tty->termios->c_cc[VSTART] = tmp.t_startc;
-       tty->termios->c_cc[VSTOP] = tmp.t_stopc;
-       tty->termios->c_cc[VEOF] = tmp.t_eofc;
-       tty->termios->c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */
+       tty->termios.c_cc[VINTR] = tmp.t_intrc;
+       tty->termios.c_cc[VQUIT] = tmp.t_quitc;
+       tty->termios.c_cc[VSTART] = tmp.t_startc;
+       tty->termios.c_cc[VSTOP] = tmp.t_stopc;
+       tty->termios.c_cc[VEOF] = tmp.t_eofc;
+       tty->termios.c_cc[VEOL2] = tmp.t_brkc;  /* what is brkc anyway? */
        mutex_unlock(&tty->termios_mutex);
        return 0;
 }
@@ -842,14 +842,14 @@ static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
        struct ltchars tmp;
 
        mutex_lock(&tty->termios_mutex);
-       tmp.t_suspc = tty->termios->c_cc[VSUSP];
+       tmp.t_suspc = tty->termios.c_cc[VSUSP];
        /* what is dsuspc anyway? */
-       tmp.t_dsuspc = tty->termios->c_cc[VSUSP];
-       tmp.t_rprntc = tty->termios->c_cc[VREPRINT];
+       tmp.t_dsuspc = tty->termios.c_cc[VSUSP];
+       tmp.t_rprntc = tty->termios.c_cc[VREPRINT];
        /* what is flushc anyway? */
-       tmp.t_flushc = tty->termios->c_cc[VEOL2];
-       tmp.t_werasc = tty->termios->c_cc[VWERASE];
-       tmp.t_lnextc = tty->termios->c_cc[VLNEXT];
+       tmp.t_flushc = tty->termios.c_cc[VEOL2];
+       tmp.t_werasc = tty->termios.c_cc[VWERASE];
+       tmp.t_lnextc = tty->termios.c_cc[VLNEXT];
        mutex_unlock(&tty->termios_mutex);
        return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
 }
@@ -862,14 +862,14 @@ static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars)
                return -EFAULT;
 
        mutex_lock(&tty->termios_mutex);
-       tty->termios->c_cc[VSUSP] = tmp.t_suspc;
+       tty->termios.c_cc[VSUSP] = tmp.t_suspc;
        /* what is dsuspc anyway? */
-       tty->termios->c_cc[VEOL2] = tmp.t_dsuspc;
-       tty->termios->c_cc[VREPRINT] = tmp.t_rprntc;
+       tty->termios.c_cc[VEOL2] = tmp.t_dsuspc;
+       tty->termios.c_cc[VREPRINT] = tmp.t_rprntc;
        /* what is flushc anyway? */
-       tty->termios->c_cc[VEOL2] = tmp.t_flushc;
-       tty->termios->c_cc[VWERASE] = tmp.t_werasc;
-       tty->termios->c_cc[VLNEXT] = tmp.t_lnextc;
+       tty->termios.c_cc[VEOL2] = tmp.t_flushc;
+       tty->termios.c_cc[VWERASE] = tmp.t_werasc;
+       tty->termios.c_cc[VLNEXT] = tmp.t_lnextc;
        mutex_unlock(&tty->termios_mutex);
        return 0;
 }
@@ -920,12 +920,12 @@ static int tty_change_softcar(struct tty_struct *tty, int arg)
        struct ktermios old;
 
        mutex_lock(&tty->termios_mutex);
-       old = *tty->termios;
-       tty->termios->c_cflag &= ~CLOCAL;
-       tty->termios->c_cflag |= bit;
+       old = tty->termios;
+       tty->termios.c_cflag &= ~CLOCAL;
+       tty->termios.c_cflag |= bit;
        if (tty->ops->set_termios)
                tty->ops->set_termios(tty, &old);
-       if ((tty->termios->c_cflag & CLOCAL) != bit)
+       if ((tty->termios.c_cflag & CLOCAL) != bit)
                ret = -EINVAL;
        mutex_unlock(&tty->termios_mutex);
        return ret;
@@ -1031,7 +1031,7 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
                                               (struct termios __user *) arg))
                        return -EFAULT;
                mutex_lock(&real_tty->termios_mutex);
-               memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios));
+               real_tty->termios_locked = kterm;
                mutex_unlock(&real_tty->termios_mutex);
                return 0;
 #else
@@ -1048,7 +1048,7 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
                                               (struct termios __user *) arg))
                        return -EFAULT;
                mutex_lock(&real_tty->termios_mutex);
-               memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios));
+               real_tty->termios_locked = kterm;
                mutex_unlock(&real_tty->termios_mutex);
                return ret;
 #endif
index 6f99c9959f0c8f5db9c950810a8196e0907415b2..4d7b56268c79408a35b2a3990990778b9359f071 100644 (file)
@@ -413,7 +413,7 @@ EXPORT_SYMBOL_GPL(tty_ldisc_flush);
 static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
 {
        mutex_lock(&tty->termios_mutex);
-       tty->termios->c_line = num;
+       tty->termios.c_line = num;
        mutex_unlock(&tty->termios_mutex);
 }
 
@@ -568,7 +568,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
        if (IS_ERR(new_ldisc))
                return PTR_ERR(new_ldisc);
 
-       tty_lock();
+       tty_lock(tty);
        /*
         *      We need to look at the tty locking here for pty/tty pairs
         *      when both sides try to change in parallel.
@@ -582,12 +582,12 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
         */
 
        if (tty->ldisc->ops->num == ldisc) {
-               tty_unlock();
+               tty_unlock(tty);
                tty_ldisc_put(new_ldisc);
                return 0;
        }
 
-       tty_unlock();
+       tty_unlock(tty);
        /*
         *      Problem: What do we do if this blocks ?
         *      We could deadlock here
@@ -595,7 +595,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 
        tty_wait_until_sent(tty, 0);
 
-       tty_lock();
+       tty_lock(tty);
        mutex_lock(&tty->ldisc_mutex);
 
        /*
@@ -605,10 +605,10 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 
        while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) {
                mutex_unlock(&tty->ldisc_mutex);
-               tty_unlock();
+               tty_unlock(tty);
                wait_event(tty_ldisc_wait,
                        test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0);
-               tty_lock();
+               tty_lock(tty);
                mutex_lock(&tty->ldisc_mutex);
        }
 
@@ -623,7 +623,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 
        o_ldisc = tty->ldisc;
 
-       tty_unlock();
+       tty_unlock(tty);
        /*
         *      Make sure we don't change while someone holds a
         *      reference to the line discipline. The TTY_LDISC bit
@@ -650,7 +650,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 
        retval = tty_ldisc_wait_idle(tty, 5 * HZ);
 
-       tty_lock();
+       tty_lock(tty);
        mutex_lock(&tty->ldisc_mutex);
 
        /* handle wait idle failure locked */
@@ -665,7 +665,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
                clear_bit(TTY_LDISC_CHANGING, &tty->flags);
                mutex_unlock(&tty->ldisc_mutex);
                tty_ldisc_put(new_ldisc);
-               tty_unlock();
+               tty_unlock(tty);
                return -EIO;
        }
 
@@ -708,7 +708,7 @@ enable:
        if (o_work)
                schedule_work(&o_tty->buf.work);
        mutex_unlock(&tty->ldisc_mutex);
-       tty_unlock();
+       tty_unlock(tty);
        return retval;
 }
 
@@ -722,9 +722,9 @@ enable:
 static void tty_reset_termios(struct tty_struct *tty)
 {
        mutex_lock(&tty->termios_mutex);
-       *tty->termios = tty->driver->init_termios;
-       tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
-       tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
+       tty->termios = tty->driver->init_termios;
+       tty->termios.c_ispeed = tty_termios_input_baud_rate(&tty->termios);
+       tty->termios.c_ospeed = tty_termios_baud_rate(&tty->termios);
        mutex_unlock(&tty->termios_mutex);
 }
 
@@ -816,11 +816,11 @@ void tty_ldisc_hangup(struct tty_struct *tty)
         * need to wait for another function taking the BTM
         */
        clear_bit(TTY_LDISC, &tty->flags);
-       tty_unlock();
+       tty_unlock(tty);
        cancel_work_sync(&tty->buf.work);
        mutex_unlock(&tty->ldisc_mutex);
 retry:
-       tty_lock();
+       tty_lock(tty);
        mutex_lock(&tty->ldisc_mutex);
 
        /* At this point we have a closed ldisc and we want to
@@ -831,7 +831,7 @@ retry:
                if (atomic_read(&tty->ldisc->users) != 1) {
                        char cur_n[TASK_COMM_LEN], tty_n[64];
                        long timeout = 3 * HZ;
-                       tty_unlock();
+                       tty_unlock(tty);
 
                        while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) {
                                timeout = MAX_SCHEDULE_TIMEOUT;
@@ -846,7 +846,7 @@ retry:
 
                if (reset == 0) {
 
-                       if (!tty_ldisc_reinit(tty, tty->termios->c_line))
+                       if (!tty_ldisc_reinit(tty, tty->termios.c_line))
                                err = tty_ldisc_open(tty, tty->ldisc);
                        else
                                err = 1;
@@ -894,6 +894,23 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
        tty_ldisc_enable(tty);
        return 0;
 }
+
+static void tty_ldisc_kill(struct tty_struct *tty)
+{
+       mutex_lock(&tty->ldisc_mutex);
+       /*
+        * Now kill off the ldisc
+        */
+       tty_ldisc_close(tty, tty->ldisc);
+       tty_ldisc_put(tty->ldisc);
+       /* Force an oops if we mess this up */
+       tty->ldisc = NULL;
+
+       /* Ensure the next open requests the N_TTY ldisc */
+       tty_set_termios_ldisc(tty, N_TTY);
+       mutex_unlock(&tty->ldisc_mutex);
+}
+
 /**
  *     tty_ldisc_release               -       release line discipline
  *     @tty: tty being shut down
@@ -912,28 +929,21 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
         * race with the set_ldisc code path.
         */
 
-       tty_unlock();
+       tty_lock_pair(tty, o_tty);
        tty_ldisc_halt(tty);
        tty_ldisc_flush_works(tty);
-       tty_lock();
-
-       mutex_lock(&tty->ldisc_mutex);
-       /*
-        * Now kill off the ldisc
-        */
-       tty_ldisc_close(tty, tty->ldisc);
-       tty_ldisc_put(tty->ldisc);
-       /* Force an oops if we mess this up */
-       tty->ldisc = NULL;
-
-       /* Ensure the next open requests the N_TTY ldisc */
-       tty_set_termios_ldisc(tty, N_TTY);
-       mutex_unlock(&tty->ldisc_mutex);
+       if (o_tty) {
+               tty_ldisc_halt(o_tty);
+               tty_ldisc_flush_works(o_tty);
+       }
 
        /* This will need doing differently if we need to lock */
+       tty_ldisc_kill(tty);
+
        if (o_tty)
-               tty_ldisc_release(o_tty, NULL);
+               tty_ldisc_kill(o_tty);
 
+       tty_unlock_pair(tty, o_tty);
        /* And the memory resources remaining (buffers, termios) will be
           disposed of when the kref hits zero */
 }
index 9ff986c32a21ef702edf515a79c19440a504b747..67feac9e6ebbef7e224c47672bff95f7f511c5a2 100644 (file)
@@ -4,29 +4,70 @@
 #include <linux/semaphore.h>
 #include <linux/sched.h>
 
-/*
- * The 'big tty mutex'
- *
- * This mutex is taken and released by tty_lock() and tty_unlock(),
- * replacing the older big kernel lock.
- * It can no longer be taken recursively, and does not get
- * released implicitly while sleeping.
- *
- * Don't use in new code.
- */
-static DEFINE_MUTEX(big_tty_mutex);
+/* Legacy tty mutex glue */
+
+enum {
+       TTY_MUTEX_NORMAL,
+       TTY_MUTEX_NESTED,
+};
 
 /*
  * Getting the big tty mutex.
  */
-void __lockfunc tty_lock(void)
+
+static void __lockfunc tty_lock_nested(struct tty_struct *tty,
+                                      unsigned int subclass)
 {
-       mutex_lock(&big_tty_mutex);
+       if (tty->magic != TTY_MAGIC) {
+               printk(KERN_ERR "L Bad %p\n", tty);
+               WARN_ON(1);
+               return;
+       }
+       tty_kref_get(tty);
+       mutex_lock_nested(&tty->legacy_mutex, subclass);
+}
+
+void __lockfunc tty_lock(struct tty_struct *tty)
+{
+       return tty_lock_nested(tty, TTY_MUTEX_NORMAL);
 }
 EXPORT_SYMBOL(tty_lock);
 
-void __lockfunc tty_unlock(void)
+void __lockfunc tty_unlock(struct tty_struct *tty)
 {
-       mutex_unlock(&big_tty_mutex);
+       if (tty->magic != TTY_MAGIC) {
+               printk(KERN_ERR "U Bad %p\n", tty);
+               WARN_ON(1);
+               return;
+       }
+       mutex_unlock(&tty->legacy_mutex);
+       tty_kref_put(tty);
 }
 EXPORT_SYMBOL(tty_unlock);
+
+/*
+ * Getting the big tty mutex for a pair of ttys with lock ordering
+ * On a non pty/tty pair tty2 can be NULL which is just fine.
+ */
+void __lockfunc tty_lock_pair(struct tty_struct *tty,
+                                       struct tty_struct *tty2)
+{
+       if (tty < tty2) {
+               tty_lock(tty);
+               tty_lock_nested(tty2, TTY_MUTEX_NESTED);
+       } else {
+               if (tty2 && tty2 != tty)
+                       tty_lock(tty2);
+               tty_lock_nested(tty, TTY_MUTEX_NESTED);
+       }
+}
+EXPORT_SYMBOL(tty_lock_pair);
+
+void __lockfunc tty_unlock_pair(struct tty_struct *tty,
+                                               struct tty_struct *tty2)
+{
+       tty_unlock(tty);
+       if (tty2 && tty2 != tty)
+               tty_unlock(tty2);
+}
+EXPORT_SYMBOL(tty_unlock_pair);
index bf6e238146ae40acd4ac8ea2f517574870366590..96302f4c707984f34f1530a91452144b7008c86f 100644 (file)
@@ -33,6 +33,46 @@ void tty_port_init(struct tty_port *port)
 }
 EXPORT_SYMBOL(tty_port_init);
 
+/**
+ * tty_port_link_device - link tty and tty_port
+ * @port: tty_port of the device
+ * @driver: tty_driver for this device
+ * @index: index of the tty
+ *
+ * Provide the tty layer wit ha link from a tty (specified by @index) to a
+ * tty_port (@port). Use this only if neither tty_port_register_device nor
+ * tty_port_install is used in the driver. If used, this has to be called before
+ * tty_register_driver.
+ */
+void tty_port_link_device(struct tty_port *port,
+               struct tty_driver *driver, unsigned index)
+{
+       if (WARN_ON(index >= driver->num))
+               return;
+       driver->ports[index] = port;
+}
+EXPORT_SYMBOL_GPL(tty_port_link_device);
+
+/**
+ * tty_port_register_device - register tty device
+ * @port: tty_port of the device
+ * @driver: tty_driver for this device
+ * @index: index of the tty
+ * @device: parent if exists, otherwise NULL
+ *
+ * It is the same as tty_register_device except the provided @port is linked to
+ * a concrete tty specified by @index. Use this or tty_port_install (or both).
+ * Call tty_port_link_device as a last resort.
+ */
+struct device *tty_port_register_device(struct tty_port *port,
+               struct tty_driver *driver, unsigned index,
+               struct device *device)
+{
+       tty_port_link_device(port, driver, index);
+       return tty_register_device(driver, index, device);
+}
+EXPORT_SYMBOL_GPL(tty_port_register_device);
+
 int tty_port_alloc_xmit_buf(struct tty_port *port)
 {
        /* We may sleep in get_zeroed_page() */
@@ -230,7 +270,7 @@ int tty_port_block_til_ready(struct tty_port *port,
 
        /* block if port is in the process of being closed */
        if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
-               wait_event_interruptible_tty(port->close_wait,
+               wait_event_interruptible_tty(tty, port->close_wait,
                                !(port->flags & ASYNC_CLOSING));
                if (port->flags & ASYNC_HUP_NOTIFY)
                        return -EAGAIN;
@@ -246,7 +286,7 @@ int tty_port_block_til_ready(struct tty_port *port,
        }
        if (filp->f_flags & O_NONBLOCK) {
                /* Indicate we are open */
-               if (tty->termios->c_cflag & CBAUD)
+               if (tty->termios.c_cflag & CBAUD)
                        tty_port_raise_dtr_rts(port);
                port->flags |= ASYNC_NORMAL_ACTIVE;
                return 0;
@@ -270,7 +310,7 @@ int tty_port_block_til_ready(struct tty_port *port,
 
        while (1) {
                /* Indicate we are open */
-               if (tty->termios->c_cflag & CBAUD)
+               if (tty->termios.c_cflag & CBAUD)
                        tty_port_raise_dtr_rts(port);
 
                prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
@@ -296,9 +336,9 @@ int tty_port_block_til_ready(struct tty_port *port,
                        retval = -ERESTARTSYS;
                        break;
                }
-               tty_unlock();
+               tty_unlock(tty);
                schedule();
-               tty_lock();
+               tty_lock(tty);
        }
        finish_wait(&port->open_wait, &wait);
 
@@ -369,7 +409,7 @@ int tty_port_close_start(struct tty_port *port,
 
        /* Drop DTR/RTS if HUPCL is set. This causes any attached modem to
           hang up the line */
-       if (tty->termios->c_cflag & HUPCL)
+       if (tty->termios.c_cflag & HUPCL)
                tty_port_lower_dtr_rts(port);
 
        /* Don't call port->drop for the last reference. Callers will want
@@ -413,6 +453,24 @@ void tty_port_close(struct tty_port *port, struct tty_struct *tty,
 }
 EXPORT_SYMBOL(tty_port_close);
 
+/**
+ * tty_port_install - generic tty->ops->install handler
+ * @port: tty_port of the device
+ * @driver: tty_driver for this device
+ * @tty: tty to be installed
+ *
+ * It is the same as tty_standard_install except the provided @port is linked
+ * to a concrete tty specified by @tty. Use this or tty_port_register_device
+ * (or both). Call tty_port_link_device as a last resort.
+ */
+int tty_port_install(struct tty_port *port, struct tty_driver *driver,
+               struct tty_struct *tty)
+{
+       tty->port = port;
+       return tty_standard_install(driver, tty);
+}
+EXPORT_SYMBOL_GPL(tty_port_install);
+
 int tty_port_open(struct tty_port *port, struct tty_struct *tty,
                                                        struct file *filp)
 {
index 48cc6f25cfd39c319cea40e5d70232ca39c3c964..681765baef69345f568ce29bce068601b812db56 100644 (file)
@@ -119,6 +119,7 @@ static const int NR_TYPES = ARRAY_SIZE(max_vals);
 
 static struct input_handler kbd_handler;
 static DEFINE_SPINLOCK(kbd_event_lock);
+static DEFINE_SPINLOCK(led_lock);
 static unsigned long key_down[BITS_TO_LONGS(KEY_CNT)]; /* keyboard key bitmap */
 static unsigned char shift_down[NR_SHIFT];             /* shift state counters.. */
 static bool dead_key_next;
@@ -310,7 +311,7 @@ static void put_queue(struct vc_data *vc, int ch)
 
        if (tty) {
                tty_insert_flip_char(tty, ch, 0);
-               con_schedule_flip(tty);
+               tty_schedule_flip(tty);
        }
 }
 
@@ -325,7 +326,7 @@ static void puts_queue(struct vc_data *vc, char *cp)
                tty_insert_flip_char(tty, *cp, 0);
                cp++;
        }
-       con_schedule_flip(tty);
+       tty_schedule_flip(tty);
 }
 
 static void applkey(struct vc_data *vc, int key, char mode)
@@ -586,7 +587,7 @@ static void fn_send_intr(struct vc_data *vc)
        if (!tty)
                return;
        tty_insert_flip_char(tty, 0, TTY_BREAK);
-       con_schedule_flip(tty);
+       tty_schedule_flip(tty);
 }
 
 static void fn_scroll_forw(struct vc_data *vc)
@@ -984,7 +985,7 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag)
  * or (ii) whatever pattern of lights people want to show using KDSETLED,
  * or (iii) specified bits of specified words in kernel memory.
  */
-unsigned char getledstate(void)
+static unsigned char getledstate(void)
 {
        return ledstate;
 }
@@ -992,7 +993,7 @@ unsigned char getledstate(void)
 void setledstate(struct kbd_struct *kbd, unsigned int led)
 {
         unsigned long flags;
-        spin_lock_irqsave(&kbd_event_lock, flags);
+        spin_lock_irqsave(&led_lock, flags);
        if (!(led & ~7)) {
                ledioctl = led;
                kbd->ledmode = LED_SHOW_IOCTL;
@@ -1000,7 +1001,7 @@ void setledstate(struct kbd_struct *kbd, unsigned int led)
                kbd->ledmode = LED_SHOW_FLAGS;
 
        set_leds();
-       spin_unlock_irqrestore(&kbd_event_lock, flags);
+       spin_unlock_irqrestore(&led_lock, flags);
 }
 
 static inline unsigned char getleds(void)
@@ -1049,13 +1050,13 @@ static int kbd_update_leds_helper(struct input_handle *handle, void *data)
  */
 int vt_get_leds(int console, int flag)
 {
-       unsigned long flags;
        struct kbd_struct * kbd = kbd_table + console;
        int ret;
+       unsigned long flags;
 
-       spin_lock_irqsave(&kbd_event_lock, flags);
+       spin_lock_irqsave(&led_lock, flags);
        ret = vc_kbd_led(kbd, flag);
-       spin_unlock_irqrestore(&kbd_event_lock, flags);
+       spin_unlock_irqrestore(&led_lock, flags);
 
        return ret;
 }
@@ -1091,11 +1092,11 @@ void vt_set_led_state(int console, int leds)
 void vt_kbd_con_start(int console)
 {
        struct kbd_struct * kbd = kbd_table + console;
-/*     unsigned long flags; */
-/*     spin_lock_irqsave(&kbd_event_lock, flags); */
+       unsigned long flags;
+       spin_lock_irqsave(&led_lock, flags);
        clr_vc_kbd_led(kbd, VC_SCROLLOCK);
        set_leds();
-/*     spin_unlock_irqrestore(&kbd_event_lock, flags); */
+       spin_unlock_irqrestore(&led_lock, flags);
 }
 
 /**
@@ -1104,21 +1105,15 @@ void vt_kbd_con_start(int console)
  *
  *     Handle console stop. This is a wrapper for the VT layer
  *     so that we can keep kbd knowledge internal
- *
- *     FIXME: We eventually need to hold the kbd lock here to protect
- *     the LED updating. We can't do it yet because fn_hold calls stop_tty
- *     and start_tty under the kbd_event_lock, while normal tty paths
- *     don't hold the lock. We probably need to split out an LED lock
- *     but not during an -rc release!
  */
 void vt_kbd_con_stop(int console)
 {
        struct kbd_struct * kbd = kbd_table + console;
-/*     unsigned long flags; */
-/*     spin_lock_irqsave(&kbd_event_lock, flags); */
+       unsigned long flags;
+       spin_lock_irqsave(&led_lock, flags);
        set_vc_kbd_led(kbd, VC_SCROLLOCK);
        set_leds();
-/*     spin_unlock_irqrestore(&kbd_event_lock, flags); */
+       spin_unlock_irqrestore(&led_lock, flags);
 }
 
 /*
@@ -1130,7 +1125,12 @@ void vt_kbd_con_stop(int console)
  */
 static void kbd_bh(unsigned long dummy)
 {
-       unsigned char leds = getleds();
+       unsigned char leds;
+       unsigned long flags;
+       
+       spin_lock_irqsave(&led_lock, flags);
+       leds = getleds();
+       spin_unlock_irqrestore(&led_lock, flags);
 
        if (leds != ledstate) {
                input_handler_for_each_handle(&kbd_handler, &leds,
@@ -2035,11 +2035,11 @@ int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm)
                        return -EPERM;
                if (arg & ~0x77)
                        return -EINVAL;
-                spin_lock_irqsave(&kbd_event_lock, flags);
+                spin_lock_irqsave(&led_lock, flags);
                kbd->ledflagstate = (arg & 7);
                kbd->default_ledflagstate = ((arg >> 4) & 7);
                set_leds();
-                spin_unlock_irqrestore(&kbd_event_lock, flags);
+                spin_unlock_irqrestore(&led_lock, flags);
                return 0;
 
        /* the ioctls below only set the lights, not the functions */
@@ -2134,8 +2134,10 @@ void vt_reset_keyboard(int console)
        clr_vc_kbd_mode(kbd, VC_CRLF);
        kbd->lockstate = 0;
        kbd->slockstate = 0;
+       spin_lock(&led_lock);
        kbd->ledmode = LED_SHOW_FLAGS;
        kbd->ledflagstate = kbd->default_ledflagstate;
+       spin_unlock(&led_lock);
        /* do not do set_leds here because this causes an endless tasklet loop
           when the keyboard hasn't been initialized yet */
        spin_unlock_irqrestore(&kbd_event_lock, flags);
index 84cbf298c0947c192b98ead8d71c4362458da459..e07ded30fc7f00b5d5b74d8d8fdb8a3fc64bab0f 100644 (file)
@@ -1380,7 +1380,7 @@ static void respond_string(const char *p, struct tty_struct *tty)
                tty_insert_flip_char(tty, *p, 0);
                p++;
        }
-       con_schedule_flip(tty);
+       tty_schedule_flip(tty);
 }
 
 static void cursor_report(struct vc_data *vc, struct tty_struct *tty)
@@ -2792,41 +2792,52 @@ static void con_flush_chars(struct tty_struct *tty)
 /*
  * Allocate the console screen memory.
  */
-static int con_open(struct tty_struct *tty, struct file *filp)
+static int con_install(struct tty_driver *driver, struct tty_struct *tty)
 {
        unsigned int currcons = tty->index;
-       int ret = 0;
+       struct vc_data *vc;
+       int ret;
 
        console_lock();
-       if (tty->driver_data == NULL) {
-               ret = vc_allocate(currcons);
-               if (ret == 0) {
-                       struct vc_data *vc = vc_cons[currcons].d;
+       ret = vc_allocate(currcons);
+       if (ret)
+               goto unlock;
 
-                       /* Still being freed */
-                       if (vc->port.tty) {
-                               console_unlock();
-                               return -ERESTARTSYS;
-                       }
-                       tty->driver_data = vc;
-                       vc->port.tty = tty;
+       vc = vc_cons[currcons].d;
 
-                       if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
-                               tty->winsize.ws_row = vc_cons[currcons].d->vc_rows;
-                               tty->winsize.ws_col = vc_cons[currcons].d->vc_cols;
-                       }
-                       if (vc->vc_utf)
-                               tty->termios->c_iflag |= IUTF8;
-                       else
-                               tty->termios->c_iflag &= ~IUTF8;
-                       console_unlock();
-                       return ret;
-               }
+       /* Still being freed */
+       if (vc->port.tty) {
+               ret = -ERESTARTSYS;
+               goto unlock;
        }
+
+       ret = tty_port_install(&vc->port, driver, tty);
+       if (ret)
+               goto unlock;
+
+       tty->driver_data = vc;
+       vc->port.tty = tty;
+
+       if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
+               tty->winsize.ws_row = vc_cons[currcons].d->vc_rows;
+               tty->winsize.ws_col = vc_cons[currcons].d->vc_cols;
+       }
+       if (vc->vc_utf)
+               tty->termios.c_iflag |= IUTF8;
+       else
+               tty->termios.c_iflag &= ~IUTF8;
+unlock:
        console_unlock();
        return ret;
 }
 
+static int con_open(struct tty_struct *tty, struct file *filp)
+{
+       /* everything done in install */
+       return 0;
+}
+
+
 static void con_close(struct tty_struct *tty, struct file *filp)
 {
        /* Nothing to do - we defer to shutdown */
@@ -2839,7 +2850,6 @@ static void con_shutdown(struct tty_struct *tty)
        console_lock();
        vc->port.tty = NULL;
        console_unlock();
-       tty_shutdown(tty);
 }
 
 static int default_italic_color    = 2; // green (ASCII)
@@ -2947,6 +2957,7 @@ static int __init con_init(void)
 console_initcall(con_init);
 
 static const struct tty_operations con_ops = {
+       .install = con_install,
        .open = con_open,
        .close = con_close,
        .write = con_write,
index d7e422dc0ef7d567ea391c13b901d0b222a8e2fc..e1f8b2c973fe1e7df698e918328fd5bc421906e6 100644 (file)
@@ -307,6 +307,34 @@ enum {
 #define FW_GET_BYTE(p) (*((__u8 *) (p)))
 
 #define FW_DIR "ueagle-atm/"
+#define EAGLE_FIRMWARE FW_DIR "eagle.fw"
+#define ADI930_FIRMWARE FW_DIR "adi930.fw"
+#define EAGLE_I_FIRMWARE FW_DIR "eagleI.fw"
+#define EAGLE_II_FIRMWARE FW_DIR "eagleII.fw"
+#define EAGLE_III_FIRMWARE FW_DIR "eagleIII.fw"
+#define EAGLE_IV_FIRMWARE FW_DIR "eagleIV.fw"
+
+#define DSP4I_FIRMWARE FW_DIR "DSP4i.bin"
+#define DSP4P_FIRMWARE FW_DIR "DSP4p.bin"
+#define DSP9I_FIRMWARE FW_DIR "DSP9i.bin"
+#define DSP9P_FIRMWARE FW_DIR "DSP9p.bin"
+#define DSPEI_FIRMWARE FW_DIR "DSPei.bin"
+#define DSPEP_FIRMWARE FW_DIR "DSPep.bin"
+#define FPGA930_FIRMWARE FW_DIR "930-fpga.bin"
+
+#define CMV4P_FIRMWARE FW_DIR "CMV4p.bin"
+#define CMV4PV2_FIRMWARE FW_DIR "CMV4p.bin.v2"
+#define CMV4I_FIRMWARE FW_DIR "CMV4i.bin"
+#define CMV4IV2_FIRMWARE FW_DIR "CMV4i.bin.v2"
+#define CMV9P_FIRMWARE FW_DIR "CMV9p.bin"
+#define CMV9PV2_FIRMWARE FW_DIR "CMV9p.bin.v2"
+#define CMV9I_FIRMWARE FW_DIR "CMV9i.bin"
+#define CMV9IV2_FIRMWARE FW_DIR "CMV9i.bin.v2"
+#define CMVEP_FIRMWARE FW_DIR "CMVep.bin"
+#define CMVEPV2_FIRMWARE FW_DIR "CMVep.bin.v2"
+#define CMVEI_FIRMWARE FW_DIR "CMVei.bin"
+#define CMVEIV2_FIRMWARE FW_DIR "CMVei.bin.v2"
+
 #define UEA_FW_NAME_MAX 30
 #define NB_MODEM 4
 
@@ -694,26 +722,26 @@ err:
 static int uea_load_firmware(struct usb_device *usb, unsigned int ver)
 {
        int ret;
-       char *fw_name = FW_DIR "eagle.fw";
+       char *fw_name = EAGLE_FIRMWARE;
 
        uea_enters(usb);
        uea_info(usb, "pre-firmware device, uploading firmware\n");
 
        switch (ver) {
        case ADI930:
-               fw_name = FW_DIR "adi930.fw";
+               fw_name = ADI930_FIRMWARE;
                break;
        case EAGLE_I:
-               fw_name = FW_DIR "eagleI.fw";
+               fw_name = EAGLE_I_FIRMWARE;
                break;
        case EAGLE_II:
-               fw_name = FW_DIR "eagleII.fw";
+               fw_name = EAGLE_II_FIRMWARE;
                break;
        case EAGLE_III:
-               fw_name = FW_DIR "eagleIII.fw";
+               fw_name = EAGLE_III_FIRMWARE;
                break;
        case EAGLE_IV:
-               fw_name = FW_DIR "eagleIV.fw";
+               fw_name = EAGLE_IV_FIRMWARE;
                break;
        }
 
@@ -869,19 +897,19 @@ static int request_dsp(struct uea_softc *sc)
 
        if (UEA_CHIP_VERSION(sc) == EAGLE_IV) {
                if (IS_ISDN(sc))
-                       dsp_name = FW_DIR "DSP4i.bin";
+                       dsp_name = DSP4I_FIRMWARE;
                else
-                       dsp_name = FW_DIR "DSP4p.bin";
+                       dsp_name = DSP4P_FIRMWARE;
        } else if (UEA_CHIP_VERSION(sc) == ADI930) {
                if (IS_ISDN(sc))
-                       dsp_name = FW_DIR "DSP9i.bin";
+                       dsp_name = DSP9I_FIRMWARE;
                else
-                       dsp_name = FW_DIR "DSP9p.bin";
+                       dsp_name = DSP9P_FIRMWARE;
        } else {
                if (IS_ISDN(sc))
-                       dsp_name = FW_DIR "DSPei.bin";
+                       dsp_name = DSPEI_FIRMWARE;
                else
-                       dsp_name = FW_DIR "DSPep.bin";
+                       dsp_name = DSPEP_FIRMWARE;
        }
 
        ret = request_firmware(&sc->dsp_firm, dsp_name, &sc->usb_dev->dev);
@@ -1925,7 +1953,7 @@ static int load_XILINX_firmware(struct uea_softc *sc)
        int ret, size, u, ln;
        const u8 *pfw;
        u8 value;
-       char *fw_name = FW_DIR "930-fpga.bin";
+       char *fw_name = FPGA930_FIRMWARE;
 
        uea_enters(INS_TO_USBDEV(sc));
 
@@ -2753,3 +2781,28 @@ module_usb_driver(uea_driver);
 MODULE_AUTHOR("Damien Bergamini/Matthieu Castet/Stanislaw W. Gruszka");
 MODULE_DESCRIPTION("ADI 930/Eagle USB ADSL Modem driver");
 MODULE_LICENSE("Dual BSD/GPL");
+MODULE_FIRMWARE(EAGLE_FIRMWARE);
+MODULE_FIRMWARE(ADI930_FIRMWARE);
+MODULE_FIRMWARE(EAGLE_I_FIRMWARE);
+MODULE_FIRMWARE(EAGLE_II_FIRMWARE);
+MODULE_FIRMWARE(EAGLE_III_FIRMWARE);
+MODULE_FIRMWARE(EAGLE_IV_FIRMWARE);
+MODULE_FIRMWARE(DSP4I_FIRMWARE);
+MODULE_FIRMWARE(DSP4P_FIRMWARE);
+MODULE_FIRMWARE(DSP9I_FIRMWARE);
+MODULE_FIRMWARE(DSP9P_FIRMWARE);
+MODULE_FIRMWARE(DSPEI_FIRMWARE);
+MODULE_FIRMWARE(DSPEP_FIRMWARE);
+MODULE_FIRMWARE(FPGA930_FIRMWARE);
+MODULE_FIRMWARE(CMV4P_FIRMWARE);
+MODULE_FIRMWARE(CMV4PV2_FIRMWARE);
+MODULE_FIRMWARE(CMV4I_FIRMWARE);
+MODULE_FIRMWARE(CMV4IV2_FIRMWARE);
+MODULE_FIRMWARE(CMV9P_FIRMWARE);
+MODULE_FIRMWARE(CMV9PV2_FIRMWARE);
+MODULE_FIRMWARE(CMV9I_FIRMWARE);
+MODULE_FIRMWARE(CMV9IV2_FIRMWARE);
+MODULE_FIRMWARE(CMVEP_FIRMWARE);
+MODULE_FIRMWARE(CMVEPV2_FIRMWARE);
+MODULE_FIRMWARE(CMVEI_FIRMWARE);
+MODULE_FIRMWARE(CMVEIV2_FIRMWARE);
index 8337fb5d988de6cc68c7e06aa44341d09cd67c62..47e499c9c0b62734fa52adc44033e1b0d4bbda48 100644 (file)
@@ -1,9 +1,9 @@
 config USB_CHIPIDEA
        tristate "ChipIdea Highspeed Dual Role Controller"
-       depends on USB
+       depends on USB || USB_GADGET
        help
-          Say Y here if your system has a dual role high speed USB
-          controller based on ChipIdea silicon IP. Currently, only the
+         Say Y here if your system has a dual role high speed USB
+         controller based on ChipIdea silicon IP. Currently, only the
          peripheral mode is supported.
 
          When compiled dynamically, the module will be called ci-hdrc.ko.
@@ -12,7 +12,7 @@ if USB_CHIPIDEA
 
 config USB_CHIPIDEA_UDC
        bool "ChipIdea device controller"
-       depends on USB_GADGET
+       depends on USB_GADGET=y || USB_GADGET=USB_CHIPIDEA
        select USB_GADGET_DUALSPEED
        help
          Say Y here to enable device controller functionality of the
@@ -20,6 +20,7 @@ config USB_CHIPIDEA_UDC
 
 config USB_CHIPIDEA_HOST
        bool "ChipIdea host controller"
+       depends on USB=y || USB=USB_CHIPIDEA
        select USB_EHCI_ROOT_HUB_TT
        help
          Say Y here to enable host controller functionality of the
index 56d6bf66848894b76564ba452e00d6cf37f13416..455ef1649231b21fe6e2c092d0d312fde9286f0c 100644 (file)
@@ -826,7 +826,7 @@ static void acm_tty_set_termios(struct tty_struct *tty,
                                                struct ktermios *termios_old)
 {
        struct acm *acm = tty->driver_data;
-       struct ktermios *termios = tty->termios;
+       struct ktermios *termios = &tty->termios;
        struct usb_cdc_line_coding newline;
        int newctrl = acm->ctrlout;
 
@@ -1298,7 +1298,8 @@ skip_countries:
        usb_set_intfdata(data_interface, acm);
 
        usb_get_intf(control_interface);
-       tty_register_device(acm_tty_driver, minor, &control_interface->dev);
+       tty_port_register_device(&acm->port, acm_tty_driver, minor,
+                       &control_interface->dev);
 
        return 0;
 alloc_fail7:
index 682e8256b95da719d3e5d2aeea019cc59c25520f..d6c49d9ed4e03864fe500915f589149105c8cc10 100644 (file)
@@ -204,12 +204,12 @@ set_avoid_reset_quirk(struct device *dev, struct device_attribute *attr,
                const char *buf, size_t count)
 {
        struct usb_device       *udev = to_usb_device(dev);
-       int                     config;
+       int                     val;
 
-       if (sscanf(buf, "%d", &config) != 1 || config < 0 || config > 1)
+       if (sscanf(buf, "%d", &val) != 1 || val < 0 || val > 1)
                return -EINVAL;
        usb_lock_device(udev);
-       if (config)
+       if (val)
                udev->quirks |= USB_QUIRK_RESET_MORPHS;
        else
                udev->quirks &= ~USB_QUIRK_RESET_MORPHS;
index ee0ebacf8227df070dc4a40daf8cd873007ca296..89dcf155d57e9e75fec8919e120fe6fcaa4b0136 100644 (file)
@@ -450,7 +450,7 @@ static int dbgp_ehci_startup(void)
        writel(FLAG_CF, &ehci_regs->configured_flag);
 
        /* Wait until the controller is no longer halted */
-       loop = 10;
+       loop = 1000;
        do {
                status = readl(&ehci_regs->status);
                if (!(status & STS_HALT))
index b13e0bb5f5b8131de7cc26a928449215f2e0334c..0bb617e1dda2e0ecf2a440b6494761338f15004c 100644 (file)
@@ -3599,6 +3599,7 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
 
        if (hsotg->num_of_eps == 0) {
                dev_err(dev, "wrong number of EPs (zero)\n");
+               ret = -EINVAL;
                goto err_supplies;
        }
 
@@ -3606,6 +3607,7 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
                      GFP_KERNEL);
        if (!eps) {
                dev_err(dev, "cannot get memory\n");
+               ret = -ENOMEM;
                goto err_supplies;
        }
 
@@ -3622,6 +3624,7 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
                                                     GFP_KERNEL);
        if (!hsotg->ctrl_req) {
                dev_err(dev, "failed to allocate ctrl req\n");
+               ret = -ENOMEM;
                goto err_ep_mem;
        }
 
index 90e82e288eb9f25b6aad4842db1a001f174a0515..0e52309261543208f50a0ecd71e2d158ac256415 100644 (file)
@@ -669,6 +669,8 @@ static int eth_stop(struct net_device *net)
        spin_lock_irqsave(&dev->lock, flags);
        if (dev->port_usb) {
                struct gether   *link = dev->port_usb;
+               const struct usb_endpoint_descriptor *in;
+               const struct usb_endpoint_descriptor *out;
 
                if (link->close)
                        link->close(link);
@@ -682,10 +684,14 @@ static int eth_stop(struct net_device *net)
                 * their own pace; the network stack can handle old packets.
                 * For the moment we leave this here, since it works.
                 */
+               in = link->in_ep->desc;
+               out = link->out_ep->desc;
                usb_ep_disable(link->in_ep);
                usb_ep_disable(link->out_ep);
                if (netif_carrier_ok(net)) {
                        DBG(dev, "host still using in/out endpoints\n");
+                       link->in_ep->desc = in;
+                       link->out_ep->desc = out;
                        usb_ep_enable(link->in_ep);
                        usb_ep_enable(link->out_ep);
                }
index 5b3f5fffea92d241b50587b885c24bf69f83e878..2b5534c2ab8446bbb69b92ffe36c0c80b32ee77c 100644 (file)
@@ -1129,7 +1129,8 @@ int gserial_setup(struct usb_gadget *g, unsigned count)
        for (i = 0; i < count; i++) {
                struct device   *tty_dev;
 
-               tty_dev = tty_register_device(gs_tty_driver, i, &g->dev);
+               tty_dev = tty_port_register_device(&ports[i].port->port,
+                               gs_tty_driver, i, &g->dev);
                if (IS_ERR(tty_dev))
                        pr_warning("%s: no classdev for port %d, err %ld\n",
                                __func__, i, PTR_ERR(tty_dev));
index 075d2eca8108c59d3af002122248ecf44cd6f2bb..c3f619b1f598734d51589a9b05fa2851a270bb38 100644 (file)
@@ -450,7 +450,7 @@ config USB_OHCI_LITTLE_ENDIAN
 
 config USB_UHCI_HCD
        tristate "UHCI HCD (most Intel and VIA) support"
-       depends on USB && (PCI || SPARC_LEON)
+       depends on USB && (PCI || SPARC_LEON || ARCH_VT8500)
        ---help---
          The Universal Host Controller Interface is a standard by Intel for
          accessing the USB hardware in the PC (which is also called the USB
@@ -468,7 +468,15 @@ config USB_UHCI_HCD
 config USB_UHCI_SUPPORT_NON_PCI_HC
        bool
        depends on USB_UHCI_HCD
-       default y if SPARC_LEON
+       default y if (SPARC_LEON || ARCH_VT8500)
+
+config USB_UHCI_PLATFORM
+       bool "Generic UHCI Platform Driver support"
+       depends on USB_UHCI_SUPPORT_NON_PCI_HC
+       default y if ARCH_VT8500
+       ---help---
+         Enable support for generic UHCI platform devices that require no
+         additional configuration.
 
 config USB_UHCI_BIG_ENDIAN_MMIO
        bool
index a47e2cffaaf84a752b709f7e812b85b1dbd4481a..411bb74152ebe2ba3b063fb0e5e3445626d61af1 100644 (file)
@@ -150,31 +150,24 @@ static int __devinit ehci_atmel_drv_probe(struct platform_device *pdev)
        hcd->rsrc_start = res->start;
        hcd->rsrc_len = resource_size(res);
 
-       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
-                               driver->description)) {
-               dev_dbg(&pdev->dev, "controller already in use\n");
-               retval = -EBUSY;
-               goto fail_request_resource;
-       }
-
-       hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
+       hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
        if (hcd->regs == NULL) {
                dev_dbg(&pdev->dev, "error mapping memory\n");
                retval = -EFAULT;
-               goto fail_ioremap;
+               goto fail_request_resource;
        }
 
-       iclk = clk_get(&pdev->dev, "ehci_clk");
+       iclk = devm_clk_get(&pdev->dev, "ehci_clk");
        if (IS_ERR(iclk)) {
                dev_err(&pdev->dev, "Error getting interface clock\n");
                retval = -ENOENT;
-               goto fail_get_iclk;
+               goto fail_request_resource;
        }
-       fclk = clk_get(&pdev->dev, "uhpck");
+       fclk = devm_clk_get(&pdev->dev, "uhpck");
        if (IS_ERR(fclk)) {
                dev_err(&pdev->dev, "Error getting function clock\n");
                retval = -ENOENT;
-               goto fail_get_fclk;
+               goto fail_request_resource;
        }
 
        atmel_start_ehci(pdev);
@@ -187,13 +180,6 @@ static int __devinit ehci_atmel_drv_probe(struct platform_device *pdev)
 
 fail_add_hcd:
        atmel_stop_ehci(pdev);
-       clk_put(fclk);
-fail_get_fclk:
-       clk_put(iclk);
-fail_get_iclk:
-       iounmap(hcd->regs);
-fail_ioremap:
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 fail_request_resource:
        usb_put_hcd(hcd);
 fail_create_hcd:
@@ -209,13 +195,9 @@ static int __devexit ehci_atmel_drv_remove(struct platform_device *pdev)
 
        ehci_shutdown(hcd);
        usb_remove_hcd(hcd);
-       iounmap(hcd->regs);
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
        usb_put_hcd(hcd);
 
        atmel_stop_ehci(pdev);
-       clk_put(fclk);
-       clk_put(iclk);
        fclk = iclk = NULL;
 
        return 0;
index cba10d625a5d6430d8343717bb80b7cbd0f3ca9a..65c945eb4144a2d9d9f23dcd8685b1e1aade52d6 100644 (file)
@@ -98,23 +98,17 @@ static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
        hcd->rsrc_start = res->start;
        hcd->rsrc_len = resource_size(res);
 
-       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-               pr_debug("request_mem_region failed");
-               ret = -EBUSY;
-               goto err1;
-       }
-
-       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+       hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
        if (!hcd->regs) {
-               pr_debug("ioremap failed");
+               pr_debug("devm_request_and_ioremap failed");
                ret = -ENOMEM;
-               goto err2;
+               goto err1;
        }
 
        if (alchemy_usb_control(ALCHEMY_USB_EHCI0, 1)) {
                printk(KERN_INFO "%s: controller init failed!\n", pdev->name);
                ret = -ENODEV;
-               goto err3;
+               goto err1;
        }
 
        ret = usb_add_hcd(hcd, pdev->resource[1].start,
@@ -125,10 +119,6 @@ static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
        }
 
        alchemy_usb_control(ALCHEMY_USB_EHCI0, 0);
-err3:
-       iounmap(hcd->regs);
-err2:
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 err1:
        usb_put_hcd(hcd);
        return ret;
@@ -140,8 +130,6 @@ static int ehci_hcd_au1xxx_drv_remove(struct platform_device *pdev)
 
        usb_remove_hcd(hcd);
        alchemy_usb_control(ALCHEMY_USB_EHCI0, 0);
-       iounmap(hcd->regs);
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
        usb_put_hcd(hcd);
        platform_set_drvdata(pdev, NULL);
 
index caaa3e5be3347360d8a228838f26bb8e70d875f6..d91708d2e7298f7072c5cb77ff1bcefb396efb12 100644 (file)
@@ -105,27 +105,17 @@ static int cns3xxx_ehci_probe(struct platform_device *pdev)
        hcd->rsrc_start = res->start;
        hcd->rsrc_len = resource_size(res);
 
-       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
-                               driver->description)) {
-               dev_dbg(dev, "controller already in use\n");
-               retval = -EBUSY;
-               goto err1;
-       }
-
-       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+       hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
        if (hcd->regs == NULL) {
                dev_dbg(dev, "error mapping memory\n");
                retval = -EFAULT;
-               goto err2;
+               goto err1;
        }
 
        retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
        if (retval == 0)
                return retval;
 
-       iounmap(hcd->regs);
-err2:
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 err1:
        usb_put_hcd(hcd);
 
@@ -137,8 +127,6 @@ static int cns3xxx_ehci_remove(struct platform_device *pdev)
        struct usb_hcd *hcd = platform_get_drvdata(pdev);
 
        usb_remove_hcd(hcd);
-       iounmap(hcd->regs);
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 
        /*
         * EHCI and OHCI share the same clock and power,
index 22ca45c079a4223ed1cae600c83133881d327a99..3180cb3624d9839d90846c1dceea48ab5ac817c1 100644 (file)
@@ -127,12 +127,6 @@ static int __devinit ehci_hcd_grlib_probe(struct platform_device *op)
        hcd->rsrc_start = res.start;
        hcd->rsrc_len = resource_size(&res);
 
-       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-               printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__);
-               rv = -EBUSY;
-               goto err_rmr;
-       }
-
        irq = irq_of_parse_and_map(dn, 0);
        if (irq == NO_IRQ) {
                printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__);
@@ -140,9 +134,9 @@ static int __devinit ehci_hcd_grlib_probe(struct platform_device *op)
                goto err_irq;
        }
 
-       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+       hcd->regs = devm_request_and_ioremap(&op->dev, &res);
        if (!hcd->regs) {
-               printk(KERN_ERR "%s: ioremap failed\n", __FILE__);
+               pr_err("%s: devm_request_and_ioremap failed\n", __FILE__);
                rv = -ENOMEM;
                goto err_ioremap;
        }
@@ -161,17 +155,13 @@ static int __devinit ehci_hcd_grlib_probe(struct platform_device *op)
 
        rv = usb_add_hcd(hcd, irq, 0);
        if (rv)
-               goto err_ehci;
+               goto err_ioremap;
 
        return 0;
 
-err_ehci:
-       iounmap(hcd->regs);
 err_ioremap:
        irq_dispose_mapping(irq);
 err_irq:
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-err_rmr:
        usb_put_hcd(hcd);
 
        return rv;
@@ -188,9 +178,7 @@ static int ehci_hcd_grlib_remove(struct platform_device *op)
 
        usb_remove_hcd(hcd);
 
-       iounmap(hcd->regs);
        irq_dispose_mapping(hcd->irq);
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 
        usb_put_hcd(hcd);
 
index 488d401942e90c784e02d687087773324b178b8a..f224c0a48bed117ef3ab475941839f6617be9086 100644 (file)
@@ -98,30 +98,19 @@ static int ixp4xx_ehci_probe(struct platform_device *pdev)
        hcd->rsrc_start = res->start;
        hcd->rsrc_len = resource_size(res);
 
-       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
-                               driver->description)) {
-               dev_dbg(&pdev->dev, "controller already in use\n");
-               retval = -EBUSY;
-               goto fail_request_resource;
-       }
-
-       hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
+       hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
        if (hcd->regs == NULL) {
                dev_dbg(&pdev->dev, "error mapping memory\n");
                retval = -EFAULT;
-               goto fail_ioremap;
+               goto fail_request_resource;
        }
 
        retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
        if (retval)
-               goto fail_add_hcd;
+               goto fail_request_resource;
 
        return retval;
 
-fail_add_hcd:
-       iounmap(hcd->regs);
-fail_ioremap:
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 fail_request_resource:
        usb_put_hcd(hcd);
 fail_create_hcd:
@@ -134,8 +123,6 @@ static int ixp4xx_ehci_remove(struct platform_device *pdev)
        struct usb_hcd *hcd = platform_get_drvdata(pdev);
 
        usb_remove_hcd(hcd);
-       iounmap(hcd->regs);
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
        usb_put_hcd(hcd);
 
        return 0;
index a283e59709d6ce8a4cf0ba50dc7b8e229d65654a..aa0f328922dfad88495b919a84d82abd3a494ac9 100644 (file)
@@ -106,29 +106,19 @@ static int ehci_hcd_ls1x_probe(struct platform_device *pdev)
        hcd->rsrc_start = res->start;
        hcd->rsrc_len   = resource_size(res);
 
-       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-               dev_dbg(&pdev->dev, "controller already in use\n");
-               ret = -EBUSY;
-               goto err_put_hcd;
-       }
-
-       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+       hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
        if (hcd->regs == NULL) {
                dev_dbg(&pdev->dev, "error mapping memory\n");
                ret = -EFAULT;
-               goto err_release_region;
+               goto err_put_hcd;
        }
 
        ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
        if (ret)
-               goto err_iounmap;
+               goto err_put_hcd;
 
        return ret;
 
-err_iounmap:
-       iounmap(hcd->regs);
-err_release_region:
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 err_put_hcd:
        usb_put_hcd(hcd);
        return ret;
@@ -139,8 +129,6 @@ static int ehci_hcd_ls1x_remove(struct platform_device *pdev)
        struct usb_hcd *hcd = platform_get_drvdata(pdev);
 
        usb_remove_hcd(hcd);
-       iounmap(hcd->regs);
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
        usb_put_hcd(hcd);
 
        return 0;
index 17dd9e94001ec679329b2492f6620b51b7ac373a..4af4dc5b618c5710bd4f6226361916763122ac53 100644 (file)
@@ -133,7 +133,7 @@ static int ehci_msm_probe(struct platform_device *pdev)
 
        hcd->rsrc_start = res->start;
        hcd->rsrc_len = resource_size(res);
-       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+       hcd->regs = devm_ioremap(&pdev->dev, hcd->rsrc_start, hcd->rsrc_len);
        if (!hcd->regs) {
                dev_err(&pdev->dev, "ioremap failed\n");
                ret = -ENOMEM;
@@ -145,17 +145,17 @@ static int ehci_msm_probe(struct platform_device *pdev)
         * powering up VBUS, mapping of registers address space and power
         * management.
         */
-       phy = usb_get_phy(USB_PHY_TYPE_USB2);
+       phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
        if (IS_ERR_OR_NULL(phy)) {
                dev_err(&pdev->dev, "unable to find transceiver\n");
                ret = -ENODEV;
-               goto unmap;
+               goto put_hcd;
        }
 
        ret = otg_set_host(phy->otg, &hcd->self);
        if (ret < 0) {
                dev_err(&pdev->dev, "unable to register with transceiver\n");
-               goto put_transceiver;
+               goto put_hcd;
        }
 
        device_init_wakeup(&pdev->dev, 1);
@@ -168,10 +168,6 @@ static int ehci_msm_probe(struct platform_device *pdev)
 
        return 0;
 
-put_transceiver:
-       usb_put_phy(phy);
-unmap:
-       iounmap(hcd->regs);
 put_hcd:
        usb_put_hcd(hcd);
 
@@ -187,7 +183,6 @@ static int __devexit ehci_msm_remove(struct platform_device *pdev)
        pm_runtime_set_suspended(&pdev->dev);
 
        otg_set_host(phy->otg, NULL);
-       usb_put_phy(phy);
 
        usb_put_hcd(hcd);
 
index f6df1ccc961775ac182ce32838c71360bce8611d..f7bfc0b898b97a90dfece792fe40ca16ef4a2f73 100644 (file)
@@ -161,7 +161,7 @@ static int mv_ehci_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        size = sizeof(*ehci_mv) + sizeof(struct clk *) * pdata->clknum;
-       ehci_mv = kzalloc(size, GFP_KERNEL);
+       ehci_mv = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
        if (ehci_mv == NULL) {
                dev_err(&pdev->dev, "cannot allocate ehci_hcd_mv\n");
                retval = -ENOMEM;
@@ -175,12 +175,12 @@ static int mv_ehci_probe(struct platform_device *pdev)
        ehci_mv->clknum = pdata->clknum;
        for (clk_i = 0; clk_i < ehci_mv->clknum; clk_i++) {
                ehci_mv->clk[clk_i] =
-                   clk_get(&pdev->dev, pdata->clkname[clk_i]);
+                   devm_clk_get(&pdev->dev, pdata->clkname[clk_i]);
                if (IS_ERR(ehci_mv->clk[clk_i])) {
                        dev_err(&pdev->dev, "error get clck \"%s\"\n",
                                pdata->clkname[clk_i]);
                        retval = PTR_ERR(ehci_mv->clk[clk_i]);
-                       goto err_put_clk;
+                       goto err_clear_drvdata;
                }
        }
 
@@ -188,34 +188,36 @@ static int mv_ehci_probe(struct platform_device *pdev)
        if (r == NULL) {
                dev_err(&pdev->dev, "no phy I/O memory resource defined\n");
                retval = -ENODEV;
-               goto err_put_clk;
+               goto err_clear_drvdata;
        }
 
-       ehci_mv->phy_regs = ioremap(r->start, resource_size(r));
+       ehci_mv->phy_regs = devm_ioremap(&pdev->dev, r->start,
+                                        resource_size(r));
        if (ehci_mv->phy_regs == 0) {
                dev_err(&pdev->dev, "failed to map phy I/O memory\n");
                retval = -EFAULT;
-               goto err_put_clk;
+               goto err_clear_drvdata;
        }
 
        r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "capregs");
        if (!r) {
                dev_err(&pdev->dev, "no I/O memory resource defined\n");
                retval = -ENODEV;
-               goto err_iounmap_phyreg;
+               goto err_clear_drvdata;
        }
 
-       ehci_mv->cap_regs = ioremap(r->start, resource_size(r));
+       ehci_mv->cap_regs = devm_ioremap(&pdev->dev, r->start,
+                                        resource_size(r));
        if (ehci_mv->cap_regs == NULL) {
                dev_err(&pdev->dev, "failed to map I/O memory\n");
                retval = -EFAULT;
-               goto err_iounmap_phyreg;
+               goto err_clear_drvdata;
        }
 
        retval = mv_ehci_enable(ehci_mv);
        if (retval) {
                dev_err(&pdev->dev, "init phy error %d\n", retval);
-               goto err_iounmap_capreg;
+               goto err_clear_drvdata;
        }
 
        offset = readl(ehci_mv->cap_regs) & CAPLENGTH_MASK;
@@ -239,7 +241,7 @@ static int mv_ehci_probe(struct platform_device *pdev)
        ehci_mv->mode = pdata->mode;
        if (ehci_mv->mode == MV_USB_MODE_OTG) {
 #ifdef CONFIG_USB_OTG_UTILS
-               ehci_mv->otg = usb_get_phy(USB_PHY_TYPE_USB2);
+               ehci_mv->otg = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
                if (IS_ERR_OR_NULL(ehci_mv->otg)) {
                        dev_err(&pdev->dev,
                                "unable to find transceiver\n");
@@ -252,7 +254,7 @@ static int mv_ehci_probe(struct platform_device *pdev)
                        dev_err(&pdev->dev,
                                "unable to register with transceiver\n");
                        retval = -ENODEV;
-                       goto err_put_transceiver;
+                       goto err_disable_clk;
                }
                /* otg will enable clock before use as host */
                mv_ehci_disable(ehci_mv);
@@ -286,22 +288,10 @@ static int mv_ehci_probe(struct platform_device *pdev)
 err_set_vbus:
        if (pdata->set_vbus)
                pdata->set_vbus(0);
-#ifdef CONFIG_USB_OTG_UTILS
-err_put_transceiver:
-       if (!IS_ERR_OR_NULL(ehci_mv->otg))
-               usb_put_phy(ehci_mv->otg);
-#endif
 err_disable_clk:
        mv_ehci_disable(ehci_mv);
-err_iounmap_capreg:
-       iounmap(ehci_mv->cap_regs);
-err_iounmap_phyreg:
-       iounmap(ehci_mv->phy_regs);
-err_put_clk:
-       for (clk_i--; clk_i >= 0; clk_i--)
-               clk_put(ehci_mv->clk[clk_i]);
+err_clear_drvdata:
        platform_set_drvdata(pdev, NULL);
-       kfree(ehci_mv);
 err_put_hcd:
        usb_put_hcd(hcd);
 
@@ -317,10 +307,8 @@ static int mv_ehci_remove(struct platform_device *pdev)
        if (hcd->rh_registered)
                usb_remove_hcd(hcd);
 
-       if (!IS_ERR_OR_NULL(ehci_mv->otg)) {
+       if (!IS_ERR_OR_NULL(ehci_mv->otg))
                otg_set_host(ehci_mv->otg->otg, NULL);
-               usb_put_phy(ehci_mv->otg);
-       }
 
        if (ehci_mv->mode == MV_USB_MODE_HOST) {
                if (ehci_mv->pdata->set_vbus)
@@ -329,15 +317,8 @@ static int mv_ehci_remove(struct platform_device *pdev)
                mv_ehci_disable(ehci_mv);
        }
 
-       iounmap(ehci_mv->cap_regs);
-       iounmap(ehci_mv->phy_regs);
-
-       for (clk_i = 0; clk_i < ehci_mv->clknum; clk_i++)
-               clk_put(ehci_mv->clk[clk_i]);
-
        platform_set_drvdata(pdev, NULL);
 
-       kfree(ehci_mv);
        usb_put_hcd(hcd);
 
        return 0;
index 34201372c85f57c799c13e4d8ceb7561629bb7e8..959e1a4c34911c5919e133c1320c779f50454e0d 100644 (file)
@@ -121,7 +121,7 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
        if (!hcd)
                return -ENOMEM;
 
-       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
        if (!priv) {
                ret = -ENOMEM;
                goto err_alloc;
@@ -131,34 +131,28 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
        if (!res) {
                dev_err(dev, "Found HC with no register addr. Check setup!\n");
                ret = -ENODEV;
-               goto err_get_resource;
+               goto err_alloc;
        }
 
        hcd->rsrc_start = res->start;
        hcd->rsrc_len = resource_size(res);
 
-       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-               dev_dbg(dev, "controller already in use\n");
-               ret = -EBUSY;
-               goto err_request_mem;
-       }
-
-       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+       hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
        if (!hcd->regs) {
                dev_err(dev, "error mapping memory\n");
                ret = -EFAULT;
-               goto err_ioremap;
+               goto err_alloc;
        }
 
        /* enable clocks */
-       priv->usbclk = clk_get(dev, "ipg");
+       priv->usbclk = devm_clk_get(&pdev->dev, "ipg");
        if (IS_ERR(priv->usbclk)) {
                ret = PTR_ERR(priv->usbclk);
-               goto err_clk;
+               goto err_alloc;
        }
        clk_prepare_enable(priv->usbclk);
 
-       priv->ahbclk = clk_get(dev, "ahb");
+       priv->ahbclk = devm_clk_get(&pdev->dev, "ahb");
        if (IS_ERR(priv->ahbclk)) {
                ret = PTR_ERR(priv->ahbclk);
                goto err_clk_ahb;
@@ -166,7 +160,7 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
        clk_prepare_enable(priv->ahbclk);
 
        /* "dr" device has its own clock on i.MX51 */
-       priv->phyclk = clk_get(dev, "phy");
+       priv->phyclk = devm_clk_get(&pdev->dev, "phy");
        if (IS_ERR(priv->phyclk))
                priv->phyclk = NULL;
        if (priv->phyclk)
@@ -245,23 +239,12 @@ err_add:
        if (pdata && pdata->exit)
                pdata->exit(pdev);
 err_init:
-       if (priv->phyclk) {
+       if (priv->phyclk)
                clk_disable_unprepare(priv->phyclk);
-               clk_put(priv->phyclk);
-       }
 
        clk_disable_unprepare(priv->ahbclk);
-       clk_put(priv->ahbclk);
 err_clk_ahb:
        clk_disable_unprepare(priv->usbclk);
-       clk_put(priv->usbclk);
-err_clk:
-       iounmap(hcd->regs);
-err_ioremap:
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-err_request_mem:
-err_get_resource:
-       kfree(priv);
 err_alloc:
        usb_put_hcd(hcd);
        return ret;
@@ -280,22 +263,14 @@ static int __exit ehci_mxc_drv_remove(struct platform_device *pdev)
                usb_phy_shutdown(pdata->otg);
 
        usb_remove_hcd(hcd);
-       iounmap(hcd->regs);
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
        usb_put_hcd(hcd);
        platform_set_drvdata(pdev, NULL);
 
        clk_disable_unprepare(priv->usbclk);
-       clk_put(priv->usbclk);
        clk_disable_unprepare(priv->ahbclk);
-       clk_put(priv->ahbclk);
 
-       if (priv->phyclk) {
+       if (priv->phyclk)
                clk_disable_unprepare(priv->phyclk);
-               clk_put(priv->phyclk);
-       }
-
-       kfree(priv);
 
        return 0;
 }
index bb55eb4a7d485b806e69ba0c5141912f04bd6791..d7fe287d067803e484d56efdf53060546634ea1e 100644 (file)
 #define        EHCI_INSNREG05_ULPI_EXTREGADD_SHIFT             8
 #define        EHCI_INSNREG05_ULPI_WRDATA_SHIFT                0
 
-/* Errata i693 */
-static struct clk      *utmi_p1_fck;
-static struct clk      *utmi_p2_fck;
-static struct clk      *xclk60mhsp1_ck;
-static struct clk      *xclk60mhsp2_ck;
-static struct clk      *usbhost_p1_fck;
-static struct clk      *usbhost_p2_fck;
-static struct clk      *init_60m_fclk;
-
 /*-------------------------------------------------------------------------*/
 
 static const struct hc_driver ehci_omap_hc_driver;
@@ -80,40 +71,6 @@ static inline u32 ehci_read(void __iomem *base, u32 reg)
        return __raw_readl(base + reg);
 }
 
-/* Erratum i693 workaround sequence */
-static void omap_ehci_erratum_i693(struct ehci_hcd *ehci)
-{
-       int ret = 0;
-
-       /* Switch to the internal 60 MHz clock */
-       ret = clk_set_parent(utmi_p1_fck, init_60m_fclk);
-       if (ret != 0)
-               ehci_err(ehci, "init_60m_fclk set parent"
-                       "failed error:%d\n", ret);
-
-       ret = clk_set_parent(utmi_p2_fck, init_60m_fclk);
-       if (ret != 0)
-               ehci_err(ehci, "init_60m_fclk set parent"
-                       "failed error:%d\n", ret);
-
-       clk_enable(usbhost_p1_fck);
-       clk_enable(usbhost_p2_fck);
-
-       /* Wait 1ms and switch back to the external clock */
-       mdelay(1);
-       ret = clk_set_parent(utmi_p1_fck, xclk60mhsp1_ck);
-       if (ret != 0)
-               ehci_err(ehci, "xclk60mhsp1_ck set parent"
-                       "failed error:%d\n", ret);
-
-       ret = clk_set_parent(utmi_p2_fck, xclk60mhsp2_ck);
-       if (ret != 0)
-               ehci_err(ehci, "xclk60mhsp2_ck set parent"
-                       "failed error:%d\n", ret);
-
-       clk_disable(usbhost_p1_fck);
-       clk_disable(usbhost_p2_fck);
-}
 
 static void omap_ehci_soft_phy_reset(struct usb_hcd *hcd, u8 port)
 {
@@ -195,50 +152,6 @@ static int omap_ehci_init(struct usb_hcd *hcd)
        return rc;
 }
 
-static int omap_ehci_hub_control(
-       struct usb_hcd  *hcd,
-       u16             typeReq,
-       u16             wValue,
-       u16             wIndex,
-       char            *buf,
-       u16             wLength
-)
-{
-       struct ehci_hcd *ehci = hcd_to_ehci(hcd);
-       u32 __iomem *status_reg = &ehci->regs->port_status[
-                               (wIndex & 0xff) - 1];
-       u32             temp;
-       unsigned long   flags;
-       int             retval = 0;
-
-       spin_lock_irqsave(&ehci->lock, flags);
-
-       if (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_SUSPEND) {
-               temp = ehci_readl(ehci, status_reg);
-               if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) != 0) {
-                       retval = -EPIPE;
-                       goto done;
-               }
-
-               temp &= ~PORT_WKCONN_E;
-               temp |= PORT_WKDISC_E | PORT_WKOC_E;
-               ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
-
-               omap_ehci_erratum_i693(ehci);
-
-               set_bit((wIndex & 0xff) - 1, &ehci->suspended_ports);
-               goto done;
-       }
-
-       spin_unlock_irqrestore(&ehci->lock, flags);
-
-       /* Handle the hub control events here */
-       return ehci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
-done:
-       spin_unlock_irqrestore(&ehci->lock, flags);
-       return retval;
-}
-
 static void disable_put_regulator(
                struct ehci_hcd_omap_platform_data *pdata)
 {
@@ -351,79 +264,9 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
                goto err_pm_runtime;
        }
 
-       /* get clocks */
-       utmi_p1_fck = clk_get(dev, "utmi_p1_gfclk");
-       if (IS_ERR(utmi_p1_fck)) {
-               ret = PTR_ERR(utmi_p1_fck);
-               dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret);
-               goto err_add_hcd;
-       }
-
-       xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck");
-       if (IS_ERR(xclk60mhsp1_ck)) {
-               ret = PTR_ERR(xclk60mhsp1_ck);
-               dev_err(dev, "xclk60mhsp1_ck failed error:%d\n", ret);
-               goto err_utmi_p1_fck;
-       }
-
-       utmi_p2_fck = clk_get(dev, "utmi_p2_gfclk");
-       if (IS_ERR(utmi_p2_fck)) {
-               ret = PTR_ERR(utmi_p2_fck);
-               dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret);
-               goto err_xclk60mhsp1_ck;
-       }
-
-       xclk60mhsp2_ck = clk_get(dev, "xclk60mhsp2_ck");
-       if (IS_ERR(xclk60mhsp2_ck)) {
-               ret = PTR_ERR(xclk60mhsp2_ck);
-               dev_err(dev, "xclk60mhsp2_ck failed error:%d\n", ret);
-               goto err_utmi_p2_fck;
-       }
-
-       usbhost_p1_fck = clk_get(dev, "usb_host_hs_utmi_p1_clk");
-       if (IS_ERR(usbhost_p1_fck)) {
-               ret = PTR_ERR(usbhost_p1_fck);
-               dev_err(dev, "usbhost_p1_fck failed error:%d\n", ret);
-               goto err_xclk60mhsp2_ck;
-       }
-
-       usbhost_p2_fck = clk_get(dev, "usb_host_hs_utmi_p2_clk");
-       if (IS_ERR(usbhost_p2_fck)) {
-               ret = PTR_ERR(usbhost_p2_fck);
-               dev_err(dev, "usbhost_p2_fck failed error:%d\n", ret);
-               goto err_usbhost_p1_fck;
-       }
-
-       init_60m_fclk = clk_get(dev, "init_60m_fclk");
-       if (IS_ERR(init_60m_fclk)) {
-               ret = PTR_ERR(init_60m_fclk);
-               dev_err(dev, "init_60m_fclk failed error:%d\n", ret);
-               goto err_usbhost_p2_fck;
-       }
 
        return 0;
 
-err_usbhost_p2_fck:
-       clk_put(usbhost_p2_fck);
-
-err_usbhost_p1_fck:
-       clk_put(usbhost_p1_fck);
-
-err_xclk60mhsp2_ck:
-       clk_put(xclk60mhsp2_ck);
-
-err_utmi_p2_fck:
-       clk_put(utmi_p2_fck);
-
-err_xclk60mhsp1_ck:
-       clk_put(xclk60mhsp1_ck);
-
-err_utmi_p1_fck:
-       clk_put(utmi_p1_fck);
-
-err_add_hcd:
-       usb_remove_hcd(hcd);
-
 err_pm_runtime:
        disable_put_regulator(pdata);
        pm_runtime_put_sync(dev);
@@ -454,14 +297,6 @@ static int ehci_hcd_omap_remove(struct platform_device *pdev)
        iounmap(hcd->regs);
        usb_put_hcd(hcd);
 
-       clk_put(utmi_p1_fck);
-       clk_put(utmi_p2_fck);
-       clk_put(xclk60mhsp1_ck);
-       clk_put(xclk60mhsp2_ck);
-       clk_put(usbhost_p1_fck);
-       clk_put(usbhost_p2_fck);
-       clk_put(init_60m_fclk);
-
        pm_runtime_put_sync(dev);
        pm_runtime_disable(dev);
 
@@ -532,7 +367,7 @@ static const struct hc_driver ehci_omap_hc_driver = {
         * root hub support
         */
        .hub_status_data        = ehci_hub_status_data,
-       .hub_control            = omap_ehci_hub_control,
+       .hub_control            = ehci_hub_control,
        .bus_suspend            = ehci_bus_suspend,
        .bus_resume             = ehci_bus_resume,
 
index 4b1d896d5a2214f75f32a5e943e9a4e5804f24f9..764e0100b6f438d82ab64057e8cb37abd638fa79 100644 (file)
@@ -82,10 +82,14 @@ static int __devinit ehci_platform_probe(struct platform_device *dev)
 {
        struct usb_hcd *hcd;
        struct resource *res_mem;
+       struct usb_ehci_pdata *pdata = dev->dev.platform_data;
        int irq;
        int err = -ENOMEM;
 
-       BUG_ON(!dev->dev.platform_data);
+       if (!pdata) {
+               WARN_ON(1);
+               return -ENODEV;
+       }
 
        if (usb_disabled())
                return -ENODEV;
@@ -101,10 +105,18 @@ static int __devinit ehci_platform_probe(struct platform_device *dev)
                return -ENXIO;
        }
 
+       if (pdata->power_on) {
+               err = pdata->power_on(dev);
+               if (err < 0)
+                       return err;
+       }
+
        hcd = usb_create_hcd(&ehci_platform_hc_driver, &dev->dev,
                             dev_name(&dev->dev));
-       if (!hcd)
-               return -ENOMEM;
+       if (!hcd) {
+               err = -ENOMEM;
+               goto err_power;
+       }
 
        hcd->rsrc_start = res_mem->start;
        hcd->rsrc_len = resource_size(res_mem);
@@ -116,8 +128,10 @@ static int __devinit ehci_platform_probe(struct platform_device *dev)
        }
 
        hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
-       if (!hcd->regs)
+       if (!hcd->regs) {
+               err = -ENOMEM;
                goto err_release_region;
+       }
        err = usb_add_hcd(hcd, irq, IRQF_SHARED);
        if (err)
                goto err_iounmap;
@@ -132,12 +146,17 @@ err_release_region:
        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 err_put_hcd:
        usb_put_hcd(hcd);
+err_power:
+       if (pdata->power_off)
+               pdata->power_off(dev);
+
        return err;
 }
 
 static int __devexit ehci_platform_remove(struct platform_device *dev)
 {
        struct usb_hcd *hcd = platform_get_drvdata(dev);
+       struct usb_ehci_pdata *pdata = dev->dev.platform_data;
 
        usb_remove_hcd(hcd);
        iounmap(hcd->regs);
@@ -145,6 +164,9 @@ static int __devexit ehci_platform_remove(struct platform_device *dev)
        usb_put_hcd(hcd);
        platform_set_drvdata(dev, NULL);
 
+       if (pdata->power_off)
+               pdata->power_off(dev);
+
        return 0;
 }
 
@@ -153,14 +175,32 @@ static int __devexit ehci_platform_remove(struct platform_device *dev)
 static int ehci_platform_suspend(struct device *dev)
 {
        struct usb_hcd *hcd = dev_get_drvdata(dev);
+       struct usb_ehci_pdata *pdata = dev->platform_data;
+       struct platform_device *pdev =
+               container_of(dev, struct platform_device, dev);
        bool do_wakeup = device_may_wakeup(dev);
+       int ret;
+
+       ret = ehci_suspend(hcd, do_wakeup);
 
-       return ehci_suspend(hcd, do_wakeup);
+       if (pdata->power_suspend)
+               pdata->power_suspend(pdev);
+
+       return ret;
 }
 
 static int ehci_platform_resume(struct device *dev)
 {
        struct usb_hcd *hcd = dev_get_drvdata(dev);
+       struct usb_ehci_pdata *pdata = dev->platform_data;
+       struct platform_device *pdev =
+               container_of(dev, struct platform_device, dev);
+
+       if (pdata->power_on) {
+               int err = pdata->power_on(pdev);
+               if (err < 0)
+                       return err;
+       }
 
        ehci_resume(hcd, false);
        return 0;
index bbbe89dfd886b8ef250217cb18c25bc9eb0e0a74..fa937d05a02b9adbb4639c6269e987e620027cfc 100644 (file)
@@ -114,12 +114,6 @@ static int __devinit ehci_hcd_ppc_of_probe(struct platform_device *op)
        hcd->rsrc_start = res.start;
        hcd->rsrc_len = resource_size(&res);
 
-       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-               printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__);
-               rv = -EBUSY;
-               goto err_rmr;
-       }
-
        irq = irq_of_parse_and_map(dn, 0);
        if (irq == NO_IRQ) {
                printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__);
@@ -127,9 +121,9 @@ static int __devinit ehci_hcd_ppc_of_probe(struct platform_device *op)
                goto err_irq;
        }
 
-       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+       hcd->regs = devm_request_and_ioremap(&op->dev, &res);
        if (!hcd->regs) {
-               printk(KERN_ERR "%s: ioremap failed\n", __FILE__);
+               pr_err("%s: devm_request_and_ioremap failed\n", __FILE__);
                rv = -ENOMEM;
                goto err_ioremap;
        }
@@ -139,8 +133,10 @@ static int __devinit ehci_hcd_ppc_of_probe(struct platform_device *op)
        if (np != NULL) {
                /* claim we really affected by usb23 erratum */
                if (!of_address_to_resource(np, 0, &res))
-                       ehci->ohci_hcctrl_reg = ioremap(res.start +
-                                       OHCI_HCCTRL_OFFSET, OHCI_HCCTRL_LEN);
+                       ehci->ohci_hcctrl_reg =
+                               devm_ioremap(&op->dev,
+                                            res.start + OHCI_HCCTRL_OFFSET,
+                                            OHCI_HCCTRL_LEN);
                else
                        pr_debug("%s: no ohci offset in fdt\n", __FILE__);
                if (!ehci->ohci_hcctrl_reg) {
@@ -169,19 +165,13 @@ static int __devinit ehci_hcd_ppc_of_probe(struct platform_device *op)
 
        rv = usb_add_hcd(hcd, irq, 0);
        if (rv)
-               goto err_ehci;
+               goto err_ioremap;
 
        return 0;
 
-err_ehci:
-       if (ehci->has_amcc_usb23)
-               iounmap(ehci->ohci_hcctrl_reg);
-       iounmap(hcd->regs);
 err_ioremap:
        irq_dispose_mapping(irq);
 err_irq:
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-err_rmr:
        usb_put_hcd(hcd);
 
        return rv;
@@ -202,9 +192,7 @@ static int ehci_hcd_ppc_of_remove(struct platform_device *op)
 
        usb_remove_hcd(hcd);
 
-       iounmap(hcd->regs);
        irq_dispose_mapping(hcd->irq);
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 
        /* use request_mem_region to test if the ohci driver is loaded.  if so
         * ensure the ohci core is operational.
@@ -222,8 +210,6 @@ static int ehci_hcd_ppc_of_remove(struct platform_device *op)
                                pr_debug("%s: no ohci offset in fdt\n", __FILE__);
                        of_node_put(np);
                }
-
-               iounmap(ehci->ohci_hcctrl_reg);
        }
        usb_put_hcd(hcd);
 
index 9d8f1dd57cb36a5041ec22ef9c60b28923fbcf83..d055503e4183fbefa68b8e572c8e64f1ed1008df 100644 (file)
@@ -128,7 +128,7 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev)
        }
 
        s5p_ehci->hcd = hcd;
-       s5p_ehci->clk = clk_get(&pdev->dev, "usbhost");
+       s5p_ehci->clk = devm_clk_get(&pdev->dev, "usbhost");
 
        if (IS_ERR(s5p_ehci->clk)) {
                dev_err(&pdev->dev, "Failed to get usbhost clock\n");
@@ -138,7 +138,7 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev)
 
        err = clk_enable(s5p_ehci->clk);
        if (err)
-               goto fail_clken;
+               goto fail_clk;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
@@ -184,8 +184,6 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev)
 
 fail_io:
        clk_disable(s5p_ehci->clk);
-fail_clken:
-       clk_put(s5p_ehci->clk);
 fail_clk:
        usb_put_hcd(hcd);
        return err;
@@ -203,7 +201,6 @@ static int __devexit s5p_ehci_remove(struct platform_device *pdev)
                pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
 
        clk_disable(s5p_ehci->clk);
-       clk_put(s5p_ehci->clk);
 
        usb_put_hcd(hcd);
 
index 58c96bd50d22853d10a8ac423b39acf0e375eeb7..efad02d947f2dff039e519f105cb4b85682e7ba1 100644 (file)
@@ -40,7 +40,7 @@ static int ehci_sead3_setup(struct usb_hcd *hcd)
        ehci->need_io_watchdog = 0;
 
        /* Set burst length to 16 words. */
-       ehci_writel(ehci, 0x1010, &ehci->regs->reserved[1]);
+       ehci_writel(ehci, 0x1010, &ehci->regs->reserved1[1]);
 
        return ret;
 }
@@ -112,17 +112,11 @@ static int ehci_hcd_sead3_drv_probe(struct platform_device *pdev)
        hcd->rsrc_start = res->start;
        hcd->rsrc_len = resource_size(res);
 
-       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-               pr_debug("request_mem_region failed");
-               ret = -EBUSY;
-               goto err1;
-       }
-
-       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+       hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
        if (!hcd->regs) {
                pr_debug("ioremap failed");
                ret = -ENOMEM;
-               goto err2;
+               goto err1;
        }
 
        /* Root hub has integrated TT. */
@@ -135,9 +129,6 @@ static int ehci_hcd_sead3_drv_probe(struct platform_device *pdev)
                return ret;
        }
 
-       iounmap(hcd->regs);
-err2:
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 err1:
        usb_put_hcd(hcd);
        return ret;
@@ -148,8 +139,6 @@ static int ehci_hcd_sead3_drv_remove(struct platform_device *pdev)
        struct usb_hcd *hcd = platform_get_drvdata(pdev);
 
        usb_remove_hcd(hcd);
-       iounmap(hcd->regs);
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
        usb_put_hcd(hcd);
        platform_set_drvdata(pdev, NULL);
 
index b3f1e3650da0a455bcea891f231308270dd99a4b..6081e1ed3ac9d9e8338c233829103661d1d46a99 100644 (file)
@@ -125,33 +125,27 @@ static int ehci_hcd_sh_probe(struct platform_device *pdev)
        hcd->rsrc_start = res->start;
        hcd->rsrc_len = resource_size(res);
 
-       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
-                               driver->description)) {
-               dev_dbg(&pdev->dev, "controller already in use\n");
-               ret = -EBUSY;
-               goto fail_request_resource;
-       }
-
-       hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
+       hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
        if (hcd->regs == NULL) {
                dev_dbg(&pdev->dev, "error mapping memory\n");
                ret = -ENXIO;
-               goto fail_ioremap;
+               goto fail_request_resource;
        }
 
-       priv = kmalloc(sizeof(struct ehci_sh_priv), GFP_KERNEL);
+       priv = devm_kzalloc(&pdev->dev, sizeof(struct ehci_sh_priv),
+                           GFP_KERNEL);
        if (!priv) {
                dev_dbg(&pdev->dev, "error allocating priv data\n");
                ret = -ENOMEM;
-               goto fail_alloc;
+               goto fail_request_resource;
        }
 
        /* These are optional, we don't care if they fail */
-       priv->fclk = clk_get(&pdev->dev, "usb_fck");
+       priv->fclk = devm_clk_get(&pdev->dev, "usb_fck");
        if (IS_ERR(priv->fclk))
                priv->fclk = NULL;
 
-       priv->iclk = clk_get(&pdev->dev, "usb_ick");
+       priv->iclk = devm_clk_get(&pdev->dev, "usb_ick");
        if (IS_ERR(priv->iclk))
                priv->iclk = NULL;
 
@@ -176,14 +170,6 @@ fail_add_hcd:
        clk_disable(priv->iclk);
        clk_disable(priv->fclk);
 
-       clk_put(priv->iclk);
-       clk_put(priv->fclk);
-
-       kfree(priv);
-fail_alloc:
-       iounmap(hcd->regs);
-fail_ioremap:
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 fail_request_resource:
        usb_put_hcd(hcd);
 fail_create_hcd:
@@ -198,19 +184,12 @@ static int __exit ehci_hcd_sh_remove(struct platform_device *pdev)
        struct usb_hcd *hcd = priv->hcd;
 
        usb_remove_hcd(hcd);
-       iounmap(hcd->regs);
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
        usb_put_hcd(hcd);
        platform_set_drvdata(pdev, NULL);
 
        clk_disable(priv->fclk);
        clk_disable(priv->iclk);
 
-       clk_put(priv->fclk);
-       clk_put(priv->iclk);
-
-       kfree(priv);
-
        return 0;
 }
 
index 950e95efa381bce88d7c6c148ac90609755ee83b..75eca42dd6072f332750f7b54b92d89139296251 100644 (file)
@@ -634,7 +634,8 @@ static int tegra_ehci_probe(struct platform_device *pdev)
 
        setup_vbus_gpio(pdev, pdata);
 
-       tegra = kzalloc(sizeof(struct tegra_ehci_hcd), GFP_KERNEL);
+       tegra = devm_kzalloc(&pdev->dev, sizeof(struct tegra_ehci_hcd),
+                            GFP_KERNEL);
        if (!tegra)
                return -ENOMEM;
 
@@ -642,13 +643,12 @@ static int tegra_ehci_probe(struct platform_device *pdev)
                                        dev_name(&pdev->dev));
        if (!hcd) {
                dev_err(&pdev->dev, "Unable to create HCD\n");
-               err = -ENOMEM;
-               goto fail_hcd;
+               return -ENOMEM;
        }
 
        platform_set_drvdata(pdev, tegra);
 
-       tegra->clk = clk_get(&pdev->dev, NULL);
+       tegra->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(tegra->clk)) {
                dev_err(&pdev->dev, "Can't get ehci clock\n");
                err = PTR_ERR(tegra->clk);
@@ -657,9 +657,9 @@ static int tegra_ehci_probe(struct platform_device *pdev)
 
        err = clk_prepare_enable(tegra->clk);
        if (err)
-               goto fail_clken;
+               goto fail_clk;
 
-       tegra->emc_clk = clk_get(&pdev->dev, "emc");
+       tegra->emc_clk = devm_clk_get(&pdev->dev, "emc");
        if (IS_ERR(tegra->emc_clk)) {
                dev_err(&pdev->dev, "Can't get emc clock\n");
                err = PTR_ERR(tegra->emc_clk);
@@ -677,7 +677,7 @@ static int tegra_ehci_probe(struct platform_device *pdev)
        }
        hcd->rsrc_start = res->start;
        hcd->rsrc_len = resource_size(res);
-       hcd->regs = ioremap(res->start, resource_size(res));
+       hcd->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res));
        if (!hcd->regs) {
                dev_err(&pdev->dev, "Failed to remap I/O memory\n");
                err = -ENOMEM;
@@ -702,7 +702,7 @@ static int tegra_ehci_probe(struct platform_device *pdev)
                default:
                        err = -ENODEV;
                        dev_err(&pdev->dev, "unknown usb instance\n");
-                       goto fail_phy;
+                       goto fail_io;
                }
        }
 
@@ -712,7 +712,7 @@ static int tegra_ehci_probe(struct platform_device *pdev)
        if (IS_ERR(tegra->phy)) {
                dev_err(&pdev->dev, "Failed to open USB phy\n");
                err = -ENXIO;
-               goto fail_phy;
+               goto fail_io;
        }
 
        err = tegra_usb_phy_power_on(tegra->phy);
@@ -733,7 +733,8 @@ static int tegra_ehci_probe(struct platform_device *pdev)
 
 #ifdef CONFIG_USB_OTG_UTILS
        if (pdata->operating_mode == TEGRA_USB_OTG) {
-               tegra->transceiver = usb_get_phy(USB_PHY_TYPE_USB2);
+               tegra->transceiver =
+                       devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
                if (!IS_ERR_OR_NULL(tegra->transceiver))
                        otg_set_host(tegra->transceiver->otg, &hcd->self);
        }
@@ -757,25 +758,16 @@ static int tegra_ehci_probe(struct platform_device *pdev)
 
 fail:
 #ifdef CONFIG_USB_OTG_UTILS
-       if (!IS_ERR_OR_NULL(tegra->transceiver)) {
+       if (!IS_ERR_OR_NULL(tegra->transceiver))
                otg_set_host(tegra->transceiver->otg, NULL);
-               usb_put_phy(tegra->transceiver);
-       }
 #endif
        tegra_usb_phy_close(tegra->phy);
-fail_phy:
-       iounmap(hcd->regs);
 fail_io:
        clk_disable_unprepare(tegra->emc_clk);
-       clk_put(tegra->emc_clk);
 fail_emc_clk:
        clk_disable_unprepare(tegra->clk);
-fail_clken:
-       clk_put(tegra->clk);
 fail_clk:
        usb_put_hcd(hcd);
-fail_hcd:
-       kfree(tegra);
        return err;
 }
 
@@ -792,25 +784,20 @@ static int tegra_ehci_remove(struct platform_device *pdev)
        pm_runtime_put_noidle(&pdev->dev);
 
 #ifdef CONFIG_USB_OTG_UTILS
-       if (!IS_ERR_OR_NULL(tegra->transceiver)) {
+       if (!IS_ERR_OR_NULL(tegra->transceiver))
                otg_set_host(tegra->transceiver->otg, NULL);
-               usb_put_phy(tegra->transceiver);
-       }
 #endif
 
        usb_remove_hcd(hcd);
-       usb_put_hcd(hcd);
 
        tegra_usb_phy_close(tegra->phy);
-       iounmap(hcd->regs);
+
+       usb_put_hcd(hcd);
 
        clk_disable_unprepare(tegra->clk);
-       clk_put(tegra->clk);
 
        clk_disable_unprepare(tegra->emc_clk);
-       clk_put(tegra->emc_clk);
 
-       kfree(tegra);
        return 0;
 }
 
index 4d147c4e33f5343802787d5db358b25fcfae0244..96722bfebc84ba0bed49f6cd4c0aa3313f7f55dd 100644 (file)
@@ -16,6 +16,7 @@
  *
  */
 
+#include <linux/of.h>
 #include <linux/platform_device.h>
 
 static int ehci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
@@ -106,17 +107,11 @@ static int vt8500_ehci_drv_probe(struct platform_device *pdev)
        hcd->rsrc_start = res->start;
        hcd->rsrc_len = resource_size(res);
 
-       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-               pr_debug("request_mem_region failed");
-               ret = -EBUSY;
-               goto err1;
-       }
-
-       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+       hcd->regs = devm_request_and_ioremap(&pdev->dev, res);
        if (!hcd->regs) {
                pr_debug("ioremap failed");
                ret = -ENOMEM;
-               goto err2;
+               goto err1;
        }
 
        ehci = hcd_to_ehci(hcd);
@@ -129,9 +124,6 @@ static int vt8500_ehci_drv_probe(struct platform_device *pdev)
                return ret;
        }
 
-       iounmap(hcd->regs);
-err2:
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 err1:
        usb_put_hcd(hcd);
        return ret;
@@ -142,14 +134,18 @@ static int vt8500_ehci_drv_remove(struct platform_device *pdev)
        struct usb_hcd *hcd = platform_get_drvdata(pdev);
 
        usb_remove_hcd(hcd);
-       iounmap(hcd->regs);
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
        usb_put_hcd(hcd);
        platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
 
+static const struct of_device_id vt8500_ehci_ids[] = {
+       { .compatible = "via,vt8500-ehci", },
+       { .compatible = "wm,prizm-ehci", },
+       {}
+};
+
 static struct platform_driver vt8500_ehci_driver = {
        .probe          = vt8500_ehci_drv_probe,
        .remove         = vt8500_ehci_drv_remove,
@@ -157,7 +153,9 @@ static struct platform_driver vt8500_ehci_driver = {
        .driver = {
                .name   = "vt8500-ehci",
                .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(vt8500_ehci_ids),
        }
 };
 
 MODULE_ALIAS("platform:vt8500-ehci");
+MODULE_DEVICE_TABLE(of, vt8500_ehci_ids);
index 39f24fa37ebe9fff07c3f38087dbf6f04bedaaa8..6a3f921a5d7683f1434e972a4b59c5fabf470dbc 100644 (file)
@@ -152,12 +152,6 @@ static int __devinit ehci_hcd_xilinx_of_probe(struct platform_device *op)
        hcd->rsrc_start = res.start;
        hcd->rsrc_len = resource_size(&res);
 
-       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-               printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__);
-               rv = -EBUSY;
-               goto err_rmr;
-       }
-
        irq = irq_of_parse_and_map(dn, 0);
        if (!irq) {
                printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__);
@@ -165,11 +159,11 @@ static int __devinit ehci_hcd_xilinx_of_probe(struct platform_device *op)
                goto err_irq;
        }
 
-       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+       hcd->regs = devm_request_and_ioremap(&op->dev, &res);
        if (!hcd->regs) {
-               printk(KERN_ERR "%s: ioremap failed\n", __FILE__);
+               pr_err("%s: devm_request_and_ioremap failed\n", __FILE__);
                rv = -ENOMEM;
-               goto err_ioremap;
+               goto err_irq;
        }
 
        ehci = hcd_to_ehci(hcd);
@@ -200,12 +194,7 @@ static int __devinit ehci_hcd_xilinx_of_probe(struct platform_device *op)
        if (rv == 0)
                return 0;
 
-       iounmap(hcd->regs);
-
-err_ioremap:
 err_irq:
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-err_rmr:
        usb_put_hcd(hcd);
 
        return rv;
@@ -227,9 +216,6 @@ static int ehci_hcd_xilinx_of_remove(struct platform_device *op)
 
        usb_remove_hcd(hcd);
 
-       iounmap(hcd->regs);
-       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-
        usb_put_hcd(hcd);
 
        return 0;
index 2ed112d3e1595d45c5d6a8ab4053c883310124d1..256326322cfd8b96dd5ee686c0f1a769be52a074 100644 (file)
@@ -543,12 +543,12 @@ static void postproc_ep(struct isp1362_hcd *isp1362_hcd, struct isp1362_ep *ep)
                            usb_pipein(urb->pipe) ? "IN" : "OUT", ep->nextpid,
                            short_ok ? "" : "not_",
                            PTD_GET_COUNT(ptd), ep->maxpacket, len);
+                       /* save the data underrun error code for later and
+                        * proceed with the status stage
+                        */
+                       urb->actual_length += PTD_GET_COUNT(ptd);
                        if (usb_pipecontrol(urb->pipe)) {
                                ep->nextpid = USB_PID_ACK;
-                               /* save the data underrun error code for later and
-                                * proceed with the status stage
-                                */
-                               urb->actual_length += PTD_GET_COUNT(ptd);
                                BUG_ON(urb->actual_length > urb->transfer_buffer_length);
 
                                if (urb->status == -EINPROGRESS)
index e7d75d295988c3fabc64c36fdf6d1db23f70b7d0..f8b2d91851f7cbfd509aa35b98119acdc544e948 100644 (file)
@@ -403,8 +403,6 @@ err0:
 static inline void
 usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev)
 {
-       struct ohci_hcd         *ohci = hcd_to_ohci (hcd);
-
        usb_remove_hcd(hcd);
        if (!IS_ERR_OR_NULL(hcd->phy)) {
                (void) otg_set_host(hcd->phy->otg, 0);
index 670c7059c9ae3aaa8fc3530d17639005cf36bbac..e24ec9f79164afc9e6563a147cb76d4c0f3c96c3 100644 (file)
@@ -83,10 +83,14 @@ static int __devinit ohci_platform_probe(struct platform_device *dev)
 {
        struct usb_hcd *hcd;
        struct resource *res_mem;
+       struct usb_ohci_pdata *pdata = dev->dev.platform_data;
        int irq;
        int err = -ENOMEM;
 
-       BUG_ON(!dev->dev.platform_data);
+       if (!pdata) {
+               WARN_ON(1);
+               return -ENODEV;
+       }
 
        if (usb_disabled())
                return -ENODEV;
@@ -103,10 +107,18 @@ static int __devinit ohci_platform_probe(struct platform_device *dev)
                return -ENXIO;
        }
 
+       if (pdata->power_on) {
+               err = pdata->power_on(dev);
+               if (err < 0)
+                       return err;
+       }
+
        hcd = usb_create_hcd(&ohci_platform_hc_driver, &dev->dev,
                        dev_name(&dev->dev));
-       if (!hcd)
-               return -ENOMEM;
+       if (!hcd) {
+               err = -ENOMEM;
+               goto err_power;
+       }
 
        hcd->rsrc_start = res_mem->start;
        hcd->rsrc_len = resource_size(res_mem);
@@ -118,8 +130,10 @@ static int __devinit ohci_platform_probe(struct platform_device *dev)
        }
 
        hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
-       if (!hcd->regs)
+       if (!hcd->regs) {
+               err = -ENOMEM;
                goto err_release_region;
+       }
        err = usb_add_hcd(hcd, irq, IRQF_SHARED);
        if (err)
                goto err_iounmap;
@@ -134,12 +148,17 @@ err_release_region:
        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 err_put_hcd:
        usb_put_hcd(hcd);
+err_power:
+       if (pdata->power_off)
+               pdata->power_off(dev);
+
        return err;
 }
 
 static int __devexit ohci_platform_remove(struct platform_device *dev)
 {
        struct usb_hcd *hcd = platform_get_drvdata(dev);
+       struct usb_ohci_pdata *pdata = dev->dev.platform_data;
 
        usb_remove_hcd(hcd);
        iounmap(hcd->regs);
@@ -147,6 +166,9 @@ static int __devexit ohci_platform_remove(struct platform_device *dev)
        usb_put_hcd(hcd);
        platform_set_drvdata(dev, NULL);
 
+       if (pdata->power_off)
+               pdata->power_off(dev);
+
        return 0;
 }
 
@@ -154,12 +176,28 @@ static int __devexit ohci_platform_remove(struct platform_device *dev)
 
 static int ohci_platform_suspend(struct device *dev)
 {
+       struct usb_ohci_pdata *pdata = dev->platform_data;
+       struct platform_device *pdev =
+               container_of(dev, struct platform_device, dev);
+
+       if (pdata->power_suspend)
+               pdata->power_suspend(pdev);
+
        return 0;
 }
 
 static int ohci_platform_resume(struct device *dev)
 {
        struct usb_hcd *hcd = dev_get_drvdata(dev);
+       struct usb_ohci_pdata *pdata = dev->platform_data;
+       struct platform_device *pdev =
+               container_of(dev, struct platform_device, dev);
+
+       if (pdata->power_on) {
+               int err = pdata->power_on(pdev);
+               if (err < 0)
+                       return err;
+       }
 
        ohci_finish_controller_resume(hcd);
        return 0;
index e1a3cc6d28dcc0ba69917bfb7a8b92d96c10c86b..77f4402aca03e0a16a9875431df8ec51bd60e311 100644 (file)
@@ -23,6 +23,8 @@
 #include <linux/signal.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
 #include <mach/hardware.h>
 #include <mach/ohci.h>
 #include <mach/pxa3xx-u2d.h>
@@ -272,6 +274,67 @@ static void pxa27x_stop_hc(struct pxa27x_ohci *ohci, struct device *dev)
        clk_disable_unprepare(ohci->clk);
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id pxa_ohci_dt_ids[] = {
+       { .compatible = "marvell,pxa-ohci" },
+       { }
+};
+
+MODULE_DEVICE_TABLE(of, pxa_ohci_dt_ids);
+
+static u64 pxa_ohci_dma_mask = DMA_BIT_MASK(32);
+
+static int __devinit ohci_pxa_of_init(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct pxaohci_platform_data *pdata;
+       u32 tmp;
+
+       if (!np)
+               return 0;
+
+       /* Right now device-tree probed devices don't get dma_mask set.
+        * Since shared usb code relies on it, set it here for now.
+        * Once we have dma capability bindings this can go away.
+        */
+       if (!pdev->dev.dma_mask)
+               pdev->dev.dma_mask = &pxa_ohci_dma_mask;
+
+       pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return -ENOMEM;
+
+       if (of_get_property(np, "marvell,enable-port1", NULL))
+               pdata->flags |= ENABLE_PORT1;
+       if (of_get_property(np, "marvell,enable-port2", NULL))
+               pdata->flags |= ENABLE_PORT2;
+       if (of_get_property(np, "marvell,enable-port3", NULL))
+               pdata->flags |= ENABLE_PORT3;
+       if (of_get_property(np, "marvell,port-sense-low", NULL))
+               pdata->flags |= POWER_SENSE_LOW;
+       if (of_get_property(np, "marvell,power-control-low", NULL))
+               pdata->flags |= POWER_CONTROL_LOW;
+       if (of_get_property(np, "marvell,no-oc-protection", NULL))
+               pdata->flags |= NO_OC_PROTECTION;
+       if (of_get_property(np, "marvell,oc-mode-perport", NULL))
+               pdata->flags |= OC_MODE_PERPORT;
+       if (!of_property_read_u32(np, "marvell,power-on-delay", &tmp))
+               pdata->power_on_delay = tmp;
+       if (!of_property_read_u32(np, "marvell,port-mode", &tmp))
+               pdata->port_mode = tmp;
+       if (!of_property_read_u32(np, "marvell,power-budget", &tmp))
+               pdata->power_budget = tmp;
+
+       pdev->dev.platform_data = pdata;
+
+       return 0;
+}
+#else
+static int __devinit ohci_pxa_of_init(struct platform_device *pdev)
+{
+       return 0;
+}
+#endif
 
 /*-------------------------------------------------------------------------*/
 
@@ -297,6 +360,10 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device
        struct resource *r;
        struct clk *usb_clk;
 
+       retval = ohci_pxa_of_init(pdev);
+       if (retval)
+               return retval;
+
        inf = pdev->dev.platform_data;
 
        if (!inf)
@@ -544,6 +611,7 @@ static struct platform_driver ohci_hcd_pxa27x_driver = {
        .driver         = {
                .name   = "pxa27x-ohci",
                .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(pxa_ohci_dt_ids),
 #ifdef CONFIG_PM
                .pm     = &ohci_hcd_pxa27x_pm_ops,
 #endif
index df0828cb2aa328ecf06cb37cb1a6981fa41d52f3..c5e9e4a76f148d4eed0c4785cf46fb38d143a074 100644 (file)
@@ -800,6 +800,13 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev)
 }
 EXPORT_SYMBOL_GPL(usb_enable_xhci_ports);
 
+void usb_disable_xhci_ports(struct pci_dev *xhci_pdev)
+{
+       pci_write_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN, 0x0);
+       pci_write_config_dword(xhci_pdev, USB_INTEL_XUSB2PR, 0x0);
+}
+EXPORT_SYMBOL_GPL(usb_disable_xhci_ports);
+
 /**
  * PCI Quirks for xHCI.
  *
index b1002a8ef96f58fc46039d6c37b4bcca18d056cb..ef004a5de20f176c27801f83bd9ae2456570e6b1 100644 (file)
@@ -10,6 +10,7 @@ void usb_amd_quirk_pll_disable(void);
 void usb_amd_quirk_pll_enable(void);
 bool usb_is_intel_switchable_xhci(struct pci_dev *pdev);
 void usb_enable_xhci_ports(struct pci_dev *xhci_pdev);
+void usb_disable_xhci_ports(struct pci_dev *xhci_pdev);
 #else
 static inline void usb_amd_quirk_pll_disable(void) {}
 static inline void usb_amd_quirk_pll_enable(void) {}
index e4db350602b8ea639aca1a1d30a069901f0e4db8..4b9e9aba26654e3f70f5801bf2ada2438a739c94 100644 (file)
@@ -846,6 +846,11 @@ static const char hcd_name[] = "uhci_hcd";
 #define PLATFORM_DRIVER                uhci_grlib_driver
 #endif
 
+#ifdef CONFIG_USB_UHCI_PLATFORM
+#include "uhci-platform.c"
+#define PLATFORM_DRIVER                uhci_platform_driver
+#endif
+
 #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER)
 #error "missing bus glue for uhci-hcd"
 #endif
diff --git a/drivers/usb/host/uhci-platform.c b/drivers/usb/host/uhci-platform.c
new file mode 100644 (file)
index 0000000..e478049
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Generic UHCI HCD (Host Controller Driver) for Platform Devices
+ *
+ * Copyright (c) 2011 Tony Prisk <linux@prisktech.co.nz>
+ *
+ * This file is based on uhci-grlib.c
+ * (C) Copyright 2004-2007 Alan Stern, stern@rowland.harvard.edu
+ */
+
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+static int uhci_platform_init(struct usb_hcd *hcd)
+{
+       struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+
+       uhci->rh_numports = uhci_count_ports(hcd);
+
+       /* Set up pointers to to generic functions */
+       uhci->reset_hc = uhci_generic_reset_hc;
+       uhci->check_and_reset_hc = uhci_generic_check_and_reset_hc;
+
+       /* No special actions need to be taken for the functions below */
+       uhci->configure_hc = NULL;
+       uhci->resume_detect_interrupts_are_broken = NULL;
+       uhci->global_suspend_mode_is_broken = NULL;
+
+       /* Reset if the controller isn't already safely quiescent. */
+       check_and_reset_hc(uhci);
+       return 0;
+}
+
+static const struct hc_driver uhci_platform_hc_driver = {
+       .description =          hcd_name,
+       .product_desc =         "Generic UHCI Host Controller",
+       .hcd_priv_size =        sizeof(struct uhci_hcd),
+
+       /* Generic hardware linkage */
+       .irq =                  uhci_irq,
+       .flags =                HCD_MEMORY | HCD_USB11,
+
+       /* Basic lifecycle operations */
+       .reset =                uhci_platform_init,
+       .start =                uhci_start,
+#ifdef CONFIG_PM
+       .pci_suspend =          NULL,
+       .pci_resume =           NULL,
+       .bus_suspend =          uhci_rh_suspend,
+       .bus_resume =           uhci_rh_resume,
+#endif
+       .stop =                 uhci_stop,
+
+       .urb_enqueue =          uhci_urb_enqueue,
+       .urb_dequeue =          uhci_urb_dequeue,
+
+       .endpoint_disable =     uhci_hcd_endpoint_disable,
+       .get_frame_number =     uhci_hcd_get_frame_number,
+
+       .hub_status_data =      uhci_hub_status_data,
+       .hub_control =          uhci_hub_control,
+};
+
+
+static int __devinit uhci_hcd_platform_probe(struct platform_device *pdev)
+{
+       struct usb_hcd *hcd;
+       struct uhci_hcd *uhci;
+       struct resource *res;
+       int ret;
+
+       if (usb_disabled())
+               return -ENODEV;
+
+       hcd = usb_create_hcd(&uhci_platform_hc_driver, &pdev->dev,
+                       pdev->name);
+       if (!hcd)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       hcd->rsrc_start = res->start;
+       hcd->rsrc_len = resource_size(res);
+
+       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+               pr_err("%s: request_mem_region failed\n", __func__);
+               ret = -EBUSY;
+               goto err_rmr;
+       }
+
+       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+       if (!hcd->regs) {
+               pr_err("%s: ioremap failed\n", __func__);
+               ret = -ENOMEM;
+               goto err_irq;
+       }
+       uhci = hcd_to_uhci(hcd);
+
+       uhci->regs = hcd->regs;
+
+       ret = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_DISABLED |
+                                                               IRQF_SHARED);
+       if (ret)
+               goto err_uhci;
+
+       return 0;
+
+err_uhci:
+       iounmap(hcd->regs);
+err_irq:
+       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err_rmr:
+       usb_put_hcd(hcd);
+
+       return ret;
+}
+
+static int uhci_hcd_platform_remove(struct platform_device *pdev)
+{
+       struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+       usb_remove_hcd(hcd);
+       iounmap(hcd->regs);
+       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+       usb_put_hcd(hcd);
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+/* Make sure the controller is quiescent and that we're not using it
+ * any more.  This is mainly for the benefit of programs which, like kexec,
+ * expect the hardware to be idle: not doing DMA or generating IRQs.
+ *
+ * This routine may be called in a damaged or failing kernel.  Hence we
+ * do not acquire the spinlock before shutting down the controller.
+ */
+static void uhci_hcd_platform_shutdown(struct platform_device *op)
+{
+       struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
+
+       uhci_hc_died(hcd_to_uhci(hcd));
+}
+
+static const struct of_device_id platform_uhci_ids[] = {
+       { .compatible = "platform-uhci", },
+       {}
+};
+
+static struct platform_driver uhci_platform_driver = {
+       .probe          = uhci_hcd_platform_probe,
+       .remove         = uhci_hcd_platform_remove,
+       .shutdown       = uhci_hcd_platform_shutdown,
+       .driver = {
+               .name = "platform-uhci",
+               .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(platform_uhci_ids),
+       },
+};
index 1e141f755b26dd22836461a28ac0d2f1c9a7bcbd..c3a647816af0b7b690172cbf4e90799b47718dd3 100644 (file)
@@ -238,16 +238,16 @@ static struct hc_driver whc_hc_driver = {
 
 static int whc_probe(struct umc_dev *umc)
 {
-       int ret = -ENOMEM;
+       int ret;
        struct usb_hcd *usb_hcd;
-       struct wusbhc *wusbhc = NULL;
-       struct whc *whc = NULL;
+       struct wusbhc *wusbhc;
+       struct whc *whc;
        struct device *dev = &umc->dev;
 
        usb_hcd = usb_create_hcd(&whc_hc_driver, dev, "whci");
        if (usb_hcd == NULL) {
                dev_err(dev, "unable to create hcd\n");
-               goto error;
+               return -ENOMEM;
        }
 
        usb_hcd->wireless = 1;
index 76083ae9213800cf48ecc1fa2208def7c1cf4542..dc31c425ce0179551b27e2d7a900f1bb7b411ad8 100644 (file)
@@ -436,7 +436,7 @@ static int qset_add_urb_sg(struct whc *whc, struct whc_qset *qset, struct urb *u
        int i;
        int ntds = 0;
        struct whc_std *std = NULL;
-       struct whc_page_list_entry *entry;
+       struct whc_page_list_entry *new_pl_virt;
        dma_addr_t prev_end = 0;
        size_t pl_len;
        int p = 0;
@@ -508,12 +508,15 @@ static int qset_add_urb_sg(struct whc *whc, struct whc_qset *qset, struct urb *u
 
                        pl_len = std->num_pointers * sizeof(struct whc_page_list_entry);
 
-                       std->pl_virt = krealloc(std->pl_virt, pl_len, mem_flags);
-                       if (std->pl_virt == NULL) {
+                       new_pl_virt = krealloc(std->pl_virt, pl_len, mem_flags);
+                       if (new_pl_virt == NULL) {
+                               kfree(std->pl_virt);
+                               std->pl_virt = NULL;
                                return -ENOMEM;
                        }
+                       std->pl_virt = new_pl_virt;
 
-                       for (;p < std->num_pointers; p++, entry++) {
+                       for (;p < std->num_pointers; p++) {
                                std->pl_virt[p].buf_ptr = cpu_to_le64(dma_addr);
                                dma_addr = (dma_addr + WHCI_PAGE_SIZE) & ~(WHCI_PAGE_SIZE-1);
                        }
index 18b231b0c5d373afbec7efde87faed879ca26889..9bfd4ca1153c32cd51d3468608948a31a3a08953 100644 (file)
@@ -94,11 +94,21 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
                xhci->quirks |= XHCI_EP_LIMIT_QUIRK;
                xhci->limit_active_eps = 64;
                xhci->quirks |= XHCI_SW_BW_CHECKING;
+               /*
+                * PPT desktop boards DH77EB and DH77DF will power back on after
+                * a few seconds of being shutdown.  The fix for this is to
+                * switch the ports from xHCI to EHCI on shutdown.  We can't use
+                * DMI information to find those particular boards (since each
+                * vendor will change the board name), so we have to key off all
+                * PPT chipsets.
+                */
+               xhci->quirks |= XHCI_SPURIOUS_REBOOT;
        }
        if (pdev->vendor == PCI_VENDOR_ID_ETRON &&
                        pdev->device == PCI_DEVICE_ID_ASROCK_P67) {
                xhci->quirks |= XHCI_RESET_ON_RESUME;
                xhci_dbg(xhci, "QUIRK: Resetting on resume\n");
+               xhci->quirks |= XHCI_TRUST_TX_LENGTH;
        }
        if (pdev->vendor == PCI_VENDOR_ID_VIA)
                xhci->quirks |= XHCI_RESET_ON_RESUME;
index 8275645889da4ce779c08c88ac4ea06473f222e0..643c2f3f3e738e1785447fd2d8c27559e0fb0d24 100644 (file)
@@ -145,29 +145,37 @@ static void next_trb(struct xhci_hcd *xhci,
  */
 static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring)
 {
-       union xhci_trb *next;
        unsigned long long addr;
 
        ring->deq_updates++;
 
-       /* If this is not event ring, there is one more usable TRB */
+       /*
+        * If this is not event ring, and the dequeue pointer
+        * is not on a link TRB, there is one more usable TRB
+        */
        if (ring->type != TYPE_EVENT &&
                        !last_trb(xhci, ring, ring->deq_seg, ring->dequeue))
                ring->num_trbs_free++;
-       next = ++(ring->dequeue);
 
-       /* Update the dequeue pointer further if that was a link TRB or we're at
-        * the end of an event ring segment (which doesn't have link TRBS)
-        */
-       while (last_trb(xhci, ring, ring->deq_seg, next)) {
-               if (ring->type == TYPE_EVENT && last_trb_on_last_seg(xhci,
-                               ring, ring->deq_seg, next)) {
-                       ring->cycle_state = (ring->cycle_state ? 0 : 1);
+       do {
+               /*
+                * Update the dequeue pointer further if that was a link TRB or
+                * we're at the end of an event ring segment (which doesn't have
+                * link TRBS)
+                */
+               if (last_trb(xhci, ring, ring->deq_seg, ring->dequeue)) {
+                       if (ring->type == TYPE_EVENT &&
+                                       last_trb_on_last_seg(xhci, ring,
+                                               ring->deq_seg, ring->dequeue)) {
+                               ring->cycle_state = (ring->cycle_state ? 0 : 1);
+                       }
+                       ring->deq_seg = ring->deq_seg->next;
+                       ring->dequeue = ring->deq_seg->trbs;
+               } else {
+                       ring->dequeue++;
                }
-               ring->deq_seg = ring->deq_seg->next;
-               ring->dequeue = ring->deq_seg->trbs;
-               next = ring->dequeue;
-       }
+       } while (last_trb(xhci, ring, ring->deq_seg, ring->dequeue));
+
        addr = (unsigned long long) xhci_trb_virt_to_dma(ring->deq_seg, ring->dequeue);
 }
 
@@ -2073,8 +2081,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
                if (xhci->quirks & XHCI_TRUST_TX_LENGTH)
                        trb_comp_code = COMP_SHORT_TX;
                else
-                       xhci_warn(xhci, "WARN Successful completion on short TX: "
-                                       "needs XHCI_TRUST_TX_LENGTH quirk?\n");
+                       xhci_warn_ratelimited(xhci,
+                                       "WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk?\n");
        case COMP_SHORT_TX:
                break;
        case COMP_STOP:
index 7648b2d4b268182b4e9097db1bab61b97b86a0d4..c59d5b5b6c7d227a8005ca520e8b9badad5207b1 100644 (file)
@@ -166,7 +166,7 @@ int xhci_reset(struct xhci_hcd *xhci)
        xhci_writel(xhci, command, &xhci->op_regs->command);
 
        ret = handshake(xhci, &xhci->op_regs->command,
-                       CMD_RESET, 0, 250 * 1000);
+                       CMD_RESET, 0, 10 * 1000 * 1000);
        if (ret)
                return ret;
 
@@ -175,7 +175,8 @@ int xhci_reset(struct xhci_hcd *xhci)
         * xHCI cannot write to any doorbells or operational registers other
         * than status until the "Controller Not Ready" flag is cleared.
         */
-       ret = handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000);
+       ret = handshake(xhci, &xhci->op_regs->status,
+                       STS_CNR, 0, 10 * 1000 * 1000);
 
        for (i = 0; i < 2; ++i) {
                xhci->bus_state[i].port_c_suspend = 0;
@@ -658,6 +659,9 @@ void xhci_shutdown(struct usb_hcd *hcd)
 {
        struct xhci_hcd *xhci = hcd_to_xhci(hcd);
 
+       if (xhci->quirks && XHCI_SPURIOUS_REBOOT)
+               usb_disable_xhci_ports(to_pci_dev(hcd->self.controller));
+
        spin_lock_irq(&xhci->lock);
        xhci_halt(xhci);
        spin_unlock_irq(&xhci->lock);
index 55c0785810c99fb5286e29d39cd4d7ff2b98addb..c713256297acd073e7589f2fdfd936390fb8bbd0 100644 (file)
@@ -1494,6 +1494,7 @@ struct xhci_hcd {
 #define XHCI_TRUST_TX_LENGTH   (1 << 10)
 #define XHCI_LPM_SUPPORT       (1 << 11)
 #define XHCI_INTEL_HOST                (1 << 12)
+#define XHCI_SPURIOUS_REBOOT   (1 << 13)
        unsigned int            num_active_eps;
        unsigned int            limit_active_eps;
        /* There are two roothubs to keep track of bus suspend info for */
@@ -1537,6 +1538,8 @@ static inline struct usb_hcd *xhci_to_hcd(struct xhci_hcd *xhci)
        dev_err(xhci_to_hcd(xhci)->self.controller , fmt , ## args)
 #define xhci_warn(xhci, fmt, args...) \
        dev_warn(xhci_to_hcd(xhci)->self.controller , fmt , ## args)
+#define xhci_warn_ratelimited(xhci, fmt, args...) \
+       dev_warn_ratelimited(xhci_to_hcd(xhci)->self.controller , fmt , ## args)
 
 /* TODO: copied from ehci.h - can be refactored? */
 /* xHCI spec says all registers are little endian */
index a2702cbfe804c9629005184f17c78ca16918d247..80894791c02003fb8ee628e8ed722411bb174ee9 100644 (file)
@@ -868,9 +868,6 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device
 
        dbg(2, "%s: enter", __func__);
 
-       if (udev == NULL)
-               dev_info(&interface->dev, "udev is NULL.\n");
-
        /* allocate memory for our device state and initialize it */
 
        dev = kmalloc (sizeof(struct lego_usb_tower), GFP_KERNEL);
index ef0c3f9f0947a8718d5d5362ba9025df84a696fa..6259f0d99324c58e30d21c7510e186b60e61514a 100644 (file)
@@ -8,7 +8,7 @@ config USB_MUSB_HDRC
        tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
        depends on USB && USB_GADGET
        select NOP_USB_XCEIV if (ARCH_DAVINCI || MACH_OMAP3EVM || BLACKFIN)
-       select NOP_USB_XCEIV if (SOC_OMAPTI81XX || SOC_OMAPAM33XX)
+       select NOP_USB_XCEIV if (SOC_TI81XX || SOC_AM33XX)
        select TWL4030_USB if MACH_OMAP_3430SDP
        select TWL6030_USB if MACH_OMAP_4430SDP || MACH_OMAP4_PANDA
        select USB_OTG_UTILS
@@ -57,7 +57,7 @@ config USB_MUSB_AM35X
 
 config USB_MUSB_DSPS
        tristate "TI DSPS platforms"
-       depends on SOC_OMAPTI81XX || SOC_OMAPAM33XX
+       depends on SOC_TI81XX || SOC_AM33XX
 
 config USB_MUSB_BLACKFIN
        tristate "Blackfin"
index 217808d9fbe1991298da67295404d50cd71e593a..494772fc9e23ad123b7fb726fe1e0de24807b849 100644 (file)
@@ -479,9 +479,9 @@ static int __devinit dsps_create_musb_pdev(struct dsps_glue *glue, u8 id)
                ret = -ENODEV;
                goto err0;
        }
-       strcpy((u8 *)res->name, "mc");
        res->parent = NULL;
        resources[1] = *res;
+       resources[1].name = "mc";
 
        /* allocate the child platform device */
        musb = platform_device_alloc("musb-hdrc", -1);
@@ -566,27 +566,28 @@ static int __devinit dsps_probe(struct platform_device *pdev)
        }
        platform_set_drvdata(pdev, glue);
 
-       /* create the child platform device for first instances of musb */
-       ret = dsps_create_musb_pdev(glue, 0);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "failed to create child pdev\n");
-               goto err2;
-       }
-
        /* enable the usbss clocks */
        pm_runtime_enable(&pdev->dev);
 
        ret = pm_runtime_get_sync(&pdev->dev);
        if (ret < 0) {
                dev_err(&pdev->dev, "pm_runtime_get_sync FAILED");
+               goto err2;
+       }
+
+       /* create the child platform device for first instances of musb */
+       ret = dsps_create_musb_pdev(glue, 0);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "failed to create child pdev\n");
                goto err3;
        }
 
        return 0;
 
 err3:
-       pm_runtime_disable(&pdev->dev);
+       pm_runtime_put(&pdev->dev);
 err2:
+       pm_runtime_disable(&pdev->dev);
        kfree(glue->wrp);
 err1:
        kfree(glue);
index 8c9bb1ad30698b58f8949d7cdc0ca048492f5d62..681da06170c29273045b9602f9b63a873cacf8c0 100644 (file)
@@ -603,12 +603,12 @@ static int usbhsc_resume(struct device *dev)
        struct usbhs_priv *priv = dev_get_drvdata(dev);
        struct platform_device *pdev = usbhs_priv_to_pdev(priv);
 
-       usbhs_platform_call(priv, phy_reset, pdev);
-
        if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL))
                usbhsc_power_ctrl(priv, 1);
 
-       usbhsc_hotplug(priv);
+       usbhs_platform_call(priv, phy_reset, pdev);
+
+       usbhsc_drvcllbck_notify_hotplug(pdev);
 
        return 0;
 }
index 1834cf50888cbc8a6832e5250a8ccd8dbdddaee5..9b69a132329474052486e0483649b6c64a746a4f 100644 (file)
@@ -1266,6 +1266,12 @@ static int usbhsh_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
        return ret;
 }
 
+static int usbhsh_bus_nop(struct usb_hcd *hcd)
+{
+       /* nothing to do */
+       return 0;
+}
+
 static struct hc_driver usbhsh_driver = {
        .description =          usbhsh_hcd_name,
        .hcd_priv_size =        sizeof(struct usbhsh_hpriv),
@@ -1290,6 +1296,8 @@ static struct hc_driver usbhsh_driver = {
         */
        .hub_status_data =      usbhsh_hub_status_data,
        .hub_control =          usbhsh_hub_control,
+       .bus_suspend =          usbhsh_bus_nop,
+       .bus_resume =           usbhsh_bus_nop,
 };
 
 /*
index f8ce97d8b0ad3c5beb79868a35b0dbfe8495368c..3b98fb733362d21ad994f6f5a7950312d78e2f1b 100644 (file)
@@ -215,7 +215,7 @@ static void ark3116_release(struct usb_serial *serial)
 
 static void ark3116_init_termios(struct tty_struct *tty)
 {
-       struct ktermios *termios = tty->termios;
+       struct ktermios *termios = &tty->termios;
        *termios = tty_std_termios;
        termios->c_cflag = B9600 | CS8
                                      | CREAD | HUPCL | CLOCAL;
@@ -229,7 +229,7 @@ static void ark3116_set_termios(struct tty_struct *tty,
 {
        struct usb_serial *serial = port->serial;
        struct ark3116_private *priv = usb_get_serial_port_data(port);
-       struct ktermios *termios = tty->termios;
+       struct ktermios *termios = &tty->termios;
        unsigned int cflag = termios->c_cflag;
        int bps = tty_get_baud_rate(tty);
        int quot;
index 6b7365632951c6c8735c25fcec0c69aa9a8026c8..a46df73ee96e34310f9a1640d6c88cd89c3be09c 100644 (file)
@@ -307,7 +307,7 @@ static void belkin_sa_set_termios(struct tty_struct *tty,
        unsigned long control_state;
        int bad_flow_control;
        speed_t baud;
-       struct ktermios *termios = tty->termios;
+       struct ktermios *termios = &tty->termios;
 
        iflag = termios->c_iflag;
        cflag = termios->c_cflag;
index f398d1e34474c34084b43dac6702a6378f71a970..c15f2e7cefc77e4782dfb39fcedc54e5b0bc6329 100644 (file)
@@ -61,18 +61,23 @@ static int usb_serial_device_probe(struct device *dev)
                goto exit;
        }
 
+       /* make sure suspend/resume doesn't race against port_probe */
+       retval = usb_autopm_get_interface(port->serial->interface);
+       if (retval)
+               goto exit;
+
        driver = port->serial->type;
        if (driver->port_probe) {
                retval = driver->port_probe(port);
                if (retval)
-                       goto exit;
+                       goto exit_with_autopm;
        }
 
        retval = device_create_file(dev, &dev_attr_port_number);
        if (retval) {
                if (driver->port_remove)
                        retval = driver->port_remove(port);
-               goto exit;
+               goto exit_with_autopm;
        }
 
        minor = port->number;
@@ -81,6 +86,8 @@ static int usb_serial_device_probe(struct device *dev)
                 "%s converter now attached to ttyUSB%d\n",
                 driver->description, minor);
 
+exit_with_autopm:
+       usb_autopm_put_interface(port->serial->interface);
 exit:
        return retval;
 }
@@ -96,6 +103,9 @@ static int usb_serial_device_remove(struct device *dev)
        if (!port)
                return -ENODEV;
 
+       /* make sure suspend/resume doesn't race against port_remove */
+       usb_autopm_get_interface(port->serial->interface);
+
        device_remove_file(&port->dev, &dev_attr_port_number);
 
        driver = port->serial->type;
@@ -107,6 +117,7 @@ static int usb_serial_device_remove(struct device *dev)
        dev_info(dev, "%s converter now disconnected from ttyUSB%d\n",
                 driver->description, minor);
 
+       usb_autopm_put_interface(port->serial->interface);
        return retval;
 }
 
index b9cca6dcde07a8f341f198ef694bf76adce24f32..9a564286bfd75db516d117f30921e2730eab4529 100644 (file)
@@ -165,8 +165,8 @@ static int usb_console_setup(struct console *co, char *options)
                }
 
                if (serial->type->set_termios) {
-                       tty->termios->c_cflag = cflag;
-                       tty_termios_encode_baud_rate(tty->termios, baud, baud);
+                       tty->termios.c_cflag = cflag;
+                       tty_termios_encode_baud_rate(&tty->termios, baud, baud);
                        memset(&dummy, 0, sizeof(struct ktermios));
                        serial->type->set_termios(tty, port, &dummy);
 
index 1e71079ce33b7128c116f602d865428297804da7..ba5e07e188a0aa585aee873a7377e73e5b15385e 100644 (file)
@@ -469,7 +469,7 @@ static void cp210x_get_termios(struct tty_struct *tty,
 
        if (tty) {
                cp210x_get_termios_port(tty->driver_data,
-                       &tty->termios->c_cflag, &baud);
+                       &tty->termios.c_cflag, &baud);
                tty_encode_baud_rate(tty, baud, baud);
        }
 
@@ -631,7 +631,7 @@ static void cp210x_change_speed(struct tty_struct *tty,
 {
        u32 baud;
 
-       baud = tty->termios->c_ospeed;
+       baud = tty->termios.c_ospeed;
 
        /* This maps the requested rate to a rate valid on cp2102 or cp2103,
         * or to an arbitrary rate in [1M,2M].
@@ -665,10 +665,10 @@ static void cp210x_set_termios(struct tty_struct *tty,
        if (!tty)
                return;
 
-       cflag = tty->termios->c_cflag;
+       cflag = tty->termios.c_cflag;
        old_cflag = old_termios->c_cflag;
 
-       if (tty->termios->c_ospeed != old_termios->c_ospeed)
+       if (tty->termios.c_ospeed != old_termios->c_ospeed)
                cp210x_change_speed(tty, port, old_termios);
 
        /* If the number of data bits is to be updated */
index b78c34eb5d3f6f976aac101eb15094e8f99370e4..be34f153e56616462aa686611e284e492d1bc60b 100644 (file)
@@ -922,38 +922,38 @@ static void cypress_set_termios(struct tty_struct *tty,
           early enough */
        if (!priv->termios_initialized) {
                if (priv->chiptype == CT_EARTHMATE) {
-                       *(tty->termios) = tty_std_termios;
-                       tty->termios->c_cflag = B4800 | CS8 | CREAD | HUPCL |
+                       tty->termios = tty_std_termios;
+                       tty->termios.c_cflag = B4800 | CS8 | CREAD | HUPCL |
                                CLOCAL;
-                       tty->termios->c_ispeed = 4800;
-                       tty->termios->c_ospeed = 4800;
+                       tty->termios.c_ispeed = 4800;
+                       tty->termios.c_ospeed = 4800;
                } else if (priv->chiptype == CT_CYPHIDCOM) {
-                       *(tty->termios) = tty_std_termios;
-                       tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL |
+                       tty->termios = tty_std_termios;
+                       tty->termios.c_cflag = B9600 | CS8 | CREAD | HUPCL |
                                CLOCAL;
-                       tty->termios->c_ispeed = 9600;
-                       tty->termios->c_ospeed = 9600;
+                       tty->termios.c_ispeed = 9600;
+                       tty->termios.c_ospeed = 9600;
                } else if (priv->chiptype == CT_CA42V2) {
-                       *(tty->termios) = tty_std_termios;
-                       tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL |
+                       tty->termios = tty_std_termios;
+                       tty->termios.c_cflag = B9600 | CS8 | CREAD | HUPCL |
                                CLOCAL;
-                       tty->termios->c_ispeed = 9600;
-                       tty->termios->c_ospeed = 9600;
+                       tty->termios.c_ispeed = 9600;
+                       tty->termios.c_ospeed = 9600;
                }
                priv->termios_initialized = 1;
        }
        spin_unlock_irqrestore(&priv->lock, flags);
 
        /* Unsupported features need clearing */
-       tty->termios->c_cflag &= ~(CMSPAR|CRTSCTS);
+       tty->termios.c_cflag &= ~(CMSPAR|CRTSCTS);
 
-       cflag = tty->termios->c_cflag;
-       iflag = tty->termios->c_iflag;
+       cflag = tty->termios.c_cflag;
+       iflag = tty->termios.c_iflag;
 
        /* check if there are new settings */
        if (old_termios) {
                spin_lock_irqsave(&priv->lock, flags);
-               priv->tmp_termios = *(tty->termios);
+               priv->tmp_termios = tty->termios;
                spin_unlock_irqrestore(&priv->lock, flags);
        }
 
@@ -1021,7 +1021,7 @@ static void cypress_set_termios(struct tty_struct *tty,
                                "4800bps.");
                /* define custom termios settings for NMEA protocol */
 
-               tty->termios->c_iflag /* input modes - */
+               tty->termios.c_iflag /* input modes - */
                        &= ~(IGNBRK  /* disable ignore break */
                        | BRKINT     /* disable break causes interrupt */
                        | PARMRK     /* disable mark parity errors */
@@ -1031,10 +1031,10 @@ static void cypress_set_termios(struct tty_struct *tty,
                        | ICRNL      /* disable translate CR to NL */
                        | IXON);     /* disable enable XON/XOFF flow control */
 
-               tty->termios->c_oflag /* output modes */
+               tty->termios.c_oflag /* output modes */
                        &= ~OPOST;    /* disable postprocess output char */
 
-               tty->termios->c_lflag /* line discipline modes */
+               tty->termios.c_lflag /* line discipline modes */
                        &= ~(ECHO     /* disable echo input characters */
                        | ECHONL      /* disable echo new line */
                        | ICANON      /* disable erase, kill, werase, and rprnt
@@ -1200,7 +1200,7 @@ static void cypress_read_int_callback(struct urb *urb)
 
        /* hangup, as defined in acm.c... this might be a bad place for it
         * though */
-       if (tty && !(tty->termios->c_cflag & CLOCAL) &&
+       if (tty && !(tty->termios.c_cflag & CLOCAL) &&
                        !(priv->current_status & UART_CD)) {
                dbg("%s - calling hangup", __func__);
                tty_hangup(tty);
index b5cd838093ef58be7129ff9f78bcb814fc697da0..afd9d2ec577ba02f32afbe4e396252643e29ec0d 100644 (file)
@@ -687,8 +687,8 @@ static void digi_set_termios(struct tty_struct *tty,
                struct usb_serial_port *port, struct ktermios *old_termios)
 {
        struct digi_port *priv = usb_get_serial_port_data(port);
-       unsigned int iflag = tty->termios->c_iflag;
-       unsigned int cflag = tty->termios->c_cflag;
+       unsigned int iflag = tty->termios.c_iflag;
+       unsigned int cflag = tty->termios.c_cflag;
        unsigned int old_iflag = old_termios->c_iflag;
        unsigned int old_cflag = old_termios->c_cflag;
        unsigned char buf[32];
@@ -709,7 +709,7 @@ static void digi_set_termios(struct tty_struct *tty,
                        /* don't set RTS if using hardware flow control */
                        /* and throttling input */
                        modem_signals = TIOCM_DTR;
-                       if (!(tty->termios->c_cflag & CRTSCTS) ||
+                       if (!(tty->termios.c_cflag & CRTSCTS) ||
                            !test_bit(TTY_THROTTLED, &tty->flags))
                                modem_signals |= TIOCM_RTS;
                        digi_set_modem_signals(port, modem_signals, 1);
@@ -748,7 +748,7 @@ static void digi_set_termios(struct tty_struct *tty,
                }
        }
        /* set parity */
-       tty->termios->c_cflag &= ~CMSPAR;
+       tty->termios.c_cflag &= ~CMSPAR;
 
        if ((cflag&(PARENB|PARODD)) != (old_cflag&(PARENB|PARODD))) {
                if (cflag&PARENB) {
@@ -1124,8 +1124,8 @@ static int digi_open(struct tty_struct *tty, struct usb_serial_port *port)
 
        /* set termios settings */
        if (tty) {
-               not_termios.c_cflag = ~tty->termios->c_cflag;
-               not_termios.c_iflag = ~tty->termios->c_iflag;
+               not_termios.c_cflag = ~tty->termios.c_cflag;
+               not_termios.c_iflag = ~tty->termios.c_iflag;
                digi_set_termios(tty, port, &not_termios);
        }
        return 0;
@@ -1500,7 +1500,7 @@ static int digi_read_oob_callback(struct urb *urb)
 
                rts = 0;
                if (tty)
-                       rts = tty->termios->c_cflag & CRTSCTS;
+                       rts = tty->termios.c_cflag & CRTSCTS;
                
                if (tty && opcode == DIGI_CMD_READ_INPUT_SIGNALS) {
                        spin_lock(&priv->dp_port_lock);
index cdf61dd0731837fb0acf62fc6cd44f0a199ef38f..34e86383090a846e2f843a716ff047bde9c59390 100644 (file)
@@ -87,7 +87,7 @@ static int empeg_startup(struct usb_serial *serial)
 
 static void empeg_init_termios(struct tty_struct *tty)
 {
-       struct ktermios *termios = tty->termios;
+       struct ktermios *termios = &tty->termios;
 
        /*
         * The empeg-car player wants these particular tty settings.
index 499b15fd82f162e788afefba9ec50271f9cf94d0..79451ee12ca08c451e4c2ad75f25823126ffce69 100644 (file)
@@ -173,10 +173,11 @@ static void f81232_set_termios(struct tty_struct *tty,
        /* FIXME - Stubbed out for now */
 
        /* Don't change anything if nothing has changed */
-       if (!tty_termios_hw_change(tty->termios, old_termios))
+       if (!tty_termios_hw_change(&tty->termios, old_termios))
                return;
 
        /* Do the real work here... */
+       tty_termios_copy_hw(&tty->termios, old_termios);
 }
 
 static int f81232_tiocmget(struct tty_struct *tty)
index bc912e5a3bebddf3073fe17e015b6195be3708be..b7016b6a3bef564fd285c58408fdf912469a64a2 100644 (file)
@@ -811,6 +811,7 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(LARSENBRUSGAARD_VID, LB_ALTITRACK_PID) },
        { USB_DEVICE(GN_OTOMETRICS_VID, AURICAL_USB_PID) },
        { USB_DEVICE(PI_VID, PI_E861_PID) },
+       { USB_DEVICE(KONDO_VID, KONDO_USB_SERIAL_PID) },
        { USB_DEVICE(BAYER_VID, BAYER_CONTOUR_CABLE_PID) },
        { USB_DEVICE(FTDI_VID, MARVELL_OPENRD_PID),
                .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
@@ -2081,7 +2082,7 @@ static void ftdi_set_termios(struct tty_struct *tty,
 {
        struct usb_device *dev = port->serial->dev;
        struct ftdi_private *priv = usb_get_serial_port_data(port);
-       struct ktermios *termios = tty->termios;
+       struct ktermios *termios = &tty->termios;
        unsigned int cflag = termios->c_cflag;
        __u16 urb_value; /* will hold the new flags */
 
@@ -2106,7 +2107,7 @@ static void ftdi_set_termios(struct tty_struct *tty,
 
        cflag = termios->c_cflag;
 
-       if (old_termios == 0)
+       if (!old_termios)
                goto no_skip;
 
        if (old_termios->c_cflag == termios->c_cflag
index 5661c7e2d4151cbb8f2335c4572f83fc3deccff8..5dd96ca6c380a0971921d198e12399e1902663db 100644 (file)
 #define PI_VID              0x1a72  /* Vendor ID */
 #define PI_E861_PID         0x1008  /* E-861 piezo controller USB connection */
 
+/*
+ * Kondo Kagaku Co.Ltd.
+ * http://www.kondo-robot.com/EN
+ */
+#define KONDO_VID              0x165c
+#define KONDO_USB_SERIAL_PID   0x0002
+
 /*
  * Bayer Ascensia Contour blood glucose meter USB-converter cable.
  * http://winglucofacts.com/cables/
index e1f5ccd1e8f8c64a49e12d9ff3463d60e4f9fb01..f435575c4e6e256382d29e6eff05c5c0c00293d6 100644 (file)
@@ -1458,7 +1458,7 @@ static void edge_throttle(struct tty_struct *tty)
        }
 
        /* if we are implementing RTS/CTS, toggle that line */
-       if (tty->termios->c_cflag & CRTSCTS) {
+       if (tty->termios.c_cflag & CRTSCTS) {
                edge_port->shadowMCR &= ~MCR_RTS;
                status = send_cmd_write_uart_register(edge_port, MCR,
                                                        edge_port->shadowMCR);
@@ -1497,7 +1497,7 @@ static void edge_unthrottle(struct tty_struct *tty)
                        return;
        }
        /* if we are implementing RTS/CTS, toggle that line */
-       if (tty->termios->c_cflag & CRTSCTS) {
+       if (tty->termios.c_cflag & CRTSCTS) {
                edge_port->shadowMCR |= MCR_RTS;
                send_cmd_write_uart_register(edge_port, MCR,
                                                edge_port->shadowMCR);
@@ -1516,9 +1516,9 @@ static void edge_set_termios(struct tty_struct *tty,
        struct edgeport_port *edge_port = usb_get_serial_port_data(port);
        unsigned int cflag;
 
-       cflag = tty->termios->c_cflag;
+       cflag = tty->termios.c_cflag;
        dbg("%s - clfag %08x iflag %08x", __func__,
-           tty->termios->c_cflag, tty->termios->c_iflag);
+           tty->termios.c_cflag, tty->termios.c_iflag);
        dbg("%s - old clfag %08x old iflag %08x", __func__,
            old_termios->c_cflag, old_termios->c_iflag);
 
@@ -1987,7 +1987,7 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial,
                tty = tty_port_tty_get(&edge_port->port->port);
                if (tty) {
                        change_port_settings(tty,
-                               edge_port, tty->termios);
+                               edge_port, &tty->termios);
                        tty_kref_put(tty);
                }
 
@@ -2570,7 +2570,7 @@ static void change_port_settings(struct tty_struct *tty,
                return;
        }
 
-       cflag = tty->termios->c_cflag;
+       cflag = tty->termios.c_cflag;
 
        switch (cflag & CSIZE) {
        case CS5:
index 3936904c641969cd4566ba88ee5dc39d8912e6b9..765978ae752ec6b7991154b6fe193029278f8bd9 100644 (file)
@@ -1870,7 +1870,7 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)
 
        /* set up the port settings */
        if (tty)
-               edge_set_termios(tty, port, tty->termios);
+               edge_set_termios(tty, port, &tty->termios);
 
        /* open up the port */
 
@@ -2272,13 +2272,13 @@ static void change_port_settings(struct tty_struct *tty,
 
        config = kmalloc (sizeof (*config), GFP_KERNEL);
        if (!config) {
-               *tty->termios = *old_termios;
+               tty->termios = *old_termios;
                dev_err(&edge_port->port->dev, "%s - out of memory\n",
                                                                __func__);
                return;
        }
 
-       cflag = tty->termios->c_cflag;
+       cflag = tty->termios.c_cflag;
 
        config->wFlags = 0;
 
@@ -2362,7 +2362,7 @@ static void change_port_settings(struct tty_struct *tty,
        } else
                dbg("%s - OUTBOUND XON/XOFF is disabled", __func__);
 
-       tty->termios->c_cflag &= ~CMSPAR;
+       tty->termios.c_cflag &= ~CMSPAR;
 
        /* Round the baud rate */
        baud = tty_get_baud_rate(tty);
@@ -2408,10 +2408,10 @@ static void edge_set_termios(struct tty_struct *tty,
        struct edgeport_port *edge_port = usb_get_serial_port_data(port);
        unsigned int cflag;
 
-       cflag = tty->termios->c_cflag;
+       cflag = tty->termios.c_cflag;
 
        dbg("%s - clfag %08x iflag %08x", __func__,
-           tty->termios->c_cflag, tty->termios->c_iflag);
+           tty->termios.c_cflag, tty->termios.c_iflag);
        dbg("%s - old clfag %08x old iflag %08x", __func__,
            old_termios->c_cflag, old_termios->c_iflag);
        dbg("%s - port %d", __func__, port->number);
index 5811d34b6c6bc514fb8474cc9662ad9521471a72..2cb30c535839db429c0165a76be26afdf84063cb 100644 (file)
@@ -227,7 +227,6 @@ static void ipw_release(struct usb_serial *serial)
 {
        struct usb_wwan_intf_private *data = usb_get_serial_data(serial);
 
-       usb_wwan_release(serial);
        usb_set_serial_data(serial, NULL);
        kfree(data);
 }
@@ -309,12 +308,12 @@ static struct usb_serial_driver ipw_device = {
        .description =          "IPWireless converter",
        .id_table =             id_table,
        .num_ports =            1,
-       .disconnect =           usb_wwan_disconnect,
        .open =                 ipw_open,
        .close =                ipw_close,
        .probe =                ipw_probe,
        .attach =               usb_wwan_startup,
        .release =              ipw_release,
+       .port_remove =          usb_wwan_port_remove,
        .dtr_rts =              ipw_dtr_rts,
        .write =                usb_wwan_write,
 };
index fc09414c960f045767446ee4a36f4001235700fd..5a96692b12a21235915dd7ba91a8071ff0711f04 100644 (file)
@@ -381,7 +381,7 @@ static void ir_set_termios(struct tty_struct *tty,
                ir_xbof = ir_xbof_change(xbof) ;
 
        /* Only speed changes are supported */
-       tty_termios_copy_hw(tty->termios, old_termios);
+       tty_termios_copy_hw(&tty->termios, old_termios);
        tty_encode_baud_rate(tty, baud, baud);
 
        /*
index 22b1eb5040b7648815be691e215bcfe306cb2d78..bf3864045c1842291d38dc42bd7f536c4413f214 100644 (file)
@@ -921,7 +921,7 @@ static void iuu_set_termios(struct tty_struct *tty,
 {
        const u32 supported_mask = CMSPAR|PARENB|PARODD;
        struct iuu_private *priv = usb_get_serial_port_data(port);
-       unsigned int cflag = tty->termios->c_cflag;
+       unsigned int cflag = tty->termios.c_cflag;
        int status;
        u32 actual;
        u32 parity;
@@ -930,7 +930,7 @@ static void iuu_set_termios(struct tty_struct *tty,
        u32 newval = cflag & supported_mask;
 
        /* Just use the ospeed. ispeed should be the same. */
-       baud = tty->termios->c_ospeed;
+       baud = tty->termios.c_ospeed;
 
        dbg("%s - enter c_ospeed or baud=%d", __func__, baud);
 
@@ -961,13 +961,13 @@ static void iuu_set_termios(struct tty_struct *tty,
         * settings back over and then adjust them
         */
        if (old_termios)
-               tty_termios_copy_hw(tty->termios, old_termios);
+               tty_termios_copy_hw(&tty->termios, old_termios);
        if (status != 0)        /* Set failed - return old bits */
                return;
        /* Re-encode speed, parity and csize */
        tty_encode_baud_rate(tty, baud, baud);
-       tty->termios->c_cflag &= ~(supported_mask|CSIZE);
-       tty->termios->c_cflag |= newval | csize;
+       tty->termios.c_cflag &= ~(supported_mask|CSIZE);
+       tty->termios.c_cflag |= newval | csize;
 }
 
 static void iuu_close(struct usb_serial_port *port)
@@ -993,14 +993,14 @@ static void iuu_close(struct usb_serial_port *port)
 
 static void iuu_init_termios(struct tty_struct *tty)
 {
-       *(tty->termios) = tty_std_termios;
-       tty->termios->c_cflag = CLOCAL | CREAD | CS8 | B9600
+       tty->termios = tty_std_termios;
+       tty->termios.c_cflag = CLOCAL | CREAD | CS8 | B9600
                                | TIOCM_CTS | CSTOPB | PARENB;
-       tty->termios->c_ispeed = 9600;
-       tty->termios->c_ospeed = 9600;
-       tty->termios->c_lflag = 0;
-       tty->termios->c_oflag = 0;
-       tty->termios->c_iflag = 0;
+       tty->termios.c_ispeed = 9600;
+       tty->termios.c_ospeed = 9600;
+       tty->termios.c_lflag = 0;
+       tty->termios.c_oflag = 0;
+       tty->termios.c_iflag = 0;
 }
 
 static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port)
@@ -1012,8 +1012,8 @@ static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port)
        u32 actual;
        struct iuu_private *priv = usb_get_serial_port_data(port);
 
-       baud = tty->termios->c_ospeed;
-       tty->termios->c_ispeed = baud;
+       baud = tty->termios.c_ospeed;
+       tty->termios.c_ispeed = baud;
        /* Re-encode speed */
        tty_encode_baud_rate(tty, baud, baud);
 
index af0b70eaf032f6617c36b596ce70776842a20d9f..7bcbb47e1449a83b210f9d280d5f60c965607641 100644 (file)
@@ -158,7 +158,7 @@ static void keyspan_set_termios(struct tty_struct *tty,
 
        p_priv = usb_get_serial_port_data(port);
        d_details = p_priv->device_details;
-       cflag = tty->termios->c_cflag;
+       cflag = tty->termios.c_cflag;
        device_port = port->number - port->serial->minor;
 
        /* Baud rate calculation takes baud rate as an integer
@@ -179,7 +179,7 @@ static void keyspan_set_termios(struct tty_struct *tty,
        p_priv->flow_control = (cflag & CRTSCTS) ? flow_cts : flow_none;
 
        /* Mark/Space not supported */
-       tty->termios->c_cflag &= ~CMSPAR;
+       tty->termios.c_cflag &= ~CMSPAR;
 
        keyspan_send_setup(port, 0);
 }
@@ -1086,7 +1086,7 @@ static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port)
 
        device_port = port->number - port->serial->minor;
        if (tty) {
-               cflag = tty->termios->c_cflag;
+               cflag = tty->termios.c_cflag;
                /* Baud rate calculation takes baud rate as an integer
                   so other rates can be generated if desired. */
                baud_rate = tty_get_baud_rate(tty);
index a4ac3cfeffc4b84d6fa8ac41236bad5f2bf6e724..dcada8615fcf851eab023134ee7d5215d17f4c0b 100644 (file)
@@ -338,7 +338,7 @@ static void keyspan_pda_set_termios(struct tty_struct *tty,
           7[EOMS]1: 10 bit, b0/b7 is parity
           7[EOMS]2: 11 bit, b0/b7 is parity, extra bit always (mark?)
 
-          HW flow control is dictated by the tty->termios->c_cflags & CRTSCTS
+          HW flow control is dictated by the tty->termios.c_cflags & CRTSCTS
           bit.
 
           For now, just do baud. */
@@ -353,7 +353,7 @@ static void keyspan_pda_set_termios(struct tty_struct *tty,
        }
        /* Only speed can change so copy the old h/w parameters
           then encode the new speed */
-       tty_termios_copy_hw(tty->termios, old_termios);
+       tty_termios_copy_hw(&tty->termios, old_termios);
        tty_encode_baud_rate(tty, speed, speed);
 }
 
index 5bed59cd5776d097e210944ed51339c53564faeb..def9ad2587157ebc7c0cb856da5a23f96d314f9f 100644 (file)
@@ -311,12 +311,12 @@ static int  klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port)
 
        /* set up termios structure */
        spin_lock_irqsave(&priv->lock, flags);
-       priv->termios.c_iflag = tty->termios->c_iflag;
-       priv->termios.c_oflag = tty->termios->c_oflag;
-       priv->termios.c_cflag = tty->termios->c_cflag;
-       priv->termios.c_lflag = tty->termios->c_lflag;
+       priv->termios.c_iflag = tty->termios.c_iflag;
+       priv->termios.c_oflag = tty->termios.c_oflag;
+       priv->termios.c_cflag = tty->termios.c_cflag;
+       priv->termios.c_lflag = tty->termios.c_lflag;
        for (i = 0; i < NCCS; i++)
-               priv->termios.c_cc[i] = tty->termios->c_cc[i];
+               priv->termios.c_cc[i] = tty->termios.c_cc[i];
        priv->cfg.pktlen   = cfg->pktlen;
        priv->cfg.baudrate = cfg->baudrate;
        priv->cfg.databits = cfg->databits;
@@ -445,9 +445,9 @@ static void klsi_105_set_termios(struct tty_struct *tty,
                                 struct ktermios *old_termios)
 {
        struct klsi_105_private *priv = usb_get_serial_port_data(port);
-       unsigned int iflag = tty->termios->c_iflag;
+       unsigned int iflag = tty->termios.c_iflag;
        unsigned int old_iflag = old_termios->c_iflag;
-       unsigned int cflag = tty->termios->c_cflag;
+       unsigned int cflag = tty->termios.c_cflag;
        unsigned int old_cflag = old_termios->c_cflag;
        struct klsi_105_port_settings *cfg;
        unsigned long flags;
@@ -560,7 +560,7 @@ static void klsi_105_set_termios(struct tty_struct *tty,
        if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD))
            || (cflag & CSTOPB) != (old_cflag & CSTOPB)) {
                /* Not currently supported */
-               tty->termios->c_cflag &= ~(PARENB|PARODD|CSTOPB);
+               tty->termios.c_cflag &= ~(PARENB|PARODD|CSTOPB);
 #if 0
                priv->last_lcr = 0;
 
@@ -587,7 +587,7 @@ static void klsi_105_set_termios(struct tty_struct *tty,
            || (iflag & IXON) != (old_iflag & IXON)
            ||  (cflag & CRTSCTS) != (old_cflag & CRTSCTS)) {
                /* Not currently supported */
-               tty->termios->c_cflag &= ~CRTSCTS;
+               tty->termios.c_cflag &= ~CRTSCTS;
                /* Drop DTR/RTS if no flow control otherwise assert */
 #if 0
                if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS))
index fafeabb64c553152946618f6f65d37d46131f2fd..bf5c74965d3467603066511d8259600559a6a043 100644 (file)
@@ -191,11 +191,11 @@ static void kobil_release(struct usb_serial *serial)
 static void kobil_init_termios(struct tty_struct *tty)
 {
        /* Default to echo off and other sane device settings */
-       tty->termios->c_lflag = 0;
-       tty->termios->c_lflag &= ~(ISIG | ICANON | ECHO | IEXTEN | XCASE);
-       tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF;
+       tty->termios.c_lflag = 0;
+       tty->termios.c_iflag &= ~(ISIG | ICANON | ECHO | IEXTEN | XCASE);
+       tty->termios.c_iflag |= IGNBRK | IGNPAR | IXOFF;
        /* do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D) */
-       tty->termios->c_oflag &= ~ONLCR;
+       tty->termios.c_oflag &= ~ONLCR;
 }
 
 static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port)
@@ -581,14 +581,14 @@ static void kobil_set_termios(struct tty_struct *tty,
        struct kobil_private *priv;
        int result;
        unsigned short urb_val = 0;
-       int c_cflag = tty->termios->c_cflag;
+       int c_cflag = tty->termios.c_cflag;
        speed_t speed;
 
        priv = usb_get_serial_port_data(port);
        if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID ||
                        priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID) {
                /* This device doesn't support ioctl calls */
-               *tty->termios = *old;
+               tty_termios_copy_hw(&tty->termios, old);
                return;
        }
 
@@ -612,7 +612,7 @@ static void kobil_set_termios(struct tty_struct *tty,
                        urb_val |= SUSBCR_SPASB_EvenParity;
        } else
                urb_val |= SUSBCR_SPASB_NoParity;
-       tty->termios->c_cflag &= ~CMSPAR;
+       tty->termios.c_cflag &= ~CMSPAR;
        tty_encode_baud_rate(tty, speed, speed);
 
        result = usb_control_msg(port->serial->dev,
index a71fa0aa04066dd38758fe35c87cf007a3b55f4a..df98cffdba65532927997ab8536a2618d1befbc3 100644 (file)
@@ -454,7 +454,7 @@ static int  mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port)
         * either.
         */
        spin_lock_irqsave(&priv->lock, flags);
-       if (tty && (tty->termios->c_cflag & CBAUD))
+       if (tty && (tty->termios.c_cflag & CBAUD))
                priv->control_state = TIOCM_DTR | TIOCM_RTS;
        else
                priv->control_state = 0;
@@ -634,7 +634,7 @@ static void mct_u232_set_termios(struct tty_struct *tty,
 {
        struct usb_serial *serial = port->serial;
        struct mct_u232_private *priv = usb_get_serial_port_data(port);
-       struct ktermios *termios = tty->termios;
+       struct ktermios *termios = &tty->termios;
        unsigned int cflag = termios->c_cflag;
        unsigned int old_cflag = old_termios->c_cflag;
        unsigned long flags;
index d47eb06fe463b51463cb899659a5f2428d5bd24b..2b0627b5fe2c357bdd8f82601001b23a04d56d97 100644 (file)
@@ -130,12 +130,6 @@ static void metrousb_read_int_callback(struct urb *urb)
 
        /* Set the data read from the usb port into the serial port buffer. */
        tty = tty_port_tty_get(&port->port);
-       if (!tty) {
-               dev_err(&port->dev, "%s - bad tty pointer - exiting\n",
-                       __func__);
-               return;
-       }
-
        if (tty && urb->actual_length) {
                /* Loop through the data copying each byte to the tty layer. */
                tty_insert_flip_string(tty, data, urb->actual_length);
index a07dd3c8cfef3e408fbaa4bba593267621ccec71..012f67b2e4cc2eb50145c3b7b2f9ff1f4fcf5e82 100644 (file)
@@ -1349,7 +1349,7 @@ static void mos7720_throttle(struct tty_struct *tty)
        }
 
        /* if we are implementing RTS/CTS, toggle that line */
-       if (tty->termios->c_cflag & CRTSCTS) {
+       if (tty->termios.c_cflag & CRTSCTS) {
                mos7720_port->shadowMCR &= ~UART_MCR_RTS;
                write_mos_reg(port->serial, port->number - port->serial->minor,
                              MCR, mos7720_port->shadowMCR);
@@ -1383,7 +1383,7 @@ static void mos7720_unthrottle(struct tty_struct *tty)
        }
 
        /* if we are implementing RTS/CTS, toggle that line */
-       if (tty->termios->c_cflag & CRTSCTS) {
+       if (tty->termios.c_cflag & CRTSCTS) {
                mos7720_port->shadowMCR |= UART_MCR_RTS;
                write_mos_reg(port->serial, port->number - port->serial->minor,
                              MCR, mos7720_port->shadowMCR);
@@ -1604,8 +1604,8 @@ static void change_port_settings(struct tty_struct *tty,
        lStop = 0x00;   /* 1 stop bit */
        lParity = 0x00; /* No parity */
 
-       cflag = tty->termios->c_cflag;
-       iflag = tty->termios->c_iflag;
+       cflag = tty->termios.c_cflag;
+       iflag = tty->termios.c_iflag;
 
        /* Change the number of bits */
        switch (cflag & CSIZE) {
@@ -1753,11 +1753,11 @@ static void mos7720_set_termios(struct tty_struct *tty,
 
        dbg("%s\n", "setting termios - ASPIRE");
 
-       cflag = tty->termios->c_cflag;
+       cflag = tty->termios.c_cflag;
 
        dbg("%s - cflag %08x iflag %08x", __func__,
-           tty->termios->c_cflag,
-           RELEVANT_IFLAG(tty->termios->c_iflag));
+           tty->termios.c_cflag,
+           RELEVANT_IFLAG(tty->termios.c_iflag));
 
        dbg("%s - old cflag %08x old iflag %08x", __func__,
            old_termios->c_cflag,
index 57eca244842431fa100f742424c9dbc6310c4156..402c32d7accb8bfa089e5a179b981e462767eb0a 100644 (file)
@@ -82,8 +82,7 @@
  * Defines used for sending commands to port
  */
 
-#define WAIT_FOR_EVER   (HZ * 0)       /* timeout urb is wait for ever */
-#define MOS_WDR_TIMEOUT (HZ * 5)       /* default urb timeout */
+#define MOS_WDR_TIMEOUT                5000    /* default urb timeout */
 
 #define MOS_PORT1       0x0200
 #define MOS_PORT2       0x0300
@@ -1232,9 +1231,12 @@ static int mos7840_chars_in_buffer(struct tty_struct *tty)
                return 0;
 
        spin_lock_irqsave(&mos7840_port->pool_lock, flags);
-       for (i = 0; i < NUM_URBS; ++i)
-               if (mos7840_port->busy[i])
-                       chars += URB_TRANSFER_BUFFER_SIZE;
+       for (i = 0; i < NUM_URBS; ++i) {
+               if (mos7840_port->busy[i]) {
+                       struct urb *urb = mos7840_port->write_urb_pool[i];
+                       chars += urb->transfer_buffer_length;
+               }
+       }
        spin_unlock_irqrestore(&mos7840_port->pool_lock, flags);
        dbg("%s - returns %d", __func__, chars);
        return chars;
@@ -1344,7 +1346,7 @@ static void mos7840_close(struct usb_serial_port *port)
 static void mos7840_block_until_chase_response(struct tty_struct *tty,
                                        struct moschip_port *mos7840_port)
 {
-       int timeout = 1 * HZ;
+       int timeout = msecs_to_jiffies(1000);
        int wait = 10;
        int count;
 
@@ -1649,7 +1651,7 @@ static void mos7840_throttle(struct tty_struct *tty)
                        return;
        }
        /* if we are implementing RTS/CTS, toggle that line */
-       if (tty->termios->c_cflag & CRTSCTS) {
+       if (tty->termios.c_cflag & CRTSCTS) {
                mos7840_port->shadowMCR &= ~MCR_RTS;
                status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER,
                                         mos7840_port->shadowMCR);
@@ -1692,7 +1694,7 @@ static void mos7840_unthrottle(struct tty_struct *tty)
        }
 
        /* if we are implementing RTS/CTS, toggle that line */
-       if (tty->termios->c_cflag & CRTSCTS) {
+       if (tty->termios.c_cflag & CRTSCTS) {
                mos7840_port->shadowMCR |= MCR_RTS;
                status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER,
                                         mos7840_port->shadowMCR);
@@ -1998,8 +2000,8 @@ static void mos7840_change_port_settings(struct tty_struct *tty,
        lStop = LCR_STOP_1;
        lParity = LCR_PAR_NONE;
 
-       cflag = tty->termios->c_cflag;
-       iflag = tty->termios->c_iflag;
+       cflag = tty->termios.c_cflag;
+       iflag = tty->termios.c_iflag;
 
        /* Change the number of bits */
        if (cflag & CSIZE) {
@@ -2159,10 +2161,10 @@ static void mos7840_set_termios(struct tty_struct *tty,
 
        dbg("%s", "setting termios - ");
 
-       cflag = tty->termios->c_cflag;
+       cflag = tty->termios.c_cflag;
 
        dbg("%s - clfag %08x iflag %08x", __func__,
-           tty->termios->c_cflag, RELEVANT_IFLAG(tty->termios->c_iflag));
+           tty->termios.c_cflag, RELEVANT_IFLAG(tty->termios.c_iflag));
        dbg("%s - old clfag %08x old iflag %08x", __func__,
            old_termios->c_cflag, RELEVANT_IFLAG(old_termios->c_iflag));
        dbg("%s - port %d", __func__, port->number);
@@ -2672,7 +2674,7 @@ static int mos7840_startup(struct usb_serial *serial)
 
        /* setting configuration feature to one */
        usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
-                       (__u8) 0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5 * HZ);
+                       (__u8) 0x03, 0x00, 0x01, 0x00, NULL, 0x00, MOS_WDR_TIMEOUT);
        return 0;
 error:
        for (/* nothing */; i >= 0; i--) {
index 08ff9b862049197566454d1052d6c46160efbab6..cc40f47ecea13ff2041389d5aa7d5526159e58d8 100644 (file)
@@ -80,85 +80,9 @@ static void option_instat_callback(struct urb *urb);
 #define OPTION_PRODUCT_GTM380_MODEM            0x7201
 
 #define HUAWEI_VENDOR_ID                       0x12D1
-#define HUAWEI_PRODUCT_E600                    0x1001
-#define HUAWEI_PRODUCT_E220                    0x1003
-#define HUAWEI_PRODUCT_E220BIS                 0x1004
-#define HUAWEI_PRODUCT_E1401                   0x1401
-#define HUAWEI_PRODUCT_E1402                   0x1402
-#define HUAWEI_PRODUCT_E1403                   0x1403
-#define HUAWEI_PRODUCT_E1404                   0x1404
-#define HUAWEI_PRODUCT_E1405                   0x1405
-#define HUAWEI_PRODUCT_E1406                   0x1406
-#define HUAWEI_PRODUCT_E1407                   0x1407
-#define HUAWEI_PRODUCT_E1408                   0x1408
-#define HUAWEI_PRODUCT_E1409                   0x1409
-#define HUAWEI_PRODUCT_E140A                   0x140A
-#define HUAWEI_PRODUCT_E140B                   0x140B
-#define HUAWEI_PRODUCT_E140C                   0x140C
-#define HUAWEI_PRODUCT_E140D                   0x140D
-#define HUAWEI_PRODUCT_E140E                   0x140E
-#define HUAWEI_PRODUCT_E140F                   0x140F
-#define HUAWEI_PRODUCT_E1410                   0x1410
-#define HUAWEI_PRODUCT_E1411                   0x1411
-#define HUAWEI_PRODUCT_E1412                   0x1412
-#define HUAWEI_PRODUCT_E1413                   0x1413
-#define HUAWEI_PRODUCT_E1414                   0x1414
-#define HUAWEI_PRODUCT_E1415                   0x1415
-#define HUAWEI_PRODUCT_E1416                   0x1416
-#define HUAWEI_PRODUCT_E1417                   0x1417
-#define HUAWEI_PRODUCT_E1418                   0x1418
-#define HUAWEI_PRODUCT_E1419                   0x1419
-#define HUAWEI_PRODUCT_E141A                   0x141A
-#define HUAWEI_PRODUCT_E141B                   0x141B
-#define HUAWEI_PRODUCT_E141C                   0x141C
-#define HUAWEI_PRODUCT_E141D                   0x141D
-#define HUAWEI_PRODUCT_E141E                   0x141E
-#define HUAWEI_PRODUCT_E141F                   0x141F
-#define HUAWEI_PRODUCT_E1420                   0x1420
-#define HUAWEI_PRODUCT_E1421                   0x1421
-#define HUAWEI_PRODUCT_E1422                   0x1422
-#define HUAWEI_PRODUCT_E1423                   0x1423
-#define HUAWEI_PRODUCT_E1424                   0x1424
-#define HUAWEI_PRODUCT_E1425                   0x1425
-#define HUAWEI_PRODUCT_E1426                   0x1426
-#define HUAWEI_PRODUCT_E1427                   0x1427
-#define HUAWEI_PRODUCT_E1428                   0x1428
-#define HUAWEI_PRODUCT_E1429                   0x1429
-#define HUAWEI_PRODUCT_E142A                   0x142A
-#define HUAWEI_PRODUCT_E142B                   0x142B
-#define HUAWEI_PRODUCT_E142C                   0x142C
-#define HUAWEI_PRODUCT_E142D                   0x142D
-#define HUAWEI_PRODUCT_E142E                   0x142E
-#define HUAWEI_PRODUCT_E142F                   0x142F
-#define HUAWEI_PRODUCT_E1430                   0x1430
-#define HUAWEI_PRODUCT_E1431                   0x1431
-#define HUAWEI_PRODUCT_E1432                   0x1432
-#define HUAWEI_PRODUCT_E1433                   0x1433
-#define HUAWEI_PRODUCT_E1434                   0x1434
-#define HUAWEI_PRODUCT_E1435                   0x1435
-#define HUAWEI_PRODUCT_E1436                   0x1436
-#define HUAWEI_PRODUCT_E1437                   0x1437
-#define HUAWEI_PRODUCT_E1438                   0x1438
-#define HUAWEI_PRODUCT_E1439                   0x1439
-#define HUAWEI_PRODUCT_E143A                   0x143A
-#define HUAWEI_PRODUCT_E143B                   0x143B
-#define HUAWEI_PRODUCT_E143C                   0x143C
-#define HUAWEI_PRODUCT_E143D                   0x143D
-#define HUAWEI_PRODUCT_E143E                   0x143E
-#define HUAWEI_PRODUCT_E143F                   0x143F
 #define HUAWEI_PRODUCT_K4505                   0x1464
 #define HUAWEI_PRODUCT_K3765                   0x1465
-#define HUAWEI_PRODUCT_E14AC                   0x14AC
-#define HUAWEI_PRODUCT_K3806                   0x14AE
 #define HUAWEI_PRODUCT_K4605                   0x14C6
-#define HUAWEI_PRODUCT_K5005                   0x14C8
-#define HUAWEI_PRODUCT_K3770                   0x14C9
-#define HUAWEI_PRODUCT_K3771                   0x14CA
-#define HUAWEI_PRODUCT_K4510                   0x14CB
-#define HUAWEI_PRODUCT_K4511                   0x14CC
-#define HUAWEI_PRODUCT_ETS1220                 0x1803
-#define HUAWEI_PRODUCT_E353                    0x1506
-#define HUAWEI_PRODUCT_E173S                   0x1C05
 
 #define QUANTA_VENDOR_ID                       0x0408
 #define QUANTA_PRODUCT_Q101                    0xEA02
@@ -615,104 +539,123 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GLX) },
        { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GKE) },
        { USB_DEVICE(QUANTA_VENDOR_ID, QUANTA_PRODUCT_GLE) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E600, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E220BIS, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1401, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1402, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1403, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1404, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1405, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1406, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1407, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1408, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1409, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140A, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140B, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140C, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140D, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140E, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E140F, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1410, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1411, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1412, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1413, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1414, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1415, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1416, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1417, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1418, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1419, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141A, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141B, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141C, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141D, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141E, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E141F, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1420, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1421, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1422, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1423, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1424, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1425, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1426, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1427, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1428, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1429, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142A, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142B, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142C, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142D, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142E, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E142F, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1430, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1431, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1432, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1433, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1434, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1435, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1436, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1437, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1438, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E1439, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143A, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143B, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143C, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143D, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143E, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143F, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173S, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4505, 0xff, 0xff, 0xff),
                .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist },
        { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3765, 0xff, 0xff, 0xff),
                .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ETS1220, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E14AC, 0xff, 0xff, 0xff) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3806, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4605, 0xff, 0xff, 0xff),
                .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4605, 0xff, 0x01, 0x31) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4605, 0xff, 0x01, 0x32) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K5005, 0xff, 0x01, 0x31) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K5005, 0xff, 0x01, 0x32) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K5005, 0xff, 0x01, 0x33) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3770, 0xff, 0x02, 0x31) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3770, 0xff, 0x02, 0x32) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3771, 0xff, 0x02, 0x31) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3771, 0xff, 0x02, 0x32) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4510, 0xff, 0x01, 0x31) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4510, 0xff, 0x01, 0x32) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4511, 0xff, 0x01, 0x31) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4511, 0xff, 0x01, 0x32) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x01) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x02) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x03) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x10) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x12) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x13) },
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x02, 0x01) },  /* E398 3G Modem */
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x02, 0x02) },  /* E398 3G PC UI Interface */
-       { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x02, 0x03) },  /* E398 3G Application Interface */
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0xff, 0xff) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x01) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x02) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x03) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x04) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x05) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x06) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x0A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x0B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x0D) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x0E) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x0F) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x10) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x12) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x13) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x14) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x15) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x17) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x18) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x19) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x1A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x1B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x1C) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x31) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x32) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x33) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x34) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x35) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x36) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x3A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x3B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x3D) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x3E) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x3F) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x48) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x49) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x4A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x4B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x4C) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x61) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x62) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x63) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x64) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x65) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x66) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6D) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6E) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x6F) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x78) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x79) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x7A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x7B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x01, 0x7C) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x01) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x02) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x03) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x04) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x05) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x06) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x0A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x0B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x0D) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x0E) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x0F) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x10) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x12) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x13) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x14) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x15) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x17) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x18) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x19) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x1A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x1B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x1C) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x31) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x32) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x33) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x34) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x35) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x36) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x3A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x3B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x3D) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x3E) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x3F) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x48) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x49) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x4A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x4B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x4C) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x61) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x62) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x63) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x64) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x65) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x66) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6D) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6E) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x6F) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x78) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x79) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x7A) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x7B) },
+       { USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, 0xff, 0x02, 0x7C) },
+
+
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) },
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V620) },
        { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V740) },
@@ -943,6 +886,8 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1010, 0xff, 0xff, 0xff),
          .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1012, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1018, 0xff, 0xff, 0xff),
+         .driver_info = (kernel_ulong_t)&net_intf3_blacklist },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1057, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1058, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1059, 0xff, 0xff, 0xff) },
@@ -1297,8 +1242,8 @@ static struct usb_serial_driver option_1port_device = {
        .tiocmset          = usb_wwan_tiocmset,
        .ioctl             = usb_wwan_ioctl,
        .attach            = usb_wwan_startup,
-       .disconnect        = usb_wwan_disconnect,
        .release           = option_release,
+       .port_remove       = usb_wwan_port_remove,
        .read_int_callback = option_instat_callback,
 #ifdef CONFIG_PM
        .suspend           = usb_wwan_suspend,
@@ -1414,8 +1359,6 @@ static void option_release(struct usb_serial *serial)
        struct usb_wwan_intf_private *intfdata = usb_get_serial_data(serial);
        struct option_private *priv = intfdata->private;
 
-       usb_wwan_release(serial);
-
        kfree(priv);
        kfree(intfdata);
 }
index 5976b65ab6ee6851cfb10ca2f5dd956c71c8a284..9f555560bfbf0355e6fb8e981168b30daedb4f2b 100644 (file)
@@ -404,10 +404,10 @@ static int oti6858_chars_in_buffer(struct tty_struct *tty)
 
 static void oti6858_init_termios(struct tty_struct *tty)
 {
-       *(tty->termios) = tty_std_termios;
-       tty->termios->c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL;
-       tty->termios->c_ispeed = 38400;
-       tty->termios->c_ospeed = 38400;
+       tty->termios = tty_std_termios;
+       tty->termios.c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL;
+       tty->termios.c_ispeed = 38400;
+       tty->termios.c_ospeed = 38400;
 }
 
 static void oti6858_set_termios(struct tty_struct *tty,
@@ -425,7 +425,7 @@ static void oti6858_set_termios(struct tty_struct *tty,
                return;
        }
 
-       cflag = tty->termios->c_cflag;
+       cflag = tty->termios.c_cflag;
 
        spin_lock_irqsave(&priv->lock, flags);
        divisor = priv->pending_setup.divisor;
index 13b8dd6481f565bd421a0a504b15d449ecbc3d72..2b9108a8ea6470bb32eb9adceaabe150a959cffc 100644 (file)
@@ -260,16 +260,16 @@ static void pl2303_set_termios(struct tty_struct *tty,
           serial settings even to the same values as before. Thus
           we actually need to filter in this specific case */
 
-       if (!tty_termios_hw_change(tty->termios, old_termios))
+       if (!tty_termios_hw_change(&tty->termios, old_termios))
                return;
 
-       cflag = tty->termios->c_cflag;
+       cflag = tty->termios.c_cflag;
 
        buf = kzalloc(7, GFP_KERNEL);
        if (!buf) {
                dev_err(&port->dev, "%s - out of memory.\n", __func__);
                /* Report back no change occurred */
-               *tty->termios = *old_termios;
+               tty->termios = *old_termios;
                return;
        }
 
index 8d103019d6aa529511a82070a3864ef87af44c22..bfd50779f0c9f9bf93d2f795322912caa3978f7b 100644 (file)
@@ -199,43 +199,49 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
 
        /* default to enabling interface */
        altsetting = 0;
-       switch (ifnum) {
-               /* Composite mode; don't bind to the QMI/net interface as that
-                * gets handled by other drivers.
-                */
 
+       /* Composite mode; don't bind to the QMI/net interface as that
+        * gets handled by other drivers.
+        */
+
+       if (is_gobi1k) {
                /* Gobi 1K USB layout:
                 * 0: serial port (doesn't respond)
                 * 1: serial port (doesn't respond)
                 * 2: AT-capable modem port
                 * 3: QMI/net
-                *
-                * Gobi 2K+ USB layout:
+                */
+               if (ifnum == 2)
+                       dev_dbg(dev, "Modem port found\n");
+               else
+                       altsetting = -1;
+       } else {
+               /* Gobi 2K+ USB layout:
                 * 0: QMI/net
                 * 1: DM/DIAG (use libqcdm from ModemManager for communication)
                 * 2: AT-capable modem port
                 * 3: NMEA
                 */
-
-       case 1:
-               if (is_gobi1k)
+               switch (ifnum) {
+               case 0:
+                       /* Don't claim the QMI/net interface */
                        altsetting = -1;
-               else
+                       break;
+               case 1:
                        dev_dbg(dev, "Gobi 2K+ DM/DIAG interface found\n");
-               break;
-       case 2:
-               dev_dbg(dev, "Modem port found\n");
-               break;
-       case 3:
-               if (is_gobi1k)
-                       altsetting = -1;
-               else
+                       break;
+               case 2:
+                       dev_dbg(dev, "Modem port found\n");
+                       break;
+               case 3:
                        /*
                         * NMEA (serial line 9600 8N1)
                         * # echo "\$GPS_START" > /dev/ttyUSBx
                         * # echo "\$GPS_STOP"  > /dev/ttyUSBx
                         */
                        dev_dbg(dev, "Gobi 2K+ NMEA GPS interface found\n");
+                       break;
+               }
        }
 
 done:
@@ -262,8 +268,7 @@ static void qc_release(struct usb_serial *serial)
 {
        struct usb_wwan_intf_private *priv = usb_get_serial_data(serial);
 
-       /* Call usb_wwan release & free the private data allocated in qcprobe */
-       usb_wwan_release(serial);
+       /* Free the private data allocated in qcprobe */
        usb_set_serial_data(serial, NULL);
        kfree(priv);
 }
@@ -283,8 +288,8 @@ static struct usb_serial_driver qcdevice = {
        .write_room          = usb_wwan_write_room,
        .chars_in_buffer     = usb_wwan_chars_in_buffer,
        .attach              = usb_wwan_startup,
-       .disconnect          = usb_wwan_disconnect,
        .release             = qc_release,
+       .port_remove         = usb_wwan_port_remove,
 #ifdef CONFIG_PM
        .suspend             = usb_wwan_suspend,
        .resume              = usb_wwan_resume,
index 151670b6b72a9871bcf88fd5e611b3247bae9904..7df9cdb053ed757dc119c5b3a0b22dc69b0c4dec 100644 (file)
@@ -275,7 +275,7 @@ static void qt2_set_termios(struct tty_struct *tty,
 {
        struct usb_device *dev = port->serial->dev;
        struct qt2_port_private *port_priv;
-       struct ktermios *termios = tty->termios;
+       struct ktermios *termios = &tty->termios;
        u16 baud;
        unsigned int cflag = termios->c_cflag;
        u16 new_lcr = 0;
@@ -406,7 +406,7 @@ static int qt2_open(struct tty_struct *tty, struct usb_serial_port *port)
        port_priv->device_port = (u8) device_port;
 
        if (tty)
-               qt2_set_termios(tty, port, tty->termios);
+               qt2_set_termios(tty, port, &tty->termios);
 
        return 0;
 
index 0274710cced5ce432504ca02c98de0cab2add0ee..b14ebbd735676d564fc992511d0efa5d5e1d6a61 100644 (file)
@@ -382,7 +382,7 @@ static int sierra_send_setup(struct usb_serial_port *port)
 static void sierra_set_termios(struct tty_struct *tty,
                struct usb_serial_port *port, struct ktermios *old_termios)
 {
-       tty_termios_copy_hw(tty->termios, old_termios);
+       tty_termios_copy_hw(&tty->termios, old_termios);
        sierra_send_setup(port);
 }
 
index cad608984710321903ccef7ef0ce8d53a4e88ebf..ab68a4d74d61b5a5a2e8bc67479e4f7750098946 100644 (file)
@@ -316,10 +316,10 @@ static void spcp8x5_dtr_rts(struct usb_serial_port *port, int on)
 static void spcp8x5_init_termios(struct tty_struct *tty)
 {
        /* for the 1st time call this function */
-       *(tty->termios) = tty_std_termios;
-       tty->termios->c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL;
-       tty->termios->c_ispeed = 115200;
-       tty->termios->c_ospeed = 115200;
+       tty->termios = tty_std_termios;
+       tty->termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL;
+       tty->termios.c_ispeed = 115200;
+       tty->termios.c_ospeed = 115200;
 }
 
 /* set the serial param for transfer. we should check if we really need to
@@ -330,7 +330,7 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
        struct usb_serial *serial = port->serial;
        struct spcp8x5_private *priv = usb_get_serial_port_data(port);
        unsigned long flags;
-       unsigned int cflag = tty->termios->c_cflag;
+       unsigned int cflag = tty->termios.c_cflag;
        unsigned int old_cflag = old_termios->c_cflag;
        unsigned short uartdata;
        unsigned char buf[2] = {0, 0};
@@ -340,7 +340,7 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
 
 
        /* check that they really want us to change something */
-       if (!tty_termios_hw_change(tty->termios, old_termios))
+       if (!tty_termios_hw_change(&tty->termios, old_termios))
                return;
 
        /* set DTR/RTS active */
index 3fee23bf0c141718228d6b3a5ae04bc42a58a96d..cf2d30cf7588c09ca1e502471990d4c2a92cc456 100644 (file)
@@ -216,7 +216,7 @@ static void ssu100_set_termios(struct tty_struct *tty,
                               struct ktermios *old_termios)
 {
        struct usb_device *dev = port->serial->dev;
-       struct ktermios *termios = tty->termios;
+       struct ktermios *termios = &tty->termios;
        u16 baud, divisor, remainder;
        unsigned int cflag = termios->c_cflag;
        u16 urb_value = 0; /* will hold the new flags */
@@ -322,7 +322,7 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port)
                dbg("%s - set uart failed", __func__);
 
        if (tty)
-               ssu100_set_termios(tty, port, tty->termios);
+               ssu100_set_termios(tty, port, &tty->termios);
 
        return usb_serial_generic_open(tty, port);
 }
index a4404f5ad68ec5e782c68f9b261e52b4224ac497..f502a16aac215db11f5ce53a4492422495768340 100644 (file)
@@ -520,7 +520,7 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port)
        }
 
        if (tty)
-               ti_set_termios(tty, port, tty->termios);
+               ti_set_termios(tty, port, &tty->termios);
 
        dbg("%s - sending TI_OPEN_PORT", __func__);
        status = ti_command_out_sync(tdev, TI_OPEN_PORT,
@@ -562,7 +562,7 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port)
        usb_clear_halt(dev, port->read_urb->pipe);
 
        if (tty)
-               ti_set_termios(tty, port, tty->termios);
+               ti_set_termios(tty, port, &tty->termios);
 
        dbg("%s - sending TI_OPEN_PORT (2)", __func__);
        status = ti_command_out_sync(tdev, TI_OPEN_PORT,
@@ -831,8 +831,8 @@ static void ti_set_termios(struct tty_struct *tty,
        int port_number = port->number - port->serial->minor;
        unsigned int mcr;
 
-       cflag = tty->termios->c_cflag;
-       iflag = tty->termios->c_iflag;
+       cflag = tty->termios.c_cflag;
+       iflag = tty->termios.c_iflag;
 
        dbg("%s - cflag %08x, iflag %08x", __func__, cflag, iflag);
        dbg("%s - old clfag %08x, old iflag %08x", __func__,
@@ -871,7 +871,7 @@ static void ti_set_termios(struct tty_struct *tty,
        }
 
        /* CMSPAR isn't supported by this driver */
-       tty->termios->c_cflag &= ~CMSPAR;
+       tty->termios.c_cflag &= ~CMSPAR;
 
        if (cflag & PARENB) {
                if (cflag & PARODD) {
index 27483f91a4a38a41bfdd3f2a5c9583be33ac8027..aa4b0d7759924af8d7a728396c9acb26926ae617 100644 (file)
@@ -207,7 +207,7 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty)
        if (retval)
                goto error_get_interface;
 
-       retval = tty_standard_install(driver, tty);
+       retval = tty_port_install(&port->port, driver, tty);
        if (retval)
                goto error_init_termios;
 
@@ -305,8 +305,7 @@ static void serial_close(struct tty_struct *tty, struct file *filp)
  * Do the resource freeing and refcount dropping for the port.
  * Avoid freeing the console.
  *
- * Called asynchronously after the last tty kref is dropped,
- * and the tty layer has already done the tty_shutdown(tty);
+ * Called asynchronously after the last tty kref is dropped.
  */
 static void serial_cleanup(struct tty_struct *tty)
 {
@@ -423,7 +422,7 @@ static void serial_set_termios(struct tty_struct *tty, struct ktermios *old)
        if (port->serial->type->set_termios)
                port->serial->type->set_termios(tty, port, old);
        else
-               tty_termios_copy_hw(tty->termios, old);
+               tty_termios_copy_hw(&tty->termios, old);
 }
 
 static int serial_break(struct tty_struct *tty, int break_state)
index c47b6ec030634f9af420987e06c33727042b4f05..1f034d2397c6c6ea3888e79aa6cd2ddb6d73202b 100644 (file)
@@ -9,8 +9,7 @@ extern void usb_wwan_dtr_rts(struct usb_serial_port *port, int on);
 extern int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port);
 extern void usb_wwan_close(struct usb_serial_port *port);
 extern int usb_wwan_startup(struct usb_serial *serial);
-extern void usb_wwan_disconnect(struct usb_serial *serial);
-extern void usb_wwan_release(struct usb_serial *serial);
+extern int usb_wwan_port_remove(struct usb_serial_port *port);
 extern int usb_wwan_write_room(struct tty_struct *tty);
 extern void usb_wwan_set_termios(struct tty_struct *tty,
                                 struct usb_serial_port *port,
index f35971dff4a5782d6c0cca563f53558043359674..72b678d90831464a5e099a7efad4c4654efd04cd 100644 (file)
@@ -67,7 +67,7 @@ void usb_wwan_set_termios(struct tty_struct *tty,
        struct usb_wwan_intf_private *intfdata = port->serial->private;
 
        /* Doesn't support option setting */
-       tty_termios_copy_hw(tty->termios, old_termios);
+       tty_termios_copy_hw(&tty->termios, old_termios);
 
        if (intfdata->send_setup)
                intfdata->send_setup(port);
@@ -565,62 +565,52 @@ bail_out_error:
 }
 EXPORT_SYMBOL(usb_wwan_startup);
 
-static void stop_read_write_urbs(struct usb_serial *serial)
+int usb_wwan_port_remove(struct usb_serial_port *port)
 {
-       int i, j;
-       struct usb_serial_port *port;
+       int i;
        struct usb_wwan_port_private *portdata;
 
-       /* Stop reading/writing urbs */
-       for (i = 0; i < serial->num_ports; ++i) {
-               port = serial->port[i];
-               portdata = usb_get_serial_port_data(port);
-               for (j = 0; j < N_IN_URB; j++)
-                       usb_kill_urb(portdata->in_urbs[j]);
-               for (j = 0; j < N_OUT_URB; j++)
-                       usb_kill_urb(portdata->out_urbs[j]);
+       portdata = usb_get_serial_port_data(port);
+       usb_set_serial_port_data(port, NULL);
+
+       /* Stop reading/writing urbs and free them */
+       for (i = 0; i < N_IN_URB; i++) {
+               usb_kill_urb(portdata->in_urbs[i]);
+               usb_free_urb(portdata->in_urbs[i]);
+               free_page((unsigned long)portdata->in_buffer[i]);
+       }
+       for (i = 0; i < N_OUT_URB; i++) {
+               usb_kill_urb(portdata->out_urbs[i]);
+               usb_free_urb(portdata->out_urbs[i]);
+               kfree(portdata->out_buffer[i]);
        }
-}
 
-void usb_wwan_disconnect(struct usb_serial *serial)
-{
-       stop_read_write_urbs(serial);
+       /* Now free port private data */
+       kfree(portdata);
+       return 0;
 }
-EXPORT_SYMBOL(usb_wwan_disconnect);
+EXPORT_SYMBOL(usb_wwan_port_remove);
 
-void usb_wwan_release(struct usb_serial *serial)
+#ifdef CONFIG_PM
+static void stop_read_write_urbs(struct usb_serial *serial)
 {
        int i, j;
        struct usb_serial_port *port;
        struct usb_wwan_port_private *portdata;
 
-       /* Now free them */
+       /* Stop reading/writing urbs */
        for (i = 0; i < serial->num_ports; ++i) {
                port = serial->port[i];
                portdata = usb_get_serial_port_data(port);
-
-               for (j = 0; j < N_IN_URB; j++) {
-                       usb_free_urb(portdata->in_urbs[j]);
-                       free_page((unsigned long)
-                                 portdata->in_buffer[j]);
-                       portdata->in_urbs[j] = NULL;
-               }
-               for (j = 0; j < N_OUT_URB; j++) {
-                       usb_free_urb(portdata->out_urbs[j]);
-                       kfree(portdata->out_buffer[j]);
-                       portdata->out_urbs[j] = NULL;
-               }
-       }
-
-       /* Now free per port private data */
-       for (i = 0; i < serial->num_ports; i++) {
-               port = serial->port[i];
-               kfree(usb_get_serial_port_data(port));
+               if (!portdata)
+                       continue;
+               for (j = 0; j < N_IN_URB; j++)
+                       usb_kill_urb(portdata->in_urbs[j]);
+               for (j = 0; j < N_OUT_URB; j++)
+                       usb_kill_urb(portdata->out_urbs[j]);
        }
 }
-EXPORT_SYMBOL(usb_wwan_release);
 
-#ifdef CONFIG_PM
 int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message)
 {
        struct usb_wwan_intf_private *intfdata = serial->private;
@@ -712,7 +702,7 @@ int usb_wwan_resume(struct usb_serial *serial)
 
                /* skip closed ports */
                spin_lock_irq(&intfdata->susp_lock);
-               if (!portdata->opened) {
+               if (!portdata || !portdata->opened) {
                        spin_unlock_irq(&intfdata->susp_lock);
                        continue;
                }
index 473635e7f5dbdf8bb4c28c20102f12b438b31d77..b36077de72b96e17fe9eb1c830ec73c0d6e3f0eb 100644 (file)
@@ -724,7 +724,7 @@ static void firm_setup_port(struct tty_struct *tty)
 {
        struct usb_serial_port *port = tty->driver_data;
        struct whiteheat_port_settings port_settings;
-       unsigned int cflag = tty->termios->c_cflag;
+       unsigned int cflag = tty->termios.c_cflag;
 
        port_settings.port = port->number + 1;
 
index b28f2ad127d493aef0cdd6891d638ff8eba2f694..95edee53d860b917f077725156f3ed4af5ef58c9 100644 (file)
 #include "protocol.h"
 #include "debug.h"
 
+#define SD_INIT1_FIRMWARE "ene-ub6250/sd_init1.bin"
+#define SD_INIT2_FIRMWARE "ene-ub6250/sd_init2.bin"
+#define SD_RW_FIRMWARE "ene-ub6250/sd_rdwr.bin"
+#define MS_INIT_FIRMWARE "ene-ub6250/ms_init.bin"
+#define MSP_RW_FIRMWARE "ene-ub6250/msp_rdwr.bin"
+#define MS_RW_FIRMWARE "ene-ub6250/ms_rdwr.bin"
+
 MODULE_DESCRIPTION("Driver for ENE UB6250 reader");
 MODULE_LICENSE("GPL");
-
+MODULE_FIRMWARE(SD_INIT1_FIRMWARE);
+MODULE_FIRMWARE(SD_INIT2_FIRMWARE);
+MODULE_FIRMWARE(SD_RW_FIRMWARE);
+MODULE_FIRMWARE(MS_INIT_FIRMWARE);
+MODULE_FIRMWARE(MSP_RW_FIRMWARE);
+MODULE_FIRMWARE(MS_RW_FIRMWARE);
 
 /*
  * The table of devices
@@ -1883,28 +1895,28 @@ static int ene_load_bincode(struct us_data *us, unsigned char flag)
        /* For SD */
        case SD_INIT1_PATTERN:
                US_DEBUGP("SD_INIT1_PATTERN\n");
-               fw_name = "ene-ub6250/sd_init1.bin";
+               fw_name = SD_INIT1_FIRMWARE;
                break;
        case SD_INIT2_PATTERN:
                US_DEBUGP("SD_INIT2_PATTERN\n");
-               fw_name = "ene-ub6250/sd_init2.bin";
+               fw_name = SD_INIT2_FIRMWARE;
                break;
        case SD_RW_PATTERN:
-               US_DEBUGP("SD_RDWR_PATTERN\n");
-               fw_name = "ene-ub6250/sd_rdwr.bin";
+               US_DEBUGP("SD_RW_PATTERN\n");
+               fw_name = SD_RW_FIRMWARE;
                break;
        /* For MS */
        case MS_INIT_PATTERN:
                US_DEBUGP("MS_INIT_PATTERN\n");
-               fw_name = "ene-ub6250/ms_init.bin";
+               fw_name = MS_INIT_FIRMWARE;
                break;
        case MSP_RW_PATTERN:
                US_DEBUGP("MSP_RW_PATTERN\n");
-               fw_name = "ene-ub6250/msp_rdwr.bin";
+               fw_name = MSP_RW_FIRMWARE;
                break;
        case MS_RW_PATTERN:
                US_DEBUGP("MS_RW_PATTERN\n");
-               fw_name = "ene-ub6250/ms_rdwr.bin";
+               fw_name = MS_RW_FIRMWARE;
                break;
        default:
                US_DEBUGP("----------- Unknown PATTERN ----------\n");
index fa810a83e8300957c72de584ab3f3fcd1e31a29a..dd88441c8f7891e0d242e1107d6ff585a30999e4 100644 (file)
@@ -202,7 +202,7 @@ int wusb_dev_sec_add(struct wusbhc *wusbhc,
 {
        int result, bytes, secd_size;
        struct device *dev = &usb_dev->dev;
-       struct usb_security_descriptor *secd;
+       struct usb_security_descriptor *secd, *new_secd;
        const struct usb_encryption_descriptor *etd, *ccm1_etd = NULL;
        const void *itr, *top;
        char buf[64];
@@ -221,11 +221,12 @@ int wusb_dev_sec_add(struct wusbhc *wusbhc,
                goto out;
        }
        secd_size = le16_to_cpu(secd->wTotalLength);
-       secd = krealloc(secd, secd_size, GFP_KERNEL);
-       if (secd == NULL) {
+       new_secd = krealloc(secd, secd_size, GFP_KERNEL);
+       if (new_secd == NULL) {
                dev_err(dev, "Can't allocate space for security descriptors\n");
                goto out;
        }
+       secd = new_secd;
        result = usb_get_descriptor(usb_dev, USB_DT_SECURITY,
                                    0, secd, secd_size);
        if (result < secd_size) {
index 9e4a924616884d7152497bb465e67c1c2167b2bb..a09b65ebd9bb712d02060e760ff2c349bcdc2e77 100644 (file)
@@ -46,8 +46,10 @@ int wa_create(struct wahc *wa, struct usb_interface *iface)
        wa->dto_epd = &iface->cur_altsetting->endpoint[2].desc;
        wa->xfer_result_size = usb_endpoint_maxp(wa->dti_epd);
        wa->xfer_result = kmalloc(wa->xfer_result_size, GFP_KERNEL);
-       if (wa->xfer_result == NULL)
+       if (wa->xfer_result == NULL) {
+               result = -ENOMEM;
                goto error_xfer_result_alloc;
+       }
        result = wa_nep_create(wa, iface);
        if (result < 0) {
                dev_err(dev, "WA-CDS: can't initialize notif endpoint: %d\n",
index e4e2fd1b51076dfbc8ffc73920ac148d830c4d4f..202bba6c997cce61eb116fc74db8e842454ce1f4 100644 (file)
@@ -9,3 +9,6 @@ config VHOST_NET
          To compile this driver as a module, choose M here: the module will
          be called vhost_net.
 
+if STAGING
+source "drivers/vhost/Kconfig.tcm"
+endif
diff --git a/drivers/vhost/Kconfig.tcm b/drivers/vhost/Kconfig.tcm
new file mode 100644 (file)
index 0000000..a9c6f76
--- /dev/null
@@ -0,0 +1,6 @@
+config TCM_VHOST
+       tristate "TCM_VHOST fabric module (EXPERIMENTAL)"
+       depends on TARGET_CORE && EVENTFD && EXPERIMENTAL && m
+       default n
+       ---help---
+       Say M here to enable the TCM_VHOST fabric module for use with virtio-scsi guests
index 72dd02050bb986cf6d426828f64ea521aaff3284..a27b053bc9ab12d546c9f17bee106a916eb5e236 100644 (file)
@@ -1,2 +1,4 @@
 obj-$(CONFIG_VHOST_NET) += vhost_net.o
 vhost_net-y := vhost.o net.o
+
+obj-$(CONFIG_TCM_VHOST) += tcm_vhost.o
diff --git a/drivers/vhost/tcm_vhost.c b/drivers/vhost/tcm_vhost.c
new file mode 100644 (file)
index 0000000..fb36654
--- /dev/null
@@ -0,0 +1,1628 @@
+/*******************************************************************************
+ * Vhost kernel TCM fabric driver for virtio SCSI initiators
+ *
+ * (C) Copyright 2010-2012 RisingTide Systems LLC.
+ * (C) Copyright 2010-2012 IBM Corp.
+ *
+ * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ *
+ * Authors: Nicholas A. Bellinger <nab@risingtidesystems.com>
+ *          Stefan Hajnoczi <stefanha@linux.vnet.ibm.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/moduleparam.h>
+#include <generated/utsrelease.h>
+#include <linux/utsname.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/configfs.h>
+#include <linux/ctype.h>
+#include <linux/compat.h>
+#include <linux/eventfd.h>
+#include <linux/vhost.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <asm/unaligned.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_tcq.h>
+#include <target/target_core_base.h>
+#include <target/target_core_fabric.h>
+#include <target/target_core_fabric_configfs.h>
+#include <target/target_core_configfs.h>
+#include <target/configfs_macros.h>
+#include <linux/vhost.h>
+#include <linux/virtio_net.h> /* TODO vhost.h currently depends on this */
+#include <linux/virtio_scsi.h>
+
+#include "vhost.c"
+#include "vhost.h"
+#include "tcm_vhost.h"
+
+struct vhost_scsi {
+       atomic_t vhost_ref_cnt;
+       struct tcm_vhost_tpg *vs_tpg;
+       struct vhost_dev dev;
+       struct vhost_virtqueue vqs[3];
+
+       struct vhost_work vs_completion_work; /* cmd completion work item */
+       struct list_head vs_completion_list;  /* cmd completion queue */
+       spinlock_t vs_completion_lock;        /* protects s_completion_list */
+};
+
+/* Local pointer to allocated TCM configfs fabric module */
+static struct target_fabric_configfs *tcm_vhost_fabric_configfs;
+
+static struct workqueue_struct *tcm_vhost_workqueue;
+
+/* Global spinlock to protect tcm_vhost TPG list for vhost IOCTL access */
+static DEFINE_MUTEX(tcm_vhost_mutex);
+static LIST_HEAD(tcm_vhost_list);
+
+static int tcm_vhost_check_true(struct se_portal_group *se_tpg)
+{
+       return 1;
+}
+
+static int tcm_vhost_check_false(struct se_portal_group *se_tpg)
+{
+       return 0;
+}
+
+static char *tcm_vhost_get_fabric_name(void)
+{
+       return "vhost";
+}
+
+static u8 tcm_vhost_get_fabric_proto_ident(struct se_portal_group *se_tpg)
+{
+       struct tcm_vhost_tpg *tpg = container_of(se_tpg,
+                               struct tcm_vhost_tpg, se_tpg);
+       struct tcm_vhost_tport *tport = tpg->tport;
+
+       switch (tport->tport_proto_id) {
+       case SCSI_PROTOCOL_SAS:
+               return sas_get_fabric_proto_ident(se_tpg);
+       case SCSI_PROTOCOL_FCP:
+               return fc_get_fabric_proto_ident(se_tpg);
+       case SCSI_PROTOCOL_ISCSI:
+               return iscsi_get_fabric_proto_ident(se_tpg);
+       default:
+               pr_err("Unknown tport_proto_id: 0x%02x, using"
+                       " SAS emulation\n", tport->tport_proto_id);
+               break;
+       }
+
+       return sas_get_fabric_proto_ident(se_tpg);
+}
+
+static char *tcm_vhost_get_fabric_wwn(struct se_portal_group *se_tpg)
+{
+       struct tcm_vhost_tpg *tpg = container_of(se_tpg,
+                               struct tcm_vhost_tpg, se_tpg);
+       struct tcm_vhost_tport *tport = tpg->tport;
+
+       return &tport->tport_name[0];
+}
+
+static u16 tcm_vhost_get_tag(struct se_portal_group *se_tpg)
+{
+       struct tcm_vhost_tpg *tpg = container_of(se_tpg,
+                               struct tcm_vhost_tpg, se_tpg);
+       return tpg->tport_tpgt;
+}
+
+static u32 tcm_vhost_get_default_depth(struct se_portal_group *se_tpg)
+{
+       return 1;
+}
+
+static u32 tcm_vhost_get_pr_transport_id(
+       struct se_portal_group *se_tpg,
+       struct se_node_acl *se_nacl,
+       struct t10_pr_registration *pr_reg,
+       int *format_code,
+       unsigned char *buf)
+{
+       struct tcm_vhost_tpg *tpg = container_of(se_tpg,
+                               struct tcm_vhost_tpg, se_tpg);
+       struct tcm_vhost_tport *tport = tpg->tport;
+
+       switch (tport->tport_proto_id) {
+       case SCSI_PROTOCOL_SAS:
+               return sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg,
+                                       format_code, buf);
+       case SCSI_PROTOCOL_FCP:
+               return fc_get_pr_transport_id(se_tpg, se_nacl, pr_reg,
+                                       format_code, buf);
+       case SCSI_PROTOCOL_ISCSI:
+               return iscsi_get_pr_transport_id(se_tpg, se_nacl, pr_reg,
+                                       format_code, buf);
+       default:
+               pr_err("Unknown tport_proto_id: 0x%02x, using"
+                       " SAS emulation\n", tport->tport_proto_id);
+               break;
+       }
+
+       return sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg,
+                       format_code, buf);
+}
+
+static u32 tcm_vhost_get_pr_transport_id_len(
+       struct se_portal_group *se_tpg,
+       struct se_node_acl *se_nacl,
+       struct t10_pr_registration *pr_reg,
+       int *format_code)
+{
+       struct tcm_vhost_tpg *tpg = container_of(se_tpg,
+                               struct tcm_vhost_tpg, se_tpg);
+       struct tcm_vhost_tport *tport = tpg->tport;
+
+       switch (tport->tport_proto_id) {
+       case SCSI_PROTOCOL_SAS:
+               return sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,
+                                       format_code);
+       case SCSI_PROTOCOL_FCP:
+               return fc_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,
+                                       format_code);
+       case SCSI_PROTOCOL_ISCSI:
+               return iscsi_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,
+                                       format_code);
+       default:
+               pr_err("Unknown tport_proto_id: 0x%02x, using"
+                       " SAS emulation\n", tport->tport_proto_id);
+               break;
+       }
+
+       return sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg,
+                       format_code);
+}
+
+static char *tcm_vhost_parse_pr_out_transport_id(
+       struct se_portal_group *se_tpg,
+       const char *buf,
+       u32 *out_tid_len,
+       char **port_nexus_ptr)
+{
+       struct tcm_vhost_tpg *tpg = container_of(se_tpg,
+                               struct tcm_vhost_tpg, se_tpg);
+       struct tcm_vhost_tport *tport = tpg->tport;
+
+       switch (tport->tport_proto_id) {
+       case SCSI_PROTOCOL_SAS:
+               return sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,
+                                       port_nexus_ptr);
+       case SCSI_PROTOCOL_FCP:
+               return fc_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,
+                                       port_nexus_ptr);
+       case SCSI_PROTOCOL_ISCSI:
+               return iscsi_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,
+                                       port_nexus_ptr);
+       default:
+               pr_err("Unknown tport_proto_id: 0x%02x, using"
+                       " SAS emulation\n", tport->tport_proto_id);
+               break;
+       }
+
+       return sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len,
+                       port_nexus_ptr);
+}
+
+static struct se_node_acl *tcm_vhost_alloc_fabric_acl(
+       struct se_portal_group *se_tpg)
+{
+       struct tcm_vhost_nacl *nacl;
+
+       nacl = kzalloc(sizeof(struct tcm_vhost_nacl), GFP_KERNEL);
+       if (!nacl) {
+               pr_err("Unable to alocate struct tcm_vhost_nacl\n");
+               return NULL;
+       }
+
+       return &nacl->se_node_acl;
+}
+
+static void tcm_vhost_release_fabric_acl(
+       struct se_portal_group *se_tpg,
+       struct se_node_acl *se_nacl)
+{
+       struct tcm_vhost_nacl *nacl = container_of(se_nacl,
+                       struct tcm_vhost_nacl, se_node_acl);
+       kfree(nacl);
+}
+
+static u32 tcm_vhost_tpg_get_inst_index(struct se_portal_group *se_tpg)
+{
+       return 1;
+}
+
+static void tcm_vhost_release_cmd(struct se_cmd *se_cmd)
+{
+       return;
+}
+
+static int tcm_vhost_shutdown_session(struct se_session *se_sess)
+{
+       return 0;
+}
+
+static void tcm_vhost_close_session(struct se_session *se_sess)
+{
+       return;
+}
+
+static u32 tcm_vhost_sess_get_index(struct se_session *se_sess)
+{
+       return 0;
+}
+
+static int tcm_vhost_write_pending(struct se_cmd *se_cmd)
+{
+       /* Go ahead and process the write immediately */
+       target_execute_cmd(se_cmd);
+       return 0;
+}
+
+static int tcm_vhost_write_pending_status(struct se_cmd *se_cmd)
+{
+       return 0;
+}
+
+static void tcm_vhost_set_default_node_attrs(struct se_node_acl *nacl)
+{
+       return;
+}
+
+static u32 tcm_vhost_get_task_tag(struct se_cmd *se_cmd)
+{
+       return 0;
+}
+
+static int tcm_vhost_get_cmd_state(struct se_cmd *se_cmd)
+{
+       return 0;
+}
+
+static void vhost_scsi_complete_cmd(struct tcm_vhost_cmd *);
+
+static int tcm_vhost_queue_data_in(struct se_cmd *se_cmd)
+{
+       struct tcm_vhost_cmd *tv_cmd = container_of(se_cmd,
+                               struct tcm_vhost_cmd, tvc_se_cmd);
+       vhost_scsi_complete_cmd(tv_cmd);
+       return 0;
+}
+
+static int tcm_vhost_queue_status(struct se_cmd *se_cmd)
+{
+       struct tcm_vhost_cmd *tv_cmd = container_of(se_cmd,
+                               struct tcm_vhost_cmd, tvc_se_cmd);
+       vhost_scsi_complete_cmd(tv_cmd);
+       return 0;
+}
+
+static int tcm_vhost_queue_tm_rsp(struct se_cmd *se_cmd)
+{
+       return 0;
+}
+
+static u16 tcm_vhost_set_fabric_sense_len(struct se_cmd *se_cmd,
+       u32 sense_length)
+{
+       return 0;
+}
+
+static u16 tcm_vhost_get_fabric_sense_len(void)
+{
+       return 0;
+}
+
+static void vhost_scsi_free_cmd(struct tcm_vhost_cmd *tv_cmd)
+{
+       struct se_cmd *se_cmd = &tv_cmd->tvc_se_cmd;
+
+       /* TODO locking against target/backend threads? */
+       transport_generic_free_cmd(se_cmd, 1);
+
+       if (tv_cmd->tvc_sgl_count) {
+               u32 i;
+               for (i = 0; i < tv_cmd->tvc_sgl_count; i++)
+                       put_page(sg_page(&tv_cmd->tvc_sgl[i]));
+
+               kfree(tv_cmd->tvc_sgl);
+       }
+
+       kfree(tv_cmd);
+}
+
+/* Dequeue a command from the completion list */
+static struct tcm_vhost_cmd *vhost_scsi_get_cmd_from_completion(
+       struct vhost_scsi *vs)
+{
+       struct tcm_vhost_cmd *tv_cmd = NULL;
+
+       spin_lock_bh(&vs->vs_completion_lock);
+       if (list_empty(&vs->vs_completion_list)) {
+               spin_unlock_bh(&vs->vs_completion_lock);
+               return NULL;
+       }
+
+       list_for_each_entry(tv_cmd, &vs->vs_completion_list,
+                           tvc_completion_list) {
+               list_del(&tv_cmd->tvc_completion_list);
+               break;
+       }
+       spin_unlock_bh(&vs->vs_completion_lock);
+       return tv_cmd;
+}
+
+/* Fill in status and signal that we are done processing this command
+ *
+ * This is scheduled in the vhost work queue so we are called with the owner
+ * process mm and can access the vring.
+ */
+static void vhost_scsi_complete_cmd_work(struct vhost_work *work)
+{
+       struct vhost_scsi *vs = container_of(work, struct vhost_scsi,
+                                       vs_completion_work);
+       struct tcm_vhost_cmd *tv_cmd;
+
+       while ((tv_cmd = vhost_scsi_get_cmd_from_completion(vs)) != NULL) {
+               struct virtio_scsi_cmd_resp v_rsp;
+               struct se_cmd *se_cmd = &tv_cmd->tvc_se_cmd;
+               int ret;
+
+               pr_debug("%s tv_cmd %p resid %u status %#02x\n", __func__,
+                       tv_cmd, se_cmd->residual_count, se_cmd->scsi_status);
+
+               memset(&v_rsp, 0, sizeof(v_rsp));
+               v_rsp.resid = se_cmd->residual_count;
+               /* TODO is status_qualifier field needed? */
+               v_rsp.status = se_cmd->scsi_status;
+               v_rsp.sense_len = se_cmd->scsi_sense_length;
+               memcpy(v_rsp.sense, tv_cmd->tvc_sense_buf,
+                      v_rsp.sense_len);
+               ret = copy_to_user(tv_cmd->tvc_resp, &v_rsp, sizeof(v_rsp));
+               if (likely(ret == 0))
+                       vhost_add_used(&vs->vqs[2], tv_cmd->tvc_vq_desc, 0);
+               else
+                       pr_err("Faulted on virtio_scsi_cmd_resp\n");
+
+               vhost_scsi_free_cmd(tv_cmd);
+       }
+
+       vhost_signal(&vs->dev, &vs->vqs[2]);
+}
+
+static void vhost_scsi_complete_cmd(struct tcm_vhost_cmd *tv_cmd)
+{
+       struct vhost_scsi *vs = tv_cmd->tvc_vhost;
+
+       pr_debug("%s tv_cmd %p\n", __func__, tv_cmd);
+
+       spin_lock_bh(&vs->vs_completion_lock);
+       list_add_tail(&tv_cmd->tvc_completion_list, &vs->vs_completion_list);
+       spin_unlock_bh(&vs->vs_completion_lock);
+
+       vhost_work_queue(&vs->dev, &vs->vs_completion_work);
+}
+
+static struct tcm_vhost_cmd *vhost_scsi_allocate_cmd(
+       struct tcm_vhost_tpg *tv_tpg,
+       struct virtio_scsi_cmd_req *v_req,
+       u32 exp_data_len,
+       int data_direction)
+{
+       struct tcm_vhost_cmd *tv_cmd;
+       struct tcm_vhost_nexus *tv_nexus;
+       struct se_portal_group *se_tpg = &tv_tpg->se_tpg;
+       struct se_session *se_sess;
+       struct se_cmd *se_cmd;
+       int sam_task_attr;
+
+       tv_nexus = tv_tpg->tpg_nexus;
+       if (!tv_nexus) {
+               pr_err("Unable to locate active struct tcm_vhost_nexus\n");
+               return ERR_PTR(-EIO);
+       }
+       se_sess = tv_nexus->tvn_se_sess;
+
+       tv_cmd = kzalloc(sizeof(struct tcm_vhost_cmd), GFP_ATOMIC);
+       if (!tv_cmd) {
+               pr_err("Unable to allocate struct tcm_vhost_cmd\n");
+               return ERR_PTR(-ENOMEM);
+       }
+       INIT_LIST_HEAD(&tv_cmd->tvc_completion_list);
+       tv_cmd->tvc_tag = v_req->tag;
+
+       se_cmd = &tv_cmd->tvc_se_cmd;
+       /*
+        * Locate the SAM Task Attr from virtio_scsi_cmd_req
+        */
+       sam_task_attr = v_req->task_attr;
+       /*
+        * Initialize struct se_cmd descriptor from TCM infrastructure
+        */
+       transport_init_se_cmd(se_cmd, se_tpg->se_tpg_tfo, se_sess, exp_data_len,
+                               data_direction, sam_task_attr,
+                               &tv_cmd->tvc_sense_buf[0]);
+
+#if 0  /* FIXME: vhost_scsi_allocate_cmd() BIDI operation */
+       if (bidi)
+               se_cmd->se_cmd_flags |= SCF_BIDI;
+#endif
+       return tv_cmd;
+}
+
+/*
+ * Map a user memory range into a scatterlist
+ *
+ * Returns the number of scatterlist entries used or -errno on error.
+ */
+static int vhost_scsi_map_to_sgl(struct scatterlist *sgl,
+       unsigned int sgl_count, void __user *ptr, size_t len, int write)
+{
+       struct scatterlist *sg = sgl;
+       unsigned int npages = 0;
+       int ret;
+
+       while (len > 0) {
+               struct page *page;
+               unsigned int offset = (uintptr_t)ptr & ~PAGE_MASK;
+               unsigned int nbytes = min_t(unsigned int,
+                               PAGE_SIZE - offset, len);
+
+               if (npages == sgl_count) {
+                       ret = -ENOBUFS;
+                       goto err;
+               }
+
+               ret = get_user_pages_fast((unsigned long)ptr, 1, write, &page);
+               BUG_ON(ret == 0); /* we should either get our page or fail */
+               if (ret < 0)
+                       goto err;
+
+               sg_set_page(sg, page, nbytes, offset);
+               ptr += nbytes;
+               len -= nbytes;
+               sg++;
+               npages++;
+       }
+       return npages;
+
+err:
+       /* Put pages that we hold */
+       for (sg = sgl; sg != &sgl[npages]; sg++)
+               put_page(sg_page(sg));
+       return ret;
+}
+
+static int vhost_scsi_map_iov_to_sgl(struct tcm_vhost_cmd *tv_cmd,
+       struct iovec *iov, unsigned int niov, int write)
+{
+       int ret;
+       unsigned int i;
+       u32 sgl_count;
+       struct scatterlist *sg;
+
+       /*
+        * Find out how long sglist needs to be
+        */
+       sgl_count = 0;
+       for (i = 0; i < niov; i++) {
+               sgl_count += (((uintptr_t)iov[i].iov_base + iov[i].iov_len +
+                               PAGE_SIZE - 1) >> PAGE_SHIFT) -
+                               ((uintptr_t)iov[i].iov_base >> PAGE_SHIFT);
+       }
+       /* TODO overflow checking */
+
+       sg = kmalloc(sizeof(tv_cmd->tvc_sgl[0]) * sgl_count, GFP_ATOMIC);
+       if (!sg)
+               return -ENOMEM;
+       pr_debug("%s sg %p sgl_count %u is_err %ld\n", __func__,
+              sg, sgl_count, IS_ERR(sg));
+       sg_init_table(sg, sgl_count);
+
+       tv_cmd->tvc_sgl = sg;
+       tv_cmd->tvc_sgl_count = sgl_count;
+
+       pr_debug("Mapping %u iovecs for %u pages\n", niov, sgl_count);
+       for (i = 0; i < niov; i++) {
+               ret = vhost_scsi_map_to_sgl(sg, sgl_count, iov[i].iov_base,
+                                       iov[i].iov_len, write);
+               if (ret < 0) {
+                       for (i = 0; i < tv_cmd->tvc_sgl_count; i++)
+                               put_page(sg_page(&tv_cmd->tvc_sgl[i]));
+                       kfree(tv_cmd->tvc_sgl);
+                       tv_cmd->tvc_sgl = NULL;
+                       tv_cmd->tvc_sgl_count = 0;
+                       return ret;
+               }
+
+               sg += ret;
+               sgl_count -= ret;
+       }
+       return 0;
+}
+
+static void tcm_vhost_submission_work(struct work_struct *work)
+{
+       struct tcm_vhost_cmd *tv_cmd =
+               container_of(work, struct tcm_vhost_cmd, work);
+       struct se_cmd *se_cmd = &tv_cmd->tvc_se_cmd;
+       struct scatterlist *sg_ptr, *sg_bidi_ptr = NULL;
+       int rc, sg_no_bidi = 0;
+       /*
+        * Locate the struct se_lun pointer based on v_req->lun, and
+        * attach it to struct se_cmd
+        */
+       rc = transport_lookup_cmd_lun(&tv_cmd->tvc_se_cmd, tv_cmd->tvc_lun);
+       if (rc < 0) {
+               pr_err("Failed to look up lun: %d\n", tv_cmd->tvc_lun);
+               transport_send_check_condition_and_sense(&tv_cmd->tvc_se_cmd,
+                       tv_cmd->tvc_se_cmd.scsi_sense_reason, 0);
+               transport_generic_free_cmd(se_cmd, 0);
+               return;
+       }
+
+       rc = target_setup_cmd_from_cdb(se_cmd, tv_cmd->tvc_cdb);
+       if (rc == -ENOMEM) {
+               transport_send_check_condition_and_sense(se_cmd,
+                               TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
+               transport_generic_free_cmd(se_cmd, 0);
+               return;
+       } else if (rc < 0) {
+               if (se_cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT)
+                       tcm_vhost_queue_status(se_cmd);
+               else
+                       transport_send_check_condition_and_sense(se_cmd,
+                                       se_cmd->scsi_sense_reason, 0);
+               transport_generic_free_cmd(se_cmd, 0);
+               return;
+       }
+
+       if (tv_cmd->tvc_sgl_count) {
+               sg_ptr = tv_cmd->tvc_sgl;
+               /*
+                * For BIDI commands, pass in the extra READ buffer
+                * to transport_generic_map_mem_to_cmd() below..
+                */
+/* FIXME: Fix BIDI operation in tcm_vhost_submission_work() */
+#if 0
+               if (se_cmd->se_cmd_flags & SCF_BIDI) {
+                       sg_bidi_ptr = NULL;
+                       sg_no_bidi = 0;
+               }
+#endif
+       } else {
+               sg_ptr = NULL;
+       }
+
+       rc = transport_generic_map_mem_to_cmd(se_cmd, sg_ptr,
+                               tv_cmd->tvc_sgl_count, sg_bidi_ptr,
+                               sg_no_bidi);
+       if (rc < 0) {
+               transport_send_check_condition_and_sense(se_cmd,
+                               se_cmd->scsi_sense_reason, 0);
+               transport_generic_free_cmd(se_cmd, 0);
+               return;
+       }
+       transport_handle_cdb_direct(se_cmd);
+}
+
+static void vhost_scsi_handle_vq(struct vhost_scsi *vs)
+{
+       struct vhost_virtqueue *vq = &vs->vqs[2];
+       struct virtio_scsi_cmd_req v_req;
+       struct tcm_vhost_tpg *tv_tpg;
+       struct tcm_vhost_cmd *tv_cmd;
+       u32 exp_data_len, data_first, data_num, data_direction;
+       unsigned out, in, i;
+       int head, ret;
+
+       /* Must use ioctl VHOST_SCSI_SET_ENDPOINT */
+       tv_tpg = vs->vs_tpg;
+       if (unlikely(!tv_tpg)) {
+               pr_err("%s endpoint not set\n", __func__);
+               return;
+       }
+
+       mutex_lock(&vq->mutex);
+       vhost_disable_notify(&vs->dev, vq);
+
+       for (;;) {
+               head = vhost_get_vq_desc(&vs->dev, vq, vq->iov,
+                                       ARRAY_SIZE(vq->iov), &out, &in,
+                                       NULL, NULL);
+               pr_debug("vhost_get_vq_desc: head: %d, out: %u in: %u\n",
+                                       head, out, in);
+               /* On error, stop handling until the next kick. */
+               if (unlikely(head < 0))
+                       break;
+               /* Nothing new?  Wait for eventfd to tell us they refilled. */
+               if (head == vq->num) {
+                       if (unlikely(vhost_enable_notify(&vs->dev, vq))) {
+                               vhost_disable_notify(&vs->dev, vq);
+                               continue;
+                       }
+                       break;
+               }
+
+/* FIXME: BIDI operation */
+               if (out == 1 && in == 1) {
+                       data_direction = DMA_NONE;
+                       data_first = 0;
+                       data_num = 0;
+               } else if (out == 1 && in > 1) {
+                       data_direction = DMA_FROM_DEVICE;
+                       data_first = out + 1;
+                       data_num = in - 1;
+               } else if (out > 1 && in == 1) {
+                       data_direction = DMA_TO_DEVICE;
+                       data_first = 1;
+                       data_num = out - 1;
+               } else {
+                       vq_err(vq, "Invalid buffer layout out: %u in: %u\n",
+                                       out, in);
+                       break;
+               }
+
+               /*
+                * Check for a sane resp buffer so we can report errors to
+                * the guest.
+                */
+               if (unlikely(vq->iov[out].iov_len !=
+                                       sizeof(struct virtio_scsi_cmd_resp))) {
+                       vq_err(vq, "Expecting virtio_scsi_cmd_resp, got %zu"
+                               " bytes\n", vq->iov[out].iov_len);
+                       break;
+               }
+
+               if (unlikely(vq->iov[0].iov_len != sizeof(v_req))) {
+                       vq_err(vq, "Expecting virtio_scsi_cmd_req, got %zu"
+                               " bytes\n", vq->iov[0].iov_len);
+                       break;
+               }
+               pr_debug("Calling __copy_from_user: vq->iov[0].iov_base: %p,"
+                       " len: %zu\n", vq->iov[0].iov_base, sizeof(v_req));
+               ret = __copy_from_user(&v_req, vq->iov[0].iov_base,
+                               sizeof(v_req));
+               if (unlikely(ret)) {
+                       vq_err(vq, "Faulted on virtio_scsi_cmd_req\n");
+                       break;
+               }
+
+               exp_data_len = 0;
+               for (i = 0; i < data_num; i++)
+                       exp_data_len += vq->iov[data_first + i].iov_len;
+
+               tv_cmd = vhost_scsi_allocate_cmd(tv_tpg, &v_req,
+                                       exp_data_len, data_direction);
+               if (IS_ERR(tv_cmd)) {
+                       vq_err(vq, "vhost_scsi_allocate_cmd failed %ld\n",
+                                       PTR_ERR(tv_cmd));
+                       break;
+               }
+               pr_debug("Allocated tv_cmd: %p exp_data_len: %d, data_direction"
+                       ": %d\n", tv_cmd, exp_data_len, data_direction);
+
+               tv_cmd->tvc_vhost = vs;
+
+               if (unlikely(vq->iov[out].iov_len !=
+                               sizeof(struct virtio_scsi_cmd_resp))) {
+                       vq_err(vq, "Expecting virtio_scsi_cmd_resp, got %zu"
+                               " bytes, out: %d, in: %d\n",
+                               vq->iov[out].iov_len, out, in);
+                       break;
+               }
+
+               tv_cmd->tvc_resp = vq->iov[out].iov_base;
+
+               /*
+                * Copy in the recieved CDB descriptor into tv_cmd->tvc_cdb
+                * that will be used by tcm_vhost_new_cmd_map() and down into
+                * target_setup_cmd_from_cdb()
+                */
+               memcpy(tv_cmd->tvc_cdb, v_req.cdb, TCM_VHOST_MAX_CDB_SIZE);
+               /*
+                * Check that the recieved CDB size does not exceeded our
+                * hardcoded max for tcm_vhost
+                */
+               /* TODO what if cdb was too small for varlen cdb header? */
+               if (unlikely(scsi_command_size(tv_cmd->tvc_cdb) >
+                                       TCM_VHOST_MAX_CDB_SIZE)) {
+                       vq_err(vq, "Received SCSI CDB with command_size: %d that"
+                               " exceeds SCSI_MAX_VARLEN_CDB_SIZE: %d\n",
+                               scsi_command_size(tv_cmd->tvc_cdb),
+                               TCM_VHOST_MAX_CDB_SIZE);
+                       break; /* TODO */
+               }
+               tv_cmd->tvc_lun = ((v_req.lun[2] << 8) | v_req.lun[3]) & 0x3FFF;
+
+               pr_debug("vhost_scsi got command opcode: %#02x, lun: %d\n",
+                       tv_cmd->tvc_cdb[0], tv_cmd->tvc_lun);
+
+               if (data_direction != DMA_NONE) {
+                       ret = vhost_scsi_map_iov_to_sgl(tv_cmd,
+                                       &vq->iov[data_first], data_num,
+                                       data_direction == DMA_TO_DEVICE);
+                       if (unlikely(ret)) {
+                               vq_err(vq, "Failed to map iov to sgl\n");
+                               break; /* TODO */
+                       }
+               }
+
+               /*
+                * Save the descriptor from vhost_get_vq_desc() to be used to
+                * complete the virtio-scsi request in TCM callback context via
+                * tcm_vhost_queue_data_in() and tcm_vhost_queue_status()
+                */
+               tv_cmd->tvc_vq_desc = head;
+               /*
+                * Dispatch tv_cmd descriptor for cmwq execution in process
+                * context provided by tcm_vhost_workqueue.  This also ensures
+                * tv_cmd is executed on the same kworker CPU as this vhost
+                * thread to gain positive L2 cache locality effects..
+                */
+               INIT_WORK(&tv_cmd->work, tcm_vhost_submission_work);
+               queue_work(tcm_vhost_workqueue, &tv_cmd->work);
+       }
+
+       mutex_unlock(&vq->mutex);
+}
+
+static void vhost_scsi_ctl_handle_kick(struct vhost_work *work)
+{
+       pr_err("%s: The handling func for control queue.\n", __func__);
+}
+
+static void vhost_scsi_evt_handle_kick(struct vhost_work *work)
+{
+       pr_err("%s: The handling func for event queue.\n", __func__);
+}
+
+static void vhost_scsi_handle_kick(struct vhost_work *work)
+{
+       struct vhost_virtqueue *vq = container_of(work, struct vhost_virtqueue,
+                                               poll.work);
+       struct vhost_scsi *vs = container_of(vq->dev, struct vhost_scsi, dev);
+
+       vhost_scsi_handle_vq(vs);
+}
+
+/*
+ * Called from vhost_scsi_ioctl() context to walk the list of available
+ * tcm_vhost_tpg with an active struct tcm_vhost_nexus
+ */
+static int vhost_scsi_set_endpoint(
+       struct vhost_scsi *vs,
+       struct vhost_scsi_target *t)
+{
+       struct tcm_vhost_tport *tv_tport;
+       struct tcm_vhost_tpg *tv_tpg;
+       int index;
+
+       mutex_lock(&vs->dev.mutex);
+       /* Verify that ring has been setup correctly. */
+       for (index = 0; index < vs->dev.nvqs; ++index) {
+               /* Verify that ring has been setup correctly. */
+               if (!vhost_vq_access_ok(&vs->vqs[index])) {
+                       mutex_unlock(&vs->dev.mutex);
+                       return -EFAULT;
+               }
+       }
+
+       if (vs->vs_tpg) {
+               mutex_unlock(&vs->dev.mutex);
+               return -EEXIST;
+       }
+       mutex_unlock(&vs->dev.mutex);
+
+       mutex_lock(&tcm_vhost_mutex);
+       list_for_each_entry(tv_tpg, &tcm_vhost_list, tv_tpg_list) {
+               mutex_lock(&tv_tpg->tv_tpg_mutex);
+               if (!tv_tpg->tpg_nexus) {
+                       mutex_unlock(&tv_tpg->tv_tpg_mutex);
+                       continue;
+               }
+               if (atomic_read(&tv_tpg->tv_tpg_vhost_count)) {
+                       mutex_unlock(&tv_tpg->tv_tpg_mutex);
+                       continue;
+               }
+               tv_tport = tv_tpg->tport;
+
+               if (!strcmp(tv_tport->tport_name, t->vhost_wwpn) &&
+                   (tv_tpg->tport_tpgt == t->vhost_tpgt)) {
+                       atomic_inc(&tv_tpg->tv_tpg_vhost_count);
+                       smp_mb__after_atomic_inc();
+                       mutex_unlock(&tv_tpg->tv_tpg_mutex);
+                       mutex_unlock(&tcm_vhost_mutex);
+
+                       mutex_lock(&vs->dev.mutex);
+                       vs->vs_tpg = tv_tpg;
+                       atomic_inc(&vs->vhost_ref_cnt);
+                       smp_mb__after_atomic_inc();
+                       mutex_unlock(&vs->dev.mutex);
+                       return 0;
+               }
+               mutex_unlock(&tv_tpg->tv_tpg_mutex);
+       }
+       mutex_unlock(&tcm_vhost_mutex);
+       return -EINVAL;
+}
+
+static int vhost_scsi_clear_endpoint(
+       struct vhost_scsi *vs,
+       struct vhost_scsi_target *t)
+{
+       struct tcm_vhost_tport *tv_tport;
+       struct tcm_vhost_tpg *tv_tpg;
+       int index;
+
+       mutex_lock(&vs->dev.mutex);
+       /* Verify that ring has been setup correctly. */
+       for (index = 0; index < vs->dev.nvqs; ++index) {
+               if (!vhost_vq_access_ok(&vs->vqs[index])) {
+                       mutex_unlock(&vs->dev.mutex);
+                       return -EFAULT;
+               }
+       }
+
+       if (!vs->vs_tpg) {
+               mutex_unlock(&vs->dev.mutex);
+               return -ENODEV;
+       }
+       tv_tpg = vs->vs_tpg;
+       tv_tport = tv_tpg->tport;
+
+       if (strcmp(tv_tport->tport_name, t->vhost_wwpn) ||
+           (tv_tpg->tport_tpgt != t->vhost_tpgt)) {
+               mutex_unlock(&vs->dev.mutex);
+               pr_warn("tv_tport->tport_name: %s, tv_tpg->tport_tpgt: %hu"
+                       " does not match t->vhost_wwpn: %s, t->vhost_tpgt: %hu\n",
+                       tv_tport->tport_name, tv_tpg->tport_tpgt,
+                       t->vhost_wwpn, t->vhost_tpgt);
+               return -EINVAL;
+       }
+       atomic_dec(&tv_tpg->tv_tpg_vhost_count);
+       vs->vs_tpg = NULL;
+       mutex_unlock(&vs->dev.mutex);
+
+       return 0;
+}
+
+static int vhost_scsi_open(struct inode *inode, struct file *f)
+{
+       struct vhost_scsi *s;
+       int r;
+
+       s = kzalloc(sizeof(*s), GFP_KERNEL);
+       if (!s)
+               return -ENOMEM;
+
+       vhost_work_init(&s->vs_completion_work, vhost_scsi_complete_cmd_work);
+       INIT_LIST_HEAD(&s->vs_completion_list);
+       spin_lock_init(&s->vs_completion_lock);
+
+       s->vqs[0].handle_kick = vhost_scsi_ctl_handle_kick;
+       s->vqs[1].handle_kick = vhost_scsi_evt_handle_kick;
+       s->vqs[2].handle_kick = vhost_scsi_handle_kick;
+       r = vhost_dev_init(&s->dev, s->vqs, 3);
+       if (r < 0) {
+               kfree(s);
+               return r;
+       }
+
+       f->private_data = s;
+       return 0;
+}
+
+static int vhost_scsi_release(struct inode *inode, struct file *f)
+{
+       struct vhost_scsi *s = f->private_data;
+
+       if (s->vs_tpg && s->vs_tpg->tport) {
+               struct vhost_scsi_target backend;
+
+               memcpy(backend.vhost_wwpn, s->vs_tpg->tport->tport_name,
+                               sizeof(backend.vhost_wwpn));
+               backend.vhost_tpgt = s->vs_tpg->tport_tpgt;
+               vhost_scsi_clear_endpoint(s, &backend);
+       }
+
+       vhost_dev_cleanup(&s->dev, false);
+       kfree(s);
+       return 0;
+}
+
+static int vhost_scsi_set_features(struct vhost_scsi *vs, u64 features)
+{
+       if (features & ~VHOST_FEATURES)
+               return -EOPNOTSUPP;
+
+       mutex_lock(&vs->dev.mutex);
+       if ((features & (1 << VHOST_F_LOG_ALL)) &&
+           !vhost_log_access_ok(&vs->dev)) {
+               mutex_unlock(&vs->dev.mutex);
+               return -EFAULT;
+       }
+       vs->dev.acked_features = features;
+       /* TODO possibly smp_wmb() and flush vqs */
+       mutex_unlock(&vs->dev.mutex);
+       return 0;
+}
+
+static long vhost_scsi_ioctl(struct file *f, unsigned int ioctl,
+                               unsigned long arg)
+{
+       struct vhost_scsi *vs = f->private_data;
+       struct vhost_scsi_target backend;
+       void __user *argp = (void __user *)arg;
+       u64 __user *featurep = argp;
+       u64 features;
+       int r;
+
+       switch (ioctl) {
+       case VHOST_SCSI_SET_ENDPOINT:
+               if (copy_from_user(&backend, argp, sizeof backend))
+                       return -EFAULT;
+
+               return vhost_scsi_set_endpoint(vs, &backend);
+       case VHOST_SCSI_CLEAR_ENDPOINT:
+               if (copy_from_user(&backend, argp, sizeof backend))
+                       return -EFAULT;
+
+               return vhost_scsi_clear_endpoint(vs, &backend);
+       case VHOST_SCSI_GET_ABI_VERSION:
+               if (copy_from_user(&backend, argp, sizeof backend))
+                       return -EFAULT;
+
+               backend.abi_version = VHOST_SCSI_ABI_VERSION;
+
+               if (copy_to_user(argp, &backend, sizeof backend))
+                       return -EFAULT;
+               return 0;
+       case VHOST_GET_FEATURES:
+               features = VHOST_FEATURES;
+               if (copy_to_user(featurep, &features, sizeof features))
+                       return -EFAULT;
+               return 0;
+       case VHOST_SET_FEATURES:
+               if (copy_from_user(&features, featurep, sizeof features))
+                       return -EFAULT;
+               return vhost_scsi_set_features(vs, features);
+       default:
+               mutex_lock(&vs->dev.mutex);
+               r = vhost_dev_ioctl(&vs->dev, ioctl, arg);
+               mutex_unlock(&vs->dev.mutex);
+               return r;
+       }
+}
+
+static const struct file_operations vhost_scsi_fops = {
+       .owner          = THIS_MODULE,
+       .release        = vhost_scsi_release,
+       .unlocked_ioctl = vhost_scsi_ioctl,
+       /* TODO compat ioctl? */
+       .open           = vhost_scsi_open,
+       .llseek         = noop_llseek,
+};
+
+static struct miscdevice vhost_scsi_misc = {
+       MISC_DYNAMIC_MINOR,
+       "vhost-scsi",
+       &vhost_scsi_fops,
+};
+
+static int __init vhost_scsi_register(void)
+{
+       return misc_register(&vhost_scsi_misc);
+}
+
+static int vhost_scsi_deregister(void)
+{
+       return misc_deregister(&vhost_scsi_misc);
+}
+
+static char *tcm_vhost_dump_proto_id(struct tcm_vhost_tport *tport)
+{
+       switch (tport->tport_proto_id) {
+       case SCSI_PROTOCOL_SAS:
+               return "SAS";
+       case SCSI_PROTOCOL_FCP:
+               return "FCP";
+       case SCSI_PROTOCOL_ISCSI:
+               return "iSCSI";
+       default:
+               break;
+       }
+
+       return "Unknown";
+}
+
+static int tcm_vhost_port_link(
+       struct se_portal_group *se_tpg,
+       struct se_lun *lun)
+{
+       struct tcm_vhost_tpg *tv_tpg = container_of(se_tpg,
+                               struct tcm_vhost_tpg, se_tpg);
+
+       atomic_inc(&tv_tpg->tv_tpg_port_count);
+       smp_mb__after_atomic_inc();
+
+       return 0;
+}
+
+static void tcm_vhost_port_unlink(
+       struct se_portal_group *se_tpg,
+       struct se_lun *se_lun)
+{
+       struct tcm_vhost_tpg *tv_tpg = container_of(se_tpg,
+                               struct tcm_vhost_tpg, se_tpg);
+
+       atomic_dec(&tv_tpg->tv_tpg_port_count);
+       smp_mb__after_atomic_dec();
+}
+
+static struct se_node_acl *tcm_vhost_make_nodeacl(
+       struct se_portal_group *se_tpg,
+       struct config_group *group,
+       const char *name)
+{
+       struct se_node_acl *se_nacl, *se_nacl_new;
+       struct tcm_vhost_nacl *nacl;
+       u64 wwpn = 0;
+       u32 nexus_depth;
+
+       /* tcm_vhost_parse_wwn(name, &wwpn, 1) < 0)
+               return ERR_PTR(-EINVAL); */
+       se_nacl_new = tcm_vhost_alloc_fabric_acl(se_tpg);
+       if (!se_nacl_new)
+               return ERR_PTR(-ENOMEM);
+
+       nexus_depth = 1;
+       /*
+        * se_nacl_new may be released by core_tpg_add_initiator_node_acl()
+        * when converting a NodeACL from demo mode -> explict
+        */
+       se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new,
+                               name, nexus_depth);
+       if (IS_ERR(se_nacl)) {
+               tcm_vhost_release_fabric_acl(se_tpg, se_nacl_new);
+               return se_nacl;
+       }
+       /*
+        * Locate our struct tcm_vhost_nacl and set the FC Nport WWPN
+        */
+       nacl = container_of(se_nacl, struct tcm_vhost_nacl, se_node_acl);
+       nacl->iport_wwpn = wwpn;
+
+       return se_nacl;
+}
+
+static void tcm_vhost_drop_nodeacl(struct se_node_acl *se_acl)
+{
+       struct tcm_vhost_nacl *nacl = container_of(se_acl,
+                               struct tcm_vhost_nacl, se_node_acl);
+       core_tpg_del_initiator_node_acl(se_acl->se_tpg, se_acl, 1);
+       kfree(nacl);
+}
+
+static int tcm_vhost_make_nexus(
+       struct tcm_vhost_tpg *tv_tpg,
+       const char *name)
+{
+       struct se_portal_group *se_tpg;
+       struct tcm_vhost_nexus *tv_nexus;
+
+       mutex_lock(&tv_tpg->tv_tpg_mutex);
+       if (tv_tpg->tpg_nexus) {
+               mutex_unlock(&tv_tpg->tv_tpg_mutex);
+               pr_debug("tv_tpg->tpg_nexus already exists\n");
+               return -EEXIST;
+       }
+       se_tpg = &tv_tpg->se_tpg;
+
+       tv_nexus = kzalloc(sizeof(struct tcm_vhost_nexus), GFP_KERNEL);
+       if (!tv_nexus) {
+               mutex_unlock(&tv_tpg->tv_tpg_mutex);
+               pr_err("Unable to allocate struct tcm_vhost_nexus\n");
+               return -ENOMEM;
+       }
+       /*
+        *  Initialize the struct se_session pointer
+        */
+       tv_nexus->tvn_se_sess = transport_init_session();
+       if (IS_ERR(tv_nexus->tvn_se_sess)) {
+               mutex_unlock(&tv_tpg->tv_tpg_mutex);
+               kfree(tv_nexus);
+               return -ENOMEM;
+       }
+       /*
+        * Since we are running in 'demo mode' this call with generate a
+        * struct se_node_acl for the tcm_vhost struct se_portal_group with
+        * the SCSI Initiator port name of the passed configfs group 'name'.
+        */
+       tv_nexus->tvn_se_sess->se_node_acl = core_tpg_check_initiator_node_acl(
+                               se_tpg, (unsigned char *)name);
+       if (!tv_nexus->tvn_se_sess->se_node_acl) {
+               mutex_unlock(&tv_tpg->tv_tpg_mutex);
+               pr_debug("core_tpg_check_initiator_node_acl() failed"
+                               " for %s\n", name);
+               transport_free_session(tv_nexus->tvn_se_sess);
+               kfree(tv_nexus);
+               return -ENOMEM;
+       }
+       /*
+        * Now register the TCM vHost virtual I_T Nexus as active with the
+        * call to __transport_register_session()
+        */
+       __transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl,
+                       tv_nexus->tvn_se_sess, tv_nexus);
+       tv_tpg->tpg_nexus = tv_nexus;
+
+       mutex_unlock(&tv_tpg->tv_tpg_mutex);
+       return 0;
+}
+
+static int tcm_vhost_drop_nexus(
+       struct tcm_vhost_tpg *tpg)
+{
+       struct se_session *se_sess;
+       struct tcm_vhost_nexus *tv_nexus;
+
+       mutex_lock(&tpg->tv_tpg_mutex);
+       tv_nexus = tpg->tpg_nexus;
+       if (!tv_nexus) {
+               mutex_unlock(&tpg->tv_tpg_mutex);
+               return -ENODEV;
+       }
+
+       se_sess = tv_nexus->tvn_se_sess;
+       if (!se_sess) {
+               mutex_unlock(&tpg->tv_tpg_mutex);
+               return -ENODEV;
+       }
+
+       if (atomic_read(&tpg->tv_tpg_port_count)) {
+               mutex_unlock(&tpg->tv_tpg_mutex);
+               pr_err("Unable to remove TCM_vHost I_T Nexus with"
+                       " active TPG port count: %d\n",
+                       atomic_read(&tpg->tv_tpg_port_count));
+               return -EPERM;
+       }
+
+       if (atomic_read(&tpg->tv_tpg_vhost_count)) {
+               mutex_unlock(&tpg->tv_tpg_mutex);
+               pr_err("Unable to remove TCM_vHost I_T Nexus with"
+                       " active TPG vhost count: %d\n",
+                       atomic_read(&tpg->tv_tpg_vhost_count));
+               return -EPERM;
+       }
+
+       pr_debug("TCM_vHost_ConfigFS: Removing I_T Nexus to emulated"
+               " %s Initiator Port: %s\n", tcm_vhost_dump_proto_id(tpg->tport),
+               tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
+       /*
+        * Release the SCSI I_T Nexus to the emulated vHost Target Port
+        */
+       transport_deregister_session(tv_nexus->tvn_se_sess);
+       tpg->tpg_nexus = NULL;
+       mutex_unlock(&tpg->tv_tpg_mutex);
+
+       kfree(tv_nexus);
+       return 0;
+}
+
+static ssize_t tcm_vhost_tpg_show_nexus(
+       struct se_portal_group *se_tpg,
+       char *page)
+{
+       struct tcm_vhost_tpg *tv_tpg = container_of(se_tpg,
+                               struct tcm_vhost_tpg, se_tpg);
+       struct tcm_vhost_nexus *tv_nexus;
+       ssize_t ret;
+
+       mutex_lock(&tv_tpg->tv_tpg_mutex);
+       tv_nexus = tv_tpg->tpg_nexus;
+       if (!tv_nexus) {
+               mutex_unlock(&tv_tpg->tv_tpg_mutex);
+               return -ENODEV;
+       }
+       ret = snprintf(page, PAGE_SIZE, "%s\n",
+                       tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
+       mutex_unlock(&tv_tpg->tv_tpg_mutex);
+
+       return ret;
+}
+
+static ssize_t tcm_vhost_tpg_store_nexus(
+       struct se_portal_group *se_tpg,
+       const char *page,
+       size_t count)
+{
+       struct tcm_vhost_tpg *tv_tpg = container_of(se_tpg,
+                               struct tcm_vhost_tpg, se_tpg);
+       struct tcm_vhost_tport *tport_wwn = tv_tpg->tport;
+       unsigned char i_port[TCM_VHOST_NAMELEN], *ptr, *port_ptr;
+       int ret;
+       /*
+        * Shutdown the active I_T nexus if 'NULL' is passed..
+        */
+       if (!strncmp(page, "NULL", 4)) {
+               ret = tcm_vhost_drop_nexus(tv_tpg);
+               return (!ret) ? count : ret;
+       }
+       /*
+        * Otherwise make sure the passed virtual Initiator port WWN matches
+        * the fabric protocol_id set in tcm_vhost_make_tport(), and call
+        * tcm_vhost_make_nexus().
+        */
+       if (strlen(page) >= TCM_VHOST_NAMELEN) {
+               pr_err("Emulated NAA Sas Address: %s, exceeds"
+                               " max: %d\n", page, TCM_VHOST_NAMELEN);
+               return -EINVAL;
+       }
+       snprintf(&i_port[0], TCM_VHOST_NAMELEN, "%s", page);
+
+       ptr = strstr(i_port, "naa.");
+       if (ptr) {
+               if (tport_wwn->tport_proto_id != SCSI_PROTOCOL_SAS) {
+                       pr_err("Passed SAS Initiator Port %s does not"
+                               " match target port protoid: %s\n", i_port,
+                               tcm_vhost_dump_proto_id(tport_wwn));
+                       return -EINVAL;
+               }
+               port_ptr = &i_port[0];
+               goto check_newline;
+       }
+       ptr = strstr(i_port, "fc.");
+       if (ptr) {
+               if (tport_wwn->tport_proto_id != SCSI_PROTOCOL_FCP) {
+                       pr_err("Passed FCP Initiator Port %s does not"
+                               " match target port protoid: %s\n", i_port,
+                               tcm_vhost_dump_proto_id(tport_wwn));
+                       return -EINVAL;
+               }
+               port_ptr = &i_port[3]; /* Skip over "fc." */
+               goto check_newline;
+       }
+       ptr = strstr(i_port, "iqn.");
+       if (ptr) {
+               if (tport_wwn->tport_proto_id != SCSI_PROTOCOL_ISCSI) {
+                       pr_err("Passed iSCSI Initiator Port %s does not"
+                               " match target port protoid: %s\n", i_port,
+                               tcm_vhost_dump_proto_id(tport_wwn));
+                       return -EINVAL;
+               }
+               port_ptr = &i_port[0];
+               goto check_newline;
+       }
+       pr_err("Unable to locate prefix for emulated Initiator Port:"
+                       " %s\n", i_port);
+       return -EINVAL;
+       /*
+        * Clear any trailing newline for the NAA WWN
+        */
+check_newline:
+       if (i_port[strlen(i_port)-1] == '\n')
+               i_port[strlen(i_port)-1] = '\0';
+
+       ret = tcm_vhost_make_nexus(tv_tpg, port_ptr);
+       if (ret < 0)
+               return ret;
+
+       return count;
+}
+
+TF_TPG_BASE_ATTR(tcm_vhost, nexus, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *tcm_vhost_tpg_attrs[] = {
+       &tcm_vhost_tpg_nexus.attr,
+       NULL,
+};
+
+static struct se_portal_group *tcm_vhost_make_tpg(
+       struct se_wwn *wwn,
+       struct config_group *group,
+       const char *name)
+{
+       struct tcm_vhost_tport *tport = container_of(wwn,
+                       struct tcm_vhost_tport, tport_wwn);
+
+       struct tcm_vhost_tpg *tpg;
+       unsigned long tpgt;
+       int ret;
+
+       if (strstr(name, "tpgt_") != name)
+               return ERR_PTR(-EINVAL);
+       if (kstrtoul(name + 5, 10, &tpgt) || tpgt > UINT_MAX)
+               return ERR_PTR(-EINVAL);
+
+       tpg = kzalloc(sizeof(struct tcm_vhost_tpg), GFP_KERNEL);
+       if (!tpg) {
+               pr_err("Unable to allocate struct tcm_vhost_tpg");
+               return ERR_PTR(-ENOMEM);
+       }
+       mutex_init(&tpg->tv_tpg_mutex);
+       INIT_LIST_HEAD(&tpg->tv_tpg_list);
+       tpg->tport = tport;
+       tpg->tport_tpgt = tpgt;
+
+       ret = core_tpg_register(&tcm_vhost_fabric_configfs->tf_ops, wwn,
+                               &tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL);
+       if (ret < 0) {
+               kfree(tpg);
+               return NULL;
+       }
+       mutex_lock(&tcm_vhost_mutex);
+       list_add_tail(&tpg->tv_tpg_list, &tcm_vhost_list);
+       mutex_unlock(&tcm_vhost_mutex);
+
+       return &tpg->se_tpg;
+}
+
+static void tcm_vhost_drop_tpg(struct se_portal_group *se_tpg)
+{
+       struct tcm_vhost_tpg *tpg = container_of(se_tpg,
+                               struct tcm_vhost_tpg, se_tpg);
+
+       mutex_lock(&tcm_vhost_mutex);
+       list_del(&tpg->tv_tpg_list);
+       mutex_unlock(&tcm_vhost_mutex);
+       /*
+        * Release the virtual I_T Nexus for this vHost TPG
+        */
+       tcm_vhost_drop_nexus(tpg);
+       /*
+        * Deregister the se_tpg from TCM..
+        */
+       core_tpg_deregister(se_tpg);
+       kfree(tpg);
+}
+
+static struct se_wwn *tcm_vhost_make_tport(
+       struct target_fabric_configfs *tf,
+       struct config_group *group,
+       const char *name)
+{
+       struct tcm_vhost_tport *tport;
+       char *ptr;
+       u64 wwpn = 0;
+       int off = 0;
+
+       /* if (tcm_vhost_parse_wwn(name, &wwpn, 1) < 0)
+               return ERR_PTR(-EINVAL); */
+
+       tport = kzalloc(sizeof(struct tcm_vhost_tport), GFP_KERNEL);
+       if (!tport) {
+               pr_err("Unable to allocate struct tcm_vhost_tport");
+               return ERR_PTR(-ENOMEM);
+       }
+       tport->tport_wwpn = wwpn;
+       /*
+        * Determine the emulated Protocol Identifier and Target Port Name
+        * based on the incoming configfs directory name.
+        */
+       ptr = strstr(name, "naa.");
+       if (ptr) {
+               tport->tport_proto_id = SCSI_PROTOCOL_SAS;
+               goto check_len;
+       }
+       ptr = strstr(name, "fc.");
+       if (ptr) {
+               tport->tport_proto_id = SCSI_PROTOCOL_FCP;
+               off = 3; /* Skip over "fc." */
+               goto check_len;
+       }
+       ptr = strstr(name, "iqn.");
+       if (ptr) {
+               tport->tport_proto_id = SCSI_PROTOCOL_ISCSI;
+               goto check_len;
+       }
+
+       pr_err("Unable to locate prefix for emulated Target Port:"
+                       " %s\n", name);
+       kfree(tport);
+       return ERR_PTR(-EINVAL);
+
+check_len:
+       if (strlen(name) >= TCM_VHOST_NAMELEN) {
+               pr_err("Emulated %s Address: %s, exceeds"
+                       " max: %d\n", name, tcm_vhost_dump_proto_id(tport),
+                       TCM_VHOST_NAMELEN);
+               kfree(tport);
+               return ERR_PTR(-EINVAL);
+       }
+       snprintf(&tport->tport_name[0], TCM_VHOST_NAMELEN, "%s", &name[off]);
+
+       pr_debug("TCM_VHost_ConfigFS: Allocated emulated Target"
+               " %s Address: %s\n", tcm_vhost_dump_proto_id(tport), name);
+
+       return &tport->tport_wwn;
+}
+
+static void tcm_vhost_drop_tport(struct se_wwn *wwn)
+{
+       struct tcm_vhost_tport *tport = container_of(wwn,
+                               struct tcm_vhost_tport, tport_wwn);
+
+       pr_debug("TCM_VHost_ConfigFS: Deallocating emulated Target"
+               " %s Address: %s\n", tcm_vhost_dump_proto_id(tport),
+               tport->tport_name);
+
+       kfree(tport);
+}
+
+static ssize_t tcm_vhost_wwn_show_attr_version(
+       struct target_fabric_configfs *tf,
+       char *page)
+{
+       return sprintf(page, "TCM_VHOST fabric module %s on %s/%s"
+               "on "UTS_RELEASE"\n", TCM_VHOST_VERSION, utsname()->sysname,
+               utsname()->machine);
+}
+
+TF_WWN_ATTR_RO(tcm_vhost, version);
+
+static struct configfs_attribute *tcm_vhost_wwn_attrs[] = {
+       &tcm_vhost_wwn_version.attr,
+       NULL,
+};
+
+static struct target_core_fabric_ops tcm_vhost_ops = {
+       .get_fabric_name                = tcm_vhost_get_fabric_name,
+       .get_fabric_proto_ident         = tcm_vhost_get_fabric_proto_ident,
+       .tpg_get_wwn                    = tcm_vhost_get_fabric_wwn,
+       .tpg_get_tag                    = tcm_vhost_get_tag,
+       .tpg_get_default_depth          = tcm_vhost_get_default_depth,
+       .tpg_get_pr_transport_id        = tcm_vhost_get_pr_transport_id,
+       .tpg_get_pr_transport_id_len    = tcm_vhost_get_pr_transport_id_len,
+       .tpg_parse_pr_out_transport_id  = tcm_vhost_parse_pr_out_transport_id,
+       .tpg_check_demo_mode            = tcm_vhost_check_true,
+       .tpg_check_demo_mode_cache      = tcm_vhost_check_true,
+       .tpg_check_demo_mode_write_protect = tcm_vhost_check_false,
+       .tpg_check_prod_mode_write_protect = tcm_vhost_check_false,
+       .tpg_alloc_fabric_acl           = tcm_vhost_alloc_fabric_acl,
+       .tpg_release_fabric_acl         = tcm_vhost_release_fabric_acl,
+       .tpg_get_inst_index             = tcm_vhost_tpg_get_inst_index,
+       .release_cmd                    = tcm_vhost_release_cmd,
+       .shutdown_session               = tcm_vhost_shutdown_session,
+       .close_session                  = tcm_vhost_close_session,
+       .sess_get_index                 = tcm_vhost_sess_get_index,
+       .sess_get_initiator_sid         = NULL,
+       .write_pending                  = tcm_vhost_write_pending,
+       .write_pending_status           = tcm_vhost_write_pending_status,
+       .set_default_node_attributes    = tcm_vhost_set_default_node_attrs,
+       .get_task_tag                   = tcm_vhost_get_task_tag,
+       .get_cmd_state                  = tcm_vhost_get_cmd_state,
+       .queue_data_in                  = tcm_vhost_queue_data_in,
+       .queue_status                   = tcm_vhost_queue_status,
+       .queue_tm_rsp                   = tcm_vhost_queue_tm_rsp,
+       .get_fabric_sense_len           = tcm_vhost_get_fabric_sense_len,
+       .set_fabric_sense_len           = tcm_vhost_set_fabric_sense_len,
+       /*
+        * Setup callers for generic logic in target_core_fabric_configfs.c
+        */
+       .fabric_make_wwn                = tcm_vhost_make_tport,
+       .fabric_drop_wwn                = tcm_vhost_drop_tport,
+       .fabric_make_tpg                = tcm_vhost_make_tpg,
+       .fabric_drop_tpg                = tcm_vhost_drop_tpg,
+       .fabric_post_link               = tcm_vhost_port_link,
+       .fabric_pre_unlink              = tcm_vhost_port_unlink,
+       .fabric_make_np                 = NULL,
+       .fabric_drop_np                 = NULL,
+       .fabric_make_nodeacl            = tcm_vhost_make_nodeacl,
+       .fabric_drop_nodeacl            = tcm_vhost_drop_nodeacl,
+};
+
+static int tcm_vhost_register_configfs(void)
+{
+       struct target_fabric_configfs *fabric;
+       int ret;
+
+       pr_debug("TCM_VHOST fabric module %s on %s/%s"
+               " on "UTS_RELEASE"\n", TCM_VHOST_VERSION, utsname()->sysname,
+               utsname()->machine);
+       /*
+        * Register the top level struct config_item_type with TCM core
+        */
+       fabric = target_fabric_configfs_init(THIS_MODULE, "vhost");
+       if (IS_ERR(fabric)) {
+               pr_err("target_fabric_configfs_init() failed\n");
+               return PTR_ERR(fabric);
+       }
+       /*
+        * Setup fabric->tf_ops from our local tcm_vhost_ops
+        */
+       fabric->tf_ops = tcm_vhost_ops;
+       /*
+        * Setup default attribute lists for various fabric->tf_cit_tmpl
+        */
+       TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = tcm_vhost_wwn_attrs;
+       TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = tcm_vhost_tpg_attrs;
+       TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = NULL;
+       TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL;
+       TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL;
+       TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs = NULL;
+       TF_CIT_TMPL(fabric)->tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
+       TF_CIT_TMPL(fabric)->tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
+       TF_CIT_TMPL(fabric)->tfc_tpg_nacl_param_cit.ct_attrs = NULL;
+       /*
+        * Register the fabric for use within TCM
+        */
+       ret = target_fabric_configfs_register(fabric);
+       if (ret < 0) {
+               pr_err("target_fabric_configfs_register() failed"
+                               " for TCM_VHOST\n");
+               return ret;
+       }
+       /*
+        * Setup our local pointer to *fabric
+        */
+       tcm_vhost_fabric_configfs = fabric;
+       pr_debug("TCM_VHOST[0] - Set fabric -> tcm_vhost_fabric_configfs\n");
+       return 0;
+};
+
+static void tcm_vhost_deregister_configfs(void)
+{
+       if (!tcm_vhost_fabric_configfs)
+               return;
+
+       target_fabric_configfs_deregister(tcm_vhost_fabric_configfs);
+       tcm_vhost_fabric_configfs = NULL;
+       pr_debug("TCM_VHOST[0] - Cleared tcm_vhost_fabric_configfs\n");
+};
+
+static int __init tcm_vhost_init(void)
+{
+       int ret = -ENOMEM;
+
+       tcm_vhost_workqueue = alloc_workqueue("tcm_vhost", 0, 0);
+       if (!tcm_vhost_workqueue)
+               goto out;
+
+       ret = vhost_scsi_register();
+       if (ret < 0)
+               goto out_destroy_workqueue;
+
+       ret = tcm_vhost_register_configfs();
+       if (ret < 0)
+               goto out_vhost_scsi_deregister;
+
+       return 0;
+
+out_vhost_scsi_deregister:
+       vhost_scsi_deregister();
+out_destroy_workqueue:
+       destroy_workqueue(tcm_vhost_workqueue);
+out:
+       return ret;
+};
+
+static void tcm_vhost_exit(void)
+{
+       tcm_vhost_deregister_configfs();
+       vhost_scsi_deregister();
+       destroy_workqueue(tcm_vhost_workqueue);
+};
+
+MODULE_DESCRIPTION("TCM_VHOST series fabric driver");
+MODULE_LICENSE("GPL");
+module_init(tcm_vhost_init);
+module_exit(tcm_vhost_exit);
diff --git a/drivers/vhost/tcm_vhost.h b/drivers/vhost/tcm_vhost.h
new file mode 100644 (file)
index 0000000..c983ed2
--- /dev/null
@@ -0,0 +1,101 @@
+#define TCM_VHOST_VERSION  "v0.1"
+#define TCM_VHOST_NAMELEN 256
+#define TCM_VHOST_MAX_CDB_SIZE 32
+
+struct tcm_vhost_cmd {
+       /* Descriptor from vhost_get_vq_desc() for virt_queue segment */
+       int tvc_vq_desc;
+       /* The Tag from include/linux/virtio_scsi.h:struct virtio_scsi_cmd_req */
+       u64 tvc_tag;
+       /* The number of scatterlists associated with this cmd */
+       u32 tvc_sgl_count;
+       /* Saved unpacked SCSI LUN for tcm_vhost_submission_work() */
+       u32 tvc_lun;
+       /* Pointer to the SGL formatted memory from virtio-scsi */
+       struct scatterlist *tvc_sgl;
+       /* Pointer to response */
+       struct virtio_scsi_cmd_resp __user *tvc_resp;
+       /* Pointer to vhost_scsi for our device */
+       struct vhost_scsi *tvc_vhost;
+       /* The TCM I/O descriptor that is accessed via container_of() */
+       struct se_cmd tvc_se_cmd;
+       /* work item used for cmwq dispatch to tcm_vhost_submission_work() */
+       struct work_struct work;
+       /* Copy of the incoming SCSI command descriptor block (CDB) */
+       unsigned char tvc_cdb[TCM_VHOST_MAX_CDB_SIZE];
+       /* Sense buffer that will be mapped into outgoing status */
+       unsigned char tvc_sense_buf[TRANSPORT_SENSE_BUFFER];
+       /* Completed commands list, serviced from vhost worker thread */
+       struct list_head tvc_completion_list;
+};
+
+struct tcm_vhost_nexus {
+       /* Pointer to TCM session for I_T Nexus */
+       struct se_session *tvn_se_sess;
+};
+
+struct tcm_vhost_nacl {
+       /* Binary World Wide unique Port Name for Vhost Initiator port */
+       u64 iport_wwpn;
+       /* ASCII formatted WWPN for Sas Initiator port */
+       char iport_name[TCM_VHOST_NAMELEN];
+       /* Returned by tcm_vhost_make_nodeacl() */
+       struct se_node_acl se_node_acl;
+};
+
+struct tcm_vhost_tpg {
+       /* Vhost port target portal group tag for TCM */
+       u16 tport_tpgt;
+       /* Used to track number of TPG Port/Lun Links wrt to explict I_T Nexus shutdown */
+       atomic_t tv_tpg_port_count;
+       /* Used for vhost_scsi device reference to tpg_nexus */
+       atomic_t tv_tpg_vhost_count;
+       /* list for tcm_vhost_list */
+       struct list_head tv_tpg_list;
+       /* Used to protect access for tpg_nexus */
+       struct mutex tv_tpg_mutex;
+       /* Pointer to the TCM VHost I_T Nexus for this TPG endpoint */
+       struct tcm_vhost_nexus *tpg_nexus;
+       /* Pointer back to tcm_vhost_tport */
+       struct tcm_vhost_tport *tport;
+       /* Returned by tcm_vhost_make_tpg() */
+       struct se_portal_group se_tpg;
+};
+
+struct tcm_vhost_tport {
+       /* SCSI protocol the tport is providing */
+       u8 tport_proto_id;
+       /* Binary World Wide unique Port Name for Vhost Target port */
+       u64 tport_wwpn;
+       /* ASCII formatted WWPN for Vhost Target port */
+       char tport_name[TCM_VHOST_NAMELEN];
+       /* Returned by tcm_vhost_make_tport() */
+       struct se_wwn tport_wwn;
+};
+
+/*
+ * As per request from MST, keep TCM_VHOST related ioctl defines out of
+ * linux/vhost.h (user-space) for now..
+ */
+
+#include <linux/vhost.h>
+
+/*
+ * Used by QEMU userspace to ensure a consistent vhost-scsi ABI.
+ *
+ * ABI Rev 0: July 2012 version starting point for v3.6-rc merge candidate +
+ *            RFC-v2 vhost-scsi userspace.  Add GET_ABI_VERSION ioctl usage
+ */
+
+#define VHOST_SCSI_ABI_VERSION 0
+
+struct vhost_scsi_target {
+       int abi_version;
+       unsigned char vhost_wwpn[TRANSPORT_IQN_LEN];
+       unsigned short vhost_tpgt;
+};
+
+/* VHOST_SCSI specific defines */
+#define VHOST_SCSI_SET_ENDPOINT _IOW(VHOST_VIRTIO, 0x40, struct vhost_scsi_target)
+#define VHOST_SCSI_CLEAR_ENDPOINT _IOW(VHOST_VIRTIO, 0x41, struct vhost_scsi_target)
+#define VHOST_SCSI_GET_ABI_VERSION _IOW(VHOST_VIRTIO, 0x42, struct vhost_scsi_target)
index f75da8758adcf79612d6a8b5b566a00624a0e42f..f49181c7311390c471b0abc6caa6d8ca6ae4de91 100644 (file)
@@ -228,7 +228,6 @@ static int pm860x_backlight_probe(struct platform_device *pdev)
        data->port = pdata->flags;
        if (data->port < 0) {
                dev_err(&pdev->dev, "wrong platform data is assigned");
-               kfree(data);
                return -EINVAL;
        }
 
index 2dcdbc9364d8802ed26154f18097a8995b5c5271..99ebdde590f8266dc1b734c9c827fd40693d227f 100644 (file)
@@ -15,6 +15,7 @@ if VIRT_DRIVERS
 config FSL_HV_MANAGER
        tristate "Freescale hypervisor management driver"
        depends on FSL_SOC
+       select EPAPR_PARAVIRT
        help
           The Freescale hypervisor management driver provides several services
          to drivers and applications related to the Freescale hypervisor:
index 5ceb1cd501955003182fe62b365da7d1b5d282f2..7e984034a11b03a97ae3e9fbfbfd4313297f98b8 100644 (file)
@@ -60,7 +60,6 @@ config W1_MASTER_GPIO
 
 config HDQ_MASTER_OMAP
        tristate "OMAP HDQ driver"
-       depends on ARCH_OMAP2PLUS
        help
          Say Y here if you want support for the 1-wire or HDQ Interface
          on an OMAP processor.
index 4b0fcf3c2d035f8aba0d0e0ba938f34df6621ef2..ca8e60bb2f9cb386f454a33224d6cc7906a20fc7 100644 (file)
@@ -18,9 +18,6 @@
 #include <linux/sched.h>
 #include <linux/pm_runtime.h>
 
-#include <asm/irq.h>
-#include <mach/hardware.h>
-
 #include "../w1.h"
 #include "../w1_int.h"
 
@@ -73,11 +70,11 @@ struct hdq_data {
 };
 
 static int __devinit omap_hdq_probe(struct platform_device *pdev);
-static int omap_hdq_remove(struct platform_device *pdev);
+static int __devexit omap_hdq_remove(struct platform_device *pdev);
 
 static struct platform_driver omap_hdq_driver = {
        .probe =        omap_hdq_probe,
-       .remove =       omap_hdq_remove,
+       .remove =       __devexit_p(omap_hdq_remove),
        .driver =       {
                .name = "omap_hdq",
        },
@@ -538,39 +535,35 @@ static void omap_w1_write_byte(void *_hdq, u8 byte)
                hdq_data->init_trans = 0;
                mutex_unlock(&hdq_data->hdq_mutex);
        }
-
-       return;
 }
 
 static int __devinit omap_hdq_probe(struct platform_device *pdev)
 {
+       struct device *dev = &pdev->dev;
        struct hdq_data *hdq_data;
        struct resource *res;
        int ret, irq;
        u8 rev;
 
-       hdq_data = kmalloc(sizeof(*hdq_data), GFP_KERNEL);
+       hdq_data = devm_kzalloc(dev, sizeof(*hdq_data), GFP_KERNEL);
        if (!hdq_data) {
                dev_dbg(&pdev->dev, "unable to allocate memory\n");
-               ret = -ENOMEM;
-               goto err_kmalloc;
+               return -ENOMEM;
        }
 
-       hdq_data->dev = &pdev->dev;
+       hdq_data->dev = dev;
        platform_set_drvdata(pdev, hdq_data);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
                dev_dbg(&pdev->dev, "unable to get resource\n");
-               ret = -ENXIO;
-               goto err_resource;
+               return -ENXIO;
        }
 
-       hdq_data->hdq_base = ioremap(res->start, SZ_4K);
+       hdq_data->hdq_base = devm_request_and_ioremap(dev, res);
        if (!hdq_data->hdq_base) {
                dev_dbg(&pdev->dev, "ioremap failed\n");
-               ret = -EINVAL;
-               goto err_ioremap;
+               return -ENOMEM;
        }
 
        hdq_data->hdq_usecount = 0;
@@ -591,7 +584,8 @@ static int __devinit omap_hdq_probe(struct platform_device *pdev)
                goto err_irq;
        }
 
-       ret = request_irq(irq, hdq_isr, IRQF_DISABLED, "omap_hdq", hdq_data);
+       ret = devm_request_irq(dev, irq, hdq_isr, IRQF_DISABLED,
+                       "omap_hdq", hdq_data);
        if (ret < 0) {
                dev_dbg(&pdev->dev, "could not request irq\n");
                goto err_irq;
@@ -616,19 +610,10 @@ err_irq:
 err_w1:
        pm_runtime_disable(&pdev->dev);
 
-       iounmap(hdq_data->hdq_base);
-
-err_ioremap:
-err_resource:
-       platform_set_drvdata(pdev, NULL);
-       kfree(hdq_data);
-
-err_kmalloc:
        return ret;
-
 }
 
-static int omap_hdq_remove(struct platform_device *pdev)
+static int __devexit omap_hdq_remove(struct platform_device *pdev)
 {
        struct hdq_data *hdq_data = platform_get_drvdata(pdev);
 
@@ -644,27 +629,11 @@ static int omap_hdq_remove(struct platform_device *pdev)
 
        /* remove module dependency */
        pm_runtime_disable(&pdev->dev);
-       free_irq(INT_24XX_HDQ_IRQ, hdq_data);
-       platform_set_drvdata(pdev, NULL);
-       iounmap(hdq_data->hdq_base);
-       kfree(hdq_data);
 
        return 0;
 }
 
-static int __init
-omap_hdq_init(void)
-{
-       return platform_driver_register(&omap_hdq_driver);
-}
-module_init(omap_hdq_init);
-
-static void __exit
-omap_hdq_exit(void)
-{
-       platform_driver_unregister(&omap_hdq_driver);
-}
-module_exit(omap_hdq_exit);
+module_platform_driver(omap_hdq_driver);
 
 module_param(w1_id, int, S_IRUSR);
 MODULE_PARM_DESC(w1_id, "1-wire id for the slave detection");
index df600d14974d6ddcbe2ec00bdbb6b199b779537c..6012c4ea3206ac58e5d8c0efc561859b10c4b4b1 100644 (file)
@@ -14,6 +14,8 @@
 #include <linux/slab.h>
 #include <linux/w1-gpio.h>
 #include <linux/gpio.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
 
 #include "../w1.h"
 #include "../w1_int.h"
@@ -42,12 +44,55 @@ static u8 w1_gpio_read_bit(void *data)
        return gpio_get_value(pdata->pin) ? 1 : 0;
 }
 
+#ifdef CONFIG_OF
+static struct of_device_id w1_gpio_dt_ids[] = {
+       { .compatible = "w1-gpio" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, w1_gpio_dt_ids);
+
+static int w1_gpio_probe_dt(struct platform_device *pdev)
+{
+       struct w1_gpio_platform_data *pdata = pdev->dev.platform_data;
+       struct device_node *np = pdev->dev.of_node;
+       const struct of_device_id *of_id =
+                       of_match_device(w1_gpio_dt_ids, &pdev->dev);
+
+       if (!of_id)
+               return 0;
+
+       pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return -ENOMEM;
+
+       if (of_get_property(np, "linux,open-drain", NULL))
+               pdata->is_open_drain = 1;
+
+       pdata->pin = of_get_gpio(np, 0);
+       pdata->ext_pullup_enable_pin = of_get_gpio(np, 1);
+       pdev->dev.platform_data = pdata;
+
+       return 0;
+}
+#else
+static int w1_gpio_probe_dt(struct platform_device *pdev)
+{
+       return 0;
+}
+#endif
+
 static int __init w1_gpio_probe(struct platform_device *pdev)
 {
        struct w1_bus_master *master;
-       struct w1_gpio_platform_data *pdata = pdev->dev.platform_data;
+       struct w1_gpio_platform_data *pdata;
        int err;
 
+       err = w1_gpio_probe_dt(pdev);
+       if (err < 0)
+               return err;
+
+       pdata = pdev->dev.platform_data;
+
        if (!pdata)
                return -ENXIO;
 
@@ -59,6 +104,13 @@ static int __init w1_gpio_probe(struct platform_device *pdev)
        if (err)
                goto free_master;
 
+       if (gpio_is_valid(pdata->ext_pullup_enable_pin)) {
+               err = gpio_request_one(pdata->ext_pullup_enable_pin,
+                                      GPIOF_INIT_LOW, "w1 pullup");
+               if (err < 0)
+                       goto free_gpio;
+       }
+
        master->data = pdata;
        master->read_bit = w1_gpio_read_bit;
 
@@ -72,15 +124,21 @@ static int __init w1_gpio_probe(struct platform_device *pdev)
 
        err = w1_add_master_device(master);
        if (err)
-               goto free_gpio;
+               goto free_gpio_ext_pu;
 
        if (pdata->enable_external_pullup)
                pdata->enable_external_pullup(1);
 
+       if (gpio_is_valid(pdata->ext_pullup_enable_pin))
+               gpio_set_value(pdata->ext_pullup_enable_pin, 1);
+
        platform_set_drvdata(pdev, master);
 
        return 0;
 
+ free_gpio_ext_pu:
+       if (gpio_is_valid(pdata->ext_pullup_enable_pin))
+               gpio_free(pdata->ext_pullup_enable_pin);
  free_gpio:
        gpio_free(pdata->pin);
  free_master:
@@ -97,6 +155,9 @@ static int __exit w1_gpio_remove(struct platform_device *pdev)
        if (pdata->enable_external_pullup)
                pdata->enable_external_pullup(0);
 
+       if (gpio_is_valid(pdata->ext_pullup_enable_pin))
+               gpio_set_value(pdata->ext_pullup_enable_pin, 0);
+
        w1_remove_master_device(master);
        gpio_free(pdata->pin);
        kfree(master);
@@ -135,6 +196,7 @@ static struct platform_driver w1_gpio_driver = {
        .driver = {
                .name   = "w1-gpio",
                .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(w1_gpio_dt_ids),
        },
        .remove = __exit_p(w1_gpio_remove),
        .suspend = w1_gpio_suspend,
index d90062b211f8a107a142f439129a6f8d699aa1de..92d08e7fcba2377088bf4b45b12e18f773f6bb23 100644 (file)
@@ -91,6 +91,11 @@ static struct w1_family w1_therm_family_DS28EA00 = {
        .fops = &w1_therm_fops,
 };
 
+static struct w1_family w1_therm_family_DS1825 = {
+       .fid = W1_THERM_DS1825,
+       .fops = &w1_therm_fops,
+};
+
 struct w1_therm_family_converter
 {
        u8                      broken;
@@ -120,6 +125,10 @@ static struct w1_therm_family_converter w1_therm_families[] = {
                .f              = &w1_therm_family_DS28EA00,
                .convert        = w1_DS18B20_convert_temp
        },
+       {
+               .f              = &w1_therm_family_DS1825,
+               .convert        = w1_DS18B20_convert_temp
+       }
 };
 
 static inline int w1_DS18B20_convert_temp(u8 rom[9])
index b00ada44a89be8989a46912fb85e976624d5e586..a1f0ce151d53d902813ef9f6521ee4973c9f053b 100644 (file)
@@ -39,6 +39,7 @@
 #define W1_EEPROM_DS2431       0x2D
 #define W1_FAMILY_DS2760       0x30
 #define W1_FAMILY_DS2780       0x32
+#define W1_THERM_DS1825                0x3B
 #define W1_FAMILY_DS2781       0x3D
 #define W1_THERM_DS28EA00      0x42
 
index 40f7bf1f8654da6f9db51a1d78637353f55cd9f3..e6a038ae8dc28bf6c64a6311e886b6afa8853db8 100644 (file)
@@ -193,7 +193,7 @@ static int __devinit mpc8xxx_wdt_probe(struct platform_device *ofdev)
        int ret;
        const struct of_device_id *match;
        struct device_node *np = ofdev->dev.of_node;
-       struct mpc8xxx_wdt_type *wdt_type;
+       const struct mpc8xxx_wdt_type *wdt_type;
        u32 freq = fsl_get_sys_freq();
        bool enabled;
 
index 7595581d032cc9d9c5a7f04ee12b861dc76051ee..f14e7a18072082eeb1df2b8d3a77c7b52c50a855 100644 (file)
@@ -869,7 +869,6 @@ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
                struct irq_info *info = info_for_irq(irq);
                WARN_ON(info == NULL || info->type != IRQT_IPI);
        }
-
  out:
        mutex_unlock(&irq_mapping_update_lock);
        return irq;
@@ -949,7 +948,6 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
                struct irq_info *info = info_for_irq(irq);
                WARN_ON(info == NULL || info->type != IRQT_VIRQ);
        }
-
 out:
        mutex_unlock(&irq_mapping_update_lock);
 
index 181fa8158a8b01d48393bb9d2b1d9d4e0bf9e79e..858c9714b2f390a26e1a1450f196d7abf6e14340 100644 (file)
@@ -37,7 +37,6 @@ struct zorro_dev zorro_autocon[ZORRO_NUM_AUTO];
      */
 
 struct zorro_bus {
-       struct list_head devices;       /* list of devices on this bus */
        struct device dev;
 };
 
@@ -136,7 +135,6 @@ static int __init amiga_zorro_probe(struct platform_device *pdev)
        if (!bus)
                return -ENOMEM;
 
-       INIT_LIST_HEAD(&bus->devices);
        bus->dev.parent = &pdev->dev;
        dev_set_name(&bus->dev, "zorro");
        error = device_register(&bus->dev);
index 344713b1166953376b60ea1ae3cb062578342139..eeb14030d8a24e67f113d65f1da1578d04b3de89 100644 (file)
@@ -40,10 +40,8 @@ fw-shipped-$(CONFIG_BNX2) += bnx2/bnx2-mips-09-6.2.1a.fw \
                             bnx2/bnx2-mips-06-6.2.1.fw \
                             bnx2/bnx2-rv2p-06-6.0.15.fw
 fw-shipped-$(CONFIG_CASSINI) += sun/cassini.bin
-fw-shipped-$(CONFIG_COMPUTONE) += intelliport2.bin
 fw-shipped-$(CONFIG_CHELSIO_T3) += cxgb3/t3b_psram-1.1.0.bin \
                                   cxgb3/t3c_psram-1.1.0.bin \
-                                  cxgb3/t3fw-7.10.0.bin \
                                   cxgb3/ael2005_opt_edc.bin \
                                   cxgb3/ael2005_twx_edc.bin \
                                   cxgb3/ael2020_twx_edc.bin
diff --git a/firmware/cxgb3/t3fw-7.10.0.bin.ihex b/firmware/cxgb3/t3fw-7.10.0.bin.ihex
deleted file mode 100644 (file)
index 96399d8..0000000
+++ /dev/null
@@ -1,1935 +0,0 @@
-:1000000060007400200380002003700000001000D6
-:1000100000002000E100028400070000E1000288E7
-:1000200000010000E0000000E00000A0010000006E
-:1000300044444440E3000183200200002001E0002A
-:100040002001FF101FFFD0001FFFC000E300043C91
-:100050000200000020006C841FFFC2A020006CCCB6
-:100060001FFFC2A420006D0C1FFFC2A820006D80DE
-:100070001FFFC2AC200003C0C00000E43100EA3121
-:1000800000A13100A03103020002ED306E2A05000C
-:10009000ED3100020002160012FFDBC03014FFDA5F
-:1000A000D30FD30FD30F03431F244C107249F0D347
-:1000B0000FD30FD30F12FFD5230A00240A00D30F4A
-:1000C000D30FD30F03431F244C107249F0D30FD327
-:1000D0000FD30F14FFCE03421F14FFCB03421F1296
-:1000E000FFCCC0302D37302D37342D37382D373CED
-:1000F000233D017233ED00020012FFC4C0302F37E0
-:10010000002F37102F37202F3730233D017233ED6A
-:1001100000020012FFBEC0302737002737102737F4
-:1001200020273730233D017233ED03020012FFB95F
-:1001300013FFBA0C0200932012FFB913FFB90C028F
-:1001400000932012FFB8C0319320822012FFB71312
-:10015000FFB7932012FFB715FFB316FFB6C030D715
-:100160002005660160001B00000000000000000088
-:10017000043605000200D30FD30F05330C6E3B1479
-:100180000747140704437631E604360505330C6F40
-:100190003BED00020012FFA615FFA3230A00D720A3
-:1001A000070443043E0505330C0747146F3BF00377
-:1001B000020012FFA1C03014FFA1D30FD30FD30F41
-:1001C0009340B4447249F2D30FD30FD30F14FF9B63
-:1001D000834014FF9B834012FF9B230A0014FF9A65
-:1001E000D30FD30FD30F9340B4447249F2D30FD33C
-:1001F0000FD30F14FF95834012FF95C92F832084DE
-:10020000218522BC22743B0F8650B4559630B433FE
-:100210007433F463FFE60000653FE1655FDE12FFC3
-:100220007C230A0028374028374428374828374C91
-:10023000233D017233ED03020000020012FF7AC079
-:1002400032032E0503020012FF7813FF819320C0B2
-:1002500011014931004831010200C00014FF7E0441
-:10026000D23115FF7D945014FF7D04D33115FF7CEE
-:10027000945014FF7C04D43115FF7C24560014FFE5
-:100280007B04D53115FF7B24560010FF7A03000054
-:10029000000000000000000000000000000000005E
-:1002A000000000000000000000000000000000004E
-:1002B000000000000000000000000000000000003E
-:1002C000000000000000000000000000000000002E
-:1002D000000000000000000000000000000000001E
-:1002E000000000000000000000000000000000000E
-:1002F00000000000000000000000000000000000FE
-:1003000000000000000000000000000000000000ED
-:1003100000000000000000000000000000000000DD
-:1003200000000000000000000000000000000000CD
-:1003300000000000000000000000000000000000BD
-:1003400000000000000000000000000000000000AD
-:10035000000000000000000000000000000000009D
-:10036000000000000000000000000000000000008D
-:10037000000000000000000000000000000000007D
-:10038000000000000000000000000000000000006D
-:10039000000000000000000000000000000000005D
-:1003A000000000000000000000000000000000004D
-:1003B000000000000000000000000000000000003D
-:1003C000000000000000000000000000000000002D
-:1003D000000000000000000000000000000000001D
-:1003E000000000000000000000000000000000000D
-:1003F00000000000000000000000000000000000FD
-:1004000000000000000000000000000000000000EC
-:1004100000000000000000000000000000000000DC
-:1004200063FFFC000000000000000000000000006E
-:100430000000000000000000000000001FFC0000A1
-:100440001FFC0000E30005C81FFC00001FFC0000AB
-:10045000E30005C81FFC00001FFC0000E30005C806
-:100460001FFFC0001FFFC000E30005C81FFFC00042
-:100470001FFFC018E30005C81FFFC0181FFFC018EA
-:10048000E30005E01FFFC0181FFFC294E30005E072
-:100490001FFFC2941FFFC294E300085C1FFFC2A0AD
-:1004A0001FFFC59CE300085C200000002000016ADB
-:1004B000E3000B582000018020000180E3000CC401
-:1004C0002000020020000203E3000CC42000021CF4
-:1004D00020000220E3000CC8200002202000022699
-:1004E000E3000CCC2000023C20000240E3000CD4CE
-:1004F0002000024020000249E3000CD82000024CFA
-:1005000020000250E3000CE42000025020000259B9
-:10051000E3000CE82000025C20000260E3000CF421
-:100520002000026020000269E3000CF82000026C49
-:1005300020000270E3000D04200002702000027908
-:10054000E3000D082000028C2000028CE3000D1453
-:100550002000029020000293E3000D14200002AC62
-:10056000200002B0E3000D18200002D0200002F2AB
-:10057000E3000D1C200003B0200003B0E3000D4099
-:10058000200003B0200003B0E3000D40200003B0C2
-:10059000200003B0E3000D40200003B0200003B0B2
-:1005A000E3000D40200003B020006EA4E3000D40E6
-:1005B00020006EA420006EA4E30078340000000048
-:1005C00000000000000000001FFC00001FFC0000F5
-:1005D0001FFFC5A01FFFC69020006EA820006EA8B8
-:1005E000DEFFFE000000080CDEADBEEF1FFFC2B054
-:1005F0001FFCFE001FFFC0A41FFFC5D0300000007D
-:10060000003FFFFF8040000010000000080FFFFFC8
-:100610001FFFC27D000FFFFF804FFFFF8000000023
-:1006200000000880B000000560500000600000007D
-:1006300040000011350000004100000010000001E2
-:100640002000000000001000400000000500000035
-:10065000800000190400000000000800E100020012
-:1006600010000005806000007000000020000009FC
-:10067000001FF8008000001EA0000000F80000002D
-:1006800007FFFFFF080000001800000001008001C4
-:10069000420000001FFFC22D1FFFC0EC00010080C0
-:1006A000604000001A0000000C0000001000000A6A
-:1006B000000030000001000080000018FC00000075
-:1006C0008000000100004000600008008000001C65
-:1006D0008000001A030000008000040004030403EB
-:1006E00050000003FFFFBFFF1FFFC3E400000FFF28
-:1006F000FFFFF000000016D00000FFF7A50000008B
-:100700001FFFC4C01FFFC4710001000800000B20C0
-:10071000202FFF801FFFC46500002C00FFFEFFF8A4
-:1007200000FFFFFF1FFFC58800002000FFFFDFFF65
-:100730000000FFEF010011001FFFC3E21FFFC5A073
-:10074000FFFFEFFF0000FFFB1FFFC6501FFFBEB003
-:10075000FFFFF7FF1FFFC0740000FFFD1FFFC64033
-:100760000001FBD01FFFC5C01FFFC6801FFFC5A132
-:10077000E0FFFE001FFFC5B0000080001FFFC54C5A
-:100780001FFFC5C41FFFC0781FFFC4E41FFCFFD8B4
-:10079000000100817FFFFFFFE1000600000027103D
-:1007A0001FFCFE301FFCFE701FFFC5481FFFC56009
-:1007B0000003D0901FFFC5742B5063802B507980AD
-:1007C0002B5090802B50A6801FFFC4790100110F81
-:1007D000202FFE0020300080202FFF000000FFFFB0
-:1007E0000001FFF82B50B2002B50B208000100109E
-:1007F0002B50B1802B50B2802B50BA000001001159
-:100800002B50BD282B50BC802B50BDA020300000A9
-:10081000DFFFFE005000000200C0000002000000E8
-:10082000FFFFF7F41FFFC07C000FF800044000003A
-:10083000001000000C4000001C400000E00000A080
-:100840001FFFC5501FFD00081FFFC5641FFFC578AF
-:100850001FFFC58CE1000690E10006EC00000000DF
-:100860000000000000000000000000000100000087
-:100870000000000000000000000000002010004008
-:10088000201000402010004020140080200C0000A8
-:10089000200C0000200C00002010004020140080DC
-:1008A0002014008020140080201800C0201C0100AB
-:1008B000201C0100201C010020200140201800C045
-:1008C000201800C0201800C0201C0100201800C003
-:1008D000201800C0201800C0201C0100202001406A
-:1008E00020200140202001402020094020200940F4
-:1008F000202009402020094020240980FFFFFFFF1D
-:10090000FFFFFFFFFFFFFFFF0000000000000000EF
-:1009100000000000000000000000000020005588DA
-:1009200020005458200055882000558820005394FA
-:100930002000539420005394200051D4200051D41F
-:10094000200051CC2000513820004FE020004DC045
-:1009500020004B94000000000000000020005558CB
-:1009600020005424200054C8200054C82000527C89
-:100970002000527C2000527C2000527C2000527CBF
-:10098000200051C42000527C20004F0020004D70F8
-:1009900020004B40000000000000000020000BF091
-:1009A00020003ADC200004C02000473020000BE883
-:1009B000200041F4200003F0200046F020004B1CF2
-:1009C00020003F0020003E1C20003A58200038E85C
-:1009D00020003658200031B820003C7820002DD06F
-:1009E0002000286420006828200023F0200020D068
-:1009F0002000207C20001D68200018602000158841
-:100A000020000E5420000C3420001134200013204C
-:100A1000200043EC20003EB420000BF8200004C06E
-:100A200000000000000000000000000000000000C6
-:100A300000000000000000000000000000000000B6
-:100A400000000000000000000000000000000000A6
-:100A50000000000000000000000000000000000096
-:100A60000000000000000000000000000000000086
-:100A70000000000000000000000000000000000076
-:100A80000000000000000000000000000000000066
-:100A90000000000000000000000000000000000056
-:100AA0003264000000000000326400006400640052
-:100AB00064006400640064006400640000000000DE
-:100AC0000000000000000000000000000000000026
-:100AD0000000000000000000000000000000000016
-:100AE0000000000000000000000000000000000006
-:100AF00000000000000000000000000000000000F6
-:100B000000000000000010000000000000000000D5
-:100B100000000000000000000000000000001000C5
-:100B200000000000000000000000000000000000C5
-:100B300000432380000000000000000000000000CF
-:100B400000000000000000000000000000000000A5
-:100B50000000000000000000005C94015D94025E53
-:100B600094035F94004300000000000000000000B8
-:100B70000000000000000000000000000000000075
-:100B80000000000000000000000000000000000065
-:100B90000000000000000000005C90015D90025E1B
-:100BA00090035F9000530000000000000000000070
-:100BB0000000000000000000000000000000000035
-:100BC0000000000000000000000000000000000025
-:100BD0000000000000000000009C94001D90019D9A
-:100BE00094029E94039F94040894050994060A9421
-:100BF000070B94004300000000000000000000000C
-:100C000000000000000000000000000000000000E4
-:100C10000000000000000000009C90019D90029EDA
-:100C200090071D90039F90047890057990067A9024
-:100C3000077B90005300000000000000000000004F
-:100C400000000000000000000000000000000000A4
-:100C5000000000000000000000DC94001D9001DD99
-:100C60009402DE9403DF940404940505940606942C
-:100C70000707940808940909940A0A940B0B940036
-:100C80004300000000000000000000000000000021
-:100C9000000000000000000000DC9001DD9002DE9A
-:100CA000900B1D9003DF9004B49005B59006B690AC
-:100CB00007B79008B89009B9900ABA900BBB90009A
-:100CC0005300000063FFFC0020006C6010FFFF0A6F
-:100CD0000000000020006C8400D23110FFFE0A00EA
-:100CE0000000000020006CCC00D33110FFFE0A0091
-:100CF0000000000020006D0C00D43110FFFE0A003F
-:100D00000000000020006D8000D53110FFFE0A00B9
-:100D10000000000063FFFC00E00000A012FFF7826B
-:100D200020028257C82163FFFC12FFF303E830045E
-:100D3000EE3005C03093209421952263FFFC000023
-:100D40001FFFD000000400201FFFC5A01FFFC6909A
-:100D5000200A0011FFFB13FFFB03E631010200161E
-:100D6000FFFA17FFFAD30F776B069060B4667763CC
-:100D7000F85415F3541AA50F140063FFF90000008E
-:100D80006C1004C020D10F006C1004C0C71AEF060D
-:100D9000D830BC2BD72085720D4211837105450BCD
-:100DA000957202330C2376017B3B04233D0893713B
-:100DB000A32D12EEFE19EEFEA2767D632C2E0A0004
-:100DC000088202280A01038E380E0E42C8EE29A6B8
-:100DD0007E6D4A0500208800308C8271D10FC0F0F2
-:100DE000028F387FC0EA63FFE400C0F1C050037E89
-:100DF0000CA2EE0E3D1208820203F538050542CB27
-:100E00005729A67E2FDC100F4F366DFA050020887B
-:100E100000308CBC75C03008E208280A0105833810
-:100E2000030342C93E29A67E0D480CD30F6D8A05E7
-:100E300000208800B08C8271D10FC05008F5387541
-:100E4000C0C163FFBBC06002863876C0DA63FFD4DE
-:100E50006C101216EED8C1F9C1E8C1C72B221E28AA
-:100E6000221DC0D07B81352920060BB702299CFAB0
-:100E7000655008282072288CFF2824726491642A07
-:100E8000B0000CA80C64816F0EA90C6492BB7FA10A
-:100E90003FC1CE7CA13669AC336000370029200603
-:100EA000D7D0299CFACC57282072288CFF2824728E
-:100EB0006491392AD0000CA80C6481680EA90C64D6
-:100EC000931F7FA10BC1CE7CA10268AC06C020D1CC
-:100ED0000F2D25028A32C0900A6E5065E5B529248F
-:100EE00067090F4765F5B12C200C1FEEB30CCE112E
-:100EF000AFEE29E286B44879830260058219EEAF2D
-:100F000009C90A2992A36890078F2009FF0C65F58B
-:100F10006E2FE28564F56865559628221D7B810554
-:100F2000D9B060000200C0908B9417EEA50B881416
-:100F300087740B0B47A87718EEA309BB100877023C
-:100F400097F018EEA117EEA208A8010B8802074738
-:100F5000021BEE9E97F10B880298F22790232B90AC
-:100F60002204781006BB1007471208BB0228902104
-:100F70000777100C88100788020B880217EE968BF3
-:100F80003307BB0187340B880298F3979997F48B4A
-:100F90009587399BF588968B3898F688979BF897B4
-:100FA000F998F717EE8D28E28507C7082D74CF084A
-:100FB000480B28E68565550F2B221E28221D7B89AC
-:100FC000022B0A0064BF052CB00728B000DA200607
-:100FD000880A28824CC0D10B8000DBA065AFE76394
-:100FE000FEEA0000292072659E946004E72A2072C0
-:100FF00065AEBF6004DE00002EB0032C2067D4E095
-:1010000065C1058A328C330AFF500C4554BC5564C7
-:10101000F4EB19EE72882A09A90109880C64821F71
-:10102000C0926000DD2ED0032A2067D4E065A0D8EE
-:101030008A328B330AFC500B4554BC5564C4BE192C
-:10104000EE67882A09A9017989D50BEA5064A4E3DF
-:101050000CEE11C0F02F16132E16168AE78CE82A14
-:1010600016128EE9DFC0AAEA7EAB01B1CF0BA85001
-:101070006583468837DBC0AE89991E789B022BCCEE
-:10108000012B161B29120E2B0A0029161A7FC307E3
-:101090007FC9027EAB01C0B165B49D8B352F0A00BC
-:1010A0002A0A007AC30564C3CB2F0A0165F4892B91
-:1010B00012162B1619005104C0C100CC1A2CCCFFFB
-:1010C0002C16170CFC132C16182B121A2A121BDCC8
-:1010D000505819B6C0D0C0902E5CF42C12172812AC
-:1010E000182F121B2A121A08FF010CAA01883407B4
-:1010F0004C0AAB8B2812192BC6162F86082A860994
-:101100002E74102924672E70038975B1EA2A74039E
-:10111000B09909490C659DB42B20672D250265B354
-:10112000FA2B221E2C221D7BC901C0B064BD9D2C50
-:10113000B00728B000DA2006880A28824CC0D10BFC
-:101140008000DBA065AFE763FD8289BAB199659045
-:101150009788341CEE2398BA8F331EEE1C0F4F5421
-:101160002FB42C8D2A8A320EDD020CAC017DC966AB
-:101170000A49516F92608A3375A65B2CB0130AED51
-:10118000510DCD010D0D410C0C417DC9492EB01200
-:10119000B0EE65E3C6C0D08E378CB88A368FB97C86
-:1011A000A3077AC9027EFB01C0D1CED988350AAD2A
-:1011B000020E8E0878EB022DAC0189B7DAC0AF9B26
-:1011C00079BB01B1CADCB0C0B07DA3077AD9027C7B
-:1011D000EB01C0B164B161C091292467C020D10F77
-:1011E00000008ADAB1AA64A0C02C20672D25026510
-:1011F000C3111DEDF68A321EEDFB0DAD010EDD0CA7
-:1012000065D28A0A4E516FE202600281C0902924A1
-:1012100067090F4765F2F828221D7B89022B0A0017
-:1012200064BCA92CB00728B000DA2006880A2882FE
-:101230004CC0D10B8000DBA065AFE763FC8E0000E3
-:101240000CE9506492ED0CEF11C080281611AFBF6D
-:101250002F16198EF88BF7DAE08FF92B1610ABFBEF
-:101260007FBB01B1EA0CA8506580D68837DCE0AFBF
-:1012700089991C789B022CEC012C161B29120C2C32
-:101280000A0029161A7AE3077AE9027FBB01C0C176
-:1012900065C2A58B352C0A002A0A007AE30564E1B1
-:1012A000CA2C0A0164CE0D60028E88341BEDCD98E5
-:1012B000DA8F331EEDC60F4F542FD42C8C2A8A326E
-:1012C0000ECC020BAB010CBB0C65BF0A0A49516E78
-:1012D000920263FF018A330AAB5064BEF92CD0132B
-:1012E0000AEE510ECE010E0E410C0C410ECC0C65D7
-:1012F000CEE42FD012B0FF65F26EC0B08E378CD81E
-:101300008A362FD2097CA3077AC9027EFB01C0B1BD
-:1013100065BEC38835DBA0AE8E78EB01B1AB89D753
-:10132000DAC0AF9D79DB01B1CAC0C07BA3077AB92F
-:10133000027DEB01C0C165CE9DC090292467C0200D
-:10134000D10F88378C3698140CE90C29161408F83C
-:101350000C981D78FB07281214B088281614891DD4
-:101360009F159B16C0F02B121429161A2B161B8BD7
-:10137000147AE30B7AE90688158E1678EB01C0F132
-:1013800065F1BA29121A2F12118A352E121B9A1AD8
-:10139000AFEE2F1210C0A0AF9F79FB01B1EE9F11ED
-:1013A000881AC0F098107AE30A7EA9052A12017AF9
-:1013B0008B01C0F164F08160018389368B37991706
-:1013C0000BE80C981F09C90C29161578EB07281291
-:1013D00015B088281615D9C09A199E188A1F2E1282
-:1013E000152A161A2E161BDAC0C0E08C177F930B35
-:1013F0007FA90688188F1978FB01C0E165E13E29B5
-:10140000121A2F12138A352E121B9A1BAFEE2F12AF
-:1014100012C0A0AF9F79FB01B1EE9F13881BC0F0F3
-:1014200098127AE30A7EA9052A12037A8B01C0F189
-:1014300065F10A2E12162E16192A121B005104C02D
-:10144000E100EE1AB0EE2E16170EFF132F16180F2E
-:10145000CC01ACAA2F121A0EBC01ACFC7FCB01B19F
-:10146000AA2A161B2C161A63FC5E00007FB30263C7
-:10147000FE3163FE2B7EB30263FC3063FC2A000066
-:101480006450C0DA20DBC058168AC020D10FC0914A
-:1014900063FD7A00C09163FA44DA20DB70C0D12E7C
-:1014A0000A80C09A2924682C7007581575D2A0D1DB
-:1014B0000F03470B18ED4DDB70A8287873022B7DC6
-:1014C000F8D9B063FA6100002A2C74DB40580EEEA4
-:1014D00063FAE4000029221D2D25027B9901C0B08A
-:1014E000C9B62CB00728B000DA2006880A28824C3A
-:1014F000C0D10B8000DBA065AFE7C020D10FC09149
-:1015000063FBFF00022A0258024C0AA202060000F6
-:10151000022A025802490AA202060000DB70DA2001
-:10152000C0D12E0A80C09E2924682C7007581554FB
-:10153000C020D10FC09463FBC9C09663FBC4C096A2
-:1015400063FBBF002A2C74DB30DC405BFE0FDBA0AA
-:10155000C2A02AB4002C200C63FF27008D358CB765
-:101560007DCB0263FDD263FC6D8F358ED77FEB029E
-:1015700063FDC563FC6000006C1004C020D10F0047
-:101580006C1004C020D10F006C10042B221E2822E6
-:101590001DC0A0C0942924062A25027B8901DBA056
-:1015A000C9B913ED04DA2028B0002CB00703880A6B
-:1015B00028824CC0D10B8000DBA065AFE7C020D1F2
-:1015C0000F0000006C10042C20062A210268C805B8
-:1015D00028CCF965812E0A094C6591048F30C1B879
-:1015E0000F8F147FB00528212365812716ECF3297E
-:1015F000629E6F98026000F819ECEF2992266890BD
-:10160000078A2009AA0C65A0E72A629D64A0E12B45
-:10161000200C0CB911A6992D92866FD9026000DBBF
-:101620001DECE70DBD0A2DD2A368D0078E200DEE6C
-:101630000C65E0C7279285C0E06470BF1DECEC68C4
-:10164000434E1CECEB8A2B0CAA029A708920089955
-:10165000110D99029971882A98748F329F752821EB
-:1016600004088811987718ECDC0CBF11A6FF2DF246
-:1016700085A8B82E84CF2DDC282DF685C85A2A2CB3
-:1016800074DB40580E81D2A0D10FC020D10F0000D2
-:101690000029CCF96490B12C20668931B1CC0C0CB6
-:1016A000472C24666EC60260008509F85065807F6D
-:1016B0001CECD18A2B0F08400B881008AA020CAA38
-:1016C000029A7089200899110D99029971883398AE
-:1016D000738C329C728A2A9A748934997563FF7D5F
-:1016E00000CC57DA20DB30DC4058155FC020D10F2A
-:1016F00000DA20C0B65815EE63FFE500DA20581571
-:10170000EC63FFDC00DA20DB30DC40DD5058167A79
-:10171000D2A0D10FC858DA20DB305814C72A2102D2
-:1017200065AFBDC09409A90229250263FFB200007C
-:101730002B21045814731DECADC0E02E24668F30AD
-:101740002B200C0F8F1463FF66292138C088798302
-:101750001F8C310CFC5064CF562B2104C0C0581490
-:10176000681DECA2C0E08F302B200C0F8F1463FF9C
-:101770003E2C20662B2104B1CC0C0C472C2466583F
-:1017800014601DEC9AC0E02E24668F302B200C0FC5
-:101790008F1463FF1A0000006C1004C0B7C0A116BC
-:1017A000EC9615EC88D720D840B822C04005350209
-:1017B0009671957002A438040442C94B1AEC7B1947
-:1017C000EC7C29A67EC140D30F6D4A0500808800BD
-:1017D000208C220A88A272D10FC05008A53875B09B
-:1017E000E363FFD76C10069313941129200665520A
-:1017F00088C0716898052A9CF965A29816EC6F2933
-:1018000021028A1309094C6590CD8AA00A6A512ADF
-:10181000ACFD65A0C2CC5FDB30DA208C115815120C
-:10182000C0519A13C7BF9BA98E132EE20968E060CE
-:101830002F629E1DEC606FF8026000842DD2266836
-:10184000D0052F22007DF9782C629DC79064C0706E
-:101850009C108A132B200C2AA0200CBD11A6DD0A97
-:101860004F14BFA809880129D286AF88288C09792E
-:101870008B591FEC520FBF0A2FF2A368F0052822E4
-:10188000007F894729D285D4906590756000430018
-:10189000002B200C1FEC4A0CBD11A6DD29D2860FAF
-:1018A000BF0A6E96102FF2A368F00488207F890586
-:1018B00029D285659165DA2058157DC95C6001FFE4
-:1018C00000DA20C0B658157A60000C00C09063FFA3
-:1018D000B50000DA205815766551E48D138C11DBC4
-:1018E000D08DD0022A020D6D515813E39A1364A1D2
-:1018F000CEC75F8FA195A9C0510F0F479F1163FEFF
-:10190000FD00C091C0F12820062C2066288CF9A784
-:10191000CC0C0C472C24666FC6098D138DD170DE5C
-:1019200002290A00099D02648159C9D38A102B211A
-:10193000045813F38A13C0B02B24662EA2092AA0E0
-:10194000200E28141CEC298D1315EC1DC1700A778C
-:101950003685562DDC28AC2C9C12DED0A8557CD3C5
-:10196000022EDDF8D3E0DA40055B02DC305BFF8A53
-:10197000D4A028200CB455C0D02B0A882F0A800C84
-:101980008C11A6CC29C285AF3FAB9929C6851CEC2A
-:1019900012DEF0AC882D84CF28120229120378F3CE
-:1019A000022EFDF8289020D3E007880CC1700808AB
-:1019B00047289420087736657FAB891313EC10898C
-:1019C00090C0F47797491BEC0EC1CA2821048513F7
-:1019D000099E4006EE11875304881185520E880235
-:1019E0000C88029BA09FA18F2B9DA598A497A795DB
-:1019F000A603FF029FA22C200C1EEBF7AECE0CCC50
-:101A00001106CC082BC2852DE4CF2BBC202BC6851C
-:101A10002A2C748B11580D9CD2A0D10F28203DC0C8
-:101A2000E07C877F2E24670E0A4765A07B1AEBF5C2
-:101A300088201EEBE38F138EE48FF40888110A8848
-:101A4000020F8F14AFEE1FEBF098910FEE029E90F5
-:101A50001EEBEFC0801AEBE02CD285AABAB8CC28D6
-:101A6000A4CF2CD6852C21022F20720ECC02B1FFE0
-:101A70002F24722C2502C020D10F871387700707EF
-:101A80004763FD6E282138C099798B0263FE9ADD89
-:101A9000F063FE9500DA20DB308C11DD505815968E
-:101AA000D2A0D10FC0E163FF7A8B138C11DD50C03F
-:101AB000AA2E0A802A2468DA205813F1D2A0D10F66
-:101AC000C020D10F6C1006292102C0D07597102AB2
-:101AD00032047FA70A8B357FBF052D25020DD90261
-:101AE000090C4C65C18216EBB41EEBB228629EC095
-:101AF000FA78F30260018829E2266890078A2009B3
-:101B0000AA0C65A17A2A629DDFA064A1772B200C24
-:101B10000CBC11A6CC29C286C08C79830260015707
-:101B200019EBA709B90A2992A368900788200988A8
-:101B30000C65814327C2851CEBA964713A89310980
-:101B40008B140CBB016FB11D2C20669F10B1CC0C07
-:101B50000C472C24666EC60260014009FF5065F1F7
-:101B60003A8A102AAC188934C0C47F973C18EBA974
-:101B70001BEBA88F359C719B708B209D7408BB025A
-:101B80009B72C08298751BEBA40F08409B730F8853
-:101B90001198777FF70B2F2102284A0008FF022FA8
-:101BA0002502C0B4600004000000C0B07E97048F1E
-:101BB000362F25227D970488372825217C9736C02B
-:101BC000F1C0900AF9382F3C200909426490861927
-:101BD000EB7618EB7728967E00F08800A08C00F05A
-:101BE0008800A08C00F08800A08C2A629D2DE4A2C1
-:101BF0002AAC182A669D89307797388F338A321835
-:101C0000EB8007BE0B2C2104B4BB04CC1198E0C0C0
-:101C10008498E1882B9DE59AE69FE71AEB78099F67
-:101C20004006FF110FCC020A880298E2C1FC0FCCDB
-:101C3000022CE604C9B82C200C1EEB670CCA11AEAE
-:101C4000CC06AA0829A2852DC4CF09B90B29A685DF
-:101C5000CF5CC020D10FC081C0900F8938C0877978
-:101C6000880263FF7263FF6600CC57DA20DB30DC4A
-:101C7000405813FDC020D10FDA2058148D63FFE8BF
-:101C8000C0A063FE82DA20C0B658148963FFD90071
-:101C9000DB402A2C74580CFCD2A0D10F8A102B21C7
-:101CA000045813171EEB44C0D02D246663FEB10008
-:101CB0006C1006D62019EB3F1EEB4128610217EB92
-:101CC0003E08084C65805F8A300A6A5169A3572B29
-:101CD000729E6EB83F2A922668A0048C607AC9343E
-:101CE0002A729D2C4CFECAAB2B600CB64F0CBD115A
-:101CF000A7DD28D2860EBE0A78FB269C112EE2A311
-:101D00002C160068E0052F62007EF91522D285CFDF
-:101D10002560000D00DA60C0B6581465C85A60012D
-:101D20000F00DA60581462655106DC40DB308D30FC
-:101D3000DA600D6D515812D0D3A064A0F384A1C015
-:101D40005104044763FF6D00C0B02C60668931B157
-:101D5000CC0C0C472C64666FC60270960A2B61048B
-:101D60005812E7C0B02B64666550B42A3C10C0E737
-:101D7000DC20C0D1C0F002DF380F0F4264F09019B0
-:101D8000EB0A18EB0B28967E8D106DDA0500A08803
-:101D900000C08CC0A089301DEB1A77975388328C15
-:101DA000108F3302CE0BC02492E12261049DE00427
-:101DB00022118D6B9BE59FE798E61FEB1009984079
-:101DC0000688110822020FDD02C18D9DE208220261
-:101DD00092E4B4C22E600C1FEB000CE811A7882C13
-:101DE0008285AFEE0C220B2BE4CF228685D2A0D1C8
-:101DF0000F28600CD2A08C1119EAF80C8D11A9885B
-:101E0000A7DD2ED2852B84CF0ECC0B2CD685D10FFF
-:101E1000C0F00ADF387FE80263FF6C63FF600000F8
-:101E20002A6C74C0B2DC20DD405812C5C0B063FF1C
-:101E300063C020D10F0000006C10042920062A2264
-:101E40001EC0392C221D232468C0307AC107DDA0B2
-:101E5000600004000000C0D06E9738C08F2E0A804A
-:101E60002B2014C0962924060EBB022E21022B24FF
-:101E7000147E8004232502DE307AC10EC8ABDBD08D
-:101E8000DA202C0A00580B062E21020E0F4CC8FE39
-:101E90006000690068956528210208084C65805C2F
-:101EA0001AEAC61EEAC42BA29EC09A7B9B5E2BE256
-:101EB0002668B0048C207BC95329A29D1FEAC16407
-:101EC000904A9390C0C31DEAD52B21049D9608BB70
-:101ED000110CBB029B979B911CEAD2C08523E4A204
-:101EE0002BA29D2824068DFA282102B0DD2BBC30C0
-:101EF0002BA69D9DFA0C8802282502C8D2C020D1AD
-:101F00000F8EF912EAC82E2689C020D10FDA20C020
-:101F1000B65813E7C020D10F6C10062A2006941083
-:101F200068A80528ACF965825029210209094C6589
-:101F3000920ACC5FDB30DA208C1058134BC051D39F
-:101F4000A0C7AF9A3AC0D01CEA9D14EAA31EEA9C2F
-:101F50008F3A16EA99B1FB64B13128629E6F88020C
-:101F60006001ED294C332992266890078A2009AA3E
-:101F70000C65A1DC2A629DC08E64A1D42B200C0CC0
-:101F8000B7110677082972867983026001CD0CB9F2
-:101F90000A2992A36890082C220009CC0C65C1BBC9
-:101FA0002772856471B5282006288CF96481E52C98
-:101FB00020668931B1CC0C0C472C24666EC60260B9
-:101FC00001A109F85065819B2A21048CE488361E02
-:101FD000EA7D088914A9CC08084709881019EA92F3
-:101FE0000ECC029C7099718C2A1EEA9008CC020ECD
-:101FF000CC029C722E302C293013283012049910F8
-:102000000688100CEE109F740EAE0209880208EECE
-:10201000029E738C3704AA119C758938C0F4997696
-:102020008839C0C1987718EA828E359C7B9E780EDD
-:102030008E1408EE029E7A8E301CEA7177E73088A3
-:102040003289339C7C9F7D0E9C4006CC118F2B29BE
-:1020500076132D76112876120CAA0218EA68C1C9E7
-:102060000CAA022A761008FF029F7EC0AA60000117
-:10207000C0A6A4BC0CB911A6992892852DC4CF087E
-:10208000A80B289685655100C020D10F2B200C0C81
-:10209000B7110677082A72860CB90A6FA902600187
-:1020A000182992A36890082A220009AA0C65A109A0
-:1020B0002A728564A1032C203D0C2C4064C08C8CBA
-:1020C000350C8C1464C0848FE57CF37F8C360C8CCB
-:1020D0001464C0777CF374283013C0FC78F86CC0AB
-:1020E00090292467090C4765C0D719EA4718EA45C3
-:1020F0008F208C3508FF110C8C1408FF0288E49F98
-:10210000A1AC8C09CC029CA08C369FA30C8C14AC87
-:102110008809880298A218EA3DA4BC2F72852DC4B4
-:10212000CF2FFC102F76852F210229207208FF0265
-:10213000B2992924722F2502C020D10F00CC57DA82
-:1021400020DB308C105812C8C020D10FC09163FF23
-:102150008FDA20C0B658135663FFE100DA20581317
-:102160005463FFD82B21045811E61EEA152B200CCE
-:10217000C0D02D24668F3A63FE4DDA20DB30DC4080
-:10218000DD505813DDD2A0D10F2A2C748B10580BC0
-:10219000BED2A0D10F292138C08879832E8C310C72
-:1021A000FC5064CE222B2104C0C05811D5C0D01ED3
-:1021B000EA048F3A2B200C63FE0DDA2058133C639F
-:1021C000FF7ADA205BFF1CD2A0D10F002C20662BF7
-:1021D0002104B1CC0C0C472C24665811C91EE9F817
-:1021E0002B200CC0D02D24668F3A63FDDA0000004E
-:1021F0006C10089514C061C1B0D9402A203DC04080
-:102200000BAA010A64382A200629160568A8052C9D
-:10221000ACF965C33F1DE9EA6440052F120464F27E
-:10222000A02621021EE9E606064C6562E615E9E2F3
-:102230006440D98A352930039A130A990C6490CCEA
-:102240002C200C8B139C100CCC11A5CC9C112CC2F7
-:1022500086B4BB7CB3026002D78F100EFE0A2EE25A
-:10226000A368E0098620D30F0E660C6562C2881150
-:102270002882856482BA891364905EDA80D9308CB2
-:10228000201EE9E01FE9E11DE9CE8B138DD4D4B007
-:102290007FB718B88A293C10853608C6110E660229
-:1022A0009681058514A5D50F550295800418146DE7
-:1022B0008927889608CB110888140EBB02A8D82954
-:1022C0009C200F88029BA198A088929BA308881449
-:1022D000A8D80F880298A22AAC1019E9CCC0C08FE8
-:1022E000131EE9BD86118D10286285AEDD08FF0B37
-:1022F0002CD4CF2821022F66858B352A207209889D
-:1023000002ABAA2825022A2472C020D10F29529E8E
-:1023100018E9A96F980260020B28822668800829B4
-:10232000220008990C6591FC2A529DC1CE9A126434
-:10233000A1F22B200C2620060CB8110588082D824E
-:10234000860EBE0A7DC3026002052EE2A368E00885
-:102350002F22000EFF0C65F1F6288285D780DE80E3
-:102360006482009816266CF96462012C206688311C
-:102370002CCC010C0C472C24666EC6026001BC08F4
-:10238000FD5065D1B61DE9AB1CE98F19E9962A21EC
-:10239000048B2D2830102F211D0C88100BFB090AEF
-:1023A00088020988020CBB026441529B709D71989F
-:1023B00072C04D8D35D9E064D06ED730DBD0D830C7
-:1023C0007FD714273C10BCE92632168C3996E69C40
-:1023D000E78A37B4382AE6080B131464304A2A8295
-:1023E0001686799A9696978C778A7D9C982B821779
-:1023F0002C7C209A9A2A9C189B99867BB03B298C2E
-:10240000086DB9218BC996A52692162AAC18B899E1
-:102410009BA196A08BC786CD9BA22B921596A49BC1
-:10242000A386CB2CCC2026A605C0346BD4200D3B34
-:102430000C0DD8090E880A7FB705C0909988BC8812
-:10244000C0900B1A126DAA069988998B288C18C017
-:10245000D01BE97A1CE97916E96EB1FF2A211C2309
-:10246000E6130F0F4F26E6122F251D7FA906C0F099
-:10247000C08028251D05F6111AE9678F202BE61567
-:102480002CE6162DE61726E6180AFA022AE6142983
-:102490002006299CF96490F829200C8D14C0801A1C
-:1024A000E94E0C9C11AA99A5CCDA202BC285289460
-:1024B000CF0B4B0B2BC685C0B08C155811BBD2A0CF
-:1024C000D10F8A356FA546D8308BD56DA90C8A8679
-:1024D0000A8A14CBA77AB335288C10C080282467C9
-:1024E000080B4765B10BDA20DB302C12055811DEE2
-:1024F000D3A0C0C1C0D02DA4039C1463FD22863696
-:102500006461059B709D719872C04D63FEA4C0818B
-:1025100063FFC9008814CC87DA20DB308C15581192
-:10252000D2C020D10FDA20C0B658126163FFE40098
-:1025300000DA208B1058125E63FFD8009E178A12B3
-:102540002B21045810EF8E17C09029246663FE34A7
-:10255000C08063FE06DA20DB308C15DD505812E6B1
-:10256000D2A0D10FDA2058125263FFA7002B2138D6
-:10257000C0A87BAB026001048C310CFC5064CE041B
-:102580008A122B2104C0C098175810DD8E1763FDE6
-:10259000F32D21382DDCFF0D0D4F2D253865DEF78D
-:1025A00028206A7F87050826416460A3C09016E949
-:1025B000141CE9232A200723E61BB1AA0CFD0226DE
-:1025C000E61A2B200A29E61D2DE61E0CBB022BE67F
-:1025D0001C8B260A0A472BE6208B282AE53E2BE691
-:1025E000212924072820062A2064688346B44463EE
-:1025F000FEA5DB30DA208C158D142E0A80C08E28C3
-:10260000246858111FD2A0D10F2E7C4819E8ED2A5A
-:1026100032162B76129D712D761328761489960A20
-:102620002A14AA990C9902997069ED71C14663FD4B
-:102630008100000064AFB51DE8E22C20168DD20A9F
-:10264000CC0C00D10400CC1AACBC9C2963FF9D00CB
-:102650002B21046EB81E2C2066B8CC0C0C472C2401
-:1026600066C9C09E178A125810A68E17C0348F20D4
-:10267000C0D02D2466C06826240663FF2E8A122B44
-:1026800021042C20669817B1CC0C0C472C246658DA
-:10269000109C8E178716C0D02D246663FCE68D35FE
-:1026A000C08064D04AD9E0DC30DBE0DF301AE8E5F6
-:1026B000B188B4FF16E8E584C92D9DFF87C82CCCEE
-:1026C0001027D63006460127D6320A440117E8DF24
-:1026D00024D631A74727D63324F21596B794B68D62
-:1026E000C3BCBB9DB58D35299C107D83C22F211D98
-:1026F000C14663FD330000006C1006292006289CAB
-:10270000F86582BF2921022B200C09094C6590E154
-:1027100016E8AA0CBA11A6AA2DA2862C0A127DC30D
-:102720000260028C19E8A609B90A2992A3689007E9
-:102730008C2009CC0C65C27829A2856492722D6226
-:102740009E1AE89C6FD80260026E2AA22629160102
-:1027500068A0082B22000ABB0C65B25C29629DC1EF
-:102760008C6492542A21200A806099102C203CC746
-:10277000EF000F3E010B3EB1BD0FDB390BBB098FE4
-:10278000260DBD112DDC1C0D0D410EDD038E27B174
-:10279000DD0D0D410FEE0C0DBB0B2BBC1C0BB7025E
-:1027A0007EC71C2C21257BCB162D1AFC0CBA0C0DD8
-:1027B000A16000093E01073EB1780987390B770A0D
-:1027C00077EB0260020A2C2123282121B1CC0C0CCA
-:1027D0004F2C25237C8B29B0CD2D2523C855DA20FD
-:1027E000DB30581095292102CC96C0E80E9E022EAF
-:1027F0002502CC57DA20DB30DC4058111BC020D139
-:102800000F2C20668931B1CC0C0C472C24666EC687
-:10281000026001D309FD5065D1CD2F0A012E301180
-:1028200029221464E01128221B090C4400C1040071
-:10283000FA1A0A880228261B2E3010C0A0C0B094B5
-:102840001295131CE85F88302CC022088D147787FE
-:1028500004C0F10CFA38C041C0F225203CC0840805
-:1028600058010F5F010F4B3805354007BB10C0F012
-:10287000084F3808FF100FBB0228ECFEC0F0084FCD
-:1028800038842B0BA8100AFF102A21200F88020B76
-:10289000880208440218E86E8F1108440228212596
-:1028A0000A2A140828140488110A88022A21049488
-:1028B000F08B2004E41008BB1104BB02C04A04BB27
-:1028C000029BF1842A08AB110BEB0294F40A541119
-:1028D0000B44020555100D1B4094F707BB100B5518
-:1028E00002085502C08195F68433C05094F3B19428
-:1028F0008B3295F898F99BF2C080C1BC24261499BC
-:10290000FA9BF598FB853895FC843A94FD8B3B9BAC
-:10291000FE883998FF853525F6108436851324F610
-:10292000118B3784122BF612C0B064C07E893077C9
-:1029300097438D3288332E30108F111CE83109995E
-:10294000400699112CF614C0C42CF6158C2B2DF6CC
-:102950001A28F61B2BF61904A81109880208EE02A2
-:1029600019E827C18008EE0209C90229F6162EF6D9
-:1029700018C09E600001C09A2F200C18E8170CFEAA
-:1029800011A8FFA6EE2DE2852BF4CF0D9D0B2DE6B1
-:1029900085C87F8A268929A7AA9A260A990C090937
-:1029A00048292525655050C020D10F00C09A63FFEB
-:1029B000C6DA2058113F63FE38DA20C0B658113C01
-:1029C00063FE2E0068973C2B9CFD64BE24C020D182
-:1029D0000FDA20DB705810F8C0C0C0D10ADA390A0B
-:1029E000DC3865CDE063FE098A102B2104580FC442
-:1029F000C0B02B246663FE21DB402A2C745809A248
-:102A0000D2A0D10FDA20580FC963FCF76C1004C0B4
-:102A100020D10F006C1004290A801EE80E1FE80E5A
-:102A20001CE7E60C2B11ACBB2C2CFC2DB2850FCC7B
-:102A3000029ED19CD0C051C07013E80A14E8091856
-:102A4000E8072AB285A82804240A234691A986B853
-:102A5000AA2AB685A98827849F25649FD10F0000E4
-:102A60006C100AD630283010292006288CF9648290
-:102A70009B68980B2A9CF965A1B2022A02580FABF9
-:102A800089371BE7CFC89164520E2A21020A0C4CE9
-:102A900065C2588D3019E7C874D7052E212365E229
-:102AA0009E2F929E1AE7C46FF8026002532AA22654
-:102AB00068A0082C22000ACC0C65C2442A929D64AE
-:102AC000A23E9A151FE7BE8D67C1E6C8DD2B6206E0
-:102AD00018E7BC64B0052880217B8B432B200C18A1
-:102AE000E7B60CBC11A8CC29C28679EB460FBE0A0A
-:102AF0002EE2A368E0052F22007EF9372CC2859CC8
-:102B00001864C2332B212F87660B7B360B790C6F31
-:102B10009D266ED2462C203D7BC740CE5560001EC0
-:102B20002A200CC1B28C205811229A1864A2458D1B
-:102B30006763FFCFC0C063FFC5D7B063FFD300C0DA
-:102B4000E06000022E60030EDB0C6EB20EDC700C37
-:102B5000EA11AA6A2AAC20580199D7A0DA20DB70C2
-:102B6000C1C82D21205810BC8C268B279A160CBB6F
-:102B70000C7AB3348F18896399F3886298F28E6562
-:102B80009EF82D60108A189D1768D729C0D09DA97E
-:102B90002C22182B22139CAB9BAA97A58E667E73C2
-:102BA00002600097CF5860001FDA208B1658108201
-:102BB00065A13863FFBDC081C0908F18C0A29AF98B
-:102BC00099FB98FA97F563FFD2DB30DA20DC4058A6
-:102BD0001026C051D6A0C0C02BA0102CA4039B1758
-:102BE0002C1208022A02066B02DF702D60038E177A
-:102BF0009D149E100CDD11C0E0AD6D2DDC20580140
-:102C0000188C148B16ACAC2C64038A268929ABAAC9
-:102C10000A990C9A26886609094829252507880CEF
-:102C200098662F2218A7FF2F261863FE96DA20DB5E
-:102C300030DC40DD50581130D2A0D10FC0302C20F4
-:102C4000668961B1CC0C0C472C24666EC60260000C
-:102C5000D2C03009FD5065D0CA8E6764E0696470E7
-:102C600066DB608C18DF70DA202D60038E170CDDB8
-:102C7000119E10AD6D2DDC201EE7755800F923263E
-:102C800018DA208B16DC402F2213DD50B1FF2F26DF
-:102C900013580FC5D2A0D10F0028203D0848406529
-:102CA0008DE76F953EDA308DB56D990C8CA80C8C44
-:102CB00014CACF7CD32D2AAC10C090292467090DEB
-:102CC0004764DDC5600092002C1208066B022D6C73
-:102CD00020077F028E17DA209E101EE75C58007DC9
-:102CE00063FF9A00C09163FFD1000000655081DA54
-:102CF00020DB60DC40580FDCC020C0F02FA403D1E3
-:102D00000FDA20C0B658106A63FFE000006F95022A
-:102D100063FD6CDA20DB30DC40DD50C4E0580F5836
-:102D2000D2A0D10F8A152B2104580EF52324662832
-:102D30006010981763FF2100DA2058105D63FFAB25
-:102D4000C858DB30DA20580F3C2A210265AF9CC0FE
-:102D50009409A90229250263FF91DB30DC40DD5094
-:102D6000C0A32E0A802A2468DA20580F45D2A0D1A9
-:102D70000FC020D10FDA202B200C58107263FF6B8C
-:102D80006C1004282006C062288CF8658125C0508C
-:102D9000C7DF2B221BC0E12A206B29212300A104BD
-:102DA000B099292523B1AA00EC1A0BC4010A0A44E0
-:102DB0002A246B04E4390DCC030CBB012B261B64C5
-:102DC000406929200C1BE6FC0C9A110BAA082FA2C3
-:102DD000861BE6FA6FF9026000B60B9B0A2BB2A3C2
-:102DE00068B0082C22000BCC0C65C0A42BA2851D5A
-:102DF000E71E64B09B8C2B2421040DCC029CB08870
-:102E000020C0C50888110C880298B1882A0844118E
-:102E100098B48F3494B79FB5C0401EE6EF2DA285BD
-:102E20000E9E0825E4CF2DDC282DA6852921020938
-:102E3000094C68941A689820C9402A210265A00BA1
-:102E40002A221E2B221D7AB10265A079C020D10F43
-:102E50002C212365CFDE6000082E21212D21237E29
-:102E6000DBD52B221E2F221D2525027BF901C0B0A8
-:102E700064BFC413E6D02CB00728B000DA20038862
-:102E80000A28824CC0D10B8000DBA065AFE763FF4E
-:102E9000A62A2C74C0B02C0A02580E2F1CE6F49CF3
-:102EA000A08B2008BB1106BB029BA1893499A263A9
-:102EB000FF790000262468DA20DB30DC40DD505842
-:102EC000108ED2A0D10FDA202B200C580FF9C02081
-:102ED000D10F00006C1006073D14C080DC30DB40D1
-:102EE000DA20C047C02123BC3003283808084277C5
-:102EF0004001B1DD64815A1EE6AC19E6AD29E67EDB
-:102F0000D30F6DDA0500508800308CC0E0C020255A
-:102F1000A03C14E6ABB6D38FC0C0D00F87142440BA
-:102F2000220F8940941077F704C081048238C0F1E1
-:102F30000B2810C044C02204540104FD3802520181
-:102F400002FE3808DD10821C07EE100E6E020EDD48
-:102F500002242CFEC0E004FE380AEE100E88020D9A
-:102F600088028DAB1EE69B08D8020E880298B0C07E
-:102F7000E80428100E5E0184A025A125084411084C
-:102F80004402052514045511043402C0810E8E3903
-:102F900094B18FAA84109FB475660C26A11FC0F24D
-:102FA000062614600009000026A120C0F20626149F
-:102FB0000565020F770107873905E61007781008C5
-:102FC000660206550295B625A1040AE611085811B5
-:102FD00008280208660296B7C060644056649053A1
-:102FE000067E11C0F489C288C30B340B96459847FE
-:102FF000994618E6829F410459110E99021FE680F6
-:10300000020E4708D80298420E99029F40C1E00E76
-:10301000990299442FA00CB4380CF91114E66F1ED4
-:10302000E666A4FFAE992E928526F4CF0E880B2873
-:103030009685D10F2BA00C1FE6601CE6670CBE1115
-:10304000ACBBAFEE2DE28526B4CF0D3D0B2DE68552
-:10305000D10FC08005283878480263FEA263FE962F
-:103060006C1006C0C06570F18830C03008871477D6
-:103070008712C0B0C0A619E652299022C030CC9762
-:10308000C031600003C0B0C0A6C0E0C091C0D4C0D1
-:103090008225203C0B3F109712831CC070085801FA
-:1030A0000D5D01089738C0800B98380777100488A9
-:1030B00010086802087702C0800D98382D3CFE0881
-:1030C00088100D9E388D2B0AEE1008EE0207EE02D6
-:1030D0000CB8100FDD02053B400EDD029D4089203B
-:1030E000043D100899110D99022D210409A9020827
-:1030F000DD119941872A05B9100D3D020ABB110D5A
-:10310000BB02087702974428212587120828140457
-:103110008811071E4007EE100E99027566092621D8
-:103120001F062614600006002621200626140868C3
-:10313000029B47098802984629200CD2C0C0800C07
-:103140009E111BE6251FE61CAB99AFEE2DE28528EC
-:1031500094CF0DAD0B2DE685D10FDD40C0A6C0B0DC
-:103160008E51CAE0B2AAB1BB2DDC108F500E78365A
-:10317000981008770C9FD898D989538F5299119934
-:10318000DB9FDA7E8309B1CC255C10C97763FFCF62
-:1031900088108D1108E70C9751AD8DD7F078DB01C1
-:1031A000B1F79D5397528830C03008871408884083
-:1031B000648ED565BEC963FEBC0000006C1004D7E8
-:1031C00020B03A8820C0308221CAA0742B1E2972F8
-:1031D000046D080FC980C9918575B133A2527A3B3D
-:1031E0000B742B0863FFE900649FECD10FD240D130
-:1031F0000F0000006C100AD6302E3027D950DA406C
-:1032000015E5F02430269A1529160464E00264932B
-:10321000732920062A9CF865A3CE2A2102270A04D6
-:103220000A0B4C65B3978C3074C7052D212365D4E8
-:10323000A0C0A62B0A032C2200580F3664A3B9178E
-:10324000E5DE8E389A1664E3BA2F6027285021C92C
-:10325000F37E8311C2B08C202A200C580F55D7A0C2
-:10326000CDA16004A200C2B08C202A200C580F29E6
-:10327000D7A064A4862F212E8B680FBF360FB90C00
-:103280006F9D54296027D5B06E920528203D7B8F15
-:103290004CDA20DB50C1C42D211F580EEF8B269A2B
-:1032A000189A1989272AAC380B990C7A9353896399
-:1032B000C08099738F6298789F728E659E798D67B2
-:1032C0009D7B8C6695759C7A8E687E53026000B1FA
-:1032D0008B1465B050600038DBF063FFA5008A14E2
-:1032E000C9A92E60030E9B0C6EB2A5DC500CEA112E
-:1032F000AA6A2AAC285BFFB1D5A063FF93C0E06344
-:10330000FFE2DA208B18580EAC65A2B163FF9E0075
-:1033100000DA20DB308C15580E54D6A0C0C0C0D1C6
-:103320002D16042CA403DC70DA20DB60DF502D6046
-:1033300003C0E09E109D171EE5B90CDD110D6D0850
-:103340002DDC285BFF478E668F678817AF5FA8A8C4
-:1033500028640375FB01B1EE8A189E669F67892673
-:103360008829AA9909880C99268E6808084805EECC
-:103370000C28252515E5939E6865EECC63FEE600D6
-:103380000000C9432F21232B21212FFC010F0F4FB8
-:103390002F25237FBB026003142C20668961B1CCEA
-:1033A0000C0C472C24666EC60260022809FD50658D
-:1033B000D22264E1B62E602764E1B0DC70DF50DA1F
-:1033C00020DB601EE5AB2D6003C08098100CDD1182
-:1033D000AD6D2DDC285BFF22644181C0442B0A00C7
-:1033E0008C202A200C580ECB0AA70265A00FC0B073
-:1033F0002C22002A200C580EC7D7A064AFEFDA2089
-:10340000C1BCC1C82D21208F188E268929AFEE9E00
-:10341000260E990C090948292525580E8FC090C001
-:1034200050C0C288609A191EE566C0A12EE022082D
-:103430008F14778704C0810E8938C0800B93102DBC
-:10344000203C2921200CDC0104DB010929140BA8F4
-:10345000380CA5380D3D401CE57E8B2B08881007E5
-:1034600055100855020533022821250F154003BBCE
-:10347000020CBB0207551005D3100828140ADD11F1
-:103480000488110988020533022921040833029BAC
-:1034900070C0808A201BE57708AA110BAA029A71D6
-:1034A000C0A1852A9376957408931103DD020ADD85
-:1034B000029D778C63C1DC9C738B6298789A799BB0
-:1034C00072232214C0C0B1352526149C7B9D7593B0
-:1034D0007A2B621A9B7C2A621C9A7D28621D987E38
-:1034E00025621B957F2362172376102D62182D7697
-:1034F000112C62192C761264E0B98E6077E73DC01A
-:10350000FE13E53E1DE53FC1818A628B6304951180
-:103510000E9C4006CC110C5502247615085502C0AD
-:10352000802D76148D2B2B761B2A761A287619255A
-:10353000761803DD022D76166000030000C0FA2E17
-:10354000200C19E52518E51CA9E90CEE11A8EEC020
-:10355000802DE2852894CF0DFD0B2DE685DA208B9A
-:10356000198C158D14580D90D2A0D10FDC70DF503E
-:10357000DB602D6C28C0A01EE53E9A10DA205BFEB1
-:103580005563FE53002B203D0B4B4065BC826FE51D
-:1035900027DA308F556DE90C8EAA0E8E14C9E87E9D
-:1035A000F3162AAC10C090292467090F4764FC6009
-:1035B00060015F00C0FA63FF85C09163FFE8881473
-:1035C000658168DA20DB608C15580DA7C020C0909B
-:1035D00029A403D10F8A162B2104580CC9C0A02A94
-:1035E00024668E6863FDCA00002B9CF965B0FDDA85
-:1035F00020580CCE63FC220000DA20C0B6580E2CF6
-:1036000063FFBA002B200C0CBE11A7EE2DE286C181
-:10361000C27DC30260011819E4E909B90A2992A31D
-:103620006890082A220009AA0C65A10326E2856495
-:1036300060FD2C20668931B1CC0C0C472C24666FC0
-:10364000C60270960C8A162B2104580CADC0D02DE2
-:1036500024668E3077E74D1CE4E91BE4E98F32885D
-:1036600033C0A42D21040E994006991104DD1109DF
-:10367000DD029A61C19009DD029B60C0908B2B9D99
-:10368000649F66986799650CBB029B6228200C1AA0
-:10369000E4D2AA8A0C8811A7882F828529A4CF2F6B
-:1036A000FC202F86858A1465A0A6C020D10FB0FC0F
-:1036B0008B142C2523C8B7022A02066B02580CDE95
-:1036C0002A210265AEF7C0D80DAD022D250263FE9A
-:1036D000EC008E14C8E8DA20DB30580CD72A21021F
-:1036E00065AEDA07AF022F250263FED100DA20DBD8
-:1036F000308C158D14580E80D2A0D10FDA202B20DB
-:103700000C580DEB63FEB600DA202B200C580E0D82
-:1037100063FEAADA20DB308C152D12042E0A8028D5
-:103720000A00282468580CD663FAE500C020D10F9F
-:10373000DA20580DDF8914CD92DA20DB308C155851
-:103740000D4ADBA0C020C0A02AB403D10FC020D1F5
-:103750000F2A2C748B1558064CD2A0D10F000000F4
-:103760006C100E28210224160108084C6583A91F3D
-:10377000E49229F29E6F98026003AD1EE48E29E266
-:10378000266890082A220009AA0C65A39B24F29DB2
-:103790006443952A31160A4B412B240BB4BB0B0B07
-:1037A000472B240C0CB611AF66286286C1CC78C3B7
-:1037B0000260037F19E48209B90A2992A36890077D
-:1037C0008C2009CC0C65C36B276285647365293135
-:1037D00009C0D02D24668C3599139C2A88369C14F8
-:1037E000982B8E3798159E169E2C8C38C0E10C5C59
-:1037F000149C179C2D88392925042E251D28251C4D
-:103800002C3028C0822C243C2930290C0C4708C8B5
-:103810000129243D29311598189912090841089960
-:103820000C299CEC29251F7EC725921C8212282A70
-:1038300000082060991B01023E00093EB128098260
-:1038400039891B0E221102990C821C29251F821C0A
-:10385000941D951E24211F15E4880451609A10C1FF
-:10386000802B1610252014961F05054301063E00E7
-:103870000D3EB16B0DB6398B3C2D9CFC08663606AF
-:10388000441C893D2E26132E26142E26152E246B1D
-:1038900025241406D61CC05025261825261B2524B1
-:1038A000672524682832112525232525242525254B
-:1038B00025252C2925222D25202B252124252E26A2
-:1038C000252F14E46F16E46D1BE45298192D211C6A
-:1038D000C08498719B70892095759577957F967CAB
-:1038E000967E98799B7894731BE46714E4680C388F
-:1038F000400288100C064015E464016610947D9B1C
-:1039000074841D1BE444086602957B18E431851E0F
-:103910000B99029972997A0866022B121096768694
-:103920001F6FD2026001C8C0A0991A6D080AB1AA1F
-:1039300000A10400E81A7D8B0263FFEE891AC0E043
-:10394000961F1DE43E2B1610951E941D28203D2920
-:10395000761A297612C040C051C0B22D76130806DF
-:10396000408D170B8801065E380AEE101BE44A08EA
-:103970005438B0A609661188140B44102B761B042A
-:10398000EE028B1614E44308DA1406EE020D8810DA
-:103990002A761E86131AE41C04EE020D66110866D0
-:1039A000022E76160D14141EE41A0D44110BD814B1
-:1039B0000866020A44022E76182E76102476172600
-:1039C000761FC084287619287611C76F0C24400F03
-:1039D00044111CE3FB26761D26761C2676152676DA
-:1039E000148A262676242676252976222E762028E5
-:1039F00076218E1888150DB91016E4278BC70D880F
-:103A0000110E5E39ADBB851904EE022676230988B6
-:103A100002861F89102876260A04480544110505E8
-:103A2000480E551105440204EE02851E841D2E76B3
-:103A3000272820069B2D29246A2E31172B12102EA1
-:103A40002538CC83C0D02D2407C0D7090840648016
-:103A50008E9A290928416480AA64E0B42D2406C006
-:103A60009809E9362D0AA02A628501C404ADAA2D61
-:103A700021042A668508DD11883F8E3E2732100812
-:103A8000EA1800C40408E8180088110ECE5308771D
-:103A900002C08308DD029D4118E401090D4E9840E3
-:103AA00088209A4397449D4517E3FE1DE3CB058884
-:103AB0001108EE02ADBDC08007EE029E4228D4CFB1
-:103AC0002AF29D87CA2AAC18B1772AF69D1AE3B963
-:103AD00097CA28A4A268711C655060C020D10F004D
-:103AE0002D2406C080C09809E9360E893863FF731B
-:103AF000C0A063FE481BE3CB1AE3EB2AB68963FF41
-:103B0000D600000065EF54C098C0D82D240663FF8E
-:103B1000522D2406C09063FF4ACC57DA20DB308C4C
-:103B200011580C51C020D10F00DA20C0B6580CE05B
-:103B300063FFE500DA20580CDE63FFDC2A2C748B6F
-:103B400011580551D2A0D10F6C10062820068A33D7
-:103B50006F8202600161C05013E39729210216E3CE
-:103B600096699204252502D9502C20159A2814E331
-:103B7000948F2627200B0AFE0C0477092B712064F2
-:103B8000E1398E428D436FBC0260016F00E104B0E9
-:103B9000C800881A08A80808D80298272B200668A9
-:103BA000B32ECE972B221E2C221D0111027BC901A0
-:103BB000C0B064B0172CB00728B000DA2003880A20
-:103BC00028824CC0D10B8000DBA065AFE7C020D1BC
-:103BD0000F2D206464DFCA8B29C0F10BAB0C66BFCC
-:103BE000C02B200C0CBC11A6CC28C2862E0A08784B
-:103BF000EB611EE3720EBE0A2EE2A368E0052822E6
-:103C0000007E894F29C2851EE37E6490461FE38CA7
-:103C10009E90C084989128200A95930F88029892CC
-:103C20008E200FEE029E942F200788262F950A984B
-:103C3000969A972E200625240768E3432921022A15
-:103C4000C2851DE3652AAC20ADBD25D4CF2AC6852B
-:103C500063FF4E002E2065CBEDC082282465C9F697
-:103C600005E4310002002A62821BE36D2941020B48
-:103C7000AA022A668209E43129210263FF23000097
-:103C800064DFB88F422E201600F1040DEE0C00EE1A
-:103C90001AAEAE9E2963FFA38A202B3221B1AA9AC5
-:103CA000B0293221283223B4992936217989A92BC8
-:103CB00032222B362163FFA0C020D10F9F2725245D
-:103CC00015ACB82875202B2006C0C12EBCFE64E0C0
-:103CD000AB68B7772DBCFD65DEC72D2064C0F064EE
-:103CE000D0868E290EAE0C66E089C0F128205A28B5
-:103CF0008CFE08CF3865FEE863FF580000E00493AF
-:103D000010C0810AF30C038339C78F08D80308A8B1
-:103D10000108F80C080819A83303C80CA8B82875BE
-:103D200020030B472B24158310CBB700E104B0BC54
-:103D300000CC1AACAC0CDC029C27659E5EC0B20BBA
-:103D4000990209094F29250263FE50002D206A0DB2
-:103D50002D4165DF7EDA20C0B0580CA864AF18C0D2
-:103D6000F163FEEF9F2763FFD02E221F65EE3263C3
-:103D7000FF79000028221F658E2763FF6E25240629
-:103D800029210263FE1B00006C10066571332B4C69
-:103D900018C0C7293C18C0A1C08009A8380808422B
-:103DA0006481101CE3011AE3022AC67E2A5CFDD35B
-:103DB0000F6DAA0500B08800908C8940C0A00988CA
-:103DC000471FE32B080B47094C50090D5304DD1026
-:103DD000B4CC04CC100D5D029D310CBB029B30882D
-:103DE000438E2098350FEE029E328D26D850A6DDE8
-:103DF0009D268E40C0900E5E5064E0971CE3111E1D
-:103E0000E300038B0BC0F49FB19EB02D200A99B341
-:103E10000CDD029DB28F200CFF029FB48E262D2058
-:103E2000079EB68C282DB50A9CB72924072F20069B
-:103E30002B206469F339CBB61DE2E22320168DD224
-:103E40000B330C00D10400331AB48DA3C393292281
-:103E5000200C13E2E11FE2D80C2E11AFEEA32229B1
-:103E600024CF2FE285D2A00FDD0B2DE685D10F00E8
-:103E70002E200CB48C0CEB111FE2D81DE2CFAFEE5C
-:103E8000ADBB22B28529E4CF02C20B22B685D2A0F7
-:103E9000D10F00002E200C1CE2C81FE2CF0CEB114A
-:103EA000AFEEACBB22B28529E4CF02820B22B685ED
-:103EB000D2A0D10FC0D00BAD387DC80263FEEC6339
-:103EC000FEE08E40272C747BEE12DA70C0B32C3CDF
-:103ED00018DD50580A9B8940C08063FEE3066E02DD
-:103EE000022A02DB30DC40DD505800049A10DB501F
-:103EF000DA70580465881063FEF700006C100692B3
-:103F0000121EE2B98C40AE2D0C8C472E3C1804CA10
-:103F10000BD9A07DA30229ADF875C302600084C04F
-:103F2000B0C023C0A09D106D0844B89F0EB80A8D84
-:103F3000900EB70BB8770D6D36ADAA9D800D660C4F
-:103F4000D8F000808800708C879068B124B2227706
-:103F5000D3278891C0D0CB879890279C1000708879
-:103F600000F08C9D91CB6FC08108BB0375CB36638D
-:103F7000FFB4B1222EEC1863FFD485920D770C8626
-:103F8000939790A6D67D6B01B1559693959260005C
-:103F900016B3CC2D9C188810D9D078D3C729DDF85A
-:103FA00063FFC100C0238A421BE2C000CD322D4412
-:103FB000029B3092318942854379A1051EE2BC0EF5
-:103FC000550187121BE2AB897095350B9902993226
-:103FD00088420A880C98428676A6A696768F44AFC9
-:103FE000AF9F44D10F0000006C10089311D63088A9
-:103FF00030C0910863510808470598389812282165
-:1040000002293CFD08084C6581656591628A630A56
-:104010002B5065B18B0A6F142E0AFF7CA60A2C2048
-:104020005ACCC42D0A022D245A7FE0026002158961
-:104030002888261FE29F09880C65820F2E200B0F0F
-:10404000EE0B2DE0FE2EE0FF08DD110EDD021EE27C
-:1040500099AEDD1EE2991CE2990EDD010DCC37C14F
-:1040600080084837B88DB488981089601AE2557B6B
-:1040700096218B622AA0219C147BA3179D132A20D2
-:104080000C8B108C20580BCA8C148D13DBA0CEAC7B
-:104090006001C4002E200C1BE2480CEA110BAA0898
-:1040A0002BA2861FE2467BDB3B0FEF0A2FF2A368B1
-:1040B000F0052822007F892C2BA28564B0AA876294
-:1040C0008826DE700C7936097A0C6FAD1C8F279B21
-:1040D0001508FF0C77F3197E7B729D139C149B15BA
-:1040E000CF56600025C0B063FFD0D79063FFDD00DE
-:1040F000009D139C14DA20DB70580B2F8B158C1449
-:104100008D1365A06A8E6263FFCC00DA208B11DC10
-:1041100040580AD5D6A08B15C051DE70DA20DC607D
-:10412000DD405BFF768D138C14D9A02E200C1BE292
-:10413000221FE2290CEA11AFEFC0E0ABAA2BA28547
-:104140002EF4CF0B990B29A68563FF1D00DA20DC26
-:1041500060DD40DE708912282007DF50A9882824FE
-:10416000075BFF09D2A0D10F00DBE0DA20580B502B
-:104170006550EF2A20140A3A4065A0EBDB60DC4072
-:10418000DD30022A025809BCD6A064A0D584A183E0
-:10419000A00404470305479512036351C05163FE11
-:1041A0005C2C2006D30F28CCFD6480A568C704C012
-:1041B000932924062C2006C0B18D641FE2019D279F
-:1041C0009D289D298FF29D2600F10400BB1A00F066
-:1041D00004B0BE0EDD01C0F0ADBB8D652F24070D10
-:1041E0000E5E01EE11AEBB2E0AFEB0BB0B0B190E1C
-:1041F000BB36C0E20B0B470EBB372B241618E1F978
-:104200000A09450D0B422B240B29240AB4BE2E2487
-:104210000C7D88572920162FCCFDB09D0A5C520DCD
-:10422000CC362C246465FDEC0C0C4764CDE618E11B
-:10423000E48E2888820C9F0C00810400FF1AAFEEE8
-:104240009E2963FDCF1CE21163FE13001CE20B6389
-:10425000FE0C8D6563FFA500DA202B200C580B396E
-:10426000645F0FC020D10F00C020D10FC09329245C
-:1042700016C09363FFA000006C1004C06017E1CD6E
-:104280001DE1D0C3812931012A300829240A78A1EF
-:1042900008C3B27BA172D260D10FC0C16550512654
-:1042A00025022AD0202F200B290AFB2B20142E2098
-:1042B0001526241509BB010DFF0928F1202B241414
-:1042C000A8EE2EF52064A0A92B221E28221D011184
-:1042D000027B8901DB6064B0172CB00728B000DADC
-:1042E0002007880A28824CC0D10B8000DBA065AF74
-:1042F000E7DB30DC40DD50DA205800DE29210209FE
-:104300000B4CCAB2D2A0D10F00CC5A2C30087BC1C2
-:10431000372ED02064E02D022A02033B02DC40DD70
-:10432000505800D4D2A0D10F2B2014B0BB2B241492
-:104330000B0F4164F0797CB7CAC0C10C9C022C25DC
-:1043400002D2A0D10FC020D10F2E200669E2C126D3
-:1043500024062B221E2F221D29200B2820150D9903
-:10436000092A9120262415AA882895207BF14960E6
-:104370000048B0BB2B24140B0A4164A0627CB70236
-:104380002C25022B221E2C221DD30F7BC901C0B06D
-:10439000C9B62CB00728B000DA2007880A28824C5A
-:1043A000C0D10B8000DBA065AFE7C020D10F0000BB
-:1043B000262406D2A0D10F0000DB601DE18164BF7E
-:1043C0004F2CB00728B000DA2007880A28824CC09A
-:1043D000D10B8000DBA065AFE71DE17963FF310001
-:1043E00026240663FF9C00006C1004282006260A81
-:1043F000046F856364502A2920147D9724022A02C1
-:10440000DB30DC40DD50580019292102090A4CC874
-:10441000A2C020D10FC0B10B9B022B2502C020D11E
-:104420000F00022A02033B022C0A015800D1C9AA3C
-:10443000DA20DB30DC40580A0C29A011D3A07E978B
-:10444000082C0AFD0C9C012CA411C0512D2014062F
-:10445000DD022D241463FFA4DA20DB30DC40DD50C4
-:10446000C0E0580987D2A0D10F0000006C100616DA
-:10447000E1521CE152655157C0E117E14E2821027B
-:104480002D220008084C6580932B32000B695129BE
-:104490009CFD6590872A629E6EA84C2A722668A0B1
-:1044A000027AD9432A629DCBAD7CBE502B200C0CE6
-:1044B000BD11A6DD28D2862F4C0478FB160CBF0A4E
-:1044C0002FF2A368F0052822007F89072DD285D31B
-:1044D0000F65D0742A210419E17AD30F7A9B2EDA62
-:1044E00020580883600035002D21041BE1757DBB39
-:1044F00024DA20C0B658087ECA546001030B2B5042
-:104500002B240BB4BB0B0B472B240C63FFA0DA202E
-:10451000580A67600006DA20C0B6580A656550E0A0
-:10452000DC40DB302D3200022A020D6D515808D2DA
-:104530001CE123D3A064A0C8C05184A18EA00404B0
-:10454000470E0E4763FF3500002B2104C08B8931D5
-:10455000C070DF7009F950098F386EB8172C2066CB
-:10456000AECC0C0C472C24667CFB099D105808E44B
-:104570008D1027246694D11EE126B8DC9ED06550AC
-:1045800056C0D7B83AC0B1C0F00CBF380F0F42CBFD
-:10459000F119E10518E10728967EB04BD30F6DBAEB
-:1045A0000500A08800C08C2C200CC0201DE10B0C45
-:1045B000CF11A6FF2EF285ADCC27C4CF0E4E0B2E09
-:1045C000F685D10FC0800AB83878D0CD63FFC1001E
-:1045D0008E300E0E4763FEA12A2C742B0A01044D67
-:1045E000025808D72F200C12E0FC0CF911A699A252
-:1045F000FF27F4CF289285D2A008480B289685D1B2
-:104600000FC020D10F0000006C1004C060CB55DB40
-:1046100030DC40055D02022A025BFF942921020979
-:10462000084CC882D2A0D10F2B2014B0BB2B24146D
-:104630000B0C41CBC57DB7EBC0C10C9C022C2502F5
-:10464000D2A0D10F0000022A02033B02066C02C076
-:10465000D0C7F72E201428310126250228240A0F5E
-:10466000EE012E241458010E63FFA300262406D267
-:10467000A0D10F006C1006282102D62008084C6536
-:10468000809D2B200C12E0CC0CB811A2882A8286C7
-:10469000B5497A930260009719E0C909B90A2992CD
-:1046A000A36890082A620009AA0C65A08228828566
-:1046B0001CE0D46480799C80B887B14B9B819B10AF
-:1046C000655074C0A7D970280A01C0D0078D380D75
-:1046D0000D42CBDE1FE0B51EE0B62EF67ED830D3FD
-:1046E0000F6D4A0500808800908C2E3008C0A00015
-:1046F000EE322E740028600C19E0B80C8D11A2DD8A
-:10470000A988C0202CD2852284CFD2A00CBC0B2C2F
-:10471000D685D10FC0F0038F387FA0C063FFB400EF
-:10472000CC582A6C74DB30DC4058080BC020D10F09
-:10473000DA605809DF63FFE7DD402A6C74C0B0DC43
-:104740007058087F2E30088B1000EE322E7400282F
-:10475000600C19E0A10C8D11A2DDA988C0202CD21B
-:10476000852284CFD2A00CBC0B2CD685D10F0000A3
-:104770006C1004292014282006B19929241468817A
-:1047800024C0AF2C0A012B21022C24067BA004C0DC
-:10479000D02D2502022A02033B02044C02C0D0584D
-:1047A00000C0D2A0D10FC020D10F00006C1004298E
-:1047B0003101C2B429240A2A3011C28378A16C7B4A
-:1047C000A1696450472C2006C0686FC562CA572D86
-:1047D00020147CD722DA20DB30DC40DD505BFFA5E3
-:1047E000292102090E4CC8E2C020D10FC0F10F9F51
-:1047F000022F2502C020D10FDA20DB30C0C05BFFC2
-:10480000DC28201406880228241463FFC7292015F9
-:104810001BE06C2A200BC0C09C240BAA092BA120F2
-:104820002C2415AB9929A52063FF9900C020D10F36
-:10483000DA20DB30DC40DD50C0E0580891D2A0D156
-:104840000F0000006C1004CB5513E06725221F0DEC
-:10485000461106550CA32326221E25261F06440BAF
-:1048600024261E734B1DC852D240D10F280A80C087
-:104870004024261FA82828261E28261DD240D10FF6
-:10488000C020D10F244DF824261E63FFD80000005D
-:104890006C1004D620282006C0706E85026000D4FB
-:1048A0001DE04E19E04612E0442A8CFC64A1302B36
-:1048B0006102B44C0B0B4C65B0A22B600C8A600CEF
-:1048C000B8110288082E828609B90A7EC3026000E8
-:1048D0009A2992A368900509AA0C65A08E28828562
-:1048E000648088B8891BE04A94819B80655155C0DB
-:1048F000B7B8382A0A01C0C009AC380C0C4264C0F1
-:10490000421FE0291EE02B2EF67EB04AD30F6DAA7F
-:104910000500808800908CC0A029600C0C9C11A21E
-:10492000CC2BC285AD990B4B0B2BC6852860062777
-:1049300094CF6881222D6015D2A0C9D2C0E22E6426
-:1049400006D10F00C0F008AF387FB0BD63FFB100E3
-:10495000276406D2A0D10F00D2A0D10F00CC57DA25
-:1049600060DB30DC405808C0C020D10FDA60580945
-:104970005063FFE80028221E29221DD30F789901D9
-:10498000C080C1D6C1C11BE018C122AB6B6480429C
-:1049900078913F2A80000CAE0C64E0BB02AF0C643F
-:1049A000F0B52EACEC64E0AF0DAF0C64F0A92EAC0A
-:1049B000E864E0A32FACE764F09D2EACE664E097DA
-:1049C0002F800708F80BDA807B83022A8DF8D8A0A5
-:1049D00065AFBC28612308D739D97060007B00001F
-:1049E0002B600C0CB811A2882C82862A0A087CAB9A
-:1049F0007E09BA0A2AA2A368A0052C62007AC96FB0
-:104A00002A828564A0691FDFFE276504C0E3C0C455
-:104A10002E64069CA11CE02B9FA02E600A97A30C7D
-:104A2000EE029EA28F600CFF029FA42E60147AEF0C
-:104A30004627A417ADBC2F828527C4CF2FFC202F7B
-:104A4000868563FE692A6C74C0B1DC90DD4058072E
-:104A5000BC1DDFE163FEC100D9A0DA60DB30C2D04B
-:104A6000C1E0DC4009DE39DD50580805D2A0D10F85
-:104A7000DA6058090F63FEE4290A0129A4170DBF63
-:104A8000082E828527F4CF2EEC202E868564500BCD
-:104A90002A6C74DB4058017CD2A0D10FC020D10F0A
-:104AA0006C10062B221E28221D93107B8901C0B09A
-:104AB000C0C9C03BC1F20406401DDFCBC0E2C074D8
-:104AC0000747010E4E01AD2D9E11C0402E0A146401
-:104AD000B06E6D084428221D7B81652AB0007EA13E
-:104AE0003B7FA1477B51207CA14968A91768AA1484
-:104AF00073A111C09F79A10CC18B78A107C1AE2908
-:104B00000A1E29B4007CA12B2AB0070BAB0BDAB02C
-:104B10007DB3022ABDF8DBA0CAA563FFB428B0109C
-:104B200089116987BB649FB863FFDC00647FB4634D
-:104B3000FFD50000646FD0C041C1AE2AB40063FF4E
-:104B4000C62B2102CEBE2A221D2B221E7AB12A8C10
-:104B5000107CB1217AB901C0B0C9B913DF96DA204F
-:104B600028B0002CB00703880A28824CC0D10B80E3
-:104B700000DBA065AFE7D240D10F8910659FD463F9
-:104B8000FFF300006C1008C0D0C8598C30292102F6
-:104B90000C0C4760000C8E300E1E5065E19E2921E2
-:104BA00002C0C116DF85090B4C65B0908A300A6ED1
-:104BB0005168E3026000852F629E1BDF7E6EF85312
-:104BC0002BB22668B0052E22007BE94727629DB7ED
-:104BD00048CB7F97102B200CB04E0CBF11A6FF299D
-:104BE000F2869E12798B4117DF7507B70A2772A3E9
-:104BF000687004882077893029F285DF90D7906526
-:104C000090652A210419DFAE7A9B22DA205806B873
-:104C1000600029002C21041BDFAA7CBB18DA20C00D
-:104C2000B65806B3C95860014CC09063FFCCDA2077
-:104C300058089F600006DA20C0B658089D655135B7
-:104C4000DC40DB308D30DA200D6D5158070BC0D0C1
-:104C5000D3A064A120292102C05184A18CA0040406
-:104C6000470C0C4763FF3E00C09B8831DBD008F83F
-:104C700050089B3828210498116E8823282066ACA0
-:104C80008C0C0C472C24667CBB159F139E148A1039
-:104C90008B1158071B8E148F13C0D02D24668A30B9
-:104CA000C092C1C81BDF5B7FA6099BF099F12CF471
-:104CB0000827FC106550A4B83ADF70C051C08007C7
-:104CC000583808084264806718DF3819DF392986A8
-:104CD0007E6A420AD30F6DE90500A08800F08CC0FF
-:104CE000A08930B4E37F9628C0F207E90B2C940822
-:104CF0009B909F912F200C12DF380CF811A6882969
-:104D00008285A2FF2DF4CFD2A009330B238685D153
-:104D10000F22200C891218DF300C2B11A6BBA82201
-:104D20002D24CF2CB285D2A00C990B29B685D10F9A
-:104D3000C087C0900A593879809663FF8ADB30DAE1
-:104D400020C0C1C0D05BFF56292102C0D02A9CFEE2
-:104D500065AE4D2D2502C09063FE45009E142A2CA1
-:104D600074C0B1DC70DD405806F68E14C0D01BDF75
-:104D700028C1C863FF6AC020D10F00006C1006284C
-:104D8000210217DF0D08084C65824929729E6F9831
-:104D90000260025019DF082A922668A0078B200AB9
-:104DA000BB0C65B23F2A729DC0CB64A2371DDF04E5
-:104DB000C0602B3008C0F164B0712E0AFFB0B86437
-:104DC00081512DBCFE64D0F364505C2A2C74044BDA
-:104DD000025800AD0AA2020600000000001ADF0817
-:104DE0002C20076EBB0260022218DEFE13DF081BB8
-:104DF000DF36C0E229200A9AD09ED1ABCB039902BC
-:104E000099D223B08026B480B13308330293D318EB
-:104E1000DEF20CFD11A7DD2CD285A8F82684CF0C7C
-:104E2000EC0B2CD685655FA2C020D10F2B21048806
-:104E300031DE6008F85008CE386EB8102C2066B10C
-:104E4000CC0C0C472C24667CEB026001AF2E30109A
-:104E50002930112C301300993200CB3264E1452AFD
-:104E600030141EDF1A00AA3278CF050E9C092BC41D
-:104E70007F1CDF1766A0050E98092A8480B4A71846
-:104E8000DF15C76F009104AC9CDBC000AE1A00F3C5
-:104E90001A6EC1048BD00BCB0C1CDF0F08B81C069C
-:104EA0003303AC882A848B2CD03627848C03CC0126
-:104EB0000ECC022CD4365801AD63FF0B2F200C0C06
-:104EC000FB11A7BB2DB286C0987D9302600121190A
-:104ED000DEBB09F90A2992A36890082D220009DD9A
-:104EE0000C65D10C2DB285DE6064D10488312B2194
-:104EF0000408F85008CE386FB80263FEDF2C206635
-:104F0000B1CC0C0C472C24667CE30263FECE9D10D2
-:104F100060013100293108292504283014B0886443
-:104F200080A62B31092B240AC0812B30162FD423C5
-:104F30002B240BB4BC2C240C8D378B36292504DE96
-:104F4000D00D8E39DCB00B8C390ECC0264CE7808D3
-:104F50009C1101C4048F380DBE1800C4040DB8188C
-:104F600000881108FF02C08308CC0218DECC9CA187
-:104F700098A018DECB8C209EA39FA405CC110BCF4C
-:104F800053C1E09EA50CFF0208FF029FA218DE8914
-:104F90002624662C729D2684A22CCC182C769D6328
-:104FA000FE250000002D30121CDECD00DA3278DF45
-:104FB000050C9E0B2AE47F66B0050C9F0B2BF4803A
-:104FC0002A301100AA3263FEEC2E240A2B31099BF1
-:104FD0002B63FF5300CC57DA20DB30DC405807222C
-:104FE000C020D10F00DA20C0B65807B163FFE5003A
-:104FF00000DBF0DA205807AE63FFD9000058064006
-:105000001DDE70C0F126246663FE41008B20280A55
-:10501000FFB1CE23200A2C21040E0E472E24077840
-:1050200031359AD02CD50A96D319DEA62ED416C0C7
-:105030008398D1C0E309B80298D409390299D226DD
-:10504000240763FDC958062E8D102624662B2104E3
-:105050002F200C63FD86000008B81119DE6808EEE9
-:1050600002882B9ED59AD0C0EF09880298D204C935
-:10507000110E990299D4C0E49ED163FFC1000000D3
-:105080006C1004C020D10F006C100485210D381164
-:1050900014DE478622A42408660C962205330B935F
-:1050A00021743B13C862D230D10FC030BC29992182
-:1050B00099209322D230D10F233DF8932163FFE34F
-:1050C0006C100AD620941817DE3CD930B8389819DD
-:1050D0009914655256C0E1D2E02E61021DDE390EF0
-:1050E0000E4C65E1628F308E190F6F512FFCFD65FC
-:1050F000F1558EE129D0230E8F5077E66B8F181E65
-:10510000DE78B0FF0FF4110F1F146590CE18DE7516
-:105110008C60A8CCC0B119DE2728600B09CC0B0D20
-:10512000880929812028811E2A0A0009880C08BACA
-:10513000381BDE6B0CA90A2992947B9B0260008CC1
-:105140002B600C94160CBD11A7DD29D286B84879C6
-:1051500083026000D219DE1909B80A2882A39817C1
-:105160006880026000A36000A51ADE5F84180AEE62
-:1051700001CA981BDE108C192BB0008CC06EB313C3
-:105180001DDE0D0C1C520DCC0B2DC295C0A17EDB7B
-:10519000AE6000380C0C5360000900000018DE51AE
-:1051A0008C60A8CCC0B119DE0328600B09CC0B0DB4
-:1051B000880929812028811E2A0A0009880C08BA3A
-:1051C000380CA90A2992947E930263FF72DA60C0B8
-:1051D000BA58073764507360026A00001ADDF68C13
-:1051E000192AA0008CC06EA31A18DDF20C1C5208FC
-:1051F000CC0B18DE3B2BC295C0A178B30263FF3FF6
-:1052000063FFC9000C0C5363FF0989607899182962
-:10521000D285C9922B729E1DDDE76EB8232DD22652
-:10522000991369D00B60000DDA60580721600017F0
-:105230000088607D890A9A1A29729D9C129915CF5F
-:1052400095DA60C0B658071A6551F98D148C18DBD1
-:10525000D08DD0066A020D6D51580587D3A09A14DF
-:1052600064A1E182A085A1B8AF9F1905054702029C
-:10527000479518C05163FE602B6104C08B8931C013
-:10528000A009F950098A386EB81F2C6066A2CC0CB0
-:105290000C472C64667CAB119F119E1B8A15580528
-:1052A000988E1B8F11C0A02A64669F1164F0E58957
-:1052B0001388190FFD022E0A006DD9172F810300E4
-:1052C000908DAEFE0080889F9200908C008088B800
-:1052D0009900908C65514E8A10851A8B301FDDC85D
-:1052E000881229600708580A2C82942D61040ECC7C
-:1052F0000C2C86946FDB3C1CDDF4AC9C29C0800B2D
-:105300005D50A29909094729C48065D0DA2E600C46
-:10531000C0D01FDDB10CE811AFEEA7882282852D29
-:10532000E4CF02420B228685D2A0D10F8E300E0E22
-:105330004763FDA2A29C0C0C472C64077AB6CD8B68
-:10534000602E600A280AFF08E80C64810E18DDDD73
-:1053500083168213B33902330B2C34162D350AC051
-:105360002392319F30C020923308B20208E80292A3
-:10537000349832C0802864072B600CD2A01CDD96C4
-:105380000CBE11A7EE2DE285ACBB28B4CF0D9D0B52
-:105390002DE685D10F8B1888138D30B88C0D8F4773
-:1053A0000D4950B4990499100D0D5F04DD1009FFEB
-:1053B000029F800DBB029B8165508D851AB83AC053
-:1053C000F1C0800CF83808084264806B1BDD771947
-:1053D000DD7829B67E8D18B0DD6DDA0500A0880075
-:1053E000C08CC0A063FEF30082138B161DDD8828DD
-:1053F000600AC0E02EC4800D880202B20B99239F80
-:1054000020C0D298229D2122600CB2BB0C2D11A786
-:10541000DD28D28508BB0B18DD702BD685A8222E7F
-:1054200024CFD2A0D10F9E1B851A2A6C748B185BD7
-:10543000FF168E1B63FEA300C087C0900AF938795F
-:10544000809263FF86C020D10F9E1B2A6C74C0B16E
-:105450008D1858053B8E1B851A63FE7E886B821360
-:10546000891608BE110ECE0202920B9E25B4991E1B
-:10547000DD639F200E88029822C0EF04D8110E88A9
-:10548000029824C0E49E21C080D2A02B600C286426
-:10549000071CDD510CBE11A7EE2DE285ACBB28B474
-:1054A000CF0D9D0B2DE685D10F0000006C1004C0C0
-:1054B00020D10F006C10048633C071C03060000131
-:1054C000B13300310400741A0462017460F1D10F29
-:1054D0006C1004022A02033B025BFFF61CDD391B41
-:1054E000DD83C79F88B009A903098A019AB0798032
-:1054F0001EC0F00FE4311DDD300002002BD2821EF1
-:10550000DD7C2AC1020EBB022BD6820AE431D10F08
-:1055100028C102C19009880208084F28C50208E482
-:1055200031D10F006C1004C0C00CE43112DD251A1B
-:10553000DD2200020029A28218DD701BDD6E26210B
-:10554000020B990108660129A68226250206E4318C
-:1055500014DD6B15DD66236A9023261685502426FC
-:1055600015252617222C50D10F0000006C1008D6EC
-:10557000102B0A64291AB41ADD0F0D23111CDD103B
-:105580000F2511B81898130E551118DD5DAC55A8EC
-:1055900038AA332C80FF2A80FEA933288D01298068
-:1055A0000108AA112880000CAA02088811098802A3
-:1055B00008AA1C288C0828160458086814DD010A5B
-:1055C000A70224411A2A30802B120407AA2858085F
-:1055D00063B1338B13B4559A6004AC28B4662C566F
-:1055E0002B7B69E016DD3A9412C050C0D017DCF472
-:1055F0009D15D370D4102F60802E60829F169E1749
-:10560000881672891A8D128C402A607F0DCC282B47
-:105610003A200CAA28580851C0B10ABE372E354886
-:105620008F1772F91A8D128C402A60810DCC282BAD
-:105630003A200CAA28580849C0B10ABE372E354A6C
-:10564000B233B444B1556952B6B466C0508F15B880
-:1056500077D370B2FF9F156EF899D10F6C1004C00C
-:1056600021D10F006C1004270A001CDCD31FDCE4DE
-:105670001EDCE71DDCD01ADD141BDD22C02824B09F
-:10568000006D2A75AA48288080C09164806100411D
-:105690000415DCCBC03125503600361A06550105FD
-:1056A00095390C56110C66082962966E974D0D5966
-:1056B0000A29922468900812DD0602420872993B7A
-:1056C00023629512DCC8CB349F300282020E440262
-:1056D000C092993194329233AD52246295C0902495
-:1056E0004C1024669524B0002924A0AA42292480C5
-:1056F000B177B14404044224B400D10FD10FD10FCB
-:105700006C10041ADCAC2AA00058021C5BFFD50206
-:105710002A02033B025BFFD11BDCAAC9A12CB10208
-:10572000C0D40DCC020C0C4F2CB5020CE431D10FBF
-:10573000C0A00AE43118DCA00002002F828219DC2C
-:10574000B32EB10209FF022F86820EE431D10F0081
-:105750006C1004C02002E43114DC9A16DC970002BD
-:1057600000226282234102732F0603E431C020D15C
-:105770000F19DCE61ADCE52841020A2A0109880132
-:105780002A668228450208E43115DCDC12DCE125BA
-:105790004621D10F6C1004292006289CF96480A0B2
-:1057A0002A9CFD65A0968A288D262F0A087AD9049E
-:1057B0002B221FC8BD2C206464C0812E22090EAE8E
-:1057C0000C66E0782B200C1EDC7C0CBC11AECC28C7
-:1057D000C28619DC7A78F3026000AD09B90A299211
-:1057E000A36890082E220009EE0C65E09B29C28573
-:1057F0001FDC846490929F90C0E41FDC919E9128EE
-:10580000200AC0E09E930F8802989288200F880299
-:1058100098942F20079A979D962F950A2E24072853
-:10582000200629206468833328C28512DC6B288C0B
-:1058300020A2B22E24CF28C685C020D10FC020D1EF
-:105840000F2A206A0111020A2A4165AF52DA20C0EC
-:10585000B05805EA64AFE5C021D10F00649FC81FAE
-:10586000DC582D20168FF209DD0C00F10400DD1A42
-:10587000ADAD9D2912DC5928C285A2B22E24CF28B5
-:105880008C2028C685C020D10FC021D10F00000078
-:105890006C1004260A001BDC9F15DC4928206517C4
-:1058A000DC46288CFE6480940C4D110DBD082CD272
-:1058B000F52BD2F42ED2F77CB13DB4BB2BD6F47BC2
-:1058C000E9052BD2F62BD6F47CB92C2AD2F62AD6AF
-:1058D000F52AD6F406E4310002002872822AFAFF83
-:1058E000004104290A012F510200991A0A9903095B
-:1058F00088012876820FE4312624652BD2F48E5C51
-:105900002CD2F5B0EE9E5C7BCB1629D2F62FD2F7C7
-:105910000CB80C09FF0C08FF0C0F2F14C8F960001D
-:10592000320BCA0C0A2A14CEA92B5102C0C20CBBDE
-:10593000020B0B4F2B55020BE431D10F00DB30DA99
-:10594000205BFF941BDC7464AF5D0C4D11ADBD6337
-:10595000FFA8000006E4310002002F728218DC303C
-:105960002E510208FF022F76820EE431D10F000083
-:105970006C1004C03003E43116DC1015DC11000299
-:105980000024628274472118DC64875C084801287F
-:105990006682CD7319DC620C2A11AA99229283299E
-:1059A00092847291038220CC292B51020BE431C0E6
-:1059B00020D10F001FDC5B2E51020FEE012E55028D
-:1059C0000EE431B02DB17C9C5C12DC5608DD112D4B
-:1059D000561DD10F6C10061BDBF71EDBF922B00041
-:1059E0001ADC526F23721DDC39C04818DC511FDCF1
-:1059F0004FDC10D5C083F000808600508A6D4A4F7E
-:105A00000F35110D34092440800B560A296294B1D8
-:105A1000330E55092251480F44110C440A8740099E
-:105A2000A80C02883622514907883608770CA899B5
-:105A30002966949740296295874109A80C02883607
-:105A400007883608770CA899296695974103034281
-:105A5000B13808084298F0D10F1CDC3613DC372728
-:105A6000B0002332B5647057C091C0D016DC351534
-:105A7000DC33C0402AC00003884328C4006D793C51
-:105A8000004104B14400971A7780148E502FB295CC
-:105A90002DB695AFEE2EED2006EE369E5060001826
-:105AA00077A00983509D5023B69560000223B295DC
-:105AB000223D2006223622B695B455B8BBD10F0040
-:105AC00003884328C400D10F6C1004C04004E431A3
-:105AD00015DC1D000200885013DC1CCB815BFFBD70
-:105AE0001CDC1B0C2D11ADCC2BC2822AC28394501E
-:105AF0007BAB142EC28429C2850ABD0C0E990C0DF5
-:105B0000990C0929146000050BA90C092914993076
-:105B100015DBAC2A51020AE4312A2CFC58004B2B2D
-:105B200032000AA2022BBCFF9B30CCB6C8A4D2A084
-:105B3000D10F000004E4311EDBA00002002DE28240
-:105B40002FBAFF2C51020FDD012DE6820CE431D17A
-:105B50000F0000006C1004D10F0000006C1004C096
-:105B600020D10F006C100413DBFAC0D103230923EA
-:105B7000318FC0A06F340260008D19DB8F1BDB906A
-:105B800017DBF30C2811A8772672832572822CFA72
-:105B9000FF76514788502E7285255C0425768275E4
-:105BA000E9052572842576827659292E72842E760F
-:105BB000822E76830AE431000200239282002104BF
-:105BC0002FB10200D61A0C66030633012396820F0A
-:105BD000E43126728325728260000200D8A07659D3
-:105BE000220AE43100020023928200210400D21A2A
-:105BF0002FB1020C22030232012296820FE431D22D
-:105C000080D10F00D280D10FC020D10F6C1004DBE7
-:105C100030862015DB68280A00282502DA2028B003
-:105C2000002CB00705880A28824C2D0A010B800041
-:105C3000DBA065AFE61ADB610A4A0A29A2A3C7BF47
-:105C4000769101D10F2BA6A3D10F00006C1004C0D8
-:105C5000D1C7CF1BDB5B19DB5817DB560C2811A80B
-:105C60007786758574C0A076516288508E77B4555A
-:105C7000957475E903857695747659278F769F75A7
-:105C80009F740AE431000200239282B42E2FB102E5
-:105C900000E10400D61A0C66030633012396820F36
-:105CA000E431867583747639280AE4310002002EC7
-:105CB0009282B42200210424B10200DF1A0CFF03F7
-:105CC0000FEE012E968204E431D280D10FD8A07657
-:105CD00051D6D280D10F00006C1004290A801EDB3F
-:105CE0005D1FDB5D1CDB350C2B11ACBB2C2CFC2DA4
-:105CF000B2850FCC029ED19CD0C051C07013DB592D
-:105D000014DB5818DB562AB285A82804240A234637
-:105D100091A986B8AA2AB685A98827849F25649F59
-:105D2000D10F00006C100419DB8B0C2A11A9A98972
-:105D300090C484798B761BDB79ABAC2AC2832CC2EE
-:105D4000847AC1688AA02BBC30D3A064A05E0B2BE0
-:105D50000A2CB2A319DB4268C0071DDB7FD30F7D7D
-:105D6000C94AA929299D0129901F68913270A6036B
-:105D7000D3A0CA9E689210C7AF2AB6A32A2CFC5B98
-:105D8000FFB3D230D10F000013DB7503A3018C31B8
-:105D90001DDB130C8C140DCC012CB6A363FFDC00AF
-:105DA000C020D10FDA205BFFCCC020D10FC020D1A2
-:105DB0000F0000006C1004DB30C0D019DAFEDA20CE
-:105DC00028300022300708481209880A28824CDC53
-:105DD000200B80001BDAF90C4A11ABAA29A2840916
-:105DE000290B29A684D10F006C1004C04118DAF2E7
-:105DF00017DAF40C2611A727277038A866256286C3
-:105E0000007104A35500441A75414822628415DBD1
-:105E10001502320BC922882117DAF10884140744CD
-:105E200001754905C834C020D10FD10F0809471D9D
-:105E3000DB4AC0B28E201FDADF0E0E43AFEC2BC45C
-:105E4000A00FEE0A2DE6242A6284C0200A990B29AD
-:105E50006684D10FC020D10F6C1004DB30C0D01885
-:105E6000DAD5DA2025300022300708580A28824C7B
-:105E7000DC200B80008931709E121BDACF0C4A1196
-:105E8000ABAA29A28409290B29A684D10F09C952DA
-:105E900068532600910418DACAC0A12F811600AAFF
-:105EA0001A0AFF022F85161EDAC40C4D11AEDD2C26
-:105EB000D2840C2C0B2CD684D10FC0811FDAC1B830
-:105EC0009A0A0A472EF11600A10400881A08EE0269
-:105ED0002EF5161DDAB90C4C11ADCC2BC2840B2B50
-:105EE0000B2BC684D10F00006C1004DB30C0D0191E
-:105EF000DAB1DA2028300022300709880A28824CDB
-:105F0000DC200B80001CDAAC0C4B11ACBB2AB28439
-:105F10000A2A0B2AB684D10F6C1004C04118DAA6E5
-:105F200016DAA80C2711A626266038A87225228624
-:105F3000006104A35500441A7541082222840232EC
-:105F40000BD10F00C020D10F6C100415DB050249E6
-:105F5000142956112452120208430F8811C07300ED
-:105F6000810400361A008104C78F00771A0877036E
-:105F7000074401064402245612D10F006C10066E2D
-:105F800023026000AC6420A7C0A0851013DADD16E0
-:105F9000DAF4C040A6AA2BA2AE0B19416490666841
-:105FA000915D68925268933C2AA2AA283C7F288C73
-:105FB0007F0A0A4D2980012880002AACF208881146
-:105FC0000988027589462B3D0129B0002BB00108D4
-:105FD00099110B99027A9934B8332A2A00B1447284
-:105FE00049B160004A7FBF0715DADF63FFB90000DF
-:105FF000253AE863FFB10000253AE863FFA90000F5
-:10600000250A6463FFA1C05A63FF9C0000705F080B
-:106010002534FF058C142C34FE70AF0B0A8D142E22
-:106020003D012AE4012DE400DA405BFD5063FFA747
-:10603000D10FD10F6C10041ADA6219DA5F1CDACAB8
-:106040001BDACBC080C07160000D00000022A438B4
-:10605000B1AA299C107B915F26928679C2156E6247
-:1060600062C0206D080AB12200210400741A764B28
-:10607000DB63FFEE2292850D6311032514645FCF6D
-:10608000D650032D436DD9039820B4220644146DD5
-:106090004922982098219822982398249825982678
-:1060A000982798289829982A982B982C982D982EDC
-:1060B000982F222C4063FF971EDA4027E68027E6C0
-:1060C00081D10F00C02063FF830000006C1004C06A
-:1060D00062C04112DA3B1ADA3713DA522AA00023DF
-:1060E000322D19DA9F2BACFE2992AE6EA30260000E
-:1060F0008E090E402D1AC2C2CD0EDC392C251A6431
-:10610000B0895BFF9E15DA9A1ADA952B3AE80A3ABB
-:10611000015805922B211A0ABB28D3A09B50580581
-:10612000A92B52000ABB082A0A005805A815DA91C3
-:106130002D21022C3AE80C3C2804DD022D25029C7E
-:10614000505805A08B50AABBC0A15805A01CDA8AE4
-:106150002D21020C3C2806DD0213DA882D25029C35
-:10616000305805988B30AABBC0A25805982A210246
-:10617000C0B40BAA020A0A4F2A25025805ACD10F57
-:10618000242423C3CC2C251A63FF760018DA801C44
-:10619000DA7C19DA7D1BDA7B17DA4F85202E0AFDAF
-:1061A0001FDA7C2D203624F47A24F47E24F4820E27
-:1061B000DD0124F4862E0AF707552806DD02C07596
-:1061C0000EDD01050506AB5BA959C0E8AC5C24C433
-:1061D000AB0EDD0227C4AC2E0ADFA85527B4EC0EA7
-:1061E000DD0124B4EBC2E027942C0EDD0224942BB5
-:1061F0002E0A800D0D4627546C24546B0EDD022DA3
-:10620000243663FEFC0000006C10042A0A302B0ABE
-:10621000035BFF4D12DA53C390292616C3A1C0B306
-:10622000C08A2826175BFF48C03CC3B12B26161A2C
-:10623000D9E42AA02023261764A079C3A2C0B15BA9
-:10624000FF42C3A2C0B15BFF40C3C22C2616C2AF3F
-:10625000C0B12326175BFF3CC28F282616C0FE2F35
-:106260002617C2E22E26162A0AA1C0B1C0D82D26B2
-:10627000175BFF352A0AA12A2616C3A6C0B3C1920E
-:106280002926175BFF31C3C62C2616C1B32A0AA2E2
-:106290002B2617C0B35BFF2C290AA2292616C1851D
-:1062A000282617C2FB2F2616C0E72E26171DDA391F
-:1062B0002D2610D10FC3A2C0B35BFF2363FF820062
-:1062C0006C10041CDA031BD9ED18DA3317DA341614
-:1062D000DA3415DA34C0E0C0D414D9FF1FD9B9C0FC
-:1062E000288FF06D2A36DAC0D9C07C5B020FC90C4A
-:1062F0001CD9F90C9C28A8C3A6C22A36802A25845A
-:10630000A4C2A7CC2D248C2B248A2B24872E248B4B
-:10631000B1BB2E369F2C369E2C369DB1AC1CD9D7E6
-:106320001BDA22C0286D2A33DAC0D9C07C5B020F89
-:10633000C90C1CD9E80C9C28A8C3A6C22A36802BFD
-:106340002584A4C2B1BBA7CC2D248C2E248B2A2457
-:106350008A2E369F2C369E2C369DB1ACC07919D929
-:10636000D81BDA1413DA121ADA1218DA1314D9D97C
-:1063700016DA1304F42812DA1204660C040506A2D5
-:1063800052A858AA5AA3539B3029A50027848AC033
-:1063900091C0A52A848C29848B17DA0B18DA0AA7F6
-:1063A0005726361D26361E2E361F16DA0813DA0833
-:1063B000A65504330C2826C82E75002D54AC2E5437
-:1063C000AB2E54AA2326E62326E52E26E7D10F007E
-:1063D0006C100613D99417D9E224723D2232937FB0
-:1063E0002F0B6D08052832937F8F0263FFF3C0C423
-:1063F000C0B01AD973C051D94004593929A4206EAC
-:1064000044020BB502C3281ED96EDDB025E4220577
-:106410002D392DE421C0501ED9EF19D9DF18D9DF4D
-:1064200016D9E11DD9ED94102A724517D9AB6DA983
-:106430004BD450B3557A5B17DF50756B071FD9608B
-:106440008FF00F5F0C12D9A302F228AE2222D68160
-:10645000D54013D9A0746B0715D95A855005450C42
-:10646000035328B145A73FA832A93322369D2236CF
-:106470009E2436802B369F2BF48B2CF48C14D969F8
-:1064800024424DC030041414C84C6D0806B13304C6
-:106490001414C84263FFF20015D947C44000310408
-:1064A0001AD948C0D193A200DD1AC138B0DD9DA32E
-:1064B00018D95D2B824D29824E29A5202882537A36
-:1064C000871E2C54008E106FE45D12D93D2F2121C0
-:1064D0002321202F251F04330C23252023251ED103
-:1064E0000FC06218D99F88807E87D98910265400F2
-:1064F0006F94191BD9332AB1200A1A1404AA0C2A42
-:10650000B5202AB5212AB51E2AB51FD10F1BD92CBB
-:106510002AB1200A1A1403AA0C2AB5202AB5212A66
-:10652000B51E2AB51FD10F001CD9262BC1212DC1A4
-:10653000202BC51F03DD0C2DC5202DC51ED10F003E
-:106540006C100619D91F14D98612D93615D9A3C7CC
-:106550003FC0E02E56A82E56A92E56AA2E56AB2383
-:10656000262918D946DB101CD99DC0D42A42452DB6
-:1065700016012C160000B0890A880C98905BFF94D5
-:106580002C22E318D90F0C5C149C842B22E48C84FD
-:10659000B1BB0B5B140CBB0C9B852A22E50A5A1479
-:1065A0002A86062922CD0959142986072F22892FE8
-:1065B00086095BFF435BFF1423463BC1B01ED90035
-:1065C0001DD9602AE1022D463A0BAA020A0A4F2A77
-:1065D000E5025804965BFEBD5BFE96C050C0B01647
-:1065E000D8F614D8FE17D96FC0C0C73E93122C2618
-:1065F0002DC0306000440000007F9F0FB155091985
-:1066000014659FF4C0500AA9027FA7EF18D8EADAF0
-:106610005008580A28822C2B0A000B8000005104D5
-:10662000D2A0C091C7AF00991A0A99039912CE3827
-:1066300064206BD3202B20072516032C12022A621C
-:10664000827CA86318D8DC01110208580A28822C21
-:10665000DA500B8000D2A0643FD58A310A8A140434
-:10666000AA01C82A2B22010B8B1404BB017BA9456C
-:10667000DDA07A7B081DD8D22DD2000DAD0CDB3009
-:1066800019D8CD1AD91488130ADA28DC801DD951FB
-:1066900009880A28823C0DAA080B8000652F93D335
-:1066A00020C0B063FF9400007FAF34B155005004A8
-:1066B0000A091963FF42DAB07B7B081AD8C12AA203
-:1066C000000ABA0C1BD9048C310BAB280C8A141CA1
-:1066D000D941ACBB1CD94104AA012BC68163FF8FF1
-:1066E000645F60C050C0B0C7CE9C1263FF5500000D
-:1066F0006C100427221EC08008E4311BD8AF0002B2
-:10670000002AB28219D8AF003104C06100661A298C
-:1067100091020A6A022AB68209E43115D90C0C38B2
-:1067200011A8532832822432842A8CFC7841102903
-:1067300021022A368297A0096902292502D10F0079
-:106740002B21022C32850B6B022CCCFC2C36829731
-:10675000C02B2502D10F00006C1004C0E71DD89299
-:106760001CD8940D4911D7208B228A200B4B0BD2B9
-:10677000A007A80C9B72288CF4C8346F8E026000AE
-:10678000A31FD88AA298AF7B78B334C93DC081C01B
-:10679000F0028F380F0F42C9FA2CD67ED5206D4AF1
-:1067A0000500308800508C887008980878B16DD248
-:1067B000A09870D10FC0F0038F387FE0DE63FFD860
-:1067C000027B0CAFBB0B990C643047D830C0F1C0D2
-:1067D0005002F5380505426450792CD67E0B3612EE
-:1067E0002F6C100F4F366DFA0500808800208C0644
-:1067F000440CC081C05003B208237C0C03853805CB
-:10680000054264505A2CD67ED30F6D4A050020886D
-:1068100000308CD2A0A798BC889870D10FD2A0BCB1
-:10682000799970D10FD2302BAD08C0F1C0500BF563
-:1068300038050542CB542CD67E083F14260A100F8B
-:10684000660C0646366D6A0500208800B08C8270A2
-:1068500063FF2D00C05003F53875E08063FF7A00B8
-:10686000C06002863876E09F63FF9900C05003F550
-:106870003875E0C463FFBE006C1004D62068520F68
-:10688000695324DA20DB30DC405800F7D2A0D10F66
-:10689000DA20DB30DC405800F49A2424240EC02196
-:1068A00022640FC020D10F00B83BB04C2A2C748951
-:1068B000242D200E2E200FA4DDB1EE2E240FB0DDEE
-:1068C0002D240E2890072D9003A488B088B1DD2DCB
-:1068D00094032894075BFFA069511DC0E082242A1D
-:1068E000600F18D8BF2A240329600E8F202924079F
-:1068F00008FF029F209E64D10FC020D10F0000002E
-:106900006C1004942319D8B7C0B3083A110BAA022B
-:10691000992019D8299A2116D827C05028929D2548
-:1069200064A2288C1828969DD10F00006C100428B2
-:106930002066C038232406B788282466D10F0000BB
-:106940006C10060D3C111AD819D820035B0C862256
-:106950000D55118221AA8902320B928105630C9395
-:10696000820C550C792B54CB531CD8111DD80FC059
-:10697000F7A256C031C0A0043A380A0A42769343BF
-:10698000044302C9AB2CD67ED30F6DBA0500208814
-:1069900000308C8281A25272917D92818382C83EA6
-:1069A000D10FC071C06002763876F0DB63FFD5008E
-:1069B000C020BC89998199809282D10F222DF892B2
-:1069C0008163FFA219D7FA02860CA9669611D940F5
-:1069D000063612961006BB0C64A0442CD67E8A1094
-:1069E000D30F6DAA0500208800908CBC828311C053
-:1069F000E0A433240A01034E380E0E42CAEC2CD612
-:106A00007E6DBA0500208800308C821102520CA2E3
-:106A100082BC22928163FF83BC82928163FF7C00EF
-:106A2000C06002363876F0B563FFAF00C070024731
-:106A30003877F0CC63FFC6006C100414D7EBC1525A
-:106A4000A424CA3128221D73811C292102659016B5
-:106A50002A300075A912022A02033B022C3007C01B
-:106A6000D25801D5653FDCD10F2B300703BB0B0B90
-:106A7000BA0274B3022ABDF8D3A063FFC4000000B9
-:106A80006C1004292006C0706E9741292102C08F26
-:106A90002A2014C0B62B240606AA022A24147980C0
-:106AA000022725022A221E2C221D7AC10EC8ABDA2B
-:106AB00020DB302C0A00033D025BF7F96450892D7E
-:106AC00021020D0D4CC9D3C020D10F00002E9CFB1C
-:106AD00064E0962F21020F0F4C65F0A51AD7B71E60
-:106AE000D7B529A29EC08A798B712BE22668B004A3
-:106AF0008C207BC96629A29D1FD7B264905D9790B8
-:106B0000C0C31DD7C62B21049D9608BB110CBB0228
-:106B10009B919B971CD7C3C08527E4A22BA29D28DD
-:106B200024068DFA282102B0DD2BBC302BA69D9DBA
-:106B3000FA0C8802282502C8D2C020D10F8EF91283
-:106B4000D7B92E2689C020D10F283000688938DABD
-:106B500020DB30DC4058004463FF6300022A022B34
-:106B60000A065800D3220A00D10F655010293000C0
-:106B7000689924022A02033B02DC4058003BC020F3
-:106B8000D10FD270D10F00002A2C74033B02044CA9
-:106B9000025BFEF163FF2700DB30DC402A2C745BD4
-:106BA000FEEEC020D10F00006C1004C83F8926887B
-:106BB00029A399992609880C080848282525CC522C
-:106BC000C020D10FDB402A2C745BF92FD2A0D10F4B
-:106BD0006C1004D820D73082220D451105220C926A
-:106BE0008264207407420B13D771D420A3837323CC
-:106BF00002242DF8858074514CBC82C0906D08161B
-:106C000000408800708C773903D720C0918680744B
-:106C10003901D42074610263FFE2CA98C097C04171
-:106C20001BD7F2C0A00B8B0C0B4A380A0A42C9AA28
-:106C30001DD75E1CD75F2CD67EC140D30F6D4A0591
-:106C400000208800308C9780D270D10FBC8FC0E0BC
-:106C50000F4E387E90E263FFD6BC8292819280C054
-:106C6000209282D10F0000006C1006C0D71CD74EB6
-:106C70001BD7500D4911D7202E221F28221D0E4E42
-:106C80000BD280078A0C2E761F2AAC80C8346FAED8
-:106C9000026000CB2F0A801AD754A29EAA7A7EA344
-:106CA0003FC93FC0E1C05002E538050542CA552B37
-:106CB000C67EDB20D30F6D4A0500308800B08C2ED5
-:106CC000721DAE9E0EA50C645086D2802E761DC01D
-:106CD00091298403D10FC05003E53875D0D363FFE9
-:106CE000CD15D741027E0CA5EE643051C0A1250A16
-:106CF0000002A538033A020505426450922BC67E75
-:106D00000E35129510255C10054536D30F6D5A05CA
-:106D100000A08800208CC0A1A3E2C05023FA800309
-:106D2000730C03A538AF730505426450722BC67E01
-:106D3000851005450C6D5A0500208800308CD280E6
-:106D4000C0A10E9B0CAB7BAFBB2B761D2A8403D15D
-:106D50000FD280C0C1AF7D2D761D2C8403D10F00D2
-:106D6000D2302E8D08C0F1C0500EF538050542CB4B
-:106D7000592BC67E0A3F14C1600F660C064636D3F7
-:106D80000F6D6A0500208800E08C22721D63FF03EE
-:106D9000C061C05003653875D80263FF6263FF5C51
-:106DA000C05002A53875D08763FF8100C06003F62C
-:106DB0003876D0BF63FFB9006C10042A2015292053
-:106DC0001614D6FF0A990CCB9D2E200B04ED092B2F
-:106DD000D1208F2809BC36ACAA0CBB0C2BD5200ABD
-:106DE0000A472A2415CAAF8B438942B0A8009104F0
-:106DF00000881AA8FF0FBB029B278F260FB80C78BC
-:106E00003B1AC020D10F0000292102C0A20A99021A
-:106E1000292502C021D10F008B2763FFDC2BD12055
-:106E20000CAA0C0A0A472A2415ACBB2BD520C9AEE4
-:106E30008B438C288F42B0AD00F10400DD1AADCC3D
-:106E40000CBB029B27DA20B7EB580019C021D10FE9
-:106E50009F2763FFEF0000006C100428203C643083
-:106E60004705306000073E01053EB156076539050C
-:106E70004928C77FA933030641076603B1660606A2
-:106E800041A6337E871E222125291AFC732B150269
-:106E9000380C09816000063E01023EB124064239E9
-:106EA00003220AD10FD230D10FC05163FFC00000BE
-:106EB0006C100427221EC08008E4311DD6BF0002DA
-:106EC000002CD2821BD6BF003104C06100661A2B91
-:106ED000B1020C6C022CD6820BE43119D7440C3A67
-:106EE00011AA932832829780253282243284B455A5
-:106EF00025368275410A292102096902292502D114
-:106F00000F2A21022B32830A6A022B36822A25029B
-:106F1000D10F00006C100418D6A80C2711087708B0
-:106F2000267286253C04765B1315D6A405220A2218
-:106F300022A3682002742904227285D10FC020D1B7
-:106F40000F0000006C100419D6A727221EC080096C
-:106F5000770208E4311DD6980002002CD2821BD69D
-:106F600098003104C06100661A2BB1020C6C022C2F
-:106F7000D6820BE43119D71D0C3A11AA932832821C
-:106F80009780253282243284B45525368275410B90
-:106F90002A21020A6A022A2502D10F002B21022C83
-:106FA00032830B6B022C36822B2502D10F0000009E
-:106FB0006C10041BD6810C2A11ABAA29A286B43806
-:106FC000798B221BD67E19D6A50B2B0A2BB2A309CF
-:106FD000290868B00274B90D299D0129901F6E928D
-:106FE0000822A285D10FC020D10FC892C020D10F96
-:106FF000DA205BEE88C020D10F0000006C10041472
-:10700000D66E28429E19D66B6F88026000BA29920C
-:10701000266890078A2009AA0C65A0AC2A429DC068
-:10702000DC64A0A42B200C19D6650CBC11A4CC2EBA
-:10703000C28609B90A7ED30260009A2992A3689099
-:10704000078D2009DD0C65D08C25C2856450862D06
-:107050002104C0306ED80D2C2066B8CC0C0C472C07
-:10706000246665C07B1CD6E218D66B1AD66219D688
-:10707000731DD667C0E49E519D508F209357935542
-:1070800099539A569A5408FF021AD6839F5288261B
-:107090009F5A9E599D58935E9C5D935C9A5B08082D
-:1070A00048058811985FC0D81FD64C0CB911A49917
-:1070B000289285AFBF23F4CF288C402896858E2652
-:1070C0002D24069E29C020D10FCA33DA20C0B65B1A
-:1070D000FF78C72FD10FC93ADA205BFF75C72FD1D0
-:1070E0000FDBD05BFE072324662B200C63FF7500AB
-:1070F000C72FD10FC72FD10F6C1004C85B292006F2
-:1071000068941C689607C020D10FC020D10FDA20E8
-:10711000DB30DC40DD502E0A005BFE59D2A0D10FDF
-:107120002E200C18D6250CEF11A8FF29F286C08856
-:10713000798B791AD6220AEA0A2AA2A368A0048BBC
-:10714000207AB96823F2856430621BD62C290A8024
-:107150002C20682820672D21040B881104DD1108DC
-:10716000DD020DCC02C0842D4A100DCC021DD624A8
-:1071700098319D308A2B99379C340BAA02C0C09C51
-:10718000359C369A322A2C74DB4028F285C0D328ED
-:107190008C2028F6852C25042D24061FD60FDD40D3
-:1071A000AFEE2CE4CF5BFDE6D2A0D10F00DA20DBFE
-:1071B000E05BFF3FC020D10F6C100AD6302A2006BA
-:1071C00024160128ACF86583862B2122C0F22A21DF
-:1071D00024CC572AAC010A0A4F2A25247ABB026024
-:1071E000037F2C21020C0C4C65C3192E22158D3205
-:1071F000C0910EDD0C65D39088381ED5EF64836B8B
-:107200008C37C0B8C0960CB9399914B49A9A120D3B
-:10721000991199138F6718D5EAC9FB2880217F83BC
-:10722000168B142C22002A200C5BFF61D4A064A3CF
-:10723000B38F6760002800002B200C89120CBA1154
-:10724000AEAA2CA2861DD5DD7C9B3E0DBD0A2DD29B
-:10725000A368D00488207D893024A28564436427F4
-:10726000212E07F73607F90C6F9D01D7F0DA20DBE6
-:1072700070C1C42D211F5BFEF889268827DDA00977
-:10728000880C7A8B179A10600006C04063FFCC0010
-:1072900000DA208B105BFEC88D1065A267C0E09EEF
-:1072A000488C649C498B658A669B4A9A4B97458FAC
-:1072B000677F7302600120CD529D10DA20DB302CF5
-:1072C00012015BFE698D10C051D6A08FA7C0C08A85
-:1072D00068974D9A4C8869896A984E994F8E6A8A48
-:1072E00069AE7E77EB01B1AA9E6A9A698B60C0A0F5
-:1072F0000B8E1477B701C0A1C091C08493159D1760
-:107300009516C0D025203CC030085801089338C0DD
-:1073100082083310085B010535400B9D3807DD10EE
-:107320000BAB100E19402A211F07991003DD020D27
-:10733000BB020553100933020A55112921250A2AD7
-:10734000140929140499110A99020933028A2B2974
-:1073500021040BAA021BD6270899110955020855CA
-:10736000020BAA029A408920881408991109880200
-:1073700019D5A61DD62109880298418B2A934695D6
-:107380004783150DBB0285168D179B448A65896658
-:10739000AACAA97C77CB01B1AA07FB0C9C669A65A7
-:1073A00088268E29AD87972607EE0C0E0E482E25CF
-:1073B000259B672B200C87131ED5800CB911AE9925
-:1073C000289285A78828968517D584C090A7BB29C1
-:1073D000B4CF871863FE3C008C60C0E0C091C0F061
-:1073E000C034C0B82A210428203C08AA110B8B0104
-:1073F000038301039F380B9B39C03208FF100388B9
-:1074000001089E380C881407EE100FEE0203880165
-:1074100008983905BF1029211F0ABB1107881008D9
-:10742000FF020BAA0218D57809291403AA022B21FE
-:107430002583200B2B1404BB110833110FBB020B47
-:1074400099028B148F2A0B33020833028B2B647042
-:10745000868868974D984C8769886A9341994697C2
-:107460004E984FC07077C701C0719A4718D5E30B8B
-:107470007C100CEC0208F802984418D5E00CBC0211
-:1074800008CC029C402A200C295CFEC0801FD54AF3
-:107490001CD5520CAE112B2124ACAAAFEEB0BB8F81
-:1074A000132CE28528A4CFAFCC2CE6852A22152BFD
-:1074B0002524B1AA2A26156490DBC9D28F262E2254
-:1074C000090DFF082F26060FEE0C0E0E482E25255F
-:1074D0006550E4C020D10F00C07093419F4499468D
-:1074E0009A4777C70A1CD5362CC022C0810C873832
-:1074F0001CD5C40B781008E80208B8020C88029862
-:107500004063FF8000CC57DA20DB608C115BFDD636
-:10751000292102689806689403C020D10F2B221EEF
-:10752000C0A029221D2A25027B9901C0B064BFE8B2
-:1075300013D5212CB00728B000DA2003880A28824E
-:107540004CC0D10B8000DBA065AFE763FFCA000031
-:1075500068A779DA20DB30DC40DD505BFEE7D2A0A3
-:10756000D10FC16DC19D29252C60000429252CD681
-:10757000902624672F2468DA20DB308C11DD502E12
-:107580000A805BFD3FD2A0D10FC168C1A82A252C7B
-:1075900063FFDD000000C8DF8C268B29ADCC9C2664
-:1075A0000CBB0C0B0B482B25252A2C74DB602C12F2
-:1075B000015BFD87D2A0D10F2A2C748B115BF6B230
-:1075C000D2A0D10FDA205BFE3A63FF3800DA20C088
-:1075D000B15BFE8A64ABF1655F352D2124B1DD2DF1
-:1075E000252463FF1FDA202B200C5BFE5663FF145B
-:1075F00012D5858220028257C82163FFFC12D581F3
-:1076000003E83004EE3005B13093209421952263D5
-:10761000FFFC000010D57D910092019302940311AC
-:10762000D554821001EA30A21101F031C04004E4C7
-:107630001600020011D5768210234A00032202921E
-:107640001011D540C021921004E4318403830282DA
-:1076500001810000D23001230000000010D56D919F
-:107660000092019302940311D543821001EA30A2E3
-:107670001101F131C04004E41600020011D564820A
-:107680001013D4E7032202921004E431840383022E
-:107690008201810000D330013300000010D55E91DB
-:1076A00000810165104981026510448103CF1F925A
-:1076B000019302940311D531821001EA30A2110125
-:1076C000F231C04004E41600020011D550821013BC
-:1076D000D4CF032202921004E43184038302820196
-:1076E000C010910391029101810000D43001430048
-:1076F00012D500C03028374028374428374828376B
-:107700004C233D017233ED03020063FFFC000000D7
-:1077100010D542910092019302940311D54082103A
-:10772000921011D4F28310032202921011D53D124F
-:10773000D5049210C04004E41600020011D5348232
-:107740001013D4EB032202921004E4318403830269
-:107750008201810000D53001530000006C10026EE0
-:10776000322FD620056F04043F04745B2A05440CB5
-:1077700000410400331A220A006D490D73630403AB
-:10778000660CB1220F2211031314736302222C0121
-:10779000D10FC83BD10F000073630CC021D10F0083
-:1077A0000000000044495630C020D10F6C10020088
-:1077B00040046B4C07032318020219D10F0203196E
-:1077C000C020D10F6C100202EA30D10F6C1002CC35
-:1077D0002503F03160000F006F220503F1316000D6
-:1077E000056F230503F231000200D10F6C1002CCAB
-:1077F0002502F030D10F00006F220402F130D10FCA
-:107800006F230402F230D10FC020D10F6C1002227E
-:107810000A20230A006D280E2837402837442837CD
-:107820004828374C233D01030200D10F6C1002029F
-:10783000E431D10F0A0000004368656C73696F2062
-:1078400046572044454255473D3020284275696CD3
-:1078500074204D6F6E204D61722020382031373AF0
-:1078600032383A3135205053542032303130206F85
-:107870006E20636C656F70617472612E61736963F1
-:1078800064657369676E6572732E636F6D3A2F68F6
-:107890006F6D652F66656C69782F772F66775F3718
-:1078A0002E392D6977617270292C205665727369A3
-:1078B0006F6E2054337878203030372E30612E3080
-:1078C00030202D20313030373061303010070A0041
-:0478D0000BDFE8756D
-:00000001FF
diff --git a/firmware/intelliport2.bin.ihex b/firmware/intelliport2.bin.ihex
deleted file mode 100644 (file)
index e9cfe8c..0000000
+++ /dev/null
@@ -1,2147 +0,0 @@
-:100000003C4237180201030000000000000000001D
-:10001000576564204465632030312031323A3234F0
-:100020003A33302031393939000000000000000037
-:10003000E96C0F426547694E6E496E47206F462056
-:10004000634F6445CC135A15E8167618041A921BB0
-:10005000201DAE1E3C20CA215823E6247426022807
-:1000600090291E2BAC2C3A2EC82F5631E432723414
-:1000700000368E371C39AA3A383CC63D543FE24020
-:100080007042FE438C451A47A848364AC44B524D2D
-:10009000E04E6E50FC518A531855A6563458C2593A
-:1000A000505BDE5C6C5EFA5F88611663A464326646
-:1000B000C0674E69DC6A6A6CF86D866F1471A27253
-:1000C0003074BE754C776C778C77AC7733DB8ADC19
-:1000D0005333DB250700750A8A1E080183E30CEB06
-:1000E00020903C01750A8A1E080180E3C0EB129043
-:1000F0008A1E0D013C02750680E30CEB049080E340
-:10010000C053508B1EBA138EDBE86A65558BEC53D7
-:100110001E2BC08ED88B5E04C1E304035E06D1E3C0
-:100120002E8B9F44008D472A1E5A1F5B5DC3558B43
-:10013000EC531E2BC08ED88B5E04C1E304035E0615
-:10014000D1E32E8B9F44008D47341E5A1F5B5DC345
-:10015000FB558BEC53515256571E061E0733C08E6B
-:10016000D88B5E04268A47592503008BF0D1E62EF2
-:100170008BB4C400C1E0042602471AD1E08BE82EFC
-:100180008BAE4400892C268A471C88440F268A4758
-:100190001D884410268A471E884411268A471F88D6
-:1001A0004412268A4720884413268A472388441409
-:1001B000268A4724884415268A475A88440E33C025
-:1001C00089440689440888440B88440AB021B464F1
-:1001D000894404894402B05588440D88440CE86A77
-:1001E00000725BE8C900E8C110894408807C0F01F7
-:1001F0007429E82B02E87F02807C0F03741DE8A9B4
-:10020000108BF82B44083DA00F7210897C0833C076
-:1002100087440685C07504C6440AFF8A440A84C020
-:10022000750BB80800E86A4AE8A90173BFE84F01F6
-:100230008166487FFF83667ABFB002E8040E8A4475
-:100240000A98071F5F5E5A595B5DC3814E48800064
-:10025000B040E83D4AE88940732AE84D108BD8B099
-:1002600005E82E4AF6462702751AE83D102BC33DD5
-:10027000581B72EB8166487FFFB002E8C40DC6448C
-:100280000A01F9C3834E7A40F8C3FBB001E8024A81
-:10029000FAE8991EE40A84C075F0B04EE60AFBB095
-:1002A00001E8EE49FAE8851EE40A84C075F0C3FA55
-:1002B000E87A1EE4EC884416E4E4884417E4F888FD
-:1002C0004418E4F0884419E41088441AE41288447D
-:1002D0001BE41488441CE43488441DE43688441E1E
-:1002E000E4D824018AE0E4DA24020AC488441F8A9C
-:1002F0004410E8CD1F8A4411E835218A4412E88968
-:10030000218A4413E84321C686A10000E414241086
-:10031000E614E412243DE6128A44153C01721E776D
-:1003200016B011E634B013E636E4140C10E614E40B
-:10033000120C40E612EB06E4120C02E6128A440F9D
-:100340003C0174063C02740AEB0EE4120C08E6123F
-:10035000EB06E4120C10E612E82FFF8A44143C026C
-:100360007508B05588440C88440DB021B4648944A4
-:1003700004894402E40C0C10E60CE8ED39FBC3E8F8
-:100380005F3F7308FBB00AE80849EBF3FAE89D1DEC
-:100390008A64168A441789869400E6E48AC4E6ECE7
-:1003A0008A64188A441989869600E6F08AC4E6F8B9
-:1003B0008A441AE6108A441BE6128A441CE6148A10
-:1003C000441DE6348A441EE6368A441FE6D8E6DA3F
-:1003D000E9B7FE90FA8A440EE6FEE402A80175052C
-:1003E00033C0FBF8C333C0E400FBF9C38A64148054
-:1003F000FC02742BFEC0FEC780FF4E721C74098085
-:10040000FF507308B00AEB17B00DEB1302DC32FF9C
-:1004100080FB7F7C02B3218AC33C7F7C02B021C376
-:10042000FA807C0B047602FBC38B46243D080072E5
-:10043000F68E46028B7E228A440C8B5C02AAE8ABC5
-:10044000FFAAE8A7FFAAE8A3FFAAE89FFF88440C39
-:10045000895C0280440B04897E22836E24048346D7
-:100460001A04807E26027406806626FDFBC360B0F7
-:10047000FDE8023F61FBC3FA807C0F037509C644A7
-:100480000B00E8E538FBC3C47E148B4E3A85C97572
-:1004900035268B0D4747E3EA3B7E047622B80200FF
-:1004A00039462E7707C7462E0000EB138B5E2C894A
-:1004B0005E0426C70700004343895E2C29462E852B
-:1004C000C978CE894E3A8A440D8B5C04268A25472A
-:1004D0003AC47516FE4C0BFF4406E80FFFE2ED88A8
-:1004E000440D895C04894E3AEBA7C6440AFEE879BC
-:1004F00038FBC390E8B30D8AE88A0ECB13B3078AA2
-:10050000C1EEEB00EC3AC1750902CDFECB75F0EB04
-:100510000C90880ECB138AE8BBFFFFF9C3880ECB83
-:1005200013F8C390BB3F3F8A8E9E00BAFE00EC8A50
-:10053000E832C122C37502F8C3F9C390E8E5FF733E
-:1005400001C3BAD000BB03038A8E9F00EC8AE83255
-:10055000C122C37502F8C3F9C39033C08ED88EC0D0
-:10056000803EC813007507B00AE82647EBF2FB335C
-:10057000DB8A1EC913434383FB7E760733DBB0025D
-:10058000E80F472E8BAF4400837E080074E7881E77
-:10059000C913B002E8FB46FAF7463840007414E885
-:1005A000961BE87FFF721C33D28A969F0083C20E8F
-:1005B000EB0C90E8771BE883FF7208BA4800E83339
-:1005C000FF73AB23CB898E9A0089969C00FE86B57B
-:1005D00000C606C81300B00AE8670AFBEB891018CA
-:1005E000082833C0A005018AC824407524C7067CAA
-:1005F000128E45C70642120100C606541202B00808
-:10060000F6C1017402B004A34612A24C12A29412C5
-:10061000C3C7067C12B645A00F0184C0750E6A00E0
-:100620001FC60693121E9C0EE8B10C90C70644121A
-:100630000100A342128BD8C1E304881E9412BEE2CB
-:10064000052BF08BC833DB8BFB2EAC888548128AD8
-:10065000D80C05E6FE8AE0EB00E4FE32C4A83F7445
-:1006600003E99E00E400888550128AE02430BA1025
-:10067000FF3C30741280FC04740ABA0403F60608C6
-:1006800001FE7403BA080F88954C1202FA32C0F6C4
-:10069000C4087402B001888558128AC43C35745B62
-:1006A0003C3674573C3474533C04744F3C14744BC4
-:1006B0003C157447A8407425C685541204D1E7B48C
-:1006C000038AC389855C128AC38AE380CC01898549
-:1006D0006412D1EF47E203EB1A90E96CFFC6855430
-:1006E0001202D1E78AE68AC30C0489855C12D1EF35
-:1006F00047E2E733C08AC7A34612C3C68554120631
-:10070000EBBBC68554120033C08885501288854CD7
-:100710001288855812EBA6C7462602128B461E8900
-:1007200046008946228B4620894624C7461A000087
-:10073000C3C7463C8000C7463801001E568B763042
-:100740008976048976148E5E0633C089044646890C
-:10075000762C89463A8B4632484889462E5E1FC31E
-:1007600033C089464889464AC74646AE0189464E47
-:100770008B46448946508B4642894640894608C389
-:1007800033C0894676894678C7467A1000561E8B54
-:10079000767089761089760C8E5E12C70400008B05
-:1007A00046728946741F5EC3895618895602895657
-:1007B0000689560A89560E8956128956168BD84BC9
-:1007C0004BC1E302BF0200897E1E03FB897E30031A
-:1007D000FB897E4203FB897E7083EB08895E20895A
-:1007E0005E32895E44895E7250E82BFFE871FFE853
-:1007F0003FFFE88BFF58C3B83075C1E8040E5B03B8
-:10080000C3A3BA13833E4212007407803E941200C1
-:10081000750E6A001FC60693121E9C0EE8BD0A9054
-:10082000B8307AC1E80440A3C0132B061201F7D8F0
-:1008300033D28BCA8A0E9412F7F13D8000770E6A8C
-:10084000001FC6069312259C0EE8900A90483DFFB3
-:10085000077203B8FF07A3C21333C98A0E94123379
-:10086000F6B800092E8BAC440089464C404646E25F
-:10087000F38A0E941233F68B16C013A1C2132E8B7B
-:10088000AC4400E822FF03D04646E2F2C333C02E58
-:100890008BAD44008946084747E2F4C35133C00A90
-:1008A000C22E8BAD440089869E00814E38002047C1
-:1008B00047FEC480FC04720432E4FEC0E2E35983C4
-:1008C000E9107405F7D9E8C4FFC35133C00AC22E3A
-:1008D0008BAD440089869E00834E3840474780C4D4
-:1008E00010790432E4FEC0E2E65983E9107405F79A
-:1008F000D9E899FFC3E8D2FFC38D089C08CA08F560
-:10090000088B0E421233F6515633DB8BCB8A944858
-:10091000128A8C4C128A9C54128BFEC1E70585DB2F
-:100920007502B1102EFF97F9085E5946E2D9C3014E
-:10093000CC03D000E802D000E801D000E800D000ED
-:10094000E804D0A8DA00DC00DE01D803CC03CC0335
-:10095000CC04D0A8DA20DC00DE03CC03CC03CC002E
-:10096000D803CC03CC03CC03CC03CC03CC03CC0303
-:10097000CC03CC03CC03CC03CC03CC03CC03CC03FF
-:10098000CC04D000DA20DC03DE01D803CC03CC0396
-:10099000CC03CC00D800CC00D0000056521E0E1F55
-:1009A000BE2F0933D2FCAD85C0740D8AD4EEAD855F
-:1009B000C074058AD4EEEBEE1F5A5EC3E48084C097
-:1009C00074167814B027E6FCB011E634E4FC3C273A
-:1009D0007506E4117502F8C3F9C383C206B0BFEE11
-:1009E00083EA02B010EE8886AF00B01183C204EE35
-:1009F00083C202EEB01383C202EE83C202EE2EA1C6
-:100A00004C2D8986940083EA0EEE83C2028AC4EEDE
-:100A100083C204B003EE8886A80083EA0432C0EEE5
-:100A200083C202B089EE8886A6000C06EEB040B400
-:100A30003889461CC74636380083C20432C0EE8867
-:100A400086A700C383C206B0BFEE83EA02EC3A86F3
-:100A5000AF00752483C204EC3C11751C83C206EC04
-:100A60003C13751483EA088A86A800EE83EA02EC38
-:100A700024C03CC07502F8C3F9C333C98BD18BF1D4
-:100A80008A0E9412C1E9022E8BAC4400F74638005E
-:100A900020740E8A869E00E6FE32C0E68042E8FAA6
-:100AA000FE83C608E2E185D27403E80508C333C9B2
-:100AB0008BF18A0E94122E8BAC4400F7463840001E
-:100AC0007406E87316E812FF4646E2EAC333C98BA0
-:100AD000F18A0E9412C1E9022E8BAC4400F746381D
-:100AE00000207416E84616E8D2FE730E6A001FC690
-:100AF0000693121C9C0EE8E3079083C608E2D9C354
-:100B000033C98BF18A0E94122E8BAC4400F7463811
-:100B100040007416E82116E82AFF730E6A001FC60B
-:100B20000693121C9C0EE8B307904646E2DAC30C0B
-:100B300000001000131200001400283C001B3E00AF
-:100B4000002A00002C0000420014D80000DA000047
-:100B50003400113600133800113A001300005650CB
-:100B600052BE2F0B2EAD85C07406922EACEEEBF468
-:100B70005A585EC3532EA16022E6E4E6F08AC4E62A
-:100B8000ECE6F8E8D8FFB04BE610B050E612B0380B
-:100B9000E614E8AE15B046E60AE8A715B01AE60A6C
-:100BA000E8A015B022E60AE89915E8FD068BD8E41E
-:100BB00016A8047518E8F2062BC33D320072F06ADD
-:100BC000001FC6069312239C0EE8100790E8DA0671
-:100BD0002BC33D2400771BB031E6FC565155B910AC
-:100BE000002E8BAC4400814E3880004646E2F25D18
-:100BF000595EE869FFE84B15B046E60AE844155B24
-:100C0000C333F68B0E42122E8BAC4400F7463800ED
-:100C1000207406E81715E85BFF83C620E2E9C38B62
-:100C2000C20504008946282EA14C2D89868E008994
-:100C300086900089869200C686A3000AC686C300F5
-:100C4000035283C2048A86A6000C06EE5A83C202AF
-:100C5000B005EE8886A500C3E803FFE8E514B042BE
-:100C6000E60AF74638800074062EA19C22EB042E7B
-:100C7000A16C22C7461C0C008986940089869600C8
-:100C800089868E008986900089869200E6F0E6E4E7
-:100C90008AC4E6F8E6ECC686C30003E8A514B01AD9
-:100CA000E60AB0108886A500E60CC333C98BF18A2A
-:100CB0000E94122E8BAC4400F7463840007406E8C0
-:100CC0007614E85AFF4646E2EAC333C98BF18A0E2E
-:100CD00094122E8BAC4400F7463800207406E84C82
-:100CE00014E874FF4646E2EAC390833E441200755E
-:100CF00014B001BA0601EE2AC0EEB002EEB004EE66
-:100D0000B80002EB0FBA0601B040EEB801008A0E3F
-:100D10000E01D3E0A38812C3A18812A384122D2050
-:100D200000A38A122D2000A38212C706861220007B
-:100D3000C70680123200C3833E44120074768B0EC5
-:100D4000421233F68AA4541284E4745F8A844812EF
-:100D50000C04E6FEF6C4047425B01BBA0000EEEBEA
-:100D6000002AC0BA0200EEEB00B003EEEB0032C086
-:100D7000BA0200EEEB00BA0000B000EEEB2DB01F9F
-:100D8000BA0000EEEB002AC0BA0200EEEB00B0039E
-:100D9000EEEB00D1E68A845D12D1EEF6D0BA020005
-:100DA000EEEB00BA0000B00AEEEB00E404EB00E466
-:100DB0000446E290C390B81400BA3EFFEFB80600B4
-:100DC000BA32FFEFB80F00BA34FFEFBA36FFEF8345
-:100DD0003E4412007516B81100BA38FFEFB8120081
-:100DE000BA3AFFEFB81B00BA3CFFEFC3B81100BA24
-:100DF00038FFEFB81200BA3AFFEFB81B00BA3CFF59
-:100E0000EFC3B8FC00BA28FFEFFB833E4412007426
-:100E100007B8CC00BA28FFEFC300FFFF202428FF4B
-:100E20002CFFFF303438FFFF3C903C0F770EBB198E
-:100E30000E2ED73CFF74058AD8F8C3902ADBF9C37D
-:100E4000833E4412007427A00601802606013080EC
-:100E50003E0601307518B90200BFC413BA0601EC92
-:100E6000A82075F8BA0401EDABE2F1EB1690B904D5
-:100E700000BFC413BA0601ECA82075F8BA0401EC4F
-:100E8000AAE2F1FA90BEC413AD80E43F80FC027484
-:100E90000E6A001FC60693120A9C0EE83E0490AD2F
-:100EA0003C0F75ED8AC4E881FF72E6881E1A01C600
-:100EB000068E1200B0000A061A01BA0001EEC6063C
-:100EC0008F1240833E4412007506B80C00EB04906C
-:100ED000B84C00BA28FFEFC3833E4412007501C32B
-:100EE000A150120B0652120AC4A80874F2A00F01F6
-:100EF0002AE450FF36BA131FE8505683C4026A0032
-:100F00001F33C0A3BC13A00F01A3BE138B1EBC13C1
-:100F10008A875012F687501208740D24078AE0BEA3
-:100F2000CC00A0BC13E8943DFF06BC13FF0EBE131B
-:100F300075DAC3901E33C08ED8B001E8543D1FC38C
-:100F400033C98BF18A0E94122E8BAC4400C74662D3
-:100F50003844C7467CFC3BC7467EE23BC7868000E0
-:100F6000EC3CE8AB16C686C00011837E080074070F
-:100F70005156E833335E594646E2CDC333C98BF14F
-:100F80008BF98A0E9412C1E902E3132E8BAC440054
-:100F90008A869E0088856C1283C60847E2EDC3FAF4
-:100FA000FCB0C0BA0001EE33C08ED88EC08ED0BF68
-:100FB0001601B9CC772BCFD1E9F3ABBC4012E8D9FD
-:100FC00002E8703CBECC0FE8F23CF49033C08ED8FF
-:100FD0008EC08ED0F6060A0180740BBE3555E8DB54
-:100FE0003CB001E8AC3CE8B300E8F6F5E808F8E806
-:100FF0000FF9E885FAE8B6FAE8EFFCE8C210E80372
-:101000003CE8B2FDE830FDE85402C6068F12C0E8A5
-:10101000BBFAE8EBFAE8E9FBE8AFFCE88DFCE81F77
-:10102000FFE858FFE8DBFDE816FE33C0BE5A05E8CE
-:101030008A3CE8A3FEE8E0FCFBBEA444E87D3CE972
-:10104000CA2D56988BF08B425285C07527C74252E5
-:10105000010053368B9C2C01F6C301750C36896850
-:10106000523689AC2C015B5EC33689AC2C013689C3
-:10107000AC1C015B5EC356988BF033ED368B841C41
-:1010800001A80175158BE833C08742523689841C4C
-:1010900001A80174053689842C015EC3565133F6CC
-:1010A000B80100B9080089841C0189842C014646D6
-:1010B000E2F4595EC390BB01008BE8FF4E6E740AE8
-:1010C0008BDD8B4658A80174F0C38B4648A90800F5
-:1010D0007445F7463840007427E85C1080C2068AE1
-:1010E00086A80024BF8886A800EE60B0FEE886329D
-:1010F00061B002E84CFF8B464824F7894648EB175D
-:10110000E82A10814E2600408A86A5000C028886B7
-:10111000A500E60C8B4648A904007414B002E8212F
-:10112000FF8B464824FB89464860B0DFE8473261C0
-:1011300033C0874658F6C301750B36894758A80156
-:10114000750DE974FFA32201A8017503E96AFF89FF
-:101150001E3201C3BB01008BE8F74638400074150E
-:10116000E8D50F80C20AECA840750A8BDD8B465685
-:10117000A80174E3C38B462680E4FE80CC02894636
-:1011800026B002E8BCFE33C0874656F6C301750A96
-:1011900036894756A801750BEBBDA32001A8017540
-:1011A00002EBB4891E3001C3601E062BC08ED8A08E
-:1011B000901284C07549A12201A8017503E8F6FECA
-:1011C000A12001A8017503E88AFFA1AC13487805A6
-:1011D0007445A3AC13A1AE134878057451A3AE13A4
-:1011E000A1B0134878057463A3B013A17E124078B0
-:1011F00003A37E12B80080BA22FFEF071F61CFA0C1
-:101200009112403C02720B33C0A29112FF167C1265
-:10121000EBA4A29112EB9FA08E1232068F12A28E27
-:10122000120A061A01BA0001EEB82C01EBA4833EA3
-:101230008412107211BA28FFED0C81EFE85337BA0F
-:1012400028FFED247EEFB80400EB92C6068D120154
-:10125000E83F37C6068D1200A1B213EB8B908A1EB1
-:101260000B012AFF6BC319BA62FFEFB80A00BA601C
-:10127000FFEFB801E0BA66FFEFB8FFFFBA52FFEF29
-:10128000B809C0BA56FFEFC706AC132C01C706AEAB
-:10129000130400C606911200C3908A1E0B012AFF98
-:1012A0006BC305D1E8A31801C39052BA50FFED5AA1
-:1012B000C39053518B1E1801B9320590E2FE4B7555
-:1012C000F7595BC3B080BA00010A061A01EEC39059
-:1012D000B040EBF2B0C0EBEEB000EBEAFA60061EF5
-:1012E000162BDB8EDB2EA1BA4C2EA3924CA09312B0
-:1012F000988BE889262D7A803ECA13007403E96B27
-:1013000042E8C0FFE8ABFFE8A8FFB020C606901295
-:1013100000FF167C128BFD83FF0A7211E8B9FFE80B
-:1013200090FFE8ABFFE88AFF83EF0AEBEA0BFF745C
-:101330000FE8A4FFE87BFFE89AFFE875FF4F75F11F
-:10134000E895FFE86CFFEBB98A86A50024FDEE88DE
-:1013500086A500C38A86A6000C02EEC38B7638F7FA
-:10136000C6010074EF8B4E368B462E3BC173028B49
-:10137000C82BC189462E014E34C47E0426010D8B34
-:101380007E2C83EA04F36C8EC1897E2C3B463C7232
-:1013900012F7C62000750B83CE20897638B000E89E
-:1013A000A0FCC3F7C60400741B8BD883CE108976CB
-:1013B000388A86A70024FE8886A70083C208EE83A9
-:1013C000EA088BC33D40007201C3814E380004839C
-:1013D000C2028A86A50024FA8886A500EEC38A8602
-:1013E000A6000C02EEC3F74638010074F18B4E2EB6
-:1013F00032DB8ABEA30083C206C476048B7E2C83B4
-:10140000F908722CECA80174168AE083EA0AEC83CE
-:10141000C20A84E77551AAFEC34983F90873E5320D
-:10142000FF26011C015E34897604894E2E897E2CAC
-:101430003B4E3C7211F64638207401C3834E38206F
-:10144000B000E8FDFBC3F64638047415834E38102F
-:101450008A86A70024FE8886A70083EA02EE83C25C
-:10146000023D4000725DC332FF26031C85DB740918
-:1014700026891C8BF74747494980E41E80CCC0264B
-:101480008904F6C41074278B7638F7C60010740BE5
-:1014900050FE86B200B00AE8A8FB58F7C6000174F7
-:1014A0000DE882268B76388B4E2E8B7E04AB8BF725
-:1014B00033C0AB32DB8ABEA300494983F9087217F7
-:1014C000E941FF814E38000483C2F88A86A50024D2
-:1014D000FA8886A500EEC3E945FF83C208EC88863A
-:1014E000AA00C0E8048AE08AC88686A90032E08B98
-:1014F0005E3E84E3744F8AC18B4E26F6C504740C9D
-:10150000A808740580E1BFEB0380C940F6C50874E4
-:101510000CA802740580E17FEB0380C980884E2609
-:101520008BF08A86A50084C97408A802741524FD6E
-:10153000EB06A802750D0C028886A50083EA0AEE68
-:1015400083C20A8BC684E77501C3C686BA0001B0A0
-:101550000EE8EEFAF74638000274EE837E2E06722D
-:10156000E88AA6AA00C45E048B7E2CB0FFAAB00253
-:10157000AB26830703836E2E03897E2CF646382024
-:101580007401C3834E3820B000E8B6FAC39083EAF2
-:1015900008E9B4FD83C2068B5E26F6C3C075EF8BE7
-:1015A0004E1CEC8886A40083EA0AA82075028ACD26
-:1015B00032ED8B461A3BC87318014E2A2BC189465F
-:1015C0001AC57600F36E8ED98976003D2000723000
-:1015D000C385C074318BC801462AC57600F36E8E70
-:1015E000D980CB02895E26E832F1F6C701751683F1
-:1015F000C202E853FDF6C710750BB002E843FAC308
-:10160000F6C70174F0C380CB02895E26F6C7017469
-:10161000DE83C202E831FDF686A40040740B80E749
-:10162000FE80CF02895E26EBCCB004E814FAC3C07A
-:10163000C2C8CAC4C6CCCED0D2D8DAD4D6DCDE90EA
-:10164000E90E01E4C48AE0E4C48BD083F90872F0A7
-:1016500026833F0074048BDF49498BFB8ADE83E3DA
-:101660000F2E8AA72F16ABF6C4107424F7C60010ED
-:10167000740B50FE86B200B00AE8C6F958F7C600EF
-:1016800001740DE8A0248B76388B4E2E8B7E04AB34
-:10169000897E0433C0AB4949894E2E897E2C8BC18B
-:1016A000EB4E90EB9E90E4D684C07963E6D08AC876
-:1016B00025030003D8D1E32E8BAF4400888EAE0003
-:1016C0008B4E2EC45E048B7E2C8B7638E4862407EA
-:1016D0003C0375CFE41C913BC173028BC82BC189BD
-:1016E000462E014E3426010FBAC400F36C897E2CBD
-:1016F0003B463C721CF7C62000750B83CE208976D2
-:1017000038B000E83CF98A86AE00243FE6D6C3F93B
-:10171000C3F7C60A007435F7C61000752F83CE10C4
-:10172000897638F7C60200740E50E4D824FEE6D855
-:1017300058F7C6080074155051B9E803E40A84C08C
-:10174000E0FA84C07504B024E60A59583D4000739D
-:10175000B58A86A50024EF8886A500E60C81CE1008
-:1017600004897638EBA00008040C0109050D020A73
-:10177000060E030B070F004080C02060A0E0105051
-:1017800090D03070B0F0E4D2E6D08AC825030003D0
-:10179000D8D1E32E8BAF4400888EAE00E4D8C0E8E9
-:1017A000048BD82E8A8766178AE08AC88686A900A5
-:1017B00032E0E4988B5E3E84E374548AC18B4E26FB
-:1017C000F6C504740CA808740580E1BFEB0380C95A
-:1017D00040F6C508740CA802740580E17FEB038015
-:1017E000C980884E268BF08A86A500F6C1FD740854
-:1017F000A806741924F9EB0FA8067511F6C5017532
-:10180000040C04EB020C028886A500E60C8BC6844F
-:10181000E775098A86AE00243FE6D2C3C686BA00C1
-:1018200001B00EE81CF8F74638000274E6837E2EFD
-:101830000672E08A86A9008AE08686AA008AC832F3
-:10184000C480C90B22C1C0E4040AE0C45E048B7EDC
-:101850002CB0FFAAB002AB26830703836E2E038948
-:101860007E2CF646382075AB834E3820B000E8D188
-:10187000F7EBA090E41224DFE61281E3FE9F895E7D
-:1018800026836648F7EB7390F6C72075E7E4120CE1
-:1018900020E61232C0E6C6B083E6C680CF20895E5D
-:1018A000268A86A5000C028886A500E60CEB7490BB
-:1018B000F6C74075D3E4120C20E61232C0E6C6B07B
-:1018C00081E6C680E7DF80CB01895E26B006E8713D
-:1018D000F7908A86A50024F9E60C8886A500EB43DC
-:1018E000E4D4E6D08BF825030003D8D1E32E8BAFE8
-:1018F00044008B5E26F6C76075B6F6C3C075D3BAD2
-:10190000C6008B4E1C8B461A3BC8731E014E2A2BF9
-:10191000C189461AC57600F36E8ED98976003D20BE
-:1019200000723D8BC7243FE6D4C385C074398BC891
-:1019300001462AC57600F36E8ED983CB02895E26D6
-:10194000E8D9EDF6C70175398A86A50024F9E60CB9
-:101950008886A500F6C71075CAB002E8E4F6EBC3A6
-:10196000F6C70174EFEBBCF6C70174DC8A86A500EC
-:10197000A802741181E3FFFE81CB0002895E26EB91
-:10198000C78A86A50024FB0C02E60C8886A500EB1E
-:101990009290FDF7DF7FFEFBEFBF0004000405041B
-:1019A00005040104000405040504060406040504F6
-:1019B00005040604060405040504020400040504E5
-:1019C00005040104000405040504060406040504D6
-:1019D00005040604060405040504070407040504B9
-:1019E00005040704070405040504060406040504A9
-:1019F0000504060406040504050407040704050499
-:101A00000504070407040504050406040604050488
-:101A10000504060406040504050403040004050483
-:101A20000504010400040504050406040604050475
-:101A30000504060406040504050402040004050464
-:101A40000504010400040504050406040604050455
-:101A50000504060406040504050407040704050438
-:101A60000504070407040504050406040604050428
-:101A70000504060406040504050407040704050418
-:101A80000504070407040504050406040604050408
-:101A90000504060406040504050433DB8AD88A8796
-:101AA0006C12E6FEC1E302E4CEA8047509A8027434
-:101AB00003E92CFEF9C35053E8CBFC5B58A8027431
-:101AC00003E91CFEF8C333DB8AD88A876C12E6FE72
-:101AD000C1E302E9D0FB9A1AC61A00000200040012
-:101AE00002000600020004000200080002000400D8
-:101AF000020006000200040002000A0002000400C6
-:101B000002000600020004000200080002000400B7
-:101B1000020006000200040002000C0002000400A3
-:101B20000200060002000400020008000200040097
-:101B3000020006000200040002000A000200040085
-:101B40000200060002000400020008000200040077
-:101B5000020006000200040002000E000200040061
-:101B60000200060002000400020008000200040057
-:101B7000020006000200040002000A000200040045
-:101B80000200060002000400020008000200040037
-:101B9000020006000200040002000C000200040023
-:101BA0000200060002000400020008000200040017
-:101BB000020006000200040002000A000200040005
-:101BC00002000600020004000200080002000400F7
-:101BD00002000600020004000200C390DA1494150B
-:101BE0005C13E613DA1BDA1BE613DA1B8B94641220
-:101BF000C1E604A80174355033C08AC2E6FEE4A0F1
-:101C000085C074278BD82E8A9FDA1A52562E8BA83D
-:101C100044008B5628ECA801750D8886AD00240E73
-:101C20008AD82EFF97DC1B5E5AEBCD58A80274367B
-:101C300083C61033C08AC6E6FEE4A085C074278B35
-:101C4000D82E8A9FDA1A52562E8BA844008B56281B
-:101C5000ECA801750D8886AD00240E8AD82EFF975A
-:101C6000DC1B5E5AEBCDC39032E48BD88BD02E8A2E
-:101C70009F9A192E2297921956528AC3240303C69B
-:101C800080E304D0EB2EFF97D61A585EA955007555
-:101C9000D9C3601E062BC08ED8A15C12E6FEE400FC
-:101CA00022C4740833F6E8BFFFEBEE90E40407E4C7
-:101CB000041FB80080BA22FFEF61CF90601E062B90
-:101CC000C08ED8A15E12E6FEE40022C47408BE04F1
-:101CD00000E894FFEBEDE40407E4041FB80080BAC9
-:101CE00022FFEF61CF90601E062BC08ED8A15C1240
-:101CF000E6FEE40022C4741833F6E86BFFA160121C
-:101D0000E6FEE40022C474E5BE0800E85AFFEBDDFD
-:101D1000A16012E6FEE40022C475EDE40407E404C9
-:101D2000A15C12E6FEE4041FE404B80080BA22FFBE
-:101D3000EF61CF90601E062BC08ED8A15E12E6FE2A
-:101D4000E40022C47419BE0400E81CFFA16212E67C
-:101D5000FEE40022C474E4BE0C00E80BFFEBDCA13F
-:101D60006212E6FEE40022C475EDE40407E404A177
-:101D70005E12E6FEE4041FE404B80080BA22FFEF1E
-:101D800061CF601E062BC08ED8A15C12E6FEE480F7
-:101D900084C4740833F6E853FEEBEE90B80080BAC2
-:101DA00022FFEF071F61CF90601E062BC08ED8A1C7
-:101DB0005E12E6FEE48084C47408BE0200E82CFED5
-:101DC000EBEDB80080BA22FFEF071F61CF90601ED5
-:101DD000062BC08ED8A16012E6FEE48084C474088D
-:101DE000BE0400E806FEEBEDB80080BA22FFEF0764
-:101DF0001F61CF90601E062BC08ED8A16212E6FE36
-:101E0000E48084C47408BE0600E8E0FDEBEDB80091
-:101E100080BA22FFEF071F61CF90601E062BC08E95
-:101E2000D8A15C12E6FEE40022C4741833F6E83749
-:101E3000FEA16012E6FEE48084C474E5BE0400E8FE
-:101E4000AAFDEBDDA16012E6FEE48084C475EDA17D
-:101E50005C12E6FEE40407E4041FB80080BA22FF27
-:101E6000EF61CF90601E062BC08ED8A15E12E6FEF9
-:101E7000E40022C47419BE0400E8ECFDA16212E67D
-:101E8000FEE48084C474E4BE0600E85FFDEBDCA1E0
-:101E90006212E6FEE48084C475EDA15E12E6FEE403
-:101EA0000407E4041FB80080BA22FFEF61CF601E70
-:101EB000062BC08ED8A15C12E6FEE48084C47418A0
-:101EC00033F6E827FDA16012E6FEE40022C474E5C3
-:101ED000BE0800E892FDEBDDA16012E6FEE4002200
-:101EE000C475EDE40407E4041FB80080BA22FFEFD4
-:101EF00061CF601E062BC08ED8A15E12E6FEE48084
-:101F000084C47419BE0200E8E2FCA16212E6FEE499
-:101F10000022C474E4BE0C00E84DFDEBDCA16212AB
-:101F2000E6FEE40022C475EDE40407E4041FB800F3
-:101F300080BA22FFEF61CF90601E062BC08ED8A121
-:101F40005C12E6FEE48084C4741833F6E89DFCA1BC
-:101F50006012E6FEE48084C474E5BE0400E88CFCF4
-:101F6000EBDDA16012E6FEE48084C475ED071FB8C6
-:101F70000080BA22FFEF61CF601E062BC08ED8A171
-:101F80005E12E6FEE48084C47419BE0200E85CFCC4
-:101F9000A16212E6FEE48084C474E4BE0600E84B4D
-:101FA000FCEBDCA16212E6FEE48084C475ED071F41
-:101FB000B80080BA22FFEF61CF90601E062BC08E62
-:101FC000D8902AC0E6FEE4CEA801741433DBE8D52D
-:101FD000F6EBEF90B80080BA22FFEF071F61CF90B9
-:101FE000F60605010175EDB001E6FEE4CEA8017428
-:101FF000E3BB0400E8AFF6EBC990601E062BC08E71
-:10200000D890FB90FA2AC0E6FEE4CEA802741333FF
-:10201000DBE8CCF8EBECB80080BA22FFEF071F61D9
-:10202000CF90A80474F033DBE85BF7EBD590601E2B
-:10203000062BC08ED890FB90FAB001E6FEE4CEA845
-:10204000027415BB0400E897F8EBEB90B80080BA77
-:1020500022FFEF071F61CF90A80474F0BB0400E8D3
-:1020600024F7EBD26A001FC6069312099C0EE86B98
-:10207000F2906A001FC6069312299C0EE85DF2904A
-:10208000722072207220CE1D921CE61C1A1E722035
-:10209000821DAE1E381F7220821D72207220381FD2
-:1020A000722072207220F41DBC1C341D641E72202C
-:1020B000A81DF21E781F7220A81D72207220781FA2
-:1020C000FCB940008CCBB864202BFFAB93AB93E200
-:1020D000FAC7064C00A811833E4412007520C706BB
-:1020E0003C00084BC7063000BA1FC7063400FA1F71
-:1020F000F6060501017506C70638002E20C3C7067F
-:102100003C00564B33DB8A1E5412C1E302021E56BA
-:10211000122E8B878020A330008A1E5512C1E30245
-:10212000021E57122E8B87A020A33400C38B869EDD
-:1021300000E6FE86C4E6D0C38B869E00E6FE33D260
-:102140008AD4C351B91027E40A909084C07405E280
-:10215000F659F9C359F8C384C0781E518AE88AC871
-:10216000B80100D3E0098698003AAEA00059751076
-:10217000E8A9E5834E2602F9C39889869800EBF01A
-:10218000F8C384C07812518AE08AC8B80100D3E04D
-:1021900059F7D021869800C3C78698000000C383F2
-:1021A000C2048A86A6000C04EE83EA04C3E893FF07
-:1021B0007204B082E60AC38B4626A8FD74118A8693
-:1021C000A500A806740824F98886A500E60CC3F6C5
-:1021D000C401740A8A86A50024FB0C02EB0CA80239
-:1021E000750F8A86A50024FD0C043A86A50075D8D3
-:1021F000C38A86A500EBCFE4D833DB8AD8C0EB04D2
-:102200002E8A9F6617889EA9008B5E2680E33FF684
-:10221000C7047407A810750380CB40F6C70874077D
-:10222000A880750380CB40885E268A86A500F6C309
-:10223000FD740DA806740824F98886A500E60CC371
-:10224000F6C70174040C02EBF0F6C30275E90C0446
-:10225000EBE7C404C4048504590448044104C303DF
-:10226000820341038202570241028201410182003E
-:1022700041004E02AD0157012D002B002700210027
-:102280001600F404F404A3046F045B045104F40383
-:10229000A3035103A3026D025102A3015101A30044
-:1022A00051006202D9016D01380036003100290069
-:1022B0001B005157BF0200EB0F905156BF0100EBBE
-:1022C00007905156BF0300903C197602B017988BC7
-:1022D000F08A82C4002AE48BF083FE187346D1E6AC
-:1022E0002E8B8C5222F74638800074052E8B8C8200
-:1022F00022F7C7020074123B8E9400740C898E94EE
-:10230000008AC5E6EC8AC1E6E4F7C7010074123B17
-:102310008E9600740C898E96008AC5E6F88AC1E60E
-:10232000F05E59C377068B8E8E00EBC58B8E9000C6
-:10233000EBBFD503F6003E0010000400CA043301D1
-:102340004D00140005000103050709000102030404
-:1023500080841E00A02526000000608BF033FF2E35
-:10236000A150232E8B165223BB3223F74638800010
-:10237000740C2EA154232E8B165623BB3C23B90577
-:10238000002E3B31730A4747E2F7B8FFFFEB1D9081
-:10239000D1EF2E8A8D46232AEDD1EAD1D8E2FAF781
-:1023A000F6050200C1E8022E8AA54B232EA358236E
-:1023B000612EA15823C3080020008000000260099C
-:1023C0000800200080000002000800000100020058
-:1023D0000300040052565785C074053D0109760379
-:1023E000B80109BF5B01F7463880007403BFB20132
-:1023F00033F62E3B84B62376044646EBF5F7E72EFC
-:102400008BBCC02303C783D200D1E7F7F72E8AA481
-:10241000CA235F5E5AC3E43E80BEC30003750CF757
-:10242000467A200074050C80E63EC3247FE63EC356
-:1024300024038886C3008AE0E41024FC0AC4E61062
-:10244000808EA10042E8CEFFC390568BF083E60752
-:10245000D1E62EFFA458249068246C2470247424A0
-:102460007824872487248724B400EB0EB4C0EB0AB9
-:10247000B440EB06B420EB02B4A0E410241F0AC45D
-:10248000E610808EA100425EC3903C0277128AE083
-:10249000E41024F3C0E4020AC4E610808EA10042D6
-:1024A000C3908B5E3884C0741F3C02742083CB08B9
-:1024B0008B462E3B463C770CE888FC7207B024E63E
-:1024C0000A83CB10895E38C383E3F7EBF7F7C310B9
-:1024D0000074F5E86DFC72EC8A86C000E638B02323
-:1024E000E60AEBE08B5E388B462E3B463CE4D87721
-:1024F0000B24FE80CB12E6D8895E38C30C0180CB5A
-:1025000002EBF35033DBC1E804250F0F8AD82E8A83
-:102510008766178ADC2E8AA7661709463E58C3507D
-:1025200033DBC1E804250F0F8AD82E8A8766178A05
-:10253000DC2E8AA76617F7D021463E58C38B463E4D
-:1025400033DB8AD80ADC2E8A877617E62C8AE0E409
-:102550002A240F0AC4E62A8A86A50084E4750DA8F9
-:10256000807411247F8886A500E60CC3A8807504BA
-:102570000C80EBF1C31E6033C933D233F68ED98D94
-:10258000BEFD00578B0584C074168BD1428BFE4F65
-:10259000780938A3E40074084F79F788A2E400466C
-:1025A0005F83C7094183F91072D989B6860089967D
-:1025B0008400611FC353C7466600008B4664A94070
-:1025C00000740DB300A980007402B37F889EC1001F
-:1025D00032DBA90200740380CB40A9004074038061
-:1025E000CB02A90080740380CB01A9301E74038044
-:1025F000CBBCA90020740380CB08A904017403801C
-:10260000CB10A90800740380CB20889EC2005BC356
-:102610000651575016078DBEC400B91F0033C0AA1B
-:1026200040E2FC8B86920089868E00898690005855
-:102630005F5907C3E4D8C0E80453250F008BD82E98
-:102640008A8766178886A9005AC30886AC00C686A2
-:10265000BA0001B00EE8EAE9C3AD36A3B413AD3653
-:10266000A3B613AD36A3B81383E90636F706B6133F
-:102670000F00C38A4626F74648800074020C108873
-:1026800086BD0032C0837E1A00750E8B5E4043808B
-:10269000E3FE3B5E0875020C01837E3A00750D1E59
-:1026A000C55E148B1F1F85DB75020C02F7463810C0
-:1026B0000074020C048B5E7AF7C3020074020C08EB
-:1026C000F7C3040074020C10F7C3080074020C2056
-:1026D000F7C3400074020C408886BF00C3906A00B4
-:1026E0001FC60693120D9C0EE8F1EB90B002E6DADD
-:1026F000F8C333C0E6DAF8C3B001E6D8F8C333C094
-:10270000E6D8F8C3B0FFE84EFAE8A1FAF8C3AC493E
-:10271000E8AFFBF8C390AC49E815FDF8C390AC49AD
-:10272000E867FDF8C390AC49E81FFDF8C390AC49D9
-:10273000E634F8C3AC49E636F8C3AC493C02771F2F
-:1027400084C0751DE41424EFE614E412243FE6125D
-:10275000E416A8047409E8EAF97204B018E60AF865
-:10276000C38AE0E4140C10E614E4120CC0F6C401B1
-:102770007402247FE612F8C3AC49E825FDF8C39043
-:10278000B80040E87DFDE8B4FDE8A8FEB001E8B976
-:10279000FEF8C390B80040E885FDE8A0FDF8C390BE
-:1027A000B80010E85DFDE894FDE888FEB008E899FF
-:1027B000FEF8C390B80010E865FDE880FDF8C3900E
-:1027C000B80080E83DFDE874FDE868FEB002E879F5
-:1027D000FEF8C390B80080E845FDE860FDF8C390BE
-:1027E000B80020E81DFDE854FDE848FEB004E859B3
-:1027F000FEF8C390B80020E825FDE840FDF8C3903E
-:10280000AC49E84814E43C24E70AC4E63CF8C39029
-:10281000B8FC3B89467CE43C0C18E63CF8C3E41267
-:102820000C02E612F8C3E41224FDEBF6E8B5FCF85E
-:10283000C390836638FDF8C3AC49A8017406834E83
-:102840007A20EB0483667ADFE8CBFBF8C3908A86B4
-:10285000A5000C0224FB8886A500E60C814E26010B
-:1028600020AC4932E489466E834E48084946F9C394
-:102870008A86A5000C0224FB8886A500E60C814E02
-:10288000260120ACB40AF6E4EBD8E8FA13E43C24C1
-:10289000F80AC4E63CF8C390AD4949894664A901E9
-:1028A00000741B8BD883E3FA751AA90400740FE433
-:1028B0003E0C02E63EB83844894662F8C390E43ED6
-:1028C00024FCEBEFE43E24FCE63EE8E8FCB8AA403A
-:1028D000EBE6E86EF87205B018E60AF8C390AC496A
-:1028E000E8CFF9F8C390AC49E8CFF9F8C390E868AD
-:1028F000FD750632C0E6DAF8C3B002E6DA36A0B4F7
-:102900001324103410E8160136A1B413A901007481
-:1029100005E8FCFEEB0EA90200740432C0EB02B025
-:1029200001E8DEFE36A1B413E8B513E43C24F80A4E
-:10293000C4E63C36A1B413C1E805250100E8FAFE5F
-:1029400036A0B5132410E859FB32C0368A26B513D9
-:10295000F6C4047409FEC0F6C4087402FEC0E8DBC5
-:10296000FD36A1B613250F00E857F936A1B613C1FD
-:10297000E804250300E8B8FA36A1B613C1E8052536
-:102980000200E805FB36A1B613F6C401750432C097
-:10299000EB0980E402D0ECB0022AC4E8ACFA36F6C7
-:1029A00006B713407405E883FEEB03E884FE36F6B1
-:1029B00006B713207405E865FEEB03E868FEF8C36C
-:1029C000E4120C01E612F8C3E41224FEEBF6E41460
-:1029D00024F00C05E614E42A24F00C06E62AF8C3D9
-:1029E000E42A24F0E62AE41424F00C07E614F8C3E1
-:1029F000AD4949E864F989868E00F8C3AD4949E8D4
-:102A000058F989869000F8C3834E2604E8A8F7F8A1
-:102A1000C390836626FBE89EF7F8C390AC4984C058
-:102A2000750DE41024EFE610808EA10042F8C3E497
-:102A3000100C10EBF190AC493C02760232C0C0E0C1
-:102A400004A82074020C0824188AE0E41224E70A7F
-:102A5000C4E612808EA10044F8C3AC498886C00049
-:102A6000F8C3AC49E63AF8C3AC4984C07408E41230
-:102A70000C04E612F8C3E41224FBEBF6AC49E8D6EA
-:102A8000F67303E827F7F8C3E412A802740424FDE0
-:102A9000E612B8F000E887FA816626FFF3E857F7F8
-:102AA000E89AFAF8C390B88000E857FA804E2708F1
-:102AB000E844F7E887FAF8C3B88000E861FA81666D
-:102AC00026FFF7E831F7E874FAF8C390B81000E889
-:102AD00031FA804E2704E81EF7E861FAF8C3B8100F
-:102AE00000E83BFA816626FFFBE80BF7E84EFAF8B0
-:102AF000C39033C0AC493C017304B001EB063C0CFD
-:102B00007602B00C89461CF8C390814E2600208ABC
-:102B100086A5000C0224FB8886A500E60C834E26C1
-:102B200001F8C390814E2600408A86A5000C0288D9
-:102B300086A500E60CF8C390AC4950E805F658723B
-:102B400008E638B023E60AF8C3F9C390AC50ADE804
-:102B500082F85AF6C201741239869600740C89867E
-:102B60009600E6F086E0E6F886E0F6C202741039D8
-:102B7000869400740A89869400E6E486E0E6EC8395
-:102B8000E903C390E4168886BC00E8E6FA33DBE488
-:102B90000CA806740380CB01A810740380CB02A894
-:102BA00080740380CB04E4128AE024180AD8E4DAA3
-:102BB000F6C4027407A840750380CB20A8027509EB
-:102BC000E42AA80F740380CB40F74638020074094A
-:102BD000E4D8A801750380CB80889EBE00FE86B431
-:102BE00000B00AE85CE4F8C3AC493C027441771FCA
-:102BF00050E84FF558720C84C0740AB012E60A808F
-:102C00004E3801F8C3B011E60A806638FEF8C38B6F
-:102C1000463825FFF7894638A9000475E68A86A557
-:102C200000A81075DE0C108886A500E60CF8C3819C
-:102C30004E3800088A86A500A81074C724EFEBE779
-:102C4000AD49493C0172113C0C770D508AE0E41407
-:102C500025F00F0AC4E614588AC484C07402E64200
-:102C6000F8C3E8CFF9FE86B900B00EE8D4E3F8C3A4
-:102C70003A86AF00741F8886AF008AE080C206B033
-:102C8000BFEE80EA028AC4EE8A86A80080C202EE05
-:102C900080EA068AC4C38B463E85C08A86A5007436
-:102CA00012A808750D0C088886A50080C202EE8067
-:102CB000EA02C3A80874FB24F7EBEC8B462684C019
-:102CC00074168A86A500A802740D24FD8886A500C6
-:102CD00083C202EE83EA02C38A86A500A80275F7C2
-:102CE0000C02EBE85283C20CECC0E8048886A90011
-:102CF0008B5E2680E33FF6C7047407A8087503803F
-:102D0000CB40F6C7087407A802750380CB80885EA5
-:102D1000268A86A50084DB7410A802740A24FD8824
-:102D200086A50083EA0AEE5AC3A80275FA0C02EBE4
-:102D3000EE90FFFF00480030BA20C41A00180012BD
-:102D4000000C0006000300028001C000600030009B
-:102D50001800CD0100018000100010000E000C00D2
-:102D6000080000000000060004000300020001004B
-:102D70005251563C1E7747988BF08A82C40032E449
-:102D800083FE18743D83FE19743E83FE1E772FD197
-:102D9000E62E8B8C322D3B8E94007422898E94000B
-:102DA00083C2068A86A8008AE00C80EE83EA068A3F
-:102DB000C1EE83C2028AC5EE83C2048AC4EE5E59A4
-:102DC0005AC38B8E8E00EBCE8B8E9000EBC8525187
-:102DD0003D05007703B805008BC8BA0200B800D0E3
-:102DE000F7F1050100D1E8595AC38B467AA820743F
-:102DF0000B80BEC3000375040C01EB0224FE894660
-:102E00007AC324038886C3008AA6A8008ADC80E4EB
-:102E1000FC0AC43AC3740B8886A80083C206EE83FA
-:102E2000EA06E8C5FFC30008183828903C04772359
-:102E300032E48BD82E8A87262E8AA6A8008ADC80C8
-:102E4000E4C70AC43AC3740B8886A80083C206EE9E
-:102E500083EA06C384C07402B0048AA6A8008ADC90
-:102E600080E4FB0AC43AC3740B8886A80083C206B8
-:102E7000EE83EA06C3908B5E3884C074343C0274DF
-:102E80003B8A86AF000C04E8E6FD8B462E3B463CB1
-:102E9000771BF7C30004751581CB000483C2028A37
-:102EA00086A50024FA8886A500EE83EA02895E38AA
-:102EB000C38A86AF0024FBE8B6FDEBF1F7C3100030
-:102EC00074EFEBED83C20CEC83EA0CC0E804888657
-:102ED000A900C3908A86A7000C018886A7008BDA18
-:102EE00080C208EE8BD3F8C38A86A70024FEEBEAE3
-:102EF0008A86A7000C02EBE28A86A70024FDEBDAA3
-:102F0000B0FFE852F2E897F2F8C3AC49E861FEF886
-:102F1000C390AC49E8EBFEF8C390AC49E835FFF844
-:102F2000C390AC49E805FFF8C3905283C206B0BF16
-:102F3000EE5283C202AC49EE5A8A86A800EE5AF8D5
-:102F4000C3905283C206B0BFEE5283C206EBE69036
-:102F5000AC493C02770D84C0750B8A86AF0024FD16
-:102F6000E80DFDF8C3508A86AF000C02E801FD5B56
-:102F700083C2088A86A700F6C301740C24DF888602
-:102F8000A700EE83EA08F8C30C20EBF2AC49E8E5B1
-:102F9000FEF8C390B80040E869F5E8F9FCE824FFC2
-:102FA000B001E8A5F6F8C390B80040E871F5E8E58F
-:102FB000FCF8C390B80010E849F5E8D9FCE804FF34
-:102FC000B008E885F6F8C390B80010E851F5E8C5F8
-:102FD000FCF8C390B80080E829F5E8B9FCE8E4FE05
-:102FE000B002E865F6F8C390B80080E831F5E8A5CE
-:102FF000FCF8C390B80020E809F5E899FCE8C4FEA5
-:10300000B004E845F6F8C390B80020E811F5E8856B
-:10301000FCF8C390AC49E8340CF8C390B8FC3B8989
-:10302000467CF8C38A86AF000C80E843FCF8C39066
-:103030008A86AF00247FEBF28A86AF000C40E82F2F
-:10304000FCF8C3908A86AF0024BFEBF2AC49A8011C
-:103050007407834E7A20EB059083667ADFE88AFD59
-:10306000F8C383C2068A86A8000C408886A800EEB2
-:1030700083EA06AC4932E489466E834E2601834ECC
-:103080004808B006E8BBDF4946F9C39083C2068A08
-:1030900086A8000C408886A800EE83EA06ACB40A35
-:1030A000F6E4EBD0E8E00BF8C390AD4949894664FB
-:1030B000A9010074198BD883E3FA750AA904007476
-:1030C0000DB8E23FEB0BE8ECF4B8AA40EB03B838DC
-:1030D00044894662F8C38A86AF00A802740A24FDB8
-:1030E000E88DFB0C02E888FBF8C3AC49E881FCF8EA
-:1030F000C390AC49E879FCF8C390E85CF57505E845
-:10310000E6FDF8C3E8CDFD36A0B41324103410E872
-:10311000260136A1B413A901007405E8FEFEEB0EEA
-:10312000A90200740432C0EB02B001E8E8FE36A147
-:10313000B413E8AB0B36A1B413C1E805250100E8D0
-:103140000CFF36A0B5132410E82BFD32C0368A26BA
-:10315000B513F6C4047409FEC0F6C4087402FEC0B8
-:10316000E8EFFD36A1B613250F00E803FC36A1B643
-:1031700013C1E804250300E888FC36A1B613C1E8B2
-:1031800005250200E8CDFC36A1B613F6C40175048E
-:1031900032C0EB0980E402D0ECB0022AC4E88CFC17
-:1031A00036F606B713407405E88DFEEB03E894FE8F
-:1031B00036F606B713207405E869FEEB03E870FEE7
-:1031C000F8C3F8C38B4638A9040075230D040089A1
-:1031D000463883C2088B462E3B463C7314834E38D8
-:1031E000108A86A70024FE8886A700EE83EA08F8E6
-:1031F000C38A86A7000C01EBEE908B4638A9040029
-:10320000740625FBFF894638F8C3AD4949E8BEFB83
-:1032100089868E00F8C3AD4949E8B2FB89869000E3
-:10322000F8C3834E2604E892FAF8C390836626FB1F
-:10323000E888FAF8C390AC4984C07507808EA30073
-:1032400004F8C380A6A300FBF8C3AC4983C2083CC2
-:1032500002760232C03C017412770B8A86A70024E2
-:10326000EF8886A700EE83EA08F8C38A86A7000CD9
-:1032700010EBEE905283C206B0BFEE5283C204AC94
-:1032800049EE5A8A86A800EE5AF8C3905283C206C5
-:10329000B0BFEE5283C208EBE690AC49F8C3AC492C
-:1032A000E8B4EE7303E8F7EEF8C38A86AF00247F34
-:1032B000E8BDF9B8F000E866F2816626FFF3E8237E
-:1032C000FAE8D2F9F8C3B88000E837F2804E270850
-:1032D000E811FAE8C0F9F8C3B88000E841F2816665
-:1032E00026FFF7E8FEF9E8ADF9F8C390B81000E85A
-:1032F00011F2804E2704E8EBF9E89AF9F8C3B81008
-:1033000000E8FFF1816626FFFBE8D8F9F8C3AC4975
-:10331000F8C383C2068A86A8000C408886A800EEFF
-:1033200083EA06F8C39083C2068A86A80024BFEB0E
-:10333000EA90AC498AE080C20AEC80EA0AA82074CC
-:10334000058AC4EEF8C30651578B4E24E3344989ED
-:103350004E24FF461A8E46028B7E228AC4AA897E9C
-:10336000228B462624FD89462675298A86A500A833
-:1033700002752180C2020C028886A500EE80EA0256
-:10338000EB12C47E003B7E1E760A4F268825897E7E
-:1033900000FF461A5F5907F8C390ACAD83E9038577
-:1033A000C074053D00207205B8FFFFEB03C1E003C8
-:1033B0003B8694007426898694008BD85283C2067B
-:1033C0008A86A8008AE00C80EE83EA068AC3EE8330
-:1033D000C2028AC7EE83C2048AC4EE5AF8C3B08818
-:1033E0008886BC00E88CF233DB8A86A500A80274CC
-:1033F0000380CB01A805740380CB02A80874038066
-:10340000CB04F686A70010740380CB108A86A9002F
-:10341000F6C304750A83C20CEC83EA0CC0E8048A84
-:10342000E08A86AF00A8807408F6C401750380CBDB
-:1034300020F686A70002750AF74638040074038058
-:10344000CB40889EBE00FE86B400B00AE8F3DBF8ED
-:10345000C3FE86B400B00AE8E8DBF8C3AC493C021E
-:103460007437771084C07406804E3801F8C38066C4
-:1034700038FEF8C38B463825FFF7894638A9000483
-:1034800075EA8A86A500A80175E20C0583C2028848
-:1034900086A500EE83EA02F8C3814E3800088A86CA
-:1034A000A500A80174C624FAEBE2AD4949F8C3901F
-:1034B000E811FAFE86B900B00EE886DBF8C3B0FF6B
-:1034C000E8BFECF8C39083667AFBB000E873DBF8E2
-:1034D000C390AC49E853D9721136881E1A0136A040
-:1034E0008E120AC352BA0001EE5AF8C3AC4932E454
-:1034F00036A38612050600368B1E88122BD8368915
-:103500001E8A12F8C390AD8BD8AD83E90403C32B98
-:103510004676894678F7467A0200740A83667AFD11
-:10352000B80000E81CDBF8C3061607AC49250F00FD
-:103530006BC0098DBEFD0003F8AC49250F00AA85BC
-:10354000C074082BC8518BC8F3A459E827F0E8448D
-:103550000307F8C333C0AC4936A3B21336A3B01384
-:10356000F8C383667AEFE82C03F8C390834E7A1091
-:10357000EBF4E89BF0F8C390AD3C19770E3C19775B
-:103580000A8BF881E7FF0088A6C400F8C390834E39
-:103590002620AC4932E4D1E08BD8C1E30203C389D1
-:1035A000466E834E4804B006E897DA4946F9C39060
-:1035B000FE86B300B00AE889DAF8C39033C0AC499C
-:1035C0006BC00A89868A00F8C390AC4932E43D0A90
-:1035D000007705B80A00EB083D5A007203B85A009C
-:1035E00051F7D80564008BC88B4644F7E1B96400F5
-:1035F000F7F189464659F8C3AC49E885EBF8C39022
-:10360000AC4984C07507816638FFFDF8C3814E3828
-:103610000002F74638400075088A86A9008886AA05
-:1036200000F8C3905156E87F0C5E59F8C390FE86AF
-:10363000B600B00AE80BDAF8C390FE86B700B00A0D
-:10364000E8FFD9F8C390FE86B800B00AE8F3D9F8CD
-:10365000C39000905155AC2EA2523633C9AD8BF9B0
-:10366000C1E705A9010074232E8BAD4400837E08B9
-:103670000074182E803E523601740960B004E8BB15
-:103680000C61EB0760B0FBE8EC0C614747D1E875D3
-:10369000D24183F90472C65D5983E905F746384083
-:1036A000007405E887EAF8C3E88DEAF8C39036C6E7
-:1036B00006C81301F8C333C0AC4936A38012AC4925
-:1036C000362B068812F7D836A38212F8C390DE266E
-:1036D000DE26EC26F226F826FE2604270E271627DD
-:1036E0001E2726272E273427BE34C634D2343A2745
-:1036F000782780279427A027B427C027D427E0273E
-:10370000F42700281028EC34DE261E2826282C2832
-:10371000322838284E288A28063528359828BE2889
-:10372000D228DE28E628543562356C35EE28C029CB
-:10373000C829CE29E02972357835F029FC298E3543
-:10374000082A122A1C2AB035362ABC355A2A622A7F
-:10375000682ACA357C2AF835882AA62AB82ACC2AAB
-:10376000DE2AF22A00360A2B242B2436382B4C2B47
-:10377000842B2E363A3646365436E82BAE36402C5D
-:10378000622CB6367028DE26DE26D42EE82EF02EE9
-:10379000F82E002F0A2F122F1A2F222F2A2F422FF6
-:1037A000BE34C634D234502F8C2F942FA82FB42F70
-:1037B000C82FD42FE82FF42F083014301C30EC34ED
-:1037C000DE2624303030383044304C306230A43083
-:1037D00006352835AA30CE30D630EA30F2305435AE
-:1037E00062356C35FA30C231C231C431FA317235CA
-:1037F00078350A3216328E3522322C323632B035D6
-:103800004A32BC3574328C329A32CA359E32F8351F
-:10381000AA32C632D832EC32FE320E3300361233C0
-:103820002633243632339A33DE332E363A36463652
-:1038300054365C34AE36AA34B034B6368C30E32815
-:10384000F7463840007532E8E3E833C0AC493D5BE9
-:103850000077198BD8D1E32EFF97CE36720B85C92E
-:1038600075E88B4648E81A0CC34E41C36A001FC670
-:103870000693120C9C0EE863DAE8BCE833C0AC494E
-:103880003D5B0077E78BD8D1E32EFF97863772D95F
-:1038900085C975E8C3F7467A1000750F83BE8400AA
-:1038A000007408B8483A89868000C381BE8000EC65
-:1038B0003C74F783BE8800007505B8EC3CEBE7F775
-:1038C000467A080075401E608B8E88003B4E7477E8
-:1038D000333B4E78772EC47E108BDF26033D47475F
-:1038E00033C08ED88DB6F4008BC1F7467A010075CF
-:1038F0001DF3A4260107294678014676294674B0AF
-:103900000CE83ED7611FC78688000000EBACE3E3FC
-:103910005090AC247FAAE2FA58EBD8908B8E8800A6
-:10392000E3468B9E8A0085DB743EBA50FFED2B8602
-:1039300082003BC372378DB6F400C47E108BDF2645
-:10394000033D47478BC1161FF7467A01007524F3E4
-:10395000A4260107294678014676294674C7868839
-:10396000000000B00CE8DAD683667AF7C3B000E84E
-:10397000D0D6C3E3DC50AC247FAAE2FA58EBD29055
-:103980001E6033C08ED88DB6FD008B8688008B9666
-:1039900084003A0475108BDE468BC88DBEF400F3AC
-:1039A000A674668BF39083C6094A75E68DB6FD0052
-:1039B0008B9684003A0473108BDE468BC88DBEF460
-:1039C00000F3A674768BF39083C6094A75E68DB62C
-:1039D000F400ACF7467A01007402247F1EC55E1025
-:1039E0008B37884002468937FF4E78FF4676FF4E78
-:1039F000741F8B8E880049898E8800E3438DB6F44E
-:103A0000008BFE46F3A4E97DFFC576108B1C85DB99
-:103A1000740803F383C60383E6FE8B8684002BC2FF
-:103A2000B48089044646C7040000897610834E7A24
-:103A300004C78688000000611FF9C333C0611FC33B
-:103A4000B08084C0611FC3908B4E782B8E88007627
-:103A50002789B68C008B5E743BCB72028BCB3BC844
-:103A600072028BC88BC1E34433D28EC28BD183BE2A
-:103A70008800007406E98E0033C0C38B5E10031FFC
-:103A8000434352F7467A0100752AAC8DBEE4008BA1
-:103A90008E8600F2AE74348807434A75ED588B5E0B
-:103AA0001001072946780146762946748BC62B8675
-:103AB0008C00C390AC8DBEE4008B8E8600F2AE7499
-:103AC0000A247F8807434A75EBEBD28886F400C747
-:103AD0008688000100582BC2740E8B5E10010729E6
-:103AE000467801467629467440E894FE72BE4A75CF
-:103AF0001583BE8A000074B4BA50FFED8986820037
-:103B0000834E7A08EBA68DBEF40003BE8800A4FFA6
-:103B1000868800E86AFE729479064A748FE95BFF32
-:103B20004A74CEEBE19050E811CC8B467439467262
-:103B300074271E565133C9C5760CAD74107809032D
-:103B4000C805010024FE03F03B761076ED294E7681
-:103B5000014E78E837CC595E1F58C390C47E1026BA
-:103B60008B1D83C30326891D4B03FBAB91AAB803AE
-:103B700000294678014676294674C390C47E1026F3
-:103B80008B1D4326891D4303FBAAFF4E78FF467613
-:103B9000FF4E74C3E8E5FFC38081848582838687F6
-:103BA00050538ADC83E30ED1EB2E8A87983B08863C
-:103BB000B000FE86B100B00AE887D45B58C3508AD3
-:103BC000C8B8FF00E895FF58C3908A86BB00E8ABF1
-:103BD000FFC3E8CBFFE8F2FFC390E8C3FFE8B4FF00
-:103BE000C39033C0E895FFC3B8FF0033C9E86CFF4A
-:103BF000C390B8FF01B110E862FFC390C3FC3BE281
-:103C00003BF23BF23BFC3BE23BE83BE83BFC3BE26C
-:103C10003BE83BE83BFC3BE23BE23BE23B00100085
-:103C20000000100000001000000010000000100054
-:103C3000000010000000100000001000000008004C
-:103C40000000080000000800000008000051538B2D
-:103C50004E3881E1FFEEA804740481C900018AE0B6
-:103C600080E4032418D0E40AC433DB8AD82E8B877F
-:103C7000FD3B89467C2E0B8F1D3C894E38D1EB2EA7
-:103C80008AA73D3C5B59C3AC493C01721D74203C82
-:103C900003722374283C08722B74303C20723774F2
-:103CA0003ABBDA3B32E4895E7EC3BBA03BEBF5BB9B
-:103CB000943BB401EBF0BBFC3BB402EBE9BBE23B51
-:103CC000B403EBE2BBBE3BB404EBDBBBCA3BAC4989
-:103CD0008886BB00EBCEBBD23BEBF3BBFC3BEBC41B
-:103CE000A9040075D1A9080075DAEBD18B5E748B3D
-:103CF0004E783BCB72028BCB3BC872028BC88BC118
-:103D0000E32CC47E108BDF26033D4747F7467A013C
-:103D100000751CF7C70100740249A4D1E9F3A5732B
-:103D200001A4260107294678014676294674C35026
-:103D300053BB7F7FF7C70100740549AC22C3AAD1EA
-:103D4000E9E31D9CAD23C3AB497414AD23C3AB4958
-:103D5000740DAD23C3AB497406AD23C3ABE2E59D3F
-:103D60007304AC22C3AB5B58EBB8E8CEC98B5E38AA
-:103D7000F7C310047501C3F7C340007405E8B8E346
-:103D8000EB03E8A8E3816638EFFBF6C310743CF65A
-:103D9000C3027406E4D80C01E6D8F6C30474118398
-:103DA000C2088A86A7000C01EE8886A70083EA086D
-:103DB000F6C308740FE88BE3720A8A86C000E638FF
-:103DC000B023E60AF7C300047501C3F7C300087502
-:103DD000F98A86A500F6C340750DA81075EC0C1085
-:103DE0008886A500E60CC3A80175DF83C2020C0516
-:103DF000EE8886A500C3B000E847D2EB0FB002E81A
-:103E0000900EEB08836638DF834E7A0233C08ED87B
-:103E1000FAA0921240A292123C05721EC60692129D
-:103E200000FBB001E86B0EFAA1260123062A01A8C7
-:103E3000017507E8E207E8610990B000E837D2FBB6
-:103E400085ED74B9FAF7467A460075C08B46783D21
-:103E50000A0072B08B4E7483F950729A836638DF11
-:103E6000C576148B463A85C07558AD85C0750FE888
-:103E7000F8FEF7467A08007493E8A0FAEB8E3B76DA
-:103E8000047621B90200394E2E7705C7462E000070
-:103E9000568B762C897604C7040000464689762C1A
-:103EA000294E2E5E85C07917F6C4107405FF567C26
-:103EB000EB03FF567E897614B00CE885D1EB86893A
-:103EC000463AFF96800029463A897614B00CE8718C
-:103ED000D1E971FF0000000000000000080410029A
-:103EE00001200000000000000000000000000000B1
-:103EF00000000000808080808080808080808080C2
-:103F000080808080808080808080808080808080B1
-:103F100080808080808080808080808080808080A1
-:103F20008080808080808080808080808080808091
-:103F30008080808080C0C0C0C0C0C0C0C0C0C0C0C1
-:103F4000C0C0C0C0C0C0C0C0C0C0C0C0C0C0C080B1
-:103F500080808000808080808080808080808080E1
-:103F60008080808080808080808080808080808051
-:103F70008080808080808080808080808080808041
-:103F80008080808080808080808080808080808031
-:103F90008080808080808080808080808080808021
-:103FA0008080808080808080808080808080808011
-:103FB0008080808080808080808080808080808001
-:103FC00080808080808080808080808080808080F1
-:103FD000808080804E417841D041F44106421842B1
-:103FE000C3908E46028B7E22897E6C806627FD8B75
-:103FF000562483FA0472E983EA028BD93BCA76021B
-:104000008BCAB00A57518BFEF2AE8BC1595F751E39
-:1040100050402BC874062BD12BD9F3A4594B4A4AD4
-:10402000B00DAAA43BCA76028BCAE313EBD42BD9FA
-:10403000F7C601007402A449D1E9F3A57301A4896C
-:104040007E222B7E6C297E24017E1A8BCB807E26DD
-:10405000027405806626FDC360B0FDE8180361C3E5
-:10406000C390E87C0272F990834E26208B466A89C1
-:10407000466E8B46480D040025BFFF894648B006B2
-:10408000E8BFCFC3897E222B7E6C017E1A297E2455
-:10409000807E26027405836626FDC360B0FDE8D5E8
-:1040A0000261C3908ABEC200EB24F7464840007507
-:1040B000B18E46028B7E22897E6C8B562483EA0A5F
-:1040C000789E03D7806627FD33C08ABEC200E3B462
-:1040D0003BFA77B0AC49932E8A87D43E9322DF75A2
-:1040E00017AAE3A03BFA779CAC49932E8A87D43E6B
-:1040F0009322DF7503AAEBD6F6C37F7505FF4666EC
-:10410000EBDFF6C340750C8BD883EB08D1E32EFFB1
-:10411000A7D43FFF46662C20EBC785C0742C894688
-:104120006A834E4840897E222B7E6C017E1A297E4E
-:1041300024807E26027408836626FDE8A301C360FE
-:10414000B0FDE8310261E89801C3E957FF908B5E4A
-:10415000664B7803895E66AA8B5E64F7C3002075A0
-:1041600003E940FFF7C3400074088A86C100AAE94A
-:1041700032FFB83200EBA3908B5E66895E6883C322
-:104180000880E3F8895E668B5E6481E3001881FB3A
-:104190000018742DAA85DB7425F746644000751855
-:1041A00081FB0010740C8B46662B4668C1E004E965
-:1041B00068FFB86400E962FF8A86C100AAAAE9E341
-:1041C000FE518B4E662B4E68B020F3AA59E9D4FEFF
-:1041D0008B5E66895E688B5E64F7C324007410C7CB
-:1041E00046660000F7C304007405B00DAAB00AAA21
-:1041F000EB489090AAF7466400407406B8D007E9EF
-:1042000018FFE99FFE90AAF7466400807406B8D0B4
-:1042100007E906FFE98DFE908B5E66895E6885DBA7
-:10422000750C8B5E64F7C310007406E976FE8B5E36
-:1042300064F7C308007427B00AAAF7C32000751FEB
-:10424000F7C300017503E95BFEF7C340007506B8CC
-:104250006400E9C5FE8A86C100AAAAE946FEAAC78B
-:1042600046660000F7C3000674F1F7C340007419F6
-:104270008A86C10081E3000681FB00047206760293
-:10428000AAAAAAAAAAAAE91BFE81E3000681FB004A
-:1042900004720E7606B89600E97FFEB86400E979EC
-:1042A000FE8B4668E973FE90368B0EDA1283F93284
-:1042B000731D1E0633C08ED88EC08D764CBFDC12A7
-:1042C00003F9A5A5A583C106890EDA12071FC3B09D
-:1042D00008E86ECDC390836648FEE893C4E8C8FF43
-:1042E000C3F6462702750F9CFA837E1A0074098074
-:1042F0004E27019DF9C3F8C35052F7463840007469
-:104300001DE834DE83C20AECA840752783EA088AD8
-:1043100086A5000C028886A500EE5A58EBD1E80C61
-:10432000DE8A86A50024FB0C028886A500E60C5ACE
-:1043300058EBBC804E27025A589DF8C30846269C6D
-:10434000FA8A8EA500F7463840007514F6C1067447
-:1043500023E8D9DD8AC124F98886A500E60C9DC32F
-:10436000F6C102740FE8D0DD83C2028AC124FD8841
-:1043700086A500EE9DC38B5E2622C3884626740167
-:10438000C3806627FD9CFA8A8EA500F74638400058
-:104390007516F6C104750FE893DD8AC124FD0C047F
-:1043A0008886A500E60C9DC3F6C10275F9E888DD94
-:1043B00083C20AECA820750E83EA088AC10C028821
-:1043C00086A500EE9DC383EA0A33C98A4E1C8B463C
-:1043D0001A3BC8731B014E2A2BC189461A1EC5768B
-:1043E00000F36E1F89760083C2028A86A500EBCD9A
-:1043F00085C0741201462A8BC81EC57600F36E1F55
-:10440000897600894E1AF6C701752380CB02895E32
-:1044100026E808C383C2028A86A50024FDEE8886AA
-:10442000A500F6C7107505B002E816CC9DC383C27F
-:10443000028A86A500EB86908BD18B46243BC876FA
-:10444000028BC82BD12BC18BD9E322806627FD8E2E
-:1044500046028B7E22F7C601007402A449D1E9F31B
-:10446000A57301A4897E22894624015E1A8BCA8025
-:104470007E26027405806626FDC360B0FDE8F6FE68
-:1044800061C350E40A84C0750A8686A10084C074A2
-:104490000AE60A580C20894648F9C35824DF8946A1
-:1044A00048F8C390FBB002E8E807FAE82E01FBB039
-:1044B00001E8DE07FAB002E8BCCBFB85ED74E5FA53
-:1044C0008E5E0AFB90FA8B46488B7640A88C75DE90
-:1044D000A820741A50E855DC58E8A6FF7310B00203
-:1044E000E85FCBEBC99025FF008BC8EB3690A801A5
-:1044F00075224683E6FE3B76087479AD8AFCB3F0FC
-:1045000022FB3AFB74E03ABEA000742EE8D2FD73A1
-:1045100077EB9B908AE024FC8846488B4E4AF6C491
-:1045200002741DE8BBFD7286E813F3897640E393BD
-:10453000834E4803894E4AE974FF25FF0F8BC890CC
-:104540008B86980085C0741A518A8EA000C0E90439
-:10455000BA0100D3E25923C2740803F1897640E915
-:1045600061FFFF5662E3F5834E4801894E4A897622
-:1045700040E93AFF814E2600108B46503B46467775
-:1045800003E852FDE927FF9088BEA000EBAC0A06C5
-:1045900090128AE0BA0601B004EEEC84C07512B045
-:1045A00004EE8AC4EE32E4A8807406C706841200C2
-:1045B0000088269012C30A0690128AE0BA0601EC1F
-:1045C000A80175EDBA08018AC4EE32E4A88074E14E
-:1045D000C7068412000088269012C39036F706247E
-:1045E0000101007530368B0EDA1280F936732633EE
-:1045F000C08EC08ED8BFDC1203F9B008E877CA8538
-:10460000ED740E8D764CA5A5A580C10680F9367295
-:10461000E9890EDA12C3C390F7062601010075F688
-:104620008B0E201385C975EE33C08EC08ED8BF2483
-:1046300013B93600B00AE83DCA85ED7506E91201E6
-:10464000E90A0133DB8A464C8AA6B300FECC780E19
-:1046500088A6B3000ADCB40AAB83E90276E28AA634
-:10466000B200FECC780E88A6B2000ADCB408AB8398
-:10467000E90276CC8AA6B100FECC78188ABEB000DA
-:10468000750488A6B00088A6B1000ADC8AE7AB836F
-:10469000E90276AC8AA6B400FECC781F88A6B400E6
-:1046A0000ADCB40BAB8A86BC008AA6BD00AB8B8645
-:1046B000BE00AB83E90676888A464C8AA6B600FE21
-:1046C000CC781988A6B6000ADCB40CABE8DBCBAB1F
-:1046D0008B462AAB83E90676748A464C8AA6B700D5
-:1046E000FECC781988A6B7000ADCB40DABE8BACBCB
-:1046F000AB8B4634AB83E90676538A464C8AA6B820
-:1047000000FECC781988A6B8000ADCB40EABA15024
-:1047100012ABA15212AB83E90676328A464C8AA6C6
-:10472000B500FECC781888A6B5000ADCB40FAB8BB8
-:10473000869A00AB8B869C00AB83E906760F84DB00
-:104740007503E9EFFEB00AE8F8C8E9E7FEB00AE849
-:10475000F0C8F7D983C1368BC10D800086C4A3226F
-:10476000134141890E2013C3A184122BC17211A3DE
-:104770008412BE2213D1E9F36F90890E2013F8C37F
-:10478000F9C3C381EF6A1374F98BC70D800086C427
-:10479000A368134747893E6613C3F7062A01010041
-:1047A00075E08B0E6613E30780F92077D54949330E
-:1047B000C08EC08ED8BF6A138BF703F983C6343B13
-:1047C000FE77C0B00EE8AEC885ED74B78A464C8A55
-:1047D000B6B900FECE781588B6B9008AA6A90080C1
-:1047E000CCC0AB84F67405B00EE856C88AB6BA00E1
-:1047F000FECE78CB8A9EA9008ABEAB008A563F8A3D
-:10480000F332F70AB6AC00C686AC000022F2744B55
-:10481000F6C608740FB402F6C3087502B403AB8081
-:10482000E6F77437F6C601740FB400F6C3017502DB
-:10483000B401AB80E6FE7423F6C602740FB404F62E
-:10484000C3027502B405AB80E6FD740FF6C60474AE
-:104850000AB406F6C3047502B407ABC686BA0000F4
-:10486000889EAB00E958FF90A184122BC17211A35E
-:104870008412BE6813D1E9F36F90890E6613F8C3F2
-:10488000F9C3A1841241412BC17223A384128BC1AD
-:10489000484832E40C8086C4EF9090909090BEDC43
-:1048A000124949D1E9F36F90890EDA12F8C3F9C3BE
-:1048B0008AC88A464CB40183EB06EF9090909090A2
-:1048C000B80100EF90909090908AC1EF90909090F6
-:1048D00090E99700E9AC0033C08ED8891E8412C3DA
-:1048E000368B1E8412FB90FAB00CE889C785ED74F4
-:1048F000E6C5760C83FB1472DBFB90FAAD85C078BD
-:10490000AF74E28BFE03F8368B0E86123BC1770242
-:104910008BC883EB043BD977028BCB33C08A464CE0
-:10492000EF90909090908BC1EF90909090904180FC
-:10493000E1FE2BD951D1E9F36F90598BC74024FE8A
-:104940003BC674272BFE4E4E538B5E103BF3721307
-:10495000031F83C30380E3FEC7070000836E740256
-:10496000895E105B893C89760CEB8989760C3976F7
-:104970001077817208833C007403E977FFE80DBE6D
-:10498000E962FF36891E8412B00CE8B5C633C08ECA
-:10499000D8C3A184123D10007277BA04013B068887
-:1049A000127506C7067E1200008B0EDA12E30BE8C2
-:1049B000D0FE7257C7067E12FF7F8B0E2013E30BCB
-:1049C000E8A5FD7246C7067E12FF7F8B0E6613E3D5
-:1049D0000BE894FE7235C7067E12FF7FA12801A95D
-:1049E00001007503E8F9FE803E8D1200751DA1845B
-:1049F000123D200076153B0682127609A17E123BFD
-:104A0000068012720C800E901280C3B080FF167C5C
-:104A100012C3800E901240C36A001FC6069312177D
-:104A20009C0EE8B7C86A001FC6069312209C0EE8C9
-:104A3000AAC86A001FC6069312169C0EE89DC8906D
-:104A4000BA0601ECA82075CAFB90FABA0401ED90F1
-:104A5000909090903A06941277BE33DB8AD8D1E3D7
-:104A60002E8BAF4400C47E0885FF74B9F6C4C075B0
-:104A70005532C0C1E00280E4F08BF0ED9090909050
-:104A80009085C074BB8BC84180E1FE0BC68B5E5025
-:104A90004B4B2BD9789CAB8BC1404001464ED1E9A2
-:104AA000F36D90895E50897E088B462680E4EF89FD
-:104AB0004626F6C401750CF746480C007505B00291
-:104AC000E87FC5E97AFF86C48BC883E13F4180E176
-:104AD000FEE30A3C807209243FB4F0EBB0E960FFCA
-:104AE000253F0033FF8EC7BF96128BF7D1E9F36DD8
-:104AF000908BC8E848EDE947FF906A001FC606930F
-:104B0000121B9C0EE8D5C790601E0633C08ED88E4F
-:104B1000C0BA0601ECA80474E1B006EEECA28C1257
-:104B2000A8407411A18812A38412C6068D1200E851
-:104B300060FEA08C12A8807403E804FFB80080BA5D
-:104B400022FFEF071F61CF906A001FC60693121B5A
-:104B50009C0EE887C790601E0633C08ED88EC0BA00
-:104B60000601ECA80474E1BA0801ECA28C12A8407A
-:104B70007411A18812A38412C6068D1200E812FED9
-:104B8000A08C12A8807403E8B6FEB80080BA22FF99
-:104B9000EF071F61CF90EE86E0EE86E0EC86E0EC5A
-:104BA00086E080E1FEF36C9080E1FEF36E900500FC
-:104BB0007547A84B05007548A84B0500A348A84BAE
-:104BC00005003549A84B06009848964B0600BA48A0
-:104BD000964B0600C348964B0600CB48964B060002
-:104BE0002049964B06002849964B06004E4A9C4B9E
-:104BF00006007B4A9C4B05009E4AA24B0500EC4AEE
-:104C0000A24B00001E06833E4412007409A0060158
-:104C100024303C30741A8CC88ED88EC0BBAE4B8BFF
-:104C20000FE30D8B7F028B7704F3A483C306EBEFB6
-:104C3000071FC39033C0A33E01B90C01BE40018BD6
-:104C4000FE81C6B40F89048BC62BF13BC777F6A350
-:104C50003C01C3901E0660368B2E3E018B5E003BEE
-:104C6000EB742B8B7602891C89770236A13C018973
-:104C7000460036892E3C018BEBFF4E0674088B6E86
-:104C800000FF4E0675F836892E3E018B66046107DB
-:104C90001FC31E0660368B2E3E0198894606896624
-:104CA000043B6E0074108B6E00FF4E0675F836895B
-:104CB0002E3E018B660461071FC3C3901E06609CD5
-:104CC000FA33ED8EDD8B2E3C0185ED743D8B4E006D
-:104CD000890E3C018BCC8DA60A01561E06608966A2
-:104CE00004C746080F1AC7460601008B1E3E018501
-:104CF000DB741D8BC58707894600895E028BD889C6
-:104D00006F028BE19D61071FF8C39D61071FF9C307
-:104D1000892E3E01896E00896E0287E19D8BE1EB51
-:104D2000E4000D0A5465726D696E616C73207375D1
-:104D300070706F727465643A0D0A312920414E53C8
-:104D40004920636F6D70617469626C650D0A322968
-:104D500020577973652033300D0A506C6561736597
-:104D60002073656C6563743A20000D0A636F646597
-:104D7000207365676D656E743D000D0A4D6F6E6939
-:104D8000746F722076322E350A0D0A3E000D0A50DD
-:104D90006172646F6E3F000D0A4E6F206164647231
-:104DA00065737320737065636966696564000D0AD5
-:104DB0003A000D0A004C6F633D000D0A4641544114
-:104DC0004C204552524F523D000D0A4D6F6E697492
-:104DD0006F7220636F6D6D616E64733A2D0D0A20E2
-:104DE0002020442C645B5B787878783A5D7878781A
-:104DF000785D202D2064756D70206D656D6F727902
-:104E00000D0A2020204C2C6C5B5B787878783A5D1A
-:104E1000787878785D202D2064756D702073696EC8
-:104E2000676C65206C696E650D0A202020452C6535
-:104E30005B5B787878783A5D787878785D202D209B
-:104E400065646974206D656D6F72790D0A2020208C
-:104E5000462C665B5B78787878205D787878785D2A
-:104E6000202D2066696C6C206D656D6F72792070E5
-:104E70006172616772617068730D0A202020495B5E
-:104E8000787878785D202020202020202020202D78
-:104E900020776F726420696E7075742066726F6D12
-:104EA00020706F72740D0A202020695B7878787802
-:104EB0005D202020202020202020202D20627974B9
-:104EC0006520696E7075742066726F6D20706F72E8
-:104ED000740D0A2020204F78787878207878202068
-:104EE000202020202020202D206F757470757420C4
-:104EF000776F726420746F20706F72740D0A2020B7
-:104F0000206F787878782078782020202020202042
-:104F100020202D206F75747075742062797465205F
-:104F2000746F20706F72740D0A202020475B5B78CD
-:104F30007878783A5D787878785D2020202D206721
-:104F40006F746F20616464726573730D0A20202092
-:104F5000575B5B787878783A5D787878785D202050
-:104F6000202D207761746368206120776F72640D53
-:104F70000A20202043202020202020202020202024
-:104F800020202020202D20696E7465727275707447
-:104F900073206F66660D0A202020532020202020D9
-:104FA00020202020202020202020202D20696E7409
-:104FB00065727275707473206F6E0D0A20202073F5
-:104FC00020202020202020202020202020202020E1
-:104FD0002D2073696E676C6520737465700D0A20EF
-:104FE000202042787878782020202020202020203F
-:104FF0002020202D20627265616B706F696E7420B5
-:105000007365740D0A20202062202020202020209B
-:105010002020202020202020202D20627265616B1E
-:10502000706F696E7420636C6561720D0A202020B8
-:10503000522020202020202020202020202020203E
-:10504000202D207265737461727420627265616BC9
-:10505000706F696E740D0A2020207220202020209D
-:1050600020202020202020202020202D2072656755
-:105070006973746572732061742062726B70740D51
-:105080000A202020582C78206E202020202020204C
-:1050900020202020202D206578616D696E652063B9
-:1050A00068616E6E656C206E0D0A202020482C3FD2
-:1050B00020202020202020202020202020202D20E3
-:1050C00074686973206D657373616765001B5B327B
-:1050D0004A1B5B313B3148414E5349205465726D48
-:1050E000696E616C0D0A0A001B5B4B001B5B4A007A
-:1050F0001B5B324A1B5B313B3148001B5B44201B6E
-:105100005B44001B5B313B373248001B5B003B00BC
-:1051100048001B5B73001B5B75001B7A2B0B7F1B0E
-:105120007A2E0C7F1B7A2D087F1B7A2C0A7F1B7A24
-:1051300022087F1A57797365203330205465726DC9
-:10514000696E616C0D0A001B54001B59001A001E89
-:105150000008200800001B3D0000001B46000D0059
-:105160003F4464456546664767486849694F6F43F1
-:1051700063537342625272577758784C6C3C60D4D8
-:1051800057D45750585058D659D659B459B4593C99
-:10519000603C606C57485726570657905790579871
-:1051A00057485F0C5F585F335F405FA057A057FEC2
-:1051B00059FE59DC57DC5788619861C061CC61D8D1
-:1051C00061F66102622262F8564A625862605920B2
-:1051D00020666C6167733D00202061783D002020CF
-:1051E00062783D00202063783D00202064783D00F7
-:1051F000202063733D00202064733D0020206573F0
-:105200003D00202073733D00202064693D00202074
-:1052100073693D00202062703D00202073703D00C6
-:10522000202069703D00206368616E656C3D002040
-:105230002020207365673D002074695F7374723DA0
-:10524000002074695F746F733D002074695F6D6145
-:10525000783D002074695F6261733D002074695F6E
-:1052600073697A3D002074695F7374663D00207431
-:10527000695F726F6F3D002074695F666C673D0007
-:105280002074695F746F743D002072695F70636E93
-:105290003D002072695F7374723D002072695F7314
-:1052A00074663D002072695F726F6F3D0020726905
-:1052B0005F6261733D002072695F73697A3D00200F
-:1052C00072695F746F743D002072695F6D696E3D35
-:1052D000002072695F666C673D002072695F746FC1
-:1052E000733D002072695F7468723D002074685FCE
-:1052F0007374663D002074685F7374723D0020749F
-:10530000685F6261733D002074685F73697A3D0075
-:105310002074685F7472673D002074685F666C6714
-:105320003D002074685F636E743D002072685F7397
-:1053300074723D002072685F7374663D002072686D
-:105340005F6261733D002072685F73697A3D00207F
-:1053500072685F7370613D002072685F61736F3DBA
-:10536000002072685F726F6F3D002072685F666C2C
-:10537000673D00206D5F636172653D002070745F62
-:10538000666C6F3D002061735F666C6F3D0020723C
-:105390006D5F666C6F3D00202020715F696E3D007F
-:1053A0002020715F6F75743D0020715F6472616EC3
-:1053B0003D002020715F74696D3D00202020715FE9
-:1053C00066633D0020715F737461743D0020715FFE
-:1053D000646174613D0020715F6D6F646D3D0020FC
-:1053E00068616E645F6F3D002068616E645F623D5E
-:1053F000002068616E645F653D002068616E645FD7
-:10540000693D0020206F706F73743D002020746927
-:105410006D656F3D0020637573746D313D002063D1
-:105420007573746D323D0020637573746D643D0057
-:10543000207478726174653D0020727872617465C1
-:105440003D002020635F6D61703D0020635F6164FB
-:1054500064723D0020635F616973723D0020635F89
-:10546000787461673D0020635F646566723D00206B
-:10547000635F666C73683D002074786D6178733D7E
-:10548000002072695F656D733D002020635F6C735F
-:10549000723D002020635F6965723D002020635FDC
-:1054A0006663723D002020635F6D63723D002020C3
-:1054B000635F6C63723D002020635F6473733D0023
-:1054C00020635F647373693D0020635F647373726C
-:1054D0003D002020635F6973723D002020635F639D
-:1054E00061723D002020635F6566723D0020635F4E
-:1054F000657273743D0020635F65636E743D0020C8
-:10550000635F62726B633D0020635F626F6B633D3C
-:105510000020635F7265706C3D0020635F6363739E
-:10552000723D0020635F737474313D0020635F73CC
-:105530007474323D002BC08ED88EC0E8C200E8E5FE
-:1055400000FABF8400C705DC568C4D02BF0C00C7B3
-:10555000056E5E8C4D02BF0400C705BA5E8C4D021D
-:10556000E8F10090E84901E81600F490E8E500BE93
-:10557000BA4DE8090CA09312E85D0CE8C209EBE40F
-:10558000E8D50CE8C40C0AC074F68B1EF8793C0D03
-:10559000742E3C0874173C7F741383FB207FE188D2
-:1055A00087D67943891EF879E8770CEBD30BDB7447
-:1055B000CF4B891EF8798B36167AE8C10BEBC19078
-:1055C000E80200EBBBC687D679000BDB741EA0D6C1
-:1055D00079BF6051B91D008BD9060E07F2AE077571
-:1055E00017412BD9D1E32EFF977D519033C0A3F8FB
-:1055F00079BE894DE8870BC3BE8D4DE8800BEBEC7F
-:10560000BA0002B093EEB055EEBA1002B093EEB00D
-:10561000AAEEBA0002EC3C557508BA1002EC3CAA9E
-:105620007403E82FF6C3BA0402B01AEEB020EEB04D
-:1056300030EEB040EEB080EEBA0002B013EEB0072C
-:10564000EEBA0802B080EEBA0202B0BBEEBA0402B3
-:10565000B005EEC3C606CA1301C706F8790000C636
-:1056600006F67901C706D0790000C706D279000096
-:10567000C706D4790000C706FA790000C706FC798E
-:105680000000C706FE790000C706007A0000C706C2
-:10569000027ACE598C0E047AC706067A0000C70635
-:1056A000277A0000C606297A00C6062A7A00C39027
-:1056B000BE224DE8C80AE83F002C313C0177F7E8EC
-:1056C00081098B360C7AE8B50ABE6A4DE8AF0A0E3E
-:1056D00058E8F80ABE7A4DE8A40AC39060D1E38383
-:1056E000FB1873111EBA00008EDA2EFF97B7518B8C
-:1056F000EC8946101F61CF90E84F0B0AC07505E892
-:10570000560BEBF4C390833EF879017416BED7793B
-:10571000E8310A8BD0AC3C2C74043C207505E8239E
-:105720000AEEC3E9D2FE833EF8790174F6BED7795A
-:10573000E8110A8BD0AC3C2C74083C207404E9B707
-:10574000FE90E8FF09EFC3908B16067A833EF87946
-:1057500001740BBED779E8EB098BD0A3067AB02091
-:10576000E8570B8B16067AECE86F0BC38B16067A9C
-:10577000833EF87901740BBED779E8C7098BD0A3B3
-:10578000067AB020E8330B8B16067AEDE8670BC378
-:10579000FAC606F67900C390C606F67901FBC390F7
-:1057A00006E85809B020E8110B268B05E8470BB036
-:1057B00008E8060BE8030BE8000BE8FD0AB8010057
-:1057C000E8CFF4BA0202EC24017502EBDCBA06025F
-:1057D000EC07C390C706087A1000EB06C706087AE4
-:1057E0000100068E06FC798B3EFA79E80E09E80B7B
-:1057F00000893EFA798C06FC7907C390BEB24DE869
-:105800007C098B16087A52E82A09E80F0AE80C0A84
-:1058100033DBB9100090268A01E8BC09E8FD094392
-:10582000E2F4E8F709E8F40933DBB9100090268ABE
-:10583000013C2072053C7E760390B02EE8E30943DC
-:10584000E2ECBEB24DE8360983C7105A4A75B7C3B9
-:10585000068E06007A8B3EFE79E8A008893EFE7926
-:105860008C06007A578B360E7AE81209C706087A3A
-:105870001000BA0002E8E800E881FF5FBA0000E823
-:10588000DE00BEB54DE8F6088CC0E83F09B03AE846
-:1058900090098BC7E83509E87E08E8C30090E8B7AF
-:1058A00009E8A6090AC074F63C0B750683EF10EBF5
-:1058B00019903C0A750683C710EB0F903C0C7504D9
-:1058C00047EB07903C0875244F908B36FE798BC7C9
-:1058D0002BC63D000172A53D1001720483EE20909D
-:1058E00083C6108936FE79578BFEEB803C2E7508F7
-:1058F000BA0113E86A0007C3C6060A7A0232C990E1
-:105900003C30724C3C39760C245F3C4172423C4640
-:10591000773E2C072C3050E8CC085802C8FE0E0AFF
-:105920007A740FC0E104E82F09E81E090AC074F672
-:10593000EBCE26880DE8E0078AD0E823008AC13C38
-:105940002072053C7E760390B02EE8D508E970FF02
-:10595000E8C507E80A00268A05E87C08E91DFF90EB
-:10596000F606267A02750286F2528B361A7AE80D0E
-:10597000085A528AC60206247AF606267A01750665
-:10598000E89F08EB0D9032E4E80D088B361C7AE8AE
-:10599000EC075A8AC20206257AF606267A017506AF
-:1059A000E87F08EB069032E4E8ED078B361E7AE8D4
-:1059B000CC07C390068E06047A8B3E027AE83C0739
-:1059C000893E027A8C06047A07FF1E027AC3BE97CC
-:1059D0004DE8AA07CB900657BED779E866078BD863
-:1059E000E861078BC82BCB78118EC3BF0000B8FFCE
-:1059F000FF51B90800F3AB59E2F75F07C39006BE49
-:105A0000D779E83F078BD8D1E32E8B9F4400BE2681
-:105A100052E8F1088BC3E8DD08B80100E873F2E84A
-:105A2000E008BE2F52E8DD088B4718E8C808BE77AB
-:105A300052E8D1088B4726E8BC08BE5352E8C50897
-:105A40008B471EE8B008BE5C52E8B9088B4720E8D7
-:105A5000A408BE6E52E8AD088B4724E89808BE80C3
-:105A600052E8A1088B472AE88C08E89508BE38520E
-:105A7000E892088B07E87E08BE4152E887088B470A
-:105A80001AE87208BE4A52E87B088B471CE8660891
-:105A9000BE6552E86F088B4722E85A08E86308BEE3
-:105AA000D152E860088B4738E84B08BEAD52E85445
-:105AB000088B4730E83F08BEB652E848088B4732AB
-:105AC000E83308BEA452E83C088B472EE82708BEFE
-:105AD000BF52E830088B4734E81B08E82408BE8929
-:105AE00052E821088B4704E80C08BE9252E81508DA
-:105AF0008B4714E80008BE9B52E809088B472CE846
-:105B0000F407BEC852E8FD078B4736E8E807BEDA5F
-:105B100052E8F1078B473AE8DC07BEE352E8E507B5
-:105B20008B473CE8D007E8D907BE1953E8D6078B66
-:105B30004748E8C107BEFE52E8CA078B4742E8B5AE
-:105B400007BE0753E8BE078B4744E8A907BE7C534E
-:105B5000E8B2078B474CE89D07BE8553E8A6078B44
-:105B6000474EE89107BE8E53E89A078B4750E88569
-:105B700007E88E07BE2253E88B078B474AE8760773
-:105B8000BEEC52E87F078B4708E86A07BEF552E88B
-:105B900073078B4740E85E07BE1053E867078B47E3
-:105BA00046E85207E85B07BE6A53E858078B477A16
-:105BB000E84307BE3D53E84C078B4770E83707BE04
-:105BC0004653E840078B4772E82B07BE4F53E83433
-:105BD000078B4774E81F07E82807BE2B53E8250703
-:105BE0008B470CE81007BE3453E819078B4710E8C1
-:105BF0000407BE5853E80D078B4776E8F806BE61E8
-:105C000053E801078B4778E8EC06BE7353E8F506C6
-:105C10008B473EE8E006E8E906BE9753E8E6068BC8
-:105C20004752E8D106BEA053E8DA068B4754E8C5D0
-:105C300006BEA953E8CE068B4756E8B906BEB25356
-:105C4000E8C2068B4758E8AD06BEBB53E8B6068BE4
-:105C5000475AE8A106BEC453E8AA068B475CE895FC
-:105C600006E89E06BECD53E89B068B475EE8860697
-:105C7000BED653E88F068B4760E87A06BEDF53E84E
-:105C800083068B4762E86E06BEE853E877068B47CB
-:105C90007CE86206BEF153E86B068B477EE8560649
-:105CA000BEFA53E85F068B878000E84906E8520693
-:105CB000BE4254E84F068B879E00E83906BE035467
-:105CC000E842068B4764E82D06BE0C54E836068B86
-:105CD000476EE82106BE1554E82A068B878E00E839
-:105CE0001406BE1E54E81D068B879000E80706BE0A
-:105CF0002754E810068B879200E8FA05E80306BEF1
-:105D00003054E800068B879400E8EA05BE3954E871
-:105D1000F3058B879600E8DD05BE6F54E8E6058B3A
-:105D2000879800E8D005BE5D54E8D9058A87A000B1
-:105D3000E8A705BE5454E8CC058A4728E89B05BE71
-:105D40006654E8C0058A87A100E88E05E8B305BE61
-:105D50007854E8B0058A87A200E87E05BE8154E841
-:105D6000A3058A87A300E87105BE8A54E896058AD0
-:105D700087A400E86405BE9354E889058A87A500D6
-:105D8000E85705BE9C54E87C058A87A600E84A05CA
-:105D9000BEA554E86F058A87A700E83D05BEAE544E
-:105DA000E862058A87A800E83005E85505BEB754C3
-:105DB000E852058A87A900E82005BEC054E84505D9
-:105DC0008A87AA00E81305BEC954E838058A87AB5C
-:105DD00000E80605BED254E82B058A87AD00E8F935
-:105DE00004BEDB54E81E058A87AE00E8EC04BEE47E
-:105DF00054E811058A87AF00E8DF04BEED54E804DB
-:105E0000058A87B000E8D204E8F704BEF654E8F447
-:105E1000048A87B100E8C204BEFF54E8E7048A8719
-:105E2000B200E8B504BE0855E8DA048A87B300E892
-:105E3000A804BE1155E8CD048A87BB00E89B04E89E
-:105E4000C004BE1A55E8BD048A87BC00E88B04BEB6
-:105E50002355E8B0048A87BE00E87E04BE2C55E8CE
-:105E6000A3048A87BF00E87104E8960407C36006AC
-:105E70001E168BECFF4E16F7461A00027401FBB893
-:105E800000008ED88EC0892E2D7AE8CB0081661A4C
-:105E9000FFFEC6062A7A00E8D800B8005FA32B7A76
-:105EA000E85D00803E2A7A00740A814E1A0001C61D
-:105EB000062A7A00171F0761CF9060061E168BEC2A
-:105EC000F7461A00027401FBB800008ED88EC08914
-:105ED0002E2D7A81661AFFFEC6062A7A00E8920005
-:105EE000B8005FA32B7AE81700803E2A7A00740A74
-:105EF000814E1A0001C6062A7A00171F0761CF904B
-:105F0000B8F000E88CEDFF262B7AC390065356803C
-:105F10003E297A007403E83F00BED779E825028B5A
-:105F2000D8A3277A2E8A07A2297AB0CC2E88075EBA
-:105F30005B07C3C6062A7A00B80A5FA32B7AC39010
-:105F40008B2E2D7AE82B00C3C6062A7A01E80800BA
-:105F5000B80A5FA32B7AC39057803E297A00740F4A
-:105F60008B3E277AA0297A2E8805C606297A005FFB
-:105F7000C390BEB24DE80602BED851E80002FF76DB
-:105F80001458E84702BEDE51E8F301FF760E58E8E8
-:105F90003A02BEE451E8E601FF761258E82D02BE4F
-:105FA000EA51E8D901FF761058E82002BE1452E801
-:105FB000CC01FF760A58E81302BE1A52E8BF01FF6F
-:105FC000760C58E80602BECF51E8B201FF761A58A7
-:105FD000E8F901BEB24DE8A501BEF051E89F01FF0E
-:105FE000761858E8E601BEF651E89201FF760258AD
-:105FF000E8D901BEFC51E88501FF760458E8CC01E0
-:10600000BE0252E87801FF760058E8BF01BE085290
-:10601000E86B01FF760658E8B201BE0E52E85E0159
-:10602000FF760858E8A501BE2052E85101FF761618
-:1060300058E89801BE894DE84401C390BEC94DE8B7
-:106040003C01C33C0074053C017459C3C7060C7A7B
-:10605000CD50C7060E7AF050C706107AE850C70632
-:10606000127AEC50C706147AF450C706167AFB5021
-:10607000C706187A0351C7061A7A0B51C7061C7A4D
-:106080000E51C7061E7A1051C706207A1251C70654
-:10609000227A1651C606247A01C606257A01C6065A
-:1060A000267A03C3C7060C7A1A51C7060E7A4D51D9
-:1060B000C706107A4751C706127A4A51C706147AA2
-:1060C0004F51C706167A5151C706187A5551C7065F
-:1060D0001A7A5651C7061C7A5951C7061E7A5A5168
-:1060E000C706207A5B51C706227A5E51C606247A1B
-:1060F00020C606257A20C606267A02C3A1F879486A
-:106100007414BED779E83C008BF8AC3C3A75078E26
-:10611000C7E830008BF8C3908BC72B06FE798AF056
-:10612000240F8AD002D002D080C20BC0EE0480C6F9
-:1061300003043DC38CC0E89300B03AE8E4008BC789
-:10614000E88900C35133C990AC3C2074FB900AC06D
-:1061500074262C3072223C0976143C11721A2C07DA
-:106160003C0F760A3C2A72102C203C0F770A98C10B
-:10617000E10403C8ACEBD7904E8BC159C390068C99
-:10618000C88EC0E8020007C3268A04460AC0740607
-:10619000E88F00EBF390C3900BC0747A5133D2B9FF
-:1061A000E803F7F18BCAE803008BC159BA6400F623
-:1061B000F2E80C008AC498B20AF6F2E802008AC437
-:1061C000500AF074050430E8580058C386C4E80744
-:1061D0000086C4E80200C390C1C804E80800C1C03A
-:1061E00004E80200C3905350240FBBCA622ED7E8C4
-:1061F0003000585BC39086C4E8070086C4E80200FC
-:10620000C39050B908008AE032C0D1C00430E81110
-:1062100000E2F558C390B030E80700C3B020E801B1
-:1062200000C3568B36D0798884D0774681E6FF014B
-:10623000FF06D4798936D079813ED479FE0175087C
-:1062400056E814005EEBF1905EC3BA0202EC240142
-:106250007404BA0602ECC390803EF67900740960BB
-:10626000B80100E82CEA6190BA0202ECA804742894
-:106270008B36D279833ED47900741D8A84D07746D8
-:1062800081E6FF018936D279FF0ED479BA0602EE93
-:10629000BA0202ECA80475DCA1D479C352BA060292
-:1062A000EE5AC3905250BA0202ECA8047408585A2D
-:1062B000E8E9FFF9C390585AF8C35250BA0202EC09
-:1062C000A80474FB585AE8D3FFC330313233343555
-:1062D0003637383941424344454653508AE080E4DA
-:1062E0000FBBCA62C0E8042ED7E8CEFF8AC42ED7FF
-:1062F000E8C7FF585BC386E0E8DFFF86E0E8DAFF27
-:10630000C390BEB24D502EAC3C007405E8ABFFEB21
-:10631000F558C390C808000056578B7604BF040098
-:10632000C746FC0000C746FA0000C746F8000083D5
-:106330007E0600750E56E8B60E590BC075058BC764
-:10634000E95B018B46FC8946FE0BFF7505B8010031
-:10635000EB0233C05056E8A40D5959B4008946FCED
-:106360008B5EFC83FB087603E92B01D1E32EFFA7AC
-:10637000B264B80300E92601837EFA007414C746AC
-:10638000FA00008A445898508A44599850E8C20F3D
-:106390005959837EF800740AC746F8000056E89BF6
-:1063A0000859837E060075058BC7E9F10083FF0459
-:1063B0007503E9E6008BC7E9E400837EFE00750300
-:1063C000BF0200E9D500837EFE007503BF0100E92E
-:1063D000C9008B5EFE83FB077603E98600D1E32EBE
-:1063E000FFA7A26433FFE97F00BF0400807C580F41
-:1063F0007422837EF800751CFE44586A0856E87EB5
-:106400000C59598A445804805056E8720C5959C79F
-:1064100046FA0100837EF800740AC746F800005669
-:10642000E8190859EB42BF0400807C5800742283AD
-:106430007EF800751CFE4C586A0856E8410C595904
-:106440008A445804805056E8350C5959C746FA0119
-:1064500000837EF800740AC746F8000056E8DC079F
-:1064600059EB05BF0400EB00EB31BF0400EB2CC778
-:1064700046F801006A0856E8050C5959807C58090D
-:106480007D04B00FEB02B00004805056E8F00B59C9
-:1064900059BF0400EB05BF0400EB00E9A5FE5F5EF9
-:1064A000C9C3E4636364636463646364E963266427
-:1064B00051647863BA63C6639664D2636A646A643B
-:1064C0006F647263C808000056578B76048B7E0891
-:1064D0006A0156E8A90B59598A4606C0E0060480AD
-:1064E0005056E89A0B5959C746FE0000897EF8EBD2
-:1064F00003FF46FE8B5EF8FF46F8803F0075F2838F
-:106500007EFE107D25B810002B46FED1F88946FC92
-:10651000C746FA0000EB0B6A2056E8620B5959FF98
-:1065200046FA8B46FA3B46FC7CEDEB0C8BDF478A48
-:10653000075056E8490B5959803D0075EF6A0256DD
-:10654000E83C0B5959EB005F5EC9C3C80400005614
-:10655000578B7E04C746FE0000BE1400E909018B7C
-:106560005EFE83C3042BDF8A87AC0B88445AC64483
-:1065700058088A46FE884459C744060000C6441994
-:1065800000C6441A00C6441B00C6441D0DC6441E66
-:1065900003C6441F00C6442000C6442100C6445B15
-:1065A00000C6445D00C6445E00C6445F00C6446049
-:1065B00000C746FC0000EB0D8B5EFCD1E3C740300A
-:1065C0000000FF46FC837EFC107CEDC746FC00000B
-:1065D000EB0A8B5EFCC6405000FF46FC837EFC0449
-:1065E0007CF0C744540000C7445600008A445A98BF
-:1065F000BAF80023D0B805000BC28946FC9CFA8A81
-:1066000046FCBAFE00EEBA0000EC9D24088846FC69
-:10661000837EFC007502EB4AFF76FEE87A0C59682F
-:10662000350256E8320A59590BC07534683802569B
-:10663000E8250A59590BC0752768420256E8180A1E
-:1066400059590BC0751A684C0256E80B0A59590B78
-:10665000C0750D68560256E8FE0959590BC0740200
-:10666000EB00FF46FE83C662397EFE7D03E9EFFE46
-:10667000EB005F5EC9C3C808000056578B4604BADA
-:106680006200F7EA0514008BF0837E06007405B8FB
-:106690001000EB03B808008944048A460888445C6B
-:1066A00056E85904598BF88BC78944568944548A53
-:1066B000445D88442F0BFF751D68C20F6A0156E8C0
-:1066C00002FE83C406EB006A0156E847FC59590BE9
-:1066D000C075F4BF0100897EFAB90500BBE96A2ED6
-:1066E0008B073B46FA74074343E2F4E9A4032EFF09
-:1066F000670AC744060200C74408F4088B5E04D149
-:10670000E38B87FC0889440A33C08BF8894454E939
-:10671000800356E8BB0559BF01008A445D88446088
-:10672000E96F03837C04087530807C5C0175158AF1
-:10673000445DB400D1E08BD8FFB7E40856E8F70811
-:106740005959EB138A445DB400D1E08BD8FFB7C42C
-:106750000856E8E2085959EB2E807C5C0175158AD1
-:10676000445DB400D1E08BD8FFB7D40856E8C70821
-:106770005959EB138A445DB400D1E08BD8FFB7B40C
-:106780000856E8B20859596A0156E887FB59598BEF
-:10679000D883FB03772AD1E32EFFA7E16ABF01006C
-:1067A0008A445D88445EEB188A445D04FF240788B0
-:1067B000445DEB0C8A445DFEC0240788445DEB0019
-:1067C000E9CF028A445DB400D1E08BD8FFB7FD0267
-:1067D00056E863085959681D0356E85A0859596A1A
-:1067E0000156E82FFB59598BD883FB037736D1E349
-:1067F0002EFFA7D96ABF01008A445D88445FEB245D
-:106800008A445D04FF8A540480C2FF22C288445D2A
-:10681000EB128A445DFEC08A540480C2FF22C28803
-:10682000445DEB00E96B028B5C0683C3FED1E38B16
-:10683000400889048B1CFF77066A0056E885FC83B4
-:10684000C4068B5C064BD1E38B40088944028B5C09
-:1068500002FF77066A0156E86AFC83C4066A01569D
-:10686000E8B1FA59598BD883FB037603E91F02D1AB
-:10687000E32EFFA7D16A8B5C028B47048944028B0D
-:106880005C02803F44750D8B5C028A4701B4003B7B
-:1068900044047DE28B4604D1E08B1C03D88B440278
-:1068A0008947088B5C064BD1E38B4402894008E999
-:1068B000DE018B5C028B47028944028B5C02803FC5
-:1068C00044750D8B5C028A4701B4003B44047DE2B1
-:1068D0008B4604D1E08B1C03D88B44028947088B7C
-:1068E0005C064BD1E38B4402894008E9A201BF0159
-:1068F00000E99C018B5C028A07B4008946F8B90C58
-:1069000000BBA16A2E8B073B46F874074343E2F4B1
-:10691000E977012EFF67188B4604D1E08B5C0203F8
-:10692000D88B47088B5C06FF4406D1E38940088B6F
-:106930001C807F010074128B5C028A47018B1C8AC9
-:106940005701B6008BDA884018E94001FF4C06E990
-:106950003A018B5C028A47018B1C8A5701B6008B77
-:10696000DA884018E925018B5C028A47018B1C8A72
-:106970005701B6008BDA884018FF4C06E90D018BF1
-:106980005C028A47018B1C8A5701B6008BDA3040C3
-:1069900018E9F800B8F0108BF88944548A445F88ED
-:1069A000445DE9E7008A441C983D020074073D03FA
-:1069B000007402EB07C746FE0000EB2B8A441C98CC
-:1069C000D1E08BD8FFB7690256E86B0659596A01C6
-:1069D00056E840F959598946FE837EFE00740683C5
-:1069E0007EFE0375E9EB00837EFE0374628A441C1D
-:1069F00098D1E08BD8FFB76D0256E83A0659595640
-:106A0000E84D97598946FC8B5EFC83EBFE83FB03C4
-:106A10007733D1E32EFFA7996A68AC0256E81706D0
-:106A20005959EB23688F0256E80C065959EB186840
-:106A3000750256E801065959EB0D68C60256E8F68C
-:106A4000055959EB02EB006A0156E8C7F85959BFDE
-:106A50000100EB3868DD0256E8DC0559596A015639
-:106A6000E8B1F85959BF0100EB22B8D0308BF88952
-:106A700044548A446088445DEB12B8E0208BF88966
-:106A800044548A445E88445DEB02EB00EB02EB0069
-:106A9000EB00E941FC5F5EC9C3196A246A2F6A3AB8
-:106AA0006A0000010002000400410042004300446B
-:106AB00000800081008200FF001769546A7A6AA58D
-:106AC00069526994696A6A676952697F6967694C42
-:106AD00069F4687668B268EE68F56700681268F570
-:106AE000679D67A867B4679D6700000100F010E02C
-:106AF00020D0302768F266C36723671267C8040096
-:106B00000056578B76048A4459988946FC6A098B4B
-:106B100046FC05840150E8930859598BF88BC7252A
-:106B200000F03D001075558BC725F0003DF0007555
-:106B30004B8BC725000FC1F8088946FE8B44043BE8
-:106B400046FE7D0533C0E9EF008BC7250F00BA0F65
-:106B5000002BD03B56FE740533C0E9DB00C744026E
-:106B600004098A46FE88445F88445D8B5EFCD1E35D
-:106B7000C787FC080409B8F010E9BC008BC72500E2
-:106B8000F03D002075528BC725F0003DE0007548B0
-:106B90008BC725000FC1F8088946FE837EFE087E5C
-:106BA0000533C0E992008BC7250F00BA0F002BD028
-:106BB0003B56FE740533C0EB7F90C744020C098A34
-:106BC00046FE88445E88445D8B5EFCD1E3C787FC4B
-:106BD000080C09B8E020EB608BC72500F03D0030C1
-:106BE00075528BC725F0003DD00075488BC7250036
-:106BF0000FC1F8088946FE8B44043B46FE7D0433F2
-:106C0000C0EB358BC7250F00BA0F002BD03B56FECB
-:106C1000740433C0EB22C7440214098A46FE884438
-:106C20006088445D8B5EFCD1E3C787FC081409B81B
-:106C3000D030EB0433C0EB005F5EC9C3C806000070
-:106C4000568B76046A0856E8350459598A44580424
-:106C5000805056E8290459598B44543B4456750AD0
-:106C60008A445D3A442F7502EB648B445489445640
-:106C70008B5C028A470188442F8A445DB400C1E0DE
-:106C8000088B54540BD08A445DB400BB0F002BD842
-:106C90000BD38956FE6A108A445998050400990559
-:106CA000400183D2005250E8540883C4068956FC40
-:106CB0008946FA8B46FE0946FA834EFC006A19FFA4
-:106CC00076FCFF76FAE8730783C406E8FE075EC920
-:106CD000C3C81C000056578B5E048A4759988BF036
-:106CE0008B5E048A475DB4008946E6837EE6007DBC
-:106CF0000A8B5E048B4704488946E68B5E048B470B
-:106D0000043B46E67F05C746E600008B5E048A46E4
-:106D1000E688475D8BDED1E38B9F5902C647022090
-:106D20008BDED1E38B9F5902C64703308BDED1E364
-:106D30008B9F6102C64702208BDED1E38B9F6102ED
-:106D4000C64703308B46E68946FA837EFA007418FC
-:106D50008B46FABB0A0033D2F7F380C2308BDED108
-:106D6000E38B9F5902885703BB0A008B46FA33D244
-:106D7000F7F38946FA837EFA0074188B46FABB0A49
-:106D80000033D2F7F380C2308BDED1E38B9F590200
-:106D90008857028B46E68946FA837EFA0074188B80
-:106DA00046FABB0A0033D2F7F380C2308BDED1E360
-:106DB0008B9F6102885703BB0A008B46FA33D2F7D8
-:106DC000F38946FA837EFA0074188B46FABB0A00F0
-:106DD00033D2F7F380C2308BDED1E38B9F61028820
-:106DE00057028B5EE6D1E3FFB712026A00FF76041A
-:106DF000E8D1F683C40668D30F6A01FF7604E8C3BE
-:106E0000F683C406FF76E656E8019359598956F28F
-:106E10008946F0FF76E656E8149359598956EE896B
-:106E200046EC9CFAC45EF0268B078946EAC45EEC09
-:106E3000268B078946E8BA50FFED8946FE9DC74676
-:106E4000E40100E8EEA0BA50FFED8946FC8B46FC59
-:106E50002B46FE3DE8037303E980019CFABA50FF1C
-:106E6000ED8946FC8B46FC2B46FE8946F8C45EF055
-:106E7000268B072B46EA8946F6C45EF0268B0789E7
-:106E800046EAC45EEC268B072B46E88946F4C45ECE
-:106E9000EC268B078946E8BA50FFED8946FE9D81B6
-:106EA0007EF8E803761CFF76F8FF76F6E87601595F
-:106EB000598946F6FF76F8FF76F4E8680159598952
-:106EC00046F4BF0E00EB178BDED1E38B9F5902C651
-:106ED00001208BDED1E38B9F6102C601204783FF37
-:106EE0001176E48BDED1E38B9F5902C6470D308BC0
-:106EF000DED1E38B9F6102C6470D30837EF60977B2
-:106F000005B80D00EB26837EF6637705B80E00EB1F
-:106F10001B817EF6E7037705B80F00EB0F817EF645
-:106F20000F277705B81000EB03B811008BF8EB259D
-:106F30008B46F6BB0A0033D2F7F380C2308BDED12A
-:106F4000E38B9F590288114FBB0A008B46F633D260
-:106F5000F7F38946F6837EF60075D5837EF40977CC
-:106F600005B80D00EB26837EF4637705B80E00EBC1
-:106F70001B817EF4E7037705B80F00EB0F817EF4E9
-:106F80000F277705B81000EB03B811008BF8EB253D
-:106F90008B46F4BB0A0033D2F7F380C2308BDED1CC
-:106FA000E38B9F610288114FBB0A008B46F433D2FA
-:106FB000F7F38946F4837EF40075D58BDED1E3FFC9
-:106FC000B75902FF7604E86E0059598BDED1E3FF12
-:106FD000B76102FF7604E85E0059596A00FF760443
-:106FE000E831F359598BD883FB04771FD1E32EFF87
-:106FF000A71B70EB22C746E40000FF4EE6EB0CC770
-:1070000046E40000FF46E6EB02EB00837EE40074FA
-:1070100003E92AFEE9D4FC5F5EC9C3F36FF56FFF95
-:107020006FF36F0970558BEC8B4604B9E803F7E1F9
-:107030008B4E06F7F15DC3558BEC568B7606EB0E47
-:107040008BDE468A0750FF7604E833005959803CAE
-:107050000075EDEB005E5DC3558BEC568B7606EB51
-:10706000148BDE468A0750FF7604E8450059590B19
-:10707000C07402EB07803C0075E7EB005E5DC3C89F
-:10708000020000568B76048A445A988946FE9CFA80
-:107090008A46FEBAFE00EEBA0200ECA80274069D13
-:1070A000E8919EEBE9BA00008A4606EE9DEB005E91
-:1070B000C9C3C8040000568B76048A445A9889468E
-:1070C000FEE8E6A18946FCE8E0A12B46FC3DB80BB2
-:1070D0007605B80100EB239CFA8A46FEBAFE00EE64
-:1070E000BA0200ECA80274069DE8489EEBD9BA00EB
-:1070F000008A4606EE9D33C0EB005EC9C3C804009B
-:107100000056578B7604837E0600740756E8030109
-:1071100059EB0556E8A200598846FF807EFF0877A4
-:10712000068A46FFE98400807EFF0F7603EB7990A4
-:107130008A46FFB4002D0A008BD883FB047767D101
-:10714000E32EFFA7AF71B000EB6156E86B0059B4B6
-:1071500000250F008946FC56E85E0059B4008BF804
-:1071600056E8550059B400C1E0088BD703D08BFA1C
-:107170008B5EFCD1E3897830EB2E56E83B005988D2
-:10718000445BEB2456E831005988445056E8290006
-:107190005988445156E821005988445256E819004C
-:1071A00059884453EB02EB00E95BFF5F5EC9C346BD
-:1071B00071A6714A717A718471C8040000568B7689
-:1071C000048A445A988946FE9CFA8A46FEBAFE0012
-:1071D000EEBA0200ECA80175069DE8579DEBE9BAEE
-:1071E0000000EC8846FD9D8A46FDEB005EC9C3C8E1
-:1071F000020000568B76048A445A988946FE9CFA0F
-:107200008A46FEBAFE00EEBA0200EC32E424019D8A
-:107210005EC9C3C8060000568B76048A445A988912
-:1072200046FEE885A08946FAE87FA02B46FA3DB8DD
-:107230000B7604B008EB249CFA8A46FEBAFE00EEF8
-:10724000BA0200ECA80175069DE8E89CEBDABA00EA
-:1072500000EC8846FD9D8A46FDEB005EC9C3558B58
-:10726000EC568B56048A4606EE33F6EB035058462E
-:1072700083FE147CF85E5DC3C8020000568B560482
-:10728000EC8846FF33F6EB0350584683FE147CF837
-:107290008A46FFEB005EC9C3C802000056578B76D2
-:1072A00004833EB00B00751FBA8801B000EEBA86A9
-:1072B00001B000EE6A096A00683001E87D0183C40C
-:1072C00006C706B00B01006A098BC605800150E8AD
-:1072D000DA0059598BF88BC7C1E80C250F00894695
-:1072E000FE8BC7C1E808250F008B56FE83F20C3BCE
-:1072F000C275218BC7C1E804250F008B56FE83F2AF
-:10730000063BC2750F8BC7250F008B56FE83F20913
-:107310003BC2740D6A0756E838005959C746FE0744
-:10732000008A46FE0480A233028BC6BA6200F7EAE6
-:107330008A56FE8BD888976C006832028BC6BA6278
-:1073400000F7EA05140050E80EFD5959EB005F5EA6
-:10735000C9C3C8020000568B760683E60F8BC6C1F0
-:10736000E00C8BD683F20CC1E2080BC28BD683F201
-:1073700006C1E2040BC28BD683F2090BC28946FE1A
-:107380006A196A108B46049905400183D200525055
-:10739000E86B0183C4060B46FE83CA005250E89A8C
-:1073A0000083C406E82501EB005EC9C3558BEC568B
-:1073B0005733FF6A01688601E8A3FE5959B1102AC4
-:1073C0004E06D3660433F6EB2E817E0400807204F1
-:1073D000B001EB02B00050688801E881FE59596A9B
-:1073E00003688601E877FE59596A01688601E86DED
-:1073F000FE5959D16604463B76067CCD33F6EB2424
-:10740000D1E76A03688601E854FE59596A01688623
-:1074100001E84AFE5959688801E85CFE599825013F
-:10742000000BF84683FE107CD76A00688601E82DC1
-:10743000FE59598BC7EB005F5E5DC3558BEC565709
-:107440008B7E086A01688601E813FE5959B820004E
-:107450002BC750FF7606FF7604E8A20083C4068996
-:10746000560689460433F6EB47817E060080720C8F
-:107470007506837E04007204B001EB02B000506810
-:107480008801E8D9FD59596A03688601E8CFFD599A
-:10749000596A01688601E8C5FD59596A01FF7606F7
-:1074A000FF7604E8580083C40689560689460446D8
-:1074B0003BF77CB56A00688601E8A2FD59596A006D
-:1074C000688601E898FD59595F5E5DC3558BEC569F
-:1074D0006A01688601E886FD595933F6EB00688831
-:1074E00001E894FD59A80175088BC6463D64007CEF
-:1074F000ED6A00688601E865FD59595E5DC3C80400
-:1075000000008B46048B56068B4E08E306D1E0D173
-:10751000D2E2FA8946FC8956FE8B56FE8B46FCEB7E
-:1075200000C9C300000000000000000000000000CF
-:1075300050726576696F7573204D656E7500426592
-:1075400067696E00000000000000000000000000FD
-:10755000000000000000000000000000000000002B
-:10756000000000000000000000000000000000001B
-:10757000000000000000000000000000000000000B
-:1075800000000000000000000000000000000000FB
-:1075900000000000000000000000000000000000EB
-:1075A00000000000000000000000000000000000DB
-:1075B00000000000000000000000000000000000CB
-:1075C00000000000000000000000000000000000BB
-:1075D00000000000000000000000000000000000AB
-:1075E000000000000000000000000000000000009B
-:1075F000000000000000000000000000000000008B
-:10760000000000000000000000000000000000007A
-:10761000000000000000000000000000000000006A
-:10762000000000000000000000000000000000005A
-:10763000000000000000000000000000000000004A
-:10764000000000000000000000000000000000003A
-:10765000000000000000000000000000000000002A
-:10766000000000000000000000000000000000001A
-:10767000000000000000000000000000000000000A
-:1076800000000000000000000000000000000000FA
-:1076900000000000000000000000000000000000EA
-:1076A00000000000000000000000000000000000DA
-:1076B00000000000000000000000000000000000CA
-:1076C000000000000000000000000000506F727415
-:1076D000203000506F7274203100506F727420326D
-:1076E00000506F7274203300506F72742034005059
-:1076F0006F7274203500506F7274203600506F72B4
-:1077000074203700506F7274203800506F727420EC
-:107710003900506F727420313000506F7274203114
-:107720003100506F727420313200506F727420310A
-:107730003300506F727420313400506F72742031F6
-:1077400035009C01A301AA01B101B801BF01C60126
-:10775000CD01D401DB01E201EA01F201FA010202EA
-:107760000A02080000078100038080809F919591A4
-:107770009F000381848E95848484840003828484A2
-:107780008484958E8400048800B20BC60BDA0BEE5D
-:107790000B020C160C2A0C3E0C520C770C9C0CBEE7
-:1077A0000CE00C020D01802054657374205061734D
-:1077B000736564201F20507265737320800200017E
-:1077C00080204D697373696E67205278204461741C
-:1077D000611F205072657373208002000180204277
-:1077E00061642052782044617461201F20507265CA
-:1077F000737320800200018020586D7472204275DE
-:1078000073791F20507265737320800200018020FD
-:107810006E6F742063757272656E746C791F2020B0
-:10782000696D706C656D656E7465640200240D2F62
-:107830000D3A0D450D500D5B0D660D710D7C0D87DC
-:107840000D920D9D0DA80DB30DBE0DC90D53802CCD
-:107850003254442053862C334454522053822C33C8
-:10786000525453201F53812C3252442053852C32C2
-:1078700043442053832C334354532053842C3344A8
-:1078800053522053872C3252492702000180202076
-:10789000444344202D2070696E2032301F275385C9
-:1078A0002E31818263908081828384858687888956
-:1078B0008A8B8C8D8E8F27020001802020445352AA
-:1078C000202D2070696E2031311F2753842E318185
-:1078D000826390808182838485868788898A8B8C65
-:1078E0008D8E8F27020001802020435453202D20AD
-:1078F00070696E20341F2753832E318182639080FC
-:107900008182838485868788898A8B8C8D8E8F2758
-:107910000200018020205249202D2070696E203203
-:10792000321F2753872E3181826390808182838426
-:1079300085868788898A8B8C8D8E8F2702000180AF
-:107940002020445452202D2070696E20362F381F7D
-:107950002753862E3181826390808182838485863D
-:107960008788898A8B8C8D8E8F270200018020204A
-:10797000525453202D2070696E20351F2753822EBC
-:107980003181826390808182838485868788898A19
-:107990008B8C8D8E8F27020001802020527844200E
-:1079A0002D2070696E20321F2753812E30534D8158
-:1079B000826390808182838485868788898A8B8C84
-:1079C0008D8E8F27020001802020547844202D20A6
-:1079D00070696E20331F2753802E30534D81826390
-:1079E00090808182838485868788898A8B8C8D8E1E
-:1079F0008F27020001802020444344202D207069FD
-:107A00006E20351F2753852E3181826390808182BD
-:107A1000838485868788898A8B8C8D8E8F27020048
-:107A200001802020445352202D2070696E20351F84
-:107A30002753842E3181826390808182838485865E
-:107A40008788898A8B8C8D8E8F2702000180202069
-:107A5000435453202D2070696E20311F2753832EED
-:107A60003181826390808182838485868788898A38
-:107A70008B8C8D8E8F270200018020205249202D73
-:107A800020286E2E632E291F2753872E3181826373
-:107A900090808182838485868788898A8B8C8D8E6D
-:107AA0008F27020001802020445452202D2070692D
-:107AB0006E20321F2753862E31818263908081820F
-:107AC000838485868788898A8B8C8D8E8F27020098
-:107AD00001802020525453202D2070696E20371FC2
-:107AE0002753822E318182639080818283848586B0
-:107AF0008788898A8B8C8D8E8F27020001802020B9
-:107B0000527844202D2070696E20361F2753812E15
-:107B100030534D81826390808182838485868788FB
-:107B2000898A8B8C8D8E8F270200018020205478CB
-:107B300044202D2070696E20331F2753802E305330
-:107B40004D81826390808182838485868788898A3B
-:107B50008B8C8D8E8F27020001802020444344208F
-:107B60002D2070696E20351F202020202753852E60
-:107B700031818263888081828384858687270200A1
-:107B800001802020445352202D2070696E20351F23
-:107B9000202020202753842E318182638880818297
-:107BA0008384858687270200018020204354532048
-:107BB0002D2070696E20311F202020202753832E16
-:107BC0003181826388808182838485868727020051
-:107BD000018020205249202D20286E2E632E291F3F
-:107BE000202020202753872E318182638880818244
-:107BF00083848586872702000180202044545220F8
-:107C00002D2070696E20321F202020202753862EC1
-:107C10003181826388808182838485868727020000
-:107C200001802020525453202D2070696E20371F70
-:107C3000202020202753822E3181826388808182F8
-:107C40008384858687270200018020205278442083
-:107C50002D2070696E20361F202020202753812E72
-:107C600030534D8182638880818283848586872713
-:107C7000020001802020547844202D2070696E205D
-:107C8000331F202020202753802E30534D818263C4
-:107C90008880818283848586872702000180202056
-:107CA000444344202D2070696E2032301F20202054
-:107CB000202753852E318182638880818283848549
-:107CC000868727020001802020445352202D2070F7
-:107CD000696E2031311F202020202753842E3181CE
-:107CE0008263888081828384858687270200018061
-:107CF0002020435453202D2070696E20341F2020F3
-:107D000020202753832E318182638880818283845F
-:107D1000858687270200018020205249202D20706F
-:107D2000696E2032321F202020202753872E318178
-:107D30008263888081828384858687270200018010
-:107D40002020445452202D2070696E20362F381F79
-:107D5000202020202753862E3181826388808182D3
-:107D60008384858687270200018020205254532077
-:107D70002D2070696E20351F202020202753822E51
-:107D8000318182638880818283848586872702008F
-:107D900001802020527844202D2070696E20321FEF
-:107DA000202020202753812E30534D8182638880EC
-:107DB0008182838485868727020001802020547871
-:107DC00044202D2070696E20331F2020202027534F
-:107DD000802E30534D8182638880818283848586A2
-:107DE0008727020068049604B6033C040E04890346
-:107DF0005C03E20360088A08BE0738080E0895078E
-:107E00006C07E6071C057405FA05C404F004CC05EC
-:107E1000A00548057806C806420728065006180738
-:107E2000F006A0060000F408F408D40D04090409C3
-:107E30000409040942000C091C09E50D020014099B
-:107E40000409F40D43001C090C09050E0004040983
-:107E50001409120E2C092C092C092C0900003C09CC
-:107E60006C091E0E740974097409740900014C0927
-:107E70002C092D0E740974097409740900025C0937
-:107E80003C093D0E740974097409740900036C09F6
-:107E90004C094D0E7409740974097409FF002C090A
-:107EA0005C09000000058409EC095E0EF409F40980
-:107EB000F409F409000694097409680EAC0AAC0AC6
-:107EC000AC0AAC0A0007A4098409720EBC0ABC0AF9
-:107ED000BC0ABC0A0008B40994097C0ED40AD40A6E
-:107EE000D40AD40A000BC409A409830EFC0AFC0AB4
-:107EF000FC0AFC0A000CD409B409900E140B140BF4
-:107F0000140B140B0002E409C409A00E2C0B2C0B5B
-:107F10002C0B2C0B0400EC09D4090E00FF00740993
-:107F2000E40900008201FC09A40AAC0E8202040AE2
-:107F3000F409AF0E82030C0AFC09B20E8204140A83
-:107F4000040AB60E82051C0A0C0ABC0E8206240A1C
-:107F5000140AC00E82072C0A1C0AC40E8208340AB6
-:107F6000240AC80E82093C0A2C0ACC0E820A440A52
-:107F7000340AD10E82104C0A3C0AD60E820B540AE7
-:107F8000440ADB0E82115C0A4C0AE00E820C640A81
-:107F9000540AE50E82126C0A5C0AEA0E820D740A1B
-:107FA000640AEF0E820E7C0A6C0AF40E820F840AB9
-:107FB000740AFB0E82138C0A7C0A020F8214940A44
-:107FC000840A090F82159C0A8C0A100F8216A40AD3
-:107FD000940A170F8217F4099C0A1E0F8202B40A32
-:107FE000B40A260F8203AC0AAC0A2D0F8200C40A21
-:107FF000CC0A340F8201CC0ABC0A3F0F8202BC0AB1
-:10800000C40A4D0F8200DC0AF40A590F8201E40A07
-:10801000D40A630F8202EC0ADC0A6E0F8203F40AB0
-:10802000E40A7A0F8204D40AEC0A870F8200040B58
-:108030000C0B930F82010C0BFC0A9B0F8202FC0AB3
-:10804000040BA70F82001C0B240BB00F8201240B22
-:10805000140BB50F8202140B1C0BBE0F4400340B23
-:10806000A40B9C0144013C0B2C0BA3014402440BC8
-:10807000340BAA0144034C0B3C0BB1014404540BD8
-:10808000440BB80144055C0B4C0BBF014406640B68
-:10809000540BC60144076C0B5C0BCD014408740BF8
-:1080A000640BD40144097C0B6C0BDB01440A840B88
-:1080B000740BE201440B8C0B7C0BEA01440C940B17
-:1080C000840BF201440D9C0B8C0BFA01440EA40BA3
-:1080D000940B0202440F2C0B9C0B0A02171F0F2F4C
-:1080E0000000018078783A20747820637073202A29
-:1080F0002A2A2A2A0200018078783A20747820639C
-:108100007073202A2A2A2A2A0200018078783A20CD
-:10811000747820637073202A2A2A2A2A0200018098
-:1081200078783A20747820637073202A2A2A2A2AC1
-:10813000020001C078783A20726320637073202AAD
-:108140002A2A2A2A020001C078783A207263206322
-:108150007073202A2A2A2A2A020001C078783A203D
-:10816000726320637073202A2A2A2A2A020001C01F
-:1081700078783A20726320637073202A2A2A2A2A88
-:1081800002000180496E7374616C6C204C6F6F70DB
-:108190006261636B1F5072657373208020746F205F
-:1081A000737461727402000180204361626C652007
-:1081B000746F2052656D6F74651F50726573732004
-:1081C0008020746F20737461727402000180204CEF
-:1081D0006F63616C204C6F6F706261636B201F2056
-:1081E0002052756E6E696E67202E2E2E0200018061
-:1081F00052656D6F7465204C6F6F706261636B20A8
-:108200001F202052756E6E696E67202E2E2E020082
-:10821000018020496E74726E6C204C6F6F706261C9
-:10822000636B1F202052756E6E696E67202E2E2E96
-:10823000020001805472616E736D69742050617424
-:108240007465726E1F202052756E6E696E67202EE7
-:108250002E2E020001802020303A2027438000018A
-:10826000802020313A202743810001802020323AAB
-:10827000202743820001802020333A2027438300B7
-:1082800001802020343A20274384000180202035BB
-:108290003A202743850001802020363A2027438654
-:1082A0000001802020373A202743870001802020CA
-:1082B000383A202743880001802020393A2027437C
-:1082C000890001802031303A2027438A0001802034
-:1082D00031313A2027438B0001802031323A202768
-:1082E000438C0001802031333A2027438D000180E8
-:1082F0002031343A2027438E0001802031353A2046
-:1083000027438F002A2A204D61696E20204D656E1B
-:1083100075202A2A004D6F6E69746F72206120509B
-:108320006F7274004D6F6E69746F722061205369B3
-:10833000676E616C00457374696D617465204350AC
-:108340005300446961676E6F7374696373004C6FA7
-:1083500063616C204C6F6F706261636B0052656D7E
-:108360006F7465204C6F6F706261636B00496E744F
-:10837000726E6C204C6F6F706261636B005472613F
-:108380006E736D6974205061747465726E00426121
-:10839000756420526174650044617461204269749F
-:1083A000730053746F702042697473005061726976
-:1083B00074790044617461205061747465726E0058
-:1083C000547820466C6F7720436F6E74726F6C0028
-:1083D000506F7274204E756D6265720035300037D3
-:1083E0003500313130003133342E35003135300035
-:1083F00032303000333030003630300031323030FF
-:10840000003138303000323030300032343030001B
-:1084100033363030003438303000373230300039C5
-:108420003630300031392C3230300033382C343093
-:10843000300035362C3030300035372C36303000B7
-:1084400036342C3030300037362C38303000313173
-:10845000352C323030003720626974730038206266
-:1084600069747300312073746F7020626974003115
-:108470002E352073746F702062697473003220731C
-:10848000746F702062697473006E6F20706172691E
-:108490007479006F64642070617269747900657624
-:1084A000656E207061726974790073706163652014
-:1084B000706172697479006D61726B2070617269AC
-:1084C000747900436F6C756D6E7300426172626502
-:1084D0007220506F6C650055555555552E2E2E0047
-:1084E0004E6F6E6500586F6E2F586F66660043546E
-:1084F00053005072657373208020666F72206D6523
-:108500006E750028636F756E74696E672E2E2E2946
-:108510000000654E64204F6620436F4465000000F4
-:10852000000000000000000000000000000000004B
-:10853000000000000000000000000000000000003B
-:10854000000000000000000000000000000000002B
-:10855000000000000000000000000000000000001B
-:10856000000000000000000000000000000000000B
-:1085700000000000000000000000000000000000FB
-:1085800000000000000000000000000000000000EB
-:1085900000000000000000000000000000000000DB
-:1085A00000000000000000000000000000000000CB
-:1085B00000000000000000000000000000000000BB
-:1085C00000000000000000000000000000000000AB
-:1085D000000000000000000000000000000000009B
-:1085E000000000000000000000000000000000008B
-:1085F000000000000000000000000000000000007B
-:00000001FF
-/*  Intelliport II loadware */
-/* -31232 bytes read from ff.lod */
index 587ef5123cd8166f7906ccbeee768eaf3da8fd84..7ef637d7f3a56f22f1b9c4197cd6c94a483ef85b 100644 (file)
@@ -351,9 +351,7 @@ void afs_dispatch_give_up_callbacks(struct work_struct *work)
  */
 void afs_flush_callback_breaks(struct afs_server *server)
 {
-       cancel_delayed_work(&server->cb_break_work);
-       queue_delayed_work(afs_callback_update_worker,
-                          &server->cb_break_work, 0);
+       mod_delayed_work(afs_callback_update_worker, &server->cb_break_work, 0);
 }
 
 #if 0
index d59b7516e943ba2617f84e26088a2da42857d4e9..f342acf3547d0d06148335df01ab922939876b02 100644 (file)
@@ -285,12 +285,7 @@ static void afs_reap_server(struct work_struct *work)
                expiry = server->time_of_death + afs_server_timeout;
                if (expiry > now) {
                        delay = (expiry - now) * HZ;
-                       if (!queue_delayed_work(afs_wq, &afs_server_reaper,
-                                               delay)) {
-                               cancel_delayed_work(&afs_server_reaper);
-                               queue_delayed_work(afs_wq, &afs_server_reaper,
-                                                  delay);
-                       }
+                       mod_delayed_work(afs_wq, &afs_server_reaper, delay);
                        break;
                }
 
@@ -323,6 +318,5 @@ static void afs_reap_server(struct work_struct *work)
 void __exit afs_purge_servers(void)
 {
        afs_server_timeout = 0;
-       cancel_delayed_work(&afs_server_reaper);
-       queue_delayed_work(afs_wq, &afs_server_reaper, 0);
+       mod_delayed_work(afs_wq, &afs_server_reaper, 0);
 }
index 431984d2e372cfcb18984e46366011b12f72e9ee..57bcb1596530892e91ebf39fd12abfee0fe2dead 100644 (file)
@@ -561,12 +561,7 @@ static void afs_vlocation_reaper(struct work_struct *work)
                if (expiry > now) {
                        delay = (expiry - now) * HZ;
                        _debug("delay %lu", delay);
-                       if (!queue_delayed_work(afs_wq, &afs_vlocation_reap,
-                                               delay)) {
-                               cancel_delayed_work(&afs_vlocation_reap);
-                               queue_delayed_work(afs_wq, &afs_vlocation_reap,
-                                                  delay);
-                       }
+                       mod_delayed_work(afs_wq, &afs_vlocation_reap, delay);
                        break;
                }
 
@@ -614,13 +609,10 @@ void afs_vlocation_purge(void)
        spin_lock(&afs_vlocation_updates_lock);
        list_del_init(&afs_vlocation_updates);
        spin_unlock(&afs_vlocation_updates_lock);
-       cancel_delayed_work(&afs_vlocation_update);
-       queue_delayed_work(afs_vlocation_update_worker,
-                          &afs_vlocation_update, 0);
+       mod_delayed_work(afs_vlocation_update_worker, &afs_vlocation_update, 0);
        destroy_workqueue(afs_vlocation_update_worker);
 
-       cancel_delayed_work(&afs_vlocation_reap);
-       queue_delayed_work(afs_wq, &afs_vlocation_reap, 0);
+       mod_delayed_work(afs_wq, &afs_vlocation_reap, 0);
 }
 
 /*
index 1feb68ecef9509dd88a4323f3193845af6a84e15..8c0e56d92938c49ad61fef0bfb3888f47429ebc9 100644 (file)
@@ -94,25 +94,21 @@ static struct dentry *get_next_positive_subdir(struct dentry *prev,
 {
        struct autofs_sb_info *sbi = autofs4_sbi(root->d_sb);
        struct list_head *next;
-       struct dentry *p, *q;
+       struct dentry *q;
 
        spin_lock(&sbi->lookup_lock);
+       spin_lock(&root->d_lock);
 
-       if (prev == NULL) {
-               spin_lock(&root->d_lock);
+       if (prev)
+               next = prev->d_u.d_child.next;
+       else {
                prev = dget_dlock(root);
                next = prev->d_subdirs.next;
-               p = prev;
-               goto start;
        }
 
-       p = prev;
-       spin_lock(&p->d_lock);
-again:
-       next = p->d_u.d_child.next;
-start:
+cont:
        if (next == &root->d_subdirs) {
-               spin_unlock(&p->d_lock);
+               spin_unlock(&root->d_lock);
                spin_unlock(&sbi->lookup_lock);
                dput(prev);
                return NULL;
@@ -121,16 +117,15 @@ start:
        q = list_entry(next, struct dentry, d_u.d_child);
 
        spin_lock_nested(&q->d_lock, DENTRY_D_LOCK_NESTED);
-       /* Negative dentry - try next */
-       if (!simple_positive(q)) {
-               spin_unlock(&p->d_lock);
-               lock_set_subclass(&q->d_lock.dep_map, 0, _RET_IP_);
-               p = q;
-               goto again;
+       /* Already gone or negative dentry (under construction) - try next */
+       if (q->d_count == 0 || !simple_positive(q)) {
+               spin_unlock(&q->d_lock);
+               next = q->d_u.d_child.next;
+               goto cont;
        }
        dget_dlock(q);
        spin_unlock(&q->d_lock);
-       spin_unlock(&p->d_lock);
+       spin_unlock(&root->d_lock);
        spin_unlock(&sbi->lookup_lock);
 
        dput(prev);
index 73922abba832d0a41c1cb01bbf5bcc0fec1cb78b..dbb7a6c34ebe19dfdc7ca5e024d5bb82ba1786d3 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -73,7 +73,7 @@ static struct kmem_cache *bio_find_or_create_slab(unsigned int extra_size)
 {
        unsigned int sz = sizeof(struct bio) + extra_size;
        struct kmem_cache *slab = NULL;
-       struct bio_slab *bslab;
+       struct bio_slab *bslab, *new_bio_slabs;
        unsigned int i, entry = -1;
 
        mutex_lock(&bio_slab_lock);
@@ -97,11 +97,12 @@ static struct kmem_cache *bio_find_or_create_slab(unsigned int extra_size)
 
        if (bio_slab_nr == bio_slab_max && entry == -1) {
                bio_slab_max <<= 1;
-               bio_slabs = krealloc(bio_slabs,
-                                    bio_slab_max * sizeof(struct bio_slab),
-                                    GFP_KERNEL);
-               if (!bio_slabs)
+               new_bio_slabs = krealloc(bio_slabs,
+                                        bio_slab_max * sizeof(struct bio_slab),
+                                        GFP_KERNEL);
+               if (!new_bio_slabs)
                        goto out_unlock;
+               bio_slabs = new_bio_slabs;
        }
        if (entry == -1)
                entry = bio_slab_nr++;
@@ -1312,7 +1313,7 @@ EXPORT_SYMBOL(bio_copy_kern);
  * Note that this code is very hard to test under normal circumstances because
  * direct-io pins the pages with get_user_pages().  This makes
  * is_page_cache_freeable return false, and the VM will not clean the pages.
- * But other code (eg, pdflush) could clean the pages if they are mapped
+ * But other code (eg, flusher threads) could clean the pages if they are mapped
  * pagecache.
  *
  * Simply disabling the call to bio_set_pages_dirty() is a good way to test the
@@ -1500,7 +1501,7 @@ struct bio_pair *bio_split(struct bio *bi, int first_sectors)
        trace_block_split(bdev_get_queue(bi->bi_bdev), bi,
                                bi->bi_sector + first_sectors);
 
-       BUG_ON(bi->bi_vcnt != 1);
+       BUG_ON(bi->bi_vcnt != 1 && bi->bi_vcnt != 0);
        BUG_ON(bi->bi_idx != 0);
        atomic_set(&bp->cnt, 3);
        bp->error = 0;
@@ -1510,17 +1511,19 @@ struct bio_pair *bio_split(struct bio *bi, int first_sectors)
        bp->bio2.bi_size -= first_sectors << 9;
        bp->bio1.bi_size = first_sectors << 9;
 
-       bp->bv1 = bi->bi_io_vec[0];
-       bp->bv2 = bi->bi_io_vec[0];
-       bp->bv2.bv_offset += first_sectors << 9;
-       bp->bv2.bv_len -= first_sectors << 9;
-       bp->bv1.bv_len = first_sectors << 9;
+       if (bi->bi_vcnt != 0) {
+               bp->bv1 = bi->bi_io_vec[0];
+               bp->bv2 = bi->bi_io_vec[0];
+               bp->bv2.bv_offset += first_sectors << 9;
+               bp->bv2.bv_len -= first_sectors << 9;
+               bp->bv1.bv_len = first_sectors << 9;
 
-       bp->bio1.bi_io_vec = &bp->bv1;
-       bp->bio2.bi_io_vec = &bp->bv2;
+               bp->bio1.bi_io_vec = &bp->bv1;
+               bp->bio2.bi_io_vec = &bp->bv2;
 
-       bp->bio1.bi_max_vecs = 1;
-       bp->bio2.bi_max_vecs = 1;
+               bp->bio1.bi_max_vecs = 1;
+               bp->bio2.bi_max_vecs = 1;
+       }
 
        bp->bio1.bi_end_io = bio_pair_end_1;
        bp->bio2.bi_end_io = bio_pair_end_2;
index 1e519195d45bd1ab466f8b7ee12505f35a45d271..38e721b35d45388cb0febed8021a02277a4a2f1b 100644 (file)
@@ -1578,10 +1578,12 @@ ssize_t blkdev_aio_write(struct kiocb *iocb, const struct iovec *iov,
                         unsigned long nr_segs, loff_t pos)
 {
        struct file *file = iocb->ki_filp;
+       struct blk_plug plug;
        ssize_t ret;
 
        BUG_ON(iocb->ki_pos != pos);
 
+       blk_start_plug(&plug);
        ret = __generic_file_aio_write(iocb, iov, nr_segs, &iocb->ki_pos);
        if (ret > 0 || ret == -EIOCBQUEUED) {
                ssize_t err;
@@ -1590,6 +1592,7 @@ ssize_t blkdev_aio_write(struct kiocb *iocb, const struct iovec *iov,
                if (err < 0 && ret > 0)
                        ret = err;
        }
+       blk_finish_plug(&plug);
        return ret;
 }
 EXPORT_SYMBOL_GPL(blkdev_aio_write);
index 83baec24946d7449194e94893f92f918b14c79b5..6e8f416773d4b221713c30079eb1de1f732e5ded 100644 (file)
@@ -324,7 +324,8 @@ static noinline int add_async_extent(struct async_cow *cow,
  * If this code finds it can't get good compression, it puts an
  * entry onto the work queue to write the uncompressed bytes.  This
  * makes sure that both compressed inodes and uncompressed inodes
- * are written in the same order that pdflush sent them down.
+ * are written in the same order that the flusher thread sent them
+ * down.
  */
 static noinline int compress_file_range(struct inode *inode,
                                        struct page *locked_page,
index bc2f6ffff3cfb004099a5d4eb84f8a9aa688d7cd..7bb755677a220f71fd0540932c0c19565aec6a23 100644 (file)
@@ -664,10 +664,6 @@ static noinline int btrfs_mksubvol(struct path *parent,
        struct dentry *dentry;
        int error;
 
-       error = mnt_want_write(parent->mnt);
-       if (error)
-               return error;
-
        mutex_lock_nested(&dir->i_mutex, I_MUTEX_PARENT);
 
        dentry = lookup_one_len(name, parent->dentry, namelen);
@@ -703,7 +699,6 @@ out_dput:
        dput(dentry);
 out_unlock:
        mutex_unlock(&dir->i_mutex);
-       mnt_drop_write(parent->mnt);
        return error;
 }
 
index 643335a4fe3c6699a894c19d01e79bed9ef631c7..051c7fe551dd38bb7e391e5abaeff992f32b90f7 100644 (file)
@@ -596,7 +596,7 @@ void btrfs_start_ordered_extent(struct inode *inode,
        /*
         * pages in the range can be dirty, clean or writeback.  We
         * start IO on any dirty ones so the wait doesn't stall waiting
-        * for pdflush to find them
+        * for the flusher thread to find them
         */
        if (!test_bit(BTRFS_ORDERED_DIRECT, &entry->flags))
                filemap_fdatawrite_range(inode->i_mapping, start, end);
index 8c6e61d6eed5b754945930fbaaaaf21d6f98d028..f2eb24c477a3ca1c60ee95b51040354dd5a869ba 100644 (file)
@@ -100,10 +100,6 @@ static void __save_error_info(struct btrfs_fs_info *fs_info)
        fs_info->fs_state = BTRFS_SUPER_FLAG_ERROR;
 }
 
-/* NOTE:
- *     We move write_super stuff at umount in order to avoid deadlock
- *     for umount hold all lock.
- */
 static void save_error_info(struct btrfs_fs_info *fs_info)
 {
        __save_error_info(fs_info);
index b8708f994e679a559af68b90b3135b2b8fa2a9ac..e86ae04abe6a78e72dd86b3a813bce3107a8802e 100644 (file)
@@ -1744,10 +1744,6 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
 
        device->fs_devices = root->fs_info->fs_devices;
 
-       /*
-        * we don't want write_supers to jump in here with our device
-        * half setup
-        */
        mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
        list_add_rcu(&device->dev_list, &root->fs_info->fs_devices->devices);
        list_add(&device->dev_alloc_list,
index a08306a8bec911ac72dfc76bf6fbbf79760d8db1..802930179c2b49ec4627714cc0e0f623060034f7 100644 (file)
@@ -9,6 +9,7 @@ config CIFS
        select CRYPTO_ARC4
        select CRYPTO_ECB
        select CRYPTO_DES
+       select CRYPTO_SHA256
        help
          This is the client VFS module for the Common Internet File System
          (CIFS) protocol which is the successor to the Server Message Block
index feee9430927181bf9c729200709ef4a3f9df810d..aa0d68b086ebcf47cfcd84bf66cc9c8ecfdcc0dd 100644 (file)
@@ -17,4 +17,4 @@ cifs-$(CONFIG_CIFS_DFS_UPCALL) += dns_resolve.o cifs_dfs_ref.o
 cifs-$(CONFIG_CIFS_FSCACHE) += fscache.o cache.o
 
 cifs-$(CONFIG_CIFS_SMB2) += smb2ops.o smb2maperror.o smb2transport.o \
-                           smb2misc.o smb2pdu.o smb2inode.o
+                           smb2misc.o smb2pdu.o smb2inode.o smb2file.o
index 05f4dc263a23b791f1f1ab9e8e0ba0cb6831af19..2ee5c54797fa72633608eefd33dbe7fbfda27b58 100644 (file)
@@ -1222,7 +1222,7 @@ struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb,
        if (!open_file)
                return get_cifs_acl_by_path(cifs_sb, path, pacllen);
 
-       pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->netfid, pacllen);
+       pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->fid.netfid, pacllen);
        cifsFileInfo_put(open_file);
        return pntsd;
 }
index 6a0d741159f0d1474f6e51924b9cedc93b800d84..724738c1a56083dc2893a4b7ef56807394fc4290 100644 (file)
@@ -686,12 +686,17 @@ calc_seckey(struct cifs_ses *ses)
 void
 cifs_crypto_shash_release(struct TCP_Server_Info *server)
 {
+       if (server->secmech.hmacsha256)
+               crypto_free_shash(server->secmech.hmacsha256);
+
        if (server->secmech.md5)
                crypto_free_shash(server->secmech.md5);
 
        if (server->secmech.hmacmd5)
                crypto_free_shash(server->secmech.hmacmd5);
 
+       kfree(server->secmech.sdeschmacsha256);
+
        kfree(server->secmech.sdeschmacmd5);
 
        kfree(server->secmech.sdescmd5);
@@ -716,6 +721,13 @@ cifs_crypto_shash_allocate(struct TCP_Server_Info *server)
                goto crypto_allocate_md5_fail;
        }
 
+       server->secmech.hmacsha256 = crypto_alloc_shash("hmac(sha256)", 0, 0);
+       if (IS_ERR(server->secmech.hmacsha256)) {
+               cERROR(1, "could not allocate crypto hmacsha256\n");
+               rc = PTR_ERR(server->secmech.hmacsha256);
+               goto crypto_allocate_hmacsha256_fail;
+       }
+
        size = sizeof(struct shash_desc) +
                        crypto_shash_descsize(server->secmech.hmacmd5);
        server->secmech.sdeschmacmd5 = kmalloc(size, GFP_KERNEL);
@@ -727,7 +739,6 @@ cifs_crypto_shash_allocate(struct TCP_Server_Info *server)
        server->secmech.sdeschmacmd5->shash.tfm = server->secmech.hmacmd5;
        server->secmech.sdeschmacmd5->shash.flags = 0x0;
 
-
        size = sizeof(struct shash_desc) +
                        crypto_shash_descsize(server->secmech.md5);
        server->secmech.sdescmd5 = kmalloc(size, GFP_KERNEL);
@@ -739,12 +750,29 @@ cifs_crypto_shash_allocate(struct TCP_Server_Info *server)
        server->secmech.sdescmd5->shash.tfm = server->secmech.md5;
        server->secmech.sdescmd5->shash.flags = 0x0;
 
+       size = sizeof(struct shash_desc) +
+                       crypto_shash_descsize(server->secmech.hmacsha256);
+       server->secmech.sdeschmacsha256 = kmalloc(size, GFP_KERNEL);
+       if (!server->secmech.sdeschmacsha256) {
+               cERROR(1, "%s: Can't alloc hmacsha256\n", __func__);
+               rc = -ENOMEM;
+               goto crypto_allocate_hmacsha256_sdesc_fail;
+       }
+       server->secmech.sdeschmacsha256->shash.tfm = server->secmech.hmacsha256;
+       server->secmech.sdeschmacsha256->shash.flags = 0x0;
+
        return 0;
 
+crypto_allocate_hmacsha256_sdesc_fail:
+       kfree(server->secmech.sdescmd5);
+
 crypto_allocate_md5_sdesc_fail:
        kfree(server->secmech.sdeschmacmd5);
 
 crypto_allocate_hmacmd5_sdesc_fail:
+       crypto_free_shash(server->secmech.hmacsha256);
+
+crypto_allocate_hmacsha256_fail:
        crypto_free_shash(server->secmech.md5);
 
 crypto_allocate_md5_fail:
index db8a404a51dd03436653c0a52d0a6e5330bbe5bc..4dda4890d776152f2f7a67bc22a32724fdf5bac2 100644 (file)
@@ -51,7 +51,6 @@
 #ifdef CONFIG_CIFS_SMB2
 #include "smb2pdu.h"
 #endif
-#define CIFS_MAGIC_NUMBER 0xFF534D42   /* the first four bytes of SMB PDUs */
 
 int cifsFYI = 0;
 int cifsERROR = 1;
@@ -89,6 +88,10 @@ extern mempool_t *cifs_mid_poolp;
 
 struct workqueue_struct        *cifsiod_wq;
 
+#ifdef CONFIG_HIGHMEM
+DEFINE_MUTEX(cifs_kmap_mutex);
+#endif
+
 static int
 cifs_read_super(struct super_block *sb)
 {
@@ -160,13 +163,12 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
        struct super_block *sb = dentry->d_sb;
        struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
        struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
-       int rc = -EOPNOTSUPP;
+       struct TCP_Server_Info *server = tcon->ses->server;
        unsigned int xid;
+       int rc = 0;
 
        xid = get_xid();
 
-       buf->f_type = CIFS_MAGIC_NUMBER;
-
        /*
         * PATH_MAX may be too long - it would presumably be total path,
         * but note that some servers (includinng Samba 3) have a shorter
@@ -178,27 +180,8 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_files = 0;       /* undefined */
        buf->f_ffree = 0;       /* unlimited */
 
-       /*
-        * We could add a second check for a QFS Unix capability bit
-        */
-       if ((tcon->ses->capabilities & CAP_UNIX) &&
-           (CIFS_POSIX_EXTENSIONS & le64_to_cpu(tcon->fsUnixInfo.Capability)))
-               rc = CIFSSMBQFSPosixInfo(xid, tcon, buf);
-
-       /*
-        * Only need to call the old QFSInfo if failed on newer one,
-        * e.g. by OS/2.
-        **/
-       if (rc && (tcon->ses->capabilities & CAP_NT_SMBS))
-               rc = CIFSSMBQFSInfo(xid, tcon, buf);
-
-       /*
-        * Some old Windows servers also do not support level 103, retry with
-        * older level one if old server failed the previous call or we
-        * bypassed it because we detected that this was an older LANMAN sess
-        */
-       if (rc)
-               rc = SMBOldQFSInfo(xid, tcon, buf);
+       if (server->ops->queryfs)
+               rc = server->ops->queryfs(xid, tcon, buf);
 
        free_xid(xid);
        return 0;
index 977dc0e85ccbc76c02cdc1d87c3a3c8f2854bd9a..6e3be3e2ba7ea6d0a7f4d144543757a624ce1f16 100644 (file)
@@ -32,6 +32,8 @@
 #include "smb2pdu.h"
 #endif
 
+#define CIFS_MAGIC_NUMBER 0xFF534D42      /* the first four bytes of SMB PDUs */
+
 /*
  * The sizes of various internal tables and strings
  */
@@ -128,8 +130,10 @@ struct sdesc {
 struct cifs_secmech {
        struct crypto_shash *hmacmd5; /* hmac-md5 hash function */
        struct crypto_shash *md5; /* md5 hash function */
+       struct crypto_shash *hmacsha256; /* hmac-sha256 hash function */
        struct sdesc *sdeschmacmd5;  /* ctxt to generate ntlmv2 hash, CR1 */
        struct sdesc *sdescmd5; /* ctxt to generate cifs/smb signature */
+       struct sdesc *sdeschmacsha256;  /* ctxt to generate smb2 signature */
 };
 
 /* per smb session structure/fields */
@@ -171,6 +175,12 @@ struct cifs_tcon;
 struct dfs_info3_param;
 struct cifs_fattr;
 struct smb_vol;
+struct cifs_fid;
+struct cifs_readdata;
+struct cifs_writedata;
+struct cifs_io_parms;
+struct cifs_search_info;
+struct cifsInodeInfo;
 
 struct smb_version_operations {
        int (*send_cancel)(struct TCP_Server_Info *, void *,
@@ -212,6 +222,10 @@ struct smb_version_operations {
        bool (*need_neg)(struct TCP_Server_Info *);
        /* negotiate to the server */
        int (*negotiate)(const unsigned int, struct cifs_ses *);
+       /* set negotiated write size */
+       unsigned int (*negotiate_wsize)(struct cifs_tcon *, struct smb_vol *);
+       /* set negotiated read size */
+       unsigned int (*negotiate_rsize)(struct cifs_tcon *, struct smb_vol *);
        /* setup smb sessionn */
        int (*sess_setup)(const unsigned int, struct cifs_ses *,
                          const struct nls_table *);
@@ -235,10 +249,22 @@ struct smb_version_operations {
        int (*query_path_info)(const unsigned int, struct cifs_tcon *,
                               struct cifs_sb_info *, const char *,
                               FILE_ALL_INFO *, bool *);
+       /* query file data from the server */
+       int (*query_file_info)(const unsigned int, struct cifs_tcon *,
+                              struct cifs_fid *, FILE_ALL_INFO *);
        /* get server index number */
        int (*get_srv_inum)(const unsigned int, struct cifs_tcon *,
                            struct cifs_sb_info *, const char *,
                            u64 *uniqueid, FILE_ALL_INFO *);
+       /* set size by path */
+       int (*set_path_size)(const unsigned int, struct cifs_tcon *,
+                            const char *, __u64, struct cifs_sb_info *, bool);
+       /* set size by file handle */
+       int (*set_file_size)(const unsigned int, struct cifs_tcon *,
+                            struct cifsFileInfo *, __u64, bool);
+       /* set attributes */
+       int (*set_file_info)(struct inode *, const char *, FILE_BASIC_INFO *,
+                            const unsigned int);
        /* build a full path to the root of the mount */
        char * (*build_path_to_root)(struct smb_vol *, struct cifs_sb_info *,
                                     struct cifs_tcon *);
@@ -256,6 +282,62 @@ struct smb_version_operations {
        /* remove directory */
        int (*rmdir)(const unsigned int, struct cifs_tcon *, const char *,
                     struct cifs_sb_info *);
+       /* unlink file */
+       int (*unlink)(const unsigned int, struct cifs_tcon *, const char *,
+                     struct cifs_sb_info *);
+       /* open, rename and delete file */
+       int (*rename_pending_delete)(const char *, struct dentry *,
+                                    const unsigned int);
+       /* send rename request */
+       int (*rename)(const unsigned int, struct cifs_tcon *, const char *,
+                     const char *, struct cifs_sb_info *);
+       /* send create hardlink request */
+       int (*create_hardlink)(const unsigned int, struct cifs_tcon *,
+                              const char *, const char *,
+                              struct cifs_sb_info *);
+       /* open a file for non-posix mounts */
+       int (*open)(const unsigned int, struct cifs_tcon *, const char *, int,
+                   int, int, struct cifs_fid *, __u32 *, FILE_ALL_INFO *,
+                   struct cifs_sb_info *);
+       /* set fid protocol-specific info */
+       void (*set_fid)(struct cifsFileInfo *, struct cifs_fid *, __u32);
+       /* close a file */
+       int (*close)(const unsigned int, struct cifs_tcon *, struct cifs_fid *);
+       /* send a flush request to the server */
+       int (*flush)(const unsigned int, struct cifs_tcon *, struct cifs_fid *);
+       /* async read from the server */
+       int (*async_readv)(struct cifs_readdata *);
+       /* async write to the server */
+       int (*async_writev)(struct cifs_writedata *);
+       /* sync read from the server */
+       int (*sync_read)(const unsigned int, struct cifsFileInfo *,
+                        struct cifs_io_parms *, unsigned int *, char **,
+                        int *);
+       /* sync write to the server */
+       int (*sync_write)(const unsigned int, struct cifsFileInfo *,
+                         struct cifs_io_parms *, unsigned int *, struct kvec *,
+                         unsigned long);
+       /* open dir, start readdir */
+       int (*query_dir_first)(const unsigned int, struct cifs_tcon *,
+                              const char *, struct cifs_sb_info *,
+                              struct cifs_fid *, __u16,
+                              struct cifs_search_info *);
+       /* continue readdir */
+       int (*query_dir_next)(const unsigned int, struct cifs_tcon *,
+                             struct cifs_fid *,
+                             __u16, struct cifs_search_info *srch_inf);
+       /* close dir */
+       int (*close_dir)(const unsigned int, struct cifs_tcon *,
+                        struct cifs_fid *);
+       /* calculate a size of SMB message */
+       unsigned int (*calc_smb_size)(void *);
+       bool (*is_status_pending)(char *, struct TCP_Server_Info *, int);
+       /* send oplock break response */
+       int (*oplock_response)(struct cifs_tcon *, struct cifs_fid *,
+                              struct cifsInodeInfo *);
+       /* query remote filesystem */
+       int (*queryfs)(const unsigned int, struct cifs_tcon *,
+                      struct kstatfs *);
 };
 
 struct smb_version_values {
@@ -495,6 +577,90 @@ get_next_mid(struct TCP_Server_Info *server)
        return server->ops->get_next_mid(server);
 }
 
+/*
+ * When the server supports very large reads and writes via POSIX extensions,
+ * we can allow up to 2^24-1, minus the size of a READ/WRITE_AND_X header, not
+ * including the RFC1001 length.
+ *
+ * Note that this might make for "interesting" allocation problems during
+ * writeback however as we have to allocate an array of pointers for the
+ * pages. A 16M write means ~32kb page array with PAGE_CACHE_SIZE == 4096.
+ *
+ * For reads, there is a similar problem as we need to allocate an array
+ * of kvecs to handle the receive, though that should only need to be done
+ * once.
+ */
+#define CIFS_MAX_WSIZE ((1<<24) - 1 - sizeof(WRITE_REQ) + 4)
+#define CIFS_MAX_RSIZE ((1<<24) - sizeof(READ_RSP) + 4)
+
+/*
+ * When the server doesn't allow large posix writes, only allow a rsize/wsize
+ * of 2^17-1 minus the size of the call header. That allows for a read or
+ * write up to the maximum size described by RFC1002.
+ */
+#define CIFS_MAX_RFC1002_WSIZE ((1<<17) - 1 - sizeof(WRITE_REQ) + 4)
+#define CIFS_MAX_RFC1002_RSIZE ((1<<17) - 1 - sizeof(READ_RSP) + 4)
+
+/*
+ * The default wsize is 1M. find_get_pages seems to return a maximum of 256
+ * pages in a single call. With PAGE_CACHE_SIZE == 4k, this means we can fill
+ * a single wsize request with a single call.
+ */
+#define CIFS_DEFAULT_IOSIZE (1024 * 1024)
+
+/*
+ * Windows only supports a max of 60kb reads and 65535 byte writes. Default to
+ * those values when posix extensions aren't in force. In actuality here, we
+ * use 65536 to allow for a write that is a multiple of 4k. Most servers seem
+ * to be ok with the extra byte even though Windows doesn't send writes that
+ * are that large.
+ *
+ * Citation:
+ *
+ * http://blogs.msdn.com/b/openspecification/archive/2009/04/10/smb-maximum-transmit-buffer-size-and-performance-tuning.aspx
+ */
+#define CIFS_DEFAULT_NON_POSIX_RSIZE (60 * 1024)
+#define CIFS_DEFAULT_NON_POSIX_WSIZE (65536)
+
+/*
+ * On hosts with high memory, we can't currently support wsize/rsize that are
+ * larger than we can kmap at once. Cap the rsize/wsize at
+ * LAST_PKMAP * PAGE_SIZE. We'll never be able to fill a read or write request
+ * larger than that anyway.
+ */
+#ifdef CONFIG_HIGHMEM
+#define CIFS_KMAP_SIZE_LIMIT   (LAST_PKMAP * PAGE_CACHE_SIZE)
+#else /* CONFIG_HIGHMEM */
+#define CIFS_KMAP_SIZE_LIMIT   (1<<24)
+#endif /* CONFIG_HIGHMEM */
+
+#ifdef CONFIG_HIGHMEM
+/*
+ * On arches that have high memory, kmap address space is limited. By
+ * serializing the kmap operations on those arches, we ensure that we don't
+ * end up with a bunch of threads in writeback with partially mapped page
+ * arrays, stuck waiting for kmap to come back. That situation prevents
+ * progress and can deadlock.
+ */
+
+extern struct mutex cifs_kmap_mutex;
+
+static inline void
+cifs_kmap_lock(void)
+{
+       mutex_lock(&cifs_kmap_mutex);
+}
+
+static inline void
+cifs_kmap_unlock(void)
+{
+       mutex_unlock(&cifs_kmap_mutex);
+}
+#else /* !CONFIG_HIGHMEM */
+#define cifs_kmap_lock() do { ; } while (0)
+#define cifs_kmap_unlock() do { ; } while (0)
+#endif /* CONFIG_HIGHMEM */
+
 /*
  * Macros to allow the TCP_Server_Info->net field and related code to drop out
  * when CONFIG_NET_NS isn't set.
@@ -740,6 +906,14 @@ struct cifs_search_info {
        bool smallBuf:1; /* so we know which buf_release function to call */
 };
 
+struct cifs_fid {
+       __u16 netfid;
+#ifdef CONFIG_CIFS_SMB2
+       __u64 persistent_fid;   /* persist file id for smb2 */
+       __u64 volatile_fid;     /* volatile file id for smb2 */
+#endif
+};
+
 struct cifsFileInfo {
        struct list_head tlist; /* pointer to next fid owned by tcon */
        struct list_head flist; /* next fid (file instance) for this inode */
@@ -749,7 +923,7 @@ struct cifsFileInfo {
                                 */
        unsigned int uid;       /* allows finding which FileInfo structure */
        __u32 pid;              /* process id who opened file */
-       __u16 netfid;           /* file id from remote */
+       struct cifs_fid fid;    /* file id from remote */
        /* BB add lock scope info here if needed */ ;
        /* lock scope id (0 if none) */
        struct dentry *dentry;
@@ -765,12 +939,57 @@ struct cifsFileInfo {
 
 struct cifs_io_parms {
        __u16 netfid;
+#ifdef CONFIG_CIFS_SMB2
+       __u64 persistent_fid;   /* persist file id for smb2 */
+       __u64 volatile_fid;     /* volatile file id for smb2 */
+#endif
        __u32 pid;
        __u64 offset;
        unsigned int length;
        struct cifs_tcon *tcon;
 };
 
+struct cifs_readdata;
+
+/* asynchronous read support */
+struct cifs_readdata {
+       struct kref                     refcount;
+       struct list_head                list;
+       struct completion               done;
+       struct cifsFileInfo             *cfile;
+       struct address_space            *mapping;
+       __u64                           offset;
+       unsigned int                    bytes;
+       pid_t                           pid;
+       int                             result;
+       struct list_head                pages;
+       struct work_struct              work;
+       int (*marshal_iov) (struct cifs_readdata *rdata,
+                           unsigned int remaining);
+       unsigned int                    nr_iov;
+       struct kvec                     iov[1];
+};
+
+struct cifs_writedata;
+
+/* asynchronous write support */
+struct cifs_writedata {
+       struct kref                     refcount;
+       struct list_head                list;
+       struct completion               done;
+       enum writeback_sync_modes       sync_mode;
+       struct work_struct              work;
+       struct cifsFileInfo             *cfile;
+       __u64                           offset;
+       pid_t                           pid;
+       unsigned int                    bytes;
+       int                             result;
+       void (*marshal_iov) (struct kvec *iov,
+                            struct cifs_writedata *wdata);
+       unsigned int                    nr_pages;
+       struct page                     *pages[1];
+};
+
 /*
  * Take a reference on the file private data. Must be called with
  * cifs_file_list_lock held.
index f1bbf8305d3a75a114b998eabe17901e9825cdb9..c7ad9a8cf82a01f37b4ca1e01f135db4f5d822db 100644 (file)
@@ -65,6 +65,7 @@ extern char *cifs_compose_mount_options(const char *sb_mountdata,
 extern struct mid_q_entry *AllocMidQEntry(const struct smb_hdr *smb_buffer,
                                        struct TCP_Server_Info *server);
 extern void DeleteMidQEntry(struct mid_q_entry *midEntry);
+extern void cifs_delete_mid(struct mid_q_entry *mid);
 extern void cifs_wake_up_task(struct mid_q_entry *mid);
 extern int cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
                           unsigned int nvec, mid_receive_t *receive,
@@ -99,7 +100,7 @@ extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
                            unsigned int bytes_written);
 extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, bool);
 extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool);
-extern unsigned int smbCalcSize(struct smb_hdr *ptr);
+extern unsigned int smbCalcSize(void *buf);
 extern int decode_negTokenInit(unsigned char *security_blob, int length,
                        struct TCP_Server_Info *server);
 extern int cifs_convert_address(struct sockaddr *dst, const char *src, int len);
@@ -121,9 +122,10 @@ extern struct timespec cnvrtDosUnixTm(__le16 le_date, __le16 le_time,
                                      int offset);
 extern void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock);
 
-extern struct cifsFileInfo *cifs_new_fileinfo(__u16 fileHandle,
-                               struct file *file, struct tcon_link *tlink,
-                               __u32 oplock);
+extern struct cifsFileInfo *cifs_new_fileinfo(struct cifs_fid *fid,
+                                             struct file *file,
+                                             struct tcon_link *tlink,
+                                             __u32 oplock);
 extern int cifs_posix_open(char *full_path, struct inode **inode,
                           struct super_block *sb, int mode,
                           unsigned int f_flags, __u32 *oplock, __u16 *netfid,
@@ -136,14 +138,17 @@ extern void cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr);
 extern struct inode *cifs_iget(struct super_block *sb,
                               struct cifs_fattr *fattr);
 
-extern int cifs_get_file_info(struct file *filp);
 extern int cifs_get_inode_info(struct inode **inode, const char *full_path,
                               FILE_ALL_INFO *data, struct super_block *sb,
                               int xid, const __u16 *fid);
-extern int cifs_get_file_info_unix(struct file *filp);
 extern int cifs_get_inode_info_unix(struct inode **pinode,
                        const unsigned char *search_path,
                        struct super_block *sb, unsigned int xid);
+extern int cifs_set_file_info(struct inode *inode, struct iattr *attrs,
+                             unsigned int xid, char *full_path, __u32 dosattr);
+extern int cifs_rename_pending_delete(const char *full_path,
+                                     struct dentry *dentry,
+                                     const unsigned int xid);
 extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb,
                              struct cifs_fattr *fattr, struct inode *inode,
                              const char *path, const __u16 *pfid);
@@ -265,13 +270,11 @@ extern int CIFSSMBSetAttrLegacy(unsigned int xid, struct cifs_tcon *tcon,
                        const struct nls_table *nls_codepage);
 #endif /* possibly unneeded function */
 extern int CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
-                       const char *fileName, __u64 size,
-                       bool setAllocationSizeFlag,
-                       const struct nls_table *nls_codepage,
-                       int remap_special_chars);
+                        const char *file_name, __u64 size,
+                        struct cifs_sb_info *cifs_sb, bool set_allocation);
 extern int CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
-                        __u64 size, __u16 fileHandle, __u32 opener_pid,
-                       bool AllocSizeFlag);
+                             struct cifsFileInfo *cfile, __u64 size,
+                             bool set_allocation);
 
 struct cifs_unix_set_info_args {
        __u64   ctime;
@@ -303,22 +306,17 @@ extern int CIFSPOSIXDelFile(const unsigned int xid, struct cifs_tcon *tcon,
                        const struct nls_table *nls_codepage,
                        int remap_special_chars);
 extern int CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon,
-                       const char *name,
-                       const struct nls_table *nls_codepage,
-                       int remap_special_chars);
+                         const char *name, struct cifs_sb_info *cifs_sb);
 extern int CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
-                       const char *fromName, const char *toName,
-                       const struct nls_table *nls_codepage,
-                       int remap_special_chars);
+                        const char *from_name, const char *to_name,
+                        struct cifs_sb_info *cifs_sb);
 extern int CIFSSMBRenameOpenFile(const unsigned int xid, struct cifs_tcon *tcon,
                                 int netfid, const char *target_name,
                                 const struct nls_table *nls_codepage,
                                 int remap_special_chars);
-extern int CIFSCreateHardLink(const unsigned int xid,
-                       struct cifs_tcon *tcon,
-                       const char *fromName, const char *toName,
-                       const struct nls_table *nls_codepage,
-                       int remap_special_chars);
+extern int CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
+                             const char *from_name, const char *to_name,
+                             struct cifs_sb_info *cifs_sb);
 extern int CIFSUnixCreateHardLink(const unsigned int xid,
                        struct cifs_tcon *tcon,
                        const char *fromName, const char *toName,
@@ -367,8 +365,7 @@ extern int CIFSSMBWrite(const unsigned int xid, struct cifs_io_parms *io_parms,
                        unsigned int *nbytes, const char *buf,
                        const char __user *ubuf, const int long_op);
 extern int CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
-                       unsigned int *nbytes, struct kvec *iov, const int nvec,
-                       const int long_op);
+                       unsigned int *nbytes, struct kvec *iov, const int nvec);
 extern int CIFSGetSrvInodeNumber(const unsigned int xid, struct cifs_tcon *tcon,
                                 const char *search_name, __u64 *inode_number,
                                 const struct nls_table *nls_codepage,
@@ -462,45 +459,9 @@ extern int E_md4hash(const unsigned char *passwd, unsigned char *p16,
 extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8,
                        unsigned char *p24);
 
-/* asynchronous read support */
-struct cifs_readdata {
-       struct kref                     refcount;
-       struct list_head                list;
-       struct completion               done;
-       struct cifsFileInfo             *cfile;
-       struct address_space            *mapping;
-       __u64                           offset;
-       unsigned int                    bytes;
-       pid_t                           pid;
-       int                             result;
-       struct list_head                pages;
-       struct work_struct              work;
-       int (*marshal_iov) (struct cifs_readdata *rdata,
-                           unsigned int remaining);
-       unsigned int                    nr_iov;
-       struct kvec                     iov[1];
-};
-
 void cifs_readdata_release(struct kref *refcount);
 int cifs_async_readv(struct cifs_readdata *rdata);
-
-/* asynchronous write support */
-struct cifs_writedata {
-       struct kref                     refcount;
-       struct list_head                list;
-       struct completion               done;
-       enum writeback_sync_modes       sync_mode;
-       struct work_struct              work;
-       struct cifsFileInfo             *cfile;
-       __u64                           offset;
-       pid_t                           pid;
-       unsigned int                    bytes;
-       int                             result;
-       void (*marshal_iov) (struct kvec *iov,
-                            struct cifs_writedata *wdata);
-       unsigned int                    nr_pages;
-       struct page                     *pages[1];
-};
+int cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid);
 
 int cifs_async_writev(struct cifs_writedata *wdata);
 void cifs_writev_complete(struct work_struct *work);
index 074923ce593d7d53da6ae010128dffc8c080815b..c4f43cf671dc2f3bd5b14649f4647d1b94f73608 100644 (file)
@@ -86,32 +86,6 @@ static struct {
 #endif /* CONFIG_CIFS_WEAK_PW_HASH */
 #endif /* CIFS_POSIX */
 
-#ifdef CONFIG_HIGHMEM
-/*
- * On arches that have high memory, kmap address space is limited. By
- * serializing the kmap operations on those arches, we ensure that we don't
- * end up with a bunch of threads in writeback with partially mapped page
- * arrays, stuck waiting for kmap to come back. That situation prevents
- * progress and can deadlock.
- */
-static DEFINE_MUTEX(cifs_kmap_mutex);
-
-static inline void
-cifs_kmap_lock(void)
-{
-       mutex_lock(&cifs_kmap_mutex);
-}
-
-static inline void
-cifs_kmap_unlock(void)
-{
-       mutex_unlock(&cifs_kmap_mutex);
-}
-#else /* !CONFIG_HIGHMEM */
-#define cifs_kmap_lock() do { ; } while(0)
-#define cifs_kmap_unlock() do { ; } while(0)
-#endif /* CONFIG_HIGHMEM */
-
 /*
  * Mark as invalid, all open files on tree connections since they
  * were closed when session to server was lost.
@@ -902,15 +876,15 @@ PsxDelete:
 }
 
 int
-CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon,
-              const char *fileName, const struct nls_table *nls_codepage,
-              int remap)
+CIFSSMBDelFile(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
+              struct cifs_sb_info *cifs_sb)
 {
        DELETE_FILE_REQ *pSMB = NULL;
        DELETE_FILE_RSP *pSMBr = NULL;
        int rc = 0;
        int bytes_returned;
        int name_len;
+       int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
 
 DelFileRetry:
        rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
@@ -919,15 +893,15 @@ DelFileRetry:
                return rc;
 
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
-               name_len =
-                   cifsConvertToUTF16((__le16 *) pSMB->fileName, fileName,
-                                      PATH_MAX, nls_codepage, remap);
+               name_len = cifsConvertToUTF16((__le16 *) pSMB->fileName, name,
+                                             PATH_MAX, cifs_sb->local_nls,
+                                             remap);
                name_len++;     /* trailing null */
                name_len *= 2;
        } else {                /* BB improve check for buffer overruns BB */
-               name_len = strnlen(fileName, PATH_MAX);
+               name_len = strnlen(name, PATH_MAX);
                name_len++;     /* trailing null */
-               strncpy(pSMB->fileName, fileName, name_len);
+               strncpy(pSMB->fileName, name, name_len);
        }
        pSMB->SearchAttributes =
            cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
@@ -1440,7 +1414,7 @@ cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid)
        return 0;
 }
 
-static int
+int
 cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid)
 {
        int length, len;
@@ -1576,9 +1550,14 @@ cifs_readv_callback(struct mid_q_entry *mid)
                /* result already set, check signature */
                if (server->sec_mode &
                    (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
-                       if (cifs_verify_signature(rdata->iov, rdata->nr_iov,
-                                         server, mid->sequence_number + 1))
-                               cERROR(1, "Unexpected SMB signature");
+                       int rc = 0;
+
+                       rc = cifs_verify_signature(rdata->iov, rdata->nr_iov,
+                                                  server,
+                                                  mid->sequence_number + 1);
+                       if (rc)
+                               cERROR(1, "SMB signature verification returned "
+                                      "error = %d", rc);
                }
                /* FIXME: should this be counted toward the initiating task? */
                task_io_account_read(rdata->bytes);
@@ -1627,7 +1606,7 @@ cifs_async_readv(struct cifs_readdata *rdata)
        smb->hdr.PidHigh = cpu_to_le16((__u16)(rdata->pid >> 16));
 
        smb->AndXCommand = 0xFF;        /* none */
-       smb->Fid = rdata->cfile->netfid;
+       smb->Fid = rdata->cfile->fid.netfid;
        smb->OffsetLow = cpu_to_le32(rdata->offset & 0xFFFFFFFF);
        if (wct == 12)
                smb->OffsetHigh = cpu_to_le32(rdata->offset >> 32);
@@ -1921,6 +1900,7 @@ cifs_writev_requeue(struct cifs_writedata *wdata)
 {
        int i, rc;
        struct inode *inode = wdata->cfile->dentry->d_inode;
+       struct TCP_Server_Info *server;
 
        for (i = 0; i < wdata->nr_pages; i++) {
                lock_page(wdata->pages[i]);
@@ -1928,7 +1908,8 @@ cifs_writev_requeue(struct cifs_writedata *wdata)
        }
 
        do {
-               rc = cifs_async_writev(wdata);
+               server = tlink_tcon(wdata->cfile->tlink)->ses->server;
+               rc = server->ops->async_writev(wdata);
        } while (rc == -EAGAIN);
 
        for (i = 0; i < wdata->nr_pages; i++) {
@@ -2079,7 +2060,7 @@ cifs_async_writev(struct cifs_writedata *wdata)
        smb->hdr.PidHigh = cpu_to_le16((__u16)(wdata->pid >> 16));
 
        smb->AndXCommand = 0xFF;        /* none */
-       smb->Fid = wdata->cfile->netfid;
+       smb->Fid = wdata->cfile->fid.netfid;
        smb->OffsetLow = cpu_to_le32(wdata->offset & 0xFFFFFFFF);
        if (wct == 14)
                smb->OffsetHigh = cpu_to_le32(wdata->offset >> 32);
@@ -2142,8 +2123,7 @@ async_writev_out:
 
 int
 CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
-             unsigned int *nbytes, struct kvec *iov, int n_vec,
-             const int long_op)
+             unsigned int *nbytes, struct kvec *iov, int n_vec)
 {
        int rc = -EACCES;
        WRITE_REQ *pSMB = NULL;
@@ -2214,8 +2194,7 @@ CIFSSMBWrite2(const unsigned int xid, struct cifs_io_parms *io_parms,
                iov[0].iov_len = smb_hdr_len + 8;
 
 
-       rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type,
-                         long_op);
+       rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, 0);
        cifs_stats_inc(&tcon->stats.cifs_stats.num_writes);
        if (rc) {
                cFYI(1, "Send error Write2 = %d", rc);
@@ -2552,8 +2531,8 @@ CIFSSMBFlush(const unsigned int xid, struct cifs_tcon *tcon, int smb_file_id)
 
 int
 CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
-             const char *fromName, const char *toName,
-             const struct nls_table *nls_codepage, int remap)
+             const char *from_name, const char *to_name,
+             struct cifs_sb_info *cifs_sb)
 {
        int rc = 0;
        RENAME_REQ *pSMB = NULL;
@@ -2561,6 +2540,7 @@ CIFSSMBRename(const unsigned int xid, struct cifs_tcon *tcon,
        int bytes_returned;
        int name_len, name_len2;
        __u16 count;
+       int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
 
        cFYI(1, "In CIFSSMBRename");
 renameRetry:
@@ -2575,9 +2555,9 @@ renameRetry:
                        ATTR_DIRECTORY);
 
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
-               name_len =
-                   cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName,
-                                      PATH_MAX, nls_codepage, remap);
+               name_len = cifsConvertToUTF16((__le16 *) pSMB->OldFileName,
+                                             from_name, PATH_MAX,
+                                             cifs_sb->local_nls, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
                pSMB->OldFileName[name_len] = 0x04;     /* pad */
@@ -2585,17 +2565,18 @@ renameRetry:
                pSMB->OldFileName[name_len + 1] = 0x00;
                name_len2 =
                    cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
-                                      toName, PATH_MAX, nls_codepage, remap);
+                                      to_name, PATH_MAX, cifs_sb->local_nls,
+                                      remap);
                name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
                name_len2 *= 2; /* convert to bytes */
        } else {        /* BB improve the check for buffer overruns BB */
-               name_len = strnlen(fromName, PATH_MAX);
+               name_len = strnlen(from_name, PATH_MAX);
                name_len++;     /* trailing null */
-               strncpy(pSMB->OldFileName, fromName, name_len);
-               name_len2 = strnlen(toName, PATH_MAX);
+               strncpy(pSMB->OldFileName, from_name, name_len);
+               name_len2 = strnlen(to_name, PATH_MAX);
                name_len2++;    /* trailing null */
                pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
-               strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
+               strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
                name_len2++;    /* trailing null */
                name_len2++;    /* signature byte */
        }
@@ -2943,8 +2924,8 @@ createHardLinkRetry:
 
 int
 CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
-                  const char *fromName, const char *toName,
-                  const struct nls_table *nls_codepage, int remap)
+                  const char *from_name, const char *to_name,
+                  struct cifs_sb_info *cifs_sb)
 {
        int rc = 0;
        NT_RENAME_REQ *pSMB = NULL;
@@ -2952,6 +2933,7 @@ CIFSCreateHardLink(const unsigned int xid, struct cifs_tcon *tcon,
        int bytes_returned;
        int name_len, name_len2;
        __u16 count;
+       int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
 
        cFYI(1, "In CIFSCreateHardLink");
 winCreateHardLinkRetry:
@@ -2971,8 +2953,8 @@ winCreateHardLinkRetry:
 
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len =
-                   cifsConvertToUTF16((__le16 *) pSMB->OldFileName, fromName,
-                                      PATH_MAX, nls_codepage, remap);
+                   cifsConvertToUTF16((__le16 *) pSMB->OldFileName, from_name,
+                                      PATH_MAX, cifs_sb->local_nls, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
 
@@ -2981,17 +2963,18 @@ winCreateHardLinkRetry:
                pSMB->OldFileName[name_len + 1] = 0x00; /* pad */
                name_len2 =
                    cifsConvertToUTF16((__le16 *)&pSMB->OldFileName[name_len+2],
-                                      toName, PATH_MAX, nls_codepage, remap);
+                                      to_name, PATH_MAX, cifs_sb->local_nls,
+                                      remap);
                name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
                name_len2 *= 2; /* convert to bytes */
        } else {        /* BB improve the check for buffer overruns BB */
-               name_len = strnlen(fromName, PATH_MAX);
+               name_len = strnlen(from_name, PATH_MAX);
                name_len++;     /* trailing null */
-               strncpy(pSMB->OldFileName, fromName, name_len);
-               name_len2 = strnlen(toName, PATH_MAX);
+               strncpy(pSMB->OldFileName, from_name, name_len);
+               name_len2 = strnlen(to_name, PATH_MAX);
                name_len2++;    /* trailing null */
                pSMB->OldFileName[name_len] = 0x04;     /* 2nd buffer format */
-               strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
+               strncpy(&pSMB->OldFileName[name_len + 1], to_name, name_len2);
                name_len2++;    /* trailing null */
                name_len2++;    /* signature byte */
        }
@@ -5412,16 +5395,16 @@ QFSPosixRetry:
 }
 
 
-/* We can not use write of zero bytes trick to
-   set file size due to need for large file support.  Also note that
-   this SetPathInfo is preferred to SetFileInfo based method in next
-   routine which is only needed to work around a sharing violation bug
-   in Samba which this routine can run into */
-
+/*
+ * We can not use write of zero bytes trick to set file size due to need for
+ * large file support. Also note that this SetPathInfo is preferred to
+ * SetFileInfo based method in next routine which is only needed to work around
+ * a sharing violation bugin Samba which this routine can run into.
+ */
 int
 CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
-             const char *fileName, __u64 size, bool SetAllocation,
-             const struct nls_table *nls_codepage, int remap)
+             const char *file_name, __u64 size, struct cifs_sb_info *cifs_sb,
+             bool set_allocation)
 {
        struct smb_com_transaction2_spi_req *pSMB = NULL;
        struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
@@ -5429,6 +5412,8 @@ CIFSSMBSetEOF(const unsigned int xid, struct cifs_tcon *tcon,
        int name_len;
        int rc = 0;
        int bytes_returned = 0;
+       int remap = cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR;
+
        __u16 params, byte_count, data_count, param_offset, offset;
 
        cFYI(1, "In SetEOF");
@@ -5440,14 +5425,14 @@ SetEOFRetry:
 
        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
                name_len =
-                   cifsConvertToUTF16((__le16 *) pSMB->FileName, fileName,
-                                      PATH_MAX, nls_codepage, remap);
+                   cifsConvertToUTF16((__le16 *) pSMB->FileName, file_name,
+                                      PATH_MAX, cifs_sb->local_nls, remap);
                name_len++;     /* trailing null */
                name_len *= 2;
        } else {        /* BB improve the check for buffer overruns BB */
-               name_len = strnlen(fileName, PATH_MAX);
+               name_len = strnlen(file_name, PATH_MAX);
                name_len++;     /* trailing null */
-               strncpy(pSMB->FileName, fileName, name_len);
+               strncpy(pSMB->FileName, file_name, name_len);
        }
        params = 6 + name_len;
        data_count = sizeof(struct file_end_of_file_info);
@@ -5461,7 +5446,7 @@ SetEOFRetry:
        param_offset = offsetof(struct smb_com_transaction2_spi_req,
                                InformationLevel) - 4;
        offset = param_offset + params;
-       if (SetAllocation) {
+       if (set_allocation) {
                if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
                        pSMB->InformationLevel =
                                cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
@@ -5508,8 +5493,8 @@ SetEOFRetry:
 }
 
 int
-CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon, __u64 size,
-                  __u16 fid, __u32 pid_of_opener, bool SetAllocation)
+CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon,
+                  struct cifsFileInfo *cfile, __u64 size, bool set_allocation)
 {
        struct smb_com_transaction2_sfi_req *pSMB  = NULL;
        struct file_end_of_file_info *parm_data;
@@ -5523,8 +5508,8 @@ CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon, __u64 size,
        if (rc)
                return rc;
 
-       pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
-       pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
+       pSMB->hdr.Pid = cpu_to_le16((__u16)cfile->pid);
+       pSMB->hdr.PidHigh = cpu_to_le16((__u16)(cfile->pid >> 16));
 
        params = 6;
        pSMB->MaxSetupCount = 0;
@@ -5553,8 +5538,8 @@ CIFSSMBSetFileSize(const unsigned int xid, struct cifs_tcon *tcon, __u64 size,
                                + offset);
        pSMB->DataOffset = cpu_to_le16(offset);
        parm_data->FileSize = cpu_to_le64(size);
-       pSMB->Fid = fid;
-       if (SetAllocation) {
+       pSMB->Fid = cfile->fid.netfid;
+       if (set_allocation) {
                if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
                        pSMB->InformationLevel =
                                cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
index 6df6fa14cba8e9f19fd5d686f17af6bdf928a48a..549409b1c7765e7090f896b58abac06ca8c80ebf 100644 (file)
@@ -819,6 +819,10 @@ standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid)
                cifs_dump_mem("Bad SMB: ", buf,
                        min_t(unsigned int, server->total_read, 48));
 
+       if (server->ops->is_status_pending &&
+           server->ops->is_status_pending(buf, server, length))
+               return -1;
+
        if (!mid)
                return length;
 
@@ -3261,146 +3265,6 @@ void cifs_setup_cifs_sb(struct smb_vol *pvolume_info,
                           "mount option supported");
 }
 
-/*
- * When the server supports very large reads and writes via POSIX extensions,
- * we can allow up to 2^24-1, minus the size of a READ/WRITE_AND_X header, not
- * including the RFC1001 length.
- *
- * Note that this might make for "interesting" allocation problems during
- * writeback however as we have to allocate an array of pointers for the
- * pages. A 16M write means ~32kb page array with PAGE_CACHE_SIZE == 4096.
- *
- * For reads, there is a similar problem as we need to allocate an array
- * of kvecs to handle the receive, though that should only need to be done
- * once.
- */
-#define CIFS_MAX_WSIZE ((1<<24) - 1 - sizeof(WRITE_REQ) + 4)
-#define CIFS_MAX_RSIZE ((1<<24) - sizeof(READ_RSP) + 4)
-
-/*
- * When the server doesn't allow large posix writes, only allow a rsize/wsize
- * of 2^17-1 minus the size of the call header. That allows for a read or
- * write up to the maximum size described by RFC1002.
- */
-#define CIFS_MAX_RFC1002_WSIZE ((1<<17) - 1 - sizeof(WRITE_REQ) + 4)
-#define CIFS_MAX_RFC1002_RSIZE ((1<<17) - 1 - sizeof(READ_RSP) + 4)
-
-/*
- * The default wsize is 1M. find_get_pages seems to return a maximum of 256
- * pages in a single call. With PAGE_CACHE_SIZE == 4k, this means we can fill
- * a single wsize request with a single call.
- */
-#define CIFS_DEFAULT_IOSIZE (1024 * 1024)
-
-/*
- * Windows only supports a max of 60kb reads and 65535 byte writes. Default to
- * those values when posix extensions aren't in force. In actuality here, we
- * use 65536 to allow for a write that is a multiple of 4k. Most servers seem
- * to be ok with the extra byte even though Windows doesn't send writes that
- * are that large.
- *
- * Citation:
- *
- * http://blogs.msdn.com/b/openspecification/archive/2009/04/10/smb-maximum-transmit-buffer-size-and-performance-tuning.aspx
- */
-#define CIFS_DEFAULT_NON_POSIX_RSIZE (60 * 1024)
-#define CIFS_DEFAULT_NON_POSIX_WSIZE (65536)
-
-/*
- * On hosts with high memory, we can't currently support wsize/rsize that are
- * larger than we can kmap at once. Cap the rsize/wsize at
- * LAST_PKMAP * PAGE_SIZE. We'll never be able to fill a read or write request
- * larger than that anyway.
- */
-#ifdef CONFIG_HIGHMEM
-#define CIFS_KMAP_SIZE_LIMIT   (LAST_PKMAP * PAGE_CACHE_SIZE)
-#else /* CONFIG_HIGHMEM */
-#define CIFS_KMAP_SIZE_LIMIT   (1<<24)
-#endif /* CONFIG_HIGHMEM */
-
-static unsigned int
-cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info)
-{
-       __u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
-       struct TCP_Server_Info *server = tcon->ses->server;
-       unsigned int wsize;
-
-       /* start with specified wsize, or default */
-       if (pvolume_info->wsize)
-               wsize = pvolume_info->wsize;
-       else if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_WRITE_CAP))
-               wsize = CIFS_DEFAULT_IOSIZE;
-       else
-               wsize = CIFS_DEFAULT_NON_POSIX_WSIZE;
-
-       /* can server support 24-bit write sizes? (via UNIX extensions) */
-       if (!tcon->unix_ext || !(unix_cap & CIFS_UNIX_LARGE_WRITE_CAP))
-               wsize = min_t(unsigned int, wsize, CIFS_MAX_RFC1002_WSIZE);
-
-       /*
-        * no CAP_LARGE_WRITE_X or is signing enabled without CAP_UNIX set?
-        * Limit it to max buffer offered by the server, minus the size of the
-        * WRITEX header, not including the 4 byte RFC1001 length.
-        */
-       if (!(server->capabilities & CAP_LARGE_WRITE_X) ||
-           (!(server->capabilities & CAP_UNIX) &&
-            (server->sec_mode & (SECMODE_SIGN_ENABLED|SECMODE_SIGN_REQUIRED))))
-               wsize = min_t(unsigned int, wsize,
-                               server->maxBuf - sizeof(WRITE_REQ) + 4);
-
-       /* limit to the amount that we can kmap at once */
-       wsize = min_t(unsigned int, wsize, CIFS_KMAP_SIZE_LIMIT);
-
-       /* hard limit of CIFS_MAX_WSIZE */
-       wsize = min_t(unsigned int, wsize, CIFS_MAX_WSIZE);
-
-       return wsize;
-}
-
-static unsigned int
-cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *pvolume_info)
-{
-       __u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
-       struct TCP_Server_Info *server = tcon->ses->server;
-       unsigned int rsize, defsize;
-
-       /*
-        * Set default value...
-        *
-        * HACK alert! Ancient servers have very small buffers. Even though
-        * MS-CIFS indicates that servers are only limited by the client's
-        * bufsize for reads, testing against win98se shows that it throws
-        * INVALID_PARAMETER errors if you try to request too large a read.
-        * OS/2 just sends back short reads.
-        *
-        * If the server doesn't advertise CAP_LARGE_READ_X, then assume that
-        * it can't handle a read request larger than its MaxBufferSize either.
-        */
-       if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_READ_CAP))
-               defsize = CIFS_DEFAULT_IOSIZE;
-       else if (server->capabilities & CAP_LARGE_READ_X)
-               defsize = CIFS_DEFAULT_NON_POSIX_RSIZE;
-       else
-               defsize = server->maxBuf - sizeof(READ_RSP);
-
-       rsize = pvolume_info->rsize ? pvolume_info->rsize : defsize;
-
-       /*
-        * no CAP_LARGE_READ_X? Then MS-CIFS states that we must limit this to
-        * the client's MaxBufferSize.
-        */
-       if (!(server->capabilities & CAP_LARGE_READ_X))
-               rsize = min_t(unsigned int, CIFSMaxBufSize, rsize);
-
-       /* limit to the amount that we can kmap at once */
-       rsize = min_t(unsigned int, rsize, CIFS_KMAP_SIZE_LIMIT);
-
-       /* hard limit of CIFS_MAX_RSIZE */
-       rsize = min_t(unsigned int, rsize, CIFS_MAX_RSIZE);
-
-       return rsize;
-}
-
 static void
 cleanup_volume_info_contents(struct smb_vol *volume_info)
 {
@@ -3651,8 +3515,8 @@ try_mount_again:
        if (!tcon->ipc && server->ops->qfs_tcon)
                server->ops->qfs_tcon(xid, tcon);
 
-       cifs_sb->wsize = cifs_negotiate_wsize(tcon, volume_info);
-       cifs_sb->rsize = cifs_negotiate_rsize(tcon, volume_info);
+       cifs_sb->wsize = server->ops->negotiate_wsize(tcon, volume_info);
+       cifs_sb->rsize = server->ops->negotiate_rsize(tcon, volume_info);
 
        /* tune readahead according to rsize */
        cifs_sb->bdi.ra_pages = cifs_sb->rsize / PAGE_CACHE_SIZE;
index cbe709ad6663485cdcec49dbce9d1156de510c5d..7265e5a28643d24e9da788a9cb3c653e6fc413be 100644 (file)
@@ -160,17 +160,18 @@ check_name(struct dentry *direntry)
 static int
 cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
               struct tcon_link *tlink, unsigned oflags, umode_t mode,
-              __u32 *oplock, __u16 *fileHandle, int *created)
+              __u32 *oplock, struct cifs_fid *fid, int *created)
 {
        int rc = -ENOENT;
        int create_options = CREATE_NOT_DIR;
-       int desiredAccess;
+       int desired_access;
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
        struct cifs_tcon *tcon = tlink_tcon(tlink);
        char *full_path = NULL;
        FILE_ALL_INFO *buf = NULL;
        struct inode *newinode = NULL;
        int disposition;
+       struct TCP_Server_Info *server = tcon->ses->server;
 
        *oplock = 0;
        if (tcon->ses->server->oplocks)
@@ -185,8 +186,8 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
        if (tcon->unix_ext && cap_unix(tcon->ses) && !tcon->broken_posix_open &&
            (CIFS_UNIX_POSIX_PATH_OPS_CAP &
                        le64_to_cpu(tcon->fsUnixInfo.Capability))) {
-               rc = cifs_posix_open(full_path, &newinode,
-                       inode->i_sb, mode, oflags, oplock, fileHandle, xid);
+               rc = cifs_posix_open(full_path, &newinode, inode->i_sb, mode,
+                                    oflags, oplock, &fid->netfid, xid);
                switch (rc) {
                case 0:
                        if (newinode == NULL) {
@@ -202,7 +203,7 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
                                 * close it and proceed as if it were a normal
                                 * lookup.
                                 */
-                               CIFSSMBClose(xid, tcon, *fileHandle);
+                               CIFSSMBClose(xid, tcon, fid->netfid);
                                goto cifs_create_get_file_info;
                        }
                        /* success, no need to query */
@@ -244,11 +245,11 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
                 */
        }
 
-       desiredAccess = 0;
+       desired_access = 0;
        if (OPEN_FMODE(oflags) & FMODE_READ)
-               desiredAccess |= GENERIC_READ; /* is this too little? */
+               desired_access |= GENERIC_READ; /* is this too little? */
        if (OPEN_FMODE(oflags) & FMODE_WRITE)
-               desiredAccess |= GENERIC_WRITE;
+               desired_access |= GENERIC_WRITE;
 
        disposition = FILE_OVERWRITE_IF;
        if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
@@ -260,8 +261,15 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
        else
                cFYI(1, "Create flag not set in create function");
 
-       /* BB add processing to set equivalent of mode - e.g. via CreateX with
-          ACLs */
+       /*
+        * BB add processing to set equivalent of mode - e.g. via CreateX with
+        * ACLs
+        */
+
+       if (!server->ops->open) {
+               rc = -ENOSYS;
+               goto out;
+       }
 
        buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
        if (buf == NULL) {
@@ -279,28 +287,18 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
        if (backup_cred(cifs_sb))
                create_options |= CREATE_OPEN_BACKUP_INTENT;
 
-       if (tcon->ses->capabilities & CAP_NT_SMBS)
-               rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
-                        desiredAccess, create_options,
-                        fileHandle, oplock, buf, cifs_sb->local_nls,
-                        cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
-       else
-               rc = -EIO; /* no NT SMB support fall into legacy open below */
-
-       if (rc == -EIO) {
-               /* old server, retry the open legacy style */
-               rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
-                       desiredAccess, create_options,
-                       fileHandle, oplock, buf, cifs_sb->local_nls,
-                       cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
-       }
+       rc = server->ops->open(xid, tcon, full_path, disposition,
+                              desired_access, create_options, fid, oplock,
+                              buf, cifs_sb);
        if (rc) {
                cFYI(1, "cifs_create returned 0x%x", rc);
                goto out;
        }
 
-       /* If Open reported that we actually created a file
-          then we now have to set the mode if possible */
+       /*
+        * If Open reported that we actually created a file then we now have to
+        * set the mode if possible.
+        */
        if ((tcon->unix_ext) && (*oplock & CIFS_CREATE_ACTION)) {
                struct cifs_unix_set_info_args args = {
                                .mode   = mode,
@@ -321,11 +319,13 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
                        args.uid = NO_CHANGE_64;
                        args.gid = NO_CHANGE_64;
                }
-               CIFSSMBUnixSetFileInfo(xid, tcon, &args, *fileHandle,
-                                       current->tgid);
+               CIFSSMBUnixSetFileInfo(xid, tcon, &args, fid->netfid,
+                                      current->tgid);
        } else {
-               /* BB implement mode setting via Windows security
-                  descriptors e.g. */
+               /*
+                * BB implement mode setting via Windows security
+                * descriptors e.g.
+                */
                /* CIFSSMBWinSetPerms(xid,tcon,path,mode,-1,-1,nls);*/
 
                /* Could set r/o dos attribute if mode & 0222 == 0 */
@@ -334,11 +334,11 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,
 cifs_create_get_file_info:
        /* server might mask mode so we have to query for it */
        if (tcon->unix_ext)
-               rc = cifs_get_inode_info_unix(&newinode, full_path,
-                                             inode->i_sb, xid);
+               rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb,
+                                             xid);
        else {
-               rc = cifs_get_inode_info(&newinode, full_path, buf,
-                                        inode->i_sb, xid, fileHandle);
+               rc = cifs_get_inode_info(&newinode, full_path, buf, inode->i_sb,
+                                        xid, &fid->netfid);
                if (newinode) {
                        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
                                newinode->i_mode = mode;
@@ -364,7 +364,7 @@ cifs_create_set_dentry:
        /* ENOENT for create?  How weird... */
        rc = -ENOENT;
        if (!newinode) {
-               CIFSSMBClose(xid, tcon, *fileHandle);
+               CIFSSMBClose(xid, tcon, fid->netfid);
                goto out;
        }
        rc = 0;
@@ -384,11 +384,13 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
        unsigned int xid;
        struct tcon_link *tlink;
        struct cifs_tcon *tcon;
-       __u16 fileHandle;
+       struct TCP_Server_Info *server;
+       struct cifs_fid fid;
        __u32 oplock;
-       struct cifsFileInfo *pfile_info;
+       struct cifsFileInfo *file_info;
 
-       /* Posix open is only called (at lookup time) for file create now.  For
+       /*
+        * Posix open is only called (at lookup time) for file create now. For
         * opens (rather than creates), because we do not know if it is a file
         * or directory yet, and current Samba no longer allows us to do posix
         * open on dirs, we could end up wasting an open call on what turns out
@@ -420,22 +422,25 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
                goto out_free_xid;
 
        tcon = tlink_tcon(tlink);
+       server = tcon->ses->server;
 
        rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode,
-                           &oplock, &fileHandle, opened);
+                           &oplock, &fid, opened);
 
        if (rc)
                goto out;
 
        rc = finish_open(file, direntry, generic_file_open, opened);
        if (rc) {
-               CIFSSMBClose(xid, tcon, fileHandle);
+               if (server->ops->close)
+                       server->ops->close(xid, tcon, &fid);
                goto out;
        }
 
-       pfile_info = cifs_new_fileinfo(fileHandle, file, tlink, oplock);
-       if (pfile_info == NULL) {
-               CIFSSMBClose(xid, tcon, fileHandle);
+       file_info = cifs_new_fileinfo(&fid, file, tlink, oplock);
+       if (file_info == NULL) {
+               if (server->ops->close)
+                       server->ops->close(xid, tcon, &fid);
                rc = -ENOMEM;
        }
 
@@ -460,7 +465,9 @@ int cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
         */
        unsigned oflags = O_EXCL | O_CREAT | O_RDWR;
        struct tcon_link *tlink;
-       __u16 fileHandle;
+       struct cifs_tcon *tcon;
+       struct TCP_Server_Info *server;
+       struct cifs_fid fid;
        __u32 oplock;
        int created = FILE_CREATED;
 
@@ -473,9 +480,11 @@ int cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
                goto out_free_xid;
 
        rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode,
-                           &oplock, &fileHandle, &created);
-       if (!rc)
-               CIFSSMBClose(xid, tlink_tcon(tlink), fileHandle);
+                           &oplock, &fid, &created);
+       tcon = tlink_tcon(tlink);
+       server = tcon->ses->server;
+       if (!rc && server->ops->close)
+               server->ops->close(xid, tcon, &fid);
 
        cifs_put_tlink(tlink);
 out_free_xid:
index 9154192b0683e368a521ddf118961e1cdd592355..404949a06b018823a184af17b8365a47149b97fc 100644 (file)
@@ -169,16 +169,19 @@ posix_open_ret:
 
 static int
 cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
-            struct cifs_tcon *tcon, unsigned int f_flags, __u32 *poplock,
-            __u16 *pnetfid, unsigned int xid)
+            struct cifs_tcon *tcon, unsigned int f_flags, __u32 *oplock,
+            struct cifs_fid *fid, unsigned int xid)
 {
        int rc;
-       int desiredAccess;
+       int desired_access;
        int disposition;
        int create_options = CREATE_NOT_DIR;
        FILE_ALL_INFO *buf;
 
-       desiredAccess = cifs_convert_flags(f_flags);
+       if (!tcon->ses->server->ops->open)
+               return -ENOSYS;
+
+       desired_access = cifs_convert_flags(f_flags);
 
 /*********************************************************************
  *  open flag mapping table:
@@ -215,16 +218,9 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
        if (backup_cred(cifs_sb))
                create_options |= CREATE_OPEN_BACKUP_INTENT;
 
-       if (tcon->ses->capabilities & CAP_NT_SMBS)
-               rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
-                        desiredAccess, create_options, pnetfid, poplock, buf,
-                        cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
-                                & CIFS_MOUNT_MAP_SPECIAL_CHR);
-       else
-               rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
-                       desiredAccess, CREATE_NOT_DIR, pnetfid, poplock, buf,
-                       cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
-                               & CIFS_MOUNT_MAP_SPECIAL_CHR);
+       rc = tcon->ses->server->ops->open(xid, tcon, full_path, disposition,
+                                         desired_access, create_options, fid,
+                                         oplock, buf, cifs_sb);
 
        if (rc)
                goto out;
@@ -234,7 +230,7 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb,
                                              xid);
        else
                rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb,
-                                        xid, pnetfid);
+                                        xid, &fid->netfid);
 
 out:
        kfree(buf);
@@ -242,44 +238,41 @@ out:
 }
 
 struct cifsFileInfo *
-cifs_new_fileinfo(__u16 fileHandle, struct file *file,
+cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
                  struct tcon_link *tlink, __u32 oplock)
 {
        struct dentry *dentry = file->f_path.dentry;
        struct inode *inode = dentry->d_inode;
-       struct cifsInodeInfo *pCifsInode = CIFS_I(inode);
-       struct cifsFileInfo *pCifsFile;
-
-       pCifsFile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
-       if (pCifsFile == NULL)
-               return pCifsFile;
-
-       pCifsFile->count = 1;
-       pCifsFile->netfid = fileHandle;
-       pCifsFile->pid = current->tgid;
-       pCifsFile->uid = current_fsuid();
-       pCifsFile->dentry = dget(dentry);
-       pCifsFile->f_flags = file->f_flags;
-       pCifsFile->invalidHandle = false;
-       pCifsFile->tlink = cifs_get_tlink(tlink);
-       mutex_init(&pCifsFile->fh_mutex);
-       INIT_WORK(&pCifsFile->oplock_break, cifs_oplock_break);
-       INIT_LIST_HEAD(&pCifsFile->llist);
+       struct cifsInodeInfo *cinode = CIFS_I(inode);
+       struct cifsFileInfo *cfile;
+
+       cfile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
+       if (cfile == NULL)
+               return cfile;
+
+       cfile->count = 1;
+       cfile->pid = current->tgid;
+       cfile->uid = current_fsuid();
+       cfile->dentry = dget(dentry);
+       cfile->f_flags = file->f_flags;
+       cfile->invalidHandle = false;
+       cfile->tlink = cifs_get_tlink(tlink);
+       mutex_init(&cfile->fh_mutex);
+       INIT_WORK(&cfile->oplock_break, cifs_oplock_break);
+       INIT_LIST_HEAD(&cfile->llist);
+       tlink_tcon(tlink)->ses->server->ops->set_fid(cfile, fid, oplock);
 
        spin_lock(&cifs_file_list_lock);
-       list_add(&pCifsFile->tlist, &(tlink_tcon(tlink)->openFileList));
+       list_add(&cfile->tlist, &(tlink_tcon(tlink)->openFileList));
        /* if readable file instance put first in list*/
        if (file->f_mode & FMODE_READ)
-               list_add(&pCifsFile->flist, &pCifsInode->openFileList);
+               list_add(&cfile->flist, &cinode->openFileList);
        else
-               list_add_tail(&pCifsFile->flist, &pCifsInode->openFileList);
+               list_add_tail(&cfile->flist, &cinode->openFileList);
        spin_unlock(&cifs_file_list_lock);
 
-       cifs_set_oplock_level(pCifsInode, oplock);
-       pCifsInode->can_cache_brlcks = pCifsInode->clientCanCacheAll;
-
-       file->private_data = pCifsFile;
-       return pCifsFile;
+       file->private_data = cfile;
+       return cfile;
 }
 
 static void cifs_del_lock_waiters(struct cifsLockInfo *lock);
@@ -319,13 +312,13 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
        if (list_empty(&cifsi->openFileList)) {
                cFYI(1, "closing last open instance for inode %p",
                        cifs_file->dentry->d_inode);
-
-               /* in strict cache mode we need invalidate mapping on the last
-                  close  because it may cause a error when we open this file
-                  again and get at least level II oplock */
+               /*
+                * In strict cache mode we need invalidate mapping on the last
+                * close  because it may cause a error when we open this file
+                * again and get at least level II oplock.
+                */
                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_STRICT_IO)
                        CIFS_I(inode)->invalid_mapping = true;
-
                cifs_set_oplock_level(cifsi, 0);
        }
        spin_unlock(&cifs_file_list_lock);
@@ -333,10 +326,13 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file)
        cancel_work_sync(&cifs_file->oplock_break);
 
        if (!tcon->need_reconnect && !cifs_file->invalidHandle) {
+               struct TCP_Server_Info *server = tcon->ses->server;
                unsigned int xid;
-               int rc;
+               int rc = -ENOSYS;
+
                xid = get_xid();
-               rc = CIFSSMBClose(xid, tcon, cifs_file->netfid);
+               if (server->ops->close)
+                       rc = server->ops->close(xid, tcon, &cifs_file->fid);
                free_xid(xid);
        }
 
@@ -364,10 +360,10 @@ int cifs_open(struct inode *inode, struct file *file)
        struct cifs_sb_info *cifs_sb;
        struct cifs_tcon *tcon;
        struct tcon_link *tlink;
-       struct cifsFileInfo *pCifsFile = NULL;
+       struct cifsFileInfo *cfile = NULL;
        char *full_path = NULL;
        bool posix_open_ok = false;
-       __u16 netfid;
+       struct cifs_fid fid;
 
        xid = get_xid();
 
@@ -399,7 +395,7 @@ int cifs_open(struct inode *inode, struct file *file)
                /* can not refresh inode info since size could be stale */
                rc = cifs_posix_open(full_path, &inode, inode->i_sb,
                                cifs_sb->mnt_file_mode /* ignored */,
-                               file->f_flags, &oplock, &netfid, xid);
+                               file->f_flags, &oplock, &fid.netfid, xid);
                if (rc == 0) {
                        cFYI(1, "posix open succeeded");
                        posix_open_ok = true;
@@ -415,20 +411,23 @@ int cifs_open(struct inode *inode, struct file *file)
                } else if ((rc != -EIO) && (rc != -EREMOTE) &&
                         (rc != -EOPNOTSUPP)) /* path not found or net err */
                        goto out;
-               /* else fallthrough to retry open the old way on network i/o
-                  or DFS errors */
+               /*
+                * Else fallthrough to retry open the old way on network i/o
+                * or DFS errors.
+                */
        }
 
        if (!posix_open_ok) {
                rc = cifs_nt_open(full_path, inode, cifs_sb, tcon,
-                                 file->f_flags, &oplock, &netfid, xid);
+                                 file->f_flags, &oplock, &fid, xid);
                if (rc)
                        goto out;
        }
 
-       pCifsFile = cifs_new_fileinfo(netfid, file, tlink, oplock);
-       if (pCifsFile == NULL) {
-               CIFSSMBClose(xid, tcon, netfid);
+       cfile = cifs_new_fileinfo(&fid, file, tlink, oplock);
+       if (cfile == NULL) {
+               if (tcon->ses->server->ops->close)
+                       tcon->ses->server->ops->close(xid, tcon, &fid);
                rc = -ENOMEM;
                goto out;
        }
@@ -436,8 +435,10 @@ int cifs_open(struct inode *inode, struct file *file)
        cifs_fscache_set_inode_cookie(inode, file);
 
        if ((oplock & CIFS_CREATE_ACTION) && !posix_open_ok && tcon->unix_ext) {
-               /* time to set mode which we can not set earlier due to
-                  problems creating new read-only files */
+               /*
+                * Time to set mode which we can not set earlier due to
+                * problems creating new read-only files.
+                */
                struct cifs_unix_set_info_args args = {
                        .mode   = inode->i_mode,
                        .uid    = NO_CHANGE_64,
@@ -447,8 +448,8 @@ int cifs_open(struct inode *inode, struct file *file)
                        .mtime  = NO_CHANGE_64,
                        .device = 0,
                };
-               CIFSSMBUnixSetFileInfo(xid, tcon, &args, netfid,
-                                       pCifsFile->pid);
+               CIFSSMBUnixSetFileInfo(xid, tcon, &args, fid.netfid,
+                                      cfile->pid);
        }
 
 out:
@@ -458,59 +459,66 @@ out:
        return rc;
 }
 
-/* Try to reacquire byte range locks that were released when session */
-/* to server was lost */
+/*
+ * Try to reacquire byte range locks that were released when session
+ * to server was lost
+ */
 static int cifs_relock_file(struct cifsFileInfo *cifsFile)
 {
        int rc = 0;
 
-/* BB list all locks open on this file and relock */
+       /* BB list all locks open on this file and relock */
 
        return rc;
 }
 
-static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
+static int
+cifs_reopen_file(struct cifsFileInfo *cfile, bool can_flush)
 {
        int rc = -EACCES;
        unsigned int xid;
        __u32 oplock;
        struct cifs_sb_info *cifs_sb;
        struct cifs_tcon *tcon;
-       struct cifsInodeInfo *pCifsInode;
+       struct TCP_Server_Info *server;
+       struct cifsInodeInfo *cinode;
        struct inode *inode;
        char *full_path = NULL;
-       int desiredAccess;
+       int desired_access;
        int disposition = FILE_OPEN;
        int create_options = CREATE_NOT_DIR;
-       __u16 netfid;
+       struct cifs_fid fid;
 
        xid = get_xid();
-       mutex_lock(&pCifsFile->fh_mutex);
-       if (!pCifsFile->invalidHandle) {
-               mutex_unlock(&pCifsFile->fh_mutex);
+       mutex_lock(&cfile->fh_mutex);
+       if (!cfile->invalidHandle) {
+               mutex_unlock(&cfile->fh_mutex);
                rc = 0;
                free_xid(xid);
                return rc;
        }
 
-       inode = pCifsFile->dentry->d_inode;
+       inode = cfile->dentry->d_inode;
        cifs_sb = CIFS_SB(inode->i_sb);
-       tcon = tlink_tcon(pCifsFile->tlink);
+       tcon = tlink_tcon(cfile->tlink);
+       server = tcon->ses->server;
 
-/* can not grab rename sem here because various ops, including
-   those that already have the rename sem can end up causing writepage
-   to get called and if the server was down that means we end up here,
-   and we can never tell if the caller already has the rename_sem */
-       full_path = build_path_from_dentry(pCifsFile->dentry);
+       /*
+        * Can not grab rename sem here because various ops, including those
+        * that already have the rename sem can end up causing writepage to get
+        * called and if the server was down that means we end up here, and we
+        * can never tell if the caller already has the rename_sem.
+        */
+       full_path = build_path_from_dentry(cfile->dentry);
        if (full_path == NULL) {
                rc = -ENOMEM;
-               mutex_unlock(&pCifsFile->fh_mutex);
+               mutex_unlock(&cfile->fh_mutex);
                free_xid(xid);
                return rc;
        }
 
-       cFYI(1, "inode = 0x%p file flags 0x%x for %s",
-                inode, pCifsFile->f_flags, full_path);
+       cFYI(1, "inode = 0x%p file flags 0x%x for %s", inode, cfile->f_flags,
+            full_path);
 
        if (tcon->ses->server->oplocks)
                oplock = REQ_OPLOCK;
@@ -524,69 +532,69 @@ static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush)
                 * O_CREAT, O_EXCL and O_TRUNC already had their effect on the
                 * original open. Must mask them off for a reopen.
                 */
-               unsigned int oflags = pCifsFile->f_flags &
+               unsigned int oflags = cfile->f_flags &
                                                ~(O_CREAT | O_EXCL | O_TRUNC);
 
                rc = cifs_posix_open(full_path, NULL, inode->i_sb,
-                               cifs_sb->mnt_file_mode /* ignored */,
-                               oflags, &oplock, &netfid, xid);
+                                    cifs_sb->mnt_file_mode /* ignored */,
+                                    oflags, &oplock, &fid.netfid, xid);
                if (rc == 0) {
                        cFYI(1, "posix reopen succeeded");
                        goto reopen_success;
                }
-               /* fallthrough to retry open the old way on errors, especially
-                  in the reconnect path it is important to retry hard */
+               /*
+                * fallthrough to retry open the old way on errors, especially
+                * in the reconnect path it is important to retry hard
+                */
        }
 
-       desiredAccess = cifs_convert_flags(pCifsFile->f_flags);
+       desired_access = cifs_convert_flags(cfile->f_flags);
 
        if (backup_cred(cifs_sb))
                create_options |= CREATE_OPEN_BACKUP_INTENT;
 
-       /* Can not refresh inode by passing in file_info buf to be returned
-          by SMBOpen and then calling get_inode_info with returned buf
-          since file might have write behind data that needs to be flushed
-          and server version of file size can be stale. If we knew for sure
-          that inode was not dirty locally we could do this */
-
-       rc = CIFSSMBOpen(xid, tcon, full_path, disposition, desiredAccess,
-                        create_options, &netfid, &oplock, NULL,
-                        cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
-                               CIFS_MOUNT_MAP_SPECIAL_CHR);
+       /*
+        * Can not refresh inode by passing in file_info buf to be returned by
+        * CIFSSMBOpen and then calling get_inode_info with returned buf since
+        * file might have write behind data that needs to be flushed and server
+        * version of file size can be stale. If we knew for sure that inode was
+        * not dirty locally we could do this.
+        */
+       rc = server->ops->open(xid, tcon, full_path, disposition,
+                              desired_access, create_options, &fid, &oplock,
+                              NULL, cifs_sb);
        if (rc) {
-               mutex_unlock(&pCifsFile->fh_mutex);
-               cFYI(1, "cifs_open returned 0x%x", rc);
+               mutex_unlock(&cfile->fh_mutex);
+               cFYI(1, "cifs_reopen returned 0x%x", rc);
                cFYI(1, "oplock: %d", oplock);
                goto reopen_error_exit;
        }
 
 reopen_success:
-       pCifsFile->netfid = netfid;
-       pCifsFile->invalidHandle = false;
-       mutex_unlock(&pCifsFile->fh_mutex);
-       pCifsInode = CIFS_I(inode);
+       cfile->invalidHandle = false;
+       mutex_unlock(&cfile->fh_mutex);
+       cinode = CIFS_I(inode);
 
        if (can_flush) {
                rc = filemap_write_and_wait(inode->i_mapping);
                mapping_set_error(inode->i_mapping, rc);
 
                if (tcon->unix_ext)
-                       rc = cifs_get_inode_info_unix(&inode,
-                               full_path, inode->i_sb, xid);
+                       rc = cifs_get_inode_info_unix(&inode, full_path,
+                                                     inode->i_sb, xid);
                else
-                       rc = cifs_get_inode_info(&inode,
-                               full_path, NULL, inode->i_sb,
-                               xid, NULL);
-       } /* else we are writing out data to server already
-            and could deadlock if we tried to flush data, and
-            since we do not know if we have data that would
-            invalidate the current end of file on the server
-            we can not go to the server to get the new inod
-            info */
-
-       cifs_set_oplock_level(pCifsInode, oplock);
+                       rc = cifs_get_inode_info(&inode, full_path, NULL,
+                                                inode->i_sb, xid, NULL);
+       }
+       /*
+        * Else we are writing out data to server already and could deadlock if
+        * we tried to flush data, and since we do not know if we have data that
+        * would invalidate the current end of file on the server we can not go
+        * to the server to get the new inode info.
+        */
 
-       cifs_relock_file(pCifsFile);
+       server->ops->set_fid(cfile, &fid, oplock);
+       cifs_relock_file(cfile);
 
 reopen_error_exit:
        kfree(full_path);
@@ -609,42 +617,48 @@ int cifs_closedir(struct inode *inode, struct file *file)
 {
        int rc = 0;
        unsigned int xid;
-       struct cifsFileInfo *pCFileStruct = file->private_data;
-       char *ptmp;
+       struct cifsFileInfo *cfile = file->private_data;
+       struct cifs_tcon *tcon;
+       struct TCP_Server_Info *server;
+       char *buf;
 
        cFYI(1, "Closedir inode = 0x%p", inode);
 
+       if (cfile == NULL)
+               return rc;
+
        xid = get_xid();
+       tcon = tlink_tcon(cfile->tlink);
+       server = tcon->ses->server;
 
-       if (pCFileStruct) {
-               struct cifs_tcon *pTcon = tlink_tcon(pCFileStruct->tlink);
+       cFYI(1, "Freeing private data in close dir");
+       spin_lock(&cifs_file_list_lock);
+       if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) {
+               cfile->invalidHandle = true;
+               spin_unlock(&cifs_file_list_lock);
+               if (server->ops->close_dir)
+                       rc = server->ops->close_dir(xid, tcon, &cfile->fid);
+               else
+                       rc = -ENOSYS;
+               cFYI(1, "Closing uncompleted readdir with rc %d", rc);
+               /* not much we can do if it fails anyway, ignore rc */
+               rc = 0;
+       } else
+               spin_unlock(&cifs_file_list_lock);
 
-               cFYI(1, "Freeing private data in close dir");
-               spin_lock(&cifs_file_list_lock);
-               if (!pCFileStruct->srch_inf.endOfSearch &&
-                   !pCFileStruct->invalidHandle) {
-                       pCFileStruct->invalidHandle = true;
-                       spin_unlock(&cifs_file_list_lock);
-                       rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);
-                       cFYI(1, "Closing uncompleted readdir with rc %d",
-                                rc);
-                       /* not much we can do if it fails anyway, ignore rc */
-                       rc = 0;
-               } else
-                       spin_unlock(&cifs_file_list_lock);
-               ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;
-               if (ptmp) {
-                       cFYI(1, "closedir free smb buf in srch struct");
-                       pCFileStruct->srch_inf.ntwrk_buf_start = NULL;
-                       if (pCFileStruct->srch_inf.smallBuf)
-                               cifs_small_buf_release(ptmp);
-                       else
-                               cifs_buf_release(ptmp);
-               }
-               cifs_put_tlink(pCFileStruct->tlink);
-               kfree(file->private_data);
-               file->private_data = NULL;
+       buf = cfile->srch_inf.ntwrk_buf_start;
+       if (buf) {
+               cFYI(1, "closedir free smb buf in srch struct");
+               cfile->srch_inf.ntwrk_buf_start = NULL;
+               if (cfile->srch_inf.smallBuf)
+                       cifs_small_buf_release(buf);
+               else
+                       cifs_buf_release(buf);
        }
+
+       cifs_put_tlink(cfile->tlink);
+       kfree(file->private_data);
+       file->private_data = NULL;
        /* BB can we lock the filestruct while this is going on? */
        free_xid(xid);
        return rc;
@@ -932,7 +946,8 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
                        cur->OffsetLow = cpu_to_le32((u32)li->offset);
                        cur->OffsetHigh = cpu_to_le32((u32)(li->offset>>32));
                        if (++num == max_num) {
-                               stored_rc = cifs_lockv(xid, tcon, cfile->netfid,
+                               stored_rc = cifs_lockv(xid, tcon,
+                                                      cfile->fid.netfid,
                                                       (__u8)li->type, 0, num,
                                                       buf);
                                if (stored_rc)
@@ -944,7 +959,7 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
                }
 
                if (num) {
-                       stored_rc = cifs_lockv(xid, tcon, cfile->netfid,
+                       stored_rc = cifs_lockv(xid, tcon, cfile->fid.netfid,
                                               (__u8)types[i], 0, num, buf);
                        if (stored_rc)
                                rc = stored_rc;
@@ -1038,7 +1053,7 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile)
                        type = CIFS_WRLCK;
                lck = list_entry(el, struct lock_to_push, llist);
                lck->pid = flock->fl_pid;
-               lck->netfid = cfile->netfid;
+               lck->netfid = cfile->fid.netfid;
                lck->length = length;
                lck->type = type;
                lck->offset = flock->fl_start;
@@ -1137,7 +1152,7 @@ static int
 cifs_mandatory_lock(unsigned int xid, struct cifsFileInfo *cfile, __u64 offset,
                    __u64 length, __u32 type, int lock, int unlock, bool wait)
 {
-       return CIFSSMBLock(xid, tlink_tcon(cfile->tlink), cfile->netfid,
+       return CIFSSMBLock(xid, tlink_tcon(cfile->tlink), cfile->fid.netfid,
                           current->tgid, length, offset, unlock, lock,
                           (__u8)type, wait, 0);
 }
@@ -1151,7 +1166,7 @@ cifs_getlk(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;
-       __u16 netfid = cfile->netfid;
+       __u16 netfid = cfile->fid.netfid;
 
        if (posix_lck) {
                int posix_lock_type;
@@ -1295,7 +1310,8 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
                         */
                        list_move(&li->llist, &tmp_llist);
                        if (++num == max_num) {
-                               stored_rc = cifs_lockv(xid, tcon, cfile->netfid,
+                               stored_rc = cifs_lockv(xid, tcon,
+                                                      cfile->fid.netfid,
                                                       li->type, num, 0, buf);
                                if (stored_rc) {
                                        /*
@@ -1318,7 +1334,7 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
                                cur++;
                }
                if (num) {
-                       stored_rc = cifs_lockv(xid, tcon, cfile->netfid,
+                       stored_rc = cifs_lockv(xid, tcon, cfile->fid.netfid,
                                               types[i], num, 0, buf);
                        if (stored_rc) {
                                cifs_move_llist(&tmp_llist, &cfile->llist);
@@ -1343,7 +1359,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;
-       __u16 netfid = cfile->netfid;
+       __u16 netfid = cfile->fid.netfid;
 
        if (posix_lck) {
                int posix_lock_type;
@@ -1423,7 +1439,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock)
                        tcon->ses->server);
 
        cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
-       netfid = cfile->netfid;
+       netfid = cfile->fid.netfid;
        cinode = CIFS_I(file->f_path.dentry->d_inode);
 
        if (cap_unix(tcon->ses) &&
@@ -1469,15 +1485,16 @@ cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset,
                cifsi->server_eof = end_of_write;
 }
 
-static ssize_t cifs_write(struct cifsFileInfo *open_file, __u32 pid,
-                         const char *write_data, size_t write_size,
-                         loff_t *poffset)
+static ssize_t
+cifs_write(struct cifsFileInfo *open_file, __u32 pid, const char *write_data,
+          size_t write_size, loff_t *offset)
 {
        int rc = 0;
        unsigned int bytes_written = 0;
        unsigned int total_written;
        struct cifs_sb_info *cifs_sb;
-       struct cifs_tcon *pTcon;
+       struct cifs_tcon *tcon;
+       struct TCP_Server_Info *server;
        unsigned int xid;
        struct dentry *dentry = open_file->dentry;
        struct cifsInodeInfo *cifsi = CIFS_I(dentry->d_inode);
@@ -1486,9 +1503,13 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, __u32 pid,
        cifs_sb = CIFS_SB(dentry->d_sb);
 
        cFYI(1, "write %zd bytes to offset %lld of %s", write_size,
-          *poffset, dentry->d_name.name);
+            *offset, dentry->d_name.name);
+
+       tcon = tlink_tcon(open_file->tlink);
+       server = tcon->ses->server;
 
-       pTcon = tlink_tcon(open_file->tlink);
+       if (!server->ops->sync_write)
+               return -ENOSYS;
 
        xid = get_xid();
 
@@ -1514,13 +1535,12 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, __u32 pid,
                        /* iov[0] is reserved for smb header */
                        iov[1].iov_base = (char *)write_data + total_written;
                        iov[1].iov_len = len;
-                       io_parms.netfid = open_file->netfid;
                        io_parms.pid = pid;
-                       io_parms.tcon = pTcon;
-                       io_parms.offset = *poffset;
+                       io_parms.tcon = tcon;
+                       io_parms.offset = *offset;
                        io_parms.length = len;
-                       rc = CIFSSMBWrite2(xid, &io_parms, &bytes_written, iov,
-                                          1, 0);
+                       rc = server->ops->sync_write(xid, open_file, &io_parms,
+                                                    &bytes_written, iov, 1);
                }
                if (rc || (bytes_written == 0)) {
                        if (total_written)
@@ -1531,18 +1551,18 @@ static ssize_t cifs_write(struct cifsFileInfo *open_file, __u32 pid,
                        }
                } else {
                        spin_lock(&dentry->d_inode->i_lock);
-                       cifs_update_eof(cifsi, *poffset, bytes_written);
+                       cifs_update_eof(cifsi, *offset, bytes_written);
                        spin_unlock(&dentry->d_inode->i_lock);
-                       *poffset += bytes_written;
+                       *offset += bytes_written;
                }
        }
 
-       cifs_stats_bytes_written(pTcon, total_written);
+       cifs_stats_bytes_written(tcon, total_written);
 
        if (total_written > 0) {
                spin_lock(&dentry->d_inode->i_lock);
-               if (*poffset > dentry->d_inode->i_size)
-                       i_size_write(dentry->d_inode, *poffset);
+               if (*offset > dentry->d_inode->i_size)
+                       i_size_write(dentry->d_inode, *offset);
                spin_unlock(&dentry->d_inode->i_lock);
        }
        mark_inode_dirty_sync(dentry->d_inode);
@@ -1746,6 +1766,7 @@ static int cifs_writepages(struct address_space *mapping,
        bool done = false, scanned = false, range_whole = false;
        pgoff_t end, index;
        struct cifs_writedata *wdata;
+       struct TCP_Server_Info *server;
        struct page *page;
        int rc = 0;
 
@@ -1896,7 +1917,8 @@ retry:
                                break;
                        }
                        wdata->pid = wdata->cfile->pid;
-                       rc = cifs_async_writev(wdata);
+                       server = tlink_tcon(wdata->cfile->tlink)->ses->server;
+                       rc = server->ops->async_writev(wdata);
                } while (wbc->sync_mode == WB_SYNC_ALL && rc == -EAGAIN);
 
                for (i = 0; i < nr_pages; ++i)
@@ -2054,6 +2076,7 @@ int cifs_strict_fsync(struct file *file, loff_t start, loff_t end,
        unsigned int xid;
        int rc = 0;
        struct cifs_tcon *tcon;
+       struct TCP_Server_Info *server;
        struct cifsFileInfo *smbfile = file->private_data;
        struct inode *inode = file->f_path.dentry->d_inode;
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
@@ -2077,8 +2100,13 @@ int cifs_strict_fsync(struct file *file, loff_t start, loff_t end,
        }
 
        tcon = tlink_tcon(smbfile->tlink);
-       if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
-               rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
+       if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) {
+               server = tcon->ses->server;
+               if (server->ops->flush)
+                       rc = server->ops->flush(xid, tcon, &smbfile->fid);
+               else
+                       rc = -ENOSYS;
+       }
 
        free_xid(xid);
        mutex_unlock(&inode->i_mutex);
@@ -2090,6 +2118,7 @@ int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
        unsigned int xid;
        int rc = 0;
        struct cifs_tcon *tcon;
+       struct TCP_Server_Info *server;
        struct cifsFileInfo *smbfile = file->private_data;
        struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
        struct inode *inode = file->f_mapping->host;
@@ -2105,8 +2134,13 @@ int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
                file->f_path.dentry->d_name.name, datasync);
 
        tcon = tlink_tcon(smbfile->tlink);
-       if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC))
-               rc = CIFSSMBFlush(xid, tcon, smbfile->netfid);
+       if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOSSYNC)) {
+               server = tcon->ses->server;
+               if (server->ops->flush)
+                       rc = server->ops->flush(xid, tcon, &smbfile->fid);
+               else
+                       rc = -ENOSYS;
+       }
 
        free_xid(xid);
        mutex_unlock(&inode->i_mutex);
@@ -2215,6 +2249,9 @@ static int
 cifs_uncached_retry_writev(struct cifs_writedata *wdata)
 {
        int rc;
+       struct TCP_Server_Info *server;
+
+       server = tlink_tcon(wdata->cfile->tlink)->ses->server;
 
        do {
                if (wdata->cfile->invalidHandle) {
@@ -2222,7 +2259,7 @@ cifs_uncached_retry_writev(struct cifs_writedata *wdata)
                        if (rc != 0)
                                continue;
                }
-               rc = cifs_async_writev(wdata);
+               rc = server->ops->async_writev(wdata);
        } while (rc == -EAGAIN);
 
        return rc;
@@ -2257,6 +2294,10 @@ cifs_iovec_write(struct file *file, const struct iovec *iov,
        cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
        open_file = file->private_data;
        tcon = tlink_tcon(open_file->tlink);
+
+       if (!tcon->ses->server->ops->async_writev)
+               return -ENOSYS;
+
        offset = *poffset;
 
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
@@ -2468,6 +2509,9 @@ static int
 cifs_retry_async_readv(struct cifs_readdata *rdata)
 {
        int rc;
+       struct TCP_Server_Info *server;
+
+       server = tlink_tcon(rdata->cfile->tlink)->ses->server;
 
        do {
                if (rdata->cfile->invalidHandle) {
@@ -2475,7 +2519,7 @@ cifs_retry_async_readv(struct cifs_readdata *rdata)
                        if (rc != 0)
                                continue;
                }
-               rc = cifs_async_readv(rdata);
+               rc = server->ops->async_readv(rdata);
        } while (rc == -EAGAIN);
 
        return rc;
@@ -2627,6 +2671,9 @@ cifs_iovec_read(struct file *file, const struct iovec *iov,
        open_file = file->private_data;
        tcon = tlink_tcon(open_file->tlink);
 
+       if (!tcon->ses->server->ops->async_readv)
+               return -ENOSYS;
+
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
                pid = open_file->pid;
        else
@@ -2706,6 +2753,10 @@ restart_loop:
        cifs_stats_bytes_read(tcon, total_read);
        *poffset += total_read;
 
+       /* mask nodata case */
+       if (rc == -ENODATA)
+               rc = 0;
+
        return total_read ? total_read : rc;
 }
 
@@ -2743,8 +2794,8 @@ ssize_t cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov,
        return cifs_user_readv(iocb, iov, nr_segs, pos);
 }
 
-static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
-                        loff_t *poffset)
+static ssize_t
+cifs_read(struct file *file, char *read_data, size_t read_size, loff_t *offset)
 {
        int rc = -EACCES;
        unsigned int bytes_read = 0;
@@ -2753,8 +2804,9 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
        unsigned int rsize;
        struct cifs_sb_info *cifs_sb;
        struct cifs_tcon *tcon;
+       struct TCP_Server_Info *server;
        unsigned int xid;
-       char *current_offset;
+       char *cur_offset;
        struct cifsFileInfo *open_file;
        struct cifs_io_parms io_parms;
        int buf_type = CIFS_NO_BUFFER;
@@ -2773,6 +2825,12 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
        }
        open_file = file->private_data;
        tcon = tlink_tcon(open_file->tlink);
+       server = tcon->ses->server;
+
+       if (!server->ops->sync_read) {
+               free_xid(xid);
+               return -ENOSYS;
+       }
 
        if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD)
                pid = open_file->pid;
@@ -2782,9 +2840,8 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
        if ((file->f_flags & O_ACCMODE) == O_WRONLY)
                cFYI(1, "attempting read on write only file instance");
 
-       for (total_read = 0, current_offset = read_data;
-            read_size > total_read;
-            total_read += bytes_read, current_offset += bytes_read) {
+       for (total_read = 0, cur_offset = read_data; read_size > total_read;
+            total_read += bytes_read, cur_offset += bytes_read) {
                current_read_size = min_t(uint, read_size - total_read, rsize);
                /*
                 * For windows me and 9x we do not want to request more than it
@@ -2802,13 +2859,13 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
                                if (rc != 0)
                                        break;
                        }
-                       io_parms.netfid = open_file->netfid;
                        io_parms.pid = pid;
                        io_parms.tcon = tcon;
-                       io_parms.offset = *poffset;
+                       io_parms.offset = *offset;
                        io_parms.length = current_read_size;
-                       rc = CIFSSMBRead(xid, &io_parms, &bytes_read,
-                                        &current_offset, &buf_type);
+                       rc = server->ops->sync_read(xid, open_file, &io_parms,
+                                                   &bytes_read, &cur_offset,
+                                                   &buf_type);
                }
                if (rc || (bytes_read == 0)) {
                        if (total_read) {
@@ -2819,7 +2876,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size,
                        }
                } else {
                        cifs_stats_bytes_read(tcon, total_read);
-                       *poffset += bytes_read;
+                       *offset += bytes_read;
                }
        }
        free_xid(xid);
@@ -3347,6 +3404,7 @@ void cifs_oplock_break(struct work_struct *work)
                                                  oplock_break);
        struct inode *inode = cfile->dentry->d_inode;
        struct cifsInodeInfo *cinode = CIFS_I(inode);
+       struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
        int rc = 0;
 
        if (inode && S_ISREG(inode->i_mode)) {
@@ -3374,10 +3432,8 @@ void cifs_oplock_break(struct work_struct *work)
         * disconnected since oplock already released by the server
         */
        if (!cfile->oplock_break_cancelled) {
-               rc = CIFSSMBLock(0, tlink_tcon(cfile->tlink), cfile->netfid,
-                                current->tgid, 0, 0, 0, 0,
-                                LOCKING_ANDX_OPLOCK_RELEASE, false,
-                                cinode->clientCanCacheRead ? 1 : 0);
+               rc = tcon->ses->server->ops->oplock_response(tcon, &cfile->fid,
+                                                            cinode);
                cFYI(1, "Oplock release rc = %d", rc);
        }
 }
index 7354877fa3bd825519ea981b1c6208fd886dff11..da4dd714d32558758ebebe752742e5de6b3ee069 100644 (file)
@@ -124,10 +124,10 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
 {
        struct cifsInodeInfo *cifs_i = CIFS_I(inode);
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
-       unsigned long oldtime = cifs_i->time;
 
        cifs_revalidate_cache(inode, fattr);
 
+       spin_lock(&inode->i_lock);
        inode->i_atime = fattr->cf_atime;
        inode->i_mtime = fattr->cf_mtime;
        inode->i_ctime = fattr->cf_ctime;
@@ -148,9 +148,6 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
        else
                cifs_i->time = jiffies;
 
-       cFYI(1, "inode 0x%p old_time=%ld new_time=%ld", inode,
-                oldtime, cifs_i->time);
-
        cifs_i->delete_pending = fattr->cf_flags & CIFS_FATTR_DELETE_PENDING;
 
        cifs_i->server_eof = fattr->cf_eof;
@@ -158,7 +155,6 @@ cifs_fattr_to_inode(struct inode *inode, struct cifs_fattr *fattr)
         * Can't safely change the file size here if the client is writing to
         * it due to potential races.
         */
-       spin_lock(&inode->i_lock);
        if (is_size_safe_to_change(cifs_i, fattr->cf_eof)) {
                i_size_write(inode, fattr->cf_eof);
 
@@ -286,7 +282,8 @@ cifs_create_dfs_fattr(struct cifs_fattr *fattr, struct super_block *sb)
        fattr->cf_flags |= CIFS_FATTR_DFS_REFERRAL;
 }
 
-int cifs_get_file_info_unix(struct file *filp)
+static int
+cifs_get_file_info_unix(struct file *filp)
 {
        int rc;
        unsigned int xid;
@@ -298,7 +295,7 @@ int cifs_get_file_info_unix(struct file *filp)
        struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
 
        xid = get_xid();
-       rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->netfid, &find_data);
+       rc = CIFSSMBUnixQFileInfo(xid, tcon, cfile->fid.netfid, &find_data);
        if (!rc) {
                cifs_unix_basic_to_fattr(&fattr, &find_data, cifs_sb);
        } else if (rc == -EREMOTE) {
@@ -554,7 +551,8 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
        fattr->cf_gid = cifs_sb->mnt_gid;
 }
 
-int cifs_get_file_info(struct file *filp)
+static int
+cifs_get_file_info(struct file *filp)
 {
        int rc;
        unsigned int xid;
@@ -564,9 +562,13 @@ int cifs_get_file_info(struct file *filp)
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
        struct cifsFileInfo *cfile = filp->private_data;
        struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
+       struct TCP_Server_Info *server = tcon->ses->server;
+
+       if (!server->ops->query_file_info)
+               return -ENOSYS;
 
        xid = get_xid();
-       rc = CIFSSMBQFileInfo(xid, tcon, cfile->netfid, &find_data);
+       rc = server->ops->query_file_info(xid, tcon, &cfile->fid, &find_data);
        switch (rc) {
        case 0:
                cifs_all_info_to_fattr(&fattr, &find_data, cifs_sb, false);
@@ -859,12 +861,14 @@ struct inode *cifs_root_iget(struct super_block *sb)
 
        if (rc && tcon->ipc) {
                cFYI(1, "ipc connection - fake read inode");
+               spin_lock(&inode->i_lock);
                inode->i_mode |= S_IFDIR;
                set_nlink(inode, 2);
                inode->i_op = &cifs_ipc_inode_ops;
                inode->i_fop = &simple_dir_operations;
                inode->i_uid = cifs_sb->mnt_uid;
                inode->i_gid = cifs_sb->mnt_gid;
+               spin_unlock(&inode->i_lock);
        } else if (rc) {
                iget_failed(inode);
                inode = ERR_PTR(rc);
@@ -878,25 +882,22 @@ out:
        return inode;
 }
 
-static int
+int
 cifs_set_file_info(struct inode *inode, struct iattr *attrs, unsigned int xid,
-                   char *full_path, __u32 dosattr)
+                  char *full_path, __u32 dosattr)
 {
-       int rc;
-       int oplock = 0;
-       __u16 netfid;
-       __u32 netpid;
        bool set_time = false;
-       struct cifsFileInfo *open_file;
-       struct cifsInodeInfo *cifsInode = CIFS_I(inode);
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
-       struct tcon_link *tlink = NULL;
-       struct cifs_tcon *pTcon;
+       struct TCP_Server_Info *server;
        FILE_BASIC_INFO info_buf;
 
        if (attrs == NULL)
                return -EINVAL;
 
+       server = cifs_sb_master_tcon(cifs_sb)->ses->server;
+       if (!server->ops->set_file_info)
+               return -ENOSYS;
+
        if (attrs->ia_valid & ATTR_ATIME) {
                set_time = true;
                info_buf.LastAccessTime =
@@ -927,81 +928,17 @@ cifs_set_file_info(struct inode *inode, struct iattr *attrs, unsigned int xid,
        info_buf.CreationTime = 0;      /* don't change */
        info_buf.Attributes = cpu_to_le32(dosattr);
 
-       /*
-        * If the file is already open for write, just use that fileid
-        */
-       open_file = find_writable_file(cifsInode, true);
-       if (open_file) {
-               netfid = open_file->netfid;
-               netpid = open_file->pid;
-               pTcon = tlink_tcon(open_file->tlink);
-               goto set_via_filehandle;
-       }
-
-       tlink = cifs_sb_tlink(cifs_sb);
-       if (IS_ERR(tlink)) {
-               rc = PTR_ERR(tlink);
-               tlink = NULL;
-               goto out;
-       }
-       pTcon = tlink_tcon(tlink);
-
-       /*
-        * NT4 apparently returns success on this call, but it doesn't
-        * really work.
-        */
-       if (!(pTcon->ses->flags & CIFS_SES_NT4)) {
-               rc = CIFSSMBSetPathInfo(xid, pTcon, full_path,
-                                    &info_buf, cifs_sb->local_nls,
-                                    cifs_sb->mnt_cifs_flags &
-                                       CIFS_MOUNT_MAP_SPECIAL_CHR);
-               if (rc == 0) {
-                       cifsInode->cifsAttrs = dosattr;
-                       goto out;
-               } else if (rc != -EOPNOTSUPP && rc != -EINVAL)
-                       goto out;
-       }
-
-       cFYI(1, "calling SetFileInfo since SetPathInfo for "
-                "times not supported by this server");
-       rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN,
-                        SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
-                        CREATE_NOT_DIR, &netfid, &oplock,
-                        NULL, cifs_sb->local_nls,
-                        cifs_sb->mnt_cifs_flags &
-                               CIFS_MOUNT_MAP_SPECIAL_CHR);
-
-       if (rc != 0) {
-               if (rc == -EIO)
-                       rc = -EINVAL;
-               goto out;
-       }
-
-       netpid = current->tgid;
-
-set_via_filehandle:
-       rc = CIFSSMBSetFileInfo(xid, pTcon, &info_buf, netfid, netpid);
-       if (!rc)
-               cifsInode->cifsAttrs = dosattr;
-
-       if (open_file == NULL)
-               CIFSSMBClose(xid, pTcon, netfid);
-       else
-               cifsFileInfo_put(open_file);
-out:
-       if (tlink != NULL)
-               cifs_put_tlink(tlink);
-       return rc;
+       return server->ops->set_file_info(inode, full_path, &info_buf, xid);
 }
 
 /*
- * open the given file (if it isn't already), set the DELETE_ON_CLOSE bit
+ * Open the given file (if it isn't already), set the DELETE_ON_CLOSE bit
  * and rename it to a random name that hopefully won't conflict with
  * anything else.
  */
-static int
-cifs_rename_pending_delete(char *full_path, struct dentry *dentry,
-                          unsigned int xid)
+int
+cifs_rename_pending_delete(const char *full_path, struct dentry *dentry,
+                          const unsigned int xid)
 {
        int oplock = 0;
        int rc;
@@ -1110,6 +1047,15 @@ undo_setattr:
        goto out_close;
 }
 
+/* copied from fs/nfs/dir.c with small changes */
+static void
+cifs_drop_nlink(struct inode *inode)
+{
+       spin_lock(&inode->i_lock);
+       if (inode->i_nlink > 0)
+               drop_nlink(inode);
+       spin_unlock(&inode->i_lock);
+}
 
 /*
  * If dentry->d_inode is null (usually meaning the cached dentry
@@ -1129,6 +1075,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
        struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
        struct tcon_link *tlink;
        struct cifs_tcon *tcon;
+       struct TCP_Server_Info *server;
        struct iattr *attrs = NULL;
        __u32 dosattr = 0, origattr = 0;
 
@@ -1138,6 +1085,7 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
        if (IS_ERR(tlink))
                return PTR_ERR(tlink);
        tcon = tlink_tcon(tlink);
+       server = tcon->ses->server;
 
        xid = get_xid();
 
@@ -1160,19 +1108,27 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
        }
 
 retry_std_delete:
-       rc = CIFSSMBDelFile(xid, tcon, full_path, cifs_sb->local_nls,
-                       cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+       if (!server->ops->unlink) {
+               rc = -ENOSYS;
+               goto psx_del_no_retry;
+       }
+
+       rc = server->ops->unlink(xid, tcon, full_path, cifs_sb);
 
 psx_del_no_retry:
        if (!rc) {
                if (inode)
-                       drop_nlink(inode);
+                       cifs_drop_nlink(inode);
        } else if (rc == -ENOENT) {
                d_drop(dentry);
        } else if (rc == -ETXTBSY) {
-               rc = cifs_rename_pending_delete(full_path, dentry, xid);
-               if (rc == 0)
-                       drop_nlink(inode);
+               if (server->ops->rename_pending_delete) {
+                       rc = server->ops->rename_pending_delete(full_path,
+                                                               dentry, xid);
+                       if (rc == 0)
+                               cifs_drop_nlink(inode);
+               } else
+                       rc = -ENOSYS;
        } else if ((rc == -EACCES) && (dosattr == 0) && inode) {
                attrs = kzalloc(sizeof(*attrs), GFP_KERNEL);
                if (attrs == NULL) {
@@ -1241,9 +1197,10 @@ cifs_mkdir_qinfo(struct inode *inode, struct dentry *dentry, umode_t mode,
         * setting nlink not necessary except in cases where we failed to get it
         * from the server or was set bogus
         */
+       spin_lock(&dentry->d_inode->i_lock);
        if ((dentry->d_inode) && (dentry->d_inode->i_nlink < 2))
                set_nlink(dentry->d_inode, 2);
-
+       spin_unlock(&dentry->d_inode->i_lock);
        mode &= ~current_umask();
        /* must turn on setgid bit if parent dir has it */
        if (inode->i_mode & S_ISGID)
@@ -1487,29 +1444,32 @@ rmdir_exit:
 }
 
 static int
-cifs_do_rename(unsigned int xid, struct dentry *from_dentry,
-              const char *fromPath, struct dentry *to_dentry,
-              const char *toPath)
+cifs_do_rename(const unsigned int xid, struct dentry *from_dentry,
+              const char *from_path, struct dentry *to_dentry,
+              const char *to_path)
 {
        struct cifs_sb_info *cifs_sb = CIFS_SB(from_dentry->d_sb);
        struct tcon_link *tlink;
-       struct cifs_tcon *pTcon;
+       struct cifs_tcon *tcon;
+       struct TCP_Server_Info *server;
        __u16 srcfid;
        int oplock, rc;
 
        tlink = cifs_sb_tlink(cifs_sb);
        if (IS_ERR(tlink))
                return PTR_ERR(tlink);
-       pTcon = tlink_tcon(tlink);
+       tcon = tlink_tcon(tlink);
+       server = tcon->ses->server;
+
+       if (!server->ops->rename)
+               return -ENOSYS;
 
        /* try path-based rename first */
-       rc = CIFSSMBRename(xid, pTcon, fromPath, toPath, cifs_sb->local_nls,
-                          cifs_sb->mnt_cifs_flags &
-                               CIFS_MOUNT_MAP_SPECIAL_CHR);
+       rc = server->ops->rename(xid, tcon, from_path, to_path, cifs_sb);
 
        /*
-        * don't bother with rename by filehandle unless file is busy and
-        * source Note that cross directory moves do not work with
+        * Don't bother with rename by filehandle unless file is busy and
+        * source. Note that cross directory moves do not work with
         * rename by filehandle to various Windows servers.
         */
        if (rc == 0 || rc != -ETXTBSY)
@@ -1520,29 +1480,28 @@ cifs_do_rename(unsigned int xid, struct dentry *from_dentry,
                goto do_rename_exit;
 
        /* open the file to be renamed -- we need DELETE perms */
-       rc = CIFSSMBOpen(xid, pTcon, fromPath, FILE_OPEN, DELETE,
+       rc = CIFSSMBOpen(xid, tcon, from_path, FILE_OPEN, DELETE,
                         CREATE_NOT_DIR, &srcfid, &oplock, NULL,
                         cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
                                CIFS_MOUNT_MAP_SPECIAL_CHR);
-
        if (rc == 0) {
-               rc = CIFSSMBRenameOpenFile(xid, pTcon, srcfid,
+               rc = CIFSSMBRenameOpenFile(xid, tcon, srcfid,
                                (const char *) to_dentry->d_name.name,
                                cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
                                        CIFS_MOUNT_MAP_SPECIAL_CHR);
-
-               CIFSSMBClose(xid, pTcon, srcfid);
+               CIFSSMBClose(xid, tcon, srcfid);
        }
 do_rename_exit:
        cifs_put_tlink(tlink);
        return rc;
 }
 
-int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
-       struct inode *target_dir, struct dentry *target_dentry)
+int
+cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
+           struct inode *target_dir, struct dentry *target_dentry)
 {
-       char *fromName = NULL;
-       char *toName = NULL;
+       char *from_name = NULL;
+       char *to_name = NULL;
        struct cifs_sb_info *cifs_sb;
        struct tcon_link *tlink;
        struct cifs_tcon *tcon;
@@ -1563,25 +1522,25 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
         * we already have the rename sem so we do not need to
         * grab it again here to protect the path integrity
         */
-       fromName = build_path_from_dentry(source_dentry);
-       if (fromName == NULL) {
+       from_name = build_path_from_dentry(source_dentry);
+       if (from_name == NULL) {
                rc = -ENOMEM;
                goto cifs_rename_exit;
        }
 
-       toName = build_path_from_dentry(target_dentry);
-       if (toName == NULL) {
+       to_name = build_path_from_dentry(target_dentry);
+       if (to_name == NULL) {
                rc = -ENOMEM;
                goto cifs_rename_exit;
        }
 
-       rc = cifs_do_rename(xid, source_dentry, fromName,
-                           target_dentry, toName);
+       rc = cifs_do_rename(xid, source_dentry, from_name, target_dentry,
+                           to_name);
 
        if (rc == -EEXIST && tcon->unix_ext) {
                /*
-                * Are src and dst hardlinks of same inode? We can
-                * only tell with unix extensions enabled
+                * Are src and dst hardlinks of same inode? We can only tell
+                * with unix extensions enabled.
                 */
                info_buf_source =
                        kmalloc(2 * sizeof(FILE_UNIX_BASIC_INFO),
@@ -1592,19 +1551,19 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
                }
 
                info_buf_target = info_buf_source + 1;
-               tmprc = CIFSSMBUnixQPathInfo(xid, tcon, fromName,
-                                       info_buf_source,
-                                       cifs_sb->local_nls,
-                                       cifs_sb->mnt_cifs_flags &
-                                       CIFS_MOUNT_MAP_SPECIAL_CHR);
+               tmprc = CIFSSMBUnixQPathInfo(xid, tcon, from_name,
+                                            info_buf_source,
+                                            cifs_sb->local_nls,
+                                            cifs_sb->mnt_cifs_flags &
+                                               CIFS_MOUNT_MAP_SPECIAL_CHR);
                if (tmprc != 0)
                        goto unlink_target;
 
-               tmprc = CIFSSMBUnixQPathInfo(xid, tcon, toName,
-                                       info_buf_target,
-                                       cifs_sb->local_nls,
-                                       cifs_sb->mnt_cifs_flags &
-                                       CIFS_MOUNT_MAP_SPECIAL_CHR);
+               tmprc = CIFSSMBUnixQPathInfo(xid, tcon, to_name,
+                                            info_buf_target,
+                                            cifs_sb->local_nls,
+                                            cifs_sb->mnt_cifs_flags &
+                                               CIFS_MOUNT_MAP_SPECIAL_CHR);
 
                if (tmprc == 0 && (info_buf_source->UniqueId ==
                                   info_buf_target->UniqueId)) {
@@ -1612,8 +1571,11 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
                        rc = 0;
                        goto cifs_rename_exit;
                }
-       } /* else ... BB we could add the same check for Windows by
-                    checking the UniqueId via FILE_INTERNAL_INFO */
+       }
+       /*
+        * else ... BB we could add the same check for Windows by
+        * checking the UniqueId via FILE_INTERNAL_INFO
+        */
 
 unlink_target:
        /* Try unlinking the target dentry if it's not negative */
@@ -1621,15 +1583,14 @@ unlink_target:
                tmprc = cifs_unlink(target_dir, target_dentry);
                if (tmprc)
                        goto cifs_rename_exit;
-
-               rc = cifs_do_rename(xid, source_dentry, fromName,
-                                   target_dentry, toName);
+               rc = cifs_do_rename(xid, source_dentry, from_name,
+                                   target_dentry, to_name);
        }
 
 cifs_rename_exit:
        kfree(info_buf_source);
-       kfree(fromName);
-       kfree(toName);
+       kfree(from_name);
+       kfree(to_name);
        free_xid(xid);
        cifs_put_tlink(tlink);
        return rc;
@@ -1854,7 +1815,8 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
        struct cifsInodeInfo *cifsInode = CIFS_I(inode);
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
        struct tcon_link *tlink = NULL;
-       struct cifs_tcon *pTcon = NULL;
+       struct cifs_tcon *tcon = NULL;
+       struct TCP_Server_Info *server;
        struct cifs_io_parms io_parms;
 
        /*
@@ -1868,19 +1830,21 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
         */
        open_file = find_writable_file(cifsInode, true);
        if (open_file) {
-               __u16 nfid = open_file->netfid;
-               __u32 npid = open_file->pid;
-               pTcon = tlink_tcon(open_file->tlink);
-               rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, nfid,
-                                       npid, false);
+               tcon = tlink_tcon(open_file->tlink);
+               server = tcon->ses->server;
+               if (server->ops->set_file_size)
+                       rc = server->ops->set_file_size(xid, tcon, open_file,
+                                                       attrs->ia_size, false);
+               else
+                       rc = -ENOSYS;
                cifsFileInfo_put(open_file);
                cFYI(1, "SetFSize for attrs rc = %d", rc);
                if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
                        unsigned int bytes_written;
 
-                       io_parms.netfid = nfid;
-                       io_parms.pid = npid;
-                       io_parms.tcon = pTcon;
+                       io_parms.netfid = open_file->fid.netfid;
+                       io_parms.pid = open_file->pid;
+                       io_parms.tcon = tcon;
                        io_parms.offset = 0;
                        io_parms.length = attrs->ia_size;
                        rc = CIFSSMBWrite(xid, &io_parms, &bytes_written,
@@ -1890,52 +1854,55 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs,
        } else
                rc = -EINVAL;
 
-       if (rc != 0) {
-               if (pTcon == NULL) {
-                       tlink = cifs_sb_tlink(cifs_sb);
-                       if (IS_ERR(tlink))
-                               return PTR_ERR(tlink);
-                       pTcon = tlink_tcon(tlink);
-               }
+       if (!rc)
+               goto set_size_out;
 
-               /* Set file size by pathname rather than by handle
-                  either because no valid, writeable file handle for
-                  it was found or because there was an error setting
-                  it by handle */
-               rc = CIFSSMBSetEOF(xid, pTcon, full_path, attrs->ia_size,
-                                  false, cifs_sb->local_nls,
+       if (tcon == NULL) {
+               tlink = cifs_sb_tlink(cifs_sb);
+               if (IS_ERR(tlink))
+                       return PTR_ERR(tlink);
+               tcon = tlink_tcon(tlink);
+               server = tcon->ses->server;
+       }
+
+       /*
+        * Set file size by pathname rather than by handle either because no
+        * valid, writeable file handle for it was found or because there was
+        * an error setting it by handle.
+        */
+       if (server->ops->set_path_size)
+               rc = server->ops->set_path_size(xid, tcon, full_path,
+                                               attrs->ia_size, cifs_sb, false);
+       else
+               rc = -ENOSYS;
+       cFYI(1, "SetEOF by path (setattrs) rc = %d", rc);
+       if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
+               __u16 netfid;
+               int oplock = 0;
+
+               rc = SMBLegacyOpen(xid, tcon, full_path, FILE_OPEN,
+                                  GENERIC_WRITE, CREATE_NOT_DIR, &netfid,
+                                  &oplock, NULL, cifs_sb->local_nls,
                                   cifs_sb->mnt_cifs_flags &
-                                       CIFS_MOUNT_MAP_SPECIAL_CHR);
-               cFYI(1, "SetEOF by path (setattrs) rc = %d", rc);
-               if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) {
-                       __u16 netfid;
-                       int oplock = 0;
-
-                       rc = SMBLegacyOpen(xid, pTcon, full_path,
-                               FILE_OPEN, GENERIC_WRITE,
-                               CREATE_NOT_DIR, &netfid, &oplock, NULL,
-                               cifs_sb->local_nls,
-                               cifs_sb->mnt_cifs_flags &
-                                       CIFS_MOUNT_MAP_SPECIAL_CHR);
-                       if (rc == 0) {
-                               unsigned int bytes_written;
-
-                               io_parms.netfid = netfid;
-                               io_parms.pid = current->tgid;
-                               io_parms.tcon = pTcon;
-                               io_parms.offset = 0;
-                               io_parms.length = attrs->ia_size;
-                               rc = CIFSSMBWrite(xid, &io_parms,
-                                                 &bytes_written,
-                                                 NULL, NULL,  1);
-                               cFYI(1, "wrt seteof rc %d", rc);
-                               CIFSSMBClose(xid, pTcon, netfid);
-                       }
+                                               CIFS_MOUNT_MAP_SPECIAL_CHR);
+               if (rc == 0) {
+                       unsigned int bytes_written;
+
+                       io_parms.netfid = netfid;
+                       io_parms.pid = current->tgid;
+                       io_parms.tcon = tcon;
+                       io_parms.offset = 0;
+                       io_parms.length = attrs->ia_size;
+                       rc = CIFSSMBWrite(xid, &io_parms, &bytes_written, NULL,
+                                         NULL,  1);
+                       cFYI(1, "wrt seteof rc %d", rc);
+                       CIFSSMBClose(xid, tcon, netfid);
                }
-               if (tlink)
-                       cifs_put_tlink(tlink);
        }
+       if (tlink)
+               cifs_put_tlink(tlink);
 
+set_size_out:
        if (rc == 0) {
                cifsInode->server_eof = attrs->ia_size;
                cifs_setsize(inode, attrs->ia_size);
@@ -2042,7 +2009,7 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs)
        args->device = 0;
        open_file = find_writable_file(cifsInode, true);
        if (open_file) {
-               u16 nfid = open_file->netfid;
+               u16 nfid = open_file->fid.netfid;
                u32 npid = open_file->pid;
                pTcon = tlink_tcon(open_file->tlink);
                rc = CIFSSMBUnixSetFileInfo(xid, pTcon, args, nfid, npid);
index ae082a66de2fbd71ed20fec5b7b8e8228dc58c10..5b3481bd3d96dd3ae692cbcb52977d2ed9e25864 100644 (file)
@@ -75,8 +75,9 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
                        tcon = tlink_tcon(pSMBFile->tlink);
                        caps = le64_to_cpu(tcon->fsUnixInfo.Capability);
                        if (CIFS_UNIX_EXTATTR_CAP & caps) {
-                               rc = CIFSGetExtAttr(xid, tcon, pSMBFile->netfid,
-                                       &ExtAttrBits, &ExtAttrMask);
+                               rc = CIFSGetExtAttr(xid, tcon,
+                                                   pSMBFile->fid.netfid,
+                                                   &ExtAttrBits, &ExtAttrMask);
                                if (rc == 0)
                                        rc = put_user(ExtAttrBits &
                                                FS_FL_USER_VISIBLE,
@@ -94,8 +95,12 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
                                        rc = -EFAULT;
                                        break;
                                }
-                               /* rc= CIFSGetExtAttr(xid,tcon,pSMBFile->netfid,
-                                       extAttrBits, &ExtAttrMask);*/
+                               /*
+                                * rc = CIFSGetExtAttr(xid, tcon,
+                                *                     pSMBFile->fid.netfid,
+                                *                     extAttrBits,
+                                *                     &ExtAttrMask);
+                                */
                        }
                        cFYI(1, "set flags not implemented yet");
                        break;
index 09e4b3ae45640e3d0c1bd8757cc6da935fca65f5..51dc2fb6e854a724b16b782b6ab514446b8db7f5 100644 (file)
@@ -391,70 +391,86 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
 {
        int rc = -EACCES;
        unsigned int xid;
-       char *fromName = NULL;
-       char *toName = NULL;
+       char *from_name = NULL;
+       char *to_name = NULL;
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
        struct tcon_link *tlink;
-       struct cifs_tcon *pTcon;
+       struct cifs_tcon *tcon;
+       struct TCP_Server_Info *server;
        struct cifsInodeInfo *cifsInode;
 
        tlink = cifs_sb_tlink(cifs_sb);
        if (IS_ERR(tlink))
                return PTR_ERR(tlink);
-       pTcon = tlink_tcon(tlink);
+       tcon = tlink_tcon(tlink);
 
        xid = get_xid();
 
-       fromName = build_path_from_dentry(old_file);
-       toName = build_path_from_dentry(direntry);
-       if ((fromName == NULL) || (toName == NULL)) {
+       from_name = build_path_from_dentry(old_file);
+       to_name = build_path_from_dentry(direntry);
+       if ((from_name == NULL) || (to_name == NULL)) {
                rc = -ENOMEM;
                goto cifs_hl_exit;
        }
 
-       if (pTcon->unix_ext)
-               rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName,
+       if (tcon->unix_ext)
+               rc = CIFSUnixCreateHardLink(xid, tcon, from_name, to_name,
                                            cifs_sb->local_nls,
                                            cifs_sb->mnt_cifs_flags &
                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
        else {
-               rc = CIFSCreateHardLink(xid, pTcon, fromName, toName,
-                                       cifs_sb->local_nls,
-                                       cifs_sb->mnt_cifs_flags &
-                                               CIFS_MOUNT_MAP_SPECIAL_CHR);
+               server = tcon->ses->server;
+               if (!server->ops->create_hardlink)
+                       return -ENOSYS;
+               rc = server->ops->create_hardlink(xid, tcon, from_name, to_name,
+                                                 cifs_sb);
                if ((rc == -EIO) || (rc == -EINVAL))
                        rc = -EOPNOTSUPP;
        }
 
        d_drop(direntry);       /* force new lookup from server of target */
 
-       /* if source file is cached (oplocked) revalidate will not go to server
-          until the file is closed or oplock broken so update nlinks locally */
+       /*
+        * if source file is cached (oplocked) revalidate will not go to server
+        * until the file is closed or oplock broken so update nlinks locally
+        */
        if (old_file->d_inode) {
                cifsInode = CIFS_I(old_file->d_inode);
                if (rc == 0) {
+                       spin_lock(&old_file->d_inode->i_lock);
                        inc_nlink(old_file->d_inode);
-/* BB should we make this contingent on superblock flag NOATIME? */
-/*                     old_file->d_inode->i_ctime = CURRENT_TIME;*/
-                       /* parent dir timestamps will update from srv
-                       within a second, would it really be worth it
-                       to set the parent dir cifs inode time to zero
-                       to force revalidate (faster) for it too? */
+                       spin_unlock(&old_file->d_inode->i_lock);
+                       /*
+                        * BB should we make this contingent on superblock flag
+                        * NOATIME?
+                        */
+                       /* old_file->d_inode->i_ctime = CURRENT_TIME; */
+                       /*
+                        * parent dir timestamps will update from srv within a
+                        * second, would it really be worth it to set the parent
+                        * dir cifs inode time to zero to force revalidate
+                        * (faster) for it too?
+                        */
                }
-               /* if not oplocked will force revalidate to get info
-                  on source file from srv */
+               /*
+                * if not oplocked will force revalidate to get info on source
+                * file from srv
+                */
                cifsInode->time = 0;
 
-               /* Will update parent dir timestamps from srv within a second.
-                  Would it really be worth it to set the parent dir (cifs
-                  inode) time field to zero to force revalidate on parent
-                  directory faster ie
-                       CIFS_I(inode)->time = 0;  */
+               /*
+                * Will update parent dir timestamps from srv within a second.
+                * Would it really be worth it to set the parent dir (cifs
+                * inode) time field to zero to force revalidate on parent
+                * directory faster ie
+                *
+                * CIFS_I(inode)->time = 0;
+                */
        }
 
 cifs_hl_exit:
-       kfree(fromName);
-       kfree(toName);
+       kfree(from_name);
+       kfree(to_name);
        free_xid(xid);
        cifs_put_tlink(tlink);
        return rc;
index ce41fee07e5b87917abe7d2acd5af53e7c2268d8..a921b0712eff43ce05ca81c710aa5dd05dc8397a 100644 (file)
@@ -466,7 +466,7 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
                        list_for_each(tmp2, &tcon->openFileList) {
                                netfile = list_entry(tmp2, struct cifsFileInfo,
                                                     tlist);
-                               if (pSMB->Fid != netfile->netfid)
+                               if (pSMB->Fid != netfile->fid.netfid)
                                        continue;
 
                                cFYI(1, "file id match, oplock break");
index 581c225f7f50b3ae5ac4f4915b6b229c22432fd7..e7bab3be5cf9f074e988fc24d056e8e3f8d7a4c9 100644 (file)
@@ -913,8 +913,9 @@ map_smb_to_linux_error(char *buf, bool logErr)
  * portion, the number of word parameters and the data portion of the message
  */
 unsigned int
-smbCalcSize(struct smb_hdr *ptr)
+smbCalcSize(void *buf)
 {
+       struct smb_hdr *ptr = (struct smb_hdr *)buf;
        return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) +
                2 /* size of the bcc field */ + get_bcc(ptr));
 }
index d87f82678bc74f9b6e602262568c8a8679ebac41..b0f4a428398de6dbd8f6b47118361dd1e257e4bc 100644 (file)
@@ -220,7 +220,8 @@ int get_symlink_reparse_path(char *full_path, struct cifs_sb_info *cifs_sb,
 }
  */
 
-static int initiate_cifs_search(const unsigned int xid, struct file *file)
+static int
+initiate_cifs_search(const unsigned int xid, struct file *file)
 {
        __u16 search_flags;
        int rc = 0;
@@ -229,6 +230,7 @@ static int initiate_cifs_search(const unsigned int xid, struct file *file)
        struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
        struct tcon_link *tlink = NULL;
        struct cifs_tcon *tcon;
+       struct TCP_Server_Info *server;
 
        if (file->private_data == NULL) {
                tlink = cifs_sb_tlink(cifs_sb);
@@ -248,6 +250,13 @@ static int initiate_cifs_search(const unsigned int xid, struct file *file)
                tcon = tlink_tcon(cifsFile->tlink);
        }
 
+       server = tcon->ses->server;
+
+       if (!server->ops->query_dir_first) {
+               rc = -ENOSYS;
+               goto error_exit;
+       }
+
        cifsFile->invalidHandle = true;
        cifsFile->srch_inf.endOfSearch = false;
 
@@ -278,10 +287,10 @@ ffirst_retry:
        if (backup_cred(cifs_sb))
                search_flags |= CIFS_SEARCH_BACKUP_SEARCH;
 
-       rc = CIFSFindFirst(xid, tcon, full_path, cifs_sb->local_nls,
-               &cifsFile->netfid, search_flags, &cifsFile->srch_inf,
-               cifs_sb->mnt_cifs_flags &
-                       CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
+       rc = server->ops->query_dir_first(xid, tcon, full_path, cifs_sb,
+                                         &cifsFile->fid, search_flags,
+                                         &cifsFile->srch_inf);
+
        if (rc == 0)
                cifsFile->invalidHandle = false;
        /* BB add following call to handle readdir on new NTFS symlink errors
@@ -501,62 +510,67 @@ static int cifs_save_resume_key(const char *current_entry,
        return rc;
 }
 
-/* find the corresponding entry in the search */
-/* Note that the SMB server returns search entries for . and .. which
-   complicates logic here if we choose to parse for them and we do not
-   assume that they are located in the findfirst return buffer.*/
-/* We start counting in the buffer with entry 2 and increment for every
-   entry (do not increment for . or .. entry) */
-static int find_cifs_entry(const unsigned int xid, struct cifs_tcon *pTcon,
-       struct file *file, char **ppCurrentEntry, int *num_to_ret)
+/*
+ * Find the corresponding entry in the search. Note that the SMB server returns
+ * search entries for . and .. which complicates logic here if we choose to
+ * parse for them and we do not assume that they are located in the findfirst
+ * return buffer. We start counting in the buffer with entry 2 and increment for
+ * every entry (do not increment for . or .. entry).
+ */
+static int
+find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon,
+               struct file *file, char **current_entry, int *num_to_ret)
 {
        __u16 search_flags;
        int rc = 0;
        int pos_in_buf = 0;
        loff_t first_entry_in_buffer;
        loff_t index_to_find = file->f_pos;
-       struct cifsFileInfo *cifsFile = file->private_data;
+       struct cifsFileInfo *cfile = file->private_data;
        struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
+       struct TCP_Server_Info *server = tcon->ses->server;
        /* check if index in the buffer */
 
-       if ((cifsFile == NULL) || (ppCurrentEntry == NULL) ||
-          (num_to_ret == NULL))
+       if (!server->ops->query_dir_first || !server->ops->query_dir_next)
+               return -ENOSYS;
+
+       if ((cfile == NULL) || (current_entry == NULL) || (num_to_ret == NULL))
                return -ENOENT;
 
-       *ppCurrentEntry = NULL;
-       first_entry_in_buffer =
-               cifsFile->srch_inf.index_of_last_entry -
-                       cifsFile->srch_inf.entries_in_buffer;
+       *current_entry = NULL;
+       first_entry_in_buffer = cfile->srch_inf.index_of_last_entry -
+                                       cfile->srch_inf.entries_in_buffer;
 
-       /* if first entry in buf is zero then is first buffer
-       in search response data which means it is likely . and ..
-       will be in this buffer, although some servers do not return
-       . and .. for the root of a drive and for those we need
-       to start two entries earlier */
+       /*
+        * If first entry in buf is zero then is first buffer
+        * in search response data which means it is likely . and ..
+        * will be in this buffer, although some servers do not return
+        * . and .. for the root of a drive and for those we need
+        * to start two entries earlier.
+        */
 
        dump_cifs_file_struct(file, "In fce ");
-       if (((index_to_find < cifsFile->srch_inf.index_of_last_entry) &&
-            is_dir_changed(file)) ||
-          (index_to_find < first_entry_in_buffer)) {
+       if (((index_to_find < cfile->srch_inf.index_of_last_entry) &&
+            is_dir_changed(file)) || (index_to_find < first_entry_in_buffer)) {
                /* close and restart search */
                cFYI(1, "search backing up - close and restart search");
                spin_lock(&cifs_file_list_lock);
-               if (!cifsFile->srch_inf.endOfSearch &&
-                   !cifsFile->invalidHandle) {
-                       cifsFile->invalidHandle = true;
+               if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) {
+                       cfile->invalidHandle = true;
                        spin_unlock(&cifs_file_list_lock);
-                       CIFSFindClose(xid, pTcon, cifsFile->netfid);
+                       if (server->ops->close)
+                               server->ops->close(xid, tcon, &cfile->fid);
                } else
                        spin_unlock(&cifs_file_list_lock);
-               if (cifsFile->srch_inf.ntwrk_buf_start) {
+               if (cfile->srch_inf.ntwrk_buf_start) {
                        cFYI(1, "freeing SMB ff cache buf on search rewind");
-                       if (cifsFile->srch_inf.smallBuf)
-                               cifs_small_buf_release(cifsFile->srch_inf.
+                       if (cfile->srch_inf.smallBuf)
+                               cifs_small_buf_release(cfile->srch_inf.
                                                ntwrk_buf_start);
                        else
-                               cifs_buf_release(cifsFile->srch_inf.
+                               cifs_buf_release(cfile->srch_inf.
                                                ntwrk_buf_start);
-                       cifsFile->srch_inf.ntwrk_buf_start = NULL;
+                       cfile->srch_inf.ntwrk_buf_start = NULL;
                }
                rc = initiate_cifs_search(xid, file);
                if (rc) {
@@ -565,65 +579,64 @@ static int find_cifs_entry(const unsigned int xid, struct cifs_tcon *pTcon,
                        return rc;
                }
                /* FindFirst/Next set last_entry to NULL on malformed reply */
-               if (cifsFile->srch_inf.last_entry)
-                       cifs_save_resume_key(cifsFile->srch_inf.last_entry,
-                                               cifsFile);
+               if (cfile->srch_inf.last_entry)
+                       cifs_save_resume_key(cfile->srch_inf.last_entry, cfile);
        }
 
        search_flags = CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME;
        if (backup_cred(cifs_sb))
                search_flags |= CIFS_SEARCH_BACKUP_SEARCH;
 
-       while ((index_to_find >= cifsFile->srch_inf.index_of_last_entry) &&
-             (rc == 0) && !cifsFile->srch_inf.endOfSearch) {
+       while ((index_to_find >= cfile->srch_inf.index_of_last_entry) &&
+              (rc == 0) && !cfile->srch_inf.endOfSearch) {
                cFYI(1, "calling findnext2");
-               rc = CIFSFindNext(xid, pTcon, cifsFile->netfid, search_flags,
-                                 &cifsFile->srch_inf);
+               rc = server->ops->query_dir_next(xid, tcon, &cfile->fid,
+                                                search_flags,
+                                                &cfile->srch_inf);
                /* FindFirst/Next set last_entry to NULL on malformed reply */
-               if (cifsFile->srch_inf.last_entry)
-                       cifs_save_resume_key(cifsFile->srch_inf.last_entry,
-                                               cifsFile);
+               if (cfile->srch_inf.last_entry)
+                       cifs_save_resume_key(cfile->srch_inf.last_entry, cfile);
                if (rc)
                        return -ENOENT;
        }
-       if (index_to_find < cifsFile->srch_inf.index_of_last_entry) {
+       if (index_to_find < cfile->srch_inf.index_of_last_entry) {
                /* we found the buffer that contains the entry */
                /* scan and find it */
                int i;
-               char *current_entry;
-               char *end_of_smb = cifsFile->srch_inf.ntwrk_buf_start +
-                       smbCalcSize((struct smb_hdr *)
-                               cifsFile->srch_inf.ntwrk_buf_start);
-
-               current_entry = cifsFile->srch_inf.srch_entries_start;
-               first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry
-                                       - cifsFile->srch_inf.entries_in_buffer;
+               char *cur_ent;
+               char *end_of_smb = cfile->srch_inf.ntwrk_buf_start +
+                       server->ops->calc_smb_size(
+                                       cfile->srch_inf.ntwrk_buf_start);
+
+               cur_ent = cfile->srch_inf.srch_entries_start;
+               first_entry_in_buffer = cfile->srch_inf.index_of_last_entry
+                                       - cfile->srch_inf.entries_in_buffer;
                pos_in_buf = index_to_find - first_entry_in_buffer;
                cFYI(1, "found entry - pos_in_buf %d", pos_in_buf);
 
-               for (i = 0; (i < (pos_in_buf)) && (current_entry != NULL); i++) {
+               for (i = 0; (i < (pos_in_buf)) && (cur_ent != NULL); i++) {
                        /* go entry by entry figuring out which is first */
-                       current_entry = nxt_dir_entry(current_entry, end_of_smb,
-                                               cifsFile->srch_inf.info_level);
+                       cur_ent = nxt_dir_entry(cur_ent, end_of_smb,
+                                               cfile->srch_inf.info_level);
                }
-               if ((current_entry == NULL) && (i < pos_in_buf)) {
+               if ((cur_ent == NULL) && (i < pos_in_buf)) {
                        /* BB fixme - check if we should flag this error */
                        cERROR(1, "reached end of buf searching for pos in buf"
-                         " %d index to find %lld rc %d",
-                         pos_in_buf, index_to_find, rc);
+                                 " %d index to find %lld rc %d", pos_in_buf,
+                                 index_to_find, rc);
                }
                rc = 0;
-               *ppCurrentEntry = current_entry;
+               *current_entry = cur_ent;
        } else {
                cFYI(1, "index not in buffer - could not findnext into it");
                return 0;
        }
 
-       if (pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) {
+       if (pos_in_buf >= cfile->srch_inf.entries_in_buffer) {
                cFYI(1, "can not return entries pos_in_buf beyond last");
                *num_to_ret = 0;
        } else
-               *num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf;
+               *num_to_ret = cfile->srch_inf.entries_in_buffer - pos_in_buf;
 
        return rc;
 }
@@ -723,7 +736,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
        int rc = 0;
        unsigned int xid;
        int i;
-       struct cifs_tcon *pTcon;
+       struct cifs_tcon *tcon;
        struct cifsFileInfo *cifsFile = NULL;
        char *current_entry;
        int num_to_fill = 0;
@@ -781,12 +794,12 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
                        }
                } /* else {
                        cifsFile->invalidHandle = true;
-                       CIFSFindClose(xid, pTcon, cifsFile->netfid);
+                       tcon->ses->server->close(xid, tcon, &cifsFile->fid);
                } */
 
-               pTcon = tlink_tcon(cifsFile->tlink);
-               rc = find_cifs_entry(xid, pTcon, file,
-                               &current_entry, &num_to_fill);
+               tcon = tlink_tcon(cifsFile->tlink);
+               rc = find_cifs_entry(xid, tcon, file, &current_entry,
+                                    &num_to_fill);
                if (rc) {
                        cFYI(1, "fce error %d", rc);
                        goto rddir2_exit;
@@ -798,7 +811,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
                }
                cFYI(1, "loop through %d times filling dir for net buf %p",
                        num_to_fill, cifsFile->srch_inf.ntwrk_buf_start);
-               max_len = smbCalcSize((struct smb_hdr *)
+               max_len = tcon->ses->server->ops->calc_smb_size(
                                cifsFile->srch_inf.ntwrk_buf_start);
                end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len;
 
@@ -815,10 +828,12 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir)
                                          num_to_fill, i);
                                break;
                        }
-                       /* if buggy server returns . and .. late do
-                       we want to check for that here? */
-                       rc = cifs_filldir(current_entry, file,
-                                       filldir, direntry, tmp_buf, max_len);
+                       /*
+                        * if buggy server returns . and .. late do we want to
+                        * check for that here?
+                        */
+                       rc = cifs_filldir(current_entry, file, filldir,
+                                         direntry, tmp_buf, max_len);
                        if (rc == -EOVERFLOW) {
                                rc = 0;
                                break;
index 3129ac74b819f4bc0d921e00a92dda6d01a434a8..f6c7a1c9a1b66bde0db601d2fc05deb59d66d76f 100644 (file)
@@ -17,6 +17,8 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+#include <linux/pagemap.h>
+#include <linux/vfs.h>
 #include "cifsglob.h"
 #include "cifsproto.h"
 #include "cifs_debug.h"
@@ -63,7 +65,7 @@ send_nt_cancel(struct TCP_Server_Info *server, void *buf,
 static bool
 cifs_compare_fids(struct cifsFileInfo *ob1, struct cifsFileInfo *ob2)
 {
-       return ob1->netfid == ob2->netfid;
+       return ob1->fid.netfid == ob2->fid.netfid;
 }
 
 static unsigned int
@@ -410,6 +412,89 @@ cifs_negotiate(const unsigned int xid, struct cifs_ses *ses)
        return rc;
 }
 
+static unsigned int
+cifs_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
+{
+       __u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
+       struct TCP_Server_Info *server = tcon->ses->server;
+       unsigned int wsize;
+
+       /* start with specified wsize, or default */
+       if (volume_info->wsize)
+               wsize = volume_info->wsize;
+       else if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_WRITE_CAP))
+               wsize = CIFS_DEFAULT_IOSIZE;
+       else
+               wsize = CIFS_DEFAULT_NON_POSIX_WSIZE;
+
+       /* can server support 24-bit write sizes? (via UNIX extensions) */
+       if (!tcon->unix_ext || !(unix_cap & CIFS_UNIX_LARGE_WRITE_CAP))
+               wsize = min_t(unsigned int, wsize, CIFS_MAX_RFC1002_WSIZE);
+
+       /*
+        * no CAP_LARGE_WRITE_X or is signing enabled without CAP_UNIX set?
+        * Limit it to max buffer offered by the server, minus the size of the
+        * WRITEX header, not including the 4 byte RFC1001 length.
+        */
+       if (!(server->capabilities & CAP_LARGE_WRITE_X) ||
+           (!(server->capabilities & CAP_UNIX) &&
+            (server->sec_mode & (SECMODE_SIGN_ENABLED|SECMODE_SIGN_REQUIRED))))
+               wsize = min_t(unsigned int, wsize,
+                               server->maxBuf - sizeof(WRITE_REQ) + 4);
+
+       /* limit to the amount that we can kmap at once */
+       wsize = min_t(unsigned int, wsize, CIFS_KMAP_SIZE_LIMIT);
+
+       /* hard limit of CIFS_MAX_WSIZE */
+       wsize = min_t(unsigned int, wsize, CIFS_MAX_WSIZE);
+
+       return wsize;
+}
+
+static unsigned int
+cifs_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
+{
+       __u64 unix_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
+       struct TCP_Server_Info *server = tcon->ses->server;
+       unsigned int rsize, defsize;
+
+       /*
+        * Set default value...
+        *
+        * HACK alert! Ancient servers have very small buffers. Even though
+        * MS-CIFS indicates that servers are only limited by the client's
+        * bufsize for reads, testing against win98se shows that it throws
+        * INVALID_PARAMETER errors if you try to request too large a read.
+        * OS/2 just sends back short reads.
+        *
+        * If the server doesn't advertise CAP_LARGE_READ_X, then assume that
+        * it can't handle a read request larger than its MaxBufferSize either.
+        */
+       if (tcon->unix_ext && (unix_cap & CIFS_UNIX_LARGE_READ_CAP))
+               defsize = CIFS_DEFAULT_IOSIZE;
+       else if (server->capabilities & CAP_LARGE_READ_X)
+               defsize = CIFS_DEFAULT_NON_POSIX_RSIZE;
+       else
+               defsize = server->maxBuf - sizeof(READ_RSP);
+
+       rsize = volume_info->rsize ? volume_info->rsize : defsize;
+
+       /*
+        * no CAP_LARGE_READ_X? Then MS-CIFS states that we must limit this to
+        * the client's MaxBufferSize.
+        */
+       if (!(server->capabilities & CAP_LARGE_READ_X))
+               rsize = min_t(unsigned int, CIFSMaxBufSize, rsize);
+
+       /* limit to the amount that we can kmap at once */
+       rsize = min_t(unsigned int, rsize, CIFS_KMAP_SIZE_LIMIT);
+
+       /* hard limit of CIFS_MAX_RSIZE */
+       rsize = min_t(unsigned int, rsize, CIFS_MAX_RSIZE);
+
+       return rsize;
+}
+
 static void
 cifs_qfs_tcon(const unsigned int xid, struct cifs_tcon *tcon)
 {
@@ -489,6 +574,13 @@ cifs_get_srv_inum(const unsigned int xid, struct cifs_tcon *tcon,
                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
 }
 
+static int
+cifs_query_file_info(const unsigned int xid, struct cifs_tcon *tcon,
+                    struct cifs_fid *fid, FILE_ALL_INFO *data)
+{
+       return CIFSSMBQFileInfo(xid, tcon, fid->netfid, data);
+}
+
 static char *
 cifs_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
                        struct cifs_tcon *tcon)
@@ -607,6 +699,212 @@ cifs_mkdir_setinfo(struct inode *inode, const char *full_path,
                cifsInode->cifsAttrs = dosattrs;
 }
 
+static int
+cifs_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
+              int disposition, int desired_access, int create_options,
+              struct cifs_fid *fid, __u32 *oplock, FILE_ALL_INFO *buf,
+              struct cifs_sb_info *cifs_sb)
+{
+       if (!(tcon->ses->capabilities & CAP_NT_SMBS))
+               return SMBLegacyOpen(xid, tcon, path, disposition,
+                                    desired_access, create_options,
+                                    &fid->netfid, oplock, buf,
+                                    cifs_sb->local_nls, cifs_sb->mnt_cifs_flags
+                                               & CIFS_MOUNT_MAP_SPECIAL_CHR);
+       return CIFSSMBOpen(xid, tcon, path, disposition, desired_access,
+                          create_options, &fid->netfid, oplock, buf,
+                          cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
+                                               CIFS_MOUNT_MAP_SPECIAL_CHR);
+}
+
+static void
+cifs_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock)
+{
+       struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
+       cfile->fid.netfid = fid->netfid;
+       cifs_set_oplock_level(cinode, oplock);
+       cinode->can_cache_brlcks = cinode->clientCanCacheAll;
+}
+
+static int
+cifs_close_file(const unsigned int xid, struct cifs_tcon *tcon,
+               struct cifs_fid *fid)
+{
+       return CIFSSMBClose(xid, tcon, fid->netfid);
+}
+
+static int
+cifs_flush_file(const unsigned int xid, struct cifs_tcon *tcon,
+               struct cifs_fid *fid)
+{
+       return CIFSSMBFlush(xid, tcon, fid->netfid);
+}
+
+static int
+cifs_sync_read(const unsigned int xid, struct cifsFileInfo *cfile,
+              struct cifs_io_parms *parms, unsigned int *bytes_read,
+              char **buf, int *buf_type)
+{
+       parms->netfid = cfile->fid.netfid;
+       return CIFSSMBRead(xid, parms, bytes_read, buf, buf_type);
+}
+
+static int
+cifs_sync_write(const unsigned int xid, struct cifsFileInfo *cfile,
+               struct cifs_io_parms *parms, unsigned int *written,
+               struct kvec *iov, unsigned long nr_segs)
+{
+
+       parms->netfid = cfile->fid.netfid;
+       return CIFSSMBWrite2(xid, parms, written, iov, nr_segs);
+}
+
+static int
+smb_set_file_info(struct inode *inode, const char *full_path,
+                 FILE_BASIC_INFO *buf, const unsigned int xid)
+{
+       int oplock = 0;
+       int rc;
+       __u16 netfid;
+       __u32 netpid;
+       struct cifsFileInfo *open_file;
+       struct cifsInodeInfo *cinode = CIFS_I(inode);
+       struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+       struct tcon_link *tlink = NULL;
+       struct cifs_tcon *tcon;
+       FILE_BASIC_INFO info_buf;
+
+       /* if the file is already open for write, just use that fileid */
+       open_file = find_writable_file(cinode, true);
+       if (open_file) {
+               netfid = open_file->fid.netfid;
+               netpid = open_file->pid;
+               tcon = tlink_tcon(open_file->tlink);
+               goto set_via_filehandle;
+       }
+
+       tlink = cifs_sb_tlink(cifs_sb);
+       if (IS_ERR(tlink)) {
+               rc = PTR_ERR(tlink);
+               tlink = NULL;
+               goto out;
+       }
+       tcon = tlink_tcon(tlink);
+
+       /*
+        * NT4 apparently returns success on this call, but it doesn't really
+        * work.
+        */
+       if (!(tcon->ses->flags & CIFS_SES_NT4)) {
+               rc = CIFSSMBSetPathInfo(xid, tcon, full_path, buf,
+                                       cifs_sb->local_nls,
+                                       cifs_sb->mnt_cifs_flags &
+                                               CIFS_MOUNT_MAP_SPECIAL_CHR);
+               if (rc == 0) {
+                       cinode->cifsAttrs = le32_to_cpu(buf->Attributes);
+                       goto out;
+               } else if (rc != -EOPNOTSUPP && rc != -EINVAL)
+                       goto out;
+       }
+
+       cFYI(1, "calling SetFileInfo since SetPathInfo for times not supported "
+               "by this server");
+       rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN,
+                        SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, CREATE_NOT_DIR,
+                        &netfid, &oplock, NULL, cifs_sb->local_nls,
+                        cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+
+       if (rc != 0) {
+               if (rc == -EIO)
+                       rc = -EINVAL;
+               goto out;
+       }
+
+       netpid = current->tgid;
+
+set_via_filehandle:
+       rc = CIFSSMBSetFileInfo(xid, tcon, &info_buf, netfid, netpid);
+       if (!rc)
+               cinode->cifsAttrs = le32_to_cpu(buf->Attributes);
+
+       if (open_file == NULL)
+               CIFSSMBClose(xid, tcon, netfid);
+       else
+               cifsFileInfo_put(open_file);
+out:
+       if (tlink != NULL)
+               cifs_put_tlink(tlink);
+       return rc;
+}
+
+static int
+cifs_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
+                    const char *path, struct cifs_sb_info *cifs_sb,
+                    struct cifs_fid *fid, __u16 search_flags,
+                    struct cifs_search_info *srch_inf)
+{
+       return CIFSFindFirst(xid, tcon, path, cifs_sb->local_nls,
+                            &fid->netfid, search_flags, srch_inf,
+                            cifs_sb->mnt_cifs_flags &
+                            CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb));
+}
+
+static int
+cifs_query_dir_next(const unsigned int xid, struct cifs_tcon *tcon,
+                   struct cifs_fid *fid, __u16 search_flags,
+                   struct cifs_search_info *srch_inf)
+{
+       return CIFSFindNext(xid, tcon, fid->netfid, search_flags, srch_inf);
+}
+
+static int
+cifs_close_dir(const unsigned int xid, struct cifs_tcon *tcon,
+              struct cifs_fid *fid)
+{
+       return CIFSFindClose(xid, tcon, fid->netfid);
+}
+
+static int
+cifs_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid,
+                    struct cifsInodeInfo *cinode)
+{
+       return CIFSSMBLock(0, tcon, fid->netfid, current->tgid, 0, 0, 0, 0,
+                          LOCKING_ANDX_OPLOCK_RELEASE, false,
+                          cinode->clientCanCacheRead ? 1 : 0);
+}
+
+static int
+cifs_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
+            struct kstatfs *buf)
+{
+       int rc = -EOPNOTSUPP;
+
+       buf->f_type = CIFS_MAGIC_NUMBER;
+
+       /*
+        * We could add a second check for a QFS Unix capability bit
+        */
+       if ((tcon->ses->capabilities & CAP_UNIX) &&
+           (CIFS_POSIX_EXTENSIONS & le64_to_cpu(tcon->fsUnixInfo.Capability)))
+               rc = CIFSSMBQFSPosixInfo(xid, tcon, buf);
+
+       /*
+        * Only need to call the old QFSInfo if failed on newer one,
+        * e.g. by OS/2.
+        **/
+       if (rc && (tcon->ses->capabilities & CAP_NT_SMBS))
+               rc = CIFSSMBQFSInfo(xid, tcon, buf);
+
+       /*
+        * Some old Windows servers also do not support level 103, retry with
+        * older level one if old server failed the previous call or we
+        * bypassed it because we detected that this was an older LANMAN sess
+        */
+       if (rc)
+               rc = SMBOldQFSInfo(xid, tcon, buf);
+       return rc;
+}
+
 struct smb_version_operations smb1_operations = {
        .send_cancel = send_nt_cancel,
        .compare_fids = cifs_compare_fids,
@@ -630,6 +928,8 @@ struct smb_version_operations smb1_operations = {
        .check_trans2 = cifs_check_trans2,
        .need_neg = cifs_need_neg,
        .negotiate = cifs_negotiate,
+       .negotiate_wsize = cifs_negotiate_wsize,
+       .negotiate_rsize = cifs_negotiate_rsize,
        .sess_setup = CIFS_SessSetup,
        .logoff = CIFSSMBLogoff,
        .tree_connect = CIFSTCon,
@@ -638,12 +938,34 @@ struct smb_version_operations smb1_operations = {
        .qfs_tcon = cifs_qfs_tcon,
        .is_path_accessible = cifs_is_path_accessible,
        .query_path_info = cifs_query_path_info,
+       .query_file_info = cifs_query_file_info,
        .get_srv_inum = cifs_get_srv_inum,
+       .set_path_size = CIFSSMBSetEOF,
+       .set_file_size = CIFSSMBSetFileSize,
+       .set_file_info = smb_set_file_info,
        .build_path_to_root = cifs_build_path_to_root,
        .echo = CIFSSMBEcho,
        .mkdir = CIFSSMBMkDir,
        .mkdir_setinfo = cifs_mkdir_setinfo,
        .rmdir = CIFSSMBRmDir,
+       .unlink = CIFSSMBDelFile,
+       .rename_pending_delete = cifs_rename_pending_delete,
+       .rename = CIFSSMBRename,
+       .create_hardlink = CIFSCreateHardLink,
+       .open = cifs_open_file,
+       .set_fid = cifs_set_fid,
+       .close = cifs_close_file,
+       .flush = cifs_flush_file,
+       .async_readv = cifs_async_readv,
+       .async_writev = cifs_async_writev,
+       .sync_read = cifs_sync_read,
+       .sync_write = cifs_sync_write,
+       .query_dir_first = cifs_query_dir_first,
+       .query_dir_next = cifs_query_dir_next,
+       .close_dir = cifs_close_dir,
+       .calc_smb_size = smbCalcSize,
+       .oplock_response = cifs_oplock_response,
+       .queryfs = cifs_queryfs,
 };
 
 struct smb_version_values smb1_values = {
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c
new file mode 100644 (file)
index 0000000..5ff25e0
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ *   fs/cifs/smb2file.c
+ *
+ *   Copyright (C) International Business Machines  Corp., 2002, 2011
+ *   Author(s): Steve French (sfrench@us.ibm.com),
+ *              Pavel Shilovsky ((pshilovsky@samba.org) 2012
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+ *   the GNU Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public License
+ *   along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/slab.h>
+#include <linux/pagemap.h>
+#include <asm/div64.h>
+#include "cifsfs.h"
+#include "cifspdu.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "cifs_debug.h"
+#include "cifs_fs_sb.h"
+#include "cifs_unicode.h"
+#include "fscache.h"
+#include "smb2proto.h"
+
+void
+smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)
+{
+       oplock &= 0xFF;
+       if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
+               cinode->clientCanCacheAll = true;
+               cinode->clientCanCacheRead = true;
+               cFYI(1, "Exclusive Oplock granted on inode %p",
+                    &cinode->vfs_inode);
+       } else if (oplock == SMB2_OPLOCK_LEVEL_II) {
+               cinode->clientCanCacheAll = false;
+               cinode->clientCanCacheRead = true;
+               cFYI(1, "Level II Oplock granted on inode %p",
+                   &cinode->vfs_inode);
+       } else {
+               cinode->clientCanCacheAll = false;
+               cinode->clientCanCacheRead = false;
+       }
+}
+
+int
+smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon, const char *path,
+              int disposition, int desired_access, int create_options,
+              struct cifs_fid *fid, __u32 *oplock, FILE_ALL_INFO *buf,
+              struct cifs_sb_info *cifs_sb)
+{
+       int rc;
+       __le16 *smb2_path;
+       struct smb2_file_all_info *smb2_data = NULL;
+
+       smb2_path = cifs_convert_path_to_utf16(path, cifs_sb);
+       if (smb2_path == NULL) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + MAX_NAME * 2,
+                           GFP_KERNEL);
+       if (smb2_data == NULL) {
+               rc = -ENOMEM;
+               goto out;
+       }
+
+       desired_access |= FILE_READ_ATTRIBUTES;
+       *oplock = SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+
+       rc = SMB2_open(xid, tcon, smb2_path, &fid->persistent_fid,
+                      &fid->volatile_fid, desired_access, disposition,
+                      0, 0, (__u8 *)oplock, smb2_data);
+       if (rc)
+               goto out;
+
+       if (buf) {
+               /* open response does not have IndexNumber field - get it */
+               rc = SMB2_get_srv_num(xid, tcon, fid->persistent_fid,
+                                     fid->volatile_fid,
+                                     &smb2_data->IndexNumber);
+               if (rc) {
+                       /* let get_inode_info disable server inode numbers */
+                       smb2_data->IndexNumber = 0;
+                       rc = 0;
+               }
+               move_smb2_info_to_cifs(buf, smb2_data);
+       }
+
+out:
+       kfree(smb2_data);
+       kfree(smb2_path);
+       return rc;
+}
index 33c1d89090c0e5f68cb8b6157bda1451a5182860..7c0e2143e775e04f183ccad271de61e73bc2edf3 100644 (file)
@@ -23,6 +23,8 @@
 #ifndef _SMB2_GLOB_H
 #define _SMB2_GLOB_H
 
+#define SMB2_MAGIC_NUMBER 0xFE534D42
+
 /*
  *****************************************************************
  * Constants go here
 #define SMB2_OP_MKDIR 5
 #define SMB2_OP_RENAME 6
 #define SMB2_OP_DELETE 7
+#define SMB2_OP_HARDLINK 8
+#define SMB2_OP_SET_EOF 9
+
+/* Used when constructing chained read requests. */
+#define CHAINED_REQUEST 1
+#define START_OF_CHAIN 2
+#define END_OF_CHAIN 4
+#define RELATED_REQUEST 8
+
+#define SMB2_SIGNATURE_SIZE (16)
+#define SMB2_NTLMV2_SESSKEY_SIZE (16)
+#define SMB2_HMACSHA256_SIZE (32)
 
 #endif /* _SMB2_GLOB_H */
index 2aa5cb08c526a3461ea759ea6f09b8abb65686b9..706482452df4f8ce196520fc2d34043dd1d42e6a 100644 (file)
@@ -47,6 +47,7 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
        int rc, tmprc = 0;
        u64 persistent_fid, volatile_fid;
        __le16 *utf16_path;
+       __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
 
        utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
        if (!utf16_path)
@@ -54,7 +55,7 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
 
        rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid,
                       desired_access, create_disposition, file_attributes,
-                      create_options);
+                      create_options, &oplock, NULL);
        if (rc) {
                kfree(utf16_path);
                return rc;
@@ -74,6 +75,22 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
                 * SMB2_open() call.
                 */
                break;
+       case SMB2_OP_RENAME:
+               tmprc = SMB2_rename(xid, tcon, persistent_fid, volatile_fid,
+                                   (__le16 *)data);
+               break;
+       case SMB2_OP_HARDLINK:
+               tmprc = SMB2_set_hardlink(xid, tcon, persistent_fid,
+                                         volatile_fid, (__le16 *)data);
+               break;
+       case SMB2_OP_SET_EOF:
+               tmprc = SMB2_set_eof(xid, tcon, persistent_fid, volatile_fid,
+                                    current->tgid, (__le64 *)data);
+               break;
+       case SMB2_OP_SET_INFO:
+               tmprc = SMB2_set_info(xid, tcon, persistent_fid, volatile_fid,
+                                     (FILE_BASIC_INFO *)data);
+               break;
        default:
                cERROR(1, "Invalid command");
                break;
@@ -86,7 +103,7 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
        return rc;
 }
 
-static void
+void
 move_smb2_info_to_cifs(FILE_ALL_INFO *dst, struct smb2_file_all_info *src)
 {
        memcpy(dst, src, (size_t)(&src->CurrentByteOffset) - (size_t)src);
@@ -161,3 +178,80 @@ smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
                                  0, CREATE_NOT_FILE | CREATE_DELETE_ON_CLOSE,
                                  NULL, SMB2_OP_DELETE);
 }
+
+int
+smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
+           struct cifs_sb_info *cifs_sb)
+{
+       return smb2_open_op_close(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
+                                 0, CREATE_DELETE_ON_CLOSE, NULL,
+                                 SMB2_OP_DELETE);
+}
+
+static int
+smb2_set_path_attr(const unsigned int xid, struct cifs_tcon *tcon,
+                  const char *from_name, const char *to_name,
+                  struct cifs_sb_info *cifs_sb, __u32 access, int command)
+{
+       __le16 *smb2_to_name = NULL;
+       int rc;
+
+       smb2_to_name = cifs_convert_path_to_utf16(to_name, cifs_sb);
+       if (smb2_to_name == NULL) {
+               rc = -ENOMEM;
+               goto smb2_rename_path;
+       }
+
+       rc = smb2_open_op_close(xid, tcon, cifs_sb, from_name, access,
+                               FILE_OPEN, 0, 0, smb2_to_name, command);
+smb2_rename_path:
+       kfree(smb2_to_name);
+       return rc;
+}
+
+int
+smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
+                const char *from_name, const char *to_name,
+                struct cifs_sb_info *cifs_sb)
+{
+       return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
+                                 DELETE, SMB2_OP_RENAME);
+}
+
+int
+smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
+                    const char *from_name, const char *to_name,
+                    struct cifs_sb_info *cifs_sb)
+{
+       return smb2_set_path_attr(xid, tcon, from_name, to_name, cifs_sb,
+                                 FILE_READ_ATTRIBUTES, SMB2_OP_HARDLINK);
+}
+
+int
+smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
+                  const char *full_path, __u64 size,
+                  struct cifs_sb_info *cifs_sb, bool set_alloc)
+{
+       __le64 eof = cpu_to_le64(size);
+       return smb2_open_op_close(xid, tcon, cifs_sb, full_path,
+                                 FILE_WRITE_DATA, FILE_OPEN, 0, 0, &eof,
+                                 SMB2_OP_SET_EOF);
+}
+
+int
+smb2_set_file_info(struct inode *inode, const char *full_path,
+                  FILE_BASIC_INFO *buf, const unsigned int xid)
+{
+       struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+       struct tcon_link *tlink;
+       int rc;
+
+       tlink = cifs_sb_tlink(cifs_sb);
+       if (IS_ERR(tlink))
+               return PTR_ERR(tlink);
+       rc = smb2_open_op_close(xid, tlink_tcon(tlink), cifs_sb, full_path,
+                               FILE_WRITE_ATTRIBUTES, FILE_OPEN, 0, 0, buf,
+                               SMB2_OP_SET_INFO);
+       cifs_put_tlink(tlink);
+       return rc;
+}
index be41478acc05ef5395bc40b2ea9f101f38eb62f5..eaf5466d4041f79601fadcd146e5e9a220293386 100644 (file)
@@ -2455,7 +2455,8 @@ map_smb2_to_linux_error(char *buf, bool log_err)
                return 0;
 
        /* mask facility */
-       if (log_err && (smb2err != (STATUS_MORE_PROCESSING_REQUIRED)))
+       if (log_err && (smb2err != STATUS_MORE_PROCESSING_REQUIRED) &&
+           (smb2err != STATUS_END_OF_FILE))
                smb2_print_status(smb2err);
        else if (cifsFYI & CIFS_RC)
                smb2_print_status(smb2err);
index a4ff5d547554d174466bc48eb7c8fccb48c8f668..0a9bb354dd46fddb560e948cb1a16676e58f9aef 100644 (file)
@@ -52,7 +52,8 @@ check_smb2_hdr(struct smb2_hdr *hdr, __u64 mid)
                        cERROR(1, "Bad protocol string signature header %x",
                                  *(unsigned int *) hdr->ProtocolId);
                if (mid != hdr->MessageId)
-                       cERROR(1, "Mids do not match");
+                       cERROR(1, "Mids do not match: %llu and %llu", mid,
+                                 hdr->MessageId);
        }
        cERROR(1, "Bad SMB detected. The Mid=%llu", hdr->MessageId);
        return 1;
@@ -107,7 +108,7 @@ smb2_check_message(char *buf, unsigned int length)
         * ie Validate the wct via smb2_struct_sizes table above
         */
 
-       if (length < 2 + sizeof(struct smb2_hdr)) {
+       if (length < sizeof(struct smb2_pdu)) {
                if ((length >= sizeof(struct smb2_hdr)) && (hdr->Status != 0)) {
                        pdu->StructureSize2 = 0;
                        /*
@@ -121,15 +122,15 @@ smb2_check_message(char *buf, unsigned int length)
                return 1;
        }
        if (len > CIFSMaxBufSize + MAX_SMB2_HDR_SIZE - 4) {
-               cERROR(1, "SMB length greater than maximum, mid=%lld", mid);
+               cERROR(1, "SMB length greater than maximum, mid=%llu", mid);
                return 1;
        }
 
        if (check_smb2_hdr(hdr, mid))
                return 1;
 
-       if (hdr->StructureSize != SMB2_HEADER_SIZE) {
-               cERROR(1, "Illegal structure size %d",
+       if (hdr->StructureSize != SMB2_HEADER_STRUCTURE_SIZE) {
+               cERROR(1, "Illegal structure size %u",
                          le16_to_cpu(hdr->StructureSize));
                return 1;
        }
@@ -141,8 +142,8 @@ smb2_check_message(char *buf, unsigned int length)
        }
 
        if (smb2_rsp_struct_sizes[command] != pdu->StructureSize2) {
-               if (hdr->Status == 0 ||
-                   pdu->StructureSize2 != SMB2_ERROR_STRUCTURE_SIZE2) {
+               if (command != SMB2_OPLOCK_BREAK_HE && (hdr->Status == 0 ||
+                   pdu->StructureSize2 != SMB2_ERROR_STRUCTURE_SIZE2)) {
                        /* error packets have 9 byte structure size */
                        cERROR(1, "Illegal response size %u for command %d",
                                   le16_to_cpu(pdu->StructureSize2), command);
@@ -161,8 +162,11 @@ smb2_check_message(char *buf, unsigned int length)
        if (4 + len != clc_len) {
                cFYI(1, "Calculated size %u length %u mismatch mid %llu",
                        clc_len, 4 + len, mid);
-               if (clc_len == 4 + len + 1) /* BB FIXME (fix samba) */
-                       return 0; /* BB workaround Samba 3 bug SessSetup rsp */
+               if (clc_len + 20 == len && command == SMB2_OPLOCK_BREAK_HE)
+                       return 0; /* Windows 7 server returns 24 bytes more */
+               /* server can return one byte more */
+               if (clc_len == 4 + len + 1)
+                       return 0;
                return 1;
        }
        return 0;
@@ -242,7 +246,15 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr)
                    ((struct smb2_query_info_rsp *)hdr)->OutputBufferLength);
                break;
        case SMB2_READ:
+               *off = ((struct smb2_read_rsp *)hdr)->DataOffset;
+               *len = le32_to_cpu(((struct smb2_read_rsp *)hdr)->DataLength);
+               break;
        case SMB2_QUERY_DIRECTORY:
+               *off = le16_to_cpu(
+                 ((struct smb2_query_directory_rsp *)hdr)->OutputBufferOffset);
+               *len = le32_to_cpu(
+                 ((struct smb2_query_directory_rsp *)hdr)->OutputBufferLength);
+               break;
        case SMB2_IOCTL:
        case SMB2_CHANGE_NOTIFY:
        default:
@@ -285,8 +297,9 @@ smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr)
  * portion, the number of word parameters and the data portion of the message.
  */
 unsigned int
-smb2_calc_size(struct smb2_hdr *hdr)
+smb2_calc_size(void *buf)
 {
+       struct smb2_hdr *hdr = (struct smb2_hdr *)buf;
        struct smb2_pdu *pdu = (struct smb2_pdu *)hdr;
        int offset; /* the offset from the beginning of SMB to data area */
        int data_length; /* the length of the variable length data area */
@@ -345,3 +358,72 @@ cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb)
                                        CIFS_MOUNT_MAP_SPECIAL_CHR);
        return to;
 }
+
+bool
+smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
+{
+       struct smb2_oplock_break *rsp = (struct smb2_oplock_break *)buffer;
+       struct list_head *tmp, *tmp1, *tmp2;
+       struct cifs_ses *ses;
+       struct cifs_tcon *tcon;
+       struct cifsInodeInfo *cinode;
+       struct cifsFileInfo *cfile;
+
+       cFYI(1, "Checking for oplock break");
+
+       if (rsp->hdr.Command != SMB2_OPLOCK_BREAK)
+               return false;
+
+       if (le16_to_cpu(rsp->StructureSize) !=
+                               smb2_rsp_struct_sizes[SMB2_OPLOCK_BREAK_HE]) {
+               return false;
+       }
+
+       cFYI(1, "oplock level 0x%d", rsp->OplockLevel);
+
+       /* look up tcon based on tid & uid */
+       spin_lock(&cifs_tcp_ses_lock);
+       list_for_each(tmp, &server->smb_ses_list) {
+               ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
+               list_for_each(tmp1, &ses->tcon_list) {
+                       tcon = list_entry(tmp1, struct cifs_tcon, tcon_list);
+
+                       cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks);
+                       spin_lock(&cifs_file_list_lock);
+                       list_for_each(tmp2, &tcon->openFileList) {
+                               cfile = list_entry(tmp2, struct cifsFileInfo,
+                                                    tlist);
+                               if (rsp->PersistentFid !=
+                                   cfile->fid.persistent_fid ||
+                                   rsp->VolatileFid !=
+                                   cfile->fid.volatile_fid)
+                                       continue;
+
+                               cFYI(1, "file id match, oplock break");
+                               cinode = CIFS_I(cfile->dentry->d_inode);
+
+                               if (!cinode->clientCanCacheAll &&
+                                   rsp->OplockLevel == SMB2_OPLOCK_LEVEL_NONE)
+                                       cfile->oplock_break_cancelled = true;
+                               else
+                                       cfile->oplock_break_cancelled = false;
+
+                               smb2_set_oplock_level(cinode,
+                                 rsp->OplockLevel ? SMB2_OPLOCK_LEVEL_II : 0);
+
+                               queue_work(cifsiod_wq, &cfile->oplock_break);
+
+                               spin_unlock(&cifs_file_list_lock);
+                               spin_unlock(&cifs_tcp_ses_lock);
+                               return true;
+                       }
+                       spin_unlock(&cifs_file_list_lock);
+                       spin_unlock(&cifs_tcp_ses_lock);
+                       cFYI(1, "No matching file for oplock break");
+                       return true;
+               }
+       }
+       spin_unlock(&cifs_tcp_ses_lock);
+       cFYI(1, "Can not process oplock break for non-existent connection");
+       return false;
+}
index 826209bf36842c904259533a0199fc6f5138a0b9..3a8c682580269ac2adbf34e90ccdecb87c07415c 100644 (file)
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
+#include <linux/pagemap.h>
+#include <linux/vfs.h>
 #include "cifsglob.h"
 #include "smb2pdu.h"
 #include "smb2proto.h"
 #include "cifsproto.h"
 #include "cifs_debug.h"
+#include "smb2status.h"
+#include "smb2glob.h"
 
 static int
 change_conf(struct TCP_Server_Info *server)
@@ -63,6 +67,17 @@ smb2_add_credits(struct TCP_Server_Info *server, const unsigned int add,
        server->in_flight--;
        if (server->in_flight == 0 && (optype & CIFS_OP_MASK) != CIFS_NEG_OP)
                rc = change_conf(server);
+       /*
+        * Sometimes server returns 0 credits on oplock break ack - we need to
+        * rebalance credits in this case.
+        */
+       else if (server->in_flight > 0 && server->oplock_credits == 0 &&
+                server->oplocks) {
+               if (server->credits > 1) {
+                       server->credits--;
+                       server->oplock_credits++;
+               }
+       }
        spin_unlock(&server->req_lock);
        wake_up(&server->request_q);
        if (rc)
@@ -157,6 +172,48 @@ smb2_negotiate(const unsigned int xid, struct cifs_ses *ses)
        return rc;
 }
 
+static unsigned int
+smb2_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
+{
+       struct TCP_Server_Info *server = tcon->ses->server;
+       unsigned int wsize;
+
+       /* start with specified wsize, or default */
+       wsize = volume_info->wsize ? volume_info->wsize : CIFS_DEFAULT_IOSIZE;
+       wsize = min_t(unsigned int, wsize, server->max_write);
+       /*
+        * limit write size to 2 ** 16, because we don't support multicredit
+        * requests now.
+        */
+       wsize = min_t(unsigned int, wsize, 2 << 15);
+
+       /* limit to the amount that we can kmap at once */
+       wsize = min_t(unsigned int, wsize, CIFS_KMAP_SIZE_LIMIT);
+
+       return wsize;
+}
+
+static unsigned int
+smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info)
+{
+       struct TCP_Server_Info *server = tcon->ses->server;
+       unsigned int rsize;
+
+       /* start with specified rsize, or default */
+       rsize = volume_info->rsize ? volume_info->rsize : CIFS_DEFAULT_IOSIZE;
+       rsize = min_t(unsigned int, rsize, server->max_read);
+       /*
+        * limit write size to 2 ** 16, because we don't support multicredit
+        * requests now.
+        */
+       rsize = min_t(unsigned int, rsize, 2 << 15);
+
+       /* limit to the amount that we can kmap at once */
+       rsize = min_t(unsigned int, rsize, CIFS_KMAP_SIZE_LIMIT);
+
+       return rsize;
+}
+
 static int
 smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
                        struct cifs_sb_info *cifs_sb, const char *full_path)
@@ -164,13 +221,14 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
        int rc;
        __u64 persistent_fid, volatile_fid;
        __le16 *utf16_path;
+       __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
 
        utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
        if (!utf16_path)
                return -ENOMEM;
 
        rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid,
-                      FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0);
+                      FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0, &oplock, NULL);
        if (rc) {
                kfree(utf16_path);
                return rc;
@@ -190,6 +248,26 @@ smb2_get_srv_inum(const unsigned int xid, struct cifs_tcon *tcon,
        return 0;
 }
 
+static int
+smb2_query_file_info(const unsigned int xid, struct cifs_tcon *tcon,
+                    struct cifs_fid *fid, FILE_ALL_INFO *data)
+{
+       int rc;
+       struct smb2_file_all_info *smb2_data;
+
+       smb2_data = kzalloc(sizeof(struct smb2_file_all_info) + MAX_NAME * 2,
+                           GFP_KERNEL);
+       if (smb2_data == NULL)
+               return -ENOMEM;
+
+       rc = SMB2_query_info(xid, tcon, fid->persistent_fid, fid->volatile_fid,
+                            smb2_data);
+       if (!rc)
+               move_smb2_info_to_cifs(data, smb2_data);
+       kfree(smb2_data);
+       return rc;
+}
+
 static char *
 smb2_build_path_to_root(struct smb_vol *vol, struct cifs_sb_info *cifs_sb,
                        struct cifs_tcon *tcon)
@@ -292,6 +370,179 @@ smb2_print_stats(struct seq_file *m, struct cifs_tcon *tcon)
 #endif
 }
 
+static void
+smb2_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock)
+{
+       struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
+       cfile->fid.persistent_fid = fid->persistent_fid;
+       cfile->fid.volatile_fid = fid->volatile_fid;
+       smb2_set_oplock_level(cinode, oplock);
+       /* cinode->can_cache_brlcks = cinode->clientCanCacheAll; */
+}
+
+static int
+smb2_close_file(const unsigned int xid, struct cifs_tcon *tcon,
+               struct cifs_fid *fid)
+{
+       return SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid);
+}
+
+static int
+smb2_flush_file(const unsigned int xid, struct cifs_tcon *tcon,
+               struct cifs_fid *fid)
+{
+       return SMB2_flush(xid, tcon, fid->persistent_fid, fid->volatile_fid);
+}
+
+static unsigned int
+smb2_read_data_offset(char *buf)
+{
+       struct smb2_read_rsp *rsp = (struct smb2_read_rsp *)buf;
+       return rsp->DataOffset;
+}
+
+static unsigned int
+smb2_read_data_length(char *buf)
+{
+       struct smb2_read_rsp *rsp = (struct smb2_read_rsp *)buf;
+       return le32_to_cpu(rsp->DataLength);
+}
+
+
+static int
+smb2_sync_read(const unsigned int xid, struct cifsFileInfo *cfile,
+              struct cifs_io_parms *parms, unsigned int *bytes_read,
+              char **buf, int *buf_type)
+{
+       parms->persistent_fid = cfile->fid.persistent_fid;
+       parms->volatile_fid = cfile->fid.volatile_fid;
+       return SMB2_read(xid, parms, bytes_read, buf, buf_type);
+}
+
+static int
+smb2_sync_write(const unsigned int xid, struct cifsFileInfo *cfile,
+               struct cifs_io_parms *parms, unsigned int *written,
+               struct kvec *iov, unsigned long nr_segs)
+{
+
+       parms->persistent_fid = cfile->fid.persistent_fid;
+       parms->volatile_fid = cfile->fid.volatile_fid;
+       return SMB2_write(xid, parms, written, iov, nr_segs);
+}
+
+static int
+smb2_set_file_size(const unsigned int xid, struct cifs_tcon *tcon,
+                  struct cifsFileInfo *cfile, __u64 size, bool set_alloc)
+{
+       __le64 eof = cpu_to_le64(size);
+       return SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid,
+                           cfile->fid.volatile_fid, cfile->pid, &eof);
+}
+
+static int
+smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
+                    const char *path, struct cifs_sb_info *cifs_sb,
+                    struct cifs_fid *fid, __u16 search_flags,
+                    struct cifs_search_info *srch_inf)
+{
+       __le16 *utf16_path;
+       int rc;
+       __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
+       __u64 persistent_fid, volatile_fid;
+
+       utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
+       if (!utf16_path)
+               return -ENOMEM;
+
+       rc = SMB2_open(xid, tcon, utf16_path, &persistent_fid, &volatile_fid,
+                      FILE_READ_ATTRIBUTES | FILE_READ_DATA, FILE_OPEN, 0, 0,
+                      &oplock, NULL);
+       kfree(utf16_path);
+       if (rc) {
+               cERROR(1, "open dir failed");
+               return rc;
+       }
+
+       srch_inf->entries_in_buffer = 0;
+       srch_inf->index_of_last_entry = 0;
+       fid->persistent_fid = persistent_fid;
+       fid->volatile_fid = volatile_fid;
+
+       rc = SMB2_query_directory(xid, tcon, persistent_fid, volatile_fid, 0,
+                                 srch_inf);
+       if (rc) {
+               cERROR(1, "query directory failed");
+               SMB2_close(xid, tcon, persistent_fid, volatile_fid);
+       }
+       return rc;
+}
+
+static int
+smb2_query_dir_next(const unsigned int xid, struct cifs_tcon *tcon,
+                   struct cifs_fid *fid, __u16 search_flags,
+                   struct cifs_search_info *srch_inf)
+{
+       return SMB2_query_directory(xid, tcon, fid->persistent_fid,
+                                   fid->volatile_fid, 0, srch_inf);
+}
+
+static int
+smb2_close_dir(const unsigned int xid, struct cifs_tcon *tcon,
+              struct cifs_fid *fid)
+{
+       return SMB2_close(xid, tcon, fid->persistent_fid, fid->volatile_fid);
+}
+
+/*
+* If we negotiate SMB2 protocol and get STATUS_PENDING - update
+* the number of credits and return true. Otherwise - return false.
+*/
+static bool
+smb2_is_status_pending(char *buf, struct TCP_Server_Info *server, int length)
+{
+       struct smb2_hdr *hdr = (struct smb2_hdr *)buf;
+
+       if (le32_to_cpu(hdr->Status) != STATUS_PENDING)
+               return false;
+
+       if (!length) {
+               spin_lock(&server->req_lock);
+               server->credits += le16_to_cpu(hdr->CreditRequest);
+               spin_unlock(&server->req_lock);
+               wake_up(&server->request_q);
+       }
+
+       return true;
+}
+
+static int
+smb2_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid,
+                    struct cifsInodeInfo *cinode)
+{
+       return SMB2_oplock_break(0, tcon, fid->persistent_fid,
+                                fid->volatile_fid,
+                                cinode->clientCanCacheRead ? 1 : 0);
+}
+
+static int
+smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
+            struct kstatfs *buf)
+{
+       int rc;
+       u64 persistent_fid, volatile_fid;
+       __le16 srch_path = 0; /* Null - open root of share */
+       u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
+
+       rc = SMB2_open(xid, tcon, &srch_path, &persistent_fid, &volatile_fid,
+                      FILE_READ_ATTRIBUTES, FILE_OPEN, 0, 0, &oplock, NULL);
+       if (rc)
+               return rc;
+       buf->f_type = SMB2_MAGIC_NUMBER;
+       rc = SMB2_QFS_info(xid, tcon, persistent_fid, volatile_fid, buf);
+       SMB2_close(xid, tcon, persistent_fid, volatile_fid);
+       return rc;
+}
+
 struct smb_version_operations smb21_operations = {
        .setup_request = smb2_setup_request,
        .setup_async_request = smb2_setup_async_request,
@@ -301,13 +552,19 @@ struct smb_version_operations smb21_operations = {
        .get_credits_field = smb2_get_credits_field,
        .get_credits = smb2_get_credits,
        .get_next_mid = smb2_get_next_mid,
+       .read_data_offset = smb2_read_data_offset,
+       .read_data_length = smb2_read_data_length,
+       .map_error = map_smb2_to_linux_error,
        .find_mid = smb2_find_mid,
        .check_message = smb2_check_message,
        .dump_detail = smb2_dump_detail,
        .clear_stats = smb2_clear_stats,
        .print_stats = smb2_print_stats,
+       .is_oplock_break = smb2_is_valid_oplock_break,
        .need_neg = smb2_need_neg,
        .negotiate = smb2_negotiate,
+       .negotiate_wsize = smb2_negotiate_wsize,
+       .negotiate_rsize = smb2_negotiate_rsize,
        .sess_setup = SMB2_sess_setup,
        .logoff = SMB2_logoff,
        .tree_connect = SMB2_tcon,
@@ -317,16 +574,39 @@ struct smb_version_operations smb21_operations = {
        .echo = SMB2_echo,
        .query_path_info = smb2_query_path_info,
        .get_srv_inum = smb2_get_srv_inum,
+       .query_file_info = smb2_query_file_info,
+       .set_path_size = smb2_set_path_size,
+       .set_file_size = smb2_set_file_size,
+       .set_file_info = smb2_set_file_info,
        .build_path_to_root = smb2_build_path_to_root,
        .mkdir = smb2_mkdir,
        .mkdir_setinfo = smb2_mkdir_setinfo,
        .rmdir = smb2_rmdir,
+       .unlink = smb2_unlink,
+       .rename = smb2_rename_path,
+       .create_hardlink = smb2_create_hardlink,
+       .open = smb2_open_file,
+       .set_fid = smb2_set_fid,
+       .close = smb2_close_file,
+       .flush = smb2_flush_file,
+       .async_readv = smb2_async_readv,
+       .async_writev = smb2_async_writev,
+       .sync_read = smb2_sync_read,
+       .sync_write = smb2_sync_write,
+       .query_dir_first = smb2_query_dir_first,
+       .query_dir_next = smb2_query_dir_next,
+       .close_dir = smb2_close_dir,
+       .calc_smb_size = smb2_calc_size,
+       .is_status_pending = smb2_is_status_pending,
+       .oplock_response = smb2_oplock_response,
+       .queryfs = smb2_queryfs,
 };
 
 struct smb_version_values smb21_values = {
        .version_string = SMB21_VERSION_STRING,
        .header_size = sizeof(struct smb2_hdr),
        .max_header_size = MAX_SMB2_HDR_SIZE,
+       .read_rsp_size = sizeof(struct smb2_read_rsp) - 1,
        .lock_cmd = SMB2_LOCK,
        .cap_unix = 0,
        .cap_nt_find = SMB2_NT_FIND,
index 62b3f17d061363657374bacfab7dc7abff21a5a6..b1834203c8317e418c03dfc2e14a59cfda488c7a 100644 (file)
@@ -31,7 +31,9 @@
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/vfs.h>
+#include <linux/task_io_accounting_ops.h>
 #include <linux/uaccess.h>
+#include <linux/pagemap.h>
 #include <linux/xattr.h>
 #include "smb2pdu.h"
 #include "cifsglob.h"
@@ -42,6 +44,8 @@
 #include "cifs_debug.h"
 #include "ntlmssp.h"
 #include "smb2status.h"
+#include "smb2glob.h"
+#include "cifspdu.h"
 
 /*
  *  The following table defines the expected "StructureSize" of SMB2 requests
@@ -115,9 +119,9 @@ smb2_hdr_assemble(struct smb2_hdr *hdr, __le16 smb2_cmd /* command */ ,
        /* BB how does SMB2 do case sensitive? */
        /* if (tcon->nocase)
                hdr->Flags |= SMBFLG_CASELESS; */
-       /* if (tcon->ses && tcon->ses->server &&
+       if (tcon->ses && tcon->ses->server &&
            (tcon->ses->server->sec_mode & SECMODE_SIGN_REQUIRED))
-               hdr->Flags |= SMB2_FLAGS_SIGNED; */
+               hdr->Flags |= SMB2_FLAGS_SIGNED;
 out:
        pdu->StructureSize2 = cpu_to_le16(parmsize);
        return;
@@ -438,6 +442,38 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
                rc = -EIO;
                goto neg_exit;
        }
+
+       cFYI(1, "sec_flags 0x%x", sec_flags);
+       if (sec_flags & CIFSSEC_MUST_SIGN) {
+               cFYI(1, "Signing required");
+               if (!(server->sec_mode & (SMB2_NEGOTIATE_SIGNING_REQUIRED |
+                     SMB2_NEGOTIATE_SIGNING_ENABLED))) {
+                       cERROR(1, "signing required but server lacks support");
+                       rc = -EOPNOTSUPP;
+                       goto neg_exit;
+               }
+               server->sec_mode |= SECMODE_SIGN_REQUIRED;
+       } else if (sec_flags & CIFSSEC_MAY_SIGN) {
+               cFYI(1, "Signing optional");
+               if (server->sec_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) {
+                       cFYI(1, "Server requires signing");
+                       server->sec_mode |= SECMODE_SIGN_REQUIRED;
+               } else {
+                       server->sec_mode &=
+                               ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
+               }
+       } else {
+               cFYI(1, "Signing disabled");
+               if (server->sec_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) {
+                       cERROR(1, "Server requires packet signing to be enabled"
+                                 " in /proc/fs/cifs/SecurityFlags.");
+                       rc = -EOPNOTSUPP;
+                       goto neg_exit;
+               }
+               server->sec_mode &=
+                       ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
+       }
+
 #ifdef CONFIG_SMB2_ASN1  /* BB REMOVEME when updated asn1.c ready */
        rc = decode_neg_token_init(security_blob, blob_length,
                                   &server->sec_type);
@@ -666,6 +702,8 @@ SMB2_logoff(const unsigned int xid, struct cifs_ses *ses)
 
         /* since no tcon, smb2_init can not do this, so do here */
        req->hdr.SessionId = ses->Suid;
+       if (server->sec_mode & SECMODE_SIGN_REQUIRED)
+               req->hdr.Flags |= SMB2_FLAGS_SIGNED;
 
        rc = SendReceiveNoRsp(xid, ses, (char *) &req->hdr, 0);
        /*
@@ -833,7 +871,8 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
 int
 SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
          u64 *persistent_fid, u64 *volatile_fid, __u32 desired_access,
-         __u32 create_disposition, __u32 file_attributes, __u32 create_options)
+         __u32 create_disposition, __u32 file_attributes, __u32 create_options,
+         __u8 *oplock, struct smb2_file_all_info *buf)
 {
        struct smb2_create_req *req;
        struct smb2_create_rsp *rsp;
@@ -856,7 +895,7 @@ SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
        if (rc)
                return rc;
 
-       if (enable_oplocks)
+       if (server->oplocks)
                req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_BATCH;
        else
                req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_NONE;
@@ -906,6 +945,17 @@ SMB2_open(const unsigned int xid, struct cifs_tcon *tcon, __le16 *path,
        }
        *persistent_fid = rsp->PersistentFileId;
        *volatile_fid = rsp->VolatileFileId;
+
+       if (buf) {
+               memcpy(buf, &rsp->CreationTime, 32);
+               buf->AllocationSize = rsp->AllocationSize;
+               buf->EndOfFile = rsp->EndofFile;
+               buf->Attributes = rsp->FileAttributes;
+               buf->NumberOfLinks = cpu_to_le32(1);
+               buf->DeletePending = 0;
+       }
+
+       *oplock = rsp->OplockLevel;
 creat_exit:
        free_rsp_buf(resp_buftype, rsp);
        return rc;
@@ -1019,10 +1069,10 @@ validate_and_copy_buf(unsigned int offset, unsigned int buffer_length,
        return 0;
 }
 
-int
-SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
-               u64 persistent_fid, u64 volatile_fid,
-               struct smb2_file_all_info *data)
+static int
+query_info(const unsigned int xid, struct cifs_tcon *tcon,
+          u64 persistent_fid, u64 volatile_fid, u8 info_class,
+          size_t output_len, size_t min_len, void *data)
 {
        struct smb2_query_info_req *req;
        struct smb2_query_info_rsp *rsp = NULL;
@@ -1044,14 +1094,13 @@ SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
                return rc;
 
        req->InfoType = SMB2_O_INFO_FILE;
-       req->FileInfoClass = FILE_ALL_INFORMATION;
+       req->FileInfoClass = info_class;
        req->PersistentFileId = persistent_fid;
        req->VolatileFileId = volatile_fid;
        /* 4 for rfc1002 length field and 1 for Buffer */
        req->InputBufferOffset =
                cpu_to_le16(sizeof(struct smb2_query_info_req) - 1 - 4);
-       req->OutputBufferLength =
-               cpu_to_le32(sizeof(struct smb2_file_all_info) + MAX_NAME * 2);
+       req->OutputBufferLength = cpu_to_le32(output_len);
 
        iov[0].iov_base = (char *)req;
        /* 4 for rfc1002 length field */
@@ -1067,14 +1116,34 @@ SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
 
        rc = validate_and_copy_buf(le16_to_cpu(rsp->OutputBufferOffset),
                                   le32_to_cpu(rsp->OutputBufferLength),
-                                  &rsp->hdr, sizeof(struct smb2_file_all_info),
-                                  (char *)data);
+                                  &rsp->hdr, min_len, data);
 
 qinf_exit:
        free_rsp_buf(resp_buftype, rsp);
        return rc;
 }
 
+int
+SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
+               u64 persistent_fid, u64 volatile_fid,
+               struct smb2_file_all_info *data)
+{
+       return query_info(xid, tcon, persistent_fid, volatile_fid,
+                         FILE_ALL_INFORMATION,
+                         sizeof(struct smb2_file_all_info) + MAX_NAME * 2,
+                         sizeof(struct smb2_file_all_info), data);
+}
+
+int
+SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon,
+                u64 persistent_fid, u64 volatile_fid, __le64 *uniqueid)
+{
+       return query_info(xid, tcon, persistent_fid, volatile_fid,
+                         FILE_INTERNAL_INFORMATION,
+                         sizeof(struct smb2_file_internal_info),
+                         sizeof(struct smb2_file_internal_info), uniqueid);
+}
+
 /*
  * This is a no-op for now. We're not really interested in the reply, but
  * rather in the fact that the server sent one and that server->lstrp
@@ -1123,3 +1192,864 @@ SMB2_echo(struct TCP_Server_Info *server)
        cifs_small_buf_release(req);
        return rc;
 }
+
+int
+SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
+          u64 volatile_fid)
+{
+       struct smb2_flush_req *req;
+       struct TCP_Server_Info *server;
+       struct cifs_ses *ses = tcon->ses;
+       struct kvec iov[1];
+       int resp_buftype;
+       int rc = 0;
+
+       cFYI(1, "Flush");
+
+       if (ses && (ses->server))
+               server = ses->server;
+       else
+               return -EIO;
+
+       rc = small_smb2_init(SMB2_FLUSH, tcon, (void **) &req);
+       if (rc)
+               return rc;
+
+       req->PersistentFileId = persistent_fid;
+       req->VolatileFileId = volatile_fid;
+
+       iov[0].iov_base = (char *)req;
+       /* 4 for rfc1002 length field */
+       iov[0].iov_len = get_rfc1002_length(req) + 4;
+
+       rc = SendReceive2(xid, ses, iov, 1, &resp_buftype, 0);
+
+       if ((rc != 0) && tcon)
+               cifs_stats_fail_inc(tcon, SMB2_FLUSH_HE);
+
+       free_rsp_buf(resp_buftype, iov[0].iov_base);
+       return rc;
+}
+
+/*
+ * To form a chain of read requests, any read requests after the first should
+ * have the end_of_chain boolean set to true.
+ */
+static int
+smb2_new_read_req(struct kvec *iov, struct cifs_io_parms *io_parms,
+                 unsigned int remaining_bytes, int request_type)
+{
+       int rc = -EACCES;
+       struct smb2_read_req *req = NULL;
+
+       rc = small_smb2_init(SMB2_READ, io_parms->tcon, (void **) &req);
+       if (rc)
+               return rc;
+       if (io_parms->tcon->ses->server == NULL)
+               return -ECONNABORTED;
+
+       req->hdr.ProcessId = cpu_to_le32(io_parms->pid);
+
+       req->PersistentFileId = io_parms->persistent_fid;
+       req->VolatileFileId = io_parms->volatile_fid;
+       req->ReadChannelInfoOffset = 0; /* reserved */
+       req->ReadChannelInfoLength = 0; /* reserved */
+       req->Channel = 0; /* reserved */
+       req->MinimumCount = 0;
+       req->Length = cpu_to_le32(io_parms->length);
+       req->Offset = cpu_to_le64(io_parms->offset);
+
+       if (request_type & CHAINED_REQUEST) {
+               if (!(request_type & END_OF_CHAIN)) {
+                       /* 4 for rfc1002 length field */
+                       req->hdr.NextCommand =
+                               cpu_to_le32(get_rfc1002_length(req) + 4);
+               } else /* END_OF_CHAIN */
+                       req->hdr.NextCommand = 0;
+               if (request_type & RELATED_REQUEST) {
+                       req->hdr.Flags |= SMB2_FLAGS_RELATED_OPERATIONS;
+                       /*
+                        * Related requests use info from previous read request
+                        * in chain.
+                        */
+                       req->hdr.SessionId = 0xFFFFFFFF;
+                       req->hdr.TreeId = 0xFFFFFFFF;
+                       req->PersistentFileId = 0xFFFFFFFF;
+                       req->VolatileFileId = 0xFFFFFFFF;
+               }
+       }
+       if (remaining_bytes > io_parms->length)
+               req->RemainingBytes = cpu_to_le32(remaining_bytes);
+       else
+               req->RemainingBytes = 0;
+
+       iov[0].iov_base = (char *)req;
+       /* 4 for rfc1002 length field */
+       iov[0].iov_len = get_rfc1002_length(req) + 4;
+       return rc;
+}
+
+static void
+smb2_readv_callback(struct mid_q_entry *mid)
+{
+       struct cifs_readdata *rdata = mid->callback_data;
+       struct cifs_tcon *tcon = tlink_tcon(rdata->cfile->tlink);
+       struct TCP_Server_Info *server = tcon->ses->server;
+       struct smb2_hdr *buf = (struct smb2_hdr *)rdata->iov[0].iov_base;
+       unsigned int credits_received = 1;
+
+       cFYI(1, "%s: mid=%llu state=%d result=%d bytes=%u", __func__,
+               mid->mid, mid->mid_state, rdata->result, rdata->bytes);
+
+       switch (mid->mid_state) {
+       case MID_RESPONSE_RECEIVED:
+               credits_received = le16_to_cpu(buf->CreditRequest);
+               /* result already set, check signature */
+               if (server->sec_mode &
+                   (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
+                       if (smb2_verify_signature2(rdata->iov, rdata->nr_iov,
+                                                  server))
+                               cERROR(1, "Unexpected SMB signature");
+               }
+               /* FIXME: should this be counted toward the initiating task? */
+               task_io_account_read(rdata->bytes);
+               cifs_stats_bytes_read(tcon, rdata->bytes);
+               break;
+       case MID_REQUEST_SUBMITTED:
+       case MID_RETRY_NEEDED:
+               rdata->result = -EAGAIN;
+               break;
+       default:
+               if (rdata->result != -ENODATA)
+                       rdata->result = -EIO;
+       }
+
+       if (rdata->result)
+               cifs_stats_fail_inc(tcon, SMB2_READ_HE);
+
+       queue_work(cifsiod_wq, &rdata->work);
+       DeleteMidQEntry(mid);
+       add_credits(server, credits_received, 0);
+}
+
+/* smb2_async_readv - send an async write, and set up mid to handle result */
+int
+smb2_async_readv(struct cifs_readdata *rdata)
+{
+       int rc;
+       struct smb2_hdr *buf;
+       struct cifs_io_parms io_parms;
+
+       cFYI(1, "%s: offset=%llu bytes=%u", __func__,
+               rdata->offset, rdata->bytes);
+
+       io_parms.tcon = tlink_tcon(rdata->cfile->tlink);
+       io_parms.offset = rdata->offset;
+       io_parms.length = rdata->bytes;
+       io_parms.persistent_fid = rdata->cfile->fid.persistent_fid;
+       io_parms.volatile_fid = rdata->cfile->fid.volatile_fid;
+       io_parms.pid = rdata->pid;
+       rc = smb2_new_read_req(&rdata->iov[0], &io_parms, 0, 0);
+       if (rc)
+               return rc;
+
+       buf = (struct smb2_hdr *)rdata->iov[0].iov_base;
+       /* 4 for rfc1002 length field */
+       rdata->iov[0].iov_len = get_rfc1002_length(rdata->iov[0].iov_base) + 4;
+
+       kref_get(&rdata->refcount);
+       rc = cifs_call_async(io_parms.tcon->ses->server, rdata->iov, 1,
+                            cifs_readv_receive, smb2_readv_callback,
+                            rdata, 0);
+       if (rc)
+               kref_put(&rdata->refcount, cifs_readdata_release);
+
+       cifs_small_buf_release(buf);
+       return rc;
+}
+
+int
+SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
+         unsigned int *nbytes, char **buf, int *buf_type)
+{
+       int resp_buftype, rc = -EACCES;
+       struct smb2_read_rsp *rsp = NULL;
+       struct kvec iov[1];
+
+       *nbytes = 0;
+       rc = smb2_new_read_req(iov, io_parms, 0, 0);
+       if (rc)
+               return rc;
+
+       rc = SendReceive2(xid, io_parms->tcon->ses, iov, 1,
+                         &resp_buftype, CIFS_LOG_ERROR);
+
+       rsp = (struct smb2_read_rsp *)iov[0].iov_base;
+
+       if (rsp->hdr.Status == STATUS_END_OF_FILE) {
+               free_rsp_buf(resp_buftype, iov[0].iov_base);
+               return 0;
+       }
+
+       if (rc) {
+               cifs_stats_fail_inc(io_parms->tcon, SMB2_READ_HE);
+               cERROR(1, "Send error in read = %d", rc);
+       } else {
+               *nbytes = le32_to_cpu(rsp->DataLength);
+               if ((*nbytes > CIFS_MAX_MSGSIZE) ||
+                   (*nbytes > io_parms->length)) {
+                       cFYI(1, "bad length %d for count %d", *nbytes,
+                               io_parms->length);
+                       rc = -EIO;
+                       *nbytes = 0;
+               }
+       }
+
+       if (*buf) {
+               memcpy(*buf, (char *)rsp->hdr.ProtocolId + rsp->DataOffset,
+                      *nbytes);
+               free_rsp_buf(resp_buftype, iov[0].iov_base);
+       } else if (resp_buftype != CIFS_NO_BUFFER) {
+               *buf = iov[0].iov_base;
+               if (resp_buftype == CIFS_SMALL_BUFFER)
+                       *buf_type = CIFS_SMALL_BUFFER;
+               else if (resp_buftype == CIFS_LARGE_BUFFER)
+                       *buf_type = CIFS_LARGE_BUFFER;
+       }
+       return rc;
+}
+
+/*
+ * Check the mid_state and signature on received buffer (if any), and queue the
+ * workqueue completion task.
+ */
+static void
+smb2_writev_callback(struct mid_q_entry *mid)
+{
+       struct cifs_writedata *wdata = mid->callback_data;
+       struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
+       unsigned int written;
+       struct smb2_write_rsp *rsp = (struct smb2_write_rsp *)mid->resp_buf;
+       unsigned int credits_received = 1;
+
+       switch (mid->mid_state) {
+       case MID_RESPONSE_RECEIVED:
+               credits_received = le16_to_cpu(rsp->hdr.CreditRequest);
+               wdata->result = smb2_check_receive(mid, tcon->ses->server, 0);
+               if (wdata->result != 0)
+                       break;
+
+               written = le32_to_cpu(rsp->DataLength);
+               /*
+                * Mask off high 16 bits when bytes written as returned
+                * by the server is greater than bytes requested by the
+                * client. OS/2 servers are known to set incorrect
+                * CountHigh values.
+                */
+               if (written > wdata->bytes)
+                       written &= 0xFFFF;
+
+               if (written < wdata->bytes)
+                       wdata->result = -ENOSPC;
+               else
+                       wdata->bytes = written;
+               break;
+       case MID_REQUEST_SUBMITTED:
+       case MID_RETRY_NEEDED:
+               wdata->result = -EAGAIN;
+               break;
+       default:
+               wdata->result = -EIO;
+               break;
+       }
+
+       if (wdata->result)
+               cifs_stats_fail_inc(tcon, SMB2_WRITE_HE);
+
+       queue_work(cifsiod_wq, &wdata->work);
+       DeleteMidQEntry(mid);
+       add_credits(tcon->ses->server, credits_received, 0);
+}
+
+/* smb2_async_writev - send an async write, and set up mid to handle result */
+int
+smb2_async_writev(struct cifs_writedata *wdata)
+{
+       int i, rc = -EACCES;
+       struct smb2_write_req *req = NULL;
+       struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink);
+       struct kvec *iov = NULL;
+
+       rc = small_smb2_init(SMB2_WRITE, tcon, (void **) &req);
+       if (rc)
+               goto async_writev_out;
+
+       /* 1 iov per page + 1 for header */
+       iov = kzalloc((wdata->nr_pages + 1) * sizeof(*iov), GFP_NOFS);
+       if (iov == NULL) {
+               rc = -ENOMEM;
+               goto async_writev_out;
+       }
+
+       req->hdr.ProcessId = cpu_to_le32(wdata->cfile->pid);
+
+       req->PersistentFileId = wdata->cfile->fid.persistent_fid;
+       req->VolatileFileId = wdata->cfile->fid.volatile_fid;
+       req->WriteChannelInfoOffset = 0;
+       req->WriteChannelInfoLength = 0;
+       req->Channel = 0;
+       req->Offset = cpu_to_le64(wdata->offset);
+       /* 4 for rfc1002 length field */
+       req->DataOffset = cpu_to_le16(
+                               offsetof(struct smb2_write_req, Buffer) - 4);
+       req->RemainingBytes = 0;
+
+       /* 4 for rfc1002 length field and 1 for Buffer */
+       iov[0].iov_len = get_rfc1002_length(req) + 4 - 1;
+       iov[0].iov_base = (char *)req;
+
+       /*
+        * This function should marshal up the page array into the kvec
+        * array, reserving [0] for the header. It should kmap the pages
+        * and set the iov_len properly for each one. It may also set
+        * wdata->bytes too.
+        */
+       cifs_kmap_lock();
+       wdata->marshal_iov(iov, wdata);
+       cifs_kmap_unlock();
+
+       cFYI(1, "async write at %llu %u bytes", wdata->offset, wdata->bytes);
+
+       req->Length = cpu_to_le32(wdata->bytes);
+
+       inc_rfc1001_len(&req->hdr, wdata->bytes - 1 /* Buffer */);
+
+       kref_get(&wdata->refcount);
+       rc = cifs_call_async(tcon->ses->server, iov, wdata->nr_pages + 1,
+                            NULL, smb2_writev_callback, wdata, 0);
+
+       if (rc)
+               kref_put(&wdata->refcount, cifs_writedata_release);
+
+       /* send is done, unmap pages */
+       for (i = 0; i < wdata->nr_pages; i++)
+               kunmap(wdata->pages[i]);
+
+async_writev_out:
+       cifs_small_buf_release(req);
+       kfree(iov);
+       return rc;
+}
+
+/*
+ * SMB2_write function gets iov pointer to kvec array with n_vec as a length.
+ * The length field from io_parms must be at least 1 and indicates a number of
+ * elements with data to write that begins with position 1 in iov array. All
+ * data length is specified by count.
+ */
+int
+SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
+          unsigned int *nbytes, struct kvec *iov, int n_vec)
+{
+       int rc = 0;
+       struct smb2_write_req *req = NULL;
+       struct smb2_write_rsp *rsp = NULL;
+       int resp_buftype;
+       *nbytes = 0;
+
+       if (n_vec < 1)
+               return rc;
+
+       rc = small_smb2_init(SMB2_WRITE, io_parms->tcon, (void **) &req);
+       if (rc)
+               return rc;
+
+       if (io_parms->tcon->ses->server == NULL)
+               return -ECONNABORTED;
+
+       req->hdr.ProcessId = cpu_to_le32(io_parms->pid);
+
+       req->PersistentFileId = io_parms->persistent_fid;
+       req->VolatileFileId = io_parms->volatile_fid;
+       req->WriteChannelInfoOffset = 0;
+       req->WriteChannelInfoLength = 0;
+       req->Channel = 0;
+       req->Length = cpu_to_le32(io_parms->length);
+       req->Offset = cpu_to_le64(io_parms->offset);
+       /* 4 for rfc1002 length field */
+       req->DataOffset = cpu_to_le16(
+                               offsetof(struct smb2_write_req, Buffer) - 4);
+       req->RemainingBytes = 0;
+
+       iov[0].iov_base = (char *)req;
+       /* 4 for rfc1002 length field and 1 for Buffer */
+       iov[0].iov_len = get_rfc1002_length(req) + 4 - 1;
+
+       /* length of entire message including data to be written */
+       inc_rfc1001_len(req, io_parms->length - 1 /* Buffer */);
+
+       rc = SendReceive2(xid, io_parms->tcon->ses, iov, n_vec + 1,
+                         &resp_buftype, 0);
+
+       if (rc) {
+               cifs_stats_fail_inc(io_parms->tcon, SMB2_WRITE_HE);
+               cERROR(1, "Send error in write = %d", rc);
+       } else {
+               rsp = (struct smb2_write_rsp *)iov[0].iov_base;
+               *nbytes = le32_to_cpu(rsp->DataLength);
+               free_rsp_buf(resp_buftype, rsp);
+       }
+       return rc;
+}
+
+static unsigned int
+num_entries(char *bufstart, char *end_of_buf, char **lastentry, size_t size)
+{
+       int len;
+       unsigned int entrycount = 0;
+       unsigned int next_offset = 0;
+       FILE_DIRECTORY_INFO *entryptr;
+
+       if (bufstart == NULL)
+               return 0;
+
+       entryptr = (FILE_DIRECTORY_INFO *)bufstart;
+
+       while (1) {
+               entryptr = (FILE_DIRECTORY_INFO *)
+                                       ((char *)entryptr + next_offset);
+
+               if ((char *)entryptr + size > end_of_buf) {
+                       cERROR(1, "malformed search entry would overflow");
+                       break;
+               }
+
+               len = le32_to_cpu(entryptr->FileNameLength);
+               if ((char *)entryptr + len + size > end_of_buf) {
+                       cERROR(1, "directory entry name would overflow frame "
+                                 "end of buf %p", end_of_buf);
+                       break;
+               }
+
+               *lastentry = (char *)entryptr;
+               entrycount++;
+
+               next_offset = le32_to_cpu(entryptr->NextEntryOffset);
+               if (!next_offset)
+                       break;
+       }
+
+       return entrycount;
+}
+
+/*
+ * Readdir/FindFirst
+ */
+int
+SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
+                    u64 persistent_fid, u64 volatile_fid, int index,
+                    struct cifs_search_info *srch_inf)
+{
+       struct smb2_query_directory_req *req;
+       struct smb2_query_directory_rsp *rsp = NULL;
+       struct kvec iov[2];
+       int rc = 0;
+       int len;
+       int resp_buftype;
+       unsigned char *bufptr;
+       struct TCP_Server_Info *server;
+       struct cifs_ses *ses = tcon->ses;
+       __le16 asteriks = cpu_to_le16('*');
+       char *end_of_smb;
+       unsigned int output_size = CIFSMaxBufSize;
+       size_t info_buf_size;
+
+       if (ses && (ses->server))
+               server = ses->server;
+       else
+               return -EIO;
+
+       rc = small_smb2_init(SMB2_QUERY_DIRECTORY, tcon, (void **) &req);
+       if (rc)
+               return rc;
+
+       switch (srch_inf->info_level) {
+       case SMB_FIND_FILE_DIRECTORY_INFO:
+               req->FileInformationClass = FILE_DIRECTORY_INFORMATION;
+               info_buf_size = sizeof(FILE_DIRECTORY_INFO) - 1;
+               break;
+       case SMB_FIND_FILE_ID_FULL_DIR_INFO:
+               req->FileInformationClass = FILEID_FULL_DIRECTORY_INFORMATION;
+               info_buf_size = sizeof(SEARCH_ID_FULL_DIR_INFO) - 1;
+               break;
+       default:
+               cERROR(1, "info level %u isn't supported",
+                      srch_inf->info_level);
+               rc = -EINVAL;
+               goto qdir_exit;
+       }
+
+       req->FileIndex = cpu_to_le32(index);
+       req->PersistentFileId = persistent_fid;
+       req->VolatileFileId = volatile_fid;
+
+       len = 0x2;
+       bufptr = req->Buffer;
+       memcpy(bufptr, &asteriks, len);
+
+       req->FileNameOffset =
+               cpu_to_le16(sizeof(struct smb2_query_directory_req) - 1 - 4);
+       req->FileNameLength = cpu_to_le16(len);
+       /*
+        * BB could be 30 bytes or so longer if we used SMB2 specific
+        * buffer lengths, but this is safe and close enough.
+        */
+       output_size = min_t(unsigned int, output_size, server->maxBuf);
+       output_size = min_t(unsigned int, output_size, 2 << 15);
+       req->OutputBufferLength = cpu_to_le32(output_size);
+
+       iov[0].iov_base = (char *)req;
+       /* 4 for RFC1001 length and 1 for Buffer */
+       iov[0].iov_len = get_rfc1002_length(req) + 4 - 1;
+
+       iov[1].iov_base = (char *)(req->Buffer);
+       iov[1].iov_len = len;
+
+       inc_rfc1001_len(req, len - 1 /* Buffer */);
+
+       rc = SendReceive2(xid, ses, iov, 2, &resp_buftype, 0);
+       if (rc) {
+               cifs_stats_fail_inc(tcon, SMB2_QUERY_DIRECTORY_HE);
+               goto qdir_exit;
+       }
+       rsp = (struct smb2_query_directory_rsp *)iov[0].iov_base;
+
+       rc = validate_buf(le16_to_cpu(rsp->OutputBufferOffset),
+                         le32_to_cpu(rsp->OutputBufferLength), &rsp->hdr,
+                         info_buf_size);
+       if (rc)
+               goto qdir_exit;
+
+       srch_inf->unicode = true;
+
+       if (srch_inf->ntwrk_buf_start) {
+               if (srch_inf->smallBuf)
+                       cifs_small_buf_release(srch_inf->ntwrk_buf_start);
+               else
+                       cifs_buf_release(srch_inf->ntwrk_buf_start);
+       }
+       srch_inf->ntwrk_buf_start = (char *)rsp;
+       srch_inf->srch_entries_start = srch_inf->last_entry = 4 /* rfclen */ +
+               (char *)&rsp->hdr + le16_to_cpu(rsp->OutputBufferOffset);
+       /* 4 for rfc1002 length field */
+       end_of_smb = get_rfc1002_length(rsp) + 4 + (char *)&rsp->hdr;
+       srch_inf->entries_in_buffer =
+                       num_entries(srch_inf->srch_entries_start, end_of_smb,
+                                   &srch_inf->last_entry, info_buf_size);
+       srch_inf->index_of_last_entry += srch_inf->entries_in_buffer;
+       cFYI(1, "num entries %d last_index %lld srch start %p srch end %p",
+               srch_inf->entries_in_buffer, srch_inf->index_of_last_entry,
+               srch_inf->srch_entries_start, srch_inf->last_entry);
+       if (resp_buftype == CIFS_LARGE_BUFFER)
+               srch_inf->smallBuf = false;
+       else if (resp_buftype == CIFS_SMALL_BUFFER)
+               srch_inf->smallBuf = true;
+       else
+               cERROR(1, "illegal search buffer type");
+
+       if (rsp->hdr.Status == STATUS_NO_MORE_FILES)
+               srch_inf->endOfSearch = 1;
+       else
+               srch_inf->endOfSearch = 0;
+
+       return rc;
+
+qdir_exit:
+       free_rsp_buf(resp_buftype, rsp);
+       return rc;
+}
+
+static int
+send_set_info(const unsigned int xid, struct cifs_tcon *tcon,
+              u64 persistent_fid, u64 volatile_fid, u32 pid, int info_class,
+              unsigned int num, void **data, unsigned int *size)
+{
+       struct smb2_set_info_req *req;
+       struct smb2_set_info_rsp *rsp = NULL;
+       struct kvec *iov;
+       int rc = 0;
+       int resp_buftype;
+       unsigned int i;
+       struct TCP_Server_Info *server;
+       struct cifs_ses *ses = tcon->ses;
+
+       if (ses && (ses->server))
+               server = ses->server;
+       else
+               return -EIO;
+
+       if (!num)
+               return -EINVAL;
+
+       iov = kmalloc(sizeof(struct kvec) * num, GFP_KERNEL);
+       if (!iov)
+               return -ENOMEM;
+
+       rc = small_smb2_init(SMB2_SET_INFO, tcon, (void **) &req);
+       if (rc) {
+               kfree(iov);
+               return rc;
+       }
+
+       req->hdr.ProcessId = cpu_to_le32(pid);
+
+       req->InfoType = SMB2_O_INFO_FILE;
+       req->FileInfoClass = info_class;
+       req->PersistentFileId = persistent_fid;
+       req->VolatileFileId = volatile_fid;
+
+       /* 4 for RFC1001 length and 1 for Buffer */
+       req->BufferOffset =
+                       cpu_to_le16(sizeof(struct smb2_set_info_req) - 1 - 4);
+       req->BufferLength = cpu_to_le32(*size);
+
+       inc_rfc1001_len(req, *size - 1 /* Buffer */);
+
+       memcpy(req->Buffer, *data, *size);
+
+       iov[0].iov_base = (char *)req;
+       /* 4 for RFC1001 length */
+       iov[0].iov_len = get_rfc1002_length(req) + 4;
+
+       for (i = 1; i < num; i++) {
+               inc_rfc1001_len(req, size[i]);
+               le32_add_cpu(&req->BufferLength, size[i]);
+               iov[i].iov_base = (char *)data[i];
+               iov[i].iov_len = size[i];
+       }
+
+       rc = SendReceive2(xid, ses, iov, num, &resp_buftype, 0);
+       rsp = (struct smb2_set_info_rsp *)iov[0].iov_base;
+
+       if (rc != 0) {
+               cifs_stats_fail_inc(tcon, SMB2_SET_INFO_HE);
+               goto out;
+       }
+
+       if (rsp == NULL) {
+               rc = -EIO;
+               goto out;
+       }
+
+out:
+       free_rsp_buf(resp_buftype, rsp);
+       kfree(iov);
+       return rc;
+}
+
+int
+SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon,
+           u64 persistent_fid, u64 volatile_fid, __le16 *target_file)
+{
+       struct smb2_file_rename_info info;
+       void **data;
+       unsigned int size[2];
+       int rc;
+       int len = (2 * UniStrnlen((wchar_t *)target_file, PATH_MAX));
+
+       data = kmalloc(sizeof(void *) * 2, GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       info.ReplaceIfExists = 1; /* 1 = replace existing target with new */
+                             /* 0 = fail if target already exists */
+       info.RootDirectory = 0;  /* MBZ for network ops (why does spec say?) */
+       info.FileNameLength = cpu_to_le32(len);
+
+       data[0] = &info;
+       size[0] = sizeof(struct smb2_file_rename_info);
+
+       data[1] = target_file;
+       size[1] = len + 2 /* null */;
+
+       rc = send_set_info(xid, tcon, persistent_fid, volatile_fid,
+                          current->tgid, FILE_RENAME_INFORMATION, 2, data,
+                          size);
+       kfree(data);
+       return rc;
+}
+
+int
+SMB2_set_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
+                 u64 persistent_fid, u64 volatile_fid, __le16 *target_file)
+{
+       struct smb2_file_link_info info;
+       void **data;
+       unsigned int size[2];
+       int rc;
+       int len = (2 * UniStrnlen((wchar_t *)target_file, PATH_MAX));
+
+       data = kmalloc(sizeof(void *) * 2, GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       info.ReplaceIfExists = 0; /* 1 = replace existing link with new */
+                             /* 0 = fail if link already exists */
+       info.RootDirectory = 0;  /* MBZ for network ops (why does spec say?) */
+       info.FileNameLength = cpu_to_le32(len);
+
+       data[0] = &info;
+       size[0] = sizeof(struct smb2_file_link_info);
+
+       data[1] = target_file;
+       size[1] = len + 2 /* null */;
+
+       rc = send_set_info(xid, tcon, persistent_fid, volatile_fid,
+                          current->tgid, FILE_LINK_INFORMATION, 2, data, size);
+       kfree(data);
+       return rc;
+}
+
+int
+SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
+            u64 volatile_fid, u32 pid, __le64 *eof)
+{
+       struct smb2_file_eof_info info;
+       void *data;
+       unsigned int size;
+
+       info.EndOfFile = *eof;
+
+       data = &info;
+       size = sizeof(struct smb2_file_eof_info);
+
+       return send_set_info(xid, tcon, persistent_fid, volatile_fid, pid,
+                            FILE_END_OF_FILE_INFORMATION, 1, &data, &size);
+}
+
+int
+SMB2_set_info(const unsigned int xid, struct cifs_tcon *tcon,
+             u64 persistent_fid, u64 volatile_fid, FILE_BASIC_INFO *buf)
+{
+       unsigned int size;
+       size = sizeof(FILE_BASIC_INFO);
+       return send_set_info(xid, tcon, persistent_fid, volatile_fid,
+                            current->tgid, FILE_BASIC_INFORMATION, 1,
+                            (void **)&buf, &size);
+}
+
+int
+SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
+                 const u64 persistent_fid, const u64 volatile_fid,
+                 __u8 oplock_level)
+{
+       int rc = 0, buf_type;
+       struct smb2_oplock_break *req = NULL;
+       struct kvec iov[1];
+
+       cFYI(1, "SMB2_oplock_break");
+       rc = small_smb2_init(SMB2_OPLOCK_BREAK, tcon, (void **) &req);
+
+       if (rc)
+               return rc;
+
+       req->VolatileFid = volatile_fid;
+       req->PersistentFid = persistent_fid;
+       req->OplockLevel = oplock_level;
+       req->hdr.CreditRequest = cpu_to_le16(1);
+
+       iov->iov_base = (char *)req;
+       /* 4 for rfc1002 length */
+       iov->iov_len = get_rfc1002_length(req) + 4;
+
+       rc = SendReceive2(xid, tcon->ses, iov, 1, &buf_type, CIFS_OBREAK_OP);
+       /* SMB2 buffer freed by function above */
+
+       if (rc) {
+               cifs_stats_fail_inc(tcon, SMB2_OPLOCK_BREAK_HE);
+               cFYI(1, "Send error in Oplock Break = %d", rc);
+       }
+
+       return rc;
+}
+
+static void
+copy_fs_info_to_kstatfs(struct smb2_fs_full_size_info *pfs_inf,
+                       struct kstatfs *kst)
+{
+       kst->f_bsize = le32_to_cpu(pfs_inf->BytesPerSector) *
+                         le32_to_cpu(pfs_inf->SectorsPerAllocationUnit);
+       kst->f_blocks = le64_to_cpu(pfs_inf->TotalAllocationUnits);
+       kst->f_bfree  = le64_to_cpu(pfs_inf->ActualAvailableAllocationUnits);
+       kst->f_bavail = le64_to_cpu(pfs_inf->CallerAvailableAllocationUnits);
+       return;
+}
+
+static int
+build_qfs_info_req(struct kvec *iov, struct cifs_tcon *tcon, int level,
+                  int outbuf_len, u64 persistent_fid, u64 volatile_fid)
+{
+       int rc;
+       struct smb2_query_info_req *req;
+
+       cFYI(1, "Query FSInfo level %d", level);
+
+       if ((tcon->ses == NULL) || (tcon->ses->server == NULL))
+               return -EIO;
+
+       rc = small_smb2_init(SMB2_QUERY_INFO, tcon, (void **) &req);
+       if (rc)
+               return rc;
+
+       req->InfoType = SMB2_O_INFO_FILESYSTEM;
+       req->FileInfoClass = level;
+       req->PersistentFileId = persistent_fid;
+       req->VolatileFileId = volatile_fid;
+       /* 4 for rfc1002 length field and 1 for pad */
+       req->InputBufferOffset =
+                       cpu_to_le16(sizeof(struct smb2_query_info_req) - 1 - 4);
+       req->OutputBufferLength = cpu_to_le32(
+               outbuf_len + sizeof(struct smb2_query_info_rsp) - 1 - 4);
+
+       iov->iov_base = (char *)req;
+       /* 4 for rfc1002 length field */
+       iov->iov_len = get_rfc1002_length(req) + 4;
+       return 0;
+}
+
+int
+SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
+             u64 persistent_fid, u64 volatile_fid, struct kstatfs *fsdata)
+{
+       struct smb2_query_info_rsp *rsp = NULL;
+       struct kvec iov;
+       int rc = 0;
+       int resp_buftype;
+       struct cifs_ses *ses = tcon->ses;
+       struct smb2_fs_full_size_info *info = NULL;
+
+       rc = build_qfs_info_req(&iov, tcon, FS_FULL_SIZE_INFORMATION,
+                               sizeof(struct smb2_fs_full_size_info),
+                               persistent_fid, volatile_fid);
+       if (rc)
+               return rc;
+
+       rc = SendReceive2(xid, ses, &iov, 1, &resp_buftype, 0);
+       if (rc) {
+               cifs_stats_fail_inc(tcon, SMB2_QUERY_INFO_HE);
+               goto qinf_exit;
+       }
+       rsp = (struct smb2_query_info_rsp *)iov.iov_base;
+
+       info = (struct smb2_fs_full_size_info *)(4 /* RFC1001 len */ +
+               le16_to_cpu(rsp->OutputBufferOffset) + (char *)&rsp->hdr);
+       rc = validate_buf(le16_to_cpu(rsp->OutputBufferOffset),
+                         le32_to_cpu(rsp->OutputBufferLength), &rsp->hdr,
+                         sizeof(struct smb2_fs_full_size_info));
+       if (!rc)
+               copy_fs_info_to_kstatfs(info, fsdata);
+
+qinf_exit:
+       free_rsp_buf(resp_buftype, iov.iov_base);
+       return rc;
+}
index f37a1b41b402b76e9f5ce7ae155e7bd5bb3a08a3..4b318250646b7da50d9019216c2fcf50e3ef659f 100644 (file)
 
 #define SMB2_PROTO_NUMBER __constant_cpu_to_le32(0x424d53fe)
 
-#define SMB2_HEADER_SIZE __constant_le16_to_cpu(64)
-
-#define SMB2_ERROR_STRUCTURE_SIZE2 __constant_le16_to_cpu(9)
-
 /*
  * SMB2 Header Definition
  *
@@ -99,6 +95,9 @@
  * "PDU" :  "Protocol Data Unit" (ie a network "frame")
  *
  */
+
+#define SMB2_HEADER_STRUCTURE_SIZE __constant_le16_to_cpu(64)
+
 struct smb2_hdr {
        __be32 smb2_buf_length; /* big endian on wire */
                                /* length is only two or three bytes - with
@@ -140,6 +139,9 @@ struct smb2_pdu {
  *  command code name for the struct. Note that structures must be packed.
  *
  */
+
+#define SMB2_ERROR_STRUCTURE_SIZE2 __constant_le16_to_cpu(9)
+
 struct smb2_err_rsp {
        struct smb2_hdr hdr;
        __le16 StructureSize;
@@ -451,6 +453,79 @@ struct smb2_close_rsp {
        __le32 Attributes;
 } __packed;
 
+struct smb2_flush_req {
+       struct smb2_hdr hdr;
+       __le16 StructureSize;   /* Must be 24 */
+       __le16 Reserved1;
+       __le32 Reserved2;
+       __u64  PersistentFileId; /* opaque endianness */
+       __u64  VolatileFileId; /* opaque endianness */
+} __packed;
+
+struct smb2_flush_rsp {
+       struct smb2_hdr hdr;
+       __le16 StructureSize;
+       __le16 Reserved;
+} __packed;
+
+struct smb2_read_req {
+       struct smb2_hdr hdr;
+       __le16 StructureSize; /* Must be 49 */
+       __u8   Padding; /* offset from start of SMB2 header to place read */
+       __u8   Reserved;
+       __le32 Length;
+       __le64 Offset;
+       __u64  PersistentFileId; /* opaque endianness */
+       __u64  VolatileFileId; /* opaque endianness */
+       __le32 MinimumCount;
+       __le32 Channel; /* Reserved MBZ */
+       __le32 RemainingBytes;
+       __le16 ReadChannelInfoOffset; /* Reserved MBZ */
+       __le16 ReadChannelInfoLength; /* Reserved MBZ */
+       __u8   Buffer[1];
+} __packed;
+
+struct smb2_read_rsp {
+       struct smb2_hdr hdr;
+       __le16 StructureSize; /* Must be 17 */
+       __u8   DataOffset;
+       __u8   Reserved;
+       __le32 DataLength;
+       __le32 DataRemaining;
+       __u32  Reserved2;
+       __u8   Buffer[1];
+} __packed;
+
+/* For write request Flags field below the following flag is defined: */
+#define SMB2_WRITEFLAG_WRITE_THROUGH 0x00000001
+
+struct smb2_write_req {
+       struct smb2_hdr hdr;
+       __le16 StructureSize; /* Must be 49 */
+       __le16 DataOffset; /* offset from start of SMB2 header to write data */
+       __le32 Length;
+       __le64 Offset;
+       __u64  PersistentFileId; /* opaque endianness */
+       __u64  VolatileFileId; /* opaque endianness */
+       __le32 Channel; /* Reserved MBZ */
+       __le32 RemainingBytes;
+       __le16 WriteChannelInfoOffset; /* Reserved MBZ */
+       __le16 WriteChannelInfoLength; /* Reserved MBZ */
+       __le32 Flags;
+       __u8   Buffer[1];
+} __packed;
+
+struct smb2_write_rsp {
+       struct smb2_hdr hdr;
+       __le16 StructureSize; /* Must be 17 */
+       __u8   DataOffset;
+       __u8   Reserved;
+       __le32 DataLength;
+       __le32 DataRemaining;
+       __u32  Reserved2;
+       __u8   Buffer[1];
+} __packed;
+
 struct smb2_echo_req {
        struct smb2_hdr hdr;
        __le16 StructureSize;   /* Must be 4 */
@@ -463,6 +538,34 @@ struct smb2_echo_rsp {
        __u16  Reserved;
 } __packed;
 
+/* search (query_directory) Flags field */
+#define SMB2_RESTART_SCANS             0x01
+#define SMB2_RETURN_SINGLE_ENTRY       0x02
+#define SMB2_INDEX_SPECIFIED           0x04
+#define SMB2_REOPEN                    0x10
+
+struct smb2_query_directory_req {
+       struct smb2_hdr hdr;
+       __le16 StructureSize; /* Must be 33 */
+       __u8   FileInformationClass;
+       __u8   Flags;
+       __le32 FileIndex;
+       __u64  PersistentFileId; /* opaque endianness */
+       __u64  VolatileFileId; /* opaque endianness */
+       __le16 FileNameOffset;
+       __le16 FileNameLength;
+       __le32 OutputBufferLength;
+       __u8   Buffer[1];
+} __packed;
+
+struct smb2_query_directory_rsp {
+       struct smb2_hdr hdr;
+       __le16 StructureSize; /* Must be 9 */
+       __le16 OutputBufferOffset;
+       __le32 OutputBufferLength;
+       __u8   Buffer[1];
+} __packed;
+
 /* Possible InfoType values */
 #define SMB2_O_INFO_FILE       0x01
 #define SMB2_O_INFO_FILESYSTEM 0x02
@@ -493,11 +596,59 @@ struct smb2_query_info_rsp {
        __u8   Buffer[1];
 } __packed;
 
+struct smb2_set_info_req {
+       struct smb2_hdr hdr;
+       __le16 StructureSize; /* Must be 33 */
+       __u8   InfoType;
+       __u8   FileInfoClass;
+       __le32 BufferLength;
+       __le16 BufferOffset;
+       __u16  Reserved;
+       __le32 AdditionalInformation;
+       __u64  PersistentFileId; /* opaque endianness */
+       __u64  VolatileFileId; /* opaque endianness */
+       __u8   Buffer[1];
+} __packed;
+
+struct smb2_set_info_rsp {
+       struct smb2_hdr hdr;
+       __le16 StructureSize; /* Must be 2 */
+} __packed;
+
+struct smb2_oplock_break {
+       struct smb2_hdr hdr;
+       __le16 StructureSize; /* Must be 24 */
+       __u8   OplockLevel;
+       __u8   Reserved;
+       __le32 Reserved2;
+       __u64  PersistentFid;
+       __u64  VolatileFid;
+} __packed;
+
 /*
  *     PDU infolevel structure definitions
  *     BB consider moving to a different header
  */
 
+/* File System Information Classes */
+#define FS_VOLUME_INFORMATION          1 /* Query */
+#define FS_LABEL_INFORMATION           2 /* Set */
+#define FS_SIZE_INFORMATION            3 /* Query */
+#define FS_DEVICE_INFORMATION          4 /* Query */
+#define FS_ATTRIBUTE_INFORMATION       5 /* Query */
+#define FS_CONTROL_INFORMATION         6 /* Query, Set */
+#define FS_FULL_SIZE_INFORMATION       7 /* Query */
+#define FS_OBJECT_ID_INFORMATION       8 /* Query, Set */
+#define FS_DRIVER_PATH_INFORMATION     9 /* Query */
+
+struct smb2_fs_full_size_info {
+       __le64 TotalAllocationUnits;
+       __le64 CallerAvailableAllocationUnits;
+       __le64 ActualAvailableAllocationUnits;
+       __le32 SectorsPerAllocationUnit;
+       __le32 BytesPerSector;
+} __packed;
+
 /* partial list of QUERY INFO levels */
 #define FILE_DIRECTORY_INFORMATION     1
 #define FILE_FULL_DIRECTORY_INFORMATION 2
@@ -546,6 +697,28 @@ struct smb2_query_info_rsp {
 #define FILEID_GLOBAL_TX_DIRECTORY_INFORMATION 50
 #define FILE_STANDARD_LINK_INFORMATION 54
 
+struct smb2_file_internal_info {
+       __le64 IndexNumber;
+} __packed; /* level 6 Query */
+
+struct smb2_file_rename_info { /* encoding of request for level 10 */
+       __u8   ReplaceIfExists; /* 1 = replace existing target with new */
+                               /* 0 = fail if target already exists */
+       __u8   Reserved[7];
+       __u64  RootDirectory;  /* MBZ for network operations (why says spec?) */
+       __le32 FileNameLength;
+       char   FileName[0];     /* New name to be assigned */
+} __packed; /* level 10 Set */
+
+struct smb2_file_link_info { /* encoding of request for level 11 */
+       __u8   ReplaceIfExists; /* 1 = replace existing link with new */
+                               /* 0 = fail if link already exists */
+       __u8   Reserved[7];
+       __u64  RootDirectory;  /* MBZ for network operations (why says spec?) */
+       __le32 FileNameLength;
+       char   FileName[0];     /* Name to be assigned to new link */
+} __packed; /* level 11 Set */
+
 /*
  * This level 18, although with struct with same name is different from cifs
  * level 0x107. Level 0x107 has an extra u64 between AccessFlags and
@@ -574,4 +747,8 @@ struct smb2_file_all_info { /* data block encoding of response to level 18 */
        char   FileName[1];
 } __packed; /* level 18 Query */
 
+struct smb2_file_eof_info { /* encoding of request for level 10 */
+       __le64 EndOfFile; /* new end of file value */
+} __packed; /* level 20 Set */
+
 #endif                         /* _SMB2PDU_H */
index bfaa7b148afd0e4d3d334a52c699a90dac75aeea..a73a963af8f4eca0d7f1d1bbff4944f1d4be7286 100644 (file)
@@ -34,11 +34,13 @@ struct statfs;
  */
 extern int map_smb2_to_linux_error(char *buf, bool log_err);
 extern int smb2_check_message(char *buf, unsigned int length);
-extern unsigned int smb2_calc_size(struct smb2_hdr *hdr);
+extern unsigned int smb2_calc_size(void *buf);
 extern char *smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *hdr);
 extern __le16 *cifs_convert_path_to_utf16(const char *from,
                                          struct cifs_sb_info *cifs_sb);
 
+extern int smb2_verify_signature2(struct kvec *, unsigned int,
+                                 struct TCP_Server_Info *);
 extern int smb2_check_receive(struct mid_q_entry *mid,
                              struct TCP_Server_Info *server, bool log_error);
 extern int smb2_setup_request(struct cifs_ses *ses, struct kvec *iov,
@@ -47,11 +49,20 @@ extern int smb2_setup_async_request(struct TCP_Server_Info *server,
                                    struct kvec *iov, unsigned int nvec,
                                    struct mid_q_entry **ret_mid);
 extern void smb2_echo_request(struct work_struct *work);
+extern bool smb2_is_valid_oplock_break(char *buffer,
+                                      struct TCP_Server_Info *srv);
 
+extern void move_smb2_info_to_cifs(FILE_ALL_INFO *dst,
+                                  struct smb2_file_all_info *src);
 extern int smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
                                struct cifs_sb_info *cifs_sb,
                                const char *full_path, FILE_ALL_INFO *data,
                                bool *adjust_tz);
+extern int smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
+                             const char *full_path, __u64 size,
+                             struct cifs_sb_info *cifs_sb, bool set_alloc);
+extern int smb2_set_file_info(struct inode *inode, const char *full_path,
+                             FILE_BASIC_INFO *buf, const unsigned int xid);
 extern int smb2_mkdir(const unsigned int xid, struct cifs_tcon *tcon,
                      const char *name, struct cifs_sb_info *cifs_sb);
 extern void smb2_mkdir_setinfo(struct inode *inode, const char *full_path,
@@ -59,6 +70,21 @@ extern void smb2_mkdir_setinfo(struct inode *inode, const char *full_path,
                               struct cifs_tcon *tcon, const unsigned int xid);
 extern int smb2_rmdir(const unsigned int xid, struct cifs_tcon *tcon,
                      const char *name, struct cifs_sb_info *cifs_sb);
+extern int smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon,
+                      const char *name, struct cifs_sb_info *cifs_sb);
+extern int smb2_rename_path(const unsigned int xid, struct cifs_tcon *tcon,
+                           const char *from_name, const char *to_name,
+                           struct cifs_sb_info *cifs_sb);
+extern int smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
+                               const char *from_name, const char *to_name,
+                               struct cifs_sb_info *cifs_sb);
+
+extern int smb2_open_file(const unsigned int xid, struct cifs_tcon *tcon,
+                         const char *full_path, int disposition,
+                         int desired_access, int create_options,
+                         struct cifs_fid *fid, __u32 *oplock,
+                         FILE_ALL_INFO *buf, struct cifs_sb_info *cifs_sb);
+extern void smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock);
 
 /*
  * SMB2 Worker functions - most of protocol specific implementation details
@@ -75,12 +101,45 @@ extern int SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon);
 extern int SMB2_open(const unsigned int xid, struct cifs_tcon *tcon,
                     __le16 *path, u64 *persistent_fid, u64 *volatile_fid,
                     __u32 desired_access, __u32 create_disposition,
-                    __u32 file_attributes, __u32 create_options);
+                    __u32 file_attributes, __u32 create_options,
+                    __u8 *oplock, struct smb2_file_all_info *buf);
 extern int SMB2_close(const unsigned int xid, struct cifs_tcon *tcon,
                      u64 persistent_file_id, u64 volatile_file_id);
+extern int SMB2_flush(const unsigned int xid, struct cifs_tcon *tcon,
+                     u64 persistent_file_id, u64 volatile_file_id);
 extern int SMB2_query_info(const unsigned int xid, struct cifs_tcon *tcon,
                           u64 persistent_file_id, u64 volatile_file_id,
                           struct smb2_file_all_info *data);
+extern int SMB2_get_srv_num(const unsigned int xid, struct cifs_tcon *tcon,
+                           u64 persistent_fid, u64 volatile_fid,
+                           __le64 *uniqueid);
+extern int smb2_async_readv(struct cifs_readdata *rdata);
+extern int SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms,
+                    unsigned int *nbytes, char **buf, int *buf_type);
+extern int smb2_async_writev(struct cifs_writedata *wdata);
+extern int SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms,
+                     unsigned int *nbytes, struct kvec *iov, int n_vec);
 extern int SMB2_echo(struct TCP_Server_Info *server);
+extern int SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
+                               u64 persistent_fid, u64 volatile_fid, int index,
+                               struct cifs_search_info *srch_inf);
+extern int SMB2_rename(const unsigned int xid, struct cifs_tcon *tcon,
+                      u64 persistent_fid, u64 volatile_fid,
+                      __le16 *target_file);
+extern int SMB2_set_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
+                            u64 persistent_fid, u64 volatile_fid,
+                            __le16 *target_file);
+extern int SMB2_set_eof(const unsigned int xid, struct cifs_tcon *tcon,
+                       u64 persistent_fid, u64 volatile_fid, u32 pid,
+                       __le64 *eof);
+extern int SMB2_set_info(const unsigned int xid, struct cifs_tcon *tcon,
+                        u64 persistent_fid, u64 volatile_fid,
+                        FILE_BASIC_INFO *buf);
+extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon,
+                            const u64 persistent_fid, const u64 volatile_fid,
+                            const __u8 oplock_level);
+extern int SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon,
+                        u64 persistent_file_id, u64 volatile_file_id,
+                        struct kstatfs *FSData);
 
 #endif                 /* _SMB2PROTO_H */
index 31f5d420b3ea353570814716498327c274caa8a8..7276f6fe3c1161cf64219015e9048bf571f21c00 100644 (file)
 #include "smb2proto.h"
 #include "cifs_debug.h"
 #include "smb2status.h"
+#include "smb2glob.h"
+
+static int
+smb2_calc_signature2(const struct kvec *iov, int n_vec,
+                    struct TCP_Server_Info *server)
+{
+       int i, rc;
+       unsigned char smb2_signature[SMB2_HMACSHA256_SIZE];
+       unsigned char *sigptr = smb2_signature;
+       struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base;
+
+       memset(smb2_signature, 0x0, SMB2_HMACSHA256_SIZE);
+       memset(smb2_pdu->Signature, 0x0, SMB2_SIGNATURE_SIZE);
+
+       rc = crypto_shash_setkey(server->secmech.hmacsha256,
+               server->session_key.response, SMB2_NTLMV2_SESSKEY_SIZE);
+       if (rc) {
+               cERROR(1, "%s: Could not update with response\n", __func__);
+               return rc;
+       }
+
+       rc = crypto_shash_init(&server->secmech.sdeschmacsha256->shash);
+       if (rc) {
+               cERROR(1, "%s: Could not init md5\n", __func__);
+               return rc;
+       }
+
+       for (i = 0; i < n_vec; i++) {
+               if (iov[i].iov_len == 0)
+                       continue;
+               if (iov[i].iov_base == NULL) {
+                       cERROR(1, "null iovec entry");
+                       return -EIO;
+               }
+               /*
+                * The first entry includes a length field (which does not get
+                * signed that occupies the first 4 bytes before the header).
+                */
+               if (i == 0) {
+                       if (iov[0].iov_len <= 8) /* cmd field at offset 9 */
+                               break; /* nothing to sign or corrupt header */
+                       rc =
+                       crypto_shash_update(
+                               &server->secmech.sdeschmacsha256->shash,
+                               iov[i].iov_base + 4, iov[i].iov_len - 4);
+               } else {
+                       rc =
+                       crypto_shash_update(
+                               &server->secmech.sdeschmacsha256->shash,
+                               iov[i].iov_base, iov[i].iov_len);
+               }
+               if (rc) {
+                       cERROR(1, "%s: Could not update with payload\n",
+                                                       __func__);
+                       return rc;
+               }
+       }
+
+       rc = crypto_shash_final(&server->secmech.sdeschmacsha256->shash,
+                               sigptr);
+       if (rc)
+               cERROR(1, "%s: Could not generate sha256 hash\n", __func__);
+
+       memcpy(smb2_pdu->Signature, sigptr, SMB2_SIGNATURE_SIZE);
+
+       return rc;
+}
+
+/* must be called with server->srv_mutex held */
+static int
+smb2_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *server)
+{
+       int rc = 0;
+       struct smb2_hdr *smb2_pdu = iov[0].iov_base;
+
+       if (!(smb2_pdu->Flags & SMB2_FLAGS_SIGNED) ||
+           server->tcpStatus == CifsNeedNegotiate)
+               return rc;
+
+       if (!server->session_estab) {
+               strncpy(smb2_pdu->Signature, "BSRSPYL", 8);
+               return rc;
+       }
+
+       rc = smb2_calc_signature2(iov, n_vec, server);
+
+       return rc;
+}
+
+int
+smb2_verify_signature2(struct kvec *iov, unsigned int n_vec,
+                      struct TCP_Server_Info *server)
+{
+       unsigned int rc;
+       char server_response_sig[16];
+       struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base;
+
+       if ((smb2_pdu->Command == SMB2_NEGOTIATE) ||
+           (smb2_pdu->Command == SMB2_OPLOCK_BREAK) ||
+           (!server->session_estab))
+               return 0;
+
+       /*
+        * BB what if signatures are supposed to be on for session but
+        * server does not send one? BB
+        */
+
+       /* Do not need to verify session setups with signature "BSRSPYL " */
+       if (memcmp(smb2_pdu->Signature, "BSRSPYL ", 8) == 0)
+               cFYI(1, "dummy signature received for smb command 0x%x",
+                       smb2_pdu->Command);
+
+       /*
+        * Save off the origiginal signature so we can modify the smb and check
+        * our calculated signature against what the server sent.
+        */
+       memcpy(server_response_sig, smb2_pdu->Signature, SMB2_SIGNATURE_SIZE);
+
+       memset(smb2_pdu->Signature, 0, SMB2_SIGNATURE_SIZE);
+
+       mutex_lock(&server->srv_mutex);
+       rc = smb2_calc_signature2(iov, n_vec, server);
+       mutex_unlock(&server->srv_mutex);
+
+       if (rc)
+               return rc;
+
+       if (memcmp(server_response_sig, smb2_pdu->Signature,
+                  SMB2_SIGNATURE_SIZE))
+               return -EACCES;
+       else
+               return 0;
+}
+
+static int
+smb2_verify_signature(struct smb2_hdr *smb2_pdu, struct TCP_Server_Info *server)
+{
+       struct kvec iov;
+
+       iov.iov_base = (char *)smb2_pdu;
+       iov.iov_len = get_rfc1002_length(smb2_pdu) + 4;
+       return smb2_verify_signature2(&iov, 1, server);
+}
 
 /*
  * Set message id for the request. Should be called after wait_for_free_request
@@ -118,12 +261,11 @@ smb2_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
 
        dump_smb(mid->resp_buf, min_t(u32, 80, len));
        /* convert the length into a more usable form */
-       /* BB - uncomment with SMB2 signing implementation */
-       /* if ((len > 24) &&
+       if ((len > 24) &&
            (server->sec_mode & (SECMODE_SIGN_REQUIRED|SECMODE_SIGN_ENABLED))) {
                if (smb2_verify_signature(mid->resp_buf, server))
                        cERROR(1, "Unexpected SMB signature");
-       } */
+       }
 
        return map_smb2_to_linux_error(mid->resp_buf, log_error);
 }
@@ -141,9 +283,9 @@ smb2_setup_request(struct cifs_ses *ses, struct kvec *iov,
        rc = smb2_get_mid_entry(ses, hdr, &mid);
        if (rc)
                return rc;
-       /* rc = smb2_sign_smb2(iov, nvec, ses->server);
+       rc = smb2_sign_smb2(iov, nvec, ses->server);
        if (rc)
-               delete_mid(mid); */
+               cifs_delete_mid(mid);
        *ret_mid = mid;
        return rc;
 }
@@ -162,11 +304,12 @@ smb2_setup_async_request(struct TCP_Server_Info *server, struct kvec *iov,
        if (mid == NULL)
                return -ENOMEM;
 
-       /* rc = smb2_sign_smb2(iov, nvec, server);
+       rc = smb2_sign_smb2(iov, nvec, server);
        if (rc) {
                DeleteMidQEntry(mid);
                return rc;
-       }*/
+       }
+
        *ret_mid = mid;
        return rc;
 }
index 83867ef348dfe15276d83379f12ae5c46399f7a0..c4d7825dfc0a31c7d91132cb3e9cc87f5ff48155 100644 (file)
@@ -109,8 +109,8 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
        mempool_free(midEntry, cifs_mid_poolp);
 }
 
-static void
-delete_mid(struct mid_q_entry *mid)
+void
+cifs_delete_mid(struct mid_q_entry *mid)
 {
        spin_lock(&GlobalMid_Lock);
        list_del(&mid->qhead);
@@ -419,7 +419,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov,
        if (rc == 0)
                return 0;
 
-       delete_mid(mid);
+       cifs_delete_mid(mid);
        add_credits(server, 1, optype);
        wake_up(&server->request_q);
        return rc;
@@ -503,13 +503,16 @@ cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server,
        /* convert the length into a more usable form */
        if (server->sec_mode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) {
                struct kvec iov;
+               int rc = 0;
 
                iov.iov_base = mid->resp_buf;
                iov.iov_len = len;
                /* FIXME: add code to kill session */
-               if (cifs_verify_signature(&iov, 1, server,
-                                         mid->sequence_number + 1) != 0)
-                       cERROR(1, "Unexpected SMB signature");
+               rc = cifs_verify_signature(&iov, 1, server,
+                                          mid->sequence_number + 1);
+               if (rc)
+                       cERROR(1, "SMB signature verification returned error = "
+                              "%d", rc);
        }
 
        /* BB special case reconnect tid and uid here? */
@@ -529,7 +532,7 @@ cifs_setup_request(struct cifs_ses *ses, struct kvec *iov,
                return rc;
        rc = cifs_sign_smbv(iov, nvec, ses->server, &mid->sequence_number);
        if (rc)
-               delete_mid(mid);
+               cifs_delete_mid(mid);
        *ret_mid = mid;
        return rc;
 }
@@ -649,11 +652,11 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses,
        rc = ses->server->ops->check_receive(midQ, ses->server,
                                             flags & CIFS_LOG_ERROR);
 
-       /* mark it so buf will not be freed by delete_mid */
+       /* mark it so buf will not be freed by cifs_delete_mid */
        if ((flags & CIFS_NO_RESP) == 0)
                midQ->resp_buf = NULL;
 out:
-       delete_mid(midQ);
+       cifs_delete_mid(midQ);
        add_credits(ses->server, credits, optype);
 
        return rc;
@@ -759,7 +762,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses,
        memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
        rc = cifs_check_receive(midQ, ses->server, 0);
 out:
-       delete_mid(midQ);
+       cifs_delete_mid(midQ);
        add_credits(ses->server, 1, 0);
 
        return rc;
@@ -843,7 +846,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
 
        rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number);
        if (rc) {
-               delete_mid(midQ);
+               cifs_delete_mid(midQ);
                mutex_unlock(&ses->server->srv_mutex);
                return rc;
        }
@@ -856,7 +859,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
        mutex_unlock(&ses->server->srv_mutex);
 
        if (rc < 0) {
-               delete_mid(midQ);
+               cifs_delete_mid(midQ);
                return rc;
        }
 
@@ -877,7 +880,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
                           blocking lock to return. */
                        rc = send_cancel(ses->server, in_buf, midQ);
                        if (rc) {
-                               delete_mid(midQ);
+                               cifs_delete_mid(midQ);
                                return rc;
                        }
                } else {
@@ -889,7 +892,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
                        /* If we get -ENOLCK back the lock may have
                           already been removed. Don't exit in this case. */
                        if (rc && rc != -ENOLCK) {
-                               delete_mid(midQ);
+                               cifs_delete_mid(midQ);
                                return rc;
                        }
                }
@@ -926,7 +929,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon,
        memcpy(out_buf, midQ->resp_buf, *pbytes_returned + 4);
        rc = cifs_check_receive(midQ, ses->server, 0);
 out:
-       delete_mid(midQ);
+       cifs_delete_mid(midQ);
        if (rstart && rc == -EACCES)
                return -ERESTARTSYS;
        return rc;
index 1faf4cb56f3963d0945d8004b8640464b9e3b6fd..f86c720dba0eeea72d7ecefdefa8ad0b52886011 100644 (file)
@@ -1062,6 +1062,7 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
        unsigned long user_addr;
        size_t bytes;
        struct buffer_head map_bh = { 0, };
+       struct blk_plug plug;
 
        if (rw & WRITE)
                rw = WRITE_ODIRECT;
@@ -1177,6 +1178,8 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
                                PAGE_SIZE - user_addr / PAGE_SIZE);
        }
 
+       blk_start_plug(&plug);
+
        for (seg = 0; seg < nr_segs; seg++) {
                user_addr = (unsigned long)iov[seg].iov_base;
                sdio.size += bytes = iov[seg].iov_len;
@@ -1235,6 +1238,8 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
        if (sdio.bio)
                dio_bio_submit(dio, &sdio);
 
+       blk_finish_plug(&plug);
+
        /*
         * It is possible that, we return short IO due to end of file.
         * In that case, we need to release all the pages we got hold on.
index 63dc19c54d5a0dc567210d86b6b3a676934aa191..27a6ba9aaeec7e410c1002b72cd81c344c3d76ef 100644 (file)
@@ -15,8 +15,8 @@
 #include "lock.h"
 #include "user.h"
 
-static uint64_t                        dlm_cb_seq;
-static spinlock_t              dlm_cb_seq_spin;
+static uint64_t dlm_cb_seq;
+static DEFINE_SPINLOCK(dlm_cb_seq_spin);
 
 static void dlm_dump_lkb_callbacks(struct dlm_lkb *lkb)
 {
index 9ccf7346834aaed5385923e2283b9e30cd4fd99e..a0387dd8b1f0f3abf10ab7e257f9af34d7886900 100644 (file)
@@ -750,6 +750,7 @@ static ssize_t comm_local_write(struct dlm_comm *cm, const char *buf,
 static ssize_t comm_addr_write(struct dlm_comm *cm, const char *buf, size_t len)
 {
        struct sockaddr_storage *addr;
+       int rv;
 
        if (len != sizeof(struct sockaddr_storage))
                return -EINVAL;
@@ -762,6 +763,13 @@ static ssize_t comm_addr_write(struct dlm_comm *cm, const char *buf, size_t len)
                return -ENOMEM;
 
        memcpy(addr, buf, len);
+
+       rv = dlm_lowcomms_addr(cm->nodeid, addr, len);
+       if (rv) {
+               kfree(addr);
+               return rv;
+       }
+
        cm->addr[cm->addr_count++] = addr;
        return len;
 }
@@ -878,34 +886,7 @@ static void put_space(struct dlm_space *sp)
        config_item_put(&sp->group.cg_item);
 }
 
-static int addr_compare(struct sockaddr_storage *x, struct sockaddr_storage *y)
-{
-       switch (x->ss_family) {
-       case AF_INET: {
-               struct sockaddr_in *sinx = (struct sockaddr_in *)x;
-               struct sockaddr_in *siny = (struct sockaddr_in *)y;
-               if (sinx->sin_addr.s_addr != siny->sin_addr.s_addr)
-                       return 0;
-               if (sinx->sin_port != siny->sin_port)
-                       return 0;
-               break;
-       }
-       case AF_INET6: {
-               struct sockaddr_in6 *sinx = (struct sockaddr_in6 *)x;
-               struct sockaddr_in6 *siny = (struct sockaddr_in6 *)y;
-               if (!ipv6_addr_equal(&sinx->sin6_addr, &siny->sin6_addr))
-                       return 0;
-               if (sinx->sin6_port != siny->sin6_port)
-                       return 0;
-               break;
-       }
-       default:
-               return 0;
-       }
-       return 1;
-}
-
-static struct dlm_comm *get_comm(int nodeid, struct sockaddr_storage *addr)
+static struct dlm_comm *get_comm(int nodeid)
 {
        struct config_item *i;
        struct dlm_comm *cm = NULL;
@@ -919,19 +900,11 @@ static struct dlm_comm *get_comm(int nodeid, struct sockaddr_storage *addr)
        list_for_each_entry(i, &comm_list->cg_children, ci_entry) {
                cm = config_item_to_comm(i);
 
-               if (nodeid) {
-                       if (cm->nodeid != nodeid)
-                               continue;
-                       found = 1;
-                       config_item_get(i);
-                       break;
-               } else {
-                       if (!cm->addr_count || !addr_compare(cm->addr[0], addr))
-                               continue;
-                       found = 1;
-                       config_item_get(i);
-                       break;
-               }
+               if (cm->nodeid != nodeid)
+                       continue;
+               found = 1;
+               config_item_get(i);
+               break;
        }
        mutex_unlock(&clusters_root.subsys.su_mutex);
 
@@ -995,7 +968,7 @@ int dlm_config_nodes(char *lsname, struct dlm_config_node **nodes_out,
 
 int dlm_comm_seq(int nodeid, uint32_t *seq)
 {
-       struct dlm_comm *cm = get_comm(nodeid, NULL);
+       struct dlm_comm *cm = get_comm(nodeid);
        if (!cm)
                return -EEXIST;
        *seq = cm->seq;
@@ -1003,28 +976,6 @@ int dlm_comm_seq(int nodeid, uint32_t *seq)
        return 0;
 }
 
-int dlm_nodeid_to_addr(int nodeid, struct sockaddr_storage *addr)
-{
-       struct dlm_comm *cm = get_comm(nodeid, NULL);
-       if (!cm)
-               return -EEXIST;
-       if (!cm->addr_count)
-               return -ENOENT;
-       memcpy(addr, cm->addr[0], sizeof(*addr));
-       put_comm(cm);
-       return 0;
-}
-
-int dlm_addr_to_nodeid(struct sockaddr_storage *addr, int *nodeid)
-{
-       struct dlm_comm *cm = get_comm(0, addr);
-       if (!cm)
-               return -EEXIST;
-       *nodeid = cm->nodeid;
-       put_comm(cm);
-       return 0;
-}
-
 int dlm_our_nodeid(void)
 {
        return local_comm ? local_comm->nodeid : 0;
index dbd35a08f3a5f4c4aa03c9495b33975400f68bfa..f30697bc2780dd25ff5586f70d17226c77d83e16 100644 (file)
@@ -46,8 +46,6 @@ void dlm_config_exit(void);
 int dlm_config_nodes(char *lsname, struct dlm_config_node **nodes_out,
                     int *count_out);
 int dlm_comm_seq(int nodeid, uint32_t *seq);
-int dlm_nodeid_to_addr(int nodeid, struct sockaddr_storage *addr);
-int dlm_addr_to_nodeid(struct sockaddr_storage *addr, int *nodeid);
 int dlm_our_nodeid(void);
 int dlm_our_addr(struct sockaddr_storage *addr, int num);
 
index 9d3e485f88c8b3b2230a9ba49ad315113b077bfd..871c1abf6029869ba7157c2f0db032eaabe951f3 100644 (file)
@@ -604,6 +604,7 @@ struct dlm_ls {
        struct idr              ls_recover_idr;
        spinlock_t              ls_recover_idr_lock;
        wait_queue_head_t       ls_wait_general;
+       wait_queue_head_t       ls_recover_lock_wait;
        struct mutex            ls_clear_proc_locks;
 
        struct list_head        ls_root_list;   /* root resources */
@@ -616,15 +617,40 @@ struct dlm_ls {
        char                    ls_name[1];
 };
 
-#define LSFL_WORK              0
-#define LSFL_RUNNING           1
-#define LSFL_RECOVERY_STOP     2
-#define LSFL_RCOM_READY                3
-#define LSFL_RCOM_WAIT         4
-#define LSFL_UEVENT_WAIT       5
-#define LSFL_TIMEWARN          6
-#define LSFL_CB_DELAY          7
-#define LSFL_NODIR             8
+/*
+ * LSFL_RECOVER_STOP - dlm_ls_stop() sets this to tell dlm recovery routines
+ * that they should abort what they're doing so new recovery can be started.
+ *
+ * LSFL_RECOVER_DOWN - dlm_ls_stop() sets this to tell dlm_recoverd that it
+ * should do down_write() on the in_recovery rw_semaphore. (doing down_write
+ * within dlm_ls_stop causes complaints about the lock acquired/released
+ * in different contexts.)
+ *
+ * LSFL_RECOVER_LOCK - dlm_recoverd holds the in_recovery rw_semaphore.
+ * It sets this after it is done with down_write() on the in_recovery
+ * rw_semaphore and clears it after it has released the rw_semaphore.
+ *
+ * LSFL_RECOVER_WORK - dlm_ls_start() sets this to tell dlm_recoverd that it
+ * should begin recovery of the lockspace.
+ *
+ * LSFL_RUNNING - set when normal locking activity is enabled.
+ * dlm_ls_stop() clears this to tell dlm locking routines that they should
+ * quit what they are doing so recovery can run.  dlm_recoverd sets
+ * this after recovery is finished.
+ */
+
+#define LSFL_RECOVER_STOP      0
+#define LSFL_RECOVER_DOWN      1
+#define LSFL_RECOVER_LOCK      2
+#define LSFL_RECOVER_WORK      3
+#define LSFL_RUNNING           4
+
+#define LSFL_RCOM_READY                5
+#define LSFL_RCOM_WAIT         6
+#define LSFL_UEVENT_WAIT       7
+#define LSFL_TIMEWARN          8
+#define LSFL_CB_DELAY          9
+#define LSFL_NODIR             10
 
 /* much of this is just saving user space pointers associated with the
    lock that we pass back to the user lib with an ast */
@@ -667,7 +693,7 @@ static inline int dlm_locking_stopped(struct dlm_ls *ls)
 
 static inline int dlm_recovery_stopped(struct dlm_ls *ls)
 {
-       return test_bit(LSFL_RECOVERY_STOP, &ls->ls_flags);
+       return test_bit(LSFL_RECOVER_STOP, &ls->ls_flags);
 }
 
 static inline int dlm_no_directory(struct dlm_ls *ls)
index 952557d00ccdf0744ca2527300ef1d2798e14cdb..2e99fb0c973776fe9f103f5f0d220d2e7aceb256 100644 (file)
@@ -582,8 +582,6 @@ static int new_lockspace(const char *name, const char *cluster,
        INIT_LIST_HEAD(&ls->ls_root_list);
        init_rwsem(&ls->ls_root_sem);
 
-       down_write(&ls->ls_in_recovery);
-
        spin_lock(&lslist_lock);
        ls->ls_create_count = 1;
        list_add(&ls->ls_list, &lslist);
@@ -597,13 +595,24 @@ static int new_lockspace(const char *name, const char *cluster,
                }
        }
 
-       /* needs to find ls in lslist */
+       init_waitqueue_head(&ls->ls_recover_lock_wait);
+
+       /*
+        * Once started, dlm_recoverd first looks for ls in lslist, then
+        * initializes ls_in_recovery as locked in "down" mode.  We need
+        * to wait for the wakeup from dlm_recoverd because in_recovery
+        * has to start out in down mode.
+        */
+
        error = dlm_recoverd_start(ls);
        if (error) {
                log_error(ls, "can't start dlm_recoverd %d", error);
                goto out_callback;
        }
 
+       wait_event(ls->ls_recover_lock_wait,
+                  test_bit(LSFL_RECOVER_LOCK, &ls->ls_flags));
+
        ls->ls_kobj.kset = dlm_kset;
        error = kobject_init_and_add(&ls->ls_kobj, &dlm_ktype, NULL,
                                     "%s", ls->ls_name);
index 5c1b0e38c7a4c7d7dd0865da4c09240a1e880443..331ea4f94efd2b3f0479ea03d36485573081adc7 100644 (file)
@@ -140,6 +140,16 @@ struct writequeue_entry {
        struct connection *con;
 };
 
+struct dlm_node_addr {
+       struct list_head list;
+       int nodeid;
+       int addr_count;
+       struct sockaddr_storage *addr[DLM_MAX_ADDR_COUNT];
+};
+
+static LIST_HEAD(dlm_node_addrs);
+static DEFINE_SPINLOCK(dlm_node_addrs_spin);
+
 static struct sockaddr_storage *dlm_local_addr[DLM_MAX_ADDR_COUNT];
 static int dlm_local_count;
 static int dlm_allow_conn;
@@ -264,31 +274,146 @@ static struct connection *assoc2con(int assoc_id)
        return NULL;
 }
 
-static int nodeid_to_addr(int nodeid, struct sockaddr *retaddr)
+static struct dlm_node_addr *find_node_addr(int nodeid)
+{
+       struct dlm_node_addr *na;
+
+       list_for_each_entry(na, &dlm_node_addrs, list) {
+               if (na->nodeid == nodeid)
+                       return na;
+       }
+       return NULL;
+}
+
+static int addr_compare(struct sockaddr_storage *x, struct sockaddr_storage *y)
+{
+       switch (x->ss_family) {
+       case AF_INET: {
+               struct sockaddr_in *sinx = (struct sockaddr_in *)x;
+               struct sockaddr_in *siny = (struct sockaddr_in *)y;
+               if (sinx->sin_addr.s_addr != siny->sin_addr.s_addr)
+                       return 0;
+               if (sinx->sin_port != siny->sin_port)
+                       return 0;
+               break;
+       }
+       case AF_INET6: {
+               struct sockaddr_in6 *sinx = (struct sockaddr_in6 *)x;
+               struct sockaddr_in6 *siny = (struct sockaddr_in6 *)y;
+               if (!ipv6_addr_equal(&sinx->sin6_addr, &siny->sin6_addr))
+                       return 0;
+               if (sinx->sin6_port != siny->sin6_port)
+                       return 0;
+               break;
+       }
+       default:
+               return 0;
+       }
+       return 1;
+}
+
+static int nodeid_to_addr(int nodeid, struct sockaddr_storage *sas_out,
+                         struct sockaddr *sa_out)
 {
-       struct sockaddr_storage addr;
-       int error;
+       struct sockaddr_storage sas;
+       struct dlm_node_addr *na;
 
        if (!dlm_local_count)
                return -1;
 
-       error = dlm_nodeid_to_addr(nodeid, &addr);
-       if (error)
-               return error;
+       spin_lock(&dlm_node_addrs_spin);
+       na = find_node_addr(nodeid);
+       if (na && na->addr_count)
+               memcpy(&sas, na->addr[0], sizeof(struct sockaddr_storage));
+       spin_unlock(&dlm_node_addrs_spin);
+
+       if (!na)
+               return -EEXIST;
+
+       if (!na->addr_count)
+               return -ENOENT;
+
+       if (sas_out)
+               memcpy(sas_out, &sas, sizeof(struct sockaddr_storage));
+
+       if (!sa_out)
+               return 0;
 
        if (dlm_local_addr[0]->ss_family == AF_INET) {
-               struct sockaddr_in *in4  = (struct sockaddr_in *) &addr;
-               struct sockaddr_in *ret4 = (struct sockaddr_in *) retaddr;
+               struct sockaddr_in *in4  = (struct sockaddr_in *) &sas;
+               struct sockaddr_in *ret4 = (struct sockaddr_in *) sa_out;
                ret4->sin_addr.s_addr = in4->sin_addr.s_addr;
        } else {
-               struct sockaddr_in6 *in6  = (struct sockaddr_in6 *) &addr;
-               struct sockaddr_in6 *ret6 = (struct sockaddr_in6 *) retaddr;
+               struct sockaddr_in6 *in6  = (struct sockaddr_in6 *) &sas;
+               struct sockaddr_in6 *ret6 = (struct sockaddr_in6 *) sa_out;
                ret6->sin6_addr = in6->sin6_addr;
        }
 
        return 0;
 }
 
+static int addr_to_nodeid(struct sockaddr_storage *addr, int *nodeid)
+{
+       struct dlm_node_addr *na;
+       int rv = -EEXIST;
+
+       spin_lock(&dlm_node_addrs_spin);
+       list_for_each_entry(na, &dlm_node_addrs, list) {
+               if (!na->addr_count)
+                       continue;
+
+               if (!addr_compare(na->addr[0], addr))
+                       continue;
+
+               *nodeid = na->nodeid;
+               rv = 0;
+               break;
+       }
+       spin_unlock(&dlm_node_addrs_spin);
+       return rv;
+}
+
+int dlm_lowcomms_addr(int nodeid, struct sockaddr_storage *addr, int len)
+{
+       struct sockaddr_storage *new_addr;
+       struct dlm_node_addr *new_node, *na;
+
+       new_node = kzalloc(sizeof(struct dlm_node_addr), GFP_NOFS);
+       if (!new_node)
+               return -ENOMEM;
+
+       new_addr = kzalloc(sizeof(struct sockaddr_storage), GFP_NOFS);
+       if (!new_addr) {
+               kfree(new_node);
+               return -ENOMEM;
+       }
+
+       memcpy(new_addr, addr, len);
+
+       spin_lock(&dlm_node_addrs_spin);
+       na = find_node_addr(nodeid);
+       if (!na) {
+               new_node->nodeid = nodeid;
+               new_node->addr[0] = new_addr;
+               new_node->addr_count = 1;
+               list_add(&new_node->list, &dlm_node_addrs);
+               spin_unlock(&dlm_node_addrs_spin);
+               return 0;
+       }
+
+       if (na->addr_count >= DLM_MAX_ADDR_COUNT) {
+               spin_unlock(&dlm_node_addrs_spin);
+               kfree(new_addr);
+               kfree(new_node);
+               return -ENOSPC;
+       }
+
+       na->addr[na->addr_count++] = new_addr;
+       spin_unlock(&dlm_node_addrs_spin);
+       kfree(new_node);
+       return 0;
+}
+
 /* Data available on socket or listen socket received a connect */
 static void lowcomms_data_ready(struct sock *sk, int count_unused)
 {
@@ -348,7 +473,7 @@ int dlm_lowcomms_connect_node(int nodeid)
 }
 
 /* Make a socket active */
-static int add_sock(struct socket *sock, struct connection *con)
+static void add_sock(struct socket *sock, struct connection *con)
 {
        con->sock = sock;
 
@@ -358,7 +483,6 @@ static int add_sock(struct socket *sock, struct connection *con)
        con->sock->sk->sk_state_change = lowcomms_state_change;
        con->sock->sk->sk_user_data = con;
        con->sock->sk->sk_allocation = GFP_NOFS;
-       return 0;
 }
 
 /* Add the port number to an IPv6 or 4 sockaddr and return the address
@@ -510,7 +634,7 @@ static void process_sctp_notification(struct connection *con,
                                return;
                        }
                        make_sockaddr(&prim.ssp_addr, 0, &addr_len);
-                       if (dlm_addr_to_nodeid(&prim.ssp_addr, &nodeid)) {
+                       if (addr_to_nodeid(&prim.ssp_addr, &nodeid)) {
                                unsigned char *b=(unsigned char *)&prim.ssp_addr;
                                log_print("reject connect from unknown addr");
                                print_hex_dump_bytes("ss: ", DUMP_PREFIX_NONE, 
@@ -747,7 +871,7 @@ static int tcp_accept_from_sock(struct connection *con)
 
        /* Get the new node's NODEID */
        make_sockaddr(&peeraddr, 0, &len);
-       if (dlm_addr_to_nodeid(&peeraddr, &nodeid)) {
+       if (addr_to_nodeid(&peeraddr, &nodeid)) {
                unsigned char *b=(unsigned char *)&peeraddr;
                log_print("connect from non cluster node");
                print_hex_dump_bytes("ss: ", DUMP_PREFIX_NONE, 
@@ -862,7 +986,7 @@ static void sctp_init_assoc(struct connection *con)
        if (con->retries++ > MAX_CONNECT_RETRIES)
                return;
 
-       if (nodeid_to_addr(con->nodeid, (struct sockaddr *)&rem_addr)) {
+       if (nodeid_to_addr(con->nodeid, NULL, (struct sockaddr *)&rem_addr)) {
                log_print("no address for nodeid %d", con->nodeid);
                return;
        }
@@ -928,11 +1052,11 @@ static void sctp_init_assoc(struct connection *con)
 /* Connect a new socket to its peer */
 static void tcp_connect_to_sock(struct connection *con)
 {
-       int result = -EHOSTUNREACH;
        struct sockaddr_storage saddr, src_addr;
        int addr_len;
        struct socket *sock = NULL;
        int one = 1;
+       int result;
 
        if (con->nodeid == 0) {
                log_print("attempt to connect sock 0 foiled");
@@ -944,10 +1068,8 @@ static void tcp_connect_to_sock(struct connection *con)
                goto out;
 
        /* Some odd races can cause double-connects, ignore them */
-       if (con->sock) {
-               result = 0;
+       if (con->sock)
                goto out;
-       }
 
        /* Create a socket to communicate with */
        result = sock_create_kern(dlm_local_addr[0]->ss_family, SOCK_STREAM,
@@ -956,8 +1078,11 @@ static void tcp_connect_to_sock(struct connection *con)
                goto out_err;
 
        memset(&saddr, 0, sizeof(saddr));
-       if (dlm_nodeid_to_addr(con->nodeid, &saddr))
+       result = nodeid_to_addr(con->nodeid, &saddr, NULL);
+       if (result < 0) {
+               log_print("no address for nodeid %d", con->nodeid);
                goto out_err;
+       }
 
        sock->sk->sk_user_data = con;
        con->rx_action = receive_from_sock;
@@ -983,8 +1108,7 @@ static void tcp_connect_to_sock(struct connection *con)
        kernel_setsockopt(sock, SOL_TCP, TCP_NODELAY, (char *)&one,
                          sizeof(one));
 
-       result =
-               sock->ops->connect(sock, (struct sockaddr *)&saddr, addr_len,
+       result = sock->ops->connect(sock, (struct sockaddr *)&saddr, addr_len,
                                   O_NONBLOCK);
        if (result == -EINPROGRESS)
                result = 0;
@@ -1002,11 +1126,17 @@ out_err:
         * Some errors are fatal and this list might need adjusting. For other
         * errors we try again until the max number of retries is reached.
         */
-       if (result != -EHOSTUNREACH && result != -ENETUNREACH &&
-           result != -ENETDOWN && result != -EINVAL
-           && result != -EPROTONOSUPPORT) {
+       if (result != -EHOSTUNREACH &&
+           result != -ENETUNREACH &&
+           result != -ENETDOWN && 
+           result != -EINVAL &&
+           result != -EPROTONOSUPPORT) {
+               log_print("connect %d try %d error %d", con->nodeid,
+                         con->retries, result);
+               mutex_unlock(&con->sock_mutex);
+               msleep(1000);
                lowcomms_connect_sock(con);
-               result = 0;
+               return;
        }
 out:
        mutex_unlock(&con->sock_mutex);
@@ -1044,10 +1174,8 @@ static struct socket *tcp_create_listen_sock(struct connection *con,
        if (result < 0) {
                log_print("Failed to set SO_REUSEADDR on socket: %d", result);
        }
-       sock->sk->sk_user_data = con;
        con->rx_action = tcp_accept_from_sock;
        con->connect_action = tcp_connect_to_sock;
-       con->sock = sock;
 
        /* Bind to our port */
        make_sockaddr(saddr, dlm_config.ci_tcp_port, &addr_len);
@@ -1358,8 +1486,7 @@ static void send_to_sock(struct connection *con)
                                }
                                cond_resched();
                                goto out;
-                       }
-                       if (ret <= 0)
+                       } else if (ret < 0)
                                goto send_error;
                }
 
@@ -1376,7 +1503,6 @@ static void send_to_sock(struct connection *con)
                if (e->len == 0 && e->users == 0) {
                        list_del(&e->list);
                        free_entry(e);
-                       continue;
                }
        }
        spin_unlock(&con->writequeue_lock);
@@ -1394,7 +1520,6 @@ out_connect:
        mutex_unlock(&con->sock_mutex);
        if (!test_bit(CF_INIT_PENDING, &con->flags))
                lowcomms_connect_sock(con);
-       return;
 }
 
 static void clean_one_writequeue(struct connection *con)
@@ -1414,6 +1539,7 @@ static void clean_one_writequeue(struct connection *con)
 int dlm_lowcomms_close(int nodeid)
 {
        struct connection *con;
+       struct dlm_node_addr *na;
 
        log_print("closing connection to node %d", nodeid);
        con = nodeid2con(nodeid, 0);
@@ -1428,6 +1554,17 @@ int dlm_lowcomms_close(int nodeid)
                clean_one_writequeue(con);
                close_connection(con, true);
        }
+
+       spin_lock(&dlm_node_addrs_spin);
+       na = find_node_addr(nodeid);
+       if (na) {
+               list_del(&na->list);
+               while (na->addr_count--)
+                       kfree(na->addr[na->addr_count]);
+               kfree(na);
+       }
+       spin_unlock(&dlm_node_addrs_spin);
+
        return 0;
 }
 
@@ -1577,3 +1714,17 @@ fail_destroy:
 fail:
        return error;
 }
+
+void dlm_lowcomms_exit(void)
+{
+       struct dlm_node_addr *na, *safe;
+
+       spin_lock(&dlm_node_addrs_spin);
+       list_for_each_entry_safe(na, safe, &dlm_node_addrs, list) {
+               list_del(&na->list);
+               while (na->addr_count--)
+                       kfree(na->addr[na->addr_count]);
+               kfree(na);
+       }
+       spin_unlock(&dlm_node_addrs_spin);
+}
index 1311e6426287b61eed336c5f17f0cd1a67eab77f..67462e54fc2f80953979e3fb188aac35ed2195e2 100644 (file)
 
 int dlm_lowcomms_start(void);
 void dlm_lowcomms_stop(void);
+void dlm_lowcomms_exit(void);
 int dlm_lowcomms_close(int nodeid);
 void *dlm_lowcomms_get_buffer(int nodeid, int len, gfp_t allocation, char **ppc);
 void dlm_lowcomms_commit_buffer(void *mh);
 int dlm_lowcomms_connect_node(int nodeid);
+int dlm_lowcomms_addr(int nodeid, struct sockaddr_storage *addr, int len);
 
 #endif                         /* __LOWCOMMS_DOT_H__ */
 
index 5a59efa0bb469ebb9991be5d29bdb98c93233cfd..079c0bd71ab77eb291f704022daa9cf50567347d 100644 (file)
@@ -17,6 +17,7 @@
 #include "user.h"
 #include "memory.h"
 #include "config.h"
+#include "lowcomms.h"
 
 static int __init init_dlm(void)
 {
@@ -78,6 +79,7 @@ static void __exit exit_dlm(void)
        dlm_config_exit();
        dlm_memory_exit();
        dlm_lockspace_exit();
+       dlm_lowcomms_exit();
        dlm_unregister_debugfs();
 }
 
index 862640a36d5cbba1762ad47317dffbd72eab0531..476557b54921793a246cb11b1fc8f19c348aa17d 100644 (file)
@@ -616,13 +616,13 @@ int dlm_ls_stop(struct dlm_ls *ls)
        down_write(&ls->ls_recv_active);
 
        /*
-        * Abort any recovery that's in progress (see RECOVERY_STOP,
+        * Abort any recovery that's in progress (see RECOVER_STOP,
         * dlm_recovery_stopped()) and tell any other threads running in the
         * dlm to quit any processing (see RUNNING, dlm_locking_stopped()).
         */
 
        spin_lock(&ls->ls_recover_lock);
-       set_bit(LSFL_RECOVERY_STOP, &ls->ls_flags);
+       set_bit(LSFL_RECOVER_STOP, &ls->ls_flags);
        new = test_and_clear_bit(LSFL_RUNNING, &ls->ls_flags);
        ls->ls_recover_seq++;
        spin_unlock(&ls->ls_recover_lock);
@@ -642,12 +642,16 @@ int dlm_ls_stop(struct dlm_ls *ls)
         *    when recovery is complete.
         */
 
-       if (new)
-               down_write(&ls->ls_in_recovery);
+       if (new) {
+               set_bit(LSFL_RECOVER_DOWN, &ls->ls_flags);
+               wake_up_process(ls->ls_recoverd_task);
+               wait_event(ls->ls_recover_lock_wait,
+                          test_bit(LSFL_RECOVER_LOCK, &ls->ls_flags));
+       }
 
        /*
         * The recoverd suspend/resume makes sure that dlm_recoverd (if
-        * running) has noticed RECOVERY_STOP above and quit processing the
+        * running) has noticed RECOVER_STOP above and quit processing the
         * previous recovery.
         */
 
@@ -709,7 +713,8 @@ int dlm_ls_start(struct dlm_ls *ls)
                kfree(rv_old);
        }
 
-       dlm_recoverd_kick(ls);
+       set_bit(LSFL_RECOVER_WORK, &ls->ls_flags);
+       wake_up_process(ls->ls_recoverd_task);
        return 0;
 
  fail:
index 87f1a56eab32c8850ce1eec9eefa404c15919f49..9d61947d473a1191f4a0391bb837746dfb8206c3 100644 (file)
@@ -581,7 +581,7 @@ void dlm_receive_rcom(struct dlm_ls *ls, struct dlm_rcom *rc, int nodeid)
 
        spin_lock(&ls->ls_recover_lock);
        status = ls->ls_recover_status;
-       stop = test_bit(LSFL_RECOVERY_STOP, &ls->ls_flags);
+       stop = test_bit(LSFL_RECOVER_STOP, &ls->ls_flags);
        seq = ls->ls_recover_seq;
        spin_unlock(&ls->ls_recover_lock);
 
index 88ce65ff021ed35848b30ae129e9334930413cc3..32f9f8926ec3f17a3a69433402e8a0fecb07a1f6 100644 (file)
@@ -41,6 +41,7 @@ static int enable_locking(struct dlm_ls *ls, uint64_t seq)
                set_bit(LSFL_RUNNING, &ls->ls_flags);
                /* unblocks processes waiting to enter the dlm */
                up_write(&ls->ls_in_recovery);
+               clear_bit(LSFL_RECOVER_LOCK, &ls->ls_flags);
                error = 0;
        }
        spin_unlock(&ls->ls_recover_lock);
@@ -262,7 +263,7 @@ static void do_ls_recovery(struct dlm_ls *ls)
        rv = ls->ls_recover_args;
        ls->ls_recover_args = NULL;
        if (rv && ls->ls_recover_seq == rv->seq)
-               clear_bit(LSFL_RECOVERY_STOP, &ls->ls_flags);
+               clear_bit(LSFL_RECOVER_STOP, &ls->ls_flags);
        spin_unlock(&ls->ls_recover_lock);
 
        if (rv) {
@@ -282,26 +283,34 @@ static int dlm_recoverd(void *arg)
                return -1;
        }
 
+       down_write(&ls->ls_in_recovery);
+       set_bit(LSFL_RECOVER_LOCK, &ls->ls_flags);
+       wake_up(&ls->ls_recover_lock_wait);
+
        while (!kthread_should_stop()) {
                set_current_state(TASK_INTERRUPTIBLE);
-               if (!test_bit(LSFL_WORK, &ls->ls_flags))
+               if (!test_bit(LSFL_RECOVER_WORK, &ls->ls_flags) &&
+                   !test_bit(LSFL_RECOVER_DOWN, &ls->ls_flags))
                        schedule();
                set_current_state(TASK_RUNNING);
 
-               if (test_and_clear_bit(LSFL_WORK, &ls->ls_flags))
+               if (test_and_clear_bit(LSFL_RECOVER_DOWN, &ls->ls_flags)) {
+                       down_write(&ls->ls_in_recovery);
+                       set_bit(LSFL_RECOVER_LOCK, &ls->ls_flags);
+                       wake_up(&ls->ls_recover_lock_wait);
+               }
+
+               if (test_and_clear_bit(LSFL_RECOVER_WORK, &ls->ls_flags))
                        do_ls_recovery(ls);
        }
 
+       if (test_bit(LSFL_RECOVER_LOCK, &ls->ls_flags))
+               up_write(&ls->ls_in_recovery);
+
        dlm_put_lockspace(ls);
        return 0;
 }
 
-void dlm_recoverd_kick(struct dlm_ls *ls)
-{
-       set_bit(LSFL_WORK, &ls->ls_flags);
-       wake_up_process(ls->ls_recoverd_task);
-}
-
 int dlm_recoverd_start(struct dlm_ls *ls)
 {
        struct task_struct *p;
index 866657c5d69deb0eaf415f95f6f2690ab70564c8..8856079733fa303d4b411938b13a5f1caac55598 100644 (file)
@@ -14,7 +14,6 @@
 #ifndef __RECOVERD_DOT_H__
 #define __RECOVERD_DOT_H__
 
-void dlm_recoverd_kick(struct dlm_ls *ls);
 void dlm_recoverd_stop(struct dlm_ls *ls);
 int dlm_recoverd_start(struct dlm_ls *ls);
 void dlm_recoverd_suspend(struct dlm_ls *ls);
index 5badb0c039de404b24208c8e6c2041b3331ae5bb..1562c27a2fab27f700825e0090e4d98492fa2fbd 100644 (file)
 
 #define EXOFS_DBGMSG2(M...) do {} while (0)
 
-enum {MAX_PAGES_KMALLOC = PAGE_SIZE / sizeof(struct page *), };
-
 unsigned exofs_max_io_pages(struct ore_layout *layout,
                            unsigned expected_pages)
 {
-       unsigned pages = min_t(unsigned, expected_pages, MAX_PAGES_KMALLOC);
+       unsigned pages = min_t(unsigned, expected_pages,
+                              layout->max_io_length / PAGE_SIZE);
 
-       /* TODO: easily support bio chaining */
-       pages =  min_t(unsigned, pages, layout->max_io_length / PAGE_SIZE);
        return pages;
 }
 
@@ -101,7 +98,8 @@ static void _pcol_reset(struct page_collect *pcol)
         * it might not end here. don't be left with nothing
         */
        if (!pcol->expected_pages)
-               pcol->expected_pages = MAX_PAGES_KMALLOC;
+               pcol->expected_pages =
+                               exofs_max_io_pages(&pcol->sbi->layout, ~0);
 }
 
 static int pcol_try_alloc(struct page_collect *pcol)
@@ -389,6 +387,8 @@ static int readpage_strip(void *data, struct page *page)
        size_t len;
        int ret;
 
+       BUG_ON(!PageLocked(page));
+
        /* FIXME: Just for debugging, will be removed */
        if (PageUptodate(page))
                EXOFS_ERR("PageUptodate(0x%lx, 0x%lx)\n", pcol->inode->i_ino,
@@ -572,8 +572,16 @@ static struct page *__r4w_get_page(void *priv, u64 offset, bool *uptodate)
 
        if (!pcol->that_locked_page ||
            (pcol->that_locked_page->index != index)) {
-               struct page *page = find_get_page(pcol->inode->i_mapping, index);
+               struct page *page;
+               loff_t i_size = i_size_read(pcol->inode);
+
+               if (offset >= i_size) {
+                       *uptodate = true;
+                       EXOFS_DBGMSG("offset >= i_size index=0x%lx\n", index);
+                       return ZERO_PAGE(0);
+               }
 
+               page =  find_get_page(pcol->inode->i_mapping, index);
                if (!page) {
                        page = find_or_create_page(pcol->inode->i_mapping,
                                                   index, GFP_NOFS);
@@ -602,12 +610,13 @@ static void __r4w_put_page(void *priv, struct page *page)
 {
        struct page_collect *pcol = priv;
 
-       if (pcol->that_locked_page != page) {
+       if ((pcol->that_locked_page != page) && (ZERO_PAGE(0) != page)) {
                EXOFS_DBGMSG("index=0x%lx\n", page->index);
                page_cache_release(page);
                return;
        }
-       EXOFS_DBGMSG("that_locked_page index=0x%lx\n", page->index);
+       EXOFS_DBGMSG("that_locked_page index=0x%lx\n",
+                    ZERO_PAGE(0) == page ? -1 : page->index);
 }
 
 static const struct _ore_r4w_op _r4w_op = {
index 24a49d47e9354c00f0ebd2da6c92d3520e71332c..1585db1aa3651a3eb2fbe586156fd5bd270f5b82 100644 (file)
@@ -837,11 +837,11 @@ static int _write_mirror(struct ore_io_state *ios, int cur_comp)
                                bio->bi_rw |= REQ_WRITE;
                        }
 
-                       osd_req_write(or, _ios_obj(ios, dev), per_dev->offset,
-                                     bio, per_dev->length);
+                       osd_req_write(or, _ios_obj(ios, cur_comp),
+                                     per_dev->offset, bio, per_dev->length);
                        ORE_DBGMSG("write(0x%llx) offset=0x%llx "
                                      "length=0x%llx dev=%d\n",
-                                    _LLU(_ios_obj(ios, dev)->id),
+                                    _LLU(_ios_obj(ios, cur_comp)->id),
                                     _LLU(per_dev->offset),
                                     _LLU(per_dev->length), dev);
                } else if (ios->kern_buff) {
@@ -853,20 +853,20 @@ static int _write_mirror(struct ore_io_state *ios, int cur_comp)
                               (ios->si.unit_off + ios->length >
                                ios->layout->stripe_unit));
 
-                       ret = osd_req_write_kern(or, _ios_obj(ios, per_dev->dev),
+                       ret = osd_req_write_kern(or, _ios_obj(ios, cur_comp),
                                                 per_dev->offset,
                                                 ios->kern_buff, ios->length);
                        if (unlikely(ret))
                                goto out;
                        ORE_DBGMSG2("write_kern(0x%llx) offset=0x%llx "
                                      "length=0x%llx dev=%d\n",
-                                    _LLU(_ios_obj(ios, dev)->id),
+                                    _LLU(_ios_obj(ios, cur_comp)->id),
                                     _LLU(per_dev->offset),
                                     _LLU(ios->length), per_dev->dev);
                } else {
-                       osd_req_set_attributes(or, _ios_obj(ios, dev));
+                       osd_req_set_attributes(or, _ios_obj(ios, cur_comp));
                        ORE_DBGMSG2("obj(0x%llx) set_attributes=%d dev=%d\n",
-                                    _LLU(_ios_obj(ios, dev)->id),
+                                    _LLU(_ios_obj(ios, cur_comp)->id),
                                     ios->out_attr_len, dev);
                }
 
index 433783624d107d1d29fd16ffb1c4890ecd78c7cd..dde41a75c7c8dbd36597272a13f5c6f3487507d3 100644 (file)
@@ -400,8 +400,6 @@ static int exofs_sync_fs(struct super_block *sb, int wait)
        ret = ore_write(ios);
        if (unlikely(ret))
                EXOFS_ERR("%s: ore_write failed.\n", __func__);
-       else
-               sb->s_dirt = 0;
 
 
        unlock_super(sb);
@@ -412,14 +410,6 @@ out:
        return ret;
 }
 
-static void exofs_write_super(struct super_block *sb)
-{
-       if (!(sb->s_flags & MS_RDONLY))
-               exofs_sync_fs(sb, 1);
-       else
-               sb->s_dirt = 0;
-}
-
 static void _exofs_print_device(const char *msg, const char *dev_path,
                                struct osd_dev *od, u64 pid)
 {
@@ -952,7 +942,6 @@ static const struct super_operations exofs_sops = {
        .write_inode    = exofs_write_inode,
        .evict_inode    = exofs_evict_inode,
        .put_super      = exofs_put_super,
-       .write_super    = exofs_write_super,
        .sync_fs        = exofs_sync_fs,
        .statfs         = exofs_statfs,
 };
index 5a7b691e748bdcda66746098d42194cb4682f7e5..1b4f2f95fc3797880ed7a7c6eab82b086ca11e4e 100644 (file)
@@ -80,8 +80,13 @@ static ssize_t uri_show(struct exofs_dev *edp, char *buf)
 
 static ssize_t uri_store(struct exofs_dev *edp, const char *buf, size_t len)
 {
+       uint8_t *new_uri;
+
        edp->urilen = strlen(buf) + 1;
-       edp->uri = krealloc(edp->uri, edp->urilen, GFP_KERNEL);
+       new_uri = krealloc(edp->uri, edp->urilen, GFP_KERNEL);
+       if (new_uri == NULL)
+               return -ENOMEM;
+       edp->uri = new_uri;
        strncpy(edp->uri, buf, edp->urilen);
        return edp->urilen;
 }
index 9a4a5c48b1c99f6a60ff02d35cda4ef1ced9bd50..a07597307fd1cd221b20997d9e0268caa6bc9138 100644 (file)
@@ -3459,14 +3459,6 @@ ext3_reserve_inode_write(handle_t *handle, struct inode *inode,
  * inode out, but prune_icache isn't a user-visible syncing function.
  * Whenever the user wants stuff synced (sys_sync, sys_msync, sys_fsync)
  * we start and wait on commits.
- *
- * Is this efficient/effective?  Well, we're being nice to the system
- * by cleaning up our inodes proactively so they can be reaped
- * without I/O.  But we are potentially leaving up to five seconds'
- * worth of inodes floating about which prune_icache wants us to
- * write out.  One way to fix that would be to get prune_icache()
- * to do a write_super() to free up some memory.  It has the desired
- * effect.
  */
 int ext3_mark_inode_dirty(handle_t *handle, struct inode *inode)
 {
index ff9bcdc5b0d5a7b5f210723092716e9e0f32937c..8c892e93d8e7b6f2ff727709619eedde0e880812 100644 (file)
@@ -64,11 +64,6 @@ static int ext3_freeze(struct super_block *sb);
 
 /*
  * Wrappers for journal_start/end.
- *
- * The only special thing we need to do here is to make sure that all
- * journal_end calls result in the superblock being marked dirty, so
- * that sync() will call the filesystem's write_super callback if
- * appropriate.
  */
 handle_t *ext3_journal_start_sb(struct super_block *sb, int nblocks)
 {
@@ -90,12 +85,6 @@ handle_t *ext3_journal_start_sb(struct super_block *sb, int nblocks)
        return journal_start(journal, nblocks);
 }
 
-/*
- * The only special thing we need to do here is to make sure that all
- * journal_stop calls result in the superblock being marked dirty, so
- * that sync() will call the filesystem's write_super callback if
- * appropriate.
- */
 int __ext3_journal_stop(const char *where, handle_t *handle)
 {
        struct super_block *sb;
index 6324f74e03424e9ac21ceb01f6fbee07caa546df..dff171c3a1234e2ea9f545d8c2fd65c1b9b4bc1d 100644 (file)
@@ -1970,7 +1970,7 @@ static void ext4_end_io_buffer_write(struct buffer_head *bh, int uptodate);
  * This function can get called via...
  *   - ext4_da_writepages after taking page lock (have journal handle)
  *   - journal_submit_inode_data_buffers (no journal handle)
- *   - shrink_page_list via pdflush (no journal handle)
+ *   - shrink_page_list via the kswapd/direct reclaim (no journal handle)
  *   - grab_page_cache when doing write_begin (have journal handle)
  *
  * We don't do any block allocation in this function. If we have page with
@@ -4589,14 +4589,6 @@ static int ext4_expand_extra_isize(struct inode *inode,
  * inode out, but prune_icache isn't a user-visible syncing function.
  * Whenever the user wants stuff synced (sys_sync, sys_msync, sys_fsync)
  * we start and wait on commits.
- *
- * Is this efficient/effective?  Well, we're being nice to the system
- * by cleaning up our inodes proactively so they can be reaped
- * without I/O.  But we are potentially leaving up to five seconds'
- * worth of inodes floating about which prune_icache wants us to
- * write out.  One way to fix that would be to get prune_icache()
- * to do a write_super() to free up some memory.  It has the desired
- * effect.
  */
 int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode)
 {
index d76ec8277d3fca660e619d097711cc0057349823..3e0851e4f468ee190c53d7d6819e6e634d47412c 100644 (file)
@@ -326,11 +326,6 @@ static void ext4_put_nojournal(handle_t *handle)
 
 /*
  * Wrappers for jbd2_journal_start/end.
- *
- * The only special thing we need to do here is to make sure that all
- * journal_end calls result in the superblock being marked dirty, so
- * that sync() will call the filesystem's write_super callback if
- * appropriate.
  */
 handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks)
 {
@@ -356,12 +351,6 @@ handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks)
        return jbd2_journal_start(journal, nblocks);
 }
 
-/*
- * The only special thing we need to do here is to make sure that all
- * jbd2_journal_stop calls result in the superblock being marked dirty, so
- * that sync() will call the filesystem's write_super callback if
- * appropriate.
- */
 int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle)
 {
        struct super_block *sb;
index 93d8d6c9494dbd5737b0842a3ebb55ef972e0d87..aba15f1b7ad2974aa85e2c7272afc3d7836a40bc 100644 (file)
@@ -703,13 +703,16 @@ static ssize_t fuse_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
                                  unsigned long nr_segs, loff_t pos)
 {
        struct inode *inode = iocb->ki_filp->f_mapping->host;
+       struct fuse_conn *fc = get_fuse_conn(inode);
 
-       if (pos + iov_length(iov, nr_segs) > i_size_read(inode)) {
+       /*
+        * In auto invalidate mode, always update attributes on read.
+        * Otherwise, only update if we attempt to read past EOF (to ensure
+        * i_size is up to date).
+        */
+       if (fc->auto_inval_data ||
+           (pos + iov_length(iov, nr_segs) > i_size_read(inode))) {
                int err;
-               /*
-                * If trying to read past EOF, make sure the i_size
-                * attribute is up-to-date.
-                */
                err = fuse_update_attributes(inode, NULL, iocb->ki_filp, NULL);
                if (err)
                        return err;
@@ -1700,7 +1703,7 @@ static int fuse_verify_ioctl_iov(struct iovec *iov, size_t count)
        size_t n;
        u32 max = FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT;
 
-       for (n = 0; n < count; n++) {
+       for (n = 0; n < count; n++, iov++) {
                if (iov->iov_len > (size_t) max)
                        return -ENOMEM;
                max -= iov->iov_len;
index 771fb6322c0750d223bb2ee7873f6d0cdbdef41b..e24dd74e3068d130545ee58f918519d4ca2ee620 100644 (file)
@@ -484,6 +484,9 @@ struct fuse_conn {
        /** Is fallocate not implemented by fs? */
        unsigned no_fallocate:1;
 
+       /** Use enhanced/automatic page cache invalidation. */
+       unsigned auto_inval_data:1;
+
        /** The number of requests waiting for completion */
        atomic_t num_waiting;
 
index 1cd61652018c7c8547a060344ef998ee6ae96879..ce0a2838ccd097a5392d469fc0650d2e7b0d7e8d 100644 (file)
@@ -197,6 +197,7 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,
        struct fuse_conn *fc = get_fuse_conn(inode);
        struct fuse_inode *fi = get_fuse_inode(inode);
        loff_t oldsize;
+       struct timespec old_mtime;
 
        spin_lock(&fc->lock);
        if (attr_version != 0 && fi->attr_version > attr_version) {
@@ -204,15 +205,35 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,
                return;
        }
 
+       old_mtime = inode->i_mtime;
        fuse_change_attributes_common(inode, attr, attr_valid);
 
        oldsize = inode->i_size;
        i_size_write(inode, attr->size);
        spin_unlock(&fc->lock);
 
-       if (S_ISREG(inode->i_mode) && oldsize != attr->size) {
-               truncate_pagecache(inode, oldsize, attr->size);
-               invalidate_inode_pages2(inode->i_mapping);
+       if (S_ISREG(inode->i_mode)) {
+               bool inval = false;
+
+               if (oldsize != attr->size) {
+                       truncate_pagecache(inode, oldsize, attr->size);
+                       inval = true;
+               } else if (fc->auto_inval_data) {
+                       struct timespec new_mtime = {
+                               .tv_sec = attr->mtime,
+                               .tv_nsec = attr->mtimensec,
+                       };
+
+                       /*
+                        * Auto inval mode also checks and invalidates if mtime
+                        * has changed.
+                        */
+                       if (!timespec_equal(&old_mtime, &new_mtime))
+                               inval = true;
+               }
+
+               if (inval)
+                       invalidate_inode_pages2(inode->i_mapping);
        }
 }
 
@@ -834,6 +855,8 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req)
                                fc->big_writes = 1;
                        if (arg->flags & FUSE_DONT_MASK)
                                fc->dont_mask = 1;
+                       if (arg->flags & FUSE_AUTO_INVAL_DATA)
+                               fc->auto_inval_data = 1;
                } else {
                        ra_pages = fc->max_read / PAGE_CACHE_SIZE;
                        fc->no_lock = 1;
@@ -859,7 +882,8 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req)
        arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE;
        arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_ATOMIC_O_TRUNC |
                FUSE_EXPORT_SUPPORT | FUSE_BIG_WRITES | FUSE_DONT_MASK |
-               FUSE_FLOCK_LOCKS;
+               FUSE_SPLICE_WRITE | FUSE_SPLICE_MOVE | FUSE_SPLICE_READ |
+               FUSE_FLOCK_LOCKS | FUSE_IOCTL_DIR | FUSE_AUTO_INVAL_DATA;
        req->in.h.opcode = FUSE_INIT;
        req->in.numargs = 1;
        req->in.args[0].size = sizeof(*arg);
index d6526347d3860eb8269f5ac5fb2f9817220af6b5..01c4975da4bc6252a9ce41e4c23ebd183c80a47c 100644 (file)
@@ -612,6 +612,7 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
        struct gfs2_sbd *sdp = GFS2_SB(mapping->host);
        struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode);
        unsigned int data_blocks = 0, ind_blocks = 0, rblocks;
+       unsigned requested = 0;
        int alloc_required;
        int error = 0;
        pgoff_t index = pos >> PAGE_CACHE_SHIFT;
@@ -641,7 +642,8 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
                if (error)
                        goto out_unlock;
 
-               error = gfs2_inplace_reserve(ip, data_blocks + ind_blocks);
+               requested = data_blocks + ind_blocks;
+               error = gfs2_inplace_reserve(ip, requested);
                if (error)
                        goto out_qunlock;
        }
@@ -654,7 +656,7 @@ static int gfs2_write_begin(struct file *file, struct address_space *mapping,
        if (&ip->i_inode == sdp->sd_rindex)
                rblocks += 2 * RES_STATFS;
        if (alloc_required)
-               rblocks += gfs2_rg_blocks(ip);
+               rblocks += gfs2_rg_blocks(ip, requested);
 
        error = gfs2_trans_begin(sdp, rblocks,
                                 PAGE_CACHE_SIZE/sdp->sd_sb.sb_bsize);
@@ -868,8 +870,7 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping,
        brelse(dibh);
 failed:
        gfs2_trans_end(sdp);
-       if (gfs2_mb_reserved(ip))
-               gfs2_inplace_release(ip);
+       gfs2_inplace_release(ip);
        if (ip->i_res->rs_qa_qd_num)
                gfs2_quota_unlock(ip);
        if (inode == sdp->sd_rindex) {
@@ -1023,7 +1024,7 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb,
                                  offset, nr_segs, gfs2_get_block_direct,
                                  NULL, NULL, 0);
 out:
-       gfs2_glock_dq_m(1, &gh);
+       gfs2_glock_dq(&gh);
        gfs2_holder_uninit(&gh);
        return rv;
 }
index 49cd7dd4a9fa882781fa895aff8c19401c170aad..1fd3ae237bdde3faee7b67d68bfc50b496b6e976 100644 (file)
@@ -786,7 +786,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
                goto out_rlist;
 
        if (gfs2_rs_active(ip->i_res)) /* needs to be done with the rgrp glock held */
-               gfs2_rs_deltree(ip->i_res);
+               gfs2_rs_deltree(ip, ip->i_res);
 
        error = gfs2_trans_begin(sdp, rg_blocks + RES_DINODE +
                                 RES_INDIRECT + RES_STATFS + RES_QUOTA,
index d1d791ef38de2188852551254a63f974a605feff..30e21997a1a1323963e6de594482d3a4f9e74878 100644 (file)
@@ -322,6 +322,29 @@ static long gfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
        return -ENOTTY;
 }
 
+/**
+ * gfs2_size_hint - Give a hint to the size of a write request
+ * @file: The struct file
+ * @offset: The file offset of the write
+ * @size: The length of the write
+ *
+ * When we are about to do a write, this function records the total
+ * write size in order to provide a suitable hint to the lower layers
+ * about how many blocks will be required.
+ *
+ */
+
+static void gfs2_size_hint(struct file *filep, loff_t offset, size_t size)
+{
+       struct inode *inode = filep->f_dentry->d_inode;
+       struct gfs2_sbd *sdp = GFS2_SB(inode);
+       struct gfs2_inode *ip = GFS2_I(inode);
+       size_t blks = (size + sdp->sd_sb.sb_bsize - 1) >> sdp->sd_sb.sb_bsize_shift;
+       int hint = min_t(size_t, INT_MAX, blks);
+
+       atomic_set(&ip->i_res->rs_sizehint, hint);
+}
+
 /**
  * gfs2_allocate_page_backing - Use bmap to allocate blocks
  * @page: The (locked) page to allocate backing for
@@ -382,8 +405,7 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
        if (ret)
                return ret;
 
-       atomic_set(&ip->i_res->rs_sizehint,
-                  PAGE_CACHE_SIZE >> sdp->sd_sb.sb_bsize_shift);
+       gfs2_size_hint(vma->vm_file, pos, PAGE_CACHE_SIZE);
 
        gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
        ret = gfs2_glock_nq(&gh);
@@ -419,7 +441,7 @@ static int gfs2_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
                rblocks += data_blocks ? data_blocks : 1;
        if (ind_blocks || data_blocks) {
                rblocks += RES_STATFS + RES_QUOTA;
-               rblocks += gfs2_rg_blocks(ip);
+               rblocks += gfs2_rg_blocks(ip, data_blocks + ind_blocks);
        }
        ret = gfs2_trans_begin(sdp, rblocks, 0);
        if (ret)
@@ -663,7 +685,8 @@ static ssize_t gfs2_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
        if (ret)
                return ret;
 
-       atomic_set(&ip->i_res->rs_sizehint, writesize >> sdp->sd_sb.sb_bsize_shift);
+       gfs2_size_hint(file, pos, writesize);
+
        if (file->f_flags & O_APPEND) {
                struct gfs2_holder gh;
 
@@ -789,7 +812,7 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset,
        if (unlikely(error))
                goto out_uninit;
 
-       atomic_set(&ip->i_res->rs_sizehint, len >> sdp->sd_sb.sb_bsize_shift);
+       gfs2_size_hint(file, offset, len);
 
        while (len > 0) {
                if (len < bytes)
@@ -822,7 +845,7 @@ retry:
                                &max_bytes, &data_blocks, &ind_blocks);
 
                rblocks = RES_DINODE + ind_blocks + RES_STATFS + RES_QUOTA +
-                         RES_RG_HDR + gfs2_rg_blocks(ip);
+                         RES_RG_HDR + gfs2_rg_blocks(ip, data_blocks + ind_blocks);
                if (gfs2_is_jdata(ip))
                        rblocks += data_blocks ? data_blocks : 1;
 
index 1ed81f40da0dc7c0cf1e71b6da268d5edce07ca7..e6c2fd53cab252da56fab66b3ca2749ef7ed1f44 100644 (file)
@@ -185,20 +185,6 @@ static void gfs2_glock_remove_from_lru(struct gfs2_glock *gl)
        spin_unlock(&lru_lock);
 }
 
-/**
- * __gfs2_glock_schedule_for_reclaim - Add a glock to the reclaim list
- * @gl: the glock
- *
- * If the glock is demotable, then we add it (or move it) to the end
- * of the glock LRU list.
- */
-
-static void __gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl)
-{
-       if (demote_ok(gl))
-               gfs2_glock_add_to_lru(gl);
-}
-
 /**
  * gfs2_glock_put_nolock() - Decrement reference count on glock
  * @gl: The glock to put
@@ -883,7 +869,14 @@ static int gfs2_glock_demote_wait(void *word)
        return 0;
 }
 
-static void wait_on_holder(struct gfs2_holder *gh)
+/**
+ * gfs2_glock_wait - wait on a glock acquisition
+ * @gh: the glock holder
+ *
+ * Returns: 0 on success
+ */
+
+int gfs2_glock_wait(struct gfs2_holder *gh)
 {
        unsigned long time1 = jiffies;
 
@@ -894,12 +887,7 @@ static void wait_on_holder(struct gfs2_holder *gh)
                gh->gh_gl->gl_hold_time = min(gh->gh_gl->gl_hold_time +
                                              GL_GLOCK_HOLD_INCR,
                                              GL_GLOCK_MAX_HOLD);
-}
-
-static void wait_on_demote(struct gfs2_glock *gl)
-{
-       might_sleep();
-       wait_on_bit(&gl->gl_flags, GLF_DEMOTE, gfs2_glock_demote_wait, TASK_UNINTERRUPTIBLE);
+       return gh->gh_error;
 }
 
 /**
@@ -929,19 +917,6 @@ static void handle_callback(struct gfs2_glock *gl, unsigned int state,
        trace_gfs2_demote_rq(gl);
 }
 
-/**
- * gfs2_glock_wait - wait on a glock acquisition
- * @gh: the glock holder
- *
- * Returns: 0 on success
- */
-
-int gfs2_glock_wait(struct gfs2_holder *gh)
-{
-       wait_on_holder(gh);
-       return gh->gh_error;
-}
-
 void gfs2_print_dbg(struct seq_file *seq, const char *fmt, ...)
 {
        struct va_format vaf;
@@ -979,7 +954,7 @@ __acquires(&gl->gl_spin)
        struct gfs2_sbd *sdp = gl->gl_sbd;
        struct list_head *insert_pt = NULL;
        struct gfs2_holder *gh2;
-       int try_lock = 0;
+       int try_futile = 0;
 
        BUG_ON(gh->gh_owner_pid == NULL);
        if (test_and_set_bit(HIF_WAIT, &gh->gh_iflags))
@@ -987,7 +962,7 @@ __acquires(&gl->gl_spin)
 
        if (gh->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB)) {
                if (test_bit(GLF_LOCK, &gl->gl_flags))
-                       try_lock = 1;
+                       try_futile = !may_grant(gl, gh);
                if (test_bit(GLF_INVALIDATE_IN_PROGRESS, &gl->gl_flags))
                        goto fail;
        }
@@ -996,9 +971,8 @@ __acquires(&gl->gl_spin)
                if (unlikely(gh2->gh_owner_pid == gh->gh_owner_pid &&
                    (gh->gh_gl->gl_ops->go_type != LM_TYPE_FLOCK)))
                        goto trap_recursive;
-               if (try_lock &&
-                   !(gh2->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB)) &&
-                   !may_grant(gl, gh)) {
+               if (try_futile &&
+                   !(gh2->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB))) {
 fail:
                        gh->gh_error = GLR_TRYFAILED;
                        gfs2_holder_wake(gh);
@@ -1121,8 +1095,9 @@ void gfs2_glock_dq(struct gfs2_holder *gh)
                    !test_bit(GLF_DEMOTE, &gl->gl_flags))
                        fast_path = 1;
        }
-       if (!test_bit(GLF_LFLUSH, &gl->gl_flags))
-               __gfs2_glock_schedule_for_reclaim(gl);
+       if (!test_bit(GLF_LFLUSH, &gl->gl_flags) && demote_ok(gl))
+               gfs2_glock_add_to_lru(gl);
+
        trace_gfs2_glock_queue(gh, 0);
        spin_unlock(&gl->gl_spin);
        if (likely(fast_path))
@@ -1141,7 +1116,8 @@ void gfs2_glock_dq_wait(struct gfs2_holder *gh)
 {
        struct gfs2_glock *gl = gh->gh_gl;
        gfs2_glock_dq(gh);
-       wait_on_demote(gl);
+       might_sleep();
+       wait_on_bit(&gl->gl_flags, GLF_DEMOTE, gfs2_glock_demote_wait, TASK_UNINTERRUPTIBLE);
 }
 
 /**
index aaecc8085fc55945009c855eda554079cf100b59..99d7c64b5091a77b7d1c993bdb4022f69d76ef22 100644 (file)
@@ -102,6 +102,24 @@ struct gfs2_rgrpd {
        u32 rd_rs_cnt;                  /* count of current reservations */
 };
 
+struct gfs2_rbm {
+       struct gfs2_rgrpd *rgd;
+       struct gfs2_bitmap *bi; /* Bitmap must belong to the rgd */
+       u32 offset;             /* The offset is bitmap relative */
+};
+
+static inline u64 gfs2_rbm_to_block(const struct gfs2_rbm *rbm)
+{
+       return rbm->rgd->rd_data0 + (rbm->bi->bi_start * GFS2_NBBY) + rbm->offset;
+}
+
+static inline bool gfs2_rbm_eq(const struct gfs2_rbm *rbm1,
+                              const struct gfs2_rbm *rbm2)
+{
+       return (rbm1->rgd == rbm2->rgd) && (rbm1->bi == rbm2->bi) && 
+              (rbm1->offset == rbm2->offset);
+}
+
 enum gfs2_state_bits {
        BH_Pinned = BH_PrivateStart,
        BH_Escaped = BH_PrivateStart + 1,
@@ -250,17 +268,12 @@ struct gfs2_blkreserv {
        /* components used during write (step 1): */
        atomic_t rs_sizehint;         /* hint of the write size */
 
-       /* components used during inplace_reserve (step 2): */
-       u32 rs_requested; /* Filled in by caller of gfs2_inplace_reserve() */
-
        /* components used during get_local_rgrp (step 3): */
-       struct gfs2_rgrpd *rs_rgd;    /* pointer to the gfs2_rgrpd */
+       struct gfs2_rbm rs_rbm;
        struct gfs2_holder rs_rgd_gh; /* Filled in by get_local_rgrp */
        struct rb_node rs_node;       /* link to other block reservations */
 
        /* components used during block searches and assignments (step 4): */
-       struct gfs2_bitmap *rs_bi;    /* bitmap for the current allocation */
-       u32 rs_biblk;                 /* start block relative to the bi */
        u32 rs_free;                  /* how many blocks are still free */
 
        /* ancillary quota stuff */
index 4ce22e54730806e02ed0ba70f7e7fc847d513142..f2709ea887da9ef164ab28a8857625f495cbc8fc 100644 (file)
@@ -737,10 +737,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
                brelse(bh);
 
        gfs2_trans_end(sdp);
-       /* Check if we reserved space in the rgrp. Function link_dinode may
-          not, depending on whether alloc is required. */
-       if (gfs2_mb_reserved(dip))
-               gfs2_inplace_release(dip);
+       gfs2_inplace_release(dip);
        gfs2_quota_unlock(dip);
        mark_inode_dirty(inode);
        gfs2_glock_dq_uninit_m(2, ghs);
@@ -897,7 +894,7 @@ static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
                        goto out_gunlock_q;
 
                error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
-                                        gfs2_rg_blocks(dip) +
+                                        gfs2_rg_blocks(dip, sdp->sd_max_dirres) +
                                         2 * RES_DINODE + RES_STATFS +
                                         RES_QUOTA, 0);
                if (error)
@@ -1378,7 +1375,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
                        goto out_gunlock_q;
 
                error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
-                                        gfs2_rg_blocks(ndip) +
+                                        gfs2_rg_blocks(ndip, sdp->sd_max_dirres) +
                                         4 * RES_DINODE + 4 * RES_LEAF +
                                         RES_STATFS + RES_QUOTA + 4, 0);
                if (error)
@@ -1722,7 +1719,9 @@ static int gfs2_setxattr(struct dentry *dentry, const char *name,
        gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
        ret = gfs2_glock_nq(&gh);
        if (ret == 0) {
-               ret = generic_setxattr(dentry, name, data, size, flags);
+               ret = gfs2_rs_alloc(ip);
+               if (ret == 0)
+                       ret = generic_setxattr(dentry, name, data, size, flags);
                gfs2_glock_dq(&gh);
        }
        gfs2_holder_uninit(&gh);
@@ -1757,7 +1756,9 @@ static int gfs2_removexattr(struct dentry *dentry, const char *name)
        gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
        ret = gfs2_glock_nq(&gh);
        if (ret == 0) {
-               ret = generic_removexattr(dentry, name);
+               ret = gfs2_rs_alloc(ip);
+               if (ret == 0)
+                       ret = generic_removexattr(dentry, name);
                gfs2_glock_dq(&gh);
        }
        gfs2_holder_uninit(&gh);
index 3a56c8d94de0607249e6296a18ec28b5ea120e89..22255d96b27efbb9c3a93e6db8678a147d99548b 100644 (file)
@@ -52,7 +52,7 @@ static int gfs2_aspace_writepage(struct page *page, struct writeback_control *wb
                /*
                 * If it's a fully non-blocking write attempt and we cannot
                 * lock the buffer then redirty the page.  Note that this can
-                * potentially cause a busy-wait loop from pdflush and kswapd
+                * potentially cause a busy-wait loop from flusher thread and kswapd
                 * activity, but those code paths have their own higher-level
                 * throttling.
                 */
index a3bde91645c29489fce1097456955235f2a63a12..420bc3805ccc4740f6dd04069724baf6098a5042 100644 (file)
@@ -765,6 +765,7 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda)
        struct gfs2_holder *ghs, i_gh;
        unsigned int qx, x;
        struct gfs2_quota_data *qd;
+       unsigned reserved;
        loff_t offset;
        unsigned int nalloc = 0, blocks;
        int error;
@@ -811,13 +812,13 @@ static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda)
         * two blocks need to be updated instead of 1 */
        blocks = num_qd * data_blocks + RES_DINODE + num_qd + 3;
 
-       error = gfs2_inplace_reserve(ip, 1 +
-                                    (nalloc * (data_blocks + ind_blocks)));
+       reserved = 1 + (nalloc * (data_blocks + ind_blocks));
+       error = gfs2_inplace_reserve(ip, reserved);
        if (error)
                goto out_alloc;
 
        if (nalloc)
-               blocks += gfs2_rg_blocks(ip) + nalloc * ind_blocks + RES_STATFS;
+               blocks += gfs2_rg_blocks(ip, reserved) + nalloc * ind_blocks + RES_STATFS;
 
        error = gfs2_trans_begin(sdp, blocks, 0);
        if (error)
@@ -1598,7 +1599,7 @@ static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id,
                error = gfs2_inplace_reserve(ip, blocks);
                if (error)
                        goto out_i;
-               blocks += gfs2_rg_blocks(ip);
+               blocks += gfs2_rg_blocks(ip, blocks);
        }
 
        /* Some quotas span block boundaries and can update two blocks,
index 4d34887a601d966660549b0d0a27517353c1ed5e..55a2651666c9b75a2ab58134974bb22df2ae5cb0 100644 (file)
@@ -67,53 +67,44 @@ static const char valid_change[16] = {
                1, 0, 0, 0
 };
 
-static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal,
-                       unsigned char old_state,
-                       struct gfs2_bitmap **rbi);
-
 /**
  * gfs2_setbit - Set a bit in the bitmaps
- * @rgd: the resource group descriptor
- * @buf2: the clone buffer that holds the bitmaps
- * @bi: the bitmap structure
- * @block: the block to set
+ * @rbm: The position of the bit to set
+ * @do_clone: Also set the clone bitmap, if it exists
  * @new_state: the new state of the block
  *
  */
 
-static inline void gfs2_setbit(struct gfs2_rgrpd *rgd, unsigned char *buf2,
-                              struct gfs2_bitmap *bi, u32 block,
+static inline void gfs2_setbit(const struct gfs2_rbm *rbm, bool do_clone,
                               unsigned char new_state)
 {
        unsigned char *byte1, *byte2, *end, cur_state;
-       unsigned int buflen = bi->bi_len;
-       const unsigned int bit = (block % GFS2_NBBY) * GFS2_BIT_SIZE;
+       unsigned int buflen = rbm->bi->bi_len;
+       const unsigned int bit = (rbm->offset % GFS2_NBBY) * GFS2_BIT_SIZE;
 
-       byte1 = bi->bi_bh->b_data + bi->bi_offset + (block / GFS2_NBBY);
-       end = bi->bi_bh->b_data + bi->bi_offset + buflen;
+       byte1 = rbm->bi->bi_bh->b_data + rbm->bi->bi_offset + (rbm->offset / GFS2_NBBY);
+       end = rbm->bi->bi_bh->b_data + rbm->bi->bi_offset + buflen;
 
        BUG_ON(byte1 >= end);
 
        cur_state = (*byte1 >> bit) & GFS2_BIT_MASK;
 
        if (unlikely(!valid_change[new_state * 4 + cur_state])) {
-               printk(KERN_WARNING "GFS2: buf_blk = 0x%llx old_state=%d, "
-                      "new_state=%d\n",
-                      (unsigned long long)block, cur_state, new_state);
-               printk(KERN_WARNING "GFS2: rgrp=0x%llx bi_start=0x%lx\n",
-                      (unsigned long long)rgd->rd_addr,
-                      (unsigned long)bi->bi_start);
-               printk(KERN_WARNING "GFS2: bi_offset=0x%lx bi_len=0x%lx\n",
-                      (unsigned long)bi->bi_offset,
-                      (unsigned long)bi->bi_len);
+               printk(KERN_WARNING "GFS2: buf_blk = 0x%x old_state=%d, "
+                      "new_state=%d\n", rbm->offset, cur_state, new_state);
+               printk(KERN_WARNING "GFS2: rgrp=0x%llx bi_start=0x%x\n",
+                      (unsigned long long)rbm->rgd->rd_addr,
+                      rbm->bi->bi_start);
+               printk(KERN_WARNING "GFS2: bi_offset=0x%x bi_len=0x%x\n",
+                      rbm->bi->bi_offset, rbm->bi->bi_len);
                dump_stack();
-               gfs2_consist_rgrpd(rgd);
+               gfs2_consist_rgrpd(rbm->rgd);
                return;
        }
        *byte1 ^= (cur_state ^ new_state) << bit;
 
-       if (buf2) {
-               byte2 = buf2 + bi->bi_offset + (block / GFS2_NBBY);
+       if (do_clone && rbm->bi->bi_clone) {
+               byte2 = rbm->bi->bi_clone + rbm->bi->bi_offset + (rbm->offset / GFS2_NBBY);
                cur_state = (*byte2 >> bit) & GFS2_BIT_MASK;
                *byte2 ^= (cur_state ^ new_state) << bit;
        }
@@ -121,30 +112,21 @@ static inline void gfs2_setbit(struct gfs2_rgrpd *rgd, unsigned char *buf2,
 
 /**
  * gfs2_testbit - test a bit in the bitmaps
- * @rgd: the resource group descriptor
- * @buffer: the buffer that holds the bitmaps
- * @buflen: the length (in bytes) of the buffer
- * @block: the block to read
+ * @rbm: The bit to test
  *
+ * Returns: The two bit block state of the requested bit
  */
 
-static inline unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd,
-                                        const unsigned char *buffer,
-                                        unsigned int buflen, u32 block)
+static inline u8 gfs2_testbit(const struct gfs2_rbm *rbm)
 {
-       const unsigned char *byte, *end;
-       unsigned char cur_state;
+       const u8 *buffer = rbm->bi->bi_bh->b_data + rbm->bi->bi_offset;
+       const u8 *byte;
        unsigned int bit;
 
-       byte = buffer + (block / GFS2_NBBY);
-       bit = (block % GFS2_NBBY) * GFS2_BIT_SIZE;
-       end = buffer + buflen;
-
-       gfs2_assert(rgd->rd_sbd, byte < end);
-
-       cur_state = (*byte >> bit) & GFS2_BIT_MASK;
+       byte = buffer + (rbm->offset / GFS2_NBBY);
+       bit = (rbm->offset % GFS2_NBBY) * GFS2_BIT_SIZE;
 
-       return cur_state;
+       return (*byte >> bit) & GFS2_BIT_MASK;
 }
 
 /**
@@ -192,7 +174,7 @@ static inline u64 gfs2_bit_search(const __le64 *ptr, u64 mask, u8 state)
  */
 static inline int rs_cmp(u64 blk, u32 len, struct gfs2_blkreserv *rs)
 {
-       u64 startblk = gfs2_rs_startblk(rs);
+       u64 startblk = gfs2_rbm_to_block(&rs->rs_rbm);
 
        if (blk >= startblk + rs->rs_free)
                return 1;
@@ -201,36 +183,6 @@ static inline int rs_cmp(u64 blk, u32 len, struct gfs2_blkreserv *rs)
        return 0;
 }
 
-/**
- * rs_find - Find a rgrp multi-block reservation that contains a given block
- * @rgd: The rgrp
- * @rgblk: The block we're looking for, relative to the rgrp
- */
-static struct gfs2_blkreserv *rs_find(struct gfs2_rgrpd *rgd, u32 rgblk)
-{
-       struct rb_node **newn;
-       int rc;
-       u64 fsblk = rgblk + rgd->rd_data0;
-
-       spin_lock(&rgd->rd_rsspin);
-       newn = &rgd->rd_rstree.rb_node;
-       while (*newn) {
-               struct gfs2_blkreserv *cur =
-                       rb_entry(*newn, struct gfs2_blkreserv, rs_node);
-               rc = rs_cmp(fsblk, 1, cur);
-               if (rc < 0)
-                       newn = &((*newn)->rb_left);
-               else if (rc > 0)
-                       newn = &((*newn)->rb_right);
-               else {
-                       spin_unlock(&rgd->rd_rsspin);
-                       return cur;
-               }
-       }
-       spin_unlock(&rgd->rd_rsspin);
-       return NULL;
-}
-
 /**
  * gfs2_bitfit - Search an rgrp's bitmap buffer to find a bit-pair representing
  *       a block in a given allocation state.
@@ -262,8 +214,6 @@ static u32 gfs2_bitfit(const u8 *buf, const unsigned int len,
        u64 mask = 0x5555555555555555ULL;
        u32 bit;
 
-       BUG_ON(state > 3);
-
        /* Mask off bits we don't care about at the start of the search */
        mask <<= spoint;
        tmp = gfs2_bit_search(ptr, mask, state);
@@ -487,6 +437,8 @@ int gfs2_rs_alloc(struct gfs2_inode *ip)
        if (!res)
                error = -ENOMEM;
 
+       RB_CLEAR_NODE(&res->rs_node);
+
        down_write(&ip->i_rw_mutex);
        if (ip->i_res)
                kmem_cache_free(gfs2_rsrv_cachep, res);
@@ -499,8 +451,8 @@ int gfs2_rs_alloc(struct gfs2_inode *ip)
 static void dump_rs(struct seq_file *seq, struct gfs2_blkreserv *rs)
 {
        gfs2_print_dbg(seq, "  r: %llu s:%llu b:%u f:%u\n",
-                      rs->rs_rgd->rd_addr, gfs2_rs_startblk(rs), rs->rs_biblk,
-                      rs->rs_free);
+                      rs->rs_rbm.rgd->rd_addr, gfs2_rbm_to_block(&rs->rs_rbm),
+                      rs->rs_rbm.offset, rs->rs_free);
 }
 
 /**
@@ -508,41 +460,28 @@ static void dump_rs(struct seq_file *seq, struct gfs2_blkreserv *rs)
  * @rs: The reservation to remove
  *
  */
-static void __rs_deltree(struct gfs2_blkreserv *rs)
+static void __rs_deltree(struct gfs2_inode *ip, struct gfs2_blkreserv *rs)
 {
        struct gfs2_rgrpd *rgd;
 
        if (!gfs2_rs_active(rs))
                return;
 
-       rgd = rs->rs_rgd;
-       /* We can't do this: The reason is that when the rgrp is invalidated,
-          it's in the "middle" of acquiring the glock, but the HOLDER bit
-          isn't set yet:
-          BUG_ON(!gfs2_glock_is_locked_by_me(rs->rs_rgd->rd_gl));*/
-       trace_gfs2_rs(NULL, rs, TRACE_RS_TREEDEL);
-
-       if (!RB_EMPTY_ROOT(&rgd->rd_rstree))
-               rb_erase(&rs->rs_node, &rgd->rd_rstree);
+       rgd = rs->rs_rbm.rgd;
+       trace_gfs2_rs(ip, rs, TRACE_RS_TREEDEL);
+       rb_erase(&rs->rs_node, &rgd->rd_rstree);
+       RB_CLEAR_NODE(&rs->rs_node);
        BUG_ON(!rgd->rd_rs_cnt);
        rgd->rd_rs_cnt--;
 
        if (rs->rs_free) {
                /* return reserved blocks to the rgrp and the ip */
-               BUG_ON(rs->rs_rgd->rd_reserved < rs->rs_free);
-               rs->rs_rgd->rd_reserved -= rs->rs_free;
+               BUG_ON(rs->rs_rbm.rgd->rd_reserved < rs->rs_free);
+               rs->rs_rbm.rgd->rd_reserved -= rs->rs_free;
                rs->rs_free = 0;
-               clear_bit(GBF_FULL, &rs->rs_bi->bi_flags);
+               clear_bit(GBF_FULL, &rs->rs_rbm.bi->bi_flags);
                smp_mb__after_clear_bit();
        }
-       /* We can't change any of the step 1 or step 2 components of the rs.
-          E.g. We can't set rs_rgd to NULL because the rgd glock is held and
-          dequeued through this pointer.
-          Can't: atomic_set(&rs->rs_sizehint, 0);
-          Can't: rs->rs_requested = 0;
-          Can't: rs->rs_rgd = NULL;*/
-       rs->rs_bi = NULL;
-       rs->rs_biblk = 0;
 }
 
 /**
@@ -550,17 +489,16 @@ static void __rs_deltree(struct gfs2_blkreserv *rs)
  * @rs: The reservation to remove
  *
  */
-void gfs2_rs_deltree(struct gfs2_blkreserv *rs)
+void gfs2_rs_deltree(struct gfs2_inode *ip, struct gfs2_blkreserv *rs)
 {
        struct gfs2_rgrpd *rgd;
 
-       if (!gfs2_rs_active(rs))
-               return;
-
-       rgd = rs->rs_rgd;
-       spin_lock(&rgd->rd_rsspin);
-       __rs_deltree(rs);
-       spin_unlock(&rgd->rd_rsspin);
+       rgd = rs->rs_rbm.rgd;
+       if (rgd) {
+               spin_lock(&rgd->rd_rsspin);
+               __rs_deltree(ip, rs);
+               spin_unlock(&rgd->rd_rsspin);
+       }
 }
 
 /**
@@ -572,7 +510,7 @@ void gfs2_rs_delete(struct gfs2_inode *ip)
 {
        down_write(&ip->i_rw_mutex);
        if (ip->i_res) {
-               gfs2_rs_deltree(ip->i_res);
+               gfs2_rs_deltree(ip, ip->i_res);
                trace_gfs2_rs(ip, ip->i_res, TRACE_RS_DELETE);
                BUG_ON(ip->i_res->rs_free);
                kmem_cache_free(gfs2_rsrv_cachep, ip->i_res);
@@ -597,7 +535,7 @@ static void return_all_reservations(struct gfs2_rgrpd *rgd)
        spin_lock(&rgd->rd_rsspin);
        while ((n = rb_first(&rgd->rd_rstree))) {
                rs = rb_entry(n, struct gfs2_blkreserv, rs_node);
-               __rs_deltree(rs);
+               __rs_deltree(NULL, rs);
        }
        spin_unlock(&rgd->rd_rsspin);
 }
@@ -1285,7 +1223,7 @@ static struct gfs2_blkreserv *rs_insert(struct gfs2_bitmap *bi,
        struct rb_node **newn, *parent = NULL;
        int rc;
        struct gfs2_blkreserv *rs = ip->i_res;
-       struct gfs2_rgrpd *rgd = rs->rs_rgd;
+       struct gfs2_rgrpd *rgd = rs->rs_rbm.rgd;
        u64 fsblock = gfs2_bi2rgd_blk(bi, biblk) + rgd->rd_data0;
 
        spin_lock(&rgd->rd_rsspin);
@@ -1313,14 +1251,11 @@ static struct gfs2_blkreserv *rs_insert(struct gfs2_bitmap *bi,
        /* Do our reservation work */
        rs = ip->i_res;
        rs->rs_free = amount;
-       rs->rs_biblk = biblk;
-       rs->rs_bi = bi;
+       rs->rs_rbm.offset = biblk;
+       rs->rs_rbm.bi = bi;
        rb_link_node(&rs->rs_node, parent, newn);
        rb_insert_color(&rs->rs_node, &rgd->rd_rstree);
 
-       /* Do our inode accounting for the reservation */
-       /*BUG_ON(!gfs2_glock_is_locked_by_me(ip->i_gl));*/
-
        /* Do our rgrp accounting for the reservation */
        rgd->rd_reserved += amount; /* blocks reserved */
        rgd->rd_rs_cnt++; /* number of in-tree reservations */
@@ -1350,7 +1285,7 @@ static u32 unclaimed_blocks(struct gfs2_rgrpd *rgd)
  * Returns: 0 if successful or BFITNOENT if there isn't enough free space
  */
 
-static int rg_mblk_search(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip)
+static int rg_mblk_search(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip, unsigned requested)
 {
        struct gfs2_bitmap *bi = rgd->rd_bits;
        const u32 length = rgd->rd_length;
@@ -1422,8 +1357,7 @@ do_search:
                           what we can. If there's not enough, keep looking. */
                        if (nonzero == NULL)
                                rsv_bytes = search_bytes;
-                       else if ((nonzero - ptr) * GFS2_NBBY >=
-                                ip->i_res->rs_requested)
+                       else if ((nonzero - ptr) * GFS2_NBBY >= requested)
                                rsv_bytes = (nonzero - ptr);
 
                        if (rsv_bytes) {
@@ -1461,22 +1395,223 @@ skip:
  * Returns: 1 on success (it fits), 0 on failure (it doesn't fit)
  */
 
-static int try_rgrp_fit(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip)
+static int try_rgrp_fit(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip,
+                       unsigned requested)
 {
-       struct gfs2_blkreserv *rs = ip->i_res;
-
        if (rgd->rd_flags & (GFS2_RGF_NOALLOC | GFS2_RDF_ERROR))
                return 0;
        /* Look for a multi-block reservation. */
        if (unclaimed_blocks(rgd) >= RGRP_RSRV_MINBLKS &&
-           rg_mblk_search(rgd, ip) != BFITNOENT)
+           rg_mblk_search(rgd, ip, requested) != BFITNOENT)
                return 1;
-       if (unclaimed_blocks(rgd) >= rs->rs_requested)
+       if (unclaimed_blocks(rgd) >= requested)
                return 1;
 
        return 0;
 }
 
+/**
+ * gfs2_next_unreserved_block - Return next block that is not reserved
+ * @rgd: The resource group
+ * @block: The starting block
+ * @ip: Ignore any reservations for this inode
+ *
+ * If the block does not appear in any reservation, then return the
+ * block number unchanged. If it does appear in the reservation, then
+ * keep looking through the tree of reservations in order to find the
+ * first block number which is not reserved.
+ */
+
+static u64 gfs2_next_unreserved_block(struct gfs2_rgrpd *rgd, u64 block,
+                                     const struct gfs2_inode *ip)
+{
+       struct gfs2_blkreserv *rs;
+       struct rb_node *n;
+       int rc;
+
+       spin_lock(&rgd->rd_rsspin);
+       n = rb_first(&rgd->rd_rstree);
+       while (n) {
+               rs = rb_entry(n, struct gfs2_blkreserv, rs_node);
+               rc = rs_cmp(block, 1, rs);
+               if (rc < 0)
+                       n = n->rb_left;
+               else if (rc > 0)
+                       n = n->rb_right;
+               else
+                       break;
+       }
+
+       if (n) {
+               while ((rs_cmp(block, 1, rs) == 0) && (ip->i_res != rs)) {
+                       block = gfs2_rbm_to_block(&rs->rs_rbm) + rs->rs_free;
+                       n = rb_next(&rs->rs_node);
+                       if (n == NULL)
+                               break;
+                       rs = rb_entry(n, struct gfs2_blkreserv, rs_node);
+               }
+       }
+
+       spin_unlock(&rgd->rd_rsspin);
+       return block;
+}
+
+/**
+ * gfs2_rbm_from_block - Set the rbm based upon rgd and block number
+ * @rbm: The rbm with rgd already set correctly
+ * @block: The block number (filesystem relative)
+ *
+ * This sets the bi and offset members of an rbm based on a
+ * resource group and a filesystem relative block number. The
+ * resource group must be set in the rbm on entry, the bi and
+ * offset members will be set by this function.
+ *
+ * Returns: 0 on success, or an error code
+ */
+
+static int gfs2_rbm_from_block(struct gfs2_rbm *rbm, u64 block)
+{
+       u64 rblock = block - rbm->rgd->rd_data0;
+       u32 goal = (u32)rblock;
+       int x;
+
+       if (WARN_ON_ONCE(rblock > UINT_MAX))
+               return -EINVAL;
+       if (block >= rbm->rgd->rd_data0 + rbm->rgd->rd_data)
+               return -E2BIG;
+
+       for (x = 0; x < rbm->rgd->rd_length; x++) {
+               rbm->bi = rbm->rgd->rd_bits + x;
+               if (goal < (rbm->bi->bi_start + rbm->bi->bi_len) * GFS2_NBBY) {
+                       rbm->offset = goal - (rbm->bi->bi_start * GFS2_NBBY);
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+/**
+ * gfs2_reservation_check_and_update - Check for reservations during block alloc
+ * @rbm: The current position in the resource group
+ *
+ * This checks the current position in the rgrp to see whether there is
+ * a reservation covering this block. If not then this function is a
+ * no-op. If there is, then the position is moved to the end of the
+ * contiguous reservation(s) so that we are pointing at the first
+ * non-reserved block.
+ *
+ * Returns: 0 if no reservation, 1 if @rbm has changed, otherwise an error
+ */
+
+static int gfs2_reservation_check_and_update(struct gfs2_rbm *rbm,
+                                            const struct gfs2_inode *ip)
+{
+       u64 block = gfs2_rbm_to_block(rbm);
+       u64 nblock;
+       int ret;
+
+       nblock = gfs2_next_unreserved_block(rbm->rgd, block, ip);
+       if (nblock == block)
+               return 0;
+       ret = gfs2_rbm_from_block(rbm, nblock);
+       if (ret < 0)
+               return ret;
+       return 1;
+}
+
+/**
+ * gfs2_rbm_find - Look for blocks of a particular state
+ * @rbm: Value/result starting position and final position
+ * @state: The state which we want to find
+ * @ip: If set, check for reservations
+ * @nowrap: Stop looking at the end of the rgrp, rather than wrapping
+ *          around until we've reached the starting point.
+ *
+ * Side effects:
+ * - If looking for free blocks, we set GBF_FULL on each bitmap which
+ *   has no free blocks in it.
+ *
+ * Returns: 0 on success, -ENOSPC if there is no block of the requested state
+ */
+
+static int gfs2_rbm_find(struct gfs2_rbm *rbm, u8 state,
+                        const struct gfs2_inode *ip, bool nowrap)
+{
+       struct buffer_head *bh;
+       struct gfs2_bitmap *initial_bi;
+       u32 initial_offset;
+       u32 offset;
+       u8 *buffer;
+       int index;
+       int n = 0;
+       int iters = rbm->rgd->rd_length;
+       int ret;
+
+       /* If we are not starting at the beginning of a bitmap, then we
+        * need to add one to the bitmap count to ensure that we search
+        * the starting bitmap twice.
+        */
+       if (rbm->offset != 0)
+               iters++;
+
+       while(1) {
+               if (test_bit(GBF_FULL, &rbm->bi->bi_flags) &&
+                   (state == GFS2_BLKST_FREE))
+                       goto next_bitmap;
+
+               bh = rbm->bi->bi_bh;
+               buffer = bh->b_data + rbm->bi->bi_offset;
+               WARN_ON(!buffer_uptodate(bh));
+               if (state != GFS2_BLKST_UNLINKED && rbm->bi->bi_clone)
+                       buffer = rbm->bi->bi_clone + rbm->bi->bi_offset;
+               initial_offset = rbm->offset;
+               offset = gfs2_bitfit(buffer, rbm->bi->bi_len, rbm->offset, state);
+               if (offset == BFITNOENT)
+                       goto bitmap_full;
+               rbm->offset = offset;
+               if (ip == NULL)
+                       return 0;
+
+               initial_bi = rbm->bi;
+               ret = gfs2_reservation_check_and_update(rbm, ip);
+               if (ret == 0)
+                       return 0;
+               if (ret > 0) {
+                       n += (rbm->bi - initial_bi);
+                       goto next_iter;
+               }
+               if (ret == -E2BIG) {
+                       index = 0;
+                       rbm->offset = 0;
+                       n += (rbm->bi - initial_bi);
+                       goto res_covered_end_of_rgrp;
+               }
+               return ret;
+
+bitmap_full:   /* Mark bitmap as full and fall through */
+               if ((state == GFS2_BLKST_FREE) && initial_offset == 0)
+                       set_bit(GBF_FULL, &rbm->bi->bi_flags);
+
+next_bitmap:   /* Find next bitmap in the rgrp */
+               rbm->offset = 0;
+               index = rbm->bi - rbm->rgd->rd_bits;
+               index++;
+               if (index == rbm->rgd->rd_length)
+                       index = 0;
+res_covered_end_of_rgrp:
+               rbm->bi = &rbm->rgd->rd_bits[index];
+               if ((index == 0) && nowrap)
+                       break;
+               n++;
+next_iter:
+               if (n >= iters)
+                       break;
+       }
+
+       return -ENOSPC;
+}
+
 /**
  * try_rgrp_unlink - Look for any unlinked, allocated, but unused inodes
  * @rgd: The rgrp
@@ -1489,34 +1624,33 @@ static int try_rgrp_fit(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip)
 
 static void try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked, u64 skip)
 {
-       u32 goal = 0, block;
-       u64 no_addr;
+       u64 block;
        struct gfs2_sbd *sdp = rgd->rd_sbd;
        struct gfs2_glock *gl;
        struct gfs2_inode *ip;
        int error;
        int found = 0;
-       struct gfs2_bitmap *bi;
+       struct gfs2_rbm rbm = { .rgd = rgd, .bi = rgd->rd_bits, .offset = 0 };
 
-       while (goal < rgd->rd_data) {
+       while (1) {
                down_write(&sdp->sd_log_flush_lock);
-               block = rgblk_search(rgd, goal, GFS2_BLKST_UNLINKED, &bi);
+               error = gfs2_rbm_find(&rbm, GFS2_BLKST_UNLINKED, NULL, true);
                up_write(&sdp->sd_log_flush_lock);
-               if (block == BFITNOENT)
+               if (error == -ENOSPC)
+                       break;
+               if (WARN_ON_ONCE(error))
                        break;
 
-               block = gfs2_bi2rgd_blk(bi, block);
-               /* rgblk_search can return a block < goal, so we need to
-                  keep it marching forward. */
-               no_addr = block + rgd->rd_data0;
-               goal = max(block + 1, goal + 1);
-               if (*last_unlinked != NO_BLOCK && no_addr <= *last_unlinked)
+               block = gfs2_rbm_to_block(&rbm);
+               if (gfs2_rbm_from_block(&rbm, block + 1))
+                       break;
+               if (*last_unlinked != NO_BLOCK && block <= *last_unlinked)
                        continue;
-               if (no_addr == skip)
+               if (block == skip)
                        continue;
-               *last_unlinked = no_addr;
+               *last_unlinked = block;
 
-               error = gfs2_glock_get(sdp, no_addr, &gfs2_inode_glops, CREATE, &gl);
+               error = gfs2_glock_get(sdp, block, &gfs2_inode_glops, CREATE, &gl);
                if (error)
                        continue;
 
@@ -1562,40 +1696,39 @@ int gfs2_inplace_reserve(struct gfs2_inode *ip, u32 requested)
 
        if (sdp->sd_args.ar_rgrplvb)
                flags |= GL_SKIP;
-       rs->rs_requested = requested;
        if (gfs2_assert_warn(sdp, requested)) {
                error = -EINVAL;
                goto out;
        }
        if (gfs2_rs_active(rs)) {
-               begin = rs->rs_rgd;
+               begin = rs->rs_rbm.rgd;
                flags = 0; /* Yoda: Do or do not. There is no try */
        } else if (ip->i_rgd && rgrp_contains_block(ip->i_rgd, ip->i_goal)) {
-               rs->rs_rgd = begin = ip->i_rgd;
+               rs->rs_rbm.rgd = begin = ip->i_rgd;
        } else {
-               rs->rs_rgd = begin = gfs2_blk2rgrpd(sdp, ip->i_goal, 1);
+               rs->rs_rbm.rgd = begin = gfs2_blk2rgrpd(sdp, ip->i_goal, 1);
        }
-       if (rs->rs_rgd == NULL)
+       if (rs->rs_rbm.rgd == NULL)
                return -EBADSLT;
 
        while (loops < 3) {
                rg_locked = 0;
 
-               if (gfs2_glock_is_locked_by_me(rs->rs_rgd->rd_gl)) {
+               if (gfs2_glock_is_locked_by_me(rs->rs_rbm.rgd->rd_gl)) {
                        rg_locked = 1;
                        error = 0;
                } else if (!loops && !gfs2_rs_active(rs) &&
-                          rs->rs_rgd->rd_rs_cnt > RGRP_RSRV_MAX_CONTENDERS) {
+                          rs->rs_rbm.rgd->rd_rs_cnt > RGRP_RSRV_MAX_CONTENDERS) {
                        /* If the rgrp already is maxed out for contenders,
                           we can eliminate it as a "first pass" without even
                           requesting the rgrp glock. */
                        error = GLR_TRYFAILED;
                } else {
-                       error = gfs2_glock_nq_init(rs->rs_rgd->rd_gl,
+                       error = gfs2_glock_nq_init(rs->rs_rbm.rgd->rd_gl,
                                                   LM_ST_EXCLUSIVE, flags,
                                                   &rs->rs_rgd_gh);
                        if (!error && sdp->sd_args.ar_rgrplvb) {
-                               error = update_rgrp_lvb(rs->rs_rgd);
+                               error = update_rgrp_lvb(rs->rs_rbm.rgd);
                                if (error) {
                                        gfs2_glock_dq_uninit(&rs->rs_rgd_gh);
                                        return error;
@@ -1605,36 +1738,36 @@ int gfs2_inplace_reserve(struct gfs2_inode *ip, u32 requested)
                switch (error) {
                case 0:
                        if (gfs2_rs_active(rs)) {
-                               if (unclaimed_blocks(rs->rs_rgd) +
-                                   rs->rs_free >= rs->rs_requested) {
-                                       ip->i_rgd = rs->rs_rgd;
+                               if (unclaimed_blocks(rs->rs_rbm.rgd) +
+                                   rs->rs_free >= requested) {
+                                       ip->i_rgd = rs->rs_rbm.rgd;
                                        return 0;
                                }
                                /* We have a multi-block reservation, but the
                                   rgrp doesn't have enough free blocks to
                                   satisfy the request. Free the reservation
                                   and look for a suitable rgrp. */
-                               gfs2_rs_deltree(rs);
+                               gfs2_rs_deltree(ip, rs);
                        }
-                       if (try_rgrp_fit(rs->rs_rgd, ip)) {
+                       if (try_rgrp_fit(rs->rs_rbm.rgd, ip, requested)) {
                                if (sdp->sd_args.ar_rgrplvb)
-                                       gfs2_rgrp_bh_get(rs->rs_rgd);
-                               ip->i_rgd = rs->rs_rgd;
+                                       gfs2_rgrp_bh_get(rs->rs_rbm.rgd);
+                               ip->i_rgd = rs->rs_rbm.rgd;
                                return 0;
                        }
-                       if (rs->rs_rgd->rd_flags & GFS2_RDF_CHECK) {
+                       if (rs->rs_rbm.rgd->rd_flags & GFS2_RDF_CHECK) {
                                if (sdp->sd_args.ar_rgrplvb)
-                                       gfs2_rgrp_bh_get(rs->rs_rgd);
-                               try_rgrp_unlink(rs->rs_rgd, &last_unlinked,
+                                       gfs2_rgrp_bh_get(rs->rs_rbm.rgd);
+                               try_rgrp_unlink(rs->rs_rbm.rgd, &last_unlinked,
                                                ip->i_no_addr);
                        }
                        if (!rg_locked)
                                gfs2_glock_dq_uninit(&rs->rs_rgd_gh);
                        /* fall through */
                case GLR_TRYFAILED:
-                       rs->rs_rgd = gfs2_rgrpd_get_next(rs->rs_rgd);
-                       rs->rs_rgd = rs->rs_rgd ? : begin; /* if NULL, wrap */
-                       if (rs->rs_rgd != begin) /* If we didn't wrap */
+                       rs->rs_rbm.rgd = gfs2_rgrpd_get_next(rs->rs_rbm.rgd);
+                       rs->rs_rbm.rgd = rs->rs_rbm.rgd ? : begin; /* if NULL, wrap */
+                       if (rs->rs_rbm.rgd != begin) /* If we didn't wrap */
                                break;
 
                        flags &= ~LM_FLAG_TRY;
@@ -1656,8 +1789,6 @@ int gfs2_inplace_reserve(struct gfs2_inode *ip, u32 requested)
        error = -ENOSPC;
 
 out:
-       if (error)
-               rs->rs_requested = 0;
        return error;
 }
 
@@ -1672,15 +1803,8 @@ void gfs2_inplace_release(struct gfs2_inode *ip)
 {
        struct gfs2_blkreserv *rs = ip->i_res;
 
-       if (!rs)
-               return;
-
-       if (!rs->rs_free)
-               gfs2_rs_deltree(rs);
-
        if (rs->rs_rgd_gh.gh_gl)
                gfs2_glock_dq_uninit(&rs->rs_rgd_gh);
-       rs->rs_requested = 0;
 }
 
 /**
@@ -1693,173 +1817,48 @@ void gfs2_inplace_release(struct gfs2_inode *ip)
 
 static unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block)
 {
-       struct gfs2_bitmap *bi = NULL;
-       u32 length, rgrp_block, buf_block;
-       unsigned int buf;
-       unsigned char type;
+       struct gfs2_rbm rbm = { .rgd = rgd, };
+       int ret;
 
-       length = rgd->rd_length;
-       rgrp_block = block - rgd->rd_data0;
+       ret = gfs2_rbm_from_block(&rbm, block);
+       WARN_ON_ONCE(ret != 0);
 
-       for (buf = 0; buf < length; buf++) {
-               bi = rgd->rd_bits + buf;
-               if (rgrp_block < (bi->bi_start + bi->bi_len) * GFS2_NBBY)
-                       break;
-       }
-
-       gfs2_assert(rgd->rd_sbd, buf < length);
-       buf_block = rgrp_block - bi->bi_start * GFS2_NBBY;
-
-       type = gfs2_testbit(rgd, bi->bi_bh->b_data + bi->bi_offset,
-                          bi->bi_len, buf_block);
-
-       return type;
+       return gfs2_testbit(&rbm);
 }
 
-/**
- * rgblk_search - find a block in @state
- * @rgd: the resource group descriptor
- * @goal: the goal block within the RG (start here to search for avail block)
- * @state: GFS2_BLKST_XXX the before-allocation state to find
- * @rbi: address of the pointer to the bitmap containing the block found
- *
- * Walk rgrp's bitmap to find bits that represent a block in @state.
- *
- * This function never fails, because we wouldn't call it unless we
- * know (from reservation results, etc.) that a block is available.
- *
- * Scope of @goal is just within rgrp, not the whole filesystem.
- * Scope of @returned block is just within bitmap, not the whole filesystem.
- *
- * Returns: the block number found relative to the bitmap rbi
- */
-
-static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal, unsigned char state,
-                       struct gfs2_bitmap **rbi)
-{
-       struct gfs2_bitmap *bi = NULL;
-       const u32 length = rgd->rd_length;
-       u32 biblk = BFITNOENT;
-       unsigned int buf, x;
-       const u8 *buffer = NULL;
-
-       *rbi = NULL;
-       /* Find bitmap block that contains bits for goal block */
-       for (buf = 0; buf < length; buf++) {
-               bi = rgd->rd_bits + buf;
-               /* Convert scope of "goal" from rgrp-wide to within found bit block */
-               if (goal < (bi->bi_start + bi->bi_len) * GFS2_NBBY) {
-                       goal -= bi->bi_start * GFS2_NBBY;
-                       goto do_search;
-               }
-       }
-       buf = 0;
-       goal = 0;
-
-do_search:
-       /* Search (up to entire) bitmap in this rgrp for allocatable block.
-          "x <= length", instead of "x < length", because we typically start
-          the search in the middle of a bit block, but if we can't find an
-          allocatable block anywhere else, we want to be able wrap around and
-          search in the first part of our first-searched bit block.  */
-       for (x = 0; x <= length; x++) {
-               bi = rgd->rd_bits + buf;
-
-               if (test_bit(GBF_FULL, &bi->bi_flags) &&
-                   (state == GFS2_BLKST_FREE))
-                       goto skip;
-
-               /* The GFS2_BLKST_UNLINKED state doesn't apply to the clone
-                  bitmaps, so we must search the originals for that. */
-               buffer = bi->bi_bh->b_data + bi->bi_offset;
-               WARN_ON(!buffer_uptodate(bi->bi_bh));
-               if (state != GFS2_BLKST_UNLINKED && bi->bi_clone)
-                       buffer = bi->bi_clone + bi->bi_offset;
-
-               while (1) {
-                       struct gfs2_blkreserv *rs;
-                       u32 rgblk;
-
-                       biblk = gfs2_bitfit(buffer, bi->bi_len, goal, state);
-                       if (biblk == BFITNOENT)
-                               break;
-                       /* Check if this block is reserved() */
-                       rgblk = gfs2_bi2rgd_blk(bi, biblk);
-                       rs = rs_find(rgd, rgblk);
-                       if (rs == NULL)
-                               break;
-
-                       BUG_ON(rs->rs_bi != bi);
-                       biblk = BFITNOENT;
-                       /* This should jump to the first block after the
-                          reservation. */
-                       goal = rs->rs_biblk + rs->rs_free;
-                       if (goal >= bi->bi_len * GFS2_NBBY)
-                               break;
-               }
-               if (biblk != BFITNOENT)
-                       break;
-
-               if ((goal == 0) && (state == GFS2_BLKST_FREE))
-                       set_bit(GBF_FULL, &bi->bi_flags);
-
-               /* Try next bitmap block (wrap back to rgrp header if at end) */
-skip:
-               buf++;
-               buf %= length;
-               goal = 0;
-       }
-
-       if (biblk != BFITNOENT)
-               *rbi = bi;
-
-       return biblk;
-}
 
 /**
  * gfs2_alloc_extent - allocate an extent from a given bitmap
- * @rgd: the resource group descriptor
- * @bi: the bitmap within the rgrp
- * @blk: the block within the bitmap
+ * @rbm: the resource group information
  * @dinode: TRUE if the first block we allocate is for a dinode
- * @n: The extent length
+ * @n: The extent length (value/result)
  *
- * Add the found bitmap buffer to the transaction.
+ * Add the bitmap buffer to the transaction.
  * Set the found bits to @new_state to change block's allocation state.
- * Returns: starting block number of the extent (fs scope)
  */
-static u64 gfs2_alloc_extent(struct gfs2_rgrpd *rgd, struct gfs2_bitmap *bi,
-                            u32 blk, bool dinode, unsigned int *n)
+static void gfs2_alloc_extent(const struct gfs2_rbm *rbm, bool dinode,
+                            unsigned int *n)
 {
+       struct gfs2_rbm pos = { .rgd = rbm->rgd, };
        const unsigned int elen = *n;
-       u32 goal, rgblk;
-       const u8 *buffer = NULL;
-       struct gfs2_blkreserv *rs;
-
-       *n = 0;
-       buffer = bi->bi_bh->b_data + bi->bi_offset;
-       gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1);
-       gfs2_setbit(rgd, bi->bi_clone, bi, blk,
-                   dinode ? GFS2_BLKST_DINODE : GFS2_BLKST_USED);
-       (*n)++;
-       goal = blk;
+       u64 block;
+       int ret;
+
+       *n = 1;
+       block = gfs2_rbm_to_block(rbm);
+       gfs2_trans_add_bh(rbm->rgd->rd_gl, rbm->bi->bi_bh, 1);
+       gfs2_setbit(rbm, true, dinode ? GFS2_BLKST_DINODE : GFS2_BLKST_USED);
+       block++;
        while (*n < elen) {
-               goal++;
-               if (goal >= (bi->bi_len * GFS2_NBBY))
-                       break;
-               rgblk = gfs2_bi2rgd_blk(bi, goal);
-               rs = rs_find(rgd, rgblk);
-               if (rs) /* Oops, we bumped into someone's reservation */
+               ret = gfs2_rbm_from_block(&pos, block);
+               WARN_ON(ret);
+               if (gfs2_testbit(&pos) != GFS2_BLKST_FREE)
                        break;
-               if (gfs2_testbit(rgd, buffer, bi->bi_len, goal) !=
-                   GFS2_BLKST_FREE)
-                       break;
-               gfs2_setbit(rgd, bi->bi_clone, bi, goal, GFS2_BLKST_USED);
+               gfs2_trans_add_bh(pos.rgd->rd_gl, pos.bi->bi_bh, 1);
+               gfs2_setbit(&pos, true, GFS2_BLKST_USED);
                (*n)++;
+               block++;
        }
-       blk = gfs2_bi2rgd_blk(bi, blk);
-       rgd->rd_last_alloc = blk + *n - 1;
-       return rgd->rd_data0 + blk;
 }
 
 /**
@@ -1875,46 +1874,30 @@ static u64 gfs2_alloc_extent(struct gfs2_rgrpd *rgd, struct gfs2_bitmap *bi,
 static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, u64 bstart,
                                     u32 blen, unsigned char new_state)
 {
-       struct gfs2_rgrpd *rgd;
-       struct gfs2_bitmap *bi = NULL;
-       u32 length, rgrp_blk, buf_blk;
-       unsigned int buf;
+       struct gfs2_rbm rbm;
 
-       rgd = gfs2_blk2rgrpd(sdp, bstart, 1);
-       if (!rgd) {
+       rbm.rgd = gfs2_blk2rgrpd(sdp, bstart, 1);
+       if (!rbm.rgd) {
                if (gfs2_consist(sdp))
                        fs_err(sdp, "block = %llu\n", (unsigned long long)bstart);
                return NULL;
        }
 
-       length = rgd->rd_length;
-
-       rgrp_blk = bstart - rgd->rd_data0;
-
        while (blen--) {
-               for (buf = 0; buf < length; buf++) {
-                       bi = rgd->rd_bits + buf;
-                       if (rgrp_blk < (bi->bi_start + bi->bi_len) * GFS2_NBBY)
-                               break;
+               gfs2_rbm_from_block(&rbm, bstart);
+               bstart++;
+               if (!rbm.bi->bi_clone) {
+                       rbm.bi->bi_clone = kmalloc(rbm.bi->bi_bh->b_size,
+                                                  GFP_NOFS | __GFP_NOFAIL);
+                       memcpy(rbm.bi->bi_clone + rbm.bi->bi_offset,
+                              rbm.bi->bi_bh->b_data + rbm.bi->bi_offset,
+                              rbm.bi->bi_len);
                }
-
-               gfs2_assert(rgd->rd_sbd, buf < length);
-
-               buf_blk = rgrp_blk - bi->bi_start * GFS2_NBBY;
-               rgrp_blk++;
-
-               if (!bi->bi_clone) {
-                       bi->bi_clone = kmalloc(bi->bi_bh->b_size,
-                                              GFP_NOFS | __GFP_NOFAIL);
-                       memcpy(bi->bi_clone + bi->bi_offset,
-                              bi->bi_bh->b_data + bi->bi_offset,
-                              bi->bi_len);
-               }
-               gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1);
-               gfs2_setbit(rgd, NULL, bi, buf_blk, new_state);
+               gfs2_trans_add_bh(rbm.rgd->rd_gl, rbm.bi->bi_bh, 1);
+               gfs2_setbit(&rbm, false, new_state);
        }
 
-       return rgd;
+       return rbm.rgd;
 }
 
 /**
@@ -1956,56 +1939,41 @@ static void gfs2_rgrp_error(struct gfs2_rgrpd *rgd)
 }
 
 /**
- * claim_reserved_blks - Claim previously reserved blocks
- * @ip: the inode that's claiming the reservation
- * @dinode: 1 if this block is a dinode block, otherwise data block
- * @nblocks: desired extent length
+ * gfs2_adjust_reservation - Adjust (or remove) a reservation after allocation
+ * @ip: The inode we have just allocated blocks for
+ * @rbm: The start of the allocated blocks
+ * @len: The extent length
  *
- * Lay claim to previously allocated block reservation blocks.
- * Returns: Starting block number of the blocks claimed.
- * Sets *nblocks to the actual extent length allocated.
+ * Adjusts a reservation after an allocation has taken place. If the
+ * reservation does not match the allocation, or if it is now empty
+ * then it is removed.
  */
-static u64 claim_reserved_blks(struct gfs2_inode *ip, bool dinode,
-                              unsigned int *nblocks)
+
+static void gfs2_adjust_reservation(struct gfs2_inode *ip,
+                                   const struct gfs2_rbm *rbm, unsigned len)
 {
        struct gfs2_blkreserv *rs = ip->i_res;
-       struct gfs2_rgrpd *rgd = rs->rs_rgd;
-       struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
-       struct gfs2_bitmap *bi;
-       u64 start_block = gfs2_rs_startblk(rs);
-       const unsigned int elen = *nblocks;
-
-       /*BUG_ON(!gfs2_glock_is_locked_by_me(ip->i_gl));*/
-       gfs2_assert_withdraw(sdp, rgd);
-       /*BUG_ON(!gfs2_glock_is_locked_by_me(rgd->rd_gl));*/
-       bi = rs->rs_bi;
-       gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1);
-
-       for (*nblocks = 0; *nblocks < elen && rs->rs_free; (*nblocks)++) {
-               /* Make sure the bitmap hasn't changed */
-               gfs2_setbit(rgd, bi->bi_clone, bi, rs->rs_biblk,
-                           dinode ? GFS2_BLKST_DINODE : GFS2_BLKST_USED);
-               rs->rs_biblk++;
-               rs->rs_free--;
-
-               BUG_ON(!rgd->rd_reserved);
-               rgd->rd_reserved--;
-               dinode = false;
-               trace_gfs2_rs(ip, rs, TRACE_RS_CLAIM);
-       }
-
-       if (!rs->rs_free) {
-               struct gfs2_rgrpd *rgd = ip->i_res->rs_rgd;
+       struct gfs2_rgrpd *rgd = rbm->rgd;
+       unsigned rlen;
+       u64 block;
+       int ret;
 
-               gfs2_rs_deltree(rs);
-               /* -nblocks because we haven't returned to do the math yet.
-                  I'm doing the math backwards to prevent negative numbers,
-                  but think of it as:
-                  if (unclaimed_blocks(rgd) - *nblocks >= RGRP_RSRV_MINBLKS */
-               if (unclaimed_blocks(rgd) >= RGRP_RSRV_MINBLKS + *nblocks)
-                       rg_mblk_search(rgd, ip);
+       spin_lock(&rgd->rd_rsspin);
+       if (gfs2_rs_active(rs)) {
+               if (gfs2_rbm_eq(&rs->rs_rbm, rbm)) {
+                       block = gfs2_rbm_to_block(rbm);
+                       ret = gfs2_rbm_from_block(&rs->rs_rbm, block + len);
+                       rlen = min(rs->rs_free, len);
+                       rs->rs_free -= rlen;
+                       rgd->rd_reserved -= rlen;
+                       trace_gfs2_rs(ip, rs, TRACE_RS_CLAIM);
+                       if (rs->rs_free && !ret)
+                               goto out;
+               }
+               __rs_deltree(ip, rs);
        }
-       return start_block;
+out:
+       spin_unlock(&rgd->rd_rsspin);
 }
 
 /**
@@ -2024,47 +1992,37 @@ int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *nblocks,
 {
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
        struct buffer_head *dibh;
-       struct gfs2_rgrpd *rgd;
+       struct gfs2_rbm rbm = { .rgd = ip->i_rgd, };
        unsigned int ndata;
-       u32 goal, blk; /* block, within the rgrp scope */
+       u64 goal;
        u64 block; /* block, within the file system scope */
        int error;
-       struct gfs2_bitmap *bi;
 
-       /* Only happens if there is a bug in gfs2, return something distinctive
-        * to ensure that it is noticed.
-        */
-       if (ip->i_res->rs_requested == 0)
-               return -ECANCELED;
-
-       /* Check if we have a multi-block reservation, and if so, claim the
-          next free block from it. */
-       if (gfs2_rs_active(ip->i_res)) {
-               BUG_ON(!ip->i_res->rs_free);
-               rgd = ip->i_res->rs_rgd;
-               block = claim_reserved_blks(ip, dinode, nblocks);
-       } else {
-               rgd = ip->i_rgd;
+       if (gfs2_rs_active(ip->i_res))
+               goal = gfs2_rbm_to_block(&ip->i_res->rs_rbm);
+       else if (!dinode && rgrp_contains_block(rbm.rgd, ip->i_goal))
+               goal = ip->i_goal;
+       else
+               goal = rbm.rgd->rd_last_alloc + rbm.rgd->rd_data0;
 
-               if (!dinode && rgrp_contains_block(rgd, ip->i_goal))
-                       goal = ip->i_goal - rgd->rd_data0;
-               else
-                       goal = rgd->rd_last_alloc;
-
-               blk = rgblk_search(rgd, goal, GFS2_BLKST_FREE, &bi);
-
-               /* Since all blocks are reserved in advance, this shouldn't
-                  happen */
-               if (blk == BFITNOENT) {
-                       printk(KERN_WARNING "BFITNOENT, nblocks=%u\n",
-                              *nblocks);
-                       printk(KERN_WARNING "FULL=%d\n",
-                              test_bit(GBF_FULL, &rgd->rd_bits->bi_flags));
-                       goto rgrp_error;
-               }
+       if ((goal < rbm.rgd->rd_data0) ||
+           (goal >= rbm.rgd->rd_data0 + rbm.rgd->rd_data))
+               rbm.rgd = gfs2_blk2rgrpd(sdp, goal, 1);
+
+       gfs2_rbm_from_block(&rbm, goal);
+       error = gfs2_rbm_find(&rbm, GFS2_BLKST_FREE, ip, false);
 
-               block = gfs2_alloc_extent(rgd, bi, blk, dinode, nblocks);
+       /* Since all blocks are reserved in advance, this shouldn't happen */
+       if (error) {
+               fs_warn(sdp, "error=%d, nblocks=%u, full=%d\n", error, *nblocks,
+                       test_bit(GBF_FULL, &rbm.rgd->rd_bits->bi_flags));
+               goto rgrp_error;
        }
+
+       gfs2_alloc_extent(&rbm, dinode, nblocks);
+       block = gfs2_rbm_to_block(&rbm);
+       if (gfs2_rs_active(ip->i_res))
+               gfs2_adjust_reservation(ip, &rbm, *nblocks);
        ndata = *nblocks;
        if (dinode)
                ndata--;
@@ -2081,22 +2039,22 @@ int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *nblocks,
                        brelse(dibh);
                }
        }
-       if (rgd->rd_free < *nblocks) {
+       if (rbm.rgd->rd_free < *nblocks) {
                printk(KERN_WARNING "nblocks=%u\n", *nblocks);
                goto rgrp_error;
        }
 
-       rgd->rd_free -= *nblocks;
+       rbm.rgd->rd_free -= *nblocks;
        if (dinode) {
-               rgd->rd_dinodes++;
-               *generation = rgd->rd_igeneration++;
+               rbm.rgd->rd_dinodes++;
+               *generation = rbm.rgd->rd_igeneration++;
                if (*generation == 0)
-                       *generation = rgd->rd_igeneration++;
+                       *generation = rbm.rgd->rd_igeneration++;
        }
 
-       gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
-       gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data);
-       gfs2_rgrp_ondisk2lvb(rgd->rd_rgl, rgd->rd_bits[0].bi_bh->b_data);
+       gfs2_trans_add_bh(rbm.rgd->rd_gl, rbm.rgd->rd_bits[0].bi_bh, 1);
+       gfs2_rgrp_out(rbm.rgd, rbm.rgd->rd_bits[0].bi_bh->b_data);
+       gfs2_rgrp_ondisk2lvb(rbm.rgd->rd_rgl, rbm.rgd->rd_bits[0].bi_bh->b_data);
 
        gfs2_statfs_change(sdp, 0, -(s64)*nblocks, dinode ? 1 : 0);
        if (dinode)
@@ -2110,14 +2068,14 @@ int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *nblocks,
                gfs2_quota_change(ip, ndata, ip->i_inode.i_uid,
                                  ip->i_inode.i_gid);
 
-       rgd->rd_free_clone -= *nblocks;
-       trace_gfs2_block_alloc(ip, rgd, block, *nblocks,
+       rbm.rgd->rd_free_clone -= *nblocks;
+       trace_gfs2_block_alloc(ip, rbm.rgd, block, *nblocks,
                               dinode ? GFS2_BLKST_DINODE : GFS2_BLKST_USED);
        *bn = block;
        return 0;
 
 rgrp_error:
-       gfs2_rgrp_error(rgd);
+       gfs2_rgrp_error(rbm.rgd);
        return -EIO;
 }
 
index ca6e26729b867ee0f458e1acae042034e2a703dc..c98f6af07e1c515edcad187394086de2580b68a2 100644 (file)
@@ -46,7 +46,7 @@ extern int gfs2_alloc_blocks(struct gfs2_inode *ip, u64 *bn, unsigned int *n,
                             bool dinode, u64 *generation);
 
 extern int gfs2_rs_alloc(struct gfs2_inode *ip);
-extern void gfs2_rs_deltree(struct gfs2_blkreserv *rs);
+extern void gfs2_rs_deltree(struct gfs2_inode *ip, struct gfs2_blkreserv *rs);
 extern void gfs2_rs_delete(struct gfs2_inode *ip);
 extern void __gfs2_free_blocks(struct gfs2_inode *ip, u64 bstart, u32 blen, int meta);
 extern void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen);
@@ -73,30 +73,16 @@ extern int gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset,
                                   const struct gfs2_bitmap *bi, unsigned minlen, u64 *ptrimmed);
 extern int gfs2_fitrim(struct file *filp, void __user *argp);
 
-/* This is how to tell if a multi-block reservation is "inplace" reserved: */
-static inline int gfs2_mb_reserved(struct gfs2_inode *ip)
+/* This is how to tell if a reservation is in the rgrp tree: */
+static inline bool gfs2_rs_active(struct gfs2_blkreserv *rs)
 {
-       if (ip->i_res && ip->i_res->rs_requested)
-               return 1;
-       return 0;
+       return rs && !RB_EMPTY_NODE(&rs->rs_node);
 }
 
-/* This is how to tell if a multi-block reservation is in the rgrp tree: */
-static inline int gfs2_rs_active(struct gfs2_blkreserv *rs)
-{
-       if (rs && rs->rs_bi)
-               return 1;
-       return 0;
-}
 
 static inline u32 gfs2_bi2rgd_blk(const struct gfs2_bitmap *bi, u32 blk)
 {
        return (bi->bi_start * GFS2_NBBY) + blk;
 }
 
-static inline u64 gfs2_rs_startblk(const struct gfs2_blkreserv *rs)
-{
-       return gfs2_bi2rgd_blk(rs->rs_bi, rs->rs_biblk) + rs->rs_rgd->rd_data0;
-}
-
 #endif /* __RGRP_DOT_H__ */
index fc3168f47a146a978b733a2dd106aaf50706aeb7..3cbac68030386cf53e8057cbdf59a843d71a80ba 100644 (file)
@@ -1557,7 +1557,7 @@ out_truncate:
 out_unlock:
        /* Error path for case 1 */
        if (gfs2_rs_active(ip->i_res))
-               gfs2_rs_deltree(ip->i_res);
+               gfs2_rs_deltree(ip, ip->i_res);
 
        if (test_bit(HIF_HOLDER, &ip->i_iopen_gh.gh_iflags))
                gfs2_glock_dq(&ip->i_iopen_gh);
index a25c252fe412a9ebe7ad239b67bb9ba41c459e29..b947aa4dfca4bdc6f0f0e683e98f8e86599425d5 100644 (file)
@@ -526,12 +526,12 @@ TRACE_EVENT(gfs2_rs,
        ),
 
        TP_fast_assign(
-               __entry->dev            = rs->rs_rgd ? rs->rs_rgd->rd_sbd->sd_vfs->s_dev : 0;
-               __entry->rd_addr        = rs->rs_rgd ? rs->rs_rgd->rd_addr : 0;
-               __entry->rd_free_clone  = rs->rs_rgd ? rs->rs_rgd->rd_free_clone : 0;
-               __entry->rd_reserved    = rs->rs_rgd ? rs->rs_rgd->rd_reserved : 0;
+               __entry->dev            = rs->rs_rbm.rgd ? rs->rs_rbm.rgd->rd_sbd->sd_vfs->s_dev : 0;
+               __entry->rd_addr        = rs->rs_rbm.rgd ? rs->rs_rbm.rgd->rd_addr : 0;
+               __entry->rd_free_clone  = rs->rs_rbm.rgd ? rs->rs_rbm.rgd->rd_free_clone : 0;
+               __entry->rd_reserved    = rs->rs_rbm.rgd ? rs->rs_rbm.rgd->rd_reserved : 0;
                __entry->inum           = ip ? ip->i_no_addr : 0;
-               __entry->start          = gfs2_rs_startblk(rs);
+               __entry->start          = gfs2_rbm_to_block(&rs->rs_rbm);
                __entry->free           = rs->rs_free;
                __entry->func           = func;
        ),
index 41f42cdccbb8e5bb3669bc36a159bcc5f6492e90..bf2ae9aeee7ab1208f42cea980e382fa5d183b7f 100644 (file)
@@ -28,11 +28,10 @@ struct gfs2_glock;
 
 /* reserve either the number of blocks to be allocated plus the rg header
  * block, or all of the blocks in the rg, whichever is smaller */
-static inline unsigned int gfs2_rg_blocks(const struct gfs2_inode *ip)
+static inline unsigned int gfs2_rg_blocks(const struct gfs2_inode *ip, unsigned requested)
 {
-       const struct gfs2_blkreserv *rs = ip->i_res;
-       if (rs && rs->rs_requested < ip->i_rgd->rd_length)
-               return rs->rs_requested + 1;
+       if (requested < ip->i_rgd->rd_length)
+               return requested + 1;
        return ip->i_rgd->rd_length;
 }
 
index 27a0b4a901f597d6b835051c29ca8632f4a7cf98..db330e5518cdafe8aacef6ee3ae00f1d912b5b51 100644 (file)
@@ -448,17 +448,18 @@ ssize_t gfs2_listxattr(struct dentry *dentry, char *buffer, size_t size)
 }
 
 /**
- * ea_get_unstuffed - actually copies the unstuffed data into the
- *                    request buffer
+ * ea_iter_unstuffed - copies the unstuffed xattr data to/from the
+ *                     request buffer
  * @ip: The GFS2 inode
  * @ea: The extended attribute header structure
- * @data: The data to be copied
+ * @din: The data to be copied in
+ * @dout: The data to be copied out (one of din,dout will be NULL)
  *
  * Returns: errno
  */
 
-static int ea_get_unstuffed(struct gfs2_inode *ip, struct gfs2_ea_header *ea,
-                           char *data)
+static int gfs2_iter_unstuffed(struct gfs2_inode *ip, struct gfs2_ea_header *ea,
+                              const char *din, char *dout)
 {
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
        struct buffer_head **bh;
@@ -467,6 +468,8 @@ static int ea_get_unstuffed(struct gfs2_inode *ip, struct gfs2_ea_header *ea,
        __be64 *dataptrs = GFS2_EA2DATAPTRS(ea);
        unsigned int x;
        int error = 0;
+       unsigned char *pos;
+       unsigned cp_size;
 
        bh = kcalloc(nptrs, sizeof(struct buffer_head *), GFP_NOFS);
        if (!bh)
@@ -497,12 +500,21 @@ static int ea_get_unstuffed(struct gfs2_inode *ip, struct gfs2_ea_header *ea,
                        goto out;
                }
 
-               memcpy(data, bh[x]->b_data + sizeof(struct gfs2_meta_header),
-                      (sdp->sd_jbsize > amount) ? amount : sdp->sd_jbsize);
+               pos = bh[x]->b_data + sizeof(struct gfs2_meta_header);
+               cp_size = (sdp->sd_jbsize > amount) ? amount : sdp->sd_jbsize;
 
-               amount -= sdp->sd_jbsize;
-               data += sdp->sd_jbsize;
+               if (dout) {
+                       memcpy(dout, pos, cp_size);
+                       dout += sdp->sd_jbsize;
+               }
+
+               if (din) {
+                       gfs2_trans_add_bh(ip->i_gl, bh[x], 1);
+                       memcpy(pos, din, cp_size);
+                       din += sdp->sd_jbsize;
+               }
 
+               amount -= sdp->sd_jbsize;
                brelse(bh[x]);
        }
 
@@ -523,7 +535,7 @@ static int gfs2_ea_get_copy(struct gfs2_inode *ip, struct gfs2_ea_location *el,
                memcpy(data, GFS2_EA2DATA(el->el_ea), len);
                return len;
        }
-       ret = ea_get_unstuffed(ip, el->el_ea, data);
+       ret = gfs2_iter_unstuffed(ip, el->el_ea, NULL, data);
        if (ret < 0)
                return ret;
        return len;
@@ -727,7 +739,7 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er,
                goto out_gunlock_q;
 
        error = gfs2_trans_begin(GFS2_SB(&ip->i_inode),
-                                blks + gfs2_rg_blocks(ip) +
+                                blks + gfs2_rg_blocks(ip, blks) +
                                 RES_DINODE + RES_STATFS + RES_QUOTA, 0);
        if (error)
                goto out_ipres;
@@ -1220,69 +1232,23 @@ static int gfs2_xattr_set(struct dentry *dentry, const char *name,
                                size, flags, type);
 }
 
+
 static int ea_acl_chmod_unstuffed(struct gfs2_inode *ip,
                                  struct gfs2_ea_header *ea, char *data)
 {
        struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
-       struct buffer_head **bh;
        unsigned int amount = GFS2_EA_DATA_LEN(ea);
        unsigned int nptrs = DIV_ROUND_UP(amount, sdp->sd_jbsize);
-       __be64 *dataptrs = GFS2_EA2DATAPTRS(ea);
-       unsigned int x;
-       int error;
-
-       bh = kcalloc(nptrs, sizeof(struct buffer_head *), GFP_NOFS);
-       if (!bh)
-               return -ENOMEM;
-
-       error = gfs2_trans_begin(sdp, nptrs + RES_DINODE, 0);
-       if (error)
-               goto out;
-
-       for (x = 0; x < nptrs; x++) {
-               error = gfs2_meta_read(ip->i_gl, be64_to_cpu(*dataptrs), 0,
-                                      bh + x);
-               if (error) {
-                       while (x--)
-                               brelse(bh[x]);
-                       goto fail;
-               }
-               dataptrs++;
-       }
-
-       for (x = 0; x < nptrs; x++) {
-               error = gfs2_meta_wait(sdp, bh[x]);
-               if (error) {
-                       for (; x < nptrs; x++)
-                               brelse(bh[x]);
-                       goto fail;
-               }
-               if (gfs2_metatype_check(sdp, bh[x], GFS2_METATYPE_ED)) {
-                       for (; x < nptrs; x++)
-                               brelse(bh[x]);
-                       error = -EIO;
-                       goto fail;
-               }
-
-               gfs2_trans_add_bh(ip->i_gl, bh[x], 1);
-
-               memcpy(bh[x]->b_data + sizeof(struct gfs2_meta_header), data,
-                      (sdp->sd_jbsize > amount) ? amount : sdp->sd_jbsize);
-
-               amount -= sdp->sd_jbsize;
-               data += sdp->sd_jbsize;
-
-               brelse(bh[x]);
-       }
+       int ret;
 
-out:
-       kfree(bh);
-       return error;
+       ret = gfs2_trans_begin(sdp, nptrs + RES_DINODE, 0);
+       if (ret)
+               return ret;
 
-fail:
+       ret = gfs2_iter_unstuffed(ip, ea, data, NULL);
        gfs2_trans_end(sdp);
-       kfree(bh);
-       return error;
+
+       return ret;
 }
 
 int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data)
index 5fd51a5833ffb91facba871b74589bf8b9a6c087..b7ec224910c5d7bda2f36432260fa6a6050d76d4 100644 (file)
@@ -236,10 +236,10 @@ out:
  * hfs_mdb_commit()
  *
  * Description:
- *   This updates the MDB on disk (look also at hfs_write_super()).
+ *   This updates the MDB on disk.
  *   It does not check, if the superblock has been modified, or
  *   if the filesystem has been mounted read-only. It is mainly
- *   called by hfs_write_super() and hfs_btree_extend().
+ *   called by hfs_sync_fs() and flush_mdb().
  * Input Variable(s):
  *   struct hfs_mdb *mdb: Pointer to the hfs MDB
  *   int backup;
index 425c2f2cf1700a3f5d9db8fc4e93dcde0450d998..a2862339323b2a5f1e08dd7e25a779e1b683b828 100644 (file)
@@ -534,8 +534,8 @@ int journal_start_commit(journal_t *journal, tid_t *ptid)
                ret = 1;
        } else if (journal->j_committing_transaction) {
                /*
-                * If ext3_write_super() recently started a commit, then we
-                * have to wait for completion of that transaction
+                * If commit has been started, then we have to wait for
+                * completion of that transaction.
                 */
                if (ptid)
                        *ptid = journal->j_committing_transaction->t_tid;
@@ -1113,6 +1113,11 @@ static void mark_journal_empty(journal_t *journal)
 
        BUG_ON(!mutex_is_locked(&journal->j_checkpoint_mutex));
        spin_lock(&journal->j_state_lock);
+       /* Is it already empty? */
+       if (sb->s_start == 0) {
+               spin_unlock(&journal->j_state_lock);
+               return;
+       }
        jbd_debug(1, "JBD: Marking journal as empty (seq %d)\n",
                  journal->j_tail_sequence);
 
index e9a3c4c85594e30aca1ed1f14d5667ba0595160a..8625da27eccf3cb1666f9557c4879bf908d9da29 100644 (file)
@@ -612,8 +612,8 @@ int jbd2_journal_start_commit(journal_t *journal, tid_t *ptid)
                ret = 1;
        } else if (journal->j_committing_transaction) {
                /*
-                * If ext3_write_super() recently started a commit, then we
-                * have to wait for completion of that transaction
+                * If commit has been started, then we have to wait for
+                * completion of that transaction.
                 */
                if (ptid)
                        *ptid = journal->j_committing_transaction->t_tid;
index df0de27c273349c22ee6b8770b589663801c68f5..e784a217b50067919ad3ebffe559b3552b58a9bc 100644 (file)
@@ -26,6 +26,7 @@ static int sync_request(struct page *page, struct block_device *bdev, int rw)
        struct completion complete;
 
        bio_init(&bio);
+       bio.bi_max_vecs = 1;
        bio.bi_io_vec = &bio_vec;
        bio_vec.bv_page = page;
        bio_vec.bv_len = PAGE_SIZE;
@@ -95,12 +96,11 @@ static int __bdev_writeseg(struct super_block *sb, u64 ofs, pgoff_t index,
        struct address_space *mapping = super->s_mapping_inode->i_mapping;
        struct bio *bio;
        struct page *page;
-       struct request_queue *q = bdev_get_queue(sb->s_bdev);
-       unsigned int max_pages = queue_max_hw_sectors(q) >> (PAGE_SHIFT - 9);
+       unsigned int max_pages;
        int i;
 
-       if (max_pages > BIO_MAX_PAGES)
-               max_pages = BIO_MAX_PAGES;
+       max_pages = min(nr_pages, (size_t) bio_get_nr_vecs(super->s_bdev));
+
        bio = bio_alloc(GFP_NOFS, max_pages);
        BUG_ON(!bio);
 
@@ -190,12 +190,11 @@ static int do_erase(struct super_block *sb, u64 ofs, pgoff_t index,
 {
        struct logfs_super *super = logfs_super(sb);
        struct bio *bio;
-       struct request_queue *q = bdev_get_queue(sb->s_bdev);
-       unsigned int max_pages = queue_max_hw_sectors(q) >> (PAGE_SHIFT - 9);
+       unsigned int max_pages;
        int i;
 
-       if (max_pages > BIO_MAX_PAGES)
-               max_pages = BIO_MAX_PAGES;
+       max_pages = min(nr_pages, (size_t) bio_get_nr_vecs(super->s_bdev));
+
        bio = bio_alloc(GFP_NOFS, max_pages);
        BUG_ON(!bio);
 
index a422f42238b250764011fa421d24a1a0858dd153..6984562738d36bc4142a3e0556730ae9e3bf3a57 100644 (file)
@@ -156,10 +156,26 @@ static void __logfs_destroy_inode(struct inode *inode)
        call_rcu(&inode->i_rcu, logfs_i_callback);
 }
 
+static void __logfs_destroy_meta_inode(struct inode *inode)
+{
+       struct logfs_inode *li = logfs_inode(inode);
+       BUG_ON(li->li_block);
+       call_rcu(&inode->i_rcu, logfs_i_callback);
+}
+
 static void logfs_destroy_inode(struct inode *inode)
 {
        struct logfs_inode *li = logfs_inode(inode);
 
+       if (inode->i_ino < LOGFS_RESERVED_INOS) {
+               /*
+                * The reserved inodes are never destroyed unless we are in
+                * unmont path.
+                */
+               __logfs_destroy_meta_inode(inode);
+               return;
+       }
+
        BUG_ON(list_empty(&li->li_freeing_list));
        spin_lock(&logfs_inode_lock);
        li->li_refcount--;
@@ -373,8 +389,8 @@ static void logfs_put_super(struct super_block *sb)
 {
        struct logfs_super *super = logfs_super(sb);
        /* kill the meta-inodes */
-       iput(super->s_master_inode);
        iput(super->s_segfile_inode);
+       iput(super->s_master_inode);
        iput(super->s_mapping_inode);
 }
 
index 1e1c369df22bb085f62519b1100eb300053aaae8..2a09b8d73989539aedfe205fafd7f856f1122c7c 100644 (file)
@@ -565,7 +565,7 @@ static void write_wbuf(struct super_block *sb, struct logfs_area *area,
        index = ofs >> PAGE_SHIFT;
        page_ofs = ofs & (PAGE_SIZE - 1);
 
-       page = find_lock_page(mapping, index);
+       page = find_or_create_page(mapping, index, GFP_NOFS);
        BUG_ON(!page);
        memcpy(wbuf, page_address(page) + page_ofs, super->s_writesize);
        unlock_page(page);
index f1cb512c5019dacf057391ed857a9697f0b98422..5be0abef603d4f82af9e59aaca639118e280476b 100644 (file)
@@ -2189,7 +2189,6 @@ void logfs_evict_inode(struct inode *inode)
                return;
        }
 
-       BUG_ON(inode->i_ino < LOGFS_RESERVED_INOS);
        page = inode_to_page(inode);
        BUG_ON(!page); /* FIXME: Use emergency page */
        logfs_put_write_page(page);
index e28d090c98d6bbb2986d40fd4ae57e795cf7415c..038da0991794a39962fac3d4ef7ed5b18008c6f9 100644 (file)
@@ -886,7 +886,7 @@ static struct logfs_area *alloc_area(struct super_block *sb)
 
 static void map_invalidatepage(struct page *page, unsigned long l)
 {
-       BUG();
+       return;
 }
 
 static int map_releasepage(struct page *page, gfp_t g)
index 8bf3a3f6925ab7459d93416f171b05d8cbf13cb7..b7db60897f91d5e8be99f59400add178cd082b8e 100644 (file)
@@ -12,19 +12,19 @@ nfs-$(CONFIG_ROOT_NFS)      += nfsroot.o
 nfs-$(CONFIG_SYSCTL)   += sysctl.o
 nfs-$(CONFIG_NFS_FSCACHE) += fscache.o fscache-index.o
 
-obj-$(CONFIG_NFS_V2) += nfs2.o
-nfs2-y := nfs2super.o proc.o nfs2xdr.o
+obj-$(CONFIG_NFS_V2) += nfsv2.o
+nfsv2-y := nfs2super.o proc.o nfs2xdr.o
 
-obj-$(CONFIG_NFS_V3) += nfs3.o
-nfs3-y := nfs3super.o nfs3client.o nfs3proc.o nfs3xdr.o
-nfs3-$(CONFIG_NFS_V3_ACL) += nfs3acl.o
+obj-$(CONFIG_NFS_V3) += nfsv3.o
+nfsv3-y := nfs3super.o nfs3client.o nfs3proc.o nfs3xdr.o
+nfsv3-$(CONFIG_NFS_V3_ACL) += nfs3acl.o
 
-obj-$(CONFIG_NFS_V4) += nfs4.o
-nfs4-y := nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o nfs4super.o nfs4file.o \
+obj-$(CONFIG_NFS_V4) += nfsv4.o
+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
-nfs4-$(CONFIG_SYSCTL)  += nfs4sysctl.o
-nfs4-$(CONFIG_NFS_V4_1)        += pnfs.o pnfs_dev.o
+nfsv4-$(CONFIG_SYSCTL) += nfs4sysctl.o
+nfsv4-$(CONFIG_NFS_V4_1)       += 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 9fc0d9dfc91b8a5e4226b0fcfb56bb55658f0869..99694442b93f6d64f5f433d8cf3cc8fdc08de52e 100644 (file)
@@ -105,7 +105,7 @@ struct nfs_subversion *get_nfs_version(unsigned int version)
 
        if (IS_ERR(nfs)) {
                mutex_lock(&nfs_version_mutex);
-               request_module("nfs%d", version);
+               request_module("nfsv%d", version);
                nfs = find_nfs_version(version);
                mutex_unlock(&nfs_version_mutex);
        }
index b701358c39c351d0613d1db29ebcf382ca8cb0a6..a850079467d85f149d997b9c96176c9a0829be0d 100644 (file)
@@ -61,6 +61,12 @@ struct idmap {
        struct mutex            idmap_mutex;
 };
 
+struct idmap_legacy_upcalldata {
+       struct rpc_pipe_msg pipe_msg;
+       struct idmap_msg idmap_msg;
+       struct idmap *idmap;
+};
+
 /**
  * nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields
  * @fattr: fully initialised struct nfs_fattr
@@ -324,6 +330,7 @@ static ssize_t nfs_idmap_get_key(const char *name, size_t namelen,
                ret = nfs_idmap_request_key(&key_type_id_resolver_legacy,
                                            name, namelen, type, data,
                                            data_size, idmap);
+               idmap->idmap_key_cons = NULL;
                mutex_unlock(&idmap->idmap_mutex);
        }
        return ret;
@@ -380,11 +387,13 @@ static const match_table_t nfs_idmap_tokens = {
 static int nfs_idmap_legacy_upcall(struct key_construction *, const char *, void *);
 static ssize_t idmap_pipe_downcall(struct file *, const char __user *,
                                   size_t);
+static void idmap_release_pipe(struct inode *);
 static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *);
 
 static const struct rpc_pipe_ops idmap_upcall_ops = {
        .upcall         = rpc_pipe_generic_upcall,
        .downcall       = idmap_pipe_downcall,
+       .release_pipe   = idmap_release_pipe,
        .destroy_msg    = idmap_pipe_destroy_msg,
 };
 
@@ -616,7 +625,8 @@ void nfs_idmap_quit(void)
        nfs_idmap_quit_keyring();
 }
 
-static int nfs_idmap_prepare_message(char *desc, struct idmap_msg *im,
+static int nfs_idmap_prepare_message(char *desc, struct idmap *idmap,
+                                    struct idmap_msg *im,
                                     struct rpc_pipe_msg *msg)
 {
        substring_t substr;
@@ -659,6 +669,7 @@ static int nfs_idmap_legacy_upcall(struct key_construction *cons,
                                   const char *op,
                                   void *aux)
 {
+       struct idmap_legacy_upcalldata *data;
        struct rpc_pipe_msg *msg;
        struct idmap_msg *im;
        struct idmap *idmap = (struct idmap *)aux;
@@ -666,15 +677,15 @@ static int nfs_idmap_legacy_upcall(struct key_construction *cons,
        int ret = -ENOMEM;
 
        /* msg and im are freed in idmap_pipe_destroy_msg */
-       msg = kmalloc(sizeof(*msg), GFP_KERNEL);
-       if (!msg)
-               goto out0;
-
-       im = kmalloc(sizeof(*im), GFP_KERNEL);
-       if (!im)
+       data = kmalloc(sizeof(*data), GFP_KERNEL);
+       if (!data)
                goto out1;
 
-       ret = nfs_idmap_prepare_message(key->description, im, msg);
+       msg = &data->pipe_msg;
+       im = &data->idmap_msg;
+       data->idmap = idmap;
+
+       ret = nfs_idmap_prepare_message(key->description, idmap, im, msg);
        if (ret < 0)
                goto out2;
 
@@ -683,15 +694,15 @@ static int nfs_idmap_legacy_upcall(struct key_construction *cons,
 
        ret = rpc_queue_upcall(idmap->idmap_pipe, msg);
        if (ret < 0)
-               goto out2;
+               goto out3;
 
        return ret;
 
+out3:
+       idmap->idmap_key_cons = NULL;
 out2:
-       kfree(im);
+       kfree(data);
 out1:
-       kfree(msg);
-out0:
        complete_request_key(cons, ret);
        return ret;
 }
@@ -749,9 +760,8 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
        }
 
        if (!(im.im_status & IDMAP_STATUS_SUCCESS)) {
-               ret = mlen;
-               complete_request_key(cons, -ENOKEY);
-               goto out_incomplete;
+               ret = -ENOKEY;
+               goto out;
        }
 
        namelen_in = strnlen(im.im_name, IDMAP_NAMESZ);
@@ -768,16 +778,32 @@ idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
 
 out:
        complete_request_key(cons, ret);
-out_incomplete:
        return ret;
 }
 
 static void
 idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg)
 {
+       struct idmap_legacy_upcalldata *data = container_of(msg,
+                       struct idmap_legacy_upcalldata,
+                       pipe_msg);
+       struct idmap *idmap = data->idmap;
+       struct key_construction *cons;
+       if (msg->errno) {
+               cons = ACCESS_ONCE(idmap->idmap_key_cons);
+               idmap->idmap_key_cons = NULL;
+               complete_request_key(cons, msg->errno);
+       }
        /* Free memory allocated in nfs_idmap_legacy_upcall() */
-       kfree(msg->data);
-       kfree(msg);
+       kfree(data);
+}
+
+static void
+idmap_release_pipe(struct inode *inode)
+{
+       struct rpc_inode *rpci = RPC_I(inode);
+       struct idmap *idmap = (struct idmap *)rpci->private;
+       idmap->idmap_key_cons = NULL;
 }
 
 int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid)
index 3b950dd81e81f82b4fd32c5b508fde181d07b875..da0618aeeadb88c04447a63b18e2d908b6d03955 100644 (file)
@@ -205,6 +205,9 @@ extern const struct dentry_operations nfs4_dentry_operations;
 int nfs_atomic_open(struct inode *, struct dentry *, struct file *,
                    unsigned, umode_t, int *);
 
+/* super.c */
+extern struct file_system_type nfs4_fs_type;
+
 /* nfs4namespace.c */
 rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *);
 struct rpc_clnt *nfs4_create_sec_client(struct rpc_clnt *, struct inode *, struct qstr *);
index a99a8d94872131610ab543d5a06d9f4f541cc2dc..635274140b180287668dbaa7540bd84852051181 100644 (file)
@@ -3737,9 +3737,10 @@ out:
 static void nfs4_write_cached_acl(struct inode *inode, struct page **pages, size_t pgbase, size_t acl_len)
 {
        struct nfs4_cached_acl *acl;
+       size_t buflen = sizeof(*acl) + acl_len;
 
-       if (pages && acl_len <= PAGE_SIZE) {
-               acl = kmalloc(sizeof(*acl) + acl_len, GFP_KERNEL);
+       if (pages && buflen <= PAGE_SIZE) {
+               acl = kmalloc(buflen, GFP_KERNEL);
                if (acl == NULL)
                        goto out;
                acl->cached = 1;
@@ -3819,7 +3820,7 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
        if (ret)
                goto out_free;
 
-       acl_len = res.acl_len - res.acl_data_offset;
+       acl_len = res.acl_len;
        if (acl_len > args.acl_len)
                nfs4_write_cached_acl(inode, NULL, 0, acl_len);
        else
@@ -6223,11 +6224,58 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
        dprintk("<-- %s\n", __func__);
 }
 
+static size_t max_response_pages(struct nfs_server *server)
+{
+       u32 max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz;
+       return nfs_page_array_len(0, max_resp_sz);
+}
+
+static void nfs4_free_pages(struct page **pages, size_t size)
+{
+       int i;
+
+       if (!pages)
+               return;
+
+       for (i = 0; i < size; i++) {
+               if (!pages[i])
+                       break;
+               __free_page(pages[i]);
+       }
+       kfree(pages);
+}
+
+static struct page **nfs4_alloc_pages(size_t size, gfp_t gfp_flags)
+{
+       struct page **pages;
+       int i;
+
+       pages = kcalloc(size, sizeof(struct page *), gfp_flags);
+       if (!pages) {
+               dprintk("%s: can't alloc array of %zu pages\n", __func__, size);
+               return NULL;
+       }
+
+       for (i = 0; i < size; i++) {
+               pages[i] = alloc_page(gfp_flags);
+               if (!pages[i]) {
+                       dprintk("%s: failed to allocate page\n", __func__);
+                       nfs4_free_pages(pages, size);
+                       return NULL;
+               }
+       }
+
+       return pages;
+}
+
 static void nfs4_layoutget_release(void *calldata)
 {
        struct nfs4_layoutget *lgp = calldata;
+       struct nfs_server *server = NFS_SERVER(lgp->args.inode);
+       size_t max_pages = max_response_pages(server);
 
        dprintk("--> %s\n", __func__);
+       nfs4_free_pages(lgp->args.layout.pages, max_pages);
        put_nfs_open_context(lgp->args.ctx);
        kfree(calldata);
        dprintk("<-- %s\n", __func__);
@@ -6239,9 +6287,10 @@ static const struct rpc_call_ops nfs4_layoutget_call_ops = {
        .rpc_release = nfs4_layoutget_release,
 };
 
-int nfs4_proc_layoutget(struct nfs4_layoutget *lgp)
+void nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags)
 {
        struct nfs_server *server = NFS_SERVER(lgp->args.inode);
+       size_t max_pages = max_response_pages(server);
        struct rpc_task *task;
        struct rpc_message msg = {
                .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTGET],
@@ -6259,12 +6308,19 @@ int nfs4_proc_layoutget(struct nfs4_layoutget *lgp)
 
        dprintk("--> %s\n", __func__);
 
+       lgp->args.layout.pages = nfs4_alloc_pages(max_pages, gfp_flags);
+       if (!lgp->args.layout.pages) {
+               nfs4_layoutget_release(lgp);
+               return;
+       }
+       lgp->args.layout.pglen = max_pages * PAGE_SIZE;
+
        lgp->res.layoutp = &lgp->args.layout;
        lgp->res.seq_res.sr_slot = NULL;
        nfs41_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0);
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task))
-               return PTR_ERR(task);
+               return;
        status = nfs4_wait_for_completion_rpc_task(task);
        if (status == 0)
                status = task->tk_status;
@@ -6272,7 +6328,7 @@ int nfs4_proc_layoutget(struct nfs4_layoutget *lgp)
                status = pnfs_layout_process(lgp);
        rpc_put_task(task);
        dprintk("<-- %s status=%d\n", __func__, status);
-       return status;
+       return;
 }
 
 static void
@@ -6304,12 +6360,8 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata)
                return;
        }
        spin_lock(&lo->plh_inode->i_lock);
-       if (task->tk_status == 0) {
-               if (lrp->res.lrs_present) {
-                       pnfs_set_layout_stateid(lo, &lrp->res.stateid, true);
-               } else
-                       BUG_ON(!list_empty(&lo->plh_segs));
-       }
+       if (task->tk_status == 0 && lrp->res.lrs_present)
+               pnfs_set_layout_stateid(lo, &lrp->res.stateid, true);
        lo->plh_block_lgets--;
        spin_unlock(&lo->plh_inode->i_lock);
        dprintk("<-- %s\n", __func__);
index 6930bec91bca22a8f8f7cf0548dcfe9cc6964762..1720d32ffa545670398d16e077a094aae781528b 100644 (file)
@@ -117,8 +117,7 @@ nfs4_schedule_state_renewal(struct nfs_client *clp)
                timeout = 5 * HZ;
        dprintk("%s: requeueing work. Lease period = %ld\n",
                        __func__, (timeout + HZ - 1) / HZ);
-       cancel_delayed_work(&clp->cl_renewd);
-       schedule_delayed_work(&clp->cl_renewd, timeout);
+       mod_delayed_work(system_wq, &clp->cl_renewd, timeout);
        set_bit(NFS_CS_RENEWD, &clp->cl_res_state);
        spin_unlock(&clp->cl_lock);
 }
index 12a31a9dbcddc562e7f55e65ae4952810dccb3f7..bd61221ad2c5542b08f42249d10285c159f66b1d 100644 (file)
@@ -23,14 +23,6 @@ static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type,
 static struct dentry *nfs4_remote_referral_mount(struct file_system_type *fs_type,
        int flags, const char *dev_name, void *raw_data);
 
-static struct file_system_type nfs4_fs_type = {
-       .owner          = THIS_MODULE,
-       .name           = "nfs4",
-       .mount          = nfs_fs_mount,
-       .kill_sb        = nfs_kill_super,
-       .fs_flags       = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
-};
-
 static struct file_system_type nfs4_remote_fs_type = {
        .owner          = THIS_MODULE,
        .name           = "nfs4",
@@ -344,14 +336,8 @@ static int __init init_nfs_v4(void)
        if (err)
                goto out1;
 
-       err = register_filesystem(&nfs4_fs_type);
-       if (err < 0)
-               goto out2;
-
        register_nfs_version(&nfs_v4);
        return 0;
-out2:
-       nfs4_unregister_sysctl();
 out1:
        nfs_idmap_quit();
 out:
@@ -361,7 +347,6 @@ out:
 static void __exit exit_nfs_v4(void)
 {
        unregister_nfs_version(&nfs_v4);
-       unregister_filesystem(&nfs4_fs_type);
        nfs4_unregister_sysctl();
        nfs_idmap_quit();
 }
index ca13483edd60aee67c8e1673b18250959187f8a4..1bfbd67c556d753a21f046c87edc3c9b07b0b8f0 100644 (file)
@@ -5045,22 +5045,19 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
                         struct nfs_getaclres *res)
 {
        unsigned int savep;
-       __be32 *bm_p;
        uint32_t attrlen,
                 bitmap[3] = {0};
        int status;
-       size_t page_len = xdr->buf->page_len;
+       unsigned int pg_offset;
 
        res->acl_len = 0;
        if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
                goto out;
 
-       bm_p = xdr->p;
-       res->acl_data_offset = be32_to_cpup(bm_p) + 2;
-       res->acl_data_offset <<= 2;
-       /* Check if the acl data starts beyond the allocated buffer */
-       if (res->acl_data_offset > page_len)
-               return -ERANGE;
+       xdr_enter_page(xdr, xdr->buf->page_len);
+
+       /* Calculate the offset of the page data */
+       pg_offset = xdr->buf->head[0].iov_len;
 
        if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
                goto out;
@@ -5074,23 +5071,20 @@ static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
                /* The bitmap (xdr len + bitmaps) and the attr xdr len words
                 * are stored with the acl data to handle the problem of
                 * variable length bitmaps.*/
-               xdr->p = bm_p;
+               res->acl_data_offset = xdr_stream_pos(xdr) - pg_offset;
 
                /* We ignore &savep and don't do consistency checks on
                 * the attr length.  Let userspace figure it out.... */
-               attrlen += res->acl_data_offset;
-               if (attrlen > page_len) {
+               res->acl_len = attrlen;
+               if (attrlen > (xdr->nwords << 2)) {
                        if (res->acl_flags & NFS4_ACL_LEN_REQUEST) {
                                /* getxattr interface called with a NULL buf */
-                               res->acl_len = attrlen;
                                goto out;
                        }
-                       dprintk("NFS: acl reply: attrlen %u > page_len %zu\n",
-                                       attrlen, page_len);
+                       dprintk("NFS: acl reply: attrlen %u > page_len %u\n",
+                                       attrlen, xdr->nwords << 2);
                        return -EINVAL;
                }
-               xdr_read_pages(xdr, attrlen);
-               res->acl_len = attrlen;
        } else
                status = -EOPNOTSUPP;
 
index f50d3e8d6f2230a42cdc656b61004dcf62182dd2..ea6d111b03e9484c23d5ca3f7997f10d893a57ad 100644 (file)
@@ -570,17 +570,66 @@ static bool objio_pg_test(struct nfs_pageio_descriptor *pgio,
                return false;
 
        return pgio->pg_count + req->wb_bytes <=
-                       OBJIO_LSEG(pgio->pg_lseg)->layout.max_io_length;
+                       (unsigned long)pgio->pg_layout_private;
+}
+
+void objio_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
+{
+       pnfs_generic_pg_init_read(pgio, req);
+       if (unlikely(pgio->pg_lseg == NULL))
+               return; /* Not pNFS */
+
+       pgio->pg_layout_private = (void *)
+                               OBJIO_LSEG(pgio->pg_lseg)->layout.max_io_length;
+}
+
+static bool aligned_on_raid_stripe(u64 offset, struct ore_layout *layout,
+                                  unsigned long *stripe_end)
+{
+       u32 stripe_off;
+       unsigned stripe_size;
+
+       if (layout->raid_algorithm == PNFS_OSD_RAID_0)
+               return true;
+
+       stripe_size = layout->stripe_unit *
+                               (layout->group_width - layout->parity);
+
+       div_u64_rem(offset, stripe_size, &stripe_off);
+       if (!stripe_off)
+               return true;
+
+       *stripe_end = stripe_size - stripe_off;
+       return false;
+}
+
+void objio_init_write(struct nfs_pageio_descriptor *pgio, struct nfs_page *req)
+{
+       unsigned long stripe_end = 0;
+
+       pnfs_generic_pg_init_write(pgio, req);
+       if (unlikely(pgio->pg_lseg == NULL))
+               return; /* Not pNFS */
+
+       if (req->wb_offset ||
+           !aligned_on_raid_stripe(req->wb_index * PAGE_SIZE,
+                              &OBJIO_LSEG(pgio->pg_lseg)->layout,
+                              &stripe_end)) {
+               pgio->pg_layout_private = (void *)stripe_end;
+       } else {
+               pgio->pg_layout_private = (void *)
+                               OBJIO_LSEG(pgio->pg_lseg)->layout.max_io_length;
+       }
 }
 
 static const struct nfs_pageio_ops objio_pg_read_ops = {
-       .pg_init = pnfs_generic_pg_init_read,
+       .pg_init = objio_init_read,
        .pg_test = objio_pg_test,
        .pg_doio = pnfs_generic_pg_readpages,
 };
 
 static const struct nfs_pageio_ops objio_pg_write_ops = {
-       .pg_init = pnfs_generic_pg_init_write,
+       .pg_init = objio_init_write,
        .pg_test = objio_pg_test,
        .pg_doio = pnfs_generic_pg_writepages,
 };
index 1a6732ed04a447aa14147468e15f4b7956557376..311a79681e2b16311724e25921d922768c999026 100644 (file)
@@ -49,6 +49,7 @@ void nfs_pgheader_init(struct nfs_pageio_descriptor *desc,
        hdr->io_start = req_offset(hdr->req);
        hdr->good_bytes = desc->pg_count;
        hdr->dreq = desc->pg_dreq;
+       hdr->layout_private = desc->pg_layout_private;
        hdr->release = release;
        hdr->completion_ops = desc->pg_completion_ops;
        if (hdr->completion_ops->init_hdr)
@@ -268,6 +269,7 @@ void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
        desc->pg_error = 0;
        desc->pg_lseg = NULL;
        desc->pg_dreq = NULL;
+       desc->pg_layout_private = NULL;
 }
 EXPORT_SYMBOL_GPL(nfs_pageio_init);
 
index 76875bfcf19ceda4a54cb0dde14466a304191cf9..2e00feacd4bee642c59c965612068653f120756c 100644 (file)
@@ -583,9 +583,6 @@ send_layoutget(struct pnfs_layout_hdr *lo,
        struct nfs_server *server = NFS_SERVER(ino);
        struct nfs4_layoutget *lgp;
        struct pnfs_layout_segment *lseg = NULL;
-       struct page **pages = NULL;
-       int i;
-       u32 max_resp_sz, max_pages;
 
        dprintk("--> %s\n", __func__);
 
@@ -594,20 +591,6 @@ send_layoutget(struct pnfs_layout_hdr *lo,
        if (lgp == NULL)
                return NULL;
 
-       /* allocate pages for xdr post processing */
-       max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz;
-       max_pages = nfs_page_array_len(0, max_resp_sz);
-
-       pages = kcalloc(max_pages, sizeof(struct page *), gfp_flags);
-       if (!pages)
-               goto out_err_free;
-
-       for (i = 0; i < max_pages; i++) {
-               pages[i] = alloc_page(gfp_flags);
-               if (!pages[i])
-                       goto out_err_free;
-       }
-
        lgp->args.minlength = PAGE_CACHE_SIZE;
        if (lgp->args.minlength > range->length)
                lgp->args.minlength = range->length;
@@ -616,39 +599,19 @@ send_layoutget(struct pnfs_layout_hdr *lo,
        lgp->args.type = server->pnfs_curr_ld->id;
        lgp->args.inode = ino;
        lgp->args.ctx = get_nfs_open_context(ctx);
-       lgp->args.layout.pages = pages;
-       lgp->args.layout.pglen = max_pages * PAGE_SIZE;
        lgp->lsegpp = &lseg;
        lgp->gfp_flags = gfp_flags;
 
        /* Synchronously retrieve layout information from server and
         * store in lseg.
         */
-       nfs4_proc_layoutget(lgp);
+       nfs4_proc_layoutget(lgp, gfp_flags);
        if (!lseg) {
                /* remember that LAYOUTGET failed and suspend trying */
                set_bit(lo_fail_bit(range->iomode), &lo->plh_flags);
        }
 
-       /* free xdr pages */
-       for (i = 0; i < max_pages; i++)
-               __free_page(pages[i]);
-       kfree(pages);
-
        return lseg;
-
-out_err_free:
-       /* free any allocated xdr pages, lgp as it's not used */
-       if (pages) {
-               for (i = 0; i < max_pages; i++) {
-                       if (!pages[i])
-                               break;
-                       __free_page(pages[i]);
-               }
-               kfree(pages);
-       }
-       kfree(lgp);
-       return NULL;
 }
 
 /*
index 2c6c80503ba4851ed1e69c253293684c540b2c32..745aa1b39e7c3d1e543a1c0beae0113c99a23cac 100644 (file)
@@ -172,7 +172,7 @@ extern int nfs4_proc_getdevicelist(struct nfs_server *server,
                                   struct pnfs_devicelist *devlist);
 extern int nfs4_proc_getdeviceinfo(struct nfs_server *server,
                                   struct pnfs_device *dev);
-extern int nfs4_proc_layoutget(struct nfs4_layoutget *lgp);
+extern void nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags);
 extern int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp);
 
 /* pnfs.c */
index ac6a3c55dce408afbd5348a2f9af42a7f78e660e..239aff7338eb89ee8c0d4080694178317d84929e 100644 (file)
@@ -319,6 +319,34 @@ EXPORT_SYMBOL_GPL(nfs_sops);
 static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *);
 static int nfs4_validate_mount_data(void *options,
        struct nfs_parsed_mount_data *args, const char *dev_name);
+
+struct file_system_type nfs4_fs_type = {
+       .owner          = THIS_MODULE,
+       .name           = "nfs4",
+       .mount          = nfs_fs_mount,
+       .kill_sb        = nfs_kill_super,
+       .fs_flags       = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
+};
+EXPORT_SYMBOL_GPL(nfs4_fs_type);
+
+static int __init register_nfs4_fs(void)
+{
+       return register_filesystem(&nfs4_fs_type);
+}
+
+static void unregister_nfs4_fs(void)
+{
+       unregister_filesystem(&nfs4_fs_type);
+}
+#else
+static int __init register_nfs4_fs(void)
+{
+       return 0;
+}
+
+static void unregister_nfs4_fs(void)
+{
+}
 #endif
 
 static struct shrinker acl_shrinker = {
@@ -337,12 +365,18 @@ int __init register_nfs_fs(void)
        if (ret < 0)
                goto error_0;
 
-       ret = nfs_register_sysctl();
+       ret = register_nfs4_fs();
        if (ret < 0)
                goto error_1;
+
+       ret = nfs_register_sysctl();
+       if (ret < 0)
+               goto error_2;
        register_shrinker(&acl_shrinker);
        return 0;
 
+error_2:
+       unregister_nfs4_fs();
 error_1:
        unregister_filesystem(&nfs_fs_type);
 error_0:
@@ -356,6 +390,7 @@ void __exit unregister_nfs_fs(void)
 {
        unregister_shrinker(&acl_shrinker);
        nfs_unregister_sysctl();
+       unregister_nfs4_fs();
        unregister_filesystem(&nfs_fs_type);
 }
 
@@ -2645,4 +2680,6 @@ MODULE_PARM_DESC(max_session_slots, "Maximum number of outstanding NFSv4.1 "
 module_param(send_implementation_id, ushort, 0644);
 MODULE_PARM_DESC(send_implementation_id,
                "Send implementation ID with NFSv4.1 exchange_id");
+MODULE_ALIAS("nfs4");
+
 #endif /* CONFIG_NFS_V4 */
index 5829d0ce7cfb574f28451380b153df72d3dcd18f..e3b55372726cb0d2a082c62ed86a35e8605c66b5 100644 (file)
@@ -1814,19 +1814,19 @@ int __init nfs_init_writepagecache(void)
        nfs_wdata_mempool = mempool_create_slab_pool(MIN_POOL_WRITE,
                                                     nfs_wdata_cachep);
        if (nfs_wdata_mempool == NULL)
-               return -ENOMEM;
+               goto out_destroy_write_cache;
 
        nfs_cdata_cachep = kmem_cache_create("nfs_commit_data",
                                             sizeof(struct nfs_commit_data),
                                             0, SLAB_HWCACHE_ALIGN,
                                             NULL);
        if (nfs_cdata_cachep == NULL)
-               return -ENOMEM;
+               goto out_destroy_write_mempool;
 
        nfs_commit_mempool = mempool_create_slab_pool(MIN_POOL_COMMIT,
                                                      nfs_wdata_cachep);
        if (nfs_commit_mempool == NULL)
-               return -ENOMEM;
+               goto out_destroy_commit_cache;
 
        /*
         * NFS congestion size, scale with available memory.
@@ -1849,11 +1849,20 @@ int __init nfs_init_writepagecache(void)
                nfs_congestion_kb = 256*1024;
 
        return 0;
+
+out_destroy_commit_cache:
+       kmem_cache_destroy(nfs_cdata_cachep);
+out_destroy_write_mempool:
+       mempool_destroy(nfs_wdata_mempool);
+out_destroy_write_cache:
+       kmem_cache_destroy(nfs_wdata_cachep);
+       return -ENOMEM;
 }
 
 void nfs_destroy_writepagecache(void)
 {
        mempool_destroy(nfs_commit_mempool);
+       kmem_cache_destroy(nfs_cdata_cachep);
        mempool_destroy(nfs_wdata_mempool);
        kmem_cache_destroy(nfs_wdata_cachep);
 }
index 6522cac6057c900fccdac3138475ea4c0aa0a830..6a10812711c1d37bca6660530cd6c34cbb7b30fb 100644 (file)
@@ -676,17 +676,13 @@ static const struct super_operations nilfs_sops = {
        .alloc_inode    = nilfs_alloc_inode,
        .destroy_inode  = nilfs_destroy_inode,
        .dirty_inode    = nilfs_dirty_inode,
-       /* .write_inode    = nilfs_write_inode, */
-       /* .drop_inode    = nilfs_drop_inode, */
        .evict_inode    = nilfs_evict_inode,
        .put_super      = nilfs_put_super,
-       /* .write_super    = nilfs_write_super, */
        .sync_fs        = nilfs_sync_fs,
        .freeze_fs      = nilfs_freeze,
        .unfreeze_fs    = nilfs_unfreeze,
        .statfs         = nilfs_statfs,
        .remount_fs     = nilfs_remount,
-       /* .umount_begin */
        .show_options = nilfs_show_options
 };
 
index 6eee4177807bf611874208c09fce9440979fbc4f..be1267a34ceae883b7d705c967347ad4a4185b57 100644 (file)
@@ -107,8 +107,6 @@ struct the_nilfs {
         * used for
         * - loading the latest checkpoint exclusively.
         * - allocating a new full segment.
-        * - protecting s_dirt in the super_block struct
-        *   (see nilfs_write_super) and the following fields.
         */
        struct buffer_head     *ns_sbh[2];
        struct nilfs_super_block *ns_sbp[2];
index 3344bdd5506e3f06259efb7f176e0263764fc2dd..08b886f119ce49cd0232f954b775be71e76ae736 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 f35794b97e8e5cb5cc396af28206d69ca1202935..aeb5b5abbd4fcb9036b1b9e7391541c20d8b8d3c 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 d43803669739df471e8e832ced4377f6f75ab015..f0e7a57bc8990419e75b48988e523e1ed6efbea4 100644 (file)
@@ -414,8 +414,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;
 }
@@ -511,7 +515,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;
 
@@ -525,8 +530,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;
 }
@@ -537,12 +541,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);
@@ -556,12 +565,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)
@@ -728,13 +741,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;
@@ -743,7 +756,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;
@@ -751,12 +764,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 63fc294a469268d06d9ae1cc9f3d19f3ba95f695..bd2625bd88b47a7b2961ec0d43b77f5675a80ad6 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 b13c00ac48eb377086f1928d8ff0cffae3b8cc44..21230209c9579c2ed88a9f9cdfcf30a7dd54d6bd 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);
        }
 }
 
@@ -191,8 +199,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 e3cbd746f64a5eb4ac9359cf8a3f271a6da8a332..871569c7d609360688c229e1357d3610e44841d0 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 8445fbc8985cae9c7357f59f97fface6e482815b..463e828f1f312e0a73e5fb86123a979147f74d5c 100644 (file)
@@ -264,7 +264,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;
 
@@ -280,23 +280,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;
 }
@@ -337,7 +331,7 @@ static long inotify_ioctl(struct file *file, unsigned int cmd,
 static const struct file_operations inotify_fops = {
        .poll           = inotify_poll,
        .read           = inotify_read,
-       .fasync         = inotify_fasync,
+       .fasync         = fsnotify_fasync,
        .release        = inotify_release,
        .unlocked_ioctl = inotify_ioctl,
        .compat_ioctl   = inotify_ioctl,
@@ -519,13 +513,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))
@@ -533,6 +527,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;
 
@@ -546,9 +541,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);
@@ -707,12 +702,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);
        }
 
@@ -741,7 +735,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;
 }
@@ -817,7 +811,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 f104d565b6823aa75ab39c5c0717e9e3fd9382f3..fc6b49bf73600c2aad93e802865512b692a7cc24 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 c887b1378f7ed5087eca0df3ca745e15d9a88cc6..b3963d8c998846207eb8a0c48590c14d566630f4 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 b7b4b0e8554fb1e8ab6948f2efd35704ed156e56..4df58b8ea64a97d562f0701f4061152ed0f02fc2 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 a4e855e3690e6ab844d37788b71649975321cb19..f3f2d95a3bfe5f3e29db994b862ba45407013413 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/time.h>
 #include <linux/debugfs.h>
 #include <linux/slab.h>
+#include <linux/bitmap.h>
 
 #include "heartbeat.h"
 #include "tcp.h"
@@ -282,15 +283,6 @@ struct o2hb_bio_wait_ctxt {
        int               wc_error;
 };
 
-static int o2hb_pop_count(void *map, int count)
-{
-       int i = -1, pop = 0;
-
-       while ((i = find_next_bit(map, count, i + 1)) < count)
-               pop++;
-       return pop;
-}
-
 static void o2hb_write_timeout(struct work_struct *work)
 {
        int failed, quorum;
@@ -307,9 +299,9 @@ static void o2hb_write_timeout(struct work_struct *work)
                spin_lock_irqsave(&o2hb_live_lock, flags);
                if (test_bit(reg->hr_region_num, o2hb_quorum_region_bitmap))
                        set_bit(reg->hr_region_num, o2hb_failed_region_bitmap);
-               failed = o2hb_pop_count(&o2hb_failed_region_bitmap,
+               failed = bitmap_weight(o2hb_failed_region_bitmap,
                                        O2NM_MAX_REGIONS);
-               quorum = o2hb_pop_count(&o2hb_quorum_region_bitmap,
+               quorum = bitmap_weight(o2hb_quorum_region_bitmap,
                                        O2NM_MAX_REGIONS);
                spin_unlock_irqrestore(&o2hb_live_lock, flags);
 
@@ -771,7 +763,7 @@ static void o2hb_set_quorum_device(struct o2hb_region *reg)
         * If global heartbeat active, unpin all regions if the
         * region count > CUT_OFF
         */
-       if (o2hb_pop_count(&o2hb_quorum_region_bitmap,
+       if (bitmap_weight(o2hb_quorum_region_bitmap,
                           O2NM_MAX_REGIONS) > O2HB_PIN_CUT_OFF)
                o2hb_region_unpin(NULL);
 unlock:
@@ -956,23 +948,9 @@ out:
        return changed;
 }
 
-/* This could be faster if we just implmented a find_last_bit, but I
- * don't think the circumstances warrant it. */
-static int o2hb_highest_node(unsigned long *nodes,
-                            int numbits)
+static int o2hb_highest_node(unsigned long *nodes, int numbits)
 {
-       int highest, node;
-
-       highest = numbits;
-       node = -1;
-       while ((node = find_next_bit(nodes, numbits, node + 1)) != -1) {
-               if (node >= numbits)
-                       break;
-
-               highest = node;
-       }
-
-       return highest;
+       return find_last_bit(nodes, numbits);
 }
 
 static int o2hb_do_disk_heartbeat(struct o2hb_region *reg)
@@ -1833,7 +1811,7 @@ static ssize_t o2hb_region_dev_write(struct o2hb_region *reg,
        live_threshold = O2HB_LIVE_THRESHOLD;
        if (o2hb_global_heartbeat_active()) {
                spin_lock(&o2hb_live_lock);
-               if (o2hb_pop_count(&o2hb_region_bitmap, O2NM_MAX_REGIONS) == 1)
+               if (bitmap_weight(o2hb_region_bitmap, O2NM_MAX_REGIONS) == 1)
                        live_threshold <<= 1;
                spin_unlock(&o2hb_live_lock);
        }
@@ -2184,7 +2162,7 @@ static void o2hb_heartbeat_group_drop_item(struct config_group *group,
        if (!o2hb_dependent_users)
                goto unlock;
 
-       if (o2hb_pop_count(&o2hb_quorum_region_bitmap,
+       if (bitmap_weight(o2hb_quorum_region_bitmap,
                           O2NM_MAX_REGIONS) <= O2HB_PIN_CUT_OFF)
                o2hb_region_pin(NULL);
 
@@ -2478,7 +2456,7 @@ static int o2hb_region_inc_user(const char *region_uuid)
        if (o2hb_dependent_users > 1)
                goto unlock;
 
-       if (o2hb_pop_count(&o2hb_quorum_region_bitmap,
+       if (bitmap_weight(o2hb_quorum_region_bitmap,
                           O2NM_MAX_REGIONS) <= O2HB_PIN_CUT_OFF)
                ret = o2hb_region_pin(NULL);
 
index baa2b9ef7eef90094dbd3ef8d76f6a6e1df64224..2260fb9e650831fef349ce2c6f6dcd878ffa45d2 100644 (file)
@@ -199,7 +199,8 @@ extern struct mlog_bits mlog_and_bits, mlog_not_bits;
 #define mlog_errno(st) do {                                            \
        int _st = (st);                                                 \
        if (_st != -ERESTARTSYS && _st != -EINTR &&                     \
-           _st != AOP_TRUNCATED_PAGE && _st != -ENOSPC)                \
+           _st != AOP_TRUNCATED_PAGE && _st != -ENOSPC &&              \
+           _st != -EDQUOT)                                             \
                mlog(ML_ERROR, "status = %lld\n", (long long)_st);      \
 } while (0)
 
index 005261c333b090f5f53f376bd5bbed55b8e16ba7..3d09a940c015d4e0304aaf2d3c98baeb3c0b80f8 100644 (file)
@@ -1888,8 +1888,10 @@ ok:
                         * up nodes that this node contacted */
                        while ((nn = find_next_bit (mle->response_map, O2NM_MAX_NODES,
                                                    nn+1)) < O2NM_MAX_NODES) {
-                               if (nn != dlm->node_num && nn != assert->node_idx)
+                               if (nn != dlm->node_num && nn != assert->node_idx) {
                                        master_request = 1;
+                                       break;
+                               }
                        }
                }
                mle->master = assert->node_idx;
@@ -2020,7 +2022,7 @@ int dlm_dispatch_assert_master(struct dlm_ctxt *dlm,
                               int ignore_higher, u8 request_from, u32 flags)
 {
        struct dlm_work_item *item;
-       item = kzalloc(sizeof(*item), GFP_NOFS);
+       item = kzalloc(sizeof(*item), GFP_ATOMIC);
        if (!item)
                return -ENOMEM;
 
@@ -2357,6 +2359,10 @@ static int dlm_is_lockres_migrateable(struct dlm_ctxt *dlm,
 
        assert_spin_locked(&res->spinlock);
 
+       /* delay migration when the lockres is in MIGRATING state */
+       if (res->state & DLM_LOCK_RES_MIGRATING)
+               return 0;
+
        if (res->owner != dlm->node_num)
                return 0;
 
index 01ebfd0bdad72264b99345378f0c6febe246503d..15d81adb8d772845fad5b8fd00da547c5c22cd38 100644 (file)
@@ -1887,6 +1887,13 @@ static int dlm_process_recovery_data(struct dlm_ctxt *dlm,
 
                if (ml->type == LKM_NLMODE)
                        goto skip_lvb;
+               
+               /*
+                * If the lock is in the blocked list it can't have a valid lvb,
+                * so skip it
+                */
+               if (ml->list == DLM_BLOCKED_LIST)
+                       goto skip_lvb;
 
                if (!dlm_lvb_is_empty(mres->lvb)) {
                        if (lksb->flags & DLM_LKSB_PUT_LVB) {
index f1fbb4b552ad3649238becdd9c21d4b138d5c8d7..66edce7ecfd78f807451bdbf724cfabc071dbd5a 100644 (file)
@@ -57,7 +57,7 @@
 static int ocfs2_fast_symlink_readpage(struct file *unused, struct page *page)
 {
        struct inode *inode = page->mapping->host;
-       struct buffer_head *bh;
+       struct buffer_head *bh = NULL;
        int status = ocfs2_read_inode_block(inode, &bh);
        struct ocfs2_dinode *fe;
        const char *link;
index f3d96e7e7b19d4254924a59dfc4121aa5d8635b4..bc132e167d2dd2e361fd8fb0354f987f2fa296dd 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -717,7 +717,7 @@ cleanup_all:
                         * here, so just reset the state.
                         */
                        file_reset_write(f);
-                       mnt_drop_write(f->f_path.mnt);
+                       __mnt_drop_write(f->f_path.mnt);
                }
        }
 cleanup_file:
index 36a29b753c79c709175ebfd788196d1ecad948b5..c495a3055e2a3be9b5e471afebdf53ac00c6fe51 100644 (file)
@@ -1589,10 +1589,10 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags)
                goto out;
        }
 
-       down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
        for (cnt = 0; cnt < MAXQUOTAS; cnt++)
                warn[cnt].w_type = QUOTA_NL_NOWARN;
 
+       down_read(&sb_dqopt(inode->i_sb)->dqptr_sem);
        spin_lock(&dq_data_lock);
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
                if (!dquots[cnt])
index 4c0c7d163d150c02535cffcad08a1aead02f53d2..a98b7740a0fcade0b894920154e65ecbe7987509 100644 (file)
@@ -1334,9 +1334,7 @@ struct buffer_head *reiserfs_read_bitmap_block(struct super_block *sb,
        else if (bitmap == 0)
                block = (REISERFS_DISK_OFFSET_IN_BYTES >> sb->s_blocksize_bits) + 1;
 
-       reiserfs_write_unlock(sb);
        bh = sb_bread(sb, block);
-       reiserfs_write_lock(sb);
        if (bh == NULL)
                reiserfs_warning(sb, "sh-2029: %s: bitmap block (#%u) "
                                 "reading failed", __func__, block);
index a6d4268fb6c11798db5f8339bd14ab297cd9b21f..855da58db1456b94d43715bb4a28bbc5f982a8d7 100644 (file)
@@ -76,10 +76,10 @@ void reiserfs_evict_inode(struct inode *inode)
                ;
        }
       out:
+       reiserfs_write_unlock_once(inode->i_sb, depth);
        clear_inode(inode);     /* note this must go after the journal_end to prevent deadlock */
        dquot_drop(inode);
        inode->i_blocks = 0;
-       reiserfs_write_unlock_once(inode->i_sb, depth);
        return;
 
 no_delete:
index b05cf47463d0c2347e8eca1597001f96dd2a97fc..0902cfa6a12efd21e4ebd52a39333b7f9d6270eb 100644 (file)
@@ -536,46 +536,6 @@ void drop_super(struct super_block *sb)
 
 EXPORT_SYMBOL(drop_super);
 
-/**
- * sync_supers - helper for periodic superblock writeback
- *
- * Call the write_super method if present on all dirty superblocks in
- * the system.  This is for the periodic writeback used by most older
- * filesystems.  For data integrity superblock writeback use
- * sync_filesystems() instead.
- *
- * Note: check the dirty flag before waiting, so we don't
- * hold up the sync while mounting a device. (The newly
- * mounted device won't need syncing.)
- */
-void sync_supers(void)
-{
-       struct super_block *sb, *p = NULL;
-
-       spin_lock(&sb_lock);
-       list_for_each_entry(sb, &super_blocks, s_list) {
-               if (hlist_unhashed(&sb->s_instances))
-                       continue;
-               if (sb->s_op->write_super && sb->s_dirt) {
-                       sb->s_count++;
-                       spin_unlock(&sb_lock);
-
-                       down_read(&sb->s_umount);
-                       if (sb->s_root && sb->s_dirt && (sb->s_flags & MS_BORN))
-                               sb->s_op->write_super(sb);
-                       up_read(&sb->s_umount);
-
-                       spin_lock(&sb_lock);
-                       if (p)
-                               __put_super(p);
-                       p = sb;
-               }
-       }
-       if (p)
-               __put_super(p);
-       spin_unlock(&sb_lock);
-}
-
 /**
  *     iterate_supers - call function for all active superblocks
  *     @f: function to call
index 35389ca2d267093895681dc0f01dfa1e5f577d79..7bd6e72afd1136a3141e42227553ba5daa5ffcba 100644 (file)
  *
  * A thing to keep in mind: inode @i_mutex is locked in most VFS operations we
  * implement. However, this is not true for 'ubifs_writepage()', which may be
- * called with @i_mutex unlocked. For example, when pdflush is doing background
- * write-back, it calls 'ubifs_writepage()' with unlocked @i_mutex. At "normal"
- * work-paths the @i_mutex is locked in 'ubifs_writepage()', e.g. in the
- * "sys_write -> alloc_pages -> direct reclaim path". So, in 'ubifs_writepage()'
- * we are only guaranteed that the page is locked.
+ * called with @i_mutex unlocked. For example, when flusher thread is doing
+ * background write-back, it calls 'ubifs_writepage()' with unlocked @i_mutex.
+ * At "normal" work-paths the @i_mutex is locked in 'ubifs_writepage()', e.g.
+ * in the "sys_write -> alloc_pages -> direct reclaim path". So, in
+ * 'ubifs_writepage()' we are only guaranteed that the page is locked.
  *
  * Similarly, @i_mutex is not always locked in 'ubifs_readpage()', e.g., the
  * read-ahead path does not lock it ("sys_read -> generic_file_aio_read ->
index 1c766c39c03819b4d088f19f0215c63a89f2b539..c3fa6c5327a3bb7b6939206c118a9d6ace0ee039 100644 (file)
@@ -303,7 +303,7 @@ static int ubifs_write_inode(struct inode *inode, struct writeback_control *wbc)
        mutex_lock(&ui->ui_mutex);
        /*
         * Due to races between write-back forced by budgeting
-        * (see 'sync_some_inodes()') and pdflush write-back, the inode may
+        * (see 'sync_some_inodes()') and background write-back, the inode may
         * have already been synchronized, do not do this again. This might
         * also happen if it was synchronized in an VFS operation, e.g.
         * 'ubifs_link()'.
index fafaad795cd6da4842a798e25446f6b426d65d65..aa233469b3c1a0deb1e3ef60b8039f5dd2e1cd55 100644 (file)
@@ -1124,14 +1124,17 @@ int udf_setsize(struct inode *inode, loff_t newsize)
                                if (err)
                                        return err;
                                down_write(&iinfo->i_data_sem);
-                       } else
+                       } else {
                                iinfo->i_lenAlloc = newsize;
+                               goto set_size;
+                       }
                }
                err = udf_extend_file(inode, newsize);
                if (err) {
                        up_write(&iinfo->i_data_sem);
                        return err;
                }
+set_size:
                truncate_setsize(inode, newsize);
                up_write(&iinfo->i_data_sem);
        } else {
index dcbf98722afcd5df2a8940f4dbd5c1c8a02c7b40..18fc038a438da4b6bbf58fa73c23c27ecd0cb721 100644 (file)
@@ -1344,6 +1344,7 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block,
                udf_err(sb, "error loading logical volume descriptor: "
                        "Partition table too long (%u > %lu)\n", table_len,
                        sb->s_blocksize - sizeof(*lvd));
+               ret = 1;
                goto out_bh;
        }
 
@@ -1388,8 +1389,10 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block,
                                                UDF_ID_SPARABLE,
                                                strlen(UDF_ID_SPARABLE))) {
                                if (udf_load_sparable_map(sb, map,
-                                   (struct sparablePartitionMap *)gpm) < 0)
+                                   (struct sparablePartitionMap *)gpm) < 0) {
+                                       ret = 1;
                                        goto out_bh;
+                               }
                        } else if (!strncmp(upm2->partIdent.ident,
                                                UDF_ID_METADATA,
                                                strlen(UDF_ID_METADATA))) {
@@ -2000,6 +2003,8 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
                        if (!silent)
                                pr_notice("Rescanning with blocksize %d\n",
                                          UDF_DEFAULT_BLOCKSIZE);
+                       brelse(sbi->s_lvid_bh);
+                       sbi->s_lvid_bh = NULL;
                        uopt.blocksize = UDF_DEFAULT_BLOCKSIZE;
                        ret = udf_load_vrs(sb, &uopt, silent, &fileset);
                }
index f9c3fe304a17fc9ae470c7754294b3f129c78bea..69cf4fcde03e2d31266f70f6dfee1b73fe71b4a7 100644 (file)
@@ -179,12 +179,14 @@ xfs_ioc_trim(
         * used by the fstrim application.  In the end it really doesn't
         * matter as trimming blocks is an advisory interface.
         */
+       if (range.start >= XFS_FSB_TO_B(mp, mp->m_sb.sb_dblocks) ||
+           range.minlen > XFS_FSB_TO_B(mp, XFS_ALLOC_AG_MAX_USABLE(mp)))
+               return -XFS_ERROR(EINVAL);
+
        start = BTOBB(range.start);
        end = start + BTOBBT(range.len) - 1;
        minlen = BTOBB(max_t(u64, granularity, range.minlen));
 
-       if (XFS_BB_TO_FSB(mp, start) >= mp->m_sb.sb_dblocks)
-               return -XFS_ERROR(EINVAL);
        if (end > XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks) - 1)
                end = XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)- 1;
 
index 21e37b55f7e596c6d29c0c0125a755f7a8ada7f6..5aceb3f8ecd625de029daaff00e6093a0e0213a2 100644 (file)
@@ -962,23 +962,22 @@ xfs_dialloc(
                if (!pag->pagi_freecount && !okalloc)
                        goto nextag;
 
+               /*
+                * Then read in the AGI buffer and recheck with the AGI buffer
+                * lock held.
+                */
                error = xfs_ialloc_read_agi(mp, tp, agno, &agbp);
                if (error)
                        goto out_error;
 
-               /*
-                * Once the AGI has been read in we have to recheck
-                * pagi_freecount with the AGI buffer lock held.
-                */
                if (pag->pagi_freecount) {
                        xfs_perag_put(pag);
                        goto out_alloc;
                }
 
-               if (!okalloc) {
-                       xfs_trans_brelse(tp, agbp);
-                       goto nextag;
-               }
+               if (!okalloc)
+                       goto nextag_relse_buffer;
+
 
                error = xfs_ialloc_ag_alloc(tp, agbp, &ialloced);
                if (error) {
@@ -1007,6 +1006,8 @@ xfs_dialloc(
                        return 0;
                }
 
+nextag_relse_buffer:
+               xfs_trans_brelse(tp, agbp);
 nextag:
                xfs_perag_put(pag);
                if (++agno == mp->m_sb.sb_agcount)
index 05a05a7b611963f03d0249a97cb5edbc50c152a6..deee09e534dcf35de23535bfa6ce94f6ffa750a6 100644 (file)
@@ -54,12 +54,7 @@ typedef struct xfs_trans_reservations {
 #include "xfs_sync.h"
 
 struct xlog;
-struct xfs_mount_args;
 struct xfs_inode;
-struct xfs_bmbt_irec;
-struct xfs_bmap_free;
-struct xfs_extdelta;
-struct xfs_swapext;
 struct xfs_mru_cache;
 struct xfs_nameops;
 struct xfs_ail;
index 92d4331cd4f1c118ea0a0087849d399a3948f230..ca28a4ba4b548f0c379291bfb0e716ac3a9ec54e 100644 (file)
@@ -857,7 +857,7 @@ xfs_rtbuf_get(
        xfs_buf_t       *bp;            /* block buffer, result */
        xfs_inode_t     *ip;            /* bitmap or summary inode */
        xfs_bmbt_irec_t map;
-       int             nmap;
+       int             nmap = 1;
        int             error;          /* error value */
 
        ip = issum ? mp->m_rsumip : mp->m_rbmip;
index e5795dd6013ad2b34d5a208d1cf7ad448c937387..7d36ccf57f93236c5d8228c158b3ff5ba0886672 100644 (file)
@@ -37,6 +37,7 @@ struct xlog_recover;
 struct xlog_recover_item;
 struct xfs_buf_log_format;
 struct xfs_inode_log_format;
+struct xfs_bmbt_irec;
 
 DECLARE_EVENT_CLASS(xfs_attr_list_class,
        TP_PROTO(struct xfs_attr_list_context *ctx),
index 2c744c7a5b3dcdd452d1c531884faa0ed0a3e29b..26a92fc28a590ce68a198b326632835f46cda1d9 100644 (file)
@@ -491,11 +491,11 @@ acpi_get_sleep_type_data(u8 sleep_state, u8 * slp_typ_a, u8 * slp_typ_b);
 
 acpi_status acpi_enter_sleep_state_prep(u8 sleep_state);
 
-acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state, u8 flags);
+acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state);
 
 ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status asmlinkage acpi_enter_sleep_state_s4bios(void))
 
-acpi_status acpi_leave_sleep_state_prep(u8 sleep_state, u8 flags);
+acpi_status acpi_leave_sleep_state_prep(u8 sleep_state);
 
 acpi_status acpi_leave_sleep_state(u8 sleep_state);
 
index 3af87de6a68cd1a9afbcf21aaa4a47151158416e..3d00bd5bd7e30bdfb11689512f7e502d22d4ab71 100644 (file)
@@ -803,7 +803,7 @@ typedef u8 acpi_adr_space_type;
 
 /* Sleep function dispatch */
 
-typedef acpi_status(*ACPI_SLEEP_FUNCTION) (u8 sleep_state, u8 flags);
+typedef acpi_status(*ACPI_SLEEP_FUNCTION) (u8 sleep_state);
 
 struct acpi_sleep_functions {
        ACPI_SLEEP_FUNCTION legacy_function;
index ed5b44de4c915b27b61a2ef77dc58d0c69ecc569..14dc41d185a7a3163bc59f45a9df37588584fb65 100644 (file)
@@ -5,18 +5,44 @@
  * Many architectures just need a simple module
  * loader without arch specific data.
  */
+#ifndef CONFIG_HAVE_MOD_ARCH_SPECIFIC
 struct mod_arch_specific
 {
 };
+#endif
 
 #ifdef CONFIG_64BIT
-#define Elf_Shdr Elf64_Shdr
-#define Elf_Sym Elf64_Sym
-#define Elf_Ehdr Elf64_Ehdr
-#else
-#define Elf_Shdr Elf32_Shdr
-#define Elf_Sym Elf32_Sym
-#define Elf_Ehdr Elf32_Ehdr
+#define Elf_Shdr       Elf64_Shdr
+#define Elf_Phdr       Elf64_Phdr
+#define Elf_Sym                Elf64_Sym
+#define Elf_Dyn                Elf64_Dyn
+#define Elf_Ehdr       Elf64_Ehdr
+#define Elf_Addr       Elf64_Addr
+#ifdef CONFIG_MODULES_USE_ELF_REL
+#define Elf_Rel                Elf64_Rel
+#endif
+#ifdef CONFIG_MODULES_USE_ELF_RELA
+#define Elf_Rela       Elf64_Rela
+#endif
+#define ELF_R_TYPE(X)  ELF64_R_TYPE(X)
+#define ELF_R_SYM(X)   ELF64_R_SYM(X)
+
+#else /* CONFIG_64BIT */
+
+#define Elf_Shdr       Elf32_Shdr
+#define Elf_Phdr       Elf32_Phdr
+#define Elf_Sym                Elf32_Sym
+#define Elf_Dyn                Elf32_Dyn
+#define Elf_Ehdr       Elf32_Ehdr
+#define Elf_Addr       Elf32_Addr
+#ifdef CONFIG_MODULES_USE_ELF_REL
+#define Elf_Rel                Elf32_Rel
+#endif
+#ifdef CONFIG_MODULES_USE_ELF_RELA
+#define Elf_Rela       Elf32_Rela
+#endif
+#define ELF_R_TYPE(X)  ELF32_R_TYPE(X)
+#define ELF_R_SYM(X)   ELF32_R_SYM(X)
 #endif
 
 #endif /* __ASM_GENERIC_MODULE_H */
index 4e2e1cc505ab2f1ddbbf54e93353685d202efd79..d1ea7ce0b4cb95c9e61935aefbcb09c12f49bdbc 100644 (file)
                *(.scommon)                                             \
        }
 
+/*
+ * Allow archectures to redefine BSS_FIRST_SECTIONS to add extra
+ * sections to the front of bss.
+ */
+#ifndef BSS_FIRST_SECTIONS
+#define BSS_FIRST_SECTIONS
+#endif
+
 #define BSS(bss_align)                                                 \
        . = ALIGN(bss_align);                                           \
        .bss : AT(ADDR(.bss) - LOAD_OFFSET) {                           \
+               BSS_FIRST_SECTIONS                                      \
                *(.bss..page_aligned)                                   \
                *(.dynbss)                                              \
                *(.bss)                                                 \
diff --git a/include/crypto/cast5.h b/include/crypto/cast5.h
new file mode 100644 (file)
index 0000000..dcb90c1
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef _CRYPTO_CAST5_H
+#define _CRYPTO_CAST5_H
+
+#include <linux/types.h>
+#include <linux/crypto.h>
+
+#define CAST5_BLOCK_SIZE 8
+#define CAST5_MIN_KEY_SIZE 5
+#define CAST5_MAX_KEY_SIZE 16
+
+struct cast5_ctx {
+       u32 Km[16];
+       u8 Kr[16];
+       int rr; /* rr ? rounds = 12 : rounds = 16; (rfc 2144) */
+};
+
+int cast5_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen);
+
+void __cast5_encrypt(struct cast5_ctx *ctx, u8 *dst, const u8 *src);
+void __cast5_decrypt(struct cast5_ctx *ctx, u8 *dst, const u8 *src);
+
+#endif
diff --git a/include/crypto/cast6.h b/include/crypto/cast6.h
new file mode 100644 (file)
index 0000000..02dde6b
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef _CRYPTO_CAST6_H
+#define _CRYPTO_CAST6_H
+
+#include <linux/types.h>
+#include <linux/crypto.h>
+
+#define CAST6_BLOCK_SIZE 16
+#define CAST6_MIN_KEY_SIZE 16
+#define CAST6_MAX_KEY_SIZE 32
+
+struct cast6_ctx {
+       u32 Km[12][4];
+       u8 Kr[12][4];
+};
+
+int __cast6_setkey(struct cast6_ctx *ctx, const u8 *key,
+                  unsigned int keylen, u32 *flags);
+int cast6_setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen);
+
+void __cast6_encrypt(struct cast6_ctx *ctx, u8 *dst, const u8 *src);
+void __cast6_decrypt(struct cast6_ctx *ctx, u8 *dst, const u8 *src);
+
+#endif
index 5bfad8c8059580d9668c72e9acf9f056f24b928c..821eae8cbd8cf131bdbcc41dd46de828e700269a 100644 (file)
@@ -83,6 +83,8 @@ struct hash_alg_common *ahash_attr_alg(struct rtattr *rta, u32 type, u32 mask);
 
 int crypto_register_shash(struct shash_alg *alg);
 int crypto_unregister_shash(struct shash_alg *alg);
+int crypto_register_shashes(struct shash_alg *algs, int count);
+int crypto_unregister_shashes(struct shash_alg *algs, int count);
 int shash_register_instance(struct crypto_template *tmpl,
                            struct shash_instance *inst);
 void shash_free_instance(struct crypto_instance *inst);
index 7ff5c99b16389330e21110a8c43b3b8877484f82..c78bb997e2c60846a1f5e261664d96ee1656fe6d 100644 (file)
        {0x1002, 0x6800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6801, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6802, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x6806, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6808, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6809, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6810, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x6816, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \
+       {0x1002, 0x6817, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6818, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6819, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PITCAIRN|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x6820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VERDE|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
index 58056865b8e9601bc40da73198a82d0bcb406960..dc3a8cd7db8a0741ff5b4478476e8d0e3d566b9c 100644 (file)
@@ -964,6 +964,8 @@ struct drm_radeon_cs {
 #define RADEON_INFO_IB_VM_MAX_SIZE     0x0f
 /* max pipes - needed for compute shaders */
 #define RADEON_INFO_MAX_PIPES          0x10
+/* timestamp for GL_ARB_timer_query (OpenGL), returns the current GPU clock */
+#define RADEON_INFO_TIMESTAMP          0x11
 
 struct drm_radeon_info {
        uint32_t                request;
index d9a7544748785d020ba77f74392fb1275fbe02fd..b3d6385a52115b87d28d4e9e8a2cb9d93579afe4 100644 (file)
@@ -84,7 +84,6 @@ header-y += capability.h
 header-y += capi.h
 header-y += cciss_defs.h
 header-y += cciss_ioctl.h
-header-y += cdk.h
 header-y += cdrom.h
 header-y += cgroupstats.h
 header-y += chio.h
@@ -93,7 +92,6 @@ header-y += cn_proc.h
 header-y += coda.h
 header-y += coda_psdev.h
 header-y += coff.h
-header-y += comstats.h
 header-y += connector.h
 header-y += const.h
 header-y += cramfs_fs.h
@@ -140,7 +138,6 @@ header-y += fuse.h
 header-y += futex.h
 header-y += gameport.h
 header-y += gen_stats.h
-header-y += generic_serial.h
 header-y += genetlink.h
 header-y += gfs2_ondisk.h
 header-y += gigaset_dev.h
@@ -195,6 +192,7 @@ header-y += in_route.h
 header-y += sock_diag.h
 header-y += inet_diag.h
 header-y += unix_diag.h
+header-y += packet_diag.h
 header-y += inotify.h
 header-y += input.h
 header-y += ioctl.h
@@ -391,6 +389,7 @@ header-y += v4l2-dv-timings.h
 header-y += v4l2-mediabus.h
 header-y += v4l2-subdev.h
 header-y += veth.h
+header-y += vfio.h
 header-y += vhost.h
 header-y += videodev2.h
 header-y += virtio_9p.h
index 3ad510b25283ee1e5285929b702d739fb0afc31a..4f2a76224509ef5c652a8503153ca73435b9dde1 100644 (file)
@@ -96,7 +96,7 @@ void acpi_table_print_madt_entry (struct acpi_subtable_header *madt);
 void acpi_numa_slit_init (struct acpi_table_slit *slit);
 void acpi_numa_processor_affinity_init (struct acpi_srat_cpu_affinity *pa);
 void acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa);
-void acpi_numa_memory_affinity_init (struct acpi_srat_mem_affinity *ma);
+int acpi_numa_memory_affinity_init (struct acpi_srat_mem_affinity *ma);
 void acpi_numa_arch_fixup(void);
 
 #ifdef CONFIG_ACPI_HOTPLUG_CPU
index 1d14b1dc1aee69588ce68329e5fa71189d277016..89a931babecf86ebbf95c6a0e8b648840d06ad06 100644 (file)
@@ -63,7 +63,7 @@ struct atmel_tc {
        struct platform_device  *pdev;
        struct resource         *iomem;
        void __iomem            *regs;
-       struct atmel_tcb_config *tcb_config;
+       const struct atmel_tcb_config *tcb_config;
        int                     irq[3];
        struct clk              *clk[3];
        struct list_head        node;
index c97c6b9cd38ee34e501735758de2b710decceae0..2a9a9abc91260c09a7940136a965a08209c5828b 100644 (file)
@@ -124,7 +124,6 @@ void bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages,
 void bdi_start_background_writeback(struct backing_dev_info *bdi);
 int bdi_writeback_thread(void *data);
 int bdi_has_dirty_io(struct backing_dev_info *bdi);
-void bdi_arm_supers_timer(void);
 void bdi_wakeup_thread_delayed(struct backing_dev_info *bdi);
 void bdi_lock_two(struct bdi_writeback *wb1, struct bdi_writeback *wb2);
 
index 3c80885fa829dcb6fe60616b9aba6e85bea550fb..3fb8bbafe5e7f70f69614e2730aefc914fb0083d 100644 (file)
 #define  BCMA_CC_CHIPST_4313_OTP_PRESENT       2
 #define  BCMA_CC_CHIPST_4331_SPROM_PRESENT     2
 #define  BCMA_CC_CHIPST_4331_OTP_PRESENT       4
+#define  BCMA_CC_CHIPST_43228_ILP_DIV_EN       0x00000001
+#define  BCMA_CC_CHIPST_43228_OTP_PRESENT      0x00000002
+#define  BCMA_CC_CHIPST_43228_SERDES_REFCLK_PADSEL     0x00000004
+#define  BCMA_CC_CHIPST_43228_SDIO_MODE                0x00000008
+#define  BCMA_CC_CHIPST_43228_SDIO_OTP_PRESENT 0x00000010
+#define  BCMA_CC_CHIPST_43228_SDIO_RESET       0x00000020
 #define  BCMA_CC_CHIPST_4706_PKG_OPTION                BIT(0) /* 0: full-featured package 1: low-cost package */
 #define  BCMA_CC_CHIPST_4706_SFLASH_PRESENT    BIT(1) /* 0: parallel, 1: serial flash is present */
 #define  BCMA_CC_CHIPST_4706_SFLASH_TYPE       BIT(2) /* 0: 8b-p/ST-s flash, 1: 16b-p/Atmal-s flash */
 #define  BCMA_CC_CHIPST_4706_MIPS_BENDIAN      BIT(3) /* 0: little, 1: big endian */
 #define  BCMA_CC_CHIPST_4706_PCIE1_DISABLE     BIT(5) /* PCIE1 enable strap pin */
+#define  BCMA_CC_CHIPST_5357_NAND_BOOT         BIT(4) /* NAND boot, valid for CC rev 38 and/or BCM5357 */
 #define BCMA_CC_JCMD                   0x0030          /* Rev >= 10 only */
 #define  BCMA_CC_JCMD_START            0x80000000
 #define  BCMA_CC_JCMD_BUSY             0x80000000
 #define  BCMA_CC_SROM_CONTROL_SIZE_16K 0x00000004
 #define  BCMA_CC_SROM_CONTROL_SIZE_SHIFT       1
 #define  BCMA_CC_SROM_CONTROL_PRESENT  0x00000001
+/* Block 0x140 - 0x190 registers are chipset specific */
+#define BCMA_CC_4706_FLASHSCFG         0x18C           /* Flash struct configuration */
+#define  BCMA_CC_4706_FLASHSCFG_MASK   0x000000ff
+#define  BCMA_CC_4706_FLASHSCFG_SF1    0x00000001      /* 2nd serial flash present */
+#define  BCMA_CC_4706_FLASHSCFG_PF1    0x00000002      /* 2nd parallel flash present */
+#define  BCMA_CC_4706_FLASHSCFG_SF1_TYPE       0x00000004      /* 2nd serial flash type : 0 : ST, 1 : Atmel */
+#define  BCMA_CC_4706_FLASHSCFG_NF1    0x00000008      /* 2nd NAND flash present */
+#define  BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_MASK     0x000000f0
+#define  BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_4MB      0x00000010      /* 4MB */
+#define  BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_8MB      0x00000020      /* 8MB */
+#define  BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_16MB     0x00000030      /* 16MB */
+#define  BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_32MB     0x00000040      /* 32MB */
+#define  BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_64MB     0x00000050      /* 64MB */
+#define  BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_128MB    0x00000060      /* 128MB */
+#define  BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_256MB    0x00000070      /* 256MB */
+/* NAND flash registers for BCM4706 (corerev = 31) */
+#define BCMA_CC_NFLASH_CTL             0x01A0
+#define  BCMA_CC_NFLASH_CTL_ERR                0x08000000
+#define BCMA_CC_NFLASH_CONF            0x01A4
+#define BCMA_CC_NFLASH_COL_ADDR                0x01A8
+#define BCMA_CC_NFLASH_ROW_ADDR                0x01AC
+#define BCMA_CC_NFLASH_DATA            0x01B0
+#define BCMA_CC_NFLASH_WAITCNT0                0x01B4
 /* 0x1E0 is defined as shared BCMA_CLKCTLST */
 #define BCMA_CC_HW_WORKAROUND          0x01E4 /* Hardware workaround (rev >= 20) */
 #define BCMA_CC_UART0_DATA             0x0300
 #define BCMA_CC_PLLCTL_ADDR            0x0660
 #define BCMA_CC_PLLCTL_DATA            0x0664
 #define BCMA_CC_SPROM                  0x0800 /* SPROM beginning */
+/* NAND flash MLC controller registers (corerev >= 38) */
+#define BCMA_CC_NAND_REVISION          0x0C00
+#define BCMA_CC_NAND_CMD_START         0x0C04
+#define BCMA_CC_NAND_CMD_ADDR_X                0x0C08
+#define BCMA_CC_NAND_CMD_ADDR          0x0C0C
+#define BCMA_CC_NAND_CMD_END_ADDR      0x0C10
+#define BCMA_CC_NAND_CS_NAND_SELECT    0x0C14
+#define BCMA_CC_NAND_CS_NAND_XOR       0x0C18
+#define BCMA_CC_NAND_SPARE_RD0         0x0C20
+#define BCMA_CC_NAND_SPARE_RD4         0x0C24
+#define BCMA_CC_NAND_SPARE_RD8         0x0C28
+#define BCMA_CC_NAND_SPARE_RD12                0x0C2C
+#define BCMA_CC_NAND_SPARE_WR0         0x0C30
+#define BCMA_CC_NAND_SPARE_WR4         0x0C34
+#define BCMA_CC_NAND_SPARE_WR8         0x0C38
+#define BCMA_CC_NAND_SPARE_WR12                0x0C3C
+#define BCMA_CC_NAND_ACC_CONTROL       0x0C40
+#define BCMA_CC_NAND_CONFIG            0x0C48
+#define BCMA_CC_NAND_TIMING_1          0x0C50
+#define BCMA_CC_NAND_TIMING_2          0x0C54
+#define BCMA_CC_NAND_SEMAPHORE         0x0C58
+#define BCMA_CC_NAND_DEVID             0x0C60
+#define BCMA_CC_NAND_DEVID_X           0x0C64
+#define BCMA_CC_NAND_BLOCK_LOCK_STATUS 0x0C68
+#define BCMA_CC_NAND_INTFC_STATUS      0x0C6C
+#define BCMA_CC_NAND_ECC_CORR_ADDR_X   0x0C70
+#define BCMA_CC_NAND_ECC_CORR_ADDR     0x0C74
+#define BCMA_CC_NAND_ECC_UNC_ADDR_X    0x0C78
+#define BCMA_CC_NAND_ECC_UNC_ADDR      0x0C7C
+#define BCMA_CC_NAND_READ_ERROR_COUNT  0x0C80
+#define BCMA_CC_NAND_CORR_STAT_THRESHOLD       0x0C84
+#define BCMA_CC_NAND_READ_ADDR_X       0x0C90
+#define BCMA_CC_NAND_READ_ADDR         0x0C94
+#define BCMA_CC_NAND_PAGE_PROGRAM_ADDR_X       0x0C98
+#define BCMA_CC_NAND_PAGE_PROGRAM_ADDR 0x0C9C
+#define BCMA_CC_NAND_COPY_BACK_ADDR_X  0x0CA0
+#define BCMA_CC_NAND_COPY_BACK_ADDR    0x0CA4
+#define BCMA_CC_NAND_BLOCK_ERASE_ADDR_X        0x0CA8
+#define BCMA_CC_NAND_BLOCK_ERASE_ADDR  0x0CAC
+#define BCMA_CC_NAND_INV_READ_ADDR_X   0x0CB0
+#define BCMA_CC_NAND_INV_READ_ADDR     0x0CB4
+#define BCMA_CC_NAND_BLK_WR_PROTECT    0x0CC0
+#define BCMA_CC_NAND_ACC_CONTROL_CS1   0x0CD0
+#define BCMA_CC_NAND_CONFIG_CS1                0x0CD4
+#define BCMA_CC_NAND_TIMING_1_CS1      0x0CD8
+#define BCMA_CC_NAND_TIMING_2_CS1      0x0CDC
+#define BCMA_CC_NAND_SPARE_RD16                0x0D30
+#define BCMA_CC_NAND_SPARE_RD20                0x0D34
+#define BCMA_CC_NAND_SPARE_RD24                0x0D38
+#define BCMA_CC_NAND_SPARE_RD28                0x0D3C
+#define BCMA_CC_NAND_CACHE_ADDR                0x0D40
+#define BCMA_CC_NAND_CACHE_DATA                0x0D44
+#define BCMA_CC_NAND_CTRL_CONFIG       0x0D48
+#define BCMA_CC_NAND_CTRL_STATUS       0x0D4C
 
 /* Divider allocation in 4716/47162/5356 */
 #define BCMA_CC_PMU5_MAINPLL_CPU       1
 /* 4313 Chip specific ChipControl register bits */
 #define BCMA_CCTRL_4313_12MA_LED_DRIVE         0x00000007      /* 12 mA drive strengh for later 4313 */
 
+/* BCM5357 ChipControl register bits */
+#define BCMA_CHIPCTL_5357_EXTPA                        BIT(14)
+#define BCMA_CHIPCTL_5357_ANT_MUX_2O3          BIT(15)
+#define BCMA_CHIPCTL_5357_NFLASH               BIT(16)
+#define BCMA_CHIPCTL_5357_I2S_PINS_ENABLE      BIT(18)
+#define BCMA_CHIPCTL_5357_I2CSPI_PINS_ENABLE   BIT(19)
+
 /* Data for the PMU, if available.
  * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
  */
index 5a71d57196404780ab587458ac1826343fd74c1c..a393e82bf7bfe18e23173076d6f9e63d0c69dc16 100644 (file)
 #define  BCMA_CLKCTLST_HAVEHTREQ       0x00000010 /* HT available request */
 #define  BCMA_CLKCTLST_HWCROFF         0x00000020 /* Force HW clock request off */
 #define  BCMA_CLKCTLST_EXTRESREQ       0x00000700 /* Mask of external resource requests */
+#define  BCMA_CLKCTLST_EXTRESREQ_SHIFT 8
 #define  BCMA_CLKCTLST_HAVEALP         0x00010000 /* ALP available */
 #define  BCMA_CLKCTLST_HAVEHT          0x00020000 /* HT available */
 #define  BCMA_CLKCTLST_BP_ON_ALP       0x00040000 /* RO: running on ALP clock */
 #define  BCMA_CLKCTLST_BP_ON_HT                0x00080000 /* RO: running on HT clock */
 #define  BCMA_CLKCTLST_EXTRESST                0x07000000 /* Mask of external resource status */
+#define  BCMA_CLKCTLST_EXTRESST_SHIFT  24
 /* Is there any BCM4328 on BCMA bus? */
 #define  BCMA_CLKCTLST_4328A0_HAVEHT   0x00010000 /* 4328a0 has reversed bits */
 #define  BCMA_CLKCTLST_4328A0_HAVEALP  0x00020000 /* 4328a0 has reversed bits */
index 4e72a9d48232d513b5b2fe44d973de8dfeb1e9e4..4a2ab7c85393df48fd8d93e085f3b7ead5de7be2 100644 (file)
@@ -601,7 +601,7 @@ static inline void blk_clear_rl_full(struct request_list *rl, bool sync)
  * it already be started by driver.
  */
 #define RQ_NOMERGE_FLAGS       \
-       (REQ_NOMERGE | REQ_STARTED | REQ_SOFTBARRIER | REQ_FLUSH | REQ_FUA)
+       (REQ_NOMERGE | REQ_STARTED | REQ_SOFTBARRIER | REQ_FLUSH | REQ_FUA | REQ_DISCARD)
 #define rq_mergeable(rq)       \
        (!((rq)->cmd_flags & RQ_NOMERGE_FLAGS) && \
         (((rq)->cmd_flags & REQ_DISCARD) || \
@@ -894,6 +894,8 @@ extern void blk_queue_flush_queueable(struct request_queue *q, bool queueable);
 extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev);
 
 extern int blk_rq_map_sg(struct request_queue *, struct request *, struct scatterlist *);
+extern int blk_bio_map_sg(struct request_queue *q, struct bio *bio,
+                         struct scatterlist *sglist);
 extern void blk_dump_rq_flags(struct request *, char *);
 extern long nr_blockdev_pages(void);
 
@@ -1139,6 +1141,16 @@ static inline int queue_limit_discard_alignment(struct queue_limits *lim, sector
                & (lim->discard_granularity - 1);
 }
 
+static inline int bdev_discard_alignment(struct block_device *bdev)
+{
+       struct request_queue *q = bdev_get_queue(bdev);
+
+       if (bdev != bdev->bd_contains)
+               return bdev->bd_part->discard_alignment;
+
+       return q->limits.discard_alignment;
+}
+
 static inline unsigned int queue_discard_zeroes_data(struct request_queue *q)
 {
        if (q->limits.max_discard_sectors && q->limits.discard_zeroes_data == 1)
index 018055efc0343b2a8f7e800255ff53b9e10a3584..e52958d7c2d119cb416587466f4a4d2a5bb1e8d0 100644 (file)
@@ -74,20 +74,21 @@ struct can_frame {
 /*
  * defined bits for canfd_frame.flags
  *
- * As the default for CAN FD should be to support the high data rate in the
- * payload section of the frame (HDR) and to support up to 64 byte in the
- * data section (EDL) the bits are only set in the non-default case.
- * Btw. as long as there's no real implementation for CAN FD network driver
- * these bits are only preliminary.
+ * The use of struct canfd_frame implies the Extended Data Length (EDL) bit to
+ * be set in the CAN frame bitstream on the wire. The EDL bit switch turns
+ * the CAN controllers bitstream processor into the CAN FD mode which creates
+ * two new options within the CAN FD frame specification:
  *
- * RX: NOHDR/NOEDL - info about received CAN FD frame
- *     ESI         - bit from originating CAN controller
- * TX: NOHDR/NOEDL - control per-frame settings if supported by CAN controller
- *     ESI         - bit is set by local CAN controller
+ * Bit Rate Switch - to indicate a second bitrate is/was used for the payload
+ * Error State Indicator - represents the error state of the transmitting node
+ *
+ * As the CANFD_ESI bit is internally generated by the transmitting CAN
+ * controller only the CANFD_BRS bit is relevant for real CAN controllers when
+ * building a CAN FD frame for transmission. Setting the CANFD_ESI bit can make
+ * sense for virtual CAN interfaces to test applications with echoed frames.
  */
-#define CANFD_NOHDR 0x01 /* frame without high data rate */
-#define CANFD_NOEDL 0x02 /* frame without extended data length */
-#define CANFD_ESI   0x04 /* error state indicator */
+#define CANFD_BRS 0x01 /* bit rate switch (second bitrate for payload data) */
+#define CANFD_ESI 0x02 /* error state indicator of the transmitting node */
 
 /**
  * struct canfd_frame - CAN flexible data rate frame structure
diff --git a/include/linux/cd1400.h b/include/linux/cd1400.h
deleted file mode 100644 (file)
index 1dc3ab0..0000000
+++ /dev/null
@@ -1,292 +0,0 @@
-/*****************************************************************************/
-
-/*
- *     cd1400.h  -- cd1400 UART hardware info.
- *
- *     Copyright (C) 1996-1998  Stallion Technologies
- *     Copyright (C) 1994-1996  Greg Ungerer.
- *
- *     This program is free software; you can redistribute it and/or modify
- *     it under the terms of the GNU General Public License as published by
- *     the Free Software Foundation; either version 2 of the License, or
- *     (at your option) any later version.
- *
- *     This program is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public License
- *     along with this program; if not, write to the Free Software
- *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/*****************************************************************************/
-#ifndef        _CD1400_H
-#define        _CD1400_H
-/*****************************************************************************/
-
-/*
- *     Define the number of async ports per cd1400 uart chip.
- */
-#define        CD1400_PORTS            4
-
-/*
- *     Define the cd1400 uarts internal FIFO sizes.
- */
-#define        CD1400_TXFIFOSIZE       12
-#define        CD1400_RXFIFOSIZE       12
-
-/*
- *     Local RX FIFO thresh hold level. Also define the RTS thresh hold
- *     based on the RX thresh hold.
- */
-#define        FIFO_RXTHRESHOLD        6
-#define        FIFO_RTSTHRESHOLD       7
-
-/*****************************************************************************/
-
-/*
- *     Define the cd1400 register addresses. These are all the valid
- *     registers with the cd1400. Some are global, some virtual, some
- *     per port.
- */
-#define        GFRCR           0x40
-#define        CAR             0x68
-#define        GCR             0x4b
-#define        SVRR            0x67
-#define        RICR            0x44
-#define        TICR            0x45
-#define        MICR            0x46
-#define        RIR             0x6b
-#define        TIR             0x6a
-#define        MIR             0x69
-#define        PPR             0x7e
-
-#define        RIVR            0x43
-#define        TIVR            0x42
-#define        MIVR            0x41
-#define        TDR             0x63
-#define        RDSR            0x62
-#define        MISR            0x4c
-#define        EOSRR           0x60
-
-#define        LIVR            0x18
-#define        CCR             0x05
-#define        SRER            0x06
-#define        COR1            0x08
-#define        COR2            0x09
-#define        COR3            0x0a
-#define        COR4            0x1e
-#define        COR5            0x1f
-#define        CCSR            0x0b
-#define        RDCR            0x0e
-#define        SCHR1           0x1a
-#define        SCHR2           0x1b
-#define        SCHR3           0x1c
-#define        SCHR4           0x1d
-#define        SCRL            0x22
-#define        SCRH            0x23
-#define        LNC             0x24
-#define        MCOR1           0x15
-#define        MCOR2           0x16
-#define        RTPR            0x21
-#define        MSVR1           0x6c
-#define        MSVR2           0x6d
-#define        PSVR            0x6f
-#define        RBPR            0x78
-#define        RCOR            0x7c
-#define        TBPR            0x72
-#define        TCOR            0x76
-
-/*****************************************************************************/
-
-/*
- *     Define the set of baud rate clock divisors.
- */
-#define        CD1400_CLK0     8
-#define        CD1400_CLK1     32
-#define        CD1400_CLK2     128
-#define        CD1400_CLK3     512
-#define        CD1400_CLK4     2048
-
-#define        CD1400_NUMCLKS  5
-
-/*****************************************************************************/
-
-/*
- *     Define the clock pre-scalar value to be a 5 ms clock. This should be
- *     OK for now. It would probably be better to make it 10 ms, but we
- *     can't fit that divisor into 8 bits!
- */
-#define        PPR_SCALAR      244
-
-/*****************************************************************************/
-
-/*
- *     Define values used to set character size options.
- */
-#define        COR1_CHL5       0x00
-#define        COR1_CHL6       0x01
-#define        COR1_CHL7       0x02
-#define        COR1_CHL8       0x03
-
-/*
- *     Define values used to set the number of stop bits.
- */
-#define        COR1_STOP1      0x00
-#define        COR1_STOP15     0x04
-#define        COR1_STOP2      0x08
-
-/*
- *     Define values used to set the parity scheme in use.
- */
-#define        COR1_PARNONE    0x00
-#define        COR1_PARFORCE   0x20
-#define        COR1_PARENB     0x40
-#define        COR1_PARIGNORE  0x10
-
-#define        COR1_PARODD     0x80
-#define        COR1_PAREVEN    0x00
-
-#define        COR2_IXM        0x80
-#define        COR2_TXIBE      0x40
-#define        COR2_ETC        0x20
-#define        COR2_LLM        0x10
-#define        COR2_RLM        0x08
-#define        COR2_RTSAO      0x04
-#define        COR2_CTSAE      0x02
-
-#define        COR3_SCDRNG     0x80
-#define        COR3_SCD34      0x40
-#define        COR3_FCT        0x20
-#define        COR3_SCD12      0x10
-
-/*
- *     Define values used by COR4.
- */
-#define        COR4_BRKINT     0x08
-#define        COR4_IGNBRK     0x18
-
-/*****************************************************************************/
-
-/*
- *     Define the modem control register values.
- *     Note that the actual hardware is a little different to the conventional
- *     pin names on the cd1400.
- */
-#define        MSVR1_DTR       0x01
-#define        MSVR1_DSR       0x10
-#define        MSVR1_RI        0x20
-#define        MSVR1_CTS       0x40
-#define        MSVR1_DCD       0x80
-
-#define        MSVR2_RTS       0x02
-#define        MSVR2_DSR       0x10
-#define        MSVR2_RI        0x20
-#define        MSVR2_CTS       0x40
-#define        MSVR2_DCD       0x80
-
-#define        MCOR1_DCD       0x80
-#define        MCOR1_CTS       0x40
-#define        MCOR1_RI        0x20
-#define        MCOR1_DSR       0x10
-
-#define        MCOR2_DCD       0x80
-#define        MCOR2_CTS       0x40
-#define        MCOR2_RI        0x20
-#define        MCOR2_DSR       0x10
-
-/*****************************************************************************/
-
-/*
- *     Define the bits used with the service (interrupt) enable register.
- */
-#define        SRER_NNDT       0x01
-#define        SRER_TXEMPTY    0x02
-#define        SRER_TXDATA     0x04
-#define        SRER_RXDATA     0x10
-#define        SRER_MODEM      0x80
-
-/*****************************************************************************/
-
-/*
- *     Define operational commands for the command register.
- */
-#define        CCR_RESET       0x80
-#define        CCR_CORCHANGE   0x4e
-#define        CCR_SENDCH      0x20
-#define        CCR_CHANCTRL    0x10
-
-#define        CCR_TXENABLE    (CCR_CHANCTRL | 0x08)
-#define        CCR_TXDISABLE   (CCR_CHANCTRL | 0x04)
-#define        CCR_RXENABLE    (CCR_CHANCTRL | 0x02)
-#define        CCR_RXDISABLE   (CCR_CHANCTRL | 0x01)
-
-#define        CCR_SENDSCHR1   (CCR_SENDCH | 0x01)
-#define        CCR_SENDSCHR2   (CCR_SENDCH | 0x02)
-#define        CCR_SENDSCHR3   (CCR_SENDCH | 0x03)
-#define        CCR_SENDSCHR4   (CCR_SENDCH | 0x04)
-
-#define        CCR_RESETCHAN   (CCR_RESET | 0x00)
-#define        CCR_RESETFULL   (CCR_RESET | 0x01)
-#define        CCR_TXFLUSHFIFO (CCR_RESET | 0x02)
-
-#define        CCR_MAXWAIT     10000
-
-/*****************************************************************************/
-
-/*
- *     Define the valid acknowledgement types (for hw ack cycle).
- */
-#define        ACK_TYPMASK     0x07
-#define        ACK_TYPTX       0x02
-#define        ACK_TYPMDM      0x01
-#define        ACK_TYPRXGOOD   0x03
-#define        ACK_TYPRXBAD    0x07
-
-#define        SVRR_RX         0x01
-#define        SVRR_TX         0x02
-#define        SVRR_MDM        0x04
-
-#define        ST_OVERRUN      0x01
-#define        ST_FRAMING      0x02
-#define        ST_PARITY       0x04
-#define        ST_BREAK        0x08
-#define        ST_SCHAR1       0x10
-#define        ST_SCHAR2       0x20
-#define        ST_SCHAR3       0x30
-#define        ST_SCHAR4       0x40
-#define        ST_RANGE        0x70
-#define        ST_SCHARMASK    0x70
-#define        ST_TIMEOUT      0x80
-
-#define        MISR_DCD        0x80
-#define        MISR_CTS        0x40
-#define        MISR_RI         0x20
-#define        MISR_DSR        0x10
-
-/*****************************************************************************/
-
-/*
- *     Defines for the CCSR status register.
- */
-#define        CCSR_RXENABLED  0x80
-#define        CCSR_RXFLOWON   0x40
-#define        CCSR_RXFLOWOFF  0x20
-#define        CCSR_TXENABLED  0x08
-#define        CCSR_TXFLOWON   0x04
-#define        CCSR_TXFLOWOFF  0x02
-
-/*****************************************************************************/
-
-/*
- *     Define the embedded commands.
- */
-#define        ETC_CMD         0x00
-#define        ETC_STARTBREAK  0x81
-#define        ETC_DELAY       0x82
-#define        ETC_STOPBREAK   0x83
-
-/*****************************************************************************/
-#endif
diff --git a/include/linux/cdk.h b/include/linux/cdk.h
deleted file mode 100644 (file)
index 80093a8..0000000
+++ /dev/null
@@ -1,486 +0,0 @@
-/*****************************************************************************/
-
-/*
- *     cdk.h  -- CDK interface definitions.
- *
- *     Copyright (C) 1996-1998  Stallion Technologies
- *     Copyright (C) 1994-1996  Greg Ungerer.
- *
- *     This program is free software; you can redistribute it and/or modify
- *     it under the terms of the GNU General Public License as published by
- *     the Free Software Foundation; either version 2 of the License, or
- *     (at your option) any later version.
- *
- *     This program is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public License
- *     along with this program; if not, write to the Free Software
- *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/*****************************************************************************/
-#ifndef        _CDK_H
-#define        _CDK_H
-/*****************************************************************************/
-
-#pragma        pack(2)
-
-/*
- *     The following set of definitions is used to communicate with the
- *     shared memory interface of the Stallion intelligent multiport serial
- *     boards. The definitions in this file are taken directly from the
- *     document titled "Generic Stackable Interface, Downloader and
- *     Communications Development Kit".
- */
-
-/*
- *     Define the set of important shared memory addresses. These are
- *     required to initialize the board and get things started. All of these
- *     addresses are relative to the start of the shared memory.
- */
-#define        CDK_SIGADDR     0x200
-#define        CDK_FEATADDR    0x280
-#define        CDK_CDKADDR     0x300
-#define        CDK_RDYADDR     0x262
-
-#define        CDK_ALIVEMARKER 13
-
-/*
- *     On hardware power up the ROMs located on the EasyConnection 8/64 will
- *     fill out the following signature information into shared memory. This
- *     way the host system can quickly determine that the board is present
- *     and is operational.
- */
-typedef struct cdkecpsig {
-       unsigned long   magic;
-       unsigned short  romver;
-       unsigned short  cputype;
-       unsigned char   panelid[8];
-} cdkecpsig_t;
-
-#define        ECP_MAGIC       0x21504345
-
-/*
- *     On hardware power up the ROMs located on the ONboard, Stallion and
- *     Brumbys will fill out the following signature information into shared
- *     memory. This way the host system can quickly determine that the board
- *     is present and is operational.
- */
-typedef struct cdkonbsig {
-       unsigned short  magic0;
-       unsigned short  magic1;
-       unsigned short  magic2;
-       unsigned short  magic3;
-       unsigned short  romver;
-       unsigned short  memoff;
-       unsigned short  memseg;
-       unsigned short  amask0;
-       unsigned short  pic;
-       unsigned short  status;
-       unsigned short  btype;
-       unsigned short  clkticks;
-       unsigned short  clkspeed;
-       unsigned short  amask1;
-       unsigned short  amask2;
-} cdkonbsig_t;
-
-#define        ONB_MAGIC0      0xf2a7
-#define        ONB_MAGIC1      0xa149
-#define        ONB_MAGIC2      0x6352
-#define        ONB_MAGIC3      0xf121
-
-/*
- *     Define the feature area structure. The feature area is the set of
- *     startup parameters used by the slave image when it starts executing.
- *     They allow for the specification of buffer sizes, debug trace, etc.
- */
-typedef struct cdkfeature {
-       unsigned long   debug;
-       unsigned long   banner;
-       unsigned long   etype;
-       unsigned long   nrdevs;
-       unsigned long   brdspec;
-       unsigned long   txrqsize;
-       unsigned long   rxrqsize;
-       unsigned long   flags;
-} cdkfeature_t;
-
-#define        ETYP_DDK        0
-#define        ETYP_CDK        1
-
-/*
- *     Define the CDK header structure. This is the info that the slave
- *     environment sets up after it has been downloaded and started. It
- *     essentially provides a memory map for the shared memory interface.
- */
-typedef struct cdkhdr {
-       unsigned short  command;
-       unsigned short  status;
-       unsigned short  port;
-       unsigned short  mode;
-       unsigned long   cmd_buf[14];
-       unsigned short  alive_cnt;
-       unsigned short  intrpt_mode;
-       unsigned char   intrpt_id[8];
-       unsigned char   ver_release;
-       unsigned char   ver_modification;
-       unsigned char   ver_fix;
-       unsigned char   deadman_restart;
-       unsigned short  deadman;
-       unsigned short  nrdevs;
-       unsigned long   memp;
-       unsigned long   hostp;
-       unsigned long   slavep;
-       unsigned char   hostreq;
-       unsigned char   slavereq;
-       unsigned char   cmd_reserved[30];
-} cdkhdr_t;
-
-#define        MODE_DDK        0
-#define        MODE_CDK        1
-
-#define        IMD_INTR        0x0
-#define        IMD_PPINTR      0x1
-#define        IMD_POLL        0xff
-
-/*
- *     Define the memory mapping structure. This structure is pointed to by
- *     the memp field in the stlcdkhdr struct. As many as these structures
- *     as required are laid out in shared memory to define how the rest of
- *     shared memory is divided up. There will be one for each port.
- */
-typedef struct cdkmem {
-       unsigned short  dtype;
-       unsigned long   offset;
-} cdkmem_t;
-
-#define        TYP_UNDEFINED   0x0
-#define        TYP_ASYNCTRL    0x1
-#define        TYP_ASYNC       0x20
-#define        TYP_PARALLEL    0x40
-#define        TYP_SYNCX21     0x60
-
-/*****************************************************************************/
-
-/*
- *     Following is a set of defines and structures used to actually deal
- *     with the serial ports on the board. Firstly is the set of commands
- *     that can be applied to ports.
- */
-#define        ASYCMD          (((unsigned long) 'a') << 8)
-
-#define        A_NULL          (ASYCMD | 0)
-#define        A_FLUSH         (ASYCMD | 1)
-#define        A_BREAK         (ASYCMD | 2)
-#define        A_GETPORT       (ASYCMD | 3)
-#define        A_SETPORT       (ASYCMD | 4)
-#define        A_SETPORTF      (ASYCMD | 5)
-#define        A_SETPORTFTX    (ASYCMD | 6)
-#define        A_SETPORTFRX    (ASYCMD | 7)
-#define        A_GETSIGNALS    (ASYCMD | 8)
-#define        A_SETSIGNALS    (ASYCMD | 9)
-#define        A_SETSIGNALSF   (ASYCMD | 10)
-#define        A_SETSIGNALSFTX (ASYCMD | 11)
-#define        A_SETSIGNALSFRX (ASYCMD | 12)
-#define        A_GETNOTIFY     (ASYCMD | 13)
-#define        A_SETNOTIFY     (ASYCMD | 14)
-#define        A_NOTIFY        (ASYCMD | 15)
-#define        A_PORTCTRL      (ASYCMD | 16)
-#define        A_GETSTATS      (ASYCMD | 17)
-#define        A_RQSTATE       (ASYCMD | 18)
-#define        A_FLOWSTATE     (ASYCMD | 19)
-#define        A_CLEARSTATS    (ASYCMD | 20)
-
-/*
- *     Define those arguments used for simple commands.
- */
-#define        FLUSHRX         0x1
-#define        FLUSHTX         0x2
-
-#define        BREAKON         -1
-#define        BREAKOFF        -2
-
-/*
- *     Define the port setting structure, and all those defines that go along
- *     with it. Basically this structure defines the characteristics of this
- *     port: baud rate, chars, parity, input/output char cooking etc.
- */
-typedef struct asyport {
-       unsigned long   baudout;
-       unsigned long   baudin;
-       unsigned long   iflag;
-       unsigned long   oflag;
-       unsigned long   lflag;
-       unsigned long   pflag;
-       unsigned long   flow;
-       unsigned long   spare1;
-       unsigned short  vtime;
-       unsigned short  vmin;
-       unsigned short  txlo;
-       unsigned short  txhi;
-       unsigned short  rxlo;
-       unsigned short  rxhi;
-       unsigned short  rxhog;
-       unsigned short  spare2;
-       unsigned char   csize;
-       unsigned char   stopbs;
-       unsigned char   parity;
-       unsigned char   stopin;
-       unsigned char   startin;
-       unsigned char   stopout;
-       unsigned char   startout;
-       unsigned char   parmark;
-       unsigned char   brkmark;
-       unsigned char   cc[11];
-} asyport_t;
-
-#define        PT_STOP1        0x0
-#define        PT_STOP15       0x1
-#define        PT_STOP2        0x2
-
-#define        PT_NOPARITY     0x0
-#define        PT_ODDPARITY    0x1
-#define        PT_EVENPARITY   0x2
-#define        PT_MARKPARITY   0x3
-#define        PT_SPACEPARITY  0x4
-
-#define        F_NONE          0x0
-#define        F_IXON          0x1
-#define        F_IXOFF         0x2
-#define        F_IXANY         0x4
-#define        F_IOXANY        0x8
-#define        F_RTSFLOW       0x10
-#define        F_CTSFLOW       0x20
-#define        F_DTRFLOW       0x40
-#define        F_DCDFLOW       0x80
-#define        F_DSROFLOW      0x100
-#define        F_DSRIFLOW      0x200
-
-#define        FI_NORX         0x1
-#define        FI_RAW          0x2
-#define        FI_ISTRIP       0x4
-#define        FI_UCLC         0x8
-#define        FI_INLCR        0x10
-#define        FI_ICRNL        0x20
-#define        FI_IGNCR        0x40
-#define        FI_IGNBREAK     0x80
-#define        FI_DSCRDBREAK   0x100
-#define        FI_1MARKBREAK   0x200
-#define        FI_2MARKBREAK   0x400
-#define        FI_XCHNGBREAK   0x800
-#define        FI_IGNRXERRS    0x1000
-#define        FI_DSCDRXERRS   0x2000
-#define        FI_1MARKRXERRS  0x4000
-#define        FI_2MARKRXERRS  0x8000
-#define        FI_XCHNGRXERRS  0x10000
-#define        FI_DSCRDNULL    0x20000
-
-#define        FO_OLCUC        0x1
-#define        FO_ONLCR        0x2
-#define        FO_OOCRNL       0x4
-#define        FO_ONOCR        0x8
-#define        FO_ONLRET       0x10
-#define        FO_ONL          0x20
-#define        FO_OBS          0x40
-#define        FO_OVT          0x80
-#define        FO_OFF          0x100
-#define        FO_OTAB1        0x200
-#define        FO_OTAB2        0x400
-#define        FO_OTAB3        0x800
-#define        FO_OCR1         0x1000
-#define        FO_OCR2         0x2000
-#define        FO_OCR3         0x4000
-#define        FO_OFILL        0x8000
-#define        FO_ODELL        0x10000
-
-#define        P_RTSLOCK       0x1
-#define        P_CTSLOCK       0x2
-#define        P_MAPRTS        0x4
-#define        P_MAPCTS        0x8
-#define        P_LOOPBACK      0x10
-#define        P_DTRFOLLOW     0x20
-#define        P_FAKEDCD       0x40
-
-#define        P_RXIMIN        0x10000
-#define        P_RXITIME       0x20000
-#define        P_RXTHOLD       0x40000
-
-/*
- *     Define a structure to communicate serial port signal and data state
- *     information.
- */
-typedef struct asysigs {
-       unsigned long   data;
-       unsigned long   signal;
-       unsigned long   sigvalue;
-} asysigs_t;
-
-#define        DT_TXBUSY       0x1
-#define        DT_TXEMPTY      0x2
-#define        DT_TXLOW        0x4
-#define        DT_TXHIGH       0x8
-#define        DT_TXFULL       0x10
-#define        DT_TXHOG        0x20
-#define        DT_TXFLOWED     0x40
-#define        DT_TXBREAK      0x80
-
-#define        DT_RXBUSY       0x100
-#define        DT_RXEMPTY      0x200
-#define        DT_RXLOW        0x400
-#define        DT_RXHIGH       0x800
-#define        DT_RXFULL       0x1000
-#define        DT_RXHOG        0x2000
-#define        DT_RXFLOWED     0x4000
-#define        DT_RXBREAK      0x8000
-
-#define        SG_DTR          0x1
-#define        SG_DCD          0x2
-#define        SG_RTS          0x4
-#define        SG_CTS          0x8
-#define        SG_DSR          0x10
-#define        SG_RI           0x20
-
-/*
- *     Define the notification setting structure. This is used to tell the
- *     port what events we want to be informed about. Fields here use the
- *     same defines as for the asysigs structure above.
- */
-typedef struct asynotify {
-       unsigned long   ctrl;
-       unsigned long   data;
-       unsigned long   signal;
-       unsigned long   sigvalue;
-} asynotify_t;
-
-/*
- *     Define the port control structure. It is used to do fine grain
- *     control operations on the port.
- */
-typedef struct {
-       unsigned long   rxctrl;
-       unsigned long   txctrl;
-       char            rximdch;
-       char            tximdch;
-       char            spare1;
-       char            spare2;
-} asyctrl_t;
-
-#define        CT_ENABLE       0x1
-#define        CT_DISABLE      0x2
-#define        CT_STOP         0x4
-#define        CT_START        0x8
-#define        CT_STARTFLOW    0x10
-#define        CT_STOPFLOW     0x20
-#define        CT_SENDCHR      0x40
-
-/*
- *     Define the stats structure kept for each port. This is a useful set
- *     of data collected for each port on the slave. The A_GETSTATS command
- *     is used to retrieve this data from the slave.
- */
-typedef struct asystats {
-       unsigned long   opens;
-       unsigned long   txchars;
-       unsigned long   rxchars;
-       unsigned long   txringq;
-       unsigned long   rxringq;
-       unsigned long   txmsgs;
-       unsigned long   rxmsgs;
-       unsigned long   txflushes;
-       unsigned long   rxflushes;
-       unsigned long   overruns;
-       unsigned long   framing;
-       unsigned long   parity;
-       unsigned long   ringover;
-       unsigned long   lost;
-       unsigned long   rxstart;
-       unsigned long   rxstop;
-       unsigned long   txstart;
-       unsigned long   txstop;
-       unsigned long   dcdcnt;
-       unsigned long   dtrcnt;
-       unsigned long   ctscnt;
-       unsigned long   rtscnt;
-       unsigned long   dsrcnt;
-       unsigned long   ricnt;
-       unsigned long   txbreaks;
-       unsigned long   rxbreaks;
-       unsigned long   signals;
-       unsigned long   state;
-       unsigned long   hwid;
-} asystats_t;
-
-/*****************************************************************************/
-
-/*
- *     All command and control communication with a device on the slave is
- *     via a control block in shared memory. Each device has its own control
- *     block, defined by the following structure. The control block allows
- *     the host to open, close and control the device on the slave.
- */
-typedef struct cdkctrl {
-       unsigned char   open;
-       unsigned char   close;
-       unsigned long   openarg;
-       unsigned long   closearg;
-       unsigned long   cmd;
-       unsigned long   status;
-       unsigned long   args[32];
-} cdkctrl_t;
-
-/*
- *     Each device on the slave passes data to and from the host via a ring
- *     queue in shared memory. Define a ring queue structure to hold the
- *     vital information about each ring queue. Two ring queues will be
- *     allocated for each port, one for receive data and one for transmit
- *     data.
- */
-typedef struct cdkasyrq {
-       unsigned long   offset;
-       unsigned short  size;
-       unsigned short  head;
-       unsigned short  tail;
-} cdkasyrq_t;
-
-/*
- *     Each asynchronous port is defined in shared memory by the following
- *     structure. It contains a control block to command a device, and also
- *     the necessary data channel information as well.
- */
-typedef struct cdkasy {
-       cdkctrl_t       ctrl;
-       unsigned short  notify;
-       asynotify_t     changed;
-       unsigned short  receive;
-       cdkasyrq_t      rxq;
-       unsigned short  transmit;
-       cdkasyrq_t      txq;
-} cdkasy_t;
-
-#pragma        pack()
-
-/*****************************************************************************/
-
-/*
- *     Define the set of ioctls used by the driver to do special things
- *     to the board. These include interrupting it, and initializing
- *     the driver after board startup and shutdown.
- */
-#include <linux/ioctl.h>
-
-#define        STL_BINTR       _IO('s',20)
-#define        STL_BSTART      _IO('s',21)
-#define        STL_BSTOP       _IO('s',22)
-#define        STL_BRESET      _IO('s',23)
-
-/*
- *     Define a set of ioctl extensions, used to get at special stuff.
- */
-#define        STL_GETPFLAG    _IO('s',80)
-#define        STL_SETPFLAG    _IO('s',81)
-
-/*****************************************************************************/
-#endif
index acba894374a1537b4b961eee222e9c28b53845cf..8a7096fcb01ee1354e1d46c67d5d1ff9919bc742 100644 (file)
@@ -97,6 +97,8 @@ struct clock_event_device {
        void                    (*broadcast)(const struct cpumask *mask);
        void                    (*set_mode)(enum clock_event_mode mode,
                                            struct clock_event_device *);
+       void                    (*suspend)(struct clock_event_device *);
+       void                    (*resume)(struct clock_event_device *);
        unsigned long           min_delta_ticks;
        unsigned long           max_delta_ticks;
 
@@ -156,6 +158,9 @@ clockevents_calc_mult_shift(struct clock_event_device *ce, u32 freq, u32 minsec)
                                      freq, minsec);
 }
 
+extern void clockevents_suspend(void);
+extern void clockevents_resume(void);
+
 #ifdef CONFIG_GENERIC_CLOCKEVENTS
 extern void clockevents_notify(unsigned long reason, void *arg);
 #else
@@ -164,6 +169,9 @@ extern void clockevents_notify(unsigned long reason, void *arg);
 
 #else /* CONFIG_GENERIC_CLOCKEVENTS_BUILD */
 
+static inline void clockevents_suspend(void) {}
+static inline void clockevents_resume(void) {}
+
 #define clockevents_notify(reason, arg) do { } while (0)
 
 #endif
diff --git a/include/linux/comstats.h b/include/linux/comstats.h
deleted file mode 100644 (file)
index 3f5ea8e..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/*****************************************************************************/
-
-/*
- *     comstats.h  -- Serial Port Stats.
- *
- *     Copyright (C) 1996-1998  Stallion Technologies
- *     Copyright (C) 1994-1996  Greg Ungerer.
- *
- *     This program is free software; you can redistribute it and/or modify
- *     it under the terms of the GNU General Public License as published by
- *     the Free Software Foundation; either version 2 of the License, or
- *     (at your option) any later version.
- *
- *     This program is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public License
- *     along with this program; if not, write to the Free Software
- *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/*****************************************************************************/
-#ifndef        _COMSTATS_H
-#define        _COMSTATS_H
-/*****************************************************************************/
-
-/*
- *     Serial port stats structure. The structure itself is UART
- *     independent, but some fields may be UART/driver specific (for
- *     example state).
- */
-
-typedef struct {
-       unsigned long   brd;
-       unsigned long   panel;
-       unsigned long   port;
-       unsigned long   hwid;
-       unsigned long   type;
-       unsigned long   txtotal;
-       unsigned long   rxtotal;
-       unsigned long   txbuffered;
-       unsigned long   rxbuffered;
-       unsigned long   rxoverrun;
-       unsigned long   rxparity;
-       unsigned long   rxframing;
-       unsigned long   rxlost;
-       unsigned long   txbreaks;
-       unsigned long   rxbreaks;
-       unsigned long   txxon;
-       unsigned long   txxoff;
-       unsigned long   rxxon;
-       unsigned long   rxxoff;
-       unsigned long   txctson;
-       unsigned long   txctsoff;
-       unsigned long   rxrtson;
-       unsigned long   rxrtsoff;
-       unsigned long   modem;
-       unsigned long   state;
-       unsigned long   flags;
-       unsigned long   ttystate;
-       unsigned long   cflags;
-       unsigned long   iflags;
-       unsigned long   oflags;
-       unsigned long   lflags;
-       unsigned long   signals;
-} comstats_t;
-
-
-/*
- *     Board stats structure. Returns useful info about the board.
- */
-
-#define        COM_MAXPANELS   8
-
-typedef struct {
-       unsigned long   panel;
-       unsigned long   type;
-       unsigned long   hwid;
-       unsigned long   nrports;
-} companel_t;
-
-typedef struct {
-       unsigned long   brd;
-       unsigned long   type;
-       unsigned long   hwid;
-       unsigned long   state;
-       unsigned long   ioaddr;
-       unsigned long   ioaddr2;
-       unsigned long   memaddr;
-       unsigned long   irq;
-       unsigned long   nrpanels;
-       unsigned long   nrports;
-       companel_t      panels[COM_MAXPANELS];
-} combrd_t;
-
-
-/*
- *     Define the ioctl operations for stats stuff.
- */
-#include <linux/ioctl.h>
-
-#define        COM_GETPORTSTATS        _IO('c',30)
-#define        COM_CLRPORTSTATS        _IO('c',31)
-#define        COM_GETBRDSTATS         _IO('c',32)
-
-
-/*
- *     Define the set of ioctls that give user level access to the
- *     private port, panel and board structures. The argument required
- *     will be driver dependent!  
- */
-#define        COM_READPORT            _IO('c',40)
-#define        COM_READBOARD           _IO('c',41)
-#define        COM_READPANEL           _IO('c',42)
-
-/*****************************************************************************/
-#endif
index 52a5f15a2223ecb916391138ca9cb44f5d5d108a..86529e642d6c047ac2399ba0c21c69e229adf755 100644 (file)
@@ -772,6 +772,13 @@ static inline void pm_suspend_ignore_children(struct device *dev, bool enable)
        dev->power.ignore_children = enable;
 }
 
+static inline void dev_pm_syscore_device(struct device *dev, bool val)
+{
+#ifdef CONFIG_PM_SLEEP
+       dev->power.syscore = val;
+#endif
+}
+
 static inline void device_lock(struct device *dev)
 {
        mutex_lock(&dev->mutex);
index 38dba16c417646ff28f9ea78dea28a268d65d125..aa110476a95be0b1d479555346c560d45ecc0b20 100644 (file)
@@ -1491,7 +1491,6 @@ struct sb_writers {
 struct super_block {
        struct list_head        s_list;         /* Keep this first */
        dev_t                   s_dev;          /* search index; _not_ kdev_t */
-       unsigned char           s_dirt;
        unsigned char           s_blocksize_bits;
        unsigned long           s_blocksize;
        loff_t                  s_maxbytes;     /* Max file size */
@@ -1861,7 +1860,6 @@ struct super_operations {
        int (*drop_inode) (struct inode *);
        void (*evict_inode) (struct inode *);
        void (*put_super) (struct super_block *);
-       void (*write_super) (struct super_block *);
        int (*sync_fs)(struct super_block *sb, int wait);
        int (*freeze_fs) (struct super_block *);
        int (*unfreeze_fs) (struct super_block *);
@@ -2397,7 +2395,6 @@ extern int vfs_fsync_range(struct file *file, loff_t start, loff_t end,
                           int datasync);
 extern int vfs_fsync(struct file *file, int datasync);
 extern int generic_write_sync(struct file *file, loff_t pos, loff_t count);
-extern void sync_supers(void);
 extern void emergency_sync(void);
 extern void emergency_remount(void);
 #ifdef CONFIG_BLOCK
index 63d966d5c2ea7a382c2f42cc664c7804dec86f73..d5b0910d49615ee01cf3255818d99e78241cb09f 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 af961d6f7ab14edc6b3a0c8ec813124fba5415da..642928cf57b4b47672c6fd18552b3fd3e114153e 100644 (file)
@@ -306,9 +306,10 @@ extern void *perf_trace_buf_prepare(int size, unsigned short type,
 
 static inline void
 perf_trace_buf_submit(void *raw_data, int size, int rctx, u64 addr,
-                      u64 count, struct pt_regs *regs, void *head)
+                      u64 count, struct pt_regs *regs, void *head,
+                      struct task_struct *task)
 {
-       perf_tp_event(addr, count, raw_data, size, regs, head, rctx);
+       perf_tp_event(addr, count, raw_data, size, regs, head, rctx, task);
 }
 #endif
 
index 9303348965fbdbc8a8d6d706949b543d54c5609b..d8c713e148e3a5c15fc166e507fe811210872027 100644 (file)
@@ -57,6 +57,9 @@
  *
  * 7.19
  *  - add FUSE_FALLOCATE
+ *
+ * 7.20
+ *  - add FUSE_AUTO_INVAL_DATA
  */
 
 #ifndef _LINUX_FUSE_H
@@ -88,7 +91,7 @@
 #define FUSE_KERNEL_VERSION 7
 
 /** Minor version number of this interface */
-#define FUSE_KERNEL_MINOR_VERSION 19
+#define FUSE_KERNEL_MINOR_VERSION 20
 
 /** The node ID of the root inode */
 #define FUSE_ROOT_ID 1
@@ -163,10 +166,19 @@ struct fuse_file_lock {
 /**
  * INIT request/reply flags
  *
+ * FUSE_ASYNC_READ: asynchronous read requests
  * FUSE_POSIX_LOCKS: remote locking for POSIX file locks
+ * FUSE_FILE_OPS: kernel sends file handle for fstat, etc... (not yet supported)
+ * FUSE_ATOMIC_O_TRUNC: handles the O_TRUNC open flag in the filesystem
  * FUSE_EXPORT_SUPPORT: filesystem handles lookups of "." and ".."
+ * FUSE_BIG_WRITES: filesystem can handle write size larger than 4kB
  * FUSE_DONT_MASK: don't apply umask to file mode on create operations
+ * FUSE_SPLICE_WRITE: kernel supports splice write on the device
+ * FUSE_SPLICE_MOVE: kernel supports splice move on the device
+ * FUSE_SPLICE_READ: kernel supports splice read on the device
  * FUSE_FLOCK_LOCKS: remote locking for BSD style file locks
+ * FUSE_HAS_IOCTL_DIR: kernel supports ioctl on directories
+ * FUSE_AUTO_INVAL_DATA: automatically invalidate cached pages
  */
 #define FUSE_ASYNC_READ                (1 << 0)
 #define FUSE_POSIX_LOCKS       (1 << 1)
@@ -175,7 +187,12 @@ struct fuse_file_lock {
 #define FUSE_EXPORT_SUPPORT    (1 << 4)
 #define FUSE_BIG_WRITES                (1 << 5)
 #define FUSE_DONT_MASK         (1 << 6)
+#define FUSE_SPLICE_WRITE      (1 << 7)
+#define FUSE_SPLICE_MOVE       (1 << 8)
+#define FUSE_SPLICE_READ       (1 << 9)
 #define FUSE_FLOCK_LOCKS       (1 << 10)
+#define FUSE_HAS_IOCTL_DIR     (1 << 11)
+#define FUSE_AUTO_INVAL_DATA   (1 << 12)
 
 /**
  * CUSE INIT request/reply flags
diff --git a/include/linux/generic_serial.h b/include/linux/generic_serial.h
deleted file mode 100644 (file)
index 79b3eb3..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- *  generic_serial.h
- *
- *  Copyright (C) 1998 R.E.Wolff@BitWizard.nl
- *
- *  written for the SX serial driver.
- *
- *  Version 0.1 -- December, 1998.
- */
-
-#ifndef GENERIC_SERIAL_H
-#define GENERIC_SERIAL_H
-
-#warning Use of this header is deprecated.
-#warning Since nobody sets the constants defined here for you, you should not, in any case, use them. Including the header is thus pointless.
-
-/* Flags */
-/* Warning: serial.h defines some ASYNC_ flags, they say they are "only"
-   used in serial.c, but they are also used in all other serial drivers. 
-   Make sure they don't clash with these here... */
-#define GS_TX_INTEN      0x00800000
-#define GS_RX_INTEN      0x00400000
-#define GS_ACTIVE        0x00200000
-
-#define GS_TYPE_NORMAL   1
-
-#define GS_DEBUG_FLUSH   0x00000001
-#define GS_DEBUG_BTR     0x00000002
-#define GS_DEBUG_TERMIOS 0x00000004
-#define GS_DEBUG_STUFF   0x00000008
-#define GS_DEBUG_CLOSE   0x00000010
-#define GS_DEBUG_FLOW    0x00000020
-#define GS_DEBUG_WRITE   0x00000040
-
-#endif
index bb7f30971858ca5127de592cdaa0cec227935384..305f23cd7cff53f3ef97794db7d6aa7dde6035c6 100644 (file)
@@ -22,7 +22,7 @@
  *
  * - bits 16-25 are the hardirq count (max # of nested hardirqs: 1024)
  * - bit 26 is the NMI_MASK
- * - bit 28 is the PREEMPT_ACTIVE flag
+ * - bit 27 is the PREEMPT_ACTIVE flag
  *
  * PREEMPT_MASK: 0x000000ff
  * SOFTIRQ_MASK: 0x0000ff00
index b80506bdd733ee181f202ddb6322529d42299d1b..24df9e70406ffb94fb98faf91c174e236155a639 100644 (file)
@@ -67,4 +67,14 @@ static inline unsigned long hash_ptr(const void *ptr, unsigned int bits)
 {
        return hash_long((unsigned long)ptr, bits);
 }
+
+static inline u32 hash32_ptr(const void *ptr)
+{
+       unsigned long val = (unsigned long)ptr;
+
+#if BITS_PER_LONG == 64
+       val ^= (val >> 32);
+#endif
+       return (u32)val;
+}
 #endif /* _LINUX_HASH_H */
index a36343a37ebced7c26ae036b3f4155efddd18790..4ea1cc7392bd9464ba7282f689e1aae4075b5539 100644 (file)
@@ -21,6 +21,7 @@
  * @values: Array of bitmasks of GPIO settings (low/high) for each
  *     position
  * @n_values: Number of multiplexer positions (busses to instantiate)
+ * @classes: Optional I2C auto-detection classes
  * @gpios: Array of GPIO numbers used to control MUX
  * @n_gpios: Number of GPIOs used to control MUX
  * @idle: Bitmask to write to MUX when idle or GPIO_I2CMUX_NO_IDLE if not used
@@ -30,6 +31,7 @@ struct i2c_mux_gpio_platform_data {
        int base_nr;
        const unsigned *values;
        int n_values;
+       const unsigned *classes;
        const unsigned *gpios;
        int n_gpios;
        unsigned idle;
index c790838300148f2021bb97072f4267cd216861cb..40cb05a97b4602d802bd222a3f207c99fab7b564 100644 (file)
@@ -36,6 +36,7 @@
 struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
                                struct device *mux_dev,
                                void *mux_priv, u32 force_nr, u32 chan_id,
+                               unsigned int class,
                                int (*select) (struct i2c_adapter *,
                                               void *mux_dev, u32 chan_id),
                                int (*deselect) (struct i2c_adapter *,
index 28f1f8d5ab1f03a6995ea0f255bacc5d5f815c24..1712677d59046374410438d7f86e985a27c3daff 100644 (file)
@@ -36,6 +36,7 @@
 struct pca954x_platform_mode {
        int             adap_id;
        unsigned int    deselect_on_exit:1;
+       unsigned int    class;
 };
 
 /* Per mux/switch data, used with i2c_register_board_info */
index f0e69c6e82083c33eb799cbba0eb2ba789699a56..9adcc29f084af485a8b674dd6c6b3b51532ce68b 100644 (file)
@@ -92,6 +92,7 @@
 #define ARPHRD_PHONET  820             /* PhoNet media type            */
 #define ARPHRD_PHONET_PIPE 821         /* PhoNet pipe header           */
 #define ARPHRD_CAIF    822             /* CAIF media type              */
+#define ARPHRD_IP6GRE  823             /* GRE over IPv6                */
 
 #define ARPHRD_VOID      0xFFFF        /* Void type, nothing is known */
 #define ARPHRD_NONE      0xFFFE        /* zero header length */
index 6960fc1841a7adc3bd42ff5b9a2221b78f2b9eb2..07a192e0c5fc341eecd4fbbcfaf74d8e3d55f3d8 100644 (file)
@@ -67,6 +67,9 @@ struct team_port {
        struct netpoll *np;
 #endif
 
+       s32 priority; /* lower number ~ higher priority */
+       u16 queue_id;
+       struct list_head qom_list; /* node in queue override mapping list */
        long mode_priv[0];
 };
 
@@ -96,21 +99,6 @@ static inline void team_netpoll_send_skb(struct team_port *port,
 }
 #endif
 
-static inline int team_dev_queue_xmit(struct team *team, struct team_port *port,
-                                     struct sk_buff *skb)
-{
-       BUILD_BUG_ON(sizeof(skb->queue_mapping) !=
-                    sizeof(qdisc_skb_cb(skb)->slave_dev_queue_mapping));
-       skb_set_queue_mapping(skb, qdisc_skb_cb(skb)->slave_dev_queue_mapping);
-
-       skb->dev = port->dev;
-       if (unlikely(netpoll_tx_running(port->dev))) {
-               team_netpoll_send_skb(port, skb);
-               return 0;
-       }
-       return dev_queue_xmit(skb);
-}
-
 struct team_mode_ops {
        int (*init)(struct team *team);
        void (*exit)(struct team *team);
@@ -130,6 +118,7 @@ enum team_option_type {
        TEAM_OPTION_TYPE_STRING,
        TEAM_OPTION_TYPE_BINARY,
        TEAM_OPTION_TYPE_BOOL,
+       TEAM_OPTION_TYPE_S32,
 };
 
 struct team_option_inst_info {
@@ -146,6 +135,7 @@ struct team_gsetter_ctx {
                        u32 len;
                } bin_val;
                bool bool_val;
+               s32 s32_val;
        } data;
        struct team_option_inst_info *info;
 };
@@ -197,9 +187,26 @@ struct team {
 
        const struct team_mode *mode;
        struct team_mode_ops ops;
+       bool queue_override_enabled;
+       struct list_head *qom_lists; /* array of queue override mapping lists */
        long mode_priv[TEAM_MODE_PRIV_LONGS];
 };
 
+static inline int team_dev_queue_xmit(struct team *team, struct team_port *port,
+                                     struct sk_buff *skb)
+{
+       BUILD_BUG_ON(sizeof(skb->queue_mapping) !=
+                    sizeof(qdisc_skb_cb(skb)->slave_dev_queue_mapping));
+       skb_set_queue_mapping(skb, qdisc_skb_cb(skb)->slave_dev_queue_mapping);
+
+       skb->dev = port->dev;
+       if (unlikely(netpoll_tx_running(team->dev))) {
+               team_netpoll_send_skb(port, skb);
+               return 0;
+       }
+       return dev_queue_xmit(skb);
+}
+
 static inline struct hlist_head *team_port_index_hash(struct team *team,
                                                      int port_index)
 {
index 5efff60b6f56906112b5c71dffbdf47b2b22cc8d..8c5035ac31421aa1bee89a34c342de34ff63131a 100644 (file)
@@ -75,6 +75,9 @@ enum {
        IFLA_GRE_TTL,
        IFLA_GRE_TOS,
        IFLA_GRE_PMTUDISC,
+       IFLA_GRE_ENCAP_LIMIT,
+       IFLA_GRE_FLOWINFO,
+       IFLA_GRE_FLAGS,
        __IFLA_GRE_MAX,
 };
 
index b76b4a87065e3615cbfc1b17e81b9fd90bcf8898..be91f344d5fce1b3b8a41ff149ece8b917715542 100644 (file)
@@ -87,6 +87,8 @@
 #define ADF4350_MAX_BANDSEL_CLK                125000 /* Hz */
 #define ADF4350_MAX_FREQ_REFIN         250000000 /* Hz */
 #define ADF4350_MAX_MODULUS            4095
+#define ADF4350_MAX_R_CNT              1023
+
 
 /**
  * struct adf4350_platform_data - platform specific information
index 67f9ddacb70c327e6576b47d0c103cddb752dd18..d032780d0ce50849c5441aae24025b2cc2f80cc3 100644 (file)
@@ -104,9 +104,14 @@ static inline void ipv4_devconf_setall(struct in_device *in_dev)
 #define IN_DEV_ANDCONF(in_dev, attr) \
        (IPV4_DEVCONF_ALL(dev_net(in_dev->dev), attr) && \
         IN_DEV_CONF_GET((in_dev), attr))
-#define IN_DEV_ORCONF(in_dev, attr) \
-       (IPV4_DEVCONF_ALL(dev_net(in_dev->dev), attr) || \
+
+#define IN_DEV_NET_ORCONF(in_dev, net, attr) \
+       (IPV4_DEVCONF_ALL(net, attr) || \
         IN_DEV_CONF_GET((in_dev), attr))
+
+#define IN_DEV_ORCONF(in_dev, attr) \
+       IN_DEV_NET_ORCONF(in_dev, dev_net(in_dev->dev), attr)
+
 #define IN_DEV_MAXCONF(in_dev, attr) \
        (max(IPV4_DEVCONF_ALL(dev_net(in_dev->dev), attr), \
             IN_DEV_CONF_GET((in_dev), attr)))
@@ -133,6 +138,8 @@ static inline void ipv4_devconf_setall(struct in_device *in_dev)
                                        IN_DEV_ORCONF((in_dev), \
                                                      PROMOTE_SECONDARIES)
 #define IN_DEV_ROUTE_LOCALNET(in_dev)  IN_DEV_ORCONF(in_dev, ROUTE_LOCALNET)
+#define IN_DEV_NET_ROUTE_LOCALNET(in_dev, net) \
+       IN_DEV_NET_ORCONF(in_dev, net, ROUTE_LOCALNET)
 
 #define IN_DEV_RX_REDIRECTS(in_dev) \
        ((IN_DEV_FORWARD(in_dev) && \
index f875b316249d257ce2f56e7243e4463c9d4994e2..16625d799b6fc1ca85f89d5d9f81415332c8e86e 100644 (file)
@@ -2,6 +2,7 @@
 #define LINUX_INPUT_EETI_TS_H
 
 struct eeti_ts_platform_data {
+       int irq_gpio;
        unsigned int irq_active_high;
 };
 
index 54d6d690073c1cb5119671b99df70af3ddfc615d..7e83370e6fd2b134691e7fa348529e70d0a1ae56 100644 (file)
@@ -20,6 +20,7 @@
 #define __LINUX_IOMMU_H
 
 #include <linux/errno.h>
+#include <linux/types.h>
 
 #define IOMMU_READ     (1)
 #define IOMMU_WRITE    (2)
@@ -30,6 +31,7 @@ struct iommu_group;
 struct bus_type;
 struct device;
 struct iommu_domain;
+struct notifier_block;
 
 /* iommu fault flags */
 #define IOMMU_FAULT_READ       0x0
index bf22b03179022da13565642026213601e879fa88..48af63c9a48d25f5f6d9e2681e6eeeec5a4fef8c 100644 (file)
@@ -31,4 +31,21 @@ struct ip6_tnl_parm {
        struct in6_addr raddr;  /* remote tunnel end-point address */
 };
 
+struct ip6_tnl_parm2 {
+       char name[IFNAMSIZ];    /* name of tunnel device */
+       int link;               /* ifindex of underlying L2 interface */
+       __u8 proto;             /* tunnel protocol */
+       __u8 encap_limit;       /* encapsulation limit for tunnel */
+       __u8 hop_limit;         /* hop limit for tunnel */
+       __be32 flowinfo;        /* traffic class and flowlabel for tunnel */
+       __u32 flags;            /* tunnel flags */
+       struct in6_addr laddr;  /* local tunnel end-point address */
+       struct in6_addr raddr;  /* remote tunnel end-point address */
+
+       __be16                  i_flags;
+       __be16                  o_flags;
+       __be32                  i_key;
+       __be32                  o_key;
+};
+
 #endif
index 379e433e15e0fc97fc3f376b610f12ff77f694ae..879db26ec4013297fb76f16143b87ec9db52b5e4 100644 (file)
@@ -369,6 +369,7 @@ struct ipv6_pinfo {
        __u8                    rcv_tclass;
 
        __u32                   dst_cookie;
+       __u32                   rx_dst_cookie;
 
        struct ipv6_mc_socklist __rcu *ipv6_mc_list;
        struct ipv6_ac_socklist *ipv6_ac_list;
index 553fb66da130a3a9b3700958c5cce22a6b5cda73..216b0ba109d72f453836568e1aa6c7b7c85e21a6 100644 (file)
@@ -349,6 +349,7 @@ enum {
        IRQCHIP_MASK_ON_SUSPEND         = (1 <<  2),
        IRQCHIP_ONOFFLINE_ENABLED       = (1 <<  3),
        IRQCHIP_SKIP_SET_WAKE           = (1 <<  4),
+       IRQCHIP_ONESHOT_SAFE            = (1 <<  5),
 };
 
 /* This include will go away once we isolated irq_desc usage to core code */
index 9a323d12de1c1700b10988013f38f6d8b1ca4615..0ba014c550565622702a154cf6a6dc78ffabe1fe 100644 (file)
 
 struct irq_affinity_notify;
 struct proc_dir_entry;
-struct timer_rand_state;
 struct module;
 /**
  * struct irq_desc - interrupt descriptor
  * @irq_data:          per irq and chip data passed down to chip functions
- * @timer_rand_state:  pointer to timer rand state struct
  * @kstat_irqs:                irq stats per cpu
  * @handle_irq:                highlevel irq-events handler
  * @preflow_handler:   handler called before the flow handler (currently used by sparc)
diff --git a/include/linux/istallion.h b/include/linux/istallion.h
deleted file mode 100644 (file)
index ad700a6..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/*****************************************************************************/
-
-/*
- *     istallion.h  -- stallion intelligent multiport serial driver.
- *
- *     Copyright (C) 1996-1998  Stallion Technologies
- *     Copyright (C) 1994-1996  Greg Ungerer.
- *
- *     This program is free software; you can redistribute it and/or modify
- *     it under the terms of the GNU General Public License as published by
- *     the Free Software Foundation; either version 2 of the License, or
- *     (at your option) any later version.
- *
- *     This program is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public License
- *     along with this program; if not, write to the Free Software
- *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/*****************************************************************************/
-#ifndef        _ISTALLION_H
-#define        _ISTALLION_H
-/*****************************************************************************/
-
-/*
- *     Define important driver constants here.
- */
-#define        STL_MAXBRDS             4
-#define        STL_MAXPANELS           4
-#define        STL_MAXPORTS            64
-#define        STL_MAXCHANS            (STL_MAXPORTS + 1)
-#define        STL_MAXDEVS             (STL_MAXBRDS * STL_MAXPORTS)
-
-
-/*
- *     Define a set of structures to hold all the board/panel/port info
- *     for our ports. These will be dynamically allocated as required at
- *     driver initialization time.
- */
-
-/*
- *     Port and board structures to hold status info about each object.
- *     The board structure contains pointers to structures for each port
- *     connected to it. Panels are not distinguished here, since
- *     communication with the slave board will always be on a per port
- *     basis.
- */
-struct stliport {
-       unsigned long           magic;
-       struct tty_port         port;
-       unsigned int            portnr;
-       unsigned int            panelnr;
-       unsigned int            brdnr;
-       unsigned long           state;
-       unsigned int            devnr;
-       int                     baud_base;
-       int                     custom_divisor;
-       int                     closing_wait;
-       int                     rc;
-       int                     argsize;
-       void                    *argp;
-       unsigned int            rxmarkmsk;
-       wait_queue_head_t       raw_wait;
-       struct asysigs          asig;
-       unsigned long           addr;
-       unsigned long           rxoffset;
-       unsigned long           txoffset;
-       unsigned long           sigs;
-       unsigned long           pflag;
-       unsigned int            rxsize;
-       unsigned int            txsize;
-       unsigned char           reqbit;
-       unsigned char           portidx;
-       unsigned char           portbit;
-};
-
-/*
- *     Use a structure of function pointers to do board level operations.
- *     These include, enable/disable, paging shared memory, interrupting, etc.
- */
-struct stlibrd {
-       unsigned long   magic;
-       unsigned int    brdnr;
-       unsigned int    brdtype;
-       unsigned long   state;
-       unsigned int    nrpanels;
-       unsigned int    nrports;
-       unsigned int    nrdevs;
-       unsigned int    iobase;
-       int             iosize;
-       unsigned long   memaddr;
-       void            __iomem *membase;
-       unsigned long   memsize;
-       int             pagesize;
-       int             hostoffset;
-       int             slaveoffset;
-       int             bitsize;
-       int             enabval;
-       unsigned int    panels[STL_MAXPANELS];
-       int             panelids[STL_MAXPANELS];
-       void            (*init)(struct stlibrd *brdp);
-       void            (*enable)(struct stlibrd *brdp);
-       void            (*reenable)(struct stlibrd *brdp);
-       void            (*disable)(struct stlibrd *brdp);
-       void            __iomem *(*getmemptr)(struct stlibrd *brdp, unsigned long offset, int line);
-       void            (*intr)(struct stlibrd *brdp);
-       void            (*reset)(struct stlibrd *brdp);
-       struct stliport *ports[STL_MAXPORTS];
-};
-
-
-/*
- *     Define MAGIC numbers used for above structures.
- */
-#define        STLI_PORTMAGIC  0xe671c7a1
-#define        STLI_BOARDMAGIC 0x4bc6c825
-
-/*****************************************************************************/
-#endif
index 265e2c3cbd1cd74d2b3efd416aa9301c90ae90ad..05e3c2c7a8cf81e2184f49a531a8158fa45639b4 100644 (file)
@@ -39,9 +39,6 @@
 # error Invalid value of HZ.
 #endif
 
-/* LATCH is used in the interval timer and ftape setup. */
-#define LATCH  ((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */
-
 /* Suppose we want to divide two numbers NOM and DEN: NOM/DEN, then we can
  * improve accuracy by shifting LSH bits, hence calculating:
  *     (NOM << LSH) / DEN
 #define SH_DIV(NOM,DEN,LSH) (   (((NOM) / (DEN)) << (LSH))              \
                              + ((((NOM) % (DEN)) << (LSH)) + (DEN) / 2) / (DEN))
 
-/* HZ is the requested value. ACTHZ is actual HZ ("<< 8" is for accuracy) */
-#define ACTHZ (SH_DIV (CLOCK_TICK_RATE, LATCH, 8))
+#ifdef CLOCK_TICK_RATE
+/* LATCH is used in the interval timer and ftape setup. */
+# define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */
+
+/*
+ * HZ is the requested value. However the CLOCK_TICK_RATE may not allow
+ * for exactly HZ. So SHIFTED_HZ is high res HZ ("<< 8" is for accuracy)
+ */
+# define SHIFTED_HZ (SH_DIV(CLOCK_TICK_RATE, LATCH, 8))
+#else
+# define SHIFTED_HZ (HZ << 8)
+#endif
 
-/* TICK_NSEC is the time between ticks in nsec assuming real ACTHZ */
-#define TICK_NSEC (SH_DIV (1000000UL * 1000, ACTHZ, 8))
+/* TICK_NSEC is the time between ticks in nsec assuming SHIFTED_HZ */
+#define TICK_NSEC (SH_DIV(1000000UL * 1000, SHIFTED_HZ, 8))
 
 /* TICK_USEC is the time between ticks in usec assuming fake USER_HZ */
 #define TICK_USEC ((1000000UL + USER_HZ/2) / USER_HZ)
 
-/* TICK_USEC_TO_NSEC is the time between ticks in nsec assuming real ACTHZ and */
-/* a value TUSEC for TICK_USEC (can be set bij adjtimex)               */
-#define TICK_USEC_TO_NSEC(TUSEC) (SH_DIV (TUSEC * USER_HZ * 1000, ACTHZ, 8))
+/*
+ * TICK_USEC_TO_NSEC is the time between ticks in nsec assuming SHIFTED_HZ and
+ * a value TUSEC for TICK_USEC (can be set bij adjtimex)
+ */
+#define TICK_USEC_TO_NSEC(TUSEC) (SH_DIV(TUSEC * USER_HZ * 1000, SHIFTED_HZ, 8))
 
 /* some arch's have a small-data section that can be accessed register-relative
  * but that can only take up to, say, 4-byte variables. jiffies being part of
@@ -303,7 +312,13 @@ extern void jiffies_to_timespec(const unsigned long jiffies,
 extern unsigned long timeval_to_jiffies(const struct timeval *value);
 extern void jiffies_to_timeval(const unsigned long jiffies,
                               struct timeval *value);
+
 extern clock_t jiffies_to_clock_t(unsigned long x);
+static inline clock_t jiffies_delta_to_clock_t(long delta)
+{
+       return jiffies_to_clock_t(max(0L, delta));
+}
+
 extern unsigned long clock_t_to_jiffies(unsigned long x);
 extern u64 jiffies_64_to_clock_t(u64 x);
 extern u64 nsec_to_clock_t(u64 x);
index daf4a3a40ee0e4ed7d5e29be6b6a342f11ed487b..b7c8cdc1d4223b4565d7c1ede7e10229621cca97 100644 (file)
@@ -65,7 +65,6 @@ struct kbd_struct {
 
 extern int kbd_init(void);
 
-extern unsigned char getledstate(void);
 extern void setledstate(struct kbd_struct *kbd, unsigned int led);
 
 extern int do_poke_blanked_console;
@@ -145,16 +144,4 @@ void compute_shiftstate(void);
 
 extern unsigned int keymap_count;
 
-/* console.c */
-
-static inline void con_schedule_flip(struct tty_struct *t)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&t->buf.lock, flags);
-       if (t->buf.tail != NULL)
-               t->buf.tail->commit = t->buf.tail->used;
-       spin_unlock_irqrestore(&t->buf.lock, flags);
-       schedule_work(&t->buf.work);
-}
-
 #endif
index 064725854db8c7eff3c5a38a093aec190a6c6c7f..42d9e863a3139ad953c23f53ef36f4cc19182dd8 100644 (file)
@@ -75,8 +75,6 @@ extern const char *kdb_diemsg;
 #define KDB_FLAG_CATASTROPHIC  (1 << 1) /* A catastrophic event has occurred */
 #define KDB_FLAG_CMD_INTERRUPT (1 << 2) /* Previous command was interrupted */
 #define KDB_FLAG_NOIPI         (1 << 3) /* Do not send IPIs */
-#define KDB_FLAG_ONLY_DO_DUMP  (1 << 4) /* Only do a dump, used when
-                                         * kdb is off */
 #define KDB_FLAG_NO_CONSOLE    (1 << 5) /* No console is available,
                                          * kdb is disabled */
 #define KDB_FLAG_NO_VT_CONSOLE (1 << 6) /* No VT console is available, do
index 2ce09aa7d3b3d12b3cb27fbfb2d4896390b3045f..f4f5be8dd58e1f6f9fc524ed64c2e757f5ea3598 100644 (file)
@@ -163,6 +163,7 @@ struct kvm_pit_config {
 #define KVM_EXIT_OSI              18
 #define KVM_EXIT_PAPR_HCALL      19
 #define KVM_EXIT_S390_UCONTROL   20
+#define KVM_EXIT_WATCHDOG         21
 
 /* For KVM_EXIT_INTERNAL_ERROR */
 #define KVM_INTERNAL_ERROR_EMULATION 1
@@ -473,6 +474,8 @@ struct kvm_ppc_smmu_info {
        struct kvm_ppc_one_seg_page_size sps[KVM_PPC_PAGE_SIZES_MAX_SZ];
 };
 
+#define KVM_PPC_PVINFO_FLAGS_EV_IDLE   (1<<0)
+
 #define KVMIO 0xAE
 
 /* machine type bits, to be used as argument to KVM_CREATE_VM */
@@ -618,6 +621,7 @@ struct kvm_ppc_smmu_info {
 #define KVM_CAP_PPC_GET_SMMU_INFO 78
 #define KVM_CAP_S390_COW 79
 #define KVM_CAP_PPC_ALLOC_HTAB 80
+#define KVM_CAP_PPC_BOOKE_WATCHDOG 81
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
index b70b48b01098c569b00cebc4a80cc2dbd691cdaf..7c0bbd110f963a30a3daa93e0b31c5f1781ea832 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/slab.h>
 #include <linux/rcupdate.h>
 #include <linux/ratelimit.h>
+#include <linux/err.h>
 #include <asm/signal.h>
 
 #include <linux/kvm.h>
 #define KVM_MAX_MMIO_FRAGMENTS \
        (KVM_MMIO_SIZE / KVM_USER_MMIO_SIZE + KVM_EXTRA_MMIO_FRAGMENTS)
 
+/*
+ * For the normal pfn, the highest 12 bits should be zero,
+ * so we can mask these bits to indicate the error.
+ */
+#define KVM_PFN_ERR_MASK       (0xfffULL << 52)
+
+#define KVM_PFN_ERR_FAULT      (KVM_PFN_ERR_MASK)
+#define KVM_PFN_ERR_HWPOISON   (KVM_PFN_ERR_MASK + 1)
+#define KVM_PFN_ERR_BAD                (KVM_PFN_ERR_MASK + 2)
+
+static inline bool is_error_pfn(pfn_t pfn)
+{
+       return !!(pfn & KVM_PFN_ERR_MASK);
+}
+
+static inline bool is_noslot_pfn(pfn_t pfn)
+{
+       return pfn == KVM_PFN_ERR_BAD;
+}
+
+static inline bool is_invalid_pfn(pfn_t pfn)
+{
+       return !is_noslot_pfn(pfn) && is_error_pfn(pfn);
+}
+
+#define KVM_ERR_PTR_BAD_PAGE   (ERR_PTR(-ENOENT))
+
+static inline bool is_error_page(struct page *page)
+{
+       return IS_ERR(page);
+}
+
 /*
  * vcpu->requests bit members
  */
 #define KVM_REQ_IMMEDIATE_EXIT    15
 #define KVM_REQ_PMU               16
 #define KVM_REQ_PMI               17
+#define KVM_REQ_WATCHDOG          18
 
 #define KVM_USERSPACE_IRQ_SOURCE_ID    0
 
@@ -183,6 +217,18 @@ struct kvm_vcpu {
        } async_pf;
 #endif
 
+#ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
+       /*
+        * Cpu relax intercept or pause loop exit optimization
+        * in_spin_loop: set when a vcpu does a pause loop exit
+        *  or cpu relax intercepted.
+        * dy_eligible: indicates whether vcpu is eligible for directed yield.
+        */
+       struct {
+               bool in_spin_loop;
+               bool dy_eligible;
+       } spin_loop;
+#endif
        struct kvm_vcpu_arch arch;
 };
 
@@ -201,7 +247,6 @@ struct kvm_memory_slot {
        gfn_t base_gfn;
        unsigned long npages;
        unsigned long flags;
-       unsigned long *rmap;
        unsigned long *dirty_bitmap;
        struct kvm_arch_memory_slot arch;
        unsigned long userspace_addr;
@@ -378,22 +423,6 @@ id_to_memslot(struct kvm_memslots *slots, int id)
        return slot;
 }
 
-#define HPA_MSB ((sizeof(hpa_t) * 8) - 1)
-#define HPA_ERR_MASK ((hpa_t)1 << HPA_MSB)
-static inline int is_error_hpa(hpa_t hpa) { return hpa >> HPA_MSB; }
-
-extern struct page *bad_page;
-extern struct page *fault_page;
-
-extern pfn_t bad_pfn;
-extern pfn_t fault_pfn;
-
-int is_error_page(struct page *page);
-int is_error_pfn(pfn_t pfn);
-int is_hwpoison_pfn(pfn_t pfn);
-int is_fault_pfn(pfn_t pfn);
-int is_noslot_pfn(pfn_t pfn);
-int is_invalid_pfn(pfn_t pfn);
 int kvm_is_error_hva(unsigned long addr);
 int kvm_set_memory_region(struct kvm *kvm,
                          struct kvm_userspace_memory_region *mem,
@@ -427,16 +456,15 @@ void kvm_release_page_dirty(struct page *page);
 void kvm_set_page_dirty(struct page *page);
 void kvm_set_page_accessed(struct page *page);
 
-pfn_t hva_to_pfn_atomic(struct kvm *kvm, unsigned long addr);
+pfn_t hva_to_pfn_atomic(unsigned long addr);
 pfn_t gfn_to_pfn_atomic(struct kvm *kvm, gfn_t gfn);
 pfn_t gfn_to_pfn_async(struct kvm *kvm, gfn_t gfn, bool *async,
                       bool write_fault, bool *writable);
 pfn_t gfn_to_pfn(struct kvm *kvm, gfn_t gfn);
 pfn_t gfn_to_pfn_prot(struct kvm *kvm, gfn_t gfn, bool write_fault,
                      bool *writable);
-pfn_t gfn_to_pfn_memslot(struct kvm *kvm,
-                        struct kvm_memory_slot *slot, gfn_t gfn);
-void kvm_release_pfn_dirty(pfn_t);
+pfn_t gfn_to_pfn_memslot(struct kvm_memory_slot *slot, gfn_t gfn);
+void kvm_release_pfn_dirty(pfn_t pfn);
 void kvm_release_pfn_clean(pfn_t pfn);
 void kvm_set_pfn_dirty(pfn_t pfn);
 void kvm_set_pfn_accessed(pfn_t pfn);
@@ -494,6 +522,7 @@ int kvm_vm_ioctl_set_memory_region(struct kvm *kvm,
                                   struct
                                   kvm_userspace_memory_region *mem,
                                   int user_alloc);
+int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level);
 long kvm_arch_vm_ioctl(struct file *filp,
                       unsigned int ioctl, unsigned long arg);
 
@@ -573,7 +602,7 @@ void kvm_arch_sync_events(struct kvm *kvm);
 int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu);
 void kvm_vcpu_kick(struct kvm_vcpu *vcpu);
 
-int kvm_is_mmio_pfn(pfn_t pfn);
+bool kvm_is_mmio_pfn(pfn_t pfn);
 
 struct kvm_irq_ack_notifier {
        struct hlist_node link;
@@ -740,6 +769,14 @@ static inline gfn_t gfn_to_index(gfn_t gfn, gfn_t base_gfn, int level)
                (base_gfn >> KVM_HPAGE_GFN_SHIFT(level));
 }
 
+static inline gfn_t
+hva_to_gfn_memslot(unsigned long hva, struct kvm_memory_slot *slot)
+{
+       gfn_t gfn_offset = (hva - slot->userspace_addr) >> PAGE_SHIFT;
+
+       return slot->base_gfn + gfn_offset;
+}
+
 static inline unsigned long gfn_to_hva_memslot(struct kvm_memory_slot *slot,
                                               gfn_t gfn)
 {
@@ -899,5 +936,32 @@ static inline bool kvm_check_request(int req, struct kvm_vcpu *vcpu)
        }
 }
 
+#ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
+
+static inline void kvm_vcpu_set_in_spin_loop(struct kvm_vcpu *vcpu, bool val)
+{
+       vcpu->spin_loop.in_spin_loop = val;
+}
+static inline void kvm_vcpu_set_dy_eligible(struct kvm_vcpu *vcpu, bool val)
+{
+       vcpu->spin_loop.dy_eligible = val;
+}
+
+#else /* !CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT */
+
+static inline void kvm_vcpu_set_in_spin_loop(struct kvm_vcpu *vcpu, bool val)
+{
+}
+
+static inline void kvm_vcpu_set_dy_eligible(struct kvm_vcpu *vcpu, bool val)
+{
+}
+
+static inline bool kvm_vcpu_eligible_for_directed_yield(struct kvm_vcpu *vcpu)
+{
+       return true;
+}
+
+#endif /* CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT */
 #endif
 
index 3aade1d8f410a287064167232e649be2dfb9522c..6e53bb31c220d9f33224f2660bc52a1d9c44f0db 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/spinlock.h>
 #include <linux/rwsem.h>
 #include <linux/timer.h>
+#include <linux/workqueue.h>
 
 struct device;
 /*
@@ -69,6 +70,9 @@ struct led_classdev {
        struct timer_list        blink_timer;
        int                      blink_brightness;
 
+       struct work_struct      set_brightness_work;
+       int                     delayed_set_value;
+
 #ifdef CONFIG_LEDS_TRIGGERS
        /* Protects the trigger data below */
        struct rw_semaphore      trigger_lock;
@@ -237,4 +241,20 @@ struct gpio_led_platform_data {
 struct platform_device *gpio_led_register_device(
                int id, const struct gpio_led_platform_data *pdata);
 
+enum cpu_led_event {
+       CPU_LED_IDLE_START,     /* CPU enters idle */
+       CPU_LED_IDLE_END,       /* CPU idle ends */
+       CPU_LED_START,          /* Machine starts, especially resume */
+       CPU_LED_STOP,           /* Machine stops, especially suspend */
+       CPU_LED_HALTED,         /* Machine shutdown */
+};
+#ifdef CONFIG_LEDS_TRIGGER_CPU
+extern void ledtrig_cpu(enum cpu_led_event evt);
+#else
+static inline void ledtrig_cpu(enum cpu_led_event evt)
+{
+       return;
+}
+#endif
+
 #endif         /* __LINUX_LEDS_H_INCLUDED */
index 64f90e17e51d5a87f3aa997e664c132542ad8029..a22707186421165457814cb903d3b2371e8f0e1d 100644 (file)
@@ -184,6 +184,7 @@ enum {
        ATA_LFLAG_DISABLED      = (1 << 6), /* link is disabled */
        ATA_LFLAG_SW_ACTIVITY   = (1 << 7), /* keep activity stats */
        ATA_LFLAG_NO_LPM        = (1 << 8), /* disable LPM on this link */
+       ATA_LFLAG_RST_ONCE      = (1 << 9), /* limit recovery to one reset */
 
        /* struct ata_port flags */
        ATA_FLAG_SLAVE_POSS     = (1 << 0), /* host supports slave dev */
@@ -986,8 +987,7 @@ extern int ata_host_activate(struct ata_host *host, int irq,
                             irq_handler_t irq_handler, unsigned long irq_flags,
                             struct scsi_host_template *sht);
 extern void ata_host_detach(struct ata_host *host);
-extern void ata_host_init(struct ata_host *, struct device *,
-                         unsigned long, struct ata_port_operations *);
+extern void ata_host_init(struct ata_host *, struct device *, struct ata_port_operations *);
 extern int ata_scsi_detect(struct scsi_host_template *sht);
 extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg);
 extern int ata_scsi_queuecmd(struct Scsi_Host *h, struct scsi_cmnd *cmd);
@@ -1012,6 +1012,17 @@ extern bool ata_link_offline(struct ata_link *link);
 #ifdef CONFIG_PM
 extern int ata_host_suspend(struct ata_host *host, pm_message_t mesg);
 extern void ata_host_resume(struct ata_host *host);
+extern int ata_sas_port_async_suspend(struct ata_port *ap, int *async);
+extern int ata_sas_port_async_resume(struct ata_port *ap, int *async);
+#else
+static inline int ata_sas_port_async_suspend(struct ata_port *ap, int *async)
+{
+       return 0;
+}
+static inline int ata_sas_port_async_resume(struct ata_port *ap, int *async)
+{
+       return 0;
+}
 #endif
 extern int ata_ratelimit(void);
 extern void ata_msleep(struct ata_port *ap, unsigned int msecs);
index 40c372165f3edc0413a709c57c4e728bd0198ca5..32a1b5cfeba1f426547127233c84732363fc4e30 100644 (file)
@@ -16,6 +16,7 @@ struct pcap_subdev {
 struct pcap_platform_data {
        unsigned int irq_base;
        unsigned int config;
+       int gpio;
        void (*init) (void *);  /* board specific init */
        int num_subdevs;
        struct pcap_subdev *subdevs;
index 3d7ae4d7fd3688ab8c5771d710ee5e9803cd7dc9..46c0f320ed764ab33b4dfe9d18ad796c1bfa722f 100644 (file)
@@ -74,6 +74,7 @@ enum max77686_regulators {
 struct max77686_regulator_data {
        int id;
        struct regulator_init_data *initdata;
+       struct device_node *of_node;
 };
 
 enum max77686_opmode {
index f350fd0ba1dfd566374afb8afb86fdf1d1ba95ef..94514710a03f721b999a9a09f49ac2845ccf5a85 100644 (file)
@@ -14,6 +14,7 @@
 #define TPS6586X_SLEW_RATE_MASK         0x07
 
 enum {
+       TPS6586X_ID_SYS,
        TPS6586X_ID_SM_0,
        TPS6586X_ID_SM_1,
        TPS6586X_ID_SM_2,
index ac83b105bedd66d2fb051ead198d11297ab650c3..fa8529a859b8b7637a6b25e76e15ba7848cd9f79 100644 (file)
@@ -97,7 +97,8 @@ struct sdhci_host {
 
        const struct sdhci_ops *ops;    /* Low level hw interface */
 
-       struct regulator *vmmc; /* Power regulator */
+       struct regulator *vmmc;         /* Power regulator (vmmc) */
+       struct regulator *vqmmc;        /* Signaling regulator (vccq) */
 
        /* Internal data */
        struct mmc_host *mmc;   /* MMC structure */
index 6955045199b09c006bce030bf21b8b0bdb011d15..78874b36112036dc04084ee0d7062bc98950409a 100644 (file)
@@ -232,7 +232,7 @@ struct of_device_id
        char    type[32];
        char    compatible[128];
 #ifdef __KERNEL__
-       void    *data;
+       const void *data;
 #else
        kernel_ulong_t data;
 #endif
index b2be02ebf453df40cb07ab7fdfa261903fa44c11..560ca53a75fa629b1be138b07f865f95c07b2bb3 100644 (file)
@@ -28,21 +28,49 @@ void *module_alloc(unsigned long size);
 /* Free memory returned from module_alloc. */
 void module_free(struct module *mod, void *module_region);
 
-/* Apply the given relocation to the (simplified) ELF.  Return -error
-   or 0. */
+/*
+ * Apply the given relocation to the (simplified) ELF.  Return -error
+ * or 0.
+ */
+#ifdef CONFIG_MODULES_USE_ELF_REL
 int apply_relocate(Elf_Shdr *sechdrs,
                   const char *strtab,
                   unsigned int symindex,
                   unsigned int relsec,
                   struct module *mod);
+#else
+static inline int apply_relocate(Elf_Shdr *sechdrs,
+                                const char *strtab,
+                                unsigned int symindex,
+                                unsigned int relsec,
+                                struct module *me)
+{
+       printk(KERN_ERR "module %s: REL relocation unsupported\n", me->name);
+       return -ENOEXEC;
+}
+#endif
 
-/* Apply the given add relocation to the (simplified) ELF.  Return
-   -error or 0 */
+/*
+ * Apply the given add relocation to the (simplified) ELF.  Return
+ * -error or 0
+ */
+#ifdef CONFIG_MODULES_USE_ELF_RELA
 int apply_relocate_add(Elf_Shdr *sechdrs,
                       const char *strtab,
                       unsigned int symindex,
                       unsigned int relsec,
                       struct module *mod);
+#else
+static inline int apply_relocate_add(Elf_Shdr *sechdrs,
+                                    const char *strtab,
+                                    unsigned int symindex,
+                                    unsigned int relsec,
+                                    struct module *me)
+{
+       printk(KERN_ERR "module %s: REL relocation unsupported\n", me->name);
+       return -ENOEXEC;
+}
+#endif
 
 /* Any final processing of module before access.  Return -error or 0. */
 int module_finalize(const Elf_Ehdr *hdr,
index 650ef352f045f48ec9874b611faf18fc2a2b94cb..211ff67e8b0d0c3def3389ed474ab098112fa749 100644 (file)
@@ -78,8 +78,6 @@ struct nand_bbt_descr {
 #define NAND_BBT_LASTBLOCK     0x00000010
 /* The bbt is at the given page, else we must scan for the bbt */
 #define NAND_BBT_ABSPAGE       0x00000020
-/* The bbt is at the given page, else we must scan for the bbt */
-#define NAND_BBT_SEARCH                0x00000040
 /* bbt is stored per chip on multichip devices */
 #define NAND_BBT_PERCHIP       0x00000080
 /* bbt has a version counter at offset veroffs */
@@ -110,7 +108,10 @@ struct nand_bbt_descr {
  * OOB area. This option is passed to the default bad block table function.
  */
 #define NAND_BBT_USE_FLASH     0x00020000
-/* Do not store flash based bad block table in OOB area; store it in-band */
+/*
+ * Do not store flash based bad block table marker in the OOB area; store it
+ * in-band.
+ */
 #define NAND_BBT_NO_OOB                0x00040000
 /*
  * Do not write new bad block markers to OOB; useful, e.g., when ECC covers
index 63dadc0dfb629a74f6e578a16255ffc4cdb4d56a..81d61e70459938e6aab57239898e31fc8389e25c 100644 (file)
@@ -265,14 +265,7 @@ int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
 int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
                    const u_char *buf);
 
-static inline int mtd_read_oob(struct mtd_info *mtd, loff_t from,
-                              struct mtd_oob_ops *ops)
-{
-       ops->retlen = ops->oobretlen = 0;
-       if (!mtd->_read_oob)
-               return -EOPNOTSUPP;
-       return mtd->_read_oob(mtd, from, ops);
-}
+int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops);
 
 static inline int mtd_write_oob(struct mtd_info *mtd, loff_t to,
                                struct mtd_oob_ops *ops)
index 57977c6405292347f8026fd23f7bc4572312e345..6dce5a7154bbd95bea5498371cb60b18b3185a4b 100644 (file)
@@ -185,12 +185,6 @@ typedef enum {
  * This happens with the Renesas AG-AND chips, possibly others.
  */
 #define BBT_AUTO_REFRESH       0x00000080
-/*
- * Chip does not require ready check on read. True
- * for all large page devices, as they do not support
- * autoincrement.
- */
-#define NAND_NO_READRDY                0x00000100
 /* Chip does not allow subpage writes */
 #define NAND_NO_SUBPAGE_WRITE  0x00000200
 
@@ -361,13 +355,13 @@ struct nand_ecc_ctrl {
                        uint8_t *calc_ecc);
        int (*read_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
                        uint8_t *buf, int oob_required, int page);
-       void (*write_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
+       int (*write_page_raw)(struct mtd_info *mtd, struct nand_chip *chip,
                        const uint8_t *buf, int oob_required);
        int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip,
                        uint8_t *buf, int oob_required, int page);
        int (*read_subpage)(struct mtd_info *mtd, struct nand_chip *chip,
                        uint32_t offs, uint32_t len, uint8_t *buf);
-       void (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
+       int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
                        const uint8_t *buf, int oob_required);
        int (*write_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip,
                        int page);
@@ -559,6 +553,7 @@ struct nand_chip {
 #define NAND_MFR_MICRON                0x2c
 #define NAND_MFR_AMD           0x01
 #define NAND_MFR_MACRONIX      0xc2
+#define NAND_MFR_EON           0x92
 
 /**
  * struct nand_flash_dev - NAND Flash Device ID Structure
index a38e1fa8af0194d5e2ac43be29f3a65a313afd76..ade44c1f4027b30dad2084dc3d2bfd91311ec927 100644 (file)
@@ -49,7 +49,6 @@
 #define        FLERRADR(f)             (f->reg + 0x98)
 
 /* FLCMNCR control bits */
-#define ECCPOS2                (0x1 << 25)
 #define _4ECCCNTEN     (0x1 << 24)
 #define _4ECCEN                (0x1 << 23)
 #define _4ECCCORRECT   (0x1 << 22)
@@ -59,9 +58,6 @@
 #define QTSEL_E                (0x1 << 17)
 #define ENDIAN         (0x1 << 16)     /* 1 = little endian */
 #define FCKSEL_E       (0x1 << 15)
-#define ECCPOS_00      (0x00 << 12)
-#define ECCPOS_01      (0x01 << 12)
-#define ECCPOS_02      (0x02 << 12)
 #define ACM_SACCES_MODE        (0x01 << 10)
 #define NANWF_E                (0x1 << 9)
 #define SE_D           (0x1 << 8)      /* Spare area disable */
 #define DOCMD2_E       (0x1 << 17)     /* 2nd cmd stage execute */
 #define DOCMD1_E       (0x1 << 16)     /* 1st cmd stage execute */
 
+/* FLINTDMACR control bits */
+#define ESTERINTE      (0x1 << 24)     /* ECC error interrupt enable */
+#define AC1CLR         (0x1 << 19)     /* ECC FIFO clear */
+#define AC0CLR         (0x1 << 18)     /* Data FIFO clear */
+#define ECERB          (0x1 << 9)      /* ECC error */
+#define STERB          (0x1 << 8)      /* Status error */
+#define STERINTE       (0x1 << 4)      /* Status error enable */
+
 /* FLTRCR control bits */
 #define TRSTRT         (0x1 << 0)      /* translation start */
 #define TREND          (0x1 << 1)      /* translation end */
 #define        _4ECCEND        (0x1 << 1)      /* 4 symbols end */
 #define        _4ECCEXST       (0x1 << 0)      /* 4 symbols exist */
 
-#define INIT_FL4ECCRESULT_VAL  0x03FF03FF
-#define LOOP_TIMEOUT_MAX       0x00010000
+#define LOOP_TIMEOUT_MS        100
+
+enum flctl_ecc_res_t {
+       FL_SUCCESS,
+       FL_REPAIRABLE,
+       FL_ERROR,
+       FL_TIMEOUT
+};
 
 struct sh_flctl {
        struct mtd_info         mtd;
@@ -145,8 +155,7 @@ struct sh_flctl {
        uint32_t erase_ADRCNT;          /* bits of FLCMDCR in ERASE1 cmd */
        uint32_t rw_ADRCNT;     /* bits of FLCMDCR in READ WRITE cmd */
        uint32_t flcmncr_base;  /* base value of FLCMNCR */
-
-       int     hwecc_cant_correct[4];
+       uint32_t flintdmacr_base;       /* irq enable bits */
 
        unsigned page_size:1;   /* NAND page size (0 = 512, 1 = 2048) */
        unsigned hwecc:1;       /* Hardware ECC (0 = disabled, 1 = enabled) */
index 51bf8ada6dc0166b103c4d11067d92fbb2496d78..49258e0ed1c679e4dfacc488b8e94aa49e7d815e 100644 (file)
@@ -15,6 +15,8 @@
 #define MV643XX_ETH_SIZE_REG_4         0x2224
 #define MV643XX_ETH_BASE_ADDR_ENABLE_REG       0x2290
 
+#define MV643XX_TX_CSUM_DEFAULT_LIMIT  0
+
 struct mv643xx_eth_shared_platform_data {
        struct mbus_dram_target_info    *dram;
        struct platform_device  *shared_smi;
index eb06e58bed0b2dc9c7e2d6a9b166d69380556e58..8ba0cd27b70b81fd0480138ca15c5ab0cd3924e9 100644 (file)
@@ -953,7 +953,8 @@ struct net_device_ops {
 #ifdef CONFIG_NET_POLL_CONTROLLER
        void                    (*ndo_poll_controller)(struct net_device *dev);
        int                     (*ndo_netpoll_setup)(struct net_device *dev,
-                                                    struct netpoll_info *info);
+                                                    struct netpoll_info *info,
+                                                    gfp_t gfp);
        void                    (*ndo_netpoll_cleanup)(struct net_device *dev);
 #endif
        int                     (*ndo_set_vf_mac)(struct net_device *dev,
@@ -1300,6 +1301,8 @@ struct net_device {
        /* for setting kernel sock attribute on TCP connection setup */
 #define GSO_MAX_SIZE           65536
        unsigned int            gso_max_size;
+#define GSO_MAX_SEGS           65535
+       u16                     gso_max_segs;
 
 #ifdef CONFIG_DCB
        /* Data Center Bridging netlink ops */
@@ -2244,8 +2247,6 @@ extern void netif_carrier_on(struct net_device *dev);
 
 extern void netif_carrier_off(struct net_device *dev);
 
-extern void netif_notify_peers(struct net_device *dev);
-
 /**
  *     netif_dormant_on - mark device as dormant.
  *     @dev: network device
@@ -2594,8 +2595,7 @@ extern void               __dev_set_rx_mode(struct net_device *dev);
 extern int             dev_set_promiscuity(struct net_device *dev, int inc);
 extern int             dev_set_allmulti(struct net_device *dev, int inc);
 extern void            netdev_state_change(struct net_device *dev);
-extern int             netdev_bonding_change(struct net_device *dev,
-                                             unsigned long event);
+extern void            netdev_notify_peers(struct net_device *dev);
 extern void            netdev_features_change(struct net_device *dev);
 /* Load a device via the kmod */
 extern void            dev_load(struct net *net, const char *name);
index 28f5389c924b51b76cf88dc5da1af7f3a0853138..66d5379c305e60d17dcde8b60d286f0b57b23a16 100644 (file)
@@ -23,6 +23,7 @@ struct netpoll {
        u8 remote_mac[ETH_ALEN];
 
        struct list_head rx; /* rx_np list element */
+       struct rcu_head rcu;
 };
 
 struct netpoll_info {
@@ -38,28 +39,40 @@ struct netpoll_info {
        struct delayed_work tx_work;
 
        struct netpoll *netpoll;
+       struct rcu_head rcu;
 };
 
 void netpoll_send_udp(struct netpoll *np, const char *msg, int len);
 void netpoll_print_options(struct netpoll *np);
 int netpoll_parse_options(struct netpoll *np, char *opt);
-int __netpoll_setup(struct netpoll *np, struct net_device *ndev);
+int __netpoll_setup(struct netpoll *np, struct net_device *ndev, gfp_t gfp);
 int netpoll_setup(struct netpoll *np);
 int netpoll_trap(void);
 void netpoll_set_trap(int trap);
 void __netpoll_cleanup(struct netpoll *np);
+void __netpoll_free_rcu(struct netpoll *np);
 void netpoll_cleanup(struct netpoll *np);
-int __netpoll_rx(struct sk_buff *skb);
+int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo);
 void netpoll_send_skb_on_dev(struct netpoll *np, struct sk_buff *skb,
                             struct net_device *dev);
 static inline void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb)
 {
+       unsigned long flags;
+       local_irq_save(flags);
        netpoll_send_skb_on_dev(np, skb, np->dev);
+       local_irq_restore(flags);
 }
 
 
 
 #ifdef CONFIG_NETPOLL
+static inline bool netpoll_rx_on(struct sk_buff *skb)
+{
+       struct netpoll_info *npinfo = rcu_dereference_bh(skb->dev->npinfo);
+
+       return npinfo && (!list_empty(&npinfo->rx_np) || npinfo->rx_flags);
+}
+
 static inline bool netpoll_rx(struct sk_buff *skb)
 {
        struct netpoll_info *npinfo;
@@ -67,14 +80,14 @@ static inline bool netpoll_rx(struct sk_buff *skb)
        bool ret = false;
 
        local_irq_save(flags);
-       npinfo = rcu_dereference_bh(skb->dev->npinfo);
 
-       if (!npinfo || (list_empty(&npinfo->rx_np) && !npinfo->rx_flags))
+       if (!netpoll_rx_on(skb))
                goto out;
 
+       npinfo = rcu_dereference_bh(skb->dev->npinfo);
        spin_lock(&npinfo->rx_lock);
        /* check rx_flags again with the lock held */
-       if (npinfo->rx_flags && __netpoll_rx(skb))
+       if (npinfo->rx_flags && __netpoll_rx(skb, npinfo))
                ret = true;
        spin_unlock(&npinfo->rx_lock);
 
@@ -83,13 +96,6 @@ out:
        return ret;
 }
 
-static inline int netpoll_rx_on(struct sk_buff *skb)
-{
-       struct netpoll_info *npinfo = rcu_dereference_bh(skb->dev->npinfo);
-
-       return npinfo && (!list_empty(&npinfo->rx_np) || npinfo->rx_flags);
-}
-
 static inline int netpoll_receive_skb(struct sk_buff *skb)
 {
        if (!list_empty(&skb->dev->napi_list))
@@ -119,7 +125,7 @@ static inline void netpoll_poll_unlock(void *have)
        }
 }
 
-static inline int netpoll_tx_running(struct net_device *dev)
+static inline bool netpoll_tx_running(struct net_device *dev)
 {
        return irqs_disabled();
 }
@@ -127,11 +133,11 @@ static inline int netpoll_tx_running(struct net_device *dev)
 #else
 static inline bool netpoll_rx(struct sk_buff *skb)
 {
-       return 0;
+       return false;
 }
-static inline int netpoll_rx_on(struct sk_buff *skb)
+static inline bool netpoll_rx_on(struct sk_buff *skb)
 {
-       return 0;
+       return false;
 }
 static inline int netpoll_receive_skb(struct sk_buff *skb)
 {
@@ -147,9 +153,9 @@ static inline void netpoll_poll_unlock(void *have)
 static inline void netpoll_netdev_init(struct net_device *dev)
 {
 }
-static inline int netpoll_tx_running(struct net_device *dev)
+static inline bool netpoll_tx_running(struct net_device *dev)
 {
-       return 0;
+       return false;
 }
 #endif
 
index 880805774f9f105425a7eade9721b9965f7d43c9..92ce5783b707df8ea90306aaf145f1fbba3d02a2 100644 (file)
@@ -69,6 +69,7 @@ struct nfs_pageio_descriptor {
        const struct nfs_pgio_completion_ops *pg_completion_ops;
        struct pnfs_layout_segment *pg_lseg;
        struct nfs_direct_req   *pg_dreq;
+       void                    *pg_layout_private;
 };
 
 #define NFS_WBACK_BUSY(req)    (test_bit(PG_BUSY,&(req)->wb_flags))
index 00485e084394d4ca1a5782b3cd54fc63e9b06acd..ac7c8ae254f251933e48f04d5c877eaaa3ec6e09 100644 (file)
@@ -1248,6 +1248,7 @@ struct nfs_pgio_header {
        void (*release) (struct nfs_pgio_header *hdr);
        const struct nfs_pgio_completion_ops *completion_ops;
        struct nfs_direct_req   *dreq;
+       void                    *layout_private;
        spinlock_t              lock;
        /* fields protected by lock */
        int                     pnfs_error;
diff --git a/include/linux/nx842.h b/include/linux/nx842.h
new file mode 100644 (file)
index 0000000..a4d324c
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef __NX842_H__
+#define __NX842_H__
+
+int nx842_get_workmem_size(void);
+int nx842_get_workmem_size_aligned(void);
+int nx842_compress(const unsigned char *in, unsigned int in_len,
+               unsigned char *out, unsigned int *out_len, void *wrkmem);
+int nx842_decompress(const unsigned char *in, unsigned int in_len,
+               unsigned char *out, unsigned int *out_len, void *wrkmem);
+
+#endif
index 01b925ad8d78c62b7fad6ac84dfb179d9bf3a763..c3cdc1025c30694eee350d9cd62609e4db40de02 100644 (file)
@@ -6,6 +6,7 @@
 
 #ifdef CONFIG_OF_ADDRESS
 extern u64 of_translate_address(struct device_node *np, const __be32 *addr);
+extern bool of_can_translate_address(struct device_node *dev);
 extern int of_address_to_resource(struct device_node *dev, int index,
                                  struct resource *r);
 extern struct device_node *of_find_matching_node_by_address(
index c73a34c3434d75150cc4f6440e3ba3a5a8ffc47f..c090cf9249bb68b6d1bcf1dec4d8e70f63e03137 100644 (file)
@@ -28,6 +28,7 @@
 #define OMAP3_ISP_USER_H
 
 #include <linux/types.h>
+#include <linux/videodev2.h>
 
 /*
  * Private IOCTLs
@@ -427,7 +428,7 @@ struct omap3isp_ccdc_update_config {
 #define OMAP3ISP_PREV_COLOR_CONV       (1 << 8)
 #define OMAP3ISP_PREV_YC_LIMIT         (1 << 9)
 #define OMAP3ISP_PREV_DEFECT_COR       (1 << 10)
-#define OMAP3ISP_PREV_GAMMABYPASS      (1 << 11)
+/* Bit 11 was OMAP3ISP_PREV_GAMMABYPASS, now merged with OMAP3ISP_PREV_GAMMA */
 #define OMAP3ISP_PREV_DRK_FRM_CAPTURE  (1 << 12)
 #define OMAP3ISP_PREV_DRK_FRM_SUBTRACT (1 << 13)
 #define OMAP3ISP_PREV_LENS_SHADING     (1 << 14)
@@ -436,6 +437,7 @@ struct omap3isp_ccdc_update_config {
 
 #define OMAP3ISP_PREV_NF_TBL_SIZE      64
 #define OMAP3ISP_PREV_CFA_TBL_SIZE     576
+#define OMAP3ISP_PREV_CFA_BLK_SIZE     (OMAP3ISP_PREV_CFA_TBL_SIZE / 4)
 #define OMAP3ISP_PREV_GAMMA_TBL_SIZE   1024
 #define OMAP3ISP_PREV_YENH_TBL_SIZE    128
 
@@ -477,7 +479,7 @@ struct omap3isp_prev_cfa {
        enum omap3isp_cfa_fmt format;
        __u8 gradthrs_vert;
        __u8 gradthrs_horz;
-       __u32 table[OMAP3ISP_PREV_CFA_TBL_SIZE];
+       __u32 table[4][OMAP3ISP_PREV_CFA_BLK_SIZE];
 };
 
 /**
diff --git a/include/linux/packet_diag.h b/include/linux/packet_diag.h
new file mode 100644 (file)
index 0000000..ea2e892
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef __PACKET_DIAG_H__
+#define __PACKET_DIAG_H__
+
+#include <linux/types.h>
+
+struct packet_diag_req {
+       __u8    sdiag_family;
+       __u8    sdiag_protocol;
+       __u16   pad;
+       __u32   pdiag_ino;
+       __u32   pdiag_show;
+       __u32   pdiag_cookie[2];
+};
+
+#define PACKET_SHOW_INFO       0x00000001 /* Basic packet_sk information */
+#define PACKET_SHOW_MCLIST     0x00000002 /* A set of packet_diag_mclist-s */
+
+struct packet_diag_msg {
+       __u8    pdiag_family;
+       __u8    pdiag_type;
+       __u16   pdiag_num;
+
+       __u32   pdiag_ino;
+       __u32   pdiag_cookie[2];
+};
+
+enum {
+       PACKET_DIAG_INFO,
+       PACKET_DIAG_MCLIST,
+
+       PACKET_DIAG_MAX,
+};
+
+struct packet_diag_info {
+       __u32   pdi_index;
+       __u32   pdi_version;
+       __u32   pdi_reserve;
+       __u32   pdi_copy_thresh;
+       __u32   pdi_tstamp;
+       __u32   pdi_flags;
+
+#define PDI_RUNNING    0x1
+#define PDI_AUXDATA    0x2
+#define PDI_ORIGDEV    0x4
+#define PDI_VNETHDR    0x8
+#define PDI_LOSS       0x10
+};
+
+struct packet_diag_mclist {
+       __u32   pdmc_index;
+       __u32   pdmc_count;
+       __u16   pdmc_type;
+       __u16   pdmc_alen;
+       __u8    pdmc_addr[MAX_ADDR_LEN];
+};
+
+#endif
index 76c5c8b724a77253e3ca635c90e53ed6230b3c5f..7602ccb3f40ec672001be2eae9be3395604493f2 100644 (file)
@@ -1272,7 +1272,8 @@ static inline bool perf_paranoid_kernel(void)
 extern void perf_event_init(void);
 extern void perf_tp_event(u64 addr, u64 count, void *record,
                          int entry_size, struct pt_regs *regs,
-                         struct hlist_head *head, int rctx);
+                         struct hlist_head *head, int rctx,
+                         struct task_struct *task);
 extern void perf_bp_event(struct perf_event *event, void *data);
 
 #ifndef perf_misc_flags
index 6dd96fb45482b00b0ede76c92f83fc6bd76f0f2f..d2816454c2633fb6b68bc576dc053eea27fd0920 100644 (file)
@@ -20,6 +20,7 @@
 /* This struct is private to the core and should be regarded as a cookie */
 struct pinctrl;
 struct pinctrl_state;
+struct device;
 
 #ifdef CONFIG_PINCTRL
 
@@ -139,7 +140,7 @@ static inline struct pinctrl * __must_check devm_pinctrl_get_select(
        s = pinctrl_lookup_state(p, name);
        if (IS_ERR(s)) {
                devm_pinctrl_put(p);
-               return ERR_PTR(PTR_ERR(s));
+               return ERR_CAST(s);
        }
 
        ret = pinctrl_select_state(p, s);
diff --git a/include/linux/platform_data/max310x.h b/include/linux/platform_data/max310x.h
new file mode 100644 (file)
index 0000000..91648bf
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ *  Maxim (Dallas) MAX3107/8 serial driver
+ *
+ *  Copyright (C) 2012 Alexander Shiyan <shc_work@mail.ru>
+ *
+ *  Based on max3100.c, by Christian Pellegrin <chripell@evolware.org>
+ *  Based on max3110.c, by Feng Tang <feng.tang@intel.com>
+ *  Based on max3107.c, by Aavamobile
+ *
+ *  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 _MAX310X_H_
+#define _MAX310X_H_
+
+/*
+ * Example board initialization data:
+ *
+ * static struct max310x_pdata max3107_pdata = {
+ *     .driver_flags   = MAX310X_EXT_CLK,
+ *     .uart_flags[0]  = MAX310X_ECHO_SUPRESS | MAX310X_AUTO_DIR_CTRL,
+ *     .frequency      = 3686400,
+ *     .gpio_base      = -1,
+ * };
+ *
+ * static struct spi_board_info spi_device_max3107[] = {
+ *     {
+ *             .modalias       = "max3107",
+ *             .irq            = IRQ_EINT3,
+ *             .bus_num        = 1,
+ *             .chip_select    = 1,
+ *             .platform_data  = &max3107_pdata,
+ *     },
+ * };
+ */
+
+#define MAX310X_MAX_UARTS      1
+
+/* MAX310X platform data structure */
+struct max310x_pdata {
+       /* Flags global to driver */
+       const u8                driver_flags:2;
+#define MAX310X_EXT_CLK                (0x00000001)    /* External clock enable */
+#define MAX310X_AUTOSLEEP      (0x00000002)    /* Enable AutoSleep mode */
+       /* Flags global to UART port */
+       const u8                uart_flags[MAX310X_MAX_UARTS];
+#define MAX310X_LOOPBACK       (0x00000001)    /* Loopback mode enable */
+#define MAX310X_ECHO_SUPRESS   (0x00000002)    /* Enable echo supress */
+#define MAX310X_AUTO_DIR_CTRL  (0x00000004)    /* Enable Auto direction
+                                                * control (RS-485)
+                                                */
+       /* Frequency (extrenal clock or crystal) */
+       const int               frequency;
+       /* GPIO base number (can be negative) */
+       const int               gpio_base;
+       /* Called during startup */
+       void (*init)(void);
+       /* Called before finish */
+       void (*exit)(void);
+       /* Suspend callback */
+       void (*suspend)(int do_suspend);
+};
+
+#endif
similarity index 72%
rename from arch/arm/mach-u300/include/mach/gpio-u300.h
rename to include/linux/platform_data/pinctrl-coh901.h
index e81400c1753aad7fa03db27cde769c2bf2d8f78c..30dea251b835b3433af3fd93a840a2d70a91cc57 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007-2011 ST-Ericsson AB
+ * Copyright (C) 2007-2012 ST-Ericsson AB
  * License terms: GNU General Public License (GPL) version 2
  * GPIO block resgister definitions and inline macros for
  * U300 GPIO COH 901 335 or COH 901 571/3
@@ -9,25 +9,14 @@
 #ifndef __MACH_U300_GPIO_U300_H
 #define __MACH_U300_GPIO_U300_H
 
-/**
- * enum u300_gpio_variant - the type of U300 GPIO employed
- */
-enum u300_gpio_variant {
-       U300_GPIO_COH901335,
-       U300_GPIO_COH901571_3_BS335,
-       U300_GPIO_COH901571_3_BS365,
-};
-
 /**
  * struct u300_gpio_platform - U300 GPIO platform data
- * @variant: IP block variant
  * @ports: number of GPIO block ports
  * @gpio_base: first GPIO number for this block (use a free range)
  * @gpio_irq_base: first GPIO IRQ number for this block (use a free range)
  * @pinctrl_device: pin control device to spawn as child
  */
 struct u300_gpio_platform {
-       enum u300_gpio_variant variant;
        u8 ports;
        int gpio_base;
        int gpio_irq_base;
index f067e60a38322fa3a935249cc75c185a8bf522af..44d1f2307dbc3a9d21ed0bb6a0e1948e91415b1a 100644 (file)
@@ -510,12 +510,14 @@ struct dev_pm_info {
        bool                    is_prepared:1;  /* Owned by the PM core */
        bool                    is_suspended:1; /* Ditto */
        bool                    ignore_children:1;
+       bool                    early_init:1;   /* Owned by the PM core */
        spinlock_t              lock;
 #ifdef CONFIG_PM_SLEEP
        struct list_head        entry;
        struct completion       completion;
        struct wakeup_source    *wakeup;
        bool                    wakeup_path:1;
+       bool                    syscore:1;
 #else
        unsigned int            should_wakeup:1;
 #endif
index a7d6172922d405c950c701bf4a7d2d21bb4e0c77..7c1d252b20c08de0ec725976c67b6fc13326e2e0 100644 (file)
@@ -114,7 +114,6 @@ struct generic_pm_domain_data {
        struct mutex lock;
        unsigned int refcount;
        bool need_restore;
-       bool always_on;
 };
 
 #ifdef CONFIG_PM_GENERIC_DOMAINS
@@ -139,36 +138,32 @@ extern int __pm_genpd_of_add_device(struct device_node *genpd_node,
                                    struct device *dev,
                                    struct gpd_timing_data *td);
 
-static inline int pm_genpd_add_device(struct generic_pm_domain *genpd,
-                                     struct device *dev)
-{
-       return __pm_genpd_add_device(genpd, dev, NULL);
-}
-
-static inline int pm_genpd_of_add_device(struct device_node *genpd_node,
-                                        struct device *dev)
-{
-       return __pm_genpd_of_add_device(genpd_node, dev, NULL);
-}
+extern int __pm_genpd_name_add_device(const char *domain_name,
+                                     struct device *dev,
+                                     struct gpd_timing_data *td);
 
 extern int pm_genpd_remove_device(struct generic_pm_domain *genpd,
                                  struct device *dev);
-extern void pm_genpd_dev_always_on(struct device *dev, bool val);
 extern void pm_genpd_dev_need_restore(struct device *dev, bool val);
 extern int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
                                  struct generic_pm_domain *new_subdomain);
+extern int pm_genpd_add_subdomain_names(const char *master_name,
+                                       const char *subdomain_name);
 extern int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
                                     struct generic_pm_domain *target);
 extern int pm_genpd_add_callbacks(struct device *dev,
                                  struct gpd_dev_ops *ops,
                                  struct gpd_timing_data *td);
 extern int __pm_genpd_remove_callbacks(struct device *dev, bool clear_td);
-extern int genpd_attach_cpuidle(struct generic_pm_domain *genpd, int state);
-extern int genpd_detach_cpuidle(struct generic_pm_domain *genpd);
+extern int pm_genpd_attach_cpuidle(struct generic_pm_domain *genpd, int state);
+extern int pm_genpd_name_attach_cpuidle(const char *name, int state);
+extern int pm_genpd_detach_cpuidle(struct generic_pm_domain *genpd);
+extern int pm_genpd_name_detach_cpuidle(const char *name);
 extern void pm_genpd_init(struct generic_pm_domain *genpd,
                          struct dev_power_governor *gov, bool is_off);
 
 extern int pm_genpd_poweron(struct generic_pm_domain *genpd);
+extern int pm_genpd_name_poweron(const char *domain_name);
 
 extern bool default_stop_ok(struct device *dev);
 
@@ -189,8 +184,15 @@ static inline int __pm_genpd_add_device(struct generic_pm_domain *genpd,
 {
        return -ENOSYS;
 }
-static inline int pm_genpd_add_device(struct generic_pm_domain *genpd,
-                                     struct device *dev)
+static inline int __pm_genpd_of_add_device(struct device_node *genpd_node,
+                                          struct device *dev,
+                                          struct gpd_timing_data *td)
+{
+       return -ENOSYS;
+}
+static inline int __pm_genpd_name_add_device(const char *domain_name,
+                                            struct device *dev,
+                                            struct gpd_timing_data *td)
 {
        return -ENOSYS;
 }
@@ -199,13 +201,17 @@ static inline int pm_genpd_remove_device(struct generic_pm_domain *genpd,
 {
        return -ENOSYS;
 }
-static inline void pm_genpd_dev_always_on(struct device *dev, bool val) {}
 static inline void pm_genpd_dev_need_restore(struct device *dev, bool val) {}
 static inline int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
                                         struct generic_pm_domain *new_sd)
 {
        return -ENOSYS;
 }
+static inline int pm_genpd_add_subdomain_names(const char *master_name,
+                                              const char *subdomain_name)
+{
+       return -ENOSYS;
+}
 static inline int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
                                            struct generic_pm_domain *target)
 {
@@ -221,11 +227,19 @@ static inline int __pm_genpd_remove_callbacks(struct device *dev, bool clear_td)
 {
        return -ENOSYS;
 }
-static inline int genpd_attach_cpuidle(struct generic_pm_domain *genpd, int st)
+static inline int pm_genpd_attach_cpuidle(struct generic_pm_domain *genpd, int st)
 {
        return -ENOSYS;
 }
-static inline int genpd_detach_cpuidle(struct generic_pm_domain *genpd)
+static inline int pm_genpd_name_attach_cpuidle(const char *name, int state)
+{
+       return -ENOSYS;
+}
+static inline int pm_genpd_detach_cpuidle(struct generic_pm_domain *genpd)
+{
+       return -ENOSYS;
+}
+static inline int pm_genpd_name_detach_cpuidle(const char *name)
 {
        return -ENOSYS;
 }
@@ -237,6 +251,10 @@ static inline int pm_genpd_poweron(struct generic_pm_domain *genpd)
 {
        return -ENOSYS;
 }
+static inline int pm_genpd_name_poweron(const char *domain_name)
+{
+       return -ENOSYS;
+}
 static inline bool default_stop_ok(struct device *dev)
 {
        return false;
@@ -245,6 +263,24 @@ static inline bool default_stop_ok(struct device *dev)
 #define pm_domain_always_on_gov NULL
 #endif
 
+static inline int pm_genpd_add_device(struct generic_pm_domain *genpd,
+                                     struct device *dev)
+{
+       return __pm_genpd_add_device(genpd, dev, NULL);
+}
+
+static inline int pm_genpd_of_add_device(struct device_node *genpd_node,
+                                        struct device *dev)
+{
+       return __pm_genpd_of_add_device(genpd_node, dev, NULL);
+}
+
+static inline int pm_genpd_name_add_device(const char *domain_name,
+                                          struct device *dev)
+{
+       return __pm_genpd_name_add_device(domain_name, dev, NULL);
+}
+
 static inline int pm_genpd_remove_callbacks(struct device *dev)
 {
        return __pm_genpd_remove_callbacks(dev, true);
@@ -258,4 +294,20 @@ static inline void genpd_queue_power_off_work(struct generic_pm_domain *gpd) {}
 static inline void pm_genpd_poweroff_unused(void) {}
 #endif
 
+#ifdef CONFIG_PM_GENERIC_DOMAINS_SLEEP
+extern void pm_genpd_syscore_switch(struct device *dev, bool suspend);
+#else
+static inline void pm_genpd_syscore_switch(struct device *dev, bool suspend) {}
+#endif
+
+static inline void pm_genpd_syscore_poweroff(struct device *dev)
+{
+       pm_genpd_syscore_switch(dev, true);
+}
+
+static inline void pm_genpd_syscore_poweron(struct device *dev)
+{
+       pm_genpd_syscore_switch(dev, false);
+}
+
 #endif /* _LINUX_PM_DOMAIN_H */
index 597e4fdb97fe4d676b5fa0b717ae53f023893e5e..3db698aee34cd9437f8f42823f17825796597f09 100644 (file)
@@ -130,8 +130,6 @@ extern void exit_ptrace(struct task_struct *tracer);
 #define PTRACE_MODE_READ       0x01
 #define PTRACE_MODE_ATTACH     0x02
 #define PTRACE_MODE_NOAUDIT    0x04
-/* Returns 0 on success, -errno on denial. */
-extern int __ptrace_may_access(struct task_struct *task, unsigned int mode);
 /* Returns true on success, false on denial. */
 extern bool ptrace_may_access(struct task_struct *task, unsigned int mode);
 
index 115ead2b51553d78a523c4e62db3cb4b84866cd0..42686c5b6772943fc7409b73f4bfc645a303979c 100644 (file)
@@ -191,6 +191,20 @@ extern void rcu_idle_enter(void);
 extern void rcu_idle_exit(void);
 extern void rcu_irq_enter(void);
 extern void rcu_irq_exit(void);
+
+#ifdef CONFIG_RCU_USER_QS
+extern void rcu_user_enter(void);
+extern void rcu_user_exit(void);
+extern void rcu_user_enter_irq(void);
+extern void rcu_user_exit_irq(void);
+extern void rcu_user_hooks_switch(struct task_struct *prev,
+                                 struct task_struct *next);
+#else
+static inline void rcu_user_enter(void) { }
+static inline void rcu_user_exit(void) { }
+#endif /* CONFIG_RCU_USER_QS */
+
+
 extern void exit_rcu(void);
 
 /**
@@ -210,14 +224,12 @@ extern void exit_rcu(void);
  * to nest RCU_NONIDLE() wrappers, but the nesting level is currently
  * quite limited.  If deeper nesting is required, it will be necessary
  * to adjust DYNTICK_TASK_NESTING_VALUE accordingly.
- *
- * This macro may be used from process-level code only.
  */
 #define RCU_NONIDLE(a) \
        do { \
-               rcu_idle_exit(); \
+               rcu_irq_enter(); \
                do { a; } while (0); \
-               rcu_idle_enter(); \
+               rcu_irq_exit(); \
        } while (0)
 
 /*
index 7f7e00df3adf9991ce844a280c4c5c03a9d7bcb6..9c4c9c673f38d65439fcf5d8c0298183f4538a2d 100644 (file)
@@ -285,6 +285,7 @@ struct regmap_irq {
  * @ack_base:    Base ack address.  If zero then the chip is clear on read.
  * @wake_base:   Base address for wake enables.  If zero unsupported.
  * @irq_reg_stride:  Stride to use for chips where registers are not contiguous.
+ * @runtime_pm:  Hold a runtime PM lock on the device when accessing it.
  *
  * @num_regs:    Number of registers in each control bank.
  * @irqs:        Descriptors for individual IRQs.  Interrupt numbers are
@@ -299,6 +300,7 @@ struct regmap_irq_chip {
        unsigned int ack_base;
        unsigned int wake_base;
        unsigned int irq_reg_stride;
+       bool runtime_pm;
 
        int num_regs;
 
index da339fd8c7559de74ad46dd3536f4b95981c89d8..21603524bdb2a218dc921751b12d0d6dcf8f3666 100644 (file)
@@ -352,4 +352,11 @@ static inline void regulator_set_drvdata(struct regulator *regulator,
 
 #endif
 
+static inline int regulator_set_voltage_tol(struct regulator *regulator,
+                                           int new_uV, int tol_uV)
+{
+       return regulator_set_voltage(regulator,
+                                    new_uV - tol_uV, new_uV + tol_uV);
+}
+
 #endif
index bac4c871f3bd1930b481c214e932cec9666e05b6..c10012f0af15d1277249157ac60afa2f6503e745 100644 (file)
@@ -58,6 +58,7 @@ enum regulator_status {
  *     regulator_desc.n_voltages.  Voltages may be reported in any order.
  *
  * @set_current_limit: Configure a limit for a current-limited regulator.
+ *                     The driver should select the current closest to max_uA.
  * @get_current_limit: Get the configured limit for a current-limited regulator.
  *
  * @set_mode: Set the configured operating mode for the regulator.
diff --git a/include/linux/sc26198.h b/include/linux/sc26198.h
deleted file mode 100644 (file)
index 7ca35ab..0000000
+++ /dev/null
@@ -1,533 +0,0 @@
-/*****************************************************************************/
-
-/*
- *     sc26198.h  -- SC26198 UART hardware info.
- *
- *     Copyright (C) 1995-1998  Stallion Technologies
- *
- *     This program is free software; you can redistribute it and/or modify
- *     it under the terms of the GNU General Public License as published by
- *     the Free Software Foundation; either version 2 of the License, or
- *     (at your option) any later version.
- *
- *     This program is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public License
- *     along with this program; if not, write to the Free Software
- *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/*****************************************************************************/
-#ifndef        _SC26198_H
-#define        _SC26198_H
-/*****************************************************************************/
-
-/*
- *     Define the number of async ports per sc26198 uart device.
- */
-#define        SC26198_PORTS           8
-
-/*
- *     Baud rate timing clocks. All derived from a master 14.7456 MHz clock.
- */
-#define        SC26198_MASTERCLOCK     14745600L
-#define        SC26198_DCLK            (SC26198_MASTERCLOCK)
-#define        SC26198_CCLK            (SC26198_MASTERCLOCK / 2)
-#define        SC26198_BCLK            (SC26198_MASTERCLOCK / 4)
-
-/*
- *     Define internal FIFO sizes for the 26198 ports.
- */
-#define        SC26198_TXFIFOSIZE      16
-#define        SC26198_RXFIFOSIZE      16
-
-/*****************************************************************************/
-
-/*
- *     Global register definitions. These registers are global to each 26198
- *     device, not specific ports on it.
- */
-#define        TSTR            0x0d
-#define        GCCR            0x0f
-#define        ICR             0x1b
-#define        WDTRCR          0x1d
-#define        IVR             0x1f
-#define        BRGTRUA         0x84
-#define        GPOSR           0x87
-#define        GPOC            0x8b
-#define        UCIR            0x8c
-#define        CIR             0x8c
-#define        BRGTRUB         0x8d
-#define        GRXFIFO         0x8e
-#define        GTXFIFO         0x8e
-#define        GCCR2           0x8f
-#define        BRGTRLA         0x94
-#define        GPOR            0x97
-#define        GPOD            0x9b
-#define        BRGTCR          0x9c
-#define        GICR            0x9c
-#define        BRGTRLB         0x9d
-#define        GIBCR           0x9d
-#define        GITR            0x9f
-
-/*
- *     Per port channel registers. These are the register offsets within
- *     the port address space, so need to have the port address (0 to 7)
- *     inserted in bit positions 4:6.
- */
-#define        MR0             0x00
-#define        MR1             0x01
-#define        IOPCR           0x02
-#define        BCRBRK          0x03
-#define        BCRCOS          0x04
-#define        BCRX            0x06
-#define        BCRA            0x07
-#define        XONCR           0x08
-#define        XOFFCR          0x09
-#define        ARCR            0x0a
-#define        RXCSR           0x0c
-#define        TXCSR           0x0e
-#define        MR2             0x80
-#define        SR              0x81
-#define SCCR           0x81
-#define        ISR             0x82
-#define        IMR             0x82
-#define        TXFIFO          0x83
-#define        RXFIFO          0x83
-#define        IPR             0x84
-#define        IOPIOR          0x85
-#define        XISR            0x86
-
-/*
- *     For any given port calculate the address to use to access a specified
- *     register. This is only used for unusual access, mostly this is done
- *     through the assembler access routines.
- */
-#define        SC26198_PORTREG(port,reg)       ((((port) & 0x07) << 4) | (reg))
-
-/*****************************************************************************/
-
-/*
- *     Global configuration control register bit definitions.
- */
-#define        GCCR_NOACK              0x00
-#define        GCCR_IVRACK             0x02
-#define        GCCR_IVRCHANACK         0x04
-#define        GCCR_IVRTYPCHANACK      0x06
-#define        GCCR_ASYNCCYCLE         0x00
-#define        GCCR_SYNCCYCLE          0x40
-
-/*****************************************************************************/
-
-/*
- *     Mode register 0 bit definitions.
- */
-#define        MR0_ADDRNONE            0x00
-#define        MR0_AUTOWAKE            0x01
-#define        MR0_AUTODOZE            0x02
-#define        MR0_AUTOWAKEDOZE        0x03
-#define        MR0_SWFNONE             0x00
-#define        MR0_SWFTX               0x04
-#define        MR0_SWFRX               0x08
-#define        MR0_SWFRXTX             0x0c
-#define        MR0_TXMASK              0x30
-#define        MR0_TXEMPTY             0x00
-#define        MR0_TXHIGH              0x10
-#define        MR0_TXHALF              0x20
-#define        MR0_TXRDY               0x00
-#define        MR0_ADDRNT              0x00
-#define        MR0_ADDRT               0x40
-#define        MR0_SWFNT               0x00
-#define        MR0_SWFT                0x80
-
-/*
- *     Mode register 1 bit definitions.
- */
-#define        MR1_CS5                 0x00
-#define        MR1_CS6                 0x01
-#define        MR1_CS7                 0x02
-#define        MR1_CS8                 0x03
-#define        MR1_PAREVEN             0x00
-#define        MR1_PARODD              0x04
-#define        MR1_PARENB              0x00
-#define        MR1_PARFORCE            0x08
-#define        MR1_PARNONE             0x10
-#define        MR1_PARSPECIAL          0x18
-#define        MR1_ERRCHAR             0x00
-#define        MR1_ERRBLOCK            0x20
-#define        MR1_ISRUNMASKED         0x00
-#define        MR1_ISRMASKED           0x40
-#define        MR1_AUTORTS             0x80
-
-/*
- *     Mode register 2 bit definitions.
- */
-#define        MR2_STOP1               0x00
-#define        MR2_STOP15              0x01
-#define        MR2_STOP2               0x02
-#define        MR2_STOP916             0x03
-#define        MR2_RXFIFORDY           0x00
-#define        MR2_RXFIFOHALF          0x04
-#define        MR2_RXFIFOHIGH          0x08
-#define        MR2_RXFIFOFULL          0x0c
-#define        MR2_AUTOCTS             0x10
-#define        MR2_TXRTS               0x20
-#define        MR2_MODENORM            0x00
-#define        MR2_MODEAUTOECHO        0x40
-#define        MR2_MODELOOP            0x80
-#define        MR2_MODEREMECHO         0xc0
-
-/*****************************************************************************/
-
-/*
- *     Baud Rate Generator (BRG) selector values.
- */
-#define        BRG_50                  0x00
-#define        BRG_75                  0x01
-#define        BRG_150                 0x02
-#define        BRG_200                 0x03
-#define        BRG_300                 0x04
-#define        BRG_450                 0x05
-#define        BRG_600                 0x06
-#define        BRG_900                 0x07
-#define        BRG_1200                0x08
-#define        BRG_1800                0x09
-#define        BRG_2400                0x0a
-#define        BRG_3600                0x0b
-#define        BRG_4800                0x0c
-#define        BRG_7200                0x0d
-#define        BRG_9600                0x0e
-#define        BRG_14400               0x0f
-#define        BRG_19200               0x10
-#define        BRG_28200               0x11
-#define        BRG_38400               0x12
-#define        BRG_57600               0x13
-#define        BRG_115200              0x14
-#define        BRG_230400              0x15
-#define        BRG_GIN0                0x16
-#define        BRG_GIN1                0x17
-#define        BRG_CT0                 0x18
-#define        BRG_CT1                 0x19
-#define        BRG_RX2TX316            0x1b
-#define        BRG_RX2TX31             0x1c
-
-#define        SC26198_MAXBAUD         921600
-
-/*****************************************************************************/
-
-/*
- *     Command register command definitions.
- */
-#define        CR_NULL                 0x04
-#define        CR_ADDRNORMAL           0x0c
-#define        CR_RXRESET              0x14
-#define        CR_TXRESET              0x1c
-#define        CR_CLEARRXERR           0x24
-#define        CR_BREAKRESET           0x2c
-#define        CR_TXSTARTBREAK         0x34
-#define        CR_TXSTOPBREAK          0x3c
-#define        CR_RTSON                0x44
-#define        CR_RTSOFF               0x4c
-#define        CR_ADDRINIT             0x5c
-#define        CR_RXERRBLOCK           0x6c
-#define        CR_TXSENDXON            0x84
-#define        CR_TXSENDXOFF           0x8c
-#define        CR_GANGXONSET           0x94
-#define        CR_GANGXOFFSET          0x9c
-#define        CR_GANGXONINIT          0xa4
-#define        CR_GANGXOFFINIT         0xac
-#define        CR_HOSTXON              0xb4
-#define        CR_HOSTXOFF             0xbc
-#define        CR_CANCELXOFF           0xc4
-#define        CR_ADDRRESET            0xdc
-#define        CR_RESETALLPORTS        0xf4
-#define        CR_RESETALL             0xfc
-
-#define        CR_RXENABLE             0x01
-#define        CR_TXENABLE             0x02
-
-/*****************************************************************************/
-
-/*
- *     Channel status register.
- */
-#define        SR_RXRDY                0x01
-#define        SR_RXFULL               0x02
-#define        SR_TXRDY                0x04
-#define        SR_TXEMPTY              0x08
-#define        SR_RXOVERRUN            0x10
-#define        SR_RXPARITY             0x20
-#define        SR_RXFRAMING            0x40
-#define        SR_RXBREAK              0x80
-
-#define        SR_RXERRS               (SR_RXPARITY | SR_RXFRAMING | SR_RXOVERRUN)
-
-/*****************************************************************************/
-
-/*
- *     Interrupt status register and interrupt mask register bit definitions.
- */
-#define        IR_TXRDY                0x01
-#define        IR_RXRDY                0x02
-#define        IR_RXBREAK              0x04
-#define        IR_XONXOFF              0x10
-#define        IR_ADDRRECOG            0x20
-#define        IR_RXWATCHDOG           0x40
-#define        IR_IOPORT               0x80
-
-/*****************************************************************************/
-
-/*
- *     Interrupt vector register field definitions.
- */
-#define        IVR_CHANMASK            0x07
-#define        IVR_TYPEMASK            0x18
-#define        IVR_CONSTMASK           0xc0
-
-#define        IVR_RXDATA              0x10
-#define        IVR_RXBADDATA           0x18
-#define        IVR_TXDATA              0x08
-#define        IVR_OTHER               0x00
-
-/*****************************************************************************/
-
-/*
- *     BRG timer control register bit definitions.
- */
-#define        BRGCTCR_DISABCLK0       0x00
-#define        BRGCTCR_ENABCLK0        0x08
-#define        BRGCTCR_DISABCLK1       0x00
-#define        BRGCTCR_ENABCLK1        0x80
-
-#define        BRGCTCR_0SCLK16         0x00
-#define        BRGCTCR_0SCLK32         0x01
-#define        BRGCTCR_0SCLK64         0x02
-#define        BRGCTCR_0SCLK128        0x03
-#define        BRGCTCR_0X1             0x04
-#define        BRGCTCR_0X12            0x05
-#define        BRGCTCR_0IO1A           0x06
-#define        BRGCTCR_0GIN0           0x07
-
-#define        BRGCTCR_1SCLK16         0x00
-#define        BRGCTCR_1SCLK32         0x10
-#define        BRGCTCR_1SCLK64         0x20
-#define        BRGCTCR_1SCLK128        0x30
-#define        BRGCTCR_1X1             0x40
-#define        BRGCTCR_1X12            0x50
-#define        BRGCTCR_1IO1B           0x60
-#define        BRGCTCR_1GIN1           0x70
-
-/*****************************************************************************/
-
-/*
- *     Watch dog timer enable register.
- */
-#define        WDTRCR_ENABALL          0xff
-
-/*****************************************************************************/
-
-/*
- *     XON/XOFF interrupt status register.
- */
-#define        XISR_TXCHARMASK         0x03
-#define        XISR_TXCHARNORMAL       0x00
-#define        XISR_TXWAIT             0x01
-#define        XISR_TXXOFFPEND         0x02
-#define        XISR_TXXONPEND          0x03
-
-#define        XISR_TXFLOWMASK         0x0c
-#define        XISR_TXNORMAL           0x00
-#define        XISR_TXSTOPPEND         0x04
-#define        XISR_TXSTARTED          0x08
-#define        XISR_TXSTOPPED          0x0c
-
-#define        XISR_RXFLOWMASK         0x30
-#define        XISR_RXFLOWNONE         0x00
-#define        XISR_RXXONSENT          0x10
-#define        XISR_RXXOFFSENT         0x20
-
-#define        XISR_RXXONGOT           0x40
-#define        XISR_RXXOFFGOT          0x80
-
-/*****************************************************************************/
-
-/*
- *     Current interrupt register.
- */
-#define        CIR_TYPEMASK            0xc0
-#define        CIR_TYPEOTHER           0x00
-#define        CIR_TYPETX              0x40
-#define        CIR_TYPERXGOOD          0x80
-#define        CIR_TYPERXBAD           0xc0
-
-#define        CIR_RXDATA              0x80
-#define        CIR_RXBADDATA           0x40
-#define        CIR_TXDATA              0x40
-
-#define        CIR_CHANMASK            0x07
-#define        CIR_CNTMASK             0x38
-
-#define        CIR_SUBTYPEMASK         0x38
-#define        CIR_SUBNONE             0x00
-#define        CIR_SUBCOS              0x08
-#define        CIR_SUBADDR             0x10
-#define        CIR_SUBXONXOFF          0x18
-#define        CIR_SUBBREAK            0x28
-
-/*****************************************************************************/
-
-/*
- *     Global interrupting channel register.
- */
-#define        GICR_CHANMASK           0x07
-
-/*****************************************************************************/
-
-/*
- *     Global interrupting byte count register.
- */
-#define        GICR_COUNTMASK          0x0f
-
-/*****************************************************************************/
-
-/*
- *     Global interrupting type register.
- */
-#define        GITR_RXMASK             0xc0
-#define        GITR_RXNONE             0x00
-#define        GITR_RXBADDATA          0x80
-#define        GITR_RXGOODDATA         0xc0
-#define        GITR_TXDATA             0x20
-
-#define        GITR_SUBTYPEMASK        0x07
-#define        GITR_SUBNONE            0x00
-#define        GITR_SUBCOS             0x01
-#define        GITR_SUBADDR            0x02
-#define        GITR_SUBXONXOFF         0x03
-#define        GITR_SUBBREAK           0x05
-
-/*****************************************************************************/
-
-/*
- *     Input port change register.
- */
-#define        IPR_CTS                 0x01
-#define        IPR_DTR                 0x02
-#define        IPR_RTS                 0x04
-#define        IPR_DCD                 0x08
-#define        IPR_CTSCHANGE           0x10
-#define        IPR_DTRCHANGE           0x20
-#define        IPR_RTSCHANGE           0x40
-#define        IPR_DCDCHANGE           0x80
-
-#define        IPR_CHANGEMASK          0xf0
-
-/*****************************************************************************/
-
-/*
- *     IO port interrupt and output register.
- */
-#define        IOPR_CTS                0x01
-#define        IOPR_DTR                0x02
-#define        IOPR_RTS                0x04
-#define        IOPR_DCD                0x08
-#define        IOPR_CTSCOS             0x10
-#define        IOPR_DTRCOS             0x20
-#define        IOPR_RTSCOS             0x40
-#define        IOPR_DCDCOS             0x80
-
-/*****************************************************************************/
-
-/*
- *     IO port configuration register.
- */
-#define        IOPCR_SETCTS            0x00
-#define        IOPCR_SETDTR            0x04
-#define        IOPCR_SETRTS            0x10
-#define        IOPCR_SETDCD            0x00
-
-#define        IOPCR_SETSIGS           (IOPCR_SETRTS | IOPCR_SETRTS | IOPCR_SETDTR | IOPCR_SETDCD)
-
-/*****************************************************************************/
-
-/*
- *     General purpose output select register.
- */
-#define        GPORS_TXC1XA            0x08
-#define        GPORS_TXC16XA           0x09
-#define        GPORS_RXC16XA           0x0a
-#define        GPORS_TXC16XB           0x0b
-#define        GPORS_GPOR3             0x0c
-#define        GPORS_GPOR2             0x0d
-#define        GPORS_GPOR1             0x0e
-#define        GPORS_GPOR0             0x0f
-
-/*****************************************************************************/
-
-/*
- *     General purpose output register.
- */
-#define        GPOR_0                  0x01
-#define        GPOR_1                  0x02
-#define        GPOR_2                  0x04
-#define        GPOR_3                  0x08
-
-/*****************************************************************************/
-
-/*
- *     General purpose output clock register.
- */
-#define        GPORC_0NONE             0x00
-#define        GPORC_0GIN0             0x01
-#define        GPORC_0GIN1             0x02
-#define        GPORC_0IO3A             0x02
-
-#define        GPORC_1NONE             0x00
-#define        GPORC_1GIN0             0x04
-#define        GPORC_1GIN1             0x08
-#define        GPORC_1IO3C             0x0c
-
-#define        GPORC_2NONE             0x00
-#define        GPORC_2GIN0             0x10
-#define        GPORC_2GIN1             0x20
-#define        GPORC_2IO3E             0x20
-
-#define        GPORC_3NONE             0x00
-#define        GPORC_3GIN0             0x40
-#define        GPORC_3GIN1             0x80
-#define        GPORC_3IO3G             0xc0
-
-/*****************************************************************************/
-
-/*
- *     General purpose output data register.
- */
-#define        GPOD_0MASK              0x03
-#define        GPOD_0SET1              0x00
-#define        GPOD_0SET0              0x01
-#define        GPOD_0SETR0             0x02
-#define        GPOD_0SETIO3B           0x03
-
-#define        GPOD_1MASK              0x0c
-#define        GPOD_1SET1              0x00
-#define        GPOD_1SET0              0x04
-#define        GPOD_1SETR0             0x08
-#define        GPOD_1SETIO3D           0x0c
-
-#define        GPOD_2MASK              0x30
-#define        GPOD_2SET1              0x00
-#define        GPOD_2SET0              0x10
-#define        GPOD_2SETR0             0x20
-#define        GPOD_2SETIO3F           0x30
-
-#define        GPOD_3MASK              0xc0
-#define        GPOD_3SET1              0x00
-#define        GPOD_3SET0              0x40
-#define        GPOD_3SETR0             0x80
-#define        GPOD_3SETIO3H           0xc0
-
-/*****************************************************************************/
-#endif
index c147e7024f11f2859d8f648b1abac437bac941f1..dce80e7d594589cd8f5c6f6c0af13f5f030e4377 100644 (file)
@@ -334,14 +334,6 @@ static inline void lockup_detector_init(void)
 }
 #endif
 
-#if defined(CONFIG_LOCKUP_DETECTOR) && defined(CONFIG_SUSPEND)
-void lockup_detector_bootcpu_resume(void);
-#else
-static inline void lockup_detector_bootcpu_resume(void)
-{
-}
-#endif
-
 #ifdef CONFIG_DETECT_HUNG_TASK
 extern unsigned int  sysctl_hung_task_panic;
 extern unsigned long sysctl_hung_task_check_count;
@@ -1901,6 +1893,14 @@ static inline void tsk_restore_flags(struct task_struct *task,
        task->flags |= orig_flags & flags;
 }
 
+static inline void rcu_switch(struct task_struct *prev,
+                             struct task_struct *next)
+{
+#ifdef CONFIG_RCU_USER_QS
+       rcu_user_hooks_switch(prev, next);
+#endif
+}
+
 #ifdef CONFIG_SMP
 extern void do_set_cpus_allowed(struct task_struct *p,
                               const struct cpumask *new_mask);
index 4e5a73cdbbef18463920022626931d02c0540eb9..3dea6a9d568f416ccd1b704eec1d4bff9dea6d90 100644 (file)
@@ -1242,8 +1242,6 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *     Check that the @parent process has sufficient permission to trace the
  *     current process before allowing the current process to present itself
  *     to the @parent process for tracing.
- *     The parent process will still have to undergo the ptrace_access_check
- *     checks before it is allowed to trace this one.
  *     @parent contains the task_struct structure for debugger process.
  *     Return 0 if permission is granted.
  * @capget:
diff --git a/include/linux/serial167.h b/include/linux/serial167.h
deleted file mode 100644 (file)
index 59c81b7..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * serial167.h
- *
- * Richard Hirst [richard@sleepie.demon.co.uk]
- *
- * Based on cyclades.h
- */
-
-struct cyclades_monitor {
-        unsigned long           int_count;
-        unsigned long           char_count;
-        unsigned long           char_max;
-        unsigned long           char_last;
-};
-
-/*
- * This is our internal structure for each serial port's state.
- * 
- * Many fields are paralleled by the structure used by the serial_struct
- * structure.
- *
- * For definitions of the flags field, see tty.h
- */
-
-struct cyclades_port {
-       int                     magic;
-       int                     type;
-       int                     card;
-       int                     line;
-       int                     flags;          /* defined in tty.h */
-       struct tty_struct       *tty;
-       int                     read_status_mask;
-       int                     timeout;
-       int                     xmit_fifo_size;
-       int                     cor1,cor2,cor3,cor4,cor5,cor6,cor7;
-       int                     tbpr,tco,rbpr,rco;
-       int                     ignore_status_mask;
-       int                     close_delay;
-       int                     IER;    /* Interrupt Enable Register */
-       unsigned long           last_active;
-       int                     count;  /* # of fd on device */
-       int                     x_char; /* to be pushed out ASAP */
-       int                     x_break;
-       int                     blocked_open; /* # of blocked opens */
-       unsigned char           *xmit_buf;
-       int                     xmit_head;
-       int                     xmit_tail;
-       int                     xmit_cnt;
-        int                     default_threshold;
-        int                     default_timeout;
-       wait_queue_head_t       open_wait;
-       wait_queue_head_t       close_wait;
-        struct cyclades_monitor mon;
-};
-
-#define CYCLADES_MAGIC  0x4359
-
-#define CYGETMON                0x435901
-#define CYGETTHRESH             0x435902
-#define CYSETTHRESH             0x435903
-#define CYGETDEFTHRESH          0x435904
-#define CYSETDEFTHRESH          0x435905
-#define CYGETTIMEOUT            0x435906
-#define CYSETTIMEOUT            0x435907
-#define CYGETDEFTIMEOUT         0x435908
-#define CYSETDEFTIMEOUT         0x435909
-
-#define CyMaxChipsPerCard 1
-
-/**** cd2401 registers ****/
-
-#define CyGFRCR         (0x81)
-#define CyCCR          (0x13)
-#define      CyCLR_CHAN                (0x40)
-#define      CyINIT_CHAN       (0x20)
-#define      CyCHIP_RESET      (0x10)
-#define      CyENB_XMTR                (0x08)
-#define      CyDIS_XMTR                (0x04)
-#define      CyENB_RCVR                (0x02)
-#define      CyDIS_RCVR                (0x01)
-#define CyCAR          (0xee)
-#define CyIER          (0x11)
-#define      CyMdmCh           (0x80)
-#define      CyRxExc           (0x20)
-#define      CyRxData          (0x08)
-#define      CyTxMpty          (0x02)
-#define      CyTxRdy           (0x01)
-#define CyLICR         (0x26)
-#define CyRISR         (0x89)
-#define      CyTIMEOUT         (0x80)
-#define      CySPECHAR         (0x70)
-#define      CyOVERRUN         (0x08)
-#define      CyPARITY          (0x04)
-#define      CyFRAME           (0x02)
-#define      CyBREAK           (0x01)
-#define CyREOIR                (0x84)
-#define CyTEOIR                (0x85)
-#define CyMEOIR                (0x86)
-#define      CyNOTRANS         (0x08)
-#define CyRFOC         (0x30)
-#define CyRDR          (0xf8)
-#define CyTDR          (0xf8)
-#define CyMISR         (0x8b)
-#define CyRISR         (0x89)
-#define CyTISR         (0x8a)
-#define CyMSVR1                (0xde)
-#define CyMSVR2                (0xdf)
-#define      CyDSR             (0x80)
-#define      CyDCD             (0x40)
-#define      CyCTS             (0x20)
-#define      CyDTR             (0x02)
-#define      CyRTS             (0x01)
-#define CyRTPRL                (0x25)
-#define CyRTPRH                (0x24)
-#define CyCOR1         (0x10)
-#define      CyPARITY_NONE     (0x00)
-#define      CyPARITY_E                (0x40)
-#define      CyPARITY_O                (0xC0)
-#define      Cy_5_BITS         (0x04)
-#define      Cy_6_BITS         (0x05)
-#define      Cy_7_BITS         (0x06)
-#define      Cy_8_BITS         (0x07)
-#define CyCOR2         (0x17)
-#define      CyETC             (0x20)
-#define      CyCtsAE           (0x02)
-#define CyCOR3         (0x16)
-#define      Cy_1_STOP         (0x02)
-#define      Cy_2_STOP         (0x04)
-#define CyCOR4         (0x15)
-#define      CyREC_FIFO                (0x0F)  /* Receive FIFO threshold */
-#define CyCOR5         (0x14)
-#define CyCOR6         (0x18)
-#define CyCOR7         (0x07)
-#define CyRBPR         (0xcb)
-#define CyRCOR         (0xc8)
-#define CyTBPR         (0xc3)
-#define CyTCOR         (0xc0)
-#define CySCHR1                (0x1f)
-#define CySCHR2        (0x1e)
-#define CyTPR          (0xda)
-#define CyPILR1                (0xe3)
-#define CyPILR2                (0xe0)
-#define CyPILR3                (0xe1)
-#define CyCMR          (0x1b)
-#define      CyASYNC           (0x02)
-#define CyLICR          (0x26)
-#define CyLIVR          (0x09)
-#define CySCRL         (0x23)
-#define CySCRH         (0x22)
-#define CyTFTC         (0x80)
-
-
-/* max number of chars in the FIFO */
-
-#define CyMAX_CHAR_FIFO        12
-
-/***************************************************************************/
index a416e92012ef72db74f1d9ffe2c54bbe2c98b217..c174c90fb3fbcbb56abb5096f40ee559a75aeb94 100644 (file)
@@ -65,11 +65,38 @@ enum {
  * platform device.  Using these will make your driver
  * dependent on the 8250 driver.
  */
-struct uart_port;
-struct uart_8250_port;
+
+struct uart_8250_port {
+       struct uart_port        port;
+       struct timer_list       timer;          /* "no irq" timer */
+       struct list_head        list;           /* ports on this IRQ */
+       unsigned short          capabilities;   /* port capabilities */
+       unsigned short          bugs;           /* port bugs */
+       unsigned int            tx_loadsz;      /* transmit fifo load size */
+       unsigned char           acr;
+       unsigned char           ier;
+       unsigned char           lcr;
+       unsigned char           mcr;
+       unsigned char           mcr_mask;       /* mask of user bits */
+       unsigned char           mcr_force;      /* mask of forced bits */
+       unsigned char           cur_iotype;     /* Running I/O type */
+
+       /*
+        * Some bits in registers are cleared on a read, so they must
+        * be saved whenever the register is read but the bits will not
+        * be immediately processed.
+        */
+#define LSR_SAVE_FLAGS UART_LSR_BRK_ERROR_BITS
+       unsigned char           lsr_saved_flags;
+#define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
+       unsigned char           msr_saved_flags;
+
+       /* 8250 specific callbacks */
+       int                     (*dl_read)(struct uart_8250_port *);
+       void                    (*dl_write)(struct uart_8250_port *, int);
+};
 
 int serial8250_register_8250_port(struct uart_8250_port *);
-int serial8250_register_port(struct uart_port *);
 void serial8250_unregister_port(int line);
 void serial8250_suspend_port(int line);
 void serial8250_resume_port(int line);
index 0253c2022e53ebef9950a428b559f8a598167c7a..7cf0b68bbe9e2b531ef44760ea4fd94c2aac23ea 100644 (file)
 /* SH-SCI */
 #define PORT_SCIFB     93
 
-/* MAX3107 */
-#define PORT_MAX3107   94
+/* MAX310X */
+#define PORT_MAX310X   94
 
 /* High Speed UART for Medfield */
 #define PORT_MFD       95
index 7632c87da2c9fd66eab61b6c7415d5669b7aeefd..b33a3a1f205e45c747c9125a5b5920365ca2f8be 100644 (file)
@@ -846,13 +846,16 @@ static inline int skb_shared(const struct sk_buff *skb)
  *
  *     NULL is returned on a memory allocation failure.
  */
-static inline struct sk_buff *skb_share_check(struct sk_buff *skb,
-                                             gfp_t pri)
+static inline struct sk_buff *skb_share_check(struct sk_buff *skb, gfp_t pri)
 {
        might_sleep_if(pri & __GFP_WAIT);
        if (skb_shared(skb)) {
                struct sk_buff *nskb = skb_clone(skb, pri);
-               kfree_skb(skb);
+
+               if (likely(nskb))
+                       consume_skb(skb);
+               else
+                       kfree_skb(skb);
                skb = nskb;
        }
        return skb;
index 00bc189cb3955b57384bbcf3e458b3b593c94774..ad6e3a6bf9fbd7e17627e07527ef3e699f447678 100644 (file)
 enum
 {
        IPSTATS_MIB_NUM = 0,
+/* frequently written fields in fast path, kept in same cache line */
        IPSTATS_MIB_INPKTS,                     /* InReceives */
+       IPSTATS_MIB_INOCTETS,                   /* InOctets */
+       IPSTATS_MIB_INDELIVERS,                 /* InDelivers */
+       IPSTATS_MIB_OUTFORWDATAGRAMS,           /* OutForwDatagrams */
+       IPSTATS_MIB_OUTPKTS,                    /* OutRequests */
+       IPSTATS_MIB_OUTOCTETS,                  /* OutOctets */
+/* other fields */
        IPSTATS_MIB_INHDRERRORS,                /* InHdrErrors */
        IPSTATS_MIB_INTOOBIGERRORS,             /* InTooBigErrors */
        IPSTATS_MIB_INNOROUTES,                 /* InNoRoutes */
@@ -26,9 +33,6 @@ enum
        IPSTATS_MIB_INUNKNOWNPROTOS,            /* InUnknownProtos */
        IPSTATS_MIB_INTRUNCATEDPKTS,            /* InTruncatedPkts */
        IPSTATS_MIB_INDISCARDS,                 /* InDiscards */
-       IPSTATS_MIB_INDELIVERS,                 /* InDelivers */
-       IPSTATS_MIB_OUTFORWDATAGRAMS,           /* OutForwDatagrams */
-       IPSTATS_MIB_OUTPKTS,                    /* OutRequests */
        IPSTATS_MIB_OUTDISCARDS,                /* OutDiscards */
        IPSTATS_MIB_OUTNOROUTES,                /* OutNoRoutes */
        IPSTATS_MIB_REASMTIMEOUT,               /* ReasmTimeout */
@@ -42,8 +46,6 @@ enum
        IPSTATS_MIB_OUTMCASTPKTS,               /* OutMcastPkts */
        IPSTATS_MIB_INBCASTPKTS,                /* InBcastPkts */
        IPSTATS_MIB_OUTBCASTPKTS,               /* OutBcastPkts */
-       IPSTATS_MIB_INOCTETS,                   /* InOctets */
-       IPSTATS_MIB_OUTOCTETS,                  /* OutOctets */
        IPSTATS_MIB_INMCASTOCTETS,              /* InMcastOctets */
        IPSTATS_MIB_OUTMCASTOCTETS,             /* OutMcastOctets */
        IPSTATS_MIB_INBCASTOCTETS,              /* InBcastOctets */
index 1a6b0045b06b63a616946bd421ce3f7f8e530160..c2b02a5c86ae0bb03798d9221c6199dc8be63d4b 100644 (file)
 #define SSB_CHIPCO_FLASHCTL_ST_SE      0x02D8          /* Sector Erase */
 #define SSB_CHIPCO_FLASHCTL_ST_BE      0x00C7          /* Bulk Erase */
 #define SSB_CHIPCO_FLASHCTL_ST_DP      0x00B9          /* Deep Power-down */
-#define SSB_CHIPCO_FLASHCTL_ST_RSIG    0x03AB          /* Read Electronic Signature */
+#define SSB_CHIPCO_FLASHCTL_ST_RES     0x03AB          /* Read Electronic Signature */
+#define SSB_CHIPCO_FLASHCTL_ST_CSA     0x1000          /* Keep chip select asserted */
+#define SSB_CHIPCO_FLASHCTL_ST_SSE     0x0220          /* Sub-sector Erase */
 
 /* Status register bits for ST flashes */
 #define SSB_CHIPCO_FLASHSTA_ST_WIP     0x01            /* Write In Progress */
diff --git a/include/linux/stallion.h b/include/linux/stallion.h
deleted file mode 100644 (file)
index 336af33..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-/*****************************************************************************/
-
-/*
- *     stallion.h  -- stallion multiport serial driver.
- *
- *     Copyright (C) 1996-1998  Stallion Technologies
- *     Copyright (C) 1994-1996  Greg Ungerer.
- *
- *     This program is free software; you can redistribute it and/or modify
- *     it under the terms of the GNU General Public License as published by
- *     the Free Software Foundation; either version 2 of the License, or
- *     (at your option) any later version.
- *
- *     This program is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public License
- *     along with this program; if not, write to the Free Software
- *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/*****************************************************************************/
-#ifndef        _STALLION_H
-#define        _STALLION_H
-/*****************************************************************************/
-
-/*
- *     Define important driver constants here.
- */
-#define        STL_MAXBRDS             4
-#define        STL_MAXPANELS           4
-#define        STL_MAXBANKS            8
-#define        STL_PORTSPERPANEL       16
-#define        STL_MAXPORTS            64
-#define        STL_MAXDEVS             (STL_MAXBRDS * STL_MAXPORTS)
-
-
-/*
- *     Define a set of structures to hold all the board/panel/port info
- *     for our ports. These will be dynamically allocated as required.
- */
-
-/*
- *     Define a ring queue structure for each port. This will hold the
- *     TX data waiting to be output. Characters are fed into this buffer
- *     from the line discipline (or even direct from user space!) and
- *     then fed into the UARTs during interrupts. Will use a classic ring
- *     queue here for this. The good thing about this type of ring queue
- *     is that the head and tail pointers can be updated without interrupt
- *     protection - since "write" code only needs to change the head, and
- *     interrupt code only needs to change the tail.
- */
-struct stlrq {
-       char    *buf;
-       char    *head;
-       char    *tail;
-};
-
-/*
- *     Port, panel and board structures to hold status info about each.
- *     The board structure contains pointers to structures for each panel
- *     connected to it, and in turn each panel structure contains pointers
- *     for each port structure for each port on that panel. Note that
- *     the port structure also contains the board and panel number that it
- *     is associated with, this makes it (fairly) easy to get back to the
- *     board/panel info for a port.
- */
-struct stlport {
-       unsigned long           magic;
-       struct tty_port         port;
-       unsigned int            portnr;
-       unsigned int            panelnr;
-       unsigned int            brdnr;
-       int                     ioaddr;
-       int                     uartaddr;
-       unsigned int            pagenr;
-       unsigned long           istate;
-       int                     baud_base;
-       int                     custom_divisor;
-       int                     close_delay;
-       int                     closing_wait;
-       int                     openwaitcnt;
-       int                     brklen;
-       unsigned int            sigs;
-       unsigned int            rxignoremsk;
-       unsigned int            rxmarkmsk;
-       unsigned int            imr;
-       unsigned int            crenable;
-       unsigned long           clk;
-       unsigned long           hwid;
-       void                    *uartp;
-       comstats_t              stats;
-       struct stlrq            tx;
-};
-
-struct stlpanel {
-       unsigned long   magic;
-       unsigned int    panelnr;
-       unsigned int    brdnr;
-       unsigned int    pagenr;
-       unsigned int    nrports;
-       int             iobase;
-       void            *uartp;
-       void            (*isr)(struct stlpanel *panelp, unsigned int iobase);
-       unsigned int    hwid;
-       unsigned int    ackmask;
-       struct stlport  *ports[STL_PORTSPERPANEL];
-};
-
-struct stlbrd {
-       unsigned long   magic;
-       unsigned int    brdnr;
-       unsigned int    brdtype;
-       unsigned int    state;
-       unsigned int    nrpanels;
-       unsigned int    nrports;
-       unsigned int    nrbnks;
-       int             irq;
-       int             irqtype;
-       int             (*isr)(struct stlbrd *brdp);
-       unsigned int    ioaddr1;
-       unsigned int    ioaddr2;
-       unsigned int    iosize1;
-       unsigned int    iosize2;
-       unsigned int    iostatus;
-       unsigned int    ioctrl;
-       unsigned int    ioctrlval;
-       unsigned int    hwid;
-       unsigned long   clk;
-       unsigned int    bnkpageaddr[STL_MAXBANKS];
-       unsigned int    bnkstataddr[STL_MAXBANKS];
-       struct stlpanel *bnk2panel[STL_MAXBANKS];
-       struct stlpanel *panels[STL_MAXPANELS];
-};
-
-
-/*
- *     Define MAGIC numbers used for above structures.
- */
-#define        STL_PORTMAGIC   0x5a7182c9
-#define        STL_PANELMAGIC  0x7ef621a1
-#define        STL_BOARDMAGIC  0xa2267f52
-
-/*****************************************************************************/
-#endif
index 4b94a61955df361934984992b37e185b8d933f87..91b34812cd8478a2aacfbdacc6818c75e4bfe587 100644 (file)
@@ -44,6 +44,12 @@ enum thermal_trip_type {
        THERMAL_TRIP_CRITICAL,
 };
 
+enum thermal_trend {
+       THERMAL_TREND_STABLE, /* temperature is stable */
+       THERMAL_TREND_RAISING, /* temperature is raising */
+       THERMAL_TREND_DROPPING, /* temperature is dropping */
+};
+
 struct thermal_zone_device_ops {
        int (*bind) (struct thermal_zone_device *,
                     struct thermal_cooling_device *);
@@ -65,6 +71,8 @@ struct thermal_zone_device_ops {
        int (*set_trip_hyst) (struct thermal_zone_device *, int,
                              unsigned long);
        int (*get_crit_temp) (struct thermal_zone_device *, unsigned long *);
+       int (*get_trend) (struct thermal_zone_device *, int,
+                         enum thermal_trend *);
        int (*notify) (struct thermal_zone_device *, int,
                       enum thermal_trip_type);
 };
@@ -75,6 +83,8 @@ struct thermal_cooling_device_ops {
        int (*set_cur_state) (struct thermal_cooling_device *, unsigned long);
 };
 
+#define THERMAL_NO_LIMIT -1UL /* no upper/lower limit requirement */
+
 #define THERMAL_TRIPS_NONE -1
 #define THERMAL_MAX_TRIPS 12
 #define THERMAL_NAME_LENGTH 20
@@ -84,6 +94,9 @@ struct thermal_cooling_device {
        struct device device;
        void *devdata;
        const struct thermal_cooling_device_ops *ops;
+       bool updated; /* true if the cooling device does not need update */
+       struct mutex lock; /* protect thermal_instances list */
+       struct list_head thermal_instances;
        struct list_head node;
 };
 
@@ -105,17 +118,16 @@ struct thermal_zone_device {
        struct thermal_attr *trip_hyst_attrs;
        void *devdata;
        int trips;
-       int tc1;
-       int tc2;
        int passive_delay;
        int polling_delay;
+       int temperature;
        int last_temperature;
-       bool passive;
+       int passive;
        unsigned int forced_passive;
        const struct thermal_zone_device_ops *ops;
-       struct list_head cooling_devices;
+       struct list_head thermal_instances;
        struct idr idr;
-       struct mutex lock;      /* protect cooling devices list */
+       struct mutex lock; /* protect thermal_instances list */
        struct list_head node;
        struct delayed_work poll_queue;
 };
@@ -152,12 +164,12 @@ enum {
 #define THERMAL_GENL_CMD_MAX (__THERMAL_GENL_CMD_MAX - 1)
 
 struct thermal_zone_device *thermal_zone_device_register(const char *, int, int,
-               void *, const struct thermal_zone_device_ops *, int tc1,
-               int tc2, int passive_freq, int polling_freq);
+               void *, const struct thermal_zone_device_ops *, int, int);
 void thermal_zone_device_unregister(struct thermal_zone_device *);
 
 int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int,
-                                    struct thermal_cooling_device *);
+                                    struct thermal_cooling_device *,
+                                    unsigned long, unsigned long);
 int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int,
                                       struct thermal_cooling_device *);
 void thermal_zone_device_update(struct thermal_zone_device *);
index 3ca0269dd0b587d4dfa4a157bcde969de57d6030..932b7639224883535456c37c1d30801ec6f7b305 100644 (file)
@@ -281,9 +281,10 @@ struct kim_data_s {
 long st_kim_start(void *);
 long st_kim_stop(void *);
 
-void st_kim_recv(void *, const unsigned char *, long count);
 void st_kim_complete(void *);
 void kim_st_list_protocols(struct st_data_s *, void *);
+void st_kim_recv(void *, const unsigned char *, long);
+
 
 /*
  * BTS headers
index 99bc88b1fc02734a30619038d2f9a7f430b4a951..7c5ceb20e03a8cf2195ae114e1f78905668158e5 100644 (file)
@@ -232,7 +232,7 @@ struct timex {
  * estimated error = NTP dispersion.
  */
 extern unsigned long tick_usec;                /* USER_HZ period (usec) */
-extern unsigned long tick_nsec;                /* ACTHZ          period (nsec) */
+extern unsigned long tick_nsec;                /* SHIFTED_HZ period (nsec) */
 
 extern void ntp_init(void);
 extern void ntp_clear(void);
index e91cd43394dfa82f3926c356abb4543b2e14bf36..fec12d667211dd398ba07ed5127b9e3485bcdd49 100644 (file)
@@ -164,6 +164,7 @@ int arch_update_cpu_topology(void);
                                | 0*SD_SHARE_CPUPOWER                   \
                                | 0*SD_SHARE_PKG_RESOURCES              \
                                | 0*SD_SERIALIZE                        \
+                               | 1*SD_PREFER_SIBLING                   \
                                ,                                       \
        .last_balance           = jiffies,                              \
        .balance_interval       = 1,                                    \
index 9f47ab540f65e997b79b0a16c52332c564354234..69a787fdfa9cfe66336163361915a6457140ed5c 100644 (file)
@@ -103,28 +103,28 @@ struct tty_bufhead {
 #define TTY_PARITY     3
 #define TTY_OVERRUN    4
 
-#define INTR_CHAR(tty) ((tty)->termios->c_cc[VINTR])
-#define QUIT_CHAR(tty) ((tty)->termios->c_cc[VQUIT])
-#define ERASE_CHAR(tty) ((tty)->termios->c_cc[VERASE])
-#define KILL_CHAR(tty) ((tty)->termios->c_cc[VKILL])
-#define EOF_CHAR(tty) ((tty)->termios->c_cc[VEOF])
-#define TIME_CHAR(tty) ((tty)->termios->c_cc[VTIME])
-#define MIN_CHAR(tty) ((tty)->termios->c_cc[VMIN])
-#define SWTC_CHAR(tty) ((tty)->termios->c_cc[VSWTC])
-#define START_CHAR(tty) ((tty)->termios->c_cc[VSTART])
-#define STOP_CHAR(tty) ((tty)->termios->c_cc[VSTOP])
-#define SUSP_CHAR(tty) ((tty)->termios->c_cc[VSUSP])
-#define EOL_CHAR(tty) ((tty)->termios->c_cc[VEOL])
-#define REPRINT_CHAR(tty) ((tty)->termios->c_cc[VREPRINT])
-#define DISCARD_CHAR(tty) ((tty)->termios->c_cc[VDISCARD])
-#define WERASE_CHAR(tty) ((tty)->termios->c_cc[VWERASE])
-#define LNEXT_CHAR(tty)        ((tty)->termios->c_cc[VLNEXT])
-#define EOL2_CHAR(tty) ((tty)->termios->c_cc[VEOL2])
-
-#define _I_FLAG(tty, f)        ((tty)->termios->c_iflag & (f))
-#define _O_FLAG(tty, f)        ((tty)->termios->c_oflag & (f))
-#define _C_FLAG(tty, f)        ((tty)->termios->c_cflag & (f))
-#define _L_FLAG(tty, f)        ((tty)->termios->c_lflag & (f))
+#define INTR_CHAR(tty) ((tty)->termios.c_cc[VINTR])
+#define QUIT_CHAR(tty) ((tty)->termios.c_cc[VQUIT])
+#define ERASE_CHAR(tty) ((tty)->termios.c_cc[VERASE])
+#define KILL_CHAR(tty) ((tty)->termios.c_cc[VKILL])
+#define EOF_CHAR(tty) ((tty)->termios.c_cc[VEOF])
+#define TIME_CHAR(tty) ((tty)->termios.c_cc[VTIME])
+#define MIN_CHAR(tty) ((tty)->termios.c_cc[VMIN])
+#define SWTC_CHAR(tty) ((tty)->termios.c_cc[VSWTC])
+#define START_CHAR(tty) ((tty)->termios.c_cc[VSTART])
+#define STOP_CHAR(tty) ((tty)->termios.c_cc[VSTOP])
+#define SUSP_CHAR(tty) ((tty)->termios.c_cc[VSUSP])
+#define EOL_CHAR(tty) ((tty)->termios.c_cc[VEOL])
+#define REPRINT_CHAR(tty) ((tty)->termios.c_cc[VREPRINT])
+#define DISCARD_CHAR(tty) ((tty)->termios.c_cc[VDISCARD])
+#define WERASE_CHAR(tty) ((tty)->termios.c_cc[VWERASE])
+#define LNEXT_CHAR(tty)        ((tty)->termios.c_cc[VLNEXT])
+#define EOL2_CHAR(tty) ((tty)->termios.c_cc[VEOL2])
+
+#define _I_FLAG(tty, f)        ((tty)->termios.c_iflag & (f))
+#define _O_FLAG(tty, f)        ((tty)->termios.c_oflag & (f))
+#define _C_FLAG(tty, f)        ((tty)->termios.c_cflag & (f))
+#define _L_FLAG(tty, f)        ((tty)->termios.c_lflag & (f))
 
 #define I_IGNBRK(tty)  _I_FLAG((tty), IGNBRK)
 #define I_BRKINT(tty)  _I_FLAG((tty), BRKINT)
@@ -268,10 +268,11 @@ struct tty_struct {
        struct mutex ldisc_mutex;
        struct tty_ldisc *ldisc;
 
+       struct mutex legacy_mutex;
        struct mutex termios_mutex;
        spinlock_t ctrl_lock;
        /* Termios values are protected by the termios mutex */
-       struct ktermios *termios, *termios_locked;
+       struct ktermios termios, termios_locked;
        struct termiox *termiox;        /* May be NULL for unsupported */
        char name[64];
        struct pid *pgrp;               /* Protected by ctrl lock */
@@ -423,7 +424,6 @@ extern void tty_unthrottle(struct tty_struct *tty);
 extern int tty_do_resize(struct tty_struct *tty, struct winsize *ws);
 extern void tty_driver_remove_tty(struct tty_driver *driver,
                                  struct tty_struct *tty);
-extern void tty_shutdown(struct tty_struct *tty);
 extern void tty_free_termios(struct tty_struct *tty);
 extern int is_current_pgrp_orphaned(void);
 extern struct pid *tty_get_pgrp(struct tty_struct *tty);
@@ -497,6 +497,11 @@ extern int tty_write_lock(struct tty_struct *tty, int ndelay);
 #define tty_is_writelocked(tty)  (mutex_is_locked(&tty->atomic_write_lock))
 
 extern void tty_port_init(struct tty_port *port);
+extern void tty_port_link_device(struct tty_port *port,
+               struct tty_driver *driver, unsigned index);
+extern struct device *tty_port_register_device(struct tty_port *port,
+               struct tty_driver *driver, unsigned index,
+               struct device *device);
 extern int tty_port_alloc_xmit_buf(struct tty_port *port);
 extern void tty_port_free_xmit_buf(struct tty_port *port);
 extern void tty_port_put(struct tty_port *port);
@@ -521,6 +526,8 @@ extern int tty_port_close_start(struct tty_port *port,
 extern void tty_port_close_end(struct tty_port *port, struct tty_struct *tty);
 extern void tty_port_close(struct tty_port *port,
                                struct tty_struct *tty, struct file *filp);
+extern int tty_port_install(struct tty_port *port, struct tty_driver *driver,
+                               struct tty_struct *tty);
 extern int tty_port_open(struct tty_port *port,
                                struct tty_struct *tty, struct file *filp);
 static inline int tty_port_users(struct tty_port *port)
@@ -605,8 +612,12 @@ extern long vt_compat_ioctl(struct tty_struct *tty,
 
 /* tty_mutex.c */
 /* functions for preparation of BKL removal */
-extern void __lockfunc tty_lock(void) __acquires(tty_lock);
-extern void __lockfunc tty_unlock(void) __releases(tty_lock);
+extern void __lockfunc tty_lock(struct tty_struct *tty);
+extern void __lockfunc tty_unlock(struct tty_struct *tty);
+extern void __lockfunc tty_lock_pair(struct tty_struct *tty,
+                               struct tty_struct *tty2);
+extern void __lockfunc tty_unlock_pair(struct tty_struct *tty,
+                               struct tty_struct *tty2);
 
 /*
  * this shall be called only from where BTM is held (like close)
@@ -621,9 +632,9 @@ extern void __lockfunc tty_unlock(void) __releases(tty_lock);
 static inline void tty_wait_until_sent_from_close(struct tty_struct *tty,
                long timeout)
 {
-       tty_unlock(); /* tty->ops->close holds the BTM, drop it while waiting */
+       tty_unlock(tty); /* tty->ops->close holds the BTM, drop it while waiting */
        tty_wait_until_sent(tty, timeout);
-       tty_lock();
+       tty_lock(tty);
 }
 
 /*
@@ -638,16 +649,16 @@ static inline void tty_wait_until_sent_from_close(struct tty_struct *tty,
  *
  * Do not use in new code.
  */
-#define wait_event_interruptible_tty(wq, condition)                    \
+#define wait_event_interruptible_tty(tty, wq, condition)               \
 ({                                                                     \
        int __ret = 0;                                                  \
        if (!(condition)) {                                             \
-               __wait_event_interruptible_tty(wq, condition, __ret);   \
+               __wait_event_interruptible_tty(tty, wq, condition, __ret);      \
        }                                                               \
        __ret;                                                          \
 })
 
-#define __wait_event_interruptible_tty(wq, condition, ret)             \
+#define __wait_event_interruptible_tty(tty, wq, condition, ret)                \
 do {                                                                   \
        DEFINE_WAIT(__wait);                                            \
                                                                        \
@@ -656,9 +667,9 @@ do {                                                                        \
                if (condition)                                          \
                        break;                                          \
                if (!signal_pending(current)) {                         \
-                       tty_unlock();                                   \
+                       tty_unlock(tty);                                        \
                        schedule();                                     \
-                       tty_lock();                                     \
+                       tty_lock(tty);                                  \
                        continue;                                       \
                }                                                       \
                ret = -ERESTARTSYS;                                     \
index 6e6dbb7447b6e76beec4a4115d049e6dd00c4735..dd976cfb61312d66d53d6a9e009e70d3eb4d347d 100644 (file)
  *
  * void (*shutdown)(struct tty_struct * tty);
  *
- *     This routine is called synchronously when a particular tty device
- *     is closed for the last time freeing up the resources.
- *     Note that tty_shutdown() is not called if ops->shutdown is defined.
- *     This means one is responsible to take care of calling ops->remove (e.g.
- *     via tty_driver_remove_tty) and releasing tty->termios.
- *     Note that this hook may be called from *all* the contexts where one
- *     uses tty refcounting (e.g. tty_port_tty_get).
- *
+ *     This routine is called under the tty lock when a particular tty device
+ *     is closed for the last time. It executes before the tty resources
+ *     are freed so may execute while another function holds a tty kref.
  *
  * void (*cleanup)(struct tty_struct * tty);
  *
@@ -294,18 +289,18 @@ struct tty_operations {
 struct tty_driver {
        int     magic;          /* magic number for this structure */
        struct kref kref;       /* Reference management */
-       struct cdev cdev;
+       struct cdev *cdevs;
        struct module   *owner;
        const char      *driver_name;
        const char      *name;
        int     name_base;      /* offset of printed name */
        int     major;          /* major device number */
        int     minor_start;    /* start of minor device number */
-       int     num;            /* number of devices allocated */
+       unsigned int    num;    /* number of devices allocated */
        short   type;           /* type of tty driver */
        short   subtype;        /* subtype of tty driver */
        struct ktermios init_termios; /* Initial termios */
-       int     flags;          /* tty driver flags */
+       unsigned long   flags;          /* tty driver flags */
        struct proc_dir_entry *proc_entry; /* /proc fs entry */
        struct tty_driver *other; /* only used for the PTY driver */
 
@@ -313,6 +308,7 @@ struct tty_driver {
         * Pointer to the tty data structures
         */
        struct tty_struct **ttys;
+       struct tty_port **ports;
        struct ktermios **termios;
        void *driver_state;
 
@@ -326,7 +322,8 @@ struct tty_driver {
 
 extern struct list_head tty_drivers;
 
-extern struct tty_driver *__alloc_tty_driver(int lines, struct module *owner);
+extern struct tty_driver *__tty_alloc_driver(unsigned int lines,
+               struct module *owner, unsigned long flags);
 extern void put_tty_driver(struct tty_driver *driver);
 extern void tty_set_operations(struct tty_driver *driver,
                        const struct tty_operations *op);
@@ -334,7 +331,21 @@ extern struct tty_driver *tty_find_polling_driver(char *name, int *line);
 
 extern void tty_driver_kref_put(struct tty_driver *driver);
 
-#define alloc_tty_driver(lines) __alloc_tty_driver(lines, THIS_MODULE)
+/* Use TTY_DRIVER_* flags below */
+#define tty_alloc_driver(lines, flags) \
+               __tty_alloc_driver(lines, THIS_MODULE, flags)
+
+/*
+ * DEPRECATED Do not use this in new code, use tty_alloc_driver instead.
+ * (And change the return value checks.)
+ */
+static inline struct tty_driver *alloc_tty_driver(unsigned int lines)
+{
+       struct tty_driver *ret = tty_alloc_driver(lines, 0);
+       if (IS_ERR(ret))
+               return NULL;
+       return ret;
+}
 
 static inline struct tty_driver *tty_driver_kref_get(struct tty_driver *d)
 {
@@ -380,6 +391,14 @@ static inline struct tty_driver *tty_driver_kref_get(struct tty_driver *d)
  *     the requested timeout to the caller instead of using a simple
  *     on/off interface.
  *
+ * TTY_DRIVER_DYNAMIC_ALLOC -- do not allocate structures which are
+ *     needed per line for this driver as it would waste memory.
+ *     The driver will take care.
+ *
+ * TTY_DRIVER_UNNUMBERED_NODE -- do not create numbered /dev nodes. In
+ *     other words create /dev/ttyprintk and not /dev/ttyprintk0.
+ *     Applicable only when a driver for a single tty device is
+ *     being allocated.
  */
 #define TTY_DRIVER_INSTALLED           0x0001
 #define TTY_DRIVER_RESET_TERMIOS       0x0002
@@ -387,6 +406,8 @@ static inline struct tty_driver *tty_driver_kref_get(struct tty_driver *d)
 #define TTY_DRIVER_DYNAMIC_DEV         0x0008
 #define TTY_DRIVER_DEVPTS_MEM          0x0010
 #define TTY_DRIVER_HARDWARE_BREAK      0x0020
+#define TTY_DRIVER_DYNAMIC_ALLOC       0x0040
+#define TTY_DRIVER_UNNUMBERED_NODE     0x0080
 
 /* tty driver types */
 #define TTY_DRIVER_TYPE_SYSTEM         0x0001
index 1894f42fe3f7bd1df44a0f46bc1eb456421f5d31..c9d09f8b7ff2d66579ee58700658667347ef8094 100644 (file)
@@ -41,6 +41,14 @@ struct usb_ehci_pdata {
        unsigned        big_endian_mmio:1;
        unsigned        port_power_on:1;
        unsigned        port_power_off:1;
+
+       /* Turn on all power and clocks */
+       int (*power_on)(struct platform_device *pdev);
+       /* Turn off all power and clocks */
+       void (*power_off)(struct platform_device *pdev);
+       /* Turn on only VBUS suspend power and hotplug detection,
+        * turn off everything else */
+       void (*power_suspend)(struct platform_device *pdev);
 };
 
 #endif /* __USB_CORE_EHCI_PDRIVER_H */
index c5fdb148fc02ccea72ca2b911caa0ab0f7f4be88..608050b2545f917f790fca91bc9f89042626752c 100644 (file)
@@ -135,8 +135,8 @@ struct usb_hcd {
 
        unsigned int            irq;            /* irq allocated */
        void __iomem            *regs;          /* device memory/io */
-       u64                     rsrc_start;     /* memory/io resource start */
-       u64                     rsrc_len;       /* memory/io resource length */
+       resource_size_t         rsrc_start;     /* memory/io resource start */
+       resource_size_t         rsrc_len;       /* memory/io resource length */
        unsigned                power_budget;   /* in mA, 0 = no limit */
 
        /* bandwidth_mutex should be taken before adding or removing
index 2808f2a9cce806f461f1379239c3f0edf9b2dafd..74e7755168b72c3efed2c39e46a39d7eefc5f858 100644 (file)
@@ -33,6 +33,14 @@ struct usb_ohci_pdata {
        unsigned        big_endian_desc:1;
        unsigned        big_endian_mmio:1;
        unsigned        no_big_frame_no:1;
+
+       /* Turn on all power and clocks */
+       int (*power_on)(struct platform_device *pdev);
+       /* Turn off all power and clocks */
+       void (*power_off)(struct platform_device *pdev);
+       /* Turn on only VBUS suspend power and hotplug detection,
+        * turn off everything else */
+       void (*power_suspend)(struct platform_device *pdev);
 };
 
 #endif /* __USB_CORE_OHCI_PDRIVER_H */
index 0fa8b64c3cdbd1614dfe6e4ea12c2bdb6ceabd04..4f0667e010dd39333ef672af24969c5c6683819a 100644 (file)
 /* Backward compatibility target definitions --- to be removed. */
 #define V4L2_SEL_TGT_CROP_ACTIVE       V4L2_SEL_TGT_CROP
 #define V4L2_SEL_TGT_COMPOSE_ACTIVE    V4L2_SEL_TGT_COMPOSE
-#define V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL \
-       V4L2_SEL_TGT_CROP
-#define V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL \
-       V4L2_SEL_TGT_COMPOSE
+#define V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL        V4L2_SEL_TGT_CROP
+#define V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL V4L2_SEL_TGT_COMPOSE
+#define V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS        V4L2_SEL_TGT_CROP_BOUNDS
+#define V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS V4L2_SEL_TGT_COMPOSE_BOUNDS
 
 /* Selection flags */
 #define V4L2_SEL_FLAG_GE               (1 << 0)
index 3adeff82212f80aa95bca4456c56355706a18bfa..065e3ae79ab0e7f09138cceb19d8f35ce6d72d67 100644 (file)
@@ -19,6 +19,7 @@ struct w1_gpio_platform_data {
        unsigned int pin;
        unsigned int is_open_drain:1;
        void (*enable_external_pullup)(int enable);
+       unsigned int ext_pullup_enable_pin;
 };
 
 #endif /* _LINUX_W1_GPIO_H */
index af155450cabb8a91ec33d2991a011d43437e23f6..b14d5d59af7cadeb5fb8f255544346b004b44c48 100644 (file)
@@ -16,6 +16,7 @@ struct workqueue_struct;
 
 struct work_struct;
 typedef void (*work_func_t)(struct work_struct *work);
+void delayed_work_timer_fn(unsigned long __data);
 
 /*
  * The first word is the work queue pointer and the flags rolled into
@@ -67,9 +68,18 @@ enum {
        WORK_STRUCT_FLAG_BITS   = WORK_STRUCT_COLOR_SHIFT +
                                  WORK_STRUCT_COLOR_BITS,
 
+       /* data contains off-queue information when !WORK_STRUCT_CWQ */
+       WORK_OFFQ_FLAG_BASE     = WORK_STRUCT_FLAG_BITS,
+
+       WORK_OFFQ_CANCELING     = (1 << WORK_OFFQ_FLAG_BASE),
+
+       WORK_OFFQ_FLAG_BITS     = 1,
+       WORK_OFFQ_CPU_SHIFT     = WORK_OFFQ_FLAG_BASE + WORK_OFFQ_FLAG_BITS,
+
+       /* convenience constants */
        WORK_STRUCT_FLAG_MASK   = (1UL << WORK_STRUCT_FLAG_BITS) - 1,
        WORK_STRUCT_WQ_DATA_MASK = ~WORK_STRUCT_FLAG_MASK,
-       WORK_STRUCT_NO_CPU      = WORK_CPU_NONE << WORK_STRUCT_FLAG_BITS,
+       WORK_STRUCT_NO_CPU      = (unsigned long)WORK_CPU_NONE << WORK_OFFQ_CPU_SHIFT,
 
        /* bit mask for work_busy() return values */
        WORK_BUSY_PENDING       = 1 << 0,
@@ -92,6 +102,7 @@ struct work_struct {
 struct delayed_work {
        struct work_struct work;
        struct timer_list timer;
+       int cpu;
 };
 
 static inline struct delayed_work *to_delayed_work(struct work_struct *work)
@@ -124,12 +135,14 @@ struct execute_work {
 
 #define __DELAYED_WORK_INITIALIZER(n, f) {                     \
        .work = __WORK_INITIALIZER((n).work, (f)),              \
-       .timer = TIMER_INITIALIZER(NULL, 0, 0),                 \
+       .timer = TIMER_INITIALIZER(delayed_work_timer_fn,       \
+                               0, (unsigned long)&(n)),        \
        }
 
 #define __DEFERRED_WORK_INITIALIZER(n, f) {                    \
        .work = __WORK_INITIALIZER((n).work, (f)),              \
-       .timer = TIMER_DEFERRED_INITIALIZER(NULL, 0, 0),        \
+       .timer = TIMER_DEFERRED_INITIALIZER(delayed_work_timer_fn, \
+                               0, (unsigned long)&(n)),        \
        }
 
 #define DECLARE_WORK(n, f)                                     \
@@ -207,18 +220,24 @@ static inline unsigned int work_static(struct work_struct *work) { return 0; }
        do {                                                    \
                INIT_WORK(&(_work)->work, (_func));             \
                init_timer(&(_work)->timer);                    \
+               (_work)->timer.function = delayed_work_timer_fn;\
+               (_work)->timer.data = (unsigned long)(_work);   \
        } while (0)
 
 #define INIT_DELAYED_WORK_ONSTACK(_work, _func)                        \
        do {                                                    \
                INIT_WORK_ONSTACK(&(_work)->work, (_func));     \
                init_timer_on_stack(&(_work)->timer);           \
+               (_work)->timer.function = delayed_work_timer_fn;\
+               (_work)->timer.data = (unsigned long)(_work);   \
        } while (0)
 
 #define INIT_DELAYED_WORK_DEFERRABLE(_work, _func)             \
        do {                                                    \
                INIT_WORK(&(_work)->work, (_func));             \
                init_timer_deferrable(&(_work)->timer);         \
+               (_work)->timer.function = delayed_work_timer_fn;\
+               (_work)->timer.data = (unsigned long)(_work);   \
        } while (0)
 
 /**
@@ -365,23 +384,28 @@ __alloc_workqueue_key(const char *fmt, unsigned int flags, int max_active,
 
 extern void destroy_workqueue(struct workqueue_struct *wq);
 
-extern int queue_work(struct workqueue_struct *wq, struct work_struct *work);
-extern int queue_work_on(int cpu, struct workqueue_struct *wq,
+extern bool queue_work_on(int cpu, struct workqueue_struct *wq,
                        struct work_struct *work);
-extern int queue_delayed_work(struct workqueue_struct *wq,
+extern bool queue_work(struct workqueue_struct *wq, struct work_struct *work);
+extern bool queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
                        struct delayed_work *work, unsigned long delay);
-extern int queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
+extern bool queue_delayed_work(struct workqueue_struct *wq,
                        struct delayed_work *work, unsigned long delay);
+extern bool mod_delayed_work_on(int cpu, struct workqueue_struct *wq,
+                       struct delayed_work *dwork, unsigned long delay);
+extern bool mod_delayed_work(struct workqueue_struct *wq,
+                       struct delayed_work *dwork, unsigned long delay);
 
 extern void flush_workqueue(struct workqueue_struct *wq);
 extern void drain_workqueue(struct workqueue_struct *wq);
 extern void flush_scheduled_work(void);
 
-extern int schedule_work(struct work_struct *work);
-extern int schedule_work_on(int cpu, struct work_struct *work);
-extern int schedule_delayed_work(struct delayed_work *work, unsigned long delay);
-extern int schedule_delayed_work_on(int cpu, struct delayed_work *work,
-                                       unsigned long delay);
+extern bool schedule_work_on(int cpu, struct work_struct *work);
+extern bool schedule_work(struct work_struct *work);
+extern bool schedule_delayed_work_on(int cpu, struct delayed_work *work,
+                                    unsigned long delay);
+extern bool schedule_delayed_work(struct delayed_work *work,
+                                 unsigned long delay);
 extern int schedule_on_each_cpu(work_func_t func);
 extern int keventd_up(void);
 
index c66fe3332d8376ab4fd226d60d7afd16e94b1a9f..50c3e8fa06a865b439047f80a0ac9be9a26cfeeb 100644 (file)
@@ -104,7 +104,6 @@ static inline void wait_on_inode(struct inode *inode)
        wait_on_bit(&inode->i_state, __I_NEW, inode_wait, TASK_UNINTERRUPTIBLE);
 }
 
-
 /*
  * mm/page-writeback.c
  */
index 4d94be5226af75ba9da2064311b80b7987e93764..95842696857f26122b9a3233b19c251ec6038eb2 100644 (file)
@@ -41,12 +41,6 @@ enum isp_interface_type {
        ISP_INTERFACE_CSI2C_PHY1,
 };
 
-enum {
-       ISP_BRIDGE_DISABLE = 0,
-       ISP_BRIDGE_LITTLE_ENDIAN = 2,
-       ISP_BRIDGE_BIG_ENDIAN = 3,
-};
-
 enum {
        ISP_LANE_SHIFT_0 = 0,
        ISP_LANE_SHIFT_2 = 1,
@@ -67,17 +61,15 @@ enum {
  *             0 - Active high, 1 - Active low
  * @vs_pol: Vertical synchronization polarity
  *             0 - Active high, 1 - Active low
- * @bridge: CCDC Bridge input control
- *             ISP_BRIDGE_DISABLE - Disable
- *             ISP_BRIDGE_LITTLE_ENDIAN - Little endian
- *             ISP_BRIDGE_BIG_ENDIAN - Big endian
+ * @data_pol: Data polarity
+ *             0 - Normal, 1 - One's complement
  */
 struct isp_parallel_platform_data {
        unsigned int data_lane_shift:2;
        unsigned int clk_pol:1;
        unsigned int hs_pol:1;
        unsigned int vs_pol:1;
-       unsigned int bridge:2;
+       unsigned int data_pol:1;
 };
 
 enum {
index 773e527deabe3cb04b8371df40648a8100464ce4..96058a5a4acc3870f63298469e5b22e30601bc25 100644 (file)
@@ -117,8 +117,6 @@ struct saa7146_dev
 {
        struct module                   *module;
 
-       struct list_head                item;
-
        struct v4l2_device              v4l2_dev;
        struct v4l2_ctrl_handler        ctrl_handler;
 
@@ -166,8 +164,6 @@ static inline struct saa7146_dev *to_saa7146_dev(struct v4l2_device *v4l2_dev)
 int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c_adapter, u32 bitrate);
 
 /* from saa7146_core.c */
-extern struct list_head saa7146_devices;
-extern struct mutex saa7146_devices_lock;
 int saa7146_register_extension(struct saa7146_extension*);
 int saa7146_unregister_extension(struct saa7146_extension*);
 struct saa7146_format* saa7146_format_by_fourcc(struct saa7146_dev *dev, int fourcc);
index a298ec49ddc489ba70d47003fba8a39f32335ff4..4404829d48e599055510c5de54ceb8f34edf1b5e 100644 (file)
@@ -133,7 +133,7 @@ struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
                struct i2c_adapter *adapter, struct i2c_board_info *info,
                const unsigned short *probe_addrs);
 
-/* Initialize an v4l2_subdev with data from an i2c_client struct */
+/* Initialize a v4l2_subdev with data from an i2c_client struct */
 void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,
                const struct v4l2_subdev_ops *ops);
 /* Return i2c client address of v4l2_subdev. */
@@ -166,7 +166,7 @@ struct spi_device;
 struct v4l2_subdev *v4l2_spi_new_subdev(struct v4l2_device *v4l2_dev,
                struct spi_master *master, struct spi_board_info *info);
 
-/* Initialize an v4l2_subdev with data from an spi_device struct */
+/* Initialize a v4l2_subdev with data from an spi_device struct */
 void v4l2_spi_subdev_init(struct v4l2_subdev *sd, struct spi_device *spi,
                const struct v4l2_subdev_ops *ops);
 #endif
index 5c416cdc88d5d44eae38ce5e8445d5c2de6d2c78..6ee8897c47e9035ab491541e972395d094c91916 100644 (file)
@@ -39,9 +39,6 @@ struct v4l2_ctrl_handler;
 #define V4L2_FL_USES_V4L2_FH   (1)
 /* Use the prio field of v4l2_fh for core priority checking */
 #define V4L2_FL_USE_FH_PRIO    (2)
-/* If ioctl core locking is in use, then apply that also to all
-   file operations. Don't use this flag in new drivers! */
-#define V4L2_FL_LOCK_ALL_FOPS  (3)
 
 /* Priority helper functions */
 
index c35a3545e273258bf9afcb7a04fa512f55ef9685..4cc1652284b6e985aec25534e8f5edaff468d8cc 100644 (file)
@@ -120,7 +120,7 @@ struct v4l2_subdev_io_pin_config {
        each pin being configured.  This function could be called at times
        other than just subdevice initialization.
 
-   init: initialize the sensor registors to some sort of reasonable default
+   init: initialize the sensor registers to some sort of reasonable default
        values. Do not use for new drivers and should be removed in existing
        drivers.
 
index 7f7df93f37cd0d3b3259775ebf6ab23743b3c564..b630dae03411ae69694e842d75108a254c0584aa 100644 (file)
@@ -3,6 +3,7 @@
 #define _ARP_H
 
 #include <linux/if_arp.h>
+#include <linux/hash.h>
 #include <net/neighbour.h>
 
 
@@ -10,7 +11,7 @@ extern struct neigh_table arp_tbl;
 
 static inline u32 arp_hashfn(u32 key, const struct net_device *dev, u32 hash_rnd)
 {
-       u32 val = key ^ dev->ifindex;
+       u32 val = key ^ hash32_ptr(dev);
 
        return val * hash_rnd;
 }
index 565d4bee1e493bbaa145f5e3621bc27e4295727f..ede036977ae8b6debe3ee4560f7e93905bd92f9a 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <linux/poll.h>
 #include <net/sock.h>
+#include <linux/seq_file.h>
 
 #ifndef AF_BLUETOOTH
 #define AF_BLUETOOTH   31
@@ -202,6 +203,10 @@ enum {
 struct bt_sock_list {
        struct hlist_head head;
        rwlock_t          lock;
+#ifdef CONFIG_PROC_FS
+        struct file_operations   fops;
+        int (* custom_seq_show)(struct seq_file *, void *);
+#endif
 };
 
 int  bt_sock_register(int proto, const struct net_proto_family *ops);
@@ -292,6 +297,11 @@ extern void hci_sock_cleanup(void);
 extern int bt_sysfs_init(void);
 extern void bt_sysfs_cleanup(void);
 
+extern int  bt_procfs_init(struct module* module, struct net *net, const char *name,
+                          struct bt_sock_list* sk_list,
+                          int (* seq_show)(struct seq_file *, void *));
+extern void bt_procfs_cleanup(struct net *net, const char *name);
+
 extern struct dentry *bt_debugfs;
 
 int l2cap_init(void);
index ccd723e0f783e34a14a382e116a72e2a0369becb..0f28f7052f828f263f66114a018f9d2677c7352d 100644 (file)
 /* First BR/EDR Controller shall have ID = 0 */
 #define HCI_BREDR_ID   0
 
+/* AMP controller status */
+#define AMP_CTRL_POWERED_DOWN                  0x00
+#define AMP_CTRL_BLUETOOTH_ONLY                        0x01
+#define AMP_CTRL_NO_CAPACITY                   0x02
+#define AMP_CTRL_LOW_CAPACITY                  0x03
+#define AMP_CTRL_MEDIUM_CAPACITY               0x04
+#define AMP_CTRL_HIGH_CAPACITY                 0x05
+#define AMP_CTRL_FULL_CAPACITY                 0x06
+
 /* HCI device quirks */
 enum {
        HCI_QUIRK_RESET_ON_CLOSE,
@@ -293,8 +302,11 @@ enum {
 
 /* ---- HCI Error Codes ---- */
 #define HCI_ERROR_AUTH_FAILURE         0x05
+#define HCI_ERROR_CONNECTION_TIMEOUT   0x08
 #define HCI_ERROR_REJ_BAD_ADDR         0x0f
 #define HCI_ERROR_REMOTE_USER_TERM     0x13
+#define HCI_ERROR_REMOTE_LOW_RESOURCES 0x14
+#define HCI_ERROR_REMOTE_POWER_OFF     0x15
 #define HCI_ERROR_LOCAL_HOST_TERM      0x16
 #define HCI_ERROR_PAIRING_NOT_ALLOWED  0x18
 
@@ -1295,6 +1307,8 @@ struct hci_ev_num_comp_blocks {
 } __packed;
 
 /* Low energy meta events */
+#define LE_CONN_ROLE_MASTER    0x00
+
 #define HCI_EV_LE_CONN_COMPLETE                0x01
 struct hci_ev_le_conn_complete {
        __u8     status;
index 475b8c04ba52c01530f9a17a50f2f895211c7e2b..1bbc1091748ce3c6cfb6c0944551a8935bd53ae5 100644 (file)
@@ -115,12 +115,6 @@ struct oob_data {
        u8 randomizer[16];
 };
 
-struct adv_entry {
-       struct list_head list;
-       bdaddr_t bdaddr;
-       u8 bdaddr_type;
-};
-
 struct le_scan_params {
        u8 type;
        u16 interval;
@@ -356,16 +350,16 @@ extern rwlock_t hci_cb_list_lock;
 
 /* ----- HCI interface to upper protocols ----- */
 extern int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr);
-extern int l2cap_connect_cfm(struct hci_conn *hcon, u8 status);
+extern void l2cap_connect_cfm(struct hci_conn *hcon, u8 status);
 extern int l2cap_disconn_ind(struct hci_conn *hcon);
-extern int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason);
+extern void l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason);
 extern int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt);
 extern int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb,
                              u16 flags);
 
 extern int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr);
-extern int sco_connect_cfm(struct hci_conn *hcon, __u8 status);
-extern int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason);
+extern void sco_connect_cfm(struct hci_conn *hcon, __u8 status);
+extern void sco_disconn_cfm(struct hci_conn *hcon, __u8 reason);
 extern int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb);
 
 /* ----- Inquiry cache ----- */
@@ -557,9 +551,7 @@ static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
        return NULL;
 }
 
-void hci_acl_connect(struct hci_conn *conn);
 void hci_acl_disconn(struct hci_conn *conn, __u8 reason);
-void hci_add_sco(struct hci_conn *conn, __u16 handle);
 void hci_setup_sync(struct hci_conn *conn, __u16 handle);
 void hci_sco_setup(struct hci_conn *conn, __u8 status);
 
@@ -587,8 +579,7 @@ void hci_conn_put_device(struct hci_conn *conn);
 
 static inline void hci_conn_hold(struct hci_conn *conn)
 {
-       BT_DBG("hcon %p refcnt %d -> %d", conn, atomic_read(&conn->refcnt),
-              atomic_read(&conn->refcnt) + 1);
+       BT_DBG("hcon %p orig refcnt %d", conn, atomic_read(&conn->refcnt));
 
        atomic_inc(&conn->refcnt);
        cancel_delayed_work(&conn->disc_work);
@@ -596,8 +587,7 @@ static inline void hci_conn_hold(struct hci_conn *conn)
 
 static inline void hci_conn_put(struct hci_conn *conn)
 {
-       BT_DBG("hcon %p refcnt %d -> %d", conn, atomic_read(&conn->refcnt),
-              atomic_read(&conn->refcnt) - 1);
+       BT_DBG("hcon %p orig refcnt %d", conn, atomic_read(&conn->refcnt));
 
        if (atomic_dec_and_test(&conn->refcnt)) {
                unsigned long timeo;
@@ -1012,7 +1002,7 @@ int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
                          u8 addr_type, u32 flags, u8 *name, u8 name_len,
                          u8 *dev_class);
 int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
-                            u8 link_type, u8 addr_type);
+                            u8 link_type, u8 addr_type, u8 reason);
 int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
                           u8 link_type, u8 addr_type, u8 status);
 int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
@@ -1056,7 +1046,7 @@ int mgmt_discovering(struct hci_dev *hdev, u8 discovering);
 int mgmt_interleaved_discovery(struct hci_dev *hdev);
 int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
 int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
-
+bool mgmt_valid_hdev(struct hci_dev *hdev);
 int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent);
 
 /* HCI info for socket */
index a7679f8913d2e9e8b9c14a0807bedd12c607b9cc..d206296137e2b4fb50aa49bcee18dae9f0d687fb 100644 (file)
@@ -671,20 +671,8 @@ enum {
        L2CAP_EV_RECV_FRAME,
 };
 
-static inline void l2cap_chan_hold(struct l2cap_chan *c)
-{
-       BT_DBG("chan %p orig refcnt %d", c, atomic_read(&c->refcnt));
-
-       atomic_inc(&c->refcnt);
-}
-
-static inline void l2cap_chan_put(struct l2cap_chan *c)
-{
-       BT_DBG("chan %p orig refcnt %d", c, atomic_read(&c->refcnt));
-
-       if (atomic_dec_and_test(&c->refcnt))
-               kfree(c);
-}
+void l2cap_chan_hold(struct l2cap_chan *c);
+void l2cap_chan_put(struct l2cap_chan *c);
 
 static inline void l2cap_chan_lock(struct l2cap_chan *chan)
 {
@@ -771,7 +759,6 @@ int l2cap_add_scid(struct l2cap_chan *chan,  __u16 scid);
 
 struct l2cap_chan *l2cap_chan_create(void);
 void l2cap_chan_close(struct l2cap_chan *chan, int reason);
-void l2cap_chan_destroy(struct l2cap_chan *chan);
 int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
                       bdaddr_t *dst, u8 dst_type);
 int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
index 4348ee8bda6993a15193a4e1e6adb640c9512e1f..1b48effcd97352ab89e0d030257acbfa43abb8ec 100644 (file)
@@ -405,7 +405,16 @@ struct mgmt_ev_device_connected {
        __u8    eir[0];
 } __packed;
 
+#define MGMT_DEV_DISCONN_UNKNOWN       0x00
+#define MGMT_DEV_DISCONN_TIMEOUT       0x01
+#define MGMT_DEV_DISCONN_LOCAL_HOST    0x02
+#define MGMT_DEV_DISCONN_REMOTE                0x03
+
 #define MGMT_EV_DEVICE_DISCONNECTED    0x000C
+struct mgmt_ev_device_disconnected {
+       struct mgmt_addr_info addr;
+       __u8    reason;
+} __packed;
 
 #define MGMT_EV_CONNECT_FAILED         0x000D
 struct mgmt_ev_connect_failed {
index ca356a7349202272236b9d7db421f6d8804d89a5..50993a531d45b3e1780c76a6c1a2c063f9129bdd 100644 (file)
@@ -108,8 +108,8 @@ struct smp_cmd_security_req {
 #define SMP_CONFIRM_FAILED             0x04
 #define SMP_PAIRING_NOTSUPP            0x05
 #define SMP_ENC_KEY_SIZE               0x06
-#define SMP_CMD_NOTSUPP                0x07
-#define SMP_UNSPECIFIED                0x08
+#define SMP_CMD_NOTSUPP                        0x07
+#define SMP_UNSPECIFIED                        0x08
 #define SMP_REPEATED_ATTEMPTS          0x09
 
 #define SMP_MIN_ENC_KEY_SIZE           7
@@ -123,8 +123,8 @@ struct smp_chan {
        struct l2cap_conn *conn;
        u8              preq[7]; /* SMP Pairing Request */
        u8              prsp[7]; /* SMP Pairing Response */
-       u8              prnd[16]; /* SMP Pairing Random (local) */
-       u8              rrnd[16]; /* SMP Pairing Random (remote) */
+       u8              prnd[16]; /* SMP Pairing Random (local) */
+       u8              rrnd[16]; /* SMP Pairing Random (remote) */
        u8              pcnf[16]; /* SMP Pairing Confirm */
        u8              tk[16]; /* SMP Temporary Key */
        u8              enc_key_size;
index 493fa0c790051ecd10a41050e7c7a05d323a52b0..3d254e10ff30e7ab3c5a4fee2ee0b38f1309bd94 100644 (file)
@@ -96,6 +96,7 @@ enum ieee80211_band {
  *     is not permitted.
  * @IEEE80211_CHAN_NO_HT40MINUS: extension channel below this channel
  *     is not permitted.
+ * @IEEE80211_CHAN_NO_OFDM: OFDM is not allowed on this channel.
  */
 enum ieee80211_channel_flags {
        IEEE80211_CHAN_DISABLED         = 1<<0,
@@ -104,6 +105,7 @@ enum ieee80211_channel_flags {
        IEEE80211_CHAN_RADAR            = 1<<3,
        IEEE80211_CHAN_NO_HT40PLUS      = 1<<4,
        IEEE80211_CHAN_NO_HT40MINUS     = 1<<5,
+       IEEE80211_CHAN_NO_OFDM          = 1<<6,
 };
 
 #define IEEE80211_CHAN_NO_HT40 \
index 550debfc240384f529562e3cc10cafcd342725f4..389cf621161d6903510c023e04e57a4ccd03072c 100644 (file)
@@ -305,6 +305,8 @@ static struct sk_buff *codel_dequeue(struct Qdisc *sch,
                        }
                }
        } else if (drop) {
+               u32 delta;
+
                if (params->ecn && INET_ECN_set_ce(skb)) {
                        stats->ecn_mark++;
                } else {
@@ -320,9 +322,11 @@ static struct sk_buff *codel_dequeue(struct Qdisc *sch,
                 * assume that the drop rate that controlled the queue on the
                 * last cycle is a good starting point to control it now.
                 */
-               if (codel_time_before(now - vars->drop_next,
+               delta = vars->count - vars->lastcount;
+               if (delta > 1 &&
+                   codel_time_before(now - vars->drop_next,
                                      16 * params->interval)) {
-                       vars->count = (vars->count - vars->lastcount) | 1;
+                       vars->count = delta;
                        /* we dont care if rec_inv_sqrt approximation
                         * is not very precise :
                         * Next Newton steps will correct it quadratically.
index baf59789006427bc7c373449b62b271e6e777d15..9a7881066fb316b02fdd7ed52aaf84d038ded1f6 100644 (file)
@@ -110,7 +110,7 @@ struct dst_entry {
 };
 
 extern u32 *dst_cow_metrics_generic(struct dst_entry *dst, unsigned long old);
-extern const u32 dst_default_metrics[RTAX_MAX];
+extern const u32 dst_default_metrics[];
 
 #define DST_METRICS_READ_ONLY  0x1UL
 #define __DST_METRICS_PTR(Y)   \
@@ -396,11 +396,15 @@ static inline void dst_confirm(struct dst_entry *dst)
 static inline int dst_neigh_output(struct dst_entry *dst, struct neighbour *n,
                                   struct sk_buff *skb)
 {
-       struct hh_cache *hh;
+       const struct hh_cache *hh;
+
+       if (dst->pending_confirm) {
+               unsigned long now = jiffies;
 
-       if (unlikely(dst->pending_confirm)) {
-               n->confirmed = jiffies;
                dst->pending_confirm = 0;
+               /* avoid dirtying neighbour */
+               if (n->confirmed != now)
+                       n->confirmed = now;
        }
 
        hh = &n->hh;
index 5ee66f517b4f6c34734be9d5f6552439802a5a38..ba1d3615acbb7bc481e7b676d897140cea0213b6 100644 (file)
@@ -39,6 +39,7 @@ struct inet_connection_sock_af_ops {
        int         (*queue_xmit)(struct sk_buff *skb, struct flowi *fl);
        void        (*send_check)(struct sock *sk, struct sk_buff *skb);
        int         (*rebuild_header)(struct sock *sk);
+       void        (*sk_rx_dst_set)(struct sock *sk, const struct sk_buff *skb);
        int         (*conn_request)(struct sock *sk, struct sk_buff *skb);
        struct sock *(*syn_recv_sock)(struct sock *sk, struct sk_buff *skb,
                                      struct request_sock *req,
index 83b567fe194163b74f734cedaf1dffff28e914a6..613cfa4016728300da88a8fc6f1f664de99da5cc 100644 (file)
@@ -249,13 +249,4 @@ static inline __u8 inet_sk_flowi_flags(const struct sock *sk)
        return flags;
 }
 
-static inline void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
-{
-       struct dst_entry *dst = skb_dst(skb);
-
-       dst_hold(dst);
-       sk->sk_rx_dst = dst;
-       inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
-}
-
 #endif /* _INET_SOCK_H */
index bd5e444a19ce43482f09f695c6e3b36a303302b3..5a5d84d3d2c6b6e3777035a631fb10e7479ab8de 100644 (file)
@@ -120,7 +120,7 @@ extern struct sk_buff  *__ip_make_skb(struct sock *sk,
                                      struct flowi4 *fl4,
                                      struct sk_buff_head *queue,
                                      struct inet_cork *cork);
-extern int             ip_send_skb(struct sk_buff *skb);
+extern int             ip_send_skb(struct net *net, struct sk_buff *skb);
 extern int             ip_push_pending_frames(struct sock *sk, struct flowi4 *fl4);
 extern void            ip_flush_pending_frames(struct sock *sk);
 extern struct sk_buff  *ip_make_skb(struct sock *sk,
index 358fb86f57eb952816bc76736b7b85644dd77184..e03047f7090bb3419c2aa6f8b39f3a7ff0494f8a 100644 (file)
@@ -5,6 +5,8 @@
 #include <linux/netdevice.h>
 #include <linux/ip6_tunnel.h>
 
+#define IP6TUNNEL_ERR_TIMEO (30*HZ)
+
 /* capable of sending packets */
 #define IP6_TNL_F_CAP_XMIT 0x10000
 /* capable of receiving packets */
 /* determine capability on a per-packet basis */
 #define IP6_TNL_F_CAP_PER_PACKET 0x40000
 
-/* IPv6 tunnel */
+struct __ip6_tnl_parm {
+       char name[IFNAMSIZ];    /* name of tunnel device */
+       int link;               /* ifindex of underlying L2 interface */
+       __u8 proto;             /* tunnel protocol */
+       __u8 encap_limit;       /* encapsulation limit for tunnel */
+       __u8 hop_limit;         /* hop limit for tunnel */
+       __be32 flowinfo;        /* traffic class and flowlabel for tunnel */
+       __u32 flags;            /* tunnel flags */
+       struct in6_addr laddr;  /* local tunnel end-point address */
+       struct in6_addr raddr;  /* remote tunnel end-point address */
+
+       __be16                  i_flags;
+       __be16                  o_flags;
+       __be32                  i_key;
+       __be32                  o_key;
+};
 
+/* IPv6 tunnel */
 struct ip6_tnl {
        struct ip6_tnl __rcu *next;     /* next tunnel in list */
        struct net_device *dev; /* virtual device associated with tunnel */
-       struct ip6_tnl_parm parms;      /* tunnel configuration parameters */
+       struct __ip6_tnl_parm parms;    /* tunnel configuration parameters */
        struct flowi fl;        /* flowi template for xmit */
        struct dst_entry *dst_cache;    /* cached dst */
        u32 dst_cookie;
+
+       int err_count;
+       unsigned long err_time;
+
+       /* These fields used only by GRE */
+       __u32 i_seqno;  /* The last seen seqno  */
+       __u32 o_seqno;  /* The last output seqno */
+       int hlen;       /* Precalculated GRE header length */
+       int mlink;
 };
 
 /* Tunnel encapsulation limit destination sub-option */
@@ -31,4 +58,14 @@ struct ipv6_tlv_tnl_enc_lim {
        __u8 encap_limit;       /* tunnel encapsulation limit   */
 } __packed;
 
+struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t);
+void ip6_tnl_dst_reset(struct ip6_tnl *t);
+void ip6_tnl_dst_store(struct ip6_tnl *t, struct dst_entry *dst);
+int ip6_tnl_rcv_ctl(struct ip6_tnl *t, const struct in6_addr *laddr,
+               const struct in6_addr *raddr);
+int ip6_tnl_xmit_ctl(struct ip6_tnl *t);
+__u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw);
+__u32 ip6_tnl_get_cap(struct ip6_tnl *t, const struct in6_addr *laddr,
+                            const struct in6_addr *raddr);
+
 #endif
index 01c34b363a34d1f7b126d55dffd8e170963528ed..6d01fb00ff2b613f7061f16e91c6890b2c927e61 100644 (file)
@@ -34,6 +34,7 @@
 #define NEXTHDR_IPV6           41      /* IPv6 in IPv6 */
 #define NEXTHDR_ROUTING                43      /* Routing header. */
 #define NEXTHDR_FRAGMENT       44      /* Fragmentation/reassembly header. */
+#define NEXTHDR_GRE            47      /* GRE header. */
 #define NEXTHDR_ESP            50      /* Encapsulating security payload. */
 #define NEXTHDR_AUTH           51      /* Authentication header. */
 #define NEXTHDR_ICMP           58      /* ICMP for IPv6. */
index 59ba38bc400f43d3e87c1502395cef9a54e5811c..80ffde3bb164e2a3a856838f0c8c4c2906bfeaf6 100644 (file)
 /* Same for payload size. See qos.c for the smallest max data size */
 #define IRCOMM_TTY_DATA_UNINITIALISED  (64 - IRCOMM_TTY_HDR_UNINITIALISED)
 
-/* Those are really defined in include/linux/serial.h - Jean II */
-#define ASYNC_B_INITIALIZED    31      /* Serial port was initialized */
-#define ASYNC_B_NORMAL_ACTIVE  29      /* Normal device is active */
-#define ASYNC_B_CLOSING                27      /* Serial port is closing */
-
 /*
  * IrCOMM TTY driver state
  */
 struct ircomm_tty_cb {
        irda_queue_t queue;            /* Must be first */
+       struct tty_port port;
        magic_t magic;
 
        int state;                /* Connect state */
 
-       struct tty_struct *tty;
        struct ircomm_cb *ircomm; /* IrCOMM layer instance */
 
        struct sk_buff *tx_skb;   /* Transmit buffer */
@@ -80,7 +75,6 @@ struct ircomm_tty_cb {
        LOCAL_FLOW flow;          /* IrTTP flow status */
 
        int line;
-       unsigned long flags;
 
        __u8 dlsap_sel;
        __u8 slsap_sel;
@@ -97,19 +91,10 @@ struct ircomm_tty_cb {
        void *skey;
        void *ckey;
 
-       wait_queue_head_t open_wait;
-       wait_queue_head_t close_wait;
        struct timer_list watchdog_timer;
        struct work_struct  tqueue;
 
-        unsigned short    close_delay;
-        unsigned short    closing_wait; /* time to wait before closing */
-
-       int  open_count;
-       int  blocked_open;      /* # of blocked opens */
-
        /* Protect concurent access to :
-        *      o self->open_count
         *      o self->ctrl_skb
         *      o self->tx_skb
         * Maybe other things may gain to be protected as well...
index 226c846cab08bdf84e0991aee83124c42e6aab0d..f2d0fc570527baf216f34cd364c0162330dcbd28 100644 (file)
@@ -133,7 +133,7 @@ extern int llc_build_and_send_ui_pkt(struct llc_sap *sap, struct sk_buff *skb,
 extern void llc_sap_handler(struct llc_sap *sap, struct sk_buff *skb);
 extern void llc_conn_handler(struct llc_sap *sap, struct sk_buff *skb);
 
-extern int llc_station_init(void);
+extern void llc_station_init(void);
 extern void llc_station_exit(void);
 
 #ifdef CONFIG_PROC_FS
index 96a3b5c03e37d965b51e9d9754af3969df6146fc..980d263765cf41059ede684d54abafb6a9e66c6c 100644 (file)
@@ -49,6 +49,7 @@ enum {
 #include <linux/types.h>
 #include <linux/if_arp.h>
 #include <linux/netdevice.h>
+#include <linux/hash.h>
 
 #include <net/neighbour.h>
 
@@ -134,7 +135,7 @@ static inline u32 ndisc_hashfn(const void *pkey, const struct net_device *dev, _
 {
        const u32 *p32 = pkey;
 
-       return (((p32[0] ^ dev->ifindex) * hash_rnd[0]) +
+       return (((p32[0] ^ hash32_ptr(dev)) * hash_rnd[0]) +
                (p32[1] * hash_rnd[1]) +
                (p32[2] * hash_rnd[2]) +
                (p32[3] * hash_rnd[3]));
index 344d8988842a527fbec3bffc674cda865f67b15c..0dab173e27da6e8e66a8eea4913f5b0230f612bd 100644 (file)
@@ -334,18 +334,22 @@ static inline int neigh_hh_bridge(struct hh_cache *hh, struct sk_buff *skb)
 }
 #endif
 
-static inline int neigh_hh_output(struct hh_cache *hh, struct sk_buff *skb)
+static inline int neigh_hh_output(const struct hh_cache *hh, struct sk_buff *skb)
 {
        unsigned int seq;
        int hh_len;
 
        do {
-               int hh_alen;
-
                seq = read_seqbegin(&hh->hh_lock);
                hh_len = hh->hh_len;
-               hh_alen = HH_DATA_ALIGN(hh_len);
-               memcpy(skb->data - hh_alen, hh->hh_data, hh_alen);
+               if (likely(hh_len <= HH_DATA_MOD)) {
+                       /* this is inlined by gcc */
+                       memcpy(skb->data - HH_DATA_MOD, hh->hh_data, HH_DATA_MOD);
+               } else {
+                       int hh_alen = HH_DATA_ALIGN(hh_len);
+
+                       memcpy(skb->data - hh_alen, hh->hh_data, hh_alen);
+               }
        } while (read_seqretry(&hh->hh_lock, seq));
 
        skb_push(skb, hh_len);
index ae1cd6c9ba521bb6ca9a57706b4ca77180bdcc7a..5ae57f1ab7551e556c0145dcb51206d5de08ecc6 100644 (file)
@@ -15,6 +15,7 @@
 #include <net/netns/packet.h>
 #include <net/netns/ipv4.h>
 #include <net/netns/ipv6.h>
+#include <net/netns/sctp.h>
 #include <net/netns/dccp.h>
 #include <net/netns/x_tables.h>
 #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
@@ -66,6 +67,7 @@ struct net {
        struct hlist_head       *dev_name_head;
        struct hlist_head       *dev_index_head;
        unsigned int            dev_base_seq;   /* protected by rtnl_mutex */
+       int                     ifindex;
 
        /* core fib_rules */
        struct list_head        rules_ops;
@@ -80,6 +82,9 @@ struct net {
 #if IS_ENABLED(CONFIG_IPV6)
        struct netns_ipv6       ipv6;
 #endif
+#if defined(CONFIG_IP_SCTP) || defined(CONFIG_IP_SCTP_MODULE)
+       struct netns_sctp       sctp;
+#endif
 #if defined(CONFIG_IP_DCCP) || defined(CONFIG_IP_DCCP_MODULE)
        struct netns_dccp       dccp;
 #endif
@@ -104,6 +109,13 @@ struct net {
        struct sock             *diag_nlsk;
 };
 
+/*
+ * ifindex generation is per-net namespace, and loopback is
+ * always the 1st device in ns (see net_dev_init), thus any
+ * loopback device should get ifindex 1
+ */
+
+#define LOOPBACK_IFINDEX       1
 
 #include <linux/seq_file_net.h>
 
index 785f37a3b44ee80e1336d7301bd54c6ff48b7ba7..09175d5d1fbf15e56dbf4ae7406e886f0dce1602 100644 (file)
  *   nla_put_u16(skb, type, value)     add u16 attribute to skb
  *   nla_put_u32(skb, type, value)     add u32 attribute to skb
  *   nla_put_u64(skb, type, value)     add u64 attribute to skb
+ *   nla_put_s8(skb, type, value)      add s8 attribute to skb
+ *   nla_put_s16(skb, type, value)     add s16 attribute to skb
+ *   nla_put_s32(skb, type, value)     add s32 attribute to skb
+ *   nla_put_s64(skb, type, value)     add s64 attribute to skb
  *   nla_put_string(skb, type, str)    add string attribute to skb
  *   nla_put_flag(skb, type)           add flag attribute to skb
  *   nla_put_msecs(skb, type, jiffies) add msecs attribute to skb
  *   nla_get_u16(nla)                  get payload for a u16 attribute
  *   nla_get_u32(nla)                  get payload for a u32 attribute
  *   nla_get_u64(nla)                  get payload for a u64 attribute
+ *   nla_get_s8(nla)                   get payload for a s8 attribute
+ *   nla_get_s16(nla)                  get payload for a s16 attribute
+ *   nla_get_s32(nla)                  get payload for a s32 attribute
+ *   nla_get_s64(nla)                  get payload for a s64 attribute
  *   nla_get_flag(nla)                 return 1 if flag is true
  *   nla_get_msecs(nla)                        get payload for a msecs attribute
  *
@@ -160,6 +168,10 @@ enum {
        NLA_NESTED_COMPAT,
        NLA_NUL_STRING,
        NLA_BINARY,
+       NLA_S8,
+       NLA_S16,
+       NLA_S32,
+       NLA_S64,
        __NLA_TYPE_MAX,
 };
 
@@ -183,6 +195,8 @@ enum {
  *    NLA_NESTED_COMPAT    Minimum length of structure payload
  *    NLA_U8, NLA_U16,
  *    NLA_U32, NLA_U64,
+ *    NLA_S8, NLA_S16,
+ *    NLA_S32, NLA_S64,
  *    NLA_MSECS            Leaving the length field zero will verify the
  *                         given type fits, using it verifies minimum length
  *                         just like "All other"
@@ -878,6 +892,50 @@ static inline int nla_put_le64(struct sk_buff *skb, int attrtype, __le64 value)
        return nla_put(skb, attrtype, sizeof(__le64), &value);
 }
 
+/**
+ * nla_put_s8 - Add a s8 netlink attribute to a socket buffer
+ * @skb: socket buffer to add attribute to
+ * @attrtype: attribute type
+ * @value: numeric value
+ */
+static inline int nla_put_s8(struct sk_buff *skb, int attrtype, s8 value)
+{
+       return nla_put(skb, attrtype, sizeof(s8), &value);
+}
+
+/**
+ * nla_put_s16 - Add a s16 netlink attribute to a socket buffer
+ * @skb: socket buffer to add attribute to
+ * @attrtype: attribute type
+ * @value: numeric value
+ */
+static inline int nla_put_s16(struct sk_buff *skb, int attrtype, s16 value)
+{
+       return nla_put(skb, attrtype, sizeof(s16), &value);
+}
+
+/**
+ * nla_put_s32 - Add a s32 netlink attribute to a socket buffer
+ * @skb: socket buffer to add attribute to
+ * @attrtype: attribute type
+ * @value: numeric value
+ */
+static inline int nla_put_s32(struct sk_buff *skb, int attrtype, s32 value)
+{
+       return nla_put(skb, attrtype, sizeof(s32), &value);
+}
+
+/**
+ * nla_put_s64 - Add a s64 netlink attribute to a socket buffer
+ * @skb: socket buffer to add attribute to
+ * @attrtype: attribute type
+ * @value: numeric value
+ */
+static inline int nla_put_s64(struct sk_buff *skb, int attrtype, s64 value)
+{
+       return nla_put(skb, attrtype, sizeof(s64), &value);
+}
+
 /**
  * nla_put_string - Add a string netlink attribute to a socket buffer
  * @skb: socket buffer to add attribute to
@@ -993,6 +1051,46 @@ static inline __be64 nla_get_be64(const struct nlattr *nla)
        return tmp;
 }
 
+/**
+ * nla_get_s32 - return payload of s32 attribute
+ * @nla: s32 netlink attribute
+ */
+static inline s32 nla_get_s32(const struct nlattr *nla)
+{
+       return *(s32 *) nla_data(nla);
+}
+
+/**
+ * nla_get_s16 - return payload of s16 attribute
+ * @nla: s16 netlink attribute
+ */
+static inline s16 nla_get_s16(const struct nlattr *nla)
+{
+       return *(s16 *) nla_data(nla);
+}
+
+/**
+ * nla_get_s8 - return payload of s8 attribute
+ * @nla: s8 netlink attribute
+ */
+static inline s8 nla_get_s8(const struct nlattr *nla)
+{
+       return *(s8 *) nla_data(nla);
+}
+
+/**
+ * nla_get_s64 - return payload of s64 attribute
+ * @nla: s64 netlink attribute
+ */
+static inline s64 nla_get_s64(const struct nlattr *nla)
+{
+       s64 tmp;
+
+       nla_memcpy(&tmp, nla, sizeof(tmp));
+
+       return tmp;
+}
+
 /**
  * nla_get_flag - return payload of flag attribute
  * @nla: flag netlink attribute
diff --git a/include/net/netns/sctp.h b/include/net/netns/sctp.h
new file mode 100644 (file)
index 0000000..5e5eb1f
--- /dev/null
@@ -0,0 +1,131 @@
+#ifndef __NETNS_SCTP_H__
+#define __NETNS_SCTP_H__
+
+struct sock;
+struct proc_dir_entry;
+struct sctp_mib;
+struct ctl_table_header;
+
+struct netns_sctp {
+       DEFINE_SNMP_STAT(struct sctp_mib, sctp_statistics);
+
+#ifdef CONFIG_PROC_FS
+       struct proc_dir_entry *proc_net_sctp;
+#endif
+#ifdef CONFIG_SYSCTL
+       struct ctl_table_header *sysctl_header;
+#endif
+       /* This is the global socket data structure used for responding to
+        * the Out-of-the-blue (OOTB) packets.  A control sock will be created
+        * for this socket at the initialization time.
+        */
+       struct sock *ctl_sock;
+
+       /* This is the global local address list.
+        * We actively maintain this complete list of addresses on
+        * the system by catching address add/delete events.
+        *
+        * It is a list of sctp_sockaddr_entry.
+        */
+       struct list_head local_addr_list;
+       struct list_head addr_waitq;
+       struct timer_list addr_wq_timer;
+       struct list_head auto_asconf_splist;
+       spinlock_t addr_wq_lock;
+
+       /* Lock that protects the local_addr_list writers */
+       spinlock_t local_addr_lock;
+
+       /* RFC2960 Section 14. Suggested SCTP Protocol Parameter Values
+        *
+        * The following protocol parameters are RECOMMENDED:
+        *
+        * RTO.Initial              - 3  seconds
+        * RTO.Min                  - 1  second
+        * RTO.Max                 -  60 seconds
+        * RTO.Alpha                - 1/8  (3 when converted to right shifts.)
+        * RTO.Beta                 - 1/4  (2 when converted to right shifts.)
+        */
+       unsigned int rto_initial;
+       unsigned int rto_min;
+       unsigned int rto_max;
+
+       /* Note: rto_alpha and rto_beta are really defined as inverse
+        * powers of two to facilitate integer operations.
+        */
+       int rto_alpha;
+       int rto_beta;
+
+       /* Max.Burst                - 4 */
+       int max_burst;
+
+       /* Whether Cookie Preservative is enabled(1) or not(0) */
+       int cookie_preserve_enable;
+
+       /* Valid.Cookie.Life        - 60  seconds  */
+       unsigned int valid_cookie_life;
+
+       /* Delayed SACK timeout  200ms default*/
+       unsigned int sack_timeout;
+
+       /* HB.interval              - 30 seconds  */
+       unsigned int hb_interval;
+
+       /* Association.Max.Retrans  - 10 attempts
+        * Path.Max.Retrans         - 5  attempts (per destination address)
+        * Max.Init.Retransmits     - 8  attempts
+        */
+       int max_retrans_association;
+       int max_retrans_path;
+       int max_retrans_init;
+       /* Potentially-Failed.Max.Retrans sysctl value
+        * taken from:
+        * http://tools.ietf.org/html/draft-nishida-tsvwg-sctp-failover-05
+        */
+       int pf_retrans;
+
+       /*
+        * Policy for preforming sctp/socket accounting
+        * 0   - do socket level accounting, all assocs share sk_sndbuf
+        * 1   - do sctp accounting, each asoc may use sk_sndbuf bytes
+        */
+       int sndbuf_policy;
+
+       /*
+        * Policy for preforming sctp/socket accounting
+        * 0   - do socket level accounting, all assocs share sk_rcvbuf
+        * 1   - do sctp accounting, each asoc may use sk_rcvbuf bytes
+        */
+       int rcvbuf_policy;
+
+       int default_auto_asconf;
+
+       /* Flag to indicate if addip is enabled. */
+       int addip_enable;
+       int addip_noauth;
+
+       /* Flag to indicate if PR-SCTP is enabled. */
+       int prsctp_enable;
+
+       /* Flag to idicate if SCTP-AUTH is enabled */
+       int auth_enable;
+
+       /*
+        * Policy to control SCTP IPv4 address scoping
+        * 0   - Disable IPv4 address scoping
+        * 1   - Enable IPv4 address scoping
+        * 2   - Selectively allow only IPv4 private addresses
+        * 3   - Selectively allow only IPv4 link local address
+        */
+       int scope_policy;
+
+       /* Threshold for rwnd update SACKS.  Receive buffer shifted this many
+        * bits is an indicator of when to send and window update SACK.
+        */
+       int rwnd_upd_shift;
+
+       /* Threshold for autoclose timeout, in seconds. */
+       unsigned long max_autoclose;
+};
+
+#endif /* __NETNS_SCTP_H__ */
index ff499640528b0012fd76c09141e978688f00b0a9..9c6414f553f91f2256698323ea5d8ec72db4e868 100644 (file)
 /*
  * sctp/protocol.c
  */
-extern struct sock *sctp_get_ctl_sock(void);
-extern int sctp_copy_local_addr_list(struct sctp_bind_addr *,
+extern int sctp_copy_local_addr_list(struct net *, struct sctp_bind_addr *,
                                     sctp_scope_t, gfp_t gfp,
                                     int flags);
 extern struct sctp_pf *sctp_get_pf_specific(sa_family_t family);
 extern int sctp_register_pf(struct sctp_pf *, sa_family_t);
-extern void sctp_addr_wq_mgmt(struct sctp_sockaddr_entry *, int);
+extern void sctp_addr_wq_mgmt(struct net *, struct sctp_sockaddr_entry *, int);
 
 /*
  * sctp/socket.c
@@ -140,12 +139,12 @@ extern int sctp_asconf_mgmt(struct sctp_sock *, struct sctp_sockaddr_entry *);
 /*
  * sctp/primitive.c
  */
-int sctp_primitive_ASSOCIATE(struct sctp_association *, void *arg);
-int sctp_primitive_SHUTDOWN(struct sctp_association *, void *arg);
-int sctp_primitive_ABORT(struct sctp_association *, void *arg);
-int sctp_primitive_SEND(struct sctp_association *, void *arg);
-int sctp_primitive_REQUESTHEARTBEAT(struct sctp_association *, void *arg);
-int sctp_primitive_ASCONF(struct sctp_association *, void *arg);
+int sctp_primitive_ASSOCIATE(struct net *, struct sctp_association *, void *arg);
+int sctp_primitive_SHUTDOWN(struct net *, struct sctp_association *, void *arg);
+int sctp_primitive_ABORT(struct net *, struct sctp_association *, void *arg);
+int sctp_primitive_SEND(struct net *, struct sctp_association *, void *arg);
+int sctp_primitive_REQUESTHEARTBEAT(struct net *, struct sctp_association *, void *arg);
+int sctp_primitive_ASCONF(struct net *, struct sctp_association *, void *arg);
 
 /*
  * sctp/input.c
@@ -156,7 +155,7 @@ void sctp_hash_established(struct sctp_association *);
 void sctp_unhash_established(struct sctp_association *);
 void sctp_hash_endpoint(struct sctp_endpoint *);
 void sctp_unhash_endpoint(struct sctp_endpoint *);
-struct sock *sctp_err_lookup(int family, struct sk_buff *,
+struct sock *sctp_err_lookup(struct net *net, int family, struct sk_buff *,
                             struct sctphdr *, struct sctp_association **,
                             struct sctp_transport **);
 void sctp_err_finish(struct sock *, struct sctp_association *);
@@ -173,14 +172,14 @@ void sctp_backlog_migrate(struct sctp_association *assoc,
 /*
  * sctp/proc.c
  */
-int sctp_snmp_proc_init(void);
-void sctp_snmp_proc_exit(void);
-int sctp_eps_proc_init(void);
-void sctp_eps_proc_exit(void);
-int sctp_assocs_proc_init(void);
-void sctp_assocs_proc_exit(void);
-int sctp_remaddr_proc_init(void);
-void sctp_remaddr_proc_exit(void);
+int sctp_snmp_proc_init(struct net *net);
+void sctp_snmp_proc_exit(struct net *net);
+int sctp_eps_proc_init(struct net *net);
+void sctp_eps_proc_exit(struct net *net);
+int sctp_assocs_proc_init(struct net *net);
+void sctp_assocs_proc_exit(struct net *net);
+int sctp_remaddr_proc_init(struct net *net);
+void sctp_remaddr_proc_exit(struct net *net);
 
 
 /*
@@ -222,11 +221,10 @@ extern struct kmem_cache *sctp_bucket_cachep __read_mostly;
 #define sctp_bh_unlock_sock(sk)  bh_unlock_sock(sk)
 
 /* SCTP SNMP MIB stats handlers */
-DECLARE_SNMP_STAT(struct sctp_mib, sctp_statistics);
-#define SCTP_INC_STATS(field)      SNMP_INC_STATS(sctp_statistics, field)
-#define SCTP_INC_STATS_BH(field)   SNMP_INC_STATS_BH(sctp_statistics, field)
-#define SCTP_INC_STATS_USER(field) SNMP_INC_STATS_USER(sctp_statistics, field)
-#define SCTP_DEC_STATS(field)      SNMP_DEC_STATS(sctp_statistics, field)
+#define SCTP_INC_STATS(net, field)      SNMP_INC_STATS((net)->sctp.sctp_statistics, field)
+#define SCTP_INC_STATS_BH(net, field)   SNMP_INC_STATS_BH((net)->sctp.sctp_statistics, field)
+#define SCTP_INC_STATS_USER(net, field) SNMP_INC_STATS_USER((net)->sctp.sctp_statistics, field)
+#define SCTP_DEC_STATS(net, field)      SNMP_DEC_STATS((net)->sctp.sctp_statistics, field)
 
 #endif /* !TEST_FRAME */
 
@@ -361,25 +359,29 @@ atomic_t sctp_dbg_objcnt_## name = ATOMIC_INIT(0)
 #define SCTP_DBG_OBJCNT_ENTRY(name) \
 {.label= #name, .counter= &sctp_dbg_objcnt_## name}
 
-void sctp_dbg_objcnt_init(void);
-void sctp_dbg_objcnt_exit(void);
+void sctp_dbg_objcnt_init(struct net *);
+void sctp_dbg_objcnt_exit(struct net *);
 
 #else
 
 #define SCTP_DBG_OBJCNT_INC(name)
 #define SCTP_DBG_OBJCNT_DEC(name)
 
-static inline void sctp_dbg_objcnt_init(void) { return; }
-static inline void sctp_dbg_objcnt_exit(void) { return; }
+static inline void sctp_dbg_objcnt_init(struct net *net) { return; }
+static inline void sctp_dbg_objcnt_exit(struct net *net) { return; }
 
 #endif /* CONFIG_SCTP_DBG_OBJCOUNT */
 
 #if defined CONFIG_SYSCTL
 void sctp_sysctl_register(void);
 void sctp_sysctl_unregister(void);
+int sctp_sysctl_net_register(struct net *net);
+void sctp_sysctl_net_unregister(struct net *net);
 #else
 static inline void sctp_sysctl_register(void) { return; }
 static inline void sctp_sysctl_unregister(void) { return; }
+static inline int sctp_sysctl_net_register(struct net *net) { return 0; }
+static inline void sctp_sysctl_net_unregister(struct net *net) { return; }
 #endif
 
 /* Size of Supported Address Parameter for 'x' address types. */
@@ -586,7 +588,6 @@ for (pos = chunk->subh.fwdtsn_hdr->skip;\
 
 extern struct proto sctp_prot;
 extern struct proto sctpv6_prot;
-extern struct proc_dir_entry *proc_net_sctp;
 void sctp_put_port(struct sock *sk);
 
 extern struct idr sctp_assocs_id;
@@ -632,21 +633,21 @@ static inline int sctp_sanity_check(void)
 
 /* Warning: The following hash functions assume a power of two 'size'. */
 /* This is the hash function for the SCTP port hash table. */
-static inline int sctp_phashfn(__u16 lport)
+static inline int sctp_phashfn(struct net *net, __u16 lport)
 {
-       return lport & (sctp_port_hashsize - 1);
+       return (net_hash_mix(net) + lport) & (sctp_port_hashsize - 1);
 }
 
 /* This is the hash function for the endpoint hash table. */
-static inline int sctp_ep_hashfn(__u16 lport)
+static inline int sctp_ep_hashfn(struct net *net, __u16 lport)
 {
-       return lport & (sctp_ep_hashsize - 1);
+       return (net_hash_mix(net) + lport) & (sctp_ep_hashsize - 1);
 }
 
 /* This is the hash function for the association hash table. */
-static inline int sctp_assoc_hashfn(__u16 lport, __u16 rport)
+static inline int sctp_assoc_hashfn(struct net *net, __u16 lport, __u16 rport)
 {
-       int h = (lport << 16) + rport;
+       int h = (lport << 16) + rport + net_hash_mix(net);
        h ^= h>>8;
        return h & (sctp_assoc_hashsize - 1);
 }
index 9148632b820467ff3e64ec911c63429e56272539..b5887e1677e4e421479919399b945844133595af 100644 (file)
@@ -77,7 +77,8 @@ typedef struct {
        int action;
 } sctp_sm_command_t;
 
-typedef sctp_disposition_t (sctp_state_fn_t) (const struct sctp_endpoint *,
+typedef sctp_disposition_t (sctp_state_fn_t) (struct net *,
+                                             const struct sctp_endpoint *,
                                              const struct sctp_association *,
                                              const sctp_subtype_t type,
                                              void *arg,
@@ -178,7 +179,8 @@ sctp_state_fn_t sctp_sf_autoclose_timer_expire;
 
 /* Prototypes for utility support functions.  */
 __u8 sctp_get_chunk_type(struct sctp_chunk *chunk);
-const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t,
+const sctp_sm_table_entry_t *sctp_sm_lookup_event(struct net *,
+                                           sctp_event_t,
                                            sctp_state_t,
                                            sctp_subtype_t);
 int sctp_chunk_iif(const struct sctp_chunk *);
@@ -268,7 +270,7 @@ void sctp_chunk_assign_ssn(struct sctp_chunk *);
 
 /* Prototypes for statetable processing. */
 
-int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype,
+int sctp_do_sm(struct net *net, sctp_event_t event_type, sctp_subtype_t subtype,
               sctp_state_t state,
                struct sctp_endpoint *,
                struct sctp_association *asoc,
index fc5e60016e37422e9408d9ca0c0b00136aaf2bb6..0fef00f5d3ce1fe65e2e6483ba1502f69615597b 100644 (file)
@@ -102,6 +102,7 @@ struct sctp_bind_bucket {
        unsigned short  fastreuse;
        struct hlist_node       node;
        struct hlist_head       owner;
+       struct net      *net;
 };
 
 struct sctp_bind_hashbucket {
@@ -118,69 +119,6 @@ struct sctp_hashbucket {
 
 /* The SCTP globals structure. */
 extern struct sctp_globals {
-       /* RFC2960 Section 14. Suggested SCTP Protocol Parameter Values
-        *
-        * The following protocol parameters are RECOMMENDED:
-        *
-        * RTO.Initial              - 3  seconds
-        * RTO.Min                  - 1  second
-        * RTO.Max                 -  60 seconds
-        * RTO.Alpha                - 1/8  (3 when converted to right shifts.)
-        * RTO.Beta                 - 1/4  (2 when converted to right shifts.)
-        */
-       unsigned int rto_initial;
-       unsigned int rto_min;
-       unsigned int rto_max;
-
-       /* Note: rto_alpha and rto_beta are really defined as inverse
-        * powers of two to facilitate integer operations.
-        */
-       int rto_alpha;
-       int rto_beta;
-
-       /* Max.Burst                - 4 */
-       int max_burst;
-
-       /* Whether Cookie Preservative is enabled(1) or not(0) */
-       int cookie_preserve_enable;
-
-       /* Valid.Cookie.Life        - 60  seconds  */
-       unsigned int valid_cookie_life;
-
-       /* Delayed SACK timeout  200ms default*/
-       unsigned int sack_timeout;
-
-       /* HB.interval              - 30 seconds  */
-       unsigned int hb_interval;
-
-       /* Association.Max.Retrans  - 10 attempts
-        * Path.Max.Retrans         - 5  attempts (per destination address)
-        * Max.Init.Retransmits     - 8  attempts
-        */
-       int max_retrans_association;
-       int max_retrans_path;
-       int max_retrans_init;
-
-       /* Potentially-Failed.Max.Retrans sysctl value
-        * taken from:
-        * http://tools.ietf.org/html/draft-nishida-tsvwg-sctp-failover-05
-        */
-       int pf_retrans;
-
-       /*
-        * Policy for preforming sctp/socket accounting
-        * 0   - do socket level accounting, all assocs share sk_sndbuf
-        * 1   - do sctp accounting, each asoc may use sk_sndbuf bytes
-        */
-       int sndbuf_policy;
-
-       /*
-        * Policy for preforming sctp/socket accounting
-        * 0   - do socket level accounting, all assocs share sk_rcvbuf
-        * 1   - do sctp accounting, each asoc may use sk_rcvbuf bytes
-        */
-       int rcvbuf_policy;
-
        /* The following variables are implementation specific.  */
 
        /* Default initialization values to be applied to new associations. */
@@ -204,70 +142,11 @@ extern struct sctp_globals {
        int port_hashsize;
        struct sctp_bind_hashbucket *port_hashtable;
 
-       /* This is the global local address list.
-        * We actively maintain this complete list of addresses on
-        * the system by catching address add/delete events.
-        *
-        * It is a list of sctp_sockaddr_entry.
-        */
-       struct list_head local_addr_list;
-       int default_auto_asconf;
-       struct list_head addr_waitq;
-       struct timer_list addr_wq_timer;
-       struct list_head auto_asconf_splist;
-       spinlock_t addr_wq_lock;
-
-       /* Lock that protects the local_addr_list writers */
-       spinlock_t addr_list_lock;
-       
-       /* Flag to indicate if addip is enabled. */
-       int addip_enable;
-       int addip_noauth_enable;
-
-       /* Flag to indicate if PR-SCTP is enabled. */
-       int prsctp_enable;
-
-       /* Flag to idicate if SCTP-AUTH is enabled */
-       int auth_enable;
-
-       /*
-        * Policy to control SCTP IPv4 address scoping
-        * 0   - Disable IPv4 address scoping
-        * 1   - Enable IPv4 address scoping
-        * 2   - Selectively allow only IPv4 private addresses
-        * 3   - Selectively allow only IPv4 link local address
-        */
-       int ipv4_scope_policy;
-
        /* Flag to indicate whether computing and verifying checksum
         * is disabled. */
         bool checksum_disable;
-
-       /* Threshold for rwnd update SACKS.  Receive buffer shifted this many
-        * bits is an indicator of when to send and window update SACK.
-        */
-       int rwnd_update_shift;
-
-       /* Threshold for autoclose timeout, in seconds. */
-       unsigned long max_autoclose;
 } sctp_globals;
 
-#define sctp_rto_initial               (sctp_globals.rto_initial)
-#define sctp_rto_min                   (sctp_globals.rto_min)
-#define sctp_rto_max                   (sctp_globals.rto_max)
-#define sctp_rto_alpha                 (sctp_globals.rto_alpha)
-#define sctp_rto_beta                  (sctp_globals.rto_beta)
-#define sctp_max_burst                 (sctp_globals.max_burst)
-#define sctp_valid_cookie_life         (sctp_globals.valid_cookie_life)
-#define sctp_cookie_preserve_enable    (sctp_globals.cookie_preserve_enable)
-#define sctp_max_retrans_association   (sctp_globals.max_retrans_association)
-#define sctp_sndbuf_policy             (sctp_globals.sndbuf_policy)
-#define sctp_rcvbuf_policy             (sctp_globals.rcvbuf_policy)
-#define sctp_max_retrans_path          (sctp_globals.max_retrans_path)
-#define sctp_pf_retrans                        (sctp_globals.pf_retrans)
-#define sctp_max_retrans_init          (sctp_globals.max_retrans_init)
-#define sctp_sack_timeout              (sctp_globals.sack_timeout)
-#define sctp_hb_interval               (sctp_globals.hb_interval)
 #define sctp_max_instreams             (sctp_globals.max_instreams)
 #define sctp_max_outstreams            (sctp_globals.max_outstreams)
 #define sctp_address_families          (sctp_globals.address_families)
@@ -277,21 +156,7 @@ extern struct sctp_globals {
 #define sctp_assoc_hashtable           (sctp_globals.assoc_hashtable)
 #define sctp_port_hashsize             (sctp_globals.port_hashsize)
 #define sctp_port_hashtable            (sctp_globals.port_hashtable)
-#define sctp_local_addr_list           (sctp_globals.local_addr_list)
-#define sctp_local_addr_lock           (sctp_globals.addr_list_lock)
-#define sctp_auto_asconf_splist                (sctp_globals.auto_asconf_splist)
-#define sctp_addr_waitq                        (sctp_globals.addr_waitq)
-#define sctp_addr_wq_timer             (sctp_globals.addr_wq_timer)
-#define sctp_addr_wq_lock              (sctp_globals.addr_wq_lock)
-#define sctp_default_auto_asconf       (sctp_globals.default_auto_asconf)
-#define sctp_scope_policy              (sctp_globals.ipv4_scope_policy)
-#define sctp_addip_enable              (sctp_globals.addip_enable)
-#define sctp_addip_noauth              (sctp_globals.addip_noauth_enable)
-#define sctp_prsctp_enable             (sctp_globals.prsctp_enable)
-#define sctp_auth_enable               (sctp_globals.auth_enable)
 #define sctp_checksum_disable          (sctp_globals.checksum_disable)
-#define sctp_rwnd_upd_shift            (sctp_globals.rwnd_update_shift)
-#define sctp_max_autoclose             (sctp_globals.max_autoclose)
 
 /* SCTP Socket type: UDP or TCP style. */
 typedef enum {
@@ -1085,7 +950,7 @@ struct sctp_transport {
        __u64 hb_nonce;
 };
 
-struct sctp_transport *sctp_transport_new(const union sctp_addr *,
+struct sctp_transport *sctp_transport_new(struct net *, const union sctp_addr *,
                                          gfp_t);
 void sctp_transport_set_owner(struct sctp_transport *,
                              struct sctp_association *);
@@ -1240,7 +1105,7 @@ struct sctp_bind_addr {
 
 void sctp_bind_addr_init(struct sctp_bind_addr *, __u16 port);
 void sctp_bind_addr_free(struct sctp_bind_addr *);
-int sctp_bind_addr_copy(struct sctp_bind_addr *dest,
+int sctp_bind_addr_copy(struct net *net, struct sctp_bind_addr *dest,
                        const struct sctp_bind_addr *src,
                        sctp_scope_t scope, gfp_t gfp,
                        int flags);
@@ -1267,7 +1132,7 @@ int sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw, int len,
                           __u16 port, gfp_t gfp);
 
 sctp_scope_t sctp_scope(const union sctp_addr *);
-int sctp_in_scope(const union sctp_addr *addr, const sctp_scope_t scope);
+int sctp_in_scope(struct net *net, const union sctp_addr *addr, const sctp_scope_t scope);
 int sctp_is_any(struct sock *sk, const union sctp_addr *addr);
 int sctp_addr_is_valid(const union sctp_addr *addr);
 int sctp_is_ep_boundall(struct sock *sk);
@@ -1425,13 +1290,13 @@ struct sctp_association *sctp_endpoint_lookup_assoc(
 int sctp_endpoint_is_peeled_off(struct sctp_endpoint *,
                                const union sctp_addr *);
 struct sctp_endpoint *sctp_endpoint_is_match(struct sctp_endpoint *,
-                                       const union sctp_addr *);
-int sctp_has_association(const union sctp_addr *laddr,
+                                       struct net *, const union sctp_addr *);
+int sctp_has_association(struct net *net, const union sctp_addr *laddr,
                         const union sctp_addr *paddr);
 
-int sctp_verify_init(const struct sctp_association *asoc, sctp_cid_t,
-                    sctp_init_chunk_t *peer_init, struct sctp_chunk *chunk,
-                    struct sctp_chunk **err_chunk);
+int sctp_verify_init(struct net *net, const struct sctp_association *asoc,
+                    sctp_cid_t, sctp_init_chunk_t *peer_init,
+                    struct sctp_chunk *chunk, struct sctp_chunk **err_chunk);
 int sctp_process_init(struct sctp_association *, struct sctp_chunk *chunk,
                      const union sctp_addr *peer,
                      sctp_init_chunk_t *init, gfp_t gfp);
@@ -2013,6 +1878,7 @@ void sctp_assoc_control_transport(struct sctp_association *,
                                  sctp_transport_cmd_t, sctp_sn_error_t);
 struct sctp_transport *sctp_assoc_lookup_tsn(struct sctp_association *, __u32);
 struct sctp_transport *sctp_assoc_is_match(struct sctp_association *,
+                                          struct net *,
                                           const union sctp_addr *,
                                           const union sctp_addr *);
 void sctp_assoc_migrate(struct sctp_association *, struct sock *);
index 0147b901e79c4d6b43eef9dbe45f76eef0fc1720..71596261fa997ec7014b77f0bbee9b47b6146493 100644 (file)
@@ -154,13 +154,15 @@ struct linux_xfrm_mib {
  */
 #define SNMP_UPD_PO_STATS(mib, basefield, addend)      \
        do { \
-               this_cpu_inc(mib[0]->mibs[basefield##PKTS]);            \
-               this_cpu_add(mib[0]->mibs[basefield##OCTETS], addend);  \
+               __typeof__(*mib[0]->mibs) *ptr = mib[0]->mibs;  \
+               this_cpu_inc(ptr[basefield##PKTS]);             \
+               this_cpu_add(ptr[basefield##OCTETS], addend);   \
        } while (0)
 #define SNMP_UPD_PO_STATS_BH(mib, basefield, addend)   \
        do { \
-               __this_cpu_inc(mib[0]->mibs[basefield##PKTS]);          \
-               __this_cpu_add(mib[0]->mibs[basefield##OCTETS], addend);        \
+               __typeof__(*mib[0]->mibs) *ptr = mib[0]->mibs;  \
+               __this_cpu_inc(ptr[basefield##PKTS]);           \
+               __this_cpu_add(ptr[basefield##OCTETS], addend); \
        } while (0)
 
 
index b3730239bf1828bd9fb618b8b8988b37832fe5c3..72132aef53fc61a721ce23c8fbc4fe17cb7a9699 100644 (file)
@@ -218,6 +218,7 @@ struct cg_proto;
   *    @sk_route_nocaps: forbidden route capabilities (e.g NETIF_F_GSO_MASK)
   *    @sk_gso_type: GSO type (e.g. %SKB_GSO_TCPV4)
   *    @sk_gso_max_size: Maximum GSO segment size to build
+  *    @sk_gso_max_segs: Maximum number of GSO segments
   *    @sk_lingertime: %SO_LINGER l_linger setting
   *    @sk_backlog: always used with the per-socket spinlock held
   *    @sk_callback_lock: used with the callbacks in the end of this struct
@@ -338,6 +339,7 @@ struct sock {
        netdev_features_t       sk_route_nocaps;
        int                     sk_gso_type;
        unsigned int            sk_gso_max_size;
+       u16                     sk_gso_max_segs;
        int                     sk_rcvlowat;
        unsigned long           sk_lingertime;
        struct sk_buff_head     sk_error_queue;
index e19124b84cd2a299a28737e60e1e0346efe24c2f..1f000ffe70758c0596b8c4d18230e781b88f495f 100644 (file)
@@ -464,6 +464,7 @@ extern int tcp_disconnect(struct sock *sk, int flags);
 void tcp_connect_init(struct sock *sk);
 void tcp_finish_connect(struct sock *sk, struct sk_buff *skb);
 int tcp_send_rcvq(struct sock *sk, struct msghdr *msg, size_t size);
+void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb);
 
 /* From syncookies.c */
 extern __u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS];
index d9509eb29b80f989eb47531877279ae93f31f85c..5e1662dbb83c18c0545b15152c0d2d394b9f2d5c 100644 (file)
@@ -213,6 +213,9 @@ struct xfrm_state {
        struct xfrm_lifetime_cur curlft;
        struct tasklet_hrtimer  mtimer;
 
+       /* used to fix curlft->add_time when changing date */
+       long            saved_tmo;
+
        /* Last used time */
        unsigned long           lastused;
 
@@ -238,6 +241,7 @@ static inline struct net *xs_net(struct xfrm_state *x)
 
 /* xflags - make enum if more show up */
 #define XFRM_TIME_DEFER        1
+#define XFRM_SOFT_EXPIRE 2
 
 enum {
        XFRM_STATE_VOID,
@@ -567,7 +571,7 @@ struct xfrm_mgr {
        struct list_head        list;
        char                    *id;
        int                     (*notify)(struct xfrm_state *x, const struct km_event *c);
-       int                     (*acquire)(struct xfrm_state *x, struct xfrm_tmpl *, struct xfrm_policy *xp, int dir);
+       int                     (*acquire)(struct xfrm_state *x, struct xfrm_tmpl *, struct xfrm_policy *xp);
        struct xfrm_policy      *(*compile_policy)(struct sock *sk, int opt, u8 *data, int len, int *dir);
        int                     (*new_mapping)(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport);
        int                     (*notify_policy)(struct xfrm_policy *x, int dir, const struct km_event *c);
index ae33706afeb06eb24976c70f7d04ea047486939a..ef937b56f9b54c44e4003d762eaa7105534077da 100644 (file)
@@ -79,7 +79,8 @@ enum phy_event {
        PHYE_OOB_DONE         = 1,
        PHYE_OOB_ERROR        = 2,
        PHYE_SPINUP_HOLD      = 3, /* hot plug SATA, no COMWAKE sent */
-       PHY_NUM_EVENTS        = 4,
+       PHYE_RESUME_TIMEOUT   = 4,
+       PHY_NUM_EVENTS        = 5,
 };
 
 enum discover_event {
@@ -87,8 +88,10 @@ enum discover_event {
        DISCE_REVALIDATE_DOMAIN = 1,
        DISCE_PORT_GONE         = 2,
        DISCE_PROBE             = 3,
-       DISCE_DESTRUCT          = 4,
-       DISC_NUM_EVENTS         = 5,
+       DISCE_SUSPEND           = 4,
+       DISCE_RESUME            = 5,
+       DISCE_DESTRUCT          = 6,
+       DISC_NUM_EVENTS         = 7,
 };
 
 /* ---------- Expander Devices ---------- */
@@ -128,7 +131,7 @@ struct ex_phy {
        u8   attached_sas_addr[SAS_ADDR_SIZE];
        u8   attached_phy_id;
 
-       u8   phy_change_count;
+       int phy_change_count;
        enum routing_attribute routing_attr;
        u8   virtual:1;
 
@@ -141,7 +144,7 @@ struct ex_phy {
 struct expander_device {
        struct list_head children;
 
-       u16    ex_change_count;
+       int    ex_change_count;
        u16    max_route_indexes;
        u8     num_phys;
 
@@ -169,6 +172,7 @@ struct sata_device {
         enum   ata_command_set command_set;
         struct smp_resp        rps_resp; /* report_phy_sata_resp */
         u8     port_no;        /* port number, if this is a PM (Port) */
+       int    pm_result;
 
        struct ata_port *ap;
        struct ata_host ata_host;
@@ -182,6 +186,7 @@ struct ssp_device {
 
 enum {
        SAS_DEV_GONE,
+       SAS_DEV_FOUND, /* device notified to lldd */
        SAS_DEV_DESTROY,
        SAS_DEV_EH_PENDING,
        SAS_DEV_LU_RESET,
@@ -273,6 +278,7 @@ struct asd_sas_port {
        enum   sas_linkrate linkrate;
 
        struct sas_work work;
+       int suspended;
 
 /* public: */
        int id;
@@ -321,6 +327,7 @@ struct asd_sas_phy {
        unsigned long phy_events_pending;
 
        int error;
+       int suspended;
 
        struct sas_phy *phy;
 
@@ -687,6 +694,9 @@ struct sas_domain_function_template {
 
 extern int sas_register_ha(struct sas_ha_struct *);
 extern int sas_unregister_ha(struct sas_ha_struct *);
+extern void sas_prep_resume_ha(struct sas_ha_struct *sas_ha);
+extern void sas_resume_ha(struct sas_ha_struct *sas_ha);
+extern void sas_suspend_ha(struct sas_ha_struct *sas_ha);
 
 int sas_set_phy_speed(struct sas_phy *phy,
                      struct sas_phy_linkrates *rates);
index 2dfbdaa0b34a8b64cf94e22ec2a5f21bdc0990a9..ff71a56546845f2e29266ecf466ecd6d7174f38a 100644 (file)
@@ -45,6 +45,8 @@ void sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q,
 void sas_ata_schedule_reset(struct domain_device *dev);
 void sas_ata_wait_eh(struct domain_device *dev);
 void sas_probe_sata(struct asd_sas_port *port);
+void sas_suspend_sata(struct asd_sas_port *port);
+void sas_resume_sata(struct asd_sas_port *port);
 void sas_ata_end_eh(struct ata_port *ap);
 #else
 
@@ -82,6 +84,14 @@ static inline void sas_probe_sata(struct asd_sas_port *port)
 {
 }
 
+static inline void sas_suspend_sata(struct asd_sas_port *port)
+{
+}
+
+static inline void sas_resume_sata(struct asd_sas_port *port)
+{
+}
+
 static inline int sas_get_ata_info(struct domain_device *dev, struct ex_phy *phy)
 {
        return 0;
index 4f865df42f0f9daf2e078b6a26c1b108638454ba..1a33f48ebe7875f6ae6b6769583646a2e501dae9 100644 (file)
@@ -1788,7 +1788,7 @@ struct snd_emu10k1 {
        unsigned int efx_voices_mask[2];
        unsigned int next_free_voice;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        unsigned int *saved_ptr;
        unsigned int *saved_gpr;
        unsigned int *tram_val_saved;
@@ -1856,7 +1856,7 @@ unsigned short snd_emu10k1_ac97_read(struct snd_ac97 *ac97, unsigned short reg);
 void snd_emu10k1_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short data);
 unsigned int snd_emu10k1_rate_to_pitch(unsigned int rate);
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 void snd_emu10k1_suspend_regs(struct snd_emu10k1 *emu);
 void snd_emu10k1_resume_init(struct snd_emu10k1 *emu);
 void snd_emu10k1_resume_regs(struct snd_emu10k1 *emu);
index f99a0d2ddfe7b9e4e099fc386161be546a08fca4..ac62c67e6f4273ce361dd8b216b2cf05a07583e0 100644 (file)
 #define SNDRV_DEFAULT_DMA_SIZE { [0 ... (SNDRV_CARDS-1)] = SNDRV_AUTO_DMA_SIZE }
 #define SNDRV_DEFAULT_PTR      SNDRV_DEFAULT_STR
 
+#ifdef SNDRV_LEGACY_FIND_FREE_IOPORT
+static long snd_legacy_find_free_ioport(long *port_table, long size)
+{
+       while (*port_table != -1) {
+               if (request_region(*port_table, size, "ALSA test")) {
+                       release_region(*port_table, size);
+                       return *port_table;
+               }
+               port_table++;
+       }
+       return -1;
+}
+#endif
+
 #ifdef SNDRV_LEGACY_FIND_FREE_IRQ
 #include <linux/interrupt.h>
 
index ea7a2035456d4f913e15b9997696ab5ca4934ad1..5a8671e8a67ff8fa8f715311300901181555d78e 100644 (file)
@@ -73,6 +73,9 @@ DECLARE_EVENT_CLASS(sched_wakeup_template,
                __entry->prio           = p->prio;
                __entry->success        = success;
                __entry->target_cpu     = task_cpu(p);
+       )
+       TP_perf_assign(
+               __perf_task(p);
        ),
 
        TP_printk("comm=%s pid=%d prio=%d success=%d target_cpu=%03d",
@@ -325,6 +328,7 @@ DECLARE_EVENT_CLASS(sched_stat_template,
        )
        TP_perf_assign(
                __perf_count(delay);
+               __perf_task(tsk);
        ),
 
        TP_printk("comm=%s pid=%d delay=%Lu [ns]",
index c6bc2faaf2611533b1b2a72e6d3e191fa6033616..a763888a36f961339d5a437190c1c944077f875f 100644 (file)
@@ -712,6 +712,9 @@ __attribute__((section("_ftrace_events"))) *__event_##call = &event_##call
 #undef __perf_count
 #define __perf_count(c) __count = (c)
 
+#undef __perf_task
+#define __perf_task(t) __task = (t)
+
 #undef TP_perf_assign
 #define TP_perf_assign(args...) args
 
@@ -725,6 +728,7 @@ perf_trace_##call(void *__data, proto)                                      \
        struct ftrace_raw_##call *entry;                                \
        struct pt_regs __regs;                                          \
        u64 __addr = 0, __count = 1;                                    \
+       struct task_struct *__task = NULL;                              \
        struct hlist_head *head;                                        \
        int __entry_size;                                               \
        int __data_size;                                                \
@@ -752,7 +756,7 @@ perf_trace_##call(void *__data, proto)                                      \
                                                                        \
        head = this_cpu_ptr(event_call->perf_events);                   \
        perf_trace_buf_submit(entry, __entry_size, rctx, __addr,        \
-               __count, &__regs, head);                                \
+               __count, &__regs, head, __task);                        \
 }
 
 /*
index af6c7f8ba019ae25519f858850b2637b1fc76c8e..c26b8a1d2b576f8b0286168bbed0647a7ded67a1 100644 (file)
@@ -441,6 +441,24 @@ config PREEMPT_RCU
          This option enables preemptible-RCU code that is common between
          the TREE_PREEMPT_RCU and TINY_PREEMPT_RCU implementations.
 
+config RCU_USER_QS
+       bool "Consider userspace as in RCU extended quiescent state"
+       depends on HAVE_RCU_USER_QS && SMP
+       help
+         This option sets hooks on kernel / userspace boundaries and
+         puts RCU in extended quiescent state when the CPU runs in
+         userspace. It means that when a CPU runs in userspace, it is
+         excluded from the global RCU state machine and thus doesn't
+         to keep the timer tick on for RCU.
+
+config RCU_USER_QS_FORCE
+       bool "Force userspace extended QS by default"
+       depends on RCU_USER_QS
+       help
+         Set the hooks in user/kernel boundaries by default in order to
+         test this feature that treats userspace as an extended quiescent
+         state until we have a real user like a full adaptive nohz option.
+
 config RCU_FANOUT
        int "Tree-based hierarchical RCU fanout value"
        range 2 64 if 64BIT
index 3a5ca582ba1ebe2373803bfbf1887357d05b523e..4397ab35149e6ee6121b1553ff313d03e7e21d5e 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);
                fsnotify_put_mark(entry);
                goto out;
        }
@@ -292,7 +292,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(entry);
        goto out;
 
@@ -332,7 +332,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,7 +443,7 @@ 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(old_entry); /* pair to fsnotify_find mark_entry */
        fsnotify_put_mark(old_entry); /* and kill it */
        return 0;
index 3823281401b57e423f9a4ba9255b5904920e7e1d..a66affc1c12c26db52b3f1ea6dd9c2f22f4fc04f 100644 (file)
@@ -349,7 +349,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. */
@@ -456,7 +456,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 8b68ce78ff170b8777be887a3bc8407c59863ba5..be7b33b73d3001eef1b676ad1efde4f318824902 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/kdb.h>
 #include <linux/kdebug.h>
 #include <linux/export.h>
+#include <linux/hardirq.h>
 #include "kdb_private.h"
 #include "../debug_core.h"
 
@@ -52,6 +53,9 @@ int kdb_stub(struct kgdb_state *ks)
        if (atomic_read(&kgdb_setting_breakpoint))
                reason = KDB_REASON_KEYBOARD;
 
+       if (in_nmi())
+               reason = KDB_REASON_NMI;
+
        for (i = 0, bp = kdb_breakpoints; i < KDB_MAXBPT; i++, bp++) {
                if ((bp->bp_enabled) && (bp->bp_addr == addr)) {
                        reason = KDB_REASON_BREAK;
index bb9520f0f6ff8e607d0b08b2561efa62f4ba3b8d..0a69d2adc4f3cb7fb49a14c3ccefb87cfe0084bd 100644 (file)
@@ -715,9 +715,6 @@ kdb_printit:
        /* check for having reached the LINES number of printed lines */
        if (kdb_nextline == linecount) {
                char buf1[16] = "";
-#if defined(CONFIG_SMP)
-               char buf2[32];
-#endif
 
                /* Watch out for recursion here.  Any routine that calls
                 * kdb_printf will come back through here.  And kdb_read
@@ -732,14 +729,6 @@ kdb_printit:
                if (moreprompt == NULL)
                        moreprompt = "more> ";
 
-#if defined(CONFIG_SMP)
-               if (strchr(moreprompt, '%')) {
-                       sprintf(buf2, moreprompt, get_cpu());
-                       put_cpu();
-                       moreprompt = buf2;
-               }
-#endif
-
                kdb_input_flush();
                c = console_drivers;
 
index 1f91413edb87d0c9b77efc4e84c9b2f9729e9b8c..31df1706b9a9344bf3d63a1b0146987378060ed4 100644 (file)
@@ -139,11 +139,10 @@ static const int __nkdb_err = sizeof(kdbmsgs) / sizeof(kdbmsg_t);
 static char *__env[] = {
 #if defined(CONFIG_SMP)
  "PROMPT=[%d]kdb> ",
- "MOREPROMPT=[%d]more> ",
 #else
  "PROMPT=kdb> ",
- "MOREPROMPT=more> ",
 #endif
+ "MOREPROMPT=more> ",
  "RADIX=16",
  "MDCOUNT=8",                  /* lines of md output */
  KDB_PLATFORM_ENV,
@@ -1236,18 +1235,6 @@ static int kdb_local(kdb_reason_t reason, int error, struct pt_regs *regs,
                *cmdbuf = '\0';
                *(cmd_hist[cmd_head]) = '\0';
 
-               if (KDB_FLAG(ONLY_DO_DUMP)) {
-                       /* kdb is off but a catastrophic error requires a dump.
-                        * Take the dump and reboot.
-                        * Turn on logging so the kdb output appears in the log
-                        * buffer in the dump.
-                        */
-                       const char *setargs[] = { "set", "LOGGING", "1" };
-                       kdb_set(2, setargs);
-                       kdb_reboot(0, NULL);
-                       /*NOTREACHED*/
-               }
-
 do_full_getstr:
 #if defined(CONFIG_SMP)
                snprintf(kdb_prompt_str, CMD_BUFLEN, kdbgetenv("PROMPT"),
index 6581a040f39926dd46878640413bfd180922415a..98d4597f43d69e35a76535fac7d0bb6821ebdf7f 100644 (file)
@@ -153,7 +153,8 @@ put_callchain_entry(int rctx)
        put_recursion_context(__get_cpu_var(callchain_recursion), rctx);
 }
 
-struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
+struct perf_callchain_entry *
+perf_callchain(struct perf_event *event, struct pt_regs *regs)
 {
        int rctx;
        struct perf_callchain_entry *entry;
@@ -178,6 +179,12 @@ struct perf_callchain_entry *perf_callchain(struct pt_regs *regs)
        }
 
        if (regs) {
+               /*
+                * Disallow cross-task user callchains.
+                */
+               if (event->ctx->task && event->ctx->task != current)
+                       goto exit_put;
+
                perf_callchain_store(entry, PERF_CONTEXT_USER);
                perf_callchain_user(entry, regs);
        }
index f1cf0edeb39afa1a3f6543a2f383ac8c4828127b..b7935fcec7d923b0b0b89fe0fe7dfdf61967b447 100644 (file)
@@ -4039,7 +4039,7 @@ void perf_prepare_sample(struct perf_event_header *header,
        if (sample_type & PERF_SAMPLE_CALLCHAIN) {
                int size = 1;
 
-               data->callchain = perf_callchain(regs);
+               data->callchain = perf_callchain(event, regs);
 
                if (data->callchain)
                        size += data->callchain->nr;
@@ -5209,7 +5209,8 @@ static int perf_tp_event_match(struct perf_event *event,
 }
 
 void perf_tp_event(u64 addr, u64 count, void *record, int entry_size,
-                  struct pt_regs *regs, struct hlist_head *head, int rctx)
+                  struct pt_regs *regs, struct hlist_head *head, int rctx,
+                  struct task_struct *task)
 {
        struct perf_sample_data data;
        struct perf_event *event;
@@ -5228,6 +5229,31 @@ void perf_tp_event(u64 addr, u64 count, void *record, int entry_size,
                        perf_swevent_event(event, count, &data, regs);
        }
 
+       /*
+        * If we got specified a target task, also iterate its context and
+        * deliver this event there too.
+        */
+       if (task && task != current) {
+               struct perf_event_context *ctx;
+               struct trace_entry *entry = record;
+
+               rcu_read_lock();
+               ctx = rcu_dereference(task->perf_event_ctxp[perf_sw_context]);
+               if (!ctx)
+                       goto unlock;
+
+               list_for_each_entry_rcu(event, &ctx->event_list, event_entry) {
+                       if (event->attr.type != PERF_TYPE_TRACEPOINT)
+                               continue;
+                       if (event->attr.config != entry->type)
+                               continue;
+                       if (perf_tp_event_match(event, &data, regs))
+                               perf_swevent_event(event, count, &data, regs);
+               }
+unlock:
+               rcu_read_unlock();
+       }
+
        perf_swevent_put_recursion_context(rctx);
 }
 EXPORT_SYMBOL_GPL(perf_tp_event);
index b0b107f90afc983a0a7abd4b2f0f9519670f2275..a096c19f2c2a1aba50b62df4b91618cdcdb276d9 100644 (file)
@@ -101,7 +101,8 @@ __output_copy(struct perf_output_handle *handle,
 }
 
 /* Callchain handling */
-extern struct perf_callchain_entry *perf_callchain(struct pt_regs *regs);
+extern struct perf_callchain_entry *
+perf_callchain(struct perf_event *event, struct pt_regs *regs);
 extern int get_callchain_buffers(void);
 extern void put_callchain_buffers(void);
 
index e2b0fb9a0b3b3d0d5871ee37bf08618a6bf052e7..3717e7b306e08c0e8c2d3a66219c3cae13176d99 100644 (file)
@@ -2231,11 +2231,11 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,
  * @uaddr2:    the pi futex we will take prior to returning to user-space
  *
  * The caller will wait on uaddr and will be requeued by futex_requeue() to
- * uaddr2 which must be PI aware.  Normal wakeup will wake on uaddr2 and
- * complete the acquisition of the rt_mutex prior to returning to userspace.
- * This ensures the rt_mutex maintains an owner when it has waiters; without
- * one, the pi logic wouldn't know which task to boost/deboost, if there was a
- * need to.
+ * uaddr2 which must be PI aware and unique from uaddr.  Normal wakeup will wake
+ * on uaddr2 and complete the acquisition of the rt_mutex prior to returning to
+ * userspace.  This ensures the rt_mutex maintains an owner when it has waiters;
+ * without one, the pi logic would not know which task to boost/deboost, if
+ * there was a need to.
  *
  * We call schedule in futex_wait_queue_me() when we enqueue and return there
  * via the following:
@@ -2272,6 +2272,9 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
        struct futex_q q = futex_q_init;
        int res, ret;
 
+       if (uaddr == uaddr2)
+               return -EINVAL;
+
        if (!bitset)
                return -EINVAL;
 
@@ -2343,7 +2346,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
                 * signal.  futex_unlock_pi() will not destroy the lock_ptr nor
                 * the pi_state.
                 */
-               WARN_ON(!&q.pi_state);
+               WARN_ON(!q.pi_state);
                pi_mutex = &q.pi_state->pi_mutex;
                ret = rt_mutex_finish_proxy_lock(pi_mutex, to, &rt_waiter, 1);
                debug_rt_mutex_free_waiter(&rt_waiter);
@@ -2370,7 +2373,7 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
         * fault, unlock the rt_mutex and return the fault to userspace.
         */
        if (ret == -EFAULT) {
-               if (rt_mutex_owner(pi_mutex) == current)
+               if (pi_mutex && rt_mutex_owner(pi_mutex) == current)
                        rt_mutex_unlock(pi_mutex);
        } else if (ret == -EINTR) {
                /*
index 0a8e8f059627dec4ee56bab79849e0f86372d3b5..4c69326aa773f6469b7170d66814d7480ea12ea7 100644 (file)
@@ -943,6 +943,18 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
                goto out_thread;
        }
 
+       /*
+        * Drivers are often written to work w/o knowledge about the
+        * underlying irq chip implementation, so a request for a
+        * threaded irq without a primary hard irq context handler
+        * requires the ONESHOT flag to be set. Some irq chips like
+        * MSI based interrupts are per se one shot safe. Check the
+        * chip flags, so we can avoid the unmask dance at the end of
+        * the threaded handler for those.
+        */
+       if (desc->irq_data.chip->flags & IRQCHIP_ONESHOT_SAFE)
+               new->flags &= ~IRQF_ONESHOT;
+
        /*
         * The following block of code has to be executed atomically
         */
@@ -1017,7 +1029,8 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
                 */
                new->thread_mask = 1 << ffz(thread_mask);
 
-       } else if (new->handler == irq_default_primary_handler) {
+       } else if (new->handler == irq_default_primary_handler &&
+                  !(desc->irq_data.chip->flags & IRQCHIP_ONESHOT_SAFE)) {
                /*
                 * The interrupt was requested with handler = NULL, so
                 * we use the default primary handler for it. But it
index 43049192b5ec9bcb57863b3729b3cb6ac18b8d0c..60f48fa0fd0dddf57b7e4ae80a2d45816923b6ce 100644 (file)
@@ -118,6 +118,7 @@ void jump_label_rate_limit(struct static_key_deferred *key,
        key->timeout = rl;
        INIT_DELAYED_WORK(&key->work, jump_label_update_timeout);
 }
+EXPORT_SYMBOL_GPL(jump_label_rate_limit);
 
 static int addr_conflict(struct jump_entry *entry, void *start, void *end)
 {
index 4edbd9c11aca35a71e56bc237ef638d596a7db23..7f2ee45f362c5a59de4c07a24ff52507451421ce 100644 (file)
@@ -1949,26 +1949,6 @@ static int simplify_symbols(struct module *mod, const struct load_info *info)
        return ret;
 }
 
-int __weak apply_relocate(Elf_Shdr *sechdrs,
-                         const char *strtab,
-                         unsigned int symindex,
-                         unsigned int relsec,
-                         struct module *me)
-{
-       pr_err("module %s: REL relocation unsupported\n", me->name);
-       return -ENOEXEC;
-}
-
-int __weak apply_relocate_add(Elf_Shdr *sechdrs,
-                             const char *strtab,
-                             unsigned int symindex,
-                             unsigned int relsec,
-                             struct module *me)
-{
-       pr_err("module %s: RELA relocation unsupported\n", me->name);
-       return -ENOEXEC;
-}
-
 static int apply_relocations(struct module *mod, const struct load_info *info)
 {
        unsigned int i;
@@ -2730,6 +2710,10 @@ static int check_module_license_and_versions(struct module *mod)
        if (strcmp(mod->name, "driverloader") == 0)
                add_taint_module(mod, TAINT_PROPRIETARY_MODULE);
 
+       /* lve claims to be GPL but upstream won't provide source */
+       if (strcmp(mod->name, "lve") == 0)
+               add_taint_module(mod, TAINT_PROPRIETARY_MODULE);
+
 #ifdef CONFIG_MODVERSIONS
        if ((mod->num_syms && !mod->crcs)
            || (mod->num_gpl_syms && !mod->gpl_crcs)
index a70518c9d82f42c57eb400208ce95dd4dd2aafaa..5dfdc9ea180b8ac497ed915c45b809fb65799261 100644 (file)
@@ -263,6 +263,10 @@ config PM_GENERIC_DOMAINS
        bool
        depends on PM
 
+config PM_GENERIC_DOMAINS_SLEEP
+       def_bool y
+       depends on PM_SLEEP && PM_GENERIC_DOMAINS
+
 config PM_GENERIC_DOMAINS_RUNTIME
        def_bool y
        depends on PM_RUNTIME && PM_GENERIC_DOMAINS
index 1da39ea248fdf3bee6f16f536693b0daad10afbe..c8b7446b27dfc21add10f610e1692a2f3acee7ed 100644 (file)
@@ -178,9 +178,6 @@ static int suspend_enter(suspend_state_t state, bool *wakeup)
        arch_suspend_enable_irqs();
        BUG_ON(irqs_disabled());
 
-       /* Kick the lockup detector */
-       lockup_detector_bootcpu_resume();
-
  Enable_cpus:
        enable_nonboot_cpus();
 
index 6a76ab9d4476466b5ba3b3e37d38aadbb2e02644..66a2ea37b5763b450929a5f955e3bc81ad130a1c 100644 (file)
@@ -1034,6 +1034,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
                        struct log *msg = log_from_idx(idx);
 
                        len += msg_print_text(msg, prev, true, NULL, 0);
+                       prev = msg->flags;
                        idx = log_next(idx);
                        seq++;
                }
@@ -1046,6 +1047,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
                        struct log *msg = log_from_idx(idx);
 
                        len -= msg_print_text(msg, prev, true, NULL, 0);
+                       prev = msg->flags;
                        idx = log_next(idx);
                        seq++;
                }
index a232bb59d93fa220e3720ce3d068b44d96ca24f3..1f5e55dda955544ca4a3f1f944e967f6b561bea2 100644 (file)
@@ -180,7 +180,8 @@ static int ptrace_has_cap(struct user_namespace *ns, unsigned int mode)
                return has_ns_capability(current, ns, CAP_SYS_PTRACE);
 }
 
-int __ptrace_may_access(struct task_struct *task, unsigned int mode)
+/* Returns 0 on success, -errno on denial. */
+static int __ptrace_may_access(struct task_struct *task, unsigned int mode)
 {
        const struct cred *cred = current_cred(), *tcred;
 
index 4e6a61b15e86fe0e27fc30d80775de4f4c8c47e6..29ca1c6da59496133947e5a1c3d1a860ef261e3e 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/mutex.h>
 #include <linux/export.h>
 #include <linux/hardirq.h>
+#include <linux/delay.h>
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/rcu.h>
@@ -81,6 +82,9 @@ void __rcu_read_unlock(void)
        } else {
                barrier();  /* critical section before exit code. */
                t->rcu_read_lock_nesting = INT_MIN;
+#ifdef CONFIG_PROVE_RCU_DELAY
+               udelay(10); /* Make preemption more probable. */
+#endif /* #ifdef CONFIG_PROVE_RCU_DELAY */
                barrier();  /* assign before ->rcu_read_unlock_special load */
                if (unlikely(ACCESS_ONCE(t->rcu_read_unlock_special)))
                        rcu_read_unlock_special(t);
index 547b1fe5b052c4000a3747c58c3852aa618ae184..aee6df828e0924926080520466c6ca1eee9e5352 100644 (file)
@@ -56,24 +56,27 @@ static void __call_rcu(struct rcu_head *head,
 static long long rcu_dynticks_nesting = DYNTICK_TASK_EXIT_IDLE;
 
 /* Common code for rcu_idle_enter() and rcu_irq_exit(), see kernel/rcutree.c. */
-static void rcu_idle_enter_common(long long oldval)
+static void rcu_idle_enter_common(long long newval)
 {
        if (rcu_dynticks_nesting) {
                RCU_TRACE(trace_rcu_dyntick("--=",
-                                           oldval, rcu_dynticks_nesting));
+                                           rcu_dynticks_nesting, newval));
+               rcu_dynticks_nesting = newval;
                return;
        }
-       RCU_TRACE(trace_rcu_dyntick("Start", oldval, rcu_dynticks_nesting));
+       RCU_TRACE(trace_rcu_dyntick("Start", rcu_dynticks_nesting, newval));
        if (!is_idle_task(current)) {
                struct task_struct *idle = idle_task(smp_processor_id());
 
                RCU_TRACE(trace_rcu_dyntick("Error on entry: not idle task",
-                                           oldval, rcu_dynticks_nesting));
+                                           rcu_dynticks_nesting, newval));
                ftrace_dump(DUMP_ALL);
                WARN_ONCE(1, "Current pid: %d comm: %s / Idle pid: %d comm: %s",
                          current->pid, current->comm,
                          idle->pid, idle->comm); /* must be idle task! */
        }
+       barrier();
+       rcu_dynticks_nesting = newval;
        rcu_sched_qs(0); /* implies rcu_bh_qsctr_inc(0) */
 }
 
@@ -84,17 +87,16 @@ static void rcu_idle_enter_common(long long oldval)
 void rcu_idle_enter(void)
 {
        unsigned long flags;
-       long long oldval;
+       long long newval;
 
        local_irq_save(flags);
-       oldval = rcu_dynticks_nesting;
        WARN_ON_ONCE((rcu_dynticks_nesting & DYNTICK_TASK_NEST_MASK) == 0);
        if ((rcu_dynticks_nesting & DYNTICK_TASK_NEST_MASK) ==
            DYNTICK_TASK_NEST_VALUE)
-               rcu_dynticks_nesting = 0;
+               newval = 0;
        else
-               rcu_dynticks_nesting  -= DYNTICK_TASK_NEST_VALUE;
-       rcu_idle_enter_common(oldval);
+               newval = rcu_dynticks_nesting - DYNTICK_TASK_NEST_VALUE;
+       rcu_idle_enter_common(newval);
        local_irq_restore(flags);
 }
 EXPORT_SYMBOL_GPL(rcu_idle_enter);
@@ -105,15 +107,15 @@ EXPORT_SYMBOL_GPL(rcu_idle_enter);
 void rcu_irq_exit(void)
 {
        unsigned long flags;
-       long long oldval;
+       long long newval;
 
        local_irq_save(flags);
-       oldval = rcu_dynticks_nesting;
-       rcu_dynticks_nesting--;
-       WARN_ON_ONCE(rcu_dynticks_nesting < 0);
-       rcu_idle_enter_common(oldval);
+       newval = rcu_dynticks_nesting - 1;
+       WARN_ON_ONCE(newval < 0);
+       rcu_idle_enter_common(newval);
        local_irq_restore(flags);
 }
+EXPORT_SYMBOL_GPL(rcu_irq_exit);
 
 /* Common code for rcu_idle_exit() and rcu_irq_enter(), see kernel/rcutree.c. */
 static void rcu_idle_exit_common(long long oldval)
@@ -171,6 +173,7 @@ void rcu_irq_enter(void)
        rcu_idle_exit_common(oldval);
        local_irq_restore(flags);
 }
+EXPORT_SYMBOL_GPL(rcu_irq_enter);
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 
index 25b15033c61f88ff7d76854fd16401779d9d9f62..c6cf6ff6ba8d492f556b90d5b722e5152708ed46 100644 (file)
@@ -53,10 +53,10 @@ MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com> and Josh Triplett <josh@fre
 
 static int nreaders = -1;      /* # reader threads, defaults to 2*ncpus */
 static int nfakewriters = 4;   /* # fake writer threads */
-static int stat_interval;      /* Interval between stats, in seconds. */
+static int stat_interval = 60; /* Interval between stats, in seconds. */
                                /*  Defaults to "only at end of test". */
 static bool verbose;           /* Print more debug info. */
-static bool test_no_idle_hz;   /* Test RCU's support for tickless idle CPUs. */
+static bool test_no_idle_hz = 1; /* Test RCU support for tickless idle CPUs. */
 static int shuffle_interval = 3; /* Interval between shuffles (in sec)*/
 static int stutter = 5;                /* Start/stop testing interval (in sec) */
 static int irqreader = 1;      /* RCU readers from irq (timers). */
@@ -176,8 +176,14 @@ static long n_rcu_torture_boosts;
 static long n_rcu_torture_timers;
 static long n_offline_attempts;
 static long n_offline_successes;
+static unsigned long sum_offline;
+static int min_offline = -1;
+static int max_offline;
 static long n_online_attempts;
 static long n_online_successes;
+static unsigned long sum_online;
+static int min_online = -1;
+static int max_online;
 static long n_barrier_attempts;
 static long n_barrier_successes;
 static struct list_head rcu_torture_removed;
@@ -1214,11 +1220,13 @@ rcu_torture_printk(char *page)
                       n_rcu_torture_boost_failure,
                       n_rcu_torture_boosts,
                       n_rcu_torture_timers);
-       cnt += sprintf(&page[cnt], "onoff: %ld/%ld:%ld/%ld ",
-                      n_online_successes,
-                      n_online_attempts,
-                      n_offline_successes,
-                      n_offline_attempts);
+       cnt += sprintf(&page[cnt],
+                      "onoff: %ld/%ld:%ld/%ld %d,%d:%d,%d %lu:%lu (HZ=%d) ",
+                      n_online_successes, n_online_attempts,
+                      n_offline_successes, n_offline_attempts,
+                      min_online, max_online,
+                      min_offline, max_offline,
+                      sum_online, sum_offline, HZ);
        cnt += sprintf(&page[cnt], "barrier: %ld/%ld:%ld",
                       n_barrier_successes,
                       n_barrier_attempts,
@@ -1490,8 +1498,10 @@ static int __cpuinit
 rcu_torture_onoff(void *arg)
 {
        int cpu;
+       unsigned long delta;
        int maxcpu = -1;
        DEFINE_RCU_RANDOM(rand);
+       unsigned long starttime;
 
        VERBOSE_PRINTK_STRING("rcu_torture_onoff task started");
        for_each_online_cpu(cpu)
@@ -1509,6 +1519,7 @@ rcu_torture_onoff(void *arg)
                                printk(KERN_ALERT "%s" TORTURE_FLAG
                                       "rcu_torture_onoff task: offlining %d\n",
                                       torture_type, cpu);
+                       starttime = jiffies;
                        n_offline_attempts++;
                        if (cpu_down(cpu) == 0) {
                                if (verbose)
@@ -1516,12 +1527,23 @@ rcu_torture_onoff(void *arg)
                                               "rcu_torture_onoff task: offlined %d\n",
                                               torture_type, cpu);
                                n_offline_successes++;
+                               delta = jiffies - starttime;
+                               sum_offline += delta;
+                               if (min_offline < 0) {
+                                       min_offline = delta;
+                                       max_offline = delta;
+                               }
+                               if (min_offline > delta)
+                                       min_offline = delta;
+                               if (max_offline < delta)
+                                       max_offline = delta;
                        }
                } else if (cpu_is_hotpluggable(cpu)) {
                        if (verbose)
                                printk(KERN_ALERT "%s" TORTURE_FLAG
                                       "rcu_torture_onoff task: onlining %d\n",
                                       torture_type, cpu);
+                       starttime = jiffies;
                        n_online_attempts++;
                        if (cpu_up(cpu) == 0) {
                                if (verbose)
@@ -1529,6 +1551,16 @@ rcu_torture_onoff(void *arg)
                                               "rcu_torture_onoff task: onlined %d\n",
                                               torture_type, cpu);
                                n_online_successes++;
+                               delta = jiffies - starttime;
+                               sum_online += delta;
+                               if (min_online < 0) {
+                                       min_online = delta;
+                                       max_online = delta;
+                               }
+                               if (min_online > delta)
+                                       min_online = delta;
+                               if (max_online < delta)
+                                       max_online = delta;
                        }
                }
                schedule_timeout_interruptible(onoff_interval * HZ);
index f280e542e3e9f531df83b03d1e1fce6cf8ebaaa2..a3484892ca48bd080b00f0357df571ae9e0a9151 100644 (file)
@@ -52,6 +52,7 @@
 #include <linux/prefetch.h>
 #include <linux/delay.h>
 #include <linux/stop_machine.h>
+#include <linux/random.h>
 
 #include "rcutree.h"
 #include <trace/events/rcu.h>
@@ -61,6 +62,7 @@
 /* Data structures. */
 
 static struct lock_class_key rcu_node_class[RCU_NUM_LVLS];
+static struct lock_class_key rcu_fqs_class[RCU_NUM_LVLS];
 
 #define RCU_STATE_INITIALIZER(sname, cr) { \
        .level = { &sname##_state.node[0] }, \
@@ -72,7 +74,6 @@ static struct lock_class_key rcu_node_class[RCU_NUM_LVLS];
        .orphan_nxttail = &sname##_state.orphan_nxtlist, \
        .orphan_donetail = &sname##_state.orphan_donelist, \
        .barrier_mutex = __MUTEX_INITIALIZER(sname##_state.barrier_mutex), \
-       .fqslock = __RAW_SPIN_LOCK_UNLOCKED(&sname##_state.fqslock), \
        .name = #sname, \
 }
 
@@ -88,7 +89,7 @@ LIST_HEAD(rcu_struct_flavors);
 
 /* Increase (but not decrease) the CONFIG_RCU_FANOUT_LEAF at boot time. */
 static int rcu_fanout_leaf = CONFIG_RCU_FANOUT_LEAF;
-module_param(rcu_fanout_leaf, int, 0);
+module_param(rcu_fanout_leaf, int, 0444);
 int rcu_num_lvls __read_mostly = RCU_NUM_LVLS;
 static int num_rcu_lvl[] = {  /* Number of rcu_nodes at specified level. */
        NUM_RCU_LVL_0,
@@ -210,15 +211,18 @@ EXPORT_SYMBOL_GPL(rcu_note_context_switch);
 DEFINE_PER_CPU(struct rcu_dynticks, rcu_dynticks) = {
        .dynticks_nesting = DYNTICK_TASK_EXIT_IDLE,
        .dynticks = ATOMIC_INIT(1),
+#if defined(CONFIG_RCU_USER_QS) && !defined(CONFIG_RCU_USER_QS_FORCE)
+       .ignore_user_qs = true,
+#endif
 };
 
 static int blimit = 10;                /* Maximum callbacks per rcu_do_batch. */
 static int qhimark = 10000;    /* If this many pending, ignore blimit. */
 static int qlowmark = 100;     /* Once only this many pending, use blimit. */
 
-module_param(blimit, int, 0);
-module_param(qhimark, int, 0);
-module_param(qlowmark, int, 0);
+module_param(blimit, int, 0444);
+module_param(qhimark, int, 0444);
+module_param(qlowmark, int, 0444);
 
 int rcu_cpu_stall_suppress __read_mostly; /* 1 = suppress stall warnings. */
 int rcu_cpu_stall_timeout __read_mostly = CONFIG_RCU_CPU_STALL_TIMEOUT;
@@ -226,7 +230,14 @@ 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 void force_quiescent_state(struct rcu_state *rsp, int relaxed);
+static ulong jiffies_till_first_fqs = RCU_JIFFIES_TILL_FORCE_QS;
+static ulong jiffies_till_next_fqs = RCU_JIFFIES_TILL_FORCE_QS;
+
+module_param(jiffies_till_first_fqs, ulong, 0644);
+module_param(jiffies_till_next_fqs, ulong, 0644);
+
+static void force_qs_rnp(struct rcu_state *rsp, int (*f)(struct rcu_data *));
+static void force_quiescent_state(struct rcu_state *rsp);
 static int rcu_pending(int cpu);
 
 /*
@@ -252,7 +263,7 @@ EXPORT_SYMBOL_GPL(rcu_batches_completed_bh);
  */
 void rcu_bh_force_quiescent_state(void)
 {
-       force_quiescent_state(&rcu_bh_state, 0);
+       force_quiescent_state(&rcu_bh_state);
 }
 EXPORT_SYMBOL_GPL(rcu_bh_force_quiescent_state);
 
@@ -286,7 +297,7 @@ EXPORT_SYMBOL_GPL(rcutorture_record_progress);
  */
 void rcu_sched_force_quiescent_state(void)
 {
-       force_quiescent_state(&rcu_sched_state, 0);
+       force_quiescent_state(&rcu_sched_state);
 }
 EXPORT_SYMBOL_GPL(rcu_sched_force_quiescent_state);
 
@@ -317,45 +328,17 @@ static struct rcu_node *rcu_get_root(struct rcu_state *rsp)
 }
 
 /*
- * If the specified CPU is offline, tell the caller that it is in
- * a quiescent state.  Otherwise, whack it with a reschedule IPI.
- * Grace periods can end up waiting on an offline CPU when that
- * CPU is in the process of coming online -- it will be added to the
- * rcu_node bitmasks before it actually makes it online.  The same thing
- * can happen while a CPU is in the process of coming online.  Because this
- * race is quite rare, we check for it after detecting that the grace
- * period has been delayed rather than checking each and every CPU
- * each and every time we start a new grace period.
- */
-static int rcu_implicit_offline_qs(struct rcu_data *rdp)
-{
-       /*
-        * If the CPU is offline for more than a jiffy, it is in a quiescent
-        * state.  We can trust its state not to change because interrupts
-        * are disabled.  The reason for the jiffy's worth of slack is to
-        * handle CPUs initializing on the way up and finding their way
-        * to the idle loop on the way down.
-        */
-       if (cpu_is_offline(rdp->cpu) &&
-           ULONG_CMP_LT(rdp->rsp->gp_start + 2, jiffies)) {
-               trace_rcu_fqs(rdp->rsp->name, rdp->gpnum, rdp->cpu, "ofl");
-               rdp->offline_fqs++;
-               return 1;
-       }
-       return 0;
-}
-
-/*
- * rcu_idle_enter_common - inform RCU that current CPU is moving towards idle
+ * rcu_eqs_enter_common - current CPU is moving towards extended quiescent state
  *
  * If the new value of the ->dynticks_nesting counter now is zero,
  * we really have entered idle, and must do the appropriate accounting.
  * The caller must have disabled interrupts.
  */
-static void rcu_idle_enter_common(struct rcu_dynticks *rdtp, long long oldval)
+static void rcu_eqs_enter_common(struct rcu_dynticks *rdtp, long long oldval,
+                               bool user)
 {
        trace_rcu_dyntick("Start", oldval, 0);
-       if (!is_idle_task(current)) {
+       if (!is_idle_task(current) && !user) {
                struct task_struct *idle = idle_task(smp_processor_id());
 
                trace_rcu_dyntick("Error on entry: not idle task", oldval, 0);
@@ -372,7 +355,7 @@ static void rcu_idle_enter_common(struct rcu_dynticks *rdtp, long long oldval)
        WARN_ON_ONCE(atomic_read(&rdtp->dynticks) & 0x1);
 
        /*
-        * The idle task is not permitted to enter the idle loop while
+        * It is illegal to enter an extended quiescent state while
         * in an RCU read-side critical section.
         */
        rcu_lockdep_assert(!lock_is_held(&rcu_lock_map),
@@ -383,6 +366,25 @@ static void rcu_idle_enter_common(struct rcu_dynticks *rdtp, long long oldval)
                           "Illegal idle entry in RCU-sched read-side critical section.");
 }
 
+/*
+ * Enter an RCU extended quiescent state, which can be either the
+ * idle loop or adaptive-tickless usermode execution.
+ */
+static void rcu_eqs_enter(bool user)
+{
+       long long oldval;
+       struct rcu_dynticks *rdtp;
+
+       rdtp = &__get_cpu_var(rcu_dynticks);
+       oldval = rdtp->dynticks_nesting;
+       WARN_ON_ONCE((oldval & DYNTICK_TASK_NEST_MASK) == 0);
+       if ((oldval & DYNTICK_TASK_NEST_MASK) == DYNTICK_TASK_NEST_VALUE)
+               rdtp->dynticks_nesting = 0;
+       else
+               rdtp->dynticks_nesting -= DYNTICK_TASK_NEST_VALUE;
+       rcu_eqs_enter_common(rdtp, oldval, user);
+}
+
 /**
  * rcu_idle_enter - inform RCU that current CPU is entering idle
  *
@@ -398,21 +400,60 @@ static void rcu_idle_enter_common(struct rcu_dynticks *rdtp, long long oldval)
 void rcu_idle_enter(void)
 {
        unsigned long flags;
-       long long oldval;
+
+       local_irq_save(flags);
+       rcu_eqs_enter(0);
+       local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(rcu_idle_enter);
+
+#ifdef CONFIG_RCU_USER_QS
+/**
+ * rcu_user_enter - inform RCU that we are resuming userspace.
+ *
+ * Enter RCU idle mode right before resuming userspace.  No use of RCU
+ * is permitted between this call and rcu_user_exit(). This way the
+ * CPU doesn't need to maintain the tick for RCU maintenance purposes
+ * when the CPU runs in userspace.
+ */
+void rcu_user_enter(void)
+{
+       unsigned long flags;
        struct rcu_dynticks *rdtp;
 
+       WARN_ON_ONCE(!current->mm);
+
        local_irq_save(flags);
        rdtp = &__get_cpu_var(rcu_dynticks);
-       oldval = rdtp->dynticks_nesting;
-       WARN_ON_ONCE((oldval & DYNTICK_TASK_NEST_MASK) == 0);
-       if ((oldval & DYNTICK_TASK_NEST_MASK) == DYNTICK_TASK_NEST_VALUE)
-               rdtp->dynticks_nesting = 0;
-       else
-               rdtp->dynticks_nesting -= DYNTICK_TASK_NEST_VALUE;
-       rcu_idle_enter_common(rdtp, oldval);
+       if (!rdtp->ignore_user_qs && !rdtp->in_user) {
+               rdtp->in_user = true;
+               rcu_eqs_enter(1);
+       }
        local_irq_restore(flags);
 }
-EXPORT_SYMBOL_GPL(rcu_idle_enter);
+EXPORT_SYMBOL_GPL(rcu_user_enter);
+
+/**
+ * rcu_user_enter_irq - inform RCU that we are going to resume userspace
+ * after the current irq returns.
+ *
+ * This is similar to rcu_user_enter() but in the context of a non-nesting
+ * irq. After this call, RCU enters into idle mode when the interrupt
+ * returns.
+ */
+void rcu_user_enter_irq(void)
+{
+       unsigned long flags;
+       struct rcu_dynticks *rdtp;
+
+       local_irq_save(flags);
+       rdtp = &__get_cpu_var(rcu_dynticks);
+       /* Ensure this irq is interrupting a non-idle RCU state.  */
+       WARN_ON_ONCE(!(rdtp->dynticks_nesting & DYNTICK_TASK_MASK));
+       rdtp->dynticks_nesting = 1;
+       local_irq_restore(flags);
+}
+#endif
 
 /**
  * rcu_irq_exit - inform RCU that current CPU is exiting irq towards idle
@@ -444,18 +485,20 @@ void rcu_irq_exit(void)
        if (rdtp->dynticks_nesting)
                trace_rcu_dyntick("--=", oldval, rdtp->dynticks_nesting);
        else
-               rcu_idle_enter_common(rdtp, oldval);
+               rcu_eqs_enter_common(rdtp, oldval, 1);
        local_irq_restore(flags);
 }
+EXPORT_SYMBOL_GPL(rcu_irq_exit);
 
 /*
- * rcu_idle_exit_common - inform RCU that current CPU is moving away from idle
+ * rcu_eqs_exit_common - current CPU moving away from extended quiescent state
  *
  * If the new value of the ->dynticks_nesting counter was previously zero,
  * we really have exited idle, and must do the appropriate accounting.
  * The caller must have disabled interrupts.
  */
-static void rcu_idle_exit_common(struct rcu_dynticks *rdtp, long long oldval)
+static void rcu_eqs_exit_common(struct rcu_dynticks *rdtp, long long oldval,
+                              int user)
 {
        smp_mb__before_atomic_inc();  /* Force ordering w/previous sojourn. */
        atomic_inc(&rdtp->dynticks);
@@ -464,7 +507,7 @@ static void rcu_idle_exit_common(struct rcu_dynticks *rdtp, long long oldval)
        WARN_ON_ONCE(!(atomic_read(&rdtp->dynticks) & 0x1));
        rcu_cleanup_after_idle(smp_processor_id());
        trace_rcu_dyntick("End", oldval, rdtp->dynticks_nesting);
-       if (!is_idle_task(current)) {
+       if (!is_idle_task(current) && !user) {
                struct task_struct *idle = idle_task(smp_processor_id());
 
                trace_rcu_dyntick("Error on exit: not idle task",
@@ -476,6 +519,25 @@ static void rcu_idle_exit_common(struct rcu_dynticks *rdtp, long long oldval)
        }
 }
 
+/*
+ * Exit an RCU extended quiescent state, which can be either the
+ * idle loop or adaptive-tickless usermode execution.
+ */
+static void rcu_eqs_exit(bool user)
+{
+       struct rcu_dynticks *rdtp;
+       long long oldval;
+
+       rdtp = &__get_cpu_var(rcu_dynticks);
+       oldval = rdtp->dynticks_nesting;
+       WARN_ON_ONCE(oldval < 0);
+       if (oldval & DYNTICK_TASK_NEST_MASK)
+               rdtp->dynticks_nesting += DYNTICK_TASK_NEST_VALUE;
+       else
+               rdtp->dynticks_nesting = DYNTICK_TASK_EXIT_IDLE;
+       rcu_eqs_exit_common(rdtp, oldval, user);
+}
+
 /**
  * rcu_idle_exit - inform RCU that current CPU is leaving idle
  *
@@ -488,23 +550,59 @@ static void rcu_idle_exit_common(struct rcu_dynticks *rdtp, long long oldval)
  * now starting.
  */
 void rcu_idle_exit(void)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       rcu_eqs_exit(0);
+       local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(rcu_idle_exit);
+
+#ifdef CONFIG_RCU_USER_QS
+/**
+ * rcu_user_exit - inform RCU that we are exiting userspace.
+ *
+ * Exit RCU idle mode while entering the kernel because it can
+ * run a RCU read side critical section anytime.
+ */
+void rcu_user_exit(void)
 {
        unsigned long flags;
        struct rcu_dynticks *rdtp;
-       long long oldval;
 
        local_irq_save(flags);
        rdtp = &__get_cpu_var(rcu_dynticks);
-       oldval = rdtp->dynticks_nesting;
-       WARN_ON_ONCE(oldval < 0);
-       if (oldval & DYNTICK_TASK_NEST_MASK)
-               rdtp->dynticks_nesting += DYNTICK_TASK_NEST_VALUE;
-       else
-               rdtp->dynticks_nesting = DYNTICK_TASK_EXIT_IDLE;
-       rcu_idle_exit_common(rdtp, oldval);
+       if (rdtp->in_user) {
+               rdtp->in_user = false;
+               rcu_eqs_exit(1);
+       }
        local_irq_restore(flags);
 }
-EXPORT_SYMBOL_GPL(rcu_idle_exit);
+EXPORT_SYMBOL_GPL(rcu_user_exit);
+
+/**
+ * rcu_user_exit_irq - inform RCU that we won't resume to userspace
+ * idle mode after the current non-nesting irq returns.
+ *
+ * This is similar to rcu_user_exit() but in the context of an irq.
+ * This is called when the irq has interrupted a userspace RCU idle mode
+ * context. When the current non-nesting interrupt returns after this call,
+ * the CPU won't restore the RCU idle mode.
+ */
+void rcu_user_exit_irq(void)
+{
+       unsigned long flags;
+       struct rcu_dynticks *rdtp;
+
+       local_irq_save(flags);
+       rdtp = &__get_cpu_var(rcu_dynticks);
+       /* Ensure we are interrupting an RCU idle mode. */
+       WARN_ON_ONCE(rdtp->dynticks_nesting & DYNTICK_TASK_NEST_MASK);
+       rdtp->dynticks_nesting += DYNTICK_TASK_EXIT_IDLE;
+       local_irq_restore(flags);
+}
+#endif
 
 /**
  * rcu_irq_enter - inform RCU that current CPU is entering irq away from idle
@@ -539,9 +637,10 @@ void rcu_irq_enter(void)
        if (oldval)
                trace_rcu_dyntick("++=", oldval, rdtp->dynticks_nesting);
        else
-               rcu_idle_exit_common(rdtp, oldval);
+               rcu_eqs_exit_common(rdtp, oldval, 1);
        local_irq_restore(flags);
 }
+EXPORT_SYMBOL_GPL(rcu_irq_enter);
 
 /**
  * rcu_nmi_enter - inform RCU of entry to NMI context
@@ -603,6 +702,21 @@ int rcu_is_cpu_idle(void)
 }
 EXPORT_SYMBOL(rcu_is_cpu_idle);
 
+#ifdef CONFIG_RCU_USER_QS
+void rcu_user_hooks_switch(struct task_struct *prev,
+                          struct task_struct *next)
+{
+       struct rcu_dynticks *rdtp;
+
+       /* Interrupts are disabled in context switch */
+       rdtp = &__get_cpu_var(rcu_dynticks);
+       if (!rdtp->ignore_user_qs) {
+               clear_tsk_thread_flag(prev, TIF_NOHZ);
+               set_tsk_thread_flag(next, TIF_NOHZ);
+       }
+}
+#endif /* #ifdef CONFIG_RCU_USER_QS */
+
 #if defined(CONFIG_PROVE_RCU) && defined(CONFIG_HOTPLUG_CPU)
 
 /*
@@ -673,7 +787,7 @@ static int dyntick_save_progress_counter(struct rcu_data *rdp)
  * Return true if the specified CPU has passed through a quiescent
  * state by virtue of being in or having passed through an dynticks
  * idle state since the last call to dyntick_save_progress_counter()
- * for this same CPU.
+ * for this same CPU, or by virtue of having been offline.
  */
 static int rcu_implicit_dynticks_qs(struct rcu_data *rdp)
 {
@@ -697,8 +811,26 @@ static int rcu_implicit_dynticks_qs(struct rcu_data *rdp)
                return 1;
        }
 
-       /* Go check for the CPU being offline. */
-       return rcu_implicit_offline_qs(rdp);
+       /*
+        * Check for the CPU being offline, but only if the grace period
+        * is old enough.  We don't need to worry about the CPU changing
+        * state: If we see it offline even once, it has been through a
+        * quiescent state.
+        *
+        * The reason for insisting that the grace period be at least
+        * one jiffy old is that CPUs that are not quite online and that
+        * have just gone offline can still execute RCU read-side critical
+        * sections.
+        */
+       if (ULONG_CMP_GE(rdp->rsp->gp_start + 2, jiffies))
+               return 0;  /* Grace period is not old enough. */
+       barrier();
+       if (cpu_is_offline(rdp->cpu)) {
+               trace_rcu_fqs(rdp->rsp->name, rdp->gpnum, rdp->cpu, "ofl");
+               rdp->offline_fqs++;
+               return 1;
+       }
+       return 0;
 }
 
 static int jiffies_till_stall_check(void)
@@ -782,11 +914,11 @@ static void print_other_cpu_stall(struct rcu_state *rsp)
        else if (!trigger_all_cpu_backtrace())
                dump_stack();
 
-       /* If so configured, complain about tasks blocking the grace period. */
+       /* Complain about tasks blocking the grace period. */
 
        rcu_print_detail_task_stall(rsp);
 
-       force_quiescent_state(rsp, 0);  /* Kick them all. */
+       force_quiescent_state(rsp);  /* Kick them all. */
 }
 
 static void print_cpu_stall(struct rcu_state *rsp)
@@ -1021,97 +1153,57 @@ rcu_start_gp_per_cpu(struct rcu_state *rsp, struct rcu_node *rnp, struct rcu_dat
        /* Prior grace period ended, so advance callbacks for current CPU. */
        __rcu_process_gp_end(rsp, rnp, rdp);
 
-       /*
-        * Because this CPU just now started the new grace period, we know
-        * that all of its callbacks will be covered by this upcoming grace
-        * period, even the ones that were registered arbitrarily recently.
-        * Therefore, advance all outstanding callbacks to RCU_WAIT_TAIL.
-        *
-        * Other CPUs cannot be sure exactly when the grace period started.
-        * Therefore, their recently registered callbacks must pass through
-        * an additional RCU_NEXT_READY stage, so that they will be handled
-        * by the next RCU grace period.
-        */
-       rdp->nxttail[RCU_NEXT_READY_TAIL] = rdp->nxttail[RCU_NEXT_TAIL];
-       rdp->nxttail[RCU_WAIT_TAIL] = rdp->nxttail[RCU_NEXT_TAIL];
-
        /* Set state so that this CPU will detect the next quiescent state. */
        __note_new_gpnum(rsp, rnp, rdp);
 }
 
 /*
- * Start a new RCU grace period if warranted, re-initializing the hierarchy
- * in preparation for detecting the next grace period.  The caller must hold
- * the root node's ->lock, which is released before return.  Hard irqs must
- * be disabled.
- *
- * Note that it is legal for a dying CPU (which is marked as offline) to
- * invoke this function.  This can happen when the dying CPU reports its
- * quiescent state.
+ * Initialize a new grace period.
  */
-static void
-rcu_start_gp(struct rcu_state *rsp, unsigned long flags)
-       __releases(rcu_get_root(rsp)->lock)
+static int rcu_gp_init(struct rcu_state *rsp)
 {
-       struct rcu_data *rdp = this_cpu_ptr(rsp->rda);
+       unsigned long flags;
+       struct rcu_data *rdp;
        struct rcu_node *rnp = rcu_get_root(rsp);
 
-       if (!rcu_scheduler_fully_active ||
-           !cpu_needs_another_gp(rsp, rdp)) {
-               /*
-                * Either the scheduler hasn't yet spawned the first
-                * non-idle task or this CPU does not need another
-                * grace period.  Either way, don't start a new grace
-                * period.
-                */
-               raw_spin_unlock_irqrestore(&rnp->lock, flags);
-               return;
-       }
+       raw_spin_lock_irqsave(&rnp->lock, flags);
+       rsp->gp_flags = 0; /* Clear all flags: New grace period. */
 
-       if (rsp->fqs_active) {
-               /*
-                * This CPU needs a grace period, but force_quiescent_state()
-                * is running.  Tell it to start one on this CPU's behalf.
-                */
-               rsp->fqs_need_gp = 1;
+       if (rcu_gp_in_progress(rsp)) {
+               /* Grace period already in progress, don't start another. */
                raw_spin_unlock_irqrestore(&rnp->lock, flags);
-               return;
+               return 0;
        }
 
        /* Advance to a new grace period and initialize state. */
        rsp->gpnum++;
        trace_rcu_grace_period(rsp->name, rsp->gpnum, "start");
-       WARN_ON_ONCE(rsp->fqs_state == RCU_GP_INIT);
-       rsp->fqs_state = RCU_GP_INIT; /* Hold off force_quiescent_state. */
-       rsp->jiffies_force_qs = jiffies + RCU_JIFFIES_TILL_FORCE_QS;
        record_gp_stall_check_time(rsp);
-       raw_spin_unlock(&rnp->lock);  /* leave irqs disabled. */
+       raw_spin_unlock_irqrestore(&rnp->lock, flags);
 
        /* Exclude any concurrent CPU-hotplug operations. */
-       raw_spin_lock(&rsp->onofflock);  /* irqs already disabled. */
+       get_online_cpus();
 
        /*
         * Set the quiescent-state-needed bits in all the rcu_node
-        * structures for all currently online CPUs in breadth-first
-        * order, starting from the root rcu_node structure.  This
-        * operation relies on the layout of the hierarchy within the
-        * rsp->node[] array.  Note that other CPUs will access only
-        * the leaves of the hierarchy, which still indicate that no
+        * structures for all currently online CPUs in breadth-first order,
+        * starting from the root rcu_node structure, relying on the layout
+        * of the tree within the rsp->node[] array.  Note that other CPUs
+        * access only the leaves of the hierarchy, thus seeing that no
         * grace period is in progress, at least until the corresponding
         * leaf node has been initialized.  In addition, we have excluded
         * CPU-hotplug operations.
         *
-        * Note that the grace period cannot complete until we finish
-        * the initialization process, as there will be at least one
-        * qsmask bit set in the root node until that time, namely the
-        * one corresponding to this CPU, due to the fact that we have
-        * irqs disabled.
+        * The grace period cannot complete until the initialization
+        * process finishes, because this kthread handles both.
         */
        rcu_for_each_node_breadth_first(rsp, rnp) {
-               raw_spin_lock(&rnp->lock);      /* irqs already disabled. */
+               raw_spin_lock_irqsave(&rnp->lock, flags);
+               rdp = this_cpu_ptr(rsp->rda);
                rcu_preempt_check_blocked_tasks(rnp);
                rnp->qsmask = rnp->qsmaskinit;
                rnp->gpnum = rsp->gpnum;
+               WARN_ON_ONCE(rnp->completed != rsp->completed);
                rnp->completed = rsp->completed;
                if (rnp == rdp->mynode)
                        rcu_start_gp_per_cpu(rsp, rnp, rdp);
@@ -1119,37 +1211,56 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags)
                trace_rcu_grace_period_init(rsp->name, rnp->gpnum,
                                            rnp->level, rnp->grplo,
                                            rnp->grphi, rnp->qsmask);
-               raw_spin_unlock(&rnp->lock);    /* irqs remain disabled. */
+               raw_spin_unlock_irqrestore(&rnp->lock, flags);
+#ifdef CONFIG_PROVE_RCU_DELAY
+               if ((random32() % (rcu_num_nodes * 8)) == 0)
+                       schedule_timeout_uninterruptible(2);
+#endif /* #ifdef CONFIG_PROVE_RCU_DELAY */
+               cond_resched();
        }
 
-       rnp = rcu_get_root(rsp);
-       raw_spin_lock(&rnp->lock);              /* irqs already disabled. */
-       rsp->fqs_state = RCU_SIGNAL_INIT; /* force_quiescent_state now OK. */
-       raw_spin_unlock(&rnp->lock);            /* irqs remain disabled. */
-       raw_spin_unlock_irqrestore(&rsp->onofflock, flags);
+       put_online_cpus();
+       return 1;
 }
 
 /*
- * Report a full set of quiescent states to the specified rcu_state
- * data structure.  This involves cleaning up after the prior grace
- * period and letting rcu_start_gp() start up the next grace period
- * if one is needed.  Note that the caller must hold rnp->lock, as
- * required by rcu_start_gp(), which will release it.
+ * Do one round of quiescent-state forcing.
  */
-static void rcu_report_qs_rsp(struct rcu_state *rsp, unsigned long flags)
-       __releases(rcu_get_root(rsp)->lock)
+int rcu_gp_fqs(struct rcu_state *rsp, int fqs_state_in)
 {
-       unsigned long gp_duration;
+       unsigned long flags;
+       int fqs_state = fqs_state_in;
        struct rcu_node *rnp = rcu_get_root(rsp);
-       struct rcu_data *rdp = this_cpu_ptr(rsp->rda);
 
-       WARN_ON_ONCE(!rcu_gp_in_progress(rsp));
+       rsp->n_force_qs++;
+       if (fqs_state == RCU_SAVE_DYNTICK) {
+               /* Collect dyntick-idle snapshots. */
+               force_qs_rnp(rsp, dyntick_save_progress_counter);
+               fqs_state = RCU_FORCE_QS;
+       } else {
+               /* Handle dyntick-idle and offline CPUs. */
+               force_qs_rnp(rsp, rcu_implicit_dynticks_qs);
+       }
+       /* Clear flag to prevent immediate re-entry. */
+       if (ACCESS_ONCE(rsp->gp_flags) & RCU_GP_FLAG_FQS) {
+               raw_spin_lock_irqsave(&rnp->lock, flags);
+               rsp->gp_flags &= ~RCU_GP_FLAG_FQS;
+               raw_spin_unlock_irqrestore(&rnp->lock, flags);
+       }
+       return fqs_state;
+}
 
-       /*
-        * Ensure that all grace-period and pre-grace-period activity
-        * is seen before the assignment to rsp->completed.
-        */
-       smp_mb(); /* See above block comment. */
+/*
+ * Clean up after the old grace period.
+ */
+static void rcu_gp_cleanup(struct rcu_state *rsp)
+{
+       unsigned long flags;
+       unsigned long gp_duration;
+       struct rcu_data *rdp;
+       struct rcu_node *rnp = rcu_get_root(rsp);
+
+       raw_spin_lock_irqsave(&rnp->lock, flags);
        gp_duration = jiffies - rsp->gp_start;
        if (gp_duration > rsp->gp_max)
                rsp->gp_max = gp_duration;
@@ -1161,35 +1272,147 @@ static void rcu_report_qs_rsp(struct rcu_state *rsp, unsigned long flags)
         * they can do to advance the grace period.  It is therefore
         * safe for us to drop the lock in order to mark the grace
         * period as completed in all of the rcu_node structures.
-        *
-        * But if this CPU needs another grace period, it will take
-        * care of this while initializing the next grace period.
-        * We use RCU_WAIT_TAIL instead of the usual RCU_DONE_TAIL
-        * because the callbacks have not yet been advanced: Those
-        * callbacks are waiting on the grace period that just now
-        * completed.
         */
-       if (*rdp->nxttail[RCU_WAIT_TAIL] == NULL) {
-               raw_spin_unlock(&rnp->lock);     /* irqs remain disabled. */
+       raw_spin_unlock_irqrestore(&rnp->lock, flags);
 
-               /*
-                * Propagate new ->completed value to rcu_node structures
-                * so that other CPUs don't have to wait until the start
-                * of the next grace period to process their callbacks.
-                */
-               rcu_for_each_node_breadth_first(rsp, rnp) {
-                       raw_spin_lock(&rnp->lock); /* irqs already disabled. */
-                       rnp->completed = rsp->gpnum;
-                       raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */
-               }
-               rnp = rcu_get_root(rsp);
-               raw_spin_lock(&rnp->lock); /* irqs already disabled. */
+       /*
+        * Propagate new ->completed value to rcu_node structures so
+        * that other CPUs don't have to wait until the start of the next
+        * grace period to process their callbacks.  This also avoids
+        * some nasty RCU grace-period initialization races.
+        */
+       rcu_for_each_node_breadth_first(rsp, rnp) {
+               raw_spin_lock_irqsave(&rnp->lock, flags);
+               rnp->completed = rsp->gpnum;
+               raw_spin_unlock_irqrestore(&rnp->lock, flags);
+               cond_resched();
        }
+       rnp = rcu_get_root(rsp);
+       raw_spin_lock_irqsave(&rnp->lock, flags);
 
-       rsp->completed = rsp->gpnum;  /* Declare the grace period complete. */
+       rsp->completed = rsp->gpnum; /* Declare grace period done. */
        trace_rcu_grace_period(rsp->name, rsp->completed, "end");
        rsp->fqs_state = RCU_GP_IDLE;
-       rcu_start_gp(rsp, flags);  /* releases root node's rnp->lock. */
+       rdp = this_cpu_ptr(rsp->rda);
+       if (cpu_needs_another_gp(rsp, rdp))
+               rsp->gp_flags = 1;
+       raw_spin_unlock_irqrestore(&rnp->lock, flags);
+}
+
+/*
+ * Body of kthread that handles grace periods.
+ */
+static int rcu_gp_kthread(void *arg)
+{
+       int fqs_state;
+       unsigned long j;
+       int ret;
+       struct rcu_state *rsp = arg;
+       struct rcu_node *rnp = rcu_get_root(rsp);
+
+       for (;;) {
+
+               /* Handle grace-period start. */
+               for (;;) {
+                       wait_event_interruptible(rsp->gp_wq,
+                                                rsp->gp_flags &
+                                                RCU_GP_FLAG_INIT);
+                       if ((rsp->gp_flags & RCU_GP_FLAG_INIT) &&
+                           rcu_gp_init(rsp))
+                               break;
+                       cond_resched();
+                       flush_signals(current);
+               }
+
+               /* Handle quiescent-state forcing. */
+               fqs_state = RCU_SAVE_DYNTICK;
+               j = jiffies_till_first_fqs;
+               if (j > HZ) {
+                       j = HZ;
+                       jiffies_till_first_fqs = HZ;
+               }
+               for (;;) {
+                       rsp->jiffies_force_qs = jiffies + j;
+                       ret = wait_event_interruptible_timeout(rsp->gp_wq,
+                                       (rsp->gp_flags & RCU_GP_FLAG_FQS) ||
+                                       (!ACCESS_ONCE(rnp->qsmask) &&
+                                        !rcu_preempt_blocked_readers_cgp(rnp)),
+                                       j);
+                       /* If grace period done, leave loop. */
+                       if (!ACCESS_ONCE(rnp->qsmask) &&
+                           !rcu_preempt_blocked_readers_cgp(rnp))
+                               break;
+                       /* If time for quiescent-state forcing, do it. */
+                       if (ret == 0 || (rsp->gp_flags & RCU_GP_FLAG_FQS)) {
+                               fqs_state = rcu_gp_fqs(rsp, fqs_state);
+                               cond_resched();
+                       } else {
+                               /* Deal with stray signal. */
+                               cond_resched();
+                               flush_signals(current);
+                       }
+                       j = jiffies_till_next_fqs;
+                       if (j > HZ) {
+                               j = HZ;
+                               jiffies_till_next_fqs = HZ;
+                       } else if (j < 1) {
+                               j = 1;
+                               jiffies_till_next_fqs = 1;
+                       }
+               }
+
+               /* Handle grace-period end. */
+               rcu_gp_cleanup(rsp);
+       }
+       return 0;
+}
+
+/*
+ * Start a new RCU grace period if warranted, re-initializing the hierarchy
+ * in preparation for detecting the next grace period.  The caller must hold
+ * the root node's ->lock, which is released before return.  Hard irqs must
+ * be disabled.
+ *
+ * Note that it is legal for a dying CPU (which is marked as offline) to
+ * invoke this function.  This can happen when the dying CPU reports its
+ * quiescent state.
+ */
+static void
+rcu_start_gp(struct rcu_state *rsp, unsigned long flags)
+       __releases(rcu_get_root(rsp)->lock)
+{
+       struct rcu_data *rdp = this_cpu_ptr(rsp->rda);
+       struct rcu_node *rnp = rcu_get_root(rsp);
+
+       if (!rsp->gp_kthread ||
+           !cpu_needs_another_gp(rsp, rdp)) {
+               /*
+                * Either we have not yet spawned the grace-period
+                * task or this CPU does not need another grace period.
+                * Either way, don't start a new grace period.
+                */
+               raw_spin_unlock_irqrestore(&rnp->lock, flags);
+               return;
+       }
+
+       rsp->gp_flags = 1;
+       raw_spin_unlock_irqrestore(&rnp->lock, flags);
+       wake_up(&rsp->gp_wq);
+}
+
+/*
+ * Report a full set of quiescent states to the specified rcu_state
+ * data structure.  This involves cleaning up after the prior grace
+ * period and letting rcu_start_gp() start up the next grace period
+ * if one is needed.  Note that the caller must hold rnp->lock, as
+ * required by rcu_start_gp(), which will release it.
+ */
+static void rcu_report_qs_rsp(struct rcu_state *rsp, unsigned long flags)
+       __releases(rcu_get_root(rsp)->lock)
+{
+       WARN_ON_ONCE(!rcu_gp_in_progress(rsp));
+       raw_spin_unlock_irqrestore(&rcu_get_root(rsp)->lock, flags);
+       wake_up(&rsp->gp_wq);  /* Memory barrier implied by wake_up() path. */
 }
 
 /*
@@ -1390,17 +1613,6 @@ static void rcu_adopt_orphan_cbs(struct rcu_state *rsp)
        int i;
        struct rcu_data *rdp = __this_cpu_ptr(rsp->rda);
 
-       /*
-        * If there is an rcu_barrier() operation in progress, then
-        * only the task doing that operation is permitted to adopt
-        * callbacks.  To do otherwise breaks rcu_barrier() and friends
-        * by causing them to fail to wait for the callbacks in the
-        * orphanage.
-        */
-       if (rsp->rcu_barrier_in_progress &&
-           rsp->rcu_barrier_in_progress != current)
-               return;
-
        /* Do the accounting first. */
        rdp->qlen_lazy += rsp->qlen_lazy;
        rdp->qlen += rsp->qlen;
@@ -1455,9 +1667,8 @@ static void rcu_cleanup_dying_cpu(struct rcu_state *rsp)
  * The CPU has been completely removed, and some other CPU is reporting
  * this fact from process context.  Do the remainder of the cleanup,
  * including orphaning the outgoing CPU's RCU callbacks, and also
- * adopting them, if there is no _rcu_barrier() instance running.
- * There can only be one CPU hotplug operation at a time, so no other
- * CPU can be attempting to update rcu_cpu_kthread_task.
+ * adopting them.  There can only be one CPU hotplug operation at a time,
+ * so no other CPU can be attempting to update rcu_cpu_kthread_task.
  */
 static void rcu_cleanup_dead_cpu(int cpu, struct rcu_state *rsp)
 {
@@ -1519,10 +1730,6 @@ static void rcu_cleanup_dead_cpu(int cpu, struct rcu_state *rsp)
 
 #else /* #ifdef CONFIG_HOTPLUG_CPU */
 
-static void rcu_adopt_orphan_cbs(struct rcu_state *rsp)
-{
-}
-
 static void rcu_cleanup_dying_cpu(struct rcu_state *rsp)
 {
 }
@@ -1687,6 +1894,7 @@ static void force_qs_rnp(struct rcu_state *rsp, int (*f)(struct rcu_data *))
        struct rcu_node *rnp;
 
        rcu_for_each_leaf_node(rsp, rnp) {
+               cond_resched();
                mask = 0;
                raw_spin_lock_irqsave(&rnp->lock, flags);
                if (!rcu_gp_in_progress(rsp)) {
@@ -1723,72 +1931,39 @@ static void force_qs_rnp(struct rcu_state *rsp, int (*f)(struct rcu_data *))
  * Force quiescent states on reluctant CPUs, and also detect which
  * CPUs are in dyntick-idle mode.
  */
-static void force_quiescent_state(struct rcu_state *rsp, int relaxed)
+static void force_quiescent_state(struct rcu_state *rsp)
 {
        unsigned long flags;
-       struct rcu_node *rnp = rcu_get_root(rsp);
-
-       trace_rcu_utilization("Start fqs");
-       if (!rcu_gp_in_progress(rsp)) {
-               trace_rcu_utilization("End fqs");
-               return;  /* No grace period in progress, nothing to force. */
-       }
-       if (!raw_spin_trylock_irqsave(&rsp->fqslock, flags)) {
-               rsp->n_force_qs_lh++; /* Inexact, can lose counts.  Tough! */
-               trace_rcu_utilization("End fqs");
-               return; /* Someone else is already on the job. */
-       }
-       if (relaxed && ULONG_CMP_GE(rsp->jiffies_force_qs, jiffies))
-               goto unlock_fqs_ret; /* no emergency and done recently. */
-       rsp->n_force_qs++;
-       raw_spin_lock(&rnp->lock);  /* irqs already disabled */
-       rsp->jiffies_force_qs = jiffies + RCU_JIFFIES_TILL_FORCE_QS;
-       if(!rcu_gp_in_progress(rsp)) {
-               rsp->n_force_qs_ngp++;
-               raw_spin_unlock(&rnp->lock);  /* irqs remain disabled */
-               goto unlock_fqs_ret;  /* no GP in progress, time updated. */
-       }
-       rsp->fqs_active = 1;
-       switch (rsp->fqs_state) {
-       case RCU_GP_IDLE:
-       case RCU_GP_INIT:
-
-               break; /* grace period idle or initializing, ignore. */
-
-       case RCU_SAVE_DYNTICK:
-
-               raw_spin_unlock(&rnp->lock);  /* irqs remain disabled */
-
-               /* Record dyntick-idle state. */
-               force_qs_rnp(rsp, dyntick_save_progress_counter);
-               raw_spin_lock(&rnp->lock);  /* irqs already disabled */
-               if (rcu_gp_in_progress(rsp))
-                       rsp->fqs_state = RCU_FORCE_QS;
-               break;
-
-       case RCU_FORCE_QS:
-
-               /* Check dyntick-idle state, send IPI to laggarts. */
-               raw_spin_unlock(&rnp->lock);  /* irqs remain disabled */
-               force_qs_rnp(rsp, rcu_implicit_dynticks_qs);
-
-               /* Leave state in case more forcing is required. */
-
-               raw_spin_lock(&rnp->lock);  /* irqs already disabled */
-               break;
+       bool ret;
+       struct rcu_node *rnp;
+       struct rcu_node *rnp_old = NULL;
+
+       /* Funnel through hierarchy to reduce memory contention. */
+       rnp = per_cpu_ptr(rsp->rda, raw_smp_processor_id())->mynode;
+       for (; rnp != NULL; rnp = rnp->parent) {
+               ret = (ACCESS_ONCE(rsp->gp_flags) & RCU_GP_FLAG_FQS) ||
+                     !raw_spin_trylock(&rnp->fqslock);
+               if (rnp_old != NULL)
+                       raw_spin_unlock(&rnp_old->fqslock);
+               if (ret) {
+                       rsp->n_force_qs_lh++;
+                       return;
+               }
+               rnp_old = rnp;
        }
-       rsp->fqs_active = 0;
-       if (rsp->fqs_need_gp) {
-               raw_spin_unlock(&rsp->fqslock); /* irqs remain disabled */
-               rsp->fqs_need_gp = 0;
-               rcu_start_gp(rsp, flags); /* releases rnp->lock */
-               trace_rcu_utilization("End fqs");
-               return;
+       /* rnp_old == rcu_get_root(rsp), rnp == NULL. */
+
+       /* Reached the root of the rcu_node tree, acquire lock. */
+       raw_spin_lock_irqsave(&rnp_old->lock, flags);
+       raw_spin_unlock(&rnp_old->fqslock);
+       if (ACCESS_ONCE(rsp->gp_flags) & RCU_GP_FLAG_FQS) {
+               rsp->n_force_qs_lh++;
+               raw_spin_unlock_irqrestore(&rnp_old->lock, flags);
+               return;  /* Someone beat us to it. */
        }
-       raw_spin_unlock(&rnp->lock);  /* irqs remain disabled */
-unlock_fqs_ret:
-       raw_spin_unlock_irqrestore(&rsp->fqslock, flags);
-       trace_rcu_utilization("End fqs");
+       rsp->gp_flags |= RCU_GP_FLAG_FQS;
+       raw_spin_unlock_irqrestore(&rnp_old->lock, flags);
+       wake_up(&rsp->gp_wq);  /* Memory barrier implied by wake_up() path. */
 }
 
 /*
@@ -1804,13 +1979,6 @@ __rcu_process_callbacks(struct rcu_state *rsp)
 
        WARN_ON_ONCE(rdp->beenonline == 0);
 
-       /*
-        * If an RCU GP has gone long enough, go check for dyntick
-        * idle CPUs and, if needed, send resched IPIs.
-        */
-       if (ULONG_CMP_LT(ACCESS_ONCE(rsp->jiffies_force_qs), jiffies))
-               force_quiescent_state(rsp, 1);
-
        /*
         * Advance callbacks in response to end of earlier grace
         * period that some other CPU ended.
@@ -1838,6 +2006,8 @@ static void rcu_process_callbacks(struct softirq_action *unused)
 {
        struct rcu_state *rsp;
 
+       if (cpu_is_offline(smp_processor_id()))
+               return;
        trace_rcu_utilization("Start RCU core");
        for_each_rcu_flavor(rsp)
                __rcu_process_callbacks(rsp);
@@ -1909,12 +2079,11 @@ static void __call_rcu_core(struct rcu_state *rsp, struct rcu_data *rdp,
                        rdp->blimit = LONG_MAX;
                        if (rsp->n_force_qs == rdp->n_force_qs_snap &&
                            *rdp->nxttail[RCU_DONE_TAIL] != head)
-                               force_quiescent_state(rsp, 0);
+                               force_quiescent_state(rsp);
                        rdp->n_force_qs_snap = rsp->n_force_qs;
                        rdp->qlen_last_fqs_check = rdp->qlen;
                }
-       } else if (ULONG_CMP_LT(ACCESS_ONCE(rsp->jiffies_force_qs), jiffies))
-               force_quiescent_state(rsp, 1);
+       }
 }
 
 static void
@@ -2195,17 +2364,7 @@ static int __rcu_pending(struct rcu_state *rsp, struct rcu_data *rdp)
        /* Is the RCU core waiting for a quiescent state from this CPU? */
        if (rcu_scheduler_fully_active &&
            rdp->qs_pending && !rdp->passed_quiesce) {
-
-               /*
-                * If force_quiescent_state() coming soon and this CPU
-                * needs a quiescent state, and this is either RCU-sched
-                * or RCU-bh, force a local reschedule.
-                */
                rdp->n_rp_qs_pending++;
-               if (!rdp->preemptible &&
-                   ULONG_CMP_LT(ACCESS_ONCE(rsp->jiffies_force_qs) - 1,
-                                jiffies))
-                       set_need_resched();
        } else if (rdp->qs_pending && rdp->passed_quiesce) {
                rdp->n_rp_report_qs++;
                return 1;
@@ -2235,13 +2394,6 @@ static int __rcu_pending(struct rcu_state *rsp, struct rcu_data *rdp)
                return 1;
        }
 
-       /* Has an RCU GP gone long enough to send resched IPIs &c? */
-       if (rcu_gp_in_progress(rsp) &&
-           ULONG_CMP_LT(ACCESS_ONCE(rsp->jiffies_force_qs), jiffies)) {
-               rdp->n_rp_need_fqs++;
-               return 1;
-       }
-
        /* nothing to do */
        rdp->n_rp_need_nothing++;
        return 0;
@@ -2326,13 +2478,10 @@ static void rcu_barrier_func(void *type)
 static void _rcu_barrier(struct rcu_state *rsp)
 {
        int cpu;
-       unsigned long flags;
        struct rcu_data *rdp;
-       struct rcu_data rd;
        unsigned long snap = ACCESS_ONCE(rsp->n_barrier_done);
        unsigned long snap_done;
 
-       init_rcu_head_on_stack(&rd.barrier_head);
        _rcu_barrier_trace(rsp, "Begin", -1, snap);
 
        /* Take mutex to serialize concurrent rcu_barrier() requests. */
@@ -2372,70 +2521,30 @@ static void _rcu_barrier(struct rcu_state *rsp)
        /*
         * Initialize the count to one rather than to zero in order to
         * avoid a too-soon return to zero in case of a short grace period
-        * (or preemption of this task).  Also flag this task as doing
-        * an rcu_barrier().  This will prevent anyone else from adopting
-        * orphaned callbacks, which could cause otherwise failure if a
-        * CPU went offline and quickly came back online.  To see this,
-        * consider the following sequence of events:
-        *
-        * 1.   We cause CPU 0 to post an rcu_barrier_callback() callback.
-        * 2.   CPU 1 goes offline, orphaning its callbacks.
-        * 3.   CPU 0 adopts CPU 1's orphaned callbacks.
-        * 4.   CPU 1 comes back online.
-        * 5.   We cause CPU 1 to post an rcu_barrier_callback() callback.
-        * 6.   Both rcu_barrier_callback() callbacks are invoked, awakening
-        *      us -- but before CPU 1's orphaned callbacks are invoked!!!
+        * (or preemption of this task).  Exclude CPU-hotplug operations
+        * to ensure that no offline CPU has callbacks queued.
         */
        init_completion(&rsp->barrier_completion);
        atomic_set(&rsp->barrier_cpu_count, 1);
-       raw_spin_lock_irqsave(&rsp->onofflock, flags);
-       rsp->rcu_barrier_in_progress = current;
-       raw_spin_unlock_irqrestore(&rsp->onofflock, flags);
+       get_online_cpus();
 
        /*
-        * Force every CPU with callbacks to register a new callback
-        * that will tell us when all the preceding callbacks have
-        * been invoked.  If an offline CPU has callbacks, wait for
-        * it to either come back online or to finish orphaning those
-        * callbacks.
+        * Force each CPU with callbacks to register a new callback.
+        * When that callback is invoked, we will know that all of the
+        * corresponding CPU's preceding callbacks have been invoked.
         */
        for_each_possible_cpu(cpu) {
-               preempt_disable();
                rdp = per_cpu_ptr(rsp->rda, cpu);
-               if (cpu_is_offline(cpu)) {
-                       _rcu_barrier_trace(rsp, "Offline", cpu,
-                                          rsp->n_barrier_done);
-                       preempt_enable();
-                       while (cpu_is_offline(cpu) && ACCESS_ONCE(rdp->qlen))
-                               schedule_timeout_interruptible(1);
-               } else if (ACCESS_ONCE(rdp->qlen)) {
+               if (ACCESS_ONCE(rdp->qlen)) {
                        _rcu_barrier_trace(rsp, "OnlineQ", cpu,
                                           rsp->n_barrier_done);
                        smp_call_function_single(cpu, rcu_barrier_func, rsp, 1);
-                       preempt_enable();
                } else {
                        _rcu_barrier_trace(rsp, "OnlineNQ", cpu,
                                           rsp->n_barrier_done);
-                       preempt_enable();
                }
        }
-
-       /*
-        * Now that all online CPUs have rcu_barrier_callback() callbacks
-        * posted, we can adopt all of the orphaned callbacks and place
-        * an rcu_barrier_callback() callback after them.  When that is done,
-        * we are guaranteed to have an rcu_barrier_callback() callback
-        * following every callback that could possibly have been
-        * registered before _rcu_barrier() was called.
-        */
-       raw_spin_lock_irqsave(&rsp->onofflock, flags);
-       rcu_adopt_orphan_cbs(rsp);
-       rsp->rcu_barrier_in_progress = NULL;
-       raw_spin_unlock_irqrestore(&rsp->onofflock, flags);
-       atomic_inc(&rsp->barrier_cpu_count);
-       smp_mb__after_atomic_inc(); /* Ensure atomic_inc() before callback. */
-       rd.rsp = rsp;
-       rsp->call(&rd.barrier_head, rcu_barrier_callback);
+       put_online_cpus();
 
        /*
         * Now that we have an rcu_barrier_callback() callback on each
@@ -2456,8 +2565,6 @@ static void _rcu_barrier(struct rcu_state *rsp)
 
        /* Other rcu_barrier() invocations can now safely proceed. */
        mutex_unlock(&rsp->barrier_mutex);
-
-       destroy_rcu_head_on_stack(&rd.barrier_head);
 }
 
 /**
@@ -2497,6 +2604,9 @@ 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;
        raw_spin_unlock_irqrestore(&rnp->lock, flags);
@@ -2626,6 +2736,28 @@ static int __cpuinit rcu_cpu_notify(struct notifier_block *self,
        return NOTIFY_OK;
 }
 
+/*
+ * Spawn the kthread that handles this RCU flavor's grace periods.
+ */
+static int __init rcu_spawn_gp_kthread(void)
+{
+       unsigned long flags;
+       struct rcu_node *rnp;
+       struct rcu_state *rsp;
+       struct task_struct *t;
+
+       for_each_rcu_flavor(rsp) {
+               t = kthread_run(rcu_gp_kthread, rsp, rsp->name);
+               BUG_ON(IS_ERR(t));
+               rnp = rcu_get_root(rsp);
+               raw_spin_lock_irqsave(&rnp->lock, flags);
+               rsp->gp_kthread = t;
+               raw_spin_unlock_irqrestore(&rnp->lock, flags);
+       }
+       return 0;
+}
+early_initcall(rcu_spawn_gp_kthread);
+
 /*
  * This function is invoked towards the end of the scheduler's initialization
  * process.  Before this is called, the idle task might contain
@@ -2676,10 +2808,14 @@ static void __init rcu_init_levelspread(struct rcu_state *rsp)
 static void __init rcu_init_one(struct rcu_state *rsp,
                struct rcu_data __percpu *rda)
 {
-       static char *buf[] = { "rcu_node_level_0",
-                              "rcu_node_level_1",
-                              "rcu_node_level_2",
-                              "rcu_node_level_3" };  /* Match MAX_RCU_LVLS */
+       static char *buf[] = { "rcu_node_0",
+                              "rcu_node_1",
+                              "rcu_node_2",
+                              "rcu_node_3" };  /* Match MAX_RCU_LVLS */
+       static char *fqs[] = { "rcu_node_fqs_0",
+                              "rcu_node_fqs_1",
+                              "rcu_node_fqs_2",
+                              "rcu_node_fqs_3" };  /* Match MAX_RCU_LVLS */
        int cpustride = 1;
        int i;
        int j;
@@ -2704,7 +2840,11 @@ static void __init rcu_init_one(struct rcu_state *rsp,
                        raw_spin_lock_init(&rnp->lock);
                        lockdep_set_class_and_name(&rnp->lock,
                                                   &rcu_node_class[i], buf[i]);
-                       rnp->gpnum = 0;
+                       raw_spin_lock_init(&rnp->fqslock);
+                       lockdep_set_class_and_name(&rnp->fqslock,
+                                                  &rcu_fqs_class[i], fqs[i]);
+                       rnp->gpnum = rsp->gpnum;
+                       rnp->completed = rsp->completed;
                        rnp->qsmask = 0;
                        rnp->qsmaskinit = 0;
                        rnp->grplo = j * cpustride;
@@ -2727,6 +2867,7 @@ static void __init rcu_init_one(struct rcu_state *rsp,
        }
 
        rsp->rda = rda;
+       init_waitqueue_head(&rsp->gp_wq);
        rnp = rsp->level[rcu_num_lvls - 1];
        for_each_possible_cpu(i) {
                while (i > rnp->grphi)
index 4d29169f212468bdc6f8dd17311ecf8bdd6850a8..c2a3e7d596dcedd89c9e889990c7432a9d8a0bd0 100644 (file)
@@ -102,6 +102,10 @@ 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. */
@@ -202,6 +206,7 @@ struct rcu_node {
                                /*  per-CPU kthreads as needed. */
        unsigned int node_kthread_status;
                                /* State of node_kthread_task for tracing. */
+       raw_spinlock_t fqslock ____cacheline_internodealigned_in_smp;
 } ____cacheline_internodealigned_in_smp;
 
 /*
@@ -312,11 +317,13 @@ struct rcu_data {
        unsigned long n_rp_cpu_needs_gp;
        unsigned long n_rp_gp_completed;
        unsigned long n_rp_gp_started;
-       unsigned long n_rp_need_fqs;
        unsigned long n_rp_need_nothing;
 
-       /* 6) _rcu_barrier() callback. */
+       /* 6) _rcu_barrier() and OOM callbacks. */
        struct rcu_head barrier_head;
+#ifdef CONFIG_RCU_FAST_NO_HZ
+       struct rcu_head oom_head;
+#endif /* #ifdef CONFIG_RCU_FAST_NO_HZ */
 
        int cpu;
        struct rcu_state *rsp;
@@ -375,20 +382,17 @@ struct rcu_state {
 
        u8      fqs_state ____cacheline_internodealigned_in_smp;
                                                /* Force QS state. */
-       u8      fqs_active;                     /* force_quiescent_state() */
-                                               /*  is running. */
-       u8      fqs_need_gp;                    /* A CPU was prevented from */
-                                               /*  starting a new grace */
-                                               /*  period because */
-                                               /*  force_quiescent_state() */
-                                               /*  was running. */
        u8      boost;                          /* Subject to priority boost. */
        unsigned long gpnum;                    /* Current gp number. */
        unsigned long completed;                /* # of last completed gp. */
+       struct task_struct *gp_kthread;         /* Task for grace periods. */
+       wait_queue_head_t gp_wq;                /* Where GP task waits. */
+       int gp_flags;                           /* Commands for GP task. */
 
        /* End of fields guarded by root rcu_node's lock. */
 
-       raw_spinlock_t onofflock;               /* exclude on/offline and */
+       raw_spinlock_t onofflock ____cacheline_internodealigned_in_smp;
+                                               /* exclude on/offline and */
                                                /*  starting new GP. */
        struct rcu_head *orphan_nxtlist;        /* Orphaned callbacks that */
                                                /*  need a grace period. */
@@ -398,16 +402,11 @@ struct rcu_state {
        struct rcu_head **orphan_donetail;      /* Tail of above. */
        long qlen_lazy;                         /* Number of lazy callbacks. */
        long qlen;                              /* Total number of callbacks. */
-       struct task_struct *rcu_barrier_in_progress;
-                                               /* Task doing rcu_barrier(), */
-                                               /*  or NULL if no barrier. */
        struct mutex barrier_mutex;             /* Guards barrier fields. */
        atomic_t barrier_cpu_count;             /* # CPUs waiting on. */
        struct completion barrier_completion;   /* Wake at barrier end. */
        unsigned long n_barrier_done;           /* ++ at start and end of */
                                                /*  _rcu_barrier(). */
-       raw_spinlock_t fqslock;                 /* Only one task forcing */
-                                               /*  quiescent states. */
        unsigned long jiffies_force_qs;         /* Time at which to invoke */
                                                /*  force_quiescent_state(). */
        unsigned long n_force_qs;               /* Number of calls to */
@@ -426,6 +425,10 @@ struct rcu_state {
        struct list_head flavors;               /* List of RCU flavors. */
 };
 
+/* Values for rcu_state structure's gp_flags field. */
+#define RCU_GP_FLAG_INIT 0x1   /* Need grace-period initialization. */
+#define RCU_GP_FLAG_FQS  0x2   /* Need grace-period quiescent-state forcing. */
+
 extern struct list_head rcu_struct_flavors;
 #define for_each_rcu_flavor(rsp) \
        list_for_each_entry((rsp), &rcu_struct_flavors, flavors)
index 7f3244c0df014a7673831159ae1dbc25ceff55c8..c3e3fc499788619ef67c772c36c551b58a4c97a4 100644 (file)
@@ -25,6 +25,7 @@
  */
 
 #include <linux/delay.h>
+#include <linux/oom.h>
 
 #define RCU_KTHREAD_PRIO 1
 
@@ -118,7 +119,7 @@ EXPORT_SYMBOL_GPL(rcu_batches_completed);
  */
 void rcu_force_quiescent_state(void)
 {
-       force_quiescent_state(&rcu_preempt_state, 0);
+       force_quiescent_state(&rcu_preempt_state);
 }
 EXPORT_SYMBOL_GPL(rcu_force_quiescent_state);
 
@@ -365,8 +366,11 @@ void rcu_read_unlock_special(struct task_struct *t)
                if (&t->rcu_node_entry == rnp->exp_tasks)
                        rnp->exp_tasks = np;
 #ifdef CONFIG_RCU_BOOST
-               if (&t->rcu_node_entry == rnp->boost_tasks)
+               if (&t->rcu_node_entry == rnp->boost_tasks) {
                        rnp->boost_tasks = np;
+                       if (rnp->boost_tasks == NULL)
+                               rnp->boost_tasks = rnp->exp_tasks;
+               }
                /* Snapshot/clear ->rcu_boost_mutex with rcu_node lock held. */
                if (t->rcu_boost_mutex) {
                        rbmp = t->rcu_boost_mutex;
@@ -551,6 +555,8 @@ static int rcu_preempt_offline_tasks(struct rcu_state *rsp,
 
        /* If we are on an internal node, complain bitterly. */
        WARN_ON_ONCE(rnp != rdp->mynode);
+       /* If any offline CPUs are blocking current GP, complain bitterly. */
+       WARN_ON_ONCE(rnp->qsmask != 0);
 
        /*
         * Move tasks up to root rcu_node.  Don't try to get fancy for
@@ -561,7 +567,7 @@ static int rcu_preempt_offline_tasks(struct rcu_state *rsp,
         * absolutely necessary, but this is a good performance/complexity
         * tradeoff.
         */
-       if (rcu_preempt_blocked_readers_cgp(rnp) && rnp->qsmask == 0)
+       if (rcu_preempt_blocked_readers_cgp(rnp))
                retval |= RCU_OFL_TASKS_NORM_GP;
        if (rcu_preempted_readers_exp(rnp))
                retval |= RCU_OFL_TASKS_EXP_GP;
@@ -584,17 +590,19 @@ static int rcu_preempt_offline_tasks(struct rcu_state *rsp,
                raw_spin_unlock(&rnp_root->lock); /* irqs still disabled */
        }
 
+       rnp->gp_tasks = NULL;
+       rnp->exp_tasks = NULL;
 #ifdef CONFIG_RCU_BOOST
-       /* In case root is being boosted and leaf is not. */
+       rnp->boost_tasks = NULL;
+       /* In case root is being boosted and leaf was not. */
        raw_spin_lock(&rnp_root->lock); /* irqs already disabled */
        if (rnp_root->boost_tasks != NULL &&
-           rnp_root->boost_tasks != rnp_root->gp_tasks)
+           rnp_root->boost_tasks != rnp_root->gp_tasks &&
+           rnp_root->boost_tasks != rnp_root->exp_tasks)
                rnp_root->boost_tasks = rnp_root->gp_tasks;
        raw_spin_unlock(&rnp_root->lock); /* irqs still disabled */
 #endif /* #ifdef CONFIG_RCU_BOOST */
 
-       rnp->gp_tasks = NULL;
-       rnp->exp_tasks = NULL;
        return retval;
 }
 
@@ -676,7 +684,7 @@ void synchronize_rcu(void)
 EXPORT_SYMBOL_GPL(synchronize_rcu);
 
 static DECLARE_WAIT_QUEUE_HEAD(sync_rcu_preempt_exp_wq);
-static long sync_rcu_preempt_exp_count;
+static unsigned long sync_rcu_preempt_exp_count;
 static DEFINE_MUTEX(sync_rcu_preempt_exp_mutex);
 
 /*
@@ -791,41 +799,55 @@ void synchronize_rcu_expedited(void)
        unsigned long flags;
        struct rcu_node *rnp;
        struct rcu_state *rsp = &rcu_preempt_state;
-       long snap;
+       unsigned long snap;
        int trycount = 0;
 
        smp_mb(); /* Caller's modifications seen first by other CPUs. */
        snap = ACCESS_ONCE(sync_rcu_preempt_exp_count) + 1;
        smp_mb(); /* Above access cannot bleed into critical section. */
 
+       /*
+        * Block CPU-hotplug operations.  This means that any CPU-hotplug
+        * operation that finds an rcu_node structure with tasks in the
+        * process of being boosted will know that all tasks blocking
+        * this expedited grace period will already be in the process of
+        * being boosted.  This simplifies the process of moving tasks
+        * from leaf to root rcu_node structures.
+        */
+       get_online_cpus();
+
        /*
         * Acquire lock, falling back to synchronize_rcu() if too many
         * lock-acquisition failures.  Of course, if someone does the
         * expedited grace period for us, just leave.
         */
        while (!mutex_trylock(&sync_rcu_preempt_exp_mutex)) {
+               if (ULONG_CMP_LT(snap,
+                   ACCESS_ONCE(sync_rcu_preempt_exp_count))) {
+                       put_online_cpus();
+                       goto mb_ret; /* Others did our work for us. */
+               }
                if (trycount++ < 10) {
                        udelay(trycount * num_online_cpus());
                } else {
+                       put_online_cpus();
                        synchronize_rcu();
                        return;
                }
-               if ((ACCESS_ONCE(sync_rcu_preempt_exp_count) - snap) > 0)
-                       goto mb_ret; /* Others did our work for us. */
        }
-       if ((ACCESS_ONCE(sync_rcu_preempt_exp_count) - snap) > 0)
+       if (ULONG_CMP_LT(snap, ACCESS_ONCE(sync_rcu_preempt_exp_count))) {
+               put_online_cpus();
                goto unlock_mb_ret; /* Others did our work for us. */
+       }
 
        /* force all RCU readers onto ->blkd_tasks lists. */
        synchronize_sched_expedited();
 
-       raw_spin_lock_irqsave(&rsp->onofflock, flags);
-
        /* Initialize ->expmask for all non-leaf rcu_node structures. */
        rcu_for_each_nonleaf_node_breadth_first(rsp, rnp) {
-               raw_spin_lock(&rnp->lock); /* irqs already disabled. */
+               raw_spin_lock_irqsave(&rnp->lock, flags);
                rnp->expmask = rnp->qsmaskinit;
-               raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */
+               raw_spin_unlock_irqrestore(&rnp->lock, flags);
        }
 
        /* Snapshot current state of ->blkd_tasks lists. */
@@ -834,7 +856,7 @@ void synchronize_rcu_expedited(void)
        if (NUM_RCU_NODES > 1)
                sync_rcu_preempt_exp_init(rsp, rcu_get_root(rsp));
 
-       raw_spin_unlock_irqrestore(&rsp->onofflock, flags);
+       put_online_cpus();
 
        /* Wait for snapshotted ->blkd_tasks lists to drain. */
        rnp = rcu_get_root(rsp);
@@ -1191,9 +1213,9 @@ static int rcu_boost_kthread(void *arg)
  * kthread to start boosting them.  If there is an expedited grace
  * period in progress, it is always time to boost.
  *
- * The caller must hold rnp->lock, which this function releases,
- * but irqs remain disabled.  The ->boost_kthread_task is immortal,
- * so we don't need to worry about it going away.
+ * The caller must hold rnp->lock, which this function releases.
+ * The ->boost_kthread_task is immortal, so we don't need to worry
+ * about it going away.
  */
 static void rcu_initiate_boost(struct rcu_node *rnp, unsigned long flags)
 {
@@ -1997,6 +2019,26 @@ static void rcu_prepare_for_idle(int cpu)
        if (!tne)
                return;
 
+       /* Adaptive-tick mode, where usermode execution is idle to RCU. */
+       if (!is_idle_task(current)) {
+               rdtp->dyntick_holdoff = jiffies - 1;
+               if (rcu_cpu_has_nonlazy_callbacks(cpu)) {
+                       trace_rcu_prep_idle("User dyntick with callbacks");
+                       rdtp->idle_gp_timer_expires =
+                               round_up(jiffies + RCU_IDLE_GP_DELAY,
+                                        RCU_IDLE_GP_DELAY);
+               } else if (rcu_cpu_has_callbacks(cpu)) {
+                       rdtp->idle_gp_timer_expires =
+                               round_jiffies(jiffies + RCU_IDLE_LAZY_GP_DELAY);
+                       trace_rcu_prep_idle("User dyntick with lazy callbacks");
+               } else {
+                       return;
+               }
+               tp = &rdtp->idle_gp_timer;
+               mod_timer_pinned(tp, rdtp->idle_gp_timer_expires);
+               return;
+       }
+
        /*
         * If this is an idle re-entry, for example, due to use of
         * RCU_NONIDLE() or the new idle-loop tracing API within the idle
@@ -2075,16 +2117,16 @@ static void rcu_prepare_for_idle(int cpu)
 #ifdef CONFIG_TREE_PREEMPT_RCU
        if (per_cpu(rcu_preempt_data, cpu).nxtlist) {
                rcu_preempt_qs(cpu);
-               force_quiescent_state(&rcu_preempt_state, 0);
+               force_quiescent_state(&rcu_preempt_state);
        }
 #endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
        if (per_cpu(rcu_sched_data, cpu).nxtlist) {
                rcu_sched_qs(cpu);
-               force_quiescent_state(&rcu_sched_state, 0);
+               force_quiescent_state(&rcu_sched_state);
        }
        if (per_cpu(rcu_bh_data, cpu).nxtlist) {
                rcu_bh_qs(cpu);
-               force_quiescent_state(&rcu_bh_state, 0);
+               force_quiescent_state(&rcu_bh_state);
        }
 
        /*
@@ -2112,6 +2154,90 @@ static void rcu_idle_count_callbacks_posted(void)
        __this_cpu_add(rcu_dynticks.nonlazy_posted, 1);
 }
 
+/*
+ * Data for flushing lazy RCU callbacks at OOM time.
+ */
+static atomic_t oom_callback_count;
+static DECLARE_WAIT_QUEUE_HEAD(oom_callback_wq);
+
+/*
+ * RCU OOM callback -- decrement the outstanding count and deliver the
+ * wake-up if we are the last one.
+ */
+static void rcu_oom_callback(struct rcu_head *rhp)
+{
+       if (atomic_dec_and_test(&oom_callback_count))
+               wake_up(&oom_callback_wq);
+}
+
+/*
+ * Post an rcu_oom_notify callback on the current CPU if it has at
+ * least one lazy callback.  This will unnecessarily post callbacks
+ * to CPUs that already have a non-lazy callback at the end of their
+ * callback list, but this is an infrequent operation, so accept some
+ * extra overhead to keep things simple.
+ */
+static void rcu_oom_notify_cpu(void *flavor)
+{
+       struct rcu_state *rsp = flavor;
+       struct rcu_data *rdp = __this_cpu_ptr(rsp->rda);
+
+       if (rdp->qlen_lazy != 0) {
+               atomic_inc(&oom_callback_count);
+               rsp->call(&rdp->oom_head, rcu_oom_callback);
+       }
+}
+
+/*
+ * If low on memory, ensure that each CPU has a non-lazy callback.
+ * This will wake up CPUs that have only lazy callbacks, in turn
+ * ensuring that they free up the corresponding memory in a timely manner.
+ */
+static int rcu_oom_notify(struct notifier_block *self,
+                          unsigned long notused, void *nfreed)
+{
+       int cpu;
+
+       /* Wait for callbacks from earlier instance to complete. */
+       wait_event(oom_callback_wq, atomic_read(&oom_callback_count) == 0);
+
+       /*
+        * Prevent premature wakeup: ensure that all increments happen
+        * before there is a chance of the counter reaching zero.
+        */
+       atomic_set(&oom_callback_count, 1);
+
+       get_online_cpus();
+       for_each_online_cpu(cpu) {
+#ifdef CONFIG_PREEMPT_RCU
+               smp_call_function_single(cpu, rcu_oom_notify_cpu,
+                                        &rcu_preempt_state, 1);
+#endif /* #ifdef CONFIG_PREEMPT_RCU */
+               smp_call_function_single(cpu, rcu_oom_notify_cpu,
+                                        &rcu_bh_state, 1);
+               smp_call_function_single(cpu, rcu_oom_notify_cpu,
+                                        &rcu_sched_state, 1);
+       }
+       put_online_cpus();
+
+       /* Unconditionally decrement: no need to wake ourselves up. */
+       atomic_dec(&oom_callback_count);
+
+       *(unsigned long *)nfreed = 1;
+       return NOTIFY_OK;
+}
+
+static struct notifier_block rcu_oom_nb = {
+       .notifier_call = rcu_oom_notify
+};
+
+static int __init rcu_register_oom_notifier(void)
+{
+       register_oom_notifier(&rcu_oom_nb);
+       return 0;
+}
+early_initcall(rcu_register_oom_notifier);
+
 #endif /* #else #if !defined(CONFIG_RCU_FAST_NO_HZ) */
 
 #ifdef CONFIG_RCU_CPU_STALL_INFO
index abffb486e94ed7ea581b54861f253ca8567bddda..8a2eb716091b42dace491a4d912c6e880f35817e 100644 (file)
@@ -51,8 +51,8 @@ static int show_rcubarrier(struct seq_file *m, void *unused)
        struct rcu_state *rsp;
 
        for_each_rcu_flavor(rsp)
-               seq_printf(m, "%s: %c bcc: %d nbd: %lu\n",
-                          rsp->name, rsp->rcu_barrier_in_progress ? 'B' : '.',
+               seq_printf(m, "%s: bcc: %d nbd: %lu\n",
+                          rsp->name,
                           atomic_read(&rsp->barrier_cpu_count),
                           rsp->n_barrier_done);
        return 0;
@@ -386,10 +386,9 @@ static void print_one_rcu_pending(struct seq_file *m, struct rcu_data *rdp)
                   rdp->n_rp_report_qs,
                   rdp->n_rp_cb_ready,
                   rdp->n_rp_cpu_needs_gp);
-       seq_printf(m, "gpc=%ld gps=%ld nf=%ld nn=%ld\n",
+       seq_printf(m, "gpc=%ld gps=%ld nn=%ld\n",
                   rdp->n_rp_gp_completed,
                   rdp->n_rp_gp_started,
-                  rdp->n_rp_need_fqs,
                   rdp->n_rp_need_nothing);
 }
 
index d325c4b2dcbb0c5995a903d76e3035129d1590c3..1cbf38067af5575f94d74d640637e45e511cdde8 100644 (file)
@@ -2081,6 +2081,7 @@ context_switch(struct rq *rq, struct task_struct *prev,
 #endif
 
        /* Here we just switch the register state and the stack. */
+       rcu_switch(prev, next);
        switch_to(prev, next, prev);
 
        barrier();
@@ -3462,6 +3463,13 @@ asmlinkage void __sched schedule(void)
 }
 EXPORT_SYMBOL(schedule);
 
+asmlinkage void __sched schedule_user(void)
+{
+       rcu_user_exit();
+       schedule();
+       rcu_user_enter();
+}
+
 /**
  * schedule_preempt_disabled - called with preemption disabled
  *
@@ -3563,6 +3571,7 @@ asmlinkage void __sched preempt_schedule_irq(void)
        /* Catch callers which need to be fixed */
        BUG_ON(ti->preempt_count || !irqs_disabled());
 
+       rcu_user_exit();
        do {
                add_preempt_count(PREEMPT_ACTIVE);
                local_irq_enable();
@@ -4340,9 +4349,7 @@ recheck:
         */
        if (unlikely(policy == p->policy && (!rt_policy(policy) ||
                        param->sched_priority == p->rt_priority))) {
-
-               __task_rq_unlock(rq);
-               raw_spin_unlock_irqrestore(&p->pi_lock, flags);
+               task_rq_unlock(rq, p, &flags);
                return 0;
        }
 
@@ -5306,10 +5313,8 @@ void idle_task_exit(void)
  * their home CPUs. So we just add the counter to another CPU's counter,
  * to keep the global sum constant after CPU-down:
  */
-static void migrate_nr_uninterruptible(struct rq *rq_src)
+static void migrate_nr_uninterruptible(struct rq *rq_src, struct rq *rq_dest)
 {
-       struct rq *rq_dest = cpu_rq(cpumask_any(cpu_active_mask));
-
        rq_dest->nr_uninterruptible += rq_src->nr_uninterruptible;
        rq_src->nr_uninterruptible = 0;
 }
@@ -5331,7 +5336,7 @@ static void calc_global_load_remove(struct rq *rq)
  * there's no concurrency possible, we hold the required locks anyway
  * because of lock validation efforts.
  */
-static void migrate_tasks(unsigned int dead_cpu)
+static void migrate_tasks(unsigned int dead_cpu, struct rq *rq_dest)
 {
        struct rq *rq = cpu_rq(dead_cpu);
        struct task_struct *next, *stop = rq->stop;
@@ -5365,11 +5370,11 @@ static void migrate_tasks(unsigned int dead_cpu)
 
                /* Find suitable destination for @next, with force if needed. */
                dest_cpu = select_fallback_rq(dead_cpu, next);
-               raw_spin_unlock(&rq->lock);
+               double_rq_unlock(rq, rq_dest);
 
                __migrate_task(next, dead_cpu, dest_cpu);
 
-               raw_spin_lock(&rq->lock);
+               double_rq_lock(rq, rq_dest);
        }
 
        rq->stop = stop;
@@ -5583,6 +5588,7 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu)
        int cpu = (long)hcpu;
        unsigned long flags;
        struct rq *rq = cpu_rq(cpu);
+       struct rq __maybe_unused *rq_dest = cpu_rq(cpumask_any(cpu_active_mask));
 
        switch (action & ~CPU_TASKS_FROZEN) {
 
@@ -5605,17 +5611,19 @@ migration_call(struct notifier_block *nfb, unsigned long action, void *hcpu)
        case CPU_DYING:
                sched_ttwu_pending();
                /* Update our root-domain */
-               raw_spin_lock_irqsave(&rq->lock, flags);
+               local_irq_save(flags);
+               double_rq_lock(rq, rq_dest);
                if (rq->rd) {
                        BUG_ON(!cpumask_test_cpu(cpu, rq->rd->span));
                        set_rq_offline(rq);
                }
-               migrate_tasks(cpu);
+               migrate_tasks(cpu, rq_dest);
                BUG_ON(rq->nr_running != 1); /* the migration thread */
-               raw_spin_unlock_irqrestore(&rq->lock, flags);
 
-               migrate_nr_uninterruptible(rq);
+               migrate_nr_uninterruptible(rq, rq_dest);
                calc_global_load_remove(rq);
+               double_rq_unlock(rq, rq_dest);
+               local_irq_restore(flags);
                break;
 #endif
        }
index d72586fdf6607db63c5f43a2e1fbbb32ff0ac2c7..23aa789c53ee5c6e061c6bf2b0f8181292695044 100644 (file)
@@ -65,8 +65,8 @@ static int convert_prio(int prio)
 int cpupri_find(struct cpupri *cp, struct task_struct *p,
                struct cpumask *lowest_mask)
 {
-       int                  idx      = 0;
-       int                  task_pri = convert_prio(p->prio);
+       int idx = 0;
+       int task_pri = convert_prio(p->prio);
 
        if (task_pri >= MAX_RT_PRIO)
                return 0;
@@ -137,9 +137,9 @@ int cpupri_find(struct cpupri *cp, struct task_struct *p,
  */
 void cpupri_set(struct cpupri *cp, int cpu, int newpri)
 {
-       int                 *currpri = &cp->cpu_to_pri[cpu];
-       int                  oldpri  = *currpri;
-       int                  do_mb = 0;
+       int *currpri = &cp->cpu_to_pri[cpu];
+       int oldpri = *currpri;
+       int do_mb = 0;
 
        newpri = convert_prio(newpri);
 
index 22321db64952f9461b9e03a3e90bd99217478f8f..d0cc03b3e70b9d2d2bfbbd418e6dfc858a7f6387 100644 (file)
@@ -3069,6 +3069,9 @@ struct lb_env {
        int                     new_dst_cpu;
        enum cpu_idle_type      idle;
        long                    imbalance;
+       /* The set of CPUs under consideration for load-balancing */
+       struct cpumask          *cpus;
+
        unsigned int            flags;
 
        unsigned int            loop;
@@ -3653,8 +3656,7 @@ fix_small_capacity(struct sched_domain *sd, struct sched_group *group)
  */
 static inline void update_sg_lb_stats(struct lb_env *env,
                        struct sched_group *group, int load_idx,
-                       int local_group, const struct cpumask *cpus,
-                       int *balance, struct sg_lb_stats *sgs)
+                       int local_group, int *balance, struct sg_lb_stats *sgs)
 {
        unsigned long nr_running, max_nr_running, min_nr_running;
        unsigned long load, max_cpu_load, min_cpu_load;
@@ -3671,7 +3673,7 @@ static inline void update_sg_lb_stats(struct lb_env *env,
        max_nr_running = 0;
        min_nr_running = ~0UL;
 
-       for_each_cpu_and(i, sched_group_cpus(group), cpus) {
+       for_each_cpu_and(i, sched_group_cpus(group), env->cpus) {
                struct rq *rq = cpu_rq(i);
 
                nr_running = rq->nr_running;
@@ -3800,8 +3802,7 @@ static bool update_sd_pick_busiest(struct lb_env *env,
  * @sds: variable to hold the statistics for this sched_domain.
  */
 static inline void update_sd_lb_stats(struct lb_env *env,
-                                     const struct cpumask *cpus,
-                                     int *balance, struct sd_lb_stats *sds)
+                                       int *balance, struct sd_lb_stats *sds)
 {
        struct sched_domain *child = env->sd->child;
        struct sched_group *sg = env->sd->groups;
@@ -3818,8 +3819,7 @@ static inline void update_sd_lb_stats(struct lb_env *env,
 
                local_group = cpumask_test_cpu(env->dst_cpu, sched_group_cpus(sg));
                memset(&sgs, 0, sizeof(sgs));
-               update_sg_lb_stats(env, sg, load_idx, local_group,
-                                  cpus, balance, &sgs);
+               update_sg_lb_stats(env, sg, load_idx, local_group, balance, &sgs);
 
                if (local_group && !(*balance))
                        return;
@@ -4055,7 +4055,6 @@ static inline void calculate_imbalance(struct lb_env *env, struct sd_lb_stats *s
  * to restore balance.
  *
  * @env: The load balancing environment.
- * @cpus: The set of CPUs under consideration for load-balancing.
  * @balance: Pointer to a variable indicating if this_cpu
  *     is the appropriate cpu to perform load balancing at this_level.
  *
@@ -4065,7 +4064,7 @@ static inline void calculate_imbalance(struct lb_env *env, struct sd_lb_stats *s
  *                put to idle by rebalancing its tasks onto our group.
  */
 static struct sched_group *
-find_busiest_group(struct lb_env *env, const struct cpumask *cpus, int *balance)
+find_busiest_group(struct lb_env *env, int *balance)
 {
        struct sd_lb_stats sds;
 
@@ -4075,7 +4074,7 @@ find_busiest_group(struct lb_env *env, const struct cpumask *cpus, int *balance)
         * Compute the various statistics relavent for load balancing at
         * this level.
         */
-       update_sd_lb_stats(env, cpus, balance, &sds);
+       update_sd_lb_stats(env, balance, &sds);
 
        /*
         * this_cpu is not the appropriate cpu to perform load balancing at
@@ -4155,8 +4154,7 @@ ret:
  * find_busiest_queue - find the busiest runqueue among the cpus in group.
  */
 static struct rq *find_busiest_queue(struct lb_env *env,
-                                    struct sched_group *group,
-                                    const struct cpumask *cpus)
+                                    struct sched_group *group)
 {
        struct rq *busiest = NULL, *rq;
        unsigned long max_load = 0;
@@ -4171,7 +4169,7 @@ static struct rq *find_busiest_queue(struct lb_env *env,
                if (!capacity)
                        capacity = fix_small_capacity(env->sd, group);
 
-               if (!cpumask_test_cpu(i, cpus))
+               if (!cpumask_test_cpu(i, env->cpus))
                        continue;
 
                rq = cpu_rq(i);
@@ -4252,6 +4250,7 @@ static int load_balance(int this_cpu, struct rq *this_rq,
                .dst_grpmask    = sched_group_cpus(sd->groups),
                .idle           = idle,
                .loop_break     = sched_nr_migrate_break,
+               .cpus           = cpus,
        };
 
        cpumask_copy(cpus, cpu_active_mask);
@@ -4260,7 +4259,7 @@ static int load_balance(int this_cpu, struct rq *this_rq,
        schedstat_inc(sd, lb_count[idle]);
 
 redo:
-       group = find_busiest_group(&env, cpus, balance);
+       group = find_busiest_group(&env, balance);
 
        if (*balance == 0)
                goto out_balanced;
@@ -4270,7 +4269,7 @@ redo:
                goto out_balanced;
        }
 
-       busiest = find_busiest_queue(&env, group, cpus);
+       busiest = find_busiest_queue(&env, group);
        if (!busiest) {
                schedstat_inc(sd, lb_nobusyq[idle]);
                goto out_balanced;
index 7e1ce012a851351c10853fe732e714afa2bb8a5c..30b6de0d977c4734eb479d7489f61e56b35afaa8 100644 (file)
@@ -397,6 +397,30 @@ void clockevents_exchange_device(struct clock_event_device *old,
        local_irq_restore(flags);
 }
 
+/**
+ * clockevents_suspend - suspend clock devices
+ */
+void clockevents_suspend(void)
+{
+       struct clock_event_device *dev;
+
+       list_for_each_entry_reverse(dev, &clockevent_devices, list)
+               if (dev->suspend)
+                       dev->suspend(dev);
+}
+
+/**
+ * clockevents_resume - resume clock devices
+ */
+void clockevents_resume(void)
+{
+       struct clock_event_device *dev;
+
+       list_for_each_entry(dev, &clockevent_devices, list)
+               if (dev->resume)
+                       dev->resume(dev);
+}
+
 #ifdef CONFIG_GENERIC_CLOCKEVENTS
 /**
  * clockevents_notify - notification about relevant events
index a470154e040826f9549e5faf9ed4aefd174de698..46da0537c10b4d78e3c5645d8b709bb3503cc2af 100644 (file)
@@ -37,7 +37,7 @@
  * requested HZ value. It is also not recommended
  * for "tick-less" systems.
  */
-#define NSEC_PER_JIFFY ((u32)((((u64)NSEC_PER_SEC)<<8)/ACTHZ))
+#define NSEC_PER_JIFFY ((u32)((((u64)NSEC_PER_SEC)<<8)/SHIFTED_HZ))
 
 /* Since jiffies uses a simple NSEC_PER_JIFFY multiplier
  * conversion, the .shift value could be zero. However
index b7fbadc5c973c928e531cf6d701f1520e4809812..24174b4d669b1280c632d4ed0126dc2f1bb297ef 100644 (file)
@@ -28,7 +28,7 @@ DEFINE_SPINLOCK(ntp_lock);
 /* USER_HZ period (usecs): */
 unsigned long                  tick_usec = TICK_USEC;
 
-/* ACTHZ period (nsecs): */
+/* SHIFTED_HZ period (nsecs): */
 unsigned long                  tick_nsec;
 
 static u64                     tick_length;
index f045cc50832d0fc8aee045755d3ba60d655f2647..f80e8d02b8bc198386bbadd0dce471685b9384b4 100644 (file)
@@ -65,14 +65,14 @@ struct timekeeper {
         * used instead.
         */
        struct timespec         wall_to_monotonic;
-       /* time spent in suspend */
-       struct timespec         total_sleep_time;
-       /* The raw monotonic time for the CLOCK_MONOTONIC_RAW posix clock. */
-       struct timespec         raw_time;
        /* Offset clock monotonic -> clock realtime */
        ktime_t                 offs_real;
+       /* time spent in suspend */
+       struct timespec         total_sleep_time;
        /* Offset clock monotonic -> clock boottime */
        ktime_t                 offs_boot;
+       /* The raw monotonic time for the CLOCK_MONOTONIC_RAW posix clock. */
+       struct timespec         raw_time;
        /* Seqlock for all timekeeper values */
        seqlock_t               lock;
 };
@@ -108,13 +108,38 @@ static struct timespec tk_xtime(struct timekeeper *tk)
 static void tk_set_xtime(struct timekeeper *tk, const struct timespec *ts)
 {
        tk->xtime_sec = ts->tv_sec;
-       tk->xtime_nsec = ts->tv_nsec << tk->shift;
+       tk->xtime_nsec = (u64)ts->tv_nsec << tk->shift;
 }
 
 static void tk_xtime_add(struct timekeeper *tk, const struct timespec *ts)
 {
        tk->xtime_sec += ts->tv_sec;
-       tk->xtime_nsec += ts->tv_nsec << tk->shift;
+       tk->xtime_nsec += (u64)ts->tv_nsec << tk->shift;
+}
+
+static void tk_set_wall_to_mono(struct timekeeper *tk, struct timespec wtm)
+{
+       struct timespec tmp;
+
+       /*
+        * Verify consistency of: offset_real = -wall_to_monotonic
+        * before modifying anything
+        */
+       set_normalized_timespec(&tmp, -tk->wall_to_monotonic.tv_sec,
+                                       -tk->wall_to_monotonic.tv_nsec);
+       WARN_ON_ONCE(tk->offs_real.tv64 != timespec_to_ktime(tmp).tv64);
+       tk->wall_to_monotonic = wtm;
+       set_normalized_timespec(&tmp, -wtm.tv_sec, -wtm.tv_nsec);
+       tk->offs_real = timespec_to_ktime(tmp);
+}
+
+static void tk_set_sleep_time(struct timekeeper *tk, struct timespec t)
+{
+       /* Verify consistency before modifying */
+       WARN_ON_ONCE(tk->offs_boot.tv64 != timespec_to_ktime(tk->total_sleep_time).tv64);
+
+       tk->total_sleep_time    = t;
+       tk->offs_boot           = timespec_to_ktime(t);
 }
 
 /**
@@ -217,14 +242,6 @@ static inline s64 timekeeping_get_ns_raw(struct timekeeper *tk)
        return nsec + arch_gettimeoffset();
 }
 
-static void update_rt_offset(struct timekeeper *tk)
-{
-       struct timespec tmp, *wtm = &tk->wall_to_monotonic;
-
-       set_normalized_timespec(&tmp, -wtm->tv_sec, -wtm->tv_nsec);
-       tk->offs_real = timespec_to_ktime(tmp);
-}
-
 /* must hold write on timekeeper.lock */
 static void timekeeping_update(struct timekeeper *tk, bool clearntp)
 {
@@ -234,12 +251,10 @@ static void timekeeping_update(struct timekeeper *tk, bool clearntp)
                tk->ntp_error = 0;
                ntp_clear();
        }
-       update_rt_offset(tk);
        xt = tk_xtime(tk);
        update_vsyscall(&xt, &tk->wall_to_monotonic, tk->clock, tk->mult);
 }
 
-
 /**
  * timekeeping_forward_now - update clock to the current time
  *
@@ -277,18 +292,19 @@ static void timekeeping_forward_now(struct timekeeper *tk)
  */
 void getnstimeofday(struct timespec *ts)
 {
+       struct timekeeper *tk = &timekeeper;
        unsigned long seq;
        s64 nsecs = 0;
 
        WARN_ON(timekeeping_suspended);
 
        do {
-               seq = read_seqbegin(&timekeeper.lock);
+               seq = read_seqbegin(&tk->lock);
 
-               ts->tv_sec = timekeeper.xtime_sec;
-               ts->tv_nsec = timekeeping_get_ns(&timekeeper);
+               ts->tv_sec = tk->xtime_sec;
+               ts->tv_nsec = timekeeping_get_ns(tk);
 
-       } while (read_seqretry(&timekeeper.lock, seq));
+       } while (read_seqretry(&tk->lock, seq));
 
        timespec_add_ns(ts, nsecs);
 }
@@ -296,19 +312,18 @@ EXPORT_SYMBOL(getnstimeofday);
 
 ktime_t ktime_get(void)
 {
+       struct timekeeper *tk = &timekeeper;
        unsigned int seq;
        s64 secs, nsecs;
 
        WARN_ON(timekeeping_suspended);
 
        do {
-               seq = read_seqbegin(&timekeeper.lock);
-               secs = timekeeper.xtime_sec +
-                               timekeeper.wall_to_monotonic.tv_sec;
-               nsecs = timekeeping_get_ns(&timekeeper) +
-                               timekeeper.wall_to_monotonic.tv_nsec;
+               seq = read_seqbegin(&tk->lock);
+               secs = tk->xtime_sec + tk->wall_to_monotonic.tv_sec;
+               nsecs = timekeeping_get_ns(tk) + tk->wall_to_monotonic.tv_nsec;
 
-       } while (read_seqretry(&timekeeper.lock, seq));
+       } while (read_seqretry(&tk->lock, seq));
        /*
         * Use ktime_set/ktime_add_ns to create a proper ktime on
         * 32-bit architectures without CONFIG_KTIME_SCALAR.
@@ -327,18 +342,19 @@ EXPORT_SYMBOL_GPL(ktime_get);
  */
 void ktime_get_ts(struct timespec *ts)
 {
+       struct timekeeper *tk = &timekeeper;
        struct timespec tomono;
        unsigned int seq;
 
        WARN_ON(timekeeping_suspended);
 
        do {
-               seq = read_seqbegin(&timekeeper.lock);
-               ts->tv_sec = timekeeper.xtime_sec;
-               ts->tv_nsec = timekeeping_get_ns(&timekeeper);
-               tomono = timekeeper.wall_to_monotonic;
+               seq = read_seqbegin(&tk->lock);
+               ts->tv_sec = tk->xtime_sec;
+               ts->tv_nsec = timekeeping_get_ns(tk);
+               tomono = tk->wall_to_monotonic;
 
-       } while (read_seqretry(&timekeeper.lock, seq));
+       } while (read_seqretry(&tk->lock, seq));
 
        set_normalized_timespec(ts, ts->tv_sec + tomono.tv_sec,
                                ts->tv_nsec + tomono.tv_nsec);
@@ -358,22 +374,23 @@ EXPORT_SYMBOL_GPL(ktime_get_ts);
  */
 void getnstime_raw_and_real(struct timespec *ts_raw, struct timespec *ts_real)
 {
+       struct timekeeper *tk = &timekeeper;
        unsigned long seq;
        s64 nsecs_raw, nsecs_real;
 
        WARN_ON_ONCE(timekeeping_suspended);
 
        do {
-               seq = read_seqbegin(&timekeeper.lock);
+               seq = read_seqbegin(&tk->lock);
 
-               *ts_raw = timekeeper.raw_time;
-               ts_real->tv_sec = timekeeper.xtime_sec;
+               *ts_raw = tk->raw_time;
+               ts_real->tv_sec = tk->xtime_sec;
                ts_real->tv_nsec = 0;
 
-               nsecs_raw = timekeeping_get_ns_raw(&timekeeper);
-               nsecs_real = timekeeping_get_ns(&timekeeper);
+               nsecs_raw = timekeeping_get_ns_raw(tk);
+               nsecs_real = timekeeping_get_ns(tk);
 
-       } while (read_seqretry(&timekeeper.lock, seq));
+       } while (read_seqretry(&tk->lock, seq));
 
        timespec_add_ns(ts_raw, nsecs_raw);
        timespec_add_ns(ts_real, nsecs_real);
@@ -406,28 +423,28 @@ EXPORT_SYMBOL(do_gettimeofday);
  */
 int do_settimeofday(const struct timespec *tv)
 {
+       struct timekeeper *tk = &timekeeper;
        struct timespec ts_delta, xt;
        unsigned long flags;
 
        if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
                return -EINVAL;
 
-       write_seqlock_irqsave(&timekeeper.lock, flags);
+       write_seqlock_irqsave(&tk->lock, flags);
 
-       timekeeping_forward_now(&timekeeper);
+       timekeeping_forward_now(tk);
 
-       xt = tk_xtime(&timekeeper);
+       xt = tk_xtime(tk);
        ts_delta.tv_sec = tv->tv_sec - xt.tv_sec;
        ts_delta.tv_nsec = tv->tv_nsec - xt.tv_nsec;
 
-       timekeeper.wall_to_monotonic =
-                       timespec_sub(timekeeper.wall_to_monotonic, ts_delta);
+       tk_set_wall_to_mono(tk, timespec_sub(tk->wall_to_monotonic, ts_delta));
 
-       tk_set_xtime(&timekeeper, tv);
+       tk_set_xtime(tk, tv);
 
-       timekeeping_update(&timekeeper, true);
+       timekeeping_update(tk, true);
 
-       write_sequnlock_irqrestore(&timekeeper.lock, flags);
+       write_sequnlock_irqrestore(&tk->lock, flags);
 
        /* signal hrtimers about time change */
        clock_was_set();
@@ -436,7 +453,6 @@ int do_settimeofday(const struct timespec *tv)
 }
 EXPORT_SYMBOL(do_settimeofday);
 
-
 /**
  * timekeeping_inject_offset - Adds or subtracts from the current time.
  * @tv:                pointer to the timespec variable containing the offset
@@ -445,23 +461,23 @@ EXPORT_SYMBOL(do_settimeofday);
  */
 int timekeeping_inject_offset(struct timespec *ts)
 {
+       struct timekeeper *tk = &timekeeper;
        unsigned long flags;
 
        if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC)
                return -EINVAL;
 
-       write_seqlock_irqsave(&timekeeper.lock, flags);
+       write_seqlock_irqsave(&tk->lock, flags);
 
-       timekeeping_forward_now(&timekeeper);
+       timekeeping_forward_now(tk);
 
 
-       tk_xtime_add(&timekeeper, ts);
-       timekeeper.wall_to_monotonic =
-                               timespec_sub(timekeeper.wall_to_monotonic, *ts);
+       tk_xtime_add(tk, ts);
+       tk_set_wall_to_mono(tk, timespec_sub(tk->wall_to_monotonic, *ts));
 
-       timekeeping_update(&timekeeper, true);
+       timekeeping_update(tk, true);
 
-       write_sequnlock_irqrestore(&timekeeper.lock, flags);
+       write_sequnlock_irqrestore(&tk->lock, flags);
 
        /* signal hrtimers about time change */
        clock_was_set();
@@ -477,23 +493,24 @@ EXPORT_SYMBOL(timekeeping_inject_offset);
  */
 static int change_clocksource(void *data)
 {
+       struct timekeeper *tk = &timekeeper;
        struct clocksource *new, *old;
        unsigned long flags;
 
        new = (struct clocksource *) data;
 
-       write_seqlock_irqsave(&timekeeper.lock, flags);
+       write_seqlock_irqsave(&tk->lock, flags);
 
-       timekeeping_forward_now(&timekeeper);
+       timekeeping_forward_now(tk);
        if (!new->enable || new->enable(new) == 0) {
-               old = timekeeper.clock;
-               tk_setup_internals(&timekeeper, new);
+               old = tk->clock;
+               tk_setup_internals(tk, new);
                if (old->disable)
                        old->disable(old);
        }
-       timekeeping_update(&timekeeper, true);
+       timekeeping_update(tk, true);
 
-       write_sequnlock_irqrestore(&timekeeper.lock, flags);
+       write_sequnlock_irqrestore(&tk->lock, flags);
 
        return 0;
 }
@@ -507,7 +524,9 @@ static int change_clocksource(void *data)
  */
 void timekeeping_notify(struct clocksource *clock)
 {
-       if (timekeeper.clock == clock)
+       struct timekeeper *tk = &timekeeper;
+
+       if (tk->clock == clock)
                return;
        stop_machine(change_clocksource, clock, NULL);
        tick_clock_notify();
@@ -536,35 +555,36 @@ EXPORT_SYMBOL_GPL(ktime_get_real);
  */
 void getrawmonotonic(struct timespec *ts)
 {
+       struct timekeeper *tk = &timekeeper;
        unsigned long seq;
        s64 nsecs;
 
        do {
-               seq = read_seqbegin(&timekeeper.lock);
-               nsecs = timekeeping_get_ns_raw(&timekeeper);
-               *ts = timekeeper.raw_time;
+               seq = read_seqbegin(&tk->lock);
+               nsecs = timekeeping_get_ns_raw(tk);
+               *ts = tk->raw_time;
 
-       } while (read_seqretry(&timekeeper.lock, seq));
+       } while (read_seqretry(&tk->lock, seq));
 
        timespec_add_ns(ts, nsecs);
 }
 EXPORT_SYMBOL(getrawmonotonic);
 
-
 /**
  * timekeeping_valid_for_hres - Check if timekeeping is suitable for hres
  */
 int timekeeping_valid_for_hres(void)
 {
+       struct timekeeper *tk = &timekeeper;
        unsigned long seq;
        int ret;
 
        do {
-               seq = read_seqbegin(&timekeeper.lock);
+               seq = read_seqbegin(&tk->lock);
 
-               ret = timekeeper.clock->flags & CLOCK_SOURCE_VALID_FOR_HRES;
+               ret = tk->clock->flags & CLOCK_SOURCE_VALID_FOR_HRES;
 
-       } while (read_seqretry(&timekeeper.lock, seq));
+       } while (read_seqretry(&tk->lock, seq));
 
        return ret;
 }
@@ -574,15 +594,16 @@ int timekeeping_valid_for_hres(void)
  */
 u64 timekeeping_max_deferment(void)
 {
+       struct timekeeper *tk = &timekeeper;
        unsigned long seq;
        u64 ret;
 
        do {
-               seq = read_seqbegin(&timekeeper.lock);
+               seq = read_seqbegin(&tk->lock);
 
-               ret = timekeeper.clock->max_idle_ns;
+               ret = tk->clock->max_idle_ns;
 
-       } while (read_seqretry(&timekeeper.lock, seq));
+       } while (read_seqretry(&tk->lock, seq));
 
        return ret;
 }
@@ -622,46 +643,43 @@ void __attribute__((weak)) read_boot_clock(struct timespec *ts)
  */
 void __init timekeeping_init(void)
 {
+       struct timekeeper *tk = &timekeeper;
        struct clocksource *clock;
        unsigned long flags;
-       struct timespec now, boot;
+       struct timespec now, boot, tmp;
 
        read_persistent_clock(&now);
        read_boot_clock(&boot);
 
-       seqlock_init(&timekeeper.lock);
+       seqlock_init(&tk->lock);
 
        ntp_init();
 
-       write_seqlock_irqsave(&timekeeper.lock, flags);
+       write_seqlock_irqsave(&tk->lock, flags);
        clock = clocksource_default_clock();
        if (clock->enable)
                clock->enable(clock);
-       tk_setup_internals(&timekeeper, clock);
+       tk_setup_internals(tk, clock);
 
-       tk_set_xtime(&timekeeper, &now);
-       timekeeper.raw_time.tv_sec = 0;
-       timekeeper.raw_time.tv_nsec = 0;
+       tk_set_xtime(tk, &now);
+       tk->raw_time.tv_sec = 0;
+       tk->raw_time.tv_nsec = 0;
        if (boot.tv_sec == 0 && boot.tv_nsec == 0)
-               boot = tk_xtime(&timekeeper);
-
-       set_normalized_timespec(&timekeeper.wall_to_monotonic,
-                               -boot.tv_sec, -boot.tv_nsec);
-       update_rt_offset(&timekeeper);
-       timekeeper.total_sleep_time.tv_sec = 0;
-       timekeeper.total_sleep_time.tv_nsec = 0;
-       write_sequnlock_irqrestore(&timekeeper.lock, flags);
+               boot = tk_xtime(tk);
+
+       set_normalized_timespec(&tmp, -boot.tv_sec, -boot.tv_nsec);
+       tk_set_wall_to_mono(tk, tmp);
+
+       tmp.tv_sec = 0;
+       tmp.tv_nsec = 0;
+       tk_set_sleep_time(tk, tmp);
+
+       write_sequnlock_irqrestore(&tk->lock, flags);
 }
 
 /* time in seconds when suspend began */
 static struct timespec timekeeping_suspend_time;
 
-static void update_sleep_time(struct timespec t)
-{
-       timekeeper.total_sleep_time = t;
-       timekeeper.offs_boot = timespec_to_ktime(t);
-}
-
 /**
  * __timekeeping_inject_sleeptime - Internal function to add sleep interval
  * @delta: pointer to a timespec delta value
@@ -677,13 +695,11 @@ static void __timekeeping_inject_sleeptime(struct timekeeper *tk,
                                        "sleep delta value!\n");
                return;
        }
-
        tk_xtime_add(tk, delta);
-       tk->wall_to_monotonic = timespec_sub(tk->wall_to_monotonic, *delta);
-       update_sleep_time(timespec_add(tk->total_sleep_time, *delta));
+       tk_set_wall_to_mono(tk, timespec_sub(tk->wall_to_monotonic, *delta));
+       tk_set_sleep_time(tk, timespec_add(tk->total_sleep_time, *delta));
 }
 
-
 /**
  * timekeeping_inject_sleeptime - Adds suspend interval to timeekeeping values
  * @delta: pointer to a timespec delta value
@@ -696,6 +712,7 @@ static void __timekeeping_inject_sleeptime(struct timekeeper *tk,
  */
 void timekeeping_inject_sleeptime(struct timespec *delta)
 {
+       struct timekeeper *tk = &timekeeper;
        unsigned long flags;
        struct timespec ts;
 
@@ -704,21 +721,20 @@ void timekeeping_inject_sleeptime(struct timespec *delta)
        if (!(ts.tv_sec == 0 && ts.tv_nsec == 0))
                return;
 
-       write_seqlock_irqsave(&timekeeper.lock, flags);
+       write_seqlock_irqsave(&tk->lock, flags);
 
-       timekeeping_forward_now(&timekeeper);
+       timekeeping_forward_now(tk);
 
-       __timekeeping_inject_sleeptime(&timekeeper, delta);
+       __timekeeping_inject_sleeptime(tk, delta);
 
-       timekeeping_update(&timekeeper, true);
+       timekeeping_update(tk, true);
 
-       write_sequnlock_irqrestore(&timekeeper.lock, flags);
+       write_sequnlock_irqrestore(&tk->lock, flags);
 
        /* signal hrtimers about time change */
        clock_was_set();
 }
 
-
 /**
  * timekeeping_resume - Resumes the generic timekeeping subsystem.
  *
@@ -728,25 +744,27 @@ void timekeeping_inject_sleeptime(struct timespec *delta)
  */
 static void timekeeping_resume(void)
 {
+       struct timekeeper *tk = &timekeeper;
        unsigned long flags;
        struct timespec ts;
 
        read_persistent_clock(&ts);
 
+       clockevents_resume();
        clocksource_resume();
 
-       write_seqlock_irqsave(&timekeeper.lock, flags);
+       write_seqlock_irqsave(&tk->lock, flags);
 
        if (timespec_compare(&ts, &timekeeping_suspend_time) > 0) {
                ts = timespec_sub(ts, timekeeping_suspend_time);
-               __timekeeping_inject_sleeptime(&timekeeper, &ts);
+               __timekeeping_inject_sleeptime(tk, &ts);
        }
        /* re-base the last cycle value */
-       timekeeper.clock->cycle_last = timekeeper.clock->read(timekeeper.clock);
-       timekeeper.ntp_error = 0;
+       tk->clock->cycle_last = tk->clock->read(tk->clock);
+       tk->ntp_error = 0;
        timekeeping_suspended = 0;
-       timekeeping_update(&timekeeper, false);
-       write_sequnlock_irqrestore(&timekeeper.lock, flags);
+       timekeeping_update(tk, false);
+       write_sequnlock_irqrestore(&tk->lock, flags);
 
        touch_softlockup_watchdog();
 
@@ -758,14 +776,15 @@ static void timekeeping_resume(void)
 
 static int timekeeping_suspend(void)
 {
+       struct timekeeper *tk = &timekeeper;
        unsigned long flags;
        struct timespec         delta, delta_delta;
        static struct timespec  old_delta;
 
        read_persistent_clock(&timekeeping_suspend_time);
 
-       write_seqlock_irqsave(&timekeeper.lock, flags);
-       timekeeping_forward_now(&timekeeper);
+       write_seqlock_irqsave(&tk->lock, flags);
+       timekeeping_forward_now(tk);
        timekeeping_suspended = 1;
 
        /*
@@ -774,7 +793,7 @@ static int timekeeping_suspend(void)
         * try to compensate so the difference in system time
         * and persistent_clock time stays close to constant.
         */
-       delta = timespec_sub(tk_xtime(&timekeeper), timekeeping_suspend_time);
+       delta = timespec_sub(tk_xtime(tk), timekeeping_suspend_time);
        delta_delta = timespec_sub(delta, old_delta);
        if (abs(delta_delta.tv_sec)  >= 2) {
                /*
@@ -787,10 +806,11 @@ static int timekeeping_suspend(void)
                timekeeping_suspend_time =
                        timespec_add(timekeeping_suspend_time, delta_delta);
        }
-       write_sequnlock_irqrestore(&timekeeper.lock, flags);
+       write_sequnlock_irqrestore(&tk->lock, flags);
 
        clockevents_notify(CLOCK_EVT_NOTIFY_SUSPEND, NULL);
        clocksource_suspend();
+       clockevents_suspend();
 
        return 0;
 }
@@ -898,27 +918,29 @@ static void timekeeping_adjust(struct timekeeper *tk, s64 offset)
                 * the error. This causes the likely below to be unlikely.
                 *
                 * The proper fix is to avoid rounding up by using
-                * the high precision timekeeper.xtime_nsec instead of
+                * the high precision tk->xtime_nsec instead of
                 * xtime.tv_nsec everywhere. Fixing this will take some
                 * time.
                 */
                if (likely(error <= interval))
                        adj = 1;
                else
-                       adj = timekeeping_bigadjust(tk, error, &interval,
-                                                       &offset);
-       } else if (error < -interval) {
-               /* See comment above, this is just switched for the negative */
-               error >>= 2;
-               if (likely(error >= -interval)) {
-                       adj = -1;
-                       interval = -interval;
-                       offset = -offset;
-               } else
-                       adj = timekeeping_bigadjust(tk, error, &interval,
-                                                       &offset);
-       } else
-               return;
+                       adj = timekeeping_bigadjust(tk, error, &interval, &offset);
+       } else {
+               if (error < -interval) {
+                       /* See comment above, this is just switched for the negative */
+                       error >>= 2;
+                       if (likely(error >= -interval)) {
+                               adj = -1;
+                               interval = -interval;
+                               offset = -offset;
+                       } else {
+                               adj = timekeeping_bigadjust(tk, error, &interval, &offset);
+                       }
+               } else {
+                       goto out_adjust;
+               }
+       }
 
        if (unlikely(tk->clock->maxadj &&
                (tk->mult + adj > tk->clock->mult + tk->clock->maxadj))) {
@@ -981,6 +1003,7 @@ static void timekeeping_adjust(struct timekeeper *tk, s64 offset)
        tk->xtime_nsec -= offset;
        tk->ntp_error -= (interval - offset) << tk->ntp_error_shift;
 
+out_adjust:
        /*
         * It may be possible that when we entered this function, xtime_nsec
         * was very small.  Further, if we're slightly speeding the clocksource
@@ -1003,7 +1026,6 @@ static void timekeeping_adjust(struct timekeeper *tk, s64 offset)
 
 }
 
-
 /**
  * accumulate_nsecs_to_secs - Accumulates nsecs into secs
  *
@@ -1024,15 +1046,21 @@ static inline void accumulate_nsecs_to_secs(struct timekeeper *tk)
 
                /* Figure out if its a leap sec and apply if needed */
                leap = second_overflow(tk->xtime_sec);
-               tk->xtime_sec += leap;
-               tk->wall_to_monotonic.tv_sec -= leap;
-               if (leap)
-                       clock_was_set_delayed();
+               if (unlikely(leap)) {
+                       struct timespec ts;
+
+                       tk->xtime_sec += leap;
+
+                       ts.tv_sec = leap;
+                       ts.tv_nsec = 0;
+                       tk_set_wall_to_mono(tk,
+                               timespec_sub(tk->wall_to_monotonic, ts));
 
+                       clock_was_set_delayed();
+               }
        }
 }
 
-
 /**
  * logarithmic_accumulation - shifted accumulation of cycles
  *
@@ -1076,7 +1104,6 @@ static cycle_t logarithmic_accumulation(struct timekeeper *tk, cycle_t offset,
        return offset;
 }
 
-
 /**
  * update_wall_time - Uses the current clocksource to increment the wall time
  *
@@ -1084,21 +1111,22 @@ static cycle_t logarithmic_accumulation(struct timekeeper *tk, cycle_t offset,
 static void update_wall_time(void)
 {
        struct clocksource *clock;
+       struct timekeeper *tk = &timekeeper;
        cycle_t offset;
        int shift = 0, maxshift;
        unsigned long flags;
        s64 remainder;
 
-       write_seqlock_irqsave(&timekeeper.lock, flags);
+       write_seqlock_irqsave(&tk->lock, flags);
 
        /* Make sure we're fully resumed: */
        if (unlikely(timekeeping_suspended))
                goto out;
 
-       clock = timekeeper.clock;
+       clock = tk->clock;
 
 #ifdef CONFIG_ARCH_USES_GETTIMEOFFSET
-       offset = timekeeper.cycle_interval;
+       offset = tk->cycle_interval;
 #else
        offset = (clock->read(clock) - clock->cycle_last) & clock->mask;
 #endif
@@ -1111,19 +1139,19 @@ static void update_wall_time(void)
         * chunk in one go, and then try to consume the next smaller
         * doubled multiple.
         */
-       shift = ilog2(offset) - ilog2(timekeeper.cycle_interval);
+       shift = ilog2(offset) - ilog2(tk->cycle_interval);
        shift = max(0, shift);
        /* Bound shift to one less than what overflows tick_length */
        maxshift = (64 - (ilog2(ntp_tick_length())+1)) - 1;
        shift = min(shift, maxshift);
-       while (offset >= timekeeper.cycle_interval) {
-               offset = logarithmic_accumulation(&timekeeper, offset, shift);
-               if(offset < timekeeper.cycle_interval<<shift)
+       while (offset >= tk->cycle_interval) {
+               offset = logarithmic_accumulation(tk, offset, shift);
+               if (offset < tk->cycle_interval<<shift)
                        shift--;
        }
 
        /* correct the clock when NTP error is too big */
-       timekeeping_adjust(&timekeeper, offset);
+       timekeeping_adjust(tk, offset);
 
 
        /*
@@ -1135,21 +1163,21 @@ static void update_wall_time(void)
        * the vsyscall implementations are converted to use xtime_nsec
        * (shifted nanoseconds), this can be killed.
        */
-       remainder = timekeeper.xtime_nsec & ((1 << timekeeper.shift) - 1);
-       timekeeper.xtime_nsec -= remainder;
-       timekeeper.xtime_nsec += 1 << timekeeper.shift;
-       timekeeper.ntp_error += remainder << timekeeper.ntp_error_shift;
+       remainder = tk->xtime_nsec & ((1 << tk->shift) - 1);
+       tk->xtime_nsec -= remainder;
+       tk->xtime_nsec += 1 << tk->shift;
+       tk->ntp_error += remainder << tk->ntp_error_shift;
 
        /*
         * Finally, make sure that after the rounding
         * xtime_nsec isn't larger than NSEC_PER_SEC
         */
-       accumulate_nsecs_to_secs(&timekeeper);
+       accumulate_nsecs_to_secs(tk);
 
-       timekeeping_update(&timekeeper, false);
+       timekeeping_update(tk, false);
 
 out:
-       write_sequnlock_irqrestore(&timekeeper.lock, flags);
+       write_sequnlock_irqrestore(&tk->lock, flags);
 
 }
 
@@ -1166,18 +1194,18 @@ out:
  */
 void getboottime(struct timespec *ts)
 {
+       struct timekeeper *tk = &timekeeper;
        struct timespec boottime = {
-               .tv_sec = timekeeper.wall_to_monotonic.tv_sec +
-                               timekeeper.total_sleep_time.tv_sec,
-               .tv_nsec = timekeeper.wall_to_monotonic.tv_nsec +
-                               timekeeper.total_sleep_time.tv_nsec
+               .tv_sec = tk->wall_to_monotonic.tv_sec +
+                               tk->total_sleep_time.tv_sec,
+               .tv_nsec = tk->wall_to_monotonic.tv_nsec +
+                               tk->total_sleep_time.tv_nsec
        };
 
        set_normalized_timespec(ts, -boottime.tv_sec, -boottime.tv_nsec);
 }
 EXPORT_SYMBOL_GPL(getboottime);
 
-
 /**
  * get_monotonic_boottime - Returns monotonic time since boot
  * @ts:                pointer to the timespec to be set
@@ -1189,19 +1217,20 @@ EXPORT_SYMBOL_GPL(getboottime);
  */
 void get_monotonic_boottime(struct timespec *ts)
 {
+       struct timekeeper *tk = &timekeeper;
        struct timespec tomono, sleep;
        unsigned int seq;
 
        WARN_ON(timekeeping_suspended);
 
        do {
-               seq = read_seqbegin(&timekeeper.lock);
-               ts->tv_sec = timekeeper.xtime_sec;
-               ts->tv_nsec = timekeeping_get_ns(&timekeeper);
-               tomono = timekeeper.wall_to_monotonic;
-               sleep = timekeeper.total_sleep_time;
+               seq = read_seqbegin(&tk->lock);
+               ts->tv_sec = tk->xtime_sec;
+               ts->tv_nsec = timekeeping_get_ns(tk);
+               tomono = tk->wall_to_monotonic;
+               sleep = tk->total_sleep_time;
 
-       } while (read_seqretry(&timekeeper.lock, seq));
+       } while (read_seqretry(&tk->lock, seq));
 
        set_normalized_timespec(ts, ts->tv_sec + tomono.tv_sec + sleep.tv_sec,
                        ts->tv_nsec + tomono.tv_nsec + sleep.tv_nsec);
@@ -1231,31 +1260,38 @@ EXPORT_SYMBOL_GPL(ktime_get_boottime);
  */
 void monotonic_to_bootbased(struct timespec *ts)
 {
-       *ts = timespec_add(*ts, timekeeper.total_sleep_time);
+       struct timekeeper *tk = &timekeeper;
+
+       *ts = timespec_add(*ts, tk->total_sleep_time);
 }
 EXPORT_SYMBOL_GPL(monotonic_to_bootbased);
 
 unsigned long get_seconds(void)
 {
-       return timekeeper.xtime_sec;
+       struct timekeeper *tk = &timekeeper;
+
+       return tk->xtime_sec;
 }
 EXPORT_SYMBOL(get_seconds);
 
 struct timespec __current_kernel_time(void)
 {
-       return tk_xtime(&timekeeper);
+       struct timekeeper *tk = &timekeeper;
+
+       return tk_xtime(tk);
 }
 
 struct timespec current_kernel_time(void)
 {
+       struct timekeeper *tk = &timekeeper;
        struct timespec now;
        unsigned long seq;
 
        do {
-               seq = read_seqbegin(&timekeeper.lock);
+               seq = read_seqbegin(&tk->lock);
 
-               now = tk_xtime(&timekeeper);
-       } while (read_seqretry(&timekeeper.lock, seq));
+               now = tk_xtime(tk);
+       } while (read_seqretry(&tk->lock, seq));
 
        return now;
 }
@@ -1263,15 +1299,16 @@ EXPORT_SYMBOL(current_kernel_time);
 
 struct timespec get_monotonic_coarse(void)
 {
+       struct timekeeper *tk = &timekeeper;
        struct timespec now, mono;
        unsigned long seq;
 
        do {
-               seq = read_seqbegin(&timekeeper.lock);
+               seq = read_seqbegin(&tk->lock);
 
-               now = tk_xtime(&timekeeper);
-               mono = timekeeper.wall_to_monotonic;
-       } while (read_seqretry(&timekeeper.lock, seq));
+               now = tk_xtime(tk);
+               mono = tk->wall_to_monotonic;
+       } while (read_seqretry(&tk->lock, seq));
 
        set_normalized_timespec(&now, now.tv_sec + mono.tv_sec,
                                now.tv_nsec + mono.tv_nsec);
@@ -1300,14 +1337,15 @@ void do_timer(unsigned long ticks)
 void get_xtime_and_monotonic_and_sleep_offset(struct timespec *xtim,
                                struct timespec *wtom, struct timespec *sleep)
 {
+       struct timekeeper *tk = &timekeeper;
        unsigned long seq;
 
        do {
-               seq = read_seqbegin(&timekeeper.lock);
-               *xtim = tk_xtime(&timekeeper);
-               *wtom = timekeeper.wall_to_monotonic;
-               *sleep = timekeeper.total_sleep_time;
-       } while (read_seqretry(&timekeeper.lock, seq));
+               seq = read_seqbegin(&tk->lock);
+               *xtim = tk_xtime(tk);
+               *wtom = tk->wall_to_monotonic;
+               *sleep = tk->total_sleep_time;
+       } while (read_seqretry(&tk->lock, seq));
 }
 
 #ifdef CONFIG_HIGH_RES_TIMERS
@@ -1321,19 +1359,20 @@ void get_xtime_and_monotonic_and_sleep_offset(struct timespec *xtim,
  */
 ktime_t ktime_get_update_offsets(ktime_t *offs_real, ktime_t *offs_boot)
 {
+       struct timekeeper *tk = &timekeeper;
        ktime_t now;
        unsigned int seq;
        u64 secs, nsecs;
 
        do {
-               seq = read_seqbegin(&timekeeper.lock);
+               seq = read_seqbegin(&tk->lock);
 
-               secs = timekeeper.xtime_sec;
-               nsecs = timekeeping_get_ns(&timekeeper);
+               secs = tk->xtime_sec;
+               nsecs = timekeeping_get_ns(tk);
 
-               *offs_real = timekeeper.offs_real;
-               *offs_boot = timekeeper.offs_boot;
-       } while (read_seqretry(&timekeeper.lock, seq));
+               *offs_real = tk->offs_real;
+               *offs_boot = tk->offs_boot;
+       } while (read_seqretry(&tk->lock, seq));
 
        now = ktime_add_ns(ktime_set(secs, 0), nsecs);
        now = ktime_sub(now, *offs_real);
@@ -1346,19 +1385,19 @@ ktime_t ktime_get_update_offsets(ktime_t *offs_real, ktime_t *offs_boot)
  */
 ktime_t ktime_get_monotonic_offset(void)
 {
+       struct timekeeper *tk = &timekeeper;
        unsigned long seq;
        struct timespec wtom;
 
        do {
-               seq = read_seqbegin(&timekeeper.lock);
-               wtom = timekeeper.wall_to_monotonic;
-       } while (read_seqretry(&timekeeper.lock, seq));
+               seq = read_seqbegin(&tk->lock);
+               wtom = tk->wall_to_monotonic;
+       } while (read_seqretry(&tk->lock, seq));
 
        return timespec_to_ktime(wtom);
 }
 EXPORT_SYMBOL_GPL(ktime_get_monotonic_offset);
 
-
 /**
  * xtime_update() - advances the timekeeping infrastructure
  * @ticks:     number of ticks, that have elapsed since the last call.
index fee3752ae8f66f5348199c67b6ad05c5a41346f5..8a6d2ee2086c2cd721dc29ae92d23082370e10db 100644 (file)
@@ -281,7 +281,7 @@ perf_ftrace_function_call(unsigned long ip, unsigned long parent_ip)
 
        head = this_cpu_ptr(event_function.perf_events);
        perf_trace_buf_submit(entry, ENTRY_SIZE, rctx, 0,
-                             1, &regs, head);
+                             1, &regs, head, NULL);
 
 #undef ENTRY_SIZE
 }
index b31d3d5699fea09c235ace4c47e16fc8fb8785e0..1a2117043bb140d06b366d8d6e0798bb69fcad26 100644 (file)
@@ -1002,7 +1002,8 @@ static __kprobes void kprobe_perf_func(struct kprobe *kp,
        store_trace_args(sizeof(*entry), tp, regs, (u8 *)&entry[1], dsize);
 
        head = this_cpu_ptr(call->perf_events);
-       perf_trace_buf_submit(entry, size, rctx, entry->ip, 1, regs, head);
+       perf_trace_buf_submit(entry, size, rctx,
+                                       entry->ip, 1, regs, head, NULL);
 }
 
 /* Kretprobe profile handler */
@@ -1033,7 +1034,8 @@ static __kprobes void kretprobe_perf_func(struct kretprobe_instance *ri,
        store_trace_args(sizeof(*entry), tp, regs, (u8 *)&entry[1], dsize);
 
        head = this_cpu_ptr(call->perf_events);
-       perf_trace_buf_submit(entry, size, rctx, entry->ret_ip, 1, regs, head);
+       perf_trace_buf_submit(entry, size, rctx,
+                                       entry->ret_ip, 1, regs, head, NULL);
 }
 #endif /* CONFIG_PERF_EVENTS */
 
index 96fc733690992bf97dc610c87ff2a6b0ecbb97d8..60e4d78756723189b95d11390bc566a6578a4bbe 100644 (file)
@@ -532,7 +532,7 @@ static void perf_syscall_enter(void *ignore, struct pt_regs *regs, long id)
                               (unsigned long *)&rec->args);
 
        head = this_cpu_ptr(sys_data->enter_event->perf_events);
-       perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head);
+       perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head, NULL);
 }
 
 int perf_sysenter_enable(struct ftrace_event_call *call)
@@ -608,7 +608,7 @@ static void perf_syscall_exit(void *ignore, struct pt_regs *regs, long ret)
        rec->ret = syscall_get_return_value(current, regs);
 
        head = this_cpu_ptr(sys_data->exit_event->perf_events);
-       perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head);
+       perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head, NULL);
 }
 
 int perf_sysexit_enable(struct ftrace_event_call *call)
index 2b36ac68549e2e23d148c81b7905407d344fdc80..03003cd7dd962d1ca31b2574f9d09f77a74f47a4 100644 (file)
@@ -670,7 +670,7 @@ static void uprobe_perf_func(struct trace_uprobe *tu, struct pt_regs *regs)
                call_fetch(&tu->args[i].fetch, regs, data + tu->args[i].offset);
 
        head = this_cpu_ptr(call->perf_events);
-       perf_trace_buf_submit(entry, size, rctx, entry->ip, 1, regs, head);
+       perf_trace_buf_submit(entry, size, rctx, entry->ip, 1, regs, head, NULL);
 
  out:
        preempt_enable();
index 69add8a9da686a326be90e45aa09ab8427a24875..4b1dfba70f7cf8ae7397623656a9b695028f702a 100644 (file)
@@ -575,7 +575,7 @@ out:
 /*
  * Create/destroy watchdog threads as CPUs come and go:
  */
-static int
+static int __cpuinit
 cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
 {
        int hotcpu = (unsigned long)hcpu;
@@ -610,27 +610,10 @@ cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
        return NOTIFY_OK;
 }
 
-static struct notifier_block cpu_nfb = {
+static struct notifier_block __cpuinitdata cpu_nfb = {
        .notifier_call = cpu_callback
 };
 
-#ifdef CONFIG_SUSPEND
-/*
- * On exit from suspend we force an offline->online transition on the boot CPU
- * so that the PMU state that was lost while in suspended state gets set up
- * properly for the boot CPU.  This information is required for restarting the
- * NMI watchdog.
- */
-void lockup_detector_bootcpu_resume(void)
-{
-       void *cpu = (void *)(long)smp_processor_id();
-
-       cpu_callback(&cpu_nfb, CPU_DEAD_FROZEN, cpu);
-       cpu_callback(&cpu_nfb, CPU_UP_PREPARE_FROZEN, cpu);
-       cpu_callback(&cpu_nfb, CPU_ONLINE_FROZEN, cpu);
-}
-#endif
-
 void __init lockup_detector_init(void)
 {
        void *cpu = (void *)(long)smp_processor_id();
index 692d97628a106360683dfef46797952cdf1861e1..7da24711038fa7035d8383b9c96f52c9496e157b 100644 (file)
@@ -183,7 +183,8 @@ struct global_cwq {
        struct hlist_head       busy_hash[BUSY_WORKER_HASH_SIZE];
                                                /* L: hash of busy workers */
 
-       struct worker_pool      pools[2];       /* normal and highpri pools */
+       struct worker_pool      pools[NR_WORKER_POOLS];
+                                               /* normal and highpri pools */
 
        wait_queue_head_t       rebind_hold;    /* rebind hold wait */
 } ____cacheline_aligned_in_smp;
@@ -268,12 +269,14 @@ struct workqueue_struct {
 };
 
 struct workqueue_struct *system_wq __read_mostly;
+struct workqueue_struct *system_highpri_wq __read_mostly;
 struct workqueue_struct *system_long_wq __read_mostly;
 struct workqueue_struct *system_nrt_wq __read_mostly;
 struct workqueue_struct *system_unbound_wq __read_mostly;
 struct workqueue_struct *system_freezable_wq __read_mostly;
 struct workqueue_struct *system_nrt_freezable_wq __read_mostly;
 EXPORT_SYMBOL_GPL(system_wq);
+EXPORT_SYMBOL_GPL(system_highpri_wq);
 EXPORT_SYMBOL_GPL(system_long_wq);
 EXPORT_SYMBOL_GPL(system_nrt_wq);
 EXPORT_SYMBOL_GPL(system_unbound_wq);
@@ -533,18 +536,24 @@ static int work_next_color(int color)
 }
 
 /*
- * A work's data points to the cwq with WORK_STRUCT_CWQ set while the
- * work is on queue.  Once execution starts, WORK_STRUCT_CWQ is
- * cleared and the work data contains the cpu number it was last on.
+ * While queued, %WORK_STRUCT_CWQ is set and non flag bits of a work's data
+ * contain the pointer to the queued cwq.  Once execution starts, the flag
+ * is cleared and the high bits contain OFFQ flags and CPU number.
  *
- * set_work_{cwq|cpu}() and clear_work_data() can be used to set the
- * cwq, cpu or clear work->data.  These functions should only be
- * called while the work is owned - ie. while the PENDING bit is set.
+ * set_work_cwq(), set_work_cpu_and_clear_pending(), mark_work_canceling()
+ * and clear_work_data() can be used to set the cwq, cpu or clear
+ * work->data.  These functions should only be called while the work is
+ * owned - ie. while the PENDING bit is set.
  *
- * get_work_[g]cwq() can be used to obtain the gcwq or cwq
- * corresponding to a work.  gcwq is available once the work has been
- * queued anywhere after initialization.  cwq is available only from
- * queueing until execution starts.
+ * get_work_[g]cwq() can be used to obtain the gcwq or cwq corresponding to
+ * a work.  gcwq is available once the work has been queued anywhere after
+ * initialization until it is sync canceled.  cwq is available only while
+ * the work item is queued.
+ *
+ * %WORK_OFFQ_CANCELING is used to mark a work item which is being
+ * canceled.  While being canceled, a work item may have its PENDING set
+ * but stay off timer and worklist for arbitrarily long and nobody should
+ * try to steal the PENDING bit.
  */
 static inline void set_work_data(struct work_struct *work, unsigned long data,
                                 unsigned long flags)
@@ -561,13 +570,22 @@ static void set_work_cwq(struct work_struct *work,
                      WORK_STRUCT_PENDING | WORK_STRUCT_CWQ | extra_flags);
 }
 
-static void set_work_cpu(struct work_struct *work, unsigned int cpu)
+static void set_work_cpu_and_clear_pending(struct work_struct *work,
+                                          unsigned int cpu)
 {
-       set_work_data(work, cpu << WORK_STRUCT_FLAG_BITS, WORK_STRUCT_PENDING);
+       /*
+        * The following wmb is paired with the implied mb in
+        * test_and_set_bit(PENDING) and ensures all updates to @work made
+        * here are visible to and precede any updates by the next PENDING
+        * owner.
+        */
+       smp_wmb();
+       set_work_data(work, (unsigned long)cpu << WORK_OFFQ_CPU_SHIFT, 0);
 }
 
 static void clear_work_data(struct work_struct *work)
 {
+       smp_wmb();      /* see set_work_cpu_and_clear_pending() */
        set_work_data(work, WORK_STRUCT_NO_CPU, 0);
 }
 
@@ -590,7 +608,7 @@ static struct global_cwq *get_work_gcwq(struct work_struct *work)
                return ((struct cpu_workqueue_struct *)
                        (data & WORK_STRUCT_WQ_DATA_MASK))->pool->gcwq;
 
-       cpu = data >> WORK_STRUCT_FLAG_BITS;
+       cpu = data >> WORK_OFFQ_CPU_SHIFT;
        if (cpu == WORK_CPU_NONE)
                return NULL;
 
@@ -598,6 +616,22 @@ static struct global_cwq *get_work_gcwq(struct work_struct *work)
        return get_gcwq(cpu);
 }
 
+static void mark_work_canceling(struct work_struct *work)
+{
+       struct global_cwq *gcwq = get_work_gcwq(work);
+       unsigned long cpu = gcwq ? gcwq->cpu : WORK_CPU_NONE;
+
+       set_work_data(work, (cpu << WORK_OFFQ_CPU_SHIFT) | WORK_OFFQ_CANCELING,
+                     WORK_STRUCT_PENDING);
+}
+
+static bool work_is_canceling(struct work_struct *work)
+{
+       unsigned long data = atomic_long_read(&work->data);
+
+       return !(data & WORK_STRUCT_CWQ) && (data & WORK_OFFQ_CANCELING);
+}
+
 /*
  * Policy functions.  These define the policies on how the global worker
  * pools are managed.  Unless noted otherwise, these functions assume that
@@ -901,6 +935,191 @@ static struct worker *find_worker_executing_work(struct global_cwq *gcwq,
                                            work);
 }
 
+/**
+ * move_linked_works - move linked works to a list
+ * @work: start of series of works to be scheduled
+ * @head: target list to append @work to
+ * @nextp: out paramter for nested worklist walking
+ *
+ * Schedule linked works starting from @work to @head.  Work series to
+ * be scheduled starts at @work and includes any consecutive work with
+ * WORK_STRUCT_LINKED set in its predecessor.
+ *
+ * If @nextp is not NULL, it's updated to point to the next work of
+ * the last scheduled work.  This allows move_linked_works() to be
+ * nested inside outer list_for_each_entry_safe().
+ *
+ * CONTEXT:
+ * spin_lock_irq(gcwq->lock).
+ */
+static void move_linked_works(struct work_struct *work, struct list_head *head,
+                             struct work_struct **nextp)
+{
+       struct work_struct *n;
+
+       /*
+        * Linked worklist will always end before the end of the list,
+        * use NULL for list head.
+        */
+       list_for_each_entry_safe_from(work, n, NULL, entry) {
+               list_move_tail(&work->entry, head);
+               if (!(*work_data_bits(work) & WORK_STRUCT_LINKED))
+                       break;
+       }
+
+       /*
+        * If we're already inside safe list traversal and have moved
+        * multiple works to the scheduled queue, the next position
+        * needs to be updated.
+        */
+       if (nextp)
+               *nextp = n;
+}
+
+static void cwq_activate_first_delayed(struct cpu_workqueue_struct *cwq)
+{
+       struct work_struct *work = list_first_entry(&cwq->delayed_works,
+                                                   struct work_struct, entry);
+
+       trace_workqueue_activate_work(work);
+       move_linked_works(work, &cwq->pool->worklist, NULL);
+       __clear_bit(WORK_STRUCT_DELAYED_BIT, work_data_bits(work));
+       cwq->nr_active++;
+}
+
+/**
+ * cwq_dec_nr_in_flight - decrement cwq's nr_in_flight
+ * @cwq: cwq of interest
+ * @color: color of work which left the queue
+ * @delayed: for a delayed work
+ *
+ * A work either has completed or is removed from pending queue,
+ * decrement nr_in_flight of its cwq and handle workqueue flushing.
+ *
+ * CONTEXT:
+ * spin_lock_irq(gcwq->lock).
+ */
+static void cwq_dec_nr_in_flight(struct cpu_workqueue_struct *cwq, int color,
+                                bool delayed)
+{
+       /* ignore uncolored works */
+       if (color == WORK_NO_COLOR)
+               return;
+
+       cwq->nr_in_flight[color]--;
+
+       if (!delayed) {
+               cwq->nr_active--;
+               if (!list_empty(&cwq->delayed_works)) {
+                       /* one down, submit a delayed one */
+                       if (cwq->nr_active < cwq->max_active)
+                               cwq_activate_first_delayed(cwq);
+               }
+       }
+
+       /* is flush in progress and are we at the flushing tip? */
+       if (likely(cwq->flush_color != color))
+               return;
+
+       /* are there still in-flight works? */
+       if (cwq->nr_in_flight[color])
+               return;
+
+       /* this cwq is done, clear flush_color */
+       cwq->flush_color = -1;
+
+       /*
+        * If this was the last cwq, wake up the first flusher.  It
+        * will handle the rest.
+        */
+       if (atomic_dec_and_test(&cwq->wq->nr_cwqs_to_flush))
+               complete(&cwq->wq->first_flusher->done);
+}
+
+/**
+ * try_to_grab_pending - steal work item from worklist and disable irq
+ * @work: work item to steal
+ * @is_dwork: @work is a delayed_work
+ * @flags: place to store irq state
+ *
+ * Try to grab PENDING bit of @work.  This function can handle @work in any
+ * stable state - idle, on timer or on worklist.  Return values are
+ *
+ *  1          if @work was pending and we successfully stole PENDING
+ *  0          if @work was idle and we claimed PENDING
+ *  -EAGAIN    if PENDING couldn't be grabbed at the moment, safe to busy-retry
+ *  -ENOENT    if someone else is canceling @work, this state may persist
+ *             for arbitrarily long
+ *
+ * On >= 0 return, the caller owns @work's PENDING bit.  To avoid getting
+ * preempted while holding PENDING and @work off queue, preemption must be
+ * disabled on entry.  This ensures that we don't return -EAGAIN while
+ * another task is preempted in this function.
+ *
+ * On successful return, >= 0, irq is disabled and the caller is
+ * responsible for releasing it using local_irq_restore(*@flags).
+ *
+ * This function is safe to call from any context other than IRQ handler.
+ * An IRQ handler may run on top of delayed_work_timer_fn() which can make
+ * this function return -EAGAIN perpetually.
+ */
+static int try_to_grab_pending(struct work_struct *work, bool is_dwork,
+                              unsigned long *flags)
+{
+       struct global_cwq *gcwq;
+
+       WARN_ON_ONCE(in_irq());
+
+       local_irq_save(*flags);
+
+       /* try to steal the timer if it exists */
+       if (is_dwork) {
+               struct delayed_work *dwork = to_delayed_work(work);
+
+               if (likely(del_timer(&dwork->timer)))
+                       return 1;
+       }
+
+       /* try to claim PENDING the normal way */
+       if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work)))
+               return 0;
+
+       /*
+        * The queueing is in progress, or it is already queued. Try to
+        * steal it from ->worklist without clearing WORK_STRUCT_PENDING.
+        */
+       gcwq = get_work_gcwq(work);
+       if (!gcwq)
+               goto fail;
+
+       spin_lock(&gcwq->lock);
+       if (!list_empty(&work->entry)) {
+               /*
+                * This work is queued, but perhaps we locked the wrong gcwq.
+                * In that case we must see the new value after rmb(), see
+                * insert_work()->wmb().
+                */
+               smp_rmb();
+               if (gcwq == get_work_gcwq(work)) {
+                       debug_work_deactivate(work);
+                       list_del_init(&work->entry);
+                       cwq_dec_nr_in_flight(get_work_cwq(work),
+                               get_work_color(work),
+                               *work_data_bits(work) & WORK_STRUCT_DELAYED);
+
+                       spin_unlock(&gcwq->lock);
+                       return 1;
+               }
+       }
+       spin_unlock(&gcwq->lock);
+fail:
+       local_irq_restore(*flags);
+       if (work_is_canceling(work))
+               return -ENOENT;
+       cpu_relax();
+       return -EAGAIN;
+}
+
 /**
  * insert_work - insert a work into gcwq
  * @cwq: cwq @work belongs to
@@ -981,7 +1200,15 @@ static void __queue_work(unsigned int cpu, struct workqueue_struct *wq,
        struct cpu_workqueue_struct *cwq;
        struct list_head *worklist;
        unsigned int work_flags;
-       unsigned long flags;
+       unsigned int req_cpu = cpu;
+
+       /*
+        * While a work item is PENDING && off queue, a task trying to
+        * steal the PENDING will busy-loop waiting for it to either get
+        * queued or lose PENDING.  Grabbing PENDING and queueing should
+        * happen with IRQ disabled.
+        */
+       WARN_ON_ONCE(!irqs_disabled());
 
        debug_work_activate(work);
 
@@ -994,7 +1221,7 @@ static void __queue_work(unsigned int cpu, struct workqueue_struct *wq,
        if (!(wq->flags & WQ_UNBOUND)) {
                struct global_cwq *last_gcwq;
 
-               if (unlikely(cpu == WORK_CPU_UNBOUND))
+               if (cpu == WORK_CPU_UNBOUND)
                        cpu = raw_smp_processor_id();
 
                /*
@@ -1008,7 +1235,7 @@ static void __queue_work(unsigned int cpu, struct workqueue_struct *wq,
                    (last_gcwq = get_work_gcwq(work)) && last_gcwq != gcwq) {
                        struct worker *worker;
 
-                       spin_lock_irqsave(&last_gcwq->lock, flags);
+                       spin_lock(&last_gcwq->lock);
 
                        worker = find_worker_executing_work(last_gcwq, work);
 
@@ -1016,22 +1243,23 @@ static void __queue_work(unsigned int cpu, struct workqueue_struct *wq,
                                gcwq = last_gcwq;
                        else {
                                /* meh... not running there, queue here */
-                               spin_unlock_irqrestore(&last_gcwq->lock, flags);
-                               spin_lock_irqsave(&gcwq->lock, flags);
+                               spin_unlock(&last_gcwq->lock);
+                               spin_lock(&gcwq->lock);
                        }
-               } else
-                       spin_lock_irqsave(&gcwq->lock, flags);
+               } else {
+                       spin_lock(&gcwq->lock);
+               }
        } else {
                gcwq = get_gcwq(WORK_CPU_UNBOUND);
-               spin_lock_irqsave(&gcwq->lock, flags);
+               spin_lock(&gcwq->lock);
        }
 
        /* gcwq determined, get cwq and queue */
        cwq = get_cwq(gcwq->cpu, wq);
-       trace_workqueue_queue_work(cpu, cwq, work);
+       trace_workqueue_queue_work(req_cpu, cwq, work);
 
        if (WARN_ON(!list_empty(&work->entry))) {
-               spin_unlock_irqrestore(&gcwq->lock, flags);
+               spin_unlock(&gcwq->lock);
                return;
        }
 
@@ -1049,79 +1277,111 @@ static void __queue_work(unsigned int cpu, struct workqueue_struct *wq,
 
        insert_work(cwq, work, worklist, work_flags);
 
-       spin_unlock_irqrestore(&gcwq->lock, flags);
+       spin_unlock(&gcwq->lock);
 }
 
 /**
- * queue_work - queue work on a workqueue
+ * queue_work_on - queue work on specific cpu
+ * @cpu: CPU number to execute work on
  * @wq: workqueue to use
  * @work: work to queue
  *
- * Returns 0 if @work was already on a queue, non-zero otherwise.
+ * Returns %false if @work was already on a queue, %true otherwise.
  *
- * We queue the work to the CPU on which it was submitted, but if the CPU dies
- * it can be processed by another CPU.
+ * We queue the work to a specific CPU, the caller must ensure it
+ * can't go away.
  */
-int queue_work(struct workqueue_struct *wq, struct work_struct *work)
+bool queue_work_on(int cpu, struct workqueue_struct *wq,
+                  struct work_struct *work)
 {
-       int ret;
+       bool ret = false;
+       unsigned long flags;
+
+       local_irq_save(flags);
 
-       ret = queue_work_on(get_cpu(), wq, work);
-       put_cpu();
+       if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))) {
+               __queue_work(cpu, wq, work);
+               ret = true;
+       }
 
+       local_irq_restore(flags);
        return ret;
 }
-EXPORT_SYMBOL_GPL(queue_work);
+EXPORT_SYMBOL_GPL(queue_work_on);
 
 /**
- * queue_work_on - queue work on specific cpu
- * @cpu: CPU number to execute work on
+ * queue_work - queue work on a workqueue
  * @wq: workqueue to use
  * @work: work to queue
  *
- * Returns 0 if @work was already on a queue, non-zero otherwise.
+ * Returns %false if @work was already on a queue, %true otherwise.
  *
- * We queue the work to a specific CPU, the caller must ensure it
- * can't go away.
+ * We queue the work to the CPU on which it was submitted, but if the CPU dies
+ * it can be processed by another CPU.
  */
-int
-queue_work_on(int cpu, struct workqueue_struct *wq, struct work_struct *work)
+bool queue_work(struct workqueue_struct *wq, struct work_struct *work)
 {
-       int ret = 0;
-
-       if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))) {
-               __queue_work(cpu, wq, work);
-               ret = 1;
-       }
-       return ret;
+       return queue_work_on(WORK_CPU_UNBOUND, wq, work);
 }
-EXPORT_SYMBOL_GPL(queue_work_on);
+EXPORT_SYMBOL_GPL(queue_work);
 
-static void delayed_work_timer_fn(unsigned long __data)
+void delayed_work_timer_fn(unsigned long __data)
 {
        struct delayed_work *dwork = (struct delayed_work *)__data;
        struct cpu_workqueue_struct *cwq = get_work_cwq(&dwork->work);
 
-       __queue_work(smp_processor_id(), cwq->wq, &dwork->work);
+       local_irq_disable();
+       __queue_work(dwork->cpu, cwq->wq, &dwork->work);
+       local_irq_enable();
 }
+EXPORT_SYMBOL_GPL(delayed_work_timer_fn);
 
-/**
- * queue_delayed_work - queue work on a workqueue after delay
- * @wq: workqueue to use
- * @dwork: delayable work to queue
- * @delay: number of jiffies to wait before queueing
- *
- * Returns 0 if @work was already on a queue, non-zero otherwise.
- */
-int queue_delayed_work(struct workqueue_struct *wq,
-                       struct delayed_work *dwork, unsigned long delay)
+static void __queue_delayed_work(int cpu, struct workqueue_struct *wq,
+                               struct delayed_work *dwork, unsigned long delay)
 {
-       if (delay == 0)
-               return queue_work(wq, &dwork->work);
+       struct timer_list *timer = &dwork->timer;
+       struct work_struct *work = &dwork->work;
+       unsigned int lcpu;
+
+       WARN_ON_ONCE(timer->function != delayed_work_timer_fn ||
+                    timer->data != (unsigned long)dwork);
+       BUG_ON(timer_pending(timer));
+       BUG_ON(!list_empty(&work->entry));
+
+       timer_stats_timer_set_start_info(&dwork->timer);
+
+       /*
+        * This stores cwq for the moment, for the timer_fn.  Note that the
+        * work's gcwq is preserved to allow reentrance detection for
+        * delayed works.
+        */
+       if (!(wq->flags & WQ_UNBOUND)) {
+               struct global_cwq *gcwq = get_work_gcwq(work);
+
+               /*
+                * If we cannot get the last gcwq from @work directly,
+                * select the last CPU such that it avoids unnecessarily
+                * triggering non-reentrancy check in __queue_work().
+                */
+               lcpu = cpu;
+               if (gcwq)
+                       lcpu = gcwq->cpu;
+               if (lcpu == WORK_CPU_UNBOUND)
+                       lcpu = raw_smp_processor_id();
+       } else {
+               lcpu = WORK_CPU_UNBOUND;
+       }
 
-       return queue_delayed_work_on(-1, wq, dwork, delay);
+       set_work_cwq(work, get_cwq(lcpu, wq), 0);
+
+       dwork->cpu = cpu;
+       timer->expires = jiffies + delay;
+
+       if (unlikely(cpu != WORK_CPU_UNBOUND))
+               add_timer_on(timer, cpu);
+       else
+               add_timer(timer);
 }
-EXPORT_SYMBOL_GPL(queue_delayed_work);
 
 /**
  * queue_delayed_work_on - queue work on specific CPU after delay
@@ -1130,53 +1390,100 @@ EXPORT_SYMBOL_GPL(queue_delayed_work);
  * @dwork: work to queue
  * @delay: number of jiffies to wait before queueing
  *
- * Returns 0 if @work was already on a queue, non-zero otherwise.
+ * Returns %false if @work was already on a queue, %true otherwise.  If
+ * @delay is zero and @dwork is idle, it will be scheduled for immediate
+ * execution.
  */
-int queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
-                       struct delayed_work *dwork, unsigned long delay)
+bool queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
+                          struct delayed_work *dwork, unsigned long delay)
 {
-       int ret = 0;
-       struct timer_list *timer = &dwork->timer;
        struct work_struct *work = &dwork->work;
+       bool ret = false;
+       unsigned long flags;
 
-       if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))) {
-               unsigned int lcpu;
+       if (!delay)
+               return queue_work_on(cpu, wq, &dwork->work);
 
-               BUG_ON(timer_pending(timer));
-               BUG_ON(!list_empty(&work->entry));
+       /* read the comment in __queue_work() */
+       local_irq_save(flags);
 
-               timer_stats_timer_set_start_info(&dwork->timer);
+       if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))) {
+               __queue_delayed_work(cpu, wq, dwork, delay);
+               ret = true;
+       }
 
-               /*
-                * This stores cwq for the moment, for the timer_fn.
-                * Note that the work's gcwq is preserved to allow
-                * reentrance detection for delayed works.
-                */
-               if (!(wq->flags & WQ_UNBOUND)) {
-                       struct global_cwq *gcwq = get_work_gcwq(work);
+       local_irq_restore(flags);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(queue_delayed_work_on);
 
-                       if (gcwq && gcwq->cpu != WORK_CPU_UNBOUND)
-                               lcpu = gcwq->cpu;
-                       else
-                               lcpu = raw_smp_processor_id();
-               } else
-                       lcpu = WORK_CPU_UNBOUND;
+/**
+ * queue_delayed_work - queue work on a workqueue after delay
+ * @wq: workqueue to use
+ * @dwork: delayable work to queue
+ * @delay: number of jiffies to wait before queueing
+ *
+ * Equivalent to queue_delayed_work_on() but tries to use the local CPU.
+ */
+bool queue_delayed_work(struct workqueue_struct *wq,
+                       struct delayed_work *dwork, unsigned long delay)
+{
+       return queue_delayed_work_on(WORK_CPU_UNBOUND, wq, dwork, delay);
+}
+EXPORT_SYMBOL_GPL(queue_delayed_work);
 
-               set_work_cwq(work, get_cwq(lcpu, wq), 0);
+/**
+ * mod_delayed_work_on - modify delay of or queue a delayed work on specific CPU
+ * @cpu: CPU number to execute work on
+ * @wq: workqueue to use
+ * @dwork: work to queue
+ * @delay: number of jiffies to wait before queueing
+ *
+ * If @dwork is idle, equivalent to queue_delayed_work_on(); otherwise,
+ * modify @dwork's timer so that it expires after @delay.  If @delay is
+ * zero, @work is guaranteed to be scheduled immediately regardless of its
+ * current state.
+ *
+ * Returns %false if @dwork was idle and queued, %true if @dwork was
+ * pending and its timer was modified.
+ *
+ * This function is safe to call from any context other than IRQ handler.
+ * See try_to_grab_pending() for details.
+ */
+bool mod_delayed_work_on(int cpu, struct workqueue_struct *wq,
+                        struct delayed_work *dwork, unsigned long delay)
+{
+       unsigned long flags;
+       int ret;
 
-               timer->expires = jiffies + delay;
-               timer->data = (unsigned long)dwork;
-               timer->function = delayed_work_timer_fn;
+       do {
+               ret = try_to_grab_pending(&dwork->work, true, &flags);
+       } while (unlikely(ret == -EAGAIN));
 
-               if (unlikely(cpu >= 0))
-                       add_timer_on(timer, cpu);
-               else
-                       add_timer(timer);
-               ret = 1;
+       if (likely(ret >= 0)) {
+               __queue_delayed_work(cpu, wq, dwork, delay);
+               local_irq_restore(flags);
        }
+
+       /* -ENOENT from try_to_grab_pending() becomes %true */
        return ret;
 }
-EXPORT_SYMBOL_GPL(queue_delayed_work_on);
+EXPORT_SYMBOL_GPL(mod_delayed_work_on);
+
+/**
+ * mod_delayed_work - modify delay of or queue a delayed work
+ * @wq: workqueue to use
+ * @dwork: work to queue
+ * @delay: number of jiffies to wait before queueing
+ *
+ * mod_delayed_work_on() on local CPU.
+ */
+bool mod_delayed_work(struct workqueue_struct *wq, struct delayed_work *dwork,
+                     unsigned long delay)
+{
+       return mod_delayed_work_on(WORK_CPU_UNBOUND, wq, dwork, delay);
+}
+EXPORT_SYMBOL_GPL(mod_delayed_work);
 
 /**
  * worker_enter_idle - enter idle state
@@ -1434,6 +1741,7 @@ retry:
        /* rebind busy workers */
        for_each_busy_worker(worker, i, pos, gcwq) {
                struct work_struct *rebind_work = &worker->rebind_work;
+               struct workqueue_struct *wq;
 
                /* morph UNBOUND to REBIND */
                worker->flags &= ~WORKER_UNBOUND;
@@ -1443,11 +1751,20 @@ retry:
                                     work_data_bits(rebind_work)))
                        continue;
 
-               /* wq doesn't matter, use the default one */
                debug_work_activate(rebind_work);
-               insert_work(get_cwq(gcwq->cpu, system_wq), rebind_work,
-                           worker->scheduled.next,
-                           work_color_to_flags(WORK_NO_COLOR));
+
+               /*
+                * wq doesn't really matter but let's keep @worker->pool
+                * and @cwq->pool consistent for sanity.
+                */
+               if (worker_pool_pri(worker->pool))
+                       wq = system_highpri_wq;
+               else
+                       wq = system_wq;
+
+               insert_work(get_cwq(gcwq->cpu, wq), rebind_work,
+                       worker->scheduled.next,
+                       work_color_to_flags(WORK_NO_COLOR));
        }
 }
 
@@ -1810,107 +2127,6 @@ static bool manage_workers(struct worker *worker)
        return ret;
 }
 
-/**
- * move_linked_works - move linked works to a list
- * @work: start of series of works to be scheduled
- * @head: target list to append @work to
- * @nextp: out paramter for nested worklist walking
- *
- * Schedule linked works starting from @work to @head.  Work series to
- * be scheduled starts at @work and includes any consecutive work with
- * WORK_STRUCT_LINKED set in its predecessor.
- *
- * If @nextp is not NULL, it's updated to point to the next work of
- * the last scheduled work.  This allows move_linked_works() to be
- * nested inside outer list_for_each_entry_safe().
- *
- * CONTEXT:
- * spin_lock_irq(gcwq->lock).
- */
-static void move_linked_works(struct work_struct *work, struct list_head *head,
-                             struct work_struct **nextp)
-{
-       struct work_struct *n;
-
-       /*
-        * Linked worklist will always end before the end of the list,
-        * use NULL for list head.
-        */
-       list_for_each_entry_safe_from(work, n, NULL, entry) {
-               list_move_tail(&work->entry, head);
-               if (!(*work_data_bits(work) & WORK_STRUCT_LINKED))
-                       break;
-       }
-
-       /*
-        * If we're already inside safe list traversal and have moved
-        * multiple works to the scheduled queue, the next position
-        * needs to be updated.
-        */
-       if (nextp)
-               *nextp = n;
-}
-
-static void cwq_activate_first_delayed(struct cpu_workqueue_struct *cwq)
-{
-       struct work_struct *work = list_first_entry(&cwq->delayed_works,
-                                                   struct work_struct, entry);
-
-       trace_workqueue_activate_work(work);
-       move_linked_works(work, &cwq->pool->worklist, NULL);
-       __clear_bit(WORK_STRUCT_DELAYED_BIT, work_data_bits(work));
-       cwq->nr_active++;
-}
-
-/**
- * cwq_dec_nr_in_flight - decrement cwq's nr_in_flight
- * @cwq: cwq of interest
- * @color: color of work which left the queue
- * @delayed: for a delayed work
- *
- * A work either has completed or is removed from pending queue,
- * decrement nr_in_flight of its cwq and handle workqueue flushing.
- *
- * CONTEXT:
- * spin_lock_irq(gcwq->lock).
- */
-static void cwq_dec_nr_in_flight(struct cpu_workqueue_struct *cwq, int color,
-                                bool delayed)
-{
-       /* ignore uncolored works */
-       if (color == WORK_NO_COLOR)
-               return;
-
-       cwq->nr_in_flight[color]--;
-
-       if (!delayed) {
-               cwq->nr_active--;
-               if (!list_empty(&cwq->delayed_works)) {
-                       /* one down, submit a delayed one */
-                       if (cwq->nr_active < cwq->max_active)
-                               cwq_activate_first_delayed(cwq);
-               }
-       }
-
-       /* is flush in progress and are we at the flushing tip? */
-       if (likely(cwq->flush_color != color))
-               return;
-
-       /* are there still in-flight works? */
-       if (cwq->nr_in_flight[color])
-               return;
-
-       /* this cwq is done, clear flush_color */
-       cwq->flush_color = -1;
-
-       /*
-        * If this was the last cwq, wake up the first flusher.  It
-        * will handle the rest.
-        */
-       if (atomic_dec_and_test(&cwq->wq->nr_cwqs_to_flush))
-               complete(&cwq->wq->first_flusher->done);
-}
-
 /**
  * process_one_work - process single work
  * @worker: self
@@ -1970,15 +2186,13 @@ __acquires(&gcwq->lock)
                return;
        }
 
-       /* claim and process */
+       /* claim and dequeue */
        debug_work_deactivate(work);
        hlist_add_head(&worker->hentry, bwh);
        worker->current_work = work;
        worker->current_cwq = cwq;
        work_color = get_work_color(work);
 
-       /* record the current cpu number in the work data and dequeue */
-       set_work_cpu(work, gcwq->cpu);
        list_del_init(&work->entry);
 
        /*
@@ -1995,9 +2209,16 @@ __acquires(&gcwq->lock)
        if ((worker->flags & WORKER_UNBOUND) && need_more_worker(pool))
                wake_up_worker(pool);
 
+       /*
+        * Record the last CPU and clear PENDING which should be the last
+        * update to @work.  Also, do this inside @gcwq->lock so that
+        * PENDING and queued state changes happen together while IRQ is
+        * disabled.
+        */
+       set_work_cpu_and_clear_pending(work, gcwq->cpu);
+
        spin_unlock_irq(&gcwq->lock);
 
-       work_clear_pending(work);
        lock_map_acquire_read(&cwq->wq->lockdep_map);
        lock_map_acquire(&lockdep_map);
        trace_workqueue_execute_start(work);
@@ -2738,60 +2959,26 @@ bool flush_work_sync(struct work_struct *work)
 }
 EXPORT_SYMBOL_GPL(flush_work_sync);
 
-/*
- * Upon a successful return (>= 0), the caller "owns" WORK_STRUCT_PENDING bit,
- * so this work can't be re-armed in any way.
- */
-static int try_to_grab_pending(struct work_struct *work)
-{
-       struct global_cwq *gcwq;
-       int ret = -1;
-
-       if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work)))
-               return 0;
-
-       /*
-        * The queueing is in progress, or it is already queued. Try to
-        * steal it from ->worklist without clearing WORK_STRUCT_PENDING.
-        */
-       gcwq = get_work_gcwq(work);
-       if (!gcwq)
-               return ret;
-
-       spin_lock_irq(&gcwq->lock);
-       if (!list_empty(&work->entry)) {
-               /*
-                * This work is queued, but perhaps we locked the wrong gcwq.
-                * In that case we must see the new value after rmb(), see
-                * insert_work()->wmb().
-                */
-               smp_rmb();
-               if (gcwq == get_work_gcwq(work)) {
-                       debug_work_deactivate(work);
-                       list_del_init(&work->entry);
-                       cwq_dec_nr_in_flight(get_work_cwq(work),
-                               get_work_color(work),
-                               *work_data_bits(work) & WORK_STRUCT_DELAYED);
-                       ret = 1;
-               }
-       }
-       spin_unlock_irq(&gcwq->lock);
-
-       return ret;
-}
-
-static bool __cancel_work_timer(struct work_struct *work,
-                               struct timer_list* timer)
+static bool __cancel_work_timer(struct work_struct *work, bool is_dwork)
 {
+       unsigned long flags;
        int ret;
 
        do {
-               ret = (timer && likely(del_timer(timer)));
-               if (!ret)
-                       ret = try_to_grab_pending(work);
-               wait_on_work(work);
+               ret = try_to_grab_pending(work, is_dwork, &flags);
+               /*
+                * If someone else is canceling, wait for the same event it
+                * would be waiting for before retrying.
+                */
+               if (unlikely(ret == -ENOENT))
+                       wait_on_work(work);
        } while (unlikely(ret < 0));
 
+       /* tell other tasks trying to grab @work to back off */
+       mark_work_canceling(work);
+       local_irq_restore(flags);
+
+       wait_on_work(work);
        clear_work_data(work);
        return ret;
 }
@@ -2816,7 +3003,7 @@ static bool __cancel_work_timer(struct work_struct *work,
  */
 bool cancel_work_sync(struct work_struct *work)
 {
-       return __cancel_work_timer(work, NULL);
+       return __cancel_work_timer(work, false);
 }
 EXPORT_SYMBOL_GPL(cancel_work_sync);
 
@@ -2834,9 +3021,11 @@ EXPORT_SYMBOL_GPL(cancel_work_sync);
  */
 bool flush_delayed_work(struct delayed_work *dwork)
 {
+       local_irq_disable();
        if (del_timer_sync(&dwork->timer))
-               __queue_work(raw_smp_processor_id(),
+               __queue_work(dwork->cpu,
                             get_work_cwq(&dwork->work)->wq, &dwork->work);
+       local_irq_enable();
        return flush_work(&dwork->work);
 }
 EXPORT_SYMBOL(flush_delayed_work);
@@ -2855,9 +3044,11 @@ EXPORT_SYMBOL(flush_delayed_work);
  */
 bool flush_delayed_work_sync(struct delayed_work *dwork)
 {
+       local_irq_disable();
        if (del_timer_sync(&dwork->timer))
-               __queue_work(raw_smp_processor_id(),
+               __queue_work(dwork->cpu,
                             get_work_cwq(&dwork->work)->wq, &dwork->work);
+       local_irq_enable();
        return flush_work_sync(&dwork->work);
 }
 EXPORT_SYMBOL(flush_delayed_work_sync);
@@ -2873,54 +3064,39 @@ EXPORT_SYMBOL(flush_delayed_work_sync);
  */
 bool cancel_delayed_work_sync(struct delayed_work *dwork)
 {
-       return __cancel_work_timer(&dwork->work, &dwork->timer);
+       return __cancel_work_timer(&dwork->work, true);
 }
 EXPORT_SYMBOL(cancel_delayed_work_sync);
 
 /**
- * schedule_work - put work task in global workqueue
- * @work: job to be done
- *
- * Returns zero if @work was already on the kernel-global workqueue and
- * non-zero otherwise.
- *
- * This puts a job in the kernel-global workqueue if it was not already
- * queued and leaves it in the same position on the kernel-global
- * workqueue otherwise.
- */
-int schedule_work(struct work_struct *work)
-{
-       return queue_work(system_wq, work);
-}
-EXPORT_SYMBOL(schedule_work);
-
-/*
  * schedule_work_on - put work task on a specific cpu
  * @cpu: cpu to put the work task on
  * @work: job to be done
  *
  * This puts a job on a specific cpu
  */
-int schedule_work_on(int cpu, struct work_struct *work)
+bool schedule_work_on(int cpu, struct work_struct *work)
 {
        return queue_work_on(cpu, system_wq, work);
 }
 EXPORT_SYMBOL(schedule_work_on);
 
 /**
- * schedule_delayed_work - put work task in global workqueue after delay
- * @dwork: job to be done
- * @delay: number of jiffies to wait or 0 for immediate execution
+ * schedule_work - put work task in global workqueue
+ * @work: job to be done
  *
- * After waiting for a given time this puts a job in the kernel-global
- * workqueue.
+ * Returns %false if @work was already on the kernel-global workqueue and
+ * %true otherwise.
+ *
+ * This puts a job in the kernel-global workqueue if it was not already
+ * queued and leaves it in the same position on the kernel-global
+ * workqueue otherwise.
  */
-int schedule_delayed_work(struct delayed_work *dwork,
-                                       unsigned long delay)
+bool schedule_work(struct work_struct *work)
 {
-       return queue_delayed_work(system_wq, dwork, delay);
+       return queue_work(system_wq, work);
 }
-EXPORT_SYMBOL(schedule_delayed_work);
+EXPORT_SYMBOL(schedule_work);
 
 /**
  * schedule_delayed_work_on - queue work in global workqueue on CPU after delay
@@ -2931,13 +3107,27 @@ EXPORT_SYMBOL(schedule_delayed_work);
  * After waiting for a given time this puts a job in the kernel-global
  * workqueue on the specified CPU.
  */
-int schedule_delayed_work_on(int cpu,
-                       struct delayed_work *dwork, unsigned long delay)
+bool schedule_delayed_work_on(int cpu, struct delayed_work *dwork,
+                             unsigned long delay)
 {
        return queue_delayed_work_on(cpu, system_wq, dwork, delay);
 }
 EXPORT_SYMBOL(schedule_delayed_work_on);
 
+/**
+ * schedule_delayed_work - put work task in global workqueue after delay
+ * @dwork: job to be done
+ * @delay: number of jiffies to wait or 0 for immediate execution
+ *
+ * After waiting for a given time this puts a job in the kernel-global
+ * workqueue.
+ */
+bool schedule_delayed_work(struct delayed_work *dwork, unsigned long delay)
+{
+       return queue_delayed_work(system_wq, dwork, delay);
+}
+EXPORT_SYMBOL(schedule_delayed_work);
+
 /**
  * schedule_on_each_cpu - execute a function synchronously on each online CPU
  * @func: the function to call
@@ -3490,7 +3680,7 @@ static int __devinit workqueue_cpu_down_callback(struct notifier_block *nfb,
        case CPU_DOWN_PREPARE:
                /* unbinding should happen on the local CPU */
                INIT_WORK_ONSTACK(&unbind_work, gcwq_unbind_fn);
-               schedule_work_on(cpu, &unbind_work);
+               queue_work_on(cpu, system_highpri_wq, &unbind_work);
                flush_work(&unbind_work);
                break;
        }
@@ -3692,6 +3882,10 @@ static int __init init_workqueues(void)
        unsigned int cpu;
        int i;
 
+       /* make sure we have enough bits for OFFQ CPU number */
+       BUILD_BUG_ON((1LU << (BITS_PER_LONG - WORK_OFFQ_CPU_SHIFT)) <
+                    WORK_CPU_LAST);
+
        cpu_notifier(workqueue_cpu_up_callback, CPU_PRI_WORKQUEUE_UP);
        cpu_notifier(workqueue_cpu_down_callback, CPU_PRI_WORKQUEUE_DOWN);
 
@@ -3746,6 +3940,7 @@ static int __init init_workqueues(void)
        }
 
        system_wq = alloc_workqueue("events", 0, 0);
+       system_highpri_wq = alloc_workqueue("events_highpri", WQ_HIGHPRI, 0);
        system_long_wq = alloc_workqueue("events_long", 0, 0);
        system_nrt_wq = alloc_workqueue("events_nrt", WQ_NON_REENTRANT, 0);
        system_unbound_wq = alloc_workqueue("events_unbound", WQ_UNBOUND,
@@ -3754,9 +3949,9 @@ static int __init init_workqueues(void)
                                              WQ_FREEZABLE, 0);
        system_nrt_freezable_wq = alloc_workqueue("events_nrt_freezable",
                        WQ_NON_REENTRANT | WQ_FREEZABLE, 0);
-       BUG_ON(!system_wq || !system_long_wq || !system_nrt_wq ||
-              !system_unbound_wq || !system_freezable_wq ||
-               !system_nrt_freezable_wq);
+       BUG_ON(!system_wq || !system_highpri_wq || !system_long_wq ||
+              !system_nrt_wq || !system_unbound_wq || !system_freezable_wq ||
+              !system_nrt_freezable_wq);
        return 0;
 }
 early_initcall(init_workqueues);
index 2403a63b5da5bcf4e978d5dc2dfe8682cebef453..dacbbe4d7a805a40bfa2fb043b4f33e5d45ac8f8 100644 (file)
@@ -629,6 +629,20 @@ config PROVE_RCU_REPEATEDLY
 
         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
index 6b4718e2ee341d7fd7f068d83e31da014d1a5ef0..b41823cc05e61caf4b862418fde58a5025bfb748 100644 (file)
@@ -39,12 +39,6 @@ DEFINE_SPINLOCK(bdi_lock);
 LIST_HEAD(bdi_list);
 LIST_HEAD(bdi_pending_list);
 
-static struct task_struct *sync_supers_tsk;
-static struct timer_list sync_supers_timer;
-
-static int bdi_sync_supers(void *);
-static void sync_supers_timer_fn(unsigned long);
-
 void bdi_lock_two(struct bdi_writeback *wb1, struct bdi_writeback *wb2)
 {
        if (wb1 < wb2) {
@@ -250,12 +244,6 @@ static int __init default_bdi_init(void)
 {
        int err;
 
-       sync_supers_tsk = kthread_run(bdi_sync_supers, NULL, "sync_supers");
-       BUG_ON(IS_ERR(sync_supers_tsk));
-
-       setup_timer(&sync_supers_timer, sync_supers_timer_fn, 0);
-       bdi_arm_supers_timer();
-
        err = bdi_init(&default_backing_dev_info);
        if (!err)
                bdi_register(&default_backing_dev_info, NULL, "default");
@@ -270,46 +258,6 @@ int bdi_has_dirty_io(struct backing_dev_info *bdi)
        return wb_has_dirty_io(&bdi->wb);
 }
 
-/*
- * kupdated() used to do this. We cannot do it from the bdi_forker_thread()
- * or we risk deadlocking on ->s_umount. The longer term solution would be
- * to implement sync_supers_bdi() or similar and simply do it from the
- * bdi writeback thread individually.
- */
-static int bdi_sync_supers(void *unused)
-{
-       set_user_nice(current, 0);
-
-       while (!kthread_should_stop()) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               schedule();
-
-               /*
-                * Do this periodically, like kupdated() did before.
-                */
-               sync_supers();
-       }
-
-       return 0;
-}
-
-void bdi_arm_supers_timer(void)
-{
-       unsigned long next;
-
-       if (!dirty_writeback_interval)
-               return;
-
-       next = msecs_to_jiffies(dirty_writeback_interval * 10) + jiffies;
-       mod_timer(&sync_supers_timer, round_jiffies_up(next));
-}
-
-static void sync_supers_timer_fn(unsigned long unused)
-{
-       wake_up_process(sync_supers_tsk);
-       bdi_arm_supers_timer();
-}
-
 static void wakeup_timer_fn(unsigned long data)
 {
        struct backing_dev_info *bdi = (struct backing_dev_info *)data;
index fa5ca304148e7b4756bf2e52cd6afde1dba2b5c3..384344575c375e1a1464734670218557c31e0e27 100644 (file)
@@ -1412,12 +1412,8 @@ generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
                        retval = filemap_write_and_wait_range(mapping, pos,
                                        pos + iov_length(iov, nr_segs) - 1);
                        if (!retval) {
-                               struct blk_plug plug;
-
-                               blk_start_plug(&plug);
                                retval = mapping->a_ops->direct_IO(READ, iocb,
                                                        iov, pos, nr_segs);
-                               blk_finish_plug(&plug);
                        }
                        if (retval > 0) {
                                *ppos = pos + retval;
@@ -2527,14 +2523,12 @@ ssize_t generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
 {
        struct file *file = iocb->ki_filp;
        struct inode *inode = file->f_mapping->host;
-       struct blk_plug plug;
        ssize_t ret;
 
        BUG_ON(iocb->ki_pos != pos);
 
        sb_start_write(inode->i_sb);
        mutex_lock(&inode->i_mutex);
-       blk_start_plug(&plug);
        ret = __generic_file_aio_write(iocb, iov, nr_segs, &iocb->ki_pos);
        mutex_unlock(&inode->i_mutex);
 
@@ -2545,7 +2539,6 @@ ssize_t generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
                if (err < 0 && ret > 0)
                        ret = err;
        }
-       blk_finish_plug(&plug);
        sb_end_write(inode->i_sb);
        return ret;
 }
index 6b3e71a2cd483a70c845d33136719c43739a6c68..89dc399d332880d3458aaff9878a351db76b8c97 100644 (file)
@@ -292,7 +292,7 @@ static int __frontswap_shrink(unsigned long target_pages,
 void frontswap_shrink(unsigned long target_pages)
 {
        unsigned long pages_to_unuse = 0;
-       int type, ret;
+       int uninitialized_var(type), ret;
 
        /*
         * we don't want to hold swap_lock while doing a very
index 45eb6217bf38e764bfb65d90f29ae2bb46f77886..5f059935f7bb2ad2fd5eed4c54a111e5289862c6 100644 (file)
@@ -578,6 +578,7 @@ static struct kmemleak_object *create_object(unsigned long ptr, size_t size,
        if (node != &object->tree_node) {
                kmemleak_stop("Cannot insert 0x%lx into the object search tree "
                              "(already existing)\n", ptr);
+               kmem_cache_free(object_cache, object);
                object = lookup_object(ptr, 1);
                spin_lock(&object->lock);
                dump_object_info(object);
index e5363f34e0250656c357d965a2e8949577cfb607..5ad5ce23c1e082bc999222f42e542d942794c7c7 100644 (file)
@@ -1532,7 +1532,6 @@ int dirty_writeback_centisecs_handler(ctl_table *table, int write,
        void __user *buffer, size_t *length, loff_t *ppos)
 {
        proc_dointvec(table, write, buffer, length, ppos);
-       bdi_arm_supers_timer();
        return 0;
 }
 
index f8b0d539b4822af7812c8f9edcb51224450f3f64..cb6ce2dfc7cf4d8819309110a302e560fd9745cf 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -517,7 +517,6 @@ static bool slab_max_order_set __initdata;
 
 static inline struct kmem_cache *page_get_cache(struct page *page)
 {
-       page = compound_head(page);
        BUG_ON(!PageSlab(page));
        return page->slab_cache;
 }
index aa3ca5bb01b55a097f1397a6a92728f81b3167a5..8cf8b4962d6c895ad28646978dc26525c8efd6cc 100644 (file)
@@ -23,49 +23,17 @@ enum slab_state slab_state;
 LIST_HEAD(slab_caches);
 DEFINE_MUTEX(slab_mutex);
 
-/*
- * 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.
- * @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 interrupt, but can be interrupted.
- * The @ctor is run when new pages are allocated by the cache.
- *
- * The flags are
- *
- * %SLAB_POISON - Poison the slab with a known test pattern (a5a5a5a5)
- * to catch references to uninitialised memory.
- *
- * %SLAB_RED_ZONE - Insert `Red' zones around the allocated memory to check
- * for buffer overruns.
- *
- * %SLAB_HWCACHE_ALIGN - Align the objects in this cache to a hardware
- * cacheline.  This can be beneficial if you're counting cycles as closely
- * as davem.
- */
-
-struct kmem_cache *kmem_cache_create(const char *name, size_t size, size_t align,
-               unsigned long flags, void (*ctor)(void *))
+#ifdef CONFIG_DEBUG_VM
+static int kmem_cache_sanity_check(const char *name, size_t size)
 {
        struct kmem_cache *s = NULL;
 
-#ifdef CONFIG_DEBUG_VM
        if (!name || in_interrupt() || size < sizeof(void *) ||
                size > KMALLOC_MAX_SIZE) {
-               printk(KERN_ERR "kmem_cache_create(%s) integrity check"
-                       " failed\n", name);
-               goto out;
+               pr_err("kmem_cache_create(%s) integrity check failed\n", name);
+               return -EINVAL;
        }
-#endif
 
-       get_online_cpus();
-       mutex_lock(&slab_mutex);
-
-#ifdef CONFIG_DEBUG_VM
        list_for_each_entry(s, &slab_caches, list) {
                char tmp;
                int res;
@@ -77,36 +45,67 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size, size_t align
                 */
                res = probe_kernel_address(s->name, tmp);
                if (res) {
-                       printk(KERN_ERR
-                              "Slab cache with size %d has lost its name\n",
+                       pr_err("Slab cache with size %d has lost its name\n",
                               s->object_size);
                        continue;
                }
 
                if (!strcmp(s->name, name)) {
-                       printk(KERN_ERR "kmem_cache_create(%s): Cache name"
-                               " already exists.\n",
-                               name);
+                       pr_err("%s (%s): Cache name already exists.\n",
+                              __func__, name);
                        dump_stack();
                        s = NULL;
-                       goto oops;
+                       return -EINVAL;
                }
        }
 
        WARN_ON(strchr(name, ' '));     /* It confuses parsers */
+       return 0;
+}
+#else
+static inline int kmem_cache_sanity_check(const char *name, size_t size)
+{
+       return 0;
+}
 #endif
 
-       s = __kmem_cache_create(name, size, align, flags, ctor);
+/*
+ * 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.
+ * @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 interrupt, but can be interrupted.
+ * The @ctor is run when new pages are allocated by the cache.
+ *
+ * The flags are
+ *
+ * %SLAB_POISON - Poison the slab with a known test pattern (a5a5a5a5)
+ * to catch references to uninitialised memory.
+ *
+ * %SLAB_RED_ZONE - Insert `Red' zones around the allocated memory to check
+ * for buffer overruns.
+ *
+ * %SLAB_HWCACHE_ALIGN - Align the objects in this cache to a hardware
+ * cacheline.  This can be beneficial if you're counting cycles as closely
+ * 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 *s = NULL;
 
-#ifdef CONFIG_DEBUG_VM
-oops:
-#endif
+       get_online_cpus();
+       mutex_lock(&slab_mutex);
+       if (kmem_cache_sanity_check(name, size) == 0)
+               s = __kmem_cache_create(name, size, align, flags, ctor);
        mutex_unlock(&slab_mutex);
        put_online_cpus();
 
-#ifdef CONFIG_DEBUG_VM
-out:
-#endif
        if (!s && (flags & SLAB_PANIC))
                panic("kmem_cache_create: Failed to create slab '%s'\n", name);
 
index 8f78e25770317e63a37c741d66c2761f71afa2e9..c67bd0a4a952bed22432e5d2a86d269bb9991bae 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -1069,13 +1069,13 @@ bad:
        return 0;
 }
 
-static noinline int free_debug_processing(struct kmem_cache *s,
-                struct page *page, void *object, unsigned long addr)
+static noinline struct kmem_cache_node *free_debug_processing(
+       struct kmem_cache *s, struct page *page, void *object,
+       unsigned long addr, unsigned long *flags)
 {
-       unsigned long flags;
-       int rc = 0;
+       struct kmem_cache_node *n = get_node(s, page_to_nid(page));
 
-       local_irq_save(flags);
+       spin_lock_irqsave(&n->list_lock, *flags);
        slab_lock(page);
 
        if (!check_slab(s, page))
@@ -1113,15 +1113,19 @@ static noinline int free_debug_processing(struct kmem_cache *s,
                set_track(s, object, TRACK_FREE, addr);
        trace(s, page, object, 0);
        init_object(s, object, SLUB_RED_INACTIVE);
-       rc = 1;
 out:
        slab_unlock(page);
-       local_irq_restore(flags);
-       return rc;
+       /*
+        * Keep node_lock to preserve integrity
+        * until the object is actually freed
+        */
+       return n;
 
 fail:
+       slab_unlock(page);
+       spin_unlock_irqrestore(&n->list_lock, *flags);
        slab_fix(s, "Object at 0x%p not freed", object);
-       goto out;
+       return NULL;
 }
 
 static int __init setup_slub_debug(char *str)
@@ -1214,8 +1218,9 @@ static inline void setup_object_debug(struct kmem_cache *s,
 static inline int alloc_debug_processing(struct kmem_cache *s,
        struct page *page, void *object, unsigned long addr) { return 0; }
 
-static inline int free_debug_processing(struct kmem_cache *s,
-       struct page *page, void *object, unsigned long addr) { return 0; }
+static inline struct kmem_cache_node *free_debug_processing(
+       struct kmem_cache *s, struct page *page, void *object,
+       unsigned long addr, unsigned long *flags) { return NULL; }
 
 static inline int slab_pad_check(struct kmem_cache *s, struct page *page)
                        { return 1; }
@@ -1957,6 +1962,7 @@ int put_cpu_partial(struct kmem_cache *s, struct page *page, int drain)
                                local_irq_save(flags);
                                unfreeze_partials(s);
                                local_irq_restore(flags);
+                               oldpage = NULL;
                                pobjects = 0;
                                pages = 0;
                                stat(s, CPU_PARTIAL_DRAIN);
@@ -2452,7 +2458,8 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
 
        stat(s, FREE_SLOWPATH);
 
-       if (kmem_cache_debug(s) && !free_debug_processing(s, page, x, addr))
+       if (kmem_cache_debug(s) &&
+               !(n = free_debug_processing(s, page, x, addr, &flags)))
                return;
 
        do {
@@ -3477,7 +3484,7 @@ void kfree(const void *x)
        if (unlikely(!PageSlab(page))) {
                BUG_ON(!PageCompound(page));
                kmemleak_free(x);
-               put_page(page);
+               __free_pages(page, compound_order(page));
                return;
        }
        slab_free(page->slab, page, object, _RET_IP_);
index 73a2a83ee2da51333731c4bb5f8307a78c2c5496..402442402af710d5acedf500347cca48f89a6be4 100644 (file)
@@ -137,9 +137,21 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev,
        return rc;
 }
 
+static inline netdev_tx_t vlan_netpoll_send_skb(struct vlan_dev_priv *vlan, struct sk_buff *skb)
+{
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       if (vlan->netpoll)
+               netpoll_send_skb(vlan->netpoll, skb);
+#else
+       BUG();
+#endif
+       return NETDEV_TX_OK;
+}
+
 static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb,
                                            struct net_device *dev)
 {
+       struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
        struct vlan_ethhdr *veth = (struct vlan_ethhdr *)(skb->data);
        unsigned int len;
        int ret;
@@ -150,29 +162,30 @@ static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb,
         * OTHER THINGS LIKE FDDI/TokenRing/802.3 SNAPs...
         */
        if (veth->h_vlan_proto != htons(ETH_P_8021Q) ||
-           vlan_dev_priv(dev)->flags & VLAN_FLAG_REORDER_HDR) {
+           vlan->flags & VLAN_FLAG_REORDER_HDR) {
                u16 vlan_tci;
-               vlan_tci = vlan_dev_priv(dev)->vlan_id;
+               vlan_tci = vlan->vlan_id;
                vlan_tci |= vlan_dev_get_egress_qos_mask(dev, skb);
                skb = __vlan_hwaccel_put_tag(skb, vlan_tci);
        }
 
-       skb->dev = vlan_dev_priv(dev)->real_dev;
+       skb->dev = vlan->real_dev;
        len = skb->len;
-       if (netpoll_tx_running(dev))
-               return skb->dev->netdev_ops->ndo_start_xmit(skb, skb->dev);
+       if (unlikely(netpoll_tx_running(dev)))
+               return vlan_netpoll_send_skb(vlan, skb);
+
        ret = dev_queue_xmit(skb);
 
        if (likely(ret == NET_XMIT_SUCCESS || ret == NET_XMIT_CN)) {
                struct vlan_pcpu_stats *stats;
 
-               stats = this_cpu_ptr(vlan_dev_priv(dev)->vlan_pcpu_stats);
+               stats = this_cpu_ptr(vlan->vlan_pcpu_stats);
                u64_stats_update_begin(&stats->syncp);
                stats->tx_packets++;
                stats->tx_bytes += len;
                u64_stats_update_end(&stats->syncp);
        } else {
-               this_cpu_inc(vlan_dev_priv(dev)->vlan_pcpu_stats->tx_dropped);
+               this_cpu_inc(vlan->vlan_pcpu_stats->tx_dropped);
        }
 
        return ret;
@@ -669,25 +682,26 @@ static void vlan_dev_poll_controller(struct net_device *dev)
        return;
 }
 
-static int vlan_dev_netpoll_setup(struct net_device *dev, struct netpoll_info *npinfo)
+static int vlan_dev_netpoll_setup(struct net_device *dev, struct netpoll_info *npinfo,
+                                 gfp_t gfp)
 {
-       struct vlan_dev_priv *info = vlan_dev_priv(dev);
-       struct net_device *real_dev = info->real_dev;
+       struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
+       struct net_device *real_dev = vlan->real_dev;
        struct netpoll *netpoll;
        int err = 0;
 
-       netpoll = kzalloc(sizeof(*netpoll), GFP_KERNEL);
+       netpoll = kzalloc(sizeof(*netpoll), gfp);
        err = -ENOMEM;
        if (!netpoll)
                goto out;
 
-       err = __netpoll_setup(netpoll, real_dev);
+       err = __netpoll_setup(netpoll, real_dev, gfp);
        if (err) {
                kfree(netpoll);
                goto out;
        }
 
-       info->netpoll = netpoll;
+       vlan->netpoll = netpoll;
 
 out:
        return err;
@@ -695,19 +709,15 @@ out:
 
 static void vlan_dev_netpoll_cleanup(struct net_device *dev)
 {
-       struct vlan_dev_priv *info = vlan_dev_priv(dev);
-       struct netpoll *netpoll = info->netpoll;
+       struct vlan_dev_priv *vlan= vlan_dev_priv(dev);
+       struct netpoll *netpoll = vlan->netpoll;
 
        if (!netpoll)
                return;
 
-       info->netpoll = NULL;
-
-        /* Wait for transmitting packets to finish before freeing. */
-        synchronize_rcu_bh();
+       vlan->netpoll = NULL;
 
-        __netpoll_cleanup(netpoll);
-        kfree(netpoll);
+       __netpoll_free_rcu(netpoll);
 }
 #endif /* CONFIG_NET_POLL_CONTROLLER */
 
index b4b44dbed645f74046ae4663a31b805a0ed72b52..0c0ad930a632f23e4c0661a20684c5d572e3dc15 100644 (file)
@@ -812,6 +812,7 @@ int vcc_getsockopt(struct socket *sock, int level, int optname,
 
                if (!vcc->dev || !test_bit(ATM_VF_ADDR, &vcc->flags))
                        return -ENOTCONN;
+               memset(&pvc, 0, sizeof(pvc));
                pvc.sap_family = AF_ATMPVC;
                pvc.sap_addr.itf = vcc->dev->number;
                pvc.sap_addr.vpi = vcc->vpi;
index 3a734919c36cbeac2e59e923225096f76380620b..ae0324021407c2b61aaf7c45a39bebb9d419972c 100644 (file)
@@ -95,6 +95,7 @@ static int pvc_getname(struct socket *sock, struct sockaddr *sockaddr,
                return -ENOTCONN;
        *sockaddr_len = sizeof(struct sockaddr_atmpvc);
        addr = (struct sockaddr_atmpvc *)sockaddr;
+       memset(addr, 0, sizeof(*addr));
        addr->sap_family = AF_ATMPVC;
        addr->sap_addr.itf = vcc->dev->number;
        addr->sap_addr.vpi = vcc->vpi;
index b421cc49d2cd1f83a88b905047df40e2853c4b0b..fc866f2e4528c71c82ba125c23fb48fbd430b390 100644 (file)
@@ -200,11 +200,11 @@ void batadv_gw_election(struct batadv_priv *bat_priv)
        if (atomic_read(&bat_priv->gw_mode) != BATADV_GW_MODE_CLIENT)
                goto out;
 
-       if (!batadv_atomic_dec_not_zero(&bat_priv->gw_reselect))
-               goto out;
-
        curr_gw = batadv_gw_get_selected_gw_node(bat_priv);
 
+       if (!batadv_atomic_dec_not_zero(&bat_priv->gw_reselect) && curr_gw)
+               goto out;
+
        next_gw = batadv_gw_get_best_gw_node(bat_priv);
 
        if (curr_gw == next_gw)
index a438f4b582fc8adccba3a67dfb33326b1ecf4606..99dd8f75b3ff20f0d2a277e1f65ffc284b002f2e 100644 (file)
@@ -197,6 +197,7 @@ static void batadv_tt_local_event(struct batadv_priv *bat_priv,
 del:
                list_del(&entry->list);
                kfree(entry);
+               kfree(tt_change_node);
                event_removed = true;
                goto unlock;
        }
index 4ff0bf3ba9a516bcb99e6a8165c38b81419a28c5..0760d1fed6f08bb13404a11622b83cf3dcf02484 100644 (file)
@@ -316,7 +316,7 @@ send_rsp:
 static inline int a2mp_cmd_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
                               struct a2mp_cmd *hdr)
 {
-       BT_DBG("ident %d code %d", hdr->ident, hdr->code);
+       BT_DBG("ident %d code 0x%2.2x", hdr->ident, hdr->code);
 
        skb_pull(skb, le16_to_cpu(hdr->len));
        return 0;
@@ -325,17 +325,19 @@ static inline int a2mp_cmd_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
 /* Handle A2MP signalling */
 static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
 {
-       struct a2mp_cmd *hdr = (void *) skb->data;
+       struct a2mp_cmd *hdr;
        struct amp_mgr *mgr = chan->data;
        int err = 0;
 
        amp_mgr_get(mgr);
 
        while (skb->len >= sizeof(*hdr)) {
-               struct a2mp_cmd *hdr = (void *) skb->data;
-               u16 len = le16_to_cpu(hdr->len);
+               u16 len;
 
-               BT_DBG("code 0x%02x id %d len %d", hdr->code, hdr->ident, len);
+               hdr = (void *) skb->data;
+               len = le16_to_cpu(hdr->len);
+
+               BT_DBG("code 0x%2.2x id %d len %u", hdr->code, hdr->ident, len);
 
                skb_pull(skb, sizeof(*hdr));
 
@@ -393,7 +395,9 @@ static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
 
        if (err) {
                struct a2mp_cmd_rej rej;
+
                rej.reason = __constant_cpu_to_le16(0);
+               hdr = (void *) skb->data;
 
                BT_DBG("Send A2MP Rej: cmd 0x%2.2x err %d", hdr->code, err);
 
@@ -412,7 +416,7 @@ static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
 
 static void a2mp_chan_close_cb(struct l2cap_chan *chan)
 {
-       l2cap_chan_destroy(chan);
+       l2cap_chan_put(chan);
 }
 
 static void a2mp_chan_state_change_cb(struct l2cap_chan *chan, int state)
index f7db5792ec648d3078d047cb46d0b269a68028bf..a9ad589f3e72eb113ef1b896e7001773036d60ab 100644 (file)
@@ -28,6 +28,7 @@
 #include <asm/ioctls.h>
 
 #include <net/bluetooth/bluetooth.h>
+#include <linux/proc_fs.h>
 
 #define VERSION "2.16"
 
@@ -532,6 +533,142 @@ int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
 }
 EXPORT_SYMBOL(bt_sock_wait_state);
 
+#ifdef CONFIG_PROC_FS
+struct bt_seq_state {
+       struct bt_sock_list *l;
+};
+
+static void *bt_seq_start(struct seq_file *seq, loff_t *pos)
+       __acquires(seq->private->l->lock)
+{
+       struct bt_seq_state *s = seq->private;
+       struct bt_sock_list *l = s->l;
+
+       read_lock(&l->lock);
+       return seq_hlist_start_head(&l->head, *pos);
+}
+
+static void *bt_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+       struct bt_seq_state *s = seq->private;
+       struct bt_sock_list *l = s->l;
+
+       return seq_hlist_next(v, &l->head, pos);
+}
+
+static void bt_seq_stop(struct seq_file *seq, void *v)
+       __releases(seq->private->l->lock)
+{
+       struct bt_seq_state *s = seq->private;
+       struct bt_sock_list *l = s->l;
+
+       read_unlock(&l->lock);
+}
+
+static int bt_seq_show(struct seq_file *seq, void *v)
+{
+       struct bt_seq_state *s = seq->private;
+       struct bt_sock_list *l = s->l;
+
+       if (v == SEQ_START_TOKEN) {
+               seq_puts(seq ,"sk               RefCnt Rmem   Wmem   User   Inode  Src Dst Parent");
+
+               if (l->custom_seq_show) {
+                       seq_putc(seq, ' ');
+                       l->custom_seq_show(seq, v);
+               }
+
+               seq_putc(seq, '\n');
+       } else {
+               struct sock *sk = sk_entry(v);
+               struct bt_sock *bt = bt_sk(sk);
+
+               seq_printf(seq,
+                          "%pK %-6d %-6u %-6u %-6u %-6lu %pMR %pMR %-6lu",
+                          sk,
+                          atomic_read(&sk->sk_refcnt),
+                          sk_rmem_alloc_get(sk),
+                          sk_wmem_alloc_get(sk),
+                          sock_i_uid(sk),
+                          sock_i_ino(sk),
+                          &bt->src,
+                          &bt->dst,
+                          bt->parent? sock_i_ino(bt->parent): 0LU);
+
+               if (l->custom_seq_show) {
+                       seq_putc(seq, ' ');
+                       l->custom_seq_show(seq, v);
+               }
+
+               seq_putc(seq, '\n');
+       }
+       return 0;
+}
+
+static struct seq_operations bt_seq_ops = {
+       .start = bt_seq_start,
+       .next  = bt_seq_next,
+       .stop  = bt_seq_stop,
+       .show  = bt_seq_show,
+};
+
+static int bt_seq_open(struct inode *inode, struct file *file)
+{
+       struct bt_sock_list *sk_list;
+       struct bt_seq_state *s;
+
+       sk_list = PDE(inode)->data;
+       s = __seq_open_private(file, &bt_seq_ops,
+                              sizeof(struct bt_seq_state));
+       if (!s)
+               return -ENOMEM;
+
+       s->l = sk_list;
+       return 0;
+}
+
+int bt_procfs_init(struct module* module, struct net *net, const char *name,
+                  struct bt_sock_list* sk_list,
+                  int (* seq_show)(struct seq_file *, void *))
+{
+       struct proc_dir_entry * pde;
+
+       sk_list->custom_seq_show = seq_show;
+
+       sk_list->fops.owner     = module;
+       sk_list->fops.open      = bt_seq_open;
+       sk_list->fops.read      = seq_read;
+       sk_list->fops.llseek    = seq_lseek;
+       sk_list->fops.release   = seq_release_private;
+
+       pde = proc_net_fops_create(net, name, 0, &sk_list->fops);
+       if (!pde)
+               return -ENOMEM;
+
+       pde->data = sk_list;
+
+       return 0;
+}
+
+void bt_procfs_cleanup(struct net *net, const char *name)
+{
+       proc_net_remove(net, name);
+}
+#else
+int bt_procfs_init(struct module* module, struct net *net, const char *name,
+                  struct bt_sock_list* sk_list,
+                  int (* seq_show)(struct seq_file *, void *))
+{
+       return 0;
+}
+
+void bt_procfs_cleanup(struct net *net, const char *name)
+{
+}
+#endif
+EXPORT_SYMBOL(bt_procfs_init);
+EXPORT_SYMBOL(bt_procfs_cleanup);
+
 static struct net_proto_family bt_sock_family_ops = {
        .owner  = THIS_MODULE,
        .family = PF_BLUETOOTH,
index 5e5f5b410e0b24f751eb158ad235fe16bfa3ee6f..5b6cc0bf4dec676c4265af8f148d2ae3e24d0133 100644 (file)
 
 #include "bnep.h"
 
+static struct bt_sock_list bnep_sk_list = {
+       .lock = __RW_LOCK_UNLOCKED(bnep_sk_list.lock)
+};
+
 static int bnep_sock_release(struct socket *sock)
 {
        struct sock *sk = sock->sk;
@@ -38,6 +42,8 @@ static int bnep_sock_release(struct socket *sock)
        if (!sk)
                return 0;
 
+       bt_sock_unlink(&bnep_sk_list, sk);
+
        sock_orphan(sk);
        sock_put(sk);
        return 0;
@@ -204,6 +210,7 @@ static int bnep_sock_create(struct net *net, struct socket *sock, int protocol,
        sk->sk_protocol = protocol;
        sk->sk_state    = BT_OPEN;
 
+       bt_sock_link(&bnep_sk_list, sk);
        return 0;
 }
 
@@ -222,19 +229,30 @@ int __init bnep_sock_init(void)
                return err;
 
        err = bt_sock_register(BTPROTO_BNEP, &bnep_sock_family_ops);
-       if (err < 0)
+       if (err < 0) {
+               BT_ERR("Can't register BNEP socket");
                goto error;
+       }
+
+       err = bt_procfs_init(THIS_MODULE, &init_net, "bnep", &bnep_sk_list, NULL);
+       if (err < 0) {
+               BT_ERR("Failed to create BNEP proc file");
+               bt_sock_unregister(BTPROTO_BNEP);
+               goto error;
+       }
+
+       BT_INFO("BNEP socket layer initialized");
 
        return 0;
 
 error:
-       BT_ERR("Can't register BNEP socket");
        proto_unregister(&bnep_proto);
        return err;
 }
 
 void __exit bnep_sock_cleanup(void)
 {
+       bt_procfs_cleanup(&init_net, "bnep");
        if (bt_sock_unregister(BTPROTO_BNEP) < 0)
                BT_ERR("Can't unregister BNEP socket");
 
index 311668d14571626dac778201a65ed21f05c72cbe..d5cacef5274836e90e7ddb6ede1bac609cb2e44c 100644 (file)
 
 #include "cmtp.h"
 
+static struct bt_sock_list cmtp_sk_list = {
+       .lock = __RW_LOCK_UNLOCKED(cmtp_sk_list.lock)
+};
+
 static int cmtp_sock_release(struct socket *sock)
 {
        struct sock *sk = sock->sk;
@@ -51,6 +55,8 @@ static int cmtp_sock_release(struct socket *sock)
        if (!sk)
                return 0;
 
+       bt_sock_unlink(&cmtp_sk_list, sk);
+
        sock_orphan(sk);
        sock_put(sk);
 
@@ -214,6 +220,8 @@ static int cmtp_sock_create(struct net *net, struct socket *sock, int protocol,
        sk->sk_protocol = protocol;
        sk->sk_state    = BT_OPEN;
 
+       bt_sock_link(&cmtp_sk_list, sk);
+
        return 0;
 }
 
@@ -232,19 +240,30 @@ int cmtp_init_sockets(void)
                return err;
 
        err = bt_sock_register(BTPROTO_CMTP, &cmtp_sock_family_ops);
-       if (err < 0)
+       if (err < 0) {
+               BT_ERR("Can't register CMTP socket");
                goto error;
+       }
+
+       err = bt_procfs_init(THIS_MODULE, &init_net, "cmtp", &cmtp_sk_list, NULL);
+       if (err < 0) {
+               BT_ERR("Failed to create CMTP proc file");
+               bt_sock_unregister(BTPROTO_HIDP);
+               goto error;
+       }
+
+       BT_INFO("CMTP socket layer initialized");
 
        return 0;
 
 error:
-       BT_ERR("Can't register CMTP socket");
        proto_unregister(&cmtp_proto);
        return err;
 }
 
 void cmtp_cleanup_sockets(void)
 {
+       bt_procfs_cleanup(&init_net, "cmtp");
        if (bt_sock_unregister(BTPROTO_CMTP) < 0)
                BT_ERR("Can't unregister CMTP socket");
 
index 5ad7da21747413f50ba0106041c6e73d6ce727d4..98670b1df17be448160cdb91e84d0eceeaf1d0aa 100644 (file)
@@ -30,7 +30,7 @@
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/a2mp.h>
 
-static void hci_le_connect(struct hci_conn *conn)
+static void hci_le_create_connection(struct hci_conn *conn)
 {
        struct hci_dev *hdev = conn->hdev;
        struct hci_cp_le_create_conn cp;
@@ -54,12 +54,12 @@ static void hci_le_connect(struct hci_conn *conn)
        hci_send_cmd(hdev, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp);
 }
 
-static void hci_le_connect_cancel(struct hci_conn *conn)
+static void hci_le_create_connection_cancel(struct hci_conn *conn)
 {
        hci_send_cmd(conn->hdev, HCI_OP_LE_CREATE_CONN_CANCEL, 0, NULL);
 }
 
-void hci_acl_connect(struct hci_conn *conn)
+static void hci_acl_create_connection(struct hci_conn *conn)
 {
        struct hci_dev *hdev = conn->hdev;
        struct inquiry_entry *ie;
@@ -103,7 +103,7 @@ void hci_acl_connect(struct hci_conn *conn)
        hci_send_cmd(hdev, HCI_OP_CREATE_CONN, sizeof(cp), &cp);
 }
 
-static void hci_acl_connect_cancel(struct hci_conn *conn)
+static void hci_acl_create_connection_cancel(struct hci_conn *conn)
 {
        struct hci_cp_create_conn_cancel cp;
 
@@ -129,7 +129,7 @@ void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
        hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp);
 }
 
-void hci_add_sco(struct hci_conn *conn, __u16 handle)
+static void hci_add_sco(struct hci_conn *conn, __u16 handle)
 {
        struct hci_dev *hdev = conn->hdev;
        struct hci_cp_add_sco cp;
@@ -245,9 +245,9 @@ static void hci_conn_timeout(struct work_struct *work)
        case BT_CONNECT2:
                if (conn->out) {
                        if (conn->type == ACL_LINK)
-                               hci_acl_connect_cancel(conn);
+                               hci_acl_create_connection_cancel(conn);
                        else if (conn->type == LE_LINK)
-                               hci_le_connect_cancel(conn);
+                               hci_le_create_connection_cancel(conn);
                }
                break;
        case BT_CONFIG:
@@ -470,40 +470,37 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
 }
 EXPORT_SYMBOL(hci_get_route);
 
-/* Create SCO, ACL or LE connection.
- * Device _must_ be locked */
-struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
-                            __u8 dst_type, __u8 sec_level, __u8 auth_type)
+static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
+                                   u8 dst_type, u8 sec_level, u8 auth_type)
 {
-       struct hci_conn *acl;
-       struct hci_conn *sco;
        struct hci_conn *le;
 
-       BT_DBG("%s dst %s", hdev->name, batostr(dst));
+       le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
+       if (!le) {
+               le = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
+               if (le)
+                       return ERR_PTR(-EBUSY);
 
-       if (type == LE_LINK) {
-               le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
-               if (!le) {
-                       le = hci_conn_hash_lookup_state(hdev, LE_LINK,
-                                                       BT_CONNECT);
-                       if (le)
-                               return ERR_PTR(-EBUSY);
+               le = hci_conn_add(hdev, LE_LINK, dst);
+               if (!le)
+                       return ERR_PTR(-ENOMEM);
 
-                       le = hci_conn_add(hdev, LE_LINK, dst);
-                       if (!le)
-                               return ERR_PTR(-ENOMEM);
+               le->dst_type = bdaddr_to_le(dst_type);
+               hci_le_create_connection(le);
+       }
 
-                       le->dst_type = bdaddr_to_le(dst_type);
-                       hci_le_connect(le);
-               }
+       le->pending_sec_level = sec_level;
+       le->auth_type = auth_type;
 
-               le->pending_sec_level = sec_level;
-               le->auth_type = auth_type;
+       hci_conn_hold(le);
 
-               hci_conn_hold(le);
+       return le;
+}
 
-               return le;
-       }
+static struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
+                                               u8 sec_level, u8 auth_type)
+{
+       struct hci_conn *acl;
 
        acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
        if (!acl) {
@@ -518,15 +515,25 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
                acl->sec_level = BT_SECURITY_LOW;
                acl->pending_sec_level = sec_level;
                acl->auth_type = auth_type;
-               hci_acl_connect(acl);
+               hci_acl_create_connection(acl);
        }
 
-       if (type == ACL_LINK)
+       return acl;
+}
+
+static struct hci_conn *hci_connect_sco(struct hci_dev *hdev, bdaddr_t *dst,
+                                    u8 sec_level, u8 auth_type)
+{
+       struct hci_conn *acl;
+       struct hci_conn *sco;
+
+       acl = hci_connect_acl(hdev, dst, sec_level, auth_type);
+       if (IS_ERR(acl))
                return acl;
 
-       sco = hci_conn_hash_lookup_ba(hdev, type, dst);
+       sco = hci_conn_hash_lookup_ba(hdev, SCO_LINK, dst);
        if (!sco) {
-               sco = hci_conn_add(hdev, type, dst);
+               sco = hci_conn_add(hdev, SCO_LINK, dst);
                if (!sco) {
                        hci_conn_put(acl);
                        return ERR_PTR(-ENOMEM);
@@ -555,6 +562,24 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
        return sco;
 }
 
+/* Create SCO, ACL or LE connection. */
+struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
+                            __u8 dst_type, __u8 sec_level, __u8 auth_type)
+{
+       BT_DBG("%s dst %s type 0x%x", hdev->name, batostr(dst), type);
+
+       switch (type) {
+       case LE_LINK:
+               return hci_connect_le(hdev, dst, dst_type, sec_level, auth_type);
+       case ACL_LINK:
+               return hci_connect_acl(hdev, dst, sec_level, auth_type);
+       case SCO_LINK:
+               return hci_connect_sco(hdev, dst, sec_level, auth_type);
+       }
+
+       return ERR_PTR(-EINVAL);
+}
+
 /* Check link security requirement */
 int hci_conn_check_link_mode(struct hci_conn *conn)
 {
@@ -771,7 +796,7 @@ void hci_conn_check_pending(struct hci_dev *hdev)
 
        conn = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2);
        if (conn)
-               hci_acl_connect(conn);
+               hci_acl_create_connection(conn);
 
        hci_dev_unlock(hdev);
 }
index d4de5db18d5a8e48d950a368e7ef93840d269a07..fa974a19d365e78031cc53977871a1e2b8df2016 100644 (file)
@@ -696,7 +696,8 @@ int hci_dev_open(__u16 dev)
                hci_dev_hold(hdev);
                set_bit(HCI_UP, &hdev->flags);
                hci_notify(hdev, HCI_DEV_UP);
-               if (!test_bit(HCI_SETUP, &hdev->dev_flags)) {
+               if (!test_bit(HCI_SETUP, &hdev->dev_flags) &&
+                   mgmt_valid_hdev(hdev)) {
                        hci_dev_lock(hdev);
                        mgmt_powered(hdev, 1);
                        hci_dev_unlock(hdev);
@@ -797,7 +798,8 @@ static int hci_dev_do_close(struct hci_dev *hdev)
         * and no tasks are scheduled. */
        hdev->close(hdev);
 
-       if (!test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
+       if (!test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags) &&
+           mgmt_valid_hdev(hdev)) {
                hci_dev_lock(hdev);
                mgmt_powered(hdev, 0);
                hci_dev_unlock(hdev);
index 41ff978a33f9078b3e23b7cc3fed67c78921b5c7..48689e3401b4cf328c3c73a70b1835554555d480 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/mgmt.h>
 
 /* Handle HCI Event packets */
 
@@ -303,7 +304,7 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
 
        hci_dev_lock(hdev);
 
-       if (status != 0) {
+       if (status) {
                mgmt_write_scan_failed(hdev, param, status);
                hdev->discov_timeout = 0;
                goto done;
@@ -513,7 +514,7 @@ static void hci_setup_event_mask(struct hci_dev *hdev)
        if (hdev->features[3] & LMP_RSSI_INQ)
                events[4] |= 0x02; /* Inquiry Result with RSSI */
 
-       if (hdev->features[5] & LMP_SNIFF_SUBR)
+       if (lmp_sniffsubr_capable(hdev))
                events[5] |= 0x20; /* Sniff Subrating */
 
        if (hdev->features[5] & LMP_PAUSE_ENC)
@@ -522,13 +523,13 @@ static void hci_setup_event_mask(struct hci_dev *hdev)
        if (hdev->features[6] & LMP_EXT_INQ)
                events[5] |= 0x40; /* Extended Inquiry Result */
 
-       if (hdev->features[6] & LMP_NO_FLUSH)
+       if (lmp_no_flush_capable(hdev))
                events[7] |= 0x01; /* Enhanced Flush Complete */
 
        if (hdev->features[7] & LMP_LSTO)
                events[6] |= 0x80; /* Link Supervision Timeout Changed */
 
-       if (hdev->features[6] & LMP_SIMPLE_PAIR) {
+       if (lmp_ssp_capable(hdev)) {
                events[6] |= 0x01;      /* IO Capability Request */
                events[6] |= 0x02;      /* IO Capability Response */
                events[6] |= 0x04;      /* User Confirmation Request */
@@ -541,7 +542,7 @@ static void hci_setup_event_mask(struct hci_dev *hdev)
                                         * Features Notification */
        }
 
-       if (hdev->features[4] & LMP_LE)
+       if (lmp_le_capable(hdev))
                events[7] |= 0x20;      /* LE Meta-Event */
 
        hci_send_cmd(hdev, HCI_OP_SET_EVENT_MASK, sizeof(events), events);
@@ -623,11 +624,11 @@ static void hci_setup_link_policy(struct hci_dev *hdev)
        struct hci_cp_write_def_link_policy cp;
        u16 link_policy = 0;
 
-       if (hdev->features[0] & LMP_RSWITCH)
+       if (lmp_rswitch_capable(hdev))
                link_policy |= HCI_LP_RSWITCH;
        if (hdev->features[0] & LMP_HOLD)
                link_policy |= HCI_LP_HOLD;
-       if (hdev->features[0] & LMP_SNIFF)
+       if (lmp_sniff_capable(hdev))
                link_policy |= HCI_LP_SNIFF;
        if (hdev->features[1] & LMP_PARK)
                link_policy |= HCI_LP_PARK;
@@ -686,7 +687,7 @@ static void hci_cc_read_local_features(struct hci_dev *hdev,
                hdev->esco_type |= (ESCO_HV3);
        }
 
-       if (hdev->features[3] & LMP_ESCO)
+       if (lmp_esco_capable(hdev))
                hdev->esco_type |= (ESCO_EV3);
 
        if (hdev->features[4] & LMP_EV4)
@@ -746,7 +747,7 @@ static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
                break;
        }
 
-       if (test_bit(HCI_INIT, &hdev->flags) && hdev->features[4] & LMP_LE)
+       if (test_bit(HCI_INIT, &hdev->flags) && lmp_le_capable(hdev))
                hci_set_le_support(hdev);
 
 done:
@@ -925,7 +926,7 @@ static void hci_cc_pin_code_reply(struct hci_dev *hdev, struct sk_buff *skb)
        if (test_bit(HCI_MGMT, &hdev->dev_flags))
                mgmt_pin_code_reply_complete(hdev, &rp->bdaddr, rp->status);
 
-       if (rp->status != 0)
+       if (rp->status)
                goto unlock;
 
        cp = hci_sent_cmd_data(hdev, HCI_OP_PIN_CODE_REPLY);
@@ -1365,6 +1366,9 @@ static bool hci_resolve_next_name(struct hci_dev *hdev)
                return false;
 
        e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_NEEDED);
+       if (!e)
+               return false;
+
        if (hci_resolve_name(hdev, e) == 0) {
                e->name_state = NAME_PENDING;
                return true;
@@ -1393,12 +1397,20 @@ static void hci_check_pending_name(struct hci_dev *hdev, struct hci_conn *conn,
                return;
 
        e = hci_inquiry_cache_lookup_resolve(hdev, bdaddr, NAME_PENDING);
-       if (e) {
+       /* If the device was not found in a list of found devices names of which
+        * are pending. there is no need to continue resolving a next name as it
+        * will be done upon receiving another Remote Name Request Complete
+        * Event */
+       if (!e)
+               return;
+
+       list_del(&e->list);
+       if (name) {
                e->name_state = NAME_KNOWN;
-               list_del(&e->list);
-               if (name)
-                       mgmt_remote_name(hdev, bdaddr, ACL_LINK, 0x00,
-                                        e->data.rssi, name, name_len);
+               mgmt_remote_name(hdev, bdaddr, ACL_LINK, 0x00,
+                                e->data.rssi, name, name_len);
+       } else {
+               e->name_state = NAME_NOT_KNOWN;
        }
 
        if (hci_resolve_next_name(hdev))
@@ -1614,43 +1626,30 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status)
 
 static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status)
 {
-       struct hci_cp_le_create_conn *cp;
        struct hci_conn *conn;
 
        BT_DBG("%s status 0x%2.2x", hdev->name, status);
 
-       cp = hci_sent_cmd_data(hdev, HCI_OP_LE_CREATE_CONN);
-       if (!cp)
-               return;
+       if (status) {
+               hci_dev_lock(hdev);
 
-       hci_dev_lock(hdev);
+               conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
+               if (!conn) {
+                       hci_dev_unlock(hdev);
+                       return;
+               }
 
-       conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->peer_addr);
+               BT_DBG("%s bdaddr %s conn %p", hdev->name, batostr(&conn->dst),
+                      conn);
 
-       BT_DBG("%s bdaddr %s conn %p", hdev->name, batostr(&cp->peer_addr),
-              conn);
+               conn->state = BT_CLOSED;
+               mgmt_connect_failed(hdev, &conn->dst, conn->type,
+                                   conn->dst_type, status);
+               hci_proto_connect_cfm(conn, status);
+               hci_conn_del(conn);
 
-       if (status) {
-               if (conn && conn->state == BT_CONNECT) {
-                       conn->state = BT_CLOSED;
-                       mgmt_connect_failed(hdev, &cp->peer_addr, conn->type,
-                                           conn->dst_type, status);
-                       hci_proto_connect_cfm(conn, status);
-                       hci_conn_del(conn);
-               }
-       } else {
-               if (!conn) {
-                       conn = hci_conn_add(hdev, LE_LINK, &cp->peer_addr);
-                       if (conn) {
-                               conn->dst_type = cp->peer_addr_type;
-                               conn->out = true;
-                       } else {
-                               BT_ERR("No memory for new connection");
-                       }
-               }
+               hci_dev_unlock(hdev);
        }
-
-       hci_dev_unlock(hdev);
 }
 
 static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status)
@@ -1762,7 +1761,12 @@ static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
                if (conn->type == ACL_LINK) {
                        conn->state = BT_CONFIG;
                        hci_conn_hold(conn);
-                       conn->disc_timeout = HCI_DISCONN_TIMEOUT;
+
+                       if (!conn->out && !hci_conn_ssp_enabled(conn) &&
+                           !hci_find_link_key(hdev, &ev->bdaddr))
+                               conn->disc_timeout = HCI_PAIRING_TIMEOUT;
+                       else
+                               conn->disc_timeout = HCI_DISCONN_TIMEOUT;
                } else
                        conn->state = BT_CONNECTED;
 
@@ -1888,6 +1892,22 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
        }
 }
 
+static u8 hci_to_mgmt_reason(u8 err)
+{
+       switch (err) {
+       case HCI_ERROR_CONNECTION_TIMEOUT:
+               return MGMT_DEV_DISCONN_TIMEOUT;
+       case HCI_ERROR_REMOTE_USER_TERM:
+       case HCI_ERROR_REMOTE_LOW_RESOURCES:
+       case HCI_ERROR_REMOTE_POWER_OFF:
+               return MGMT_DEV_DISCONN_REMOTE;
+       case HCI_ERROR_LOCAL_HOST_TERM:
+               return MGMT_DEV_DISCONN_LOCAL_HOST;
+       default:
+               return MGMT_DEV_DISCONN_UNKNOWN;
+       }
+}
+
 static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_disconn_complete *ev = (void *) skb->data;
@@ -1906,12 +1926,15 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
        if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags) &&
            (conn->type == ACL_LINK || conn->type == LE_LINK)) {
-               if (ev->status != 0)
+               if (ev->status) {
                        mgmt_disconnect_failed(hdev, &conn->dst, conn->type,
                                               conn->dst_type, ev->status);
-               else
+               } else {
+                       u8 reason = hci_to_mgmt_reason(ev->reason);
+
                        mgmt_device_disconnected(hdev, &conn->dst, conn->type,
-                                                conn->dst_type);
+                                                conn->dst_type, reason);
+               }
        }
 
        if (ev->status == 0) {
@@ -3252,12 +3275,8 @@ static void hci_user_passkey_request_evt(struct hci_dev *hdev,
 
        BT_DBG("%s", hdev->name);
 
-       hci_dev_lock(hdev);
-
        if (test_bit(HCI_MGMT, &hdev->dev_flags))
                mgmt_user_passkey_request(hdev, &ev->bdaddr, ACL_LINK, 0);
-
-       hci_dev_unlock(hdev);
 }
 
 static void hci_simple_pair_complete_evt(struct hci_dev *hdev,
@@ -3279,7 +3298,7 @@ static void hci_simple_pair_complete_evt(struct hci_dev *hdev,
         * initiated the authentication. A traditional auth_complete
         * event gets always produced as initiator and is also mapped to
         * the mgmt_auth_failed event */
-       if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags) && ev->status != 0)
+       if (!test_bit(HCI_CONN_AUTH_PEND, &conn->flags) && ev->status)
                mgmt_auth_failed(hdev, &conn->dst, conn->type, conn->dst_type,
                                 ev->status);
 
@@ -3350,11 +3369,23 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
        hci_dev_lock(hdev);
 
-       if (ev->status) {
-               conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
-               if (!conn)
+       conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
+       if (!conn) {
+               conn = hci_conn_add(hdev, LE_LINK, &ev->bdaddr);
+               if (!conn) {
+                       BT_ERR("No memory for new connection");
                        goto unlock;
+               }
+
+               conn->dst_type = ev->bdaddr_type;
+
+               if (ev->role == LE_CONN_ROLE_MASTER) {
+                       conn->out = true;
+                       conn->link_mode |= HCI_LM_MASTER;
+               }
+       }
 
+       if (ev->status) {
                mgmt_connect_failed(hdev, &conn->dst, conn->type,
                                    conn->dst_type, ev->status);
                hci_proto_connect_cfm(conn, ev->status);
@@ -3363,18 +3394,6 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
                goto unlock;
        }
 
-       conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &ev->bdaddr);
-       if (!conn) {
-               conn = hci_conn_add(hdev, LE_LINK, &ev->bdaddr);
-               if (!conn) {
-                       BT_ERR("No memory for new connection");
-                       hci_dev_unlock(hdev);
-                       return;
-               }
-
-               conn->dst_type = ev->bdaddr_type;
-       }
-
        if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
                mgmt_device_connected(hdev, &ev->bdaddr, conn->type,
                                      conn->dst_type, 0, NULL, 0, NULL);
index a7f04de03d7916add5a20cf44d8e88e5daad495d..bb64331db3b7c1a329a58b05b3fd09382718144f 100644 (file)
@@ -694,6 +694,7 @@ static int hci_sock_getname(struct socket *sock, struct sockaddr *addr,
        *addr_len = sizeof(*haddr);
        haddr->hci_family = AF_BLUETOOTH;
        haddr->hci_dev    = hdev->id;
+       haddr->hci_channel= 0;
 
        release_sock(sk);
        return 0;
@@ -1009,6 +1010,7 @@ static int hci_sock_getsockopt(struct socket *sock, int level, int optname,
                {
                        struct hci_filter *f = &hci_pi(sk)->filter;
 
+                       memset(&uf, 0, sizeof(uf));
                        uf.type_mask = f->type_mask;
                        uf.opcode    = f->opcode;
                        uf.event_mask[0] = *((u32 *) f->event_mask + 0);
@@ -1100,21 +1102,30 @@ int __init hci_sock_init(void)
                return err;
 
        err = bt_sock_register(BTPROTO_HCI, &hci_sock_family_ops);
-       if (err < 0)
+       if (err < 0) {
+               BT_ERR("HCI socket registration failed");
                goto error;
+       }
+
+       err = bt_procfs_init(THIS_MODULE, &init_net, "hci", &hci_sk_list, NULL);
+       if (err < 0) {
+               BT_ERR("Failed to create HCI proc file");
+               bt_sock_unregister(BTPROTO_HCI);
+               goto error;
+       }
 
        BT_INFO("HCI socket layer initialized");
 
        return 0;
 
 error:
-       BT_ERR("HCI socket registration failed");
        proto_unregister(&hci_sk_proto);
        return err;
 }
 
 void hci_sock_cleanup(void)
 {
+       bt_procfs_cleanup(&init_net, "hci");
        if (bt_sock_unregister(BTPROTO_HCI) < 0)
                BT_ERR("HCI socket unregistration failed");
 
index 18b3f6892a36847de621954cbae7358ae719c0be..eca3889371c4395e43ac589ce7d485727b0ac1b2 100644 (file)
 
 #include "hidp.h"
 
+static struct bt_sock_list hidp_sk_list = {
+       .lock = __RW_LOCK_UNLOCKED(hidp_sk_list.lock)
+};
+
 static int hidp_sock_release(struct socket *sock)
 {
        struct sock *sk = sock->sk;
@@ -34,6 +38,8 @@ static int hidp_sock_release(struct socket *sock)
        if (!sk)
                return 0;
 
+       bt_sock_unlink(&hidp_sk_list, sk);
+
        sock_orphan(sk);
        sock_put(sk);
 
@@ -253,6 +259,8 @@ static int hidp_sock_create(struct net *net, struct socket *sock, int protocol,
        sk->sk_protocol = protocol;
        sk->sk_state    = BT_OPEN;
 
+       bt_sock_link(&hidp_sk_list, sk);
+
        return 0;
 }
 
@@ -271,8 +279,19 @@ int __init hidp_init_sockets(void)
                return err;
 
        err = bt_sock_register(BTPROTO_HIDP, &hidp_sock_family_ops);
-       if (err < 0)
+       if (err < 0) {
+               BT_ERR("Can't register HIDP socket");
                goto error;
+       }
+
+       err = bt_procfs_init(THIS_MODULE, &init_net, "hidp", &hidp_sk_list, NULL);
+       if (err < 0) {
+               BT_ERR("Failed to create HIDP proc file");
+               bt_sock_unregister(BTPROTO_HIDP);
+               goto error;
+       }
+
+       BT_INFO("HIDP socket layer initialized");
 
        return 0;
 
@@ -284,6 +303,7 @@ error:
 
 void __exit hidp_cleanup_sockets(void)
 {
+       bt_procfs_cleanup(&init_net, "hidp");
        if (bt_sock_unregister(BTPROTO_HIDP) < 0)
                BT_ERR("Can't unregister HIDP socket");
 
index a8964db04bfb5cd1d0d348ed96c472e4786f3f44..f0a3ab156ec60a2c119119e1a9efe98aaeb34013 100644 (file)
@@ -416,13 +416,30 @@ struct l2cap_chan *l2cap_chan_create(void)
        return chan;
 }
 
-void l2cap_chan_destroy(struct l2cap_chan *chan)
+static void l2cap_chan_destroy(struct l2cap_chan *chan)
 {
+       BT_DBG("chan %p", chan);
+
        write_lock(&chan_list_lock);
        list_del(&chan->global_l);
        write_unlock(&chan_list_lock);
 
-       l2cap_chan_put(chan);
+       kfree(chan);
+}
+
+void l2cap_chan_hold(struct l2cap_chan *c)
+{
+       BT_DBG("chan %p orig refcnt %d", c, atomic_read(&c->refcnt));
+
+       atomic_inc(&c->refcnt);
+}
+
+void l2cap_chan_put(struct l2cap_chan *c)
+{
+       BT_DBG("chan %p orig refcnt %d", c, atomic_read(&c->refcnt));
+
+       if (atomic_dec_and_test(&c->refcnt))
+               l2cap_chan_destroy(c);
 }
 
 void l2cap_chan_set_defaults(struct l2cap_chan *chan)
@@ -1181,6 +1198,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
        sk = chan->sk;
 
        hci_conn_hold(conn->hcon);
+       conn->hcon->disc_timeout = HCI_DISCONN_TIMEOUT;
 
        bacpy(&bt_sk(sk)->src, conn->src);
        bacpy(&bt_sk(sk)->dst, conn->dst);
@@ -5329,7 +5347,7 @@ int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
        return exact ? lm1 : lm2;
 }
 
-int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
+void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
 {
        struct l2cap_conn *conn;
 
@@ -5342,7 +5360,6 @@ int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
        } else
                l2cap_conn_del(hcon, bt_to_errno(status));
 
-       return 0;
 }
 
 int l2cap_disconn_ind(struct hci_conn *hcon)
@@ -5356,12 +5373,11 @@ int l2cap_disconn_ind(struct hci_conn *hcon)
        return conn->disc_reason;
 }
 
-int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
+void l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
 {
        BT_DBG("hcon %p reason %d", hcon, reason);
 
        l2cap_conn_del(hcon, bt_to_errno(reason));
-       return 0;
 }
 
 static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
@@ -5404,6 +5420,11 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
                BT_DBG("chan %p scid 0x%4.4x state %s", chan, chan->scid,
                       state_to_string(chan->state));
 
+               if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) {
+                       l2cap_chan_unlock(chan);
+                       continue;
+               }
+
                if (chan->scid == L2CAP_CID_LE_DATA) {
                        if (!status && encrypt) {
                                chan->sec_level = hcon->sec_level;
index a4bb27e8427e9aabaa48b90727cb23bcf5568f96..3a6ce73541d97aee7f270013d106f5d578884684 100644 (file)
 #include <net/bluetooth/l2cap.h>
 #include <net/bluetooth/smp.h>
 
+static struct bt_sock_list l2cap_sk_list = {
+       .lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock)
+};
+
 static const struct proto_ops l2cap_sock_ops;
 static void l2cap_sock_init(struct sock *sk, struct sock *parent);
 static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio);
@@ -245,6 +249,7 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l
 
        BT_DBG("sock %p, sk %p", sock, sk);
 
+       memset(la, 0, sizeof(struct sockaddr_l2));
        addr->sa_family = AF_BLUETOOTH;
        *len = sizeof(struct sockaddr_l2);
 
@@ -823,7 +828,7 @@ static void l2cap_sock_kill(struct sock *sk)
 
        /* Kill poor orphan */
 
-       l2cap_chan_destroy(l2cap_pi(sk)->chan);
+       l2cap_chan_put(l2cap_pi(sk)->chan);
        sock_set_flag(sk, SOCK_DEAD);
        sock_put(sk);
 }
@@ -886,6 +891,8 @@ static int l2cap_sock_release(struct socket *sock)
        if (!sk)
                return 0;
 
+       bt_sock_unlink(&l2cap_sk_list, sk);
+
        err = l2cap_sock_shutdown(sock, 2);
 
        sock_orphan(sk);
@@ -1174,7 +1181,7 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int p
 
        chan = l2cap_chan_create();
        if (!chan) {
-               l2cap_sock_kill(sk);
+               sk_free(sk);
                return NULL;
        }
 
@@ -1210,6 +1217,7 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
                return -ENOMEM;
 
        l2cap_sock_init(sk, NULL);
+       bt_sock_link(&l2cap_sk_list, sk);
        return 0;
 }
 
@@ -1248,21 +1256,30 @@ int __init l2cap_init_sockets(void)
                return err;
 
        err = bt_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops);
-       if (err < 0)
+       if (err < 0) {
+               BT_ERR("L2CAP socket registration failed");
                goto error;
+       }
+
+       err = bt_procfs_init(THIS_MODULE, &init_net, "l2cap", &l2cap_sk_list, NULL);
+       if (err < 0) {
+               BT_ERR("Failed to create L2CAP proc file");
+               bt_sock_unregister(BTPROTO_L2CAP);
+               goto error;
+       }
 
        BT_INFO("L2CAP socket layer initialized");
 
        return 0;
 
 error:
-       BT_ERR("L2CAP socket registration failed");
        proto_unregister(&l2cap_proto);
        return err;
 }
 
 void l2cap_cleanup_sockets(void)
 {
+       bt_procfs_cleanup(&init_net, "l2cap");
        if (bt_sock_unregister(BTPROTO_L2CAP) < 0)
                BT_ERR("L2CAP socket unregistration failed");
 
index ad6613d17ca6de815be200b9576d6ecf510fef0d..05d4b83a01894ed9ef86843a2493a5207fd4d82a 100644 (file)
@@ -193,6 +193,11 @@ static u8 mgmt_status_table[] = {
        MGMT_STATUS_CONNECT_FAILED,     /* MAC Connection Failed */
 };
 
+bool mgmt_valid_hdev(struct hci_dev *hdev)
+{
+       return hdev->dev_type == HCI_BREDR;
+}
+
 static u8 mgmt_status(u8 hci_status)
 {
        if (hci_status < ARRAY_SIZE(mgmt_status_table))
@@ -317,7 +322,6 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
                           u16 data_len)
 {
        struct mgmt_rp_read_index_list *rp;
-       struct list_head *p;
        struct hci_dev *d;
        size_t rp_len;
        u16 count;
@@ -328,7 +332,10 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
        read_lock(&hci_dev_list_lock);
 
        count = 0;
-       list_for_each(p, &hci_dev_list) {
+       list_for_each_entry(d, &hci_dev_list, list) {
+               if (!mgmt_valid_hdev(d))
+                       continue;
+
                count++;
        }
 
@@ -346,6 +353,9 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
                if (test_bit(HCI_SETUP, &d->dev_flags))
                        continue;
 
+               if (!mgmt_valid_hdev(d))
+                       continue;
+
                rp->index[i++] = cpu_to_le16(d->id);
                BT_DBG("Added hci%u", d->id);
        }
@@ -370,10 +380,10 @@ static u32 get_supported_settings(struct hci_dev *hdev)
        settings |= MGMT_SETTING_DISCOVERABLE;
        settings |= MGMT_SETTING_PAIRABLE;
 
-       if (hdev->features[6] & LMP_SIMPLE_PAIR)
+       if (lmp_ssp_capable(hdev))
                settings |= MGMT_SETTING_SSP;
 
-       if (!(hdev->features[4] & LMP_NO_BREDR)) {
+       if (lmp_bredr_capable(hdev)) {
                settings |= MGMT_SETTING_BREDR;
                settings |= MGMT_SETTING_LINK_SECURITY;
        }
@@ -381,7 +391,7 @@ static u32 get_supported_settings(struct hci_dev *hdev)
        if (enable_hs)
                settings |= MGMT_SETTING_HS;
 
-       if (hdev->features[4] & LMP_LE)
+       if (lmp_le_capable(hdev))
                settings |= MGMT_SETTING_LE;
 
        return settings;
@@ -403,7 +413,7 @@ static u32 get_current_settings(struct hci_dev *hdev)
        if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
                settings |= MGMT_SETTING_PAIRABLE;
 
-       if (!(hdev->features[4] & LMP_NO_BREDR))
+       if (lmp_bredr_capable(hdev))
                settings |= MGMT_SETTING_BREDR;
 
        if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
@@ -1111,7 +1121,7 @@ static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
 
        hci_dev_lock(hdev);
 
-       if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
+       if (!lmp_ssp_capable(hdev)) {
                err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
                                 MGMT_STATUS_NOT_SUPPORTED);
                goto failed;
@@ -1195,7 +1205,7 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
 
        hci_dev_lock(hdev);
 
-       if (!(hdev->features[4] & LMP_LE)) {
+       if (!lmp_le_capable(hdev)) {
                err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
                                 MGMT_STATUS_NOT_SUPPORTED);
                goto unlock;
@@ -2191,7 +2201,7 @@ static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
                goto unlock;
        }
 
-       if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
+       if (!lmp_ssp_capable(hdev)) {
                err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
                                 MGMT_STATUS_NOT_SUPPORTED);
                goto unlock;
@@ -2820,6 +2830,9 @@ static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
 
 int mgmt_index_added(struct hci_dev *hdev)
 {
+       if (!mgmt_valid_hdev(hdev))
+               return -ENOTSUPP;
+
        return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
 }
 
@@ -2827,6 +2840,9 @@ int mgmt_index_removed(struct hci_dev *hdev)
 {
        u8 status = MGMT_STATUS_INVALID_INDEX;
 
+       if (!mgmt_valid_hdev(hdev))
+               return -ENOTSUPP;
+
        mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
 
        return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
@@ -3061,16 +3077,17 @@ static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
 }
 
 int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
-                            u8 link_type, u8 addr_type)
+                            u8 link_type, u8 addr_type, u8 reason)
 {
-       struct mgmt_addr_info ev;
+       struct mgmt_ev_device_disconnected ev;
        struct sock *sk = NULL;
        int err;
 
        mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
 
-       bacpy(&ev.bdaddr, bdaddr);
-       ev.type = link_to_bdaddr(link_type, addr_type);
+       bacpy(&ev.addr.bdaddr, bdaddr);
+       ev.addr.type = link_to_bdaddr(link_type, addr_type);
+       ev.reason = reason;
 
        err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
                         sk);
index 7e1e59645c056f71400ad9ed4dc0444548c41951..b3226f3658cfda1142c7484b110324115dccc85b 100644 (file)
@@ -528,6 +528,7 @@ static int rfcomm_sock_getname(struct socket *sock, struct sockaddr *addr, int *
 
        BT_DBG("sock %p, sk %p", sock, sk);
 
+       memset(sa, 0, sizeof(*sa));
        sa->rc_family  = AF_BLUETOOTH;
        sa->rc_channel = rfcomm_pi(sk)->channel;
        if (peer)
@@ -822,6 +823,7 @@ static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, c
                }
 
                sec.level = rfcomm_pi(sk)->sec_level;
+               sec.key_size = 0;
 
                len = min_t(unsigned int, len, sizeof(sec));
                if (copy_to_user(optval, (char *) &sec, len))
@@ -1033,8 +1035,17 @@ int __init rfcomm_init_sockets(void)
                return err;
 
        err = bt_sock_register(BTPROTO_RFCOMM, &rfcomm_sock_family_ops);
-       if (err < 0)
+       if (err < 0) {
+               BT_ERR("RFCOMM socket layer registration failed");
+               goto error;
+       }
+
+       err = bt_procfs_init(THIS_MODULE, &init_net, "rfcomm", &rfcomm_sk_list, NULL);
+       if (err < 0) {
+               BT_ERR("Failed to create RFCOMM proc file");
+               bt_sock_unregister(BTPROTO_RFCOMM);
                goto error;
+       }
 
        if (bt_debugfs) {
                rfcomm_sock_debugfs = debugfs_create_file("rfcomm", 0444,
@@ -1048,13 +1059,14 @@ int __init rfcomm_init_sockets(void)
        return 0;
 
 error:
-       BT_ERR("RFCOMM socket layer registration failed");
        proto_unregister(&rfcomm_proto);
        return err;
 }
 
 void __exit rfcomm_cleanup_sockets(void)
 {
+       bt_procfs_cleanup(&init_net, "rfcomm");
+
        debugfs_remove(rfcomm_sock_debugfs);
 
        if (bt_sock_unregister(BTPROTO_RFCOMM) < 0)
index cb960773c002efafeb45b888ee8f3ba3e9208490..ccc248791d50239c24fce5c0635245f33f654fa3 100644 (file)
@@ -278,8 +278,8 @@ out:
        if (err < 0)
                goto free;
 
-       dev->tty_dev = tty_register_device(rfcomm_tty_driver, dev->id, NULL);
-
+       dev->tty_dev = tty_port_register_device(&dev->port, rfcomm_tty_driver,
+                       dev->id, NULL);
        if (IS_ERR(dev->tty_dev)) {
                err = PTR_ERR(dev->tty_dev);
                list_del(&dev->list);
@@ -456,7 +456,7 @@ static int rfcomm_get_dev_list(void __user *arg)
 
        size = sizeof(*dl) + dev_num * sizeof(*di);
 
-       dl = kmalloc(size, GFP_KERNEL);
+       dl = kzalloc(size, GFP_KERNEL);
        if (!dl)
                return -ENOMEM;
 
@@ -705,9 +705,9 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
                        break;
                }
 
-               tty_unlock();
+               tty_unlock(tty);
                schedule();
-               tty_lock();
+               tty_lock(tty);
        }
        set_current_state(TASK_RUNNING);
        remove_wait_queue(&dev->wait, &wait);
@@ -861,7 +861,7 @@ static int rfcomm_tty_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned l
 
 static void rfcomm_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
 {
-       struct ktermios *new = tty->termios;
+       struct ktermios *new = &tty->termios;
        int old_baud_rate = tty_termios_baud_rate(old);
        int new_baud_rate = tty_termios_baud_rate(new);
 
index 40bbe25dcff7f97c9a279c6d087eaed078563364..dc42b917aaafad3f050177694c438648af2b22bb 100644 (file)
@@ -131,6 +131,15 @@ static int sco_conn_del(struct hci_conn *hcon, int err)
                sco_sock_clear_timer(sk);
                sco_chan_del(sk, err);
                bh_unlock_sock(sk);
+
+               sco_conn_lock(conn);
+               conn->sk = NULL;
+               sco_pi(sk)->conn = NULL;
+               sco_conn_unlock(conn);
+
+               if (conn->hcon)
+                       hci_conn_put(conn->hcon);
+
                sco_sock_kill(sk);
        }
 
@@ -821,16 +830,6 @@ static void sco_chan_del(struct sock *sk, int err)
 
        BT_DBG("sk %p, conn %p, err %d", sk, conn, err);
 
-       if (conn) {
-               sco_conn_lock(conn);
-               conn->sk = NULL;
-               sco_pi(sk)->conn = NULL;
-               sco_conn_unlock(conn);
-
-               if (conn->hcon)
-                       hci_conn_put(conn->hcon);
-       }
-
        sk->sk_state = BT_CLOSED;
        sk->sk_err   = err;
        sk->sk_state_change(sk);
@@ -913,7 +912,7 @@ int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
        return lm;
 }
 
-int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
+void sco_connect_cfm(struct hci_conn *hcon, __u8 status)
 {
        BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
        if (!status) {
@@ -924,16 +923,13 @@ int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
                        sco_conn_ready(conn);
        } else
                sco_conn_del(hcon, bt_to_errno(status));
-
-       return 0;
 }
 
-int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
+void sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
 {
        BT_DBG("hcon %p reason %d", hcon, reason);
 
        sco_conn_del(hcon, bt_to_errno(reason));
-       return 0;
 }
 
 int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb)
@@ -1026,6 +1022,13 @@ int __init sco_init(void)
                goto error;
        }
 
+       err = bt_procfs_init(THIS_MODULE, &init_net, "sco", &sco_sk_list, NULL);
+       if (err < 0) {
+               BT_ERR("Failed to create SCO proc file");
+               bt_sock_unregister(BTPROTO_SCO);
+               goto error;
+       }
+
        if (bt_debugfs) {
                sco_debugfs = debugfs_create_file("sco", 0444, bt_debugfs,
                                                  NULL, &sco_debugfs_fops);
@@ -1044,6 +1047,8 @@ error:
 
 void __exit sco_exit(void)
 {
+       bt_procfs_cleanup(&init_net, "sco");
+
        debugfs_remove(sco_debugfs);
 
        if (bt_sock_unregister(BTPROTO_SCO) < 0)
index 16ef0dc85a0a87580c311563028cc567fa826bce..901a616c8083e22f5163f8bbd1613b1529c63519 100644 (file)
@@ -579,8 +579,11 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
 
        if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags))
                smp = smp_chan_create(conn);
+       else
+               smp = conn->smp_chan;
 
-       smp = conn->smp_chan;
+       if (!smp)
+               return SMP_UNSPECIFIED;
 
        smp->preq[0] = SMP_CMD_PAIRING_REQ;
        memcpy(&smp->preq[1], req, sizeof(*req));
index 3334845376005cdba3a3b6b2d0b4013da4617446..070e8a68cfc63f856b281b4f19e08181cbd5172f 100644 (file)
@@ -31,9 +31,11 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
        struct net_bridge_mdb_entry *mdst;
        struct br_cpu_netstats *brstats = this_cpu_ptr(br->stats);
 
+       rcu_read_lock();
 #ifdef CONFIG_BRIDGE_NETFILTER
        if (skb->nf_bridge && (skb->nf_bridge->mask & BRNF_BRIDGED_DNAT)) {
                br_nf_pre_routing_finish_bridge_slow(skb);
+               rcu_read_unlock();
                return NETDEV_TX_OK;
        }
 #endif
@@ -48,7 +50,6 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
        skb_reset_mac_header(skb);
        skb_pull(skb, ETH_HLEN);
 
-       rcu_read_lock();
        if (is_broadcast_ether_addr(dest))
                br_flood_deliver(br, skb);
        else if (is_multicast_ether_addr(dest)) {
@@ -206,24 +207,23 @@ static void br_poll_controller(struct net_device *br_dev)
 static void br_netpoll_cleanup(struct net_device *dev)
 {
        struct net_bridge *br = netdev_priv(dev);
-       struct net_bridge_port *p, *n;
+       struct net_bridge_port *p;
 
-       list_for_each_entry_safe(p, n, &br->port_list, list) {
+       list_for_each_entry(p, &br->port_list, list)
                br_netpoll_disable(p);
-       }
 }
 
-static int br_netpoll_setup(struct net_device *dev, struct netpoll_info *ni)
+static int br_netpoll_setup(struct net_device *dev, struct netpoll_info *ni,
+                           gfp_t gfp)
 {
        struct net_bridge *br = netdev_priv(dev);
-       struct net_bridge_port *p, *n;
+       struct net_bridge_port *p;
        int err = 0;
 
-       list_for_each_entry_safe(p, n, &br->port_list, list) {
+       list_for_each_entry(p, &br->port_list, list) {
                if (!p->dev)
                        continue;
-
-               err = br_netpoll_enable(p);
+               err = br_netpoll_enable(p, gfp);
                if (err)
                        goto fail;
        }
@@ -236,17 +236,17 @@ fail:
        goto out;
 }
 
-int br_netpoll_enable(struct net_bridge_port *p)
+int br_netpoll_enable(struct net_bridge_port *p, gfp_t gfp)
 {
        struct netpoll *np;
        int err = 0;
 
-       np = kzalloc(sizeof(*p->np), GFP_KERNEL);
+       np = kzalloc(sizeof(*p->np), gfp);
        err = -ENOMEM;
        if (!np)
                goto out;
 
-       err = __netpoll_setup(np, p->dev);
+       err = __netpoll_setup(np, p->dev, gfp);
        if (err) {
                kfree(np);
                goto out;
@@ -267,11 +267,7 @@ void br_netpoll_disable(struct net_bridge_port *p)
 
        p->np = NULL;
 
-       /* Wait for transmitting packets to finish before freeing. */
-       synchronize_rcu_bh();
-
-       __netpoll_cleanup(np);
-       kfree(np);
+       __netpoll_free_rcu(np);
 }
 
 #endif
index d21f32383517f6b66a3b0c43ea534beb3840307c..9ce430b4657c2781efa84b136122b1292516f53d 100644 (file)
@@ -312,7 +312,7 @@ int br_fdb_fillbuf(struct net_bridge *br, void *buf,
 
                        fe->is_local = f->is_local;
                        if (!f->is_static)
-                               fe->ageing_timer_value = jiffies_to_clock_t(jiffies - f->updated);
+                               fe->ageing_timer_value = jiffies_delta_to_clock_t(jiffies - f->updated);
                        ++fe;
                        ++num;
                }
index e9466d412707849b17b01200240cbb67e66b20af..02015a505d2a41ddbf5c6abea3867613fe7030e8 100644 (file)
@@ -65,7 +65,7 @@ static void __br_deliver(const struct net_bridge_port *to, struct sk_buff *skb)
 {
        skb->dev = to->dev;
 
-       if (unlikely(netpoll_tx_running(to->dev))) {
+       if (unlikely(netpoll_tx_running(to->br->dev))) {
                if (packet_length(skb) > skb->dev->mtu && !skb_is_gso(skb))
                        kfree_skb(skb);
                else {
index e1144e1617be38814ebb2fb497755cb10b646559..1c8fdc3558cd48e9ad5d7be9c3981ebf80878364 100644 (file)
@@ -361,7 +361,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
        if (err)
                goto err2;
 
-       if (br_netpoll_info(br) && ((err = br_netpoll_enable(p))))
+       if (br_netpoll_info(br) && ((err = br_netpoll_enable(p, GFP_KERNEL))))
                goto err3;
 
        err = netdev_set_master(dev, br->dev);
@@ -427,6 +427,10 @@ int br_del_if(struct net_bridge *br, struct net_device *dev)
        if (!p || p->br != br)
                return -EINVAL;
 
+       /* Since more than one interface can be attached to a bridge,
+        * there still maybe an alternate path for netconsole to use;
+        * therefore there is no reason for a NETDEV_RELEASE event.
+        */
        del_nbp(p);
 
        spin_lock_bh(&br->lock);
index a768b2408edff64890dde477df5918c102630a5e..f507d2af9646bcb273cf1f50f98feb065027e14a 100644 (file)
@@ -316,7 +316,7 @@ static inline void br_netpoll_send_skb(const struct net_bridge_port *p,
                netpoll_send_skb(np, skb);
 }
 
-extern int br_netpoll_enable(struct net_bridge_port *p);
+extern int br_netpoll_enable(struct net_bridge_port *p, gfp_t gfp);
 extern void br_netpoll_disable(struct net_bridge_port *p);
 #else
 static inline struct netpoll_info *br_netpoll_info(struct net_bridge *br)
@@ -329,7 +329,7 @@ static inline void br_netpoll_send_skb(const struct net_bridge_port *p,
 {
 }
 
-static inline int br_netpoll_enable(struct net_bridge_port *p)
+static inline int br_netpoll_enable(struct net_bridge_port *p, gfp_t gfp)
 {
        return 0;
 }
index a6747e673426e3f29c734f11596c1be328e7b558..c3530a81a33bf40c9162cb28a6f931ea937baf54 100644 (file)
@@ -170,5 +170,5 @@ void br_stp_port_timer_init(struct net_bridge_port *p)
 unsigned long br_timer_value(const struct timer_list *timer)
 {
        return timer_pending(timer)
-               ? jiffies_to_clock_t(timer->expires - jiffies) : 0;
+               ? jiffies_delta_to_clock_t(timer->expires - jiffies) : 0;
 }
index 0cb3fe8d8e7248c1618829673041135a606b36ff..598da19e1cd93a6f0c567f41f145f8546822bb27 100644 (file)
@@ -1055,6 +1055,8 @@ rollback:
  */
 int dev_set_alias(struct net_device *dev, const char *alias, size_t len)
 {
+       char *new_ifalias;
+
        ASSERT_RTNL();
 
        if (len >= IFALIASZ)
@@ -1068,9 +1070,10 @@ int dev_set_alias(struct net_device *dev, const char *alias, size_t len)
                return 0;
        }
 
-       dev->ifalias = krealloc(dev->ifalias, len + 1, GFP_KERNEL);
-       if (!dev->ifalias)
+       new_ifalias = krealloc(dev->ifalias, len + 1, GFP_KERNEL);
+       if (!new_ifalias)
                return -ENOMEM;
+       dev->ifalias = new_ifalias;
 
        strlcpy(dev->ifalias, alias, len+1);
        return len;
@@ -1106,11 +1109,23 @@ void netdev_state_change(struct net_device *dev)
 }
 EXPORT_SYMBOL(netdev_state_change);
 
-int netdev_bonding_change(struct net_device *dev, unsigned long event)
+/**
+ *     netdev_notify_peers - notify network peers about existence of @dev
+ *     @dev: network device
+ *
+ * Generate traffic such that interested network peers are aware of
+ * @dev, such as by generating a gratuitous ARP. This may be used when
+ * a device wants to inform the rest of the network about some sort of
+ * reconfiguration such as a failover event or virtual machine
+ * migration.
+ */
+void netdev_notify_peers(struct net_device *dev)
 {
-       return call_netdevice_notifiers(event, dev);
+       rtnl_lock();
+       call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, dev);
+       rtnl_unlock();
 }
-EXPORT_SYMBOL(netdev_bonding_change);
+EXPORT_SYMBOL(netdev_notify_peers);
 
 /**
  *     dev_load        - load a network module
@@ -2134,6 +2149,9 @@ netdev_features_t netif_skb_features(struct sk_buff *skb)
        __be16 protocol = skb->protocol;
        netdev_features_t features = skb->dev->features;
 
+       if (skb_shinfo(skb)->gso_segs > skb->dev->gso_max_segs)
+               features &= ~NETIF_F_GSO_MASK;
+
        if (protocol == htons(ETH_P_8021Q)) {
                struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data;
                protocol = veh->h_vlan_encapsulated_proto;
@@ -5218,12 +5236,12 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
  */
 static int dev_new_index(struct net *net)
 {
-       static int ifindex;
+       int ifindex = net->ifindex;
        for (;;) {
                if (++ifindex <= 0)
                        ifindex = 1;
                if (!__dev_get_by_index(net, ifindex))
-                       return ifindex;
+                       return net->ifindex = ifindex;
        }
 }
 
@@ -5576,7 +5594,12 @@ int register_netdevice(struct net_device *dev)
                }
        }
 
-       dev->ifindex = dev_new_index(net);
+       ret = -EBUSY;
+       if (!dev->ifindex)
+               dev->ifindex = dev_new_index(net);
+       else if (__dev_get_by_index(net, dev->ifindex))
+               goto err_uninit;
+
        if (dev->iflink == -1)
                dev->iflink = dev->ifindex;
 
@@ -5986,6 +6009,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
        dev_net_set(dev, &init_net);
 
        dev->gso_max_size = GSO_MAX_SIZE;
+       dev->gso_max_segs = GSO_MAX_SEGS;
 
        INIT_LIST_HEAD(&dev->napi_list);
        INIT_LIST_HEAD(&dev->unreg_list);
index 069d51d29414a3245f9b60b66c534f78ce3b1752..b8d7c700541d71488e9e3bd5553c9fcedab7f910 100644 (file)
@@ -149,7 +149,15 @@ int dst_discard(struct sk_buff *skb)
 }
 EXPORT_SYMBOL(dst_discard);
 
-const u32 dst_default_metrics[RTAX_MAX];
+const u32 dst_default_metrics[RTAX_MAX + 1] = {
+       /* This initializer is needed to force linker to place this variable
+        * into const section. Otherwise it might end into bss section.
+        * We really want to avoid false sharing on this variable, and catch
+        * any writes on it.
+        */
+       [RTAX_MAX] = 0xdeadbeef,
+};
+
 
 void *dst_alloc(struct dst_ops *ops, struct net_device *dev,
                int initial_ref, int initial_obsolete, unsigned short flags)
@@ -214,8 +222,8 @@ void __dst_free(struct dst_entry *dst)
        if (dst_garbage.timer_inc > DST_GC_INC) {
                dst_garbage.timer_inc = DST_GC_INC;
                dst_garbage.timer_expires = DST_GC_MIN;
-               cancel_delayed_work(&dst_gc_work);
-               schedule_delayed_work(&dst_gc_work, dst_garbage.timer_expires);
+               mod_delayed_work(system_wq, &dst_gc_work,
+                                dst_garbage.timer_expires);
        }
        spin_unlock_bh(&dst_garbage.lock);
 }
index b4c90e42b4434455c8205f4483991326a85eedb6..346b1eb83a1f0336ed1e9dcf4f5905b733022dff 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/workqueue.h>
 #include <linux/slab.h>
 #include <linux/export.h>
+#include <linux/if_vlan.h>
 #include <net/tcp.h>
 #include <net/udp.h>
 #include <asm/unaligned.h>
@@ -54,7 +55,7 @@ static atomic_t trapped;
         MAX_UDP_CHUNK)
 
 static void zap_completion_queue(void);
-static void arp_reply(struct sk_buff *skb);
+static void netpoll_arp_reply(struct sk_buff *skb, struct netpoll_info *npinfo);
 
 static unsigned int carrier_timeout = 4;
 module_param(carrier_timeout, uint, 0644);
@@ -167,15 +168,24 @@ static void poll_napi(struct net_device *dev)
        struct napi_struct *napi;
        int budget = 16;
 
+       WARN_ON_ONCE(!irqs_disabled());
+
        list_for_each_entry(napi, &dev->napi_list, dev_list) {
+               local_irq_enable();
                if (napi->poll_owner != smp_processor_id() &&
                    spin_trylock(&napi->poll_lock)) {
-                       budget = poll_one_napi(dev->npinfo, napi, budget);
+                       rcu_read_lock_bh();
+                       budget = poll_one_napi(rcu_dereference_bh(dev->npinfo),
+                                              napi, budget);
+                       rcu_read_unlock_bh();
                        spin_unlock(&napi->poll_lock);
 
-                       if (!budget)
+                       if (!budget) {
+                               local_irq_disable();
                                break;
+                       }
                }
+               local_irq_disable();
        }
 }
 
@@ -185,13 +195,14 @@ static void service_arp_queue(struct netpoll_info *npi)
                struct sk_buff *skb;
 
                while ((skb = skb_dequeue(&npi->arp_tx)))
-                       arp_reply(skb);
+                       netpoll_arp_reply(skb, npi);
        }
 }
 
 static void netpoll_poll_dev(struct net_device *dev)
 {
        const struct net_device_ops *ops;
+       struct netpoll_info *ni = rcu_dereference_bh(dev->npinfo);
 
        if (!dev || !netif_running(dev))
                return;
@@ -206,17 +217,18 @@ static void netpoll_poll_dev(struct net_device *dev)
        poll_napi(dev);
 
        if (dev->flags & IFF_SLAVE) {
-               if (dev->npinfo) {
+               if (ni) {
                        struct net_device *bond_dev = dev->master;
                        struct sk_buff *skb;
-                       while ((skb = skb_dequeue(&dev->npinfo->arp_tx))) {
+                       struct netpoll_info *bond_ni = rcu_dereference_bh(bond_dev->npinfo);
+                       while ((skb = skb_dequeue(&ni->arp_tx))) {
                                skb->dev = bond_dev;
-                               skb_queue_tail(&bond_dev->npinfo->arp_tx, skb);
+                               skb_queue_tail(&bond_ni->arp_tx, skb);
                        }
                }
        }
 
-       service_arp_queue(dev->npinfo);
+       service_arp_queue(ni);
 
        zap_completion_queue();
 }
@@ -302,6 +314,7 @@ static int netpoll_owner_active(struct net_device *dev)
        return 0;
 }
 
+/* call with IRQ disabled */
 void netpoll_send_skb_on_dev(struct netpoll *np, struct sk_buff *skb,
                             struct net_device *dev)
 {
@@ -309,8 +322,11 @@ void netpoll_send_skb_on_dev(struct netpoll *np, struct sk_buff *skb,
        unsigned long tries;
        const struct net_device_ops *ops = dev->netdev_ops;
        /* It is up to the caller to keep npinfo alive. */
-       struct netpoll_info *npinfo = np->dev->npinfo;
+       struct netpoll_info *npinfo;
+
+       WARN_ON_ONCE(!irqs_disabled());
 
+       npinfo = rcu_dereference_bh(np->dev->npinfo);
        if (!npinfo || !netif_running(dev) || !netif_device_present(dev)) {
                __kfree_skb(skb);
                return;
@@ -319,16 +335,22 @@ void netpoll_send_skb_on_dev(struct netpoll *np, struct sk_buff *skb,
        /* don't get messages out of order, and no recursion */
        if (skb_queue_len(&npinfo->txq) == 0 && !netpoll_owner_active(dev)) {
                struct netdev_queue *txq;
-               unsigned long flags;
 
                txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb));
 
-               local_irq_save(flags);
                /* try until next clock tick */
                for (tries = jiffies_to_usecs(1)/USEC_PER_POLL;
                     tries > 0; --tries) {
                        if (__netif_tx_trylock(txq)) {
                                if (!netif_xmit_stopped(txq)) {
+                                       if (vlan_tx_tag_present(skb) &&
+                                           !(netif_skb_features(skb) & NETIF_F_HW_VLAN_TX)) {
+                                               skb = __vlan_put_tag(skb, vlan_tx_tag_get(skb));
+                                               if (unlikely(!skb))
+                                                       break;
+                                               skb->vlan_tci = 0;
+                                       }
+
                                        status = ops->ndo_start_xmit(skb, dev);
                                        if (status == NETDEV_TX_OK)
                                                txq_trans_update(txq);
@@ -347,10 +369,9 @@ void netpoll_send_skb_on_dev(struct netpoll *np, struct sk_buff *skb,
                }
 
                WARN_ONCE(!irqs_disabled(),
-                       "netpoll_send_skb(): %s enabled interrupts in poll (%pF)\n",
+                       "netpoll_send_skb_on_dev(): %s enabled interrupts in poll (%pF)\n",
                        dev->name, ops->ndo_start_xmit);
 
-               local_irq_restore(flags);
        }
 
        if (status != NETDEV_TX_OK) {
@@ -423,9 +444,8 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
 }
 EXPORT_SYMBOL(netpoll_send_udp);
 
-static void arp_reply(struct sk_buff *skb)
+static void netpoll_arp_reply(struct sk_buff *skb, struct netpoll_info *npinfo)
 {
-       struct netpoll_info *npinfo = skb->dev->npinfo;
        struct arphdr *arp;
        unsigned char *arp_ptr;
        int size, type = ARPOP_REPLY, ptype = ETH_P_ARP;
@@ -543,13 +563,12 @@ static void arp_reply(struct sk_buff *skb)
        spin_unlock_irqrestore(&npinfo->rx_lock, flags);
 }
 
-int __netpoll_rx(struct sk_buff *skb)
+int __netpoll_rx(struct sk_buff *skb, struct netpoll_info *npinfo)
 {
        int proto, len, ulen;
        int hits = 0;
        const struct iphdr *iph;
        struct udphdr *uh;
-       struct netpoll_info *npinfo = skb->dev->npinfo;
        struct netpoll *np, *tmp;
 
        if (list_empty(&npinfo->rx_np))
@@ -565,6 +584,12 @@ int __netpoll_rx(struct sk_buff *skb)
                return 1;
        }
 
+       if (skb->protocol == cpu_to_be16(ETH_P_8021Q)) {
+               skb = vlan_untag(skb);
+               if (unlikely(!skb))
+                       goto out;
+       }
+
        proto = ntohs(eth_hdr(skb)->h_proto);
        if (proto != ETH_P_IP)
                goto out;
@@ -715,7 +740,7 @@ int netpoll_parse_options(struct netpoll *np, char *opt)
 }
 EXPORT_SYMBOL(netpoll_parse_options);
 
-int __netpoll_setup(struct netpoll *np, struct net_device *ndev)
+int __netpoll_setup(struct netpoll *np, struct net_device *ndev, gfp_t gfp)
 {
        struct netpoll_info *npinfo;
        const struct net_device_ops *ops;
@@ -734,7 +759,7 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev)
        }
 
        if (!ndev->npinfo) {
-               npinfo = kmalloc(sizeof(*npinfo), GFP_KERNEL);
+               npinfo = kmalloc(sizeof(*npinfo), gfp);
                if (!npinfo) {
                        err = -ENOMEM;
                        goto out;
@@ -752,7 +777,7 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev)
 
                ops = np->dev->netdev_ops;
                if (ops->ndo_netpoll_setup) {
-                       err = ops->ndo_netpoll_setup(ndev, npinfo);
+                       err = ops->ndo_netpoll_setup(ndev, npinfo, gfp);
                        if (err)
                                goto free_npinfo;
                }
@@ -857,7 +882,7 @@ int netpoll_setup(struct netpoll *np)
        refill_skbs();
 
        rtnl_lock();
-       err = __netpoll_setup(np, ndev);
+       err = __netpoll_setup(np, ndev, GFP_KERNEL);
        rtnl_unlock();
 
        if (err)
@@ -878,6 +903,24 @@ static int __init netpoll_init(void)
 }
 core_initcall(netpoll_init);
 
+static void rcu_cleanup_netpoll_info(struct rcu_head *rcu_head)
+{
+       struct netpoll_info *npinfo =
+                       container_of(rcu_head, struct netpoll_info, rcu);
+
+       skb_queue_purge(&npinfo->arp_tx);
+       skb_queue_purge(&npinfo->txq);
+
+       /* we can't call cancel_delayed_work_sync here, as we are in softirq */
+       cancel_delayed_work(&npinfo->tx_work);
+
+       /* clean after last, unfinished work */
+       __skb_queue_purge(&npinfo->txq);
+       /* now cancel it again */
+       cancel_delayed_work(&npinfo->tx_work);
+       kfree(npinfo);
+}
+
 void __netpoll_cleanup(struct netpoll *np)
 {
        struct netpoll_info *npinfo;
@@ -903,20 +946,24 @@ void __netpoll_cleanup(struct netpoll *np)
                        ops->ndo_netpoll_cleanup(np->dev);
 
                RCU_INIT_POINTER(np->dev->npinfo, NULL);
+               call_rcu_bh(&npinfo->rcu, rcu_cleanup_netpoll_info);
+       }
+}
+EXPORT_SYMBOL_GPL(__netpoll_cleanup);
 
-               /* avoid racing with NAPI reading npinfo */
-               synchronize_rcu_bh();
+static void rcu_cleanup_netpoll(struct rcu_head *rcu_head)
+{
+       struct netpoll *np = container_of(rcu_head, struct netpoll, rcu);
 
-               skb_queue_purge(&npinfo->arp_tx);
-               skb_queue_purge(&npinfo->txq);
-               cancel_delayed_work_sync(&npinfo->tx_work);
+       __netpoll_cleanup(np);
+       kfree(np);
+}
 
-               /* clean after last, unfinished work */
-               __skb_queue_purge(&npinfo->txq);
-               kfree(npinfo);
-       }
+void __netpoll_free_rcu(struct netpoll *np)
+{
+       call_rcu_bh(&np->rcu, rcu_cleanup_netpoll);
 }
-EXPORT_SYMBOL_GPL(__netpoll_cleanup);
+EXPORT_SYMBOL_GPL(__netpoll_free_rcu);
 
 void netpoll_cleanup(struct netpoll *np)
 {
index ed0c0431fcd8ff225842ec8de8537f54f0a3294f..c75e3f9d060f8e3d086b747255ab65c8104f7dde 100644 (file)
@@ -101,12 +101,10 @@ static int write_update_netdev_table(struct net_device *dev)
        u32 max_len;
        struct netprio_map *map;
 
-       rtnl_lock();
        max_len = atomic_read(&max_prioidx) + 1;
        map = rtnl_dereference(dev->priomap);
        if (!map || map->priomap_len < max_len)
                ret = extend_netdev_table(dev, max_len);
-       rtnl_unlock();
 
        return ret;
 }
@@ -256,17 +254,17 @@ static int write_priomap(struct cgroup *cgrp, struct cftype *cft,
        if (!dev)
                goto out_free_devname;
 
+       rtnl_lock();
        ret = write_update_netdev_table(dev);
        if (ret < 0)
                goto out_put_dev;
 
-       rcu_read_lock();
-       map = rcu_dereference(dev->priomap);
+       map = rtnl_dereference(dev->priomap);
        if (map)
                map->priomap[prioidx] = priority;
-       rcu_read_unlock();
 
 out_put_dev:
+       rtnl_unlock();
        dev_put(dev);
 
 out_free_devname:
@@ -277,12 +275,6 @@ out_free_devname:
 void net_prio_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
 {
        struct task_struct *p;
-       char *tmp = kzalloc(sizeof(char) * PATH_MAX, GFP_KERNEL);
-
-       if (!tmp) {
-               pr_warn("Unable to attach cgrp due to alloc failure!\n");
-               return;
-       }
 
        cgroup_taskset_for_each(p, cgrp, tset) {
                unsigned int fd;
@@ -296,32 +288,24 @@ void net_prio_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
                        continue;
                }
 
-               rcu_read_lock();
+               spin_lock(&files->file_lock);
                fdt = files_fdtable(files);
                for (fd = 0; fd < fdt->max_fds; fd++) {
-                       char *path;
                        struct file *file;
                        struct socket *sock;
-                       unsigned long s;
-                       int rv, err = 0;
+                       int err;
 
                        file = fcheck_files(files, fd);
                        if (!file)
                                continue;
 
-                       path = d_path(&file->f_path, tmp, PAGE_SIZE);
-                       rv = sscanf(path, "socket:[%lu]", &s);
-                       if (rv <= 0)
-                               continue;
-
                        sock = sock_from_file(file, &err);
-                       if (!err)
+                       if (sock)
                                sock_update_netprioidx(sock->sk, p);
                }
-               rcu_read_unlock();
+               spin_unlock(&files->file_lock);
                task_unlock(p);
        }
-       kfree(tmp);
 }
 
 static struct cftype ss_files[] = {
index 2c5a0a06c4ce3053a4a6c6afa3437f3a47f2d08c..34d975b0f2770e0792dbcf879fdecf0742c0728a 100644 (file)
@@ -618,7 +618,7 @@ int rtnl_put_cacheinfo(struct sk_buff *skb, struct dst_entry *dst, u32 id,
                       long expires, u32 error)
 {
        struct rta_cacheinfo ci = {
-               .rta_lastuse = jiffies_to_clock_t(jiffies - dst->lastuse),
+               .rta_lastuse = jiffies_delta_to_clock_t(jiffies - dst->lastuse),
                .rta_used = dst->__use,
                .rta_clntref = atomic_read(&(dst->__refcnt)),
                .rta_error = error,
@@ -1812,8 +1812,6 @@ replay:
                        return -ENODEV;
                }
 
-               if (ifm->ifi_index)
-                       return -EOPNOTSUPP;
                if (tb[IFLA_MAP] || tb[IFLA_MASTER] || tb[IFLA_PROTINFO])
                        return -EOPNOTSUPP;
 
@@ -1839,10 +1837,14 @@ replay:
                        return PTR_ERR(dest_net);
 
                dev = rtnl_create_link(net, dest_net, ifname, ops, tb);
-
-               if (IS_ERR(dev))
+               if (IS_ERR(dev)) {
                        err = PTR_ERR(dev);
-               else if (ops->newlink)
+                       goto out;
+               }
+
+               dev->ifindex = ifm->ifi_index;
+
+               if (ops->newlink)
                        err = ops->newlink(net, dev, tb, data);
                else
                        err = register_netdevice(dev);
index 8f6ccfd68ef4fb6625652f0b34f7f3fdb4b4a91e..040cebeed45b810cf9dd7d85c6ac2cbade98ee77 100644 (file)
@@ -265,6 +265,7 @@ void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
        for (i=0, cmfptr=(__force int __user *)CMSG_DATA(cm); i<fdmax;
             i++, cmfptr++)
        {
+               struct socket *sock;
                int new_fd;
                err = security_file_receive(fp[i]);
                if (err)
@@ -281,6 +282,9 @@ void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
                }
                /* Bump the usage count and install the file. */
                get_file(fp[i]);
+               sock = sock_from_file(fp[i], &err);
+               if (sock)
+                       sock_update_netprioidx(sock->sk, current);
                fd_install(new_fd, fp[i]);
        }
 
index 6b654b3ddfda2a9a03f77bc1d2a5476a2c25e9d4..8f67ced8d6a808689255435dd412df132138af65 100644 (file)
@@ -1458,6 +1458,7 @@ void sk_setup_caps(struct sock *sk, struct dst_entry *dst)
                } else {
                        sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM;
                        sk->sk_gso_max_size = dst->dev->gso_max_size;
+                       sk->sk_gso_max_segs = dst->dev->gso_max_segs;
                }
        }
 }
index 75c3582a7678ab418771b2a5ad5fd3c069a9e512..fb85d371a8dec875a01205b22ef6ddef5e99d511 100644 (file)
@@ -246,7 +246,7 @@ static inline int ccid_hc_rx_getsockopt(struct ccid *ccid, struct sock *sk,
                                        u32 __user *optval, int __user *optlen)
 {
        int rc = -ENOPROTOOPT;
-       if (ccid->ccid_ops->ccid_hc_rx_getsockopt != NULL)
+       if (ccid != NULL && ccid->ccid_ops->ccid_hc_rx_getsockopt != NULL)
                rc = ccid->ccid_ops->ccid_hc_rx_getsockopt(sk, optname, len,
                                                 optval, optlen);
        return rc;
@@ -257,7 +257,7 @@ static inline int ccid_hc_tx_getsockopt(struct ccid *ccid, struct sock *sk,
                                        u32 __user *optval, int __user *optlen)
 {
        int rc = -ENOPROTOOPT;
-       if (ccid->ccid_ops->ccid_hc_tx_getsockopt != NULL)
+       if (ccid != NULL && ccid->ccid_ops->ccid_hc_tx_getsockopt != NULL)
                rc = ccid->ccid_ops->ccid_hc_tx_getsockopt(sk, optname, len,
                                                 optval, optlen);
        return rc;
index d65e98798ecaff29110a2ff303d500482162df66..119c04317d48eed4abcb2bbf6071062c8d9784fd 100644 (file)
@@ -535,6 +535,7 @@ static int ccid3_hc_tx_getsockopt(struct sock *sk, const int optname, int len,
        case DCCP_SOCKOPT_CCID_TX_INFO:
                if (len < sizeof(tfrc))
                        return -EINVAL;
+               memset(&tfrc, 0, sizeof(tfrc));
                tfrc.tfrctx_x      = hc->tx_x;
                tfrc.tfrctx_x_recv = hc->tx_x_recv;
                tfrc.tfrctx_x_calc = hc->tx_x_calc;
index 85a3604c87c8d2cac6cac4d7049d9ba75877bf66..c855e8d0738f75a08a1d44a35a02ff870132510f 100644 (file)
@@ -961,7 +961,7 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowidn *o
                .saddr = oldflp->saddr,
                .flowidn_scope = RT_SCOPE_UNIVERSE,
                .flowidn_mark = oldflp->flowidn_mark,
-               .flowidn_iif = init_net.loopback_dev->ifindex,
+               .flowidn_iif = LOOPBACK_IFINDEX,
                .flowidn_oif = oldflp->flowidn_oif,
        };
        struct dn_route *rt = NULL;
@@ -979,7 +979,7 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowidn *o
                       "dn_route_output_slow: dst=%04x src=%04x mark=%d"
                       " iif=%d oif=%d\n", le16_to_cpu(oldflp->daddr),
                       le16_to_cpu(oldflp->saddr),
-                      oldflp->flowidn_mark, init_net.loopback_dev->ifindex,
+                      oldflp->flowidn_mark, LOOPBACK_IFINDEX,
                       oldflp->flowidn_oif);
 
        /* If we have an output interface, verify its a DECnet device */
@@ -1042,7 +1042,7 @@ source_ok:
                        if (!fld.daddr)
                                goto out;
                }
-               fld.flowidn_oif = init_net.loopback_dev->ifindex;
+               fld.flowidn_oif = LOOPBACK_IFINDEX;
                res.type = RTN_LOCAL;
                goto make_route;
        }
index fe4582ca969a4ff85c862f8fd96d3b6ec3d03a4d..6681ccf5c3eeae5bbbca030cf2d09cf826ad335c 100644 (file)
@@ -1364,7 +1364,7 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head,
        if (*(u8 *)iph != 0x45)
                goto out_unlock;
 
-       if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))
+       if (unlikely(ip_fast_csum((u8 *)iph, 5)))
                goto out_unlock;
 
        id = ntohl(*(__be32 *)&iph->id);
@@ -1380,7 +1380,6 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head,
                iph2 = ip_hdr(p);
 
                if ((iph->protocol ^ iph2->protocol) |
-                   (iph->tos ^ iph2->tos) |
                    ((__force u32)iph->saddr ^ (__force u32)iph2->saddr) |
                    ((__force u32)iph->daddr ^ (__force u32)iph2->daddr)) {
                        NAPI_GRO_CB(p)->same_flow = 0;
@@ -1390,6 +1389,7 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head,
                /* All fields must match except length and checksum. */
                NAPI_GRO_CB(p)->flush |=
                        (iph->ttl ^ iph2->ttl) |
+                       (iph->tos ^ iph2->tos) |
                        ((u16)(ntohs(iph2->id) + NAPI_GRO_CB(p)->count) ^ id);
 
                NAPI_GRO_CB(p)->flush |= flush;
index 44bf82e3aef7d6d4b5afc39a357b7da6d85a44e7..adf273f8ad2eb28a658321c68967bb2e6ccf25a0 100644 (file)
@@ -94,25 +94,22 @@ static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = {
        [IFA_LABEL]             = { .type = NLA_STRING, .len = IFNAMSIZ - 1 },
 };
 
-/* inet_addr_hash's shifting is dependent upon this IN4_ADDR_HSIZE
- * value.  So if you change this define, make appropriate changes to
- * inet_addr_hash as well.
- */
-#define IN4_ADDR_HSIZE 256
+#define IN4_ADDR_HSIZE_SHIFT   8
+#define IN4_ADDR_HSIZE         (1U << IN4_ADDR_HSIZE_SHIFT)
+
 static struct hlist_head inet_addr_lst[IN4_ADDR_HSIZE];
 static DEFINE_SPINLOCK(inet_addr_hash_lock);
 
-static inline unsigned int inet_addr_hash(struct net *net, __be32 addr)
+static u32 inet_addr_hash(struct net *net, __be32 addr)
 {
-       u32 val = (__force u32) addr ^ hash_ptr(net, 8);
+       u32 val = (__force u32) addr ^ net_hash_mix(net);
 
-       return ((val ^ (val >> 8) ^ (val >> 16) ^ (val >> 24)) &
-               (IN4_ADDR_HSIZE - 1));
+       return hash_32(val, IN4_ADDR_HSIZE_SHIFT);
 }
 
 static void inet_hash_insert(struct net *net, struct in_ifaddr *ifa)
 {
-       unsigned int hash = inet_addr_hash(net, ifa->ifa_local);
+       u32 hash = inet_addr_hash(net, ifa->ifa_local);
 
        spin_lock(&inet_addr_hash_lock);
        hlist_add_head_rcu(&ifa->hash, &inet_addr_lst[hash]);
@@ -136,18 +133,18 @@ static void inet_hash_remove(struct in_ifaddr *ifa)
  */
 struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref)
 {
-       unsigned int hash = inet_addr_hash(net, addr);
+       u32 hash = inet_addr_hash(net, addr);
        struct net_device *result = NULL;
        struct in_ifaddr *ifa;
        struct hlist_node *node;
 
        rcu_read_lock();
        hlist_for_each_entry_rcu(ifa, node, &inet_addr_lst[hash], hash) {
-               struct net_device *dev = ifa->ifa_dev->dev;
-
-               if (!net_eq(dev_net(dev), net))
-                       continue;
                if (ifa->ifa_local == addr) {
+                       struct net_device *dev = ifa->ifa_dev->dev;
+
+                       if (!net_eq(dev_net(dev), net))
+                               continue;
                        result = dev;
                        break;
                }
@@ -182,10 +179,10 @@ static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
 static void devinet_sysctl_register(struct in_device *idev);
 static void devinet_sysctl_unregister(struct in_device *idev);
 #else
-static inline void devinet_sysctl_register(struct in_device *idev)
+static void devinet_sysctl_register(struct in_device *idev)
 {
 }
-static inline void devinet_sysctl_unregister(struct in_device *idev)
+static void devinet_sysctl_unregister(struct in_device *idev)
 {
 }
 #endif
@@ -205,7 +202,7 @@ static void inet_rcu_free_ifa(struct rcu_head *head)
        kfree(ifa);
 }
 
-static inline void inet_free_ifa(struct in_ifaddr *ifa)
+static void inet_free_ifa(struct in_ifaddr *ifa)
 {
        call_rcu(&ifa->rcu_head, inet_rcu_free_ifa);
 }
@@ -659,7 +656,7 @@ static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg
  *     Determine a default network mask, based on the IP address.
  */
 
-static inline int inet_abc_len(__be32 addr)
+static int inet_abc_len(__be32 addr)
 {
        int rc = -1;    /* Something else, probably a multicast. */
 
@@ -1124,7 +1121,7 @@ skip:
        }
 }
 
-static inline bool inetdev_valid_mtu(unsigned int mtu)
+static bool inetdev_valid_mtu(unsigned int mtu)
 {
        return mtu >= 68;
 }
@@ -1239,7 +1236,7 @@ static struct notifier_block ip_netdev_notifier = {
        .notifier_call = inetdev_event,
 };
 
-static inline size_t inet_nlmsg_size(void)
+static size_t inet_nlmsg_size(void)
 {
        return NLMSG_ALIGN(sizeof(struct ifaddrmsg))
               + nla_total_size(4) /* IFA_ADDRESS */
index c43ae3fba7921e590859cea407ba9b9e030b16be..7f073a38c87d88a89f2c11d3cd56b67a66d194b2 100644 (file)
@@ -218,7 +218,7 @@ __be32 fib_compute_spec_dst(struct sk_buff *skb)
        scope = RT_SCOPE_UNIVERSE;
        if (!ipv4_is_zeronet(ip_hdr(skb)->saddr)) {
                fl4.flowi4_oif = 0;
-               fl4.flowi4_iif = net->loopback_dev->ifindex;
+               fl4.flowi4_iif = LOOPBACK_IFINDEX;
                fl4.daddr = ip_hdr(skb)->saddr;
                fl4.saddr = 0;
                fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos);
index f0cdb30921c0bdb5b1639e15d05908dfde6586f9..3c820dae235e4e55fca8a2e9c0598ac3be5b6673 100644 (file)
@@ -367,7 +367,7 @@ static void __leaf_free_rcu(struct rcu_head *head)
 
 static inline void free_leaf(struct leaf *l)
 {
-       call_rcu_bh(&l->rcu, __leaf_free_rcu);
+       call_rcu(&l->rcu, __leaf_free_rcu);
 }
 
 static inline void free_leaf_info(struct leaf_info *leaf)
@@ -1550,7 +1550,8 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp,
                 * state.directly.
                 */
                if (pref_mismatch) {
-                       int mp = KEYLENGTH - fls(pref_mismatch);
+                       /* fls(x) = __fls(x) + 1 */
+                       int mp = KEYLENGTH - __fls(pref_mismatch) - 1;
 
                        if (tkey_extract_bits(cn->key, mp, cn->pos - mp) != 0)
                                goto backtrace;
@@ -1655,7 +1656,12 @@ int fib_table_delete(struct fib_table *tb, struct fib_config *cfg)
        if (!l)
                return -ESRCH;
 
-       fa_head = get_fa_head(l, plen);
+       li = find_leaf_info(l, plen);
+
+       if (!li)
+               return -ESRCH;
+
+       fa_head = &li->falh;
        fa = fib_find_alias(fa_head, tos, 0);
 
        if (!fa)
@@ -1691,9 +1697,6 @@ int fib_table_delete(struct fib_table *tb, struct fib_config *cfg)
        rtmsg_fib(RTM_DELROUTE, htonl(key), fa, plen, tb->tb_id,
                  &cfg->fc_nlinfo, 0);
 
-       l = fib_find_node(t, key);
-       li = find_leaf_info(l, plen);
-
        list_del_rcu(&fa->fa_list);
 
        if (!plen)
index 6699f23e6f55b0012cc50b74030f415362efbed1..0b5580c69f2d46b5d2c49bcd0bcbb220439544ff 100644 (file)
@@ -2435,6 +2435,8 @@ static int igmp_mc_seq_show(struct seq_file *seq, void *v)
                struct ip_mc_list *im = (struct ip_mc_list *)v;
                struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq);
                char   *querier;
+               long delta;
+
 #ifdef CONFIG_IP_MULTICAST
                querier = IGMP_V1_SEEN(state->in_dev) ? "V1" :
                          IGMP_V2_SEEN(state->in_dev) ? "V2" :
@@ -2448,11 +2450,12 @@ static int igmp_mc_seq_show(struct seq_file *seq, void *v)
                                   state->dev->ifindex, state->dev->name, state->in_dev->mc_count, querier);
                }
 
+               delta = im->timer.expires - jiffies;
                seq_printf(seq,
                           "\t\t\t\t%08X %5d %d:%08lX\t\t%d\n",
                           im->multiaddr, im->users,
-                          im->tm_running, im->tm_running ?
-                          jiffies_to_clock_t(im->timer.expires-jiffies) : 0,
+                          im->tm_running,
+                          im->tm_running ? jiffies_delta_to_clock_t(delta) : 0,
                           im->reporter);
        }
        return 0;
index ba39a52d18c1966209b02127ad7a4335479fcbdc..147ccc3e93db08de8ba0c6ab0cc255b639eafdbb 100644 (file)
@@ -197,7 +197,7 @@ static inline int ip_finish_output2(struct sk_buff *skb)
        neigh = __ipv4_neigh_lookup_noref(dev, nexthop);
        if (unlikely(!neigh))
                neigh = __neigh_create(&arp_tbl, &nexthop, dev, false);
-       if (neigh) {
+       if (!IS_ERR(neigh)) {
                int res = dst_neigh_output(dst, neigh, skb);
 
                rcu_read_unlock_bh();
@@ -1366,9 +1366,8 @@ out:
        return skb;
 }
 
-int ip_send_skb(struct sk_buff *skb)
+int ip_send_skb(struct net *net, struct sk_buff *skb)
 {
-       struct net *net = sock_net(skb->sk);
        int err;
 
        err = ip_local_out(skb);
@@ -1391,7 +1390,7 @@ int ip_push_pending_frames(struct sock *sk, struct flowi4 *fl4)
                return 0;
 
        /* Netfilter gets whole the not fragmented skb. */
-       return ip_send_skb(skb);
+       return ip_send_skb(sock_net(sk), skb);
 }
 
 /*
@@ -1536,6 +1535,7 @@ void ip_send_unicast_reply(struct net *net, struct sk_buff *skb, __be32 daddr,
                          arg->csumoffset) = csum_fold(csum_add(nskb->csum,
                                                                arg->csum));
                nskb->ip_summed = CHECKSUM_NONE;
+               skb_orphan(nskb);
                skb_set_queue_mapping(nskb, skb_get_queue_mapping(skb));
                ip_push_pending_frames(sk, &fl4);
        }
index 8eec8f4a05360d24897719495100ea100f0c69b2..3a57570c8ee5ecf8570cb9fb714664d2a262d211 100644 (file)
@@ -1798,7 +1798,7 @@ static struct mr_table *ipmr_rt_fib_lookup(struct net *net, struct sk_buff *skb)
                .flowi4_oif = (rt_is_output_route(rt) ?
                               skb->dev->ifindex : 0),
                .flowi4_iif = (rt_is_output_route(rt) ?
-                              net->loopback_dev->ifindex :
+                              LOOPBACK_IFINDEX :
                               skb->dev->ifindex),
                .flowi4_mark = skb->mark,
        };
index 31371be8174be1d8da1a50f11dd6c48409b29b74..c30130062cd6515f31d7497eaa6a403d2b1d629d 100644 (file)
@@ -85,7 +85,7 @@ static bool rpfilter_mt(const struct sk_buff *skb, struct xt_action_param *par)
                        return ipv4_is_local_multicast(iph->daddr) ^ invert;
                flow.flowi4_iif = 0;
        } else {
-               flow.flowi4_iif = dev_net(par->in)->loopback_dev->ifindex;
+               flow.flowi4_iif = LOOPBACK_IFINDEX;
        }
 
        flow.daddr = iph->saddr;
index c035251beb070bb7f4220324a90e0ffeee8e103c..50f6d3adb474490ed7a39285b59881431215510b 100644 (file)
@@ -70,7 +70,6 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
-#include <linux/bootmem.h>
 #include <linux/string.h>
 #include <linux/socket.h>
 #include <linux/sockios.h>
@@ -80,7 +79,6 @@
 #include <linux/netdevice.h>
 #include <linux/proc_fs.h>
 #include <linux/init.h>
-#include <linux/workqueue.h>
 #include <linux/skbuff.h>
 #include <linux/inetdevice.h>
 #include <linux/igmp.h>
 #include <linux/mroute.h>
 #include <linux/netfilter_ipv4.h>
 #include <linux/random.h>
-#include <linux/jhash.h>
 #include <linux/rcupdate.h>
 #include <linux/times.h>
 #include <linux/slab.h>
-#include <linux/prefetch.h>
 #include <net/dst.h>
 #include <net/net_namespace.h>
 #include <net/protocol.h>
@@ -1591,11 +1587,14 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
        if (ipv4_is_zeronet(daddr))
                goto martian_destination;
 
-       if (likely(!IN_DEV_ROUTE_LOCALNET(in_dev))) {
-               if (ipv4_is_loopback(daddr))
+       /* Following code try to avoid calling IN_DEV_NET_ROUTE_LOCALNET(),
+        * and call it once if daddr or/and saddr are loopback addresses
+        */
+       if (ipv4_is_loopback(daddr)) {
+               if (!IN_DEV_NET_ROUTE_LOCALNET(in_dev, net))
                        goto martian_destination;
-
-               if (ipv4_is_loopback(saddr))
+       } else if (ipv4_is_loopback(saddr)) {
+               if (!IN_DEV_NET_ROUTE_LOCALNET(in_dev, net))
                        goto martian_source;
        }
 
@@ -1620,7 +1619,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
 
        if (res.type == RTN_LOCAL) {
                err = fib_validate_source(skb, saddr, daddr, tos,
-                                         net->loopback_dev->ifindex,
+                                         LOOPBACK_IFINDEX,
                                          dev, in_dev, &itag);
                if (err < 0)
                        goto martian_source_keep_err;
@@ -1896,7 +1895,7 @@ struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *fl4)
 
        orig_oif = fl4->flowi4_oif;
 
-       fl4->flowi4_iif = net->loopback_dev->ifindex;
+       fl4->flowi4_iif = LOOPBACK_IFINDEX;
        fl4->flowi4_tos = tos & IPTOS_RT_MASK;
        fl4->flowi4_scope = ((tos & RTO_ONLINK) ?
                         RT_SCOPE_LINK : RT_SCOPE_UNIVERSE);
@@ -1985,7 +1984,7 @@ struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *fl4)
                if (!fl4->daddr)
                        fl4->daddr = fl4->saddr = htonl(INADDR_LOOPBACK);
                dev_out = net->loopback_dev;
-               fl4->flowi4_oif = net->loopback_dev->ifindex;
+               fl4->flowi4_oif = LOOPBACK_IFINDEX;
                res.type = RTN_LOCAL;
                flags |= RTCF_LOCAL;
                goto make_route;
@@ -2032,7 +2031,6 @@ struct rtable *__ip_route_output_key(struct net *net, struct flowi4 *fl4)
                }
                dev_out = net->loopback_dev;
                fl4->flowi4_oif = dev_out->ifindex;
-               res.fi = NULL;
                flags |= RTCF_LOCAL;
                goto make_route;
        }
index e7e6eeae49c0123d392fa16c7687c333b30b79b8..2109ff4a1dafd489fbe0e2240075432df4517374 100644 (file)
@@ -811,7 +811,9 @@ static unsigned int tcp_xmit_size_goal(struct sock *sk, u32 mss_now,
                           old_size_goal + mss_now > xmit_size_goal)) {
                        xmit_size_goal = old_size_goal;
                } else {
-                       tp->xmit_size_goal_segs = xmit_size_goal / mss_now;
+                       tp->xmit_size_goal_segs =
+                               min_t(u16, xmit_size_goal / mss_now,
+                                     sk->sk_gso_max_segs);
                        xmit_size_goal = tp->xmit_size_goal_segs * mss_now;
                }
        }
index 4d4db16e336ea63c2b581079e5295a4a74924aab..1432cdb0644c2b16f893de842bcd3b9fdd3c5538 100644 (file)
@@ -291,7 +291,8 @@ bool tcp_is_cwnd_limited(const struct sock *sk, u32 in_flight)
        left = tp->snd_cwnd - in_flight;
        if (sk_can_gso(sk) &&
            left * sysctl_tcp_tso_win_divisor < tp->snd_cwnd &&
-           left * tp->mss_cache < sk->sk_gso_max_size)
+           left * tp->mss_cache < sk->sk_gso_max_size &&
+           left < sk->sk_gso_max_segs)
                return true;
        return left <= tcp_max_tso_deferred_mss(tp);
 }
index 2fd2bc9e3c644d650282ea8c66a41fab9683167f..bcfccc5cb8d0ec20af97902d0341fac4b559c388 100644 (file)
@@ -237,7 +237,11 @@ static inline void TCP_ECN_check_ce(struct tcp_sock *tp, const struct sk_buff *s
                        tcp_enter_quickack_mode((struct sock *)tp);
                break;
        case INET_ECN_CE:
-               tp->ecn_flags |= TCP_ECN_DEMAND_CWR;
+               if (!(tp->ecn_flags & TCP_ECN_DEMAND_CWR)) {
+                       /* Better not delay acks, sender can have a very low cwnd */
+                       tcp_enter_quickack_mode((struct sock *)tp);
+                       tp->ecn_flags |= TCP_ECN_DEMAND_CWR;
+               }
                /* fallinto */
        default:
                tp->ecn_flags |= TCP_ECN_SEEN;
@@ -5392,6 +5396,8 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
 {
        struct tcp_sock *tp = tcp_sk(sk);
 
+       if (unlikely(sk->sk_rx_dst == NULL))
+               inet_csk(sk)->icsk_af_ops->sk_rx_dst_set(sk, skb);
        /*
         *      Header prediction.
         *      The code loosely follows the one in the famous
@@ -5605,7 +5611,7 @@ void tcp_finish_connect(struct sock *sk, struct sk_buff *skb)
        tcp_set_state(sk, TCP_ESTABLISHED);
 
        if (skb != NULL) {
-               inet_sk_rx_dst_set(sk, skb);
+               icsk->icsk_af_ops->sk_rx_dst_set(sk, skb);
                security_inet_conn_established(sk, skb);
        }
 
@@ -5740,7 +5746,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
 
                TCP_ECN_rcv_synack(tp, th);
 
-               tp->snd_wl1 = TCP_SKB_CB(skb)->seq;
+               tcp_init_wl(tp, TCP_SKB_CB(skb)->seq);
                tcp_ack(sk, skb, FLAG_SLOWPATH);
 
                /* Ok.. it's good. Set up sequence numbers and
@@ -5753,7 +5759,6 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
                 * never scaled.
                 */
                tp->snd_wnd = ntohs(th->window);
-               tcp_init_wl(tp, TCP_SKB_CB(skb)->seq);
 
                if (!tp->rx_opt.wscale_ok) {
                        tp->rx_opt.snd_wscale = tp->rx_opt.rcv_wscale = 0;
index 42b2a6a73092a9a75bd96239af003269575328f5..09356b3644d1f3a6c9648f942f6fa177be8ea466 100644 (file)
@@ -1627,9 +1627,6 @@ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
                                sk->sk_rx_dst = NULL;
                        }
                }
-               if (unlikely(sk->sk_rx_dst == NULL))
-                       inet_sk_rx_dst_set(sk, skb);
-
                if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len)) {
                        rsk = sk;
                        goto reset;
@@ -1872,10 +1869,21 @@ static struct timewait_sock_ops tcp_timewait_sock_ops = {
        .twsk_destructor= tcp_twsk_destructor,
 };
 
+void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
+{
+       struct dst_entry *dst = skb_dst(skb);
+
+       dst_hold(dst);
+       sk->sk_rx_dst = dst;
+       inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
+}
+EXPORT_SYMBOL(inet_sk_rx_dst_set);
+
 const struct inet_connection_sock_af_ops ipv4_specific = {
        .queue_xmit        = ip_queue_xmit,
        .send_check        = tcp_v4_send_check,
        .rebuild_header    = inet_sk_rebuild_header,
+       .sk_rx_dst_set     = inet_sk_rx_dst_set,
        .conn_request      = tcp_v4_conn_request,
        .syn_recv_sock     = tcp_v4_syn_recv_sock,
        .net_header_len    = sizeof(struct iphdr),
@@ -2385,7 +2393,7 @@ static void get_openreq4(const struct sock *sk, const struct request_sock *req,
                         struct seq_file *f, int i, int uid, int *len)
 {
        const struct inet_request_sock *ireq = inet_rsk(req);
-       int ttd = req->expires - jiffies;
+       long delta = req->expires - jiffies;
 
        seq_printf(f, "%4d: %08X:%04X %08X:%04X"
                " %02X %08X:%08X %02X:%08lX %08X %5d %8d %u %d %pK%n",
@@ -2397,7 +2405,7 @@ static void get_openreq4(const struct sock *sk, const struct request_sock *req,
                TCP_SYN_RECV,
                0, 0, /* could print option size, but that is af dependent. */
                1,    /* timers active (only the expire timer) */
-               jiffies_to_clock_t(ttd),
+               jiffies_delta_to_clock_t(delta),
                req->retrans,
                uid,
                0,  /* non standard timer */
@@ -2448,7 +2456,7 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i, int *len)
                tp->write_seq - tp->snd_una,
                rx_queue,
                timer_active,
-               jiffies_to_clock_t(timer_expires - jiffies),
+               jiffies_delta_to_clock_t(timer_expires - jiffies),
                icsk->icsk_retransmits,
                sock_i_uid(sk),
                icsk->icsk_probes_out,
@@ -2467,10 +2475,7 @@ static void get_timewait4_sock(const struct inet_timewait_sock *tw,
 {
        __be32 dest, src;
        __u16 destp, srcp;
-       int ttd = tw->tw_ttd - jiffies;
-
-       if (ttd < 0)
-               ttd = 0;
+       long delta = tw->tw_ttd - jiffies;
 
        dest  = tw->tw_daddr;
        src   = tw->tw_rcv_saddr;
@@ -2480,7 +2485,7 @@ static void get_timewait4_sock(const struct inet_timewait_sock *tw,
        seq_printf(f, "%4d: %08X:%04X %08X:%04X"
                " %02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK%n",
                i, src, srcp, dest, destp, tw->tw_substate, 0, 0,
-               3, jiffies_to_clock_t(ttd), 0, 0, 0, 0,
+               3, jiffies_delta_to_clock_t(delta), 0, 0, 0, 0,
                atomic_read(&tw->tw_refcnt), tw, len);
 }
 
index 2288a6399e1e4fee43beebdc2817d38bea140bfb..0abe67bb4d3a3adb0d9df820b1fe64b6ef9da591 100644 (file)
@@ -731,6 +731,18 @@ static int __net_init tcp_net_metrics_init(struct net *net)
 
 static void __net_exit tcp_net_metrics_exit(struct net *net)
 {
+       unsigned int i;
+
+       for (i = 0; i < (1U << net->ipv4.tcp_metrics_hash_log) ; i++) {
+               struct tcp_metrics_block *tm, *next;
+
+               tm = rcu_dereference_protected(net->ipv4.tcp_metrics_hash[i].chain, 1);
+               while (tm) {
+                       next = rcu_dereference_protected(tm->tcpm_next, 1);
+                       kfree(tm);
+                       tm = next;
+               }
+       }
        kfree(net->ipv4.tcp_metrics_hash);
 }
 
index 232a90c3ec8695dfa740fe141ba113074f99a289..d9c9dcef2de303592832867af979dcfb380b6132 100644 (file)
@@ -387,7 +387,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
                struct tcp_sock *oldtp = tcp_sk(sk);
                struct tcp_cookie_values *oldcvp = oldtp->cookie_values;
 
-               inet_sk_rx_dst_set(newsk, skb);
+               newicsk->icsk_af_ops->sk_rx_dst_set(newsk, skb);
 
                /* TCP Cookie Transactions require space for the cookie pair,
                 * as it differs for each connection.  There is no need to
index 3f1bcff0b10b5d2daa0307de4ff29f0ba6ddb5cc..20dfd892c86f7128c7408833e57cfbe4ee39be88 100644 (file)
@@ -940,7 +940,7 @@ void __init tcp_tasklet_init(void)
  * We cant xmit new skbs from this context, as we might already
  * hold qdisc lock.
  */
-void tcp_wfree(struct sk_buff *skb)
+static void tcp_wfree(struct sk_buff *skb)
 {
        struct sock *sk = skb->sk;
        struct tcp_sock *tp = tcp_sk(sk);
@@ -1522,21 +1522,21 @@ static void tcp_cwnd_validate(struct sock *sk)
  * when we would be allowed to send the split-due-to-Nagle skb fully.
  */
 static unsigned int tcp_mss_split_point(const struct sock *sk, const struct sk_buff *skb,
-                                       unsigned int mss_now, unsigned int cwnd)
+                                       unsigned int mss_now, unsigned int max_segs)
 {
        const struct tcp_sock *tp = tcp_sk(sk);
-       u32 needed, window, cwnd_len;
+       u32 needed, window, max_len;
 
        window = tcp_wnd_end(tp) - TCP_SKB_CB(skb)->seq;
-       cwnd_len = mss_now * cwnd;
+       max_len = mss_now * max_segs;
 
-       if (likely(cwnd_len <= window && skb != tcp_write_queue_tail(sk)))
-               return cwnd_len;
+       if (likely(max_len <= window && skb != tcp_write_queue_tail(sk)))
+               return max_len;
 
        needed = min(skb->len, window);
 
-       if (cwnd_len <= needed)
-               return cwnd_len;
+       if (max_len <= needed)
+               return max_len;
 
        return needed - needed % mss_now;
 }
@@ -1765,7 +1765,8 @@ static bool tcp_tso_should_defer(struct sock *sk, struct sk_buff *skb)
        limit = min(send_win, cong_win);
 
        /* If a full-sized TSO skb can be sent, do it. */
-       if (limit >= sk->sk_gso_max_size)
+       if (limit >= min_t(unsigned int, sk->sk_gso_max_size,
+                          sk->sk_gso_max_segs * tp->mss_cache))
                goto send_now;
 
        /* Middle in queue won't get any more data, full sendable already? */
@@ -1999,7 +2000,9 @@ static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
                limit = mss_now;
                if (tso_segs > 1 && !tcp_urg_mode(tp))
                        limit = tcp_mss_split_point(sk, skb, mss_now,
-                                                   cwnd_quota);
+                                                   min_t(unsigned int,
+                                                         cwnd_quota,
+                                                         sk->sk_gso_max_segs));
 
                if (skb->len > limit &&
                    unlikely(tso_fragment(sk, skb, limit, mss_now, gfp)))
index b4c3582a991f94db7f6047d5b514b062ccf7e43d..6f6d1aca3c3de0e21036c075c0a13c429ef4f8ae 100644 (file)
@@ -758,7 +758,7 @@ static int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4)
                uh->check = CSUM_MANGLED_0;
 
 send:
-       err = ip_send_skb(skb);
+       err = ip_send_skb(sock_net(sk), skb);
        if (err) {
                if (err == -ENOBUFS && !inet->recverr) {
                        UDP_INC_STATS_USER(sock_net(sk),
index 5728695b54492dc2d275458b8db786f410e94002..4f7fe7270e3703226de121041d1e5e96a5b127df 100644 (file)
@@ -201,6 +201,22 @@ config IPV6_TUNNEL
 
          If unsure, say N.
 
+config IPV6_GRE
+       tristate "IPv6: GRE tunnel"
+       select IPV6_TUNNEL
+       ---help---
+         Tunneling means encapsulating data of one protocol type within
+         another protocol and sending it over a channel that understands the
+         encapsulating protocol. This particular tunneling driver implements
+         GRE (Generic Routing Encapsulation) and at this time allows
+         encapsulating of IPv4 or IPv6 over existing IPv6 infrastructure.
+         This driver is useful if the other endpoint is a Cisco router: Cisco
+         likes GRE much better than the other Linux tunneling driver ("IP
+         tunneling" above). In addition, GRE allows multicast redistribution
+         through the tunnel.
+
+         Saying M here will produce a module called ip6_gre. If unsure, say N.
+
 config IPV6_MULTIPLE_TABLES
        bool "IPv6: Multiple Routing Tables"
        depends on EXPERIMENTAL
index 686934acfac18eac215a17b8d4d01ea5ad03c860..b6d3f79151e28251f3b3b5a062869fa9acb64526 100644 (file)
@@ -36,6 +36,7 @@ obj-$(CONFIG_NETFILTER)       += netfilter/
 
 obj-$(CONFIG_IPV6_SIT) += sit.o
 obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
+obj-$(CONFIG_IPV6_GRE) += ip6_gre.o
 
 obj-y += addrconf_core.o exthdrs_core.o
 
index 79181819a24fa7d3ed67b5a4c22d44e51945da63..6bc85f7c31e3c58a01a6d1aa351cd827584fad24 100644 (file)
@@ -494,8 +494,7 @@ static void addrconf_forward_change(struct net *net, __s32 newf)
        struct net_device *dev;
        struct inet6_dev *idev;
 
-       rcu_read_lock();
-       for_each_netdev_rcu(net, dev) {
+       for_each_netdev(net, dev) {
                idev = __in6_dev_get(dev);
                if (idev) {
                        int changed = (!idev->cnf.forwarding) ^ (!newf);
@@ -504,7 +503,6 @@ static void addrconf_forward_change(struct net *net, __s32 newf)
                                dev_forward_change(idev);
                }
        }
-       rcu_read_unlock();
 }
 
 static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int newf)
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
new file mode 100644 (file)
index 0000000..a84ad5d
--- /dev/null
@@ -0,0 +1,1790 @@
+/*
+ *     GRE over IPv6 protocol decoder.
+ *
+ *     Authors: Dmitry Kozlov (xeb@mail.ru)
+ *
+ *     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.
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/capability.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/in.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/if_arp.h>
+#include <linux/mroute.h>
+#include <linux/init.h>
+#include <linux/in6.h>
+#include <linux/inetdevice.h>
+#include <linux/igmp.h>
+#include <linux/netfilter_ipv4.h>
+#include <linux/etherdevice.h>
+#include <linux/if_ether.h>
+#include <linux/hash.h>
+#include <linux/if_tunnel.h>
+#include <linux/ip6_tunnel.h>
+
+#include <net/sock.h>
+#include <net/ip.h>
+#include <net/icmp.h>
+#include <net/protocol.h>
+#include <net/addrconf.h>
+#include <net/arp.h>
+#include <net/checksum.h>
+#include <net/dsfield.h>
+#include <net/inet_ecn.h>
+#include <net/xfrm.h>
+#include <net/net_namespace.h>
+#include <net/netns/generic.h>
+#include <net/rtnetlink.h>
+
+#include <net/ipv6.h>
+#include <net/ip6_fib.h>
+#include <net/ip6_route.h>
+#include <net/ip6_tunnel.h>
+
+
+#define IPV6_TCLASS_MASK (IPV6_FLOWINFO_MASK & ~IPV6_FLOWLABEL_MASK)
+#define IPV6_TCLASS_SHIFT 20
+
+#define HASH_SIZE_SHIFT  5
+#define HASH_SIZE (1 << HASH_SIZE_SHIFT)
+
+static int ip6gre_net_id __read_mostly;
+struct ip6gre_net {
+       struct ip6_tnl __rcu *tunnels[4][HASH_SIZE];
+
+       struct net_device *fb_tunnel_dev;
+};
+
+static struct rtnl_link_ops ip6gre_link_ops __read_mostly;
+static int ip6gre_tunnel_init(struct net_device *dev);
+static void ip6gre_tunnel_setup(struct net_device *dev);
+static void ip6gre_tunnel_link(struct ip6gre_net *ign, struct ip6_tnl *t);
+static void ip6gre_tnl_link_config(struct ip6_tnl *t, int set_mtu);
+
+/* Tunnel hash table */
+
+/*
+   4 hash tables:
+
+   3: (remote,local)
+   2: (remote,*)
+   1: (*,local)
+   0: (*,*)
+
+   We require exact key match i.e. if a key is present in packet
+   it will match only tunnel with the same key; if it is not present,
+   it will match only keyless tunnel.
+
+   All keysless packets, if not matched configured keyless tunnels
+   will match fallback tunnel.
+ */
+
+#define HASH_KEY(key) (((__force u32)key^((__force u32)key>>4))&(HASH_SIZE - 1))
+static u32 HASH_ADDR(const struct in6_addr *addr)
+{
+       u32 hash = ipv6_addr_hash(addr);
+
+       return hash_32(hash, HASH_SIZE_SHIFT);
+}
+
+#define tunnels_r_l    tunnels[3]
+#define tunnels_r      tunnels[2]
+#define tunnels_l      tunnels[1]
+#define tunnels_wc     tunnels[0]
+/*
+ * Locking : hash tables are protected by RCU and RTNL
+ */
+
+#define for_each_ip_tunnel_rcu(start) \
+       for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
+
+/* often modified stats are per cpu, other are shared (netdev->stats) */
+struct pcpu_tstats {
+       u64     rx_packets;
+       u64     rx_bytes;
+       u64     tx_packets;
+       u64     tx_bytes;
+       struct u64_stats_sync   syncp;
+};
+
+static struct rtnl_link_stats64 *ip6gre_get_stats64(struct net_device *dev,
+               struct rtnl_link_stats64 *tot)
+{
+       int i;
+
+       for_each_possible_cpu(i) {
+               const struct pcpu_tstats *tstats = per_cpu_ptr(dev->tstats, i);
+               u64 rx_packets, rx_bytes, tx_packets, tx_bytes;
+               unsigned int start;
+
+               do {
+                       start = u64_stats_fetch_begin_bh(&tstats->syncp);
+                       rx_packets = tstats->rx_packets;
+                       tx_packets = tstats->tx_packets;
+                       rx_bytes = tstats->rx_bytes;
+                       tx_bytes = tstats->tx_bytes;
+               } while (u64_stats_fetch_retry_bh(&tstats->syncp, start));
+
+               tot->rx_packets += rx_packets;
+               tot->tx_packets += tx_packets;
+               tot->rx_bytes   += rx_bytes;
+               tot->tx_bytes   += tx_bytes;
+       }
+
+       tot->multicast = dev->stats.multicast;
+       tot->rx_crc_errors = dev->stats.rx_crc_errors;
+       tot->rx_fifo_errors = dev->stats.rx_fifo_errors;
+       tot->rx_length_errors = dev->stats.rx_length_errors;
+       tot->rx_errors = dev->stats.rx_errors;
+       tot->tx_fifo_errors = dev->stats.tx_fifo_errors;
+       tot->tx_carrier_errors = dev->stats.tx_carrier_errors;
+       tot->tx_dropped = dev->stats.tx_dropped;
+       tot->tx_aborted_errors = dev->stats.tx_aborted_errors;
+       tot->tx_errors = dev->stats.tx_errors;
+
+       return tot;
+}
+
+/* Given src, dst and key, find appropriate for input tunnel. */
+
+static struct ip6_tnl *ip6gre_tunnel_lookup(struct net_device *dev,
+               const struct in6_addr *remote, const struct in6_addr *local,
+               __be32 key, __be16 gre_proto)
+{
+       struct net *net = dev_net(dev);
+       int link = dev->ifindex;
+       unsigned int h0 = HASH_ADDR(remote);
+       unsigned int h1 = HASH_KEY(key);
+       struct ip6_tnl *t, *cand = NULL;
+       struct ip6gre_net *ign = net_generic(net, ip6gre_net_id);
+       int dev_type = (gre_proto == htons(ETH_P_TEB)) ?
+                      ARPHRD_ETHER : ARPHRD_IP6GRE;
+       int score, cand_score = 4;
+
+       for_each_ip_tunnel_rcu(ign->tunnels_r_l[h0 ^ h1]) {
+               if (!ipv6_addr_equal(local, &t->parms.laddr) ||
+                   !ipv6_addr_equal(remote, &t->parms.raddr) ||
+                   key != t->parms.i_key ||
+                   !(t->dev->flags & IFF_UP))
+                       continue;
+
+               if (t->dev->type != ARPHRD_IP6GRE &&
+                   t->dev->type != dev_type)
+                       continue;
+
+               score = 0;
+               if (t->parms.link != link)
+                       score |= 1;
+               if (t->dev->type != dev_type)
+                       score |= 2;
+               if (score == 0)
+                       return t;
+
+               if (score < cand_score) {
+                       cand = t;
+                       cand_score = score;
+               }
+       }
+
+       for_each_ip_tunnel_rcu(ign->tunnels_r[h0 ^ h1]) {
+               if (!ipv6_addr_equal(remote, &t->parms.raddr) ||
+                   key != t->parms.i_key ||
+                   !(t->dev->flags & IFF_UP))
+                       continue;
+
+               if (t->dev->type != ARPHRD_IP6GRE &&
+                   t->dev->type != dev_type)
+                       continue;
+
+               score = 0;
+               if (t->parms.link != link)
+                       score |= 1;
+               if (t->dev->type != dev_type)
+                       score |= 2;
+               if (score == 0)
+                       return t;
+
+               if (score < cand_score) {
+                       cand = t;
+                       cand_score = score;
+               }
+       }
+
+       for_each_ip_tunnel_rcu(ign->tunnels_l[h1]) {
+               if ((!ipv6_addr_equal(local, &t->parms.laddr) &&
+                         (!ipv6_addr_equal(local, &t->parms.raddr) ||
+                                !ipv6_addr_is_multicast(local))) ||
+                   key != t->parms.i_key ||
+                   !(t->dev->flags & IFF_UP))
+                       continue;
+
+               if (t->dev->type != ARPHRD_IP6GRE &&
+                   t->dev->type != dev_type)
+                       continue;
+
+               score = 0;
+               if (t->parms.link != link)
+                       score |= 1;
+               if (t->dev->type != dev_type)
+                       score |= 2;
+               if (score == 0)
+                       return t;
+
+               if (score < cand_score) {
+                       cand = t;
+                       cand_score = score;
+               }
+       }
+
+       for_each_ip_tunnel_rcu(ign->tunnels_wc[h1]) {
+               if (t->parms.i_key != key ||
+                   !(t->dev->flags & IFF_UP))
+                       continue;
+
+               if (t->dev->type != ARPHRD_IP6GRE &&
+                   t->dev->type != dev_type)
+                       continue;
+
+               score = 0;
+               if (t->parms.link != link)
+                       score |= 1;
+               if (t->dev->type != dev_type)
+                       score |= 2;
+               if (score == 0)
+                       return t;
+
+               if (score < cand_score) {
+                       cand = t;
+                       cand_score = score;
+               }
+       }
+
+       if (cand != NULL)
+               return cand;
+
+       dev = ign->fb_tunnel_dev;
+       if (dev->flags & IFF_UP)
+               return netdev_priv(dev);
+
+       return NULL;
+}
+
+static struct ip6_tnl __rcu **__ip6gre_bucket(struct ip6gre_net *ign,
+               const struct __ip6_tnl_parm *p)
+{
+       const struct in6_addr *remote = &p->raddr;
+       const struct in6_addr *local = &p->laddr;
+       unsigned int h = HASH_KEY(p->i_key);
+       int prio = 0;
+
+       if (!ipv6_addr_any(local))
+               prio |= 1;
+       if (!ipv6_addr_any(remote) && !ipv6_addr_is_multicast(remote)) {
+               prio |= 2;
+               h ^= HASH_ADDR(remote);
+       }
+
+       return &ign->tunnels[prio][h];
+}
+
+static inline struct ip6_tnl __rcu **ip6gre_bucket(struct ip6gre_net *ign,
+               const struct ip6_tnl *t)
+{
+       return __ip6gre_bucket(ign, &t->parms);
+}
+
+static void ip6gre_tunnel_link(struct ip6gre_net *ign, struct ip6_tnl *t)
+{
+       struct ip6_tnl __rcu **tp = ip6gre_bucket(ign, t);
+
+       rcu_assign_pointer(t->next, rtnl_dereference(*tp));
+       rcu_assign_pointer(*tp, t);
+}
+
+static void ip6gre_tunnel_unlink(struct ip6gre_net *ign, struct ip6_tnl *t)
+{
+       struct ip6_tnl __rcu **tp;
+       struct ip6_tnl *iter;
+
+       for (tp = ip6gre_bucket(ign, t);
+            (iter = rtnl_dereference(*tp)) != NULL;
+            tp = &iter->next) {
+               if (t == iter) {
+                       rcu_assign_pointer(*tp, t->next);
+                       break;
+               }
+       }
+}
+
+static struct ip6_tnl *ip6gre_tunnel_find(struct net *net,
+                                          const struct __ip6_tnl_parm *parms,
+                                          int type)
+{
+       const struct in6_addr *remote = &parms->raddr;
+       const struct in6_addr *local = &parms->laddr;
+       __be32 key = parms->i_key;
+       int link = parms->link;
+       struct ip6_tnl *t;
+       struct ip6_tnl __rcu **tp;
+       struct ip6gre_net *ign = net_generic(net, ip6gre_net_id);
+
+       for (tp = __ip6gre_bucket(ign, parms);
+            (t = rtnl_dereference(*tp)) != NULL;
+            tp = &t->next)
+               if (ipv6_addr_equal(local, &t->parms.laddr) &&
+                   ipv6_addr_equal(remote, &t->parms.raddr) &&
+                   key == t->parms.i_key &&
+                   link == t->parms.link &&
+                   type == t->dev->type)
+                       break;
+
+       return t;
+}
+
+static struct ip6_tnl *ip6gre_tunnel_locate(struct net *net,
+               const struct __ip6_tnl_parm *parms, int create)
+{
+       struct ip6_tnl *t, *nt;
+       struct net_device *dev;
+       char name[IFNAMSIZ];
+       struct ip6gre_net *ign = net_generic(net, ip6gre_net_id);
+
+       t = ip6gre_tunnel_find(net, parms, ARPHRD_IP6GRE);
+       if (t || !create)
+               return t;
+
+       if (parms->name[0])
+               strlcpy(name, parms->name, IFNAMSIZ);
+       else
+               strcpy(name, "ip6gre%d");
+
+       dev = alloc_netdev(sizeof(*t), name, ip6gre_tunnel_setup);
+       if (!dev)
+               return NULL;
+
+       dev_net_set(dev, net);
+
+       nt = netdev_priv(dev);
+       nt->parms = *parms;
+       dev->rtnl_link_ops = &ip6gre_link_ops;
+
+       nt->dev = dev;
+       ip6gre_tnl_link_config(nt, 1);
+
+       if (register_netdevice(dev) < 0)
+               goto failed_free;
+
+       /* Can use a lockless transmit, unless we generate output sequences */
+       if (!(nt->parms.o_flags & GRE_SEQ))
+               dev->features |= NETIF_F_LLTX;
+
+       dev_hold(dev);
+       ip6gre_tunnel_link(ign, nt);
+       return nt;
+
+failed_free:
+       free_netdev(dev);
+       return NULL;
+}
+
+static void ip6gre_tunnel_uninit(struct net_device *dev)
+{
+       struct net *net = dev_net(dev);
+       struct ip6gre_net *ign = net_generic(net, ip6gre_net_id);
+
+       ip6gre_tunnel_unlink(ign, netdev_priv(dev));
+       dev_put(dev);
+}
+
+
+static void ip6gre_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+               u8 type, u8 code, int offset, __be32 info)
+{
+       const struct ipv6hdr *ipv6h = (const struct ipv6hdr *)skb->data;
+       __be16 *p = (__be16 *)(ipv6h + 1);
+       int grehlen = sizeof(ipv6h) + 4;
+       struct ip6_tnl *t;
+       __be16 flags;
+
+       flags = p[0];
+       if (flags&(GRE_CSUM|GRE_KEY|GRE_SEQ|GRE_ROUTING|GRE_VERSION)) {
+               if (flags&(GRE_VERSION|GRE_ROUTING))
+                       return;
+               if (flags&GRE_KEY) {
+                       grehlen += 4;
+                       if (flags&GRE_CSUM)
+                               grehlen += 4;
+               }
+       }
+
+       /* If only 8 bytes returned, keyed message will be dropped here */
+       if (skb_headlen(skb) < grehlen)
+               return;
+
+       rcu_read_lock();
+
+       t = ip6gre_tunnel_lookup(skb->dev, &ipv6h->daddr, &ipv6h->saddr,
+                               flags & GRE_KEY ?
+                               *(((__be32 *)p) + (grehlen / 4) - 1) : 0,
+                               p[1]);
+       if (t == NULL)
+               goto out;
+
+       switch (type) {
+               __u32 teli;
+               struct ipv6_tlv_tnl_enc_lim *tel;
+               __u32 mtu;
+       case ICMPV6_DEST_UNREACH:
+               net_warn_ratelimited("%s: Path to destination invalid or inactive!\n",
+                                    t->parms.name);
+               break;
+       case ICMPV6_TIME_EXCEED:
+               if (code == ICMPV6_EXC_HOPLIMIT) {
+                       net_warn_ratelimited("%s: Too small hop limit or routing loop in tunnel!\n",
+                                            t->parms.name);
+               }
+               break;
+       case ICMPV6_PARAMPROB:
+               teli = 0;
+               if (code == ICMPV6_HDR_FIELD)
+                       teli = ip6_tnl_parse_tlv_enc_lim(skb, skb->data);
+
+               if (teli && teli == info - 2) {
+                       tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->data[teli];
+                       if (tel->encap_limit == 0) {
+                               net_warn_ratelimited("%s: Too small encapsulation limit or routing loop in tunnel!\n",
+                                                    t->parms.name);
+                       }
+               } else {
+                       net_warn_ratelimited("%s: Recipient unable to parse tunneled packet!\n",
+                                            t->parms.name);
+               }
+               break;
+       case ICMPV6_PKT_TOOBIG:
+               mtu = info - offset;
+               if (mtu < IPV6_MIN_MTU)
+                       mtu = IPV6_MIN_MTU;
+               t->dev->mtu = mtu;
+               break;
+       }
+
+       if (time_before(jiffies, t->err_time + IP6TUNNEL_ERR_TIMEO))
+               t->err_count++;
+       else
+               t->err_count = 1;
+       t->err_time = jiffies;
+out:
+       rcu_read_unlock();
+}
+
+static inline void ip6gre_ecn_decapsulate_ipv4(const struct ip6_tnl *t,
+               const struct ipv6hdr *ipv6h, struct sk_buff *skb)
+{
+       __u8 dsfield = ipv6_get_dsfield(ipv6h) & ~INET_ECN_MASK;
+
+       if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY)
+               ipv4_change_dsfield(ip_hdr(skb), INET_ECN_MASK, dsfield);
+
+       if (INET_ECN_is_ce(dsfield))
+               IP_ECN_set_ce(ip_hdr(skb));
+}
+
+static inline void ip6gre_ecn_decapsulate_ipv6(const struct ip6_tnl *t,
+               const struct ipv6hdr *ipv6h, struct sk_buff *skb)
+{
+       if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY)
+               ipv6_copy_dscp(ipv6_get_dsfield(ipv6h), ipv6_hdr(skb));
+
+       if (INET_ECN_is_ce(ipv6_get_dsfield(ipv6h)))
+               IP6_ECN_set_ce(ipv6_hdr(skb));
+}
+
+static int ip6gre_rcv(struct sk_buff *skb)
+{
+       const struct ipv6hdr *ipv6h;
+       u8     *h;
+       __be16    flags;
+       __sum16   csum = 0;
+       __be32 key = 0;
+       u32    seqno = 0;
+       struct ip6_tnl *tunnel;
+       int    offset = 4;
+       __be16 gre_proto;
+
+       if (!pskb_may_pull(skb, sizeof(struct in6_addr)))
+               goto drop_nolock;
+
+       ipv6h = ipv6_hdr(skb);
+       h = skb->data;
+       flags = *(__be16 *)h;
+
+       if (flags&(GRE_CSUM|GRE_KEY|GRE_ROUTING|GRE_SEQ|GRE_VERSION)) {
+               /* - Version must be 0.
+                  - We do not support routing headers.
+                */
+               if (flags&(GRE_VERSION|GRE_ROUTING))
+                       goto drop_nolock;
+
+               if (flags&GRE_CSUM) {
+                       switch (skb->ip_summed) {
+                       case CHECKSUM_COMPLETE:
+                               csum = csum_fold(skb->csum);
+                               if (!csum)
+                                       break;
+                               /* fall through */
+                       case CHECKSUM_NONE:
+                               skb->csum = 0;
+                               csum = __skb_checksum_complete(skb);
+                               skb->ip_summed = CHECKSUM_COMPLETE;
+                       }
+                       offset += 4;
+               }
+               if (flags&GRE_KEY) {
+                       key = *(__be32 *)(h + offset);
+                       offset += 4;
+               }
+               if (flags&GRE_SEQ) {
+                       seqno = ntohl(*(__be32 *)(h + offset));
+                       offset += 4;
+               }
+       }
+
+       gre_proto = *(__be16 *)(h + 2);
+
+       rcu_read_lock();
+       tunnel = ip6gre_tunnel_lookup(skb->dev,
+                                         &ipv6h->saddr, &ipv6h->daddr, key,
+                                         gre_proto);
+       if (tunnel) {
+               struct pcpu_tstats *tstats;
+
+               if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
+                       goto drop;
+
+               if (!ip6_tnl_rcv_ctl(tunnel, &ipv6h->daddr, &ipv6h->saddr)) {
+                       tunnel->dev->stats.rx_dropped++;
+                       goto drop;
+               }
+
+               secpath_reset(skb);
+
+               skb->protocol = gre_proto;
+               /* WCCP version 1 and 2 protocol decoding.
+                * - Change protocol to IP
+                * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header
+                */
+               if (flags == 0 && gre_proto == htons(ETH_P_WCCP)) {
+                       skb->protocol = htons(ETH_P_IP);
+                       if ((*(h + offset) & 0xF0) != 0x40)
+                               offset += 4;
+               }
+
+               skb->mac_header = skb->network_header;
+               __pskb_pull(skb, offset);
+               skb_postpull_rcsum(skb, skb_transport_header(skb), offset);
+               skb->pkt_type = PACKET_HOST;
+
+               if (((flags&GRE_CSUM) && csum) ||
+                   (!(flags&GRE_CSUM) && tunnel->parms.i_flags&GRE_CSUM)) {
+                       tunnel->dev->stats.rx_crc_errors++;
+                       tunnel->dev->stats.rx_errors++;
+                       goto drop;
+               }
+               if (tunnel->parms.i_flags&GRE_SEQ) {
+                       if (!(flags&GRE_SEQ) ||
+                           (tunnel->i_seqno &&
+                                       (s32)(seqno - tunnel->i_seqno) < 0)) {
+                               tunnel->dev->stats.rx_fifo_errors++;
+                               tunnel->dev->stats.rx_errors++;
+                               goto drop;
+                       }
+                       tunnel->i_seqno = seqno + 1;
+               }
+
+               /* Warning: All skb pointers will be invalidated! */
+               if (tunnel->dev->type == ARPHRD_ETHER) {
+                       if (!pskb_may_pull(skb, ETH_HLEN)) {
+                               tunnel->dev->stats.rx_length_errors++;
+                               tunnel->dev->stats.rx_errors++;
+                               goto drop;
+                       }
+
+                       ipv6h = ipv6_hdr(skb);
+                       skb->protocol = eth_type_trans(skb, tunnel->dev);
+                       skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN);
+               }
+
+               tstats = this_cpu_ptr(tunnel->dev->tstats);
+               u64_stats_update_begin(&tstats->syncp);
+               tstats->rx_packets++;
+               tstats->rx_bytes += skb->len;
+               u64_stats_update_end(&tstats->syncp);
+
+               __skb_tunnel_rx(skb, tunnel->dev);
+
+               skb_reset_network_header(skb);
+               if (skb->protocol == htons(ETH_P_IP))
+                       ip6gre_ecn_decapsulate_ipv4(tunnel, ipv6h, skb);
+               else if (skb->protocol == htons(ETH_P_IPV6))
+                       ip6gre_ecn_decapsulate_ipv6(tunnel, ipv6h, skb);
+
+               netif_rx(skb);
+
+               rcu_read_unlock();
+               return 0;
+       }
+       icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0);
+
+drop:
+       rcu_read_unlock();
+drop_nolock:
+       kfree_skb(skb);
+       return 0;
+}
+
+struct ipv6_tel_txoption {
+       struct ipv6_txoptions ops;
+       __u8 dst_opt[8];
+};
+
+static void init_tel_txopt(struct ipv6_tel_txoption *opt, __u8 encap_limit)
+{
+       memset(opt, 0, sizeof(struct ipv6_tel_txoption));
+
+       opt->dst_opt[2] = IPV6_TLV_TNL_ENCAP_LIMIT;
+       opt->dst_opt[3] = 1;
+       opt->dst_opt[4] = encap_limit;
+       opt->dst_opt[5] = IPV6_TLV_PADN;
+       opt->dst_opt[6] = 1;
+
+       opt->ops.dst0opt = (struct ipv6_opt_hdr *) opt->dst_opt;
+       opt->ops.opt_nflen = 8;
+}
+
+static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
+                        struct net_device *dev,
+                        __u8 dsfield,
+                        struct flowi6 *fl6,
+                        int encap_limit,
+                        __u32 *pmtu)
+{
+       struct net *net = dev_net(dev);
+       struct ip6_tnl *tunnel = netdev_priv(dev);
+       struct net_device *tdev;    /* Device to other host */
+       struct ipv6hdr  *ipv6h;     /* Our new IP header */
+       unsigned int max_headroom;  /* The extra header space needed */
+       int    gre_hlen;
+       struct ipv6_tel_txoption opt;
+       int    mtu;
+       struct dst_entry *dst = NULL, *ndst = NULL;
+       struct net_device_stats *stats = &tunnel->dev->stats;
+       int err = -1;
+       u8 proto;
+       int pkt_len;
+       struct sk_buff *new_skb;
+
+       if (dev->type == ARPHRD_ETHER)
+               IPCB(skb)->flags = 0;
+
+       if (dev->header_ops && dev->type == ARPHRD_IP6GRE) {
+               gre_hlen = 0;
+               ipv6h = (struct ipv6hdr *)skb->data;
+               fl6->daddr = ipv6h->daddr;
+       } else {
+               gre_hlen = tunnel->hlen;
+               fl6->daddr = tunnel->parms.raddr;
+       }
+
+       if (!fl6->flowi6_mark)
+               dst = ip6_tnl_dst_check(tunnel);
+
+       if (!dst) {
+               ndst = ip6_route_output(net, NULL, fl6);
+
+               if (ndst->error)
+                       goto tx_err_link_failure;
+               ndst = xfrm_lookup(net, ndst, flowi6_to_flowi(fl6), NULL, 0);
+               if (IS_ERR(ndst)) {
+                       err = PTR_ERR(ndst);
+                       ndst = NULL;
+                       goto tx_err_link_failure;
+               }
+               dst = ndst;
+       }
+
+       tdev = dst->dev;
+
+       if (tdev == dev) {
+               stats->collisions++;
+               net_warn_ratelimited("%s: Local routing loop detected!\n",
+                                    tunnel->parms.name);
+               goto tx_err_dst_release;
+       }
+
+       mtu = dst_mtu(dst) - sizeof(*ipv6h);
+       if (encap_limit >= 0) {
+               max_headroom += 8;
+               mtu -= 8;
+       }
+       if (mtu < IPV6_MIN_MTU)
+               mtu = IPV6_MIN_MTU;
+       if (skb_dst(skb))
+               skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu);
+       if (skb->len > mtu) {
+               *pmtu = mtu;
+               err = -EMSGSIZE;
+               goto tx_err_dst_release;
+       }
+
+       if (tunnel->err_count > 0) {
+               if (time_before(jiffies,
+                               tunnel->err_time + IP6TUNNEL_ERR_TIMEO)) {
+                       tunnel->err_count--;
+
+                       dst_link_failure(skb);
+               } else
+                       tunnel->err_count = 0;
+       }
+
+       max_headroom = LL_RESERVED_SPACE(tdev) + gre_hlen + dst->header_len;
+
+       if (skb_headroom(skb) < max_headroom || skb_shared(skb) ||
+           (skb_cloned(skb) && !skb_clone_writable(skb, 0))) {
+               new_skb = skb_realloc_headroom(skb, max_headroom);
+               if (max_headroom > dev->needed_headroom)
+                       dev->needed_headroom = max_headroom;
+               if (!new_skb)
+                       goto tx_err_dst_release;
+
+               if (skb->sk)
+                       skb_set_owner_w(new_skb, skb->sk);
+               consume_skb(skb);
+               skb = new_skb;
+       }
+
+       skb_dst_drop(skb);
+
+       if (fl6->flowi6_mark) {
+               skb_dst_set(skb, dst);
+               ndst = NULL;
+       } else {
+               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);
+               ipv6_push_nfrag_opts(skb, &opt.ops, &proto, NULL);
+       }
+
+       skb_push(skb, gre_hlen);
+       skb_reset_network_header(skb);
+
+       /*
+        *      Push down and install the IP header.
+        */
+       ipv6h = ipv6_hdr(skb);
+       *(__be32 *)ipv6h = fl6->flowlabel | htonl(0x60000000);
+       dsfield = INET_ECN_encapsulate(0, dsfield);
+       ipv6_change_dsfield(ipv6h, ~INET_ECN_MASK, dsfield);
+       ipv6h->hop_limit = tunnel->parms.hop_limit;
+       ipv6h->nexthdr = proto;
+       ipv6h->saddr = fl6->saddr;
+       ipv6h->daddr = fl6->daddr;
+
+       ((__be16 *)(ipv6h + 1))[0] = tunnel->parms.o_flags;
+       ((__be16 *)(ipv6h + 1))[1] = (dev->type == ARPHRD_ETHER) ?
+                                  htons(ETH_P_TEB) : skb->protocol;
+
+       if (tunnel->parms.o_flags&(GRE_KEY|GRE_CSUM|GRE_SEQ)) {
+               __be32 *ptr = (__be32 *)(((u8 *)ipv6h) + tunnel->hlen - 4);
+
+               if (tunnel->parms.o_flags&GRE_SEQ) {
+                       ++tunnel->o_seqno;
+                       *ptr = htonl(tunnel->o_seqno);
+                       ptr--;
+               }
+               if (tunnel->parms.o_flags&GRE_KEY) {
+                       *ptr = tunnel->parms.o_key;
+                       ptr--;
+               }
+               if (tunnel->parms.o_flags&GRE_CSUM) {
+                       *ptr = 0;
+                       *(__sum16 *)ptr = ip_compute_csum((void *)(ipv6h+1),
+                               skb->len - sizeof(struct ipv6hdr));
+               }
+       }
+
+       nf_reset(skb);
+       pkt_len = skb->len;
+       err = ip6_local_out(skb);
+
+       if (net_xmit_eval(err) == 0) {
+               struct pcpu_tstats *tstats = this_cpu_ptr(tunnel->dev->tstats);
+
+               tstats->tx_bytes += pkt_len;
+               tstats->tx_packets++;
+       } else {
+               stats->tx_errors++;
+               stats->tx_aborted_errors++;
+       }
+
+       if (ndst)
+               ip6_tnl_dst_store(tunnel, ndst);
+
+       return 0;
+tx_err_link_failure:
+       stats->tx_carrier_errors++;
+       dst_link_failure(skb);
+tx_err_dst_release:
+       dst_release(ndst);
+       return err;
+}
+
+static inline int ip6gre_xmit_ipv4(struct sk_buff *skb, struct net_device *dev)
+{
+       struct ip6_tnl *t = netdev_priv(dev);
+       const struct iphdr  *iph = ip_hdr(skb);
+       int encap_limit = -1;
+       struct flowi6 fl6;
+       __u8 dsfield;
+       __u32 mtu;
+       int err;
+
+       if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
+               encap_limit = t->parms.encap_limit;
+
+       memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6));
+       fl6.flowi6_proto = IPPROTO_IPIP;
+
+       dsfield = ipv4_get_dsfield(iph);
+
+       if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)
+               fl6.flowlabel |= htonl((__u32)iph->tos << IPV6_TCLASS_SHIFT)
+                                         & IPV6_TCLASS_MASK;
+       if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
+               fl6.flowi6_mark = skb->mark;
+
+       err = ip6gre_xmit2(skb, dev, dsfield, &fl6, encap_limit, &mtu);
+       if (err != 0) {
+               /* XXX: send ICMP error even if DF is not set. */
+               if (err == -EMSGSIZE)
+                       icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
+                                 htonl(mtu));
+               return -1;
+       }
+
+       return 0;
+}
+
+static inline int ip6gre_xmit_ipv6(struct sk_buff *skb, struct net_device *dev)
+{
+       struct ip6_tnl *t = netdev_priv(dev);
+       struct ipv6hdr *ipv6h = ipv6_hdr(skb);
+       int encap_limit = -1;
+       __u16 offset;
+       struct flowi6 fl6;
+       __u8 dsfield;
+       __u32 mtu;
+       int err;
+
+       if (ipv6_addr_equal(&t->parms.raddr, &ipv6h->saddr))
+               return -1;
+
+       offset = ip6_tnl_parse_tlv_enc_lim(skb, skb_network_header(skb));
+       if (offset > 0) {
+               struct ipv6_tlv_tnl_enc_lim *tel;
+               tel = (struct ipv6_tlv_tnl_enc_lim *)&skb_network_header(skb)[offset];
+               if (tel->encap_limit == 0) {
+                       icmpv6_send(skb, ICMPV6_PARAMPROB,
+                                   ICMPV6_HDR_FIELD, offset + 2);
+                       return -1;
+               }
+               encap_limit = tel->encap_limit - 1;
+       } else if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
+               encap_limit = t->parms.encap_limit;
+
+       memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6));
+       fl6.flowi6_proto = IPPROTO_IPV6;
+
+       dsfield = ipv6_get_dsfield(ipv6h);
+       if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)
+               fl6.flowlabel |= (*(__be32 *) ipv6h & IPV6_TCLASS_MASK);
+       if (t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL)
+               fl6.flowlabel |= (*(__be32 *) ipv6h & IPV6_FLOWLABEL_MASK);
+       if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
+               fl6.flowi6_mark = skb->mark;
+
+       err = ip6gre_xmit2(skb, dev, dsfield, &fl6, encap_limit, &mtu);
+       if (err != 0) {
+               if (err == -EMSGSIZE)
+                       icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
+               return -1;
+       }
+
+       return 0;
+}
+
+/**
+ * ip6_tnl_addr_conflict - compare packet addresses to tunnel's own
+ *   @t: the outgoing tunnel device
+ *   @hdr: IPv6 header from the incoming packet
+ *
+ * Description:
+ *   Avoid trivial tunneling loop by checking that tunnel exit-point
+ *   doesn't match source of incoming packet.
+ *
+ * Return:
+ *   1 if conflict,
+ *   0 else
+ **/
+
+static inline bool ip6gre_tnl_addr_conflict(const struct ip6_tnl *t,
+       const struct ipv6hdr *hdr)
+{
+       return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr);
+}
+
+static int ip6gre_xmit_other(struct sk_buff *skb, struct net_device *dev)
+{
+       struct ip6_tnl *t = netdev_priv(dev);
+       int encap_limit = -1;
+       struct flowi6 fl6;
+       __u32 mtu;
+       int err;
+
+       if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
+               encap_limit = t->parms.encap_limit;
+
+       memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6));
+       fl6.flowi6_proto = skb->protocol;
+
+       err = ip6gre_xmit2(skb, dev, 0, &fl6, encap_limit, &mtu);
+
+       return err;
+}
+
+static netdev_tx_t ip6gre_tunnel_xmit(struct sk_buff *skb,
+       struct net_device *dev)
+{
+       struct ip6_tnl *t = netdev_priv(dev);
+       struct net_device_stats *stats = &t->dev->stats;
+       int ret;
+
+       if (!ip6_tnl_xmit_ctl(t))
+               return -1;
+
+       switch (skb->protocol) {
+       case htons(ETH_P_IP):
+               ret = ip6gre_xmit_ipv4(skb, dev);
+               break;
+       case htons(ETH_P_IPV6):
+               ret = ip6gre_xmit_ipv6(skb, dev);
+               break;
+       default:
+               ret = ip6gre_xmit_other(skb, dev);
+               break;
+       }
+
+       if (ret < 0)
+               goto tx_err;
+
+       return NETDEV_TX_OK;
+
+tx_err:
+       stats->tx_errors++;
+       stats->tx_dropped++;
+       kfree_skb(skb);
+       return NETDEV_TX_OK;
+}
+
+static void ip6gre_tnl_link_config(struct ip6_tnl *t, int set_mtu)
+{
+       struct net_device *dev = t->dev;
+       struct __ip6_tnl_parm *p = &t->parms;
+       struct flowi6 *fl6 = &t->fl.u.ip6;
+       int addend = sizeof(struct ipv6hdr) + 4;
+
+       if (dev->type != ARPHRD_ETHER) {
+               memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr));
+               memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr));
+       }
+
+       /* Set up flowi template */
+       fl6->saddr = p->laddr;
+       fl6->daddr = p->raddr;
+       fl6->flowi6_oif = p->link;
+       fl6->flowlabel = 0;
+
+       if (!(p->flags&IP6_TNL_F_USE_ORIG_TCLASS))
+               fl6->flowlabel |= IPV6_TCLASS_MASK & p->flowinfo;
+       if (!(p->flags&IP6_TNL_F_USE_ORIG_FLOWLABEL))
+               fl6->flowlabel |= IPV6_FLOWLABEL_MASK & p->flowinfo;
+
+       p->flags &= ~(IP6_TNL_F_CAP_XMIT|IP6_TNL_F_CAP_RCV|IP6_TNL_F_CAP_PER_PACKET);
+       p->flags |= ip6_tnl_get_cap(t, &p->laddr, &p->raddr);
+
+       if (p->flags&IP6_TNL_F_CAP_XMIT &&
+                       p->flags&IP6_TNL_F_CAP_RCV && dev->type != ARPHRD_ETHER)
+               dev->flags |= IFF_POINTOPOINT;
+       else
+               dev->flags &= ~IFF_POINTOPOINT;
+
+       dev->iflink = p->link;
+
+       /* Precalculate GRE options length */
+       if (t->parms.o_flags&(GRE_CSUM|GRE_KEY|GRE_SEQ)) {
+               if (t->parms.o_flags&GRE_CSUM)
+                       addend += 4;
+               if (t->parms.o_flags&GRE_KEY)
+                       addend += 4;
+               if (t->parms.o_flags&GRE_SEQ)
+                       addend += 4;
+       }
+
+       if (p->flags & IP6_TNL_F_CAP_XMIT) {
+               int strict = (ipv6_addr_type(&p->raddr) &
+                             (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL));
+
+               struct rt6_info *rt = rt6_lookup(dev_net(dev),
+                                                &p->raddr, &p->laddr,
+                                                p->link, strict);
+
+               if (rt == NULL)
+                       return;
+
+               if (rt->dst.dev) {
+                       dev->hard_header_len = rt->dst.dev->hard_header_len + addend;
+
+                       if (set_mtu) {
+                               dev->mtu = rt->dst.dev->mtu - addend;
+                               if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
+                                       dev->mtu -= 8;
+
+                               if (dev->mtu < IPV6_MIN_MTU)
+                                       dev->mtu = IPV6_MIN_MTU;
+                       }
+               }
+               dst_release(&rt->dst);
+       }
+
+       t->hlen = addend;
+}
+
+static int ip6gre_tnl_change(struct ip6_tnl *t,
+       const struct __ip6_tnl_parm *p, int set_mtu)
+{
+       t->parms.laddr = p->laddr;
+       t->parms.raddr = p->raddr;
+       t->parms.flags = p->flags;
+       t->parms.hop_limit = p->hop_limit;
+       t->parms.encap_limit = p->encap_limit;
+       t->parms.flowinfo = p->flowinfo;
+       t->parms.link = p->link;
+       t->parms.proto = p->proto;
+       t->parms.i_key = p->i_key;
+       t->parms.o_key = p->o_key;
+       t->parms.i_flags = p->i_flags;
+       t->parms.o_flags = p->o_flags;
+       ip6_tnl_dst_reset(t);
+       ip6gre_tnl_link_config(t, set_mtu);
+       return 0;
+}
+
+static void ip6gre_tnl_parm_from_user(struct __ip6_tnl_parm *p,
+       const struct ip6_tnl_parm2 *u)
+{
+       p->laddr = u->laddr;
+       p->raddr = u->raddr;
+       p->flags = u->flags;
+       p->hop_limit = u->hop_limit;
+       p->encap_limit = u->encap_limit;
+       p->flowinfo = u->flowinfo;
+       p->link = u->link;
+       p->i_key = u->i_key;
+       p->o_key = u->o_key;
+       p->i_flags = u->i_flags;
+       p->o_flags = u->o_flags;
+       memcpy(p->name, u->name, sizeof(u->name));
+}
+
+static void ip6gre_tnl_parm_to_user(struct ip6_tnl_parm2 *u,
+       const struct __ip6_tnl_parm *p)
+{
+       u->proto = IPPROTO_GRE;
+       u->laddr = p->laddr;
+       u->raddr = p->raddr;
+       u->flags = p->flags;
+       u->hop_limit = p->hop_limit;
+       u->encap_limit = p->encap_limit;
+       u->flowinfo = p->flowinfo;
+       u->link = p->link;
+       u->i_key = p->i_key;
+       u->o_key = p->o_key;
+       u->i_flags = p->i_flags;
+       u->o_flags = p->o_flags;
+       memcpy(u->name, p->name, sizeof(u->name));
+}
+
+static int ip6gre_tunnel_ioctl(struct net_device *dev,
+       struct ifreq *ifr, int cmd)
+{
+       int err = 0;
+       struct ip6_tnl_parm2 p;
+       struct __ip6_tnl_parm p1;
+       struct ip6_tnl *t;
+       struct net *net = dev_net(dev);
+       struct ip6gre_net *ign = net_generic(net, ip6gre_net_id);
+
+       switch (cmd) {
+       case SIOCGETTUNNEL:
+               t = NULL;
+               if (dev == ign->fb_tunnel_dev) {
+                       if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) {
+                               err = -EFAULT;
+                               break;
+                       }
+                       ip6gre_tnl_parm_from_user(&p1, &p);
+                       t = ip6gre_tunnel_locate(net, &p1, 0);
+               }
+               if (t == NULL)
+                       t = netdev_priv(dev);
+               ip6gre_tnl_parm_to_user(&p, &t->parms);
+               if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
+                       err = -EFAULT;
+               break;
+
+       case SIOCADDTUNNEL:
+       case SIOCCHGTUNNEL:
+               err = -EPERM;
+               if (!capable(CAP_NET_ADMIN))
+                       goto done;
+
+               err = -EFAULT;
+               if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
+                       goto done;
+
+               err = -EINVAL;
+               if ((p.i_flags|p.o_flags)&(GRE_VERSION|GRE_ROUTING))
+                       goto done;
+
+               if (!(p.i_flags&GRE_KEY))
+                       p.i_key = 0;
+               if (!(p.o_flags&GRE_KEY))
+                       p.o_key = 0;
+
+               ip6gre_tnl_parm_from_user(&p1, &p);
+               t = ip6gre_tunnel_locate(net, &p1, cmd == SIOCADDTUNNEL);
+
+               if (dev != ign->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) {
+                       if (t != NULL) {
+                               if (t->dev != dev) {
+                                       err = -EEXIST;
+                                       break;
+                               }
+                       } else {
+                               t = netdev_priv(dev);
+
+                               ip6gre_tunnel_unlink(ign, t);
+                               synchronize_net();
+                               ip6gre_tnl_change(t, &p1, 1);
+                               ip6gre_tunnel_link(ign, t);
+                               netdev_state_change(dev);
+                       }
+               }
+
+               if (t) {
+                       err = 0;
+
+                       ip6gre_tnl_parm_to_user(&p, &t->parms);
+                       if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
+                               err = -EFAULT;
+               } else
+                       err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT);
+               break;
+
+       case SIOCDELTUNNEL:
+               err = -EPERM;
+               if (!capable(CAP_NET_ADMIN))
+                       goto done;
+
+               if (dev == ign->fb_tunnel_dev) {
+                       err = -EFAULT;
+                       if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p)))
+                               goto done;
+                       err = -ENOENT;
+                       ip6gre_tnl_parm_from_user(&p1, &p);
+                       t = ip6gre_tunnel_locate(net, &p1, 0);
+                       if (t == NULL)
+                               goto done;
+                       err = -EPERM;
+                       if (t == netdev_priv(ign->fb_tunnel_dev))
+                               goto done;
+                       dev = t->dev;
+               }
+               unregister_netdevice(dev);
+               err = 0;
+               break;
+
+       default:
+               err = -EINVAL;
+       }
+
+done:
+       return err;
+}
+
+static int ip6gre_tunnel_change_mtu(struct net_device *dev, int new_mtu)
+{
+       struct ip6_tnl *tunnel = netdev_priv(dev);
+       if (new_mtu < 68 ||
+           new_mtu > 0xFFF8 - dev->hard_header_len - tunnel->hlen)
+               return -EINVAL;
+       dev->mtu = new_mtu;
+       return 0;
+}
+
+static int ip6gre_header(struct sk_buff *skb, struct net_device *dev,
+                       unsigned short type,
+                       const void *daddr, const void *saddr, unsigned int len)
+{
+       struct ip6_tnl *t = netdev_priv(dev);
+       struct ipv6hdr *ipv6h = (struct ipv6hdr *)skb_push(skb, t->hlen);
+       __be16 *p = (__be16 *)(ipv6h+1);
+
+       *(__be32 *)ipv6h = t->fl.u.ip6.flowlabel | htonl(0x60000000);
+       ipv6h->hop_limit = t->parms.hop_limit;
+       ipv6h->nexthdr = NEXTHDR_GRE;
+       ipv6h->saddr = t->parms.laddr;
+       ipv6h->daddr = t->parms.raddr;
+
+       p[0]            = t->parms.o_flags;
+       p[1]            = htons(type);
+
+       /*
+        *      Set the source hardware address.
+        */
+
+       if (saddr)
+               memcpy(&ipv6h->saddr, saddr, sizeof(struct in6_addr));
+       if (daddr)
+               memcpy(&ipv6h->daddr, daddr, sizeof(struct in6_addr));
+       if (!ipv6_addr_any(&ipv6h->daddr))
+               return t->hlen;
+
+       return -t->hlen;
+}
+
+static int ip6gre_header_parse(const struct sk_buff *skb, unsigned char *haddr)
+{
+       const struct ipv6hdr *ipv6h = (const struct ipv6hdr *)skb_mac_header(skb);
+       memcpy(haddr, &ipv6h->saddr, sizeof(struct in6_addr));
+       return sizeof(struct in6_addr);
+}
+
+static const struct header_ops ip6gre_header_ops = {
+       .create = ip6gre_header,
+       .parse  = ip6gre_header_parse,
+};
+
+static const struct net_device_ops ip6gre_netdev_ops = {
+       .ndo_init               = ip6gre_tunnel_init,
+       .ndo_uninit             = ip6gre_tunnel_uninit,
+       .ndo_start_xmit         = ip6gre_tunnel_xmit,
+       .ndo_do_ioctl           = ip6gre_tunnel_ioctl,
+       .ndo_change_mtu         = ip6gre_tunnel_change_mtu,
+       .ndo_get_stats64        = ip6gre_get_stats64,
+};
+
+static void ip6gre_dev_free(struct net_device *dev)
+{
+       free_percpu(dev->tstats);
+       free_netdev(dev);
+}
+
+static void ip6gre_tunnel_setup(struct net_device *dev)
+{
+       struct ip6_tnl *t;
+
+       dev->netdev_ops = &ip6gre_netdev_ops;
+       dev->destructor = ip6gre_dev_free;
+
+       dev->type = ARPHRD_IP6GRE;
+       dev->hard_header_len = LL_MAX_HEADER + sizeof(struct ipv6hdr) + 4;
+       dev->mtu = ETH_DATA_LEN - sizeof(struct ipv6hdr) - 4;
+       t = netdev_priv(dev);
+       if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
+               dev->mtu -= 8;
+       dev->flags |= IFF_NOARP;
+       dev->iflink = 0;
+       dev->addr_len = sizeof(struct in6_addr);
+       dev->features |= NETIF_F_NETNS_LOCAL;
+       dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
+}
+
+static int ip6gre_tunnel_init(struct net_device *dev)
+{
+       struct ip6_tnl *tunnel;
+
+       tunnel = netdev_priv(dev);
+
+       tunnel->dev = dev;
+       strcpy(tunnel->parms.name, dev->name);
+
+       memcpy(dev->dev_addr, &tunnel->parms.laddr, sizeof(struct in6_addr));
+       memcpy(dev->broadcast, &tunnel->parms.raddr, sizeof(struct in6_addr));
+
+       if (ipv6_addr_any(&tunnel->parms.raddr))
+               dev->header_ops = &ip6gre_header_ops;
+
+       dev->tstats = alloc_percpu(struct pcpu_tstats);
+       if (!dev->tstats)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static void ip6gre_fb_tunnel_init(struct net_device *dev)
+{
+       struct ip6_tnl *tunnel = netdev_priv(dev);
+
+       tunnel->dev = dev;
+       strcpy(tunnel->parms.name, dev->name);
+
+       tunnel->hlen            = sizeof(struct ipv6hdr) + 4;
+
+       dev_hold(dev);
+}
+
+
+static struct inet6_protocol ip6gre_protocol __read_mostly = {
+       .handler     = ip6gre_rcv,
+       .err_handler = ip6gre_err,
+       .flags       = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
+};
+
+static void ip6gre_destroy_tunnels(struct ip6gre_net *ign,
+       struct list_head *head)
+{
+       int prio;
+
+       for (prio = 0; prio < 4; prio++) {
+               int h;
+               for (h = 0; h < HASH_SIZE; h++) {
+                       struct ip6_tnl *t;
+
+                       t = rtnl_dereference(ign->tunnels[prio][h]);
+
+                       while (t != NULL) {
+                               unregister_netdevice_queue(t->dev, head);
+                               t = rtnl_dereference(t->next);
+                       }
+               }
+       }
+}
+
+static int __net_init ip6gre_init_net(struct net *net)
+{
+       struct ip6gre_net *ign = net_generic(net, ip6gre_net_id);
+       int err;
+
+       ign->fb_tunnel_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6gre0",
+                                          ip6gre_tunnel_setup);
+       if (!ign->fb_tunnel_dev) {
+               err = -ENOMEM;
+               goto err_alloc_dev;
+       }
+       dev_net_set(ign->fb_tunnel_dev, net);
+
+       ip6gre_fb_tunnel_init(ign->fb_tunnel_dev);
+       ign->fb_tunnel_dev->rtnl_link_ops = &ip6gre_link_ops;
+
+       err = register_netdev(ign->fb_tunnel_dev);
+       if (err)
+               goto err_reg_dev;
+
+       rcu_assign_pointer(ign->tunnels_wc[0],
+                          netdev_priv(ign->fb_tunnel_dev));
+       return 0;
+
+err_reg_dev:
+       ip6gre_dev_free(ign->fb_tunnel_dev);
+err_alloc_dev:
+       return err;
+}
+
+static void __net_exit ip6gre_exit_net(struct net *net)
+{
+       struct ip6gre_net *ign;
+       LIST_HEAD(list);
+
+       ign = net_generic(net, ip6gre_net_id);
+       rtnl_lock();
+       ip6gre_destroy_tunnels(ign, &list);
+       unregister_netdevice_many(&list);
+       rtnl_unlock();
+}
+
+static struct pernet_operations ip6gre_net_ops = {
+       .init = ip6gre_init_net,
+       .exit = ip6gre_exit_net,
+       .id   = &ip6gre_net_id,
+       .size = sizeof(struct ip6gre_net),
+};
+
+static int ip6gre_tunnel_validate(struct nlattr *tb[], struct nlattr *data[])
+{
+       __be16 flags;
+
+       if (!data)
+               return 0;
+
+       flags = 0;
+       if (data[IFLA_GRE_IFLAGS])
+               flags |= nla_get_be16(data[IFLA_GRE_IFLAGS]);
+       if (data[IFLA_GRE_OFLAGS])
+               flags |= nla_get_be16(data[IFLA_GRE_OFLAGS]);
+       if (flags & (GRE_VERSION|GRE_ROUTING))
+               return -EINVAL;
+
+       return 0;
+}
+
+static int ip6gre_tap_validate(struct nlattr *tb[], struct nlattr *data[])
+{
+       struct in6_addr daddr;
+
+       if (tb[IFLA_ADDRESS]) {
+               if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
+                       return -EINVAL;
+               if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
+                       return -EADDRNOTAVAIL;
+       }
+
+       if (!data)
+               goto out;
+
+       if (data[IFLA_GRE_REMOTE]) {
+               nla_memcpy(&daddr, data[IFLA_GRE_REMOTE], sizeof(struct in6_addr));
+               if (ipv6_addr_any(&daddr))
+                       return -EINVAL;
+       }
+
+out:
+       return ip6gre_tunnel_validate(tb, data);
+}
+
+
+static void ip6gre_netlink_parms(struct nlattr *data[],
+                               struct __ip6_tnl_parm *parms)
+{
+       memset(parms, 0, sizeof(*parms));
+
+       if (!data)
+               return;
+
+       if (data[IFLA_GRE_LINK])
+               parms->link = nla_get_u32(data[IFLA_GRE_LINK]);
+
+       if (data[IFLA_GRE_IFLAGS])
+               parms->i_flags = nla_get_be16(data[IFLA_GRE_IFLAGS]);
+
+       if (data[IFLA_GRE_OFLAGS])
+               parms->o_flags = nla_get_be16(data[IFLA_GRE_OFLAGS]);
+
+       if (data[IFLA_GRE_IKEY])
+               parms->i_key = nla_get_be32(data[IFLA_GRE_IKEY]);
+
+       if (data[IFLA_GRE_OKEY])
+               parms->o_key = nla_get_be32(data[IFLA_GRE_OKEY]);
+
+       if (data[IFLA_GRE_LOCAL])
+               nla_memcpy(&parms->laddr, data[IFLA_GRE_LOCAL], sizeof(struct in6_addr));
+
+       if (data[IFLA_GRE_REMOTE])
+               nla_memcpy(&parms->raddr, data[IFLA_GRE_REMOTE], sizeof(struct in6_addr));
+
+       if (data[IFLA_GRE_TTL])
+               parms->hop_limit = nla_get_u8(data[IFLA_GRE_TTL]);
+
+       if (data[IFLA_GRE_ENCAP_LIMIT])
+               parms->encap_limit = nla_get_u8(data[IFLA_GRE_ENCAP_LIMIT]);
+
+       if (data[IFLA_GRE_FLOWINFO])
+               parms->flowinfo = nla_get_u32(data[IFLA_GRE_FLOWINFO]);
+
+       if (data[IFLA_GRE_FLAGS])
+               parms->flags = nla_get_u32(data[IFLA_GRE_FLAGS]);
+}
+
+static int ip6gre_tap_init(struct net_device *dev)
+{
+       struct ip6_tnl *tunnel;
+
+       tunnel = netdev_priv(dev);
+
+       tunnel->dev = dev;
+       strcpy(tunnel->parms.name, dev->name);
+
+       ip6gre_tnl_link_config(tunnel, 1);
+
+       dev->tstats = alloc_percpu(struct pcpu_tstats);
+       if (!dev->tstats)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static const struct net_device_ops ip6gre_tap_netdev_ops = {
+       .ndo_init = ip6gre_tap_init,
+       .ndo_uninit = ip6gre_tunnel_uninit,
+       .ndo_start_xmit = ip6gre_tunnel_xmit,
+       .ndo_set_mac_address = eth_mac_addr,
+       .ndo_validate_addr = eth_validate_addr,
+       .ndo_change_mtu = ip6gre_tunnel_change_mtu,
+       .ndo_get_stats64 = ip6gre_get_stats64,
+};
+
+static void ip6gre_tap_setup(struct net_device *dev)
+{
+
+       ether_setup(dev);
+
+       dev->netdev_ops = &ip6gre_tap_netdev_ops;
+       dev->destructor = ip6gre_dev_free;
+
+       dev->iflink = 0;
+       dev->features |= NETIF_F_NETNS_LOCAL;
+}
+
+static int ip6gre_newlink(struct net *src_net, struct net_device *dev,
+       struct nlattr *tb[], struct nlattr *data[])
+{
+       struct ip6_tnl *nt;
+       struct net *net = dev_net(dev);
+       struct ip6gre_net *ign = net_generic(net, ip6gre_net_id);
+       int err;
+
+       nt = netdev_priv(dev);
+       ip6gre_netlink_parms(data, &nt->parms);
+
+       if (ip6gre_tunnel_find(net, &nt->parms, dev->type))
+               return -EEXIST;
+
+       if (dev->type == ARPHRD_ETHER && !tb[IFLA_ADDRESS])
+               eth_hw_addr_random(dev);
+
+       nt->dev = dev;
+       ip6gre_tnl_link_config(nt, !tb[IFLA_MTU]);
+
+       /* Can use a lockless transmit, unless we generate output sequences */
+       if (!(nt->parms.o_flags & GRE_SEQ))
+               dev->features |= NETIF_F_LLTX;
+
+       err = register_netdevice(dev);
+       if (err)
+               goto out;
+
+       dev_hold(dev);
+       ip6gre_tunnel_link(ign, nt);
+
+out:
+       return err;
+}
+
+static int ip6gre_changelink(struct net_device *dev, struct nlattr *tb[],
+                           struct nlattr *data[])
+{
+       struct ip6_tnl *t, *nt;
+       struct net *net = dev_net(dev);
+       struct ip6gre_net *ign = net_generic(net, ip6gre_net_id);
+       struct __ip6_tnl_parm p;
+
+       if (dev == ign->fb_tunnel_dev)
+               return -EINVAL;
+
+       nt = netdev_priv(dev);
+       ip6gre_netlink_parms(data, &p);
+
+       t = ip6gre_tunnel_locate(net, &p, 0);
+
+       if (t) {
+               if (t->dev != dev)
+                       return -EEXIST;
+       } else {
+               t = nt;
+
+               ip6gre_tunnel_unlink(ign, t);
+               ip6gre_tnl_change(t, &p, !tb[IFLA_MTU]);
+               ip6gre_tunnel_link(ign, t);
+               netdev_state_change(dev);
+       }
+
+       return 0;
+}
+
+static size_t ip6gre_get_size(const struct net_device *dev)
+{
+       return
+               /* IFLA_GRE_LINK */
+               nla_total_size(4) +
+               /* IFLA_GRE_IFLAGS */
+               nla_total_size(2) +
+               /* IFLA_GRE_OFLAGS */
+               nla_total_size(2) +
+               /* IFLA_GRE_IKEY */
+               nla_total_size(4) +
+               /* IFLA_GRE_OKEY */
+               nla_total_size(4) +
+               /* IFLA_GRE_LOCAL */
+               nla_total_size(4) +
+               /* IFLA_GRE_REMOTE */
+               nla_total_size(4) +
+               /* IFLA_GRE_TTL */
+               nla_total_size(1) +
+               /* IFLA_GRE_TOS */
+               nla_total_size(1) +
+               /* IFLA_GRE_ENCAP_LIMIT */
+               nla_total_size(1) +
+               /* IFLA_GRE_FLOWINFO */
+               nla_total_size(4) +
+               /* IFLA_GRE_FLAGS */
+               nla_total_size(4) +
+               0;
+}
+
+static int ip6gre_fill_info(struct sk_buff *skb, const struct net_device *dev)
+{
+       struct ip6_tnl *t = netdev_priv(dev);
+       struct __ip6_tnl_parm *p = &t->parms;
+
+       if (nla_put_u32(skb, IFLA_GRE_LINK, p->link) ||
+           nla_put_be16(skb, IFLA_GRE_IFLAGS, p->i_flags) ||
+           nla_put_be16(skb, IFLA_GRE_OFLAGS, p->o_flags) ||
+           nla_put_be32(skb, IFLA_GRE_IKEY, p->i_key) ||
+           nla_put_be32(skb, IFLA_GRE_OKEY, p->o_key) ||
+           nla_put(skb, IFLA_GRE_LOCAL, sizeof(struct in6_addr), &p->raddr) ||
+           nla_put(skb, IFLA_GRE_REMOTE, sizeof(struct in6_addr), &p->laddr) ||
+           nla_put_u8(skb, IFLA_GRE_TTL, p->hop_limit) ||
+           /*nla_put_u8(skb, IFLA_GRE_TOS, t->priority) ||*/
+           nla_put_u8(skb, IFLA_GRE_ENCAP_LIMIT, p->encap_limit) ||
+           nla_put_be32(skb, IFLA_GRE_FLOWINFO, p->flowinfo) ||
+           nla_put_u32(skb, IFLA_GRE_FLAGS, p->flags))
+               goto nla_put_failure;
+       return 0;
+
+nla_put_failure:
+       return -EMSGSIZE;
+}
+
+static const struct nla_policy ip6gre_policy[IFLA_GRE_MAX + 1] = {
+       [IFLA_GRE_LINK]        = { .type = NLA_U32 },
+       [IFLA_GRE_IFLAGS]      = { .type = NLA_U16 },
+       [IFLA_GRE_OFLAGS]      = { .type = NLA_U16 },
+       [IFLA_GRE_IKEY]        = { .type = NLA_U32 },
+       [IFLA_GRE_OKEY]        = { .type = NLA_U32 },
+       [IFLA_GRE_LOCAL]       = { .len = FIELD_SIZEOF(struct ipv6hdr, saddr) },
+       [IFLA_GRE_REMOTE]      = { .len = FIELD_SIZEOF(struct ipv6hdr, daddr) },
+       [IFLA_GRE_TTL]         = { .type = NLA_U8 },
+       [IFLA_GRE_ENCAP_LIMIT] = { .type = NLA_U8 },
+       [IFLA_GRE_FLOWINFO]    = { .type = NLA_U32 },
+       [IFLA_GRE_FLAGS]       = { .type = NLA_U32 },
+};
+
+static struct rtnl_link_ops ip6gre_link_ops __read_mostly = {
+       .kind           = "ip6gre",
+       .maxtype        = IFLA_GRE_MAX,
+       .policy         = ip6gre_policy,
+       .priv_size      = sizeof(struct ip6_tnl),
+       .setup          = ip6gre_tunnel_setup,
+       .validate       = ip6gre_tunnel_validate,
+       .newlink        = ip6gre_newlink,
+       .changelink     = ip6gre_changelink,
+       .get_size       = ip6gre_get_size,
+       .fill_info      = ip6gre_fill_info,
+};
+
+static struct rtnl_link_ops ip6gre_tap_ops __read_mostly = {
+       .kind           = "ip6gretap",
+       .maxtype        = IFLA_GRE_MAX,
+       .policy         = ip6gre_policy,
+       .priv_size      = sizeof(struct ip6_tnl),
+       .setup          = ip6gre_tap_setup,
+       .validate       = ip6gre_tap_validate,
+       .newlink        = ip6gre_newlink,
+       .changelink     = ip6gre_changelink,
+       .get_size       = ip6gre_get_size,
+       .fill_info      = ip6gre_fill_info,
+};
+
+/*
+ *     And now the modules code and kernel interface.
+ */
+
+static int __init ip6gre_init(void)
+{
+       int err;
+
+       pr_info("GRE over IPv6 tunneling driver\n");
+
+       err = register_pernet_device(&ip6gre_net_ops);
+       if (err < 0)
+               return err;
+
+       err = inet6_add_protocol(&ip6gre_protocol, IPPROTO_GRE);
+       if (err < 0) {
+               pr_info("%s: can't add protocol\n", __func__);
+               goto add_proto_failed;
+       }
+
+       err = rtnl_link_register(&ip6gre_link_ops);
+       if (err < 0)
+               goto rtnl_link_failed;
+
+       err = rtnl_link_register(&ip6gre_tap_ops);
+       if (err < 0)
+               goto tap_ops_failed;
+
+out:
+       return err;
+
+tap_ops_failed:
+       rtnl_link_unregister(&ip6gre_link_ops);
+rtnl_link_failed:
+       inet6_del_protocol(&ip6gre_protocol, IPPROTO_GRE);
+add_proto_failed:
+       unregister_pernet_device(&ip6gre_net_ops);
+       goto out;
+}
+
+static void __exit ip6gre_fini(void)
+{
+       rtnl_link_unregister(&ip6gre_tap_ops);
+       rtnl_link_unregister(&ip6gre_link_ops);
+       inet6_del_protocol(&ip6gre_protocol, IPPROTO_GRE);
+       unregister_pernet_device(&ip6gre_net_ops);
+}
+
+module_init(ip6gre_init);
+module_exit(ip6gre_fini);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)");
+MODULE_DESCRIPTION("GRE over IPv6 tunneling device");
+MODULE_ALIAS_RTNL_LINK("ip6gre");
+MODULE_ALIAS_NETDEV("ip6gre0");
index 9a1d5fe6aef8f229e22c8b2e8f3cef1663be09ce..33d2a0e6712de084077727298d9e2353f39eb9c0 100644 (file)
@@ -126,7 +126,7 @@ static struct net_device_stats *ip6_get_stats(struct net_device *dev)
  * Locking : hash tables are protected by RCU and RTNL
  */
 
-static inline struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t)
+struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t)
 {
        struct dst_entry *dst = t->dst_cache;
 
@@ -139,20 +139,23 @@ static inline struct dst_entry *ip6_tnl_dst_check(struct ip6_tnl *t)
 
        return dst;
 }
+EXPORT_SYMBOL_GPL(ip6_tnl_dst_check);
 
-static inline void ip6_tnl_dst_reset(struct ip6_tnl *t)
+void ip6_tnl_dst_reset(struct ip6_tnl *t)
 {
        dst_release(t->dst_cache);
        t->dst_cache = NULL;
 }
+EXPORT_SYMBOL_GPL(ip6_tnl_dst_reset);
 
-static inline void ip6_tnl_dst_store(struct ip6_tnl *t, struct dst_entry *dst)
+void ip6_tnl_dst_store(struct ip6_tnl *t, struct dst_entry *dst)
 {
        struct rt6_info *rt = (struct rt6_info *) dst;
        t->dst_cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0;
        dst_release(t->dst_cache);
        t->dst_cache = dst;
 }
+EXPORT_SYMBOL_GPL(ip6_tnl_dst_store);
 
 /**
  * ip6_tnl_lookup - fetch tunnel matching the end-point addresses
@@ -200,7 +203,7 @@ ip6_tnl_lookup(struct net *net, const struct in6_addr *remote, const struct in6_
  **/
 
 static struct ip6_tnl __rcu **
-ip6_tnl_bucket(struct ip6_tnl_net *ip6n, const struct ip6_tnl_parm *p)
+ip6_tnl_bucket(struct ip6_tnl_net *ip6n, const struct __ip6_tnl_parm *p)
 {
        const struct in6_addr *remote = &p->raddr;
        const struct in6_addr *local = &p->laddr;
@@ -267,7 +270,7 @@ static void ip6_dev_free(struct net_device *dev)
  *   created tunnel or NULL
  **/
 
-static struct ip6_tnl *ip6_tnl_create(struct net *net, struct ip6_tnl_parm *p)
+static struct ip6_tnl *ip6_tnl_create(struct net *net, struct __ip6_tnl_parm *p)
 {
        struct net_device *dev;
        struct ip6_tnl *t;
@@ -322,7 +325,7 @@ failed:
  **/
 
 static struct ip6_tnl *ip6_tnl_locate(struct net *net,
-               struct ip6_tnl_parm *p, int create)
+               struct __ip6_tnl_parm *p, int create)
 {
        const struct in6_addr *remote = &p->raddr;
        const struct in6_addr *local = &p->laddr;
@@ -374,8 +377,7 @@ ip6_tnl_dev_uninit(struct net_device *dev)
  *   else index to encapsulation limit
  **/
 
-static __u16
-parse_tlv_tnl_enc_lim(struct sk_buff *skb, __u8 * raw)
+__u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw)
 {
        const struct ipv6hdr *ipv6h = (const struct ipv6hdr *) raw;
        __u8 nexthdr = ipv6h->nexthdr;
@@ -425,6 +427,7 @@ parse_tlv_tnl_enc_lim(struct sk_buff *skb, __u8 * raw)
        }
        return 0;
 }
+EXPORT_SYMBOL(ip6_tnl_parse_tlv_enc_lim);
 
 /**
  * ip6_tnl_err - tunnel error handler
@@ -480,7 +483,7 @@ ip6_tnl_err(struct sk_buff *skb, __u8 ipproto, struct inet6_skb_parm *opt,
        case ICMPV6_PARAMPROB:
                teli = 0;
                if ((*code) == ICMPV6_HDR_FIELD)
-                       teli = parse_tlv_tnl_enc_lim(skb, skb->data);
+                       teli = ip6_tnl_parse_tlv_enc_lim(skb, skb->data);
 
                if (teli && teli == *info - 2) {
                        tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->data[teli];
@@ -693,11 +696,11 @@ static void ip6ip6_dscp_ecn_decapsulate(const struct ip6_tnl *t,
                IP6_ECN_set_ce(ipv6_hdr(skb));
 }
 
-static __u32 ip6_tnl_get_cap(struct ip6_tnl *t,
+__u32 ip6_tnl_get_cap(struct ip6_tnl *t,
                             const struct in6_addr *laddr,
                             const struct in6_addr *raddr)
 {
-       struct ip6_tnl_parm *p = &t->parms;
+       struct __ip6_tnl_parm *p = &t->parms;
        int ltype = ipv6_addr_type(laddr);
        int rtype = ipv6_addr_type(raddr);
        __u32 flags = 0;
@@ -715,13 +718,14 @@ static __u32 ip6_tnl_get_cap(struct ip6_tnl *t,
        }
        return flags;
 }
+EXPORT_SYMBOL(ip6_tnl_get_cap);
 
 /* called with rcu_read_lock() */
-static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t,
+int ip6_tnl_rcv_ctl(struct ip6_tnl *t,
                                  const struct in6_addr *laddr,
                                  const struct in6_addr *raddr)
 {
-       struct ip6_tnl_parm *p = &t->parms;
+       struct __ip6_tnl_parm *p = &t->parms;
        int ret = 0;
        struct net *net = dev_net(t->dev);
 
@@ -740,6 +744,7 @@ static inline int ip6_tnl_rcv_ctl(struct ip6_tnl *t,
        }
        return ret;
 }
+EXPORT_SYMBOL_GPL(ip6_tnl_rcv_ctl);
 
 /**
  * ip6_tnl_rcv - decapsulate IPv6 packet and retransmit it locally
@@ -859,9 +864,9 @@ ip6_tnl_addr_conflict(const struct ip6_tnl *t, const struct ipv6hdr *hdr)
        return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr);
 }
 
-static inline int ip6_tnl_xmit_ctl(struct ip6_tnl *t)
+int ip6_tnl_xmit_ctl(struct ip6_tnl *t)
 {
-       struct ip6_tnl_parm *p = &t->parms;
+       struct __ip6_tnl_parm *p = &t->parms;
        int ret = 0;
        struct net *net = dev_net(t->dev);
 
@@ -885,6 +890,8 @@ static inline int ip6_tnl_xmit_ctl(struct ip6_tnl *t)
        }
        return ret;
 }
+EXPORT_SYMBOL_GPL(ip6_tnl_xmit_ctl);
+
 /**
  * ip6_tnl_xmit2 - encapsulate packet and send
  *   @skb: the outgoing socket buffer
@@ -1085,7 +1092,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
            !ip6_tnl_xmit_ctl(t) || ip6_tnl_addr_conflict(t, ipv6h))
                return -1;
 
-       offset = parse_tlv_tnl_enc_lim(skb, skb_network_header(skb));
+       offset = ip6_tnl_parse_tlv_enc_lim(skb, skb_network_header(skb));
        if (offset > 0) {
                struct ipv6_tlv_tnl_enc_lim *tel;
                tel = (struct ipv6_tlv_tnl_enc_lim *)&skb_network_header(skb)[offset];
@@ -1152,7 +1159,7 @@ tx_err:
 static void ip6_tnl_link_config(struct ip6_tnl *t)
 {
        struct net_device *dev = t->dev;
-       struct ip6_tnl_parm *p = &t->parms;
+       struct __ip6_tnl_parm *p = &t->parms;
        struct flowi6 *fl6 = &t->fl.u.ip6;
 
        memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr));
@@ -1215,7 +1222,7 @@ static void ip6_tnl_link_config(struct ip6_tnl *t)
  **/
 
 static int
-ip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p)
+ip6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p)
 {
        t->parms.laddr = p->laddr;
        t->parms.raddr = p->raddr;
@@ -1230,6 +1237,34 @@ ip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p)
        return 0;
 }
 
+static void
+ip6_tnl_parm_from_user(struct __ip6_tnl_parm *p, const struct ip6_tnl_parm *u)
+{
+       p->laddr = u->laddr;
+       p->raddr = u->raddr;
+       p->flags = u->flags;
+       p->hop_limit = u->hop_limit;
+       p->encap_limit = u->encap_limit;
+       p->flowinfo = u->flowinfo;
+       p->link = u->link;
+       p->proto = u->proto;
+       memcpy(p->name, u->name, sizeof(u->name));
+}
+
+static void
+ip6_tnl_parm_to_user(struct ip6_tnl_parm *u, const struct __ip6_tnl_parm *p)
+{
+       u->laddr = p->laddr;
+       u->raddr = p->raddr;
+       u->flags = p->flags;
+       u->hop_limit = p->hop_limit;
+       u->encap_limit = p->encap_limit;
+       u->flowinfo = p->flowinfo;
+       u->link = p->link;
+       u->proto = p->proto;
+       memcpy(u->name, p->name, sizeof(u->name));
+}
+
 /**
  * ip6_tnl_ioctl - configure ipv6 tunnels from userspace
  *   @dev: virtual device associated with tunnel
@@ -1263,6 +1298,7 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
        int err = 0;
        struct ip6_tnl_parm p;
+       struct __ip6_tnl_parm p1;
        struct ip6_tnl *t = NULL;
        struct net *net = dev_net(dev);
        struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
@@ -1274,11 +1310,12 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                                err = -EFAULT;
                                break;
                        }
-                       t = ip6_tnl_locate(net, &p, 0);
+                       ip6_tnl_parm_from_user(&p1, &p);
+                       t = ip6_tnl_locate(net, &p1, 0);
                }
                if (t == NULL)
                        t = netdev_priv(dev);
-               memcpy(&p, &t->parms, sizeof (p));
+               ip6_tnl_parm_to_user(&p, &t->parms);
                if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof (p))) {
                        err = -EFAULT;
                }
@@ -1295,7 +1332,8 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                if (p.proto != IPPROTO_IPV6 && p.proto != IPPROTO_IPIP &&
                    p.proto != 0)
                        break;
-               t = ip6_tnl_locate(net, &p, cmd == SIOCADDTUNNEL);
+               ip6_tnl_parm_from_user(&p1, &p);
+               t = ip6_tnl_locate(net, &p1, cmd == SIOCADDTUNNEL);
                if (dev != ip6n->fb_tnl_dev && cmd == SIOCCHGTUNNEL) {
                        if (t != NULL) {
                                if (t->dev != dev) {
@@ -1307,13 +1345,14 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 
                        ip6_tnl_unlink(ip6n, t);
                        synchronize_net();
-                       err = ip6_tnl_change(t, &p);
+                       err = ip6_tnl_change(t, &p1);
                        ip6_tnl_link(ip6n, t);
                        netdev_state_change(dev);
                }
                if (t) {
                        err = 0;
-                       if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof (p)))
+                       ip6_tnl_parm_to_user(&p, &t->parms);
+                       if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p)))
                                err = -EFAULT;
 
                } else
@@ -1329,7 +1368,9 @@ ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                        if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p)))
                                break;
                        err = -ENOENT;
-                       if ((t = ip6_tnl_locate(net, &p, 0)) == NULL)
+                       ip6_tnl_parm_from_user(&p1, &p);
+                       t = ip6_tnl_locate(net, &p1, 0);
+                       if (t == NULL)
                                break;
                        err = -EPERM;
                        if (t->dev == ip6n->fb_tnl_dev)
index da2e92d05c15a5052ea2cc19ba9bfc5751c23cf6..745a32042950127f3509781b6247b6434743d1d7 100644 (file)
@@ -307,10 +307,10 @@ static int __net_init ipv6_proc_init_net(struct net *net)
                goto proc_dev_snmp6_fail;
        return 0;
 
+proc_dev_snmp6_fail:
+       proc_net_remove(net, "snmp6");
 proc_snmp6_fail:
        proc_net_remove(net, "sockstat6");
-proc_dev_snmp6_fail:
-       proc_net_remove(net, "dev_snmp6");
        return -ENOMEM;
 }
 
index 8e80fd279100d7d18d111eff1be73f10fdd6eeaf..0ddf2d132e7f0840bcf327d4d0149fe2136fe943 100644 (file)
@@ -965,7 +965,7 @@ struct dst_entry * ip6_route_output(struct net *net, const struct sock *sk,
 {
        int flags = 0;
 
-       fl6->flowi6_iif = net->loopback_dev->ifindex;
+       fl6->flowi6_iif = LOOPBACK_IFINDEX;
 
        if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr))
                flags |= RT6_LOOKUP_F_IFACE;
index c66b90f71c9b9610b5dec49c038b80dffd836058..94987b8fc0fdecdaa0c41fd53ad08f0bcfe10590 100644 (file)
@@ -1447,7 +1447,17 @@ static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb)
                opt_skb = skb_clone(skb, sk_gfp_atomic(sk, GFP_ATOMIC));
 
        if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */
+               struct dst_entry *dst = sk->sk_rx_dst;
+
                sock_rps_save_rxhash(sk, skb);
+               if (dst) {
+                       if (inet_sk(sk)->rx_dst_ifindex != skb->skb_iif ||
+                           dst->ops->check(dst, np->rx_dst_cookie) == NULL) {
+                               dst_release(dst);
+                               sk->sk_rx_dst = NULL;
+                       }
+               }
+
                if (tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len))
                        goto reset;
                if (opt_skb)
@@ -1705,9 +1715,9 @@ static void tcp_v6_early_demux(struct sk_buff *skb)
                        struct dst_entry *dst = sk->sk_rx_dst;
                        struct inet_sock *icsk = inet_sk(sk);
                        if (dst)
-                               dst = dst_check(dst, 0);
+                               dst = dst_check(dst, inet6_sk(sk)->rx_dst_cookie);
                        if (dst &&
-                           icsk->rx_dst_ifindex == inet6_iif(skb))
+                           icsk->rx_dst_ifindex == skb->skb_iif)
                                skb_dst_set_noref(skb, dst);
                }
        }
@@ -1719,10 +1729,23 @@ static struct timewait_sock_ops tcp6_timewait_sock_ops = {
        .twsk_destructor= tcp_twsk_destructor,
 };
 
+static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
+{
+       struct dst_entry *dst = skb_dst(skb);
+       const struct rt6_info *rt = (const struct rt6_info *)dst;
+
+       dst_hold(dst);
+       sk->sk_rx_dst = dst;
+       inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
+       if (rt->rt6i_node)
+               inet6_sk(sk)->rx_dst_cookie = rt->rt6i_node->fn_sernum;
+}
+
 static const struct inet_connection_sock_af_ops ipv6_specific = {
        .queue_xmit        = inet6_csk_xmit,
        .send_check        = tcp_v6_send_check,
        .rebuild_header    = inet6_sk_rebuild_header,
+       .sk_rx_dst_set     = inet6_sk_rx_dst_set,
        .conn_request      = tcp_v6_conn_request,
        .syn_recv_sock     = tcp_v6_syn_recv_sock,
        .net_header_len    = sizeof(struct ipv6hdr),
@@ -1754,6 +1777,7 @@ static const struct inet_connection_sock_af_ops ipv6_mapped = {
        .queue_xmit        = ip_queue_xmit,
        .send_check        = tcp_v4_send_check,
        .rebuild_header    = inet_sk_rebuild_header,
+       .sk_rx_dst_set     = inet_sk_rx_dst_set,
        .conn_request      = tcp_v6_conn_request,
        .syn_recv_sock     = tcp_v6_syn_recv_sock,
        .net_header_len    = sizeof(struct iphdr),
@@ -1875,7 +1899,7 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
                   tp->write_seq-tp->snd_una,
                   (sp->sk_state == TCP_LISTEN) ? sp->sk_ack_backlog : (tp->rcv_nxt - tp->copied_seq),
                   timer_active,
-                  jiffies_to_clock_t(timer_expires - jiffies),
+                  jiffies_delta_to_clock_t(timer_expires - jiffies),
                   icsk->icsk_retransmits,
                   sock_i_uid(sp),
                   icsk->icsk_probes_out,
@@ -1895,10 +1919,7 @@ static void get_timewait6_sock(struct seq_file *seq,
        const struct in6_addr *dest, *src;
        __u16 destp, srcp;
        const struct inet6_timewait_sock *tw6 = inet6_twsk((struct sock *)tw);
-       int ttd = tw->tw_ttd - jiffies;
-
-       if (ttd < 0)
-               ttd = 0;
+       long delta = tw->tw_ttd - jiffies;
 
        dest = &tw6->tw_v6_daddr;
        src  = &tw6->tw_v6_rcv_saddr;
@@ -1914,7 +1935,7 @@ static void get_timewait6_sock(struct seq_file *seq,
                   dest->s6_addr32[0], dest->s6_addr32[1],
                   dest->s6_addr32[2], dest->s6_addr32[3], destp,
                   tw->tw_substate, 0, 0,
-                  3, jiffies_to_clock_t(ttd), 0, 0, 0, 0,
+                  3, jiffies_delta_to_clock_t(delta), 0, 0, 0, 0,
                   atomic_read(&tw->tw_refcnt), tw);
 }
 
index 8b915f3ac3b91a6b2471149799117d8bdd5b8b00..30893912835926a2bbc83ce716a1fdbf242c81a4 100644 (file)
@@ -99,7 +99,6 @@ pi_param_info_t ircomm_param_info = { pi_major_call_table, 3, 0x0f, 4 };
  */
 int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush)
 {
-       struct tty_struct *tty;
        unsigned long flags;
        struct sk_buff *skb;
        int count;
@@ -109,10 +108,6 @@ int ircomm_param_request(struct ircomm_tty_cb *self, __u8 pi, int flush)
        IRDA_ASSERT(self != NULL, return -1;);
        IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 
-       tty = self->tty;
-       if (!tty)
-               return 0;
-
        /* Make sure we don't send parameters for raw mode */
        if (self->service_type == IRCOMM_3_WIRE_RAW)
                return 0;
index 6b9d5a0e42f9fb3753e32c0b167e202657b372b3..96689906b93c02022abbe097e866296a28beac0a 100644 (file)
@@ -52,6 +52,8 @@
 #include <net/irda/ircomm_tty_attach.h>
 #include <net/irda/ircomm_tty.h>
 
+static int ircomm_tty_install(struct tty_driver *driver,
+               struct tty_struct *tty);
 static int  ircomm_tty_open(struct tty_struct *tty, struct file *filp);
 static void ircomm_tty_close(struct tty_struct * tty, struct file *filp);
 static int  ircomm_tty_write(struct tty_struct * tty,
@@ -82,6 +84,7 @@ static struct tty_driver *driver;
 static hashbin_t *ircomm_tty = NULL;
 
 static const struct tty_operations ops = {
+       .install         = ircomm_tty_install,
        .open            = ircomm_tty_open,
        .close           = ircomm_tty_close,
        .write           = ircomm_tty_write,
@@ -104,6 +107,35 @@ static const struct tty_operations ops = {
 #endif /* CONFIG_PROC_FS */
 };
 
+static void ircomm_port_raise_dtr_rts(struct tty_port *port, int raise)
+{
+       struct ircomm_tty_cb *self = container_of(port, struct ircomm_tty_cb,
+                       port);
+       /*
+        * Here, we use to lock those two guys, but as ircomm_param_request()
+        * does it itself, I don't see the point (and I see the deadlock).
+        * Jean II
+        */
+       if (raise)
+               self->settings.dte |= IRCOMM_RTS | IRCOMM_DTR;
+       else
+               self->settings.dte &= ~(IRCOMM_RTS | IRCOMM_DTR);
+
+       ircomm_param_request(self, IRCOMM_DTE, TRUE);
+}
+
+static int ircomm_port_carrier_raised(struct tty_port *port)
+{
+       struct ircomm_tty_cb *self = container_of(port, struct ircomm_tty_cb,
+                       port);
+       return self->settings.dce & IRCOMM_CD;
+}
+
+static const struct tty_port_operations ircomm_port_ops = {
+       .dtr_rts = ircomm_port_raise_dtr_rts,
+       .carrier_raised = ircomm_port_carrier_raised,
+};
+
 /*
  * Function ircomm_tty_init()
  *
@@ -194,7 +226,7 @@ static int ircomm_tty_startup(struct ircomm_tty_cb *self)
        IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
 
        /* Check if already open */
-       if (test_and_set_bit(ASYNC_B_INITIALIZED, &self->flags)) {
+       if (test_and_set_bit(ASYNCB_INITIALIZED, &self->port.flags)) {
                IRDA_DEBUG(2, "%s(), already open so break out!\n", __func__ );
                return 0;
        }
@@ -231,7 +263,7 @@ static int ircomm_tty_startup(struct ircomm_tty_cb *self)
 
        return 0;
 err:
-       clear_bit(ASYNC_B_INITIALIZED, &self->flags);
+       clear_bit(ASYNCB_INITIALIZED, &self->port.flags);
        return ret;
 }
 
@@ -242,72 +274,62 @@ err:
  *
  */
 static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self,
-                                     struct file *filp)
+               struct tty_struct *tty, struct file *filp)
 {
+       struct tty_port *port = &self->port;
        DECLARE_WAITQUEUE(wait, current);
        int             retval;
        int             do_clocal = 0, extra_count = 0;
        unsigned long   flags;
-       struct tty_struct *tty;
 
        IRDA_DEBUG(2, "%s()\n", __func__ );
 
-       tty = self->tty;
-
        /*
         * If non-blocking mode is set, or the port is not enabled,
         * then make the check up front and then exit.
         */
        if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){
                /* nonblock mode is set or port is not enabled */
-               self->flags |= ASYNC_NORMAL_ACTIVE;
+               port->flags |= ASYNC_NORMAL_ACTIVE;
                IRDA_DEBUG(1, "%s(), O_NONBLOCK requested!\n", __func__ );
                return 0;
        }
 
-       if (tty->termios->c_cflag & CLOCAL) {
+       if (tty->termios.c_cflag & CLOCAL) {
                IRDA_DEBUG(1, "%s(), doing CLOCAL!\n", __func__ );
                do_clocal = 1;
        }
 
        /* Wait for carrier detect and the line to become
         * free (i.e., not in use by the callout).  While we are in
-        * this loop, self->open_count is dropped by one, so that
+        * this loop, port->count is dropped by one, so that
         * mgsl_close() knows when to free things.  We restore it upon
         * exit, either normal or abnormal.
         */
 
        retval = 0;
-       add_wait_queue(&self->open_wait, &wait);
+       add_wait_queue(&port->open_wait, &wait);
 
        IRDA_DEBUG(2, "%s(%d):block_til_ready before block on %s open_count=%d\n",
-             __FILE__,__LINE__, tty->driver->name, self->open_count );
+             __FILE__, __LINE__, tty->driver->name, port->count);
 
-       /* As far as I can see, we protect open_count - Jean II */
-       spin_lock_irqsave(&self->spinlock, flags);
+       spin_lock_irqsave(&port->lock, flags);
        if (!tty_hung_up_p(filp)) {
                extra_count = 1;
-               self->open_count--;
+               port->count--;
        }
-       spin_unlock_irqrestore(&self->spinlock, flags);
-       self->blocked_open++;
+       spin_unlock_irqrestore(&port->lock, flags);
+       port->blocked_open++;
 
        while (1) {
-               if (tty->termios->c_cflag & CBAUD) {
-                       /* Here, we use to lock those two guys, but
-                        * as ircomm_param_request() does it itself,
-                        * I don't see the point (and I see the deadlock).
-                        * Jean II */
-                       self->settings.dte |= IRCOMM_RTS + IRCOMM_DTR;
-
-                       ircomm_param_request(self, IRCOMM_DTE, TRUE);
-               }
+               if (tty->termios.c_cflag & CBAUD)
+                       tty_port_raise_dtr_rts(port);
 
                current->state = TASK_INTERRUPTIBLE;
 
                if (tty_hung_up_p(filp) ||
-                   !test_bit(ASYNC_B_INITIALIZED, &self->flags)) {
-                       retval = (self->flags & ASYNC_HUP_NOTIFY) ?
+                   !test_bit(ASYNCB_INITIALIZED, &port->flags)) {
+                       retval = (port->flags & ASYNC_HUP_NOTIFY) ?
                                        -EAGAIN : -ERESTARTSYS;
                        break;
                }
@@ -317,8 +339,8 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self,
                 * specified, we cannot return before the IrCOMM link is
                 * ready
                 */
-               if (!test_bit(ASYNC_B_CLOSING, &self->flags) &&
-                   (do_clocal || (self->settings.dce & IRCOMM_CD)) &&
+               if (!test_bit(ASYNCB_CLOSING, &port->flags) &&
+                   (do_clocal || tty_port_carrier_raised(port)) &&
                    self->state == IRCOMM_TTY_READY)
                {
                        break;
@@ -330,46 +352,36 @@ static int ircomm_tty_block_til_ready(struct ircomm_tty_cb *self,
                }
 
                IRDA_DEBUG(1, "%s(%d):block_til_ready blocking on %s open_count=%d\n",
-                     __FILE__,__LINE__, tty->driver->name, self->open_count );
+                     __FILE__, __LINE__, tty->driver->name, port->count);
 
                schedule();
        }
 
        __set_current_state(TASK_RUNNING);
-       remove_wait_queue(&self->open_wait, &wait);
+       remove_wait_queue(&port->open_wait, &wait);
 
        if (extra_count) {
                /* ++ is not atomic, so this should be protected - Jean II */
-               spin_lock_irqsave(&self->spinlock, flags);
-               self->open_count++;
-               spin_unlock_irqrestore(&self->spinlock, flags);
+               spin_lock_irqsave(&port->lock, flags);
+               port->count++;
+               spin_unlock_irqrestore(&port->lock, flags);
        }
-       self->blocked_open--;
+       port->blocked_open--;
 
        IRDA_DEBUG(1, "%s(%d):block_til_ready after blocking on %s open_count=%d\n",
-             __FILE__,__LINE__, tty->driver->name, self->open_count);
+             __FILE__, __LINE__, tty->driver->name, port->count);
 
        if (!retval)
-               self->flags |= ASYNC_NORMAL_ACTIVE;
+               port->flags |= ASYNC_NORMAL_ACTIVE;
 
        return retval;
 }
 
-/*
- * Function ircomm_tty_open (tty, filp)
- *
- *    This routine is called when a particular tty device is opened. This
- *    routine is mandatory; if this routine is not filled in, the attempted
- *    open will fail with ENODEV.
- */
-static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
+
+static int ircomm_tty_install(struct tty_driver *driver, struct tty_struct *tty)
 {
        struct ircomm_tty_cb *self;
        unsigned int line = tty->index;
-       unsigned long   flags;
-       int ret;
-
-       IRDA_DEBUG(2, "%s()\n", __func__ );
 
        /* Check if instance already exists */
        self = hashbin_lock_find(ircomm_tty, line, NULL);
@@ -381,6 +393,8 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
                        return -ENOMEM;
                }
 
+               tty_port_init(&self->port);
+               self->port.ops = &ircomm_port_ops;
                self->magic = IRCOMM_TTY_MAGIC;
                self->flow = FLOW_STOP;
 
@@ -388,13 +402,9 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
                INIT_WORK(&self->tqueue, ircomm_tty_do_softint);
                self->max_header_size = IRCOMM_TTY_HDR_UNINITIALISED;
                self->max_data_size = IRCOMM_TTY_DATA_UNINITIALISED;
-               self->close_delay = 5*HZ/10;
-               self->closing_wait = 30*HZ;
 
                /* Init some important stuff */
                init_timer(&self->watchdog_timer);
-               init_waitqueue_head(&self->open_wait);
-               init_waitqueue_head(&self->close_wait);
                spin_lock_init(&self->spinlock);
 
                /*
@@ -404,31 +414,48 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
                 *
                 * Note this is completely usafe and doesn't work properly
                 */
-               tty->termios->c_iflag = 0;
-               tty->termios->c_oflag = 0;
+               tty->termios.c_iflag = 0;
+               tty->termios.c_oflag = 0;
 
                /* Insert into hash */
                hashbin_insert(ircomm_tty, (irda_queue_t *) self, line, NULL);
        }
-       /* ++ is not atomic, so this should be protected - Jean II */
-       spin_lock_irqsave(&self->spinlock, flags);
-       self->open_count++;
 
-       tty->driver_data = self;
-       self->tty = tty;
-       spin_unlock_irqrestore(&self->spinlock, flags);
+       return tty_port_install(&self->port, driver, tty);
+}
+
+/*
+ * Function ircomm_tty_open (tty, filp)
+ *
+ *    This routine is called when a particular tty device is opened. This
+ *    routine is mandatory; if this routine is not filled in, the attempted
+ *    open will fail with ENODEV.
+ */
+static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
+{
+       struct ircomm_tty_cb *self = tty->driver_data;
+       unsigned long   flags;
+       int ret;
+
+       IRDA_DEBUG(2, "%s()\n", __func__ );
+
+       /* ++ is not atomic, so this should be protected - Jean II */
+       spin_lock_irqsave(&self->port.lock, flags);
+       self->port.count++;
+       spin_unlock_irqrestore(&self->port.lock, flags);
+       tty_port_tty_set(&self->port, tty);
 
        IRDA_DEBUG(1, "%s(), %s%d, count = %d\n", __func__ , tty->driver->name,
-                  self->line, self->open_count);
+                  self->line, self->port.count);
 
        /* Not really used by us, but lets do it anyway */
-       self->tty->low_latency = (self->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+       tty->low_latency = (self->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0;
 
        /*
         * If the port is the middle of closing, bail out now
         */
        if (tty_hung_up_p(filp) ||
-           test_bit(ASYNC_B_CLOSING, &self->flags)) {
+           test_bit(ASYNCB_CLOSING, &self->port.flags)) {
 
                /* Hm, why are we blocking on ASYNC_CLOSING if we
                 * do return -EAGAIN/-ERESTARTSYS below anyway?
@@ -438,14 +465,15 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
                 * probably better sleep uninterruptible?
                 */
 
-               if (wait_event_interruptible(self->close_wait, !test_bit(ASYNC_B_CLOSING, &self->flags))) {
+               if (wait_event_interruptible(self->port.close_wait,
+                               !test_bit(ASYNCB_CLOSING, &self->port.flags))) {
                        IRDA_WARNING("%s - got signal while blocking on ASYNC_CLOSING!\n",
                                     __func__);
                        return -ERESTARTSYS;
                }
 
 #ifdef SERIAL_DO_RESTART
-               return (self->flags & ASYNC_HUP_NOTIFY) ?
+               return (self->port.flags & ASYNC_HUP_NOTIFY) ?
                        -EAGAIN : -ERESTARTSYS;
 #else
                return -EAGAIN;
@@ -453,7 +481,7 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
        }
 
        /* Check if this is a "normal" ircomm device, or an irlpt device */
-       if (line < 0x10) {
+       if (self->line < 0x10) {
                self->service_type = IRCOMM_3_WIRE | IRCOMM_9_WIRE;
                self->settings.service_type = IRCOMM_9_WIRE; /* 9 wire as default */
                /* Jan Kiszka -> add DSR/RI -> Conform to IrCOMM spec */
@@ -469,7 +497,7 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
        if (ret)
                return ret;
 
-       ret = ircomm_tty_block_til_ready(self, filp);
+       ret = ircomm_tty_block_til_ready(self, tty, filp);
        if (ret) {
                IRDA_DEBUG(2,
                      "%s(), returning after block_til_ready with %d\n", __func__ ,
@@ -489,81 +517,22 @@ static int ircomm_tty_open(struct tty_struct *tty, struct file *filp)
 static void ircomm_tty_close(struct tty_struct *tty, struct file *filp)
 {
        struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
-       unsigned long flags;
+       struct tty_port *port = &self->port;
 
        IRDA_DEBUG(0, "%s()\n", __func__ );
 
        IRDA_ASSERT(self != NULL, return;);
        IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
-       spin_lock_irqsave(&self->spinlock, flags);
-
-       if (tty_hung_up_p(filp)) {
-               spin_unlock_irqrestore(&self->spinlock, flags);
-
-               IRDA_DEBUG(0, "%s(), returning 1\n", __func__ );
-               return;
-       }
-
-       if ((tty->count == 1) && (self->open_count != 1)) {
-               /*
-                * Uh, oh.  tty->count is 1, which means that the tty
-                * structure will be freed.  state->count should always
-                * be one in these conditions.  If it's greater than
-                * one, we've got real problems, since it means the
-                * serial port won't be shutdown.
-                */
-               IRDA_DEBUG(0, "%s(), bad serial port count; "
-                          "tty->count is 1, state->count is %d\n", __func__ ,
-                          self->open_count);
-               self->open_count = 1;
-       }
-
-       if (--self->open_count < 0) {
-               IRDA_ERROR("%s(), bad serial port count for ttys%d: %d\n",
-                          __func__, self->line, self->open_count);
-               self->open_count = 0;
-       }
-       if (self->open_count) {
-               spin_unlock_irqrestore(&self->spinlock, flags);
-
-               IRDA_DEBUG(0, "%s(), open count > 0\n", __func__ );
+       if (tty_port_close_start(port, tty, filp) == 0)
                return;
-       }
-
-       /* Hum... Should be test_and_set_bit ??? - Jean II */
-       set_bit(ASYNC_B_CLOSING, &self->flags);
-
-       /* We need to unlock here (we were unlocking at the end of this
-        * function), because tty_wait_until_sent() may schedule.
-        * I don't know if the rest should be protected somehow,
-        * so someone should check. - Jean II */
-       spin_unlock_irqrestore(&self->spinlock, flags);
-
-       /*
-        * Now we wait for the transmit buffer to clear; and we notify
-        * the line discipline to only process XON/XOFF characters.
-        */
-       tty->closing = 1;
-       if (self->closing_wait != ASYNC_CLOSING_WAIT_NONE)
-               tty_wait_until_sent_from_close(tty, self->closing_wait);
 
        ircomm_tty_shutdown(self);
 
        tty_driver_flush_buffer(tty);
-       tty_ldisc_flush(tty);
-
-       tty->closing = 0;
-       self->tty = NULL;
 
-       if (self->blocked_open) {
-               if (self->close_delay)
-                       schedule_timeout_interruptible(self->close_delay);
-               wake_up_interruptible(&self->open_wait);
-       }
-
-       self->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
-       wake_up_interruptible(&self->close_wait);
+       tty_port_close_end(port, tty);
+       tty_port_tty_set(port, NULL);
 }
 
 /*
@@ -606,7 +575,7 @@ static void ircomm_tty_do_softint(struct work_struct *work)
        if (!self || self->magic != IRCOMM_TTY_MAGIC)
                return;
 
-       tty = self->tty;
+       tty = tty_port_tty_get(&self->port);
        if (!tty)
                return;
 
@@ -627,7 +596,7 @@ static void ircomm_tty_do_softint(struct work_struct *work)
        }
 
        if (tty->hw_stopped)
-               return;
+               goto put;
 
        /* Unlink transmit buffer */
        spin_lock_irqsave(&self->spinlock, flags);
@@ -646,6 +615,8 @@ static void ircomm_tty_do_softint(struct work_struct *work)
 
        /* Check if user (still) wants to be waken up */
        tty_wakeup(tty);
+put:
+       tty_kref_put(tty);
 }
 
 /*
@@ -880,7 +851,7 @@ static void ircomm_tty_throttle(struct tty_struct *tty)
                ircomm_tty_send_xchar(tty, STOP_CHAR(tty));
 
        /* Hardware flow control? */
-       if (tty->termios->c_cflag & CRTSCTS) {
+       if (tty->termios.c_cflag & CRTSCTS) {
                self->settings.dte &= ~IRCOMM_RTS;
                self->settings.dte |= IRCOMM_DELTA_RTS;
 
@@ -912,7 +883,7 @@ static void ircomm_tty_unthrottle(struct tty_struct *tty)
        }
 
        /* Using hardware flow control? */
-       if (tty->termios->c_cflag & CRTSCTS) {
+       if (tty->termios.c_cflag & CRTSCTS) {
                self->settings.dte |= (IRCOMM_RTS|IRCOMM_DELTA_RTS);
 
                ircomm_param_request(self, IRCOMM_DTE, TRUE);
@@ -955,7 +926,7 @@ static void ircomm_tty_shutdown(struct ircomm_tty_cb *self)
 
        IRDA_DEBUG(0, "%s()\n", __func__ );
 
-       if (!test_and_clear_bit(ASYNC_B_INITIALIZED, &self->flags))
+       if (!test_and_clear_bit(ASYNCB_INITIALIZED, &self->port.flags))
                return;
 
        ircomm_tty_detach_cable(self);
@@ -994,6 +965,7 @@ static void ircomm_tty_shutdown(struct ircomm_tty_cb *self)
 static void ircomm_tty_hangup(struct tty_struct *tty)
 {
        struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
+       struct tty_port *port = &self->port;
        unsigned long   flags;
 
        IRDA_DEBUG(0, "%s()\n", __func__ );
@@ -1004,14 +976,17 @@ static void ircomm_tty_hangup(struct tty_struct *tty)
        /* ircomm_tty_flush_buffer(tty); */
        ircomm_tty_shutdown(self);
 
-       /* I guess we need to lock here - Jean II */
-       spin_lock_irqsave(&self->spinlock, flags);
-       self->flags &= ~ASYNC_NORMAL_ACTIVE;
-       self->tty = NULL;
-       self->open_count = 0;
-       spin_unlock_irqrestore(&self->spinlock, flags);
+       spin_lock_irqsave(&port->lock, flags);
+       port->flags &= ~ASYNC_NORMAL_ACTIVE;
+       if (port->tty) {
+               set_bit(TTY_IO_ERROR, &port->tty->flags);
+               tty_kref_put(port->tty);
+       }
+       port->tty = NULL;
+       port->count = 0;
+       spin_unlock_irqrestore(&port->lock, flags);
 
-       wake_up_interruptible(&self->open_wait);
+       wake_up_interruptible(&port->open_wait);
 }
 
 /*
@@ -1071,20 +1046,20 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self)
        IRDA_ASSERT(self != NULL, return;);
        IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
-       tty = self->tty;
+       tty = tty_port_tty_get(&self->port);
 
        status = self->settings.dce;
 
        if (status & IRCOMM_DCE_DELTA_ANY) {
                /*wake_up_interruptible(&self->delta_msr_wait);*/
        }
-       if ((self->flags & ASYNC_CHECK_CD) && (status & IRCOMM_DELTA_CD)) {
+       if ((self->port.flags & ASYNC_CHECK_CD) && (status & IRCOMM_DELTA_CD)) {
                IRDA_DEBUG(2,
                           "%s(), ircomm%d CD now %s...\n", __func__ , self->line,
                           (status & IRCOMM_CD) ? "on" : "off");
 
                if (status & IRCOMM_CD) {
-                       wake_up_interruptible(&self->open_wait);
+                       wake_up_interruptible(&self->port.open_wait);
                } else {
                        IRDA_DEBUG(2,
                                   "%s(), Doing serial hangup..\n", __func__ );
@@ -1092,10 +1067,10 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self)
                                tty_hangup(tty);
 
                        /* Hangup will remote the tty, so better break out */
-                       return;
+                       goto put;
                }
        }
-       if (self->flags & ASYNC_CTS_FLOW) {
+       if (tty && self->port.flags & ASYNC_CTS_FLOW) {
                if (tty->hw_stopped) {
                        if (status & IRCOMM_CTS) {
                                IRDA_DEBUG(2,
@@ -1103,10 +1078,10 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self)
                                tty->hw_stopped = 0;
 
                                /* Wake up processes blocked on open */
-                               wake_up_interruptible(&self->open_wait);
+                               wake_up_interruptible(&self->port.open_wait);
 
                                schedule_work(&self->tqueue);
-                               return;
+                               goto put;
                        }
                } else {
                        if (!(status & IRCOMM_CTS)) {
@@ -1116,6 +1091,8 @@ void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self)
                        }
                }
        }
+put:
+       tty_kref_put(tty);
 }
 
 /*
@@ -1128,6 +1105,7 @@ static int ircomm_tty_data_indication(void *instance, void *sap,
                                      struct sk_buff *skb)
 {
        struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
+       struct tty_struct *tty;
 
        IRDA_DEBUG(2, "%s()\n", __func__ );
 
@@ -1135,7 +1113,8 @@ static int ircomm_tty_data_indication(void *instance, void *sap,
        IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;);
        IRDA_ASSERT(skb != NULL, return -1;);
 
-       if (!self->tty) {
+       tty = tty_port_tty_get(&self->port);
+       if (!tty) {
                IRDA_DEBUG(0, "%s(), no tty!\n", __func__ );
                return 0;
        }
@@ -1146,7 +1125,7 @@ static int ircomm_tty_data_indication(void *instance, void *sap,
         * Devices like WinCE can do this, and since they don't send any
         * params, we can just as well declare the hardware for running.
         */
-       if (self->tty->hw_stopped && (self->flow == FLOW_START)) {
+       if (tty->hw_stopped && (self->flow == FLOW_START)) {
                IRDA_DEBUG(0, "%s(), polling for line settings!\n", __func__ );
                ircomm_param_request(self, IRCOMM_POLL, TRUE);
 
@@ -1159,8 +1138,9 @@ static int ircomm_tty_data_indication(void *instance, void *sap,
         * Use flip buffer functions since the code may be called from interrupt
         * context
         */
-       tty_insert_flip_string(self->tty, skb->data, skb->len);
-       tty_flip_buffer_push(self->tty);
+       tty_insert_flip_string(tty, skb->data, skb->len);
+       tty_flip_buffer_push(tty);
+       tty_kref_put(tty);
 
        /* No need to kfree_skb - see ircomm_ttp_data_indication() */
 
@@ -1211,12 +1191,13 @@ static void ircomm_tty_flow_indication(void *instance, void *sap,
        IRDA_ASSERT(self != NULL, return;);
        IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
-       tty = self->tty;
+       tty = tty_port_tty_get(&self->port);
 
        switch (cmd) {
        case FLOW_START:
                IRDA_DEBUG(2, "%s(), hw start!\n", __func__ );
-               tty->hw_stopped = 0;
+               if (tty)
+                       tty->hw_stopped = 0;
 
                /* ircomm_tty_do_softint will take care of the rest */
                schedule_work(&self->tqueue);
@@ -1224,15 +1205,19 @@ static void ircomm_tty_flow_indication(void *instance, void *sap,
        default:  /* If we get here, something is very wrong, better stop */
        case FLOW_STOP:
                IRDA_DEBUG(2, "%s(), hw stopped!\n", __func__ );
-               tty->hw_stopped = 1;
+               if (tty)
+                       tty->hw_stopped = 1;
                break;
        }
+
+       tty_kref_put(tty);
        self->flow = cmd;
 }
 
 #ifdef CONFIG_PROC_FS
 static void ircomm_tty_line_info(struct ircomm_tty_cb *self, struct seq_file *m)
 {
+       struct tty_struct *tty;
        char sep;
 
        seq_printf(m, "State: %s\n", ircomm_tty_state[self->state]);
@@ -1328,40 +1313,43 @@ static void ircomm_tty_line_info(struct ircomm_tty_cb *self, struct seq_file *m)
 
        seq_puts(m, "Flags:");
        sep = ' ';
-       if (self->flags & ASYNC_CTS_FLOW) {
+       if (self->port.flags & ASYNC_CTS_FLOW) {
                seq_printf(m, "%cASYNC_CTS_FLOW", sep);
                sep = '|';
        }
-       if (self->flags & ASYNC_CHECK_CD) {
+       if (self->port.flags & ASYNC_CHECK_CD) {
                seq_printf(m, "%cASYNC_CHECK_CD", sep);
                sep = '|';
        }
-       if (self->flags & ASYNC_INITIALIZED) {
+       if (self->port.flags & ASYNC_INITIALIZED) {
                seq_printf(m, "%cASYNC_INITIALIZED", sep);
                sep = '|';
        }
-       if (self->flags & ASYNC_LOW_LATENCY) {
+       if (self->port.flags & ASYNC_LOW_LATENCY) {
                seq_printf(m, "%cASYNC_LOW_LATENCY", sep);
                sep = '|';
        }
-       if (self->flags & ASYNC_CLOSING) {
+       if (self->port.flags & ASYNC_CLOSING) {
                seq_printf(m, "%cASYNC_CLOSING", sep);
                sep = '|';
        }
-       if (self->flags & ASYNC_NORMAL_ACTIVE) {
+       if (self->port.flags & ASYNC_NORMAL_ACTIVE) {
                seq_printf(m, "%cASYNC_NORMAL_ACTIVE", sep);
                sep = '|';
        }
        seq_putc(m, '\n');
 
        seq_printf(m, "Role: %s\n", self->client ? "client" : "server");
-       seq_printf(m, "Open count: %d\n", self->open_count);
+       seq_printf(m, "Open count: %d\n", self->port.count);
        seq_printf(m, "Max data size: %d\n", self->max_data_size);
        seq_printf(m, "Max header size: %d\n", self->max_header_size);
 
-       if (self->tty)
+       tty = tty_port_tty_get(&self->port);
+       if (tty) {
                seq_printf(m, "Hardware: %s\n",
-                              self->tty->hw_stopped ? "Stopped" : "Running");
+                              tty->hw_stopped ? "Stopped" : "Running");
+               tty_kref_put(tty);
+       }
 }
 
 static int ircomm_tty_proc_show(struct seq_file *m, void *v)
index b65d66e0d8174bd49d6301ea1d8444c1f072b7d1..3ab70e7a07157821b3112578528ce63b99c4389c 100644 (file)
@@ -130,6 +130,8 @@ static int (*state[])(struct ircomm_tty_cb *self, IRCOMM_TTY_EVENT event,
  */
 int ircomm_tty_attach_cable(struct ircomm_tty_cb *self)
 {
+       struct tty_struct *tty;
+
        IRDA_DEBUG(0, "%s()\n", __func__ );
 
        IRDA_ASSERT(self != NULL, return -1;);
@@ -142,7 +144,11 @@ int ircomm_tty_attach_cable(struct ircomm_tty_cb *self)
        }
 
        /* Make sure nobody tries to write before the link is up */
-       self->tty->hw_stopped = 1;
+       tty = tty_port_tty_get(&self->port);
+       if (tty) {
+               tty->hw_stopped = 1;
+               tty_kref_put(tty);
+       }
 
        ircomm_tty_ias_register(self);
 
@@ -398,23 +404,26 @@ void ircomm_tty_disconnect_indication(void *instance, void *sap,
                                      struct sk_buff *skb)
 {
        struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance;
+       struct tty_struct *tty;
 
        IRDA_DEBUG(2, "%s()\n", __func__ );
 
        IRDA_ASSERT(self != NULL, return;);
        IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
-       if (!self->tty)
+       tty = tty_port_tty_get(&self->port);
+       if (!tty)
                return;
 
        /* This will stop control data transfers */
        self->flow = FLOW_STOP;
 
        /* Stop data transfers */
-       self->tty->hw_stopped = 1;
+       tty->hw_stopped = 1;
 
        ircomm_tty_do_event(self, IRCOMM_TTY_DISCONNECT_INDICATION, NULL,
                            NULL);
+       tty_kref_put(tty);
 }
 
 /*
@@ -550,12 +559,15 @@ void ircomm_tty_connect_indication(void *instance, void *sap,
  */
 void ircomm_tty_link_established(struct ircomm_tty_cb *self)
 {
+       struct tty_struct *tty;
+
        IRDA_DEBUG(2, "%s()\n", __func__ );
 
        IRDA_ASSERT(self != NULL, return;);
        IRDA_ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;);
 
-       if (!self->tty)
+       tty = tty_port_tty_get(&self->port);
+       if (!tty)
                return;
 
        del_timer(&self->watchdog_timer);
@@ -566,19 +578,22 @@ void ircomm_tty_link_established(struct ircomm_tty_cb *self)
         * will have to wait for the peer device (DCE) to raise the CTS
         * line.
         */
-       if ((self->flags & ASYNC_CTS_FLOW) && ((self->settings.dce & IRCOMM_CTS) == 0)) {
+       if ((self->port.flags & ASYNC_CTS_FLOW) &&
+                       ((self->settings.dce & IRCOMM_CTS) == 0)) {
                IRDA_DEBUG(0, "%s(), waiting for CTS ...\n", __func__ );
-               return;
+               goto put;
        } else {
                IRDA_DEBUG(1, "%s(), starting hardware!\n", __func__ );
 
-               self->tty->hw_stopped = 0;
+               tty->hw_stopped = 0;
 
                /* Wake up processes blocked on open */
-               wake_up_interruptible(&self->open_wait);
+               wake_up_interruptible(&self->port.open_wait);
        }
 
        schedule_work(&self->tqueue);
+put:
+       tty_kref_put(tty);
 }
 
 /*
@@ -977,14 +992,17 @@ static int ircomm_tty_state_ready(struct ircomm_tty_cb *self,
                ircomm_tty_next_state(self, IRCOMM_TTY_SEARCH);
                ircomm_tty_start_watchdog_timer(self, 3*HZ);
 
-               if (self->flags & ASYNC_CHECK_CD) {
+               if (self->port.flags & ASYNC_CHECK_CD) {
                        /* Drop carrier */
                        self->settings.dce = IRCOMM_DELTA_CD;
                        ircomm_tty_check_modem_status(self);
                } else {
+                       struct tty_struct *tty = tty_port_tty_get(&self->port);
                        IRDA_DEBUG(0, "%s(), hanging up!\n", __func__ );
-                       if (self->tty)
-                               tty_hangup(self->tty);
+                       if (tty) {
+                               tty_hangup(tty);
+                               tty_kref_put(tty);
+                       }
                }
                break;
        default:
index d0667d68351dfc8944c2d694de054232cffefc75..b343f50dc8d72a07b321d9e70eb33e3ed8f62443 100644 (file)
  *    Change speed of the driver. If the remote device is a DCE, then this
  *    should make it change the speed of its serial port
  */
-static void ircomm_tty_change_speed(struct ircomm_tty_cb *self)
+static void ircomm_tty_change_speed(struct ircomm_tty_cb *self,
+               struct tty_struct *tty)
 {
        unsigned int cflag, cval;
        int baud;
 
        IRDA_DEBUG(2, "%s()\n", __func__ );
 
-       if (!self->tty || !self->tty->termios || !self->ircomm)
+       if (!self->ircomm)
                return;
 
-       cflag = self->tty->termios->c_cflag;
+       cflag = tty->termios.c_cflag;
 
        /*  byte size and parity */
        switch (cflag & CSIZE) {
@@ -81,7 +82,7 @@ static void ircomm_tty_change_speed(struct ircomm_tty_cb *self)
                cval |= IRCOMM_PARITY_EVEN;
 
        /* Determine divisor based on baud rate */
-       baud = tty_get_baud_rate(self->tty);
+       baud = tty_get_baud_rate(tty);
        if (!baud)
                baud = 9600;    /* B0 transition handled in rs_set_termios */
 
@@ -90,19 +91,19 @@ static void ircomm_tty_change_speed(struct ircomm_tty_cb *self)
 
        /* CTS flow control flag and modem status interrupts */
        if (cflag & CRTSCTS) {
-               self->flags |= ASYNC_CTS_FLOW;
+               self->port.flags |= ASYNC_CTS_FLOW;
                self->settings.flow_control |= IRCOMM_RTS_CTS_IN;
                /* This got me. Bummer. Jean II */
                if (self->service_type == IRCOMM_3_WIRE_RAW)
                        IRDA_WARNING("%s(), enabling RTS/CTS on link that doesn't support it (3-wire-raw)\n", __func__);
        } else {
-               self->flags &= ~ASYNC_CTS_FLOW;
+               self->port.flags &= ~ASYNC_CTS_FLOW;
                self->settings.flow_control &= ~IRCOMM_RTS_CTS_IN;
        }
        if (cflag & CLOCAL)
-               self->flags &= ~ASYNC_CHECK_CD;
+               self->port.flags &= ~ASYNC_CHECK_CD;
        else
-               self->flags |= ASYNC_CHECK_CD;
+               self->port.flags |= ASYNC_CHECK_CD;
 #if 0
        /*
         * Set up parity check flag
@@ -148,18 +149,18 @@ void ircomm_tty_set_termios(struct tty_struct *tty,
                            struct ktermios *old_termios)
 {
        struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data;
-       unsigned int cflag = tty->termios->c_cflag;
+       unsigned int cflag = tty->termios.c_cflag;
 
        IRDA_DEBUG(2, "%s()\n", __func__ );
 
        if ((cflag == old_termios->c_cflag) &&
-           (RELEVANT_IFLAG(tty->termios->c_iflag) ==
+           (RELEVANT_IFLAG(tty->termios.c_iflag) ==
             RELEVANT_IFLAG(old_termios->c_iflag)))
        {
                return;
        }
 
-       ircomm_tty_change_speed(self);
+       ircomm_tty_change_speed(self, tty);
 
        /* Handle transition to B0 status */
        if ((old_termios->c_cflag & CBAUD) &&
@@ -172,7 +173,7 @@ void ircomm_tty_set_termios(struct tty_struct *tty,
        if (!(old_termios->c_cflag & CBAUD) &&
            (cflag & CBAUD)) {
                self->settings.dte |= IRCOMM_DTR;
-               if (!(tty->termios->c_cflag & CRTSCTS) ||
+               if (!(tty->termios.c_cflag & CRTSCTS) ||
                    !test_bit(TTY_THROTTLED, &tty->flags)) {
                        self->settings.dte |= IRCOMM_RTS;
                }
@@ -181,7 +182,7 @@ void ircomm_tty_set_termios(struct tty_struct *tty,
 
        /* Handle turning off CRTSCTS */
        if ((old_termios->c_cflag & CRTSCTS) &&
-           !(tty->termios->c_cflag & CRTSCTS))
+           !(tty->termios.c_cflag & CRTSCTS))
        {
                tty->hw_stopped = 0;
                ircomm_tty_start(tty);
@@ -270,10 +271,10 @@ static int ircomm_tty_get_serial_info(struct ircomm_tty_cb *self,
 
        memset(&info, 0, sizeof(info));
        info.line = self->line;
-       info.flags = self->flags;
+       info.flags = self->port.flags;
        info.baud_base = self->settings.data_rate;
-       info.close_delay = self->close_delay;
-       info.closing_wait = self->closing_wait;
+       info.close_delay = self->port.close_delay;
+       info.closing_wait = self->port.closing_wait;
 
        /* For compatibility  */
        info.type = PORT_16550A;
index 34e418508a675d1f3427fa09f73ef43f2c9adae7..ec7d161c129b9f0194c3d10d2c624d8ed6b3b82d 100644 (file)
@@ -3024,7 +3024,7 @@ static u32 get_acqseq(void)
        return res;
 }
 
-static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *xp, int dir)
+static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *xp)
 {
        struct sk_buff *skb;
        struct sadb_msg *hdr;
@@ -3105,7 +3105,7 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct
        pol->sadb_x_policy_len = sizeof(struct sadb_x_policy)/sizeof(uint64_t);
        pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
        pol->sadb_x_policy_type = IPSEC_POLICY_IPSEC;
-       pol->sadb_x_policy_dir = dir+1;
+       pol->sadb_x_policy_dir = XFRM_POLICY_OUT + 1;
        pol->sadb_x_policy_id = xp->index;
 
        /* Set sadb_comb's. */
index 35e1e4bde58730d8395e2870d552230bca3a9c3d..927547171bc7119f57a7b8afecf453ec5eeabf61 100644 (file)
@@ -410,6 +410,7 @@ static int l2tp_ip6_getname(struct socket *sock, struct sockaddr *uaddr,
        lsa->l2tp_family = AF_INET6;
        lsa->l2tp_flowinfo = 0;
        lsa->l2tp_scope_id = 0;
+       lsa->l2tp_unused = 0;
        if (peer) {
                if (!lsk->peer_conn_id)
                        return -ENOTCONN;
index f6fe4d400502df780e1f57e574e5b4a1574b7f8d..c2190005a11410e2f95141fb841dadc051157a8b 100644 (file)
@@ -969,14 +969,13 @@ static int llc_ui_getname(struct socket *sock, struct sockaddr *uaddr,
        struct sockaddr_llc sllc;
        struct sock *sk = sock->sk;
        struct llc_sock *llc = llc_sk(sk);
-       int rc = 0;
+       int rc = -EBADF;
 
        memset(&sllc, 0, sizeof(sllc));
        lock_sock(sk);
        if (sock_flag(sk, SOCK_ZAPPED))
                goto out;
        *uaddrlen = sizeof(sllc);
-       memset(uaddr, 0, *uaddrlen);
        if (peer) {
                rc = -ENOTCONN;
                if (sk->sk_state != TCP_ESTABLISHED)
@@ -1206,7 +1205,7 @@ static int __init llc2_init(void)
        rc = llc_proc_init();
        if (rc != 0) {
                printk(llc_proc_err_msg);
-               goto out_unregister_llc_proto;
+               goto out_station;
        }
        rc = llc_sysctl_init();
        if (rc) {
@@ -1226,7 +1225,8 @@ out_sysctl:
        llc_sysctl_exit();
 out_proc:
        llc_proc_exit();
-out_unregister_llc_proto:
+out_station:
+       llc_station_exit();
        proto_unregister(&llc_proto);
        goto out;
 }
index e32cab44ea959d8f49781d46580b4204afb7e3cb..dd3e83328ad544d3183233da61fa40289975de51 100644 (file)
@@ -42,6 +42,7 @@ static void (*llc_type_handlers[2])(struct llc_sap *sap,
 void llc_add_pack(int type, void (*handler)(struct llc_sap *sap,
                                            struct sk_buff *skb))
 {
+       smp_wmb(); /* ensure initialisation is complete before it's called */
        if (type == LLC_DEST_SAP || type == LLC_DEST_CONN)
                llc_type_handlers[type - 1] = handler;
 }
@@ -50,11 +51,19 @@ void llc_remove_pack(int type)
 {
        if (type == LLC_DEST_SAP || type == LLC_DEST_CONN)
                llc_type_handlers[type - 1] = NULL;
+       synchronize_net();
 }
 
 void llc_set_station_handler(void (*handler)(struct sk_buff *skb))
 {
+       /* Ensure initialisation is complete before it's called */
+       if (handler)
+               smp_wmb();
+
        llc_station_handler = handler;
+
+       if (!handler)
+               synchronize_net();
 }
 
 /**
@@ -150,6 +159,8 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev,
        int dest;
        int (*rcv)(struct sk_buff *, struct net_device *,
                   struct packet_type *, struct net_device *);
+       void (*sta_handler)(struct sk_buff *skb);
+       void (*sap_handler)(struct llc_sap *sap, struct sk_buff *skb);
 
        if (!net_eq(dev_net(dev), &init_net))
                goto drop;
@@ -182,7 +193,8 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev,
         */
        rcv = rcu_dereference(sap->rcv_func);
        dest = llc_pdu_type(skb);
-       if (unlikely(!dest || !llc_type_handlers[dest - 1])) {
+       sap_handler = dest ? ACCESS_ONCE(llc_type_handlers[dest - 1]) : NULL;
+       if (unlikely(!sap_handler)) {
                if (rcv)
                        rcv(skb, dev, pt, orig_dev);
                else
@@ -193,7 +205,7 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev,
                        if (cskb)
                                rcv(cskb, dev, pt, orig_dev);
                }
-               llc_type_handlers[dest - 1](sap, skb);
+               sap_handler(sap, skb);
        }
        llc_sap_put(sap);
 out:
@@ -202,9 +214,10 @@ drop:
        kfree_skb(skb);
        goto out;
 handle_station:
-       if (!llc_station_handler)
+       sta_handler = ACCESS_ONCE(llc_station_handler);
+       if (!sta_handler)
                goto drop;
-       llc_station_handler(skb);
+       sta_handler(skb);
        goto out;
 }
 
index 39a8d8924b9c989747502774a4360b78e98d6ba4..b2f2bac2c2a2397b5fd6f6b79659996270b96377 100644 (file)
@@ -268,7 +268,7 @@ static int llc_station_ac_send_null_dsap_xid_c(struct sk_buff *skb)
 out:
        return rc;
 free:
-       kfree_skb(skb);
+       kfree_skb(nskb);
        goto out;
 }
 
@@ -293,7 +293,7 @@ static int llc_station_ac_send_xid_r(struct sk_buff *skb)
 out:
        return rc;
 free:
-       kfree_skb(skb);
+       kfree_skb(nskb);
        goto out;
 }
 
@@ -322,7 +322,7 @@ static int llc_station_ac_send_test_r(struct sk_buff *skb)
 out:
        return rc;
 free:
-       kfree_skb(skb);
+       kfree_skb(nskb);
        goto out;
 }
 
@@ -687,12 +687,8 @@ static void llc_station_rcv(struct sk_buff *skb)
        llc_station_state_process(skb);
 }
 
-int __init llc_station_init(void)
+void __init llc_station_init(void)
 {
-       int rc = -ENOBUFS;
-       struct sk_buff *skb;
-       struct llc_station_state_ev *ev;
-
        skb_queue_head_init(&llc_main_station.mac_pdu_q);
        skb_queue_head_init(&llc_main_station.ev_q.list);
        spin_lock_init(&llc_main_station.ev_q.lock);
@@ -700,23 +696,12 @@ int __init llc_station_init(void)
                        (unsigned long)&llc_main_station);
        llc_main_station.ack_timer.expires  = jiffies +
                                                sysctl_llc_station_ack_timeout;
-       skb = alloc_skb(0, GFP_ATOMIC);
-       if (!skb)
-               goto out;
-       rc = 0;
-       llc_set_station_handler(llc_station_rcv);
-       ev = llc_station_ev(skb);
-       memset(ev, 0, sizeof(*ev));
        llc_main_station.maximum_retry  = 1;
-       llc_main_station.state          = LLC_STATION_STATE_DOWN;
-       ev->type        = LLC_STATION_EV_TYPE_SIMPLE;
-       ev->prim_type   = LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK;
-       rc = llc_station_next_state(skb);
-out:
-       return rc;
+       llc_main_station.state          = LLC_STATION_STATE_UP;
+       llc_set_station_handler(llc_station_rcv);
 }
 
-void __exit llc_station_exit(void)
+void llc_station_exit(void)
 {
        llc_set_station_handler(NULL);
 }
index 6fac18c0423ff391213de03242299ff3b1e4b965..0e2f83e71277f37176226c7c41e5fd03a9cb8abb 100644 (file)
@@ -136,10 +136,13 @@ bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie)
  * mesh_accept_plinks_update - update accepting_plink in local mesh beacons
  *
  * @sdata: mesh interface in which mesh beacons are going to be updated
+ *
+ * Returns: beacon changed flag if the beacon content changed.
  */
-void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata)
+u32 mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata)
 {
        bool free_plinks;
+       u32 changed = 0;
 
        /* In case mesh_plink_free_count > 0 and mesh_plinktbl_capacity == 0,
         * the mesh interface might be able to establish plinks with peers that
@@ -149,8 +152,12 @@ void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata)
         */
        free_plinks = mesh_plink_availables(sdata);
 
-       if (free_plinks != sdata->u.mesh.accepting_plinks)
-               ieee80211_mesh_housekeeping_timer((unsigned long) sdata);
+       if (free_plinks != sdata->u.mesh.accepting_plinks) {
+               sdata->u.mesh.accepting_plinks = free_plinks;
+               changed = BSS_CHANGED_BEACON;
+       }
+
+       return changed;
 }
 
 int mesh_rmc_init(struct ieee80211_sub_if_data *sdata)
@@ -262,7 +269,6 @@ mesh_add_meshconf_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
        neighbors = (neighbors > 15) ? 15 : neighbors;
        *pos++ = neighbors << 1;
        /* Mesh capability */
-       ifmsh->accepting_plinks = mesh_plink_availables(sdata);
        *pos = MESHCONF_CAPAB_FORWARDING;
        *pos |= ifmsh->accepting_plinks ?
            MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00;
@@ -521,14 +527,13 @@ int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr,
 static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata,
                           struct ieee80211_if_mesh *ifmsh)
 {
-       bool free_plinks;
+       u32 changed;
 
        ieee80211_sta_expire(sdata, IEEE80211_MESH_PEER_INACTIVITY_LIMIT);
        mesh_path_expire(sdata);
 
-       free_plinks = mesh_plink_availables(sdata);
-       if (free_plinks != sdata->u.mesh.accepting_plinks)
-               ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
+       changed = mesh_accept_plinks_update(sdata);
+       ieee80211_bss_info_change_notify(sdata, changed);
 
        mod_timer(&ifmsh->housekeeping_timer,
                  round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL));
@@ -622,6 +627,7 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
 
        del_timer_sync(&sdata->u.mesh.housekeeping_timer);
        del_timer_sync(&sdata->u.mesh.mesh_path_root_timer);
+       del_timer_sync(&sdata->u.mesh.mesh_path_timer);
        /*
         * If the timer fired while we waited for it, it will have
         * requeued the work. Now the work will be running again
@@ -634,6 +640,8 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
        local->fif_other_bss--;
        atomic_dec(&local->iff_allmultis);
        ieee80211_configure_filter(local);
+
+       sdata->u.mesh.timers_running = 0;
 }
 
 static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
index faaa39bcfd109b783c2f297fdda6aa3585587026..13fd5b5fdb0a8b540d12d525ebba87ddd75da6c9 100644 (file)
@@ -282,7 +282,7 @@ void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata,
                           u8 *hw_addr,
                           struct ieee802_11_elems *ie);
 bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie);
-void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata);
+u32 mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata);
 void mesh_plink_broken(struct sta_info *sta);
 void mesh_plink_deactivate(struct sta_info *sta);
 int mesh_plink_open(struct sta_info *sta);
index af671b984df37123cf6841fb9a8e4e5db70bde65..f20e9f26d13796ccb8ed8abaeeb9aa8fb9634d63 100644 (file)
@@ -48,17 +48,17 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
                u8 *da, __le16 llid, __le16 plid, __le16 reason);
 
 static inline
-void mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata)
+u32 mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata)
 {
        atomic_inc(&sdata->u.mesh.mshstats.estab_plinks);
-       mesh_accept_plinks_update(sdata);
+       return mesh_accept_plinks_update(sdata);
 }
 
 static inline
-void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata)
+u32 mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata)
 {
        atomic_dec(&sdata->u.mesh.mshstats.estab_plinks);
-       mesh_accept_plinks_update(sdata);
+       return mesh_accept_plinks_update(sdata);
 }
 
 /**
@@ -170,22 +170,21 @@ out:
  * @sta: mesh peer link to deactivate
  *
  * All mesh paths with this peer as next hop will be flushed
+ * Returns beacon changed flag if the beacon content changed.
  *
  * Locking: the caller must hold sta->lock
  */
-static bool __mesh_plink_deactivate(struct sta_info *sta)
+static u32 __mesh_plink_deactivate(struct sta_info *sta)
 {
        struct ieee80211_sub_if_data *sdata = sta->sdata;
-       bool deactivated = false;
+       u32 changed = 0;
 
-       if (sta->plink_state == NL80211_PLINK_ESTAB) {
-               mesh_plink_dec_estab_count(sdata);
-               deactivated = true;
-       }
+       if (sta->plink_state == NL80211_PLINK_ESTAB)
+               changed = mesh_plink_dec_estab_count(sdata);
        sta->plink_state = NL80211_PLINK_BLOCKED;
        mesh_path_flush_by_nexthop(sta);
 
-       return deactivated;
+       return changed;
 }
 
 /**
@@ -198,18 +197,17 @@ static bool __mesh_plink_deactivate(struct sta_info *sta)
 void mesh_plink_deactivate(struct sta_info *sta)
 {
        struct ieee80211_sub_if_data *sdata = sta->sdata;
-       bool deactivated;
+       u32 changed;
 
        spin_lock_bh(&sta->lock);
-       deactivated = __mesh_plink_deactivate(sta);
+       changed = __mesh_plink_deactivate(sta);
        sta->reason = cpu_to_le16(WLAN_REASON_MESH_PEER_CANCELED);
        mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
                            sta->sta.addr, sta->llid, sta->plid,
                            sta->reason);
        spin_unlock_bh(&sta->lock);
 
-       if (deactivated)
-               ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
+       ieee80211_bss_info_change_notify(sdata, changed);
 }
 
 static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
@@ -541,15 +539,14 @@ int mesh_plink_open(struct sta_info *sta)
 void mesh_plink_block(struct sta_info *sta)
 {
        struct ieee80211_sub_if_data *sdata = sta->sdata;
-       bool deactivated;
+       u32 changed;
 
        spin_lock_bh(&sta->lock);
-       deactivated = __mesh_plink_deactivate(sta);
+       changed = __mesh_plink_deactivate(sta);
        sta->plink_state = NL80211_PLINK_BLOCKED;
        spin_unlock_bh(&sta->lock);
 
-       if (deactivated)
-               ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
+       ieee80211_bss_info_change_notify(sdata, changed);
 }
 
 
@@ -852,9 +849,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
                        del_timer(&sta->plink_timer);
                        sta->plink_state = NL80211_PLINK_ESTAB;
                        spin_unlock_bh(&sta->lock);
-                       mesh_plink_inc_estab_count(sdata);
+                       changed |= mesh_plink_inc_estab_count(sdata);
                        changed |= mesh_set_ht_prot_mode(sdata);
-                       changed |= BSS_CHANGED_BEACON;
                        mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n",
                                sta->sta.addr);
                        break;
@@ -888,9 +884,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
                        del_timer(&sta->plink_timer);
                        sta->plink_state = NL80211_PLINK_ESTAB;
                        spin_unlock_bh(&sta->lock);
-                       mesh_plink_inc_estab_count(sdata);
+                       changed |= mesh_plink_inc_estab_count(sdata);
                        changed |= mesh_set_ht_prot_mode(sdata);
-                       changed |= BSS_CHANGED_BEACON;
                        mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n",
                                sta->sta.addr);
                        mesh_plink_frame_tx(sdata,
@@ -908,13 +903,12 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
                case CLS_ACPT:
                        reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
                        sta->reason = reason;
-                       __mesh_plink_deactivate(sta);
+                       changed |= __mesh_plink_deactivate(sta);
                        sta->plink_state = NL80211_PLINK_HOLDING;
                        llid = sta->llid;
                        mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
                        spin_unlock_bh(&sta->lock);
                        changed |= mesh_set_ht_prot_mode(sdata);
-                       changed |= BSS_CHANGED_BEACON;
                        mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
                                            sta->sta.addr, llid, plid, reason);
                        break;
index cef0c9e79aba5ff4657938478dea6e829e10b164..a4a5acdbaa4dd3ac5e2fb8c5f0ff1d1b97553d6a 100644 (file)
@@ -1430,6 +1430,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        del_timer_sync(&sdata->u.mgd.bcn_mon_timer);
        del_timer_sync(&sdata->u.mgd.timer);
        del_timer_sync(&sdata->u.mgd.chswitch_timer);
+
+       sdata->u.mgd.timers_running = 0;
 }
 
 void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
index bcaee5d1283915efdbc8c63f4365c7ed42d486dc..839dd9737989ec78bbb979c814953b1bdd0187a8 100644 (file)
@@ -299,7 +299,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
        if (local->scan_req != local->int_scan_req)
                cfg80211_scan_done(local->scan_req, aborted);
        local->scan_req = NULL;
-       local->scan_sdata = NULL;
+       rcu_assign_pointer(local->scan_sdata, NULL);
 
        local->scanning = 0;
        local->scan_channel = NULL;
@@ -984,7 +984,6 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata)
                        kfree(local->sched_scan_ies.ie[i]);
 
                drv_sched_scan_stop(local, sdata);
-               rcu_assign_pointer(local->sched_scan_sdata, NULL);
        }
 out:
        mutex_unlock(&local->mtx);
index 84444dda194b61806efaeadde4c2458f502d8283..72bf32a84874718927a4bcbdc2e26395be00bdd8 100644 (file)
@@ -2759,6 +2759,7 @@ do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
        {
                struct ip_vs_timeout_user t;
 
+               memset(&t, 0, sizeof(t));
                __ip_vs_get_timeouts(net, &t);
                if (copy_to_user(user, &t, sizeof(t)) != 0)
                        ret = -EFAULT;
index 0060e3b396b7b41fb0a5791966a39222cce8c04d..cc55b35f80e5acd045c37fc20bb37d98ba3d258c 100644 (file)
@@ -14,3 +14,11 @@ config PACKET
          be called af_packet.
 
          If unsure, say Y.
+
+config PACKET_DIAG
+       tristate "Packet: sockets monitoring interface"
+       depends on PACKET
+       default n
+       ---help---
+         Support for PF_PACKET sockets monitoring interface used by the ss tool.
+         If unsure, say Y.
index 81183eabfdec5cee58148d85df0877fc0e3a3d45..9df61347a3c3e98938c7b11a83195a22eb5d755c 100644 (file)
@@ -3,3 +3,5 @@
 #
 
 obj-$(CONFIG_PACKET) += af_packet.o
+obj-$(CONFIG_PACKET_DIAG) += af_packet_diag.o
+af_packet_diag-y += diag.o
index ceaca7c134a011b659bc439dff6de58269b532b4..8fd380a30037db468784abd425b6a225205c73f7 100644 (file)
@@ -93,6 +93,8 @@
 #include <net/inet_common.h>
 #endif
 
+#include "internal.h"
+
 /*
    Assumptions:
    - if device has no dev->hard_header routine, it adds and removes ll header
@@ -146,14 +148,6 @@ dev->hard_header == NULL (ll header is added by device, we cannot control it)
 
 /* Private packet socket structures. */
 
-struct packet_mclist {
-       struct packet_mclist    *next;
-       int                     ifindex;
-       int                     count;
-       unsigned short          type;
-       unsigned short          alen;
-       unsigned char           addr[MAX_ADDR_LEN];
-};
 /* identical to struct packet_mreq except it has
  * a longer address field.
  */
@@ -175,63 +169,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
 #define BLK_PLUS_PRIV(sz_of_priv) \
        (BLK_HDR_LEN + ALIGN((sz_of_priv), V3_ALIGNMENT))
 
-/* kbdq - kernel block descriptor queue */
-struct tpacket_kbdq_core {
-       struct pgv      *pkbdq;
-       unsigned int    feature_req_word;
-       unsigned int    hdrlen;
-       unsigned char   reset_pending_on_curr_blk;
-       unsigned char   delete_blk_timer;
-       unsigned short  kactive_blk_num;
-       unsigned short  blk_sizeof_priv;
-
-       /* last_kactive_blk_num:
-        * trick to see if user-space has caught up
-        * in order to avoid refreshing timer when every single pkt arrives.
-        */
-       unsigned short  last_kactive_blk_num;
-
-       char            *pkblk_start;
-       char            *pkblk_end;
-       int             kblk_size;
-       unsigned int    knum_blocks;
-       uint64_t        knxt_seq_num;
-       char            *prev;
-       char            *nxt_offset;
-       struct sk_buff  *skb;
-
-       atomic_t        blk_fill_in_prog;
-
-       /* Default is set to 8ms */
-#define DEFAULT_PRB_RETIRE_TOV (8)
-
-       unsigned short  retire_blk_tov;
-       unsigned short  version;
-       unsigned long   tov_in_jiffies;
-
-       /* timer to retire an outstanding block */
-       struct timer_list retire_blk_timer;
-};
-
 #define PGV_FROM_VMALLOC 1
-struct pgv {
-       char *buffer;
-};
-
-struct packet_ring_buffer {
-       struct pgv              *pg_vec;
-       unsigned int            head;
-       unsigned int            frames_per_block;
-       unsigned int            frame_size;
-       unsigned int            frame_max;
-
-       unsigned int            pg_vec_order;
-       unsigned int            pg_vec_pages;
-       unsigned int            pg_vec_len;
-
-       struct tpacket_kbdq_core        prb_bdqc;
-       atomic_t                pending;
-};
 
 #define BLOCK_STATUS(x)        ((x)->hdr.bh1.block_status)
 #define BLOCK_NUM_PKTS(x)      ((x)->hdr.bh1.num_pkts)
@@ -269,34 +207,6 @@ static void prb_fill_vlan_info(struct tpacket_kbdq_core *,
                struct tpacket3_hdr *);
 static void packet_flush_mclist(struct sock *sk);
 
-struct packet_fanout;
-struct packet_sock {
-       /* struct sock has to be the first member of packet_sock */
-       struct sock             sk;
-       struct packet_fanout    *fanout;
-       struct tpacket_stats    stats;
-       union  tpacket_stats_u  stats_u;
-       struct packet_ring_buffer       rx_ring;
-       struct packet_ring_buffer       tx_ring;
-       int                     copy_thresh;
-       spinlock_t              bind_lock;
-       struct mutex            pg_vec_lock;
-       unsigned int            running:1,      /* prot_hook is attached*/
-                               auxdata:1,
-                               origdev:1,
-                               has_vnet_hdr:1;
-       int                     ifindex;        /* bound device         */
-       __be16                  num;
-       struct packet_mclist    *mclist;
-       atomic_t                mapped;
-       enum tpacket_versions   tp_version;
-       unsigned int            tp_hdrlen;
-       unsigned int            tp_reserve;
-       unsigned int            tp_loss:1;
-       unsigned int            tp_tstamp;
-       struct packet_type      prot_hook ____cacheline_aligned_in_smp;
-};
-
 #define PACKET_FANOUT_MAX      256
 
 struct packet_fanout {
@@ -334,11 +244,6 @@ struct packet_skb_cb {
        (((x)->kactive_blk_num < ((x)->knum_blocks-1)) ? \
        ((x)->kactive_blk_num+1) : 0)
 
-static struct packet_sock *pkt_sk(struct sock *sk)
-{
-       return (struct packet_sock *)sk;
-}
-
 static void __fanout_unlink(struct sock *sk, struct packet_sock *po);
 static void __fanout_link(struct sock *sk, struct packet_sock *po);
 
@@ -1079,7 +984,7 @@ static void *packet_current_rx_frame(struct packet_sock *po,
        default:
                WARN(1, "TPACKET version not supported\n");
                BUG();
-               return 0;
+               return NULL;
        }
 }
 
@@ -1936,7 +1841,6 @@ static void tpacket_destruct_skb(struct sk_buff *skb)
 
        if (likely(po->tx_ring.pg_vec)) {
                ph = skb_shinfo(skb)->destructor_arg;
-               BUG_ON(__packet_get_status(po, ph) != TP_STATUS_SENDING);
                BUG_ON(atomic_read(&po->tx_ring.pending) == 0);
                atomic_dec(&po->tx_ring.pending);
                __packet_set_status(po, ph, TP_STATUS_AVAILABLE);
diff --git a/net/packet/diag.c b/net/packet/diag.c
new file mode 100644 (file)
index 0000000..3dda4ec
--- /dev/null
@@ -0,0 +1,176 @@
+#include <linux/module.h>
+#include <linux/sock_diag.h>
+#include <linux/net.h>
+#include <linux/netdevice.h>
+#include <linux/packet_diag.h>
+#include <net/net_namespace.h>
+#include <net/sock.h>
+
+#include "internal.h"
+
+static int pdiag_put_info(const struct packet_sock *po, struct sk_buff *nlskb)
+{
+       struct packet_diag_info pinfo;
+
+       pinfo.pdi_index = po->ifindex;
+       pinfo.pdi_version = po->tp_version;
+       pinfo.pdi_reserve = po->tp_reserve;
+       pinfo.pdi_copy_thresh = po->copy_thresh;
+       pinfo.pdi_tstamp = po->tp_tstamp;
+
+       pinfo.pdi_flags = 0;
+       if (po->running)
+               pinfo.pdi_flags |= PDI_RUNNING;
+       if (po->auxdata)
+               pinfo.pdi_flags |= PDI_AUXDATA;
+       if (po->origdev)
+               pinfo.pdi_flags |= PDI_ORIGDEV;
+       if (po->has_vnet_hdr)
+               pinfo.pdi_flags |= PDI_VNETHDR;
+       if (po->tp_loss)
+               pinfo.pdi_flags |= PDI_LOSS;
+
+       return nla_put(nlskb, PACKET_DIAG_INFO, sizeof(pinfo), &pinfo);
+}
+
+static int pdiag_put_mclist(const struct packet_sock *po, struct sk_buff *nlskb)
+{
+       struct nlattr *mca;
+       struct packet_mclist *ml;
+
+       mca = nla_nest_start(nlskb, PACKET_DIAG_MCLIST);
+       if (!mca)
+               return -EMSGSIZE;
+
+       rtnl_lock();
+       for (ml = po->mclist; ml; ml = ml->next) {
+               struct packet_diag_mclist *dml;
+
+               dml = nla_reserve_nohdr(nlskb, sizeof(*dml));
+               if (!dml) {
+                       rtnl_unlock();
+                       nla_nest_cancel(nlskb, mca);
+                       return -EMSGSIZE;
+               }
+
+               dml->pdmc_index = ml->ifindex;
+               dml->pdmc_type = ml->type;
+               dml->pdmc_alen = ml->alen;
+               dml->pdmc_count = ml->count;
+               BUILD_BUG_ON(sizeof(dml->pdmc_addr) != sizeof(ml->addr));
+               memcpy(dml->pdmc_addr, ml->addr, sizeof(ml->addr));
+       }
+
+       rtnl_unlock();
+       nla_nest_end(nlskb, mca);
+
+       return 0;
+}
+
+static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct packet_diag_req *req,
+               u32 pid, u32 seq, u32 flags, int sk_ino)
+{
+       struct nlmsghdr *nlh;
+       struct packet_diag_msg *rp;
+       const struct packet_sock *po = pkt_sk(sk);
+
+       nlh = nlmsg_put(skb, pid, seq, SOCK_DIAG_BY_FAMILY, sizeof(*rp), flags);
+       if (!nlh)
+               return -EMSGSIZE;
+
+       rp = nlmsg_data(nlh);
+       rp->pdiag_family = AF_PACKET;
+       rp->pdiag_type = sk->sk_type;
+       rp->pdiag_num = ntohs(po->num);
+       rp->pdiag_ino = sk_ino;
+       sock_diag_save_cookie(sk, rp->pdiag_cookie);
+
+       if ((req->pdiag_show & PACKET_SHOW_INFO) &&
+                       pdiag_put_info(po, skb))
+               goto out_nlmsg_trim;
+
+       if ((req->pdiag_show & PACKET_SHOW_MCLIST) &&
+                       pdiag_put_mclist(po, skb))
+               goto out_nlmsg_trim;
+
+       return nlmsg_end(skb, nlh);
+
+out_nlmsg_trim:
+       nlmsg_cancel(skb, nlh);
+       return -EMSGSIZE;
+}
+
+static int packet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
+{
+       int num = 0, s_num = cb->args[0];
+       struct packet_diag_req *req;
+       struct net *net;
+       struct sock *sk;
+       struct hlist_node *node;
+
+       net = sock_net(skb->sk);
+       req = nlmsg_data(cb->nlh);
+
+       rcu_read_lock();
+       sk_for_each_rcu(sk, node, &net->packet.sklist) {
+               if (!net_eq(sock_net(sk), net))
+                       continue;
+               if (num < s_num)
+                       goto next;
+
+               if (sk_diag_fill(sk, skb, req, NETLINK_CB(cb->skb).pid,
+                                       cb->nlh->nlmsg_seq, NLM_F_MULTI,
+                                       sock_i_ino(sk)) < 0)
+                       goto done;
+next:
+               num++;
+       }
+done:
+       rcu_read_unlock();
+       cb->args[0] = num;
+
+       return skb->len;
+}
+
+static int packet_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
+{
+       int hdrlen = sizeof(struct packet_diag_req);
+       struct net *net = sock_net(skb->sk);
+       struct packet_diag_req *req;
+
+       if (nlmsg_len(h) < hdrlen)
+               return -EINVAL;
+
+       req = nlmsg_data(h);
+       /* Make it possible to support protocol filtering later */
+       if (req->sdiag_protocol)
+               return -EINVAL;
+
+       if (h->nlmsg_flags & NLM_F_DUMP) {
+               struct netlink_dump_control c = {
+                       .dump = packet_diag_dump,
+               };
+               return netlink_dump_start(net->diag_nlsk, skb, h, &c);
+       } else
+               return -EOPNOTSUPP;
+}
+
+static const struct sock_diag_handler packet_diag_handler = {
+       .family = AF_PACKET,
+       .dump = packet_diag_handler_dump,
+};
+
+static int __init packet_diag_init(void)
+{
+       return sock_diag_register(&packet_diag_handler);
+}
+
+static void __exit packet_diag_exit(void)
+{
+       sock_diag_unregister(&packet_diag_handler);
+}
+
+module_init(packet_diag_init);
+module_exit(packet_diag_exit);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 17 /* AF_PACKET */);
diff --git a/net/packet/internal.h b/net/packet/internal.h
new file mode 100644 (file)
index 0000000..2c5fca2
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef __PACKET_INTERNAL_H__
+#define __PACKET_INTERNAL_H__
+
+struct packet_mclist {
+       struct packet_mclist    *next;
+       int                     ifindex;
+       int                     count;
+       unsigned short          type;
+       unsigned short          alen;
+       unsigned char           addr[MAX_ADDR_LEN];
+};
+
+/* kbdq - kernel block descriptor queue */
+struct tpacket_kbdq_core {
+       struct pgv      *pkbdq;
+       unsigned int    feature_req_word;
+       unsigned int    hdrlen;
+       unsigned char   reset_pending_on_curr_blk;
+       unsigned char   delete_blk_timer;
+       unsigned short  kactive_blk_num;
+       unsigned short  blk_sizeof_priv;
+
+       /* last_kactive_blk_num:
+        * trick to see if user-space has caught up
+        * in order to avoid refreshing timer when every single pkt arrives.
+        */
+       unsigned short  last_kactive_blk_num;
+
+       char            *pkblk_start;
+       char            *pkblk_end;
+       int             kblk_size;
+       unsigned int    knum_blocks;
+       uint64_t        knxt_seq_num;
+       char            *prev;
+       char            *nxt_offset;
+       struct sk_buff  *skb;
+
+       atomic_t        blk_fill_in_prog;
+
+       /* Default is set to 8ms */
+#define DEFAULT_PRB_RETIRE_TOV (8)
+
+       unsigned short  retire_blk_tov;
+       unsigned short  version;
+       unsigned long   tov_in_jiffies;
+
+       /* timer to retire an outstanding block */
+       struct timer_list retire_blk_timer;
+};
+
+struct pgv {
+       char *buffer;
+};
+
+struct packet_ring_buffer {
+       struct pgv              *pg_vec;
+       unsigned int            head;
+       unsigned int            frames_per_block;
+       unsigned int            frame_size;
+       unsigned int            frame_max;
+
+       unsigned int            pg_vec_order;
+       unsigned int            pg_vec_pages;
+       unsigned int            pg_vec_len;
+
+       struct tpacket_kbdq_core        prb_bdqc;
+       atomic_t                pending;
+};
+
+struct packet_fanout;
+struct packet_sock {
+       /* struct sock has to be the first member of packet_sock */
+       struct sock             sk;
+       struct packet_fanout    *fanout;
+       struct tpacket_stats    stats;
+       union  tpacket_stats_u  stats_u;
+       struct packet_ring_buffer       rx_ring;
+       struct packet_ring_buffer       tx_ring;
+       int                     copy_thresh;
+       spinlock_t              bind_lock;
+       struct mutex            pg_vec_lock;
+       unsigned int            running:1,      /* prot_hook is attached*/
+                               auxdata:1,
+                               origdev:1,
+                               has_vnet_hdr:1;
+       int                     ifindex;        /* bound device         */
+       __be16                  num;
+       struct packet_mclist    *mclist;
+       atomic_t                mapped;
+       enum tpacket_versions   tp_version;
+       unsigned int            tp_hdrlen;
+       unsigned int            tp_reserve;
+       unsigned int            tp_loss:1;
+       unsigned int            tp_tstamp;
+       struct packet_type      prot_hook ____cacheline_aligned_in_smp;
+};
+
+static struct packet_sock *pkt_sk(struct sock *sk)
+{
+       return (struct packet_sock *)sk;
+}
+
+#endif
index 24c55c53e6a2fe150c2a34b181c60e2527278a55..c9d931e7ffecf1134e3743f4fc3920a10bb1f9cc 100644 (file)
@@ -164,8 +164,7 @@ static void rfkill_schedule_global_op(enum rfkill_sched_op op)
        rfkill_op_pending = true;
        if (op == RFKILL_GLOBAL_OP_EPO && !rfkill_is_epo_lock_active()) {
                /* bypass the limiter for EPO */
-               cancel_delayed_work(&rfkill_op_work);
-               schedule_delayed_work(&rfkill_op_work, 0);
+               mod_delayed_work(system_wq, &rfkill_op_work, 0);
                rfkill_last_scheduled = jiffies;
        } else
                rfkill_schedule_ratelimited();
index f10fb8256442014afbba6b85a23a3544ee0ec9e4..05d60859d8e3d1c2eb700ff7d1d63d81d9f98894 100644 (file)
@@ -67,6 +67,9 @@ static int tcf_gact_init(struct nlattr *nla, struct nlattr *est,
        struct tcf_common *pc;
        int ret = 0;
        int err;
+#ifdef CONFIG_GACT_PROB
+       struct tc_gact_p *p_parm = NULL;
+#endif
 
        if (nla == NULL)
                return -EINVAL;
@@ -82,6 +85,12 @@ static int tcf_gact_init(struct nlattr *nla, struct nlattr *est,
 #ifndef CONFIG_GACT_PROB
        if (tb[TCA_GACT_PROB] != NULL)
                return -EOPNOTSUPP;
+#else
+       if (tb[TCA_GACT_PROB]) {
+               p_parm = nla_data(tb[TCA_GACT_PROB]);
+               if (p_parm->ptype >= MAX_RAND)
+                       return -EINVAL;
+       }
 #endif
 
        pc = tcf_hash_check(parm->index, a, bind, &gact_hash_info);
@@ -103,8 +112,7 @@ static int tcf_gact_init(struct nlattr *nla, struct nlattr *est,
        spin_lock_bh(&gact->tcf_lock);
        gact->tcf_action = parm->action;
 #ifdef CONFIG_GACT_PROB
-       if (tb[TCA_GACT_PROB] != NULL) {
-               struct tc_gact_p *p_parm = nla_data(tb[TCA_GACT_PROB]);
+       if (p_parm) {
                gact->tcfg_paction = p_parm->paction;
                gact->tcfg_pval    = p_parm->pval;
                gact->tcfg_ptype   = p_parm->ptype;
@@ -133,7 +141,7 @@ static int tcf_gact(struct sk_buff *skb, const struct tc_action *a,
 
        spin_lock(&gact->tcf_lock);
 #ifdef CONFIG_GACT_PROB
-       if (gact->tcfg_ptype && gact_rand[gact->tcfg_ptype] != NULL)
+       if (gact->tcfg_ptype)
                action = gact_rand[gact->tcfg_ptype](gact);
        else
                action = gact->tcf_action;
index 60e281ad0f07292d5b60b0501e465c1316df433a..58fb3c7aab9eea8a0e65851948dd3d81da4fe3b8 100644 (file)
@@ -185,7 +185,12 @@ err3:
 err2:
        kfree(tname);
 err1:
-       kfree(pc);
+       if (ret == ACT_P_CREATED) {
+               if (est)
+                       gen_kill_estimator(&pc->tcfc_bstats,
+                                          &pc->tcfc_rate_est);
+               kfree_rcu(pc, tcfc_rcu);
+       }
        return err;
 }
 
index fe81cc18e9e0dd20624aa4a6e7aa5aa098f737fc..9c0fd0c788145c0b6fa877463022f5ec90a707e2 100644 (file)
@@ -200,13 +200,12 @@ static int tcf_mirred(struct sk_buff *skb, const struct tc_action *a,
 out:
        if (err) {
                m->tcf_qstats.overlimits++;
-               /* should we be asking for packet to be dropped?
-                * may make sense for redirect case only
-                */
-               retval = TC_ACT_SHOT;
-       } else {
+               if (m->tcfm_eaction != TCA_EGRESS_MIRROR)
+                       retval = TC_ACT_SHOT;
+               else
+                       retval = m->tcf_action;
+       } else
                retval = m->tcf_action;
-       }
        spin_unlock(&m->tcf_lock);
 
        return retval;
index 26aa2f6ce257c5b39541df44db40c950fcd67045..45c53ab067a63240357a970e15ab2633802211d6 100644 (file)
@@ -74,7 +74,10 @@ static int tcf_pedit_init(struct nlattr *nla, struct nlattr *est,
                p = to_pedit(pc);
                keys = kmalloc(ksize, GFP_KERNEL);
                if (keys == NULL) {
-                       kfree(pc);
+                       if (est)
+                               gen_kill_estimator(&pc->tcfc_bstats,
+                                                  &pc->tcfc_rate_est);
+                       kfree_rcu(pc, tcfc_rcu);
                        return -ENOMEM;
                }
                ret = ACT_P_CREATED;
index 3922f2a2821b83cf3f9db318980a7cad06111e1f..3714f60f0b3c5869725e449de8456ec9bd6b20fe 100644 (file)
@@ -131,7 +131,10 @@ static int tcf_simp_init(struct nlattr *nla, struct nlattr *est,
                d = to_defact(pc);
                ret = alloc_defdata(d, defdata);
                if (ret < 0) {
-                       kfree(pc);
+                       if (est)
+                               gen_kill_estimator(&pc->tcfc_bstats,
+                                                  &pc->tcfc_rate_est);
+                       kfree_rcu(pc, tcfc_rcu);
                        return ret;
                }
                d->tcf_action = parm->action;
index 511323e89cecb221f9650d9d35e13c20d5d54b29..6c4d5fe53ce80ab534b34431f246a0ec4b48e055 100644 (file)
@@ -324,24 +324,6 @@ void netif_carrier_off(struct net_device *dev)
 }
 EXPORT_SYMBOL(netif_carrier_off);
 
-/**
- *     netif_notify_peers - notify network peers about existence of @dev
- *     @dev: network device
- *
- * Generate traffic such that interested network peers are aware of
- * @dev, such as by generating a gratuitous ARP. This may be used when
- * a device wants to inform the rest of the network about some sort of
- * reconfiguration such as a failover event or virtual machine
- * migration.
- */
-void netif_notify_peers(struct net_device *dev)
-{
-       rtnl_lock();
-       call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, dev);
-       rtnl_unlock();
-}
-EXPORT_SYMBOL(netif_notify_peers);
-
 /* "NOOP" scheduler: the best scheduler, recommended for all interfaces
    under all circumstances. It is difficult to invent anything faster or
    cheaper.
index 9af01f3df18c66b6325c8afe628758b56e306952..e4723d31fdd56d6a46b2519afd19d612c7336749 100644 (file)
@@ -203,6 +203,34 @@ out:
        return index;
 }
 
+/* Length of the next packet (0 if the queue is empty). */
+static unsigned int qdisc_peek_len(struct Qdisc *sch)
+{
+       struct sk_buff *skb;
+
+       skb = sch->ops->peek(sch);
+       return skb ? qdisc_pkt_len(skb) : 0;
+}
+
+static void qfq_deactivate_class(struct qfq_sched *, struct qfq_class *);
+static void qfq_activate_class(struct qfq_sched *q, struct qfq_class *cl,
+                              unsigned int len);
+
+static void qfq_update_class_params(struct qfq_sched *q, struct qfq_class *cl,
+                                   u32 lmax, u32 inv_w, int delta_w)
+{
+       int i;
+
+       /* update qfq-specific data */
+       cl->lmax = lmax;
+       cl->inv_w = inv_w;
+       i = qfq_calc_index(cl->inv_w, cl->lmax);
+
+       cl->grp = &q->groups[i];
+
+       q->wsum += delta_w;
+}
+
 static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
                            struct nlattr **tca, unsigned long *arg)
 {
@@ -250,6 +278,8 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
                lmax = 1UL << QFQ_MTU_SHIFT;
 
        if (cl != NULL) {
+               bool need_reactivation = false;
+
                if (tca[TCA_RATE]) {
                        err = gen_replace_estimator(&cl->bstats, &cl->rate_est,
                                                    qdisc_root_sleeping_lock(sch),
@@ -258,12 +288,29 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
                                return err;
                }
 
-               if (inv_w != cl->inv_w) {
-                       sch_tree_lock(sch);
-                       q->wsum += delta_w;
-                       cl->inv_w = inv_w;
-                       sch_tree_unlock(sch);
+               if (lmax == cl->lmax && inv_w == cl->inv_w)
+                       return 0; /* nothing to update */
+
+               i = qfq_calc_index(inv_w, lmax);
+               sch_tree_lock(sch);
+               if (&q->groups[i] != cl->grp && cl->qdisc->q.qlen > 0) {
+                       /*
+                        * shift cl->F back, to not charge the
+                        * class for the not-yet-served head
+                        * packet
+                        */
+                       cl->F = cl->S;
+                       /* remove class from its slot in the old group */
+                       qfq_deactivate_class(q, cl);
+                       need_reactivation = true;
                }
+
+               qfq_update_class_params(q, cl, lmax, inv_w, delta_w);
+
+               if (need_reactivation) /* activate in new group */
+                       qfq_activate_class(q, cl, qdisc_peek_len(cl->qdisc));
+               sch_tree_unlock(sch);
+
                return 0;
        }
 
@@ -273,11 +320,8 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
 
        cl->refcnt = 1;
        cl->common.classid = classid;
-       cl->lmax = lmax;
-       cl->inv_w = inv_w;
-       i = qfq_calc_index(cl->inv_w, cl->lmax);
 
-       cl->grp = &q->groups[i];
+       qfq_update_class_params(q, cl, lmax, inv_w, delta_w);
 
        cl->qdisc = qdisc_create_dflt(sch->dev_queue,
                                      &pfifo_qdisc_ops, classid);
@@ -294,7 +338,6 @@ static int qfq_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
                        return err;
                }
        }
-       q->wsum += weight;
 
        sch_tree_lock(sch);
        qdisc_class_hash_insert(&q->clhash, &cl->common);
@@ -711,15 +754,6 @@ static void qfq_update_eligible(struct qfq_sched *q, u64 old_V)
        }
 }
 
-/* What is length of next packet in queue (0 if queue is empty) */
-static unsigned int qdisc_peek_len(struct Qdisc *sch)
-{
-       struct sk_buff *skb;
-
-       skb = sch->ops->peek(sch);
-       return skb ? qdisc_pkt_len(skb) : 0;
-}
-
 /*
  * Updates the class, returns true if also the group needs to be updated.
  */
@@ -843,11 +877,8 @@ static void qfq_update_start(struct qfq_sched *q, struct qfq_class *cl)
 static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 {
        struct qfq_sched *q = qdisc_priv(sch);
-       struct qfq_group *grp;
        struct qfq_class *cl;
        int err;
-       u64 roundedS;
-       int s;
 
        cl = qfq_classify(skb, sch, &err);
        if (cl == NULL) {
@@ -876,11 +907,25 @@ static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
                return err;
 
        /* If reach this point, queue q was idle */
-       grp = cl->grp;
+       qfq_activate_class(q, cl, qdisc_pkt_len(skb));
+
+       return err;
+}
+
+/*
+ * Handle class switch from idle to backlogged.
+ */
+static void qfq_activate_class(struct qfq_sched *q, struct qfq_class *cl,
+                              unsigned int pkt_len)
+{
+       struct qfq_group *grp = cl->grp;
+       u64 roundedS;
+       int s;
+
        qfq_update_start(q, cl);
 
        /* compute new finish time and rounded start. */
-       cl->F = cl->S + (u64)qdisc_pkt_len(skb) * cl->inv_w;
+       cl->F = cl->S + (u64)pkt_len * cl->inv_w;
        roundedS = qfq_round_down(cl->S, grp->slot_shift);
 
        /*
@@ -917,8 +962,6 @@ static int qfq_enqueue(struct sk_buff *skb, struct Qdisc *sch)
 
 skip_update:
        qfq_slot_insert(grp, cl, roundedS);
-
-       return err;
 }
 
 
index ebaef3ed6065bee6d49880cde701ee49b26585e4..b1ef3bc301a5ad424fb041c0f6f37c010098bcc3 100644 (file)
@@ -82,6 +82,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
                                          sctp_scope_t scope,
                                          gfp_t gfp)
 {
+       struct net *net = sock_net(sk);
        struct sctp_sock *sp;
        int i;
        sctp_paramhdr_t *p;
@@ -124,7 +125,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
         * socket values.
         */
        asoc->max_retrans = sp->assocparams.sasoc_asocmaxrxt;
-       asoc->pf_retrans  = sctp_pf_retrans;
+       asoc->pf_retrans  = net->sctp.pf_retrans;
 
        asoc->rto_initial = msecs_to_jiffies(sp->rtoinfo.srto_initial);
        asoc->rto_max = msecs_to_jiffies(sp->rtoinfo.srto_max);
@@ -175,7 +176,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
        asoc->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] = 0;
        asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] = asoc->sackdelay;
        asoc->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] =
-               min_t(unsigned long, sp->autoclose, sctp_max_autoclose) * HZ;
+               min_t(unsigned long, sp->autoclose, net->sctp.max_autoclose) * HZ;
 
        /* Initializes the timers */
        for (i = SCTP_EVENT_TIMEOUT_NONE; i < SCTP_NUM_TIMEOUT_TYPES; ++i)
@@ -281,7 +282,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
         * and will revert old behavior.
         */
        asoc->peer.asconf_capable = 0;
-       if (sctp_addip_noauth)
+       if (net->sctp.addip_noauth)
                asoc->peer.asconf_capable = 1;
        asoc->asconf_addr_del_pending = NULL;
        asoc->src_out_of_asoc_ok = 0;
@@ -641,6 +642,7 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
                                           const gfp_t gfp,
                                           const int peer_state)
 {
+       struct net *net = sock_net(asoc->base.sk);
        struct sctp_transport *peer;
        struct sctp_sock *sp;
        unsigned short port;
@@ -674,7 +676,7 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
                return peer;
        }
 
-       peer = sctp_transport_new(addr, gfp);
+       peer = sctp_transport_new(net, addr, gfp);
        if (!peer)
                return NULL;
 
@@ -1089,13 +1091,15 @@ out:
 
 /* Is this the association we are looking for? */
 struct sctp_transport *sctp_assoc_is_match(struct sctp_association *asoc,
+                                          struct net *net,
                                           const union sctp_addr *laddr,
                                           const union sctp_addr *paddr)
 {
        struct sctp_transport *transport;
 
        if ((htons(asoc->base.bind_addr.port) == laddr->v4.sin_port) &&
-           (htons(asoc->peer.port) == paddr->v4.sin_port)) {
+           (htons(asoc->peer.port) == paddr->v4.sin_port) &&
+           net_eq(sock_net(asoc->base.sk), net)) {
                transport = sctp_assoc_lookup_paddr(asoc, paddr);
                if (!transport)
                        goto out;
@@ -1116,6 +1120,7 @@ static void sctp_assoc_bh_rcv(struct work_struct *work)
        struct sctp_association *asoc =
                container_of(work, struct sctp_association,
                             base.inqueue.immediate);
+       struct net *net = sock_net(asoc->base.sk);
        struct sctp_endpoint *ep;
        struct sctp_chunk *chunk;
        struct sctp_inq *inqueue;
@@ -1148,13 +1153,13 @@ static void sctp_assoc_bh_rcv(struct work_struct *work)
                if (sctp_chunk_is_data(chunk))
                        asoc->peer.last_data_from = chunk->transport;
                else
-                       SCTP_INC_STATS(SCTP_MIB_INCTRLCHUNKS);
+                       SCTP_INC_STATS(net, SCTP_MIB_INCTRLCHUNKS);
 
                if (chunk->transport)
                        chunk->transport->last_time_heard = jiffies;
 
                /* Run through the state machine. */
-               error = sctp_do_sm(SCTP_EVENT_T_CHUNK, subtype,
+               error = sctp_do_sm(net, SCTP_EVENT_T_CHUNK, subtype,
                                   state, ep, asoc, chunk, GFP_ATOMIC);
 
                /* Check to see if the association is freed in response to
@@ -1414,6 +1419,7 @@ void sctp_assoc_sync_pmtu(struct sock *sk, struct sctp_association *asoc)
 /* Should we send a SACK to update our peer? */
 static inline int sctp_peer_needs_update(struct sctp_association *asoc)
 {
+       struct net *net = sock_net(asoc->base.sk);
        switch (asoc->state) {
        case SCTP_STATE_ESTABLISHED:
        case SCTP_STATE_SHUTDOWN_PENDING:
@@ -1421,7 +1427,7 @@ static inline int sctp_peer_needs_update(struct sctp_association *asoc)
        case SCTP_STATE_SHUTDOWN_SENT:
                if ((asoc->rwnd > asoc->a_rwnd) &&
                    ((asoc->rwnd - asoc->a_rwnd) >= max_t(__u32,
-                          (asoc->base.sk->sk_rcvbuf >> sctp_rwnd_upd_shift),
+                          (asoc->base.sk->sk_rcvbuf >> net->sctp.rwnd_upd_shift),
                           asoc->pathmtu)))
                        return 1;
                break;
@@ -1542,7 +1548,8 @@ int sctp_assoc_set_bind_addr_from_ep(struct sctp_association *asoc,
        if (asoc->peer.ipv6_address)
                flags |= SCTP_ADDR6_PEERSUPP;
 
-       return sctp_bind_addr_copy(&asoc->base.bind_addr,
+       return sctp_bind_addr_copy(sock_net(asoc->base.sk),
+                                  &asoc->base.bind_addr,
                                   &asoc->ep->base.bind_addr,
                                   scope, gfp, flags);
 }
index bf812048cf6f7a244c547e0cd31a731351abfab3..159b9bc5d63300e53560cf6495f8f65b9fd06449 100644 (file)
@@ -392,13 +392,14 @@ nomem:
  */
 int sctp_auth_asoc_init_active_key(struct sctp_association *asoc, gfp_t gfp)
 {
+       struct net *net = sock_net(asoc->base.sk);
        struct sctp_auth_bytes  *secret;
        struct sctp_shared_key *ep_key;
 
        /* If we don't support AUTH, or peer is not capable
         * we don't need to do anything.
         */
-       if (!sctp_auth_enable || !asoc->peer.auth_capable)
+       if (!net->sctp.auth_enable || !asoc->peer.auth_capable)
                return 0;
 
        /* If the key_id is non-zero and we couldn't find an
@@ -445,11 +446,12 @@ struct sctp_shared_key *sctp_auth_get_shkey(
  */
 int sctp_auth_init_hmacs(struct sctp_endpoint *ep, gfp_t gfp)
 {
+       struct net *net = sock_net(ep->base.sk);
        struct crypto_hash *tfm = NULL;
        __u16   id;
 
        /* if the transforms are already allocted, we are done */
-       if (!sctp_auth_enable) {
+       if (!net->sctp.auth_enable) {
                ep->auth_hmacs = NULL;
                return 0;
        }
@@ -674,7 +676,12 @@ static int __sctp_auth_cid(sctp_cid_t chunk, struct sctp_chunks_param *param)
 /* Check if peer requested that this chunk is authenticated */
 int sctp_auth_send_cid(sctp_cid_t chunk, const struct sctp_association *asoc)
 {
-       if (!sctp_auth_enable || !asoc || !asoc->peer.auth_capable)
+       struct net  *net;
+       if (!asoc)
+               return 0;
+
+       net = sock_net(asoc->base.sk);
+       if (!net->sctp.auth_enable || !asoc->peer.auth_capable)
                return 0;
 
        return __sctp_auth_cid(chunk, asoc->peer.peer_chunks);
@@ -683,7 +690,12 @@ int sctp_auth_send_cid(sctp_cid_t chunk, const struct sctp_association *asoc)
 /* Check if we requested that peer authenticate this chunk. */
 int sctp_auth_recv_cid(sctp_cid_t chunk, const struct sctp_association *asoc)
 {
-       if (!sctp_auth_enable || !asoc)
+       struct net *net;
+       if (!asoc)
+               return 0;
+
+       net = sock_net(asoc->base.sk);
+       if (!net->sctp.auth_enable)
                return 0;
 
        return __sctp_auth_cid(chunk,
index 4ece451c8d27d59ba2a73fba1baf6cb8ca19fe4e..d886b3bf84f5a1823e208d3c784db05a6c88938a 100644 (file)
@@ -52,8 +52,8 @@
 #include <net/sctp/sm.h>
 
 /* Forward declarations for internal helpers. */
-static int sctp_copy_one_addr(struct sctp_bind_addr *, union sctp_addr *,
-                             sctp_scope_t scope, gfp_t gfp,
+static int sctp_copy_one_addr(struct net *, struct sctp_bind_addr *,
+                             union sctp_addr *, sctp_scope_t scope, gfp_t gfp,
                              int flags);
 static void sctp_bind_addr_clean(struct sctp_bind_addr *);
 
@@ -62,7 +62,7 @@ static void sctp_bind_addr_clean(struct sctp_bind_addr *);
 /* Copy 'src' to 'dest' taking 'scope' into account.  Omit addresses
  * in 'src' which have a broader scope than 'scope'.
  */
-int sctp_bind_addr_copy(struct sctp_bind_addr *dest,
+int sctp_bind_addr_copy(struct net *net, struct sctp_bind_addr *dest,
                        const struct sctp_bind_addr *src,
                        sctp_scope_t scope, gfp_t gfp,
                        int flags)
@@ -75,7 +75,7 @@ int sctp_bind_addr_copy(struct sctp_bind_addr *dest,
 
        /* Extract the addresses which are relevant for this scope.  */
        list_for_each_entry(addr, &src->address_list, list) {
-               error = sctp_copy_one_addr(dest, &addr->a, scope,
+               error = sctp_copy_one_addr(net, dest, &addr->a, scope,
                                           gfp, flags);
                if (error < 0)
                        goto out;
@@ -87,7 +87,7 @@ int sctp_bind_addr_copy(struct sctp_bind_addr *dest,
         */
        if (list_empty(&dest->address_list) && (SCTP_SCOPE_GLOBAL == scope)) {
                list_for_each_entry(addr, &src->address_list, list) {
-                       error = sctp_copy_one_addr(dest, &addr->a,
+                       error = sctp_copy_one_addr(net, dest, &addr->a,
                                                   SCTP_SCOPE_LINK, gfp,
                                                   flags);
                        if (error < 0)
@@ -448,7 +448,7 @@ union sctp_addr *sctp_find_unmatch_addr(struct sctp_bind_addr       *bp,
 }
 
 /* Copy out addresses from the global local address list. */
-static int sctp_copy_one_addr(struct sctp_bind_addr *dest,
+static int sctp_copy_one_addr(struct net *net, struct sctp_bind_addr *dest,
                              union sctp_addr *addr,
                              sctp_scope_t scope, gfp_t gfp,
                              int flags)
@@ -456,8 +456,8 @@ static int sctp_copy_one_addr(struct sctp_bind_addr *dest,
        int error = 0;
 
        if (sctp_is_any(NULL, addr)) {
-               error = sctp_copy_local_addr_list(dest, scope, gfp, flags);
-       } else if (sctp_in_scope(addr, scope)) {
+               error = sctp_copy_local_addr_list(net, dest, scope, gfp, flags);
+       } else if (sctp_in_scope(net, addr, scope)) {
                /* Now that the address is in scope, check to see if
                 * the address type is supported by local sock as
                 * well as the remote peer.
@@ -494,7 +494,7 @@ int sctp_is_any(struct sock *sk, const union sctp_addr *addr)
 }
 
 /* Is 'addr' valid for 'scope'?  */
-int sctp_in_scope(const union sctp_addr *addr, sctp_scope_t scope)
+int sctp_in_scope(struct net *net, const union sctp_addr *addr, sctp_scope_t scope)
 {
        sctp_scope_t addr_scope = sctp_scope(addr);
 
@@ -512,7 +512,7 @@ int sctp_in_scope(const union sctp_addr *addr, sctp_scope_t scope)
         * Address scoping can be selectively controlled via sysctl
         * option
         */
-       switch (sctp_scope_policy) {
+       switch (net->sctp.scope_policy) {
        case SCTP_SCOPE_POLICY_DISABLE:
                return 1;
        case SCTP_SCOPE_POLICY_ENABLE:
index 6c8556459a751b3e2faa6b0442b804396ff6de7e..7c2df9c33df37a588c426e7945cd71233edd4577 100644 (file)
@@ -257,7 +257,7 @@ struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
        offset = 0;
 
        if ((whole > 1) || (whole && over))
-               SCTP_INC_STATS_USER(SCTP_MIB_FRAGUSRMSGS);
+               SCTP_INC_STATS_USER(sock_net(asoc->base.sk), SCTP_MIB_FRAGUSRMSGS);
 
        /* Create chunks for all the full sized DATA chunks. */
        for (i=0, len=first_len; i < whole; i++) {
index 68a385d7c3bdaaab2ebed8c7f4bec94dc53d4c79..1859e2bc83d113d1a14d01f904475b01099e0626 100644 (file)
@@ -65,6 +65,7 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
                                                struct sock *sk,
                                                gfp_t gfp)
 {
+       struct net *net = sock_net(sk);
        struct sctp_hmac_algo_param *auth_hmacs = NULL;
        struct sctp_chunks_param *auth_chunks = NULL;
        struct sctp_shared_key *null_key;
@@ -74,7 +75,7 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
        if (!ep->digest)
                return NULL;
 
-       if (sctp_auth_enable) {
+       if (net->sctp.auth_enable) {
                /* Allocate space for HMACS and CHUNKS authentication
                 * variables.  There are arrays that we encode directly
                 * into parameters to make the rest of the operations easier.
@@ -106,7 +107,7 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
                /* If the Add-IP functionality is enabled, we must
                 * authenticate, ASCONF and ASCONF-ACK chunks
                 */
-               if (sctp_addip_enable) {
+               if (net->sctp.addip_enable) {
                        auth_chunks->chunks[0] = SCTP_CID_ASCONF;
                        auth_chunks->chunks[1] = SCTP_CID_ASCONF_ACK;
                        auth_chunks->param_hdr.length =
@@ -140,14 +141,14 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
        INIT_LIST_HEAD(&ep->asocs);
 
        /* Use SCTP specific send buffer space queues.  */
-       ep->sndbuf_policy = sctp_sndbuf_policy;
+       ep->sndbuf_policy = net->sctp.sndbuf_policy;
 
        sk->sk_data_ready = sctp_data_ready;
        sk->sk_write_space = sctp_write_space;
        sock_set_flag(sk, SOCK_USE_WRITE_QUEUE);
 
        /* Get the receive buffer policy for this endpoint */
-       ep->rcvbuf_policy = sctp_rcvbuf_policy;
+       ep->rcvbuf_policy = net->sctp.rcvbuf_policy;
 
        /* Initialize the secret key used with cookie. */
        get_random_bytes(&ep->secret_key[0], SCTP_SECRET_SIZE);
@@ -302,11 +303,13 @@ void sctp_endpoint_put(struct sctp_endpoint *ep)
 
 /* Is this the endpoint we are looking for?  */
 struct sctp_endpoint *sctp_endpoint_is_match(struct sctp_endpoint *ep,
+                                              struct net *net,
                                               const union sctp_addr *laddr)
 {
        struct sctp_endpoint *retval = NULL;
 
-       if (htons(ep->base.bind_addr.port) == laddr->v4.sin_port) {
+       if ((htons(ep->base.bind_addr.port) == laddr->v4.sin_port) &&
+           net_eq(sock_net(ep->base.sk), net)) {
                if (sctp_bind_addr_match(&ep->base.bind_addr, laddr,
                                         sctp_sk(ep->base.sk)))
                        retval = ep;
@@ -343,7 +346,8 @@ static struct sctp_association *__sctp_endpoint_lookup_assoc(
 
        rport = ntohs(paddr->v4.sin_port);
 
-       hash = sctp_assoc_hashfn(ep->base.bind_addr.port, rport);
+       hash = sctp_assoc_hashfn(sock_net(ep->base.sk), ep->base.bind_addr.port,
+                                rport);
        head = &sctp_assoc_hashtable[hash];
        read_lock(&head->lock);
        sctp_for_each_hentry(epb, node, &head->chain) {
@@ -386,13 +390,14 @@ int sctp_endpoint_is_peeled_off(struct sctp_endpoint *ep,
 {
        struct sctp_sockaddr_entry *addr;
        struct sctp_bind_addr *bp;
+       struct net *net = sock_net(ep->base.sk);
 
        bp = &ep->base.bind_addr;
        /* This function is called with the socket lock held,
         * so the address_list can not change.
         */
        list_for_each_entry(addr, &bp->address_list, list) {
-               if (sctp_has_association(&addr->a, paddr))
+               if (sctp_has_association(net, &addr->a, paddr))
                        return 1;
        }
 
@@ -409,6 +414,7 @@ static void sctp_endpoint_bh_rcv(struct work_struct *work)
                             base.inqueue.immediate);
        struct sctp_association *asoc;
        struct sock *sk;
+       struct net *net;
        struct sctp_transport *transport;
        struct sctp_chunk *chunk;
        struct sctp_inq *inqueue;
@@ -423,6 +429,7 @@ static void sctp_endpoint_bh_rcv(struct work_struct *work)
        asoc = NULL;
        inqueue = &ep->base.inqueue;
        sk = ep->base.sk;
+       net = sock_net(sk);
 
        while (NULL != (chunk = sctp_inq_pop(inqueue))) {
                subtype = SCTP_ST_CHUNK(chunk->chunk_hdr->type);
@@ -474,12 +481,12 @@ normal:
                if (asoc && sctp_chunk_is_data(chunk))
                        asoc->peer.last_data_from = chunk->transport;
                else
-                       SCTP_INC_STATS(SCTP_MIB_INCTRLCHUNKS);
+                       SCTP_INC_STATS(sock_net(ep->base.sk), SCTP_MIB_INCTRLCHUNKS);
 
                if (chunk->transport)
                        chunk->transport->last_time_heard = jiffies;
 
-               error = sctp_do_sm(SCTP_EVENT_T_CHUNK, subtype, state,
+               error = sctp_do_sm(net, SCTP_EVENT_T_CHUNK, subtype, state,
                                   ep, asoc, chunk, GFP_ATOMIC);
 
                if (error && chunk)
index e64d5210ed130610402b261218360adc5295102c..25dfe7380479e9598e5732a753349e324aea463a 100644 (file)
 
 /* Forward declarations for internal helpers. */
 static int sctp_rcv_ootb(struct sk_buff *);
-static struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb,
+static struct sctp_association *__sctp_rcv_lookup(struct net *net,
+                                     struct sk_buff *skb,
                                      const union sctp_addr *laddr,
                                      const union sctp_addr *paddr,
                                      struct sctp_transport **transportp);
-static struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr);
+static struct sctp_endpoint *__sctp_rcv_lookup_endpoint(struct net *net,
+                                               const union sctp_addr *laddr);
 static struct sctp_association *__sctp_lookup_association(
+                                       struct net *net,
                                        const union sctp_addr *local,
                                        const union sctp_addr *peer,
                                        struct sctp_transport **pt);
@@ -80,7 +83,7 @@ static int sctp_add_backlog(struct sock *sk, struct sk_buff *skb);
 
 
 /* Calculate the SCTP checksum of an SCTP packet.  */
-static inline int sctp_rcv_checksum(struct sk_buff *skb)
+static inline int sctp_rcv_checksum(struct net *net, struct sk_buff *skb)
 {
        struct sctphdr *sh = sctp_hdr(skb);
        __le32 cmp = sh->checksum;
@@ -96,7 +99,7 @@ static inline int sctp_rcv_checksum(struct sk_buff *skb)
 
        if (val != cmp) {
                /* CRC failure, dump it. */
-               SCTP_INC_STATS_BH(SCTP_MIB_CHECKSUMERRORS);
+               SCTP_INC_STATS_BH(net, SCTP_MIB_CHECKSUMERRORS);
                return -1;
        }
        return 0;
@@ -129,11 +132,12 @@ int sctp_rcv(struct sk_buff *skb)
        union sctp_addr dest;
        int family;
        struct sctp_af *af;
+       struct net *net = dev_net(skb->dev);
 
        if (skb->pkt_type!=PACKET_HOST)
                goto discard_it;
 
-       SCTP_INC_STATS_BH(SCTP_MIB_INSCTPPACKS);
+       SCTP_INC_STATS_BH(net, SCTP_MIB_INSCTPPACKS);
 
        if (skb_linearize(skb))
                goto discard_it;
@@ -145,7 +149,7 @@ int sctp_rcv(struct sk_buff *skb)
        if (skb->len < sizeof(struct sctphdr))
                goto discard_it;
        if (!sctp_checksum_disable && !skb_csum_unnecessary(skb) &&
-                 sctp_rcv_checksum(skb) < 0)
+                 sctp_rcv_checksum(net, skb) < 0)
                goto discard_it;
 
        skb_pull(skb, sizeof(struct sctphdr));
@@ -178,10 +182,10 @@ int sctp_rcv(struct sk_buff *skb)
            !af->addr_valid(&dest, NULL, skb))
                goto discard_it;
 
-       asoc = __sctp_rcv_lookup(skb, &src, &dest, &transport);
+       asoc = __sctp_rcv_lookup(net, skb, &src, &dest, &transport);
 
        if (!asoc)
-               ep = __sctp_rcv_lookup_endpoint(&dest);
+               ep = __sctp_rcv_lookup_endpoint(net, &dest);
 
        /* Retrieve the common input handling substructure. */
        rcvr = asoc ? &asoc->base : &ep->base;
@@ -200,7 +204,7 @@ int sctp_rcv(struct sk_buff *skb)
                        sctp_endpoint_put(ep);
                        ep = NULL;
                }
-               sk = sctp_get_ctl_sock();
+               sk = net->sctp.ctl_sock;
                ep = sctp_sk(sk)->ep;
                sctp_endpoint_hold(ep);
                rcvr = &ep->base;
@@ -216,7 +220,7 @@ int sctp_rcv(struct sk_buff *skb)
         */
        if (!asoc) {
                if (sctp_rcv_ootb(skb)) {
-                       SCTP_INC_STATS_BH(SCTP_MIB_OUTOFBLUES);
+                       SCTP_INC_STATS_BH(net, SCTP_MIB_OUTOFBLUES);
                        goto discard_release;
                }
        }
@@ -272,9 +276,9 @@ int sctp_rcv(struct sk_buff *skb)
                        skb = NULL; /* sctp_chunk_free already freed the skb */
                        goto discard_release;
                }
-               SCTP_INC_STATS_BH(SCTP_MIB_IN_PKT_BACKLOG);
+               SCTP_INC_STATS_BH(net, SCTP_MIB_IN_PKT_BACKLOG);
        } else {
-               SCTP_INC_STATS_BH(SCTP_MIB_IN_PKT_SOFTIRQ);
+               SCTP_INC_STATS_BH(net, SCTP_MIB_IN_PKT_SOFTIRQ);
                sctp_inq_push(&chunk->rcvr->inqueue, chunk);
        }
 
@@ -289,7 +293,7 @@ int sctp_rcv(struct sk_buff *skb)
        return 0;
 
 discard_it:
-       SCTP_INC_STATS_BH(SCTP_MIB_IN_PKT_DISCARDS);
+       SCTP_INC_STATS_BH(net, SCTP_MIB_IN_PKT_DISCARDS);
        kfree_skb(skb);
        return 0;
 
@@ -462,11 +466,13 @@ void sctp_icmp_proto_unreachable(struct sock *sk,
                }
                        
        } else {
+               struct net *net = sock_net(sk);
+
                if (timer_pending(&t->proto_unreach_timer) &&
                    del_timer(&t->proto_unreach_timer))
                        sctp_association_put(asoc);
 
-               sctp_do_sm(SCTP_EVENT_T_OTHER,
+               sctp_do_sm(net, SCTP_EVENT_T_OTHER,
                           SCTP_ST_OTHER(SCTP_EVENT_ICMP_PROTO_UNREACH),
                           asoc->state, asoc->ep, asoc, t,
                           GFP_ATOMIC);
@@ -474,7 +480,7 @@ void sctp_icmp_proto_unreachable(struct sock *sk,
 }
 
 /* Common lookup code for icmp/icmpv6 error handler. */
-struct sock *sctp_err_lookup(int family, struct sk_buff *skb,
+struct sock *sctp_err_lookup(struct net *net, int family, struct sk_buff *skb,
                             struct sctphdr *sctphdr,
                             struct sctp_association **app,
                             struct sctp_transport **tpp)
@@ -503,7 +509,7 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *skb,
        /* Look for an association that matches the incoming ICMP error
         * packet.
         */
-       asoc = __sctp_lookup_association(&saddr, &daddr, &transport);
+       asoc = __sctp_lookup_association(net, &saddr, &daddr, &transport);
        if (!asoc)
                return NULL;
 
@@ -539,7 +545,7 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *skb,
         * servers this needs to be solved differently.
         */
        if (sock_owned_by_user(sk))
-               NET_INC_STATS_BH(&init_net, LINUX_MIB_LOCKDROPPEDICMPS);
+               NET_INC_STATS_BH(net, LINUX_MIB_LOCKDROPPEDICMPS);
 
        *app = asoc;
        *tpp = transport;
@@ -586,9 +592,10 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info)
        struct inet_sock *inet;
        sk_buff_data_t saveip, savesctp;
        int err;
+       struct net *net = dev_net(skb->dev);
 
        if (skb->len < ihlen + 8) {
-               ICMP_INC_STATS_BH(&init_net, ICMP_MIB_INERRORS);
+               ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS);
                return;
        }
 
@@ -597,12 +604,12 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info)
        savesctp = skb->transport_header;
        skb_reset_network_header(skb);
        skb_set_transport_header(skb, ihlen);
-       sk = sctp_err_lookup(AF_INET, skb, sctp_hdr(skb), &asoc, &transport);
+       sk = sctp_err_lookup(net, AF_INET, skb, sctp_hdr(skb), &asoc, &transport);
        /* Put back, the original values. */
        skb->network_header = saveip;
        skb->transport_header = savesctp;
        if (!sk) {
-               ICMP_INC_STATS_BH(&init_net, ICMP_MIB_INERRORS);
+               ICMP_INC_STATS_BH(net, ICMP_MIB_INERRORS);
                return;
        }
        /* Warning:  The sock lock is held.  Remember to call
@@ -723,12 +730,13 @@ discard:
 /* Insert endpoint into the hash table.  */
 static void __sctp_hash_endpoint(struct sctp_endpoint *ep)
 {
+       struct net *net = sock_net(ep->base.sk);
        struct sctp_ep_common *epb;
        struct sctp_hashbucket *head;
 
        epb = &ep->base;
 
-       epb->hashent = sctp_ep_hashfn(epb->bind_addr.port);
+       epb->hashent = sctp_ep_hashfn(net, epb->bind_addr.port);
        head = &sctp_ep_hashtable[epb->hashent];
 
        sctp_write_lock(&head->lock);
@@ -747,12 +755,13 @@ void sctp_hash_endpoint(struct sctp_endpoint *ep)
 /* Remove endpoint from the hash table.  */
 static void __sctp_unhash_endpoint(struct sctp_endpoint *ep)
 {
+       struct net *net = sock_net(ep->base.sk);
        struct sctp_hashbucket *head;
        struct sctp_ep_common *epb;
 
        epb = &ep->base;
 
-       epb->hashent = sctp_ep_hashfn(epb->bind_addr.port);
+       epb->hashent = sctp_ep_hashfn(net, epb->bind_addr.port);
 
        head = &sctp_ep_hashtable[epb->hashent];
 
@@ -770,7 +779,8 @@ void sctp_unhash_endpoint(struct sctp_endpoint *ep)
 }
 
 /* Look up an endpoint. */
-static struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr)
+static struct sctp_endpoint *__sctp_rcv_lookup_endpoint(struct net *net,
+                                               const union sctp_addr *laddr)
 {
        struct sctp_hashbucket *head;
        struct sctp_ep_common *epb;
@@ -778,16 +788,16 @@ static struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *l
        struct hlist_node *node;
        int hash;
 
-       hash = sctp_ep_hashfn(ntohs(laddr->v4.sin_port));
+       hash = sctp_ep_hashfn(net, ntohs(laddr->v4.sin_port));
        head = &sctp_ep_hashtable[hash];
        read_lock(&head->lock);
        sctp_for_each_hentry(epb, node, &head->chain) {
                ep = sctp_ep(epb);
-               if (sctp_endpoint_is_match(ep, laddr))
+               if (sctp_endpoint_is_match(ep, net, laddr))
                        goto hit;
        }
 
-       ep = sctp_sk((sctp_get_ctl_sock()))->ep;
+       ep = sctp_sk(net->sctp.ctl_sock)->ep;
 
 hit:
        sctp_endpoint_hold(ep);
@@ -798,13 +808,15 @@ hit:
 /* Insert association into the hash table.  */
 static void __sctp_hash_established(struct sctp_association *asoc)
 {
+       struct net *net = sock_net(asoc->base.sk);
        struct sctp_ep_common *epb;
        struct sctp_hashbucket *head;
 
        epb = &asoc->base;
 
        /* Calculate which chain this entry will belong to. */
-       epb->hashent = sctp_assoc_hashfn(epb->bind_addr.port, asoc->peer.port);
+       epb->hashent = sctp_assoc_hashfn(net, epb->bind_addr.port,
+                                        asoc->peer.port);
 
        head = &sctp_assoc_hashtable[epb->hashent];
 
@@ -827,12 +839,13 @@ void sctp_hash_established(struct sctp_association *asoc)
 /* Remove association from the hash table.  */
 static void __sctp_unhash_established(struct sctp_association *asoc)
 {
+       struct net *net = sock_net(asoc->base.sk);
        struct sctp_hashbucket *head;
        struct sctp_ep_common *epb;
 
        epb = &asoc->base;
 
-       epb->hashent = sctp_assoc_hashfn(epb->bind_addr.port,
+       epb->hashent = sctp_assoc_hashfn(net, epb->bind_addr.port,
                                         asoc->peer.port);
 
        head = &sctp_assoc_hashtable[epb->hashent];
@@ -855,6 +868,7 @@ void sctp_unhash_established(struct sctp_association *asoc)
 
 /* Look up an association. */
 static struct sctp_association *__sctp_lookup_association(
+                                       struct net *net,
                                        const union sctp_addr *local,
                                        const union sctp_addr *peer,
                                        struct sctp_transport **pt)
@@ -869,12 +883,13 @@ static struct sctp_association *__sctp_lookup_association(
        /* Optimize here for direct hit, only listening connections can
         * have wildcards anyways.
         */
-       hash = sctp_assoc_hashfn(ntohs(local->v4.sin_port), ntohs(peer->v4.sin_port));
+       hash = sctp_assoc_hashfn(net, ntohs(local->v4.sin_port),
+                                ntohs(peer->v4.sin_port));
        head = &sctp_assoc_hashtable[hash];
        read_lock(&head->lock);
        sctp_for_each_hentry(epb, node, &head->chain) {
                asoc = sctp_assoc(epb);
-               transport = sctp_assoc_is_match(asoc, local, peer);
+               transport = sctp_assoc_is_match(asoc, net, local, peer);
                if (transport)
                        goto hit;
        }
@@ -892,27 +907,29 @@ hit:
 
 /* Look up an association. BH-safe. */
 SCTP_STATIC
-struct sctp_association *sctp_lookup_association(const union sctp_addr *laddr,
+struct sctp_association *sctp_lookup_association(struct net *net,
+                                                const union sctp_addr *laddr,
                                                 const union sctp_addr *paddr,
                                            struct sctp_transport **transportp)
 {
        struct sctp_association *asoc;
 
        sctp_local_bh_disable();
-       asoc = __sctp_lookup_association(laddr, paddr, transportp);
+       asoc = __sctp_lookup_association(net, laddr, paddr, transportp);
        sctp_local_bh_enable();
 
        return asoc;
 }
 
 /* Is there an association matching the given local and peer addresses? */
-int sctp_has_association(const union sctp_addr *laddr,
+int sctp_has_association(struct net *net,
+                        const union sctp_addr *laddr,
                         const union sctp_addr *paddr)
 {
        struct sctp_association *asoc;
        struct sctp_transport *transport;
 
-       if ((asoc = sctp_lookup_association(laddr, paddr, &transport))) {
+       if ((asoc = sctp_lookup_association(net, laddr, paddr, &transport))) {
                sctp_association_put(asoc);
                return 1;
        }
@@ -938,7 +955,8 @@ int sctp_has_association(const union sctp_addr *laddr,
  * in certain circumstances.
  *
  */
-static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb,
+static struct sctp_association *__sctp_rcv_init_lookup(struct net *net,
+       struct sk_buff *skb,
        const union sctp_addr *laddr, struct sctp_transport **transportp)
 {
        struct sctp_association *asoc;
@@ -978,7 +996,7 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb,
 
                af->from_addr_param(paddr, params.addr, sh->source, 0);
 
-               asoc = __sctp_lookup_association(laddr, paddr, &transport);
+               asoc = __sctp_lookup_association(net, laddr, paddr, &transport);
                if (asoc)
                        return asoc;
        }
@@ -1001,6 +1019,7 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb,
  * subsequent ASCONF Chunks. If found, proceed to rule D4.
  */
 static struct sctp_association *__sctp_rcv_asconf_lookup(
+                                       struct net *net,
                                        sctp_chunkhdr_t *ch,
                                        const union sctp_addr *laddr,
                                        __be16 peer_port,
@@ -1020,7 +1039,7 @@ static struct sctp_association *__sctp_rcv_asconf_lookup(
 
        af->from_addr_param(&paddr, param, peer_port, 0);
 
-       return __sctp_lookup_association(laddr, &paddr, transportp);
+       return __sctp_lookup_association(net, laddr, &paddr, transportp);
 }
 
 
@@ -1033,7 +1052,8 @@ static struct sctp_association *__sctp_rcv_asconf_lookup(
 * This means that any chunks that can help us identify the association need
 * to be looked at to find this association.
 */
-static struct sctp_association *__sctp_rcv_walk_lookup(struct sk_buff *skb,
+static struct sctp_association *__sctp_rcv_walk_lookup(struct net *net,
+                                     struct sk_buff *skb,
                                      const union sctp_addr *laddr,
                                      struct sctp_transport **transportp)
 {
@@ -1074,8 +1094,9 @@ static struct sctp_association *__sctp_rcv_walk_lookup(struct sk_buff *skb,
                            break;
 
                    case SCTP_CID_ASCONF:
-                           if (have_auth || sctp_addip_noauth)
-                                   asoc = __sctp_rcv_asconf_lookup(ch, laddr,
+                           if (have_auth || net->sctp.addip_noauth)
+                                   asoc = __sctp_rcv_asconf_lookup(
+                                                       net, ch, laddr,
                                                        sctp_hdr(skb)->source,
                                                        transportp);
                    default:
@@ -1098,7 +1119,8 @@ static struct sctp_association *__sctp_rcv_walk_lookup(struct sk_buff *skb,
  * include looking inside of INIT/INIT-ACK chunks or after the AUTH
  * chunks.
  */
-static struct sctp_association *__sctp_rcv_lookup_harder(struct sk_buff *skb,
+static struct sctp_association *__sctp_rcv_lookup_harder(struct net *net,
+                                     struct sk_buff *skb,
                                      const union sctp_addr *laddr,
                                      struct sctp_transport **transportp)
 {
@@ -1118,11 +1140,11 @@ static struct sctp_association *__sctp_rcv_lookup_harder(struct sk_buff *skb,
        switch (ch->type) {
        case SCTP_CID_INIT:
        case SCTP_CID_INIT_ACK:
-               return __sctp_rcv_init_lookup(skb, laddr, transportp);
+               return __sctp_rcv_init_lookup(net, skb, laddr, transportp);
                break;
 
        default:
-               return __sctp_rcv_walk_lookup(skb, laddr, transportp);
+               return __sctp_rcv_walk_lookup(net, skb, laddr, transportp);
                break;
        }
 
@@ -1131,21 +1153,22 @@ static struct sctp_association *__sctp_rcv_lookup_harder(struct sk_buff *skb,
 }
 
 /* Lookup an association for an inbound skb. */
-static struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb,
+static struct sctp_association *__sctp_rcv_lookup(struct net *net,
+                                     struct sk_buff *skb,
                                      const union sctp_addr *paddr,
                                      const union sctp_addr *laddr,
                                      struct sctp_transport **transportp)
 {
        struct sctp_association *asoc;
 
-       asoc = __sctp_lookup_association(laddr, paddr, transportp);
+       asoc = __sctp_lookup_association(net, laddr, paddr, transportp);
 
        /* Further lookup for INIT/INIT-ACK packets.
         * SCTP Implementors Guide, 2.18 Handling of address
         * parameters within the INIT or INIT-ACK.
         */
        if (!asoc)
-               asoc = __sctp_rcv_lookup_harder(skb, laddr, transportp);
+               asoc = __sctp_rcv_lookup_harder(net, skb, laddr, transportp);
 
        return asoc;
 }
index ed7139ea7978dc664f6dfbff33977cf31bbc4325..ea14cb44529528124e2bdd24988a59f1cacc2569 100644 (file)
@@ -99,6 +99,7 @@ static int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev,
        struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr;
        struct sctp_sockaddr_entry *addr = NULL;
        struct sctp_sockaddr_entry *temp;
+       struct net *net = dev_net(ifa->idev->dev);
        int found = 0;
 
        switch (ev) {
@@ -110,27 +111,27 @@ static int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev,
                        addr->a.v6.sin6_addr = ifa->addr;
                        addr->a.v6.sin6_scope_id = ifa->idev->dev->ifindex;
                        addr->valid = 1;
-                       spin_lock_bh(&sctp_local_addr_lock);
-                       list_add_tail_rcu(&addr->list, &sctp_local_addr_list);
-                       sctp_addr_wq_mgmt(addr, SCTP_ADDR_NEW);
-                       spin_unlock_bh(&sctp_local_addr_lock);
+                       spin_lock_bh(&net->sctp.local_addr_lock);
+                       list_add_tail_rcu(&addr->list, &net->sctp.local_addr_list);
+                       sctp_addr_wq_mgmt(net, addr, SCTP_ADDR_NEW);
+                       spin_unlock_bh(&net->sctp.local_addr_lock);
                }
                break;
        case NETDEV_DOWN:
-               spin_lock_bh(&sctp_local_addr_lock);
+               spin_lock_bh(&net->sctp.local_addr_lock);
                list_for_each_entry_safe(addr, temp,
-                                       &sctp_local_addr_list, list) {
+                                       &net->sctp.local_addr_list, list) {
                        if (addr->a.sa.sa_family == AF_INET6 &&
                                        ipv6_addr_equal(&addr->a.v6.sin6_addr,
                                                &ifa->addr)) {
-                               sctp_addr_wq_mgmt(addr, SCTP_ADDR_DEL);
+                               sctp_addr_wq_mgmt(net, addr, SCTP_ADDR_DEL);
                                found = 1;
                                addr->valid = 0;
                                list_del_rcu(&addr->list);
                                break;
                        }
                }
-               spin_unlock_bh(&sctp_local_addr_lock);
+               spin_unlock_bh(&net->sctp.local_addr_lock);
                if (found)
                        kfree_rcu(addr, rcu);
                break;
@@ -154,6 +155,7 @@ SCTP_STATIC void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        struct ipv6_pinfo *np;
        sk_buff_data_t saveip, savesctp;
        int err;
+       struct net *net = dev_net(skb->dev);
 
        idev = in6_dev_get(skb->dev);
 
@@ -162,12 +164,12 @@ SCTP_STATIC void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
        savesctp = skb->transport_header;
        skb_reset_network_header(skb);
        skb_set_transport_header(skb, offset);
-       sk = sctp_err_lookup(AF_INET6, skb, sctp_hdr(skb), &asoc, &transport);
+       sk = sctp_err_lookup(net, AF_INET6, skb, sctp_hdr(skb), &asoc, &transport);
        /* Put back, the original pointers. */
        skb->network_header   = saveip;
        skb->transport_header = savesctp;
        if (!sk) {
-               ICMP6_INC_STATS_BH(dev_net(skb->dev), idev, ICMP6_MIB_INERRORS);
+               ICMP6_INC_STATS_BH(net, idev, ICMP6_MIB_INERRORS);
                goto out;
        }
 
@@ -241,7 +243,7 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport)
                          __func__, skb, skb->len,
                          &fl6.saddr, &fl6.daddr);
 
-       SCTP_INC_STATS(SCTP_MIB_OUTSCTPPACKS);
+       SCTP_INC_STATS(sock_net(sk), SCTP_MIB_OUTSCTPPACKS);
 
        if (!(transport->param_flags & SPP_PMTUD_ENABLE))
                skb->local_df = 1;
@@ -580,7 +582,7 @@ static int sctp_v6_available(union sctp_addr *addr, struct sctp_sock *sp)
        if (!(type & IPV6_ADDR_UNICAST))
                return 0;
 
-       return ipv6_chk_addr(&init_net, in6, NULL, 0);
+       return ipv6_chk_addr(sock_net(&sp->inet.sk), in6, NULL, 0);
 }
 
 /* This function checks if the address is a valid address to be used for
@@ -857,14 +859,14 @@ static int sctp_inet6_bind_verify(struct sctp_sock *opt, union sctp_addr *addr)
                struct net_device *dev;
 
                if (type & IPV6_ADDR_LINKLOCAL) {
+                       struct net *net;
                        if (!addr->v6.sin6_scope_id)
                                return 0;
+                       net = sock_net(&opt->inet.sk);
                        rcu_read_lock();
-                       dev = dev_get_by_index_rcu(&init_net,
-                                                  addr->v6.sin6_scope_id);
+                       dev = dev_get_by_index_rcu(net, addr->v6.sin6_scope_id);
                        if (!dev ||
-                           !ipv6_chk_addr(&init_net, &addr->v6.sin6_addr,
-                                          dev, 0)) {
+                           !ipv6_chk_addr(net, &addr->v6.sin6_addr, dev, 0)) {
                                rcu_read_unlock();
                                return 0;
                        }
@@ -897,7 +899,7 @@ static int sctp_inet6_send_verify(struct sctp_sock *opt, union sctp_addr *addr)
                        if (!addr->v6.sin6_scope_id)
                                return 0;
                        rcu_read_lock();
-                       dev = dev_get_by_index_rcu(&init_net,
+                       dev = dev_get_by_index_rcu(sock_net(&opt->inet.sk),
                                                   addr->v6.sin6_scope_id);
                        rcu_read_unlock();
                        if (!dev)
index 8ef8e7d9eb61bbf74b6c023f4e33ee360085f84c..fe012c44f8dff15e4882165e2718b11f919cf260 100644 (file)
@@ -129,20 +129,20 @@ static const struct file_operations sctp_objcnt_ops = {
 };
 
 /* Initialize the objcount in the proc filesystem.  */
-void sctp_dbg_objcnt_init(void)
+void sctp_dbg_objcnt_init(struct net *net)
 {
        struct proc_dir_entry *ent;
 
        ent = proc_create("sctp_dbg_objcnt", 0,
-                         proc_net_sctp, &sctp_objcnt_ops);
+                         net->sctp.proc_net_sctp, &sctp_objcnt_ops);
        if (!ent)
                pr_warn("sctp_dbg_objcnt: Unable to create /proc entry.\n");
 }
 
 /* Cleanup the objcount entry in the proc filesystem.  */
-void sctp_dbg_objcnt_exit(void)
+void sctp_dbg_objcnt_exit(struct net *net)
 {
-       remove_proc_entry("sctp_dbg_objcnt", proc_net_sctp);
+       remove_proc_entry("sctp_dbg_objcnt", net->sctp.proc_net_sctp);
 }
 
 
index 838e18b4d7ea62cfd4d57e9d64a86630a0100f67..0c6359bb973c58c1ba77fa3edf599c822df3535b 100644 (file)
@@ -597,7 +597,7 @@ out:
        return err;
 no_route:
        kfree_skb(nskb);
-       IP_INC_STATS_BH(&init_net, IPSTATS_MIB_OUTNOROUTES);
+       IP_INC_STATS_BH(sock_net(asoc->base.sk), IPSTATS_MIB_OUTNOROUTES);
 
        /* FIXME: Returning the 'err' will effect all the associations
         * associated with a socket, although only one of the paths of the
index e7aa177c9522a232c1f1b58c6e5a40df2db03a29..072bf6ae3c26da20baa92d07b9c6248b86db95b2 100644 (file)
@@ -299,6 +299,7 @@ void sctp_outq_free(struct sctp_outq *q)
 /* Put a new chunk in an sctp_outq.  */
 int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk)
 {
+       struct net *net = sock_net(q->asoc->base.sk);
        int error = 0;
 
        SCTP_DEBUG_PRINTK("sctp_outq_tail(%p, %p[%s])\n",
@@ -337,15 +338,15 @@ int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk)
 
                        sctp_outq_tail_data(q, chunk);
                        if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
-                               SCTP_INC_STATS(SCTP_MIB_OUTUNORDERCHUNKS);
+                               SCTP_INC_STATS(net, SCTP_MIB_OUTUNORDERCHUNKS);
                        else
-                               SCTP_INC_STATS(SCTP_MIB_OUTORDERCHUNKS);
+                               SCTP_INC_STATS(net, SCTP_MIB_OUTORDERCHUNKS);
                        q->empty = 0;
                        break;
                }
        } else {
                list_add_tail(&chunk->list, &q->control_chunk_list);
-               SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
+               SCTP_INC_STATS(net, SCTP_MIB_OUTCTRLCHUNKS);
        }
 
        if (error < 0)
@@ -478,11 +479,12 @@ void sctp_retransmit_mark(struct sctp_outq *q,
 void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
                     sctp_retransmit_reason_t reason)
 {
+       struct net *net = sock_net(q->asoc->base.sk);
        int error = 0;
 
        switch(reason) {
        case SCTP_RTXR_T3_RTX:
-               SCTP_INC_STATS(SCTP_MIB_T3_RETRANSMITS);
+               SCTP_INC_STATS(net, SCTP_MIB_T3_RETRANSMITS);
                sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_T3_RTX);
                /* Update the retran path if the T3-rtx timer has expired for
                 * the current retran path.
@@ -493,15 +495,15 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport,
                        transport->asoc->unack_data;
                break;
        case SCTP_RTXR_FAST_RTX:
-               SCTP_INC_STATS(SCTP_MIB_FAST_RETRANSMITS);
+               SCTP_INC_STATS(net, SCTP_MIB_FAST_RETRANSMITS);
                sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_FAST_RTX);
                q->fast_rtx = 1;
                break;
        case SCTP_RTXR_PMTUD:
-               SCTP_INC_STATS(SCTP_MIB_PMTUD_RETRANSMITS);
+               SCTP_INC_STATS(net, SCTP_MIB_PMTUD_RETRANSMITS);
                break;
        case SCTP_RTXR_T1_RTX:
-               SCTP_INC_STATS(SCTP_MIB_T1_RETRANSMITS);
+               SCTP_INC_STATS(net, SCTP_MIB_T1_RETRANSMITS);
                transport->asoc->init_retries++;
                break;
        default:
@@ -1914,6 +1916,6 @@ static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 ctsn)
 
        if (ftsn_chunk) {
                list_add_tail(&ftsn_chunk->list, &q->control_chunk_list);
-               SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
+               SCTP_INC_STATS(sock_net(asoc->base.sk), SCTP_MIB_OUTCTRLCHUNKS);
        }
 }
index 534c7eae9d15f9b0371b7cd2963f74e7cbf18e7c..794bb14decdea60ec58e68a59bc5a6b2feda4a01 100644 (file)
@@ -57,7 +57,7 @@
 
 #define DECLARE_PRIMITIVE(name) \
 /* This is called in the code as sctp_primitive_ ## name.  */ \
-int sctp_primitive_ ## name(struct sctp_association *asoc, \
+int sctp_primitive_ ## name(struct net *net, struct sctp_association *asoc, \
                            void *arg) { \
        int error = 0; \
        sctp_event_t event_type; sctp_subtype_t subtype; \
@@ -69,7 +69,7 @@ int sctp_primitive_ ## name(struct sctp_association *asoc, \
        state = asoc ? asoc->state : SCTP_STATE_CLOSED; \
        ep = asoc ? asoc->ep : NULL; \
        \
-       error = sctp_do_sm(event_type, subtype, state, ep, asoc, \
+       error = sctp_do_sm(net, event_type, subtype, state, ep, asoc,   \
                           arg, GFP_KERNEL); \
        return error; \
 }
index 1e2eee88c3ea4750c093e44b3c3080f8ad3551fd..d9cb2ab149fe1d5c1f8eb9391044d0e42600e072 100644 (file)
@@ -80,11 +80,12 @@ static const struct snmp_mib sctp_snmp_list[] = {
 /* Display sctp snmp mib statistics(/proc/net/sctp/snmp). */
 static int sctp_snmp_seq_show(struct seq_file *seq, void *v)
 {
+       struct net *net = seq->private;
        int i;
 
        for (i = 0; sctp_snmp_list[i].name != NULL; i++)
                seq_printf(seq, "%-32s\t%ld\n", sctp_snmp_list[i].name,
-                          snmp_fold_field((void __percpu **)sctp_statistics,
+                          snmp_fold_field((void __percpu **)net->sctp.sctp_statistics,
                                      sctp_snmp_list[i].entry));
 
        return 0;
@@ -93,7 +94,7 @@ static int sctp_snmp_seq_show(struct seq_file *seq, void *v)
 /* Initialize the seq file operations for 'snmp' object. */
 static int sctp_snmp_seq_open(struct inode *inode, struct file *file)
 {
-       return single_open(file, sctp_snmp_seq_show, NULL);
+       return single_open_net(inode, file, sctp_snmp_seq_show);
 }
 
 static const struct file_operations sctp_snmp_seq_fops = {
@@ -105,11 +106,12 @@ static const struct file_operations sctp_snmp_seq_fops = {
 };
 
 /* Set up the proc fs entry for 'snmp' object. */
-int __init sctp_snmp_proc_init(void)
+int __net_init sctp_snmp_proc_init(struct net *net)
 {
        struct proc_dir_entry *p;
 
-       p = proc_create("snmp", S_IRUGO, proc_net_sctp, &sctp_snmp_seq_fops);
+       p = proc_create("snmp", S_IRUGO, net->sctp.proc_net_sctp,
+                       &sctp_snmp_seq_fops);
        if (!p)
                return -ENOMEM;
 
@@ -117,9 +119,9 @@ int __init sctp_snmp_proc_init(void)
 }
 
 /* Cleanup the proc fs entry for 'snmp' object. */
-void sctp_snmp_proc_exit(void)
+void sctp_snmp_proc_exit(struct net *net)
 {
-       remove_proc_entry("snmp", proc_net_sctp);
+       remove_proc_entry("snmp", net->sctp.proc_net_sctp);
 }
 
 /* Dump local addresses of an association/endpoint. */
@@ -213,6 +215,8 @@ static int sctp_eps_seq_show(struct seq_file *seq, void *v)
        sctp_for_each_hentry(epb, node, &head->chain) {
                ep = sctp_ep(epb);
                sk = epb->sk;
+               if (!net_eq(sock_net(sk), seq_file_net(seq)))
+                       continue;
                seq_printf(seq, "%8pK %8pK %-3d %-3d %-4d %-5d %5d %5lu ", ep, sk,
                           sctp_sk(sk)->type, sk->sk_state, hash,
                           epb->bind_addr.port,
@@ -238,7 +242,8 @@ static const struct seq_operations sctp_eps_ops = {
 /* Initialize the seq file operations for 'eps' object. */
 static int sctp_eps_seq_open(struct inode *inode, struct file *file)
 {
-       return seq_open(file, &sctp_eps_ops);
+       return seq_open_net(inode, file, &sctp_eps_ops,
+                           sizeof(struct seq_net_private));
 }
 
 static const struct file_operations sctp_eps_seq_fops = {
@@ -249,11 +254,12 @@ static const struct file_operations sctp_eps_seq_fops = {
 };
 
 /* Set up the proc fs entry for 'eps' object. */
-int __init sctp_eps_proc_init(void)
+int __net_init sctp_eps_proc_init(struct net *net)
 {
        struct proc_dir_entry *p;
 
-       p = proc_create("eps", S_IRUGO, proc_net_sctp, &sctp_eps_seq_fops);
+       p = proc_create("eps", S_IRUGO, net->sctp.proc_net_sctp,
+                       &sctp_eps_seq_fops);
        if (!p)
                return -ENOMEM;
 
@@ -261,9 +267,9 @@ int __init sctp_eps_proc_init(void)
 }
 
 /* Cleanup the proc fs entry for 'eps' object. */
-void sctp_eps_proc_exit(void)
+void sctp_eps_proc_exit(struct net *net)
 {
-       remove_proc_entry("eps", proc_net_sctp);
+       remove_proc_entry("eps", net->sctp.proc_net_sctp);
 }
 
 
@@ -316,6 +322,8 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v)
        sctp_for_each_hentry(epb, node, &head->chain) {
                assoc = sctp_assoc(epb);
                sk = epb->sk;
+               if (!net_eq(sock_net(sk), seq_file_net(seq)))
+                       continue;
                seq_printf(seq,
                           "%8pK %8pK %-3d %-3d %-2d %-4d "
                           "%4d %8d %8d %7d %5lu %-5d %5d ",
@@ -354,7 +362,8 @@ static const struct seq_operations sctp_assoc_ops = {
 /* Initialize the seq file operations for 'assocs' object. */
 static int sctp_assocs_seq_open(struct inode *inode, struct file *file)
 {
-       return seq_open(file, &sctp_assoc_ops);
+       return seq_open_net(inode, file, &sctp_assoc_ops,
+                           sizeof(struct seq_net_private));
 }
 
 static const struct file_operations sctp_assocs_seq_fops = {
@@ -365,11 +374,11 @@ static const struct file_operations sctp_assocs_seq_fops = {
 };
 
 /* Set up the proc fs entry for 'assocs' object. */
-int __init sctp_assocs_proc_init(void)
+int __net_init sctp_assocs_proc_init(struct net *net)
 {
        struct proc_dir_entry *p;
 
-       p = proc_create("assocs", S_IRUGO, proc_net_sctp,
+       p = proc_create("assocs", S_IRUGO, net->sctp.proc_net_sctp,
                        &sctp_assocs_seq_fops);
        if (!p)
                return -ENOMEM;
@@ -378,9 +387,9 @@ int __init sctp_assocs_proc_init(void)
 }
 
 /* Cleanup the proc fs entry for 'assocs' object. */
-void sctp_assocs_proc_exit(void)
+void sctp_assocs_proc_exit(struct net *net)
 {
-       remove_proc_entry("assocs", proc_net_sctp);
+       remove_proc_entry("assocs", net->sctp.proc_net_sctp);
 }
 
 static void *sctp_remaddr_seq_start(struct seq_file *seq, loff_t *pos)
@@ -426,6 +435,8 @@ static int sctp_remaddr_seq_show(struct seq_file *seq, void *v)
        sctp_local_bh_disable();
        read_lock(&head->lock);
        sctp_for_each_hentry(epb, node, &head->chain) {
+               if (!net_eq(sock_net(epb->sk), seq_file_net(seq)))
+                       continue;
                assoc = sctp_assoc(epb);
                list_for_each_entry(tsp, &assoc->peer.transport_addr_list,
                                        transports) {
@@ -489,14 +500,15 @@ static const struct seq_operations sctp_remaddr_ops = {
 };
 
 /* Cleanup the proc fs entry for 'remaddr' object. */
-void sctp_remaddr_proc_exit(void)
+void sctp_remaddr_proc_exit(struct net *net)
 {
-       remove_proc_entry("remaddr", proc_net_sctp);
+       remove_proc_entry("remaddr", net->sctp.proc_net_sctp);
 }
 
 static int sctp_remaddr_seq_open(struct inode *inode, struct file *file)
 {
-       return seq_open(file, &sctp_remaddr_ops);
+       return seq_open_net(inode, file, &sctp_remaddr_ops,
+                           sizeof(struct seq_net_private));
 }
 
 static const struct file_operations sctp_remaddr_seq_fops = {
@@ -506,11 +518,12 @@ static const struct file_operations sctp_remaddr_seq_fops = {
        .release = seq_release,
 };
 
-int __init sctp_remaddr_proc_init(void)
+int __net_init sctp_remaddr_proc_init(struct net *net)
 {
        struct proc_dir_entry *p;
 
-       p = proc_create("remaddr", S_IRUGO, proc_net_sctp, &sctp_remaddr_seq_fops);
+       p = proc_create("remaddr", S_IRUGO, net->sctp.proc_net_sctp,
+                       &sctp_remaddr_seq_fops);
        if (!p)
                return -ENOMEM;
        return 0;
index 1f89c4e696457fc02948066052713cac4d2f46fc..2d518425d5984bf954c6ebba3d7db0abb7ef5dc7 100644 (file)
 
 /* Global data structures. */
 struct sctp_globals sctp_globals __read_mostly;
-DEFINE_SNMP_STAT(struct sctp_mib, sctp_statistics) __read_mostly;
-
-#ifdef CONFIG_PROC_FS
-struct proc_dir_entry  *proc_net_sctp;
-#endif
 
 struct idr sctp_assocs_id;
 DEFINE_SPINLOCK(sctp_assocs_id_lock);
 
-/* This is the global socket data structure used for responding to
- * the Out-of-the-blue (OOTB) packets.  A control sock will be created
- * for this socket at the initialization time.
- */
-static struct sock *sctp_ctl_sock;
-
 static struct sctp_pf *sctp_pf_inet6_specific;
 static struct sctp_pf *sctp_pf_inet_specific;
 static struct sctp_af *sctp_af_v4_specific;
@@ -96,74 +85,54 @@ long sysctl_sctp_mem[3];
 int sysctl_sctp_rmem[3];
 int sysctl_sctp_wmem[3];
 
-/* Return the address of the control sock. */
-struct sock *sctp_get_ctl_sock(void)
-{
-       return sctp_ctl_sock;
-}
-
 /* Set up the proc fs entry for the SCTP protocol. */
-static __init int sctp_proc_init(void)
+static __net_init int sctp_proc_init(struct net *net)
 {
-       if (percpu_counter_init(&sctp_sockets_allocated, 0))
-               goto out_nomem;
 #ifdef CONFIG_PROC_FS
-       if (!proc_net_sctp) {
-               proc_net_sctp = proc_mkdir("sctp", init_net.proc_net);
-               if (!proc_net_sctp)
-                       goto out_free_percpu;
-       }
-
-       if (sctp_snmp_proc_init())
+       net->sctp.proc_net_sctp = proc_net_mkdir(net, "sctp", net->proc_net);
+       if (!net->sctp.proc_net_sctp)
+               goto out_proc_net_sctp;
+       if (sctp_snmp_proc_init(net))
                goto out_snmp_proc_init;
-       if (sctp_eps_proc_init())
+       if (sctp_eps_proc_init(net))
                goto out_eps_proc_init;
-       if (sctp_assocs_proc_init())
+       if (sctp_assocs_proc_init(net))
                goto out_assocs_proc_init;
-       if (sctp_remaddr_proc_init())
+       if (sctp_remaddr_proc_init(net))
                goto out_remaddr_proc_init;
 
        return 0;
 
 out_remaddr_proc_init:
-       sctp_assocs_proc_exit();
+       sctp_assocs_proc_exit(net);
 out_assocs_proc_init:
-       sctp_eps_proc_exit();
+       sctp_eps_proc_exit(net);
 out_eps_proc_init:
-       sctp_snmp_proc_exit();
+       sctp_snmp_proc_exit(net);
 out_snmp_proc_init:
-       if (proc_net_sctp) {
-               proc_net_sctp = NULL;
-               remove_proc_entry("sctp", init_net.proc_net);
-       }
-out_free_percpu:
-       percpu_counter_destroy(&sctp_sockets_allocated);
-#else
-       return 0;
-#endif /* CONFIG_PROC_FS */
-
-out_nomem:
+       remove_proc_entry("sctp", net->proc_net);
+       net->sctp.proc_net_sctp = NULL;
+out_proc_net_sctp:
        return -ENOMEM;
+#endif /* CONFIG_PROC_FS */
+       return 0;
 }
 
 /* Clean up the proc fs entry for the SCTP protocol.
  * Note: Do not make this __exit as it is used in the init error
  * path.
  */
-static void sctp_proc_exit(void)
+static void sctp_proc_exit(struct net *net)
 {
 #ifdef CONFIG_PROC_FS
-       sctp_snmp_proc_exit();
-       sctp_eps_proc_exit();
-       sctp_assocs_proc_exit();
-       sctp_remaddr_proc_exit();
-
-       if (proc_net_sctp) {
-               proc_net_sctp = NULL;
-               remove_proc_entry("sctp", init_net.proc_net);
-       }
+       sctp_snmp_proc_exit(net);
+       sctp_eps_proc_exit(net);
+       sctp_assocs_proc_exit(net);
+       sctp_remaddr_proc_exit(net);
+
+       remove_proc_entry("sctp", net->proc_net);
+       net->sctp.proc_net_sctp = NULL;
 #endif
-       percpu_counter_destroy(&sctp_sockets_allocated);
 }
 
 /* Private helper to extract ipv4 address and stash them in
@@ -201,29 +170,29 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist,
 /* Extract our IP addresses from the system and stash them in the
  * protocol structure.
  */
-static void sctp_get_local_addr_list(void)
+static void sctp_get_local_addr_list(struct net *net)
 {
        struct net_device *dev;
        struct list_head *pos;
        struct sctp_af *af;
 
        rcu_read_lock();
-       for_each_netdev_rcu(&init_net, dev) {
+       for_each_netdev_rcu(net, dev) {
                __list_for_each(pos, &sctp_address_families) {
                        af = list_entry(pos, struct sctp_af, list);
-                       af->copy_addrlist(&sctp_local_addr_list, dev);
+                       af->copy_addrlist(&net->sctp.local_addr_list, dev);
                }
        }
        rcu_read_unlock();
 }
 
 /* Free the existing local addresses.  */
-static void sctp_free_local_addr_list(void)
+static void sctp_free_local_addr_list(struct net *net)
 {
        struct sctp_sockaddr_entry *addr;
        struct list_head *pos, *temp;
 
-       list_for_each_safe(pos, temp, &sctp_local_addr_list) {
+       list_for_each_safe(pos, temp, &net->sctp.local_addr_list) {
                addr = list_entry(pos, struct sctp_sockaddr_entry, list);
                list_del(pos);
                kfree(addr);
@@ -231,17 +200,17 @@ static void sctp_free_local_addr_list(void)
 }
 
 /* Copy the local addresses which are valid for 'scope' into 'bp'.  */
-int sctp_copy_local_addr_list(struct sctp_bind_addr *bp, sctp_scope_t scope,
-                             gfp_t gfp, int copy_flags)
+int sctp_copy_local_addr_list(struct net *net, struct sctp_bind_addr *bp,
+                             sctp_scope_t scope, gfp_t gfp, int copy_flags)
 {
        struct sctp_sockaddr_entry *addr;
        int error = 0;
 
        rcu_read_lock();
-       list_for_each_entry_rcu(addr, &sctp_local_addr_list, list) {
+       list_for_each_entry_rcu(addr, &net->sctp.local_addr_list, list) {
                if (!addr->valid)
                        continue;
-               if (sctp_in_scope(&addr->a, scope)) {
+               if (sctp_in_scope(net, &addr->a, scope)) {
                        /* Now that the address is in scope, check to see if
                         * the address type is really supported by the local
                         * sock as well as the remote peer.
@@ -397,7 +366,8 @@ static int sctp_v4_addr_valid(union sctp_addr *addr,
 /* Should this be available for binding?   */
 static int sctp_v4_available(union sctp_addr *addr, struct sctp_sock *sp)
 {
-       int ret = inet_addr_type(&init_net, addr->v4.sin_addr.s_addr);
+       struct net *net = sock_net(&sp->inet.sk);
+       int ret = inet_addr_type(net, addr->v4.sin_addr.s_addr);
 
 
        if (addr->v4.sin_addr.s_addr != htonl(INADDR_ANY) &&
@@ -484,7 +454,7 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
        SCTP_DEBUG_PRINTK("%s: DST:%pI4, SRC:%pI4 - ",
                          __func__, &fl4->daddr, &fl4->saddr);
 
-       rt = ip_route_output_key(&init_net, fl4);
+       rt = ip_route_output_key(sock_net(sk), fl4);
        if (!IS_ERR(rt))
                dst = &rt->dst;
 
@@ -530,7 +500,7 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
                    (AF_INET == laddr->a.sa.sa_family)) {
                        fl4->saddr = laddr->a.v4.sin_addr.s_addr;
                        fl4->fl4_sport = laddr->a.v4.sin_port;
-                       rt = ip_route_output_key(&init_net, fl4);
+                       rt = ip_route_output_key(sock_net(sk), fl4);
                        if (!IS_ERR(rt)) {
                                dst = &rt->dst;
                                goto out_unlock;
@@ -627,14 +597,15 @@ static void sctp_v4_ecn_capable(struct sock *sk)
 
 void sctp_addr_wq_timeout_handler(unsigned long arg)
 {
+       struct net *net = (struct net *)arg;
        struct sctp_sockaddr_entry *addrw, *temp;
        struct sctp_sock *sp;
 
-       spin_lock_bh(&sctp_addr_wq_lock);
+       spin_lock_bh(&net->sctp.addr_wq_lock);
 
-       list_for_each_entry_safe(addrw, temp, &sctp_addr_waitq, list) {
+       list_for_each_entry_safe(addrw, temp, &net->sctp.addr_waitq, list) {
                SCTP_DEBUG_PRINTK_IPADDR("sctp_addrwq_timo_handler: the first ent in wq %p is ",
-                   " for cmd %d at entry %p\n", &sctp_addr_waitq, &addrw->a, addrw->state,
+                   " for cmd %d at entry %p\n", &net->sctp.addr_waitq, &addrw->a, addrw->state,
                    addrw);
 
 #if IS_ENABLED(CONFIG_IPV6)
@@ -648,7 +619,7 @@ void sctp_addr_wq_timeout_handler(unsigned long arg)
                                goto free_next;
 
                        in6 = (struct in6_addr *)&addrw->a.v6.sin6_addr;
-                       if (ipv6_chk_addr(&init_net, in6, NULL, 0) == 0 &&
+                       if (ipv6_chk_addr(net, in6, NULL, 0) == 0 &&
                            addrw->state == SCTP_ADDR_NEW) {
                                unsigned long timeo_val;
 
@@ -656,12 +627,12 @@ void sctp_addr_wq_timeout_handler(unsigned long arg)
                                    SCTP_ADDRESS_TICK_DELAY);
                                timeo_val = jiffies;
                                timeo_val += msecs_to_jiffies(SCTP_ADDRESS_TICK_DELAY);
-                               mod_timer(&sctp_addr_wq_timer, timeo_val);
+                               mod_timer(&net->sctp.addr_wq_timer, timeo_val);
                                break;
                        }
                }
 #endif
-               list_for_each_entry(sp, &sctp_auto_asconf_splist, auto_asconf_list) {
+               list_for_each_entry(sp, &net->sctp.auto_asconf_splist, auto_asconf_list) {
                        struct sock *sk;
 
                        sk = sctp_opt2sk(sp);
@@ -679,31 +650,32 @@ free_next:
                list_del(&addrw->list);
                kfree(addrw);
        }
-       spin_unlock_bh(&sctp_addr_wq_lock);
+       spin_unlock_bh(&net->sctp.addr_wq_lock);
 }
 
-static void sctp_free_addr_wq(void)
+static void sctp_free_addr_wq(struct net *net)
 {
        struct sctp_sockaddr_entry *addrw;
        struct sctp_sockaddr_entry *temp;
 
-       spin_lock_bh(&sctp_addr_wq_lock);
-       del_timer(&sctp_addr_wq_timer);
-       list_for_each_entry_safe(addrw, temp, &sctp_addr_waitq, list) {
+       spin_lock_bh(&net->sctp.addr_wq_lock);
+       del_timer(&net->sctp.addr_wq_timer);
+       list_for_each_entry_safe(addrw, temp, &net->sctp.addr_waitq, list) {
                list_del(&addrw->list);
                kfree(addrw);
        }
-       spin_unlock_bh(&sctp_addr_wq_lock);
+       spin_unlock_bh(&net->sctp.addr_wq_lock);
 }
 
 /* lookup the entry for the same address in the addr_waitq
  * sctp_addr_wq MUST be locked
  */
-static struct sctp_sockaddr_entry *sctp_addr_wq_lookup(struct sctp_sockaddr_entry *addr)
+static struct sctp_sockaddr_entry *sctp_addr_wq_lookup(struct net *net,
+                                       struct sctp_sockaddr_entry *addr)
 {
        struct sctp_sockaddr_entry *addrw;
 
-       list_for_each_entry(addrw, &sctp_addr_waitq, list) {
+       list_for_each_entry(addrw, &net->sctp.addr_waitq, list) {
                if (addrw->a.sa.sa_family != addr->a.sa.sa_family)
                        continue;
                if (addrw->a.sa.sa_family == AF_INET) {
@@ -719,7 +691,7 @@ static struct sctp_sockaddr_entry *sctp_addr_wq_lookup(struct sctp_sockaddr_entr
        return NULL;
 }
 
-void sctp_addr_wq_mgmt(struct sctp_sockaddr_entry *addr, int cmd)
+void sctp_addr_wq_mgmt(struct net *net, struct sctp_sockaddr_entry *addr, int cmd)
 {
        struct sctp_sockaddr_entry *addrw;
        unsigned long timeo_val;
@@ -730,38 +702,38 @@ void sctp_addr_wq_mgmt(struct sctp_sockaddr_entry *addr, int cmd)
         * new address after a couple of addition and deletion of that address
         */
 
-       spin_lock_bh(&sctp_addr_wq_lock);
+       spin_lock_bh(&net->sctp.addr_wq_lock);
        /* Offsets existing events in addr_wq */
-       addrw = sctp_addr_wq_lookup(addr);
+       addrw = sctp_addr_wq_lookup(net, addr);
        if (addrw) {
                if (addrw->state != cmd) {
                        SCTP_DEBUG_PRINTK_IPADDR("sctp_addr_wq_mgmt offsets existing entry for %d ",
                            " in wq %p\n", addrw->state, &addrw->a,
-                           &sctp_addr_waitq);
+                           &net->sctp.addr_waitq);
                        list_del(&addrw->list);
                        kfree(addrw);
                }
-               spin_unlock_bh(&sctp_addr_wq_lock);
+               spin_unlock_bh(&net->sctp.addr_wq_lock);
                return;
        }
 
        /* OK, we have to add the new address to the wait queue */
        addrw = kmemdup(addr, sizeof(struct sctp_sockaddr_entry), GFP_ATOMIC);
        if (addrw == NULL) {
-               spin_unlock_bh(&sctp_addr_wq_lock);
+               spin_unlock_bh(&net->sctp.addr_wq_lock);
                return;
        }
        addrw->state = cmd;
-       list_add_tail(&addrw->list, &sctp_addr_waitq);
+       list_add_tail(&addrw->list, &net->sctp.addr_waitq);
        SCTP_DEBUG_PRINTK_IPADDR("sctp_addr_wq_mgmt add new entry for cmd:%d ",
-           " in wq %p\n", addrw->state, &addrw->a, &sctp_addr_waitq);
+           " in wq %p\n", addrw->state, &addrw->a, &net->sctp.addr_waitq);
 
-       if (!timer_pending(&sctp_addr_wq_timer)) {
+       if (!timer_pending(&net->sctp.addr_wq_timer)) {
                timeo_val = jiffies;
                timeo_val += msecs_to_jiffies(SCTP_ADDRESS_TICK_DELAY);
-               mod_timer(&sctp_addr_wq_timer, timeo_val);
+               mod_timer(&net->sctp.addr_wq_timer, timeo_val);
        }
-       spin_unlock_bh(&sctp_addr_wq_lock);
+       spin_unlock_bh(&net->sctp.addr_wq_lock);
 }
 
 /* Event handler for inet address addition/deletion events.
@@ -776,11 +748,9 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev,
        struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
        struct sctp_sockaddr_entry *addr = NULL;
        struct sctp_sockaddr_entry *temp;
+       struct net *net = dev_net(ifa->ifa_dev->dev);
        int found = 0;
 
-       if (!net_eq(dev_net(ifa->ifa_dev->dev), &init_net))
-               return NOTIFY_DONE;
-
        switch (ev) {
        case NETDEV_UP:
                addr = kmalloc(sizeof(struct sctp_sockaddr_entry), GFP_ATOMIC);
@@ -789,27 +759,27 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev,
                        addr->a.v4.sin_port = 0;
                        addr->a.v4.sin_addr.s_addr = ifa->ifa_local;
                        addr->valid = 1;
-                       spin_lock_bh(&sctp_local_addr_lock);
-                       list_add_tail_rcu(&addr->list, &sctp_local_addr_list);
-                       sctp_addr_wq_mgmt(addr, SCTP_ADDR_NEW);
-                       spin_unlock_bh(&sctp_local_addr_lock);
+                       spin_lock_bh(&net->sctp.local_addr_lock);
+                       list_add_tail_rcu(&addr->list, &net->sctp.local_addr_list);
+                       sctp_addr_wq_mgmt(net, addr, SCTP_ADDR_NEW);
+                       spin_unlock_bh(&net->sctp.local_addr_lock);
                }
                break;
        case NETDEV_DOWN:
-               spin_lock_bh(&sctp_local_addr_lock);
+               spin_lock_bh(&net->sctp.local_addr_lock);
                list_for_each_entry_safe(addr, temp,
-                                       &sctp_local_addr_list, list) {
+                                       &net->sctp.local_addr_list, list) {
                        if (addr->a.sa.sa_family == AF_INET &&
                                        addr->a.v4.sin_addr.s_addr ==
                                        ifa->ifa_local) {
-                               sctp_addr_wq_mgmt(addr, SCTP_ADDR_DEL);
+                               sctp_addr_wq_mgmt(net, addr, SCTP_ADDR_DEL);
                                found = 1;
                                addr->valid = 0;
                                list_del_rcu(&addr->list);
                                break;
                        }
                }
-               spin_unlock_bh(&sctp_local_addr_lock);
+               spin_unlock_bh(&net->sctp.local_addr_lock);
                if (found)
                        kfree_rcu(addr, rcu);
                break;
@@ -822,7 +792,7 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev,
  * Initialize the control inode/socket with a control endpoint data
  * structure.  This endpoint is reserved exclusively for the OOTB processing.
  */
-static int sctp_ctl_sock_init(void)
+static int sctp_ctl_sock_init(struct net *net)
 {
        int err;
        sa_family_t family = PF_INET;
@@ -830,14 +800,14 @@ static int sctp_ctl_sock_init(void)
        if (sctp_get_pf_specific(PF_INET6))
                family = PF_INET6;
 
-       err = inet_ctl_sock_create(&sctp_ctl_sock, family,
-                                  SOCK_SEQPACKET, IPPROTO_SCTP, &init_net);
+       err = inet_ctl_sock_create(&net->sctp.ctl_sock, family,
+                                  SOCK_SEQPACKET, IPPROTO_SCTP, net);
 
        /* If IPv6 socket could not be created, try the IPv4 socket */
        if (err < 0 && family == PF_INET6)
-               err = inet_ctl_sock_create(&sctp_ctl_sock, AF_INET,
+               err = inet_ctl_sock_create(&net->sctp.ctl_sock, AF_INET,
                                           SOCK_SEQPACKET, IPPROTO_SCTP,
-                                          &init_net);
+                                          net);
 
        if (err < 0) {
                pr_err("Failed to create the SCTP control socket\n");
@@ -990,7 +960,7 @@ static inline int sctp_v4_xmit(struct sk_buff *skb,
        inet->pmtudisc = transport->param_flags & SPP_PMTUD_ENABLE ?
                         IP_PMTUDISC_DO : IP_PMTUDISC_DONT;
 
-       SCTP_INC_STATS(SCTP_MIB_OUTSCTPPACKS);
+       SCTP_INC_STATS(sock_net(&inet->sk), SCTP_MIB_OUTSCTPPACKS);
        return ip_queue_xmit(skb, &transport->fl);
 }
 
@@ -1063,6 +1033,7 @@ static const struct net_protocol sctp_protocol = {
        .handler     = sctp_rcv,
        .err_handler = sctp_v4_err,
        .no_policy   = 1,
+       .netns_ok    = 1,
 };
 
 /* IPv4 address related functions.  */
@@ -1130,16 +1101,16 @@ int sctp_register_pf(struct sctp_pf *pf, sa_family_t family)
        return 1;
 }
 
-static inline int init_sctp_mibs(void)
+static inline int init_sctp_mibs(struct net *net)
 {
-       return snmp_mib_init((void __percpu **)sctp_statistics,
+       return snmp_mib_init((void __percpu **)net->sctp.sctp_statistics,
                             sizeof(struct sctp_mib),
                             __alignof__(struct sctp_mib));
 }
 
-static inline void cleanup_sctp_mibs(void)
+static inline void cleanup_sctp_mibs(struct net *net)
 {
-       snmp_mib_free((void __percpu **)sctp_statistics);
+       snmp_mib_free((void __percpu **)net->sctp.sctp_statistics);
 }
 
 static void sctp_v4_pf_init(void)
@@ -1194,6 +1165,143 @@ static void sctp_v4_del_protocol(void)
        unregister_inetaddr_notifier(&sctp_inetaddr_notifier);
 }
 
+static int sctp_net_init(struct net *net)
+{
+       int status;
+
+       /*
+        * 14. Suggested SCTP Protocol Parameter Values
+        */
+       /* The following protocol parameters are RECOMMENDED:  */
+       /* RTO.Initial              - 3  seconds */
+       net->sctp.rto_initial                   = SCTP_RTO_INITIAL;
+       /* RTO.Min                  - 1  second */
+       net->sctp.rto_min                       = SCTP_RTO_MIN;
+       /* RTO.Max                 -  60 seconds */
+       net->sctp.rto_max                       = SCTP_RTO_MAX;
+       /* RTO.Alpha                - 1/8 */
+       net->sctp.rto_alpha                     = SCTP_RTO_ALPHA;
+       /* RTO.Beta                 - 1/4 */
+       net->sctp.rto_beta                      = SCTP_RTO_BETA;
+
+       /* Valid.Cookie.Life        - 60  seconds */
+       net->sctp.valid_cookie_life             = SCTP_DEFAULT_COOKIE_LIFE;
+
+       /* Whether Cookie Preservative is enabled(1) or not(0) */
+       net->sctp.cookie_preserve_enable        = 1;
+
+       /* Max.Burst                - 4 */
+       net->sctp.max_burst                     = SCTP_DEFAULT_MAX_BURST;
+
+       /* Association.Max.Retrans  - 10 attempts
+        * Path.Max.Retrans         - 5  attempts (per destination address)
+        * Max.Init.Retransmits     - 8  attempts
+        */
+       net->sctp.max_retrans_association       = 10;
+       net->sctp.max_retrans_path              = 5;
+       net->sctp.max_retrans_init              = 8;
+
+       /* Sendbuffer growth        - do per-socket accounting */
+       net->sctp.sndbuf_policy                 = 0;
+
+       /* Rcvbuffer growth         - do per-socket accounting */
+       net->sctp.rcvbuf_policy                 = 0;
+
+       /* HB.interval              - 30 seconds */
+       net->sctp.hb_interval                   = SCTP_DEFAULT_TIMEOUT_HEARTBEAT;
+
+       /* delayed SACK timeout */
+       net->sctp.sack_timeout                  = SCTP_DEFAULT_TIMEOUT_SACK;
+
+       /* Disable ADDIP by default. */
+       net->sctp.addip_enable = 0;
+       net->sctp.addip_noauth = 0;
+       net->sctp.default_auto_asconf = 0;
+
+       /* Enable PR-SCTP by default. */
+       net->sctp.prsctp_enable = 1;
+
+       /* Disable AUTH by default. */
+       net->sctp.auth_enable = 0;
+
+       /* Set SCOPE policy to enabled */
+       net->sctp.scope_policy = SCTP_SCOPE_POLICY_ENABLE;
+
+       /* Set the default rwnd update threshold */
+       net->sctp.rwnd_upd_shift = SCTP_DEFAULT_RWND_SHIFT;
+
+       /* Initialize maximum autoclose timeout. */
+       net->sctp.max_autoclose         = INT_MAX / HZ;
+
+       status = sctp_sysctl_net_register(net);
+       if (status)
+               goto err_sysctl_register;
+
+       /* Allocate and initialise sctp mibs.  */
+       status = init_sctp_mibs(net);
+       if (status)
+               goto err_init_mibs;
+
+       /* Initialize proc fs directory.  */
+       status = sctp_proc_init(net);
+       if (status)
+               goto err_init_proc;
+
+       sctp_dbg_objcnt_init(net);
+
+       /* Initialize the control inode/socket for handling OOTB packets.  */
+       if ((status = sctp_ctl_sock_init(net))) {
+               pr_err("Failed to initialize the SCTP control sock\n");
+               goto err_ctl_sock_init;
+       }
+
+       /* Initialize the local address list. */
+       INIT_LIST_HEAD(&net->sctp.local_addr_list);
+       spin_lock_init(&net->sctp.local_addr_lock);
+       sctp_get_local_addr_list(net);
+
+       /* Initialize the address event list */
+       INIT_LIST_HEAD(&net->sctp.addr_waitq);
+       INIT_LIST_HEAD(&net->sctp.auto_asconf_splist);
+       spin_lock_init(&net->sctp.addr_wq_lock);
+       net->sctp.addr_wq_timer.expires = 0;
+       setup_timer(&net->sctp.addr_wq_timer, sctp_addr_wq_timeout_handler,
+                   (unsigned long)net);
+
+       return 0;
+
+err_ctl_sock_init:
+       sctp_dbg_objcnt_exit(net);
+       sctp_proc_exit(net);
+err_init_proc:
+       cleanup_sctp_mibs(net);
+err_init_mibs:
+       sctp_sysctl_net_unregister(net);
+err_sysctl_register:
+       return status;
+}
+
+static void sctp_net_exit(struct net *net)
+{
+       /* Free the local address list */
+       sctp_free_addr_wq(net);
+       sctp_free_local_addr_list(net);
+
+       /* Free the control endpoint.  */
+       inet_ctl_sock_destroy(net->sctp.ctl_sock);
+
+       sctp_dbg_objcnt_exit(net);
+
+       sctp_proc_exit(net);
+       cleanup_sctp_mibs(net);
+       sctp_sysctl_net_unregister(net);
+}
+
+static struct pernet_operations sctp_net_ops = {
+       .init = sctp_net_init,
+       .exit = sctp_net_exit,
+};
+
 /* Initialize the universe into something sensible.  */
 SCTP_STATIC __init int sctp_init(void)
 {
@@ -1224,62 +1332,9 @@ SCTP_STATIC __init int sctp_init(void)
        if (!sctp_chunk_cachep)
                goto err_chunk_cachep;
 
-       /* Allocate and initialise sctp mibs.  */
-       status = init_sctp_mibs();
+       status = percpu_counter_init(&sctp_sockets_allocated, 0);
        if (status)
-               goto err_init_mibs;
-
-       /* Initialize proc fs directory.  */
-       status = sctp_proc_init();
-       if (status)
-               goto err_init_proc;
-
-       /* Initialize object count debugging.  */
-       sctp_dbg_objcnt_init();
-
-       /*
-        * 14. Suggested SCTP Protocol Parameter Values
-        */
-       /* The following protocol parameters are RECOMMENDED:  */
-       /* RTO.Initial              - 3  seconds */
-       sctp_rto_initial                = SCTP_RTO_INITIAL;
-       /* RTO.Min                  - 1  second */
-       sctp_rto_min                    = SCTP_RTO_MIN;
-       /* RTO.Max                 -  60 seconds */
-       sctp_rto_max                    = SCTP_RTO_MAX;
-       /* RTO.Alpha                - 1/8 */
-       sctp_rto_alpha                  = SCTP_RTO_ALPHA;
-       /* RTO.Beta                 - 1/4 */
-       sctp_rto_beta                   = SCTP_RTO_BETA;
-
-       /* Valid.Cookie.Life        - 60  seconds */
-       sctp_valid_cookie_life          = SCTP_DEFAULT_COOKIE_LIFE;
-
-       /* Whether Cookie Preservative is enabled(1) or not(0) */
-       sctp_cookie_preserve_enable     = 1;
-
-       /* Max.Burst                - 4 */
-       sctp_max_burst                  = SCTP_DEFAULT_MAX_BURST;
-
-       /* Association.Max.Retrans  - 10 attempts
-        * Path.Max.Retrans         - 5  attempts (per destination address)
-        * Max.Init.Retransmits     - 8  attempts
-        */
-       sctp_max_retrans_association    = 10;
-       sctp_max_retrans_path           = 5;
-       sctp_max_retrans_init           = 8;
-
-       /* Sendbuffer growth        - do per-socket accounting */
-       sctp_sndbuf_policy              = 0;
-
-       /* Rcvbuffer growth         - do per-socket accounting */
-       sctp_rcvbuf_policy              = 0;
-
-       /* HB.interval              - 30 seconds */
-       sctp_hb_interval                = SCTP_DEFAULT_TIMEOUT_HEARTBEAT;
-
-       /* delayed SACK timeout */
-       sctp_sack_timeout               = SCTP_DEFAULT_TIMEOUT_SACK;
+               goto err_percpu_counter_init;
 
        /* Implementation specific variables. */
 
@@ -1287,9 +1342,6 @@ SCTP_STATIC __init int sctp_init(void)
        sctp_max_instreams              = SCTP_DEFAULT_INSTREAMS;
        sctp_max_outstreams             = SCTP_DEFAULT_OUTSTREAMS;
 
-       /* Initialize maximum autoclose timeout. */
-       sctp_max_autoclose              = INT_MAX / HZ;
-
        /* Initialize handle used for association ids. */
        idr_init(&sctp_assocs_id);
 
@@ -1376,41 +1428,12 @@ SCTP_STATIC __init int sctp_init(void)
        pr_info("Hash tables configured (established %d bind %d)\n",
                sctp_assoc_hashsize, sctp_port_hashsize);
 
-       /* Disable ADDIP by default. */
-       sctp_addip_enable = 0;
-       sctp_addip_noauth = 0;
-       sctp_default_auto_asconf = 0;
-
-       /* Enable PR-SCTP by default. */
-       sctp_prsctp_enable = 1;
-
-       /* Disable AUTH by default. */
-       sctp_auth_enable = 0;
-
-       /* Set SCOPE policy to enabled */
-       sctp_scope_policy = SCTP_SCOPE_POLICY_ENABLE;
-
-       /* Set the default rwnd update threshold */
-       sctp_rwnd_upd_shift             = SCTP_DEFAULT_RWND_SHIFT;
-
        sctp_sysctl_register();
 
        INIT_LIST_HEAD(&sctp_address_families);
        sctp_v4_pf_init();
        sctp_v6_pf_init();
 
-       /* Initialize the local address list. */
-       INIT_LIST_HEAD(&sctp_local_addr_list);
-       spin_lock_init(&sctp_local_addr_lock);
-       sctp_get_local_addr_list();
-
-       /* Initialize the address event list */
-       INIT_LIST_HEAD(&sctp_addr_waitq);
-       INIT_LIST_HEAD(&sctp_auto_asconf_splist);
-       spin_lock_init(&sctp_addr_wq_lock);
-       sctp_addr_wq_timer.expires = 0;
-       setup_timer(&sctp_addr_wq_timer, sctp_addr_wq_timeout_handler, 0);
-
        status = sctp_v4_protosw_init();
 
        if (status)
@@ -1420,11 +1443,9 @@ SCTP_STATIC __init int sctp_init(void)
        if (status)
                goto err_v6_protosw_init;
 
-       /* Initialize the control inode/socket for handling OOTB packets.  */
-       if ((status = sctp_ctl_sock_init())) {
-               pr_err("Failed to initialize the SCTP control sock\n");
-               goto err_ctl_sock_init;
-       }
+       status = register_pernet_subsys(&sctp_net_ops);
+       if (status)
+               goto err_register_pernet_subsys;
 
        status = sctp_v4_add_protocol();
        if (status)
@@ -1441,13 +1462,12 @@ out:
 err_v6_add_protocol:
        sctp_v4_del_protocol();
 err_add_protocol:
-       inet_ctl_sock_destroy(sctp_ctl_sock);
-err_ctl_sock_init:
+       unregister_pernet_subsys(&sctp_net_ops);
+err_register_pernet_subsys:
        sctp_v6_protosw_exit();
 err_v6_protosw_init:
        sctp_v4_protosw_exit();
 err_protosw_init:
-       sctp_free_local_addr_list();
        sctp_v4_pf_exit();
        sctp_v6_pf_exit();
        sctp_sysctl_unregister();
@@ -1461,11 +1481,8 @@ err_ehash_alloc:
                   get_order(sctp_assoc_hashsize *
                             sizeof(struct sctp_hashbucket)));
 err_ahash_alloc:
-       sctp_dbg_objcnt_exit();
-       sctp_proc_exit();
-err_init_proc:
-       cleanup_sctp_mibs();
-err_init_mibs:
+       percpu_counter_destroy(&sctp_sockets_allocated);
+err_percpu_counter_init:
        kmem_cache_destroy(sctp_chunk_cachep);
 err_chunk_cachep:
        kmem_cache_destroy(sctp_bucket_cachep);
@@ -1482,18 +1499,13 @@ SCTP_STATIC __exit void sctp_exit(void)
        /* Unregister with inet6/inet layers. */
        sctp_v6_del_protocol();
        sctp_v4_del_protocol();
-       sctp_free_addr_wq();
 
-       /* Free the control endpoint.  */
-       inet_ctl_sock_destroy(sctp_ctl_sock);
+       unregister_pernet_subsys(&sctp_net_ops);
 
        /* Free protosw registrations */
        sctp_v6_protosw_exit();
        sctp_v4_protosw_exit();
 
-       /* Free the local address list.  */
-       sctp_free_local_addr_list();
-
        /* Unregister with socket layer. */
        sctp_v6_pf_exit();
        sctp_v4_pf_exit();
@@ -1508,9 +1520,7 @@ SCTP_STATIC __exit void sctp_exit(void)
                   get_order(sctp_port_hashsize *
                             sizeof(struct sctp_bind_hashbucket)));
 
-       sctp_dbg_objcnt_exit();
-       sctp_proc_exit();
-       cleanup_sctp_mibs();
+       percpu_counter_destroy(&sctp_sockets_allocated);
 
        rcu_barrier(); /* Wait for completion of call_rcu()'s */
 
index 479a70ef6ff8abe2a59a16ddc672f6638c7b3369..fbe1636309a75ac054de225fe4d1cf245a3923d2 100644 (file)
@@ -198,6 +198,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
                             const struct sctp_bind_addr *bp,
                             gfp_t gfp, int vparam_len)
 {
+       struct net *net = sock_net(asoc->base.sk);
        sctp_inithdr_t init;
        union sctp_params addrs;
        size_t chunksize;
@@ -237,7 +238,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
        chunksize += WORD_ROUND(SCTP_SAT_LEN(num_types));
        chunksize += sizeof(ecap_param);
 
-       if (sctp_prsctp_enable)
+       if (net->sctp.prsctp_enable)
                chunksize += sizeof(prsctp_param);
 
        /* ADDIP: Section 4.2.7:
@@ -245,7 +246,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
         *  the ASCONF,the ASCONF-ACK, and the AUTH  chunks in its INIT and
         *  INIT-ACK parameters.
         */
-       if (sctp_addip_enable) {
+       if (net->sctp.addip_enable) {
                extensions[num_ext] = SCTP_CID_ASCONF;
                extensions[num_ext+1] = SCTP_CID_ASCONF_ACK;
                num_ext += 2;
@@ -257,7 +258,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
        chunksize += vparam_len;
 
        /* Account for AUTH related parameters */
-       if (sctp_auth_enable) {
+       if (net->sctp.auth_enable) {
                /* Add random parameter length*/
                chunksize += sizeof(asoc->c.auth_random);
 
@@ -331,7 +332,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
                sctp_addto_param(retval, num_ext, extensions);
        }
 
-       if (sctp_prsctp_enable)
+       if (net->sctp.prsctp_enable)
                sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param);
 
        if (sp->adaptation_ind) {
@@ -342,7 +343,7 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
        }
 
        /* Add SCTP-AUTH chunks to the parameter list */
-       if (sctp_auth_enable) {
+       if (net->sctp.auth_enable) {
                sctp_addto_chunk(retval, sizeof(asoc->c.auth_random),
                                 asoc->c.auth_random);
                if (auth_hmacs)
@@ -1940,7 +1941,7 @@ static int sctp_process_hn_param(const struct sctp_association *asoc,
        return 0;
 }
 
-static int sctp_verify_ext_param(union sctp_params param)
+static int sctp_verify_ext_param(struct net *net, union sctp_params param)
 {
        __u16 num_ext = ntohs(param.p->length) - sizeof(sctp_paramhdr_t);
        int have_auth = 0;
@@ -1964,10 +1965,10 @@ static int sctp_verify_ext_param(union sctp_params param)
         * only if ADD-IP is turned on and we are not backward-compatible
         * mode.
         */
-       if (sctp_addip_noauth)
+       if (net->sctp.addip_noauth)
                return 1;
 
-       if (sctp_addip_enable && !have_auth && have_asconf)
+       if (net->sctp.addip_enable && !have_auth && have_asconf)
                return 0;
 
        return 1;
@@ -1976,13 +1977,14 @@ static int sctp_verify_ext_param(union sctp_params param)
 static void sctp_process_ext_param(struct sctp_association *asoc,
                                    union sctp_params param)
 {
+       struct net *net = sock_net(asoc->base.sk);
        __u16 num_ext = ntohs(param.p->length) - sizeof(sctp_paramhdr_t);
        int i;
 
        for (i = 0; i < num_ext; i++) {
                switch (param.ext->chunks[i]) {
                    case SCTP_CID_FWD_TSN:
-                           if (sctp_prsctp_enable &&
+                           if (net->sctp.prsctp_enable &&
                                !asoc->peer.prsctp_capable)
                                    asoc->peer.prsctp_capable = 1;
                            break;
@@ -1990,12 +1992,12 @@ static void sctp_process_ext_param(struct sctp_association *asoc,
                            /* if the peer reports AUTH, assume that he
                             * supports AUTH.
                             */
-                           if (sctp_auth_enable)
+                           if (net->sctp.auth_enable)
                                    asoc->peer.auth_capable = 1;
                            break;
                    case SCTP_CID_ASCONF:
                    case SCTP_CID_ASCONF_ACK:
-                           if (sctp_addip_enable)
+                           if (net->sctp.addip_enable)
                                    asoc->peer.asconf_capable = 1;
                            break;
                    default:
@@ -2081,7 +2083,8 @@ static sctp_ierror_t sctp_process_unk_param(const struct sctp_association *asoc,
  *     SCTP_IERROR_ERROR - stop processing, trigger an ERROR
  *     SCTP_IERROR_NO_ERROR - continue with the chunk
  */
-static sctp_ierror_t sctp_verify_param(const struct sctp_association *asoc,
+static sctp_ierror_t sctp_verify_param(struct net *net,
+                                       const struct sctp_association *asoc,
                                        union sctp_params param,
                                        sctp_cid_t cid,
                                        struct sctp_chunk *chunk,
@@ -2110,12 +2113,12 @@ static sctp_ierror_t sctp_verify_param(const struct sctp_association *asoc,
                break;
 
        case SCTP_PARAM_SUPPORTED_EXT:
-               if (!sctp_verify_ext_param(param))
+               if (!sctp_verify_ext_param(net, param))
                        return SCTP_IERROR_ABORT;
                break;
 
        case SCTP_PARAM_SET_PRIMARY:
-               if (sctp_addip_enable)
+               if (net->sctp.addip_enable)
                        break;
                goto fallthrough;
 
@@ -2126,12 +2129,12 @@ static sctp_ierror_t sctp_verify_param(const struct sctp_association *asoc,
                break;
 
        case SCTP_PARAM_FWD_TSN_SUPPORT:
-               if (sctp_prsctp_enable)
+               if (net->sctp.prsctp_enable)
                        break;
                goto fallthrough;
 
        case SCTP_PARAM_RANDOM:
-               if (!sctp_auth_enable)
+               if (!net->sctp.auth_enable)
                        goto fallthrough;
 
                /* SCTP-AUTH: Secion 6.1
@@ -2148,7 +2151,7 @@ static sctp_ierror_t sctp_verify_param(const struct sctp_association *asoc,
                break;
 
        case SCTP_PARAM_CHUNKS:
-               if (!sctp_auth_enable)
+               if (!net->sctp.auth_enable)
                        goto fallthrough;
 
                /* SCTP-AUTH: Section 3.2
@@ -2164,7 +2167,7 @@ static sctp_ierror_t sctp_verify_param(const struct sctp_association *asoc,
                break;
 
        case SCTP_PARAM_HMAC_ALGO:
-               if (!sctp_auth_enable)
+               if (!net->sctp.auth_enable)
                        goto fallthrough;
 
                hmacs = (struct sctp_hmac_algo_param *)param.p;
@@ -2198,7 +2201,7 @@ fallthrough:
 }
 
 /* Verify the INIT packet before we process it.  */
-int sctp_verify_init(const struct sctp_association *asoc,
+int sctp_verify_init(struct net *net, const struct sctp_association *asoc,
                     sctp_cid_t cid,
                     sctp_init_chunk_t *peer_init,
                     struct sctp_chunk *chunk,
@@ -2245,7 +2248,7 @@ int sctp_verify_init(const struct sctp_association *asoc,
        /* Verify all the variable length parameters */
        sctp_walk_params(param, peer_init, init_hdr.params) {
 
-               result = sctp_verify_param(asoc, param, cid, chunk, errp);
+               result = sctp_verify_param(net, asoc, param, cid, chunk, errp);
                switch (result) {
                    case SCTP_IERROR_ABORT:
                    case SCTP_IERROR_NOMEM:
@@ -2270,6 +2273,7 @@ int sctp_process_init(struct sctp_association *asoc, struct sctp_chunk *chunk,
                      const union sctp_addr *peer_addr,
                      sctp_init_chunk_t *peer_init, gfp_t gfp)
 {
+       struct net *net = sock_net(asoc->base.sk);
        union sctp_params param;
        struct sctp_transport *transport;
        struct list_head *pos, *temp;
@@ -2326,7 +2330,7 @@ int sctp_process_init(struct sctp_association *asoc, struct sctp_chunk *chunk,
         * also give us an option to silently ignore the packet, which
         * is what we'll do here.
         */
-       if (!sctp_addip_noauth &&
+       if (!net->sctp.addip_noauth &&
             (asoc->peer.asconf_capable && !asoc->peer.auth_capable)) {
                asoc->peer.addip_disabled_mask |= (SCTP_PARAM_ADD_IP |
                                                  SCTP_PARAM_DEL_IP |
@@ -2466,6 +2470,7 @@ static int sctp_process_param(struct sctp_association *asoc,
                              const union sctp_addr *peer_addr,
                              gfp_t gfp)
 {
+       struct net *net = sock_net(asoc->base.sk);
        union sctp_addr addr;
        int i;
        __u16 sat;
@@ -2494,13 +2499,13 @@ do_addr_param:
                af = sctp_get_af_specific(param_type2af(param.p->type));
                af->from_addr_param(&addr, param.addr, htons(asoc->peer.port), 0);
                scope = sctp_scope(peer_addr);
-               if (sctp_in_scope(&addr, scope))
+               if (sctp_in_scope(net, &addr, scope))
                        if (!sctp_assoc_add_peer(asoc, &addr, gfp, SCTP_UNCONFIRMED))
                                return 0;
                break;
 
        case SCTP_PARAM_COOKIE_PRESERVATIVE:
-               if (!sctp_cookie_preserve_enable)
+               if (!net->sctp.cookie_preserve_enable)
                        break;
 
                stale = ntohl(param.life->lifespan_increment);
@@ -2580,7 +2585,7 @@ do_addr_param:
                break;
 
        case SCTP_PARAM_SET_PRIMARY:
-               if (!sctp_addip_enable)
+               if (!net->sctp.addip_enable)
                        goto fall_through;
 
                addr_param = param.v + sizeof(sctp_addip_param_t);
@@ -2607,7 +2612,7 @@ do_addr_param:
                break;
 
        case SCTP_PARAM_FWD_TSN_SUPPORT:
-               if (sctp_prsctp_enable) {
+               if (net->sctp.prsctp_enable) {
                        asoc->peer.prsctp_capable = 1;
                        break;
                }
@@ -2615,7 +2620,7 @@ do_addr_param:
                goto fall_through;
 
        case SCTP_PARAM_RANDOM:
-               if (!sctp_auth_enable)
+               if (!net->sctp.auth_enable)
                        goto fall_through;
 
                /* Save peer's random parameter */
@@ -2628,7 +2633,7 @@ do_addr_param:
                break;
 
        case SCTP_PARAM_HMAC_ALGO:
-               if (!sctp_auth_enable)
+               if (!net->sctp.auth_enable)
                        goto fall_through;
 
                /* Save peer's HMAC list */
@@ -2644,7 +2649,7 @@ do_addr_param:
                break;
 
        case SCTP_PARAM_CHUNKS:
-               if (!sctp_auth_enable)
+               if (!net->sctp.auth_enable)
                        goto fall_through;
 
                asoc->peer.peer_chunks = kmemdup(param.p,
index fe99628e1257bd1173dadfa1826a0f2d5f35c7f6..bcfebb91559d1d9e9a0b6472986f626021a3f358 100644 (file)
@@ -251,6 +251,7 @@ void sctp_generate_t3_rtx_event(unsigned long peer)
        int error;
        struct sctp_transport *transport = (struct sctp_transport *) peer;
        struct sctp_association *asoc = transport->asoc;
+       struct net *net = sock_net(asoc->base.sk);
 
        /* Check whether a task is in the sock.  */
 
@@ -271,7 +272,7 @@ void sctp_generate_t3_rtx_event(unsigned long peer)
                goto out_unlock;
 
        /* Run through the state machine.  */
-       error = sctp_do_sm(SCTP_EVENT_T_TIMEOUT,
+       error = sctp_do_sm(net, SCTP_EVENT_T_TIMEOUT,
                           SCTP_ST_TIMEOUT(SCTP_EVENT_TIMEOUT_T3_RTX),
                           asoc->state,
                           asoc->ep, asoc,
@@ -291,6 +292,7 @@ out_unlock:
 static void sctp_generate_timeout_event(struct sctp_association *asoc,
                                        sctp_event_timeout_t timeout_type)
 {
+       struct net *net = sock_net(asoc->base.sk);
        int error = 0;
 
        sctp_bh_lock_sock(asoc->base.sk);
@@ -312,7 +314,7 @@ static void sctp_generate_timeout_event(struct sctp_association *asoc,
                goto out_unlock;
 
        /* Run through the state machine.  */
-       error = sctp_do_sm(SCTP_EVENT_T_TIMEOUT,
+       error = sctp_do_sm(net, SCTP_EVENT_T_TIMEOUT,
                           SCTP_ST_TIMEOUT(timeout_type),
                           asoc->state, asoc->ep, asoc,
                           (void *)timeout_type, GFP_ATOMIC);
@@ -371,6 +373,7 @@ void sctp_generate_heartbeat_event(unsigned long data)
        int error = 0;
        struct sctp_transport *transport = (struct sctp_transport *) data;
        struct sctp_association *asoc = transport->asoc;
+       struct net *net = sock_net(asoc->base.sk);
 
        sctp_bh_lock_sock(asoc->base.sk);
        if (sock_owned_by_user(asoc->base.sk)) {
@@ -388,7 +391,7 @@ void sctp_generate_heartbeat_event(unsigned long data)
        if (transport->dead)
                goto out_unlock;
 
-       error = sctp_do_sm(SCTP_EVENT_T_TIMEOUT,
+       error = sctp_do_sm(net, SCTP_EVENT_T_TIMEOUT,
                           SCTP_ST_TIMEOUT(SCTP_EVENT_TIMEOUT_HEARTBEAT),
                           asoc->state, asoc->ep, asoc,
                           transport, GFP_ATOMIC);
@@ -408,6 +411,7 @@ void sctp_generate_proto_unreach_event(unsigned long data)
 {
        struct sctp_transport *transport = (struct sctp_transport *) data;
        struct sctp_association *asoc = transport->asoc;
+       struct net *net = sock_net(asoc->base.sk);
        
        sctp_bh_lock_sock(asoc->base.sk);
        if (sock_owned_by_user(asoc->base.sk)) {
@@ -426,7 +430,7 @@ void sctp_generate_proto_unreach_event(unsigned long data)
        if (asoc->base.dead)
                goto out_unlock;
 
-       sctp_do_sm(SCTP_EVENT_T_OTHER,
+       sctp_do_sm(net, SCTP_EVENT_T_OTHER,
                   SCTP_ST_OTHER(SCTP_EVENT_ICMP_PROTO_UNREACH),
                   asoc->state, asoc->ep, asoc, transport, GFP_ATOMIC);
 
@@ -753,8 +757,10 @@ static int sctp_cmd_process_sack(sctp_cmd_seq_t *cmds,
        int err = 0;
 
        if (sctp_outq_sack(&asoc->outqueue, sackh)) {
+               struct net *net = sock_net(asoc->base.sk);
+
                /* There are no more TSNs awaiting SACK.  */
-               err = sctp_do_sm(SCTP_EVENT_T_OTHER,
+               err = sctp_do_sm(net, SCTP_EVENT_T_OTHER,
                                 SCTP_ST_OTHER(SCTP_EVENT_NO_PENDING_TSN),
                                 asoc->state, asoc->ep, asoc, NULL,
                                 GFP_ATOMIC);
@@ -1042,6 +1048,8 @@ static int sctp_cmd_send_msg(struct sctp_association *asoc,
  */
 static void sctp_cmd_send_asconf(struct sctp_association *asoc)
 {
+       struct net *net = sock_net(asoc->base.sk);
+
        /* Send the next asconf chunk from the addip chunk
         * queue.
         */
@@ -1053,7 +1061,7 @@ static void sctp_cmd_send_asconf(struct sctp_association *asoc)
 
                /* Hold the chunk until an ASCONF_ACK is received. */
                sctp_chunk_hold(asconf);
-               if (sctp_primitive_ASCONF(asoc, asconf))
+               if (sctp_primitive_ASCONF(net, asoc, asconf))
                        sctp_chunk_free(asconf);
                else
                        asoc->addip_last_asconf = asconf;
@@ -1089,7 +1097,7 @@ static void sctp_cmd_send_asconf(struct sctp_association *asoc)
  * If you want to understand all of lksctp, this is a
  * good place to start.
  */
-int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype,
+int sctp_do_sm(struct net *net, sctp_event_t event_type, sctp_subtype_t subtype,
               sctp_state_t state,
               struct sctp_endpoint *ep,
               struct sctp_association *asoc,
@@ -1110,12 +1118,12 @@ int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype,
        /* Look up the state function, run it, and then process the
         * side effects.  These three steps are the heart of lksctp.
         */
-       state_fn = sctp_sm_lookup_event(event_type, state, subtype);
+       state_fn = sctp_sm_lookup_event(net, event_type, state, subtype);
 
        sctp_init_cmd_seq(&commands);
 
        DEBUG_PRE;
-       status = (*state_fn->fn)(ep, asoc, subtype, event_arg, &commands);
+       status = (*state_fn->fn)(net, ep, asoc, subtype, event_arg, &commands);
        DEBUG_POST;
 
        error = sctp_side_effects(event_type, subtype, state,
index 9fca103573508aa6f0880455e0e2c2d66dbb6150..094813b6c3c3cb99dddf407eeb93a2397a676cae 100644 (file)
@@ -66,7 +66,8 @@
 #include <net/sctp/sm.h>
 #include <net/sctp/structs.h>
 
-static struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *ep,
+static struct sctp_packet *sctp_abort_pkt_new(struct net *net,
+                                 const struct sctp_endpoint *ep,
                                  const struct sctp_association *asoc,
                                  struct sctp_chunk *chunk,
                                  const void *payload,
@@ -74,36 +75,43 @@ static struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *ep,
 static int sctp_eat_data(const struct sctp_association *asoc,
                         struct sctp_chunk *chunk,
                         sctp_cmd_seq_t *commands);
-static struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *asoc,
+static struct sctp_packet *sctp_ootb_pkt_new(struct net *net,
+                                            const struct sctp_association *asoc,
                                             const struct sctp_chunk *chunk);
-static void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep,
+static void sctp_send_stale_cookie_err(struct net *net,
+                                      const struct sctp_endpoint *ep,
                                       const struct sctp_association *asoc,
                                       const struct sctp_chunk *chunk,
                                       sctp_cmd_seq_t *commands,
                                       struct sctp_chunk *err_chunk);
-static sctp_disposition_t sctp_sf_do_5_2_6_stale(const struct sctp_endpoint *ep,
+static sctp_disposition_t sctp_sf_do_5_2_6_stale(struct net *net,
+                                                const struct sctp_endpoint *ep,
                                                 const struct sctp_association *asoc,
                                                 const sctp_subtype_t type,
                                                 void *arg,
                                                 sctp_cmd_seq_t *commands);
-static sctp_disposition_t sctp_sf_shut_8_4_5(const struct sctp_endpoint *ep,
+static sctp_disposition_t sctp_sf_shut_8_4_5(struct net *net,
+                                            const struct sctp_endpoint *ep,
                                             const struct sctp_association *asoc,
                                             const sctp_subtype_t type,
                                             void *arg,
                                             sctp_cmd_seq_t *commands);
-static sctp_disposition_t sctp_sf_tabort_8_4_8(const struct sctp_endpoint *ep,
+static sctp_disposition_t sctp_sf_tabort_8_4_8(struct net *net,
+                                       const struct sctp_endpoint *ep,
                                        const struct sctp_association *asoc,
                                        const sctp_subtype_t type,
                                        void *arg,
                                        sctp_cmd_seq_t *commands);
 static struct sctp_sackhdr *sctp_sm_pull_sack(struct sctp_chunk *chunk);
 
-static sctp_disposition_t sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands,
+static sctp_disposition_t sctp_stop_t1_and_abort(struct net *net,
+                                          sctp_cmd_seq_t *commands,
                                           __be16 error, int sk_err,
                                           const struct sctp_association *asoc,
                                           struct sctp_transport *transport);
 
 static sctp_disposition_t sctp_sf_abort_violation(
+                                    struct net *net,
                                     const struct sctp_endpoint *ep,
                                     const struct sctp_association *asoc,
                                     void *arg,
@@ -112,6 +120,7 @@ static sctp_disposition_t sctp_sf_abort_violation(
                                     const size_t paylen);
 
 static sctp_disposition_t sctp_sf_violation_chunklen(
+                                    struct net *net,
                                     const struct sctp_endpoint *ep,
                                     const struct sctp_association *asoc,
                                     const sctp_subtype_t type,
@@ -119,6 +128,7 @@ static sctp_disposition_t sctp_sf_violation_chunklen(
                                     sctp_cmd_seq_t *commands);
 
 static sctp_disposition_t sctp_sf_violation_paramlen(
+                                    struct net *net,
                                     const struct sctp_endpoint *ep,
                                     const struct sctp_association *asoc,
                                     const sctp_subtype_t type,
@@ -126,6 +136,7 @@ static sctp_disposition_t sctp_sf_violation_paramlen(
                                     sctp_cmd_seq_t *commands);
 
 static sctp_disposition_t sctp_sf_violation_ctsn(
+                                    struct net *net,
                                     const struct sctp_endpoint *ep,
                                     const struct sctp_association *asoc,
                                     const sctp_subtype_t type,
@@ -133,18 +144,21 @@ static sctp_disposition_t sctp_sf_violation_ctsn(
                                     sctp_cmd_seq_t *commands);
 
 static sctp_disposition_t sctp_sf_violation_chunk(
+                                    struct net *net,
                                     const struct sctp_endpoint *ep,
                                     const struct sctp_association *asoc,
                                     const sctp_subtype_t type,
                                     void *arg,
                                     sctp_cmd_seq_t *commands);
 
-static sctp_ierror_t sctp_sf_authenticate(const struct sctp_endpoint *ep,
+static sctp_ierror_t sctp_sf_authenticate(struct net *net,
+                                   const struct sctp_endpoint *ep,
                                    const struct sctp_association *asoc,
                                    const sctp_subtype_t type,
                                    struct sctp_chunk *chunk);
 
-static sctp_disposition_t __sctp_sf_do_9_1_abort(const struct sctp_endpoint *ep,
+static sctp_disposition_t __sctp_sf_do_9_1_abort(struct net *net,
+                                       const struct sctp_endpoint *ep,
                                        const struct sctp_association *asoc,
                                        const sctp_subtype_t type,
                                        void *arg,
@@ -204,7 +218,8 @@ sctp_chunk_length_valid(struct sctp_chunk *chunk,
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_do_4_C(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_do_4_C(struct net *net,
+                                 const struct sctp_endpoint *ep,
                                  const struct sctp_association *asoc,
                                  const sctp_subtype_t type,
                                  void *arg,
@@ -214,7 +229,7 @@ sctp_disposition_t sctp_sf_do_4_C(const struct sctp_endpoint *ep,
        struct sctp_ulpevent *ev;
 
        if (!sctp_vtag_verify_either(chunk, asoc))
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
        /* RFC 2960 6.10 Bundling
         *
@@ -222,11 +237,11 @@ sctp_disposition_t sctp_sf_do_4_C(const struct sctp_endpoint *ep,
         * SHUTDOWN COMPLETE with any other chunks.
         */
        if (!chunk->singleton)
-               return sctp_sf_violation_chunk(ep, asoc, type, arg, commands);
+               return sctp_sf_violation_chunk(net, ep, asoc, type, arg, commands);
 
        /* Make sure that the SHUTDOWN_COMPLETE chunk has a valid length. */
        if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
-               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+               return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
                                                  commands);
 
        /* RFC 2960 10.2 SCTP-to-ULP
@@ -259,8 +274,8 @@ sctp_disposition_t sctp_sf_do_4_C(const struct sctp_endpoint *ep,
        sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
                        SCTP_STATE(SCTP_STATE_CLOSED));
 
-       SCTP_INC_STATS(SCTP_MIB_SHUTDOWNS);
-       SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
+       SCTP_INC_STATS(net, SCTP_MIB_SHUTDOWNS);
+       SCTP_DEC_STATS(net, SCTP_MIB_CURRESTAB);
 
        sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
 
@@ -289,7 +304,8 @@ sctp_disposition_t sctp_sf_do_4_C(const struct sctp_endpoint *ep,
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_do_5_1B_init(struct net *net,
+                                       const struct sctp_endpoint *ep,
                                        const struct sctp_association *asoc,
                                        const sctp_subtype_t type,
                                        void *arg,
@@ -313,21 +329,21 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep,
         * with an INIT chunk that is bundled with other chunks.
         */
        if (!chunk->singleton)
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
        /* If the packet is an OOTB packet which is temporarily on the
         * control endpoint, respond with an ABORT.
         */
-       if (ep == sctp_sk((sctp_get_ctl_sock()))->ep) {
-               SCTP_INC_STATS(SCTP_MIB_OUTOFBLUES);
-               return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
+       if (ep == sctp_sk(net->sctp.ctl_sock)->ep) {
+               SCTP_INC_STATS(net, SCTP_MIB_OUTOFBLUES);
+               return sctp_sf_tabort_8_4_8(net, ep, asoc, type, arg, commands);
        }
 
        /* 3.1 A packet containing an INIT chunk MUST have a zero Verification
         * Tag.
         */
        if (chunk->sctp_hdr->vtag != 0)
-               return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
+               return sctp_sf_tabort_8_4_8(net, ep, asoc, type, arg, commands);
 
        /* Make sure that the INIT chunk has a valid length.
         * Normally, this would cause an ABORT with a Protocol Violation
@@ -335,7 +351,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep,
         * just discard the packet.
         */
        if (!sctp_chunk_length_valid(chunk, sizeof(sctp_init_chunk_t)))
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
        /* If the INIT is coming toward a closing socket, we'll send back
         * and ABORT.  Essentially, this catches the race of INIT being
@@ -344,18 +360,18 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep,
         * can treat this OOTB
         */
        if (sctp_sstate(ep->base.sk, CLOSING))
-               return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
+               return sctp_sf_tabort_8_4_8(net, ep, asoc, type, arg, commands);
 
        /* Verify the INIT chunk before processing it. */
        err_chunk = NULL;
-       if (!sctp_verify_init(asoc, chunk->chunk_hdr->type,
+       if (!sctp_verify_init(net, asoc, chunk->chunk_hdr->type,
                              (sctp_init_chunk_t *)chunk->chunk_hdr, chunk,
                              &err_chunk)) {
                /* This chunk contains fatal error. It is to be discarded.
                 * Send an ABORT, with causes if there is any.
                 */
                if (err_chunk) {
-                       packet = sctp_abort_pkt_new(ep, asoc, arg,
+                       packet = sctp_abort_pkt_new(net, ep, asoc, arg,
                                        (__u8 *)(err_chunk->chunk_hdr) +
                                        sizeof(sctp_chunkhdr_t),
                                        ntohs(err_chunk->chunk_hdr->length) -
@@ -366,13 +382,13 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep,
                        if (packet) {
                                sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
                                                SCTP_PACKET(packet));
-                               SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
+                               SCTP_INC_STATS(net, SCTP_MIB_OUTCTRLCHUNKS);
                                return SCTP_DISPOSITION_CONSUME;
                        } else {
                                return SCTP_DISPOSITION_NOMEM;
                        }
                } else {
-                       return sctp_sf_tabort_8_4_8(ep, asoc, type, arg,
+                       return sctp_sf_tabort_8_4_8(net, ep, asoc, type, arg,
                                                    commands);
                }
        }
@@ -484,7 +500,8 @@ nomem:
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_do_5_1C_ack(struct net *net,
+                                      const struct sctp_endpoint *ep,
                                       const struct sctp_association *asoc,
                                       const sctp_subtype_t type,
                                       void *arg,
@@ -496,25 +513,25 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep,
        struct sctp_packet *packet;
 
        if (!sctp_vtag_verify(chunk, asoc))
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
        /* 6.10 Bundling
         * An endpoint MUST NOT bundle INIT, INIT ACK or
         * SHUTDOWN COMPLETE with any other chunks.
         */
        if (!chunk->singleton)
-               return sctp_sf_violation_chunk(ep, asoc, type, arg, commands);
+               return sctp_sf_violation_chunk(net, ep, asoc, type, arg, commands);
 
        /* Make sure that the INIT-ACK chunk has a valid length */
        if (!sctp_chunk_length_valid(chunk, sizeof(sctp_initack_chunk_t)))
-               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+               return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
                                                  commands);
        /* Grab the INIT header.  */
        chunk->subh.init_hdr = (sctp_inithdr_t *) chunk->skb->data;
 
        /* Verify the INIT chunk before processing it. */
        err_chunk = NULL;
-       if (!sctp_verify_init(asoc, chunk->chunk_hdr->type,
+       if (!sctp_verify_init(net, asoc, chunk->chunk_hdr->type,
                              (sctp_init_chunk_t *)chunk->chunk_hdr, chunk,
                              &err_chunk)) {
 
@@ -526,7 +543,7 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep,
                 * the association.
                 */
                if (err_chunk) {
-                       packet = sctp_abort_pkt_new(ep, asoc, arg,
+                       packet = sctp_abort_pkt_new(net, ep, asoc, arg,
                                        (__u8 *)(err_chunk->chunk_hdr) +
                                        sizeof(sctp_chunkhdr_t),
                                        ntohs(err_chunk->chunk_hdr->length) -
@@ -537,7 +554,7 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep,
                        if (packet) {
                                sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
                                                SCTP_PACKET(packet));
-                               SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
+                               SCTP_INC_STATS(net, SCTP_MIB_OUTCTRLCHUNKS);
                                error = SCTP_ERROR_INV_PARAM;
                        }
                }
@@ -554,10 +571,10 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep,
                 * was malformed.
                 */
                if (sctp_auth_recv_cid(SCTP_CID_ABORT, asoc))
-                       return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+                       return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
-               SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
-               return sctp_stop_t1_and_abort(commands, error, ECONNREFUSED,
+               SCTP_INC_STATS(net, SCTP_MIB_ABORTEDS);
+               return sctp_stop_t1_and_abort(net, commands, error, ECONNREFUSED,
                                                asoc, chunk->transport);
        }
 
@@ -633,7 +650,8 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep,
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_do_5_1D_ce(struct net *net,
+                                     const struct sctp_endpoint *ep,
                                      const struct sctp_association *asoc,
                                      const sctp_subtype_t type, void *arg,
                                      sctp_cmd_seq_t *commands)
@@ -650,9 +668,9 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep,
        /* If the packet is an OOTB packet which is temporarily on the
         * control endpoint, respond with an ABORT.
         */
-       if (ep == sctp_sk((sctp_get_ctl_sock()))->ep) {
-               SCTP_INC_STATS(SCTP_MIB_OUTOFBLUES);
-               return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
+       if (ep == sctp_sk(net->sctp.ctl_sock)->ep) {
+               SCTP_INC_STATS(net, SCTP_MIB_OUTOFBLUES);
+               return sctp_sf_tabort_8_4_8(net, ep, asoc, type, arg, commands);
        }
 
        /* Make sure that the COOKIE_ECHO chunk has a valid length.
@@ -661,7 +679,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep,
         * in sctp_unpack_cookie().
         */
        if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
        /* If the endpoint is not listening or if the number of associations
         * on the TCP-style socket exceed the max backlog, respond with an
@@ -670,7 +688,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep,
        sk = ep->base.sk;
        if (!sctp_sstate(sk, LISTENING) ||
            (sctp_style(sk, TCP) && sk_acceptq_is_full(sk)))
-               return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
+               return sctp_sf_tabort_8_4_8(net, ep, asoc, type, arg, commands);
 
        /* "Decode" the chunk.  We have no optional parameters so we
         * are in good shape.
@@ -703,13 +721,13 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep,
                        goto nomem;
 
                case -SCTP_IERROR_STALE_COOKIE:
-                       sctp_send_stale_cookie_err(ep, asoc, chunk, commands,
+                       sctp_send_stale_cookie_err(net, ep, asoc, chunk, commands,
                                                   err_chk_p);
-                       return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+                       return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
                case -SCTP_IERROR_BAD_SIG:
                default:
-                       return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+                       return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
                }
        }
 
@@ -756,14 +774,14 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep,
                skb_pull(chunk->auth_chunk, sizeof(sctp_chunkhdr_t));
                auth.transport = chunk->transport;
 
-               ret = sctp_sf_authenticate(ep, new_asoc, type, &auth);
+               ret = sctp_sf_authenticate(net, ep, new_asoc, type, &auth);
 
                /* We can now safely free the auth_chunk clone */
                kfree_skb(chunk->auth_chunk);
 
                if (ret != SCTP_IERROR_NO_ERROR) {
                        sctp_association_free(new_asoc);
-                       return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+                       return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
                }
        }
 
@@ -804,8 +822,8 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep,
        sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc));
        sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
                        SCTP_STATE(SCTP_STATE_ESTABLISHED));
-       SCTP_INC_STATS(SCTP_MIB_CURRESTAB);
-       SCTP_INC_STATS(SCTP_MIB_PASSIVEESTABS);
+       SCTP_INC_STATS(net, SCTP_MIB_CURRESTAB);
+       SCTP_INC_STATS(net, SCTP_MIB_PASSIVEESTABS);
        sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL());
 
        if (new_asoc->autoclose)
@@ -856,7 +874,8 @@ nomem:
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_do_5_1E_ca(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_do_5_1E_ca(struct net *net,
+                                     const struct sctp_endpoint *ep,
                                      const struct sctp_association *asoc,
                                      const sctp_subtype_t type, void *arg,
                                      sctp_cmd_seq_t *commands)
@@ -865,13 +884,13 @@ sctp_disposition_t sctp_sf_do_5_1E_ca(const struct sctp_endpoint *ep,
        struct sctp_ulpevent *ev;
 
        if (!sctp_vtag_verify(chunk, asoc))
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
        /* Verify that the chunk length for the COOKIE-ACK is OK.
         * If we don't do this, any bundled chunks may be junked.
         */
        if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
-               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+               return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
                                                  commands);
 
        /* Reset init error count upon receipt of COOKIE-ACK,
@@ -892,8 +911,8 @@ sctp_disposition_t sctp_sf_do_5_1E_ca(const struct sctp_endpoint *ep,
                        SCTP_TO(SCTP_EVENT_TIMEOUT_T1_COOKIE));
        sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
                        SCTP_STATE(SCTP_STATE_ESTABLISHED));
-       SCTP_INC_STATS(SCTP_MIB_CURRESTAB);
-       SCTP_INC_STATS(SCTP_MIB_ACTIVEESTABS);
+       SCTP_INC_STATS(net, SCTP_MIB_CURRESTAB);
+       SCTP_INC_STATS(net, SCTP_MIB_ACTIVEESTABS);
        sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL());
        if (asoc->autoclose)
                sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_START,
@@ -958,7 +977,8 @@ static sctp_disposition_t sctp_sf_heartbeat(const struct sctp_endpoint *ep,
 }
 
 /* Generate a HEARTBEAT packet on the given transport.  */
-sctp_disposition_t sctp_sf_sendbeat_8_3(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_sendbeat_8_3(struct net *net,
+                                       const struct sctp_endpoint *ep,
                                        const struct sctp_association *asoc,
                                        const sctp_subtype_t type,
                                        void *arg,
@@ -972,8 +992,8 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const struct sctp_endpoint *ep,
                /* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
                sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
                                SCTP_PERR(SCTP_ERROR_NO_ERROR));
-               SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
-               SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
+               SCTP_INC_STATS(net, SCTP_MIB_ABORTEDS);
+               SCTP_DEC_STATS(net, SCTP_MIB_CURRESTAB);
                return SCTP_DISPOSITION_DELETE_TCB;
        }
 
@@ -1028,7 +1048,8 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const struct sctp_endpoint *ep,
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_beat_8_3(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_beat_8_3(struct net *net,
+                                   const struct sctp_endpoint *ep,
                                    const struct sctp_association *asoc,
                                    const sctp_subtype_t type,
                                    void *arg,
@@ -1039,11 +1060,11 @@ sctp_disposition_t sctp_sf_beat_8_3(const struct sctp_endpoint *ep,
        size_t paylen = 0;
 
        if (!sctp_vtag_verify(chunk, asoc))
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
        /* Make sure that the HEARTBEAT chunk has a valid length. */
        if (!sctp_chunk_length_valid(chunk, sizeof(sctp_heartbeat_chunk_t)))
-               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+               return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
                                                  commands);
 
        /* 8.3 The receiver of the HEARTBEAT should immediately
@@ -1095,7 +1116,8 @@ nomem:
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_backbeat_8_3(struct net *net,
+                                       const struct sctp_endpoint *ep,
                                        const struct sctp_association *asoc,
                                        const sctp_subtype_t type,
                                        void *arg,
@@ -1108,12 +1130,12 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep,
        unsigned long max_interval;
 
        if (!sctp_vtag_verify(chunk, asoc))
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
        /* Make sure that the HEARTBEAT-ACK chunk has a valid length.  */
        if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t) +
                                            sizeof(sctp_sender_hb_info_t)))
-               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+               return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
                                                  commands);
 
        hbinfo = (sctp_sender_hb_info_t *) chunk->skb->data;
@@ -1171,7 +1193,7 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep,
 /* Helper function to send out an abort for the restart
  * condition.
  */
-static int sctp_sf_send_restart_abort(union sctp_addr *ssa,
+static int sctp_sf_send_restart_abort(struct net *net, union sctp_addr *ssa,
                                      struct sctp_chunk *init,
                                      sctp_cmd_seq_t *commands)
 {
@@ -1197,18 +1219,18 @@ static int sctp_sf_send_restart_abort(union sctp_addr *ssa,
        errhdr->length = htons(len);
 
        /* Assign to the control socket. */
-       ep = sctp_sk((sctp_get_ctl_sock()))->ep;
+       ep = sctp_sk(net->sctp.ctl_sock)->ep;
 
        /* Association is NULL since this may be a restart attack and we
         * want to send back the attacker's vtag.
         */
-       pkt = sctp_abort_pkt_new(ep, NULL, init, errhdr, len);
+       pkt = sctp_abort_pkt_new(net, ep, NULL, init, errhdr, len);
 
        if (!pkt)
                goto out;
        sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, SCTP_PACKET(pkt));
 
-       SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
+       SCTP_INC_STATS(net, SCTP_MIB_OUTCTRLCHUNKS);
 
        /* Discard the rest of the inbound packet. */
        sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET, SCTP_NULL());
@@ -1240,6 +1262,7 @@ static int sctp_sf_check_restart_addrs(const struct sctp_association *new_asoc,
                                       struct sctp_chunk *init,
                                       sctp_cmd_seq_t *commands)
 {
+       struct net *net = sock_net(new_asoc->base.sk);
        struct sctp_transport *new_addr;
        int ret = 1;
 
@@ -1258,7 +1281,7 @@ static int sctp_sf_check_restart_addrs(const struct sctp_association *new_asoc,
                            transports) {
                if (!list_has_sctp_addr(&asoc->peer.transport_addr_list,
                                        &new_addr->ipaddr)) {
-                       sctp_sf_send_restart_abort(&new_addr->ipaddr, init,
+                       sctp_sf_send_restart_abort(net, &new_addr->ipaddr, init,
                                                   commands);
                        ret = 0;
                        break;
@@ -1358,6 +1381,7 @@ static char sctp_tietags_compare(struct sctp_association *new_asoc,
  * chunk handling.
  */
 static sctp_disposition_t sctp_sf_do_unexpected_init(
+       struct net *net,
        const struct sctp_endpoint *ep,
        const struct sctp_association *asoc,
        const sctp_subtype_t type,
@@ -1382,20 +1406,20 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
         * with an INIT chunk that is bundled with other chunks.
         */
        if (!chunk->singleton)
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
        /* 3.1 A packet containing an INIT chunk MUST have a zero Verification
         * Tag.
         */
        if (chunk->sctp_hdr->vtag != 0)
-               return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
+               return sctp_sf_tabort_8_4_8(net, ep, asoc, type, arg, commands);
 
        /* Make sure that the INIT chunk has a valid length.
         * In this case, we generate a protocol violation since we have
         * an association established.
         */
        if (!sctp_chunk_length_valid(chunk, sizeof(sctp_init_chunk_t)))
-               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+               return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
                                                  commands);
        /* Grab the INIT header.  */
        chunk->subh.init_hdr = (sctp_inithdr_t *) chunk->skb->data;
@@ -1405,14 +1429,14 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
 
        /* Verify the INIT chunk before processing it. */
        err_chunk = NULL;
-       if (!sctp_verify_init(asoc, chunk->chunk_hdr->type,
+       if (!sctp_verify_init(net, asoc, chunk->chunk_hdr->type,
                              (sctp_init_chunk_t *)chunk->chunk_hdr, chunk,
                              &err_chunk)) {
                /* This chunk contains fatal error. It is to be discarded.
                 * Send an ABORT, with causes if there is any.
                 */
                if (err_chunk) {
-                       packet = sctp_abort_pkt_new(ep, asoc, arg,
+                       packet = sctp_abort_pkt_new(net, ep, asoc, arg,
                                        (__u8 *)(err_chunk->chunk_hdr) +
                                        sizeof(sctp_chunkhdr_t),
                                        ntohs(err_chunk->chunk_hdr->length) -
@@ -1421,14 +1445,14 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
                        if (packet) {
                                sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
                                                SCTP_PACKET(packet));
-                               SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
+                               SCTP_INC_STATS(net, SCTP_MIB_OUTCTRLCHUNKS);
                                retval = SCTP_DISPOSITION_CONSUME;
                        } else {
                                retval = SCTP_DISPOSITION_NOMEM;
                        }
                        goto cleanup;
                } else {
-                       return sctp_sf_tabort_8_4_8(ep, asoc, type, arg,
+                       return sctp_sf_tabort_8_4_8(net, ep, asoc, type, arg,
                                                    commands);
                }
        }
@@ -1570,7 +1594,8 @@ cleanup:
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_do_5_2_1_siminit(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_do_5_2_1_siminit(struct net *net,
+                                   const struct sctp_endpoint *ep,
                                    const struct sctp_association *asoc,
                                    const sctp_subtype_t type,
                                    void *arg,
@@ -1579,7 +1604,7 @@ sctp_disposition_t sctp_sf_do_5_2_1_siminit(const struct sctp_endpoint *ep,
        /* Call helper to do the real work for both simulataneous and
         * duplicate INIT chunk handling.
         */
-       return sctp_sf_do_unexpected_init(ep, asoc, type, arg, commands);
+       return sctp_sf_do_unexpected_init(net, ep, asoc, type, arg, commands);
 }
 
 /*
@@ -1623,7 +1648,8 @@ sctp_disposition_t sctp_sf_do_5_2_1_siminit(const struct sctp_endpoint *ep,
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_do_5_2_2_dupinit(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_do_5_2_2_dupinit(struct net *net,
+                                       const struct sctp_endpoint *ep,
                                        const struct sctp_association *asoc,
                                        const sctp_subtype_t type,
                                        void *arg,
@@ -1632,7 +1658,7 @@ sctp_disposition_t sctp_sf_do_5_2_2_dupinit(const struct sctp_endpoint *ep,
        /* Call helper to do the real work for both simulataneous and
         * duplicate INIT chunk handling.
         */
-       return sctp_sf_do_unexpected_init(ep, asoc, type, arg, commands);
+       return sctp_sf_do_unexpected_init(net, ep, asoc, type, arg, commands);
 }
 
 
@@ -1645,7 +1671,8 @@ sctp_disposition_t sctp_sf_do_5_2_2_dupinit(const struct sctp_endpoint *ep,
  * An unexpected INIT ACK usually indicates the processing of an old or
  * duplicated INIT chunk.
 */
-sctp_disposition_t sctp_sf_do_5_2_3_initack(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_do_5_2_3_initack(struct net *net,
+                                           const struct sctp_endpoint *ep,
                                            const struct sctp_association *asoc,
                                            const sctp_subtype_t type,
                                            void *arg, sctp_cmd_seq_t *commands)
@@ -1653,10 +1680,10 @@ sctp_disposition_t sctp_sf_do_5_2_3_initack(const struct sctp_endpoint *ep,
        /* Per the above section, we'll discard the chunk if we have an
         * endpoint.  If this is an OOTB INIT-ACK, treat it as such.
         */
-       if (ep == sctp_sk((sctp_get_ctl_sock()))->ep)
-               return sctp_sf_ootb(ep, asoc, type, arg, commands);
+       if (ep == sctp_sk(net->sctp.ctl_sock)->ep)
+               return sctp_sf_ootb(net, ep, asoc, type, arg, commands);
        else
-               return sctp_sf_discard_chunk(ep, asoc, type, arg, commands);
+               return sctp_sf_discard_chunk(net, ep, asoc, type, arg, commands);
 }
 
 /* Unexpected COOKIE-ECHO handler for peer restart (Table 2, action 'A')
@@ -1664,7 +1691,8 @@ sctp_disposition_t sctp_sf_do_5_2_3_initack(const struct sctp_endpoint *ep,
  * Section 5.2.4
  *  A)  In this case, the peer may have restarted.
  */
-static sctp_disposition_t sctp_sf_do_dupcook_a(const struct sctp_endpoint *ep,
+static sctp_disposition_t sctp_sf_do_dupcook_a(struct net *net,
+                                       const struct sctp_endpoint *ep,
                                        const struct sctp_association *asoc,
                                        struct sctp_chunk *chunk,
                                        sctp_cmd_seq_t *commands,
@@ -1700,7 +1728,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const struct sctp_endpoint *ep,
         * its peer.
        */
        if (sctp_state(asoc, SHUTDOWN_ACK_SENT)) {
-               disposition = sctp_sf_do_9_2_reshutack(ep, asoc,
+               disposition = sctp_sf_do_9_2_reshutack(net, ep, asoc,
                                SCTP_ST_CHUNK(chunk->chunk_hdr->type),
                                chunk, commands);
                if (SCTP_DISPOSITION_NOMEM == disposition)
@@ -1763,7 +1791,8 @@ nomem:
  *      after responding to the local endpoint's INIT
  */
 /* This case represents an initialization collision.  */
-static sctp_disposition_t sctp_sf_do_dupcook_b(const struct sctp_endpoint *ep,
+static sctp_disposition_t sctp_sf_do_dupcook_b(struct net *net,
+                                       const struct sctp_endpoint *ep,
                                        const struct sctp_association *asoc,
                                        struct sctp_chunk *chunk,
                                        sctp_cmd_seq_t *commands,
@@ -1784,7 +1813,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_b(const struct sctp_endpoint *ep,
        sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc));
        sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
                        SCTP_STATE(SCTP_STATE_ESTABLISHED));
-       SCTP_INC_STATS(SCTP_MIB_CURRESTAB);
+       SCTP_INC_STATS(net, SCTP_MIB_CURRESTAB);
        sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START, SCTP_NULL());
 
        repl = sctp_make_cookie_ack(new_asoc, chunk);
@@ -1833,7 +1862,8 @@ nomem:
  *     but a new tag of its own.
  */
 /* This case represents an initialization collision.  */
-static sctp_disposition_t sctp_sf_do_dupcook_c(const struct sctp_endpoint *ep,
+static sctp_disposition_t sctp_sf_do_dupcook_c(struct net *net,
+                                       const struct sctp_endpoint *ep,
                                        const struct sctp_association *asoc,
                                        struct sctp_chunk *chunk,
                                        sctp_cmd_seq_t *commands,
@@ -1854,7 +1884,8 @@ static sctp_disposition_t sctp_sf_do_dupcook_c(const struct sctp_endpoint *ep,
  *    enter the ESTABLISHED state, if it has not already done so.
  */
 /* This case represents an initialization collision.  */
-static sctp_disposition_t sctp_sf_do_dupcook_d(const struct sctp_endpoint *ep,
+static sctp_disposition_t sctp_sf_do_dupcook_d(struct net *net,
+                                       const struct sctp_endpoint *ep,
                                        const struct sctp_association *asoc,
                                        struct sctp_chunk *chunk,
                                        sctp_cmd_seq_t *commands,
@@ -1876,7 +1907,7 @@ static sctp_disposition_t sctp_sf_do_dupcook_d(const struct sctp_endpoint *ep,
                                SCTP_TO(SCTP_EVENT_TIMEOUT_T1_COOKIE));
                sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
                                SCTP_STATE(SCTP_STATE_ESTABLISHED));
-               SCTP_INC_STATS(SCTP_MIB_CURRESTAB);
+               SCTP_INC_STATS(net, SCTP_MIB_CURRESTAB);
                sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMERS_START,
                                SCTP_NULL());
 
@@ -1948,7 +1979,8 @@ nomem:
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_do_5_2_4_dupcook(struct net *net,
+                                       const struct sctp_endpoint *ep,
                                        const struct sctp_association *asoc,
                                        const sctp_subtype_t type,
                                        void *arg,
@@ -1967,7 +1999,7 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const struct sctp_endpoint *ep,
         * done later.
         */
        if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
-               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+               return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
                                                  commands);
 
        /* "Decode" the chunk.  We have no optional parameters so we
@@ -2001,12 +2033,12 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const struct sctp_endpoint *ep,
                        goto nomem;
 
                case -SCTP_IERROR_STALE_COOKIE:
-                       sctp_send_stale_cookie_err(ep, asoc, chunk, commands,
+                       sctp_send_stale_cookie_err(net, ep, asoc, chunk, commands,
                                                   err_chk_p);
-                       return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+                       return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
                case -SCTP_IERROR_BAD_SIG:
                default:
-                       return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+                       return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
                }
        }
 
@@ -2017,27 +2049,27 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const struct sctp_endpoint *ep,
 
        switch (action) {
        case 'A': /* Association restart. */
-               retval = sctp_sf_do_dupcook_a(ep, asoc, chunk, commands,
+               retval = sctp_sf_do_dupcook_a(net, ep, asoc, chunk, commands,
                                              new_asoc);
                break;
 
        case 'B': /* Collision case B. */
-               retval = sctp_sf_do_dupcook_b(ep, asoc, chunk, commands,
+               retval = sctp_sf_do_dupcook_b(net, ep, asoc, chunk, commands,
                                              new_asoc);
                break;
 
        case 'C': /* Collision case C. */
-               retval = sctp_sf_do_dupcook_c(ep, asoc, chunk, commands,
+               retval = sctp_sf_do_dupcook_c(net, ep, asoc, chunk, commands,
                                              new_asoc);
                break;
 
        case 'D': /* Collision case D. */
-               retval = sctp_sf_do_dupcook_d(ep, asoc, chunk, commands,
+               retval = sctp_sf_do_dupcook_d(net, ep, asoc, chunk, commands,
                                              new_asoc);
                break;
 
        default: /* Discard packet for all others. */
-               retval = sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               retval = sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
                break;
        }
 
@@ -2063,6 +2095,7 @@ nomem:
  * See sctp_sf_do_9_1_abort().
  */
 sctp_disposition_t sctp_sf_shutdown_pending_abort(
+       struct net *net,
        const struct sctp_endpoint *ep,
        const struct sctp_association *asoc,
        const sctp_subtype_t type,
@@ -2072,7 +2105,7 @@ sctp_disposition_t sctp_sf_shutdown_pending_abort(
        struct sctp_chunk *chunk = arg;
 
        if (!sctp_vtag_verify_either(chunk, asoc))
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
        /* Make sure that the ABORT chunk has a valid length.
         * Since this is an ABORT chunk, we have to discard it
@@ -2085,7 +2118,7 @@ sctp_disposition_t sctp_sf_shutdown_pending_abort(
         * packet.
         */
        if (!sctp_chunk_length_valid(chunk, sizeof(sctp_abort_chunk_t)))
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
        /* ADD-IP: Special case for ABORT chunks
         * F4)  One special consideration is that ABORT Chunks arriving
@@ -2094,9 +2127,9 @@ sctp_disposition_t sctp_sf_shutdown_pending_abort(
         */
        if (SCTP_ADDR_DEL ==
                    sctp_bind_addr_state(&asoc->base.bind_addr, &chunk->dest))
-               return sctp_sf_discard_chunk(ep, asoc, type, arg, commands);
+               return sctp_sf_discard_chunk(net, ep, asoc, type, arg, commands);
 
-       return __sctp_sf_do_9_1_abort(ep, asoc, type, arg, commands);
+       return __sctp_sf_do_9_1_abort(net, ep, asoc, type, arg, commands);
 }
 
 /*
@@ -2104,7 +2137,8 @@ sctp_disposition_t sctp_sf_shutdown_pending_abort(
  *
  * See sctp_sf_do_9_1_abort().
  */
-sctp_disposition_t sctp_sf_shutdown_sent_abort(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_shutdown_sent_abort(struct net *net,
+                                       const struct sctp_endpoint *ep,
                                        const struct sctp_association *asoc,
                                        const sctp_subtype_t type,
                                        void *arg,
@@ -2113,7 +2147,7 @@ sctp_disposition_t sctp_sf_shutdown_sent_abort(const struct sctp_endpoint *ep,
        struct sctp_chunk *chunk = arg;
 
        if (!sctp_vtag_verify_either(chunk, asoc))
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
        /* Make sure that the ABORT chunk has a valid length.
         * Since this is an ABORT chunk, we have to discard it
@@ -2126,7 +2160,7 @@ sctp_disposition_t sctp_sf_shutdown_sent_abort(const struct sctp_endpoint *ep,
         * packet.
         */
        if (!sctp_chunk_length_valid(chunk, sizeof(sctp_abort_chunk_t)))
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
        /* ADD-IP: Special case for ABORT chunks
         * F4)  One special consideration is that ABORT Chunks arriving
@@ -2135,7 +2169,7 @@ sctp_disposition_t sctp_sf_shutdown_sent_abort(const struct sctp_endpoint *ep,
         */
        if (SCTP_ADDR_DEL ==
                    sctp_bind_addr_state(&asoc->base.bind_addr, &chunk->dest))
-               return sctp_sf_discard_chunk(ep, asoc, type, arg, commands);
+               return sctp_sf_discard_chunk(net, ep, asoc, type, arg, commands);
 
        /* Stop the T2-shutdown timer. */
        sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
@@ -2145,7 +2179,7 @@ sctp_disposition_t sctp_sf_shutdown_sent_abort(const struct sctp_endpoint *ep,
        sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
                        SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD));
 
-       return __sctp_sf_do_9_1_abort(ep, asoc, type, arg, commands);
+       return __sctp_sf_do_9_1_abort(net, ep, asoc, type, arg, commands);
 }
 
 /*
@@ -2154,6 +2188,7 @@ sctp_disposition_t sctp_sf_shutdown_sent_abort(const struct sctp_endpoint *ep,
  * See sctp_sf_do_9_1_abort().
  */
 sctp_disposition_t sctp_sf_shutdown_ack_sent_abort(
+       struct net *net,
        const struct sctp_endpoint *ep,
        const struct sctp_association *asoc,
        const sctp_subtype_t type,
@@ -2163,7 +2198,7 @@ sctp_disposition_t sctp_sf_shutdown_ack_sent_abort(
        /* The same T2 timer, so we should be able to use
         * common function with the SHUTDOWN-SENT state.
         */
-       return sctp_sf_shutdown_sent_abort(ep, asoc, type, arg, commands);
+       return sctp_sf_shutdown_sent_abort(net, ep, asoc, type, arg, commands);
 }
 
 /*
@@ -2180,7 +2215,8 @@ sctp_disposition_t sctp_sf_shutdown_ack_sent_abort(
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_cookie_echoed_err(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_cookie_echoed_err(struct net *net,
+                                       const struct sctp_endpoint *ep,
                                        const struct sctp_association *asoc,
                                        const sctp_subtype_t type,
                                        void *arg,
@@ -2190,13 +2226,13 @@ sctp_disposition_t sctp_sf_cookie_echoed_err(const struct sctp_endpoint *ep,
        sctp_errhdr_t *err;
 
        if (!sctp_vtag_verify(chunk, asoc))
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
        /* Make sure that the ERROR chunk has a valid length.
         * The parameter walking depends on this as well.
         */
        if (!sctp_chunk_length_valid(chunk, sizeof(sctp_operr_chunk_t)))
-               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+               return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
                                                  commands);
 
        /* Process the error here */
@@ -2206,7 +2242,7 @@ sctp_disposition_t sctp_sf_cookie_echoed_err(const struct sctp_endpoint *ep,
         */
        sctp_walk_errors(err, chunk->chunk_hdr) {
                if (SCTP_ERROR_STALE_COOKIE == err->cause)
-                       return sctp_sf_do_5_2_6_stale(ep, asoc, type,
+                       return sctp_sf_do_5_2_6_stale(net, ep, asoc, type,
                                                        arg, commands);
        }
 
@@ -2215,7 +2251,7 @@ sctp_disposition_t sctp_sf_cookie_echoed_err(const struct sctp_endpoint *ep,
         * we are discarding the packet, there should be no adverse
         * affects.
         */
-       return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+       return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 }
 
 /*
@@ -2243,7 +2279,8 @@ sctp_disposition_t sctp_sf_cookie_echoed_err(const struct sctp_endpoint *ep,
  *
  * The return value is the disposition of the chunk.
  */
-static sctp_disposition_t sctp_sf_do_5_2_6_stale(const struct sctp_endpoint *ep,
+static sctp_disposition_t sctp_sf_do_5_2_6_stale(struct net *net,
+                                                const struct sctp_endpoint *ep,
                                                 const struct sctp_association *asoc,
                                                 const sctp_subtype_t type,
                                                 void *arg,
@@ -2365,7 +2402,8 @@ nomem:
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_do_9_1_abort(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_do_9_1_abort(struct net *net,
+                                       const struct sctp_endpoint *ep,
                                        const struct sctp_association *asoc,
                                        const sctp_subtype_t type,
                                        void *arg,
@@ -2374,7 +2412,7 @@ sctp_disposition_t sctp_sf_do_9_1_abort(const struct sctp_endpoint *ep,
        struct sctp_chunk *chunk = arg;
 
        if (!sctp_vtag_verify_either(chunk, asoc))
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
        /* Make sure that the ABORT chunk has a valid length.
         * Since this is an ABORT chunk, we have to discard it
@@ -2387,7 +2425,7 @@ sctp_disposition_t sctp_sf_do_9_1_abort(const struct sctp_endpoint *ep,
         * packet.
         */
        if (!sctp_chunk_length_valid(chunk, sizeof(sctp_abort_chunk_t)))
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
        /* ADD-IP: Special case for ABORT chunks
         * F4)  One special consideration is that ABORT Chunks arriving
@@ -2396,12 +2434,13 @@ sctp_disposition_t sctp_sf_do_9_1_abort(const struct sctp_endpoint *ep,
         */
        if (SCTP_ADDR_DEL ==
                    sctp_bind_addr_state(&asoc->base.bind_addr, &chunk->dest))
-               return sctp_sf_discard_chunk(ep, asoc, type, arg, commands);
+               return sctp_sf_discard_chunk(net, ep, asoc, type, arg, commands);
 
-       return __sctp_sf_do_9_1_abort(ep, asoc, type, arg, commands);
+       return __sctp_sf_do_9_1_abort(net, ep, asoc, type, arg, commands);
 }
 
-static sctp_disposition_t __sctp_sf_do_9_1_abort(const struct sctp_endpoint *ep,
+static sctp_disposition_t __sctp_sf_do_9_1_abort(struct net *net,
+                                       const struct sctp_endpoint *ep,
                                        const struct sctp_association *asoc,
                                        const sctp_subtype_t type,
                                        void *arg,
@@ -2418,7 +2457,7 @@ static sctp_disposition_t __sctp_sf_do_9_1_abort(const struct sctp_endpoint *ep,
                sctp_errhdr_t *err;
                sctp_walk_errors(err, chunk->chunk_hdr);
                if ((void *)err != (void *)chunk->chunk_end)
-                       return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+                       return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
                error = ((sctp_errhdr_t *)chunk->skb->data)->cause;
        }
@@ -2426,8 +2465,8 @@ static sctp_disposition_t __sctp_sf_do_9_1_abort(const struct sctp_endpoint *ep,
        sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, SCTP_ERROR(ECONNRESET));
        /* ASSOC_FAILED will DELETE_TCB. */
        sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_PERR(error));
-       SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
-       SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
+       SCTP_INC_STATS(net, SCTP_MIB_ABORTEDS);
+       SCTP_DEC_STATS(net, SCTP_MIB_CURRESTAB);
 
        return SCTP_DISPOSITION_ABORT;
 }
@@ -2437,7 +2476,8 @@ static sctp_disposition_t __sctp_sf_do_9_1_abort(const struct sctp_endpoint *ep,
  *
  * See sctp_sf_do_9_1_abort() above.
  */
-sctp_disposition_t sctp_sf_cookie_wait_abort(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_cookie_wait_abort(struct net *net,
+                                    const struct sctp_endpoint *ep,
                                     const struct sctp_association *asoc,
                                     const sctp_subtype_t type,
                                     void *arg,
@@ -2448,7 +2488,7 @@ sctp_disposition_t sctp_sf_cookie_wait_abort(const struct sctp_endpoint *ep,
        __be16 error = SCTP_ERROR_NO_ERROR;
 
        if (!sctp_vtag_verify_either(chunk, asoc))
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
        /* Make sure that the ABORT chunk has a valid length.
         * Since this is an ABORT chunk, we have to discard it
@@ -2461,27 +2501,28 @@ sctp_disposition_t sctp_sf_cookie_wait_abort(const struct sctp_endpoint *ep,
         * packet.
         */
        if (!sctp_chunk_length_valid(chunk, sizeof(sctp_abort_chunk_t)))
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
        /* See if we have an error cause code in the chunk.  */
        len = ntohs(chunk->chunk_hdr->length);
        if (len >= sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_errhdr))
                error = ((sctp_errhdr_t *)chunk->skb->data)->cause;
 
-       return sctp_stop_t1_and_abort(commands, error, ECONNREFUSED, asoc,
+       return sctp_stop_t1_and_abort(net, commands, error, ECONNREFUSED, asoc,
                                      chunk->transport);
 }
 
 /*
  * Process an incoming ICMP as an ABORT.  (COOKIE-WAIT state)
  */
-sctp_disposition_t sctp_sf_cookie_wait_icmp_abort(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_cookie_wait_icmp_abort(struct net *net,
+                                       const struct sctp_endpoint *ep,
                                        const struct sctp_association *asoc,
                                        const sctp_subtype_t type,
                                        void *arg,
                                        sctp_cmd_seq_t *commands)
 {
-       return sctp_stop_t1_and_abort(commands, SCTP_ERROR_NO_ERROR,
+       return sctp_stop_t1_and_abort(net, commands, SCTP_ERROR_NO_ERROR,
                                      ENOPROTOOPT, asoc,
                                      (struct sctp_transport *)arg);
 }
@@ -2489,7 +2530,8 @@ sctp_disposition_t sctp_sf_cookie_wait_icmp_abort(const struct sctp_endpoint *ep
 /*
  * Process an ABORT.  (COOKIE-ECHOED state)
  */
-sctp_disposition_t sctp_sf_cookie_echoed_abort(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_cookie_echoed_abort(struct net *net,
+                                              const struct sctp_endpoint *ep,
                                               const struct sctp_association *asoc,
                                               const sctp_subtype_t type,
                                               void *arg,
@@ -2498,7 +2540,7 @@ sctp_disposition_t sctp_sf_cookie_echoed_abort(const struct sctp_endpoint *ep,
        /* There is a single T1 timer, so we should be able to use
         * common function with the COOKIE-WAIT state.
         */
-       return sctp_sf_cookie_wait_abort(ep, asoc, type, arg, commands);
+       return sctp_sf_cookie_wait_abort(net, ep, asoc, type, arg, commands);
 }
 
 /*
@@ -2506,7 +2548,8 @@ sctp_disposition_t sctp_sf_cookie_echoed_abort(const struct sctp_endpoint *ep,
  *
  * This is common code called by several sctp_sf_*_abort() functions above.
  */
-static sctp_disposition_t sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands,
+static sctp_disposition_t sctp_stop_t1_and_abort(struct net *net,
+                                          sctp_cmd_seq_t *commands,
                                           __be16 error, int sk_err,
                                           const struct sctp_association *asoc,
                                           struct sctp_transport *transport)
@@ -2514,7 +2557,7 @@ static sctp_disposition_t sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands,
        SCTP_DEBUG_PRINTK("ABORT received (INIT).\n");
        sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
                        SCTP_STATE(SCTP_STATE_CLOSED));
-       SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
+       SCTP_INC_STATS(net, SCTP_MIB_ABORTEDS);
        sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
                        SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
        sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, SCTP_ERROR(sk_err));
@@ -2557,7 +2600,8 @@ static sctp_disposition_t sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands,
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_do_9_2_shutdown(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_do_9_2_shutdown(struct net *net,
+                                          const struct sctp_endpoint *ep,
                                           const struct sctp_association *asoc,
                                           const sctp_subtype_t type,
                                           void *arg,
@@ -2570,12 +2614,12 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown(const struct sctp_endpoint *ep,
        __u32 ctsn;
 
        if (!sctp_vtag_verify(chunk, asoc))
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
        /* Make sure that the SHUTDOWN chunk has a valid length. */
        if (!sctp_chunk_length_valid(chunk,
                                      sizeof(struct sctp_shutdown_chunk_t)))
-               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+               return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
                                                  commands);
 
        /* Convert the elaborate header.  */
@@ -2595,7 +2639,7 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown(const struct sctp_endpoint *ep,
         * sender with an ABORT.
         */
        if (!TSN_lt(ctsn, asoc->next_tsn))
-               return sctp_sf_violation_ctsn(ep, asoc, type, arg, commands);
+               return sctp_sf_violation_ctsn(net, ep, asoc, type, arg, commands);
 
        /* API 5.3.1.5 SCTP_SHUTDOWN_EVENT
         * When a peer sends a SHUTDOWN, SCTP delivers this notification to
@@ -2619,7 +2663,7 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown(const struct sctp_endpoint *ep,
        disposition = SCTP_DISPOSITION_CONSUME;
 
        if (sctp_outq_is_empty(&asoc->outqueue)) {
-               disposition = sctp_sf_do_9_2_shutdown_ack(ep, asoc, type,
+               disposition = sctp_sf_do_9_2_shutdown_ack(net, ep, asoc, type,
                                                          arg, commands);
        }
 
@@ -2645,7 +2689,8 @@ out:
  * The Cumulative TSN Ack of the received SHUTDOWN chunk
  * MUST be processed.
  */
-sctp_disposition_t sctp_sf_do_9_2_shut_ctsn(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_do_9_2_shut_ctsn(struct net *net,
+                                          const struct sctp_endpoint *ep,
                                           const struct sctp_association *asoc,
                                           const sctp_subtype_t type,
                                           void *arg,
@@ -2656,12 +2701,12 @@ sctp_disposition_t sctp_sf_do_9_2_shut_ctsn(const struct sctp_endpoint *ep,
        __u32 ctsn;
 
        if (!sctp_vtag_verify(chunk, asoc))
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
        /* Make sure that the SHUTDOWN chunk has a valid length. */
        if (!sctp_chunk_length_valid(chunk,
                                      sizeof(struct sctp_shutdown_chunk_t)))
-               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+               return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
                                                  commands);
 
        sdh = (sctp_shutdownhdr_t *)chunk->skb->data;
@@ -2678,7 +2723,7 @@ sctp_disposition_t sctp_sf_do_9_2_shut_ctsn(const struct sctp_endpoint *ep,
         * sender with an ABORT.
         */
        if (!TSN_lt(ctsn, asoc->next_tsn))
-               return sctp_sf_violation_ctsn(ep, asoc, type, arg, commands);
+               return sctp_sf_violation_ctsn(net, ep, asoc, type, arg, commands);
 
        /* verify, by checking the Cumulative TSN Ack field of the
         * chunk, that all its outstanding DATA chunks have been
@@ -2697,7 +2742,8 @@ sctp_disposition_t sctp_sf_do_9_2_shut_ctsn(const struct sctp_endpoint *ep,
  * that belong to this association, it should discard the INIT chunk and
  * retransmit the SHUTDOWN ACK chunk.
  */
-sctp_disposition_t sctp_sf_do_9_2_reshutack(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_do_9_2_reshutack(struct net *net,
+                                   const struct sctp_endpoint *ep,
                                    const struct sctp_association *asoc,
                                    const sctp_subtype_t type,
                                    void *arg,
@@ -2708,7 +2754,7 @@ sctp_disposition_t sctp_sf_do_9_2_reshutack(const struct sctp_endpoint *ep,
 
        /* Make sure that the chunk has a valid length */
        if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
-               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+               return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
                                                  commands);
 
        /* Since we are not going to really process this INIT, there
@@ -2760,7 +2806,8 @@ nomem:
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_do_ecn_cwr(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_do_ecn_cwr(struct net *net,
+                                     const struct sctp_endpoint *ep,
                                      const struct sctp_association *asoc,
                                      const sctp_subtype_t type,
                                      void *arg,
@@ -2771,10 +2818,10 @@ sctp_disposition_t sctp_sf_do_ecn_cwr(const struct sctp_endpoint *ep,
        u32 lowest_tsn;
 
        if (!sctp_vtag_verify(chunk, asoc))
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
        if (!sctp_chunk_length_valid(chunk, sizeof(sctp_ecne_chunk_t)))
-               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+               return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
                                                  commands);
 
        cwr = (sctp_cwrhdr_t *) chunk->skb->data;
@@ -2815,7 +2862,8 @@ sctp_disposition_t sctp_sf_do_ecn_cwr(const struct sctp_endpoint *ep,
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_do_ecne(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_do_ecne(struct net *net,
+                                  const struct sctp_endpoint *ep,
                                   const struct sctp_association *asoc,
                                   const sctp_subtype_t type,
                                   void *arg,
@@ -2825,10 +2873,10 @@ sctp_disposition_t sctp_sf_do_ecne(const struct sctp_endpoint *ep,
        struct sctp_chunk *chunk = arg;
 
        if (!sctp_vtag_verify(chunk, asoc))
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
        if (!sctp_chunk_length_valid(chunk, sizeof(sctp_ecne_chunk_t)))
-               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+               return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
                                                  commands);
 
        ecne = (sctp_ecnehdr_t *) chunk->skb->data;
@@ -2871,7 +2919,8 @@ sctp_disposition_t sctp_sf_do_ecne(const struct sctp_endpoint *ep,
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_eat_data_6_2(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_eat_data_6_2(struct net *net,
+                                       const struct sctp_endpoint *ep,
                                        const struct sctp_association *asoc,
                                        const sctp_subtype_t type,
                                        void *arg,
@@ -2884,11 +2933,11 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const struct sctp_endpoint *ep,
        if (!sctp_vtag_verify(chunk, asoc)) {
                sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG,
                                SCTP_NULL());
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
        }
 
        if (!sctp_chunk_length_valid(chunk, sizeof(sctp_data_chunk_t)))
-               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+               return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
                                                  commands);
 
        error = sctp_eat_data(asoc, chunk, commands );
@@ -2897,16 +2946,16 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const struct sctp_endpoint *ep,
                break;
        case SCTP_IERROR_HIGH_TSN:
        case SCTP_IERROR_BAD_STREAM:
-               SCTP_INC_STATS(SCTP_MIB_IN_DATA_CHUNK_DISCARDS);
+               SCTP_INC_STATS(net, SCTP_MIB_IN_DATA_CHUNK_DISCARDS);
                goto discard_noforce;
        case SCTP_IERROR_DUP_TSN:
        case SCTP_IERROR_IGNORE_TSN:
-               SCTP_INC_STATS(SCTP_MIB_IN_DATA_CHUNK_DISCARDS);
+               SCTP_INC_STATS(net, SCTP_MIB_IN_DATA_CHUNK_DISCARDS);
                goto discard_force;
        case SCTP_IERROR_NO_DATA:
                goto consume;
        case SCTP_IERROR_PROTO_VIOLATION:
-               return sctp_sf_abort_violation(ep, asoc, chunk, commands,
+               return sctp_sf_abort_violation(net, ep, asoc, chunk, commands,
                        (u8 *)chunk->subh.data_hdr, sizeof(sctp_datahdr_t));
        default:
                BUG();
@@ -2992,7 +3041,8 @@ consume:
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_eat_data_fast_4_4(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_eat_data_fast_4_4(struct net *net,
+                                    const struct sctp_endpoint *ep,
                                     const struct sctp_association *asoc,
                                     const sctp_subtype_t type,
                                     void *arg,
@@ -3004,11 +3054,11 @@ sctp_disposition_t sctp_sf_eat_data_fast_4_4(const struct sctp_endpoint *ep,
        if (!sctp_vtag_verify(chunk, asoc)) {
                sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG,
                                SCTP_NULL());
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
        }
 
        if (!sctp_chunk_length_valid(chunk, sizeof(sctp_data_chunk_t)))
-               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+               return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
                                                  commands);
 
        error = sctp_eat_data(asoc, chunk, commands );
@@ -3022,7 +3072,7 @@ sctp_disposition_t sctp_sf_eat_data_fast_4_4(const struct sctp_endpoint *ep,
        case SCTP_IERROR_NO_DATA:
                goto consume;
        case SCTP_IERROR_PROTO_VIOLATION:
-               return sctp_sf_abort_violation(ep, asoc, chunk, commands,
+               return sctp_sf_abort_violation(net, ep, asoc, chunk, commands,
                        (u8 *)chunk->subh.data_hdr, sizeof(sctp_datahdr_t));
        default:
                BUG();
@@ -3082,7 +3132,8 @@ consume:
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_eat_sack_6_2(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_eat_sack_6_2(struct net *net,
+                                       const struct sctp_endpoint *ep,
                                        const struct sctp_association *asoc,
                                        const sctp_subtype_t type,
                                        void *arg,
@@ -3093,18 +3144,18 @@ sctp_disposition_t sctp_sf_eat_sack_6_2(const struct sctp_endpoint *ep,
        __u32 ctsn;
 
        if (!sctp_vtag_verify(chunk, asoc))
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
        /* Make sure that the SACK chunk has a valid length. */
        if (!sctp_chunk_length_valid(chunk, sizeof(sctp_sack_chunk_t)))
-               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+               return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
                                                  commands);
 
        /* Pull the SACK chunk from the data buffer */
        sackh = sctp_sm_pull_sack(chunk);
        /* Was this a bogus SACK? */
        if (!sackh)
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
        chunk->subh.sack_hdr = sackh;
        ctsn = ntohl(sackh->cum_tsn_ack);
 
@@ -3125,7 +3176,7 @@ sctp_disposition_t sctp_sf_eat_sack_6_2(const struct sctp_endpoint *ep,
         * sender with an ABORT.
         */
        if (!TSN_lt(ctsn, asoc->next_tsn))
-               return sctp_sf_violation_ctsn(ep, asoc, type, arg, commands);
+               return sctp_sf_violation_ctsn(net, ep, asoc, type, arg, commands);
 
        /* Return this SACK for further processing.  */
        sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_SACK, SCTP_SACKH(sackh));
@@ -3154,7 +3205,8 @@ sctp_disposition_t sctp_sf_eat_sack_6_2(const struct sctp_endpoint *ep,
  *
  * The return value is the disposition of the chunk.
 */
-static sctp_disposition_t sctp_sf_tabort_8_4_8(const struct sctp_endpoint *ep,
+static sctp_disposition_t sctp_sf_tabort_8_4_8(struct net *net,
+                                       const struct sctp_endpoint *ep,
                                        const struct sctp_association *asoc,
                                        const sctp_subtype_t type,
                                        void *arg,
@@ -3164,7 +3216,7 @@ static sctp_disposition_t sctp_sf_tabort_8_4_8(const struct sctp_endpoint *ep,
        struct sctp_chunk *chunk = arg;
        struct sctp_chunk *abort;
 
-       packet = sctp_ootb_pkt_new(asoc, chunk);
+       packet = sctp_ootb_pkt_new(net, asoc, chunk);
 
        if (packet) {
                /* Make an ABORT. The T bit will be set if the asoc
@@ -3188,9 +3240,9 @@ static sctp_disposition_t sctp_sf_tabort_8_4_8(const struct sctp_endpoint *ep,
                sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
                                SCTP_PACKET(packet));
 
-               SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
+               SCTP_INC_STATS(net, SCTP_MIB_OUTCTRLCHUNKS);
 
-               sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
                return SCTP_DISPOSITION_CONSUME;
        }
 
@@ -3205,7 +3257,8 @@ static sctp_disposition_t sctp_sf_tabort_8_4_8(const struct sctp_endpoint *ep,
  *
  * The return value is the disposition of the chunk.
 */
-sctp_disposition_t sctp_sf_operr_notify(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_operr_notify(struct net *net,
+                                       const struct sctp_endpoint *ep,
                                        const struct sctp_association *asoc,
                                        const sctp_subtype_t type,
                                        void *arg,
@@ -3215,15 +3268,15 @@ sctp_disposition_t sctp_sf_operr_notify(const struct sctp_endpoint *ep,
        sctp_errhdr_t *err;
 
        if (!sctp_vtag_verify(chunk, asoc))
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
        /* Make sure that the ERROR chunk has a valid length. */
        if (!sctp_chunk_length_valid(chunk, sizeof(sctp_operr_chunk_t)))
-               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+               return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
                                                  commands);
        sctp_walk_errors(err, chunk->chunk_hdr);
        if ((void *)err != (void *)chunk->chunk_end)
-               return sctp_sf_violation_paramlen(ep, asoc, type, arg,
+               return sctp_sf_violation_paramlen(net, ep, asoc, type, arg,
                                                  (void *)err, commands);
 
        sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_OPERR,
@@ -3242,7 +3295,8 @@ sctp_disposition_t sctp_sf_operr_notify(const struct sctp_endpoint *ep,
  *
  * The return value is the disposition.
  */
-sctp_disposition_t sctp_sf_do_9_2_final(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_do_9_2_final(struct net *net,
+                                       const struct sctp_endpoint *ep,
                                        const struct sctp_association *asoc,
                                        const sctp_subtype_t type,
                                        void *arg,
@@ -3253,11 +3307,11 @@ sctp_disposition_t sctp_sf_do_9_2_final(const struct sctp_endpoint *ep,
        struct sctp_ulpevent *ev;
 
        if (!sctp_vtag_verify(chunk, asoc))
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
        /* Make sure that the SHUTDOWN_ACK chunk has a valid length. */
        if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
-               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+               return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
                                                  commands);
        /* 10.2 H) SHUTDOWN COMPLETE notification
         *
@@ -3290,8 +3344,8 @@ sctp_disposition_t sctp_sf_do_9_2_final(const struct sctp_endpoint *ep,
 
        sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
                        SCTP_STATE(SCTP_STATE_CLOSED));
-       SCTP_INC_STATS(SCTP_MIB_SHUTDOWNS);
-       SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
+       SCTP_INC_STATS(net, SCTP_MIB_SHUTDOWNS);
+       SCTP_DEC_STATS(net, SCTP_MIB_CURRESTAB);
        sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));
 
        /* ...and remove all record of the association. */
@@ -3324,7 +3378,8 @@ nomem:
  *    receiver of the OOTB packet shall discard the OOTB packet and take
  *    no further action.
  */
-sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_ootb(struct net *net,
+                               const struct sctp_endpoint *ep,
                                const struct sctp_association *asoc,
                                const sctp_subtype_t type,
                                void *arg,
@@ -3338,13 +3393,13 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep,
        int ootb_shut_ack = 0;
        int ootb_cookie_ack = 0;
 
-       SCTP_INC_STATS(SCTP_MIB_OUTOFBLUES);
+       SCTP_INC_STATS(net, SCTP_MIB_OUTOFBLUES);
 
        ch = (sctp_chunkhdr_t *) chunk->chunk_hdr;
        do {
                /* Report violation if the chunk is less then minimal */
                if (ntohs(ch->length) < sizeof(sctp_chunkhdr_t))
-                       return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+                       return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
                                                  commands);
 
                /* Now that we know we at least have a chunk header,
@@ -3359,7 +3414,7 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep,
                 *   sending an ABORT of its own.
                 */
                if (SCTP_CID_ABORT == ch->type)
-                       return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+                       return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
                /* RFC 8.4, 7) If the packet contains a "Stale cookie" ERROR
                 * or a COOKIE ACK the SCTP Packet should be silently
@@ -3381,18 +3436,18 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep,
                /* Report violation if chunk len overflows */
                ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length));
                if (ch_end > skb_tail_pointer(skb))
-                       return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+                       return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
                                                  commands);
 
                ch = (sctp_chunkhdr_t *) ch_end;
        } while (ch_end < skb_tail_pointer(skb));
 
        if (ootb_shut_ack)
-               return sctp_sf_shut_8_4_5(ep, asoc, type, arg, commands);
+               return sctp_sf_shut_8_4_5(net, ep, asoc, type, arg, commands);
        else if (ootb_cookie_ack)
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
        else
-               return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
+               return sctp_sf_tabort_8_4_8(net, ep, asoc, type, arg, commands);
 }
 
 /*
@@ -3416,7 +3471,8 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep,
  *
  * The return value is the disposition of the chunk.
  */
-static sctp_disposition_t sctp_sf_shut_8_4_5(const struct sctp_endpoint *ep,
+static sctp_disposition_t sctp_sf_shut_8_4_5(struct net *net,
+                                            const struct sctp_endpoint *ep,
                                             const struct sctp_association *asoc,
                                             const sctp_subtype_t type,
                                             void *arg,
@@ -3426,7 +3482,7 @@ static sctp_disposition_t sctp_sf_shut_8_4_5(const struct sctp_endpoint *ep,
        struct sctp_chunk *chunk = arg;
        struct sctp_chunk *shut;
 
-       packet = sctp_ootb_pkt_new(asoc, chunk);
+       packet = sctp_ootb_pkt_new(net, asoc, chunk);
 
        if (packet) {
                /* Make an SHUTDOWN_COMPLETE.
@@ -3450,19 +3506,19 @@ static sctp_disposition_t sctp_sf_shut_8_4_5(const struct sctp_endpoint *ep,
                sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
                                SCTP_PACKET(packet));
 
-               SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
+               SCTP_INC_STATS(net, SCTP_MIB_OUTCTRLCHUNKS);
 
                /* If the chunk length is invalid, we don't want to process
                 * the reset of the packet.
                 */
                if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
-                       return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+                       return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
                /* We need to discard the rest of the packet to prevent
                 * potential bomming attacks from additional bundled chunks.
                 * This is documented in SCTP Threats ID.
                 */
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
        }
 
        return SCTP_DISPOSITION_NOMEM;
@@ -3479,7 +3535,8 @@ static sctp_disposition_t sctp_sf_shut_8_4_5(const struct sctp_endpoint *ep,
  *   chunks. --piggy ]
  *
  */
-sctp_disposition_t sctp_sf_do_8_5_1_E_sa(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_do_8_5_1_E_sa(struct net *net,
+                                     const struct sctp_endpoint *ep,
                                      const struct sctp_association *asoc,
                                      const sctp_subtype_t type,
                                      void *arg,
@@ -3489,7 +3546,7 @@ sctp_disposition_t sctp_sf_do_8_5_1_E_sa(const struct sctp_endpoint *ep,
 
        /* Make sure that the SHUTDOWN_ACK chunk has a valid length. */
        if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
-               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+               return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
                                                  commands);
 
        /* Although we do have an association in this case, it corresponds
@@ -3497,13 +3554,14 @@ sctp_disposition_t sctp_sf_do_8_5_1_E_sa(const struct sctp_endpoint *ep,
         * packet and the state function that handles OOTB SHUTDOWN_ACK is
         * called with a NULL association.
         */
-       SCTP_INC_STATS(SCTP_MIB_OUTOFBLUES);
+       SCTP_INC_STATS(net, SCTP_MIB_OUTOFBLUES);
 
-       return sctp_sf_shut_8_4_5(ep, NULL, type, arg, commands);
+       return sctp_sf_shut_8_4_5(net, ep, NULL, type, arg, commands);
 }
 
 /* ADDIP Section 4.2 Upon reception of an ASCONF Chunk.  */
-sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_do_asconf(struct net *net,
+                                    const struct sctp_endpoint *ep,
                                     const struct sctp_association *asoc,
                                     const sctp_subtype_t type, void *arg,
                                     sctp_cmd_seq_t *commands)
@@ -3519,7 +3577,7 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep,
        if (!sctp_vtag_verify(chunk, asoc)) {
                sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG,
                                SCTP_NULL());
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
        }
 
        /* ADD-IP: Section 4.1.1
@@ -3528,12 +3586,12 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep,
         * is received unauthenticated it MUST be silently discarded as
         * described in [I-D.ietf-tsvwg-sctp-auth].
         */
-       if (!sctp_addip_noauth && !chunk->auth)
-               return sctp_sf_discard_chunk(ep, asoc, type, arg, commands);
+       if (!net->sctp.addip_noauth && !chunk->auth)
+               return sctp_sf_discard_chunk(net, ep, asoc, type, arg, commands);
 
        /* Make sure that the ASCONF ADDIP chunk has a valid length.  */
        if (!sctp_chunk_length_valid(chunk, sizeof(sctp_addip_chunk_t)))
-               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+               return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
                                                  commands);
 
        hdr = (sctp_addiphdr_t *)chunk->skb->data;
@@ -3542,7 +3600,7 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep,
        addr_param = (union sctp_addr_param *)hdr->params;
        length = ntohs(addr_param->p.length);
        if (length < sizeof(sctp_paramhdr_t))
-               return sctp_sf_violation_paramlen(ep, asoc, type, arg,
+               return sctp_sf_violation_paramlen(net, ep, asoc, type, arg,
                           (void *)addr_param, commands);
 
        /* Verify the ASCONF chunk before processing it. */
@@ -3550,7 +3608,7 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep,
                            (sctp_paramhdr_t *)((void *)addr_param + length),
                            (void *)chunk->chunk_end,
                            &err_param))
-               return sctp_sf_violation_paramlen(ep, asoc, type, arg,
+               return sctp_sf_violation_paramlen(net, ep, asoc, type, arg,
                                                  (void *)err_param, commands);
 
        /* ADDIP 5.2 E1) Compare the value of the serial number to the value
@@ -3630,7 +3688,8 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep,
  * When building TLV parameters for the ASCONF Chunk that will add or
  * delete IP addresses the D0 to D13 rules should be applied:
  */
-sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_do_asconf_ack(struct net *net,
+                                        const struct sctp_endpoint *ep,
                                         const struct sctp_association *asoc,
                                         const sctp_subtype_t type, void *arg,
                                         sctp_cmd_seq_t *commands)
@@ -3645,7 +3704,7 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep,
        if (!sctp_vtag_verify(asconf_ack, asoc)) {
                sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG,
                                SCTP_NULL());
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
        }
 
        /* ADD-IP, Section 4.1.2:
@@ -3654,12 +3713,12 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep,
         * is received unauthenticated it MUST be silently discarded as
         * described in [I-D.ietf-tsvwg-sctp-auth].
         */
-       if (!sctp_addip_noauth && !asconf_ack->auth)
-               return sctp_sf_discard_chunk(ep, asoc, type, arg, commands);
+       if (!net->sctp.addip_noauth && !asconf_ack->auth)
+               return sctp_sf_discard_chunk(net, ep, asoc, type, arg, commands);
 
        /* Make sure that the ADDIP chunk has a valid length.  */
        if (!sctp_chunk_length_valid(asconf_ack, sizeof(sctp_addip_chunk_t)))
-               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+               return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
                                                  commands);
 
        addip_hdr = (sctp_addiphdr_t *)asconf_ack->skb->data;
@@ -3670,7 +3729,7 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep,
            (sctp_paramhdr_t *)addip_hdr->params,
            (void *)asconf_ack->chunk_end,
            &err_param))
-               return sctp_sf_violation_paramlen(ep, asoc, type, arg,
+               return sctp_sf_violation_paramlen(net, ep, asoc, type, arg,
                           (void *)err_param, commands);
 
        if (last_asconf) {
@@ -3705,8 +3764,8 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep,
                                SCTP_ERROR(ECONNABORTED));
                sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
                                SCTP_PERR(SCTP_ERROR_ASCONF_ACK));
-               SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
-               SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
+               SCTP_INC_STATS(net, SCTP_MIB_ABORTEDS);
+               SCTP_DEC_STATS(net, SCTP_MIB_CURRESTAB);
                return SCTP_DISPOSITION_ABORT;
        }
 
@@ -3739,8 +3798,8 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep,
                                SCTP_ERROR(ECONNABORTED));
                sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
                                SCTP_PERR(SCTP_ERROR_ASCONF_ACK));
-               SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
-               SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
+               SCTP_INC_STATS(net, SCTP_MIB_ABORTEDS);
+               SCTP_DEC_STATS(net, SCTP_MIB_CURRESTAB);
                return SCTP_DISPOSITION_ABORT;
        }
 
@@ -3761,7 +3820,8 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep,
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_eat_fwd_tsn(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_eat_fwd_tsn(struct net *net,
+                                      const struct sctp_endpoint *ep,
                                       const struct sctp_association *asoc,
                                       const sctp_subtype_t type,
                                       void *arg,
@@ -3776,12 +3836,12 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn(const struct sctp_endpoint *ep,
        if (!sctp_vtag_verify(chunk, asoc)) {
                sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG,
                                SCTP_NULL());
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
        }
 
        /* Make sure that the FORWARD_TSN chunk has valid length.  */
        if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_fwdtsn_chunk)))
-               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+               return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
                                                  commands);
 
        fwdtsn_hdr = (struct sctp_fwdtsn_hdr *)chunk->skb->data;
@@ -3828,6 +3888,7 @@ discard_noforce:
 }
 
 sctp_disposition_t sctp_sf_eat_fwd_tsn_fast(
+       struct net *net,
        const struct sctp_endpoint *ep,
        const struct sctp_association *asoc,
        const sctp_subtype_t type,
@@ -3843,12 +3904,12 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn_fast(
        if (!sctp_vtag_verify(chunk, asoc)) {
                sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG,
                                SCTP_NULL());
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
        }
 
        /* Make sure that the FORWARD_TSN chunk has a valid length.  */
        if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_fwdtsn_chunk)))
-               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+               return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
                                                  commands);
 
        fwdtsn_hdr = (struct sctp_fwdtsn_hdr *)chunk->skb->data;
@@ -3915,7 +3976,8 @@ gen_shutdown:
  *
  * The return value is the disposition of the chunk.
  */
-static sctp_ierror_t sctp_sf_authenticate(const struct sctp_endpoint *ep,
+static sctp_ierror_t sctp_sf_authenticate(struct net *net,
+                                   const struct sctp_endpoint *ep,
                                    const struct sctp_association *asoc,
                                    const sctp_subtype_t type,
                                    struct sctp_chunk *chunk)
@@ -3988,7 +4050,8 @@ nomem:
        return SCTP_IERROR_NOMEM;
 }
 
-sctp_disposition_t sctp_sf_eat_auth(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_eat_auth(struct net *net,
+                                   const struct sctp_endpoint *ep,
                                    const struct sctp_association *asoc,
                                    const sctp_subtype_t type,
                                    void *arg,
@@ -4001,21 +4064,21 @@ sctp_disposition_t sctp_sf_eat_auth(const struct sctp_endpoint *ep,
 
        /* Make sure that the peer has AUTH capable */
        if (!asoc->peer.auth_capable)
-               return sctp_sf_unk_chunk(ep, asoc, type, arg, commands);
+               return sctp_sf_unk_chunk(net, ep, asoc, type, arg, commands);
 
        if (!sctp_vtag_verify(chunk, asoc)) {
                sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG,
                                SCTP_NULL());
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
        }
 
        /* Make sure that the AUTH chunk has valid length.  */
        if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_auth_chunk)))
-               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+               return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
                                                  commands);
 
        auth_hdr = (struct sctp_authhdr *)chunk->skb->data;
-       error = sctp_sf_authenticate(ep, asoc, type, chunk);
+       error = sctp_sf_authenticate(net, ep, asoc, type, chunk);
        switch (error) {
        case SCTP_IERROR_AUTH_BAD_HMAC:
                /* Generate the ERROR chunk and discard the rest
@@ -4032,10 +4095,10 @@ sctp_disposition_t sctp_sf_eat_auth(const struct sctp_endpoint *ep,
                /* Fall Through */
        case SCTP_IERROR_AUTH_BAD_KEYID:
        case SCTP_IERROR_BAD_SIG:
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
        case SCTP_IERROR_PROTO_VIOLATION:
-               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+               return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
                                                  commands);
 
        case SCTP_IERROR_NOMEM:
@@ -4084,7 +4147,8 @@ sctp_disposition_t sctp_sf_eat_auth(const struct sctp_endpoint *ep,
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_unk_chunk(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_unk_chunk(struct net *net,
+                                    const struct sctp_endpoint *ep,
                                     const struct sctp_association *asoc,
                                     const sctp_subtype_t type,
                                     void *arg,
@@ -4097,20 +4161,20 @@ sctp_disposition_t sctp_sf_unk_chunk(const struct sctp_endpoint *ep,
        SCTP_DEBUG_PRINTK("Processing the unknown chunk id %d.\n", type.chunk);
 
        if (!sctp_vtag_verify(unk_chunk, asoc))
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
        /* Make sure that the chunk has a valid length.
         * Since we don't know the chunk type, we use a general
         * chunkhdr structure to make a comparison.
         */
        if (!sctp_chunk_length_valid(unk_chunk, sizeof(sctp_chunkhdr_t)))
-               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+               return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
                                                  commands);
 
        switch (type.chunk & SCTP_CID_ACTION_MASK) {
        case SCTP_CID_ACTION_DISCARD:
                /* Discard the packet.  */
-               return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
                break;
        case SCTP_CID_ACTION_DISCARD_ERR:
                /* Generate an ERROR chunk as response. */
@@ -4125,7 +4189,7 @@ sctp_disposition_t sctp_sf_unk_chunk(const struct sctp_endpoint *ep,
                }
 
                /* Discard the packet.  */
-               sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+               sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
                return SCTP_DISPOSITION_CONSUME;
                break;
        case SCTP_CID_ACTION_SKIP:
@@ -4167,7 +4231,8 @@ sctp_disposition_t sctp_sf_unk_chunk(const struct sctp_endpoint *ep,
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_discard_chunk(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_discard_chunk(struct net *net,
+                                        const struct sctp_endpoint *ep,
                                         const struct sctp_association *asoc,
                                         const sctp_subtype_t type,
                                         void *arg,
@@ -4180,7 +4245,7 @@ sctp_disposition_t sctp_sf_discard_chunk(const struct sctp_endpoint *ep,
         * chunkhdr structure to make a comparison.
         */
        if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
-               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+               return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
                                                  commands);
 
        SCTP_DEBUG_PRINTK("Chunk %d is discarded\n", type.chunk);
@@ -4205,13 +4270,14 @@ sctp_disposition_t sctp_sf_discard_chunk(const struct sctp_endpoint *ep,
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_pdiscard(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_pdiscard(struct net *net,
+                                   const struct sctp_endpoint *ep,
                                    const struct sctp_association *asoc,
                                    const sctp_subtype_t type,
                                    void *arg,
                                    sctp_cmd_seq_t *commands)
 {
-       SCTP_INC_STATS(SCTP_MIB_IN_PKT_DISCARDS);
+       SCTP_INC_STATS(net, SCTP_MIB_IN_PKT_DISCARDS);
        sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET, SCTP_NULL());
 
        return SCTP_DISPOSITION_CONSUME;
@@ -4232,7 +4298,8 @@ sctp_disposition_t sctp_sf_pdiscard(const struct sctp_endpoint *ep,
  * We simply tag the chunk as a violation.  The state machine will log
  * the violation and continue.
  */
-sctp_disposition_t sctp_sf_violation(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_violation(struct net *net,
+                                    const struct sctp_endpoint *ep,
                                     const struct sctp_association *asoc,
                                     const sctp_subtype_t type,
                                     void *arg,
@@ -4242,7 +4309,7 @@ sctp_disposition_t sctp_sf_violation(const struct sctp_endpoint *ep,
 
        /* Make sure that the chunk has a valid length. */
        if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
-               return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+               return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
                                                  commands);
 
        return SCTP_DISPOSITION_VIOLATION;
@@ -4252,6 +4319,7 @@ sctp_disposition_t sctp_sf_violation(const struct sctp_endpoint *ep,
  * Common function to handle a protocol violation.
  */
 static sctp_disposition_t sctp_sf_abort_violation(
+                                    struct net *net,
                                     const struct sctp_endpoint *ep,
                                     const struct sctp_association *asoc,
                                     void *arg,
@@ -4302,7 +4370,7 @@ static sctp_disposition_t sctp_sf_abort_violation(
                }
 
                sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
-               SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
+               SCTP_INC_STATS(net, SCTP_MIB_OUTCTRLCHUNKS);
 
                if (asoc->state <= SCTP_STATE_COOKIE_ECHOED) {
                        sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
@@ -4316,10 +4384,10 @@ static sctp_disposition_t sctp_sf_abort_violation(
                                        SCTP_ERROR(ECONNABORTED));
                        sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
                                        SCTP_PERR(SCTP_ERROR_PROTO_VIOLATION));
-                       SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
+                       SCTP_DEC_STATS(net, SCTP_MIB_CURRESTAB);
                }
        } else {
-               packet = sctp_ootb_pkt_new(asoc, chunk);
+               packet = sctp_ootb_pkt_new(net, asoc, chunk);
 
                if (!packet)
                        goto nomem_pkt;
@@ -4334,13 +4402,13 @@ static sctp_disposition_t sctp_sf_abort_violation(
                sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
                        SCTP_PACKET(packet));
 
-               SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
+               SCTP_INC_STATS(net, SCTP_MIB_OUTCTRLCHUNKS);
        }
 
-       SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
+       SCTP_INC_STATS(net, SCTP_MIB_ABORTEDS);
 
 discard:
-       sctp_sf_pdiscard(ep, asoc, SCTP_ST_CHUNK(0), arg, commands);
+       sctp_sf_pdiscard(net, ep, asoc, SCTP_ST_CHUNK(0), arg, commands);
        return SCTP_DISPOSITION_ABORT;
 
 nomem_pkt:
@@ -4369,6 +4437,7 @@ nomem:
  * Generate an  ABORT chunk and terminate the association.
  */
 static sctp_disposition_t sctp_sf_violation_chunklen(
+                                    struct net *net,
                                     const struct sctp_endpoint *ep,
                                     const struct sctp_association *asoc,
                                     const sctp_subtype_t type,
@@ -4377,7 +4446,7 @@ static sctp_disposition_t sctp_sf_violation_chunklen(
 {
        static const char err_str[]="The following chunk had invalid length:";
 
-       return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str,
+       return sctp_sf_abort_violation(net, ep, asoc, arg, commands, err_str,
                                        sizeof(err_str));
 }
 
@@ -4388,6 +4457,7 @@ static sctp_disposition_t sctp_sf_violation_chunklen(
  * the length is considered as invalid.
  */
 static sctp_disposition_t sctp_sf_violation_paramlen(
+                                    struct net *net,
                                     const struct sctp_endpoint *ep,
                                     const struct sctp_association *asoc,
                                     const sctp_subtype_t type,
@@ -4407,17 +4477,17 @@ static sctp_disposition_t sctp_sf_violation_paramlen(
                goto nomem;
 
        sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
-       SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
+       SCTP_INC_STATS(net, SCTP_MIB_OUTCTRLCHUNKS);
 
        sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
                        SCTP_ERROR(ECONNABORTED));
        sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
                        SCTP_PERR(SCTP_ERROR_PROTO_VIOLATION));
-       SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
-       SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
+       SCTP_DEC_STATS(net, SCTP_MIB_CURRESTAB);
+       SCTP_INC_STATS(net, SCTP_MIB_ABORTEDS);
 
 discard:
-       sctp_sf_pdiscard(ep, asoc, SCTP_ST_CHUNK(0), arg, commands);
+       sctp_sf_pdiscard(net, ep, asoc, SCTP_ST_CHUNK(0), arg, commands);
        return SCTP_DISPOSITION_ABORT;
 nomem:
        return SCTP_DISPOSITION_NOMEM;
@@ -4430,6 +4500,7 @@ nomem:
  * error code.
  */
 static sctp_disposition_t sctp_sf_violation_ctsn(
+                                    struct net *net,
                                     const struct sctp_endpoint *ep,
                                     const struct sctp_association *asoc,
                                     const sctp_subtype_t type,
@@ -4438,7 +4509,7 @@ static sctp_disposition_t sctp_sf_violation_ctsn(
 {
        static const char err_str[]="The cumulative tsn ack beyond the max tsn currently sent:";
 
-       return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str,
+       return sctp_sf_abort_violation(net, ep, asoc, arg, commands, err_str,
                                        sizeof(err_str));
 }
 
@@ -4449,6 +4520,7 @@ static sctp_disposition_t sctp_sf_violation_ctsn(
  * on the path and we may not want to continue this communication.
  */
 static sctp_disposition_t sctp_sf_violation_chunk(
+                                    struct net *net,
                                     const struct sctp_endpoint *ep,
                                     const struct sctp_association *asoc,
                                     const sctp_subtype_t type,
@@ -4458,9 +4530,9 @@ static sctp_disposition_t sctp_sf_violation_chunk(
        static const char err_str[]="The following chunk violates protocol:";
 
        if (!asoc)
-               return sctp_sf_violation(ep, asoc, type, arg, commands);
+               return sctp_sf_violation(net, ep, asoc, type, arg, commands);
 
-       return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str,
+       return sctp_sf_abort_violation(net, ep, asoc, arg, commands, err_str,
                                        sizeof(err_str));
 }
 /***************************************************************************
@@ -4523,7 +4595,8 @@ static sctp_disposition_t sctp_sf_violation_chunk(
  *
  * The return value is a disposition.
  */
-sctp_disposition_t sctp_sf_do_prm_asoc(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_do_prm_asoc(struct net *net,
+                                      const struct sctp_endpoint *ep,
                                       const struct sctp_association *asoc,
                                       const sctp_subtype_t type,
                                       void *arg,
@@ -4634,7 +4707,8 @@ nomem:
  *
  * The return value is the disposition.
  */
-sctp_disposition_t sctp_sf_do_prm_send(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_do_prm_send(struct net *net,
+                                      const struct sctp_endpoint *ep,
                                       const struct sctp_association *asoc,
                                       const sctp_subtype_t type,
                                       void *arg,
@@ -4673,6 +4747,7 @@ sctp_disposition_t sctp_sf_do_prm_send(const struct sctp_endpoint *ep,
  * The return value is the disposition.
  */
 sctp_disposition_t sctp_sf_do_9_2_prm_shutdown(
+       struct net *net,
        const struct sctp_endpoint *ep,
        const struct sctp_association *asoc,
        const sctp_subtype_t type,
@@ -4694,7 +4769,7 @@ sctp_disposition_t sctp_sf_do_9_2_prm_shutdown(
 
        disposition = SCTP_DISPOSITION_CONSUME;
        if (sctp_outq_is_empty(&asoc->outqueue)) {
-               disposition = sctp_sf_do_9_2_start_shutdown(ep, asoc, type,
+               disposition = sctp_sf_do_9_2_start_shutdown(net, ep, asoc, type,
                                                            arg, commands);
        }
        return disposition;
@@ -4728,6 +4803,7 @@ sctp_disposition_t sctp_sf_do_9_2_prm_shutdown(
  * The return value is the disposition.
  */
 sctp_disposition_t sctp_sf_do_9_1_prm_abort(
+       struct net *net,
        const struct sctp_endpoint *ep,
        const struct sctp_association *asoc,
        const sctp_subtype_t type,
@@ -4759,14 +4835,15 @@ sctp_disposition_t sctp_sf_do_9_1_prm_abort(
        sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
                        SCTP_PERR(SCTP_ERROR_USER_ABORT));
 
-       SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
-       SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
+       SCTP_INC_STATS(net, SCTP_MIB_ABORTEDS);
+       SCTP_DEC_STATS(net, SCTP_MIB_CURRESTAB);
 
        return retval;
 }
 
 /* We tried an illegal operation on an association which is closed.  */
-sctp_disposition_t sctp_sf_error_closed(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_error_closed(struct net *net,
+                                       const struct sctp_endpoint *ep,
                                        const struct sctp_association *asoc,
                                        const sctp_subtype_t type,
                                        void *arg,
@@ -4779,7 +4856,8 @@ sctp_disposition_t sctp_sf_error_closed(const struct sctp_endpoint *ep,
 /* We tried an illegal operation on an association which is shutting
  * down.
  */
-sctp_disposition_t sctp_sf_error_shutdown(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_error_shutdown(struct net *net,
+                                         const struct sctp_endpoint *ep,
                                          const struct sctp_association *asoc,
                                          const sctp_subtype_t type,
                                          void *arg,
@@ -4805,6 +4883,7 @@ sctp_disposition_t sctp_sf_error_shutdown(const struct sctp_endpoint *ep,
  * (timers)
  */
 sctp_disposition_t sctp_sf_cookie_wait_prm_shutdown(
+       struct net *net,
        const struct sctp_endpoint *ep,
        const struct sctp_association *asoc,
        const sctp_subtype_t type,
@@ -4817,7 +4896,7 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_shutdown(
        sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
                        SCTP_STATE(SCTP_STATE_CLOSED));
 
-       SCTP_INC_STATS(SCTP_MIB_SHUTDOWNS);
+       SCTP_INC_STATS(net, SCTP_MIB_SHUTDOWNS);
 
        sctp_add_cmd_sf(commands, SCTP_CMD_DELETE_TCB, SCTP_NULL());
 
@@ -4839,6 +4918,7 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_shutdown(
  * (timers)
  */
 sctp_disposition_t sctp_sf_cookie_echoed_prm_shutdown(
+       struct net *net,
        const struct sctp_endpoint *ep,
        const struct sctp_association *asoc,
        const sctp_subtype_t type,
@@ -4847,7 +4927,7 @@ sctp_disposition_t sctp_sf_cookie_echoed_prm_shutdown(
        /* There is a single T1 timer, so we should be able to use
         * common function with the COOKIE-WAIT state.
         */
-       return sctp_sf_cookie_wait_prm_shutdown(ep, asoc, type, arg, commands);
+       return sctp_sf_cookie_wait_prm_shutdown(net, ep, asoc, type, arg, commands);
 }
 
 /*
@@ -4865,6 +4945,7 @@ sctp_disposition_t sctp_sf_cookie_echoed_prm_shutdown(
  * (timers)
  */
 sctp_disposition_t sctp_sf_cookie_wait_prm_abort(
+       struct net *net,
        const struct sctp_endpoint *ep,
        const struct sctp_association *asoc,
        const sctp_subtype_t type,
@@ -4884,7 +4965,7 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_abort(
        sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
                        SCTP_STATE(SCTP_STATE_CLOSED));
 
-       SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
+       SCTP_INC_STATS(net, SCTP_MIB_ABORTEDS);
 
        /* Even if we can't send the ABORT due to low memory delete the
         * TCB.  This is a departure from our typical NOMEM handling.
@@ -4914,6 +4995,7 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_abort(
  * (timers)
  */
 sctp_disposition_t sctp_sf_cookie_echoed_prm_abort(
+       struct net *net,
        const struct sctp_endpoint *ep,
        const struct sctp_association *asoc,
        const sctp_subtype_t type,
@@ -4923,7 +5005,7 @@ sctp_disposition_t sctp_sf_cookie_echoed_prm_abort(
        /* There is a single T1 timer, so we should be able to use
         * common function with the COOKIE-WAIT state.
         */
-       return sctp_sf_cookie_wait_prm_abort(ep, asoc, type, arg, commands);
+       return sctp_sf_cookie_wait_prm_abort(net, ep, asoc, type, arg, commands);
 }
 
 /*
@@ -4939,6 +5021,7 @@ sctp_disposition_t sctp_sf_cookie_echoed_prm_abort(
  * (timers)
  */
 sctp_disposition_t sctp_sf_shutdown_pending_prm_abort(
+       struct net *net,
        const struct sctp_endpoint *ep,
        const struct sctp_association *asoc,
        const sctp_subtype_t type,
@@ -4949,7 +5032,7 @@ sctp_disposition_t sctp_sf_shutdown_pending_prm_abort(
        sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
                        SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD));
 
-       return sctp_sf_do_9_1_prm_abort(ep, asoc, type, arg, commands);
+       return sctp_sf_do_9_1_prm_abort(net, ep, asoc, type, arg, commands);
 }
 
 /*
@@ -4965,6 +5048,7 @@ sctp_disposition_t sctp_sf_shutdown_pending_prm_abort(
  * (timers)
  */
 sctp_disposition_t sctp_sf_shutdown_sent_prm_abort(
+       struct net *net,
        const struct sctp_endpoint *ep,
        const struct sctp_association *asoc,
        const sctp_subtype_t type,
@@ -4979,7 +5063,7 @@ sctp_disposition_t sctp_sf_shutdown_sent_prm_abort(
        sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
                        SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD));
 
-       return sctp_sf_do_9_1_prm_abort(ep, asoc, type, arg, commands);
+       return sctp_sf_do_9_1_prm_abort(net, ep, asoc, type, arg, commands);
 }
 
 /*
@@ -4995,6 +5079,7 @@ sctp_disposition_t sctp_sf_shutdown_sent_prm_abort(
  * (timers)
  */
 sctp_disposition_t sctp_sf_shutdown_ack_sent_prm_abort(
+       struct net *net,
        const struct sctp_endpoint *ep,
        const struct sctp_association *asoc,
        const sctp_subtype_t type,
@@ -5004,7 +5089,7 @@ sctp_disposition_t sctp_sf_shutdown_ack_sent_prm_abort(
        /* The same T2 timer, so we should be able to use
         * common function with the SHUTDOWN-SENT state.
         */
-       return sctp_sf_shutdown_sent_prm_abort(ep, asoc, type, arg, commands);
+       return sctp_sf_shutdown_sent_prm_abort(net, ep, asoc, type, arg, commands);
 }
 
 /*
@@ -5030,6 +5115,7 @@ sctp_disposition_t sctp_sf_shutdown_ack_sent_prm_abort(
  *   association on which a heartbeat should be issued.
  */
 sctp_disposition_t sctp_sf_do_prm_requestheartbeat(
+                                       struct net *net,
                                        const struct sctp_endpoint *ep,
                                        const struct sctp_association *asoc,
                                        const sctp_subtype_t type,
@@ -5061,7 +5147,8 @@ sctp_disposition_t sctp_sf_do_prm_requestheartbeat(
  * When an endpoint has an ASCONF signaled change to be sent to the
  * remote endpoint it should do A1 to A9
  */
-sctp_disposition_t sctp_sf_do_prm_asconf(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_do_prm_asconf(struct net *net,
+                                       const struct sctp_endpoint *ep,
                                        const struct sctp_association *asoc,
                                        const sctp_subtype_t type,
                                        void *arg,
@@ -5082,6 +5169,7 @@ sctp_disposition_t sctp_sf_do_prm_asconf(const struct sctp_endpoint *ep,
  * The return value is the disposition of the primitive.
  */
 sctp_disposition_t sctp_sf_ignore_primitive(
+       struct net *net,
        const struct sctp_endpoint *ep,
        const struct sctp_association *asoc,
        const sctp_subtype_t type,
@@ -5103,6 +5191,7 @@ sctp_disposition_t sctp_sf_ignore_primitive(
  * retransmit, the stack will immediately send up this notification.
  */
 sctp_disposition_t sctp_sf_do_no_pending_tsn(
+       struct net *net,
        const struct sctp_endpoint *ep,
        const struct sctp_association *asoc,
        const sctp_subtype_t type,
@@ -5134,6 +5223,7 @@ sctp_disposition_t sctp_sf_do_no_pending_tsn(
  * The return value is the disposition.
  */
 sctp_disposition_t sctp_sf_do_9_2_start_shutdown(
+       struct net *net,
        const struct sctp_endpoint *ep,
        const struct sctp_association *asoc,
        const sctp_subtype_t type,
@@ -5203,6 +5293,7 @@ nomem:
  * The return value is the disposition.
  */
 sctp_disposition_t sctp_sf_do_9_2_shutdown_ack(
+       struct net *net,
        const struct sctp_endpoint *ep,
        const struct sctp_association *asoc,
        const sctp_subtype_t type,
@@ -5221,11 +5312,11 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown_ack(
         */
        if (chunk) {
                if (!sctp_vtag_verify(chunk, asoc))
-                       return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
+                       return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
 
                /* Make sure that the SHUTDOWN chunk has a valid length. */
                if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_shutdown_chunk_t)))
-                       return sctp_sf_violation_chunklen(ep, asoc, type, arg,
+                       return sctp_sf_violation_chunklen(net, ep, asoc, type, arg,
                                                          commands);
        }
 
@@ -5273,7 +5364,8 @@ nomem:
  *
  * The return value is the disposition of the event.
  */
-sctp_disposition_t sctp_sf_ignore_other(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_ignore_other(struct net *net,
+                                       const struct sctp_endpoint *ep,
                                        const struct sctp_association *asoc,
                                        const sctp_subtype_t type,
                                        void *arg,
@@ -5298,7 +5390,8 @@ sctp_disposition_t sctp_sf_ignore_other(const struct sctp_endpoint *ep,
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_do_6_3_3_rtx(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_do_6_3_3_rtx(struct net *net,
+                                       const struct sctp_endpoint *ep,
                                        const struct sctp_association *asoc,
                                        const sctp_subtype_t type,
                                        void *arg,
@@ -5306,7 +5399,7 @@ sctp_disposition_t sctp_sf_do_6_3_3_rtx(const struct sctp_endpoint *ep,
 {
        struct sctp_transport *transport = arg;
 
-       SCTP_INC_STATS(SCTP_MIB_T3_RTX_EXPIREDS);
+       SCTP_INC_STATS(net, SCTP_MIB_T3_RTX_EXPIREDS);
 
        if (asoc->overall_error_count >= asoc->max_retrans) {
                if (asoc->state == SCTP_STATE_SHUTDOWN_PENDING) {
@@ -5327,8 +5420,8 @@ sctp_disposition_t sctp_sf_do_6_3_3_rtx(const struct sctp_endpoint *ep,
                        /* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
                        sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
                                        SCTP_PERR(SCTP_ERROR_NO_ERROR));
-                       SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
-                       SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
+                       SCTP_INC_STATS(net, SCTP_MIB_ABORTEDS);
+                       SCTP_DEC_STATS(net, SCTP_MIB_CURRESTAB);
                        return SCTP_DISPOSITION_DELETE_TCB;
                }
        }
@@ -5384,13 +5477,14 @@ sctp_disposition_t sctp_sf_do_6_3_3_rtx(const struct sctp_endpoint *ep,
  * allow. However, an SCTP transmitter MUST NOT be more aggressive than
  * the following algorithms allow.
  */
-sctp_disposition_t sctp_sf_do_6_2_sack(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_do_6_2_sack(struct net *net,
+                                      const struct sctp_endpoint *ep,
                                       const struct sctp_association *asoc,
                                       const sctp_subtype_t type,
                                       void *arg,
                                       sctp_cmd_seq_t *commands)
 {
-       SCTP_INC_STATS(SCTP_MIB_DELAY_SACK_EXPIREDS);
+       SCTP_INC_STATS(net, SCTP_MIB_DELAY_SACK_EXPIREDS);
        sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_FORCE());
        return SCTP_DISPOSITION_CONSUME;
 }
@@ -5414,7 +5508,8 @@ sctp_disposition_t sctp_sf_do_6_2_sack(const struct sctp_endpoint *ep,
  * (timers, events)
  *
  */
-sctp_disposition_t sctp_sf_t1_init_timer_expire(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_t1_init_timer_expire(struct net *net,
+                                          const struct sctp_endpoint *ep,
                                           const struct sctp_association *asoc,
                                           const sctp_subtype_t type,
                                           void *arg,
@@ -5425,7 +5520,7 @@ sctp_disposition_t sctp_sf_t1_init_timer_expire(const struct sctp_endpoint *ep,
        int attempts = asoc->init_err_counter + 1;
 
        SCTP_DEBUG_PRINTK("Timer T1 expired (INIT).\n");
-       SCTP_INC_STATS(SCTP_MIB_T1_INIT_EXPIREDS);
+       SCTP_INC_STATS(net, SCTP_MIB_T1_INIT_EXPIREDS);
 
        if (attempts <= asoc->max_init_attempts) {
                bp = (struct sctp_bind_addr *) &asoc->base.bind_addr;
@@ -5475,7 +5570,8 @@ sctp_disposition_t sctp_sf_t1_init_timer_expire(const struct sctp_endpoint *ep,
  * (timers, events)
  *
  */
-sctp_disposition_t sctp_sf_t1_cookie_timer_expire(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_t1_cookie_timer_expire(struct net *net,
+                                          const struct sctp_endpoint *ep,
                                           const struct sctp_association *asoc,
                                           const sctp_subtype_t type,
                                           void *arg,
@@ -5485,7 +5581,7 @@ sctp_disposition_t sctp_sf_t1_cookie_timer_expire(const struct sctp_endpoint *ep
        int attempts = asoc->init_err_counter + 1;
 
        SCTP_DEBUG_PRINTK("Timer T1 expired (COOKIE-ECHO).\n");
-       SCTP_INC_STATS(SCTP_MIB_T1_COOKIE_EXPIREDS);
+       SCTP_INC_STATS(net, SCTP_MIB_T1_COOKIE_EXPIREDS);
 
        if (attempts <= asoc->max_init_attempts) {
                repl = sctp_make_cookie_echo(asoc, NULL);
@@ -5523,7 +5619,8 @@ sctp_disposition_t sctp_sf_t1_cookie_timer_expire(const struct sctp_endpoint *ep
  * the T2-Shutdown timer,  giving its peer ample opportunity to transmit
  * all of its queued DATA chunks that have not yet been sent.
  */
-sctp_disposition_t sctp_sf_t2_timer_expire(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_t2_timer_expire(struct net *net,
+                                          const struct sctp_endpoint *ep,
                                           const struct sctp_association *asoc,
                                           const sctp_subtype_t type,
                                           void *arg,
@@ -5532,7 +5629,7 @@ sctp_disposition_t sctp_sf_t2_timer_expire(const struct sctp_endpoint *ep,
        struct sctp_chunk *reply = NULL;
 
        SCTP_DEBUG_PRINTK("Timer T2 expired.\n");
-       SCTP_INC_STATS(SCTP_MIB_T2_SHUTDOWN_EXPIREDS);
+       SCTP_INC_STATS(net, SCTP_MIB_T2_SHUTDOWN_EXPIREDS);
 
        ((struct sctp_association *)asoc)->shutdown_retries++;
 
@@ -5542,8 +5639,8 @@ sctp_disposition_t sctp_sf_t2_timer_expire(const struct sctp_endpoint *ep,
                /* Note:  CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
                sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
                                SCTP_PERR(SCTP_ERROR_NO_ERROR));
-               SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
-               SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
+               SCTP_INC_STATS(net, SCTP_MIB_ABORTEDS);
+               SCTP_DEC_STATS(net, SCTP_MIB_CURRESTAB);
                return SCTP_DISPOSITION_DELETE_TCB;
        }
 
@@ -5592,6 +5689,7 @@ nomem:
  * If the T4 RTO timer expires the endpoint should do B1 to B5
  */
 sctp_disposition_t sctp_sf_t4_timer_expire(
+       struct net *net,
        const struct sctp_endpoint *ep,
        const struct sctp_association *asoc,
        const sctp_subtype_t type,
@@ -5601,7 +5699,7 @@ sctp_disposition_t sctp_sf_t4_timer_expire(
        struct sctp_chunk *chunk = asoc->addip_last_asconf;
        struct sctp_transport *transport = chunk->transport;
 
-       SCTP_INC_STATS(SCTP_MIB_T4_RTO_EXPIREDS);
+       SCTP_INC_STATS(net, SCTP_MIB_T4_RTO_EXPIREDS);
 
        /* ADDIP 4.1 B1) Increment the error counters and perform path failure
         * detection on the appropriate destination address as defined in
@@ -5626,8 +5724,8 @@ sctp_disposition_t sctp_sf_t4_timer_expire(
                                SCTP_ERROR(ETIMEDOUT));
                sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
                                SCTP_PERR(SCTP_ERROR_NO_ERROR));
-               SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
-               SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
+               SCTP_INC_STATS(net, SCTP_MIB_ABORTEDS);
+               SCTP_DEC_STATS(net, SCTP_MIB_CURRESTAB);
                return SCTP_DISPOSITION_ABORT;
        }
 
@@ -5662,7 +5760,8 @@ sctp_disposition_t sctp_sf_t4_timer_expire(
  * At the expiration of this timer the sender SHOULD abort the association
  * by sending an ABORT chunk.
  */
-sctp_disposition_t sctp_sf_t5_timer_expire(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_t5_timer_expire(struct net *net,
+                                          const struct sctp_endpoint *ep,
                                           const struct sctp_association *asoc,
                                           const sctp_subtype_t type,
                                           void *arg,
@@ -5671,7 +5770,7 @@ sctp_disposition_t sctp_sf_t5_timer_expire(const struct sctp_endpoint *ep,
        struct sctp_chunk *reply = NULL;
 
        SCTP_DEBUG_PRINTK("Timer T5 expired.\n");
-       SCTP_INC_STATS(SCTP_MIB_T5_SHUTDOWN_GUARD_EXPIREDS);
+       SCTP_INC_STATS(net, SCTP_MIB_T5_SHUTDOWN_GUARD_EXPIREDS);
 
        reply = sctp_make_abort(asoc, NULL, 0);
        if (!reply)
@@ -5683,8 +5782,8 @@ sctp_disposition_t sctp_sf_t5_timer_expire(const struct sctp_endpoint *ep,
        sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
                        SCTP_PERR(SCTP_ERROR_NO_ERROR));
 
-       SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
-       SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
+       SCTP_INC_STATS(net, SCTP_MIB_ABORTEDS);
+       SCTP_DEC_STATS(net, SCTP_MIB_CURRESTAB);
 
        return SCTP_DISPOSITION_DELETE_TCB;
 nomem:
@@ -5697,6 +5796,7 @@ nomem:
  * the user.  So this routine looks same as sctp_sf_do_9_2_prm_shutdown().
  */
 sctp_disposition_t sctp_sf_autoclose_timer_expire(
+       struct net *net,
        const struct sctp_endpoint *ep,
        const struct sctp_association *asoc,
        const sctp_subtype_t type,
@@ -5705,7 +5805,7 @@ sctp_disposition_t sctp_sf_autoclose_timer_expire(
 {
        int disposition;
 
-       SCTP_INC_STATS(SCTP_MIB_AUTOCLOSE_EXPIREDS);
+       SCTP_INC_STATS(net, SCTP_MIB_AUTOCLOSE_EXPIREDS);
 
        /* From 9.2 Shutdown of an Association
         * Upon receipt of the SHUTDOWN primitive from its upper
@@ -5720,7 +5820,7 @@ sctp_disposition_t sctp_sf_autoclose_timer_expire(
 
        disposition = SCTP_DISPOSITION_CONSUME;
        if (sctp_outq_is_empty(&asoc->outqueue)) {
-               disposition = sctp_sf_do_9_2_start_shutdown(ep, asoc, type,
+               disposition = sctp_sf_do_9_2_start_shutdown(net, ep, asoc, type,
                                                            arg, commands);
        }
        return disposition;
@@ -5738,7 +5838,8 @@ sctp_disposition_t sctp_sf_autoclose_timer_expire(
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_not_impl(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_not_impl(struct net *net,
+                                   const struct sctp_endpoint *ep,
                                    const struct sctp_association *asoc,
                                    const sctp_subtype_t type,
                                    void *arg,
@@ -5755,7 +5856,8 @@ sctp_disposition_t sctp_sf_not_impl(const struct sctp_endpoint *ep,
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_bug(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_bug(struct net *net,
+                              const struct sctp_endpoint *ep,
                               const struct sctp_association *asoc,
                               const sctp_subtype_t type,
                               void *arg,
@@ -5775,7 +5877,8 @@ sctp_disposition_t sctp_sf_bug(const struct sctp_endpoint *ep,
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_timer_ignore(const struct sctp_endpoint *ep,
+sctp_disposition_t sctp_sf_timer_ignore(struct net *net,
+                                       const struct sctp_endpoint *ep,
                                        const struct sctp_association *asoc,
                                        const sctp_subtype_t type,
                                        void *arg,
@@ -5817,7 +5920,8 @@ static struct sctp_sackhdr *sctp_sm_pull_sack(struct sctp_chunk *chunk)
 /* Create an ABORT packet to be sent as a response, with the specified
  * error causes.
  */
-static struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *ep,
+static struct sctp_packet *sctp_abort_pkt_new(struct net *net,
+                                 const struct sctp_endpoint *ep,
                                  const struct sctp_association *asoc,
                                  struct sctp_chunk *chunk,
                                  const void *payload,
@@ -5826,7 +5930,7 @@ static struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *ep,
        struct sctp_packet *packet;
        struct sctp_chunk *abort;
 
-       packet = sctp_ootb_pkt_new(asoc, chunk);
+       packet = sctp_ootb_pkt_new(net, asoc, chunk);
 
        if (packet) {
                /* Make an ABORT.
@@ -5858,7 +5962,8 @@ static struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *ep,
 }
 
 /* Allocate a packet for responding in the OOTB conditions.  */
-static struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *asoc,
+static struct sctp_packet *sctp_ootb_pkt_new(struct net *net,
+                                            const struct sctp_association *asoc,
                                             const struct sctp_chunk *chunk)
 {
        struct sctp_packet *packet;
@@ -5911,7 +6016,7 @@ static struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *asoc
        }
 
        /* Make a transport for the bucket, Eliza... */
-       transport = sctp_transport_new(sctp_source(chunk), GFP_ATOMIC);
+       transport = sctp_transport_new(net, sctp_source(chunk), GFP_ATOMIC);
        if (!transport)
                goto nomem;
 
@@ -5919,7 +6024,7 @@ static struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *asoc
         * the source address.
         */
        sctp_transport_route(transport, (union sctp_addr *)&chunk->dest,
-                            sctp_sk(sctp_get_ctl_sock()));
+                            sctp_sk(net->sctp.ctl_sock));
 
        packet = sctp_packet_init(&transport->packet, transport, sport, dport);
        packet = sctp_packet_config(packet, vtag, 0);
@@ -5937,7 +6042,8 @@ void sctp_ootb_pkt_free(struct sctp_packet *packet)
 }
 
 /* Send a stale cookie error when a invalid COOKIE ECHO chunk is found  */
-static void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep,
+static void sctp_send_stale_cookie_err(struct net *net,
+                                      const struct sctp_endpoint *ep,
                                       const struct sctp_association *asoc,
                                       const struct sctp_chunk *chunk,
                                       sctp_cmd_seq_t *commands,
@@ -5946,7 +6052,7 @@ static void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep,
        struct sctp_packet *packet;
 
        if (err_chunk) {
-               packet = sctp_ootb_pkt_new(asoc, chunk);
+               packet = sctp_ootb_pkt_new(net, asoc, chunk);
                if (packet) {
                        struct sctp_signed_cookie *cookie;
 
@@ -5959,7 +6065,7 @@ static void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep,
                        sctp_packet_append_chunk(packet, err_chunk);
                        sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
                                        SCTP_PACKET(packet));
-                       SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
+                       SCTP_INC_STATS(net, SCTP_MIB_OUTCTRLCHUNKS);
                } else
                        sctp_chunk_free (err_chunk);
        }
@@ -5979,6 +6085,7 @@ static int sctp_eat_data(const struct sctp_association *asoc,
        __u32 tsn;
        struct sctp_tsnmap *map = (struct sctp_tsnmap *)&asoc->peer.tsn_map;
        struct sock *sk = asoc->base.sk;
+       struct net *net = sock_net(sk);
        u16 ssn;
        u16 sid;
        u8 ordered = 0;
@@ -6109,8 +6216,8 @@ static int sctp_eat_data(const struct sctp_association *asoc,
                                SCTP_ERROR(ECONNABORTED));
                sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
                                SCTP_PERR(SCTP_ERROR_NO_DATA));
-               SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
-               SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
+               SCTP_INC_STATS(net, SCTP_MIB_ABORTEDS);
+               SCTP_DEC_STATS(net, SCTP_MIB_CURRESTAB);
                return SCTP_IERROR_NO_DATA;
        }
 
@@ -6120,9 +6227,9 @@ static int sctp_eat_data(const struct sctp_association *asoc,
         * if we renege and the chunk arrives again.
         */
        if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
-               SCTP_INC_STATS(SCTP_MIB_INUNORDERCHUNKS);
+               SCTP_INC_STATS(net, SCTP_MIB_INUNORDERCHUNKS);
        else {
-               SCTP_INC_STATS(SCTP_MIB_INORDERCHUNKS);
+               SCTP_INC_STATS(net, SCTP_MIB_INORDERCHUNKS);
                ordered = 1;
        }
 
index 7c211a7f90f4d065eec82baa0cb751373e7eb0be..84d98d8a5a7417bd92ea919c56e0f8033073a6c4 100644 (file)
@@ -59,7 +59,8 @@ other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STATES];
 static const sctp_sm_table_entry_t
 timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM_STATES];
 
-static const sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t cid,
+static const sctp_sm_table_entry_t *sctp_chunk_event_lookup(struct net *net,
+                                                           sctp_cid_t cid,
                                                            sctp_state_t state);
 
 
@@ -82,13 +83,14 @@ static const sctp_sm_table_entry_t bug = {
        rtn;                                                            \
 })
 
-const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
+const sctp_sm_table_entry_t *sctp_sm_lookup_event(struct net *net,
+                                                 sctp_event_t event_type,
                                                  sctp_state_t state,
                                                  sctp_subtype_t event_subtype)
 {
        switch (event_type) {
        case SCTP_EVENT_T_CHUNK:
-               return sctp_chunk_event_lookup(event_subtype.chunk, state);
+               return sctp_chunk_event_lookup(net, event_subtype.chunk, state);
        case SCTP_EVENT_T_TIMEOUT:
                return DO_LOOKUP(SCTP_EVENT_TIMEOUT_MAX, timeout,
                                 timeout_event_table);
@@ -906,7 +908,8 @@ static const sctp_sm_table_entry_t timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][S
        TYPE_SCTP_EVENT_TIMEOUT_AUTOCLOSE,
 };
 
-static const sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t cid,
+static const sctp_sm_table_entry_t *sctp_chunk_event_lookup(struct net *net,
+                                                           sctp_cid_t cid,
                                                            sctp_state_t state)
 {
        if (state > SCTP_STATE_MAX)
@@ -915,12 +918,12 @@ static const sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t cid,
        if (cid <= SCTP_CID_BASE_MAX)
                return &chunk_event_table[cid][state];
 
-       if (sctp_prsctp_enable) {
+       if (net->sctp.prsctp_enable) {
                if (cid == SCTP_CID_FWD_TSN)
                        return &prsctp_chunk_event_table[0][state];
        }
 
-       if (sctp_addip_enable) {
+       if (net->sctp.addip_enable) {
                if (cid == SCTP_CID_ASCONF)
                        return &addip_chunk_event_table[0][state];
 
@@ -928,7 +931,7 @@ static const sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t cid,
                        return &addip_chunk_event_table[1][state];
        }
 
-       if (sctp_auth_enable) {
+       if (net->sctp.auth_enable) {
                if (cid == SCTP_CID_AUTH)
                        return &auth_chunk_event_table[0][state];
        }
index 5e259817a7f34cd4a183139fe9c4bf5ee2ab6689..d37d24ff197f094d5200fd9e51a692a08112157e 100644 (file)
@@ -427,6 +427,7 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
 static int sctp_send_asconf(struct sctp_association *asoc,
                            struct sctp_chunk *chunk)
 {
+       struct net      *net = sock_net(asoc->base.sk);
        int             retval = 0;
 
        /* If there is an outstanding ASCONF chunk, queue it for later
@@ -439,7 +440,7 @@ static int sctp_send_asconf(struct sctp_association *asoc,
 
        /* Hold the chunk until an ASCONF_ACK is received. */
        sctp_chunk_hold(chunk);
-       retval = sctp_primitive_ASCONF(asoc, chunk);
+       retval = sctp_primitive_ASCONF(net, asoc, chunk);
        if (retval)
                sctp_chunk_free(chunk);
        else
@@ -515,6 +516,7 @@ static int sctp_send_asconf_add_ip(struct sock              *sk,
                                   struct sockaddr      *addrs,
                                   int                  addrcnt)
 {
+       struct net *net = sock_net(sk);
        struct sctp_sock                *sp;
        struct sctp_endpoint            *ep;
        struct sctp_association         *asoc;
@@ -529,7 +531,7 @@ static int sctp_send_asconf_add_ip(struct sock              *sk,
        int                             i;
        int                             retval = 0;
 
-       if (!sctp_addip_enable)
+       if (!net->sctp.addip_enable)
                return retval;
 
        sp = sctp_sk(sk);
@@ -717,6 +719,7 @@ static int sctp_send_asconf_del_ip(struct sock              *sk,
                                   struct sockaddr      *addrs,
                                   int                  addrcnt)
 {
+       struct net *net = sock_net(sk);
        struct sctp_sock        *sp;
        struct sctp_endpoint    *ep;
        struct sctp_association *asoc;
@@ -732,7 +735,7 @@ static int sctp_send_asconf_del_ip(struct sock              *sk,
        int                     stored = 0;
 
        chunk = NULL;
-       if (!sctp_addip_enable)
+       if (!net->sctp.addip_enable)
                return retval;
 
        sp = sctp_sk(sk);
@@ -1050,6 +1053,7 @@ static int __sctp_connect(struct sock* sk,
                          int addrs_size,
                          sctp_assoc_t *assoc_id)
 {
+       struct net *net = sock_net(sk);
        struct sctp_sock *sp;
        struct sctp_endpoint *ep;
        struct sctp_association *asoc = NULL;
@@ -1200,7 +1204,7 @@ static int __sctp_connect(struct sock* sk,
                        goto out_free;
        }
 
-       err = sctp_primitive_ASSOCIATE(asoc, NULL);
+       err = sctp_primitive_ASSOCIATE(net, asoc, NULL);
        if (err < 0) {
                goto out_free;
        }
@@ -1458,6 +1462,7 @@ SCTP_STATIC int sctp_getsockopt_connectx3(struct sock* sk, int len,
  */
 SCTP_STATIC void sctp_close(struct sock *sk, long timeout)
 {
+       struct net *net = sock_net(sk);
        struct sctp_endpoint *ep;
        struct sctp_association *asoc;
        struct list_head *pos, *temp;
@@ -1499,9 +1504,9 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout)
 
                        chunk = sctp_make_abort_user(asoc, NULL, 0);
                        if (chunk)
-                               sctp_primitive_ABORT(asoc, chunk);
+                               sctp_primitive_ABORT(net, asoc, chunk);
                } else
-                       sctp_primitive_SHUTDOWN(asoc, NULL);
+                       sctp_primitive_SHUTDOWN(net, asoc, NULL);
        }
 
        /* On a TCP-style socket, block for at most linger_time if set. */
@@ -1569,6 +1574,7 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *, sctp_cmsgs_t *);
 SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
                             struct msghdr *msg, size_t msg_len)
 {
+       struct net *net = sock_net(sk);
        struct sctp_sock *sp;
        struct sctp_endpoint *ep;
        struct sctp_association *new_asoc=NULL, *asoc=NULL;
@@ -1714,7 +1720,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
                if (sinfo_flags & SCTP_EOF) {
                        SCTP_DEBUG_PRINTK("Shutting down association: %p\n",
                                          asoc);
-                       sctp_primitive_SHUTDOWN(asoc, NULL);
+                       sctp_primitive_SHUTDOWN(net, asoc, NULL);
                        err = 0;
                        goto out_unlock;
                }
@@ -1727,7 +1733,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
                        }
 
                        SCTP_DEBUG_PRINTK("Aborting association: %p\n", asoc);
-                       sctp_primitive_ABORT(asoc, chunk);
+                       sctp_primitive_ABORT(net, asoc, chunk);
                        err = 0;
                        goto out_unlock;
                }
@@ -1900,7 +1906,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
 
        /* Auto-connect, if we aren't connected already. */
        if (sctp_state(asoc, CLOSED)) {
-               err = sctp_primitive_ASSOCIATE(asoc, NULL);
+               err = sctp_primitive_ASSOCIATE(net, asoc, NULL);
                if (err < 0)
                        goto out_free;
                SCTP_DEBUG_PRINTK("We associated primitively.\n");
@@ -1928,7 +1934,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
         * works that way today.  Keep it that way or this
         * breaks.
         */
-       err = sctp_primitive_SEND(asoc, datamsg);
+       err = sctp_primitive_SEND(net, asoc, datamsg);
        /* Did the lower layer accept the chunk? */
        if (err)
                sctp_datamsg_free(datamsg);
@@ -2320,7 +2326,9 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params,
        int error;
 
        if (params->spp_flags & SPP_HB_DEMAND && trans) {
-               error = sctp_primitive_REQUESTHEARTBEAT (trans->asoc, trans);
+               struct net *net = sock_net(trans->asoc->base.sk);
+
+               error = sctp_primitive_REQUESTHEARTBEAT(net, trans->asoc, trans);
                if (error)
                        return error;
        }
@@ -3033,6 +3041,7 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, unsigned
 static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optval,
                                             unsigned int optlen)
 {
+       struct net *net = sock_net(sk);
        struct sctp_sock        *sp;
        struct sctp_association *asoc = NULL;
        struct sctp_setpeerprim prim;
@@ -3042,7 +3051,7 @@ static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char __user *optva
 
        sp = sctp_sk(sk);
 
-       if (!sctp_addip_enable)
+       if (!net->sctp.addip_enable)
                return -EPERM;
 
        if (optlen != sizeof(struct sctp_setpeerprim))
@@ -3279,9 +3288,10 @@ static int sctp_setsockopt_auth_chunk(struct sock *sk,
                                      char __user *optval,
                                      unsigned int optlen)
 {
+       struct net *net = sock_net(sk);
        struct sctp_authchunk val;
 
-       if (!sctp_auth_enable)
+       if (!net->sctp.auth_enable)
                return -EACCES;
 
        if (optlen != sizeof(struct sctp_authchunk))
@@ -3311,11 +3321,12 @@ static int sctp_setsockopt_hmac_ident(struct sock *sk,
                                      char __user *optval,
                                      unsigned int optlen)
 {
+       struct net *net = sock_net(sk);
        struct sctp_hmacalgo *hmacs;
        u32 idents;
        int err;
 
-       if (!sctp_auth_enable)
+       if (!net->sctp.auth_enable)
                return -EACCES;
 
        if (optlen < sizeof(struct sctp_hmacalgo))
@@ -3348,11 +3359,12 @@ static int sctp_setsockopt_auth_key(struct sock *sk,
                                    char __user *optval,
                                    unsigned int optlen)
 {
+       struct net *net = sock_net(sk);
        struct sctp_authkey *authkey;
        struct sctp_association *asoc;
        int ret;
 
-       if (!sctp_auth_enable)
+       if (!net->sctp.auth_enable)
                return -EACCES;
 
        if (optlen <= sizeof(struct sctp_authkey))
@@ -3389,10 +3401,11 @@ static int sctp_setsockopt_active_key(struct sock *sk,
                                      char __user *optval,
                                      unsigned int optlen)
 {
+       struct net *net = sock_net(sk);
        struct sctp_authkeyid val;
        struct sctp_association *asoc;
 
-       if (!sctp_auth_enable)
+       if (!net->sctp.auth_enable)
                return -EACCES;
 
        if (optlen != sizeof(struct sctp_authkeyid))
@@ -3417,10 +3430,11 @@ static int sctp_setsockopt_del_key(struct sock *sk,
                                   char __user *optval,
                                   unsigned int optlen)
 {
+       struct net *net = sock_net(sk);
        struct sctp_authkeyid val;
        struct sctp_association *asoc;
 
-       if (!sctp_auth_enable)
+       if (!net->sctp.auth_enable)
                return -EACCES;
 
        if (optlen != sizeof(struct sctp_authkeyid))
@@ -3471,7 +3485,7 @@ static int sctp_setsockopt_auto_asconf(struct sock *sk, char __user *optval,
                sp->do_auto_asconf = 0;
        } else if (val && !sp->do_auto_asconf) {
                list_add_tail(&sp->auto_asconf_list,
-                   &sctp_auto_asconf_splist);
+                   &sock_net(sk)->sctp.auto_asconf_splist);
                sp->do_auto_asconf = 1;
        }
        return 0;
@@ -3843,6 +3857,7 @@ out:
  */
 SCTP_STATIC int sctp_init_sock(struct sock *sk)
 {
+       struct net *net = sock_net(sk);
        struct sctp_endpoint *ep;
        struct sctp_sock *sp;
 
@@ -3872,7 +3887,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
        sp->default_timetolive = 0;
 
        sp->default_rcv_context = 0;
-       sp->max_burst = sctp_max_burst;
+       sp->max_burst = net->sctp.max_burst;
 
        /* Initialize default setup parameters. These parameters
         * can be modified with the SCTP_INITMSG socket option or
@@ -3880,24 +3895,24 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
         */
        sp->initmsg.sinit_num_ostreams   = sctp_max_outstreams;
        sp->initmsg.sinit_max_instreams  = sctp_max_instreams;
-       sp->initmsg.sinit_max_attempts   = sctp_max_retrans_init;
-       sp->initmsg.sinit_max_init_timeo = sctp_rto_max;
+       sp->initmsg.sinit_max_attempts   = net->sctp.max_retrans_init;
+       sp->initmsg.sinit_max_init_timeo = net->sctp.rto_max;
 
        /* Initialize default RTO related parameters.  These parameters can
         * be modified for with the SCTP_RTOINFO socket option.
         */
-       sp->rtoinfo.srto_initial = sctp_rto_initial;
-       sp->rtoinfo.srto_max     = sctp_rto_max;
-       sp->rtoinfo.srto_min     = sctp_rto_min;
+       sp->rtoinfo.srto_initial = net->sctp.rto_initial;
+       sp->rtoinfo.srto_max     = net->sctp.rto_max;
+       sp->rtoinfo.srto_min     = net->sctp.rto_min;
 
        /* Initialize default association related parameters. These parameters
         * can be modified with the SCTP_ASSOCINFO socket option.
         */
-       sp->assocparams.sasoc_asocmaxrxt = sctp_max_retrans_association;
+       sp->assocparams.sasoc_asocmaxrxt = net->sctp.max_retrans_association;
        sp->assocparams.sasoc_number_peer_destinations = 0;
        sp->assocparams.sasoc_peer_rwnd = 0;
        sp->assocparams.sasoc_local_rwnd = 0;
-       sp->assocparams.sasoc_cookie_life = sctp_valid_cookie_life;
+       sp->assocparams.sasoc_cookie_life = net->sctp.valid_cookie_life;
 
        /* Initialize default event subscriptions. By default, all the
         * options are off.
@@ -3907,10 +3922,10 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
        /* Default Peer Address Parameters.  These defaults can
         * be modified via SCTP_PEER_ADDR_PARAMS
         */
-       sp->hbinterval  = sctp_hb_interval;
-       sp->pathmaxrxt  = sctp_max_retrans_path;
+       sp->hbinterval  = net->sctp.hb_interval;
+       sp->pathmaxrxt  = net->sctp.max_retrans_path;
        sp->pathmtu     = 0; // allow default discovery
-       sp->sackdelay   = sctp_sack_timeout;
+       sp->sackdelay   = net->sctp.sack_timeout;
        sp->sackfreq    = 2;
        sp->param_flags = SPP_HB_ENABLE |
                          SPP_PMTUD_ENABLE |
@@ -3961,10 +3976,10 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
 
        local_bh_disable();
        percpu_counter_inc(&sctp_sockets_allocated);
-       sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
-       if (sctp_default_auto_asconf) {
+       sock_prot_inuse_add(net, sk->sk_prot, 1);
+       if (net->sctp.default_auto_asconf) {
                list_add_tail(&sp->auto_asconf_list,
-                   &sctp_auto_asconf_splist);
+                   &net->sctp.auto_asconf_splist);
                sp->do_auto_asconf = 1;
        } else
                sp->do_auto_asconf = 0;
@@ -4011,6 +4026,7 @@ SCTP_STATIC void sctp_destroy_sock(struct sock *sk)
  */
 SCTP_STATIC void sctp_shutdown(struct sock *sk, int how)
 {
+       struct net *net = sock_net(sk);
        struct sctp_endpoint *ep;
        struct sctp_association *asoc;
 
@@ -4022,7 +4038,7 @@ SCTP_STATIC void sctp_shutdown(struct sock *sk, int how)
                if (!list_empty(&ep->asocs)) {
                        asoc = list_entry(ep->asocs.next,
                                          struct sctp_association, asocs);
-                       sctp_primitive_SHUTDOWN(asoc, NULL);
+                       sctp_primitive_SHUTDOWN(net, asoc, NULL);
                }
        }
 }
@@ -4653,9 +4669,10 @@ static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to,
        union sctp_addr temp;
        int cnt = 0;
        int addrlen;
+       struct net *net = sock_net(sk);
 
        rcu_read_lock();
-       list_for_each_entry_rcu(addr, &sctp_local_addr_list, list) {
+       list_for_each_entry_rcu(addr, &net->sctp.local_addr_list, list) {
                if (!addr->valid)
                        continue;
 
@@ -5299,12 +5316,13 @@ static int sctp_getsockopt_maxburst(struct sock *sk, int len,
 static int sctp_getsockopt_hmac_ident(struct sock *sk, int len,
                                    char __user *optval, int __user *optlen)
 {
+       struct net *net = sock_net(sk);
        struct sctp_hmacalgo  __user *p = (void __user *)optval;
        struct sctp_hmac_algo_param *hmacs;
        __u16 data_len = 0;
        u32 num_idents;
 
-       if (!sctp_auth_enable)
+       if (!net->sctp.auth_enable)
                return -EACCES;
 
        hmacs = sctp_sk(sk)->ep->auth_hmacs_list;
@@ -5328,10 +5346,11 @@ static int sctp_getsockopt_hmac_ident(struct sock *sk, int len,
 static int sctp_getsockopt_active_key(struct sock *sk, int len,
                                    char __user *optval, int __user *optlen)
 {
+       struct net *net = sock_net(sk);
        struct sctp_authkeyid val;
        struct sctp_association *asoc;
 
-       if (!sctp_auth_enable)
+       if (!net->sctp.auth_enable)
                return -EACCES;
 
        if (len < sizeof(struct sctp_authkeyid))
@@ -5360,6 +5379,7 @@ static int sctp_getsockopt_active_key(struct sock *sk, int len,
 static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len,
                                    char __user *optval, int __user *optlen)
 {
+       struct net *net = sock_net(sk);
        struct sctp_authchunks __user *p = (void __user *)optval;
        struct sctp_authchunks val;
        struct sctp_association *asoc;
@@ -5367,7 +5387,7 @@ static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len,
        u32    num_chunks = 0;
        char __user *to;
 
-       if (!sctp_auth_enable)
+       if (!net->sctp.auth_enable)
                return -EACCES;
 
        if (len < sizeof(struct sctp_authchunks))
@@ -5403,6 +5423,7 @@ num:
 static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len,
                                    char __user *optval, int __user *optlen)
 {
+       struct net *net = sock_net(sk);
        struct sctp_authchunks __user *p = (void __user *)optval;
        struct sctp_authchunks val;
        struct sctp_association *asoc;
@@ -5410,7 +5431,7 @@ static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len,
        u32    num_chunks = 0;
        char __user *to;
 
-       if (!sctp_auth_enable)
+       if (!net->sctp.auth_enable)
                return -EACCES;
 
        if (len < sizeof(struct sctp_authchunks))
@@ -5769,7 +5790,7 @@ static void sctp_unhash(struct sock *sk)
  * a fastreuse flag (FIXME: NPI ipg).
  */
 static struct sctp_bind_bucket *sctp_bucket_create(
-       struct sctp_bind_hashbucket *head, unsigned short snum);
+       struct sctp_bind_hashbucket *head, struct net *, unsigned short snum);
 
 static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
 {
@@ -5799,11 +5820,12 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
                                rover = low;
                        if (inet_is_reserved_local_port(rover))
                                continue;
-                       index = sctp_phashfn(rover);
+                       index = sctp_phashfn(sock_net(sk), rover);
                        head = &sctp_port_hashtable[index];
                        sctp_spin_lock(&head->lock);
                        sctp_for_each_hentry(pp, node, &head->chain)
-                               if (pp->port == rover)
+                               if ((pp->port == rover) &&
+                                   net_eq(sock_net(sk), pp->net))
                                        goto next;
                        break;
                next:
@@ -5827,10 +5849,10 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
                 * to the port number (snum) - we detect that with the
                 * port iterator, pp being NULL.
                 */
-               head = &sctp_port_hashtable[sctp_phashfn(snum)];
+               head = &sctp_port_hashtable[sctp_phashfn(sock_net(sk), snum)];
                sctp_spin_lock(&head->lock);
                sctp_for_each_hentry(pp, node, &head->chain) {
-                       if (pp->port == snum)
+                       if ((pp->port == snum) && net_eq(pp->net, sock_net(sk)))
                                goto pp_found;
                }
        }
@@ -5881,7 +5903,7 @@ pp_found:
 pp_not_found:
        /* If there was a hash table miss, create a new port.  */
        ret = 1;
-       if (!pp && !(pp = sctp_bucket_create(head, snum)))
+       if (!pp && !(pp = sctp_bucket_create(head, sock_net(sk), snum)))
                goto fail_unlock;
 
        /* In either case (hit or miss), make sure fastreuse is 1 only
@@ -6113,7 +6135,7 @@ unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait)
  ********************************************************************/
 
 static struct sctp_bind_bucket *sctp_bucket_create(
-       struct sctp_bind_hashbucket *head, unsigned short snum)
+       struct sctp_bind_hashbucket *head, struct net *net, unsigned short snum)
 {
        struct sctp_bind_bucket *pp;
 
@@ -6123,6 +6145,7 @@ static struct sctp_bind_bucket *sctp_bucket_create(
                pp->port = snum;
                pp->fastreuse = 0;
                INIT_HLIST_HEAD(&pp->owner);
+               pp->net = net;
                hlist_add_head(&pp->node, &head->chain);
        }
        return pp;
@@ -6142,7 +6165,8 @@ static void sctp_bucket_destroy(struct sctp_bind_bucket *pp)
 static inline void __sctp_put_port(struct sock *sk)
 {
        struct sctp_bind_hashbucket *head =
-               &sctp_port_hashtable[sctp_phashfn(inet_sk(sk)->inet_num)];
+               &sctp_port_hashtable[sctp_phashfn(sock_net(sk),
+                                                 inet_sk(sk)->inet_num)];
        struct sctp_bind_bucket *pp;
 
        sctp_spin_lock(&head->lock);
@@ -6809,7 +6833,8 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
        newsp->hmac = NULL;
 
        /* Hook this new socket in to the bind_hash list. */
-       head = &sctp_port_hashtable[sctp_phashfn(inet_sk(oldsk)->inet_num)];
+       head = &sctp_port_hashtable[sctp_phashfn(sock_net(oldsk),
+                                                inet_sk(oldsk)->inet_num)];
        sctp_local_bh_disable();
        sctp_spin_lock(&head->lock);
        pp = sctp_sk(oldsk)->bind_hash;
index 2b2bfe933ff14413aa4970391eb25d038ff3d90a..70e3ba5cb50b319319e60c7bfa6fae69bc5c1fed 100644 (file)
@@ -63,9 +63,35 @@ extern int sysctl_sctp_rmem[3];
 extern int sysctl_sctp_wmem[3];
 
 static ctl_table sctp_table[] = {
+       {
+               .procname       = "sctp_mem",
+               .data           = &sysctl_sctp_mem,
+               .maxlen         = sizeof(sysctl_sctp_mem),
+               .mode           = 0644,
+               .proc_handler   = proc_doulongvec_minmax
+       },
+       {
+               .procname       = "sctp_rmem",
+               .data           = &sysctl_sctp_rmem,
+               .maxlen         = sizeof(sysctl_sctp_rmem),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec,
+       },
+       {
+               .procname       = "sctp_wmem",
+               .data           = &sysctl_sctp_wmem,
+               .maxlen         = sizeof(sysctl_sctp_wmem),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec,
+       },
+
+       { /* sentinel */ }
+};
+
+static ctl_table sctp_net_table[] = {
        {
                .procname       = "rto_initial",
-               .data           = &sctp_rto_initial,
+               .data           = &init_net.sctp.rto_initial,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
@@ -74,7 +100,7 @@ static ctl_table sctp_table[] = {
        },
        {
                .procname       = "rto_min",
-               .data           = &sctp_rto_min,
+               .data           = &init_net.sctp.rto_min,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
@@ -83,7 +109,7 @@ static ctl_table sctp_table[] = {
        },
        {
                .procname       = "rto_max",
-               .data           = &sctp_rto_max,
+               .data           = &init_net.sctp.rto_max,
                .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
@@ -91,17 +117,22 @@ static ctl_table sctp_table[] = {
                .extra2         = &timer_max
        },
        {
-               .procname       = "valid_cookie_life",
-               .data           = &sctp_valid_cookie_life,
-               .maxlen         = sizeof(unsigned int),
-               .mode           = 0644,
-               .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
-               .extra2         = &timer_max
+               .procname       = "rto_alpha_exp_divisor",
+               .data           = &init_net.sctp.rto_alpha,
+               .maxlen         = sizeof(int),
+               .mode           = 0444,
+               .proc_handler   = proc_dointvec,
+       },
+       {
+               .procname       = "rto_beta_exp_divisor",
+               .data           = &init_net.sctp.rto_beta,
+               .maxlen         = sizeof(int),
+               .mode           = 0444,
+               .proc_handler   = proc_dointvec,
        },
        {
                .procname       = "max_burst",
-               .data           = &sctp_max_burst,
+               .data           = &init_net.sctp.max_burst,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
@@ -109,31 +140,42 @@ static ctl_table sctp_table[] = {
                .extra2         = &int_max
        },
        {
-               .procname       = "association_max_retrans",
-               .data           = &sctp_max_retrans_association,
+               .procname       = "cookie_preserve_enable",
+               .data           = &init_net.sctp.cookie_preserve_enable,
                .maxlen         = sizeof(int),
                .mode           = 0644,
+               .proc_handler   = proc_dointvec,
+       },
+       {
+               .procname       = "valid_cookie_life",
+               .data           = &init_net.sctp.valid_cookie_life,
+               .maxlen         = sizeof(unsigned int),
+               .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
-               .extra2         = &int_max
+               .extra1         = &one,
+               .extra2         = &timer_max
        },
        {
-               .procname       = "sndbuf_policy",
-               .data           = &sctp_sndbuf_policy,
+               .procname       = "sack_timeout",
+               .data           = &init_net.sctp.sack_timeout,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &sack_timer_min,
+               .extra2         = &sack_timer_max,
        },
        {
-               .procname       = "rcvbuf_policy",
-               .data           = &sctp_rcvbuf_policy,
-               .maxlen         = sizeof(int),
+               .procname       = "hb_interval",
+               .data           = &init_net.sctp.hb_interval,
+               .maxlen         = sizeof(unsigned int),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &one,
+               .extra2         = &timer_max
        },
        {
-               .procname       = "path_max_retrans",
-               .data           = &sctp_max_retrans_path,
+               .procname       = "association_max_retrans",
+               .data           = &init_net.sctp.max_retrans_association,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
@@ -141,17 +183,17 @@ static ctl_table sctp_table[] = {
                .extra2         = &int_max
        },
        {
-               .procname       = "pf_retrans",
-               .data           = &sctp_pf_retrans,
+               .procname       = "path_max_retrans",
+               .data           = &init_net.sctp.max_retrans_path,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &zero,
+               .extra1         = &one,
                .extra2         = &int_max
        },
        {
                .procname       = "max_init_retransmits",
-               .data           = &sctp_max_retrans_init,
+               .data           = &init_net.sctp.max_retrans_init,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
@@ -159,103 +201,66 @@ static ctl_table sctp_table[] = {
                .extra2         = &int_max
        },
        {
-               .procname       = "hb_interval",
-               .data           = &sctp_hb_interval,
-               .maxlen         = sizeof(unsigned int),
+               .procname       = "pf_retrans",
+               .data           = &init_net.sctp.pf_retrans,
+               .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &one,
-               .extra2         = &timer_max
+               .extra1         = &zero,
+               .extra2         = &int_max
        },
        {
-               .procname       = "cookie_preserve_enable",
-               .data           = &sctp_cookie_preserve_enable,
+               .procname       = "sndbuf_policy",
+               .data           = &init_net.sctp.sndbuf_policy,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
        {
-               .procname       = "rto_alpha_exp_divisor",
-               .data           = &sctp_rto_alpha,
-               .maxlen         = sizeof(int),
-               .mode           = 0444,
-               .proc_handler   = proc_dointvec,
-       },
-       {
-               .procname       = "rto_beta_exp_divisor",
-               .data           = &sctp_rto_beta,
-               .maxlen         = sizeof(int),
-               .mode           = 0444,
-               .proc_handler   = proc_dointvec,
-       },
-       {
-               .procname       = "addip_enable",
-               .data           = &sctp_addip_enable,
+               .procname       = "rcvbuf_policy",
+               .data           = &init_net.sctp.rcvbuf_policy,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
        {
                .procname       = "default_auto_asconf",
-               .data           = &sctp_default_auto_asconf,
+               .data           = &init_net.sctp.default_auto_asconf,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
        {
-               .procname       = "prsctp_enable",
-               .data           = &sctp_prsctp_enable,
+               .procname       = "addip_enable",
+               .data           = &init_net.sctp.addip_enable,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
        {
-               .procname       = "sack_timeout",
-               .data           = &sctp_sack_timeout,
+               .procname       = "addip_noauth_enable",
+               .data           = &init_net.sctp.addip_noauth,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec_minmax,
-               .extra1         = &sack_timer_min,
-               .extra2         = &sack_timer_max,
-       },
-       {
-               .procname       = "sctp_mem",
-               .data           = &sysctl_sctp_mem,
-               .maxlen         = sizeof(sysctl_sctp_mem),
-               .mode           = 0644,
-               .proc_handler   = proc_doulongvec_minmax
-       },
-       {
-               .procname       = "sctp_rmem",
-               .data           = &sysctl_sctp_rmem,
-               .maxlen         = sizeof(sysctl_sctp_rmem),
-               .mode           = 0644,
-               .proc_handler   = proc_dointvec,
-       },
-       {
-               .procname       = "sctp_wmem",
-               .data           = &sysctl_sctp_wmem,
-               .maxlen         = sizeof(sysctl_sctp_wmem),
-               .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
        {
-               .procname       = "auth_enable",
-               .data           = &sctp_auth_enable,
+               .procname       = "prsctp_enable",
+               .data           = &init_net.sctp.prsctp_enable,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
        {
-               .procname       = "addip_noauth_enable",
-               .data           = &sctp_addip_noauth,
+               .procname       = "auth_enable",
+               .data           = &init_net.sctp.auth_enable,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
        {
                .procname       = "addr_scope_policy",
-               .data           = &sctp_scope_policy,
+               .data           = &init_net.sctp.scope_policy,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_dointvec_minmax,
@@ -264,7 +269,7 @@ static ctl_table sctp_table[] = {
        },
        {
                .procname       = "rwnd_update_shift",
-               .data           = &sctp_rwnd_upd_shift,
+               .data           = &init_net.sctp.rwnd_upd_shift,
                .maxlen         = sizeof(int),
                .mode           = 0644,
                .proc_handler   = &proc_dointvec_minmax,
@@ -273,7 +278,7 @@ static ctl_table sctp_table[] = {
        },
        {
                .procname       = "max_autoclose",
-               .data           = &sctp_max_autoclose,
+               .data           = &init_net.sctp.max_autoclose,
                .maxlen         = sizeof(unsigned long),
                .mode           = 0644,
                .proc_handler   = &proc_doulongvec_minmax,
@@ -284,6 +289,27 @@ static ctl_table sctp_table[] = {
        { /* sentinel */ }
 };
 
+int sctp_sysctl_net_register(struct net *net)
+{
+       struct ctl_table *table;
+       int i;
+
+       table = kmemdup(sctp_net_table, sizeof(sctp_net_table), GFP_KERNEL);
+       if (!table)
+               return -ENOMEM;
+
+       for (i = 0; table[i].data; i++)
+               table[i].data += (char *)(&net->sctp) - (char *)&init_net.sctp;
+
+       net->sctp.sysctl_header = register_net_sysctl(net, "net/sctp", table);
+       return 0;
+}
+
+void sctp_sysctl_net_unregister(struct net *net)
+{
+       unregister_net_sysctl_table(net->sctp.sysctl_header);
+}
+
 static struct ctl_table_header * sctp_sysctl_header;
 
 /* Sysctl registration.  */
index c97472b248a2b257972cd9e4a353e89874ad87aa..953c21e4af977a752362187976e84b578bdb085c 100644 (file)
@@ -59,7 +59,8 @@
 /* 1st Level Abstractions.  */
 
 /* Initialize a new transport from provided memory.  */
-static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
+static struct sctp_transport *sctp_transport_init(struct net *net,
+                                                 struct sctp_transport *peer,
                                                  const union sctp_addr *addr,
                                                  gfp_t gfp)
 {
@@ -76,7 +77,7 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
         * given destination transport address, set RTO to the protocol
         * parameter 'RTO.Initial'.
         */
-       peer->rto = msecs_to_jiffies(sctp_rto_initial);
+       peer->rto = msecs_to_jiffies(net->sctp.rto_initial);
 
        peer->last_time_heard = jiffies;
        peer->last_time_ecne_reduced = jiffies;
@@ -86,8 +87,8 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
                            SPP_SACKDELAY_ENABLE;
 
        /* Initialize the default path max_retrans.  */
-       peer->pathmaxrxt  = sctp_max_retrans_path;
-       peer->pf_retrans  = sctp_pf_retrans;
+       peer->pathmaxrxt  = net->sctp.max_retrans_path;
+       peer->pf_retrans  = net->sctp.pf_retrans;
 
        INIT_LIST_HEAD(&peer->transmitted);
        INIT_LIST_HEAD(&peer->send_ready);
@@ -109,7 +110,8 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
 }
 
 /* Allocate and initialize a new transport.  */
-struct sctp_transport *sctp_transport_new(const union sctp_addr *addr,
+struct sctp_transport *sctp_transport_new(struct net *net,
+                                         const union sctp_addr *addr,
                                          gfp_t gfp)
 {
        struct sctp_transport *transport;
@@ -118,7 +120,7 @@ struct sctp_transport *sctp_transport_new(const union sctp_addr *addr,
        if (!transport)
                goto fail;
 
-       if (!sctp_transport_init(transport, addr, gfp))
+       if (!sctp_transport_init(net, transport, addr, gfp))
                goto fail_init;
 
        transport->malloced = 1;
@@ -316,6 +318,7 @@ void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt)
        SCTP_ASSERT(tp->rto_pending, "rto_pending not set", return);
 
        if (tp->rttvar || tp->srtt) {
+               struct net *net = sock_net(tp->asoc->base.sk);
                /* 6.3.1 C3) When a new RTT measurement R' is made, set
                 * RTTVAR <- (1 - RTO.Beta) * RTTVAR + RTO.Beta * |SRTT - R'|
                 * SRTT <- (1 - RTO.Alpha) * SRTT + RTO.Alpha * R'
@@ -327,10 +330,10 @@ void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt)
                 * For example, assuming the default value of RTO.Alpha of
                 * 1/8, rto_alpha would be expressed as 3.
                 */
-               tp->rttvar = tp->rttvar - (tp->rttvar >> sctp_rto_beta)
-                       + ((abs(tp->srtt - rtt)) >> sctp_rto_beta);
-               tp->srtt = tp->srtt - (tp->srtt >> sctp_rto_alpha)
-                       + (rtt >> sctp_rto_alpha);
+               tp->rttvar = tp->rttvar - (tp->rttvar >> net->sctp.rto_beta)
+                       + ((abs(tp->srtt - rtt)) >> net->sctp.rto_beta);
+               tp->srtt = tp->srtt - (tp->srtt >> net->sctp.rto_alpha)
+                       + (rtt >> net->sctp.rto_alpha);
        } else {
                /* 6.3.1 C2) When the first RTT measurement R is made, set
                 * SRTT <- R, RTTVAR <- R/2.
index f5a6a4f4faf721af4874538093cb003f4efc202c..360d8697b95c33408d6a4913b9b1d497d27e5ee7 100644 (file)
@@ -326,7 +326,9 @@ static void sctp_ulpq_store_reasm(struct sctp_ulpq *ulpq,
  * payload was fragmented on the way and ip had to reassemble them.
  * We add the rest of skb's to the first skb's fraglist.
  */
-static struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff_head *queue, struct sk_buff *f_frag, struct sk_buff *l_frag)
+static struct sctp_ulpevent *sctp_make_reassembled_event(struct net *net,
+       struct sk_buff_head *queue, struct sk_buff *f_frag,
+       struct sk_buff *l_frag)
 {
        struct sk_buff *pos;
        struct sk_buff *new = NULL;
@@ -394,7 +396,7 @@ static struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff_head *qu
        }
 
        event = sctp_skb2event(f_frag);
-       SCTP_INC_STATS(SCTP_MIB_REASMUSRMSGS);
+       SCTP_INC_STATS(net, SCTP_MIB_REASMUSRMSGS);
 
        return event;
 }
@@ -493,7 +495,8 @@ static struct sctp_ulpevent *sctp_ulpq_retrieve_reassembled(struct sctp_ulpq *ul
                cevent = sctp_skb2event(pd_first);
                pd_point = sctp_sk(asoc->base.sk)->pd_point;
                if (pd_point && pd_point <= pd_len) {
-                       retval = sctp_make_reassembled_event(&ulpq->reasm,
+                       retval = sctp_make_reassembled_event(sock_net(asoc->base.sk),
+                                                            &ulpq->reasm,
                                                             pd_first,
                                                             pd_last);
                        if (retval)
@@ -503,7 +506,8 @@ static struct sctp_ulpevent *sctp_ulpq_retrieve_reassembled(struct sctp_ulpq *ul
 done:
        return retval;
 found:
-       retval = sctp_make_reassembled_event(&ulpq->reasm, first_frag, pos);
+       retval = sctp_make_reassembled_event(sock_net(ulpq->asoc->base.sk),
+                                            &ulpq->reasm, first_frag, pos);
        if (retval)
                retval->msg_flags |= MSG_EOR;
        goto done;
@@ -563,7 +567,8 @@ static struct sctp_ulpevent *sctp_ulpq_retrieve_partial(struct sctp_ulpq *ulpq)
         * further.
         */
 done:
-       retval = sctp_make_reassembled_event(&ulpq->reasm, first_frag, last_frag);
+       retval = sctp_make_reassembled_event(sock_net(ulpq->asoc->base.sk),
+                                       &ulpq->reasm, first_frag, last_frag);
        if (retval && is_last)
                retval->msg_flags |= MSG_EOR;
 
@@ -655,7 +660,8 @@ static struct sctp_ulpevent *sctp_ulpq_retrieve_first(struct sctp_ulpq *ulpq)
         * further.
         */
 done:
-       retval = sctp_make_reassembled_event(&ulpq->reasm, first_frag, last_frag);
+       retval = sctp_make_reassembled_event(sock_net(ulpq->asoc->base.sk),
+                                       &ulpq->reasm, first_frag, last_frag);
        return retval;
 }
 
index dfe5b66c97e0bc836efed43ad080dec620301306..a5471f804d994ece8c31df6be0e04d5076b6dfd0 100644 (file)
@@ -2657,6 +2657,7 @@ static int dev_ifconf(struct net *net, struct compat_ifconf __user *uifc32)
        if (copy_from_user(&ifc32, uifc32, sizeof(struct compat_ifconf)))
                return -EFAULT;
 
+       memset(&ifc, 0, sizeof(ifc));
        if (ifc32.ifcbuf == 0) {
                ifc32.ifc_len = 0;
                ifc.ifc_len = 0;
index 31b40cc4a9c3c59bac7986e3c5c8725153381179..dcd64d5b07aadfba26a799506452a9b04fe8e7d3 100644 (file)
@@ -952,6 +952,11 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
                 */
                synchronize_rcu();
                INIT_LIST_HEAD(&wdev->list);
+               /*
+                * Ensure that all events have been processed and
+                * freed.
+                */
+               cfg80211_process_wdev_events(wdev);
                break;
        case NETDEV_PRE_UP:
                if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype)))
index 5206c6844fd735b5aac540a3afe7337ce79963d7..bc7430b54771af18e903ee1d263ede3b4eb1b78f 100644 (file)
@@ -426,6 +426,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
                          struct net_device *dev, enum nl80211_iftype ntype,
                          u32 *flags, struct vif_params *params);
 void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev);
+void cfg80211_process_wdev_events(struct wireless_dev *wdev);
 
 int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
                                 struct wireless_dev *wdev,
index 2303ee73b50ad2fc40dc136c9250861e9bb890ee..2ded3c7fad063a067151595c774b9bddd14bdc9a 100644 (file)
@@ -680,6 +680,8 @@ static u32 map_regdom_flags(u32 rd_flags)
                channel_flags |= IEEE80211_CHAN_NO_IBSS;
        if (rd_flags & NL80211_RRF_DFS)
                channel_flags |= IEEE80211_CHAN_RADAR;
+       if (rd_flags & NL80211_RRF_NO_OFDM)
+               channel_flags |= IEEE80211_CHAN_NO_OFDM;
        return channel_flags;
 }
 
@@ -901,7 +903,21 @@ static void handle_channel(struct wiphy *wiphy,
        chan->max_antenna_gain = min(chan->orig_mag,
                (int) MBI_TO_DBI(power_rule->max_antenna_gain));
        chan->max_reg_power = (int) MBM_TO_DBM(power_rule->max_eirp);
-       chan->max_power = min(chan->max_power, chan->max_reg_power);
+       if (chan->orig_mpwr) {
+               /*
+                * Devices that have their own custom regulatory domain
+                * but also use WIPHY_FLAG_STRICT_REGULATORY will follow the
+                * passed country IE power settings.
+                */
+               if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE &&
+                   wiphy->flags & WIPHY_FLAG_CUSTOM_REGULATORY &&
+                   wiphy->flags & WIPHY_FLAG_STRICT_REGULATORY)
+                       chan->max_power = chan->max_reg_power;
+               else
+                       chan->max_power = min(chan->orig_mpwr,
+                                             chan->max_reg_power);
+       } else
+               chan->max_power = chan->max_reg_power;
 }
 
 static void handle_band(struct wiphy *wiphy,
@@ -1885,6 +1901,7 @@ static void restore_custom_reg_settings(struct wiphy *wiphy)
                        chan->flags = chan->orig_flags;
                        chan->max_antenna_gain = chan->orig_mag;
                        chan->max_power = chan->orig_mpwr;
+                       chan->beacon_found = false;
                }
        }
 }
index 26f8cd30f712dc190d9e207e4dff989a75106c66..994e2f0cc7a8a12fc34cbe61fdee97afde3df10b 100644 (file)
@@ -735,7 +735,7 @@ void cfg80211_upload_connect_keys(struct wireless_dev *wdev)
        wdev->connect_keys = NULL;
 }
 
-static void cfg80211_process_wdev_events(struct wireless_dev *wdev)
+void cfg80211_process_wdev_events(struct wireless_dev *wdev)
 {
        struct cfg80211_event *ev;
        unsigned long flags;
index c5a5165a5927a185043bdc83e8c9c4e25f549753..5ad4d2c4b83c5ca1fb58ff719c516b710ba2ef96 100644 (file)
@@ -42,13 +42,14 @@ static DEFINE_SPINLOCK(xfrm_policy_sk_bundle_lock);
 static struct dst_entry *xfrm_policy_sk_bundles;
 static DEFINE_RWLOCK(xfrm_policy_lock);
 
-static DEFINE_RWLOCK(xfrm_policy_afinfo_lock);
-static struct xfrm_policy_afinfo *xfrm_policy_afinfo[NPROTO];
+static DEFINE_SPINLOCK(xfrm_policy_afinfo_lock);
+static struct xfrm_policy_afinfo __rcu *xfrm_policy_afinfo[NPROTO]
+                                               __read_mostly;
 
 static struct kmem_cache *xfrm_dst_cache __read_mostly;
 
 static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family);
-static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo);
+static inline void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo);
 static void xfrm_init_pmtu(struct dst_entry *dst);
 static int stale_bundle(struct dst_entry *dst);
 static int xfrm_bundle_ok(struct xfrm_dst *xdst);
@@ -2418,7 +2419,7 @@ int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo)
                return -EINVAL;
        if (unlikely(afinfo->family >= NPROTO))
                return -EAFNOSUPPORT;
-       write_lock_bh(&xfrm_policy_afinfo_lock);
+       spin_lock_bh(&xfrm_policy_afinfo_lock);
        if (unlikely(xfrm_policy_afinfo[afinfo->family] != NULL))
                err = -ENOBUFS;
        else {
@@ -2439,9 +2440,9 @@ int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo)
                        dst_ops->neigh_lookup = xfrm_neigh_lookup;
                if (likely(afinfo->garbage_collect == NULL))
                        afinfo->garbage_collect = xfrm_garbage_collect_deferred;
-               xfrm_policy_afinfo[afinfo->family] = afinfo;
+               rcu_assign_pointer(xfrm_policy_afinfo[afinfo->family], afinfo);
        }
-       write_unlock_bh(&xfrm_policy_afinfo_lock);
+       spin_unlock_bh(&xfrm_policy_afinfo_lock);
 
        rtnl_lock();
        for_each_net(net) {
@@ -2474,13 +2475,14 @@ int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo)
                return -EINVAL;
        if (unlikely(afinfo->family >= NPROTO))
                return -EAFNOSUPPORT;
-       write_lock_bh(&xfrm_policy_afinfo_lock);
+       spin_lock_bh(&xfrm_policy_afinfo_lock);
        if (likely(xfrm_policy_afinfo[afinfo->family] != NULL)) {
                if (unlikely(xfrm_policy_afinfo[afinfo->family] != afinfo))
                        err = -EINVAL;
                else {
                        struct dst_ops *dst_ops = afinfo->dst_ops;
-                       xfrm_policy_afinfo[afinfo->family] = NULL;
+                       rcu_assign_pointer(xfrm_policy_afinfo[afinfo->family],
+                                                                       NULL);
                        dst_ops->kmem_cachep = NULL;
                        dst_ops->check = NULL;
                        dst_ops->negative_advice = NULL;
@@ -2488,7 +2490,8 @@ int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo)
                        afinfo->garbage_collect = NULL;
                }
        }
-       write_unlock_bh(&xfrm_policy_afinfo_lock);
+       spin_unlock_bh(&xfrm_policy_afinfo_lock);
+       synchronize_rcu();
        return err;
 }
 EXPORT_SYMBOL(xfrm_policy_unregister_afinfo);
@@ -2497,16 +2500,16 @@ static void __net_init xfrm_dst_ops_init(struct net *net)
 {
        struct xfrm_policy_afinfo *afinfo;
 
-       read_lock_bh(&xfrm_policy_afinfo_lock);
-       afinfo = xfrm_policy_afinfo[AF_INET];
+       rcu_read_lock_bh();
+       afinfo = rcu_dereference(xfrm_policy_afinfo[AF_INET]);
        if (afinfo)
                net->xfrm.xfrm4_dst_ops = *afinfo->dst_ops;
 #if IS_ENABLED(CONFIG_IPV6)
-       afinfo = xfrm_policy_afinfo[AF_INET6];
+       afinfo = rcu_dereference(xfrm_policy_afinfo[AF_INET6]);
        if (afinfo)
                net->xfrm.xfrm6_dst_ops = *afinfo->dst_ops;
 #endif
-       read_unlock_bh(&xfrm_policy_afinfo_lock);
+       rcu_read_unlock_bh();
 }
 
 static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family)
@@ -2514,16 +2517,16 @@ static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family)
        struct xfrm_policy_afinfo *afinfo;
        if (unlikely(family >= NPROTO))
                return NULL;
-       read_lock(&xfrm_policy_afinfo_lock);
-       afinfo = xfrm_policy_afinfo[family];
+       rcu_read_lock();
+       afinfo = rcu_dereference(xfrm_policy_afinfo[family]);
        if (unlikely(!afinfo))
-               read_unlock(&xfrm_policy_afinfo_lock);
+               rcu_read_unlock();
        return afinfo;
 }
 
-static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo)
+static inline void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo)
 {
-       read_unlock(&xfrm_policy_afinfo_lock);
+       rcu_read_unlock();
 }
 
 static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
index 5b228f97d4b3308a950ae857828e04e90df86848..7856c33898fa7f791445067180a9c32a56befe89 100644 (file)
@@ -415,8 +415,17 @@ static enum hrtimer_restart xfrm_timer_handler(struct hrtimer * me)
        if (x->lft.hard_add_expires_seconds) {
                long tmo = x->lft.hard_add_expires_seconds +
                        x->curlft.add_time - now;
-               if (tmo <= 0)
-                       goto expired;
+               if (tmo <= 0) {
+                       if (x->xflags & XFRM_SOFT_EXPIRE) {
+                               /* enter hard expire without soft expire first?!
+                                * setting a new date could trigger this.
+                                * workarbound: fix x->curflt.add_time by below:
+                                */
+                               x->curlft.add_time = now - x->saved_tmo - 1;
+                               tmo = x->lft.hard_add_expires_seconds - x->saved_tmo;
+                       } else
+                               goto expired;
+               }
                if (tmo < next)
                        next = tmo;
        }
@@ -433,10 +442,14 @@ static enum hrtimer_restart xfrm_timer_handler(struct hrtimer * me)
        if (x->lft.soft_add_expires_seconds) {
                long tmo = x->lft.soft_add_expires_seconds +
                        x->curlft.add_time - now;
-               if (tmo <= 0)
+               if (tmo <= 0) {
                        warn = 1;
-               else if (tmo < next)
+                       x->xflags &= ~XFRM_SOFT_EXPIRE;
+               } else if (tmo < next) {
                        next = tmo;
+                       x->xflags |= XFRM_SOFT_EXPIRE;
+                       x->saved_tmo = tmo;
+               }
        }
        if (x->lft.soft_use_expires_seconds) {
                long tmo = x->lft.soft_use_expires_seconds +
@@ -1687,7 +1700,7 @@ int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol)
 
        read_lock(&xfrm_km_lock);
        list_for_each_entry(km, &xfrm_km_list, list) {
-               acqret = km->acquire(x, t, pol, XFRM_POLICY_OUT);
+               acqret = km->acquire(x, t, pol);
                if (!acqret)
                        err = acqret;
        }
index e75d8e47f35cab2bdddd1051e6da556ef20eb26c..ab58034c42d60483d68df00567d0498d923972f0 100644 (file)
@@ -2567,8 +2567,7 @@ static inline size_t xfrm_acquire_msgsize(struct xfrm_state *x,
 }
 
 static int build_acquire(struct sk_buff *skb, struct xfrm_state *x,
-                        struct xfrm_tmpl *xt, struct xfrm_policy *xp,
-                        int dir)
+                        struct xfrm_tmpl *xt, struct xfrm_policy *xp)
 {
        __u32 seq = xfrm_get_acqseq();
        struct xfrm_user_acquire *ua;
@@ -2583,7 +2582,7 @@ static int build_acquire(struct sk_buff *skb, struct xfrm_state *x,
        memcpy(&ua->id, &x->id, sizeof(ua->id));
        memcpy(&ua->saddr, &x->props.saddr, sizeof(ua->saddr));
        memcpy(&ua->sel, &x->sel, sizeof(ua->sel));
-       copy_to_user_policy(xp, &ua->policy, dir);
+       copy_to_user_policy(xp, &ua->policy, XFRM_POLICY_OUT);
        ua->aalgos = xt->aalgos;
        ua->ealgos = xt->ealgos;
        ua->calgos = xt->calgos;
@@ -2605,7 +2604,7 @@ static int build_acquire(struct sk_buff *skb, struct xfrm_state *x,
 }
 
 static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt,
-                            struct xfrm_policy *xp, int dir)
+                            struct xfrm_policy *xp)
 {
        struct net *net = xs_net(x);
        struct sk_buff *skb;
@@ -2614,7 +2613,7 @@ static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt,
        if (skb == NULL)
                return -ENOMEM;
 
-       if (build_acquire(skb, x, xt, xp, dir) < 0)
+       if (build_acquire(skb, x, xt, xp) < 0)
                BUG();
 
        return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_ACQUIRE, GFP_ATOMIC);
index 643279dd30fbbe6151578e328be864745cc03216..38ee70f3cd5b970101edd6d2edb52b4df8d73d14 100644 (file)
@@ -59,6 +59,16 @@ void seccomp_bpf_print(struct sock_filter *filter, size_t count);
 #define FIND_LABEL(labels, label) seccomp_bpf_label((labels), #label)
 
 #define EXPAND(...) __VA_ARGS__
+
+/* Ensure that we load the logically correct offset. */
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)])
+#elif __BYTE_ORDER == __BIG_ENDIAN
+#define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) + sizeof(__u32)
+#else
+#error "Unknown endianness"
+#endif
+
 /* Map all width-sensitive operations */
 #if __BITS_PER_LONG == 32
 
@@ -70,21 +80,16 @@ void seccomp_bpf_print(struct sock_filter *filter, size_t count);
 #define JLE(x, jt) JLE32(x, EXPAND(jt))
 #define JA(x, jt) JA32(x, EXPAND(jt))
 #define ARG(i) ARG_32(i)
-#define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)])
 
 #elif __BITS_PER_LONG == 64
 
 /* Ensure that we load the logically correct offset. */
 #if __BYTE_ORDER == __LITTLE_ENDIAN
 #define ENDIAN(_lo, _hi) _lo, _hi
-#define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)])
 #define HI_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) + sizeof(__u32)
 #elif __BYTE_ORDER == __BIG_ENDIAN
 #define ENDIAN(_lo, _hi) _hi, _lo
-#define LO_ARG(idx) offsetof(struct seccomp_data, args[(idx)]) + sizeof(__u32)
 #define HI_ARG(idx) offsetof(struct seccomp_data, args[(idx)])
-#else
-#error "Unknown endianness"
 #endif
 
 union arg64 {
index 18ba881c34159a8bcdc3b8b582bd3f0617f90e8a..4f8248d5a11f2e74712b77d4c3521870652dcddd 100755 (executable)
@@ -89,7 +89,7 @@ echo $code >> $T.s
 disas $T
 cat $T.dis >> $T.aa
 
-faultline=`cat $T.dis | head -1 | cut -d":" -f2`
+faultline=`cat $T.dis | head -1 | cut -d":" -f2-`
 faultline=`echo "$faultline" | sed -e 's/\[/\\\[/g; s/\]/\\\]/g'`
 
 cat $T.oo | sed -e "s/\($faultline\)/\*\1     <-- trapping instruction/g"
index 77d53999ffb90f51bea3f0395be08e495e3b75b8..1c932a2c1d83f488ea35a964c90d8bfd5f99dde7 100644 (file)
@@ -3,7 +3,7 @@
 # These targets are used from top-level makefile
 
 PHONY += oldconfig xconfig gconfig menuconfig config silentoldconfig update-po-config \
-       localmodconfig localyesconfig
+       localmodconfig localyesconfig kvmconfig
 
 ifdef KBUILD_KCONFIG
 Kconfig := $(KBUILD_KCONFIG)
@@ -33,6 +33,11 @@ silentoldconfig: $(obj)/conf
        $(Q)mkdir -p include/generated
        $< --$@ $(Kconfig)
 
+kvmconfig:
+       $(Q)$(CONFIG_SHELL) $(srctree)/scripts/config -e KVMTOOL_TEST_ENABLE
+       $(Q)yes "" | make oldconfig > /dev/null
+       @echo 'Kernel configuration modified to run as KVM guest.'
+
 localyesconfig localmodconfig: $(obj)/streamline_config.pl $(obj)/conf
        $(Q)mkdir -p include/generated
        $(Q)perl $< --$@ $(srctree) $(Kconfig) > .tmp.config
index 2fbbbc1ddea02ad573315ef264fc5c79064a1f5e..39b6314fe634dd461f5b9c8e71f3409633c0a0b6 100644 (file)
@@ -100,7 +100,7 @@ my @searchconfigs = (
        },
 );
 
-sub find_config {
+sub read_config {
     foreach my $conf (@searchconfigs) {
        my $file = $conf->{"file"};
 
@@ -115,17 +115,15 @@ sub find_config {
 
        print STDERR "using config: '$file'\n";
 
-       open(CIN, "$exec $file |") || die "Failed to run $exec $file";
-       return;
+       open(my $infile, '-|', "$exec $file") || die "Failed to run $exec $file";
+       my @x = <$infile>;
+       close $infile;
+       return @x;
     }
     die "No config file found";
 }
 
-find_config;
-
-# Read in the entire config file into config_file
-my @config_file = <CIN>;
-close CIN;
+my @config_file = read_config;
 
 # Parse options
 my $localmodconfig = 0;
@@ -135,7 +133,7 @@ GetOptions("localmodconfig" => \$localmodconfig,
           "localyesconfig" => \$localyesconfig);
 
 # Get the build source and top level Kconfig file (passed in)
-my $ksource = $ARGV[0];
+my $ksource = ($ARGV[0] ? $ARGV[0] : '.');
 my $kconfig = $ARGV[1];
 my $lsmod_file = $ENV{'LSMOD'};
 
@@ -173,8 +171,8 @@ sub read_kconfig {
        $source =~ s/\$$env/$ENV{$env}/;
     }
 
-    open(KIN, "$source") || die "Can't open $kconfig";
-    while (<KIN>) {
+    open(my $kinfile, '<', $source) || die "Can't open $kconfig";
+    while (<$kinfile>) {
        chomp;
 
        # Make sure that lines ending with \ continue
@@ -251,10 +249,10 @@ sub read_kconfig {
            $state = "NONE";
        }
     }
-    close(KIN);
+    close($kinfile);
 
     # read in any configs that were found.
-    foreach $kconfig (@kconfigs) {
+    foreach my $kconfig (@kconfigs) {
        if (!defined($read_kconfigs{$kconfig})) {
            $read_kconfigs{$kconfig} = 1;
            read_kconfig($kconfig);
@@ -295,8 +293,8 @@ foreach my $makefile (@makefiles) {
     my $line = "";
     my %make_vars;
 
-    open(MIN,$makefile) || die "Can't open $makefile";
-    while (<MIN>) {
+    open(my $infile, '<', $makefile) || die "Can't open $makefile";
+    while (<$infile>) {
        # if this line ends with a backslash, continue
        chomp;
        if (/^(.*)\\$/) {
@@ -343,10 +341,11 @@ foreach my $makefile (@makefiles) {
            }
        }
     }
-    close(MIN);
+    close($infile);
 }
 
 my %modules;
+my $linfile;
 
 if (defined($lsmod_file)) {
     if ( ! -f $lsmod_file) {
@@ -356,13 +355,10 @@ if (defined($lsmod_file)) {
                die "$lsmod_file not found";
        }
     }
-    if ( -x $lsmod_file) {
-       # the file is executable, run it
-       open(LIN, "$lsmod_file|");
-    } else {
-       # Just read the contents
-       open(LIN, "$lsmod_file");
-    }
+
+    my $otype = ( -x $lsmod_file) ? '-|' : '<';
+    open($linfile, $otype, $lsmod_file);
+
 } else {
 
     # see what modules are loaded on this system
@@ -379,16 +375,16 @@ if (defined($lsmod_file)) {
        $lsmod = "lsmod";
     }
 
-    open(LIN,"$lsmod|") || die "Can not call lsmod with $lsmod";
+    open($linfile, '-|', $lsmod) || die "Can not call lsmod with $lsmod";
 }
 
-while (<LIN>) {
+while (<$linfile>) {
        next if (/^Module/);  # Skip the first line.
        if (/^(\S+)/) {
                $modules{$1} = 1;
        }
 }
-close (LIN);
+close ($linfile);
 
 # add to the configs hash all configs that are needed to enable
 # a loaded module. This is a direct obj-${CONFIG_FOO} += bar.o
index 83554ee8a587fbf27bdc7095fa8a600b82aada57..d51b7c76c37da3e60ab23e7b47c2fe03249b4707 100644 (file)
@@ -290,10 +290,51 @@ static int yama_ptrace_access_check(struct task_struct *child,
        return rc;
 }
 
+/**
+ * yama_ptrace_traceme - validate PTRACE_TRACEME calls
+ * @parent: task that will become the ptracer of the current task
+ *
+ * Returns 0 if following the ptrace is allowed, -ve on error.
+ */
+static int yama_ptrace_traceme(struct task_struct *parent)
+{
+       int rc;
+
+       /* If standard caps disallows it, so does Yama.  We should
+        * only tighten restrictions further.
+        */
+       rc = cap_ptrace_traceme(parent);
+       if (rc)
+               return rc;
+
+       /* Only disallow PTRACE_TRACEME on more aggressive settings. */
+       switch (ptrace_scope) {
+       case YAMA_SCOPE_CAPABILITY:
+               if (!ns_capable(task_user_ns(parent), CAP_SYS_PTRACE))
+                       rc = -EPERM;
+               break;
+       case YAMA_SCOPE_NO_ATTACH:
+               rc = -EPERM;
+               break;
+       }
+
+       if (rc) {
+               char name[sizeof(current->comm)];
+               printk_ratelimited(KERN_NOTICE
+                       "ptraceme of pid %d was attempted by: %s (pid %d)\n",
+                       current->pid,
+                       get_task_comm(name, parent),
+                       parent->pid);
+       }
+
+       return rc;
+}
+
 static struct security_operations yama_ops = {
        .name =                 "yama",
 
        .ptrace_access_check =  yama_ptrace_access_check,
+       .ptrace_traceme =       yama_ptrace_traceme,
        .task_prctl =           yama_task_prctl,
        .task_free =            yama_task_free,
 };
index 0d7b25e816437064775a1f81ab8753a0f619ccab..4e1fda75c1c9fbc335b6b45fd34871e8ce0a1898 100644 (file)
@@ -106,7 +106,7 @@ static struct pxa2xx_pcm_client pxa2xx_ac97_pcm_client = {
        .prepare                = pxa2xx_ac97_pcm_prepare,
 };
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 
 static int pxa2xx_ac97_do_suspend(struct snd_card *card)
 {
@@ -243,7 +243,7 @@ static struct platform_driver pxa2xx_ac97_driver = {
        .driver         = {
                .name   = "pxa2xx-ac97",
                .owner  = THIS_MODULE,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
                .pm     = &pxa2xx_ac97_pm_ops,
 #endif
        },
index eb4ceb71123e1aa91f9063fa57653befc5a7ef09..98554f4882b7d0738e107b4ab55070fbb285871a 100644 (file)
@@ -534,7 +534,7 @@ out_put_pclk:
        return retval;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int atmel_abdac_suspend(struct device *pdev)
 {
        struct snd_card *card = dev_get_drvdata(pdev);
index bf47025bdf45776ce020e738f04af62752ea025c..3c8d3ba7ddfc67841cf41b31f1d9f0aca28afba2 100644 (file)
@@ -1134,7 +1134,7 @@ err_snd_card_new:
        return retval;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int atmel_ac97c_suspend(struct device *pdev)
 {
        struct snd_card *card = dev_get_drvdata(pdev);
index 4e7ec2b498738b6e2ebca47511be93b590af2aa8..d0f00356fc115a32db23bc8475f08a6aad178c47 100644 (file)
@@ -101,7 +101,7 @@ void *snd_malloc_sgbuf_pages(struct device *device,
                if (snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV, device,
                                                 chunk, &tmpb) < 0) {
                        if (!sgbuf->pages)
-                               return NULL;
+                               goto _failed;
                        if (!res_size)
                                goto _failed;
                        size = sgbuf->pages * PAGE_SIZE;
index 1128b35b2b05f47fc2c5783a16a10e9e26b9de29..5a34355e78e8f83295496e1feb836a99f7ff7b44 100644 (file)
@@ -1176,7 +1176,7 @@ static int __devexit loopback_remove(struct platform_device *devptr)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int loopback_suspend(struct device *pdev)
 {
        struct snd_card *card = dev_get_drvdata(pdev);
index f7d3bfc6bca83ed296a59fb059cd79ea364c6879..54bb6644a598a8177e3fbec4220df2966abd6131 100644 (file)
@@ -1064,7 +1064,7 @@ static int __devexit snd_dummy_remove(struct platform_device *devptr)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int snd_dummy_suspend(struct device *pdev)
 {
        struct snd_card *card = dev_get_drvdata(pdev);
index 6ca59fc6dcb9c0faf3e5fe07890fd237568a5d79..ef171295f6d46b3684667dfac434196f5a9ccd3f 100644 (file)
@@ -199,7 +199,7 @@ static void pcsp_stop_beep(struct snd_pcsp *chip)
        pcspkr_stop_sound();
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int pcsp_suspend(struct device *dev)
 {
        struct snd_pcsp *chip = dev_get_drvdata(dev);
@@ -212,7 +212,7 @@ static SIMPLE_DEV_PM_OPS(pcsp_pm, pcsp_suspend, NULL);
 #define PCSP_PM_OPS    &pcsp_pm
 #else
 #define PCSP_PM_OPS    NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static void pcsp_shutdown(struct platform_device *dev)
 {
index a76bc8d27c1d914a2dd36262ef2f1f8f1a9307bf..3fc8b66fd167fc98bbdd42c29b889920f5c104ce 100644 (file)
@@ -443,9 +443,8 @@ static void __devinit snd_interwave_detect_memory(struct snd_gus_card * gus)
                for (i = 0; i < 8; ++i)
                        iwave[i] = snd_gf1_peek(gus, bank_pos + i);
 #ifdef CONFIG_SND_DEBUG_ROM
-               printk(KERN_DEBUG "ROM at 0x%06x = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", bank_pos,
-                      iwave[0], iwave[1], iwave[2], iwave[3],
-                      iwave[4], iwave[5], iwave[6], iwave[7]);
+               printk(KERN_DEBUG "ROM at 0x%06x = %*phC\n", bank_pos,
+                                 8, iwave);
 #endif
                if (strncmp(iwave, "INTRWAVE", 8))
                        continue;       /* first check */
index c24594c866f458adbcdd155e025d4f2ba9c78ebf..3d1afb612b3548ade1db68d1b60af8f3e7e6ce4b 100644 (file)
@@ -37,6 +37,7 @@
 #include <sound/opl4.h>
 #include <sound/control.h>
 #include <sound/info.h>
+#define SNDRV_LEGACY_FIND_FREE_IOPORT
 #define SNDRV_LEGACY_FIND_FREE_IRQ
 #define SNDRV_LEGACY_FIND_FREE_DMA
 #include <sound/initval.h>
@@ -770,20 +771,6 @@ static int __devinit snd_miro_mixer(struct snd_card *card,
        return 0;
 }
 
-static long snd_legacy_find_free_ioport(long *port_table, long size)
-{
-       while (*port_table != -1) {
-               struct resource *res;
-               if ((res = request_region(*port_table, size, 
-                                         "ALSA test")) != NULL) {
-                       release_and_free_resource(res);
-                       return *port_table;
-               }
-               port_table++;
-       }
-       return -1;
-}
-
 static int __devinit snd_miro_init(struct snd_miro *chip,
                                   unsigned short hardware)
 {
index f8fbe22515c99b627885fa3c05da815514777f4e..2899c9fd1ceb4c12a34d01d714ec1bd3d4e74767 100644 (file)
@@ -39,6 +39,7 @@
 #ifndef OPTi93X
 #include <sound/opl4.h>
 #endif
+#define SNDRV_LEGACY_FIND_FREE_IOPORT
 #define SNDRV_LEGACY_FIND_FREE_IRQ
 #define SNDRV_LEGACY_FIND_FREE_DMA
 #include <sound/initval.h>
@@ -185,19 +186,6 @@ static char * snd_opti9xx_names[] = {
        "82C930",       "82C931",       "82C933"
 };
 
-
-static long __devinit snd_legacy_find_free_ioport(long *port_table, long size)
-{
-       while (*port_table != -1) {
-               if (request_region(*port_table, size, "ALSA test")) {
-                       release_region(*port_table, size);
-                       return *port_table;
-               }
-               port_table++;
-       }
-       return -1;
-}
-
 static int __devinit snd_opti9xx_init(struct snd_opti9xx *chip,
                                      unsigned short hardware)
 {
index ee895f3c8605890f39032263485e9bfb99720939..c7e3c533316eeb72e0873353478354caa7594aab 100644 (file)
@@ -270,7 +270,7 @@ struct snd_ali {
        spinlock_t      reg_lock;
        spinlock_t      voice_alloc;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        struct snd_ali_image *image;
 #endif
 };
@@ -1883,7 +1883,7 @@ static int __devinit snd_ali_mixer(struct snd_ali * codec)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int ali_suspend(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
@@ -1989,7 +1989,7 @@ static SIMPLE_DEV_PM_OPS(ali_pm, ali_suspend, ali_resume);
 #define ALI_PM_OPS     &ali_pm
 #else
 #define ALI_PM_OPS     NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static int snd_ali_free(struct snd_ali * codec)
 {
@@ -2000,7 +2000,7 @@ static int snd_ali_free(struct snd_ali * codec)
        if (codec->port)
                pci_release_regions(codec->pci);
        pci_disable_device(codec->pci);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        kfree(codec->image);
 #endif
        pci_dev_put(codec->pci_m1533);
@@ -2232,7 +2232,7 @@ static int __devinit snd_ali_create(struct snd_card *card,
                return err;
        }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        codec->image = kmalloc(sizeof(*codec->image), GFP_KERNEL);
        if (!codec->image)
                snd_printk(KERN_WARNING "can't allocate apm buffer\n");
index 68c4469c6d1995ed775d49212de6db204da0e668..00f157a2cf6411d8b1ad1b1ffef32f566d5e02b8 100644 (file)
@@ -765,7 +765,7 @@ static int __devinit snd_als300_create(struct snd_card *card,
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int snd_als300_suspend(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
index 0eeca49c57541b3dc85cab82ba389214adab40e1..feb2a143683079df95f47384f0b52c9621a0a03b 100644 (file)
@@ -987,7 +987,7 @@ static void __devexit snd_card_als4000_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int snd_als4000_suspend(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
@@ -1040,7 +1040,7 @@ static SIMPLE_DEV_PM_OPS(snd_als4000_pm, snd_als4000_suspend, snd_als4000_resume
 #define SND_ALS4000_PM_OPS     &snd_als4000_pm
 #else
 #define SND_ALS4000_PM_OPS     NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static struct pci_driver als4000_driver = {
        .name = KBUILD_MODNAME,
index e8de831f98bc510c6cde42159bce817dad45408b..a51e3ce3c800b2f8d97c82337a1598aa918e4c7a 100644 (file)
@@ -2968,7 +2968,7 @@ static struct pci_driver driver = {
        .id_table = asihpi_pci_tbl,
        .probe = snd_asihpi_probe,
        .remove = __devexit_p(snd_asihpi_remove),
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*     .suspend = snd_asihpi_suspend,
        .resume = snd_asihpi_resume, */
 #endif
index 31020d2a868bd97b92d18e65ceb469214f24f7f6..c744df5bb1c65d1a0eb30f884f668ed0986e1d5f 100644 (file)
@@ -535,7 +535,7 @@ static int snd_atiixp_aclink_reset(struct atiixp *chip)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int snd_atiixp_aclink_down(struct atiixp *chip)
 {
        // if (atiixp_read(chip, MODEM_MIRROR) & 0x1) /* modem running, too? */
@@ -1458,7 +1458,7 @@ static int __devinit snd_atiixp_mixer_new(struct atiixp *chip, int clock,
 }
 
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*
  * power management
  */
@@ -1533,7 +1533,7 @@ static SIMPLE_DEV_PM_OPS(snd_atiixp_pm, snd_atiixp_suspend, snd_atiixp_resume);
 #define SND_ATIIXP_PM_OPS      &snd_atiixp_pm
 #else
 #define SND_ATIIXP_PM_OPS      NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 
 #ifdef CONFIG_PROC_FS
index 79e204ec623fe298859f216c85c36244ab81bf33..6fc03d9f2cff451c2b3db77a525c64cd984c6b92 100644 (file)
@@ -511,7 +511,7 @@ static int snd_atiixp_aclink_reset(struct atiixp_modem *chip)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int snd_atiixp_aclink_down(struct atiixp_modem *chip)
 {
        // if (atiixp_read(chip, MODEM_MIRROR) & 0x1) /* modem running, too? */
@@ -1113,7 +1113,7 @@ static int __devinit snd_atiixp_mixer_new(struct atiixp_modem *chip, int clock)
 }
 
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*
  * power management
  */
@@ -1169,7 +1169,7 @@ static SIMPLE_DEV_PM_OPS(snd_atiixp_pm, snd_atiixp_suspend, snd_atiixp_resume);
 #define SND_ATIIXP_PM_OPS      &snd_atiixp_pm
 #else
 #define SND_ATIIXP_PM_OPS      NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 #ifdef CONFIG_PROC_FS
 /*
index 4dddd871548b3de1c83bb829c4c16bee7fa1a14e..c03b66b784a377ef22135d81de415995c9c163d7 100644 (file)
@@ -365,7 +365,7 @@ struct snd_azf3328 {
         * CONFIG_PM register storage below, but that's slightly difficult. */
        u16 shadow_reg_ctrl_6AH;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        /* register value containers for power management
         * Note: not always full I/O range preserved (similar to Win driver!) */
        u32 saved_regs_ctrl[AZF_ALIGN(AZF_IO_SIZE_CTRL_PM) / 4];
@@ -2729,7 +2729,7 @@ snd_azf3328_remove(struct pci_dev *pci)
        snd_azf3328_dbgcallleave();
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static inline void
 snd_azf3328_suspend_regs(unsigned long io_addr, unsigned count, u32 *saved_regs)
 {
@@ -2866,7 +2866,7 @@ static SIMPLE_DEV_PM_OPS(snd_azf3328_pm, snd_azf3328_suspend, snd_azf3328_resume
 #define SND_AZF3328_PM_OPS     &snd_azf3328_pm
 #else
 #define SND_AZF3328_PM_OPS     NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static struct pci_driver azf3328_driver = {
        .name = KBUILD_MODNAME,
index e8e8ccc964038c1aa29154d83c44b8c2b616b8e5..04402c14cb2392276bb23308244c626b6539fc4e 100644 (file)
@@ -710,7 +710,7 @@ struct snd_ca0106 {
 
        u16 spi_dac_reg[16];
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 #define NUM_SAVED_VOLUMES      9
        unsigned int saved_vol[NUM_SAVED_VOLUMES];
 #endif
@@ -733,7 +733,7 @@ int snd_ca0106_i2c_write(struct snd_ca0106 *emu, u32 reg, u32 value);
 int snd_ca0106_spi_write(struct snd_ca0106 * emu,
                                   unsigned int data);
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 void snd_ca0106_mixer_suspend(struct snd_ca0106 *chip);
 void snd_ca0106_mixer_resume(struct snd_ca0106 *chip);
 #else
index 83277b747b36928f96ba14ab9bb0d32dcea1de57..fc6787699ba92bbb5fb608c6a685592f764661ee 100644 (file)
@@ -1871,7 +1871,7 @@ static void __devexit snd_ca0106_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int snd_ca0106_suspend(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
index 84f3f92436b5a34eb414158bea5405288e27e455..68eacf7002d6ee87b848818b06a6997236d00426 100644 (file)
@@ -907,7 +907,7 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu)
         return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 struct ca0106_vol_tbl {
        unsigned int channel_id;
        unsigned int reg;
@@ -953,4 +953,4 @@ void snd_ca0106_mixer_resume(struct snd_ca0106  *chip)
        if (chip->details->i2c_adc)
                ca0106_set_capture_mic_line_in(chip);
 }
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
index b7d6f2b886effc78de4da2caaeac53b1ff786010..7c25906b5f88c99648052479a079f5c49595feda 100644 (file)
@@ -504,7 +504,7 @@ struct cmipci {
 
        spinlock_t reg_lock;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        unsigned int saved_regs[0x20];
        unsigned char saved_mixers[0x20];
 #endif
@@ -3315,7 +3315,7 @@ static void __devexit snd_cmipci_remove(struct pci_dev *pci)
 }
 
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*
  * power management
  */
@@ -3403,7 +3403,7 @@ static SIMPLE_DEV_PM_OPS(snd_cmipci_pm, snd_cmipci_suspend, snd_cmipci_resume);
 #define SND_CMIPCI_PM_OPS      &snd_cmipci_pm
 #else
 #define SND_CMIPCI_PM_OPS      NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static struct pci_driver cmipci_driver = {
        .name = KBUILD_MODNAME,
index 45a8317085f44961719db1b76195afb1d4d7e0ff..8e86ec0031fcce10cdec54d3bbb6d03d310daa8f 100644 (file)
@@ -486,7 +486,7 @@ struct cs4281 {
 
        struct gameport *gameport;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        u32 suspend_regs[SUSPEND_REGISTERS];
 #endif
 
@@ -1977,7 +1977,7 @@ static void __devexit snd_cs4281_remove(struct pci_dev *pci)
 /*
  * Power Management
  */
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 
 static int saved_regs[SUSPEND_REGISTERS] = {
        BA0_JSCTL,
@@ -2089,7 +2089,7 @@ static SIMPLE_DEV_PM_OPS(cs4281_pm, cs4281_suspend, cs4281_resume);
 #define CS4281_PM_OPS  &cs4281_pm
 #else
 #define CS4281_PM_OPS  NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static struct pci_driver cs4281_driver = {
        .name = KBUILD_MODNAME,
index 1e007c736a8bf6b939334fcc3ee9d5faf0ec14f7..575bed0836ffa242856ab5db73f8cbe2d80288da 100644 (file)
@@ -166,7 +166,7 @@ static struct pci_driver cs46xx_driver = {
        .id_table = snd_cs46xx_ids,
        .probe = snd_card_cs46xx_probe,
        .remove = __devexit_p(snd_card_cs46xx_remove),
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        .driver = {
                .pm = &snd_cs46xx_pm,
        },
index 29d8a8da1ba73a6bf0e4ff915e7492a7745ec862..fc339ef0a0ae439a87087753a4bfaf6e28de9742 100644 (file)
@@ -1721,7 +1721,7 @@ struct snd_cs46xx {
        unsigned int play_ctl;
 #endif
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        u32 *saved_regs;
 #endif
 };
index f75f5ffdfdfb60724db8a90dbac5ca05447f3816..a2bb8c91ebe6041c61b2789d0ef97b073ac518b1 100644 (file)
@@ -94,7 +94,7 @@ static unsigned short snd_cs46xx_codec_read(struct snd_cs46xx *chip,
 
        if (snd_BUG_ON(codec_index != CS46XX_PRIMARY_CODEC_INDEX &&
                       codec_index != CS46XX_SECONDARY_CODEC_INDEX))
-               return -EINVAL;
+               return 0xffff;
 
        chip->active_ctrl(chip, 1);
 
@@ -2797,7 +2797,7 @@ static int snd_cs46xx_free(struct snd_cs46xx *chip)
        }
 #endif
        
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        kfree(chip->saved_regs);
 #endif
 
@@ -3590,7 +3590,7 @@ static struct cs_card_type __devinitdata cards[] = {
 /*
  * APM support
  */
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static unsigned int saved_regs[] = {
        BA0_ACOSV,
        /*BA0_ASER_FADDR,*/
@@ -3711,7 +3711,7 @@ static int snd_cs46xx_resume(struct device *dev)
 }
 
 SIMPLE_DEV_PM_OPS(snd_cs46xx_pm, snd_cs46xx_suspend, snd_cs46xx_resume);
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 
 /*
@@ -3868,7 +3868,7 @@ int __devinit snd_cs46xx_create(struct snd_card *card,
        
        snd_cs46xx_proc_init(card, chip);
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        chip->saved_regs = kmalloc(sizeof(*chip->saved_regs) *
                                   ARRAY_SIZE(saved_regs), GFP_KERNEL);
        if (!chip->saved_regs) {
index b5189495d58a412634d6be413e7cf77ac9876907..86f14620f817f70821aabe16086a20a238f0c0c3 100644 (file)
@@ -90,7 +90,7 @@ static inline unsigned int snd_cs46xx_peekBA0(struct snd_cs46xx *chip, unsigned
 struct dsp_spos_instance *cs46xx_dsp_spos_create (struct snd_cs46xx * chip);
 void cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip);
 int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * module);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 int cs46xx_dsp_resume(struct snd_cs46xx * chip);
 #endif
 struct dsp_symbol_entry *cs46xx_dsp_lookup_symbol (struct snd_cs46xx * chip, char * symbol_name,
index 56fec0bc0efb30cfbd04fcad3d80dd03efa81725..1686b4f4c44fb493538ada5bf14f4965ed645443 100644 (file)
@@ -287,7 +287,7 @@ void  cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip)
                if (ins->scbs[i].deleted) continue;
 
                cs46xx_dsp_proc_free_scb_desc ( (ins->scbs + i) );
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
                kfree(ins->scbs[i].data);
 #endif
        }
@@ -1019,7 +1019,7 @@ cs46xx_dsp_create_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32
 {
        struct dsp_scb_descriptor * desc;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        /* copy the data for resume */
        scb_data = kmemdup(scb_data, SCB_BYTES, GFP_KERNEL);
        if (!scb_data)
@@ -1032,7 +1032,7 @@ cs46xx_dsp_create_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32
                _dsp_create_scb(chip,scb_data,dest);
        } else {
                snd_printk(KERN_ERR "dsp_spos: failed to map SCB\n");
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
                kfree(scb_data);
 #endif
        }
@@ -1937,7 +1937,7 @@ int cs46xx_dsp_set_iec958_volume (struct snd_cs46xx * chip, u16 left, u16 right)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 int cs46xx_dsp_resume(struct snd_cs46xx * chip)
 {
        struct dsp_spos_instance * ins = chip->dsp_spos_instance;
index c2c695b07f8cc0c63e1599f403ccaade2b9e52f7..409e8764fbeb2a3678b4c01446a699fc631bc2a5 100644 (file)
@@ -203,7 +203,7 @@ void cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor *
        remove_symbol (chip,scb->scb_symbol);
 
        ins->scbs[scb->index].deleted = 1;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        kfree(ins->scbs[scb->index].data);
        ins->scbs[scb->index].data = NULL;
 #endif
index ccc642269b9e6a71a108df9f03d39d54f5df9029..a8f75f8dfda9912229cf8b4bfd087230900c49e8 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 snd-cs5535audio-y := cs5535audio.o cs5535audio_pcm.o
-snd-cs5535audio-$(CONFIG_PM) += cs5535audio_pm.o
+snd-cs5535audio-$(CONFIG_PM_SLEEP) += cs5535audio_pm.o
 snd-cs5535audio-$(CONFIG_OLPC) += cs5535audio_olpc.o
 
 # Toplevel Module Dependency
index 51f64ba5facf0ace8ec14e85ef4eb6911100f9d9..4915efa551fca122434cc926adcf92721b58018f 100644 (file)
@@ -399,7 +399,7 @@ static struct pci_driver cs5535audio_driver = {
        .id_table = snd_cs5535audio_ids,
        .probe = snd_cs5535audio_probe,
        .remove = __devexit_p(snd_cs5535audio_remove),
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        .driver = {
                .pm = &snd_cs5535audio_pm,
        },
index 8e40262d4117cf923c9972711177ab5b8b445dcd..58b235c46e862d8adeb5d23c7f28ea9216bd0601 100644 (file)
@@ -1536,7 +1536,7 @@ static void atc_connect_resources(struct ct_atc *atc)
        }
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int atc_suspend(struct ct_atc *atc)
 {
        int i;
@@ -1647,7 +1647,7 @@ static struct ct_atc atc_preset __devinitdata = {
        .output_switch_put = atc_output_switch_put,
        .mic_source_switch_get = atc_mic_source_switch_get,
        .mic_source_switch_put = atc_mic_source_switch_put,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        .suspend = atc_suspend,
        .resume = atc_resume,
 #endif
index 653e813ad1422729ce69c26df8a81b721c095387..69b51f9d345eda48eff3fa2b85790b70990e188d 100644 (file)
@@ -143,7 +143,7 @@ struct ct_atc {
 
        struct ct_timer *timer;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        int (*suspend)(struct ct_atc *atc);
        int (*resume)(struct ct_atc *atc);
 #define NUM_PCMS (NUM_CTALSADEVS - 1)
index c56fe533b3f375b643988e9d1b9b40f783fa6385..5977e9a24b5ca68971e1f5f0dc17f17b03257098 100644 (file)
@@ -72,7 +72,7 @@ struct hw {
        int (*card_init)(struct hw *hw, struct card_conf *info);
        int (*card_stop)(struct hw *hw);
        int (*pll_init)(struct hw *hw, unsigned int rsr);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        int (*suspend)(struct hw *hw);
        int (*resume)(struct hw *hw, struct card_conf *info);
 #endif
index dc1969bc67d4982d187cb095ad29d6f61b132607..4507f7088b24c1b69dba253a2968d3bfdc95d7da 100644 (file)
@@ -2085,7 +2085,7 @@ static int hw_card_init(struct hw *hw, struct card_conf *info)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int hw_suspend(struct hw *hw)
 {
        struct pci_dev *pci = hw->pci;
@@ -2180,7 +2180,7 @@ static struct hw ct20k1_preset __devinitdata = {
        .is_adc_source_selected = hw_is_adc_input_selected,
        .select_adc_source = hw_adc_input_select,
        .capabilities = hw_capabilities,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        .suspend = hw_suspend,
        .resume = hw_resume,
 #endif
index 9d1231dc4ae22d8a5041bd3722fd406f55d95a58..b9c9349058bcc9178242fc5680849eb6f074c07c 100644 (file)
@@ -2201,7 +2201,7 @@ static int hw_card_init(struct hw *hw, struct card_conf *info)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int hw_suspend(struct hw *hw)
 {
        struct pci_dev *pci = hw->pci;
@@ -2250,7 +2250,7 @@ static struct hw ct20k2_preset __devinitdata = {
        .output_switch_put = hw_output_switch_put,
        .mic_source_switch_get = hw_mic_source_switch_get,
        .mic_source_switch_put = hw_mic_source_switch_put,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        .suspend = hw_suspend,
        .resume = hw_resume,
 #endif
index 0cc13eeef8da7ee04125f32005393bdbe95df821..48fe0e39c2be273a95762698999dd4cf5508b019 100644 (file)
@@ -1118,7 +1118,7 @@ mixer_set_input_right(struct ct_mixer *mixer,
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int mixer_resume(struct ct_mixer *mixer)
 {
        int i, state;
@@ -1188,7 +1188,7 @@ int ct_mixer_create(struct ct_atc *atc, struct ct_mixer **rmixer)
        mixer->get_output_ports = mixer_get_output_ports;
        mixer->set_input_left = mixer_set_input_left;
        mixer->set_input_right = mixer_set_input_right;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        mixer->resume = mixer_resume;
 #endif
 
index b009e989e77ddcef32cc8451c8eb8b99102f67c0..be881c639fee536f46c3f605984facc37d6d0ebb 100644 (file)
@@ -56,7 +56,7 @@ struct ct_mixer {
                              enum MIXER_PORT_T type, struct rsc *rsc);
        int (*set_input_right)(struct ct_mixer *mixer,
                               enum MIXER_PORT_T type, struct rsc *rsc);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        int (*resume)(struct ct_mixer *mixer);
 #endif
 };
index 2c8622617c8c4cac7df6f01535cc97adc165c206..d021876901bb63ce48a7559c29043a7122a95c6d 100644 (file)
@@ -427,7 +427,7 @@ int ct_alsa_pcm_create(struct ct_atc *atc,
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG,
                        snd_dma_pci_data(atc->pci), 128*1024, 128*1024);
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        atc->pcms[device] = pcm;
 #endif
 
index e002183ef8b2a7f0c5cd8a542d58340020299beb..07c07d752fd8978fa040363b10329078c14a0fcf 100644 (file)
@@ -125,7 +125,7 @@ static void __devexit ct_card_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int ct_card_suspend(struct device *dev)
 {
        struct snd_card *card = dev_get_drvdata(dev);
index 0ff754f180d0e852e55c74b2454d1ca00dba21d6..abb0b86c41c942286c2897727e60ab466323d93f 100644 (file)
@@ -46,7 +46,7 @@ static int get_firmware(const struct firmware **fw_entry,
        int err;
        char name[30];
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        if (chip->fw_cache[fw_index]) {
                DE_ACT(("firmware requested: %s is cached\n", card_fw[fw_index].data));
                *fw_entry = chip->fw_cache[fw_index];
@@ -59,7 +59,7 @@ static int get_firmware(const struct firmware **fw_entry,
        err = request_firmware(fw_entry, name, pci_device(chip));
        if (err < 0)
                snd_printk(KERN_ERR "get_firmware(): Firmware not available (%d)\n", err);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        else
                chip->fw_cache[fw_index] = *fw_entry;
 #endif
@@ -70,7 +70,7 @@ static int get_firmware(const struct firmware **fw_entry,
 
 static void free_firmware(const struct firmware *fw_entry)
 {
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        DE_ACT(("firmware not released (kept in cache)\n"));
 #else
        release_firmware(fw_entry);
@@ -82,7 +82,7 @@ static void free_firmware(const struct firmware *fw_entry)
 
 static void free_firmware_cache(struct echoaudio *chip)
 {
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        int i;
 
        for (i = 0; i < 8 ; i++)
@@ -2203,7 +2203,7 @@ ctl_error:
 
 
 
-#if defined(CONFIG_PM)
+#if defined(CONFIG_PM_SLEEP)
 
 static int snd_echo_suspend(struct device *dev)
 {
@@ -2313,7 +2313,7 @@ static SIMPLE_DEV_PM_OPS(snd_echo_pm, snd_echo_suspend, snd_echo_resume);
 #define SND_ECHO_PM_OPS        &snd_echo_pm
 #else
 #define SND_ECHO_PM_OPS        NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 
 static void __devexit snd_echo_remove(struct pci_dev *pci)
index 1df974dcb5f4b9b37a7e1727645a3fcbec50d0d9..e158369f5faaa117d23d71878293a27d6a428f86 100644 (file)
@@ -449,7 +449,7 @@ struct echoaudio {
        volatile u32 __iomem *dsp_registers;    /* DSP's register base */
        u32 active_mask;                        /* Chs. active mask or
                                                 * punks out */
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        const struct firmware *fw_cache[8];     /* Cached firmwares */
 #endif
 
index ddac4e6d660d0116f27af2ebf4f70344b63b932d..b7c1875ba90ec2ad06518a1af310fd62d3f357cb 100644 (file)
@@ -206,7 +206,7 @@ static void __devexit snd_card_emu10k1_remove(struct pci_dev *pci)
 }
 
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int snd_emu10k1_suspend(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
@@ -268,7 +268,7 @@ static SIMPLE_DEV_PM_OPS(snd_emu10k1_pm, snd_emu10k1_suspend, snd_emu10k1_resume
 #define SND_EMU10K1_PM_OPS     &snd_emu10k1_pm
 #else
 #define SND_EMU10K1_PM_OPS     NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static struct pci_driver emu10k1_driver = {
        .name = KBUILD_MODNAME,
index 754924081d0ac99a4434c0e887faa1b69dc9f417..bed4485f34f61fa7b90cfaa6bc5a3da3b9e55150 100644 (file)
@@ -1241,7 +1241,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu)
  *  Create the EMU10K1 instance
  */
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int alloc_pm_buffer(struct snd_emu10k1 *emu);
 static void free_pm_buffer(struct snd_emu10k1 *emu);
 #endif
@@ -1275,7 +1275,7 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu)
                snd_dma_free_pages(&emu->ptb_pages);
        vfree(emu->page_ptr_table);
        vfree(emu->page_addr_table);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        free_pm_buffer(emu);
 #endif
        if (emu->port)
@@ -1971,7 +1971,7 @@ int __devinit snd_emu10k1_create(struct snd_card *card,
        err = snd_emu10k1_init(emu, enable_ir, 0);
        if (err < 0)
                goto error;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        err = alloc_pm_buffer(emu);
        if (err < 0)
                goto error;
@@ -2000,7 +2000,7 @@ int __devinit snd_emu10k1_create(struct snd_card *card,
        return err;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static unsigned char saved_regs[] = {
        CPF, PTRX, CVCF, VTFT, Z1, Z2, PSST, DSL, CCCA, CCR, CLP,
        FXRT, MAPA, MAPB, ENVVOL, ATKHLDV, DCYSUSV, LFOVAL1, ENVVAL,
index dae4050ede5cc96f4dd3b070da01b4bbebfff591..52419959178c6fcad09855b67b417537b70e226a 100644 (file)
@@ -2646,7 +2646,7 @@ int __devinit snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device, struct
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 int __devinit snd_emu10k1_efx_alloc_pm_buffer(struct snd_emu10k1 *emu)
 {
        int len;
index 4f502a2bdc3c51759ef26a4c4f80c858cc6192f9..0a436626182b9cc358def5a31f7a7daabf43c484 100644 (file)
@@ -326,7 +326,10 @@ snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *subst
        for (page = blk->first_page; page <= blk->last_page; page++, idx++) {
                unsigned long ofs = idx << PAGE_SHIFT;
                dma_addr_t addr;
-               addr = snd_pcm_sgbuf_get_addr(substream, ofs);
+               if (ofs >= runtime->dma_bytes)
+                       addr = emu->silent_page.addr;
+               else
+                       addr = snd_pcm_sgbuf_get_addr(substream, ofs);
                if (! is_valid_page(emu, addr)) {
                        printk(KERN_ERR "emu: failure page = %d\n", idx);
                        mutex_unlock(&hdr->block_mutex);
index a81dc44228eab97911ea0cde311014bafa4d2ee9..88cec6b7dd41244643a6df7b3b7d80e4fb5776ab 100644 (file)
@@ -893,7 +893,7 @@ int __devinit snd_p16v_mixer(struct snd_emu10k1 *emu)
         return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 
 #define NUM_CHS        1       /* up to 4, but only first channel is used */
 
index f7e6f73186e18a99a7e25b5e5d4c5639f3032af6..2ba58d3659591106e948b198a818963b31499861 100644 (file)
@@ -2032,7 +2032,7 @@ static void snd_ensoniq_chip_init(struct ensoniq *ensoniq)
        synchronize_irq(ensoniq->irq);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int snd_ensoniq_suspend(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
@@ -2094,7 +2094,7 @@ static SIMPLE_DEV_PM_OPS(snd_ensoniq_pm, snd_ensoniq_suspend, snd_ensoniq_resume
 #define SND_ENSONIQ_PM_OPS     &snd_ensoniq_pm
 #else
 #define SND_ENSONIQ_PM_OPS     NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static int __devinit snd_ensoniq_create(struct snd_card *card,
                                     struct pci_dev *pci,
index dbb81807bc1ae5cb6cba33b699dce20f97075e35..394c5d413530cd66fb5b1c1718d55f6b523ece13 100644 (file)
@@ -236,7 +236,7 @@ struct es1938 {
 #ifdef SUPPORT_JOYSTICK
        struct gameport *gameport;
 #endif
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        unsigned char saved_regs[SAVED_REG_SIZE];
 #endif
 };
@@ -1456,7 +1456,7 @@ static void snd_es1938_chip_init(struct es1938 *chip)
        outb(0, SLDM_REG(chip, DMACLEAR));
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*
  * PM support
  */
@@ -1536,7 +1536,7 @@ static SIMPLE_DEV_PM_OPS(es1938_pm, es1938_suspend, es1938_resume);
 #define ES1938_PM_OPS  &es1938_pm
 #else
 #define ES1938_PM_OPS  NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 #ifdef SUPPORT_JOYSTICK
 static int __devinit snd_es1938_create_gameport(struct es1938 *chip)
index fb4c90b99c003c4c673c00bc67c5442f058541d7..5d0e568fdea1b39e6a4c94f9c4fa360edffa5ede 100644 (file)
@@ -491,7 +491,7 @@ struct esschan {
        /* linked list */
        struct list_head list;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        u16 wc_map[4];
 #endif
 };
@@ -544,7 +544,7 @@ struct es1968 {
        struct list_head substream_list;
        spinlock_t substream_lock;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        u16 apu_map[NR_APUS][NR_APU_REGS];
 #endif
 
@@ -706,7 +706,7 @@ static void __apu_set_register(struct es1968 *chip, u16 channel, u8 reg, u16 dat
 {
        if (snd_BUG_ON(channel >= NR_APUS))
                return;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        chip->apu_map[channel][reg] = data;
 #endif
        reg |= (channel << 4);
@@ -993,7 +993,7 @@ static void snd_es1968_program_wavecache(struct es1968 *chip, struct esschan *es
        /* set the wavecache control reg */
        wave_set_register(chip, es->apu[channel] << 3, tmpval);
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        es->wc_map[channel] = tmpval;
 #endif
 }
@@ -2377,7 +2377,7 @@ static void snd_es1968_start_irq(struct es1968 *chip)
        outw(w, chip->io_port + ESM_PORT_HOST_IRQ);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*
  * PM support
  */
@@ -2461,7 +2461,7 @@ static SIMPLE_DEV_PM_OPS(es1968_pm, es1968_suspend, es1968_resume);
 #define ES1968_PM_OPS  &es1968_pm
 #else
 #define ES1968_PM_OPS  NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 #ifdef SUPPORT_JOYSTICK
 #define JOYSTICK_ADDR  0x200
index 522c8706f24446e5cb70f2522284d37d7ef14213..ce3e548de41da10012f6661cecb6089c698578d3 100644 (file)
@@ -205,7 +205,7 @@ struct fm801 {
        struct snd_tea575x tea;
 #endif
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        u16 saved_regs[0x20];
 #endif
 };
@@ -1361,7 +1361,7 @@ static void __devexit snd_card_fm801_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static unsigned char saved_regs[] = {
        FM801_PCM_VOL, FM801_I2S_VOL, FM801_FM_VOL, FM801_REC_SRC,
        FM801_PLY_CTRL, FM801_PLY_COUNT, FM801_PLY_BUF1, FM801_PLY_BUF2,
@@ -1421,7 +1421,7 @@ static SIMPLE_DEV_PM_OPS(snd_fm801_pm, snd_fm801_suspend, snd_fm801_resume);
 #define SND_FM801_PM_OPS       &snd_fm801_pm
 #else
 #define SND_FM801_PM_OPS       NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static struct pci_driver fm801_driver = {
        .name = KBUILD_MODNAME,
index 647218d69f6890862b5fcfd690dc9e09d29bc3ea..4f7d2dfcef7b16357ead4185b7b62e3463d5f1a5 100644 (file)
@@ -332,13 +332,12 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
        if (cfg->dig_outs)
                snd_printd("   dig-out=0x%x/0x%x\n",
                           cfg->dig_out_pins[0], cfg->dig_out_pins[1]);
-       snd_printd("   inputs:");
+       snd_printd("   inputs:\n");
        for (i = 0; i < cfg->num_inputs; i++) {
-               snd_printd(" %s=0x%x",
+               snd_printd("     %s=0x%x\n",
                            hda_get_autocfg_input_label(codec, cfg, i),
                            cfg->inputs[i].pin);
        }
-       snd_printd("\n");
        if (cfg->dig_in_pin)
                snd_printd("   dig-in=0x%x\n", cfg->dig_in_pin);
 
index 0bc2315b181dad0ec6ed7a33af9e0a0a636c3608..0849aac449f2043fe1df237c48773436b5aefe7d 100644 (file)
@@ -231,16 +231,22 @@ void snd_hda_detach_beep_device(struct hda_codec *codec)
 }
 EXPORT_SYMBOL_HDA(snd_hda_detach_beep_device);
 
+static bool ctl_has_mute(struct snd_kcontrol *kcontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       return query_amp_caps(codec, get_amp_nid(kcontrol),
+                             get_amp_direction(kcontrol)) & AC_AMPCAP_MUTE;
+}
+
 /* get/put callbacks for beep mute mixer switches */
 int snd_hda_mixer_amp_switch_get_beep(struct snd_kcontrol *kcontrol,
                                      struct snd_ctl_elem_value *ucontrol)
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct hda_beep *beep = codec->beep;
-       if (beep) {
+       if (beep && (!beep->enabled || !ctl_has_mute(kcontrol))) {
                ucontrol->value.integer.value[0] =
-                       ucontrol->value.integer.value[1] =
-                       beep->enabled;
+                       ucontrol->value.integer.value[1] = beep->enabled;
                return 0;
        }
        return snd_hda_mixer_amp_switch_get(kcontrol, ucontrol);
@@ -252,9 +258,20 @@ int snd_hda_mixer_amp_switch_put_beep(struct snd_kcontrol *kcontrol,
 {
        struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
        struct hda_beep *beep = codec->beep;
-       if (beep)
-               snd_hda_enable_beep_device(codec,
-                                          *ucontrol->value.integer.value);
+       if (beep) {
+               u8 chs = get_amp_channels(kcontrol);
+               int enable = 0;
+               long *valp = ucontrol->value.integer.value;
+               if (chs & 1) {
+                       enable |= *valp;
+                       valp++;
+               }
+               if (chs & 2)
+                       enable |= *valp;
+               snd_hda_enable_beep_device(codec, enable);
+       }
+       if (!ctl_has_mute(kcontrol))
+               return 0;
        return snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
 }
 EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_put_beep);
index 88a9c20eb7a29cbff43745f5a64afefefb52b76e..2f5d61a72ba7d1e0d303e79317436351a2085510 100644 (file)
@@ -3497,7 +3497,7 @@ static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec, hda_nid_t fg
 {
        int sup = snd_hda_param_read(codec, fg, AC_PAR_POWER_STATE);
 
-       if (sup < 0)
+       if (sup == -1)
                return false;
        if (sup & power_state)
                return true;
@@ -4184,7 +4184,7 @@ int snd_hda_codec_build_pcms(struct hda_codec *codec)
  *
  * This function returns 0 if successful, or a negative error code.
  */
-int __devinit snd_hda_build_pcms(struct hda_bus *bus)
+int snd_hda_build_pcms(struct hda_bus *bus)
 {
        struct hda_codec *codec;
 
index c422d330ca54fe018379e5b14b24dcd03a4e208e..d772c2521cd9014268a3d2a067c688058b860f1a 100644 (file)
@@ -386,6 +386,10 @@ enum {
 /* DIGITAL2 bits */
 #define AC_DIG2_CC                     (0x7f<<0)
 
+/* DIGITAL3 bits */
+#define AC_DIG3_ICT                    (0xf<<0)
+#define AC_DIG3_KAE                    (1<<7)
+
 /* Pin widget control - 8bit */
 #define AC_PINCTL_EPT                  (0x3<<0)
 #define AC_PINCTL_EPT_NATIVE           0
@@ -1072,7 +1076,7 @@ static inline void snd_hda_power_down(struct hda_codec *codec) {}
 /*
  * patch firmware
  */
-int snd_hda_load_patch(struct hda_bus *bus, const char *patch);
+int snd_hda_load_patch(struct hda_bus *bus, size_t size, const void *buf);
 #endif
 
 /*
index 6b2efb8cb1f9c6bded4e7d318467f8825be75903..b9a644ca03b34faee8940a6ebbfcc74bce40e9fc 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/mutex.h>
 #include <linux/ctype.h>
 #include <linux/string.h>
-#include <linux/firmware.h>
 #include <linux/export.h>
 #include <sound/core.h>
 #include "hda_codec.h"
@@ -747,18 +746,21 @@ static int parse_line_mode(char *buf, struct hda_bus *bus)
  *
  * the spaces at the beginning and the end of the line are stripped
  */
-static int get_line_from_fw(char *buf, int size, struct firmware *fw)
+static int get_line_from_fw(char *buf, int size, size_t *fw_size_p,
+                           const void **fw_data_p)
 {
        int len;
-       const char *p = fw->data;
-       while (isspace(*p) && fw->size) {
+       size_t fw_size = *fw_size_p;
+       const char *p = *fw_data_p;
+
+       while (isspace(*p) && fw_size) {
                p++;
-               fw->size--;
+               fw_size--;
        }
-       if (!fw->size)
+       if (!fw_size)
                return 0;
 
-       for (len = 0; len < fw->size; len++) {
+       for (len = 0; len < fw_size; len++) {
                if (!*p)
                        break;
                if (*p == '\n') {
@@ -770,8 +772,8 @@ static int get_line_from_fw(char *buf, int size, struct firmware *fw)
                        *buf++ = *p++;
        }
        *buf = 0;
-       fw->size -= len;
-       fw->data = p;
+       *fw_size_p = fw_size - len;
+       *fw_data_p = p;
        remove_trail_spaces(buf);
        return 1;
 }
@@ -779,29 +781,15 @@ static int get_line_from_fw(char *buf, int size, struct firmware *fw)
 /*
  * load a "patch" firmware file and parse it
  */
-int snd_hda_load_patch(struct hda_bus *bus, const char *patch)
+int snd_hda_load_patch(struct hda_bus *bus, size_t fw_size, const void *fw_buf)
 {
-       int err;
-       const struct firmware *fw;
-       struct firmware tmp;
        char buf[128];
        struct hda_codec *codec;
        int line_mode;
-       struct device *dev = bus->card->dev;
-
-       if (snd_BUG_ON(!dev))
-               return -ENODEV;
-       err = request_firmware(&fw, patch, dev);
-       if (err < 0) {
-               printk(KERN_ERR "hda-codec: Cannot load the patch '%s'\n",
-                      patch);
-               return err;
-       }
 
-       tmp = *fw;
        line_mode = LINE_MODE_NONE;
        codec = NULL;
-       while (get_line_from_fw(buf, sizeof(buf) - 1, &tmp)) {
+       while (get_line_from_fw(buf, sizeof(buf) - 1, &fw_size, &fw_buf)) {
                if (!*buf || *buf == '#' || *buf == '\n')
                        continue;
                if (*buf == '[')
@@ -810,7 +798,6 @@ int snd_hda_load_patch(struct hda_bus *bus, const char *patch)
                         (codec || !patch_items[line_mode].need_codec))
                        patch_items[line_mode].parser(buf, bus, &codec);
        }
-       release_firmware(fw);
        return 0;
 }
 EXPORT_SYMBOL_HDA(snd_hda_load_patch);
index c8aced182fd15738cf165505d532e24e89bcd906..933c2a1cbd8624555eb6c422b6b7074c362ba38b 100644 (file)
@@ -55,6 +55,7 @@
 #include <sound/initval.h>
 #include <linux/vgaarb.h>
 #include <linux/vga_switcheroo.h>
+#include <linux/firmware.h>
 #include "hda_codec.h"
 
 
@@ -151,6 +152,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6},"
                         "{Intel, CPT},"
                         "{Intel, PPT},"
                         "{Intel, LPT},"
+                        "{Intel, LPT_LP},"
                         "{Intel, HPT},"
                         "{Intel, PBG},"
                         "{Intel, SCH},"
@@ -470,6 +472,10 @@ struct azx {
        struct snd_dma_buffer rb;
        struct snd_dma_buffer posbuf;
 
+#ifdef CONFIG_SND_HDA_PATCH_LOADER
+       const struct firmware *fw;
+#endif
+
        /* flags */
        int position_fix[2]; /* for both playback/capture streams */
        int poll_count;
@@ -559,13 +565,17 @@ enum {
  * VGA-switcher support
  */
 #ifdef SUPPORT_VGA_SWITCHEROO
+#define use_vga_switcheroo(chip)       ((chip)->use_vga_switcheroo)
+#else
+#define use_vga_switcheroo(chip)       0
+#endif
+
+#if defined(SUPPORT_VGA_SWITCHEROO) || defined(CONFIG_SND_HDA_PATCH_LOADER)
 #define DELAYED_INIT_MARK
 #define DELAYED_INITDATA_MARK
-#define use_vga_switcheroo(chip)       ((chip)->use_vga_switcheroo)
 #else
 #define DELAYED_INIT_MARK      __devinit
 #define DELAYED_INITDATA_MARK  __devinitdata
-#define use_vga_switcheroo(chip)       0
 #endif
 
 static char *driver_short_names[] DELAYED_INITDATA_MARK = {
@@ -2400,11 +2410,10 @@ static void azx_power_notify(struct hda_bus *bus)
 }
 #endif /* CONFIG_SND_HDA_POWER_SAVE */
 
-#ifdef CONFIG_PM
+#if defined(CONFIG_PM_SLEEP) || defined(SUPPORT_VGA_SWITCHEROO)
 /*
  * power management
  */
-
 static int azx_suspend(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
@@ -2462,10 +2471,8 @@ static int azx_resume(struct device *dev)
 static SIMPLE_DEV_PM_OPS(azx_pm, azx_suspend, azx_resume);
 #define AZX_PM_OPS     &azx_pm
 #else
-#define azx_suspend(dev)
-#define azx_resume(dev)
 #define AZX_PM_OPS     NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP || SUPPORT_VGA_SWITCHEROO */
 
 
 /*
@@ -2639,6 +2646,10 @@ static int azx_free(struct azx *chip)
                pci_release_regions(chip->pci);
        pci_disable_device(chip->pci);
        kfree(chip->azx_dev);
+#ifdef CONFIG_SND_HDA_PATCH_LOADER
+       if (chip->fw)
+               release_firmware(chip->fw);
+#endif
        kfree(chip);
 
        return 0;
@@ -3146,12 +3157,40 @@ static void power_down_all_codecs(struct azx *chip)
 #endif
 }
 
+#ifdef CONFIG_SND_HDA_PATCH_LOADER
+/* callback from request_firmware_nowait() */
+static void azx_firmware_cb(const struct firmware *fw, void *context)
+{
+       struct snd_card *card = context;
+       struct azx *chip = card->private_data;
+       struct pci_dev *pci = chip->pci;
+
+       if (!fw) {
+               snd_printk(KERN_ERR SFX "Cannot load firmware, aborting\n");
+               goto error;
+       }
+
+       chip->fw = fw;
+       if (!chip->disabled) {
+               /* continue probing */
+               if (azx_probe_continue(chip))
+                       goto error;
+       }
+       return; /* OK */
+
+ error:
+       snd_card_free(card);
+       pci_set_drvdata(pci, NULL);
+}
+#endif
+
 static int __devinit azx_probe(struct pci_dev *pci,
                               const struct pci_device_id *pci_id)
 {
        static int dev;
        struct snd_card *card;
        struct azx *chip;
+       bool probe_now;
        int err;
 
        if (dev >= SNDRV_CARDS)
@@ -3167,15 +3206,28 @@ static int __devinit azx_probe(struct pci_dev *pci,
                return err;
        }
 
-       /* set this here since it's referred in snd_hda_load_patch() */
        snd_card_set_dev(card, &pci->dev);
 
        err = azx_create(card, pci, dev, pci_id->driver_data, &chip);
        if (err < 0)
                goto out_free;
        card->private_data = chip;
+       probe_now = !chip->disabled;
 
-       if (!chip->disabled) {
+#ifdef CONFIG_SND_HDA_PATCH_LOADER
+       if (patch[dev] && *patch[dev]) {
+               snd_printk(KERN_ERR SFX "Applying patch firmware '%s'\n",
+                          patch[dev]);
+               err = request_firmware_nowait(THIS_MODULE, true, patch[dev],
+                                             &pci->dev, GFP_KERNEL, card,
+                                             azx_firmware_cb);
+               if (err < 0)
+                       goto out_free;
+               probe_now = false; /* continued in azx_firmware_cb() */
+       }
+#endif /* CONFIG_SND_HDA_PATCH_LOADER */
+
+       if (probe_now) {
                err = azx_probe_continue(chip);
                if (err < 0)
                        goto out_free;
@@ -3205,12 +3257,13 @@ static int DELAYED_INIT_MARK azx_probe_continue(struct azx *chip)
        if (err < 0)
                goto out_free;
 #ifdef CONFIG_SND_HDA_PATCH_LOADER
-       if (patch[dev] && *patch[dev]) {
-               snd_printk(KERN_ERR SFX "Applying patch firmware '%s'\n",
-                          patch[dev]);
-               err = snd_hda_load_patch(chip->bus, patch[dev]);
+       if (chip->fw) {
+               err = snd_hda_load_patch(chip->bus, chip->fw->size,
+                                        chip->fw->data);
                if (err < 0)
                        goto out_free;
+               release_firmware(chip->fw); /* no longer needed */
+               chip->fw = NULL;
        }
 #endif
        if ((probe_only[dev] & 1) == 0) {
@@ -3270,6 +3323,14 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = {
        { PCI_DEVICE(0x8086, 0x8c20),
          .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
          AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_COMBO },
+       /* Lynx Point-LP */
+       { PCI_DEVICE(0x8086, 0x9c20),
+         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
+         AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_COMBO },
+       /* Lynx Point-LP */
+       { PCI_DEVICE(0x8086, 0x9c21),
+         .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP |
+         AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_COMBO },
        /* Haswell */
        { PCI_DEVICE(0x8086, 0x0c0c),
          .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP |
index 7e46258fc7002e24eeb1159e49b05d157a534995..045e5d32f5ded3d2e5b54f3f344e99a29ab09aac 100644 (file)
@@ -402,6 +402,9 @@ static void print_digital_conv(struct snd_info_buffer *buffer,
 {
        unsigned int digi1 = snd_hda_codec_read(codec, nid, 0,
                                                AC_VERB_GET_DIGI_CONVERT_1, 0);
+       unsigned char digi2 = digi1 >> 8;
+       unsigned char digi3 = digi1 >> 16;
+
        snd_iprintf(buffer, "  Digital:");
        if (digi1 & AC_DIG1_ENABLE)
                snd_iprintf(buffer, " Enabled");
@@ -412,16 +415,20 @@ static void print_digital_conv(struct snd_info_buffer *buffer,
        if (digi1 & AC_DIG1_EMPHASIS)
                snd_iprintf(buffer, " Preemphasis");
        if (digi1 & AC_DIG1_COPYRIGHT)
-               snd_iprintf(buffer, " Copyright");
+               snd_iprintf(buffer, " Non-Copyright");
        if (digi1 & AC_DIG1_NONAUDIO)
                snd_iprintf(buffer, " Non-Audio");
        if (digi1 & AC_DIG1_PROFESSIONAL)
                snd_iprintf(buffer, " Pro");
        if (digi1 & AC_DIG1_LEVEL)
                snd_iprintf(buffer, " GenLevel");
+       if (digi3 & AC_DIG3_KAE)
+               snd_iprintf(buffer, " KAE");
        snd_iprintf(buffer, "\n");
        snd_iprintf(buffer, "  Digital category: 0x%x\n",
-                   (digi1 >> 8) & AC_DIG2_CC);
+                   digi2 & AC_DIG2_CC);
+       snd_iprintf(buffer, "  IEC Coding Type: 0x%x\n",
+                       digi3 & AC_DIG3_ICT);
 }
 
 static const char *get_pwr_state(u32 state)
index 0208fa121e5aad0fa4c77f6d5a642aebb38417dd..21218853366d2562fcb92318b0886f7324c2250e 100644 (file)
@@ -4814,6 +4814,32 @@ static const struct snd_kcontrol_new ad1882_3stack_mixers[] = {
        { } /* end */
 };
 
+/* simple auto-mute control for AD1882 3-stack board */
+#define AD1882_HP_EVENT        0x01
+
+static void ad1882_3stack_automute(struct hda_codec *codec)
+{
+       bool mute = snd_hda_jack_detect(codec, 0x11);
+       snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+                           mute ? 0 : PIN_OUT);
+}
+
+static int ad1882_3stack_automute_init(struct hda_codec *codec)
+{
+       ad198x_init(codec);
+       ad1882_3stack_automute(codec);
+       return 0;
+}
+
+static void ad1882_3stack_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+       switch (res >> 26) {
+       case AD1882_HP_EVENT:
+               ad1882_3stack_automute(codec);
+               break;
+       }
+}
+
 static const struct snd_kcontrol_new ad1882_6stack_mixers[] = {
        HDA_CODEC_MUTE("Surround Playback Switch", 0x16, 0x0, HDA_OUTPUT),
        HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x24, 1, 0x0, HDA_OUTPUT),
@@ -4928,6 +4954,11 @@ static const struct hda_verb ad1882_init_verbs[] = {
        { } /* end */
 };
 
+static const struct hda_verb ad1882_3stack_automute_verbs[] = {
+       {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1882_HP_EVENT},
+       { } /* end */
+};
+
 #ifdef CONFIG_SND_HDA_POWER_SAVE
 static const struct hda_amp_list ad1882_loopbacks[] = {
        { 0x20, HDA_INPUT, 0 }, /* Front Mic */
@@ -4942,12 +4973,14 @@ static const struct hda_amp_list ad1882_loopbacks[] = {
 enum {
        AD1882_3STACK,
        AD1882_6STACK,
+       AD1882_3STACK_AUTOMUTE,
        AD1882_MODELS
 };
 
 static const char * const ad1882_models[AD1986A_MODELS] = {
        [AD1882_3STACK]         = "3stack",
        [AD1882_6STACK]         = "6stack",
+       [AD1882_3STACK_AUTOMUTE] = "3stack-automute",
 };
 
 
@@ -5002,6 +5035,7 @@ static int patch_ad1882(struct hda_codec *codec)
        switch (board_config) {
        default:
        case AD1882_3STACK:
+       case AD1882_3STACK_AUTOMUTE:
                spec->num_mixers = 3;
                spec->mixers[2] = ad1882_3stack_mixers;
                spec->channel_mode = ad1882_modes;
@@ -5009,6 +5043,12 @@ static int patch_ad1882(struct hda_codec *codec)
                spec->need_dac_fix = 1;
                spec->multiout.max_channels = 2;
                spec->multiout.num_dacs = 1;
+               if (board_config != AD1882_3STACK) {
+                       spec->init_verbs[spec->num_init_verbs++] =
+                               ad1882_3stack_automute_verbs;
+                       codec->patch_ops.unsol_event = ad1882_3stack_unsol_event;
+                       codec->patch_ops.init = ad1882_3stack_automute_init;
+               }
                break;
        case AD1882_6STACK:
                spec->num_mixers = 3;
index 14361184ae1e0e17ac2483dcac3c525289369f1f..5e22a8f43d2eebc288083142b355feffb61ffedb 100644 (file)
@@ -2967,12 +2967,10 @@ static const char * const cxt5066_models[CXT5066_MODELS] = {
 };
 
 static const struct snd_pci_quirk cxt5066_cfg_tbl[] = {
-       SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT5066_AUTO),
        SND_PCI_QUIRK_MASK(0x1025, 0xff00, 0x0400, "Acer", CXT5066_IDEAPAD),
        SND_PCI_QUIRK(0x1028, 0x02d8, "Dell Vostro", CXT5066_DELL_VOSTRO),
        SND_PCI_QUIRK(0x1028, 0x02f5, "Dell Vostro 320", CXT5066_IDEAPAD),
        SND_PCI_QUIRK(0x1028, 0x0401, "Dell Vostro 1014", CXT5066_DELL_VOSTRO),
-       SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTRO),
        SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD),
        SND_PCI_QUIRK(0x1028, 0x050f, "Dell Inspiron", CXT5066_IDEAPAD),
        SND_PCI_QUIRK(0x1028, 0x0510, "Dell Vostro", CXT5066_IDEAPAD),
@@ -2988,14 +2986,10 @@ static const struct snd_pci_quirk cxt5066_cfg_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD),
        SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD),
        SND_PCI_QUIRK(0x17aa, 0x21c6, "Thinkpad Edge 13", CXT5066_ASUS),
-       SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T510", CXT5066_AUTO),
-       SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520 & W520", CXT5066_AUTO),
        SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT5066_THINKPAD),
        SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT5066_THINKPAD),
        SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo U350", CXT5066_ASUS),
        SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G560", CXT5066_ASUS),
-       SND_PCI_QUIRK(0x17aa, 0x3938, "Lenovo G565", CXT5066_AUTO),
-       SND_PCI_QUIRK(0x1b0a, 0x2092, "CyberpowerPC Gamer Xplorer N57001", CXT5066_AUTO),
        {}
 };
 
index 69b928449789e22afcaef39a67dea3323bc5e5e7..8f23374fa6427198735f91b987656986052a8773 100644 (file)
@@ -877,8 +877,6 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
        struct hdmi_eld *eld;
        struct hdmi_spec_per_cvt *per_cvt = NULL;
 
-       hinfo->nid = 0; /* clear the leftover value */
-
        /* Validate hinfo */
        pin_idx = hinfo_to_pin_index(spec, hinfo);
        if (snd_BUG_ON(pin_idx < 0))
@@ -1163,6 +1161,14 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
        return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format);
 }
 
+static int generic_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                                            struct hda_codec *codec,
+                                            struct snd_pcm_substream *substream)
+{
+       snd_hda_codec_cleanup_stream(codec, hinfo->nid);
+       return 0;
+}
+
 static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
                          struct hda_codec *codec,
                          struct snd_pcm_substream *substream)
@@ -1202,6 +1208,7 @@ static const struct hda_pcm_ops generic_ops = {
        .open = hdmi_pcm_open,
        .close = hdmi_pcm_close,
        .prepare = generic_hdmi_playback_pcm_prepare,
+       .cleanup = generic_hdmi_playback_pcm_cleanup,
 };
 
 static int generic_hdmi_build_pcms(struct hda_codec *codec)
@@ -1220,7 +1227,6 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec)
                pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
                pstr->substreams = 1;
                pstr->ops = generic_ops;
-               pstr->nid = 1; /* FIXME: just for avoiding a debug WARNING */
                /* other pstr fields are set in open */
        }
 
index 344b221d2102ffd9d4568961d7a0d2b5f8490e2a..4f81dd44c837e1de6b1de327f457bcb0fcc8f16f 100644 (file)
@@ -6099,6 +6099,8 @@ static const struct alc_fixup alc269_fixups[] = {
        [ALC269_FIXUP_PCM_44K] = {
                .type = ALC_FIXUP_FUNC,
                .v.func = alc269_fixup_pcm_44k,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_QUANTA_MUTE
        },
        [ALC269_FIXUP_STEREO_DMIC] = {
                .type = ALC_FIXUP_FUNC,
@@ -6206,9 +6208,11 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
        SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE),
        SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE),
+       SND_PCI_QUIRK(0x17aa, 0x21f6, "Thinkpad T530", ALC269_FIXUP_LENOVO_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x21fa, "Thinkpad X230", ALC269_FIXUP_LENOVO_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x21fb, "Thinkpad T430s", ALC269_FIXUP_LENOVO_DOCK),
        SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK),
-       SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_QUANTA_MUTE),
-       SND_PCI_QUIRK(0x17aa, 0x3bf8, "Lenovo Ideapd", ALC269_FIXUP_PCM_44K),
+       SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
        SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
 
 #if 0
index 94040ccf8e8fbd954833a6302ed37ab60a34f1ed..ea5775a1a7db292e25dd7956b8ac502d1a9db33e 100644 (file)
@@ -4272,7 +4272,8 @@ static int stac92xx_init(struct hda_codec *codec)
        unsigned int gpio;
        int i;
 
-       snd_hda_sequence_write(codec, spec->init);
+       if (spec->init)
+               snd_hda_sequence_write(codec, spec->init);
 
        /* power down adcs initially */
        if (spec->powerdown_adcs)
@@ -5748,7 +5749,6 @@ again:
                /* fallthru */
        case 0x111d76b4: /* 6 Port without Analog Mixer */
        case 0x111d76b5:
-               spec->init = stac92hd71bxx_core_init;
                codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
                spec->num_dmics = stac92xx_connected_ports(codec,
                                        stac92hd71bxx_dmic_nids,
@@ -5773,7 +5773,6 @@ again:
                        spec->stream_delay = 40; /* 40 milliseconds */
 
                /* disable VSW */
-               spec->init = stac92hd71bxx_core_init;
                unmute_init++;
                snd_hda_codec_set_pincfg(codec, 0x0f, 0x40f000f0);
                snd_hda_codec_set_pincfg(codec, 0x19, 0x40f000f3);
@@ -5788,7 +5787,6 @@ again:
 
                /* fallthru */
        default:
-               spec->init = stac92hd71bxx_core_init;
                codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs;
                spec->num_dmics = stac92xx_connected_ports(codec,
                                        stac92hd71bxx_dmic_nids,
@@ -5796,6 +5794,9 @@ again:
                break;
        }
 
+       if (get_wcaps_type(get_wcaps(codec, 0x28)) == AC_WID_VOL_KNB)
+               spec->init = stac92hd71bxx_core_init;
+
        if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP)
                snd_hda_sequence_write_cache(codec, unmute_init);
 
index 80d90cb42853bd50abfac7349361142e71185a7c..43077177691588ab03590cd0576369c54b55d266 100644 (file)
@@ -1752,6 +1752,14 @@ static int via_suspend(struct hda_codec *codec)
 {
        struct via_spec *spec = codec->spec;
        vt1708_stop_hp_work(spec);
+
+       if (spec->codec_type == VT1802) {
+               /* Fix pop noise on headphones */
+               int i;
+               for (i = 0; i < spec->autocfg.hp_outs; i++)
+                       snd_hda_set_pin_ctl(codec, spec->autocfg.hp_pins[i], 0);
+       }
+
        return 0;
 }
 #endif
index 3e4f8c12ffceeb7d48b117c50ebce743d408e243..20bcddea2eab19320d25299180368a815bc4f90f 100644 (file)
@@ -2103,7 +2103,7 @@ static int aureon_reset(struct snd_ice1712 *ice)
 /*
  * suspend/resume
  */
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int aureon_resume(struct snd_ice1712 *ice)
 {
        struct aureon_spec *spec = ice->spec;
@@ -2160,7 +2160,7 @@ static int __devinit aureon_init(struct snd_ice1712 *ice)
                wm_set_vol(ice, i, spec->vol[i], spec->master[i % 2]);
        }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        ice->pm_resume = aureon_resume;
        ice->pm_suspend_enabled = 1;
 #endif
index 0da778a69ef8b47d9bc1af83791561e04b6d1069..d0e7d87f09f0ed4947462630906ec02249e583c6 100644 (file)
@@ -384,7 +384,7 @@ struct snd_ice1712 {
        char **ext_clock_names;
        int ext_clock_count;
        void (*pro_open)(struct snd_ice1712 *, struct snd_pcm_substream *);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        int (*pm_suspend)(struct snd_ice1712 *);
        int (*pm_resume)(struct snd_ice1712 *);
        unsigned int pm_suspend_enabled:1;
index bed9f34f4efee6b9556dbe23cf675242cbf7c0b4..3050a52792532ad3a58303f54a800dcc7c0ab883 100644 (file)
@@ -2792,7 +2792,7 @@ static void __devexit snd_vt1724_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int snd_vt1724_suspend(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
@@ -2878,7 +2878,7 @@ static SIMPLE_DEV_PM_OPS(snd_vt1724_pm, snd_vt1724_suspend, snd_vt1724_resume);
 #define SND_VT1724_PM_OPS      &snd_vt1724_pm
 #else
 #define SND_VT1724_PM_OPS      NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static struct pci_driver vt1724_driver = {
        .name = KBUILD_MODNAME,
index 98bc3b7681b5615f97d8e55f0a6fc947951382f0..14fd536b6452d6e5dda1ec01f12929a89c4cd7c0 100644 (file)
@@ -486,7 +486,7 @@ static int __devinit juli_add_controls(struct snd_ice1712 *ice)
  * suspend/resume
  * */
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int juli_resume(struct snd_ice1712 *ice)
 {
        struct snd_akm4xxx *ak = ice->akm;
@@ -652,7 +652,7 @@ static int __devinit juli_init(struct snd_ice1712 *ice)
 
        ice->spdif.ops.open = juli_spdif_in_open;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        ice->pm_resume = juli_resume;
        ice->pm_suspend = juli_suspend;
        ice->pm_suspend_enabled = 1;
index 764cc93dbca402f6372b6f73a0854470f3046f73..7f2b63f97e61b4b182efb140fcb4ddee426f72cd 100644 (file)
@@ -1099,7 +1099,7 @@ static void ak4396_init(struct snd_ice1712 *ice)
                ak4396_write(ice, ak4396_inits[i], ak4396_inits[i+1]);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int prodigy_hd2_resume(struct snd_ice1712 *ice)
 {
        /* initialize ak4396 codec and restore previous mixer volumes */
@@ -1140,7 +1140,7 @@ static int __devinit prodigy_hd2_init(struct snd_ice1712 *ice)
                return -ENOMEM;
        ice->spec = spec;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        ice->pm_resume = &prodigy_hd2_resume;
        ice->pm_suspend_enabled = 1;
 #endif
index cd553f592e2d12643558958b14693ccd87a6ac07..5c4115289a9a1c15f56e20e1e5345cdfe6f04b7b 100644 (file)
@@ -2620,7 +2620,7 @@ static int snd_intel8x0_free(struct intel8x0 *chip)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*
  * power management
  */
@@ -2741,7 +2741,7 @@ static SIMPLE_DEV_PM_OPS(intel8x0_pm, intel8x0_suspend, intel8x0_resume);
 #define INTEL8X0_PM_OPS        &intel8x0_pm
 #else
 #define INTEL8X0_PM_OPS        NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 #define INTEL8X0_TESTBUF_SIZE  32768   /* enough large for one shot */
 
index da44bb3f8e7aaf1c8c7ca35278d27c275010365c..4d551736531eebe546e4620768907e6775840ab2 100644 (file)
@@ -1008,7 +1008,7 @@ static int snd_intel8x0m_free(struct intel8x0m *chip)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*
  * power management
  */
@@ -1067,7 +1067,7 @@ static SIMPLE_DEV_PM_OPS(intel8x0m_pm, intel8x0m_suspend, intel8x0m_resume);
 #define INTEL8X0M_PM_OPS       &intel8x0m_pm
 #else
 #define INTEL8X0M_PM_OPS       NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 #ifdef CONFIG_PROC_FS
 static void snd_intel8x0m_proc_read(struct snd_info_entry * entry,
index d1ab43706735fb42d12cc8514b48b9add557b5c2..5579b08bb35b6337c646b6d2cb6be5215f0d01d9 100644 (file)
@@ -851,6 +851,8 @@ static int __devinit lx_pcm_create(struct lx6464es *chip)
        /* hardcoded device name & channel count */
        err = snd_pcm_new(chip->card, (char *)card_name, 0,
                          1, 1, &pcm);
+       if (err < 0)
+               return err;
 
        pcm->private_data = chip;
 
index c85d1ffcc9558b5f64ed4e9aaea1963b7c8597c2..eb3cd3a4315eff8990b7f2d7162a6aaa640d35e6 100644 (file)
@@ -789,7 +789,7 @@ struct snd_m3 {
 
        unsigned int in_suspend;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        u16 *suspend_mem;
 #endif
 
@@ -2368,7 +2368,7 @@ static int snd_m3_free(struct snd_m3 *chip)
                outw(0, chip->iobase + HOST_INT_CTRL); /* disable ints */
        }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        vfree(chip->suspend_mem);
 #endif
 
@@ -2390,7 +2390,7 @@ static int snd_m3_free(struct snd_m3 *chip)
 /*
  * APM support
  */
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int m3_suspend(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
@@ -2485,7 +2485,7 @@ static SIMPLE_DEV_PM_OPS(m3_pm, m3_suspend, m3_resume);
 #define M3_PM_OPS      &m3_pm
 #else
 #define M3_PM_OPS      NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 #ifdef CONFIG_SND_MAESTRO3_INPUT
 static int __devinit snd_m3_input_register(struct snd_m3 *chip)
@@ -2656,7 +2656,7 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
        }
        chip->irq = pci->irq;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        chip->suspend_mem = vmalloc(sizeof(u16) * (REV_B_CODE_MEMORY_LENGTH + REV_B_DATA_MEMORY_LENGTH));
        if (chip->suspend_mem == NULL)
                snd_printk(KERN_WARNING "can't allocate apm buffer\n");
index 465cff25b14622738f1e16d423fc6b579c32d0ad..e80e9a1e84aa4b8cd6ccfaf12abe49de0b063343 100644 (file)
@@ -1377,7 +1377,7 @@ snd_nm256_peek_for_sig(struct nm256 *chip)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*
  * APM event handler, so the card is properly reinitialized after a power
  * event.
@@ -1441,7 +1441,7 @@ static SIMPLE_DEV_PM_OPS(nm256_pm, nm256_suspend, nm256_resume);
 #define NM256_PM_OPS   &nm256_pm
 #else
 #define NM256_PM_OPS   NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static int snd_nm256_free(struct nm256 *chip)
 {
index 37520a2b4dcf29c8f7cf7e869d74aed2ad74b36c..2becae155a48d2f0c49bcb999194bc61a469e139 100644 (file)
@@ -872,7 +872,7 @@ static struct pci_driver oxygen_driver = {
        .id_table = oxygen_ids,
        .probe = generic_oxygen_probe,
        .remove = __devexit_p(oxygen_pci_remove),
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        .driver = {
                .pm = &oxygen_pci_pm,
        },
index 7112a89fb8bd0ba32319dc4fc458248605455d31..09a24b24958bedfa8797f52680e977c289dfb117 100644 (file)
@@ -161,7 +161,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id,
                                     )
                    );
 void oxygen_pci_remove(struct pci_dev *pci);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 extern const struct dev_pm_ops oxygen_pci_pm;
 #endif
 void oxygen_pci_shutdown(struct pci_dev *pci);
index ab8738e21ad1378d569e349244d6e7bc6fac270c..25697584b94c693b8f5ec69e726fa0c0c3bf2da8 100644 (file)
@@ -726,7 +726,7 @@ void oxygen_pci_remove(struct pci_dev *pci)
 }
 EXPORT_SYMBOL(oxygen_pci_remove);
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int oxygen_pci_suspend(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
@@ -824,7 +824,7 @@ static int oxygen_pci_resume(struct device *dev)
 
 SIMPLE_DEV_PM_OPS(oxygen_pci_pm, oxygen_pci_suspend, oxygen_pci_resume);
 EXPORT_SYMBOL(oxygen_pci_pm);
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 void oxygen_pci_shutdown(struct pci_dev *pci)
 {
index d3b606b69f3bf38864a16e6a1d77c5813d844d59..3d71423b23bcf5450b2926c5b900fa76a91a8559 100644 (file)
@@ -93,7 +93,7 @@ static struct pci_driver xonar_driver = {
        .id_table = xonar_ids,
        .probe = xonar_probe,
        .remove = __devexit_p(oxygen_pci_remove),
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        .driver = {
                .pm = &oxygen_pci_pm,
        },
index 760ee467cd9aac9e8969d6c8cb2f03a94c6f1d3d..7d291542c5baba8803cbc3fddae2d33121e2f3d0 100644 (file)
@@ -464,7 +464,7 @@ struct snd_riptide {
 
        unsigned long received_irqs;
        unsigned long handled_irqs;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        int in_suspend;
 #endif
 };
@@ -1150,7 +1150,7 @@ static void riptide_handleirq(unsigned long dev_id)
        }
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int riptide_suspend(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
@@ -1193,7 +1193,7 @@ static SIMPLE_DEV_PM_OPS(riptide_pm, riptide_suspend, riptide_resume);
 #define RIPTIDE_PM_OPS &riptide_pm
 #else
 #define RIPTIDE_PM_OPS NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static int try_to_load_firmware(struct cmdif *cif, struct snd_riptide *chip)
 {
index 512434efcc31136f1570ab5e17429523a354f187..535efe295075a014c8641c083b0bd30fd268dab0 100644 (file)
@@ -103,7 +103,7 @@ struct voice {
  * we're not doing power management, we still need to allocate a page
  * for the silence buffer.
  */
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 #define SIS_SUSPEND_PAGES      4
 #else
 #define SIS_SUSPEND_PAGES      1
@@ -1208,7 +1208,7 @@ static int sis_chip_init(struct sis7019 *sis)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int sis_suspend(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
@@ -1305,7 +1305,7 @@ static SIMPLE_DEV_PM_OPS(sis_pm, sis_suspend, sis_resume);
 #define SIS_PM_OPS     &sis_pm
 #else
 #define SIS_PM_OPS     NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static int sis_alloc_suspend(struct sis7019 *sis)
 {
index d36e6ca147e18932fd63afbe1c273e936234ecc3..8a6f1f76e8709508cb186a4957ad2776e2865392 100644 (file)
@@ -177,7 +177,7 @@ static struct pci_driver trident_driver = {
        .id_table = snd_trident_ids,
        .probe = snd_trident_probe,
        .remove = __devexit_p(snd_trident_remove),
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        .driver = {
                .pm = &snd_trident_pm,
        },
index 94011dcae7312e4e48f6e75a0b8d59f73e92b572..06b10d1a76e56c3593e09f704ba5efb3b6688577 100644 (file)
@@ -3919,7 +3919,7 @@ static void snd_trident_clear_voices(struct snd_trident * trident, unsigned shor
        }
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int snd_trident_suspend(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
@@ -3983,4 +3983,4 @@ static int snd_trident_resume(struct device *dev)
 }
 
 SIMPLE_DEV_PM_OPS(snd_trident_pm, snd_trident_suspend, snd_trident_resume);
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
index 0eb7245dd362de2445d383f343d904ac3f04edb1..e3d32e2d574e9021368e449b46db8b6674762cd8 100644 (file)
@@ -362,7 +362,7 @@ struct via82xx {
 
        unsigned char old_legacy;
        unsigned char old_legacy_cfg;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        unsigned char legacy_saved;
        unsigned char legacy_cfg_saved;
        unsigned char spdif_ctrl_saved;
@@ -2038,7 +2038,7 @@ static int __devinit snd_via686_init_misc(struct via82xx *chip)
                if (mpu_port >= 0x200) {        /* force MIDI */
                        mpu_port &= 0xfffc;
                        pci_write_config_dword(chip->pci, 0x18, mpu_port | 0x01);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
                        chip->mpu_port_saved = mpu_port;
 #endif
                } else {
@@ -2090,7 +2090,7 @@ static int __devinit snd_via686_init_misc(struct via82xx *chip)
 
        snd_via686_create_gameport(chip, &legacy);
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        chip->legacy_saved = legacy;
        chip->legacy_cfg_saved = legacy_cfg;
 #endif
@@ -2238,7 +2238,7 @@ static int snd_via82xx_chip_init(struct via82xx *chip)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*
  * power management
  */
@@ -2313,7 +2313,7 @@ static SIMPLE_DEV_PM_OPS(snd_via82xx_pm, snd_via82xx_suspend, snd_via82xx_resume
 #define SND_VIA82XX_PM_OPS     &snd_via82xx_pm
 #else
 #define SND_VIA82XX_PM_OPS     NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static int snd_via82xx_free(struct via82xx *chip)
 {
index e886bc16999db91d6882d82cdc0b96580a36d9c3..8e0efc416f22f74bd68ba1f1fa89565073ee2bb0 100644 (file)
@@ -1019,7 +1019,7 @@ static int snd_via82xx_chip_init(struct via82xx_modem *chip)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 /*
  * power management
  */
@@ -1076,7 +1076,7 @@ static SIMPLE_DEV_PM_OPS(snd_via82xx_pm, snd_via82xx_suspend, snd_via82xx_resume
 #define SND_VIA82XX_PM_OPS     &snd_via82xx_pm
 #else
 #define SND_VIA82XX_PM_OPS     NULL
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 static int snd_via82xx_free(struct via82xx_modem *chip)
 {
index b89e7a86e9d8f809bdee1306b7fb92ac0d2bcffd..fdfbaf8572336ddd31648a127d668701d60b0a28 100644 (file)
@@ -257,7 +257,7 @@ static void __devexit snd_vx222_remove(struct pci_dev *pci)
        pci_set_drvdata(pci, NULL);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int snd_vx222_suspend(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
index 4810356b97ba0997379aa2a45711087d789f5cf9..e01fe34db9eca55ec0feb02082b5f25b87917b62 100644 (file)
@@ -355,7 +355,7 @@ static struct pci_driver ymfpci_driver = {
        .id_table = snd_ymfpci_ids,
        .probe = snd_card_ymfpci_probe,
        .remove = __devexit_p(snd_card_ymfpci_remove),
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        .driver = {
                .pm = &snd_ymfpci_pm,
        },
index bddc4052286be3e7c9433b5195765a43bcf27669..4631a23489151f8631e878e4a98fe31b51ab066b 100644 (file)
@@ -363,7 +363,7 @@ struct snd_ymfpci {
        const struct firmware *dsp_microcode;
        const struct firmware *controller_microcode;
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        u32 *saved_regs;
        u32 saved_ydsxgr_mode;
        u16 saved_dsxg_legacy;
index 62b23635b7543b651e979e5628c1ec631b53df6d..ee8b6366e48d1c2d5a50dc3e2fc8487378a005f6 100644 (file)
@@ -2242,7 +2242,7 @@ static int snd_ymfpci_free(struct snd_ymfpci *chip)
        pci_set_power_state(chip->pci, 3);
 #endif
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        vfree(chip->saved_regs);
 #endif
        if (chip->irq >= 0)
@@ -2272,7 +2272,7 @@ static int snd_ymfpci_dev_free(struct snd_device *device)
        return snd_ymfpci_free(chip);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int saved_regs_index[] = {
        /* spdif */
        YDSXGR_SPDIFOUTCTRL,
@@ -2374,7 +2374,7 @@ static int snd_ymfpci_resume(struct device *dev)
 }
 
 SIMPLE_DEV_PM_OPS(snd_ymfpci_pm, snd_ymfpci_suspend, snd_ymfpci_resume);
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
 
 int __devinit snd_ymfpci_create(struct snd_card *card,
                                struct pci_dev * pci,
@@ -2452,7 +2452,7 @@ int __devinit snd_ymfpci_create(struct snd_card *card,
                return err;
        }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        chip->saved_regs = vmalloc(YDSXGR_NUM_SAVED_REGS * sizeof(u32));
        if (chip->saved_regs == NULL) {
                snd_ymfpci_free(chip);
index f5ceb6f282decab0e89e4b8c5637c0520efde7d9..210cafe0489020ea970ac2724a68797a5be23a6e 100644 (file)
@@ -143,7 +143,7 @@ static int __devexit snd_pmac_remove(struct platform_device *devptr)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int snd_pmac_driver_suspend(struct device *dev)
 {
        struct snd_card *card = dev_get_drvdata(dev);
index 318c5ba5360f6dfb3e9184aa9f169ad0f23aa3a4..dfb744381c42cb2288b7bb7325fdb04b04338b82 100644 (file)
@@ -413,7 +413,14 @@ EXPORT_SYMBOL(sport_create);
 
 void sport_delete(struct sport_device *sport)
 {
+       if (sport->tx_desc)
+               dma_free_coherent(NULL, sport->tx_desc_size,
+                               sport->tx_desc, 0);
+       if (sport->rx_desc)
+               dma_free_coherent(NULL, sport->rx_desc_size,
+                               sport->rx_desc, 0);
        sport_free_resource(sport);
+       kfree(sport);
 }
 EXPORT_SYMBOL(sport_delete);
 
index 3c795921c5f6b840f6654d53907ed44e18435841..b7836503dc69507473c45cc3c68ac55ec9b0f758 100644 (file)
@@ -2404,8 +2404,12 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec)
 
        dev_dbg(dev, "%s: Enter.\n", __func__);
 
+       /* Inform SoC Core that we have our own I/O arrangements. */
+       codec->control_data = (void *)true;
+
        /* Setup AB8500 according to board-settings */
-       pdata = (struct ab8500_platform_data *)dev_get_platdata(dev->parent);
+       pdata = dev_get_platdata(dev->parent);
+
        status = ab8500_audio_setup_mics(codec, &pdata->codec->amics);
        if (status < 0) {
                pr_err("%s: Failed to setup mics (%d)!\n", __func__, status);
index 8c39dddd7d0063d90adcf587c5e6dc19c37f73ad..11b1b714b8b5e106ad7784258ca4caa4a4939e9e 100644 (file)
@@ -186,6 +186,7 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec)
 
        printk(KERN_INFO "AD1980 SoC Audio Codec\n");
 
+       codec->control_data = codec;    /* we don't use regmap! */
        ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
        if (ret < 0) {
                printk(KERN_ERR "ad1980: failed to register AC97 codec\n");
index 44f59064d8de11247187a8d124661361e7913e65..704544bfc90dc564c774593ee7d0300098c47d6c 100644 (file)
@@ -1392,17 +1392,7 @@ static struct i2c_driver adau1373_i2c_driver = {
        .id_table = adau1373_i2c_id,
 };
 
-static int __init adau1373_init(void)
-{
-       return i2c_add_driver(&adau1373_i2c_driver);
-}
-module_init(adau1373_init);
-
-static void __exit adau1373_exit(void)
-{
-       i2c_del_driver(&adau1373_i2c_driver);
-}
-module_exit(adau1373_exit);
+module_i2c_driver(adau1373_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC ADAU1373 driver");
 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
index 3d50fc8646b672fd87eb82c21abb72b4699ec368..51f2f3cd81364658d0b78d48c7baddb7cac5abd2 100644 (file)
@@ -527,17 +527,7 @@ static struct i2c_driver adau1701_i2c_driver = {
        .id_table       = adau1701_i2c_id,
 };
 
-static int __init adau1701_init(void)
-{
-       return i2c_add_driver(&adau1701_i2c_driver);
-}
-module_init(adau1701_init);
-
-static void __exit adau1701_exit(void)
-{
-       i2c_del_driver(&adau1701_i2c_driver);
-}
-module_exit(adau1701_exit);
+module_i2c_driver(adau1701_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC ADAU1701 SigmaDSP driver");
 MODULE_AUTHOR("Cliff Cai <cliff.cai@analog.com>");
index 5fb7c2a80e6daa5e8e68948a09b95a852fba778e..2b457976a7bff0f18ada9248acdc0c25b4bd82cd 100644 (file)
@@ -696,17 +696,7 @@ static struct i2c_driver ak4671_i2c_driver = {
        .id_table = ak4671_i2c_id,
 };
 
-static int __init ak4671_modinit(void)
-{
-       return i2c_add_driver(&ak4671_i2c_driver);
-}
-module_init(ak4671_modinit);
-
-static void __exit ak4671_exit(void)
-{
-       i2c_del_driver(&ak4671_i2c_driver);
-}
-module_exit(ak4671_exit);
+module_i2c_driver(ak4671_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC AK4671 codec driver");
 MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
index 5c9cacaf2d525cddabffd0b416c0695dfadaab99..5e96a0a1669cb46c8b8d7a55101be1c3f3ea8146 100644 (file)
@@ -229,6 +229,69 @@ int arizona_out_ev(struct snd_soc_dapm_widget *w,
 }
 EXPORT_SYMBOL_GPL(arizona_out_ev);
 
+static unsigned int arizona_sysclk_48k_rates[] = {
+       6144000,
+       12288000,
+       22579200,
+       49152000,
+};
+
+static unsigned int arizona_sysclk_44k1_rates[] = {
+       5644800,
+       11289600,
+       24576000,
+       45158400,
+};
+
+static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
+                            unsigned int freq)
+{
+       struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec);
+       unsigned int reg;
+       unsigned int *rates;
+       int ref, div, refclk;
+
+       switch (clk) {
+       case ARIZONA_CLK_OPCLK:
+               reg = ARIZONA_OUTPUT_SYSTEM_CLOCK;
+               refclk = priv->sysclk;
+               break;
+       case ARIZONA_CLK_ASYNC_OPCLK:
+               reg = ARIZONA_OUTPUT_ASYNC_CLOCK;
+               refclk = priv->asyncclk;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (refclk % 8000)
+               rates = arizona_sysclk_44k1_rates;
+       else
+               rates = arizona_sysclk_48k_rates;
+
+       for (ref = 0; ref < ARRAY_SIZE(arizona_sysclk_48k_rates) &&
+                    rates[ref] <= refclk; ref++) {
+               div = 1;
+               while (rates[ref] / div >= freq && div < 32) {
+                       if (rates[ref] / div == freq) {
+                               dev_dbg(codec->dev, "Configured %dHz OPCLK\n",
+                                       freq);
+                               snd_soc_update_bits(codec, reg,
+                                                   ARIZONA_OPCLK_DIV_MASK |
+                                                   ARIZONA_OPCLK_SEL_MASK,
+                                                   (div <<
+                                                    ARIZONA_OPCLK_DIV_SHIFT) |
+                                                   ref);
+                               return 0;
+                       }
+                       div++;
+               }
+       }
+
+       dev_err(codec->dev, "Unable to generate %dHz OPCLK\n", freq);
+       return -EINVAL;
+}
+
 int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
                       int source, unsigned int freq, int dir)
 {
@@ -252,6 +315,9 @@ int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id,
                reg = ARIZONA_ASYNC_CLOCK_1;
                clk = &priv->asyncclk;
                break;
+       case ARIZONA_CLK_OPCLK:
+       case ARIZONA_CLK_ASYNC_OPCLK:
+               return arizona_set_opclk(codec, clk_id, freq);
        default:
                return -EINVAL;
        }
index 59caca8865e8aa355c279dd257cf836d667627aa..eb66b52777c9e82ad478a39bd3bb2936971feaa1 100644 (file)
 
 #include <sound/soc.h>
 
-#define ARIZONA_CLK_SYSCLK   1
-#define ARIZONA_CLK_ASYNCCLK 2
+#define ARIZONA_CLK_SYSCLK         1
+#define ARIZONA_CLK_ASYNCCLK       2
+#define ARIZONA_CLK_OPCLK          3
+#define ARIZONA_CLK_ASYNC_OPCLK    4
 
 #define ARIZONA_CLK_SRC_MCLK1    0x0
 #define ARIZONA_CLK_SRC_MCLK2    0x1
index 047917f0b8aef6c54d82f618db30b706fe72636f..44a176f741700188398dd4778eeb4873e0e0af23 100644 (file)
@@ -29,6 +29,8 @@
 #include <linux/i2c.h>
 #include <linux/delay.h>
 #include <linux/regulator/consumer.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
 
 /*
  * The codec isn't really big-endian or little-endian, since the I2S
@@ -639,6 +641,15 @@ static const struct snd_soc_codec_driver soc_codec_device_cs4270 = {
        .reg_cache_default =    cs4270_default_reg_cache,
 };
 
+/*
+ * cs4270_of_match - the device tree bindings
+ */
+static const struct of_device_id cs4270_of_match[] = {
+       { .compatible = "cirrus,cs4270", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, cs4270_of_match);
+
 /**
  * cs4270_i2c_probe - initialize the I2C interface of the CS4270
  * @i2c_client: the I2C client object
@@ -650,9 +661,25 @@ static const struct snd_soc_codec_driver soc_codec_device_cs4270 = {
 static int cs4270_i2c_probe(struct i2c_client *i2c_client,
        const struct i2c_device_id *id)
 {
+       struct device_node *np = i2c_client->dev.of_node;
        struct cs4270_private *cs4270;
        int ret;
 
+       /* See if we have a way to bring the codec out of reset */
+       if (np) {
+               enum of_gpio_flags flags;
+               int gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &flags);
+
+               if (gpio_is_valid(gpio)) {
+                       ret = devm_gpio_request_one(&i2c_client->dev, gpio,
+                                    flags & OF_GPIO_ACTIVE_LOW ?
+                                       GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
+                                    "cs4270 reset");
+                       if (ret < 0)
+                               return ret;
+               }
+       }
+
        /* Verify that we have a CS4270 */
 
        ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID);
@@ -718,23 +745,14 @@ static struct i2c_driver cs4270_i2c_driver = {
        .driver = {
                .name = "cs4270",
                .owner = THIS_MODULE,
+               .of_match_table = cs4270_of_match,
        },
        .id_table = cs4270_id,
        .probe = cs4270_i2c_probe,
        .remove = cs4270_i2c_remove,
 };
 
-static int __init cs4270_init(void)
-{
-       return i2c_add_driver(&cs4270_i2c_driver);
-}
-module_init(cs4270_init);
-
-static void __exit cs4270_exit(void)
-{
-       i2c_del_driver(&cs4270_i2c_driver);
-}
-module_exit(cs4270_exit);
+module_i2c_driver(cs4270_i2c_driver);
 
 MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
 MODULE_DESCRIPTION("Cirrus Logic CS4270 ALSA SoC Codec Driver");
index 091d0193f507df21553be5515efc5f6836cd88d9..1e0fa3b5f79a5e5659ec76acf5c4a70457fad328 100644 (file)
@@ -614,24 +614,7 @@ static struct i2c_driver cs42l51_i2c_driver = {
        .remove = cs42l51_i2c_remove,
 };
 
-static int __init cs42l51_init(void)
-{
-       int ret;
-
-       ret = i2c_add_driver(&cs42l51_i2c_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "%s: can't add i2c driver\n", __func__);
-               return ret;
-       }
-       return 0;
-}
-module_init(cs42l51_init);
-
-static void __exit cs42l51_exit(void)
-{
-       i2c_del_driver(&cs42l51_i2c_driver);
-}
-module_exit(cs42l51_exit);
+module_i2c_driver(cs42l51_i2c_driver);
 
 MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>");
 MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver");
index 628daf6a1d97e8fee699f8d87ea92ec6dbf5fdaf..61599298fb26c32bdb193e1be0ccb33d2490a0af 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/slab.h>
 #include <linux/workqueue.h>
 #include <linux/platform_device.h>
-#include <linux/slab.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
index 5d8f39e329788b10fdcf47f8166e03e1911b7d10..1bf55602c9ebf2ecf97ca2912a99815a5e707493 100644 (file)
@@ -13,7 +13,6 @@
  */
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/version.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/delay.h>
index ba4fafb93e5624d2aff10f6e20cf81ad34066ea9..81a328c78838250c952609275af6888e875e6057 100644 (file)
@@ -250,17 +250,7 @@ static struct i2c_driver lm4857_i2c_driver = {
        .id_table = lm4857_i2c_id,
 };
 
-static int __init lm4857_init(void)
-{
-       return i2c_add_driver(&lm4857_i2c_driver);
-}
-module_init(lm4857_init);
-
-static void __exit lm4857_exit(void)
-{
-       i2c_del_driver(&lm4857_i2c_driver);
-}
-module_exit(lm4857_exit);
+module_i2c_driver(lm4857_i2c_driver);
 
 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
 MODULE_DESCRIPTION("LM4857 amplifier driver");
index af7324b79dd0a8c8ae900277a7bf4abf2a98995a..3264a5169306fc3f8d769912173f803fae3d17a4 100644 (file)
@@ -2107,23 +2107,7 @@ static struct i2c_driver max98088_i2c_driver = {
        .id_table = max98088_i2c_id,
 };
 
-static int __init max98088_init(void)
-{
-       int ret;
-
-       ret = i2c_add_driver(&max98088_i2c_driver);
-       if (ret)
-               pr_err("Failed to register max98088 I2C driver: %d\n", ret);
-
-       return ret;
-}
-module_init(max98088_init);
-
-static void __exit max98088_exit(void)
-{
-       i2c_del_driver(&max98088_i2c_driver);
-}
-module_exit(max98088_exit);
+module_i2c_driver(max98088_i2c_driver);
 
 MODULE_DESCRIPTION("ALSA SoC MAX98088 driver");
 MODULE_AUTHOR("Peter Hsiang, Jesse Marroquin");
index 7cd508e16a5ca3cd0bfe7dcef88941d7c6ab5c90..38d43c59d3f4cfbc67cc11f2d86af73f8ae910b9 100644 (file)
@@ -2533,23 +2533,7 @@ static struct i2c_driver max98095_i2c_driver = {
        .id_table = max98095_i2c_id,
 };
 
-static int __init max98095_init(void)
-{
-       int ret;
-
-       ret = i2c_add_driver(&max98095_i2c_driver);
-       if (ret)
-               pr_err("Failed to register max98095 I2C driver: %d\n", ret);
-
-       return ret;
-}
-module_init(max98095_init);
-
-static void __exit max98095_exit(void)
-{
-       i2c_del_driver(&max98095_i2c_driver);
-}
-module_exit(max98095_exit);
+module_i2c_driver(max98095_i2c_driver);
 
 MODULE_DESCRIPTION("ALSA SoC MAX98095 driver");
 MODULE_AUTHOR("Peter Hsiang");
index a1913091f56ca5641fd58a4066890065deb0d5d6..efe535c37b39eb82f110e76328f3345fb3fdd10e 100644 (file)
@@ -369,17 +369,7 @@ static struct i2c_driver max9850_i2c_driver = {
        .id_table = max9850_i2c_id,
 };
 
-static int __init max9850_init(void)
-{
-       return i2c_add_driver(&max9850_i2c_driver);
-}
-module_init(max9850_init);
-
-static void __exit max9850_exit(void)
-{
-       i2c_del_driver(&max9850_i2c_driver);
-}
-module_exit(max9850_exit);
+module_i2c_driver(max9850_i2c_driver);
 
 MODULE_AUTHOR("Christian Glindkamp <christian.glindkamp@taskit.de>");
 MODULE_DESCRIPTION("ASoC MAX9850 codec driver");
index 3a2ba3d8fd6de13ec21f8e5b6ed67df85af77256..d15e5943c85e931bc0ffd5472b27768bbadaeb79 100644 (file)
@@ -291,17 +291,7 @@ static struct i2c_driver max9877_i2c_driver = {
        .id_table = max9877_i2c_id,
 };
 
-static int __init max9877_init(void)
-{
-       return i2c_add_driver(&max9877_i2c_driver);
-}
-module_init(max9877_init);
-
-static void __exit max9877_exit(void)
-{
-       i2c_del_driver(&max9877_i2c_driver);
-}
-module_exit(max9877_exit);
+module_i2c_driver(max9877_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC MAX9877 amp driver");
 MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
index 6276e352125f0a22e156c388c08f53d229fd543e..8f726c063f42badc9c598de4af670fb78f8937e1 100644 (file)
@@ -581,6 +581,8 @@ static int mc13783_probe(struct snd_soc_codec *codec)
 {
        struct mc13783_priv *priv = snd_soc_codec_get_drvdata(codec);
 
+       codec->control_data = priv->mc13xxx;
+
        mc13xxx_lock(priv->mc13xxx);
 
        /* these are the reset values */
index 8af6a5245b18acbfefe5fa1ca8ecbec8fd9068be..df2f99d1d428940424d419378ce6cf9d82a937bf 100644 (file)
@@ -239,6 +239,7 @@ static const struct snd_soc_dapm_route sgtl5000_dapm_routes[] = {
        {"Headphone Mux", "DAC", "DAC"},        /* dac --> hp_mux */
        {"LO", NULL, "DAC"},                    /* dac --> line_out */
 
+       {"LINE_IN", NULL, "VAG_POWER"},
        {"Headphone Mux", "LINE_IN", "LINE_IN"},/* line_in --> hp_mux */
        {"HP", NULL, "Headphone Mux"},          /* hp_mux --> hp */
 
@@ -1357,8 +1358,6 @@ static int sgtl5000_probe(struct snd_soc_codec *codec)
        if (ret)
                goto err;
 
-       snd_soc_dapm_new_widgets(&codec->dapm);
-
        return 0;
 
 err:
index 8d717f4b5a875d5efb4bcdf283f3604366a07dea..51b7313a4c14b05c7da73c82313e4be49478c71a 100644 (file)
@@ -1006,17 +1006,7 @@ static struct i2c_driver sta32x_i2c_driver = {
        .id_table = sta32x_i2c_id,
 };
 
-static int __init sta32x_init(void)
-{
-       return i2c_add_driver(&sta32x_i2c_driver);
-}
-module_init(sta32x_init);
-
-static void __exit sta32x_exit(void)
-{
-       i2c_del_driver(&sta32x_i2c_driver);
-}
-module_exit(sta32x_exit);
+module_i2c_driver(sta32x_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC STA32X driver");
 MODULE_AUTHOR("Johannes Stezenbach <js@sig21.net>");
index 0c225cd569d231007b92c51bc7c8cf4baf02b9dc..9e31448623866e9e7665b289bdca1665b4924db2 100644 (file)
@@ -358,7 +358,7 @@ static int sta529_resume(struct snd_soc_codec *codec)
        return 0;
 }
 
-struct snd_soc_codec_driver sta529_codec_driver = {
+static const struct snd_soc_codec_driver sta529_codec_driver = {
        .probe = sta529_probe,
        .remove = sta529_remove,
        .set_bias_level = sta529_set_bias_level,
index 982e437799a8e62aa8085a9d5b509fa4d8f8a387..33c0f3d39c87ea0ea6c99ea1752f30e663914766 100644 (file)
@@ -340,6 +340,7 @@ static int stac9766_codec_probe(struct snd_soc_codec *codec)
 
        printk(KERN_INFO "STAC9766 SoC Audio Codec %s\n", STAC9766_VERSION);
 
+       codec->control_data = codec;    /* we don't use regmap! */
        ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
        if (ret < 0)
                goto codec_err;
index b0a73d37ed52b4dfb52fb97a367e03f37a6df291..f230292ba96bbfc0c5cf7c7264dd4435de3d7590 100644 (file)
@@ -746,24 +746,7 @@ static struct i2c_driver aic32x4_i2c_driver = {
        .id_table = aic32x4_i2c_id,
 };
 
-static int __init aic32x4_modinit(void)
-{
-       int ret = 0;
-
-       ret = i2c_add_driver(&aic32x4_i2c_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "Failed to register aic32x4 I2C driver: %d\n",
-                      ret);
-       }
-       return ret;
-}
-module_init(aic32x4_modinit);
-
-static void __exit aic32x4_exit(void)
-{
-       i2c_del_driver(&aic32x4_i2c_driver);
-}
-module_exit(aic32x4_exit);
+module_i2c_driver(aic32x4_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC tlv320aic32x4 codec driver");
 MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>");
index dc78f5a4bcbf8922bb9690452f4e4e99c0a3ec18..01485bd514048ca976c0adc7a0902ceebb9e259c 100644 (file)
@@ -1499,23 +1499,7 @@ static struct i2c_driver aic3x_i2c_driver = {
        .id_table = aic3x_i2c_id,
 };
 
-static int __init aic3x_modinit(void)
-{
-       int ret = 0;
-       ret = i2c_add_driver(&aic3x_i2c_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "Failed to register TLV320AIC3x I2C driver: %d\n",
-                      ret);
-       }
-       return ret;
-}
-module_init(aic3x_modinit);
-
-static void __exit aic3x_exit(void)
-{
-       i2c_del_driver(&aic3x_i2c_driver);
-}
-module_exit(aic3x_exit);
+module_i2c_driver(aic3x_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC TLV320AIC3X codec driver");
 MODULE_AUTHOR("Vladimir Barinov");
index 0dd41077ab79eab0daf001111a5248ac17ee98f2..d2e16c5d7d1f71ca5d4425e7c6d8a83dc7bcb7ec 100644 (file)
@@ -1621,24 +1621,7 @@ static struct i2c_driver tlv320dac33_i2c_driver = {
        .id_table       = tlv320dac33_i2c_id,
 };
 
-static int __init dac33_module_init(void)
-{
-       int r;
-       r = i2c_add_driver(&tlv320dac33_i2c_driver);
-       if (r < 0) {
-               printk(KERN_ERR "DAC33: driver registration failed\n");
-               return r;
-       }
-       return 0;
-}
-module_init(dac33_module_init);
-
-static void __exit dac33_module_exit(void)
-{
-       i2c_del_driver(&tlv320dac33_i2c_driver);
-}
-module_exit(dac33_module_exit);
-
+module_i2c_driver(tlv320dac33_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC TLV320DAC33 codec driver");
 MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
index 6fe4aa3ac54401da4210df65ead54e0a1fe537b2..565ff39ad3a35ced5598c9532bc33b85f1d8983a 100644 (file)
@@ -487,19 +487,8 @@ static struct i2c_driver tpa6130a2_i2c_driver = {
        .id_table = tpa6130a2_id,
 };
 
-static int __init tpa6130a2_init(void)
-{
-       return i2c_add_driver(&tpa6130a2_i2c_driver);
-}
-
-static void __exit tpa6130a2_exit(void)
-{
-       i2c_del_driver(&tpa6130a2_i2c_driver);
-}
+module_i2c_driver(tpa6130a2_i2c_driver);
 
 MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@ti.com>");
 MODULE_DESCRIPTION("TPA6130A2 Headphone amplifier driver");
 MODULE_LICENSE("GPL");
-
-module_init(tpa6130a2_init);
-module_exit(tpa6130a2_exit);
index 3fd5b29dc9335b5bee03b0b28f6cbbdfee2ea297..89cd6fcad0151a7ab3e39b777d09268c4905a66d 100644 (file)
@@ -858,17 +858,7 @@ static struct i2c_driver wm2000_i2c_driver = {
        .id_table = wm2000_i2c_id,
 };
 
-static int __init wm2000_init(void)
-{
-       return i2c_add_driver(&wm2000_i2c_driver);
-}
-module_init(wm2000_init);
-
-static void __exit wm2000_exit(void)
-{
-       i2c_del_driver(&wm2000_i2c_driver);
-}
-module_exit(wm2000_exit);
+module_i2c_driver(wm2000_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM2000 driver");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfonmicro.com>");
index 32682c1b7cdece413693db6f6487ae4df640da09..71debd0a382250af2d3d60daac4e3323fe011030 100644 (file)
@@ -2270,17 +2270,7 @@ static struct i2c_driver wm2200_i2c_driver = {
        .id_table = wm2200_i2c_id,
 };
 
-static int __init wm2200_modinit(void)
-{
-       return i2c_add_driver(&wm2200_i2c_driver);
-}
-module_init(wm2200_modinit);
-
-static void __exit wm2200_exit(void)
-{
-       i2c_del_driver(&wm2200_i2c_driver);
-}
-module_exit(wm2200_exit);
+module_i2c_driver(wm2200_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM2200 driver");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
index 6537f16d383e12f459b9f39950c7b28b46d8d7da..a00901cee9d0c7a95aa9a1a6da2ebf0058328b3d 100644 (file)
@@ -285,6 +285,10 @@ SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
                    0, NULL, 0),
 SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
                    ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,
+                   ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK,
+                   ARIZONA_OPCLK_ASYNC_ENA_SHIFT, 0, NULL, 0),
 
 SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0),
 SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0),
@@ -639,6 +643,15 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = {
        { "AIF2 Capture", NULL, "SYSCLK" },
        { "AIF3 Capture", NULL, "SYSCLK" },
 
+       { "IN1L PGA", NULL, "IN1L" },
+       { "IN1R PGA", NULL, "IN1R" },
+
+       { "IN2L PGA", NULL, "IN2L" },
+       { "IN2R PGA", NULL, "IN2R" },
+
+       { "IN3L PGA", NULL, "IN3L" },
+       { "IN3R PGA", NULL, "IN3R" },
+
        ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"),
        ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"),
        ARIZONA_MIXER_ROUTES("OUT2L", "HPOUT2L"),
index 8033f70651897215613275901fd432eea6cdb673..57c7d9c0aadb98179962807d512f2e6a59f56a75 100644 (file)
@@ -305,6 +305,10 @@ SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
                    0, NULL, 0),
 SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1,
                    ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK,
+                   ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0),
+SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK,
+                   ARIZONA_OPCLK_ASYNC_ENA_SHIFT, 0, NULL, 0),
 
 SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0),
 SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0),
@@ -681,6 +685,18 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
        { "AIF2 Capture", NULL, "SYSCLK" },
        { "AIF3 Capture", NULL, "SYSCLK" },
 
+       { "IN1L PGA", NULL, "IN1L" },
+       { "IN1R PGA", NULL, "IN1R" },
+
+       { "IN2L PGA", NULL, "IN2L" },
+       { "IN2R PGA", NULL, "IN2R" },
+
+       { "IN3L PGA", NULL, "IN3L" },
+       { "IN3R PGA", NULL, "IN3R" },
+
+       { "IN4L PGA", NULL, "IN4L" },
+       { "IN4R PGA", NULL, "IN4R" },
+
        ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"),
        ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"),
        ARIZONA_MIXER_ROUTES("OUT2L", "HPOUT2L"),
index 73f1c8d7bafbdc591e990f2dc2fd678a61ff1f8a..839414f9e2ed3866d41f09c96cd3d50ec9dcc045 100644 (file)
@@ -2241,23 +2241,7 @@ static struct i2c_driver wm8903_i2c_driver = {
        .id_table = wm8903_i2c_id,
 };
 
-static int __init wm8903_modinit(void)
-{
-       int ret = 0;
-       ret = i2c_add_driver(&wm8903_i2c_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "Failed to register wm8903 I2C driver: %d\n",
-                      ret);
-       }
-       return ret;
-}
-module_init(wm8903_modinit);
-
-static void __exit wm8903_exit(void)
-{
-       i2c_del_driver(&wm8903_i2c_driver);
-}
-module_exit(wm8903_exit);
+module_i2c_driver(wm8903_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM8903 driver");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.cm>");
index 481a3d9cfe4852958047cec3f83be88cd17a365d..b20aa4e7c3f9c2f85f84deaddc06aee763061987 100644 (file)
@@ -785,23 +785,7 @@ static struct i2c_driver wm8940_i2c_driver = {
        .id_table = wm8940_i2c_id,
 };
 
-static int __init wm8940_modinit(void)
-{
-       int ret = 0;
-       ret = i2c_add_driver(&wm8940_i2c_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "Failed to register wm8940 I2C driver: %d\n",
-                      ret);
-       }
-       return ret;
-}
-module_init(wm8940_modinit);
-
-static void __exit wm8940_exit(void)
-{
-       i2c_del_driver(&wm8940_i2c_driver);
-}
-module_exit(wm8940_exit);
+module_i2c_driver(wm8940_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM8940 driver");
 MODULE_AUTHOR("Jonathan Cameron");
index 61fe97433e738eb43c486115a985fc1bd0ad68f5..2f1c075755b1fc7dd4827fbcd547da0556e9e2a9 100644 (file)
@@ -1071,23 +1071,7 @@ static struct i2c_driver wm8955_i2c_driver = {
        .id_table = wm8955_i2c_id,
 };
 
-static int __init wm8955_modinit(void)
-{
-       int ret = 0;
-       ret = i2c_add_driver(&wm8955_i2c_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "Failed to register WM8955 I2C driver: %d\n",
-                      ret);
-       }
-       return ret;
-}
-module_init(wm8955_modinit);
-
-static void __exit wm8955_exit(void)
-{
-       i2c_del_driver(&wm8955_i2c_driver);
-}
-module_exit(wm8955_exit);
+module_i2c_driver(wm8955_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM8955 driver");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
index 1332692ef81bc9628e8cad04ccf65cd972c7fb8c..00121ba3659718ab4c4af6ff5135373762de4765 100644 (file)
@@ -946,7 +946,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)
                wm8994->mbc_texts = kmalloc(sizeof(char *)
                                            * pdata->num_mbc_cfgs, GFP_KERNEL);
                if (!wm8994->mbc_texts) {
-                       dev_err(wm8994->codec->dev,
+                       dev_err(wm8994->hubs.codec->dev,
                                "Failed to allocate %d MBC config texts\n",
                                pdata->num_mbc_cfgs);
                        return;
@@ -958,9 +958,10 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)
                wm8994->mbc_enum.max = pdata->num_mbc_cfgs;
                wm8994->mbc_enum.texts = wm8994->mbc_texts;
 
-               ret = snd_soc_add_codec_controls(wm8994->codec, control, 1);
+               ret = snd_soc_add_codec_controls(wm8994->hubs.codec,
+                                                control, 1);
                if (ret != 0)
-                       dev_err(wm8994->codec->dev,
+                       dev_err(wm8994->hubs.codec->dev,
                                "Failed to add MBC mode controls: %d\n", ret);
        }
 
@@ -974,7 +975,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)
                wm8994->vss_texts = kmalloc(sizeof(char *)
                                            * pdata->num_vss_cfgs, GFP_KERNEL);
                if (!wm8994->vss_texts) {
-                       dev_err(wm8994->codec->dev,
+                       dev_err(wm8994->hubs.codec->dev,
                                "Failed to allocate %d VSS config texts\n",
                                pdata->num_vss_cfgs);
                        return;
@@ -986,9 +987,10 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)
                wm8994->vss_enum.max = pdata->num_vss_cfgs;
                wm8994->vss_enum.texts = wm8994->vss_texts;
 
-               ret = snd_soc_add_codec_controls(wm8994->codec, control, 1);
+               ret = snd_soc_add_codec_controls(wm8994->hubs.codec,
+                                                control, 1);
                if (ret != 0)
-                       dev_err(wm8994->codec->dev,
+                       dev_err(wm8994->hubs.codec->dev,
                                "Failed to add VSS mode controls: %d\n", ret);
        }
 
@@ -1003,7 +1005,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)
                wm8994->vss_hpf_texts = kmalloc(sizeof(char *)
                                                * pdata->num_vss_hpf_cfgs, GFP_KERNEL);
                if (!wm8994->vss_hpf_texts) {
-                       dev_err(wm8994->codec->dev,
+                       dev_err(wm8994->hubs.codec->dev,
                                "Failed to allocate %d VSS HPF config texts\n",
                                pdata->num_vss_hpf_cfgs);
                        return;
@@ -1015,9 +1017,10 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)
                wm8994->vss_hpf_enum.max = pdata->num_vss_hpf_cfgs;
                wm8994->vss_hpf_enum.texts = wm8994->vss_hpf_texts;
 
-               ret = snd_soc_add_codec_controls(wm8994->codec, control, 1);
+               ret = snd_soc_add_codec_controls(wm8994->hubs.codec,
+                                                control, 1);
                if (ret != 0)
-                       dev_err(wm8994->codec->dev,
+                       dev_err(wm8994->hubs.codec->dev,
                                "Failed to add VSS HPFmode controls: %d\n",
                                ret);
        }
@@ -1033,7 +1036,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)
                wm8994->enh_eq_texts = kmalloc(sizeof(char *)
                                                * pdata->num_enh_eq_cfgs, GFP_KERNEL);
                if (!wm8994->enh_eq_texts) {
-                       dev_err(wm8994->codec->dev,
+                       dev_err(wm8994->hubs.codec->dev,
                                "Failed to allocate %d enhanced EQ config texts\n",
                                pdata->num_enh_eq_cfgs);
                        return;
@@ -1045,9 +1048,10 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec)
                wm8994->enh_eq_enum.max = pdata->num_enh_eq_cfgs;
                wm8994->enh_eq_enum.texts = wm8994->enh_eq_texts;
 
-               ret = snd_soc_add_codec_controls(wm8994->codec, control, 1);
+               ret = snd_soc_add_codec_controls(wm8994->hubs.codec,
+                                                control, 1);
                if (ret != 0)
-                       dev_err(wm8994->codec->dev,
+                       dev_err(wm8994->hubs.codec->dev,
                                "Failed to add enhanced EQ controls: %d\n",
                                ret);
        }
index 96518ac8e24ce9660f6fde240cc951570af6a61c..804f4116912f3d49d106fe0ec338cfe1671ad58d 100644 (file)
@@ -1010,23 +1010,7 @@ static struct i2c_driver wm8960_i2c_driver = {
        .id_table = wm8960_i2c_id,
 };
 
-static int __init wm8960_modinit(void)
-{
-       int ret = 0;
-       ret = i2c_add_driver(&wm8960_i2c_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "Failed to register WM8960 I2C driver: %d\n",
-                      ret);
-       }
-       return ret;
-}
-module_init(wm8960_modinit);
-
-static void __exit wm8960_exit(void)
-{
-       i2c_del_driver(&wm8960_i2c_driver);
-}
-module_exit(wm8960_exit);
+module_i2c_driver(wm8960_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM8960 driver");
 MODULE_AUTHOR("Liam Girdwood");
index 01edbcc754d2cb7ef10124963a701583cf75f762..719fb69a17c81ea83d77c02f1c79e75193df6a4c 100644 (file)
@@ -1114,23 +1114,7 @@ static struct i2c_driver wm8961_i2c_driver = {
        .id_table = wm8961_i2c_id,
 };
 
-static int __init wm8961_modinit(void)
-{
-       int ret = 0;
-       ret = i2c_add_driver(&wm8961_i2c_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "Failed to register wm8961 I2C driver: %d\n",
-                      ret);
-       }
-       return ret;
-}
-module_init(wm8961_modinit);
-
-static void __exit wm8961_exit(void)
-{
-       i2c_del_driver(&wm8961_i2c_driver);
-}
-module_exit(wm8961_exit);
+module_i2c_driver(wm8961_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM8961 driver");
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
index eaf65863ec2190c8e705eaa3d4b5a95ff6378d30..ce6720073798ddd352df483182b1653b121ec096 100644 (file)
@@ -2501,6 +2501,9 @@ static int wm8962_set_bias_level(struct snd_soc_codec *codec,
                /* VMID 2*250k */
                snd_soc_update_bits(codec, WM8962_PWR_MGMT_1,
                                    WM8962_VMID_SEL_MASK, 0x100);
+
+               if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+                       msleep(100);
                break;
 
        case SND_SOC_BIAS_OFF:
@@ -3730,21 +3733,6 @@ static int wm8962_runtime_resume(struct device *dev)
 
        regcache_sync(wm8962->regmap);
 
-       regmap_update_bits(wm8962->regmap, WM8962_ANTI_POP,
-                          WM8962_STARTUP_BIAS_ENA | WM8962_VMID_BUF_ENA,
-                          WM8962_STARTUP_BIAS_ENA | WM8962_VMID_BUF_ENA);
-
-       /* Bias enable at 2*50k for ramp */
-       regmap_update_bits(wm8962->regmap, WM8962_PWR_MGMT_1,
-                          WM8962_VMID_SEL_MASK | WM8962_BIAS_ENA,
-                          WM8962_BIAS_ENA | 0x180);
-
-       msleep(5);
-
-       /* VMID back to 2x250k for standby */
-       regmap_update_bits(wm8962->regmap, WM8962_PWR_MGMT_1,
-                          WM8962_VMID_SEL_MASK, 0x100);
-
        return 0;
 }
 
index eef783f6b6d6849aa014296a9afea6b5743adfca..5ce6477584438b3a8555bada53f8e17c1dd7cc5e 100644 (file)
@@ -721,23 +721,7 @@ static struct i2c_driver wm8971_i2c_driver = {
        .id_table = wm8971_i2c_id,
 };
 
-static int __init wm8971_modinit(void)
-{
-       int ret = 0;
-       ret = i2c_add_driver(&wm8971_i2c_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "Failed to register WM8971 I2C driver: %d\n",
-                      ret);
-       }
-       return ret;
-}
-module_init(wm8971_modinit);
-
-static void __exit wm8971_exit(void)
-{
-       i2c_del_driver(&wm8971_i2c_driver);
-}
-module_exit(wm8971_exit);
+module_i2c_driver(wm8971_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM8971 driver");
 MODULE_AUTHOR("Lab126");
index d93c03f820c9e802f87d2cfcd0fb7357d7b9fa15..9a39511af52ad180bda356d210a7594de1c3f80f 100644 (file)
@@ -659,23 +659,7 @@ static struct i2c_driver wm8974_i2c_driver = {
        .id_table = wm8974_i2c_id,
 };
 
-static int __init wm8974_modinit(void)
-{
-       int ret = 0;
-       ret = i2c_add_driver(&wm8974_i2c_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "Failed to register wm8974 I2C driver: %d\n",
-                      ret);
-       }
-       return ret;
-}
-module_init(wm8974_modinit);
-
-static void __exit wm8974_exit(void)
-{
-       i2c_del_driver(&wm8974_i2c_driver);
-}
-module_exit(wm8974_exit);
+module_i2c_driver(wm8974_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM8974 driver");
 MODULE_AUTHOR("Liam Girdwood");
index a5be3adecf7572bed47d4ed99b59f6fbf87fbed8..5421fd9fbcb5d37954e77f88962c31e9d953e2dc 100644 (file)
@@ -1105,23 +1105,7 @@ static struct i2c_driver wm8978_i2c_driver = {
        .id_table = wm8978_i2c_id,
 };
 
-static int __init wm8978_modinit(void)
-{
-       int ret = 0;
-       ret = i2c_add_driver(&wm8978_i2c_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "Failed to register WM8978 I2C driver: %d\n",
-                      ret);
-       }
-       return ret;
-}
-module_init(wm8978_modinit);
-
-static void __exit wm8978_exit(void)
-{
-       i2c_del_driver(&wm8978_i2c_driver);
-}
-module_exit(wm8978_exit);
+module_i2c_driver(wm8978_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM8978 codec driver");
 MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
index 9ac31ba9b82e1ad635167baa38563da16d1e6ee2..b9dbfebbda13ee50d98791c159c554001e4c4baa 100644 (file)
@@ -1400,23 +1400,7 @@ static struct i2c_driver wm8991_i2c_driver = {
        .id_table = wm8991_i2c_id,
 };
 
-static int __init wm8991_modinit(void)
-{
-       int ret;
-       ret = i2c_add_driver(&wm8991_i2c_driver);
-       if (ret != 0) {
-               printk(KERN_ERR "Failed to register WM8991 I2C driver: %d\n",
-                      ret);
-       }
-       return 0;
-}
-module_init(wm8991_modinit);
-
-static void __exit wm8991_exit(void)
-{
-       i2c_del_driver(&wm8991_i2c_driver);
-}
-module_exit(wm8991_exit);
+module_i2c_driver(wm8991_i2c_driver);
 
 MODULE_DESCRIPTION("ASoC WM8991 driver");
 MODULE_AUTHOR("Graeme Gregory");
index bb62f4b3d563d434143f52a6ba70f614a8ed61fd..e07fa83dea858554736d66f23c51092cc3ed2bd9 100644 (file)
@@ -789,11 +789,27 @@ static int clk_sys_event(struct snd_soc_dapm_widget *w,
                         struct snd_kcontrol *kcontrol, int event)
 {
        struct snd_soc_codec *codec = w->codec;
+       struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
 
        switch (event) {
        case SND_SOC_DAPM_PRE_PMU:
                return configure_clock(codec);
 
+       case SND_SOC_DAPM_POST_PMU:
+               /*
+                * JACKDET won't run until we start the clock and it
+                * only reports deltas, make sure we notify the state
+                * up the stack on startup.  Use a *very* generous
+                * timeout for paranoia, there's no urgency and we
+                * don't want false reports.
+                */
+               if (wm8994->jackdet && !wm8994->clk_has_run) {
+                       schedule_delayed_work(&wm8994->jackdet_bootstrap,
+                                             msecs_to_jiffies(1000));
+                       wm8994->clk_has_run = true;
+               }
+               break;
+
        case SND_SOC_DAPM_POST_PMD:
                configure_clock(codec);
                break;
@@ -1632,7 +1648,8 @@ SND_SOC_DAPM_SUPPLY("VMID", SND_SOC_NOPM, 0, 0, vmid_event,
                    SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
 
 SND_SOC_DAPM_SUPPLY("CLK_SYS", SND_SOC_NOPM, 0, 0, clk_sys_event,
-                   SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+                   SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                   SND_SOC_DAPM_PRE_PMD),
 
 SND_SOC_DAPM_SUPPLY("DSP1CLK", SND_SOC_NOPM, 3, 0, NULL, 0),
 SND_SOC_DAPM_SUPPLY("DSP2CLK", SND_SOC_NOPM, 2, 0, NULL, 0),
@@ -2102,6 +2119,10 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
        case WM8994_FLL_SRC_LRCLK:
        case WM8994_FLL_SRC_BCLK:
                break;
+       case WM8994_FLL_SRC_INTERNAL:
+               freq_in = 12000000;
+               freq_out = 12000000;
+               break;
        default:
                return -EINVAL;
        }
@@ -2161,12 +2182,14 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
 
        snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_4 + reg_offset,
                            WM8994_FLL1_N_MASK,
-                                   fll.n << WM8994_FLL1_N_SHIFT);
+                           fll.n << WM8994_FLL1_N_SHIFT);
 
        snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_5 + reg_offset,
-                           WM8958_FLL1_BYP |
+                           WM8994_FLL1_FRC_NCO | WM8958_FLL1_BYP |
                            WM8994_FLL1_REFCLK_DIV_MASK |
                            WM8994_FLL1_REFCLK_SRC_MASK,
+                           ((src == WM8994_FLL_SRC_INTERNAL)
+                            << WM8994_FLL1_FRC_NCO_SHIFT) |
                            (fll.clk_ref_div << WM8994_FLL1_REFCLK_DIV_SHIFT) |
                            (src - 1));
 
@@ -2192,13 +2215,16 @@ static int _wm8994_set_fll(struct snd_soc_codec *codec, int id, int src,
                        }
                }
 
+               reg = WM8994_FLL1_ENA;
+
                if (fll.k)
-                       reg = WM8994_FLL1_ENA | WM8994_FLL1_FRAC;
-               else
-                       reg = WM8994_FLL1_ENA;
+                       reg |= WM8994_FLL1_FRAC;
+               if (src == WM8994_FLL_SRC_INTERNAL)
+                       reg |= WM8994_FLL1_OSC_ENA;
+
                snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_1 + reg_offset,
-                                   WM8994_FLL1_ENA | WM8994_FLL1_FRAC,
-                                   reg);
+                                   WM8994_FLL1_ENA | WM8994_FLL1_OSC_ENA |
+                                   WM8994_FLL1_FRAC, reg);
 
                if (wm8994->fll_locked_irq) {
                        timeout = wait_for_completion_timeout(&wm8994->fll_locked[id],
@@ -2649,7 +2675,7 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       bclk_rate = params_rate(params) * 2;
+       bclk_rate = params_rate(params) * 4;
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
                bclk_rate *= 16;
@@ -3027,7 +3053,7 @@ static int wm8994_codec_resume(struct snd_soc_codec *codec)
 
 static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994)
 {
-       struct snd_soc_codec *codec = wm8994->codec;
+       struct snd_soc_codec *codec = wm8994->hubs.codec;
        struct wm8994_pdata *pdata = wm8994->pdata;
        struct snd_kcontrol_new controls[] = {
                SOC_ENUM_EXT("AIF1.1 EQ Mode",
@@ -3085,16 +3111,16 @@ static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994)
        wm8994->retune_mobile_enum.max = wm8994->num_retune_mobile_texts;
        wm8994->retune_mobile_enum.texts = wm8994->retune_mobile_texts;
 
-       ret = snd_soc_add_codec_controls(wm8994->codec, controls,
+       ret = snd_soc_add_codec_controls(wm8994->hubs.codec, controls,
                                   ARRAY_SIZE(controls));
        if (ret != 0)
-               dev_err(wm8994->codec->dev,
+               dev_err(wm8994->hubs.codec->dev,
                        "Failed to add ReTune Mobile controls: %d\n", ret);
 }
 
 static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
 {
-       struct snd_soc_codec *codec = wm8994->codec;
+       struct snd_soc_codec *codec = wm8994->hubs.codec;
        struct wm8994_pdata *pdata = wm8994->pdata;
        int ret, i;
 
@@ -3123,10 +3149,10 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
                };
 
                /* We need an array of texts for the enum API */
-               wm8994->drc_texts = devm_kzalloc(wm8994->codec->dev,
+               wm8994->drc_texts = devm_kzalloc(wm8994->hubs.codec->dev,
                            sizeof(char *) * pdata->num_drc_cfgs, GFP_KERNEL);
                if (!wm8994->drc_texts) {
-                       dev_err(wm8994->codec->dev,
+                       dev_err(wm8994->hubs.codec->dev,
                                "Failed to allocate %d DRC config texts\n",
                                pdata->num_drc_cfgs);
                        return;
@@ -3138,10 +3164,10 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
                wm8994->drc_enum.max = pdata->num_drc_cfgs;
                wm8994->drc_enum.texts = wm8994->drc_texts;
 
-               ret = snd_soc_add_codec_controls(wm8994->codec, controls,
+               ret = snd_soc_add_codec_controls(wm8994->hubs.codec, controls,
                                           ARRAY_SIZE(controls));
                if (ret != 0)
-                       dev_err(wm8994->codec->dev,
+                       dev_err(wm8994->hubs.codec->dev,
                                "Failed to add DRC mode controls: %d\n", ret);
 
                for (i = 0; i < WM8994_NUM_DRC; i++)
@@ -3154,7 +3180,7 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994)
        if (pdata->num_retune_mobile_cfgs)
                wm8994_handle_retune_mobile_pdata(wm8994);
        else
-               snd_soc_add_codec_controls(wm8994->codec, wm8994_eq_controls,
+               snd_soc_add_codec_controls(wm8994->hubs.codec, wm8994_eq_controls,
                                     ARRAY_SIZE(wm8994_eq_controls));
 
        for (i = 0; i < ARRAY_SIZE(pdata->micbias); i++) {
@@ -3236,6 +3262,12 @@ int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
 
        snd_soc_update_bits(codec, WM8994_MICBIAS, WM8994_MICD_ENA, reg);
 
+       /* enable MICDET and MICSHRT deboune */
+       snd_soc_update_bits(codec, WM8994_IRQ_DEBOUNCE,
+                           WM8994_MIC1_DET_DB_MASK | WM8994_MIC1_SHRT_DB_MASK |
+                           WM8994_MIC2_DET_DB_MASK | WM8994_MIC2_SHRT_DB_MASK,
+                           WM8994_MIC1_DET_DB | WM8994_MIC1_SHRT_DB);
+
        snd_soc_dapm_sync(&codec->dapm);
 
        return 0;
@@ -3253,10 +3285,13 @@ static void wm8994_mic_work(struct work_struct *work)
        int ret;
        int report;
 
+       pm_runtime_get_sync(dev);
+
        ret = regmap_read(regmap, WM8994_INTERRUPT_RAW_STATUS_2, &reg);
        if (ret < 0) {
                dev_err(dev, "Failed to read microphone status: %d\n",
                        ret);
+               pm_runtime_put(dev);
                return;
        }
 
@@ -3299,12 +3334,14 @@ static void wm8994_mic_work(struct work_struct *work)
 
        snd_soc_jack_report(priv->micdet[1].jack, report,
                            SND_JACK_HEADSET | SND_JACK_BTN_0);
+
+       pm_runtime_put(dev);
 }
 
 static irqreturn_t wm8994_mic_irq(int irq, void *data)
 {
        struct wm8994_priv *priv = data;
-       struct snd_soc_codec *codec = priv->codec;
+       struct snd_soc_codec *codec = priv->hubs.codec;
 
 #ifndef CONFIG_SND_SOC_WM8994_MODULE
        trace_snd_soc_jack_irq(dev_name(codec->dev));
@@ -3340,7 +3377,7 @@ static void wm8958_default_micdet(u16 status, void *data)
 
                        snd_soc_jack_report(wm8994->micdet[0].jack, 0,
                                            wm8994->btn_mask |
-                                            SND_JACK_HEADSET);
+                                           SND_JACK_HEADSET);
                }
                return;
        }
@@ -3417,16 +3454,19 @@ static void wm8958_default_micdet(u16 status, void *data)
 static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
 {
        struct wm8994_priv *wm8994 = data;
-       struct snd_soc_codec *codec = wm8994->codec;
+       struct snd_soc_codec *codec = wm8994->hubs.codec;
        int reg;
        bool present;
 
+       pm_runtime_get_sync(codec->dev);
+
        mutex_lock(&wm8994->accdet_lock);
 
        reg = snd_soc_read(codec, WM1811_JACKDET_CTRL);
        if (reg < 0) {
                dev_err(codec->dev, "Failed to read jack status: %d\n", reg);
                mutex_unlock(&wm8994->accdet_lock);
+               pm_runtime_put(codec->dev);
                return IRQ_NONE;
        }
 
@@ -3491,9 +3531,22 @@ static irqreturn_t wm1811_jackdet_irq(int irq, void *data)
                                    SND_JACK_MECHANICAL | SND_JACK_HEADSET |
                                    wm8994->btn_mask);
 
+       /* Since we only report deltas force an update, ensures we
+        * avoid bootstrapping issues with the core. */
+       snd_soc_jack_report(wm8994->micdet[0].jack, 0, 0);
+
+       pm_runtime_put(codec->dev);
        return IRQ_HANDLED;
 }
 
+static void wm1811_jackdet_bootstrap(struct work_struct *work)
+{
+       struct wm8994_priv *wm8994 = container_of(work,
+                                               struct wm8994_priv,
+                                               jackdet_bootstrap.work);
+       wm1811_jackdet_irq(0, wm8994);
+}
+
 /**
  * wm8958_mic_detect - Enable microphone detection via the WM8958 IRQ
  *
@@ -3564,6 +3617,10 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
                 * otherwise jump straight to microphone detection.
                 */
                if (wm8994->jackdet) {
+                       /* Disable debounce for the initial detect */
+                       snd_soc_update_bits(codec, WM1811_JACKDET_CTRL,
+                                           WM1811_JACKDET_DB, 0);
+
                        snd_soc_update_bits(codec, WM8958_MICBIAS2,
                                            WM8958_MICB2_DISCH,
                                            WM8958_MICB2_DISCH);
@@ -3591,7 +3648,7 @@ EXPORT_SYMBOL_GPL(wm8958_mic_detect);
 static irqreturn_t wm8958_mic_irq(int irq, void *data)
 {
        struct wm8994_priv *wm8994 = data;
-       struct snd_soc_codec *codec = wm8994->codec;
+       struct snd_soc_codec *codec = wm8994->hubs.codec;
        int reg, count;
 
        /*
@@ -3602,6 +3659,8 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
        if (!(snd_soc_read(codec, WM8958_MIC_DETECT_1) & WM8958_MICD_ENA))
                return IRQ_HANDLED;
 
+       pm_runtime_get_sync(codec->dev);
+
        /* We may occasionally read a detection without an impedence
         * range being provided - if that happens loop again.
         */
@@ -3612,6 +3671,7 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
                        dev_err(codec->dev,
                                "Failed to read mic detect status: %d\n",
                                reg);
+                       pm_runtime_put(codec->dev);
                        return IRQ_NONE;
                }
 
@@ -3639,6 +3699,7 @@ static irqreturn_t wm8958_mic_irq(int irq, void *data)
                dev_warn(codec->dev, "Accessory detection with no callback\n");
 
 out:
+       pm_runtime_put(codec->dev);
        return IRQ_HANDLED;
 }
 
@@ -3677,15 +3738,15 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
        unsigned int reg;
        int ret, i;
 
-       wm8994->codec = codec;
+       wm8994->hubs.codec = codec;
        codec->control_data = control->regmap;
 
        snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_REGMAP);
 
-       wm8994->codec = codec;
-
        mutex_init(&wm8994->accdet_lock);
        INIT_DELAYED_WORK(&wm8994->mic_work, wm8994_mic_work);
+       INIT_DELAYED_WORK(&wm8994->jackdet_bootstrap,
+                         wm1811_jackdet_bootstrap);
 
        for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++)
                init_completion(&wm8994->fll_locked[i]);
@@ -4025,6 +4086,8 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
                break;
        case WM8958:
                if (wm8994->revision < 1) {
+                       snd_soc_dapm_add_routes(dapm, wm8994_intercon,
+                                               ARRAY_SIZE(wm8994_intercon));
                        snd_soc_dapm_add_routes(dapm, wm8994_revd_intercon,
                                                ARRAY_SIZE(wm8994_revd_intercon));
                        snd_soc_dapm_add_routes(dapm, wm8994_lateclk_revd_intercon,
index d77e06f0a6751f7a1d4394b90324916b6085a34d..f142ec198db3dabfcfc5d1e20a51cdfd5e42874b 100644 (file)
 #define WM8994_FLL1 1
 #define WM8994_FLL2 2
 
-#define WM8994_FLL_SRC_MCLK1  1
-#define WM8994_FLL_SRC_MCLK2  2
-#define WM8994_FLL_SRC_LRCLK  3
-#define WM8994_FLL_SRC_BCLK   4
+#define WM8994_FLL_SRC_MCLK1    1
+#define WM8994_FLL_SRC_MCLK2    2
+#define WM8994_FLL_SRC_LRCLK    3
+#define WM8994_FLL_SRC_BCLK     4
+#define WM8994_FLL_SRC_INTERNAL 5
 
 enum wm8994_vmid_mode {
        WM8994_VMID_NORMAL,
@@ -72,7 +73,6 @@ struct wm8994;
 struct wm8994_priv {
        struct wm_hubs_data hubs;
        struct wm8994 *wm8994;
-       struct snd_soc_codec *codec;
        int sysclk[2];
        int sysclk_rate[2];
        int mclk[2];
@@ -81,6 +81,7 @@ struct wm8994_priv {
        struct completion fll_locked[2];
        bool fll_locked_irq;
        bool fll_byp;
+       bool clk_has_run;
 
        int vmid_refcount;
        int active_refcount;
@@ -134,6 +135,7 @@ struct wm8994_priv {
        int btn_mask;
        bool jackdet;
        int jackdet_mode;
+       struct delayed_work jackdet_bootstrap;
 
        wm8958_micdet_cb jack_cb;
        void *jack_cb_data;
index 2c2346fdd6370a3e307bd75a2815c6fcb89379eb..c7ddc56175d12ad799f449a814db1432d341305f 100644 (file)
@@ -695,17 +695,7 @@ static struct i2c_driver wm9090_i2c_driver = {
        .id_table = wm9090_id,
 };
 
-static int __init wm9090_init(void)
-{
-       return i2c_add_driver(&wm9090_i2c_driver);
-}
-module_init(wm9090_init);
-
-static void __exit wm9090_exit(void)
-{
-       i2c_del_driver(&wm9090_i2c_driver);
-}
-module_exit(wm9090_exit);
+module_i2c_driver(wm9090_i2c_driver);
 
 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
 MODULE_DESCRIPTION("WM9090 ASoC driver");
index 099e6ec321256009a99ba90c73fc66283cece2d4..c9c696ca76f72d408da00f3fdaa43bc1a57908ec 100644 (file)
@@ -146,7 +146,7 @@ SOC_SINGLE("Playback Attenuate (-6dB) Switch", AC97_MASTER_TONE, 6, 1, 0),
 SOC_SINGLE("Bass Volume", AC97_MASTER_TONE, 8, 15, 1),
 SOC_SINGLE("Treble Volume", AC97_MASTER_TONE, 0, 15, 1),
 
-SOC_SINGLE("Capture ADC Switch", AC97_REC_GAIN, 15, 1, 1),
+SOC_SINGLE("Capture Switch", AC97_REC_GAIN, 15, 1, 1),
 SOC_ENUM("Capture Volume Steps", wm9712_enum[6]),
 SOC_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 63, 1),
 SOC_SINGLE("Capture ZC Switch", AC97_REC_GAIN, 7, 1, 0),
@@ -619,6 +619,7 @@ static int wm9712_soc_probe(struct snd_soc_codec *codec)
 {
        int ret = 0;
 
+       codec->control_data = codec;    /* we don't use regmap! */
        ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
        if (ret < 0) {
                printk(KERN_ERR "wm9712: failed to register AC97 codec\n");
@@ -683,8 +684,8 @@ static int __devexit wm9712_remove(struct platform_device *pdev)
 
 static struct platform_driver wm9712_codec_driver = {
        .driver = {
-                       .name = "wm9712-codec",
-                       .owner = THIS_MODULE,
+               .name = "wm9712-codec",
+               .owner = THIS_MODULE,
        },
 
        .probe = wm9712_probe,
index 3eb19fb71d17209e0bccc071ed3f481471201276..d0b8a3287a8592af98dad706861fcb3b87460bbc 100644 (file)
@@ -1196,6 +1196,7 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec)
        if (wm9713 == NULL)
                return -ENOMEM;
        snd_soc_codec_set_drvdata(codec, wm9713);
+       codec->control_data = wm9713;   /* we don't use regmap! */
 
        ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0);
        if (ret < 0)
index 61baa48823cba20a7b8696824f333cb82bad2a1e..05a02e1b7e92028ca5644915acade877e3a6ac5e 100644 (file)
@@ -199,15 +199,56 @@ static void wm_hubs_dcs_cache_set(struct snd_soc_codec *codec, u16 dcs_cfg)
        list_add_tail(&cache->list, &hubs->dcs_cache);
 }
 
+static void wm_hubs_read_dc_servo(struct snd_soc_codec *codec,
+                                 u16 *reg_l, u16 *reg_r)
+{
+       struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
+       u16 dcs_reg, reg;
+
+       switch (hubs->dcs_readback_mode) {
+       case 2:
+               dcs_reg = WM8994_DC_SERVO_4E;
+               break;
+       case 1:
+               dcs_reg = WM8994_DC_SERVO_READBACK;
+               break;
+       default:
+               dcs_reg = WM8993_DC_SERVO_3;
+               break;
+       }
+
+       /* Different chips in the family support different readback
+        * methods.
+        */
+       switch (hubs->dcs_readback_mode) {
+       case 0:
+               *reg_l = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_1)
+                       & WM8993_DCS_INTEG_CHAN_0_MASK;
+               *reg_r = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_2)
+                       & WM8993_DCS_INTEG_CHAN_1_MASK;
+               break;
+       case 2:
+       case 1:
+               reg = snd_soc_read(codec, dcs_reg);
+               *reg_r = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK)
+                       >> WM8993_DCS_DAC_WR_VAL_1_SHIFT;
+               *reg_l = reg & WM8993_DCS_DAC_WR_VAL_0_MASK;
+               break;
+       default:
+               WARN(1, "Unknown DCS readback method\n");
+               return;
+       }
+}
+
 /*
  * Startup calibration of the DC servo
  */
-static void calibrate_dc_servo(struct snd_soc_codec *codec)
+static void enable_dc_servo(struct snd_soc_codec *codec)
 {
        struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
        struct wm_hubs_dcs_cache *cache;
        s8 offset;
-       u16 reg, reg_l, reg_r, dcs_cfg, dcs_reg;
+       u16 reg_l, reg_r, dcs_cfg, dcs_reg;
 
        switch (hubs->dcs_readback_mode) {
        case 2:
@@ -245,27 +286,7 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
                                  WM8993_DCS_TRIG_STARTUP_1);
        }
 
-       /* Different chips in the family support different readback
-        * methods.
-        */
-       switch (hubs->dcs_readback_mode) {
-       case 0:
-               reg_l = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_1)
-                       & WM8993_DCS_INTEG_CHAN_0_MASK;
-               reg_r = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_2)
-                       & WM8993_DCS_INTEG_CHAN_1_MASK;
-               break;
-       case 2:
-       case 1:
-               reg = snd_soc_read(codec, dcs_reg);
-               reg_r = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK)
-                       >> WM8993_DCS_DAC_WR_VAL_1_SHIFT;
-               reg_l = reg & WM8993_DCS_DAC_WR_VAL_0_MASK;
-               break;
-       default:
-               WARN(1, "Unknown DCS readback method\n");
-               return;
-       }
+       wm_hubs_read_dc_servo(codec, &reg_l, &reg_r);
 
        dev_dbg(codec->dev, "DCS input: %x %x\n", reg_l, reg_r);
 
@@ -535,7 +556,7 @@ static int hp_event(struct snd_soc_dapm_widget *w,
                snd_soc_update_bits(codec, WM8993_DC_SERVO_1,
                                    WM8993_DCS_TIMER_PERIOD_01_MASK, 0);
 
-               calibrate_dc_servo(codec);
+               enable_dc_servo(codec);
 
                reg |= WM8993_HPOUT1R_OUTP | WM8993_HPOUT1R_RMV_SHORT |
                        WM8993_HPOUT1L_OUTP | WM8993_HPOUT1L_RMV_SHORT;
@@ -1112,6 +1133,8 @@ int wm_hubs_add_analogue_routes(struct snd_soc_codec *codec,
        struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
        struct snd_soc_dapm_context *dapm = &codec->dapm;
 
+       hubs->codec = codec;
+
        INIT_LIST_HEAD(&hubs->dcs_cache);
        init_completion(&hubs->dcs_done);
 
index da2dc899ce6d58df7a4f34bd6f589ead6e4b2f3f..a5a09e6f87d56a466815e3ca3ef93e6027f7c42e 100644 (file)
@@ -46,6 +46,8 @@ struct wm_hubs_data {
 
        bool dcs_done_irq;
        struct completion dcs_done;
+
+       struct snd_soc_codec *codec;
 };
 
 extern int wm_hubs_add_analogue_controls(struct snd_soc_codec *);
index 10a2d8c788b73a434af2de950fdf3a3ad3652091..c80c20a89b1164e617ffdbd4560306bd7ec5da93 100644 (file)
@@ -24,7 +24,6 @@
 
 #include <mach/asp.h>
 #include <mach/edma.h>
-#include <mach/mux.h>
 
 #include "davinci-pcm.h"
 #include "davinci-i2s.h"
index 95441bfc819026071020915d6e4e3c53d2dec593..6a2c54c998be4ba133e247c6e7329cb364ae066e 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/io.h>
-#include <linux/clk.h>
+#include <linux/pm_runtime.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -380,14 +380,20 @@ static void mcasp_start_tx(struct davinci_audio_dev *dev)
 static void davinci_mcasp_start(struct davinci_audio_dev *dev, int stream)
 {
        if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
-               if (dev->txnumevt)      /* enable FIFO */
+               if (dev->txnumevt) {    /* enable FIFO */
+                       mcasp_clr_bits(dev->base + DAVINCI_MCASP_WFIFOCTL,
+                                                               FIFO_ENABLE);
                        mcasp_set_bits(dev->base + DAVINCI_MCASP_WFIFOCTL,
                                                                FIFO_ENABLE);
+               }
                mcasp_start_tx(dev);
        } else {
-               if (dev->rxnumevt)      /* enable FIFO */
+               if (dev->rxnumevt) {    /* enable FIFO */
+                       mcasp_clr_bits(dev->base + DAVINCI_MCASP_RFIFOCTL,
+                                                               FIFO_ENABLE);
                        mcasp_set_bits(dev->base + DAVINCI_MCASP_RFIFOCTL,
                                                                FIFO_ENABLE);
+               }
                mcasp_start_rx(dev);
        }
 }
@@ -776,20 +782,17 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream,
        case SNDRV_PCM_TRIGGER_RESUME:
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               if (!dev->clk_active) {
-                       clk_enable(dev->clk);
-                       dev->clk_active = 1;
-               }
+               ret = pm_runtime_get_sync(dev->dev);
+               if (IS_ERR_VALUE(ret))
+                       dev_err(dev->dev, "pm_runtime_get_sync() failed\n");
                davinci_mcasp_start(dev, substream->stream);
                break;
 
        case SNDRV_PCM_TRIGGER_SUSPEND:
                davinci_mcasp_stop(dev, substream->stream);
-               if (dev->clk_active) {
-                       clk_disable(dev->clk);
-                       dev->clk_active = 0;
-               }
-
+               ret = pm_runtime_put_sync(dev->dev);
+               if (IS_ERR_VALUE(ret))
+                       dev_err(dev->dev, "pm_runtime_put_sync() failed\n");
                break;
 
        case SNDRV_PCM_TRIGGER_STOP:
@@ -886,12 +889,13 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        }
 
        pdata = pdev->dev.platform_data;
-       dev->clk = clk_get(&pdev->dev, NULL);
-       if (IS_ERR(dev->clk))
-               return -ENODEV;
+       pm_runtime_enable(&pdev->dev);
 
-       clk_enable(dev->clk);
-       dev->clk_active = 1;
+       ret = pm_runtime_get_sync(&pdev->dev);
+       if (IS_ERR_VALUE(ret)) {
+               dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n");
+               return ret;
+       }
 
        dev->base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
        if (!dev->base) {
@@ -908,6 +912,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        dev->version = pdata->version;
        dev->txnumevt = pdata->txnumevt;
        dev->rxnumevt = pdata->rxnumevt;
+       dev->dev = &pdev->dev;
 
        dma_data = &dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK];
        dma_data->asp_chan_q = pdata->asp_chan_q;
@@ -949,19 +954,18 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
        return 0;
 
 err_release_clk:
-       clk_disable(dev->clk);
-       clk_put(dev->clk);
+       pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
        return ret;
 }
 
 static int davinci_mcasp_remove(struct platform_device *pdev)
 {
-       struct davinci_audio_dev *dev = dev_get_drvdata(&pdev->dev);
 
        snd_soc_unregister_dai(&pdev->dev);
-       clk_disable(dev->clk);
-       clk_put(dev->clk);
-       dev->clk = NULL;
+
+       pm_runtime_put_sync(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
 
        return 0;
 }
index 4681acc636061300efe053f56e214fc0eff1b98b..51479f9ee9094eed3c722412692389f42d0aaef6 100644 (file)
@@ -40,9 +40,8 @@ struct davinci_audio_dev {
        struct davinci_pcm_dma_params dma_params[2];
        void __iomem *base;
        int sample_rate;
-       struct clk *clk;
+       struct device *dev;
        unsigned int codec_fmt;
-       u8 clk_active;
 
        /* McASP specific data */
        int     tdm_slots;
index 28dd76c7cb1c08ac308ca7730d9abfc8b02b0903..7074ae6899844078ec9e57331f75f9412034c2de 100644 (file)
@@ -380,13 +380,14 @@ static int imx_ssi_dai_probe(struct snd_soc_dai *dai)
 static struct snd_soc_dai_driver imx_ssi_dai = {
        .probe = imx_ssi_dai_probe,
        .playback = {
-               .channels_min = 1,
+               /* The SSI does not support monaural audio. */
+               .channels_min = 2,
                .channels_max = 2,
                .rates = SNDRV_PCM_RATE_8000_96000,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,
        },
        .capture = {
-               .channels_min = 1,
+               .channels_min = 2,
                .channels_max = 2,
                .rates = SNDRV_PCM_RATE_8000_96000,
                .formats = SNDRV_PCM_FMTBIT_S16_LE,
@@ -523,7 +524,7 @@ static int imx_ssi_probe(struct platform_device *pdev)
        int ret = 0;
        struct snd_soc_dai_driver *dai;
 
-       ssi = kzalloc(sizeof(*ssi), GFP_KERNEL);
+       ssi = devm_kzalloc(&pdev->dev, sizeof(*ssi), GFP_KERNEL);
        if (!ssi)
                return -ENOMEM;
        dev_set_drvdata(&pdev->dev, ssi);
@@ -536,7 +537,7 @@ static int imx_ssi_probe(struct platform_device *pdev)
 
        ssi->irq = platform_get_irq(pdev, 0);
 
-       ssi->clk = clk_get(&pdev->dev, NULL);
+       ssi->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(ssi->clk)) {
                ret = PTR_ERR(ssi->clk);
                dev_err(&pdev->dev, "Cannot get the clock: %d\n",
@@ -551,23 +552,18 @@ static int imx_ssi_probe(struct platform_device *pdev)
                goto failed_get_resource;
        }
 
-       if (!request_mem_region(res->start, resource_size(res), DRV_NAME)) {
-               dev_err(&pdev->dev, "request_mem_region failed\n");
-               ret = -EBUSY;
-               goto failed_get_resource;
-       }
-
-       ssi->base = ioremap(res->start, resource_size(res));
+       ssi->base = devm_request_and_ioremap(&pdev->dev, res);
        if (!ssi->base) {
                dev_err(&pdev->dev, "ioremap failed\n");
                ret = -ENODEV;
-               goto failed_ioremap;
+               goto failed_register;
        }
 
        if (ssi->flags & IMX_SSI_USE_AC97) {
                if (ac97_ssi) {
+                       dev_err(&pdev->dev, "AC'97 SSI already registered\n");
                        ret = -EBUSY;
-                       goto failed_ac97;
+                       goto failed_register;
                }
                ac97_ssi = ssi;
                setup_channel_to_ac97(ssi);
@@ -636,15 +632,10 @@ failed_pdev_fiq_add:
 failed_pdev_fiq_alloc:
        snd_soc_unregister_dai(&pdev->dev);
 failed_register:
-failed_ac97:
-       iounmap(ssi->base);
-failed_ioremap:
        release_mem_region(res->start, resource_size(res));
 failed_get_resource:
        clk_disable_unprepare(ssi->clk);
-       clk_put(ssi->clk);
 failed_clk:
-       kfree(ssi);
 
        return ret;
 }
@@ -662,11 +653,8 @@ static int __devexit imx_ssi_remove(struct platform_device *pdev)
        if (ssi->flags & IMX_SSI_USE_AC97)
                ac97_ssi = NULL;
 
-       iounmap(ssi->base);
        release_mem_region(res->start, resource_size(res));
        clk_disable_unprepare(ssi->clk);
-       clk_put(ssi->clk);
-       kfree(ssi);
 
        return 0;
 }
index 99a997f19bb9d9f76c5fa7a93af992d7dce6b0eb..b6fa77678d97ec542a4585ff152b689c34370fd4 100644 (file)
@@ -10,7 +10,7 @@ menuconfig SND_MXS_SOC
 if SND_MXS_SOC
 
 config SND_SOC_MXS_SGTL5000
-       tristate "SoC Audio support for i.MX boards with sgtl5000"
+       tristate "SoC Audio support for MXS boards with sgtl5000"
        depends on I2C
        select SND_SOC_SGTL5000
        help
index aba71bfa33b15f0813f48a7a236bb61c5b5968b9..aa037b292f3dc05a9b6300c3cc4890988c0c2faf 100644 (file)
@@ -394,9 +394,14 @@ static int mxs_saif_hw_params(struct snd_pcm_substream *substream,
                             struct snd_soc_dai *cpu_dai)
 {
        struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai);
+       struct mxs_saif *master_saif;
        u32 scr, stat;
        int ret;
 
+       master_saif = mxs_saif_get_master(saif);
+       if (!master_saif)
+               return -EINVAL;
+
        /* mclk should already be set */
        if (!saif->mclk && saif->mclk_in_use) {
                dev_err(cpu_dai->dev, "set mclk first\n");
@@ -420,6 +425,25 @@ static int mxs_saif_hw_params(struct snd_pcm_substream *substream,
                return ret;
        }
 
+       /* prepare clk in hw_param, enable in trigger */
+       clk_prepare(saif->clk);
+       if (saif != master_saif) {
+               /*
+               * Set an initial clock rate for the saif internal logic to work
+               * properly. This is important when working in EXTMASTER mode
+               * that uses the other saif's BITCLK&LRCLK but it still needs a
+               * basic clock which should be fast enough for the internal
+               * logic.
+               */
+               clk_enable(saif->clk);
+               ret = clk_set_rate(saif->clk, 24000000);
+               clk_disable(saif->clk);
+               if (ret)
+                       return ret;
+
+               clk_prepare(master_saif->clk);
+       }
+
        scr = __raw_readl(saif->base + SAIF_CTRL);
 
        scr &= ~BM_SAIF_CTRL_WORD_LENGTH;
@@ -680,7 +704,7 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev)
                return ret;
        }
 
-       saif->clk = clk_get(&pdev->dev, NULL);
+       saif->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(saif->clk)) {
                ret = PTR_ERR(saif->clk);
                dev_err(&pdev->dev, "Cannot get the clock: %d\n",
@@ -693,8 +717,7 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev)
        saif->base = devm_request_and_ioremap(&pdev->dev, iores);
        if (!saif->base) {
                dev_err(&pdev->dev, "ioremap failed\n");
-               ret = -ENODEV;
-               goto failed_get_resource;
+               return -ENODEV;
        }
 
        dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
@@ -707,7 +730,7 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev)
                                           &saif->dma_param.chan_num);
                if (ret) {
                        dev_err(&pdev->dev, "failed to get dma channel\n");
-                       goto failed_get_resource;
+                       return ret;
                }
        } else {
                saif->dma_param.chan_num = dmares->start;
@@ -718,7 +741,7 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev)
                ret = saif->irq;
                dev_err(&pdev->dev, "failed to get irq resource: %d\n",
                        ret);
-               goto failed_get_resource;
+               return ret;
        }
 
        saif->dev = &pdev->dev;
@@ -726,7 +749,7 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev)
                               "mxs-saif", saif);
        if (ret) {
                dev_err(&pdev->dev, "failed to request irq\n");
-               goto failed_get_resource;
+               return ret;
        }
 
        saif->dma_param.chan_irq = platform_get_irq(pdev, 1);
@@ -734,7 +757,7 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev)
                ret = saif->dma_param.chan_irq;
                dev_err(&pdev->dev, "failed to get dma irq resource: %d\n",
                        ret);
-               goto failed_get_resource;
+               return ret;
        }
 
        platform_set_drvdata(pdev, saif);
@@ -742,7 +765,7 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev)
        ret = snd_soc_register_dai(&pdev->dev, &mxs_saif_dai);
        if (ret) {
                dev_err(&pdev->dev, "register DAI failed\n");
-               goto failed_get_resource;
+               return ret;
        }
 
        ret = mxs_pcm_platform_register(&pdev->dev);
@@ -755,19 +778,14 @@ static int __devinit mxs_saif_probe(struct platform_device *pdev)
 
 failed_pdev_alloc:
        snd_soc_unregister_dai(&pdev->dev);
-failed_get_resource:
-       clk_put(saif->clk);
 
        return ret;
 }
 
 static int __devexit mxs_saif_remove(struct platform_device *pdev)
 {
-       struct mxs_saif *saif = platform_get_drvdata(pdev);
-
        mxs_pcm_platform_unregister(&pdev->dev);
        snd_soc_unregister_dai(&pdev->dev);
-       clk_put(saif->clk);
 
        return 0;
 }
index 34835e8a9160ce16b1d074a1f8495d1124e5eac8..d33c48baaf711054da6e1c3f08f5a2e57d394057 100644 (file)
@@ -745,7 +745,7 @@ int omap_mcbsp_6pin_src_mux(struct omap_mcbsp *mcbsp, u8 mux)
 {
        const char *signal, *src;
 
-       if (mcbsp->pdata->mux_signal)
+       if (!mcbsp->pdata->mux_signal)
                return -EINVAL;
 
        switch (mux) {
index 9d93793d3077c61d8819760d4bd12b75e3896557..be525dfe9faa524402823872fccee5c57c548c44 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/mfd/twl6040.h>
 #include <linux/platform_data/omap-abe-twl6040.h>
 #include <linux/module.h>
+#include <linux/of.h>
 
 #include <sound/core.h>
 #include <sound/pcm.h>
@@ -43,6 +44,8 @@
 struct abe_twl6040 {
        int     jack_detection; /* board can detect jack events */
        int     mclk_freq;      /* MCLK frequency speed for twl6040 */
+
+       struct platform_device *dmic_codec_dev;
 };
 
 static int omap_abe_hw_params(struct snd_pcm_substream *substream,
@@ -185,17 +188,6 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd)
        int hs_trim;
        int ret = 0;
 
-       /* Disable not connected paths if not used */
-       twl6040_disconnect_pin(dapm, pdata->has_hs, "Headset Stereophone");
-       twl6040_disconnect_pin(dapm, pdata->has_hf, "Ext Spk");
-       twl6040_disconnect_pin(dapm, pdata->has_ep, "Earphone Spk");
-       twl6040_disconnect_pin(dapm, pdata->has_aux, "Line Out");
-       twl6040_disconnect_pin(dapm, pdata->has_vibra, "Vinrator");
-       twl6040_disconnect_pin(dapm, pdata->has_hsmic, "Headset Mic");
-       twl6040_disconnect_pin(dapm, pdata->has_mainmic, "Main Handset Mic");
-       twl6040_disconnect_pin(dapm, pdata->has_submic, "Sub Handset Mic");
-       twl6040_disconnect_pin(dapm, pdata->has_afm, "Line In");
-
        /*
         * Configure McPDM offset cancellation based on the HSOTRIM value from
         * twl6040.
@@ -216,6 +208,24 @@ static int omap_abe_twl6040_init(struct snd_soc_pcm_runtime *rtd)
                twl6040_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADSET);
        }
 
+       /*
+        * NULL pdata means we booted with DT. In this case the routing is
+        * provided and the card is fully routed, no need to mark pins.
+        */
+       if (!pdata)
+               return ret;
+
+       /* Disable not connected paths if not used */
+       twl6040_disconnect_pin(dapm, pdata->has_hs, "Headset Stereophone");
+       twl6040_disconnect_pin(dapm, pdata->has_hf, "Ext Spk");
+       twl6040_disconnect_pin(dapm, pdata->has_ep, "Earphone Spk");
+       twl6040_disconnect_pin(dapm, pdata->has_aux, "Line Out");
+       twl6040_disconnect_pin(dapm, pdata->has_vibra, "Vinrator");
+       twl6040_disconnect_pin(dapm, pdata->has_hsmic, "Headset Mic");
+       twl6040_disconnect_pin(dapm, pdata->has_mainmic, "Main Handset Mic");
+       twl6040_disconnect_pin(dapm, pdata->has_submic, "Sub Handset Mic");
+       twl6040_disconnect_pin(dapm, pdata->has_afm, "Line In");
+
        return ret;
 }
 
@@ -270,52 +280,116 @@ static struct snd_soc_card omap_abe_card = {
 static __devinit int omap_abe_probe(struct platform_device *pdev)
 {
        struct omap_abe_twl6040_data *pdata = dev_get_platdata(&pdev->dev);
+       struct device_node *node = pdev->dev.of_node;
        struct snd_soc_card *card = &omap_abe_card;
        struct abe_twl6040 *priv;
        int num_links = 0;
-       int ret;
+       int ret = 0;
 
        card->dev = &pdev->dev;
 
-       if (!pdata) {
-               dev_err(&pdev->dev, "Missing pdata\n");
-               return -ENODEV;
-       }
-
        priv = devm_kzalloc(&pdev->dev, sizeof(struct abe_twl6040), GFP_KERNEL);
        if (priv == NULL)
                return -ENOMEM;
 
-       if (pdata->card_name) {
-               card->name = pdata->card_name;
+       priv->dmic_codec_dev = ERR_PTR(-EINVAL);
+
+       if (node) {
+               struct device_node *dai_node;
+
+               if (snd_soc_of_parse_card_name(card, "ti,model")) {
+                       dev_err(&pdev->dev, "Card name is not provided\n");
+                       return -ENODEV;
+               }
+
+               ret = snd_soc_of_parse_audio_routing(card,
+                                               "ti,audio-routing");
+               if (ret) {
+                       dev_err(&pdev->dev,
+                               "Error while parsing DAPM routing\n");
+                       return ret;
+               }
+
+               dai_node = of_parse_phandle(node, "ti,mcpdm", 0);
+               if (!dai_node) {
+                       dev_err(&pdev->dev, "McPDM node is not provided\n");
+                       return -EINVAL;
+               }
+               abe_twl6040_dai_links[0].cpu_dai_name  = NULL;
+               abe_twl6040_dai_links[0].cpu_of_node = dai_node;
+
+               dai_node = of_parse_phandle(node, "ti,dmic", 0);
+               if (dai_node) {
+                       num_links = 2;
+                       abe_twl6040_dai_links[1].cpu_dai_name  = NULL;
+                       abe_twl6040_dai_links[1].cpu_of_node = dai_node;
+
+                       priv->dmic_codec_dev = platform_device_register_simple(
+                                               "dmic-codec", -1, NULL, 0);
+                       if (IS_ERR(priv->dmic_codec_dev)) {
+                               dev_err(&pdev->dev,
+                                       "Can't instantiate dmic-codec\n");
+                               return PTR_ERR(priv->dmic_codec_dev);
+                       }
+               } else {
+                       num_links = 1;
+               }
+
+               of_property_read_u32(node, "ti,jack-detection",
+                                    &priv->jack_detection);
+               of_property_read_u32(node, "ti,mclk-freq",
+                                    &priv->mclk_freq);
+               if (!priv->mclk_freq) {
+                       dev_err(&pdev->dev, "MCLK frequency not provided\n");
+                       ret = -EINVAL;
+                       goto err_unregister;
+               }
+
+               omap_abe_card.fully_routed = 1;
+       } else if (pdata) {
+               if (pdata->card_name) {
+                       card->name = pdata->card_name;
+               } else {
+                       dev_err(&pdev->dev, "Card name is not provided\n");
+                       return -ENODEV;
+               }
+
+               if (pdata->has_dmic)
+                       num_links = 2;
+               else
+                       num_links = 1;
+
+               priv->jack_detection = pdata->jack_detection;
+               priv->mclk_freq = pdata->mclk_freq;
        } else {
-               dev_err(&pdev->dev, "Card name is not provided\n");
+               dev_err(&pdev->dev, "Missing pdata\n");
                return -ENODEV;
        }
 
-       priv->jack_detection = pdata->jack_detection;
-       priv->mclk_freq = pdata->mclk_freq;
-
 
        if (!priv->mclk_freq) {
                dev_err(&pdev->dev, "MCLK frequency missing\n");
-               return -ENODEV;
+               ret = -ENODEV;
+               goto err_unregister;
        }
 
-       if (pdata->has_dmic)
-               num_links = 2;
-       else
-               num_links = 1;
-
        card->dai_link = abe_twl6040_dai_links;
        card->num_links = num_links;
 
        snd_soc_card_set_drvdata(card, priv);
 
        ret = snd_soc_register_card(card);
-       if (ret)
+       if (ret) {
                dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
                        ret);
+               goto err_unregister;
+       }
+
+       return 0;
+
+err_unregister:
+       if (!IS_ERR(priv->dmic_codec_dev))
+               platform_device_unregister(priv->dmic_codec_dev);
 
        return ret;
 }
@@ -323,17 +397,28 @@ static __devinit int omap_abe_probe(struct platform_device *pdev)
 static int __devexit omap_abe_remove(struct platform_device *pdev)
 {
        struct snd_soc_card *card = platform_get_drvdata(pdev);
+       struct abe_twl6040 *priv = snd_soc_card_get_drvdata(card);
 
        snd_soc_unregister_card(card);
 
+       if (!IS_ERR(priv->dmic_codec_dev))
+               platform_device_unregister(priv->dmic_codec_dev);
+
        return 0;
 }
 
+static const struct of_device_id omap_abe_of_match[] = {
+       {.compatible = "ti,abe-twl6040", },
+       { },
+};
+MODULE_DEVICE_TABLE(of, omap_abe_of_match);
+
 static struct platform_driver omap_abe_driver = {
        .driver = {
                .name = "omap-abe-twl6040",
                .owner = THIS_MODULE,
                .pm = &snd_soc_pm_ops,
+               .of_match_table = omap_abe_of_match,
        },
        .probe = omap_abe_probe,
        .remove = __devexit_p(omap_abe_remove),
index 1046083e90a079f594b99ef0f88b72bb7e8e5150..acdd3ef14e08c59821d2ae18f7795c0b590e3df0 100644 (file)
@@ -820,3 +820,4 @@ module_platform_driver(asoc_mcbsp_driver);
 MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>");
 MODULE_DESCRIPTION("OMAP I2S SoC Interface");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:omap-mcbsp");
index 2c66e2498a453b3c6fcf29c2ea008429f47138ca..f7babb374a3726085086173e18c5182c60a7abf3 100644 (file)
@@ -445,9 +445,8 @@ static __devinit int asoc_mcpdm_probe(struct platform_device *pdev)
 {
        struct omap_mcpdm *mcpdm;
        struct resource *res;
-       int ret = 0;
 
-       mcpdm = kzalloc(sizeof(struct omap_mcpdm), GFP_KERNEL);
+       mcpdm = devm_kzalloc(&pdev->dev, sizeof(struct omap_mcpdm), GFP_KERNEL);
        if (!mcpdm)
                return -ENOMEM;
 
@@ -456,55 +455,30 @@ static __devinit int asoc_mcpdm_probe(struct platform_device *pdev)
        mutex_init(&mcpdm->mutex);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (res == NULL) {
-               dev_err(&pdev->dev, "no resource\n");
-               goto err_res;
-       }
+       if (res == NULL)
+               return -ENOMEM;
 
-       if (!request_mem_region(res->start, resource_size(res), "McPDM")) {
-               ret = -EBUSY;
-               goto err_res;
-       }
+       if (!devm_request_mem_region(&pdev->dev, res->start,
+                                    resource_size(res), "McPDM"))
+               return -EBUSY;
 
-       mcpdm->io_base = ioremap(res->start, resource_size(res));
-       if (!mcpdm->io_base) {
-               ret = -ENOMEM;
-               goto err_iomap;
-       }
+       mcpdm->io_base = devm_ioremap(&pdev->dev, res->start,
+                                     resource_size(res));
+       if (!mcpdm->io_base)
+               return -ENOMEM;
 
        mcpdm->irq = platform_get_irq(pdev, 0);
-       if (mcpdm->irq < 0) {
-               ret = mcpdm->irq;
-               goto err_irq;
-       }
+       if (mcpdm->irq < 0)
+               return mcpdm->irq;
 
        mcpdm->dev = &pdev->dev;
 
-       ret = snd_soc_register_dai(&pdev->dev, &omap_mcpdm_dai);
-       if (!ret)
-               return 0;
-
-err_irq:
-       iounmap(mcpdm->io_base);
-err_iomap:
-       release_mem_region(res->start, resource_size(res));
-err_res:
-       kfree(mcpdm);
-       return ret;
+       return snd_soc_register_dai(&pdev->dev, &omap_mcpdm_dai);
 }
 
 static int __devexit asoc_mcpdm_remove(struct platform_device *pdev)
 {
-       struct omap_mcpdm *mcpdm = platform_get_drvdata(pdev);
-       struct resource *res;
-
        snd_soc_unregister_dai(&pdev->dev);
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       iounmap(mcpdm->io_base);
-       release_mem_region(res->start, resource_size(res));
-
-       kfree(mcpdm);
        return 0;
 }
 
index 5a649da9122a3e798713999a766885f0f732a5cd..f0feb06615f8ea355711239b4ffbd74516221a3e 100644 (file)
@@ -441,3 +441,4 @@ module_platform_driver(omap_pcm_driver);
 MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>");
 MODULE_DESCRIPTION("OMAP PCM DMA module");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:omap-pcm-audio");
index fe3995ce9b380f00674d0841e29269fdf422d1eb..fb56000836127ed910d096dff9e0c7249111bdf8 100644 (file)
@@ -199,6 +199,14 @@ config SND_SOC_TOBERMORY
        select SND_SAMSUNG_I2S
        select SND_SOC_WM8962
 
+config SND_SOC_BELLS
+       tristate "Audio support for Wolfson Bells"
+       depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410
+       select SND_SAMSUNG_I2S
+       select SND_SOC_WM5102
+       select SND_SOC_WM5110
+       select SND_SOC_WM9081
+
 config SND_SOC_LOWLAND
        tristate "Audio support for Wolfson Lowland"
        depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410
index 9d03beb40c86909e51671f531ef67e43fe73a0d8..709f6059ad67da928245a2faf3df900552e82d44 100644 (file)
@@ -42,6 +42,7 @@ snd-soc-speyside-objs := speyside.o
 snd-soc-tobermory-objs := tobermory.o
 snd-soc-lowland-objs := lowland.o
 snd-soc-littlemill-objs := littlemill.o
+snd-soc-bells-objs := bells.o
 
 obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o
 obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
@@ -65,3 +66,4 @@ obj-$(CONFIG_SND_SOC_SPEYSIDE) += snd-soc-speyside.o
 obj-$(CONFIG_SND_SOC_TOBERMORY) += snd-soc-tobermory.o
 obj-$(CONFIG_SND_SOC_LOWLAND) += snd-soc-lowland.o
 obj-$(CONFIG_SND_SOC_LITTLEMILL) += snd-soc-littlemill.o
+obj-$(CONFIG_SND_SOC_BELLS) += snd-soc-bells.o
diff --git a/sound/soc/samsung/bells.c b/sound/soc/samsung/bells.c
new file mode 100644 (file)
index 0000000..5dc10df
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+ * Bells audio support
+ *
+ * Copyright 2012 Wolfson Microelectronics
+ *
+ * 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 <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+
+#include "../codecs/wm5102.h"
+#include "../codecs/wm9081.h"
+
+/*
+ * 44.1kHz based clocks for the SYSCLK domain, use a very high clock
+ * to allow all the DSP functionality to be enabled if desired.
+ */
+#define SYSCLK_RATE (44100 * 1024)
+
+/* 48kHz based clocks for the ASYNC domain */
+#define ASYNCCLK_RATE (48000 * 512)
+
+/* BCLK2 is fixed at this currently */
+#define BCLK2_RATE (64 * 8000)
+
+/*
+ * Expect a 24.576MHz crystal if one is fitted (the driver will function
+ * if this is not fitted).
+ */
+#define MCLK_RATE 24576000
+
+#define WM9081_AUDIO_RATE 44100
+#define WM9081_MCLK_RATE  (WM9081_AUDIO_RATE * 256)
+
+static int bells_set_bias_level(struct snd_soc_card *card,
+                               struct snd_soc_dapm_context *dapm,
+                               enum snd_soc_bias_level level)
+{
+       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+       struct snd_soc_codec *codec = codec_dai->codec;
+       int ret;
+
+       if (dapm->dev != codec_dai->dev)
+               return 0;
+
+       switch (level) {
+       case SND_SOC_BIAS_PREPARE:
+               if (dapm->bias_level == SND_SOC_BIAS_STANDBY) {
+                       ret = snd_soc_codec_set_pll(codec, WM5102_FLL1,
+                                                   ARIZONA_FLL_SRC_MCLK1,
+                                                   MCLK_RATE,
+                                                   SYSCLK_RATE);
+                       if (ret < 0)
+                               pr_err("Failed to start FLL: %d\n", ret);
+
+                       ret = snd_soc_codec_set_pll(codec, WM5102_FLL2,
+                                                   ARIZONA_FLL_SRC_AIF2BCLK,
+                                                   BCLK2_RATE,
+                                                   ASYNCCLK_RATE);
+                       if (ret < 0)
+                               pr_err("Failed to start FLL: %d\n", ret);
+               }
+               break;
+
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int bells_set_bias_level_post(struct snd_soc_card *card,
+                                    struct snd_soc_dapm_context *dapm,
+                                    enum snd_soc_bias_level level)
+{
+       struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai;
+       struct snd_soc_codec *codec = codec_dai->codec;
+       int ret;
+
+       if (dapm->dev != codec_dai->dev)
+               return 0;
+
+       switch (level) {
+       case SND_SOC_BIAS_STANDBY:
+               ret = snd_soc_codec_set_pll(codec, WM5102_FLL1, 0, 0, 0);
+               if (ret < 0) {
+                       pr_err("Failed to stop FLL: %d\n", ret);
+                       return ret;
+               }
+
+               ret = snd_soc_codec_set_pll(codec, WM5102_FLL2, 0, 0, 0);
+               if (ret < 0) {
+                       pr_err("Failed to stop FLL: %d\n", ret);
+                       return ret;
+               }
+               break;
+
+       default:
+               break;
+       }
+
+       dapm->bias_level = level;
+
+       return 0;
+}
+
+static int bells_late_probe(struct snd_soc_card *card)
+{
+       struct snd_soc_codec *codec = card->rtd[0].codec;
+       struct snd_soc_dai *aif1_dai = card->rtd[0].codec_dai;
+       struct snd_soc_dai *aif2_dai = card->rtd[1].cpu_dai;
+       struct snd_soc_dai *aif3_dai = card->rtd[2].cpu_dai;
+       struct snd_soc_dai *wm9081_dai = card->rtd[2].codec_dai;
+       int ret;
+
+       ret = snd_soc_dai_set_sysclk(aif1_dai, ARIZONA_CLK_SYSCLK, 0, 0);
+       if (ret != 0) {
+               dev_err(aif1_dai->dev, "Failed to set AIF1 clock: %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_dai_set_sysclk(aif2_dai, ARIZONA_CLK_ASYNCCLK, 0, 0);
+       if (ret != 0) {
+               dev_err(aif2_dai->dev, "Failed to set AIF2 clock: %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_dai_set_sysclk(aif3_dai, ARIZONA_CLK_SYSCLK, 0, 0);
+       if (ret != 0) {
+               dev_err(aif1_dai->dev, "Failed to set AIF1 clock: %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK,
+                                      ARIZONA_CLK_SRC_FLL1, SYSCLK_RATE,
+                                      SND_SOC_CLOCK_IN);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to set SYSCLK: %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_OPCLK, 0,
+                                      WM9081_MCLK_RATE, SND_SOC_CLOCK_OUT);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to set OPCLK: %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_ASYNCCLK,
+                                      ARIZONA_CLK_SRC_FLL2, ASYNCCLK_RATE,
+                                      SND_SOC_CLOCK_IN);
+       if (ret != 0) {
+               dev_err(codec->dev, "Failed to set SYSCLK: %d\n", ret);
+               return ret;
+       }
+
+       ret = snd_soc_codec_set_sysclk(wm9081_dai->codec, WM9081_SYSCLK_MCLK,
+                                      0, WM9081_MCLK_RATE, 0);
+       if (ret != 0) {
+               dev_err(wm9081_dai->dev, "Failed to set MCLK: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static const struct snd_soc_pcm_stream baseband_params = {
+       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+       .rate_min = 8000,
+       .rate_max = 8000,
+       .channels_min = 2,
+       .channels_max = 2,
+};
+
+static const struct snd_soc_pcm_stream sub_params = {
+       .formats = SNDRV_PCM_FMTBIT_S32_LE,
+       .rate_min = WM9081_AUDIO_RATE,
+       .rate_max = WM9081_AUDIO_RATE,
+       .channels_min = 2,
+       .channels_max = 2,
+};
+
+static struct snd_soc_dai_link bells_dai_wm5102[] = {
+       {
+               .name = "CPU",
+               .stream_name = "CPU",
+               .cpu_dai_name = "samsung-i2s.0",
+               .codec_dai_name = "wm5102-aif1",
+               .platform_name = "samsung-audio",
+               .codec_name = "wm5102-codec",
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+                               | SND_SOC_DAIFMT_CBM_CFM,
+       },
+       {
+               .name = "Baseband",
+               .stream_name = "Baseband",
+               .cpu_dai_name = "wm5102-aif2",
+               .codec_dai_name = "wm1250-ev1",
+               .codec_name = "wm1250-ev1.1-0027",
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+                               | SND_SOC_DAIFMT_CBM_CFM,
+               .ignore_suspend = 1,
+               .params = &baseband_params,
+       },
+       {
+               .name = "Sub",
+               .stream_name = "Sub",
+               .cpu_dai_name = "wm5102-aif3",
+               .codec_dai_name = "wm9081-hifi",
+               .codec_name = "wm9081.1-006c",
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+                               | SND_SOC_DAIFMT_CBS_CFS,
+               .ignore_suspend = 1,
+               .params = &sub_params,
+       },
+};
+
+static struct snd_soc_dai_link bells_dai_wm5110[] = {
+       {
+               .name = "CPU",
+               .stream_name = "CPU",
+               .cpu_dai_name = "samsung-i2s.0",
+               .codec_dai_name = "wm5110-aif1",
+               .platform_name = "samsung-audio",
+               .codec_name = "wm5110-codec",
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+                               | SND_SOC_DAIFMT_CBM_CFM,
+       },
+       {
+               .name = "Baseband",
+               .stream_name = "Baseband",
+               .cpu_dai_name = "wm5110-aif2",
+               .codec_dai_name = "wm1250-ev1",
+               .codec_name = "wm1250-ev1.1-0027",
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+                               | SND_SOC_DAIFMT_CBM_CFM,
+               .ignore_suspend = 1,
+               .params = &baseband_params,
+       },
+       {
+               .name = "Sub",
+               .stream_name = "Sub",
+               .cpu_dai_name = "wm5102-aif3",
+               .codec_dai_name = "wm9081-hifi",
+               .codec_name = "wm9081.1-006c",
+               .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+                               | SND_SOC_DAIFMT_CBS_CFS,
+               .ignore_suspend = 1,
+               .params = &sub_params,
+       },
+};
+
+static struct snd_soc_codec_conf bells_codec_conf[] = {
+       {
+               .dev_name = "wm9081.1-006c",
+               .name_prefix = "Sub",
+       },
+};
+
+static struct snd_soc_dapm_route bells_routes[] = {
+       { "Sub CLK_SYS", NULL, "OPCLK" },
+};
+
+static struct snd_soc_card bells_cards[] = {
+       {
+               .name = "Bells WM5102",
+               .owner = THIS_MODULE,
+               .dai_link = bells_dai_wm5102,
+               .num_links = ARRAY_SIZE(bells_dai_wm5102),
+               .codec_conf = bells_codec_conf,
+               .num_configs = ARRAY_SIZE(bells_codec_conf),
+
+               .late_probe = bells_late_probe,
+
+               .dapm_routes = bells_routes,
+               .num_dapm_routes = ARRAY_SIZE(bells_routes),
+
+               .set_bias_level = bells_set_bias_level,
+               .set_bias_level_post = bells_set_bias_level_post,
+       },
+       {
+               .name = "Bells WM5110",
+               .owner = THIS_MODULE,
+               .dai_link = bells_dai_wm5110,
+               .num_links = ARRAY_SIZE(bells_dai_wm5110),
+               .codec_conf = bells_codec_conf,
+               .num_configs = ARRAY_SIZE(bells_codec_conf),
+
+               .late_probe = bells_late_probe,
+
+               .dapm_routes = bells_routes,
+               .num_dapm_routes = ARRAY_SIZE(bells_routes),
+
+               .set_bias_level = bells_set_bias_level,
+               .set_bias_level_post = bells_set_bias_level_post,
+       },
+};
+
+
+static __devinit int bells_probe(struct platform_device *pdev)
+{
+       int ret;
+
+       bells_cards[pdev->id].dev = &pdev->dev;
+
+       ret = snd_soc_register_card(&bells_cards[pdev->id]);
+       if (ret) {
+               dev_err(&pdev->dev,
+                       "snd_soc_register_card(%s) failed: %d\n",
+                       bells_cards[pdev->id].name, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int __devexit bells_remove(struct platform_device *pdev)
+{
+       snd_soc_unregister_card(&bells_cards[pdev->id]);
+
+       return 0;
+}
+
+static struct platform_driver bells_driver = {
+       .driver = {
+               .name = "bells",
+               .owner = THIS_MODULE,
+               .pm = &snd_soc_pm_ops,
+       },
+       .probe = bells_probe,
+       .remove = __devexit_p(bells_remove),
+};
+
+module_platform_driver(bells_driver);
+
+MODULE_DESCRIPTION("Bells audio support");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:bells");
index b7b2a1f9142521d931a94fe65cd5ea9a580869d2..89b064650f1492ffc828367ef34c89cbc82800c7 100644 (file)
@@ -20,7 +20,7 @@
 #include <sound/pcm_params.h>
 
 #include <plat/audio.h>
-#include <plat/dma.h>
+#include <mach/dma.h>
 
 #include "dma.h"
 #include "pcm.h"
index f219b2f7ee682c795bcf12ec2bea9b9855506b6f..7adf115f75cbd9b04bbc7a7dcbc7de5c798b80b8 100644 (file)
@@ -826,7 +826,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
        }
 
        if (!rtd->cpu_dai) {
-               dev_dbg(card->dev, "CPU DAI %s not registered\n",
+               dev_err(card->dev, "CPU DAI %s not registered\n",
                        dai_link->cpu_dai_name);
                return -EPROBE_DEFER;
        }
@@ -857,14 +857,14 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
                }
 
                if (!rtd->codec_dai) {
-                       dev_dbg(card->dev, "CODEC DAI %s not registered\n",
+                       dev_err(card->dev, "CODEC DAI %s not registered\n",
                                dai_link->codec_dai_name);
                        return -EPROBE_DEFER;
                }
        }
 
        if (!rtd->codec) {
-               dev_dbg(card->dev, "CODEC %s not registered\n",
+               dev_err(card->dev, "CODEC %s not registered\n",
                        dai_link->codec_name);
                return -EPROBE_DEFER;
        }
@@ -888,7 +888,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num)
                rtd->platform = platform;
        }
        if (!rtd->platform) {
-               dev_dbg(card->dev, "platform %s not registered\n",
+               dev_err(card->dev, "platform %s not registered\n",
                        dai_link->platform_name);
                return -EPROBE_DEFER;
        }
@@ -1096,7 +1096,7 @@ static int soc_probe_codec(struct snd_soc_card *card,
        }
 
        /* If the driver didn't set I/O up try regmap */
-       if (!codec->control_data)
+       if (!codec->write && dev_get_regmap(codec->dev, NULL))
                snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
 
        if (driver->controls)
@@ -1481,6 +1481,8 @@ static int soc_check_aux_dev(struct snd_soc_card *card, int num)
                        return 0;
        }
 
+       dev_err(card->dev, "%s not registered\n", aux_dev->codec_name);
+
        return -EPROBE_DEFER;
 }
 
@@ -1814,7 +1816,6 @@ base_error:
 static int soc_probe(struct platform_device *pdev)
 {
        struct snd_soc_card *card = platform_get_drvdata(pdev);
-       int ret = 0;
 
        /*
         * no card, so machine driver should be registering card
@@ -1830,13 +1831,7 @@ static int soc_probe(struct platform_device *pdev)
        /* Bodge while we unpick instantiation */
        card->dev = &pdev->dev;
 
-       ret = snd_soc_register_card(card);
-       if (ret != 0) {
-               dev_err(&pdev->dev, "Failed to register card\n");
-               return ret;
-       }
-
-       return 0;
+       return snd_soc_register_card(card);
 }
 
 static int soc_cleanup_card_resources(struct snd_soc_card *card)
@@ -3715,6 +3710,9 @@ int snd_soc_register_dai(struct device *dev,
                }
        }
 
+       if (!dai->codec)
+               dai->dapm.idle_bias_off = 1;
+
        list_add(&dai->list, &dai_list);
 
        mutex_unlock(&client_mutex);
@@ -3803,6 +3801,9 @@ int snd_soc_register_dais(struct device *dev,
                        }
                }
 
+               if (!dai->codec)
+                       dai->dapm.idle_bias_off = 1;
+
                list_add(&dai->list, &dai_list);
 
                mutex_unlock(&client_mutex);
index 7f8b3b7428bbf12c60f603fff8fbb8d3989fa254..fa0fd8ddae90fc17f280543c9399741c9a33038b 100644 (file)
@@ -83,11 +83,6 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)
        jack->status &= ~mask;
        jack->status |= status & mask;
 
-       /* The DAPM sync is expensive enough to be worth skipping.
-        * However, empty mask means pin synchronization is desired. */
-       if (mask && (jack->status == oldstatus))
-               goto out;
-
        trace_snd_soc_jack_notify(jack, status);
 
        list_for_each_entry(pin, &jack->pins, list) {
@@ -103,13 +98,12 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask)
        }
 
        /* Report before the DAPM sync to help users updating micbias status */
-       blocking_notifier_call_chain(&jack->notifier, status, jack);
+       blocking_notifier_call_chain(&jack->notifier, jack->status, jack);
 
        snd_soc_dapm_sync(dapm);
 
        snd_jack_report(jack->jack, jack->status);
 
-out:
        mutex_unlock(&jack->mutex);
 }
 EXPORT_SYMBOL_GPL(snd_soc_jack_report);
index d684df294c0c5c80458b6de591c16965027db14b..e463529b38bbfbfd35cc745bf430f68399bfee91 100644 (file)
@@ -177,7 +177,7 @@ static __devinit int tegra_alc5632_probe(struct platform_device *pdev)
        }
 
        alc5632->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0);
-       if (alc5632->gpio_hp_det == -ENODEV)
+       if (alc5632->gpio_hp_det == -EPROBE_DEFER)
                return -EPROBE_DEFER;
 
        ret = snd_soc_of_parse_card_name(card, "nvidia,model");
index 0c5bb33d258e1aeda033924e92598caa5c372d41..d4f14e492341f3751446057b68ee8d61f0c9bfbd 100644 (file)
@@ -284,27 +284,27 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev)
        } else if (np) {
                pdata->gpio_spkr_en = of_get_named_gpio(np,
                                                "nvidia,spkr-en-gpios", 0);
-               if (pdata->gpio_spkr_en == -ENODEV)
+               if (pdata->gpio_spkr_en == -EPROBE_DEFER)
                        return -EPROBE_DEFER;
 
                pdata->gpio_hp_mute = of_get_named_gpio(np,
                                                "nvidia,hp-mute-gpios", 0);
-               if (pdata->gpio_hp_mute == -ENODEV)
+               if (pdata->gpio_hp_mute == -EPROBE_DEFER)
                        return -EPROBE_DEFER;
 
                pdata->gpio_hp_det = of_get_named_gpio(np,
                                                "nvidia,hp-det-gpios", 0);
-               if (pdata->gpio_hp_det == -ENODEV)
+               if (pdata->gpio_hp_det == -EPROBE_DEFER)
                        return -EPROBE_DEFER;
 
                pdata->gpio_int_mic_en = of_get_named_gpio(np,
                                                "nvidia,int-mic-en-gpios", 0);
-               if (pdata->gpio_int_mic_en == -ENODEV)
+               if (pdata->gpio_int_mic_en == -EPROBE_DEFER)
                        return -EPROBE_DEFER;
 
                pdata->gpio_ext_mic_en = of_get_named_gpio(np,
                                                "nvidia,ext-mic-en-gpios", 0);
-               if (pdata->gpio_ext_mic_en == -ENODEV)
+               if (pdata->gpio_ext_mic_en == -EPROBE_DEFER)
                        return -EPROBE_DEFER;
        }
 
index 62ac0285bfaffe367f0c3ddfb36bac52cb6113e2..772cb19d2fb328ddd29e6dc4c8fddf73bd02c291 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/mfd/dbx500-prcmu.h>
 
 #include <mach/hardware.h>
-#include <mach/board-mop500-msp.h>
+#include <mach/msp.h>
 
 #include <sound/soc.h>
 #include <sound/soc-dai.h>
@@ -760,6 +760,9 @@ static int __devinit ux500_msp_drv_probe(struct platform_device *pdev)
        drvdata = devm_kzalloc(&pdev->dev,
                                sizeof(struct ux500_msp_i2s_drvdata),
                                GFP_KERNEL);
+       if (!drvdata)
+               return -ENOMEM;
+
        drvdata->fmt = 0;
        drvdata->slots = 1;
        drvdata->tx_mask = 0x01;
index ee14d2dac2f53c4e328f622bf6566afbd193c309..36be11e47ad60b7eb0f8fe909e24d45393baee13 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/slab.h>
 
 #include <mach/hardware.h>
-#include <mach/board-mop500-msp.h>
+#include <mach/msp.h>
 
 #include <sound/soc.h>
 
@@ -673,6 +673,8 @@ int ux500_msp_i2s_init_msp(struct platform_device *pdev,
 
        *msp_p = devm_kzalloc(&pdev->dev, sizeof(struct ux500_msp), GFP_KERNEL);
        msp = *msp_p;
+       if (!msp)
+               return -ENOMEM;
 
        msp->id = platform_data->id;
        msp->dev = &pdev->dev;
index 7f71b4a0d4bc3b391c0633f8c2d6205d156d1511..2d9136da9865f18548d3ccc23548f286b8a994e4 100644 (file)
@@ -17,7 +17,7 @@
 
 #include <linux/platform_device.h>
 
-#include <mach/board-mop500-msp.h>
+#include <mach/msp.h>
 
 #define MSP_INPUT_FREQ_APB 48000000
 
index 56ad923bf6b5cb74db2f5a56cdc2a16807c66a03..a1d9b0792a1e5b1b68816ad794a77fb76bae2398 100644 (file)
@@ -346,11 +346,10 @@ static int usb6fire_fw_check(u8 *version)
                if (!memcmp(version, known_fw_versions + i, 4))
                        return 0;
 
-       snd_printk(KERN_ERR PREFIX "invalid fimware version in device: "
-                       "%02x %02x %02x %02x. "
+       snd_printk(KERN_ERR PREFIX "invalid fimware version in device: %*ph. "
                        "please reconnect to power. if this failure "
                        "still happens, check your firmware installation.",
-                       version[0], version[1], version[2], version[3]);
+                       4, version);
        return -EINVAL;
 }
 
index 0f647d22cb4ac7bccffe25311011255cf0b33104..c411812026884408afd74f1e580f2e87bbe747fc 100644 (file)
@@ -821,10 +821,6 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep)
        if (++ep->use_count != 1)
                return 0;
 
-       /* just to be sure */
-       deactivate_urbs(ep, 0, 1);
-       wait_clear_urbs(ep);
-
        ep->active_mask = 0;
        ep->unlink_mask = 0;
        ep->phase = 0;
index a1298f379428280045bf661f89e5fa59bb0acb48..62ec808ed792503e789ea26eb74837998623915e 100644 (file)
@@ -544,6 +544,9 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
        subs->last_frame_number = 0;
        runtime->delay = 0;
 
+       /* clear the pending deactivation on the target EPs */
+       deactivate_endpoints(subs);
+
        /* for playback, submit the URBs now; otherwise, the first hwptr_done
         * updates for all URBs would happen at the same time when starting */
        if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK)
diff --git a/tools/kvm/.gitignore b/tools/kvm/.gitignore
new file mode 100644 (file)
index 0000000..60dd6db
--- /dev/null
@@ -0,0 +1,12 @@
+/lkvm
+/vm
+*.o
+*.d
+.cscope
+tags
+include/common-cmds.h
+tests/boot/boot_test.iso
+tests/boot/rootfs/
+guest/init
+guest/init_stage2
+KVMTOOLS-VERSION-FILE
diff --git a/tools/kvm/CREDITS-Git b/tools/kvm/CREDITS-Git
new file mode 100644 (file)
index 0000000..c2ddcb3
--- /dev/null
@@ -0,0 +1,30 @@
+Most of the infrastructure that 'perf' uses here has been reused
+from the Git project, as of version:
+
+    66996ec: Sync with 1.6.2.4
+
+Here is an (incomplete!) list of main contributors to those files
+in util/* and elsewhere:
+
+ Alex Riesen
+ Christian Couder
+ Dmitry Potapov
+ Jeff King
+ Johannes Schindelin
+ Johannes Sixt
+ Junio C Hamano
+ Linus Torvalds
+ Matthias Kestenholz
+ Michal Ostrowski
+ Miklos Vajna
+ Petr Baudis
+ Pierre Habouzit
+ René Scharfe
+ Samuel Tardieu
+ Shawn O. Pearce
+ Steffen Prohaska
+ Steve Haslam
+
+Thanks guys!
+
+The full history of the files can be found in the upstream Git commits.
diff --git a/tools/kvm/Documentation/kernel-debugging.txt b/tools/kvm/Documentation/kernel-debugging.txt
new file mode 100644 (file)
index 0000000..98b9438
--- /dev/null
@@ -0,0 +1,15 @@
+This document explains how to debug a guests' kernel using KGDB.
+
+1. Run the guest:
+        'lkvm run -k [vmlinuz] -p "kgdboc=ttyS1 kgdbwait" --tty 1'
+
+And see which PTY got assigned to ttyS1 (you'll see:
+'  Info: Assigned terminal 1 to pty /dev/pts/X').
+
+2. Run GDB on the host:
+        'gdb [vmlinuz]'
+
+3. Connect to the guest (from within GDB):
+        'target remote /dev/pty/X'
+
+4. Start debugging! (enter 'continue' to continue boot).
diff --git a/tools/kvm/Documentation/kvm-balloon.txt b/tools/kvm/Documentation/kvm-balloon.txt
new file mode 100644 (file)
index 0000000..efc0a87
--- /dev/null
@@ -0,0 +1,24 @@
+lkvm-balloon(1)
+================
+
+NAME
+----
+lkvm-balloon - Inflate or deflate the virtio balloon
+
+SYNOPSIS
+--------
+[verse]
+'lkvm balloon [command] [size] [instance]'
+
+DESCRIPTION
+-----------
+The command inflates or deflates the virtio balloon located in the
+specified instance.
+For a list of running instances see 'lkvm list'.
+
+Command can be either 'inflate' or 'deflate'. Inflate increases the
+size of the balloon, thus decreasing the amount of virtual RAM available
+for the guest. Deflation returns previously inflated memory back to the
+guest.
+
+size is specified in Mb.
diff --git a/tools/kvm/Documentation/kvm-debug.txt b/tools/kvm/Documentation/kvm-debug.txt
new file mode 100644 (file)
index 0000000..a8eb2c0
--- /dev/null
@@ -0,0 +1,16 @@
+lkvm-debug(1)
+================
+
+NAME
+----
+lkvm-debug - Print debug information from a running instance
+
+SYNOPSIS
+--------
+[verse]
+'lkvm debug [instance]'
+
+DESCRIPTION
+-----------
+The command prints debug information from a running instance.
+For a list of running instances see 'lkvm list'.
diff --git a/tools/kvm/Documentation/kvm-list.txt b/tools/kvm/Documentation/kvm-list.txt
new file mode 100644 (file)
index 0000000..a245607
--- /dev/null
@@ -0,0 +1,16 @@
+lkvm-list(1)
+================
+
+NAME
+----
+lkvm-list - Print a list of running instances on the host.
+
+SYNOPSIS
+--------
+[verse]
+'lkvm list'
+
+DESCRIPTION
+-----------
+This command prints a list of running instances on the host which
+belong to the user who currently ran 'lkvm list'.
diff --git a/tools/kvm/Documentation/kvm-pause.txt b/tools/kvm/Documentation/kvm-pause.txt
new file mode 100644 (file)
index 0000000..1ea2a23
--- /dev/null
@@ -0,0 +1,16 @@
+lkvm-pause(1)
+================
+
+NAME
+----
+lkvm-pause - Pause the virtual machine
+
+SYNOPSIS
+--------
+[verse]
+'lkvm pause [instance]'
+
+DESCRIPTION
+-----------
+The command pauses a virtual machine.
+For a list of running instances see 'lkvm list'.
diff --git a/tools/kvm/Documentation/kvm-resume.txt b/tools/kvm/Documentation/kvm-resume.txt
new file mode 100644 (file)
index 0000000..a36c4df
--- /dev/null
@@ -0,0 +1,16 @@
+lkvm-resume(1)
+================
+
+NAME
+----
+lkvm-resume - Resume the virtual machine
+
+SYNOPSIS
+--------
+[verse]
+'lkvm resume [instance]'
+
+DESCRIPTION
+-----------
+The command resumes a virtual machine.
+For a list of running instances see 'lkvm list'.
diff --git a/tools/kvm/Documentation/kvm-run.txt b/tools/kvm/Documentation/kvm-run.txt
new file mode 100644 (file)
index 0000000..8ddf470
--- /dev/null
@@ -0,0 +1,62 @@
+lkvm-run(1)
+================
+
+NAME
+----
+lkvm-run - Start the virtual machine
+
+SYNOPSIS
+--------
+[verse]
+'lkvm run' [-k <kernel image> | --kernel <kernel image>]
+
+DESCRIPTION
+-----------
+The command starts a virtual machine.
+
+OPTIONS
+-------
+-m::
+--mem=::
+       Virtual machine memory size in MiB.
+
+-p::
+--params::
+       Additional kernel command line arguments.
+
+-r::
+--initrd=::
+       Initial RAM disk image.
+
+-k::
+--kernel=::
+       The virtual machine kernel.
+
+--dev=::
+       KVM device file.
+
+-i::
+--image=::
+       A disk image file.
+
+-s::
+--single-step::
+       Enable single stepping.
+
+-g::
+--ioport-debug::
+       Enable ioport debugging.
+
+-c::
+--enable-virtio-console::
+       Enable the virtual IO console.
+
+--cpus::
+       The number of virtual CPUs to run.
+
+--debug::
+       Enable debug messages.
+
+SEE ALSO
+--------
+linkkvm:
diff --git a/tools/kvm/Documentation/kvm-sandbox.txt b/tools/kvm/Documentation/kvm-sandbox.txt
new file mode 100644 (file)
index 0000000..2d7f558
--- /dev/null
@@ -0,0 +1,16 @@
+lkvm-sandbox(1)
+================
+
+NAME
+----
+lkvm-sandbox - Run a command in a sandboxed guest
+
+SYNOPSIS
+--------
+[verse]
+'lkvm sandbox ['lkvm run' arguments] -- [sandboxed command]'
+
+DESCRIPTION
+-----------
+The sandboxed command will run in a guest as part of it's init
+command.
diff --git a/tools/kvm/Documentation/kvm-setup.txt b/tools/kvm/Documentation/kvm-setup.txt
new file mode 100644 (file)
index 0000000..4b6e331
--- /dev/null
@@ -0,0 +1,15 @@
+lkvm-setup(1)
+================
+
+NAME
+----
+lkvm-setup - Setup a new virtual machine
+
+SYNOPSIS
+--------
+[verse]
+'lkvm setup <name>'
+
+DESCRIPTION
+-----------
+The command setups a virtual machine.
diff --git a/tools/kvm/Documentation/kvm-stat.txt b/tools/kvm/Documentation/kvm-stat.txt
new file mode 100644 (file)
index 0000000..101ce7a
--- /dev/null
@@ -0,0 +1,19 @@
+lkvm-stat(1)
+================
+
+NAME
+----
+lkvm-stat - Print statistics about a running instance
+
+SYNOPSIS
+--------
+[verse]
+'lkvm [command] [-n instance] [-p instance pid] [--all]'
+
+DESCRIPTION
+-----------
+The command prints statistics about a running instance.
+For a list of running instances see 'lkvm list'.
+
+Commands:
+ --memory, -m  Display memory statistics
diff --git a/tools/kvm/Documentation/kvm-stop.txt b/tools/kvm/Documentation/kvm-stop.txt
new file mode 100644 (file)
index 0000000..6e4bc83
--- /dev/null
@@ -0,0 +1,16 @@
+lkvm-stop(1)
+================
+
+NAME
+----
+lkvm-stop - Stop a running instance
+
+SYNOPSIS
+--------
+[verse]
+'lkvm stop [instance]'
+
+DESCRIPTION
+-----------
+The command stops a running instance.
+For a list of running instances see 'lkvm list'.
diff --git a/tools/kvm/Documentation/kvm-version.txt b/tools/kvm/Documentation/kvm-version.txt
new file mode 100644 (file)
index 0000000..41003d2
--- /dev/null
@@ -0,0 +1,21 @@
+lkvm-version(1)
+================
+
+NAME
+----
+lkvm-version - Print the version of the kernel tree kvm tools
+was built on.
+
+SYNOPSIS
+--------
+[verse]
+'lkvm version'
+
+DESCRIPTION
+-----------
+The command prints the version of the kernel that was used to build
+kvm tools.
+
+Note that the version is not the version of the kernel which is currently
+running on the host, but is the version of the kernel tree from which kvm
+tools was built.
diff --git a/tools/kvm/Documentation/virtio-console.txt b/tools/kvm/Documentation/virtio-console.txt
new file mode 100644 (file)
index 0000000..4a58d56
--- /dev/null
@@ -0,0 +1,41 @@
+General
+--------
+
+virtio-console as the name implies is a console over virtio transport. Here is
+a simple head to head comparison of the virtio-console vs regular 8250 console:
+
+8250 serial console:
+
+ - Requires CONFIG_SERIAL_8250=y and CONFIG_SERIAL_8250_CONSOLE=y kernel configs,
+which are enabled almost everywhere.
+ - Doesn't require guest-side changes.
+ - Compatible with older guests.
+
+virtio-console:
+
+ - Requires CONFIG_VIRTIO_CONSOLE=y (along with all other virtio dependencies),
+which got enabled only in recent kernels (but not all of them).
+ - Much faster.
+ - Consumes less processing resources.
+ - Requires guest-side changes.
+
+Enabling virtio-console
+------------------------
+
+First, make sure guest kernel is built with CONFIG_VIRTIO_CONSOLE=y. Once this
+is done, the following has to be done inside guest image:
+
+ - Add the following line to /etc/inittab:
+       'hvc0:2345:respawn:/sbin/agetty -L 9600 hvc0'
+ - Add 'hvc0' to /etc/securetty (so you could actually log on)
+ - Start the guest with '--console virtio'
+
+Common errors
+--------------
+
+Q: I don't see anything on the screen!
+A: Make sure CONFIG_VIRTIO_CONSOLE=y is enabled in the *guest* kernel, also
+make sure you've updated /etc/inittab
+
+Q: It won't accept my username/password, but I enter them correctly!
+A: You didn't add 'hvc0' to /etc/securetty
diff --git a/tools/kvm/Makefile b/tools/kvm/Makefile
new file mode 100644 (file)
index 0000000..f9e1ec1
--- /dev/null
@@ -0,0 +1,427 @@
+#
+# Define WERROR=0 to disable -Werror.
+#
+
+ifeq ($(strip $(V)),)
+       E = @echo
+       Q = @
+else
+       E = @\#
+       Q =
+endif
+ifneq ($(I), )
+       KINCL_PATH=$(I)
+else
+       KINCL_PATH=../..
+endif
+export E Q KINCL_PATH
+
+include config/utilities.mak
+include config/feature-tests.mak
+
+CC     := $(CROSS_COMPILE)$(CC)
+
+FIND   := find
+CSCOPE := cscope
+TAGS   := ctags
+
+PROGRAM        := lkvm
+PROGRAM_ALIAS := vm
+
+GUEST_INIT := guest/init
+GUEST_INIT_S2 := guest/init_stage2
+
+OBJS   += builtin-balloon.o
+OBJS   += builtin-debug.o
+OBJS   += builtin-help.o
+OBJS   += builtin-list.o
+OBJS   += builtin-stat.o
+OBJS   += builtin-pause.o
+OBJS   += builtin-resume.o
+OBJS   += builtin-run.o
+OBJS   += builtin-setup.o
+OBJS   += builtin-stop.o
+OBJS   += builtin-version.o
+OBJS   += disk/core.o
+OBJS   += framebuffer.o
+OBJS   += guest_compat.o
+OBJS   += hw/rtc.o
+OBJS   += hw/serial.o
+OBJS   += ioport.o
+OBJS   += kvm-cpu.o
+OBJS   += kvm.o
+OBJS   += main.o
+OBJS   += mmio.o
+OBJS   += pci.o
+OBJS   += term.o
+OBJS   += virtio/blk.o
+OBJS   += virtio/console.o
+OBJS   += virtio/core.o
+OBJS   += virtio/net.o
+OBJS   += virtio/rng.o
+OBJS    += virtio/balloon.o
+OBJS   += virtio/pci.o
+OBJS   += disk/blk.o
+OBJS   += disk/qcow.o
+OBJS   += disk/raw.o
+OBJS   += ioeventfd.o
+OBJS   += net/uip/core.o
+OBJS   += net/uip/arp.o
+OBJS   += net/uip/icmp.o
+OBJS   += net/uip/ipv4.o
+OBJS   += net/uip/tcp.o
+OBJS   += net/uip/udp.o
+OBJS   += net/uip/buf.o
+OBJS   += net/uip/csum.o
+OBJS   += net/uip/dhcp.o
+OBJS   += kvm-cmd.o
+OBJS   += util/rbtree.o
+OBJS   += util/threadpool.o
+OBJS   += util/parse-options.o
+OBJS   += util/rbtree-interval.o
+OBJS   += util/strbuf.o
+OBJS   += util/read-write.o
+OBJS   += util/util.o
+OBJS   += virtio/9p.o
+OBJS   += virtio/9p-pdu.o
+OBJS   += hw/vesa.o
+OBJS   += hw/pci-shmem.o
+OBJS   += kvm-ipc.o
+OBJS   += builtin-sandbox.o
+OBJS   += virtio/mmio.o
+
+# Translate uname -m into ARCH string
+ARCH ?= $(shell uname -m | sed -e s/i.86/i386/ -e s/ppc.*/powerpc/)
+
+ifeq ($(ARCH),i386)
+       ARCH         := x86
+       DEFINES      += -DCONFIG_X86_32
+endif
+ifeq ($(ARCH),x86_64)
+       ARCH         := x86
+       DEFINES      += -DCONFIG_X86_64
+endif
+
+LIBFDT_SRC = fdt.o fdt_ro.o fdt_wip.o fdt_sw.o fdt_rw.o fdt_strerror.o
+LIBFDT_OBJS = $(patsubst %,../../scripts/dtc/libfdt/%,$(LIBFDT_SRC))
+
+### Arch-specific stuff
+
+#x86
+ifeq ($(ARCH),x86)
+       DEFINES += -DCONFIG_X86
+       OBJS    += x86/boot.o
+       OBJS    += x86/cpuid.o
+       OBJS    += x86/interrupt.o
+       OBJS    += x86/ioport.o
+       OBJS    += x86/irq.o
+       OBJS    += x86/kvm.o
+       OBJS    += x86/kvm-cpu.o
+       OBJS    += x86/mptable.o
+       OBJS    += hw/i8042.o
+# Exclude BIOS object files from header dependencies.
+       OTHEROBJS       += x86/bios.o
+       OTHEROBJS       += x86/bios/bios-rom.o
+       ARCH_INCLUDE := x86/include
+endif
+# POWER/ppc:  Actually only support ppc64 currently.
+ifeq ($(ARCH), powerpc)
+       DEFINES += -DCONFIG_PPC
+       OBJS    += powerpc/boot.o
+       OBJS    += powerpc/ioport.o
+       OBJS    += powerpc/irq.o
+       OBJS    += powerpc/kvm.o
+       OBJS    += powerpc/cpu_info.o
+       OBJS    += powerpc/kvm-cpu.o
+       OBJS    += powerpc/spapr_hcall.o
+       OBJS    += powerpc/spapr_rtas.o
+       OBJS    += powerpc/spapr_hvcons.o
+       OBJS    += powerpc/spapr_pci.o
+       OBJS    += powerpc/xics.o
+# We use libfdt, but it's sometimes not packaged 64bit.  It's small too,
+# so just build it in:
+       CFLAGS  += -I../../scripts/dtc/libfdt
+       OTHEROBJS       += $(LIBFDT_OBJS)
+       ARCH_INCLUDE := powerpc/include
+       CFLAGS  += -m64
+endif
+
+###
+
+ifeq (,$(ARCH_INCLUDE))
+       UNSUPP_ERR = @echo "This architecture is not supported in kvmtool." && exit 1
+else
+       UNSUPP_ERR =
+endif
+
+###
+
+# Detect optional features.
+# On a given system, some libs may link statically, some may not; so, check
+# both and only build those that link!
+
+FLAGS_BFD := $(CFLAGS) -lbfd
+ifeq ($(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD)),y)
+       CFLAGS_DYNOPT   += -DCONFIG_HAS_BFD
+       OBJS_DYNOPT     += symbol.o
+       LIBS_DYNOPT     += -lbfd
+endif
+ifeq ($(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD) -static),y)
+       CFLAGS_STATOPT  += -DCONFIG_HAS_BFD
+       OBJS_STATOPT    += symbol.o
+       LIBS_STATOPT    += -lbfd
+endif
+
+FLAGS_VNCSERVER := $(CFLAGS) -lvncserver
+ifeq ($(call try-cc,$(SOURCE_VNCSERVER),$(FLAGS_VNCSERVER)),y)
+       OBJS_DYNOPT     += ui/vnc.o
+       CFLAGS_DYNOPT   += -DCONFIG_HAS_VNCSERVER
+       LIBS_DYNOPT     += -lvncserver
+endif
+ifeq ($(call try-cc,$(SOURCE_VNCSERVER),$(FLAGS_VNCSERVER) -static),y)
+       OBJS_STATOPT    += ui/vnc.o
+       CFLAGS_STATOPT  += -DCONFIG_HAS_VNCSERVER
+       LIBS_STATOPT    += -lvncserver
+endif
+
+FLAGS_SDL := $(CFLAGS) -lSDL
+ifeq ($(call try-cc,$(SOURCE_SDL),$(FLAGS_SDL)),y)
+       OBJS_DYNOPT     += ui/sdl.o
+       CFLAGS_DYNOPT   += -DCONFIG_HAS_SDL
+       LIBS_DYNOPT     += -lSDL
+endif
+ifeq ($(call try-cc,$(SOURCE_SDL),$(FLAGS_SDL) -static), y)
+       OBJS_STATOPT    += ui/sdl.o
+       CFLAGS_STATOPT  += -DCONFIG_HAS_SDL
+       LIBS_STATOPT    += -lSDL
+endif
+
+FLAGS_ZLIB := $(CFLAGS) -lz
+ifeq ($(call try-cc,$(SOURCE_ZLIB),$(FLAGS_ZLIB)),y)
+       CFLAGS_DYNOPT   += -DCONFIG_HAS_ZLIB
+       LIBS_DYNOPT     += -lz
+endif
+ifeq ($(call try-cc,$(SOURCE_ZLIB),$(FLAGS_ZLIB) -static),y)
+       CFLAGS_STATOPT  += -DCONFIG_HAS_ZLIB
+       LIBS_STATOPT    += -lz
+endif
+
+FLAGS_AIO := $(CFLAGS) -laio
+ifeq ($(call try-cc,$(SOURCE_AIO),$(FLAGS_AIO)),y)
+       CFLAGS_DYNOPT   += -DCONFIG_HAS_AIO
+       LIBS_DYNOPT     += -laio
+endif
+ifeq ($(call try-cc,$(SOURCE_AIO),$(FLAGS_AIO) -static),y)
+       CFLAGS_STATOPT  += -DCONFIG_HAS_AIO
+       LIBS_STATOPT    += -laio
+endif
+
+ifneq ($(call try-build,$(SOURCE_STATIC),-static,),y)
+$(error No static libc found. Please install glibc-static package.)
+endif
+###
+
+LIBS   += -lrt
+LIBS   += -lpthread
+LIBS   += -lutil
+
+
+DEPS   := $(patsubst %.o,%.d,$(OBJS))
+
+DEFINES        += -D_FILE_OFFSET_BITS=64
+DEFINES        += -D_GNU_SOURCE
+DEFINES        += -DKVMTOOLS_VERSION='"$(KVMTOOLS_VERSION)"'
+DEFINES        += -DBUILD_ARCH='"$(ARCH)"'
+
+KVM_INCLUDE := include
+CFLAGS += $(CPPFLAGS) $(DEFINES) -I$(KVM_INCLUDE) -I$(ARCH_INCLUDE) -I$(KINCL_PATH)/include -I$(KINCL_PATH)/arch/$(ARCH)/include/ -O2 -fno-strict-aliasing -g
+
+WARNINGS += -Wall
+WARNINGS += -Wcast-align
+WARNINGS += -Wformat=2
+WARNINGS += -Winit-self
+WARNINGS += -Wmissing-declarations
+WARNINGS += -Wmissing-prototypes
+WARNINGS += -Wnested-externs
+WARNINGS += -Wno-system-headers
+WARNINGS += -Wold-style-definition
+WARNINGS += -Wredundant-decls
+WARNINGS += -Wsign-compare
+WARNINGS += -Wstrict-prototypes
+WARNINGS += -Wundef
+WARNINGS += -Wvolatile-register-var
+WARNINGS += -Wwrite-strings
+
+CFLAGS += $(WARNINGS)
+
+# Some targets may use 'external' sources that don't build totally cleanly.
+CFLAGS_EASYGOING := $(CFLAGS)
+
+ifneq ($(WERROR),0)
+       CFLAGS += -Werror
+endif
+
+all: arch_support_check $(PROGRAM) $(PROGRAM_ALIAS) $(GUEST_INIT) $(GUEST_INIT_S2)
+
+arch_support_check:
+       $(UNSUPP_ERR)
+
+KVMTOOLS-VERSION-FILE:
+       @$(SHELL_PATH) util/KVMTOOLS-VERSION-GEN $(OUTPUT)
+-include $(OUTPUT)KVMTOOLS-VERSION-FILE
+
+# When building -static all objects are built with appropriate flags, which
+# may differ between static & dynamic .o.  The objects are separated into
+# .o and .static.o.  See the %.o: %.c rules below.
+#
+# $(OTHEROBJS) are things that do not get substituted like this.
+#
+STATIC_OBJS = $(patsubst %.o,%.static.o,$(OBJS) $(OBJS_STATOPT))
+
+$(PROGRAM)-static:  $(DEPS) $(STATIC_OBJS) $(OTHEROBJS)
+       $(E) "  LINK    " $@
+       $(Q) $(CC) -static $(CFLAGS) $(STATIC_OBJS) $(OTHEROBJS) $(LIBS) $(LIBS_STATOPT) -o $@
+
+$(PROGRAM): $(DEPS) $(OBJS) $(OBJS_DYNOPT) $(OTHEROBJS)
+       $(E) "  LINK    " $@
+       $(Q) $(CC) $(CFLAGS) $(OBJS) $(OBJS_DYNOPT) $(OTHEROBJS) $(LIBS) $(LIBS_DYNOPT) -o $@
+
+$(PROGRAM_ALIAS): $(PROGRAM)
+       $(E) "  LN      " $@
+       $(Q) ln -f $(PROGRAM) $@
+
+$(GUEST_INIT): guest/init.c
+       $(E) "  LINK    " $@
+       $(Q) $(CC) -static guest/init.c -o $@
+
+$(GUEST_INIT_S2): guest/init_stage2.c
+       $(E) "  LINK    " $@
+       $(Q) $(CC) -static guest/init_stage2.c -o $@
+
+$(DEPS):
+
+util/rbtree.d: ../../lib/rbtree.c
+       $(Q) $(CC) -M -MT util/rbtree.o $(CFLAGS) $< -o $@
+
+%.d: %.c
+       $(Q) $(CC) -M -MT $(patsubst %.d,%.o,$@) $(CFLAGS) $< -o $@
+
+# The header file common-cmds.h is needed for compilation of builtin-help.c.
+builtin-help.d: $(KVM_INCLUDE)/common-cmds.h
+
+$(OBJS):
+
+# This rule relaxes the -Werror on libfdt, since for now it still has
+# a bunch of warnings. :(
+../../scripts/dtc/libfdt/%.o: ../../scripts/dtc/libfdt/%.c
+       $(E) "  CC      " $@
+       $(Q) $(CC) -c $(CFLAGS_EASYGOING) $< -o $@
+
+util/rbtree.static.o util/rbtree.o: ../../lib/rbtree.c
+       $(E) "  CC      " $@
+       $(Q) $(CC) -c $(CFLAGS) $< -o $@
+
+%.static.o: %.c
+       $(E) "  CC      " $@
+       $(Q) $(CC) -c $(CFLAGS) $(CFLAGS_STATOPT)  $< -o $@
+
+%.o: %.c
+       $(E) "  CC      " $@
+       $(Q) $(CC) -c $(CFLAGS) $(CFLAGS_DYNOPT) $< -o $@
+
+
+$(KVM_INCLUDE)/common-cmds.h: util/generate-cmdlist.sh command-list.txt
+
+$(KVM_INCLUDE)/common-cmds.h: $(wildcard Documentation/kvm-*.txt)
+       $(E) "  GEN     " $@
+       $(Q) util/generate-cmdlist.sh > $@+ && mv $@+ $@
+
+#
+# BIOS assembly weirdness
+#
+BIOS_CFLAGS += -m32
+BIOS_CFLAGS += -march=i386
+BIOS_CFLAGS += -mregparm=3
+
+BIOS_CFLAGS += -fno-stack-protector
+BIOS_CFLAGS += -I../../arch/$(ARCH)
+
+x86/bios.o: x86/bios/bios.bin x86/bios/bios-rom.h
+
+x86/bios/bios.bin.elf: x86/bios/entry.S x86/bios/e820.c x86/bios/int10.c x86/bios/int15.c x86/bios/rom.ld.S
+       $(E) "  CC       x86/bios/memcpy.o"
+       $(Q) $(CC) -include code16gcc.h $(CFLAGS) $(BIOS_CFLAGS) -c -s x86/bios/memcpy.c -o x86/bios/memcpy.o
+       $(E) "  CC       x86/bios/e820.o"
+       $(Q) $(CC) -include code16gcc.h $(CFLAGS) $(BIOS_CFLAGS) -c -s x86/bios/e820.c -o x86/bios/e820.o
+       $(E) "  CC       x86/bios/int10.o"
+       $(Q) $(CC) -include code16gcc.h $(CFLAGS) $(BIOS_CFLAGS) -c -s x86/bios/int10.c -o x86/bios/int10.o
+       $(E) "  CC       x86/bios/int15.o"
+       $(Q) $(CC) -include code16gcc.h $(CFLAGS) $(BIOS_CFLAGS) -c -s x86/bios/int15.c -o x86/bios/int15.o
+       $(E) "  CC       x86/bios/entry.o"
+       $(Q) $(CC) $(CFLAGS) $(BIOS_CFLAGS) -c -s x86/bios/entry.S -o x86/bios/entry.o
+       $(E) "  LD      " $@
+       $(Q) ld -T x86/bios/rom.ld.S -o x86/bios/bios.bin.elf x86/bios/memcpy.o x86/bios/entry.o x86/bios/e820.o x86/bios/int10.o x86/bios/int15.o
+
+x86/bios/bios.bin: x86/bios/bios.bin.elf
+       $(E) "  OBJCOPY " $@
+       $(Q) objcopy -O binary -j .text x86/bios/bios.bin.elf x86/bios/bios.bin
+
+x86/bios/bios-rom.o: x86/bios/bios-rom.S x86/bios/bios.bin x86/bios/bios-rom.h
+       $(E) "  CC      " $@
+       $(Q) $(CC) -c $(CFLAGS) x86/bios/bios-rom.S -o x86/bios/bios-rom.o
+
+x86/bios/bios-rom.h: x86/bios/bios.bin.elf
+       $(E) "  NM      " $@
+       $(Q) cd x86/bios && sh gen-offsets.sh > bios-rom.h && cd ..
+
+check: all
+       $(MAKE) -C tests
+       ./$(PROGRAM) run tests/pit/tick.bin
+       ./$(PROGRAM) run -d tests/boot/boot_test.iso -p "init=init"
+.PHONY: check
+
+clean:
+       $(E) "  CLEAN"
+       $(Q) rm -f x86/bios/*.bin
+       $(Q) rm -f x86/bios/*.elf
+       $(Q) rm -f x86/bios/*.o
+       $(Q) rm -f x86/bios/bios-rom.h
+       $(Q) rm -f tests/boot/boot_test.iso
+       $(Q) rm -rf tests/boot/rootfs/
+       $(Q) rm -f $(DEPS) $(OBJS) $(OTHEROBJS) $(OBJS_DYNOPT) $(STATIC_OBJS) $(PROGRAM) $(PROGRAM_ALIAS) $(PROGRAM)-static $(GUEST_INIT) $(GUEST_INIT_S2)
+       $(Q) rm -f cscope.*
+       $(Q) rm -f tags
+       $(Q) rm -f TAGS
+       $(Q) rm -f $(KVM_INCLUDE)/common-cmds.h
+       $(Q) rm -f KVMTOOLS-VERSION-FILE
+.PHONY: clean
+
+KVM_DEV        ?= /dev/kvm
+
+$(KVM_DEV):
+       $(E) "  MKNOD " $@
+       $(Q) mknod $@ char 10 232
+
+devices: $(KVM_DEV)
+.PHONY: devices
+
+TAGS:
+       $(E) "  GEN" $@
+       $(Q) $(RM) -f TAGS
+       $(Q) $(FIND) . -name '*.[hcS]' -print | xargs etags -a
+.PHONY: TAGS
+
+tags:
+       $(E) "  GEN" $@
+       $(Q) $(RM) -f tags
+       $(Q) $(FIND) . -name '*.[hcS]' -print | xargs ctags -a
+.PHONY: tags
+
+cscope:
+       $(E) "  GEN" $@
+       $(Q) $(FIND) . -name '*.[hcS]' -print > cscope.files
+       $(Q) $(CSCOPE) -bkqu
+.PHONY: cscope
+
+# Deps
+-include $(DEPS)
diff --git a/tools/kvm/README b/tools/kvm/README
new file mode 100644 (file)
index 0000000..358fa23
--- /dev/null
@@ -0,0 +1,112 @@
+Native Linux KVM tool
+=====================
+The goal of this tool is to provide a clean, from-scratch, lightweight
+KVM host tool implementation that can boot Linux guest images (just a
+hobby, won't be big and professional like QEMU) with no BIOS
+dependencies and with only the minimal amount of legacy device
+emulation.
+
+It's great as a learning tool if you want to get your feet wet in
+virtualization land: it's only 5 KLOC of clean C code that can already
+boot a guest Linux image.
+
+Right now it can boot a Linux image and provide you output via a serial
+console, over the host terminal, i.e. you can use it to boot a guest
+Linux image in a terminal or over ssh and log into the guest without
+much guest or host side setup work needed.
+
+1. To try out the tool, clone the git repository:
+
+  git clone git://github.com/penberg/linux-kvm.git
+
+or alternatively, if you already have a kernel source tree:
+
+  git remote add kvm-tool git://github.com/penberg/linux-kvm.git
+  git remote update
+  git checkout -b kvm-tool/master kvm-tool
+
+2. Compile the tool:
+
+  cd tools/kvm && make
+
+3. Download a raw userspace image:
+
+  wget http://wiki.qemu.org/download/linux-0.2.img.bz2 && bunzip2
+linux-0.2.img.bz2
+
+4. The guest kernel has to be built with the following configuration:
+
+ - For the default console output:
+       CONFIG_SERIAL_8250=y
+       CONFIG_SERIAL_8250_CONSOLE=y
+
+ - For running 32bit images on 64bit hosts:
+       CONFIG_IA32_EMULATION=y
+
+ - Proper FS options according to image FS (e.g. CONFIG_EXT2_FS, CONFIG_EXT4_FS).
+
+ - For all virtio devices listed below:
+       CONFIG_VIRTIO=y
+       CONFIG_VIRTIO_RING=y
+       CONFIG_VIRTIO_PCI=y
+
+ - For virtio-blk devices (--disk, -d):
+       CONFIG_VIRTIO_BLK=y
+
+ - For virtio-net devices ([--network, -n] virtio):
+       CONFIG_VIRTIO_NET=y
+
+ - For virtio-9p devices (--virtio-9p):
+       CONFIG_NET_9P=y
+       CONFIG_NET_9P_VIRTIO=y
+       CONFIG_9P_FS=y
+
+ - For virtio-balloon device (--balloon):
+       CONFIG_VIRTIO_BALLOON=y
+
+ - For virtio-console device (--console virtio):
+       CONFIG_VIRTIO_CONSOLE=y
+
+ - For virtio-rng device (--rng):
+       CONFIG_HW_RANDOM_VIRTIO=y
+
+ - For vesa device (--sdl or --vnc):
+       CONFIG_FB_VESA=y
+
+
+5. And finally, launch the hypervisor:
+
+  ./lkvm run --disk linux-0.2.img \
+           --kernel ../../arch/x86/boot/bzImage \
+or
+
+  sudo ./lkvm run --disk linux-0.2.img \
+                --kernel ../../arch/x86/boot/bzImage \
+                --network virtio
+
+The tool has been written by Pekka Enberg, Cyrill Gorcunov, Asias He,
+Sasha Levin and Prasad Joshi. Special thanks to Avi Kivity for his help
+on KVM internals and Ingo Molnar for all-around support and encouragement!
+
+See the following thread for original discussion for motivation of this
+project:
+
+http://thread.gmane.org/gmane.linux.kernel/962051/focus=962620
+
+Build dependencies
+=====================
+For deb based systems:
+32-bit:
+sudo apt-get install build-essential
+64-bit:
+sudo apt-get install build-essential libc6-dev-i386
+
+For rpm based systems:
+32-bit:
+yum install glibc-devel
+64-bit:
+yum install glibc-devel glibc-static
+
+On 64-bit Arch Linux make sure the multilib repository is enabled in your
+/etc/pacman.conf and run
+pacman -Sy lib32-glibc
diff --git a/tools/kvm/builtin-balloon.c b/tools/kvm/builtin-balloon.c
new file mode 100644 (file)
index 0000000..5bd2291
--- /dev/null
@@ -0,0 +1,80 @@
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+
+#include <kvm/util.h>
+#include <kvm/kvm-cmd.h>
+#include <kvm/builtin-balloon.h>
+#include <kvm/parse-options.h>
+#include <kvm/kvm.h>
+#include <kvm/kvm-ipc.h>
+
+static const char *instance_name;
+static u64 inflate;
+static u64 deflate;
+
+static const char * const balloon_usage[] = {
+       "lkvm balloon [-n name] [-p pid] [-i amount] [-d amount]",
+       NULL
+};
+
+static const struct option balloon_options[] = {
+       OPT_GROUP("Instance options:"),
+       OPT_STRING('n', "name", &instance_name, "name", "Instance name"),
+       OPT_GROUP("Balloon options:"),
+       OPT_U64('i', "inflate", &inflate, "Amount to inflate"),
+       OPT_U64('d', "deflate", &deflate, "Amount to deflate"),
+       OPT_END(),
+};
+
+void kvm_balloon_help(void)
+{
+       usage_with_options(balloon_usage, balloon_options);
+}
+
+static void parse_balloon_options(int argc, const char **argv)
+{
+       while (argc != 0) {
+               argc = parse_options(argc, argv, balloon_options, balloon_usage,
+                               PARSE_OPT_STOP_AT_NON_OPTION);
+               if (argc != 0)
+                       kvm_balloon_help();
+       }
+}
+
+int kvm_cmd_balloon(int argc, const char **argv, const char *prefix)
+{
+       int instance;
+       int r;
+       int amount;
+
+       parse_balloon_options(argc, argv);
+
+       if (inflate == 0 && deflate == 0)
+               kvm_balloon_help();
+
+       if (instance_name == NULL)
+               kvm_balloon_help();
+
+       instance = kvm__get_sock_by_instance(instance_name);
+
+       if (instance <= 0)
+               die("Failed locating instance");
+
+       if (inflate)
+               amount = inflate;
+       else if (deflate)
+               amount = -deflate;
+       else
+               kvm_balloon_help();
+
+       r = kvm_ipc__send_msg(instance, KVM_IPC_BALLOON,
+                       sizeof(amount), (u8 *)&amount);
+
+       close(instance);
+
+       if (r < 0)
+               return -1;
+
+       return 0;
+}
diff --git a/tools/kvm/builtin-debug.c b/tools/kvm/builtin-debug.c
new file mode 100644 (file)
index 0000000..4ae51d2
--- /dev/null
@@ -0,0 +1,110 @@
+#include <kvm/util.h>
+#include <kvm/kvm-cmd.h>
+#include <kvm/builtin-debug.h>
+#include <kvm/kvm.h>
+#include <kvm/parse-options.h>
+#include <kvm/kvm-ipc.h>
+#include <kvm/read-write.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+
+#define BUFFER_SIZE 100
+
+static bool all;
+static int nmi = -1;
+static bool dump;
+static const char *instance_name;
+static const char *sysrq;
+
+static const char * const debug_usage[] = {
+       "lkvm debug [--all] [-n name] [-d] [-m vcpu]",
+       NULL
+};
+
+static const struct option debug_options[] = {
+       OPT_GROUP("General options:"),
+       OPT_BOOLEAN('d', "dump", &dump, "Generate a debug dump from guest"),
+       OPT_INTEGER('m', "nmi", &nmi, "Generate NMI on VCPU"),
+       OPT_STRING('s', "sysrq", &sysrq, "sysrq", "Inject a sysrq"),
+       OPT_GROUP("Instance options:"),
+       OPT_BOOLEAN('a', "all", &all, "Debug all instances"),
+       OPT_STRING('n', "name", &instance_name, "name", "Instance name"),
+       OPT_END()
+};
+
+static void parse_debug_options(int argc, const char **argv)
+{
+       while (argc != 0) {
+               argc = parse_options(argc, argv, debug_options, debug_usage,
+                               PARSE_OPT_STOP_AT_NON_OPTION);
+               if (argc != 0)
+                       kvm_debug_help();
+       }
+}
+
+void kvm_debug_help(void)
+{
+       usage_with_options(debug_usage, debug_options);
+}
+
+static int do_debug(const char *name, int sock)
+{
+       char buff[BUFFER_SIZE];
+       struct debug_cmd_params cmd = {.dbg_type = 0};
+       int r;
+
+       if (dump)
+               cmd.dbg_type |= KVM_DEBUG_CMD_TYPE_DUMP;
+
+       if (nmi != -1) {
+               cmd.dbg_type |= KVM_DEBUG_CMD_TYPE_NMI;
+               cmd.cpu = nmi;
+       }
+
+       if (sysrq) {
+               cmd.dbg_type |= KVM_DEBUG_CMD_TYPE_SYSRQ;
+               cmd.sysrq = sysrq[0];
+       }
+
+       r = kvm_ipc__send_msg(sock, KVM_IPC_DEBUG, sizeof(cmd), (u8 *)&cmd);
+       if (r < 0)
+               return r;
+
+       if (!dump)
+               return 0;
+
+       do {
+               r = xread(sock, buff, BUFFER_SIZE);
+               if (r < 0)
+                       return 0;
+               printf("%.*s", r, buff);
+       } while (r > 0);
+
+       return 0;
+}
+
+int kvm_cmd_debug(int argc, const char **argv, const char *prefix)
+{
+       parse_debug_options(argc, argv);
+       int instance;
+       int r;
+
+       if (all)
+               return kvm__enumerate_instances(do_debug);
+
+       if (instance_name == NULL)
+               kvm_debug_help();
+
+       instance = kvm__get_sock_by_instance(instance_name);
+
+       if (instance <= 0)
+               die("Failed locating instance");
+
+       r = do_debug(instance_name, instance);
+
+       close(instance);
+
+       return r;
+}
diff --git a/tools/kvm/builtin-help.c b/tools/kvm/builtin-help.c
new file mode 100644 (file)
index 0000000..5970fb7
--- /dev/null
@@ -0,0 +1,63 @@
+#include <stdio.h>
+#include <string.h>
+
+/* user defined headers */
+#include <common-cmds.h>
+
+#include <kvm/util.h>
+#include <kvm/kvm-cmd.h>
+#include <kvm/builtin-help.h>
+#include <kvm/kvm.h>
+
+
+const char kvm_usage_string[] =
+       "lkvm COMMAND [ARGS]";
+
+const char kvm_more_info_string[] =
+       "See 'lkvm help COMMAND' for more information on a specific command.";
+
+
+static void list_common_cmds_help(void)
+{
+       unsigned int i, longest = 0;
+
+       for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
+               if (longest < strlen(common_cmds[i].name))
+                       longest = strlen(common_cmds[i].name);
+       }
+
+       puts(" The most commonly used lkvm commands are:");
+       for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
+               printf("   %-*s   ", longest, common_cmds[i].name);
+               puts(common_cmds[i].help);
+       }
+}
+
+static void kvm_help(void)
+{
+       printf("\n To start a simple non-privileged shell run '%s run'\n\n"
+               "usage: %s\n\n", KVM_BINARY_NAME, kvm_usage_string);
+       list_common_cmds_help();
+       printf("\n %s\n\n", kvm_more_info_string);
+}
+
+
+static void help_cmd(const char *cmd)
+{
+       struct cmd_struct *p;
+       p = kvm_get_command(kvm_commands, cmd);
+       if (!p)
+               kvm_help();
+       else if (p->help)
+               p->help();
+}
+
+int kvm_cmd_help(int argc, const char **argv, const char *prefix)
+{
+       if (!argv || !*argv) {
+               kvm_help();
+               return 0;
+       }
+       help_cmd(argv[0]);
+       return 0;
+}
diff --git a/tools/kvm/builtin-list.c b/tools/kvm/builtin-list.c
new file mode 100644 (file)
index 0000000..9299f17
--- /dev/null
@@ -0,0 +1,149 @@
+#include <kvm/util.h>
+#include <kvm/kvm-cmd.h>
+#include <kvm/builtin-list.h>
+#include <kvm/kvm.h>
+#include <kvm/parse-options.h>
+#include <kvm/kvm-ipc.h>
+
+#include <dirent.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <fcntl.h>
+
+static bool run;
+static bool rootfs;
+
+static const char * const list_usage[] = {
+       "lkvm list",
+       NULL
+};
+
+static const struct option list_options[] = {
+       OPT_GROUP("General options:"),
+       OPT_BOOLEAN('i', "run", &run, "List running instances"),
+       OPT_BOOLEAN('r', "rootfs", &rootfs, "List rootfs instances"),
+       OPT_END()
+};
+
+#define KVM_INSTANCE_RUNNING   "running"
+#define KVM_INSTANCE_PAUSED    "paused"
+#define KVM_INSTANCE_SHUTOFF   "shut off"
+
+void kvm_list_help(void)
+{
+       usage_with_options(list_usage, list_options);
+}
+
+static pid_t get_pid(int sock)
+{
+       pid_t pid;
+       int r;
+
+       r = kvm_ipc__send(sock, KVM_IPC_PID);
+       if (r < 0)
+               return r;
+
+       r = read(sock, &pid, sizeof(pid));
+       if (r < 0)
+               return r;
+
+       return pid;
+}
+
+int get_vmstate(int sock)
+{
+       int vmstate;
+       int r;
+
+       r = kvm_ipc__send(sock, KVM_IPC_VMSTATE);
+       if (r < 0)
+               return r;
+
+       r = read(sock, &vmstate, sizeof(vmstate));
+       if (r < 0)
+               return r;
+
+       return vmstate;
+
+}
+
+static int print_guest(const char *name, int sock)
+{
+       pid_t pid;
+       int vmstate;
+
+       pid = get_pid(sock);
+       vmstate = get_vmstate(sock);
+
+       if ((int)pid < 0 || vmstate < 0)
+               return -1;
+
+       if (vmstate == KVM_VMSTATE_PAUSED)
+               printf("%5d %-20s %s\n", pid, name, KVM_INSTANCE_PAUSED);
+       else
+               printf("%5d %-20s %s\n", pid, name, KVM_INSTANCE_RUNNING);
+
+       return 0;
+}
+
+static int kvm_list_running_instances(void)
+{
+       return kvm__enumerate_instances(print_guest);
+}
+
+static int kvm_list_rootfs(void)
+{
+       DIR *dir;
+       struct dirent *dirent;
+
+       dir = opendir(kvm__get_dir());
+       if (dir == NULL)
+               return -1;
+
+       while ((dirent = readdir(dir))) {
+               if (dirent->d_type == DT_DIR &&
+                       strcmp(dirent->d_name, ".") &&
+                       strcmp(dirent->d_name, ".."))
+                       printf("%5s %-20s %s\n", "", dirent->d_name, KVM_INSTANCE_SHUTOFF);
+       }
+
+       return 0;
+}
+
+static void parse_setup_options(int argc, const char **argv)
+{
+       while (argc != 0) {
+               argc = parse_options(argc, argv, list_options, list_usage,
+                               PARSE_OPT_STOP_AT_NON_OPTION);
+               if (argc != 0)
+                       kvm_list_help();
+       }
+}
+
+int kvm_cmd_list(int argc, const char **argv, const char *prefix)
+{
+       int r;
+
+       parse_setup_options(argc, argv);
+
+       if (!run && !rootfs)
+               run = rootfs = true;
+
+       printf("%6s %-20s %s\n", "PID", "NAME", "STATE");
+       printf("------------------------------------\n");
+
+       if (run) {
+               r = kvm_list_running_instances();
+               if (r < 0)
+                       perror("Error listing instances");
+       }
+
+       if (rootfs) {
+               r = kvm_list_rootfs();
+               if (r < 0)
+                       perror("Error listing rootfs");
+       }
+
+       return 0;
+}
diff --git a/tools/kvm/builtin-pause.c b/tools/kvm/builtin-pause.c
new file mode 100644 (file)
index 0000000..c08595a
--- /dev/null
@@ -0,0 +1,88 @@
+#include <kvm/util.h>
+#include <kvm/kvm-cmd.h>
+#include <kvm/builtin-pause.h>
+#include <kvm/builtin-list.h>
+#include <kvm/kvm.h>
+#include <kvm/parse-options.h>
+#include <kvm/kvm-ipc.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+
+static bool all;
+static const char *instance_name;
+
+static const char * const pause_usage[] = {
+       "lkvm pause [--all] [-n name]",
+       NULL
+};
+
+static const struct option pause_options[] = {
+       OPT_GROUP("General options:"),
+       OPT_BOOLEAN('a', "all", &all, "Pause all instances"),
+       OPT_STRING('n', "name", &instance_name, "name", "Instance name"),
+       OPT_END()
+};
+
+static void parse_pause_options(int argc, const char **argv)
+{
+       while (argc != 0) {
+               argc = parse_options(argc, argv, pause_options, pause_usage,
+                               PARSE_OPT_STOP_AT_NON_OPTION);
+               if (argc != 0)
+                       kvm_pause_help();
+       }
+}
+
+void kvm_pause_help(void)
+{
+       usage_with_options(pause_usage, pause_options);
+}
+
+static int do_pause(const char *name, int sock)
+{
+       int r;
+       int vmstate;
+
+       vmstate = get_vmstate(sock);
+       if (vmstate < 0)
+               return vmstate;
+       if (vmstate == KVM_VMSTATE_PAUSED) {
+               printf("Guest %s is already paused.\n", name);
+               return 0;
+       }
+
+       r = kvm_ipc__send(sock, KVM_IPC_PAUSE);
+       if (r)
+               return r;
+
+       printf("Guest %s paused\n", name);
+
+       return 0;
+}
+
+int kvm_cmd_pause(int argc, const char **argv, const char *prefix)
+{
+       int instance;
+       int r;
+
+       parse_pause_options(argc, argv);
+
+       if (all)
+               return kvm__enumerate_instances(do_pause);
+
+       if (instance_name == NULL)
+               kvm_pause_help();
+
+       instance = kvm__get_sock_by_instance(instance_name);
+
+       if (instance <= 0)
+               die("Failed locating instance");
+
+       r = do_pause(instance_name, instance);
+
+       close(instance);
+
+       return r;
+}
diff --git a/tools/kvm/builtin-resume.c b/tools/kvm/builtin-resume.c
new file mode 100644 (file)
index 0000000..0e954b4
--- /dev/null
@@ -0,0 +1,88 @@
+#include <kvm/util.h>
+#include <kvm/kvm-cmd.h>
+#include <kvm/builtin-resume.h>
+#include <kvm/builtin-list.h>
+#include <kvm/kvm.h>
+#include <kvm/parse-options.h>
+#include <kvm/kvm-ipc.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+
+static bool all;
+static const char *instance_name;
+
+static const char * const resume_usage[] = {
+       "lkvm resume [--all] [-n name]",
+       NULL
+};
+
+static const struct option resume_options[] = {
+       OPT_GROUP("General options:"),
+       OPT_BOOLEAN('a', "all", &all, "Resume all instances"),
+       OPT_STRING('n', "name", &instance_name, "name", "Instance name"),
+       OPT_END()
+};
+
+static void parse_resume_options(int argc, const char **argv)
+{
+       while (argc != 0) {
+               argc = parse_options(argc, argv, resume_options, resume_usage,
+                               PARSE_OPT_STOP_AT_NON_OPTION);
+               if (argc != 0)
+                       kvm_resume_help();
+       }
+}
+
+void kvm_resume_help(void)
+{
+       usage_with_options(resume_usage, resume_options);
+}
+
+static int do_resume(const char *name, int sock)
+{
+       int r;
+       int vmstate;
+
+       vmstate = get_vmstate(sock);
+       if (vmstate < 0)
+               return vmstate;
+       if (vmstate == KVM_VMSTATE_RUNNING) {
+               printf("Guest %s is still running.\n", name);
+               return 0;
+       }
+
+       r = kvm_ipc__send(sock, KVM_IPC_RESUME);
+       if (r)
+               return r;
+
+       printf("Guest %s resumed\n", name);
+
+       return 0;
+}
+
+int kvm_cmd_resume(int argc, const char **argv, const char *prefix)
+{
+       int instance;
+       int r;
+
+       parse_resume_options(argc, argv);
+
+       if (all)
+               return kvm__enumerate_instances(do_resume);
+
+       if (instance_name == NULL)
+               kvm_resume_help();
+
+       instance = kvm__get_sock_by_instance(instance_name);
+
+       if (instance <= 0)
+               die("Failed locating instance");
+
+       r = do_resume(instance_name, instance);
+
+       close(instance);
+
+       return r;
+}
diff --git a/tools/kvm/builtin-run.c b/tools/kvm/builtin-run.c
new file mode 100644 (file)
index 0000000..a36bd00
--- /dev/null
@@ -0,0 +1,1393 @@
+#include "kvm/builtin-run.h"
+
+#include "kvm/builtin-setup.h"
+#include "kvm/virtio-balloon.h"
+#include "kvm/virtio-console.h"
+#include "kvm/parse-options.h"
+#include "kvm/8250-serial.h"
+#include "kvm/framebuffer.h"
+#include "kvm/disk-image.h"
+#include "kvm/threadpool.h"
+#include "kvm/virtio-blk.h"
+#include "kvm/virtio-net.h"
+#include "kvm/virtio-rng.h"
+#include "kvm/ioeventfd.h"
+#include "kvm/virtio-9p.h"
+#include "kvm/barrier.h"
+#include "kvm/kvm-cpu.h"
+#include "kvm/ioport.h"
+#include "kvm/symbol.h"
+#include "kvm/i8042.h"
+#include "kvm/mutex.h"
+#include "kvm/term.h"
+#include "kvm/util.h"
+#include "kvm/strbuf.h"
+#include "kvm/vesa.h"
+#include "kvm/irq.h"
+#include "kvm/kvm.h"
+#include "kvm/pci.h"
+#include "kvm/rtc.h"
+#include "kvm/sdl.h"
+#include "kvm/vnc.h"
+#include "kvm/guest_compat.h"
+#include "kvm/pci-shmem.h"
+#include "kvm/kvm-ipc.h"
+#include "kvm/builtin-debug.h"
+
+#include <linux/types.h>
+#include <linux/err.h>
+
+#include <sys/utsname.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <termios.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <stdio.h>
+
+#define DEFAULT_KVM_DEV                "/dev/kvm"
+#define DEFAULT_CONSOLE                "serial"
+#define DEFAULT_NETWORK                "user"
+#define DEFAULT_HOST_ADDR      "192.168.33.1"
+#define DEFAULT_GUEST_ADDR     "192.168.33.15"
+#define DEFAULT_GUEST_MAC      "02:15:15:15:15:15"
+#define DEFAULT_HOST_MAC       "02:01:01:01:01:01"
+#define DEFAULT_SCRIPT         "none"
+const char *DEFAULT_SANDBOX_FILENAME = "guest/sandbox.sh";
+
+#define MB_SHIFT               (20)
+#define KB_SHIFT               (10)
+#define GB_SHIFT               (30)
+#define MIN_RAM_SIZE_MB                (64ULL)
+#define MIN_RAM_SIZE_BYTE      (MIN_RAM_SIZE_MB << MB_SHIFT)
+
+struct kvm *kvm;
+struct kvm_cpu **kvm_cpus;
+__thread struct kvm_cpu *current_kvm_cpu;
+
+static struct disk_image_params disk_image[MAX_DISK_IMAGES];
+static u64 ram_size;
+static u8  image_count;
+static u8 num_net_devices;
+static bool virtio_rng;
+static const char *kernel_cmdline;
+static const char *kernel_filename;
+static const char *vmlinux_filename;
+static const char *initrd_filename;
+static const char *firmware_filename;
+static const char *console;
+static const char *dev;
+static const char *network;
+static const char *host_ip;
+static const char *guest_ip;
+static const char *guest_mac;
+static const char *host_mac;
+static const char *script;
+static const char *guest_name;
+static const char *sandbox;
+static const char *hugetlbfs_path;
+static const char *custom_rootfs_name = "default";
+static struct virtio_net_params *net_params;
+static bool single_step;
+static bool vnc;
+static bool sdl;
+static bool balloon;
+static bool using_rootfs;
+static bool custom_rootfs;
+static bool no_net;
+static bool no_dhcp;
+extern bool ioport_debug;
+extern bool mmio_debug;
+static int  kvm_run_wrapper;
+extern int  active_console;
+extern int  debug_iodelay;
+
+bool do_debug_print = false;
+
+static int nrcpus;
+static int vidmode = -1;
+
+static const char * const run_usage[] = {
+       "lkvm run [<options>] [<kernel image>]",
+       NULL
+};
+
+enum {
+       KVM_RUN_DEFAULT,
+       KVM_RUN_SANDBOX,
+};
+
+void kvm_run_set_wrapper_sandbox(void)
+{
+       kvm_run_wrapper = KVM_RUN_SANDBOX;
+}
+
+static int img_name_parser(const struct option *opt, const char *arg, int unset)
+{
+       char path[PATH_MAX];
+       const char *cur;
+       struct stat st;
+       char *sep;
+
+       if (stat(arg, &st) == 0 &&
+           S_ISDIR(st.st_mode)) {
+               char tmp[PATH_MAX];
+
+               if (using_rootfs)
+                       die("Please use only one rootfs directory atmost");
+
+               if (realpath(arg, tmp) == 0 ||
+                   virtio_9p__register(kvm, tmp, "/dev/root") < 0)
+                       die("Unable to initialize virtio 9p");
+               using_rootfs = 1;
+               return 0;
+       }
+
+       snprintf(path, PATH_MAX, "%s%s", kvm__get_dir(), arg);
+
+       if (stat(path, &st) == 0 &&
+           S_ISDIR(st.st_mode)) {
+               char tmp[PATH_MAX];
+
+               if (using_rootfs)
+                       die("Please use only one rootfs directory atmost");
+
+               if (realpath(path, tmp) == 0 ||
+                   virtio_9p__register(kvm, tmp, "/dev/root") < 0)
+                       die("Unable to initialize virtio 9p");
+               if (virtio_9p__register(kvm, "/", "hostfs") < 0)
+                       die("Unable to initialize virtio 9p");
+               kvm_setup_resolv(arg);
+               using_rootfs = custom_rootfs = 1;
+               custom_rootfs_name = arg;
+               return 0;
+       }
+
+       if (image_count >= MAX_DISK_IMAGES)
+               die("Currently only 4 images are supported");
+
+       disk_image[image_count].filename = arg;
+       cur = arg;
+       do {
+               sep = strstr(cur, ",");
+               if (sep) {
+                       if (strncmp(sep + 1, "ro", 2) == 0)
+                               disk_image[image_count].readonly = true;
+                       else if (strncmp(sep + 1, "direct", 6) == 0)
+                               disk_image[image_count].direct = true;
+                       *sep = 0;
+                       cur = sep + 1;
+               }
+       } while (sep);
+
+       image_count++;
+
+       return 0;
+}
+
+static int virtio_9p_rootdir_parser(const struct option *opt, const char *arg, int unset)
+{
+       char *tag_name;
+       char tmp[PATH_MAX];
+
+       /*
+        * 9p dir can be of the form dirname,tag_name or
+        * just dirname. In the later case we use the
+        * default tag name
+        */
+       tag_name = strstr(arg, ",");
+       if (tag_name) {
+               *tag_name = '\0';
+               tag_name++;
+       }
+       if (realpath(arg, tmp)) {
+               if (virtio_9p__register(kvm, tmp, tag_name) < 0)
+                       die("Unable to initialize virtio 9p");
+       } else
+               die("Failed resolving 9p path");
+       return 0;
+}
+
+static int tty_parser(const struct option *opt, const char *arg, int unset)
+{
+       int tty = atoi(arg);
+
+       term_set_tty(tty);
+
+       return 0;
+}
+
+static inline void str_to_mac(const char *str, char *mac)
+{
+       sscanf(str, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+               mac, mac+1, mac+2, mac+3, mac+4, mac+5);
+}
+static int set_net_param(struct virtio_net_params *p, const char *param,
+                               const char *val)
+{
+       if (strcmp(param, "guest_mac") == 0) {
+               str_to_mac(val, p->guest_mac);
+       } else if (strcmp(param, "mode") == 0) {
+               if (!strncmp(val, "user", 4)) {
+                       int i;
+
+                       for (i = 0; i < num_net_devices; i++)
+                               if (net_params[i].mode == NET_MODE_USER)
+                                       die("Only one usermode network device allowed at a time");
+                       p->mode = NET_MODE_USER;
+               } else if (!strncmp(val, "tap", 3)) {
+                       p->mode = NET_MODE_TAP;
+               } else if (!strncmp(val, "none", 4)) {
+                       no_net = 1;
+                       return -1;
+               } else
+                       die("Unkown network mode %s, please use user, tap or none", network);
+       } else if (strcmp(param, "script") == 0) {
+               p->script = strdup(val);
+       } else if (strcmp(param, "guest_ip") == 0) {
+               p->guest_ip = strdup(val);
+       } else if (strcmp(param, "host_ip") == 0) {
+               p->host_ip = strdup(val);
+       } else if (strcmp(param, "trans") == 0) {
+               p->trans = strdup(val);
+       } else if (strcmp(param, "vhost") == 0) {
+               p->vhost = atoi(val);
+       } else if (strcmp(param, "fd") == 0) {
+               p->fd = atoi(val);
+       }
+
+       return 0;
+}
+
+static int netdev_parser(const struct option *opt, const char *arg, int unset)
+{
+       struct virtio_net_params p;
+       char *buf = NULL, *cmd = NULL, *cur = NULL;
+       bool on_cmd = true;
+
+       if (arg) {
+               buf = strdup(arg);
+               if (buf == NULL)
+                       die("Failed allocating new net buffer");
+               cur = strtok(buf, ",=");
+       }
+
+       p = (struct virtio_net_params) {
+               .guest_ip       = DEFAULT_GUEST_ADDR,
+               .host_ip        = DEFAULT_HOST_ADDR,
+               .script         = DEFAULT_SCRIPT,
+               .mode           = NET_MODE_TAP,
+       };
+
+       str_to_mac(DEFAULT_GUEST_MAC, p.guest_mac);
+       p.guest_mac[5] += num_net_devices;
+
+       while (cur) {
+               if (on_cmd) {
+                       cmd = cur;
+               } else {
+                       if (set_net_param(&p, cmd, cur) < 0)
+                               goto done;
+               }
+               on_cmd = !on_cmd;
+
+               cur = strtok(NULL, ",=");
+       };
+
+       num_net_devices++;
+
+       net_params = realloc(net_params, num_net_devices * sizeof(*net_params));
+       if (net_params == NULL)
+               die("Failed adding new network device");
+
+       net_params[num_net_devices - 1] = p;
+
+done:
+       free(buf);
+       return 0;
+}
+
+static int shmem_parser(const struct option *opt, const char *arg, int unset)
+{
+       const u64 default_size = SHMEM_DEFAULT_SIZE;
+       const u64 default_phys_addr = SHMEM_DEFAULT_ADDR;
+       const char *default_handle = SHMEM_DEFAULT_HANDLE;
+       struct shmem_info *si = malloc(sizeof(struct shmem_info));
+       u64 phys_addr;
+       u64 size;
+       char *handle = NULL;
+       int create = 0;
+       const char *p = arg;
+       char *next;
+       int base = 10;
+       int verbose = 0;
+
+       const int skip_pci = strlen("pci:");
+       if (verbose)
+               pr_info("shmem_parser(%p,%s,%d)", opt, arg, unset);
+       /* parse out optional addr family */
+       if (strcasestr(p, "pci:")) {
+               p += skip_pci;
+       } else if (strcasestr(p, "mem:")) {
+               die("I can't add to E820 map yet.\n");
+       }
+       /* parse out physical addr */
+       base = 10;
+       if (strcasestr(p, "0x"))
+               base = 16;
+       phys_addr = strtoll(p, &next, base);
+       if (next == p && phys_addr == 0) {
+               pr_info("shmem: no physical addr specified, using default.");
+               phys_addr = default_phys_addr;
+       }
+       if (*next != ':' && *next != '\0')
+               die("shmem: unexpected chars after phys addr.\n");
+       if (*next == '\0')
+               p = next;
+       else
+               p = next + 1;
+       /* parse out size */
+       base = 10;
+       if (strcasestr(p, "0x"))
+               base = 16;
+       size = strtoll(p, &next, base);
+       if (next == p && size == 0) {
+               pr_info("shmem: no size specified, using default.");
+               size = default_size;
+       }
+       /* look for [KMGkmg][Bb]*  uses base 2. */
+       int skip_B = 0;
+       if (strspn(next, "KMGkmg")) {   /* might have a prefix */
+               if (*(next + 1) == 'B' || *(next + 1) == 'b')
+                       skip_B = 1;
+               switch (*next) {
+               case 'K':
+               case 'k':
+                       size = size << KB_SHIFT;
+                       break;
+               case 'M':
+               case 'm':
+                       size = size << MB_SHIFT;
+                       break;
+               case 'G':
+               case 'g':
+                       size = size << GB_SHIFT;
+                       break;
+               default:
+                       die("shmem: bug in detecting size prefix.");
+                       break;
+               }
+               next += 1 + skip_B;
+       }
+       if (*next != ':' && *next != '\0') {
+               die("shmem: unexpected chars after phys size. <%c><%c>\n",
+                   *next, *p);
+       }
+       if (*next == '\0')
+               p = next;
+       else
+               p = next + 1;
+       /* parse out optional shmem handle */
+       const int skip_handle = strlen("handle=");
+       next = strcasestr(p, "handle=");
+       if (*p && next) {
+               if (p != next)
+                       die("unexpected chars before handle\n");
+               p += skip_handle;
+               next = strchrnul(p, ':');
+               if (next - p) {
+                       handle = malloc(next - p + 1);
+                       strncpy(handle, p, next - p);
+                       handle[next - p] = '\0';        /* just in case. */
+               }
+               if (*next == '\0')
+                       p = next;
+               else
+                       p = next + 1;
+       }
+       /* parse optional create flag to see if we should create shm seg. */
+       if (*p && strcasestr(p, "create")) {
+               create = 1;
+               p += strlen("create");
+       }
+       if (*p != '\0')
+               die("shmem: unexpected trailing chars\n");
+       if (handle == NULL) {
+               handle = malloc(strlen(default_handle) + 1);
+               strcpy(handle, default_handle);
+       }
+       if (verbose) {
+               pr_info("shmem: phys_addr = %llx", phys_addr);
+               pr_info("shmem: size      = %llx", size);
+               pr_info("shmem: handle    = %s", handle);
+               pr_info("shmem: create    = %d", create);
+       }
+
+       si->phys_addr = phys_addr;
+       si->size = size;
+       si->handle = handle;
+       si->create = create;
+       pci_shmem__register_mem(si);    /* ownership of si, etc. passed on. */
+       return 0;
+}
+
+static const struct option options[] = {
+       OPT_GROUP("Basic options:"),
+       OPT_STRING('\0', "name", &guest_name, "guest name",
+                       "A name for the guest"),
+       OPT_INTEGER('c', "cpus", &nrcpus, "Number of CPUs"),
+       OPT_U64('m', "mem", &ram_size, "Virtual machine memory size in MiB."),
+       OPT_CALLBACK('\0', "shmem", NULL,
+                    "[pci:]<addr>:<size>[:handle=<handle>][:create]",
+                    "Share host shmem with guest via pci device",
+                    shmem_parser),
+       OPT_CALLBACK('d', "disk", NULL, "image or rootfs_dir", "Disk image or rootfs directory", img_name_parser),
+       OPT_BOOLEAN('\0', "balloon", &balloon, "Enable virtio balloon"),
+       OPT_BOOLEAN('\0', "vnc", &vnc, "Enable VNC framebuffer"),
+       OPT_BOOLEAN('\0', "sdl", &sdl, "Enable SDL framebuffer"),
+       OPT_BOOLEAN('\0', "rng", &virtio_rng, "Enable virtio Random Number Generator"),
+       OPT_CALLBACK('\0', "9p", NULL, "dir_to_share,tag_name",
+                    "Enable virtio 9p to share files between host and guest", virtio_9p_rootdir_parser),
+       OPT_STRING('\0', "console", &console, "serial, virtio or hv",
+                       "Console to use"),
+       OPT_STRING('\0', "dev", &dev, "device_file", "KVM device file"),
+       OPT_CALLBACK('\0', "tty", NULL, "tty id",
+                    "Remap guest TTY into a pty on the host",
+                    tty_parser),
+       OPT_STRING('\0', "sandbox", &sandbox, "script",
+                       "Run this script when booting into custom rootfs"),
+       OPT_STRING('\0', "hugetlbfs", &hugetlbfs_path, "path", "Hugetlbfs path"),
+
+       OPT_GROUP("Kernel options:"),
+       OPT_STRING('k', "kernel", &kernel_filename, "kernel",
+                       "Kernel to boot in virtual machine"),
+       OPT_STRING('i', "initrd", &initrd_filename, "initrd",
+                       "Initial RAM disk image"),
+       OPT_STRING('p', "params", &kernel_cmdline, "params",
+                       "Kernel command line arguments"),
+       OPT_STRING('f', "firmware", &firmware_filename, "firmware",
+                       "Firmware image to boot in virtual machine"),
+
+       OPT_GROUP("Networking options:"),
+       OPT_CALLBACK_DEFAULT('n', "network", NULL, "network params",
+                    "Create a new guest NIC",
+                    netdev_parser, NULL),
+       OPT_BOOLEAN('\0', "no-dhcp", &no_dhcp, "Disable kernel DHCP in rootfs mode"),
+
+       OPT_GROUP("BIOS options:"),
+       OPT_INTEGER('\0', "vidmode", &vidmode,
+                   "Video mode"),
+
+       OPT_GROUP("Debug options:"),
+       OPT_BOOLEAN('\0', "debug", &do_debug_print,
+                       "Enable debug messages"),
+       OPT_BOOLEAN('\0', "debug-single-step", &single_step,
+                       "Enable single stepping"),
+       OPT_BOOLEAN('\0', "debug-ioport", &ioport_debug,
+                       "Enable ioport debugging"),
+       OPT_BOOLEAN('\0', "debug-mmio", &mmio_debug,
+                       "Enable MMIO debugging"),
+       OPT_INTEGER('\0', "debug-iodelay", &debug_iodelay,
+                       "Delay IO by millisecond"),
+       OPT_END()
+};
+
+/*
+ * Serialize debug printout so that the output of multiple vcpus does not
+ * get mixed up:
+ */
+static int printout_done;
+
+static void handle_sigusr1(int sig)
+{
+       struct kvm_cpu *cpu = current_kvm_cpu;
+       int fd = kvm_cpu__get_debug_fd();
+
+       if (!cpu || cpu->needs_nmi)
+               return;
+
+       dprintf(fd, "\n #\n # vCPU #%ld's dump:\n #\n", cpu->cpu_id);
+       kvm_cpu__show_registers(cpu);
+       kvm_cpu__show_code(cpu);
+       kvm_cpu__show_page_tables(cpu);
+       fflush(stdout);
+       printout_done = 1;
+       mb();
+}
+
+/* Pause/resume the guest using SIGUSR2 */
+static int is_paused;
+
+static void handle_pause(int fd, u32 type, u32 len, u8 *msg)
+{
+       if (WARN_ON(len))
+               return;
+
+       if (type == KVM_IPC_RESUME && is_paused) {
+               kvm->vm_state = KVM_VMSTATE_RUNNING;
+               kvm__continue();
+       } else if (type == KVM_IPC_PAUSE && !is_paused) {
+               kvm->vm_state = KVM_VMSTATE_PAUSED;
+               ioctl(kvm->vm_fd, KVM_KVMCLOCK_CTRL);
+               kvm__pause();
+       } else {
+               return;
+       }
+
+       is_paused = !is_paused;
+}
+
+static void handle_vmstate(int fd, u32 type, u32 len, u8 *msg)
+{
+       int r = 0;
+
+       if (type == KVM_IPC_VMSTATE)
+               r = write(fd, &kvm->vm_state, sizeof(kvm->vm_state));
+
+       if (r < 0)
+               pr_warning("Failed sending VMSTATE");
+}
+
+static void handle_debug(int fd, u32 type, u32 len, u8 *msg)
+{
+       int i;
+       struct debug_cmd_params *params;
+       u32 dbg_type;
+       u32 vcpu;
+
+       if (WARN_ON(type != KVM_IPC_DEBUG || len != sizeof(*params)))
+               return;
+
+       params = (void *)msg;
+       dbg_type = params->dbg_type;
+       vcpu = params->cpu;
+
+       if (dbg_type & KVM_DEBUG_CMD_TYPE_SYSRQ)
+               serial8250__inject_sysrq(kvm, params->sysrq);
+
+       if (dbg_type & KVM_DEBUG_CMD_TYPE_NMI) {
+               if ((int)vcpu >= kvm->nrcpus)
+                       return;
+
+               kvm_cpus[vcpu]->needs_nmi = 1;
+               pthread_kill(kvm_cpus[vcpu]->thread, SIGUSR1);
+       }
+
+       if (!(dbg_type & KVM_DEBUG_CMD_TYPE_DUMP))
+               return;
+
+       for (i = 0; i < nrcpus; i++) {
+               struct kvm_cpu *cpu = kvm_cpus[i];
+
+               if (!cpu)
+                       continue;
+
+               printout_done = 0;
+
+               kvm_cpu__set_debug_fd(fd);
+               pthread_kill(cpu->thread, SIGUSR1);
+               /*
+                * Wait for the vCPU to dump state before signalling
+                * the next thread. Since this is debug code it does
+                * not matter that we are burning CPU time a bit:
+                */
+               while (!printout_done)
+                       mb();
+       }
+
+       close(fd);
+
+       serial8250__inject_sysrq(kvm, 'p');
+}
+
+static void handle_sigalrm(int sig)
+{
+       kvm__arch_periodic_poll(kvm);
+}
+
+static void handle_stop(int fd, u32 type, u32 len, u8 *msg)
+{
+       if (WARN_ON(type != KVM_IPC_STOP || len))
+               return;
+
+       kvm_cpu__reboot();
+}
+
+static void *kvm_cpu_thread(void *arg)
+{
+       current_kvm_cpu         = arg;
+
+       if (kvm_cpu__start(current_kvm_cpu))
+               goto panic_kvm;
+
+       return (void *) (intptr_t) 0;
+
+panic_kvm:
+       fprintf(stderr, "KVM exit reason: %u (\"%s\")\n",
+               current_kvm_cpu->kvm_run->exit_reason,
+               kvm_exit_reasons[current_kvm_cpu->kvm_run->exit_reason]);
+       if (current_kvm_cpu->kvm_run->exit_reason == KVM_EXIT_UNKNOWN)
+               fprintf(stderr, "KVM exit code: 0x%Lu\n",
+                       current_kvm_cpu->kvm_run->hw.hardware_exit_reason);
+
+       kvm_cpu__set_debug_fd(STDOUT_FILENO);
+       kvm_cpu__show_registers(current_kvm_cpu);
+       kvm_cpu__show_code(current_kvm_cpu);
+       kvm_cpu__show_page_tables(current_kvm_cpu);
+
+       return (void *) (intptr_t) 1;
+}
+
+static char kernel[PATH_MAX];
+
+static const char *host_kernels[] = {
+       "/boot/vmlinuz",
+       "/boot/bzImage",
+       NULL
+};
+
+static const char *default_kernels[] = {
+       "./bzImage",
+       "arch/" BUILD_ARCH "/boot/bzImage",
+       "../../arch/" BUILD_ARCH "/boot/bzImage",
+       NULL
+};
+
+static const char *default_vmlinux[] = {
+       "vmlinux",
+       "../../../vmlinux",
+       "../../vmlinux",
+       NULL
+};
+
+static void kernel_usage_with_options(void)
+{
+       const char **k;
+       struct utsname uts;
+
+       fprintf(stderr, "Fatal: could not find default kernel image in:\n");
+       k = &default_kernels[0];
+       while (*k) {
+               fprintf(stderr, "\t%s\n", *k);
+               k++;
+       }
+
+       if (uname(&uts) < 0)
+               return;
+
+       k = &host_kernels[0];
+       while (*k) {
+               if (snprintf(kernel, PATH_MAX, "%s-%s", *k, uts.release) < 0)
+                       return;
+               fprintf(stderr, "\t%s\n", kernel);
+               k++;
+       }
+       fprintf(stderr, "\nPlease see '%s run --help' for more options.\n\n",
+               KVM_BINARY_NAME);
+}
+
+static u64 host_ram_size(void)
+{
+       long page_size;
+       long nr_pages;
+
+       nr_pages        = sysconf(_SC_PHYS_PAGES);
+       if (nr_pages < 0) {
+               pr_warning("sysconf(_SC_PHYS_PAGES) failed");
+               return 0;
+       }
+
+       page_size       = sysconf(_SC_PAGE_SIZE);
+       if (page_size < 0) {
+               pr_warning("sysconf(_SC_PAGE_SIZE) failed");
+               return 0;
+       }
+
+       return (nr_pages * page_size) >> MB_SHIFT;
+}
+
+/*
+ * If user didn't specify how much memory it wants to allocate for the guest,
+ * avoid filling the whole host RAM.
+ */
+#define RAM_SIZE_RATIO         0.8
+
+static u64 get_ram_size(int nr_cpus)
+{
+       u64 available;
+       u64 ram_size;
+
+       ram_size        = 64 * (nr_cpus + 3);
+
+       available       = host_ram_size() * RAM_SIZE_RATIO;
+       if (!available)
+               available = MIN_RAM_SIZE_MB;
+
+       if (ram_size > available)
+               ram_size        = available;
+
+       return ram_size;
+}
+
+static const char *find_kernel(void)
+{
+       const char **k;
+       struct stat st;
+       struct utsname uts;
+
+       k = &default_kernels[0];
+       while (*k) {
+               if (stat(*k, &st) < 0 || !S_ISREG(st.st_mode)) {
+                       k++;
+                       continue;
+               }
+               strncpy(kernel, *k, PATH_MAX);
+               return kernel;
+       }
+
+       if (uname(&uts) < 0)
+               return NULL;
+
+       k = &host_kernels[0];
+       while (*k) {
+               if (snprintf(kernel, PATH_MAX, "%s-%s", *k, uts.release) < 0)
+                       return NULL;
+
+               if (stat(kernel, &st) < 0 || !S_ISREG(st.st_mode)) {
+                       k++;
+                       continue;
+               }
+               return kernel;
+
+       }
+       return NULL;
+}
+
+static const char *find_vmlinux(void)
+{
+       const char **vmlinux;
+
+       vmlinux = &default_vmlinux[0];
+       while (*vmlinux) {
+               struct stat st;
+
+               if (stat(*vmlinux, &st) < 0 || !S_ISREG(st.st_mode)) {
+                       vmlinux++;
+                       continue;
+               }
+               return *vmlinux;
+       }
+       return NULL;
+}
+
+void kvm_run_help(void)
+{
+       usage_with_options(run_usage, options);
+}
+
+static int kvm_custom_stage2(void)
+{
+       char tmp[PATH_MAX], dst[PATH_MAX], *src;
+       const char *rootfs = custom_rootfs_name;
+       int r;
+
+       src = realpath("guest/init_stage2", NULL);
+       if (src == NULL)
+               return -ENOMEM;
+
+       snprintf(tmp, PATH_MAX, "%s%s/virt/init_stage2", kvm__get_dir(), rootfs);
+       remove(tmp);
+
+       snprintf(dst, PATH_MAX, "/host/%s", src);
+       r = symlink(dst, tmp);
+       free(src);
+
+       return r;
+}
+
+static int kvm_run_set_sandbox(void)
+{
+       const char *guestfs_name = custom_rootfs_name;
+       char path[PATH_MAX], script[PATH_MAX], *tmp;
+
+       snprintf(path, PATH_MAX, "%s%s/virt/sandbox.sh", kvm__get_dir(), guestfs_name);
+
+       remove(path);
+
+       if (sandbox == NULL)
+               return 0;
+
+       tmp = realpath(sandbox, NULL);
+       if (tmp == NULL)
+               return -ENOMEM;
+
+       snprintf(script, PATH_MAX, "/host/%s", tmp);
+       free(tmp);
+
+       return symlink(script, path);
+}
+
+static void kvm_write_sandbox_cmd_exactly(int fd, const char *arg)
+{
+       const char *single_quote;
+
+       if (!*arg) { /* zero length string */
+               if (write(fd, "''", 2) <= 0)
+                       die("Failed writing sandbox script");
+               return;
+       }
+
+       while (*arg) {
+               single_quote = strchrnul(arg, '\'');
+
+               /* write non-single-quote string as #('string') */
+               if (arg != single_quote) {
+                       if (write(fd, "'", 1) <= 0 ||
+                           write(fd, arg, single_quote - arg) <= 0 ||
+                           write(fd, "'", 1) <= 0)
+                               die("Failed writing sandbox script");
+               }
+
+               /* write single quote as #("'") */
+               if (*single_quote) {
+                       if (write(fd, "\"'\"", 3) <= 0)
+                               die("Failed writing sandbox script");
+               } else
+                       break;
+
+               arg = single_quote + 1;
+       }
+}
+
+static void resolve_program(const char *src, char *dst, size_t len)
+{
+       struct stat st;
+       int err;
+
+       err = stat(src, &st);
+
+       if (!err && S_ISREG(st.st_mode)) {
+               char resolved_path[PATH_MAX];
+
+               if (!realpath(src, resolved_path))
+                       die("Unable to resolve program %s: %s\n", src, strerror(errno));
+
+               snprintf(dst, len, "/host%s", resolved_path);
+       } else
+               strncpy(dst, src, len);
+}
+
+static void kvm_run_write_sandbox_cmd(const char **argv, int argc)
+{
+       const char script_hdr[] = "#! /bin/bash\n\n";
+       char program[PATH_MAX];
+       int fd;
+
+       remove(sandbox);
+
+       fd = open(sandbox, O_RDWR | O_CREAT, 0777);
+       if (fd < 0)
+               die("Failed creating sandbox script");
+
+       if (write(fd, script_hdr, sizeof(script_hdr) - 1) <= 0)
+               die("Failed writing sandbox script");
+
+       resolve_program(argv[0], program, PATH_MAX);
+       kvm_write_sandbox_cmd_exactly(fd, program);
+
+       argv++;
+       argc--;
+
+       while (argc) {
+               if (write(fd, " ", 1) <= 0)
+                       die("Failed writing sandbox script");
+
+               kvm_write_sandbox_cmd_exactly(fd, argv[0]);
+               argv++;
+               argc--;
+       }
+       if (write(fd, "\n", 1) <= 0)
+               die("Failed writing sandbox script");
+
+       close(fd);
+}
+
+static int kvm_cmd_run_init(int argc, const char **argv)
+{
+       static char real_cmdline[2048], default_name[20];
+       struct framebuffer *fb = NULL;
+       unsigned int nr_online_cpus;
+       int max_cpus, recommended_cpus;
+       int i, r;
+
+       signal(SIGALRM, handle_sigalrm);
+       kvm_ipc__register_handler(KVM_IPC_DEBUG, handle_debug);
+       signal(SIGUSR1, handle_sigusr1);
+       kvm_ipc__register_handler(KVM_IPC_PAUSE, handle_pause);
+       kvm_ipc__register_handler(KVM_IPC_RESUME, handle_pause);
+       kvm_ipc__register_handler(KVM_IPC_STOP, handle_stop);
+       kvm_ipc__register_handler(KVM_IPC_VMSTATE, handle_vmstate);
+
+       nr_online_cpus = sysconf(_SC_NPROCESSORS_ONLN);
+
+       while (argc != 0) {
+               argc = parse_options(argc, argv, options, run_usage,
+                               PARSE_OPT_STOP_AT_NON_OPTION |
+                               PARSE_OPT_KEEP_DASHDASH);
+               if (argc != 0) {
+                       /* Cusrom options, should have been handled elsewhere */
+                       if (strcmp(argv[0], "--") == 0) {
+                               if (kvm_run_wrapper == KVM_RUN_SANDBOX) {
+                                       sandbox = DEFAULT_SANDBOX_FILENAME;
+                                       kvm_run_write_sandbox_cmd(argv+1, argc-1);
+                                       break;
+                               }
+                       }
+
+                       if ((kvm_run_wrapper == KVM_RUN_DEFAULT && kernel_filename) ||
+                               (kvm_run_wrapper == KVM_RUN_SANDBOX && sandbox)) {
+                               fprintf(stderr, "Cannot handle parameter: "
+                                               "%s\n", argv[0]);
+                               usage_with_options(run_usage, options);
+                               return EINVAL;
+                       }
+                       if (kvm_run_wrapper == KVM_RUN_SANDBOX) {
+                               /*
+                                * first unhandled parameter is treated as
+                                * sandbox command
+                                */
+                               sandbox = DEFAULT_SANDBOX_FILENAME;
+                               kvm_run_write_sandbox_cmd(argv, argc);
+                       } else {
+                               /*
+                                * first unhandled parameter is treated as a kernel
+                                * image
+                                */
+                               kernel_filename = argv[0];
+                       }
+                       argv++;
+                       argc--;
+               }
+
+       }
+
+       if (!kernel_filename)
+               kernel_filename = find_kernel();
+
+       if (!kernel_filename) {
+               kernel_usage_with_options();
+               return EINVAL;
+       }
+
+       vmlinux_filename = find_vmlinux();
+
+       if (nrcpus == 0)
+               nrcpus = nr_online_cpus;
+
+       if (!ram_size)
+               ram_size        = get_ram_size(nrcpus);
+
+       if (ram_size < MIN_RAM_SIZE_MB)
+               die("Not enough memory specified: %lluMB (min %lluMB)", ram_size, MIN_RAM_SIZE_MB);
+
+       if (ram_size > host_ram_size())
+               pr_warning("Guest memory size %lluMB exceeds host physical RAM size %lluMB", ram_size, host_ram_size());
+
+       ram_size <<= MB_SHIFT;
+
+       if (!dev)
+               dev = DEFAULT_KVM_DEV;
+
+       if (!console)
+               console = DEFAULT_CONSOLE;
+
+       if (!strncmp(console, "virtio", 6))
+               active_console  = CONSOLE_VIRTIO;
+       else if (!strncmp(console, "serial", 6))
+               active_console  = CONSOLE_8250;
+       else if (!strncmp(console, "hv", 2))
+               active_console = CONSOLE_HV;
+       else
+               pr_warning("No console!");
+
+       if (!host_ip)
+               host_ip = DEFAULT_HOST_ADDR;
+
+       if (!guest_ip)
+               guest_ip = DEFAULT_GUEST_ADDR;
+
+       if (!guest_mac)
+               guest_mac = DEFAULT_GUEST_MAC;
+
+       if (!host_mac)
+               host_mac = DEFAULT_HOST_MAC;
+
+       if (!script)
+               script = DEFAULT_SCRIPT;
+
+       term_init();
+
+       if (!guest_name) {
+               if (custom_rootfs) {
+                       guest_name = custom_rootfs_name;
+               } else {
+                       sprintf(default_name, "guest-%u", getpid());
+                       guest_name = default_name;
+               }
+       }
+
+       kvm = kvm__init(dev, hugetlbfs_path, ram_size, guest_name);
+       if (IS_ERR(kvm)) {
+               r = PTR_ERR(kvm);
+               goto fail;
+       }
+
+       kvm->single_step = single_step;
+
+       r = ioeventfd__init(kvm);
+       if (r < 0) {
+               pr_err("ioeventfd__init() failed with error %d\n", r);
+               goto fail;
+       }
+
+       max_cpus = kvm__max_cpus(kvm);
+       recommended_cpus = kvm__recommended_cpus(kvm);
+
+       if (nrcpus > max_cpus) {
+               printf("  # Limit the number of CPUs to %d\n", max_cpus);
+               nrcpus = max_cpus;
+       } else if (nrcpus > recommended_cpus) {
+               printf("  # Warning: The maximum recommended amount of VCPUs"
+                       " is %d\n", recommended_cpus);
+       }
+
+       kvm->nrcpus = nrcpus;
+
+       /* Alloc one pointer too many, so array ends up 0-terminated */
+       kvm_cpus = calloc(nrcpus + 1, sizeof(void *));
+       if (!kvm_cpus)
+               die("Couldn't allocate array for %d CPUs", nrcpus);
+
+       r = irq__init(kvm);
+       if (r < 0) {
+               pr_err("irq__init() failed with error %d\n", r);
+               goto fail;
+       }
+
+       r = pci__init(kvm);
+       if (r < 0) {
+               pr_err("pci__init() failed with error %d\n", r);
+               goto fail;
+       }
+
+       r = ioport__init(kvm);
+       if (r < 0) {
+               pr_err("ioport__init() failed with error %d\n", r);
+               goto fail;
+       }
+
+       /*
+        * vidmode should be either specified
+        * either set by default
+        */
+       if (vnc || sdl) {
+               if (vidmode == -1)
+                       vidmode = 0x312;
+       } else {
+               vidmode = 0;
+       }
+
+       memset(real_cmdline, 0, sizeof(real_cmdline));
+       kvm__arch_set_cmdline(real_cmdline, vnc || sdl);
+
+       if (strlen(real_cmdline) > 0)
+               strcat(real_cmdline, " ");
+
+       if (kernel_cmdline)
+               strlcat(real_cmdline, kernel_cmdline, sizeof(real_cmdline));
+
+       if (!using_rootfs && !disk_image[0].filename && !initrd_filename) {
+               char tmp[PATH_MAX];
+
+               kvm_setup_create_new(custom_rootfs_name);
+               kvm_setup_resolv(custom_rootfs_name);
+
+               snprintf(tmp, PATH_MAX, "%s%s", kvm__get_dir(), "default");
+               if (virtio_9p__register(kvm, tmp, "/dev/root") < 0)
+                       die("Unable to initialize virtio 9p");
+               if (virtio_9p__register(kvm, "/", "hostfs") < 0)
+                       die("Unable to initialize virtio 9p");
+               using_rootfs = custom_rootfs = 1;
+       }
+
+       if (using_rootfs) {
+               strcat(real_cmdline, " root=/dev/root rw rootflags=rw,trans=virtio,version=9p2000.L rootfstype=9p");
+               if (custom_rootfs) {
+                       kvm_run_set_sandbox();
+
+                       strcat(real_cmdline, " init=/virt/init");
+
+                       if (!no_dhcp)
+                               strcat(real_cmdline, "  ip=dhcp");
+                       if (kvm_custom_stage2())
+                               die("Failed linking stage 2 of init.");
+               }
+       } else if (!strstr(real_cmdline, "root=")) {
+               strlcat(real_cmdline, " root=/dev/vda rw ", sizeof(real_cmdline));
+       }
+
+       if (image_count) {
+               kvm->nr_disks = image_count;
+               kvm->disks = disk_image__open_all((struct disk_image_params *)&disk_image, image_count);
+               if (IS_ERR(kvm->disks)) {
+                       r = PTR_ERR(kvm->disks);
+                       pr_err("disk_image__open_all() failed with error %ld\n",
+                                       PTR_ERR(kvm->disks));
+                       goto fail;
+               }
+       }
+
+       printf("  # %s run -k %s -m %Lu -c %d --name %s\n", KVM_BINARY_NAME,
+               kernel_filename, ram_size / 1024 / 1024, nrcpus, guest_name);
+
+       if (!firmware_filename) {
+               if (!kvm__load_kernel(kvm, kernel_filename,
+                               initrd_filename, real_cmdline, vidmode))
+                       die("unable to load kernel %s", kernel_filename);
+
+               kvm->vmlinux = vmlinux_filename;
+               r = symbol_init(kvm);
+               if (r < 0)
+                       pr_debug("symbol_init() failed with error %d\n", r);
+       }
+
+       ioport__setup_arch();
+
+       r = rtc__init(kvm);
+       if (r < 0) {
+               pr_err("rtc__init() failed with error %d\n", r);
+               goto fail;
+       }
+
+       r = serial8250__init(kvm);
+       if (r < 0) {
+               pr_err("serial__init() failed with error %d\n", r);
+               goto fail;
+       }
+
+       r = virtio_blk__init(kvm);
+       if (r < 0) {
+               pr_err("virtio_blk__init() failed with error %d\n", r);
+               goto fail;
+       }
+
+       if (active_console == CONSOLE_VIRTIO)
+               virtio_console__init(kvm);
+
+       if (virtio_rng)
+               virtio_rng__init(kvm);
+
+       if (balloon)
+               virtio_bln__init(kvm);
+
+       if (!network)
+               network = DEFAULT_NETWORK;
+
+       virtio_9p__init(kvm);
+
+       for (i = 0; i < num_net_devices; i++) {
+               net_params[i].kvm = kvm;
+               virtio_net__init(&net_params[i]);
+       }
+
+       if (num_net_devices == 0 && no_net == 0) {
+               struct virtio_net_params net_params;
+
+               net_params = (struct virtio_net_params) {
+                       .guest_ip       = guest_ip,
+                       .host_ip        = host_ip,
+                       .kvm            = kvm,
+                       .script         = script,
+                       .mode           = NET_MODE_USER,
+               };
+               str_to_mac(guest_mac, net_params.guest_mac);
+               str_to_mac(host_mac, net_params.host_mac);
+
+               virtio_net__init(&net_params);
+       }
+
+       kvm__init_ram(kvm);
+
+#ifdef CONFIG_X86
+       kbd__init(kvm);
+#endif
+
+       pci_shmem__init(kvm);
+
+       if (vnc || sdl) {
+               fb = vesa__init(kvm);
+               if (IS_ERR(fb)) {
+                       pr_err("vesa__init() failed with error %ld\n", PTR_ERR(fb));
+                       goto fail;
+               }
+       }
+
+       if (vnc && fb) {
+               r = vnc__init(fb);
+               if (r < 0) {
+                       pr_err("vnc__init() failed with error %d\n", r);
+                       goto fail;
+               }
+       }
+
+       if (sdl && fb) {
+               sdl__init(fb);
+               if (r < 0) {
+                       pr_err("sdl__init() failed with error %d\n", r);
+                       goto fail;
+               }
+       }
+
+       r = fb__start();
+       if (r < 0) {
+               pr_err("fb__init() failed with error %d\n", r);
+               goto fail;
+       }
+
+       /* Device init all done; firmware init must
+        * come after this (it may set up device trees etc.)
+        */
+
+       kvm__start_timer(kvm);
+
+       if (firmware_filename) {
+               if (!kvm__load_firmware(kvm, firmware_filename))
+                       die("unable to load firmware image %s: %s", firmware_filename, strerror(errno));
+       } else {
+               kvm__arch_setup_firmware(kvm);
+               if (r < 0) {
+                       pr_err("kvm__arch_setup_firmware() failed with error %d\n", r);
+                       goto fail;
+               }
+       }
+
+       for (i = 0; i < nrcpus; i++) {
+               kvm_cpus[i] = kvm_cpu__init(kvm, i);
+               if (!kvm_cpus[i])
+                       die("unable to initialize KVM VCPU");
+       }
+
+       thread_pool__init(nr_online_cpus);
+fail:
+       return r;
+}
+
+static int kvm_cmd_run_work(void)
+{
+       int i, r = -1;
+       void *ret = NULL;
+
+       for (i = 0; i < nrcpus; i++) {
+               if (pthread_create(&kvm_cpus[i]->thread, NULL, kvm_cpu_thread, kvm_cpus[i]) != 0)
+                       die("unable to create KVM VCPU thread");
+       }
+
+       /* Only VCPU #0 is going to exit by itself when shutting down */
+       if (pthread_join(kvm_cpus[0]->thread, &ret) != 0)
+               r = 0;
+
+       kvm_cpu__delete(kvm_cpus[0]);
+       kvm_cpus[0] = NULL;
+
+       for (i = 1; i < nrcpus; i++) {
+               if (kvm_cpus[i]->is_running) {
+                       pthread_kill(kvm_cpus[i]->thread, SIGKVMEXIT);
+                       if (pthread_join(kvm_cpus[i]->thread, &ret) != 0)
+                               die("pthread_join");
+                       kvm_cpu__delete(kvm_cpus[i]);
+               }
+               if (ret == NULL)
+                       r = 0;
+       }
+
+       return r;
+}
+
+static void kvm_cmd_run_exit(int guest_ret)
+{
+       int r = 0;
+
+       compat__print_all_messages();
+
+       r = symbol_exit(kvm);
+       if (r < 0)
+               pr_warning("symbol_exit() failed with error %d\n", r);
+
+       r = irq__exit(kvm);
+       if (r < 0)
+               pr_warning("irq__exit() failed with error %d\n", r);
+
+       fb__stop();
+
+       r = virtio_blk__exit(kvm);
+       if (r < 0)
+               pr_warning("virtio_blk__exit() failed with error %d\n", r);
+
+       r = virtio_rng__exit(kvm);
+       if (r < 0)
+               pr_warning("virtio_rng__exit() failed with error %d\n", r);
+
+       r = disk_image__close_all(kvm->disks, image_count);
+       if (r < 0)
+               pr_warning("disk_image__close_all() failed with error %d\n", r);
+
+       r = serial8250__exit(kvm);
+       if (r < 0)
+               pr_warning("serial8250__exit() failed with error %d\n", r);
+
+       r = rtc__exit(kvm);
+       if (r < 0)
+               pr_warning("rtc__exit() failed with error %d\n", r);
+
+       r = kvm__arch_free_firmware(kvm);
+       if (r < 0)
+               pr_warning("kvm__arch_free_firmware() failed with error %d\n", r);
+
+       r = ioport__exit(kvm);
+       if (r < 0)
+               pr_warning("ioport__exit() failed with error %d\n", r);
+
+       r = ioeventfd__exit(kvm);
+       if (r < 0)
+               pr_warning("ioeventfd__exit() failed with error %d\n", r);
+
+       r = pci__exit(kvm);
+       if (r < 0)
+               pr_warning("pci__exit() failed with error %d\n", r);
+
+       r = kvm__exit(kvm);
+       if (r < 0)
+               pr_warning("pci__exit() failed with error %d\n", r);
+
+       free(kvm_cpus);
+
+       if (guest_ret == 0)
+               printf("\n  # KVM session ended normally.\n");
+}
+
+int kvm_cmd_run(int argc, const char **argv, const char *prefix)
+{
+       int r, ret = -EFAULT;
+
+       r = kvm_cmd_run_init(argc, argv);
+       if (r < 0)
+               return r;
+
+       ret = kvm_cmd_run_work();
+       kvm_cmd_run_exit(ret);
+
+       return ret;
+}
diff --git a/tools/kvm/builtin-sandbox.c b/tools/kvm/builtin-sandbox.c
new file mode 100644 (file)
index 0000000..433f536
--- /dev/null
@@ -0,0 +1,9 @@
+#include "kvm/builtin-sandbox.h"
+#include "kvm/builtin-run.h"
+
+int kvm_cmd_sandbox(int argc, const char **argv, const char *prefix)
+{
+       kvm_run_set_wrapper_sandbox();
+
+       return kvm_cmd_run(argc, argv, prefix);
+}
diff --git a/tools/kvm/builtin-setup.c b/tools/kvm/builtin-setup.c
new file mode 100644 (file)
index 0000000..232aa60
--- /dev/null
@@ -0,0 +1,232 @@
+#include <kvm/util.h>
+#include <kvm/kvm-cmd.h>
+#include <kvm/builtin-setup.h>
+#include <kvm/kvm.h>
+#include <kvm/parse-options.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+static const char *instance_name;
+
+static const char * const setup_usage[] = {
+       "lkvm setup [name]",
+       NULL
+};
+
+static const struct option setup_options[] = {
+       OPT_END()
+};
+
+static void parse_setup_options(int argc, const char **argv)
+{
+       while (argc != 0) {
+               argc = parse_options(argc, argv, setup_options, setup_usage,
+                               PARSE_OPT_STOP_AT_NON_OPTION);
+               if (argc != 0 && instance_name)
+                       kvm_setup_help();
+               else
+                       instance_name = argv[0];
+               argv++;
+               argc--;
+       }
+}
+
+void kvm_setup_help(void)
+{
+       printf("\n%s setup creates a new rootfs under %s.\n"
+               "This can be used later by the '-d' parameter of '%s run'.\n",
+               KVM_BINARY_NAME, kvm__get_dir(), KVM_BINARY_NAME);
+       usage_with_options(setup_usage, setup_options);
+}
+
+static int copy_file(const char *from, const char *to)
+{
+       int in_fd, out_fd;
+       void *src, *dst;
+       struct stat st;
+       int err = -1;
+
+       in_fd = open(from, O_RDONLY);
+       if (in_fd < 0)
+               return err;
+
+       if (fstat(in_fd, &st) < 0)
+               goto error_close_in;
+
+       out_fd = open(to, O_RDWR | O_CREAT | O_TRUNC, st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO));
+       if (out_fd < 0)
+               goto error_close_in;
+
+       src = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, in_fd, 0);
+       if (src == MAP_FAILED)
+               goto error_close_out;
+
+       if (ftruncate(out_fd, st.st_size) < 0)
+               goto error_munmap_src;
+
+       dst = mmap(NULL, st.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, out_fd, 0);
+       if (dst == MAP_FAILED)
+               goto error_munmap_src;
+
+       memcpy(dst, src, st.st_size);
+
+       if (fsync(out_fd) < 0)
+               goto error_munmap_dst;
+
+       err = 0;
+
+error_munmap_dst:
+       munmap(dst, st.st_size);
+error_munmap_src:
+       munmap(src, st.st_size);
+error_close_out:
+       close(out_fd);
+error_close_in:
+       close(in_fd);
+
+       return err;
+}
+
+static const char *guestfs_dirs[] = {
+       "/dev",
+       "/etc",
+       "/home",
+       "/host",
+       "/proc",
+       "/root",
+       "/sys",
+       "/tmp",
+       "/var",
+       "/var/lib",
+       "/virt",
+};
+
+static const char *guestfs_symlinks[] = {
+       "/bin",
+       "/lib",
+       "/lib64",
+       "/sbin",
+       "/usr",
+       "/etc/ld.so.conf",
+};
+
+static int copy_init(const char *guestfs_name)
+{
+       char path[PATH_MAX];
+
+       snprintf(path, PATH_MAX, "%s%s/virt/init", kvm__get_dir(), guestfs_name);
+
+       return copy_file("guest/init", path);
+}
+
+static int copy_passwd(const char *guestfs_name)
+{
+       char path[PATH_MAX];
+
+       snprintf(path, PATH_MAX, "%s%s/etc/passwd", kvm__get_dir(), guestfs_name);
+
+       return copy_file("guest/passwd", path);
+}
+
+static int make_guestfs_symlink(const char *guestfs_name, const char *path)
+{
+       char target[PATH_MAX];
+       char name[PATH_MAX];
+
+       snprintf(name, PATH_MAX, "%s%s%s", kvm__get_dir(), guestfs_name, path);
+
+       snprintf(target, PATH_MAX, "/host%s", path);
+
+       return symlink(target, name);
+}
+
+static int make_dir(const char *dir)
+{
+       char name[PATH_MAX];
+
+       snprintf(name, PATH_MAX, "%s%s", kvm__get_dir(), dir);
+
+       return mkdir(name, 0777);
+}
+
+static void make_guestfs_dir(const char *guestfs_name, const char *dir)
+{
+       char name[PATH_MAX];
+
+       snprintf(name, PATH_MAX, "%s%s", guestfs_name, dir);
+
+       make_dir(name);
+}
+
+void kvm_setup_resolv(const char *guestfs_name)
+{
+       char path[PATH_MAX];
+
+       snprintf(path, PATH_MAX, "%s%s/etc/resolv.conf", kvm__get_dir(), guestfs_name);
+
+       copy_file("/etc/resolv.conf", path);
+}
+
+static int do_setup(const char *guestfs_name)
+{
+       unsigned int i;
+       int ret;
+
+       ret = make_dir(guestfs_name);
+       if (ret < 0)
+               return ret;
+
+       for (i = 0; i < ARRAY_SIZE(guestfs_dirs); i++)
+               make_guestfs_dir(guestfs_name, guestfs_dirs[i]);
+
+       for (i = 0; i < ARRAY_SIZE(guestfs_symlinks); i++) {
+               make_guestfs_symlink(guestfs_name, guestfs_symlinks[i]);
+       }
+
+       ret = copy_init(guestfs_name);
+       if (ret < 0)
+               return ret;
+
+       return copy_passwd(guestfs_name);
+}
+
+int kvm_setup_create_new(const char *guestfs_name)
+{
+       return do_setup(guestfs_name);
+}
+
+int kvm_cmd_setup(int argc, const char **argv, const char *prefix)
+{
+       int r;
+
+       parse_setup_options(argc, argv);
+
+       if (instance_name == NULL)
+               kvm_setup_help();
+
+       r = do_setup(instance_name);
+       if (r == 0)
+               printf("A new rootfs '%s' has been created in '%s%s'.\n\n"
+                       "You can now start it by running the following command:\n\n"
+                       "  %s run -d %s\n",
+                       instance_name, kvm__get_dir(), instance_name,
+                       KVM_BINARY_NAME,instance_name);
+       else
+               printf("Unable to create rootfs in %s%s: %s\n",
+                       kvm__get_dir(), instance_name, strerror(errno));
+
+       return r;
+}
diff --git a/tools/kvm/builtin-stat.c b/tools/kvm/builtin-stat.c
new file mode 100644 (file)
index 0000000..ffd72e8
--- /dev/null
@@ -0,0 +1,127 @@
+#include <kvm/util.h>
+#include <kvm/kvm-cmd.h>
+#include <kvm/builtin-stat.h>
+#include <kvm/kvm.h>
+#include <kvm/parse-options.h>
+#include <kvm/kvm-ipc.h>
+
+#include <sys/select.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+
+#include <linux/virtio_balloon.h>
+
+static bool mem;
+static bool all;
+static const char *instance_name;
+
+static const char * const stat_usage[] = {
+       "lkvm stat [command] [--all] [-n name]",
+       NULL
+};
+
+static const struct option stat_options[] = {
+       OPT_GROUP("Commands options:"),
+       OPT_BOOLEAN('m', "memory", &mem, "Display memory statistics"),
+       OPT_GROUP("Instance options:"),
+       OPT_BOOLEAN('a', "all", &all, "All instances"),
+       OPT_STRING('n', "name", &instance_name, "name", "Instance name"),
+       OPT_END()
+};
+
+static void parse_stat_options(int argc, const char **argv)
+{
+       while (argc != 0) {
+               argc = parse_options(argc, argv, stat_options, stat_usage,
+                               PARSE_OPT_STOP_AT_NON_OPTION);
+               if (argc != 0)
+                       kvm_stat_help();
+       }
+}
+
+void kvm_stat_help(void)
+{
+       usage_with_options(stat_usage, stat_options);
+}
+
+static int do_memstat(const char *name, int sock)
+{
+       struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR];
+       fd_set fdset;
+       struct timeval t = { .tv_sec = 1 };
+       int r;
+       u8 i;
+
+       FD_ZERO(&fdset);
+       FD_SET(sock, &fdset);
+       r = kvm_ipc__send(sock, KVM_IPC_STAT);
+       if (r < 0)
+               return r;
+
+       r = select(1, &fdset, NULL, NULL, &t);
+       if (r < 0) {
+               pr_err("Could not retrieve mem stats from %s", name);
+               return r;
+       }
+       r = read(sock, &stats, sizeof(stats));
+       if (r < 0)
+               return r;
+
+       printf("\n\n\t*** Guest memory statistics ***\n\n");
+       for (i = 0; i < VIRTIO_BALLOON_S_NR; i++) {
+               switch (stats[i].tag) {
+               case VIRTIO_BALLOON_S_SWAP_IN:
+                       printf("The amount of memory that has been swapped in (in bytes):");
+                       break;
+               case VIRTIO_BALLOON_S_SWAP_OUT:
+                       printf("The amount of memory that has been swapped out to disk (in bytes):");
+                       break;
+               case VIRTIO_BALLOON_S_MAJFLT:
+                       printf("The number of major page faults that have occurred:");
+                       break;
+               case VIRTIO_BALLOON_S_MINFLT:
+                       printf("The number of minor page faults that have occurred:");
+                       break;
+               case VIRTIO_BALLOON_S_MEMFREE:
+                       printf("The amount of memory not being used for any purpose (in bytes):");
+                       break;
+               case VIRTIO_BALLOON_S_MEMTOT:
+                       printf("The total amount of memory available (in bytes):");
+                       break;
+               }
+               printf("%llu\n", stats[i].val);
+       }
+       printf("\n");
+
+       return 0;
+}
+
+int kvm_cmd_stat(int argc, const char **argv, const char *prefix)
+{
+       int instance;
+       int r = 0;
+
+       parse_stat_options(argc, argv);
+
+       if (!mem)
+               usage_with_options(stat_usage, stat_options);
+
+       if (mem && all)
+               return kvm__enumerate_instances(do_memstat);
+
+       if (instance_name == NULL)
+               kvm_stat_help();
+
+       instance = kvm__get_sock_by_instance(instance_name);
+
+       if (instance <= 0)
+               die("Failed locating instance");
+
+       if (mem)
+               r = do_memstat(instance_name, instance);
+
+       close(instance);
+
+       return r;
+}
diff --git a/tools/kvm/builtin-stop.c b/tools/kvm/builtin-stop.c
new file mode 100644 (file)
index 0000000..6067630
--- /dev/null
@@ -0,0 +1,70 @@
+#include <kvm/util.h>
+#include <kvm/kvm-cmd.h>
+#include <kvm/builtin-stop.h>
+#include <kvm/kvm.h>
+#include <kvm/parse-options.h>
+#include <kvm/kvm-ipc.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+
+static bool all;
+static const char *instance_name;
+
+static const char * const stop_usage[] = {
+       "lkvm stop [--all] [-n name]",
+       NULL
+};
+
+static const struct option stop_options[] = {
+       OPT_GROUP("General options:"),
+       OPT_BOOLEAN('a', "all", &all, "Stop all instances"),
+       OPT_STRING('n', "name", &instance_name, "name", "Instance name"),
+       OPT_END()
+};
+
+static void parse_stop_options(int argc, const char **argv)
+{
+       while (argc != 0) {
+               argc = parse_options(argc, argv, stop_options, stop_usage,
+                               PARSE_OPT_STOP_AT_NON_OPTION);
+               if (argc != 0)
+                       kvm_stop_help();
+       }
+}
+
+void kvm_stop_help(void)
+{
+       usage_with_options(stop_usage, stop_options);
+}
+
+static int do_stop(const char *name, int sock)
+{
+       return kvm_ipc__send(sock, KVM_IPC_STOP);
+}
+
+int kvm_cmd_stop(int argc, const char **argv, const char *prefix)
+{
+       int instance;
+       int r;
+
+       parse_stop_options(argc, argv);
+
+       if (all)
+               return kvm__enumerate_instances(do_stop);
+
+       if (instance_name == NULL)
+               kvm_stop_help();
+
+       instance = kvm__get_sock_by_instance(instance_name);
+
+       if (instance <= 0)
+               die("Failed locating instance");
+
+       r = do_stop(instance_name, instance);
+
+       close(instance);
+
+       return r;
+}
diff --git a/tools/kvm/builtin-version.c b/tools/kvm/builtin-version.c
new file mode 100644 (file)
index 0000000..b8bb859
--- /dev/null
@@ -0,0 +1,15 @@
+#include <kvm/util.h>
+#include <kvm/kvm-cmd.h>
+#include <kvm/builtin-version.h>
+#include <kvm/kvm.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+
+int kvm_cmd_version(int argc, const char **argv, const char *prefix)
+{
+       printf("kvm tool %s\n", KVMTOOLS_VERSION);
+
+       return 0;
+}
diff --git a/tools/kvm/code16gcc.h b/tools/kvm/code16gcc.h
new file mode 100644 (file)
index 0000000..d93e480
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * code16gcc.h
+ *
+ * This file is -include'd when compiling 16-bit C code.
+ * Note: this asm() needs to be emitted before gcc emits any code.
+ * Depending on gcc version, this requires -fno-unit-at-a-time or
+ * -fno-toplevel-reorder.
+ *
+ * Hopefully gcc will eventually have a real -m16 option so we can
+ * drop this hack long term.
+ */
+
+#ifndef __ASSEMBLY__
+asm(".code16gcc");
+#endif
diff --git a/tools/kvm/command-list.txt b/tools/kvm/command-list.txt
new file mode 100644 (file)
index 0000000..d93597d
--- /dev/null
@@ -0,0 +1,15 @@
+#
+# List of known perf commands.
+# command name                 category [deprecated] [common]
+#
+lkvm-run                       mainporcelain common
+lkvm-setup                     mainporcelain common
+lkvm-pause                     common
+lkvm-resume                    common
+lkvm-version                   common
+lkvm-list                      common
+lkvm-debug                     common
+lkvm-balloon                   common
+lkvm-stop                      common
+lkvm-stat                      common
+lkvm-sandbox                   common
diff --git a/tools/kvm/config/feature-tests.mak b/tools/kvm/config/feature-tests.mak
new file mode 100644 (file)
index 0000000..4a81f56
--- /dev/null
@@ -0,0 +1,177 @@
+define SOURCE_HELLO
+#include <stdio.h>
+int main(void)
+{
+       return puts(\"hi\");
+}
+endef
+
+ifndef NO_DWARF
+define SOURCE_DWARF
+#include <dwarf.h>
+#include <elfutils/libdw.h>
+#include <elfutils/version.h>
+#ifndef _ELFUTILS_PREREQ
+#error
+#endif
+
+int main(void)
+{
+       Dwarf *dbg = dwarf_begin(0, DWARF_C_READ);
+       return (long)dbg;
+}
+endef
+endif
+
+define SOURCE_LIBELF
+#include <libelf.h>
+
+int main(void)
+{
+       Elf *elf = elf_begin(0, ELF_C_READ, 0);
+       return (long)elf;
+}
+endef
+
+define SOURCE_GLIBC
+#include <gnu/libc-version.h>
+
+int main(void)
+{
+       const char *version = gnu_get_libc_version();
+       return (long)version;
+}
+endef
+
+define SOURCE_ELF_MMAP
+#include <libelf.h>
+int main(void)
+{
+       Elf *elf = elf_begin(0, ELF_C_READ_MMAP, 0);
+       return (long)elf;
+}
+endef
+
+ifndef NO_NEWT
+define SOURCE_NEWT
+#include <newt.h>
+
+int main(void)
+{
+       newtInit();
+       newtCls();
+       return newtFinished();
+}
+endef
+endif
+
+ifndef NO_LIBPERL
+define SOURCE_PERL_EMBED
+#include <EXTERN.h>
+#include <perl.h>
+
+int main(void)
+{
+perl_alloc();
+return 0;
+}
+endef
+endif
+
+ifndef NO_LIBPYTHON
+define SOURCE_PYTHON_VERSION
+#include <Python.h>
+#if PY_VERSION_HEX >= 0x03000000
+       #error
+#endif
+int main(void){}
+endef
+define SOURCE_PYTHON_EMBED
+#include <Python.h>
+int main(void)
+{
+       Py_Initialize();
+       return 0;
+}
+endef
+endif
+
+define SOURCE_BFD
+#include <bfd.h>
+
+int main(void)
+{
+       bfd_demangle(0, 0, 0);
+       return 0;
+}
+endef
+
+define SOURCE_CPLUS_DEMANGLE
+extern char *cplus_demangle(const char *, int);
+
+int main(void)
+{
+       cplus_demangle(0, 0);
+       return 0;
+}
+endef
+
+define SOURCE_STRLCPY
+#include <stdlib.h>
+extern size_t strlcpy(char *dest, const char *src, size_t size);
+
+int main(void)
+{
+       strlcpy(NULL, NULL, 0);
+       return 0;
+}
+endef
+
+define SOURCE_VNCSERVER
+#include <rfb/rfb.h>
+
+int main(void)
+{
+       rfbIsActive((void *)0);
+       return 0;
+}
+endef
+
+define SOURCE_SDL
+#include <SDL/SDL.h>
+
+int main(void)
+{
+       SDL_Init(SDL_INIT_VIDEO);
+       return 0;
+}
+endef
+
+define SOURCE_ZLIB
+#include <zlib.h>
+
+int main(void)
+{
+       inflateInit2(NULL, 0);
+       return 0;
+}
+endef
+
+define SOURCE_AIO
+#include <libaio.h>
+
+int main(void)
+{
+       io_setup(0, NULL);
+       return 0;
+}
+endef
+
+define SOURCE_STATIC
+#include <stdlib.h>
+
+int main(void)
+{
+       return 0;
+}
+endef
diff --git a/tools/kvm/config/utilities.mak b/tools/kvm/config/utilities.mak
new file mode 100644 (file)
index 0000000..a70963b
--- /dev/null
@@ -0,0 +1,196 @@
+# This allows us to work with the newline character:
+define newline
+
+
+endef
+newline := $(newline)
+
+# nl-escape
+#
+# Usage: escape = $(call nl-escape[,escape])
+#
+# This is used as the common way to specify
+# what should replace a newline when escaping
+# newlines; the default is a bizarre string.
+#
+nl-escape = $(or $(1),m822df3020w6a44id34bt574ctac44eb9f4n)
+
+# escape-nl
+#
+# Usage: escaped-text = $(call escape-nl,text[,escape])
+#
+# GNU make's $(shell ...) function converts to a
+# single space each newline character in the output
+# produced during the expansion; this may not be
+# desirable.
+#
+# The only solution is to change each newline into
+# something that won't be converted, so that the
+# information can be recovered later with
+# $(call unescape-nl...)
+#
+escape-nl = $(subst $(newline),$(call nl-escape,$(2)),$(1))
+
+# unescape-nl
+#
+# Usage: text = $(call unescape-nl,escaped-text[,escape])
+#
+# See escape-nl.
+#
+unescape-nl = $(subst $(call nl-escape,$(2)),$(newline),$(1))
+
+# shell-escape-nl
+#
+# Usage: $(shell some-command | $(call shell-escape-nl[,escape]))
+#
+# Use this to escape newlines from within a shell call;
+# the default escape is a bizarre string.
+#
+# NOTE: The escape is used directly as a string constant
+#       in an `awk' program that is delimited by shell
+#       single-quotes, so be wary of the characters
+#       that are chosen.
+#
+define shell-escape-nl
+awk 'NR==1 {t=$$0} NR>1 {t=t "$(nl-escape)" $$0} END {printf t}'
+endef
+
+# shell-unescape-nl
+#
+# Usage: $(shell some-command | $(call shell-unescape-nl[,escape]))
+#
+# Use this to unescape newlines from within a shell call;
+# the default escape is a bizarre string.
+#
+# NOTE: The escape is used directly as an extended regular
+#       expression constant in an `awk' program that is
+#       delimited by shell single-quotes, so be wary
+#       of the characters that are chosen.
+#
+# (The bash shell has a bug where `{gsub(...),...}' is
+#  misinterpreted as a brace expansion; this can be
+#  overcome by putting a space between `{' and `gsub').
+#
+define shell-unescape-nl
+awk 'NR==1 {t=$$0} NR>1 {t=t "\n" $$0} END { gsub(/$(nl-escape)/,"\n",t); printf t }'
+endef
+
+# escape-for-shell-sq
+#
+# Usage: embeddable-text = $(call escape-for-shell-sq,text)
+#
+# This function produces text that is suitable for
+# embedding in a shell string that is delimited by
+# single-quotes.
+#
+escape-for-shell-sq =  $(subst ','\'',$(1))
+
+# shell-sq
+#
+# Usage: single-quoted-and-escaped-text = $(call shell-sq,text)
+#
+shell-sq = '$(escape-for-shell-sq)'
+
+# shell-wordify
+#
+# Usage: wordified-text = $(call shell-wordify,text)
+#
+# For instance:
+#
+#  |define text
+#  |hello
+#  |world
+#  |endef
+#  |
+#  |target:
+#  |   echo $(call shell-wordify,$(text))
+#
+# At least GNU make gets confused by expanding a newline
+# within the context of a command line of a makefile rule
+# (this is in constrast to a `$(shell ...)' function call,
+# which can handle it just fine).
+#
+# This function avoids the problem by producing a string
+# that works as a shell word, regardless of whether or
+# not it contains a newline.
+#
+# If the text to be wordified contains a newline, then
+# an intrictate shell command substitution is constructed
+# to render the text as a single line; when the shell
+# processes the resulting escaped text, it transforms
+# it into the original unescaped text.
+#
+# If the text does not contain a newline, then this function
+# produces the same results as the `$(shell-sq)' function.
+#
+shell-wordify = $(if $(findstring $(newline),$(1)),$(_sw-esc-nl),$(shell-sq))
+define _sw-esc-nl
+"$$(echo $(call escape-nl,$(shell-sq),$(2)) | $(call shell-unescape-nl,$(2)))"
+endef
+
+# is-absolute
+#
+# Usage: bool-value = $(call is-absolute,path)
+#
+is-absolute = $(shell echo $(shell-sq) | grep ^/ -q && echo y)
+
+# lookup
+#
+# Usage: absolute-executable-path-or-empty = $(call lookup,path)
+#
+# (It's necessary to use `sh -c' because GNU make messes up by
+#  trying too hard and getting things wrong).
+#
+lookup = $(call unescape-nl,$(shell sh -c $(_l-sh)))
+_l-sh = $(call shell-sq,command -v $(shell-sq) | $(call shell-escape-nl,))
+
+# is-executable
+#
+# Usage: bool-value = $(call is-executable,path)
+#
+# (It's necessary to use `sh -c' because GNU make messes up by
+#  trying too hard and getting things wrong).
+#
+is-executable = $(call _is-executable-helper,$(shell-sq))
+_is-executable-helper = $(shell sh -c $(_is-executable-sh))
+_is-executable-sh = $(call shell-sq,test -f $(1) -a -x $(1) && echo y)
+
+# get-executable
+#
+# Usage: absolute-executable-path-or-empty = $(call get-executable,path)
+#
+# The goal is to get an absolute path for an executable;
+# the `command -v' is defined by POSIX, but it's not
+# necessarily very portable, so it's only used if
+# relative path resolution is requested, as determined
+# by the presence of a leading `/'.
+#
+get-executable = $(if $(1),$(if $(is-absolute),$(_ge-abspath),$(lookup)))
+_ge-abspath = $(if $(is-executable),$(1))
+
+# get-supplied-or-default-executable
+#
+# 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)))
+endef
+_ge_attempt = $(or $(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))
+
+# try-cc
+# Usage: option = $(call try-cc, source-to-build, cc-options)
+try-cc = $(shell sh -c                                           \
+       'TMP="$(OUTPUT)$(TMPOUT).$$$$";                           \
+        echo "$(1)" |                                            \
+        $(CC) -x c - $(2) -o "$$TMP" > /dev/null 2>&1 && echo y; \
+        rm -f "$$TMP"')
+
+# try-build
+# Usage: option = $(call try-build, source-to-build, cc-options, link-options)
+try-build = $(shell sh -c                                                      \
+       'TMP="$(OUTPUT)$(TMPOUT).$$$$";                                         \
+       echo "$(1)" |                                                           \
+       $(CC) -x c - $(2) $(3) -o "$$TMP" > /dev/null 2>&1 && echo y;           \
+       rm -f "$$TMP"')
diff --git a/tools/kvm/disk/blk.c b/tools/kvm/disk/blk.c
new file mode 100644 (file)
index 0000000..37581d3
--- /dev/null
@@ -0,0 +1,76 @@
+#include "kvm/disk-image.h"
+
+#include <linux/err.h>
+#include <mntent.h>
+
+/*
+ * raw image and blk dev are similar, so reuse raw image ops.
+ */
+static struct disk_image_operations blk_dev_ops = {
+       .read   = raw_image__read,
+       .write  = raw_image__write,
+};
+
+static bool is_mounted(struct stat *st)
+{
+       struct stat st_buf;
+       struct mntent *mnt;
+       FILE *f;
+
+       f = setmntent("/proc/mounts", "r");
+       if (!f)
+               return false;
+
+       while ((mnt = getmntent(f)) != NULL) {
+               if (stat(mnt->mnt_fsname, &st_buf) == 0 &&
+                   S_ISBLK(st_buf.st_mode) && st->st_rdev == st_buf.st_rdev) {
+                       fclose(f);
+                       return true;
+               }
+       }
+
+       fclose(f);
+       return false;
+}
+
+struct disk_image *blkdev__probe(const char *filename, int flags, struct stat *st)
+{
+       struct disk_image *disk;
+       int fd, r;
+       u64 size;
+
+       if (!S_ISBLK(st->st_mode))
+               return ERR_PTR(-EINVAL);
+
+       if (is_mounted(st)) {
+               pr_err("Block device %s is already mounted! Unmount before use.",
+                      filename);
+               return ERR_PTR(-EINVAL);
+       }
+
+       /*
+        * Be careful! We are opening host block device!
+        * Open it readonly since we do not want to break user's data on disk.
+        */
+       fd = open(filename, flags);
+       if (fd < 0)
+               return ERR_PTR(fd);
+
+       if (ioctl(fd, BLKGETSIZE64, &size) < 0) {
+               r = -errno;
+               close(fd);
+               return ERR_PTR(r);
+       }
+
+       /*
+        * FIXME: This will not work on 32-bit host because we can not
+        * mmap large disk. There is not enough virtual address space
+        * in 32-bit host. However, this works on 64-bit host.
+        */
+       disk = disk_image__new(fd, size, &blk_dev_ops, DISK_IMAGE_REGULAR);
+#ifdef CONFIG_HAS_AIO
+               if (!IS_ERR_OR_NULL(disk))
+                       disk->async = 1;
+#endif
+       return disk;
+}
diff --git a/tools/kvm/disk/core.c b/tools/kvm/disk/core.c
new file mode 100644 (file)
index 0000000..621c940
--- /dev/null
@@ -0,0 +1,275 @@
+#include "kvm/disk-image.h"
+#include "kvm/qcow.h"
+#include "kvm/virtio-blk.h"
+
+#include <linux/err.h>
+#include <sys/eventfd.h>
+#include <sys/poll.h>
+
+#define AIO_MAX 256
+
+int debug_iodelay;
+
+#ifdef CONFIG_HAS_AIO
+static void *disk_image__thread(void *param)
+{
+       struct disk_image *disk = param;
+       struct io_event event[AIO_MAX];
+       struct timespec notime = {0};
+       int nr, i;
+       u64 dummy;
+
+       while (read(disk->evt, &dummy, sizeof(dummy)) > 0) {
+               nr = io_getevents(disk->ctx, 1, ARRAY_SIZE(event), event, &notime);
+               for (i = 0; i < nr; i++)
+                       disk->disk_req_cb(event[i].data, event[i].res);
+       }
+
+       return NULL;
+}
+#endif
+
+struct disk_image *disk_image__new(int fd, u64 size,
+                                  struct disk_image_operations *ops,
+                                  int use_mmap)
+{
+       struct disk_image *disk;
+       int r;
+
+       disk = malloc(sizeof *disk);
+       if (!disk)
+               return ERR_PTR(-ENOMEM);
+
+       *disk = (struct disk_image) {
+               .fd     = fd,
+               .size   = size,
+               .ops    = ops,
+       };
+
+       if (use_mmap == DISK_IMAGE_MMAP) {
+               /*
+                * The write to disk image will be discarded
+                */
+               disk->priv = mmap(NULL, size, PROT_RW, MAP_PRIVATE | MAP_NORESERVE, fd, 0);
+               if (disk->priv == MAP_FAILED) {
+                       r = -errno;
+                       free(disk);
+                       return ERR_PTR(r);
+               }
+       }
+
+#ifdef CONFIG_HAS_AIO
+       if (disk) {
+               pthread_t thread;
+
+               disk->evt = eventfd(0, 0);
+               io_setup(AIO_MAX, &disk->ctx);
+               r = pthread_create(&thread, NULL, disk_image__thread, disk);
+               if (r) {
+                       r = -errno;
+                       free(disk);
+                       return ERR_PTR(r);
+               }
+       }
+#endif
+       return disk;
+}
+
+struct disk_image *disk_image__open(const char *filename, bool readonly, bool direct)
+{
+       struct disk_image *disk;
+       struct stat st;
+       int fd, flags;
+
+       if (readonly)
+               flags = O_RDONLY;
+       else
+               flags = O_RDWR;
+       if (direct)
+               flags |= O_DIRECT;
+
+       if (stat(filename, &st) < 0)
+               return ERR_PTR(-errno);
+
+       /* blk device ?*/
+       disk = blkdev__probe(filename, flags, &st);
+       if (!IS_ERR_OR_NULL(disk))
+               return disk;
+
+       fd = open(filename, flags);
+       if (fd < 0)
+               return ERR_PTR(fd);
+
+       /* qcow image ?*/
+       disk = qcow_probe(fd, true);
+       if (!IS_ERR_OR_NULL(disk)) {
+               pr_warning("Forcing read-only support for QCOW");
+               return disk;
+       }
+
+       /* raw image ?*/
+       disk = raw_image__probe(fd, &st, readonly);
+       if (!IS_ERR_OR_NULL(disk))
+               return disk;
+
+       if (close(fd) < 0)
+               pr_warning("close() failed");
+
+       return ERR_PTR(-ENOSYS);
+}
+
+struct disk_image **disk_image__open_all(struct disk_image_params *params, int count)
+{
+       struct disk_image **disks;
+       const char *filename;
+       bool readonly;
+       bool direct;
+       void *err;
+       int i;
+
+       if (!count)
+               return ERR_PTR(-EINVAL);
+       if (count > MAX_DISK_IMAGES)
+               return ERR_PTR(-ENOSPC);
+
+       disks = calloc(count, sizeof(*disks));
+       if (!disks)
+               return ERR_PTR(-ENOMEM);
+
+       for (i = 0; i < count; i++) {
+               filename = params[i].filename;
+               readonly = params[i].readonly;
+               direct = params[i].direct;
+               if (!filename)
+                       continue;
+
+               disks[i] = disk_image__open(filename, readonly, direct);
+               if (IS_ERR_OR_NULL(disks[i])) {
+                       pr_err("Loading disk image '%s' failed", filename);
+                       err = disks[i];
+                       goto error;
+               }
+       }
+
+       return disks;
+error:
+       for (i = 0; i < count; i++)
+               if (!IS_ERR_OR_NULL(disks[i]))
+                       disk_image__close(disks[i]);
+
+       free(disks);
+       return err;
+}
+
+int disk_image__flush(struct disk_image *disk)
+{
+       if (disk->ops->flush)
+               return disk->ops->flush(disk);
+
+       return fsync(disk->fd);
+}
+
+int disk_image__close(struct disk_image *disk)
+{
+       /* If there was no disk image then there's nothing to do: */
+       if (!disk)
+               return 0;
+
+       if (disk->ops->close)
+               return disk->ops->close(disk);
+
+       if (close(disk->fd) < 0)
+               pr_warning("close() failed");
+
+       free(disk);
+
+       return 0;
+}
+
+int disk_image__close_all(struct disk_image **disks, int count)
+{
+       while (count)
+               disk_image__close(disks[--count]);
+
+       free(disks);
+
+       return 0;
+}
+
+/*
+ * Fill iov with disk data, starting from sector 'sector'.
+ * Return amount of bytes read.
+ */
+ssize_t disk_image__read(struct disk_image *disk, u64 sector,
+                        const struct iovec *iov, int iovcount, void *param)
+{
+       ssize_t total = 0;
+
+       if (debug_iodelay)
+               msleep(debug_iodelay);
+
+       if (disk->ops->read) {
+               total = disk->ops->read(disk, sector, iov, iovcount, param);
+               if (total < 0) {
+                       pr_info("disk_image__read error: total=%ld\n", (long)total);
+                       return total;
+               }
+       }
+
+       if (!disk->async && disk->disk_req_cb)
+               disk->disk_req_cb(param, total);
+
+       return total;
+}
+
+/*
+ * Write iov to disk, starting from sector 'sector'.
+ * Return amount of bytes written.
+ */
+ssize_t disk_image__write(struct disk_image *disk, u64 sector,
+                         const struct iovec *iov, int iovcount, void *param)
+{
+       ssize_t total = 0;
+
+       if (debug_iodelay)
+               msleep(debug_iodelay);
+
+       if (disk->ops->write) {
+               /*
+                * Try writev based operation first
+                */
+
+               total = disk->ops->write(disk, sector, iov, iovcount, param);
+               if (total < 0) {
+                       pr_info("disk_image__write error: total=%ld\n", (long)total);
+                       return total;
+               }
+       } else {
+               /* Do nothing */
+       }
+
+       if (!disk->async && disk->disk_req_cb)
+               disk->disk_req_cb(param, total);
+
+       return total;
+}
+
+ssize_t disk_image__get_serial(struct disk_image *disk, void *buffer, ssize_t *len)
+{
+       struct stat st;
+       int r;
+
+       r = fstat(disk->fd, &st);
+       if (r)
+               return r;
+
+       *len = snprintf(buffer, *len, "%llu%llu%llu",
+                       (u64)st.st_dev, (u64)st.st_rdev, (u64)st.st_ino);
+       return *len;
+}
+
+void disk_image__set_callback(struct disk_image *disk,
+                             void (*disk_req_cb)(void *param, long len))
+{
+       disk->disk_req_cb = disk_req_cb;
+}
diff --git a/tools/kvm/disk/qcow.c b/tools/kvm/disk/qcow.c
new file mode 100644 (file)
index 0000000..ee2992e
--- /dev/null
@@ -0,0 +1,1529 @@
+#include "kvm/qcow.h"
+
+#include "kvm/disk-image.h"
+#include "kvm/read-write.h"
+#include "kvm/mutex.h"
+#include "kvm/util.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#ifdef CONFIG_HAS_ZLIB
+#include <zlib.h>
+#endif
+
+#include <linux/err.h>
+#include <linux/byteorder.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+static int update_cluster_refcount(struct qcow *q, u64 clust_idx, u16 append);
+static int qcow_write_refcount_table(struct qcow *q);
+static u64 qcow_alloc_clusters(struct qcow *q, u64 size, int update_ref);
+static void  qcow_free_clusters(struct qcow *q, u64 clust_start, u64 size);
+
+static inline int qcow_pwrite_sync(int fd,
+       void *buf, size_t count, off_t offset)
+{
+       if (pwrite_in_full(fd, buf, count, offset) < 0)
+               return -1;
+
+       return fdatasync(fd);
+}
+
+static int l2_table_insert(struct rb_root *root, struct qcow_l2_table *new)
+{
+       struct rb_node **link = &(root->rb_node), *parent = NULL;
+       u64 offset = new->offset;
+
+       /* search the tree */
+       while (*link) {
+               struct qcow_l2_table *t;
+
+               t = rb_entry(*link, struct qcow_l2_table, node);
+               if (!t)
+                       goto error;
+
+               parent = *link;
+
+               if (t->offset > offset)
+                       link = &(*link)->rb_left;
+               else if (t->offset < offset)
+                       link = &(*link)->rb_right;
+               else
+                       goto out;
+       }
+
+       /* add new node */
+       rb_link_node(&new->node, parent, link);
+       rb_insert_color(&new->node, root);
+out:
+       return 0;
+error:
+       return -1;
+}
+
+static struct qcow_l2_table *l2_table_lookup(struct rb_root *root, u64 offset)
+{
+       struct rb_node *link = root->rb_node;
+
+       while (link) {
+               struct qcow_l2_table *t;
+
+               t = rb_entry(link, struct qcow_l2_table, node);
+               if (!t)
+                       goto out;
+
+               if (t->offset > offset)
+                       link = link->rb_left;
+               else if (t->offset < offset)
+                       link = link->rb_right;
+               else
+                       return t;
+       }
+out:
+       return NULL;
+}
+
+static void l1_table_free_cache(struct qcow_l1_table *l1t)
+{
+       struct rb_root *r = &l1t->root;
+       struct list_head *pos, *n;
+       struct qcow_l2_table *t;
+
+       list_for_each_safe(pos, n, &l1t->lru_list) {
+               /* Remove cache table from the list and RB tree */
+               list_del(pos);
+               t = list_entry(pos, struct qcow_l2_table, list);
+               rb_erase(&t->node, r);
+
+               /* Free the cached node */
+               free(t);
+       }
+}
+
+static int qcow_l2_cache_write(struct qcow *q, struct qcow_l2_table *c)
+{
+       struct qcow_header *header = q->header;
+       u64 size;
+
+       if (!c->dirty)
+               return 0;
+
+       size = 1 << header->l2_bits;
+
+       if (qcow_pwrite_sync(q->fd, c->table,
+               size * sizeof(u64), c->offset) < 0)
+               return -1;
+
+       c->dirty = 0;
+
+       return 0;
+}
+
+static int cache_table(struct qcow *q, struct qcow_l2_table *c)
+{
+       struct qcow_l1_table *l1t = &q->table;
+       struct rb_root *r = &l1t->root;
+       struct qcow_l2_table *lru;
+
+       if (l1t->nr_cached == MAX_CACHE_NODES) {
+               /*
+                * The node at the head of the list is least recently used
+                * node. Remove it from the list and replaced with a new node.
+                */
+               lru = list_first_entry(&l1t->lru_list, struct qcow_l2_table, list);
+
+               /* Remove the node from the cache */
+               rb_erase(&lru->node, r);
+               list_del_init(&lru->list);
+               l1t->nr_cached--;
+
+               /* Free the LRUed node */
+               free(lru);
+       }
+
+       /* Add new node in RB Tree: Helps in searching faster */
+       if (l2_table_insert(r, c) < 0)
+               goto error;
+
+       /* Add in LRU replacement list */
+       list_add_tail(&c->list, &l1t->lru_list);
+       l1t->nr_cached++;
+
+       return 0;
+error:
+       return -1;
+}
+
+static struct qcow_l2_table *l2_table_search(struct qcow *q, u64 offset)
+{
+       struct qcow_l1_table *l1t = &q->table;
+       struct qcow_l2_table *l2t;
+
+       l2t = l2_table_lookup(&l1t->root, offset);
+       if (!l2t)
+               return NULL;
+
+       /* Update the LRU state, by moving the searched node to list tail */
+       list_move_tail(&l2t->list, &l1t->lru_list);
+
+       return l2t;
+}
+
+/* Allocates a new node for caching L2 table */
+static struct qcow_l2_table *new_cache_table(struct qcow *q, u64 offset)
+{
+       struct qcow_header *header = q->header;
+       struct qcow_l2_table *c;
+       u64 l2t_sz;
+       u64 size;
+
+       l2t_sz = 1 << header->l2_bits;
+       size   = sizeof(*c) + l2t_sz * sizeof(u64);
+       c      = calloc(1, size);
+       if (!c)
+               goto out;
+
+       c->offset = offset;
+       RB_CLEAR_NODE(&c->node);
+       INIT_LIST_HEAD(&c->list);
+out:
+       return c;
+}
+
+static inline u64 get_l1_index(struct qcow *q, u64 offset)
+{
+       struct qcow_header *header = q->header;
+
+       return offset >> (header->l2_bits + header->cluster_bits);
+}
+
+static inline u64 get_l2_index(struct qcow *q, u64 offset)
+{
+       struct qcow_header *header = q->header;
+
+       return (offset >> (header->cluster_bits)) & ((1 << header->l2_bits)-1);
+}
+
+static inline u64 get_cluster_offset(struct qcow *q, u64 offset)
+{
+       struct qcow_header *header = q->header;
+
+       return offset & ((1 << header->cluster_bits)-1);
+}
+
+static struct qcow_l2_table *qcow_read_l2_table(struct qcow *q, u64 offset)
+{
+       struct qcow_header *header = q->header;
+       struct qcow_l2_table *l2t;
+       u64 size;
+
+       size = 1 << header->l2_bits;
+
+       /* search an entry for offset in cache */
+       l2t = l2_table_search(q, offset);
+       if (l2t)
+               return l2t;
+
+       /* allocate new node for caching l2 table */
+       l2t = new_cache_table(q, offset);
+       if (!l2t)
+               goto error;
+
+       /* table not cached: read from the disk */
+       if (pread_in_full(q->fd, l2t->table, size * sizeof(u64), offset) < 0)
+               goto error;
+
+       /* cache the table */
+       if (cache_table(q, l2t) < 0)
+               goto error;
+
+       return l2t;
+error:
+       free(l2t);
+       return NULL;
+}
+
+static int qcow_decompress_buffer(u8 *out_buf, int out_buf_size,
+       const u8 *buf, int buf_size)
+{
+#ifdef CONFIG_HAS_ZLIB
+       z_stream strm1, *strm = &strm1;
+       int ret, out_len;
+
+       memset(strm, 0, sizeof(*strm));
+
+       strm->next_in   = (u8 *)buf;
+       strm->avail_in  = buf_size;
+       strm->next_out  = out_buf;
+       strm->avail_out = out_buf_size;
+
+       ret = inflateInit2(strm, -12);
+       if (ret != Z_OK)
+               return -1;
+
+       ret = inflate(strm, Z_FINISH);
+       out_len = strm->next_out - out_buf;
+       if ((ret != Z_STREAM_END && ret != Z_BUF_ERROR) ||
+               out_len != out_buf_size) {
+               inflateEnd(strm);
+               return -1;
+       }
+
+       inflateEnd(strm);
+       return 0;
+#else
+       return -1;
+#endif
+}
+
+static ssize_t qcow1_read_cluster(struct qcow *q, u64 offset,
+       void *dst, u32 dst_len)
+{
+       struct qcow_header *header = q->header;
+       struct qcow_l1_table *l1t = &q->table;
+       struct qcow_l2_table *l2t;
+       u64 clust_offset;
+       u64 clust_start;
+       u64 l2t_offset;
+       size_t length;
+       u64 l2t_size;
+       u64 l1_idx;
+       u64 l2_idx;
+       int coffset;
+       int csize;
+
+       l1_idx = get_l1_index(q, offset);
+       if (l1_idx >= l1t->table_size)
+               return -1;
+
+       clust_offset = get_cluster_offset(q, offset);
+       if (clust_offset >= q->cluster_size)
+               return -1;
+
+       length = q->cluster_size - clust_offset;
+       if (length > dst_len)
+               length = dst_len;
+
+       mutex_lock(&q->mutex);
+
+       l2t_offset = be64_to_cpu(l1t->l1_table[l1_idx]);
+       if (!l2t_offset)
+               goto zero_cluster;
+
+       l2t_size = 1 << header->l2_bits;
+
+       /* read and cache level 2 table */
+       l2t = qcow_read_l2_table(q, l2t_offset);
+       if (!l2t)
+               goto out_error;
+
+       l2_idx = get_l2_index(q, offset);
+       if (l2_idx >= l2t_size)
+               goto out_error;
+
+       clust_start = be64_to_cpu(l2t->table[l2_idx]);
+       if (clust_start & QCOW1_OFLAG_COMPRESSED) {
+               coffset = clust_start & q->cluster_offset_mask;
+               csize   = clust_start >> (63 - q->header->cluster_bits);
+               csize   &= (q->cluster_size - 1);
+
+               if (pread_in_full(q->fd, q->cluster_data, csize,
+                                 coffset) < 0)
+                       goto out_error;
+
+               if (qcow_decompress_buffer(q->cluster_cache, q->cluster_size,
+                                       q->cluster_data, csize) < 0)
+                       goto out_error;
+
+               memcpy(dst, q->cluster_cache + clust_offset, length);
+               mutex_unlock(&q->mutex);
+       } else {
+               if (!clust_start)
+                       goto zero_cluster;
+
+               mutex_unlock(&q->mutex);
+
+               if (pread_in_full(q->fd, dst, length,
+                                 clust_start + clust_offset) < 0)
+                       return -1;
+       }
+
+       return length;
+
+zero_cluster:
+       mutex_unlock(&q->mutex);
+       memset(dst, 0, length);
+       return length;
+
+out_error:
+       mutex_unlock(&q->mutex);
+       length = -1;
+       return -1;
+}
+
+static ssize_t qcow2_read_cluster(struct qcow *q, u64 offset,
+       void *dst, u32 dst_len)
+{
+       struct qcow_header *header = q->header;
+       struct qcow_l1_table *l1t = &q->table;
+       struct qcow_l2_table *l2t;
+       u64 clust_offset;
+       u64 clust_start;
+       u64 l2t_offset;
+       size_t length;
+       u64 l2t_size;
+       u64 l1_idx;
+       u64 l2_idx;
+       int coffset;
+       int sector_offset;
+       int nb_csectors;
+       int csize;
+
+       l1_idx = get_l1_index(q, offset);
+       if (l1_idx >= l1t->table_size)
+               return -1;
+
+       clust_offset = get_cluster_offset(q, offset);
+       if (clust_offset >= q->cluster_size)
+               return -1;
+
+       length = q->cluster_size - clust_offset;
+       if (length > dst_len)
+               length = dst_len;
+
+       mutex_lock(&q->mutex);
+
+       l2t_offset = be64_to_cpu(l1t->l1_table[l1_idx]);
+
+       l2t_offset &= ~QCOW2_OFLAG_COPIED;
+       if (!l2t_offset)
+               goto zero_cluster;
+
+       l2t_size = 1 << header->l2_bits;
+
+       /* read and cache level 2 table */
+       l2t = qcow_read_l2_table(q, l2t_offset);
+       if (!l2t)
+               goto out_error;
+
+       l2_idx = get_l2_index(q, offset);
+       if (l2_idx >= l2t_size)
+               goto out_error;
+
+       clust_start = be64_to_cpu(l2t->table[l2_idx]);
+       if (clust_start & QCOW2_OFLAG_COMPRESSED) {
+               coffset = clust_start & q->cluster_offset_mask;
+               nb_csectors = ((clust_start >> q->csize_shift)
+                       & q->csize_mask) + 1;
+               sector_offset = coffset & (SECTOR_SIZE - 1);
+               csize = nb_csectors * SECTOR_SIZE - sector_offset;
+
+               if (pread_in_full(q->fd, q->cluster_data,
+                                 nb_csectors * SECTOR_SIZE,
+                                 coffset & ~(SECTOR_SIZE - 1)) < 0) {
+                       goto out_error;
+               }
+
+               if (qcow_decompress_buffer(q->cluster_cache, q->cluster_size,
+                                       q->cluster_data + sector_offset,
+                                       csize) < 0) {
+                       goto out_error;
+               }
+
+               memcpy(dst, q->cluster_cache + clust_offset, length);
+               mutex_unlock(&q->mutex);
+       } else {
+               clust_start &= QCOW2_OFFSET_MASK;
+               if (!clust_start)
+                       goto zero_cluster;
+
+               mutex_unlock(&q->mutex);
+
+               if (pread_in_full(q->fd, dst, length,
+                                 clust_start + clust_offset) < 0)
+                       return -1;
+       }
+
+       return length;
+
+zero_cluster:
+       mutex_unlock(&q->mutex);
+       memset(dst, 0, length);
+       return length;
+
+out_error:
+       mutex_unlock(&q->mutex);
+       length = -1;
+       return -1;
+}
+
+static ssize_t qcow_read_sector_single(struct disk_image *disk, u64 sector,
+       void *dst, u32 dst_len)
+{
+       struct qcow *q = disk->priv;
+       struct qcow_header *header = q->header;
+       u32 nr_read;
+       u64 offset;
+       char *buf;
+       u32 nr;
+
+       buf = dst;
+       nr_read = 0;
+
+       while (nr_read < dst_len) {
+               offset = sector << SECTOR_SHIFT;
+               if (offset >= header->size)
+                       return -1;
+
+               if (q->version == QCOW1_VERSION)
+                       nr = qcow1_read_cluster(q, offset, buf,
+                               dst_len - nr_read);
+               else
+                       nr = qcow2_read_cluster(q, offset, buf,
+                               dst_len - nr_read);
+
+               if (nr <= 0)
+                       return -1;
+
+               nr_read += nr;
+               buf     += nr;
+               sector  += (nr >> SECTOR_SHIFT);
+       }
+
+       return dst_len;
+}
+
+static ssize_t qcow_read_sector(struct disk_image *disk, u64 sector,
+                               const struct iovec *iov, int iovcount, void *param)
+{
+       ssize_t nr, total = 0;
+
+       while (iovcount--) {
+               nr = qcow_read_sector_single(disk, sector, iov->iov_base, iov->iov_len);
+               if (nr != (ssize_t)iov->iov_len) {
+                       pr_info("qcow_read_sector error: nr=%ld iov_len=%ld\n", (long)nr, (long)iov->iov_len);
+                       return -1;
+               }
+
+               sector += iov->iov_len >> SECTOR_SHIFT;
+               total += nr;
+               iov++;
+       }
+
+       return total;
+}
+
+static void refcount_table_free_cache(struct qcow_refcount_table *rft)
+{
+       struct rb_root *r = &rft->root;
+       struct list_head *pos, *n;
+       struct qcow_refcount_block *t;
+
+       list_for_each_safe(pos, n, &rft->lru_list) {
+               list_del(pos);
+               t = list_entry(pos, struct qcow_refcount_block, list);
+               rb_erase(&t->node, r);
+
+               free(t);
+       }
+}
+
+static int refcount_block_insert(struct rb_root *root, struct qcow_refcount_block *new)
+{
+       struct rb_node **link = &(root->rb_node), *parent = NULL;
+       u64 offset = new->offset;
+
+       /* search the tree */
+       while (*link) {
+               struct qcow_refcount_block *t;
+
+               t = rb_entry(*link, struct qcow_refcount_block, node);
+               if (!t)
+                       goto error;
+
+               parent = *link;
+
+               if (t->offset > offset)
+                       link = &(*link)->rb_left;
+               else if (t->offset < offset)
+                       link = &(*link)->rb_right;
+               else
+                       goto out;
+       }
+
+       /* add new node */
+       rb_link_node(&new->node, parent, link);
+       rb_insert_color(&new->node, root);
+out:
+       return 0;
+error:
+       return -1;
+}
+
+static int write_refcount_block(struct qcow *q, struct qcow_refcount_block *rfb)
+{
+       if (!rfb->dirty)
+               return 0;
+
+       if (qcow_pwrite_sync(q->fd, rfb->entries,
+               rfb->size * sizeof(u16), rfb->offset) < 0)
+               return -1;
+
+       rfb->dirty = 0;
+
+       return 0;
+}
+
+static int cache_refcount_block(struct qcow *q, struct qcow_refcount_block *c)
+{
+       struct qcow_refcount_table *rft = &q->refcount_table;
+       struct rb_root *r = &rft->root;
+       struct qcow_refcount_block *lru;
+
+       if (rft->nr_cached == MAX_CACHE_NODES) {
+               lru = list_first_entry(&rft->lru_list, struct qcow_refcount_block, list);
+
+               rb_erase(&lru->node, r);
+               list_del_init(&lru->list);
+               rft->nr_cached--;
+
+               free(lru);
+       }
+
+       if (refcount_block_insert(r, c) < 0)
+               goto error;
+
+       list_add_tail(&c->list, &rft->lru_list);
+       rft->nr_cached++;
+
+       return 0;
+error:
+       return -1;
+}
+
+static struct qcow_refcount_block *new_refcount_block(struct qcow *q, u64 rfb_offset)
+{
+       struct qcow_refcount_block *rfb;
+
+       rfb = malloc(sizeof *rfb + q->cluster_size);
+       if (!rfb)
+               return NULL;
+
+       rfb->offset = rfb_offset;
+       rfb->size = q->cluster_size / sizeof(u16);
+       RB_CLEAR_NODE(&rfb->node);
+       INIT_LIST_HEAD(&rfb->list);
+
+       return rfb;
+}
+
+static struct qcow_refcount_block *refcount_block_lookup(struct rb_root *root, u64 offset)
+{
+       struct rb_node *link = root->rb_node;
+
+       while (link) {
+               struct qcow_refcount_block *t;
+
+               t = rb_entry(link, struct qcow_refcount_block, node);
+               if (!t)
+                       goto out;
+
+               if (t->offset > offset)
+                       link = link->rb_left;
+               else if (t->offset < offset)
+                       link = link->rb_right;
+               else
+                       return t;
+       }
+out:
+       return NULL;
+}
+
+static struct qcow_refcount_block *refcount_block_search(struct qcow *q, u64 offset)
+{
+       struct qcow_refcount_table *rft = &q->refcount_table;
+       struct qcow_refcount_block *rfb;
+
+       rfb = refcount_block_lookup(&rft->root, offset);
+       if (!rfb)
+               return NULL;
+
+       /* Update the LRU state, by moving the searched node to list tail */
+       list_move_tail(&rfb->list, &rft->lru_list);
+
+       return rfb;
+}
+
+static struct qcow_refcount_block *qcow_grow_refcount_block(struct qcow *q,
+       u64 clust_idx)
+{
+       struct qcow_header *header = q->header;
+       struct qcow_refcount_table *rft = &q->refcount_table;
+       struct qcow_refcount_block *rfb;
+       u64 new_block_offset;
+       u64 rft_idx;
+
+       rft_idx = clust_idx >> (header->cluster_bits -
+               QCOW_REFCOUNT_BLOCK_SHIFT);
+
+       if (rft_idx >= rft->rf_size) {
+               pr_warning("Don't support grow refcount block table");
+               return NULL;
+       }
+
+       new_block_offset = qcow_alloc_clusters(q, q->cluster_size, 0);
+       if (new_block_offset < 0)
+               return NULL;
+
+       rfb = new_refcount_block(q, new_block_offset);
+       if (!rfb)
+               return NULL;
+
+       memset(rfb->entries, 0x00, q->cluster_size);
+       rfb->dirty = 1;
+
+       /* write refcount block */
+       if (write_refcount_block(q, rfb) < 0)
+               goto free_rfb;
+
+       if (cache_refcount_block(q, rfb) < 0)
+               goto free_rfb;
+
+       rft->rf_table[rft_idx] = cpu_to_be64(new_block_offset);
+       if (update_cluster_refcount(q, new_block_offset >>
+                   header->cluster_bits, 1) < 0)
+               goto recover_rft;
+
+       if (qcow_write_refcount_table(q) < 0)
+               goto recover_rft;
+
+       return rfb;
+
+recover_rft:
+       rft->rf_table[rft_idx] = 0;
+free_rfb:
+       free(rfb);
+       return NULL;
+}
+
+static struct qcow_refcount_block *qcow_read_refcount_block(struct qcow *q, u64 clust_idx)
+{
+       struct qcow_header *header = q->header;
+       struct qcow_refcount_table *rft = &q->refcount_table;
+       struct qcow_refcount_block *rfb;
+       u64 rfb_offset;
+       u64 rft_idx;
+
+       rft_idx = clust_idx >> (header->cluster_bits - QCOW_REFCOUNT_BLOCK_SHIFT);
+       if (rft_idx >= rft->rf_size)
+               return ERR_PTR(-ENOSPC);
+
+       rfb_offset = be64_to_cpu(rft->rf_table[rft_idx]);
+       if (!rfb_offset)
+               return ERR_PTR(-ENOSPC);
+
+       rfb = refcount_block_search(q, rfb_offset);
+       if (rfb)
+               return rfb;
+
+       rfb = new_refcount_block(q, rfb_offset);
+       if (!rfb)
+               return NULL;
+
+       if (pread_in_full(q->fd, rfb->entries, rfb->size * sizeof(u16), rfb_offset) < 0)
+               goto error_free_rfb;
+
+       if (cache_refcount_block(q, rfb) < 0)
+               goto error_free_rfb;
+
+       return rfb;
+
+error_free_rfb:
+       free(rfb);
+
+       return NULL;
+}
+
+static u16 qcow_get_refcount(struct qcow *q, u64 clust_idx)
+{
+       struct qcow_refcount_block *rfb = NULL;
+       struct qcow_header *header = q->header;
+       u64 rfb_idx;
+
+       rfb = qcow_read_refcount_block(q, clust_idx);
+       if (PTR_ERR(rfb) == -ENOSPC)
+               return 0;
+       else if (IS_ERR_OR_NULL(rfb)) {
+               pr_warning("Error while reading refcount table");
+               return -1;
+       }
+
+       rfb_idx = clust_idx & (((1ULL <<
+               (header->cluster_bits - QCOW_REFCOUNT_BLOCK_SHIFT)) - 1));
+
+       if (rfb_idx >= rfb->size) {
+               pr_warning("L1: refcount block index out of bounds");
+               return -1;
+       }
+
+       return be16_to_cpu(rfb->entries[rfb_idx]);
+}
+
+static int update_cluster_refcount(struct qcow *q, u64 clust_idx, u16 append)
+{
+       struct qcow_refcount_block *rfb = NULL;
+       struct qcow_header *header = q->header;
+       u16 refcount;
+       u64 rfb_idx;
+
+       rfb = qcow_read_refcount_block(q, clust_idx);
+       if (PTR_ERR(rfb) == -ENOSPC) {
+               rfb = qcow_grow_refcount_block(q, clust_idx);
+               if (!rfb) {
+                       pr_warning("error while growing refcount table");
+                       return -1;
+               }
+       } else if (IS_ERR_OR_NULL(rfb)) {
+               pr_warning("error while reading refcount table");
+               return -1;
+       }
+
+       rfb_idx = clust_idx & (((1ULL <<
+               (header->cluster_bits - QCOW_REFCOUNT_BLOCK_SHIFT)) - 1));
+       if (rfb_idx >= rfb->size) {
+               pr_warning("refcount block index out of bounds");
+               return -1;
+       }
+
+       refcount = be16_to_cpu(rfb->entries[rfb_idx]) + append;
+       rfb->entries[rfb_idx] = cpu_to_be16(refcount);
+       rfb->dirty = 1;
+
+       /* write refcount block */
+       if (write_refcount_block(q, rfb) < 0) {
+               pr_warning("refcount block index out of bounds");
+               return -1;
+       }
+
+       /* update free_clust_idx since refcount becomes zero */
+       if (!refcount && clust_idx < q->free_clust_idx)
+               q->free_clust_idx = clust_idx;
+
+       return 0;
+}
+
+static void  qcow_free_clusters(struct qcow *q, u64 clust_start, u64 size)
+{
+       struct qcow_header *header = q->header;
+       u64 start, end, offset;
+
+       start = clust_start & ~(q->cluster_size - 1);
+       end = (clust_start + size - 1) & ~(q->cluster_size - 1);
+       for (offset = start; offset <= end; offset += q->cluster_size)
+               update_cluster_refcount(q, offset >> header->cluster_bits, -1);
+}
+
+/*
+ * Allocate clusters according to the size. Find a postion that
+ * can satisfy the size. free_clust_idx is initialized to zero and
+ * Record last position.
+ */
+static u64 qcow_alloc_clusters(struct qcow *q, u64 size, int update_ref)
+{
+       struct qcow_header *header = q->header;
+       u16 clust_refcount;
+       u32 clust_idx = 0, i;
+       u64 clust_num;
+
+       clust_num = (size + (q->cluster_size - 1)) >> header->cluster_bits;
+
+again:
+       for (i = 0; i < clust_num; i++) {
+               clust_idx = q->free_clust_idx++;
+               clust_refcount = qcow_get_refcount(q, clust_idx);
+               if (clust_refcount < 0)
+                       return -1;
+               else if (clust_refcount > 0)
+                       goto again;
+       }
+
+       clust_idx++;
+
+       if (update_ref)
+               for (i = 0; i < clust_num; i++)
+                       if (update_cluster_refcount(q,
+                               clust_idx - clust_num + i, 1))
+                               return -1;
+
+       return (clust_idx - clust_num) << header->cluster_bits;
+}
+
+static int qcow_write_l1_table(struct qcow *q)
+{
+       struct qcow_l1_table *l1t = &q->table;
+       struct qcow_header *header = q->header;
+
+       if (qcow_pwrite_sync(q->fd, l1t->l1_table,
+               l1t->table_size * sizeof(u64),
+               header->l1_table_offset) < 0)
+               return -1;
+
+       return 0;
+}
+
+/*
+ * Get l2 table. If the table has been copied, read table directly.
+ * If the table exists, allocate a new cluster and copy the table
+ * to the new cluster.
+ */
+static int get_cluster_table(struct qcow *q, u64 offset,
+       struct qcow_l2_table **result_l2t, u64 *result_l2_index)
+{
+       struct qcow_header *header = q->header;
+       struct qcow_l1_table *l1t = &q->table;
+       struct qcow_l2_table *l2t;
+       u64 l1t_idx;
+       u64 l2t_offset;
+       u64 l2t_idx;
+       u64 l2t_size;
+       u64 l2t_new_offset;
+
+       l2t_size = 1 << header->l2_bits;
+
+       l1t_idx = get_l1_index(q, offset);
+       if (l1t_idx >= l1t->table_size)
+               return -1;
+
+       l2t_idx = get_l2_index(q, offset);
+       if (l2t_idx >= l2t_size)
+               return -1;
+
+       l2t_offset = be64_to_cpu(l1t->l1_table[l1t_idx]);
+       if (l2t_offset & QCOW2_OFLAG_COPIED) {
+               l2t_offset &= ~QCOW2_OFLAG_COPIED;
+               l2t = qcow_read_l2_table(q, l2t_offset);
+               if (!l2t)
+                       goto error;
+       } else {
+               l2t_new_offset = qcow_alloc_clusters(q,
+                       l2t_size*sizeof(u64), 1);
+
+               if (l2t_new_offset < 0)
+                       goto error;
+
+               l2t = new_cache_table(q, l2t_new_offset);
+               if (!l2t)
+                       goto free_cluster;
+
+               if (l2t_offset) {
+                       l2t = qcow_read_l2_table(q, l2t_offset);
+                       if (!l2t)
+                               goto free_cache;
+               } else
+                       memset(l2t->table, 0x00, l2t_size * sizeof(u64));
+
+               /* write l2 table */
+               l2t->dirty = 1;
+               if (qcow_l2_cache_write(q, l2t) < 0)
+                       goto free_cache;
+
+               /* cache l2 table */
+               if (cache_table(q, l2t))
+                       goto free_cache;
+
+               /* update the l1 talble */
+               l1t->l1_table[l1t_idx] = cpu_to_be64(l2t_new_offset
+                       | QCOW2_OFLAG_COPIED);
+               if (qcow_write_l1_table(q)) {
+                       pr_warning("Update l1 table error");
+                       goto free_cache;
+               }
+
+               /* free old cluster */
+               qcow_free_clusters(q, l2t_offset, q->cluster_size);
+       }
+
+       *result_l2t = l2t;
+       *result_l2_index = l2t_idx;
+
+       return 0;
+
+free_cache:
+       free(l2t);
+
+free_cluster:
+       qcow_free_clusters(q, l2t_new_offset, q->cluster_size);
+
+error:
+       return -1;
+}
+
+/*
+ * If the cluster has been copied, write data directly. If not,
+ * read the original data and write it to the new cluster with
+ * modification.
+ */
+static ssize_t qcow_write_cluster(struct qcow *q, u64 offset,
+               void *buf, u32 src_len)
+{
+       struct qcow_l2_table *l2t;
+       u64 clust_new_start;
+       u64 clust_start;
+       u64 clust_flags;
+       u64 clust_off;
+       u64 l2t_idx;
+       u64 len;
+
+       l2t = NULL;
+
+       clust_off = get_cluster_offset(q, offset);
+       if (clust_off >= q->cluster_size)
+               return -1;
+
+       len = q->cluster_size - clust_off;
+       if (len > src_len)
+               len = src_len;
+
+       mutex_lock(&q->mutex);
+
+       if (get_cluster_table(q, offset, &l2t, &l2t_idx)) {
+               pr_warning("Get l2 table error");
+               goto error;
+       }
+
+       clust_start = be64_to_cpu(l2t->table[l2t_idx]);
+       clust_flags = clust_start & QCOW2_OFLAGS_MASK;
+
+       clust_start &= QCOW2_OFFSET_MASK;
+       if (!(clust_flags & QCOW2_OFLAG_COPIED)) {
+               clust_new_start = qcow_alloc_clusters(q, q->cluster_size, 1);
+               if (clust_new_start < 0) {
+                       pr_warning("Cluster alloc error");
+                       goto error;
+               }
+
+               offset &= ~(q->cluster_size - 1);
+
+               /* if clust_start is not zero, read the original data*/
+               if (clust_start) {
+                       mutex_unlock(&q->mutex);
+                       if (qcow2_read_cluster(q, offset, q->copy_buff,
+                               q->cluster_size) < 0) {
+                               pr_warning("Read copy cluster error");
+                               qcow_free_clusters(q, clust_new_start,
+                                       q->cluster_size);
+                               return -1;
+                       }
+                       mutex_lock(&q->mutex);
+               } else
+                       memset(q->copy_buff, 0x00, q->cluster_size);
+
+               memcpy(q->copy_buff + clust_off, buf, len);
+
+                /* Write actual data */
+               if (pwrite_in_full(q->fd, q->copy_buff, q->cluster_size,
+                       clust_new_start) < 0)
+                       goto free_cluster;
+
+               /* update l2 table*/
+               l2t->table[l2t_idx] = cpu_to_be64(clust_new_start
+                       | QCOW2_OFLAG_COPIED);
+               l2t->dirty = 1;
+
+               if (qcow_l2_cache_write(q, l2t))
+                       goto free_cluster;
+
+               /* free old cluster*/
+               if (clust_flags & QCOW2_OFLAG_COMPRESSED) {
+                       int size;
+                       size = ((clust_start >> q->csize_shift) &
+                               q->csize_mask) + 1;
+                       size *= 512;
+                       clust_start &= q->cluster_offset_mask;
+                       clust_start &= ~511;
+
+                       qcow_free_clusters(q, clust_start, size);
+               } else if (clust_start)
+                       qcow_free_clusters(q, clust_start, q->cluster_size);
+
+       } else {
+               /* Write actual data */
+               if (pwrite_in_full(q->fd, buf, len,
+                       clust_start + clust_off) < 0)
+                       goto error;
+       }
+       mutex_unlock(&q->mutex);
+       return len;
+
+free_cluster:
+       qcow_free_clusters(q, clust_new_start, q->cluster_size);
+
+error:
+       mutex_unlock(&q->mutex);
+       return -1;
+}
+
+static ssize_t qcow_write_sector_single(struct disk_image *disk, u64 sector, void *src, u32 src_len)
+{
+       struct qcow *q = disk->priv;
+       struct qcow_header *header = q->header;
+       u32 nr_written;
+       char *buf;
+       u64 offset;
+       ssize_t nr;
+
+       buf             = src;
+       nr_written      = 0;
+       offset          = sector << SECTOR_SHIFT;
+
+       while (nr_written < src_len) {
+               if (offset >= header->size)
+                       return -1;
+
+               nr = qcow_write_cluster(q, offset, buf, src_len - nr_written);
+               if (nr < 0)
+                       return -1;
+
+               nr_written      += nr;
+               buf             += nr;
+               offset          += nr;
+       }
+
+       return nr_written;
+}
+
+static ssize_t qcow_write_sector(struct disk_image *disk, u64 sector,
+                               const struct iovec *iov, int iovcount, void *param)
+{
+       ssize_t nr, total = 0;
+
+       while (iovcount--) {
+               nr = qcow_write_sector_single(disk, sector, iov->iov_base, iov->iov_len);
+               if (nr != (ssize_t)iov->iov_len) {
+                       pr_info("qcow_write_sector error: nr=%ld iov_len=%ld\n", (long)nr, (long)iov->iov_len);
+                       return -1;
+               }
+
+               sector  += iov->iov_len >> SECTOR_SHIFT;
+               iov++;
+               total   += nr;
+       }
+
+       return total;
+}
+
+static int qcow_disk_flush(struct disk_image *disk)
+{
+       struct qcow *q = disk->priv;
+       struct qcow_refcount_table *rft;
+       struct list_head *pos, *n;
+       struct qcow_l1_table *l1t;
+
+       l1t = &q->table;
+       rft = &q->refcount_table;
+
+       mutex_lock(&q->mutex);
+
+       list_for_each_safe(pos, n, &rft->lru_list) {
+               struct qcow_refcount_block *c = list_entry(pos, struct qcow_refcount_block, list);
+
+               if (write_refcount_block(q, c) < 0)
+                       goto error_unlock;
+       }
+
+       list_for_each_safe(pos, n, &l1t->lru_list) {
+               struct qcow_l2_table *c = list_entry(pos, struct qcow_l2_table, list);
+
+               if (qcow_l2_cache_write(q, c) < 0)
+                       goto error_unlock;
+       }
+
+       if (qcow_write_l1_table < 0)
+               goto error_unlock;
+
+       mutex_unlock(&q->mutex);
+
+       return fsync(disk->fd);
+
+error_unlock:
+       mutex_unlock(&q->mutex);
+       return -1;
+}
+
+static int qcow_disk_close(struct disk_image *disk)
+{
+       struct qcow *q;
+
+       if (!disk)
+               return 0;
+
+       q = disk->priv;
+
+       refcount_table_free_cache(&q->refcount_table);
+       l1_table_free_cache(&q->table);
+       free(q->copy_buff);
+       free(q->cluster_data);
+       free(q->cluster_cache);
+       free(q->refcount_table.rf_table);
+       free(q->table.l1_table);
+       free(q->header);
+       free(q);
+
+       return 0;
+}
+
+static struct disk_image_operations qcow_disk_readonly_ops = {
+       .read   = qcow_read_sector,
+       .close  = qcow_disk_close,
+};
+
+static struct disk_image_operations qcow_disk_ops = {
+       .read   = qcow_read_sector,
+       .write  = qcow_write_sector,
+       .flush  = qcow_disk_flush,
+       .close  = qcow_disk_close,
+};
+
+static int qcow_read_refcount_table(struct qcow *q)
+{
+       struct qcow_header *header = q->header;
+       struct qcow_refcount_table *rft = &q->refcount_table;
+
+       rft->rf_size = (header->refcount_table_size * q->cluster_size)
+               / sizeof(u64);
+
+       rft->rf_table = calloc(rft->rf_size, sizeof(u64));
+       if (!rft->rf_table)
+               return -1;
+
+       rft->root = RB_ROOT;
+       INIT_LIST_HEAD(&rft->lru_list);
+
+       return pread_in_full(q->fd, rft->rf_table, sizeof(u64) * rft->rf_size, header->refcount_table_offset);
+}
+
+static int qcow_write_refcount_table(struct qcow *q)
+{
+       struct qcow_header *header = q->header;
+       struct qcow_refcount_table *rft = &q->refcount_table;
+
+       return qcow_pwrite_sync(q->fd, rft->rf_table,
+               rft->rf_size * sizeof(u64), header->refcount_table_offset);
+}
+
+static int qcow_read_l1_table(struct qcow *q)
+{
+       struct qcow_header *header = q->header;
+       struct qcow_l1_table *table = &q->table;
+
+       table->table_size = header->l1_size;
+
+       table->l1_table = calloc(table->table_size, sizeof(u64));
+       if (!table->l1_table)
+               return -1;
+
+       return pread_in_full(q->fd, table->l1_table, sizeof(u64) * table->table_size, header->l1_table_offset);
+}
+
+static void *qcow2_read_header(int fd)
+{
+       struct qcow2_header_disk f_header;
+       struct qcow_header *header;
+
+       header = malloc(sizeof(struct qcow_header));
+       if (!header)
+               return NULL;
+
+       if (pread_in_full(fd, &f_header, sizeof(struct qcow2_header_disk), 0) < 0) {
+               free(header);
+               return NULL;
+       }
+
+       be32_to_cpus(&f_header.magic);
+       be32_to_cpus(&f_header.version);
+       be64_to_cpus(&f_header.backing_file_offset);
+       be32_to_cpus(&f_header.backing_file_size);
+       be32_to_cpus(&f_header.cluster_bits);
+       be64_to_cpus(&f_header.size);
+       be32_to_cpus(&f_header.crypt_method);
+       be32_to_cpus(&f_header.l1_size);
+       be64_to_cpus(&f_header.l1_table_offset);
+       be64_to_cpus(&f_header.refcount_table_offset);
+       be32_to_cpus(&f_header.refcount_table_clusters);
+       be32_to_cpus(&f_header.nb_snapshots);
+       be64_to_cpus(&f_header.snapshots_offset);
+
+       *header         = (struct qcow_header) {
+               .size                   = f_header.size,
+               .l1_table_offset        = f_header.l1_table_offset,
+               .l1_size                = f_header.l1_size,
+               .cluster_bits           = f_header.cluster_bits,
+               .l2_bits                = f_header.cluster_bits - 3,
+               .refcount_table_offset  = f_header.refcount_table_offset,
+               .refcount_table_size    = f_header.refcount_table_clusters,
+       };
+
+       return header;
+}
+
+static struct disk_image *qcow2_probe(int fd, bool readonly)
+{
+       struct disk_image *disk_image;
+       struct qcow_l1_table *l1t;
+       struct qcow_header *h;
+       struct qcow *q;
+
+       q = calloc(1, sizeof(struct qcow));
+       if (!q)
+               return NULL;
+
+       mutex_init(&q->mutex);
+       q->fd = fd;
+
+       l1t = &q->table;
+
+       l1t->root = RB_ROOT;
+       INIT_LIST_HEAD(&l1t->lru_list);
+
+       h = q->header = qcow2_read_header(fd);
+       if (!h)
+               goto free_qcow;
+
+       q->version = QCOW2_VERSION;
+       q->csize_shift = (62 - (q->header->cluster_bits - 8));
+       q->csize_mask = (1 << (q->header->cluster_bits - 8)) - 1;
+       q->cluster_offset_mask = (1LL << q->csize_shift) - 1;
+       q->cluster_size = 1 << q->header->cluster_bits;
+
+       q->copy_buff = malloc(q->cluster_size);
+       if (!q->copy_buff) {
+               pr_warning("copy buff malloc error");
+               goto free_header;
+       }
+
+       q->cluster_data = malloc(q->cluster_size);
+       if (!q->cluster_data) {
+               pr_warning("cluster data malloc error");
+               goto free_copy_buff;
+       }
+
+       q->cluster_cache = malloc(q->cluster_size);
+       if (!q->cluster_cache) {
+               pr_warning("cluster cache malloc error");
+               goto free_cluster_data;
+       }
+
+       if (qcow_read_l1_table(q) < 0)
+               goto free_cluster_cache;
+
+       if (qcow_read_refcount_table(q) < 0)
+               goto free_l1_table;
+
+       /*
+        * Do not use mmap use read/write instead
+        */
+       if (readonly)
+               disk_image = disk_image__new(fd, h->size, &qcow_disk_readonly_ops, DISK_IMAGE_REGULAR);
+       else
+               disk_image = disk_image__new(fd, h->size, &qcow_disk_ops, DISK_IMAGE_REGULAR);
+
+       if (IS_ERR_OR_NULL(disk_image))
+               goto free_refcount_table;
+
+       disk_image->async = 0;
+       disk_image->priv = q;
+
+       return disk_image;
+
+free_refcount_table:
+       if (q->refcount_table.rf_table)
+               free(q->refcount_table.rf_table);
+free_l1_table:
+       if (q->table.l1_table)
+               free(q->table.l1_table);
+free_cluster_cache:
+       if (q->cluster_cache)
+               free(q->cluster_cache);
+free_cluster_data:
+       if (q->cluster_data)
+               free(q->cluster_data);
+free_copy_buff:
+       if (q->copy_buff)
+               free(q->copy_buff);
+free_header:
+       if (q->header)
+               free(q->header);
+free_qcow:
+       if (q)
+               free(q);
+
+       return NULL;
+}
+
+static bool qcow2_check_image(int fd)
+{
+       struct qcow2_header_disk f_header;
+
+       if (pread_in_full(fd, &f_header, sizeof(struct qcow2_header_disk), 0) < 0)
+               return false;
+
+       be32_to_cpus(&f_header.magic);
+       be32_to_cpus(&f_header.version);
+
+       if (f_header.magic != QCOW_MAGIC)
+               return false;
+
+       if (f_header.version != QCOW2_VERSION)
+               return false;
+
+       return true;
+}
+
+static void *qcow1_read_header(int fd)
+{
+       struct qcow1_header_disk f_header;
+       struct qcow_header *header;
+
+       header = malloc(sizeof(struct qcow_header));
+       if (!header)
+               return NULL;
+
+       if (pread_in_full(fd, &f_header, sizeof(struct qcow1_header_disk), 0) < 0) {
+               free(header);
+               return NULL;
+       }
+
+       be32_to_cpus(&f_header.magic);
+       be32_to_cpus(&f_header.version);
+       be64_to_cpus(&f_header.backing_file_offset);
+       be32_to_cpus(&f_header.backing_file_size);
+       be32_to_cpus(&f_header.mtime);
+       be64_to_cpus(&f_header.size);
+       be32_to_cpus(&f_header.crypt_method);
+       be64_to_cpus(&f_header.l1_table_offset);
+
+       *header         = (struct qcow_header) {
+               .size                   = f_header.size,
+               .l1_table_offset        = f_header.l1_table_offset,
+               .l1_size                = f_header.size / ((1 << f_header.l2_bits) * (1 << f_header.cluster_bits)),
+               .cluster_bits           = f_header.cluster_bits,
+               .l2_bits                = f_header.l2_bits,
+       };
+
+       return header;
+}
+
+static struct disk_image *qcow1_probe(int fd, bool readonly)
+{
+       struct disk_image *disk_image;
+       struct qcow_l1_table *l1t;
+       struct qcow_header *h;
+       struct qcow *q;
+
+       q = calloc(1, sizeof(struct qcow));
+       if (!q)
+               return NULL;
+
+       mutex_init(&q->mutex);
+       q->fd = fd;
+
+       l1t = &q->table;
+
+       l1t->root = RB_ROOT;
+       INIT_LIST_HEAD(&l1t->lru_list);
+
+       h = q->header = qcow1_read_header(fd);
+       if (!h)
+               goto free_qcow;
+
+       q->version = QCOW1_VERSION;
+       q->cluster_size = 1 << q->header->cluster_bits;
+       q->cluster_offset_mask = (1LL << (63 - q->header->cluster_bits)) - 1;
+       q->free_clust_idx = 0;
+
+       q->cluster_data = malloc(q->cluster_size);
+       if (!q->cluster_data) {
+               pr_warning("cluster data malloc error");
+               goto free_header;
+       }
+
+       q->cluster_cache = malloc(q->cluster_size);
+       if (!q->cluster_cache) {
+               pr_warning("cluster cache malloc error");
+               goto free_cluster_data;
+       }
+
+       if (qcow_read_l1_table(q) < 0)
+               goto free_cluster_cache;
+
+       /*
+        * Do not use mmap use read/write instead
+        */
+       if (readonly)
+               disk_image = disk_image__new(fd, h->size, &qcow_disk_readonly_ops, DISK_IMAGE_REGULAR);
+       else
+               disk_image = disk_image__new(fd, h->size, &qcow_disk_ops, DISK_IMAGE_REGULAR);
+
+       if (!disk_image)
+               goto free_l1_table;
+
+       disk_image->async = 1;
+       disk_image->priv = q;
+
+       return disk_image;
+
+free_l1_table:
+       if (q->table.l1_table)
+               free(q->table.l1_table);
+free_cluster_cache:
+       if (q->cluster_cache)
+               free(q->cluster_cache);
+free_cluster_data:
+       if (q->cluster_data)
+               free(q->cluster_data);
+free_header:
+       if (q->header)
+               free(q->header);
+free_qcow:
+       if (q)
+               free(q);
+
+       return NULL;
+}
+
+static bool qcow1_check_image(int fd)
+{
+       struct qcow1_header_disk f_header;
+
+       if (pread_in_full(fd, &f_header, sizeof(struct qcow1_header_disk), 0) < 0)
+               return false;
+
+       be32_to_cpus(&f_header.magic);
+       be32_to_cpus(&f_header.version);
+
+       if (f_header.magic != QCOW_MAGIC)
+               return false;
+
+       if (f_header.version != QCOW1_VERSION)
+               return false;
+
+       return true;
+}
+
+struct disk_image *qcow_probe(int fd, bool readonly)
+{
+       if (qcow1_check_image(fd))
+               return qcow1_probe(fd, readonly);
+
+       if (qcow2_check_image(fd))
+               return qcow2_probe(fd, readonly);
+
+       return NULL;
+}
diff --git a/tools/kvm/disk/raw.c b/tools/kvm/disk/raw.c
new file mode 100644 (file)
index 0000000..93b2b4e
--- /dev/null
@@ -0,0 +1,141 @@
+#include "kvm/disk-image.h"
+
+#include <linux/err.h>
+
+#ifdef CONFIG_HAS_AIO
+#include <libaio.h>
+#endif
+
+ssize_t raw_image__read(struct disk_image *disk, u64 sector, const struct iovec *iov,
+                               int iovcount, void *param)
+{
+       u64 offset = sector << SECTOR_SHIFT;
+
+#ifdef CONFIG_HAS_AIO
+       struct iocb iocb;
+
+       return aio_preadv(disk->ctx, &iocb, disk->fd, iov, iovcount, offset,
+                               disk->evt, param);
+#else
+       return preadv_in_full(disk->fd, iov, iovcount, offset);
+#endif
+}
+
+ssize_t raw_image__write(struct disk_image *disk, u64 sector, const struct iovec *iov,
+                               int iovcount, void *param)
+{
+       u64 offset = sector << SECTOR_SHIFT;
+
+#ifdef CONFIG_HAS_AIO
+       struct iocb iocb;
+
+       return aio_pwritev(disk->ctx, &iocb, disk->fd, iov, iovcount, offset,
+                               disk->evt, param);
+#else
+       return pwritev_in_full(disk->fd, iov, iovcount, offset);
+#endif
+}
+
+ssize_t raw_image__read_mmap(struct disk_image *disk, u64 sector, const struct iovec *iov,
+                               int iovcount, void *param)
+{
+       u64 offset = sector << SECTOR_SHIFT;
+       ssize_t total = 0;
+
+       while (iovcount--) {
+               memcpy(iov->iov_base, disk->priv + offset, iov->iov_len);
+
+               sector  += iov->iov_len >> SECTOR_SHIFT;
+               offset  += iov->iov_len;
+               total   += iov->iov_len;
+               iov++;
+       }
+
+       return total;
+}
+
+ssize_t raw_image__write_mmap(struct disk_image *disk, u64 sector, const struct iovec *iov,
+                               int iovcount, void *param)
+{
+       u64 offset = sector << SECTOR_SHIFT;
+       ssize_t total = 0;
+
+       while (iovcount--) {
+               memcpy(disk->priv + offset, iov->iov_base, iov->iov_len);
+
+               sector  += iov->iov_len >> SECTOR_SHIFT;
+               offset  += iov->iov_len;
+               total   += iov->iov_len;
+               iov++;
+       }
+
+       return total;
+}
+
+int raw_image__close(struct disk_image *disk)
+{
+       int ret = 0;
+
+       if (disk->priv != MAP_FAILED)
+               ret = munmap(disk->priv, disk->size);
+
+       close(disk->evt);
+
+#ifdef CONFIG_HAS_VIRTIO
+       io_destroy(disk->ctx);
+#endif
+
+       return ret;
+}
+
+/*
+ * multiple buffer based disk image operations
+ */
+static struct disk_image_operations raw_image_regular_ops = {
+       .read   = raw_image__read,
+       .write  = raw_image__write,
+};
+
+struct disk_image_operations ro_ops = {
+       .read   = raw_image__read_mmap,
+       .write  = raw_image__write_mmap,
+       .close  = raw_image__close,
+};
+
+struct disk_image_operations ro_ops_nowrite = {
+       .read   = raw_image__read,
+};
+
+struct disk_image *raw_image__probe(int fd, struct stat *st, bool readonly)
+{
+       struct disk_image *disk;
+
+       if (readonly) {
+               /*
+                * Use mmap's MAP_PRIVATE to implement non-persistent write
+                * FIXME: This does not work on 32-bit host.
+                */
+               struct disk_image *disk;
+
+               disk = disk_image__new(fd, st->st_size, &ro_ops, DISK_IMAGE_MMAP);
+               if (IS_ERR_OR_NULL(disk)) {
+                       disk = disk_image__new(fd, st->st_size, &ro_ops_nowrite, DISK_IMAGE_REGULAR);
+#ifdef CONFIG_HAS_AIO
+                       if (!IS_ERR_OR_NULL(disk))
+                               disk->async = 1;
+#endif
+               }
+
+               return disk;
+       } else {
+               /*
+                * Use read/write instead of mmap
+                */
+               disk = disk_image__new(fd, st->st_size, &raw_image_regular_ops, DISK_IMAGE_REGULAR);
+#ifdef CONFIG_HAS_AIO
+               if (!IS_ERR_OR_NULL(disk))
+                       disk->async = 1;
+#endif
+               return disk;
+       }
+}
diff --git a/tools/kvm/framebuffer.c b/tools/kvm/framebuffer.c
new file mode 100644 (file)
index 0000000..e15b717
--- /dev/null
@@ -0,0 +1,75 @@
+#include "kvm/framebuffer.h"
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <errno.h>
+
+static LIST_HEAD(framebuffers);
+
+struct framebuffer *fb__register(struct framebuffer *fb)
+{
+       INIT_LIST_HEAD(&fb->node);
+       list_add(&fb->node, &framebuffers);
+
+       return fb;
+}
+
+int fb__attach(struct framebuffer *fb, struct fb_target_operations *ops)
+{
+       if (fb->nr_targets >= FB_MAX_TARGETS)
+               return -ENOSPC;
+
+       fb->targets[fb->nr_targets++] = ops;
+
+       return 0;
+}
+
+static int start_targets(struct framebuffer *fb)
+{
+       unsigned long i;
+
+       for (i = 0; i < fb->nr_targets; i++) {
+               struct fb_target_operations *ops = fb->targets[i];
+               int err = 0;
+
+               if (ops->start)
+                       err = ops->start(fb);
+
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
+int fb__start(void)
+{
+       struct framebuffer *fb;
+
+       list_for_each_entry(fb, &framebuffers, node) {
+               int err;
+
+               err = start_targets(fb);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
+void fb__stop(void)
+{
+       struct framebuffer *fb;
+
+       list_for_each_entry(fb, &framebuffers, node) {
+               u32 i;
+
+               for (i = 0; i < fb->nr_targets; i++)
+                       if (fb->targets[i]->stop)
+                               fb->targets[i]->stop(fb);
+
+               munmap(fb->mem, fb->mem_size);
+       }
+}
diff --git a/tools/kvm/guest/init.c b/tools/kvm/guest/init.c
new file mode 100644 (file)
index 0000000..032a261
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * This is a simple init for shared rootfs guests. This part should be limited
+ * to doing mounts and running stage 2 of the init process.
+ */
+#include <sys/mount.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+
+static int run_process(char *filename)
+{
+       char *new_argv[] = { filename, NULL };
+       char *new_env[] = { "TERM=linux", NULL };
+
+       return execve(filename, new_argv, new_env);
+}
+
+static void do_mounts(void)
+{
+       mount("hostfs", "/host", "9p", MS_RDONLY, "trans=virtio,version=9p2000.L");
+       mount("", "/sys", "sysfs", 0, NULL);
+       mount("proc", "/proc", "proc", 0, NULL);
+       mount("devtmpfs", "/dev", "devtmpfs", 0, NULL);
+}
+
+int main(int argc, char *argv[])
+{
+       puts("Mounting...");
+
+       do_mounts();
+
+       run_process("/virt/init_stage2");
+
+       printf("Init failed: %s\n", strerror(errno));
+
+       return 0;
+}
diff --git a/tools/kvm/guest/init_stage2.c b/tools/kvm/guest/init_stage2.c
new file mode 100644 (file)
index 0000000..5f93894
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * This is a stage 2 of the init. This part should do all the heavy
+ * lifting such as setting up the console and calling /bin/sh.
+ */
+#include <sys/mount.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <linux/reboot.h>
+
+static int run_process(char *filename)
+{
+       char *new_argv[] = { filename, NULL };
+       char *new_env[] = { "TERM=linux", NULL };
+
+       return execve(filename, new_argv, new_env);
+}
+
+static int run_process_sandbox(char *filename)
+{
+       char *new_argv[] = { filename, "/virt/sandbox.sh", NULL };
+       char *new_env[] = { "TERM=linux", NULL };
+
+       return execve(filename, new_argv, new_env);
+}
+
+int main(int argc, char *argv[])
+{
+       pid_t child;
+       int status;
+
+       /* get session leader */
+       setsid();
+
+       /* set controlling terminal */
+       ioctl(0, TIOCSCTTY, 1);
+
+       child = fork();
+       if (child < 0) {
+               printf("Fatal: fork() failed with %d\n", child);
+               return 0;
+       } else if (child == 0) {
+               if (access("/virt/sandbox.sh", R_OK) == 0)
+                       run_process_sandbox("/bin/sh");
+               else
+                       run_process("/bin/sh");
+       } else {
+               waitpid(child, &status, 0);
+       }
+
+       reboot(LINUX_REBOOT_CMD_RESTART);
+
+       return 0;
+}
diff --git a/tools/kvm/guest/passwd b/tools/kvm/guest/passwd
new file mode 100644 (file)
index 0000000..eb85a55
--- /dev/null
@@ -0,0 +1 @@
+root:x:0:0:root:/root:/bin/sh
diff --git a/tools/kvm/guest_compat.c b/tools/kvm/guest_compat.c
new file mode 100644 (file)
index 0000000..fd4704b
--- /dev/null
@@ -0,0 +1,99 @@
+#include "kvm/guest_compat.h"
+
+#include "kvm/mutex.h"
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+
+struct compat_message {
+       int id;
+       char *title;
+       char *desc;
+
+       struct list_head list;
+};
+
+static int id;
+static DEFINE_MUTEX(compat_mtx);
+static LIST_HEAD(messages);
+
+static void compat__free(struct compat_message *msg)
+{
+       free(msg->title);
+       free(msg->desc);
+       free(msg);
+}
+
+int compat__add_message(const char *title, const char *desc)
+{
+       struct compat_message *msg;
+       int msg_id;
+
+       msg = malloc(sizeof(*msg));
+       if (msg == NULL)
+               goto cleanup;
+
+       msg->title = strdup(title);
+       msg->desc = strdup(desc);
+
+       if (msg->title == NULL || msg->desc == NULL)
+               goto cleanup;
+
+       mutex_lock(&compat_mtx);
+
+       msg->id = msg_id = id++;
+       list_add_tail(&msg->list, &messages);
+
+       mutex_unlock(&compat_mtx);
+
+       return msg_id;
+
+cleanup:
+       if (msg)
+               compat__free(msg);
+
+       return -ENOMEM;
+}
+
+int compat__remove_message(int id)
+{
+       struct compat_message *pos, *n;
+
+       mutex_lock(&compat_mtx);
+
+       list_for_each_entry_safe(pos, n, &messages, list) {
+               if (pos->id == id) {
+                       list_del(&pos->list);
+                       compat__free(pos);
+
+                       mutex_unlock(&compat_mtx);
+
+                       return 0;
+               }
+       }
+
+       mutex_unlock(&compat_mtx);
+
+       return -ENOENT;
+}
+
+int compat__print_all_messages(void)
+{
+       mutex_lock(&compat_mtx);
+
+       while (!list_empty(&messages)) {
+               struct compat_message *msg;
+
+               msg = list_first_entry(&messages, struct compat_message, list);
+
+               printf("\n  # KVM compatibility warning.\n\t%s\n\t%s\n",
+                       msg->title, msg->desc);
+
+               list_del(&msg->list);
+               compat__free(msg);
+       }
+
+       mutex_unlock(&compat_mtx);
+
+       return 0;
+}
diff --git a/tools/kvm/hw/i8042.c b/tools/kvm/hw/i8042.c
new file mode 100644 (file)
index 0000000..3a36425
--- /dev/null
@@ -0,0 +1,348 @@
+#include "kvm/read-write.h"
+#include "kvm/ioport.h"
+#include "kvm/mutex.h"
+#include "kvm/util.h"
+#include "kvm/term.h"
+#include "kvm/kvm.h"
+#include "kvm/i8042.h"
+#include "kvm/kvm-cpu.h"
+
+#include <stdint.h>
+
+/*
+ * IRQs
+ */
+#define KBD_IRQ                        1
+#define AUX_IRQ                        12
+
+/*
+ * Registers
+ */
+#define I8042_DATA_REG         0x60
+#define I8042_COMMAND_REG      0x64
+
+/*
+ * Commands
+ */
+#define I8042_CMD_CTL_RCTR     0x20
+#define I8042_CMD_CTL_WCTR     0x60
+#define I8042_CMD_AUX_LOOP     0xD3
+#define I8042_CMD_AUX_SEND     0xD4
+#define I8042_CMD_AUX_TEST     0xA9
+#define I8042_CMD_AUX_DISABLE  0xA7
+#define I8042_CMD_AUX_ENABLE   0xA8
+#define I8042_CMD_SYSTEM_RESET 0xFE
+
+#define RESPONSE_ACK           0xFA
+
+#define MODE_DISABLE_AUX       0x20
+
+#define AUX_ENABLE_REPORTING   0x20
+#define AUX_SCALING_FLAG       0x10
+#define AUX_DEFAULT_RESOLUTION 0x2
+#define AUX_DEFAULT_SAMPLE     100
+
+/*
+ * Status register bits
+ */
+#define I8042_STR_AUXDATA      0x20
+#define I8042_STR_KEYLOCK      0x10
+#define I8042_STR_CMDDAT       0x08
+#define I8042_STR_MUXERR       0x04
+#define I8042_STR_OBF          0x01
+
+#define KBD_MODE_KBD_INT       0x01
+#define KBD_MODE_SYS           0x02
+
+#define QUEUE_SIZE             128
+
+/*
+ * This represents the current state of the PS/2 keyboard system,
+ * including the AUX device (the mouse)
+ */
+struct kbd_state {
+       struct kvm              *kvm;
+
+       char                    kq[QUEUE_SIZE]; /* Keyboard queue */
+       int                     kread, kwrite;  /* Indexes into the queue */
+       int                     kcount;         /* number of elements in queue */
+
+       char                    mq[QUEUE_SIZE];
+       int                     mread, mwrite;
+       int                     mcount;
+
+       u8                      mstatus;        /* Mouse status byte */
+       u8                      mres;           /* Current mouse resolution */
+       u8                      msample;        /* Current mouse samples/second */
+
+       u8                      mode;           /* i8042 mode register */
+       u8                      status;         /* i8042 status register */
+       /*
+        * Some commands (on port 0x64) have arguments;
+        * we store the command here while we wait for the argument
+        */
+       u32                     write_cmd;
+};
+
+static struct kbd_state                state;
+
+/*
+ * If there are packets to be read, set the appropriate IRQs high
+ */
+static void kbd_update_irq(void)
+{
+       u8 klevel = 0;
+       u8 mlevel = 0;
+
+       /* First, clear the kbd and aux output buffer full bits */
+       state.status &= ~(I8042_STR_OBF | I8042_STR_AUXDATA);
+
+       if (state.kcount > 0) {
+               state.status |= I8042_STR_OBF;
+               klevel = 1;
+       }
+
+       /* Keyboard has higher priority than mouse */
+       if (klevel == 0 && state.mcount != 0) {
+               state.status |= I8042_STR_OBF | I8042_STR_AUXDATA;
+               mlevel = 1;
+       }
+
+       kvm__irq_line(state.kvm, KBD_IRQ, klevel);
+       kvm__irq_line(state.kvm, AUX_IRQ, mlevel);
+}
+
+/*
+ * Add a byte to the mouse queue, then set IRQs
+ */
+void mouse_queue(u8 c)
+{
+       if (state.mcount >= QUEUE_SIZE)
+               return;
+
+       state.mq[state.mwrite++ % QUEUE_SIZE] = c;
+
+       state.mcount++;
+       kbd_update_irq();
+}
+
+/*
+ * Add a byte to the keyboard queue, then set IRQs
+ */
+void kbd_queue(u8 c)
+{
+       if (state.kcount >= QUEUE_SIZE)
+               return;
+
+       state.kq[state.kwrite++ % QUEUE_SIZE] = c;
+
+       state.kcount++;
+       kbd_update_irq();
+}
+
+static void kbd_write_command(struct kvm *kvm, u8 val)
+{
+       switch (val) {
+       case I8042_CMD_CTL_RCTR:
+               kbd_queue(state.mode);
+               break;
+       case I8042_CMD_CTL_WCTR:
+       case I8042_CMD_AUX_SEND:
+       case I8042_CMD_AUX_LOOP:
+               state.write_cmd = val;
+               break;
+       case I8042_CMD_AUX_TEST:
+               /* 0 means we're a normal PS/2 mouse */
+               mouse_queue(0);
+               break;
+       case I8042_CMD_AUX_DISABLE:
+               state.mode |= MODE_DISABLE_AUX;
+               break;
+       case I8042_CMD_AUX_ENABLE:
+               state.mode &= ~MODE_DISABLE_AUX;
+               break;
+       case I8042_CMD_SYSTEM_RESET:
+               kvm_cpu__reboot();
+               break;
+       default:
+               break;
+       }
+}
+
+/*
+ * Called when the OS reads from port 0x60 (PS/2 data)
+ */
+static u32 kbd_read_data(void)
+{
+       u32 ret;
+       int i;
+
+       if (state.kcount != 0) {
+               /* Keyboard data gets read first */
+               ret = state.kq[state.kread++ % QUEUE_SIZE];
+               state.kcount--;
+               kvm__irq_line(state.kvm, KBD_IRQ, 0);
+               kbd_update_irq();
+       } else if (state.mcount > 0) {
+               /* Followed by the mouse */
+               ret = state.mq[state.mread++ % QUEUE_SIZE];
+               state.mcount--;
+               kvm__irq_line(state.kvm, AUX_IRQ, 0);
+               kbd_update_irq();
+       } else if (state.kcount == 0) {
+               i = state.kread - 1;
+               if (i < 0)
+                       i = QUEUE_SIZE;
+               ret = state.kq[i];
+       }
+       return ret;
+}
+
+/*
+ * Called when the OS read from port 0x64, the command port
+ */
+static u32 kbd_read_status(void)
+{
+       return (u32)state.status;
+}
+
+/*
+ * Called when the OS writes to port 0x60 (data port)
+ * Things written here are generally arguments to commands previously
+ * written to port 0x64 and stored in state.write_cmd
+ */
+static void kbd_write_data(u32 val)
+{
+       switch (state.write_cmd) {
+       case I8042_CMD_CTL_WCTR:
+               state.mode = val;
+               kbd_update_irq();
+               break;
+       case I8042_CMD_AUX_LOOP:
+               mouse_queue(val);
+               mouse_queue(RESPONSE_ACK);
+               break;
+       case I8042_CMD_AUX_SEND:
+               /* The OS wants to send a command to the mouse */
+               mouse_queue(RESPONSE_ACK);
+               switch (val) {
+               case 0xe6:
+                       /* set scaling = 1:1 */
+                       state.mstatus &= ~AUX_SCALING_FLAG;
+                       break;
+               case 0xe8:
+                       /* set resolution */
+                       state.mres = val;
+                       break;
+               case 0xe9:
+                       /* Report mouse status/config */
+                       mouse_queue(state.mstatus);
+                       mouse_queue(state.mres);
+                       mouse_queue(state.msample);
+                       break;
+               case 0xf2:
+                       /* send ID */
+                       mouse_queue(0); /* normal mouse */
+                       break;
+               case 0xf3:
+                       /* set sample rate */
+                       state.msample = val;
+                       break;
+               case 0xf4:
+                       /* enable reporting */
+                       state.mstatus |= AUX_ENABLE_REPORTING;
+                       break;
+               case 0xf5:
+                       state.mstatus &= ~AUX_ENABLE_REPORTING;
+                       break;
+               case 0xf6:
+                       /* set defaults, just fall through to reset */
+               case 0xff:
+                       /* reset */
+                       state.mstatus = 0x0;
+                       state.mres = AUX_DEFAULT_RESOLUTION;
+                       state.msample = AUX_DEFAULT_SAMPLE;
+                       break;
+               default:
+                       break;
+       }
+       break;
+       case 0:
+               /* Just send the ID */
+               kbd_queue(RESPONSE_ACK);
+               kbd_queue(0xab);
+               kbd_queue(0x41);
+               kbd_update_irq();
+               break;
+       default:
+               /* Yeah whatever */
+               break;
+       }
+       state.write_cmd = 0;
+}
+
+static void kbd_reset(void)
+{
+       state = (struct kbd_state) {
+               .status         = I8042_STR_MUXERR | I8042_STR_CMDDAT | I8042_STR_KEYLOCK, /* 0x1c */
+               .mode           = KBD_MODE_KBD_INT | KBD_MODE_SYS, /* 0x3 */
+               .mres           = AUX_DEFAULT_RESOLUTION,
+               .msample        = AUX_DEFAULT_SAMPLE,
+       };
+}
+
+/*
+ * Called when the OS has written to one of the keyboard's ports (0x60 or 0x64)
+ */
+static bool kbd_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+       switch (port) {
+       case I8042_COMMAND_REG: {
+               u8 value = kbd_read_status();
+               ioport__write8(data, value);
+               break;
+       }
+       case I8042_DATA_REG: {
+               u32 value = kbd_read_data();
+               ioport__write32(data, value);
+               break;
+       }
+       default:
+               return false;
+       }
+
+       return true;
+}
+
+static bool kbd_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+       switch (port) {
+       case I8042_COMMAND_REG: {
+               u8 value = ioport__read8(data);
+               kbd_write_command(kvm, value);
+               break;
+       }
+       case I8042_DATA_REG: {
+               u32 value = ioport__read32(data);
+               kbd_write_data(value);
+               break;
+       }
+       default:
+               return false;
+       }
+
+       return true;
+}
+
+static struct ioport_operations kbd_ops = {
+       .io_in          = kbd_in,
+       .io_out         = kbd_out,
+};
+
+void kbd__init(struct kvm *kvm)
+{
+       kbd_reset();
+       state.kvm = kvm;
+       ioport__register(I8042_DATA_REG, &kbd_ops, 2, NULL);
+       ioport__register(I8042_COMMAND_REG, &kbd_ops, 2, NULL);
+}
diff --git a/tools/kvm/hw/pci-shmem.c b/tools/kvm/hw/pci-shmem.c
new file mode 100644 (file)
index 0000000..ac2d264
--- /dev/null
@@ -0,0 +1,268 @@
+#include "kvm/pci-shmem.h"
+#include "kvm/virtio-pci-dev.h"
+#include "kvm/irq.h"
+#include "kvm/kvm.h"
+#include "kvm/pci.h"
+#include "kvm/util.h"
+#include "kvm/ioport.h"
+#include "kvm/ioeventfd.h"
+
+#include <linux/kvm.h>
+#include <linux/byteorder.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+static struct pci_device_header pci_shmem_pci_device = {
+       .vendor_id      = cpu_to_le16(PCI_VENDOR_ID_REDHAT_QUMRANET),
+       .device_id      = cpu_to_le16(0x1110),
+       .header_type    = PCI_HEADER_TYPE_NORMAL,
+       .class[2]       = 0xFF, /* misc pci device */
+       .status         = cpu_to_le16(PCI_STATUS_CAP_LIST),
+       .capabilities   = (void *)&pci_shmem_pci_device.msix - (void *)&pci_shmem_pci_device,
+       .msix.cap       = PCI_CAP_ID_MSIX,
+       .msix.ctrl      = cpu_to_le16(1),
+       .msix.table_offset = cpu_to_le32(1),            /* Use BAR 1 */
+       .msix.pba_offset = cpu_to_le32(0x1001),         /* Use BAR 1 */
+};
+
+/* registers for the Inter-VM shared memory device */
+enum ivshmem_registers {
+       INTRMASK = 0,
+       INTRSTATUS = 4,
+       IVPOSITION = 8,
+       DOORBELL = 12,
+};
+
+static struct shmem_info *shmem_region;
+static u16 ivshmem_registers;
+static int local_fd;
+static u32 local_id;
+static u64 msix_block;
+static u64 msix_pba;
+static struct msix_table msix_table[2];
+
+int pci_shmem__register_mem(struct shmem_info *si)
+{
+       if (shmem_region == NULL) {
+               shmem_region = si;
+       } else {
+               pr_warning("only single shmem currently avail. ignoring.\n");
+               free(si);
+       }
+       return 0;
+}
+
+static bool shmem_pci__io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+       u16 offset = port - ivshmem_registers;
+
+       switch (offset) {
+       case INTRMASK:
+               break;
+       case INTRSTATUS:
+               break;
+       case IVPOSITION:
+               ioport__write32(data, local_id);
+               break;
+       case DOORBELL:
+               break;
+       };
+
+       return true;
+}
+
+static bool shmem_pci__io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+       u16 offset = port - ivshmem_registers;
+
+       switch (offset) {
+       case INTRMASK:
+               break;
+       case INTRSTATUS:
+               break;
+       case IVPOSITION:
+               break;
+       case DOORBELL:
+               break;
+       };
+
+       return true;
+}
+
+static struct ioport_operations shmem_pci__io_ops = {
+       .io_in  = shmem_pci__io_in,
+       .io_out = shmem_pci__io_out,
+};
+
+static void callback_mmio_msix(u64 addr, u8 *data, u32 len, u8 is_write, void *ptr)
+{
+       void *mem;
+
+       if (addr - msix_block < 0x1000)
+               mem = &msix_table;
+       else
+               mem = &msix_pba;
+
+       if (is_write)
+               memcpy(mem + addr - msix_block, data, len);
+       else
+               memcpy(data, mem + addr - msix_block, len);
+}
+
+/*
+ * Return an irqfd which can be used by other guests to signal this guest
+ * whenever they need to poke it
+ */
+int pci_shmem__get_local_irqfd(struct kvm *kvm)
+{
+       int fd, gsi, r;
+       struct kvm_irqfd irqfd;
+
+       if (local_fd == 0) {
+               fd = eventfd(0, 0);
+               if (fd < 0)
+                       return fd;
+
+               if (pci_shmem_pci_device.msix.ctrl & cpu_to_le16(PCI_MSIX_FLAGS_ENABLE)) {
+                       gsi = irq__add_msix_route(kvm, &msix_table[0].msg);
+               } else {
+                       gsi = pci_shmem_pci_device.irq_line;
+               }
+
+               irqfd = (struct kvm_irqfd) {
+                       .fd = fd,
+                       .gsi = gsi,
+               };
+
+               r = ioctl(kvm->vm_fd, KVM_IRQFD, &irqfd);
+               if (r < 0)
+                       return r;
+
+               local_fd = fd;
+       }
+
+       return local_fd;
+}
+
+/*
+ * Connect a new client to ivshmem by adding the appropriate datamatch
+ * to the DOORBELL
+ */
+int pci_shmem__add_client(struct kvm *kvm, u32 id, int fd)
+{
+       struct kvm_ioeventfd ioevent;
+
+       ioevent = (struct kvm_ioeventfd) {
+               .addr           = ivshmem_registers + DOORBELL,
+               .len            = sizeof(u32),
+               .datamatch      = id,
+               .fd             = fd,
+               .flags          = KVM_IOEVENTFD_FLAG_PIO | KVM_IOEVENTFD_FLAG_DATAMATCH,
+       };
+
+       return ioctl(kvm->vm_fd, KVM_IOEVENTFD, &ioevent);
+}
+
+/*
+ * Remove a client connected to ivshmem by removing the appropriate datamatch
+ * from the DOORBELL
+ */
+int pci_shmem__remove_client(struct kvm *kvm, u32 id)
+{
+       struct kvm_ioeventfd ioevent;
+
+       ioevent = (struct kvm_ioeventfd) {
+               .addr           = ivshmem_registers + DOORBELL,
+               .len            = sizeof(u32),
+               .datamatch      = id,
+               .flags          = KVM_IOEVENTFD_FLAG_PIO
+                               | KVM_IOEVENTFD_FLAG_DATAMATCH
+                               | KVM_IOEVENTFD_FLAG_DEASSIGN,
+       };
+
+       return ioctl(kvm->vm_fd, KVM_IOEVENTFD, &ioevent);
+}
+
+static void *setup_shmem(const char *key, size_t len, int creating)
+{
+       int fd;
+       int rtn;
+       void *mem;
+       int flag = O_RDWR;
+
+       if (creating)
+               flag |= O_CREAT;
+
+       fd = shm_open(key, flag, S_IRUSR | S_IWUSR);
+       if (fd < 0) {
+               pr_warning("Failed to open shared memory file %s\n", key);
+               return NULL;
+       }
+
+       if (creating) {
+               rtn = ftruncate(fd, (off_t) len);
+               if (rtn < 0)
+                       pr_warning("Can't ftruncate(fd,%zu)\n", len);
+       }
+       mem = mmap(NULL, len,
+                  PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NORESERVE, fd, 0);
+       if (mem == MAP_FAILED) {
+               pr_warning("Failed to mmap shared memory file");
+               mem = NULL;
+       }
+       close(fd);
+
+       return mem;
+}
+
+int pci_shmem__init(struct kvm *kvm)
+{
+       u8 dev, line, pin;
+       char *mem;
+       int r;
+
+       if (shmem_region == 0)
+               return 0;
+
+       /* Register good old INTx */
+       if (irq__register_device(PCI_DEVICE_ID_PCI_SHMEM, &dev, &pin, &line) < 0)
+               return 0;
+
+       pci_shmem_pci_device.irq_pin = pin;
+       pci_shmem_pci_device.irq_line = line;
+
+       /* Register MMIO space for MSI-X */
+       r = ioport__register(IOPORT_EMPTY, &shmem_pci__io_ops, IOPORT_SIZE, NULL);
+       if (r < 0)
+               return r;
+       ivshmem_registers = (u16)r;
+
+       msix_block = pci_get_io_space_block(0x1010);
+       kvm__register_mmio(kvm, msix_block, 0x1010, false, callback_mmio_msix, NULL);
+
+       /*
+        * This registers 3 BARs:
+        *
+        * 0 - ivshmem registers
+        * 1 - MSI-X MMIO space
+        * 2 - Shared memory block
+        */
+       pci_shmem_pci_device.bar[0] = cpu_to_le32(ivshmem_registers | PCI_BASE_ADDRESS_SPACE_IO);
+       pci_shmem_pci_device.bar_size[0] = shmem_region->size;
+       pci_shmem_pci_device.bar[1] = cpu_to_le32(msix_block | PCI_BASE_ADDRESS_SPACE_MEMORY);
+       pci_shmem_pci_device.bar_size[1] = 0x1010;
+       pci_shmem_pci_device.bar[2] = cpu_to_le32(shmem_region->phys_addr | PCI_BASE_ADDRESS_SPACE_MEMORY);
+       pci_shmem_pci_device.bar_size[2] = shmem_region->size;
+
+       pci__register(&pci_shmem_pci_device, dev);
+
+       /* Open shared memory and plug it into the guest */
+       mem = setup_shmem(shmem_region->handle, shmem_region->size,
+                               shmem_region->create);
+       if (mem == NULL)
+               return 0;
+       kvm__register_mem(kvm, shmem_region->phys_addr, shmem_region->size,
+                         mem);
+       return 1;
+}
diff --git a/tools/kvm/hw/rtc.c b/tools/kvm/hw/rtc.c
new file mode 100644 (file)
index 0000000..b4f9f1f
--- /dev/null
@@ -0,0 +1,137 @@
+#include "kvm/rtc.h"
+
+#include "kvm/ioport.h"
+#include "kvm/kvm.h"
+
+#include <time.h>
+
+/*
+ * MC146818 RTC registers
+ */
+#define RTC_SECONDS                    0x00
+#define RTC_SECONDS_ALARM              0x01
+#define RTC_MINUTES                    0x02
+#define RTC_MINUTES_ALARM              0x03
+#define RTC_HOURS                      0x04
+#define RTC_HOURS_ALARM                        0x05
+#define RTC_DAY_OF_WEEK                        0x06
+#define RTC_DAY_OF_MONTH               0x07
+#define RTC_MONTH                      0x08
+#define RTC_YEAR                       0x09
+
+#define RTC_REG_A                      0x0A
+#define RTC_REG_B                      0x0B
+#define RTC_REG_C                      0x0C
+#define RTC_REG_D                      0x0D
+
+struct rtc_device {
+       u8                      cmos_idx;
+       u8                      cmos_data[128];
+};
+
+static struct rtc_device       rtc;
+
+static inline unsigned char bin2bcd(unsigned val)
+{
+       return ((val / 10) << 4) + val % 10;
+}
+
+static bool cmos_ram_data_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+       struct tm *tm;
+       time_t ti;
+
+       time(&ti);
+
+       tm = gmtime(&ti);
+
+       switch (rtc.cmos_idx) {
+       case RTC_SECONDS:
+               ioport__write8(data, bin2bcd(tm->tm_sec));
+               break;
+       case RTC_MINUTES:
+               ioport__write8(data, bin2bcd(tm->tm_min));
+               break;
+       case RTC_HOURS:
+               ioport__write8(data, bin2bcd(tm->tm_hour));
+               break;
+       case RTC_DAY_OF_WEEK:
+               ioport__write8(data, bin2bcd(tm->tm_wday + 1));
+               break;
+       case RTC_DAY_OF_MONTH:
+               ioport__write8(data, bin2bcd(tm->tm_mday));
+               break;
+       case RTC_MONTH:
+               ioport__write8(data, bin2bcd(tm->tm_mon + 1));
+               break;
+       case RTC_YEAR:
+               ioport__write8(data, bin2bcd(tm->tm_year));
+               break;
+       default:
+               ioport__write8(data, rtc.cmos_data[rtc.cmos_idx]);
+               break;
+       }
+
+       return true;
+}
+
+static bool cmos_ram_data_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+       switch (rtc.cmos_idx) {
+       case RTC_REG_C:
+       case RTC_REG_D:
+               /* Read-only */
+               break;
+       default:
+               rtc.cmos_data[rtc.cmos_idx] = ioport__read8(data);
+               break;
+       }
+
+       return true;
+}
+
+static struct ioport_operations cmos_ram_data_ioport_ops = {
+       .io_out         = cmos_ram_data_out,
+       .io_in          = cmos_ram_data_in,
+};
+
+static bool cmos_ram_index_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+       u8 value = ioport__read8(data);
+
+       kvm->nmi_disabled       = value & (1UL << 7);
+       rtc.cmos_idx            = value & ~(1UL << 7);
+
+       return true;
+}
+
+static struct ioport_operations cmos_ram_index_ioport_ops = {
+       .io_out         = cmos_ram_index_out,
+};
+
+int rtc__init(struct kvm *kvm)
+{
+       int r = 0;
+
+       /* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */
+       r = ioport__register(0x0070, &cmos_ram_index_ioport_ops, 1, NULL);
+       if (r < 0)
+               return r;
+
+       r = ioport__register(0x0071, &cmos_ram_data_ioport_ops, 1, NULL);
+       if (r < 0) {
+               ioport__unregister(0x0071);
+               return r;
+       }
+
+       return r;
+}
+
+int rtc__exit(struct kvm *kvm)
+{
+       /* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */
+       ioport__unregister(0x0070);
+       ioport__unregister(0x0071);
+
+       return 0;
+}
\ No newline at end of file
diff --git a/tools/kvm/hw/serial.c b/tools/kvm/hw/serial.c
new file mode 100644 (file)
index 0000000..956307c
--- /dev/null
@@ -0,0 +1,446 @@
+#include "kvm/8250-serial.h"
+
+#include "kvm/read-write.h"
+#include "kvm/ioport.h"
+#include "kvm/mutex.h"
+#include "kvm/util.h"
+#include "kvm/term.h"
+#include "kvm/kvm.h"
+
+#include <linux/types.h>
+#include <linux/serial_reg.h>
+
+#include <pthread.h>
+
+/*
+ * This fakes a U6_16550A. The fifo len needs to be 64 as the kernel
+ * expects that for autodetection.
+ */
+#define FIFO_LEN               64
+#define FIFO_MASK              (FIFO_LEN - 1)
+
+#define UART_IIR_TYPE_BITS     0xc0
+
+struct serial8250_device {
+       pthread_mutex_t         mutex;
+       u8                      id;
+
+       u16                     iobase;
+       u8                      irq;
+       u8                      irq_state;
+       int                     txcnt;
+       int                     rxcnt;
+       int                     rxdone;
+       char                    txbuf[FIFO_LEN];
+       char                    rxbuf[FIFO_LEN];
+
+       u8                      dll;
+       u8                      dlm;
+       u8                      iir;
+       u8                      ier;
+       u8                      fcr;
+       u8                      lcr;
+       u8                      mcr;
+       u8                      lsr;
+       u8                      msr;
+       u8                      scr;
+};
+
+#define SERIAL_REGS_SETTING \
+       .iir                    = UART_IIR_NO_INT, \
+       .lsr                    = UART_LSR_TEMT | UART_LSR_THRE, \
+       .msr                    = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS, \
+       .mcr                    = UART_MCR_OUT2,
+
+static struct serial8250_device devices[] = {
+       /* ttyS0 */
+       [0]     = {
+               .mutex                  = PTHREAD_MUTEX_INITIALIZER,
+
+               .id                     = 0,
+               .iobase                 = 0x3f8,
+               .irq                    = 4,
+
+               SERIAL_REGS_SETTING
+       },
+       /* ttyS1 */
+       [1]     = {
+               .mutex                  = PTHREAD_MUTEX_INITIALIZER,
+
+               .id                     = 1,
+               .iobase                 = 0x2f8,
+               .irq                    = 3,
+
+               SERIAL_REGS_SETTING
+       },
+       /* ttyS2 */
+       [2]     = {
+               .mutex                  = PTHREAD_MUTEX_INITIALIZER,
+
+               .id                     = 2,
+               .iobase                 = 0x3e8,
+               .irq                    = 4,
+
+               SERIAL_REGS_SETTING
+       },
+       /* ttyS3 */
+       [3]     = {
+               .mutex                  = PTHREAD_MUTEX_INITIALIZER,
+
+               .id                     = 3,
+               .iobase                 = 0x2e8,
+               .irq                    = 3,
+
+               SERIAL_REGS_SETTING
+       },
+};
+
+static void serial8250_flush_tx(struct serial8250_device *dev)
+{
+       dev->lsr |= UART_LSR_TEMT | UART_LSR_THRE;
+
+       if (dev->txcnt) {
+               term_putc(CONSOLE_8250, dev->txbuf, dev->txcnt, dev->id);
+               dev->txcnt = 0;
+       }
+}
+
+static void serial8250_update_irq(struct kvm *kvm, struct serial8250_device *dev)
+{
+       u8 iir = 0;
+
+       /* Handle clear rx */
+       if (dev->lcr & UART_FCR_CLEAR_RCVR) {
+               dev->lcr &= ~UART_FCR_CLEAR_RCVR;
+               dev->rxcnt = dev->rxdone = 0;
+               dev->lsr &= ~UART_LSR_DR;
+       }
+
+       /* Handle clear tx */
+       if (dev->lcr & UART_FCR_CLEAR_XMIT) {
+               dev->lcr &= ~UART_FCR_CLEAR_XMIT;
+               dev->txcnt = 0;
+               dev->lsr |= UART_LSR_TEMT | UART_LSR_THRE;
+       }
+
+       /* Data ready and rcv interrupt enabled ? */
+       if ((dev->ier & UART_IER_RDI) && (dev->lsr & UART_LSR_DR))
+               iir |= UART_IIR_RDI;
+
+       /* Transmitter empty and interrupt enabled ? */
+       if ((dev->ier & UART_IER_THRI) && (dev->lsr & UART_LSR_TEMT))
+               iir |= UART_IIR_THRI;
+
+       /* Now update the irq line, if necessary */
+       if (!iir) {
+               dev->iir = UART_IIR_NO_INT;
+               if (dev->irq_state)
+                       kvm__irq_line(kvm, dev->irq, 0);
+       } else {
+               dev->iir = iir;
+               if (!dev->irq_state)
+                       kvm__irq_line(kvm, dev->irq, 1);
+       }
+       dev->irq_state = iir;
+
+       /*
+        * If the kernel disabled the tx interrupt, we know that there
+        * is nothing more to transmit, so we can reset our tx logic
+        * here.
+        */
+       if (!(dev->ier & UART_IER_THRI))
+               serial8250_flush_tx(dev);
+}
+
+#define SYSRQ_PENDING_NONE             0
+
+static int sysrq_pending;
+
+static void serial8250__sysrq(struct kvm *kvm, struct serial8250_device *dev)
+{
+       dev->lsr |= UART_LSR_DR | UART_LSR_BI;
+       dev->rxbuf[dev->rxcnt++] = sysrq_pending;
+       sysrq_pending   = SYSRQ_PENDING_NONE;
+}
+
+static void serial8250__receive(struct kvm *kvm, struct serial8250_device *dev,
+                               bool handle_sysrq)
+{
+       int c;
+
+       /*
+        * If the guest transmitted a full fifo, we clear the
+        * TEMT/THRE bits to let the kernel escape from the 8250
+        * interrupt handler. We come here only once a ms, so that
+        * should give the kernel the desired pause. That also flushes
+        * the tx fifo to the terminal.
+        */
+       serial8250_flush_tx(dev);
+
+       if (dev->mcr & UART_MCR_LOOP)
+               return;
+
+       if ((dev->lsr & UART_LSR_DR) || dev->rxcnt)
+               return;
+
+       if (handle_sysrq && sysrq_pending) {
+               serial8250__sysrq(kvm, dev);
+               return;
+       }
+
+       while (term_readable(CONSOLE_8250, dev->id) &&
+              dev->rxcnt < FIFO_LEN) {
+
+               c = term_getc(CONSOLE_8250, dev->id);
+
+               if (c < 0)
+                       break;
+               dev->rxbuf[dev->rxcnt++] = c;
+               dev->lsr |= UART_LSR_DR;
+       }
+}
+
+void serial8250__update_consoles(struct kvm *kvm)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(devices); i++) {
+               struct serial8250_device *dev = &devices[i];
+
+               mutex_lock(&dev->mutex);
+
+               /* Restrict sysrq injection to the first port */
+               serial8250__receive(kvm, dev, i == 0);
+
+               serial8250_update_irq(kvm, dev);
+
+               mutex_unlock(&dev->mutex);
+       }
+}
+
+void serial8250__inject_sysrq(struct kvm *kvm, char sysrq)
+{
+       sysrq_pending = sysrq;
+}
+
+static struct serial8250_device *find_device(u16 port)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(devices); i++) {
+               struct serial8250_device *dev = &devices[i];
+
+               if (dev->iobase == (port & ~0x7))
+                       return dev;
+       }
+       return NULL;
+}
+
+static bool serial8250_out(struct ioport *ioport, struct kvm *kvm, u16 port,
+                          void *data, int size)
+{
+       struct serial8250_device *dev;
+       u16 offset;
+       bool ret = true;
+       char *addr = data;
+
+       dev = find_device(port);
+       if (!dev)
+               return false;
+
+       mutex_lock(&dev->mutex);
+
+       offset = port - dev->iobase;
+
+       switch (offset) {
+       case UART_TX:
+               if (dev->lcr & UART_LCR_DLAB) {
+                       dev->dll = ioport__read8(data);
+                       break;
+               }
+
+               /* Loopback mode */
+               if (dev->mcr & UART_MCR_LOOP) {
+                       if (dev->rxcnt < FIFO_LEN) {
+                               dev->rxbuf[dev->rxcnt++] = *addr;
+                               dev->lsr |= UART_LSR_DR;
+                       }
+                       break;
+               }
+
+               if (dev->txcnt < FIFO_LEN) {
+                       dev->txbuf[dev->txcnt++] = *addr;
+                       dev->lsr &= ~UART_LSR_TEMT;
+                       if (dev->txcnt == FIFO_LEN / 2)
+                               dev->lsr &= ~UART_LSR_THRE;
+               } else {
+                       /* Should never happpen */
+                       dev->lsr &= ~(UART_LSR_TEMT | UART_LSR_THRE);
+               }
+               break;
+       case UART_IER:
+               if (!(dev->lcr & UART_LCR_DLAB))
+                       dev->ier = ioport__read8(data) & 0x0f;
+               else
+                       dev->dlm = ioport__read8(data);
+               break;
+       case UART_FCR:
+               dev->fcr = ioport__read8(data);
+               break;
+       case UART_LCR:
+               dev->lcr = ioport__read8(data);
+               break;
+       case UART_MCR:
+               dev->mcr = ioport__read8(data);
+               break;
+       case UART_LSR:
+               /* Factory test */
+               break;
+       case UART_MSR:
+               /* Not used */
+               break;
+       case UART_SCR:
+               dev->scr = ioport__read8(data);
+               break;
+       default:
+               ret = false;
+               break;
+       }
+
+       serial8250_update_irq(kvm, dev);
+
+       mutex_unlock(&dev->mutex);
+
+       return ret;
+}
+
+static void serial8250_rx(struct serial8250_device *dev, void *data)
+{
+       if (dev->rxdone == dev->rxcnt)
+               return;
+
+       /* Break issued ? */
+       if (dev->lsr & UART_LSR_BI) {
+               dev->lsr &= ~UART_LSR_BI;
+               ioport__write8(data, 0);
+               return;
+       }
+
+       ioport__write8(data, dev->rxbuf[dev->rxdone++]);
+       if (dev->rxcnt == dev->rxdone) {
+               dev->lsr &= ~UART_LSR_DR;
+               dev->rxcnt = dev->rxdone = 0;
+       }
+}
+
+static bool serial8250_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+       struct serial8250_device *dev;
+       u16 offset;
+       bool ret = true;
+
+       dev = find_device(port);
+       if (!dev)
+               return false;
+
+       mutex_lock(&dev->mutex);
+
+       offset = port - dev->iobase;
+
+       switch (offset) {
+       case UART_RX:
+               if (dev->lcr & UART_LCR_DLAB)
+                       ioport__write8(data, dev->dll);
+               else
+                       serial8250_rx(dev, data);
+               break;
+       case UART_IER:
+               if (dev->lcr & UART_LCR_DLAB)
+                       ioport__write8(data, dev->dlm);
+               else
+                       ioport__write8(data, dev->ier);
+               break;
+       case UART_IIR:
+               ioport__write8(data, dev->iir | UART_IIR_TYPE_BITS);
+               break;
+       case UART_LCR:
+               ioport__write8(data, dev->lcr);
+               break;
+       case UART_MCR:
+               ioport__write8(data, dev->mcr);
+               break;
+       case UART_LSR:
+               ioport__write8(data, dev->lsr);
+               break;
+       case UART_MSR:
+               ioport__write8(data, dev->msr);
+               break;
+       case UART_SCR:
+               ioport__write8(data, dev->scr);
+               break;
+       default:
+               ret = false;
+               break;
+       }
+
+       serial8250_update_irq(kvm, dev);
+
+       mutex_unlock(&dev->mutex);
+
+       return ret;
+}
+
+static struct ioport_operations serial8250_ops = {
+       .io_in          = serial8250_in,
+       .io_out         = serial8250_out,
+};
+
+static int serial8250__device_init(struct kvm *kvm, struct serial8250_device *dev)
+{
+       int r;
+
+       r = ioport__register(dev->iobase, &serial8250_ops, 8, NULL);
+       kvm__irq_line(kvm, dev->irq, 0);
+
+       return r;
+}
+
+int serial8250__init(struct kvm *kvm)
+{
+       unsigned int i, j;
+       int r = 0;
+
+       for (i = 0; i < ARRAY_SIZE(devices); i++) {
+               struct serial8250_device *dev = &devices[i];
+
+               r = serial8250__device_init(kvm, dev);
+               if (r < 0)
+                       goto cleanup;
+       }
+
+       return r;
+cleanup:
+       for (j = 0; j <= i; j++) {
+               struct serial8250_device *dev = &devices[j];
+
+               ioport__unregister(dev->iobase);
+       }
+
+       return r;
+}
+
+int serial8250__exit(struct kvm *kvm)
+{
+       unsigned int i;
+       int r;
+
+       for (i = 0; i < ARRAY_SIZE(devices); i++) {
+               struct serial8250_device *dev = &devices[i];
+
+               r = ioport__unregister(dev->iobase);
+               if (r < 0)
+                       return r;
+       }
+
+       return 0;
+}
diff --git a/tools/kvm/hw/vesa.c b/tools/kvm/hw/vesa.c
new file mode 100644 (file)
index 0000000..757f0a2
--- /dev/null
@@ -0,0 +1,85 @@
+#include "kvm/vesa.h"
+
+#include "kvm/virtio-pci-dev.h"
+#include "kvm/framebuffer.h"
+#include "kvm/kvm-cpu.h"
+#include "kvm/ioport.h"
+#include "kvm/util.h"
+#include "kvm/irq.h"
+#include "kvm/kvm.h"
+#include "kvm/pci.h"
+
+#include <linux/byteorder.h>
+#include <sys/mman.h>
+#include <linux/err.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <inttypes.h>
+#include <unistd.h>
+
+static bool vesa_pci_io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+       return true;
+}
+
+static bool vesa_pci_io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+       return true;
+}
+
+static struct ioport_operations vesa_io_ops = {
+       .io_in                  = vesa_pci_io_in,
+       .io_out                 = vesa_pci_io_out,
+};
+
+static struct pci_device_header vesa_pci_device = {
+       .vendor_id              = cpu_to_le16(PCI_VENDOR_ID_REDHAT_QUMRANET),
+       .device_id              = cpu_to_le16(PCI_DEVICE_ID_VESA),
+       .header_type            = PCI_HEADER_TYPE_NORMAL,
+       .revision_id            = 0,
+       .class[2]               = 0x03,
+       .subsys_vendor_id       = cpu_to_le16(PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET),
+       .subsys_id              = cpu_to_le16(PCI_SUBSYSTEM_ID_VESA),
+       .bar[1]                 = cpu_to_le32(VESA_MEM_ADDR | PCI_BASE_ADDRESS_SPACE_MEMORY),
+       .bar_size[1]            = VESA_MEM_SIZE,
+};
+
+static struct framebuffer vesafb;
+
+struct framebuffer *vesa__init(struct kvm *kvm)
+{
+       u16 vesa_base_addr;
+       u8 dev, line, pin;
+       char *mem;
+       int r;
+
+       r = irq__register_device(PCI_DEVICE_ID_VESA, &dev, &pin, &line);
+       if (r < 0)
+               return ERR_PTR(r);
+
+       r = ioport__register(IOPORT_EMPTY, &vesa_io_ops, IOPORT_SIZE, NULL);
+       if (r < 0)
+               return ERR_PTR(r);
+
+       vesa_pci_device.irq_pin         = pin;
+       vesa_pci_device.irq_line        = line;
+       vesa_base_addr                  = (u16)r;
+       vesa_pci_device.bar[0]          = cpu_to_le32(vesa_base_addr | PCI_BASE_ADDRESS_SPACE_IO);
+       pci__register(&vesa_pci_device, dev);
+
+       mem = mmap(NULL, VESA_MEM_SIZE, PROT_RW, MAP_ANON_NORESERVE, -1, 0);
+       if (mem == MAP_FAILED)
+               ERR_PTR(-errno);
+
+       kvm__register_mem(kvm, VESA_MEM_ADDR, VESA_MEM_SIZE, mem);
+
+       vesafb = (struct framebuffer) {
+               .width                  = VESA_WIDTH,
+               .height                 = VESA_HEIGHT,
+               .depth                  = VESA_BPP,
+               .mem                    = mem,
+               .mem_addr               = VESA_MEM_ADDR,
+               .mem_size               = VESA_MEM_SIZE,
+       };
+       return fb__register(&vesafb);
+}
diff --git a/tools/kvm/include/asm/hweight.h b/tools/kvm/include/asm/hweight.h
new file mode 100644 (file)
index 0000000..1a43977
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _KVM_ASM_HWEIGHT_H_
+#define _KVM_ASM_HWEIGHT_H_
+
+#include <linux/types.h>
+unsigned int hweight32(unsigned int w);
+unsigned long hweight64(__u64 w);
+
+#endif /* _KVM_ASM_HWEIGHT_H_ */
diff --git a/tools/kvm/include/bios/memcpy.h b/tools/kvm/include/bios/memcpy.h
new file mode 100644 (file)
index 0000000..e021044
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef KVM_BIOS_MEMCPY_H
+#define KVM_BIOS_MEMCPY_H
+
+#include <linux/types.h>
+#include <stddef.h>
+
+void memcpy16(u16 dst_seg, void *dst, u16 src_seg, const void *src, size_t len);
+
+#endif /* KVM_BIOS_MEMCPY_H */
diff --git a/tools/kvm/include/kvm/8250-serial.h b/tools/kvm/include/kvm/8250-serial.h
new file mode 100644 (file)
index 0000000..e954551
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef KVM__8250_SERIAL_H
+#define KVM__8250_SERIAL_H
+
+struct kvm;
+
+int serial8250__init(struct kvm *kvm);
+int serial8250__exit(struct kvm *kvm);
+void serial8250__update_consoles(struct kvm *kvm);
+void serial8250__inject_sysrq(struct kvm *kvm, char sysrq);
+
+#endif /* KVM__8250_SERIAL_H */
diff --git a/tools/kvm/include/kvm/apic.h b/tools/kvm/include/kvm/apic.h
new file mode 100644 (file)
index 0000000..2129997
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef KVM_APIC_H_
+#define KVM_APIC_H_
+
+#include <asm/apicdef.h>
+
+/*
+ * APIC, IOAPIC stuff
+ */
+#define APIC_BASE_ADDR_STEP    0x00400000
+#define IOAPIC_BASE_ADDR_STEP  0x00100000
+
+#define APIC_ADDR(apic)                (APIC_DEFAULT_PHYS_BASE + apic * APIC_BASE_ADDR_STEP)
+#define IOAPIC_ADDR(ioapic)    (IO_APIC_DEFAULT_PHYS_BASE + ioapic * IOAPIC_BASE_ADDR_STEP)
+
+#define KVM_APIC_VERSION       0x14 /* xAPIC */
+
+#endif /* KVM_APIC_H_ */
diff --git a/tools/kvm/include/kvm/brlock.h b/tools/kvm/include/kvm/brlock.h
new file mode 100644 (file)
index 0000000..bd1d882
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef KVM__BRLOCK_H
+#define KVM__BRLOCK_H
+
+#include "kvm/kvm.h"
+#include "kvm/barrier.h"
+
+/*
+ * brlock is a lock which is very cheap for reads, but very expensive
+ * for writes.
+ * This lock will be used when updates are very rare and reads are common.
+ * This lock is currently implemented by stopping the guest while
+ * performing the updates. We assume that the only threads whichread from
+ * the locked data are VCPU threads, and the only writer isn't a VCPU thread.
+ */
+
+#ifndef barrier
+#define barrier()              __asm__ __volatile__("": : :"memory")
+#endif
+
+#ifdef KVM_BRLOCK_DEBUG
+
+#include "kvm/rwsem.h"
+
+DECLARE_RWSEM(brlock_sem);
+
+#define br_read_lock()         down_read(&brlock_sem);
+#define br_read_unlock()       up_read(&brlock_sem);
+
+#define br_write_lock()                down_write(&brlock_sem);
+#define br_write_unlock()      up_write(&brlock_sem);
+
+#else
+
+#define br_read_lock()         barrier()
+#define br_read_unlock()       barrier()
+
+#define br_write_lock()                kvm__pause()
+#define br_write_unlock()      kvm__continue()
+#endif
+
+#endif
diff --git a/tools/kvm/include/kvm/builtin-balloon.h b/tools/kvm/include/kvm/builtin-balloon.h
new file mode 100644 (file)
index 0000000..77ee656
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef KVM__BALLOON_H
+#define KVM__BALLOON_H
+
+#include <kvm/util.h>
+
+int kvm_cmd_balloon(int argc, const char **argv, const char *prefix);
+void kvm_balloon_help(void) NORETURN;
+
+#endif
diff --git a/tools/kvm/include/kvm/builtin-debug.h b/tools/kvm/include/kvm/builtin-debug.h
new file mode 100644 (file)
index 0000000..efa0268
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef KVM__DEBUG_H
+#define KVM__DEBUG_H
+
+#include <kvm/util.h>
+#include <linux/types.h>
+
+#define KVM_DEBUG_CMD_TYPE_DUMP        (1 << 0)
+#define KVM_DEBUG_CMD_TYPE_NMI (1 << 1)
+#define KVM_DEBUG_CMD_TYPE_SYSRQ (1 << 2)
+
+struct debug_cmd_params {
+       u32 dbg_type;
+       u32 cpu;
+       char sysrq;
+};
+
+int kvm_cmd_debug(int argc, const char **argv, const char *prefix);
+void kvm_debug_help(void) NORETURN;
+
+#endif
diff --git a/tools/kvm/include/kvm/builtin-help.h b/tools/kvm/include/kvm/builtin-help.h
new file mode 100644 (file)
index 0000000..2946743
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __KVM_HELP_H__
+#define __KVM_HELP_H__
+
+int kvm_cmd_help(int argc, const char **argv, const char *prefix);
+
+#endif
diff --git a/tools/kvm/include/kvm/builtin-list.h b/tools/kvm/include/kvm/builtin-list.h
new file mode 100644 (file)
index 0000000..47029ca
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef KVM__LIST_H
+#define KVM__LIST_H
+
+#include <kvm/util.h>
+
+int kvm_cmd_list(int argc, const char **argv, const char *prefix);
+void kvm_list_help(void) NORETURN;
+int get_vmstate(int sock);
+
+#endif
diff --git a/tools/kvm/include/kvm/builtin-pause.h b/tools/kvm/include/kvm/builtin-pause.h
new file mode 100644 (file)
index 0000000..84aaee3
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef KVM__PAUSE_H
+#define KVM__PAUSE_H
+
+#include <kvm/util.h>
+
+int kvm_cmd_pause(int argc, const char **argv, const char *prefix);
+void kvm_pause_help(void) NORETURN;
+
+#endif
diff --git a/tools/kvm/include/kvm/builtin-resume.h b/tools/kvm/include/kvm/builtin-resume.h
new file mode 100644 (file)
index 0000000..7de999b
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef KVM__RESUME_H
+#define KVM__RESUME_H
+
+#include <kvm/util.h>
+
+int kvm_cmd_resume(int argc, const char **argv, const char *prefix);
+void kvm_resume_help(void) NORETURN;
+
+#endif
diff --git a/tools/kvm/include/kvm/builtin-run.h b/tools/kvm/include/kvm/builtin-run.h
new file mode 100644 (file)
index 0000000..91521a5
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef __KVM_RUN_H__
+#define __KVM_RUN_H__
+
+#include <kvm/util.h>
+
+int kvm_cmd_run(int argc, const char **argv, const char *prefix);
+void kvm_run_help(void) NORETURN;
+
+void kvm_run_set_wrapper_sandbox(void);
+
+#endif
diff --git a/tools/kvm/include/kvm/builtin-sandbox.h b/tools/kvm/include/kvm/builtin-sandbox.h
new file mode 100644 (file)
index 0000000..98cd6be
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef KVM__SANDBOX_H
+#define KVM__SANDBOX_H
+
+int kvm_cmd_sandbox(int argc, const char **argv, const char *prefix);
+
+#endif
diff --git a/tools/kvm/include/kvm/builtin-setup.h b/tools/kvm/include/kvm/builtin-setup.h
new file mode 100644 (file)
index 0000000..4a8d7ee
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef KVM__SETUP_H
+#define KVM__SETUP_H
+
+#include <kvm/util.h>
+
+int kvm_cmd_setup(int argc, const char **argv, const char *prefix);
+void kvm_setup_help(void) NORETURN;
+int kvm_setup_create_new(const char *guestfs_name);
+void kvm_setup_resolv(const char *guestfs_name);
+
+#endif
diff --git a/tools/kvm/include/kvm/builtin-stat.h b/tools/kvm/include/kvm/builtin-stat.h
new file mode 100644 (file)
index 0000000..4fecb37
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef KVM__STAT_H
+#define KVM__STAT_H
+
+#include <kvm/util.h>
+
+int kvm_cmd_stat(int argc, const char **argv, const char *prefix);
+void kvm_stat_help(void) NORETURN;
+
+#endif
diff --git a/tools/kvm/include/kvm/builtin-stop.h b/tools/kvm/include/kvm/builtin-stop.h
new file mode 100644 (file)
index 0000000..b26b275
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef KVM__STOP_H
+#define KVM__STOP_H
+
+#include <kvm/util.h>
+
+int kvm_cmd_stop(int argc, const char **argv, const char *prefix);
+void kvm_stop_help(void) NORETURN;
+
+#endif
diff --git a/tools/kvm/include/kvm/builtin-version.h b/tools/kvm/include/kvm/builtin-version.h
new file mode 100644 (file)
index 0000000..83cac4d
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef KVM__VERSION_H
+#define KVM__VERSION_H
+
+int kvm_cmd_version(int argc, const char **argv, const char *prefix);
+
+#endif
diff --git a/tools/kvm/include/kvm/compiler.h b/tools/kvm/include/kvm/compiler.h
new file mode 100644 (file)
index 0000000..2013a83
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef KVM_COMPILER_H_
+#define KVM_COMPILER_H_
+
+#ifndef __compiletime_error
+# define __compiletime_error(message)
+#endif
+
+#define notrace __attribute__((no_instrument_function))
+
+#endif /* KVM_COMPILER_H_ */
diff --git a/tools/kvm/include/kvm/disk-image.h b/tools/kvm/include/kvm/disk-image.h
new file mode 100644 (file)
index 0000000..7ae17f8
--- /dev/null
@@ -0,0 +1,87 @@
+#ifndef KVM__DISK_IMAGE_H
+#define KVM__DISK_IMAGE_H
+
+#include "kvm/read-write.h"
+#include "kvm/util.h"
+
+#include <linux/types.h>
+#include <linux/fs.h>  /* for BLKGETSIZE64 */
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <stdbool.h>
+#include <sys/uio.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#define SECTOR_SHIFT           9
+#define SECTOR_SIZE            (1UL << SECTOR_SHIFT)
+
+enum {
+       DISK_IMAGE_REGULAR,
+       DISK_IMAGE_MMAP,
+};
+
+#define MAX_DISK_IMAGES         4
+
+struct disk_image;
+
+struct disk_image_operations {
+       ssize_t (*read)(struct disk_image *disk, u64 sector, const struct iovec *iov,
+                       int iovcount, void *param);
+       ssize_t (*write)(struct disk_image *disk, u64 sector, const struct iovec *iov,
+                       int iovcount, void *param);
+       int (*flush)(struct disk_image *disk);
+       int (*close)(struct disk_image *disk);
+};
+
+struct disk_image_params {
+       const char *filename;
+       bool readonly;
+       bool direct;
+};
+
+struct disk_image {
+       int                             fd;
+       u64                             size;
+       struct disk_image_operations    *ops;
+       void                            *priv;
+       void                            *disk_req_cb_param;
+       void                            (*disk_req_cb)(void *param, long len);
+       bool                            async;
+       int                             evt;
+#ifdef CONFIG_HAS_AIO
+       io_context_t                    ctx;
+#endif
+};
+
+struct disk_image *disk_image__open(const char *filename, bool readonly, bool direct);
+struct disk_image **disk_image__open_all(struct disk_image_params *params, int count);
+struct disk_image *disk_image__new(int fd, u64 size, struct disk_image_operations *ops, int mmap);
+int disk_image__close(struct disk_image *disk);
+int disk_image__close_all(struct disk_image **disks, int count);
+int disk_image__flush(struct disk_image *disk);
+ssize_t disk_image__read(struct disk_image *disk, u64 sector, const struct iovec *iov,
+                               int iovcount, void *param);
+ssize_t disk_image__write(struct disk_image *disk, u64 sector, const struct iovec *iov,
+                               int iovcount, void *param);
+ssize_t disk_image__get_serial(struct disk_image *disk, void *buffer, ssize_t *len);
+
+struct disk_image *raw_image__probe(int fd, struct stat *st, bool readonly);
+struct disk_image *blkdev__probe(const char *filename, int flags, struct stat *st);
+
+ssize_t raw_image__read(struct disk_image *disk, u64 sector,
+                               const struct iovec *iov, int iovcount, void *param);
+ssize_t raw_image__write(struct disk_image *disk, u64 sector,
+                               const struct iovec *iov, int iovcount, void *param);
+ssize_t raw_image__read_mmap(struct disk_image *disk, u64 sector,
+                               const struct iovec *iov, int iovcount, void *param);
+ssize_t raw_image__write_mmap(struct disk_image *disk, u64 sector,
+                               const struct iovec *iov, int iovcount, void *param);
+int raw_image__close(struct disk_image *disk);
+void disk_image__set_callback(struct disk_image *disk, void (*disk_req_cb)(void *param, long len));
+#endif /* KVM__DISK_IMAGE_H */
diff --git a/tools/kvm/include/kvm/e820.h b/tools/kvm/include/kvm/e820.h
new file mode 100644 (file)
index 0000000..15f62cc
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef KVM_E820_H
+#define KVM_E820_H
+
+#include <linux/types.h>
+#include <kvm/bios.h>
+
+#define SMAP    0x534d4150      /* ASCII "SMAP" */
+
+struct biosregs;
+
+extern bioscall void e820_query_map(struct biosregs *regs);
+
+#endif /* KVM_E820_H */
diff --git a/tools/kvm/include/kvm/framebuffer.h b/tools/kvm/include/kvm/framebuffer.h
new file mode 100644 (file)
index 0000000..dc5022c
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef KVM__FRAMEBUFFER_H
+#define KVM__FRAMEBUFFER_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+
+struct framebuffer;
+
+struct fb_target_operations {
+       int (*start)(struct framebuffer *fb);
+       int (*stop)(struct framebuffer *fb);
+};
+
+#define FB_MAX_TARGETS                 2
+
+struct framebuffer {
+       struct list_head                node;
+
+       u32                             width;
+       u32                             height;
+       u8                              depth;
+       char                            *mem;
+       u64                             mem_addr;
+       u64                             mem_size;
+
+       unsigned long                   nr_targets;
+       struct fb_target_operations     *targets[FB_MAX_TARGETS];
+};
+
+struct framebuffer *fb__register(struct framebuffer *fb);
+int fb__attach(struct framebuffer *fb, struct fb_target_operations *ops);
+int fb__start(void);
+void fb__stop(void);
+
+#endif /* KVM__FRAMEBUFFER_H */
diff --git a/tools/kvm/include/kvm/guest_compat.h b/tools/kvm/include/kvm/guest_compat.h
new file mode 100644 (file)
index 0000000..ae7abbd
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef KVM__GUEST_COMPAT_H
+#define KVM__GUEST_COMPAT_H
+
+int compat__print_all_messages(void);
+int compat__remove_message(int id);
+int compat__add_message(const char *title, const char *description);
+
+
+#endif
\ No newline at end of file
diff --git a/tools/kvm/include/kvm/i8042.h b/tools/kvm/include/kvm/i8042.h
new file mode 100644 (file)
index 0000000..13f18e2
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef KVM__PCKBD_H
+#define KVM__PCKBD_H
+
+#include <linux/types.h>
+
+struct kvm;
+
+void mouse_queue(u8 c);
+void kbd_queue(u8 c);
+void kbd__init(struct kvm *kvm);
+
+#endif
diff --git a/tools/kvm/include/kvm/ioeventfd.h b/tools/kvm/include/kvm/ioeventfd.h
new file mode 100644 (file)
index 0000000..d71fa40
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef KVM__IOEVENTFD_H
+#define KVM__IOEVENTFD_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <sys/eventfd.h>
+#include "kvm/util.h"
+
+struct kvm;
+
+struct ioevent {
+       u64                     io_addr;
+       u8                      io_len;
+       void                    (*fn)(struct kvm *kvm, void *ptr);
+       struct kvm              *fn_kvm;
+       void                    *fn_ptr;
+       int                     fd;
+       u64                     datamatch;
+
+       struct list_head        list;
+};
+
+int ioeventfd__init(struct kvm *kvm);
+int ioeventfd__exit(struct kvm *kvm);
+int ioeventfd__add_event(struct ioevent *ioevent, bool is_pio, bool poll_in_userspace);
+int ioeventfd__del_event(u64 addr, u64 datamatch);
+
+#endif
diff --git a/tools/kvm/include/kvm/ioport.h b/tools/kvm/include/kvm/ioport.h
new file mode 100644 (file)
index 0000000..ced8cf5
--- /dev/null
@@ -0,0 +1,69 @@
+#ifndef KVM__IOPORT_H
+#define KVM__IOPORT_H
+
+#include "kvm/rbtree-interval.h"
+
+#include <stdbool.h>
+#include <limits.h>
+#include <asm/types.h>
+#include <linux/types.h>
+#include <linux/byteorder.h>
+
+/* some ports we reserve for own use */
+#define IOPORT_DBG                     0xe0
+#define IOPORT_START                   0x6200
+#define IOPORT_SIZE                    0x400
+
+#define IOPORT_EMPTY                   USHRT_MAX
+
+struct kvm;
+
+struct ioport {
+       struct rb_int_node              node;
+       struct ioport_operations        *ops;
+       void                            *priv;
+};
+
+struct ioport_operations {
+       bool (*io_in)(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size);
+       bool (*io_out)(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size);
+};
+
+void ioport__setup_arch(void);
+
+int ioport__register(u16 port, struct ioport_operations *ops, int count, void *param);
+int ioport__unregister(u16 port);
+int ioport__init(struct kvm *kvm);
+int ioport__exit(struct kvm *kvm);
+
+static inline u8 ioport__read8(u8 *data)
+{
+       return *data;
+}
+/* On BE platforms, PCI I/O is byteswapped, i.e. LE, so swap back. */
+static inline u16 ioport__read16(u16 *data)
+{
+       return le16_to_cpu(*data);
+}
+
+static inline u32 ioport__read32(u32 *data)
+{
+       return le32_to_cpu(*data);
+}
+
+static inline void ioport__write8(u8 *data, u8 value)
+{
+       *data            = value;
+}
+
+static inline void ioport__write16(u16 *data, u16 value)
+{
+       *data            = cpu_to_le16(value);
+}
+
+static inline void ioport__write32(u32 *data, u32 value)
+{
+       *data            = cpu_to_le32(value);
+}
+
+#endif /* KVM__IOPORT_H */
diff --git a/tools/kvm/include/kvm/irq.h b/tools/kvm/include/kvm/irq.h
new file mode 100644 (file)
index 0000000..43fecaf
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef KVM__IRQ_H
+#define KVM__IRQ_H
+
+#include <linux/types.h>
+#include <linux/rbtree.h>
+#include <linux/list.h>
+#include <linux/kvm.h>
+
+#include "kvm/msi.h"
+
+struct kvm;
+
+struct irq_line {
+       u8                      line;
+       struct list_head        node;
+};
+
+struct pci_dev {
+       struct rb_node          node;
+       u32                     id;
+       u8                      pin;
+       struct list_head        lines;
+};
+
+int irq__register_device(u32 dev, u8 *num, u8 *pin, u8 *line);
+
+struct rb_node *irq__get_pci_tree(void);
+
+int irq__init(struct kvm *kvm);
+int irq__exit(struct kvm *kvm);
+int irq__add_msix_route(struct kvm *kvm, struct msi_msg *msg);
+
+#endif
diff --git a/tools/kvm/include/kvm/kvm-cmd.h b/tools/kvm/include/kvm/kvm-cmd.h
new file mode 100644 (file)
index 0000000..0a73bce
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef __KVM_CMD_H__
+#define __KVM_CMD_H__
+
+struct cmd_struct {
+       const char *cmd;
+       int (*fn)(int, const char **, const char *);
+       void (*help)(void);
+       int option;
+};
+
+extern struct cmd_struct kvm_commands[];
+struct cmd_struct *kvm_get_command(struct cmd_struct *command,
+                const char *cmd);
+
+int handle_command(struct cmd_struct *command, int argc, const char **argv);
+
+#endif
diff --git a/tools/kvm/include/kvm/kvm-cpu.h b/tools/kvm/include/kvm/kvm-cpu.h
new file mode 100644 (file)
index 0000000..d4448f6
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef KVM__KVM_CPU_H
+#define KVM__KVM_CPU_H
+
+#include "kvm/kvm-cpu-arch.h"
+#include <stdbool.h>
+
+struct kvm_cpu *kvm_cpu__init(struct kvm *kvm, unsigned long cpu_id);
+void kvm_cpu__delete(struct kvm_cpu *vcpu);
+void kvm_cpu__reset_vcpu(struct kvm_cpu *vcpu);
+void kvm_cpu__setup_cpuid(struct kvm_cpu *vcpu);
+void kvm_cpu__enable_singlestep(struct kvm_cpu *vcpu);
+void kvm_cpu__run(struct kvm_cpu *vcpu);
+void kvm_cpu__reboot(void);
+int kvm_cpu__start(struct kvm_cpu *cpu);
+bool kvm_cpu__handle_exit(struct kvm_cpu *vcpu);
+
+int kvm_cpu__get_debug_fd(void);
+void kvm_cpu__set_debug_fd(int fd);
+void kvm_cpu__show_code(struct kvm_cpu *vcpu);
+void kvm_cpu__show_registers(struct kvm_cpu *vcpu);
+void kvm_cpu__show_page_tables(struct kvm_cpu *vcpu);
+void kvm_cpu__arch_nmi(struct kvm_cpu *cpu);
+
+#endif /* KVM__KVM_CPU_H */
diff --git a/tools/kvm/include/kvm/kvm-ipc.h b/tools/kvm/include/kvm/kvm-ipc.h
new file mode 100644 (file)
index 0000000..aefffa4
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef KVM__IPC_H_
+#define KVM__IPC_H_
+
+#include <linux/types.h>
+
+enum {
+       KVM_IPC_BALLOON = 1,
+       KVM_IPC_DEBUG   = 2,
+       KVM_IPC_STAT    = 3,
+       KVM_IPC_PAUSE   = 4,
+       KVM_IPC_RESUME  = 5,
+       KVM_IPC_STOP    = 6,
+       KVM_IPC_PID     = 7,
+       KVM_IPC_VMSTATE = 8,
+};
+
+int kvm_ipc__register_handler(u32 type, void (*cb)(int fd, u32 type, u32 len, u8 *msg));
+int kvm_ipc__start(int sock);
+int kvm_ipc__stop(void);
+
+int kvm_ipc__send(int fd, u32 type);
+int kvm_ipc__send_msg(int fd, u32 type, u32 len, u8 *msg);
+
+#endif
diff --git a/tools/kvm/include/kvm/kvm.h b/tools/kvm/include/kvm/kvm.h
new file mode 100644 (file)
index 0000000..22a1b0e
--- /dev/null
@@ -0,0 +1,93 @@
+#ifndef KVM__KVM_H
+#define KVM__KVM_H
+
+#include "kvm/kvm-arch.h"
+
+#include <stdbool.h>
+#include <linux/types.h>
+#include <time.h>
+#include <signal.h>
+
+#define SIGKVMEXIT             (SIGRTMIN + 0)
+#define SIGKVMPAUSE            (SIGRTMIN + 1)
+
+#define KVM_PID_FILE_PATH      "/.lkvm/"
+#define HOME_DIR               getenv("HOME")
+#define KVM_BINARY_NAME                "lkvm"
+
+#define PAGE_SIZE (sysconf(_SC_PAGE_SIZE))
+
+#define DEFINE_KVM_EXT(ext)            \
+       .name = #ext,                   \
+       .code = ext
+
+enum {
+       KVM_VMSTATE_RUNNING,
+       KVM_VMSTATE_PAUSED,
+};
+
+struct kvm_ext {
+       const char *name;
+       int code;
+};
+
+void kvm__set_dir(const char *fmt, ...);
+const char *kvm__get_dir(void);
+
+struct kvm *kvm__init(const char *kvm_dev, const char *hugetlbfs_path, u64 ram_size, const char *name);
+int kvm__recommended_cpus(struct kvm *kvm);
+int kvm__max_cpus(struct kvm *kvm);
+void kvm__init_ram(struct kvm *kvm);
+int kvm__exit(struct kvm *kvm);
+bool kvm__load_firmware(struct kvm *kvm, const char *firmware_filename);
+bool kvm__load_kernel(struct kvm *kvm, const char *kernel_filename,
+                       const char *initrd_filename, const char *kernel_cmdline, u16 vidmode);
+void kvm__start_timer(struct kvm *kvm);
+void kvm__stop_timer(struct kvm *kvm);
+void kvm__irq_line(struct kvm *kvm, int irq, int level);
+void kvm__irq_trigger(struct kvm *kvm, int irq);
+bool kvm__emulate_io(struct kvm *kvm, u16 port, void *data, int direction, int size, u32 count);
+bool kvm__emulate_mmio(struct kvm *kvm, u64 phys_addr, u8 *data, u32 len, u8 is_write);
+int kvm__register_mem(struct kvm *kvm, u64 guest_phys, u64 size, void *userspace_addr);
+int kvm__register_mmio(struct kvm *kvm, u64 phys_addr, u64 phys_addr_len, bool coalesce,
+                       void (*mmio_fn)(u64 addr, u8 *data, u32 len, u8 is_write, void *ptr),
+                       void *ptr);
+bool kvm__deregister_mmio(struct kvm *kvm, u64 phys_addr);
+void kvm__pause(void);
+void kvm__continue(void);
+void kvm__notify_paused(void);
+int kvm__get_sock_by_instance(const char *name);
+int kvm__enumerate_instances(int (*callback)(const char *name, int pid));
+void kvm__remove_socket(const char *name);
+
+void kvm__arch_set_cmdline(char *cmdline, bool video);
+void kvm__arch_init(struct kvm *kvm, const char *hugetlbfs_path, u64 ram_size);
+void kvm__arch_delete_ram(struct kvm *kvm);
+int kvm__arch_setup_firmware(struct kvm *kvm);
+int kvm__arch_free_firmware(struct kvm *kvm);
+bool kvm__arch_cpu_supports_vm(void);
+void kvm__arch_periodic_poll(struct kvm *kvm);
+
+int load_flat_binary(struct kvm *kvm, int fd_kernel, int fd_initrd, const char *kernel_cmdline);
+bool load_bzimage(struct kvm *kvm, int fd_kernel, int fd_initrd, const char *kernel_cmdline, u16 vidmode);
+
+/*
+ * Debugging
+ */
+void kvm__dump_mem(struct kvm *kvm, unsigned long addr, unsigned long size);
+
+extern const char *kvm_exit_reasons[];
+
+static inline bool host_ptr_in_ram(struct kvm *kvm, void *p)
+{
+       return kvm->ram_start <= p && p < (kvm->ram_start + kvm->ram_size);
+}
+
+static inline void *guest_flat_to_host(struct kvm *kvm, unsigned long offset)
+{
+       return kvm->ram_start + offset;
+}
+
+bool kvm__supports_extension(struct kvm *kvm, unsigned int extension);
+
+#endif /* KVM__KVM_H */
diff --git a/tools/kvm/include/kvm/msi.h b/tools/kvm/include/kvm/msi.h
new file mode 100644 (file)
index 0000000..885eb5b
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef LKVM_MSI_H
+#define LKVM_MSI_H
+
+struct msi_msg {
+       u32     address_lo;     /* low 32 bits of msi message address */
+       u32     address_hi;     /* high 32 bits of msi message address */
+       u32     data;           /* 16 bits of msi message data */
+};
+
+#endif /* LKVM_MSI_H */
diff --git a/tools/kvm/include/kvm/mutex.h b/tools/kvm/include/kvm/mutex.h
new file mode 100644 (file)
index 0000000..3286cea
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef KVM__MUTEX_H
+#define KVM__MUTEX_H
+
+#include <pthread.h>
+
+#include "kvm/util.h"
+
+/*
+ * Kernel-alike mutex API - to make it easier for kernel developers
+ * to write user-space code! :-)
+ */
+
+#define DEFINE_MUTEX(mutex) pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER
+
+static inline void mutex_init(pthread_mutex_t *mutex)
+{
+       if (pthread_mutex_init(mutex, NULL) != 0)
+               die("unexpected pthread_mutex_init() failure!");
+}
+
+static inline void mutex_lock(pthread_mutex_t *mutex)
+{
+       if (pthread_mutex_lock(mutex) != 0)
+               die("unexpected pthread_mutex_lock() failure!");
+}
+
+static inline void mutex_unlock(pthread_mutex_t *mutex)
+{
+       if (pthread_mutex_unlock(mutex) != 0)
+               die("unexpected pthread_mutex_unlock() failure!");
+}
+
+#endif /* KVM__MUTEX_H */
diff --git a/tools/kvm/include/kvm/parse-options.h b/tools/kvm/include/kvm/parse-options.h
new file mode 100644 (file)
index 0000000..7886ff7
--- /dev/null
@@ -0,0 +1,214 @@
+#ifndef __PARSE_OPTIONS_H__
+#define __PARSE_OPTIONS_H__
+
+#include <inttypes.h>
+#include <kvm/util.h>
+
+enum parse_opt_type {
+       /* special types */
+       OPTION_END,
+       OPTION_ARGUMENT,
+       OPTION_GROUP,
+       /* options with no arguments */
+       OPTION_BIT,
+       OPTION_BOOLEAN,
+       OPTION_INCR,
+       OPTION_SET_UINT,
+       OPTION_SET_PTR,
+       /* options with arguments (usually) */
+       OPTION_STRING,
+       OPTION_INTEGER,
+       OPTION_LONG,
+       OPTION_CALLBACK,
+       OPTION_U64,
+       OPTION_UINTEGER,
+};
+
+enum parse_opt_flags {
+       PARSE_OPT_KEEP_DASHDASH = 1,
+       PARSE_OPT_STOP_AT_NON_OPTION = 2,
+       PARSE_OPT_KEEP_ARGV0 = 4,
+       PARSE_OPT_KEEP_UNKNOWN = 8,
+       PARSE_OPT_NO_INTERNAL_HELP = 16,
+};
+
+enum parse_opt_option_flags {
+       PARSE_OPT_OPTARG  = 1,
+       PARSE_OPT_NOARG   = 2,
+       PARSE_OPT_NONEG   = 4,
+       PARSE_OPT_HIDDEN  = 8,
+       PARSE_OPT_LASTARG_DEFAULT = 16,
+};
+
+struct option;
+typedef int parse_opt_cb(const struct option *, const char *arg, int unset);
+/*
+ * `type`::
+ *   holds the type of the option, you must have an OPTION_END last in your
+ *   array.
+ *
+ * `short_name`::
+ *   the character to use as a short option name, '\0' if none.
+ *
+ * `long_name`::
+ *   the long option name, without the leading dashes, NULL if none.
+ *
+ * `value`::
+ *   stores pointers to the values to be filled.
+ *
+ * `argh`::
+ *   token to explain the kind of argument this option wants. Keep it
+ *   homogenous across the repository.
+ *
+ * `help`::
+ *   the short help associated to what the option does.
+ *   Must never be NULL (except for OPTION_END).
+ *   OPTION_GROUP uses this pointer to store the group header.
+ *
+ * `flags`::
+ *   mask of parse_opt_option_flags.
+ *   PARSE_OPT_OPTARG: says that the argument is optionnal (not for BOOLEANs)
+ *   PARSE_OPT_NOARG: says that this option takes no argument, for CALLBACKs
+ *   PARSE_OPT_NONEG: says that this option cannot be negated
+ *   PARSE_OPT_HIDDEN this option is skipped in the default usage, showed in
+ *                    the long one.
+ *
+ * `callback`::
+ *   pointer to the callback to use for OPTION_CALLBACK.
+ *
+ * `defval`::
+ *   default value to fill (*->value) with for PARSE_OPT_OPTARG.
+ *   OPTION_{BIT,SET_UINT,SET_PTR} store the {mask,integer,pointer} to put in
+ *   the value when met.
+ *   CALLBACKS can use it like they want.
+ */
+struct option {
+enum parse_opt_type type;
+int short_name;
+const char *long_name;
+void *value;
+const char *argh;
+const char *help;
+
+int flags;
+parse_opt_cb *callback;
+intptr_t defval;
+};
+
+#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
+#define check_vtype(v, type) \
+       (BUILD_BUG_ON_ZERO(!__builtin_types_compatible_p(typeof(v), type)) + v)
+
+#define OPT_INTEGER(s, l, v, h)             \
+{                                           \
+       .type = OPTION_INTEGER,             \
+       .short_name = (s),                  \
+       .long_name = (l),                   \
+       .value = check_vtype(v, int *),     \
+       .help = (h)                         \
+}
+
+#define OPT_U64(s, l, v, h)                 \
+{                                           \
+       .type = OPTION_U64,                 \
+       .short_name = (s),                  \
+       .long_name = (l),                   \
+       .value = check_vtype(v, u64 *),     \
+       .help = (h)                         \
+}
+
+#define OPT_STRING(s, l, v, a, h)           \
+{                                           \
+       .type = OPTION_STRING,              \
+       .short_name = (s),                  \
+       .long_name = (l),                   \
+       .value = check_vtype(v, const char **), (a), \
+       .help = (h)                         \
+}
+
+#define OPT_BOOLEAN(s, l, v, h)             \
+{                                           \
+       .type = OPTION_BOOLEAN,             \
+       .short_name = (s),                  \
+       .long_name = (l),                   \
+       .value = check_vtype(v, bool *),    \
+       .help = (h)                         \
+}
+
+#define OPT_INCR(s, l, v, h)                \
+{                                           \
+       .type = OPTION_INCR,                \
+       .short_name = (s),                  \
+       .long_name = (l),                   \
+       .value = check_vtype(v, int *),     \
+       .help = (h)                         \
+}
+
+#define OPT_GROUP(h)                        \
+{                                           \
+       .type = OPTION_GROUP,               \
+       .help = (h)                         \
+}
+
+#define OPT_CALLBACK(s, l, v, a, h, f)      \
+{                                          \
+       .type = OPTION_CALLBACK,            \
+       .short_name = (s),                  \
+       .long_name = (l),                   \
+       .value = (v),                       \
+       (a),                                \
+       .help = (h),                        \
+       .callback = (f)                     \
+}
+
+#define OPT_CALLBACK_NOOPT(s, l, v, a, h, f) \
+{                                          \
+       .type = OPTION_CALLBACK,            \
+       .short_name = (s),                  \
+       .long_name = (l),                   \
+       .value = (v),                       \
+       (a),                                \
+       .help = (h),                        \
+       .callback = (f),                    \
+       .flags = PARSE_OPT_NOARG            \
+}
+
+#define OPT_CALLBACK_DEFAULT(s, l, v, a, h, f, d) \
+{                                          \
+       .type = OPTION_CALLBACK,            \
+       .short_name = (s),                  \
+       .long_name = (l),                   \
+       .value = (v), (a),                  \
+       .help = (h),                        \
+       .callback = (f),                    \
+       .defval = (intptr_t)d,              \
+       .flags = PARSE_OPT_LASTARG_DEFAULT  \
+}
+
+#define OPT_END() { .type = OPTION_END }
+
+enum {
+       PARSE_OPT_HELP = -1,
+       PARSE_OPT_DONE,
+       PARSE_OPT_UNKNOWN,
+};
+
+/*
+ * It's okay for the caller to consume argv/argc in the usual way.
+ * Other fields of that structure are private to parse-options and should not
+ * be modified in any way.
+ **/
+struct parse_opt_ctx_t {
+       const char **argv;
+       const char **out;
+       int argc, cpidx;
+       const char *opt;
+       int flags;
+};
+
+/* global functions */
+void usage_with_options(const char * const *usagestr,
+               const struct option *opts) NORETURN;
+int parse_options(int argc, const char **argv, const struct option *options,
+               const char * const usagestr[], int flags);
+#endif
diff --git a/tools/kvm/include/kvm/pci-shmem.h b/tools/kvm/include/kvm/pci-shmem.h
new file mode 100644 (file)
index 0000000..599ab37
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef KVM__PCI_SHMEM_H
+#define KVM__PCI_SHMEM_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+
+#define SHMEM_DEFAULT_SIZE (16 << MB_SHIFT)
+#define SHMEM_DEFAULT_ADDR (0xc8000000)
+#define SHMEM_DEFAULT_HANDLE "/kvm_shmem"
+
+struct kvm;
+struct shmem_info;
+
+struct shmem_info {
+       u64 phys_addr;
+       u64 size;
+       char *handle;
+       int create;
+};
+
+int pci_shmem__init(struct kvm *self);
+int pci_shmem__register_mem(struct shmem_info *si);
+
+int pci_shmem__get_local_irqfd(struct kvm *kvm);
+int pci_shmem__add_client(struct kvm *kvm, u32 id, int fd);
+int pci_shmem__remove_client(struct kvm *kvm, u32 id);
+
+#endif
diff --git a/tools/kvm/include/kvm/pci.h b/tools/kvm/include/kvm/pci.h
new file mode 100644 (file)
index 0000000..26639b5
--- /dev/null
@@ -0,0 +1,95 @@
+#ifndef KVM__PCI_H
+#define KVM__PCI_H
+
+#include <linux/types.h>
+#include <linux/kvm.h>
+#include <linux/pci_regs.h>
+#include <endian.h>
+
+#include "kvm/kvm.h"
+#include "kvm/msi.h"
+
+#define PCI_MAX_DEVICES                256
+/*
+ * PCI Configuration Mechanism #1 I/O ports. See Section 3.7.4.1.
+ * ("Configuration Mechanism #1") of the PCI Local Bus Specification 2.1 for
+ * details.
+ */
+#define PCI_CONFIG_ADDRESS     0xcf8
+#define PCI_CONFIG_DATA                0xcfc
+#define PCI_CONFIG_BUS_FORWARD 0xcfa
+#define PCI_IO_SIZE            0x100
+
+union pci_config_address {
+       struct {
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+               unsigned        reg_offset      : 2;            /* 1  .. 0  */
+               unsigned        register_number : 6;            /* 7  .. 2  */
+               unsigned        function_number : 3;            /* 10 .. 8  */
+               unsigned        device_number   : 5;            /* 15 .. 11 */
+               unsigned        bus_number      : 8;            /* 23 .. 16 */
+               unsigned        reserved        : 7;            /* 30 .. 24 */
+               unsigned        enable_bit      : 1;            /* 31       */
+#else
+               unsigned        enable_bit      : 1;            /* 31       */
+               unsigned        reserved        : 7;            /* 30 .. 24 */
+               unsigned        bus_number      : 8;            /* 23 .. 16 */
+               unsigned        device_number   : 5;            /* 15 .. 11 */
+               unsigned        function_number : 3;            /* 10 .. 8  */
+               unsigned        register_number : 6;            /* 7  .. 2  */
+               unsigned        reg_offset      : 2;            /* 1  .. 0  */
+#endif
+       };
+       u32 w;
+};
+
+struct msix_table {
+       struct msi_msg msg;
+       u32 ctrl;
+};
+
+struct msix_cap {
+       u8 cap;
+       u8 next;
+       u16 ctrl;
+       u32 table_offset;
+       u32 pba_offset;
+};
+
+struct pci_device_header {
+       u16             vendor_id;
+       u16             device_id;
+       u16             command;
+       u16             status;
+       u8              revision_id;
+       u8              class[3];
+       u8              cacheline_size;
+       u8              latency_timer;
+       u8              header_type;
+       u8              bist;
+       u32             bar[6];
+       u32             card_bus;
+       u16             subsys_vendor_id;
+       u16             subsys_id;
+       u32             exp_rom_bar;
+       u8              capabilities;
+       u8              reserved1[3];
+       u32             reserved2;
+       u8              irq_line;
+       u8              irq_pin;
+       u8              min_gnt;
+       u8              max_lat;
+       struct msix_cap msix;
+       u8              empty[136]; /* Rest of PCI config space */
+       u32             bar_size[6];
+} __attribute__((packed));
+
+int pci__init(struct kvm *kvm);
+int pci__exit(struct kvm *kvm);
+int pci__register(struct pci_device_header *dev, u8 dev_num);
+struct pci_device_header *pci__find_dev(u8 dev_num);
+u32 pci_get_io_space_block(u32 size);
+void pci__config_wr(struct kvm *kvm, union pci_config_address addr, void *data, int size);
+void pci__config_rd(struct kvm *kvm, union pci_config_address addr, void *data, int size);
+
+#endif /* KVM__PCI_H */
diff --git a/tools/kvm/include/kvm/qcow.h b/tools/kvm/include/kvm/qcow.h
new file mode 100644 (file)
index 0000000..e032a1e
--- /dev/null
@@ -0,0 +1,133 @@
+#ifndef KVM__QCOW_H
+#define KVM__QCOW_H
+
+#include "kvm/mutex.h"
+
+#include <linux/types.h>
+#include <stdbool.h>
+#include <linux/rbtree.h>
+#include <linux/list.h>
+
+#define QCOW_MAGIC             (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb)
+
+#define QCOW1_VERSION          1
+#define QCOW2_VERSION          2
+
+#define QCOW1_OFLAG_COMPRESSED (1ULL << 63)
+
+#define QCOW2_OFLAG_COPIED     (1ULL << 63)
+#define QCOW2_OFLAG_COMPRESSED (1ULL << 62)
+
+#define QCOW2_OFLAGS_MASK      (QCOW2_OFLAG_COPIED|QCOW2_OFLAG_COMPRESSED)
+
+#define QCOW2_OFFSET_MASK      (~QCOW2_OFLAGS_MASK)
+
+#define MAX_CACHE_NODES         32
+
+struct qcow_l2_table {
+       u64                             offset;
+       struct rb_node                  node;
+       struct list_head                list;
+       u8                              dirty;
+       u64                             table[];
+};
+
+struct qcow_l1_table {
+       u32                             table_size;
+       u64                             *l1_table;
+
+       /* Level2 caching data structures */
+       struct rb_root                  root;
+       struct list_head                lru_list;
+       int                             nr_cached;
+};
+
+#define QCOW_REFCOUNT_BLOCK_SHIFT      1
+
+struct qcow_refcount_block {
+       u64                             offset;
+       struct rb_node                  node;
+       struct list_head                list;
+       u64                             size;
+       u8                              dirty;
+       u16                             entries[];
+};
+
+struct qcow_refcount_table {
+       u32                             rf_size;
+       u64                             *rf_table;
+
+       /* Refcount block caching data structures */
+       struct rb_root                  root;
+       struct list_head                lru_list;
+       int                             nr_cached;
+};
+
+struct qcow_header {
+       u64                             size;   /* in bytes */
+       u64                             l1_table_offset;
+       u32                             l1_size;
+       u8                              cluster_bits;
+       u8                              l2_bits;
+       u64                             refcount_table_offset;
+       u32                             refcount_table_size;
+};
+
+struct qcow {
+       pthread_mutex_t                 mutex;
+       struct qcow_header              *header;
+       struct qcow_l1_table            table;
+       struct qcow_refcount_table      refcount_table;
+       int                             fd;
+       int                             csize_shift;
+       int                             csize_mask;
+       u32                             version;
+       u64                             cluster_size;
+       u64                             cluster_offset_mask;
+       u64                             free_clust_idx;
+       void                            *cluster_cache;
+       void                            *cluster_data;
+       void                            *copy_buff;
+};
+
+struct qcow1_header_disk {
+       u32                             magic;
+       u32                             version;
+
+       u64                             backing_file_offset;
+       u32                             backing_file_size;
+       u32                             mtime;
+
+       u64                             size;   /* in bytes */
+
+       u8                              cluster_bits;
+       u8                              l2_bits;
+       u32                             crypt_method;
+
+       u64                             l1_table_offset;
+};
+
+struct qcow2_header_disk {
+       u32                             magic;
+       u32                             version;
+
+       u64                             backing_file_offset;
+       u32                             backing_file_size;
+
+       u32                             cluster_bits;
+       u64                             size;   /* in bytes */
+       u32                             crypt_method;
+
+       u32                             l1_size;
+       u64                             l1_table_offset;
+
+       u64                             refcount_table_offset;
+       u32                             refcount_table_clusters;
+
+       u32                             nb_snapshots;
+       u64                             snapshots_offset;
+};
+
+struct disk_image *qcow_probe(int fd, bool readonly);
+
+#endif /* KVM__QCOW_H */
diff --git a/tools/kvm/include/kvm/rbtree-interval.h b/tools/kvm/include/kvm/rbtree-interval.h
new file mode 100644 (file)
index 0000000..13245ba
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef KVM__INTERVAL_RBTREE_H
+#define KVM__INTERVAL_RBTREE_H
+
+#include <linux/rbtree.h>
+#include <linux/types.h>
+
+#define RB_INT_INIT(l, h) (struct rb_int_node){.low = l, .high = h}
+#define rb_int(n) rb_entry(n, struct rb_int_node, node)
+
+struct rb_int_node {
+       struct rb_node  node;
+       u64             low;
+       u64             high;
+
+       /* max_high will store the highest high of it's 2 children. */
+       u64             max_high;
+};
+
+/* Return the rb_int_node interval in which 'point' is located. */
+struct rb_int_node *rb_int_search_single(struct rb_root *root, u64 point);
+
+/* Return the rb_int_node in which start:len is located. */
+struct rb_int_node *rb_int_search_range(struct rb_root *root, u64 low, u64 high);
+
+int rb_int_insert(struct rb_root *root, struct rb_int_node *data);
+void rb_int_erase(struct rb_root *root, struct rb_int_node *node);
+
+#endif
diff --git a/tools/kvm/include/kvm/read-write.h b/tools/kvm/include/kvm/read-write.h
new file mode 100644 (file)
index 0000000..67571f9
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef KVM_READ_WRITE_H
+#define KVM_READ_WRITE_H
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
+
+#ifdef CONFIG_HAS_AIO
+#include <libaio.h>
+#endif
+
+ssize_t xread(int fd, void *buf, size_t count);
+ssize_t xwrite(int fd, const void *buf, size_t count);
+
+ssize_t read_in_full(int fd, void *buf, size_t count);
+ssize_t write_in_full(int fd, const void *buf, size_t count);
+
+ssize_t xpread(int fd, void *buf, size_t count, off_t offset);
+ssize_t xpwrite(int fd, const void *buf, size_t count, off_t offset);
+
+ssize_t pread_in_full(int fd, void *buf, size_t count, off_t offset);
+ssize_t pwrite_in_full(int fd, const void *buf, size_t count, off_t offset);
+
+ssize_t xreadv(int fd, const struct iovec *iov, int iovcnt);
+ssize_t xwritev(int fd, const struct iovec *iov, int iovcnt);
+
+ssize_t readv_in_full(int fd, const struct iovec *iov, int iovcnt);
+ssize_t writev_in_full(int fd, const struct iovec *iov, int iovcnt);
+
+ssize_t xpreadv(int fd, const struct iovec *iov, int iovcnt, off_t offset);
+ssize_t xpwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset);
+
+ssize_t preadv_in_full(int fd, const struct iovec *iov, int iovcnt, off_t offset);
+ssize_t pwritev_in_full(int fd, const struct iovec *iov, int iovcnt, off_t offset);
+
+#ifdef CONFIG_HAS_AIO
+int aio_preadv(io_context_t ctx, struct iocb *iocb, int fd, const struct iovec *iov, int iovcnt,
+               off_t offset, int ev, void *param);
+int aio_pwritev(io_context_t ctx, struct iocb *iocb, int fd, const struct iovec *iov, int iovcnt,
+               off_t offset, int ev, void *param);
+#endif
+
+#endif /* KVM_READ_WRITE_H */
diff --git a/tools/kvm/include/kvm/rtc.h b/tools/kvm/include/kvm/rtc.h
new file mode 100644 (file)
index 0000000..6aa9299
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef KVM__RTC_H
+#define KVM__RTC_H
+
+struct kvm;
+
+int rtc__init(struct kvm *kvm);
+int rtc__exit(struct kvm *kvm);
+
+#endif /* KVM__RTC_H */
diff --git a/tools/kvm/include/kvm/rwsem.h b/tools/kvm/include/kvm/rwsem.h
new file mode 100644 (file)
index 0000000..75a22f8
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef KVM__RWSEM_H
+#define KVM__RWSEM_H
+
+#include <pthread.h>
+
+#include "kvm/util.h"
+
+/*
+ * Kernel-alike rwsem API - to make it easier for kernel developers
+ * to write user-space code! :-)
+ */
+
+#define DECLARE_RWSEM(sem) pthread_rwlock_t sem = PTHREAD_RWLOCK_INITIALIZER
+
+static inline void down_read(pthread_rwlock_t *rwsem)
+{
+       if (pthread_rwlock_rdlock(rwsem) != 0)
+               die("unexpected pthread_rwlock_rdlock() failure!");
+}
+
+static inline void down_write(pthread_rwlock_t *rwsem)
+{
+       if (pthread_rwlock_wrlock(rwsem) != 0)
+               die("unexpected pthread_rwlock_wrlock() failure!");
+}
+
+static inline void up_read(pthread_rwlock_t *rwsem)
+{
+       if (pthread_rwlock_unlock(rwsem) != 0)
+               die("unexpected pthread_rwlock_unlock() failure!");
+}
+
+static inline void up_write(pthread_rwlock_t *rwsem)
+{
+       if (pthread_rwlock_unlock(rwsem) != 0)
+               die("unexpected pthread_rwlock_unlock() failure!");
+}
+
+#endif /* KVM__RWSEM_H */
diff --git a/tools/kvm/include/kvm/sdl.h b/tools/kvm/include/kvm/sdl.h
new file mode 100644 (file)
index 0000000..36e5986
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef KVM__SDL_H
+#define KVM__SDL_H
+
+#include "kvm/util.h"
+
+struct framebuffer;
+
+#ifdef CONFIG_HAS_SDL
+int sdl__init(struct framebuffer *fb);
+int sdl__exit(struct framebuffer *fb);
+#else
+static inline void sdl__init(struct framebuffer *fb)
+{
+       die("SDL support not compiled in. (install the SDL-dev[el] package)");
+}
+static inline void sdl__exit(struct framebuffer *fb)
+{
+       die("SDL support not compiled in. (install the SDL-dev[el] package)");
+}
+#endif
+
+#endif /* KVM__SDL_H */
diff --git a/tools/kvm/include/kvm/segment.h b/tools/kvm/include/kvm/segment.h
new file mode 100644 (file)
index 0000000..9387a82
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef KVM_SEGMENT_H
+#define KVM_SEGMENT_H
+
+#include <linux/types.h>
+
+static inline u32 segment_to_flat(u16 selector, u16 offset)
+{
+       return ((u32)selector << 4) + (u32) offset;
+}
+
+static inline u16 flat_to_seg16(u32 address)
+{
+       return address >> 4;
+}
+
+static inline u16 flat_to_off16(u32 address, u32 segment)
+{
+       return address - (segment << 4);
+}
+
+#endif /* KVM_SEGMENT_H */
diff --git a/tools/kvm/include/kvm/strbuf.h b/tools/kvm/include/kvm/strbuf.h
new file mode 100644 (file)
index 0000000..2beefbc
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef __STRBUF_H__
+#define __STRBUF_H__
+
+#include <sys/types.h>
+#include <string.h>
+
+int prefixcmp(const char *str, const char *prefix);
+
+extern size_t strlcat(char *dest, const char *src, size_t count);
+extern size_t strlcpy(char *dest, const char *src, size_t size);
+
+/* some inline functions */
+
+static inline const char *skip_prefix(const char *str, const char *prefix)
+{
+       size_t len = strlen(prefix);
+       return strncmp(str, prefix, len) ? NULL : str + len;
+}
+
+#endif
diff --git a/tools/kvm/include/kvm/symbol.h b/tools/kvm/include/kvm/symbol.h
new file mode 100644 (file)
index 0000000..725bbaf
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef KVM__SYMBOL_H
+#define KVM__SYMBOL_H
+
+#include <stddef.h>
+#include <string.h>
+
+struct kvm;
+
+#define SYMBOL_DEFAULT_UNKNOWN "<unknown>"
+
+#ifdef CONFIG_HAS_BFD
+
+int symbol_init(struct kvm *kvm);
+int symbol_exit(struct kvm *kvm);
+char *symbol_lookup(struct kvm *kvm, unsigned long addr, char *sym, size_t size);
+
+#else
+
+static inline int symbol_init(struct kvm *kvm) { return 0; }
+static inline char *symbol_lookup(struct kvm *kvm, unsigned long addr, char *sym, size_t size)
+{
+       char *s = strncpy(sym, SYMBOL_DEFAULT_UNKNOWN, size);
+       sym[size - 1] = '\0';
+       return s;
+}
+static inline int symbol_exit(struct kvm *kvm) { return 0; }
+
+#endif
+
+#endif /* KVM__SYMBOL_H */
diff --git a/tools/kvm/include/kvm/term.h b/tools/kvm/include/kvm/term.h
new file mode 100644 (file)
index 0000000..a6a9822
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef KVM__TERM_H
+#define KVM__TERM_H
+
+#include <sys/uio.h>
+#include <stdbool.h>
+
+#define CONSOLE_8250   1
+#define CONSOLE_VIRTIO 2
+#define CONSOLE_HV     3
+
+int term_putc_iov(int who, struct iovec *iov, int iovcnt, int term);
+int term_getc_iov(int who, struct iovec *iov, int iovcnt, int term);
+int term_putc(int who, char *addr, int cnt, int term);
+int term_getc(int who, int term);
+
+bool term_readable(int who, int term);
+void term_set_tty(int term);
+void term_init(void);
+
+#endif /* KVM__TERM_H */
diff --git a/tools/kvm/include/kvm/threadpool.h b/tools/kvm/include/kvm/threadpool.h
new file mode 100644 (file)
index 0000000..768239f
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef KVM__THREADPOOL_H
+#define KVM__THREADPOOL_H
+
+#include "kvm/mutex.h"
+
+#include <linux/list.h>
+
+struct kvm;
+
+typedef void (*kvm_thread_callback_fn_t)(struct kvm *kvm, void *data);
+
+struct thread_pool__job {
+       kvm_thread_callback_fn_t        callback;
+       struct kvm                      *kvm;
+       void                            *data;
+
+       int                             signalcount;
+       pthread_mutex_t                 mutex;
+
+       struct list_head                queue;
+};
+
+static inline void thread_pool__init_job(struct thread_pool__job *job, struct kvm *kvm, kvm_thread_callback_fn_t callback, void *data)
+{
+       *job = (struct thread_pool__job) {
+               .kvm            = kvm,
+               .callback       = callback,
+               .data           = data,
+               .mutex          = PTHREAD_MUTEX_INITIALIZER,
+       };
+}
+
+int thread_pool__init(unsigned long thread_count);
+
+void thread_pool__do_job(struct thread_pool__job *job);
+
+#endif
diff --git a/tools/kvm/include/kvm/types.h b/tools/kvm/include/kvm/types.h
new file mode 100644 (file)
index 0000000..0cbc5fb
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef KVM_TYPES_H
+#define KVM_TYPES_H
+
+/* FIXME: include/linux/if_tun.h and include/linux/if_ether.h complains */
+#define __be16 u16
+
+#endif /* KVM_TYPES_H */
diff --git a/tools/kvm/include/kvm/uip.h b/tools/kvm/include/kvm/uip.h
new file mode 100644 (file)
index 0000000..4497f6a
--- /dev/null
@@ -0,0 +1,358 @@
+#ifndef KVM__UIP_H
+#define KVM__UIP_H
+
+#include "linux/types.h"
+#include "kvm/mutex.h"
+
+#include <netinet/in.h>
+#include <sys/uio.h>
+
+#define UIP_BUF_STATUS_FREE    0
+#define UIP_BUF_STATUS_INUSE   1
+#define UIP_BUF_STATUS_USED    2
+
+#define UIP_ETH_P_IP           0X0800
+#define UIP_ETH_P_ARP          0X0806
+
+#define UIP_IP_VER_4           0X40
+#define UIP_IP_HDR_LEN         0X05
+#define UIP_IP_TTL             0X40
+#define UIP_IP_P_UDP           0X11
+#define UIP_IP_P_TCP           0X06
+#define UIP_IP_P_ICMP          0X01
+
+#define UIP_TCP_HDR_LEN                0x50
+#define UIP_TCP_WIN_SIZE       14600
+#define UIP_TCP_FLAG_FIN       1
+#define UIP_TCP_FLAG_SYN       2
+#define UIP_TCP_FLAG_RST       4
+#define UIP_TCP_FLAG_PSH       8
+#define UIP_TCP_FLAG_ACK       16
+#define UIP_TCP_FLAG_URG       32
+
+#define UIP_BOOTP_VENDOR_SPECIFIC_LEN  64
+#define UIP_BOOTP_MAX_PAYLOAD_LEN      300
+#define UIP_DHCP_VENDOR_SPECIFIC_LEN   312
+#define UIP_DHCP_PORT_SERVER           67
+#define UIP_DHCP_PORT_CLIENT           68
+#define UIP_DHCP_MACPAD_LEN            10
+#define UIP_DHCP_HOSTNAME_LEN          64
+#define UIP_DHCP_FILENAME_LEN          128
+#define UIP_DHCP_MAGIC_COOKIE          0x63825363
+#define UIP_DHCP_MAGIC_COOKIE_LEN      4
+#define UIP_DHCP_LEASE_TIME            0x00003840
+#define UIP_DHCP_MAX_PAYLOAD_LEN       (UIP_BOOTP_MAX_PAYLOAD_LEN - UIP_BOOTP_VENDOR_SPECIFIC_LEN +  UIP_DHCP_VENDOR_SPECIFIC_LEN)
+#define UIP_DHCP_OPTION_LEN            (UIP_DHCP_VENDOR_SPECIFIC_LEN - UIP_DHCP_MAGIC_COOKIE_LEN)
+#define UIP_DHCP_DISCOVER              1
+#define UIP_DHCP_OFFER                 2
+#define UIP_DHCP_REQUEST               3
+#define UIP_DHCP_ACK                   5
+#define UIP_DHCP_MAX_DNS_SERVER_NR     3
+#define UIP_DHCP_MAX_DOMAIN_NAME_LEN   256
+#define UIP_DHCP_TAG_MSG_TYPE          53
+#define UIP_DHCP_TAG_MSG_TYPE_LEN      1
+#define UIP_DHCP_TAG_SERVER_ID         54
+#define UIP_DHCP_TAG_SERVER_ID_LEN     4
+#define UIP_DHCP_TAG_LEASE_TIME                51
+#define UIP_DHCP_TAG_LEASE_TIME_LEN    4
+#define UIP_DHCP_TAG_SUBMASK           1
+#define UIP_DHCP_TAG_SUBMASK_LEN       4
+#define UIP_DHCP_TAG_ROUTER            3
+#define UIP_DHCP_TAG_ROUTER_LEN                4
+#define UIP_DHCP_TAG_ROOT              17
+#define UIP_DHCP_TAG_ROOT_LEN          4
+#define UIP_DHCP_TAG_DNS_SERVER                6
+#define UIP_DHCP_TAG_DNS_SERVER_LEN    4
+#define UIP_DHCP_TAG_DOMAIN_NAME       15
+#define UIP_DHCP_TAG_END               255
+
+/*
+ * IP package maxium len == 64 KBytes
+ * IP header == 20 Bytes
+ * TCP header == 20 Bytes
+ * UDP header == 8 Bytes
+ */
+#define UIP_MAX_TCP_PAYLOAD    (64*1024 - 20 - 20 - 1)
+#define UIP_MAX_UDP_PAYLOAD    (64*1024 - 20 -  8 - 1)
+
+struct uip_eth_addr {
+       u8 addr[6];
+};
+
+struct uip_eth {
+       struct uip_eth_addr dst;
+       struct uip_eth_addr src;
+       u16 type;
+} __attribute__((packed));
+
+struct uip_arp {
+       struct uip_eth eth;
+       u16 hwtype;
+       u16 proto;
+       u8 hwlen;
+       u8 protolen;
+       u16 op;
+       struct uip_eth_addr smac;
+       u32 sip;
+       struct uip_eth_addr dmac;
+       u32 dip;
+} __attribute__((packed));
+
+struct uip_ip {
+       struct uip_eth eth;
+       u8 vhl;
+       u8 tos;
+       /*
+        * len = IP hdr +  IP payload
+        */
+       u16 len;
+       u16 id;
+       u16 flgfrag;
+       u8 ttl;
+       u8 proto;
+       u16 csum;
+       u32 sip;
+       u32 dip;
+} __attribute__((packed));
+
+struct uip_icmp {
+       struct uip_ip ip;
+       u8 type;
+       u8 code;
+       u16 csum;
+       u16 id;
+       u16 seq;
+} __attribute__((packed));
+
+struct uip_udp {
+       /*
+        * FIXME: IP Options (IP hdr len > 20 bytes) are not supported
+        */
+       struct uip_ip ip;
+       u16 sport;
+       u16 dport;
+       /*
+        * len = UDP hdr +  UDP payload
+        */
+       u16 len;
+       u16 csum;
+       u8 payload[0];
+} __attribute__((packed));
+
+struct uip_tcp {
+       /*
+        * FIXME: IP Options (IP hdr len > 20 bytes) are not supported
+        */
+       struct uip_ip ip;
+       u16 sport;
+       u16 dport;
+       u32 seq;
+       u32 ack;
+       u8  off;
+       u8  flg;
+       u16 win;
+       u16 csum;
+       u16 urgent;
+} __attribute__((packed));
+
+struct uip_pseudo_hdr {
+       u32 sip;
+       u32 dip;
+       u8 zero;
+       u8 proto;
+       u16 len;
+} __attribute__((packed));
+
+struct uip_dhcp {
+       struct uip_udp udp;
+       u8 msg_type;
+       u8 hardware_type;
+       u8 hardware_len;
+       u8 hops;
+       u32 id;
+       u16 time;
+       u16 flg;
+       u32 client_ip;
+       u32 your_ip;
+       u32 server_ip;
+       u32 agent_ip;
+       struct uip_eth_addr client_mac;
+       u8 pad[UIP_DHCP_MACPAD_LEN];
+       u8 server_hostname[UIP_DHCP_HOSTNAME_LEN];
+       u8 boot_filename[UIP_DHCP_FILENAME_LEN];
+       u32 magic_cookie;
+       u8 option[UIP_DHCP_OPTION_LEN];
+} __attribute__((packed));
+
+struct uip_info {
+       struct list_head udp_socket_head;
+       struct list_head tcp_socket_head;
+       pthread_mutex_t udp_socket_lock;
+       pthread_mutex_t tcp_socket_lock;
+       struct uip_eth_addr guest_mac;
+       struct uip_eth_addr host_mac;
+       pthread_cond_t buf_free_cond;
+       pthread_cond_t buf_used_cond;
+       struct list_head buf_head;
+       pthread_mutex_t buf_lock;
+       pthread_t udp_thread;
+       int udp_epollfd;
+       int buf_free_nr;
+       int buf_used_nr;
+       u32 guest_ip;
+       u32 guest_netmask;
+       u32 host_ip;
+       u32 dns_ip[UIP_DHCP_MAX_DNS_SERVER_NR];
+       char *domain_name;
+       u32 buf_nr;
+};
+
+struct uip_buf {
+       struct list_head list;
+       struct uip_info *info;
+       int vnet_len;
+       int eth_len;
+       int status;
+       char *vnet;
+       char *eth;
+       int id;
+};
+
+struct uip_udp_socket {
+       struct sockaddr_in addr;
+       struct list_head list;
+       pthread_mutex_t *lock;
+       u32 dport, sport;
+       u32 dip, sip;
+       int fd;
+};
+
+struct uip_tcp_socket {
+       struct sockaddr_in addr;
+       struct list_head list;
+       struct uip_info *info;
+       pthread_mutex_t *lock;
+       pthread_t thread;
+       u32 dport, sport;
+       u32 guest_acked;
+       /*
+        * Initial Sequence Number
+        */
+       u32 isn_server;
+       u32 isn_guest;
+       u32 ack_server;
+       u32 seq_server;
+       int write_done;
+       int read_done;
+       u32 dip, sip;
+       u8 *payload;
+       int fd;
+};
+
+struct uip_tx_arg {
+       struct virtio_net_hdr *vnet;
+       struct uip_info *info;
+       struct uip_eth *eth;
+       int vnet_len;
+       int eth_len;
+};
+
+static inline u16 uip_ip_hdrlen(struct uip_ip *ip)
+{
+       return (ip->vhl & 0x0f) * 4;
+}
+
+static inline u16 uip_ip_len(struct uip_ip *ip)
+{
+       return htons(ip->len);
+}
+
+static inline u16 uip_udp_hdrlen(struct uip_udp *udp)
+{
+       return 8;
+}
+
+static inline u16 uip_udp_len(struct uip_udp *udp)
+{
+       return ntohs(udp->len);
+}
+
+static inline u16 uip_tcp_hdrlen(struct uip_tcp *tcp)
+{
+       return (tcp->off >> 4) * 4;
+}
+
+static inline u16 uip_tcp_len(struct uip_tcp *tcp)
+{
+       struct uip_ip *ip;
+
+       ip = &tcp->ip;
+
+       return uip_ip_len(ip) - uip_ip_hdrlen(ip);
+}
+
+static inline u16 uip_tcp_payloadlen(struct uip_tcp *tcp)
+{
+       return uip_tcp_len(tcp) - uip_tcp_hdrlen(tcp);
+}
+
+static inline u8 *uip_tcp_payload(struct uip_tcp *tcp)
+{
+       return (u8 *)&tcp->sport + uip_tcp_hdrlen(tcp);
+}
+
+static inline bool uip_tcp_is_syn(struct uip_tcp *tcp)
+{
+       return (tcp->flg & UIP_TCP_FLAG_SYN) != 0;
+}
+
+static inline bool uip_tcp_is_fin(struct uip_tcp *tcp)
+{
+       return (tcp->flg & UIP_TCP_FLAG_FIN) != 0;
+}
+
+static inline u32 uip_tcp_isn(struct uip_tcp *tcp)
+{
+       return ntohl(tcp->seq);
+}
+
+static inline u32 uip_tcp_isn_alloc(void)
+{
+       /*
+        * FIXME: should increase every 4ms
+        */
+       return 10000000;
+}
+
+static inline u16 uip_eth_hdrlen(struct uip_eth *eth)
+{
+       return sizeof(*eth);
+}
+
+int uip_tx(struct iovec *iov, u16 out, struct uip_info *info);
+int uip_rx(struct iovec *iov, u16 in, struct uip_info *info);
+int uip_init(struct uip_info *info);
+
+int uip_tx_do_ipv4_udp_dhcp(struct uip_tx_arg *arg);
+int uip_tx_do_ipv4_icmp(struct uip_tx_arg *arg);
+int uip_tx_do_ipv4_tcp(struct uip_tx_arg *arg);
+int uip_tx_do_ipv4_udp(struct uip_tx_arg *arg);
+int uip_tx_do_ipv4(struct uip_tx_arg *arg);
+int uip_tx_do_arp(struct uip_tx_arg *arg);
+
+u16 uip_csum_icmp(struct uip_icmp *icmp);
+u16 uip_csum_udp(struct uip_udp *udp);
+u16 uip_csum_tcp(struct uip_tcp *tcp);
+u16 uip_csum_ip(struct uip_ip *ip);
+
+struct uip_buf *uip_buf_set_used(struct uip_info *info, struct uip_buf *buf);
+struct uip_buf *uip_buf_set_free(struct uip_info *info, struct uip_buf *buf);
+struct uip_buf *uip_buf_get_used(struct uip_info *info);
+struct uip_buf *uip_buf_get_free(struct uip_info *info);
+struct uip_buf *uip_buf_clone(struct uip_tx_arg *arg);
+
+int uip_udp_make_pkg(struct uip_info *info, struct uip_udp_socket *sk, struct uip_buf *buf, u8 *payload, int payload_len);
+bool uip_udp_is_dhcp(struct uip_udp *udp);
+
+int uip_dhcp_get_dns(struct uip_info *info);
+#endif /* KVM__UIP_H */
diff --git a/tools/kvm/include/kvm/util.h b/tools/kvm/include/kvm/util.h
new file mode 100644 (file)
index 0000000..0df9f0d
--- /dev/null
@@ -0,0 +1,97 @@
+#include <linux/stringify.h>
+
+#ifndef KVM__UTIL_H
+#define KVM__UTIL_H
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+/*
+ * Some bits are stolen from perf tool :)
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdbool.h>
+#include <signal.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <linux/types.h>
+
+#ifdef __GNUC__
+#define NORETURN __attribute__((__noreturn__))
+#else
+#define NORETURN
+#ifndef __attribute__
+#define __attribute__(x)
+#endif
+#endif
+
+extern bool do_debug_print;
+
+#define PROT_RW (PROT_READ|PROT_WRITE)
+#define MAP_ANON_NORESERVE (MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE)
+
+extern void die(const char *err, ...) NORETURN __attribute__((format (printf, 1, 2)));
+extern void die_perror(const char *s) NORETURN;
+extern int pr_err(const char *err, ...) __attribute__((format (printf, 1, 2)));
+extern void pr_warning(const char *err, ...) __attribute__((format (printf, 1, 2)));
+extern void pr_info(const char *err, ...) __attribute__((format (printf, 1, 2)));
+extern void set_die_routine(void (*routine)(const char *err, va_list params) NORETURN);
+
+#define pr_debug(fmt, ...)                                             \
+       do {                                                            \
+               if (do_debug_print)                                     \
+                       pr_info("(%s) %s:%d: " fmt, __FILE__,           \
+                               __func__, __LINE__, ##__VA_ARGS__);     \
+       } while (0)
+
+
+#define BUILD_BUG_ON(condition)        ((void)sizeof(char[1 - 2*!!(condition)]))
+
+#ifndef BUG_ON_HANDLER
+# define BUG_ON_HANDLER(condition)                                     \
+       do {                                                            \
+               if ((condition)) {                                      \
+                       pr_err("BUG at %s:%d", __FILE__, __LINE__);     \
+                       raise(SIGABRT);                                 \
+               }                                                       \
+       } while (0)
+#endif
+
+#define BUG_ON(condition)      BUG_ON_HANDLER((condition))
+
+#define DIE_IF(cnd)                                            \
+do {                                                           \
+       if (cnd)                                                \
+       die(" at (" __FILE__ ":" __stringify(__LINE__) "): "    \
+               __stringify(cnd) "\n");                         \
+} while (0)
+
+#define WARN_ON(condition) ({                                  \
+       int __ret_warn_on = !!(condition);                      \
+       if (__ret_warn_on)                                      \
+               pr_warning("(%s) %s:%d: failed condition: %s",  \
+                               __FILE__, __func__, __LINE__,   \
+                               __stringify(condition));        \
+       __ret_warn_on;                                          \
+})
+
+#define MSECS_TO_USECS(s) ((s) * 1000)
+
+/* Millisecond sleep */
+static inline void msleep(unsigned int msecs)
+{
+       usleep(MSECS_TO_USECS(msecs));
+}
+
+struct kvm;
+void *mmap_hugetlbfs(struct kvm *kvm, const char *htlbfs_path, u64 size);
+void *mmap_anon_or_hugetlbfs(struct kvm *kvm, const char *hugetlbfs_path, u64 size);
+
+#endif /* KVM__UTIL_H */
diff --git a/tools/kvm/include/kvm/vesa.h b/tools/kvm/include/kvm/vesa.h
new file mode 100644 (file)
index 0000000..ac041d9
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef KVM__VESA_H
+#define KVM__VESA_H
+
+#include <linux/types.h>
+
+#define VESA_WIDTH     640
+#define VESA_HEIGHT    480
+
+#define VESA_MEM_ADDR  0xd0000000
+#define VESA_MEM_SIZE  (4*VESA_WIDTH*VESA_HEIGHT)
+#define VESA_BPP       32
+
+struct kvm;
+struct biosregs;
+
+struct framebuffer *vesa__init(struct kvm *self);
+
+#endif
diff --git a/tools/kvm/include/kvm/virtio-9p.h b/tools/kvm/include/kvm/virtio-9p.h
new file mode 100644 (file)
index 0000000..cb590d1
--- /dev/null
@@ -0,0 +1,73 @@
+#ifndef KVM__VIRTIO_9P_H
+#define KVM__VIRTIO_9P_H
+#include "kvm/virtio.h"
+#include "kvm/pci.h"
+#include "kvm/threadpool.h"
+
+#include <sys/types.h>
+#include <dirent.h>
+#include <linux/list.h>
+#include <linux/rbtree.h>
+
+#define NUM_VIRT_QUEUES                1
+#define VIRTQUEUE_NUM          128
+#define        VIRTIO_9P_DEFAULT_TAG   "kvm_9p"
+#define VIRTIO_9P_HDR_LEN      (sizeof(u32)+sizeof(u8)+sizeof(u16))
+#define VIRTIO_9P_VERSION_DOTL "9P2000.L"
+#define MAX_TAG_LEN            32
+
+struct p9_msg {
+       u32                     size;
+       u8                      cmd;
+       u16                     tag;
+       u8                      msg[0];
+} __attribute__((packed));
+
+struct p9_fid {
+       u32                     fid;
+       u32                     uid;
+       char                    abs_path[PATH_MAX];
+       char                    *path;
+       DIR                     *dir;
+       int                     fd;
+       struct rb_node          node;
+};
+
+struct p9_dev_job {
+       struct virt_queue       *vq;
+       struct p9_dev           *p9dev;
+       struct thread_pool__job job_id;
+};
+
+struct p9_dev {
+       struct list_head        list;
+       struct virtio_device    vdev;
+       struct rb_root          fids;
+
+       struct virtio_9p_config *config;
+       u32                     features;
+
+       /* virtio queue */
+       struct virt_queue       vqs[NUM_VIRT_QUEUES];
+       struct p9_dev_job       jobs[NUM_VIRT_QUEUES];
+       char                    root_dir[PATH_MAX];
+};
+
+struct p9_pdu {
+       u32                     queue_head;
+       size_t                  read_offset;
+       size_t                  write_offset;
+       u16                     out_iov_cnt;
+       u16                     in_iov_cnt;
+       struct iovec            in_iov[VIRTQUEUE_NUM];
+       struct iovec            out_iov[VIRTQUEUE_NUM];
+};
+
+struct kvm;
+
+int virtio_9p__register(struct kvm *kvm, const char *root, const char *tag_name);
+int virtio_9p__init(struct kvm *kvm);
+int virtio_p9_pdu_readf(struct p9_pdu *pdu, const char *fmt, ...);
+int virtio_p9_pdu_writef(struct p9_pdu *pdu, const char *fmt, ...);
+
+#endif
diff --git a/tools/kvm/include/kvm/virtio-balloon.h b/tools/kvm/include/kvm/virtio-balloon.h
new file mode 100644 (file)
index 0000000..eb49fd4
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef KVM__BLN_VIRTIO_H
+#define KVM__BLN_VIRTIO_H
+
+struct kvm;
+
+void virtio_bln__init(struct kvm *kvm);
+
+#endif /* KVM__BLN_VIRTIO_H */
diff --git a/tools/kvm/include/kvm/virtio-blk.h b/tools/kvm/include/kvm/virtio-blk.h
new file mode 100644 (file)
index 0000000..12e59b6
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef KVM__BLK_VIRTIO_H
+#define KVM__BLK_VIRTIO_H
+
+#include "kvm/disk-image.h"
+
+struct kvm;
+
+int virtio_blk__init(struct kvm *kvm);
+int virtio_blk__exit(struct kvm *kvm);
+void virtio_blk_complete(void *param, long len);
+
+#endif /* KVM__BLK_VIRTIO_H */
diff --git a/tools/kvm/include/kvm/virtio-console.h b/tools/kvm/include/kvm/virtio-console.h
new file mode 100644 (file)
index 0000000..50d8653
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef KVM__CONSOLE_VIRTIO_H
+#define KVM__CONSOLE_VIRTIO_H
+
+struct kvm;
+
+void virtio_console__init(struct kvm *kvm);
+void virtio_console__inject_interrupt(struct kvm *kvm);
+
+#endif /* KVM__CONSOLE_VIRTIO_H */
diff --git a/tools/kvm/include/kvm/virtio-mmio.h b/tools/kvm/include/kvm/virtio-mmio.h
new file mode 100644 (file)
index 0000000..e0ede3c
--- /dev/null
@@ -0,0 +1,58 @@
+#ifndef KVM__VIRTIO_MMIO_H
+#define KVM__VIRTIO_MMIO_H
+
+#include <linux/types.h>
+#include <linux/virtio_mmio.h>
+
+#define VIRTIO_MMIO_MAX_VQ     3
+#define VIRTIO_MMIO_MAX_CONFIG 1
+#define VIRTIO_MMIO_IO_SIZE    0x200
+
+struct kvm;
+
+struct virtio_mmio_ioevent_param {
+       struct virtio_device    *vdev;
+       u32                     vq;
+};
+
+struct virtio_mmio_hdr {
+       char    magic[4];
+       u32     version;
+       u32     device_id;
+       u32     vendor_id;
+       u32     host_features;
+       u32     host_features_sel;
+       u32     reserved_1[2];
+       u32     guest_features;
+       u32     guest_features_sel;
+       u32     guest_page_size;
+       u32     reserved_2;
+       u32     queue_sel;
+       u32     queue_num_max;
+       u32     queue_num;
+       u32     queue_align;
+       u32     queue_pfn;
+       u32     reserved_3[3];
+       u32     queue_notify;
+       u32     reserved_4[3];
+       u32     interrupt_state;
+       u32     interrupt_ack;
+       u32     reserved_5[2];
+       u32     status;
+} __attribute__((packed));
+
+struct virtio_mmio {
+       u32                     addr;
+       void                    *dev;
+       struct kvm              *kvm;
+       u8                      irq;
+       struct virtio_mmio_hdr  hdr;
+       struct virtio_mmio_ioevent_param ioeventfds[VIRTIO_MMIO_MAX_VQ];
+};
+
+int virtio_mmio_signal_vq(struct kvm *kvm, struct virtio_device *vdev, u32 vq);
+int virtio_mmio_signal_config(struct kvm *kvm, struct virtio_device *vdev);
+int virtio_mmio_exit(struct kvm *kvm, struct virtio_device *vdev);
+int virtio_mmio_init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
+                     int device_id, int subsys_id, int class);
+#endif
diff --git a/tools/kvm/include/kvm/virtio-net.h b/tools/kvm/include/kvm/virtio-net.h
new file mode 100644 (file)
index 0000000..737676e
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef KVM__VIRTIO_NET_H
+#define KVM__VIRTIO_NET_H
+
+struct kvm;
+
+struct virtio_net_params {
+       const char *guest_ip;
+       const char *host_ip;
+       const char *script;
+       const char *trans;
+       char guest_mac[6];
+       char host_mac[6];
+       struct kvm *kvm;
+       int mode;
+       int vhost;
+       int fd;
+};
+
+void virtio_net__init(const struct virtio_net_params *params);
+
+enum {
+       NET_MODE_USER,
+       NET_MODE_TAP
+};
+
+#endif /* KVM__VIRTIO_NET_H */
diff --git a/tools/kvm/include/kvm/virtio-pci-dev.h b/tools/kvm/include/kvm/virtio-pci-dev.h
new file mode 100644 (file)
index 0000000..7ceb125
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef VIRTIO_PCI_DEV_H_
+#define VIRTIO_PCI_DEV_H_
+
+#include <linux/virtio_ids.h>
+
+/*
+ * Virtio PCI device constants and resources
+ * they do use (such as irqs and pins).
+ */
+
+#define PCI_DEVICE_ID_VIRTIO_NET               0x1000
+#define PCI_DEVICE_ID_VIRTIO_BLK               0x1001
+#define PCI_DEVICE_ID_VIRTIO_CONSOLE           0x1003
+#define PCI_DEVICE_ID_VIRTIO_RNG               0x1004
+#define PCI_DEVICE_ID_VIRTIO_BLN               0x1005
+#define PCI_DEVICE_ID_VIRTIO_9P                        0x1009
+#define PCI_DEVICE_ID_VESA                     0x2000
+#define PCI_DEVICE_ID_PCI_SHMEM                        0x0001
+
+#define PCI_VENDOR_ID_REDHAT_QUMRANET          0x1af4
+#define PCI_VENDOR_ID_PCI_SHMEM                        0x0001
+#define PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET        0x1af4
+
+#define PCI_SUBSYSTEM_ID_VESA                  0x0004
+#define PCI_SUBSYSTEM_ID_PCI_SHMEM             0x0001
+
+#define PCI_CLASS_BLK                          0x018000
+#define PCI_CLASS_NET                          0x020000
+#define PCI_CLASS_CONSOLE                      0x078000
+/*
+ * 0xFF Device does not fit in any defined classes
+ */
+#define PCI_CLASS_RNG                          0xff0000
+#define PCI_CLASS_BLN                          0xff0000
+#define PCI_CLASS_9P                           0xff0000
+
+#endif /* VIRTIO_PCI_DEV_H_ */
diff --git a/tools/kvm/include/kvm/virtio-pci.h b/tools/kvm/include/kvm/virtio-pci.h
new file mode 100644 (file)
index 0000000..9e036b2
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef KVM__VIRTIO_PCI_H
+#define KVM__VIRTIO_PCI_H
+
+#include "kvm/pci.h"
+
+#include <linux/types.h>
+
+#define VIRTIO_PCI_MAX_VQ      3
+#define VIRTIO_PCI_MAX_CONFIG  1
+
+struct kvm;
+
+struct virtio_pci_ioevent_param {
+       struct virtio_device    *vdev;
+       u32                     vq;
+};
+
+struct virtio_pci {
+       struct pci_device_header pci_hdr;
+       void                    *dev;
+
+       u16                     base_addr;
+       u8                      status;
+       u8                      isr;
+
+       /* MSI-X */
+       u16                     config_vector;
+       u32                     config_gsi;
+       u32                     vq_vector[VIRTIO_PCI_MAX_VQ];
+       u32                     gsis[VIRTIO_PCI_MAX_VQ];
+       u32                     msix_io_block;
+       u64                     msix_pba;
+       struct msix_table       msix_table[VIRTIO_PCI_MAX_VQ + VIRTIO_PCI_MAX_CONFIG];
+
+       /* virtio queue */
+       u16                     queue_selector;
+       struct virtio_pci_ioevent_param ioeventfds[VIRTIO_PCI_MAX_VQ];
+};
+
+int virtio_pci__signal_vq(struct kvm *kvm, struct virtio_device *vdev, u32 vq);
+int virtio_pci__signal_config(struct kvm *kvm, struct virtio_device *vdev);
+int virtio_pci__exit(struct kvm *kvm, struct virtio_device *vdev);
+int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
+                    int device_id, int subsys_id, int class);
+
+#endif
diff --git a/tools/kvm/include/kvm/virtio-rng.h b/tools/kvm/include/kvm/virtio-rng.h
new file mode 100644 (file)
index 0000000..b585b37
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef KVM__RNG_VIRTIO_H
+#define KVM__RNG_VIRTIO_H
+
+struct kvm;
+
+int virtio_rng__init(struct kvm *kvm);
+int virtio_rng__exit(struct kvm *kvm);
+
+#endif /* KVM__RNG_VIRTIO_H */
diff --git a/tools/kvm/include/kvm/virtio.h b/tools/kvm/include/kvm/virtio.h
new file mode 100644 (file)
index 0000000..71b6bad
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef KVM__VIRTIO_H
+#define KVM__VIRTIO_H
+
+#include <linux/virtio_ring.h>
+#include <linux/virtio_pci.h>
+
+#include <linux/types.h>
+#include <sys/uio.h>
+
+#include "kvm/kvm.h"
+
+#define VIRTIO_IRQ_LOW         0
+#define VIRTIO_IRQ_HIGH                1
+
+#define VIRTIO_PCI_O_CONFIG    0
+#define VIRTIO_PCI_O_MSIX      1
+
+struct virt_queue {
+       struct vring    vring;
+       u32             pfn;
+       /* The last_avail_idx field is an index to ->ring of struct vring_avail.
+          It's where we assume the next request index is at.  */
+       u16             last_avail_idx;
+       u16             last_used_signalled;
+};
+
+static inline u16 virt_queue__pop(struct virt_queue *queue)
+{
+       return queue->vring.avail->ring[queue->last_avail_idx++ % queue->vring.num];
+}
+
+static inline struct vring_desc *virt_queue__get_desc(struct virt_queue *queue, u16 desc_ndx)
+{
+       return &queue->vring.desc[desc_ndx];
+}
+
+static inline bool virt_queue__available(struct virt_queue *vq)
+{
+       if (!vq->vring.avail)
+               return 0;
+
+       vring_avail_event(&vq->vring) = vq->last_avail_idx;
+       return vq->vring.avail->idx !=  vq->last_avail_idx;
+}
+
+/*
+ * Warning: on 32-bit hosts, shifting pfn left may cause a truncation of pfn values
+ * higher than 4GB - thus, pointing to the wrong area in guest virtual memory space
+ * and breaking the virt queue which owns this pfn.
+ */
+static inline void *guest_pfn_to_host(struct kvm *kvm, u32 pfn)
+{
+       return guest_flat_to_host(kvm, (unsigned long)pfn << VIRTIO_PCI_QUEUE_ADDR_SHIFT);
+}
+
+
+struct vring_used_elem *virt_queue__set_used_elem(struct virt_queue *queue, u32 head, u32 len);
+
+bool virtio_queue__should_signal(struct virt_queue *vq);
+u16 virt_queue__get_iov(struct virt_queue *vq, struct iovec iov[],
+                       u16 *out, u16 *in, struct kvm *kvm);
+u16 virt_queue__get_head_iov(struct virt_queue *vq, struct iovec iov[],
+                            u16 *out, u16 *in, u16 head, struct kvm *kvm);
+u16 virt_queue__get_inout_iov(struct kvm *kvm, struct virt_queue *queue,
+                             struct iovec in_iov[], struct iovec out_iov[],
+                             u16 *in, u16 *out);
+int virtio__get_dev_specific_field(int offset, bool msix, u32 *config_off);
+
+enum virtio_trans {
+       VIRTIO_PCI,
+       VIRTIO_MMIO,
+};
+
+struct virtio_device {
+       bool                    use_vhost;
+       void                    *virtio;
+       struct virtio_ops       *ops;
+};
+
+struct virtio_ops {
+       void (*set_config)(struct kvm *kvm, void *dev, u8 data, u32 offset);
+       u8 (*get_config)(struct kvm *kvm, void *dev, u32 offset);
+       u32 (*get_host_features)(struct kvm *kvm, void *dev);
+       void (*set_guest_features)(struct kvm *kvm, void *dev, u32 features);
+       int (*init_vq)(struct kvm *kvm, void *dev, u32 vq, u32 pfn);
+       int (*notify_vq)(struct kvm *kvm, void *dev, u32 vq);
+       int (*get_pfn_vq)(struct kvm *kvm, void *dev, u32 vq);
+       int (*get_size_vq)(struct kvm *kvm, void *dev, u32 vq);
+       int (*set_size_vq)(struct kvm *kvm, void *dev, u32 vq, int size);
+       void (*notify_vq_gsi)(struct kvm *kvm, void *dev, u32 vq, u32 gsi);
+       void (*notify_vq_eventfd)(struct kvm *kvm, void *dev, u32 vq, u32 efd);
+       int (*signal_vq)(struct kvm *kvm, struct virtio_device *vdev, u32 queueid);
+       int (*signal_config)(struct kvm *kvm, struct virtio_device *vdev);
+       int (*init)(struct kvm *kvm, void *dev, struct virtio_device *vdev,
+                   int device_id, int subsys_id, int class);
+       int (*exit)(struct kvm *kvm, struct virtio_device *vdev);
+};
+
+int virtio_init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
+               struct virtio_ops *ops, enum virtio_trans trans,
+               int device_id, int subsys_id, int class);
+int virtio_compat_add_message(const char *device, const char *config);
+#endif /* KVM__VIRTIO_H */
diff --git a/tools/kvm/include/kvm/vnc.h b/tools/kvm/include/kvm/vnc.h
new file mode 100644 (file)
index 0000000..3278c07
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef KVM__VNC_H
+#define KVM__VNC_H
+
+struct framebuffer;
+
+#ifdef CONFIG_HAS_VNCSERVER
+int vnc__init(struct framebuffer *fb);
+int vnc__exit(struct framebuffer *fb);
+#else
+static inline int vnc__init(struct framebuffer *fb)
+{
+       return 0;
+}
+static inline int vnc__exit(struct framebuffer *fb)
+{
+       return 0;
+}
+#endif
+
+#endif /* KVM__VNC_H */
diff --git a/tools/kvm/include/linux/bitops.h b/tools/kvm/include/linux/bitops.h
new file mode 100644 (file)
index 0000000..56448b7
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef _KVM_LINUX_BITOPS_H_
+#define _KVM_LINUX_BITOPS_H_
+
+#include <linux/kernel.h>
+#include <linux/compiler.h>
+#include <asm/hweight.h>
+
+#define BITS_PER_LONG __WORDSIZE
+#define BITS_PER_BYTE           8
+#define BITS_TO_LONGS(nr)       DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
+
+static inline void set_bit(int nr, unsigned long *addr)
+{
+       addr[nr / BITS_PER_LONG] |= 1UL << (nr % BITS_PER_LONG);
+}
+
+static inline void clear_bit(int nr, unsigned long *addr)
+{
+       addr[nr / BITS_PER_LONG] &= ~(1UL << (nr % BITS_PER_LONG));
+}
+
+static __always_inline int test_bit(unsigned int nr, const unsigned long *addr)
+{
+       return ((1UL << (nr % BITS_PER_LONG)) &
+               (((unsigned long *)addr)[nr / BITS_PER_LONG])) != 0;
+}
+
+static inline unsigned long hweight_long(unsigned long w)
+{
+       return sizeof(w) == 4 ? hweight32(w) : hweight64(w);
+}
+
+#endif
diff --git a/tools/kvm/include/linux/byteorder.h b/tools/kvm/include/linux/byteorder.h
new file mode 100644 (file)
index 0000000..c490de8
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __BYTE_ORDER_H__
+#define __BYTE_ORDER_H__
+
+#include <asm/byteorder.h>
+#include <linux/byteorder/generic.h>
+
+#endif
diff --git a/tools/kvm/include/linux/compiler.h b/tools/kvm/include/linux/compiler.h
new file mode 100644 (file)
index 0000000..b9c5346
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef _PERF_LINUX_COMPILER_H_
+#define _PERF_LINUX_COMPILER_H_
+
+#ifndef __always_inline
+#define __always_inline        inline
+#endif
+#define __user
+
+#ifndef __attribute_const__
+#define __attribute_const__
+#endif
+
+#define __used         __attribute__((__unused__))
+#define __iomem
+#define __force
+#define __must_check
+#define unlikely
+
+#endif
diff --git a/tools/kvm/include/linux/kernel.h b/tools/kvm/include/linux/kernel.h
new file mode 100644 (file)
index 0000000..d2ec4a3
--- /dev/null
@@ -0,0 +1,39 @@
+
+#ifndef KVM__LINUX_KERNEL_H_
+#define KVM__LINUX_KERNEL_H_
+
+#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
+
+#define ALIGN(x,a)             __ALIGN_MASK(x,(typeof(x))(a)-1)
+#define __ALIGN_MASK(x,mask)   (((x)+(mask))&~(mask))
+
+#ifndef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+#ifndef container_of
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ * @ptr:       the pointer to the member.
+ * @type:      the type of the container struct this is embedded in.
+ * @member:    the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({                     \
+       const typeof(((type *)0)->member) * __mptr = (ptr);     \
+       (type *)((char *)__mptr - offsetof(type, member)); })
+#endif
+
+#define min(x, y) ({                           \
+       typeof(x) _min1 = (x);                  \
+       typeof(y) _min2 = (y);                  \
+       (void) (&_min1 == &_min2);              \
+       _min1 < _min2 ? _min1 : _min2; })
+
+#define max(x, y) ({                           \
+       typeof(x) _max1 = (x);                  \
+       typeof(y) _max2 = (y);                  \
+       (void) (&_max1 == &_max2);              \
+       _max1 > _max2 ? _max1 : _max2; })
+
+#endif
diff --git a/tools/kvm/include/linux/module.h b/tools/kvm/include/linux/module.h
new file mode 100644 (file)
index 0000000..0e4c6a3
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef KVM__LINUX_MODULE_H
+#define KVM__LINUX_MODULE_H
+
+#define EXPORT_SYMBOL(name)
+
+#endif
diff --git a/tools/kvm/include/linux/prefetch.h b/tools/kvm/include/linux/prefetch.h
new file mode 100644 (file)
index 0000000..62f6788
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef KVM__LINUX_PREFETCH_H
+#define KVM__LINUX_PREFETCH_H
+
+static inline void prefetch(void *a __attribute__((unused))) { }
+
+#endif
diff --git a/tools/kvm/include/linux/stddef.h b/tools/kvm/include/linux/stddef.h
new file mode 100644 (file)
index 0000000..60ea512
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef _LINUX_STDDEF_H
+#define _LINUX_STDDEF_H
+
+#include <linux/compiler.h>
+
+#undef NULL
+#define NULL ((void *)0)
+
+#undef offsetof
+#ifdef __compiler_offsetof
+#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
+#else
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+#endif
+
+#endif
diff --git a/tools/kvm/include/linux/types.h b/tools/kvm/include/linux/types.h
new file mode 100644 (file)
index 0000000..5e20f10
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef LINUX_TYPES_H
+#define LINUX_TYPES_H
+
+#include <kvm/compiler.h>
+#define __SANE_USERSPACE_TYPES__       /* For PPC64, to get LL64 types */
+#include <asm/types.h>
+
+typedef __u64 u64;
+typedef __s64 s64;
+
+typedef __u32 u32;
+typedef __s32 s32;
+
+typedef __u16 u16;
+typedef __s16 s16;
+
+typedef __u8  u8;
+typedef __s8  s8;
+
+#ifdef __CHECKER__
+#define __bitwise__ __attribute__((bitwise))
+#else
+#define __bitwise__
+#endif
+#ifdef __CHECK_ENDIAN__
+#define __bitwise __bitwise__
+#else
+#define __bitwise
+#endif
+
+
+typedef __u16 __bitwise __le16;
+typedef __u16 __bitwise __be16;
+typedef __u32 __bitwise __le32;
+typedef __u32 __bitwise __be32;
+typedef __u64 __bitwise __le64;
+typedef __u64 __bitwise __be64;
+
+struct list_head {
+       struct list_head *next, *prev;
+};
+
+struct hlist_head {
+       struct hlist_node *first;
+};
+
+struct hlist_node {
+       struct hlist_node *next, **pprev;
+};
+
+#endif /* LINUX_TYPES_H */
diff --git a/tools/kvm/ioeventfd.c b/tools/kvm/ioeventfd.c
new file mode 100644 (file)
index 0000000..226876f
--- /dev/null
@@ -0,0 +1,215 @@
+#include <sys/epoll.h>
+#include <sys/ioctl.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <signal.h>
+
+#include <linux/kernel.h>
+#include <linux/kvm.h>
+#include <linux/types.h>
+
+#include "kvm/ioeventfd.h"
+#include "kvm/kvm.h"
+#include "kvm/util.h"
+
+#define IOEVENTFD_MAX_EVENTS   20
+
+static struct  epoll_event events[IOEVENTFD_MAX_EVENTS];
+static int     epoll_fd, epoll_stop_fd;
+static LIST_HEAD(used_ioevents);
+static bool    ioeventfd_avail;
+
+static void *ioeventfd__thread(void *param)
+{
+       u64 tmp = 1;
+
+       for (;;) {
+               int nfds, i;
+
+               nfds = epoll_wait(epoll_fd, events, IOEVENTFD_MAX_EVENTS, -1);
+               for (i = 0; i < nfds; i++) {
+                       struct ioevent *ioevent;
+
+                       if (events[i].data.fd == epoll_stop_fd)
+                               goto done;
+
+                       ioevent = events[i].data.ptr;
+
+                       if (read(ioevent->fd, &tmp, sizeof(tmp)) < 0)
+                               die("Failed reading event");
+
+                       ioevent->fn(ioevent->fn_kvm, ioevent->fn_ptr);
+               }
+       }
+
+done:
+       tmp = 1;
+       tmp = write(epoll_stop_fd, &tmp, sizeof(tmp));
+
+       return NULL;
+}
+
+static int ioeventfd__start(void)
+{
+       pthread_t thread;
+
+       if (!ioeventfd_avail)
+               return -ENOSYS;
+
+       return pthread_create(&thread, NULL, ioeventfd__thread, NULL);
+}
+
+int ioeventfd__init(struct kvm *kvm)
+{
+       struct epoll_event epoll_event = {.events = EPOLLIN};
+       int r;
+
+       ioeventfd_avail = kvm__supports_extension(kvm, KVM_CAP_IOEVENTFD);
+       if (!ioeventfd_avail)
+               return 1; /* Not fatal, but let caller determine no-go. */
+
+       epoll_fd = epoll_create(IOEVENTFD_MAX_EVENTS);
+       if (epoll_fd < 0)
+               return -errno;
+
+       epoll_stop_fd = eventfd(0, 0);
+       epoll_event.data.fd = epoll_stop_fd;
+
+       r = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, epoll_stop_fd, &epoll_event);
+       if (r < 0)
+               goto cleanup;
+
+       r = ioeventfd__start();
+       if (r < 0)
+               goto cleanup;
+
+       r = 0;
+
+       return r;
+
+cleanup:
+       close(epoll_stop_fd);
+       close(epoll_fd);
+
+       return r;
+}
+
+int ioeventfd__exit(struct kvm *kvm)
+{
+       u64 tmp = 1;
+       int r;
+
+       if (!ioeventfd_avail)
+               return 0;
+
+       r = write(epoll_stop_fd, &tmp, sizeof(tmp));
+       if (r < 0)
+               return r;
+
+       r = read(epoll_stop_fd, &tmp, sizeof(tmp));
+       if (r < 0)
+               return r;
+
+       close(epoll_fd);
+       close(epoll_stop_fd);
+
+       return 0;
+}
+
+int ioeventfd__add_event(struct ioevent *ioevent, bool is_pio, bool poll_in_userspace)
+{
+       struct kvm_ioeventfd kvm_ioevent;
+       struct epoll_event epoll_event;
+       struct ioevent *new_ioevent;
+       int event, r;
+
+       if (!ioeventfd_avail)
+               return -ENOSYS;
+
+       new_ioevent = malloc(sizeof(*new_ioevent));
+       if (new_ioevent == NULL)
+               return -ENOMEM;
+
+       *new_ioevent = *ioevent;
+       event = new_ioevent->fd;
+
+       kvm_ioevent = (struct kvm_ioeventfd) {
+               .addr           = ioevent->io_addr,
+               .len            = ioevent->io_len,
+               .datamatch      = ioevent->datamatch,
+               .fd             = event,
+               .flags          = KVM_IOEVENTFD_FLAG_DATAMATCH,
+       };
+
+       if (is_pio)
+               kvm_ioevent.flags |= KVM_IOEVENTFD_FLAG_PIO;
+
+       r = ioctl(ioevent->fn_kvm->vm_fd, KVM_IOEVENTFD, &kvm_ioevent);
+       if (r) {
+               r = -errno;
+               goto cleanup;
+       }
+
+       if (!poll_in_userspace)
+               return 0;
+
+       epoll_event = (struct epoll_event) {
+               .events         = EPOLLIN,
+               .data.ptr       = new_ioevent,
+       };
+
+       r = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, event, &epoll_event);
+       if (r) {
+               r = -errno;
+               goto cleanup;
+       }
+
+       list_add_tail(&new_ioevent->list, &used_ioevents);
+
+       return 0;
+
+cleanup:
+       free(new_ioevent);
+       return r;
+}
+
+int ioeventfd__del_event(u64 addr, u64 datamatch)
+{
+       struct kvm_ioeventfd kvm_ioevent;
+       struct ioevent *ioevent;
+       u8 found = 0;
+
+       if (!ioeventfd_avail)
+               return -ENOSYS;
+
+       list_for_each_entry(ioevent, &used_ioevents, list) {
+               if (ioevent->io_addr == addr) {
+                       found = 1;
+                       break;
+               }
+       }
+
+       if (found == 0 || ioevent == NULL)
+               return -ENOENT;
+
+       kvm_ioevent = (struct kvm_ioeventfd) {
+               .addr                   = ioevent->io_addr,
+               .len                    = ioevent->io_len,
+               .datamatch              = ioevent->datamatch,
+               .flags                  = KVM_IOEVENTFD_FLAG_PIO
+                                       | KVM_IOEVENTFD_FLAG_DEASSIGN
+                                       | KVM_IOEVENTFD_FLAG_DATAMATCH,
+       };
+
+       ioctl(ioevent->fn_kvm->vm_fd, KVM_IOEVENTFD, &kvm_ioevent);
+
+       epoll_ctl(epoll_fd, EPOLL_CTL_DEL, ioevent->fd, NULL);
+
+       list_del(&ioevent->list);
+
+       close(ioevent->fd);
+       free(ioevent);
+
+       return 0;
+}
diff --git a/tools/kvm/ioport.c b/tools/kvm/ioport.c
new file mode 100644 (file)
index 0000000..662a78b
--- /dev/null
@@ -0,0 +1,195 @@
+#include "kvm/ioport.h"
+
+#include "kvm/kvm.h"
+#include "kvm/util.h"
+#include "kvm/brlock.h"
+#include "kvm/rbtree-interval.h"
+#include "kvm/mutex.h"
+
+#include <linux/kvm.h> /* for KVM_EXIT_* */
+#include <linux/types.h>
+
+#include <stdbool.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define ioport_node(n) rb_entry(n, struct ioport, node)
+
+DEFINE_MUTEX(ioport_mutex);
+
+static u16                     free_io_port_idx; /* protected by ioport_mutex */
+
+static struct rb_root          ioport_tree = RB_ROOT;
+bool                           ioport_debug;
+
+static u16 ioport__find_free_port(void)
+{
+       u16 free_port;
+
+       mutex_lock(&ioport_mutex);
+       free_port = IOPORT_START + free_io_port_idx * IOPORT_SIZE;
+       free_io_port_idx++;
+       mutex_unlock(&ioport_mutex);
+
+       return free_port;
+}
+
+static struct ioport *ioport_search(struct rb_root *root, u64 addr)
+{
+       struct rb_int_node *node;
+
+       node = rb_int_search_single(root, addr);
+       if (node == NULL)
+               return NULL;
+
+       return ioport_node(node);
+}
+
+static int ioport_insert(struct rb_root *root, struct ioport *data)
+{
+       return rb_int_insert(root, &data->node);
+}
+
+static void ioport_remove(struct rb_root *root, struct ioport *data)
+{
+       rb_int_erase(root, &data->node);
+}
+
+int ioport__register(u16 port, struct ioport_operations *ops, int count, void *param)
+{
+       struct ioport *entry;
+       int r;
+
+       br_write_lock();
+       if (port == IOPORT_EMPTY)
+               port = ioport__find_free_port();
+
+       entry = ioport_search(&ioport_tree, port);
+       if (entry) {
+               pr_warning("ioport re-registered: %x", port);
+               rb_int_erase(&ioport_tree, &entry->node);
+       }
+
+       entry = malloc(sizeof(*entry));
+       if (entry == NULL)
+               return -ENOMEM;
+
+       *entry = (struct ioport) {
+               .node   = RB_INT_INIT(port, port + count),
+               .ops    = ops,
+               .priv   = param,
+       };
+
+       r = ioport_insert(&ioport_tree, entry);
+       if (r < 0) {
+               free(entry);
+               br_write_unlock();
+               return r;
+       }
+       br_write_unlock();
+
+       return port;
+}
+
+int ioport__unregister(u16 port)
+{
+       struct ioport *entry;
+       int r;
+
+       br_write_lock();
+
+       r = -ENOENT;
+       entry = ioport_search(&ioport_tree, port);
+       if (!entry)
+               goto done;
+
+       ioport_remove(&ioport_tree, entry);
+
+       free(entry);
+
+       r = 0;
+
+done:
+       br_write_unlock();
+
+       return r;
+}
+
+static void ioport__unregister_all(void)
+{
+       struct ioport *entry;
+       struct rb_node *rb;
+       struct rb_int_node *rb_node;
+
+       rb = rb_first(&ioport_tree);
+       while (rb) {
+               rb_node = rb_int(rb);
+               entry = ioport_node(rb_node);
+               ioport_remove(&ioport_tree, entry);
+               free(entry);
+               rb = rb_first(&ioport_tree);
+       }
+}
+
+static const char *to_direction(int direction)
+{
+       if (direction == KVM_EXIT_IO_IN)
+               return "IN";
+       else
+               return "OUT";
+}
+
+static void ioport_error(u16 port, void *data, int direction, int size, u32 count)
+{
+       fprintf(stderr, "IO error: %s port=%x, size=%d, count=%u\n", to_direction(direction), port, size, count);
+}
+
+bool kvm__emulate_io(struct kvm *kvm, u16 port, void *data, int direction, int size, u32 count)
+{
+       struct ioport_operations *ops;
+       bool ret = false;
+       struct ioport *entry;
+       void *ptr = data;
+
+       br_read_lock();
+       entry = ioport_search(&ioport_tree, port);
+       if (!entry)
+               goto error;
+
+       ops     = entry->ops;
+
+       while (count--) {
+               if (direction == KVM_EXIT_IO_IN && ops->io_in)
+                               ret = ops->io_in(entry, kvm, port, ptr, size);
+               else if (ops->io_out)
+                               ret = ops->io_out(entry, kvm, port, ptr, size);
+
+               ptr += size;
+       }
+
+       br_read_unlock();
+
+       if (!ret)
+               goto error;
+
+       return true;
+error:
+       br_read_unlock();
+
+       if (ioport_debug)
+               ioport_error(port, data, direction, size, count);
+
+       return !ioport_debug;
+}
+
+int ioport__init(struct kvm *kvm)
+{
+       return 0;
+}
+
+int ioport__exit(struct kvm *kvm)
+{
+       ioport__unregister_all();
+       return 0;
+}
diff --git a/tools/kvm/kvm-cmd.c b/tools/kvm/kvm-cmd.c
new file mode 100644 (file)
index 0000000..2520b08
--- /dev/null
@@ -0,0 +1,91 @@
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+/* user defined header files */
+#include "kvm/builtin-debug.h"
+#include "kvm/builtin-pause.h"
+#include "kvm/builtin-resume.h"
+#include "kvm/builtin-balloon.h"
+#include "kvm/builtin-list.h"
+#include "kvm/builtin-version.h"
+#include "kvm/builtin-setup.h"
+#include "kvm/builtin-stop.h"
+#include "kvm/builtin-stat.h"
+#include "kvm/builtin-help.h"
+#include "kvm/builtin-sandbox.h"
+#include "kvm/kvm-cmd.h"
+#include "kvm/builtin-run.h"
+#include "kvm/util.h"
+
+struct cmd_struct kvm_commands[] = {
+       { "pause",      kvm_cmd_pause,          kvm_pause_help,         0 },
+       { "resume",     kvm_cmd_resume,         kvm_resume_help,        0 },
+       { "debug",      kvm_cmd_debug,          kvm_debug_help,         0 },
+       { "balloon",    kvm_cmd_balloon,        kvm_balloon_help,       0 },
+       { "list",       kvm_cmd_list,           kvm_list_help,          0 },
+       { "version",    kvm_cmd_version,        NULL,                   0 },
+       { "--version",  kvm_cmd_version,        NULL,                   0 },
+       { "stop",       kvm_cmd_stop,           kvm_stop_help,          0 },
+       { "stat",       kvm_cmd_stat,           kvm_stat_help,          0 },
+       { "help",       kvm_cmd_help,           NULL,                   0 },
+       { "setup",      kvm_cmd_setup,          kvm_setup_help,         0 },
+       { "run",        kvm_cmd_run,            kvm_run_help,           0 },
+       { "sandbox",    kvm_cmd_sandbox,        kvm_run_help,           0 },
+       { NULL,         NULL,                   NULL,                   0 },
+};
+
+/*
+ * kvm_get_command: Searches the command in an array of the commands and
+ * returns a pointer to cmd_struct if a match is found.
+ *
+ * Input parameters:
+ * command: Array of possible commands. The last entry in the array must be
+ *          NULL.
+ * cmd: A string command to search in the array
+ *
+ * Return Value:
+ * NULL: If the cmd is not matched with any of the command in the command array
+ * p: Pointer to cmd_struct of the matching command
+ */
+struct cmd_struct *kvm_get_command(struct cmd_struct *command,
+               const char *cmd)
+{
+       struct cmd_struct *p = command;
+
+       while (p->cmd) {
+               if (!strcmp(p->cmd, cmd))
+                       return p;
+               p++;
+       }
+       return NULL;
+}
+
+int handle_command(struct cmd_struct *command, int argc, const char **argv)
+{
+       struct cmd_struct *p;
+       const char *prefix = NULL;
+       int ret = 0;
+
+       if (!argv || !*argv) {
+               p = kvm_get_command(command, "help");
+               BUG_ON(!p);
+               return p->fn(argc, argv, prefix);
+       }
+
+       p = kvm_get_command(command, argv[0]);
+       if (!p) {
+               p = kvm_get_command(command, "help");
+               BUG_ON(!p);
+               p->fn(0, NULL, prefix);
+               return EINVAL;
+       }
+
+       ret = p->fn(argc - 1, &argv[1], prefix);
+       if (ret < 0) {
+               if (errno == EPERM)
+                       die("Permission error - are you root?");
+       }
+
+       return ret;
+}
diff --git a/tools/kvm/kvm-cpu.c b/tools/kvm/kvm-cpu.c
new file mode 100644 (file)
index 0000000..12791dd
--- /dev/null
@@ -0,0 +1,175 @@
+#include "kvm/kvm-cpu.h"
+
+#include "kvm/symbol.h"
+#include "kvm/util.h"
+#include "kvm/kvm.h"
+
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+
+extern struct kvm_cpu **kvm_cpus;
+extern __thread struct kvm_cpu *current_kvm_cpu;
+
+void kvm_cpu__enable_singlestep(struct kvm_cpu *vcpu)
+{
+       struct kvm_guest_debug debug = {
+               .control        = KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_SINGLESTEP,
+       };
+
+       if (ioctl(vcpu->vcpu_fd, KVM_SET_GUEST_DEBUG, &debug) < 0)
+               pr_warning("KVM_SET_GUEST_DEBUG failed");
+}
+
+void kvm_cpu__run(struct kvm_cpu *vcpu)
+{
+       int err;
+
+       if (!vcpu->is_running)
+               return;
+
+       err = ioctl(vcpu->vcpu_fd, KVM_RUN, 0);
+       if (err < 0 && (errno != EINTR && errno != EAGAIN))
+               die_perror("KVM_RUN failed");
+}
+
+static void kvm_cpu_signal_handler(int signum)
+{
+       if (signum == SIGKVMEXIT) {
+               if (current_kvm_cpu && current_kvm_cpu->is_running) {
+                       current_kvm_cpu->is_running = false;
+                       kvm__continue();
+               }
+       } else if (signum == SIGKVMPAUSE) {
+               current_kvm_cpu->paused = 1;
+       }
+}
+
+static void kvm_cpu__handle_coalesced_mmio(struct kvm_cpu *cpu)
+{
+       if (cpu->ring) {
+               while (cpu->ring->first != cpu->ring->last) {
+                       struct kvm_coalesced_mmio *m;
+                       m = &cpu->ring->coalesced_mmio[cpu->ring->first];
+                       kvm_cpu__emulate_mmio(cpu->kvm,
+                                             m->phys_addr,
+                                             m->data,
+                                             m->len,
+                                             1);
+                       cpu->ring->first = (cpu->ring->first + 1) % KVM_COALESCED_MMIO_MAX;
+               }
+       }
+}
+
+void kvm_cpu__reboot(void)
+{
+       int i;
+
+       /* The kvm_cpus array contains a null pointer in the last location */
+       for (i = 0; ; i++) {
+               if (kvm_cpus[i])
+                       pthread_kill(kvm_cpus[i]->thread, SIGKVMEXIT);
+               else
+                       break;
+       }
+}
+
+int kvm_cpu__start(struct kvm_cpu *cpu)
+{
+       sigset_t sigset;
+
+       sigemptyset(&sigset);
+       sigaddset(&sigset, SIGALRM);
+
+       pthread_sigmask(SIG_BLOCK, &sigset, NULL);
+
+       signal(SIGKVMEXIT, kvm_cpu_signal_handler);
+       signal(SIGKVMPAUSE, kvm_cpu_signal_handler);
+
+       kvm_cpu__reset_vcpu(cpu);
+
+       if (cpu->kvm->single_step)
+               kvm_cpu__enable_singlestep(cpu);
+
+       while (cpu->is_running) {
+               if (cpu->paused) {
+                       kvm__notify_paused();
+                       cpu->paused = 0;
+               }
+
+               if (cpu->needs_nmi) {
+                       kvm_cpu__arch_nmi(cpu);
+                       cpu->needs_nmi = 0;
+               }
+
+               kvm_cpu__run(cpu);
+
+               switch (cpu->kvm_run->exit_reason) {
+               case KVM_EXIT_UNKNOWN:
+                       break;
+               case KVM_EXIT_DEBUG:
+                       kvm_cpu__show_registers(cpu);
+                       kvm_cpu__show_code(cpu);
+                       break;
+               case KVM_EXIT_IO: {
+                       bool ret;
+
+                       ret = kvm_cpu__emulate_io(cpu->kvm,
+                                                 cpu->kvm_run->io.port,
+                                                 (u8 *)cpu->kvm_run +
+                                                 cpu->kvm_run->io.data_offset,
+                                                 cpu->kvm_run->io.direction,
+                                                 cpu->kvm_run->io.size,
+                                                 cpu->kvm_run->io.count);
+
+                       if (!ret)
+                               goto panic_kvm;
+                       break;
+               }
+               case KVM_EXIT_MMIO: {
+                       bool ret;
+
+                       /*
+                        * If we had MMIO exit, coalesced ring should be processed
+                        * *before* processing the exit itself
+                        */
+                       kvm_cpu__handle_coalesced_mmio(cpu);
+
+                       ret = kvm_cpu__emulate_mmio(cpu->kvm,
+                                                   cpu->kvm_run->mmio.phys_addr,
+                                                   cpu->kvm_run->mmio.data,
+                                                   cpu->kvm_run->mmio.len,
+                                                   cpu->kvm_run->mmio.is_write);
+
+                       if (!ret)
+                               goto panic_kvm;
+                       break;
+               }
+               case KVM_EXIT_INTR:
+                       if (cpu->is_running)
+                               break;
+                       goto exit_kvm;
+               case KVM_EXIT_SHUTDOWN:
+                       goto exit_kvm;
+               default: {
+                       bool ret;
+
+                       ret = kvm_cpu__handle_exit(cpu);
+                       if (!ret)
+                               goto panic_kvm;
+                       break;
+               }
+               }
+               kvm_cpu__handle_coalesced_mmio(cpu);
+       }
+
+exit_kvm:
+       return 0;
+
+panic_kvm:
+       return 1;
+}
diff --git a/tools/kvm/kvm-ipc.c b/tools/kvm/kvm-ipc.c
new file mode 100644 (file)
index 0000000..70831b8
--- /dev/null
@@ -0,0 +1,231 @@
+#include "kvm/kvm-ipc.h"
+#include "kvm/rwsem.h"
+#include "kvm/read-write.h"
+#include "kvm/util.h"
+
+#include <sys/epoll.h>
+#include <sys/un.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/eventfd.h>
+
+struct kvm_ipc_head {
+       u32 type;
+       u32 len;
+};
+
+#define KVM_IPC_MAX_MSGS 16
+
+static void (*msgs[KVM_IPC_MAX_MSGS])(int fd, u32 type, u32 len, u8 *msg);
+static DECLARE_RWSEM(msgs_rwlock);
+static int epoll_fd, server_fd, stop_fd;
+static pthread_t thread;
+
+int kvm_ipc__register_handler(u32 type, void (*cb)(int fd, u32 type, u32 len, u8 *msg))
+{
+       if (type >= KVM_IPC_MAX_MSGS)
+               return -ENOSPC;
+
+       down_write(&msgs_rwlock);
+       msgs[type] = cb;
+       up_write(&msgs_rwlock);
+
+       return 0;
+}
+
+int kvm_ipc__send(int fd, u32 type)
+{
+       struct kvm_ipc_head head = {.type = type, .len = 0,};
+
+       if (write_in_full(fd, &head, sizeof(head)) < 0)
+               return -1;
+
+       return 0;
+}
+
+int kvm_ipc__send_msg(int fd, u32 type, u32 len, u8 *msg)
+{
+       struct kvm_ipc_head head = {.type = type, .len = len,};
+
+       if (write_in_full(fd, &head, sizeof(head)) < 0)
+               return -1;
+
+       if (write_in_full(fd, msg, len) < 0)
+               return -1;
+
+       return 0;
+}
+
+static int kvm_ipc__handle(int fd, u32 type, u32 len, u8 *data)
+{
+       void (*cb)(int fd, u32 type, u32 len, u8 *msg);
+
+       if (type >= KVM_IPC_MAX_MSGS)
+               return -ENOSPC;
+
+       down_read(&msgs_rwlock);
+       cb = msgs[type];
+       up_read(&msgs_rwlock);
+
+       if (cb == NULL) {
+               pr_warning("No device handles type %u\n", type);
+               return -ENODEV;
+       }
+
+       cb(fd, type, len, data);
+
+       return 0;
+}
+
+static int kvm_ipc__new_conn(int fd)
+{
+       int client;
+       struct epoll_event ev;
+
+       client = accept(fd, NULL, NULL);
+       if (client < 0)
+               return -1;
+
+       ev.events = EPOLLIN | EPOLLRDHUP;
+       ev.data.fd = client;
+       if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client, &ev) < 0) {
+               close(client);
+               return -1;
+       }
+
+       return client;
+}
+
+static void kvm_ipc__close_conn(int fd)
+{
+       epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, NULL);
+       close(fd);
+}
+
+static int kvm_ipc__receive(int fd)
+{
+       struct kvm_ipc_head head;
+       u8 *msg = NULL;
+       u32 n;
+
+       n = read(fd, &head, sizeof(head));
+       if (n != sizeof(head))
+               goto done;
+
+       msg = malloc(head.len);
+       if (msg == NULL)
+               goto done;
+
+       n = read_in_full(fd, msg, head.len);
+       if (n != head.len)
+               goto done;
+
+       kvm_ipc__handle(fd, head.type, head.len, msg);
+
+       return 0;
+
+done:
+       free(msg);
+       return -1;
+}
+
+static void *kvm_ipc__thread(void *param)
+{
+       struct epoll_event event;
+
+       for (;;) {
+               int nfds;
+
+               nfds = epoll_wait(epoll_fd, &event, 1, -1);
+               if (nfds > 0) {
+                       int fd = event.data.fd;
+
+                       if (fd == stop_fd && event.events & EPOLLIN) {
+                               break;
+                       } else if (fd == server_fd) {
+                               int client, r;
+
+                               client = kvm_ipc__new_conn(fd);
+                               /*
+                                * Handle multiple IPC cmd at a time
+                                */
+                               do {
+                                       r = kvm_ipc__receive(client);
+                               } while (r == 0);
+
+                       } else if (event.events & (EPOLLERR | EPOLLRDHUP | EPOLLHUP)) {
+                               kvm_ipc__close_conn(fd);
+                       } else {
+                               kvm_ipc__receive(fd);
+                       }
+               }
+       }
+
+       return NULL;
+}
+
+int kvm_ipc__start(int sock)
+{
+       int ret;
+       struct epoll_event ev = {0};
+
+       server_fd = sock;
+
+       epoll_fd = epoll_create(KVM_IPC_MAX_MSGS);
+       if (epoll_fd < 0) {
+               ret = epoll_fd;
+               goto err;
+       }
+
+       ev.events = EPOLLIN | EPOLLET;
+       ev.data.fd = sock;
+       if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sock, &ev) < 0) {
+               pr_err("Failed starting IPC thread");
+               ret = -EFAULT;
+               goto err_epoll;
+       }
+
+       stop_fd = eventfd(0, 0);
+       if (stop_fd < 0) {
+               ret = stop_fd;
+               goto err_epoll;
+       }
+
+       ev.events = EPOLLIN | EPOLLET;
+       ev.data.fd = stop_fd;
+       if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, stop_fd, &ev) < 0) {
+               pr_err("Failed adding stop event to epoll");
+               ret = -EFAULT;
+               goto err_stop;
+       }
+
+       if (pthread_create(&thread, NULL, kvm_ipc__thread, NULL) != 0) {
+               pr_err("Failed starting IPC thread");
+               ret = -EFAULT;
+               goto err_stop;
+       }
+
+       return 0;
+
+err_stop:
+       close(stop_fd);
+err_epoll:
+       close(epoll_fd);
+err:
+       return ret;
+}
+
+int kvm_ipc__stop(void)
+{
+       u64 val = 1;
+       int ret;
+
+       ret = write(stop_fd, &val, sizeof(val));
+       if (ret < 0)
+               return ret;
+
+       close(server_fd);
+       close(epoll_fd);
+
+       return ret;
+}
diff --git a/tools/kvm/kvm.c b/tools/kvm/kvm.c
new file mode 100644 (file)
index 0000000..64d8b51
--- /dev/null
@@ -0,0 +1,593 @@
+#include "kvm/kvm.h"
+#include "kvm/read-write.h"
+#include "kvm/util.h"
+#include "kvm/strbuf.h"
+#include "kvm/mutex.h"
+#include "kvm/kvm-cpu.h"
+#include "kvm/kvm-ipc.h"
+
+#include <linux/kvm.h>
+#include <linux/err.h>
+
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <stdbool.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/eventfd.h>
+#include <asm/unistd.h>
+#include <dirent.h>
+
+#define DEFINE_KVM_EXIT_REASON(reason) [reason] = #reason
+
+const char *kvm_exit_reasons[] = {
+       DEFINE_KVM_EXIT_REASON(KVM_EXIT_UNKNOWN),
+       DEFINE_KVM_EXIT_REASON(KVM_EXIT_EXCEPTION),
+       DEFINE_KVM_EXIT_REASON(KVM_EXIT_IO),
+       DEFINE_KVM_EXIT_REASON(KVM_EXIT_HYPERCALL),
+       DEFINE_KVM_EXIT_REASON(KVM_EXIT_DEBUG),
+       DEFINE_KVM_EXIT_REASON(KVM_EXIT_HLT),
+       DEFINE_KVM_EXIT_REASON(KVM_EXIT_MMIO),
+       DEFINE_KVM_EXIT_REASON(KVM_EXIT_IRQ_WINDOW_OPEN),
+       DEFINE_KVM_EXIT_REASON(KVM_EXIT_SHUTDOWN),
+       DEFINE_KVM_EXIT_REASON(KVM_EXIT_FAIL_ENTRY),
+       DEFINE_KVM_EXIT_REASON(KVM_EXIT_INTR),
+       DEFINE_KVM_EXIT_REASON(KVM_EXIT_SET_TPR),
+       DEFINE_KVM_EXIT_REASON(KVM_EXIT_TPR_ACCESS),
+       DEFINE_KVM_EXIT_REASON(KVM_EXIT_S390_SIEIC),
+       DEFINE_KVM_EXIT_REASON(KVM_EXIT_S390_RESET),
+       DEFINE_KVM_EXIT_REASON(KVM_EXIT_DCR),
+       DEFINE_KVM_EXIT_REASON(KVM_EXIT_NMI),
+       DEFINE_KVM_EXIT_REASON(KVM_EXIT_INTERNAL_ERROR),
+#ifdef CONFIG_PPC64
+       DEFINE_KVM_EXIT_REASON(KVM_EXIT_PAPR_HCALL),
+#endif
+};
+
+extern struct kvm *kvm;
+extern struct kvm_cpu **kvm_cpus;
+static int pause_event;
+static DEFINE_MUTEX(pause_lock);
+extern struct kvm_ext kvm_req_ext[];
+
+static char kvm_dir[PATH_MAX];
+
+static int set_dir(const char *fmt, va_list args)
+{
+       char tmp[PATH_MAX];
+
+       vsnprintf(tmp, sizeof(tmp), fmt, args);
+
+       mkdir(tmp, 0777);
+
+       if (!realpath(tmp, kvm_dir))
+               return -errno;
+
+       strcat(kvm_dir, "/");
+
+       return 0;
+}
+
+void kvm__set_dir(const char *fmt, ...)
+{
+       va_list args;
+
+       va_start(args, fmt);
+       set_dir(fmt, args);
+       va_end(args);
+}
+
+const char *kvm__get_dir(void)
+{
+       return kvm_dir;
+}
+
+bool kvm__supports_extension(struct kvm *kvm, unsigned int extension)
+{
+       int ret;
+
+       ret = ioctl(kvm->sys_fd, KVM_CHECK_EXTENSION, extension);
+       if (ret < 0)
+               return false;
+
+       return ret;
+}
+
+static int kvm__check_extensions(struct kvm *kvm)
+{
+       int i;
+
+       for (i = 0; ; i++) {
+               if (!kvm_req_ext[i].name)
+                       break;
+               if (!kvm__supports_extension(kvm, kvm_req_ext[i].code)) {
+                       pr_err("Unsuppored KVM extension detected: %s",
+                               kvm_req_ext[i].name);
+                       return -i;
+               }
+       }
+
+       return 0;
+}
+
+static struct kvm *kvm__new(void)
+{
+       struct kvm *kvm = calloc(1, sizeof(*kvm));
+       if (!kvm)
+               return ERR_PTR(-ENOMEM);
+
+       kvm->sys_fd = -1;
+       kvm->vm_fd = -1;
+
+       return kvm;
+}
+
+#define KVM_SOCK_SUFFIX                ".sock"
+#define KVM_SOCK_SUFFIX_LEN    ((ssize_t)sizeof(KVM_SOCK_SUFFIX) - 1)
+
+static int kvm__create_socket(struct kvm *kvm)
+{
+       char full_name[PATH_MAX];
+       unsigned int s;
+       struct sockaddr_un local;
+       int len, r;
+
+       /* This usually 108 bytes long */
+       BUILD_BUG_ON(sizeof(local.sun_path) < 32);
+
+       if (!kvm->name)
+               return -EINVAL;
+
+       snprintf(full_name, sizeof(full_name), "%s/%s%s",
+                kvm__get_dir(), kvm->name, KVM_SOCK_SUFFIX);
+       if (access(full_name, F_OK) == 0) {
+               pr_err("Socket file %s already exist", full_name);
+               return -EEXIST;
+       }
+
+       s = socket(AF_UNIX, SOCK_STREAM, 0);
+       if (s < 0)
+               return s;
+       local.sun_family = AF_UNIX;
+       strlcpy(local.sun_path, full_name, sizeof(local.sun_path));
+       len = strlen(local.sun_path) + sizeof(local.sun_family);
+       r = bind(s, (struct sockaddr *)&local, len);
+       if (r < 0)
+               goto fail;
+
+       r = listen(s, 5);
+       if (r < 0)
+               goto fail;
+
+       return s;
+
+fail:
+       close(s);
+       return r;
+}
+
+void kvm__remove_socket(const char *name)
+{
+       char full_name[PATH_MAX];
+
+       snprintf(full_name, sizeof(full_name), "%s/%s%s",
+                kvm__get_dir(), name, KVM_SOCK_SUFFIX);
+       unlink(full_name);
+}
+
+int kvm__get_sock_by_instance(const char *name)
+{
+       int s, len, r;
+       char sock_file[PATH_MAX];
+       struct sockaddr_un local;
+
+       snprintf(sock_file, sizeof(sock_file), "%s/%s%s",
+                kvm__get_dir(), name, KVM_SOCK_SUFFIX);
+       s = socket(AF_UNIX, SOCK_STREAM, 0);
+
+       local.sun_family = AF_UNIX;
+       strlcpy(local.sun_path, sock_file, sizeof(local.sun_path));
+       len = strlen(local.sun_path) + sizeof(local.sun_family);
+
+       r = connect(s, &local, len);
+       if (r < 0 && errno == ECONNREFUSED) {
+               /* Tell the user clean ghost socket file */
+               pr_err("\"%s\" could be a ghost socket file, please remove it",
+                               sock_file);
+               return r;
+       } else if (r < 0) {
+               return r;
+       }
+
+       return s;
+}
+
+int kvm__enumerate_instances(int (*callback)(const char *name, int fd))
+{
+       int sock;
+       DIR *dir;
+       struct dirent entry, *result;
+       int ret = 0;
+
+       dir = opendir(kvm__get_dir());
+       if (!dir)
+               return -errno;
+
+       for (;;) {
+               readdir_r(dir, &entry, &result);
+               if (result == NULL)
+                       break;
+               if (entry.d_type == DT_SOCK) {
+                       ssize_t name_len = strlen(entry.d_name);
+                       char *p;
+
+                       if (name_len <= KVM_SOCK_SUFFIX_LEN)
+                               continue;
+
+                       p = &entry.d_name[name_len - KVM_SOCK_SUFFIX_LEN];
+                       if (memcmp(KVM_SOCK_SUFFIX, p, KVM_SOCK_SUFFIX_LEN))
+                               continue;
+
+                       *p = 0;
+                       sock = kvm__get_sock_by_instance(entry.d_name);
+                       if (sock < 0)
+                               continue;
+                       ret = callback(entry.d_name, sock);
+                       close(sock);
+                       if (ret < 0)
+                               break;
+               }
+       }
+
+       closedir(dir);
+
+       return ret;
+}
+
+int kvm__exit(struct kvm *kvm)
+{
+       kvm__stop_timer(kvm);
+
+       kvm__arch_delete_ram(kvm);
+       kvm_ipc__stop();
+       kvm__remove_socket(kvm->name);
+       free(kvm->name);
+       free(kvm);
+
+       return 0;
+}
+
+/*
+ * Note: KVM_SET_USER_MEMORY_REGION assumes that we don't pass overlapping
+ * memory regions to it. Therefore, be careful if you use this function for
+ * registering memory regions for emulating hardware.
+ */
+int kvm__register_mem(struct kvm *kvm, u64 guest_phys, u64 size, void *userspace_addr)
+{
+       struct kvm_userspace_memory_region mem;
+       int ret;
+
+       mem = (struct kvm_userspace_memory_region) {
+               .slot                   = kvm->mem_slots++,
+               .guest_phys_addr        = guest_phys,
+               .memory_size            = size,
+               .userspace_addr         = (unsigned long)userspace_addr,
+       };
+
+       ret = ioctl(kvm->vm_fd, KVM_SET_USER_MEMORY_REGION, &mem);
+       if (ret < 0)
+               return -errno;
+
+       return 0;
+}
+
+int kvm__recommended_cpus(struct kvm *kvm)
+{
+       int ret;
+
+       ret = ioctl(kvm->sys_fd, KVM_CHECK_EXTENSION, KVM_CAP_NR_VCPUS);
+       if (ret <= 0)
+               /*
+                * api.txt states that if KVM_CAP_NR_VCPUS does not exist,
+                * assume 4.
+                */
+               return 4;
+
+       return ret;
+}
+
+static void kvm__pid(int fd, u32 type, u32 len, u8 *msg)
+{
+       pid_t pid = getpid();
+       int r = 0;
+
+       if (type == KVM_IPC_PID)
+               r = write(fd, &pid, sizeof(pid));
+
+       if (r < 0)
+               pr_warning("Failed sending PID");
+}
+
+/*
+ * The following hack should be removed once 'x86: Raise the hard
+ * VCPU count limit' makes it's way into the mainline.
+ */
+#ifndef KVM_CAP_MAX_VCPUS
+#define KVM_CAP_MAX_VCPUS 66
+#endif
+
+int kvm__max_cpus(struct kvm *kvm)
+{
+       int ret;
+
+       ret = ioctl(kvm->sys_fd, KVM_CHECK_EXTENSION, KVM_CAP_MAX_VCPUS);
+       if (ret <= 0)
+               ret = kvm__recommended_cpus(kvm);
+
+       return ret;
+}
+
+struct kvm *kvm__init(const char *kvm_dev, const char *hugetlbfs_path, u64 ram_size, const char *name)
+{
+       struct kvm *kvm;
+       int ret;
+
+       if (!kvm__arch_cpu_supports_vm()) {
+               pr_err("Your CPU does not support hardware virtualization");
+               ret = -ENOSYS;
+               goto err;
+       }
+
+       kvm = kvm__new();
+       if (IS_ERR(kvm))
+               return kvm;
+
+       kvm->sys_fd = open(kvm_dev, O_RDWR);
+       if (kvm->sys_fd < 0) {
+               if (errno == ENOENT)
+                       pr_err("'%s' not found. Please make sure your kernel has CONFIG_KVM "
+                              "enabled and that the KVM modules are loaded.", kvm_dev);
+               else if (errno == ENODEV)
+                       pr_err("'%s' KVM driver not available.\n  # (If the KVM "
+                              "module is loaded then 'dmesg' may offer further clues "
+                              "about the failure.)", kvm_dev);
+               else
+                       pr_err("Could not open %s: ", kvm_dev);
+
+               ret = -errno;
+               goto err_free;
+       }
+
+       ret = ioctl(kvm->sys_fd, KVM_GET_API_VERSION, 0);
+       if (ret != KVM_API_VERSION) {
+               pr_err("KVM_API_VERSION ioctl");
+               ret = -errno;
+               goto err_sys_fd;
+       }
+
+       kvm->vm_fd = ioctl(kvm->sys_fd, KVM_CREATE_VM, 0);
+       if (kvm->vm_fd < 0) {
+               ret = kvm->vm_fd;
+               goto err_sys_fd;
+       }
+
+       kvm->name = strdup(name);
+       if (!kvm->name) {
+               ret = -ENOMEM;
+               goto err_vm_fd;
+       }
+
+       if (kvm__check_extensions(kvm)) {
+               pr_err("A required KVM extention is not supported by OS");
+               ret = -ENOSYS;
+               goto err_vm_fd;
+       }
+
+       kvm__arch_init(kvm, hugetlbfs_path, ram_size);
+
+       ret = kvm_ipc__start(kvm__create_socket(kvm));
+       if (ret < 0) {
+               pr_err("Starting ipc failed.");
+               goto err_vm_fd;
+       }
+
+       ret = kvm_ipc__register_handler(KVM_IPC_PID, kvm__pid);
+       if (ret < 0) {
+               pr_err("Register ipc handler failed.");
+               goto err_ipc;
+       }
+
+       return kvm;
+
+err_ipc:
+       kvm_ipc__stop();
+err_vm_fd:
+       close(kvm->vm_fd);
+err_sys_fd:
+       close(kvm->sys_fd);
+err_free:
+       free(kvm);
+err:
+       return ERR_PTR(ret);
+}
+
+/* RFC 1952 */
+#define GZIP_ID1               0x1f
+#define GZIP_ID2               0x8b
+#define CPIO_MAGIC             "0707"
+/* initrd may be gzipped, or a plain cpio */
+static bool initrd_check(int fd)
+{
+       unsigned char id[4];
+
+       if (read_in_full(fd, id, ARRAY_SIZE(id)) < 0)
+               return false;
+
+       if (lseek(fd, 0, SEEK_SET) < 0)
+               die_perror("lseek");
+
+       return (id[0] == GZIP_ID1 && id[1] == GZIP_ID2) ||
+               !memcmp(id, CPIO_MAGIC, 4);
+}
+
+bool kvm__load_kernel(struct kvm *kvm, const char *kernel_filename,
+               const char *initrd_filename, const char *kernel_cmdline, u16 vidmode)
+{
+       bool ret;
+       int fd_kernel = -1, fd_initrd = -1;
+
+       fd_kernel = open(kernel_filename, O_RDONLY);
+       if (fd_kernel < 0)
+               die("Unable to open kernel %s", kernel_filename);
+
+       if (initrd_filename) {
+               fd_initrd = open(initrd_filename, O_RDONLY);
+               if (fd_initrd < 0)
+                       die("Unable to open initrd %s", initrd_filename);
+
+               if (!initrd_check(fd_initrd))
+                       die("%s is not an initrd", initrd_filename);
+       }
+
+       ret = load_bzimage(kvm, fd_kernel, fd_initrd, kernel_cmdline, vidmode);
+
+       if (ret)
+               goto found_kernel;
+
+       pr_warning("%s is not a bzImage. Trying to load it as a flat binary...", kernel_filename);
+
+       ret = load_flat_binary(kvm, fd_kernel, fd_initrd, kernel_cmdline);
+
+       if (ret)
+               goto found_kernel;
+
+       if (initrd_filename)
+               close(fd_initrd);
+       close(fd_kernel);
+
+       die("%s is not a valid bzImage or flat binary", kernel_filename);
+
+found_kernel:
+       if (initrd_filename)
+               close(fd_initrd);
+       close(fd_kernel);
+
+       return ret;
+}
+
+#define TIMER_INTERVAL_NS 1000000      /* 1 msec */
+
+/*
+ * This function sets up a timer that's used to inject interrupts from the
+ * userspace hypervisor into the guest at periodical intervals. Please note
+ * that clock interrupt, for example, is not handled here.
+ */
+void kvm__start_timer(struct kvm *kvm)
+{
+       struct itimerspec its;
+       struct sigevent sev;
+
+       memset(&sev, 0, sizeof(struct sigevent));
+       sev.sigev_value.sival_int       = 0;
+       sev.sigev_notify                = SIGEV_THREAD_ID;
+       sev.sigev_signo                 = SIGALRM;
+       sev._sigev_un._tid              = syscall(__NR_gettid);
+
+       if (timer_create(CLOCK_REALTIME, &sev, &kvm->timerid) < 0)
+               die("timer_create()");
+
+       its.it_value.tv_sec             = TIMER_INTERVAL_NS / 1000000000;
+       its.it_value.tv_nsec            = TIMER_INTERVAL_NS % 1000000000;
+       its.it_interval.tv_sec          = its.it_value.tv_sec;
+       its.it_interval.tv_nsec         = its.it_value.tv_nsec;
+
+       if (timer_settime(kvm->timerid, 0, &its, NULL) < 0)
+               die("timer_settime()");
+}
+
+void kvm__stop_timer(struct kvm *kvm)
+{
+       if (kvm->timerid)
+               if (timer_delete(kvm->timerid) < 0)
+                       die("timer_delete()");
+
+       kvm->timerid = 0;
+}
+
+void kvm__dump_mem(struct kvm *kvm, unsigned long addr, unsigned long size)
+{
+       unsigned char *p;
+       unsigned long n;
+
+       size &= ~7; /* mod 8 */
+       if (!size)
+               return;
+
+       p = guest_flat_to_host(kvm, addr);
+
+       for (n = 0; n < size; n += 8) {
+               if (!host_ptr_in_ram(kvm, p + n))
+                       break;
+
+               printf("  0x%08lx: %02x %02x %02x %02x  %02x %02x %02x %02x\n",
+                       addr + n, p[n + 0], p[n + 1], p[n + 2], p[n + 3],
+                                 p[n + 4], p[n + 5], p[n + 6], p[n + 7]);
+       }
+}
+
+void kvm__pause(void)
+{
+       int i, paused_vcpus = 0;
+
+       /* Check if the guest is running */
+       if (!kvm_cpus[0] || kvm_cpus[0]->thread == 0)
+               return;
+
+       mutex_lock(&pause_lock);
+
+       pause_event = eventfd(0, 0);
+       if (pause_event < 0)
+               die("Failed creating pause notification event");
+       for (i = 0; i < kvm->nrcpus; i++)
+               pthread_kill(kvm_cpus[i]->thread, SIGKVMPAUSE);
+
+       while (paused_vcpus < kvm->nrcpus) {
+               u64 cur_read;
+
+               if (read(pause_event, &cur_read, sizeof(cur_read)) < 0)
+                       die("Failed reading pause event");
+               paused_vcpus += cur_read;
+       }
+       close(pause_event);
+}
+
+void kvm__continue(void)
+{
+       /* Check if the guest is running */
+       if (!kvm_cpus[0] || kvm_cpus[0]->thread == 0)
+               return;
+
+       mutex_unlock(&pause_lock);
+}
+
+void kvm__notify_paused(void)
+{
+       u64 p = 1;
+
+       if (write(pause_event, &p, sizeof(p)) < 0)
+               die("Failed notifying of paused VCPU.");
+
+       mutex_lock(&pause_lock);
+       mutex_unlock(&pause_lock);
+}
diff --git a/tools/kvm/main.c b/tools/kvm/main.c
new file mode 100644 (file)
index 0000000..05bc82c
--- /dev/null
@@ -0,0 +1,19 @@
+#include "kvm/kvm.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+/* user defined header files */
+#include <kvm/kvm-cmd.h>
+
+static int handle_kvm_command(int argc, char **argv)
+{
+       return handle_command(kvm_commands, argc, (const char **) &argv[0]);
+}
+
+int main(int argc, char *argv[])
+{
+       kvm__set_dir("%s/%s", HOME_DIR, KVM_PID_FILE_PATH);
+
+       return handle_kvm_command(argc - 1, &argv[1]);
+}
diff --git a/tools/kvm/mmio.c b/tools/kvm/mmio.c
new file mode 100644 (file)
index 0000000..dd28ef3
--- /dev/null
@@ -0,0 +1,140 @@
+#include "kvm/kvm.h"
+#include "kvm/rbtree-interval.h"
+#include "kvm/brlock.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sys/ioctl.h>
+#include <linux/kvm.h>
+#include <linux/types.h>
+#include <linux/rbtree.h>
+#include <linux/err.h>
+#include <errno.h>
+
+#define mmio_node(n) rb_entry(n, struct mmio_mapping, node)
+
+struct mmio_mapping {
+       struct rb_int_node      node;
+       void                    (*mmio_fn)(u64 addr, u8 *data, u32 len, u8 is_write, void *ptr);
+       void                    *ptr;
+};
+
+static struct rb_root mmio_tree = RB_ROOT;
+bool mmio_debug = false;
+
+static struct mmio_mapping *mmio_search(struct rb_root *root, u64 addr, u64 len)
+{
+       struct rb_int_node *node;
+
+       node = rb_int_search_range(root, addr, addr + len);
+       if (node == NULL)
+               return NULL;
+
+       return mmio_node(node);
+}
+
+/* Find lowest match, Check for overlap */
+static struct mmio_mapping *mmio_search_single(struct rb_root *root, u64 addr)
+{
+       struct rb_int_node *node;
+
+       node = rb_int_search_single(root, addr);
+       if (node == NULL)
+               return NULL;
+
+       return mmio_node(node);
+}
+
+static int mmio_insert(struct rb_root *root, struct mmio_mapping *data)
+{
+       return rb_int_insert(root, &data->node);
+}
+
+static const char *to_direction(u8 is_write)
+{
+       if (is_write)
+               return "write";
+
+       return "read";
+}
+
+int kvm__register_mmio(struct kvm *kvm, u64 phys_addr, u64 phys_addr_len, bool coalesce,
+                       void (*mmio_fn)(u64 addr, u8 *data, u32 len, u8 is_write, void *ptr),
+                       void *ptr)
+{
+       struct mmio_mapping *mmio;
+       struct kvm_coalesced_mmio_zone zone;
+       int ret;
+
+       mmio = malloc(sizeof(*mmio));
+       if (mmio == NULL)
+               return -ENOMEM;
+
+       *mmio = (struct mmio_mapping) {
+               .node = RB_INT_INIT(phys_addr, phys_addr + phys_addr_len),
+               .mmio_fn = mmio_fn,
+               .ptr    = ptr,
+       };
+
+       if (coalesce) {
+               zone = (struct kvm_coalesced_mmio_zone) {
+                       .addr   = phys_addr,
+                       .size   = phys_addr_len,
+               };
+               ret = ioctl(kvm->vm_fd, KVM_REGISTER_COALESCED_MMIO, &zone);
+               if (ret < 0) {
+                       free(mmio);
+                       return -errno;
+               }
+       }
+       br_write_lock();
+       ret = mmio_insert(&mmio_tree, mmio);
+       br_write_unlock();
+
+       return ret;
+}
+
+bool kvm__deregister_mmio(struct kvm *kvm, u64 phys_addr)
+{
+       struct mmio_mapping *mmio;
+       struct kvm_coalesced_mmio_zone zone;
+
+       br_write_lock();
+       mmio = mmio_search_single(&mmio_tree, phys_addr);
+       if (mmio == NULL) {
+               br_write_unlock();
+               return false;
+       }
+
+       zone = (struct kvm_coalesced_mmio_zone) {
+               .addr   = phys_addr,
+               .size   = 1,
+       };
+       ioctl(kvm->vm_fd, KVM_UNREGISTER_COALESCED_MMIO, &zone);
+
+       rb_int_erase(&mmio_tree, &mmio->node);
+       br_write_unlock();
+
+       free(mmio);
+       return true;
+}
+
+bool kvm__emulate_mmio(struct kvm *kvm, u64 phys_addr, u8 *data, u32 len, u8 is_write)
+{
+       struct mmio_mapping *mmio;
+
+       br_read_lock();
+       mmio = mmio_search(&mmio_tree, phys_addr, len);
+
+       if (mmio)
+               mmio->mmio_fn(phys_addr, data, len, is_write, mmio->ptr);
+       else {
+               if (mmio_debug)
+                       fprintf(stderr, "Warning: Ignoring MMIO %s at %016llx (length %u)\n",
+                               to_direction(is_write), phys_addr, len);
+       }
+       br_read_unlock();
+
+       return true;
+}
diff --git a/tools/kvm/net/uip/arp.c b/tools/kvm/net/uip/arp.c
new file mode 100644 (file)
index 0000000..98423da
--- /dev/null
@@ -0,0 +1,30 @@
+#include "kvm/uip.h"
+
+int uip_tx_do_arp(struct uip_tx_arg *arg)
+{
+       struct uip_arp *arp, *arp2;
+       struct uip_info *info;
+       struct uip_buf *buf;
+
+       info = arg->info;
+       buf = uip_buf_clone(arg);
+
+       arp      = (struct uip_arp *)(arg->eth);
+       arp2     = (struct uip_arp *)(buf->eth);
+
+       /*
+        * ARP replay code: 2
+        */
+       arp2->op   = htons(0x2);
+       arp2->dmac = arp->smac;
+       arp2->dip  = arp->sip;
+
+       if (arp->dip == htonl(info->host_ip)) {
+               arp2->smac = info->host_mac;
+               arp2->sip = htonl(info->host_ip);
+
+               uip_buf_set_used(info, buf);
+       }
+
+       return 0;
+}
diff --git a/tools/kvm/net/uip/buf.c b/tools/kvm/net/uip/buf.c
new file mode 100644 (file)
index 0000000..5e564a9
--- /dev/null
@@ -0,0 +1,114 @@
+#include "kvm/uip.h"
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+
+struct uip_buf *uip_buf_get_used(struct uip_info *info)
+{
+       struct uip_buf *buf;
+       bool found = false;
+
+       mutex_lock(&info->buf_lock);
+
+       while (!(info->buf_used_nr > 0))
+               pthread_cond_wait(&info->buf_used_cond, &info->buf_lock);
+
+       list_for_each_entry(buf, &info->buf_head, list) {
+               if (buf->status == UIP_BUF_STATUS_USED) {
+                       /*
+                        * Set status to INUSE immediately to prevent
+                        * someone from using this buf until we free it
+                        */
+                       buf->status = UIP_BUF_STATUS_INUSE;
+                       info->buf_used_nr--;
+                       found = true;
+                       break;
+               }
+       }
+
+       mutex_unlock(&info->buf_lock);
+
+       return found ? buf : NULL;
+}
+
+struct uip_buf *uip_buf_get_free(struct uip_info *info)
+{
+       struct uip_buf *buf;
+       bool found = false;
+
+       mutex_lock(&info->buf_lock);
+
+       while (!(info->buf_free_nr > 0))
+               pthread_cond_wait(&info->buf_free_cond, &info->buf_lock);
+
+       list_for_each_entry(buf, &info->buf_head, list) {
+               if (buf->status == UIP_BUF_STATUS_FREE) {
+                       /*
+                        * Set status to INUSE immediately to prevent
+                        * someone from using this buf until we free it
+                        */
+                       buf->status = UIP_BUF_STATUS_INUSE;
+                       info->buf_free_nr--;
+                       found = true;
+                       break;
+               }
+       }
+
+       mutex_unlock(&info->buf_lock);
+
+       return found ? buf : NULL;
+}
+
+struct uip_buf *uip_buf_set_used(struct uip_info *info, struct uip_buf *buf)
+{
+       mutex_lock(&info->buf_lock);
+
+       buf->status = UIP_BUF_STATUS_USED;
+       info->buf_used_nr++;
+       pthread_cond_signal(&info->buf_used_cond);
+
+       mutex_unlock(&info->buf_lock);
+
+       return buf;
+}
+
+struct uip_buf *uip_buf_set_free(struct uip_info *info, struct uip_buf *buf)
+{
+       mutex_lock(&info->buf_lock);
+
+       buf->status = UIP_BUF_STATUS_FREE;
+       info->buf_free_nr++;
+       pthread_cond_signal(&info->buf_free_cond);
+
+       mutex_unlock(&info->buf_lock);
+
+       return buf;
+}
+
+struct uip_buf *uip_buf_clone(struct uip_tx_arg *arg)
+{
+       struct uip_buf *buf;
+       struct uip_eth *eth2;
+       struct uip_info *info;
+
+       info = arg->info;
+
+       /*
+        * Get buffer from device to guest
+        */
+       buf = uip_buf_get_free(info);
+
+       /*
+        * Clone buffer
+        */
+       memcpy(buf->vnet, arg->vnet, arg->vnet_len);
+       memcpy(buf->eth, arg->eth, arg->eth_len);
+       buf->vnet_len   = arg->vnet_len;
+       buf->eth_len    = arg->eth_len;
+
+       eth2            = (struct uip_eth *)buf->eth;
+       eth2->src       = info->host_mac;
+       eth2->dst       = arg->eth->src;
+
+       return buf;
+}
diff --git a/tools/kvm/net/uip/core.c b/tools/kvm/net/uip/core.c
new file mode 100644 (file)
index 0000000..2e7603c
--- /dev/null
@@ -0,0 +1,190 @@
+#include "kvm/mutex.h"
+#include "kvm/uip.h"
+
+#include <linux/virtio_net.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+
+int uip_tx(struct iovec *iov, u16 out, struct uip_info *info)
+{
+       struct virtio_net_hdr *vnet;
+       struct uip_tx_arg arg;
+       int eth_len, vnet_len;
+       struct uip_eth *eth;
+       u8 *buf = NULL;
+       u16 proto;
+       int i;
+
+       /*
+        * Buffer from guest to device
+        */
+       vnet_len = iov[0].iov_len;
+       vnet     = iov[0].iov_base;
+
+       eth_len  = iov[1].iov_len;
+       eth      = iov[1].iov_base;
+
+       /*
+        * In case, ethernet frame is in more than one iov entry.
+        * Copy iov buffer into one linear buffer.
+        */
+       if (out > 2) {
+               eth_len = 0;
+               for (i = 1; i < out; i++)
+                       eth_len += iov[i].iov_len;
+
+               buf = malloc(eth_len);
+               if (!buf)
+                       return -1;
+
+               eth = (struct uip_eth *)buf;
+               for (i = 1; i < out; i++) {
+                       memcpy(buf, iov[i].iov_base, iov[i].iov_len);
+                       buf += iov[i].iov_len;
+               }
+       }
+
+       memset(&arg, 0, sizeof(arg));
+
+       arg.vnet_len = vnet_len;
+       arg.eth_len = eth_len;
+       arg.info = info;
+       arg.vnet = vnet;
+       arg.eth = eth;
+
+       /*
+        * Check package type
+        */
+       proto = ntohs(eth->type);
+
+       switch (proto) {
+       case UIP_ETH_P_ARP:
+               uip_tx_do_arp(&arg);
+               break;
+       case UIP_ETH_P_IP:
+               uip_tx_do_ipv4(&arg);
+               break;
+       default:
+               break;
+       }
+
+       if (out > 2 && buf)
+               free(eth);
+
+       return vnet_len + eth_len;
+}
+
+int uip_rx(struct iovec *iov, u16 in, struct uip_info *info)
+{
+       struct virtio_net_hdr *vnet;
+       struct uip_eth *eth;
+       struct uip_buf *buf;
+       int vnet_len;
+       int eth_len;
+       char *p;
+       int len;
+       int cnt;
+       int i;
+
+       /*
+        * Sleep until there is a buffer for guest
+        */
+       buf = uip_buf_get_used(info);
+
+       /*
+        * Fill device to guest buffer, vnet hdr fisrt
+        */
+       vnet_len = iov[0].iov_len;
+       vnet = iov[0].iov_base;
+       if (buf->vnet_len > vnet_len) {
+               len = -1;
+               goto out;
+       }
+       memcpy(vnet, buf->vnet, buf->vnet_len);
+
+       /*
+        * Then, the real eth data
+        * Note: Be sure buf->eth_len is not bigger than the buffer len that guest provides
+        */
+       cnt = buf->eth_len;
+       p = buf->eth;
+       for (i = 1; i < in; i++) {
+               eth_len = iov[i].iov_len;
+               eth = iov[i].iov_base;
+               if (cnt > eth_len) {
+                       memcpy(eth, p, eth_len);
+                       cnt -= eth_len;
+                       p += eth_len;
+               } else {
+                       memcpy(eth, p, cnt);
+                       cnt -= cnt;
+                       break;
+               }
+       }
+
+       if (cnt) {
+               pr_warning("uip_rx error");
+               len = -1;
+               goto out;
+       }
+
+       len = buf->vnet_len + buf->eth_len;
+
+out:
+       uip_buf_set_free(info, buf);
+       return len;
+}
+
+int uip_init(struct uip_info *info)
+{
+       struct list_head *udp_socket_head;
+       struct list_head *tcp_socket_head;
+       struct list_head *buf_head;
+       struct uip_buf *buf;
+       int buf_nr;
+       int i;
+
+       udp_socket_head = &info->udp_socket_head;
+       tcp_socket_head = &info->tcp_socket_head;
+       buf_head        = &info->buf_head;
+       buf_nr          = info->buf_nr;
+
+       INIT_LIST_HEAD(udp_socket_head);
+       INIT_LIST_HEAD(tcp_socket_head);
+       INIT_LIST_HEAD(buf_head);
+
+       pthread_mutex_init(&info->udp_socket_lock, NULL);
+       pthread_mutex_init(&info->tcp_socket_lock, NULL);
+       pthread_mutex_init(&info->buf_lock, NULL);
+
+       pthread_cond_init(&info->buf_used_cond, NULL);
+       pthread_cond_init(&info->buf_free_cond, NULL);
+
+
+       for (i = 0; i < buf_nr; i++) {
+               buf = malloc(sizeof(*buf));
+               memset(buf, 0, sizeof(*buf));
+
+               buf->status     = UIP_BUF_STATUS_FREE;
+               buf->info       = info;
+               buf->id         = i;
+               list_add_tail(&buf->list, buf_head);
+       }
+
+       list_for_each_entry(buf, buf_head, list) {
+               buf->vnet       = malloc(sizeof(struct virtio_net_hdr));
+               buf->vnet_len   = sizeof(struct virtio_net_hdr);
+               buf->eth        = malloc(1024*64 + sizeof(struct uip_pseudo_hdr));
+               buf->eth_len    = 1024*64 + sizeof(struct uip_pseudo_hdr);
+
+               memset(buf->vnet, 0, buf->vnet_len);
+               memset(buf->eth, 0, buf->eth_len);
+       }
+
+       info->buf_free_nr = buf_nr;
+       info->buf_used_nr = 0;
+
+       uip_dhcp_get_dns(info);
+
+       return 0;
+}
diff --git a/tools/kvm/net/uip/csum.c b/tools/kvm/net/uip/csum.c
new file mode 100644 (file)
index 0000000..7ca8bad
--- /dev/null
@@ -0,0 +1,92 @@
+#include "kvm/uip.h"
+
+static u16 uip_csum(u16 csum, u8 *addr, u16 count)
+{
+       long sum = csum;
+
+       while (count > 1) {
+               sum     += *(u16 *)addr;
+               addr    += 2;
+               count   -= 2;
+       }
+
+       if (count > 0)
+               sum += *(unsigned char *)addr;
+
+       while (sum>>16)
+               sum = (sum & 0xffff) + (sum >> 16);
+
+       return ~sum;
+}
+
+u16 uip_csum_ip(struct uip_ip *ip)
+{
+       return uip_csum(0, &ip->vhl, uip_ip_hdrlen(ip));
+}
+
+u16 uip_csum_icmp(struct uip_icmp *icmp)
+{
+       struct uip_ip *ip;
+
+       ip = &icmp->ip;
+       return icmp->csum = uip_csum(0, &icmp->type, htons(ip->len) - uip_ip_hdrlen(ip) - 8); /* icmp header len = 8 */
+}
+
+u16 uip_csum_udp(struct uip_udp *udp)
+{
+       struct uip_pseudo_hdr hdr;
+       struct uip_ip *ip;
+       int udp_len;
+       u8 *pad;
+
+       ip        = &udp->ip;
+
+       hdr.sip   = ip->sip;
+       hdr.dip   = ip->dip;
+       hdr.zero  = 0;
+       hdr.proto = ip->proto;
+       hdr.len   = udp->len;
+
+       udp_len   = uip_udp_len(udp);
+
+       if (udp_len % 2) {
+               pad = (u8 *)&udp->sport + udp_len;
+               *pad = 0;
+               memcpy((u8 *)&udp->sport + udp_len + 1, &hdr, sizeof(hdr));
+               return uip_csum(0, (u8 *)&udp->sport, udp_len + 1 + sizeof(hdr));
+       } else {
+               memcpy((u8 *)&udp->sport + udp_len, &hdr, sizeof(hdr));
+               return uip_csum(0, (u8 *)&udp->sport, udp_len + sizeof(hdr));
+       }
+
+}
+
+u16 uip_csum_tcp(struct uip_tcp *tcp)
+{
+       struct uip_pseudo_hdr hdr;
+       struct uip_ip *ip;
+       u16 tcp_len;
+       u8 *pad;
+
+       ip        = &tcp->ip;
+       tcp_len   = ntohs(ip->len) - uip_ip_hdrlen(ip);
+
+       hdr.sip   = ip->sip;
+       hdr.dip   = ip->dip;
+       hdr.zero  = 0;
+       hdr.proto = ip->proto;
+       hdr.len   = htons(tcp_len);
+
+       if (tcp_len > UIP_MAX_TCP_PAYLOAD + 20)
+               pr_warning("tcp_len(%d) is too large", tcp_len);
+
+       if (tcp_len % 2) {
+               pad = (u8 *)&tcp->sport + tcp_len;
+               *pad = 0;
+               memcpy((u8 *)&tcp->sport + tcp_len + 1, &hdr, sizeof(hdr));
+               return uip_csum(0, (u8 *)&tcp->sport, tcp_len + 1 + sizeof(hdr));
+       } else {
+               memcpy((u8 *)&tcp->sport + tcp_len, &hdr, sizeof(hdr));
+               return uip_csum(0, (u8 *)&tcp->sport, tcp_len + sizeof(hdr));
+       }
+}
diff --git a/tools/kvm/net/uip/dhcp.c b/tools/kvm/net/uip/dhcp.c
new file mode 100644 (file)
index 0000000..e91a7c7
--- /dev/null
@@ -0,0 +1,203 @@
+#include "kvm/uip.h"
+
+#include <arpa/inet.h>
+
+#define EMPTY_ADDR "0.0.0.0"
+
+static inline bool uip_dhcp_is_discovery(struct uip_dhcp *dhcp)
+{
+       return (dhcp->option[2] == UIP_DHCP_DISCOVER &&
+               dhcp->option[1] == UIP_DHCP_TAG_MSG_TYPE_LEN &&
+               dhcp->option[0] == UIP_DHCP_TAG_MSG_TYPE);
+}
+
+static inline bool uip_dhcp_is_request(struct uip_dhcp *dhcp)
+{
+       return (dhcp->option[2] == UIP_DHCP_REQUEST &&
+               dhcp->option[1] == UIP_DHCP_TAG_MSG_TYPE_LEN &&
+               dhcp->option[0] == UIP_DHCP_TAG_MSG_TYPE);
+}
+
+bool uip_udp_is_dhcp(struct uip_udp *udp)
+{
+       struct uip_dhcp *dhcp;
+
+       if (ntohs(udp->sport) != UIP_DHCP_PORT_CLIENT ||
+           ntohs(udp->dport) != UIP_DHCP_PORT_SERVER)
+               return false;
+
+       dhcp = (struct uip_dhcp *)udp;
+
+       if (ntohl(dhcp->magic_cookie) != UIP_DHCP_MAGIC_COOKIE)
+               return false;
+
+       return true;
+}
+
+int uip_dhcp_get_dns(struct uip_info *info)
+{
+       char key[256], val[256];
+       struct in_addr addr;
+       int ret = -1;
+       int n = 0;
+       FILE *fp;
+       u32 ip;
+
+       fp = fopen("/etc/resolv.conf", "r");
+       if (!fp)
+               goto out;
+
+       while (!feof(fp)) {
+               if (fscanf(fp, "%s %s\n", key, val) != 2)
+                       continue;
+               if (strncmp("domain", key, 6) == 0)
+                       info->domain_name = strndup(val, UIP_DHCP_MAX_DOMAIN_NAME_LEN);
+               else if (strncmp("nameserver", key, 10) == 0) {
+                       if (!inet_aton(val, &addr))
+                               continue;
+                       ip = ntohl(addr.s_addr);
+                       if (n < UIP_DHCP_MAX_DNS_SERVER_NR)
+                               info->dns_ip[n++] = ip;
+                       ret = 0;
+               }
+       }
+
+out:
+       fclose(fp);
+       return ret;
+}
+
+static int uip_dhcp_fill_option_name_and_server(struct uip_info *info, u8 *opt, int i)
+{
+       u8 domain_name_len;
+       u32 *addr;
+       int n;
+
+       if (info->domain_name) {
+               domain_name_len = strlen(info->domain_name);
+               opt[i++]        = UIP_DHCP_TAG_DOMAIN_NAME;
+               opt[i++]        = domain_name_len;
+               memcpy(&opt[i], info->domain_name, domain_name_len);
+               i               += domain_name_len;
+       }
+
+       for (n = 0; n < UIP_DHCP_MAX_DNS_SERVER_NR; n++) {
+               if (info->dns_ip[n] == 0)
+                       continue;
+               opt[i++]        = UIP_DHCP_TAG_DNS_SERVER;
+               opt[i++]        = UIP_DHCP_TAG_DNS_SERVER_LEN;
+               addr            = (u32 *)&opt[i];
+               *addr           = htonl(info->dns_ip[n]);
+               i               += UIP_DHCP_TAG_DNS_SERVER_LEN;
+       }
+
+       return i;
+}
+static int uip_dhcp_fill_option(struct uip_info *info, struct uip_dhcp *dhcp, int reply_msg_type)
+{
+       int i = 0;
+       u32 *addr;
+       u8 *opt;
+
+       opt             = dhcp->option;
+
+       opt[i++]        = UIP_DHCP_TAG_MSG_TYPE;
+       opt[i++]        = UIP_DHCP_TAG_MSG_TYPE_LEN;
+       opt[i++]        = reply_msg_type;
+
+       opt[i++]        = UIP_DHCP_TAG_SERVER_ID;
+       opt[i++]        = UIP_DHCP_TAG_SERVER_ID_LEN;
+       addr            = (u32 *)&opt[i];
+       *addr           = htonl(info->host_ip);
+       i               += UIP_DHCP_TAG_SERVER_ID_LEN;
+
+       opt[i++]        = UIP_DHCP_TAG_LEASE_TIME;
+       opt[i++]        = UIP_DHCP_TAG_LEASE_TIME_LEN;
+       addr            = (u32 *)&opt[i];
+       *addr           = htonl(UIP_DHCP_LEASE_TIME);
+       i               += UIP_DHCP_TAG_LEASE_TIME_LEN;
+
+       opt[i++]        = UIP_DHCP_TAG_SUBMASK;
+       opt[i++]        = UIP_DHCP_TAG_SUBMASK_LEN;
+       addr            = (u32 *)&opt[i];
+       *addr           = htonl(info->guest_netmask);
+       i               += UIP_DHCP_TAG_SUBMASK_LEN;
+
+       opt[i++]        = UIP_DHCP_TAG_ROUTER;
+       opt[i++]        = UIP_DHCP_TAG_ROUTER_LEN;
+       addr            = (u32 *)&opt[i];
+       *addr           = htonl(info->host_ip);
+       i               += UIP_DHCP_TAG_ROUTER_LEN;
+
+       opt[i++]        = UIP_DHCP_TAG_ROOT;
+       opt[i++]        = strlen(EMPTY_ADDR);
+       addr            = (u32 *)&opt[i];
+       strncpy((void *) addr, EMPTY_ADDR, strlen(EMPTY_ADDR));
+       i               += strlen(EMPTY_ADDR);
+
+       i               = uip_dhcp_fill_option_name_and_server(info, opt, i);
+
+       opt[i++]        = UIP_DHCP_TAG_END;
+
+       return 0;
+}
+
+static int uip_dhcp_make_pkg(struct uip_info *info, struct uip_udp_socket *sk, struct uip_buf *buf, u8 reply_msg_type)
+{
+       struct uip_dhcp *dhcp;
+
+       dhcp            = (struct uip_dhcp *)buf->eth;
+
+       dhcp->msg_type  = 2;
+       dhcp->client_ip = 0;
+       dhcp->your_ip   = htonl(info->guest_ip);
+       dhcp->server_ip = htonl(info->host_ip);
+       dhcp->agent_ip  = 0;
+
+       uip_dhcp_fill_option(info, dhcp, reply_msg_type);
+
+       sk->sip         = htonl(info->guest_ip);
+       sk->dip         = htonl(info->host_ip);
+       sk->sport       = htons(UIP_DHCP_PORT_CLIENT);
+       sk->dport       = htons(UIP_DHCP_PORT_SERVER);
+
+       return 0;
+}
+
+int uip_tx_do_ipv4_udp_dhcp(struct uip_tx_arg *arg)
+{
+       struct uip_udp_socket sk;
+       struct uip_dhcp *dhcp;
+       struct uip_info *info;
+       struct uip_buf *buf;
+       u8 reply_msg_type;
+
+       dhcp = (struct uip_dhcp *)arg->eth;
+
+       if (uip_dhcp_is_discovery(dhcp))
+               reply_msg_type = UIP_DHCP_OFFER;
+       else if (uip_dhcp_is_request(dhcp))
+               reply_msg_type = UIP_DHCP_ACK;
+       else
+               return -1;
+
+       buf = uip_buf_clone(arg);
+       info = arg->info;
+
+       /*
+        * Cook DHCP pkg
+        */
+       uip_dhcp_make_pkg(info, &sk, buf, reply_msg_type);
+
+       /*
+        * Cook UDP pkg
+        */
+       uip_udp_make_pkg(info, &sk, buf, NULL, UIP_DHCP_MAX_PAYLOAD_LEN);
+
+       /*
+        * Send data received from socket to guest
+        */
+       uip_buf_set_used(info, buf);
+
+       return 0;
+}
diff --git a/tools/kvm/net/uip/icmp.c b/tools/kvm/net/uip/icmp.c
new file mode 100644 (file)
index 0000000..233297c
--- /dev/null
@@ -0,0 +1,29 @@
+#include "kvm/uip.h"
+
+int uip_tx_do_ipv4_icmp(struct uip_tx_arg *arg)
+{
+       struct uip_ip *ip, *ip2;
+       struct uip_icmp *icmp2;
+       struct uip_buf *buf;
+
+       buf             = uip_buf_clone(arg);
+
+       icmp2           = (struct uip_icmp *)(buf->eth);
+       ip2             = (struct uip_ip *)(buf->eth);
+       ip              = (struct uip_ip *)(arg->eth);
+
+       ip2->sip        = ip->dip;
+       ip2->dip        = ip->sip;
+       ip2->csum       = 0;
+       /*
+        * ICMP reply: 0
+        */
+       icmp2->type     = 0;
+       icmp2->csum     = 0;
+       ip2->csum       = uip_csum_ip(ip2);
+       icmp2->csum     = uip_csum_icmp(icmp2);
+
+       uip_buf_set_used(arg->info, buf);
+
+       return 0;
+}
diff --git a/tools/kvm/net/uip/ipv4.c b/tools/kvm/net/uip/ipv4.c
new file mode 100644 (file)
index 0000000..58373fd
--- /dev/null
@@ -0,0 +1,29 @@
+#include "kvm/uip.h"
+
+int uip_tx_do_ipv4(struct uip_tx_arg *arg)
+{
+       struct uip_ip *ip;
+
+       ip = (struct uip_ip *)(arg->eth);
+
+       if (uip_ip_hdrlen(ip) != 20) {
+               pr_warning("IP header length is not 20 bytes");
+               return -1;
+       }
+
+       switch (ip->proto) {
+       case UIP_IP_P_ICMP:
+               uip_tx_do_ipv4_icmp(arg);
+               break;
+       case UIP_IP_P_TCP:
+               uip_tx_do_ipv4_tcp(arg);
+               break;
+       case UIP_IP_P_UDP:
+               uip_tx_do_ipv4_udp(arg);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
diff --git a/tools/kvm/net/uip/tcp.c b/tools/kvm/net/uip/tcp.c
new file mode 100644 (file)
index 0000000..586a45c
--- /dev/null
@@ -0,0 +1,317 @@
+#include "kvm/uip.h"
+
+#include <linux/virtio_net.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+
+static int uip_tcp_socket_close(struct uip_tcp_socket *sk, int how)
+{
+       shutdown(sk->fd, how);
+
+       if (sk->write_done && sk->read_done) {
+               shutdown(sk->fd, SHUT_RDWR);
+               close(sk->fd);
+
+               mutex_lock(sk->lock);
+               list_del(&sk->list);
+               mutex_unlock(sk->lock);
+
+               free(sk);
+       }
+
+       return 0;
+}
+
+static struct uip_tcp_socket *uip_tcp_socket_find(struct uip_tx_arg *arg, u32 sip, u32 dip, u16 sport, u16 dport)
+{
+       struct list_head *sk_head;
+       pthread_mutex_t *sk_lock;
+       struct uip_tcp_socket *sk;
+
+       sk_head = &arg->info->tcp_socket_head;
+       sk_lock = &arg->info->tcp_socket_lock;
+
+       mutex_lock(sk_lock);
+       list_for_each_entry(sk, sk_head, list) {
+               if (sk->sip == sip && sk->dip == dip && sk->sport == sport && sk->dport == dport) {
+                       mutex_unlock(sk_lock);
+                       return sk;
+               }
+       }
+       mutex_unlock(sk_lock);
+
+       return NULL;
+}
+
+static struct uip_tcp_socket *uip_tcp_socket_alloc(struct uip_tx_arg *arg, u32 sip, u32 dip, u16 sport, u16 dport)
+{
+       struct list_head *sk_head;
+       struct uip_tcp_socket *sk;
+       pthread_mutex_t *sk_lock;
+       struct uip_tcp *tcp;
+       struct uip_ip *ip;
+       int ret;
+
+       tcp = (struct uip_tcp *)arg->eth;
+       ip = (struct uip_ip *)arg->eth;
+
+       sk_head = &arg->info->tcp_socket_head;
+       sk_lock = &arg->info->tcp_socket_lock;
+
+       sk = malloc(sizeof(*sk));
+       memset(sk, 0, sizeof(*sk));
+
+       sk->lock                        = sk_lock;
+       sk->info                        = arg->info;
+
+       sk->fd                          = socket(AF_INET, SOCK_STREAM, 0);
+       sk->addr.sin_family             = AF_INET;
+       sk->addr.sin_addr.s_addr        = dip;
+       sk->addr.sin_port               = dport;
+
+       ret = connect(sk->fd, (struct sockaddr *)&sk->addr, sizeof(sk->addr));
+       if (ret) {
+               free(sk);
+               return NULL;
+       }
+
+       sk->sip         = ip->sip;
+       sk->dip         = ip->dip;
+       sk->sport       = tcp->sport;
+       sk->dport       = tcp->dport;
+
+       mutex_lock(sk_lock);
+       list_add_tail(&sk->list, sk_head);
+       mutex_unlock(sk_lock);
+
+       return sk;
+}
+
+static int uip_tcp_payload_send(struct uip_tcp_socket *sk, u8 flag, u16 payload_len)
+{
+       struct uip_info *info;
+       struct uip_eth *eth2;
+       struct uip_tcp *tcp2;
+       struct uip_buf *buf;
+       struct uip_ip *ip2;
+
+       info            = sk->info;
+
+       /*
+        * Get free buffer to send data to guest
+        */
+       buf             = uip_buf_get_free(info);
+
+       /*
+        * Cook a ethernet frame
+        */
+       tcp2            = (struct uip_tcp *)buf->eth;
+       eth2            = (struct uip_eth *)buf->eth;
+       ip2             = (struct uip_ip *)buf->eth;
+
+       eth2->src       = info->host_mac;
+       eth2->dst       = info->guest_mac;
+       eth2->type      = htons(UIP_ETH_P_IP);
+
+       ip2->vhl        = UIP_IP_VER_4 | UIP_IP_HDR_LEN;
+       ip2->tos        = 0;
+       ip2->id         = 0;
+       ip2->flgfrag    = 0;
+       ip2->ttl        = UIP_IP_TTL;
+       ip2->proto      = UIP_IP_P_TCP;
+       ip2->csum       = 0;
+       ip2->sip        = sk->dip;
+       ip2->dip        = sk->sip;
+
+       tcp2->sport     = sk->dport;
+       tcp2->dport     = sk->sport;
+       tcp2->seq       = htonl(sk->seq_server);
+       tcp2->ack       = htonl(sk->ack_server);
+       /*
+        * Diable TCP options, tcp hdr len equals 20 bytes
+        */
+       tcp2->off       = UIP_TCP_HDR_LEN;
+       tcp2->flg       = flag;
+       tcp2->win       = htons(UIP_TCP_WIN_SIZE);
+       tcp2->csum      = 0;
+       tcp2->urgent    = 0;
+
+       if (payload_len > 0)
+               memcpy(uip_tcp_payload(tcp2), sk->payload, payload_len);
+
+       ip2->len        = htons(uip_tcp_hdrlen(tcp2) + payload_len + uip_ip_hdrlen(ip2));
+       ip2->csum       = uip_csum_ip(ip2);
+       tcp2->csum      = uip_csum_tcp(tcp2);
+
+       /*
+        * virtio_net_hdr
+        */
+       buf->vnet_len   = sizeof(struct virtio_net_hdr);
+       memset(buf->vnet, 0, buf->vnet_len);
+
+       buf->eth_len    = ntohs(ip2->len) + uip_eth_hdrlen(&ip2->eth);
+
+       /*
+        * Increase server seq
+        */
+       sk->seq_server  += payload_len;
+
+       /*
+        * Send data received from socket to guest
+        */
+       uip_buf_set_used(info, buf);
+
+       return 0;
+}
+
+static void *uip_tcp_socket_thread(void *p)
+{
+       struct uip_tcp_socket *sk;
+       u8 *payload;
+       int ret;
+
+       sk = p;
+
+       payload = malloc(UIP_MAX_TCP_PAYLOAD);
+       sk->payload = payload;
+       if (!sk->payload)
+               goto out;
+
+       while (1) {
+
+               ret = read(sk->fd, payload, UIP_MAX_TCP_PAYLOAD);
+
+               if (ret <= 0 || ret > UIP_MAX_TCP_PAYLOAD)
+                       goto out;
+
+               uip_tcp_payload_send(sk, UIP_TCP_FLAG_ACK, ret);
+
+       }
+
+out:
+       /*
+        * Close server to guest TCP connection
+        */
+       uip_tcp_socket_close(sk, SHUT_RD);
+
+       uip_tcp_payload_send(sk, UIP_TCP_FLAG_FIN | UIP_TCP_FLAG_ACK, 0);
+       sk->seq_server += 1;
+
+       sk->read_done = 1;
+
+       free(sk->payload);
+       pthread_exit(NULL);
+
+       return NULL;
+}
+
+static int uip_tcp_socket_receive(struct uip_tcp_socket *sk)
+{
+       if (sk->thread == 0)
+               return pthread_create(&sk->thread, NULL, uip_tcp_socket_thread, (void *)sk);
+
+       return 0;
+}
+
+static int uip_tcp_socket_send(struct uip_tcp_socket *sk, struct uip_tcp *tcp)
+{
+       int len;
+       int ret;
+       u8 *payload;
+
+       if (sk->write_done)
+               return 0;
+
+       payload = uip_tcp_payload(tcp);
+       len = uip_tcp_payloadlen(tcp);
+
+       ret = write(sk->fd, payload, len);
+       if (ret != len)
+               pr_warning("tcp send error");
+
+       return ret;
+}
+
+int uip_tx_do_ipv4_tcp(struct uip_tx_arg *arg)
+{
+       struct uip_tcp_socket *sk;
+       struct uip_tcp *tcp;
+       struct uip_ip *ip;
+       int ret;
+
+       tcp = (struct uip_tcp *)arg->eth;
+       ip = (struct uip_ip *)arg->eth;
+
+       /*
+        * Guest is trying to start a TCP session, let's fake SYN-ACK to guest
+        */
+       if (uip_tcp_is_syn(tcp)) {
+               sk = uip_tcp_socket_alloc(arg, ip->sip, ip->dip, tcp->sport, tcp->dport);
+               if (!sk)
+                       return -1;
+
+               /*
+                * Setup ISN number
+                */
+               sk->isn_guest  = uip_tcp_isn(tcp);
+               sk->isn_server = uip_tcp_isn_alloc();
+
+               sk->seq_server = sk->isn_server;
+               sk->ack_server = sk->isn_guest + 1;
+               uip_tcp_payload_send(sk, UIP_TCP_FLAG_SYN | UIP_TCP_FLAG_ACK, 0);
+               sk->seq_server += 1;
+
+               /*
+                * Start receive thread for data from remote to guest
+                */
+               uip_tcp_socket_receive(sk);
+
+               goto out;
+       }
+
+       /*
+        * Find socket we have allocated
+        */
+       sk = uip_tcp_socket_find(arg, ip->sip, ip->dip, tcp->sport, tcp->dport);
+       if (!sk)
+               return -1;
+
+       sk->guest_acked = ntohl(tcp->ack);
+
+       if (uip_tcp_is_fin(tcp)) {
+               if (sk->write_done)
+                       goto out;
+
+               sk->write_done = 1;
+               sk->ack_server += 1;
+               uip_tcp_payload_send(sk, UIP_TCP_FLAG_ACK, 0);
+
+               /*
+                * Close guest to server TCP connection
+                */
+               uip_tcp_socket_close(sk, SHUT_WR);
+
+               goto out;
+       }
+
+       /*
+        * Ignore guest to server frames with zero tcp payload
+        */
+       if (uip_tcp_payloadlen(tcp) == 0)
+               goto out;
+
+       /*
+        * Sent out TCP data to remote host
+        */
+       ret = uip_tcp_socket_send(sk, tcp);
+       if (ret < 0)
+               return -1;
+       /*
+        * Send ACK to guest imediately
+        */
+       sk->ack_server += ret;
+       uip_tcp_payload_send(sk, UIP_TCP_FLAG_ACK, 0);
+
+out:
+       return 0;
+}
diff --git a/tools/kvm/net/uip/udp.c b/tools/kvm/net/uip/udp.c
new file mode 100644 (file)
index 0000000..d4518b2
--- /dev/null
@@ -0,0 +1,236 @@
+#include "kvm/uip.h"
+
+#include <linux/virtio_net.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <sys/socket.h>
+#include <sys/epoll.h>
+#include <fcntl.h>
+
+#define UIP_UDP_MAX_EVENTS 1000
+
+static struct uip_udp_socket *uip_udp_socket_find(struct uip_tx_arg *arg, u32 sip, u32 dip, u16 sport, u16 dport)
+{
+       struct list_head *sk_head;
+       struct uip_udp_socket *sk;
+       pthread_mutex_t *sk_lock;
+       struct epoll_event ev;
+       int flags;
+       int ret;
+
+       sk_head = &arg->info->udp_socket_head;
+       sk_lock = &arg->info->udp_socket_lock;
+
+       /*
+        * Find existing sk
+        */
+       mutex_lock(sk_lock);
+       list_for_each_entry(sk, sk_head, list) {
+               if (sk->sip == sip && sk->dip == dip && sk->sport == sport && sk->dport == dport) {
+                       mutex_unlock(sk_lock);
+                       return sk;
+               }
+       }
+       mutex_unlock(sk_lock);
+
+       /*
+        * Allocate new one
+        */
+       sk = malloc(sizeof(*sk));
+       memset(sk, 0, sizeof(*sk));
+
+       sk->lock = sk_lock;
+
+       sk->fd = socket(AF_INET, SOCK_DGRAM, 0);
+       if (sk->fd < 0)
+               goto out;
+
+       /*
+        * Set non-blocking
+        */
+       flags = fcntl(sk->fd, F_GETFL, 0);
+       flags |= O_NONBLOCK;
+       fcntl(sk->fd, F_SETFL, flags);
+
+       /*
+        * Add sk->fd to epoll_wait
+        */
+       ev.events       = EPOLLIN;
+       ev.data.fd      = sk->fd;
+       ev.data.ptr     = sk;
+       if (arg->info->udp_epollfd <= 0)
+               arg->info->udp_epollfd = epoll_create(UIP_UDP_MAX_EVENTS);
+       ret = epoll_ctl(arg->info->udp_epollfd, EPOLL_CTL_ADD, sk->fd, &ev);
+       if (ret == -1)
+               pr_warning("epoll_ctl error");
+
+       sk->addr.sin_family      = AF_INET;
+       sk->addr.sin_addr.s_addr = dip;
+       sk->addr.sin_port        = dport;
+
+       sk->sip                  = sip;
+       sk->dip                  = dip;
+       sk->sport                = sport;
+       sk->dport                = dport;
+
+       mutex_lock(sk_lock);
+       list_add_tail(&sk->list, sk_head);
+       mutex_unlock(sk_lock);
+
+       return sk;
+
+out:
+       free(sk);
+       return NULL;
+}
+
+static int uip_udp_socket_send(struct uip_udp_socket *sk, struct uip_udp *udp)
+{
+       int len;
+       int ret;
+
+       len = ntohs(udp->len) - uip_udp_hdrlen(udp);
+
+       ret = sendto(sk->fd, udp->payload, len, 0, (struct sockaddr *)&sk->addr, sizeof(sk->addr));
+       if (ret != len)
+               return -1;
+
+       return 0;
+}
+
+int uip_udp_make_pkg(struct uip_info *info, struct uip_udp_socket *sk, struct uip_buf *buf, u8* payload, int payload_len)
+{
+       struct uip_eth *eth2;
+       struct uip_udp *udp2;
+       struct uip_ip *ip2;
+
+       /*
+        * Cook a ethernet frame
+        */
+       udp2            = (struct uip_udp *)(buf->eth);
+       eth2            = (struct uip_eth *)buf->eth;
+       ip2             = (struct uip_ip *)(buf->eth);
+
+       eth2->src       = info->host_mac;
+       eth2->dst       = info->guest_mac;
+       eth2->type      = htons(UIP_ETH_P_IP);
+
+       ip2->vhl        = UIP_IP_VER_4 | UIP_IP_HDR_LEN;
+       ip2->tos        = 0;
+       ip2->id         = 0;
+       ip2->flgfrag    = 0;
+       ip2->ttl        = UIP_IP_TTL;
+       ip2->proto      = UIP_IP_P_UDP;
+       ip2->csum       = 0;
+
+       ip2->sip        = sk->dip;
+       ip2->dip        = sk->sip;
+       udp2->sport     = sk->dport;
+       udp2->dport     = sk->sport;
+
+       udp2->len       = htons(payload_len + uip_udp_hdrlen(udp2));
+       udp2->csum      = 0;
+
+       if (payload)
+               memcpy(udp2->payload, payload, payload_len);
+
+       ip2->len        = udp2->len + htons(uip_ip_hdrlen(ip2));
+       ip2->csum       = uip_csum_ip(ip2);
+       udp2->csum      = uip_csum_udp(udp2);
+
+       /*
+        * virtio_net_hdr
+        */
+       buf->vnet_len   = sizeof(struct virtio_net_hdr);
+       memset(buf->vnet, 0, buf->vnet_len);
+
+       buf->eth_len    = ntohs(ip2->len) + uip_eth_hdrlen(&ip2->eth);
+
+       return 0;
+}
+
+static void *uip_udp_socket_thread(void *p)
+{
+       struct epoll_event events[UIP_UDP_MAX_EVENTS];
+       struct uip_udp_socket *sk;
+       struct uip_info *info;
+       struct uip_buf *buf;
+       int payload_len;
+       u8 *payload;
+       int nfds;
+       int i;
+
+       info = p;
+
+       do {
+               payload = malloc(UIP_MAX_UDP_PAYLOAD);
+       } while (!payload);
+
+       while (1) {
+               nfds = epoll_wait(info->udp_epollfd, events, UIP_UDP_MAX_EVENTS, -1);
+
+               if (nfds == -1)
+                       continue;
+
+               for (i = 0; i < nfds; i++) {
+
+                       sk = events[i].data.ptr;
+                       payload_len = recvfrom(sk->fd, payload, UIP_MAX_UDP_PAYLOAD, 0, NULL, NULL);
+                       if (payload_len < 0)
+                               continue;
+
+                       /*
+                        * Get free buffer to send data to guest
+                        */
+                       buf = uip_buf_get_free(info);
+
+                       uip_udp_make_pkg(info, sk, buf, payload, payload_len);
+
+                       /*
+                        * Send data received from socket to guest
+                        */
+                       uip_buf_set_used(info, buf);
+               }
+       }
+
+       free(payload);
+       pthread_exit(NULL);
+       return NULL;
+}
+
+int uip_tx_do_ipv4_udp(struct uip_tx_arg *arg)
+{
+       struct uip_udp_socket *sk;
+       struct uip_info *info;
+       struct uip_udp *udp;
+       struct uip_ip *ip;
+       int ret;
+
+       udp     = (struct uip_udp *)(arg->eth);
+       ip      = (struct uip_ip *)(arg->eth);
+       info    = arg->info;
+
+       if (uip_udp_is_dhcp(udp)) {
+               uip_tx_do_ipv4_udp_dhcp(arg);
+               return 0;
+       }
+
+       /*
+        * Find socket we have allocated before, otherwise allocate one
+        */
+       sk = uip_udp_socket_find(arg, ip->sip, ip->dip, udp->sport, udp->dport);
+       if (!sk)
+               return -1;
+
+       /*
+        * Send out UDP data to remote host
+        */
+       ret = uip_udp_socket_send(sk, udp);
+       if (ret)
+               return -1;
+
+       if (!info->udp_thread)
+               pthread_create(&info->udp_thread, NULL, uip_udp_socket_thread, (void *)info);
+
+       return 0;
+}
diff --git a/tools/kvm/pci.c b/tools/kvm/pci.c
new file mode 100644 (file)
index 0000000..38f4778
--- /dev/null
@@ -0,0 +1,213 @@
+#include "kvm/pci.h"
+#include "kvm/ioport.h"
+#include "kvm/util.h"
+#include "kvm/kvm.h"
+
+#include <linux/err.h>
+#include <assert.h>
+
+#define PCI_BAR_OFFSET(b)              (offsetof(struct pci_device_header, bar[b]))
+
+static struct pci_device_header                *pci_devices[PCI_MAX_DEVICES];
+
+static union pci_config_address                pci_config_address;
+
+/* This is within our PCI gap - in an unused area.
+ * Note this is a PCI *bus address*, is used to assign BARs etc.!
+ * (That's why it can still 32bit even with 64bit guests-- 64bit
+ * PCI isn't currently supported.)
+ */
+static u32 io_space_blocks             = KVM_PCI_MMIO_AREA;
+
+u32 pci_get_io_space_block(u32 size)
+{
+       u32 block = io_space_blocks;
+       io_space_blocks += size;
+
+       return block;
+}
+
+static void *pci_config_address_ptr(u16 port)
+{
+       unsigned long offset;
+       void *base;
+
+       offset  = port - PCI_CONFIG_ADDRESS;
+       base    = &pci_config_address;
+
+       return base + offset;
+}
+
+static bool pci_config_address_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+       void *p = pci_config_address_ptr(port);
+
+       memcpy(p, data, size);
+
+       return true;
+}
+
+static bool pci_config_address_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+       void *p = pci_config_address_ptr(port);
+
+       memcpy(data, p, size);
+
+       return true;
+}
+
+static struct ioport_operations pci_config_address_ops = {
+       .io_in  = pci_config_address_in,
+       .io_out = pci_config_address_out,
+};
+
+static bool pci_device_exists(u8 bus_number, u8 device_number, u8 function_number)
+{
+       struct pci_device_header *dev;
+
+       if (pci_config_address.bus_number != bus_number)
+               return false;
+
+       if (pci_config_address.function_number != function_number)
+               return false;
+
+       if (device_number >= PCI_MAX_DEVICES)
+               return false;
+
+       dev = pci_devices[device_number];
+
+       return dev != NULL;
+}
+
+static bool pci_config_data_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+       /*
+        * If someone accesses PCI configuration space offsets that are not
+        * aligned to 4 bytes, it uses ioports to signify that.
+        */
+       pci_config_address.reg_offset = port - PCI_CONFIG_DATA;
+
+       pci__config_wr(kvm, pci_config_address, data, size);
+
+       return true;
+}
+
+static bool pci_config_data_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+       /*
+        * If someone accesses PCI configuration space offsets that are not
+        * aligned to 4 bytes, it uses ioports to signify that.
+        */
+       pci_config_address.reg_offset = port - PCI_CONFIG_DATA;
+
+       pci__config_rd(kvm, pci_config_address, data, size);
+
+       return true;
+}
+
+static struct ioport_operations pci_config_data_ops = {
+       .io_in  = pci_config_data_in,
+       .io_out = pci_config_data_out,
+};
+
+void pci__config_wr(struct kvm *kvm, union pci_config_address addr, void *data, int size)
+{
+       u8 dev_num;
+
+       dev_num = addr.device_number;
+
+       if (pci_device_exists(0, dev_num, 0)) {
+               unsigned long offset;
+
+               offset = addr.w & 0xff;
+               if (offset < sizeof(struct pci_device_header)) {
+                       void *p = pci_devices[dev_num];
+                       u8 bar = (offset - PCI_BAR_OFFSET(0)) / (sizeof(u32));
+                       u32 sz = PCI_IO_SIZE;
+
+                       if (bar < 6 && pci_devices[dev_num]->bar_size[bar])
+                               sz = pci_devices[dev_num]->bar_size[bar];
+
+                       /*
+                        * If the kernel masks the BAR it would expect to find the
+                        * size of the BAR there next time it reads from it.
+                        * When the kernel got the size it would write the address
+                        * back.
+                        */
+                       if (*(u32 *)(p + offset)) {
+                               /* See if kernel tries to mask one of the BARs */
+                               if ((offset >= PCI_BAR_OFFSET(0)) &&
+                                   (offset <= PCI_BAR_OFFSET(6)) &&
+                                   (ioport__read32(data)  == 0xFFFFFFFF))
+                                       memcpy(p + offset, &sz, sizeof(sz));
+                                   else
+                                       memcpy(p + offset, data, size);
+                       }
+               }
+       }
+}
+
+void pci__config_rd(struct kvm *kvm, union pci_config_address addr, void *data, int size)
+{
+       u8 dev_num;
+
+       dev_num = addr.device_number;
+
+       if (pci_device_exists(0, dev_num, 0)) {
+               unsigned long offset;
+
+               offset = addr.w & 0xff;
+               if (offset < sizeof(struct pci_device_header)) {
+                       void *p = pci_devices[dev_num];
+
+                       memcpy(data, p + offset, size);
+               } else {
+                       memset(data, 0x00, size);
+               }
+       } else {
+               memset(data, 0xff, size);
+       }
+}
+
+int pci__register(struct pci_device_header *dev, u8 dev_num)
+{
+       if (dev_num >= PCI_MAX_DEVICES)
+               return -ENOSPC;
+
+       pci_devices[dev_num] = dev;
+
+       return 0;
+}
+
+struct pci_device_header *pci__find_dev(u8 dev_num)
+{
+       if (dev_num >= PCI_MAX_DEVICES)
+               return ERR_PTR(-EOVERFLOW);
+
+       return pci_devices[dev_num];
+}
+
+int pci__init(struct kvm *kvm)
+{
+       int r;
+
+       r = ioport__register(PCI_CONFIG_DATA + 0, &pci_config_data_ops, 4, NULL);
+       if (r < 0)
+               return r;
+
+       r = ioport__register(PCI_CONFIG_ADDRESS + 0, &pci_config_address_ops, 4, NULL);
+       if (r < 0) {
+               ioport__unregister(PCI_CONFIG_DATA);
+               return r;
+       }
+
+       return 0;
+}
+
+int pci__exit(struct kvm *kvm)
+{
+       ioport__unregister(PCI_CONFIG_DATA);
+       ioport__unregister(PCI_CONFIG_ADDRESS);
+
+       return 0;
+}
diff --git a/tools/kvm/powerpc/boot.c b/tools/kvm/powerpc/boot.c
new file mode 100644 (file)
index 0000000..2557fc0
--- /dev/null
@@ -0,0 +1,8 @@
+#include "kvm/kvm.h"
+
+#include <stdbool.h>
+
+bool kvm__load_firmware(struct kvm *kvm, const char *firmware_filename)
+{
+       return false;
+}
diff --git a/tools/kvm/powerpc/cpu_info.c b/tools/kvm/powerpc/cpu_info.c
new file mode 100644 (file)
index 0000000..1f440a5
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * PPC CPU identification
+ *
+ * This is a very simple "host CPU info" struct to get us going.
+ * For the little host information we need, I don't want to grub about
+ * parsing stuff in /proc/device-tree so just match host PVR to differentiate
+ * PPC970 and POWER7 (which is all that's currently supported).
+ *
+ * Qemu does something similar but this is MUCH simpler!
+ *
+ * Copyright 2012 Matt Evans <matt@ozlabs.org>, IBM Corporation.
+ *
+ * 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 <kvm/kvm.h>
+#include <sys/ioctl.h>
+
+#include "cpu_info.h"
+#include "kvm/util.h"
+
+/* POWER7 */
+
+static struct cpu_info cpu_power7_info = {
+       .name = "POWER7",
+       .tb_freq = 512000000,
+       .d_bsize = 128,
+       .i_bsize = 128,
+       .flags = CPUINFO_FLAG_DFP | CPUINFO_FLAG_VSX | CPUINFO_FLAG_VMX,
+       .mmu_info = {
+               .flags = KVM_PPC_PAGE_SIZES_REAL | KVM_PPC_1T_SEGMENTS,
+               .slb_size = 32,
+       },
+};
+
+/* PPC970/G5 */
+
+static struct cpu_info cpu_970_info = {
+       .name = "G5",
+       .tb_freq = 33333333,
+       .d_bsize = 128,
+       .i_bsize = 128,
+       .flags = CPUINFO_FLAG_VMX,
+};
+
+/* This is a default catchall for 'no match' on PVR: */
+static struct cpu_info cpu_dummy_info = { .name = "unknown" };
+
+static struct pvr_info host_pvr_info[] = {
+       { 0xffffffff, 0x0f000003, &cpu_power7_info },
+       { 0xffff0000, 0x003f0000, &cpu_power7_info },
+       { 0xffff0000, 0x004a0000, &cpu_power7_info },
+       { 0xffff0000, 0x00390000, &cpu_970_info },
+       { 0xffff0000, 0x003c0000, &cpu_970_info },
+        { 0xffff0000, 0x00440000, &cpu_970_info },
+        { 0xffff0000, 0x00450000, &cpu_970_info },
+};
+
+/* If we can't query the kernel for supported page sizes assume 4K and 16M */
+static struct kvm_ppc_one_seg_page_size fallback_sps[] = {
+       [0] = {
+               .page_shift = 12,
+               .slb_enc    = 0,
+               .enc =  {
+                       [0] = {
+                               .page_shift = 12,
+                               .pte_enc    = 0,
+                       },
+               },
+       },
+       [1] = {
+               .page_shift = 24,
+               .slb_enc    = 0x100,
+               .enc =  {
+                       [0] = {
+                               .page_shift = 24,
+                               .pte_enc    = 0,
+                       },
+               },
+       },
+};
+
+
+static void setup_mmu_info(struct kvm *kvm, struct cpu_info *cpu_info)
+{
+       static struct kvm_ppc_smmu_info *mmu_info;
+       struct kvm_ppc_one_seg_page_size *sps;
+       int i, j, k, valid;
+
+       if (!kvm__supports_extension(kvm, KVM_CAP_PPC_GET_SMMU_INFO)) {
+               memcpy(&cpu_info->mmu_info.sps, fallback_sps, sizeof(fallback_sps));
+       } else if (ioctl(kvm->vm_fd, KVM_PPC_GET_SMMU_INFO, &cpu_info->mmu_info) < 0) {
+                       die_perror("KVM_PPC_GET_SMMU_INFO failed");
+       }
+
+       mmu_info = &cpu_info->mmu_info;
+
+       if (!(mmu_info->flags & KVM_PPC_PAGE_SIZES_REAL))
+               /* Guest pages are not restricted by the backing page size */
+               return;
+
+       /* Filter based on backing page size */
+
+       for (i = 0; i < KVM_PPC_PAGE_SIZES_MAX_SZ; i++) {
+               sps = &mmu_info->sps[i];
+
+               if (!sps->page_shift)
+                       break;
+
+               if (kvm->ram_pagesize < (1ul << sps->page_shift)) {
+                       /* Mark the whole segment size invalid */
+                       sps->page_shift = 0;
+                       continue;
+               }
+
+               /* Check each page size for the segment */
+               for (j = 0, valid = 0; j < KVM_PPC_PAGE_SIZES_MAX_SZ; j++) {
+                       if (!sps->enc[j].page_shift)
+                               break;
+
+                       if (kvm->ram_pagesize < (1ul << sps->enc[j].page_shift))
+                               sps->enc[j].page_shift = 0;
+                       else
+                               valid++;
+               }
+
+               if (!valid) {
+                       /* Mark the whole segment size invalid */
+                       sps->page_shift = 0;
+                       continue;
+               }
+
+               /* Mark any trailing entries invalid if we broke out early */
+               for (k = j; k < KVM_PPC_PAGE_SIZES_MAX_SZ; k++)
+                       sps->enc[k].page_shift = 0;
+
+               /* Collapse holes */
+               for (j = 0; j < KVM_PPC_PAGE_SIZES_MAX_SZ; j++) {
+                       if (sps->enc[j].page_shift)
+                               continue;
+
+                       for (k = j + 1; k < KVM_PPC_PAGE_SIZES_MAX_SZ; k++) {
+                               if (sps->enc[k].page_shift) {
+                                       sps->enc[j] = sps->enc[k];
+                                       sps->enc[k].page_shift = 0;
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       /* Mark any trailing entries invalid if we broke out early */
+       for (j = i; j < KVM_PPC_PAGE_SIZES_MAX_SZ; j++)
+               mmu_info->sps[j].page_shift = 0;
+
+       /* Collapse holes */
+       for (i = 0; i < KVM_PPC_PAGE_SIZES_MAX_SZ; i++) {
+               if (mmu_info->sps[i].page_shift)
+                       continue;
+
+               for (j = i + 1; j < KVM_PPC_PAGE_SIZES_MAX_SZ; j++) {
+                       if (mmu_info->sps[j].page_shift) {
+                               mmu_info->sps[i] = mmu_info->sps[j];
+                               mmu_info->sps[j].page_shift = 0;
+                               break;
+                       }
+               }
+       }
+}
+
+struct cpu_info *find_cpu_info(struct kvm *kvm)
+{
+       struct cpu_info *info;
+       unsigned int i;
+       u32 pvr = kvm->pvr;
+
+       for (info = NULL, i = 0; i < ARRAY_SIZE(host_pvr_info); i++) {
+               if ((pvr & host_pvr_info[i].pvr_mask) == host_pvr_info[i].pvr) {
+                       info = host_pvr_info[i].cpu_info;
+                       break;
+               }
+       }
+
+       /* Didn't find anything? Rut-ro. */
+       if (!info) {
+               pr_warning("Host CPU unsupported by kvmtool\n");
+               info = &cpu_dummy_info;
+       }
+
+       setup_mmu_info(kvm, info);
+
+       return info;
+}
diff --git a/tools/kvm/powerpc/cpu_info.h b/tools/kvm/powerpc/cpu_info.h
new file mode 100644 (file)
index 0000000..f61707a
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * PPC CPU identification
+ *
+ * Copyright 2012 Matt Evans <matt@ozlabs.org>, IBM Corporation.
+ *
+ * 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 CPU_INFO_H
+#define CPU_INFO_H
+
+#include <kvm/kvm.h>
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/kvm.h>
+
+struct cpu_info {
+       const char      *name;
+       u32             tb_freq; /* timebase frequency */
+       u32             d_bsize; /* d-cache block size */
+       u32             i_bsize; /* i-cache block size */
+       u32             flags;
+       struct kvm_ppc_smmu_info mmu_info;
+};
+
+struct pvr_info {
+       u32             pvr_mask;
+       u32             pvr;
+       struct cpu_info *cpu_info;
+};
+
+/* Misc capabilities/CPU properties */
+#define CPUINFO_FLAG_DFP       0x00000001
+#define CPUINFO_FLAG_VMX       0x00000002
+#define CPUINFO_FLAG_VSX       0x00000004
+
+struct cpu_info *find_cpu_info(struct kvm *kvm);
+
+#endif
diff --git a/tools/kvm/powerpc/include/kvm/barrier.h b/tools/kvm/powerpc/include/kvm/barrier.h
new file mode 100644 (file)
index 0000000..dd5115a
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _KVM_BARRIER_H_
+#define _KVM_BARRIER_H_
+
+#include <asm/barrier.h>
+
+#endif /* _KVM_BARRIER_H_ */
diff --git a/tools/kvm/powerpc/include/kvm/kvm-arch.h b/tools/kvm/powerpc/include/kvm/kvm-arch.h
new file mode 100644 (file)
index 0000000..316fe79
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * PPC64 architecture-specific definitions
+ *
+ * Copyright 2011 Matt Evans <matt@ozlabs.org>, IBM Corporation.
+ *
+ * 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 KVM__KVM_ARCH_H
+#define KVM__KVM_ARCH_H
+
+#include <stdbool.h>
+#include <linux/types.h>
+#include <time.h>
+
+/*
+ * MMIO lives after RAM, but it'd be nice if it didn't constantly move.
+ * Choose a suitably high address, e.g. 63T...  This limits RAM size.
+ */
+#define PPC_MMIO_START                 0x3F0000000000UL
+#define PPC_MMIO_SIZE                  0x010000000000UL
+
+#define KERNEL_LOAD_ADDR               0x0000000000000000
+#define KERNEL_START_ADDR              0x0000000000000000
+#define KERNEL_SECONDARY_START_ADDR     0x0000000000000060
+#define INITRD_LOAD_ADDR               0x0000000002800000
+
+#define FDT_MAX_SIZE                   0x10000
+#define RTAS_MAX_SIZE                  0x10000
+
+#define TIMEBASE_FREQ                  512000000ULL
+
+#define KVM_MMIO_START                 PPC_MMIO_START
+
+/*
+ * This is the address that pci_get_io_space_block() starts allocating
+ * from.  Note that this is a PCI bus address.
+ */
+#define KVM_PCI_MMIO_AREA              0x1000000
+#define KVM_VIRTIO_MMIO_AREA           0x2000000
+
+struct spapr_phb;
+
+struct kvm {
+       int                     sys_fd;         /* For system ioctls(), i.e. /dev/kvm */
+       int                     vm_fd;          /* For VM ioctls() */
+       timer_t                 timerid;        /* Posix timer for interrupts */
+
+       int                     nrcpus;         /* Number of cpus to run */
+
+       u32                     mem_slots;      /* for KVM_SET_USER_MEMORY_REGION */
+
+       u64                     ram_size;
+       void                    *ram_start;
+       u64                     ram_pagesize;
+
+       u64                     sdr1;
+       u32                     pvr;
+
+       bool                    nmi_disabled;
+
+       bool                    single_step;
+
+       const char              *vmlinux;
+       struct disk_image       **disks;
+       int                     nr_disks;
+       unsigned long           rtas_gra;
+       unsigned long           rtas_size;
+       unsigned long           fdt_gra;
+       unsigned long           initrd_gra;
+       unsigned long           initrd_size;
+       char                    *name;
+       int                     vm_state;
+       struct icp_state        *icp;
+       struct spapr_phb        *phb;
+};
+
+/* Helper for the various bits of code that generate FDT nodes */
+#define _FDT(exp)                                                      \
+       do {                                                            \
+               int ret = (exp);                                        \
+               if (ret < 0) {                                          \
+                       die("Error creating device tree: %s: %s\n",     \
+                           #exp, fdt_strerror(ret));                   \
+               }                                                       \
+       } while (0)
+
+#endif /* KVM__KVM_ARCH_H */
diff --git a/tools/kvm/powerpc/include/kvm/kvm-cpu-arch.h b/tools/kvm/powerpc/include/kvm/kvm-cpu-arch.h
new file mode 100644 (file)
index 0000000..7520c04
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * PPC64 cpu-specific definitions
+ *
+ * Copyright 2011 Matt Evans <matt@ozlabs.org>, IBM Corporation.
+ *
+ * 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 KVM__KVM_CPU_ARCH_H
+#define KVM__KVM_CPU_ARCH_H
+
+/* Architecture-specific kvm_cpu definitions. */
+
+#include <linux/kvm.h> /* for struct kvm_regs */
+#include <stdbool.h>
+#include <pthread.h>
+
+#define MSR_SF         (1UL<<63)
+#define MSR_HV         (1UL<<60)
+#define MSR_VEC                (1UL<<25)
+#define MSR_VSX                (1UL<<23)
+#define MSR_POW                (1UL<<18)
+#define MSR_EE         (1UL<<15)
+#define MSR_PR         (1UL<<14)
+#define MSR_FP         (1UL<<13)
+#define MSR_ME         (1UL<<12)
+#define MSR_FE0                (1UL<<11)
+#define MSR_SE         (1UL<<10)
+#define MSR_BE         (1UL<<9)
+#define MSR_FE1                (1UL<<8)
+#define MSR_IR         (1UL<<5)
+#define MSR_DR         (1UL<<4)
+#define MSR_PMM                (1UL<<2)
+#define MSR_RI         (1UL<<1)
+#define MSR_LE         (1UL<<0)
+
+#define POWER7_EXT_IRQ 0
+
+struct kvm;
+
+struct kvm_cpu {
+       pthread_t               thread;         /* VCPU thread */
+
+       unsigned long           cpu_id;
+
+       struct kvm              *kvm;           /* parent KVM */
+       int                     vcpu_fd;        /* For VCPU ioctls() */
+       struct kvm_run          *kvm_run;
+
+       struct kvm_regs         regs;
+       struct kvm_sregs        sregs;
+       struct kvm_fpu          fpu;
+
+       u8                      is_running;
+       u8                      paused;
+       u8                      needs_nmi;
+       /*
+        * Although PPC KVM doesn't yet support coalesced MMIO, generic code
+        * needs this in our kvm_cpu:
+        */
+       struct kvm_coalesced_mmio_ring  *ring;
+};
+
+void kvm_cpu__irq(struct kvm_cpu *vcpu, int pin, int level);
+
+/* This is never actually called on PPC. */
+static inline bool kvm_cpu__emulate_io(struct kvm *kvm, u16 port, void *data, int direction, int size, u32 count)
+{
+       return false;
+}
+
+bool kvm_cpu__emulate_mmio(struct kvm *kvm, u64 phys_addr, u8 *data, u32 len, u8 is_write);
+
+#endif /* KVM__KVM_CPU_ARCH_H */
diff --git a/tools/kvm/powerpc/ioport.c b/tools/kvm/powerpc/ioport.c
new file mode 100644 (file)
index 0000000..a8e4dc3
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * PPC64 ioport platform setup.  There isn't any! :-)
+ *
+ * Copyright 2011 Matt Evans <matt@ozlabs.org>, IBM Corporation.
+ *
+ * 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 "kvm/ioport.h"
+
+#include <stdlib.h>
+
+void ioport__setup_arch(void)
+{
+       /* PPC has no legacy ioports to set up */
+}
diff --git a/tools/kvm/powerpc/irq.c b/tools/kvm/powerpc/irq.c
new file mode 100644 (file)
index 0000000..7da4012
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * PPC64 IRQ routines
+ *
+ * Copyright 2011 Matt Evans <matt@ozlabs.org>, IBM Corporation.
+ *
+ * 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 "kvm/irq.h"
+#include "kvm/kvm.h"
+#include "kvm/util.h"
+
+#include <linux/types.h>
+#include <linux/rbtree.h>
+#include <linux/list.h>
+#include <linux/kvm.h>
+#include <sys/ioctl.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include "kvm/pci.h"
+
+#include "xics.h"
+#include "spapr_pci.h"
+
+#define XICS_IRQS               1024
+
+/*
+ * FIXME: The code in this file assumes an SPAPR guest, using XICS.  Make
+ * generic & cope with multiple PPC platform types.
+ */
+
+static int pci_devs = 0;
+
+int irq__register_device(u32 dev, u8 *num, u8 *pin, u8 *line)
+{
+       if (pci_devs >= PCI_MAX_DEVICES)
+               die("Hit PCI device limit!\n");
+
+       *num = pci_devs++;
+
+       *pin = 1;
+       /*
+        * Have I said how nasty I find this?  Line should be dontcare... PHB
+        * should determine which CPU/XICS IRQ to fire.
+        */
+       *line = xics_alloc_irqnum();
+       return 0;
+}
+
+int irq__init(struct kvm *kvm)
+{
+       /*
+        * kvm->nr_cpus is now valid; for /now/, pass
+        * this to xics_system_init(), which assumes servers
+        * are numbered 0..nrcpus.  This may not really be true,
+        * but it is OK currently.
+        */
+       kvm->icp = xics_system_init(XICS_IRQS, kvm->nrcpus);
+       return 0;
+}
+
+int irq__exit(struct kvm *kvm)
+{
+       return 0;
+}
+
+int irq__add_msix_route(struct kvm *kvm, struct msi_msg *msg)
+{
+       die(__FUNCTION__);
+       return 0;
+}
diff --git a/tools/kvm/powerpc/kvm-cpu.c b/tools/kvm/powerpc/kvm-cpu.c
new file mode 100644 (file)
index 0000000..97fc759
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+ * PPC64 processor support
+ *
+ * Copyright 2011 Matt Evans <matt@ozlabs.org>, IBM Corporation.
+ *
+ * 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 "kvm/kvm-cpu.h"
+
+#include "kvm/symbol.h"
+#include "kvm/util.h"
+#include "kvm/kvm.h"
+
+#include "spapr.h"
+#include "spapr_pci.h"
+#include "xics.h"
+
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <assert.h>
+
+static int debug_fd;
+
+void kvm_cpu__set_debug_fd(int fd)
+{
+       debug_fd = fd;
+}
+
+int kvm_cpu__get_debug_fd(void)
+{
+       return debug_fd;
+}
+
+static struct kvm_cpu *kvm_cpu__new(struct kvm *kvm)
+{
+       struct kvm_cpu *vcpu;
+
+       vcpu            = calloc(1, sizeof *vcpu);
+       if (!vcpu)
+               return NULL;
+
+       vcpu->kvm       = kvm;
+
+       return vcpu;
+}
+
+void kvm_cpu__delete(struct kvm_cpu *vcpu)
+{
+       free(vcpu);
+}
+
+struct kvm_cpu *kvm_cpu__init(struct kvm *kvm, unsigned long cpu_id)
+{
+       struct kvm_cpu *vcpu;
+       int mmap_size;
+       struct kvm_enable_cap papr_cap = { .cap = KVM_CAP_PPC_PAPR };
+
+       vcpu            = kvm_cpu__new(kvm);
+       if (!vcpu)
+               return NULL;
+
+       vcpu->cpu_id    = cpu_id;
+
+       vcpu->vcpu_fd = ioctl(vcpu->kvm->vm_fd, KVM_CREATE_VCPU, cpu_id);
+       if (vcpu->vcpu_fd < 0)
+               die_perror("KVM_CREATE_VCPU ioctl");
+
+       mmap_size = ioctl(vcpu->kvm->sys_fd, KVM_GET_VCPU_MMAP_SIZE, 0);
+       if (mmap_size < 0)
+               die_perror("KVM_GET_VCPU_MMAP_SIZE ioctl");
+
+       vcpu->kvm_run = mmap(NULL, mmap_size, PROT_RW, MAP_SHARED, vcpu->vcpu_fd, 0);
+       if (vcpu->kvm_run == MAP_FAILED)
+               die("unable to mmap vcpu fd");
+
+       if (ioctl(vcpu->vcpu_fd, KVM_ENABLE_CAP, &papr_cap) < 0)
+               die("unable to enable PAPR capability");
+
+       /*
+        * We start all CPUs, directing non-primary threads into the kernel's
+        * secondary start point.  When we come to support SLOF, we will start
+        * only one and SLOF will RTAS call us to ask for others to be
+        * started.  (FIXME: make more generic & interface with whichever
+        * firmware a platform may be using.)
+        */
+       vcpu->is_running = true;
+
+       /* Register with IRQ controller (FIXME, assumes XICS) */
+       xics_cpu_register(vcpu);
+
+       return vcpu;
+}
+
+static void kvm_cpu__setup_fpu(struct kvm_cpu *vcpu)
+{
+       /* Don't have to do anything, there's no expected FPU state. */
+}
+
+static void kvm_cpu__setup_regs(struct kvm_cpu *vcpu)
+{
+       /*
+        * FIXME: This assumes PPC64 and Linux guest.  It doesn't use the
+        * OpenFirmware entry method, but instead the "embedded" entry which
+        * passes the FDT address directly.
+        */
+       struct kvm_regs *r = &vcpu->regs;
+
+       if (vcpu->cpu_id == 0) {
+               r->pc = KERNEL_START_ADDR;
+               r->gpr[3] = vcpu->kvm->fdt_gra;
+               r->gpr[5] = 0;
+       } else {
+               r->pc = KERNEL_SECONDARY_START_ADDR;
+               r->gpr[3] = vcpu->cpu_id;
+       }
+       r->msr = 0x8000000000001000UL; /* 64bit, non-HV, ME */
+
+       if (ioctl(vcpu->vcpu_fd, KVM_SET_REGS, &vcpu->regs) < 0)
+               die_perror("KVM_SET_REGS failed");
+}
+
+static void kvm_cpu__setup_sregs(struct kvm_cpu *vcpu)
+{
+       /*
+        * Some sregs setup to initialise SDR1/PVR/HIOR on PPC64 SPAPR
+        * platforms using PR KVM.  (Technically, this is all ignored on
+        * SPAPR HV KVM.)  Different setup is required for non-PV non-SPAPR
+        * platforms!  (FIXME.)
+        */
+       struct kvm_sregs sregs;
+       struct kvm_one_reg reg = {};
+       u64 value;
+
+       if (ioctl(vcpu->vcpu_fd, KVM_GET_SREGS, &sregs) < 0)
+               die("KVM_GET_SREGS failed");
+
+       sregs.u.s.sdr1 = vcpu->kvm->sdr1;
+       sregs.pvr = vcpu->kvm->pvr;
+
+       if (ioctl(vcpu->vcpu_fd, KVM_SET_SREGS, &sregs) < 0)
+               die("KVM_SET_SREGS failed");
+
+       reg.id = KVM_REG_PPC_HIOR;
+       value = 0;
+       reg.addr = (u64)&value;
+       if (ioctl(vcpu->vcpu_fd, KVM_SET_ONE_REG, &reg) < 0)
+               die("KVM_SET_ONE_REG failed");
+}
+
+/**
+ * kvm_cpu__reset_vcpu - reset virtual CPU to a known state
+ */
+void kvm_cpu__reset_vcpu(struct kvm_cpu *vcpu)
+{
+       kvm_cpu__setup_regs(vcpu);
+       kvm_cpu__setup_sregs(vcpu);
+       kvm_cpu__setup_fpu(vcpu);
+}
+
+/* kvm_cpu__irq - set KVM's IRQ flag on this vcpu */
+void kvm_cpu__irq(struct kvm_cpu *vcpu, int pin, int level)
+{
+       unsigned int virq = level ? KVM_INTERRUPT_SET_LEVEL : KVM_INTERRUPT_UNSET;
+
+       /* FIXME: POWER-specific */
+       if (pin != POWER7_EXT_IRQ)
+               return;
+       if (ioctl(vcpu->vcpu_fd, KVM_INTERRUPT, &virq) < 0)
+               pr_warning("Could not KVM_INTERRUPT.");
+}
+
+void kvm_cpu__arch_nmi(struct kvm_cpu *cpu)
+{
+}
+
+bool kvm_cpu__handle_exit(struct kvm_cpu *vcpu)
+{
+       bool ret = true;
+       struct kvm_run *run = vcpu->kvm_run;
+       switch(run->exit_reason) {
+       case KVM_EXIT_PAPR_HCALL:
+               run->papr_hcall.ret = spapr_hypercall(vcpu, run->papr_hcall.nr,
+                                                     (target_ulong*)run->papr_hcall.args);
+               break;
+       default:
+               ret = false;
+       }
+       return ret;
+}
+
+bool kvm_cpu__emulate_mmio(struct kvm *kvm, u64 phys_addr, u8 *data, u32 len, u8 is_write)
+{
+       /*
+        * FIXME: This function will need to be split in order to support
+        * various PowerPC platforms/PHB types, etc.  It currently assumes SPAPR
+        * PPC64 guest.
+        */
+       bool ret = false;
+
+       if ((phys_addr >= SPAPR_PCI_WIN_START) &&
+           (phys_addr < SPAPR_PCI_WIN_END)) {
+               ret = spapr_phb_mmio(kvm, phys_addr, data, len, is_write);
+       } else {
+               pr_warning("MMIO %s unknown address %llx (size %d)!\n",
+                          is_write ? "write to" : "read from",
+                          phys_addr, len);
+       }
+       return ret;
+}
+
+#define CONDSTR_BIT(m, b) (((m) & MSR_##b) ? #b" " : "")
+
+void kvm_cpu__show_registers(struct kvm_cpu *vcpu)
+{
+       struct kvm_regs regs;
+       struct kvm_sregs sregs;
+       int r;
+
+       if (ioctl(vcpu->vcpu_fd, KVM_GET_REGS, &regs) < 0)
+               die("KVM_GET_REGS failed");
+        if (ioctl(vcpu->vcpu_fd, KVM_GET_SREGS, &sregs) < 0)
+               die("KVM_GET_SREGS failed");
+
+       dprintf(debug_fd, "\n Registers:\n");
+       dprintf(debug_fd, " NIP:   %016llx  MSR:   %016llx "
+               "( %s%s%s%s%s%s%s%s%s%s%s%s)\n",
+               regs.pc, regs.msr,
+               CONDSTR_BIT(regs.msr, SF),
+               CONDSTR_BIT(regs.msr, HV), /* ! */
+               CONDSTR_BIT(regs.msr, VEC),
+               CONDSTR_BIT(regs.msr, VSX),
+               CONDSTR_BIT(regs.msr, EE),
+               CONDSTR_BIT(regs.msr, PR),
+               CONDSTR_BIT(regs.msr, FP),
+               CONDSTR_BIT(regs.msr, ME),
+               CONDSTR_BIT(regs.msr, IR),
+               CONDSTR_BIT(regs.msr, DR),
+               CONDSTR_BIT(regs.msr, RI),
+               CONDSTR_BIT(regs.msr, LE));
+       dprintf(debug_fd, " CTR:   %016llx  LR:    %016llx  CR:   %08llx\n",
+               regs.ctr, regs.lr, regs.cr);
+       dprintf(debug_fd, " SRR0:  %016llx  SRR1:  %016llx  XER:  %016llx\n",
+               regs.srr0, regs.srr1, regs.xer);
+       dprintf(debug_fd, " SPRG0: %016llx  SPRG1: %016llx\n",
+               regs.sprg0, regs.sprg1);
+       dprintf(debug_fd, " SPRG2: %016llx  SPRG3: %016llx\n",
+               regs.sprg2, regs.sprg3);
+       dprintf(debug_fd, " SPRG4: %016llx  SPRG5: %016llx\n",
+               regs.sprg4, regs.sprg5);
+       dprintf(debug_fd, " SPRG6: %016llx  SPRG7: %016llx\n",
+               regs.sprg6, regs.sprg7);
+       dprintf(debug_fd, " GPRs:\n ");
+       for (r = 0; r < 32; r++) {
+               dprintf(debug_fd, "%016llx  ", regs.gpr[r]);
+               if ((r & 3) == 3)
+                       dprintf(debug_fd, "\n ");
+       }
+       dprintf(debug_fd, "\n");
+
+       /* FIXME: Assumes SLB-based (book3s) guest */
+       for (r = 0; r < 32; r++) {
+               dprintf(debug_fd, " SLB%02d  %016llx %016llx\n", r,
+                       sregs.u.s.ppc64.slb[r].slbe,
+                       sregs.u.s.ppc64.slb[r].slbv);
+       }
+       dprintf(debug_fd, "----------\n");
+}
+
+void kvm_cpu__show_code(struct kvm_cpu *vcpu)
+{
+       if (ioctl(vcpu->vcpu_fd, KVM_GET_REGS, &vcpu->regs) < 0)
+               die("KVM_GET_REGS failed");
+
+       /* FIXME: Dump/disassemble some code...! */
+
+       dprintf(debug_fd, "\n Stack:\n");
+       dprintf(debug_fd,   " ------\n");
+       /* Only works in real mode: */
+       kvm__dump_mem(vcpu->kvm, vcpu->regs.gpr[1], 32);
+}
+
+void kvm_cpu__show_page_tables(struct kvm_cpu *vcpu)
+{
+       /* Does nothing yet */
+}
diff --git a/tools/kvm/powerpc/kvm.c b/tools/kvm/powerpc/kvm.c
new file mode 100644 (file)
index 0000000..83b8edd
--- /dev/null
@@ -0,0 +1,529 @@
+/*
+ * PPC64 (SPAPR) platform support
+ *
+ * Copyright 2011 Matt Evans <matt@ozlabs.org>, IBM Corporation.
+ *
+ * Portions of FDT setup borrowed from QEMU, copyright 2010 David Gibson, IBM
+ * Corporation.
+ *
+ * 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 "kvm/kvm.h"
+#include "kvm/util.h"
+#include "libfdt.h"
+#include "cpu_info.h"
+
+#include "spapr.h"
+#include "spapr_hvcons.h"
+#include "spapr_pci.h"
+
+#include <linux/kvm.h>
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <asm/unistd.h>
+#include <errno.h>
+
+#include <linux/byteorder.h>
+
+#define HPT_ORDER 24
+
+#define HUGETLBFS_PATH "/var/lib/hugetlbfs/global/pagesize-16MB/"
+
+#define PHANDLE_XICP           0x00001111
+
+static char kern_cmdline[2048];
+
+struct kvm_ext kvm_req_ext[] = {
+       { DEFINE_KVM_EXT(KVM_CAP_PPC_UNSET_IRQ) },
+       { DEFINE_KVM_EXT(KVM_CAP_PPC_IRQ_LEVEL) },
+       { 0, 0 }
+};
+
+static uint32_t mfpvr(void)
+{
+       uint32_t r;
+       asm volatile ("mfpvr %0" : "=r"(r));
+       return r;
+}
+
+bool kvm__arch_cpu_supports_vm(void)
+{
+       return true;
+}
+
+void kvm__init_ram(struct kvm *kvm)
+{
+       u64     phys_start, phys_size;
+       void    *host_mem;
+
+       phys_start = 0;
+       phys_size  = kvm->ram_size;
+       host_mem   = kvm->ram_start;
+
+       /*
+        * We put MMIO at PPC_MMIO_START, high up.  Make sure that this doesn't
+        * crash into the end of RAM -- on PPC64 at least, this is so high
+        * (63TB!) that this is unlikely.
+        */
+       if (phys_size >= PPC_MMIO_START)
+               die("Too much memory (%lld, what a nice problem): "
+                   "overlaps MMIO!\n",
+                   phys_size);
+
+       kvm__register_mem(kvm, phys_start, phys_size, host_mem);
+}
+
+void kvm__arch_set_cmdline(char *cmdline, bool video)
+{
+       /* We don't need anything unusual in here. */
+}
+
+/* Architecture-specific KVM init */
+void kvm__arch_init(struct kvm *kvm, const char *hugetlbfs_path, u64 ram_size)
+{
+       int cap_ppc_rma;
+       unsigned long hpt;
+
+       kvm->ram_size           = ram_size;
+
+       /* Map "default" hugetblfs path to the standard 16M mount point */
+       if (hugetlbfs_path && !strcmp(hugetlbfs_path, "default"))
+               hugetlbfs_path = HUGETLBFS_PATH;
+
+       kvm->ram_start = mmap_anon_or_hugetlbfs(kvm, hugetlbfs_path, kvm->ram_size);
+
+       if (kvm->ram_start == MAP_FAILED)
+               die("Couldn't map %lld bytes for RAM (%d)\n",
+                   kvm->ram_size, errno);
+
+       /* FDT goes at top of memory, RTAS just below */
+       kvm->fdt_gra = kvm->ram_size - FDT_MAX_SIZE;
+       /* FIXME: Not all PPC systems have RTAS */
+       kvm->rtas_gra = kvm->fdt_gra - RTAS_MAX_SIZE;
+       madvise(kvm->ram_start, kvm->ram_size, MADV_MERGEABLE);
+
+       /* FIXME:  SPAPR-PR specific; allocate a guest HPT. */
+       if (posix_memalign((void **)&hpt, (1<<HPT_ORDER), (1<<HPT_ORDER)))
+               die("Can't allocate %d bytes for HPT\n", (1<<HPT_ORDER));
+
+       kvm->sdr1 = ((hpt + 0x3ffffULL) & ~0x3ffffULL) | (HPT_ORDER-18);
+
+       kvm->pvr = mfpvr();
+
+       /* FIXME: This is book3s-specific */
+       cap_ppc_rma = ioctl(kvm->sys_fd, KVM_CHECK_EXTENSION, KVM_CAP_PPC_RMA);
+       if (cap_ppc_rma == 2)
+               die("Need contiguous RMA allocation on this hardware, "
+                   "which is not yet supported.");
+
+       /* Do these before FDT setup, IRQ setup, etc. */
+       /* FIXME: SPAPR-specific */
+       hypercall_init();
+       register_core_rtas();
+       /* Now that hypercalls are initialised, register a couple for the console: */
+       spapr_hvcons_init();
+       spapr_create_phb(kvm, "pci", SPAPR_PCI_BUID,
+                        SPAPR_PCI_MEM_WIN_ADDR,
+                        SPAPR_PCI_MEM_WIN_SIZE,
+                        SPAPR_PCI_IO_WIN_ADDR,
+                        SPAPR_PCI_IO_WIN_SIZE);
+}
+
+void kvm__arch_delete_ram(struct kvm *kvm)
+{
+       munmap(kvm->ram_start, kvm->ram_size);
+}
+
+void kvm__irq_trigger(struct kvm *kvm, int irq)
+{
+       kvm__irq_line(kvm, irq, 1);
+       kvm__irq_line(kvm, irq, 0);
+}
+
+void kvm__arch_periodic_poll(struct kvm *kvm)
+{
+       /* FIXME: Should register callbacks to platform-specific polls */
+       spapr_hvcons_poll(kvm);
+}
+
+int load_flat_binary(struct kvm *kvm, int fd_kernel, int fd_initrd, const char *kernel_cmdline)
+{
+       void *p;
+       void *k_start;
+       void *i_start;
+       int nr;
+
+       if (lseek(fd_kernel, 0, SEEK_SET) < 0)
+               die_perror("lseek");
+
+       p = k_start = guest_flat_to_host(kvm, KERNEL_LOAD_ADDR);
+
+       while ((nr = read(fd_kernel, p, 65536)) > 0)
+               p += nr;
+
+       pr_info("Loaded kernel to 0x%x (%ld bytes)", KERNEL_LOAD_ADDR, p-k_start);
+
+       if (fd_initrd != -1) {
+               if (lseek(fd_initrd, 0, SEEK_SET) < 0)
+                       die_perror("lseek");
+
+               if (p-k_start > INITRD_LOAD_ADDR)
+                       die("Kernel overlaps initrd!");
+
+               /* Round up kernel size to 8byte alignment, and load initrd right after. */
+               i_start = p = guest_flat_to_host(kvm, INITRD_LOAD_ADDR);
+
+               while (((nr = read(fd_initrd, p, 65536)) > 0) &&
+                      p < (kvm->ram_start + kvm->ram_size))
+                       p += nr;
+
+               if (p >= (kvm->ram_start + kvm->ram_size))
+                       die("initrd too big to contain in guest RAM.\n");
+
+               pr_info("Loaded initrd to 0x%x (%ld bytes)",
+                       INITRD_LOAD_ADDR, p-i_start);
+               kvm->initrd_gra = INITRD_LOAD_ADDR;
+               kvm->initrd_size = p-i_start;
+       } else {
+               kvm->initrd_size = 0;
+       }
+       strncpy(kern_cmdline, kernel_cmdline, 2048);
+       kern_cmdline[2047] = '\0';
+
+       return true;
+}
+
+bool load_bzimage(struct kvm *kvm, int fd_kernel,
+                 int fd_initrd, const char *kernel_cmdline, u16 vidmode)
+{
+       /* We don't support bzImages. */
+       return false;
+}
+
+struct fdt_prop {
+       void *value;
+       int size;
+};
+
+static void generate_segment_page_sizes(struct kvm_ppc_smmu_info *info, struct fdt_prop *prop)
+{
+       struct kvm_ppc_one_seg_page_size *sps;
+       int i, j, size;
+       u32 *p;
+
+       for (size = 0, i = 0; i < KVM_PPC_PAGE_SIZES_MAX_SZ; i++) {
+               sps = &info->sps[i];
+
+               if (sps->page_shift == 0)
+                       break;
+
+               /* page shift, slb enc & count */
+               size += 3;
+
+               for (j = 0; j < KVM_PPC_PAGE_SIZES_MAX_SZ; j++) {
+                       if (info->sps[i].enc[j].page_shift == 0)
+                               break;
+
+                       /* page shift & pte enc */
+                       size += 2;
+               }
+       }
+
+       if (!size) {
+               prop->value = NULL;
+               prop->size = 0;
+               return;
+       }
+
+       /* Convert size to bytes */
+       prop->size = size * sizeof(u32);
+
+       prop->value = malloc(prop->size);
+       if (!prop->value)
+               die_perror("malloc failed");
+
+       p = (u32 *)prop->value;
+       for (i = 0; i < KVM_PPC_PAGE_SIZES_MAX_SZ; i++) {
+               sps = &info->sps[i];
+
+               if (sps->page_shift == 0)
+                       break;
+
+               *p++ = sps->page_shift;
+               *p++ = sps->slb_enc;
+
+               for (j = 0; j < KVM_PPC_PAGE_SIZES_MAX_SZ; j++)
+                       if (!info->sps[i].enc[j].page_shift)
+                               break;
+
+               *p++ = j;       /* count of enc */
+
+               for (j = 0; j < KVM_PPC_PAGE_SIZES_MAX_SZ; j++) {
+                       if (!info->sps[i].enc[j].page_shift)
+                               break;
+
+                       *p++ = info->sps[i].enc[j].page_shift;
+                       *p++ = info->sps[i].enc[j].pte_enc;
+               }
+       }
+}
+
+#define SMT_THREADS 4
+
+/*
+ * Set up the FDT for the kernel: This function is currently fairly SPAPR-heavy,
+ * and whilst most PPC targets will require CPU/memory nodes, others like RTAS
+ * should eventually be added separately.
+ */
+static void setup_fdt(struct kvm *kvm)
+{
+       uint64_t        mem_reg_property[] = { 0, cpu_to_be64(kvm->ram_size) };
+       int             smp_cpus = kvm->nrcpus;
+       uint32_t        int_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)};
+       char            hypertas_prop_kvm[] = "hcall-pft\0hcall-term\0"
+               "hcall-dabr\0hcall-interrupt\0hcall-tce\0hcall-vio\0"
+               "hcall-splpar\0hcall-bulk";
+       int             i, j;
+       char            cpu_name[30];
+       u8              staging_fdt[FDT_MAX_SIZE];
+       struct cpu_info *cpu_info = find_cpu_info(kvm);
+       struct fdt_prop segment_page_sizes;
+       u32 segment_sizes_1T[] = {0x1c, 0x28, 0xffffffff, 0xffffffff};
+
+       /* Generate an appropriate DT at kvm->fdt_gra */
+       void *fdt_dest = guest_flat_to_host(kvm, kvm->fdt_gra);
+       void *fdt = staging_fdt;
+
+       _FDT(fdt_create(fdt, FDT_MAX_SIZE));
+       _FDT(fdt_finish_reservemap(fdt));
+
+       _FDT(fdt_begin_node(fdt, ""));
+
+       _FDT(fdt_property_string(fdt, "device_type", "chrp"));
+       _FDT(fdt_property_string(fdt, "model", "IBM pSeries (kvmtool)"));
+       _FDT(fdt_property_cell(fdt, "#address-cells", 0x2));
+       _FDT(fdt_property_cell(fdt, "#size-cells", 0x2));
+
+       /* RTAS */
+       _FDT(fdt_begin_node(fdt, "rtas"));
+       /* This is what the kernel uses to switch 'We're an LPAR'! */
+        _FDT(fdt_property(fdt, "ibm,hypertas-functions", hypertas_prop_kvm,
+                           sizeof(hypertas_prop_kvm)));
+       _FDT(fdt_property_cell(fdt, "linux,rtas-base", kvm->rtas_gra));
+       _FDT(fdt_property_cell(fdt, "linux,rtas-entry", kvm->rtas_gra));
+       _FDT(fdt_property_cell(fdt, "rtas-size", kvm->rtas_size));
+       /* Now add properties for all RTAS tokens: */
+       if (spapr_rtas_fdt_setup(kvm, fdt))
+               die("Couldn't create RTAS FDT properties\n");
+
+       _FDT(fdt_end_node(fdt));
+
+       /* /chosen */
+       _FDT(fdt_begin_node(fdt, "chosen"));
+       /* cmdline */
+       _FDT(fdt_property_string(fdt, "bootargs", kern_cmdline));
+       /* Initrd */
+       if (kvm->initrd_size != 0) {
+               uint32_t ird_st_prop = cpu_to_be32(kvm->initrd_gra);
+               uint32_t ird_end_prop = cpu_to_be32(kvm->initrd_gra +
+                                                   kvm->initrd_size);
+               _FDT(fdt_property(fdt, "linux,initrd-start",
+                                  &ird_st_prop, sizeof(ird_st_prop)));
+               _FDT(fdt_property(fdt, "linux,initrd-end",
+                                  &ird_end_prop, sizeof(ird_end_prop)));
+       }
+
+       /*
+        * stdout-path: This is assuming we're using the HV console.  Also, the
+        * address is hardwired until we do a VIO bus.
+        */
+       _FDT(fdt_property_string(fdt, "linux,stdout-path",
+                                "/vdevice/vty@30000000"));
+       _FDT(fdt_end_node(fdt));
+
+       /*
+        * Memory: We don't alloc. a separate RMA yet.  If we ever need to
+        * (CAP_PPC_RMA == 2) then have one memory node for 0->RMAsize, and
+        * another RMAsize->endOfMem.
+        */
+       _FDT(fdt_begin_node(fdt, "memory@0"));
+       _FDT(fdt_property_string(fdt, "device_type", "memory"));
+       _FDT(fdt_property(fdt, "reg", mem_reg_property,
+                         sizeof(mem_reg_property)));
+       _FDT(fdt_end_node(fdt));
+
+       generate_segment_page_sizes(&cpu_info->mmu_info, &segment_page_sizes);
+
+       /* CPUs */
+       _FDT(fdt_begin_node(fdt, "cpus"));
+       _FDT(fdt_property_cell(fdt, "#address-cells", 0x1));
+       _FDT(fdt_property_cell(fdt, "#size-cells", 0x0));
+
+       for (i = 0; i < smp_cpus; i += SMT_THREADS) {
+               int32_t pft_size_prop[] = { 0, HPT_ORDER };
+               uint32_t servers_prop[SMT_THREADS];
+               uint32_t gservers_prop[SMT_THREADS * 2];
+               int threads = (smp_cpus - i) >= SMT_THREADS ? SMT_THREADS :
+                       smp_cpus - i;
+
+               sprintf(cpu_name, "PowerPC,%s@%d", cpu_info->name, i);
+               _FDT(fdt_begin_node(fdt, cpu_name));
+               sprintf(cpu_name, "PowerPC,%s", cpu_info->name);
+               _FDT(fdt_property_string(fdt, "name", cpu_name));
+               _FDT(fdt_property_string(fdt, "device_type", "cpu"));
+
+               _FDT(fdt_property_cell(fdt, "reg", i));
+               _FDT(fdt_property_cell(fdt, "cpu-version", kvm->pvr));
+
+               _FDT(fdt_property_cell(fdt, "dcache-block-size", cpu_info->d_bsize));
+               _FDT(fdt_property_cell(fdt, "icache-block-size", cpu_info->i_bsize));
+
+               _FDT(fdt_property_cell(fdt, "timebase-frequency", cpu_info->tb_freq));
+               /* Lies, but safeish lies! */
+               _FDT(fdt_property_cell(fdt, "clock-frequency", 0xddbab200));
+
+               if (cpu_info->mmu_info.slb_size)
+                       _FDT(fdt_property_cell(fdt, "ibm,slb-size", cpu_info->mmu_info.slb_size));
+
+               /*
+                * HPT size is hardwired; KVM currently fixes it at 16MB but the
+                * moment that changes we'll need to read it out of the kernel.
+                */
+               _FDT(fdt_property(fdt, "ibm,pft-size", pft_size_prop,
+                                 sizeof(pft_size_prop)));
+
+               _FDT(fdt_property_string(fdt, "status", "okay"));
+               _FDT(fdt_property(fdt, "64-bit", NULL, 0));
+               /* A server for each thread in this core */
+               for (j = 0; j < SMT_THREADS; j++) {
+                       servers_prop[j] = cpu_to_be32(i+j);
+                       /*
+                        * Hack borrowed from QEMU, direct the group queues back
+                        * to cpu 0:
+                        */
+                       gservers_prop[j*2] = cpu_to_be32(i+j);
+                       gservers_prop[j*2 + 1] = 0;
+               }
+               _FDT(fdt_property(fdt, "ibm,ppc-interrupt-server#s",
+                                  servers_prop, threads * sizeof(uint32_t)));
+               _FDT(fdt_property(fdt, "ibm,ppc-interrupt-gserver#s",
+                                 gservers_prop,
+                                 threads * 2 * sizeof(uint32_t)));
+
+               if (segment_page_sizes.value)
+                       _FDT(fdt_property(fdt, "ibm,segment-page-sizes",
+                                         segment_page_sizes.value,
+                                         segment_page_sizes.size));
+
+               if (cpu_info->mmu_info.flags & KVM_PPC_1T_SEGMENTS)
+                       _FDT(fdt_property(fdt, "ibm,processor-segment-sizes",
+                                         segment_sizes_1T, sizeof(segment_sizes_1T)));
+
+               /* VSX / DFP options: */
+               if (cpu_info->flags & CPUINFO_FLAG_VMX)
+                       _FDT(fdt_property_cell(fdt, "ibm,vmx",
+                                              (cpu_info->flags &
+                                               CPUINFO_FLAG_VSX) ? 2 : 1));
+               if (cpu_info->flags & CPUINFO_FLAG_DFP)
+                       _FDT(fdt_property_cell(fdt, "ibm,dfp", 0x1));
+               _FDT(fdt_end_node(fdt));
+       }
+       _FDT(fdt_end_node(fdt));
+
+       /* IRQ controller */
+       _FDT(fdt_begin_node(fdt, "interrupt-controller@0"));
+
+       _FDT(fdt_property_string(fdt, "device_type",
+                                "PowerPC-External-Interrupt-Presentation"));
+       _FDT(fdt_property_string(fdt, "compatible", "IBM,ppc-xicp"));
+       _FDT(fdt_property_cell(fdt, "reg", 0));
+       _FDT(fdt_property(fdt, "interrupt-controller", NULL, 0));
+       _FDT(fdt_property(fdt, "ibm,interrupt-server-ranges",
+                          int_server_ranges_prop,
+                          sizeof(int_server_ranges_prop)));
+       _FDT(fdt_property_cell(fdt, "#interrupt-cells", 2));
+       _FDT(fdt_property_cell(fdt, "linux,phandle", PHANDLE_XICP));
+       _FDT(fdt_property_cell(fdt, "phandle", PHANDLE_XICP));
+       _FDT(fdt_end_node(fdt));
+
+       /*
+        * VIO: See comment in linux,stdout-path; we don't yet represent a VIO
+        * bus/address allocation so addresses are hardwired here.
+        */
+       _FDT(fdt_begin_node(fdt, "vdevice"));
+       _FDT(fdt_property_cell(fdt, "#address-cells", 0x1));
+       _FDT(fdt_property_cell(fdt, "#size-cells", 0x0));
+       _FDT(fdt_property_string(fdt, "device_type", "vdevice"));
+       _FDT(fdt_property_string(fdt, "compatible", "IBM,vdevice"));
+       _FDT(fdt_begin_node(fdt, "vty@30000000"));
+       _FDT(fdt_property_string(fdt, "name", "vty"));
+       _FDT(fdt_property_string(fdt, "device_type", "serial"));
+       _FDT(fdt_property_string(fdt, "compatible", "hvterm1"));
+       _FDT(fdt_property_cell(fdt, "reg", 0x30000000));
+       _FDT(fdt_end_node(fdt));
+       _FDT(fdt_end_node(fdt));
+
+       /* Finalise: */
+       _FDT(fdt_end_node(fdt)); /* Root node */
+       _FDT(fdt_finish(fdt));
+
+       _FDT(fdt_open_into(fdt, fdt_dest, FDT_MAX_SIZE));
+
+       /* PCI */
+       if (spapr_populate_pci_devices(kvm, PHANDLE_XICP, fdt_dest))
+               die("Fail populating PCI device nodes");
+
+       _FDT(fdt_add_mem_rsv(fdt_dest, kvm->rtas_gra, kvm->rtas_size));
+       _FDT(fdt_pack(fdt_dest));
+
+       free(segment_page_sizes.value);
+}
+
+/**
+ * kvm__arch_setup_firmware
+ */
+int kvm__arch_setup_firmware(struct kvm *kvm)
+{
+       /*
+        * Set up RTAS stub.  All it is is a single hypercall:
+        *  0:   7c 64 1b 78     mr      r4,r3
+        *  4:   3c 60 00 00     lis     r3,0
+        *  8:   60 63 f0 00     ori     r3,r3,61440
+        *  c:   44 00 00 22     sc      1
+        * 10:   4e 80 00 20     blr
+        */
+       uint32_t *rtas = guest_flat_to_host(kvm, kvm->rtas_gra);
+
+       rtas[0] = 0x7c641b78;
+       rtas[1] = 0x3c600000;
+       rtas[2] = 0x6063f000;
+       rtas[3] = 0x44000022;
+       rtas[4] = 0x4e800020;
+       kvm->rtas_size = 20;
+
+       pr_info("Set up %ld bytes of RTAS at 0x%lx\n",
+               kvm->rtas_size, kvm->rtas_gra);
+
+       /* Load SLOF */
+
+       /* Init FDT */
+       setup_fdt(kvm);
+
+       return 0;
+}
+
+int kvm__arch_free_firmware(struct kvm *kvm)
+{
+       return 0;
+}
diff --git a/tools/kvm/powerpc/spapr.h b/tools/kvm/powerpc/spapr.h
new file mode 100644 (file)
index 0000000..0537f88
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * SPAPR definitions and declarations
+ *
+ * Borrowed heavily from QEMU's spapr.h,
+ * Copyright (c) 2010 David Gibson, IBM Corporation.
+ *
+ * Modifications by Matt Evans <matt@ozlabs.org>, IBM Corporation.
+ *
+ * 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.
+ */
+
+#if !defined(__HW_SPAPR_H__)
+#define __HW_SPAPR_H__
+
+#include <inttypes.h>
+
+/* We need some of the H_ hcall defs, but they're __KERNEL__ only. */
+#define __KERNEL__
+#include <asm/hvcall.h>
+#undef __KERNEL__
+
+#include "kvm/kvm.h"
+#include "kvm/kvm-cpu.h"
+
+typedef unsigned long target_ulong;
+typedef uintptr_t target_phys_addr_t;
+
+/*
+ * The hcalls above are standardized in PAPR and implemented by pHyp
+ * as well.
+ *
+ * We also need some hcalls which are specific to qemu / KVM-on-POWER.
+ * So far we just need one for H_RTAS, but in future we'll need more
+ * for extensions like virtio.  We put those into the 0xf000-0xfffc
+ * range which is reserved by PAPR for "platform-specific" hcalls.
+ */
+#define KVMPPC_HCALL_BASE       0xf000
+#define KVMPPC_H_RTAS           (KVMPPC_HCALL_BASE + 0x0)
+#define KVMPPC_HCALL_MAX        KVMPPC_H_RTAS
+
+#define DEBUG_SPAPR_HCALLS
+
+#ifdef DEBUG_SPAPR_HCALLS
+#define hcall_dprintf(fmt, ...) \
+    do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define hcall_dprintf(fmt, ...) \
+    do { } while (0)
+#endif
+
+typedef target_ulong (*spapr_hcall_fn)(struct kvm_cpu *vcpu,
+                                      target_ulong opcode,
+                                       target_ulong *args);
+
+void hypercall_init(void);
+void register_core_rtas(void);
+
+void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn);
+target_ulong spapr_hypercall(struct kvm_cpu *vcpu, target_ulong opcode,
+                             target_ulong *args);
+
+int spapr_rtas_fdt_setup(struct kvm *kvm, void *fdt);
+
+static inline uint32_t rtas_ld(struct kvm *kvm, target_ulong phys, int n)
+{
+       return *((uint32_t *)guest_flat_to_host(kvm, phys + 4*n));
+}
+
+static inline void rtas_st(struct kvm *kvm, target_ulong phys, int n, uint32_t val)
+{
+       *((uint32_t *)guest_flat_to_host(kvm, phys + 4*n)) = val;
+}
+
+typedef void (*spapr_rtas_fn)(struct kvm_cpu *vcpu, uint32_t token,
+                              uint32_t nargs, target_ulong args,
+                              uint32_t nret, target_ulong rets);
+void spapr_rtas_register(const char *name, spapr_rtas_fn fn);
+target_ulong spapr_rtas_call(struct kvm_cpu *vcpu,
+                             uint32_t token, uint32_t nargs, target_ulong args,
+                             uint32_t nret, target_ulong rets);
+
+#define SPAPR_PCI_BUID          0x800000020000001ULL
+#define SPAPR_PCI_MEM_WIN_ADDR  (KVM_MMIO_START + 0xA0000000)
+#define SPAPR_PCI_MEM_WIN_SIZE  0x20000000
+#define SPAPR_PCI_IO_WIN_ADDR   (SPAPR_PCI_MEM_WIN_ADDR + SPAPR_PCI_MEM_WIN_SIZE)
+#define SPAPR_PCI_IO_WIN_SIZE  0x2000000
+
+#define SPAPR_PCI_WIN_START    SPAPR_PCI_MEM_WIN_ADDR
+#define SPAPR_PCI_WIN_END      (SPAPR_PCI_IO_WIN_ADDR + SPAPR_PCI_IO_WIN_SIZE)
+
+#endif /* !defined (__HW_SPAPR_H__) */
diff --git a/tools/kvm/powerpc/spapr_hcall.c b/tools/kvm/powerpc/spapr_hcall.c
new file mode 100644 (file)
index 0000000..ff1d63a
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * SPAPR hypercalls
+ *
+ * Borrowed heavily from QEMU's spapr_hcall.c,
+ * Copyright (c) 2010 David Gibson, IBM Corporation.
+ *
+ * Copyright (c) 2011 Matt Evans <matt@ozlabs.org>, IBM Corporation.
+ *
+ * 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 "spapr.h"
+#include "kvm/util.h"
+#include "kvm/kvm.h"
+#include "kvm/kvm-cpu.h"
+
+#include <stdio.h>
+#include <assert.h>
+
+static spapr_hcall_fn papr_hypercall_table[(MAX_HCALL_OPCODE / 4) + 1];
+static spapr_hcall_fn kvmppc_hypercall_table[KVMPPC_HCALL_MAX -
+                                            KVMPPC_HCALL_BASE + 1];
+
+static target_ulong h_set_dabr(struct kvm_cpu *vcpu, target_ulong opcode, target_ulong *args)
+{
+       /* FIXME:  Implement this for -PR.  (-HV does this in kernel.) */
+       return H_HARDWARE;
+}
+
+static target_ulong h_rtas(struct kvm_cpu *vcpu, target_ulong opcode, target_ulong *args)
+{
+       target_ulong rtas_r3 = args[0];
+       /*
+        * Pointer read from phys mem; these ptrs cannot be MMIO (!) so just
+        * reference guest RAM directly.
+        */
+       uint32_t token, nargs, nret;
+
+       token = rtas_ld(vcpu->kvm, rtas_r3, 0);
+       nargs = rtas_ld(vcpu->kvm, rtas_r3, 1);
+       nret  = rtas_ld(vcpu->kvm, rtas_r3, 2);
+
+       return spapr_rtas_call(vcpu, token, nargs, rtas_r3 + 12,
+                              nret, rtas_r3 + 12 + 4*nargs);
+}
+
+static target_ulong h_logical_load(struct kvm_cpu *vcpu, target_ulong opcode, target_ulong *args)
+{
+       /* SLOF will require these, though kernel doesn't. */
+       die(__PRETTY_FUNCTION__);
+       return H_PARAMETER;
+}
+
+static target_ulong h_logical_store(struct kvm_cpu *vcpu, target_ulong opcode, target_ulong *args)
+{
+       /* SLOF will require these, though kernel doesn't. */
+       die(__PRETTY_FUNCTION__);
+       return H_PARAMETER;
+}
+
+static target_ulong h_logical_icbi(struct kvm_cpu *vcpu, target_ulong opcode, target_ulong *args)
+{
+       /* KVM will trap this in the kernel.  Die if it misses. */
+       die(__PRETTY_FUNCTION__);
+       return H_SUCCESS;
+}
+
+static target_ulong h_logical_dcbf(struct kvm_cpu *vcpu, target_ulong opcode, target_ulong *args)
+{
+       /* KVM will trap this in the kernel.  Die if it misses. */
+       die(__PRETTY_FUNCTION__);
+       return H_SUCCESS;
+}
+
+void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn)
+{
+       spapr_hcall_fn *slot;
+
+       if (opcode <= MAX_HCALL_OPCODE) {
+               assert((opcode & 0x3) == 0);
+
+               slot = &papr_hypercall_table[opcode / 4];
+       } else {
+               assert((opcode >= KVMPPC_HCALL_BASE) &&
+                      (opcode <= KVMPPC_HCALL_MAX));
+
+               slot = &kvmppc_hypercall_table[opcode - KVMPPC_HCALL_BASE];
+       }
+
+       assert(!(*slot) || (fn == *slot));
+       *slot = fn;
+}
+
+target_ulong spapr_hypercall(struct kvm_cpu *vcpu, target_ulong opcode,
+                            target_ulong *args)
+{
+       if ((opcode <= MAX_HCALL_OPCODE)
+           && ((opcode & 0x3) == 0)) {
+               spapr_hcall_fn fn = papr_hypercall_table[opcode / 4];
+
+               if (fn) {
+                       return fn(vcpu, opcode, args);
+               }
+       } else if ((opcode >= KVMPPC_HCALL_BASE) &&
+                  (opcode <= KVMPPC_HCALL_MAX)) {
+               spapr_hcall_fn fn = kvmppc_hypercall_table[opcode -
+                                                          KVMPPC_HCALL_BASE];
+
+               if (fn) {
+                       return fn(vcpu, opcode, args);
+               }
+       }
+
+       hcall_dprintf("Unimplemented hcall 0x%lx\n", opcode);
+       return H_FUNCTION;
+}
+
+void hypercall_init(void)
+{
+       /* hcall-dabr */
+       spapr_register_hypercall(H_SET_DABR, h_set_dabr);
+
+       spapr_register_hypercall(H_LOGICAL_CI_LOAD, h_logical_load);
+       spapr_register_hypercall(H_LOGICAL_CI_STORE, h_logical_store);
+       spapr_register_hypercall(H_LOGICAL_CACHE_LOAD, h_logical_load);
+       spapr_register_hypercall(H_LOGICAL_CACHE_STORE, h_logical_store);
+       spapr_register_hypercall(H_LOGICAL_ICBI, h_logical_icbi);
+       spapr_register_hypercall(H_LOGICAL_DCBF, h_logical_dcbf);
+
+       /* KVM-PPC specific hcalls */
+       spapr_register_hypercall(KVMPPC_H_RTAS, h_rtas);
+}
diff --git a/tools/kvm/powerpc/spapr_hvcons.c b/tools/kvm/powerpc/spapr_hvcons.c
new file mode 100644 (file)
index 0000000..511dbe1
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * SPAPR HV console
+ *
+ * Borrowed lightly from QEMU's spapr_vty.c, Copyright (c) 2010 David Gibson,
+ * IBM Corporation.
+ *
+ * Copyright (c) 2011 Matt Evans <matt@ozlabs.org>, IBM Corporation.
+ *
+ * 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 "kvm/term.h"
+#include "kvm/kvm.h"
+#include "kvm/kvm-cpu.h"
+#include "kvm/util.h"
+#include "spapr.h"
+#include "spapr_hvcons.h"
+
+#include <stdio.h>
+#include <sys/uio.h>
+#include <errno.h>
+
+#include <linux/byteorder.h>
+
+union hv_chario {
+       struct {
+               uint64_t char0_7;
+               uint64_t char8_15;
+       } a;
+       uint8_t buf[16];
+};
+
+static unsigned long h_put_term_char(struct kvm_cpu *vcpu, unsigned long opcode, unsigned long *args)
+{
+       /* To do: Read register from args[0], and check it. */
+       unsigned long len = args[1];
+       union hv_chario data;
+       struct iovec iov;
+
+       if (len > 16) {
+               return H_PARAMETER;
+       }
+       data.a.char0_7 = cpu_to_be64(args[2]);
+       data.a.char8_15 = cpu_to_be64(args[3]);
+
+       iov.iov_base = data.buf;
+       iov.iov_len = len;
+       do {
+               int ret;
+
+               ret = term_putc_iov(CONSOLE_HV, &iov, 1, 0);
+               if (ret < 0) {
+                       die("term_putc_iov error %d!\n", errno);
+               }
+               iov.iov_base += ret;
+               iov.iov_len -= ret;
+       } while (iov.iov_len > 0);
+
+       return H_SUCCESS;
+}
+
+
+static unsigned long h_get_term_char(struct kvm_cpu *vcpu, unsigned long opcode, unsigned long *args)
+{
+       /* To do: Read register from args[0], and check it. */
+       unsigned long *len = args + 0;
+       unsigned long *char0_7 = args + 1;
+       unsigned long *char8_15 = args + 2;
+       union hv_chario data;
+       struct iovec iov;
+
+       if (term_readable(CONSOLE_HV, 0)) {
+               iov.iov_base = data.buf;
+               iov.iov_len = 16;
+
+               *len = term_getc_iov(CONSOLE_HV, &iov, 1, 0);
+               *char0_7 = be64_to_cpu(data.a.char0_7);
+               *char8_15 = be64_to_cpu(data.a.char8_15);
+       } else {
+               *len = 0;
+       }
+
+       return H_SUCCESS;
+}
+
+void spapr_hvcons_poll(struct kvm *kvm)
+{
+       if (term_readable(CONSOLE_HV, 0)) {
+               /*
+                * We can inject an IRQ to guest here if we want.  The guest
+                * will happily poll, though, so not required.
+                */
+       }
+}
+
+void spapr_hvcons_init(void)
+{
+       spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char);
+       spapr_register_hypercall(H_GET_TERM_CHAR, h_get_term_char);
+}
diff --git a/tools/kvm/powerpc/spapr_hvcons.h b/tools/kvm/powerpc/spapr_hvcons.h
new file mode 100644 (file)
index 0000000..d3e4414
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * SPAPR HV console
+ *
+ * Copyright (c) 2011 Matt Evans <matt@ozlabs.org>, IBM Corporation.
+ *
+ * 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 spapr_hvcons_H
+#define spapr_hvcons_H
+
+#include "kvm/kvm.h"
+
+void spapr_hvcons_init(void);
+void spapr_hvcons_poll(struct kvm *kvm);
+
+#endif
diff --git a/tools/kvm/powerpc/spapr_pci.c b/tools/kvm/powerpc/spapr_pci.c
new file mode 100644 (file)
index 0000000..f9d29f0
--- /dev/null
@@ -0,0 +1,423 @@
+/*
+ * SPAPR PHB emulation, RTAS interface to PCI config space, device tree nodes
+ * for enumerated devices.
+ *
+ * Borrowed heavily from QEMU's spapr_pci.c,
+ * Copyright (c) 2011 Alexey Kardashevskiy, IBM Corporation.
+ * Copyright (c) 2011 David Gibson, IBM Corporation.
+ *
+ * Modifications copyright 2011 Matt Evans <matt@ozlabs.org>, IBM Corporation.
+ *
+ * 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 "spapr.h"
+#include "spapr_pci.h"
+#include "kvm/util.h"
+#include "kvm/pci.h"
+#include "libfdt.h"
+
+#include <linux/pci_regs.h>
+#include <linux/byteorder.h>
+
+
+/* #define DEBUG_PHB yes */
+#ifdef DEBUG_PHB
+#define phb_dprintf(fmt, ...)                                  \
+       do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define phb_dprintf(fmt, ...)                  \
+       do { } while (0)
+#endif
+
+static const uint32_t bars[] = {
+       PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1,
+       PCI_BASE_ADDRESS_2, PCI_BASE_ADDRESS_3,
+       PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5
+       /*, PCI_ROM_ADDRESS*/
+};
+
+#define PCI_NUM_REGIONS                7
+
+/* Macros to operate with address in OF binding to PCI */
+#define b_x(x, p, l)   (((x) & ((1<<(l))-1)) << (p))
+#define b_n(x)         b_x((x), 31, 1) /* 0 if relocatable */
+#define b_p(x)         b_x((x), 30, 1) /* 1 if prefetchable */
+#define b_t(x)         b_x((x), 29, 1) /* 1 if the address is aliased */
+#define b_ss(x)                b_x((x), 24, 2) /* the space code */
+#define b_bbbbbbbb(x)  b_x((x), 16, 8) /* bus number */
+#define b_ddddd(x)     b_x((x), 11, 5) /* device number */
+#define b_fff(x)       b_x((x), 8, 3)  /* function number */
+#define b_rrrrrrrr(x)  b_x((x), 0, 8)  /* register number */
+
+#define SS_M64         3
+#define SS_M32         2
+#define SS_IO          1
+#define SS_CONFIG      0
+
+
+static struct spapr_phb phb;
+
+
+static void rtas_ibm_read_pci_config(struct kvm_cpu *vcpu,
+                                    uint32_t token, uint32_t nargs,
+                                    target_ulong args,
+                                    uint32_t nret, target_ulong rets)
+{
+       uint32_t val = 0;
+       uint64_t buid = ((uint64_t)rtas_ld(vcpu->kvm, args, 1) << 32) | rtas_ld(vcpu->kvm, args, 2);
+       union pci_config_address addr = { .w = rtas_ld(vcpu->kvm, args, 0) };
+       struct pci_device_header *dev = pci__find_dev(addr.device_number);
+       uint32_t size = rtas_ld(vcpu->kvm, args, 3);
+
+       if (buid != phb.buid || !dev || (size > 4)) {
+               phb_dprintf("- cfgRd buid 0x%lx cfg addr 0x%x size %d not found\n",
+                           buid, addr.w, size);
+
+               rtas_st(vcpu->kvm, rets, 0, -1);
+               return;
+       }
+       pci__config_rd(vcpu->kvm, addr, &val, size);
+       /* It appears this wants a byteswapped result... */
+       switch (size) {
+       case 4:
+               val = le32_to_cpu(val);
+               break;
+       case 2:
+               val = le16_to_cpu(val>>16);
+               break;
+       case 1:
+               val = val >> 24;
+               break;
+       }
+       phb_dprintf("- cfgRd buid 0x%lx addr 0x%x (/%d): b%d,d%d,f%d,r0x%x, val 0x%x\n",
+                   buid, addr.w, size, addr.bus_number, addr.device_number, addr.function_number,
+                   addr.register_number, val);
+
+       rtas_st(vcpu->kvm, rets, 0, 0);
+       rtas_st(vcpu->kvm, rets, 1, val);
+}
+
+static void rtas_read_pci_config(struct kvm_cpu *vcpu,
+                                uint32_t token, uint32_t nargs,
+                                target_ulong args,
+                                uint32_t nret, target_ulong rets)
+{
+       uint32_t val;
+       union pci_config_address addr = { .w = rtas_ld(vcpu->kvm, args, 0) };
+       struct pci_device_header *dev = pci__find_dev(addr.device_number);
+       uint32_t size = rtas_ld(vcpu->kvm, args, 1);
+
+       if (!dev || (size > 4)) {
+               rtas_st(vcpu->kvm, rets, 0, -1);
+               return;
+       }
+       pci__config_rd(vcpu->kvm, addr, &val, size);
+       switch (size) {
+       case 4:
+               val = le32_to_cpu(val);
+               break;
+       case 2:
+               val = le16_to_cpu(val>>16); /* We're yuck-endian. */
+               break;
+       case 1:
+               val = val >> 24;
+               break;
+       }
+       phb_dprintf("- cfgRd addr 0x%x size %d, val 0x%x\n", addr.w, size, val);
+       rtas_st(vcpu->kvm, rets, 0, 0);
+       rtas_st(vcpu->kvm, rets, 1, val);
+}
+
+static void rtas_ibm_write_pci_config(struct kvm_cpu *vcpu,
+                                     uint32_t token, uint32_t nargs,
+                                     target_ulong args,
+                                     uint32_t nret, target_ulong rets)
+{
+       uint64_t buid = ((uint64_t)rtas_ld(vcpu->kvm, args, 1) << 32) | rtas_ld(vcpu->kvm, args, 2);
+       union pci_config_address addr = { .w = rtas_ld(vcpu->kvm, args, 0) };
+       struct pci_device_header *dev = pci__find_dev(addr.device_number);
+       uint32_t size = rtas_ld(vcpu->kvm, args, 3);
+       uint32_t val = rtas_ld(vcpu->kvm, args, 4);
+
+       if (buid != phb.buid || !dev || (size > 4)) {
+               phb_dprintf("- cfgWr buid 0x%lx cfg addr 0x%x/%d error (val 0x%x)\n",
+                           buid, addr.w, size, val);
+
+               rtas_st(vcpu->kvm, rets, 0, -1);
+               return;
+       }
+       phb_dprintf("- cfgWr buid 0x%lx addr 0x%x (/%d): b%d,d%d,f%d,r0x%x, val 0x%x\n",
+                   buid, addr.w, size, addr.bus_number, addr.device_number, addr.function_number,
+                   addr.register_number, val);
+       switch (size) {
+       case 4:
+               val = le32_to_cpu(val);
+               break;
+       case 2:
+               val = le16_to_cpu(val) << 16;
+               break;
+       case 1:
+               val = val >> 24;
+               break;
+       }
+       pci__config_wr(vcpu->kvm, addr, &val, size);
+       rtas_st(vcpu->kvm, rets, 0, 0);
+}
+
+static void rtas_write_pci_config(struct kvm_cpu *vcpu,
+                                 uint32_t token, uint32_t nargs,
+                                 target_ulong args,
+                                 uint32_t nret, target_ulong rets)
+{
+       union pci_config_address addr = { .w = rtas_ld(vcpu->kvm, args, 0) };
+       struct pci_device_header *dev = pci__find_dev(addr.device_number);
+       uint32_t size = rtas_ld(vcpu->kvm, args, 1);
+       uint32_t val = rtas_ld(vcpu->kvm, args, 2);
+
+       if (!dev || (size > 4)) {
+               rtas_st(vcpu->kvm, rets, 0, -1);
+               return;
+       }
+
+       phb_dprintf("- cfgWr addr 0x%x (/%d): b%d,d%d,f%d,r0x%x, val 0x%x\n",
+                   addr.w, size, addr.bus_number, addr.device_number, addr.function_number,
+                   addr.register_number, val);
+       switch (size) {
+       case 4:
+               val = le32_to_cpu(val);
+               break;
+       case 2:
+               val = le16_to_cpu(val) << 16;
+               break;
+       case 1:
+               val = val >> 24;
+               break;
+       }
+       pci__config_wr(vcpu->kvm, addr, &val, size);
+       rtas_st(vcpu->kvm, rets, 0, 0);
+}
+
+void spapr_create_phb(struct kvm *kvm,
+                     const char *busname, uint64_t buid,
+                     uint64_t mem_win_addr, uint64_t mem_win_size,
+                     uint64_t io_win_addr, uint64_t io_win_size)
+{
+       /*
+        * Since kvmtool doesn't really have any concept of buses etc.,
+        * there's nothing to register here.  Just register RTAS.
+        */
+       spapr_rtas_register("read-pci-config", rtas_read_pci_config);
+       spapr_rtas_register("write-pci-config", rtas_write_pci_config);
+       spapr_rtas_register("ibm,read-pci-config", rtas_ibm_read_pci_config);
+       spapr_rtas_register("ibm,write-pci-config", rtas_ibm_write_pci_config);
+
+       phb.buid = buid;
+       phb.mem_addr = mem_win_addr;
+       phb.mem_size = mem_win_size;
+       phb.io_addr  = io_win_addr;
+       phb.io_size  = io_win_size;
+
+       kvm->phb = &phb;
+}
+
+static uint32_t bar_to_ss(unsigned long bar)
+{
+       if ((bar & PCI_BASE_ADDRESS_SPACE) ==
+           PCI_BASE_ADDRESS_SPACE_IO)
+               return SS_IO;
+       else if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64)
+               return SS_M64;
+       else
+               return SS_M32;
+}
+
+static unsigned long bar_to_addr(unsigned long bar)
+{
+       if ((bar & PCI_BASE_ADDRESS_SPACE) ==
+           PCI_BASE_ADDRESS_SPACE_IO)
+               return bar & PCI_BASE_ADDRESS_IO_MASK;
+       else
+               return bar & PCI_BASE_ADDRESS_MEM_MASK;
+}
+
+int spapr_populate_pci_devices(struct kvm *kvm,
+                              uint32_t xics_phandle,
+                              void *fdt)
+{
+       int bus_off, node_off = 0, devid, fn, i, n, devices;
+       char nodename[256];
+       struct {
+               uint32_t hi;
+               uint64_t addr;
+               uint64_t size;
+       } __attribute__((packed)) reg[PCI_NUM_REGIONS + 1],
+                 assigned_addresses[PCI_NUM_REGIONS];
+       uint32_t bus_range[] = { cpu_to_be32(0), cpu_to_be32(0xff) };
+       struct {
+               uint32_t hi;
+               uint64_t child;
+               uint64_t parent;
+               uint64_t size;
+       } __attribute__((packed)) ranges[] = {
+               {
+                       cpu_to_be32(b_ss(1)), cpu_to_be64(0),
+                       cpu_to_be64(phb.io_addr),
+                       cpu_to_be64(phb.io_size),
+               },
+               {
+                       cpu_to_be32(b_ss(2)), cpu_to_be64(0),
+                       cpu_to_be64(phb.mem_addr),
+                       cpu_to_be64(phb.mem_size),
+               },
+       };
+       uint64_t bus_reg[] = { cpu_to_be64(phb.buid), 0 };
+       uint32_t interrupt_map_mask[] = {
+               cpu_to_be32(b_ddddd(-1)|b_fff(-1)), 0x0, 0x0, 0x0};
+       uint32_t interrupt_map[SPAPR_PCI_NUM_LSI][7];
+
+       /* Start populating the FDT */
+       sprintf(nodename, "pci@%" PRIx64, phb.buid);
+       bus_off = fdt_add_subnode(fdt, 0, nodename);
+       if (bus_off < 0) {
+               die("error making bus subnode, %s\n", fdt_strerror(bus_off));
+               return bus_off;
+       }
+
+       /* Write PHB properties */
+       _FDT(fdt_setprop_string(fdt, bus_off, "device_type", "pci"));
+       _FDT(fdt_setprop_string(fdt, bus_off, "compatible", "IBM,Logical_PHB"));
+       _FDT(fdt_setprop_cell(fdt, bus_off, "#address-cells", 0x3));
+       _FDT(fdt_setprop_cell(fdt, bus_off, "#size-cells", 0x2));
+       _FDT(fdt_setprop_cell(fdt, bus_off, "#interrupt-cells", 0x1));
+       _FDT(fdt_setprop(fdt, bus_off, "used-by-rtas", NULL, 0));
+       _FDT(fdt_setprop(fdt, bus_off, "bus-range", &bus_range, sizeof(bus_range)));
+       _FDT(fdt_setprop(fdt, bus_off, "ranges", &ranges, sizeof(ranges)));
+       _FDT(fdt_setprop(fdt, bus_off, "reg", &bus_reg, sizeof(bus_reg)));
+       _FDT(fdt_setprop(fdt, bus_off, "interrupt-map-mask",
+                        &interrupt_map_mask, sizeof(interrupt_map_mask)));
+
+       /* Populate PCI devices and allocate IRQs */
+       devices = 0;
+
+       for (devid = 0; devid < PCI_MAX_DEVICES; devid++) {
+               uint32_t *irqmap = interrupt_map[devices];
+               struct pci_device_header *hdr = pci__find_dev(devid);
+
+               if (!hdr)
+                       continue;
+
+               fn = 0; /* kvmtool doesn't yet do multifunction devices */
+
+               sprintf(nodename, "pci@%u,%u", devid, fn);
+
+               /* Allocate interrupt from the map */
+               if (devid > SPAPR_PCI_NUM_LSI)  {
+                       die("Unexpected behaviour in spapr_populate_pci_devices,"
+                           "wrong devid %u\n", devid);
+               }
+               irqmap[0] = cpu_to_be32(b_ddddd(devid)|b_fff(fn));
+               irqmap[1] = 0;
+               irqmap[2] = 0;
+               irqmap[3] = 0;
+               irqmap[4] = cpu_to_be32(xics_phandle);
+               /*
+                * This is nasty; the PCI devs are set up such that their own
+                * header's irq_line indicates the direct XICS IRQ number to
+                * use.  There REALLY needs to be a hierarchical system in place
+                * to 'raise' an IRQ on the bridge which indexes/looks up which
+                * XICS IRQ to fire.
+                */
+               irqmap[5] = cpu_to_be32(hdr->irq_line);
+               irqmap[6] = cpu_to_be32(0x8);
+
+               /* Add node to FDT */
+               node_off = fdt_add_subnode(fdt, bus_off, nodename);
+               if (node_off < 0) {
+                       die("error making node subnode, %s\n", fdt_strerror(bus_off));
+                       return node_off;
+               }
+
+               _FDT(fdt_setprop_cell(fdt, node_off, "vendor-id",
+                                     le16_to_cpu(hdr->vendor_id)));
+               _FDT(fdt_setprop_cell(fdt, node_off, "device-id",
+                                     le16_to_cpu(hdr->device_id)));
+               _FDT(fdt_setprop_cell(fdt, node_off, "revision-id",
+                                     hdr->revision_id));
+               _FDT(fdt_setprop_cell(fdt, node_off, "class-code",
+                                     hdr->class[0] | (hdr->class[1] << 8) | (hdr->class[2] << 16)));
+               _FDT(fdt_setprop_cell(fdt, node_off, "subsystem-id",
+                                     le16_to_cpu(hdr->subsys_id)));
+               _FDT(fdt_setprop_cell(fdt, node_off, "subsystem-vendor-id",
+                                     le16_to_cpu(hdr->subsys_vendor_id)));
+
+               /* Config space region comes first */
+               reg[0].hi = cpu_to_be32(
+                       b_n(0) |
+                       b_p(0) |
+                       b_t(0) |
+                       b_ss(SS_CONFIG) |
+                       b_bbbbbbbb(0) |
+                       b_ddddd(devid) |
+                       b_fff(fn));
+               reg[0].addr = 0;
+               reg[0].size = 0;
+
+               n = 0;
+               /* Six BARs, no ROM supported, addresses are 32bit */
+               for (i = 0; i < 6; ++i) {
+                       if (0 == hdr->bar[i]) {
+                               continue;
+                       }
+
+                       reg[n+1].hi = cpu_to_be32(
+                               b_n(0) |
+                               b_p(0) |
+                               b_t(0) |
+                               b_ss(bar_to_ss(le32_to_cpu(hdr->bar[i]))) |
+                               b_bbbbbbbb(0) |
+                               b_ddddd(devid) |
+                               b_fff(fn) |
+                               b_rrrrrrrr(bars[i]));
+                       reg[n+1].addr = 0;
+                       reg[n+1].size = cpu_to_be64(hdr->bar_size[i]);
+
+                       assigned_addresses[n].hi = cpu_to_be32(
+                               b_n(1) |
+                               b_p(0) |
+                               b_t(0) |
+                               b_ss(bar_to_ss(le32_to_cpu(hdr->bar[i]))) |
+                               b_bbbbbbbb(0) |
+                               b_ddddd(devid) |
+                               b_fff(fn) |
+                               b_rrrrrrrr(bars[i]));
+
+                       /*
+                        * Writing zeroes to assigned_addresses causes the guest kernel to
+                        * reassign BARs
+                        */
+                       assigned_addresses[n].addr = cpu_to_be64(bar_to_addr(le32_to_cpu(hdr->bar[i])));
+                       assigned_addresses[n].size = reg[n+1].size;
+
+                       ++n;
+               }
+               _FDT(fdt_setprop(fdt, node_off, "reg", reg, sizeof(reg[0])*(n+1)));
+               _FDT(fdt_setprop(fdt, node_off, "assigned-addresses",
+                                assigned_addresses,
+                                sizeof(assigned_addresses[0])*(n)));
+               _FDT(fdt_setprop_cell(fdt, node_off, "interrupts",
+                                     hdr->irq_pin));
+
+               /* We don't set ibm,dma-window property as we don't have an IOMMU. */
+
+               ++devices;
+       }
+
+       /* Write interrupt map */
+       _FDT(fdt_setprop(fdt, bus_off, "interrupt-map", &interrupt_map,
+                        devices * sizeof(interrupt_map[0])));
+
+       return 0;
+}
diff --git a/tools/kvm/powerpc/spapr_pci.h b/tools/kvm/powerpc/spapr_pci.h
new file mode 100644 (file)
index 0000000..48b221c
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * SPAPR PHB definitions
+ *
+ * Modifications by Matt Evans <matt@ozlabs.org>, IBM Corporation.
+ *
+ * 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 SPAPR_PCI_H
+#define SPAPR_PCI_H
+
+#include "kvm/kvm.h"
+#include "spapr.h"
+#include <inttypes.h>
+
+/* With XICS, we can easily accomodate 1 IRQ per PCI device. */
+
+#define SPAPR_PCI_NUM_LSI 256
+
+struct spapr_phb {
+       uint64_t buid;
+       uint64_t mem_addr;
+       uint64_t mem_size;
+       uint64_t io_addr;
+       uint64_t io_size;
+};
+
+void spapr_create_phb(struct kvm *kvm,
+                      const char *busname, uint64_t buid,
+                      uint64_t mem_win_addr, uint64_t mem_win_size,
+                      uint64_t io_win_addr, uint64_t io_win_size);
+
+int spapr_populate_pci_devices(struct kvm *kvm,
+                               uint32_t xics_phandle,
+                               void *fdt);
+
+static inline bool spapr_phb_mmio(struct kvm *kvm, u64 phys_addr, u8 *data, u32 len, u8 is_write)
+{
+       if ((phys_addr >= SPAPR_PCI_IO_WIN_ADDR) &&
+           (phys_addr < SPAPR_PCI_IO_WIN_ADDR +
+            SPAPR_PCI_IO_WIN_SIZE)) {
+               return kvm__emulate_io(kvm, phys_addr - SPAPR_PCI_IO_WIN_ADDR,
+                                      data, is_write ? KVM_EXIT_IO_OUT :
+                                      KVM_EXIT_IO_IN,
+                                      len, 1);
+       } else if ((phys_addr >= SPAPR_PCI_MEM_WIN_ADDR) &&
+                  (phys_addr < SPAPR_PCI_MEM_WIN_ADDR +
+                   SPAPR_PCI_MEM_WIN_SIZE)) {
+               return kvm__emulate_mmio(kvm, phys_addr - SPAPR_PCI_MEM_WIN_ADDR,
+                                        data, len, is_write);
+       }
+       return false;
+}
+
+#endif
diff --git a/tools/kvm/powerpc/spapr_rtas.c b/tools/kvm/powerpc/spapr_rtas.c
new file mode 100644 (file)
index 0000000..14a3462
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * SPAPR base RTAS calls
+ *
+ * Borrowed heavily from QEMU's spapr_rtas.c
+ * Copyright (c) 2010-2011 David Gibson, IBM Corporation.
+ *
+ * Modifications copyright 2011 Matt Evans <matt@ozlabs.org>, IBM Corporation.
+ *
+ * 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 "kvm/kvm.h"
+#include "kvm/kvm-cpu.h"
+#include "kvm/util.h"
+#include "kvm/term.h"
+#include "libfdt.h"
+
+#include "spapr.h"
+
+#include <stdio.h>
+#include <assert.h>
+
+#define TOKEN_BASE      0x2000
+#define TOKEN_MAX       0x100
+
+#define RTAS_CONSOLE
+
+static struct rtas_call {
+       const char *name;
+       spapr_rtas_fn fn;
+} rtas_table[TOKEN_MAX];
+
+struct rtas_call *rtas_next = rtas_table;
+
+
+static void rtas_display_character(struct kvm_cpu *vcpu,
+                                   uint32_t token, uint32_t nargs,
+                                   target_ulong args,
+                                   uint32_t nret, target_ulong rets)
+{
+       char c = rtas_ld(vcpu->kvm, args, 0);
+       term_putc(CONSOLE_HV, &c, 1, 0);
+       rtas_st(vcpu->kvm, rets, 0, 0);
+}
+
+#ifdef RTAS_CONSOLE
+static void rtas_put_term_char(struct kvm_cpu *vcpu,
+                              uint32_t token, uint32_t nargs,
+                              target_ulong args,
+                              uint32_t nret, target_ulong rets)
+{
+       char c = rtas_ld(vcpu->kvm, args, 0);
+       term_putc(CONSOLE_HV, &c, 1, 0);
+       rtas_st(vcpu->kvm, rets, 0, 0);
+}
+
+static void rtas_get_term_char(struct kvm_cpu *vcpu,
+                              uint32_t token, uint32_t nargs,
+                              target_ulong args,
+                              uint32_t nret, target_ulong rets)
+{
+       int c;
+       if (term_readable(CONSOLE_HV, 0) &&
+           (c = term_getc(CONSOLE_HV, 0)) >= 0) {
+               rtas_st(vcpu->kvm, rets, 0, 0);
+               rtas_st(vcpu->kvm, rets, 1, c);
+       } else {
+               rtas_st(vcpu->kvm, rets, 0, -2);
+       }
+}
+#endif
+
+static void rtas_get_time_of_day(struct kvm_cpu *vcpu,
+                                 uint32_t token, uint32_t nargs,
+                                 target_ulong args,
+                                 uint32_t nret, target_ulong rets)
+{
+       struct tm tm;
+       time_t tnow;
+
+       if (nret != 8) {
+               rtas_st(vcpu->kvm, rets, 0, -3);
+               return;
+       }
+
+       tnow = time(NULL);
+       /* Guest time is currently not offset in any way. */
+       gmtime_r(&tnow, &tm);
+
+       rtas_st(vcpu->kvm, rets, 0, 0); /* Success */
+       rtas_st(vcpu->kvm, rets, 1, tm.tm_year + 1900);
+       rtas_st(vcpu->kvm, rets, 2, tm.tm_mon + 1);
+       rtas_st(vcpu->kvm, rets, 3, tm.tm_mday);
+       rtas_st(vcpu->kvm, rets, 4, tm.tm_hour);
+       rtas_st(vcpu->kvm, rets, 5, tm.tm_min);
+       rtas_st(vcpu->kvm, rets, 6, tm.tm_sec);
+       rtas_st(vcpu->kvm, rets, 7, 0);
+}
+
+static void rtas_set_time_of_day(struct kvm_cpu *vcpu,
+                                 uint32_t token, uint32_t nargs,
+                                 target_ulong args,
+                                 uint32_t nret, target_ulong rets)
+{
+       pr_warning("%s called; TOD set ignored.\n", __FUNCTION__);
+}
+
+static void rtas_power_off(struct kvm_cpu *vcpu,
+                           uint32_t token, uint32_t nargs, target_ulong args,
+                           uint32_t nret, target_ulong rets)
+{
+       if (nargs != 2 || nret != 1) {
+               rtas_st(vcpu->kvm, rets, 0, -3);
+               return;
+       }
+       kvm_cpu__reboot();
+}
+
+static void rtas_query_cpu_stopped_state(struct kvm_cpu *vcpu,
+                                         uint32_t token, uint32_t nargs,
+                                         target_ulong args,
+                                         uint32_t nret, target_ulong rets)
+{
+       if (nargs != 1 || nret != 2) {
+               rtas_st(vcpu->kvm, rets, 0, -3);
+               return;
+       }
+
+       /*
+        * Can read id = rtas_ld(vcpu->kvm, args, 0), but
+        * we currently start all CPUs.  So just return true.
+        */
+       rtas_st(vcpu->kvm, rets, 0, 0);
+       rtas_st(vcpu->kvm, rets, 1, 2);
+}
+
+static void rtas_start_cpu(struct kvm_cpu *vcpu,
+                           uint32_t token, uint32_t nargs,
+                           target_ulong args,
+                           uint32_t nret, target_ulong rets)
+{
+       die(__FUNCTION__);
+}
+
+target_ulong spapr_rtas_call(struct kvm_cpu *vcpu,
+                             uint32_t token, uint32_t nargs, target_ulong args,
+                             uint32_t nret, target_ulong rets)
+{
+       if ((token >= TOKEN_BASE)
+           && ((token - TOKEN_BASE) < TOKEN_MAX)) {
+               struct rtas_call *call = rtas_table + (token - TOKEN_BASE);
+
+               if (call->fn) {
+                       call->fn(vcpu, token, nargs, args, nret, rets);
+                       return H_SUCCESS;
+               }
+       }
+
+       /*
+        * HACK: Some Linux early debug code uses RTAS display-character,
+        * but assumes the token value is 0xa (which it is on some real
+        * machines) without looking it up in the device tree.  This
+        * special case makes this work
+        */
+       if (token == 0xa) {
+               rtas_display_character(vcpu, 0xa, nargs, args, nret, rets);
+               return H_SUCCESS;
+       }
+
+       hcall_dprintf("Unknown RTAS token 0x%x\n", token);
+       rtas_st(vcpu->kvm, rets, 0, -3);
+       return H_PARAMETER;
+}
+
+void spapr_rtas_register(const char *name, spapr_rtas_fn fn)
+{
+       assert(rtas_next < (rtas_table + TOKEN_MAX));
+
+       rtas_next->name = name;
+       rtas_next->fn = fn;
+
+       rtas_next++;
+}
+
+/*
+ * This is called from the context of an open /rtas node, in order to add
+ * properties for the rtas call tokens.
+ */
+int spapr_rtas_fdt_setup(struct kvm *kvm, void *fdt)
+{
+       int ret;
+       int i;
+
+       for (i = 0; i < TOKEN_MAX; i++) {
+               struct rtas_call *call = &rtas_table[i];
+
+               if (!call->fn) {
+                       continue;
+               }
+
+               ret = fdt_property_cell(fdt, call->name, i + TOKEN_BASE);
+
+               if (ret < 0) {
+                       pr_warning("Couldn't add rtas token for %s: %s\n",
+                                  call->name, fdt_strerror(ret));
+                       return ret;
+               }
+
+       }
+       return 0;
+}
+
+void register_core_rtas(void)
+{
+       spapr_rtas_register("display-character", rtas_display_character);
+       spapr_rtas_register("get-time-of-day", rtas_get_time_of_day);
+       spapr_rtas_register("set-time-of-day", rtas_set_time_of_day);
+       spapr_rtas_register("power-off", rtas_power_off);
+       spapr_rtas_register("query-cpu-stopped-state",
+                           rtas_query_cpu_stopped_state);
+       spapr_rtas_register("start-cpu", rtas_start_cpu);
+#ifdef RTAS_CONSOLE
+       /* These are unused: We do console I/O via hcalls, not rtas. */
+       spapr_rtas_register("put-term-char", rtas_put_term_char);
+       spapr_rtas_register("get-term-char", rtas_get_term_char);
+#endif
+}
diff --git a/tools/kvm/powerpc/xics.c b/tools/kvm/powerpc/xics.c
new file mode 100644 (file)
index 0000000..2d70d3c
--- /dev/null
@@ -0,0 +1,514 @@
+/*
+ * PAPR Virtualized Interrupt System, aka ICS/ICP aka xics
+ *
+ * Borrowed heavily from QEMU's xics.c,
+ * Copyright (c) 2010,2011 David Gibson, IBM Corporation.
+ *
+ * Modifications copyright 2011 Matt Evans <matt@ozlabs.org>, IBM Corporation.
+ *
+ * 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 "spapr.h"
+#include "xics.h"
+#include "kvm/util.h"
+
+#include <stdio.h>
+#include <malloc.h>
+
+
+/* #define DEBUG_XICS yes */
+#ifdef DEBUG_XICS
+#define xics_dprintf(fmt, ...)                                 \
+       do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+#else
+#define xics_dprintf(fmt, ...)                 \
+       do { } while (0)
+#endif
+
+/*
+ * ICP: Presentation layer
+ */
+
+struct icp_server_state {
+       uint32_t xirr;
+       uint8_t pending_priority;
+       uint8_t mfrr;
+       struct kvm_cpu *cpu;
+};
+
+#define XICS_IRQ_OFFSET 16
+#define XISR_MASK      0x00ffffff
+#define CPPR_MASK      0xff000000
+
+#define XISR(ss)   (((ss)->xirr) & XISR_MASK)
+#define CPPR(ss)   (((ss)->xirr) >> 24)
+
+struct ics_state;
+
+struct icp_state {
+       unsigned long nr_servers;
+       struct icp_server_state *ss;
+       struct ics_state *ics;
+};
+
+static void ics_reject(struct ics_state *ics, int nr);
+static void ics_resend(struct ics_state *ics);
+static void ics_eoi(struct ics_state *ics, int nr);
+
+static inline void cpu_irq_raise(struct kvm_cpu *vcpu)
+{
+       xics_dprintf("INT1[%p]\n", vcpu);
+       kvm_cpu__irq(vcpu, POWER7_EXT_IRQ, 1);
+}
+
+static inline void cpu_irq_lower(struct kvm_cpu *vcpu)
+{
+       xics_dprintf("INT0[%p]\n", vcpu);
+       kvm_cpu__irq(vcpu, POWER7_EXT_IRQ, 0);
+}
+
+static void icp_check_ipi(struct icp_state *icp, int server)
+{
+       struct icp_server_state *ss = icp->ss + server;
+
+       if (XISR(ss) && (ss->pending_priority <= ss->mfrr)) {
+               return;
+       }
+
+       if (XISR(ss)) {
+               ics_reject(icp->ics, XISR(ss));
+       }
+
+       ss->xirr = (ss->xirr & ~XISR_MASK) | XICS_IPI;
+       ss->pending_priority = ss->mfrr;
+       cpu_irq_raise(ss->cpu);
+}
+
+static void icp_resend(struct icp_state *icp, int server)
+{
+       struct icp_server_state *ss = icp->ss + server;
+
+       if (ss->mfrr < CPPR(ss)) {
+               icp_check_ipi(icp, server);
+       }
+       ics_resend(icp->ics);
+}
+
+static void icp_set_cppr(struct icp_state *icp, int server, uint8_t cppr)
+{
+       struct icp_server_state *ss = icp->ss + server;
+       uint8_t old_cppr;
+       uint32_t old_xisr;
+
+       old_cppr = CPPR(ss);
+       ss->xirr = (ss->xirr & ~CPPR_MASK) | (cppr << 24);
+
+       if (cppr < old_cppr) {
+               if (XISR(ss) && (cppr <= ss->pending_priority)) {
+                       old_xisr = XISR(ss);
+                       ss->xirr &= ~XISR_MASK; /* Clear XISR */
+                       cpu_irq_lower(ss->cpu);
+                       ics_reject(icp->ics, old_xisr);
+               }
+       } else {
+               if (!XISR(ss)) {
+                       icp_resend(icp, server);
+               }
+       }
+}
+
+static void icp_set_mfrr(struct icp_state *icp, int nr, uint8_t mfrr)
+{
+       struct icp_server_state *ss = icp->ss + nr;
+
+       ss->mfrr = mfrr;
+       if (mfrr < CPPR(ss)) {
+               icp_check_ipi(icp, nr);
+       }
+}
+
+static uint32_t icp_accept(struct icp_server_state *ss)
+{
+       uint32_t xirr;
+
+       cpu_irq_lower(ss->cpu);
+       xirr = ss->xirr;
+       ss->xirr = ss->pending_priority << 24;
+       return xirr;
+}
+
+static void icp_eoi(struct icp_state *icp, int server, uint32_t xirr)
+{
+       struct icp_server_state *ss = icp->ss + server;
+
+       ics_eoi(icp->ics, xirr & XISR_MASK);
+       /* Send EOI -> ICS */
+       ss->xirr = (ss->xirr & ~CPPR_MASK) | (xirr & CPPR_MASK);
+       if (!XISR(ss)) {
+               icp_resend(icp, server);
+       }
+}
+
+static void icp_irq(struct icp_state *icp, int server, int nr, uint8_t priority)
+{
+       struct icp_server_state *ss = icp->ss + server;
+       xics_dprintf("icp_irq(nr %d, server %d, prio 0x%x)\n", nr, server, priority);
+       if ((priority >= CPPR(ss))
+           || (XISR(ss) && (ss->pending_priority <= priority))) {
+               xics_dprintf("reject %d, CPPR 0x%x, XISR 0x%x, pprio 0x%x, prio 0x%x\n",
+                            nr, CPPR(ss), XISR(ss), ss->pending_priority, priority);
+               ics_reject(icp->ics, nr);
+       } else {
+               if (XISR(ss)) {
+                       xics_dprintf("reject %d, CPPR 0x%x, XISR 0x%x, pprio 0x%x, prio 0x%x\n",
+                                    nr, CPPR(ss), XISR(ss), ss->pending_priority, priority);
+                       ics_reject(icp->ics, XISR(ss));
+               }
+               ss->xirr = (ss->xirr & ~XISR_MASK) | (nr & XISR_MASK);
+               ss->pending_priority = priority;
+               cpu_irq_raise(ss->cpu);
+       }
+}
+
+/*
+ * ICS: Source layer
+ */
+
+struct ics_irq_state {
+       int server;
+       uint8_t priority;
+       uint8_t saved_priority;
+       int rejected:1;
+       int masked_pending:1;
+};
+
+struct ics_state {
+       unsigned int nr_irqs;
+       unsigned int offset;
+       struct ics_irq_state *irqs;
+       struct icp_state *icp;
+};
+
+static int ics_valid_irq(struct ics_state *ics, uint32_t nr)
+{
+       return (nr >= ics->offset)
+               && (nr < (ics->offset + ics->nr_irqs));
+}
+
+static void ics_set_irq_msi(struct ics_state *ics, int srcno, int val)
+{
+       struct ics_irq_state *irq = ics->irqs + srcno;
+
+       if (val) {
+               if (irq->priority == 0xff) {
+                       xics_dprintf(" irq pri ff, masked pending\n");
+                       irq->masked_pending = 1;
+               } else  {
+                       icp_irq(ics->icp, irq->server, srcno + ics->offset, irq->priority);
+               }
+       }
+}
+
+static void ics_reject_msi(struct ics_state *ics, int nr)
+{
+       struct ics_irq_state *irq = ics->irqs + nr - ics->offset;
+
+       irq->rejected = 1;
+}
+
+static void ics_resend_msi(struct ics_state *ics)
+{
+       unsigned int i;
+
+       for (i = 0; i < ics->nr_irqs; i++) {
+               struct ics_irq_state *irq = ics->irqs + i;
+
+               /* FIXME: filter by server#? */
+               if (irq->rejected) {
+                       irq->rejected = 0;
+                       if (irq->priority != 0xff) {
+                               icp_irq(ics->icp, irq->server, i + ics->offset, irq->priority);
+                       }
+               }
+       }
+}
+
+static void ics_write_xive_msi(struct ics_state *ics, int nr, int server,
+                              uint8_t priority)
+{
+       struct ics_irq_state *irq = ics->irqs + nr - ics->offset;
+
+       irq->server = server;
+       irq->priority = priority;
+       xics_dprintf("ics_write_xive_msi(nr %d, server %d, pri 0x%x)\n", nr, server, priority);
+
+       if (!irq->masked_pending || (priority == 0xff)) {
+               return;
+       }
+
+       irq->masked_pending = 0;
+       icp_irq(ics->icp, server, nr, priority);
+}
+
+static void ics_reject(struct ics_state *ics, int nr)
+{
+       ics_reject_msi(ics, nr);
+}
+
+static void ics_resend(struct ics_state *ics)
+{
+       ics_resend_msi(ics);
+}
+
+static void ics_eoi(struct ics_state *ics, int nr)
+{
+}
+
+/*
+ * Exported functions
+ */
+
+static int allocated_irqnum = XICS_IRQ_OFFSET;
+
+/*
+ * xics_alloc_irqnum(): This is hacky.  The problem boils down to the PCI device
+ * code which just calls kvm__irq_line( .. pcidev->pci_hdr.irq_line ..) at will.
+ * Each PCI device's IRQ line is allocated by irq__register_device() (which
+ * allocates an IRQ AND allocates a.. PCI device num..).
+ *
+ * In future I'd like to at least mimic some kind of 'upstream IRQ controller'
+ * whereby PCI devices let their PHB know when they want to IRQ, and that
+ * percolates up.
+ *
+ * For now, allocate a REAL xics irq number and (via irq__register_device) push
+ * that into the config space. 8 bits only though!
+ */
+int xics_alloc_irqnum(void)
+{
+       int irq = allocated_irqnum++;
+
+       if (irq > 255)
+               die("Huge numbers of IRQs aren't supported with the daft kvmtool IRQ system.");
+
+       return irq;
+}
+
+static target_ulong h_cppr(struct kvm_cpu *vcpu,
+                          target_ulong opcode, target_ulong *args)
+{
+       target_ulong cppr = args[0];
+
+       xics_dprintf("h_cppr(%lx)\n", cppr);
+       icp_set_cppr(vcpu->kvm->icp, vcpu->cpu_id, cppr);
+       return H_SUCCESS;
+}
+
+static target_ulong h_ipi(struct kvm_cpu *vcpu,
+                         target_ulong opcode, target_ulong *args)
+{
+       target_ulong server = args[0];
+       target_ulong mfrr = args[1];
+
+       xics_dprintf("h_ipi(%lx, %lx)\n", server, mfrr);
+       if (server >= vcpu->kvm->icp->nr_servers) {
+               return H_PARAMETER;
+       }
+
+       icp_set_mfrr(vcpu->kvm->icp, server, mfrr);
+       return H_SUCCESS;
+}
+
+static target_ulong h_xirr(struct kvm_cpu *vcpu,
+                          target_ulong opcode, target_ulong *args)
+{
+       uint32_t xirr = icp_accept(vcpu->kvm->icp->ss + vcpu->cpu_id);
+
+       xics_dprintf("h_xirr() = %x\n", xirr);
+       args[0] = xirr;
+       return H_SUCCESS;
+}
+
+static target_ulong h_eoi(struct kvm_cpu *vcpu,
+                         target_ulong opcode, target_ulong *args)
+{
+       target_ulong xirr = args[0];
+
+       xics_dprintf("h_eoi(%lx)\n", xirr);
+       icp_eoi(vcpu->kvm->icp, vcpu->cpu_id, xirr);
+       return H_SUCCESS;
+}
+
+static void rtas_set_xive(struct kvm_cpu *vcpu, uint32_t token,
+                         uint32_t nargs, target_ulong args,
+                         uint32_t nret, target_ulong rets)
+{
+       struct ics_state *ics = vcpu->kvm->icp->ics;
+       uint32_t nr, server, priority;
+
+       if ((nargs != 3) || (nret != 1)) {
+               rtas_st(vcpu->kvm, rets, 0, -3);
+               return;
+       }
+
+       nr = rtas_ld(vcpu->kvm, args, 0);
+       server = rtas_ld(vcpu->kvm, args, 1);
+       priority = rtas_ld(vcpu->kvm, args, 2);
+
+       xics_dprintf("rtas_set_xive(%x,%x,%x)\n", nr, server, priority);
+       if (!ics_valid_irq(ics, nr) || (server >= ics->icp->nr_servers)
+           || (priority > 0xff)) {
+               rtas_st(vcpu->kvm, rets, 0, -3);
+               return;
+       }
+
+       ics_write_xive_msi(ics, nr, server, priority);
+
+       rtas_st(vcpu->kvm, rets, 0, 0); /* Success */
+}
+
+static void rtas_get_xive(struct kvm_cpu *vcpu, uint32_t token,
+                         uint32_t nargs, target_ulong args,
+                         uint32_t nret, target_ulong rets)
+{
+       struct ics_state *ics = vcpu->kvm->icp->ics;
+       uint32_t nr;
+
+       if ((nargs != 1) || (nret != 3)) {
+               rtas_st(vcpu->kvm, rets, 0, -3);
+               return;
+       }
+
+       nr = rtas_ld(vcpu->kvm, args, 0);
+
+       if (!ics_valid_irq(ics, nr)) {
+               rtas_st(vcpu->kvm, rets, 0, -3);
+               return;
+       }
+
+       rtas_st(vcpu->kvm, rets, 0, 0); /* Success */
+       rtas_st(vcpu->kvm, rets, 1, ics->irqs[nr - ics->offset].server);
+       rtas_st(vcpu->kvm, rets, 2, ics->irqs[nr - ics->offset].priority);
+}
+
+static void rtas_int_off(struct kvm_cpu *vcpu, uint32_t token,
+                        uint32_t nargs, target_ulong args,
+                        uint32_t nret, target_ulong rets)
+{
+       struct ics_state *ics = vcpu->kvm->icp->ics;
+       uint32_t nr;
+
+       if ((nargs != 1) || (nret != 1)) {
+               rtas_st(vcpu->kvm, rets, 0, -3);
+               return;
+       }
+
+       nr = rtas_ld(vcpu->kvm, args, 0);
+
+       if (!ics_valid_irq(ics, nr)) {
+               rtas_st(vcpu->kvm, rets, 0, -3);
+               return;
+       }
+
+       /* ME: QEMU wrote xive_msi here, in #if 0.  Deleted. */
+
+       rtas_st(vcpu->kvm, rets, 0, 0); /* Success */
+}
+
+static void rtas_int_on(struct kvm_cpu *vcpu, uint32_t token,
+                       uint32_t nargs, target_ulong args,
+                       uint32_t nret, target_ulong rets)
+{
+       struct ics_state *ics = vcpu->kvm->icp->ics;
+       uint32_t nr;
+
+       if ((nargs != 1) || (nret != 1)) {
+               rtas_st(vcpu->kvm, rets, 0, -3);
+               return;
+       }
+
+       nr = rtas_ld(vcpu->kvm, args, 0);
+
+       if (!ics_valid_irq(ics, nr)) {
+               rtas_st(vcpu->kvm, rets, 0, -3);
+               return;
+       }
+
+       /* ME: QEMU wrote xive_msi here, in #if 0.  Deleted. */
+
+       rtas_st(vcpu->kvm, rets, 0, 0); /* Success */
+}
+
+void xics_cpu_register(struct kvm_cpu *vcpu)
+{
+       if (vcpu->cpu_id < vcpu->kvm->icp->nr_servers)
+               vcpu->kvm->icp->ss[vcpu->cpu_id].cpu = vcpu;
+       else
+               die("Setting invalid server for cpuid %ld\n", vcpu->cpu_id);
+}
+
+struct icp_state *xics_system_init(unsigned int nr_irqs, unsigned int nr_cpus)
+{
+       int max_server_num;
+       unsigned int i;
+       struct icp_state *icp;
+       struct ics_state *ics;
+
+       max_server_num = nr_cpus;
+
+       icp = malloc(sizeof(*icp));
+       icp->nr_servers = max_server_num + 1;
+       icp->ss = malloc(icp->nr_servers*sizeof(struct icp_server_state));
+
+       for (i = 0; i < icp->nr_servers; i++) {
+               icp->ss[i].xirr = 0;
+               icp->ss[i].pending_priority = 0;
+               icp->ss[i].cpu = 0;
+               icp->ss[i].mfrr = 0xff;
+       }
+
+       /*
+        * icp->ss[env->cpu_index].cpu is set by CPUs calling in to
+        * xics_cpu_register().
+        */
+
+       ics = malloc(sizeof(*ics));
+       ics->nr_irqs = nr_irqs;
+       ics->offset = XICS_IRQ_OFFSET;
+       ics->irqs = malloc(nr_irqs * sizeof(struct ics_irq_state));
+
+       icp->ics = ics;
+       ics->icp = icp;
+
+       for (i = 0; i < nr_irqs; i++) {
+               ics->irqs[i].server = 0;
+               ics->irqs[i].priority = 0xff;
+               ics->irqs[i].saved_priority = 0xff;
+               ics->irqs[i].rejected = 0;
+               ics->irqs[i].masked_pending = 0;
+       }
+
+       spapr_register_hypercall(H_CPPR, h_cppr);
+       spapr_register_hypercall(H_IPI, h_ipi);
+       spapr_register_hypercall(H_XIRR, h_xirr);
+       spapr_register_hypercall(H_EOI, h_eoi);
+
+       spapr_rtas_register("ibm,set-xive", rtas_set_xive);
+       spapr_rtas_register("ibm,get-xive", rtas_get_xive);
+       spapr_rtas_register("ibm,int-off", rtas_int_off);
+       spapr_rtas_register("ibm,int-on", rtas_int_on);
+
+       return icp;
+}
+
+void kvm__irq_line(struct kvm *kvm, int irq, int level)
+{
+       /*
+        * Route event to ICS, which routes to ICP, which eventually does a
+        * kvm_cpu__irq(vcpu, POWER7_EXT_IRQ, 1)
+        */
+       xics_dprintf("Raising IRQ %d -> %d\n", irq, level);
+       ics_set_irq_msi(kvm->icp->ics, irq - kvm->icp->ics->offset, level);
+}
diff --git a/tools/kvm/powerpc/xics.h b/tools/kvm/powerpc/xics.h
new file mode 100644 (file)
index 0000000..144915b
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * PAPR Virtualized Interrupt System, aka ICS/ICP aka xics
+ *
+ * Copyright 2011 Matt Evans <matt@ozlabs.org>, IBM Corporation.
+ *
+ * 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 XICS_H
+#define XICS_H
+
+#define XICS_IPI        0x2
+
+struct kvm_cpu;
+struct icp_state;
+
+struct icp_state *xics_system_init(unsigned int nr_irqs, unsigned int nr_cpus);
+void xics_cpu_register(struct kvm_cpu *vcpu);
+int xics_alloc_irqnum(void);
+
+#endif
diff --git a/tools/kvm/symbol.c b/tools/kvm/symbol.c
new file mode 100644 (file)
index 0000000..b76d98b
--- /dev/null
@@ -0,0 +1,131 @@
+#include "kvm/symbol.h"
+
+#include "kvm/kvm.h"
+
+#include <linux/err.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <bfd.h>
+
+static bfd *abfd;
+
+int symbol_init(struct kvm *kvm)
+{
+       int ret = 0;
+
+       if (!kvm->vmlinux)
+               return -EINVAL;
+
+       bfd_init();
+
+       abfd = bfd_openr(kvm->vmlinux, NULL);
+       if (abfd == NULL) {
+               bfd_error_type err = bfd_get_error();
+
+               switch (err) {
+               case bfd_error_no_memory:
+                       ret = -ENOMEM;
+                       break;
+               case bfd_error_invalid_target:
+                       ret = -EINVAL;
+                       break;
+               default:
+                       ret = -EFAULT;
+                       break;
+               }
+       }
+
+       return ret;
+}
+
+static asymbol *lookup(asymbol **symbols, int nr_symbols, const char *symbol_name)
+{
+       int i, ret;
+
+       ret = -ENOENT;
+
+       for (i = 0; i < nr_symbols; i++) {
+               asymbol *symbol = symbols[i];
+
+               if (!strcmp(bfd_asymbol_name(symbol), symbol_name))
+                       return symbol;
+       }
+
+       return ERR_PTR(ret);
+}
+
+char *symbol_lookup(struct kvm *kvm, unsigned long addr, char *sym, size_t size)
+{
+       const char *filename;
+       bfd_vma sym_offset;
+       bfd_vma sym_start;
+       asection *section;
+       unsigned int line;
+       const char *func;
+       long symtab_size;
+       asymbol *symbol;
+       asymbol **syms;
+       int nr_syms, ret;
+
+       ret = -ENOENT;
+       if (!abfd)
+               goto not_found;
+
+       if (!bfd_check_format(abfd, bfd_object))
+               goto not_found;
+
+       symtab_size = bfd_get_symtab_upper_bound(abfd);
+       if (!symtab_size)
+               goto not_found;
+
+       ret = -ENOMEM;
+       syms = malloc(symtab_size);
+       if (!syms)
+               goto not_found;
+
+       nr_syms = bfd_canonicalize_symtab(abfd, syms);
+
+       ret = -ENOENT;
+       section = bfd_get_section_by_name(abfd, ".debug_aranges");
+       if (!section)
+               goto not_found;
+
+       if (!bfd_find_nearest_line(abfd, section, NULL, addr, &filename, &func, &line))
+               goto not_found;
+
+       if (!func)
+               goto not_found;
+
+       symbol = lookup(syms, nr_syms, func);
+       if (IS_ERR(symbol))
+               goto not_found;
+
+       sym_start = bfd_asymbol_value(symbol);
+
+       sym_offset = addr - sym_start;
+
+       snprintf(sym, size, "%s+%llx (%s:%i)", func, (long long) sym_offset, filename, line);
+
+       sym[size - 1] = '\0';
+
+       free(syms);
+
+       return sym;
+
+not_found:
+       return ERR_PTR(ret);
+}
+
+int symbol_exit(struct kvm *kvm)
+{
+       bfd_boolean ret = TRUE;
+
+       if (abfd)
+               ret = bfd_close(abfd);
+
+       if (ret == TRUE)
+               return 0;
+
+       return -EFAULT;
+}
diff --git a/tools/kvm/term.c b/tools/kvm/term.c
new file mode 100644 (file)
index 0000000..cc0c5a5
--- /dev/null
@@ -0,0 +1,166 @@
+#include <poll.h>
+#include <stdbool.h>
+#include <termios.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/uio.h>
+#include <signal.h>
+#include <pty.h>
+#include <utmp.h>
+
+#include "kvm/read-write.h"
+#include "kvm/term.h"
+#include "kvm/util.h"
+#include "kvm/kvm.h"
+#include "kvm/kvm-cpu.h"
+
+#define TERM_FD_IN      0
+#define TERM_FD_OUT     1
+
+extern struct kvm *kvm;
+static struct termios  orig_term;
+
+int term_escape_char   = 0x01; /* ctrl-a is used for escape */
+bool term_got_escape   = false;
+
+int active_console;
+
+int term_fds[4][2];
+
+int term_getc(int who, int term)
+{
+       unsigned char c;
+
+       if (who != active_console)
+               return -1;
+       if (read_in_full(term_fds[term][TERM_FD_IN], &c, 1) < 0)
+               return -1;
+
+       if (term_got_escape) {
+               term_got_escape = false;
+               if (c == 'x')
+                       kvm_cpu__reboot();
+               if (c == term_escape_char)
+                       return c;
+       }
+
+       if (c == term_escape_char) {
+               term_got_escape = true;
+               return -1;
+       }
+
+       return c;
+}
+
+int term_putc(int who, char *addr, int cnt, int term)
+{
+       int ret;
+
+       if (who != active_console)
+               return -1;
+
+       while (cnt--) {
+               ret = write(term_fds[term][TERM_FD_OUT], addr++, 1);
+               if (ret < 0)
+                       return 0;
+       }
+
+       return cnt;
+}
+
+int term_getc_iov(int who, struct iovec *iov, int iovcnt, int term)
+{
+       int c;
+
+       if (who != active_console)
+               return 0;
+
+       c = term_getc(who, term);
+
+       if (c < 0)
+               return 0;
+
+       *((char *)iov[TERM_FD_IN].iov_base)     = (char)c;
+
+       return sizeof(char);
+}
+
+int term_putc_iov(int who, struct iovec *iov, int iovcnt, int term)
+{
+       if (who != active_console)
+               return 0;
+
+       return writev(term_fds[term][TERM_FD_OUT], iov, iovcnt);
+}
+
+bool term_readable(int who, int term)
+{
+       struct pollfd pollfd = (struct pollfd) {
+               .fd     = term_fds[term][TERM_FD_IN],
+               .events = POLLIN,
+               .revents = 0,
+       };
+
+       if (who != active_console)
+               return false;
+
+       return poll(&pollfd, 1, 0) > 0;
+}
+
+static void term_cleanup(void)
+{
+       int i;
+
+       for (i = 0; i < 4; i++)
+               tcsetattr(term_fds[i][TERM_FD_IN], TCSANOW, &orig_term);
+}
+
+static void term_sig_cleanup(int sig)
+{
+       term_cleanup();
+       signal(sig, SIG_DFL);
+       raise(sig);
+}
+
+void term_set_tty(int term)
+{
+       struct termios orig_term;
+       int master, slave;
+       char new_pty[PATH_MAX];
+
+       if (tcgetattr(STDIN_FILENO, &orig_term) < 0)
+               die("unable to save initial standard input settings");
+
+       orig_term.c_lflag &= ~(ICANON | ECHO | ISIG);
+
+       if (openpty(&master, &slave, new_pty, &orig_term, NULL) < 0)
+               return;
+
+       close(slave);
+
+       pr_info("Assigned terminal %d to pty %s\n", term, new_pty);
+
+       term_fds[term][TERM_FD_IN] = term_fds[term][TERM_FD_OUT] = master;
+}
+
+void term_init(void)
+{
+       struct termios term;
+       int i;
+
+       if (tcgetattr(STDIN_FILENO, &orig_term) < 0)
+               die("unable to save initial standard input settings");
+
+       term = orig_term;
+       term.c_lflag &= ~(ICANON | ECHO | ISIG);
+       tcsetattr(STDIN_FILENO, TCSANOW, &term);
+
+       for (i = 0; i < 4; i++)
+               if (term_fds[i][TERM_FD_IN] == 0) {
+                       term_fds[i][TERM_FD_IN] = STDIN_FILENO;
+                       term_fds[i][TERM_FD_OUT] = STDOUT_FILENO;
+               }
+
+       signal(SIGTERM, term_sig_cleanup);
+       atexit(term_cleanup);
+}
diff --git a/tools/kvm/tests/Makefile b/tools/kvm/tests/Makefile
new file mode 100644 (file)
index 0000000..cad14ec
--- /dev/null
@@ -0,0 +1,19 @@
+all: kernel pit boot
+
+kernel:
+       $(MAKE) -C kernel
+.PHONY: kernel
+
+pit:
+       $(MAKE) -C pit
+.PHONY: pit
+
+boot:
+       $(MAKE) -C boot
+.PHONY: boot
+
+clean:
+       $(MAKE) -C kernel clean
+       $(MAKE) -C pit clean
+       $(MAKE) -C boot clean
+.PHONY: clean
diff --git a/tools/kvm/tests/boot/Makefile b/tools/kvm/tests/boot/Makefile
new file mode 100644 (file)
index 0000000..40cba68
--- /dev/null
@@ -0,0 +1,13 @@
+NAME   := init
+
+OBJ    := $(NAME).o
+
+all: $(.o)
+       rm -rf rootfs
+       mkdir rootfs
+       gcc -static init.c -o rootfs/init
+       mkisofs rootfs > boot_test.iso
+
+clean:
+       rm -rf rootfs boot_test.iso
+.PHONY: clean
diff --git a/tools/kvm/tests/boot/init.c b/tools/kvm/tests/boot/init.c
new file mode 100644 (file)
index 0000000..094f8ba
--- /dev/null
@@ -0,0 +1,11 @@
+#include <linux/reboot.h>
+#include <unistd.h>
+
+int main(int argc, char *argv[])
+{
+       puts("hello, KVM guest!\r");
+
+       reboot(LINUX_REBOOT_CMD_RESTART);
+
+       return 0;
+}
diff --git a/tools/kvm/tests/kernel/.gitignore b/tools/kvm/tests/kernel/.gitignore
new file mode 100644 (file)
index 0000000..d0cd209
--- /dev/null
@@ -0,0 +1,2 @@
+kernel.bin
+kernel.elf
diff --git a/tools/kvm/tests/kernel/Makefile b/tools/kvm/tests/kernel/Makefile
new file mode 100644 (file)
index 0000000..c7dd8da
--- /dev/null
@@ -0,0 +1,20 @@
+NAME   := kernel
+
+BIN    := $(NAME).bin
+ELF    := $(NAME).elf
+OBJ    := $(NAME).o
+
+all: $(BIN)
+
+$(BIN): $(ELF)
+       objcopy -O binary $< $@
+
+$(ELF): $(OBJ)
+       ld -Ttext=0x00 -nostdlib -static $< -o $@
+
+%.o: %.S
+       gcc -nostdinc -c $< -o $@
+
+clean:
+       rm -f $(BIN) $(ELF) $(OBJ)
+.PHONY: clean
diff --git a/tools/kvm/tests/kernel/README b/tools/kvm/tests/kernel/README
new file mode 100644 (file)
index 0000000..2923777
--- /dev/null
@@ -0,0 +1,16 @@
+Compiling
+---------
+
+You can simply type:
+
+  $ make
+
+to build a 16-bit binary that uses the i8086 instruction set.
+
+Disassembling
+-------------
+
+Use the "-m i8086" command line option with objdump to make sure it knows we're
+dealing with i8086 instruction set:
+
+  $ objdump -d -m i8086 i8086.elf
diff --git a/tools/kvm/tests/kernel/kernel.S b/tools/kvm/tests/kernel/kernel.S
new file mode 100644 (file)
index 0000000..2824b64
--- /dev/null
@@ -0,0 +1,8 @@
+       .code16gcc
+       .text
+       .globl  _start
+       .type   _start, @function
+_start:
+       # "This is probably the largest possible kernel that is bug free." -- Avi Kivity
+       1:
+       jmp 1b
diff --git a/tools/kvm/tests/pit/.gitignore b/tools/kvm/tests/pit/.gitignore
new file mode 100644 (file)
index 0000000..43f0aa8
--- /dev/null
@@ -0,0 +1,2 @@
+*.bin
+*.elf
diff --git a/tools/kvm/tests/pit/Makefile b/tools/kvm/tests/pit/Makefile
new file mode 100644 (file)
index 0000000..2fae9b2
--- /dev/null
@@ -0,0 +1,20 @@
+NAME   := tick
+
+BIN    := $(NAME).bin
+ELF    := $(NAME).elf
+OBJ    := $(NAME).o
+
+all: $(BIN)
+
+$(BIN): $(ELF)
+       objcopy -O binary $< $@
+
+$(ELF): $(OBJ)
+       ld -Ttext=0x00 -nostdlib -static $< -o $@
+
+%.o: %.S
+       gcc -nostdinc -c $< -o $@
+
+clean:
+       rm -f $(BIN) $(ELF) $(OBJ)
+.PHONY: clean
diff --git a/tools/kvm/tests/pit/README b/tools/kvm/tests/pit/README
new file mode 100644 (file)
index 0000000..2923777
--- /dev/null
@@ -0,0 +1,16 @@
+Compiling
+---------
+
+You can simply type:
+
+  $ make
+
+to build a 16-bit binary that uses the i8086 instruction set.
+
+Disassembling
+-------------
+
+Use the "-m i8086" command line option with objdump to make sure it knows we're
+dealing with i8086 instruction set:
+
+  $ objdump -d -m i8086 i8086.elf
diff --git a/tools/kvm/tests/pit/tick.S b/tools/kvm/tests/pit/tick.S
new file mode 100644 (file)
index 0000000..b9e5a80
--- /dev/null
@@ -0,0 +1,109 @@
+#define IO_PIC         0x20
+#define IRQ_OFFSET     32
+#define IO_PIT         0x40
+#define TIMER_FREQ     1193182
+#define TIMER_DIV(x)   ((TIMER_FREQ+(x)/2)/(x))
+
+/*
+ * hpa noted:
+ *
+ * 0xe0..0xef are "motherboard specific", but 0xe9 is
+ * used for Bochs debugging and 0xed is the Phoenix-reserved
+ * delay port
+ */
+#define DBG_PORT       0xe0
+
+#define TEST_COUNT     0x0200
+
+       .code16gcc
+       .text
+       .globl  _start
+       .type   _start, @function
+_start:
+/*
+ * fill up noop handlers
+ */
+       xorw    %ax, %ax
+       xorw    %di, %di
+       movw    %ax, %es
+       movw    $256, %cx
+fill_noop_idt:
+       movw    $noop_handler, %es:(%di)
+       movw    %cs, %es:2(%di)
+       add     $4, %di
+       loop    fill_noop_idt
+
+set_idt:
+       movw    $timer_isr, %es:(IRQ_OFFSET*4)
+       movw    %cs, %es:(IRQ_OFFSET*4+2)
+
+set_pic:
+       # ICW1
+       mov     $0x11, %al
+       mov     $(IO_PIC), %dx
+       out     %al,%dx
+       # ICW2
+       mov     $(IRQ_OFFSET), %al
+       mov     $(IO_PIC+1), %dx
+       out     %al, %dx
+       # ICW3
+       mov     $0x00, %al
+       mov     $(IO_PIC+1), %dx
+       out     %al, %dx
+       # ICW4
+       mov     $0x3, %al
+       mov     $(IO_PIC+1), %dx
+       out     %al, %dx
+
+set_pit:
+       # set 8254 mode
+       mov     $(IO_PIT+3), %dx
+       mov     $0x34, %al
+       outb    %al, %dx
+       # set 8254 freq 1KHz
+       mov     $(IO_PIT), %dx
+       movb    $(TIMER_DIV(1000) % 256), %al
+       outb    %al, %dx
+       movb    $(TIMER_DIV(1000) / 256), %al
+       outb    %al, %dx
+
+enable_irq0:
+       mov     $0xfe, %al
+       mov     $(IO_PIC+1), %dx
+       out     %al, %dx
+       sti
+loop:
+       1:
+       jmp     1b
+
+test_ok:
+       mov     $0x3f8,%dx
+       cs lea  msg2, %si
+       mov     $(msg2_end-msg2), %cx
+       cs rep/outsb
+
+       /* not a valid port to force exit */
+       outb    %al, $DBG_PORT
+
+timer_isr:
+       cli
+       pushaw
+       pushfw
+       mov     $0x3f8,%dx
+       mov     $0x2e, %al      # .
+       out     %al,%dx
+       decw    count
+       jz      test_ok
+       popfw
+       popaw
+       iretw
+
+noop_handler:
+       iretw
+
+count:
+       .word   TEST_COUNT
+
+msg2:
+       .asciz "\nTest OK\n"
+msg2_end:
diff --git a/tools/kvm/ui/sdl.c b/tools/kvm/ui/sdl.c
new file mode 100644 (file)
index 0000000..708b9a9
--- /dev/null
@@ -0,0 +1,303 @@
+#include "kvm/sdl.h"
+
+#include "kvm/framebuffer.h"
+#include "kvm/i8042.h"
+#include "kvm/util.h"
+#include "kvm/kvm.h"
+#include "kvm/kvm-cpu.h"
+
+#include <SDL/SDL.h>
+#include <pthread.h>
+#include <signal.h>
+
+#define FRAME_RATE             25
+
+#define SCANCODE_UNKNOWN      0
+#define SCANCODE_NORMAL       1
+#define SCANCODE_ESCAPED      2
+#define SCANCODE_KEY_PAUSE    3
+#define SCANCODE_KEY_PRNTSCRN 4
+
+struct set2_scancode {
+       u8 code;
+       u8 type;
+};
+
+#define DEFINE_SC(_code) {\
+       .code = _code,\
+       .type = SCANCODE_NORMAL,\
+}
+
+/* escaped scancodes */
+#define DEFINE_ESC(_code) {\
+       .code = _code,\
+       .type = SCANCODE_ESCAPED,\
+}
+
+static const struct set2_scancode const keymap[256] = {
+       [9]     = DEFINE_SC(0x76),      /* <esc> */
+       [10]    = DEFINE_SC(0x16),      /* 1 */
+       [11]    = DEFINE_SC(0x1e),      /* 2 */
+       [12]    = DEFINE_SC(0x26),      /* 3 */
+       [13]    = DEFINE_SC(0x25),      /* 4 */
+       [14]    = DEFINE_SC(0x2e),      /* 5 */
+       [15]    = DEFINE_SC(0x36),      /* 6 */
+       [16]    = DEFINE_SC(0x3d),      /* 7 */
+       [17]    = DEFINE_SC(0x3e),      /* 8 */
+       [18]    = DEFINE_SC(0x46),      /* 9 */
+       [19]    = DEFINE_SC(0x45),      /* 9 */
+       [20]    = DEFINE_SC(0x4e),      /* - */
+       [21]    = DEFINE_SC(0x55),      /* + */
+       [22]    = DEFINE_SC(0x66),      /* <backspace> */
+       [23]    = DEFINE_SC(0x0d),      /* <tab> */
+       [24]    = DEFINE_SC(0x15),      /* q */
+       [25]    = DEFINE_SC(0x1d),      /* w */
+       [26]    = DEFINE_SC(0x24),      /* e */
+       [27]    = DEFINE_SC(0x2d),      /* r */
+       [28]    = DEFINE_SC(0x2c),      /* t */
+       [29]    = DEFINE_SC(0x35),      /* y */
+       [30]    = DEFINE_SC(0x3c),      /* u */
+       [31]    = DEFINE_SC(0x43),      /* i */
+       [32]    = DEFINE_SC(0x44),      /* o */
+       [33]    = DEFINE_SC(0x4d),      /* p */
+       [34]    = DEFINE_SC(0x54),      /* [ */
+       [35]    = DEFINE_SC(0x5b),      /* ] */
+       [36]    = DEFINE_SC(0x5a),      /* <enter> */
+       [37]    = DEFINE_SC(0x14),      /* <left ctrl> */
+       [38]    = DEFINE_SC(0x1c),      /* a */
+       [39]    = DEFINE_SC(0x1b),      /* s */
+       [40]    = DEFINE_SC(0x23),      /* d */
+       [41]    = DEFINE_SC(0x2b),      /* f */
+       [42]    = DEFINE_SC(0x34),      /* g */
+       [43]    = DEFINE_SC(0x33),      /* h */
+       [44]    = DEFINE_SC(0x3b),      /* j */
+       [45]    = DEFINE_SC(0x42),      /* k */
+       [46]    = DEFINE_SC(0x4b),      /* l */
+       [47]    = DEFINE_SC(0x4c),      /* ; */
+       [48]    = DEFINE_SC(0x52),      /* ' */
+       [49]    = DEFINE_SC(0x0e),      /* ` */
+       [50]    = DEFINE_SC(0x12),      /* <left shift> */
+       [51]    = DEFINE_SC(0x5d),      /* \ */
+       [52]    = DEFINE_SC(0x1a),      /* z */
+       [53]    = DEFINE_SC(0x22),      /* x */
+       [54]    = DEFINE_SC(0x21),      /* c */
+       [55]    = DEFINE_SC(0x2a),      /* v */
+       [56]    = DEFINE_SC(0x32),      /* b */
+       [57]    = DEFINE_SC(0x31),      /* n */
+       [58]    = DEFINE_SC(0x3a),      /* m */
+       [59]    = DEFINE_SC(0x41),      /* < */
+       [60]    = DEFINE_SC(0x49),      /* > */
+       [61]    = DEFINE_SC(0x4a),      /* / */
+       [62]    = DEFINE_SC(0x59),      /* <right shift> */
+       [63]    = DEFINE_SC(0x7c),      /* keypad * */
+       [64]    = DEFINE_SC(0x11),      /* <left alt> */
+       [65]    = DEFINE_SC(0x29),      /* <space> */
+
+       [67]    = DEFINE_SC(0x05),      /* <F1> */
+       [68]    = DEFINE_SC(0x06),      /* <F2> */
+       [69]    = DEFINE_SC(0x04),      /* <F3> */
+       [70]    = DEFINE_SC(0x0c),      /* <F4> */
+       [71]    = DEFINE_SC(0x03),      /* <F5> */
+       [72]    = DEFINE_SC(0x0b),      /* <F6> */
+       [73]    = DEFINE_SC(0x83),      /* <F7> */
+       [74]    = DEFINE_SC(0x0a),      /* <F8> */
+       [75]    = DEFINE_SC(0x01),      /* <F9> */
+       [76]    = DEFINE_SC(0x09),      /* <F10> */
+
+       [79]    = DEFINE_SC(0x6c),      /* keypad 7 */
+       [80]    = DEFINE_SC(0x75),      /* keypad 8 */
+       [81]    = DEFINE_SC(0x7d),      /* keypad 9 */
+       [82]    = DEFINE_SC(0x7b),      /* keypad - */
+       [83]    = DEFINE_SC(0x6b),      /* keypad 4 */
+       [84]    = DEFINE_SC(0x73),      /* keypad 5 */
+       [85]    = DEFINE_SC(0x74),      /* keypad 6 */
+       [86]    = DEFINE_SC(0x79),      /* keypad + */
+       [87]    = DEFINE_SC(0x69),      /* keypad 1 */
+       [88]    = DEFINE_SC(0x72),      /* keypad 2 */
+       [89]    = DEFINE_SC(0x7a),      /* keypad 3 */
+       [90]    = DEFINE_SC(0x70),      /* keypad 0 */
+       [91]    = DEFINE_SC(0x71),      /* keypad . */
+
+       [94]    = DEFINE_SC(0x61),      /* <INT 1> */
+       [95]    = DEFINE_SC(0x78),      /* <F11> */
+       [96]    = DEFINE_SC(0x07),      /* <F12> */
+
+       [104]   = DEFINE_ESC(0x5a),     /* keypad <enter> */
+       [105]   = DEFINE_ESC(0x14),     /* <right ctrl> */
+       [106]   = DEFINE_ESC(0x4a),     /* keypad / */
+       [108]   = DEFINE_ESC(0x11),     /* <right alt> */
+       [110]   = DEFINE_ESC(0x6c),     /* <home> */
+       [111]   = DEFINE_ESC(0x75),     /* <up> */
+       [112]   = DEFINE_ESC(0x7d),     /* <pag up> */
+       [113]   = DEFINE_ESC(0x6b),     /* <left> */
+       [114]   = DEFINE_ESC(0x74),     /* <right> */
+       [115]   = DEFINE_ESC(0x69),     /* <end> */
+       [116]   = DEFINE_ESC(0x72),     /* <down> */
+       [117]   = DEFINE_ESC(0x7a),     /* <pag down> */
+       [118]   = DEFINE_ESC(0x70),     /* <ins> */
+       [119]   = DEFINE_ESC(0x71),     /* <delete> */
+};
+static bool running, done;
+
+static const struct set2_scancode *to_code(u8 scancode)
+{
+       return &keymap[scancode];
+}
+
+static void key_press(const struct set2_scancode *sc)
+{
+       switch (sc->type) {
+       case SCANCODE_ESCAPED:
+               kbd_queue(0xe0);
+               /* fallthrough */
+       case SCANCODE_NORMAL:
+               kbd_queue(sc->code);
+               break;
+       case SCANCODE_KEY_PAUSE:
+               kbd_queue(0xe1);
+               kbd_queue(0x14);
+               kbd_queue(0x77);
+               kbd_queue(0xe1);
+               kbd_queue(0xf0);
+               kbd_queue(0x14);
+               kbd_queue(0x77);
+               break;
+       case SCANCODE_KEY_PRNTSCRN:
+               kbd_queue(0xe0);
+               kbd_queue(0x12);
+               kbd_queue(0xe0);
+               kbd_queue(0x7c);
+               break;
+       }
+}
+
+static void key_release(const struct set2_scancode *sc)
+{
+       switch (sc->type) {
+       case SCANCODE_ESCAPED:
+               kbd_queue(0xe0);
+               /* fallthrough */
+       case SCANCODE_NORMAL:
+               kbd_queue(0xf0);
+               kbd_queue(sc->code);
+               break;
+       case SCANCODE_KEY_PAUSE:
+               /* nothing to do */
+               break;
+       case SCANCODE_KEY_PRNTSCRN:
+               kbd_queue(0xe0);
+               kbd_queue(0xf0);
+               kbd_queue(0x7c);
+               kbd_queue(0xe0);
+               kbd_queue(0xf0);
+               kbd_queue(0x12);
+               break;
+       }
+}
+
+static void *sdl__thread(void *p)
+{
+       Uint32 rmask, gmask, bmask, amask;
+       struct framebuffer *fb = p;
+       SDL_Surface *guest_screen;
+       SDL_Surface *screen;
+       SDL_Event ev;
+       Uint32 flags;
+
+       if (SDL_Init(SDL_INIT_VIDEO) != 0)
+               die("Unable to initialize SDL");
+
+       rmask = 0x000000ff;
+       gmask = 0x0000ff00;
+       bmask = 0x00ff0000;
+       amask = 0x00000000;
+
+       guest_screen = SDL_CreateRGBSurfaceFrom(fb->mem, fb->width, fb->height, fb->depth, fb->width * fb->depth / 8, rmask, gmask, bmask, amask);
+       if (!guest_screen)
+               die("Unable to create SDL RBG surface");
+
+       flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL | SDL_DOUBLEBUF;
+
+       SDL_WM_SetCaption("KVM tool", "KVM tool");
+
+       screen = SDL_SetVideoMode(fb->width, fb->height, fb->depth, flags);
+       if (!screen)
+               die("Unable to set SDL video mode");
+
+       SDL_EnableKeyRepeat(200, 50);
+
+       while (running) {
+               SDL_BlitSurface(guest_screen, NULL, screen, NULL);
+               SDL_Flip(screen);
+
+               while (SDL_PollEvent(&ev)) {
+                       switch (ev.type) {
+                       case SDL_KEYDOWN: {
+                               const struct set2_scancode *sc = to_code(ev.key.keysym.scancode);
+                               if (sc->type == SCANCODE_UNKNOWN) {
+                                       pr_warning("key '%d' not found in keymap", ev.key.keysym.scancode);
+                                       break;
+                               }
+                               key_press(sc);
+                               break;
+                       }
+                       case SDL_KEYUP: {
+                               const struct set2_scancode *sc = to_code(ev.key.keysym.scancode);
+                               if (sc->type == SCANCODE_UNKNOWN)
+                                       break;
+                               key_release(sc);
+                               break;
+                       }
+                       case SDL_QUIT:
+                               goto exit;
+                       }
+               }
+
+               SDL_Delay(1000 / FRAME_RATE);
+       }
+
+       if (running == false && done == false) {
+               done = true;
+               return NULL;
+       }
+exit:
+       kvm_cpu__reboot();
+
+       return NULL;
+}
+
+static int sdl__start(struct framebuffer *fb)
+{
+       pthread_t thread;
+
+       running = true;
+
+       if (pthread_create(&thread, NULL, sdl__thread, fb) != 0)
+               return -1;
+
+       return 0;
+}
+
+static int sdl__stop(struct framebuffer *fb)
+{
+       running = false;
+       while (done == false)
+               sleep(0);
+
+       return 0;
+}
+
+static struct fb_target_operations sdl_ops = {
+       .start  = sdl__start,
+       .stop   = sdl__stop,
+};
+
+int sdl__init(struct framebuffer *fb)
+{
+       return fb__attach(fb, &sdl_ops);
+}
+
+int sdl__exit(struct framebuffer *fb)
+{
+       return sdl__stop(fb);
+}
diff --git a/tools/kvm/ui/vnc.c b/tools/kvm/ui/vnc.c
new file mode 100644 (file)
index 0000000..91254c5
--- /dev/null
@@ -0,0 +1,230 @@
+#include "kvm/vnc.h"
+
+#include "kvm/framebuffer.h"
+#include "kvm/i8042.h"
+
+#include <linux/types.h>
+#include <rfb/keysym.h>
+#include <rfb/rfb.h>
+#include <pthread.h>
+
+#define VESA_QUEUE_SIZE                128
+#define VESA_IRQ               14
+
+/*
+ * This "6000" value is pretty much the result of experimentation
+ * It seems that around this value, things update pretty smoothly
+ */
+#define VESA_UPDATE_TIME       6000
+
+/*
+ * We can map the letters and numbers without a fuss,
+ * but the other characters not so much.
+ */
+static char letters[26] = {
+       0x1c, 0x32, 0x21, 0x23, 0x24, /* a-e */
+       0x2b, 0x34, 0x33, 0x43, 0x3b, /* f-j */
+       0x42, 0x4b, 0x3a, 0x31, 0x44, /* k-o */
+       0x4d, 0x15, 0x2d, 0x1b, 0x2c, /* p-t */
+       0x3c, 0x2a, 0x1d, 0x22, 0x35, /* u-y */
+       0x1a,
+};
+
+static rfbScreenInfoPtr server;
+static char num[10] = {
+       0x45, 0x16, 0x1e, 0x26, 0x2e, 0x23, 0x36, 0x3d, 0x3e, 0x46,
+};
+
+/*
+ * This is called when the VNC server receives a key event
+ * The reason this function is such a beast is that we have
+ * to convert from ASCII characters (which is what VNC gets)
+ * to PC keyboard scancodes, which is what Linux expects to
+ * get from its keyboard. ASCII and the scancode set don't
+ * really seem to mesh in any good way beyond some basics with
+ * the letters and numbers.
+ */
+static void kbd_handle_key(rfbBool down, rfbKeySym key, rfbClientPtr cl)
+{
+       char tosend = 0;
+
+       if (key >= 0x41 && key <= 0x5a)
+               key += 0x20; /* convert to lowercase */
+
+       if (key >= 0x61 && key <= 0x7a) /* a-z */
+               tosend = letters[key - 0x61];
+
+       if (key >= 0x30 && key <= 0x39)
+               tosend = num[key - 0x30];
+
+       switch (key) {
+       case XK_Insert:         kbd_queue(0xe0);        tosend = 0x70;  break;
+       case XK_Delete:         kbd_queue(0xe0);        tosend = 0x71;  break;
+       case XK_Up:             kbd_queue(0xe0);        tosend = 0x75;  break;
+       case XK_Down:           kbd_queue(0xe0);        tosend = 0x72;  break;
+       case XK_Left:           kbd_queue(0xe0);        tosend = 0x6b;  break;
+       case XK_Right:          kbd_queue(0xe0);        tosend = 0x74;  break;
+       case XK_Page_Up:        kbd_queue(0xe0);        tosend = 0x7d;  break;
+       case XK_Page_Down:      kbd_queue(0xe0);        tosend = 0x7a;  break;
+       case XK_Home:           kbd_queue(0xe0);        tosend = 0x6c;  break;
+       case XK_BackSpace:      tosend = 0x66;          break;
+       case XK_Tab:            tosend = 0x0d;          break;
+       case XK_Return:         tosend = 0x5a;          break;
+       case XK_Escape:         tosend = 0x76;          break;
+       case XK_End:            tosend = 0x69;          break;
+       case XK_Shift_L:        tosend = 0x12;          break;
+       case XK_Shift_R:        tosend = 0x59;          break;
+       case XK_Control_R:      kbd_queue(0xe0);
+       case XK_Control_L:      tosend = 0x14;          break;
+       case XK_Alt_R:          kbd_queue(0xe0);
+       case XK_Alt_L:          tosend = 0x11;          break;
+       case XK_quoteleft:      tosend = 0x0e;          break;
+       case XK_minus:          tosend = 0x4e;          break;
+       case XK_equal:          tosend = 0x55;          break;
+       case XK_bracketleft:    tosend = 0x54;          break;
+       case XK_bracketright:   tosend = 0x5b;          break;
+       case XK_backslash:      tosend = 0x5d;          break;
+       case XK_Caps_Lock:      tosend = 0x58;          break;
+       case XK_semicolon:      tosend = 0x4c;          break;
+       case XK_quoteright:     tosend = 0x52;          break;
+       case XK_comma:          tosend = 0x41;          break;
+       case XK_period:         tosend = 0x49;          break;
+       case XK_slash:          tosend = 0x4a;          break;
+       case XK_space:          tosend = 0x29;          break;
+
+       /*
+        * This is where I handle the shifted characters.
+        * They don't really map nicely the way A-Z maps to a-z,
+        * so I'm doing it manually
+        */
+       case XK_exclam:         tosend = 0x16;          break;
+       case XK_quotedbl:       tosend = 0x52;          break;
+       case XK_numbersign:     tosend = 0x26;          break;
+       case XK_dollar:         tosend = 0x25;          break;
+       case XK_percent:        tosend = 0x2e;          break;
+       case XK_ampersand:      tosend = 0x3d;          break;
+       case XK_parenleft:      tosend = 0x46;          break;
+       case XK_parenright:     tosend = 0x45;          break;
+       case XK_asterisk:       tosend = 0x3e;          break;
+       case XK_plus:           tosend = 0x55;          break;
+       case XK_colon:          tosend = 0x4c;          break;
+       case XK_less:           tosend = 0x41;          break;
+       case XK_greater:        tosend = 0x49;          break;
+       case XK_question:       tosend = 0x4a;          break;
+       case XK_at:             tosend = 0x1e;          break;
+       case XK_asciicircum:    tosend = 0x36;          break;
+       case XK_underscore:     tosend = 0x4e;          break;
+       case XK_braceleft:      tosend = 0x54;          break;
+       case XK_braceright:     tosend = 0x5b;          break;
+       case XK_bar:            tosend = 0x5d;          break;
+       case XK_asciitilde:     tosend = 0x0e;          break;
+       default:                break;
+       }
+
+       /*
+        * If this is a "key up" event (the user has released the key, we
+        * need to send 0xf0 first.
+        */
+       if (!down && tosend != 0x0)
+               kbd_queue(0xf0);
+
+       if (tosend)
+               kbd_queue(tosend);
+}
+
+/* The previous X and Y coordinates of the mouse */
+static int xlast, ylast = -1;
+
+/*
+ * This function is called by the VNC server whenever a mouse event occurs.
+ */
+static void kbd_handle_ptr(int buttonMask, int x, int y, rfbClientPtr cl)
+{
+       int dx, dy;
+       char b1 = 0x8;
+
+       /* The VNC mask and the PS/2 button encoding are the same */
+       b1 |= buttonMask;
+
+       if (xlast >= 0 && ylast >= 0) {
+               /* The PS/2 mouse sends deltas, not absolutes */
+               dx = x - xlast;
+               dy = ylast - y;
+
+               /* Set overflow bits if needed */
+               if (dy > 255)
+                       b1 |= 0x80;
+               if (dx > 255)
+                       b1 |= 0x40;
+
+               /* Set negative bits if needed */
+               if (dy < 0)
+                       b1 |= 0x20;
+               if (dx < 0)
+                       b1 |= 0x10;
+
+               mouse_queue(b1);
+               mouse_queue(dx);
+               mouse_queue(dy);
+       }
+
+       xlast = x;
+       ylast = y;
+       rfbDefaultPtrAddEvent(buttonMask, x, y, cl);
+}
+
+static void *vnc__thread(void *p)
+{
+       struct framebuffer *fb = p;
+       /*
+        * Make a fake argc and argv because the getscreen function
+        * seems to want it.
+        */
+       char argv[1][1] = {{0}};
+       int argc = 1;
+
+       server = rfbGetScreen(&argc, (char **) argv, fb->width, fb->height, 8, 3, 4);
+       server->frameBuffer             = fb->mem;
+       server->alwaysShared            = TRUE;
+       server->kbdAddEvent             = kbd_handle_key;
+       server->ptrAddEvent             = kbd_handle_ptr;
+       rfbInitServer(server);
+
+       while (rfbIsActive(server)) {
+               rfbMarkRectAsModified(server, 0, 0, fb->width, fb->height);
+               rfbProcessEvents(server, server->deferUpdateTime * VESA_UPDATE_TIME);
+       }
+       return NULL;
+}
+
+static int vnc__start(struct framebuffer *fb)
+{
+       pthread_t thread;
+
+       if (pthread_create(&thread, NULL, vnc__thread, fb) != 0)
+               return -1;
+
+       return 0;
+}
+
+static int vnc__stop(struct framebuffer *fb)
+{
+       rfbShutdownServer(server, TRUE);
+
+       return 0;
+}
+
+static struct fb_target_operations vnc_ops = {
+       .start  = vnc__start,
+       .stop   = vnc__stop,
+};
+
+int vnc__init(struct framebuffer *fb)
+{
+       return fb__attach(fb, &vnc_ops);
+}
+
+int vnc__exit(struct framebuffer *fb)
+{
+       return vnc__stop(fb);
+}
\ No newline at end of file
diff --git a/tools/kvm/util/KVMTOOLS-VERSION-GEN b/tools/kvm/util/KVMTOOLS-VERSION-GEN
new file mode 100755 (executable)
index 0000000..1af9d6c
--- /dev/null
@@ -0,0 +1,40 @@
+#!/bin/sh
+
+if [ $# -eq 1 ]  ; then
+       OUTPUT=$1
+fi
+
+GVF=${OUTPUT}KVMTOOLS-VERSION-FILE
+
+LF='
+'
+
+# First check if there is a .git to get the version from git describe
+# otherwise try to get the version from the kernel makefile
+if test -d ../../.git -o -f ../../.git &&
+       VN=$(git describe --abbrev=4 HEAD 2>/dev/null) &&
+       case "$VN" in
+       *$LF*) (exit 1) ;;
+       v[0-9]*)
+               git update-index -q --refresh
+               test -z "$(git diff-index --name-only HEAD --)" ||
+               VN="$VN-dirty" ;;
+       esac
+then
+       VN=$(echo "$VN" | sed -e 's/-/./g');
+else
+       VN=$(MAKEFLAGS= make -sC ../.. kernelversion)
+fi
+
+VN=$(expr "$VN" : v*'\(.*\)')
+
+if test -r $GVF
+then
+       VC=$(sed -e 's/^KVMTOOLS_VERSION = //' <$GVF)
+else
+       VC=unset
+fi
+test "$VN" = "$VC" || {
+       echo >&2 "KVMTOOLS_VERSION = $VN"
+       echo "KVMTOOLS_VERSION = $VN" >$GVF
+}
diff --git a/tools/kvm/util/generate-cmdlist.sh b/tools/kvm/util/generate-cmdlist.sh
new file mode 100755 (executable)
index 0000000..c8be0bd
--- /dev/null
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+echo "/* Automatically generated by $0 */
+struct cmdname_help
+{
+    char name[16];
+    char help[80];
+};
+
+static struct cmdname_help common_cmds[] = {"
+
+sed -n 's/^lkvm-\([^ \t]*\).*common/\1/p' command-list.txt |
+while read cmd
+do
+        # TODO following sed command should be fixed
+     sed -n '/^NAME/,/^lkvm-'"$cmd"'/ {
+                /NAME/d
+                /--/d
+                s/.*kvm-'"$cmd"' - \(.*\)/  {"'"$cmd"'", "\1"},/
+            p
+        }' "Documentation/kvm-$cmd.txt"
+done
+echo "};"
diff --git a/tools/kvm/util/kvm-ifup-vbr0 b/tools/kvm/util/kvm-ifup-vbr0
new file mode 100755 (executable)
index 0000000..a91c37f
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+switch=vbr0
+/sbin/ifconfig $1 0.0.0.0 up
+/usr/sbin/brctl addif ${switch} $1
+/usr/sbin/brctl setfd ${switch} 0
+/usr/sbin/brctl stp ${switch} off
diff --git a/tools/kvm/util/parse-options.c b/tools/kvm/util/parse-options.c
new file mode 100644 (file)
index 0000000..9a1bbee
--- /dev/null
@@ -0,0 +1,577 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <stdbool.h>
+
+/* user defined includes */
+#include <linux/types.h>
+#include <kvm/util.h>
+#include <kvm/parse-options.h>
+#include <kvm/strbuf.h>
+
+#define OPT_SHORT 1
+#define OPT_UNSET 2
+
+static int opterror(const struct option *opt, const char *reason, int flags)
+{
+       if (flags & OPT_SHORT)
+               return pr_err("switch `%c' %s", opt->short_name, reason);
+       if (flags & OPT_UNSET)
+               return pr_err("option `no-%s' %s", opt->long_name, reason);
+       return pr_err("option `%s' %s", opt->long_name, reason);
+}
+
+static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
+               int flags, const char **arg)
+{
+       if (p->opt) {
+               *arg = p->opt;
+               p->opt = NULL;
+       } else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 ||
+                               **(p->argv + 1) == '-')) {
+               *arg = (const char *)opt->defval;
+       } else if (p->argc > 1) {
+               p->argc--;
+               *arg = *++p->argv;
+       } else
+               return opterror(opt, "requires a value", flags);
+       return 0;
+}
+
+static int readnum(const struct option *opt, int flags,
+                  const char *str, char **end)
+{
+       switch (opt->type) {
+       case OPTION_INTEGER:
+               *(int *)opt->value = strtol(str, end, 0);
+               break;
+       case OPTION_UINTEGER:
+               *(unsigned int *)opt->value = strtol(str, end, 0);
+               break;
+       case OPTION_LONG:
+               *(long *)opt->value = strtol(str, end, 0);
+               break;
+       case OPTION_U64:
+               *(u64 *)opt->value = strtoull(str, end, 0);
+               break;
+       default:
+               return opterror(opt, "invalid numeric conversion", flags);
+       }
+
+       return 0;
+}
+
+static int get_value(struct parse_opt_ctx_t *p,
+               const struct option *opt, int flags)
+{
+       const char *s, *arg = NULL;
+       const int unset = flags & OPT_UNSET;
+
+       if (unset && p->opt)
+               return opterror(opt, "takes no value", flags);
+       if (unset && (opt->flags & PARSE_OPT_NONEG))
+               return opterror(opt, "isn't available", flags);
+
+       if (!(flags & OPT_SHORT) && p->opt) {
+               switch (opt->type) {
+               case OPTION_CALLBACK:
+                       if (!(opt->flags & PARSE_OPT_NOARG))
+                               break;
+               /* FALLTHROUGH */
+               case OPTION_BOOLEAN:
+               case OPTION_INCR:
+               case OPTION_BIT:
+               case OPTION_SET_UINT:
+               case OPTION_SET_PTR:
+                       return opterror(opt, "takes no value", flags);
+               case OPTION_END:
+               case OPTION_ARGUMENT:
+               case OPTION_GROUP:
+               case OPTION_STRING:
+               case OPTION_INTEGER:
+               case OPTION_UINTEGER:
+               case OPTION_LONG:
+               case OPTION_U64:
+               default:
+                       break;
+               }
+       }
+
+       switch (opt->type) {
+       case OPTION_BIT:
+               if (unset)
+                       *(int *)opt->value &= ~opt->defval;
+               else
+                       *(int *)opt->value |= opt->defval;
+               return 0;
+
+       case OPTION_BOOLEAN:
+               *(bool *)opt->value = unset ? false : true;
+               return 0;
+
+       case OPTION_INCR:
+               *(int *)opt->value = unset ? 0 : *(int *)opt->value + 1;
+               return 0;
+
+       case OPTION_SET_UINT:
+               *(unsigned int *)opt->value = unset ? 0 : opt->defval;
+               return 0;
+
+       case OPTION_SET_PTR:
+               *(void **)opt->value = unset ? NULL : (void *)opt->defval;
+               return 0;
+
+       case OPTION_STRING:
+               if (unset)
+                       *(const char **)opt->value = NULL;
+               else if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
+                       *(const char **)opt->value = (const char *)opt->defval;
+               else
+                       return get_arg(p, opt, flags,
+                                       (const char **)opt->value);
+               return 0;
+
+       case OPTION_CALLBACK:
+               if (unset)
+                       return (*opt->callback)(opt, NULL, 1) ? (-1) : 0;
+               if (opt->flags & PARSE_OPT_NOARG)
+                       return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
+               if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
+                       return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
+               if (get_arg(p, opt, flags, &arg))
+                       return -1;
+               return (*opt->callback)(opt, arg, 0) ? (-1) : 0;
+
+       case OPTION_INTEGER:
+               if (unset) {
+                       *(int *)opt->value = 0;
+                       return 0;
+               }
+               if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
+                       *(int *)opt->value = opt->defval;
+                       return 0;
+               }
+               if (get_arg(p, opt, flags, &arg))
+                       return -1;
+               return readnum(opt, flags, arg, (char **)&s);
+
+       case OPTION_UINTEGER:
+               if (unset) {
+                       *(unsigned int *)opt->value = 0;
+                       return 0;
+               }
+               if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
+                       *(unsigned int *)opt->value = opt->defval;
+                       return 0;
+               }
+               if (get_arg(p, opt, flags, &arg))
+                       return -1;
+               return readnum(opt, flags, arg, (char **)&s);
+
+       case OPTION_LONG:
+               if (unset) {
+                       *(long *)opt->value = 0;
+                       return 0;
+               }
+               if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
+                       *(long *)opt->value = opt->defval;
+                       return 0;
+               }
+               if (get_arg(p, opt, flags, &arg))
+                       return -1;
+               return readnum(opt, flags, arg, (char **)&s);
+
+       case OPTION_U64:
+               if (unset) {
+                       *(u64 *)opt->value = 0;
+                       return 0;
+               }
+               if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
+                       *(u64 *)opt->value = opt->defval;
+                       return 0;
+               }
+               if (get_arg(p, opt, flags, &arg))
+                       return -1;
+               return readnum(opt, flags, arg, (char **)&s);
+
+       case OPTION_END:
+       case OPTION_ARGUMENT:
+       case OPTION_GROUP:
+       default:
+               die("should not happen, someone must be hit on the forehead");
+       }
+}
+
+#define USAGE_OPTS_WIDTH 24
+#define USAGE_GAP         2
+
+static int usage_with_options_internal(const char * const *usagestr,
+               const struct option *opts, int full)
+{
+       if (!usagestr)
+               return PARSE_OPT_HELP;
+
+       fprintf(stderr, "\n usage: %s\n", *usagestr++);
+       while (*usagestr && **usagestr)
+               fprintf(stderr, "    or: %s\n", *usagestr++);
+       while (*usagestr) {
+               fprintf(stderr, "%s%s\n",
+                               **usagestr ? "    " : "",
+                               *usagestr);
+               usagestr++;
+       }
+
+       if (opts->type != OPTION_GROUP)
+               fputc('\n', stderr);
+
+       for (; opts->type != OPTION_END; opts++) {
+               size_t pos;
+               int pad;
+
+               if (opts->type == OPTION_GROUP) {
+                       fputc('\n', stderr);
+                       if (*opts->help)
+                               fprintf(stderr, "%s\n", opts->help);
+                       continue;
+               }
+               if (!full && (opts->flags & PARSE_OPT_HIDDEN))
+                       continue;
+
+               pos = fprintf(stderr, "    ");
+               if (opts->short_name)
+                       pos += fprintf(stderr, "-%c", opts->short_name);
+               else
+                       pos += fprintf(stderr, "    ");
+
+               if (opts->long_name && opts->short_name)
+                       pos += fprintf(stderr, ", ");
+               if (opts->long_name)
+                       pos += fprintf(stderr, "--%s", opts->long_name);
+
+               switch (opts->type) {
+               case OPTION_ARGUMENT:
+                       break;
+               case OPTION_LONG:
+               case OPTION_U64:
+               case OPTION_INTEGER:
+               case OPTION_UINTEGER:
+                       if (opts->flags & PARSE_OPT_OPTARG)
+                               if (opts->long_name)
+                                       pos += fprintf(stderr, "[=<n>]");
+                               else
+                                       pos += fprintf(stderr, "[<n>]");
+                       else
+                               pos += fprintf(stderr, " <n>");
+                       break;
+               case OPTION_CALLBACK:
+                       if (opts->flags & PARSE_OPT_NOARG)
+                               break;
+               /* FALLTHROUGH */
+               case OPTION_STRING:
+                       if (opts->argh) {
+                               if (opts->flags & PARSE_OPT_OPTARG)
+                                       if (opts->long_name)
+                                               pos += fprintf(stderr, "[=<%s>]", opts->argh);
+                                       else
+                                               pos += fprintf(stderr, "[<%s>]", opts->argh);
+                               else
+                                       pos += fprintf(stderr, " <%s>", opts->argh);
+                       } else {
+                               if (opts->flags & PARSE_OPT_OPTARG)
+                                       if (opts->long_name)
+                                               pos += fprintf(stderr, "[=...]");
+                                       else
+                                               pos += fprintf(stderr, "[...]");
+                               else
+                                       pos += fprintf(stderr, " ...");
+                       }
+                               break;
+               default: /* OPTION_{BIT,BOOLEAN,SET_UINT,SET_PTR} */
+               case OPTION_END:
+               case OPTION_GROUP:
+               case OPTION_BIT:
+               case OPTION_BOOLEAN:
+               case OPTION_INCR:
+               case OPTION_SET_UINT:
+               case OPTION_SET_PTR:
+                       break;
+               }
+               if (pos <= USAGE_OPTS_WIDTH)
+                       pad = USAGE_OPTS_WIDTH - pos;
+               else {
+                       fputc('\n', stderr);
+                       pad = USAGE_OPTS_WIDTH;
+               }
+               fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
+       }
+       fputc('\n', stderr);
+
+       return PARSE_OPT_HELP;
+}
+
+void usage_with_options(const char * const *usagestr,
+               const struct option *opts)
+{
+       usage_with_options_internal(usagestr, opts, 0);
+       exit(129);
+}
+
+static void check_typos(const char *arg, const struct option *options)
+{
+       if (strlen(arg) < 3)
+               return;
+
+       if (!prefixcmp(arg, "no-")) {
+               pr_err("did you mean `--%s` (with two dashes ?)", arg);
+               exit(129);
+       }
+
+       for (; options->type != OPTION_END; options++) {
+               if (!options->long_name)
+                       continue;
+               if (!prefixcmp(options->long_name, arg)) {
+                       pr_err("did you mean `--%s` (with two dashes ?)", arg);
+                       exit(129);
+               }
+       }
+}
+
+static int parse_options_usage(const char * const *usagestr,
+               const struct option *opts)
+{
+       return usage_with_options_internal(usagestr, opts, 0);
+}
+
+static int parse_short_opt(struct parse_opt_ctx_t *p,
+        const struct option *options)
+{
+       for (; options->type != OPTION_END; options++) {
+               if (options->short_name == *p->opt) {
+                       p->opt = p->opt[1] ? p->opt + 1 : NULL;
+                       return get_value(p, options, OPT_SHORT);
+               }
+       }
+       return -2;
+}
+
+static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
+               const struct option *options)
+{
+       const char *arg_end = strchr(arg, '=');
+       const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
+       int abbrev_flags = 0, ambiguous_flags = 0;
+
+       if (!arg_end)
+               arg_end = arg + strlen(arg);
+
+       for (; options->type != OPTION_END; options++) {
+               const char *rest;
+               int flags = 0;
+
+               if (!options->long_name)
+                       continue;
+
+               rest = skip_prefix(arg, options->long_name);
+               if (options->type == OPTION_ARGUMENT) {
+                       if (!rest)
+                               continue;
+                       if (*rest == '=')
+                               return opterror(options, "takes no value",
+                                               flags);
+                       if (*rest)
+                               continue;
+                       p->out[p->cpidx++] = arg - 2;
+                       return 0;
+               }
+               if (!rest) {
+                       /* abbreviated? */
+                       if (!strncmp(options->long_name, arg, arg_end - arg)) {
+is_abbreviated:
+                               if (abbrev_option) {
+                                       /*
+                                        * If this is abbreviated, it is
+                                        * ambiguous. So when there is no
+                                        * exact match later, we need to
+                                        * error out.
+                                        */
+                                       ambiguous_option = abbrev_option;
+                                       ambiguous_flags = abbrev_flags;
+                               }
+                               if (!(flags & OPT_UNSET) && *arg_end)
+                                       p->opt = arg_end + 1;
+                               abbrev_option = options;
+                               abbrev_flags = flags;
+                               continue;
+                       }
+                       /* negated and abbreviated very much? */
+                       if (!prefixcmp("no-", arg)) {
+                               flags |= OPT_UNSET;
+                               goto is_abbreviated;
+                       }
+                       /* negated? */
+                       if (strncmp(arg, "no-", 3))
+                               continue;
+                       flags |= OPT_UNSET;
+                       rest = skip_prefix(arg + 3, options->long_name);
+                       /* abbreviated and negated? */
+                       if (!rest && !prefixcmp(options->long_name, arg + 3))
+                               goto is_abbreviated;
+                       if (!rest)
+                               continue;
+               }
+               if (*rest) {
+                       if (*rest != '=')
+                               continue;
+                       p->opt = rest + 1;
+               }
+               return get_value(p, options, flags);
+       }
+
+       if (ambiguous_option)
+               return pr_err("Ambiguous option: %s "
+                               "(could be --%s%s or --%s%s)",
+                               arg,
+                               (ambiguous_flags & OPT_UNSET) ?  "no-" : "",
+                               ambiguous_option->long_name,
+                               (abbrev_flags & OPT_UNSET) ?  "no-" : "",
+                               abbrev_option->long_name);
+       if (abbrev_option)
+               return get_value(p, abbrev_option, abbrev_flags);
+       return -2;
+}
+
+
+static void parse_options_start(struct parse_opt_ctx_t *ctx, int argc,
+               const char **argv, int flags)
+{
+       memset(ctx, 0, sizeof(*ctx));
+       ctx->argc = argc;
+       ctx->argv = argv;
+       ctx->out  = argv;
+       ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0);
+       ctx->flags = flags;
+       if ((flags & PARSE_OPT_KEEP_UNKNOWN) &&
+                       (flags & PARSE_OPT_STOP_AT_NON_OPTION))
+               die("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together");
+}
+
+static int parse_options_end(struct parse_opt_ctx_t *ctx)
+{
+       memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out));
+       ctx->out[ctx->cpidx + ctx->argc] = NULL;
+       return ctx->cpidx + ctx->argc;
+}
+
+
+static int parse_options_step(struct parse_opt_ctx_t *ctx,
+               const struct option *options, const char * const usagestr[])
+{
+       int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP);
+
+       /* we must reset ->opt, unknown short option leave it dangling */
+       ctx->opt = NULL;
+
+       for (; ctx->argc; ctx->argc--, ctx->argv++) {
+               const char *arg = ctx->argv[0];
+
+               if (*arg != '-' || !arg[1]) {
+                       if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION)
+                               break;
+                       ctx->out[ctx->cpidx++] = ctx->argv[0];
+                       continue;
+               }
+
+               if (arg[1] != '-') {
+                       ctx->opt = arg + 1;
+                       if (internal_help && *ctx->opt == 'h')
+                               return parse_options_usage(usagestr, options);
+                       switch (parse_short_opt(ctx, options)) {
+                       case -1:
+                               return parse_options_usage(usagestr, options);
+                       case -2:
+                               goto unknown;
+                       default:
+                               break;
+                       }
+                       if (ctx->opt)
+                               check_typos(arg + 1, options);
+                       while (ctx->opt) {
+                               if (internal_help && *ctx->opt == 'h')
+                                       return parse_options_usage(usagestr,
+                                                       options);
+                               switch (parse_short_opt(ctx, options)) {
+                               case -1:
+                                       return parse_options_usage(usagestr,
+                                                       options);
+                               case -2:
+                                       /* fake a short option thing to hide
+                                        * the fact that we may have
+                                        * started to parse aggregated stuff
+                                        *
+                                        * This is leaky, too bad.
+                                        */
+                                       ctx->argv[0] = strdup(ctx->opt - 1);
+                                       *(char *)ctx->argv[0] = '-';
+                                       goto unknown;
+                               default:
+                                       break;
+                               }
+                       }
+                       continue;
+               }
+
+               if (!arg[2]) { /* "--" */
+                       if (!(ctx->flags & PARSE_OPT_KEEP_DASHDASH)) {
+                               ctx->argc--;
+                               ctx->argv++;
+                       }
+                       break;
+               }
+
+               if (internal_help && !strcmp(arg + 2, "help-all"))
+                       return usage_with_options_internal(usagestr, options,
+                                       1);
+               if (internal_help && !strcmp(arg + 2, "help"))
+                       return parse_options_usage(usagestr, options);
+               switch (parse_long_opt(ctx, arg + 2, options)) {
+               case -1:
+                       return parse_options_usage(usagestr, options);
+               case -2:
+                       goto unknown;
+               default:
+                       break;
+               }
+               continue;
+unknown:
+               if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN))
+                       return PARSE_OPT_UNKNOWN;
+               ctx->out[ctx->cpidx++] = ctx->argv[0];
+               ctx->opt = NULL;
+       }
+       return PARSE_OPT_DONE;
+}
+
+int parse_options(int argc, const char **argv, const struct option *options,
+               const char * const usagestr[], int flags)
+{
+       struct parse_opt_ctx_t ctx;
+
+       parse_options_start(&ctx, argc, argv, flags);
+       switch (parse_options_step(&ctx, options, usagestr)) {
+       case PARSE_OPT_HELP:
+               exit(129);
+       case PARSE_OPT_DONE:
+               break;
+       default: /* PARSE_OPT_UNKNOWN */
+               if (ctx.argv[0][1] == '-') {
+                       pr_err("unknown option `%s'", ctx.argv[0] + 2);
+               } else {
+                       pr_err("unknown switch `%c'", *ctx.opt);
+               }
+               usage_with_options(usagestr, options);
+       }
+
+       return parse_options_end(&ctx);
+}
diff --git a/tools/kvm/util/rbtree-interval.c b/tools/kvm/util/rbtree-interval.c
new file mode 100644 (file)
index 0000000..f9bf4b8
--- /dev/null
@@ -0,0 +1,89 @@
+#include <kvm/rbtree-interval.h>
+#include <stddef.h>
+#include <errno.h>
+
+struct rb_int_node *rb_int_search_single(struct rb_root *root, u64 point)
+{
+       struct rb_node *node = root->rb_node;
+       struct rb_node *lowest = NULL;
+
+       while (node) {
+               struct rb_int_node *cur = rb_int(node);
+
+               if (node->rb_left && (rb_int(node->rb_left)->max_high > point)) {
+                       node = node->rb_left;
+               } else if (cur->low <= point && cur->high > point) {
+                       lowest = node;
+                       break;
+               } else if (point > cur->low) {
+                       node = node->rb_right;
+               } else {
+                       break;
+               }
+       }
+
+       if (lowest == NULL)
+               return NULL;
+
+       return rb_int(lowest);
+}
+
+struct rb_int_node *rb_int_search_range(struct rb_root *root, u64 low, u64 high)
+{
+       struct rb_int_node *range;
+
+       range = rb_int_search_single(root, low);
+       if (range == NULL)
+               return NULL;
+
+       /* We simply verify that 'high' is smaller than the end of the range where 'low' is located */
+       if (range->high < high)
+               return NULL;
+
+       return range;
+}
+
+static void update_node_max_high(struct rb_node *node, void *arg)
+{
+       struct rb_int_node *i_node = rb_int(node);
+
+       i_node->max_high = i_node->high;
+
+       if (node->rb_left)
+               i_node->max_high = max(i_node->max_high, rb_int(node->rb_left)->max_high);
+       if (node->rb_right)
+               i_node->max_high = max(i_node->max_high, rb_int(node->rb_right)->max_high);
+}
+
+int rb_int_insert(struct rb_root *root, struct rb_int_node *i_node)
+{
+       struct rb_node **node = &(root->rb_node), *parent = NULL;
+
+       while (*node) {
+               int result = i_node->low - rb_int(*node)->low;
+
+               parent = *node;
+               if (result < 0)
+                       node    = &((*node)->rb_left);
+               else if (result > 0)
+                       node    = &((*node)->rb_right);
+               else
+                       return -EEXIST;
+       }
+
+       rb_link_node(&i_node->node, parent, node);
+       rb_insert_color(&i_node->node, root);
+
+       rb_augment_insert(&i_node->node, update_node_max_high, NULL);
+       return 0;
+}
+
+void rb_int_erase(struct rb_root *root, struct rb_int_node *node)
+{
+       struct rb_node *deepest;
+
+       deepest = rb_augment_erase_begin(&node->node);
+       rb_erase(&node->node, root);
+       rb_augment_erase_end(deepest, update_node_max_high, NULL);
+
+}
diff --git a/tools/kvm/util/read-write.c b/tools/kvm/util/read-write.c
new file mode 100644 (file)
index 0000000..44709df
--- /dev/null
@@ -0,0 +1,354 @@
+#include "kvm/read-write.h"
+
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+/* Same as read(2) except that this function never returns EAGAIN or EINTR. */
+ssize_t xread(int fd, void *buf, size_t count)
+{
+       ssize_t nr;
+
+restart:
+       nr = read(fd, buf, count);
+       if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
+               goto restart;
+
+       return nr;
+}
+
+/* Same as write(2) except that this function never returns EAGAIN or EINTR. */
+ssize_t xwrite(int fd, const void *buf, size_t count)
+{
+       ssize_t nr;
+
+restart:
+       nr = write(fd, buf, count);
+       if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
+               goto restart;
+
+       return nr;
+}
+
+ssize_t read_in_full(int fd, void *buf, size_t count)
+{
+       ssize_t total = 0;
+       char *p = buf;
+
+       while (count > 0) {
+               ssize_t nr;
+
+               nr = xread(fd, p, count);
+               if (nr <= 0) {
+                       if (total > 0)
+                               return total;
+
+                       return -1;
+               }
+
+               count -= nr;
+               total += nr;
+               p += nr;
+       }
+
+       return total;
+}
+
+ssize_t write_in_full(int fd, const void *buf, size_t count)
+{
+       const char *p = buf;
+       ssize_t total = 0;
+
+       while (count > 0) {
+               ssize_t nr;
+
+               nr = xwrite(fd, p, count);
+               if (nr < 0)
+                       return -1;
+               if (nr == 0) {
+                       errno = ENOSPC;
+                       return -1;
+               }
+               count -= nr;
+               total += nr;
+               p += nr;
+       }
+
+       return total;
+}
+
+/* Same as pread(2) except that this function never returns EAGAIN or EINTR. */
+ssize_t xpread(int fd, void *buf, size_t count, off_t offset)
+{
+       ssize_t nr;
+
+restart:
+       nr = pread(fd, buf, count, offset);
+       if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
+               goto restart;
+
+       return nr;
+}
+
+/* Same as pwrite(2) except that this function never returns EAGAIN or EINTR. */
+ssize_t xpwrite(int fd, const void *buf, size_t count, off_t offset)
+{
+       ssize_t nr;
+
+restart:
+       nr = pwrite(fd, buf, count, offset);
+       if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
+               goto restart;
+
+       return nr;
+}
+
+ssize_t pread_in_full(int fd, void *buf, size_t count, off_t offset)
+{
+       ssize_t total = 0;
+       char *p = buf;
+
+       while (count > 0) {
+               ssize_t nr;
+
+               nr = xpread(fd, p, count, offset);
+               if (nr <= 0) {
+                       if (total > 0)
+                               return total;
+
+                       return -1;
+               }
+
+               count -= nr;
+               total += nr;
+               p += nr;
+               offset += nr;
+       }
+
+       return total;
+}
+
+ssize_t pwrite_in_full(int fd, const void *buf, size_t count, off_t offset)
+{
+       const char *p = buf;
+       ssize_t total = 0;
+
+       while (count > 0) {
+               ssize_t nr;
+
+               nr = xpwrite(fd, p, count, offset);
+               if (nr < 0)
+                       return -1;
+               if (nr == 0) {
+                       errno = ENOSPC;
+                       return -1;
+               }
+               count -= nr;
+               total += nr;
+               p += nr;
+               offset += nr;
+       }
+
+       return total;
+}
+
+/* Same as readv(2) except that this function never returns EAGAIN or EINTR. */
+ssize_t xreadv(int fd, const struct iovec *iov, int iovcnt)
+{
+       ssize_t nr;
+
+restart:
+       nr = readv(fd, iov, iovcnt);
+       if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
+               goto restart;
+
+       return nr;
+}
+
+/* Same as writev(2) except that this function never returns EAGAIN or EINTR. */
+ssize_t xwritev(int fd, const struct iovec *iov, int iovcnt)
+{
+       ssize_t nr;
+
+restart:
+       nr = writev(fd, iov, iovcnt);
+       if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
+               goto restart;
+
+       return nr;
+}
+
+static inline ssize_t get_iov_size(const struct iovec *iov, int iovcnt)
+{
+       size_t size = 0;
+       while (iovcnt--)
+               size += (iov++)->iov_len;
+
+       return size;
+}
+
+static inline void shift_iovec(const struct iovec **iov, int *iovcnt,
+                               size_t nr, ssize_t *total, size_t *count, off_t *offset)
+{
+       while (nr >= (*iov)->iov_len) {
+               nr -= (*iov)->iov_len;
+               *total += (*iov)->iov_len;
+               *count -= (*iov)->iov_len;
+               if (offset)
+                       *offset += (*iov)->iov_len;
+               (*iovcnt)--;
+               (*iov)++;
+       }
+}
+
+ssize_t readv_in_full(int fd, const struct iovec *iov, int iovcnt)
+{
+       ssize_t total = 0;
+       size_t count = get_iov_size(iov, iovcnt);
+
+       while (count > 0) {
+               ssize_t nr;
+
+               nr = xreadv(fd, iov, iovcnt);
+               if (nr <= 0) {
+                       if (total > 0)
+                               return total;
+
+                       return -1;
+               }
+
+               shift_iovec(&iov, &iovcnt, nr, &total, &count, NULL);
+       }
+
+       return total;
+}
+
+ssize_t writev_in_full(int fd, const struct iovec *iov, int iovcnt)
+{
+       ssize_t total = 0;
+       size_t count = get_iov_size(iov, iovcnt);
+
+       while (count > 0) {
+               ssize_t nr;
+
+               nr = xwritev(fd, iov, iovcnt);
+               if (nr < 0)
+                       return -1;
+               if (nr == 0) {
+                       errno = ENOSPC;
+                       return -1;
+               }
+
+               shift_iovec(&iov, &iovcnt, nr, &total, &count, NULL);
+       }
+
+       return total;
+}
+
+/* Same as preadv(2) except that this function never returns EAGAIN or EINTR. */
+ssize_t xpreadv(int fd, const struct iovec *iov, int iovcnt, off_t offset)
+{
+       ssize_t nr;
+
+restart:
+       nr = preadv(fd, iov, iovcnt, offset);
+       if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
+               goto restart;
+
+       return nr;
+}
+
+/* Same as pwritev(2) except that this function never returns EAGAIN or EINTR. */
+ssize_t xpwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset)
+{
+       ssize_t nr;
+
+restart:
+       nr = pwritev(fd, iov, iovcnt, offset);
+       if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR)))
+               goto restart;
+
+       return nr;
+}
+
+ssize_t preadv_in_full(int fd, const struct iovec *iov, int iovcnt, off_t offset)
+{
+       ssize_t total = 0;
+       size_t count = get_iov_size(iov, iovcnt);
+
+       while (count > 0) {
+               ssize_t nr;
+
+               nr = xpreadv(fd, iov, iovcnt, offset);
+               if (nr <= 0) {
+                       if (total > 0)
+                               return total;
+
+                       return -1;
+               }
+
+               shift_iovec(&iov, &iovcnt, nr, &total, &count, &offset);
+       }
+
+       return total;
+}
+
+ssize_t pwritev_in_full(int fd, const struct iovec *iov, int iovcnt, off_t offset)
+{
+       ssize_t total = 0;
+       size_t count = get_iov_size(iov, iovcnt);
+
+       while (count > 0) {
+               ssize_t nr;
+
+               nr = xpwritev(fd, iov, iovcnt, offset);
+               if (nr < 0)
+                       return -1;
+               if (nr == 0) {
+                       errno = ENOSPC;
+                       return -1;
+               }
+
+               shift_iovec(&iov, &iovcnt, nr, &total, &count, &offset);
+       }
+
+       return total;
+}
+
+#ifdef CONFIG_HAS_AIO
+int aio_pwritev(io_context_t ctx, struct iocb *iocb, int fd, const struct iovec *iov, int iovcnt,
+               off_t offset, int ev, void *param)
+{
+       struct iocb *ios[1] = { iocb };
+       int ret;
+
+       io_prep_pwritev(iocb, fd, iov, iovcnt, offset);
+       io_set_eventfd(iocb, ev);
+       iocb->data = param;
+
+restart:
+       ret = io_submit(ctx, 1, ios);
+       if (ret == -EAGAIN)
+               goto restart;
+       return ret;
+}
+
+int aio_preadv(io_context_t ctx, struct iocb *iocb, int fd, const struct iovec *iov, int iovcnt,
+               off_t offset, int ev, void *param)
+{
+       struct iocb *ios[1] = { iocb };
+       int ret;
+
+       io_prep_preadv(iocb, fd, iov, iovcnt, offset);
+       io_set_eventfd(iocb, ev);
+       iocb->data = param;
+
+restart:
+       ret = io_submit(ctx, 1, ios);
+       if (ret == -EAGAIN)
+               goto restart;
+       return ret;
+}
+#endif
diff --git a/tools/kvm/util/set_private_br.sh b/tools/kvm/util/set_private_br.sh
new file mode 100755 (executable)
index 0000000..49867dd
--- /dev/null
@@ -0,0 +1,51 @@
+#!/bin/bash
+#
+# Author: Amos Kong <kongjianjun@gmail.com>
+# Date: Apr 14, 2011
+# Description: this script is used to create/delete a private bridge,
+# launch a dhcp server on the bridge by dnsmasq.
+#
+# @ ./set_private_br.sh $bridge_name $subnet_prefix
+# @ ./set_private_br.sh vbr0 192.168.33
+
+brname='vbr0'
+subnet='192.168.33'
+
+add_br()
+{
+    echo "add new private bridge: $brname"
+    /usr/sbin/brctl addbr $brname
+    echo 1 > /proc/sys/net/ipv6/conf/$brname/disable_ipv6
+    echo 1 > /proc/sys/net/ipv4/ip_forward
+    /usr/sbin/brctl stp $brname on
+    /usr/sbin/brctl setfd $brname 0
+    ifconfig $brname $subnet.1
+    ifconfig $brname up
+    # Add forward rule, then guest can access public network
+    iptables -t nat -A POSTROUTING -s $subnet.254/24 ! -d $subnet.254/24 -j MASQUERADE
+    /etc/init.d/dnsmasq stop
+    /etc/init.d/tftpd-hpa stop 2>/dev/null
+    dnsmasq --strict-order --bind-interfaces --listen-address $subnet.1 --dhcp-range $subnet.1,$subnet.254 $tftp_cmd
+}
+
+del_br()
+{
+    echo "cleanup bridge setup"
+    kill -9 `pgrep dnsmasq|tail -1`
+    ifconfig $brname down
+    /usr/sbin/brctl delbr $brname
+    iptables -t nat -D POSTROUTING -s $subnet.254/24 ! -d $subnet.254/24 -j MASQUERADE
+}
+
+
+if [ $# = 0 ]; then
+    del_br 2>/dev/null
+    exit
+fi
+if [ $# > 1 ]; then
+    brname="$1"
+fi
+if [ $# = 2 ]; then
+    subnet="$2"
+fi
+add_br
diff --git a/tools/kvm/util/strbuf.c b/tools/kvm/util/strbuf.c
new file mode 100644 (file)
index 0000000..99d6b0c
--- /dev/null
@@ -0,0 +1,62 @@
+
+/* user defined headers */
+#include <kvm/util.h>
+#include <kvm/strbuf.h>
+
+int prefixcmp(const char *str, const char *prefix)
+{
+       for (; ; str++, prefix++) {
+               if (!*prefix)
+                       return 0;
+               else if (*str != *prefix)
+                       return (unsigned char)*prefix - (unsigned char)*str;
+       }
+}
+
+/**
+ * strlcat - Append a length-limited, %NUL-terminated string to another
+ * @dest: The string to be appended to
+ * @src: The string to append to it
+ * @count: The size of the destination buffer.
+ */
+size_t strlcat(char *dest, const char *src, size_t count)
+{
+       size_t dsize = strlen(dest);
+       size_t len = strlen(src);
+       size_t res = dsize + len;
+
+       DIE_IF(dsize >= count);
+
+       dest += dsize;
+       count -= dsize;
+       if (len >= count)
+               len = count - 1;
+
+       memcpy(dest, src, len);
+       dest[len] = 0;
+
+       return res;
+}
+
+/**
+ * strlcpy - Copy a %NUL terminated string into a sized buffer
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ * @size: size of destination buffer
+ *
+ * Compatible with *BSD: the result is always a valid
+ * NUL-terminated string that fits in the buffer (unless,
+ * of course, the buffer size is zero). It does not pad
+ * out the result like strncpy() does.
+ */
+size_t strlcpy(char *dest, const char *src, size_t size)
+{
+       size_t ret = strlen(src);
+
+       if (size) {
+               size_t len = (ret >= size) ? size - 1 : ret;
+               memcpy(dest, src, len);
+               dest[len] = '\0';
+       }
+       return ret;
+}
diff --git a/tools/kvm/util/threadpool.c b/tools/kvm/util/threadpool.c
new file mode 100644 (file)
index 0000000..bafbcd7
--- /dev/null
@@ -0,0 +1,145 @@
+#include "kvm/threadpool.h"
+#include "kvm/mutex.h"
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <pthread.h>
+#include <stdbool.h>
+
+static pthread_mutex_t job_mutex       = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t thread_mutex    = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t  job_cond        = PTHREAD_COND_INITIALIZER;
+
+static LIST_HEAD(head);
+
+static pthread_t       *threads;
+static long            threadcount;
+
+static struct thread_pool__job *thread_pool__job_pop_locked(void)
+{
+       struct thread_pool__job *job;
+
+       if (list_empty(&head))
+               return NULL;
+
+       job = list_first_entry(&head, struct thread_pool__job, queue);
+       list_del(&job->queue);
+
+       return job;
+}
+
+static void thread_pool__job_push_locked(struct thread_pool__job *job)
+{
+       list_add_tail(&job->queue, &head);
+}
+
+static struct thread_pool__job *thread_pool__job_pop(void)
+{
+       struct thread_pool__job *job;
+
+       mutex_lock(&job_mutex);
+       job = thread_pool__job_pop_locked();
+       mutex_unlock(&job_mutex);
+       return job;
+}
+
+static void thread_pool__job_push(struct thread_pool__job *job)
+{
+       mutex_lock(&job_mutex);
+       thread_pool__job_push_locked(job);
+       mutex_unlock(&job_mutex);
+}
+
+static void thread_pool__handle_job(struct thread_pool__job *job)
+{
+       while (job) {
+               job->callback(job->kvm, job->data);
+
+               mutex_lock(&job->mutex);
+
+               if (--job->signalcount > 0)
+                       /* If the job was signaled again while we were working */
+                       thread_pool__job_push(job);
+
+               mutex_unlock(&job->mutex);
+
+               job = thread_pool__job_pop();
+       }
+}
+
+static void thread_pool__threadfunc_cleanup(void *param)
+{
+       mutex_unlock(&job_mutex);
+}
+
+static void *thread_pool__threadfunc(void *param)
+{
+       pthread_cleanup_push(thread_pool__threadfunc_cleanup, NULL);
+
+       for (;;) {
+               struct thread_pool__job *curjob;
+
+               mutex_lock(&job_mutex);
+               while ((curjob = thread_pool__job_pop_locked()) == NULL)
+                       pthread_cond_wait(&job_cond, &job_mutex);
+               mutex_unlock(&job_mutex);
+
+               thread_pool__handle_job(curjob);
+       }
+
+       pthread_cleanup_pop(0);
+
+       return NULL;
+}
+
+static int thread_pool__addthread(void)
+{
+       int res;
+       void *newthreads;
+
+       mutex_lock(&thread_mutex);
+       newthreads = realloc(threads, (threadcount + 1) * sizeof(pthread_t));
+       if (newthreads == NULL) {
+               mutex_unlock(&thread_mutex);
+               return -1;
+       }
+
+       threads = newthreads;
+
+       res = pthread_create(threads + threadcount, NULL,
+                            thread_pool__threadfunc, NULL);
+
+       if (res == 0)
+               threadcount++;
+       mutex_unlock(&thread_mutex);
+
+       return res;
+}
+
+int thread_pool__init(unsigned long thread_count)
+{
+       unsigned long i;
+
+       for (i = 0; i < thread_count; i++)
+               if (thread_pool__addthread() < 0)
+                       return i;
+
+       return i;
+}
+
+void thread_pool__do_job(struct thread_pool__job *job)
+{
+       struct thread_pool__job *jobinfo = job;
+
+       if (jobinfo == NULL || jobinfo->callback == NULL)
+               return;
+
+       mutex_lock(&jobinfo->mutex);
+       if (jobinfo->signalcount++ == 0)
+               thread_pool__job_push(job);
+       mutex_unlock(&jobinfo->mutex);
+
+       mutex_lock(&job_mutex);
+       pthread_cond_signal(&job_cond);
+       mutex_unlock(&job_mutex);
+}
diff --git a/tools/kvm/util/util.c b/tools/kvm/util/util.c
new file mode 100644 (file)
index 0000000..c11a15a
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Taken from perf which in turn take it from GIT
+ */
+
+#include "kvm/util.h"
+
+#include <kvm/kvm.h>
+#include <linux/magic.h>       /* For HUGETLBFS_MAGIC */
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+
+static void report(const char *prefix, const char *err, va_list params)
+{
+       char msg[1024];
+       vsnprintf(msg, sizeof(msg), err, params);
+       fprintf(stderr, " %s%s\n", prefix, msg);
+}
+
+static NORETURN void die_builtin(const char *err, va_list params)
+{
+       report(" Fatal: ", err, params);
+       exit(128);
+}
+
+static void error_builtin(const char *err, va_list params)
+{
+       report(" Error: ", err, params);
+}
+
+static void warn_builtin(const char *warn, va_list params)
+{
+       report(" Warning: ", warn, params);
+}
+
+static void info_builtin(const char *info, va_list params)
+{
+       report(" Info: ", info, params);
+}
+
+void die(const char *err, ...)
+{
+       va_list params;
+
+       va_start(params, err);
+       die_builtin(err, params);
+       va_end(params);
+}
+
+int pr_err(const char *err, ...)
+{
+       va_list params;
+
+       va_start(params, err);
+       error_builtin(err, params);
+       va_end(params);
+       return -1;
+}
+
+void pr_warning(const char *warn, ...)
+{
+       va_list params;
+
+       va_start(params, warn);
+       warn_builtin(warn, params);
+       va_end(params);
+}
+
+void pr_info(const char *info, ...)
+{
+       va_list params;
+
+       va_start(params, info);
+       info_builtin(info, params);
+       va_end(params);
+}
+
+void die_perror(const char *s)
+{
+       perror(s);
+       exit(1);
+}
+
+void *mmap_hugetlbfs(struct kvm *kvm, const char *htlbfs_path, u64 size)
+{
+       char mpath[PATH_MAX];
+       int fd;
+       struct statfs sfs;
+       void *addr;
+       unsigned long blk_size;
+
+       if (statfs(htlbfs_path, &sfs) < 0)
+               die("Can't stat %s\n", htlbfs_path);
+
+       if ((unsigned int)sfs.f_type != HUGETLBFS_MAGIC)
+               die("%s is not hugetlbfs!\n", htlbfs_path);
+
+       blk_size = (unsigned long)sfs.f_bsize;
+       if (sfs.f_bsize == 0 || blk_size > size) {
+               die("Can't use hugetlbfs pagesize %ld for mem size %lld\n",
+                   blk_size, size);
+       }
+
+       kvm->ram_pagesize = blk_size;
+
+       snprintf(mpath, PATH_MAX, "%s/kvmtoolXXXXXX", htlbfs_path);
+       fd = mkstemp(mpath);
+       if (fd < 0)
+               die("Can't open %s for hugetlbfs map\n", mpath);
+       unlink(mpath);
+       if (ftruncate(fd, size) < 0)
+               die("Can't ftruncate for mem mapping size %lld\n",
+                   size);
+       addr = mmap(NULL, size, PROT_RW, MAP_PRIVATE, fd, 0);
+       close(fd);
+
+       return addr;
+}
+
+/* This function wraps the decision between hugetlbfs map (if requested) or normal mmap */
+void *mmap_anon_or_hugetlbfs(struct kvm *kvm, const char *hugetlbfs_path, u64 size)
+{
+       if (hugetlbfs_path)
+               /*
+                * We don't /need/ to map guest RAM from hugetlbfs, but we do so
+                * if the user specifies a hugetlbfs path.
+                */
+               return mmap_hugetlbfs(kvm, hugetlbfs_path, size);
+       else {
+               kvm->ram_pagesize = getpagesize();
+               return mmap(NULL, size, PROT_RW, MAP_ANON_NORESERVE, -1, 0);
+       }
+}
diff --git a/tools/kvm/virtio/9p-pdu.c b/tools/kvm/virtio/9p-pdu.c
new file mode 100644 (file)
index 0000000..b9ce8ce
--- /dev/null
@@ -0,0 +1,287 @@
+#include "kvm/util.h"
+#include "kvm/virtio-9p.h"
+
+#include <endian.h>
+#include <stdint.h>
+
+#include <linux/compiler.h>
+#include <net/9p/9p.h>
+
+static void virtio_p9_pdu_read(struct p9_pdu *pdu, void *data, size_t size)
+{
+       size_t len;
+       int i, copied = 0;
+       u16 iov_cnt = pdu->out_iov_cnt;
+       size_t offset = pdu->read_offset;
+       struct iovec *iov = pdu->out_iov;
+
+       for (i = 0; i < iov_cnt && size; i++) {
+               if (offset >= iov[i].iov_len) {
+                       offset -= iov[i].iov_len;
+                       continue;
+               } else {
+                       len = MIN(iov[i].iov_len - offset, size);
+                       memcpy(data, iov[i].iov_base + offset, len);
+                       size -= len;
+                       data += len;
+                       offset = 0;
+                       copied += len;
+               }
+       }
+       pdu->read_offset += copied;
+}
+
+static void virtio_p9_pdu_write(struct p9_pdu *pdu,
+                               const void *data, size_t size)
+{
+       size_t len;
+       int i, copied = 0;
+       u16 iov_cnt = pdu->in_iov_cnt;
+       size_t offset = pdu->write_offset;
+       struct iovec *iov = pdu->in_iov;
+
+       for (i = 0; i < iov_cnt && size; i++) {
+               if (offset >= iov[i].iov_len) {
+                       offset -= iov[i].iov_len;
+                       continue;
+               } else {
+                       len = MIN(iov[i].iov_len - offset, size);
+                       memcpy(iov[i].iov_base + offset, data, len);
+                       size -= len;
+                       data += len;
+                       offset = 0;
+                       copied += len;
+               }
+       }
+       pdu->write_offset += copied;
+}
+
+static void virtio_p9_wstat_free(struct p9_wstat *stbuf)
+{
+       free(stbuf->name);
+       free(stbuf->uid);
+       free(stbuf->gid);
+       free(stbuf->muid);
+}
+
+static int virtio_p9_decode(struct p9_pdu *pdu, const char *fmt, va_list ap)
+{
+       int retval = 0;
+       const char *ptr;
+
+       for (ptr = fmt; *ptr; ptr++) {
+               switch (*ptr) {
+               case 'b':
+               {
+                       int8_t *val = va_arg(ap, int8_t *);
+                       virtio_p9_pdu_read(pdu, val, sizeof(*val));
+               }
+               break;
+               case 'w':
+               {
+                       int16_t le_val;
+                       int16_t *val = va_arg(ap, int16_t *);
+                       virtio_p9_pdu_read(pdu, &le_val, sizeof(le_val));
+                       *val = le16toh(le_val);
+               }
+               break;
+               case 'd':
+               {
+                       int32_t le_val;
+                       int32_t *val = va_arg(ap, int32_t *);
+                       virtio_p9_pdu_read(pdu, &le_val, sizeof(le_val));
+                       *val = le32toh(le_val);
+               }
+               break;
+               case 'q':
+               {
+                       int64_t le_val;
+                       int64_t *val = va_arg(ap, int64_t *);
+                       virtio_p9_pdu_read(pdu, &le_val, sizeof(le_val));
+                       *val = le64toh(le_val);
+               }
+               break;
+               case 's':
+               {
+                       int16_t len;
+                       char **str = va_arg(ap, char **);
+
+                       virtio_p9_pdu_readf(pdu, "w", &len);
+                       *str = malloc(len + 1);
+                       if (*str == NULL) {
+                               retval = ENOMEM;
+                               break;
+                       }
+                       virtio_p9_pdu_read(pdu, *str, len);
+                       (*str)[len] = 0;
+               }
+               break;
+               case 'Q':
+               {
+                       struct p9_qid *qid = va_arg(ap, struct p9_qid *);
+                       retval = virtio_p9_pdu_readf(pdu, "bdq",
+                                                    &qid->type, &qid->version,
+                                                    &qid->path);
+               }
+               break;
+               case 'S':
+               {
+                       struct p9_wstat *stbuf = va_arg(ap, struct p9_wstat *);
+                       memset(stbuf, 0, sizeof(struct p9_wstat));
+                       stbuf->n_uid = stbuf->n_gid = stbuf->n_muid = -1;
+                       retval = virtio_p9_pdu_readf(pdu, "wwdQdddqssss",
+                                               &stbuf->size, &stbuf->type,
+                                               &stbuf->dev, &stbuf->qid,
+                                               &stbuf->mode, &stbuf->atime,
+                                               &stbuf->mtime, &stbuf->length,
+                                               &stbuf->name, &stbuf->uid,
+                                               &stbuf->gid, &stbuf->muid);
+                       if (retval)
+                               virtio_p9_wstat_free(stbuf);
+               }
+               break;
+               case 'I':
+               {
+                       struct p9_iattr_dotl *p9attr = va_arg(ap,
+                                                      struct p9_iattr_dotl *);
+
+                       retval = virtio_p9_pdu_readf(pdu, "ddddqqqqq",
+                                                    &p9attr->valid,
+                                                    &p9attr->mode,
+                                                    &p9attr->uid,
+                                                    &p9attr->gid,
+                                                    &p9attr->size,
+                                                    &p9attr->atime_sec,
+                                                    &p9attr->atime_nsec,
+                                                    &p9attr->mtime_sec,
+                                                    &p9attr->mtime_nsec);
+               }
+               break;
+               default:
+                       retval = EINVAL;
+                       break;
+               }
+       }
+       return retval;
+}
+
+static int virtio_p9_pdu_encode(struct p9_pdu *pdu, const char *fmt, va_list ap)
+{
+       int retval = 0;
+       const char *ptr;
+
+       for (ptr = fmt; *ptr; ptr++) {
+               switch (*ptr) {
+               case 'b':
+               {
+                       int8_t val = va_arg(ap, int);
+                       virtio_p9_pdu_write(pdu, &val, sizeof(val));
+               }
+               break;
+               case 'w':
+               {
+                       int16_t val = htole16(va_arg(ap, int));
+                       virtio_p9_pdu_write(pdu, &val, sizeof(val));
+               }
+               break;
+               case 'd':
+               {
+                       int32_t val = htole32(va_arg(ap, int32_t));
+                       virtio_p9_pdu_write(pdu, &val, sizeof(val));
+               }
+               break;
+               case 'q':
+               {
+                       int64_t val = htole64(va_arg(ap, int64_t));
+                       virtio_p9_pdu_write(pdu, &val, sizeof(val));
+               }
+               break;
+               case 's':
+               {
+                       uint16_t len = 0;
+                       const char *s = va_arg(ap, char *);
+                       if (s)
+                               len = MIN(strlen(s), USHRT_MAX);
+                       virtio_p9_pdu_writef(pdu, "w", len);
+                       virtio_p9_pdu_write(pdu, s, len);
+               }
+               break;
+               case 'Q':
+               {
+                       struct p9_qid *qid = va_arg(ap, struct p9_qid *);
+                       retval = virtio_p9_pdu_writef(pdu, "bdq",
+                                                     qid->type, qid->version,
+                                                     qid->path);
+               }
+               break;
+               case 'S':
+               {
+                       struct p9_wstat *stbuf = va_arg(ap, struct p9_wstat *);
+                       retval = virtio_p9_pdu_writef(pdu, "wwdQdddqssss",
+                                               stbuf->size, stbuf->type,
+                                               stbuf->dev, &stbuf->qid,
+                                               stbuf->mode, stbuf->atime,
+                                               stbuf->mtime, stbuf->length,
+                                               stbuf->name, stbuf->uid,
+                                               stbuf->gid, stbuf->muid);
+               }
+               break;
+               case 'A':
+               {
+                       struct p9_stat_dotl *stbuf = va_arg(ap,
+                                                     struct p9_stat_dotl *);
+                       retval  = virtio_p9_pdu_writef(pdu,
+                                                      "qQdddqqqqqqqqqqqqqqq",
+                                                      stbuf->st_result_mask,
+                                                      &stbuf->qid,
+                                                      stbuf->st_mode,
+                                                      stbuf->st_uid,
+                                                      stbuf->st_gid,
+                                                      stbuf->st_nlink,
+                                                      stbuf->st_rdev,
+                                                      stbuf->st_size,
+                                                      stbuf->st_blksize,
+                                                      stbuf->st_blocks,
+                                                      stbuf->st_atime_sec,
+                                                      stbuf->st_atime_nsec,
+                                                      stbuf->st_mtime_sec,
+                                                      stbuf->st_mtime_nsec,
+                                                      stbuf->st_ctime_sec,
+                                                      stbuf->st_ctime_nsec,
+                                                      stbuf->st_btime_sec,
+                                                      stbuf->st_btime_nsec,
+                                                      stbuf->st_gen,
+                                                      stbuf->st_data_version);
+               }
+               break;
+               default:
+                       retval = EINVAL;
+                       break;
+               }
+       }
+       return retval;
+}
+
+int virtio_p9_pdu_readf(struct p9_pdu *pdu, const char *fmt, ...)
+{
+       int ret;
+       va_list ap;
+
+       va_start(ap, fmt);
+       ret = virtio_p9_decode(pdu, fmt, ap);
+       va_end(ap);
+
+       return ret;
+}
+
+int virtio_p9_pdu_writef(struct p9_pdu *pdu, const char *fmt, ...)
+{
+       int ret;
+       va_list ap;
+
+       va_start(ap, fmt);
+       ret = virtio_p9_pdu_encode(pdu, fmt, ap);
+       va_end(ap);
+
+       return ret;
+}
diff --git a/tools/kvm/virtio/9p.c b/tools/kvm/virtio/9p.c
new file mode 100644 (file)
index 0000000..27ef57b
--- /dev/null
@@ -0,0 +1,1409 @@
+#include "kvm/virtio-pci-dev.h"
+#include "kvm/ioport.h"
+#include "kvm/util.h"
+#include "kvm/threadpool.h"
+#include "kvm/irq.h"
+#include "kvm/virtio-9p.h"
+#include "kvm/guest_compat.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/vfs.h>
+
+#include <linux/virtio_ring.h>
+#include <linux/virtio_9p.h>
+#include <net/9p/9p.h>
+
+static LIST_HEAD(devs);
+static int compat_id = -1;
+
+static int insert_new_fid(struct p9_dev *dev, struct p9_fid *fid);
+static struct p9_fid *find_or_create_fid(struct p9_dev *dev, u32 fid)
+{
+       struct rb_node *node = dev->fids.rb_node;
+       struct p9_fid *pfid = NULL;
+
+       while (node) {
+               struct p9_fid *cur = rb_entry(node, struct p9_fid, node);
+
+               if (fid < cur->fid) {
+                       node = node->rb_left;
+               } else if (fid > cur->fid) {
+                       node = node->rb_right;
+               } else {
+                       return cur;
+               }
+       }
+
+       pfid = calloc(sizeof(*pfid), 1);
+       if (!pfid)
+               return NULL;
+
+       pfid->fid = fid;
+       strcpy(pfid->abs_path, dev->root_dir);
+       pfid->path = pfid->abs_path + strlen(dev->root_dir);
+
+       insert_new_fid(dev, pfid);
+
+       return pfid;
+}
+
+static int insert_new_fid(struct p9_dev *dev, struct p9_fid *fid)
+{
+       struct rb_node **node = &(dev->fids.rb_node), *parent = NULL;
+
+       while (*node) {
+               int result = fid->fid - rb_entry(*node, struct p9_fid, node)->fid;
+
+               parent = *node;
+               if (result < 0)
+                       node    = &((*node)->rb_left);
+               else if (result > 0)
+                       node    = &((*node)->rb_right);
+               else
+                       return -EEXIST;
+       }
+
+       rb_link_node(&fid->node, parent, node);
+       rb_insert_color(&fid->node, &dev->fids);
+       return 0;
+}
+
+static struct p9_fid *get_fid(struct p9_dev *p9dev, int fid)
+{
+       struct p9_fid *new;
+
+       new = find_or_create_fid(p9dev, fid);
+
+       return new;
+}
+
+/* Warning: Immediately use value returned from this function */
+static const char *rel_to_abs(struct p9_dev *p9dev,
+                             const char *path, char *abs_path)
+{
+       sprintf(abs_path, "%s/%s", p9dev->root_dir, path);
+
+       return abs_path;
+}
+
+static void stat2qid(struct stat *st, struct p9_qid *qid)
+{
+       *qid = (struct p9_qid) {
+               .path           = st->st_ino,
+               .version        = st->st_mtime,
+       };
+
+       if (S_ISDIR(st->st_mode))
+               qid->type       |= P9_QTDIR;
+}
+
+static void close_fid(struct p9_dev *p9dev, u32 fid)
+{
+       struct p9_fid *pfid = get_fid(p9dev, fid);
+
+       if (pfid->fd > 0)
+               close(pfid->fd);
+
+       if (pfid->dir)
+               closedir(pfid->dir);
+
+       rb_erase(&pfid->node, &p9dev->fids);
+       free(pfid);
+}
+
+static void clear_all_fids(struct p9_dev *p9dev)
+{
+       struct rb_node *node = rb_first(&p9dev->fids);
+
+       while (node) {
+               struct p9_fid *fid = rb_entry(node, struct p9_fid, node);
+
+               if (fid->fd > 0)
+                       close(fid->fd);
+
+               if (fid->dir)
+                       closedir(fid->dir);
+
+               rb_erase(&fid->node, &p9dev->fids);
+               free(fid);
+
+               node = rb_first(&p9dev->fids);
+       }
+}
+
+static void virtio_p9_set_reply_header(struct p9_pdu *pdu, u32 size)
+{
+       u8 cmd;
+       u16 tag;
+
+       pdu->read_offset = sizeof(u32);
+       virtio_p9_pdu_readf(pdu, "bw", &cmd, &tag);
+       pdu->write_offset = 0;
+       /* cmd + 1 is the reply message */
+       virtio_p9_pdu_writef(pdu, "dbw", size, cmd + 1, tag);
+}
+
+static u16 virtio_p9_update_iov_cnt(struct iovec iov[], u32 count, int iov_cnt)
+{
+       int i;
+       u32 total = 0;
+       for (i = 0; (i < iov_cnt) && (total < count); i++) {
+               if (total + iov[i].iov_len > count) {
+                       /* we don't need this iov fully */
+                       iov[i].iov_len -= ((total + iov[i].iov_len) - count);
+                       i++;
+                       break;
+               }
+               total += iov[i].iov_len;
+       }
+       return i;
+}
+
+static void virtio_p9_error_reply(struct p9_dev *p9dev,
+                                 struct p9_pdu *pdu, int err, u32 *outlen)
+{
+       u16 tag;
+
+       pdu->write_offset = VIRTIO_9P_HDR_LEN;
+       virtio_p9_pdu_writef(pdu, "d", err);
+       *outlen = pdu->write_offset;
+
+       /* read the tag from input */
+       pdu->read_offset = sizeof(u32) + sizeof(u8);
+       virtio_p9_pdu_readf(pdu, "w", &tag);
+
+       /* Update the header */
+       pdu->write_offset = 0;
+       virtio_p9_pdu_writef(pdu, "dbw", *outlen, P9_RLERROR, tag);
+}
+
+static void virtio_p9_version(struct p9_dev *p9dev,
+                             struct p9_pdu *pdu, u32 *outlen)
+{
+       u32 msize;
+       char *version;
+       virtio_p9_pdu_readf(pdu, "ds", &msize, &version);
+       /*
+        * reply with the same msize the client sent us
+        * Error out if the request is not for 9P2000.L
+        */
+       if (!strcmp(version, VIRTIO_9P_VERSION_DOTL))
+               virtio_p9_pdu_writef(pdu, "ds", msize, version);
+       else
+               virtio_p9_pdu_writef(pdu, "ds", msize, "unknown");
+
+       *outlen = pdu->write_offset;
+       virtio_p9_set_reply_header(pdu, *outlen);
+       free(version);
+       return;
+}
+
+static void virtio_p9_clunk(struct p9_dev *p9dev,
+                           struct p9_pdu *pdu, u32 *outlen)
+{
+       u32 fid;
+
+       virtio_p9_pdu_readf(pdu, "d", &fid);
+       close_fid(p9dev, fid);
+
+       *outlen = pdu->write_offset;
+       virtio_p9_set_reply_header(pdu, *outlen);
+       return;
+}
+
+/*
+ * FIXME!! Need to map to protocol independent value. Upstream
+ * 9p also have the same BUG
+ */
+static int virtio_p9_openflags(int flags)
+{
+       flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT | O_DIRECT);
+       flags |= O_NOFOLLOW;
+       return flags;
+}
+
+static bool is_dir(struct p9_fid *fid)
+{
+       struct stat st;
+
+       stat(fid->abs_path, &st);
+
+       return S_ISDIR(st.st_mode);
+}
+
+static void virtio_p9_open(struct p9_dev *p9dev,
+                          struct p9_pdu *pdu, u32 *outlen)
+{
+       u32 fid, flags;
+       struct stat st;
+       struct p9_qid qid;
+       struct p9_fid *new_fid;
+
+
+       virtio_p9_pdu_readf(pdu, "dd", &fid, &flags);
+       new_fid = get_fid(p9dev, fid);
+
+       if (lstat(new_fid->abs_path, &st) < 0)
+               goto err_out;
+
+       stat2qid(&st, &qid);
+
+       if (is_dir(new_fid)) {
+               new_fid->dir = opendir(new_fid->abs_path);
+               if (!new_fid->dir)
+                       goto err_out;
+       } else {
+               new_fid->fd  = open(new_fid->abs_path,
+                                   virtio_p9_openflags(flags));
+               if (new_fid->fd < 0)
+                       goto err_out;
+       }
+       /* FIXME!! need ot send proper iounit  */
+       virtio_p9_pdu_writef(pdu, "Qd", &qid, 0);
+
+       *outlen = pdu->write_offset;
+       virtio_p9_set_reply_header(pdu, *outlen);
+       return;
+err_out:
+       virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+       return;
+}
+
+static void virtio_p9_create(struct p9_dev *p9dev,
+                            struct p9_pdu *pdu, u32 *outlen)
+{
+       int fd, ret;
+       char *name;
+       struct stat st;
+       struct p9_qid qid;
+       struct p9_fid *dfid;
+       char full_path[PATH_MAX];
+       u32 dfid_val, flags, mode, gid;
+
+       virtio_p9_pdu_readf(pdu, "dsddd", &dfid_val,
+                           &name, &flags, &mode, &gid);
+       dfid = get_fid(p9dev, dfid_val);
+
+       flags = virtio_p9_openflags(flags);
+
+       sprintf(full_path, "%s/%s", dfid->abs_path, name);
+       fd = open(full_path, flags | O_CREAT, mode);
+       if (fd < 0)
+               goto err_out;
+       dfid->fd = fd;
+
+       if (lstat(full_path, &st) < 0)
+               goto err_out;
+
+       ret = chmod(full_path, mode & 0777);
+       if (ret < 0)
+               goto err_out;
+
+       ret = lchown(full_path, dfid->uid, gid);
+       if (ret < 0)
+               goto err_out;
+
+       sprintf(dfid->path, "%s/%s", dfid->path, name);
+       stat2qid(&st, &qid);
+       virtio_p9_pdu_writef(pdu, "Qd", &qid, 0);
+       *outlen = pdu->write_offset;
+       virtio_p9_set_reply_header(pdu, *outlen);
+       free(name);
+       return;
+err_out:
+       free(name);
+       virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+       return;
+}
+
+static void virtio_p9_mkdir(struct p9_dev *p9dev,
+                           struct p9_pdu *pdu, u32 *outlen)
+{
+       int ret;
+       char *name;
+       struct stat st;
+       struct p9_qid qid;
+       struct p9_fid *dfid;
+       char full_path[PATH_MAX];
+       u32 dfid_val, mode, gid;
+
+       virtio_p9_pdu_readf(pdu, "dsdd", &dfid_val,
+                           &name, &mode, &gid);
+       dfid = get_fid(p9dev, dfid_val);
+
+       sprintf(full_path, "%s/%s", dfid->abs_path, name);
+       ret = mkdir(full_path, mode);
+       if (ret < 0)
+               goto err_out;
+
+       if (lstat(full_path, &st) < 0)
+               goto err_out;
+
+       ret = chmod(full_path, mode & 0777);
+       if (ret < 0)
+               goto err_out;
+
+       ret = lchown(full_path, dfid->uid, gid);
+       if (ret < 0)
+               goto err_out;
+
+       stat2qid(&st, &qid);
+       virtio_p9_pdu_writef(pdu, "Qd", &qid, 0);
+       *outlen = pdu->write_offset;
+       virtio_p9_set_reply_header(pdu, *outlen);
+       free(name);
+       return;
+err_out:
+       free(name);
+       virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+       return;
+}
+
+static void virtio_p9_walk(struct p9_dev *p9dev,
+                          struct p9_pdu *pdu, u32 *outlen)
+{
+       u8 i;
+       u16 nwqid;
+       u16 nwname;
+       struct p9_qid wqid;
+       struct p9_fid *new_fid, *old_fid;
+       u32 fid_val, newfid_val;
+
+
+       virtio_p9_pdu_readf(pdu, "ddw", &fid_val, &newfid_val, &nwname);
+       new_fid = get_fid(p9dev, newfid_val);
+
+       nwqid = 0;
+       if (nwname) {
+               struct p9_fid *fid = get_fid(p9dev, fid_val);
+
+               strcpy(new_fid->path, fid->path);
+               /* skip the space for count */
+               pdu->write_offset += sizeof(u16);
+               for (i = 0; i < nwname; i++) {
+                       struct stat st;
+                       char tmp[PATH_MAX] = {0};
+                       char full_path[PATH_MAX];
+                       char *str;
+
+                       virtio_p9_pdu_readf(pdu, "s", &str);
+
+                       /* Format the new path we're 'walk'ing into */
+                       sprintf(tmp, "%s/%s", new_fid->path, str);
+
+                       free(str);
+
+                       if (lstat(rel_to_abs(p9dev, tmp, full_path), &st) < 0)
+                               goto err_out;
+
+                       stat2qid(&st, &wqid);
+                       strcpy(new_fid->path, tmp);
+                       new_fid->uid = fid->uid;
+                       nwqid++;
+                       virtio_p9_pdu_writef(pdu, "Q", &wqid);
+               }
+       } else {
+               /*
+                * update write_offset so our outlen get correct value
+                */
+               pdu->write_offset += sizeof(u16);
+               old_fid = get_fid(p9dev, fid_val);
+               strcpy(new_fid->path, old_fid->path);
+               new_fid->uid    = old_fid->uid;
+       }
+       *outlen = pdu->write_offset;
+       pdu->write_offset = VIRTIO_9P_HDR_LEN;
+       virtio_p9_pdu_writef(pdu, "d", nwqid);
+       virtio_p9_set_reply_header(pdu, *outlen);
+       return;
+err_out:
+       virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+       return;
+}
+
+static void virtio_p9_attach(struct p9_dev *p9dev,
+                            struct p9_pdu *pdu, u32 *outlen)
+{
+       char *uname;
+       char *aname;
+       struct stat st;
+       struct p9_qid qid;
+       struct p9_fid *fid;
+       u32 fid_val, afid, uid;
+
+       virtio_p9_pdu_readf(pdu, "ddssd", &fid_val, &afid,
+                           &uname, &aname, &uid);
+
+       free(uname);
+       free(aname);
+
+       clear_all_fids(p9dev);
+
+       if (lstat(p9dev->root_dir, &st) < 0)
+               goto err_out;
+
+       stat2qid(&st, &qid);
+
+       fid = get_fid(p9dev, fid_val);
+       fid->uid = uid;
+       strcpy(fid->path, "/");
+
+       virtio_p9_pdu_writef(pdu, "Q", &qid);
+       *outlen = pdu->write_offset;
+       virtio_p9_set_reply_header(pdu, *outlen);
+       return;
+err_out:
+       virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+       return;
+}
+
+static void virtio_p9_fill_stat(struct p9_dev *p9dev,
+                               struct stat *st, struct p9_stat_dotl *statl)
+{
+       memset(statl, 0, sizeof(*statl));
+       statl->st_mode          = st->st_mode;
+       statl->st_nlink         = st->st_nlink;
+       statl->st_uid           = st->st_uid;
+       statl->st_gid           = st->st_gid;
+       statl->st_rdev          = st->st_rdev;
+       statl->st_size          = st->st_size;
+       statl->st_blksize       = st->st_blksize;
+       statl->st_blocks        = st->st_blocks;
+       statl->st_atime_sec     = st->st_atime;
+       statl->st_atime_nsec    = st->st_atim.tv_nsec;
+       statl->st_mtime_sec     = st->st_mtime;
+       statl->st_mtime_nsec    = st->st_mtim.tv_nsec;
+       statl->st_ctime_sec     = st->st_ctime;
+       statl->st_ctime_nsec    = st->st_ctim.tv_nsec;
+       /* Currently we only support BASIC fields in stat */
+       statl->st_result_mask   = P9_STATS_BASIC;
+       stat2qid(st, &statl->qid);
+}
+
+static void virtio_p9_read(struct p9_dev *p9dev,
+                          struct p9_pdu *pdu, u32 *outlen)
+{
+       u64 offset;
+       u32 fid_val;
+       u16 iov_cnt;
+       void *iov_base;
+       size_t iov_len;
+       u32 count, rcount;
+       struct p9_fid *fid;
+
+
+       rcount = 0;
+       virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count);
+       fid = get_fid(p9dev, fid_val);
+
+       iov_base = pdu->in_iov[0].iov_base;
+       iov_len  = pdu->in_iov[0].iov_len;
+       iov_cnt  = pdu->in_iov_cnt;
+       pdu->in_iov[0].iov_base += VIRTIO_9P_HDR_LEN + sizeof(u32);
+       pdu->in_iov[0].iov_len -= VIRTIO_9P_HDR_LEN + sizeof(u32);
+       pdu->in_iov_cnt = virtio_p9_update_iov_cnt(pdu->in_iov,
+                                                  count,
+                                                  pdu->in_iov_cnt);
+       rcount = preadv(fid->fd, pdu->in_iov,
+                       pdu->in_iov_cnt, offset);
+       if (rcount > count)
+               rcount = count;
+       /*
+        * Update the iov_base back, so that rest of
+        * pdu_writef works correctly.
+        */
+       pdu->in_iov[0].iov_base = iov_base;
+       pdu->in_iov[0].iov_len  = iov_len;
+       pdu->in_iov_cnt         = iov_cnt;
+
+       pdu->write_offset = VIRTIO_9P_HDR_LEN;
+       virtio_p9_pdu_writef(pdu, "d", rcount);
+       *outlen = pdu->write_offset + rcount;
+       virtio_p9_set_reply_header(pdu, *outlen);
+       return;
+}
+
+static int virtio_p9_dentry_size(struct dirent *dent)
+{
+       /*
+        * Size of each dirent:
+        * qid(13) + offset(8) + type(1) + name_len(2) + name
+        */
+       return 24 + strlen(dent->d_name);
+}
+
+static void virtio_p9_readdir(struct p9_dev *p9dev,
+                             struct p9_pdu *pdu, u32 *outlen)
+{
+       u32 fid_val;
+       u32 count, rcount;
+       struct stat st;
+       struct p9_fid *fid;
+       struct dirent *dent;
+       char full_path[PATH_MAX];
+       u64 offset, old_offset;
+
+       rcount = 0;
+       virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count);
+       fid = get_fid(p9dev, fid_val);
+
+       if (!is_dir(fid)) {
+               errno = EINVAL;
+               goto err_out;
+       }
+
+       /* Move the offset specified */
+       seekdir(fid->dir, offset);
+
+       old_offset = offset;
+       /* If reading a dir, fill the buffer with p9_stat entries */
+       dent = readdir(fid->dir);
+
+       /* Skip the space for writing count */
+       pdu->write_offset += sizeof(u32);
+       while (dent) {
+               u32 read;
+               struct p9_qid qid;
+
+               if ((rcount + virtio_p9_dentry_size(dent)) > count) {
+                       /* seek to the previous offset and return */
+                       seekdir(fid->dir, old_offset);
+                       break;
+               }
+               old_offset = dent->d_off;
+               lstat(rel_to_abs(p9dev, dent->d_name, full_path), &st);
+               stat2qid(&st, &qid);
+               read = pdu->write_offset;
+               virtio_p9_pdu_writef(pdu, "Qqbs", &qid, dent->d_off,
+                                    dent->d_type, dent->d_name);
+               rcount += pdu->write_offset - read;
+               dent = readdir(fid->dir);
+       }
+
+       pdu->write_offset = VIRTIO_9P_HDR_LEN;
+       virtio_p9_pdu_writef(pdu, "d", rcount);
+       *outlen = pdu->write_offset + rcount;
+       virtio_p9_set_reply_header(pdu, *outlen);
+       return;
+err_out:
+       virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+       return;
+}
+
+
+static void virtio_p9_getattr(struct p9_dev *p9dev,
+                             struct p9_pdu *pdu, u32 *outlen)
+{
+       u32 fid_val;
+       struct stat st;
+       u64 request_mask;
+       struct p9_fid *fid;
+       struct p9_stat_dotl statl;
+
+       virtio_p9_pdu_readf(pdu, "dq", &fid_val, &request_mask);
+       fid = get_fid(p9dev, fid_val);
+       if (lstat(fid->abs_path, &st) < 0)
+               goto err_out;
+
+       virtio_p9_fill_stat(p9dev, &st, &statl);
+       virtio_p9_pdu_writef(pdu, "A", &statl);
+       *outlen = pdu->write_offset;
+       virtio_p9_set_reply_header(pdu, *outlen);
+       return;
+err_out:
+       virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+       return;
+}
+
+/* FIXME!! from linux/fs.h */
+/*
+ * Attribute flags.  These should be or-ed together to figure out what
+ * has been changed!
+ */
+#define ATTR_MODE      (1 << 0)
+#define ATTR_UID       (1 << 1)
+#define ATTR_GID       (1 << 2)
+#define ATTR_SIZE      (1 << 3)
+#define ATTR_ATIME     (1 << 4)
+#define ATTR_MTIME     (1 << 5)
+#define ATTR_CTIME     (1 << 6)
+#define ATTR_ATIME_SET (1 << 7)
+#define ATTR_MTIME_SET (1 << 8)
+#define ATTR_FORCE     (1 << 9) /* Not a change, but a change it */
+#define ATTR_ATTR_FLAG (1 << 10)
+#define ATTR_KILL_SUID (1 << 11)
+#define ATTR_KILL_SGID (1 << 12)
+#define ATTR_FILE      (1 << 13)
+#define ATTR_KILL_PRIV (1 << 14)
+#define ATTR_OPEN      (1 << 15) /* Truncating from open(O_TRUNC) */
+#define ATTR_TIMES_SET (1 << 16)
+
+#define ATTR_MASK    127
+
+static void virtio_p9_setattr(struct p9_dev *p9dev,
+                             struct p9_pdu *pdu, u32 *outlen)
+{
+       int ret = 0;
+       u32 fid_val;
+       struct p9_fid *fid;
+       struct p9_iattr_dotl p9attr;
+
+       virtio_p9_pdu_readf(pdu, "dI", &fid_val, &p9attr);
+       fid = get_fid(p9dev, fid_val);
+
+       if (p9attr.valid & ATTR_MODE) {
+               ret = chmod(fid->abs_path, p9attr.mode);
+               if (ret < 0)
+                       goto err_out;
+       }
+       if (p9attr.valid & (ATTR_ATIME | ATTR_MTIME)) {
+               struct timespec times[2];
+               if (p9attr.valid & ATTR_ATIME) {
+                       if (p9attr.valid & ATTR_ATIME_SET) {
+                               times[0].tv_sec = p9attr.atime_sec;
+                               times[0].tv_nsec = p9attr.atime_nsec;
+                       } else {
+                               times[0].tv_nsec = UTIME_NOW;
+                       }
+               } else {
+                       times[0].tv_nsec = UTIME_OMIT;
+               }
+               if (p9attr.valid & ATTR_MTIME) {
+                       if (p9attr.valid & ATTR_MTIME_SET) {
+                               times[1].tv_sec = p9attr.mtime_sec;
+                               times[1].tv_nsec = p9attr.mtime_nsec;
+                       } else {
+                               times[1].tv_nsec = UTIME_NOW;
+                       }
+               } else
+                       times[1].tv_nsec = UTIME_OMIT;
+
+               ret = utimensat(-1, fid->abs_path, times, AT_SYMLINK_NOFOLLOW);
+               if (ret < 0)
+                       goto err_out;
+       }
+       /*
+        * If the only valid entry in iattr is ctime we can call
+        * chown(-1,-1) to update the ctime of the file
+        */
+       if ((p9attr.valid & (ATTR_UID | ATTR_GID)) ||
+           ((p9attr.valid & ATTR_CTIME)
+            && !((p9attr.valid & ATTR_MASK) & ~ATTR_CTIME))) {
+               if (!(p9attr.valid & ATTR_UID))
+                       p9attr.uid = -1;
+
+               if (!(p9attr.valid & ATTR_GID))
+                       p9attr.gid = -1;
+
+               ret = lchown(fid->abs_path, p9attr.uid, p9attr.gid);
+               if (ret < 0)
+                       goto err_out;
+       }
+       if (p9attr.valid & (ATTR_SIZE)) {
+               ret = truncate(fid->abs_path, p9attr.size);
+               if (ret < 0)
+                       goto err_out;
+       }
+       *outlen = VIRTIO_9P_HDR_LEN;
+       virtio_p9_set_reply_header(pdu, *outlen);
+       return;
+err_out:
+       virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+       return;
+}
+
+static void virtio_p9_write(struct p9_dev *p9dev,
+                           struct p9_pdu *pdu, u32 *outlen)
+{
+
+       u64 offset;
+       u32 fid_val;
+       u32 count;
+       ssize_t res;
+       u16 iov_cnt;
+       void *iov_base;
+       size_t iov_len;
+       struct p9_fid *fid;
+       /* u32 fid + u64 offset + u32 count */
+       int twrite_size = sizeof(u32) + sizeof(u64) + sizeof(u32);
+
+       virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count);
+       fid = get_fid(p9dev, fid_val);
+
+       iov_base = pdu->out_iov[0].iov_base;
+       iov_len  = pdu->out_iov[0].iov_len;
+       iov_cnt  = pdu->out_iov_cnt;
+
+       /* Adjust the iovec to skip the header and meta data */
+       pdu->out_iov[0].iov_base += (sizeof(struct p9_msg) + twrite_size);
+       pdu->out_iov[0].iov_len -=  (sizeof(struct p9_msg) + twrite_size);
+       pdu->out_iov_cnt = virtio_p9_update_iov_cnt(pdu->out_iov, count,
+                                                   pdu->out_iov_cnt);
+       res = pwritev(fid->fd, pdu->out_iov, pdu->out_iov_cnt, offset);
+       /*
+        * Update the iov_base back, so that rest of
+        * pdu_readf works correctly.
+        */
+       pdu->out_iov[0].iov_base = iov_base;
+       pdu->out_iov[0].iov_len  = iov_len;
+       pdu->out_iov_cnt         = iov_cnt;
+
+       if (res < 0)
+               goto err_out;
+       virtio_p9_pdu_writef(pdu, "d", res);
+       *outlen = pdu->write_offset;
+       virtio_p9_set_reply_header(pdu, *outlen);
+       return;
+err_out:
+       virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+       return;
+}
+
+static void virtio_p9_remove(struct p9_dev *p9dev,
+                            struct p9_pdu *pdu, u32 *outlen)
+{
+       int ret;
+       u32 fid_val;
+       struct p9_fid *fid;
+
+       virtio_p9_pdu_readf(pdu, "d", &fid_val);
+       fid = get_fid(p9dev, fid_val);
+
+       ret = remove(fid->abs_path);
+       if (ret < 0)
+               goto err_out;
+       *outlen = pdu->write_offset;
+       virtio_p9_set_reply_header(pdu, *outlen);
+       return;
+
+err_out:
+       virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+       return;
+}
+
+static void virtio_p9_rename(struct p9_dev *p9dev,
+                            struct p9_pdu *pdu, u32 *outlen)
+{
+       int ret;
+       u32 fid_val, new_fid_val;
+       struct p9_fid *fid, *new_fid;
+       char full_path[PATH_MAX], *new_name;
+
+       virtio_p9_pdu_readf(pdu, "dds", &fid_val, &new_fid_val, &new_name);
+       fid = get_fid(p9dev, fid_val);
+       new_fid = get_fid(p9dev, new_fid_val);
+
+       sprintf(full_path, "%s/%s", new_fid->abs_path, new_name);
+       ret = rename(fid->abs_path, full_path);
+       if (ret < 0)
+               goto err_out;
+       *outlen = pdu->write_offset;
+       virtio_p9_set_reply_header(pdu, *outlen);
+       return;
+
+err_out:
+       virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+       return;
+}
+
+static void virtio_p9_readlink(struct p9_dev *p9dev,
+                              struct p9_pdu *pdu, u32 *outlen)
+{
+       int ret;
+       u32 fid_val;
+       struct p9_fid *fid;
+       char target_path[PATH_MAX];
+
+       virtio_p9_pdu_readf(pdu, "d", &fid_val);
+       fid = get_fid(p9dev, fid_val);
+
+       memset(target_path, 0, PATH_MAX);
+       ret = readlink(fid->abs_path, target_path, PATH_MAX - 1);
+       if (ret < 0)
+               goto err_out;
+
+       virtio_p9_pdu_writef(pdu, "s", target_path);
+       *outlen = pdu->write_offset;
+       virtio_p9_set_reply_header(pdu, *outlen);
+       return;
+err_out:
+       virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+       return;
+}
+
+static void virtio_p9_statfs(struct p9_dev *p9dev,
+                            struct p9_pdu *pdu, u32 *outlen)
+{
+       int ret;
+       u64 fsid;
+       u32 fid_val;
+       struct p9_fid *fid;
+       struct statfs stat_buf;
+
+       virtio_p9_pdu_readf(pdu, "d", &fid_val);
+       fid = get_fid(p9dev, fid_val);
+
+       ret = statfs(fid->abs_path, &stat_buf);
+       if (ret < 0)
+               goto err_out;
+       /* FIXME!! f_blocks needs update based on client msize */
+       fsid = (unsigned int) stat_buf.f_fsid.__val[0] |
+               (unsigned long long)stat_buf.f_fsid.__val[1] << 32;
+       virtio_p9_pdu_writef(pdu, "ddqqqqqqd", stat_buf.f_type,
+                            stat_buf.f_bsize, stat_buf.f_blocks,
+                            stat_buf.f_bfree, stat_buf.f_bavail,
+                            stat_buf.f_files, stat_buf.f_ffree,
+                            fsid, stat_buf.f_namelen);
+       *outlen = pdu->write_offset;
+       virtio_p9_set_reply_header(pdu, *outlen);
+       return;
+err_out:
+       virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+       return;
+}
+
+static void virtio_p9_mknod(struct p9_dev *p9dev,
+                           struct p9_pdu *pdu, u32 *outlen)
+{
+       int ret;
+       char *name;
+       struct stat st;
+       struct p9_fid *dfid;
+       struct p9_qid qid;
+       char full_path[PATH_MAX];
+       u32 fid_val, mode, major, minor, gid;
+
+       virtio_p9_pdu_readf(pdu, "dsdddd", &fid_val, &name, &mode,
+                           &major, &minor, &gid);
+
+       dfid = get_fid(p9dev, fid_val);
+       sprintf(full_path, "%s/%s", dfid->abs_path, name);
+       ret = mknod(full_path, mode, makedev(major, minor));
+       if (ret < 0)
+               goto err_out;
+
+       if (lstat(full_path, &st) < 0)
+               goto err_out;
+
+       ret = chmod(full_path, mode & 0777);
+       if (ret < 0)
+               goto err_out;
+
+       ret = lchown(full_path, dfid->uid, gid);
+       if (ret < 0)
+               goto err_out;
+
+       stat2qid(&st, &qid);
+       virtio_p9_pdu_writef(pdu, "Q", &qid);
+       free(name);
+       *outlen = pdu->write_offset;
+       virtio_p9_set_reply_header(pdu, *outlen);
+       return;
+err_out:
+       free(name);
+       virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+       return;
+}
+
+static void virtio_p9_fsync(struct p9_dev *p9dev,
+                           struct p9_pdu *pdu, u32 *outlen)
+{
+       int ret;
+       struct p9_fid *fid;
+       u32 fid_val, datasync;
+
+       virtio_p9_pdu_readf(pdu, "dd", &fid_val, &datasync);
+       fid = get_fid(p9dev, fid_val);
+
+       if (datasync)
+               ret = fdatasync(fid->fd);
+       else
+               ret = fsync(fid->fd);
+       if (ret < 0)
+               goto err_out;
+       *outlen = pdu->write_offset;
+       virtio_p9_set_reply_header(pdu, *outlen);
+       return;
+err_out:
+       virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+       return;
+}
+
+static void virtio_p9_symlink(struct p9_dev *p9dev,
+                             struct p9_pdu *pdu, u32 *outlen)
+{
+       int ret;
+       struct stat st;
+       u32 fid_val, gid;
+       struct p9_qid qid;
+       struct p9_fid *dfid;
+       char new_name[PATH_MAX];
+       char *old_path, *name;
+
+       virtio_p9_pdu_readf(pdu, "dssd", &fid_val, &name, &old_path, &gid);
+
+       dfid = get_fid(p9dev, fid_val);
+       sprintf(new_name, "%s/%s", dfid->abs_path, name);
+       ret = symlink(old_path, new_name);
+       if (ret < 0)
+               goto err_out;
+
+       if (lstat(new_name, &st) < 0)
+               goto err_out;
+
+       ret = lchown(new_name, dfid->uid, gid);
+       if (ret < 0)
+               goto err_out;
+
+       stat2qid(&st, &qid);
+       virtio_p9_pdu_writef(pdu, "Q", &qid);
+       free(name);
+       free(old_path);
+       *outlen = pdu->write_offset;
+       virtio_p9_set_reply_header(pdu, *outlen);
+       return;
+err_out:
+       free(name);
+       free(old_path);
+       virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+       return;
+}
+
+static void virtio_p9_link(struct p9_dev *p9dev,
+                          struct p9_pdu *pdu, u32 *outlen)
+{
+       int ret;
+       char *name;
+       u32 fid_val, dfid_val;
+       struct p9_fid *dfid, *fid;
+       char full_path[PATH_MAX];
+
+       virtio_p9_pdu_readf(pdu, "dds", &dfid_val, &fid_val, &name);
+
+       dfid = get_fid(p9dev, dfid_val);
+       fid =  get_fid(p9dev, fid_val);
+       sprintf(full_path, "%s/%s", dfid->abs_path, name);
+       ret = link(fid->abs_path, full_path);
+       if (ret < 0)
+               goto err_out;
+       free(name);
+       *outlen = pdu->write_offset;
+       virtio_p9_set_reply_header(pdu, *outlen);
+       return;
+err_out:
+       free(name);
+       virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+       return;
+
+}
+
+static void virtio_p9_lock(struct p9_dev *p9dev,
+                          struct p9_pdu *pdu, u32 *outlen)
+{
+       u8 ret;
+       u32 fid_val;
+       struct p9_flock flock;
+
+       virtio_p9_pdu_readf(pdu, "dbdqqds", &fid_val, &flock.type,
+                           &flock.flags, &flock.start, &flock.length,
+                           &flock.proc_id, &flock.client_id);
+
+       /* Just return success */
+       ret = P9_LOCK_SUCCESS;
+       virtio_p9_pdu_writef(pdu, "d", ret);
+       *outlen = pdu->write_offset;
+       virtio_p9_set_reply_header(pdu, *outlen);
+       free(flock.client_id);
+       return;
+}
+
+static void virtio_p9_getlock(struct p9_dev *p9dev,
+                             struct p9_pdu *pdu, u32 *outlen)
+{
+       u32 fid_val;
+       struct p9_getlock glock;
+       virtio_p9_pdu_readf(pdu, "dbqqds", &fid_val, &glock.type,
+                           &glock.start, &glock.length, &glock.proc_id,
+                           &glock.client_id);
+
+       /* Just return success */
+       glock.type = F_UNLCK;
+       virtio_p9_pdu_writef(pdu, "bqqds", glock.type,
+                            glock.start, glock.length, glock.proc_id,
+                            glock.client_id);
+       *outlen = pdu->write_offset;
+       virtio_p9_set_reply_header(pdu, *outlen);
+       free(glock.client_id);
+       return;
+}
+
+static int virtio_p9_ancestor(char *path, char *ancestor)
+{
+       int size = strlen(ancestor);
+       if (!strncmp(path, ancestor, size)) {
+               /*
+                * Now check whether ancestor is a full name or
+                * or directory component and not just part
+                * of a name.
+                */
+               if (path[size] == '\0' || path[size] == '/')
+                       return 1;
+       }
+       return 0;
+}
+
+static void virtio_p9_fix_path(char *fid_path, char *old_name, char *new_name)
+{
+       char tmp_name[PATH_MAX];
+       size_t rp_sz = strlen(old_name);
+
+       if (rp_sz == strlen(fid_path)) {
+               /* replace the full name */
+               strcpy(fid_path, new_name);
+               return;
+       }
+       /* save the trailing path details */
+       strcpy(tmp_name, fid_path + rp_sz);
+       sprintf(fid_path, "%s%s", new_name, tmp_name);
+       return;
+}
+
+static void rename_fids(struct p9_dev *p9dev, char *old_name, char *new_name)
+{
+       struct rb_node *node = rb_first(&p9dev->fids);
+
+       while (node) {
+               struct p9_fid *fid = rb_entry(node, struct p9_fid, node);
+
+               if (fid->fid != P9_NOFID && virtio_p9_ancestor(fid->path, old_name)) {
+                               virtio_p9_fix_path(fid->path, old_name, new_name);
+               }
+               node = rb_next(node);
+       }
+}
+
+static void virtio_p9_renameat(struct p9_dev *p9dev,
+                              struct p9_pdu *pdu, u32 *outlen)
+{
+       int ret;
+       char *old_name, *new_name;
+       u32 old_dfid_val, new_dfid_val;
+       struct p9_fid *old_dfid, *new_dfid;
+       char old_full_path[PATH_MAX], new_full_path[PATH_MAX];
+
+
+       virtio_p9_pdu_readf(pdu, "dsds", &old_dfid_val, &old_name,
+                           &new_dfid_val, &new_name);
+
+       old_dfid = get_fid(p9dev, old_dfid_val);
+       new_dfid = get_fid(p9dev, new_dfid_val);
+
+       sprintf(old_full_path, "%s/%s", old_dfid->abs_path, old_name);
+       sprintf(new_full_path, "%s/%s", new_dfid->abs_path, new_name);
+       ret = rename(old_full_path, new_full_path);
+       if (ret < 0)
+               goto err_out;
+       /*
+        * Now fix path in other fids, if the renamed path is part of
+        * that.
+        */
+       rename_fids(p9dev, old_name, new_name);
+       free(old_name);
+       free(new_name);
+       *outlen = pdu->write_offset;
+       virtio_p9_set_reply_header(pdu, *outlen);
+       return;
+err_out:
+       free(old_name);
+       free(new_name);
+       virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+       return;
+}
+
+static void virtio_p9_unlinkat(struct p9_dev *p9dev,
+                              struct p9_pdu *pdu, u32 *outlen)
+{
+       int ret;
+       char *name;
+       u32 fid_val, flags;
+       struct p9_fid *fid;
+       char full_path[PATH_MAX];
+
+       virtio_p9_pdu_readf(pdu, "dsd", &fid_val, &name, &flags);
+       fid = get_fid(p9dev, fid_val);
+
+       sprintf(full_path, "%s/%s", fid->abs_path, name);
+       ret = remove(full_path);
+       if (ret < 0)
+               goto err_out;
+       free(name);
+       *outlen = pdu->write_offset;
+       virtio_p9_set_reply_header(pdu, *outlen);
+       return;
+err_out:
+       free(name);
+       virtio_p9_error_reply(p9dev, pdu, errno, outlen);
+       return;
+}
+
+static void virtio_p9_flush(struct p9_dev *p9dev,
+                               struct p9_pdu *pdu, u32 *outlen)
+{
+       u16 tag, oldtag;
+
+       virtio_p9_pdu_readf(pdu, "ww", &tag, &oldtag);
+       virtio_p9_pdu_writef(pdu, "w", tag);
+       *outlen = pdu->write_offset;
+       virtio_p9_set_reply_header(pdu, *outlen);
+
+       return;
+}
+
+static void virtio_p9_eopnotsupp(struct p9_dev *p9dev,
+                                struct p9_pdu *pdu, u32 *outlen)
+{
+       return virtio_p9_error_reply(p9dev, pdu, EOPNOTSUPP, outlen);
+}
+
+typedef void p9_handler(struct p9_dev *p9dev,
+                       struct p9_pdu *pdu, u32 *outlen);
+
+/* FIXME should be removed when merging with latest linus tree */
+#define P9_TRENAMEAT 74
+#define P9_TUNLINKAT 76
+
+static p9_handler *virtio_9p_dotl_handler [] = {
+       [P9_TREADDIR]     = virtio_p9_readdir,
+       [P9_TSTATFS]      = virtio_p9_statfs,
+       [P9_TGETATTR]     = virtio_p9_getattr,
+       [P9_TSETATTR]     = virtio_p9_setattr,
+       [P9_TXATTRWALK]   = virtio_p9_eopnotsupp,
+       [P9_TXATTRCREATE] = virtio_p9_eopnotsupp,
+       [P9_TMKNOD]       = virtio_p9_mknod,
+       [P9_TLOCK]        = virtio_p9_lock,
+       [P9_TGETLOCK]     = virtio_p9_getlock,
+       [P9_TRENAMEAT]    = virtio_p9_renameat,
+       [P9_TREADLINK]    = virtio_p9_readlink,
+       [P9_TUNLINKAT]    = virtio_p9_unlinkat,
+       [P9_TMKDIR]       = virtio_p9_mkdir,
+       [P9_TVERSION]     = virtio_p9_version,
+       [P9_TLOPEN]       = virtio_p9_open,
+       [P9_TATTACH]      = virtio_p9_attach,
+       [P9_TWALK]        = virtio_p9_walk,
+       [P9_TCLUNK]       = virtio_p9_clunk,
+       [P9_TFSYNC]       = virtio_p9_fsync,
+       [P9_TREAD]        = virtio_p9_read,
+       [P9_TFLUSH]       = virtio_p9_flush,
+       [P9_TLINK]        = virtio_p9_link,
+       [P9_TSYMLINK]     = virtio_p9_symlink,
+       [P9_TLCREATE]     = virtio_p9_create,
+       [P9_TWRITE]       = virtio_p9_write,
+       [P9_TREMOVE]      = virtio_p9_remove,
+       [P9_TRENAME]      = virtio_p9_rename,
+};
+
+static struct p9_pdu *virtio_p9_pdu_init(struct kvm *kvm, struct virt_queue *vq)
+{
+       struct p9_pdu *pdu = calloc(1, sizeof(*pdu));
+       if (!pdu)
+               return NULL;
+
+       /* skip the pdu header p9_msg */
+       pdu->read_offset        = VIRTIO_9P_HDR_LEN;
+       pdu->write_offset       = VIRTIO_9P_HDR_LEN;
+       pdu->queue_head         = virt_queue__get_inout_iov(kvm, vq, pdu->in_iov,
+                                       pdu->out_iov, &pdu->in_iov_cnt, &pdu->out_iov_cnt);
+       return pdu;
+}
+
+static u8 virtio_p9_get_cmd(struct p9_pdu *pdu)
+{
+       struct p9_msg *msg;
+       /*
+        * we can peek directly into pdu for a u8
+        * value. The host endianess won't be an issue
+        */
+       msg = pdu->out_iov[0].iov_base;
+       return msg->cmd;
+}
+
+static bool virtio_p9_do_io_request(struct kvm *kvm, struct p9_dev_job *job)
+{
+       u8 cmd;
+       u32 len = 0;
+       p9_handler *handler;
+       struct p9_dev *p9dev;
+       struct virt_queue *vq;
+       struct p9_pdu *p9pdu;
+
+       vq = job->vq;
+       p9dev = job->p9dev;
+
+       p9pdu = virtio_p9_pdu_init(kvm, vq);
+       cmd = virtio_p9_get_cmd(p9pdu);
+
+       if ((cmd >= ARRAY_SIZE(virtio_9p_dotl_handler)) ||
+           !virtio_9p_dotl_handler[cmd])
+               handler = virtio_p9_eopnotsupp;
+       else
+               handler = virtio_9p_dotl_handler[cmd];
+
+       handler(p9dev, p9pdu, &len);
+       virt_queue__set_used_elem(vq, p9pdu->queue_head, len);
+       free(p9pdu);
+       return true;
+}
+
+static void virtio_p9_do_io(struct kvm *kvm, void *param)
+{
+       struct p9_dev_job *job = (struct p9_dev_job *)param;
+       struct p9_dev *p9dev   = job->p9dev;
+       struct virt_queue *vq  = job->vq;
+
+       while (virt_queue__available(vq)) {
+               virtio_p9_do_io_request(kvm, job);
+               p9dev->vdev.ops->signal_vq(kvm, &p9dev->vdev, vq - p9dev->vqs);
+       }
+}
+
+static void set_config(struct kvm *kvm, void *dev, u8 data, u32 offset)
+{
+       struct p9_dev *p9dev = dev;
+
+       ((u8 *)(p9dev->config))[offset] = data;
+}
+
+static u8 get_config(struct kvm *kvm, void *dev, u32 offset)
+{
+       struct p9_dev *p9dev = dev;
+
+       return ((u8 *)(p9dev->config))[offset];
+}
+
+static u32 get_host_features(struct kvm *kvm, void *dev)
+{
+       return 1 << VIRTIO_9P_MOUNT_TAG;
+}
+
+static void set_guest_features(struct kvm *kvm, void *dev, u32 features)
+{
+       struct p9_dev *p9dev = dev;
+
+       p9dev->features = features;
+}
+
+static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 pfn)
+{
+       struct p9_dev *p9dev = dev;
+       struct p9_dev_job *job;
+       struct virt_queue *queue;
+       void *p;
+
+       compat__remove_message(compat_id);
+
+       queue           = &p9dev->vqs[vq];
+       queue->pfn      = pfn;
+       p               = guest_pfn_to_host(kvm, queue->pfn);
+       job             = &p9dev->jobs[vq];
+
+       vring_init(&queue->vring, VIRTQUEUE_NUM, p, VIRTIO_PCI_VRING_ALIGN);
+
+       *job            = (struct p9_dev_job) {
+               .vq             = queue,
+               .p9dev          = p9dev,
+       };
+       thread_pool__init_job(&job->job_id, kvm, virtio_p9_do_io, job);
+
+       return 0;
+}
+
+static int notify_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+       struct p9_dev *p9dev = dev;
+
+       thread_pool__do_job(&p9dev->jobs[vq].job_id);
+
+       return 0;
+}
+
+static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+       struct p9_dev *p9dev = dev;
+
+       return p9dev->vqs[vq].pfn;
+}
+
+static int get_size_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+       return VIRTQUEUE_NUM;
+}
+
+struct virtio_ops p9_dev_virtio_ops = (struct virtio_ops) {
+       .set_config             = set_config,
+       .get_config             = get_config,
+       .get_host_features      = get_host_features,
+       .set_guest_features     = set_guest_features,
+       .init_vq                = init_vq,
+       .notify_vq              = notify_vq,
+       .get_pfn_vq             = get_pfn_vq,
+       .get_size_vq            = get_size_vq,
+};
+
+int virtio_9p__init(struct kvm *kvm)
+{
+       struct p9_dev *p9dev;
+
+       list_for_each_entry(p9dev, &devs, list) {
+               virtio_init(kvm, p9dev, &p9dev->vdev, &p9_dev_virtio_ops,
+                           VIRTIO_PCI, PCI_DEVICE_ID_VIRTIO_9P, VIRTIO_ID_9P, PCI_CLASS_9P);
+       }
+
+       return 0;
+}
+
+int virtio_9p__register(struct kvm *kvm, const char *root, const char *tag_name)
+{
+       struct p9_dev *p9dev;
+       int err = 0;
+
+       p9dev = calloc(1, sizeof(*p9dev));
+       if (!p9dev)
+               return -ENOMEM;
+
+       if (!tag_name)
+               tag_name = VIRTIO_9P_DEFAULT_TAG;
+
+       p9dev->config = calloc(1, sizeof(*p9dev->config) + strlen(tag_name) + 1);
+       if (p9dev->config == NULL) {
+               err = -ENOMEM;
+               goto free_p9dev;
+       }
+
+       strcpy(p9dev->root_dir, root);
+       p9dev->config->tag_len = strlen(tag_name);
+       if (p9dev->config->tag_len > MAX_TAG_LEN) {
+               err = -EINVAL;
+               goto free_p9dev_config;
+       }
+
+       memcpy(&p9dev->config->tag, tag_name, strlen(tag_name));
+
+       list_add(&p9dev->list, &devs);
+
+       if (compat_id == -1)
+               compat_id = virtio_compat_add_message("virtio-9p", "CONFIG_NET_9P_VIRTIO");
+
+       return err;
+
+free_p9dev_config:
+       free(p9dev->config);
+free_p9dev:
+       free(p9dev);
+       return err;
+}
diff --git a/tools/kvm/virtio/balloon.c b/tools/kvm/virtio/balloon.c
new file mode 100644 (file)
index 0000000..a838ff4
--- /dev/null
@@ -0,0 +1,267 @@
+#include "kvm/virtio-balloon.h"
+
+#include "kvm/virtio-pci-dev.h"
+
+#include "kvm/virtio.h"
+#include "kvm/util.h"
+#include "kvm/kvm.h"
+#include "kvm/pci.h"
+#include "kvm/threadpool.h"
+#include "kvm/guest_compat.h"
+#include "kvm/kvm-ipc.h"
+
+#include <linux/virtio_ring.h>
+#include <linux/virtio_balloon.h>
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <pthread.h>
+#include <sys/eventfd.h>
+
+#define NUM_VIRT_QUEUES                3
+#define VIRTIO_BLN_QUEUE_SIZE  128
+#define VIRTIO_BLN_INFLATE     0
+#define VIRTIO_BLN_DEFLATE     1
+#define VIRTIO_BLN_STATS       2
+
+struct bln_dev {
+       struct list_head        list;
+       struct virtio_device    vdev;
+
+       u32                     features;
+
+       /* virtio queue */
+       struct virt_queue       vqs[NUM_VIRT_QUEUES];
+       struct thread_pool__job jobs[NUM_VIRT_QUEUES];
+
+       struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR];
+       struct virtio_balloon_stat *cur_stat;
+       u32                     cur_stat_head;
+       u16                     stat_count;
+       int                     stat_waitfd;
+
+       struct virtio_balloon_config config;
+};
+
+static struct bln_dev bdev;
+extern struct kvm *kvm;
+static int compat_id = -1;
+
+static bool virtio_bln_do_io_request(struct kvm *kvm, struct bln_dev *bdev, struct virt_queue *queue)
+{
+       struct iovec iov[VIRTIO_BLN_QUEUE_SIZE];
+       unsigned int len = 0;
+       u16 out, in, head;
+       u32 *ptrs, i;
+
+       head    = virt_queue__get_iov(queue, iov, &out, &in, kvm);
+       ptrs    = iov[0].iov_base;
+       len     = iov[0].iov_len / sizeof(u32);
+
+       for (i = 0 ; i < len ; i++) {
+               void *guest_ptr;
+
+               guest_ptr = guest_flat_to_host(kvm, ptrs[i] << VIRTIO_BALLOON_PFN_SHIFT);
+               if (queue == &bdev->vqs[VIRTIO_BLN_INFLATE]) {
+                       madvise(guest_ptr, 1 << VIRTIO_BALLOON_PFN_SHIFT, MADV_DONTNEED);
+                       bdev->config.actual++;
+               } else if (queue == &bdev->vqs[VIRTIO_BLN_DEFLATE]) {
+                       bdev->config.actual--;
+               }
+       }
+
+       virt_queue__set_used_elem(queue, head, len);
+
+       return true;
+}
+
+static bool virtio_bln_do_stat_request(struct kvm *kvm, struct bln_dev *bdev, struct virt_queue *queue)
+{
+       struct iovec iov[VIRTIO_BLN_QUEUE_SIZE];
+       u16 out, in, head;
+       struct virtio_balloon_stat *stat;
+       u64 wait_val = 1;
+
+       head = virt_queue__get_iov(queue, iov, &out, &in, kvm);
+       stat = iov[0].iov_base;
+
+       /* Initial empty stat buffer */
+       if (bdev->cur_stat == NULL) {
+               bdev->cur_stat = stat;
+               bdev->cur_stat_head = head;
+
+               return true;
+       }
+
+       memcpy(bdev->stats, stat, iov[0].iov_len);
+
+       bdev->stat_count = iov[0].iov_len / sizeof(struct virtio_balloon_stat);
+       bdev->cur_stat = stat;
+       bdev->cur_stat_head = head;
+
+       if (write(bdev->stat_waitfd, &wait_val, sizeof(wait_val)) <= 0)
+               return -EFAULT;
+
+       return 1;
+}
+
+static void virtio_bln_do_io(struct kvm *kvm, void *param)
+{
+       struct virt_queue *vq = param;
+
+       if (vq == &bdev.vqs[VIRTIO_BLN_STATS]) {
+               virtio_bln_do_stat_request(kvm, &bdev, vq);
+               bdev.vdev.ops->signal_vq(kvm, &bdev.vdev, VIRTIO_BLN_STATS);
+               return;
+       }
+
+       while (virt_queue__available(vq)) {
+               virtio_bln_do_io_request(kvm, &bdev, vq);
+               bdev.vdev.ops->signal_vq(kvm, &bdev.vdev, vq - bdev.vqs);
+       }
+}
+
+static int virtio_bln__collect_stats(void)
+{
+       u64 tmp;
+
+       virt_queue__set_used_elem(&bdev.vqs[VIRTIO_BLN_STATS], bdev.cur_stat_head,
+                                 sizeof(struct virtio_balloon_stat));
+       bdev.vdev.ops->signal_vq(kvm, &bdev.vdev, VIRTIO_BLN_STATS);
+
+       if (read(bdev.stat_waitfd, &tmp, sizeof(tmp)) <= 0)
+               return -EFAULT;
+
+       return 0;
+}
+
+static void virtio_bln__print_stats(int fd, u32 type, u32 len, u8 *msg)
+{
+       int r;
+
+       if (WARN_ON(type != KVM_IPC_STAT || len))
+               return;
+
+       if (virtio_bln__collect_stats() < 0)
+               return;
+
+       r = write(fd, bdev.stats, sizeof(bdev.stats));
+       if (r < 0)
+               pr_warning("Failed sending memory stats");
+}
+
+static void handle_mem(int fd, u32 type, u32 len, u8 *msg)
+{
+       int mem;
+
+       if (WARN_ON(type != KVM_IPC_BALLOON || len != sizeof(int)))
+               return;
+
+       mem = *(int *)msg;
+       if (mem > 0) {
+               bdev.config.num_pages += 256 * mem;
+       } else if (mem < 0) {
+               if (bdev.config.num_pages < (u32)(256 * (-mem)))
+                       return;
+
+               bdev.config.num_pages += 256 * mem;
+       }
+
+       /* Notify that the configuration space has changed */
+       bdev.vdev.ops->signal_config(kvm, &bdev.vdev);
+}
+
+static void set_config(struct kvm *kvm, void *dev, u8 data, u32 offset)
+{
+       struct bln_dev *bdev = dev;
+
+       ((u8 *)(&bdev->config))[offset] = data;
+}
+
+static u8 get_config(struct kvm *kvm, void *dev, u32 offset)
+{
+       struct bln_dev *bdev = dev;
+
+       return ((u8 *)(&bdev->config))[offset];
+}
+
+static u32 get_host_features(struct kvm *kvm, void *dev)
+{
+       return 1 << VIRTIO_BALLOON_F_STATS_VQ;
+}
+
+static void set_guest_features(struct kvm *kvm, void *dev, u32 features)
+{
+       struct bln_dev *bdev = dev;
+
+       bdev->features = features;
+}
+
+static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 pfn)
+{
+       struct bln_dev *bdev = dev;
+       struct virt_queue *queue;
+       void *p;
+
+       compat__remove_message(compat_id);
+
+       queue           = &bdev->vqs[vq];
+       queue->pfn      = pfn;
+       p               = guest_pfn_to_host(kvm, queue->pfn);
+
+       thread_pool__init_job(&bdev->jobs[vq], kvm, virtio_bln_do_io, queue);
+       vring_init(&queue->vring, VIRTIO_BLN_QUEUE_SIZE, p, VIRTIO_PCI_VRING_ALIGN);
+
+       return 0;
+}
+
+static int notify_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+       struct bln_dev *bdev = dev;
+
+       thread_pool__do_job(&bdev->jobs[vq]);
+
+       return 0;
+}
+
+static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+       struct bln_dev *bdev = dev;
+
+       return bdev->vqs[vq].pfn;
+}
+
+static int get_size_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+       return VIRTIO_BLN_QUEUE_SIZE;
+}
+
+struct virtio_ops bln_dev_virtio_ops = (struct virtio_ops) {
+       .set_config             = set_config,
+       .get_config             = get_config,
+       .get_host_features      = get_host_features,
+       .set_guest_features     = set_guest_features,
+       .init_vq                = init_vq,
+       .notify_vq              = notify_vq,
+       .get_pfn_vq             = get_pfn_vq,
+       .get_size_vq            = get_size_vq,
+};
+
+void virtio_bln__init(struct kvm *kvm)
+{
+       kvm_ipc__register_handler(KVM_IPC_BALLOON, handle_mem);
+       kvm_ipc__register_handler(KVM_IPC_STAT, virtio_bln__print_stats);
+
+       bdev.stat_waitfd        = eventfd(0, 0);
+       memset(&bdev.config, 0, sizeof(struct virtio_balloon_config));
+
+       virtio_init(kvm, &bdev, &bdev.vdev, &bln_dev_virtio_ops,
+                   VIRTIO_PCI, PCI_DEVICE_ID_VIRTIO_BLN, VIRTIO_ID_BALLOON, PCI_CLASS_BLN);
+
+       if (compat_id == -1)
+               compat_id = virtio_compat_add_message("virtio-balloon", "CONFIG_VIRTIO_BALLOON");
+}
diff --git a/tools/kvm/virtio/blk.c b/tools/kvm/virtio/blk.c
new file mode 100644 (file)
index 0000000..1fb969f
--- /dev/null
@@ -0,0 +1,313 @@
+#include "kvm/virtio-blk.h"
+
+#include "kvm/virtio-pci-dev.h"
+#include "kvm/disk-image.h"
+#include "kvm/mutex.h"
+#include "kvm/util.h"
+#include "kvm/kvm.h"
+#include "kvm/pci.h"
+#include "kvm/threadpool.h"
+#include "kvm/ioeventfd.h"
+#include "kvm/guest_compat.h"
+#include "kvm/virtio-pci.h"
+#include "kvm/virtio.h"
+
+#include <linux/virtio_ring.h>
+#include <linux/virtio_blk.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/types.h>
+#include <pthread.h>
+
+#define VIRTIO_BLK_MAX_DEV             4
+
+/*
+ * the header and status consume too entries
+ */
+#define DISK_SEG_MAX                   (VIRTIO_BLK_QUEUE_SIZE - 2)
+#define VIRTIO_BLK_QUEUE_SIZE          256
+#define NUM_VIRT_QUEUES                        1
+
+struct blk_dev_req {
+       struct virt_queue               *vq;
+       struct blk_dev                  *bdev;
+       struct iovec                    iov[VIRTIO_BLK_QUEUE_SIZE];
+       u16                             out, in, head;
+       struct kvm                      *kvm;
+};
+
+struct blk_dev {
+       pthread_mutex_t                 mutex;
+
+       struct list_head                list;
+
+       struct virtio_device            vdev;
+       struct virtio_blk_config        blk_config;
+       struct disk_image               *disk;
+       u32                             features;
+
+       struct virt_queue               vqs[NUM_VIRT_QUEUES];
+       struct blk_dev_req              reqs[VIRTIO_BLK_QUEUE_SIZE];
+
+       pthread_t                       io_thread;
+       int                             io_efd;
+
+       struct kvm                      *kvm;
+};
+
+static LIST_HEAD(bdevs);
+static int compat_id = -1;
+
+void virtio_blk_complete(void *param, long len)
+{
+       struct blk_dev_req *req = param;
+       struct blk_dev *bdev = req->bdev;
+       int queueid = req->vq - bdev->vqs;
+       u8 *status;
+
+       /* status */
+       status  = req->iov[req->out + req->in - 1].iov_base;
+       *status = (len < 0) ? VIRTIO_BLK_S_IOERR : VIRTIO_BLK_S_OK;
+
+       mutex_lock(&bdev->mutex);
+       virt_queue__set_used_elem(req->vq, req->head, len);
+       mutex_unlock(&bdev->mutex);
+
+       if (virtio_queue__should_signal(&bdev->vqs[queueid]))
+               bdev->vdev.ops->signal_vq(req->kvm, &bdev->vdev, queueid);
+}
+
+static void virtio_blk_do_io_request(struct kvm *kvm, struct blk_dev_req *req)
+{
+       struct virtio_blk_outhdr *req_hdr;
+       ssize_t block_cnt;
+       struct blk_dev *bdev;
+       struct iovec *iov;
+       u16 out, in;
+
+       block_cnt       = -1;
+       bdev            = req->bdev;
+       iov             = req->iov;
+       out             = req->out;
+       in              = req->in;
+       req_hdr         = iov[0].iov_base;
+
+       switch (req_hdr->type) {
+       case VIRTIO_BLK_T_IN:
+               block_cnt = disk_image__read(bdev->disk, req_hdr->sector,
+                               iov + 1, in + out - 2, req);
+               break;
+       case VIRTIO_BLK_T_OUT:
+               block_cnt = disk_image__write(bdev->disk, req_hdr->sector,
+                               iov + 1, in + out - 2, req);
+               break;
+       case VIRTIO_BLK_T_FLUSH:
+               block_cnt = disk_image__flush(bdev->disk);
+               virtio_blk_complete(req, block_cnt);
+               break;
+       case VIRTIO_BLK_T_GET_ID:
+               block_cnt = VIRTIO_BLK_ID_BYTES;
+               disk_image__get_serial(bdev->disk,
+                               (iov + 1)->iov_base, &block_cnt);
+               virtio_blk_complete(req, block_cnt);
+               break;
+       default:
+               pr_warning("request type %d", req_hdr->type);
+               block_cnt       = -1;
+               break;
+       }
+}
+
+static void virtio_blk_do_io(struct kvm *kvm, struct virt_queue *vq, struct blk_dev *bdev)
+{
+       struct blk_dev_req *req;
+       u16 head;
+
+       while (virt_queue__available(vq)) {
+               head            = virt_queue__pop(vq);
+               req             = &bdev->reqs[head];
+               req->head       = virt_queue__get_head_iov(vq, req->iov, &req->out,
+                                       &req->in, head, kvm);
+               req->vq         = vq;
+
+               virtio_blk_do_io_request(kvm, req);
+       }
+}
+
+static void set_config(struct kvm *kvm, void *dev, u8 data, u32 offset)
+{
+       struct blk_dev *bdev = dev;
+
+       ((u8 *)(&bdev->blk_config))[offset] = data;
+}
+
+static u8 get_config(struct kvm *kvm, void *dev, u32 offset)
+{
+       struct blk_dev *bdev = dev;
+
+       return ((u8 *)(&bdev->blk_config))[offset];
+}
+
+static u32 get_host_features(struct kvm *kvm, void *dev)
+{
+       return  1UL << VIRTIO_BLK_F_SEG_MAX
+               | 1UL << VIRTIO_BLK_F_FLUSH
+               | 1UL << VIRTIO_RING_F_EVENT_IDX
+               | 1UL << VIRTIO_RING_F_INDIRECT_DESC;
+}
+
+static void set_guest_features(struct kvm *kvm, void *dev, u32 features)
+{
+       struct blk_dev *bdev = dev;
+
+       bdev->features = features;
+}
+
+static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 pfn)
+{
+       struct blk_dev *bdev = dev;
+       struct virt_queue *queue;
+       void *p;
+
+       compat__remove_message(compat_id);
+
+       queue           = &bdev->vqs[vq];
+       queue->pfn      = pfn;
+       p               = guest_pfn_to_host(kvm, queue->pfn);
+
+       vring_init(&queue->vring, VIRTIO_BLK_QUEUE_SIZE, p, VIRTIO_PCI_VRING_ALIGN);
+
+       return 0;
+}
+
+static void *virtio_blk_thread(void *dev)
+{
+       struct blk_dev *bdev = dev;
+       u64 data;
+
+       while (1) {
+               read(bdev->io_efd, &data, sizeof(u64));
+               virtio_blk_do_io(bdev->kvm, &bdev->vqs[0], bdev);
+       }
+
+       pthread_exit(NULL);
+       return NULL;
+}
+
+static int notify_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+       struct blk_dev *bdev = dev;
+       u64 data = 1;
+
+       write(bdev->io_efd, &data, sizeof(data));
+
+       return 0;
+}
+
+static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+       struct blk_dev *bdev = dev;
+
+       return bdev->vqs[vq].pfn;
+}
+
+static int get_size_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+       /* FIXME: dynamic */
+       return VIRTIO_BLK_QUEUE_SIZE;
+}
+
+static int set_size_vq(struct kvm *kvm, void *dev, u32 vq, int size)
+{
+       /* FIXME: dynamic */
+       return size;
+}
+
+static struct virtio_ops blk_dev_virtio_ops = (struct virtio_ops) {
+       .set_config             = set_config,
+       .get_config             = get_config,
+       .get_host_features      = get_host_features,
+       .set_guest_features     = set_guest_features,
+       .init_vq                = init_vq,
+       .notify_vq              = notify_vq,
+       .get_pfn_vq             = get_pfn_vq,
+       .get_size_vq            = get_size_vq,
+       .set_size_vq            = set_size_vq,
+};
+
+static int virtio_blk__init_one(struct kvm *kvm, struct disk_image *disk)
+{
+       struct blk_dev *bdev;
+       unsigned int i;
+
+       if (!disk)
+               return -EINVAL;
+
+       bdev = calloc(1, sizeof(struct blk_dev));
+       if (bdev == NULL)
+               return -ENOMEM;
+
+       *bdev = (struct blk_dev) {
+               .mutex                  = PTHREAD_MUTEX_INITIALIZER,
+               .disk                   = disk,
+               .blk_config             = (struct virtio_blk_config) {
+                       .capacity       = disk->size / SECTOR_SIZE,
+                       .seg_max        = DISK_SEG_MAX,
+               },
+               .io_efd                 = eventfd(0, 0),
+               .kvm                    = kvm,
+       };
+
+       virtio_init(kvm, bdev, &bdev->vdev, &blk_dev_virtio_ops,
+                   VIRTIO_PCI, PCI_DEVICE_ID_VIRTIO_BLK, VIRTIO_ID_BLOCK, PCI_CLASS_BLK);
+
+       list_add_tail(&bdev->list, &bdevs);
+
+       for (i = 0; i < ARRAY_SIZE(bdev->reqs); i++) {
+               bdev->reqs[i].bdev = bdev;
+               bdev->reqs[i].kvm = kvm;
+       }
+
+       disk_image__set_callback(bdev->disk, virtio_blk_complete);
+
+       pthread_create(&bdev->io_thread, NULL, virtio_blk_thread, bdev);
+       if (compat_id == -1)
+               compat_id = virtio_compat_add_message("virtio-blk", "CONFIG_VIRTIO_BLK");
+
+       return 0;
+}
+
+static int virtio_blk__exit_one(struct kvm *kvm, struct blk_dev *bdev)
+{
+       list_del(&bdev->list);
+       free(bdev);
+
+       return 0;
+}
+
+int virtio_blk__init(struct kvm *kvm)
+{
+       int i, r = 0;
+
+       for (i = 0; i < kvm->nr_disks; i++) {
+               r = virtio_blk__init_one(kvm, kvm->disks[i]);
+               if (r < 0)
+                       goto cleanup;
+       }
+
+       return 0;
+cleanup:
+       return virtio_blk__exit(kvm);
+}
+
+int virtio_blk__exit(struct kvm *kvm)
+{
+       while (!list_empty(&bdevs)) {
+               struct blk_dev *bdev;
+
+               bdev = list_first_entry(&bdevs, struct blk_dev, list);
+               virtio_blk__exit_one(kvm, bdev);
+       }
+
+       return 0;
+}
diff --git a/tools/kvm/virtio/console.c b/tools/kvm/virtio/console.c
new file mode 100644 (file)
index 0000000..4bb1365
--- /dev/null
@@ -0,0 +1,193 @@
+#include "kvm/virtio-console.h"
+#include "kvm/virtio-pci-dev.h"
+#include "kvm/disk-image.h"
+#include "kvm/virtio.h"
+#include "kvm/ioport.h"
+#include "kvm/util.h"
+#include "kvm/term.h"
+#include "kvm/mutex.h"
+#include "kvm/kvm.h"
+#include "kvm/pci.h"
+#include "kvm/threadpool.h"
+#include "kvm/irq.h"
+#include "kvm/guest_compat.h"
+
+#include <linux/virtio_console.h>
+#include <linux/virtio_ring.h>
+#include <linux/virtio_blk.h>
+
+#include <sys/uio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <termios.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#define VIRTIO_CONSOLE_QUEUE_SIZE      128
+#define VIRTIO_CONSOLE_NUM_QUEUES      2
+#define VIRTIO_CONSOLE_RX_QUEUE                0
+#define VIRTIO_CONSOLE_TX_QUEUE                1
+
+struct con_dev {
+       pthread_mutex_t                 mutex;
+
+       struct virtio_device            vdev;
+       struct virt_queue               vqs[VIRTIO_CONSOLE_NUM_QUEUES];
+       struct virtio_console_config    config;
+       u32                             features;
+
+       struct thread_pool__job         jobs[VIRTIO_CONSOLE_NUM_QUEUES];
+};
+
+static struct con_dev cdev = {
+       .mutex                          = PTHREAD_MUTEX_INITIALIZER,
+
+       .config = {
+               .cols                   = 80,
+               .rows                   = 24,
+               .max_nr_ports           = 1,
+       },
+};
+
+static int compat_id = -1;
+
+/*
+ * Interrupts are injected for hvc0 only.
+ */
+static void virtio_console__inject_interrupt_callback(struct kvm *kvm, void *param)
+{
+       struct iovec iov[VIRTIO_CONSOLE_QUEUE_SIZE];
+       struct virt_queue *vq;
+       u16 out, in;
+       u16 head;
+       int len;
+
+       mutex_lock(&cdev.mutex);
+
+       vq = param;
+
+       if (term_readable(CONSOLE_VIRTIO, 0) && virt_queue__available(vq)) {
+               head = virt_queue__get_iov(vq, iov, &out, &in, kvm);
+               len = term_getc_iov(CONSOLE_VIRTIO, iov, in, 0);
+               virt_queue__set_used_elem(vq, head, len);
+               cdev.vdev.ops->signal_vq(kvm, &cdev.vdev, vq - cdev.vqs);
+       }
+
+       mutex_unlock(&cdev.mutex);
+}
+
+void virtio_console__inject_interrupt(struct kvm *kvm)
+{
+       thread_pool__do_job(&cdev.jobs[VIRTIO_CONSOLE_RX_QUEUE]);
+}
+
+static void virtio_console_handle_callback(struct kvm *kvm, void *param)
+{
+       struct iovec iov[VIRTIO_CONSOLE_QUEUE_SIZE];
+       struct virt_queue *vq;
+       u16 out, in;
+       u16 head;
+       u32 len;
+
+       vq = param;
+
+       /*
+        * The current Linux implementation polls for the buffer
+        * to be used, rather than waiting for an interrupt.
+        * So there is no need to inject an interrupt for the tx path.
+        */
+
+       while (virt_queue__available(vq)) {
+               head = virt_queue__get_iov(vq, iov, &out, &in, kvm);
+               len = term_putc_iov(CONSOLE_VIRTIO, iov, out, 0);
+               virt_queue__set_used_elem(vq, head, len);
+       }
+
+}
+
+static void set_config(struct kvm *kvm, void *dev, u8 data, u32 offset)
+{
+       struct con_dev *cdev = dev;
+
+       ((u8 *)(&cdev->config))[offset] = data;
+}
+
+static u8 get_config(struct kvm *kvm, void *dev, u32 offset)
+{
+       struct con_dev *cdev = dev;
+
+       return ((u8 *)(&cdev->config))[offset];
+}
+
+static u32 get_host_features(struct kvm *kvm, void *dev)
+{
+       return 0;
+}
+
+static void set_guest_features(struct kvm *kvm, void *dev, u32 features)
+{
+       /* Unused */
+}
+
+static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 pfn)
+{
+       struct virt_queue *queue;
+       void *p;
+
+       BUG_ON(vq >= VIRTIO_CONSOLE_NUM_QUEUES);
+
+       compat__remove_message(compat_id);
+
+       queue           = &cdev.vqs[vq];
+       queue->pfn      = pfn;
+       p               = guest_pfn_to_host(kvm, queue->pfn);
+
+       vring_init(&queue->vring, VIRTIO_CONSOLE_QUEUE_SIZE, p, VIRTIO_PCI_VRING_ALIGN);
+
+       if (vq == VIRTIO_CONSOLE_TX_QUEUE)
+               thread_pool__init_job(&cdev.jobs[vq], kvm, virtio_console_handle_callback, queue);
+       else if (vq == VIRTIO_CONSOLE_RX_QUEUE)
+               thread_pool__init_job(&cdev.jobs[vq], kvm, virtio_console__inject_interrupt_callback, queue);
+
+       return 0;
+}
+
+static int notify_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+       struct con_dev *cdev = dev;
+
+       thread_pool__do_job(&cdev->jobs[vq]);
+
+       return 0;
+}
+
+static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+       struct con_dev *cdev = dev;
+
+       return cdev->vqs[vq].pfn;
+}
+
+static int get_size_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+       return VIRTIO_CONSOLE_QUEUE_SIZE;
+}
+
+static struct virtio_ops con_dev_virtio_ops = (struct virtio_ops) {
+       .set_config             = set_config,
+       .get_config             = get_config,
+       .get_host_features      = get_host_features,
+       .set_guest_features     = set_guest_features,
+       .init_vq                = init_vq,
+       .notify_vq              = notify_vq,
+       .get_pfn_vq             = get_pfn_vq,
+       .get_size_vq            = get_size_vq,
+};
+
+void virtio_console__init(struct kvm *kvm)
+{
+       virtio_init(kvm, &cdev, &cdev.vdev, &con_dev_virtio_ops,
+                   VIRTIO_PCI, PCI_DEVICE_ID_VIRTIO_CONSOLE, VIRTIO_ID_CONSOLE, PCI_CLASS_CONSOLE);
+       if (compat_id == -1)
+               compat_id = virtio_compat_add_message("virtio-console", "CONFIG_VIRTIO_CONSOLE");
+}
diff --git a/tools/kvm/virtio/core.c b/tools/kvm/virtio/core.c
new file mode 100644 (file)
index 0000000..2dfb828
--- /dev/null
@@ -0,0 +1,233 @@
+#include <linux/virtio_ring.h>
+#include <linux/types.h>
+#include <sys/uio.h>
+#include <stdlib.h>
+
+#include "kvm/guest_compat.h"
+#include "kvm/barrier.h"
+#include "kvm/virtio.h"
+#include "kvm/virtio-pci.h"
+#include "kvm/virtio-mmio.h"
+#include "kvm/util.h"
+#include "kvm/kvm.h"
+
+
+struct vring_used_elem *virt_queue__set_used_elem(struct virt_queue *queue, u32 head, u32 len)
+{
+       struct vring_used_elem *used_elem;
+
+       used_elem       = &queue->vring.used->ring[queue->vring.used->idx % queue->vring.num];
+       used_elem->id   = head;
+       used_elem->len  = len;
+
+       /*
+        * Use wmb to assure that used elem was updated with head and len.
+        * We need a wmb here since we can't advance idx unless we're ready
+        * to pass the used element to the guest.
+        */
+       wmb();
+       queue->vring.used->idx++;
+
+       /*
+        * Use wmb to assure used idx has been increased before we signal the guest.
+        * Without a wmb here the guest may ignore the queue since it won't see
+        * an updated idx.
+        */
+       wmb();
+
+       return used_elem;
+}
+
+/*
+ * Each buffer in the virtqueues is actually a chain of descriptors.  This
+ * function returns the next descriptor in the chain, or vq->vring.num if we're
+ * at the end.
+ */
+static unsigned next_desc(struct vring_desc *desc,
+                         unsigned int i, unsigned int max)
+{
+       unsigned int next;
+
+       /* If this descriptor says it doesn't chain, we're done. */
+       if (!(desc[i].flags & VRING_DESC_F_NEXT))
+               return max;
+
+       /* Check they're not leading us off end of descriptors. */
+       next = desc[i].next;
+       /* Make sure compiler knows to grab that: we don't want it changing! */
+       wmb();
+
+       return next;
+}
+
+u16 virt_queue__get_head_iov(struct virt_queue *vq, struct iovec iov[], u16 *out, u16 *in, u16 head, struct kvm *kvm)
+{
+       struct vring_desc *desc;
+       u16 idx;
+       u16 max;
+
+       idx = head;
+       *out = *in = 0;
+       max = vq->vring.num;
+       desc = vq->vring.desc;
+
+       if (desc[idx].flags & VRING_DESC_F_INDIRECT) {
+               max = desc[idx].len / sizeof(struct vring_desc);
+               desc = guest_flat_to_host(kvm, desc[idx].addr);
+               idx = 0;
+       }
+
+       do {
+               /* Grab the first descriptor, and check it's OK. */
+               iov[*out + *in].iov_len = desc[idx].len;
+               iov[*out + *in].iov_base = guest_flat_to_host(kvm, desc[idx].addr);
+               /* If this is an input descriptor, increment that count. */
+               if (desc[idx].flags & VRING_DESC_F_WRITE)
+                       (*in)++;
+               else
+                       (*out)++;
+       } while ((idx = next_desc(desc, idx, max)) != max);
+
+       return head;
+}
+
+u16 virt_queue__get_iov(struct virt_queue *vq, struct iovec iov[], u16 *out, u16 *in, struct kvm *kvm)
+{
+       u16 head;
+
+       head = virt_queue__pop(vq);
+
+       return virt_queue__get_head_iov(vq, iov, out, in, head, kvm);
+}
+
+/* in and out are relative to guest */
+u16 virt_queue__get_inout_iov(struct kvm *kvm, struct virt_queue *queue,
+                             struct iovec in_iov[], struct iovec out_iov[],
+                             u16 *in, u16 *out)
+{
+       struct vring_desc *desc;
+       u16 head, idx;
+
+       idx = head = virt_queue__pop(queue);
+       *out = *in = 0;
+       do {
+               desc = virt_queue__get_desc(queue, idx);
+               if (desc->flags & VRING_DESC_F_WRITE) {
+                       in_iov[*in].iov_base = guest_flat_to_host(kvm,
+                                                                 desc->addr);
+                       in_iov[*in].iov_len = desc->len;
+                       (*in)++;
+               } else {
+                       out_iov[*out].iov_base = guest_flat_to_host(kvm,
+                                                                   desc->addr);
+                       out_iov[*out].iov_len = desc->len;
+                       (*out)++;
+               }
+               if (desc->flags & VRING_DESC_F_NEXT)
+                       idx = desc->next;
+               else
+                       break;
+       } while (1);
+
+       return head;
+}
+
+int virtio__get_dev_specific_field(int offset, bool msix, u32 *config_off)
+{
+       if (msix) {
+               if (offset < 4)
+                       return VIRTIO_PCI_O_MSIX;
+               else
+                       offset -= 4;
+       }
+
+       *config_off = offset;
+
+       return VIRTIO_PCI_O_CONFIG;
+}
+
+bool virtio_queue__should_signal(struct virt_queue *vq)
+{
+       u16 old_idx, new_idx, event_idx;
+
+       old_idx         = vq->last_used_signalled;
+       new_idx         = vq->vring.used->idx;
+       event_idx       = vring_used_event(&vq->vring);
+
+       if (vring_need_event(event_idx, new_idx, old_idx)) {
+               vq->last_used_signalled = new_idx;
+               return true;
+       }
+
+       return false;
+}
+
+int virtio_init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
+               struct virtio_ops *ops, enum virtio_trans trans,
+               int device_id, int subsys_id, int class)
+{
+       void *virtio;
+
+       switch (trans) {
+       case VIRTIO_PCI:
+               virtio = calloc(sizeof(struct virtio_pci), 1);
+               if (!virtio)
+                       return -ENOMEM;
+               vdev->virtio                    = virtio;
+               vdev->ops                       = ops;
+               vdev->ops->signal_vq            = virtio_pci__signal_vq;
+               vdev->ops->signal_config        = virtio_pci__signal_config;
+               vdev->ops->init                 = virtio_pci__init;
+               vdev->ops->exit                 = virtio_pci__exit;
+               vdev->ops->init(kvm, dev, vdev, device_id, subsys_id, class);
+               break;
+       case VIRTIO_MMIO:
+               virtio = calloc(sizeof(struct virtio_mmio), 1);
+               if (!virtio)
+                       return -ENOMEM;
+               vdev->virtio                    = virtio;
+               vdev->ops                       = ops;
+               vdev->ops->signal_vq            = virtio_mmio_signal_vq;
+               vdev->ops->signal_config        = virtio_mmio_signal_config;
+               vdev->ops->init                 = virtio_mmio_init;
+               vdev->ops->exit                 = virtio_mmio_exit;
+               vdev->ops->init(kvm, dev, vdev, device_id, subsys_id, class);
+               break;
+       default:
+               return -1;
+       };
+
+       return 0;
+}
+
+int virtio_compat_add_message(const char *device, const char *config)
+{
+       int len = 1024;
+       int compat_id;
+       char *title;
+       char *desc;
+
+       title = malloc(len);
+       if (!title)
+               return -ENOMEM;
+
+       desc = malloc(len);
+       if (!desc) {
+               free(title);
+               return -ENOMEM;
+       }
+
+       snprintf(title, len, "%s device was not detected.", device);
+       snprintf(desc,  len, "While you have requested a %s device, "
+                            "the guest kernel did not initialize it.\n"
+                            "\tPlease make sure that the guest kernel was "
+                            "compiled with %s=y enabled in .config.",
+                            device, config);
+
+       compat_id = compat__add_message(title, desc);
+
+       free(desc);
+       free(title);
+
+       return compat_id;
+}
diff --git a/tools/kvm/virtio/mmio.c b/tools/kvm/virtio/mmio.c
new file mode 100644 (file)
index 0000000..1cf0815
--- /dev/null
@@ -0,0 +1,264 @@
+#include "kvm/virtio-mmio.h"
+#include "kvm/ioeventfd.h"
+#include "kvm/ioport.h"
+#include "kvm/virtio.h"
+#include "kvm/kvm.h"
+#include "kvm/irq.h"
+
+#include <linux/virtio_mmio.h>
+#include <string.h>
+
+static u32 virtio_mmio_io_space_blocks = KVM_VIRTIO_MMIO_AREA;
+
+static u32 virtio_mmio_get_io_space_block(u32 size)
+{
+       u32 block = virtio_mmio_io_space_blocks;
+       virtio_mmio_io_space_blocks += size;
+
+       return block;
+}
+
+static void virtio_mmio_ioevent_callback(struct kvm *kvm, void *param)
+{
+       struct virtio_mmio_ioevent_param *ioeventfd = param;
+       struct virtio_mmio *vmmio = ioeventfd->vdev->virtio;
+
+       ioeventfd->vdev->ops->notify_vq(kvm, vmmio->dev, ioeventfd->vq);
+}
+
+static int virtio_mmio_init_ioeventfd(struct kvm *kvm,
+                                     struct virtio_device *vdev, u32 vq)
+{
+       struct virtio_mmio *vmmio = vdev->virtio;
+       struct ioevent ioevent;
+       int err;
+
+       vmmio->ioeventfds[vq] = (struct virtio_mmio_ioevent_param) {
+               .vdev           = vdev,
+               .vq             = vq,
+       };
+
+       ioevent = (struct ioevent) {
+               .io_addr        = vmmio->addr + VIRTIO_MMIO_QUEUE_NOTIFY,
+               .io_len         = sizeof(u32),
+               .fn             = virtio_mmio_ioevent_callback,
+               .fn_ptr         = &vmmio->ioeventfds[vq],
+               .datamatch      = vq,
+               .fn_kvm         = kvm,
+               .fd             = eventfd(0, 0),
+       };
+
+       if (vdev->use_vhost)
+               /*
+                * Vhost will poll the eventfd in host kernel side,
+                * no need to poll in userspace.
+                */
+               err = ioeventfd__add_event(&ioevent, true, false);
+       else
+               /* Need to poll in userspace. */
+               err = ioeventfd__add_event(&ioevent, true, true);
+       if (err)
+               return err;
+
+       if (vdev->ops->notify_vq_eventfd)
+               vdev->ops->notify_vq_eventfd(kvm, vmmio->dev, vq, ioevent.fd);
+
+       return 0;
+}
+
+int virtio_mmio_signal_vq(struct kvm *kvm, struct virtio_device *vdev, u32 vq)
+{
+       struct virtio_mmio *vmmio = vdev->virtio;
+
+       vmmio->hdr.interrupt_state |= VIRTIO_MMIO_INT_VRING;
+       kvm__irq_trigger(vmmio->kvm, vmmio->irq);
+
+       return 0;
+}
+
+int virtio_mmio_signal_config(struct kvm *kvm, struct virtio_device *vdev)
+{
+       struct virtio_mmio *vmmio = vdev->virtio;
+
+       vmmio->hdr.interrupt_state |= VIRTIO_MMIO_INT_CONFIG;
+       kvm__irq_trigger(vmmio->kvm, vmmio->irq);
+
+       return 0;
+}
+
+static void virtio_mmio_device_specific(u64 addr, u8 *data, u32 len,
+                                       u8 is_write, struct virtio_device *vdev)
+{
+       struct virtio_mmio *vmmio = vdev->virtio;
+       u32 i;
+
+       for (i = 0; i < len; i++) {
+               if (is_write)
+                       vdev->ops->set_config(vmmio->kvm, vmmio->dev,
+                                             *(u8 *)data + i, addr + i);
+               else
+                       data[i] = vdev->ops->get_config(vmmio->kvm,
+                                                       vmmio->dev, addr + i);
+       }
+}
+
+static void virtio_mmio_config_in(u64 addr, void *data, u32 len,
+                                 struct virtio_device *vdev)
+{
+       struct virtio_mmio *vmmio = vdev->virtio;
+       u32 val = 0;
+
+       switch (addr) {
+       case VIRTIO_MMIO_MAGIC_VALUE:
+       case VIRTIO_MMIO_VERSION:
+       case VIRTIO_MMIO_DEVICE_ID:
+       case VIRTIO_MMIO_VENDOR_ID:
+       case VIRTIO_MMIO_STATUS:
+       case VIRTIO_MMIO_INTERRUPT_STATUS:
+               ioport__write32(data, *(u32 *)(((void *)&vmmio->hdr) + addr));
+               break;
+       case VIRTIO_MMIO_HOST_FEATURES:
+               if (vmmio->hdr.host_features_sel == 0)
+                       val = vdev->ops->get_host_features(vmmio->kvm,
+                                                          vmmio->dev);
+               ioport__write32(data, val);
+               break;
+       case VIRTIO_MMIO_QUEUE_PFN:
+               val = vdev->ops->get_pfn_vq(vmmio->kvm, vmmio->dev,
+                                           vmmio->hdr.queue_sel);
+               ioport__write32(data, val);
+               break;
+       case VIRTIO_MMIO_QUEUE_NUM_MAX:
+               val = vdev->ops->get_size_vq(vmmio->kvm, vmmio->dev,
+                                            vmmio->hdr.queue_sel);
+               ioport__write32(data, val);
+               break;
+       default:
+               break;
+       }
+}
+
+static void virtio_mmio_config_out(u64 addr, void *data, u32 len,
+                                  struct virtio_device *vdev)
+{
+       struct virtio_mmio *vmmio = vdev->virtio;
+       u32 val = 0;
+
+       switch (addr) {
+       case VIRTIO_MMIO_HOST_FEATURES_SEL:
+       case VIRTIO_MMIO_GUEST_FEATURES_SEL:
+       case VIRTIO_MMIO_QUEUE_SEL:
+       case VIRTIO_MMIO_STATUS:
+               val = ioport__read32(data);
+               *(u32 *)(((void *)&vmmio->hdr) + addr) = val;
+               break;
+       case VIRTIO_MMIO_GUEST_FEATURES:
+               if (vmmio->hdr.guest_features_sel == 0) {
+                       val = ioport__read32(data);
+                       vdev->ops->set_guest_features(vmmio->kvm,
+                                                     vmmio->dev, val);
+               }
+               break;
+       case VIRTIO_MMIO_GUEST_PAGE_SIZE:
+               val = ioport__read32(data);
+               vmmio->hdr.guest_page_size = val;
+               /* FIXME: set guest page size */
+               break;
+       case VIRTIO_MMIO_QUEUE_NUM:
+               val = ioport__read32(data);
+               vmmio->hdr.queue_num = val;
+               /* FIXME: set vq size */
+               vdev->ops->set_size_vq(vmmio->kvm, vmmio->dev,
+                                      vmmio->hdr.queue_sel, val);
+               break;
+       case VIRTIO_MMIO_QUEUE_ALIGN:
+               val = ioport__read32(data);
+               vmmio->hdr.queue_align = val;
+               /* FIXME: set used ring alignment */
+               break;
+       case VIRTIO_MMIO_QUEUE_PFN:
+               val = ioport__read32(data);
+               virtio_mmio_init_ioeventfd(vmmio->kvm, vdev, vmmio->hdr.queue_sel);
+               vdev->ops->init_vq(vmmio->kvm, vmmio->dev,
+                                  vmmio->hdr.queue_sel, val);
+               break;
+       case VIRTIO_MMIO_QUEUE_NOTIFY:
+               val = ioport__read32(data);
+               vdev->ops->notify_vq(vmmio->kvm, vmmio->dev, val);
+               break;
+       case VIRTIO_MMIO_INTERRUPT_ACK:
+               val = ioport__read32(data);
+               vmmio->hdr.interrupt_state &= ~val;
+               break;
+       default:
+               break;
+       };
+}
+
+static void virtio_mmio_mmio_callback(u64 addr, u8 *data, u32 len,
+                                     u8 is_write, void *ptr)
+{
+       struct virtio_device *vdev = ptr;
+       struct virtio_mmio *vmmio = vdev->virtio;
+       u32 offset = addr - vmmio->addr;
+
+       if (offset >= VIRTIO_MMIO_CONFIG) {
+               offset -= VIRTIO_MMIO_CONFIG;
+               virtio_mmio_device_specific(offset, data, len, is_write, ptr);
+               return;
+       }
+
+       if (is_write)
+               virtio_mmio_config_out(offset, data, len, ptr);
+       else
+               virtio_mmio_config_in(offset, data, len, ptr);
+}
+
+int virtio_mmio_init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
+                    int device_id, int subsys_id, int class)
+{
+       struct virtio_mmio *vmmio = vdev->virtio;
+       u8 device, pin, line;
+
+       vmmio->addr     = virtio_mmio_get_io_space_block(VIRTIO_MMIO_IO_SIZE);
+       vmmio->kvm      = kvm;
+       vmmio->dev      = dev;
+
+       kvm__register_mmio(kvm, vmmio->addr, VIRTIO_MMIO_IO_SIZE,
+                          false, virtio_mmio_mmio_callback, vdev);
+
+       vmmio->hdr = (struct virtio_mmio_hdr) {
+               .magic          = {'v', 'i', 'r', 't'},
+               .version        = 1,
+               .device_id      = device_id - 0x1000 + 1,
+               .vendor_id      = 0x4d564b4c , /* 'LKVM' */
+               .queue_num_max  = 256,
+       };
+
+       if (irq__register_device(subsys_id, &device, &pin, &line) < 0)
+               return -1;
+       vmmio->irq = line;
+
+       /*
+        * Instantiate guest virtio-mmio devices using kernel command line
+        * (or module) parameter, e.g
+        *
+        * virtio_mmio.devices=0x200@0xd2000000:5,0x200@0xd2000200:6
+        */
+       pr_info("virtio-mmio.devices=0x%x@0x%x:%d\n", VIRTIO_MMIO_IO_SIZE, vmmio->addr, line);
+
+       return 0;
+}
+
+int virtio_mmio_exit(struct kvm *kvm, struct virtio_device *vdev)
+{
+       struct virtio_mmio *vmmio = vdev->virtio;
+       int i;
+
+       kvm__deregister_mmio(kvm, vmmio->addr);
+
+       for (i = 0; i < VIRTIO_MMIO_MAX_VQ; i++)
+               ioeventfd__del_event(vmmio->addr + VIRTIO_MMIO_QUEUE_NOTIFY, i);
+
+       return 0;
+}
diff --git a/tools/kvm/virtio/net.c b/tools/kvm/virtio/net.c
new file mode 100644 (file)
index 0000000..10420ae
--- /dev/null
@@ -0,0 +1,555 @@
+#include "kvm/virtio-pci-dev.h"
+#include "kvm/virtio-net.h"
+#include "kvm/virtio.h"
+#include "kvm/types.h"
+#include "kvm/mutex.h"
+#include "kvm/util.h"
+#include "kvm/kvm.h"
+#include "kvm/irq.h"
+#include "kvm/uip.h"
+#include "kvm/guest_compat.h"
+
+#include <linux/vhost.h>
+#include <linux/virtio_net.h>
+#include <linux/if_tun.h>
+#include <linux/types.h>
+
+#include <arpa/inet.h>
+#include <net/if.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/eventfd.h>
+
+#define VIRTIO_NET_QUEUE_SIZE          256
+#define VIRTIO_NET_NUM_QUEUES          2
+#define VIRTIO_NET_RX_QUEUE            0
+#define VIRTIO_NET_TX_QUEUE            1
+
+struct net_dev;
+
+extern struct kvm *kvm;
+
+struct net_dev_operations {
+       int (*rx)(struct iovec *iov, u16 in, struct net_dev *ndev);
+       int (*tx)(struct iovec *iov, u16 in, struct net_dev *ndev);
+};
+
+struct net_dev {
+       pthread_mutex_t                 mutex;
+       struct virtio_device            vdev;
+       struct list_head                list;
+
+       struct virt_queue               vqs[VIRTIO_NET_NUM_QUEUES];
+       struct virtio_net_config        config;
+       u32                             features;
+
+       pthread_t                       io_rx_thread;
+       pthread_mutex_t                 io_rx_lock;
+       pthread_cond_t                  io_rx_cond;
+
+       pthread_t                       io_tx_thread;
+       pthread_mutex_t                 io_tx_lock;
+       pthread_cond_t                  io_tx_cond;
+
+       int                             vhost_fd;
+       int                             tap_fd;
+       char                            tap_name[IFNAMSIZ];
+
+       int                             mode;
+
+       struct uip_info                 info;
+       struct net_dev_operations       *ops;
+       struct kvm                      *kvm;
+};
+
+static LIST_HEAD(ndevs);
+static int compat_id = -1;
+
+static void *virtio_net_rx_thread(void *p)
+{
+       struct iovec iov[VIRTIO_NET_QUEUE_SIZE];
+       struct virt_queue *vq;
+       struct kvm *kvm;
+       struct net_dev *ndev = p;
+       u16 out, in;
+       u16 head;
+       int len;
+
+       kvm = ndev->kvm;
+       vq = &ndev->vqs[VIRTIO_NET_RX_QUEUE];
+
+       while (1) {
+               mutex_lock(&ndev->io_rx_lock);
+               if (!virt_queue__available(vq))
+                       pthread_cond_wait(&ndev->io_rx_cond, &ndev->io_rx_lock);
+               mutex_unlock(&ndev->io_rx_lock);
+
+               while (virt_queue__available(vq)) {
+                       head = virt_queue__get_iov(vq, iov, &out, &in, kvm);
+                       len = ndev->ops->rx(iov, in, ndev);
+                       virt_queue__set_used_elem(vq, head, len);
+
+                       /* We should interrupt guest right now, otherwise latency is huge. */
+                       if (virtio_queue__should_signal(&ndev->vqs[VIRTIO_NET_RX_QUEUE]))
+                               ndev->vdev.ops->signal_vq(kvm, &ndev->vdev,
+                                                          VIRTIO_NET_RX_QUEUE);
+               }
+       }
+
+       pthread_exit(NULL);
+       return NULL;
+
+}
+
+static void *virtio_net_tx_thread(void *p)
+{
+       struct iovec iov[VIRTIO_NET_QUEUE_SIZE];
+       struct virt_queue *vq;
+       struct kvm *kvm;
+       struct net_dev *ndev = p;
+       u16 out, in;
+       u16 head;
+       int len;
+
+       kvm = ndev->kvm;
+       vq = &ndev->vqs[VIRTIO_NET_TX_QUEUE];
+
+       while (1) {
+               mutex_lock(&ndev->io_tx_lock);
+               if (!virt_queue__available(vq))
+                       pthread_cond_wait(&ndev->io_tx_cond, &ndev->io_tx_lock);
+               mutex_unlock(&ndev->io_tx_lock);
+
+               while (virt_queue__available(vq)) {
+                       head = virt_queue__get_iov(vq, iov, &out, &in, kvm);
+                       len = ndev->ops->tx(iov, out, ndev);
+                       virt_queue__set_used_elem(vq, head, len);
+               }
+
+               if (virtio_queue__should_signal(&ndev->vqs[VIRTIO_NET_TX_QUEUE]))
+                       ndev->vdev.ops->signal_vq(kvm, &ndev->vdev, VIRTIO_NET_TX_QUEUE);
+       }
+
+       pthread_exit(NULL);
+
+       return NULL;
+
+}
+
+static void virtio_net_handle_callback(struct kvm *kvm, struct net_dev *ndev, int queue)
+{
+       switch (queue) {
+       case VIRTIO_NET_TX_QUEUE:
+               mutex_lock(&ndev->io_tx_lock);
+               pthread_cond_signal(&ndev->io_tx_cond);
+               mutex_unlock(&ndev->io_tx_lock);
+               break;
+       case VIRTIO_NET_RX_QUEUE:
+               mutex_lock(&ndev->io_rx_lock);
+               pthread_cond_signal(&ndev->io_rx_cond);
+               mutex_unlock(&ndev->io_rx_lock);
+               break;
+       default:
+               pr_warning("Unknown queue index %u", queue);
+       }
+}
+
+static bool virtio_net__tap_init(const struct virtio_net_params *params,
+                                       struct net_dev *ndev)
+{
+       int sock = socket(AF_INET, SOCK_STREAM, 0);
+       int pid, status, offload, hdr_len;
+       struct sockaddr_in sin = {0};
+       struct ifreq ifr;
+
+       /* Did the user already gave us the FD? */
+       if (params->fd) {
+               ndev->tap_fd = params->fd;
+               return 1;
+       }
+
+       ndev->tap_fd = open("/dev/net/tun", O_RDWR);
+       if (ndev->tap_fd < 0) {
+               pr_warning("Unable to open /dev/net/tun");
+               goto fail;
+       }
+
+       memset(&ifr, 0, sizeof(ifr));
+       ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR;
+       if (ioctl(ndev->tap_fd, TUNSETIFF, &ifr) < 0) {
+               pr_warning("Config tap device error. Are you root?");
+               goto fail;
+       }
+
+       strncpy(ndev->tap_name, ifr.ifr_name, sizeof(ndev->tap_name));
+
+       if (ioctl(ndev->tap_fd, TUNSETNOCSUM, 1) < 0) {
+               pr_warning("Config tap device TUNSETNOCSUM error");
+               goto fail;
+       }
+
+       hdr_len = sizeof(struct virtio_net_hdr);
+       if (ioctl(ndev->tap_fd, TUNSETVNETHDRSZ, &hdr_len) < 0)
+               pr_warning("Config tap device TUNSETVNETHDRSZ error");
+
+       offload = TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 | TUN_F_UFO;
+       if (ioctl(ndev->tap_fd, TUNSETOFFLOAD, offload) < 0) {
+               pr_warning("Config tap device TUNSETOFFLOAD error");
+               goto fail;
+       }
+
+       if (strcmp(params->script, "none")) {
+               pid = fork();
+               if (pid == 0) {
+                       execl(params->script, params->script, ndev->tap_name, NULL);
+                       _exit(1);
+               } else {
+                       waitpid(pid, &status, 0);
+                       if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
+                               pr_warning("Fail to setup tap by %s", params->script);
+                               goto fail;
+                       }
+               }
+       } else {
+               memset(&ifr, 0, sizeof(ifr));
+               strncpy(ifr.ifr_name, ndev->tap_name, sizeof(ndev->tap_name));
+               sin.sin_addr.s_addr = inet_addr(params->host_ip);
+               memcpy(&(ifr.ifr_addr), &sin, sizeof(ifr.ifr_addr));
+               ifr.ifr_addr.sa_family = AF_INET;
+               if (ioctl(sock, SIOCSIFADDR, &ifr) < 0) {
+                       pr_warning("Could not set ip address on tap device");
+                       goto fail;
+               }
+       }
+
+       memset(&ifr, 0, sizeof(ifr));
+       strncpy(ifr.ifr_name, ndev->tap_name, sizeof(ndev->tap_name));
+       ioctl(sock, SIOCGIFFLAGS, &ifr);
+       ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
+       if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0)
+               pr_warning("Could not bring tap device up");
+
+       close(sock);
+
+       return 1;
+
+fail:
+       if (sock >= 0)
+               close(sock);
+       if (ndev->tap_fd >= 0)
+               close(ndev->tap_fd);
+
+       return 0;
+}
+
+static void virtio_net__io_thread_init(struct kvm *kvm, struct net_dev *ndev)
+{
+       pthread_mutex_init(&ndev->io_tx_lock, NULL);
+       pthread_mutex_init(&ndev->io_rx_lock, NULL);
+
+       pthread_cond_init(&ndev->io_tx_cond, NULL);
+       pthread_cond_init(&ndev->io_rx_cond, NULL);
+
+       pthread_create(&ndev->io_tx_thread, NULL, virtio_net_tx_thread, ndev);
+       pthread_create(&ndev->io_rx_thread, NULL, virtio_net_rx_thread, ndev);
+}
+
+static inline int tap_ops_tx(struct iovec *iov, u16 out, struct net_dev *ndev)
+{
+       return writev(ndev->tap_fd, iov, out);
+}
+
+static inline int tap_ops_rx(struct iovec *iov, u16 in, struct net_dev *ndev)
+{
+       return readv(ndev->tap_fd, iov, in);
+}
+
+static inline int uip_ops_tx(struct iovec *iov, u16 out, struct net_dev *ndev)
+{
+       return uip_tx(iov, out, &ndev->info);
+}
+
+static inline int uip_ops_rx(struct iovec *iov, u16 in, struct net_dev *ndev)
+{
+       return uip_rx(iov, in, &ndev->info);
+}
+
+static struct net_dev_operations tap_ops = {
+       .rx     = tap_ops_rx,
+       .tx     = tap_ops_tx,
+};
+
+static struct net_dev_operations uip_ops = {
+       .rx     = uip_ops_rx,
+       .tx     = uip_ops_tx,
+};
+
+static void set_config(struct kvm *kvm, void *dev, u8 data, u32 offset)
+{
+       struct net_dev *ndev = dev;
+
+       ((u8 *)(&ndev->config))[offset] = data;
+}
+
+static u8 get_config(struct kvm *kvm, void *dev, u32 offset)
+{
+       struct net_dev *ndev = dev;
+
+       return ((u8 *)(&ndev->config))[offset];
+}
+
+static u32 get_host_features(struct kvm *kvm, void *dev)
+{
+       return 1UL << VIRTIO_NET_F_MAC
+               | 1UL << VIRTIO_NET_F_CSUM
+               | 1UL << VIRTIO_NET_F_HOST_UFO
+               | 1UL << VIRTIO_NET_F_HOST_TSO4
+               | 1UL << VIRTIO_NET_F_HOST_TSO6
+               | 1UL << VIRTIO_NET_F_GUEST_UFO
+               | 1UL << VIRTIO_NET_F_GUEST_TSO4
+               | 1UL << VIRTIO_NET_F_GUEST_TSO6
+               | 1UL << VIRTIO_RING_F_EVENT_IDX
+               | 1UL << VIRTIO_RING_F_INDIRECT_DESC;
+}
+
+static void set_guest_features(struct kvm *kvm, void *dev, u32 features)
+{
+       struct net_dev *ndev = dev;
+
+       ndev->features = features;
+}
+
+static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 pfn)
+{
+       struct vhost_vring_state state = { .index = vq };
+       struct vhost_vring_addr addr;
+       struct net_dev *ndev = dev;
+       struct virt_queue *queue;
+       void *p;
+       int r;
+
+       compat__remove_message(compat_id);
+
+       queue           = &ndev->vqs[vq];
+       queue->pfn      = pfn;
+       p               = guest_pfn_to_host(kvm, queue->pfn);
+
+       /* FIXME: respect pci and mmio vring alignment */
+       vring_init(&queue->vring, VIRTIO_NET_QUEUE_SIZE, p, VIRTIO_PCI_VRING_ALIGN);
+
+       if (ndev->vhost_fd == 0)
+               return 0;
+
+       state.num = queue->vring.num;
+       r = ioctl(ndev->vhost_fd, VHOST_SET_VRING_NUM, &state);
+       if (r < 0)
+               die_perror("VHOST_SET_VRING_NUM failed");
+       state.num = 0;
+       r = ioctl(ndev->vhost_fd, VHOST_SET_VRING_BASE, &state);
+       if (r < 0)
+               die_perror("VHOST_SET_VRING_BASE failed");
+
+       addr = (struct vhost_vring_addr) {
+               .index = vq,
+               .desc_user_addr = (u64)(unsigned long)queue->vring.desc,
+               .avail_user_addr = (u64)(unsigned long)queue->vring.avail,
+               .used_user_addr = (u64)(unsigned long)queue->vring.used,
+       };
+
+       r = ioctl(ndev->vhost_fd, VHOST_SET_VRING_ADDR, &addr);
+       if (r < 0)
+               die_perror("VHOST_SET_VRING_ADDR failed");
+
+       return 0;
+}
+
+static void notify_vq_gsi(struct kvm *kvm, void *dev, u32 vq, u32 gsi)
+{
+       struct net_dev *ndev = dev;
+       struct kvm_irqfd irq;
+       struct vhost_vring_file file;
+       int r;
+
+       if (ndev->vhost_fd == 0)
+               return;
+
+       irq = (struct kvm_irqfd) {
+               .gsi    = gsi,
+               .fd     = eventfd(0, 0),
+       };
+       file = (struct vhost_vring_file) {
+               .index  = vq,
+               .fd     = irq.fd,
+       };
+
+       r = ioctl(kvm->vm_fd, KVM_IRQFD, &irq);
+       if (r < 0)
+               die_perror("KVM_IRQFD failed");
+
+       r = ioctl(ndev->vhost_fd, VHOST_SET_VRING_CALL, &file);
+       if (r < 0)
+               die_perror("VHOST_SET_VRING_CALL failed");
+       file.fd = ndev->tap_fd;
+       r = ioctl(ndev->vhost_fd, VHOST_NET_SET_BACKEND, &file);
+       if (r != 0)
+               die("VHOST_NET_SET_BACKEND failed %d", errno);
+
+}
+
+static void notify_vq_eventfd(struct kvm *kvm, void *dev, u32 vq, u32 efd)
+{
+       struct net_dev *ndev = dev;
+       struct vhost_vring_file file = {
+               .index  = vq,
+               .fd     = efd,
+       };
+       int r;
+
+       if (ndev->vhost_fd == 0)
+               return;
+
+       r = ioctl(ndev->vhost_fd, VHOST_SET_VRING_KICK, &file);
+       if (r < 0)
+               die_perror("VHOST_SET_VRING_KICK failed");
+}
+
+static int notify_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+       struct net_dev *ndev = dev;
+
+       virtio_net_handle_callback(kvm, ndev, vq);
+
+       return 0;
+}
+
+static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+       struct net_dev *ndev = dev;
+
+       return ndev->vqs[vq].pfn;
+}
+
+static int get_size_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+       /* FIXME: dynamic */
+       return VIRTIO_NET_QUEUE_SIZE;
+}
+
+static int set_size_vq(struct kvm *kvm, void *dev, u32 vq, int size)
+{
+       /* FIXME: dynamic */
+       return size;
+}
+
+static struct virtio_ops net_dev_virtio_ops = (struct virtio_ops) {
+       .set_config             = set_config,
+       .get_config             = get_config,
+       .get_host_features      = get_host_features,
+       .set_guest_features     = set_guest_features,
+       .init_vq                = init_vq,
+       .get_pfn_vq             = get_pfn_vq,
+       .get_size_vq            = get_size_vq,
+       .set_size_vq            = set_size_vq,
+       .notify_vq              = notify_vq,
+       .notify_vq_gsi          = notify_vq_gsi,
+       .notify_vq_eventfd      = notify_vq_eventfd,
+};
+
+static void virtio_net__vhost_init(struct kvm *kvm, struct net_dev *ndev)
+{
+       u64 features = 1UL << VIRTIO_RING_F_EVENT_IDX;
+       struct vhost_memory *mem;
+       int r;
+
+       ndev->vhost_fd = open("/dev/vhost-net", O_RDWR);
+       if (ndev->vhost_fd < 0)
+               die_perror("Failed openning vhost-net device");
+
+       mem = calloc(1, sizeof(*mem) + sizeof(struct vhost_memory_region));
+       if (mem == NULL)
+               die("Failed allocating memory for vhost memory map");
+
+       mem->nregions = 1;
+       mem->regions[0] = (struct vhost_memory_region) {
+               .guest_phys_addr        = 0,
+               .memory_size            = kvm->ram_size,
+               .userspace_addr         = (unsigned long)kvm->ram_start,
+       };
+
+       r = ioctl(ndev->vhost_fd, VHOST_SET_OWNER);
+       if (r != 0)
+               die_perror("VHOST_SET_OWNER failed");
+
+       r = ioctl(ndev->vhost_fd, VHOST_SET_FEATURES, &features);
+       if (r != 0)
+               die_perror("VHOST_SET_FEATURES failed");
+       r = ioctl(ndev->vhost_fd, VHOST_SET_MEM_TABLE, mem);
+       if (r != 0)
+               die_perror("VHOST_SET_MEM_TABLE failed");
+
+       ndev->vdev.use_vhost = true;
+
+       free(mem);
+}
+
+void virtio_net__init(const struct virtio_net_params *params)
+{
+       int i;
+       struct net_dev *ndev;
+
+       if (!params)
+               return;
+
+       ndev = calloc(1, sizeof(struct net_dev));
+       if (ndev == NULL)
+               die("Failed allocating ndev");
+
+       list_add_tail(&ndev->list, &ndevs);
+
+       ndev->kvm = params->kvm;
+
+       mutex_init(&ndev->mutex);
+       ndev->config.status = VIRTIO_NET_S_LINK_UP;
+
+       for (i = 0 ; i < 6 ; i++) {
+               ndev->config.mac[i]             = params->guest_mac[i];
+               ndev->info.guest_mac.addr[i]    = params->guest_mac[i];
+               ndev->info.host_mac.addr[i]     = params->host_mac[i];
+       }
+
+       ndev->mode = params->mode;
+       if (ndev->mode == NET_MODE_TAP) {
+               if (!virtio_net__tap_init(params, ndev))
+                       die_perror("You have requested a TAP device, but creation of one has"
+                                       "failed because:");
+               ndev->ops = &tap_ops;
+       } else {
+               ndev->info.host_ip              = ntohl(inet_addr(params->host_ip));
+               ndev->info.guest_ip             = ntohl(inet_addr(params->guest_ip));
+               ndev->info.guest_netmask        = ntohl(inet_addr("255.255.255.0"));
+               ndev->info.buf_nr               = 20,
+               uip_init(&ndev->info);
+               ndev->ops = &uip_ops;
+       }
+
+       if (params->trans && strcmp(params->trans, "mmio") == 0)
+               virtio_init(kvm, ndev, &ndev->vdev, &net_dev_virtio_ops,
+                           VIRTIO_MMIO, PCI_DEVICE_ID_VIRTIO_NET, VIRTIO_ID_NET, PCI_CLASS_NET);
+       else
+               virtio_init(kvm, ndev, &ndev->vdev, &net_dev_virtio_ops,
+                           VIRTIO_PCI, PCI_DEVICE_ID_VIRTIO_NET, VIRTIO_ID_NET, PCI_CLASS_NET);
+
+       if (params->vhost)
+               virtio_net__vhost_init(params->kvm, ndev);
+       else
+               virtio_net__io_thread_init(params->kvm, ndev);
+
+       if (compat_id == -1)
+               compat_id = virtio_compat_add_message("virtio-net", "CONFIG_VIRTIO_NET");
+}
diff --git a/tools/kvm/virtio/pci.c b/tools/kvm/virtio/pci.c
new file mode 100644 (file)
index 0000000..f17cd8a
--- /dev/null
@@ -0,0 +1,377 @@
+#include "kvm/virtio-pci.h"
+
+#include "kvm/ioport.h"
+#include "kvm/kvm.h"
+#include "kvm/virtio-pci-dev.h"
+#include "kvm/irq.h"
+#include "kvm/virtio.h"
+#include "kvm/ioeventfd.h"
+
+#include <linux/virtio_pci.h>
+#include <linux/byteorder.h>
+#include <string.h>
+
+static void virtio_pci__ioevent_callback(struct kvm *kvm, void *param)
+{
+       struct virtio_pci_ioevent_param *ioeventfd = param;
+       struct virtio_pci *vpci = ioeventfd->vdev->virtio;
+
+       ioeventfd->vdev->ops->notify_vq(kvm, vpci->dev, ioeventfd->vq);
+}
+
+static int virtio_pci__init_ioeventfd(struct kvm *kvm, struct virtio_device *vdev, u32 vq)
+{
+       struct ioevent ioevent;
+       struct virtio_pci *vpci = vdev->virtio;
+       int r;
+
+       vpci->ioeventfds[vq] = (struct virtio_pci_ioevent_param) {
+               .vdev           = vdev,
+               .vq             = vq,
+       };
+
+       ioevent = (struct ioevent) {
+               .io_addr        = vpci->base_addr + VIRTIO_PCI_QUEUE_NOTIFY,
+               .io_len         = sizeof(u16),
+               .fn             = virtio_pci__ioevent_callback,
+               .fn_ptr         = &vpci->ioeventfds[vq],
+               .datamatch      = vq,
+               .fn_kvm         = kvm,
+               .fd             = eventfd(0, 0),
+       };
+
+       if (vdev->use_vhost)
+               /*
+                * Vhost will poll the eventfd in host kernel side,
+                * no need to poll in userspace.
+                */
+               r = ioeventfd__add_event(&ioevent, true, false);
+       else
+               /* Need to poll in userspace. */
+               r = ioeventfd__add_event(&ioevent, true, true);
+       if (r)
+               return r;
+
+       if (vdev->ops->notify_vq_eventfd)
+               vdev->ops->notify_vq_eventfd(kvm, vpci->dev, vq, ioevent.fd);
+
+       return 0;
+}
+
+static inline bool virtio_pci__msix_enabled(struct virtio_pci *vpci)
+{
+       return vpci->pci_hdr.msix.ctrl & cpu_to_le16(PCI_MSIX_FLAGS_ENABLE);
+}
+
+static bool virtio_pci__specific_io_in(struct kvm *kvm, struct virtio_device *vdev, u16 port,
+                                       void *data, int size, int offset)
+{
+       u32 config_offset;
+       struct virtio_pci *vpci = vdev->virtio;
+       int type = virtio__get_dev_specific_field(offset - 20,
+                                                       virtio_pci__msix_enabled(vpci),
+                                                       &config_offset);
+       if (type == VIRTIO_PCI_O_MSIX) {
+               switch (offset) {
+               case VIRTIO_MSI_CONFIG_VECTOR:
+                       ioport__write16(data, vpci->config_vector);
+                       break;
+               case VIRTIO_MSI_QUEUE_VECTOR:
+                       ioport__write16(data, vpci->vq_vector[vpci->queue_selector]);
+                       break;
+               };
+
+               return true;
+       } else if (type == VIRTIO_PCI_O_CONFIG) {
+               u8 cfg;
+
+               cfg = vdev->ops->get_config(kvm, vpci->dev, config_offset);
+               ioport__write8(data, cfg);
+               return true;
+       }
+
+       return false;
+}
+
+static bool virtio_pci__io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+       unsigned long offset;
+       bool ret = true;
+       struct virtio_device *vdev;
+       struct virtio_pci *vpci;
+       u32 val;
+
+       vdev = ioport->priv;
+       vpci = vdev->virtio;
+       offset = port - vpci->base_addr;
+
+       switch (offset) {
+       case VIRTIO_PCI_HOST_FEATURES:
+               val = vdev->ops->get_host_features(kvm, vpci->dev);
+               ioport__write32(data, val);
+               break;
+       case VIRTIO_PCI_QUEUE_PFN:
+               val = vdev->ops->get_pfn_vq(kvm, vpci->dev, vpci->queue_selector);
+               ioport__write32(data, val);
+               break;
+       case VIRTIO_PCI_QUEUE_NUM:
+               val = vdev->ops->get_size_vq(kvm, vpci->dev, vpci->queue_selector);
+               ioport__write16(data, val);
+               break;
+       case VIRTIO_PCI_STATUS:
+               ioport__write8(data, vpci->status);
+               break;
+       case VIRTIO_PCI_ISR:
+               ioport__write8(data, vpci->isr);
+               kvm__irq_line(kvm, vpci->pci_hdr.irq_line, VIRTIO_IRQ_LOW);
+               vpci->isr = VIRTIO_IRQ_LOW;
+               break;
+       default:
+               ret = virtio_pci__specific_io_in(kvm, vdev, port, data, size, offset);
+               break;
+       };
+
+       return ret;
+}
+
+static bool virtio_pci__specific_io_out(struct kvm *kvm, struct virtio_device *vdev, u16 port,
+                                       void *data, int size, int offset)
+{
+       struct virtio_pci *vpci = vdev->virtio;
+       u32 config_offset, gsi, vec;
+       int type = virtio__get_dev_specific_field(offset - 20, virtio_pci__msix_enabled(vpci),
+                                                       &config_offset);
+       if (type == VIRTIO_PCI_O_MSIX) {
+               switch (offset) {
+               case VIRTIO_MSI_CONFIG_VECTOR:
+                       vec = vpci->config_vector = ioport__read16(data);
+
+                       gsi = irq__add_msix_route(kvm, &vpci->msix_table[vec].msg);
+
+                       vpci->config_gsi = gsi;
+                       break;
+               case VIRTIO_MSI_QUEUE_VECTOR:
+                       vec = vpci->vq_vector[vpci->queue_selector] = ioport__read16(data);
+
+                       gsi = irq__add_msix_route(kvm, &vpci->msix_table[vec].msg);
+                       vpci->gsis[vpci->queue_selector] = gsi;
+                       if (vdev->ops->notify_vq_gsi)
+                               vdev->ops->notify_vq_gsi(kvm, vpci->dev,
+                                                       vpci->queue_selector, gsi);
+                       break;
+               };
+
+               return true;
+       } else if (type == VIRTIO_PCI_O_CONFIG) {
+               vdev->ops->set_config(kvm, vpci->dev, *(u8 *)data, config_offset);
+
+               return true;
+       }
+
+       return false;
+}
+
+static bool virtio_pci__io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+       unsigned long offset;
+       bool ret = true;
+       struct virtio_device *vdev;
+       struct virtio_pci *vpci;
+       u32 val;
+
+       vdev = ioport->priv;
+       vpci = vdev->virtio;
+       offset = port - vpci->base_addr;
+
+       switch (offset) {
+       case VIRTIO_PCI_GUEST_FEATURES:
+               val = ioport__read32(data);
+               vdev->ops->set_guest_features(kvm, vpci->dev, val);
+               break;
+       case VIRTIO_PCI_QUEUE_PFN:
+               val = ioport__read32(data);
+               virtio_pci__init_ioeventfd(kvm, vdev, vpci->queue_selector);
+               vdev->ops->init_vq(kvm, vpci->dev, vpci->queue_selector, val);
+               break;
+       case VIRTIO_PCI_QUEUE_SEL:
+               vpci->queue_selector = ioport__read16(data);
+               break;
+       case VIRTIO_PCI_QUEUE_NOTIFY:
+               val = ioport__read16(data);
+               vdev->ops->notify_vq(kvm, vpci->dev, val);
+               break;
+       case VIRTIO_PCI_STATUS:
+               vpci->status = ioport__read8(data);
+               break;
+       default:
+               ret = virtio_pci__specific_io_out(kvm, vdev, port, data, size, offset);
+               break;
+       };
+
+       return ret;
+}
+
+static struct ioport_operations virtio_pci__io_ops = {
+       .io_in  = virtio_pci__io_in,
+       .io_out = virtio_pci__io_out,
+};
+
+static void virtio_pci__mmio_callback(u64 addr, u8 *data, u32 len, u8 is_write, void *ptr)
+{
+       struct virtio_pci *vpci = ptr;
+       void *table;
+       u32 offset;
+
+       if (addr > vpci->msix_io_block + PCI_IO_SIZE) {
+               table   = &vpci->msix_pba;
+               offset  = vpci->msix_io_block + PCI_IO_SIZE;
+       } else {
+               table   = &vpci->msix_table;
+               offset  = vpci->msix_io_block;
+       }
+
+       if (is_write)
+               memcpy(table + addr - offset, data, len);
+       else
+               memcpy(data, table + addr - offset, len);
+}
+
+int virtio_pci__signal_vq(struct kvm *kvm, struct virtio_device *vdev, u32 vq)
+{
+       struct virtio_pci *vpci = vdev->virtio;
+       int tbl = vpci->vq_vector[vq];
+
+       if (virtio_pci__msix_enabled(vpci)) {
+               if (vpci->pci_hdr.msix.ctrl & cpu_to_le16(PCI_MSIX_FLAGS_MASKALL) ||
+                   vpci->msix_table[tbl].ctrl & cpu_to_le16(PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
+
+                       vpci->msix_pba |= 1 << tbl;
+                       return 0;
+               }
+
+               kvm__irq_trigger(kvm, vpci->gsis[vq]);
+       } else {
+               vpci->isr = VIRTIO_IRQ_HIGH;
+               kvm__irq_trigger(kvm, vpci->pci_hdr.irq_line);
+       }
+       return 0;
+}
+
+int virtio_pci__signal_config(struct kvm *kvm, struct virtio_device *vdev)
+{
+       struct virtio_pci *vpci = vdev->virtio;
+       int tbl = vpci->config_vector;
+
+       if (virtio_pci__msix_enabled(vpci)) {
+               if (vpci->pci_hdr.msix.ctrl & cpu_to_le16(PCI_MSIX_FLAGS_MASKALL) ||
+                   vpci->msix_table[tbl].ctrl & cpu_to_le16(PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
+
+                       vpci->msix_pba |= 1 << tbl;
+                       return 0;
+               }
+
+               kvm__irq_trigger(kvm, vpci->config_gsi);
+       } else {
+               vpci->isr = VIRTIO_PCI_ISR_CONFIG;
+               kvm__irq_trigger(kvm, vpci->pci_hdr.irq_line);
+       }
+
+       return 0;
+}
+
+int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
+                    int device_id, int subsys_id, int class)
+{
+       struct virtio_pci *vpci = vdev->virtio;
+       u8 pin, line, ndev;
+       int r;
+
+       vpci->dev = dev;
+       vpci->msix_io_block = pci_get_io_space_block(PCI_IO_SIZE * 2);
+
+       r = ioport__register(IOPORT_EMPTY, &virtio_pci__io_ops, IOPORT_SIZE, vdev);
+       if (r < 0)
+               return r;
+
+       vpci->base_addr = (u16)r;
+       r = kvm__register_mmio(kvm, vpci->msix_io_block, PCI_IO_SIZE, false,
+                              virtio_pci__mmio_callback, vpci);
+       if (r < 0)
+               goto free_ioport;
+
+       vpci->pci_hdr = (struct pci_device_header) {
+               .vendor_id              = cpu_to_le16(PCI_VENDOR_ID_REDHAT_QUMRANET),
+               .device_id              = cpu_to_le16(device_id),
+               .header_type            = PCI_HEADER_TYPE_NORMAL,
+               .revision_id            = 0,
+               .class[0]               = class & 0xff,
+               .class[1]               = (class >> 8) & 0xff,
+               .class[2]               = (class >> 16) & 0xff,
+               .subsys_vendor_id       = cpu_to_le16(PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET),
+               .subsys_id              = cpu_to_le16(subsys_id),
+               .bar[0]                 = cpu_to_le32(vpci->base_addr
+                                                       | PCI_BASE_ADDRESS_SPACE_IO),
+               .bar[1]                 = cpu_to_le32(vpci->msix_io_block
+                                                       | PCI_BASE_ADDRESS_SPACE_MEMORY),
+               .status                 = cpu_to_le16(PCI_STATUS_CAP_LIST),
+               .capabilities           = (void *)&vpci->pci_hdr.msix - (void *)&vpci->pci_hdr,
+               .bar_size[0]            = IOPORT_SIZE,
+               .bar_size[1]            = PCI_IO_SIZE,
+               .bar_size[3]            = PCI_IO_SIZE,
+       };
+
+       vpci->pci_hdr.msix.cap = PCI_CAP_ID_MSIX;
+       vpci->pci_hdr.msix.next = 0;
+       /*
+        * We at most have VIRTIO_PCI_MAX_VQ entries for virt queue,
+        * VIRTIO_PCI_MAX_CONFIG entries for config.
+        *
+        * To quote the PCI spec:
+        *
+        * System software reads this field to determine the
+        * MSI-X Table Size N, which is encoded as N-1.
+        * For example, a returned value of "00000000011"
+        * indicates a table size of 4.
+        */
+       vpci->pci_hdr.msix.ctrl = cpu_to_le16(VIRTIO_PCI_MAX_VQ + VIRTIO_PCI_MAX_CONFIG - 1);
+
+       /*
+        * Both table and PBA could be mapped on the same BAR, but for now
+        * we're not in short of BARs
+        */
+       vpci->pci_hdr.msix.table_offset = cpu_to_le32(1); /* Use BAR 1 */
+       vpci->pci_hdr.msix.pba_offset = cpu_to_le32(1 | PCI_IO_SIZE); /* Use BAR 3 */
+       vpci->config_vector = 0;
+
+       r = irq__register_device(subsys_id, &ndev, &pin, &line);
+       if (r < 0)
+               goto free_mmio;
+
+       vpci->pci_hdr.irq_pin   = pin;
+       vpci->pci_hdr.irq_line  = line;
+       r = pci__register(&vpci->pci_hdr, ndev);
+       if (r < 0)
+               goto free_ioport;
+
+       return 0;
+
+free_mmio:
+       kvm__deregister_mmio(kvm, vpci->msix_io_block);
+free_ioport:
+       ioport__unregister(vpci->base_addr);
+       return r;
+}
+
+int virtio_pci__exit(struct kvm *kvm, struct virtio_device *vdev)
+{
+       struct virtio_pci *vpci = vdev->virtio;
+       int i;
+
+       kvm__deregister_mmio(kvm, vpci->msix_io_block);
+       ioport__unregister(vpci->base_addr);
+
+       for (i = 0; i < VIRTIO_PCI_MAX_VQ; i++)
+               ioeventfd__del_event(vpci->base_addr + VIRTIO_PCI_QUEUE_NOTIFY, i);
+
+       return 0;
+}
diff --git a/tools/kvm/virtio/rng.c b/tools/kvm/virtio/rng.c
new file mode 100644 (file)
index 0000000..5aa632d
--- /dev/null
@@ -0,0 +1,194 @@
+#include "kvm/virtio-rng.h"
+
+#include "kvm/virtio-pci-dev.h"
+
+#include "kvm/virtio.h"
+#include "kvm/util.h"
+#include "kvm/kvm.h"
+#include "kvm/threadpool.h"
+#include "kvm/guest_compat.h"
+
+#include <linux/virtio_ring.h>
+#include <linux/virtio_rng.h>
+
+#include <linux/list.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <pthread.h>
+#include <linux/kernel.h>
+
+#define NUM_VIRT_QUEUES                1
+#define VIRTIO_RNG_QUEUE_SIZE  128
+
+struct rng_dev_job {
+       struct virt_queue       *vq;
+       struct rng_dev          *rdev;
+       struct thread_pool__job job_id;
+};
+
+struct rng_dev {
+       struct list_head        list;
+       struct virtio_device    vdev;
+
+       int                     fd;
+
+       /* virtio queue */
+       struct virt_queue       vqs[NUM_VIRT_QUEUES];
+       struct rng_dev_job      jobs[NUM_VIRT_QUEUES];
+};
+
+static LIST_HEAD(rdevs);
+static int compat_id = -1;
+
+static void set_config(struct kvm *kvm, void *dev, u8 data, u32 offset)
+{
+       /* Unused */
+}
+
+static u8 get_config(struct kvm *kvm, void *dev, u32 offset)
+{
+       /* Unused */
+       return 0;
+}
+
+static u32 get_host_features(struct kvm *kvm, void *dev)
+{
+       /* Unused */
+       return 0;
+}
+
+static void set_guest_features(struct kvm *kvm, void *dev, u32 features)
+{
+       /* Unused */
+}
+
+static bool virtio_rng_do_io_request(struct kvm *kvm, struct rng_dev *rdev, struct virt_queue *queue)
+{
+       struct iovec iov[VIRTIO_RNG_QUEUE_SIZE];
+       unsigned int len = 0;
+       u16 out, in, head;
+
+       head    = virt_queue__get_iov(queue, iov, &out, &in, kvm);
+       len     = readv(rdev->fd, iov, in);
+
+       virt_queue__set_used_elem(queue, head, len);
+
+       return true;
+}
+
+static void virtio_rng_do_io(struct kvm *kvm, void *param)
+{
+       struct rng_dev_job *job = param;
+       struct virt_queue *vq   = job->vq;
+       struct rng_dev *rdev    = job->rdev;
+
+       while (virt_queue__available(vq))
+               virtio_rng_do_io_request(kvm, rdev, vq);
+
+       rdev->vdev.ops->signal_vq(kvm, &rdev->vdev, vq - rdev->vqs);
+}
+
+static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 pfn)
+{
+       struct rng_dev *rdev = dev;
+       struct virt_queue *queue;
+       struct rng_dev_job *job;
+       void *p;
+
+       compat__remove_message(compat_id);
+
+       queue           = &rdev->vqs[vq];
+       queue->pfn      = pfn;
+       p               = guest_pfn_to_host(kvm, queue->pfn);
+
+       job = &rdev->jobs[vq];
+
+       vring_init(&queue->vring, VIRTIO_RNG_QUEUE_SIZE, p, VIRTIO_PCI_VRING_ALIGN);
+
+       *job = (struct rng_dev_job) {
+               .vq     = queue,
+               .rdev   = rdev,
+       };
+
+       thread_pool__init_job(&job->job_id, kvm, virtio_rng_do_io, job);
+
+       return 0;
+}
+
+static int notify_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+       struct rng_dev *rdev = dev;
+
+       thread_pool__do_job(&rdev->jobs[vq].job_id);
+
+       return 0;
+}
+
+static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+       struct rng_dev *rdev = dev;
+
+       return rdev->vqs[vq].pfn;
+}
+
+static int get_size_vq(struct kvm *kvm, void *dev, u32 vq)
+{
+       return VIRTIO_RNG_QUEUE_SIZE;
+}
+
+static struct virtio_ops rng_dev_virtio_ops = (struct virtio_ops) {
+       .set_config             = set_config,
+       .get_config             = get_config,
+       .get_host_features      = get_host_features,
+       .set_guest_features     = set_guest_features,
+       .init_vq                = init_vq,
+       .notify_vq              = notify_vq,
+       .get_pfn_vq             = get_pfn_vq,
+       .get_size_vq            = get_size_vq,
+};
+
+int virtio_rng__init(struct kvm *kvm)
+{
+       struct rng_dev *rdev;
+       int r;
+
+       rdev = malloc(sizeof(*rdev));
+       if (rdev == NULL)
+               return -ENOMEM;
+
+       rdev->fd = open("/dev/urandom", O_RDONLY);
+       if (rdev->fd < 0) {
+               r = rdev->fd;
+               goto cleanup;
+       }
+
+       r = virtio_init(kvm, rdev, &rdev->vdev, &rng_dev_virtio_ops,
+                       VIRTIO_PCI, PCI_DEVICE_ID_VIRTIO_RNG, VIRTIO_ID_RNG, PCI_CLASS_RNG);
+       if (r < 0)
+               goto cleanup;
+
+       list_add_tail(&rdev->list, &rdevs);
+
+       if (compat_id == -1)
+               compat_id = virtio_compat_add_message("virtio-rng", "CONFIG_HW_RANDOM_VIRTIO");
+       return 0;
+cleanup:
+       close(rdev->fd);
+       free(rdev);
+
+       return r;
+}
+
+int virtio_rng__exit(struct kvm *kvm)
+{
+       struct rng_dev *rdev, *tmp;
+
+       list_for_each_entry_safe(rdev, tmp, &rdevs, list) {
+               list_del(&rdev->list);
+               rdev->vdev.ops->exit(kvm, &rdev->vdev);
+               free(rdev);
+       }
+
+       return 0;
+}
diff --git a/tools/kvm/x86/bios.c b/tools/kvm/x86/bios.c
new file mode 100644 (file)
index 0000000..0f1bd85
--- /dev/null
@@ -0,0 +1,174 @@
+#include "kvm/kvm.h"
+#include "kvm/boot-protocol.h"
+#include "kvm/e820.h"
+#include "kvm/interrupt.h"
+#include "kvm/util.h"
+
+#include <string.h>
+#include <asm/e820.h>
+
+#include "bios/bios-rom.h"
+
+struct irq_handler {
+       unsigned long           address;
+       unsigned int            irq;
+       void                    *handler;
+       size_t                  size;
+};
+
+#define BIOS_IRQ_PA_ADDR(name) (MB_BIOS_BEGIN + BIOS_OFFSET__##name)
+#define BIOS_IRQ_FUNC(name)    ((char *)&bios_rom[BIOS_OFFSET__##name])
+#define BIOS_IRQ_SIZE(name)    (BIOS_ENTRY_SIZE(BIOS_OFFSET__##name))
+
+#define DEFINE_BIOS_IRQ_HANDLER(_irq, _handler)                        \
+       {                                                       \
+               .irq            = _irq,                         \
+               .address        = BIOS_IRQ_PA_ADDR(_handler),   \
+               .handler        = BIOS_IRQ_FUNC(_handler),      \
+               .size           = BIOS_IRQ_SIZE(_handler),      \
+       }
+
+static struct irq_handler bios_irq_handlers[] = {
+       DEFINE_BIOS_IRQ_HANDLER(0x10, bios_int10),
+       DEFINE_BIOS_IRQ_HANDLER(0x15, bios_int15),
+};
+
+static void setup_irq_handler(struct kvm *kvm, struct irq_handler *handler)
+{
+       struct real_intr_desc intr_desc;
+       void *p;
+
+       p = guest_flat_to_host(kvm, handler->address);
+       memcpy(p, handler->handler, handler->size);
+
+       intr_desc = (struct real_intr_desc) {
+               .segment        = REAL_SEGMENT(MB_BIOS_BEGIN),
+               .offset         = handler->address - MB_BIOS_BEGIN,
+       };
+
+       DIE_IF((handler->address - MB_BIOS_BEGIN) > 0xffffUL);
+
+       interrupt_table__set(&kvm->interrupt_table, &intr_desc, handler->irq);
+}
+
+/**
+ * e820_setup - setup some simple E820 memory map
+ * @kvm - guest system descriptor
+ */
+static void e820_setup(struct kvm *kvm)
+{
+       struct e820map *e820;
+       struct e820entry *mem_map;
+       unsigned int i = 0;
+
+       e820            = guest_flat_to_host(kvm, E820_MAP_START);
+       mem_map         = e820->map;
+
+       mem_map[i++]    = (struct e820entry) {
+               .addr           = REAL_MODE_IVT_BEGIN,
+               .size           = EBDA_START - REAL_MODE_IVT_BEGIN,
+               .type           = E820_RAM,
+       };
+       mem_map[i++]    = (struct e820entry) {
+               .addr           = EBDA_START,
+               .size           = VGA_RAM_BEGIN - EBDA_START,
+               .type           = E820_RESERVED,
+       };
+       mem_map[i++]    = (struct e820entry) {
+               .addr           = MB_BIOS_BEGIN,
+               .size           = MB_BIOS_END - MB_BIOS_BEGIN,
+               .type           = E820_RESERVED,
+       };
+       if (kvm->ram_size < KVM_32BIT_GAP_START) {
+               mem_map[i++]    = (struct e820entry) {
+                       .addr           = BZ_KERNEL_START,
+                       .size           = kvm->ram_size - BZ_KERNEL_START,
+                       .type           = E820_RAM,
+               };
+       } else {
+               mem_map[i++]    = (struct e820entry) {
+                       .addr           = BZ_KERNEL_START,
+                       .size           = KVM_32BIT_GAP_START - BZ_KERNEL_START,
+                       .type           = E820_RAM,
+               };
+               mem_map[i++]    = (struct e820entry) {
+                       .addr           = KVM_32BIT_MAX_MEM_SIZE,
+                       .size           = kvm->ram_size - KVM_32BIT_MAX_MEM_SIZE,
+                       .type           = E820_RAM,
+               };
+       }
+
+       BUG_ON(i > E820_X_MAX);
+
+       e820->nr_map = i;
+}
+
+static void setup_vga_rom(struct kvm *kvm)
+{
+       u16 *mode;
+       void *p;
+
+       p = guest_flat_to_host(kvm, VGA_ROM_OEM_STRING);
+       memset(p, 0, VGA_ROM_OEM_STRING_SIZE);
+       strncpy(p, "KVM VESA", VGA_ROM_OEM_STRING_SIZE);
+
+       mode = guest_flat_to_host(kvm, VGA_ROM_MODES);
+       mode[0] = 0x0112;
+       mode[1] = 0xffff;
+}
+
+/**
+ * setup_bios - inject BIOS into guest memory
+ * @kvm - guest system descriptor
+ */
+void setup_bios(struct kvm *kvm)
+{
+       unsigned long address = MB_BIOS_BEGIN;
+       struct real_intr_desc intr_desc;
+       unsigned int i;
+       void *p;
+
+       /*
+        * before anything else -- clean some known areas
+        * we definitely don't want any trash here
+        */
+       p = guest_flat_to_host(kvm, BDA_START);
+       memset(p, 0, BDA_END - BDA_START);
+
+       p = guest_flat_to_host(kvm, EBDA_START);
+       memset(p, 0, EBDA_END - EBDA_START);
+
+       p = guest_flat_to_host(kvm, MB_BIOS_BEGIN);
+       memset(p, 0, MB_BIOS_END - MB_BIOS_BEGIN);
+
+       p = guest_flat_to_host(kvm, VGA_ROM_BEGIN);
+       memset(p, 0, VGA_ROM_END - VGA_ROM_BEGIN);
+
+       /* just copy the bios rom into the place */
+       p = guest_flat_to_host(kvm, MB_BIOS_BEGIN);
+       memcpy(p, bios_rom, bios_rom_size);
+
+       /* E820 memory map must be present */
+       e820_setup(kvm);
+
+       /* VESA needs own tricks */
+       setup_vga_rom(kvm);
+
+       /*
+        * Setup a *fake* real mode vector table, it has only
+        * one real handler which does just iret
+        */
+       address = BIOS_IRQ_PA_ADDR(bios_intfake);
+       intr_desc = (struct real_intr_desc) {
+               .segment        = REAL_SEGMENT(MB_BIOS_BEGIN),
+               .offset         = address - MB_BIOS_BEGIN,
+       };
+       interrupt_table__setup(&kvm->interrupt_table, &intr_desc);
+
+       for (i = 0; i < ARRAY_SIZE(bios_irq_handlers); i++)
+               setup_irq_handler(kvm, &bios_irq_handlers[i]);
+
+       /* we almost done */
+       p = guest_flat_to_host(kvm, 0);
+       interrupt_table__copy(&kvm->interrupt_table, p, REAL_INTR_SIZE);
+}
diff --git a/tools/kvm/x86/bios/.gitignore b/tools/kvm/x86/bios/.gitignore
new file mode 100644 (file)
index 0000000..1f0080b
--- /dev/null
@@ -0,0 +1,3 @@
+bios-rom.bin
+bios-rom.bin.elf
+bios-rom.h
diff --git a/tools/kvm/x86/bios/bios-rom.S b/tools/kvm/x86/bios/bios-rom.S
new file mode 100644 (file)
index 0000000..3269ce9
--- /dev/null
@@ -0,0 +1,12 @@
+#include <kvm/assembly.h>
+
+       .org 0
+#ifdef CONFIG_X86_64
+       .code64
+#else
+       .code32
+#endif
+
+GLOBAL(bios_rom)
+       .incbin "x86/bios/bios.bin"
+END(bios_rom)
diff --git a/tools/kvm/x86/bios/e820.c b/tools/kvm/x86/bios/e820.c
new file mode 100644 (file)
index 0000000..a9bca29
--- /dev/null
@@ -0,0 +1,72 @@
+#include "kvm/e820.h"
+
+#include "kvm/segment.h"
+#include "kvm/bios.h"
+
+#include <asm/processor-flags.h>
+#include <asm/e820.h>
+
+static inline void set_fs(u16 seg)
+{
+       asm volatile("movw %0,%%fs" : : "rm" (seg));
+}
+
+static inline u8 rdfs8(unsigned long addr)
+{
+       u8 v;
+
+       asm volatile("addr32 movb %%fs:%1,%0" : "=q" (v) : "m" (*(u8 *)addr));
+
+       return v;
+}
+
+static inline u32 rdfs32(unsigned long addr)
+{
+       u32 v;
+
+       asm volatile("addr32 movl %%fs:%1,%0" : "=q" (v) : "m" (*(u32 *)addr));
+
+       return v;
+}
+
+bioscall void e820_query_map(struct biosregs *regs)
+{
+       struct e820map *e820;
+       u32 map_size;
+       u16 fs_seg;
+       u32 ndx;
+
+       e820            = (struct e820map *)E820_MAP_START;
+       fs_seg          = flat_to_seg16(E820_MAP_START);
+       set_fs(fs_seg);
+
+       ndx             = regs->ebx;
+
+       map_size        = rdfs32(flat_to_off16((u32)&e820->nr_map, fs_seg));
+
+       if (ndx < map_size) {
+               u32 start;
+               unsigned int i;
+               u8 *p;
+
+               fs_seg  = flat_to_seg16(E820_MAP_START);
+               set_fs(fs_seg);
+
+               start   = (u32)&e820->map[ndx];
+
+               p       = (void *) regs->edi;
+
+               for (i = 0; i < sizeof(struct e820entry); i++)
+                       *p++    = rdfs8(flat_to_off16(start + i, fs_seg));
+       }
+
+       regs->eax       = SMAP;
+       regs->ecx       = sizeof(struct e820entry);
+       regs->ebx       = ++ndx;
+
+       /* Clear CF to indicate success.  */
+       regs->eflags    &= ~X86_EFLAGS_CF;
+
+       if (ndx >= map_size)
+               regs->ebx       = 0;    /* end of map */
+}
diff --git a/tools/kvm/x86/bios/entry.S b/tools/kvm/x86/bios/entry.S
new file mode 100644 (file)
index 0000000..85056e9
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Our pretty trivial BIOS emulation
+ */
+
+#include <kvm/bios.h>
+#include <kvm/assembly.h>
+
+       .org 0
+       .code16gcc
+
+#define EFLAGS_CF      (1 << 0)
+
+#include "macro.S"
+
+/* If you change these macros, remember to update 'struct biosregs' */
+.macro SAVE_BIOSREGS
+       pushl   %fs
+       pushl   %es
+       pushl   %ds
+       pushl   %edi
+       pushl   %esi
+       pushl   %ebp
+       pushl   %esp
+       pushl   %edx
+       pushl   %ecx
+       pushl   %ebx
+       pushl   %eax
+.endm
+
+.macro RESTORE_BIOSREGS
+       popl    %eax
+       popl    %ebx
+       popl    %ecx
+       popl    %edx
+       popl    %esp
+       popl    %ebp
+       popl    %esi
+       popl    %edi
+       popl    %ds
+       popl    %es
+       popl    %fs
+.endm
+
+/*
+ * fake interrupt handler, nothing can be faster ever
+ */
+ENTRY(bios_intfake)
+       /*
+        * Set CF to indicate failure. We don't want callers to think that the
+        * interrupt handler succeeded and then treat the return values in
+        * registers as valid data.
+        */
+       orl     $EFLAGS_CF, 0x4(%esp)
+
+       IRET
+ENTRY_END(bios_intfake)
+
+/*
+ * int 10 - video - service
+ */
+ENTRY(bios_int10)
+       SAVE_BIOSREGS
+
+       movl            %esp, %eax
+       /* this is way easier than doing it in assembly */
+       /* just push all the regs and jump to a C handler */
+       call    int10_handler
+
+       RESTORE_BIOSREGS
+
+       /* Clear CF to indicate success.  */
+       andl    $~EFLAGS_CF, 0x4(%esp)
+
+       IRET
+ENTRY_END(bios_int10)
+
+ENTRY(bios_int15)
+       SAVE_BIOSREGS
+
+       movl    %esp, %eax
+       call    int15_handler
+
+       RESTORE_BIOSREGS
+
+       IRET
+ENTRY_END(bios_int15)
+
+GLOBAL(__locals)
+
+#include "local.S"
+
+END(__locals)
diff --git a/tools/kvm/x86/bios/gen-offsets.sh b/tools/kvm/x86/bios/gen-offsets.sh
new file mode 100644 (file)
index 0000000..8771bbe
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+echo "/* Autogenerated file, don't edit */"
+echo "#ifndef BIOS_OFFSETS_H"
+echo "#define BIOS_OFFSETS_H"
+
+echo ""
+echo "#define BIOS_ENTRY_SIZE(name) (name##_end - name)"
+echo ""
+
+nm bios.bin.elf | grep ' [Tt] ' | awk '{ print "#define BIOS_OFFSET__" $3 " 0x" $1; }'
+
+echo ""
+echo "#endif"
diff --git a/tools/kvm/x86/bios/int10.c b/tools/kvm/x86/bios/int10.c
new file mode 100644 (file)
index 0000000..7cc0b3f
--- /dev/null
@@ -0,0 +1,110 @@
+#include "kvm/segment.h"
+#include "kvm/bios.h"
+#include "kvm/vesa.h"
+
+#include "bios/memcpy.h"
+
+#include <boot/vesa.h>
+
+static far_ptr gen_far_ptr(unsigned int pa)
+{
+       far_ptr ptr;
+
+       ptr.seg = (pa >> 4);
+       ptr.off = pa - (ptr.seg << 4);
+
+       return ptr;
+}
+
+static inline void outb(unsigned short port, unsigned char val)
+{
+       asm volatile("outb %0, %1" : : "a"(val), "Nd"(port));
+}
+
+/*
+ * It's probably much more useful to make this print to the serial
+ * line rather than print to a non-displayed VGA memory
+ */
+static inline void int10_putchar(struct biosregs *args)
+{
+       u8 al = args->eax & 0xFF;
+
+       outb(0x3f8, al);
+}
+
+static void vbe_get_mode(struct biosregs *args)
+{
+       struct vesa_mode_info *info = (struct vesa_mode_info *) args->edi;
+
+       *info = (struct vesa_mode_info) {
+               .mode_attr              = 0xd9, /* 11011011 */
+               .logical_scan           = VESA_WIDTH*4,
+               .h_res                  = VESA_WIDTH,
+               .v_res                  = VESA_HEIGHT,
+               .bpp                    = VESA_BPP,
+               .memory_layout          = 6,
+               .memory_planes          = 1,
+               .lfb_ptr                = VESA_MEM_ADDR,
+               .rmask                  = 8,
+               .gmask                  = 8,
+               .bmask                  = 8,
+               .resv_mask              = 8,
+               .resv_pos               = 24,
+               .bpos                   = 16,
+               .gpos                   = 8,
+       };
+}
+
+static void vbe_get_info(struct biosregs *args)
+{
+       struct vesa_general_info *infop = (struct vesa_general_info *) args->edi;
+       struct vesa_general_info info;
+
+       info = (struct vesa_general_info) {
+               .signature              = VESA_MAGIC,
+               .version                = 0x102,
+               .vendor_string          = gen_far_ptr(VGA_ROM_BEGIN),
+               .capabilities           = 0x10,
+               .video_mode_ptr         = gen_far_ptr(VGA_ROM_MODES),
+               .total_memory           = (4 * VESA_WIDTH * VESA_HEIGHT) / 0x10000,
+       };
+
+       memcpy16(args->es, infop, args->ds, &info, sizeof(info));
+}
+
+#define VBE_STATUS_OK          0x004F
+
+static void int10_vesa(struct biosregs *args)
+{
+       u8 al;
+
+       al = args->eax & 0xff;
+
+       switch (al) {
+       case 0x00:
+               vbe_get_info(args);
+               break;
+       case 0x01:
+               vbe_get_mode(args);
+               break;
+       }
+
+       args->eax = VBE_STATUS_OK;
+}
+
+bioscall void int10_handler(struct biosregs *args)
+{
+       u8 ah;
+
+       ah = (args->eax & 0xff00) >> 8;
+
+       switch (ah) {
+       case 0x0e:
+               int10_putchar(args);
+               break;
+       case 0x4f:
+               int10_vesa(args);
+               break;
+       }
+
+}
diff --git a/tools/kvm/x86/bios/int15.c b/tools/kvm/x86/bios/int15.c
new file mode 100644 (file)
index 0000000..faf5343
--- /dev/null
@@ -0,0 +1,18 @@
+#include "kvm/bios.h"
+
+#include "kvm/e820.h"
+
+#include <asm/processor-flags.h>
+
+bioscall void int15_handler(struct biosregs *regs)
+{
+       switch (regs->eax) {
+       case 0xe820:
+               e820_query_map(regs);
+               break;
+       default:
+               /* Set CF to indicate failure.  */
+               regs->eflags    |= X86_EFLAGS_CF;
+               break;
+       }
+}
diff --git a/tools/kvm/x86/bios/local.S b/tools/kvm/x86/bios/local.S
new file mode 100644 (file)
index 0000000..f2cdbf4
--- /dev/null
@@ -0,0 +1,7 @@
+/*
+ * Local variables for almost every BIOS irq handler
+ * Must be put somewhere inside irq handler body
+ */
+__CALLER_SS:           .int  0
+__CALLER_SP:           .long 0
+__CALLER_CLOBBER:      .long 0
diff --git a/tools/kvm/x86/bios/macro.S b/tools/kvm/x86/bios/macro.S
new file mode 100644 (file)
index 0000000..0d5e567
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * handy BIOS macros
+ */
+
+/*
+ * switch to BIOS stack
+ */
+.macro stack_swap
+       movw %ss, %cs:(__CALLER_SS)
+       movl %esp, %cs:(__CALLER_SP)
+       movl %edx, %cs:(__CALLER_CLOBBER)
+       movw $MB_BIOS_SS, %dx
+       movw %dx, %ss
+       movw $MB_BIOS_SP, %sp
+       movl %cs:(__CALLER_CLOBBER), %edx
+.endm
+
+/*
+ * restore the original stack
+ */
+.macro stack_restore
+       movl %cs:(__CALLER_SP), %esp
+       movw %cs:(__CALLER_SS), %ss
+.endm
+
diff --git a/tools/kvm/x86/bios/memcpy.c b/tools/kvm/x86/bios/memcpy.c
new file mode 100644 (file)
index 0000000..40b9b65
--- /dev/null
@@ -0,0 +1,23 @@
+#include "bios/memcpy.h"
+
+/*
+ *  Copy memory area in 16-bit real mode.
+ */
+void memcpy16(u16 dst_seg, void *dst, u16 src_seg, const void *src, size_t len)
+{
+       __asm__ __volatile__ (
+               "pushw  %%ds                            \n"
+               "pushw  %%es                            \n"
+               "movw   %[src_seg], %%ds                \n"
+               "movw   %[dst_seg], %%es                \n"
+               "rep movsb %%ds:(%%si), %%es:(%%di)     \n"
+               "popw   %%es                            \n"
+               "popw   %%ds                            \n"
+               :
+               : "S"(src),
+                 "D"(dst),
+                 "c"(len),
+                 [src_seg] "r"(src_seg),
+                 [dst_seg] "r"(dst_seg)
+               : "cc", "memory");
+}
diff --git a/tools/kvm/x86/bios/rom.ld.S b/tools/kvm/x86/bios/rom.ld.S
new file mode 100644 (file)
index 0000000..f4f1835
--- /dev/null
@@ -0,0 +1,16 @@
+OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
+OUTPUT_ARCH(i386)
+
+SECTIONS {
+       .text 0 : {
+               *(.text)
+       }
+
+       /DISCARD/ : {
+               *(.debug*)
+               *(.data)
+               *(.bss)
+               *(.eh_frame*)
+       }
+}
+
diff --git a/tools/kvm/x86/boot.c b/tools/kvm/x86/boot.c
new file mode 100644 (file)
index 0000000..93d9677
--- /dev/null
@@ -0,0 +1,41 @@
+#include "kvm/kvm.h"
+
+#include "kvm/util.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdbool.h>
+#include <fcntl.h>
+
+#define BIOS_SELECTOR  0xf000
+#define BIOS_IP                0xfff0
+#define BIOS_SP                0x8000
+
+bool kvm__load_firmware(struct kvm *kvm, const char *firmware_filename)
+{
+       struct stat st;
+       void *p;
+       int fd;
+       int nr;
+
+       fd = open(firmware_filename, O_RDONLY);
+       if (fd < 0)
+               return false;
+
+       if (fstat(fd, &st))
+               return false;
+
+       if (st.st_size > MB_FIRMWARE_BIOS_SIZE)
+               die("firmware image %s is too big to fit in memory (%Lu KB).\n", firmware_filename, (u64)(st.st_size / 1024));
+
+       p = guest_flat_to_host(kvm, MB_FIRMWARE_BIOS_BEGIN);
+
+       while ((nr = read(fd, p, st.st_size)) > 0)
+               p += nr;
+
+       kvm->boot_selector      = BIOS_SELECTOR;
+       kvm->boot_ip            = BIOS_IP;
+       kvm->boot_sp            = BIOS_SP;
+
+       return true;
+}
diff --git a/tools/kvm/x86/cpuid.c b/tools/kvm/x86/cpuid.c
new file mode 100644 (file)
index 0000000..4c140f0
--- /dev/null
@@ -0,0 +1,60 @@
+#include "kvm/kvm-cpu.h"
+
+#include "kvm/kvm.h"
+#include "kvm/util.h"
+
+#include <sys/ioctl.h>
+#include <stdlib.h>
+
+#define CPUID_FUNC_PERFMON             0x0A
+
+#define        MAX_KVM_CPUID_ENTRIES           100
+
+static void filter_cpuid(struct kvm_cpuid2 *kvm_cpuid)
+{
+       unsigned int i;
+
+       /*
+        * Filter CPUID functions that are not supported by the hypervisor.
+        */
+       for (i = 0; i < kvm_cpuid->nent; i++) {
+               struct kvm_cpuid_entry2 *entry = &kvm_cpuid->entries[i];
+
+               switch (entry->function) {
+               case 1:
+                       /* Set X86_FEATURE_HYPERVISOR */
+                       if (entry->index == 0)
+                               entry->ecx |= (1 << 31);
+                       break;
+               case 6:
+                       /* Clear X86_FEATURE_EPB */
+                       entry->ecx = entry->ecx & ~(1 << 3);
+                       break;
+               case CPUID_FUNC_PERFMON:
+                       entry->eax = 0x00; /* disable it */
+                       break;
+               default:
+                       /* Keep the CPUID function as -is */
+                       break;
+               };
+       }
+}
+
+void kvm_cpu__setup_cpuid(struct kvm_cpu *vcpu)
+{
+       struct kvm_cpuid2 *kvm_cpuid;
+
+       kvm_cpuid = calloc(1, sizeof(*kvm_cpuid) +
+                               MAX_KVM_CPUID_ENTRIES * sizeof(*kvm_cpuid->entries));
+
+       kvm_cpuid->nent = MAX_KVM_CPUID_ENTRIES;
+       if (ioctl(vcpu->kvm->sys_fd, KVM_GET_SUPPORTED_CPUID, kvm_cpuid) < 0)
+               die_perror("KVM_GET_SUPPORTED_CPUID failed");
+
+       filter_cpuid(kvm_cpuid);
+
+       if (ioctl(vcpu->vcpu_fd, KVM_SET_CPUID2, kvm_cpuid) < 0)
+               die_perror("KVM_SET_CPUID2 failed");
+
+       free(kvm_cpuid);
+}
diff --git a/tools/kvm/x86/include/kvm/assembly.h b/tools/kvm/x86/include/kvm/assembly.h
new file mode 100644 (file)
index 0000000..e70baab
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef ASSEMBLY_H_
+#define ASSEMBLY_H_
+
+#define __ALIGN        .p2align 4, 0x90
+#define ENTRY(name)    \
+       __ALIGN;        \
+       .globl name;    \
+       name:
+
+#define GLOBAL(name)   \
+       .globl name;    \
+       name:
+
+#define ENTRY_END(name)        GLOBAL(name##_end)
+#define END(name)      GLOBAL(name##_end)
+
+/*
+ * gas produces size override prefix with which
+ * we are unhappy, lets make it hardcoded for
+ * 16 bit mode
+ */
+#define IRET   .byte 0xcf
+
+#endif /* ASSEMBLY_H_ */
diff --git a/tools/kvm/x86/include/kvm/barrier.h b/tools/kvm/x86/include/kvm/barrier.h
new file mode 100644 (file)
index 0000000..46d14f6
--- /dev/null
@@ -0,0 +1,20 @@
+#ifndef _KVM_BARRIER_H_
+#define _KVM_BARRIER_H_
+
+#define barrier() asm volatile("": : :"memory")
+
+#define mb()   asm volatile ("mfence": : :"memory")
+#define rmb()  asm volatile ("lfence": : :"memory")
+#define wmb()  asm volatile ("sfence": : :"memory")
+
+#ifdef CONFIG_SMP
+#define smp_mb()       mb()
+#define smp_rmb()      rmb()
+#define smp_wmb()      wmb()
+#else
+#define smp_mb()       barrier()
+#define smp_rmb()      barrier()
+#define smp_wmb()      barrier()
+#endif
+
+#endif /* _KVM_BARRIER_H_ */
diff --git a/tools/kvm/x86/include/kvm/bios-export.h b/tools/kvm/x86/include/kvm/bios-export.h
new file mode 100644 (file)
index 0000000..23825aa
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef BIOS_EXPORT_H_
+#define BIOS_EXPORT_H_
+
+struct kvm;
+
+extern char bios_rom[0];
+extern char bios_rom_end[0];
+
+#define bios_rom_size          (bios_rom_end - bios_rom)
+
+extern void setup_bios(struct kvm *kvm);
+
+#endif /* BIOS_EXPORT_H_ */
diff --git a/tools/kvm/x86/include/kvm/bios.h b/tools/kvm/x86/include/kvm/bios.h
new file mode 100644 (file)
index 0000000..ec7ed71
--- /dev/null
@@ -0,0 +1,93 @@
+#ifndef BIOS_H_
+#define BIOS_H_
+
+/*
+ * X86-32 Memory Map (typical)
+ *                                     start      end
+ * Real Mode Interrupt Vector Table    0x00000000 0x000003FF
+ * BDA area                            0x00000400 0x000004FF
+ * Conventional Low Memory             0x00000500 0x0009FBFF
+ * EBDA area                           0x0009FC00 0x0009FFFF
+ * VIDEO RAM                           0x000A0000 0x000BFFFF
+ * VIDEO ROM (BIOS)                    0x000C0000 0x000C7FFF
+ * ROMs & unus. space (mapped hw & misc)0x000C8000 0x000EFFFF 160 KiB (typically)
+ * Motherboard BIOS                    0x000F0000 0x000FFFFF
+ * Extended Memory                     0x00100000 0xFEBFFFFF
+ * Reserved (configs, ACPI, PnP, etc)  0xFEC00000 0xFFFFFFFF
+ */
+
+#define REAL_MODE_IVT_BEGIN            0x00000000
+#define REAL_MODE_IVT_END              0x000003ff
+
+#define BDA_START                      0x00000400
+#define BDA_END                                0x000004ff
+
+#define EBDA_START                     0x0009fc00
+#define EBDA_END                       0x0009ffff
+
+#define E820_MAP_START                 EBDA_START
+
+#define MB_BIOS_BEGIN                  0x000f0000
+#define MB_FIRMWARE_BIOS_BEGIN         0x000e0000
+#define MB_BIOS_END                    0x000fffff
+
+#define MB_BIOS_SIZE                   (MB_BIOS_END - MB_BIOS_BEGIN + 1)
+#define MB_FIRMWARE_BIOS_SIZE          (MB_BIOS_END - MB_FIRMWARE_BIOS_BEGIN + 1)
+
+#define VGA_RAM_BEGIN                  0x000a0000
+#define VGA_RAM_END                    0x000bffff
+
+#define VGA_ROM_BEGIN                  0x000c0000
+#define VGA_ROM_OEM_STRING             VGA_ROM_BEGIN
+#define VGA_ROM_OEM_STRING_SIZE                16
+#define VGA_ROM_MODES                  (VGA_ROM_OEM_STRING + VGA_ROM_OEM_STRING_SIZE)
+#define VGA_ROM_MODES_SIZE             32
+#define VGA_ROM_END                    0x000c7fff
+
+/* we handle one page only */
+#define VGA_RAM_SEG                    (VGA_RAM_BEGIN >> 4)
+#define VGA_PAGE_SIZE                  0x007d0 /* 80x25 */
+
+/* real mode interrupt vector table */
+#define REAL_INTR_BASE                 REAL_MODE_IVT_BEGIN
+#define REAL_INTR_VECTORS              256
+
+/*
+ * BIOS stack must be at absolute predefined memory address
+ * We reserve 64 bytes for BIOS stack
+ */
+#define MB_BIOS_SS                     0xfff7
+#define MB_BIOS_SP                     0x40
+
+/*
+ * When interfere with assembler code we need to be sure how
+ * arguments are passed in real mode.
+ */
+#define bioscall __attribute__((regparm(3)))
+
+#ifndef __ASSEMBLER__
+
+#include <linux/types.h>
+
+struct biosregs {
+       u32                     eax;
+       u32                     ebx;
+       u32                     ecx;
+       u32                     edx;
+       u32                     esp;
+       u32                     ebp;
+       u32                     esi;
+       u32                     edi;
+       u32                     ds;
+       u32                     es;
+       u32                     fs;
+       u32                     eip;
+       u32                     eflags;
+};
+
+extern bioscall void int10_handler(struct biosregs *regs);
+extern bioscall void int15_handler(struct biosregs *regs);
+
+#endif
+
+#endif /* BIOS_H_ */
diff --git a/tools/kvm/x86/include/kvm/boot-protocol.h b/tools/kvm/x86/include/kvm/boot-protocol.h
new file mode 100644 (file)
index 0000000..85b637f
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Linux boot protocol specifics
+ */
+
+#ifndef BOOT_PROTOCOL_H_
+#define BOOT_PROTOCOL_H_
+
+/*
+ * The protected mode kernel part of a modern bzImage is loaded
+ * at 1 MB by default.
+ */
+#define BZ_DEFAULT_SETUP_SECTS         4
+#define BZ_KERNEL_START                        0x100000UL
+#define INITRD_START                   0x1000000UL
+
+#endif /* BOOT_PROTOCOL_H_ */
diff --git a/tools/kvm/x86/include/kvm/cpufeature.h b/tools/kvm/x86/include/kvm/cpufeature.h
new file mode 100644 (file)
index 0000000..bc4abbb
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef KVM__CPUFEATURE_H
+#define KVM__CPUFEATURE_H
+
+#define CPUID_VENDOR_INTEL_1 0x756e6547 /* "Genu" */
+#define CPUID_VENDOR_INTEL_2 0x49656e69 /* "ineI" */
+#define CPUID_VENDOR_INTEL_3 0x6c65746e /* "ntel" */
+
+#define CPUID_VENDOR_AMD_1   0x68747541 /* "Auth" */
+#define CPUID_VENDOR_AMD_2   0x69746e65 /* "enti" */
+#define CPUID_VENDOR_AMD_3   0x444d4163 /* "cAMD" */
+
+/*
+ * CPUID flags we need to deal with
+ */
+#define KVM__X86_FEATURE_VMX           5       /* Hardware virtualization */
+#define KVM__X86_FEATURE_SVM           2       /* Secure virtual machine */
+#define KVM__X86_FEATURE_XSAVE         26      /* XSAVE/XRSTOR/XSETBV/XGETBV */
+
+#define cpu_feature_disable(reg, feature)      \
+       ((reg) & ~(1 << (feature)))
+#define cpu_feature_enable(reg, feature)       \
+       ((reg) |  (1 << (feature)))
+
+struct cpuid_regs {
+       u32     eax;
+       u32     ebx;
+       u32     ecx;
+       u32     edx;
+};
+
+static inline void host_cpuid(struct cpuid_regs *regs)
+{
+       asm volatile("cpuid"
+               : "=a" (regs->eax),
+                 "=b" (regs->ebx),
+                 "=c" (regs->ecx),
+                 "=d" (regs->edx)
+               : "0" (regs->eax), "2" (regs->ecx));
+}
+
+#endif /* KVM__CPUFEATURE_H */
diff --git a/tools/kvm/x86/include/kvm/interrupt.h b/tools/kvm/x86/include/kvm/interrupt.h
new file mode 100644 (file)
index 0000000..00c7ed7
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef KVM__INTERRUPT_H
+#define KVM__INTERRUPT_H
+
+#include <linux/types.h>
+#include "kvm/bios.h"
+#include "kvm/bios-export.h"
+
+struct real_intr_desc {
+       u16 offset;
+       u16 segment;
+} __attribute__((packed));
+
+#define REAL_SEGMENT_SHIFT     4
+#define REAL_SEGMENT(addr)     ((addr) >> REAL_SEGMENT_SHIFT)
+#define REAL_OFFSET(addr)      ((addr) & ((1 << REAL_SEGMENT_SHIFT) - 1))
+#define REAL_INTR_SIZE         (REAL_INTR_VECTORS * sizeof(struct real_intr_desc))
+
+struct interrupt_table {
+       struct real_intr_desc entries[REAL_INTR_VECTORS];
+};
+
+void interrupt_table__copy(struct interrupt_table *itable, void *dst, unsigned int size);
+void interrupt_table__setup(struct interrupt_table *itable, struct real_intr_desc *entry);
+void interrupt_table__set(struct interrupt_table *itable, struct real_intr_desc *entry, unsigned int num);
+
+#endif /* KVM__INTERRUPT_H */
diff --git a/tools/kvm/x86/include/kvm/kvm-arch.h b/tools/kvm/x86/include/kvm/kvm-arch.h
new file mode 100644 (file)
index 0000000..dd385d4
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef KVM__KVM_ARCH_H
+#define KVM__KVM_ARCH_H
+
+#include "kvm/interrupt.h"
+#include "kvm/segment.h"
+
+#include <stdbool.h>
+#include <linux/types.h>
+#include <time.h>
+
+/*
+ * The hole includes VESA framebuffer and PCI memory.
+ */
+#define KVM_32BIT_MAX_MEM_SIZE  (1ULL << 32)
+#define KVM_32BIT_GAP_SIZE     (768 << 20)
+#define KVM_32BIT_GAP_START    (KVM_32BIT_MAX_MEM_SIZE - KVM_32BIT_GAP_SIZE)
+
+#define KVM_MMIO_START         KVM_32BIT_GAP_START
+
+/* This is the address that pci_get_io_space_block() starts allocating
+ * from.  Note that this is a PCI bus address (though same on x86).
+ */
+#define KVM_PCI_MMIO_AREA      (KVM_MMIO_START + 0x1000000)
+#define KVM_VIRTIO_MMIO_AREA   (KVM_MMIO_START + 0x2000000)
+
+struct kvm {
+       int                     sys_fd;         /* For system ioctls(), i.e. /dev/kvm */
+       int                     vm_fd;          /* For VM ioctls() */
+       timer_t                 timerid;        /* Posix timer for interrupts */
+
+       int                     nrcpus;         /* Number of cpus to run */
+
+       u32                     mem_slots;      /* for KVM_SET_USER_MEMORY_REGION */
+
+       u64                     ram_size;
+       void                    *ram_start;
+       u64                     ram_pagesize;
+
+       bool                    nmi_disabled;
+
+       bool                    single_step;
+
+       u16                     boot_selector;
+       u16                     boot_ip;
+       u16                     boot_sp;
+
+       struct interrupt_table  interrupt_table;
+
+       const char              *vmlinux;
+       struct disk_image       **disks;
+       int                     nr_disks;
+
+       char                    *name;
+
+       int                     vm_state;
+};
+
+static inline void *guest_flat_to_host(struct kvm *kvm, unsigned long offset); /* In kvm.h */
+
+static inline void *guest_real_to_host(struct kvm *kvm, u16 selector, u16 offset)
+{
+       unsigned long flat = segment_to_flat(selector, offset);
+
+       return guest_flat_to_host(kvm, flat);
+}
+
+#endif /* KVM__KVM_ARCH_H */
diff --git a/tools/kvm/x86/include/kvm/kvm-cpu-arch.h b/tools/kvm/x86/include/kvm/kvm-cpu-arch.h
new file mode 100644 (file)
index 0000000..198efe6
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef KVM__KVM_CPU_ARCH_H
+#define KVM__KVM_CPU_ARCH_H
+
+/* Architecture-specific kvm_cpu definitions. */
+
+#include <linux/kvm.h> /* for struct kvm_regs */
+#include "kvm/kvm.h"   /* for kvm__emulate_{mm}io() */
+#include <stdbool.h>
+#include <pthread.h>
+
+struct kvm;
+
+struct kvm_cpu {
+       pthread_t               thread;         /* VCPU thread */
+
+       unsigned long           cpu_id;
+
+       struct kvm              *kvm;           /* parent KVM */
+       int                     vcpu_fd;        /* For VCPU ioctls() */
+       struct kvm_run          *kvm_run;
+
+       struct kvm_regs         regs;
+       struct kvm_sregs        sregs;
+       struct kvm_fpu          fpu;
+
+       struct kvm_msrs         *msrs;          /* dynamically allocated */
+
+       u8                      is_running;
+       u8                      paused;
+       u8                      needs_nmi;
+
+       struct kvm_coalesced_mmio_ring  *ring;
+};
+
+/*
+ * As these are such simple wrappers, let's have them in the header so they'll
+ * be cheaper to call:
+ */
+static inline bool kvm_cpu__emulate_io(struct kvm *kvm, u16 port, void *data, int direction, int size, u32 count)
+{
+       return kvm__emulate_io(kvm, port, data, direction, size, count);
+}
+
+static inline bool kvm_cpu__emulate_mmio(struct kvm *kvm, u64 phys_addr, u8 *data, u32 len, u8 is_write)
+{
+       return kvm__emulate_mmio(kvm, phys_addr, data, len, is_write);
+}
+
+#endif /* KVM__KVM_CPU_ARCH_H */
diff --git a/tools/kvm/x86/include/kvm/mptable.h b/tools/kvm/x86/include/kvm/mptable.h
new file mode 100644 (file)
index 0000000..9e3cfa6
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef KVM_MPTABLE_H_
+#define KVM_MPTABLE_H_
+
+struct kvm;
+
+int mptable__init(struct kvm *kvm);
+int mptable__exit(struct kvm *kvm);
+
+#endif /* KVM_MPTABLE_H_ */
diff --git a/tools/kvm/x86/interrupt.c b/tools/kvm/x86/interrupt.c
new file mode 100644 (file)
index 0000000..7d47869
--- /dev/null
@@ -0,0 +1,28 @@
+#include "kvm/interrupt.h"
+
+#include "kvm/util.h"
+
+#include <string.h>
+
+void interrupt_table__copy(struct interrupt_table *itable, void *dst, unsigned int size)
+{
+       if (size < sizeof(itable->entries))
+               die("An attempt to overwrite host memory");
+
+       memcpy(dst, itable->entries, sizeof(itable->entries));
+}
+
+void interrupt_table__setup(struct interrupt_table *itable, struct real_intr_desc *entry)
+{
+       unsigned int i;
+
+       for (i = 0; i < REAL_INTR_VECTORS; i++)
+               itable->entries[i] = *entry;
+}
+
+void interrupt_table__set(struct interrupt_table *itable,
+                               struct real_intr_desc *entry, unsigned int num)
+{
+       if (num < REAL_INTR_VECTORS)
+               itable->entries[num] = *entry;
+}
diff --git a/tools/kvm/x86/ioport.c b/tools/kvm/x86/ioport.c
new file mode 100644 (file)
index 0000000..86302e6
--- /dev/null
@@ -0,0 +1,77 @@
+#include "kvm/ioport.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+
+static bool debug_io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+       exit(EXIT_SUCCESS);
+}
+
+static struct ioport_operations debug_ops = {
+       .io_out         = debug_io_out,
+};
+
+static bool seabios_debug_io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+       char ch;
+
+       ch = ioport__read8(data);
+
+       putchar(ch);
+
+       return true;
+}
+
+static struct ioport_operations seabios_debug_ops = {
+       .io_out         = seabios_debug_io_out,
+};
+
+static bool dummy_io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+       return true;
+}
+
+static bool dummy_io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
+{
+       return true;
+}
+
+static struct ioport_operations dummy_read_write_ioport_ops = {
+       .io_in          = dummy_io_in,
+       .io_out         = dummy_io_out,
+};
+
+static struct ioport_operations dummy_write_only_ioport_ops = {
+       .io_out         = dummy_io_out,
+};
+
+void ioport__setup_arch(void)
+{
+       /* Legacy ioport setup */
+
+       /* 0x0020 - 0x003F - 8259A PIC 1 */
+       ioport__register(0x0020, &dummy_read_write_ioport_ops, 2, NULL);
+
+       /* PORT 0040-005F - PIT - PROGRAMMABLE INTERVAL TIMER (8253, 8254) */
+       ioport__register(0x0040, &dummy_read_write_ioport_ops, 4, NULL);
+
+       /* 0x00A0 - 0x00AF - 8259A PIC 2 */
+       ioport__register(0x00A0, &dummy_read_write_ioport_ops, 2, NULL);
+
+       /* PORT 00E0-00EF are 'motherboard specific' so we use them for our
+          internal debugging purposes.  */
+       ioport__register(IOPORT_DBG, &debug_ops, 1, NULL);
+
+       /* PORT 00ED - DUMMY PORT FOR DELAY??? */
+       ioport__register(0x00ED, &dummy_write_only_ioport_ops, 1, NULL);
+
+       /* 0x00F0 - 0x00FF - Math co-processor */
+       ioport__register(0x00F0, &dummy_write_only_ioport_ops, 2, NULL);
+
+       /* PORT 03D4-03D5 - COLOR VIDEO - CRT CONTROL REGISTERS */
+       ioport__register(0x03D4, &dummy_read_write_ioport_ops, 1, NULL);
+       ioport__register(0x03D5, &dummy_write_only_ioport_ops, 1, NULL);
+
+       ioport__register(0x402, &seabios_debug_ops, 1, NULL);
+}
diff --git a/tools/kvm/x86/irq.c b/tools/kvm/x86/irq.c
new file mode 100644 (file)
index 0000000..e83df99
--- /dev/null
@@ -0,0 +1,222 @@
+#include "kvm/irq.h"
+#include "kvm/kvm.h"
+#include "kvm/util.h"
+
+#include <linux/types.h>
+#include <linux/rbtree.h>
+#include <linux/list.h>
+#include <linux/kvm.h>
+#include <sys/ioctl.h>
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#define IRQ_MAX_GSI                    64
+#define IRQCHIP_MASTER                 0
+#define IRQCHIP_SLAVE                  1
+#define IRQCHIP_IOAPIC                 2
+
+static u8              next_line       = 5;
+static u8              next_dev        = 1;
+static struct rb_root  pci_tree        = RB_ROOT;
+
+/* First 24 GSIs are routed between IRQCHIPs and IOAPICs */
+static u32 gsi = 24;
+
+struct kvm_irq_routing *irq_routing;
+
+static int irq__add_routing(u32 gsi, u32 type, u32 irqchip, u32 pin)
+{
+       if (gsi >= IRQ_MAX_GSI)
+               return -ENOSPC;
+
+       irq_routing->entries[irq_routing->nr++] =
+               (struct kvm_irq_routing_entry) {
+                       .gsi = gsi,
+                       .type = type,
+                       .u.irqchip.irqchip = irqchip,
+                       .u.irqchip.pin = pin,
+               };
+
+       return 0;
+}
+
+static struct pci_dev *search(struct rb_root *root, u32 id)
+{
+       struct rb_node *node = root->rb_node;
+
+       while (node) {
+               struct pci_dev *data = rb_entry(node, struct pci_dev, node);
+               int result;
+
+               result = id - data->id;
+
+               if (result < 0)
+                       node = node->rb_left;
+               else if (result > 0)
+                       node = node->rb_right;
+               else
+                       return data;
+       }
+       return NULL;
+}
+
+static int insert(struct rb_root *root, struct pci_dev *data)
+{
+       struct rb_node **new = &(root->rb_node), *parent = NULL;
+
+       /* Figure out where to put new node */
+       while (*new) {
+               struct pci_dev *this    = container_of(*new, struct pci_dev, node);
+               int result              = data->id - this->id;
+
+               parent = *new;
+               if (result < 0)
+                       new = &((*new)->rb_left);
+               else if (result > 0)
+                       new = &((*new)->rb_right);
+               else
+                       return -EEXIST;
+       }
+
+       /* Add new node and rebalance tree. */
+       rb_link_node(&data->node, parent, new);
+       rb_insert_color(&data->node, root);
+
+       return 0;
+}
+
+int irq__register_device(u32 dev, u8 *num, u8 *pin, u8 *line)
+{
+       struct pci_dev *node;
+       int r;
+
+       node = search(&pci_tree, dev);
+
+       if (!node) {
+               /* We haven't found a node - First device of it's kind */
+               node = malloc(sizeof(*node));
+               if (node == NULL)
+                       return -ENOMEM;
+
+               *node = (struct pci_dev) {
+                       .id     = dev,
+                       /*
+                        * PCI supports only INTA#,B#,C#,D# per device.
+                        * A#,B#,C#,D# are allowed for multifunctional
+                        * devices so stick with A# for our single
+                        * function devices.
+                        */
+                       .pin    = 1,
+               };
+
+               INIT_LIST_HEAD(&node->lines);
+
+               r = insert(&pci_tree, node);
+               if (r) {
+                       free(node);
+                       return r;
+               }
+       }
+
+       if (node) {
+               /* This device already has a pin assigned, give out a new line and device id */
+               struct irq_line *new = malloc(sizeof(*new));
+               if (new == NULL)
+                       return -ENOMEM;
+
+               new->line       = next_line++;
+               *line           = new->line;
+               *pin            = node->pin;
+               *num            = next_dev++;
+
+               list_add(&new->node, &node->lines);
+
+               return 0;
+       }
+
+       return -EFAULT;
+}
+
+int irq__init(struct kvm *kvm)
+{
+       int i, r;
+
+       irq_routing = calloc(sizeof(struct kvm_irq_routing) +
+                       IRQ_MAX_GSI * sizeof(struct kvm_irq_routing_entry), 1);
+       if (irq_routing == NULL)
+               return -ENOMEM;
+
+       /* Hook first 8 GSIs to master IRQCHIP */
+       for (i = 0; i < 8; i++)
+               if (i != 2)
+                       irq__add_routing(i, KVM_IRQ_ROUTING_IRQCHIP, IRQCHIP_MASTER, i);
+
+       /* Hook next 8 GSIs to slave IRQCHIP */
+       for (i = 8; i < 16; i++)
+               irq__add_routing(i, KVM_IRQ_ROUTING_IRQCHIP, IRQCHIP_SLAVE, i - 8);
+
+       /* Last but not least, IOAPIC */
+       for (i = 0; i < 24; i++) {
+               if (i == 0)
+                       irq__add_routing(i, KVM_IRQ_ROUTING_IRQCHIP, IRQCHIP_IOAPIC, 2);
+               else if (i != 2)
+                       irq__add_routing(i, KVM_IRQ_ROUTING_IRQCHIP, IRQCHIP_IOAPIC, i);
+       }
+
+       r = ioctl(kvm->vm_fd, KVM_SET_GSI_ROUTING, irq_routing);
+       if (r) {
+               free(irq_routing);
+               return errno;
+       }
+
+       return 0;
+}
+
+int irq__exit(struct kvm *kvm)
+{
+       struct rb_node *ent;
+
+       free(irq_routing);
+
+       while ((ent = rb_first(&pci_tree))) {
+               struct pci_dev *dev;
+               struct irq_line *line;
+
+               dev = rb_entry(ent, struct pci_dev, node);
+               while (!list_empty(&dev->lines)) {
+                       line = list_first_entry(&dev->lines, struct irq_line, node);
+                       list_del(&line->node);
+                       free(line);
+               }
+               rb_erase(&dev->node, &pci_tree);
+               free(dev);
+       }
+
+       return 0;
+}
+
+int irq__add_msix_route(struct kvm *kvm, struct msi_msg *msg)
+{
+       int r;
+
+       irq_routing->entries[irq_routing->nr++] =
+               (struct kvm_irq_routing_entry) {
+                       .gsi = gsi,
+                       .type = KVM_IRQ_ROUTING_MSI,
+                       .u.msi.address_hi = msg->address_hi,
+                       .u.msi.address_lo = msg->address_lo,
+                       .u.msi.data = msg->data,
+               };
+
+       r = ioctl(kvm->vm_fd, KVM_SET_GSI_ROUTING, irq_routing);
+       if (r)
+               return r;
+
+       return gsi++;
+}
+
+struct rb_node *irq__get_pci_tree(void)
+{
+       return rb_first(&pci_tree);
+}
diff --git a/tools/kvm/x86/kvm-cpu.c b/tools/kvm/x86/kvm-cpu.c
new file mode 100644 (file)
index 0000000..2b3d973
--- /dev/null
@@ -0,0 +1,425 @@
+#include "kvm/kvm-cpu.h"
+
+#include "kvm/symbol.h"
+#include "kvm/util.h"
+#include "kvm/kvm.h"
+
+#include <asm/msr-index.h>
+#include <asm/apicdef.h>
+#include <linux/err.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+
+static int debug_fd;
+
+void kvm_cpu__set_debug_fd(int fd)
+{
+       debug_fd = fd;
+}
+
+int kvm_cpu__get_debug_fd(void)
+{
+       return debug_fd;
+}
+
+static inline bool is_in_protected_mode(struct kvm_cpu *vcpu)
+{
+       return vcpu->sregs.cr0 & 0x01;
+}
+
+static inline u64 ip_to_flat(struct kvm_cpu *vcpu, u64 ip)
+{
+       u64 cs;
+
+       /*
+        * NOTE! We should take code segment base address into account here.
+        * Luckily it's usually zero because Linux uses flat memory model.
+        */
+       if (is_in_protected_mode(vcpu))
+               return ip;
+
+       cs = vcpu->sregs.cs.selector;
+
+       return ip + (cs << 4);
+}
+
+static inline u32 selector_to_base(u16 selector)
+{
+       /*
+        * KVM on Intel requires 'base' to be 'selector * 16' in real mode.
+        */
+       return (u32)selector << 4;
+}
+
+static struct kvm_cpu *kvm_cpu__new(struct kvm *kvm)
+{
+       struct kvm_cpu *vcpu;
+
+       vcpu = calloc(1, sizeof(*vcpu));
+       if (!vcpu)
+               return NULL;
+
+       vcpu->kvm = kvm;
+
+       return vcpu;
+}
+
+void kvm_cpu__delete(struct kvm_cpu *vcpu)
+{
+       if (vcpu->msrs)
+               free(vcpu->msrs);
+
+       free(vcpu);
+}
+
+static int kvm_cpu__set_lint(struct kvm_cpu *vcpu)
+{
+       struct local_apic lapic;
+
+       if (ioctl(vcpu->vcpu_fd, KVM_GET_LAPIC, &lapic))
+               return -1;
+
+       lapic.lvt_lint0.delivery_mode = APIC_MODE_EXTINT;
+       lapic.lvt_lint1.delivery_mode = APIC_MODE_NMI;
+
+       return ioctl(vcpu->vcpu_fd, KVM_SET_LAPIC, &lapic);
+}
+
+struct kvm_cpu *kvm_cpu__init(struct kvm *kvm, unsigned long cpu_id)
+{
+       struct kvm_cpu *vcpu;
+       int mmap_size;
+       int coalesced_offset;
+
+       vcpu = kvm_cpu__new(kvm);
+       if (!vcpu)
+               return NULL;
+
+       vcpu->cpu_id = cpu_id;
+
+       vcpu->vcpu_fd = ioctl(vcpu->kvm->vm_fd, KVM_CREATE_VCPU, cpu_id);
+       if (vcpu->vcpu_fd < 0)
+               die_perror("KVM_CREATE_VCPU ioctl");
+
+       mmap_size = ioctl(vcpu->kvm->sys_fd, KVM_GET_VCPU_MMAP_SIZE, 0);
+       if (mmap_size < 0)
+               die_perror("KVM_GET_VCPU_MMAP_SIZE ioctl");
+
+       vcpu->kvm_run = mmap(NULL, mmap_size, PROT_RW, MAP_SHARED, vcpu->vcpu_fd, 0);
+       if (vcpu->kvm_run == MAP_FAILED)
+               die("unable to mmap vcpu fd");
+
+       coalesced_offset = ioctl(kvm->sys_fd, KVM_CHECK_EXTENSION, KVM_CAP_COALESCED_MMIO);
+       if (coalesced_offset)
+               vcpu->ring = (void *)vcpu->kvm_run + (coalesced_offset * PAGE_SIZE);
+
+       if (kvm_cpu__set_lint(vcpu))
+               die_perror("KVM_SET_LAPIC failed");
+
+       vcpu->is_running = true;
+
+       return vcpu;
+}
+
+static struct kvm_msrs *kvm_msrs__new(size_t nmsrs)
+{
+       struct kvm_msrs *vcpu = calloc(1, sizeof(*vcpu) + (sizeof(struct kvm_msr_entry) * nmsrs));
+
+       if (!vcpu)
+               die("out of memory");
+
+       return vcpu;
+}
+
+#define KVM_MSR_ENTRY(_index, _data)   \
+       (struct kvm_msr_entry) { .index = _index, .data = _data }
+
+static void kvm_cpu__setup_msrs(struct kvm_cpu *vcpu)
+{
+       unsigned long ndx = 0;
+
+       vcpu->msrs = kvm_msrs__new(100);
+
+       vcpu->msrs->entries[ndx++] = KVM_MSR_ENTRY(MSR_IA32_SYSENTER_CS,        0x0);
+       vcpu->msrs->entries[ndx++] = KVM_MSR_ENTRY(MSR_IA32_SYSENTER_ESP,       0x0);
+       vcpu->msrs->entries[ndx++] = KVM_MSR_ENTRY(MSR_IA32_SYSENTER_EIP,       0x0);
+#ifdef CONFIG_X86_64
+       vcpu->msrs->entries[ndx++] = KVM_MSR_ENTRY(MSR_STAR,                    0x0);
+       vcpu->msrs->entries[ndx++] = KVM_MSR_ENTRY(MSR_CSTAR,                   0x0);
+       vcpu->msrs->entries[ndx++] = KVM_MSR_ENTRY(MSR_KERNEL_GS_BASE,          0x0);
+       vcpu->msrs->entries[ndx++] = KVM_MSR_ENTRY(MSR_SYSCALL_MASK,            0x0);
+       vcpu->msrs->entries[ndx++] = KVM_MSR_ENTRY(MSR_LSTAR,                   0x0);
+#endif
+       vcpu->msrs->entries[ndx++] = KVM_MSR_ENTRY(MSR_IA32_TSC,                0x0);
+       vcpu->msrs->entries[ndx++] = KVM_MSR_ENTRY(MSR_IA32_MISC_ENABLE,
+                                               MSR_IA32_MISC_ENABLE_FAST_STRING);
+
+       vcpu->msrs->nmsrs = ndx;
+
+       if (ioctl(vcpu->vcpu_fd, KVM_SET_MSRS, vcpu->msrs) < 0)
+               die_perror("KVM_SET_MSRS failed");
+}
+
+static void kvm_cpu__setup_fpu(struct kvm_cpu *vcpu)
+{
+       vcpu->fpu = (struct kvm_fpu) {
+               .fcw    = 0x37f,
+               .mxcsr  = 0x1f80,
+       };
+
+       if (ioctl(vcpu->vcpu_fd, KVM_SET_FPU, &vcpu->fpu) < 0)
+               die_perror("KVM_SET_FPU failed");
+}
+
+static void kvm_cpu__setup_regs(struct kvm_cpu *vcpu)
+{
+       vcpu->regs = (struct kvm_regs) {
+               /* We start the guest in 16-bit real mode  */
+               .rflags = 0x0000000000000002ULL,
+
+               .rip    = vcpu->kvm->boot_ip,
+               .rsp    = vcpu->kvm->boot_sp,
+               .rbp    = vcpu->kvm->boot_sp,
+       };
+
+       if (vcpu->regs.rip > USHRT_MAX)
+               die("ip 0x%llx is too high for real mode", (u64)vcpu->regs.rip);
+
+       if (ioctl(vcpu->vcpu_fd, KVM_SET_REGS, &vcpu->regs) < 0)
+               die_perror("KVM_SET_REGS failed");
+}
+
+static void kvm_cpu__setup_sregs(struct kvm_cpu *vcpu)
+{
+       if (ioctl(vcpu->vcpu_fd, KVM_GET_SREGS, &vcpu->sregs) < 0)
+               die_perror("KVM_GET_SREGS failed");
+
+       vcpu->sregs.cs.selector = vcpu->kvm->boot_selector;
+       vcpu->sregs.cs.base     = selector_to_base(vcpu->kvm->boot_selector);
+       vcpu->sregs.ss.selector = vcpu->kvm->boot_selector;
+       vcpu->sregs.ss.base     = selector_to_base(vcpu->kvm->boot_selector);
+       vcpu->sregs.ds.selector = vcpu->kvm->boot_selector;
+       vcpu->sregs.ds.base     = selector_to_base(vcpu->kvm->boot_selector);
+       vcpu->sregs.es.selector = vcpu->kvm->boot_selector;
+       vcpu->sregs.es.base     = selector_to_base(vcpu->kvm->boot_selector);
+       vcpu->sregs.fs.selector = vcpu->kvm->boot_selector;
+       vcpu->sregs.fs.base     = selector_to_base(vcpu->kvm->boot_selector);
+       vcpu->sregs.gs.selector = vcpu->kvm->boot_selector;
+       vcpu->sregs.gs.base     = selector_to_base(vcpu->kvm->boot_selector);
+
+       if (ioctl(vcpu->vcpu_fd, KVM_SET_SREGS, &vcpu->sregs) < 0)
+               die_perror("KVM_SET_SREGS failed");
+}
+
+/**
+ * kvm_cpu__reset_vcpu - reset virtual CPU to a known state
+ */
+void kvm_cpu__reset_vcpu(struct kvm_cpu *vcpu)
+{
+       kvm_cpu__setup_cpuid(vcpu);
+       kvm_cpu__setup_sregs(vcpu);
+       kvm_cpu__setup_regs(vcpu);
+       kvm_cpu__setup_fpu(vcpu);
+       kvm_cpu__setup_msrs(vcpu);
+}
+
+bool kvm_cpu__handle_exit(struct kvm_cpu *vcpu)
+{
+       return false;
+}
+
+static void print_dtable(const char *name, struct kvm_dtable *dtable)
+{
+       dprintf(debug_fd, " %s                 %016llx  %08hx\n",
+               name, (u64) dtable->base, (u16) dtable->limit);
+}
+
+static void print_segment(const char *name, struct kvm_segment *seg)
+{
+       dprintf(debug_fd, " %s       %04hx      %016llx  %08x  %02hhx    %x %x   %x  %x %x %x %x\n",
+               name, (u16) seg->selector, (u64) seg->base, (u32) seg->limit,
+               (u8) seg->type, seg->present, seg->dpl, seg->db, seg->s, seg->l, seg->g, seg->avl);
+}
+
+void kvm_cpu__show_registers(struct kvm_cpu *vcpu)
+{
+       unsigned long cr0, cr2, cr3;
+       unsigned long cr4, cr8;
+       unsigned long rax, rbx, rcx;
+       unsigned long rdx, rsi, rdi;
+       unsigned long rbp,  r8,  r9;
+       unsigned long r10, r11, r12;
+       unsigned long r13, r14, r15;
+       unsigned long rip, rsp;
+       struct kvm_sregs sregs;
+       unsigned long rflags;
+       struct kvm_regs regs;
+       int i;
+
+       if (ioctl(vcpu->vcpu_fd, KVM_GET_REGS, &regs) < 0)
+               die("KVM_GET_REGS failed");
+
+       rflags = regs.rflags;
+
+       rip = regs.rip; rsp = regs.rsp;
+       rax = regs.rax; rbx = regs.rbx; rcx = regs.rcx;
+       rdx = regs.rdx; rsi = regs.rsi; rdi = regs.rdi;
+       rbp = regs.rbp; r8  = regs.r8;  r9  = regs.r9;
+       r10 = regs.r10; r11 = regs.r11; r12 = regs.r12;
+       r13 = regs.r13; r14 = regs.r14; r15 = regs.r15;
+
+       dprintf(debug_fd, "\n Registers:\n");
+       dprintf(debug_fd,   " ----------\n");
+       dprintf(debug_fd, " rip: %016lx   rsp: %016lx flags: %016lx\n", rip, rsp, rflags);
+       dprintf(debug_fd, " rax: %016lx   rbx: %016lx   rcx: %016lx\n", rax, rbx, rcx);
+       dprintf(debug_fd, " rdx: %016lx   rsi: %016lx   rdi: %016lx\n", rdx, rsi, rdi);
+       dprintf(debug_fd, " rbp: %016lx    r8: %016lx    r9: %016lx\n", rbp, r8,  r9);
+       dprintf(debug_fd, " r10: %016lx   r11: %016lx   r12: %016lx\n", r10, r11, r12);
+       dprintf(debug_fd, " r13: %016lx   r14: %016lx   r15: %016lx\n", r13, r14, r15);
+
+       if (ioctl(vcpu->vcpu_fd, KVM_GET_SREGS, &sregs) < 0)
+               die("KVM_GET_REGS failed");
+
+       cr0 = sregs.cr0; cr2 = sregs.cr2; cr3 = sregs.cr3;
+       cr4 = sregs.cr4; cr8 = sregs.cr8;
+
+       dprintf(debug_fd, " cr0: %016lx   cr2: %016lx   cr3: %016lx\n", cr0, cr2, cr3);
+       dprintf(debug_fd, " cr4: %016lx   cr8: %016lx\n", cr4, cr8);
+       dprintf(debug_fd, "\n Segment registers:\n");
+       dprintf(debug_fd,   " ------------------\n");
+       dprintf(debug_fd, " register  selector  base              limit     type  p dpl db s l g avl\n");
+       print_segment("cs ", &sregs.cs);
+       print_segment("ss ", &sregs.ss);
+       print_segment("ds ", &sregs.ds);
+       print_segment("es ", &sregs.es);
+       print_segment("fs ", &sregs.fs);
+       print_segment("gs ", &sregs.gs);
+       print_segment("tr ", &sregs.tr);
+       print_segment("ldt", &sregs.ldt);
+       print_dtable("gdt", &sregs.gdt);
+       print_dtable("idt", &sregs.idt);
+
+       dprintf(debug_fd, "\n APIC:\n");
+       dprintf(debug_fd,   " -----\n");
+       dprintf(debug_fd, " efer: %016llx  apic base: %016llx  nmi: %s\n",
+               (u64) sregs.efer, (u64) sregs.apic_base,
+               (vcpu->kvm->nmi_disabled ? "disabled" : "enabled"));
+
+       dprintf(debug_fd, "\n Interrupt bitmap:\n");
+       dprintf(debug_fd,   " -----------------\n");
+       for (i = 0; i < (KVM_NR_INTERRUPTS + 63) / 64; i++)
+               dprintf(debug_fd, " %016llx", (u64) sregs.interrupt_bitmap[i]);
+       dprintf(debug_fd, "\n");
+}
+
+#define MAX_SYM_LEN 128
+
+void kvm_cpu__show_code(struct kvm_cpu *vcpu)
+{
+       unsigned int code_bytes = 64;
+       unsigned int code_prologue = 43;
+       unsigned int code_len = code_bytes;
+       char sym[MAX_SYM_LEN] = SYMBOL_DEFAULT_UNKNOWN, *psym;
+       unsigned char c;
+       unsigned int i;
+       u8 *ip;
+
+       if (ioctl(vcpu->vcpu_fd, KVM_GET_REGS, &vcpu->regs) < 0)
+               die("KVM_GET_REGS failed");
+
+       if (ioctl(vcpu->vcpu_fd, KVM_GET_SREGS, &vcpu->sregs) < 0)
+               die("KVM_GET_SREGS failed");
+
+       ip = guest_flat_to_host(vcpu->kvm, ip_to_flat(vcpu, vcpu->regs.rip) - code_prologue);
+
+       dprintf(debug_fd, "\n Code:\n");
+       dprintf(debug_fd,   " -----\n");
+
+       psym = symbol_lookup(vcpu->kvm, vcpu->regs.rip, sym, MAX_SYM_LEN);
+       if (IS_ERR(psym))
+               dprintf(debug_fd,
+                       "Warning: symbol_lookup() failed to find symbol "
+                       "with error: %ld\n", PTR_ERR(psym));
+
+       dprintf(debug_fd, " rip: [<%016lx>] %s\n\n", (unsigned long) vcpu->regs.rip, sym);
+
+       for (i = 0; i < code_len; i++, ip++) {
+               if (!host_ptr_in_ram(vcpu->kvm, ip))
+                       break;
+
+               c = *ip;
+
+               if (ip == guest_flat_to_host(vcpu->kvm, ip_to_flat(vcpu, vcpu->regs.rip)))
+                       dprintf(debug_fd, " <%02x>", c);
+               else
+                       dprintf(debug_fd, " %02x", c);
+       }
+
+       dprintf(debug_fd, "\n");
+
+       dprintf(debug_fd, "\n Stack:\n");
+       dprintf(debug_fd,   " ------\n");
+       kvm__dump_mem(vcpu->kvm, vcpu->regs.rsp, 32);
+}
+
+void kvm_cpu__show_page_tables(struct kvm_cpu *vcpu)
+{
+       u64 *pte1;
+       u64 *pte2;
+       u64 *pte3;
+       u64 *pte4;
+
+       if (!is_in_protected_mode(vcpu))
+               return;
+
+       if (ioctl(vcpu->vcpu_fd, KVM_GET_SREGS, &vcpu->sregs) < 0)
+               die("KVM_GET_SREGS failed");
+
+       pte4 = guest_flat_to_host(vcpu->kvm, vcpu->sregs.cr3);
+       if (!host_ptr_in_ram(vcpu->kvm, pte4))
+               return;
+
+       pte3 = guest_flat_to_host(vcpu->kvm, (*pte4 & ~0xfff));
+       if (!host_ptr_in_ram(vcpu->kvm, pte3))
+               return;
+
+       pte2 = guest_flat_to_host(vcpu->kvm, (*pte3 & ~0xfff));
+       if (!host_ptr_in_ram(vcpu->kvm, pte2))
+               return;
+
+       pte1 = guest_flat_to_host(vcpu->kvm, (*pte2 & ~0xfff));
+       if (!host_ptr_in_ram(vcpu->kvm, pte1))
+               return;
+
+       dprintf(debug_fd, "Page Tables:\n");
+       if (*pte2 & (1 << 7))
+               dprintf(debug_fd, " pte4: %016llx   pte3: %016llx"
+                       "   pte2: %016llx\n",
+                       *pte4, *pte3, *pte2);
+       else
+               dprintf(debug_fd, " pte4: %016llx  pte3: %016llx   pte2: %016"
+                       "llx   pte1: %016llx\n",
+                       *pte4, *pte3, *pte2, *pte1);
+}
+
+void kvm_cpu__arch_nmi(struct kvm_cpu *cpu)
+{
+       struct kvm_lapic_state klapic;
+       struct local_apic *lapic = (void *)&klapic;
+
+       if (ioctl(cpu->vcpu_fd, KVM_GET_LAPIC, &klapic) != 0)
+               return;
+
+       if (lapic->lvt_lint1.mask)
+               return;
+
+       if (lapic->lvt_lint1.delivery_mode != APIC_MODE_NMI)
+               return;
+
+       ioctl(cpu->vcpu_fd, KVM_NMI);
+}
diff --git a/tools/kvm/x86/kvm.c b/tools/kvm/x86/kvm.c
new file mode 100644 (file)
index 0000000..0a40fd5
--- /dev/null
@@ -0,0 +1,372 @@
+#include "kvm/kvm.h"
+#include "kvm/boot-protocol.h"
+#include "kvm/cpufeature.h"
+#include "kvm/interrupt.h"
+#include "kvm/mptable.h"
+#include "kvm/util.h"
+#include "kvm/8250-serial.h"
+#include "kvm/virtio-console.h"
+
+#include <asm/bootparam.h>
+#include <linux/kvm.h>
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+
+struct kvm_ext kvm_req_ext[] = {
+       { DEFINE_KVM_EXT(KVM_CAP_COALESCED_MMIO) },
+       { DEFINE_KVM_EXT(KVM_CAP_SET_TSS_ADDR) },
+       { DEFINE_KVM_EXT(KVM_CAP_PIT2) },
+       { DEFINE_KVM_EXT(KVM_CAP_USER_MEMORY) },
+       { DEFINE_KVM_EXT(KVM_CAP_IRQ_ROUTING) },
+       { DEFINE_KVM_EXT(KVM_CAP_IRQCHIP) },
+       { DEFINE_KVM_EXT(KVM_CAP_HLT) },
+       { DEFINE_KVM_EXT(KVM_CAP_IRQ_INJECT_STATUS) },
+       { DEFINE_KVM_EXT(KVM_CAP_EXT_CPUID) },
+       { 0, 0 }
+};
+
+bool kvm__arch_cpu_supports_vm(void)
+{
+       struct cpuid_regs regs;
+       u32 eax_base;
+       int feature;
+
+       regs    = (struct cpuid_regs) {
+               .eax            = 0x00,
+       };
+       host_cpuid(&regs);
+
+       switch (regs.ebx) {
+       case CPUID_VENDOR_INTEL_1:
+               eax_base        = 0x00;
+               feature         = KVM__X86_FEATURE_VMX;
+               break;
+
+       case CPUID_VENDOR_AMD_1:
+               eax_base        = 0x80000000;
+               feature         = KVM__X86_FEATURE_SVM;
+               break;
+
+       default:
+               return false;
+       }
+
+       regs    = (struct cpuid_regs) {
+               .eax            = eax_base,
+       };
+       host_cpuid(&regs);
+
+       if (regs.eax < eax_base + 0x01)
+               return false;
+
+       regs    = (struct cpuid_regs) {
+               .eax            = eax_base + 0x01
+       };
+       host_cpuid(&regs);
+
+       return regs.ecx & (1 << feature);
+}
+
+/*
+ * Allocating RAM size bigger than 4GB requires us to leave a gap
+ * in the RAM which is used for PCI MMIO, hotplug, and unconfigured
+ * devices (see documentation of e820_setup_gap() for details).
+ *
+ * If we're required to initialize RAM bigger than 4GB, we will create
+ * a gap between 0xe0000000 and 0x100000000 in the guest virtual mem space.
+ */
+
+void kvm__init_ram(struct kvm *kvm)
+{
+       u64     phys_start, phys_size;
+       void    *host_mem;
+
+       if (kvm->ram_size < KVM_32BIT_GAP_START) {
+               /* Use a single block of RAM for 32bit RAM */
+
+               phys_start = 0;
+               phys_size  = kvm->ram_size;
+               host_mem   = kvm->ram_start;
+
+               kvm__register_mem(kvm, phys_start, phys_size, host_mem);
+       } else {
+               /* First RAM range from zero to the PCI gap: */
+
+               phys_start = 0;
+               phys_size  = KVM_32BIT_GAP_START;
+               host_mem   = kvm->ram_start;
+
+               kvm__register_mem(kvm, phys_start, phys_size, host_mem);
+
+               /* Second RAM range from 4GB to the end of RAM: */
+
+               phys_start = KVM_32BIT_MAX_MEM_SIZE;
+               phys_size  = kvm->ram_size - phys_start;
+               host_mem   = kvm->ram_start + phys_start;
+
+               kvm__register_mem(kvm, phys_start, phys_size, host_mem);
+       }
+}
+
+/* Arch-specific commandline setup */
+void kvm__arch_set_cmdline(char *cmdline, bool video)
+{
+       strcpy(cmdline, "noapic noacpi pci=conf1 reboot=k panic=1 i8042.direct=1 "
+                               "i8042.dumbkbd=1 i8042.nopnp=1");
+       if (video)
+               strcat(cmdline, " video=vesafb console=tty0");
+       else
+               strcat(cmdline, " console=ttyS0 earlyprintk=serial i8042.noaux=1");
+}
+
+/* Architecture-specific KVM init */
+void kvm__arch_init(struct kvm *kvm, const char *hugetlbfs_path, u64 ram_size)
+{
+       struct kvm_pit_config pit_config = { .flags = 0, };
+       int ret;
+
+       ret = ioctl(kvm->vm_fd, KVM_SET_TSS_ADDR, 0xfffbd000);
+       if (ret < 0)
+               die_perror("KVM_SET_TSS_ADDR ioctl");
+
+       ret = ioctl(kvm->vm_fd, KVM_CREATE_PIT2, &pit_config);
+       if (ret < 0)
+               die_perror("KVM_CREATE_PIT2 ioctl");
+
+       if (ram_size < KVM_32BIT_GAP_START) {
+               kvm->ram_size = ram_size;
+               kvm->ram_start = mmap_anon_or_hugetlbfs(kvm, hugetlbfs_path, ram_size);
+       } else {
+               kvm->ram_start = mmap_anon_or_hugetlbfs(kvm, hugetlbfs_path, ram_size + KVM_32BIT_GAP_SIZE);
+               kvm->ram_size = ram_size + KVM_32BIT_GAP_SIZE;
+               if (kvm->ram_start != MAP_FAILED)
+                       /*
+                        * We mprotect the gap (see kvm__init_ram() for details) PROT_NONE so that
+                        * if we accidently write to it, we will know.
+                        */
+                       mprotect(kvm->ram_start + KVM_32BIT_GAP_START, KVM_32BIT_GAP_SIZE, PROT_NONE);
+       }
+       if (kvm->ram_start == MAP_FAILED)
+               die("out of memory");
+
+       madvise(kvm->ram_start, kvm->ram_size, MADV_MERGEABLE);
+
+       ret = ioctl(kvm->vm_fd, KVM_CREATE_IRQCHIP);
+       if (ret < 0)
+               die_perror("KVM_CREATE_IRQCHIP ioctl");
+}
+
+void kvm__arch_delete_ram(struct kvm *kvm)
+{
+       munmap(kvm->ram_start, kvm->ram_size);
+}
+
+void kvm__irq_line(struct kvm *kvm, int irq, int level)
+{
+       struct kvm_irq_level irq_level;
+
+       irq_level       = (struct kvm_irq_level) {
+               {
+                       .irq            = irq,
+               },
+               .level          = level,
+       };
+
+       if (ioctl(kvm->vm_fd, KVM_IRQ_LINE, &irq_level) < 0)
+               die_perror("KVM_IRQ_LINE failed");
+}
+
+void kvm__irq_trigger(struct kvm *kvm, int irq)
+{
+       kvm__irq_line(kvm, irq, 1);
+       kvm__irq_line(kvm, irq, 0);
+}
+
+#define BOOT_LOADER_SELECTOR   0x1000
+#define BOOT_LOADER_IP         0x0000
+#define BOOT_LOADER_SP         0x8000
+#define BOOT_CMDLINE_OFFSET    0x20000
+
+#define BOOT_PROTOCOL_REQUIRED 0x206
+#define LOAD_HIGH              0x01
+
+int load_flat_binary(struct kvm *kvm, int fd_kernel, int fd_initrd, const char *kernel_cmdline)
+{
+       void *p;
+       int nr;
+
+       /*
+        * Some architectures may support loading an initrd alongside the flat kernel,
+        * but we do not.
+        */
+       if (fd_initrd != -1)
+               pr_warning("Loading initrd with flat binary not supported.");
+
+       if (lseek(fd_kernel, 0, SEEK_SET) < 0)
+               die_perror("lseek");
+
+       p = guest_real_to_host(kvm, BOOT_LOADER_SELECTOR, BOOT_LOADER_IP);
+
+       while ((nr = read(fd_kernel, p, 65536)) > 0)
+               p += nr;
+
+       kvm->boot_selector      = BOOT_LOADER_SELECTOR;
+       kvm->boot_ip            = BOOT_LOADER_IP;
+       kvm->boot_sp            = BOOT_LOADER_SP;
+
+       return true;
+}
+
+static const char *BZIMAGE_MAGIC = "HdrS";
+
+bool load_bzimage(struct kvm *kvm, int fd_kernel,
+                 int fd_initrd, const char *kernel_cmdline, u16 vidmode)
+{
+       struct boot_params *kern_boot;
+       unsigned long setup_sects;
+       struct boot_params boot;
+       size_t cmdline_size;
+       ssize_t setup_size;
+       void *p;
+       int nr;
+
+       /*
+        * See Documentation/x86/boot.txt for details no bzImage on-disk and
+        * memory layout.
+        */
+
+       if (lseek(fd_kernel, 0, SEEK_SET) < 0)
+               die_perror("lseek");
+
+       if (read(fd_kernel, &boot, sizeof(boot)) != sizeof(boot))
+               return false;
+
+       if (memcmp(&boot.hdr.header, BZIMAGE_MAGIC, strlen(BZIMAGE_MAGIC)))
+               return false;
+
+       if (boot.hdr.version < BOOT_PROTOCOL_REQUIRED)
+               die("Too old kernel");
+
+       if (lseek(fd_kernel, 0, SEEK_SET) < 0)
+               die_perror("lseek");
+
+       if (!boot.hdr.setup_sects)
+               boot.hdr.setup_sects = BZ_DEFAULT_SETUP_SECTS;
+       setup_sects = boot.hdr.setup_sects + 1;
+
+       setup_size = setup_sects << 9;
+       p = guest_real_to_host(kvm, BOOT_LOADER_SELECTOR, BOOT_LOADER_IP);
+
+       /* copy setup.bin to mem*/
+       if (read(fd_kernel, p, setup_size) != setup_size)
+               die_perror("read");
+
+       /* copy vmlinux.bin to BZ_KERNEL_START*/
+       p = guest_flat_to_host(kvm, BZ_KERNEL_START);
+
+       while ((nr = read(fd_kernel, p, 65536)) > 0)
+               p += nr;
+
+       p = guest_flat_to_host(kvm, BOOT_CMDLINE_OFFSET);
+       if (kernel_cmdline) {
+               cmdline_size = strlen(kernel_cmdline) + 1;
+               if (cmdline_size > boot.hdr.cmdline_size)
+                       cmdline_size = boot.hdr.cmdline_size;
+
+               memset(p, 0, boot.hdr.cmdline_size);
+               memcpy(p, kernel_cmdline, cmdline_size - 1);
+       }
+
+       kern_boot       = guest_real_to_host(kvm, BOOT_LOADER_SELECTOR, 0x00);
+
+       kern_boot->hdr.cmd_line_ptr     = BOOT_CMDLINE_OFFSET;
+       kern_boot->hdr.type_of_loader   = 0xff;
+       kern_boot->hdr.heap_end_ptr     = 0xfe00;
+       kern_boot->hdr.loadflags        |= CAN_USE_HEAP;
+       kern_boot->hdr.vid_mode         = vidmode;
+
+       /*
+        * Read initrd image into guest memory
+        */
+       if (fd_initrd >= 0) {
+               struct stat initrd_stat;
+               unsigned long addr;
+
+               if (fstat(fd_initrd, &initrd_stat))
+                       die_perror("fstat");
+
+               addr = boot.hdr.initrd_addr_max & ~0xfffff;
+               for (;;) {
+                       if (addr < BZ_KERNEL_START)
+                               die("Not enough memory for initrd");
+                       else if (addr < (kvm->ram_size - initrd_stat.st_size))
+                               break;
+                       addr -= 0x100000;
+               }
+
+               p = guest_flat_to_host(kvm, addr);
+               nr = read(fd_initrd, p, initrd_stat.st_size);
+               if (nr != initrd_stat.st_size)
+                       die("Failed to read initrd");
+
+               kern_boot->hdr.ramdisk_image    = addr;
+               kern_boot->hdr.ramdisk_size     = initrd_stat.st_size;
+       }
+
+       kvm->boot_selector = BOOT_LOADER_SELECTOR;
+       /*
+        * The real-mode setup code starts at offset 0x200 of a bzImage. See
+        * Documentation/x86/boot.txt for details.
+        */
+       kvm->boot_ip = BOOT_LOADER_IP + 0x200;
+       kvm->boot_sp = BOOT_LOADER_SP;
+
+       return true;
+}
+
+/**
+ * kvm__arch_setup_firmware - inject BIOS into guest system memory
+ * @kvm - guest system descriptor
+ *
+ * This function is a main routine where we poke guest memory
+ * and install BIOS there.
+ */
+int kvm__arch_setup_firmware(struct kvm *kvm)
+{
+       int r;
+
+       /* standart minimal configuration */
+       setup_bios(kvm);
+
+       /* FIXME: SMP, ACPI and friends here */
+
+       /* MP table */
+       r = mptable__init(kvm);
+
+       return r;
+}
+
+int kvm__arch_free_firmware(struct kvm *kvm)
+{
+       int r;
+
+       /* MP table */
+       r = mptable__exit(kvm);
+
+       return r;
+}
+
+void kvm__arch_periodic_poll(struct kvm *kvm)
+{
+       serial8250__update_consoles(kvm);
+       virtio_console__inject_interrupt(kvm);
+}
diff --git a/tools/kvm/x86/mptable.c b/tools/kvm/x86/mptable.c
new file mode 100644 (file)
index 0000000..12bdcf8
--- /dev/null
@@ -0,0 +1,287 @@
+#include "kvm/kvm.h"
+#include "kvm/bios.h"
+#include "kvm/apic.h"
+#include "kvm/mptable.h"
+#include "kvm/util.h"
+#include "kvm/irq.h"
+
+#include <linux/kernel.h>
+#include <string.h>
+
+#include <asm/mpspec_def.h>
+#include <linux/types.h>
+
+/*
+ * FIXME: please make sure the addresses borrowed
+ * for apic/ioapic never overlaped! We need a global
+ * tracker of system resources (including io, mmio,
+ * and friends).
+ */
+
+static unsigned int mpf_checksum(unsigned char *mp, int len)
+{
+       unsigned int sum = 0;
+
+       while (len--)
+               sum += *mp++;
+
+       return sum & 0xFF;
+}
+
+static unsigned int gen_cpu_flag(unsigned int cpu, unsigned int ncpu)
+{
+       /* sets enabled/disabled | BSP/AP processor */
+       return ( (cpu < ncpu) ? CPU_ENABLED       : 0) |
+               ((cpu == 0)   ? CPU_BOOTPROCESSOR : 0x00);
+}
+
+#define MPTABLE_SIG_FLOATING   "_MP_"
+#define MPTABLE_OEM            "KVMCPU00"
+#define MPTABLE_PRODUCTID      "0.1         "
+#define MPTABLE_PCIBUSTYPE     "PCI   "
+#define MPTABLE_ISABUSTYPE     "ISA   "
+
+#define MPTABLE_STRNCPY(d, s)  memcpy(d, s, sizeof(d))
+
+/* It should be more than enough */
+#define MPTABLE_MAX_SIZE       (32 << 20)
+
+/*
+ * Too many cpus will require x2apic mode
+ * and rather ACPI support so we limit it
+ * here for a while.
+ */
+#define MPTABLE_MAX_CPUS       255
+
+static void mptable_add_irq_src(struct mpc_intsrc *mpc_intsrc,
+                               u16 srcbusid,   u16 srcbusirq,
+                               u16 dstapic,    u16 dstirq)
+{
+       *mpc_intsrc = (struct mpc_intsrc) {
+               .type           = MP_INTSRC,
+               .irqtype        = mp_INT,
+               .irqflag        = MP_IRQDIR_DEFAULT,
+               .srcbus         = srcbusid,
+               .srcbusirq      = srcbusirq,
+               .dstapic        = dstapic,
+               .dstirq         = dstirq
+       };
+}
+
+/**
+ * mptable_setup - create mptable and fill guest memory with it
+ */
+int mptable__init(struct kvm *kvm)
+{
+       unsigned long real_mpc_table, real_mpf_intel, size;
+       struct mpf_intel *mpf_intel;
+       struct mpc_table *mpc_table;
+       struct mpc_cpu *mpc_cpu;
+       struct mpc_bus *mpc_bus;
+       struct mpc_ioapic *mpc_ioapic;
+       struct mpc_intsrc *mpc_intsrc;
+       struct rb_node *pci_tree;
+
+       const int pcibusid = 0;
+       const int isabusid = 1;
+
+       unsigned int i, nentries = 0, ncpus = kvm->nrcpus;
+       unsigned int ioapicid;
+       void *last_addr;
+
+       /* That is where MP table will be in guest memory */
+       real_mpc_table = ALIGN(MB_BIOS_BEGIN + bios_rom_size, 16);
+
+       if (ncpus > MPTABLE_MAX_CPUS) {
+               pr_warning("Too many cpus: %d limited to %d",
+                       ncpus, MPTABLE_MAX_CPUS);
+               ncpus = MPTABLE_MAX_CPUS;
+       }
+
+       mpc_table = calloc(1, MPTABLE_MAX_SIZE);
+       if (!mpc_table)
+               return -ENOMEM;
+
+       MPTABLE_STRNCPY(mpc_table->signature,   MPC_SIGNATURE);
+       MPTABLE_STRNCPY(mpc_table->oem,         MPTABLE_OEM);
+       MPTABLE_STRNCPY(mpc_table->productid,   MPTABLE_PRODUCTID);
+
+       mpc_table->spec         = 4;
+       mpc_table->lapic        = APIC_ADDR(0);
+       mpc_table->oemcount     = ncpus; /* will be updated again at end */
+
+       /*
+        * CPUs enumeration. Technically speaking we should
+        * ask either host or HV for apic version supported
+        * but for a while we simply put some random value
+        * here.
+        */
+       mpc_cpu = (void *)&mpc_table[1];
+       for (i = 0; i < ncpus; i++) {
+               mpc_cpu->type           = MP_PROCESSOR;
+               mpc_cpu->apicid         = i;
+               mpc_cpu->apicver        = KVM_APIC_VERSION;
+               mpc_cpu->cpuflag        = gen_cpu_flag(i, ncpus);
+               mpc_cpu->cpufeature     = 0x600; /* some default value */
+               mpc_cpu->featureflag    = 0x201; /* some default value */
+               mpc_cpu++;
+       }
+
+       last_addr = (void *)mpc_cpu;
+       nentries += ncpus;
+
+       /*
+        * PCI buses.
+        * FIXME: Some callback here to obtain real number
+        * of PCI buses present in system.
+        */
+       mpc_bus         = last_addr;
+       mpc_bus->type   = MP_BUS;
+       mpc_bus->busid  = pcibusid;
+       MPTABLE_STRNCPY(mpc_bus->bustype, MPTABLE_PCIBUSTYPE);
+
+       last_addr = (void *)&mpc_bus[1];
+       nentries++;
+
+       /*
+        * ISA bus.
+        * FIXME: Same issue as for PCI bus.
+        */
+       mpc_bus         = last_addr;
+       mpc_bus->type   = MP_BUS;
+       mpc_bus->busid  = isabusid;
+       MPTABLE_STRNCPY(mpc_bus->bustype, MPTABLE_ISABUSTYPE);
+
+       last_addr = (void *)&mpc_bus[1];
+       nentries++;
+
+       /*
+        * IO-APIC chip.
+        */
+       ioapicid                = ncpus + 1;
+       mpc_ioapic              = last_addr;
+       mpc_ioapic->type        = MP_IOAPIC;
+       mpc_ioapic->apicid      = ioapicid;
+       mpc_ioapic->apicver     = KVM_APIC_VERSION;
+       mpc_ioapic->flags       = MPC_APIC_USABLE;
+       mpc_ioapic->apicaddr    = IOAPIC_ADDR(0);
+
+       last_addr = (void *)&mpc_ioapic[1];
+       nentries++;
+
+       /*
+        * IRQ sources.
+        *
+        * FIXME: Same issue as with buses. We definitely
+        * need kind of collector routine which enumerate
+        * resources used first and pass them here.
+        * At moment we know we have only virtio block device
+        * and virtio console but this is g00berfish.
+        *
+        * Also note we use PCI irqs here, no for ISA bus yet.
+        */
+
+       for (pci_tree = irq__get_pci_tree(); pci_tree; pci_tree = rb_next(pci_tree)) {
+               struct pci_dev *dev = rb_entry(pci_tree, struct pci_dev, node);
+               struct irq_line *irq_line;
+
+               list_for_each_entry(irq_line, &dev->lines, node) {
+                       unsigned char srcbusirq;
+
+                       srcbusirq = (dev->id << 2) | (dev->pin - 1);
+
+                       mpc_intsrc = last_addr;
+
+                       mptable_add_irq_src(mpc_intsrc, pcibusid, srcbusirq, ioapicid, irq_line->line);
+                       last_addr = (void *)&mpc_intsrc[1];
+                       nentries++;
+               }
+       }
+
+       /*
+        * Local IRQs assignment (LINT0, LINT1)
+        */
+       mpc_intsrc              = last_addr;
+       mpc_intsrc->type        = MP_LINTSRC;
+       mpc_intsrc->irqtype     = mp_ExtINT;
+       mpc_intsrc->irqtype     = mp_INT;
+       mpc_intsrc->irqflag     = MP_IRQDIR_DEFAULT;
+       mpc_intsrc->srcbus      = isabusid;
+       mpc_intsrc->srcbusirq   = 0;
+       mpc_intsrc->dstapic     = 0; /* FIXME: BSP apic */
+       mpc_intsrc->dstirq      = 0; /* LINT0 */
+
+       last_addr = (void *)&mpc_intsrc[1];
+       nentries++;
+
+       mpc_intsrc              = last_addr;
+       mpc_intsrc->type        = MP_LINTSRC;
+       mpc_intsrc->irqtype     = mp_NMI;
+       mpc_intsrc->irqflag     = MP_IRQDIR_DEFAULT;
+       mpc_intsrc->srcbus      = isabusid;
+       mpc_intsrc->srcbusirq   = 0;
+       mpc_intsrc->dstapic     = 0; /* FIXME: BSP apic */
+       mpc_intsrc->dstirq      = 1; /* LINT1 */
+
+       last_addr = (void *)&mpc_intsrc[1];
+       nentries++;
+
+       /*
+        * Floating MP table finally.
+        */
+       real_mpf_intel  = ALIGN((unsigned long)last_addr - (unsigned long)mpc_table, 16);
+       mpf_intel       = (void *)((unsigned long)mpc_table + real_mpf_intel);
+
+       MPTABLE_STRNCPY(mpf_intel->signature, MPTABLE_SIG_FLOATING);
+       mpf_intel->length       = 1;
+       mpf_intel->specification= 4;
+       mpf_intel->physptr      = (unsigned int)real_mpc_table;
+       mpf_intel->checksum     = -mpf_checksum((unsigned char *)mpf_intel, sizeof(*mpf_intel));
+
+       /*
+        * No last_addr inclrement here please, we need last
+        * active position here to compute table size.
+        */
+
+       /*
+        * Don't forget to update header in fixed table.
+       */
+       mpc_table->oemcount     = nentries;
+       mpc_table->length       = last_addr - (void *)mpc_table;
+       mpc_table->checksum     = -mpf_checksum((unsigned char *)mpc_table, mpc_table->length);
+
+
+       /*
+        * We will copy the whole table, no need to separate
+        * floating structure and table itkvm.
+        */
+       size = (unsigned long)mpf_intel + sizeof(*mpf_intel) - (unsigned long)mpc_table;
+
+       /*
+        * The finial check -- never get out of system bios
+        * area. Lets also check for allocated memory overrun,
+        * in real it's late but still usefull.
+        */
+
+       if (size > (unsigned long)(MB_BIOS_END - bios_rom_size) ||
+           size > MPTABLE_MAX_SIZE) {
+               free(mpc_table);
+               pr_err("MP table is too big");
+
+               return -E2BIG;
+       }
+
+       /*
+        * OK, it is time to move it to guest memory.
+        */
+       memcpy(guest_flat_to_host(kvm, real_mpc_table), mpc_table, size);
+
+       free(mpc_table);
+
+       return 0;
+}
+
+int mptable__exit(struct kvm *kvm)
+{
+       return 0;
+}
index 77f124fe57ad54d8e45858f4e4429f6b63f42273..35655c3a7b7a438dd806b9d5a5fb8baa7102876a 100644 (file)
@@ -319,6 +319,8 @@ LIB_H += $(ARCH_INCLUDE)
 LIB_H += util/cgroup.h
 LIB_H += $(TRACE_EVENT_DIR)event-parse.h
 LIB_H += util/target.h
+LIB_H += util/rblist.h
+LIB_H += util/intlist.h
 
 LIB_OBJS += $(OUTPUT)util/abspath.o
 LIB_OBJS += $(OUTPUT)util/alias.o
@@ -383,6 +385,8 @@ LIB_OBJS += $(OUTPUT)util/xyarray.o
 LIB_OBJS += $(OUTPUT)util/cpumap.o
 LIB_OBJS += $(OUTPUT)util/cgroup.o
 LIB_OBJS += $(OUTPUT)util/target.o
+LIB_OBJS += $(OUTPUT)util/rblist.o
+LIB_OBJS += $(OUTPUT)util/intlist.o
 
 BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
 
@@ -983,7 +987,8 @@ clean:
        $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope*
        $(MAKE) -C Documentation/ clean
        $(RM) $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS
-       $(RM) $(OUTPUT)util/*-{bison,flex}*
+       $(RM) $(OUTPUT)util/*-bison*
+       $(RM) $(OUTPUT)util/*-flex*
        $(python-clean)
 
 .PHONY: all install clean strip $(LIBTRACEEVENT)
index f5a6452931e6dabaa4f3b4593ab91f30aa7d586b..4db6e1ba54e30bf780d990a8fb1d7b203e89707f 100644 (file)
@@ -313,7 +313,7 @@ try_again:
                }
        }
 
-       perf_session__update_sample_type(session);
+       perf_session__set_id_hdr_size(session);
 }
 
 static int process_buildids(struct perf_record *rec)
@@ -844,8 +844,6 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
        struct perf_record *rec = &record;
        char errbuf[BUFSIZ];
 
-       perf_header__set_cmdline(argc, argv);
-
        evsel_list = perf_evlist__new(NULL, NULL);
        if (evsel_list == NULL)
                return -ENOMEM;
index 69b1c1185159174f070425d15c17afc8d5325f50..7c88a243b5db04308c9faf2e6aaf32d19bf0bb54 100644 (file)
@@ -249,8 +249,9 @@ static int process_read_event(struct perf_tool *tool,
 static int perf_report__setup_sample_type(struct perf_report *rep)
 {
        struct perf_session *self = rep->session;
+       u64 sample_type = perf_evlist__sample_type(self->evlist);
 
-       if (!self->fd_pipe && !(self->sample_type & PERF_SAMPLE_CALLCHAIN)) {
+       if (!self->fd_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) {
                if (sort__has_parent) {
                        ui__error("Selected --sort parent, but no "
                                    "callchain data. Did you call "
@@ -274,7 +275,7 @@ static int perf_report__setup_sample_type(struct perf_report *rep)
 
        if (sort__branch_mode == 1) {
                if (!self->fd_pipe &&
-                   !(self->sample_type & PERF_SAMPLE_BRANCH_STACK)) {
+                   !(sample_type & PERF_SAMPLE_BRANCH_STACK)) {
                        ui__error("Selected -b but no branch data. "
                                  "Did you call perf record without -b?\n");
                        return -1;
index d909eb74a0eb74bc46ec8a9e6cb9d8acca5da7f2..1d592f5cbea9776fcc437e012dc20c1911fd7137 100644 (file)
@@ -478,7 +478,6 @@ static int test__basic_mmap(void)
        unsigned int nr_events[nsyscalls],
                     expected_nr_events[nsyscalls], i, j;
        struct perf_evsel *evsels[nsyscalls], *evsel;
-       int sample_size = __perf_evsel__sample_size(attr.sample_type);
 
        for (i = 0; i < nsyscalls; ++i) {
                char name[64];
@@ -563,8 +562,7 @@ static int test__basic_mmap(void)
                        goto out_munmap;
                }
 
-               err = perf_event__parse_sample(event, attr.sample_type, sample_size,
-                                              false, &sample, false);
+               err = perf_evlist__parse_sample(evlist, event, &sample, false);
                if (err) {
                        pr_err("Can't parse sample, err = %d\n", err);
                        goto out_munmap;
@@ -661,12 +659,12 @@ static int test__PERF_RECORD(void)
        const char *cmd = "sleep";
        const char *argv[] = { cmd, "1", NULL, };
        char *bname;
-       u64 sample_type, prev_time = 0;
+       u64 prev_time = 0;
        bool found_cmd_mmap = false,
             found_libc_mmap = false,
             found_vdso_mmap = false,
             found_ld_mmap = false;
-       int err = -1, errs = 0, i, wakeups = 0, sample_size;
+       int err = -1, errs = 0, i, wakeups = 0;
        u32 cpu;
        int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, };
 
@@ -756,13 +754,6 @@ static int test__PERF_RECORD(void)
                goto out_delete_evlist;
        }
 
-       /*
-        * We'll need these two to parse the PERF_SAMPLE_* fields in each
-        * event.
-        */
-       sample_type = perf_evlist__sample_type(evlist);
-       sample_size = __perf_evsel__sample_size(sample_type);
-
        /*
         * Now that all is properly set up, enable the events, they will
         * count just on workload.pid, which will start...
@@ -788,9 +779,7 @@ static int test__PERF_RECORD(void)
                                if (type < PERF_RECORD_MAX)
                                        nr_events[type]++;
 
-                               err = perf_event__parse_sample(event, sample_type,
-                                                              sample_size, true,
-                                                              &sample, false);
+                               err = perf_evlist__parse_sample(evlist, event, &sample, false);
                                if (err < 0) {
                                        if (verbose)
                                                perf_event__fprintf(event, stderr);
index 35e86c6df713d7af91bc50f98953d55f08cc4162..68cd61ef6ac5440c57579e42a935261d440e20f2 100644 (file)
@@ -38,6 +38,7 @@
 #include "util/cpumap.h"
 #include "util/xyarray.h"
 #include "util/sort.h"
+#include "util/intlist.h"
 
 #include "util/debug.h"
 
@@ -706,8 +707,16 @@ static void perf_event__process_sample(struct perf_tool *tool,
        int err;
 
        if (!machine && perf_guest) {
-               pr_err("Can't find guest [%d]'s kernel information\n",
-                       event->ip.pid);
+               static struct intlist *seen;
+
+               if (!seen)
+                       seen = intlist__new();
+
+               if (!intlist__has_entry(seen, event->ip.pid)) {
+                       pr_err("Can't find guest [%d]'s kernel information\n",
+                               event->ip.pid);
+                       intlist__add(seen, event->ip.pid);
+               }
                return;
        }
 
@@ -811,7 +820,7 @@ static void perf_top__mmap_read_idx(struct perf_top *top, int idx)
        int ret;
 
        while ((event = perf_evlist__mmap_read(top->evlist, idx)) != NULL) {
-               ret = perf_session__parse_sample(session, event, &sample);
+               ret = perf_evlist__parse_sample(top->evlist, event, &sample, false);
                if (ret) {
                        pr_err("Can't parse sample, err = %d\n", ret);
                        continue;
@@ -943,8 +952,10 @@ try_again:
                         * based cpu-clock-tick sw counter, which
                         * is always available even if no PMU support:
                         */
-                       if (attr->type == PERF_TYPE_HARDWARE &&
-                           attr->config == PERF_COUNT_HW_CPU_CYCLES) {
+                       if ((err == ENOENT || err == ENXIO) &&
+                           (attr->type == PERF_TYPE_HARDWARE) &&
+                           (attr->config == PERF_COUNT_HW_CPU_CYCLES)) {
+
                                if (verbose)
                                        ui__warning("Cycles event not supported,\n"
                                                    "trying to fall back to cpu-clock-ticks\n");
@@ -1032,7 +1043,7 @@ static int __cmd_top(struct perf_top *top)
                                               &top->session->host_machine);
        perf_top__start_counters(top);
        top->session->evlist = top->evlist;
-       perf_session__update_sample_type(top->session);
+       perf_session__set_id_hdr_size(top->session);
 
        /* Wait for a minimal set of events before starting the snapshot */
        poll(top->evlist->pollfd, top->evlist->nr_fds, 100);
index 1b197280c621fea866e3bfd90f71f3213971ee4a..d84870b0642627b11b81b5b5dc1c0abade1a09e4 100644 (file)
@@ -197,9 +197,6 @@ int perf_event__preprocess_sample(const union perf_event *self,
 
 const char *perf_event__name(unsigned int id);
 
-int perf_event__parse_sample(const union perf_event *event, u64 type,
-                            int sample_size, bool sample_id_all,
-                            struct perf_sample *sample, bool swapped);
 int perf_event__synthesize_sample(union perf_event *event, u64 type,
                                  const struct perf_sample *sample,
                                  bool swapped);
index 3edfd3483816dfa88ac49dc966d0c2a4db2b5923..9b38681add9e2d46e3a02b8ca0ffe48363a3e3c5 100644 (file)
@@ -881,3 +881,10 @@ int perf_evlist__start_workload(struct perf_evlist *evlist)
 
        return 0;
 }
+
+int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event,
+                             struct perf_sample *sample, bool swapped)
+{
+       struct perf_evsel *e = list_entry(evlist->entries.next, struct perf_evsel, node);
+       return perf_evsel__parse_sample(e, event, sample, swapped);
+}
index 40d4d3cdced0e081ec41863abe6ab46c562a3e3a..528c1acd9298443ce37afee8a2f3be515f49adfe 100644 (file)
@@ -122,6 +122,9 @@ u64 perf_evlist__sample_type(const struct perf_evlist *evlist);
 bool perf_evlist__sample_id_all(const const struct perf_evlist *evlist);
 u16 perf_evlist__id_hdr_size(const struct perf_evlist *evlist);
 
+int perf_evlist__parse_sample(struct perf_evlist *evlist, union perf_event *event,
+                             struct perf_sample *sample, bool swapped);
+
 bool perf_evlist__valid_sample_type(const struct perf_evlist *evlist);
 bool perf_evlist__valid_sample_id_all(const struct perf_evlist *evlist);
 
index e81771364867bd2b5d7bf52e38e9ae0984316a0a..2eaae140def26b5ef952d814e47a1a3179d8abbb 100644 (file)
@@ -20,7 +20,7 @@
 #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
 #define GROUP_FD(group_fd, cpu) (*(int *)xyarray__entry(group_fd, cpu, 0))
 
-int __perf_evsel__sample_size(u64 sample_type)
+static int __perf_evsel__sample_size(u64 sample_type)
 {
        u64 mask = sample_type & PERF_SAMPLE_MASK;
        int size = 0;
@@ -53,6 +53,7 @@ void perf_evsel__init(struct perf_evsel *evsel,
        evsel->attr        = *attr;
        INIT_LIST_HEAD(&evsel->node);
        hists__init(&evsel->hists);
+       evsel->sample_size = __perf_evsel__sample_size(attr->sample_type);
 }
 
 struct perf_evsel *perf_evsel__new(struct perf_event_attr *attr, int idx)
@@ -728,10 +729,10 @@ static bool sample_overlap(const union perf_event *event,
        return false;
 }
 
-int perf_event__parse_sample(const union perf_event *event, u64 type,
-                            int sample_size, bool sample_id_all,
+int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
                             struct perf_sample *data, bool swapped)
 {
+       u64 type = evsel->attr.sample_type;
        const u64 *array;
 
        /*
@@ -746,14 +747,14 @@ int perf_event__parse_sample(const union perf_event *event, u64 type,
        data->period = 1;
 
        if (event->header.type != PERF_RECORD_SAMPLE) {
-               if (!sample_id_all)
+               if (!evsel->attr.sample_id_all)
                        return 0;
                return perf_event__parse_id_sample(event, type, data, swapped);
        }
 
        array = event->sample.array;
 
-       if (sample_size + sizeof(event->header) > event->header.size)
+       if (evsel->sample_size + sizeof(event->header) > event->header.size)
                return -EFAULT;
 
        if (type & PERF_SAMPLE_IP) {
@@ -895,7 +896,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
                u.val32[1] = sample->tid;
                if (swapped) {
                        /*
-                        * Inverse of what is done in perf_event__parse_sample
+                        * Inverse of what is done in perf_evsel__parse_sample
                         */
                        u.val32[0] = bswap_32(u.val32[0]);
                        u.val32[1] = bswap_32(u.val32[1]);
@@ -930,7 +931,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
                u.val32[0] = sample->cpu;
                if (swapped) {
                        /*
-                        * Inverse of what is done in perf_event__parse_sample
+                        * Inverse of what is done in perf_evsel__parse_sample
                         */
                        u.val32[0] = bswap_32(u.val32[0]);
                        u.val64 = bswap_64(u.val64);
index 67cc5033d19234e28071523f51ecf7c7186822b1..b559929983bbefd2e991fdf26e338fe588570a66 100644 (file)
@@ -65,6 +65,7 @@ struct perf_evsel {
                void            *func;
                void            *data;
        } handler;
+       unsigned int            sample_size;
        bool                    supported;
 };
 
@@ -177,13 +178,8 @@ static inline int perf_evsel__read_scaled(struct perf_evsel *evsel,
        return __perf_evsel__read(evsel, ncpus, nthreads, true);
 }
 
-int __perf_evsel__sample_size(u64 sample_type);
-
-static inline int perf_evsel__sample_size(struct perf_evsel *evsel)
-{
-       return __perf_evsel__sample_size(evsel->attr.sample_type);
-}
-
 void hists__init(struct hists *hists);
 
+int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
+                            struct perf_sample *sample, bool swapped);
 #endif /* __PERF_EVSEL_H */
index 3a6d20443330b13d74b2b69b4c1d0e39cd5bb678..74ea3c2f81382c2881d9eda1e1cfb451b2a138f7 100644 (file)
@@ -174,6 +174,15 @@ perf_header__set_cmdline(int argc, const char **argv)
 {
        int i;
 
+       /*
+        * If header_argv has already been set, do not override it.
+        * This allows a command to set the cmdline, parse args and
+        * then call another builtin function that implements a
+        * command -- e.g, cmd_kvm calling cmd_record.
+        */
+       if (header_argv)
+               return 0;
+
        header_argc = (u32)argc;
 
        /* do not include NULL termination */
diff --git a/tools/perf/util/intlist.c b/tools/perf/util/intlist.c
new file mode 100644 (file)
index 0000000..fd530dc
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Based on intlist.c by:
+ * (c) 2009 Arnaldo Carvalho de Melo <acme@redhat.com>
+ *
+ * Licensed under the GPLv2.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <linux/compiler.h>
+
+#include "intlist.h"
+
+static struct rb_node *intlist__node_new(struct rblist *rblist __used,
+                                        const void *entry)
+{
+       int i = (int)((long)entry);
+       struct rb_node *rc = NULL;
+       struct int_node *node = malloc(sizeof(*node));
+
+       if (node != NULL) {
+               node->i = i;
+               rc = &node->rb_node;
+       }
+
+       return rc;
+}
+
+static void int_node__delete(struct int_node *ilist)
+{
+       free(ilist);
+}
+
+static void intlist__node_delete(struct rblist *rblist __used,
+                                struct rb_node *rb_node)
+{
+       struct int_node *node = container_of(rb_node, struct int_node, rb_node);
+
+       int_node__delete(node);
+}
+
+static int intlist__node_cmp(struct rb_node *rb_node, const void *entry)
+{
+       int i = (int)((long)entry);
+       struct int_node *node = container_of(rb_node, struct int_node, rb_node);
+
+       return node->i - i;
+}
+
+int intlist__add(struct intlist *ilist, int i)
+{
+       return rblist__add_node(&ilist->rblist, (void *)((long)i));
+}
+
+void intlist__remove(struct intlist *ilist __used, struct int_node *node)
+{
+       int_node__delete(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));
+
+       if (rb_node)
+               node = container_of(rb_node, struct int_node, rb_node);
+
+       return node;
+}
+
+struct intlist *intlist__new(void)
+{
+       struct intlist *ilist = malloc(sizeof(*ilist));
+
+       if (ilist != NULL) {
+               rblist__init(&ilist->rblist);
+               ilist->rblist.node_cmp    = intlist__node_cmp;
+               ilist->rblist.node_new    = intlist__node_new;
+               ilist->rblist.node_delete = intlist__node_delete;
+       }
+
+       return ilist;
+}
+
+void intlist__delete(struct intlist *ilist)
+{
+       if (ilist != NULL)
+               rblist__delete(&ilist->rblist);
+}
+
+struct int_node *intlist__entry(const struct intlist *ilist, unsigned int idx)
+{
+       struct int_node *node = NULL;
+       struct rb_node *rb_node;
+
+       rb_node = rblist__entry(&ilist->rblist, idx);
+       if (rb_node)
+               node = container_of(rb_node, struct int_node, rb_node);
+
+       return node;
+}
diff --git a/tools/perf/util/intlist.h b/tools/perf/util/intlist.h
new file mode 100644 (file)
index 0000000..6d63ab9
--- /dev/null
@@ -0,0 +1,75 @@
+#ifndef __PERF_INTLIST_H
+#define __PERF_INTLIST_H
+
+#include <linux/rbtree.h>
+#include <stdbool.h>
+
+#include "rblist.h"
+
+struct int_node {
+       struct rb_node rb_node;
+       int i;
+};
+
+struct intlist {
+       struct rblist rblist;
+};
+
+struct intlist *intlist__new(void);
+void intlist__delete(struct intlist *ilist);
+
+void intlist__remove(struct intlist *ilist, struct int_node *in);
+int intlist__add(struct intlist *ilist, int i);
+
+struct int_node *intlist__entry(const struct intlist *ilist, unsigned int idx);
+struct int_node *intlist__find(struct intlist *ilist, int i);
+
+static inline bool intlist__has_entry(struct intlist *ilist, int i)
+{
+       return intlist__find(ilist, i) != NULL;
+}
+
+static inline bool intlist__empty(const struct intlist *ilist)
+{
+       return rblist__empty(&ilist->rblist);
+}
+
+static inline unsigned int intlist__nr_entries(const struct intlist *ilist)
+{
+       return rblist__nr_entries(&ilist->rblist);
+}
+
+/* For intlist iteration */
+static inline struct int_node *intlist__first(struct intlist *ilist)
+{
+       struct rb_node *rn = rb_first(&ilist->rblist.entries);
+       return rn ? rb_entry(rn, struct int_node, rb_node) : NULL;
+}
+static inline struct int_node *intlist__next(struct int_node *in)
+{
+       struct rb_node *rn;
+       if (!in)
+               return NULL;
+       rn = rb_next(&in->rb_node);
+       return rn ? rb_entry(rn, struct int_node, rb_node) : NULL;
+}
+
+/**
+ * intlist_for_each      - iterate over a intlist
+ * @pos:       the &struct int_node to use as a loop cursor.
+ * @ilist:     the &struct intlist for loop.
+ */
+#define intlist__for_each(pos, ilist)  \
+       for (pos = intlist__first(ilist); pos; pos = intlist__next(pos))
+
+/**
+ * intlist_for_each_safe - iterate over a intlist safe against removal of
+ *                         int_node
+ * @pos:       the &struct int_node to use as a loop cursor.
+ * @n:         another &struct int_node to use as temporary storage.
+ * @ilist:     the &struct intlist for loop.
+ */
+#define intlist__for_each_safe(pos, n, ilist)  \
+       for (pos = intlist__first(ilist), n = intlist__next(pos); pos;\
+            pos = n, n = intlist__next(n))
+#endif /* __PERF_INTLIST_H */
index 1b997d2b89ce2638f63c01aee63c2b7884028427..127d648cc5488e6b1216ce3d3428c7a69e5157fb 100644 (file)
@@ -13,6 +13,9 @@ do { \
        } \
 } while (0)
 
+#define PERF_TP_SAMPLE_TYPE (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | \
+                            PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD)
+
 static int test__checkevent_tracepoint(struct perf_evlist *evlist)
 {
        struct perf_evsel *evsel = list_entry(evlist->entries.next,
@@ -21,8 +24,7 @@ static int test__checkevent_tracepoint(struct perf_evlist *evlist)
        TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->nr_entries);
        TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
        TEST_ASSERT_VAL("wrong sample_type",
-               (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
-               evsel->attr.sample_type);
+               PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type);
        TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
        return 0;
 }
@@ -37,8 +39,7 @@ static int test__checkevent_tracepoint_multi(struct perf_evlist *evlist)
                TEST_ASSERT_VAL("wrong type",
                        PERF_TYPE_TRACEPOINT == evsel->attr.type);
                TEST_ASSERT_VAL("wrong sample_type",
-                       (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU)
-                       == evsel->attr.sample_type);
+                       PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type);
                TEST_ASSERT_VAL("wrong sample_period",
                        1 == evsel->attr.sample_period);
        }
@@ -428,8 +429,7 @@ static int test__checkevent_list(struct perf_evlist *evlist)
        evsel = list_entry(evsel->node.next, struct perf_evsel, node);
        TEST_ASSERT_VAL("wrong type", PERF_TYPE_TRACEPOINT == evsel->attr.type);
        TEST_ASSERT_VAL("wrong sample_type",
-               (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | PERF_SAMPLE_CPU) ==
-               evsel->attr.sample_type);
+               PERF_TP_SAMPLE_TYPE == evsel->attr.sample_type);
        TEST_ASSERT_VAL("wrong sample_period", 1 == evsel->attr.sample_period);
        TEST_ASSERT_VAL("wrong exclude_user", evsel->attr.exclude_user);
        TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->attr.exclude_kernel);
index 99d02aa57dbf19a8c0cb1a1a3a900486ef956b65..594f8fad5ecd5ae3e858899173b1a18403335dc0 100644 (file)
@@ -1,6 +1,7 @@
 #include "util.h"
 #include "parse-options.h"
 #include "cache.h"
+#include "header.h"
 
 #define OPT_SHORT 1
 #define OPT_UNSET 2
@@ -413,6 +414,8 @@ int parse_options(int argc, const char **argv, const struct option *options,
 {
        struct parse_opt_ctx_t ctx;
 
+       perf_header__set_cmdline(argc, argv);
+
        parse_options_start(&ctx, argc, argv, flags);
        switch (parse_options_step(&ctx, options, usagestr)) {
        case PARSE_OPT_HELP:
index e03b58a4842431d51edaf68ec6da95cec6caadf5..0688bfb6d280a3b8ae3b8c0e3a474f51b9a404c2 100644 (file)
@@ -797,17 +797,13 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist,
 
        event = perf_evlist__mmap_read(evlist, cpu);
        if (event != NULL) {
-               struct perf_evsel *first;
                PyObject *pyevent = pyrf_event__new(event);
                struct pyrf_event *pevent = (struct pyrf_event *)pyevent;
 
                if (pyevent == NULL)
                        return PyErr_NoMemory();
 
-               first = list_entry(evlist->entries.next, struct perf_evsel, node);
-               err = perf_event__parse_sample(event, first->attr.sample_type,
-                                              perf_evsel__sample_size(first),
-                                              sample_id_all, &pevent->sample, false);
+               err = perf_evlist__parse_sample(evlist, event, &pevent->sample, false);
                if (err)
                        return PyErr_Format(PyExc_OSError,
                                            "perf: can't parse sample, err=%d", err);
diff --git a/tools/perf/util/rblist.c b/tools/perf/util/rblist.c
new file mode 100644 (file)
index 0000000..0171fb6
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Based on strlist.c by:
+ * (c) 2009 Arnaldo Carvalho de Melo <acme@redhat.com>
+ *
+ * Licensed under the GPLv2.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "rblist.h"
+
+int rblist__add_node(struct rblist *rblist, const void *new_entry)
+{
+       struct rb_node **p = &rblist->entries.rb_node;
+       struct rb_node *parent = NULL, *new_node;
+
+       while (*p != NULL) {
+               int rc;
+
+               parent = *p;
+
+               rc = rblist->node_cmp(parent, new_entry);
+               if (rc > 0)
+                       p = &(*p)->rb_left;
+               else if (rc < 0)
+                       p = &(*p)->rb_right;
+               else
+                       return -EEXIST;
+       }
+
+       new_node = rblist->node_new(rblist, new_entry);
+       if (new_node == NULL)
+               return -ENOMEM;
+
+       rb_link_node(new_node, parent, p);
+       rb_insert_color(new_node, &rblist->entries);
+       ++rblist->nr_entries;
+
+       return 0;
+}
+
+void rblist__remove_node(struct rblist *rblist, struct rb_node *rb_node)
+{
+       rb_erase(rb_node, &rblist->entries);
+       rblist->node_delete(rblist, rb_node);
+}
+
+struct rb_node *rblist__find(struct rblist *rblist, const void *entry)
+{
+       struct rb_node **p = &rblist->entries.rb_node;
+       struct rb_node *parent = NULL;
+
+       while (*p != NULL) {
+               int rc;
+
+               parent = *p;
+
+               rc = rblist->node_cmp(parent, entry);
+               if (rc > 0)
+                       p = &(*p)->rb_left;
+               else if (rc < 0)
+                       p = &(*p)->rb_right;
+               else
+                       return parent;
+       }
+
+       return NULL;
+}
+
+void rblist__init(struct rblist *rblist)
+{
+       if (rblist != NULL) {
+               rblist->entries  = RB_ROOT;
+               rblist->nr_entries = 0;
+       }
+
+       return;
+}
+
+void rblist__delete(struct rblist *rblist)
+{
+       if (rblist != NULL) {
+               struct rb_node *pos, *next = rb_first(&rblist->entries);
+
+               while (next) {
+                       pos = next;
+                       next = rb_next(pos);
+                       rb_erase(pos, &rblist->entries);
+                       rblist->node_delete(rblist, pos);
+               }
+               free(rblist);
+       }
+}
+
+struct rb_node *rblist__entry(const struct rblist *rblist, unsigned int idx)
+{
+       struct rb_node *node;
+
+       for (node = rb_first(&rblist->entries); node; node = rb_next(node)) {
+               if (!idx--)
+                       return node;
+       }
+
+       return NULL;
+}
diff --git a/tools/perf/util/rblist.h b/tools/perf/util/rblist.h
new file mode 100644 (file)
index 0000000..6d0cae5
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef __PERF_RBLIST_H
+#define __PERF_RBLIST_H
+
+#include <linux/rbtree.h>
+#include <stdbool.h>
+
+/*
+ * create node structs of the form:
+ * struct my_node {
+ *     struct rb_node rb_node;
+ *     ... my data ...
+ * };
+ *
+ * create list structs of the form:
+ * struct mylist {
+ *     struct rblist rblist;
+ *     ... my data ...
+ * };
+ */
+
+struct rblist {
+       struct rb_root entries;
+       unsigned int   nr_entries;
+
+       int (*node_cmp)(struct rb_node *rbn, const void *entry);
+       struct rb_node *(*node_new)(struct rblist *rlist, const void *new_entry);
+       void (*node_delete)(struct rblist *rblist, struct rb_node *rb_node);
+};
+
+void rblist__init(struct rblist *rblist);
+void rblist__delete(struct rblist *rblist);
+int rblist__add_node(struct rblist *rblist, const void *new_entry);
+void rblist__remove_node(struct rblist *rblist, struct rb_node *rb_node);
+struct rb_node *rblist__find(struct rblist *rblist, const void *entry);
+struct rb_node *rblist__entry(const struct rblist *rblist, unsigned int idx);
+
+static inline bool rblist__empty(const struct rblist *rblist)
+{
+       return rblist->nr_entries == 0;
+}
+
+static inline unsigned int rblist__nr_entries(const struct rblist *rblist)
+{
+       return rblist->nr_entries;
+}
+
+#endif /* __PERF_RBLIST_H */
index 8e4f0755d2aa8364d81fa714888d622d61f6a2db..2437fb0b463a21566ad9c8679861456e4f2b3f05 100644 (file)
@@ -80,14 +80,12 @@ out_close:
        return -1;
 }
 
-void perf_session__update_sample_type(struct perf_session *self)
+void perf_session__set_id_hdr_size(struct perf_session *session)
 {
-       self->sample_type = perf_evlist__sample_type(self->evlist);
-       self->sample_size = __perf_evsel__sample_size(self->sample_type);
-       self->sample_id_all = perf_evlist__sample_id_all(self->evlist);
-       self->id_hdr_size = perf_evlist__id_hdr_size(self->evlist);
-       self->host_machine.id_hdr_size = self->id_hdr_size;
-       machines__set_id_hdr_size(&self->machines, self->id_hdr_size);
+       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)
@@ -147,7 +145,7 @@ struct perf_session *perf_session__new(const char *filename, int mode,
        if (mode == O_RDONLY) {
                if (perf_session__open(self, force) < 0)
                        goto out_delete;
-               perf_session__update_sample_type(self);
+               perf_session__set_id_hdr_size(self);
        } else if (mode == O_WRONLY) {
                /*
                 * In O_RDONLY mode this will be performed when reading the
@@ -158,7 +156,7 @@ struct perf_session *perf_session__new(const char *filename, int mode,
        }
 
        if (tool && tool->ordering_requires_timestamps &&
-           tool->ordered_samples && !self->sample_id_all) {
+           tool->ordered_samples && !perf_evlist__sample_id_all(self->evlist)) {
                dump_printf("WARNING: No sample_id_all support, falling back to unordered processing\n");
                tool->ordered_samples = false;
        }
@@ -673,7 +671,8 @@ static void flush_sample_queue(struct perf_session *s,
                if (iter->timestamp > limit)
                        break;
 
-               ret = perf_session__parse_sample(s, iter->event, &sample);
+               ret = perf_evlist__parse_sample(s->evlist, iter->event, &sample,
+                                               s->header.needs_swap);
                if (ret)
                        pr_err("Can't parse sample, err = %d\n", ret);
                else
@@ -865,16 +864,18 @@ static void perf_session__print_tstamp(struct perf_session *session,
                                       union perf_event *event,
                                       struct perf_sample *sample)
 {
+       u64 sample_type = perf_evlist__sample_type(session->evlist);
+
        if (event->header.type != PERF_RECORD_SAMPLE &&
-           !session->sample_id_all) {
+           !perf_evlist__sample_id_all(session->evlist)) {
                fputs("-1 -1 ", stdout);
                return;
        }
 
-       if ((session->sample_type & PERF_SAMPLE_CPU))
+       if ((sample_type & PERF_SAMPLE_CPU))
                printf("%u ", sample->cpu);
 
-       if (session->sample_type & PERF_SAMPLE_TIME)
+       if (sample_type & PERF_SAMPLE_TIME)
                printf("%" PRIu64 " ", sample->time);
 }
 
@@ -899,6 +900,8 @@ static void dump_event(struct perf_session *session, union perf_event *event,
 static void dump_sample(struct perf_session *session, union perf_event *event,
                        struct perf_sample *sample)
 {
+       u64 sample_type;
+
        if (!dump_trace)
                return;
 
@@ -906,10 +909,12 @@ static void dump_sample(struct perf_session *session, union perf_event *event,
               event->header.misc, sample->pid, sample->tid, sample->ip,
               sample->period, sample->addr);
 
-       if (session->sample_type & PERF_SAMPLE_CALLCHAIN)
+       sample_type = perf_evlist__sample_type(session->evlist);
+
+       if (sample_type & PERF_SAMPLE_CALLCHAIN)
                callchain__printf(sample);
 
-       if (session->sample_type & PERF_SAMPLE_BRANCH_STACK)
+       if (sample_type & PERF_SAMPLE_BRANCH_STACK)
                branch_stack__printf(sample);
 }
 
@@ -1006,7 +1011,7 @@ static int perf_session__preprocess_sample(struct perf_session *session,
                                           union perf_event *event, struct perf_sample *sample)
 {
        if (event->header.type != PERF_RECORD_SAMPLE ||
-           !(session->sample_type & PERF_SAMPLE_CALLCHAIN))
+           !(perf_evlist__sample_type(session->evlist) & PERF_SAMPLE_CALLCHAIN))
                return 0;
 
        if (!ip_callchain__valid(sample->callchain, event)) {
@@ -1030,7 +1035,7 @@ static int perf_session__process_user_event(struct perf_session *session, union
        case PERF_RECORD_HEADER_ATTR:
                err = tool->attr(event, &session->evlist);
                if (err == 0)
-                       perf_session__update_sample_type(session);
+                       perf_session__set_id_hdr_size(session);
                return err;
        case PERF_RECORD_HEADER_EVENT_TYPE:
                return tool->event_type(tool, event);
@@ -1065,7 +1070,7 @@ static int perf_session__process_event(struct perf_session *session,
        int ret;
 
        if (session->header.needs_swap)
-               event_swap(event, session->sample_id_all);
+               event_swap(event, perf_evlist__sample_id_all(session->evlist));
 
        if (event->header.type >= PERF_RECORD_HEADER_MAX)
                return -EINVAL;
@@ -1078,7 +1083,8 @@ static int perf_session__process_event(struct perf_session *session,
        /*
         * For all kernel events we get the sample data
         */
-       ret = perf_session__parse_sample(session, event, &sample);
+       ret = perf_evlist__parse_sample(session->evlist, event, &sample,
+                                       session->header.needs_swap);
        if (ret)
                return ret;
 
@@ -1389,9 +1395,9 @@ int perf_session__process_events(struct perf_session *self,
        return err;
 }
 
-bool perf_session__has_traces(struct perf_session *self, const char *msg)
+bool perf_session__has_traces(struct perf_session *session, const char *msg)
 {
-       if (!(self->sample_type & PERF_SAMPLE_RAW)) {
+       if (!(perf_evlist__sample_type(session->evlist) & PERF_SAMPLE_RAW)) {
                pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg);
                return false;
        }
index 7c435bde6eb0ea1f913e1dadfca3da0c23432302..1f7ec87db7d7369083895d596a979db460865d23 100644 (file)
@@ -41,13 +41,9 @@ struct perf_session {
         *        perf.data file.
         */
        struct hists            hists;
-       u64                     sample_type;
-       int                     sample_size;
        int                     fd;
        bool                    fd_pipe;
        bool                    repipe;
-       bool                    sample_id_all;
-       u16                     id_hdr_size;
        int                     cwdlen;
        char                    *cwd;
        struct ordered_samples  ordered_samples;
@@ -86,7 +82,7 @@ void perf_event__attr_swap(struct perf_event_attr *attr);
 
 int perf_session__create_kernel_maps(struct perf_session *self);
 
-void perf_session__update_sample_type(struct perf_session *self);
+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
@@ -130,24 +126,6 @@ size_t perf_session__fprintf_dsos_buildid(struct perf_session *self,
 
 size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp);
 
-static inline int perf_session__parse_sample(struct perf_session *session,
-                                            const union perf_event *event,
-                                            struct perf_sample *sample)
-{
-       return perf_event__parse_sample(event, session->sample_type,
-                                       session->sample_size,
-                                       session->sample_id_all, sample,
-                                       session->header.needs_swap);
-}
-
-static inline int perf_session__synthesize_sample(struct perf_session *session,
-                                                 union perf_event *event,
-                                                 const struct perf_sample *sample)
-{
-       return perf_event__synthesize_sample(event, session->sample_type,
-                                            sample, session->header.needs_swap);
-}
-
 struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session,
                                            unsigned int type);
 
index 6783a2043555404f393bcb3bd41e6a13d3495bc6..95856ff3dda417276792c98df568a56ea0c86bd8 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 
-static struct str_node *str_node__new(const char *s, bool dupstr)
+static
+struct rb_node *strlist__node_new(struct rblist *rblist, const void *entry)
 {
-       struct str_node *self = malloc(sizeof(*self));
+       const char *s = entry;
+       struct rb_node *rc = NULL;
+       struct strlist *strlist = container_of(rblist, struct strlist, rblist);
+       struct str_node *snode = malloc(sizeof(*snode));
 
-       if (self != NULL) {
-               if (dupstr) {
+       if (snode != NULL) {
+               if (strlist->dupstr) {
                        s = strdup(s);
                        if (s == NULL)
                                goto out_delete;
                }
-               self->s = s;
+               snode->s = s;
+               rc = &snode->rb_node;
        }
 
-       return self;
+       return rc;
 
 out_delete:
-       free(self);
+       free(snode);
        return NULL;
 }
 
@@ -37,36 +42,26 @@ static void str_node__delete(struct str_node *self, bool dupstr)
        free(self);
 }
 
-int strlist__add(struct strlist *self, const char *new_entry)
+static
+void strlist__node_delete(struct rblist *rblist, struct rb_node *rb_node)
 {
-       struct rb_node **p = &self->entries.rb_node;
-       struct rb_node *parent = NULL;
-       struct str_node *sn;
-
-       while (*p != NULL) {
-               int rc;
-
-               parent = *p;
-               sn = rb_entry(parent, struct str_node, rb_node);
-               rc = strcmp(sn->s, new_entry);
-
-               if (rc > 0)
-                       p = &(*p)->rb_left;
-               else if (rc < 0)
-                       p = &(*p)->rb_right;
-               else
-                       return -EEXIST;
-       }
+       struct strlist *slist = container_of(rblist, struct strlist, rblist);
+       struct str_node *snode = container_of(rb_node, struct str_node, rb_node);
 
-       sn = str_node__new(new_entry, self->dupstr);
-       if (sn == NULL)
-               return -ENOMEM;
+       str_node__delete(snode, slist->dupstr);
+}
 
-       rb_link_node(&sn->rb_node, parent, p);
-       rb_insert_color(&sn->rb_node, &self->entries);
-       ++self->nr_entries;
+static int strlist__node_cmp(struct rb_node *rb_node, const void *entry)
+{
+       const char *str = entry;
+       struct str_node *snode = container_of(rb_node, struct str_node, rb_node);
+
+       return strcmp(snode->s, str);
+}
 
-       return 0;
+int strlist__add(struct strlist *self, const char *new_entry)
+{
+       return rblist__add_node(&self->rblist, new_entry);
 }
 
 int strlist__load(struct strlist *self, const char *filename)
@@ -96,34 +91,20 @@ out:
        return err;
 }
 
-void strlist__remove(struct strlist *self, struct str_node *sn)
+void strlist__remove(struct strlist *slist, struct str_node *snode)
 {
-       rb_erase(&sn->rb_node, &self->entries);
-       str_node__delete(sn, self->dupstr);
+       str_node__delete(snode, slist->dupstr);
 }
 
-struct str_node *strlist__find(struct strlist *self, const char *entry)
+struct str_node *strlist__find(struct strlist *slist, const char *entry)
 {
-       struct rb_node **p = &self->entries.rb_node;
-       struct rb_node *parent = NULL;
-
-       while (*p != NULL) {
-               struct str_node *sn;
-               int rc;
-
-               parent = *p;
-               sn = rb_entry(parent, struct str_node, rb_node);
-               rc = strcmp(sn->s, entry);
-
-               if (rc > 0)
-                       p = &(*p)->rb_left;
-               else if (rc < 0)
-                       p = &(*p)->rb_right;
-               else
-                       return sn;
-       }
+       struct str_node *snode = NULL;
+       struct rb_node *rb_node = rblist__find(&slist->rblist, entry);
 
-       return NULL;
+       if (rb_node)
+               snode = container_of(rb_node, struct str_node, rb_node);
+
+       return snode;
 }
 
 static int strlist__parse_list_entry(struct strlist *self, const char *s)
@@ -156,9 +137,12 @@ struct strlist *strlist__new(bool dupstr, const char *slist)
        struct strlist *self = malloc(sizeof(*self));
 
        if (self != NULL) {
-               self->entries    = RB_ROOT;
+               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;
+
                self->dupstr     = dupstr;
-               self->nr_entries = 0;
                if (slist && strlist__parse_list(self, slist) != 0)
                        goto out_error;
        }
@@ -171,30 +155,18 @@ out_error:
 
 void strlist__delete(struct strlist *self)
 {
-       if (self != NULL) {
-               struct str_node *pos;
-               struct rb_node *next = rb_first(&self->entries);
-
-               while (next) {
-                       pos = rb_entry(next, struct str_node, rb_node);
-                       next = rb_next(&pos->rb_node);
-                       strlist__remove(self, pos);
-               }
-               self->entries = RB_ROOT;
-               free(self);
-       }
+       if (self != NULL)
+               rblist__delete(&self->rblist);
 }
 
-struct str_node *strlist__entry(const struct strlist *self, unsigned int idx)
+struct str_node *strlist__entry(const struct strlist *slist, unsigned int idx)
 {
-       struct rb_node *nd;
+       struct str_node *snode = NULL;
+       struct rb_node *rb_node;
 
-       for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
-               struct str_node *pos = rb_entry(nd, struct str_node, rb_node);
+       rb_node = rblist__entry(&slist->rblist, idx);
+       if (rb_node)
+               snode = container_of(rb_node, struct str_node, rb_node);
 
-               if (!idx--)
-                       return pos;
-       }
-
-       return NULL;
+       return snode;
 }
index 3ba839007d2c975c49e4f3f286e9d64eff3d3f60..dd9f922ec67c58845ff22b6d3fabe3eb888c21e6 100644 (file)
@@ -4,14 +4,15 @@
 #include <linux/rbtree.h>
 #include <stdbool.h>
 
+#include "rblist.h"
+
 struct str_node {
        struct rb_node rb_node;
        const char     *s;
 };
 
 struct strlist {
-       struct rb_root entries;
-       unsigned int   nr_entries;
+       struct rblist rblist;
        bool           dupstr;
 };
 
@@ -32,18 +33,18 @@ static inline bool strlist__has_entry(struct strlist *self, const char *entry)
 
 static inline bool strlist__empty(const struct strlist *self)
 {
-       return self->nr_entries == 0;
+       return rblist__empty(&self->rblist);
 }
 
 static inline unsigned int strlist__nr_entries(const struct strlist *self)
 {
-       return self->nr_entries;
+       return rblist__nr_entries(&self->rblist);
 }
 
 /* For strlist iteration */
 static inline struct str_node *strlist__first(struct strlist *self)
 {
-       struct rb_node *rn = rb_first(&self->entries);
+       struct rb_node *rn = rb_first(&self->rblist.entries);
        return rn ? rb_entry(rn, struct str_node, rb_node) : NULL;
 }
 static inline struct str_node *strlist__next(struct str_node *sn)
index fdad4eeeb429c1fce9ef90125aab3e4a288c6066..8b63b678e127ba5253477db6c65355e28ae49e66 100644 (file)
@@ -64,7 +64,7 @@ static enum dso_binary_type binary_type_symtab[] = {
        DSO_BINARY_TYPE__NOT_FOUND,
 };
 
-#define DSO_BINARY_TYPE__SYMTAB_CNT sizeof(binary_type_symtab)
+#define DSO_BINARY_TYPE__SYMTAB_CNT ARRAY_SIZE(binary_type_symtab)
 
 static enum dso_binary_type binary_type_data[] = {
        DSO_BINARY_TYPE__BUILD_ID_CACHE,
@@ -72,7 +72,7 @@ static enum dso_binary_type binary_type_data[] = {
        DSO_BINARY_TYPE__NOT_FOUND,
 };
 
-#define DSO_BINARY_TYPE__DATA_CNT sizeof(binary_type_data)
+#define DSO_BINARY_TYPE__DATA_CNT ARRAY_SIZE(binary_type_data)
 
 int dso__name_len(const struct dso *dso)
 {
@@ -2875,6 +2875,7 @@ int machines__create_guest_kernel_maps(struct rb_root *machines)
        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 ||
@@ -2891,7 +2892,14 @@ int machines__create_guest_kernel_maps(struct rb_root *machines)
                                /* Filter out . and .. */
                                continue;
                        }
-                       pid = atoi(namelist[i]->d_name);
+                       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);
index 3f59c496e64c9035311389fb73e9468fb47e7889..051eaa68095e75a61b82aac4c479cf4c8101ef71 100644 (file)
@@ -110,7 +110,7 @@ int perf_target__strerror(struct perf_target *target, int errnum,
        int idx;
        const char *msg;
 
-       BUG_ON(buflen > 0);
+       BUG_ON(buflen == 0);
 
        if (errnum >= 0) {
                const char *err = strerror_r(errnum, buf, buflen);
index 28694f4a91398998f569c234c7faee104a945259..d01b24b72c61e75f3225776541c2f99824df443e 100644 (file)
@@ -21,3 +21,6 @@ config KVM_ASYNC_PF
 
 config HAVE_KVM_MSI
        bool
+
+config HAVE_KVM_CPU_RELAX_INTERCEPT
+       bool
index 74268b4c2ee167932d514281bf6ecc3187462a3e..ea475cd035112a9db93ffa028a552df9be0724af 100644 (file)
@@ -111,8 +111,8 @@ void kvm_clear_async_pf_completion_queue(struct kvm_vcpu *vcpu)
                        list_entry(vcpu->async_pf.done.next,
                                   typeof(*work), link);
                list_del(&work->link);
-               if (work->page)
-                       put_page(work->page);
+               if (!is_error_page(work->page))
+                       kvm_release_page_clean(work->page);
                kmem_cache_free(async_pf_cache, work);
        }
        spin_unlock(&vcpu->async_pf.lock);
@@ -138,8 +138,8 @@ void kvm_check_async_pf_completion(struct kvm_vcpu *vcpu)
 
                list_del(&work->queue);
                vcpu->async_pf.queued--;
-               if (work->page)
-                       put_page(work->page);
+               if (!is_error_page(work->page))
+                       kvm_release_page_clean(work->page);
                kmem_cache_free(async_pf_cache, work);
        }
 }
@@ -203,8 +203,7 @@ int kvm_async_pf_wakeup_all(struct kvm_vcpu *vcpu)
        if (!work)
                return -ENOMEM;
 
-       work->page = bad_page;
-       get_page(bad_page);
+       work->page = KVM_ERR_PTR_BAD_PAGE;
        INIT_LIST_HEAD(&work->queue); /* for list_del to work */
 
        spin_lock(&vcpu->async_pf.lock);
index e9fff9830bf0bf6f2229603516ebdd633996fd20..037cb6730e68eef3171b0e9660d1139b423d96de 100644 (file)
@@ -42,13 +42,13 @@ static int kvm_iommu_unmap_memslots(struct kvm *kvm);
 static void kvm_iommu_put_pages(struct kvm *kvm,
                                gfn_t base_gfn, unsigned long npages);
 
-static pfn_t kvm_pin_pages(struct kvm *kvm, struct kvm_memory_slot *slot,
-                          gfn_t gfn, unsigned long size)
+static pfn_t kvm_pin_pages(struct kvm_memory_slot *slot, gfn_t gfn,
+                          unsigned long size)
 {
        gfn_t end_gfn;
        pfn_t pfn;
 
-       pfn     = gfn_to_pfn_memslot(kvm, slot, gfn);
+       pfn     = gfn_to_pfn_memslot(slot, gfn);
        end_gfn = gfn + (size >> PAGE_SHIFT);
        gfn    += 1;
 
@@ -56,7 +56,7 @@ static pfn_t kvm_pin_pages(struct kvm *kvm, struct kvm_memory_slot *slot,
                return pfn;
 
        while (gfn < end_gfn)
-               gfn_to_pfn_memslot(kvm, slot, gfn++);
+               gfn_to_pfn_memslot(slot, gfn++);
 
        return pfn;
 }
@@ -105,7 +105,7 @@ int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot)
                 * Pin all pages we are about to map in memory. This is
                 * important because we unmap and unpin in 4kb steps later.
                 */
-               pfn = kvm_pin_pages(kvm, slot, gfn, page_size);
+               pfn = kvm_pin_pages(slot, gfn, page_size);
                if (is_error_pfn(pfn)) {
                        gfn += 1;
                        continue;
@@ -300,6 +300,12 @@ static void kvm_iommu_put_pages(struct kvm *kvm,
 
                /* Get physical address */
                phys = iommu_iova_to_phys(domain, gfn_to_gpa(gfn));
+
+               if (!phys) {
+                       gfn++;
+                       continue;
+               }
+
                pfn  = phys >> PAGE_SHIFT;
 
                /* Unmap address from IO address space */
index 83402d74a767bec214d2c2467cceb3a271a6be44..7118be0f2f2c804e33e9944a1afb92dce4f72b2b 100644 (file)
@@ -321,11 +321,11 @@ static int setup_routing_entry(struct kvm_irq_routing_table *rt,
                switch (ue->u.irqchip.irqchip) {
                case KVM_IRQCHIP_PIC_MASTER:
                        e->set = kvm_set_pic_irq;
-                       max_pin = 16;
+                       max_pin = PIC_NUM_PINS;
                        break;
                case KVM_IRQCHIP_PIC_SLAVE:
                        e->set = kvm_set_pic_irq;
-                       max_pin = 16;
+                       max_pin = PIC_NUM_PINS;
                        delta = 8;
                        break;
                case KVM_IRQCHIP_IOAPIC:
index 246852397e301ee86ac5c40f653e4695eae659a8..a2e85af847c1cb6e4664c311256daf7548a3a286 100644 (file)
@@ -100,13 +100,7 @@ EXPORT_SYMBOL_GPL(kvm_rebooting);
 
 static bool largepages_enabled = true;
 
-static struct page *hwpoison_page;
-static pfn_t hwpoison_pfn;
-
-struct page *fault_page;
-pfn_t fault_pfn;
-
-inline int kvm_is_mmio_pfn(pfn_t pfn)
+bool kvm_is_mmio_pfn(pfn_t pfn)
 {
        if (pfn_valid(pfn)) {
                int reserved;
@@ -236,6 +230,9 @@ int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id)
        }
        vcpu->run = page_address(page);
 
+       kvm_vcpu_set_in_spin_loop(vcpu, false);
+       kvm_vcpu_set_dy_eligible(vcpu, false);
+
        r = kvm_arch_vcpu_init(vcpu);
        if (r < 0)
                goto fail_free_run;
@@ -332,8 +329,7 @@ static void kvm_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn,
         * count is also read inside the mmu_lock critical section.
         */
        kvm->mmu_notifier_count++;
-       for (; start < end; start += PAGE_SIZE)
-               need_tlb_flush |= kvm_unmap_hva(kvm, start);
+       need_tlb_flush = kvm_unmap_hva_range(kvm, start, end);
        need_tlb_flush |= kvm->tlbs_dirty;
        /* we've to flush the tlb before the pages can be freed */
        if (need_tlb_flush)
@@ -551,16 +547,12 @@ static void kvm_destroy_dirty_bitmap(struct kvm_memory_slot *memslot)
 static void kvm_free_physmem_slot(struct kvm_memory_slot *free,
                                  struct kvm_memory_slot *dont)
 {
-       if (!dont || free->rmap != dont->rmap)
-               vfree(free->rmap);
-
        if (!dont || free->dirty_bitmap != dont->dirty_bitmap)
                kvm_destroy_dirty_bitmap(free);
 
        kvm_arch_free_memslot(free, dont);
 
        free->npages = 0;
-       free->rmap = NULL;
 }
 
 void kvm_free_physmem(struct kvm *kvm)
@@ -769,11 +761,7 @@ int __kvm_set_memory_region(struct kvm *kvm,
        if (npages && !old.npages) {
                new.user_alloc = user_alloc;
                new.userspace_addr = mem->userspace_addr;
-#ifndef CONFIG_S390
-               new.rmap = vzalloc(npages * sizeof(*new.rmap));
-               if (!new.rmap)
-                       goto out_free;
-#endif /* not defined CONFIG_S390 */
+
                if (kvm_arch_create_memslot(&new, npages))
                        goto out_free;
        }
@@ -832,7 +820,6 @@ int __kvm_set_memory_region(struct kvm *kvm,
 
        /* actual memory is freed via old in kvm_free_physmem_slot below */
        if (!npages) {
-               new.rmap = NULL;
                new.dirty_bitmap = NULL;
                memset(&new.arch, 0, sizeof(new.arch));
        }
@@ -932,42 +919,6 @@ void kvm_disable_largepages(void)
 }
 EXPORT_SYMBOL_GPL(kvm_disable_largepages);
 
-int is_error_page(struct page *page)
-{
-       return page == bad_page || page == hwpoison_page || page == fault_page;
-}
-EXPORT_SYMBOL_GPL(is_error_page);
-
-int is_error_pfn(pfn_t pfn)
-{
-       return pfn == bad_pfn || pfn == hwpoison_pfn || pfn == fault_pfn;
-}
-EXPORT_SYMBOL_GPL(is_error_pfn);
-
-int is_hwpoison_pfn(pfn_t pfn)
-{
-       return pfn == hwpoison_pfn;
-}
-EXPORT_SYMBOL_GPL(is_hwpoison_pfn);
-
-int is_fault_pfn(pfn_t pfn)
-{
-       return pfn == fault_pfn;
-}
-EXPORT_SYMBOL_GPL(is_fault_pfn);
-
-int is_noslot_pfn(pfn_t pfn)
-{
-       return pfn == bad_pfn;
-}
-EXPORT_SYMBOL_GPL(is_noslot_pfn);
-
-int is_invalid_pfn(pfn_t pfn)
-{
-       return pfn == hwpoison_pfn || pfn == fault_pfn;
-}
-EXPORT_SYMBOL_GPL(is_invalid_pfn);
-
 static inline unsigned long bad_hva(void)
 {
        return PAGE_OFFSET;
@@ -1039,12 +990,6 @@ unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn)
 }
 EXPORT_SYMBOL_GPL(gfn_to_hva);
 
-static pfn_t get_fault_pfn(void)
-{
-       get_page(fault_page);
-       return fault_pfn;
-}
-
 int get_user_page_nowait(struct task_struct *tsk, struct mm_struct *mm,
        unsigned long start, int write, struct page **page)
 {
@@ -1065,8 +1010,8 @@ static inline int check_user_page_hwpoison(unsigned long addr)
        return rc == -EHWPOISON;
 }
 
-static pfn_t hva_to_pfn(struct kvm *kvm, unsigned long addr, bool atomic,
-                       bool *async, bool write_fault, bool *writable)
+static pfn_t hva_to_pfn(unsigned long addr, bool atomic, bool *async,
+                       bool write_fault, bool *writable)
 {
        struct page *page[1];
        int npages = 0;
@@ -1116,20 +1061,19 @@ static pfn_t hva_to_pfn(struct kvm *kvm, unsigned long addr, bool atomic,
                struct vm_area_struct *vma;
 
                if (atomic)
-                       return get_fault_pfn();
+                       return KVM_PFN_ERR_FAULT;
 
                down_read(&current->mm->mmap_sem);
                if (npages == -EHWPOISON ||
                        (!async && check_user_page_hwpoison(addr))) {
                        up_read(&current->mm->mmap_sem);
-                       get_page(hwpoison_page);
-                       return page_to_pfn(hwpoison_page);
+                       return KVM_PFN_ERR_HWPOISON;
                }
 
                vma = find_vma_intersection(current->mm, addr, addr+1);
 
                if (vma == NULL)
-                       pfn = get_fault_pfn();
+                       pfn = KVM_PFN_ERR_FAULT;
                else if ((vma->vm_flags & VM_PFNMAP)) {
                        pfn = ((addr - vma->vm_start) >> PAGE_SHIFT) +
                                vma->vm_pgoff;
@@ -1137,7 +1081,7 @@ static pfn_t hva_to_pfn(struct kvm *kvm, unsigned long addr, bool atomic,
                } else {
                        if (async && (vma->vm_flags & VM_WRITE))
                                *async = true;
-                       pfn = get_fault_pfn();
+                       pfn = KVM_PFN_ERR_FAULT;
                }
                up_read(&current->mm->mmap_sem);
        } else
@@ -1146,9 +1090,9 @@ static pfn_t hva_to_pfn(struct kvm *kvm, unsigned long addr, bool atomic,
        return pfn;
 }
 
-pfn_t hva_to_pfn_atomic(struct kvm *kvm, unsigned long addr)
+pfn_t hva_to_pfn_atomic(unsigned long addr)
 {
-       return hva_to_pfn(kvm, addr, true, NULL, true, NULL);
+       return hva_to_pfn(addr, true, NULL, true, NULL);
 }
 EXPORT_SYMBOL_GPL(hva_to_pfn_atomic);
 
@@ -1161,12 +1105,10 @@ static pfn_t __gfn_to_pfn(struct kvm *kvm, gfn_t gfn, bool atomic, bool *async,
                *async = false;
 
        addr = gfn_to_hva(kvm, gfn);
-       if (kvm_is_error_hva(addr)) {
-               get_page(bad_page);
-               return page_to_pfn(bad_page);
-       }
+       if (kvm_is_error_hva(addr))
+               return KVM_PFN_ERR_BAD;
 
-       return hva_to_pfn(kvm, addr, atomic, async, write_fault, writable);
+       return hva_to_pfn(addr, atomic, async, write_fault, writable);
 }
 
 pfn_t gfn_to_pfn_atomic(struct kvm *kvm, gfn_t gfn)
@@ -1195,11 +1137,10 @@ pfn_t gfn_to_pfn_prot(struct kvm *kvm, gfn_t gfn, bool write_fault,
 }
 EXPORT_SYMBOL_GPL(gfn_to_pfn_prot);
 
-pfn_t gfn_to_pfn_memslot(struct kvm *kvm,
-                        struct kvm_memory_slot *slot, gfn_t gfn)
+pfn_t gfn_to_pfn_memslot(struct kvm_memory_slot *slot, gfn_t gfn)
 {
        unsigned long addr = gfn_to_hva_memslot(slot, gfn);
-       return hva_to_pfn(kvm, addr, false, NULL, true, NULL);
+       return hva_to_pfn(addr, false, NULL, true, NULL);
 }
 
 int gfn_to_page_many_atomic(struct kvm *kvm, gfn_t gfn, struct page **pages,
@@ -1219,30 +1160,42 @@ int gfn_to_page_many_atomic(struct kvm *kvm, gfn_t gfn, struct page **pages,
 }
 EXPORT_SYMBOL_GPL(gfn_to_page_many_atomic);
 
+static struct page *kvm_pfn_to_page(pfn_t pfn)
+{
+       if (is_error_pfn(pfn))
+               return KVM_ERR_PTR_BAD_PAGE;
+
+       if (kvm_is_mmio_pfn(pfn)) {
+               WARN_ON(1);
+               return KVM_ERR_PTR_BAD_PAGE;
+       }
+
+       return pfn_to_page(pfn);
+}
+
 struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn)
 {
        pfn_t pfn;
 
        pfn = gfn_to_pfn(kvm, gfn);
-       if (!kvm_is_mmio_pfn(pfn))
-               return pfn_to_page(pfn);
 
-       WARN_ON(kvm_is_mmio_pfn(pfn));
-
-       get_page(bad_page);
-       return bad_page;
+       return kvm_pfn_to_page(pfn);
 }
 
 EXPORT_SYMBOL_GPL(gfn_to_page);
 
 void kvm_release_page_clean(struct page *page)
 {
+       WARN_ON(is_error_page(page));
+
        kvm_release_pfn_clean(page_to_pfn(page));
 }
 EXPORT_SYMBOL_GPL(kvm_release_page_clean);
 
 void kvm_release_pfn_clean(pfn_t pfn)
 {
+       WARN_ON(is_error_pfn(pfn));
+
        if (!kvm_is_mmio_pfn(pfn))
                put_page(pfn_to_page(pfn));
 }
@@ -1250,6 +1203,8 @@ EXPORT_SYMBOL_GPL(kvm_release_pfn_clean);
 
 void kvm_release_page_dirty(struct page *page)
 {
+       WARN_ON(is_error_page(page));
+
        kvm_release_pfn_dirty(page_to_pfn(page));
 }
 EXPORT_SYMBOL_GPL(kvm_release_page_dirty);
@@ -1580,6 +1535,43 @@ bool kvm_vcpu_yield_to(struct kvm_vcpu *target)
 }
 EXPORT_SYMBOL_GPL(kvm_vcpu_yield_to);
 
+#ifdef CONFIG_HAVE_KVM_CPU_RELAX_INTERCEPT
+/*
+ * Helper that checks whether a VCPU is eligible for directed yield.
+ * Most eligible candidate to yield is decided by following heuristics:
+ *
+ *  (a) VCPU which has not done pl-exit or cpu relax intercepted recently
+ *  (preempted lock holder), indicated by @in_spin_loop.
+ *  Set at the beiginning and cleared at the end of interception/PLE handler.
+ *
+ *  (b) VCPU which has done pl-exit/ cpu relax intercepted but did not get
+ *  chance last time (mostly it has become eligible now since we have probably
+ *  yielded to lockholder in last iteration. This is done by toggling
+ *  @dy_eligible each time a VCPU checked for eligibility.)
+ *
+ *  Yielding to a recently pl-exited/cpu relax intercepted VCPU before yielding
+ *  to preempted lock-holder could result in wrong VCPU selection and CPU
+ *  burning. Giving priority for a potential lock-holder increases lock
+ *  progress.
+ *
+ *  Since algorithm is based on heuristics, accessing another VCPU data without
+ *  locking does not harm. It may result in trying to yield to  same VCPU, fail
+ *  and continue with next VCPU and so on.
+ */
+bool kvm_vcpu_eligible_for_directed_yield(struct kvm_vcpu *vcpu)
+{
+       bool eligible;
+
+       eligible = !vcpu->spin_loop.in_spin_loop ||
+                       (vcpu->spin_loop.in_spin_loop &&
+                        vcpu->spin_loop.dy_eligible);
+
+       if (vcpu->spin_loop.in_spin_loop)
+               kvm_vcpu_set_dy_eligible(vcpu, !vcpu->spin_loop.dy_eligible);
+
+       return eligible;
+}
+#endif
 void kvm_vcpu_on_spin(struct kvm_vcpu *me)
 {
        struct kvm *kvm = me->kvm;
@@ -1589,6 +1581,7 @@ void kvm_vcpu_on_spin(struct kvm_vcpu *me)
        int pass;
        int i;
 
+       kvm_vcpu_set_in_spin_loop(me, true);
        /*
         * We boost the priority of a VCPU that is runnable but not
         * currently running, because it got preempted by something
@@ -1607,6 +1600,8 @@ void kvm_vcpu_on_spin(struct kvm_vcpu *me)
                                continue;
                        if (waitqueue_active(&vcpu->wq))
                                continue;
+                       if (!kvm_vcpu_eligible_for_directed_yield(vcpu))
+                               continue;
                        if (kvm_vcpu_yield_to(vcpu)) {
                                kvm->last_boosted_vcpu = i;
                                yielded = 1;
@@ -1614,6 +1609,10 @@ void kvm_vcpu_on_spin(struct kvm_vcpu *me)
                        }
                }
        }
+       kvm_vcpu_set_in_spin_loop(me, false);
+
+       /* Ensure vcpu is not eligible during next spinloop */
+       kvm_vcpu_set_dy_eligible(me, false);
 }
 EXPORT_SYMBOL_GPL(kvm_vcpu_on_spin);
 
@@ -2092,6 +2091,29 @@ static long kvm_vm_ioctl(struct file *filp,
                r = kvm_send_userspace_msi(kvm, &msi);
                break;
        }
+#endif
+#ifdef __KVM_HAVE_IRQ_LINE
+       case KVM_IRQ_LINE_STATUS:
+       case KVM_IRQ_LINE: {
+               struct kvm_irq_level irq_event;
+
+               r = -EFAULT;
+               if (copy_from_user(&irq_event, argp, sizeof irq_event))
+                       goto out;
+
+               r = kvm_vm_ioctl_irq_line(kvm, &irq_event);
+               if (r)
+                       goto out;
+
+               r = -EFAULT;
+               if (ioctl == KVM_IRQ_LINE_STATUS) {
+                       if (copy_to_user(argp, &irq_event, sizeof irq_event))
+                               goto out;
+               }
+
+               r = 0;
+               break;
+       }
 #endif
        default:
                r = kvm_arch_vm_ioctl(filp, ioctl, arg);
@@ -2697,9 +2719,6 @@ static struct syscore_ops kvm_syscore_ops = {
        .resume = kvm_resume,
 };
 
-struct page *bad_page;
-pfn_t bad_pfn;
-
 static inline
 struct kvm_vcpu *preempt_notifier_to_vcpu(struct preempt_notifier *pn)
 {
@@ -2731,33 +2750,6 @@ int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align,
        if (r)
                goto out_fail;
 
-       bad_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
-
-       if (bad_page == NULL) {
-               r = -ENOMEM;
-               goto out;
-       }
-
-       bad_pfn = page_to_pfn(bad_page);
-
-       hwpoison_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
-
-       if (hwpoison_page == NULL) {
-               r = -ENOMEM;
-               goto out_free_0;
-       }
-
-       hwpoison_pfn = page_to_pfn(hwpoison_page);
-
-       fault_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
-
-       if (fault_page == NULL) {
-               r = -ENOMEM;
-               goto out_free_0;
-       }
-
-       fault_pfn = page_to_pfn(fault_page);
-
        if (!zalloc_cpumask_var(&cpus_hardware_enabled, GFP_KERNEL)) {
                r = -ENOMEM;
                goto out_free_0;
@@ -2832,12 +2824,6 @@ out_free_1:
 out_free_0a:
        free_cpumask_var(cpus_hardware_enabled);
 out_free_0:
-       if (fault_page)
-               __free_page(fault_page);
-       if (hwpoison_page)
-               __free_page(hwpoison_page);
-       __free_page(bad_page);
-out:
        kvm_arch_exit();
 out_fail:
        return r;
@@ -2857,8 +2843,5 @@ void kvm_exit(void)
        kvm_arch_hardware_unsetup();
        kvm_arch_exit();
        free_cpumask_var(cpus_hardware_enabled);
-       __free_page(fault_page);
-       __free_page(hwpoison_page);
-       __free_page(bad_page);
 }
 EXPORT_SYMBOL_GPL(kvm_exit);